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 15 16### Working Principles 17 18The figure below shows how the light driver works. 19 20**Figure 2** How light driver works 21 22 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