1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #include "Vibrator.h"
19 
20 #include <hardware/hardware.h>
21 #include <hardware/vibrator.h>
22 #include <log/log.h>
23 #include <utils/Trace.h>
24 
25 #include <cinttypes>
26 #include <cmath>
27 #include <fstream>
28 #include <iostream>
29 #include <sstream>
30 
31 #ifndef ARRAY_SIZE
32 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
33 #endif
34 
35 namespace aidl {
36 namespace android {
37 namespace hardware {
38 namespace vibrator {
39 
40 static constexpr uint32_t BASE_CONTINUOUS_EFFECT_OFFSET = 32768;
41 
42 static constexpr uint32_t WAVEFORM_EFFECT_0_20_LEVEL = 0;
43 static constexpr uint32_t WAVEFORM_EFFECT_1_00_LEVEL = 4;
44 static constexpr uint32_t WAVEFORM_EFFECT_LEVEL_MINIMUM = 4;
45 
46 static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100;
47 
48 static constexpr uint32_t WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0;
49 static constexpr uint32_t WAVEFORM_LONG_VIBRATION_THRESHOLD_MS = 50;
50 static constexpr uint32_t WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3 + BASE_CONTINUOUS_EFFECT_OFFSET;
51 
52 static constexpr uint32_t WAVEFORM_CLICK_INDEX = 2;
53 static constexpr uint32_t WAVEFORM_QUICK_RISE_INDEX = 6;
54 static constexpr uint32_t WAVEFORM_SLOW_RISE_INDEX = 7;
55 static constexpr uint32_t WAVEFORM_QUICK_FALL_INDEX = 8;
56 static constexpr uint32_t WAVEFORM_LIGHT_TICK_INDEX = 9;
57 
58 static constexpr uint32_t WAVEFORM_TRIGGER_QUEUE_INDEX = 65534;
59 
60 static constexpr uint32_t VOLTAGE_GLOBAL_SCALE_LEVEL = 5;
61 static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
62 
63 static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6;  // I2C Transaction + DSP Return-From-Standby
64 static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1;  // ALERT Irq Handling
65 static constexpr uint32_t MAX_TIME_MS = UINT32_MAX;
66 
67 static constexpr float AMP_ATTENUATE_STEP_SIZE = 0.125f;
68 static constexpr float EFFECT_FREQUENCY_KHZ = 48.0f;
69 
70 static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100);
71 
72 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000;
73 static constexpr int32_t COMPOSE_SIZE_MAX = 127;
74 
amplitudeToScale(float amplitude,float maximum)75 static uint8_t amplitudeToScale(float amplitude, float maximum) {
76     return std::round((-20 * std::log10(amplitude / static_cast<float>(maximum))) /
77                       (AMP_ATTENUATE_STEP_SIZE));
78 }
79 
80 enum class AlwaysOnId : uint32_t {
81     GPIO_RISE,
82     GPIO_FALL,
83 };
84 
Vibrator(std::unique_ptr<HwApi> hwapi,std::unique_ptr<HwCal> hwcal)85 Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
86     : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)), mAsyncHandle(std::async([] {})) {
87     uint32_t caldata;
88     uint32_t effectCount;
89     std::array<uint32_t, 6> volLevels;
90 
91     if (!mHwApi->setState(true)) {
92         ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
93     }
94 
95     if (mHwCal->getF0(&caldata)) {
96         mHwApi->setF0(caldata);
97     }
98     if (mHwCal->getRedc(&caldata)) {
99         mHwApi->setRedc(caldata);
100     }
101     if (mHwCal->getQ(&caldata)) {
102         mHwApi->setQ(caldata);
103     }
104 
105     mHwCal->getVolLevels(&volLevels);
106     /*
107      * Given voltage levels for two intensities, assuming a linear function,
108      * solve for 'f(0)' in 'v = f(i) = a + b * i' (i.e 'v0 - (v1 - v0) / ((i1 - i0) / i0)').
109      */
110     mEffectVolMin = std::max(std::lround(volLevels[WAVEFORM_EFFECT_0_20_LEVEL] -
111                                          (volLevels[WAVEFORM_EFFECT_1_00_LEVEL] -
112                                           volLevels[WAVEFORM_EFFECT_0_20_LEVEL]) /
113                                                  4.0f),
114                              static_cast<long>(WAVEFORM_EFFECT_LEVEL_MINIMUM));
115     mEffectVolMax = volLevels[WAVEFORM_EFFECT_1_00_LEVEL];
116     mGlobalVolMax = volLevels[VOLTAGE_GLOBAL_SCALE_LEVEL];
117 
118     mHwApi->getEffectCount(&effectCount);
119     mEffectDurations.resize(effectCount);
120     for (size_t effectIndex = 0; effectIndex < effectCount; effectIndex++) {
121         mHwApi->setEffectIndex(effectIndex);
122         uint32_t effectDuration;
123         if (mHwApi->getEffectDuration(&effectDuration)) {
124             mEffectDurations[effectIndex] = std::ceil(effectDuration / EFFECT_FREQUENCY_KHZ);
125         }
126     }
127 }
128 
getCapabilities(int32_t * _aidl_return)129 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
130     ATRACE_NAME("Vibrator::getCapabilities");
131     int32_t ret = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
132                   IVibrator::CAP_COMPOSE_EFFECTS | IVibrator::CAP_ALWAYS_ON_CONTROL;
133     if (mHwApi->hasEffectScale()) {
134         ret |= IVibrator::CAP_AMPLITUDE_CONTROL;
135     }
136     if (mHwApi->hasAspEnable()) {
137         ret |= IVibrator::CAP_EXTERNAL_CONTROL;
138     }
139     *_aidl_return = ret;
140     return ndk::ScopedAStatus::ok();
141 }
142 
off()143 ndk::ScopedAStatus Vibrator::off() {
144     ATRACE_NAME("Vibrator::off");
145     setGlobalAmplitude(false);
146     if (!mHwApi->setActivate(0)) {
147         ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
148         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
149     }
150     return ndk::ScopedAStatus::ok();
151 }
152 
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)153 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
154                                 const std::shared_ptr<IVibratorCallback> &callback) {
155     ATRACE_NAME("Vibrator::on");
156     const uint32_t index = timeoutMs < WAVEFORM_LONG_VIBRATION_THRESHOLD_MS
157                                    ? WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX
158                                    : WAVEFORM_LONG_VIBRATION_EFFECT_INDEX;
159     if (MAX_COLD_START_LATENCY_MS <= UINT32_MAX - timeoutMs) {
160         timeoutMs += MAX_COLD_START_LATENCY_MS;
161     }
162     setGlobalAmplitude(true);
163     return on(timeoutMs, index, callback);
164 }
165 
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)166 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
167                                      const std::shared_ptr<IVibratorCallback> &callback,
168                                      int32_t *_aidl_return) {
169     ATRACE_NAME("Vibrator::perform");
170     return performEffect(effect, strength, callback, _aidl_return);
171 }
172 
getSupportedEffects(std::vector<Effect> * _aidl_return)173 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
174     *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
175                      Effect::DOUBLE_CLICK};
176     return ndk::ScopedAStatus::ok();
177 }
178 
setAmplitude(float amplitude)179 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
180     ATRACE_NAME("Vibrator::setAmplitude");
181     if (amplitude <= 0.0f || amplitude > 1.0f) {
182         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
183     }
184 
185     if (!isUnderExternalControl()) {
186         return setEffectAmplitude(amplitude, 1.0);
187     } else {
188         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
189     }
190 }
191 
setExternalControl(bool enabled)192 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
193     ATRACE_NAME("Vibrator::setExternalControl");
194     setGlobalAmplitude(enabled);
195 
196     if (!mHwApi->setAspEnable(enabled)) {
197         ALOGE("Failed to set external control (%d): %s", errno, strerror(errno));
198         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
199     }
200     return ndk::ScopedAStatus::ok();
201 }
202 
getCompositionDelayMax(int32_t * maxDelayMs)203 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t *maxDelayMs) {
204     ATRACE_NAME("Vibrator::getCompositionDelayMax");
205     *maxDelayMs = COMPOSE_DELAY_MAX_MS;
206     return ndk::ScopedAStatus::ok();
207 }
208 
getCompositionSizeMax(int32_t * maxSize)209 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t *maxSize) {
210     ATRACE_NAME("Vibrator::getCompositionSizeMax");
211     *maxSize = COMPOSE_SIZE_MAX;
212     return ndk::ScopedAStatus::ok();
213 }
214 
getSupportedPrimitives(std::vector<CompositePrimitive> * supported)215 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive> *supported) {
216     *supported = {
217             CompositePrimitive::NOOP,       CompositePrimitive::CLICK,
218             CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
219             CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
220     };
221     return ndk::ScopedAStatus::ok();
222 }
223 
getPrimitiveDuration(CompositePrimitive primitive,int32_t * durationMs)224 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
225                                                   int32_t *durationMs) {
226     ndk::ScopedAStatus status;
227     uint32_t effectIndex;
228 
229     if (primitive != CompositePrimitive::NOOP) {
230         status = getPrimitiveDetails(primitive, &effectIndex);
231         if (!status.isOk()) {
232             return status;
233         }
234 
235         *durationMs = mEffectDurations[effectIndex];
236     } else {
237         *durationMs = 0;
238     }
239 
240     return ndk::ScopedAStatus::ok();
241 }
242 
compose(const std::vector<CompositeEffect> & composite,const std::shared_ptr<IVibratorCallback> & callback)243 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composite,
244                                      const std::shared_ptr<IVibratorCallback> &callback) {
245     ATRACE_NAME("Vibrator::compose");
246     std::ostringstream effectBuilder;
247     std::string effectQueue;
248 
249     if (composite.size() > COMPOSE_SIZE_MAX) {
250         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
251     }
252 
253     for (auto &e : composite) {
254         if (e.scale < 0.0f || e.scale > 1.0f) {
255             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
256         }
257 
258         if (e.delayMs) {
259             if (e.delayMs > COMPOSE_DELAY_MAX_MS) {
260                 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
261             }
262             effectBuilder << e.delayMs << ",";
263         }
264         if (e.primitive != CompositePrimitive::NOOP) {
265             ndk::ScopedAStatus status;
266             uint32_t effectIndex;
267 
268             status = getPrimitiveDetails(e.primitive, &effectIndex);
269             if (!status.isOk()) {
270                 return status;
271             }
272 
273             effectBuilder << effectIndex << "." << intensityToVolLevel(e.scale) << ",";
274         }
275     }
276 
277     if (effectBuilder.tellp() == 0) {
278         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
279     }
280 
281     effectBuilder << 0;
282 
283     effectQueue = effectBuilder.str();
284 
285     return performEffect(0 /*ignored*/, 0 /*ignored*/, &effectQueue, callback);
286 }
287 
on(uint32_t timeoutMs,uint32_t effectIndex,const std::shared_ptr<IVibratorCallback> & callback)288 ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex,
289                                 const std::shared_ptr<IVibratorCallback> &callback) {
290     if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) {
291         ALOGE("Previous vibration pending.");
292         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
293     }
294 
295     mHwApi->setEffectIndex(effectIndex);
296     mHwApi->setDuration(timeoutMs);
297     mHwApi->setActivate(1);
298 
299     mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
300 
301     return ndk::ScopedAStatus::ok();
302 }
303 
setEffectAmplitude(float amplitude,float maximum)304 ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) {
305     int32_t scale = amplitudeToScale(amplitude, maximum);
306 
307     if (!mHwApi->setEffectScale(scale)) {
308         ALOGE("Failed to set effect amplitude (%d): %s", errno, strerror(errno));
309         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
310     }
311 
312     return ndk::ScopedAStatus::ok();
313 }
314 
setGlobalAmplitude(bool set)315 ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) {
316     uint8_t amplitude = set ? mGlobalVolMax : VOLTAGE_SCALE_MAX;
317     int32_t scale = amplitudeToScale(amplitude, VOLTAGE_SCALE_MAX);
318 
319     if (!mHwApi->setGlobalScale(scale)) {
320         ALOGE("Failed to set global amplitude (%d): %s", errno, strerror(errno));
321         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
322     }
323 
324     return ndk::ScopedAStatus::ok();
325 }
326 
getSupportedAlwaysOnEffects(std::vector<Effect> * _aidl_return)327 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> *_aidl_return) {
328     *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK};
329     return ndk::ScopedAStatus::ok();
330 }
331 
alwaysOnEnable(int32_t id,Effect effect,EffectStrength strength)332 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
333     ndk::ScopedAStatus status;
334     uint32_t effectIndex;
335     uint32_t timeMs;
336     uint32_t volLevel;
337     uint32_t scale;
338 
339     status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
340     if (!status.isOk()) {
341         return status;
342     }
343 
344     scale = amplitudeToScale(volLevel, VOLTAGE_SCALE_MAX);
345 
346     switch (static_cast<AlwaysOnId>(id)) {
347         case AlwaysOnId::GPIO_RISE:
348             mHwApi->setGpioRiseIndex(effectIndex);
349             mHwApi->setGpioRiseScale(scale);
350             return ndk::ScopedAStatus::ok();
351         case AlwaysOnId::GPIO_FALL:
352             mHwApi->setGpioFallIndex(effectIndex);
353             mHwApi->setGpioFallScale(scale);
354             return ndk::ScopedAStatus::ok();
355     }
356 
357     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
358 }
alwaysOnDisable(int32_t id)359 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
360     switch (static_cast<AlwaysOnId>(id)) {
361         case AlwaysOnId::GPIO_RISE:
362             mHwApi->setGpioRiseIndex(0);
363             return ndk::ScopedAStatus::ok();
364         case AlwaysOnId::GPIO_FALL:
365             mHwApi->setGpioFallIndex(0);
366             return ndk::ScopedAStatus::ok();
367     }
368 
369     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
370 }
371 
isUnderExternalControl()372 bool Vibrator::isUnderExternalControl() {
373     bool isAspEnabled;
374     mHwApi->getAspEnable(&isAspEnabled);
375     return isAspEnabled;
376 }
377 
dump(int fd,const char ** args,uint32_t numArgs)378 binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
379     if (fd < 0) {
380         ALOGE("Called debug() with invalid fd.");
381         return STATUS_OK;
382     }
383 
384     (void)args;
385     (void)numArgs;
386 
387     dprintf(fd, "AIDL:\n");
388 
389     dprintf(fd, "  Voltage Levels:\n");
390     dprintf(fd, "    Effect Min: %" PRIu32 "\n", mEffectVolMin);
391     dprintf(fd, "    Effect Max: %" PRIu32 "\n", mEffectVolMax);
392     dprintf(fd, "    Global Max: %" PRIu32 "\n", mGlobalVolMax);
393 
394     dprintf(fd, "  Effect Durations:");
395     for (auto d : mEffectDurations) {
396         dprintf(fd, " %" PRIu32, d);
397     }
398     dprintf(fd, "\n");
399 
400     dprintf(fd, "\n");
401 
402     mHwApi->debug(fd);
403 
404     dprintf(fd, "\n");
405 
406     mHwCal->debug(fd);
407 
408     fsync(fd);
409     return STATUS_OK;
410 }
411 
getSimpleDetails(Effect effect,EffectStrength strength,uint32_t * outEffectIndex,uint32_t * outTimeMs,uint32_t * outVolLevel)412 ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
413                                               uint32_t *outEffectIndex, uint32_t *outTimeMs,
414                                               uint32_t *outVolLevel) {
415     uint32_t effectIndex;
416     uint32_t timeMs;
417     float intensity;
418     uint32_t volLevel;
419 
420     switch (strength) {
421         case EffectStrength::LIGHT:
422             intensity = 0.5f;
423             break;
424         case EffectStrength::MEDIUM:
425             intensity = 0.7f;
426             break;
427         case EffectStrength::STRONG:
428             intensity = 1.0f;
429             break;
430         default:
431             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
432     }
433 
434     switch (effect) {
435         case Effect::TEXTURE_TICK:
436             effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
437             intensity *= 0.5f;
438             break;
439         case Effect::TICK:
440             effectIndex = WAVEFORM_CLICK_INDEX;
441             intensity *= 0.5f;
442             break;
443         case Effect::CLICK:
444             effectIndex = WAVEFORM_CLICK_INDEX;
445             intensity *= 0.7f;
446             break;
447         case Effect::HEAVY_CLICK:
448             effectIndex = WAVEFORM_CLICK_INDEX;
449             intensity *= 1.0f;
450             break;
451         default:
452             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
453     }
454 
455     volLevel = intensityToVolLevel(intensity);
456     timeMs = mEffectDurations[effectIndex] + MAX_COLD_START_LATENCY_MS;
457 
458     *outEffectIndex = effectIndex;
459     *outTimeMs = timeMs;
460     *outVolLevel = volLevel;
461 
462     return ndk::ScopedAStatus::ok();
463 }
464 
getCompoundDetails(Effect effect,EffectStrength strength,uint32_t * outTimeMs,uint32_t *,std::string * outEffectQueue)465 ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
466                                                 uint32_t *outTimeMs, uint32_t * /*outVolLevel*/,
467                                                 std::string *outEffectQueue) {
468     ndk::ScopedAStatus status;
469     uint32_t timeMs;
470     std::ostringstream effectBuilder;
471     uint32_t thisEffectIndex;
472     uint32_t thisTimeMs;
473     uint32_t thisVolLevel;
474 
475     switch (effect) {
476         case Effect::DOUBLE_CLICK:
477             timeMs = 0;
478 
479             status = getSimpleDetails(Effect::CLICK, strength, &thisEffectIndex, &thisTimeMs,
480                                       &thisVolLevel);
481             if (!status.isOk()) {
482                 return status;
483             }
484             effectBuilder << thisEffectIndex << "." << thisVolLevel;
485             timeMs += thisTimeMs;
486 
487             effectBuilder << ",";
488 
489             effectBuilder << WAVEFORM_DOUBLE_CLICK_SILENCE_MS;
490             timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
491 
492             effectBuilder << ",";
493 
494             status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisEffectIndex, &thisTimeMs,
495                                       &thisVolLevel);
496             if (!status.isOk()) {
497                 return status;
498             }
499             effectBuilder << thisEffectIndex << "." << thisVolLevel;
500             timeMs += thisTimeMs;
501 
502             break;
503         default:
504             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
505     }
506 
507     *outTimeMs = timeMs;
508     *outEffectQueue = effectBuilder.str();
509 
510     return ndk::ScopedAStatus::ok();
511 }
512 
getPrimitiveDetails(CompositePrimitive primitive,uint32_t * outEffectIndex)513 ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive,
514                                                  uint32_t *outEffectIndex) {
515     uint32_t effectIndex;
516 
517     switch (primitive) {
518         case CompositePrimitive::NOOP:
519             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
520         case CompositePrimitive::CLICK:
521             effectIndex = WAVEFORM_CLICK_INDEX;
522             break;
523         case CompositePrimitive::QUICK_RISE:
524             effectIndex = WAVEFORM_QUICK_RISE_INDEX;
525             break;
526         case CompositePrimitive::SLOW_RISE:
527             effectIndex = WAVEFORM_SLOW_RISE_INDEX;
528             break;
529         case CompositePrimitive::QUICK_FALL:
530             effectIndex = WAVEFORM_QUICK_FALL_INDEX;
531             break;
532         case CompositePrimitive::LIGHT_TICK:
533             effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
534             break;
535         default:
536             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
537     }
538 
539     *outEffectIndex = effectIndex;
540 
541     return ndk::ScopedAStatus::ok();
542 }
543 
setEffectQueue(const std::string & effectQueue)544 ndk::ScopedAStatus Vibrator::setEffectQueue(const std::string &effectQueue) {
545     if (!mHwApi->setEffectQueue(effectQueue)) {
546         ALOGE("Failed to write \"%s\" to effect queue (%d): %s", effectQueue.c_str(), errno,
547               strerror(errno));
548         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
549     }
550 
551     return ndk::ScopedAStatus::ok();
552 }
553 
performEffect(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * outTimeMs)554 ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
555                                            const std::shared_ptr<IVibratorCallback> &callback,
556                                            int32_t *outTimeMs) {
557     ndk::ScopedAStatus status;
558     uint32_t effectIndex;
559     uint32_t timeMs = 0;
560     uint32_t volLevel;
561     std::string effectQueue;
562 
563     switch (effect) {
564         case Effect::TEXTURE_TICK:
565             // fall-through
566         case Effect::TICK:
567             // fall-through
568         case Effect::CLICK:
569             // fall-through
570         case Effect::HEAVY_CLICK:
571             status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
572             break;
573         case Effect::DOUBLE_CLICK:
574             status = getCompoundDetails(effect, strength, &timeMs, &volLevel, &effectQueue);
575             break;
576         default:
577             status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
578             break;
579     }
580     if (!status.isOk()) {
581         goto exit;
582     }
583 
584     status = performEffect(effectIndex, volLevel, &effectQueue, callback);
585 
586 exit:
587 
588     *outTimeMs = timeMs;
589     return status;
590 }
591 
performEffect(uint32_t effectIndex,uint32_t volLevel,const std::string * effectQueue,const std::shared_ptr<IVibratorCallback> & callback)592 ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
593                                            const std::string *effectQueue,
594                                            const std::shared_ptr<IVibratorCallback> &callback) {
595     if (effectQueue && !effectQueue->empty()) {
596         ndk::ScopedAStatus status = setEffectQueue(*effectQueue);
597         if (!status.isOk()) {
598             return status;
599         }
600         setEffectAmplitude(VOLTAGE_SCALE_MAX, VOLTAGE_SCALE_MAX);
601         effectIndex = WAVEFORM_TRIGGER_QUEUE_INDEX;
602     } else {
603         setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
604     }
605 
606     return on(MAX_TIME_MS, effectIndex, callback);
607 }
608 
waitForComplete(std::shared_ptr<IVibratorCallback> && callback)609 void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) {
610     mHwApi->pollVibeState(false);
611     mHwApi->setActivate(false);
612 
613     if (callback) {
614         auto ret = callback->onComplete();
615         if (!ret.isOk()) {
616             ALOGE("Failed completion callback: %d", ret.getExceptionCode());
617         }
618     }
619 }
620 
intensityToVolLevel(float intensity)621 uint32_t Vibrator::intensityToVolLevel(float intensity) {
622     return std::lround(intensity * (mEffectVolMax - mEffectVolMin)) + mEffectVolMin;
623 }
624 
625 }  // namespace vibrator
626 }  // namespace hardware
627 }  // namespace android
628 }  // namespace aidl
629