1# Motion 2 3## Overview 4 5### Function 6 7The motion module provides motion recognition and control capabilities. OpenHarmony supports recognition of pick-up, flip, shake, and rotation. 8 9The motion driver is developed based on the hardware driver foundation (HDF). It shields hardware differences and provides APIs for the Multimodal Sensor Data Platform (MSDP) to implement capabilities such as enabling or disabling motion recognition, and subscribing to or unsubscribing from motion recognition data. 10 11The following figure shows the motion driver architecture. The framework layer provides MSDP services, and interacts with the Motion Stub through the Motion Proxy in the User Hardware Driver Foundation (UHDF). The Motion Stub calls the Motion HDI Impl APIs to provide motion recognition capabilities for upper-layer services. 12 13**Figure 1** Motion driver architecture 14 15![](figures/motion_driver_architecture.png) 16 17### Working Principles 18 19The figure below illustrates how a motion driver works. 20 21**Figure 2** How a motion driver works 22 23![](figures/motion_driver_work.png) 24 251. MSDP: The MSDP service obtains a Motion HDI service instance from the Motion Proxy and calls the Motion HDI API. 262. IDL: The IService Manager allocates a Motion HDI instance requested by the MSDP service, and the Motion Proxy forwards the instance to the MSDP service. After the MSDP service calls the HDI API provided by the Motion Proxy, Motion Stub is called through Inter-Process Communication (IPC) to invoke the Motion Service API. The code is automatically generated by a tool and does not need to be developed by the component vendor. 273. HDI Service: The HDI service consists of Motion Interface Driver, Motion Service, and Motion Impl. Motion Interface Driver provides the motion driver code. A **HdfDriverEntry** structure is defined to implement the **Init**, **Bind**, and **Release** functions. The **HDF_INIT** macro is used to load the driver in the functions. Motion Service provides the motion recognition service interface class. The specific implementation is described in Motion Impl. The code of HDI Service must be developed by the component vendor. 28 29## Development Guidelines 30 31### When to Use 32 33The motion driver provides capabilities for the MSDP service to enable or disable motion recognition and subscribe to or unsubscribe from motion recognition data. It can be used for motion recognition when a user picks up, flips, shakes, and rotates a device. 34 35### Available APIs 36 37**Table 1** Available APIs 38 39| API | Description | 40| ------------------------------------------------------------ | ---------------------------- | 41| int32_t EnableMotion(int32_t motionType) | Enables motion recognition of the specified type. The motion recognition data can be obtained only after the motion recognition is enabled.| 42| int32_t DisableMotion(int32_t motionType) | Disables motion recognition of the specified type. | 43| int32_t Register(const sptr\<IMotionCallback\> &callbackObj) | Registers a callback for motion recognition so that the subscriber can receive the motion recognition data.| 44| int32_t Unregister(const sptr\<IMotionCallback\> &callbackObj) | Unregisters the motion recognition callback.| 45 46### How to Develop 47 48The development procedure is as follows: 49 501. Develop the user-mode driver for motion recognition based on the HDF. 512. Implement the **EnableMotion**, **DisableMotion**, **Register**, and **Unregister** APIs. 52 53The motion recognition directory structure is as follows: 54 55```undefined 56/drivers/peripheral/motion # Developed by the vendor. 57├── hdi_service # Driver capabilities provided by the motion recognition module for the MSDP service layer. 58├── test # Test code for the motion recognition module. 59│ └── unittest\hdi # HDI unit test code for the motion recognition module. 60``` 61 62The following describes how to develop a user-mode motion driver based on the HDF. For details, see [motion_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_interface_driver.cpp). 63 64You need to implement the **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions. The **Bind()** function binds the service capability with the driver; **Init()** implements the initialization required before the driver is loaded; **Release()** reclaims resources when **Init()** fails; **Dispatch()** implements the service, which is bound in **Bind()**. 65 66```c++ 67// Custom HdfMotionInterfaceHost object 68struct HdfMotionInterfaceHost { 69 struct IDeviceIoService ioService; 70 OHOS::sptr<OHOS::IRemoteObject> stub; 71}; 72 73// Enable the IPC service to call the response API. 74static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, 75 struct HdfSBuf *reply) 76{ 77 auto *hdfMotionInterfaceHost = CONTAINER_OF(client->device->service, struct HdfMotionInterfaceHost, ioService); 78 79 OHOS::MessageParcel *dataParcel = nullptr; 80 OHOS::MessageParcel *replyParcel = nullptr; 81 OHOS::MessageOption option; 82 83 if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { 84 HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__); 85 return HDF_ERR_INVALID_PARAM; 86 } 87 if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { 88 HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__); 89 return HDF_ERR_INVALID_PARAM; 90 } 91 92 return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); 93} 94 95// Initialize the HdfMotionInterface driver. 96int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject) 97{ 98 HDF_LOGI("HdfMotionInterfaceDriverInit enter"); 99 return HDF_SUCCESS; 100} 101 102// Bind the services provided by the motion driver to the HDF. 103int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject) 104{ 105 HDF_LOGI("HdfMotionInterfaceDriverBind enter"); 106 107 auto *hdfMotionInterfaceHost = new (std::nothrow) HdfMotionInterfaceHost; 108 if (hdfMotionInterfaceHost == nullptr) { 109 HDF_LOGE("%{public}s: failed to create HdfMotionInterfaceHost object", __func__); 110 return HDF_FAILURE; 111 } 112 113 hdfMotionInterfaceHost->ioService.Dispatch = MotionInterfaceDriverDispatch; 114 hdfMotionInterfaceHost->ioService.Open = NULL; 115 hdfMotionInterfaceHost->ioService.Release = NULL; 116 117 auto serviceImpl = IMotionInterface::Get(true); 118 if (serviceImpl == nullptr) { 119 HDF_LOGE("%{public}s: failed to get of implement service", __func__); 120 return HDF_FAILURE; 121 } 122 123 hdfMotionInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 124 IMotionInterface::GetDescriptor()); 125 if (hdfMotionInterfaceHost->stub == nullptr) { 126 HDF_LOGE("%{public}s: failed to get stub object", __func__); 127 return HDF_FAILURE; 128 } 129 130 deviceObject->service = &hdfMotionInterfaceHost->ioService; 131 return HDF_SUCCESS; 132} 133 134// Release the resources used by the motion driver. 135void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) 136{ 137 HDF_LOGI("HdfMotionInterfaceDriverRelease enter"); 138 auto *hdfMotionInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfMotionInterfaceHost, ioService); 139 delete hdfMotionInterfaceHost; 140 hdfMotionInterfaceHost = nullptr; 141} 142 143// Register the HDF driver entry g_motioninterfaceDriverEntry. 144struct HdfDriverEntry g_motioninterfaceDriverEntry = { 145 .moduleVersion = 1, 146 .moduleName = "motion_service", 147 .Bind = HdfMotionInterfaceDriverBind, 148 .Init = HdfMotionInterfaceDriverInit, 149 .Release = HdfMotionInterfaceDriverRelease, 150}; 151 152// Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind function and then the Init function. If the Init function fails to be called, the HDF will call Release to release driver resources and exit the driver model. 153HDF_INIT(g_userAuthInterfaceDriverEntry); 154``` 155 156### Verification 157 158The procedure is as follows: 159 1601. Call **IMotionInterface::Get()** to obtain a motion recognition instance and assign it with the **g_motionInterface** object of the **IMotionInterface** type. 161 1622. Call **Register()** using the **g_motionInterface** instance to register a callback. The callback needs to be designed based on service requirements. 163 1643. Call **EnableMotion** using the **g_motionInterface** instance to enable motion recognition of the specified type. Currently, **HDF_MOTION_TYPE_PICKUP**, **HDF_MOTION_TYPE_FLIP**, **HDF_MOTION_TYPE_SHAKE**, and **HDF_MOTION_TYPE_ROTATION** are supported. 165 1664. Call **DisableMotion** using the **g_motionInterface** instance to disable motion recognition. 167 1685. Call **Unregister** to unregister the callback for returning the motion data. The callback must have been registered. Otherwise, the **Unregister** will fail. 169 170 The sample code is as follows: 171 172 ```c++ 173 using namespace OHOS::HDI::Motion::V1_0; 174 using namespace testing::ext; 175 176 namespace { 177 sptr<IMotionInterface> g_motionInterface = nullptr; 178 sptr<IMotionCallback> g_motionCallback = new MotionCallbackService(); 179 sptr<IMotionCallback> g_motionCallbackUnregistered = new MotionCallbackService(); 180 } 181 182 class HdfMotionTest : public testing::Test { 183 public: 184 static void SetUpTestCase(); 185 static void TearDownTestCase(); 186 void SetUp(); 187 void TearDown(); 188 }; 189 190 void HdfMotionTest::SetUpTestCase() 191 { 192 // 1. Obtain a motion recognition instance. 193 g_motionInterface = IMotionInterface::Get(); 194 } 195 196 void HdfMotionTest::TearDownTestCase() 197 { 198 } 199 200 void HdfMotionTest::SetUp() 201 { 202 } 203 204 void HdfMotionTest::TearDown() 205 { 206 } 207 208 HWTEST_F(HdfMotionTest, EnableMotion_001, TestSize.Level1) 209 { 210 if (g_motionInterface == nullptr) { 211 ASSERT_NE(nullptr, g_motionInterface); 212 return; 213 } 214 215 vector<int> vec; 216 vec.push_back(HDF_MOTION_TYPE_PICKUP); 217 vec.push_back(HDF_MOTION_TYPE_FLIP); 218 vec.push_back(HDF_MOTION_TYPE_SHAKE); 219 vec.push_back(HDF_MOTION_TYPE_ROTATION); 220 221 // 2. Register a callback for subscribing to motion recognition data. 222 int32_t ret = g_motionInterface->Register(g_motionCallback); 223 EXPECT_EQ(HDF_SUCCESS, ret); 224 225 for (int i = 0; i < vec.size(); i++) { 226 // 3. Enable motion recognition. 227 ret = g_motionInterface->EnableMotion(vec[i]); 228 if (ret == HDF_SUCCESS) { 229 printf("Motion %d enabled successfully\n", vec[i]); 230 } else { 231 printf("Motion %d enable failed\n", vec[i]); 232 } 233 EXPECT_EQ(HDF_SUCCESS, ret); 234 OsalSleep(15); 235 // 4. Disable motion recognition. 236 ret = g_motionInterface->DisableMotion(vec[i]); 237 if (ret == HDF_SUCCESS) { 238 printf("Motion %d disabled successfully\n", vec[i]); 239 } else { 240 printf("Motion %d disable failed\n", vec[i]); 241 } 242 EXPECT_EQ(HDF_SUCCESS, ret); 243 OsalSleep(2); 244 } 245 // 5. Unregister the callback for returning the motion recognition data. 246 ret = g_motionInterface->Unregister(g_motionCallback); 247 EXPECT_EQ(HDF_SUCCESS, ret); 248 } 249 ``` 250 251