1# Light
2
3
4## Overview
5
6### Introduction
7
8The light driver model provides APIs for the upper-layer light hardware service layer to control lights, including obtaining the light type, setting the lighting mode and blinking effect, and turning on or off a light. This model implements cross-OS porting and differentiated configurations based on the Hardware Driver Foundation (HDF) to achieve the goal of "one-time development for cross-system deployment" of the light driver.
9
10The figure below shows the light driver model.
11
12**Figure 1** Light driver model
13
14![Light driver model](figures/light_driver_model.png)
15
16### Working Principles
17
18The figure below shows how the light driver works.
19
20**Figure 2** How light driver works
21
22![How light driver works](figures/light_working.png)
23
24The following describes how to start and run the light module driver on an RK3568 board that runs the standard system.
25
261. The Device Manager reads the Light device management configuration from the **device_info.hcs** file.
272. The Device Manager reads the light data configuration from the **light_config.hcs** file.
283. The HCS Parser parses the light device management configuration, loads the Light Host, and controls the Host to load the driver.
294. The Light Proxy obtains the light HDI service instance and calls the Light Stub over Inter-Process Communication (IPC).
305. The Light Stub processes IPC-related service logic and calls the Light Controller after parameter deserialization.
316. The Light Controller implements the HDI APIs and calls the Light Abstract Driver APIs to operate the light devices.
32
33## Development Guidelines
34
35### When to Use
36
37Light control is widely used in daily life. For example, a light is blinking when a mobile device receives an SMS message or has low battery level, and a light changes its colors based on the device charging status. These actions are implemented by calling the APIs provided by the light driver model.
38
39### Available APIs
40
41The light driver model provides APIs for obtaining information about all the lights in the system and dynamically setting the blinking mode and duration. The light hardware service calls **GetLightInfo()** to obtain the basic light information, calls **TurnOnLight()** to set the blinking effect, and calls **TurnOffLight()** to turn off lights. The following table describes the APIs of the light driver model.
42
43**Table 1** APIs of the light driver model
44
45**NOTE**<br>The following APIs are C interfaces. For details about the interface declaration, see [/drivers/peripheral/light/interfaces/include](https://gitee.com/openharmony/drivers_peripheral/tree/master/light/interfaces/include).
46
47| API                                                      | Description                                                    |
48| ------------------------------------------------------------ | ------------------------------------------------------------ |
49| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | Obtains information about all types of lights in the system. <br>**lightInfo** indicates the double pointer to the light information obtained. <br>**count** indicates the pointer to the number of lights.|
50| int32_t (*TurnOnLight)(uint32_t lightId,  struct LightEffect *effect) | Turns on available lights in the list based on the specified light type. <br>**lightId** indicates the light type, and **effect** indicates the pointer to the light effect.|
51| int32_t (*TurnOffLight)(uint32_t lightId)                    | Turns off available lights in the list based on the specified light type.                      |
52| int32_t (*TurnOnMultiLights)(uint32_t lightId, const struct LightColor *colors, const uint32_t count); | Turns on multiple sub-lights of a light based on the specified light type ID.          |
53
54### How to Develop
55Develop the light driver based on the HDF and driver entry, configure resources, and parse the HCS configuration file.
56
571. Configure the light driver in the host.
58
59   - Light HCS file path: **vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs**.
60
61   - The code is as follows:
62
63     ```c
64     /* HCS of the light device. */
65     light :: host {
66         hostName = "light_host";
67         device_light :: device {
68             device0 :: deviceNode {
69                 policy = 2;                           // Policy for the driver to publish services. If the value is 0, the driver does not publish services. If the value is 1, the driver publishes services to the kernel space. If the value is 2, the driver publishes services to both the kernel space and user space.
70                 priority = 100;                       // Priority (0–200) for starting the light driver. A larger value indicates a lower priority. The recommended value is 100. If the priorities are the same, the device loading sequence is not ensured.
71                 preload = 0;                          // The value 0 means to load the driver by default during the startup of the system. The value 2 means the opposite.
72                 permission = 0664;                    // Permission for the device node created.
73                 moduleName = "HDF_LIGHT";             // Light driver name. The value must be the same as the value of moduleName in the driver entry structure.
74                 serviceName = "hdf_light";            // Service published by the light driver. The service name must be unique.
75                 deviceMatchAttr = "hdf_light_driver"; // Keyword matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver.
76             }
77         }
78     }
79     ```
80
812. Configure the private HCS of the light driver.
82
83   - Code path: **vendor\hihope\rk3568\hdf_config\khdf\light\light_config.hcs**.
84
85   - The code is as follows:
86
87     ```c
88     root {
89         lightConfig {
90             boardConfig {
91                 match_attr = "hdf_light_driver";
92                 lightAttr {
93                     light01 {
94                         lightId = [1];    // Lightid can contain multiple logical light IDs. For example, 1 indicates the power indicator.
95                         lightName = "battery";
96                         lightNumber = 1;
97                         busRNum = 147;    // GPIO value corresponding to red (light effect color).
98                         busGNum = 146;    // GPIO value corresponding to green (light effect color).
99                         busBNum = 149;    // GPIO value corresponding to blue (light effect color).
100                         defaultBrightness = 0X00FFFFFF; // Default luminance value of the system. B: bits 0 to 7; R: bits 8 to 15; G: bits 16 to 23; extended bits 24 to 31.
101                         onTime = 50;      // Minimum duration (in milliseconds) supported by the system when the flash is on.
102                         offTime = 50;     // Minimum duration (in milliseconds) supported by the system when the flash is off.
103                     }
104                 }
105             }
106         }
107     }
108     ```
109
1103. Implement the light driver in **drivers\hdf_core\framework\model\misc\light\driver\src\light_driver.c**.
111
112   - Define the **HdfDriverEntry** object of the light driver. The driver entry function is defined as follows:
113
114     ```c
115     /* Register the light entry data structure object. */
116     struct HdfDriverEntry g_lightDriverEntry = {
117         .moduleVersion = 1,            // Version of the light module.
118         .moduleName = "HDF_LIGHT",     // Light module name, which must be the same as the value of moduleName in the device_info.hcs file.
119         .Bind = BindLightDriver,       // Bind() of the light driver.
120         .Init = InitLightDriver,       // Init() of the light driver.
121         .Release = ReleaseLightDriver, // Release() of the light driver.
122     };
123     /* Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls Bind() and then Init() to load the driver. If Init() fails to be called, the HDF calls Release() to release resources and exit. */
124     HDF_INIT(g_lightDriverEntry);
125     ```
126
127   - Implement **Bind()** of the light driver.
128
129     ```c
130     /* Bind the external service provided by the light driver to the HDF. */
131     int32_t BindLightDriver(struct HdfDeviceObject *device)
132     {
133         struct LightDriverData *drvData = NULL;
134
135         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
136     	/* Allocate resources for private interfaces. */
137         drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData));
138         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL);
139     	/* Functions to be dispatched. */
140         drvData->ioService.Dispatch = DispatchLight;
141         drvData->device = device;
142         device->service = &drvData->ioService;
143         g_lightDrvData = drvData;
144
145         return HDF_SUCCESS;
146     }
147     ```
148
149   - Implement **Init()** of the light driver.
150
151     ```c
152     /* Initialize the light driver. */
153     int32_t InitLightDriver(struct HdfDeviceObject *device)
154     {
155         struct LightDriverData *drvData = NULL;
156
157         drvData = (struct LightDriverData *)device->service;
158
159         if (OsalMutexInit(&drvData->mutex) != HDF_SUCCESS) {
160             return HDF_FAILURE;
161         }
162     	/* Initialize the workqueue. */
163         if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) {
164             return HDF_FAILURE;
165         }
166     	/* Initialize work items. */
167         if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) {
168             return HDF_FAILURE;
169         }
170     	/* Parse the HCS. */
171         if (GetLightConfigData(device->property) != HDF_SUCCESS) {
172             return HDF_FAILURE;
173         }
174     	/* Set the GPIO pin direction. */
175         if (SetLightGpioDir(drvData) != HDF_SUCCESS) {
176             return HDF_FAILURE;
177         }
178
179         return HDF_SUCCESS;
180     }
181     ```
182
183   - Implement **Release()** of the light driver. When the driver is unloaded or **Init** fails to be executed, **Release()** can be used to release resources. The implementation is as follows:
184
185     ```c
186     /* Release the resources allocated for driver initialization. */
187     void ReleaseLightDriver(struct HdfDeviceObject *device)
188     {
189         int32_t i;
190         struct LightDriverData *drvData = NULL;
191         /* Release the allocated resources. */
192         for (i = LIGHT_ID_NONE; i < LIGHT_ID_BUTT; ++i) {
193             if (drvData->info[i] != NULL) {
194                 OsalMemFree(drvData->info[i]);
195                 drvData->info[i] = NULL;
196             }
197         }
198     	/* Destroy the work queue resource if the sensor is in position. */
199         HdfWorkDestroy(&drvData->work);
200         HdfWorkQueueDestroy(&drvData->workQueue);
201         (void)OsalMutexDestroy(&drvData->mutex);
202         OsalMemFree(drvData);
203         g_lightDrvData = NULL;
204     }
205     ```
206
207   - The light driver parses the light device management configuration information from the HCS file.
208
209     ```c
210     /* Obtain the Light basic configuration from the HCS file. */
211     static int32_t GetLightBaseConfigData(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser,
212         uint32_t lightId)
213     {
214         int32_t ret;
215         uint32_t *defaultBrightness = NULL;
216         struct LightDriverData *drvData = NULL;
217         const char *name = NULL;
218
219         drvData = GetLightDrvData();
220         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
221         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM);
222         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM);
223     	/* Types are used as subscripts to create space. */
224         drvData->info[lightId] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo));
225         if (drvData->info[lightId] == NULL) {
226             HDF_LOGE("%s: malloc fail", __func__);
227             return HDF_FAILURE;
228         }
229     	 /* Fill in the light device information. */
230         ret = parser->GetUint32(node, "busRNum", (uint32_t *)&drvData->info[lightId]->busRNum, 0);
231         if (ret != HDF_SUCCESS) {
232             drvData->info[lightId]->busRNum = LIGHT_INVALID_GPIO;
233         }
234
235         ret = parser->GetUint32(node, "busGNum", (uint32_t *)&drvData->info[lightId]->busGNum, 0);
236         if (ret != HDF_SUCCESS) {
237             drvData->info[lightId]->busGNum = LIGHT_INVALID_GPIO;
238         }
239
240         ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[lightId]->busBNum, 0);
241         if (ret != HDF_SUCCESS) {
242             drvData->info[lightId]->busBNum = LIGHT_INVALID_GPIO;
243         }
244
245         ret = parser->GetString(node, "lightName", &name, NULL);
246         if (ret != HDF_SUCCESS) {
247             HDF_LOGE("%s:get lightName failed!", __func__);
248             return HDF_FAILURE;
249         }
250
251         if (strcpy_s(drvData->info[lightId]->lightInfo.lightName, NAME_MAX_LEN, name) != EOK) {
252             HDF_LOGE("%s:copy lightName failed!", __func__);
253             return HDF_FAILURE;
254         }
255
256         ret = parser->GetUint32(node, "lightNumber", (uint32_t *)&drvData->info[lightId]->lightInfo.lightNumber, 0);
257         if (ret != HDF_SUCCESS) {
258             HDF_LOGE("%s:get lightNumber failed!", __func__);
259             return HDF_FAILURE;
260         }
261
262         defaultBrightness = (uint32_t *)&drvData->info[lightId]->defaultBrightness;
263         ret = parser->GetUint32(node, "defaultBrightness", defaultBrightness, 0);
264         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "defaultBrightness");
265         ret = parser->GetUint32(node, "onTime", &drvData->info[lightId]->onTime, 0);
266         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "onTime");
267         ret = parser->GetUint32(node, "offTime", &drvData->info[lightId]->offTime, 0);
268         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "offTime");
269
270         drvData->info[lightId]->lightBrightness = 0;
271         drvData->info[lightId]->lightState = LIGHT_STATE_STOP;
272
273         return HDF_SUCCESS;
274     }
275     ```
276
277   - Allocate resources and parse the HCS configuration information as follows:
278
279     ```c
280     /* Allocate resources and parse the HCS. */
281     static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser)
282     {
283         int32_t ret;
284         uint32_t i;
285         uint32_t temp;
286         struct LightDriverData *drvData = NULL;
287
288         drvData = GetLightDrvData();
289         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
290         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM);
291         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM);
292     	 /* Obtain the number of supported light types from the HCS. */
293         drvData->lightNum = (uint32_t)parser->GetElemNum(node, "lightId");
294         if (drvData->lightNum > LIGHT_ID_NUM) {
295             HDF_LOGE("%s: lightNum cross the border", __func__);
296             return HDF_FAILURE;
297         }
298
299         ret = memset_s(drvData->info, sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT, 0,
300             sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT);
301         CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "memset_s");
302
303         for (i = 0; i < drvData->lightNum; ++i) {
304             /* Obtain the light type. */
305             ret = parser->GetUint32ArrayElem(node, "lightId", i, &temp, 0);
306             CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId");
307
308             if (temp >= LIGHT_ID_BUTT) {
309                 HDF_LOGE("%s: light id invalid para", __func__);
310                 return HDF_FAILURE;
311             }
312
313             ret = GetLightBaseConfigData(node, parser, temp);
314             if (ret != HDF_SUCCESS) {
315                 HDF_LOGE("%s: get light base config fail", __func__);
316                 return HDF_FAILURE;
317             }
318         }
319
320         return HDF_SUCCESS;
321     }
322     ```
323
324   - Use the internal APIs of the light driver to obtain the light type information, set the blinking mode, turn on and trun off lights, and create and destroy timers based on the blinking mode.
325
326     - The **GetAllLightInfo** interface is implemented as follows:
327
328       ```c
329       /* The light driver service calls GetAllLightInfo() to obtain the light type information. */
330       static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply)
331       {
332           (void)data;
333           uint32_t i;
334           struct LightInfo lightInfo;
335           struct LightDriverData *drvData = NULL;
336
337           drvData = GetLightDrvData();
338           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
339           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM);
340
341           if (!HdfSbufWriteUint32(reply, drvData->lightNum)) {
342               HDF_LOGE("%s: write sbuf failed", __func__);
343               return HDF_FAILURE;
344           }
345
346           for (i = 0; i < LIGHT_ID_BUTT; ++i) {
347               if (drvData->info[i] == NULL) {
348                   continue;
349               }
350               lightInfo.lightId = i;
351
352               if (!HdfSbufWriteUint32(reply, lightInfo.lightId)) {
353                   HDF_LOGE("%s: write lightId failed", __func__);
354                   return HDF_FAILURE;
355               }
356
357               if (strcpy_s(lightInfo.lightName, NAME_MAX_LEN, drvData->info[i]->lightInfo.lightName) != EOK) {
358                   HDF_LOGE("%s:copy lightName failed!", __func__);
359                   return HDF_FAILURE;
360               }
361
362               if (!HdfSbufWriteString(reply, (const char *)lightInfo.lightName)) {
363                   HDF_LOGE("%s: write lightName failed", __func__);
364                   return HDF_FAILURE;
365               }
366
367               lightInfo.lightNumber = drvData->info[i]->lightInfo.lightNumber;
368               if (!HdfSbufWriteUint32(reply, lightInfo.lightNumber)) {
369                   HDF_LOGE("%s: write lightNumber failed", __func__);
370                   return HDF_FAILURE;
371               }
372
373               lightInfo.lightType = HDF_LIGHT_TYPE_RGB_COLOR;
374               if (!HdfSbufWriteUint32(reply, lightInfo.lightType)) {
375                   HDF_LOGE("%s: write lightType failed", __func__);
376                   return HDF_FAILURE;
377               }
378           }
379
380           return HDF_SUCCESS;
381       }
382       ```
383
384     - The **TurnOnLight** interface is implemented as follows:
385
386       ```c
387       /* Enable lights based on the specified light type and input parameters. */
388       static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
389       {
390           (void)reply;
391           uint32_t len;
392           struct LightEffect *buf = NULL;
393           struct LightDriverData *drvData = NULL;
394
395           drvData = GetLightDrvData();
396           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
397
398           if (drvData->info[lightId] == NULL) {
399               HDF_LOGE("%s: light id info is null", __func__);
400               return HDF_FAILURE;
401           }
402
403           if (!HdfSbufReadBuffer(data, (const void **)&buf, &len)) {
404               HDF_LOGE("%s: light read data failed", __func__);
405               return HDF_FAILURE;
406           }
407       	/* Receive the lightBrightness value passed in. Bits 24 to 31 indicate extension bits, bits 16 to 23 indicate red, bits 8 to 15 indicate green, and bits 0 to 7 indicate blue. If lightBrightness is not 0, enable the light in the specified color.
408              Set the light brightness to a value ranging from 0 to 255 if supported. */
409           if (buf->lightColor.colorValue.rgbColor.r != 0) {
410               drvData->info[lightId]->lightBrightness |= 0X00FF0000;
411           }
412
413           if (buf->lightColor.colorValue.rgbColor.g != 0) {
414               drvData->info[lightId]->lightBrightness |= 0X0000FF00;
415           }
416
417           if (buf->lightColor.colorValue.rgbColor.b != 0) {
418               drvData->info[lightId]->lightBrightness |= 0X000000FF;
419           }
420       	/* The light is steady on. */
421           if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) {
422               return UpdateLight(lightId, LIGHT_STATE_START);
423           }
424       	/* The light is blinking. */
425           if (buf->flashEffect.flashMode == LIGHT_FLASH_BLINK) {
426               drvData->info[lightId]->onTime = (buf->flashEffect.onTime < drvData->info[lightId]->onTime) ?
427               drvData->info[lightId]->onTime : buf->flashEffect.onTime;
428               drvData->info[lightId]->offTime = (buf->flashEffect.offTime < drvData->info[lightId]->offTime) ?
429               drvData->info[lightId]->offTime : buf->flashEffect.offTime;
430       		/* Create a timer. */
431               if (OsalTimerCreate(&drvData->timer, LIGHT_WAIT_TIME, LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) {
432                   HDF_LOGE("%s: create light timer fail!", __func__);
433                   return HDF_FAILURE;
434               }
435       		/* Start the timer. */
436               if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) {
437                   HDF_LOGE("%s: start light timer fail!", __func__);
438                   return HDF_FAILURE;
439               }
440           }
441
442           return HDF_SUCCESS;
443       }
444       ```
445
446     - The **TurnOffLight** interface is implemented as follows:
447
448       ```c
449       /* Turn off lights based on the specified light type. */
450       static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
451       {
452           (void)data;
453           (void)reply;
454           struct LightDriverData *drvData = NULL;
455
456           drvData = GetLightDrvData();
457           CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
458
459           if (drvData->info[lightId] == NULL) {
460               HDF_LOGE("%s: light id info is null", __func__);
461               return HDF_FAILURE;
462           }
463
464           if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) {
465               HDF_LOGE("%s: gpio write failed", __func__);
466               return HDF_FAILURE;
467           }
468
469           drvData->info[lightId]->lightState = LIGHT_STATE_STOP;
470           drvData->info[lightId]->lightBrightness = 0;
471       	/* Destroy the timer. */
472           if (drvData->timer.realTimer != NULL) {
473               if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) {
474                   HDF_LOGE("%s: delete light timer fail!", __func__);
475                   return HDF_FAILURE;
476               }
477           }
478
479           return HDF_SUCCESS;
480       }
481       ```
482
4835. Implement the HDIs of the light controller.
484
485   - Code path: **drivers\peripheral\light\hal\src\light_controller.c**.
486
487   - The **GetLightInfo** interface is implemented as follows:
488
489     ```c
490     /* Read the light type information from HdfSBuf in the light abstract driver to LightInfo. */
491     static int32_t ReadLightInfo(struct HdfSBuf *reply, struct LightDevice *priv)
492     {
493         struct LightInfo *pos = NULL;
494         const char *name = NULL;
495
496         if (!HdfSbufReadUint32(reply, &priv->lightNum)) {
497             HDF_LOGE("%s: sbuf read lightNum failed", __func__);
498             return HDF_FAILURE;
499         }
500
501         if (priv->lightInfoEntry != NULL) {
502             OsalMemFree(priv->lightInfoEntry);
503             priv->lightInfoEntry = NULL;
504         }
505
506         priv->lightInfoEntry = (struct LightInfo *)OsalMemCalloc(sizeof(*priv->lightInfoEntry) * priv->lightNum);
507         if (priv->lightInfoEntry == NULL) {
508             HDF_LOGE("%s: malloc fail", __func__);
509             return HDF_FAILURE;
510         }
511
512         pos = priv->lightInfoEntry;
513
514         for (uint32_t i = 0; i < priv->lightNum; ++i) {
515             if (!HdfSbufReadUint32(reply, &pos->lightId)) {
516                 HDF_LOGE("%{public}s:read lightId failed!", __func__);
517                 return HDF_FAILURE;
518             }
519
520             name = HdfSbufReadString(reply);
521             if (strcpy_s(pos->lightName, NAME_MAX_LEN, name) != EOK) {
522                 HDF_LOGE("%{public}s:copy lightName failed!", __func__);
523                 return HDF_FAILURE;
524             }
525
526             if (!HdfSbufReadUint32(reply, &pos->lightNumber)) {
527                 HDF_LOGE("%{public}s:read lightNumber failed!", __func__);
528                 return HDF_FAILURE;
529             }
530
531             if (!HdfSbufReadInt32(reply, &pos->lightType)) {
532                 HDF_LOGE("%{public}s:read lightType failed!", __func__);
533                 return HDF_FAILURE;
534             }
535             pos++;
536         }
537
538         return HDF_SUCCESS;
539     }
540     /* GetLightInfo interface implementation. */
541     static int32_t GetLightInfo(struct LightInfo **lightInfo, uint32_t *count)
542     {
543         if ((lightInfo == NULL) || (count == NULL)) {
544             HDF_LOGE("%s:line:%{public}d pointer is null and return ret", __func__, __LINE__);
545             return HDF_FAILURE;
546         }
547
548         struct LightDevice *priv = GetLightDevicePriv();
549
550         if (priv->lightNum > 0) {
551             *count = priv->lightNum;
552             *lightInfo = priv->lightInfoEntry;
553             return HDF_SUCCESS;
554         }
555
556         (void)OsalMutexLock(&priv->mutex);
557         struct HdfSBuf *reply = HdfSbufObtainDefaultSize();
558         if (reply == NULL) {
559             HDF_LOGE("%s: get sbuf failed", __func__);
560             (void)OsalMutexUnlock(&priv->mutex);
561             return HDF_FAILURE;
562         }
563
564         int32_t ret = SendLightMsg(LIGHT_IO_CMD_GET_INFO_LIST, NULL, reply);
565         if (ret != HDF_SUCCESS) {
566             HDF_LOGE("%{public}s: Light send cmd failed, ret[%{public}d]", __func__, ret);
567             HdfSbufRecycle(reply);
568             (void)OsalMutexUnlock(&priv->mutex);
569             return ret;
570         }
571
572         if (ReadLightInfo(reply, priv) != HDF_SUCCESS) {
573             HdfSbufRecycle(reply);
574             (void)OsalMutexUnlock(&priv->mutex);
575             return HDF_FAILURE;
576         }
577
578         HdfSbufRecycle(reply);
579         (void)OsalMutexUnlock(&priv->mutex);
580
581         *count = priv->lightNum;
582         *lightInfo = priv->lightInfoEntry;
583
584         return HDF_SUCCESS;
585     }
586     ```
587
588   - The **OnLight** interface is implemented as follows:
589
590     ```c
591     static int32_t OnLight(uint32_t lightId, struct LightEffect *effect)
592     {
593         int32_t ret;
594
595         if (effect == NULL) {
596             HDF_LOGE("%{public}s: effect is NULL", __func__);
597             return HDF_FAILURE;
598         }
599
600         ret = OnLightValidityJudgment(lightId, effect);
601         if (ret != HDF_SUCCESS) {
602             HDF_LOGE("%{public}s: effect is false", __func__);
603             return ret;
604         }
605
606         struct LightDevice *priv = GetLightDevicePriv();
607         (void)OsalMutexLock(&priv->mutex);
608
609         struct HdfSBuf *msg = HdfSbufObtainDefaultSize();
610         if (msg == NULL) {
611             HDF_LOGE("%{public}s: Failed to obtain sBuf size", __func__);
612             (void)OsalMutexUnlock(&priv->mutex);
613             return HDF_FAILURE;
614         }
615
616         if (!HdfSbufWriteInt32(msg, lightId)) {
617             HDF_LOGE("%{public}s: Light write id failed", __func__);
618             HdfSbufRecycle(msg);
619             (void)OsalMutexUnlock(&priv->mutex);
620             return HDF_FAILURE;
621         }
622
623         if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_ENABLE)) {
624             HDF_LOGE("%{public}s: Light write enable failed", __func__);
625             HdfSbufRecycle(msg);
626             (void)OsalMutexUnlock(&priv->mutex);
627             return HDF_FAILURE;
628         }
629
630         if (!HdfSbufWriteBuffer(msg, effect, sizeof(*effect))) {
631             HDF_LOGE("%{public}s: Light write enable failed", __func__);
632             HdfSbufRecycle(msg);
633             (void)OsalMutexUnlock(&priv->mutex);
634             return HDF_FAILURE;
635         }
636
637         ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL);
638         if (ret != HDF_SUCCESS) {
639             HDF_LOGE("%{public}s: Light enable failed, ret[%{public}d]", __func__, ret);
640         }
641         HdfSbufRecycle(msg);
642         (void)OsalMutexUnlock(&priv->mutex);
643
644         if (memcpy_s(&g_lightEffect, sizeof(g_lightEffect), effect, sizeof(*effect)) != EOK) {
645             HDF_LOGE("%{public}s: Light effect cpy faild", __func__);
646             return HDF_FAILURE;
647         }
648
649         g_lightState[lightId] = LIGHT_ON;
650
651         return ret;
652     }
653     ```
654
655   - The **OffLight** interface is implemented as follows:
656
657     ```c
658     static int32_t OffLight(uint32_t lightId)
659     {
660         if (lightId >= LIGHT_ID_BUTT) {
661             HDF_LOGE("%{public}s: id not supported", __func__);
662             return HDF_FAILURE;
663         }
664
665         struct LightDevice *priv = GetLightDevicePriv();
666         (void)OsalMutexLock(&priv->mutex);
667
668         struct HdfSBuf *msg = HdfSbufObtainDefaultSize();
669         if (msg == NULL) {
670             HDF_LOGE("%{public}s: Failed to obtain sBuf", __func__);
671             (void)OsalMutexUnlock(&priv->mutex);
672             return HDF_FAILURE;
673         }
674
675         if (!HdfSbufWriteInt32(msg, lightId)) {
676             HDF_LOGE("%{public}s: Light write id failed", __func__);
677             HdfSbufRecycle(msg);
678             (void)OsalMutexUnlock(&priv->mutex);
679             return HDF_FAILURE;
680         }
681
682         if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_DISABLE)) {
683             HDF_LOGE("%{public}s: Light write disable failed", __func__);
684             HdfSbufRecycle(msg);
685             (void)OsalMutexUnlock(&priv->mutex);
686             return HDF_FAILURE;
687         }
688
689         int32_t ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL);
690         if (ret != HDF_SUCCESS) {
691             HDF_LOGE("%{public}s: Light disable failed, ret[%{public}d]", __func__, ret);
692         }
693         HdfSbufRecycle(msg);
694         (void)OsalMutexUnlock(&priv->mutex);
695
696         g_lightState[lightId] = LIGHT_OFF;
697
698         return ret;
699     }
700     ```
701
702   - The **OnMultiLights** interface is implemented as follows:
703
704     ```c
705     static int32_t OnMultiLights(uint32_t lightId, const struct LightColor *colors, const uint32_t count)
706     {
707         int32_t ret;
708         struct HdfSBuf *sbuf = NULL;
709
710         ret = OnMultiLightsValidityJudgment(lightId, colors, count);
711         if (ret != HDF_SUCCESS) {
712             return ret;
713         }
714
715         struct LightDevice *priv = GetLightDevicePriv();
716         (void)OsalMutexLock(&priv->mutex);
717         sbuf = HdfSbufObtain(sizeof(struct LightColor) * count);
718         if (sbuf == NULL) {
719             return HDF_DEV_ERR_NO_MEMORY;
720         }
721
722         if (!HdfSbufWriteInt32(sbuf, lightId)) {
723             ret = HDF_FAILURE;
724             goto EXIT;
725         }
726
727         if (!HdfSbufWriteInt32(sbuf, LIGHT_OPS_IO_CMD_ENABLE_MULTI_LIGHTS)) {
728             ret = HDF_FAILURE;
729             goto EXIT;
730         }
731
732         if (!HdfSbufWriteBuffer(sbuf, colors, sizeof(*colors))) {
733             ret = HDF_FAILURE;
734             goto EXIT;
735         }
736
737         if (!HdfSbufWriteInt32(sbuf, count)) {
738             ret = HDF_FAILURE;
739             goto EXIT;
740         }
741
742         ret = SendLightMsg(LIGHT_IO_CMD_OPS, sbuf, NULL);
743         if (ret != HDF_SUCCESS) {
744         }
745     	return ret;
746
747     EXIT:
748         HdfSbufRecycle(sbuf);
749         (void)OsalMutexUnlock(&priv->mutex);
750     }
751     ```
752
753### Verification
754
755After the driver is developed, develop auto-test cases in the light unit test to verify the basic functionalities of the driver. Use the developer self-test platform as the test environment.
756
757- The reference test code is as follows:
758
759  ```c
760  #include <cmath>
761  #include <cstdio>
762  #include <gtest/gtest.h>
763  #include <securec.h>
764  #include "hdf_base.h"
765  #include "osal_time.h"
766  #include "osal_mem.h"
767  #include "light_if.h"
768  #include "light_type.h"
769
770  using namespace testing::ext;
771  const struct LightInterface *g_lightDev = nullptr;
772  static struct LightInfo *g_lightInfo = nullptr;
773  static uint32_t g_count = 0;
774  /* Initialize the LightInterfaceInstance before executing the test case. */
775  class HdfLightTest : public testing::Test {
776  public:
777      static void SetUpTestCase();
778      static void TearDownTestCase();
779      void SetUp();
780      void TearDown();
781  };
782
783  void HdfLightTest::SetUpTestCase()
784  {
785      g_lightDev = NewLightInterfaceInstance();
786      if (g_lightDev == nullptr) {
787          printf("test light get Module instance fail\n\r");
788      }
789      int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count);
790      if (ret == -1) {
791          printf("get light informations fail\n\r");
792      }
793  }
794
795  /* After the test case is executed, release the resources used by the test case. */
796  void HdfLightTest::TearDownTestCase()
797  {
798      if(g_lightDev != nullptr){
799          FreeLightInterfaceInstance();
800          g_lightDev = nullptr;
801      }
802  }
803
804  void HdfLightTest::SetUp()
805  {
806  }
807
808  void HdfLightTest::TearDown()
809  {
810  }
811
812  /* Obtain the test light type. */
813  HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1)
814  {
815      struct LightInfo *info = nullptr;
816
817      if (g_lightInfo == nullptr) {
818          EXPECT_NE(nullptr, g_lightInfo);
819          return;
820      }
821
822      printf("get light list num[%u]\n\r", g_count);
823      info = g_lightInfo;
824
825      for (uint32_t i = 0; i < g_count; ++i) {
826          printf("get lightId[%u]\n\r", info->lightId);
827          EXPECT_GE(info->lightId, 0);
828          EXPECT_LE(info->lightId, 4);
829          info++;
830      }
831  }
832
833  /* Verify the steady on state of the light. */
834  HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1)
835  {
836      uint32_t i;
837      struct LightEffect effect;
838      effect.flashEffect.flashMode = 0;
839      effect.flashEffect.onTime = 0;
840      effect.flashEffect.offTime = 0;
841
842      for (i = 0; i < g_count; ++i) {
843          effect.lightColor.colorValue.rgbColor.r = 255;
844          effect.lightColor.colorValue.rgbColor.g = 0;
845          effect.lightColor.colorValue.rgbColor.b = 0;
846          int32_t ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect);
847          EXPECT_EQ(0, ret);
848
849     OsalSleep(2);
850
851     ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId);
852          EXPECT_EQ(0, ret);
853
854          effect.lightColor.colorValue.rgbColor.r = 0;
855          effect.lightColor.colorValue.rgbColor.g = 255;
856          effect.lightColor.colorValue.rgbColor.b = 0;
857          ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect);
858          EXPECT_EQ(0, ret);
859
860          OsalSleep(2);
861
862          ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId);
863          EXPECT_EQ(0, ret);
864      }
865  }
866  ```
867
868- The reference code of the **BUILD.gn** file is as follows:
869
870  ```c
871  import("//build/test.gni")
872  import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")
873
874  module_output_path = "drivers_peripheral_light/light"
875  ohos_unittest("light_test") {
876    module_out_path = module_output_path
877    sources = [ "light_test.cpp" ]
878    include_dirs = [
879      "//drivers/peripheral/light/interfaces/include",
880    ]
881    deps = [ "//drivers/peripheral/light/hal:hdi_light" ]
882
883    external_deps = [
884      "c_utils:utils",
885      "hdf_core:libhdf_utils",
886   	"hiviewdfx_hilog_native:libhilog",
887    ]
888
889    cflags = [
890      "-Wall",
891      "-Wextra",
892      "-Werror",
893      "-Wno-format",
894      "-Wno-format-extra-args",
895    ]
896
897    install_enable = true
898    install_images = [ "vendor" ]
899    module_install_dir = "bin"
900    part_name = "unionman_products"
901  }
902  ```
903