blob: 886c696df210d03ddb11ce27abb69799750859c0 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <fuchsia/hardware/backlight/llcpp/fidl.h>
#include <lib/fdio/fdio.h>
#include <lib/zx/channel.h>
#include <array>
#include <filesystem>
#include <vector>
#include <cmath>
#include <fbl/unique_fd.h>
#include <zxtest/zxtest.h>
namespace backlight {
namespace FidlBacklight = llcpp::fuchsia::hardware::backlight;
class BacklightDevice {
public:
BacklightDevice(zx::channel ch) : client_(FidlBacklight::Device::SyncClient(std::move(ch))) {
if (GetBrightnessNormalized(&orig_brightness_) != ZX_OK) {
printf("Error getting original brightness. Defaulting to 1.0\n");
orig_brightness_ = 1.0;
}
printf("Brightness at the start of the test: %f\n", orig_brightness_);
}
~BacklightDevice() {
printf("Restoring original brightness...\n");
if (SetBrightnessNormalized(orig_brightness_) != ZX_OK) {
printf("Error setting brightness to %f\n", orig_brightness_);
}
}
zx_status_t GetBrightnessNormalized(double* brightness) {
auto response = client_.GetStateNormalized();
zx_status_t status = response.ok()
? (response->result.is_err() ? response->result.err() : ZX_OK)
: response.status();
if (status != ZX_OK) {
return status;
}
*brightness = response->result.response().state.brightness;
return status;
}
zx_status_t SetBrightnessNormalized(double brightness) {
FidlBacklight::State state = {.backlight_on = brightness > 0, .brightness = brightness};
printf("Setting brightness to: %f\n", brightness);
auto response = client_.SetStateNormalized(state);
zx_status_t status = response.ok()
? (response->result.is_err() ? response->result.err() : ZX_OK)
: response.status();
return status;
}
zx_status_t GetBrightnessAbsolute(double* brightness) {
auto response = client_.GetStateAbsolute();
zx_status_t status = response.ok()
? (response->result.is_err() ? response->result.err() : ZX_OK)
: response.status();
if (status != ZX_OK) {
return status;
}
*brightness = response->result.response().state.brightness;
return status;
}
zx_status_t SetBrightnessAbsolute(double brightness) {
FidlBacklight::State state = {.backlight_on = brightness > 0, .brightness = brightness};
printf("Setting brightness to: %f nits\n", brightness);
auto response = client_.SetStateAbsolute(state);
zx_status_t status = response.ok()
? (response->result.is_err() ? response->result.err() : ZX_OK)
: response.status();
return status;
}
zx_status_t GetMaxAbsoluteBrightness(double* brightness) {
auto response = client_.GetMaxAbsoluteBrightness();
zx_status_t status = response.ok()
? (response->result.is_err() ? response->result.err() : ZX_OK)
: response.status();
if (status == ZX_OK) {
*brightness = response->result.response().max_brightness;
}
return status;
}
private:
FidlBacklight::Device::SyncClient client_;
double orig_brightness_;
};
class BacklightTest : public zxtest::Test {
public:
BacklightTest() {
constexpr char kDevicePath[] = "/dev/class/backlight/";
if (std::filesystem::exists(kDevicePath)) {
for (const auto& entry : std::filesystem::directory_iterator(kDevicePath)) {
printf("Found backlight device: %s\n", entry.path().c_str());
fbl::unique_fd fd(open(entry.path().c_str(), O_RDONLY));
EXPECT_GE(fd.get(), 0);
// Open service handle.
zx::channel channel;
EXPECT_OK(fdio_get_service_handle(fd.release(), channel.reset_and_get_address()));
devices_.push_back(std::make_unique<BacklightDevice>(std::move(channel)));
}
}
if (devices_.empty()) {
printf("No backlight devices found. Exiting...\n");
}
}
double Approx(double val) { return round(val * 100.0) / 100.0; }
void TestBrightnessNormalized(std::unique_ptr<BacklightDevice>& dev) {
std::array<double, 9> brightness_values = {0.0, 0.25, 0.5, 0.75, 1.0, 0.75, 0.5, 0.25, 0.0};
double brightness;
for (auto brt : brightness_values) {
EXPECT_OK(dev->SetBrightnessNormalized(brt));
EXPECT_OK(dev->GetBrightnessNormalized(&brightness));
EXPECT_EQ(Approx(brightness), brt);
SleepIfDelayEnabled();
}
}
void TestBrightnessAbsolute(std::unique_ptr<BacklightDevice>& dev) {
double brightness, max_brightness;
auto status = dev->GetMaxAbsoluteBrightness(&max_brightness);
if (status == ZX_OK) {
EXPECT_GT(max_brightness, 0);
std::array<double, 9> brightness_values = {0.0, 0.25, 0.5, 0.75, 1.0, 0.75, 0.5, 0.25, 0.0};
double brightness;
for (auto brt : brightness_values) {
EXPECT_OK(dev->SetBrightnessAbsolute(brt * max_brightness));
EXPECT_OK(dev->GetBrightnessAbsolute(&brightness));
EXPECT_EQ(Approx(brightness), brt * max_brightness);
SleepIfDelayEnabled();
}
} else {
EXPECT_EQ(dev->SetBrightnessAbsolute(0), ZX_ERR_NOT_SUPPORTED);
EXPECT_EQ(dev->GetBrightnessAbsolute(&brightness), ZX_ERR_NOT_SUPPORTED);
}
}
void TestAllDevices() {
for (auto& dev : devices_) {
TestBrightnessNormalized(dev);
TestBrightnessAbsolute(dev);
}
}
static void RunWithDelays() { delayEnabled_ = true; }
void SleepIfDelayEnabled() {
if (delayEnabled_) {
sleep(1);
}
}
private:
std::vector<std::unique_ptr<BacklightDevice>> devices_;
static bool delayEnabled_;
};
TEST_F(BacklightTest, VaryBrightness) { TestAllDevices(); }
} // namespace backlight
bool backlight::BacklightTest::delayEnabled_ = false;
int main(int argc, char** argv) {
int opt;
while ((opt = getopt(argc, argv, "dh")) != -1) {
switch (opt) {
case 'd':
backlight::BacklightTest::RunWithDelays();
argc--;
break;
case 'h':
default:
printf("Usage: runtests --names backlight-test [-- <options>]\n\n");
printf(
" Valid options are:\n"
" -d : By default the test runs without any delays between brightness changes.\n"
" Pass the -d argument to space the brightness changes one second apart,\n"
" so that they are visually perceptible on the screen.\n"
" -h : Print this usage text.\n\n");
return 0;
}
}
return zxtest::RunAllTests(argc, argv);
}