driver-peripherals-vibrator-des.md 16.3 KB
Newer Older
W
wusongqing 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
# Vibrator

## Overview

### Introduction

Developed on the Hardware Driver Foundation (HDF), the vibrator driver model makes vibrator driver development easier. This model masks the interaction between the device driver and system, provides unified and stable driver interfaces for the hardware service layer, and offers open interfaces and interface parsing capabilities for driver developers. This document provides guidance for developing vibrator drivers and deploying vibrators in different OSs. The figure below shows the vibrator driver model.

**Figure 1** Vibrator driver model

![Vibrator driver model](figures/vibrator_driver_model.png)

### Basic Concepts

The system controls device vibration by invoking the vibrator. There are two vibration modes:

- One-shot vibration

  The vibrator vibrates for a specified duration.

- Periodic vibration

  The vibrator vibrates with a preset effect. For example, if the preset effect is "haptic.clock.timer" = [600, 600, 200, 600], the vibrator waits for 600 ms, vibrates for 600 ms, waits for 200 ms, and vibrates for 600 ms.

### Working Principles

Based on the loading and running process (shown below) of the vibrator driver model, the relationships between key modules in the model and associated modules are clearly defined.

**Figure 2** How vibrator driver works

![How vibrator driver works](figures/vibrator_working.png)

The following uses the vibrator driver on the Hi3516D V300 development board of the standard system as an example to describe the driver loading and running process.

1. The vibrator host reads the vibrator management configuration from the Vibrator Host node of the device_info HCS (vibrator device information HCS).
2. The vibrator host parses the vibrator management configuration and associates it with the corresponding vibrator abstract driver.
3. The vibrator host reads the vibrator data configuration from the linear_vibrator_config HCS (vibrator private configuration HCS).
4. The vibrator host parses the vibrator data configuration and associates it with the corresponding vibrator haptic driver.
5. The vibrator proxy delivers an instruction to the vibrator stub.
6. The vibrator stub calls the vibrator controller.
7. The vibrator host initializes the vibrator abstract driver interfaces.
8. The vibrator haptic driver starts a thread to parse the vibrator haptic module.
9. The vibrator haptic driver calls the **Start** interface in the vibrator abstract driver.
10. The vibrator abstract driver calls the **Start** interface in the vibrator chipset driver.

## Development Guidelines

### When to Use

You can set different vibration effects as needed, for example, customizing vibration effects with different intensities and durations for buttons on the device, and customizing one-shot or periodic vibration effects with different intensities and durations for alarm clocks and incoming calls.

### Available APIs

The vibrator driver model supports static HDF Configuration Source (HCS) configurations and dynamic parameter configurations. The vibrator hardware service calls the **StartOnce** interface to trigger continuous vibration and calls the **Start** interface to trigger vibration with a specified effect. The table below lists the APIs provided by the vibrator driver model for the hardware service layer.

**Table 1** External APIs of the vibrator driver model

| API                                | Description                                                |
| -------------------------------------- | -------------------------------------------------------- |
| int32_t  StartOnce(uint32_t duration)  | Triggers vibration with a given **duration**.  |
| int32_t  Start(const char *effectType) | Triggers vibration with a given effect, which is specified by **effectType**.|
| int32_t  Stop(enum VibratorMode mode)  | Stops vibration.                        |

### How to Develop

The vibrator driver model provides stable interfaces for the upper-layer hardware service to trigger a one-shot vibration with a given duration, trigger vibration with a given effect, and stop vibration. The model implements functionalities such as cross-OS migration and differentiated configurations. To develop a vibrator, perform the following steps:

1. Develop the vibrator abstract driver based on the driver entry. Specifically, implement the **Bind**, **Init**, **Release**, and **Dispatch** functions, configure resources, and parse HCS configurations.

A
Annie_wang 已提交
70
   - Call **HDF_INIT** to register the driver entry with the HDF. During driver loading, the HDF calls the **Bind** function and then the **Init** function to load the driver. If the **Init** function fails to be called, the HDF calls **Release** to release the driver resources and exit the vibrator driver model. The vibrator driver model uses the HCS as the configuration source code. For details about HCS fields, see [Driver Configuration Management](driver-hdf-manage.md). The driver entry function is defined as follows:
W
wusongqing 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

     ```c
     /* Register the entry structure object of the vibrator abstract driver. */
     struct HdfDriverEntry g_vibratorDriverEntry = {
         .moduleVersion = 1, // Version of the vibrator module.
         .moduleName = "HDF_VIBRATOR", // Vibrator module name. The value must be the same as the value of moduleName in the device_info.hcs file.
         .Bind = BindVibratorDriver, // Function for binding a vibrator.
         .Init = InitVibratorDriver, // Function for initializing a vibrator.
        .Release = ReleaseVibratorDriver, // Function for releasing vibrator resources.
     };
     
     HDF_INIT(g_vibratorDriverEntry);
     ```

   - Develop the vibrator abstract driver. Specifically, implement the **Bind**, **Init**, **Release**, and **Dispatch** functions.

     ```c
     /* External service published by the vibrator driver. */
     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;
     }
     
     /* Bind the external service provided by the vibrator driver to the 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;
     }
     
     /* Entry function for vibrator driver initialization. */
     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 fail!", __func__);
             return HDF_FAILURE;
         }
     
         return HDF_SUCCESS;
     }
     
     /* Release the resources allocated during vibrator driver initialization. */
     void ReleaseVibratorDriver(struct HdfDeviceObject *device)
     {
         struct VibratorDriverData *drvData = NULL;
         ......
         (void)DestroyVibratorHaptic();
         (void)OsalMutexDestroy(&drvData->mutex);
         (void)OsalMemFree(drvData);
         g_vibratorDrvData = NULL;
     }
     ```

   - During system startup, the HDF configuration management loads the vibrator abstract driver based on the device information HCS and publishes the vibrator driver interfaces.

     ```c
     /* Device information HCS. */
     vibrator :: host {
                 hostName = "vibrator_host";
                 device_vibrator :: device {
                     device0 :: deviceNode {
                         policy = 2; // Policy for publishing the driver service.
                         priority = 100; // Driver startup priority (0–200). A larger value indicates a lower priority. The default value 100 is recommended. The sequence for loading devices with the same priority is random.
                         preload = 0; // Field for specifying whether to load the driver. The value 0 means to load the driver, and 2 means the opposite.
                         permission = 0664; // Permission for the driver to create a device node.
                         moduleName = "HDF_VIBRATOR"; // Driver name. The value must be the same as that of moduleName in the driver entry structure.
                         serviceName = "hdf_misc_vibrator"; // Name of the service provided by the driver. The name must be unique.
                         deviceMatchAttr = "hdf_vibrator_driver"; // Keyword matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver.
                     }
                 }
     ```

2. Create a vibrator haptic model and parse the haptic HCS configuration.

   - Create a vibrator haptic model.

     ```hcs
     /* Create a vibrator haptic model, allocate resources, and parse the haptic HCS configuration. */
     int32_t CreateVibratorHaptic(struct HdfDeviceObject *device)
     {
         struct VibratorHapticData *hapticData = NULL;
         CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
     
         hapticData = (struct VibratorHapticData *)OsalMemCalloc(sizeof(*hapticData));
         CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_ERR_MALLOC_FAIL);
         g_vibratorHapticData = hapticData;
         hapticData->supportHaptic = false;
     
         if (OsalMutexInit(&hapticData->mutex) != HDF_SUCCESS) {
             HDF_LOGE("%s: fail to init mutex", __func__);
             goto EXIT;
         }
     
         DListHeadInit(&hapticData->effectSeqHead);
     
         /* Parse the haptic HCS configuration. */
         if (ParserVibratorHapticConfig(device->property) != HDF_SUCCESS) {
             HDF_LOGE("%s: parser haptic config fail!", __func__);
             goto EXIT;
         }
     
         return HDF_SUCCESS;
     EXIT:
         OsalMemFree(hapticData);
         return HDF_FAILURE;
     }
     ```

A
Annie_wang 已提交
203
   - The vibrator effect model uses the HCS. For details about HCS fields, see [Driver Configuration Management](driver-hdf-manage.md).
W
wusongqing 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

     ```
     /* Vibrator data configuration template (vibrator_config.hcs). */
     root {
         vibratorConfig {
             boardConfig {
                 match_attr = "hdf_vibrator_driver"; // The value must be the same as that of the match_attr field configured for the vibrator.
                 vibratorAttr {
                     /* The value 0 means a rotor vibrator, and 1 means a linear vibrator. */
                     deviceType = 1; // Device type.
                     supportPreset = 1; // Supported preset type.
                 }
                 vibratorHapticConfig {
                     haptic_clock_timer {
                         effectName = "haptic.clock.timer";
                         type = 1; // The value 0 means the built-in mode, and 1 means the time sequence.
                         seq = [600, 600, 200, 600]; // Time sequence.
                     }
                     haptic_default_effect {
                         effectName = "haptic.default.effect";
                         type = 0;
                         seq = [0, 3, 800, 1];
                     }
                 }
             }
         }
     }
     ```

3. Develop the interfaces for starting and stopping vibration. A timer will be created and destroyed based on the vibration effect.

   The vibrator hardware service calls **StartOnce** to start one-shot vibration with a given duration and calls **StartEffect** to start vibration with a specified effect.

   ```c
   /* Trigger vibration with a given 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;
       /* Create a timer based on the vibration effect. */
       ret = StartHaptic(&config);
       if (ret != HDF_SUCCESS) {
           HDF_LOGE("%s: start haptic fail!", __func__);
           return ret;
       }
   
       return HDF_SUCCESS;
   }
   
   /* Trigger vibration with a given 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;
       ......
       config.cfgMode = VIBRATOR_MODE_PRESET;
       config.duration = 0;
       config.effect = effect;
   
       ret = StartHaptic(&config);
       if (ret != HDF_SUCCESS) {
           HDF_LOGE("%s: start haptic fail!", __func__);
           return ret;
       }
   
       return HDF_SUCCESS;
   }
   
   /* Stop vibration based on the specified vibration mode. */
   static int32_t Stop(struct HdfSBuf *data, struct HdfSBuf *reply)
   {
       int32_t ret;
       int32_t mode;
       struct VibratorDriverData *drvData = GetVibratorDrvData();
       (void)reply;
       ......
       /* Stop vibration and destroy the timer. */
       ret = StopHaptic();
       if (ret != HDF_SUCCESS) {
           HDF_LOGE("%s: stop haptic fail!", __func__);
           return ret;
       }
   
       (void)OsalMutexLock(&drvData->mutex);
       drvData->mode = VIBRATOR_MODE_BUTT;
       (void)OsalMutexUnlock(&drvData->mutex);
   
       return HDF_SUCCESS;
   }
   ```

4. Implement the interfaces for the vibrator chipset driver.

   - Register the vibrator chipset driver interfaces when the vibrator chipset driver is initialized successfully.

     ```c
     /* Register the vibrator chipset driver interfaces. */
     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;
         (void)OsalMutexUnlock(&drvData->mutex);
     
         return HDF_SUCCESS;
     }
     ```

   - The vibrator driver model provides vibrator chipset driver interfaces. Implement these interfaces as follows:

     ```c
     /* Start a linear vibrator to vibrate with a given duration. */
     static int32_t StartLinearVibrator()
     {
         int32_t ret;
         struct VibratorLinearDriverData *drvData = GetLinearVibratorData();
         CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE);
         ......
         ret = GpioWrite(drvData->gpioNum, GPIO_VAL_LOW);
         if (ret != HDF_SUCCESS) {
             HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, drvData->gpioNum, GPIO_VAL_LOW);
             return ret;
         }
         return HDF_SUCCESS;
     }
     
     /* Start a linear vibration to vibrate with a given effect. */
     static int32_t StartEffectLinearVibrator(uint32_t effectType)
     {
         (void)effectType;
          HDF_LOGE("%s: vibrator set build-in effect no support!", __func__);
         return HDF_SUCCESS;
     }
     
     /* Stop a linear vibration based on the specified vibration mode. */
     static int32_t StopLinearVibrator()
     {
         int32_t ret;
         struct VibratorLinearDriverData *drvData = GetLinearVibratorData();
         CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE);
         ......
         ret = GpioWrite(drvData->gpioNum, GPIO_VAL_HIGH);
         if (ret != HDF_SUCCESS) {
             HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, drvData->gpioNum, GPIO_VAL_HIGH);
             return ret;
         }
         return HDF_SUCCESS;
     }
     ```