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