| // 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 "power_manager/powerd/system/ambient_light_sensor.h" |
| |
| #include <fcntl.h> |
| |
| #include <algorithm> |
| #include <cerrno> |
| #include <cmath> |
| #include <cstring> |
| |
| #include <base/bind.h> |
| #include <base/logging.h> |
| #include <base/file_util.h> |
| #include <base/files/file_enumerator.h> |
| #include <base/files/file_path.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <base/strings/string_util.h> |
| #include <base/strings/stringprintf.h> |
| |
| #include "power_manager/common/util.h" |
| |
| namespace power_manager { |
| namespace system { |
| |
| namespace { |
| |
| // Default path examined for backlight device directories. |
| const base::FilePath::CharType kDefaultDeviceListPath[] = |
| FILE_PATH_LITERAL("/sys/bus/iio/devices"); |
| |
| // Default interval for polling the ambient light sensor. |
| const int kDefaultPollIntervalMs = 1000; |
| |
| // Number of failed init attempts before AmbientLightSensor will start logging |
| // warnings. |
| const int kNumInitAttemptsBeforeLogging = 5; |
| |
| } // namespace |
| |
| AmbientLightSensor::AmbientLightSensor() |
| : device_list_path_(kDefaultDeviceListPath), |
| poll_interval_ms_(kDefaultPollIntervalMs), |
| lux_value_(-1), |
| num_init_attempts_(0) { |
| } |
| |
| AmbientLightSensor::~AmbientLightSensor() {} |
| |
| void AmbientLightSensor::Init() { |
| StartTimer(); |
| } |
| |
| void AmbientLightSensor::AddObserver(AmbientLightObserver* observer) { |
| DCHECK(observer); |
| observers_.AddObserver(observer); |
| } |
| |
| void AmbientLightSensor::RemoveObserver(AmbientLightObserver* observer) { |
| DCHECK(observer); |
| observers_.RemoveObserver(observer); |
| } |
| |
| int AmbientLightSensor::GetAmbientLightLux() { |
| return lux_value_; |
| } |
| |
| void AmbientLightSensor::StartTimer() { |
| poll_timer_.Start(FROM_HERE, |
| base::TimeDelta::FromMilliseconds(poll_interval_ms_), |
| this, &AmbientLightSensor::ReadAls); |
| } |
| |
| void AmbientLightSensor::ReadAls() { |
| // We really want to read the ambient light level. |
| // Complete the deferred lux file open if necessary. |
| if (!als_file_.HasOpenedFile() && !InitAlsFile()) |
| return; |
| |
| // The timer will be restarted after the read finishes. |
| poll_timer_.Stop(); |
| als_file_.StartRead( |
| base::Bind(&AmbientLightSensor::ReadCallback, base::Unretained(this)), |
| base::Bind(&AmbientLightSensor::ErrorCallback, base::Unretained(this))); |
| } |
| |
| void AmbientLightSensor::ReadCallback(const std::string& data) { |
| std::string trimmed_data; |
| base::TrimWhitespaceASCII(data, base::TRIM_ALL, &trimmed_data); |
| int value = 0; |
| if (base::StringToInt(trimmed_data, &value)) { |
| lux_value_ = value; |
| VLOG(1) << "Read lux " << lux_value_; |
| FOR_EACH_OBSERVER(AmbientLightObserver, observers_, |
| OnAmbientLightUpdated(this)); |
| } else { |
| LOG(ERROR) << "Could not read lux value from ALS file contents: [" |
| << trimmed_data << "]"; |
| } |
| StartTimer(); |
| } |
| |
| void AmbientLightSensor::ErrorCallback() { |
| LOG(ERROR) << "Error reading ALS file"; |
| StartTimer(); |
| } |
| |
| bool AmbientLightSensor::InitAlsFile() { |
| CHECK(!als_file_.HasOpenedFile()); |
| |
| // Search the iio/devices directory for a subdirectory (eg "device0" or |
| // "iio:device0") that contains the "[in_]illuminance0_{input|raw}" file. |
| base::FileEnumerator dir_enumerator( |
| device_list_path_, false, base::FileEnumerator::DIRECTORIES); |
| const char* input_names[] = { |
| "in_illuminance0_input", |
| "in_illuminance0_raw", |
| "illuminance0_input", |
| }; |
| |
| num_init_attempts_++; |
| for (base::FilePath check_path = dir_enumerator.Next(); !check_path.empty(); |
| check_path = dir_enumerator.Next()) { |
| for (unsigned int i = 0; i < arraysize(input_names); i++) { |
| base::FilePath als_path = check_path.Append(input_names[i]); |
| if (!base::PathExists(als_path)) |
| continue; |
| if (als_file_.Init(als_path.value())) { |
| LOG(INFO) << "Using lux file " << als_path.value(); |
| return true; |
| } |
| } |
| } |
| |
| // If the illuminance file is not immediately found, issue a deferral |
| // message and try again later. |
| if (num_init_attempts_ > kNumInitAttemptsBeforeLogging) |
| PLOG(ERROR) << "lux file initialization failed"; |
| return false; |
| } |
| |
| } // namespace system |
| } // namespace power_manager |