Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Docs
提交
b3d55a03
D
Docs
项目概览
OpenHarmony
/
Docs
1 年多 前同步成功
通知
159
Star
292
Fork
28
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
Docs
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
b3d55a03
编写于
6月 12, 2023
作者:
O
openharmony_ci
提交者:
Gitee
6月 12, 2023
浏览文件
操作
浏览文件
下载
差异文件
!19268 fix:modfiy light、sensor、motion and vibrator delvelop guide optimization
Merge pull request !19268 from sunxuejiao/master
上级
c76e0e4d
5524183e
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
2254 addition
and
1183 deletion
+2254
-1183
zh-cn/device-dev/driver/driver-peripherals-light-des.md
zh-cn/device-dev/driver/driver-peripherals-light-des.md
+768
-297
zh-cn/device-dev/driver/driver-peripherals-motion-des.md
zh-cn/device-dev/driver/driver-peripherals-motion-des.md
+17
-14
zh-cn/device-dev/driver/driver-peripherals-sensor-des.md
zh-cn/device-dev/driver/driver-peripherals-sensor-des.md
+742
-450
zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md
zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md
+727
-422
未找到文件。
zh-cn/device-dev/driver/driver-peripherals-light-des.md
浏览文件 @
b3d55a03
...
...
@@ -19,7 +19,7 @@ Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接

以标准系统
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
\h
ihope
\r
k3568
\h
df_config
\k
hdf
\d
evice_info
\d
evice_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
\h
ihope
\r
k3568
\h
df_config
\k
hdf
\l
ight
\l
ight_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
\h
df_core
\f
ramework
\m
odel
\m
isc
\l
ight
\d
river
\s
rc
\l
ight_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
\p
eripheral
\l
ight
\h
al
\s
rc
\l
ight_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"
}
```
zh-cn/device-dev/driver/driver-peripherals-motion-des.md
浏览文件 @
b3d55a03
...
...
@@ -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_i
nterface_driver.cpp
](
https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_interface
_driver.cpp
)
。
下面结合DEMO实例,介绍如何基于HDF驱动框架,进行手势识别用户态驱动开发。具体实现请参考
[
motion_i
f_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
);
```
...
...
zh-cn/device-dev/driver/driver-peripherals-sensor-des.md
浏览文件 @
b3d55a03
...
...
@@ -27,7 +27,7 @@ Sensor驱动模型屏蔽硬件器件差异,为上层Sensor服务系统提供

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
\h
ihope
\r
k3568
\h
df_config
\k
hdf
\d
evice_info
\d
evice_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
\h
df_core
\f
ramework
\m
odel
\s
ensor
\d
river
\a
ccel
\s
ensor_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
\h
ihope
\r
k3568
\h
df_config
\k
hdf
\d
evice_info
\d
evice_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
\p
eripheral
\s
ensor
\c
hipset
\a
ccel
\a
ccel_mxc6655xa.c
- 加速度传感器差异化驱动对应的HdfDriverEntry对象,其中,Driver Entry入口函数定义如下:
```c
/* 注册加速度mxc6655xa传感器入口数据结构体对象 */
struct HdfDriverEntry g_accelMxc6655xaDevEntry = {
.moduleVersion = 1, // 加速度mxc6655xa传感器模块版本号
.moduleName = "HDF_SENSOR_ACCEL_MXC6655XA", // 加速度mxc6655xa传感器模块名,要与device_info.hcs文件里加速度mxc6655xa传感器moduleName字段值一致
.Bind = Mxc6655xaBindDriver, // 加速度mxc6655xa传感器的绑定函数
.Init = Mxc6655xaInitDriver, // 加速度mxc6655xa传感器的初始化函数
.Release = Mxc6655xaReleaseDriver, // 加速度mxc6655xa传感器资源释放函数
};
/* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
HDF_INIT(g_accelMxc6655xaDevEntry);
```
- 加速度传感器差异化驱动Bind接口实现如下:
```c
int32_t Mxc6655xaBindDriver(struct HdfDeviceObject *device)
{
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)OsalMemCalloc(sizeof(*drvData));
if (drvData == NULL) {
HDF_LOGE("%s: Malloc MXC6655XA drv data fail", __func__);
return HDF_ERR_MALLOC_FAIL;
}
drvData->ioService.Dispatch = DispatchMXC6655xa;
drvData->device = device;
device->service = &drvData->ioService;
g_mxc6655xaDrvData = drvData;
return HDF_SUCCESS;
}
ret
=
SetSensorRegCfgArray
(
&
drvData
->
accelCfg
->
busCfg
,
drvData
->
accelCfg
->
regCfgGroup
[
SENSOR_ENABLE_GROUP
]);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Accel sensor enable config failed"
,
__func__
);
return
ret
;
}
ret
=
OsalTimerCreate
(
&
drvData
->
accelTimer
,
SENSOR_TIMER_MIN_TIME
,
AccelTimerEntry
,
(
uintptr_t
)
drvData
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Accel create timer failed[%d]"
,
__func__
,
ret
);
return
ret
;
```
- 加速度传感器差异化驱动Init接口实现如下:
```c
int32_t Mxc6655xaInitDriver(struct HdfDeviceObject *device)
{
int32_t ret;
struct AccelOpsCall ops;
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service;
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
drvData->sensorCfg = AccelCreateCfgData(device->property);
if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {
HDF_LOGD("%s: Creating accelcfg failed because detection failed", __func__);
return HDF_ERR_NOT_SUPPORT;
}
ops.Init = NULL;
ops.ReadData = ReadMxc6655xaData;
ret = AccelRegisterChipOps(&ops);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Register MXC6655XA accel failed", __func__);
return HDF_FAILURE;
}
ret = InitMxc6655xa(drvData->sensorCfg);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Init MXC6655XA accel failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
ret
=
OsalTimerStartLoop
(
&
drvData
->
accelTimer
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Accel start timer failed[%d]"
,
__func__
,
ret
);
return
ret
;
```
- 加速度传感器差异化驱动Release接口实现如下:
```c
void Mxc6655xaReleaseDriver(struct HdfDeviceObject *device)
{
CHECK_NULL_PTR_RETURN(device);
struct Mxc6655xaDrvData *drvData = (struct Mxc6655xaDrvData *)device->service;
CHECK_NULL_PTR_RETURN(drvData);
if (drvData->sensorCfg != NULL) {
AccelReleaseCfgData(drvData->sensorCfg);
drvData->sensorCfg = NULL;
}
OsalMemFree(drvData);
}
drvData
->
enable
=
true
;
return
HDF_SUCCESS
;
}
/* 下发去使能寄存器组的配置 */
static
int32_t
SetAccelDisable
(
void
)
{
int32_t
ret
;
struct
AccelDrvData
*
drvData
=
AccelGetDrvData
();
CHECK_NULL_PTR_RETURN_VALUE
(
drvData
,
HDF_ERR_INVALID_PARAM
);
CHECK_NULL_PTR_RETURN_VALUE
(
drvData
->
accelCfg
,
HDF_ERR_INVALID_PARAM
);
if
(
!
drvData
->
enable
)
{
HDF_LOGE
(
"%s: Accel sensor had disable"
,
__func__
);
```
- 加速度传感器差异化驱动内部接口实现。
需要开发者实现的ReadMxc6655xaData接口函数,在 Mxc6655xaInitDriver函数里面注册此函数,具体实现如下:
```c
static int32_t ReadMxc6655xaRawData(struct SensorCfgData *data, struct AccelData *rawData, uint64_t *timestamp)
{
uint8_t status = 0;
uint8_t reg[ACCEL_AXIS_BUTT];
OsalTimespec time;
int32_t x;
int32_t y;
int32_t z;
(void)memset_s(&time, sizeof(time), 0, sizeof(time));
(void)memset_s(reg, sizeof(reg), 0, sizeof(reg));
CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
if (OsalGetTime(&time) != HDF_SUCCESS) {
HDF_LOGE("%s: Get time failed", __func__);
return HDF_FAILURE;
}
*timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT; /* unit nanosecond */
int32_t ret = ReadSensor(&data->busCfg, MXC6655XA_STATUS_ADDR, &status, sizeof(uint8_t));
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: data status [%u] ret [%d]", __func__, status, ret);
return HDF_FAILURE;
}
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_LSB_ADDR, ®[ACCEL_X_AXIS_LSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_X_MSB_ADDR, ®[ACCEL_X_AXIS_MSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_LSB_ADDR, ®[ACCEL_Y_AXIS_LSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Y_MSB_ADDR, ®[ACCEL_Y_AXIS_MSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_LSB_ADDR, ®[ACCEL_Z_AXIS_LSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
ret = ReadSensor(&data->busCfg, MXC6655XA_ACCEL_Z_MSB_ADDR, ®[ACCEL_Z_AXIS_MSB], sizeof(uint8_t));
CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
x = SensorConvertData(reg[ACCEL_X_AXIS_MSB], reg[ACCEL_X_AXIS_LSB]);
y = SensorConvertData(reg[ACCEL_Y_AXIS_MSB], reg[ACCEL_Y_AXIS_LSB]);
z = SensorConvertData(reg[ACCEL_Z_AXIS_MSB], reg[ACCEL_Z_AXIS_LSB]);
rawData->x = x;
rawData->y = y;
rawData->z = z;
return HDF_SUCCESS;
}
ret
=
SetSensorRegCfgArray
(
&
drvData
->
accelCfg
->
busCfg
,
drvData
->
accelCfg
->
regCfgGroup
[
SENSOR_DISABLE_GROUP
]);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Accel sensor disable config failed"
,
__func__
);
return
ret
;
}
ret
=
OsalTimerDelete
(
&
drvData
->
accelTimer
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Accel delete timer failed"
,
__func__
);
/* 读取加速度的event数据,在 Mxc6655xaInitDriver函数里面注册此函数,将数据传给加速度抽象驱动 */
int32_t ReadMxc6655xaData(struct SensorCfgData *cfg, struct SensorReportEvent *event)
{
int32_t ret;
struct AccelData rawData = { 0, 0, 0 };
static int32_t tmp[ACCEL_AXIS_NUM];
CHECK_NULL_PTR_RETURN_VALUE(cfg, HDF_ERR_INVALID_PARAM);
CHECK_NULL_PTR_RETURN_VALUE(event, HDF_ERR_INVALID_PARAM);
ret = ReadMxc6655xaRawData(cfg, &rawData, &event->timestamp);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: MXC6655XA read raw data failed", __func__);
return HDF_FAILURE;
}
event->sensorId = SENSOR_TAG_ACCELEROMETER;
event->option = 0;
event->mode = SENSOR_WORK_MODE_REALTIME;
rawData.x = rawData.x * MXC6655XA_ACC_SENSITIVITY_2G;
rawData.y = rawData.y * MXC6655XA_ACC_SENSITIVITY_2G;
rawData.z = rawData.z * MXC6655XA_ACC_SENSITIVITY_2G;
tmp[ACCEL_X_AXIS] = (rawData.x * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;
tmp[ACCEL_Y_AXIS] = (rawData.y * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;
tmp[ACCEL_Z_AXIS] = (rawData.z * SENSOR_CONVERT_UNIT) / SENSOR_CONVERT_UNIT;
ret = SensorRawDataToRemapData(cfg->direction, tmp, sizeof(tmp) / sizeof(tmp[0]));
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: MXC6655XA convert raw data failed", __func__);
return HDF_FAILURE;
}
event->dataLen = sizeof(tmp);
event->data = (uint8_t *)&tmp;
return ret;
}
drvData
->
enable
=
false
;
return
HDF_SUCCESS
;
}
/* 配置传感器采样率和数据上报间隔 */
static
int32_t
SetAccelBatch
(
int64_t
samplingInterval
,
int64_t
interval
)
{
(
void
)
interval
;
struct
AccelDrvData
*
drvData
=
NULL
;
drvData
=
AccelGetDrvData
();
CHECK_NULL_PTR_RETURN_VALUE
(
drvData
,
HDF_ERR_INVALID_PARAM
);
drvData
->
interval
=
samplingInterval
;
return
HDF_SUCCESS
;
}
/* 设置传感器工作模式,当前支持实时模式 */
static
int32_t
SetAccelMode
(
int32_t
mode
)
{
return
(
mode
==
SENSOR_WORK_MODE_REALTIME
)
?
HDF_SUCCESS
:
HDF_FAILURE
;
}
static
int32_t
SetAccelOption
(
uint32_t
option
)
{
(
void
)
option
;
return
HDF_SUCCESS
;
}
/* 设置传感器可选配置 */
static
int32_t
SetAccelOption
(
uint32_t
option
)
{
(
void
)
option
;
return
HDF_ERR_NOT_SUPPORT
;
}
```
4.
基于HDF驱动框架,按照驱动Driver Entry程序,完成加速度传感器差异化驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。
```
c
/* 加速度计传感器差异化驱动消息交互 */
static
int32_t
DispatchBMI160
(
struct
HdfDeviceIoClient
*
client
,
int
cmd
,
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
{
(
void
)
client
;
(
void
)
cmd
;
(
void
)
data
;
(
void
)
reply
;
return
HDF_SUCCESS
;
}
/* 加速度计传感器差异化驱动对外提供的服务绑定到HDF框架 */
int32_t
Bmi160BindDriver
(
struct
HdfDeviceObject
*
device
)
{
CHECK_NULL_PTR_RETURN_VALUE
(
device
,
HDF_ERR_INVALID_PARAM
);
struct
Bmi160DrvData
*
drvData
=
(
struct
Bmi160DrvData
*
)
OsalMemCalloc
(
sizeof
(
*
drvData
));
if
(
drvData
==
NULL
)
{
HDF_LOGE
(
"%s: Malloc Bmi160 drv data fail"
,
__func__
);
return
HDF_ERR_MALLOC_FAIL
;
}
drvData
->
ioService
.
Dispatch
=
DispatchBMI160
;
drvData
->
device
=
device
;
device
->
service
=
&
drvData
->
ioService
;
g_bmi160DrvData
=
drvData
;
return
HDF_SUCCESS
;
}
/* 加速度计传感器差异化驱动初始化 */
int32_t
Bmi160InitDriver
(
struct
HdfDeviceObject
*
device
)
{
int32_t
ret
;
struct
AccelOpsCall
ops
;
CHECK_NULL_PTR_RETURN_VALUE
(
device
,
HDF_ERR_INVALID_PARAM
);
struct
Bmi160DrvData
*
drvData
=
(
struct
Bmi160DrvData
*
)
device
->
service
;
CHECK_NULL_PTR_RETURN_VALUE
(
drvData
,
HDF_ERR_INVALID_PARAM
);
ret
=
InitAccelPreConfig
();
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Init BMI160 bus mux config"
,
__func__
);
return
HDF_FAILURE
;
}
drvData
->
sensorCfg
=
AccelCreateCfgData
(
device
->
property
);
if
(
drvData
->
sensorCfg
==
NULL
||
drvData
->
sensorCfg
->
root
==
NULL
)
{
HDF_LOGD
(
"%s: Creating accelcfg failed because detection failed"
,
__func__
);
return
HDF_ERR_NOT_SUPPORT
;
}
ops
.
Init
=
NULL
;
ops
.
ReadData
=
ReadBmi160Data
;
ret
=
AccelRegisterChipOps
(
&
ops
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Register BMI160 accel failed"
,
__func__
);
return
HDF_FAILURE
;
}
ret
=
InitBmi160
(
drvData
->
sensorCfg
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Init BMI160 accel failed"
,
__func__
);
return
HDF_FAILURE
;
}
return
HDF_SUCCESS
;
}
/* 释放驱动初始化时分配的资源 */
void
Bmi160ReleaseDriver
(
struct
HdfDeviceObject
*
device
)
{
......
if
(
drvData
->
sensorCfg
!=
NULL
)
{
AccelReleaseCfgData
(
drvData
->
sensorCfg
);
drvData
->
sensorCfg
=
NULL
;
}
OsalMemFree
(
drvData
);
}
/* 加速度传感器差异化驱动对应的HdfDriverEntry对象 */
struct
HdfDriverEntry
g_accelBmi160DevEntry
=
{
.
moduleVersion
=
1
,
.
moduleName
=
"HDF_SENSOR_ACCEL_BMI160"
,
.
Bind
=
Bmi160BindDriver
,
.
Init
=
Bmi160InitDriver
,
.
Release
=
Bmi160ReleaseDriver
,
};
HDF_INIT
(
g_accelBmi160DevEntry
);
```
5.
完成加速度传感器差异化驱动中差异化接口ReadData函数实现。
```
c
int32_t
ReadBmi160Data
(
struct
SensorCfgData
*
data
)
{
int32_t
ret
;
struct
AccelData
rawData
=
{
0
,
0
,
0
};
int32_t
tmp
[
ACCEL_AXIS_NUM
];
struct
SensorReportEvent
event
;
(
void
)
memset_s
(
&
event
,
sizeof
(
event
),
0
,
sizeof
(
event
));
ret
=
ReadBmi160RawData
(
data
,
&
rawData
,
&
event
.
timestamp
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: BMI160 read raw data failed"
,
__func__
);
return
HDF_FAILURE
;
}
event
.
sensorId
=
SENSOR_TAG_ACCELEROMETER
;
event
.
option
=
0
;
event
.
mode
=
SENSOR_WORK_MODE_REALTIME
;
……
ret
=
ReportSensorEvent
(
&
event
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: BMI160 report data failed"
,
__func__
);
}
return
ret
;
}
```
```
### 调测验证
驱动开发完成后,在传感器单元测试里面开发自测试用例,验证驱动基本功能。测试环境采用开发者自测试平台。
```
c++
static
int32_t
g_sensorDataFlag
=
0
;
// 标识是否上报传感器数据
static
const
struct
SensorInterface
*
g_sensorDev
=
nullptr
;
// 保持获取的传感器接口实例地址
/* 订阅者注册数据上报函数 */
static
int
SensorTestDataCallback
(
struct
SensorEvents
*
event
)
{
if
(
event
==
nullptr
)
{
return
-
1
;
}
float
*
data
=
(
float
*
)
event
->
data
;
printf
(
"time [%lld] sensor id [%d] x-[%f] y-[%f] z-[%f]
\n\r
"
,
event
->
timestamp
,
event
->
sensorId
,
(
*
data
),
*
(
data
+
1
),
*
(
data
+
g_axisZ
));
if
(
*
data
>
1e-5
)
{
g_sensorDataFlag
=
1
;
}
return
0
;
}
/* 用例执行前,初始化传感器接口实例 */
void
HdfSensorTest
::
SetUpTestCase
()
{
g_sensorDev
=
NewSensorInterfaceInstance
();
if
(
g_sensorDev
==
nullptr
)
{
printf
(
"test sensor get module instance failed
\n\r
"
);
}
}
/* 用例资源释放 */
void
HdfSensorTest
::
TearDownTestCase
()
{
if
(
g_sensorDev
!=
nullptr
)
{
FreeSensorInterfaceInstance
();
g_sensorDev
=
nullptr
;
}
}
/* 传感器驱动测试验证 */
HWTEST_F
(
HdfSensorTest
,
TestAccelDriver_001
,
TestSize
.
Level0
)
{
int32_t
sensorInterval
=
1000000000
;
// 数据采样率单位纳秒
int32_t
pollTime
=
5
;
// 数据采样时间单位秒
int32_t
accelSensorId
=
1
;
// 加速度传感器类型标识为1
int32_t
count
=
0
;
int
ret
;
struct
SensorInformation
*
sensorInfo
=
nullptr
;
ret
=
g_sensorDev
->
Register
(
0
,
TraditionSensorTestDataCallback
)
EXPECT_EQ
(
SENSOR_NULL_PTR
,
ret
);
ret
=
g_sensorDev
->
GetAllSensors
(
&
sensorInfo
,
&
count
);
EXPECT_EQ
(
0
,
ret
);
if
(
sensorInfo
==
nullptr
)
{
EXPECT_NE
(
nullptr
,
sensorInfo
);
return
;
}
/* 打印获取的传感器列表 */
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
printf
(
"get sensorId[%d], info name[%s]
\n\r
"
,
sensorInfo
[
i
]
->
sensorId
,
sensorInfo
[
i
]
->
sensorName
);
}
ret
=
g_sensorDev
->
Enable
(
accelSensorId
);
EXPECT_EQ
(
0
,
ret
);
g_sensorDataFlag
=
0
;
ret
=
g_sensorDev
->
SetBatch
(
accelSensorId
,
sensorInterval
,
pollTime
);
EXPECT_EQ
(
0
,
ret
);
/* 在时间pollTime内,观察输出打印数据 */
OsalSleep
(
pollTime
);
EXPECT_EQ
(
1
,
g_sensorDataFlag
);
ret
=
g_sensorDev
->
Disable
(
accelSensorId
);
g_sensorDataFlag
=
0
;
EXPECT_EQ
(
0
,
ret
);
ret
=
g_sensorDev
->
Unregister
(
0
,
TraditionSensorTestDataCallback
);
EXPECT_EQ
(
0
,
ret
);
}
```
-
参考测试代码如下:
```
c
#include <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"
}
```
zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md
浏览文件 @
b3d55a03
...
...
@@ -40,7 +40,7 @@

以标准系统
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
\h
ihope
\r
k3568
\h
df_config
\k
hdf
\d
evice_info
\d
evice_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
\h
df_core
\f
ramework
\m
odel
\m
isc
\v
ibrator
\d
river
\s
rc
\v
ibrator_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: fail
ed
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 fail
ed
!", __func__);
HDF_LOGE("%s: parser haptic config fail!", __func__);
goto EXIT;
}
...
...
@@ -213,352 +142,728 @@ Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能
}
```
-
马达效果模型使用HCS作为配置描述源码,HCS配置文件字段详细介绍参考
[
配置管理
](
driver-hdf-manage.md
)
。
-
马达抽象驱动代码实现路径:drivers
\h
df_core
\f
ramework
\m
odel
\m
isc
\v
ibrator
\d
river
\s
rc
\v
ibrator_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
\h
ihope
\r
k3568
\h
df_config
\k
hdf
\d
evice_info
\d
evice_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
\p
eripheral
\v
ibrator
\c
hipset
\l
inear
\v
ibrator_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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录