• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Light
2
3
4## 概述
5
6### 功能简介
7
8​        Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接口,包括获取灯类型、配置点灯模式、配置灯闪烁效果、点灯、熄灯等。基于HDF(Hardware Driver Foundation)驱动框架开发的Light驱动模型,实现跨操作系统迁移,器件差异配置等功能。实现Light驱动“一次开发,多系统部署”的目标。Light驱动模型如[图1](#Light驱动模型图)所示:
9
10**图 1**  Light驱动模型图
11
12![Light驱动模型图](figures/Light驱动模型图.png)
13
14### 运作机制
15
16通过介绍Light驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如[图2](#Light驱动运行图)所示:
17
18**图 2**  Light驱动运行图
19
20![Light驱动运行图](figures/Light驱动运行图.png)
21
22Light驱动模型以标准系统Hi3516DV300为例,介绍整个驱动加载及运行流程:
23
241. 从device info HCS 的Light Host里读取Light设备管理配置信息。
252. 从light_config HCS读取Light数据配置信息。
263. 解析Light设备管理配置信息,并关联对应设备驱动。
274. 客户端下发Light Stub控制到服务端。
285. 服务端调用Light Stub控制。
296. 启动Light抽象驱动接口。
30
31## 开发指导
32
33### 场景介绍
34
35灯设备的控制,在实际生活中比比皆是,例如短信通知时闪灯、手机电量不足时预警、充电时根据充电进度变换灯的颜色等等。这些动作的实现,都需要使用Light驱动模型提供的接口,动态配置点灯模式、配置灯闪烁效果、点灯、熄灯等。
36
37### 接口说明
38
39Light驱动模型支持获取系统中所有灯的信息,动态配置闪烁模式和闪烁时间的能力。Light硬件服务调用GetLightInfo获取Light设备的基本信息;调用TurnOnLight接口启动配置的闪烁效果。Light驱动模型对外开放的API接口能力,参考[表1](#Light驱动模型对外API接口能力介绍)。
40
41**表1**  Light驱动模型对外API接口能力介绍
42
43| 接口名                                                       | 功能描述                                                     |
44| ------------------------------------------------------------ | ------------------------------------------------------------ |
45| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | 获取系统中所有灯的信息,lightInfo表示灯设备的基本信息,count表示获取灯的个数。 |
46| int32_t (*TurnOnLight)(uint32_t type, struct LightEffect *effect) | 根据指定的灯类型打开灯列表中可用的灯,type表示灯类型,effect表示要设置的效果信息。 |
47| int32_t (*TurnOffLight)(uint32_t type)                       | 根据指定的灯类型关闭灯列表中可用的灯。                       |
48
49### 开发步骤
501. 基于HDF驱动框架,按照驱动Driver Entry程序,完成Light抽象驱动开发(主要由Bind、Init、Release、Dispatch函数接口实现),资源配置及HCS解析。完成Light驱动的设备信息配置。
51
52   - 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
53     Light驱动模型使用HCS作为配置描述源码,HCS配置字段详细介绍请参考[配置管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md)54     其Driver Entry入口函数定义如下:
55
56     ```c
57     /* 注册灯入口数据结构体对象 */
58     struct HdfDriverEntry g_lightDriverEntry = {
59         .moduleVersion = 1, // 灯模块版本号
60         .moduleName = "HDF_LIGHT", // 灯模块名,要与device_info.hcs文件里灯moduleName字段值一样
61         .Bind = BindLightDriver, // 灯绑定函数
62         .Init = InitLightDriver, // 灯初始化函数
63         .Release = ReleaseLightDriver, // 灯资源释放函数
64     };
65     /* 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release函数释放驱动资源并退出 */
66     HDF_INIT(g_lightDriverEntry);
67     ```
68
69   - 基于HDF驱动框架,按照驱动Driver Entry程序,完成Light抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。
70
71     ```c
72     /* Light驱动对外发布的能力 */
73     static int32_t DispatchLight(struct HdfDeviceIoClient *client,
74         int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
75     {
76         .....
77         if (cmd == LIGHT_IO_CMD_GET_INFO_LIST) {
78             CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM);
79             return GetAllLightInfo(data, reply);
80         }
81
82         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
83         (void)OsalMutexLock(&drvData->mutex);
84         if (!HdfSbufReadInt32(data, &lightType)) {
85             HDF_LOGE("%s: sbuf read lightType failed", __func__);
86             (void)OsalMutexUnlock(&drvData->mutex);
87             return HDF_ERR_INVALID_PARAM;
88         }
89         .....
90         ret = DispatchCmdHandle(lightType, data, reply);
91         (void)OsalMutexUnlock(&drvData->mutex);
92         return ret;
93     }
94
95     /* Light驱动对外提供的服务绑定到HDF框架 */
96     int32_t BindLightDriver(struct HdfDeviceObject *device)
97     {
98         struct LightDriverData *drvData = NULL;
99
100         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
101         /* 私有接口分配资源 */
102         drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData));
103         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL);
104         /* 需要发布的接口函数 */
105         drvData->ioService.Dispatch = DispatchLight;
106         drvData->device = device;
107         device->service = &drvData->ioService;
108         g_lightDrvData = drvData;
109         return HDF_SUCCESS;
110     }
111
112     /* Light驱动初始化入口函数*/
113     int32_t InitLightDriver(struct HdfDeviceObject *device)
114     {
115     	.....
116         /* 工作队列初始化 */
117         if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) {
118             HDF_LOGE("%s: init workQueue fail!", __func__);
119             return HDF_FAILURE;
120         }
121         /* 工作项初始化 */
122         if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) {
123             HDF_LOGE("%s: init workQueue fail!", __func__);
124             return HDF_FAILURE;
125         }
126         /* 解析HCS配置文件 */
127         if (GetLightConfigData(device->property) != HDF_SUCCESS) {
128             HDF_LOGE("%s: get light config fail!", __func__);
129             return HDF_FAILURE;
130         }
131
132         return HDF_SUCCESS;
133     }
134
135     /* 释放Light驱动初始化时分配的资源 */
136     void ReleaseLightDriver(struct HdfDeviceObject *device)
137     {
138         .....
139         /* 释放已分配资源 */
140         for (i = LIGHT_TYPE_NONE; i < LIGHT_TYPE_BUTT; ++i) {
141
142             if (drvData->info[i] != NULL) {
143                 OsalMemFree(drvData->info[i]);
144                 drvData->info[i] = NULL;
145             }
146         }
147         /* 销毁工作队列资源 */
148         HdfWorkDestroy(&drvData->work);
149         HdfWorkQueueDestroy(&drvData->workQueue);
150         (void)OsalMutexDestroy(&drvData->mutex);
151         (void)OsalMemFree(drvData);
152         g_lightDrvData = NULL;
153     }
154     ```
155
156   - Light设备管理模块负责系统中Light器件接口发布,在系统启动过程中,HDF框架机制通过灯Host里设备HCS配置信息,加载设备管理驱动。
157
158     ```
159     /* 灯设备HCS配置 */
160     device_light :: device {
161         device0 :: deviceNode {
162             policy = 2; // 驱动服务发布的策略(0:不提供服务,1:对内核态发布服务,2:对内核态和用户态都发布服务)
163             priority = 100; // Light驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序
164             preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载
165             permission = 0664;  // 驱动创建设备节点权限
166             moduleName = "HDF_LIGHT"; // Light驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
167             serviceName = "hdf_light"; // Light驱动对外发布服务的名称,必须唯一
168             deviceMatchAttr = "hdf_light_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
169         }
170     ```
171
1722. 调用配置解析接口,完成器件属性信息解析,器件寄存器解析,并注册到Light设备管理中。
173
174   ```c
175   /* 分配资源,解析灯HCS配置 */
176   static int32_t ParseLightInfo(const struct DeviceResourceNode *node)
177   {
178       .....
179       /* 从HCS获取支持灯的类型个数 */
180       drvData->lightNum = parser->GetElemNum(light, "lightType");
181       ....
182       for (i = 0; i < drvData->lightNum; ++i) {
183       /* 获取类型 */
184       ret = parser->GetUint32ArrayElem(light, "lightType", i, &temp, 0);
185       CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightType");
186       }
187
188       for (i = 0; i < drvData->lightNum; ++i) {
189       .....
190       /* 类型作为下标开辟空间 */
191       drvData->info[temp] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo));
192       .....
193       /* 将Light设备信息进行填充 */
194       ret = parser->GetUint32(light, "busRNum", &drvData->info[temp]->busRNum, 0);
195       CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busRNum");
196       ret = parser->GetUint32(light, "busGNum", &drvData->info[temp]->busGNum, 0);
197       CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busGNum");
198       ret = parser->GetUint32(light, "busBNum", &drvData->info[temp]->busBNum, 0);
199       CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busBNum");
200       .....
201       return HDF_SUCCESS;
202   }
203   ```
204
2053. 完成Light获取类型、闪烁和停止接口开发,会根据闪烁模式创建和销毁定时器。
206
207   ```c
208   /* Light驱动服务调用GetAllLightInfo获取灯类型,Enable接口启动闪烁模式,
209      调用Disable接口停止闪烁 */
210   static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply)
211   {
212       .....
213       /* 获取Light类型个数 */
214       if (!HdfSbufWriteUint32(reply, drvData->lightNum)) {
215           HDF_LOGE("%s: write sbuf failed", __func__);
216           return HDF_FAILURE;
217       }
218       for (i = 0; i < LIGHT_TYPE_BUTT; ++i) {
219           if (drvData->info[i] == NULL) {
220               continue;
221           }
222           lightInfo.lightType = i;
223           lightInfo.reserved = NULL;
224           /* 将Light设备信息填充进reply */
225           if (!HdfSbufWriteBuffer(reply, &lightInfo, sizeof(lightInfo))) {
226               HDF_LOGE("%s: write sbuf failed", __func__);
227               return HDF_FAILURE;
228           }
229       }
230
231       return HDF_SUCCESS;
232   }
233
234   /* 按照指定的类型和用户传入的参数使能灯 */
235   static int32_t Enable(uint32_t lightType, struct HdfSBuf *data, struct HdfSBuf *reply)
236   {
237       .....
238       /* 根据用户传的亮度值设置灯的颜色  RGB: R:16-31bit、G:8-15bit、B:0-7bit */
239       if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_R_BIT) != 0) {
240           drvData->info[lightType]->busNum = drvData->info[lightType]->busRNum;
241       } else if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_G_BIT) != 0) {
242           drvData->info[lightType]->busNum = drvData->info[lightType]->busGNum;
243       } else if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_B_BIT) != 0) {
244           drvData->info[lightType]->busNum = drvData->info[lightType]->busBNum;
245       }
246       /* 常亮模式 */
247       if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) {
248
249           if (GpioWrite(drvData->info[lightType]->busNum, GPIO_VAL_HIGH) != HDF_SUCCESS) {
250               return HDF_FAILURE;
251           }
252       }
253       /* 闪烁模式 */
254       if (buf->flashEffect.flashMode == LIGHT_FLASH_TIMED) {
255           drvData->info[lightType]->lightState = LIGHT_STATE_START;
256           /* 用户设置的闪烁时间小于系统支持的最短时间,采用系统配置的时间(HCS配置) */
257           drvData->info[lightType]->onTime = buf->flashEffect.onTime < drvData->info[lightType]->onTime ?
258           drvData->info[lightType]->onTime : buf->flashEffect.onTime;
259           drvData->info[lightType]->offTime = buf->flashEffect.offTime < drvData->info[lightType]->offTime ?
260           drvData->info[lightType]->offTime : buf->flashEffect.offTime;
261           /* 创建定时器 */
262           if (OsalTimerCreate(&drvData->timer, drvData->info[lightType]->onTime,
263               LightTimerEntry, (uintptr_t)lightType) != HDF_SUCCESS) {
264           HDF_LOGE("%s: create light timer fail!", __func__);
265           return HDF_FAILURE;
266           }
267           /* 启动周期定时器 */
268           if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) {
269           HDF_LOGE("%s: start light timer fail!", __func__);
270           return HDF_FAILURE;
271           }
272       }
273       return HDF_SUCCESS;
274   }
275
276   /* 按照指定的类型关闭灯 */
277   static int32_t Disable(uint32_t lightType, struct HdfSBuf *data, struct HdfSBuf *reply)
278   {
279       /* 删除定时器 */
280       if (drvData->timer.realTimer != NULL) {
281
282           if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) {
283               HDF_LOGE("%s: delete haptic timer fail!", __func__);
284           }
285       }
286       /* 对应的GPIO下电 */
287       if (GpioWrite(drvData->info[lightType]->busRNum, GPIO_VAL_LOW) != HDF_SUCCESS){
288           HDF_LOGE("%s: gpio write failed", __func__);
289           return HDF_FAILURE;
290       }
291
292       return HDF_SUCCESS;
293   }
294   ```
295
296### 调测验证
297
298驱动开发完成后,在灯单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。
299
300```c++
301/* 用例执行前,初始化灯接口实例 */
302void HdfLightTest::SetUpTestCase()
303{
304    g_lightDev = NewLightInterfaceInstance();
305    if (g_lightDev == nullptr) {
306        printf("test light get Module instance failed\n\r");
307    }
308    int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count);
309    if (ret == -1) {
310        printf("get light informations failed\n\r");
311    }
312}
313
314/* 用例执行后,释放用例资源 */
315void HdfLightTest::TearDownTestCase()
316{
317    if(g_lightDev != nullptr){
318        FreeLightInterfaceInstance();
319        g_lightDev = nullptr;
320    }
321}
322
323/* 测试灯获取类型 */
324HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1)
325{
326    struct LightInfo *info = nullptr;
327
328    if (g_lightInfo == nullptr) {
329        EXPECT_NE(nullptr, g_lightInfo);
330        return;
331    }
332
333    printf("get light list num[%d]\n\r", g_count);
334    info = g_lightInfo;
335
336    for (int i = 0; i < g_count; ++i) {
337        printf("get lightId[%d]\n\r", info->lightType);
338        EXPECT_GE(info->lightType, g_minLightType);
339        EXPECT_LE(info->lightType, g_maxLightType);
340        info++;
341    }
342}
343
344/* 测试灯常亮模式 */
345HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1)
346{
347    int32_t i;
348    int32_t ret;
349    struct LightEffect effect;
350    effect->lightBrightness = 0x80000000;
351    effect->flashEffect.flashMode = LIGHT_FLASH_NONE;
352    effect->flashEffect.onTime = 0;
353    effect->flashEffect.offTime = 0;
354
355    for (i = 0; i < g_count; ++i) {
356
357        ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightType, effect);
358        EXPECT_EQ(0, ret);
359
360        OsalSleep(LIGHT_WAIT_TIME);
361
362        ret = g_lightDev->TurnOffLight(type);
363        EXPECT_EQ(0, ret);
364    }
365}
366
367/* 测试灯闪烁模式 */
368HWTEST_F(HdfLightTest, EnableLight002, TestSize.Level1)
369{
370    int32_t i;
371    int32_t ret;
372    struct LightEffect effect;
373    effect->lightBrightness = 0x80000000;
374    effect->flashEffect.flashMode = LIGHT_FLASH_TIMED;
375    effect->flashEffect.onTime = g_onTime;
376    effect->flashEffect.offTime = g_offTime;
377
378    for (i = 0; i < g_count; ++i) {
379
380        ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightType, effect);
381        EXPECT_EQ(0, ret);
382
383        OsalSleep(LIGHT_WAIT_TIME);
384
385        ret = g_lightDev->TurnOffLight(type);
386        EXPECT_EQ(0, ret);
387    }
388}
389```
390
391