未验证 提交 b3d55a03 编写于 作者: O openharmony_ci 提交者: Gitee

!19268 fix:modfiy light、sensor、motion and vibrator delvelop guide optimization

Merge pull request !19268 from sunxuejiao/master
...@@ -19,7 +19,7 @@ Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接 ...@@ -19,7 +19,7 @@ Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接
![Light驱动运行图](figures/Light驱动运行图.png) ![Light驱动运行图](figures/Light驱动运行图.png)
以标准系统Hi3516DV300为例,介绍Light模块驱动加载及运行流程: 以标准系统RK3568为例,介绍Light模块驱动加载及运行流程:
1. Device Manager从device_info.hcs配置文件中读取Light设备管理配置信息。 1. Device Manager从device_info.hcs配置文件中读取Light设备管理配置信息。
2. Device Manager从light_config.hcs配置文件中读取Light数据配置信息。 2. Device Manager从light_config.hcs配置文件中读取Light数据配置信息。
...@@ -40,17 +40,74 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模 ...@@ -40,17 +40,74 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模
**表1** Light驱动模型对外API接口能力介绍 **表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 (*GetLightInfo)(struct LightInfo **lightInfo, uint32_t *count) | 获取当前系统中所有类型的灯信息,lightInfo表示指向灯信息的二级指针,count表示指向灯数量的指针。 |
| int32_t (*TurnOnLight)([in] uint32_t lightId, [in] struct LightEffect *effect) | 根据指定的灯类型ID打开列表中的可用灯,lightId表示灯类型ID,effect表示指向灯效果的指针。 | | int32_t (*TurnOnLight)(uint32_t lightId, struct LightEffect *effect) | 根据指定的灯类型ID打开列表中的可用灯,lightId表示灯类型ID,effect表示指向灯效果的指针。 |
| int32_t (*TurnOffLight)([in] uint32_t lightId) | 根据指定的灯类型ID关闭列表中的可用灯。 | | 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。
- 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - 具体代码实现如下:
- Light驱动模型使用HCS配置文件作为配置描述源码。HCS配置字段详细介绍请参考[配置管理](driver-hdf-manage.md)。其Driver Entry入口函数定义如下:
```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。
- 灯驱动驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下:
```c ```c
/* 注册灯入口数据结构体对象 */ /* 注册灯入口数据结构体对象 */
...@@ -61,36 +118,13 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模 ...@@ -61,36 +118,13 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模
.Init = InitLightDriver, // 灯初始化函数 .Init = InitLightDriver, // 灯初始化函数
.Release = ReleaseLightDriver, // 灯资源释放函数 .Release = ReleaseLightDriver, // 灯资源释放函数
}; };
/* 调用HDF_INIT将驱动入口注册到HDF框架中 */ /* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
HDF_INIT(g_lightDriverEntry); HDF_INIT(g_lightDriverEntry);
``` ```
- 基于HDF驱动框架,按照驱动Driver Entry程序,完成Light抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 - 灯驱动Bind接口实现示例如下:
```c ```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框架 */ /* Light驱动对外提供的服务绑定到HDF框架 */
int32_t BindLightDriver(struct HdfDeviceObject *device) int32_t BindLightDriver(struct HdfDeviceObject *device)
{ {
...@@ -105,50 +139,61 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模 ...@@ -105,50 +139,61 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模
drvData->device = device; drvData->device = device;
device->service = &drvData->ioService; device->service = &drvData->ioService;
g_lightDrvData = drvData; g_lightDrvData = drvData;
return HDF_SUCCESS; return HDF_SUCCESS;
} }
```
- 灯驱动Init接口实现示例如下:
```c
/* Light驱动初始化入口函数*/ /* Light驱动初始化入口函数*/
int32_t InitLightDriver(struct HdfDeviceObject *device) 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) { if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) {
HDF_LOGE("%s: init workQueue fail!", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
/* 工作项初始化 */ /* 工作项初始化 */
if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) { if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) {
HDF_LOGE("%s: init work fail!", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
/* 解析HCS配置文件 */ /* 解析HCS配置文件 */
if (GetLightConfigData(device->property) != HDF_SUCCESS) { if (GetLightConfigData(device->property) != HDF_SUCCESS) {
HDF_LOGE("%s: get light config fail!", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
/* 设置GPIO引脚方向 */ /* 设置GPIO引脚方向 */
if (SetLightGpioDir(drvData) != HDF_SUCCESS) { if (SetLightGpioDir(drvData) != HDF_SUCCESS) {
HDF_LOGE("%s: set light gpio dir fail!", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
return HDF_SUCCESS; return HDF_SUCCESS;
} }
```
- 灯驱动Release接口在驱动卸载或者Init执行失败时,会调用此接口释放资源,具体实现如下:
```c
/* 释放Light驱动初始化时分配的资源 */ /* 释放Light驱动初始化时分配的资源 */
void ReleaseLightDriver(struct HdfDeviceObject *device) 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) { if (drvData->info[i] != NULL) {
OsalMemFree(drvData->info[i]); OsalMemFree(drvData->info[i]);
drvData->info[i] = NULL; drvData->info[i] = NULL;
} }
} }
/* 销毁工作队列资源 */ /* 器件在位,销毁工作队列资源 */
HdfWorkDestroy(&drvData->work); HdfWorkDestroy(&drvData->work);
HdfWorkQueueDestroy(&drvData->workQueue); HdfWorkQueueDestroy(&drvData->workQueue);
(void)OsalMutexDestroy(&drvData->mutex); (void)OsalMutexDestroy(&drvData->mutex);
...@@ -157,194 +202,584 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模 ...@@ -157,194 +202,584 @@ Light驱动模型支持获取系统中所有灯的信息、动态配置闪烁模
} }
``` ```
- Light设备管理模块负责系统中Light器件接口发布。在系统启动过程中,HDF框架机制通过Light Host里的设备HCS配置信息,加载设备管理驱动 - 灯驱动从HCS文件中解析Light设备管理配置信息
```c ```c
/* Light设备HCS配置 */ /* 从HCS文件中获取Light基础配置 */
light :: host { static int32_t GetLightBaseConfigData(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser,
hostName = "light_host"; uint32_t lightId)
device_light :: device { {
device0 :: deviceNode { int32_t ret;
policy = 2; // 驱动服务发布的策略(0:不提供服务,1:对内核态发布服务;2:对内核态和用户态都发布服务) uint32_t *defaultBrightness = NULL;
priority = 100; // Light驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 struct LightDriverData *drvData = NULL;
preload = 0; // 驱动按需加载字段,0:加载;2:不加载 const char *name = NULL;
permission = 0664; // 驱动创建设备节点权限
moduleName = "HDF_LIGHT"; // Light驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 drvData = GetLightDrvData();
serviceName = "hdf_light"; // Light驱动对外发布服务的名称,必须唯一 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
deviceMatchAttr = "hdf_light_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 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;
} }
``` ```
2. 调用配置解析接口,完成器件属性信息解析、器件寄存器解析,并注册到Light设备管理中。 - 分配资源,解析灯HCS配置信息实现如下:
```c ```c
/* 分配资源,解析灯HCS配置。 */ /* 分配资源,解析灯HCS配置 */
static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser) 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配置获取支持的灯类型个数 */ /* 从HCS配置获取支持的灯类型个数 */
drvData->lightNum = parser->GetElemNum(light, "lightId"); 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) { for (i = 0; i < drvData->lightNum; ++i) {
/* 获取灯的类型 */ /* 获取灯的类型 */
ret = parser->GetUint32ArrayElem(light, "lightId", i, &temp, 0); ret = parser->GetUint32ArrayElem(node, "lightId", i, &temp, 0);
CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId"); CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId");
}
for (i = 0; i < drvData->lightNum; ++i) { if (temp >= LIGHT_ID_BUTT) {
..... HDF_LOGE("%s: light id invalid para", __func__);
/* 类型作为下标开辟空间 */ return HDF_FAILURE;
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;
} }
ret = parser->GetUint32(node, "busBNum", (uint32_t *)&drvData->info[temp]->busBNum, 0);
ret = GetLightBaseConfigData(node, parser, temp);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
drvData->info[temp]->busBNum = LIGHT_INVALID_GPIO; HDF_LOGE("%s: get light base config fail", __func__);
return HDF_FAILURE;
} }
} }
.....
return HDF_SUCCESS; return HDF_SUCCESS;
} }
``` ```
3. 完成Light类型获取、闪烁模式设置和停止的接口开发,并实现根据闪烁模式创建和销毁定时器。 - 灯驱动的内部接口完成了灯类型获取、闪烁模式设置和停止的接口开发,并实现根据闪烁模式创建和销毁定时器。
- GetAllLightInfo接口实现如下:
```c ```c
/* Light驱动服务调用GetAllLightInfo接口获取灯类型,调用TurnOnLight接口启动闪烁模式, /* Light驱动服务调用GetAllLightInfo接口获取灯类型信息 */
调用TurnOffLight接口停止闪烁。 */
static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply) 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)) { if (!HdfSbufWriteUint32(reply, drvData->lightNum)) {
HDF_LOGE("%s: write sbuf fail", __func__); HDF_LOGE("%s: write sbuf failed", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
for (i = 0; i < LIGHT_TYPE_BUTT; ++i) {
for (i = 0; i < LIGHT_ID_BUTT; ++i) {
if (drvData->info[i] == NULL) { if (drvData->info[i] == NULL) {
continue; continue;
} }
lightInfo.lightId = i; lightInfo.lightId = i;
lightInfo.reserved = NULL;
/* 将Light设备信息填充进reply */ if (!HdfSbufWriteUint32(reply, lightInfo.lightId)) {
if (!HdfSbufWriteBuffer(reply, &lightInfo, sizeof(lightInfo))) { HDF_LOGE("%s: write lightId failed", __func__);
HDF_LOGE("%s: write sbuf fail", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
}
return HDF_SUCCESS; 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)) {
static int32_t UpdateLight(uint32_t lightId, uint32_t lightOn) HDF_LOGE("%s: write lightName failed", __func__);
{
.....
/* 如果用户传入的亮度值无效,则使用系统默认的亮度值。 */
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__);
return HDF_FAILURE; return HDF_FAILURE;
} }
}
/* 如果8-15bit不等于0,根据lightOn的状态,输出绿色对应的GPIO引脚。 */ lightInfo.lightNumber = drvData->info[i]->lightInfo.lightNumber;
if ((lightBrightness & LIGHT_MAKE_G_BIT) != 0) { if (!HdfSbufWriteUint32(reply, lightInfo.lightNumber)) {
ret = WriteGpio(drvData->info[lightId]->busGNum, lightOn); HDF_LOGE("%s: write lightNumber failed", __func__);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: write green gpio fail", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
}
/* 如果16-23bit不等于0,根据lightOn的状态,输出红色对应的GPIO引脚。 */ lightInfo.lightType = HDF_LIGHT_TYPE_RGB_COLOR;
if ((lightBrightness & LIGHT_MAKE_R_BIT) != 0) { if (!HdfSbufWriteUint32(reply, lightInfo.lightType)) {
ret = WriteGpio(drvData->info[lightId]->busRNum, lightOn); HDF_LOGE("%s: write lightType failed", __func__);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: write red gpio fail", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
} }
.....
return HDF_SUCCESS;
} }
```
- TurnOnLight接口的实现如下:
```c
/* 按照指定的类型和用户传入的参数使能灯 */ /* 按照指定的类型和用户传入的参数使能灯 */
static int32_t TurnOnLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) 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;
}
if (!HdfSbufReadBuffer(data, (const void **)&buf, &len)) {
HDF_LOGE("%s: light read data failed", __func__);
return HDF_FAILURE;
}
/* 接收用户传入的亮度值。24-31bit表示扩展位,16-23bit表示红色,8-15bit表示绿色,0-7bit表示蓝色。如果字段不等于0,表示使能相应颜色的灯。 /* 接收用户传入的亮度值。24-31bit表示扩展位,16-23bit表示红色,8-15bit表示绿色,0-7bit表示蓝色。如果字段不等于0,表示使能相应颜色的灯。
如果支持亮度设置,则通过0-255设置不同的亮度。 */ 如果支持亮度设置,则通过0-255设置不同的亮度。 */
drvData->info[lightId]->lightBrightness = buf->lightBrightness; if (buf->lightColor.colorValue.rgbColor.r != 0) {
drvData->info[lightId]->lightBrightness |= 0X00FF0000;
}
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) { if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) {
return UpdateLight(lightId, LIGHT_STATE_START); return UpdateLight(lightId, LIGHT_STATE_START);
} }
/* 闪烁模式 */ /* 闪烁模式 */
if (buf->flashEffect.flashMode == LIGHT_FLASH_TIMED) { if (buf->flashEffect.flashMode == LIGHT_FLASH_BLINK) {
drvData->info[lightId]->lightState = LIGHT_STATE_START; drvData->info[lightId]->onTime = (buf->flashEffect.onTime < drvData->info[lightId]->onTime) ?
/* 用户设置的闪烁时间小于系统支持的最短时间,采用系统配置的时间(HCS配置)。 */
drvData->info[lightId]->onTime = buf->flashEffect.onTime < drvData->info[lightId]->onTime ?
drvData->info[lightId]->onTime : buf->flashEffect.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 < drvData->info[lightId]->offTime) ?
drvData->info[lightId]->offTime : buf->flashEffect.offTime; drvData->info[lightId]->offTime : buf->flashEffect.offTime;
/* 创建定时器 */ /* 创建定时器 */
if (OsalTimerCreate(&drvData->timer, drvData->info[lightId]->onTime, if (OsalTimerCreate(&drvData->timer, LIGHT_WAIT_TIME, LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) {
LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) {
HDF_LOGE("%s: create light timer fail!", __func__); HDF_LOGE("%s: create light timer fail!", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
/* 启动周期定时器 */ /* 启动定时器 */
if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) { if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) {
HDF_LOGE("%s: start light timer fail!", __func__); HDF_LOGE("%s: start light timer fail!", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
} }
return HDF_SUCCESS; return HDF_SUCCESS;
} }
```
- TurnOffLight接口的实现如下:
```c
/* 按照指定的类型关闭灯 */ /* 按照指定的类型关闭灯 */
static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply) static int32_t TurnOffLight(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
{ {
/* 删除定时器 */ (void)data;
if (drvData->timer.realTimer != NULL) { (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 (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) {
HDF_LOGE("%s: gpio write failed", __func__);
return HDF_FAILURE;
}
drvData->info[lightId]->lightState = LIGHT_STATE_STOP;
drvData->info[lightId]->lightBrightness = 0;
/* 销毁定时器 */
if (drvData->timer.realTimer != NULL) {
if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) { if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) {
HDF_LOGE("%s: delete haptic timer fail!", __func__); HDF_LOGE("%s: delete light timer fail!", __func__);
return HDF_FAILURE;
} }
} }
if (UpdateLight(lightId, LIGHT_STATE_STOP) != HDF_SUCCESS) {
HDF_LOGE("%s: gpio write fail", __func__); 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; return HDF_FAILURE;
} }
HdfSbufRecycle(reply);
(void)OsalMutexUnlock(&priv->mutex);
*count = priv->lightNum;
*lightInfo = priv->lightInfoEntry;
return HDF_SUCCESS; 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() ```c
{ #include <cmath>
#include <cstdio>
#include <gtest/gtest.h>
#include <securec.h>
#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(); g_lightDev = NewLightInterfaceInstance();
if (g_lightDev == nullptr) { if (g_lightDev == nullptr) {
printf("test light get Module instance fail\n\r"); printf("test light get Module instance fail\n\r");
...@@ -353,20 +788,28 @@ void HdfLightTest::SetUpTestCase() ...@@ -353,20 +788,28 @@ void HdfLightTest::SetUpTestCase()
if (ret == -1) { if (ret == -1) {
printf("get light informations fail\n\r"); printf("get light informations fail\n\r");
} }
} }
/* 用例执行后,释放用例资源。 */ /* 用例执行后,释放用例资源。 */
void HdfLightTest::TearDownTestCase() void HdfLightTest::TearDownTestCase()
{ {
if(g_lightDev != nullptr){ if(g_lightDev != nullptr){
FreeLightInterfaceInstance(); FreeLightInterfaceInstance();
g_lightDev = nullptr; g_lightDev = nullptr;
} }
} }
void HdfLightTest::SetUp()
{
}
void HdfLightTest::TearDown()
{
}
/* 获取测试灯类型 */ /* 获取测试灯类型 */
HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1)
{ {
struct LightInfo *info = nullptr; struct LightInfo *info = nullptr;
if (g_lightInfo == nullptr) { if (g_lightInfo == nullptr) {
...@@ -374,60 +817,88 @@ HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1) ...@@ -374,60 +817,88 @@ HWTEST_F(HdfLightTest, GetLightList001, TestSize.Level1)
return; return;
} }
printf("get light list num[%d]\n\r", g_count); printf("get light list num[%u]\n\r", g_count);
info = g_lightInfo; info = g_lightInfo;
for (int i = 0; i < g_count; ++i) { for (uint32_t i = 0; i < g_count; ++i) {
printf("get lightId[%d]\n\r", info->lightId); printf("get lightId[%u]\n\r", info->lightId);
EXPECT_GE(info->lightId, g_minLightId); EXPECT_GE(info->lightId, 0);
EXPECT_LE(info->lightId, g_maxLightId); EXPECT_LE(info->lightId, 4);
info++; info++;
} }
} }
/* 测试灯常亮模式 */ /* 测试灯常亮模式 */
HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1) HWTEST_F(HdfLightTest, EnableLight001, TestSize.Level1)
{ {
int32_t i; uint32_t i;
int32_t ret;
struct LightEffect effect; struct LightEffect effect;
effect->lightBrightness = 0x00800000; effect.flashEffect.flashMode = 0;
effect->flashEffect.flashMode = LIGHT_FLASH_NONE; effect.flashEffect.onTime = 0;
effect->flashEffect.onTime = 0; effect.flashEffect.offTime = 0;
effect->flashEffect.offTime = 0;
for (i = 0; i < g_count; ++i) { for (i = 0; i < g_count; ++i) {
effect.lightColor.colorValue.rgbColor.r = 255;
ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); 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); EXPECT_EQ(0, ret);
OsalSleep(LIGHT_WAIT_TIME); OsalSleep(2);
ret = g_lightDev->TurnOffLight(type); ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId);
EXPECT_EQ(0, ret); EXPECT_EQ(0, ret);
}
}
/* 测试灯闪烁模式 */ effect.lightColor.colorValue.rgbColor.r = 0;
HWTEST_F(HdfLightTest, EnableLight002, TestSize.Level1) effect.lightColor.colorValue.rgbColor.g = 255;
{ effect.lightColor.colorValue.rgbColor.b = 0;
int32_t i; ret = g_lightDev->TurnOnLight(g_lightInfo[i].lightId, &effect);
int32_t ret; EXPECT_EQ(0, 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) { OsalSleep(2);
ret = g_lightDev->TurnOnLight(g_lightInfo[i]->lightId, effect); ret = g_lightDev->TurnOffLight(g_lightInfo[i].lightId);
EXPECT_EQ(0, ret); EXPECT_EQ(0, ret);
}
}
```
OsalSleep(LIGHT_WAIT_TIME); - 编译文件BUILD.gn参考代码如下:
ret = g_lightDev->TurnOffLight(type); ```c
EXPECT_EQ(0, ret); 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"
} }
} ```
```
...@@ -37,6 +37,8 @@ Motion驱动的主要工作是为上层MSDP服务提供稳定的使能/去使能 ...@@ -37,6 +37,8 @@ Motion驱动的主要工作是为上层MSDP服务提供稳定的使能/去使能
**表1** 接口功能介绍 **表1** 接口功能介绍
注:以下接口列举的为IDL接口描述生成的对应C++语言函数接口,接口声明见idl文件[/drivers/interface/motion/v1_0/](https://gitee.com/openharmony/drivers_interface/tree/master/motion)
| 接口名 | 功能介绍 | | 接口名 | 功能介绍 |
| ------------------------------------------------------------ | ---------------------------- | | ------------------------------------------------------------ | ---------------------------- |
| int32_t EnableMotion(int32_t motionType) | 使能一种手势识别类型,只有数据订阅者使能手势识别后,才能获取订阅的手势识别数据。 | | int32_t EnableMotion(int32_t motionType) | 使能一种手势识别类型,只有数据订阅者使能手势识别后,才能获取订阅的手势识别数据。 |
...@@ -49,29 +51,30 @@ Motion驱动的主要工作是为上层MSDP服务提供稳定的使能/去使能 ...@@ -49,29 +51,30 @@ Motion驱动的主要工作是为上层MSDP服务提供稳定的使能/去使能
开发步骤分为两个大步骤。 开发步骤分为两个大步骤。
1. 基于HDF驱动框架,完成手势识别用户态驱动开发。 1. 基于HDF驱动框架,完成手势识别用户态驱动开发。
2. 厂商实现EnableMotion、DisableMotion、Register和Unregister接口功能。 2. 厂商实现EnableMotion、DisableMotion、Register和Unregister接口功能。
手势识别目录结构及各部分功能简介。 手势识别目录结构及各部分功能简介。
```undefined ```
/drivers/peripheral/motion # 此目录具体实现需要厂商根据自己的器件进行开发 /drivers/peripheral/motion // 此目录具体实现需要厂商根据自己的器件进行开发
├── hdi_service # 手势识别模块对上层MSDP服务提供的驱动能力 ├── hdi_service // motion模块对上层服务提供的驱动能力
├── test # 手势识别模块测试代码 ├── test // motion模块测试代码
│ └── unittest\hdi # 手势识别模块HDI单元测试代码 └── 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函数中进行绑定。 手势识别用户态驱动开发, 主要完成Bind、Init、Release、Dispatch函数接口实现。其中Bind函数为驱动绑定对外提供的服务能力,Init函数为系统加载驱动前需要的一些初始化的操作,Release函数的主要作用为当系统加载驱动调用Init函数失败时对资源进行回收操作,Dispatch函数为服务能力的具体实现,在Bind函数中进行绑定。
```c++ ```c
// 自定义的HdfMotionInterfaceHost对象 /* 自定义的HdfMotionInterfaceHost对象 */
struct HdfMotionInterfaceHost { struct HdfMotionInterfaceHost {
struct IDeviceIoService ioService; struct IDeviceIoService ioService;
OHOS::sptr<OHOS::IRemoteObject> stub; OHOS::sptr<OHOS::IRemoteObject> stub;
}; };
// 服务接口调用响应接口 /* 服务接口调用响应接口 */
static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
struct HdfSBuf *reply) struct HdfSBuf *reply)
{ {
...@@ -93,14 +96,14 @@ static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, i ...@@ -93,14 +96,14 @@ static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, i
return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
} }
// 初始化接口 /* 初始化接口 */
int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject) int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
{ {
HDF_LOGI("HdfMotionInterfaceDriverInit enter"); HDF_LOGI("HdfMotionInterfaceDriverInit enter");
return HDF_SUCCESS; return HDF_SUCCESS;
} }
// Motion驱动对外提供的服务绑定到HDF框架 /* Motion驱动对外提供的服务绑定到HDF框架 */
int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
{ {
HDF_LOGI("HdfMotionInterfaceDriverBind enter"); HDF_LOGI("HdfMotionInterfaceDriverBind enter");
...@@ -132,7 +135,7 @@ int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) ...@@ -132,7 +135,7 @@ int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
return HDF_SUCCESS; return HDF_SUCCESS;
} }
// 释放Motion驱动中的资源 /* 释放Motion驱动中的资源 */
void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
{ {
HDF_LOGI("HdfMotionInterfaceDriverRelease enter"); HDF_LOGI("HdfMotionInterfaceDriverRelease enter");
...@@ -141,7 +144,7 @@ void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) ...@@ -141,7 +144,7 @@ void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
hdfMotionInterfaceHost = nullptr; hdfMotionInterfaceHost = nullptr;
} }
// 注册Motion驱动入口数据结构体对象 /* 注册Motion驱动入口数据结构体对象 */
struct HdfDriverEntry g_motioninterfaceDriverEntry = { struct HdfDriverEntry g_motioninterfaceDriverEntry = {
.moduleVersion = 1, .moduleVersion = 1,
.moduleName = "motion_service", .moduleName = "motion_service",
...@@ -150,7 +153,7 @@ struct HdfDriverEntry g_motioninterfaceDriverEntry = { ...@@ -150,7 +153,7 @@ struct HdfDriverEntry g_motioninterfaceDriverEntry = {
.Release = HdfMotionInterfaceDriverRelease, .Release = HdfMotionInterfaceDriverRelease,
}; };
// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 /* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
HDF_INIT(g_userAuthInterfaceDriverEntry); HDF_INIT(g_userAuthInterfaceDriverEntry);
``` ```
......
...@@ -27,7 +27,7 @@ Sensor驱动模型屏蔽硬件器件差异,为上层Sensor服务系统提供 ...@@ -27,7 +27,7 @@ Sensor驱动模型屏蔽硬件器件差异,为上层Sensor服务系统提供
![Sensor驱动运行图](figures/Sensor驱动运行图.png) ![Sensor驱动运行图](figures/Sensor驱动运行图.png)
Sensor驱动模型以标准系统Hi3516DV300产品中的加速度传感器驱动为例,介绍整个驱动加载及运行流程: Sensor驱动模型以标准系统RK3568产品中的加速度传感器驱动为例,介绍整个驱动加载及运行流程:
1. 从device_info.hcs配置文件中的Sensor Host读取到Sensor设备管理配置信息。 1. 从device_info.hcs配置文件中的Sensor Host读取到Sensor设备管理配置信息。
2. HDF配置框架从HCB数据库中解析Sensor设备管理配置信息,并关联对应设备驱动。 2. HDF配置框架从HCB数据库中解析Sensor设备管理配置信息,并关联对应设备驱动。
...@@ -64,6 +64,8 @@ Sensor驱动模型对外开放的API接口能力的具体实现请参考: ...@@ -64,6 +64,8 @@ Sensor驱动模型对外开放的API接口能力的具体实现请参考:
**表 1** 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) | 获取系统中注册的所有传感器信息,一组完整传感器信息包括传感器名字、设备厂商、固件版本号、硬件版本号、传感器类型编号、传感器标识、最大量程、精度、功耗。 | | int32_t GetAllSensors(struct SensorInformation **sensorInfo, int32_t *count) | 获取系统中注册的所有传感器信息,一组完整传感器信息包括传感器名字、设备厂商、固件版本号、硬件版本号、传感器类型编号、传感器标识、最大量程、精度、功耗。 |
...@@ -74,8 +76,7 @@ Sensor驱动模型对外开放的API接口能力的具体实现请参考: ...@@ -74,8 +76,7 @@ Sensor驱动模型对外开放的API接口能力的具体实现请参考:
| int32_t SetOption(int32_t sensorId, uint32_t option) | 设置指定传感器量程,精度等可选配置。 | | int32_t SetOption(int32_t sensorId, uint32_t option) | 设置指定传感器量程,精度等可选配置。 |
| int32_t Register(int32_t groupId, RecordDataCallback cb) | 订阅者根据不同groupId注册传感器数据回调函数,系统会将获取到的传感器数据上报给订阅者。 | | int32_t Register(int32_t groupId, RecordDataCallback cb) | 订阅者根据不同groupId注册传感器数据回调函数,系统会将获取到的传感器数据上报给订阅者。 |
| int32_t Unregister(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驱动模型对驱动开发者开放的功能接口,驱动开发者无需实现,直接使用,请参考: Sensor驱动模型对驱动开发者开放的功能接口,驱动开发者无需实现,直接使用,请参考:
...@@ -95,8 +96,6 @@ Sensor驱动模型对驱动开发者开放的功能接口,驱动开发者无 ...@@ -95,8 +96,6 @@ Sensor驱动模型对驱动开发者开放的功能接口,驱动开发者无
| int32_t GetSensorBusHandle(struct SensorBusCfg *busCfg) | 获取传感器总线句柄信息。 | | int32_t GetSensorBusHandle(struct SensorBusCfg *busCfg) | 获取传感器总线句柄信息。 |
| int32_t ReleaseSensorBusHandle(struct SensorBusCfg *busCfg) | 释放传感器句柄信息。 | | int32_t ReleaseSensorBusHandle(struct SensorBusCfg *busCfg) | 释放传感器句柄信息。 |
Sensor驱动模型要求驱动开发者实现的接口功能,请参考: Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
**表 3** Sensor驱动模型要求驱动开发者实现的接口列表 **表 3** Sensor驱动模型要求驱动开发者实现的接口列表
...@@ -115,12 +114,34 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -115,12 +114,34 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
接口实现参考[开发步骤](#开发步骤)章节。 接口实现参考[开发步骤](#开发步骤)章节。
### 开发步骤 ### 开发步骤
1. 基于HDF驱动框架,按照驱动Driver Entry程序,完成加速度抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 基于HDF驱动框架,按照驱动Driver Entry程序,以加速度传感器驱动为例,介绍传感器驱动的开发。传感器的驱动开发包括抽象驱动开发和差异化驱动开发两部分。传感器的抽象驱动开发包括同一个传感器id中不同器件的公共接口实现;传感器的差异化驱动开发包括不同器件差异化接口的实现。
1. 开发加速度传感器抽象驱动。
- 加速度传感器抽象驱动在Sensor Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。
具体代码实现如下:
```c
/* 加速度计传感器设备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值相等
}
}
```
- 加速度传感器驱动入口函数实现 - 加速度传感器抽象驱动代码实现路径为:drivers\hdf_core\framework\model\sensor\driver\accel\sensor_accel_driver.c。
- 加速度传感器抽象驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下:
```c ```c
/* 注册加速度计传感器入口数据结构体对象 */
struct HdfDriverEntry g_sensorAccelDevEntry = { struct HdfDriverEntry g_sensorAccelDevEntry = {
.moduleVersion = 1, // 加速度计传感器模块版本号 .moduleVersion = 1, // 加速度计传感器模块版本号
.moduleName = "HDF_SENSOR_ACCEL", // 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样 .moduleName = "HDF_SENSOR_ACCEL", // 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样
...@@ -133,10 +154,9 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -133,10 +154,9 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
HDF_INIT(g_sensorAccelDevEntry); HDF_INIT(g_sensorAccelDevEntry);
``` ```
- 加速度传感器驱动操作接口实现 - 加速度传感器抽象驱动Bind接口实现如下:
```c ```c
/* 加速度计传感器驱动对外提供的服务绑定到HDF框架 */
int32_t AccelBindDriver(struct HdfDeviceObject *device) int32_t AccelBindDriver(struct HdfDeviceObject *device)
{ {
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
...@@ -153,27 +173,64 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -153,27 +173,64 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
g_accelDrvData = drvData; g_accelDrvData = drvData;
return HDF_SUCCESS; return HDF_SUCCESS;
} }
```
/* 注册加速度计传感器驱动归一化的接口函数 */ - 加速度传感器抽象驱动Init接口实现如下:
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), ```c
&config->sensorInfo, sizeof(config->sensorInfo)) != EOK) { int32_t AccelInitDriver(struct HdfDeviceObject *device)
HDF_LOGE("%s: Copy sensor info failed", __func__); {
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; 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; 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) static int32_t InitAccelAfterDetected(struct SensorCfgData *config)
{ {
struct SensorDeviceInfo deviceInfo; struct SensorDeviceInfo deviceInfo;
...@@ -183,28 +240,42 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -183,28 +240,42 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
HDF_LOGE("%s: Init accel ops failed", __func__); HDF_LOGE("%s: Init accel ops failed", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
/* 注册加速度计设备到传感器管理模块 */ /* 注册加速度计器件到传感器设备管理模块 */
if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) { if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) {
HDF_LOGE("%s: Add accel device failed", __func__); HDF_LOGE("%s: Add accel device failed", __func__);
return HDF_FAILURE; 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) { if (ParseSensorRegConfig(config) != HDF_SUCCESS) {
HDF_LOGE("%s: Parse sensor register failed", __func__); HDF_LOGE("%s: Parse sensor register failed", __func__);
(void)DeleteSensorDevice(&config->sensorInfo); (void)DeleteSensorDevice(&config->sensorInfo);
ReleaseSensorAllRegConfig(config); ReleaseSensorAllRegConfig(config);
ReleaseSensorDirectionConfig(config);
return HDF_FAILURE; return HDF_FAILURE;
} }
return HDF_SUCCESS; return HDF_SUCCESS;
} }
struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node) 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) { if (drvData->detectFlag) {
HDF_LOGE("%s: Accel sensor have detected", __func__); HDF_LOGE("%s: Accel sensor have detected", __func__);
return NULL; return NULL;
} }
if (drvData->accelCfg == NULL) { if (drvData->accelCfg == NULL) {
HDF_LOGE("%s: Accel accelCfg pointer NULL", __func__); HDF_LOGE("%s: Accel accelCfg pointer NULL", __func__);
return NULL; return NULL;
...@@ -214,90 +285,34 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -214,90 +285,34 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
HDF_LOGE("%s: Get sensor base config failed", __func__); HDF_LOGE("%s: Get sensor base config failed", __func__);
goto BASE_CONFIG_EXIT; goto BASE_CONFIG_EXIT;
} }
/* 如果探测不到器件在位,返回进行下个器件探测 */ /* 如果器件不在位(存在器件ID的情况),返回进行下个器件探测 */
if (DetectSensorDevice(drvData->accelCfg) != HDF_SUCCESS) { if (DetectSensorDevice(drvData->accelCfg) != HDF_SUCCESS) {
HDF_LOGI("%s: Accel sensor detect device no exist", __func__); HDF_LOGI("%s: Accel sensor detect device no exist", __func__);
drvData->detectFlag = false; drvData->detectFlag = false;
goto BASE_CONFIG_EXIT; goto BASE_CONFIG_EXIT;
} }
drvData->detectFlag = true;
/* 器件寄存器解析 */ /* 器件寄存器解析 */
drvData->detectFlag = true;
if (InitAccelAfterDetected(drvData->accelCfg) != HDF_SUCCESS) { if (InitAccelAfterDetected(drvData->accelCfg) != HDF_SUCCESS) {
HDF_LOGE("%s: Accel sensor detect device no exist", __func__); HDF_LOGE("%s: Accel sensor detect device no exist", __func__);
goto INIT_EXIT; goto INIT_EXIT;
} }
return drvData->accelCfg; 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;
}
/* 分配加速度配置信息资源 */
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];
……
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);
}
OsalMemFree(drvData->accelCfg);
drvData->accelCfg = NULL;
/* 器件在位,销毁工作队列资源 */
HdfWorkDestroy(&drvData->accelWork);
HdfWorkQueueDestroy(&drvData->accelWorkQueue);
OsalMemFree(drvData);
}
```
2. 完成加速度传感器驱动的设备信息配置。
加速度传感器模型使用HCS作为配置描述源码,HCS配置字段请参考[配置管理](driver-hdf-manage.md)介绍。
```hcs INIT_EXIT:
/* 加速度计传感器设备HCS配置 */ (void)ReleaseSensorBusHandle(&drvData->accelCfg->busCfg);
device_sensor_accel :: device { BASE_CONFIG_EXIT:
device0 :: deviceNode { drvData->accelCfg->root = NULL;
policy = 1; // 驱动服务发布的策略 (void)memset_s(&drvData->accelCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo));
priority = 110; // 驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序 (void)memset_s(&drvData->accelCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg));
preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载 (void)memset_s(&drvData->accelCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));
permission = 0664; // 驱动创建设备节点权限 return drvData->accelCfg;
moduleName = "HDF_SENSOR_ACCEL"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
serviceName = "sensor_accel"; // 驱动对外发布服务的名称,必须唯一
deviceMatchAttr = "hdf_sensor_accel_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
}
} }
``` ```
3. 完成加速度传感器抽象驱动内部接口开发,包括Enable、Disable、SetBatch、SetMode、SetOption、AccelCreateCfgData、AccelReleaseCfgData、AccelRegisterChipOps接口实现。 - Enable接口的代码实现如下:
```c ```c
/* 不使用函数暂时置空 */
static int32_t SetAccelInfo(struct SensorBasicInfo *info)
{
(void)info;
return HDF_ERR_NOT_SUPPORT;
}
/* 下发使能寄存器组的配置 */
static int32_t SetAccelEnable(void) static int32_t SetAccelEnable(void)
{ {
int32_t ret; int32_t ret;
...@@ -310,19 +325,19 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -310,19 +325,19 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
HDF_LOGE("%s: Accel sensor is enabled", __func__); HDF_LOGE("%s: Accel sensor is enabled", __func__);
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 设置寄存器 */
ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]); ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Accel sensor enable config failed", __func__); HDF_LOGE("%s: Accel sensor enable config failed", __func__);
return ret; return ret;
} }
/* 创建定时器 */
ret = OsalTimerCreate(&drvData->accelTimer, SENSOR_TIMER_MIN_TIME, AccelTimerEntry, (uintptr_t)drvData); ret = OsalTimerCreate(&drvData->accelTimer, SENSOR_TIMER_MIN_TIME, AccelTimerEntry, (uintptr_t)drvData);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Accel create timer failed[%d]", __func__, ret); HDF_LOGE("%s: Accel create timer failed[%d]", __func__, ret);
return ret; return ret;
} }
/* 开启定时器进行数据上报 */
ret = OsalTimerStartLoop(&drvData->accelTimer); ret = OsalTimerStartLoop(&drvData->accelTimer);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Accel start timer failed[%d]", __func__, ret); HDF_LOGE("%s: Accel start timer failed[%d]", __func__, ret);
...@@ -332,7 +347,11 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -332,7 +347,11 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 下发去使能寄存器组的配置 */ ```
- Disable接口的代码实现如下:
```c
static int32_t SetAccelDisable(void) static int32_t SetAccelDisable(void)
{ {
int32_t ret; int32_t ret;
...@@ -345,13 +364,13 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -345,13 +364,13 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
HDF_LOGE("%s: Accel sensor had disable", __func__); HDF_LOGE("%s: Accel sensor had disable", __func__);
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 设置寄存器 */
ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]); ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Accel sensor disable config failed", __func__); HDF_LOGE("%s: Accel sensor disable config failed", __func__);
return ret; return ret;
} }
/* 删除定时器 */
ret = OsalTimerDelete(&drvData->accelTimer); ret = OsalTimerDelete(&drvData->accelTimer);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Accel delete timer failed", __func__); HDF_LOGE("%s: Accel delete timer failed", __func__);
...@@ -361,7 +380,11 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -361,7 +380,11 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 配置传感器采样率和数据上报间隔 */ ```
- SetBatch接口的代码实现如下:
```c
static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval) static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval)
{ {
(void)interval; (void)interval;
...@@ -370,78 +393,186 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -370,78 +393,186 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
drvData = AccelGetDrvData(); drvData = AccelGetDrvData();
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
/* 给定时器设置采样率 */
drvData->interval = samplingInterval; drvData->interval = samplingInterval;
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 设置传感器工作模式,当前支持实时模式 */ ```
- SetMode接口的代码实现如下:
```c
static int32_t SetAccelMode(int32_t mode) static int32_t SetAccelMode(int32_t mode)
{ {
return (mode == SENSOR_WORK_MODE_REALTIME) ? HDF_SUCCESS : HDF_FAILURE; if (mode <= SENSOR_WORK_MODE_DEFAULT || mode >= SENSOR_WORK_MODE_MAX) {
HDF_LOGE("%s: The current mode is not supported", __func__);
return HDF_FAILURE;
} }
static int32_t SetAccelOption(uint32_t option)
{
(void)option;
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 设置传感器可选配置 */ ```
- SetOption接口的代码实现如下:
```c
static int32_t SetAccelOption(uint32_t option) static int32_t SetAccelOption(uint32_t option)
{ {
(void)option; (void)option;
return HDF_ERR_NOT_SUPPORT; return HDF_SUCCESS;
} }
``` ```
4. 基于HDF驱动框架,按照驱动Driver Entry程序,完成加速度传感器差异化驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。 2. 开发加速度传感器差异化驱动。
- 加速度传感器差异化驱动在Sensor Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。
具体代码实现如下:
```c ```c
/* 加速度计传感器差异化驱动消息交互 */ device_sensor_mxc6655xa :: device {
static int32_t DispatchBMI160(struct HdfDeviceIoClient *client, device0 :: deviceNode {
int cmd, struct HdfSBuf *data, struct HdfSBuf *reply) policy = 1; // policy字段是驱动服务发布的策略
{ priority = 120; // 驱动启动优先级(0-200),值越大优先级越低,建议配置为100,优先级相同则不保证device的加载顺序
(void)client; preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载
(void)cmd; permission = 0664; // 驱动创建设备节点权限
(void)data; moduleName = "HDF_SENSOR_ACCEL_MXC6655XA"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
(void)reply; serviceName = "hdf_accel_mxc6655xa"; // 加速度mxc6655xa对外发布服务的名称,必须唯一
deviceMatchAttr = "hdf_sensor_accel_mxc6655xa_driver"; // 加速度差异化驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
}
}
```
return HDF_SUCCESS; - 加速度传感器差异化驱动私有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
/* <sign> 1:negative 0:positive
<map> 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
];
}
}
} }
/* 加速度计传感器差异化驱动对外提供的服务绑定到HDF框架 */ ```
int32_t Bmi160BindDriver(struct HdfDeviceObject *device)
- 加速度差异化驱动的代码实现路径: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); CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)OsalMemCalloc(sizeof(*drvData)); struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)OsalMemCalloc(sizeof(*drvData));
if (drvData == NULL) { if (drvData == NULL) {
HDF_LOGE("%s: Malloc Bmi160 drv data fail", __func__); HDF_LOGE("%s: Malloc MXC6655XA drv data fail", __func__);
return HDF_ERR_MALLOC_FAIL; return HDF_ERR_MALLOC_FAIL;
} }
drvData->ioService.Dispatch = DispatchBMI160; drvData->ioService.Dispatch = DispatchMXC6655xa;
drvData->device = device; drvData->device = device;
device->service = &drvData->ioService; device->service = &drvData->ioService;
g_bmi160DrvData = drvData; g_mxc6655xaDrvData = drvData;
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 加速度计传感器差异化驱动初始化 */ ```
int32_t Bmi160InitDriver(struct HdfDeviceObject *device)
- 加速度传感器差异化驱动Init接口实现如下:
```c
int32_t Mxc6655xaInitDriver(struct HdfDeviceObject *device)
{ {
int32_t ret; int32_t ret;
struct AccelOpsCall ops; struct AccelOpsCall ops;
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)device->service; struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service;
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM); 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); drvData->sensorCfg = AccelCreateCfgData(device->property);
if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) { if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {
HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__); HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__);
...@@ -449,65 +580,136 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -449,65 +580,136 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
} }
ops.Init = NULL; ops.Init = NULL;
ops.ReadData = ReadBmi160Data; ops.ReadData = ReadMxc6655xaData;
ret = AccelRegisterChipOps(&ops); ret = AccelRegisterChipOps(&ops);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Register BMI160 accel failed", __func__); HDF_LOGE("%s: Register MXC6655XA accel failed", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
ret = InitBmi160(drvData->sensorCfg); ret = InitMxc6655xa(drvData->sensorCfg);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Init BMI160 accel failed", __func__); HDF_LOGE("%s: Init MXC6655XA accel failed", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
return HDF_SUCCESS; return HDF_SUCCESS;
} }
/* 释放驱动初始化时分配的资源 */ ```
void Bmi160ReleaseDriver(struct HdfDeviceObject *device)
- 加速度传感器差异化驱动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) { if (drvData->sensorCfg != NULL) {
AccelReleaseCfgData(drvData->sensorCfg); AccelReleaseCfgData(drvData->sensorCfg);
drvData->sensorCfg = NULL; drvData->sensorCfg = NULL;
} }
OsalMemFree(drvData); 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函数实现。 - 加速度传感器差异化驱动内部接口实现。
需要开发者实现的ReadMxc6655xaData接口函数,在 Mxc6655xaInitDriver函数里面注册此函数,具体实现如下:
```c ```c
int32_t ReadBmi160Data(struct SensorCfgData *data) 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, &reg[ACCEL_X_AXIS_LSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_MSB_ADDR, &reg[ACCEL_X_AXIS_MSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_LSB_ADDR, &reg[ACCEL_Y_AXIS_LSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_MSB_ADDR, &reg[ACCEL_Y_AXIS_MSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_LSB_ADDR, &reg[ACCEL_Z_AXIS_LSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_MSB_ADDR, &reg[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;
}
/* 读取加速度的event数据,在 Mxc6655xaInitDriver函数里面注册此函数,将数据传给加速度抽象驱动 */
int32_t ReadMxc6655xaData(struct SensorCfgData *cfg, struct SensorReportEvent *event)
{ {
int32_t ret; int32_t ret;
struct AccelData rawData = { 0, 0, 0 }; struct AccelData rawData = { 0, 0, 0 };
int32_t tmp[ACCEL_AXIS_NUM]; static int32_t tmp[ACCEL_AXIS_NUM];
struct SensorReportEvent event;
(void)memset_s(&event, sizeof(event), 0, sizeof(event)); CHECK_NULL_PTR_RETURN_VALUE(cfg, HDF_ERR_INVALID_PARAM);
ret = ReadBmi160RawData(data, &rawData, &event.timestamp); CHECK_NULL_PTR_RETURN_VALUE(event, HDF_ERR_INVALID_PARAM);
ret = ReadMxc6655xaRawData(cfg, &rawData, &event->timestamp);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: BMI160 read raw data failed", __func__); HDF_LOGE("%s: MXC6655XA read raw data failed", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
event.sensorId = SENSOR_TAG_ACCELEROMETER;
event.option = 0; event->sensorId = SENSOR_TAG_ACCELEROMETER;
event.mode = SENSOR_WORK_MODE_REALTIME; event->option = 0;
…… event->mode = SENSOR_WORK_MODE_REALTIME;
ret = ReportSensorEvent(&event);
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) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: BMI160 report data failed", __func__); HDF_LOGE("%s: MXC6655XA convert raw data failed", __func__);
return HDF_FAILURE;
} }
event->dataLen = sizeof(tmp);
event->data = (uint8_t *)&tmp;
return ret; return ret;
} }
``` ```
...@@ -516,79 +718,169 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考: ...@@ -516,79 +718,169 @@ Sensor驱动模型要求驱动开发者实现的接口功能,请参考:
驱动开发完成后,在传感器单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。 驱动开发完成后,在传感器单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。
```c++ - 参考测试代码如下:
static int32_t g_sensorDataFlag = 0; // 标识是否上报传感器数据
static const struct SensorInterface *g_sensorDev = nullptr; // 保持获取的传感器接口实例地址
/* 订阅者注册数据上报函数 */ ```c
static int SensorTestDataCallback(struct SensorEvents *event) #include <cmath>
{ #include <cstdio>
if (event == nullptr) { #include <unistd.h>
return -1; #include <gtest/gtest.h>
#include <securec.h>
#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; float *data = (float*)event->data;
printf("time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]\n\r", event->timestamp, printf("time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]\n\r", event->timestamp,
event->sensorId, (*data), *(data + 1), *(data + g_axisZ)); event->sensorId, (*data), *(data + 1), *(data + 2));
if (*data > 1e-5) {
g_sensorDataFlag = 1; return HDF_SUCCESS;
} }
return 0;
} class HdfSensorTest : public testing::Test {
/* 用例执行前,初始化传感器接口实例 */ public:
void HdfSensorTest::SetUpTestCase() static void SetUpTestCase();
{ static void TearDownTestCase();
void SetUp();
void TearDown();
};
/* 用例执行前,初始化传感器接口实例 */
void HdfSensorTest::SetUpTestCase()
{
g_sensorDev = NewSensorInterfaceInstance(); g_sensorDev = NewSensorInterfaceInstance();
if (g_sensorDev == nullptr) { if (g_sensorDev == nullptr) {
printf("test sensor get module instance failed\n\r"); printf("test sensor get module instance failed\n\r");
} }
} }
/* 用例资源释放 */ /* 用例资源释放 */
void HdfSensorTest::TearDownTestCase() void HdfSensorTest::TearDownTestCase()
{ {
if (g_sensorDev != nullptr) { if (g_sensorDev != nullptr) {
FreeSensorInterfaceInstance(); FreeSensorInterfaceInstance();
g_sensorDev = nullptr; g_sensorDev = nullptr;
} }
} }
/* 传感器驱动测试验证 */
HWTEST_F(HdfSensorTest,TestAccelDriver_001, TestSize.Level0) void HdfSensorTest::SetUp()
{ {
int32_t sensorInterval = 1000000000; // 数据采样率单位纳秒 }
int32_t pollTime = 5; // 数据采样时间单位秒
int32_t accelSensorId = 1; // 加速度传感器类型标识为1 void HdfSensorTest::TearDown()
int32_t count = 0; {
}
HWTEST_F(HdfSensorTest,TestAccelDriver_001, TestSize.Level0)
{
int ret; int ret;
struct SensorInformation *sensorInfo = nullptr; struct SensorInformation *sensorInfo = NULL;
int32_t count = 0;
int32_t sensorInterval = 200000000; /* 数据采样率设置200毫秒,单位纳秒 */
int32_t reportInterval = 400000000;
ret = g_sensorDev->Register(0, TraditionSensorTestDataCallback) /* 2.订阅者注册传感器数据回调处理函数 */
EXPECT_EQ(SENSOR_NULL_PTR, ret); ret = g_sensorDev->Register(TRADITIONAL_SENSOR_TYPE, SensorDataCallback);
if (ret != 0) {
return;
}
printf("Register success\n");
/* 3.获取设备支持的Sensor列表 */
ret = g_sensorDev->GetAllSensors(&sensorInfo, &count); ret = g_sensorDev->GetAllSensors(&sensorInfo, &count);
EXPECT_EQ(0, ret); if (ret != 0) {
if (sensorInfo == nullptr) {
EXPECT_NE(nullptr, sensorInfo);
return; return;
} }
/* 打印获取的传感器列表 */
for (int i = 0; i < count; i++) { printf("GetAllSensors count: %d\n", count);
printf("get sensorId[%d], info name[%s]\n\r", sensorInfo[i]->sensorId, sensorInfo[i]->sensorName);
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);
} }
ret = g_sensorDev->Enable(accelSensorId);
EXPECT_EQ(0, ret);
g_sensorDataFlag = 0;
ret = g_sensorDev->SetBatch(accelSensorId, sensorInterval, pollTime); for (int i = 0; i < count; i++)
EXPECT_EQ(0, ret); {
/* 在时间pollTime内,观察输出打印数据 */ /* 4.设置传感器采样率 */
OsalSleep(pollTime); ret = g_sensorDev->SetBatch(sensorInfo[i].sensorId, sensorInterval, reportInterval);
EXPECT_EQ(1, g_sensorDataFlag); 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");
ret = g_sensorDev->Disable(accelSensorId); usleep(1000 * 1000);
g_sensorDataFlag = 0;
EXPECT_EQ(0, ret);
ret = g_sensorDev->Unregister(0, TraditionSensorTestDataCallback); /* 6.去使能传感器 */
EXPECT_EQ(0, ret); 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"
}
```
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
![Vibrator驱动运行图](figures/Vibrator驱动运行图.png) ![Vibrator驱动运行图](figures/Vibrator驱动运行图.png)
以标准系统Hi3516DV300产品为例,介绍马达模块驱动加载及运行流程: 以标准系统RK3568产品为例,介绍马达模块驱动加载及运行流程:
1. Device Manager从device_info.hcs配置文件中读取Vibrator管理配置信息。 1. Device Manager从device_info.hcs配置文件中读取Vibrator管理配置信息。
2. HCS Parser解析Vibrator管理配置信息,并加载对应的马达抽象驱动。 2. HCS Parser解析Vibrator管理配置信息,并加载对应的马达抽象驱动。
...@@ -65,99 +65,28 @@ ...@@ -65,99 +65,28 @@
**表 1** 马达驱动模型对外API接口能力介绍 **表 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 (*StartOnce)(uint32_t duration) | 控制马达以执行给定持续时间的单次振动,duration表示单次振动的持续时间。 |
| int32_t (*Start)([in] const char *effectType) | 控制马达以预置效果执行周期性振动,effectType表示指向预设效果类型的指针。 | | int32_t (*Start)(const char *effectType) | 控制马达以预置效果执行周期性振动,effectType表示指向预设效果类型的指针。 |
| int32_t (*Stop)([in] enum VibratorMode mode) | 停止马达振动,mode表示振动模式,可以是单次或周期性的。 | | int32_t (*Stop)(enum VibratorMode mode) | 停止马达振动,mode表示振动模式,可以是单次或周期性的。 |
| int32_t (*EnableVibratorModulation)(uint32_t duration, int32_t intensity, int32_t frequency) | 根据传入的振动效果启动马达,duration表示马达振动的持续时间,intensity表示振动周期内的马达振幅,frequency表示振动周期内的马达频率。 | | 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驱动框架开发的马达驱动模型,实现跨操作系统迁移、器件差异配置等功能。具体的开发步骤如下: 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;
}
return HDF_SUCCESS; 1. 开发马达抽象驱动。
}
/* 释放马达驱动初始化时分配的资源 */ - 马达抽象驱动在Vibrator Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。
void ReleaseVibratorDriver(struct HdfDeviceObject *device)
{
struct VibratorDriverData *drvData = NULL;
......
(void)DestroyVibratorHaptic();
(void)OsalMutexDestroy(&drvData->mutex);
(void)OsalMemFree(drvData);
g_vibratorDrvData = NULL;
}
```
- 在系统启动过程中,HDF设备管理模块通过设备HCS配置信息,加载马达抽象驱动,并对外发布马达驱动接口。 具体代码实现如下:
```c ```c
/* 马达设备HCS配置 */ /* 马达设备HCS配置 */
...@@ -177,12 +106,12 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -177,12 +106,12 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
} }
``` ```
2. 创建马达效果模型,解析马达效果HCS配置 - 创建马达效果模型,解析马达效果HCS配置,代码实现路径:drivers\hdf_core\framework\model\misc\vibrator\driver\src\vibrator_haptic.c
- 创建马达效果模型。 具体代码实现如下:
```c ```c
/* 创建马达效果模型,分配资源,解析马达效果HCS配置 */ /* 创建马达效果模型 */
int32_t CreateVibratorHaptic(struct HdfDeviceObject *device) int32_t CreateVibratorHaptic(struct HdfDeviceObject *device)
{ {
struct VibratorHapticData *hapticData = NULL; struct VibratorHapticData *hapticData = NULL;
...@@ -194,15 +123,15 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -194,15 +123,15 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
hapticData->supportHaptic = false; hapticData->supportHaptic = false;
if (OsalMutexInit(&hapticData->mutex) != HDF_SUCCESS) { if (OsalMutexInit(&hapticData->mutex) != HDF_SUCCESS) {
HDF_LOGE("%s: failed to init mutex", __func__); HDF_LOGE("%s: fail to init mutex", __func__);
goto EXIT; goto EXIT;
} }
DListHeadInit(&hapticData->effectSeqHead); DListHeadInit(&hapticData->effectSeqHead);
/* 解析马达效果HCS配置 */ // get haptic hcs
if (ParserVibratorHapticConfig(device->property) != HDF_SUCCESS) { if (ParserVibratorHapticConfig(device->property) != HDF_SUCCESS) {
HDF_LOGE("%s: parser haptic config failed!", __func__); HDF_LOGE("%s: parser haptic config fail!", __func__);
goto EXIT; goto EXIT;
} }
...@@ -213,42 +142,112 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -213,42 +142,112 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
} }
``` ```
- 马达效果模型使用HCS作为配置描述源码,HCS配置文件字段详细介绍参考[配置管理](driver-hdf-manage.md) - 马达抽象驱动代码实现路径:drivers\hdf_core\framework\model\misc\vibrator\driver\src\vibrator_driver.c。
- 马达抽象驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下:
```c ```c
/* 马达数据配置模板(vibrator_config.hcs) */ /* 注册马达抽象驱动入口数据结构体对象 */
root { struct HdfDriverEntry g_vibratorDriverEntry = {
vibratorConfig { .moduleVersion = 1, // 马达模块版本号
boardConfig { .moduleName = "HDF_VIBRATOR", // 马达模块名,要与device_info.hcs文件里的马达moduleName字段值一样
match_attr = "hdf_vibrator_driver"; // 需要和马达设备配置文件中的match_attr字段保持一致 .Bind = BindVibratorDriver, // 马达绑定函数
vibratorAttr { .Init = InitVibratorDriver, // 马达初始化函数
/* 0:转子;1:线性 */ .Release = ReleaseVibratorDriver, // 马达资源释放函数
deviceType = 1; // 设备类型 };
supportPreset = 1; // 支持的预设类型 /* 调用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;
} }
vibratorHapticConfig { /* 工作队列资源初始化 */
haptic_clock_timer { if (HdfWorkQueueInit(&drvData->workQueue, VIBRATOR_WORK_QUEUE_NAME) != HDF_SUCCESS) {
effectName = "haptic.clock.timer"; HDF_LOGE("%s: init workQueue failed!", __func__);
type = 1; // 0:内置模式;1:时间序列 return HDF_FAILURE;
seq = [600, 600, 200, 600]; // 时间序列
} }
haptic_default_effect {
effectName = "haptic.default.effect"; if (HdfWorkInit(&drvData->work, VibratorWorkEntry, (void*)drvData) != HDF_SUCCESS) {
type = 0; HDF_LOGE("%s: init workQueue failed!", __func__);
seq = [0, 3, 800, 1]; 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;
} }
``` ```
3. 完成马达信息获取、振动模式设置和停止的接口开发,并实现根据振动模式创建和销毁定时器。 - 马达抽象驱动内部接口实现了马达信息获取、振动模式设置和停止等功能,并实现根据振动模式创建和销毁定时器。
马达硬件服务调用StartOnce接口动态配置持续振动时间,调用StartEffect接口启动静态配置的振动效果,为驱动开发者提供抽象的配置接口能力。 - 马达抽象驱动StartOnce接口实现如下:
```c ```c
/* 按照指定持续时间触发振动马达,duration为振动持续时长。 */ /* 按照指定持续时间触发振动马达,duration为振动持续时长 */
static int32_t StartOnce(struct HdfSBuf *data, struct HdfSBuf *reply) static int32_t StartOnce(struct HdfSBuf *data, struct HdfSBuf *reply)
{ {
uint32_t duration; uint32_t duration;
...@@ -256,11 +255,33 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -256,11 +255,33 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
struct VibratorEffectCfg config; struct VibratorEffectCfg config;
struct VibratorDriverData *drvData = GetVibratorDrvData(); struct VibratorDriverData *drvData = GetVibratorDrvData();
(void)reply; (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.cfgMode = VIBRATOR_MODE_ONCE;
config.duration = duration; config.duration = duration;
config.effect = NULL; config.effect = NULL;
/* 根据振动效果的模式创建定时器 */ /* 根据振动效果的模式开启马达效果模型 */
ret = StartHaptic(&config); ret = StartHaptic(&config);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: start haptic failed!", __func__); HDF_LOGE("%s: start haptic failed!", __func__);
...@@ -269,8 +290,12 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -269,8 +290,12 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
return HDF_SUCCESS; return HDF_SUCCESS;
} }
```
- 马达抽象驱动StartEffect接口实现如下:
/* 按照预置效果启动马达,effectType表示预置的振动效果。 */ ```c
/* 按照预置效果启动马达,effect表示预置的振动效果 */
static int32_t StartEffect(struct HdfSBuf *data, struct HdfSBuf *reply) static int32_t StartEffect(struct HdfSBuf *data, struct HdfSBuf *reply)
{ {
int32_t ret; int32_t ret;
...@@ -278,11 +303,27 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -278,11 +303,27 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
struct VibratorEffectCfg config; struct VibratorEffectCfg config;
struct VibratorDriverData *drvData = GetVibratorDrvData(); struct VibratorDriverData *drvData = GetVibratorDrvData();
(void)reply; (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.cfgMode = VIBRATOR_MODE_PRESET;
config.duration = 0; config.duration = 0;
config.effect = effect; config.effect = effect;
/* 预置效果启动马达 */
ret = StartHaptic(&config); ret = StartHaptic(&config);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: start haptic failed!", __func__); HDF_LOGE("%s: start haptic failed!", __func__);
...@@ -291,7 +332,11 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -291,7 +332,11 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
return HDF_SUCCESS; return HDF_SUCCESS;
} }
```
- 马达抽象驱动Stop接口实现如下:
```c
/* 按照指定的振动模式停止马达振动 */ /* 按照指定的振动模式停止马达振动 */
static int32_t Stop(struct HdfSBuf *data, struct HdfSBuf *reply) static int32_t Stop(struct HdfSBuf *data, struct HdfSBuf *reply)
{ {
...@@ -299,8 +344,25 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -299,8 +344,25 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
int32_t mode; int32_t mode;
struct VibratorDriverData *drvData = GetVibratorDrvData(); struct VibratorDriverData *drvData = GetVibratorDrvData();
(void)reply; (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(); ret = StopHaptic();
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: stop haptic failed!", __func__); HDF_LOGE("%s: stop haptic failed!", __func__);
...@@ -313,53 +375,86 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -313,53 +375,86 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
return HDF_SUCCESS; return HDF_SUCCESS;
} }
```
/* 按照指定振幅、频率、持续时间触发振动马达。duration为振动持续时长,intensity为振动强度,frequency为振动频率。 */ - 马达抽象驱动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) static int32_t EnableModulationParameter(struct HdfSBuf *data, struct HdfSBuf *reply)
{ {
(void)reply; (void)reply;
struct VibratorEffectCfg config; struct VibratorEffectCfg config;
struct VibratorDriverData *drvData; struct VibratorDriverData *drvData;
uint32_t duration; uint32_t duration;
int32_t intensity; uint16_t intensity;
int32_t frequency; int16_t frequency;
int32_t ret; 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); (void)OsalMutexLock(&drvData->mutex);
drvData->mode = VIBRATOR_MODE_ONCE; drvData->mode = VIBRATOR_MODE_ONCE;
(void)OsalMutexUnlock(&drvData->mutex); (void)OsalMutexUnlock(&drvData->mutex);
/* 设置振幅和频率 */
ret = drvData->ops.SetParameter(intensity, frequency); ret = drvData->ops.SetParameter(intensity, frequency);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: set parameter failed", __func__); HDF_LOGE("%s: set parameter failed!", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
config.cfgMode = VIBRATOR_MODE_ONCE; config.cfgMode = VIBRATOR_MODE_ONCE;
config.duration = duration; config.duration = duration;
config.effect = NULL; config.effect = NULL;
/* 预置效果启动马达 */
ret = StartHaptic(&config); ret = StartHaptic(&config);
if (ret != HDF_SUCCESS) { if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: start haptic failed", __func__); HDF_LOGE("%s: start haptic failed!", __func__);
return HDF_FAILURE;
}
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; return HDF_FAILURE;
} }
...@@ -367,9 +462,7 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -367,9 +462,7 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
} }
``` ```
4. 马达驱动模型提供给开发者马达驱动差异化接口,开发者实现差异化接口。 - 在马达差异化器件驱动初始化成功时,注册差异化接口,方便实现马达器件差异化驱动接口,具体实现如下:
- 在差异化器件驱动初始化成功时,注册差异实现接口,方便实现器件差异的驱动接口。
```c ```c
/* 注册马达差异化实现接口 */ /* 注册马达差异化实现接口 */
...@@ -409,126 +502,296 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能 ...@@ -409,126 +502,296 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
} }
``` ```
1. 开发马达差异化驱动。
- 马达差异化驱动在Vibrator Host中的配置信息,代码实现路径如下:vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs。
具体代码实现如下:
```c
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值相等
}
}
```
- 马达差异化驱动私有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; // 马达振动支持的最小频率
}
}
}
}
```
- 马达差异化驱动代码实现路径为: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;
}
```
- 马达驱动模型提供给开发者马达驱动差异化接口,具体实现如下: - 马达差异化驱动Init接口实现如下:
```c ```c
/* 按照指定的振动模式停止马达的振动 */ int32_t InitLinearVibratorDriver(struct HdfDeviceObject *device)
static int32_t StopModulationParameter()
{ {
uint8_t value[DRV2605L_VALUE_BUTT]; static struct VibratorOps ops;
struct Drv2605lDriverData *drvData = NULL; struct VibratorLinearDriverData *drvData = NULL;
drvData = GetDrv2605lDrvData();
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
drvData = (struct VibratorLinearDriverData *)device->service;
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); 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; ops.Start = StartLinearVibrator;
value[DRV2605L_VALUE_INDEX] = (uint8_t)DRV2605_MODE_STANDBY; ops.StartEffect = StartEffectLinearVibrator;
if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { ops.Stop = StopLinearVibrator;
HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]); ops.SetParameter = NULL;
if (RegisterVibratorOps(&ops) != HDF_SUCCESS) {
HDF_LOGE("%s: register vibrator ops fail", __func__);
return HDF_FAILURE; return HDF_FAILURE;
} }
value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_RTPIN; drvData->linearCfgData = (struct VibratorCfgData *)OsalMemCalloc(sizeof(*drvData->linearCfgData));
value[DRV2605L_VALUE_INDEX] = (uint8_t)&drvData->drv2605lCfgData->vibratorAttr.defaultIntensity; CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData->linearCfgData, HDF_ERR_MALLOC_FAIL);
if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { /* 解析马达寄存器初始化 */
HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]); if (GetVibratorBaseConfigData(device->property, drvData->linearCfgData) != HDF_SUCCESS) {
HDF_LOGE("%s: parser vibrator cfg fail", __func__);
return HDF_FAILURE;
} }
/* 注册马达Info信息初始化 */
value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_LRARESON; if (RegisterVibratorInfo(&drvData->linearCfgData->vibratorInfo) != HDF_SUCCESS) {
value[DRV2605L_VALUE_INDEX] = (uint8_t)&drvData->drv2605lCfgData->vibratorAttr.defaultFrequency; HDF_LOGE("%s: register vibrator info fail", __func__);
if (WriteDrv2605l(&drvData->drv2605lCfgData->vibratorBus.i2cCfg, value, sizeof(value)) != HDF_SUCCESS) { return HDF_FAILURE;
HDF_LOGE("%s: i2c addr [%0X] write failed", __func__, value[DRV2605L_ADDR_INDEX]);
} }
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; return HDF_SUCCESS;
} }
```
/* 设置马达振幅和频率 */ - 马达差异化驱动Release接口实现如下:
static void SetModulationParameter(int32_t intensity, int32_t frequency)
```c
void ReleaseLinearVibratorDriver(struct HdfDeviceObject *device)
{ {
uint8_t value[DRV2605L_VALUE_BUTT]; struct VibratorLinearDriverData *drvData = NULL;
struct Drv2605lDriverData *drvData = NULL;
drvData = GetDrv2605lDrvData(); 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;
}
```
- 马达差异化驱动内部接口实现如下:
```c
/* 触发振动马达 */
static int32_t StartLinearVibrator(void)
{
int32_t ret;
struct VibratorLinearDriverData *drvData = GetLinearVibratorData();
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE);
if (intensity != 0) { if (drvData->linearCfgData->vibratorBus.busType != VIBRATOR_BUS_GPIO) {
value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_RTPIN; HDF_LOGE("%s: vibrator bus type not gpio", __func__);
value[DRV2605L_VALUE_INDEX] = (uint8_t)INTENSITY_MAPPING_VALUE(intensity); return HDF_FAILURE;
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 \ ret = GpioWrite(drvData->linearCfgData->vibratorBus.GpioNum, GPIO_VAL_HIGH);
will be set as the system default intensity", __func__); 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;
}
/* 按照指定效果触发振动马达 */
static int32_t StartEffectLinearVibrator(uint32_t effectType)
{
(void)effectType;
HDF_LOGE("%s: vibrator set built-in effect no support!", __func__);
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 (frequency != 0) { if (drvData->linearCfgData->vibratorBus.busType != VIBRATOR_BUS_GPIO) {
value[DRV2605L_ADDR_INDEX] = (uint8_t)DRV2605_REG_LRARESON; HDF_LOGE("%s: vibrator bus type not gpio", __func__);
value[DRV2605L_VALUE_INDEX] = (uint8_t)FREQUENCY_MAPPING_VALUE(frequency); return HDF_FAILURE;
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 \ ret = GpioWrite(drvData->linearCfgData->vibratorBus.GpioNum, GPIO_VAL_LOW);
will be set as the system default frequency", __func__); 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++ - 参考测试代码如下:
/* 用例执行前,初始化马达接口实例。 */
void HdfVibratorTest::SetUpTestCase() ```c
{ #include <cmath>
#include <cstdio>
#include <gtest/gtest.h>
#include <securec.h>
#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(); g_vibratorDev = NewVibratorInterfaceInstance();
} }
/* 用例资源释放 */ /* 用例资源释放 */
void HdfVibratorTest::TearDownTestCase() void HdfVibratorTest::TearDownTestCase()
{ {
if(g_vibratorDev != nullptr){ if(g_vibratorDev != nullptr){
FreeVibratorInterfaceInstance(); FreeVibratorInterfaceInstance();
g_vibratorDev = nullptr; g_vibratorDev = nullptr;
} }
} }
void HdfVibratorTest::SetUp()
{
}
void HdfVibratorTest::TearDown()
{
}
/* 测试单次振动 */
HWTEST_F(HdfVibratorTest, PerformOneShotVibratorDuration_001, TestSize.Level1)
{
uint32_t duration = 1000;
uint32_t sleepTime = 2000;
/* 测试单次振动 */
HWTEST_F(HdfVibratorTest, PerformOneShotVibratorDuration_001, TestSize.Level1)
{
ASSERT_NE(nullptr, g_vibratorDev); ASSERT_NE(nullptr, g_vibratorDev);
int32_t startRet = g_vibratorDev->StartOnce(g_duration); int32_t startRet = g_vibratorDev->StartOnce(duration);
EXPECT_EQ(startRet, HDF_SUCCESS); EXPECT_EQ(startRet, HDF_SUCCESS);
OsalMSleep(g_sleepTime1); OsalMSleep(sleepTime);
int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE); int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE);
EXPECT_EQ(endRet, HDF_SUCCESS); EXPECT_EQ(endRet, HDF_SUCCESS);
} }
/* 测试预置效果振动 */ /* 测试预置效果振动 */
HWTEST_F(HdfVibratorTest, ExecuteVibratorEffect_002, TestSize.Level1) HWTEST_F(HdfVibratorTest, ExecuteVibratorEffect_001, TestSize.Level1)
{ {
uint32_t sleepTime = 5000;
const char *timeSequence = "haptic.clock.timer";
ASSERT_NE(nullptr, g_vibratorDev); ASSERT_NE(nullptr, g_vibratorDev);
int32_t startRet = g_vibratorDev->Start(g_builtIn); int32_t startRet = g_vibratorDev->Start(timeSequence);
EXPECT_EQ(startRet, HDF_SUCCESS); EXPECT_EQ(startRet, HDF_SUCCESS);
OsalMSleep(g_sleepTime1); OsalMSleep(sleepTime);
int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_PRESET); int32_t endRet = g_vibratorDev->Stop(VIBRATOR_MODE_PRESET);
EXPECT_EQ(endRet, HDF_SUCCESS); EXPECT_EQ(endRet, HDF_SUCCESS);
} }
/* 获取马达信息,包括是否支持振幅和频率的设置及振幅和频率的设置范围。 */ /* 获取马达信息,包括是否支持振幅和频率的设置及振幅和频率的设置范围。 */
HWTEST_F(HdfVibratorTest, GetVibratorInfo_001, TestSize.Level1) HWTEST_F(HdfVibratorTest, GetVibratorInfo_001, TestSize.Level1)
{ {
ASSERT_NE(nullptr, g_vibratorDev); ASSERT_NE(nullptr, g_vibratorDev);
int32_t startRet = g_vibratorDev->GetVibratorInfo(&g_vibratorInfo); int32_t startRet = g_vibratorDev->GetVibratorInfo(&g_vibratorInfo);
...@@ -539,26 +802,68 @@ HWTEST_F(HdfVibratorTest, GetVibratorInfo_001, TestSize.Level1) ...@@ -539,26 +802,68 @@ HWTEST_F(HdfVibratorTest, GetVibratorInfo_001, TestSize.Level1)
g_vibratorInfo->isSupportIntensity, g_vibratorInfo->intensityMaxValue, g_vibratorInfo->intensityMinValue); g_vibratorInfo->isSupportIntensity, g_vibratorInfo->intensityMaxValue, g_vibratorInfo->intensityMinValue);
printf("frequency = %d, frequencyMaxValue = %d, frequencyMinValue = %d\n\t", printf("frequency = %d, frequencyMaxValue = %d, frequencyMinValue = %d\n\t",
g_vibratorInfo->isSupportFrequency, g_vibratorInfo->frequencyMaxValue, g_vibratorInfo->frequencyMinValue); g_vibratorInfo->isSupportFrequency, g_vibratorInfo->frequencyMaxValue, g_vibratorInfo->frequencyMinValue);
} }
/* 按照指定振幅、频率、持续时间触发振动马达。duration为振动持续时长,intensity为振动强度,frequency为振动频率。 */ /* 按照指定振幅、频率、持续时间触发振动马达。duration为振动持续时长,intensity为振动强度,frequency为振动频率。 */
HWTEST_F(HdfVibratorTest, EnableVibratorModulation_001, TestSize.Level1) HWTEST_F(HdfVibratorTest, EnableVibratorModulation_001, TestSize.Level1)
{ {
int32_t startRet; int32_t startRet;
int32_t intensity = 30;
int32_t frequency = 200;
uint32_t duration = 1000;
uint32_t sleepTime = 2000;
ASSERT_NE(nullptr, g_vibratorDev); ASSERT_NE(nullptr, g_vibratorDev);
EXPECT_GT(g_duration, 0);
if ((g_vibratorInfo->isSupportIntensity == 1) || (g_vibratorInfo->isSupportFrequency == 1)) { if ((g_vibratorInfo->isSupportIntensity == 1) || (g_vibratorInfo->isSupportFrequency == 1)) {
EXPECT_GE(g_intensity1, g_vibratorInfo->intensityMinValue); EXPECT_GE(intensity, g_vibratorInfo->intensityMinValue);
EXPECT_LE(g_intensity1, g_vibratorInfo->intensityMaxValue); EXPECT_LE(intensity, g_vibratorInfo->intensityMaxValue);
EXPECT_GE(g_frequency1, g_vibratorInfo->frequencyMinValue); EXPECT_GE(frequency, g_vibratorInfo->frequencyMinValue);
EXPECT_LE(g_frequency1, g_vibratorInfo->frequencyMaxValue); EXPECT_LE(frequency, g_vibratorInfo->frequencyMaxValue);
startRet = g_vibratorDev->EnableVibratorModulation(g_duration, g_intensity1, g_frequency1); startRet = g_vibratorDev->EnableVibratorModulation(duration, intensity, duration);
EXPECT_EQ(startRet, HDF_SUCCESS); EXPECT_EQ(startRet, HDF_SUCCESS);
OsalMSleep(g_sleepTime1); OsalMSleep(sleepTime);
startRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE); startRet = g_vibratorDev->Stop(VIBRATOR_MODE_ONCE);
EXPECT_EQ(startRet, HDF_SUCCESS); 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"
}
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册