| // 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_pump_type.h> |
| #include <base/task/single_thread_task_executor.h> |
| #include <base/time/time.h> |
| #include <brillo/flag_helper.h> |
| |
| #include "power_manager/common/battery_percentage_converter.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_manager.h" |
| #include "power_manager/powerd/system/ambient_light_sensor_stub.h" |
| #include "power_manager/powerd/system/backlight_stub.h" |
| #include "power_manager/powerd/system/dbus_wrapper_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::BatteryPercentageConverter; |
| using power_manager::LidState; |
| 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::AmbientLightSensorInterface; |
| using power_manager::system::AmbientLightSensorManager; |
| using power_manager::system::AmbientLightSensorStub; |
| using power_manager::system::BacklightStub; |
| using power_manager::system::DBusWrapperStub; |
| 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, |
| power_manager::system::BacklightInterface::BrightnessScale scale, |
| int64_t lux, |
| bool keyboard, |
| bool force_battery) |
| : backlight_(max_level, current_level, scale) { |
| CHECK(prefs_.Init(Prefs::GetDefaultStore(), Prefs::GetDefaultSources())); |
| |
| 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(), |
| &dbus_wrapper_, |
| nullptr /* display_backlight_controller */, |
| LidState::NOT_PRESENT, 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_, &dbus_wrapper_, |
| LidState::NOT_PRESENT); |
| controller_ = std::move(controller); |
| } |
| |
| if (light_sensor_.get()) |
| light_sensor_->NotifyObservers(); |
| |
| PowerSource power_source = PowerSource::BATTERY; |
| if (!force_battery) { |
| UdevStub udev; |
| |
| auto battery_percentage_converter = |
| BatteryPercentageConverter::CreateFromPrefs(&prefs_); |
| |
| PowerSupply power_supply; |
| power_supply.Init(base::FilePath(power_manager::kPowerStatusPath), |
| &prefs_, &udev, &dbus_wrapper_, |
| battery_percentage_converter.get()); |
| 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_; |
| DBusWrapperStub dbus_wrapper_; |
| std::unique_ptr<BacklightController> controller_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Converter); |
| }; |
| |
| // Prints the path to the ambient light sensor illuminance file that powerd |
| // would monitor and a trailing newline to stdout. Prints an error and aborts |
| // with status code 1 if the ALS has been disabled or no path was found. |
| void PrintAmbientLightPath(bool keyboard) { |
| Prefs prefs; |
| CHECK(prefs.Init(Prefs::GetDefaultStore(), Prefs::GetDefaultSources())); |
| int64_t num_als = 0; |
| if (!prefs.GetInt64(power_manager::kHasAmbientLightSensorPref, &num_als) || |
| !num_als) { |
| Abort("Ambient light sensor not enabled"); |
| } |
| |
| AmbientLightSensorManager als_manager; |
| als_manager.Init(&prefs); |
| als_manager.Run(true /* read_immediately */); |
| |
| AmbientLightSensorInterface* sensor; |
| sensor = keyboard ? als_manager.GetSensorForKeyboardBacklight() |
| : als_manager.GetSensorForInternalBacklight(); |
| if (!sensor) |
| Abort("Ambient light sensor not found"); |
| |
| base::FilePath path = sensor->GetIlluminancePath(); |
| if (path.empty()) |
| Abort("Ambient light sensor illuminance file not found"); |
| |
| printf("%s\n", path.value().c_str()); |
| } |
| |
| } // 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]"); |
| |
| // Other flags. |
| DEFINE_bool(get_ambient_light_path, false, |
| "Print path to ambient light sensor illuminance file"); |
| 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::SingleThreadTaskExecutor task_executor(base::MessagePumpType::IO); |
| logging::SetMinLogLevel(logging::LOG_WARNING); |
| |
| if (FLAGS_get_brightness + FLAGS_get_max_brightness + |
| FLAGS_get_initial_brightness + FLAGS_get_brightness_percent + |
| FLAGS_get_ambient_light_path + (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_get_ambient_light_path) { |
| PrintAmbientLightPath(FLAGS_keyboard); |
| return 0; |
| } |
| |
| 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(), |
| backlight.GetBrightnessScale(), 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())); |
| } |
| |
| return 0; |
| } |