1# Motion
2
3## 概述
4
5### 功能简介
6
7手势识别模块作为端侧设备不可或缺的一部分,为用户提供手势识别控制能力。当前支持的手势识别类型有拿起、翻转、摇一摇、旋转屏等。
8
9基于HDF(Hardware Driver Foundation)驱动框架开发的Motion驱动,能够屏蔽硬件器件差异,为上层MSDP(Multimodal Sensor
10Data Platform)服务层提供稳定的手势识别控制能力接口,包括手势识别使能/去使能、手势识别订阅/取消订阅等。
11
12Motion驱动框架如图1所示,上层为Framework层,提供MSDP服务,通过UHDF(User Hardware Driver Foundation)层的Motion Proxy与Motion Stub进行交互;而Motion Stub可调用Motion HDI实现类接口,从而实现上层服务的手势识别使能/去使能、手势识别订阅/取消订阅等能力。
13
14**图1** Motion驱动框架
15
16![1660105057660](figures/Motion驱动框架图.png)
17
18### 运作机制
19
20通过介绍Motion驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如图2所示:
21
22**图 2** Motion驱动运行图
23
24![1660122293156](figures/Motion驱动运行图.png)
25
261. MSDP:上层综合传感信息处理平台服务层,当HDI接口服务实例获取成功后可以直接调用Motion HDI接口。
272. IDL:接口抽象层。MSDP服务层首先从Motion Proxy获取到Motion HDI接口服务实例。而Motion Proxy获取到的接口实例是由IService Manager进行分配。当MSDP服务层成功获取到Motion HDI接口服务实例后,MSDP服务层就可以直接调用Motion Proxy中的HDI接口,然后通过IPC(Inter-Process Communication)调用到Motion Stub,从而调用到Motion Service的接口。这部分是由工具自动生成的代码,不用器件厂商自己开发。
283. HDI Service:HDI Service中包括Motion Interface Driver、Motion Service和Motion Impl三个部分。其中Motion Interface Driver为手势识别接口的驱动代码,在这部分驱动代码中通过定义一个struct HdfDriverEntry类型的结构体变量,实现此变量中的Init、Bind和Release函数描述驱动能力,函数内部通过HDF_INIT宏加载驱动。Motion Service为手势识别服务接口类,具体的实现在Motion Impl中描述。此部分代码需要器件厂商根据自己器件来开发。
29
30## 开发指导
31
32### 场景介绍
33
34Motion驱动的主要工作是为上层MSDP服务提供稳定的使能/去使能手势识别服务,订阅/取消订阅手势识别数据回调函数的功能。可应用于拿起、翻转、摇一摇、旋转屏等手势识别场景。
35
36### 接口说明
37
38**表1** 接口功能介绍
39
40注:以下接口列举的为IDL接口描述生成的对应C++语言函数接口,接口声明见idl文件[/drivers/interface/motion/v1_0/](https://gitee.com/openharmony/drivers_interface/tree/master/motion)41
42| 接口名                                                       | 功能介绍                     |
43| ------------------------------------------------------------ | ---------------------------- |
44| int32_t EnableMotion(int32_t motionType)                     | 使能一种手势识别类型,只有数据订阅者使能手势识别后,才能获取订阅的手势识别数据。 |
45| int32_t DisableMotion(int32_t motionType)                    | 去使能手势识别。             |
46| int32_t Register(const sptr\<IMotionCallback\> &callbackObj)   | 订阅者成功注册手势识别数据回调函数,系统会将获取到的手势识别数据上报给订阅者。 |
47| int32_t Unregister(const sptr\<IMotionCallback\> &callbackObj) | 取消订阅手势识别数据回调函数。 |
48
49### 开发步骤
50
51开发步骤分为两个大步骤。
52
531. 基于HDF驱动框架,完成手势识别用户态驱动开发。
54
552. 厂商实现EnableMotion、DisableMotion、Register和Unregister接口功能。
56
57手势识别目录结构及各部分功能简介。
58
59```
60/drivers/peripheral/motion           // 此目录具体实现需要厂商根据自己的器件进行开发
61├── hdi_service              		 // motion模块对上层服务提供的驱动能力
62├── test                             // motion模块测试代码
63   └── unittest\hdi                  // motion模块hdi单元测试代码
64```
65
66下面结合DEMO实例,介绍如何基于HDF驱动框架,进行手势识别用户态驱动开发。具体实现请参考[motion_if_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_if_driver.cpp)67
68手势识别用户态驱动开发, 主要完成Bind、Init、Release、Dispatch函数接口实现。其中Bind函数为驱动绑定对外提供的服务能力,Init函数为系统加载驱动前需要的一些初始化的操作,Release函数的主要作用为当系统加载驱动调用Init函数失败时对资源进行回收操作,Dispatch函数为服务能力的具体实现,在Bind函数中进行绑定。
69
70```c
71/* 自定义的HdfMotionInterfaceHost对象 */
72struct HdfMotionInterfaceHost {
73    struct IDeviceIoService ioService;
74    OHOS::sptr<OHOS::IRemoteObject> stub;
75};
76
77/* 服务接口调用响应接口 */
78static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
79    struct HdfSBuf *reply)
80{
81    auto *hdfMotionInterfaceHost = CONTAINER_OF(client->device->service, struct HdfMotionInterfaceHost, ioService);
82
83    OHOS::MessageParcel *dataParcel = nullptr;
84    OHOS::MessageParcel *replyParcel = nullptr;
85    OHOS::MessageOption option;
86
87    if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
88        HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__);
89        return HDF_ERR_INVALID_PARAM;
90    }
91    if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
92        HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__);
93        return HDF_ERR_INVALID_PARAM;
94    }
95
96    return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
97}
98
99/* 初始化接口 */
100int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
101{
102    HDF_LOGI("HdfMotionInterfaceDriverInit enter");
103    return HDF_SUCCESS;
104}
105
106/* Motion驱动对外提供的服务绑定到HDF框架 */
107int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
108{
109    HDF_LOGI("HdfMotionInterfaceDriverBind enter");
110
111    auto *hdfMotionInterfaceHost = new (std::nothrow) HdfMotionInterfaceHost;
112    if (hdfMotionInterfaceHost == nullptr) {
113        HDF_LOGE("%{public}s: failed to create HdfMotionInterfaceHost object", __func__);
114        return HDF_FAILURE;
115    }
116
117    hdfMotionInterfaceHost->ioService.Dispatch = MotionInterfaceDriverDispatch;
118    hdfMotionInterfaceHost->ioService.Open = NULL;
119    hdfMotionInterfaceHost->ioService.Release = NULL;
120
121    auto serviceImpl = IMotionInterface::Get(true);
122    if (serviceImpl == nullptr) {
123        HDF_LOGE("%{public}s: failed to get of implement service", __func__);
124        return HDF_FAILURE;
125    }
126
127    hdfMotionInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
128        IMotionInterface::GetDescriptor());
129    if (hdfMotionInterfaceHost->stub == nullptr) {
130        HDF_LOGE("%{public}s: failed to get stub object", __func__);
131        return HDF_FAILURE;
132    }
133
134    deviceObject->service = &hdfMotionInterfaceHost->ioService;
135    return HDF_SUCCESS;
136}
137
138/* 释放Motion驱动中的资源 */
139void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
140{
141    HDF_LOGI("HdfMotionInterfaceDriverRelease enter");
142    auto *hdfMotionInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfMotionInterfaceHost, ioService);
143    delete hdfMotionInterfaceHost;
144    hdfMotionInterfaceHost = nullptr;
145}
146
147/* 注册Motion驱动入口数据结构体对象 */
148struct HdfDriverEntry g_motioninterfaceDriverEntry = {
149    .moduleVersion = 1,
150    .moduleName = "motion_service",
151    .Bind = HdfMotionInterfaceDriverBind,
152    .Init = HdfMotionInterfaceDriverInit,
153    .Release = HdfMotionInterfaceDriverRelease,
154};
155
156/* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
157HDF_INIT(g_userAuthInterfaceDriverEntry);
158```
159
160### 调测验证
161
162测试代码开发步骤:
163
1641. 通过调用IMotionInterface::Get()获取到手势识别实例,并赋给IMotionInterface类型的智能指针对象g_motionInterface。
165
1662. 通过g_motionInterface实例调用Register接口注册回调,回调函数需要根据自己的需求来设计。
167
1683. 通过g_motionInterface实例调用EnableMotion接口使能Motion类型,当前支持拿起(HDF_MOTION_TYPE_PICKUP)、翻转(HDF_MOTION_TYPE_FLIP)、摇一摇(HDF_MOTION_TYPE_SHAKE)、旋转(HDF_MOTION_TYPE_ROTATION)等手势识别类型。
169
1704. 通过g_motionInterface实例调用DisableMotion接口去使能手势识别类型。
171
1725. 通过g_motionInterface实例调用Unregister取消订阅Motion数据回调函数。注意取消订阅必须先调用Register接口注册回调,否则Unregister会返回失败。
173
174   测试代码实例如下:
175
176   ```c++
177   using namespace OHOS::HDI::Motion::V1_0;
178   using namespace testing::ext;
179
180   namespace {
181       sptr<IMotionInterface> g_motionInterface = nullptr;
182       sptr<IMotionCallback> g_motionCallback = new MotionCallbackService();
183       sptr<IMotionCallback> g_motionCallbackUnregistered = new MotionCallbackService();
184   }
185
186   class HdfMotionTest : public testing::Test {
187   public:
188       static void SetUpTestCase();
189       static void TearDownTestCase();
190       void SetUp();
191       void TearDown();
192   };
193
194   void HdfMotionTest::SetUpTestCase()
195   {
196       // 1.获取手势识别实例
197       g_motionInterface = IMotionInterface::Get();
198   }
199
200   void HdfMotionTest::TearDownTestCase()
201   {
202   }
203
204   void HdfMotionTest::SetUp()
205   {
206   }
207
208   void HdfMotionTest::TearDown()
209   {
210   }
211
212   HWTEST_F(HdfMotionTest, EnableMotion_001, TestSize.Level1)
213   {
214       if (g_motionInterface == nullptr) {
215           ASSERT_NE(nullptr, g_motionInterface);
216           return;
217       }
218
219       vector<int> vec;
220       vec.push_back(HDF_MOTION_TYPE_PICKUP);
221       vec.push_back(HDF_MOTION_TYPE_FLIP);
222       vec.push_back(HDF_MOTION_TYPE_SHAKE);
223       vec.push_back(HDF_MOTION_TYPE_ROTATION);
224
225       // 2.订阅手势识别数据回调函数
226       int32_t ret = g_motionInterface->Register(g_motionCallback);
227       EXPECT_EQ(HDF_SUCCESS, ret);
228
229       for (int i = 0; i < vec.size(); i++) {
230           // 3.使能手势识别
231           ret = g_motionInterface->EnableMotion(vec[i]);
232           if (ret == HDF_SUCCESS) {
233               printf("Motion %d enabled successfully\n", vec[i]);
234           } else {
235               printf("Motion %d enable failed\n", vec[i]);
236           }
237           EXPECT_EQ(HDF_SUCCESS, ret);
238           OsalSleep(15);
239           // 4.去使能手势识别
240           ret = g_motionInterface->DisableMotion(vec[i]);
241           if (ret == HDF_SUCCESS) {
242               printf("Motion %d disabled successfully\n", vec[i]);
243           } else {
244               printf("Motion %d disable failed\n", vec[i]);
245           }
246           EXPECT_EQ(HDF_SUCCESS, ret);
247           OsalSleep(2);
248       }
249       // 5.取消订阅手势识别数据回调函数
250       ret = g_motionInterface->Unregister(g_motionCallback);
251       EXPECT_EQ(HDF_SUCCESS, ret);
252   }
253   ```
254