1# Light 2 3 4## 概述 5 6### 功能简介 7 8 Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接口,包括获取灯类型、配置点灯模式、配置灯闪烁效果、点灯、熄灯等。基于HDF(Hardware Driver Foundation)驱动框架开发的Light驱动模型,实现跨操作系统迁移,器件差异配置等功能。实现Light驱动“一次开发,多系统部署”的目标。Light驱动模型如[图1](#Light驱动模型图)所示: 9 10**图 1** Light驱动模型图 11 12 13 14### 运作机制 15 16通过介绍Light驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如[图2](#Light驱动运行图)所示: 17 18**图 2** Light驱动运行图 19 20 21 22Light驱动模型以标准系统Hi3516DV300为例,介绍整个驱动加载及运行流程: 23 241. 从device info HCS 的Light Host里读取Light设备管理配置信息。 252. 从light_config HCS读取Light数据配置信息。 263. 解析Light设备管理配置信息,并关联对应设备驱动。 274. 客户端下发Light Stub控制到服务端。 285. 服务端调用Light Stub控制。 296. 启动Light抽象驱动接口。 30 31## 开发指导 32 33### 场景介绍 34 35灯设备的控制,在实际生活中比比皆是,例如短信通知时闪灯、手机电量不足时预警、充电时根据充电进度变换灯的颜色等等。这些动作的实现,都需要使用Light驱动模型提供的接口,动态配置点灯模式、配置灯闪烁效果、点灯、熄灯等。 36 37### 接口说明 38 39Light驱动模型支持获取系统中所有灯的信息,动态配置闪烁模式和闪烁时间的能力。Light硬件服务调用GetLightInfo获取Light设备的基本信息;调用TurnOnLight接口启动配置的闪烁效果。Light驱动模型对外开放的API接口能力,参考[表1](#Light驱动模型对外API接口能力介绍)。 40 41**表1** Light驱动模型对外API接口能力介绍 42 43| 接口名 | 功能描述 | 44| ------------------------------------------------------------ | ------------------------------------------------------------ | 45| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | 获取系统中所有灯的信息,lightInfo表示灯设备的基本信息,count表示获取灯的个数。 | 46| int32_t (*TurnOnLight)(uint32_t type, struct LightEffect *effect) | 根据指定的灯类型打开灯列表中可用的灯,type表示灯类型,effect表示要设置的效果信息。 | 47| int32_t (*TurnOffLight)(uint32_t type) | 根据指定的灯类型关闭灯列表中可用的灯。 | 48 49### 开发步骤 501. 基于HDF驱动框架,按照驱动Driver Entry程序,完成Light抽象驱动开发(主要由Bind、Init、Release、Dispatch函数接口实现),资源配置及HCS解析。完成Light驱动的设备信息配置。 51 52 - 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 53 Light驱动模型使用HCS作为配置描述源码,HCS配置字段详细介绍请参考[配置管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md)。 54 其Driver Entry入口函数定义如下: 55 56 ```c 57 /* 注册灯入口数据结构体对象 */ 58 struct HdfDriverEntry g_lightDriverEntry = { 59 .moduleVersion = 1, // 灯模块版本号 60 .moduleName = "HDF_LIGHT", // 灯模块名,要与device_info.hcs文件里灯moduleName字段值一样 61 .Bind = BindLightDriver, // 灯绑定函数 62 .Init = InitLightDriver, // 灯初始化函数 63 .Release = ReleaseLightDriver, // 灯资源释放函数 64 }; 65 /* 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release函数释放驱动资源并退出 */ 66 HDF_INIT(g_lightDriverEntry); 67 ``` 68 69 - 基于HDF驱动框架,按照驱动Driver Entry程序,完成Light抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 70 71 ```c 72 /* Light驱动对外发布的能力 */ 73 static int32_t DispatchLight(struct HdfDeviceIoClient *client, 74 int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) 75 { 76 ..... 77 if (cmd == LIGHT_IO_CMD_GET_INFO_LIST) { 78 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM); 79 return GetAllLightInfo(data, reply); 80 } 81 82 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM); 83 (void)OsalMutexLock(&drvData->mutex); 84 if (!HdfSbufReadInt32(data, &lightType)) { 85 HDF_LOGE("%s: sbuf read lightType failed", __func__); 86 (void)OsalMutexUnlock(&drvData->mutex); 87 return HDF_ERR_INVALID_PARAM; 88 } 89 ..... 90 ret = DispatchCmdHandle(lightType, data, reply); 91 (void)OsalMutexUnlock(&drvData->mutex); 92 return ret; 93 } 94 95 /* Light驱动对外提供的服务绑定到HDF框架 */ 96 int32_t BindLightDriver(struct HdfDeviceObject *device) 97 { 98 struct LightDriverData *drvData = NULL; 99 100 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); 101 /* 私有接口分配资源 */ 102 drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData)); 103 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); 104 /* 需要发布的接口函数 */ 105 drvData->ioService.Dispatch = DispatchLight; 106 drvData->device = device; 107 device->service = &drvData->ioService; 108 g_lightDrvData = drvData; 109 return HDF_SUCCESS; 110 } 111 112 /* Light驱动初始化入口函数*/ 113 int32_t InitLightDriver(struct HdfDeviceObject *device) 114 { 115 ..... 116 /* 工作队列初始化 */ 117 if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) { 118 HDF_LOGE("%s: init workQueue fail!", __func__); 119 return HDF_FAILURE; 120 } 121 /* 工作项初始化 */ 122 if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) { 123 HDF_LOGE("%s: init workQueue fail!", __func__); 124 return HDF_FAILURE; 125 } 126 /* 解析HCS配置文件 */ 127 if (GetLightConfigData(device->property) != HDF_SUCCESS) { 128 HDF_LOGE("%s: get light config fail!", __func__); 129 return HDF_FAILURE; 130 } 131 132 return HDF_SUCCESS; 133 } 134 135 /* 释放Light驱动初始化时分配的资源 */ 136 void ReleaseLightDriver(struct HdfDeviceObject *device) 137 { 138 ..... 139 /* 释放已分配资源 */ 140 for (i = LIGHT_TYPE_NONE; i < LIGHT_TYPE_BUTT; ++i) { 141 142 if (drvData->info[i] != NULL) { 143 OsalMemFree(drvData->info[i]); 144 drvData->info[i] = NULL; 145 } 146 } 147 /* 销毁工作队列资源 */ 148 HdfWorkDestroy(&drvData->work); 149 HdfWorkQueueDestroy(&drvData->workQueue); 150 (void)OsalMutexDestroy(&drvData->mutex); 151 (void)OsalMemFree(drvData); 152 g_lightDrvData = NULL; 153 } 154 ``` 155 156 - Light设备管理模块负责系统中Light器件接口发布,在系统启动过程中,HDF框架机制通过灯Host里设备HCS配置信息,加载设备管理驱动。 157 158 ``` 159 /* 灯设备HCS配置 */ 160 device_light :: device { 161 device0 :: deviceNode { 162 policy = 2; // 驱动服务发布的策略(0:不提供服务,1:对内核态发布服务,2:对内核态和用户态都发布服务) 163 priority = 100; // Light驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 164 preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 165 permission = 0664; // 驱动创建设备节点权限 166 moduleName = "HDF_LIGHT"; // Light驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 167 serviceName = "hdf_light"; // Light驱动对外发布服务的名称,必须唯一 168 deviceMatchAttr = "hdf_light_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 169 } 170 ``` 171 1722. 调用配置解析接口,完成器件属性信息解析,器件寄存器解析,并注册到Light设备管理中。 173 174 ```c 175 /* 分配资源,解析灯HCS配置 */ 176 static int32_t ParseLightInfo(const struct DeviceResourceNode *node) 177 { 178 ..... 179 /* 从HCS获取支持灯的类型个数 */ 180 drvData->lightNum = parser->GetElemNum(light, "lightType"); 181 .... 182 for (i = 0; i < drvData->lightNum; ++i) { 183 /* 获取类型 */ 184 ret = parser->GetUint32ArrayElem(light, "lightType", i, &temp, 0); 185 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightType"); 186 } 187 188 for (i = 0; i < drvData->lightNum; ++i) { 189 ..... 190 /* 类型作为下标开辟空间 */ 191 drvData->info[temp] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo)); 192 ..... 193 /* 将Light设备信息进行填充 */ 194 ret = parser->GetUint32(light, "busRNum", &drvData->info[temp]->busRNum, 0); 195 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busRNum"); 196 ret = parser->GetUint32(light, "busGNum", &drvData->info[temp]->busGNum, 0); 197 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busGNum"); 198 ret = parser->GetUint32(light, "busBNum", &drvData->info[temp]->busBNum, 0); 199 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busBNum"); 200 ..... 201 return HDF_SUCCESS; 202 } 203 ``` 204 2053. 完成Light获取类型、闪烁和停止接口开发,会根据闪烁模式创建和销毁定时器。 206 207 ```c 208 /* Light驱动服务调用GetAllLightInfo获取灯类型,Enable接口启动闪烁模式, 209 调用Disable接口停止闪烁 */ 210 static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply) 211 { 212 ..... 213 /* 获取Light类型个数 */ 214 if (!HdfSbufWriteUint32(reply, drvData->lightNum)) { 215 HDF_LOGE("%s: write sbuf failed", __func__); 216 return HDF_FAILURE; 217 } 218 for (i = 0; i < LIGHT_TYPE_BUTT; ++i) { 219 if (drvData->info[i] == NULL) { 220 continue; 221 } 222 lightInfo.lightType = i; 223 lightInfo.reserved = NULL; 224 /* 将Light设备信息填充进reply */ 225 if (!HdfSbufWriteBuffer(reply, &lightInfo, sizeof(lightInfo))) { 226 HDF_LOGE("%s: write sbuf failed", __func__); 227 return HDF_FAILURE; 228 } 229 } 230 231 return HDF_SUCCESS; 232 } 233 234 /* 按照指定的类型和用户传入的参数使能灯 */ 235 static int32_t Enable(uint32_t lightType, struct HdfSBuf *data, struct HdfSBuf *reply) 236 { 237 ..... 238 /* 根据用户传的亮度值设置灯的颜色 RGB: R:16-31bit、G:8-15bit、B:0-7bit */ 239 if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_R_BIT) != 0) { 240 drvData->info[lightType]->busNum = drvData->info[lightType]->busRNum; 241 } else if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_G_BIT) != 0) { 242 drvData->info[lightType]->busNum = drvData->info[lightType]->busGNum; 243 } else if ((drvData->info[lightType]->lightBrightness & LIGHT_MAKE_B_BIT) != 0) { 244 drvData->info[lightType]->busNum = drvData->info[lightType]->busBNum; 245 } 246 /* 常亮模式 */ 247 if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) { 248 249 if (GpioWrite(drvData->info[lightType]->busNum, GPIO_VAL_HIGH) != HDF_SUCCESS) { 250 return HDF_FAILURE; 251 } 252 } 253 /* 闪烁模式 */ 254 if (buf->flashEffect.flashMode == LIGHT_FLASH_TIMED) { 255 drvData->info[lightType]->lightState = LIGHT_STATE_START; 256 /* 用户设置的闪烁时间小于系统支持的最短时间,采用系统配置的时间(HCS配置) */ 257 drvData->info[lightType]->onTime = buf->flashEffect.onTime < drvData->info[lightType]->onTime ? 258 drvData->info[lightType]->onTime : buf->flashEffect.onTime; 259 drvData->info[lightType]->offTime = buf->flashEffect.offTime < drvData->info[lightType]->offTime ? 260 drvData->info[lightType]->offTime : buf->flashEffect.offTime; 261 /* 创建定时器 */ 262 if (OsalTimerCreate(&drvData->timer, drvData->info[lightType]->onTime, 263 LightTimerEntry, (uintptr_t)lightType) != HDF_SUCCESS) { 264 HDF_LOGE("%s: create light timer fail!", __func__); 265 return HDF_FAILURE; 266 } 267 /* 启动周期定时器 */ 268 if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) { 269 HDF_LOGE("%s: start light timer fail!", __func__); 270 return HDF_FAILURE; 271 } 272 } 273 return HDF_SUCCESS; 274 } 275 276 /* 按照指定的类型关闭灯 */ 277 static int32_t Disable(uint32_t lightType, struct HdfSBuf *data, struct HdfSBuf *reply) 278 { 279 /* 删除定时器 */ 280 if (drvData->timer.realTimer != NULL) { 281 282 if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) { 283 HDF_LOGE("%s: delete haptic timer fail!", __func__); 284 } 285 } 286 /* 对应的GPIO下电 */ 287 if (GpioWrite(drvData->info[lightType]->busRNum, GPIO_VAL_LOW) != HDF_SUCCESS){ 288 HDF_LOGE("%s: gpio write failed", __func__); 289 return HDF_FAILURE; 290 } 291 292 return HDF_SUCCESS; 293 } 294 ``` 295 296### 调测验证 297 298驱动开发完成后,在灯单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。 299 300```c++ 301/* 用例执行前,初始化灯接口实例 */ 302void HdfLightTest::SetUpTestCase() 303{ 304 g_lightDev = NewLightInterfaceInstance(); 305 if (g_lightDev == nullptr) { 306 printf("test light get Module instance failed\n\r"); 307 } 308 int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count); 309 if (ret == -1) { 310 printf("get light informations failed\n\r"); 311 } 312} 313 314/* 用例执行后,释放用例资源 */ 315void HdfLightTest::TearDownTestCase() 316{ 317 if(g_lightDev != nullptr){ 318 FreeLightInterfaceInstance(); 319 g_lightDev = nullptr; 320 } 321} 322 323/* 测试灯获取类型 */ 324HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) 325{ 326 struct LightInfo *info = nullptr; 327 328 if (g_lightInfo == nullptr) { 329 EXPECT_NE(nullptr, g_lightInfo); 330 return; 331 } 332 333 printf("get light list num[%d]\n\r", g_count); 334 info = g_lightInfo; 335 336 for (int i = 0; i < g_count; ++i) { 337 printf("get lightId[%d]\n\r", info->lightType); 338 EXPECT_GE(info->lightType, g_minLightType); 339 EXPECT_LE(info->lightType, g_maxLightType); 340 info++; 341 } 342} 343 344/* 测试灯常亮模式 */ 345HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1) 346{ 347 int32_t i; 348 int32_t ret; 349 struct LightEffect effect; 350 effect->lightBrightness = 0x80000000; 351 effect->flashEffect.flashMode = LIGHT_FLASH_NONE; 352 effect->flashEffect.onTime = 0; 353 effect->flashEffect.offTime = 0; 354 355 for (i = 0; i < g_count; ++i) { 356 357 ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightType, effect); 358 EXPECT_EQ(0, ret); 359 360 OsalSleep(LIGHT_WAIT_TIME); 361 362 ret = g_lightDev->TurnOffLight(type); 363 EXPECT_EQ(0, ret); 364 } 365} 366 367/* 测试灯闪烁模式 */ 368HWTEST_F(HdfLightTest, EnableLight002, TestSize.Level1) 369{ 370 int32_t i; 371 int32_t ret; 372 struct LightEffect effect; 373 effect->lightBrightness = 0x80000000; 374 effect->flashEffect.flashMode = LIGHT_FLASH_TIMED; 375 effect->flashEffect.onTime = g_onTime; 376 effect->flashEffect.offTime = g_offTime; 377 378 for (i = 0; i < g_count; ++i) { 379 380 ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightType, effect); 381 EXPECT_EQ(0, ret); 382 383 OsalSleep(LIGHT_WAIT_TIME); 384 385 ret = g_lightDev->TurnOffLight(type); 386 EXPECT_EQ(0, ret); 387 } 388} 389``` 390 391