blob: 4eda1891136d21c0d591f266fc68c70c5d9a4d59 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS 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 <stdint.h>
#include <unistd.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <base/at_exit.h>
#include <base/command_line.h>
#include <base/format_macros.h>
#include <base/logging.h>
#include <base/message_loop/message_loop.h>
#include <base/time/time.h>
#include <brillo/flag_helper.h>
#include "power_manager/common/power_constants.h"
#include "power_manager/common/prefs.h"
#include "power_manager/common/util.h"
#include "power_manager/powerd/policy/backlight_controller.h"
#include "power_manager/powerd/policy/internal_backlight_controller.h"
#include "power_manager/powerd/policy/keyboard_backlight_controller.h"
#include "power_manager/powerd/system/ambient_light_sensor_stub.h"
#include "power_manager/powerd/system/backlight_stub.h"
#include "power_manager/powerd/system/display/display_power_setter_stub.h"
#include "power_manager/powerd/system/internal_backlight.h"
#include "power_manager/powerd/system/power_supply.h"
#include "power_manager/powerd/system/udev_stub.h"
using power_manager::PowerSource;
using power_manager::Prefs;
using power_manager::TabletMode;
using power_manager::policy::BacklightController;
using power_manager::policy::InternalBacklightController;
using power_manager::policy::KeyboardBacklightController;
using power_manager::system::AmbientLightSensorStub;
using power_manager::system::BacklightStub;
using power_manager::system::DisplayPowerSetterStub;
using power_manager::system::InternalBacklight;
using power_manager::system::PowerSupply;
using power_manager::system::UdevStub;
using power_manager::util::ClampPercent;
namespace {
// Prints |message| to stderr with a trailing newline and exits.
void Abort(const std::string& message) {
fprintf(stderr, "%s\n", message.c_str());
exit(1);
}
// Converter instantiates several internal powerd classes to perform conversions
// between hardware backlight levels, nonlinear percents that powerd uses (which
// are dependent on the powerd prefs that have been set for the device), and
// linear percents. It also supports getting the initial level that powerd would
// choose.
class Converter {
public:
Converter(int64_t current_level,
int64_t max_level,
int64_t lux,
bool keyboard,
bool force_battery)
: backlight_(max_level, current_level) {
CHECK(prefs_.Init(Prefs::GetDefaultPaths()));
bool has_als = false;
if (prefs_.GetBool(power_manager::kHasAmbientLightSensorPref, &has_als) &&
has_als) {
light_sensor_ = std::make_unique<AmbientLightSensorStub>(lux);
}
if (keyboard) {
auto controller = std::make_unique<KeyboardBacklightController>();
controller->Init(&backlight_, &prefs_, light_sensor_.get(),
nullptr /* display_backlight_controller */,
TabletMode::UNSUPPORTED);
controller->HandleHoverStateChange(true /* hovering */);
controller_ = std::move(controller);
} else {
auto controller = std::make_unique<InternalBacklightController>();
controller->Init(&backlight_, &prefs_, light_sensor_.get(),
&display_power_setter_);
controller_ = std::move(controller);
}
if (light_sensor_.get())
light_sensor_->NotifyObservers();
PowerSource power_source = PowerSource::BATTERY;
if (!force_battery) {
UdevStub udev;
PowerSupply power_supply;
power_supply.Init(base::FilePath(power_manager::kPowerStatusPath),
&prefs_, &udev);
if (!power_supply.RefreshImmediately()) {
LOG(ERROR) << "Failed to read power supply information; using battery";
} else {
power_source = power_supply.GetPowerStatus().line_power_on
? PowerSource::AC
: PowerSource::BATTERY;
}
}
controller_->HandlePowerSourceChange(power_source);
}
// Converts a brightness level to a nonlinear percent in [0.0, 100.0].
double LevelToNonlinearPercent(int64_t level) {
return controller_->LevelToPercent(level);
}
// Converts a nonlinear percent in [0.0, 100.0] to a brightness level.
int64_t NonlinearPercentToLevel(double percent) {
return controller_->PercentToLevel(percent);
}
// Converts a brightness level to a linear percent in [0.0, 100.0].
double LevelToLinearPercent(int64_t level) {
return level * 100.0 / backlight_.GetMaxBrightnessLevel();
}
// Converts a linear percent in [0.0, 100.0] to a brightness level.
int64_t LinearPercentToLevel(double percent) {
return static_cast<int64_t>(roundl(
ClampPercent(percent) * backlight_.GetMaxBrightnessLevel() / 100.0));
}
// Returns the initial brightness level requested by |controller_|.
int64_t GetInitialLevel() { return backlight_.GetCurrentBrightnessLevel(); }
private:
// A stub is used so |controller_| won't change the actual brightness.
BacklightStub backlight_;
Prefs prefs_;
std::unique_ptr<AmbientLightSensorStub> light_sensor_;
DisplayPowerSetterStub display_power_setter_;
std::unique_ptr<BacklightController> controller_;
DISALLOW_COPY_AND_ASSIGN(Converter);
};
} // namespace
int main(int argc, char* argv[]) {
// Flags that print the brightness.
DEFINE_bool(get_brightness, false, "Print current brightness level");
DEFINE_bool(get_brightness_percent, false,
"Print current brightness as linear percent");
DEFINE_bool(get_max_brightness, false, "Print max brightness level");
DEFINE_bool(get_initial_brightness, false,
"Print brightness level used "
"by powerd at boot");
// Flags that convert between units.
DEFINE_double(nonlinear_to_level, -1.0,
"Convert supplied nonlinear brightness percent to level");
DEFINE_int64(level_to_nonlinear, -1,
"Convert supplied brightness level to nonlinear percent");
DEFINE_double(linear_to_level, -1.0,
"Convert supplied linear brightness percent to level");
DEFINE_int64(level_to_linear, -1,
"Convert supplied brightness level to linear percent");
DEFINE_double(linear_to_nonlinear, -1.0,
"Convert supplied linear brightness percent to nonlinear");
DEFINE_double(nonlinear_to_linear, -1.0,
"Convert supplied nonlinear brightness percent to linear");
// Flags that set the brightness.
DEFINE_int64(set_brightness, -1, "Set brightness level");
DEFINE_double(set_brightness_percent, -1.0,
"Set brightness as "
"linearly-calculated percent in [0.0, 100.0]");
DEFINE_int64(set_resume_brightness, -2,
"Set brightness level on resume; -1 clears current level");
DEFINE_double(set_resume_brightness_percent, -1.0,
"Set resume brightness as linearly-calculated percent in "
"[0.0, 100.0]");
// Other flags.
DEFINE_bool(force_battery, false,
"Act as if on battery even if currently on AC (for "
"-get_initial_brightness)");
DEFINE_bool(keyboard, false, "Use keyboard (rather than panel) backlight");
DEFINE_int32(lux, 0,
"Ambient light sensor reading (for -get_initial_brightness)");
brillo::FlagHelper::Init(
argc, argv,
"Print or set the internal panel or keyboard backlight's brightness.");
base::AtExitManager at_exit_manager;
base::MessageLoopForIO message_loop;
logging::SetMinLogLevel(logging::LOG_WARNING);
if (FLAGS_get_brightness + FLAGS_get_max_brightness +
FLAGS_get_initial_brightness + FLAGS_get_brightness_percent +
(FLAGS_nonlinear_to_level >= 0.0) + (FLAGS_level_to_nonlinear >= 0) +
(FLAGS_linear_to_level >= 0.0) + (FLAGS_level_to_linear >= 0) +
(FLAGS_linear_to_nonlinear >= 0.0) +
(FLAGS_nonlinear_to_linear >= 0.0) >
1) {
Abort("At most one flag that prints a level or percent may be passed.");
}
if (FLAGS_set_brightness >= 0 && FLAGS_set_brightness_percent >= 0.0)
Abort("At most one of -set_brightness* may be passed.");
if (FLAGS_set_resume_brightness >= 0 &&
FLAGS_set_resume_brightness_percent >= 0.0) {
Abort("At most one of -set_resume_brightness* may be passed.");
}
InternalBacklight backlight;
base::FilePath path(FLAGS_keyboard ? power_manager::kKeyboardBacklightPath
: power_manager::kInternalBacklightPath);
std::string pattern = FLAGS_keyboard
? power_manager::kKeyboardBacklightPattern
: power_manager::kInternalBacklightPattern;
if (!backlight.Init(path, pattern))
Abort("No backlight in " + path.value() + " matched by " + pattern + ".");
const int64_t current_level = backlight.GetCurrentBrightnessLevel();
Converter converter(current_level, backlight.GetMaxBrightnessLevel(),
FLAGS_lux, FLAGS_keyboard, FLAGS_force_battery);
// Print brightness.
if (FLAGS_get_brightness)
printf("%" PRIi64 "\n", current_level);
if (FLAGS_get_max_brightness)
printf("%" PRIi64 "\n", backlight.GetMaxBrightnessLevel());
if (FLAGS_get_brightness_percent)
printf("%f\n", converter.LevelToLinearPercent(current_level));
if (FLAGS_get_initial_brightness)
printf("%" PRIi64 "\n", converter.GetInitialLevel());
// Convert between units.
if (FLAGS_nonlinear_to_level >= 0.0) {
printf("%" PRIi64 "\n",
converter.NonlinearPercentToLevel(FLAGS_nonlinear_to_level));
}
if (FLAGS_level_to_nonlinear >= 0) {
printf("%f\n", converter.LevelToNonlinearPercent(FLAGS_level_to_nonlinear));
}
if (FLAGS_linear_to_level >= 0.0) {
printf("%" PRIi64 "\n",
converter.LinearPercentToLevel(FLAGS_linear_to_level));
}
if (FLAGS_level_to_linear >= 0) {
printf("%f\n", converter.LevelToLinearPercent(FLAGS_level_to_linear));
}
if (FLAGS_linear_to_nonlinear >= 0.0) {
printf("%f\n",
converter.LevelToNonlinearPercent(
converter.LinearPercentToLevel(FLAGS_linear_to_nonlinear)));
}
if (FLAGS_nonlinear_to_linear >= 0.0) {
printf("%f\n",
converter.LevelToLinearPercent(
converter.NonlinearPercentToLevel(FLAGS_nonlinear_to_linear)));
}
// Change the brightness.
if (FLAGS_set_brightness >= 0) {
CHECK(
backlight.SetBrightnessLevel(FLAGS_set_brightness, base::TimeDelta()));
}
if (FLAGS_set_brightness_percent >= 0.0) {
CHECK(backlight.SetBrightnessLevel(
converter.LinearPercentToLevel(FLAGS_set_brightness_percent),
base::TimeDelta()));
}
if (FLAGS_set_resume_brightness >= -1) // -1 clears
CHECK(backlight.SetResumeBrightnessLevel(FLAGS_set_resume_brightness));
if (FLAGS_set_resume_brightness_percent >= 0.0) {
CHECK(backlight.SetResumeBrightnessLevel(
converter.LinearPercentToLevel(FLAGS_set_resume_brightness_percent)));
}
return 0;
}