blob: f62c77c3738f2ad13d02eda346d520e6e61e4067 [file] [log] [blame]
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ledstatus.h"
#include <string>
#include <base/files/file_path.h>
#include <base/format_macros.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <brillo/streams/file_stream.h>
#include <brillo/streams/stream_utils.h>
namespace {
brillo::StreamPtr GetLEDDataStream(size_t index, bool write) {
std::string led_path;
if( index == 3 ) {
led_path = "/sys/class/leds/boot/brightness";
} else {
led_path = base::StringPrintf("/sys/class/leds/led%" PRIuS "/brightness",
index + 1);
}
base::FilePath dev_path{led_path};
auto access_mode = brillo::stream_utils::MakeAccessMode(!write, write);
return brillo::FileStream::Open(
dev_path, access_mode, brillo::FileStream::Disposition::OPEN_EXISTING,
nullptr);
}
} // anonymous namespace
LedStatus::LedStatus() {
// Try to open the lights HAL.
int ret = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, &lights_hal_);
if (ret) {
LOG(ERROR) << "Failed to load the lights HAL.";
return;
}
CHECK(lights_hal_);
LOG(INFO) << "Loaded lights HAL.";
// If we can open the HAL, then we map each number to one of the LEDs
// available on the board.
const std::initializer_list<const char*> kLogicalLights = {
LIGHT_ID_BACKLIGHT, LIGHT_ID_KEYBOARD, LIGHT_ID_BUTTONS, LIGHT_ID_BATTERY,
LIGHT_ID_NOTIFICATIONS, LIGHT_ID_ATTENTION, LIGHT_ID_BLUETOOTH,
LIGHT_ID_WIFI};
for (const char* light_name : kLogicalLights) {
light_device_t* light_device = nullptr;
ret = lights_hal_->methods->open(
lights_hal_, light_name,
reinterpret_cast<hw_device_t**>(&light_device));
// If a given light device couldn't be opened, don't map it to a number.
if (ret || !light_device) {
continue;
}
hal_leds_.push_back(light_name);
hal_led_status_.push_back(false);
}
// If the size of the map is zero, then the lights HAL doesn't have any valid
// leds.
if (hal_leds_.empty()) {
LOG(INFO) << "Unable to open any light devices using the HAL.";
lights_hal_ = nullptr;
return;
}
}
size_t LedStatus::GetLedCount() const {
return lights_hal_ ? hal_leds_.size() : 1;
}
std::vector<bool> LedStatus::GetStatus() const {
if (lights_hal_)
return hal_led_status_;
std::vector<bool> leds(GetLedCount());
for (size_t index = 0; index < GetLedCount(); index++)
leds[index] = IsLedOn(index);
return leds;
}
std::vector<std::string> LedStatus::GetNames() const {
return lights_hal_ ? hal_leds_ : std::vector<std::string>(GetLedCount());
}
bool LedStatus::IsLedOn(size_t index) const {
CHECK(index < GetLedCount());
if (lights_hal_)
return hal_led_status_[index];
brillo::StreamPtr stream = GetLEDDataStream(index, false);
if (!stream)
return false;
char buffer[10];
size_t size_read = 0;
if (!stream->ReadNonBlocking(buffer, sizeof(buffer), &size_read, nullptr,
nullptr)) {
return false;
}
std::string value{buffer, size_read};
base::TrimWhitespaceASCII(value, base::TrimPositions::TRIM_ALL, &value);
int brightness = 0;
if (!base::StringToInt(value, &brightness))
return false;
return brightness > 0;
}
void LedStatus::SetLedStatus(size_t index, bool on) {
CHECK(index < GetLedCount());
if (lights_hal_) {
light_state_t state = {};
state.color = on;
state.flashMode = LIGHT_FLASH_NONE;
state.flashOnMS = 0;
state.flashOffMS = 0;
state.brightnessMode = BRIGHTNESS_MODE_USER;
light_device_t* light_device = nullptr;
int rc = lights_hal_->methods->open(
lights_hal_,
hal_leds_[index].c_str(),
reinterpret_cast<hw_device_t**>(&light_device));
if (rc) {
LOG(ERROR) << "Unable to open " << hal_leds_[index];
return;
}
CHECK(light_device);
rc = light_device->set_light(light_device, &state);
if (rc) {
LOG(ERROR) << "Unable to set " << hal_leds_[index];
return;
}
hal_led_status_[index] = on;
light_device->common.close(
reinterpret_cast<hw_device_t*>(light_device));
if (rc) {
LOG(ERROR) << "Unable to close " << hal_leds_[index];
return;
}
return;
}
brillo::StreamPtr stream = GetLEDDataStream(index, true);
if (!stream)
return;
std::string brightness = on ? "255" : "0";
stream->WriteAllBlocking(brightness.data(), brightness.size(), nullptr);
}
void LedStatus::SetAllLeds(bool on) {
for (size_t i = 0; i < GetLedCount(); i++)
SetLedStatus(i, on);
}