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| 接口名 | 功能介绍 | 41| ------------------------------------------------------------ | ---------------------------- | 42| int32_t EnableMotion(int32_t motionType) | 使能一种手势识别类型,只有数据订阅者使能手势识别后,才能获取订阅的手势识别数据。 | 43| int32_t DisableMotion(int32_t motionType) | 去使能手势识别。 | 44| int32_t Register(const sptr\<IMotionCallback\> &callbackObj) | 订阅者成功注册手势识别数据回调函数,系统会将获取到的手势识别数据上报给订阅者。 | 45| int32_t Unregister(const sptr\<IMotionCallback\> &callbackObj) | 取消订阅手势识别数据回调函数。 | 46 47### 开发步骤 48 49开发步骤分为两个大步骤。 50 511. 基于HDF驱动框架,完成手势识别用户态驱动开发。 522. 厂商实现EnableMotion、DisableMotion、Register和Unregister接口功能。 53 54手势识别目录结构及各部分功能简介。 55 56```undefined 57/drivers/peripheral/motion # 此目录具体实现需要厂商根据自己的器件进行开发 58├── hdi_service # 手势识别模块对上层MSDP服务提供的驱动能力 59├── test # 手势识别模块测试代码 60│ └── unittest\hdi # 手势识别模块HDI单元测试代码 61``` 62 63下面结合DEMO实例,介绍如何基于HDF驱动框架,进行手势识别用户态驱动开发。具体实现请参考[motion_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_interface_driver.cpp)。 64 65手势识别用户态驱动开发, 主要完成Bind、Init、Release、Dispatch函数接口实现。其中Bind函数为驱动绑定对外提供的服务能力,Init函数为系统加载驱动前需要的一些初始化的操作,Release函数的主要作用为当系统加载驱动调用Init函数失败时对资源进行回收操作,Dispatch函数为服务能力的具体实现,在Bind函数中进行绑定。 66 67```c++ 68// 自定义的HdfMotionInterfaceHost对象 69struct HdfMotionInterfaceHost { 70 struct IDeviceIoService ioService; 71 OHOS::sptr<OHOS::IRemoteObject> stub; 72}; 73 74// 服务接口调用响应接口 75static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, 76 struct HdfSBuf *reply) 77{ 78 auto *hdfMotionInterfaceHost = CONTAINER_OF(client->device->service, struct HdfMotionInterfaceHost, ioService); 79 80 OHOS::MessageParcel *dataParcel = nullptr; 81 OHOS::MessageParcel *replyParcel = nullptr; 82 OHOS::MessageOption option; 83 84 if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { 85 HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__); 86 return HDF_ERR_INVALID_PARAM; 87 } 88 if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { 89 HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__); 90 return HDF_ERR_INVALID_PARAM; 91 } 92 93 return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); 94} 95 96// 初始化接口 97int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject) 98{ 99 HDF_LOGI("HdfMotionInterfaceDriverInit enter"); 100 return HDF_SUCCESS; 101} 102 103// Motion驱动对外提供的服务绑定到HDF框架 104int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) 105{ 106 HDF_LOGI("HdfMotionInterfaceDriverBind enter"); 107 108 auto *hdfMotionInterfaceHost = new (std::nothrow) HdfMotionInterfaceHost; 109 if (hdfMotionInterfaceHost == nullptr) { 110 HDF_LOGE("%{public}s: failed to create HdfMotionInterfaceHost object", __func__); 111 return HDF_FAILURE; 112 } 113 114 hdfMotionInterfaceHost->ioService.Dispatch = MotionInterfaceDriverDispatch; 115 hdfMotionInterfaceHost->ioService.Open = NULL; 116 hdfMotionInterfaceHost->ioService.Release = NULL; 117 118 auto serviceImpl = IMotionInterface::Get(true); 119 if (serviceImpl == nullptr) { 120 HDF_LOGE("%{public}s: failed to get of implement service", __func__); 121 return HDF_FAILURE; 122 } 123 124 hdfMotionInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 125 IMotionInterface::GetDescriptor()); 126 if (hdfMotionInterfaceHost->stub == nullptr) { 127 HDF_LOGE("%{public}s: failed to get stub object", __func__); 128 return HDF_FAILURE; 129 } 130 131 deviceObject->service = &hdfMotionInterfaceHost->ioService; 132 return HDF_SUCCESS; 133} 134 135// 释放Motion驱动中的资源 136void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) 137{ 138 HDF_LOGI("HdfMotionInterfaceDriverRelease enter"); 139 auto *hdfMotionInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfMotionInterfaceHost, ioService); 140 delete hdfMotionInterfaceHost; 141 hdfMotionInterfaceHost = nullptr; 142} 143 144// 注册Motion驱动入口数据结构体对象 145struct HdfDriverEntry g_motioninterfaceDriverEntry = { 146 .moduleVersion = 1, 147 .moduleName = "motion_service", 148 .Bind = HdfMotionInterfaceDriverBind, 149 .Init = HdfMotionInterfaceDriverInit, 150 .Release = HdfMotionInterfaceDriverRelease, 151}; 152 153// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 154HDF_INIT(g_userAuthInterfaceDriverEntry); 155``` 156 157### 调测验证 158 159测试代码开发步骤: 160 1611. 通过调用IMotionInterface::Get()获取到手势识别实例,并赋给IMotionInterface类型的智能指针对象g_motionInterface。 162 1632. 通过g_motionInterface实例调用Register接口注册回调,回调函数需要根据自己的需求来设计。 164 1653. 通过g_motionInterface实例调用EnableMotion接口使能Motion类型,当前支持拿起(HDF_MOTION_TYPE_PICKUP)、翻转(HDF_MOTION_TYPE_FLIP)、摇一摇(HDF_MOTION_TYPE_SHAKE)、旋转(HDF_MOTION_TYPE_ROTATION)等手势识别类型。 166 1674. 通过g_motionInterface实例调用DisableMotion接口去使能手势识别类型。 168 1695. 通过g_motionInterface实例调用Unregister取消订阅Motion数据回调函数。注意取消订阅必须先调用Register接口注册回调,否则Unregister会返回失败。 170 171 测试代码实例如下: 172 173 ```c++ 174 using namespace OHOS::HDI::Motion::V1_0; 175 using namespace testing::ext; 176 177 namespace { 178 sptr<IMotionInterface> g_motionInterface = nullptr; 179 sptr<IMotionCallback> g_motionCallback = new MotionCallbackService(); 180 sptr<IMotionCallback> g_motionCallbackUnregistered = new MotionCallbackService(); 181 } 182 183 class HdfMotionTest : public testing::Test { 184 public: 185 static void SetUpTestCase(); 186 static void TearDownTestCase(); 187 void SetUp(); 188 void TearDown(); 189 }; 190 191 void HdfMotionTest::SetUpTestCase() 192 { 193 // 1.获取手势识别实例 194 g_motionInterface = IMotionInterface::Get(); 195 } 196 197 void HdfMotionTest::TearDownTestCase() 198 { 199 } 200 201 void HdfMotionTest::SetUp() 202 { 203 } 204 205 void HdfMotionTest::TearDown() 206 { 207 } 208 209 HWTEST_F(HdfMotionTest, EnableMotion_001, TestSize.Level1) 210 { 211 if (g_motionInterface == nullptr) { 212 ASSERT_NE(nullptr, g_motionInterface); 213 return; 214 } 215 216 vector<int> vec; 217 vec.push_back(HDF_MOTION_TYPE_PICKUP); 218 vec.push_back(HDF_MOTION_TYPE_FLIP); 219 vec.push_back(HDF_MOTION_TYPE_SHAKE); 220 vec.push_back(HDF_MOTION_TYPE_ROTATION); 221 222 // 2.订阅手势识别数据回调函数 223 int32_t ret = g_motionInterface->Register(g_motionCallback); 224 EXPECT_EQ(HDF_SUCCESS, ret); 225 226 for (int i = 0; i < vec.size(); i++) { 227 // 3.使能手势识别 228 ret = g_motionInterface->EnableMotion(vec[i]); 229 if (ret == HDF_SUCCESS) { 230 printf("Motion %d enabled successfully\n", vec[i]); 231 } else { 232 printf("Motion %d enable failed\n", vec[i]); 233 } 234 EXPECT_EQ(HDF_SUCCESS, ret); 235 OsalSleep(15); 236 // 4.去使能手势识别 237 ret = g_motionInterface->DisableMotion(vec[i]); 238 if (ret == HDF_SUCCESS) { 239 printf("Motion %d disabled successfully\n", vec[i]); 240 } else { 241 printf("Motion %d disable failed\n", vec[i]); 242 } 243 EXPECT_EQ(HDF_SUCCESS, ret); 244 OsalSleep(2); 245 } 246 // 5.取消订阅手势识别数据回调函数 247 ret = g_motionInterface->Unregister(g_motionCallback); 248 EXPECT_EQ(HDF_SUCCESS, ret); 249 } 250 ``` 251