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