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 MSDP service obtains a Motion HDI service instance from the Motion Proxy and calls the Motion HDI API. The interface instance is allocated by IService Manager.  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**NOTE**<br>The following table lists the C++ function interfaces generated by the IDL interface description. For details about the interface declaration, see the IDL file [/drivers/interface/motion/v1_0/](https://gitee.com/openharmony/drivers_interface/tree/master/motion).
40
41| API                                                      | Description                    |
42| ------------------------------------------------------------ | ---------------------------- |
43| 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.|
44| int32_t DisableMotion(int32_t motionType)                    | Disables motion recognition of the specified type.            |
45| int32_t Register(const sptr\<IMotionCallback\> &callbackObj)   | Registers a callback for motion recognition so that the subscriber can receive the motion recognition data.|
46| int32_t Unregister(const sptr\<IMotionCallback\> &callbackObj) | Unregisters the motion recognition callback.|
47
48### How to Develop
49
50The development procedure is as follows:
51
521. Develop the user-mode driver for motion recognition based on the HDF.
53
542. Implement the **EnableMotion**, **DisableMotion**, **Register**, and **Unregister** APIs.
55
56The motion recognition directory structure is as follows:
57
58```
59/drivers/peripheral/motion            // Developed by the vendor.
60├── hdi_service              		 // Driver capability provided by the motion module for upper-layer services.
61├── test                              // Test codes for the motion module.
62   │   └── unittest\hdi               // HDI unit test code of the motion driver module.
63```
64
65The following describes how to develop a user-mode motion driver based on the HDF. For details, see [motion_if_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/motion/hdi_service/motion_if_driver.cpp).
66
67You 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()**.
68
69```c
70/* Custom HdfMotionInterfaceHost object. */
71struct HdfMotionInterfaceHost {
72    struct IDeviceIoService ioService;
73    OHOS::sptr<OHOS::IRemoteObject> stub;
74};
75
76/* Enable the IPC service to call the response API. */
77static int32_t MotionInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
78    struct HdfSBuf *reply)
79{
80    auto *hdfMotionInterfaceHost = CONTAINER_OF(client->device->service, struct HdfMotionInterfaceHost, ioService);
81
82    OHOS::MessageParcel *dataParcel = nullptr;
83    OHOS::MessageParcel *replyParcel = nullptr;
84    OHOS::MessageOption option;
85
86    if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
87        HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__);
88        return HDF_ERR_INVALID_PARAM;
89    }
90    if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
91        HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__);
92        return HDF_ERR_INVALID_PARAM;
93    }
94
95    return hdfMotionInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
96}
97
98/* Initialize the HdfMotionInterface driver. */
99int HdfMotionInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
100{
101    HDF_LOGI("HdfMotionInterfaceDriverInit enter");
102    return HDF_SUCCESS;
103}
104
105/* Bind the services provided by the motion driver to the HDF. */
106int HdfMotionInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
107{
108    HDF_LOGI("HdfMotionInterfaceDriverBind enter");
109
110    auto *hdfMotionInterfaceHost = new (std::nothrow) HdfMotionInterfaceHost;
111    if (hdfMotionInterfaceHost == nullptr) {
112        HDF_LOGE("%{public}s: failed to create HdfMotionInterfaceHost object", __func__);
113        return HDF_FAILURE;
114    }
115
116    hdfMotionInterfaceHost->ioService.Dispatch = MotionInterfaceDriverDispatch;
117    hdfMotionInterfaceHost->ioService.Open = NULL;
118    hdfMotionInterfaceHost->ioService.Release = NULL;
119
120    auto serviceImpl = IMotionInterface::Get(true);
121    if (serviceImpl == nullptr) {
122        HDF_LOGE("%{public}s: failed to get of implement service", __func__);
123        return HDF_FAILURE;
124    }
125
126    hdfMotionInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
127        IMotionInterface::GetDescriptor());
128    if (hdfMotionInterfaceHost->stub == nullptr) {
129        HDF_LOGE("%{public}s: failed to get stub object", __func__);
130        return HDF_FAILURE;
131    }
132
133    deviceObject->service = &hdfMotionInterfaceHost->ioService;
134    return HDF_SUCCESS;
135}
136
137/* Release the resources used by the motion driver. */
138void HdfMotionInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
139{
140    HDF_LOGI("HdfMotionInterfaceDriverRelease enter");
141    auto *hdfMotionInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfMotionInterfaceHost, ioService);
142    delete hdfMotionInterfaceHost;
143    hdfMotionInterfaceHost = nullptr;
144}
145
146/* Register the HDF driver entry g_motioninterfaceDriverEntry. */
147struct HdfDriverEntry g_motioninterfaceDriverEntry = {
148    .moduleVersion = 1,
149    .moduleName = "motion_service",
150    .Bind = HdfMotionInterfaceDriverBind,
151    .Init = HdfMotionInterfaceDriverInit,
152    .Release = HdfMotionInterfaceDriverRelease,
153};
154
155/* 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. */
156HDF_INIT(g_userAuthInterfaceDriverEntry);
157```
158
159### Verification
160
161The procedure is as follows:
162
1631. Call **IMotionInterface::Get()** to obtain a motion recognition instance and assign it with the **g_motionInterface** object of the **IMotionInterface** type.
164
1652. Call **Register()** using the **g_motionInterface** instance to register a callback. The callback needs to be designed based on service requirements.
166
1673. 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.
168
1694. Call **DisableMotion** using the **g_motionInterface** instance to disable motion recognition.
170
1715. Call **Unregister** to unregister the callback for returning the motion data. The callback must have been registered. Otherwise, the **Unregister** will fail.
172
173   The sample code is as follows:
174
175   ```c++
176   using namespace OHOS::HDI::Motion::V1_0;
177   using namespace testing::ext;
178
179   namespace {
180       sptr<IMotionInterface> g_motionInterface = nullptr;
181       sptr<IMotionCallback> g_motionCallback = new MotionCallbackService();
182       sptr<IMotionCallback> g_motionCallbackUnregistered = new MotionCallbackService();
183   }
184
185   class HdfMotionTest : public testing::Test {
186   public:
187       static void SetUpTestCase();
188       static void TearDownTestCase();
189       void SetUp();
190       void TearDown();
191   };
192
193   void HdfMotionTest::SetUpTestCase()
194   {
195       // 1. Obtain a motion recognition instance.
196       g_motionInterface = IMotionInterface::Get();
197   }
198
199   void HdfMotionTest::TearDownTestCase()
200   {
201   }
202
203   void HdfMotionTest::SetUp()
204   {
205   }
206
207   void HdfMotionTest::TearDown()
208   {
209   }
210
211   HWTEST_F(HdfMotionTest, EnableMotion_001, TestSize.Level1)
212   {
213       if (g_motionInterface == nullptr) {
214           ASSERT_NE(nullptr, g_motionInterface);
215           return;
216       }
217
218       vector<int> vec;
219       vec.push_back(HDF_MOTION_TYPE_PICKUP);
220       vec.push_back(HDF_MOTION_TYPE_FLIP);
221       vec.push_back(HDF_MOTION_TYPE_SHAKE);
222       vec.push_back(HDF_MOTION_TYPE_ROTATION);
223
224       // 2. Register a callback for subscribing to motion recognition data.
225       int32_t ret = g_motionInterface->Register(g_motionCallback);
226       EXPECT_EQ(HDF_SUCCESS, ret);
227
228       for (int i = 0; i < vec.size(); i++) {
229           // 3. Enable motion recognition.
230           ret = g_motionInterface->EnableMotion(vec[i]);
231           if (ret == HDF_SUCCESS) {
232               printf("Motion %d enabled successfully\n", vec[i]);
233           } else {
234               printf("Motion %d enable failed\n", vec[i]);
235           }
236           EXPECT_EQ(HDF_SUCCESS, ret);
237           OsalSleep(15);
238           // 4. Disable motion recognition.
239           ret = g_motionInterface->DisableMotion(vec[i]);
240           if (ret == HDF_SUCCESS) {
241               printf("Motion %d disabled successfully\n", vec[i]);
242           } else {
243               printf("Motion %d disable failed\n", vec[i]);
244           }
245           EXPECT_EQ(HDF_SUCCESS, ret);
246           OsalSleep(2);
247       }
248       // 5. Unregister the callback for returning the motion recognition data.
249       ret = g_motionInterface->Unregister(g_motionCallback);
250       EXPECT_EQ(HDF_SUCCESS, ret);
251   }
252   ```
253
254