文档中心 > 芯片厂商开放

文档内容拷贝自:codebase_host/yunhal/opendoc/zh/yunhal_doc/led.md
联系人:@陈杰

1. 概述(Introduction)

YunOS Light Hardware Abstract Layer,主要涉及下面几个方面:

  • 屏幕背光
  • 手机信息提示灯
  • 等等

依据系统“Light”形态不同,其控制能力主要包含:

  1. 亮度
  2. 颜色
  3. 周期闪烁(亮时间间隔,灭时间间隔)
  4. 等等

下表展示了已知“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 无线传输指示灯

2. 架构(Light Framework Architecture)

3. 实现(Implement Light HAL)

实现 Light HAL 的主要工作包括:实现 VendorModule 接口,声明模块入口;“继承” 和 实现 LEDDevice 接口。

3.1. 实现 VendorModule 接口

类型 说明
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;
}

3.1.1. 声明模块入口

声明模块入口,是为了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);

3.2. “继承” 和 实现 LEDDevice 接口

类型 说明
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 */
};

3.3. 编译

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)

4. 测试(Vendor Test Suite)

通过 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() 方法中。

5. 附录(Appendix)

5.1. “LED灯”联动

在实际硬件实现中,编程逻辑上“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一致,即:

  • 通过特殊的亮度值,打开一致性。特殊值 可不在正常亮度取值范围(0-255) 内,比如 256
  • 一致性打开后,LED_ID_BUTTON亮度计算自LED_ID_BACKLIGHT的亮度(两处亮度对应关系,取决于两者发光器件的人体观感)

FAQ

关于此文档暂时还没有FAQ
返回
顶部