diff --git a/zh-cn/device-dev/driver/driver-peripherals-light-des.md b/zh-cn/device-dev/driver/driver-peripherals-light-des.md index e6ce9efc422091818a13eca15d4a5bc3dd633396..280a3584d0d03df5ebf03275ced3e5b89856f253 100644 --- a/zh-cn/device-dev/driver/driver-peripherals-light-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-light-des.md @@ -19,7 +19,7 @@ Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接 ![Light驱动运行图](figures/Light驱动运行图.png) -以标准系统Hi3516DV300为例,介绍Light模块驱动加载及运行流程: +以标准系统RK3568为例,介绍Light模块驱动加载及运行流程: 1. Device Manager从device_info.hcs配置文件中读取Light设备管理配置信息。 2. Device Manager从light_config.hcs配置文件中读取Light数据配置信息。 @@ -40,17 +40,74 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模 **表1** Light驱动模型对外API接口能力介绍 +注:以下接口列举的为C接口,接口声明见文件[/drivers/peripheral/light/interfaces/include](https://gitee.com/openharmony/drivers_peripheral/tree/master/light/interfaces/include)。 + | 接口名 | 功能描述 | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| int32_t (*GetLightInfo)([out] struct LightInfo **lightInfo, [out] uint32_t *count) | 获取当前系统中所有类型的灯信息,lightInfo表示指向灯信息的二级指针,count表示指向灯数量的指针。 | -| int32_t (*TurnOnLight)([in] uint32_t lightId, [in] struct LightEffect *effect) | 根据指定的灯类型ID打开列表中的可用灯,lightId表示灯类型ID,effect表示指向灯效果的指针。 | -| int32_t (*TurnOffLight)([in] uint32_t lightId) | 根据指定的灯类型ID关闭列表中的可用灯。 | +| int32_t (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | 获取当前系统中所有类型的灯信息,lightInfo表示指向灯信息的二级指针,count表示指向灯数量的指针。 | +| int32_t (*TurnOnLight)(uint32_t lightId, struct LightEffect *effect) | 根据指定的灯类型ID打开列表中的可用灯,lightId表示灯类型ID,effect表示指向灯效果的指针。 | +| int32_t (*TurnOffLight)(uint32_t lightId) | 根据指定的灯类型ID关闭列表中的可用灯。 | +| int32_t (*TurnOnMultiLights)(uint32_t lightId, const struct LightColor *colors, const uint32_t count); | 根据指定的灯类型ID打开相应灯光中包含的多个子灯光。 | ### 开发步骤 -1. 基于HDF驱动框架,按照驱动Driver Entry程序,完成Light抽象驱动开发(主要由Bind、Init、Release、Dispatch函数接口实现),资源配置及HCS配置文件解析。 +基于HDF驱动框架,按照驱动Driver Entry程序,完成Light驱动开发,资源配置及HCS配置文件解析。 + +1. 灯驱动在Light Host中的配置信息。 + + - Light HCS文件代码路径:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。 + + - 具体代码实现如下: + + ```c + /* Light设备HCS配置 */ + light :: host { + hostName = "light_host"; + device_light :: device { + device0 :: deviceNode { + policy = 2; // 驱动服务发布的策略(0:不提供服务,1:对内核态发布服务;2:对内核态和用户态都发布服务) + priority = 100; // Light驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 + preload = 0; // 驱动按需加载字段,0:加载;2:不加载 + permission = 0664; // 驱动创建设备节点权限 + moduleName = "HDF_LIGHT"; // Light驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "hdf_light"; // Light驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "hdf_light_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 + } + } + } + ``` + +2. 灯驱动私有HCS配置: + + - 代码实现路径:vendor\hihope\rk3568\hdf_config\khdf\light\light_config.hcs。 + + - 具体代码实现如下: + + ```c + root { + lightConfig { + boardConfig { + match_attr = "hdf_light_driver"; + lightAttr { + light01 { + lightId = [1]; // Lightid可以包含多个逻辑灯光ID,例如:1表示电源指示灯。 + lightName = "battery"; + lightNumber = 1; + busRNum = 147; // Light的效果颜色红色对应GPIO值。 + busGNum = 146; // Light的效果颜色绿色对应GPIO值。 + busBNum = 149; // Light的效果颜色蓝色对应GPIO值。 + defaultBrightness = 0X00FFFFFF; // 系统默认亮度值,B:0-7位,R:8-15位,G:16-23,扩展位24-31位。 + onTime = 50; // 当闪光灯亮起时,系统支持的最短持续时间(以毫秒为单位)。 + offTime = 50; // 当闪光灯熄灭时,系统支持的最短持续时间(以毫秒为单位)。 + } + } + } + } + } + ``` + +3. 灯驱动代码实现路径为: drivers\hdf_core\framework\model\misc\light\driver\src\light_driver.c。 - - 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - Light驱动模型使用HCS配置文件作为配置描述源码。HCS配置字段详细介绍请参考[配置管理](driver-hdf-manage.md)。其Driver Entry入口函数定义如下: + - 灯驱动驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下: ```c /* 注册灯入口数据结构体对象 */ @@ -61,94 +118,82 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模 .Init = InitLightDriver, // 灯初始化函数 .Release = ReleaseLightDriver, // 灯资源释放函数 }; - /* 调用HDF_INIT将驱动入口注册到HDF框架中 */ + /* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */ HDF_INIT(g_lightDriverEntry); ``` - - 基于HDF驱动框架,按照驱动Driver Entry程序,完成Light抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 + - 灯驱动Bind接口实现示例如下: ```c - /* Light驱动对外发布的能力 */ - static int32_t DispatchLight(struct HdfDeviceIoClient *client, - int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) - { - ..... - if (cmd == LIGHT_IO_CMD_GET_INFO_LIST) { - CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM); - return GetAllLightInfo(data, reply); - } - - CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM); - (void)OsalMutexLock(&drvData->mutex); - if (!HdfSbufReadInt32(data, &lightId)) { - HDF_LOGE("%s: sbuf read lightId fail", __func__); - (void)OsalMutexUnlock(&drvData->mutex); - return HDF_ERR_INVALID_PARAM; - } - ..... - ret = DispatchCmdHandle(lightId, data, reply); - (void)OsalMutexUnlock(&drvData->mutex); - return ret; - } - /* Light驱动对外提供的服务绑定到HDF框架 */ int32_t BindLightDriver(struct HdfDeviceObject *device) { struct LightDriverData *drvData = NULL; CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); - /* 私有接口分配资源 */ + /* 私有接口分配资源 */ drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData)); CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); - /* 需要发布的接口函数 */ + /* 需要发布的接口函数 */ drvData->ioService.Dispatch = DispatchLight; drvData->device = device; device->service = &drvData->ioService; g_lightDrvData = drvData; + return HDF_SUCCESS; } - + ``` + + - 灯驱动Init接口实现示例如下: + + ```c /* Light驱动初始化入口函数*/ int32_t InitLightDriver(struct HdfDeviceObject *device) - { - ..... - /* 工作队列初始化 */ + { + struct LightDriverData *drvData = NULL; + + drvData = (struct LightDriverData *)device->service; + + if (OsalMutexInit(&drvData->mutex) != HDF_SUCCESS) { + return HDF_FAILURE; + } + /* 工作队列初始化 */ if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) { - HDF_LOGE("%s: init workQueue fail!", __func__); return HDF_FAILURE; } - /* 工作项初始化 */ + /* 工作项初始化 */ if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) { - HDF_LOGE("%s: init work fail!", __func__); return HDF_FAILURE; } - /* 解析HCS配置文件 */ + /* 解析HCS配置文件 */ if (GetLightConfigData(device->property) != HDF_SUCCESS) { - HDF_LOGE("%s: get light config fail!", __func__); return HDF_FAILURE; } - /* 设置GPIO引脚方向 */ + /* 设置GPIO引脚方向 */ if (SetLightGpioDir(drvData) != HDF_SUCCESS) { - HDF_LOGE("%s: set light gpio dir fail!", __func__); return HDF_FAILURE; } return HDF_SUCCESS; } - + ``` + + - 灯驱动Release接口在驱动卸载或者Init执行失败时,会调用此接口释放资源,具体实现如下: + + ```c /* 释放Light驱动初始化时分配的资源 */ void ReleaseLightDriver(struct HdfDeviceObject *device) - { - ..... + { + int32_t i; + struct LightDriverData *drvData = NULL; /* 释放已分配资源 */ - for (i = LIGHT_TYPE_NONE; i < LIGHT_TYPE_BUTT; ++i) { - + for (i = LIGHT_ID_NONE; i < LIGHT_ID_BUTT; ++i) { if (drvData->info[i] != NULL) { OsalMemFree(drvData->info[i]); drvData->info[i] = NULL; } } - /* 销毁工作队列资源 */ + /* 器件在位,销毁工作队列资源 */ HdfWorkDestroy(&drvData->work); HdfWorkQueueDestroy(&drvData->workQueue); (void)OsalMutexDestroy(&drvData->mutex); @@ -157,277 +202,703 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模 } ``` - - Light设备管理模块负责系统中Light器件接口发布。在系统启动过程中,HDF框架机制通过Light Host里的设备HCS配置信息,加载设备管理驱动。 + - 灯驱动从HCS文件中解析Light设备管理配置信息。 ```c - /* Light设备HCS配置 */ - light :: host { - hostName = "light_host"; - device_light :: device { - device0 :: deviceNode { - policy = 2; // 驱动服务发布的策略(0:不提供服务,1:对内核态发布服务;2:对内核态和用户态都发布服务) - priority = 100; // Light驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 - preload = 0; // 驱动按需加载字段,0:加载;2:不加载 - permission = 0664; // 驱动创建设备节点权限 - moduleName = "HDF_LIGHT"; // Light驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 - serviceName = "hdf_light"; // Light驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "hdf_light_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 + /* 从HCS文件中获取Light基础配置 */ + static int32_t GetLightBaseConfigData(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser, + uint32_t lightId) + { + int32_t ret; + uint32_t *defaultBrightness = NULL; + struct LightDriverData *drvData = NULL; + const char *name = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM); + /* 类型作为下标开辟空间 */ + drvData->info[lightId] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo)); + if (drvData->info[lightId] == NULL) { + HDF_LOGE("%s: malloc fail", __func__); + return HDF_FAILURE; + } + /* 将Light设备信息进行填充 */ + ret = parser->GetUint32(node, "busRNum", (uint32_t *)&drvData->info[lightId]->busRNum, 0); + if (ret != HDF_SUCCESS) { + drvData->info[lightId]->busRNum = LIGHT_INVALID_GPIO; + } + + ret = parser->GetUint32(node, "busGNum", (uint32_t *)&drvData->info[lightId]->busGNum, 0); + if (ret != HDF_SUCCESS) { + drvData->info[lightId]->busGNum = LIGHT_INVALID_GPIO; + } + + ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[lightId]->busBNum, 0); + if (ret != HDF_SUCCESS) { + drvData->info[lightId]->busBNum = LIGHT_INVALID_GPIO; + } + + ret = parser->GetString(node, "lightName", &name, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s:get lightName failed!", __func__); + return HDF_FAILURE; + } + + if (strcpy_s(drvData->info[lightId]->lightInfo.lightName, NAME_MAX_LEN, name) != EOK) { + HDF_LOGE("%s:copy lightName failed!", __func__); + return HDF_FAILURE; + } + + ret = parser->GetUint32(node, "lightNumber", (uint32_t *)&drvData->info[lightId]->lightInfo.lightNumber, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s:get lightNumber failed!", __func__); + return HDF_FAILURE; + } + + defaultBrightness = (uint32_t *)&drvData->info[lightId]->defaultBrightness; + ret = parser->GetUint32(node, "defaultBrightness", defaultBrightness, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "defaultBrightness"); + ret = parser->GetUint32(node, "onTime", &drvData->info[lightId]->onTime, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "onTime"); + ret = parser->GetUint32(node, "offTime", &drvData->info[lightId]->offTime, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "offTime"); + + drvData->info[lightId]->lightBrightness = 0; + drvData->info[lightId]->lightState = LIGHT_STATE_STOP; + + return HDF_SUCCESS; + } + ``` + + - 分配资源,解析灯HCS配置信息实现如下: + + ```c + /* 分配资源,解析灯HCS配置 */ + static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser) + { + int32_t ret; + uint32_t i; + uint32_t temp; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM); + /* 从HCS配置获取支持的灯类型个数 */ + drvData->lightNum = (uint32_t)parser->GetElemNum(node, "lightId"); + if (drvData->lightNum > LIGHT_ID_NUM) { + HDF_LOGE("%s: lightNum cross the border", __func__); + return HDF_FAILURE; + } + + ret = memset_s(drvData->info, sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT, 0, + sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "memset_s"); + + for (i = 0; i < drvData->lightNum; ++i) { + /* 获取灯的类型 */ + ret = parser->GetUint32ArrayElem(node, "lightId", i, &temp, 0); + CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId"); + + if (temp >= LIGHT_ID_BUTT) { + HDF_LOGE("%s: light id invalid para", __func__); + return HDF_FAILURE; + } + + ret = GetLightBaseConfigData(node, parser, temp); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: get light base config fail", __func__); + return HDF_FAILURE; } } + + return HDF_SUCCESS; } ``` -2. 调用配置解析接口,完成器件属性信息解析、器件寄存器解析,并注册到Light设备管理中。 - - ```c - /* 分配资源,解析灯HCS配置。 */ - static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser) - { - ..... - /* 从HCS配置获取支持的灯类型个数 */ - drvData->lightNum = parser->GetElemNum(light, "lightId"); - .... - for (i = 0; i < drvData->lightNum; ++i) { - /* 获取灯的类型 */ - ret = parser->GetUint32ArrayElem(light, "lightId", i, &temp, 0); - CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId"); - } - - for (i = 0; i < drvData->lightNum; ++i) { - ..... - /* 类型作为下标开辟空间 */ - drvData->info[temp] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo)); - ..... - /* 将Light设备信息进行填充 */ - ret = parser->GetUint32(node, "busRNum", (uint32_t *)&drvData->info[temp]->busRNum, 0); - if (ret != HDF_SUCCESS) { - /* 如果没有成功获取busNum,代表不支持设置busNum对应颜色的灯。 */ - drvData->info[temp]->busRNum = LIGHT_INVALID_GPIO; - } - ret = parser->GetUint32(node, "busGNum", (uint32_t *)&drvData->info[temp]->busGNum, 0); - if (ret != HDF_SUCCESS) { - drvData->info[temp]->busGNum = LIGHT_INVALID_GPIO; + - 灯驱动的内部接口完成了灯类型获取、闪烁模式设置和停止的接口开发,并实现根据闪烁模式创建和销毁定时器。 + + - GetAllLightInfo接口实现如下: + + ```c + /* Light驱动服务调用GetAllLightInfo接口获取灯类型信息 */ + static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)data; + uint32_t i; + struct LightInfo lightInfo; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM); + + if (!HdfSbufWriteUint32(reply, drvData->lightNum)) { + HDF_LOGE("%s: write sbuf failed", __func__); + return HDF_FAILURE; } - ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[temp]->busBNum, 0); - if (ret != HDF_SUCCESS) { - drvData->info[temp]->busBNum = LIGHT_INVALID_GPIO; + + for (i = 0; i < LIGHT_ID_BUTT; ++i) { + if (drvData->info[i] == NULL) { + continue; + } + lightInfo.lightId = i; + + if (!HdfSbufWriteUint32(reply, lightInfo.lightId)) { + HDF_LOGE("%s: write lightId failed", __func__); + return HDF_FAILURE; + } + + if (strcpy_s(lightInfo.lightName, NAME_MAX_LEN, drvData->info[i]->lightInfo.lightName) != EOK) { + HDF_LOGE("%s:copy lightName failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufWriteString(reply, (const char *)lightInfo.lightName)) { + HDF_LOGE("%s: write lightName failed", __func__); + return HDF_FAILURE; + } + + lightInfo.lightNumber = drvData->info[i]->lightInfo.lightNumber; + if (!HdfSbufWriteUint32(reply, lightInfo.lightNumber)) { + HDF_LOGE("%s: write lightNumber failed", __func__); + return HDF_FAILURE; + } + + lightInfo.lightType = HDF_LIGHT_TYPE_RGB_COLOR; + if (!HdfSbufWriteUint32(reply, lightInfo.lightType)) { + HDF_LOGE("%s: write lightType failed", __func__); + return HDF_FAILURE; + } } + + return HDF_SUCCESS; } - ..... - return HDF_SUCCESS; - } - ``` - -3. 完成Light类型获取、闪烁模式设置和停止的接口开发,并实现根据闪烁模式创建和销毁定时器。 - - ```c - /* Light驱动服务调用GetAllLightInfo接口获取灯类型,调用TurnOnLight接口启动闪烁模式, - 调用TurnOffLight接口停止闪烁。 */ - static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply) - { - ..... - /* 获取灯类型的个数 */ - if (!HdfSbufWriteUint32(reply, drvData->lightNum)) { - HDF_LOGE("%s: write sbuf fail", __func__); - return HDF_FAILURE; - } - for (i = 0; i < LIGHT_TYPE_BUTT; ++i) { - if (drvData->info[i] == NULL) { - continue; - } - lightInfo.lightId = i; - lightInfo.reserved = NULL; - /* 将Light设备信息填充进reply */ - if (!HdfSbufWriteBuffer(reply, &lightInfo, sizeof(lightInfo))) { - HDF_LOGE("%s: write sbuf fail", __func__); + ``` + + - TurnOnLight接口的实现如下: + + ```c + /* 按照指定的类型和用户传入的参数使能灯 */ + static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)reply; + uint32_t len; + struct LightEffect *buf = NULL; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + + if (drvData->info[lightId] == NULL) { + HDF_LOGE("%s: light id info is null", __func__); return HDF_FAILURE; } - } - - return HDF_SUCCESS; - } - - /* 更新指定类型灯的状态 */ - static int32_t UpdateLight(uint32_t lightId, uint32_t lightOn) - { - ..... - /* 如果用户传入的亮度值无效,则使用系统默认的亮度值。 */ - if (drvData->info[lightId]->lightBrightness == 0) { - lightBrightness = drvData->info[lightId]->defaultBrightness; - } else { - lightBrightness = drvData->info[lightId]->lightBrightness; - } - /* 如果0-7bit不等于0,根据lightOn的状态,输出蓝色对应的GPIO引脚。 */ - if ((lightBrightness & LIGHT_MAKE_B_BIT) != 0) { - ret = WriteGpio(drvData->info[lightId]->busBNum, lightOn); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: write blue gpio fail", __func__); + + if (!HdfSbufReadBuffer(data, (const void **)&buf, &len)) { + HDF_LOGE("%s: light read data failed", __func__); return HDF_FAILURE; } - } - /* 如果8-15bit不等于0,根据lightOn的状态,输出绿色对应的GPIO引脚。 */ - if ((lightBrightness & LIGHT_MAKE_G_BIT) != 0) { - ret = WriteGpio(drvData->info[lightId]->busGNum, lightOn); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: write green gpio fail", __func__); - return HDF_FAILURE; + /* 接收用户传入的亮度值。24-31bit表示扩展位,16-23bit表示红色,8-15bit表示绿色,0-7bit表示蓝色。如果字段不等于0,表示使能相应颜色的灯。 + 如果支持亮度设置,则通过0-255设置不同的亮度。 */ + if (buf->lightColor.colorValue.rgbColor.r != 0) { + drvData->info[lightId]->lightBrightness |= 0X00FF0000; } - } - /* 如果16-23bit不等于0,根据lightOn的状态,输出红色对应的GPIO引脚。 */ - if ((lightBrightness & LIGHT_MAKE_R_BIT) != 0) { - ret = WriteGpio(drvData->info[lightId]->busRNum, lightOn); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: write red gpio fail", __func__); - return HDF_FAILURE; + + if (buf->lightColor.colorValue.rgbColor.g != 0) { + drvData->info[lightId]->lightBrightness |= 0X0000FF00; } + + if (buf->lightColor.colorValue.rgbColor.b != 0) { + drvData->info[lightId]->lightBrightness |= 0X000000FF; + } + /* 常亮模式 */ + if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) { + return UpdateLight(lightId, LIGHT_STATE_START); + } + /* 闪烁模式 */ + if (buf->flashEffect.flashMode == LIGHT_FLASH_BLINK) { + drvData->info[lightId]->onTime = (buf->flashEffect.onTime < drvData->info[lightId]->onTime) ? + drvData->info[lightId]->onTime : buf->flashEffect.onTime; + drvData->info[lightId]->offTime = (buf->flashEffect.offTime < drvData->info[lightId]->offTime) ? + drvData->info[lightId]->offTime : buf->flashEffect.offTime; + /* 创建定时器 */ + if (OsalTimerCreate(&drvData->timer, LIGHT_WAIT_TIME, LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) { + HDF_LOGE("%s: create light timer fail!", __func__); + return HDF_FAILURE; + } + /* 启动定时器 */ + if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) { + HDF_LOGE("%s: start light timer fail!", __func__); + return HDF_FAILURE; + } + } + + return HDF_SUCCESS; } - ..... - } - - /* 按照指定的类型和用户传入的参数使能灯 */ - static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) - { - ..... - /* 接收用户传入的亮度值。24-31bit表示扩展位,16-23bit表示红色,8-15bit表示绿色,0-7bit表示蓝色。如果字段不等于0,表示使能相应颜色的灯。 - 如果支持亮度设置,则通过0-255设置不同的亮度。 */ - drvData->info[lightId]->lightBrightness = buf->lightBrightness; - /* 常亮模式 */ - if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) { - return UpdateLight(lightId, LIGHT_STATE_START); - } - /* 闪烁模式 */ - if (buf->flashEffect.flashMode == LIGHT_FLASH_TIMED) { - drvData->info[lightId]->lightState = LIGHT_STATE_START; - /* 用户设置的闪烁时间小于系统支持的最短时间,采用系统配置的时间(HCS配置)。 */ - drvData->info[lightId]->onTime = buf->flashEffect.onTime < drvData->info[lightId]->onTime ? - drvData->info[lightId]->onTime : buf->flashEffect.onTime; - drvData->info[lightId]->offTime = buf->flashEffect.offTime < drvData->info[lightId]->offTime ? - drvData->info[lightId]->offTime : buf->flashEffect.offTime; - /* 创建定时器 */ - if (OsalTimerCreate(&drvData->timer, drvData->info[lightId]->onTime, - LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) { - HDF_LOGE("%s: create light timer fail!", __func__); + ``` + + - TurnOffLight接口的实现如下: + + ```c + /* 按照指定的类型关闭灯 */ + static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)data; + (void)reply; + struct LightDriverData *drvData = NULL; + + drvData = GetLightDrvData(); + CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + + if (drvData->info[lightId] == NULL) { + HDF_LOGE("%s: light id info is null", __func__); return HDF_FAILURE; } - /* 启动周期定时器 */ - if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) { - HDF_LOGE("%s: start light timer fail!", __func__); + + if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) { + HDF_LOGE("%s: gpio write failed", __func__); return HDF_FAILURE; } - } - return HDF_SUCCESS; - } - - /* 按照指定的类型关闭灯 */ - static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) - { - /* 删除定时器 */ - if (drvData->timer.realTimer != NULL) { - - if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) { - HDF_LOGE("%s: delete haptic timer fail!", __func__); + + drvData->info[lightId]->lightState = LIGHT_STATE_STOP; + drvData->info[lightId]->lightBrightness = 0; + /* 销毁定时器 */ + if (drvData->timer.realTimer != NULL) { + if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) { + HDF_LOGE("%s: delete light timer fail!", __func__); + return HDF_FAILURE; + } } + + return HDF_SUCCESS; } - if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) { - HDF_LOGE("%s: gpio write fail", __func__); - return HDF_FAILURE; - } - - return HDF_SUCCESS; - } - ``` + ``` + +5. Light Controller中是HDI接口的实现。 + + - 代码实现路径:drivers\peripheral\light\hal\src\light_controller.c。 + + - GetLightInfo接口的实现如下: + + ```c + /* 将Light抽象驱动中写入HdfSBuf中的灯类型信息读取到LightInfo中 */ + static int32_t ReadLightInfo(struct HdfSBuf *reply, struct LightDevice *priv) + { + struct LightInfo *pos = NULL; + const char *name = NULL; + + if (!HdfSbufReadUint32(reply, &priv->lightNum)) { + HDF_LOGE("%s: sbuf read lightNum failed", __func__); + return HDF_FAILURE; + } + + if (priv->lightInfoEntry != NULL) { + OsalMemFree(priv->lightInfoEntry); + priv->lightInfoEntry = NULL; + } + + priv->lightInfoEntry = (struct LightInfo *)OsalMemCalloc(sizeof(*priv->lightInfoEntry) * priv->lightNum); + if (priv->lightInfoEntry == NULL) { + HDF_LOGE("%s: malloc fail", __func__); + return HDF_FAILURE; + } + + pos = priv->lightInfoEntry; + + for (uint32_t i = 0; i < priv->lightNum; ++i) { + if (!HdfSbufReadUint32(reply, &pos->lightId)) { + HDF_LOGE("%{public}s:read lightId failed!", __func__); + return HDF_FAILURE; + } + + name = HdfSbufReadString(reply); + if (strcpy_s(pos->lightName, NAME_MAX_LEN, name) != EOK) { + HDF_LOGE("%{public}s:copy lightName failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadUint32(reply, &pos->lightNumber)) { + HDF_LOGE("%{public}s:read lightNumber failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadInt32(reply, &pos->lightType)) { + HDF_LOGE("%{public}s:read lightType failed!", __func__); + return HDF_FAILURE; + } + pos++; + } + + return HDF_SUCCESS; + } + /* GetLightInfo接口实现 */ + static int32_t GetLightInfo(struct LightInfo **lightInfo, uint32_t *count) + { + if ((lightInfo == NULL) || (count == NULL)) { + HDF_LOGE("%s:line:%{public}d pointer is null and return ret", __func__, __LINE__); + return HDF_FAILURE; + } + + struct LightDevice *priv = GetLightDevicePriv(); + + if (priv->lightNum > 0) { + *count = priv->lightNum; + *lightInfo = priv->lightInfoEntry; + return HDF_SUCCESS; + } + + (void)OsalMutexLock(&priv->mutex); + struct HdfSBuf *reply = HdfSbufObtainDefaultSize(); + if (reply == NULL) { + HDF_LOGE("%s: get sbuf failed", __func__); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + int32_t ret = SendLightMsg(LIGHT_IO_CMD_GET_INFO_LIST, NULL, reply); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: Light send cmd failed, ret[%{public}d]", __func__, ret); + HdfSbufRecycle(reply); + (void)OsalMutexUnlock(&priv->mutex); + return ret; + } + + if (ReadLightInfo(reply, priv) != HDF_SUCCESS) { + HdfSbufRecycle(reply); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + HdfSbufRecycle(reply); + (void)OsalMutexUnlock(&priv->mutex); + + *count = priv->lightNum; + *lightInfo = priv->lightInfoEntry; + + return HDF_SUCCESS; + } + ``` + + - OnLight接口的实现如下: + + ```c + static int32_t OnLight(uint32_t lightId, struct LightEffect *effect) + { + int32_t ret; + + if (effect == NULL) { + HDF_LOGE("%{public}s: effect is NULL", __func__); + return HDF_FAILURE; + } + + ret = OnLightValidityJudgment(lightId, effect); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: effect is false", __func__); + return ret; + } + + struct LightDevice *priv = GetLightDevicePriv(); + (void)OsalMutexLock(&priv->mutex); + + struct HdfSBuf *msg = HdfSbufObtainDefaultSize(); + if (msg == NULL) { + HDF_LOGE("%{public}s: Failed to obtain sBuf size", __func__); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, lightId)) { + HDF_LOGE("%{public}s: Light write id failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_ENABLE)) { + HDF_LOGE("%{public}s: Light write enable failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteBuffer(msg, effect, sizeof(*effect))) { + HDF_LOGE("%{public}s: Light write enable failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: Light enable failed, ret[%{public}d]", __func__, ret); + } + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + + if (memcpy_s(&g_lightEffect, sizeof(g_lightEffect), effect, sizeof(*effect)) != EOK) { + HDF_LOGE("%{public}s: Light effect cpy faild", __func__); + return HDF_FAILURE; + } + + g_lightState[lightId] = LIGHT_ON; + + return ret; + } + ``` + + - OffLight接口的实现 如下: + + ```c + static int32_t OffLight(uint32_t lightId) + { + if (lightId >= LIGHT_ID_BUTT) { + HDF_LOGE("%{public}s: id not supported", __func__); + return HDF_FAILURE; + } + + struct LightDevice *priv = GetLightDevicePriv(); + (void)OsalMutexLock(&priv->mutex); + + struct HdfSBuf *msg = HdfSbufObtainDefaultSize(); + if (msg == NULL) { + HDF_LOGE("%{public}s: Failed to obtain sBuf", __func__); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, lightId)) { + HDF_LOGE("%{public}s: Light write id failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + if (!HdfSbufWriteInt32(msg, LIGHT_OPS_IO_CMD_DISABLE)) { + HDF_LOGE("%{public}s: Light write disable failed", __func__); + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + return HDF_FAILURE; + } + + int32_t ret = SendLightMsg(LIGHT_IO_CMD_OPS, msg, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: Light disable failed, ret[%{public}d]", __func__, ret); + } + HdfSbufRecycle(msg); + (void)OsalMutexUnlock(&priv->mutex); + + g_lightState[lightId] = LIGHT_OFF; + + return ret; + } + ``` + + - OnMultiLights接口的实现如下: + + ```c + static int32_t OnMultiLights(uint32_t lightId, const struct LightColor *colors, const uint32_t count) + { + int32_t ret; + struct HdfSBuf *sbuf = NULL; + + ret = OnMultiLightsValidityJudgment(lightId, colors, count); + if (ret != HDF_SUCCESS) { + return ret; + } + + struct LightDevice *priv = GetLightDevicePriv(); + (void)OsalMutexLock(&priv->mutex); + sbuf = HdfSbufObtain(sizeof(struct LightColor) * count); + if (sbuf == NULL) { + return HDF_DEV_ERR_NO_MEMORY; + } + + if (!HdfSbufWriteInt32(sbuf, lightId)) { + ret = HDF_FAILURE; + goto EXIT; + } + + if (!HdfSbufWriteInt32(sbuf, LIGHT_OPS_IO_CMD_ENABLE_MULTI_LIGHTS)) { + ret = HDF_FAILURE; + goto EXIT; + } + + if (!HdfSbufWriteBuffer(sbuf, colors, sizeof(*colors))) { + ret = HDF_FAILURE; + goto EXIT; + } + + if (!HdfSbufWriteInt32(sbuf, count)) { + ret = HDF_FAILURE; + goto EXIT; + } + + ret = SendLightMsg(LIGHT_IO_CMD_OPS, sbuf, NULL); + if (ret != HDF_SUCCESS) { + } + return ret; + + EXIT: + HdfSbufRecycle(sbuf); + (void)OsalMutexUnlock(&priv->mutex); + } + ``` ### 调测验证 驱动开发完成后,在灯单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。 -```c++ -/* 用例执行前,初始化Light接口实例。 */ -void HdfLightTest::SetUpTestCase() -{ - g_lightDev = NewLightInterfaceInstance(); - if (g_lightDev == nullptr) { - printf("test light get Module instance fail\n\r"); - } - int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count); - if (ret == -1) { - printf("get light informations fail\n\r"); - } -} - -/* 用例执行后,释放用例资源。 */ -void HdfLightTest::TearDownTestCase() -{ - if(g_lightDev != nullptr){ - FreeLightInterfaceInstance(); - g_lightDev = nullptr; - } -} - -/* 获取测试灯类型 */ -HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) -{ - struct LightInfo *info = nullptr; - - if (g_lightInfo == nullptr) { - EXPECT_NE(nullptr, g_lightInfo); - return; - } - - printf("get light list num[%d]\n\r", g_count); - info = g_lightInfo; - - for (int i = 0; i < g_count; ++i) { - printf("get lightId[%d]\n\r", info->lightId); - EXPECT_GE(info->lightId, g_minLightId); - EXPECT_LE(info->lightId, g_maxLightId); - info++; - } -} - -/* 测试灯常亮模式 */ -HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1) -{ - int32_t i; - int32_t ret; - struct LightEffect effect; - effect->lightBrightness = 0x00800000; - effect->flashEffect.flashMode = LIGHT_FLASH_NONE; - effect->flashEffect.onTime = 0; - effect->flashEffect.offTime = 0; - - for (i = 0; i < g_count; ++i) { - - ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); - EXPECT_EQ(0, ret); - - OsalSleep(LIGHT_WAIT_TIME); - - ret = g_lightDev->TurnOffLight(type); - EXPECT_EQ(0, ret); - } -} - -/* 测试灯闪烁模式 */ -HWTEST_F(HdfLightTest, EnableLight002, TestSize.Level1) -{ - int32_t i; - int32_t ret; - struct LightEffect effect; - effect->lightBrightness = 0x00800000; - effect->flashEffect.flashMode = LIGHT_FLASH_TIMED; - effect->flashEffect.onTime = g_onTime; - effect->flashEffect.offTime = g_offTime; - - for (i = 0; i < g_count; ++i) { - - ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); - EXPECT_EQ(0, ret); - - OsalSleep(LIGHT_WAIT_TIME); - - ret = g_lightDev->TurnOffLight(type); - EXPECT_EQ(0, ret); - } -} -``` +- 参考测试代码如下: + + ```c + #include + #include + #include + #include + #include "hdf_base.h" + #include "osal_time.h" + #include "osal_mem.h" + #include "light_if.h" + #include "light_type.h" + + using namespace testing::ext; + const struct LightInterface *g_lightDev = nullptr; + static struct LightInfo *g_lightInfo = nullptr; + static uint32_t g_count = 0; + /* 用例执行前,初始化Light接口实例。 */ + class HdfLightTest : public testing::Test { + public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + }; + + void HdfLightTest::SetUpTestCase() + { + g_lightDev = NewLightInterfaceInstance(); + if (g_lightDev == nullptr) { + printf("test light get Module instance fail\n\r"); + } + int32_t ret = g_lightDev->GetLightInfo(&g_lightInfo, &g_count); + if (ret == -1) { + printf("get light informations fail\n\r"); + } + } + + /* 用例执行后,释放用例资源。 */ + void HdfLightTest::TearDownTestCase() + { + if(g_lightDev != nullptr){ + FreeLightInterfaceInstance(); + g_lightDev = nullptr; + } + } + + void HdfLightTest::SetUp() + { + } + + void HdfLightTest::TearDown() + { + } + + /* 获取测试灯类型 */ + HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) + { + struct LightInfo *info = nullptr; + + if (g_lightInfo == nullptr) { + EXPECT_NE(nullptr, g_lightInfo); + return; + } + + printf("get light list num[%u]\n\r", g_count); + info = g_lightInfo; + + for (uint32_t i = 0; i < g_count; ++i) { + printf("get lightId[%u]\n\r", info->lightId); + EXPECT_GE(info->lightId, 0); + EXPECT_LE(info->lightId, 4); + info++; + } + } + + /* 测试灯常亮模式 */ + HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1) + { + uint32_t i; + struct LightEffect effect; + effect.flashEffect.flashMode = 0; + effect.flashEffect.onTime = 0; + effect.flashEffect.offTime = 0; + + for (i = 0; i < g_count; ++i) { + effect.lightColor.colorValue.rgbColor.r = 255; + effect.lightColor.colorValue.rgbColor.g = 0; + effect.lightColor.colorValue.rgbColor.b = 0; + int32_t ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect); + EXPECT_EQ(0, ret); + + OsalSleep(2); + + ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId); + EXPECT_EQ(0, ret); + + effect.lightColor.colorValue.rgbColor.r = 0; + effect.lightColor.colorValue.rgbColor.g = 255; + effect.lightColor.colorValue.rgbColor.b = 0; + ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect); + EXPECT_EQ(0, ret); + + OsalSleep(2); + + ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId); + EXPECT_EQ(0, ret); + } + } + ``` + +- 编译文件BUILD.gn参考代码如下: + + ```c + import("//build/test.gni") + import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") + + module_output_path = "drivers_peripheral_light/light" + ohos_unittest("light_test") { + module_out_path = module_output_path + sources = [ "light_test.cpp" ] + include_dirs = [ + "//drivers/hdf_core/framework/include/platform", + "//drivers/peripheral/light/interfaces/include", + ] + deps = [ "//drivers/peripheral/light/hal:hdi_light" ] + + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + ] + + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-Wno-format", + "-Wno-format-extra-args", + ] + + install_enable = true + install_images = [ "vendor" ] + module_install_dir = "bin" + part_name = "unionman_products" + } + ``` + + + diff --git a/zh-cn/device-dev/driver/driver-peripherals-motion-des.md b/zh-cn/device-dev/driver/driver-peripherals-motion-des.md index 123d0a05db0f610bb1b2ae1051c151376d66d72a..d23393fcddf9ef82fcaeeef4f31f7f02eb7e61f0 100644 --- a/zh-cn/device-dev/driver/driver-peripherals-motion-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-motion-des.md @@ -37,6 +37,8 @@ Motion驱动的主要工作是为上层MSDP服务提供稳定的使能/去使能 **表1** 接口功能介绍 +注:以下接口列举的为IDL接口描述生成的对应C++语言函数接口,接口声明见idl文件[/drivers/interface/motion/v1_0/](https://gitee.com/openharmony/drivers_interface/tree/master/motion) 。 + | 接口名 | 功能介绍 | | ------------------------------------------------------------ | ---------------------------- | | int32_t EnableMotion(int32_t motionType) | 使能一种手势识别类型,只有数据订阅者使能手势识别后,才能获取订阅的手势识别数据。 | @@ -49,29 +51,30 @@ Motion驱动的主要工作是为上层MSDP服务提供稳定的使能/去使能 开发步骤分为两个大步骤。 1. 基于HDF驱动框架,完成手势识别用户态驱动开发。 + 2. 厂商实现EnableMotion、DisableMotion、Register和Unregister接口功能。 手势识别目录结构及各部分功能简介。 -```undefined -/drivers/peripheral/motion # 此目录具体实现需要厂商根据自己的器件进行开发 -├── hdi_service # 手势识别模块对上层MSDP服务提供的驱动能力 -├── test # 手势识别模块测试代码 -│ └── unittest\hdi # 手势识别模块HDI单元测试代码 +``` +/drivers/peripheral/motion // 此目录具体实现需要厂商根据自己的器件进行开发 +├── hdi_service // motion模块对上层服务提供的驱动能力 +├── test // motion模块测试代码 + └── unittest\hdi // motion模块hdi单元测试代码 ``` -下面结合DEMO实例,介绍如何基于HDF驱动框架,进行手势识别用户态驱动开发。具体实现请参考[motion_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_interface_driver.cpp)。 +下面结合DEMO实例,介绍如何基于HDF驱动框架,进行手势识别用户态驱动开发。具体实现请参考[motion_if_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_if_driver.cpp)。 手势识别用户态驱动开发, 主要完成Bind、Init、Release、Dispatch函数接口实现。其中Bind函数为驱动绑定对外提供的服务能力,Init函数为系统加载驱动前需要的一些初始化的操作,Release函数的主要作用为当系统加载驱动调用Init函数失败时对资源进行回收操作,Dispatch函数为服务能力的具体实现,在Bind函数中进行绑定。 -```c++ -// 自定义的HdfMotionInterfaceHost对象 +```c +/* 自定义的HdfMotionInterfaceHost对象 */ struct HdfMotionInterfaceHost { struct IDeviceIoService ioService; OHOS::sptr stub; }; -// 服务接口调用响应接口 +/* 服务接口调用响应接口 */ static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) { @@ -93,14 +96,14 @@ static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, i return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); } -// 初始化接口 +/* 初始化接口 */ int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject) { HDF_LOGI("HdfMotionInterfaceDriverInit enter"); return HDF_SUCCESS; } -// Motion驱动对外提供的服务绑定到HDF框架 +/* Motion驱动对外提供的服务绑定到HDF框架 */ int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) { HDF_LOGI("HdfMotionInterfaceDriverBind enter"); @@ -132,7 +135,7 @@ int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) return HDF_SUCCESS; } -// 释放Motion驱动中的资源 +/* 释放Motion驱动中的资源 */ void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) { HDF_LOGI("HdfMotionInterfaceDriverRelease enter"); @@ -141,7 +144,7 @@ void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) hdfMotionInterfaceHost = nullptr; } -// 注册Motion驱动入口数据结构体对象 +/* 注册Motion驱动入口数据结构体对象 */ struct HdfDriverEntry g_motioninterfaceDriverEntry = { .moduleVersion = 1, .moduleName = "motion_service", @@ -150,7 +153,7 @@ struct HdfDriverEntry g_motioninterfaceDriverEntry = { .Release = HdfMotionInterfaceDriverRelease, }; -// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 +/* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */ HDF_INIT(g_userAuthInterfaceDriverEntry); ``` diff --git a/zh-cn/device-dev/driver/driver-peripherals-sensor-des.md b/zh-cn/device-dev/driver/driver-peripherals-sensor-des.md index 7884dda328d4b84431493f80deb034ff28b83a71..f7b688d0796cbf481ade2915f518aba8f4eea7c9 100755 --- a/zh-cn/device-dev/driver/driver-peripherals-sensor-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-sensor-des.md @@ -27,7 +27,7 @@ Sensor驱动模型屏蔽硬件器件差异,为上层Sensor服务系统提供 ![Sensor驱动运行图](figures/Sensor驱动运行图.png) -Sensor驱动模型以标准系统Hi3516DV300产品中的加速度传感器驱动为例,介绍整个驱动加载及运行流程: +Sensor驱动模型以标准系统RK3568产品中的加速度传感器驱动为例,介绍整个驱动加载及运行流程: 1. 从device_info.hcs配置文件中的Sensor Host读取到Sensor设备管理配置信息。 2. HDF配置框架从HCB数据库中解析Sensor设备管理配置信息,并关联对应设备驱动。 @@ -64,6 +64,8 @@ Sensor驱动模型对外开放的API接口能力的具体实现请参考: **表 1** Sensor驱动模型对外API接口功能介绍 +注:以下接口列举的为C接口,接口声明见文件[/drivers/peripheral/sensor/interfaces/include](https://gitee.com/openharmony/drivers_peripheral/tree/master/sensor/interfaces/include)。 + | 接口名 | 功能描述 | | ----- | -------- | | int32_t GetAllSensors(struct SensorInformation **sensorInfo, int32_t *count) | 获取系统中注册的所有传感器信息,一组完整传感器信息包括传感器名字、设备厂商、固件版本号、硬件版本号、传感器类型编号、传感器标识、最大量程、精度、功耗。 | @@ -74,8 +76,7 @@ Sensor驱动模型对外开放的API接口能力的具体实现请参考: | int32_t SetOption(int32_t sensorId, uint32_t option) | 设置指定传感器量程,精度等可选配置。 | | int32_t Register(int32_t groupId, RecordDataCallback cb) | 订阅者根据不同groupId注册传感器数据回调函数,系统会将获取到的传感器数据上报给订阅者。 | | int32_t Unregister(int32_t groupId, RecordDataCallback cb) | 订阅者根据groupId和回调函数注销对应订阅者的传感器数据回调函数。 | - - +| int32_t ReadData(int32_t sensorId, struct SensorEvents *event); | 在小型系统上查询指定传感器的数据。 | Sensor驱动模型对驱动开发者开放的功能接口,驱动开发者无需实现,直接使用,请参考: @@ -95,8 +96,6 @@ Sensor驱动模型对驱动开发者开放的功能接口,驱动开发者无 | int32_t GetSensorBusHandle(struct SensorBusCfg *busCfg) | 获取传感器总线句柄信息。 | | int32_t ReleaseSensorBusHandle(struct SensorBusCfg *busCfg) | 释放传感器句柄信息。 | - - Sensor驱动模型要求驱动开发者实现的接口功能,请参考: **表 3** Sensor驱动模型要求驱动开发者实现的接口列表 @@ -115,480 +114,773 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: 接口实现参考[开发步骤](#开发步骤)章节。 ### 开发步骤 -1. 基于HDF驱动框架,按照驱动Driver Entry程序,完成加速度抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 +基于HDF驱动框架,按照驱动Driver Entry程序,以加速度传感器驱动为例,介绍传感器驱动的开发。传感器的驱动开发包括抽象驱动开发和差异化驱动开发两部分。传感器的抽象驱动开发包括同一个传感器id中不同器件的公共接口实现;传感器的差异化驱动开发包括不同器件差异化接口的实现。 - - 加速度传感器驱动入口函数实现 +1. 开发加速度传感器抽象驱动。 - ```c - /* 注册加速度计传感器入口数据结构体对象 */ - struct HdfDriverEntry g_sensorAccelDevEntry = { - .moduleVersion = 1, // 加速度计传感器模块版本号 - .moduleName = "HDF_SENSOR_ACCEL", // 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样 - .Bind = BindAccelDriver, // 加速度计传感器绑定函数 - .Init = InitAccelDriver, // 加速度计传感器初始化函数 - .Release = ReleaseAccelDriver, // 加速度计传感器资源释放函数 - }; - - /* 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */ - HDF_INIT(g_sensorAccelDevEntry); - ``` + - 加速度传感器抽象驱动在Sensor Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。 - - 加速度传感器驱动操作接口实现 + 具体代码实现如下: ```c - /* 加速度计传感器驱动对外提供的服务绑定到HDF框架 */ - int32_t AccelBindDriver(struct HdfDeviceObject *device) - { - CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); - - struct AccelDrvData *drvData = (struct AccelDrvData *)OsalMemCalloc(sizeof(*drvData)); - if (drvData == NULL) { - HDF_LOGE("%s: Malloc accel drv data fail!", __func__); - return HDF_ERR_MALLOC_FAIL; - } - - drvData->ioService.Dispatch = DispatchAccel; - drvData->device = device; - device->service = &drvData->ioService; - g_accelDrvData = drvData; - return HDF_SUCCESS; - } - - /* 注册加速度计传感器驱动归一化的接口函数 */ - static int32_t InitAccelOps(struct SensorCfgData *config, struct SensorDeviceInfo *deviceInfo) - { - CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM); - - deviceInfo->ops.Enable = SetAccelEnable; - deviceInfo->ops.Disable = SetAccelDisable; - deviceInfo->ops.SetBatch = SetAccelBatch; - deviceInfo->ops.SetMode = SetAccelMode; - deviceInfo->ops.SetOption = SetAccelOption; - - if (memcpy_s(&deviceInfo->sensorInfo, sizeof(deviceInfo->sensorInfo), - &config->sensorInfo, sizeof(config->sensorInfo)) != EOK) { - HDF_LOGE("%s: Copy sensor info failed", __func__); - return HDF_FAILURE; - } - - return HDF_SUCCESS; - } - /* 提供给差异化驱动的初始化接口,完成加速度器件基本配置信息解析(加速度信息、加速度总线配置、加速度器件探测寄存器配置)、器件探测、器件寄存器解析 */ - static int32_t InitAccelAfterDetected(struct SensorCfgData *config) - { - struct SensorDeviceInfo deviceInfo; - CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM); - /* 初始化加速度计接口函数 */ - if (InitAccelOps(config, &deviceInfo) != HDF_SUCCESS) { - HDF_LOGE("%s: Init accel ops failed", __func__); - return HDF_FAILURE; - } - /* 注册加速度计设备到传感器管理模块 */ - if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) { - HDF_LOGE("%s: Add accel device failed", __func__); - return HDF_FAILURE; + /* 加速度计传感器设备HCS配置 */ + device_sensor_accel :: device { + device0 :: deviceNode { + policy = 1; // 驱动服务发布的策略 + priority = 110; // 驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 + preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 + permission = 0664; // 驱动创建设备节点权限 + moduleName = "HDF_SENSOR_ACCEL"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "sensor_accel"; // 驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "hdf_sensor_accel_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 } - /* 器件寄存器解析 */ - if (ParseSensorRegConfig(config) != HDF_SUCCESS) { - HDF_LOGE("%s: Parse sensor register failed", __func__); - (void)DeleteSensorDevice(&config->sensorInfo); - ReleaseSensorAllRegConfig(config); - return HDF_FAILURE; - } - return HDF_SUCCESS; - } - struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node) - { - …… - /* 如果探测不到器件在位,返回进行下个器件探测 */ - if (drvData->detectFlag) { - HDF_LOGE("%s: Accel sensor have detected", __func__); - return NULL; + } + ``` + + - 加速度传感器抽象驱动代码实现路径为:drivers\hdf_core\framework\model\sensor\driver\accel\sensor_accel_driver.c。 + + - 加速度传感器抽象驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下: + + ```c + struct HdfDriverEntry g_sensorAccelDevEntry = { + .moduleVersion = 1, // 加速度计传感器模块版本号 + .moduleName = "HDF_SENSOR_ACCEL", // 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样 + .Bind = BindAccelDriver, // 加速度计传感器绑定函数 + .Init = InitAccelDriver, // 加速度计传感器初始化函数 + .Release = ReleaseAccelDriver, // 加速度计传感器资源释放函数 + }; + + /* 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */ + HDF_INIT(g_sensorAccelDevEntry); + ``` + + - 加速度传感器抽象驱动Bind接口实现如下: + + ```c + int32_t AccelBindDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + + struct AccelDrvData *drvData = (struct AccelDrvData *)OsalMemCalloc(sizeof(*drvData)); + if (drvData == NULL) { + HDF_LOGE("%s: Malloc accel drv data fail!", __func__); + return HDF_ERR_MALLOC_FAIL; + } + + drvData->ioService.Dispatch = DispatchAccel; + drvData->device = device; + device->service = &drvData->ioService; + g_accelDrvData = drvData; + return HDF_SUCCESS; + } + ``` + + - 加速度传感器抽象驱动Init接口实现如下: + + ```c + int32_t AccelInitDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + struct AccelDrvData *drvData = (struct AccelDrvData *)device->service; + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + /* 工作队列资源初始化 */ + if (InitAccelData(drvData) != HDF_SUCCESS) { + HDF_LOGE("%s: Init accel config failed", __func__); + return HDF_FAILURE; + } + /* 分配加速度配置信息资源 */ + drvData->accelCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->accelCfg)); + if (drvData->accelCfg == NULL) { + HDF_LOGE("%s: Malloc accel config data failed", __func__); + return HDF_FAILURE; + } + /* 注册寄存器分组信息 */ + drvData->accelCfg->regCfgGroup = &g_regCfgGroup[0]; + drvData->cb = NULL; + + HDF_LOGI("%s: Init accel driver success", __func__); + return HDF_SUCCESS; + } + ``` + + - 加速度抽象传感器驱动Release接口在驱动卸载或者Init执行失败时,会调用此接口释放资源,具体实现如下: + + ```c + void AccelReleaseDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN(device); + + struct AccelDrvData *drvData = (struct AccelDrvData *)device->service; + CHECK_NULL_PTR_RETURN(drvData); + /* 器件在位,释放已分配资源 */ + if (drvData->detectFlag && drvData->accelCfg != NULL) { + AccelReleaseCfgData(drvData->accelCfg); + } + + OsalMemFree(drvData->accelCfg); + drvData->accelCfg = NULL; + /* 器件在位,销毁工作队列资源 */ + HdfWorkDestroy(&drvData->accelWork); + HdfWorkQueueDestroy(&drvData->accelWorkQueue); + OsalMemFree(drvData); + } + ``` + + - 加速度传感器抽象驱动内部接口代码实现如下: + + - 提供给差异化驱动的初始化接口,完成加速度传感器器件的基本配置信息解析(加速度传感器信息,加速度传感器总线配置,加速度传感器器件探测寄存器配置),器件探测,器件寄存器解析,具体实现如下: + + ```c + static int32_t InitAccelAfterDetected(struct SensorCfgData *config) + { + struct SensorDeviceInfo deviceInfo; + CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM); + /* 初始化加速度计接口函数 */ + if (InitAccelOps(config, &deviceInfo) != HDF_SUCCESS) { + HDF_LOGE("%s: Init accel ops failed", __func__); + return HDF_FAILURE; + } + /* 注册加速度计器件到传感器设备管理模块 */ + if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) { + HDF_LOGE("%s: Add accel device failed", __func__); + return HDF_FAILURE; + } + /* 器件寄存器解析 */ + if (ParseSensorDirection(config) != HDF_SUCCESS) { + HDF_LOGE("%s: Parse accel direction failed", __func__); + (void)DeleteSensorDevice(&config->sensorInfo); + return HDF_FAILURE; + } + + if (ParseSensorRegConfig(config) != HDF_SUCCESS) { + HDF_LOGE("%s: Parse sensor register failed", __func__); + (void)DeleteSensorDevice(&config->sensorInfo); + ReleaseSensorAllRegConfig(config); + ReleaseSensorDirectionConfig(config); + return HDF_FAILURE; + } + return HDF_SUCCESS; } - if (drvData->accelCfg == NULL) { - HDF_LOGE("%s: Accel accelCfg pointer NULL", __func__); - return NULL; + + struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node) + { + struct AccelDrvData *drvData = AccelGetDrvData(); + /* 如果器件不在位,返回进行下个器件探测 */ + if (drvData == NULL || node == NULL) { + HDF_LOGE("%s: Accel node pointer NULL", __func__); + return NULL; + } + + if (drvData->detectFlag) { + HDF_LOGE("%s: Accel sensor have detected", __func__); + return NULL; + } + + if (drvData->accelCfg == NULL) { + HDF_LOGE("%s: Accel accelCfg pointer NULL", __func__); + return NULL; + } + /* 设备基本配置信息解析 */ + if (GetSensorBaseConfigData(node, drvData->accelCfg) != HDF_SUCCESS) { + HDF_LOGE("%s: Get sensor base config failed", __func__); + goto BASE_CONFIG_EXIT; + } + /* 如果器件不在位(存在器件ID的情况),返回进行下个器件探测 */ + if (DetectSensorDevice(drvData->accelCfg) != HDF_SUCCESS) { + HDF_LOGI("%s: Accel sensor detect device no exist", __func__); + drvData->detectFlag = false; + goto BASE_CONFIG_EXIT; + } + /* 器件寄存器解析 */ + drvData->detectFlag = true; + if (InitAccelAfterDetected(drvData->accelCfg) != HDF_SUCCESS) { + HDF_LOGE("%s: Accel sensor detect device no exist", __func__); + goto INIT_EXIT; + } + return drvData->accelCfg; + + INIT_EXIT: + (void)ReleaseSensorBusHandle(&drvData->accelCfg->busCfg); + BASE_CONFIG_EXIT: + drvData->accelCfg->root = NULL; + (void)memset_s(&drvData->accelCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo)); + (void)memset_s(&drvData->accelCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg)); + (void)memset_s(&drvData->accelCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr)); + return drvData->accelCfg; } - /* 设备基本配置信息解析 */ - if (GetSensorBaseConfigData(node, drvData->accelCfg) != HDF_SUCCESS) { - HDF_LOGE("%s: Get sensor base config failed", __func__); - goto BASE_CONFIG_EXIT; + ``` + + - Enable接口的代码实现如下: + + ```c + static int32_t SetAccelEnable(void) + { + int32_t ret; + struct AccelDrvData *drvData = AccelGetDrvData(); + + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); + + if (drvData->enable) { + HDF_LOGE("%s: Accel sensor is enabled", __func__); + return HDF_SUCCESS; + } + /* 设置寄存器 */ + ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel sensor enable config failed", __func__); + return ret; + } + /* 创建定时器 */ + ret = OsalTimerCreate(&drvData->accelTimer, SENSOR_TIMER_MIN_TIME, AccelTimerEntry, (uintptr_t)drvData); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel create timer failed[%d]", __func__, ret); + return ret; + } + /* 开启定时器进行数据上报 */ + ret = OsalTimerStartLoop(&drvData->accelTimer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel start timer failed[%d]", __func__, ret); + return ret; + } + drvData->enable = true; + + return HDF_SUCCESS; } - /* 如果探测不到器件在位,返回进行下个器件探测 */ - if (DetectSensorDevice(drvData->accelCfg) != HDF_SUCCESS) { - HDF_LOGI("%s: Accel sensor detect device no exist", __func__); - drvData->detectFlag = false; - goto BASE_CONFIG_EXIT; + ``` + + - Disable接口的代码实现如下: + + ```c + static int32_t SetAccelDisable(void) + { + int32_t ret; + struct AccelDrvData *drvData = AccelGetDrvData(); + + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); + + if (!drvData->enable) { + HDF_LOGE("%s: Accel sensor had disable", __func__); + return HDF_SUCCESS; + } + /* 设置寄存器 */ + ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel sensor disable config failed", __func__); + return ret; + } + /* 删除定时器 */ + ret = OsalTimerDelete(&drvData->accelTimer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Accel delete timer failed", __func__); + return ret; + } + drvData->enable = false; + + return HDF_SUCCESS; } - drvData->detectFlag = true; - /* 器件寄存器解析 */ - if (InitAccelAfterDetected(drvData->accelCfg) != HDF_SUCCESS) { - HDF_LOGE("%s: Accel sensor detect device no exist", __func__); - goto INIT_EXIT; + ``` + + - SetBatch接口的代码实现如下: + + ```c + static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval) + { + (void)interval; + + struct AccelDrvData *drvData = NULL; + + drvData = AccelGetDrvData(); + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + /* 给定时器设置采样率 */ + drvData->interval = samplingInterval; + + return HDF_SUCCESS; } - return drvData->accelCfg; - …… - } - /* 加速度计传感器驱动初始化入口函数,主要功能为对传感器私有数据的结构体对象进行初始化,传感器HCS数据配置对象空间分配,传感器HCS数据配置初始化入口函数调用,传感器设备探测是否在位功能,传感器数据上报定时器创建,传感器归一化接口注册,传感器设备注册功能 */ - int32_t AccelInitDriver(struct HdfDeviceObject *device) - { - …… - /* 工作队列资源初始化 */ - if (InitAccelData(drvData) != HDF_SUCCESS) { - HDF_LOGE("%s: Init accel config failed", __func__); - return HDF_FAILURE; + ``` + + - SetMode接口的代码实现如下: + + ```c + static int32_t SetAccelMode(int32_t mode) + { + if (mode <= SENSOR_WORK_MODE_DEFAULT || mode >= SENSOR_WORK_MODE_MAX) { + HDF_LOGE("%s: The current mode is not supported", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; } - /* 分配加速度配置信息资源 */ - drvData->accelCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->accelCfg)); - if (drvData->accelCfg == NULL) { - HDF_LOGE("%s: Malloc accel config data failed", __func__); - return HDF_FAILURE; + ``` + + - SetOption接口的代码实现如下: + + ```c + static int32_t SetAccelOption(uint32_t option) + { + (void)option; + return HDF_SUCCESS; } - /* 注册寄存器分组信息 */ - drvData->accelCfg->regCfgGroup = &g_regCfgGroup[0]; - …… - return HDF_SUCCESS; - } - /* 释放驱动初始化时分配的资源 */ - void AccelReleaseDriver(struct HdfDeviceObject *device) - { - CHECK_NULL_PTR_RETURN(device); - struct AccelDrvData *drvData = (struct AccelDrvData *)device->service; - CHECK_NULL_PTR_RETURN(drvData); - /* 器件在位,释放已分配资源 */ - if (drvData->detectFlag) { - AccelReleaseCfgData(drvData->accelCfg); + ``` + +2. 开发加速度传感器差异化驱动。 + + - 加速度传感器差异化驱动在Sensor Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。 + + 具体代码实现如下: + + ```c + device_sensor_mxc6655xa :: device { + device0 :: deviceNode { + policy = 1; // policy字段是驱动服务发布的策略 + priority = 120; // 驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 + preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 + permission = 0664; // 驱动创建设备节点权限 + moduleName = "HDF_SENSOR_ACCEL_MXC6655XA"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "hdf_accel_mxc6655xa"; // 加速度mxc6655xa对外发布服务的名称,必须唯一 + deviceMatchAttr = "hdf_sensor_accel_mxc6655xa_driver"; // 加速度差异化驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 } - OsalMemFree(drvData->accelCfg); - drvData->accelCfg = NULL; - /* 器件在位,销毁工作队列资源 */ - HdfWorkDestroy(&drvData->accelWork); - HdfWorkQueueDestroy(&drvData->accelWorkQueue); - OsalMemFree(drvData); } ``` -2. 完成加速度传感器驱动的设备信息配置。 - - 加速度传感器模型使用HCS作为配置描述源码,HCS配置字段请参考[配置管理](driver-hdf-manage.md)介绍。 - - ```hcs - /* 加速度计传感器设备HCS配置 */ - device_sensor_accel :: device { - device0 :: deviceNode { - policy = 1; // 驱动服务发布的策略 - priority = 110; // 驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 - preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 - permission = 0664; // 驱动创建设备节点权限 - moduleName = "HDF_SENSOR_ACCEL"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 - serviceName = "sensor_accel"; // 驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "hdf_sensor_accel_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 + - 加速度传感器差异化驱动私有HCS配置: + + - 代码实现路径:vendor\hihope\rk3568\hdf_config\khdf\sensor\accel\mxc6655xa_config.hcs。 + + - 具体代码实现如下: + + ```c + #include "../sensor_common.hcs" + root { + accel_mxc6655xa_chip_config : sensorConfig { + match_attr = "hdf_sensor_accel_mxc6655xa_driver"; + sensorInfo :: sensorDeviceInfo { + sensorName = "accelerometer"; + vendorName = "memsi_mxc6655xa"; // max string length is 16 bytes + sensorTypeId = 1; // enum SensorTypeTag + sensorId = 1; // user define sensor id + power = 230; + minDelay = 5000000; // nanosecond + maxDelay = 200000000; // nanosecond + } + sensorBusConfig :: sensorBusInfo { + busType = 0; // 0:i2c 1:spi + busNum = 5; + busAddr = 0x15; + regWidth = 1; // 1byte + } + sensorIdAttr :: sensorIdInfo { + chipName = "mxc6655xa"; + chipIdRegister = 0x0f; + chipIdValue = 0x05; // 根据器件ID寄存器,读取的值,或查看相关芯片datasheet手册确认该值 + } + sensorDirection { + direction = 1; // chip direction range of value:0-7 + /* 1:negative 0:positive + 0:AXIS_X 1:AXIS_Y 2:AXIS_Z + */ + /* sign[AXIS_X], sign[AXIS_Y], sign[AXIS_Z], map[AXIS_X], map[AXIS_Y], map[AXIS_Z] */ + convert = [ + 0, 0, 0, 0, 1, 2, + 1, 0, 0, 1, 0, 2, + 0, 0, 1, 0, 1, 2, + 0, 1, 0, 1, 0, 2, + 1, 0, 1, 0, 1, 2, + 0, 0, 1, 1, 0, 2, + 0, 1, 1, 0, 1, 2, + 1, 1, 1, 1, 0, 2 + ]; + } + sensorRegConfig { + /* regAddr: register address + value: config register value + len: size of value + mask: mask of value + delay: config register delay time (ms) + opsType: enum SensorOpsType 0-none 1-read 2-write 3-read_check 4-update_bit + calType: enum SensorBitCalType 0-none 1-set 2-revert 3-xor 4-left shift 5-right shift + shiftNum: shift bits + debug: 0-no debug 1-debug + save: 0-no save 1-save + */ + /* regAddr, value, mask, len, delay, opsType, calType, shiftNum, debug, save */ + initSeqConfig = [ + 0x7e, 0xb6, 0xff, 1, 5, 2, 0, 0, 0, 0, + 0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0 + ]; + enableSeqConfig = [ + 0x7e, 0x11, 0xff, 1, 5, 2, 0, 0, 0, 0, + 0x41, 0x03, 0xff, 1, 0, 2, 0, 0, 0, 0, + 0x40, 0x08, 0xff, 1, 0, 2, 0, 0, 0, 0 + ]; + disableSeqConfig = [ + 0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0 + ]; + } + } } - } - ``` - -3. 完成加速度传感器抽象驱动内部接口开发,包括Enable、Disable、SetBatch、SetMode、SetOption、AccelCreateCfgData、AccelReleaseCfgData、AccelRegisterChipOps接口实现。 - - ```c - /* 不使用函数暂时置空 */ - static int32_t SetAccelInfo(struct SensorBasicInfo *info) - { - (void)info; - - return HDF_ERR_NOT_SUPPORT; - } - /* 下发使能寄存器组的配置 */ - static int32_t SetAccelEnable(void) - { - int32_t ret; - struct AccelDrvData *drvData = AccelGetDrvData(); - - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); - - if (drvData->enable) { - HDF_LOGE("%s: Accel sensor is enabled", __func__); + ``` + + - 加速度差异化驱动的代码实现路径:drivers\peripheral\sensor\chipset\accel\accel_mxc6655xa.c + + - 加速度传感器差异化驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下: + + ```c + /* 注册加速度mxc6655xa传感器入口数据结构体对象 */ + struct HdfDriverEntry g_accelMxc6655xaDevEntry = { + .moduleVersion = 1, // 加速度mxc6655xa传感器模块版本号 + .moduleName = "HDF_SENSOR_ACCEL_MXC6655XA", // 加速度mxc6655xa传感器模块名,要与device_info.hcs文件里加速度mxc6655xa传感器moduleName字段值一致 + .Bind = Mxc6655xaBindDriver, // 加速度mxc6655xa传感器的绑定函数 + .Init = Mxc6655xaInitDriver, // 加速度mxc6655xa传感器的初始化函数 + .Release = Mxc6655xaReleaseDriver, // 加速度mxc6655xa传感器资源释放函数 + }; + /* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */ + HDF_INIT(g_accelMxc6655xaDevEntry); + ``` + + - 加速度传感器差异化驱动Bind接口实现如下: + + ```c + int32_t Mxc6655xaBindDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + + struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)OsalMemCalloc(sizeof(*drvData)); + if (drvData == NULL) { + HDF_LOGE("%s: Malloc MXC6655XA drv data fail", __func__); + return HDF_ERR_MALLOC_FAIL; + } + + drvData->ioService.Dispatch = DispatchMXC6655xa; + drvData->device = device; + device->service = &drvData->ioService; + g_mxc6655xaDrvData = drvData; + return HDF_SUCCESS; } - - ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel sensor enable config failed", __func__); - return ret; - } - - ret = OsalTimerCreate(&drvData->accelTimer, SENSOR_TIMER_MIN_TIME, AccelTimerEntry, (uintptr_t)drvData); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel create timer failed[%d]", __func__, ret); - return ret; + ``` + + - 加速度传感器差异化驱动Init接口实现如下: + + ```c + int32_t Mxc6655xaInitDriver(struct HdfDeviceObject *device) + { + int32_t ret; + struct AccelOpsCall ops; + + CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); + struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service; + CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + + drvData->sensorCfg = AccelCreateCfgData(device->property); + if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) { + HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__); + return HDF_ERR_NOT_SUPPORT; + } + + ops.Init = NULL; + ops.ReadData = ReadMxc6655xaData; + ret = AccelRegisterChipOps(&ops); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Register MXC6655XA accel failed", __func__); + return HDF_FAILURE; + } + + ret = InitMxc6655xa(drvData->sensorCfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Init MXC6655XA accel failed", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; } - - ret = OsalTimerStartLoop(&drvData->accelTimer); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel start timer failed[%d]", __func__, ret); - return ret; + ``` + + - 加速度传感器差异化驱动Release接口实现如下: + + ```c + void Mxc6655xaReleaseDriver(struct HdfDeviceObject *device) + { + CHECK_NULL_PTR_RETURN(device); + + struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service; + CHECK_NULL_PTR_RETURN(drvData); + + if (drvData->sensorCfg != NULL) { + AccelReleaseCfgData(drvData->sensorCfg); + drvData->sensorCfg = NULL; + } + OsalMemFree(drvData); } - drvData->enable = true; - - return HDF_SUCCESS; - } - /* 下发去使能寄存器组的配置 */ - static int32_t SetAccelDisable(void) - { - int32_t ret; - struct AccelDrvData *drvData = AccelGetDrvData(); - - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM); - - if (!drvData->enable) { - HDF_LOGE("%s: Accel sensor had disable", __func__); + ``` + + - 加速度传感器差异化驱动内部接口实现。 + + 需要开发者实现的ReadMxc6655xaData接口函数,在 Mxc6655xaInitDriver函数里面注册此函数,具体实现如下: + + ```c + static int32_t ReadMxc6655xaRawData(struct SensorCfgData *data, struct AccelData *rawData, uint64_t *timestamp) + { + uint8_t status = 0; + uint8_t reg[ACCEL_AXIS_BUTT]; + OsalTimespec time; + int32_t x; + int32_t y; + int32_t z; + + (void)memset_s(&time, sizeof(time), 0, sizeof(time)); + (void)memset_s(reg, sizeof(reg), 0, sizeof(reg)); + + CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM); + + if (OsalGetTime(&time) != HDF_SUCCESS) { + HDF_LOGE("%s: Get time failed", __func__); + return HDF_FAILURE; + } + *timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT; /* unit nanosecond */ + + int32_t ret = ReadSensor(&data->busCfg, MXC6655XA_STATUS_ADDR, &status, sizeof(uint8_t)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: data status [%u] ret [%d]", __func__, status, ret); + return HDF_FAILURE; + } + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_LSB_ADDR, ®[ACCEL_X_AXIS_LSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_MSB_ADDR, ®[ACCEL_X_AXIS_MSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_LSB_ADDR, ®[ACCEL_Y_AXIS_LSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_MSB_ADDR, ®[ACCEL_Y_AXIS_MSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_LSB_ADDR, ®[ACCEL_Z_AXIS_LSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_MSB_ADDR, ®[ACCEL_Z_AXIS_MSB], sizeof(uint8_t)); + CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data"); + + x = SensorConvertData(reg[ACCEL_X_AXIS_MSB], reg[ACCEL_X_AXIS_LSB]); + y = SensorConvertData(reg[ACCEL_Y_AXIS_MSB], reg[ACCEL_Y_AXIS_LSB]); + z = SensorConvertData(reg[ACCEL_Z_AXIS_MSB], reg[ACCEL_Z_AXIS_LSB]); + rawData->x = x; + rawData->y = y; + rawData->z = z; + return HDF_SUCCESS; } - - ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel sensor disable config failed", __func__); - return ret; - } - - ret = OsalTimerDelete(&drvData->accelTimer); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Accel delete timer failed", __func__); + /* 读取加速度的event数据,在 Mxc6655xaInitDriver函数里面注册此函数,将数据传给加速度抽象驱动 */ + int32_t ReadMxc6655xaData(struct SensorCfgData *cfg, struct SensorReportEvent *event) + { + int32_t ret; + struct AccelData rawData = { 0, 0, 0 }; + static int32_t tmp[ACCEL_AXIS_NUM]; + + CHECK_NULL_PTR_RETURN_VALUE(cfg, HDF_ERR_INVALID_PARAM); + CHECK_NULL_PTR_RETURN_VALUE(event, HDF_ERR_INVALID_PARAM); + + ret = ReadMxc6655xaRawData(cfg, &rawData, &event->timestamp); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: MXC6655XA read raw data failed", __func__); + return HDF_FAILURE; + } + + event->sensorId = SENSOR_TAG_ACCELEROMETER; + event->option = 0; + event->mode = SENSOR_WORK_MODE_REALTIME; + + rawData.x = rawData.x * MXC6655XA_ACC_SENSITIVITY_2G; + rawData.y = rawData.y * MXC6655XA_ACC_SENSITIVITY_2G; + rawData.z = rawData.z * MXC6655XA_ACC_SENSITIVITY_2G; + + tmp[ACCEL_X_AXIS] = (rawData.x * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT; + tmp[ACCEL_Y_AXIS] = (rawData.y * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT; + tmp[ACCEL_Z_AXIS] = (rawData.z * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT; + + ret = SensorRawDataToRemapData(cfg->direction, tmp, sizeof(tmp) / sizeof(tmp[0])); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: MXC6655XA convert raw data failed", __func__); + return HDF_FAILURE; + } + + event->dataLen = sizeof(tmp); + event->data = (uint8_t *)&tmp; + return ret; } - drvData->enable = false; - - return HDF_SUCCESS; - } - /* 配置传感器采样率和数据上报间隔 */ - static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval) - { - (void)interval; - - struct AccelDrvData *drvData = NULL; - - drvData = AccelGetDrvData(); - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - - drvData->interval = samplingInterval; - - return HDF_SUCCESS; - } - /* 设置传感器工作模式,当前支持实时模式 */ - static int32_t SetAccelMode(int32_t mode) - { - return (mode == SENSOR_WORK_MODE_REALTIME) ? HDF_SUCCESS : HDF_FAILURE; - } - - static int32_t SetAccelOption(uint32_t option) - { - (void)option; - return HDF_SUCCESS; - } - /* 设置传感器可选配置 */ - static int32_t SetAccelOption(uint32_t option) - { - (void)option; - return HDF_ERR_NOT_SUPPORT; - } - ``` - -4. 基于HDF驱动框架,按照驱动Driver Entry程序,完成加速度传感器差异化驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 - - ```c - /* 加速度计传感器差异化驱动消息交互 */ - static int32_t DispatchBMI160(struct HdfDeviceIoClient *client, - int cmd, struct HdfSBuf *data, struct HdfSBuf *reply) - { - (void)client; - (void)cmd; - (void)data; - (void)reply; - - return HDF_SUCCESS; - } - /* 加速度计传感器差异化驱动对外提供的服务绑定到HDF框架 */ - int32_t Bmi160BindDriver(struct HdfDeviceObject *device) - { - CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); - - struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)OsalMemCalloc(sizeof(*drvData)); - if (drvData == NULL) { - HDF_LOGE("%s: Malloc Bmi160 drv data fail", __func__); - return HDF_ERR_MALLOC_FAIL; - } - - drvData->ioService.Dispatch = DispatchBMI160; - drvData->device = device; - device->service = &drvData->ioService; - g_bmi160DrvData = drvData; - - return HDF_SUCCESS; - } - /* 加速度计传感器差异化驱动初始化 */ - int32_t Bmi160InitDriver(struct HdfDeviceObject *device) - { - int32_t ret; - struct AccelOpsCall ops; - - CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); - struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)device->service; - CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - - ret = InitAccelPreConfig(); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Init BMI160 bus mux config", __func__); - return HDF_FAILURE; - } - - drvData->sensorCfg = AccelCreateCfgData(device->property); - if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) { - HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__); - return HDF_ERR_NOT_SUPPORT; - } - - ops.Init = NULL; - ops.ReadData = ReadBmi160Data; - ret = AccelRegisterChipOps(&ops); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Register BMI160 accel failed", __func__); - return HDF_FAILURE; - } - - ret = InitBmi160(drvData->sensorCfg); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: Init BMI160 accel failed", __func__); - return HDF_FAILURE; - } - - return HDF_SUCCESS; - } - /* 释放驱动初始化时分配的资源 */ - void Bmi160ReleaseDriver(struct HdfDeviceObject *device) - { - ...... - if (drvData->sensorCfg != NULL) { - AccelReleaseCfgData(drvData->sensorCfg); - drvData->sensorCfg = NULL; - } - OsalMemFree(drvData); - } - /* 加速度传感器差异化驱动对应的HdfDriverEntry对象 */ - struct HdfDriverEntry g_accelBmi160DevEntry = { - .moduleVersion = 1, - .moduleName = "HDF_SENSOR_ACCEL_BMI160", - .Bind = Bmi160BindDriver, - .Init = Bmi160InitDriver, - .Release = Bmi160ReleaseDriver, - }; - HDF_INIT(g_accelBmi160DevEntry); - ``` - -5. 完成加速度传感器差异化驱动中差异化接口ReadData函数实现。 - - ```c - int32_t ReadBmi160Data(struct SensorCfgData *data) - { - int32_t ret; - struct AccelData rawData = { 0, 0, 0 }; - int32_t tmp[ACCEL_AXIS_NUM]; - struct SensorReportEvent event; - (void)memset_s(&event, sizeof(event), 0, sizeof(event)); - ret = ReadBmi160RawData(data, &rawData, &event.timestamp); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: BMI160 read raw data failed", __func__); - return HDF_FAILURE; - } - event.sensorId = SENSOR_TAG_ACCELEROMETER; - event.option = 0; - event.mode = SENSOR_WORK_MODE_REALTIME; - …… - ret = ReportSensorEvent(&event); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: BMI160 report data failed", __func__); - } - return ret; - } - ``` + ``` ### 调测验证 驱动开发完成后,在传感器单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。 -```c++ -static int32_t g_sensorDataFlag = 0; // 标识是否上报传感器数据 -static const struct SensorInterface *g_sensorDev = nullptr; // 保持获取的传感器接口实例地址 - -/* 订阅者注册数据上报函数 */ -static int SensorTestDataCallback(struct SensorEvents *event) -{ - if (event == nullptr) { - return -1; - } - float *data = (float*)event->data; - printf("time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]\n\r", event->timestamp, - event->sensorId, (*data), *(data + 1), *(data + g_axisZ)); - if (*data > 1e-5) { - g_sensorDataFlag = 1; - } - return 0; -} -/* 用例执行前,初始化传感器接口实例 */ -void HdfSensorTest::SetUpTestCase() -{ - g_sensorDev = NewSensorInterfaceInstance(); - if (g_sensorDev == nullptr) { - printf("test sensor get module instance failed\n\r"); - } -} -/* 用例资源释放 */ -void HdfSensorTest::TearDownTestCase() -{ - if (g_sensorDev != nullptr) { - FreeSensorInterfaceInstance(); - g_sensorDev = nullptr; - } -} -/* 传感器驱动测试验证 */ -HWTEST_F(HdfSensorTest,TestAccelDriver_001, TestSize.Level0) -{ - int32_t sensorInterval = 1000000000; // 数据采样率单位纳秒 - int32_t pollTime = 5; // 数据采样时间单位秒 - int32_t accelSensorId = 1; // 加速度传感器类型标识为1 - int32_t count = 0; - int ret; - struct SensorInformation *sensorInfo = nullptr; - - ret = g_sensorDev->Register(0, TraditionSensorTestDataCallback) - EXPECT_EQ(SENSOR_NULL_PTR, ret); - - ret = g_sensorDev->GetAllSensors(&sensorInfo, &count); - EXPECT_EQ(0, ret); - if (sensorInfo == nullptr) { - EXPECT_NE(nullptr, sensorInfo); - return; - } - /* 打印获取的传感器列表 */ - for (int i = 0; i < count; i++) { - printf("get sensorId[%d], info name[%s]\n\r", sensorInfo[i]->sensorId, sensorInfo[i]->sensorName); - } - ret = g_sensorDev->Enable(accelSensorId); - EXPECT_EQ(0, ret); - g_sensorDataFlag = 0; - - ret = g_sensorDev->SetBatch(accelSensorId, sensorInterval, pollTime); - EXPECT_EQ(0, ret); - /* 在时间pollTime内,观察输出打印数据 */ - OsalSleep(pollTime); - EXPECT_EQ(1, g_sensorDataFlag); - - ret = g_sensorDev->Disable(accelSensorId); - g_sensorDataFlag = 0; - EXPECT_EQ(0, ret); - - ret = g_sensorDev->Unregister(0, TraditionSensorTestDataCallback); - EXPECT_EQ(0, ret); -} -``` +- 参考测试代码如下: + + ```c + #include + #include + #include + #include + #include + #include "hdf_base.h" + #include "osal_mem.h" + #include "osal_time.h" + #include "sensor_if.h" + #include "sensor_type.h" + + using namespace testing::ext; + const struct SensorInterface *g_sensorDev = nullptr; + /* 创建回调函数 */ + static int32_t SensorDataCallback(const struct SensorEvents *event) + { + if (event == NULL) { + return HDF_FAILURE; + } + + float *data = (float*)event->data; + printf("time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]\n\r", event->timestamp, + event->sensorId, (*data), *(data + 1), *(data + 2)); + + return HDF_SUCCESS; + } + + class HdfSensorTest : public testing::Test { + public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + }; + + /* 用例执行前,初始化传感器接口实例 */ + void HdfSensorTest::SetUpTestCase() + { + g_sensorDev = NewSensorInterfaceInstance(); + if (g_sensorDev == nullptr) { + printf("test sensor get module instance failed\n\r"); + } + } + /* 用例资源释放 */ + void HdfSensorTest::TearDownTestCase() + { + if (g_sensorDev != nullptr) { + FreeSensorInterfaceInstance(); + g_sensorDev = nullptr; + } + } + + void HdfSensorTest::SetUp() + { + } + + void HdfSensorTest::TearDown() + { + } + + HWTEST_F(HdfSensorTest,TestAccelDriver_001, TestSize.Level0) + { + int ret; + struct SensorInformation *sensorInfo = NULL; + int32_t count = 0; + int32_t sensorInterval = 200000000; /* 数据采样率设置200毫秒,单位纳秒 */ + int32_t reportInterval = 400000000; + + /* 2.订阅者注册传感器数据回调处理函数 */ + ret = g_sensorDev->Register(TRADITIONAL_SENSOR_TYPE, SensorDataCallback); + if (ret != 0) { + return; + } + printf("Register success\n"); + + /* 3.获取设备支持的Sensor列表 */ + ret = g_sensorDev->GetAllSensors(&sensorInfo, &count); + if (ret != 0) { + return; + } + + printf("GetAllSensors count: %d\n", count); + + for (int i = 0; i < count; i++) + { + printf("sensor [%d]: sensorName: %s, vendorName: %s, sensorTypeId: %d, sensorId: %d\n", i, + sensorInfo[i].sensorName, sensorInfo[i].vendorName, sensorInfo[i].sensorTypeId, sensorInfo[i].sensorId); + } + + for (int i = 0; i < count; i++) + { + /* 4.设置传感器采样率 */ + ret = g_sensorDev->SetBatch(sensorInfo[i].sensorId, sensorInterval, reportInterval); + if (ret != 0) { + printf("SetBatch failed\n ,ret: %d",ret); + continue; + } + printf("SetBatch success\n"); + + /* 5.使能传感器 */ + ret = g_sensorDev->Enable(sensorInfo[i].sensorId); + if (ret != 0) { + continue; + } + printf("Enable success\n"); + + usleep(1000 * 1000); + + /* 6.去使能传感器 */ + ret = g_sensorDev->Disable(sensorInfo[i].sensorId); + if (ret != 0) { + continue; + } + printf("Disable success\n"); + } + + /* 7.取消传感器数据订阅函数 */ + ret = g_sensorDev->Unregister(TRADITIONAL_SENSOR_TYPE, SensorDataCallback); + if (ret != 0) { + return; + } + printf("Unregister success\n"); + } + ``` + +- 编译文件gn参考代码如下: + + ``` + import("//build/ohos.gni") + import("//build/test.gni") + import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") + + module_output_path = "drivers_peripheral_sensor/sensor" + ohos_unittest("sensor_test") { + module_out_path = module_output_path + sources = [ "sensor_test.cpp" ] + include_dirs = [ + "//drivers/hdf_core/framework/include/platform", + "//drivers/peripheral/sensor/interfaces/include", + ] + deps = [ "//drivers/peripheral/sensor/hal:hdi_sensor" ] + + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + ] + + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-Wno-format", + "-Wno-format-extra-args", + ] + + install_enable = true + install_images = [ "vendor" ] + module_install_dir = "bin" + part_name = "unionman_products" + } + ``` diff --git a/zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md b/zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md index 346cd69b6cd714d4c1f1eecbd60353f5d37a3981..d3fa2edb1e417c1a54b3985fddc118b2837fefaa 100755 --- a/zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md @@ -40,7 +40,7 @@ ![Vibrator驱动运行图](figures/Vibrator驱动运行图.png) -以标准系统Hi3516DV300产品为例,介绍马达模块驱动加载及运行流程: +以标准系统RK3568产品为例,介绍马达模块驱动加载及运行流程: 1. Device Manager从device_info.hcs配置文件中读取Vibrator管理配置信息。 2. HCS Parser解析Vibrator管理配置信息,并加载对应的马达抽象驱动。 @@ -65,99 +65,28 @@ **表 1** 马达驱动模型对外API接口能力介绍 +注:以下接口列举的为C接口,接口声明见文件[/drivers/peripheral/vibrator/interfaces/include](https://gitee.com/openharmony/drivers_peripheral/tree/master/vibrator/interfaces/include)。 + | 接口名 | 功能描述 | | -------------------------------------- | ------------------------------------------------ | -| int32_t (*StartOnce)([in] uint32_t duration) | 控制马达以执行给定持续时间的单次振动,duration表示单次振动的持续时间。 | -| int32_t (*Start)([in] const char *effectType) | 控制马达以预置效果执行周期性振动,effectType表示指向预设效果类型的指针。 | -| int32_t (*Stop)([in] enum VibratorMode mode) | 停止马达振动,mode表示振动模式,可以是单次或周期性的。 | +| int32_t (*StartOnce)(uint32_t duration) | 控制马达以执行给定持续时间的单次振动,duration表示单次振动的持续时间。 | +| int32_t (*Start)(const char *effectType) | 控制马达以预置效果执行周期性振动,effectType表示指向预设效果类型的指针。 | +| int32_t (*Stop)(enum VibratorMode mode) | 停止马达振动,mode表示振动模式,可以是单次或周期性的。 | | int32_t (*EnableVibratorModulation)(uint32_t duration, int32_t intensity, int32_t frequency) | 根据传入的振动效果启动马达,duration表示马达振动的持续时间,intensity表示振动周期内的马达振幅,frequency表示振动周期内的马达频率。 | -| int32_t (*GetVibratorInfo)([out] struct VibratorInfo **vibratorInfo) | 获取系统中支持设置振幅和频率的所有马达信息,vibratorInfo表示指向马达信息的指针。 | +| int32_t (*GetVibratorInfo)(struct VibratorInfo **vibratorInfo) | 获取系统中支持设置振幅和频率的所有马达信息,vibratorInfo表示指向马达信息的指针。 | +| int32_t (*EnableCompositeEffect)(struct CompositeEffect *effect); | 控制马达以自定义复合效果进行周期性振动。 | +| int32_t (*GetEffectInfo)(const char *effectType, struct EffectInfo *effectInfo); | 获取指定效果类型的振动效果信息。 | +| int32_t (*IsVibratorRunning)(bool state); | 获取到的马达当前是否正在振动。 | ### 开发步骤 -Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能力接口,包括马达一次振动、马达效果配置震动、马达停止。基于HDF驱动框架开发的马达驱动模型,实现跨操作系统迁移、器件差异配置等功能。具体的开发步骤如下: - -1. 基于HDF驱动框架,按照驱动Driver Entry程序,完成马达抽象驱动开发(主要由Bind、Init、Release、Dispatch函数接口实现),配置资源和HCS解析。 - - - 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出马达驱动模型,使用HCS作为配置描述源码。HCS配置字段详细介绍参考[配置管理](driver-hdf-manage.md)。其中Driver Entry入口函数定义如下: - - ```c - /* 注册马达抽象驱动入口数据结构体对象 */ - struct HdfDriverEntry g_vibratorDriverEntry = { - .moduleVersion = 1, // 马达模块版本号 - .moduleName = "HDF_VIBRATOR", // 马达模块名,要与device_info.hcs文件里的马达moduleName字段值一样 - .Bind = BindVibratorDriver, // 马达绑定函数 - .Init = InitVibratorDriver, // 马达初始化函数 - .Release = ReleaseVibratorDriver, // 马达资源释放函数 - }; - /* 调用HDF_INIT将驱动入口注册到HDF框架中 */ - HDF_INIT(g_vibratorDriverEntry); - ``` - - - 基于HDF驱动框架,按照驱动Driver Entry程序,完成马达抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 - - ```c - /* 马达驱动对外发布的能力 */ - static int32_t DispatchVibrator(struct HdfDeviceIoClient *client, - int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) - { - int32_t loop; - - for (loop = 0; loop < sizeof(g_vibratorCmdHandle) / sizeof(g_vibratorCmdHandle[0]); ++loop) { - if ((cmd == g_vibratorCmdHandle[loop].cmd) && (g_vibratorCmdHandle[loop].func != NULL)) { - return g_vibratorCmdHandle[loop].func(data, reply); - } - } - - return HDF_SUCCESS; - } - - /* 马达驱动对外提供的服务绑定到HDF框架 */ - int32_t BindVibratorDriver(struct HdfDeviceObject *device) - { - struct VibratorDriverData *drvData = NULL; - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); - - drvData = (struct VibratorDriverData *)OsalMemCalloc(sizeof(*drvData)); - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); - - drvData->ioService.Dispatch = DispatchVibrator; - drvData->device = device; - device->service = &drvData->ioService; - g_vibratorDrvData = drvData; - - return HDF_SUCCESS; - } - - /* 马达驱动初始化入口函数*/ - int32_t InitVibratorDriver(struct HdfDeviceObject *device) - { - struct VibratorDriverData *drvData = NULL; - - drvData->mode = VIBRATOR_MODE_BUTT; - drvData->state = VIBRATOR_STATE_IDLE; - ...... - if (CreateVibratorHaptic(device) != HDF_SUCCESS) { - HDF_LOGE("%s: init workQueue failed!", __func__); - return HDF_FAILURE; - } +Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能力接口,包括马达一次振动、马达效果配置震动、马达停止。基于HDF驱动框架开发的马达驱动模型,实现跨操作系统迁移、器件差异配置等功能。以线性马达驱动为例介绍马达驱动开发。 - return HDF_SUCCESS; - } +1. 开发马达抽象驱动。 - /* 释放马达驱动初始化时分配的资源 */ - void ReleaseVibratorDriver(struct HdfDeviceObject *device) - { - struct VibratorDriverData *drvData = NULL; - ...... - (void)DestroyVibratorHaptic(); - (void)OsalMutexDestroy(&drvData->mutex); - (void)OsalMemFree(drvData); - g_vibratorDrvData = NULL; - } - ``` + - 马达抽象驱动在Vibrator Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。 - - 在系统启动过程中,HDF设备管理模块通过设备HCS配置信息,加载马达抽象驱动,并对外发布马达驱动接口。 + 具体代码实现如下: ```c /* 马达设备HCS配置 */ @@ -165,9 +94,9 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 hostName = "vibrator_host"; device_vibrator :: device { device0 :: deviceNode { - policy = 2; // 驱动服务发布的策略 + policy = 2; // 驱动服务发布的策略 priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议配置100,优先级相同则不保证device的加载顺序 - preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 + preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 permission = 0664; // 驱动创建设备节点权限 moduleName = "HDF_VIBRATOR"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 serviceName = "hdf_misc_vibrator"; // 驱动对外发布服务的名称,必须唯一 @@ -177,12 +106,12 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 } ``` -2. 创建马达效果模型,解析马达效果HCS配置。 + - 创建马达效果模型,解析马达效果HCS配置,代码实现路径:drivers\hdf_core\framework\model\misc\vibrator\driver\src\vibrator_haptic.c。 - - 创建马达效果模型。 + 具体代码实现如下: ```c - /* 创建马达效果模型,分配资源,解析马达效果HCS配置 */ + /* 创建马达效果模型 */ int32_t CreateVibratorHaptic(struct HdfDeviceObject *device) { struct VibratorHapticData *hapticData = NULL; @@ -194,15 +123,15 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 hapticData->supportHaptic = false; if (OsalMutexInit(&hapticData->mutex) != HDF_SUCCESS) { - HDF_LOGE("%s: failed to init mutex", __func__); + HDF_LOGE("%s: fail to init mutex", __func__); goto EXIT; } DListHeadInit(&hapticData->effectSeqHead); - /* 解析马达效果HCS配置 */ + // get haptic hcs if (ParserVibratorHapticConfig(device->property) != HDF_SUCCESS) { - HDF_LOGE("%s: parser haptic config failed!", __func__); + HDF_LOGE("%s: parser haptic config fail!", __func__); goto EXIT; } @@ -213,352 +142,728 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 } ``` - - 马达效果模型使用HCS作为配置描述源码,HCS配置文件字段详细介绍参考[配置管理](driver-hdf-manage.md)。 + - 马达抽象驱动代码实现路径:drivers\hdf_core\framework\model\misc\vibrator\driver\src\vibrator_driver.c。 + + - 马达抽象驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下: + + ```c + /* 注册马达抽象驱动入口数据结构体对象 */ + struct HdfDriverEntry g_vibratorDriverEntry = { + .moduleVersion = 1, // 马达模块版本号 + .moduleName = "HDF_VIBRATOR", // 马达模块名,要与device_info.hcs文件里的马达moduleName字段值一样 + .Bind = BindVibratorDriver, // 马达绑定函数 + .Init = InitVibratorDriver, // 马达初始化函数 + .Release = ReleaseVibratorDriver, // 马达资源释放函数 + }; + /* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出马达驱动模型 */ + HDF_INIT(g_vibratorDriverEntry); + ``` + + - 马达抽象驱动Bind接口实现如下: + + ```c + int32_t BindVibratorDriver(struct HdfDeviceObject *device) + { + struct VibratorDriverData *drvData = NULL; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + + drvData = (struct VibratorDriverData *)OsalMemCalloc(sizeof(*drvData)); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); + + drvData->ioService.Dispatch = DispatchVibrator; + drvData->device = device; + device->service = &drvData->ioService; + g_vibratorDrvData = drvData; + + return HDF_SUCCESS; + } + ``` + + - 马达抽象驱动Init接口实现如下: + + ```c + int32_t InitVibratorDriver(struct HdfDeviceObject *device) + { + struct VibratorDriverData *drvData = NULL; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + drvData = (struct VibratorDriverData *)device->service; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + drvData->mode = VIBRATOR_MODE_BUTT; + drvData->state = VIBRATOR_STATE_IDLE; + + if (OsalMutexInit(&drvData->mutex) != HDF_SUCCESS) { + HDF_LOGE("%s: init mutex failed!", __func__); + return HDF_FAILURE; + } + /* 工作队列资源初始化 */ + if (HdfWorkQueueInit(&drvData->workQueue, VIBRATOR_WORK_QUEUE_NAME) != HDF_SUCCESS) { + HDF_LOGE("%s: init workQueue failed!", __func__); + return HDF_FAILURE; + } + + if (HdfWorkInit(&drvData->work, VibratorWorkEntry, (void*)drvData) != HDF_SUCCESS) { + HDF_LOGE("%s: init workQueue failed!", __func__); + return HDF_FAILURE; + } + /* 创建马达效果模型初始化 */ + if (CreateVibratorHaptic(device) != HDF_SUCCESS) { + HDF_LOGE("%s: create vibrator haptic failed!", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; + } + ``` + + - 马达抽象驱动Release接口在驱动卸载或者Init执行失败时,会调用此接口释放资源,具体实现如下: + + ```c + void ReleaseVibratorDriver(struct HdfDeviceObject *device) + { + struct VibratorDriverData *drvData = NULL; + + if (device == NULL) { + HDF_LOGE("%s: device is null!", __func__); + return; + } + + drvData = (struct VibratorDriverData *)device->service; + if (drvData == NULL) { + HDF_LOGE("%s: drvData is null!", __func__); + return; + } + + (void)DestroyVibratorHaptic(); + (void)OsalMutexDestroy(&drvData->mutex); + OsalMemFree(drvData); + g_vibratorDrvData = NULL; + } + ``` + + - 马达抽象驱动内部接口实现了马达信息获取、振动模式设置和停止等功能,并实现根据振动模式创建和销毁定时器。 + + - 马达抽象驱动StartOnce接口实现如下: + + ```c + /* 按照指定持续时间触发振动马达,duration为振动持续时长 */ + static int32_t StartOnce(struct HdfSBuf *data, struct HdfSBuf *reply) + { + uint32_t duration; + int32_t ret; + struct VibratorEffectCfg config; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + (void)reply; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(data, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (!HdfSbufReadUint32(data, &duration)) { + HDF_LOGE("%s: sbuf read duration failed!", __func__); + return HDF_FAILURE; + } + + if (duration == 0) { + HDF_LOGE("%s: vibrator duration invalid para!", __func__); + return HDF_ERR_INVALID_PARAM; + } + + if (drvData->mode != VIBRATOR_MODE_BUTT) { + HDF_LOGI("%s: vibrater haptic is busy now, please stop first!", __func__); + return HDF_ERR_DEVICE_BUSY; + } + + (void)OsalMutexLock(&drvData->mutex); + drvData->mode = VIBRATOR_MODE_ONCE; + (void)OsalMutexUnlock(&drvData->mutex); + + config.cfgMode = VIBRATOR_MODE_ONCE; + config.duration = duration; + config.effect = NULL; + /* 根据振动效果的模式开启马达效果模型 */ + ret = StartHaptic(&config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: start haptic failed!", __func__); + return ret; + } + + return HDF_SUCCESS; + } + ``` + + - 马达抽象驱动StartEffect接口实现如下: + + ```c + /* 按照预置效果启动马达,effect表示预置的振动效果 */ + static int32_t StartEffect(struct HdfSBuf *data, struct HdfSBuf *reply) + { + int32_t ret; + const char *effect = NULL; + struct VibratorEffectCfg config; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + (void)reply; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(data, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + /* 从HdfSBuf中读取出预置的振动效果,进而操作马达振动 */ + effect = HdfSbufReadString(data); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(effect, HDF_FAILURE); + + if (drvData->mode != VIBRATOR_MODE_BUTT) { + HDF_LOGI("%s: vibrater haptic is busy now, please stop first!", __func__); + return HDF_ERR_DEVICE_BUSY; + } + + (void)OsalMutexLock(&drvData->mutex); + drvData->mode = VIBRATOR_MODE_PRESET; + (void)OsalMutexUnlock(&drvData->mutex); + + // start once time vibrate + config.cfgMode = VIBRATOR_MODE_PRESET; + config.duration = 0; + config.effect = effect; + /* 预置效果启动马达 */ + ret = StartHaptic(&config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: start haptic failed!", __func__); + return ret; + } + + return HDF_SUCCESS; + } + ``` + + - 马达抽象驱动Stop接口实现如下: + + ```c + /* 按照指定的振动模式停止马达振动 */ + static int32_t Stop(struct HdfSBuf *data, struct HdfSBuf *reply) + { + int32_t ret; + int32_t mode; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + (void)reply; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(data, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + /* 从HdfSBuf中读取指定的振动模式,进而操作马达停止振动 */ + if (!HdfSbufReadInt32(data, &mode)) { + HDF_LOGE("%s: sbuf read mode failed!", __func__); + return HDF_FAILURE; + } + + if ((mode != VIBRATOR_MODE_ONCE) && (mode != VIBRATOR_MODE_PRESET)) { + HDF_LOGE("%s: vibrator stop mode failed!", __func__); + return HDF_FAILURE; + } + + if (drvData->mode == VIBRATOR_MODE_BUTT) { + HDF_LOGD("%s: vibrater haptic had stopped!", __func__); + return HDF_SUCCESS; + } + /* 停止马达效果振动,销毁马达定时器 */ + ret = StopHaptic(); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: stop haptic failed!", __func__); + return ret; + } + + (void)OsalMutexLock(&drvData->mutex); + drvData->mode = VIBRATOR_MODE_BUTT; + (void)OsalMutexUnlock(&drvData->mutex); + + return HDF_SUCCESS; + } + ``` + + - 马达抽象驱动GetVibratorInfo接口实现如下: + + ```c + /* 获取马达信息,包括是否支持振幅和频率的设置及振幅和频率的设置范围 */ + static int32_t GetVibratorInfo(struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)data; + struct VibratorDriverData *drvData; + + drvData = GetVibratorDrvData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM); + + if (!HdfSbufWriteBuffer(reply, &drvData->vibratorInfo, sizeof(drvData->vibratorInfo))) { + HDF_LOGE("%s: write sbuf failed!", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; + } + ``` + + - 马达抽象驱动EnableModulationParameter接口实现如下: + + ```c + /* 按照指定振幅、频率、持续时间触发振动马达。duration为振动持续时长,intensity为振动强度,frequency为振动频率 */ + static int32_t EnableModulationParameter(struct HdfSBuf *data, struct HdfSBuf *reply) + { + (void)reply; + struct VibratorEffectCfg config; + struct VibratorDriverData *drvData; + uint32_t duration; + uint16_t intensity; + int16_t frequency; + int32_t ret; + + drvData = GetVibratorDrvData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData->ops.SetParameter, HDF_ERR_INVALID_PARAM); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM); + + if (drvData->mode != VIBRATOR_MODE_BUTT) { + HDF_LOGE("%s: vibrater is busy now, please stop first!", __func__); + return HDF_ERR_DEVICE_BUSY; + } + + if (!HdfSbufReadUint32(data, &duration)) { + HDF_LOGE("%s: sbuf read vibration period failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadUint16(data, &intensity)) { + HDF_LOGE("%s: sbuf read intensity failed!", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadInt16(data, &frequency)) { + HDF_LOGE("%s: sbuf read frequency failed!", __func__); + return HDF_FAILURE; + } + + (void)OsalMutexLock(&drvData->mutex); + drvData->mode = VIBRATOR_MODE_ONCE; + (void)OsalMutexUnlock(&drvData->mutex); + + ret = drvData->ops.SetParameter(intensity, frequency); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: set parameter failed!", __func__); + return HDF_FAILURE; + } + + config.cfgMode = VIBRATOR_MODE_ONCE; + config.duration = duration; + config.effect = NULL; + /* 预置效果启动马达 */ + ret = StartHaptic(&config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: start haptic failed!", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; + } + ``` + + - 在马达差异化器件驱动初始化成功时,注册差异化接口,方便实现马达器件差异化驱动接口,具体实现如下: + + ```c + /* 注册马达差异化实现接口 */ + int32_t RegisterVibrator(struct VibratorOps *ops) + { + struct VibratorDriverData *drvData = GetVibratorDrvData(); + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(ops, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + (void)OsalMutexLock(&drvData->mutex); + drvData->ops.Start = ops->Start; + drvData->ops.StartEffect = ops->StartEffect; + drvData->ops.Stop = ops->Stop; + drvData->ops.SetParameter = ops->SetParameter; + (void)OsalMutexUnlock(&drvData->mutex); + + return HDF_SUCCESS; + } + + /* 注册马达信息接口 */ + int32_t RegisterVibratorInfo(struct VibratorInfo *vibratorInfo) + { + struct VibratorDriverData *drvData = GetVibratorDrvData(); + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(vibratorInfo, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + (void)OsalMutexLock(&drvData->mutex); + if (memcpy_s(&drvData->vibratorInfo, sizeof(drvData->vibratorInfo), vibratorInfo, sizeof(*vibratorInfo)) != EOK) { + HDF_LOGE("%s: Memcpy vibrator config failed", __func__); + return HDF_FAILURE; + } + (void)OsalMutexUnlock(&drvData->mutex); + + return HDF_SUCCESS; + } + ``` + +1. 开发马达差异化驱动。 + + - 马达差异化驱动在Vibrator Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。 + + 具体代码实现如下: ```c - /* 马达数据配置模板(vibrator_config.hcs) */ - root { - vibratorConfig { - boardConfig { - match_attr = "hdf_vibrator_driver"; // 需要和马达设备配置文件中的match_attr字段保持一致 - vibratorAttr { - /* 0:转子;1:线性 */ - deviceType = 1; // 设备类型 - supportPreset = 1; // 支持的预设类型 - } - vibratorHapticConfig { - haptic_clock_timer { - effectName = "haptic.clock.timer"; - type = 1; // 0:内置模式;1:时间序列 - seq = [600, 600, 200, 600]; // 时间序列 - } - haptic_default_effect { - effectName = "haptic.default.effect"; - type = 0; - seq = [0, 3, 800, 1]; - } - } - } + device_linear_vibrator :: device { + device0 :: deviceNode { + policy = 1; // 驱动服务发布的策略 + priority = 105; // 驱动启动优先级(0-200),值越大优先级越低,建议配置100,优先级相同则不保证device的加载顺序 + preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 + permission = 0664; // 驱动创建设备节点权限 + moduleName = "HDF_LINEAR_VIBRATOR"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "hdf_misc_linear_vibrator"; // 线性马达对外发布服务的名称,必须唯一 + deviceMatchAttr = "hdf_linear_vibrator_driver"; // 马达差异化驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 } } ``` -3. 完成马达信息获取、振动模式设置和停止的接口开发,并实现根据振动模式创建和销毁定时器。 - - 马达硬件服务调用StartOnce接口动态配置持续振动时间,调用StartEffect接口启动静态配置的振动效果,为驱动开发者提供抽象的配置接口能力。 - - ```c - /* 按照指定持续时间触发振动马达,duration为振动持续时长。 */ - static int32_t StartOnce(struct HdfSBuf *data, struct HdfSBuf *reply) - { - uint32_t duration; - int32_t ret; - struct VibratorEffectCfg config; - struct VibratorDriverData *drvData = GetVibratorDrvData(); - (void)reply; - ...... - config.cfgMode = VIBRATOR_MODE_ONCE; - config.duration = duration; - config.effect = NULL; - /* 根据振动效果的模式创建定时器 */ - ret = StartHaptic(&config); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: start haptic failed!", __func__); - return ret; + - 马达差异化驱动私有HCS配置: + + - 代码实现路径:vendor\hihope\rk3568\hdf_config\khdf\vibrator\linear_vibrator_config.hcs。 + + - 具体代码实现如下: + + ```c + root { + linearVibratorConfig { + boardConfig { + match_attr = "hdf_linear_vibrator_driver"; // 需要和马达设备配置文件中的match_attr字段保持一致 + VibratorBusConfig { + busType = 1; // 0:i2c 1:gpio + busNum = 154; + } + VibratorChipConfig { + isSupportIntensity = 0; // 设置马达振幅能力。1表示支持,0表示不支持。 + isSupportFrequency = 0; // 设置马达振动频率能力。1表示支持,0表示不支持。 + intensityMaxValue = 0; // 马达振动支持的最大振幅 + intensityMinValue = 0; // 马达振动支持的最小振幅 + frequencyMaxValue = 0; // 马达振动支持的最大频率 + frequencyMinValue = 0; // 马达振动支持的最小频率 + } + } + } } - - return HDF_SUCCESS; - } - - /* 按照预置效果启动马达,effectType表示预置的振动效果。 */ - static int32_t StartEffect(struct HdfSBuf *data, struct HdfSBuf *reply) - { - int32_t ret; - const char *effect = NULL; - struct VibratorEffectCfg config; - struct VibratorDriverData *drvData = GetVibratorDrvData(); - (void)reply; - ...... - config.cfgMode = VIBRATOR_MODE_PRESET; - config.duration = 0; - config.effect = effect; - - ret = StartHaptic(&config); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: start haptic failed!", __func__); - return ret; + ``` + + - 马达差异化驱动代码实现路径为:drivers\peripheral\vibrator\chipset\linear\vibrator_linear_driver.c。 + + - 马达差异化驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下: + + ```c + struct HdfDriverEntry g_linearVibratorDriverEntry = { + .moduleVersion = 1, + .moduleName = "HDF_LINEAR_VIBRATOR", + .Bind = BindLinearVibratorDriver, + .Init = InitLinearVibratorDriver, + .Release = ReleaseLinearVibratorDriver, + }; + + HDF_INIT(g_linearVibratorDriverEntry); + ``` + + - 马达差异化驱动Bind接口实现如下: + + ```c + int32_t BindLinearVibratorDriver(struct HdfDeviceObject *device) + { + struct VibratorLinearDriverData *drvData = NULL; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + + drvData = (struct VibratorLinearDriverData *)OsalMemCalloc(sizeof(*drvData)); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); + + drvData->ioService.Dispatch = DispatchLinearVibrator; + drvData->device = device; + device->service = &drvData->ioService; + g_linearVibratorData = drvData; + + return HDF_SUCCESS; } - - return HDF_SUCCESS; - } - - /* 按照指定的振动模式停止马达振动 */ - static int32_t Stop(struct HdfSBuf *data, struct HdfSBuf *reply) - { - int32_t ret; - int32_t mode; - struct VibratorDriverData *drvData = GetVibratorDrvData(); - (void)reply; - ...... - /* 停止马达效果振动,销毁马达定时器。 */ - ret = StopHaptic(); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: stop haptic failed!", __func__); - return ret; + ``` + + - 马达差异化驱动Init接口实现如下: + + ```c + int32_t InitLinearVibratorDriver(struct HdfDeviceObject *device) + { + static struct VibratorOps ops; + struct VibratorLinearDriverData *drvData = NULL; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + + drvData = (struct VibratorLinearDriverData *)device->service; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + ops.Start = StartLinearVibrator; + ops.StartEffect = StartEffectLinearVibrator; + ops.Stop = StopLinearVibrator; + ops.SetParameter = NULL; + + if (RegisterVibratorOps(&ops) != HDF_SUCCESS) { + HDF_LOGE("%s: register vibrator ops fail", __func__); + return HDF_FAILURE; + } + + drvData->linearCfgData = (struct VibratorCfgData *)OsalMemCalloc(sizeof(*drvData->linearCfgData)); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData->linearCfgData, HDF_ERR_MALLOC_FAIL); + /* 解析马达寄存器初始化 */ + if (GetVibratorBaseConfigData(device->property, drvData->linearCfgData) != HDF_SUCCESS) { + HDF_LOGE("%s: parser vibrator cfg fail", __func__); + return HDF_FAILURE; + } + /* 注册马达Info信息初始化 */ + if (RegisterVibratorInfo(&drvData->linearCfgData->vibratorInfo) != HDF_SUCCESS) { + HDF_LOGE("%s: register vibrator info fail", __func__); + return HDF_FAILURE; + } + + if (GpioSetDir(drvData->linearCfgData->vibratorBus.GpioNum, GPIO_DIR_OUT) != HDF_SUCCESS) { + HDF_LOGE("%s: set vibrator gpio fail", __func__); + return HDF_FAILURE; + } + return HDF_SUCCESS; } - - (void)OsalMutexLock(&drvData->mutex); - drvData->mode = VIBRATOR_MODE_BUTT; - (void)OsalMutexUnlock(&drvData->mutex); - - return HDF_SUCCESS; - } - - /* 按照指定振幅、频率、持续时间触发振动马达。duration为振动持续时长,intensity为振动强度,frequency为振动频率。 */ - static int32_t EnableModulationParameter(struct HdfSBuf *data, struct HdfSBuf *reply) - { - (void)reply; - struct VibratorEffectCfg config; - struct VibratorDriverData *drvData; - uint32_t duration; - int32_t intensity; - int32_t frequency; - int32_t ret; - ..... - (void)OsalMutexLock(&drvData->mutex); - drvData->mode = VIBRATOR_MODE_ONCE; - (void)OsalMutexUnlock(&drvData->mutex); - /* 设置振幅和频率 */ - ret = drvData->ops.SetParameter(intensity, frequency); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: set parameter failed", __func__); - return HDF_FAILURE; + ``` + + - 马达差异化驱动Release接口实现如下: + + ```c + void ReleaseLinearVibratorDriver(struct HdfDeviceObject *device) + { + struct VibratorLinearDriverData *drvData = NULL; + + if (device == NULL) { + HDF_LOGE("%s: Device is null", __func__); + return; + } + drvData = (struct VibratorLinearDriverData *)device->service; + if (drvData == NULL) { + HDF_LOGE("%s: DrvData pointer is null", __func__); + return; + } + + OsalMemFree(drvData->linearCfgData); + OsalMemFree(drvData); + g_linearVibratorData = NULL; } - - config.cfgMode = VIBRATOR_MODE_ONCE; - config.duration = duration; - config.effect = NULL; - - ret = StartHaptic(&config); - if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: start haptic failed", __func__); - return HDF_FAILURE; + ``` + + - 马达差异化驱动内部接口实现如下: + + ```c + /* 触发振动马达 */ + static int32_t StartLinearVibrator(void) + { + int32_t ret; + struct VibratorLinearDriverData *drvData = GetLinearVibratorData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (drvData->linearCfgData->vibratorBus.busType != VIBRATOR_BUS_GPIO) { + HDF_LOGE("%s: vibrator bus type not gpio", __func__); + return HDF_FAILURE; + } + + ret = GpioWrite(drvData->linearCfgData->vibratorBus.GpioNum, GPIO_VAL_HIGH); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, + drvData->linearCfgData->vibratorBus.GpioNum, GPIO_VAL_HIGH); + return ret; + } + return HDF_SUCCESS; } - - return HDF_SUCCESS; - } - - /* 获取马达信息,包括是否支持振幅和频率的设置及振幅和频率的设置范围。 */ - static int32_t GetVibratorInfo(struct HdfSBuf *data, struct HdfSBuf *reply) - { - (void)data; - struct VibratorDriverData *drvData; - - drvData = GetVibratorDrvData(); - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM); - - if (!HdfSbufWriteBuffer(reply, &drvData->vibratorInfo, sizeof(drvData->vibratorInfo))) { - HDF_LOGE("%s: write sbuf failed", __func__); - return HDF_FAILURE; + /* 按照指定效果触发振动马达 */ + static int32_t StartEffectLinearVibrator(uint32_t effectType) + { + (void)effectType; + HDF_LOGE("%s: vibrator set built-in effect no support!", __func__); + return HDF_SUCCESS; } - - return HDF_SUCCESS; - } - ``` - -4. 马达驱动模型提供给开发者马达驱动差异化接口,开发者实现差异化接口。 - - - 在差异化器件驱动初始化成功时,注册差异实现接口,方便实现器件差异的驱动接口。 - - ```c - /* 注册马达差异化实现接口 */ - int32_t RegisterVibrator(struct VibratorOps *ops) - { - struct VibratorDriverData *drvData = GetVibratorDrvData(); - - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(ops, HDF_FAILURE); - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); - - (void)OsalMutexLock(&drvData->mutex); - drvData->ops.Start = ops->Start; - drvData->ops.StartEffect = ops->StartEffect; - drvData->ops.Stop = ops->Stop; - drvData->ops.SetParameter = ops->SetParameter; - (void)OsalMutexUnlock(&drvData->mutex); - - return HDF_SUCCESS; - } - - /* 注册马达信息接口 */ - int32_t RegisterVibratorInfo(struct VibratorInfo *vibratorInfo) - { - struct VibratorDriverData *drvData = GetVibratorDrvData(); - - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(vibratorInfo, HDF_FAILURE); - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); - - (void)OsalMutexLock(&drvData->mutex); - if (memcpy_s(&drvData->vibratorInfo, sizeof(drvData->vibratorInfo), vibratorInfo, sizeof(*vibratorInfo)) != EOK) { - HDF_LOGE("%s: Memcpy vibrator config failed", __func__); - return HDF_FAILURE; - } - (void)OsalMutexUnlock(&drvData->mutex); - - return HDF_SUCCESS; - } - ``` + /* 停止振动马达 */ + static int32_t StopLinearVibrator(void) + { + int32_t ret; + struct VibratorLinearDriverData *drvData = GetLinearVibratorData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (drvData->linearCfgData->vibratorBus.busType != VIBRATOR_BUS_GPIO) { + HDF_LOGE("%s: vibrator bus type not gpio", __func__); + return HDF_FAILURE; + } + + ret = GpioWrite(drvData->linearCfgData->vibratorBus.GpioNum, GPIO_VAL_LOW); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, + drvData->linearCfgData->vibratorBus.GpioNum, GPIO_VAL_LOW); + return ret; + } + return HDF_SUCCESS; + } + ``` - - - 马达驱动模型提供给开发者马达驱动差异化接口,具体实现如下: - - ```c - /* 按照指定的振动模式停止马达的振动 */ - static int32_t StopModulationParameter() - { - uint8_t value[DRV2605L_VALUE_BUTT]; - struct Drv2605lDriverData *drvData = NULL; - drvData = GetDrv2605lDrvData(); - - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData->drv2605lCfgData, HDF_FAILURE); - - value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_MODE; - value[DRV2605L_VALUE_INDEX] = (uint8_t)DRV2605_MODE_STANDBY; - if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { - HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]); - return HDF_FAILURE; - } - - value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_RTPIN; - value[DRV2605L_VALUE_INDEX] = (uint8_t)&drvData->drv2605lCfgData->vibratorAttr.defaultIntensity; - if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { - HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]); - } - - value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_LRARESON; - value[DRV2605L_VALUE_INDEX] = (uint8_t)&drvData->drv2605lCfgData->vibratorAttr.defaultFrequency; - if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { - HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]); - } - - return HDF_SUCCESS; - } - - /* 设置马达振幅和频率 */ - static void SetModulationParameter(int32_t intensity, int32_t frequency) - { - uint8_t value[DRV2605L_VALUE_BUTT]; - struct Drv2605lDriverData *drvData = NULL; - drvData = GetDrv2605lDrvData(); - - CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); - - if (intensity != 0) { - value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_RTPIN; - value[DRV2605L_VALUE_INDEX] = (uint8_t)INTENSITY_MAPPING_VALUE(intensity); - if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { - HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]); - return; - } - } else { - HDF_LOGD("%s: the setting of intensity 0 is not supported and \ - will be set as the system default intensity", __func__); - } - - if (frequency != 0) { - value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_LRARESON; - value[DRV2605L_VALUE_INDEX] = (uint8_t)FREQUENCY_MAPPING_VALUE(frequency); - if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { - HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]); - return; - } - } else { - HDF_LOGD("%s: the setting of frequency 0 is not supported and \ - will be set as the system default frequency", __func__); - } - } - ``` ### 调测验证 驱动开发完成后,在马达单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。 -```c++ -/* 用例执行前,初始化马达接口实例。 */ -void HdfVibratorTest::SetUpTestCase() -{ - g_vibratorDev = NewVibratorInterfaceInstance(); -} -/* 用例资源释放 */ -void HdfVibratorTest::TearDownTestCase() -{ - if(g_vibratorDev != nullptr){ - FreeVibratorInterfaceInstance(); - g_vibratorDev = nullptr; - } -} - -/* 测试单次振动 */ -HWTEST_F(HdfVibratorTest, PerformOneShotVibratorDuration_001, TestSize.Level1) -{ - ASSERT_NE(nullptr, g_vibratorDev); - - int32_t startRet = g_vibratorDev->StartOnce(g_duration); - EXPECT_EQ(startRet, HDF_SUCCESS); - - OsalMSleep(g_sleepTime1); - - int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE); - EXPECT_EQ(endRet, HDF_SUCCESS); -} -/* 测试预置效果振动 */ -HWTEST_F(HdfVibratorTest, ExecuteVibratorEffect_002, TestSize.Level1) -{ - ASSERT_NE(nullptr, g_vibratorDev); - - int32_t startRet = g_vibratorDev->Start(g_builtIn); - EXPECT_EQ(startRet, HDF_SUCCESS); - - OsalMSleep(g_sleepTime1); - - int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_PRESET); - EXPECT_EQ(endRet, HDF_SUCCESS); -} -/* 获取马达信息,包括是否支持振幅和频率的设置及振幅和频率的设置范围。 */ -HWTEST_F(HdfVibratorTest, GetVibratorInfo_001, TestSize.Level1) -{ - ASSERT_NE(nullptr, g_vibratorDev); - - int32_t startRet = g_vibratorDev->GetVibratorInfo(&g_vibratorInfo); - EXPECT_EQ(startRet, HDF_SUCCESS); - EXPECT_NE(g_vibratorInfo, nullptr); - - printf("intensity = %d, intensityMaxValue = %d, intensityMinValue = %d\n\t", - g_vibratorInfo->isSupportIntensity, g_vibratorInfo->intensityMaxValue, g_vibratorInfo->intensityMinValue); - printf("frequency = %d, frequencyMaxValue = %d, frequencyMinValue = %d\n\t", - g_vibratorInfo->isSupportFrequency, g_vibratorInfo->frequencyMaxValue, g_vibratorInfo->frequencyMinValue); -} -/* 按照指定振幅、频率、持续时间触发振动马达。duration为振动持续时长,intensity为振动强度,frequency为振动频率。 */ -HWTEST_F(HdfVibratorTest, EnableVibratorModulation_001, TestSize.Level1) -{ - int32_t startRet; - ASSERT_NE(nullptr, g_vibratorDev); - EXPECT_GT(g_duration, 0); - - if ((g_vibratorInfo->isSupportIntensity == 1) || (g_vibratorInfo->isSupportFrequency == 1)) { - EXPECT_GE(g_intensity1, g_vibratorInfo->intensityMinValue); - EXPECT_LE(g_intensity1, g_vibratorInfo->intensityMaxValue); - EXPECT_GE(g_frequency1, g_vibratorInfo->frequencyMinValue); - EXPECT_LE(g_frequency1, g_vibratorInfo->frequencyMaxValue); - - startRet = g_vibratorDev->EnableVibratorModulation(g_duration, g_intensity1, g_frequency1); - EXPECT_EQ(startRet, HDF_SUCCESS); - OsalMSleep(g_sleepTime1); - startRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE); - EXPECT_EQ(startRet, HDF_SUCCESS); - } -} -``` +- 参考测试代码如下: + + ```c + #include + #include + #include + #include + #include "hdf_base.h" + #include "osal_time.h" + #include "vibrator_if.h" + #include "vibrator_type.h" + + using namespace testing::ext; + const struct VibratorInterface *g_vibratorDev = nullptr; + static struct VibratorInfo *g_vibratorInfo = nullptr; + + class HdfVibratorTest : public testing::Test { + public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + }; + /* 用例执行前,初始化马达接口实例。 */ + void HdfVibratorTest::SetUpTestCase() + { + g_vibratorDev = NewVibratorInterfaceInstance(); + } + /* 用例资源释放 */ + void HdfVibratorTest::TearDownTestCase() + { + if(g_vibratorDev != nullptr){ + FreeVibratorInterfaceInstance(); + g_vibratorDev = nullptr; + } + } + + void HdfVibratorTest::SetUp() + { + } + + void HdfVibratorTest::TearDown() + { + } + + /* 测试单次振动 */ + HWTEST_F(HdfVibratorTest, PerformOneShotVibratorDuration_001, TestSize.Level1) + { + uint32_t duration = 1000; + uint32_t sleepTime = 2000; + + ASSERT_NE(nullptr, g_vibratorDev); + + int32_t startRet = g_vibratorDev->StartOnce(duration); + EXPECT_EQ(startRet, HDF_SUCCESS); + + OsalMSleep(sleepTime); + + int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE); + EXPECT_EQ(endRet, HDF_SUCCESS); + } + /* 测试预置效果振动 */ + HWTEST_F(HdfVibratorTest, ExecuteVibratorEffect_001, TestSize.Level1) + { + uint32_t sleepTime = 5000; + const char *timeSequence = "haptic.clock.timer"; + + ASSERT_NE(nullptr, g_vibratorDev); + + int32_t startRet = g_vibratorDev->Start(timeSequence); + EXPECT_EQ(startRet, HDF_SUCCESS); + + OsalMSleep(sleepTime); + + int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_PRESET); + EXPECT_EQ(endRet, HDF_SUCCESS); + } + /* 获取马达信息,包括是否支持振幅和频率的设置及振幅和频率的设置范围。 */ + HWTEST_F(HdfVibratorTest, GetVibratorInfo_001, TestSize.Level1) + { + ASSERT_NE(nullptr, g_vibratorDev); + + int32_t startRet = g_vibratorDev->GetVibratorInfo(&g_vibratorInfo); + EXPECT_EQ(startRet, HDF_SUCCESS); + EXPECT_NE(g_vibratorInfo, nullptr); + + printf("intensity = %d, intensityMaxValue = %d, intensityMinValue = %d\n\t", + g_vibratorInfo->isSupportIntensity, g_vibratorInfo->intensityMaxValue, g_vibratorInfo->intensityMinValue); + printf("frequency = %d, frequencyMaxValue = %d, frequencyMinValue = %d\n\t", + g_vibratorInfo->isSupportFrequency, g_vibratorInfo->frequencyMaxValue, g_vibratorInfo->frequencyMinValue); + } + /* 按照指定振幅、频率、持续时间触发振动马达。duration为振动持续时长,intensity为振动强度,frequency为振动频率。 */ + HWTEST_F(HdfVibratorTest, EnableVibratorModulation_001, TestSize.Level1) + { + int32_t startRet; + int32_t intensity = 30; + int32_t frequency = 200; + uint32_t duration = 1000; + uint32_t sleepTime = 2000; + + ASSERT_NE(nullptr, g_vibratorDev); + + if ((g_vibratorInfo->isSupportIntensity == 1) || (g_vibratorInfo->isSupportFrequency == 1)) { + EXPECT_GE(intensity, g_vibratorInfo->intensityMinValue); + EXPECT_LE(intensity, g_vibratorInfo->intensityMaxValue); + EXPECT_GE(frequency, g_vibratorInfo->frequencyMinValue); + EXPECT_LE(frequency, g_vibratorInfo->frequencyMaxValue); + + startRet = g_vibratorDev->EnableVibratorModulation(duration, intensity, duration); + EXPECT_EQ(startRet, HDF_SUCCESS); + OsalMSleep(sleepTime); + startRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE); + EXPECT_EQ(startRet, HDF_SUCCESS); + } + } + ``` + +- 编译文件gn参考代码如下: + + ```c++ + import("//build/ohos.gni") + import("//build/test.gni") + import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni") + + module_output_path = "drivers_peripheral_vibrator/vibrator" + ohos_unittest("vibrator_test") { + module_out_path = module_output_path + sources = [ "vibrator_test.cpp" ] + include_dirs = [ + "//drivers/hdf_core/framework/include/platform", + "//drivers/peripheral/vibrator/interfaces/include", + ] + deps = [ "//drivers/peripheral/vibrator/hal:hdi_vibrator" ] + + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_utils", + "hiviewdfx_hilog_native:libhilog", + ] + + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-Wno-format", + "-Wno-format-extra-args", + ] + + install_enable = true + install_images = [ "vendor" ] + module_install_dir = "bin" + part_name = "unionman_products" + } + ```