1# Light
2
3
4## 概述
5
6### 功能简介
7
8Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接口,包括获取灯类型、配置点灯模式、配置灯闪烁效果、点灯、熄灯等。基于HDF(Hardware Driver Foundation)驱动框架开发的Light驱动模型,实现跨操作系统迁移,器件差异配置等功能。实现Light驱动“一次开发,多系统部署”的目标。Light驱动模型如图1所示:
9
10**图 1**  Light驱动模型图
11
12![Light驱动模型图](figures/Light驱动模型图.png)
13
14### 运作机制
15
16通过介绍Light驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如图2所示:
17
18**图 2**  Light驱动运行图
19
20![Light驱动运行图](figures/Light驱动运行图.png)
21
22以标准系统RK3568为例,介绍Light模块驱动加载及运行流程:
23
241. Device Manager从device_info.hcs配置文件中读取Light设备管理配置信息。
252. Device Manager从light_config.hcs配置文件中读取Light数据配置信息。
263. HCS Parser解析Light设备管理配置信息,加载对应的Light Host,并控制Host完成驱动的加载。
274. Light Proxy获取到Light HDI接口服务实例后,通过IPC(Inter-Process Communication)调用到Light Stub。
285. Light Stub主要处理与IPC相关的业务逻辑,完成参数反序列化后调用Light Controller。
296. Light Controller中是HDI接口的真正实现,通过IPC调用Light抽象驱动接口,进一步操作Light硬件设备。
30
31## 开发指导
32
33### 场景介绍
34
35灯设备的控制,在实际生活中比比皆是,例如短信通知时闪灯、终端电量不足时预警、充电时根据充电进度变换灯的颜色等等。这些动作的实现,都需要使用Light驱动模型提供的接口,动态配置点灯模式、配置灯闪烁效果、点灯、熄灯等。
36
37### 接口说明
38
39Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模式和闪烁时间的能力。Light硬件服务调用GetLightInfo获取Light设备的基本信息,调用TurnOnLight接口启动配置的闪烁效果,调用TurnOffLight接口关闭Light设备。Light驱动模型对外开放的API接口能力,参考表1。
40
41**表1**  Light驱动模型对外API接口能力介绍
42
43注:以下接口列举的为C接口,接口声明见文件[/drivers/peripheral/light/interfaces/include](https://gitee.com/openharmony/drivers_peripheral/tree/master/light/interfaces/include)44
45| 接口名                                                       | 功能描述                                                     |
46| ------------------------------------------------------------ | ------------------------------------------------------------ |
47| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | 获取当前系统中所有类型的灯信息,lightInfo表示指向灯信息的二级指针,count表示指向灯数量的指针。 |
48| int32_t (*TurnOnLight)(uint32_t lightId,  struct LightEffect *effect) | 根据指定的灯类型ID打开列表中的可用灯,lightId表示灯类型ID,effect表示指向灯效果的指针。 |
49| int32_t (*TurnOffLight)(uint32_t lightId)                    | 根据指定的灯类型ID关闭列表中的可用灯。                       |
50| int32_t (*TurnOnMultiLights)(uint32_t lightId, const struct LightColor *colors, const uint32_t count); | 根据指定的灯类型ID打开相应灯光中包含的多个子灯光。           |
51
52### 开发步骤
53基于HDF驱动框架,按照驱动Driver Entry程序,完成Light驱动开发,资源配置及HCS配置文件解析。
54
551. 灯驱动在Light Host中的配置信息。
56
57   - Light HCS文件代码路径:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs58
59   - 具体代码实现如下:
60
61     ```c
62     /* Light设备HCS配置 */
63     light :: host {
64         hostName = "light_host";
65         device_light :: device {
66             device0 :: deviceNode {
67                 policy = 2;                           // 驱动服务发布的策略(0:不提供服务,1:对内核态发布服务;2:对内核态和用户态都发布服务)
68                 priority = 100;                       // Light驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序
69                 preload = 0;                          // 驱动按需加载字段,0:加载;2:不加载
70                 permission = 0664;                    // 驱动创建设备节点权限
71                 moduleName = "HDF_LIGHT";             // Light驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
72                 serviceName = "hdf_light";            // Light驱动对外发布服务的名称,必须唯一
73                 deviceMatchAttr = "hdf_light_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
74             }
75         }
76     }
77     ```
78
792. 灯驱动私有HCS配置:
80
81   - 代码实现路径:vendor\hihope\rk3568\hdf_config\khdf\light\light_config.hcs82
83   - 具体代码实现如下:
84
85     ```c
86     root {
87         lightConfig {
88             boardConfig {
89                 match_attr = "hdf_light_driver";
90                 lightAttr {
91                     light01 {
92                         lightId = [1];    // Lightid可以包含多个逻辑灯光ID,例如:1表示电源指示灯。
93                         lightName = "battery";
94                         lightNumber = 1;
95                         busRNum = 147;    // Light的效果颜色红色对应GPIO值。
96                         busGNum = 146;    // Light的效果颜色绿色对应GPIO值。
97                         busBNum = 149;    // Light的效果颜色蓝色对应GPIO值。
98                         defaultBrightness = 0X00FFFFFF;    // 系统默认亮度值,B:0-7位,R:8-15位,G:16-23,扩展位24-31位。
99                         onTime = 50;    // 当闪光灯亮起时,系统支持的最短持续时间(以毫秒为单位)。
100                         offTime = 50;    // 当闪光灯熄灭时,系统支持的最短持续时间(以毫秒为单位)。
101                     }
102                 }
103             }
104         }
105     }
106     ```
107
1083. 灯驱动代码实现路径为: drivers\hdf_core\framework\model\misc\light\driver\src\light_driver.c109
110   - 灯驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下:
111
112     ```c
113     /* 注册灯入口数据结构体对象 */
114     struct HdfDriverEntry g_lightDriverEntry = {
115         .moduleVersion = 1,            // 灯模块版本号
116         .moduleName = "HDF_LIGHT",     // 灯模块名,要与device_info.hcs文件里灯moduleName字段值一样
117         .Bind = BindLightDriver,       // 灯绑定函数
118         .Init = InitLightDriver,       // 灯初始化函数
119         .Release = ReleaseLightDriver, // 灯资源释放函数
120     };
121     /* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
122     HDF_INIT(g_lightDriverEntry);
123     ```
124
125   - 灯驱动Bind接口实现示例如下:
126
127     ```c
128     /* Light驱动对外提供的服务绑定到HDF框架 */
129     int32_t BindLightDriver(struct HdfDeviceObject *device)
130     {
131         struct LightDriverData *drvData = NULL;
132
133         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
134     	/* 私有接口分配资源 */
135         drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData));
136         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL);
137     	/* 需要发布的接口函数 */
138         drvData->ioService.Dispatch = DispatchLight;
139         drvData->device = device;
140         device->service = &drvData->ioService;
141         g_lightDrvData = drvData;
142
143         return HDF_SUCCESS;
144     }
145     ```
146
147   - 灯驱动Init接口实现示例如下:
148
149     ```c
150     /* Light驱动初始化入口函数*/
151     int32_t InitLightDriver(struct HdfDeviceObject *device)
152     {
153         struct LightDriverData *drvData = NULL;
154
155         drvData = (struct LightDriverData *)device->service;
156
157         if (OsalMutexInit(&drvData->mutex) != HDF_SUCCESS) {
158             return HDF_FAILURE;
159         }
160     	/* 工作队列初始化 */
161         if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) {
162             return HDF_FAILURE;
163         }
164     	/* 工作项初始化 */
165         if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) {
166             return HDF_FAILURE;
167         }
168     	/* 解析HCS配置文件 */
169         if (GetLightConfigData(device->property) != HDF_SUCCESS) {
170             return HDF_FAILURE;
171         }
172     	/* 设置GPIO引脚方向 */
173         if (SetLightGpioDir(drvData) != HDF_SUCCESS) {
174             return HDF_FAILURE;
175         }
176
177         return HDF_SUCCESS;
178     }
179     ```
180
181   - 灯驱动Release接口在驱动卸载或者Init执行失败时,会调用此接口释放资源,具体实现如下:
182
183     ```c
184     /* 释放Light驱动初始化时分配的资源 */
185     void ReleaseLightDriver(struct HdfDeviceObject *device)
186     {
187         int32_t i;
188         struct LightDriverData *drvData = NULL;
189         /* 释放已分配资源 */
190         for (i = LIGHT_ID_NONE; i < LIGHT_ID_BUTT; ++i) {
191             if (drvData->info[i] != NULL) {
192                 OsalMemFree(drvData->info[i]);
193                 drvData->info[i] = NULL;
194             }
195         }
196     	/* 器件在位,销毁工作队列资源 */
197         HdfWorkDestroy(&drvData->work);
198         HdfWorkQueueDestroy(&drvData->workQueue);
199         (void)OsalMutexDestroy(&drvData->mutex);
200         OsalMemFree(drvData);
201         g_lightDrvData = NULL;
202     }
203     ```
204
205   - 灯驱动从HCS文件中解析Light设备管理配置信息。
206
207     ```c
208     /* 从HCS文件中获取Light基础配置 */
209     static int32_t GetLightBaseConfigData(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser,
210         uint32_t lightId)
211     {
212         int32_t ret;
213         uint32_t *defaultBrightness = NULL;
214         struct LightDriverData *drvData = NULL;
215         const char *name = NULL;
216
217         drvData = GetLightDrvData();
218         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
219         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM);
220         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM);
221     	/* 类型作为下标开辟空间 */
222         drvData->info[lightId] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo));
223         if (drvData->info[lightId] == NULL) {
224             HDF_LOGE("%s: malloc fail", __func__);
225             return HDF_FAILURE;
226         }
227     	 /* 将Light设备信息进行填充 */
228         ret = parser->GetUint32(node, "busRNum", (uint32_t *)&drvData->info[lightId]->busRNum, 0);
229         if (ret != HDF_SUCCESS) {
230             drvData->info[lightId]->busRNum = LIGHT_INVALID_GPIO;
231         }
232
233         ret = parser->GetUint32(node, "busGNum", (uint32_t *)&drvData->info[lightId]->busGNum, 0);
234         if (ret != HDF_SUCCESS) {
235             drvData->info[lightId]->busGNum = LIGHT_INVALID_GPIO;
236         }
237
238         ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[lightId]->busBNum, 0);
239         if (ret != HDF_SUCCESS) {
240             drvData->info[lightId]->busBNum = LIGHT_INVALID_GPIO;
241         }
242
243         ret = parser->GetString(node, "lightName", &name, NULL);
244         if (ret != HDF_SUCCESS) {
245             HDF_LOGE("%s:get lightName failed!", __func__);
246             return HDF_FAILURE;
247         }
248
249         if (strcpy_s(drvData->info[lightId]->lightInfo.lightName, NAME_MAX_LEN, name) != EOK) {
250             HDF_LOGE("%s:copy lightName failed!", __func__);
251             return HDF_FAILURE;
252         }
253
254         ret = parser->GetUint32(node, "lightNumber", (uint32_t *)&drvData->info[lightId]->lightInfo.lightNumber, 0);
255         if (ret != HDF_SUCCESS) {
256             HDF_LOGE("%s:get lightNumber failed!", __func__);
257             return HDF_FAILURE;
258         }
259
260         defaultBrightness = (uint32_t *)&drvData->info[lightId]->defaultBrightness;
261         ret = parser->GetUint32(node, "defaultBrightness", defaultBrightness, 0);
262         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "defaultBrightness");
263         ret = parser->GetUint32(node, "onTime", &drvData->info[lightId]->onTime, 0);
264         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "onTime");
265         ret = parser->GetUint32(node, "offTime", &drvData->info[lightId]->offTime, 0);
266         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "offTime");
267
268         drvData->info[lightId]->lightBrightness = 0;
269         drvData->info[lightId]->lightState = LIGHT_STATE_STOP;
270
271         return HDF_SUCCESS;
272     }
273     ```
274
275   - 分配资源,解析灯HCS配置信息实现如下:
276
277     ```c
278     /* 分配资源,解析灯HCS配置 */
279     static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser)
280     {
281         int32_t ret;
282         uint32_t i;
283         uint32_t temp;
284         struct LightDriverData *drvData = NULL;
285
286         drvData = GetLightDrvData();
287         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
288         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM);
289         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM);
290     	 /* 从HCS配置获取支持的灯类型个数 */
291         drvData->lightNum = (uint32_t)parser->GetElemNum(node, "lightId");
292         if (drvData->lightNum > LIGHT_ID_NUM) {
293             HDF_LOGE("%s: lightNum cross the border", __func__);
294             return HDF_FAILURE;
295         }
296
297         ret = memset_s(drvData->info, sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT, 0,
298             sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT);
299         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "memset_s");
300
301         for (i = 0; i < drvData->lightNum; ++i) {
302             /* 获取灯的类型 */
303             ret = parser->GetUint32ArrayElem(node, "lightId", i, &temp, 0);
304             CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId");
305
306             if (temp >= LIGHT_ID_BUTT) {
307                 HDF_LOGE("%s: light id invalid para", __func__);
308                 return HDF_FAILURE;
309             }
310
311             ret = GetLightBaseConfigData(node, parser, temp);
312             if (ret != HDF_SUCCESS) {
313                 HDF_LOGE("%s: get light base config fail", __func__);
314                 return HDF_FAILURE;
315             }
316         }
317
318         return HDF_SUCCESS;
319     }
320     ```
321
322   - 灯驱动的内部接口完成了灯类型获取、闪烁模式设置和停止的接口开发,并支持根据闪烁模式创建和销毁定时器。
323
324     - GetAllLightInfo接口实现如下:
325
326       ```c
327       /* Light驱动服务调用GetAllLightInfo接口获取灯类型信息 */
328       static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply)
329       {
330           (void)data;
331           uint32_t i;
332           struct LightInfo lightInfo;
333           struct LightDriverData *drvData = NULL;
334
335           drvData = GetLightDrvData();
336           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
337           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM);
338
339           if (!HdfSbufWriteUint32(reply, drvData->lightNum)) {
340               HDF_LOGE("%s: write sbuf failed", __func__);
341               return HDF_FAILURE;
342           }
343
344           for (i = 0; i < LIGHT_ID_BUTT; ++i) {
345               if (drvData->info[i] == NULL) {
346                   continue;
347               }
348               lightInfo.lightId = i;
349
350               if (!HdfSbufWriteUint32(reply, lightInfo.lightId)) {
351                   HDF_LOGE("%s: write lightId failed", __func__);
352                   return HDF_FAILURE;
353               }
354
355               if (strcpy_s(lightInfo.lightName, NAME_MAX_LEN, drvData->info[i]->lightInfo.lightName) != EOK) {
356                   HDF_LOGE("%s:copy lightName failed!", __func__);
357                   return HDF_FAILURE;
358               }
359
360               if (!HdfSbufWriteString(reply, (const char *)lightInfo.lightName)) {
361                   HDF_LOGE("%s: write lightName failed", __func__);
362                   return HDF_FAILURE;
363               }
364
365               lightInfo.lightNumber = drvData->info[i]->lightInfo.lightNumber;
366               if (!HdfSbufWriteUint32(reply, lightInfo.lightNumber)) {
367                   HDF_LOGE("%s: write lightNumber failed", __func__);
368                   return HDF_FAILURE;
369               }
370
371               lightInfo.lightType = HDF_LIGHT_TYPE_RGB_COLOR;
372               if (!HdfSbufWriteUint32(reply, lightInfo.lightType)) {
373                   HDF_LOGE("%s: write lightType failed", __func__);
374                   return HDF_FAILURE;
375               }
376           }
377
378           return HDF_SUCCESS;
379       }
380       ```
381
382     - TurnOnLight接口的实现如下:
383
384       ```c
385       /* 按照指定的类型和用户传入的参数使能灯 */
386       static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
387       {
388           (void)reply;
389           uint32_t len;
390           struct LightEffect *buf = NULL;
391           struct LightDriverData *drvData = NULL;
392
393           drvData = GetLightDrvData();
394           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
395
396           if (drvData->info[lightId] == NULL) {
397               HDF_LOGE("%s: light id info is null", __func__);
398               return HDF_FAILURE;
399           }
400
401           if (!HdfSbufReadBuffer(data, (const void **)&buf, &len)) {
402               HDF_LOGE("%s: light read data failed", __func__);
403               return HDF_FAILURE;
404           }
405       	/* 接收用户传入的亮度值。24-31bit表示扩展位,16-23bit表示红色,8-15bit表示绿色,0-7bit表示蓝色。如果字段不等于0,表示使能相应颜色的灯。
406              如果支持亮度设置,则通过0-255设置不同的亮度。 */
407           if (buf->lightColor.colorValue.rgbColor.r != 0) {
408               drvData->info[lightId]->lightBrightness |= 0X00FF0000;
409           }
410
411           if (buf->lightColor.colorValue.rgbColor.g != 0) {
412               drvData->info[lightId]->lightBrightness |= 0X0000FF00;
413           }
414
415           if (buf->lightColor.colorValue.rgbColor.b != 0) {
416               drvData->info[lightId]->lightBrightness |= 0X000000FF;
417           }
418       	/* 常亮模式 */
419           if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) {
420               return UpdateLight(lightId, LIGHT_STATE_START);
421           }
422       	/* 闪烁模式 */
423           if (buf->flashEffect.flashMode == LIGHT_FLASH_BLINK) {
424               drvData->info[lightId]->onTime = (buf->flashEffect.onTime < drvData->info[lightId]->onTime) ?
425               drvData->info[lightId]->onTime : buf->flashEffect.onTime;
426               drvData->info[lightId]->offTime = (buf->flashEffect.offTime < drvData->info[lightId]->offTime) ?
427               drvData->info[lightId]->offTime : buf->flashEffect.offTime;
428       		/* 创建定时器 */
429               if (OsalTimerCreate(&drvData->timer, LIGHT_WAIT_TIME, LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) {
430                   HDF_LOGE("%s: create light timer fail!", __func__);
431                   return HDF_FAILURE;
432               }
433       		/* 启动定时器 */
434               if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) {
435                   HDF_LOGE("%s: start light timer fail!", __func__);
436                   return HDF_FAILURE;
437               }
438           }
439
440           return HDF_SUCCESS;
441       }
442       ```
443
444     - TurnOffLight接口的实现如下:
445
446       ```c
447       /* 按照指定的类型关闭灯 */
448       static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
449       {
450           (void)data;
451           (void)reply;
452           struct LightDriverData *drvData = NULL;
453
454           drvData = GetLightDrvData();
455           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
456
457           if (drvData->info[lightId] == NULL) {
458               HDF_LOGE("%s: light id info is null", __func__);
459               return HDF_FAILURE;
460           }
461
462           if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) {
463               HDF_LOGE("%s: gpio write failed", __func__);
464               return HDF_FAILURE;
465           }
466
467           drvData->info[lightId]->lightState = LIGHT_STATE_STOP;
468           drvData->info[lightId]->lightBrightness = 0;
469       	/* 销毁定时器 */
470           if (drvData->timer.realTimer != NULL) {
471               if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) {
472                   HDF_LOGE("%s: delete light timer fail!", __func__);
473                   return HDF_FAILURE;
474               }
475           }
476
477           return HDF_SUCCESS;
478       }
479       ```
480
4815. Light Controller中是HDI接口的实现。
482
483   - 代码实现路径:drivers\peripheral\light\hal\src\light_controller.c484
485   - GetLightInfo接口的实现如下:
486
487     ```c
488     /* 将Light抽象驱动中写入HdfSBuf中的灯类型信息读取到LightInfo中 */
489     static int32_t ReadLightInfo(struct HdfSBuf *reply, struct LightDevice *priv)
490     {
491         struct LightInfo *pos = NULL;
492         const char *name = NULL;
493
494         if (!HdfSbufReadUint32(reply, &priv->lightNum)) {
495             HDF_LOGE("%s: sbuf read lightNum failed", __func__);
496             return HDF_FAILURE;
497         }
498
499         if (priv->lightInfoEntry != NULL) {
500             OsalMemFree(priv->lightInfoEntry);
501             priv->lightInfoEntry = NULL;
502         }
503
504         priv->lightInfoEntry = (struct LightInfo *)OsalMemCalloc(sizeof(*priv->lightInfoEntry) * priv->lightNum);
505         if (priv->lightInfoEntry == NULL) {
506             HDF_LOGE("%s: malloc fail", __func__);
507             return HDF_FAILURE;
508         }
509
510         pos = priv->lightInfoEntry;
511
512         for (uint32_t i = 0; i < priv->lightNum; ++i) {
513             if (!HdfSbufReadUint32(reply, &pos->lightId)) {
514                 HDF_LOGE("%{public}s:read lightId failed!", __func__);
515                 return HDF_FAILURE;
516             }
517
518             name = HdfSbufReadString(reply);
519             if (strcpy_s(pos->lightName, NAME_MAX_LEN, name) != EOK) {
520                 HDF_LOGE("%{public}s:copy lightName failed!", __func__);
521                 return HDF_FAILURE;
522             }
523
524             if (!HdfSbufReadUint32(reply, &pos->lightNumber)) {
525                 HDF_LOGE("%{public}s:read lightNumber failed!", __func__);
526                 return HDF_FAILURE;
527             }
528
529             if (!HdfSbufReadInt32(reply, &pos->lightType)) {
530                 HDF_LOGE("%{public}s:read lightType failed!", __func__);
531                 return HDF_FAILURE;
532             }
533             pos++;
534         }
535
536         return HDF_SUCCESS;
537     }
538     /* GetLightInfo接口实现 */
539     static int32_t GetLightInfo(struct LightInfo **lightInfo, uint32_t *count)
540     {
541         if ((lightInfo == NULL) || (count == NULL)) {
542             HDF_LOGE("%s:line:%{public}d pointer is null and return ret", __func__, __LINE__);
543             return HDF_FAILURE;
544         }
545
546         struct LightDevice *priv = GetLightDevicePriv();
547
548         if (priv->lightNum > 0) {
549             *count = priv->lightNum;
550             *lightInfo = priv->lightInfoEntry;
551             return HDF_SUCCESS;
552         }
553
554         (void)OsalMutexLock(&priv->mutex);
555         struct HdfSBuf *reply = HdfSbufObtainDefaultSize();
556         if (reply == NULL) {
557             HDF_LOGE("%s: get sbuf failed", __func__);
558             (void)OsalMutexUnlock(&priv->mutex);
559             return HDF_FAILURE;
560         }
561
562         int32_t ret = SendLightMsg(LIGHT_IO_CMD_GET_INFO_LIST, NULL, reply);
563         if (ret != HDF_SUCCESS) {
564             HDF_LOGE("%{public}s: Light send cmd failed, ret[%{public}d]", __func__, ret);
565             HdfSbufRecycle(reply);
566             (void)OsalMutexUnlock(&priv->mutex);
567             return ret;
568         }
569
570         if (ReadLightInfo(reply, priv) != HDF_SUCCESS) {
571             HdfSbufRecycle(reply);
572             (void)OsalMutexUnlock(&priv->mutex);
573             return HDF_FAILURE;
574         }
575
576         HdfSbufRecycle(reply);
577         (void)OsalMutexUnlock(&priv->mutex);
578
579         *count = priv->lightNum;
580         *lightInfo = priv->lightInfoEntry;
581
582         return HDF_SUCCESS;
583     }
584     ```
585
586   - OnLight接口的实现如下:
587
588     ```c
589     static int32_t OnLight(uint32_t lightId, struct LightEffect *effect)
590     {
591         int32_t ret;
592
593         if (effect == NULL) {
594             HDF_LOGE("%{public}s: effect is NULL", __func__);
595             return HDF_FAILURE;
596         }
597
598         ret = OnLightValidityJudgment(lightId, effect);
599         if (ret != HDF_SUCCESS) {
600             HDF_LOGE("%{public}s: effect is false", __func__);
601             return ret;
602         }
603
604         struct LightDevice *priv = GetLightDevicePriv();
605         (void)OsalMutexLock(&priv->mutex);
606
607         struct HdfSBuf *msg = HdfSbufObtainDefaultSize();
608         if (msg == NULL) {
609             HDF_LOGE("%{public}s: Failed to obtain sBuf size", __func__);
610             (void)OsalMutexUnlock(&priv->mutex);
611             return HDF_FAILURE;
612         }
613
614         if (!HdfSbufWriteInt32(msg, lightId)) {
615             HDF_LOGE("%{public}s: Light write id failed", __func__);
616             HdfSbufRecycle(msg);
617             (void)OsalMutexUnlock(&priv->mutex);
618             return HDF_FAILURE;
619         }
620
621         if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_ENABLE)) {
622             HDF_LOGE("%{public}s: Light write enable failed", __func__);
623             HdfSbufRecycle(msg);
624             (void)OsalMutexUnlock(&priv->mutex);
625             return HDF_FAILURE;
626         }
627
628         if (!HdfSbufWriteBuffer(msg, effect, sizeof(*effect))) {
629             HDF_LOGE("%{public}s: Light write enable failed", __func__);
630             HdfSbufRecycle(msg);
631             (void)OsalMutexUnlock(&priv->mutex);
632             return HDF_FAILURE;
633         }
634
635         ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL);
636         if (ret != HDF_SUCCESS) {
637             HDF_LOGE("%{public}s: Light enable failed, ret[%{public}d]", __func__, ret);
638         }
639         HdfSbufRecycle(msg);
640         (void)OsalMutexUnlock(&priv->mutex);
641
642         if (memcpy_s(&g_lightEffect, sizeof(g_lightEffect), effect, sizeof(*effect)) != EOK) {
643             HDF_LOGE("%{public}s: Light effect cpy faild", __func__);
644             return HDF_FAILURE;
645         }
646
647         g_lightState[lightId] = LIGHT_ON;
648
649         return ret;
650     }
651     ```
652
653   - OffLight接口的实现 如下:
654
655     ```c
656     static int32_t OffLight(uint32_t lightId)
657     {
658         if (lightId >= LIGHT_ID_BUTT) {
659             HDF_LOGE("%{public}s: id not supported", __func__);
660             return HDF_FAILURE;
661         }
662
663         struct LightDevice *priv = GetLightDevicePriv();
664         (void)OsalMutexLock(&priv->mutex);
665
666         struct HdfSBuf *msg = HdfSbufObtainDefaultSize();
667         if (msg == NULL) {
668             HDF_LOGE("%{public}s: Failed to obtain sBuf", __func__);
669             (void)OsalMutexUnlock(&priv->mutex);
670             return HDF_FAILURE;
671         }
672
673         if (!HdfSbufWriteInt32(msg, lightId)) {
674             HDF_LOGE("%{public}s: Light write id failed", __func__);
675             HdfSbufRecycle(msg);
676             (void)OsalMutexUnlock(&priv->mutex);
677             return HDF_FAILURE;
678         }
679
680         if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_DISABLE)) {
681             HDF_LOGE("%{public}s: Light write disable failed", __func__);
682             HdfSbufRecycle(msg);
683             (void)OsalMutexUnlock(&priv->mutex);
684             return HDF_FAILURE;
685         }
686
687         int32_t ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL);
688         if (ret != HDF_SUCCESS) {
689             HDF_LOGE("%{public}s: Light disable failed, ret[%{public}d]", __func__, ret);
690         }
691         HdfSbufRecycle(msg);
692         (void)OsalMutexUnlock(&priv->mutex);
693
694         g_lightState[lightId] = LIGHT_OFF;
695
696         return ret;
697     }
698     ```
699
700   - OnMultiLights接口的实现如下:
701
702     ```c
703     static int32_t OnMultiLights(uint32_t lightId, const struct LightColor *colors, const uint32_t count)
704     {
705         int32_t ret;
706         struct HdfSBuf *sbuf = NULL;
707
708         ret = OnMultiLightsValidityJudgment(lightId, colors, count);
709         if (ret != HDF_SUCCESS) {
710             return ret;
711         }
712
713         struct LightDevice *priv = GetLightDevicePriv();
714         (void)OsalMutexLock(&priv->mutex);
715         sbuf = HdfSbufObtain(sizeof(struct LightColor) * count);
716         if (sbuf == NULL) {
717             return HDF_DEV_ERR_NO_MEMORY;
718         }
719
720         if (!HdfSbufWriteInt32(sbuf, lightId)) {
721             ret = HDF_FAILURE;
722             goto EXIT;
723         }
724
725         if (!HdfSbufWriteInt32(sbuf, LIGHT_OPS_IO_CMD_ENABLE_MULTI_LIGHTS)) {
726             ret = HDF_FAILURE;
727             goto EXIT;
728         }
729
730         if (!HdfSbufWriteBuffer(sbuf, colors, sizeof(*colors))) {
731             ret = HDF_FAILURE;
732             goto EXIT;
733         }
734
735         if (!HdfSbufWriteInt32(sbuf, count)) {
736             ret = HDF_FAILURE;
737             goto EXIT;
738         }
739
740         ret = SendLightMsg(LIGHT_IO_CMD_OPS, sbuf, NULL);
741         if (ret != HDF_SUCCESS) {
742         }
743     	return ret;
744
745     EXIT:
746         HdfSbufRecycle(sbuf);
747         (void)OsalMutexUnlock(&priv->mutex);
748     }
749     ```
750
751### 调测验证
752
753驱动开发完成后,在灯单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。
754
755- 参考测试代码如下:
756
757  ```c
758  #include <cmath>
759  #include <cstdio>
760  #include <gtest/gtest.h>
761  #include <securec.h>
762  #include "hdf_base.h"
763  #include "osal_time.h"
764  #include "osal_mem.h"
765  #include "light_if.h"
766  #include "light_type.h"
767
768  using namespace testing::ext;
769  const struct LightInterface *g_lightDev = nullptr;
770  static struct LightInfo *g_lightInfo = nullptr;
771  static uint32_t g_count = 0;
772  /* 用例执行前,初始化Light接口实例。 */
773  class HdfLightTest : public testing::Test {
774  public:
775      static void SetUpTestCase();
776      static void TearDownTestCase();
777      void SetUp();
778      void TearDown();
779  };
780
781  void HdfLightTest::SetUpTestCase()
782  {
783      g_lightDev = NewLightInterfaceInstance();
784      if (g_lightDev == nullptr) {
785          printf("test light get Module instance fail\n\r");
786      }
787      int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count);
788      if (ret == -1) {
789          printf("get light informations fail\n\r");
790      }
791  }
792
793  /* 用例执行后,释放用例资源。 */
794  void HdfLightTest::TearDownTestCase()
795  {
796      if(g_lightDev != nullptr){
797          FreeLightInterfaceInstance();
798          g_lightDev = nullptr;
799      }
800  }
801
802  void HdfLightTest::SetUp()
803  {
804  }
805
806  void HdfLightTest::TearDown()
807  {
808  }
809
810  /* 获取测试灯类型 */
811  HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1)
812  {
813      struct LightInfo *info = nullptr;
814
815      if (g_lightInfo == nullptr) {
816          EXPECT_NE(nullptr, g_lightInfo);
817          return;
818      }
819
820      printf("get light list num[%u]\n\r", g_count);
821      info = g_lightInfo;
822
823      for (uint32_t i = 0; i < g_count; ++i) {
824          printf("get lightId[%u]\n\r", info->lightId);
825          EXPECT_GE(info->lightId, 0);
826          EXPECT_LE(info->lightId, 4);
827          info++;
828      }
829  }
830
831  /* 测试灯常亮模式 */
832  HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1)
833  {
834      uint32_t i;
835      struct LightEffect effect;
836      effect.flashEffect.flashMode = 0;
837      effect.flashEffect.onTime = 0;
838      effect.flashEffect.offTime = 0;
839
840      for (i = 0; i < g_count; ++i) {
841          effect.lightColor.colorValue.rgbColor.r = 255;
842          effect.lightColor.colorValue.rgbColor.g = 0;
843          effect.lightColor.colorValue.rgbColor.b = 0;
844          int32_t ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect);
845          EXPECT_EQ(0, ret);
846
847     OsalSleep(2);
848
849     ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId);
850          EXPECT_EQ(0, ret);
851
852          effect.lightColor.colorValue.rgbColor.r = 0;
853          effect.lightColor.colorValue.rgbColor.g = 255;
854          effect.lightColor.colorValue.rgbColor.b = 0;
855          ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect);
856          EXPECT_EQ(0, ret);
857
858          OsalSleep(2);
859
860          ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId);
861          EXPECT_EQ(0, ret);
862      }
863  }
864  ```
865
866- 编译文件BUILD.gn参考代码如下:
867
868  ```c
869  import("//build/test.gni")
870  import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")
871
872  module_output_path = "drivers_peripheral_light/light"
873  ohos_unittest("light_test") {
874    module_out_path = module_output_path
875    sources = [ "light_test.cpp" ]
876    include_dirs = [
877      "//drivers/peripheral/light/interfaces/include",
878    ]
879    deps = [ "//drivers/peripheral/light/hal:hdi_light" ]
880
881    external_deps = [
882      "c_utils:utils",
883      "hdf_core:libhdf_utils",
884   	"hiviewdfx_hilog_native:libhilog",
885    ]
886
887    cflags = [
888      "-Wall",
889      "-Wextra",
890      "-Werror",
891      "-Wno-format",
892      "-Wno-format-extra-args",
893    ]
894
895    install_enable = true
896    install_images = [ "vendor" ]
897    module_install_dir = "bin"
898    part_name = "unionman_products"
899  }
900  ```
901
902
903
904