1# Light 2 3 4## 概述 5 6### 功能简介 7 8Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接口,包括获取灯类型、配置点灯模式、配置灯闪烁效果、点灯、熄灯等。基于HDF(Hardware Driver Foundation)驱动框架开发的Light驱动模型,实现跨操作系统迁移,器件差异配置等功能。实现Light驱动“一次开发,多系统部署”的目标。Light驱动模型如图1所示: 9 10**图 1** Light驱动模型图 11 12 13 14### 运作机制 15 16通过介绍Light驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如图2所示: 17 18**图 2** Light驱动运行图 19 20 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.hcs。 58 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.hcs。 82 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.c。 109 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.c。 484 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