文档内容拷贝自:
codebase_host/yunhal/opendoc/zh/yunhal_doc/led.md
联系人:@陈杰
YunOS Light Hardware Abstract Layer,主要涉及下面几个方面:
依据系统“Light”形态不同,其控制能力主要包含:
下表展示了已知“LED灯”的形态:
ID | 说明 |
---|---|
LED_ID_BACKLIGHT | 屏幕背光 |
LED_ID_KEYBOARD | 键盘背光 |
LED_ID_BUTTON | 导航区的触摸式按扭 |
LED_ID_BATTERY | 充电指示灯 |
LED_ID_NOTIFICATIONS | 新通知到达的指示灯 |
LED_ID_ATTENTION | 提醒指示灯 |
LED_ID_BLUETOOTH | 蓝牙传输指示灯 |
LED_ID_WIFI | 无线传输指示灯 |
实现 Light HAL 的主要工作包括:实现 VendorModule 接口,声明模块入口;“继承” 和 实现 LEDDevice 接口。
域 | 类型 | 说明 |
---|---|---|
version | uint32_t | 模块版本 |
id | const char* | 模块标识 |
name | const char* | 模块名 |
author | const char* | 作者 |
CreateDevice() | int32_t (*CreateDevice) (const VendorModule* module, const char* deviceID, VendorDevice** device) | 工厂方法:“生产” VendorDevice |
一个 CreateDevice() 的实现示例如下:
int32_t createDevice(const VendorModule* module, const char* deviceID, VendorDevice** outDevice) { if (!strcmp(deviceID, LED_ID_BACKLIGHT)) { outDevice[0] = (VendorDevice*) &sBacklightDevice; return 0; } if (!strcmp(deviceID, LED_ID_BATTERY)) { outDevice[0] = (VendorDevice*) &sBatteryDevice; return 0; } if (...) { ... return 0; } outDevice[0] = NULL; return -ENODEV; }
声明模块入口,是为了HAL of LED的实现模块,能被 libhal 所装载,示例代码如下:
static VendorModule sModule = { .common.version = 1, .common.id = "LED", .common.name = "My LED", .common.author = "My corp.", .common.CreateDevice = createDevice }; VENDOR_MODULE_ENTRY(sModule);
域 | 类型 | 说明 |
---|---|---|
version | uint32_t | 设备版本 |
id | const char* | 设备标识 |
module | const VendorModule* | 指向模块的指针 |
Destroy() | int32_t (*Destroy) (VendorDevice* device) | 析构函数 |
SetLED() | int (*SetLED)(LEDDevice* LEDDev, LEDState* state) | 设置“LED灯”显示状态 |
示例代码如下:
struct MyLEDDevice { LEDDevice common; /* inherit, C style */ /* Other context data goes here */ }; static int setMyLED(struct LEDDevice* device, LEDState* state) { struct MyLEDDevice *realDevice = (MyLEDDevice*) device; /* apply the state specified by LEDState parameter */ return 0; } static int32_t destroyMyLEDDevice(VendorDevice* device) { struct MyLEDDevice *realDevice = (MyLEDDevice*) device; ... return 0; /* returns some error code if has error */ } /* static instance of the Backlight LED Device */ static struct MyLEDDevice* sBacklightDevice = { /* initialize field of VendorDevice */ .common.common.version = 1, .common.common.id = LED_ID_BACKLIGHT, .common.common.module = &sModule, .common.common.Destroy = destroyMyLEDDevice, /* initialize field of LEDDevice */ .common.SetLED = setMyLED, /* initialize other extended fileds */ };
HAL 实现中,确保对 YunOS 主镜像具有最小的依赖,即除了 glibc、libstdc++ 以及 liblog 以外,不依赖其他 libraries。
一个示例的 yunos.mk 如下:
LOCAL_PATH=$(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := my_led LOCAL_MODULE_PATH := usr/lib/yunhal LOCAL_SRC_FILES := my_led.c LOCAL_C_INCLUDES := \ $(base-includes) \ $(yunhal-includes) ... LOCAL_SHARED_LIBRARIES := libhal liblog LOCAL_COMPILE_SHELL_CMD := \ mkdir -p $(XMAKE_ROOTFS)/usr/lib/yunhal/ && \ ln -sf my_led.so $(XMAKE_ROOTFS)/usr/lib/yunhal/libyunhal_LED.so # May be changed to include $(BUILD_HAL) ? include $(BUILD_SHARED_LIBRARY)
通过 led_yunhal_test 命令,检测所实现的 LED 模块是否兼容 YunOS,输出如下:
Running main() from gtest_main.cc [==========] Running 8 tests from 1 test case. [----------] Global test environment set-up. [----------] 8 tests from LEDTest [ RUN ] LEDTest.test_backlight SetUp export LED_HAL_VALIDATE_SET=1: The underlying HAL may write and then read to confirm a success write TestBacklight(): set brightness to 0(color=0xff000000) TestBacklight(): set brightness to 10(color=0xff0a0a0a) TestBacklight(): set brightness to 20(color=0xff141414) TestBacklight(): set brightness to 40(color=0xff282828) TestBacklight(): set brightness to 60(color=0xff3c3c3c) TestBacklight(): set brightness to 100(color=0xff646464) TestBacklight(): set brightness to 150(color=0xff969696) TestBacklight(): set brightness to 201(color=0xffc9c9c9) TestBacklight(): set brightness to 224(color=0xffe0e0e0) TestBacklight(): set brightness to 255(color=0xffffffff) TearDown [ OK ] LEDTest.test_backlight (10094 ms) [ RUN ] LEDTest.test_keyboard SetUp export LED_HAL_VALIDATE_SET=1: The underlying HAL may write and then read to confirm a success write TestFlash(): set 'keyboard' to color=0xff000000, hold for 3secs TestFlash(): set 'keyboard' to color=0xff000000, flash: 2secs ON, 1secs OFF TestFlash(): set 'keyboard' to color=0xffffffff, hold for 3secs TestFlash(): set 'keyboard' to color=0xffffffff, flash: 2secs ON, 1secs OFF TestFlash(): set 'keyboard' to color=0xffff0000, hold for 3secs TestFlash(): set 'keyboard' to color=0xffff0000, flash: 2secs ON, 1secs OFF TestFlash(): set 'keyboard' to color=0xff00ff00, hold for 3secs TestFlash(): set 'keyboard' to color=0xff00ff00, flash: 2secs ON, 1secs OFF TestFlash(): set 'keyboard' to color=0xff0000ff, hold for 3secs TestFlash(): set 'keyboard' to color=0xff0000ff, flash: 2secs ON, 1secs OFF TestFlash(): set 'keyboard' to color=0xffc4a000, hold for 3secs TestFlash(): set 'keyboard' to color=0xffc4a000, flash: 2secs ON, 1secs OFF TearDown
需要说明的是,测试程序特意设置了一个环境变量LED_HAL_VALIDATE_SET. LED 模块的实现,可以依据此环境变量,进入测试模式 —— 即 write 底层硬件之后 read 之,比较 write 是否成功,并将比较结果返回在 SetLED() 方法中。
在实际硬件实现中,编程逻辑上“LED灯”,往往对应同一个物理上的“LED灯”,例如大多数手机顶端,有一个“indicator LED”,__同时对应了__ LED_ID_BATTERY 和 LED_ID_NOTIFICATIONS,在实现中,往往采用基于优先级的复用 —— 通常 LED_ID_BATTERY 具备较高的优先级。
另一方面,通常手机正面有LED_ID_BATTERY/LED_ID_NOTIFICATIONS、LED_ID_BACKLIGHT和LED_ID_BUTTON,其亮度需保持观感一致。
比如,当开启环境背光功能时,屏幕亮度会随着环境光强来设定相应的屏幕背光(LED_ID_BACKLIGHT) 。但LED_ID_BUTTON,即手机下方导航触摸按扭,通常没有环境背光,故而可能存在过暗或过亮。从正面亮度一致性的角度,可以考虑让LED_ID_BUTTON亮度与LED_ID_BACKLIGHT一致,即: