• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Light
2
3
4## Overview
5
6### Light
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 the light module driver loads and starts on a Hi3516D V300 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 phone 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| API                                                      | Description                                                    |
46| ------------------------------------------------------------ | ------------------------------------------------------------ |
47| int32_t (*GetLightInfo)([out] struct LightInfo **lightInfo, [out] 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.|
48| int32_t (*TurnOnLight)([in] uint32_t lightId, [in] 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.|
49| int32_t (*TurnOffLight)([in] uint32_t lightId)                 | Turns off available lights in the list based on the specified light type.                    |
50
51### Development Procedure
521. Based on the HDF and the driver entry, complete the light abstract driver development (using the **Bind**, **Init**, **Release**, and **Dispatch** functions), resource configuration, and HCS parsing.
53
54   - Call **HDF_INIT** to register the driver entry with the HDF. Generally, the HDF calls the **Bind** function and then the **Init** function to load the driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit.
55   - The light driver model uses HDF configuration source (HCS). For details about HCS fields, see [Configuration Management](driver-hdf-manage.md). The light driver entry is defined as follows:
56
57     ```c
58     /* Register the light entry data structure object. */
59     struct HdfDriverEntry g_lightDriverEntry = {
60         .moduleVersion = 1,            // Version of the light module.
61         .moduleName = "HDF_LIGHT",     // Light module name, which must be the same as the value of moduleName in the device_info.hcs file.
62         .Bind = BindLightDriver,       // Bind() of the light driver.
63         .Init = InitLightDriver,       // Init() of the light driver.
64         .Release = ReleaseLightDriver, // Release() of the light driver.
65     };
66     /* Call HDF_INIT to register the driver entry with the HDF. */
67     HDF_INIT(g_lightDriverEntry);
68     ```
69
70   - Develop the light abstract driver. Specifically, implement the **Bind**, **Init**, **Release**, and **Dispatch** functions.
71
72     ```c
73     /* Dispatch the light driver. */
74     static int32_t DispatchLight(struct HdfDeviceIoClient *client,
75         int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
76     {
77         .....
78         if (cmd == LIGHT_IO_CMD_GET_INFO_LIST) {
79             CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM);
80             return GetAllLightInfo(data, reply);
81         }
82
83         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
84         (void)OsalMutexLock(&drvData->mutex);
85         if (!HdfSbufReadInt32(data, &lightId)) {
86             HDF_LOGE("%s: sbuf read lightId fail", __func__);
87             (void)OsalMutexUnlock(&drvData->mutex);
88             return HDF_ERR_INVALID_PARAM;
89         }
90         .....
91         ret = DispatchCmdHandle(lightId, data, reply);
92         (void)OsalMutexUnlock(&drvData->mutex);
93         return ret;
94     }
95
96     /* Bind the external service provided by the light driver to the HDF. */
97     int32_t BindLightDriver(struct HdfDeviceObject *device)
98     {
99         struct LightDriverData *drvData = NULL;
100
101         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
102         /* Allocate resources for private interfaces. */
103         drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData));
104         CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL);
105         /* Functions to be dispatched. */
106         drvData->ioService.Dispatch = DispatchLight;
107         drvData->device = device;
108         device->service = &drvData->ioService;
109         g_lightDrvData = drvData;
110         return HDF_SUCCESS;
111     }
112
113     /* Initialize the light driver. */
114     int32_t InitLightDriver(struct HdfDeviceObject *device)
115     {
116     	.....
117         /* Initialize the workqueue. */
118         if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) {
119             HDF_LOGE("%s: init workQueue fail!", __func__);
120             return HDF_FAILURE;
121         }
122         /* Initialize work items. */
123         if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) {
124             HDF_LOGE("%s: init work fail!", __func__);
125             return HDF_FAILURE;
126         }
127         /* Parse the HCS. */
128         if (GetLightConfigData(device->property) != HDF_SUCCESS) {
129             HDF_LOGE("%s: get light config fail!", __func__);
130             return HDF_FAILURE;
131         }
132         /* Set the GPIO pin direction. */
133         if (SetLightGpioDir(drvData) != HDF_SUCCESS) {
134             HDF_LOGE("%s: set light gpio dir fail!", __func__);
135             return HDF_FAILURE;
136         }
137
138         return HDF_SUCCESS;
139     }
140
141     /* Release the resources allocated for driver initialization. */
142     void ReleaseLightDriver(struct HdfDeviceObject *device)
143     {
144         .....
145         /* Release the allocated resources. */
146         for (i = LIGHT_TYPE_NONE; i < LIGHT_TYPE_BUTT; ++i) {
147
148             if (drvData->info[i] != NULL) {
149                 OsalMemFree(drvData->info[i]);
150                 drvData->info[i] = NULL;
151             }
152         }
153         /* Destroy workqueue resources. */
154         HdfWorkDestroy(&drvData->work);
155         HdfWorkQueueDestroy(&drvData->workQueue);
156         (void)OsalMutexDestroy(&drvData->mutex);
157         OsalMemFree(drvData);
158         g_lightDrvData = NULL;
159     }
160     ```
161
162   - The light device management module is responsible for publishing light device APIs in the system. During the system startup process, the HDF loads the device management driver based on **Light Host** in the HCS.
163
164     ```c
165     /* HCS of the light device. */
166     light :: host {
167         hostName = "light_host";
168         device_light :: device {
169             device0 :: deviceNode {
170                 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.
171                 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.
172                 preload = 0;                          // The value 0 means to load the driver by default during the startup of the system. The value 2 means the opposite.
173                 permission = 0664;                    // Permission for the device node created.
174                 moduleName = "HDF_LIGHT";             // Light driver name. The value must be the same as the value of moduleName in the driver entry structure.
175                 serviceName = "hdf_light";            // Service published by the light driver. The service name must be unique.
176                 deviceMatchAttr = "hdf_light_driver"; // Keyword for 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.
177             }
178         }
179     }
180     ```
181
1822. Parse the device attribute information and registers, and register them with the light device management module.
183
184   ```c
185   /* Allocate resources and parse the HCS. */
186   static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser)
187   {
188       .....
189       /* Obtain the number of supported light types from the HCS. */
190       drvData->lightNum = parser->GetElemNum(light, "lightId");
191       ....
192       for (i = 0; i < drvData->lightNum; ++i) {
193           /* Obtain the light type. */
194           ret = parser->GetUint32ArrayElem(light, "lightId", i, &temp, 0);
195           CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId");
196       }
197
198       for (i = 0; i < drvData->lightNum; ++i) {
199           .....
200           /* Types are used as subscripts to create space. */
201           drvData->info[temp] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo));
202           .....
203           /* Fill in the light device information. */
204           ret = parser->GetUint32(node, "busRNum", (uint32_t *)&drvData->info[temp]->busRNum, 0);
205           if (ret != HDF_SUCCESS) {
206               /* If busNum fails to be obtained, the color of the light corresponding to busNum cannot be set. */
207               drvData->info[temp]->busRNum = LIGHT_INVALID_GPIO;
208           }
209           ret = parser->GetUint32(node, "busGNum", (uint32_t *)&drvData->info[temp]->busGNum, 0);
210           if (ret != HDF_SUCCESS) {
211               drvData->info[temp]->busGNum = LIGHT_INVALID_GPIO;
212           }
213           ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[temp]->busBNum, 0);
214           if (ret != HDF_SUCCESS) {
215               drvData->info[temp]->busBNum = LIGHT_INVALID_GPIO;
216           }
217       }
218       .....
219       return HDF_SUCCESS;
220   }
221   ```
222
2233. Implement the APIs for obtaining the light type, setting the blinking mode, turning on and off lights, and creating and destroying a timer based on the blinking mode.
224
225   ```c
226   /* Call GetAllLightInfo() to obtain the light types, call TurnOnLight() to turn on lights,
227      and call TurnOffLight() to turn off lights. */
228   static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply)
229   {
230       .....
231       /* Obtain the number of light types. */
232       if (!HdfSbufWriteUint32(reply, drvData->lightNum)) {
233           HDF_LOGE("%s: write sbuf fail", __func__);
234           return HDF_FAILURE;
235       }
236       for (i = 0; i < LIGHT_TYPE_BUTT; ++i) {
237           if (drvData->info[i] == NULL) {
238               continue;
239           }
240           lightInfo.lightId = i;
241           lightInfo.reserved = NULL;
242           /* Fill the light device information into the reply. */
243           if (!HdfSbufWriteBuffer(reply, &lightInfo, sizeof(lightInfo))) {
244               HDF_LOGE("%s: write sbuf fail", __func__);
245               return HDF_FAILURE;
246           }
247       }
248
249       return HDF_SUCCESS;
250   }
251
252   /* Update the status of the lights of the specified type. */
253   static int32_t UpdateLight(uint32_t lightId, uint32_t lightOn)
254   {
255       .....
256       /* If the lightBrightness value passed in is invalid, use the default value. */
257       if (drvData->info[lightId]->lightBrightness == 0) {
258           lightBrightness = drvData->info[lightId]->defaultBrightness;
259       } else {
260           lightBrightness = drvData->info[lightId]->lightBrightness;
261       }
262       /* If bits 0 to 7 are not 0, output the GPIO pins corresponding to blue based on the status of lightOn. */
263       if ((lightBrightness & LIGHT_MAKE_B_BIT) != 0) {
264           ret = WriteGpio(drvData->info[lightId]->busBNum, lightOn);
265           if (ret != HDF_SUCCESS) {
266               HDF_LOGE("%s: write blue gpio fail", __func__);
267               return HDF_FAILURE;
268           }
269       }
270       /* If bits 8 to 15 are not 0, output the GPIO pins corresponding to green based on the status of lightOn. */
271       if ((lightBrightness & LIGHT_MAKE_G_BIT) != 0) {
272           ret = WriteGpio(drvData->info[lightId]->busGNum, lightOn);
273           if (ret != HDF_SUCCESS) {
274               HDF_LOGE("%s: write green gpio fail", __func__);
275               return HDF_FAILURE;
276           }
277       }
278       /* If bits 16 to 23 are not 0, output the GPIO pins corresponding to red based on the status of lightOn. */
279       if ((lightBrightness & LIGHT_MAKE_R_BIT) != 0) {
280           ret = WriteGpio(drvData->info[lightId]->busRNum, lightOn);
281           if (ret != HDF_SUCCESS) {
282               HDF_LOGE("%s: write red gpio fail", __func__);
283               return HDF_FAILURE;
284           }
285       }
286       .....
287   }
288
289   /* Enable lights based on the specified light type and input parameters. */
290   static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
291   {
292       .....
293       /* Receive the lightBrightness value passed in. Bits 24 to 31 are 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, turn on the light in the specified color.
294          Set the light brightness to a value ranging from 0 to 255 if supported. */
295       drvData->info[lightId]->lightBrightness = buf->lightBrightness;
296       /* The light is steady on. */
297       if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) {
298           return UpdateLight(lightId, LIGHT_STATE_START);
299       }
300       /* The light is blinking. */
301       if (buf->flashEffect.flashMode == LIGHT_FLASH_TIMED) {
302           drvData->info[lightId]->lightState = LIGHT_STATE_START;
303           /* If the specified blinking duration is less than the minimum time period supported by the system, the time configured by the system (in HCS) is used. */
304           drvData->info[lightId]->onTime = buf->flashEffect.onTime < drvData->info[lightId]->onTime ?
305           drvData->info[lightId]->onTime : buf->flashEffect.onTime;
306           drvData->info[lightId]->offTime = buf->flashEffect.offTime < drvData->info[lightId]->offTime ?
307           drvData->info[lightId]->offTime : buf->flashEffect.offTime;
308           /* Create a timer. */
309           if (OsalTimerCreate(&drvData->timer, drvData->info[lightId]->onTime,
310               LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) {
311               HDF_LOGE("%s: create light timer fail!", __func__);
312               return HDF_FAILURE;
313           }
314           /* Start the periodic timer. */
315           if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) {
316               HDF_LOGE("%s: start light timer fail!", __func__);
317               return HDF_FAILURE;
318           }
319       }
320       return HDF_SUCCESS;
321   }
322
323   /* Turn off lights based on the specified light type. */
324   static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
325   {
326       /* Delete the timer. */
327       if (drvData->timer.realTimer != NULL) {
328
329           if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) {
330               HDF_LOGE("%s: delete haptic timer fail!", __func__);
331           }
332       }
333       if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) {
334           HDF_LOGE("%s: gpio write fail", __func__);
335           return HDF_FAILURE;
336       }
337
338       return HDF_SUCCESS;
339   }
340   ```
341
342### Verification
343
344After 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.
345
346```c++
347/* Initialize the LightInterfaceInstance before executing the test case. */
348void HdfLightTest::SetUpTestCase()
349{
350    g_lightDev = NewLightInterfaceInstance();
351    if (g_lightDev == nullptr) {
352        printf("test light get Module instance fail\n\r");
353    }
354    int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count);
355    if (ret == -1) {
356        printf("get light informations fail\n\r");
357    }
358}
359
360/* After the test case is executed, release the resources used by the test case. */
361void HdfLightTest::TearDownTestCase()
362{
363    if(g_lightDev != nullptr){
364        FreeLightInterfaceInstance();
365        g_lightDev = nullptr;
366    }
367}
368
369/* Obtain the test light type. */
370HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1)
371{
372    struct LightInfo *info = nullptr;
373
374    if (g_lightInfo == nullptr) {
375        EXPECT_NE(nullptr, g_lightInfo);
376        return;
377    }
378
379    printf("get light list num[%d]\n\r", g_count);
380    info = g_lightInfo;
381
382    for (int i = 0; i < g_count; ++i) {
383        printf("get lightId[%d]\n\r", info->lightId);
384        EXPECT_GE(info->lightId, g_minLightId);
385        EXPECT_LE(info->lightId, g_maxLightId);
386        info++;
387    }
388}
389
390/* Verify the steady on state of the light. */
391HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1)
392{
393    int32_t i;
394    int32_t ret;
395    struct LightEffect effect;
396    effect->lightBrightness = 0x00800000;
397    effect->flashEffect.flashMode = LIGHT_FLASH_NONE;
398    effect->flashEffect.onTime = 0;
399    effect->flashEffect.offTime = 0;
400
401    for (i = 0; i < g_count; ++i) {
402
403        ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect);
404        EXPECT_EQ(0, ret);
405
406        OsalSleep(LIGHT_WAIT_TIME);
407
408        ret = g_lightDev->TurnOffLight(type);
409        EXPECT_EQ(0, ret);
410    }
411}
412
413/* Verify the blinking mode of the light. */
414HWTEST_F(HdfLightTest, EnableLight002, TestSize.Level1)
415{
416    int32_t i;
417    int32_t ret;
418    struct LightEffect effect;
419    effect->lightBrightness = 0x00800000;
420    effect->flashEffect.flashMode = LIGHT_FLASH_TIMED;
421    effect->flashEffect.onTime = g_onTime;
422    effect->flashEffect.offTime = g_offTime;
423
424    for (i = 0; i < g_count; ++i) {
425
426        ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect);
427        EXPECT_EQ(0, ret);
428
429        OsalSleep(LIGHT_WAIT_TIME);
430
431        ret = g_lightDev->TurnOffLight(type);
432        EXPECT_EQ(0, ret);
433    }
434}
435```
436