From 53afa330782194eac21ff6c8fea922024c2784b8 Mon Sep 17 00:00:00 2001 From: Jan Altensen Date: Tue, 9 Jul 2019 22:43:47 +0200 Subject: [PATCH] hidl: add hidl lights hal Change-Id: I333c8d3e20bb451d208f15661afc06ac47e1a377 --- Android.mk | 1 + hidl/Android.mk | 17 ++ hidl/light/.clang-format | 11 + hidl/light/Android.mk | 42 ++++ hidl/light/Light.cpp | 202 ++++++++++++++++++ hidl/light/Light.h | 73 +++++++ ...roid.hardware.light@2.0-service.samsung.rc | 4 + hidl/light/include/samsung_lights.h | 58 +++++ hidl/light/service.cpp | 54 +++++ 9 files changed, 462 insertions(+) create mode 100644 hidl/Android.mk create mode 100644 hidl/light/.clang-format create mode 100644 hidl/light/Android.mk create mode 100644 hidl/light/Light.cpp create mode 100644 hidl/light/Light.h create mode 100644 hidl/light/android.hardware.light@2.0-service.samsung.rc create mode 100644 hidl/light/include/samsung_lights.h create mode 100644 hidl/light/service.cpp diff --git a/Android.mk b/Android.mk index fa697a2d..69ab1afb 100644 --- a/Android.mk +++ b/Android.mk @@ -41,6 +41,7 @@ include $(SAM_ROOT)/audio/Android.mk include $(SAM_ROOT)/consumerir/Android.mk include $(SAM_ROOT)/dtbhtool/Android.mk include $(SAM_ROOT)/fingerprint/Android.mk +include $(SAM_ROOT)/hidl/Android.mk include $(SAM_ROOT)/liblights/Android.mk include $(SAM_ROOT)/modemloader/Android.mk include $(SAM_ROOT)/power/Android.mk diff --git a/hidl/Android.mk b/hidl/Android.mk new file mode 100644 index 00000000..26e32a7a --- /dev/null +++ b/hidl/Android.mk @@ -0,0 +1,17 @@ +# +# Copyright (C) 2019 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. +# 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 $(call all-subdir-makefiles) diff --git a/hidl/light/.clang-format b/hidl/light/.clang-format new file mode 100644 index 00000000..ae4a4513 --- /dev/null +++ b/hidl/light/.clang-format @@ -0,0 +1,11 @@ +BasedOnStyle: Google +AccessModifierOffset: -2 +AllowShortFunctionsOnASingleLine: Inline +ColumnLimit: 100 +CommentPragmas: NOLINT:.* +DerivePointerAlignment: false +IndentWidth: 4 +PointerAlignment: Left +TabWidth: 4 +UseTab: Never +PenaltyExcessCharacter: 32 diff --git a/hidl/light/Android.mk b/hidl/light/Android.mk new file mode 100644 index 00000000..9a6bdd89 --- /dev/null +++ b/hidl/light/Android.mk @@ -0,0 +1,42 @@ +# +# Copyright (C) 2019 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. +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + Light.cpp \ + service.cpp + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libbinder \ + libhidlbase \ + libhidltransport \ + libutils \ + android.hardware.light@2.0 + +LOCAL_MODULE := android.hardware.light@2.0-service.samsung +LOCAL_INIT_RC := android.hardware.light@2.0-service.samsung.rc +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_OWNER := samsung +LOCAL_VENDOR_MODULE := true + +include $(BUILD_EXECUTABLE) diff --git a/hidl/light/Light.cpp b/hidl/light/Light.cpp new file mode 100644 index 00000000..cc5e5d4c --- /dev/null +++ b/hidl/light/Light.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2019 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. + * 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. + */ +#define LOG_TAG "android.hardware.light@2.0-service.samsung" + +#include + +#include "Light.h" + +#define COLOR_MASK 0x00ffffff +#define MAX_INPUT_BRIGHTNESS 255 + +using android::hardware::light::V2_0::LightState; +using android::hardware::light::V2_0::Status; +using android::hardware::light::V2_0::Type; + +namespace android { +namespace hardware { +namespace light { +namespace V2_0 { +namespace implementation { + +/* + * Write value to path and close file. + */ +template +static void set(const std::string& path, const T& value) { + std::ofstream file(path); + file << value << std::endl; +} + +template +static T get(const std::string& path, const T& def) { + std::ifstream file(path); + T result; + + file >> result; + return file.fail() ? def : result; +} + +Light::Light() { + mLights.emplace(Type::BACKLIGHT, + std::bind(&Light::handleBacklight, this, std::placeholders::_1)); +#ifdef BUTTON_BRIGHTNESS_NODE + mLights.emplace(Type::BUTTONS, std::bind(&Light::handleButtons, this, std::placeholders::_1)); +#endif + mLights.emplace(Type::BATTERY, std::bind(&Light::handleBattery, this, std::placeholders::_1)); + mLights.emplace(Type::NOTIFICATIONS, + std::bind(&Light::handleNotifications, this, std::placeholders::_1)); + mLights.emplace(Type::ATTENTION, + std::bind(&Light::handleAttention, this, std::placeholders::_1)); +} + +Return Light::setLight(Type type, const LightState& state) { + auto it = mLights.find(type); + + if (it == mLights.end()) { + return Status::LIGHT_NOT_SUPPORTED; + } + + /* + * Lock global mutex until light state is updated. + */ + std::lock_guard lock(mLock); + + it->second(state); + + return Status::SUCCESS; +} + +void Light::handleBacklight(const LightState& state) { + uint32_t max_brightness = get(PANEL_MAX_BRIGHTNESS_NODE, MAX_INPUT_BRIGHTNESS); + uint32_t brightness = rgbToBrightness(state); + + if (max_brightness != MAX_INPUT_BRIGHTNESS) { + brightness = brightness * max_brightness / MAX_INPUT_BRIGHTNESS; + } + + set(PANEL_BRIGHTNESS_NODE, brightness); +} + +#ifdef BUTTON_BRIGHTNESS_NODE +void Light::handleButtons(const LightState& state) { +#ifdef VAR_BUTTON_BRIGHTNESS + uint32_t brightness = rgbToBrightness(state); +#else + uint32_t brightness = (state.color & COLOR_MASK) ? 1 : 0; +#endif + + set(BUTTON_BRIGHTNESS_NODE, brightness); +} +#endif + +void Light::handleBattery(const LightState& state) { + mBatteryState = state; + setNotificationLED(); +} + +void Light::handleNotifications(const LightState& state) { + mNotificationState = state; + setNotificationLED(); +} + +void Light::handleAttention(const LightState& state) { + mAttentionState = state; + setNotificationLED(); +} + +void Light::setNotificationLED() { + int32_t adjusted_brightness = MAX_INPUT_BRIGHTNESS; + LightState state; +#ifdef LED_BLN_NODE + bool bln = false; +#endif + + if (mBatteryState.color & COLOR_MASK) { + adjusted_brightness = LED_BRIGHTNESS_BATTERY; + state = mBatteryState; + } else if (mNotificationState.color & COLOR_MASK) { + adjusted_brightness = LED_BRIGHTNESS_NOTIFICATION; + state = mNotificationState; +#ifdef LED_BLN_NODE + bln = true; +#endif + } else if (mAttentionState.color & COLOR_MASK) { + adjusted_brightness = LED_BRIGHTNESS_ATTENTION; + state = mAttentionState; + if (state.flashMode == Flash::HARDWARE) { + if (state.flashOnMs > 0 && state.flashOffMs == 0) state.flashMode = Flash::NONE; + state.color = 0x000000ff; + } + if (state.flashMode == Flash::NONE) { + state.color = 0; + } + } else { + set(LED_BLINK_NODE, "0x00000000 0 0"); + return; + } + + if (state.flashMode == Flash::NONE) { + state.flashOnMs = 0; + state.flashOffMs = 0; + } + + state.color = calibrateColor(state.color & COLOR_MASK, adjusted_brightness); + std::stringstream ss; + ss << std::hex << "0x" << std::setfill('0') << std::setw(8) << state.color << std::dec + << " " << state.flashOnMs << " " << state.flashOffMs; + set(LED_BLINK_NODE, ss.str()); + +#ifdef LED_BLN_NODE + if (bln) { + set(LED_BLN_NODE, (state.color & COLOR_MASK) ? 1 : 0); + } +#endif +} + +Return Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) { + std::vector types; + + for (auto const& light : mLights) { + types.push_back(light.first); + } + + _hidl_cb(types); + + return Void(); +} + +uint32_t Light::rgbToBrightness(const LightState& state) { + uint32_t color = state.color & COLOR_MASK; + + return ((77 * ((color >> 16) & 0xff)) + (150 * ((color >> 8) & 0xff)) + (29 * (color & 0xff))) >> + 8; +} + +uint32_t Light::calibrateColor(uint32_t color, int32_t brightness) { + uint32_t red = ((color >> 16) & 0xFF) * LED_ADJUSTMENT_R; + uint32_t green = ((color >> 8) & 0xFF) * LED_ADJUSTMENT_G; + uint32_t blue = (color & 0xFF) * LED_ADJUSTMENT_B; + + return (((red * brightness) / 255) << 16) + (((green * brightness) / 255) << 8) + + ((blue * brightness) / 255); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace hardware +} // namespace android diff --git a/hidl/light/Light.h b/hidl/light/Light.h new file mode 100644 index 00000000..b256cc9a --- /dev/null +++ b/hidl/light/Light.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 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. + * 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. + */ + +#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H +#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H + +#include +#include +#include +#include +#include +#include "samsung_lights.h" + +namespace android { +namespace hardware { +namespace light { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct Light : public ILight { + Light(); + + Return setLight(Type type, const LightState& state) override; + Return getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; + + private: + void handleBacklight(const LightState& state); +#ifdef BUTTON_BRIGHTNESS_NODE + void handleButtons(const LightState& state); +#endif + void handleBattery(const LightState& state); + void handleNotifications(const LightState& state); + void handleAttention(const LightState& state); + void setNotificationLED(); + uint32_t rgbToBrightness(const LightState& state); + uint32_t calibrateColor(uint32_t color, int32_t brightness); + + LightState mAttentionState; + LightState mBatteryState; + LightState mNotificationState; + + std::mutex mLock; + std::unordered_map> mLights; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H diff --git a/hidl/light/android.hardware.light@2.0-service.samsung.rc b/hidl/light/android.hardware.light@2.0-service.samsung.rc new file mode 100644 index 00000000..deefa185 --- /dev/null +++ b/hidl/light/android.hardware.light@2.0-service.samsung.rc @@ -0,0 +1,4 @@ +service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service.samsung + class hal + user system + group system diff --git a/hidl/light/include/samsung_lights.h b/hidl/light/include/samsung_lights.h new file mode 100644 index 00000000..accd97e2 --- /dev/null +++ b/hidl/light/include/samsung_lights.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * Copyright (C) 2017 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. + * 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. + */ + +#ifndef SAMSUNG_LIGHTS_H +#define SAMSUNG_LIGHTS_H + +/* + * Board specific nodes + * + * If your kernel exposes these controls in another place, you can either + * symlink to the locations given here, or override this header in your + * device tree. + */ +#define PANEL_BRIGHTNESS_NODE "/sys/class/backlight/panel/brightness" +#define PANEL_MAX_BRIGHTNESS_NODE "/sys/class/backlight/panel/max_brightness" +#define BUTTON_BRIGHTNESS_NODE "/sys/class/sec/sec_touchkey/brightness" +#define LED_BLINK_NODE "/sys/class/sec/led/led_blink" +#define LED_BLN_NODE "/sys/class/misc/backlightnotification/notification_led" + +// Uncomment to enable variable button brightness +//#define VAR_BUTTON_BRIGHTNESS 1 + +/* + * Brightness adjustment factors + * + * If one of your device's LEDs is more powerful than the others, use these + * values to equalise them. This value is in the range 0.0-1.0. + */ +#define LED_ADJUSTMENT_R 1.0 +#define LED_ADJUSTMENT_G 1.0 +#define LED_ADJUSTMENT_B 1.0 + +/* + * Light brightness factors + * + * It might make sense for all colours to be scaled down (for example, if your + * LED is too bright). Use these values to adjust the brightness of each + * light. This value is within the range 0-255. + */ +#define LED_BRIGHTNESS_BATTERY 255 +#define LED_BRIGHTNESS_NOTIFICATION 255 +#define LED_BRIGHTNESS_ATTENTION 255 + +#endif // SAMSUNG_LIGHTS_H diff --git a/hidl/light/service.cpp b/hidl/light/service.cpp new file mode 100644 index 00000000..5cc08557 --- /dev/null +++ b/hidl/light/service.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 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. + * 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. + */ + +#define LOG_TAG "android.hardware.light@2.0-service.samsung" + +#include +#include +#include + +#include "Light.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +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 light = new Light(); + + configureRpcThreadpool(1, true); + + status_t status = light->registerAsService(); + + if (status != OK) { + LOG(ERROR) << "Could not register service for Light HAL"; + goto shutdown; + } + + LOG(INFO) << "Light HAL service is Ready."; + joinRpcThreadpool(); + +shutdown: + // In normal operation, we don't expect the thread pool to shutdown + LOG(ERROR) << "Light HAL failed to join thread pool."; + return 1; +}