From 9eafbb49c365fd46f818ec58ccedf23b690dc299 Mon Sep 17 00:00:00 2001 From: deanlancer Date: Sun, 8 Nov 2020 12:59:37 +0100 Subject: [PATCH] kunlun2: Update Light HAL --- light/Light.cpp | 310 ++++++++---------- light/Light.h | 41 +-- ...rdware.light@2.0-service.lenovo_kunlun2.rc | 84 +++-- light/service.cpp | 14 +- 4 files changed, 220 insertions(+), 229 deletions(-) diff --git a/light/Light.cpp b/light/Light.cpp index 1445a0c..d914e55 100644 --- a/light/Light.cpp +++ b/light/Light.cpp @@ -1,5 +1,8 @@ /* - * Copyright (C) 2018-2019 The LineageOS Project + * Copyright (C) 2014, 2017-2018 The Linux Foundation. All rights reserved. + * Not a contribution + * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2018 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,192 +17,159 @@ * limitations under the License. */ -#define LOG_TAG "LightService" - -#include +#define LOG_TAG "LightsService" #include "Light.h" - +#include +#include #include -#define LCD_LED "/sys/class/leds/wled/" -#define RED_LED "/sys/class/leds/red/" -#define BLUE_LED "/sys/class/leds/blue/" -#define GREEN_LED "/sys/class/leds/green/" - -#define BREATH "breath" -#define BRIGHTNESS "brightness" -#define MAX_BRIGHTNESS "max_brightness" -#define DELAY_OFF "delay_off" -#define DELAY_ON "delay_on" - -namespace { -/* - * Write value to path and close file. - */ -static void set(std::string path, std::string value) { - std::ofstream file(path); - - if (!file.is_open()) { - ALOGW("failed to write %s to %s", value.c_str(), path.c_str()); - return; - } - - file << value; -} - -static void set(std::string path, int value) { - set(path, std::to_string(value)); -} - -static int get(std::string path) { - std::ifstream file(path); - int value; - - if (!file.is_open()) { - ALOGW("failed to read from %s", path.c_str()); - return 0; - } - - file >> value; - return value; -} - -static int getMaxBrightness(std::string path) { - int value = get(path); - ALOGW("Got max brightness %d", value); - return value; -} - -static uint32_t getBrightness(const LightState& state) { - uint32_t alpha, red, green, blue; - - /* - * Extract brightness from AARRGGBB. - */ - alpha = (state.color >> 24) & 0xFF; - red = (state.color >> 16) & 0xFF; - green = (state.color >> 8) & 0xFF; - blue = state.color & 0xFF; - - /* - * Scale RGB brightness if Alpha brightness is not 0xFF. - */ - if (alpha != 0xFF) { - red = red * alpha / 0xFF; - green = green * alpha / 0xFF; - blue = blue * alpha / 0xFF; - } - - return (77 * red + 150 * green + 29 * blue) >> 8; -} - -static inline uint32_t scaleBrightness(uint32_t brightness, uint32_t maxBrightness) { - return brightness * maxBrightness / 0xFF; -} - -static inline uint32_t getScaledBrightness(const LightState& state, uint32_t maxBrightness) { - return scaleBrightness(getBrightness(state), maxBrightness); -} - -static void handleBacklight(const LightState& state) { - uint32_t brightness = getScaledBrightness(state, getMaxBrightness(LCD_LED MAX_BRIGHTNESS)); - set(LCD_LED BRIGHTNESS, brightness); -} - -static void handleNotification(const LightState& state) { - uint32_t redBrightness = scaleBrightness( (state.color >> 16) & 0xFF, getMaxBrightness(RED_LED MAX_BRIGHTNESS)); - uint32_t blueBrightness = scaleBrightness( state.color & 0xFF, getMaxBrightness(BLUE_LED MAX_BRIGHTNESS)); - uint32_t greenBrightness = scaleBrightness((state.color >> 8) & 0xFF, getMaxBrightness(GREEN_LED MAX_BRIGHTNESS)); - - /* Disable breathing or blinking */ - set(RED_LED BREATH, 0); - set(RED_LED DELAY_OFF, 0); - set(RED_LED DELAY_ON, 0); - - set(BLUE_LED BREATH, 0); - set(BLUE_LED DELAY_OFF, 0); - set(BLUE_LED DELAY_ON, 0); - - set(GREEN_LED BREATH, 0); - set(GREEN_LED DELAY_OFF, 0); - set(GREEN_LED DELAY_ON, 0); - - switch (state.flashMode) { - case Flash::HARDWARE: - /* Breathing */ - set(RED_LED BREATH, 1); - set(BLUE_LED BREATH, 1); - set(GREEN_LED BREATH, 1); - break; - case Flash::TIMED: - /* Blinking */ - set(RED_LED DELAY_OFF, state.flashOnMs); - set(RED_LED DELAY_ON, state.flashOffMs); - set(BLUE_LED DELAY_OFF, state.flashOnMs); - set(BLUE_LED DELAY_ON, state.flashOffMs); - set(GREEN_LED DELAY_OFF, state.flashOnMs); - set(GREEN_LED DELAY_ON, state.flashOffMs); - break; - case Flash::NONE: - default: - break; - } - set(RED_LED BRIGHTNESS, redBrightness); - set(BLUE_LED BRIGHTNESS, blueBrightness); - set(GREEN_LED BRIGHTNESS, greenBrightness); - -} - -static inline bool isLit(const LightState& state) { - return state.color & 0x00ffffff; -} - -/* Keep sorted in the order of importance. */ -static std::vector backends = { - { Type::ATTENTION, handleNotification }, - { Type::NOTIFICATIONS, handleNotification }, - { Type::BATTERY, handleNotification }, - { Type::BACKLIGHT, handleBacklight }, -}; - -} // anonymous namespace - namespace android { namespace hardware { namespace light { namespace V2_0 { namespace implementation { -Return Light::setLight(Type type, const LightState& state) { - LightStateHandler handler = nullptr; +/* + * Write value to path and close file. + */ +template +static void set(const std::string& path, const T& value) { + std::ofstream file(path); + file << value; +} - /* Lock global mutex until light state is updated. */ - std::lock_guard lock(globalLock); +template +static T get(const std::string& path, const T& def) { + std::ifstream file(path); + T result; - /* Update the cached state value for the current type. */ - for (LightBackend& backend : backends) { - if (backend.type == type) { - backend.state = state; - handler = backend.handler; + file >> result; + return file.fail() ? def : result; +} + +static int rgbToBrightness(const LightState& state) { + int color = state.color & 0x00ffffff; + return ((77 * ((color >> 16) & 0x00ff)) + + (150 * ((color >> 8) & 0x00ff)) + + (29 * (color & 0x00ff))) >> 8; +} + +Light::Light() { + mLights.emplace(Type::ATTENTION, std::bind(&Light::handleRgb, this, std::placeholders::_1, 0)); + mLights.emplace(Type::BACKLIGHT, std::bind(&Light::handleBacklight, this, std::placeholders::_1)); + mLights.emplace(Type::BATTERY, std::bind(&Light::handleRgb, this, std::placeholders::_1, 2)); + mLights.emplace(Type::NOTIFICATIONS, std::bind(&Light::handleRgb, this, std::placeholders::_1, 1)); +} + +void Light::handleBacklight(const LightState& state) { + int maxBrightness = get("/sys/class/backlight/panel0-backlight/max_brightness", -1); + if (maxBrightness < 0) { + maxBrightness = 255; + } + int sentBrightness = rgbToBrightness(state); + int brightness = sentBrightness * maxBrightness / 255; + LOG(DEBUG) << "Writing backlight brightness " << brightness + << " (orig " << sentBrightness << ")"; + set("/sys/class/backlight/panel0-backlight/brightness", brightness); +} + +void Light::handleRgb(const LightState& state, size_t index) { + mLightStates.at(index) = state; + + LightState stateToUse = mLightStates.front(); + for (const auto& lightState : mLightStates) { + if (lightState.color & 0xffffff) { + stateToUse = lightState; + break; } } - /* If no handler has been found, then the type is not supported. */ - if (!handler) { + std::map colorValues; + colorValues["red"] = (stateToUse.color >> 16) & 0xff; + // lower green and blue brightness to adjust for the (lower) brightness of red + colorValues["green"] = ((stateToUse.color >> 8) & 0xff) / 2; + colorValues["blue"] = (stateToUse.color & 0xff) / 2; + + int onMs = stateToUse.flashMode == Flash::TIMED ? stateToUse.flashOnMs : 0; + int offMs = stateToUse.flashMode == Flash::TIMED ? stateToUse.flashOffMs : 0; + + // LUT has 63 entries, we could theoretically use them as 3 (colors) * 21 (steps). + // However, the last LUT entries don't seem to behave correctly for unknown + // reasons, so we use 17 steps for a total of 51 LUT entries only. + static constexpr int kRampSteps = 16; + static constexpr int kRampMaxStepDurationMs = 15; + + auto makeLedPath = [](const std::string& led, const std::string& op) -> std::string { + return "/sys/class/leds/" + led + "/" + op; + }; + auto getScaledDutyPercent = [](int brightness) -> std::string { + std::string output; + for (int i = 0; i <= kRampSteps; i++) { + if (i != 0) { + output += ","; + } + output += std::to_string(i * 512 * brightness / (255 * kRampSteps)); + } + return output; + }; + + // Disable all blinking before starting + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "blink"), 0); + } + + if (onMs > 0 && offMs > 0) { + int pauseLo, pauseHi, stepDuration, index = 0; + if (kRampMaxStepDurationMs * kRampSteps > onMs) { + stepDuration = onMs / kRampSteps; + pauseHi = 0; + pauseLo = offMs; + } else { + stepDuration = kRampMaxStepDurationMs; + pauseHi = onMs - kRampSteps * stepDuration; + pauseLo = offMs - kRampSteps * stepDuration; + } + + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "lut_flags"), 95); + set(makeLedPath(entry.first, "start_idx"), index); + set(makeLedPath(entry.first, "duty_pcts"), getScaledDutyPercent(entry.second)); + set(makeLedPath(entry.first, "pause_lo"), pauseLo); + set(makeLedPath(entry.first, "pause_hi"), pauseHi); + set(makeLedPath(entry.first, "ramp_step_ms"), stepDuration); + index += kRampSteps + 1; + } + + // Start blinking + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "blink"), entry.second); + } + } else { + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "brightness"), entry.second); + } + } + + LOG(DEBUG) << base::StringPrintf( + "handleRgb: mode=%d, color=%08X, onMs=%d, offMs=%d", + static_cast::type>(stateToUse.flashMode), stateToUse.color, + onMs, offMs); +} + +Return Light::setLight(Type type, const LightState& state) { + auto it = mLights.find(type); + + if (it == mLights.end()) { return Status::LIGHT_NOT_SUPPORTED; } - /* Light up the type with the highest priority that matches the current handler. */ - for (LightBackend& backend : backends) { - if (handler == backend.handler && isLit(backend.state)) { - handler(backend.state); - return Status::SUCCESS; - } - } + /* + * Lock global mutex until light state is updated. + */ + std::lock_guard lock(mLock); - /* If no type has been lit up, then turn off the hardware. */ - handler(state); + it->second(state); return Status::SUCCESS; } @@ -207,8 +177,8 @@ Return Light::setLight(Type type, const LightState& state) { Return Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) { std::vector types; - for (const LightBackend& backend : backends) { - types.push_back(backend.type); + for (auto const& light : mLights) { + types.push_back(light.first); } _hidl_cb(types); diff --git a/light/Light.h b/light/Light.h index 4f102d8..27a701a 100644 --- a/light/Light.h +++ b/light/Light.h @@ -13,36 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H #define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H #include #include #include -#include +#include #include -#include - -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::hardware::light::V2_0::Flash; -using ::android::hardware::light::V2_0::ILight; -using ::android::hardware::light::V2_0::LightState; -using ::android::hardware::light::V2_0::Status; -using ::android::hardware::light::V2_0::Type; - -typedef void (*LightStateHandler)(const LightState&); - -struct LightBackend { - Type type; - LightState state; - LightStateHandler handler; - - LightBackend(Type type, LightStateHandler handler) : type(type), handler(handler) { - this->state.color = 0xff000000; - } -}; namespace android { namespace hardware { @@ -50,13 +28,28 @@ namespace light { namespace V2_0 { namespace implementation { +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::light::V2_0::ILight; +using ::android::hardware::light::V2_0::LightState; +using ::android::hardware::light::V2_0::Status; +using ::android::hardware::light::V2_0::Type; + class Light : public ILight { public: + Light(); + Return setLight(Type type, const LightState& state) override; Return getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; private: - std::mutex globalLock; + void handleBacklight(const LightState& state); + void handleRgb(const LightState& state, size_t index); + + std::mutex mLock; + std::unordered_map> mLights; + std::array mLightStates; }; } // namespace implementation diff --git a/light/android.hardware.light@2.0-service.lenovo_kunlun2.rc b/light/android.hardware.light@2.0-service.lenovo_kunlun2.rc index e88c1e3..a26e390 100644 --- a/light/android.hardware.light@2.0-service.lenovo_kunlun2.rc +++ b/light/android.hardware.light@2.0-service.lenovo_kunlun2.rc @@ -1,33 +1,61 @@ on boot - chown system system /sys/class/leds/wled/brightness - chown system system /sys/class/leds/wled/max_brightness - chown system system /sys/class/leds/red/breath - chown system system /sys/class/leds/red/brightness - chown system system /sys/class/leds/red/delay_on - chown system system /sys/class/leds/red/delay_off - chown system system /sys/class/leds/green/breath - chown system system /sys/class/leds/green/brightness - chown system system /sys/class/leds/green/delay_on - chown system system /sys/class/leds/green/delay_off - chown system system /sys/class/leds/blue/breath - chown system system /sys/class/leds/blue/brightness - chown system system /sys/class/leds/blue/delay_on - chown system system /sys/class/leds/blue/delay_off + chown system system /sys/class/backlight/panel0-backlight/brightness + chown system system /sys/class/backlight/panel0-backlight/max_brightness + chown system system /sys/class/backlight/panel0-backlight/actual_brightness - chmod 0644 /sys/class/leds/wled/brightness - chmod 0644 /sys/class/leds/wled/max_brightness - chmod 0644 /sys/class/leds/red/breath - chmod 0644 /sys/class/leds/red/brightness - chmod 0644 /sys/class/leds/red/delay_on - chmod 0644 /sys/class/leds/red/delay_off - chmod 0644 /sys/class/leds/green/breath - chmod 0644 /sys/class/leds/green/brightness - chmod 0644 /sys/class/leds/green/delay_on - chmod 0644 /sys/class/leds/green/delay_off - chmod 0644 /sys/class/leds/blue/breath - chmod 0644 /sys/class/leds/blue/brightness - chmod 0644 /sys/class/leds/blue/delay_on - chmod 0644 /sys/class/leds/blue/delay_off + chmod 0644 /sys/class/backlight/panel0-backlight/brightness + chmod 0644 /sys/class/backlight/panel0-backlight/max_brightness + + chown system system /sys/class/leds/white/brightness + chown system system /sys/class/leds/white/blink + + chown system system /sys/class/leds/red/blink + chown system system /sys/class/leds/red/brightness + chown system system /sys/class/leds/red/duty_pcts + chown system system /sys/class/leds/red/pause_hi + chown system system /sys/class/leds/red/pause_lo + chown system system /sys/class/leds/red/ramp_step_ms + chown system system /sys/class/leds/red/start_idx + chown system system /sys/class/leds/red/lut_flags + + chown system system /sys/class/leds/blue/blink + chown system system /sys/class/leds/blue/brightness + chown system system /sys/class/leds/blue/duty_pcts + chown system system /sys/class/leds/blue/pause_hi + chown system system /sys/class/leds/blue/pause_lo + chown system system /sys/class/leds/blue/ramp_step_ms + chown system system /sys/class/leds/blue/start_idx + chown system system /sys/class/leds/blue/lut_flags + + chown system system /sys/class/leds/green/blink + chown system system /sys/class/leds/green/brightness + chown system system /sys/class/leds/green/duty_pcts + chown system system /sys/class/leds/green/pause_hi + chown system system /sys/class/leds/green/pause_lo + chown system system /sys/class/leds/green/ramp_step_ms + chown system system /sys/class/leds/green/start_idx + chown system system /sys/class/leds/green/lut_flags + + chmod 660 /sys/class/leds/red/blink + chmod 660 /sys/class/leds/red/duty_pcts + chmod 660 /sys/class/leds/red/pause_hi + chmod 660 /sys/class/leds/red/pause_lo + chmod 660 /sys/class/leds/red/ramp_step_ms + chmod 660 /sys/class/leds/red/start_idx + + chmod 660 /sys/class/leds/blue/blink + chmod 660 /sys/class/leds/blue/duty_pcts + chmod 660 /sys/class/leds/blue/pause_hi + chmod 660 /sys/class/leds/blue/pause_lo + chmod 660 /sys/class/leds/blue/ramp_step_ms + chmod 660 /sys/class/leds/blue/start_idx + + chmod 660 /sys/class/leds/green/blink + chmod 660 /sys/class/leds/green/duty_pcts + chmod 660 /sys/class/leds/green/pause_hi + chmod 660 /sys/class/leds/green/pause_lo + chmod 660 /sys/class/leds/green/ramp_step_ms + chmod 660 /sys/class/leds/green/start_idx service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service interface android.hardware.light@2.0::ILight default diff --git a/light/service.cpp b/light/service.cpp index c07290e..6c8c886 100644 --- a/light/service.cpp +++ b/light/service.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The LineageOS Project + * Copyright 2018 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,9 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.light@2.0-service.lenovo_kunlun2" +#define LOG_TAG "android.hardware.light@2.0-service.lenovo" +#include #include #include "Light.h" @@ -27,24 +28,23 @@ using android::hardware::light::V2_0::ILight; using android::hardware::light::V2_0::implementation::Light; using android::OK; -using android::sp; using android::status_t; int main() { - sp service = new Light(); + android::sp service = new Light(); configureRpcThreadpool(1, true); status_t status = service->registerAsService(); if (status != OK) { - ALOGE("Cannot register Light HAL service."); + LOG(ERROR) << "Cannot register Light HAL service."; return 1; } - ALOGI("Light HAL service ready."); + LOG(INFO) << "Light HAL service ready."; joinRpcThreadpool(); - ALOGI("Light HAL service failed to join thread pool."); + LOG(ERROR) << "Light HAL service failed to join thread pool."; return 1; }