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 #include "Vibrator.h"
18
19 #include <hardware/hardware.h>
20 #include <hardware/vibrator.h>
21 #include <log/log.h>
22 #include <stdio.h>
23 #include <utils/Trace.h>
24
25 #include <cinttypes>
26 #include <cmath>
27 #include <fstream>
28 #include <iostream>
29 #include <map>
30 #include <sstream>
31
32 #ifndef ARRAY_SIZE
33 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
34 #endif
35
36 #define PROC_SND_PCM "/proc/asound/pcm"
37 #define HAPTIC_PCM_DEVICE_SYMBOL "haptic nohost playback"
38
39 namespace aidl {
40 namespace android {
41 namespace hardware {
42 namespace vibrator {
43
44 static constexpr uint32_t BASE_CONTINUOUS_EFFECT_OFFSET = 32768;
45
46 static constexpr uint32_t WAVEFORM_EFFECT_0_20_LEVEL = 0;
47 static constexpr uint32_t WAVEFORM_EFFECT_1_00_LEVEL = 4;
48 static constexpr uint32_t WAVEFORM_EFFECT_LEVEL_MINIMUM = 4;
49
50 static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100;
51
52 static constexpr uint32_t WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0;
53 static constexpr uint32_t WAVEFORM_LONG_VIBRATION_THRESHOLD_MS = 50;
54 static constexpr uint32_t WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3 + BASE_CONTINUOUS_EFFECT_OFFSET;
55
56 static constexpr uint32_t WAVEFORM_CLICK_INDEX = 2;
57 static constexpr uint32_t WAVEFORM_THUD_INDEX = 4;
58 static constexpr uint32_t WAVEFORM_SPIN_INDEX = 5;
59 static constexpr uint32_t WAVEFORM_QUICK_RISE_INDEX = 6;
60 static constexpr uint32_t WAVEFORM_SLOW_RISE_INDEX = 7;
61 static constexpr uint32_t WAVEFORM_QUICK_FALL_INDEX = 8;
62 static constexpr uint32_t WAVEFORM_LIGHT_TICK_INDEX = 9;
63 static constexpr uint32_t WAVEFORM_LOW_TICK_INDEX = 10;
64
65 static constexpr uint32_t WAVEFORM_UNSAVED_TRIGGER_QUEUE_INDEX = 65529;
66 static constexpr uint32_t WAVEFORM_TRIGGER_QUEUE_INDEX = 65534;
67
68 static constexpr uint32_t VOLTAGE_GLOBAL_SCALE_LEVEL = 5;
69 static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
70
71 static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby
72 static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling
73 static constexpr uint32_t MAX_TIME_MS = UINT32_MAX;
74
75 static constexpr float AMP_ATTENUATE_STEP_SIZE = 0.125f;
76 static constexpr float EFFECT_FREQUENCY_KHZ = 48.0f;
77
78 static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100);
79
80 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000;
81 static constexpr int32_t COMPOSE_SIZE_MAX = 127;
82 static constexpr int32_t COMPOSE_PWLE_SIZE_MAX_DEFAULT = 127;
83
84
85 // Measured resonant frequency, f0_measured, is represented by Q10.14 fixed
86 // point format on cs40l2x devices. The expression to calculate f0 is:
87 // f0 = f0_measured / 2^Q14_BIT_SHIFT
88 // See the LRA Calibration Support documentation for more details.
89 static constexpr int32_t Q14_BIT_SHIFT = 14;
90
91 // Measured Q factor, q_measured, is represented by Q8.16 fixed
92 // point format on cs40l2x devices. The expression to calculate q is:
93 // q = q_measured / 2^Q16_BIT_SHIFT
94 // See the LRA Calibration Support documentation for more details.
95 static constexpr int32_t Q16_BIT_SHIFT = 16;
96
97 static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
98 static constexpr float PWLE_LEVEL_MIN = 0.0;
99 static constexpr float PWLE_LEVEL_MAX = 1.0;
100 static constexpr float CS40L2X_PWLE_LEVEL_MAX = 0.999511;
101 static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 0.25;
102 static constexpr float PWLE_FREQUENCY_MIN_HZ = 0.25;
103 static constexpr float PWLE_FREQUENCY_MAX_HZ = 1023.75;
104 static constexpr float PWLE_BW_MAP_SIZE =
105 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
106
107 static struct pcm_config haptic_nohost_config = {
108 .channels = 1,
109 .rate = 48000,
110 .period_size = 80,
111 .period_count = 2,
112 .format = PCM_FORMAT_S16_LE,
113 };
114
amplitudeToScale(float amplitude,float maximum)115 static uint8_t amplitudeToScale(float amplitude, float maximum) {
116 return std::round((-20 * std::log10(amplitude / static_cast<float>(maximum))) /
117 (AMP_ATTENUATE_STEP_SIZE));
118 }
119
120 // Discrete points of frequency:max_level pairs as recommended by the document
121 // [R4O6] Max. Allowable Chirp Levels (go/r4o6-max-chirp-levels) around resonant frequency
122 static std::map<float, float> discretePwleMaxLevels = {{120.0, 0.4}, {130.0, 0.31}, {140.0, 0.14},
123 {145.0, 0.09}, {150.0, 0.15}, {160.0, 0.35},
124 {170.0, 0.4}};
125
126 // Initialize all limits to 0.4 according to the document [R4O6] Max. Allowable Chirp Levels
127 // (go/r4o6-max-chirp-levels)
128 std::vector<float> pwleMaxLevelLimitMap(PWLE_BW_MAP_SIZE, 0.4);
129
createPwleMaxLevelLimitMap()130 void Vibrator::createPwleMaxLevelLimitMap() {
131 int32_t capabilities;
132 Vibrator::getCapabilities(&capabilities);
133 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
134 std::map<float, float>::iterator itr0, itr1;
135
136 itr0 = discretePwleMaxLevels.begin();
137 itr1 = std::next(itr0, 1);
138
139 while (itr1 != discretePwleMaxLevels.end()) {
140 float x0 = itr0->first;
141 float y0 = itr0->second;
142 float x1 = itr1->first;
143 float y1 = itr1->second;
144 float pwleMaxLevelLimitMapIdx =
145 (itr0->first - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ;
146
147 for (float xp = x0; xp < (x1 + PWLE_FREQUENCY_RESOLUTION_HZ);
148 xp += PWLE_FREQUENCY_RESOLUTION_HZ) {
149 float yp = y0 + ((y1 - y0) / (x1 - x0)) * (xp - x0);
150
151 pwleMaxLevelLimitMap[pwleMaxLevelLimitMapIdx++] = yp;
152 }
153
154 itr0++;
155 itr1++;
156 }
157 }
158 }
159
160 enum class AlwaysOnId : uint32_t {
161 GPIO_RISE,
162 GPIO_FALL,
163 };
164
Vibrator(std::unique_ptr<HwApi> hwapi,std::unique_ptr<HwCal> hwcal)165 Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
166 : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)), mAsyncHandle(std::async([] {})) {
167 int32_t longFreqencyShift;
168 uint32_t calVer;
169 uint32_t caldata;
170 uint32_t effectCount;
171
172 if (!mHwApi->setState(true)) {
173 ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
174 }
175
176 if (mHwCal->getF0(&caldata)) {
177 mHwApi->setF0(caldata);
178 }
179 if (mHwCal->getRedc(&caldata)) {
180 mHwApi->setRedc(caldata);
181 }
182 if (mHwCal->getQ(&caldata)) {
183 mHwApi->setQ(caldata);
184 }
185
186 mHwCal->getLongFrequencyShift(&longFreqencyShift);
187 if (longFreqencyShift > 0) {
188 mF0Offset = longFreqencyShift * std::pow(2, 14);
189 } else if (longFreqencyShift < 0) {
190 mF0Offset = std::pow(2, 24) - std::abs(longFreqencyShift) * std::pow(2, 14);
191 } else {
192 mF0Offset = 0;
193 }
194
195 mHwCal->getVersion(&calVer);
196 if (calVer == 1) {
197 std::array<uint32_t, 6> volLevels;
198 mHwCal->getVolLevels(&volLevels);
199 /*
200 * Given voltage levels for two intensities, assuming a linear function,
201 * solve for 'f(0)' in 'v = f(i) = a + b * i' (i.e 'v0 - (v1 - v0) / ((i1 - i0) / i0)').
202 */
203 mClickEffectVol[0] = std::max(std::lround(volLevels[WAVEFORM_EFFECT_0_20_LEVEL] -
204 (volLevels[WAVEFORM_EFFECT_1_00_LEVEL] -
205 volLevels[WAVEFORM_EFFECT_0_20_LEVEL]) /
206 4.0f),
207 static_cast<long>(WAVEFORM_EFFECT_LEVEL_MINIMUM));
208 mClickEffectVol[1] = volLevels[WAVEFORM_EFFECT_1_00_LEVEL];
209 mTickEffectVol = mClickEffectVol;
210 mLongEffectVol[0] = 0;
211 mLongEffectVol[1] = volLevels[VOLTAGE_GLOBAL_SCALE_LEVEL];
212 } else {
213 mHwCal->getTickVolLevels(&mTickEffectVol);
214 mHwCal->getClickVolLevels(&mClickEffectVol);
215 mHwCal->getLongVolLevels(&mLongEffectVol);
216 }
217
218 mHwApi->getEffectCount(&effectCount);
219 mEffectDurations.resize(effectCount);
220 for (size_t effectIndex = 0; effectIndex < effectCount; effectIndex++) {
221 mHwApi->setEffectIndex(effectIndex);
222 uint32_t effectDuration;
223 if (mHwApi->getEffectDuration(&effectDuration)) {
224 mEffectDurations[effectIndex] = std::ceil(effectDuration / EFFECT_FREQUENCY_KHZ);
225 }
226 }
227
228 mHwApi->setClabEnable(true);
229
230 if (!(getPwleCompositionSizeMax(&compositionSizeMax).isOk())) {
231 ALOGE("Failed to get pwle composition size max, using default size: %d",
232 COMPOSE_PWLE_SIZE_MAX_DEFAULT);
233 compositionSizeMax = COMPOSE_PWLE_SIZE_MAX_DEFAULT;
234 }
235
236 createPwleMaxLevelLimitMap();
237 }
238
getCapabilities(int32_t * _aidl_return)239 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
240 ATRACE_NAME("Vibrator::getCapabilities");
241 int32_t ret = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
242 IVibrator::CAP_COMPOSE_EFFECTS | IVibrator::CAP_ALWAYS_ON_CONTROL |
243 IVibrator::CAP_GET_RESONANT_FREQUENCY | IVibrator::CAP_GET_Q_FACTOR;
244 if (mHwApi->hasEffectScale()) {
245 ret |= IVibrator::CAP_AMPLITUDE_CONTROL;
246 }
247 if (mHwApi->hasAspEnable() || hasHapticAlsaDevice()) {
248 ret |= IVibrator::CAP_EXTERNAL_CONTROL;
249 }
250 if (mHwApi->hasPwle()) {
251 ret |= IVibrator::CAP_FREQUENCY_CONTROL | IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
252 }
253 *_aidl_return = ret;
254 return ndk::ScopedAStatus::ok();
255 }
256
off()257 ndk::ScopedAStatus Vibrator::off() {
258 ATRACE_NAME("Vibrator::off");
259 setGlobalAmplitude(false);
260 mHwApi->setF0Offset(0);
261 if (!mHwApi->setActivate(0)) {
262 ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
263 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
264 }
265 return ndk::ScopedAStatus::ok();
266 }
267
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)268 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
269 const std::shared_ptr<IVibratorCallback> &callback) {
270 ATRACE_NAME("Vibrator::on");
271 const uint32_t index = timeoutMs < WAVEFORM_LONG_VIBRATION_THRESHOLD_MS
272 ? WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX
273 : WAVEFORM_LONG_VIBRATION_EFFECT_INDEX;
274 if (MAX_COLD_START_LATENCY_MS <= UINT32_MAX - timeoutMs) {
275 timeoutMs += MAX_COLD_START_LATENCY_MS;
276 }
277 setGlobalAmplitude(true);
278 mHwApi->setF0Offset(mF0Offset);
279 return on(timeoutMs, index, callback);
280 }
281
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)282 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
283 const std::shared_ptr<IVibratorCallback> &callback,
284 int32_t *_aidl_return) {
285 ATRACE_NAME("Vibrator::perform");
286 return performEffect(effect, strength, callback, _aidl_return);
287 }
288
getSupportedEffects(std::vector<Effect> * _aidl_return)289 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
290 *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
291 Effect::DOUBLE_CLICK};
292 return ndk::ScopedAStatus::ok();
293 }
294
setAmplitude(float amplitude)295 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
296 ATRACE_NAME("Vibrator::setAmplitude");
297 if (amplitude <= 0.0f || amplitude > 1.0f) {
298 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
299 }
300
301 if (!isUnderExternalControl()) {
302 return setEffectAmplitude(amplitude, 1.0);
303 } else {
304 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
305 }
306 }
307
setExternalControl(bool enabled)308 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
309 ATRACE_NAME("Vibrator::setExternalControl");
310 setGlobalAmplitude(enabled);
311
312 if (mHasHapticAlsaDevice) {
313 if (!enableHapticPcmAmp(&mHapticPcm, enabled, mCard, mDevice)) {
314 ALOGE("Failed to %s haptic pcm device: %d", (enabled ? "enable" : "disable"), mDevice);
315 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
316 }
317 }
318 if (mHwApi->hasAspEnable()) {
319 if (!mHwApi->setAspEnable(enabled)) {
320 ALOGE("Failed to set external control (%d): %s", errno, strerror(errno));
321 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
322 }
323 }
324
325 mIsUnderExternalControl = enabled;
326 return ndk::ScopedAStatus::ok();
327 }
328
getCompositionDelayMax(int32_t * maxDelayMs)329 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t *maxDelayMs) {
330 ATRACE_NAME("Vibrator::getCompositionDelayMax");
331 *maxDelayMs = COMPOSE_DELAY_MAX_MS;
332 return ndk::ScopedAStatus::ok();
333 }
334
getCompositionSizeMax(int32_t * maxSize)335 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t *maxSize) {
336 ATRACE_NAME("Vibrator::getCompositionSizeMax");
337 *maxSize = COMPOSE_SIZE_MAX;
338 return ndk::ScopedAStatus::ok();
339 }
340
getSupportedPrimitives(std::vector<CompositePrimitive> * supported)341 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive> *supported) {
342 *supported = {
343 CompositePrimitive::NOOP, CompositePrimitive::CLICK,
344 CompositePrimitive::THUD, CompositePrimitive::SPIN,
345 CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
346 CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
347 CompositePrimitive::LOW_TICK,
348 };
349 return ndk::ScopedAStatus::ok();
350 }
351
getPrimitiveDuration(CompositePrimitive primitive,int32_t * durationMs)352 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
353 int32_t *durationMs) {
354 ndk::ScopedAStatus status;
355 uint32_t effectIndex;
356
357 if (primitive != CompositePrimitive::NOOP) {
358 status = getPrimitiveDetails(primitive, &effectIndex);
359 if (!status.isOk()) {
360 return status;
361 }
362
363 *durationMs = mEffectDurations[effectIndex];
364 } else {
365 *durationMs = 0;
366 }
367
368 return ndk::ScopedAStatus::ok();
369 }
370
compose(const std::vector<CompositeEffect> & composite,const std::shared_ptr<IVibratorCallback> & callback)371 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composite,
372 const std::shared_ptr<IVibratorCallback> &callback) {
373 ATRACE_NAME("Vibrator::compose");
374 std::ostringstream effectBuilder;
375 std::string effectQueue;
376
377 if (composite.size() > COMPOSE_SIZE_MAX) {
378 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
379 }
380
381 for (auto &e : composite) {
382 if (e.scale < 0.0f || e.scale > 1.0f) {
383 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
384 }
385
386 if (e.delayMs) {
387 if (e.delayMs > COMPOSE_DELAY_MAX_MS) {
388 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
389 }
390 effectBuilder << e.delayMs << ",";
391 }
392 if (e.primitive != CompositePrimitive::NOOP) {
393 ndk::ScopedAStatus status;
394 uint32_t effectIndex;
395
396 status = getPrimitiveDetails(e.primitive, &effectIndex);
397 if (!status.isOk()) {
398 return status;
399 }
400
401 effectBuilder << effectIndex << "." << intensityToVolLevel(e.scale, effectIndex) << ",";
402 }
403 }
404
405 if (effectBuilder.tellp() == 0) {
406 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
407 }
408
409 effectBuilder << 0;
410
411 effectQueue = effectBuilder.str();
412
413 return performEffect(0 /*ignored*/, 0 /*ignored*/, &effectQueue, callback);
414 }
415
on(uint32_t timeoutMs,uint32_t effectIndex,const std::shared_ptr<IVibratorCallback> & callback)416 ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex,
417 const std::shared_ptr<IVibratorCallback> &callback) {
418 if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) {
419 ALOGE("Previous vibration pending.");
420 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
421 }
422
423 mHwApi->setEffectIndex(effectIndex);
424 mHwApi->setDuration(timeoutMs);
425 mHwApi->setActivate(1);
426
427 mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
428
429 return ndk::ScopedAStatus::ok();
430 }
431
setEffectAmplitude(float amplitude,float maximum)432 ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) {
433 int32_t scale = amplitudeToScale(amplitude, maximum);
434
435 if (!mHwApi->setEffectScale(scale)) {
436 ALOGE("Failed to set effect amplitude (%d): %s", errno, strerror(errno));
437 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
438 }
439
440 return ndk::ScopedAStatus::ok();
441 }
442
setGlobalAmplitude(bool set)443 ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) {
444 uint8_t amplitude = set ? mLongEffectVol[1] : VOLTAGE_SCALE_MAX;
445 int32_t scale = amplitudeToScale(amplitude, VOLTAGE_SCALE_MAX);
446
447 if (!mHwApi->setGlobalScale(scale)) {
448 ALOGE("Failed to set global amplitude (%d): %s", errno, strerror(errno));
449 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
450 }
451
452 return ndk::ScopedAStatus::ok();
453 }
454
getSupportedAlwaysOnEffects(std::vector<Effect> * _aidl_return)455 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> *_aidl_return) {
456 *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK};
457 return ndk::ScopedAStatus::ok();
458 }
459
alwaysOnEnable(int32_t id,Effect effect,EffectStrength strength)460 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
461 ndk::ScopedAStatus status;
462 uint32_t effectIndex;
463 uint32_t timeMs;
464 uint32_t volLevel;
465 uint32_t scale;
466
467 status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
468 if (!status.isOk()) {
469 return status;
470 }
471
472 scale = amplitudeToScale(volLevel, VOLTAGE_SCALE_MAX);
473
474 switch (static_cast<AlwaysOnId>(id)) {
475 case AlwaysOnId::GPIO_RISE:
476 mHwApi->setGpioRiseIndex(effectIndex);
477 mHwApi->setGpioRiseScale(scale);
478 return ndk::ScopedAStatus::ok();
479 case AlwaysOnId::GPIO_FALL:
480 mHwApi->setGpioFallIndex(effectIndex);
481 mHwApi->setGpioFallScale(scale);
482 return ndk::ScopedAStatus::ok();
483 }
484
485 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
486 }
alwaysOnDisable(int32_t id)487 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
488 switch (static_cast<AlwaysOnId>(id)) {
489 case AlwaysOnId::GPIO_RISE:
490 mHwApi->setGpioRiseIndex(0);
491 return ndk::ScopedAStatus::ok();
492 case AlwaysOnId::GPIO_FALL:
493 mHwApi->setGpioFallIndex(0);
494 return ndk::ScopedAStatus::ok();
495 }
496
497 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
498 }
499
getResonantFrequency(float * resonantFreqHz)500 ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
501 uint32_t caldata;
502 if (!mHwCal->getF0(&caldata)) {
503 ALOGE("Failed to get resonant frequency (%d): %s", errno, strerror(errno));
504 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
505 }
506 *resonantFreqHz = static_cast<float>(caldata) / (1 << Q14_BIT_SHIFT);
507
508 return ndk::ScopedAStatus::ok();
509 }
510
getQFactor(float * qFactor)511 ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
512 uint32_t caldata;
513 if (!mHwCal->getQ(&caldata)) {
514 ALOGE("Failed to get q factor (%d): %s", errno, strerror(errno));
515 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
516 }
517 *qFactor = static_cast<float>(caldata) / (1 << Q16_BIT_SHIFT);
518
519 return ndk::ScopedAStatus::ok();
520 }
521
getFrequencyResolution(float * freqResolutionHz)522 ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
523 int32_t capabilities;
524 Vibrator::getCapabilities(&capabilities);
525 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
526 *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
527 return ndk::ScopedAStatus::ok();
528 } else {
529 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
530 }
531 }
532
getFrequencyMinimum(float * freqMinimumHz)533 ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
534 int32_t capabilities;
535 Vibrator::getCapabilities(&capabilities);
536 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
537 *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
538 return ndk::ScopedAStatus::ok();
539 } else {
540 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
541 }
542 }
543
getBandwidthAmplitudeMap(std::vector<float> * _aidl_return)544 ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
545 // TODO(b/170919640): complete implementation
546 int32_t capabilities;
547 Vibrator::getCapabilities(&capabilities);
548 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
549 std::vector<float> bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, 1.0);
550 *_aidl_return = bandwidthAmplitudeMap;
551 return ndk::ScopedAStatus::ok();
552 } else {
553 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
554 }
555 }
556
getPwlePrimitiveDurationMax(int32_t * durationMs)557 ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
558 int32_t capabilities;
559 Vibrator::getCapabilities(&capabilities);
560 if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
561 *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
562 return ndk::ScopedAStatus::ok();
563 } else {
564 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
565 }
566 }
567
getPwleCompositionSizeMax(int32_t * maxSize)568 ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
569 int32_t capabilities;
570 Vibrator::getCapabilities(&capabilities);
571 if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
572 uint32_t segments;
573 if (!mHwApi->getAvailablePwleSegments(&segments)) {
574 ALOGE("Failed to get availablePwleSegments (%d): %s", errno, strerror(errno));
575 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
576 }
577 *maxSize = segments;
578 return ndk::ScopedAStatus::ok();
579 } else {
580 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
581 }
582 }
583
getSupportedBraking(std::vector<Braking> * supported)584 ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
585 int32_t capabilities;
586 Vibrator::getCapabilities(&capabilities);
587 if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
588 *supported = {
589 Braking::NONE,
590 Braking::CLAB,
591 };
592 return ndk::ScopedAStatus::ok();
593 } else {
594 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
595 }
596 }
597
setPwle(const std::string & pwleQueue)598 ndk::ScopedAStatus Vibrator::setPwle(const std::string &pwleQueue) {
599 if (!mHwApi->setPwle(pwleQueue)) {
600 ALOGE("Failed to write \"%s\" to pwle (%d): %s", pwleQueue.c_str(), errno, strerror(errno));
601 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
602 }
603
604 return ndk::ScopedAStatus::ok();
605 }
606
resetPreviousEndAmplitudeEndFrequency(float & prevEndAmplitude,float & prevEndFrequency)607 static void resetPreviousEndAmplitudeEndFrequency(float &prevEndAmplitude,
608 float &prevEndFrequency) {
609 const float reset = -1.0;
610 prevEndAmplitude = reset;
611 prevEndFrequency = reset;
612 }
613
incrementIndex(int & index)614 static void incrementIndex(int &index) {
615 index += 1;
616 }
617
constructActiveDefaults(std::ostringstream & pwleBuilder,const int & segmentIdx)618 static void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
619 pwleBuilder << ",C" << segmentIdx << ":1";
620 pwleBuilder << ",B" << segmentIdx << ":0";
621 pwleBuilder << ",AR" << segmentIdx << ":0";
622 pwleBuilder << ",V" << segmentIdx << ":0";
623 }
624
constructActiveSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,float amplitude,float frequency)625 static void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx,
626 int duration, float amplitude, float frequency) {
627 pwleBuilder << ",T" << segmentIdx << ":" << duration;
628 pwleBuilder << ",L" << segmentIdx << ":" << amplitude;
629 pwleBuilder << ",F" << segmentIdx << ":" << frequency;
630 constructActiveDefaults(pwleBuilder, segmentIdx);
631 }
632
constructBrakingSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,Braking brakingType)633 static void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx,
634 int duration, Braking brakingType) {
635 pwleBuilder << ",T" << segmentIdx << ":" << duration;
636 pwleBuilder << ",L" << segmentIdx << ":" << 0;
637 pwleBuilder << ",F" << segmentIdx << ":" << PWLE_FREQUENCY_MIN_HZ;
638 pwleBuilder << ",C" << segmentIdx << ":0";
639 pwleBuilder << ",B" << segmentIdx << ":"
640 << static_cast<std::underlying_type<Braking>::type>(brakingType);
641 pwleBuilder << ",AR" << segmentIdx << ":0";
642 pwleBuilder << ",V" << segmentIdx << ":0";
643 }
644
composePwle(const std::vector<PrimitivePwle> & composite,const std::shared_ptr<IVibratorCallback> & callback)645 ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
646 const std::shared_ptr<IVibratorCallback> &callback) {
647 ATRACE_NAME("Vibrator::composePwle");
648 std::ostringstream pwleBuilder;
649 std::string pwleQueue;
650
651 if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
652 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
653 }
654
655 float prevEndAmplitude;
656 float prevEndFrequency;
657 resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
658
659 int segmentIdx = 0;
660 uint32_t totalDuration = 0;
661
662 pwleBuilder << "S:0,WF:4,RP:0,WT:0";
663
664 for (auto &e : composite) {
665 switch (e.getTag()) {
666 case PrimitivePwle::active: {
667 auto active = e.get<PrimitivePwle::active>();
668 if (active.duration < 0 ||
669 active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
670 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
671 }
672 if (active.startAmplitude < PWLE_LEVEL_MIN ||
673 active.startAmplitude > PWLE_LEVEL_MAX ||
674 active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
675 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
676 }
677 if (active.startAmplitude > CS40L2X_PWLE_LEVEL_MAX) {
678 active.startAmplitude = CS40L2X_PWLE_LEVEL_MAX;
679 }
680 if (active.endAmplitude > CS40L2X_PWLE_LEVEL_MAX) {
681 active.endAmplitude = CS40L2X_PWLE_LEVEL_MAX;
682 }
683
684 if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
685 active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
686 active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
687 active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
688 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
689 }
690
691 // clip to the hard limit on input level from pwleMaxLevelLimitMap
692 float maxLevelLimit =
693 pwleMaxLevelLimitMap[active.startFrequency / PWLE_FREQUENCY_RESOLUTION_HZ - 1];
694 if (active.startAmplitude > maxLevelLimit) {
695 active.startAmplitude = maxLevelLimit;
696 }
697 maxLevelLimit =
698 pwleMaxLevelLimitMap[active.endFrequency / PWLE_FREQUENCY_RESOLUTION_HZ - 1];
699 if (active.endAmplitude > maxLevelLimit) {
700 active.endAmplitude = maxLevelLimit;
701 }
702
703 if (!((active.startAmplitude == prevEndAmplitude) &&
704 (active.startFrequency == prevEndFrequency))) {
705 constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
706 active.startFrequency);
707 incrementIndex(segmentIdx);
708 }
709
710 constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
711 active.endAmplitude, active.endFrequency);
712 incrementIndex(segmentIdx);
713
714 prevEndAmplitude = active.endAmplitude;
715 prevEndFrequency = active.endFrequency;
716 totalDuration += active.duration;
717 break;
718 }
719 case PrimitivePwle::braking: {
720 auto braking = e.get<PrimitivePwle::braking>();
721 if (braking.braking > Braking::CLAB) {
722 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
723 }
724 if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
725 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
726 }
727
728 constructBrakingSegment(pwleBuilder, segmentIdx, 0, braking.braking);
729 incrementIndex(segmentIdx);
730
731 constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking);
732 incrementIndex(segmentIdx);
733
734 resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
735 totalDuration += braking.duration;
736 break;
737 }
738 }
739 }
740
741 pwleQueue = pwleBuilder.str();
742 ALOGD("composePwle queue: (%s)", pwleQueue.c_str());
743
744 ndk::ScopedAStatus status = setPwle(pwleQueue);
745 if (!status.isOk()) {
746 ALOGE("Failed to write pwle queue");
747 return status;
748 }
749
750 setEffectAmplitude(VOLTAGE_SCALE_MAX, VOLTAGE_SCALE_MAX);
751 mHwApi->setEffectIndex(WAVEFORM_UNSAVED_TRIGGER_QUEUE_INDEX);
752
753 totalDuration += MAX_COLD_START_LATENCY_MS;
754 mHwApi->setDuration(MAX_TIME_MS);
755
756 mHwApi->setActivate(1);
757
758 mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
759
760 return ndk::ScopedAStatus::ok();
761 }
762
isUnderExternalControl()763 bool Vibrator::isUnderExternalControl() {
764 return mIsUnderExternalControl;
765 }
766
dump(int fd,const char ** args,uint32_t numArgs)767 binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
768 if (fd < 0) {
769 ALOGE("Called debug() with invalid fd.");
770 return STATUS_OK;
771 }
772
773 (void)args;
774 (void)numArgs;
775
776 dprintf(fd, "AIDL:\n");
777
778 dprintf(fd, " F0 Offset: %" PRIu32 "\n", mF0Offset);
779
780 dprintf(fd, " Voltage Levels:\n");
781 dprintf(fd, " Tick Effect Min: %" PRIu32 " Max: %" PRIu32 "\n",
782 mTickEffectVol[0], mTickEffectVol[1]);
783 dprintf(fd, " Click Effect Min: %" PRIu32 " Max: %" PRIu32 "\n",
784 mClickEffectVol[0], mClickEffectVol[1]);
785 dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n",
786 mLongEffectVol[0], mLongEffectVol[1]);
787
788 dprintf(fd, " Effect Durations:");
789 for (auto d : mEffectDurations) {
790 dprintf(fd, " %" PRIu32, d);
791 }
792 dprintf(fd, "\n");
793
794 dprintf(fd, "\n");
795
796 mHwApi->debug(fd);
797
798 dprintf(fd, "\n");
799
800 mHwCal->debug(fd);
801
802 fsync(fd);
803 return STATUS_OK;
804 }
805
getSimpleDetails(Effect effect,EffectStrength strength,uint32_t * outEffectIndex,uint32_t * outTimeMs,uint32_t * outVolLevel)806 ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
807 uint32_t *outEffectIndex, uint32_t *outTimeMs,
808 uint32_t *outVolLevel) {
809 uint32_t effectIndex;
810 uint32_t timeMs;
811 float intensity;
812 uint32_t volLevel;
813
814 switch (strength) {
815 case EffectStrength::LIGHT:
816 intensity = 0.5f;
817 break;
818 case EffectStrength::MEDIUM:
819 intensity = 0.7f;
820 break;
821 case EffectStrength::STRONG:
822 intensity = 1.0f;
823 break;
824 default:
825 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
826 }
827
828 switch (effect) {
829 case Effect::TEXTURE_TICK:
830 effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
831 intensity *= 0.5f;
832 break;
833 case Effect::TICK:
834 effectIndex = WAVEFORM_CLICK_INDEX;
835 intensity *= 0.5f;
836 break;
837 case Effect::CLICK:
838 effectIndex = WAVEFORM_CLICK_INDEX;
839 intensity *= 0.7f;
840 break;
841 case Effect::HEAVY_CLICK:
842 effectIndex = WAVEFORM_CLICK_INDEX;
843 intensity *= 1.0f;
844 break;
845 default:
846 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
847 }
848
849 volLevel = intensityToVolLevel(intensity, effectIndex);
850 timeMs = mEffectDurations[effectIndex] + MAX_COLD_START_LATENCY_MS;
851
852 *outEffectIndex = effectIndex;
853 *outTimeMs = timeMs;
854 *outVolLevel = volLevel;
855
856 return ndk::ScopedAStatus::ok();
857 }
858
getCompoundDetails(Effect effect,EffectStrength strength,uint32_t * outTimeMs,uint32_t *,std::string * outEffectQueue)859 ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
860 uint32_t *outTimeMs, uint32_t * /*outVolLevel*/,
861 std::string *outEffectQueue) {
862 ndk::ScopedAStatus status;
863 uint32_t timeMs;
864 std::ostringstream effectBuilder;
865 uint32_t thisEffectIndex;
866 uint32_t thisTimeMs;
867 uint32_t thisVolLevel;
868
869 switch (effect) {
870 case Effect::DOUBLE_CLICK:
871 timeMs = 0;
872
873 status = getSimpleDetails(Effect::CLICK, strength, &thisEffectIndex, &thisTimeMs,
874 &thisVolLevel);
875 if (!status.isOk()) {
876 return status;
877 }
878 effectBuilder << thisEffectIndex << "." << thisVolLevel;
879 timeMs += thisTimeMs;
880
881 effectBuilder << ",";
882
883 effectBuilder << WAVEFORM_DOUBLE_CLICK_SILENCE_MS;
884 timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
885
886 effectBuilder << ",";
887
888 status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisEffectIndex, &thisTimeMs,
889 &thisVolLevel);
890 if (!status.isOk()) {
891 return status;
892 }
893 effectBuilder << thisEffectIndex << "." << thisVolLevel;
894 timeMs += thisTimeMs;
895
896 break;
897 default:
898 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
899 }
900
901 *outTimeMs = timeMs;
902 *outEffectQueue = effectBuilder.str();
903
904 return ndk::ScopedAStatus::ok();
905 }
906
getPrimitiveDetails(CompositePrimitive primitive,uint32_t * outEffectIndex)907 ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive,
908 uint32_t *outEffectIndex) {
909 uint32_t effectIndex;
910
911 switch (primitive) {
912 case CompositePrimitive::NOOP:
913 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
914 case CompositePrimitive::CLICK:
915 effectIndex = WAVEFORM_CLICK_INDEX;
916 break;
917 case CompositePrimitive::THUD:
918 effectIndex = WAVEFORM_THUD_INDEX;
919 break;
920 case CompositePrimitive::SPIN:
921 effectIndex = WAVEFORM_SPIN_INDEX;
922 break;
923 case CompositePrimitive::QUICK_RISE:
924 effectIndex = WAVEFORM_QUICK_RISE_INDEX;
925 break;
926 case CompositePrimitive::SLOW_RISE:
927 effectIndex = WAVEFORM_SLOW_RISE_INDEX;
928 break;
929 case CompositePrimitive::QUICK_FALL:
930 effectIndex = WAVEFORM_QUICK_FALL_INDEX;
931 break;
932 case CompositePrimitive::LIGHT_TICK:
933 effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
934 break;
935 case CompositePrimitive::LOW_TICK:
936 effectIndex = WAVEFORM_LOW_TICK_INDEX;
937 break;
938 default:
939 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
940 }
941
942 *outEffectIndex = effectIndex;
943
944 return ndk::ScopedAStatus::ok();
945 }
946
setEffectQueue(const std::string & effectQueue)947 ndk::ScopedAStatus Vibrator::setEffectQueue(const std::string &effectQueue) {
948 if (!mHwApi->setEffectQueue(effectQueue)) {
949 ALOGE("Failed to write \"%s\" to effect queue (%d): %s", effectQueue.c_str(), errno,
950 strerror(errno));
951 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
952 }
953
954 return ndk::ScopedAStatus::ok();
955 }
956
performEffect(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * outTimeMs)957 ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
958 const std::shared_ptr<IVibratorCallback> &callback,
959 int32_t *outTimeMs) {
960 ndk::ScopedAStatus status;
961 uint32_t effectIndex;
962 uint32_t timeMs = 0;
963 uint32_t volLevel;
964 std::string effectQueue;
965
966 switch (effect) {
967 case Effect::TEXTURE_TICK:
968 // fall-through
969 case Effect::TICK:
970 // fall-through
971 case Effect::CLICK:
972 // fall-through
973 case Effect::HEAVY_CLICK:
974 status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
975 break;
976 case Effect::DOUBLE_CLICK:
977 status = getCompoundDetails(effect, strength, &timeMs, &volLevel, &effectQueue);
978 break;
979 default:
980 status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
981 break;
982 }
983 if (!status.isOk()) {
984 goto exit;
985 }
986
987 status = performEffect(effectIndex, volLevel, &effectQueue, callback);
988
989 exit:
990
991 *outTimeMs = timeMs;
992 return status;
993 }
994
performEffect(uint32_t effectIndex,uint32_t volLevel,const std::string * effectQueue,const std::shared_ptr<IVibratorCallback> & callback)995 ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
996 const std::string *effectQueue,
997 const std::shared_ptr<IVibratorCallback> &callback) {
998 if (effectQueue && !effectQueue->empty()) {
999 ndk::ScopedAStatus status = setEffectQueue(*effectQueue);
1000 if (!status.isOk()) {
1001 return status;
1002 }
1003 setEffectAmplitude(VOLTAGE_SCALE_MAX, VOLTAGE_SCALE_MAX);
1004 effectIndex = WAVEFORM_TRIGGER_QUEUE_INDEX;
1005 } else {
1006 setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
1007 }
1008
1009 return on(MAX_TIME_MS, effectIndex, callback);
1010 }
1011
waitForComplete(std::shared_ptr<IVibratorCallback> && callback)1012 void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) {
1013 mHwApi->pollVibeState(false);
1014 mHwApi->setActivate(false);
1015
1016 if (callback) {
1017 auto ret = callback->onComplete();
1018 if (!ret.isOk()) {
1019 ALOGE("Failed completion callback: %d", ret.getExceptionCode());
1020 }
1021 }
1022 }
1023
intensityToVolLevel(float intensity,uint32_t effectIndex)1024 uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) {
1025
1026 uint32_t volLevel;
1027 auto calc = [](float intst, std::array<uint32_t, 2> v) -> uint32_t {
1028 return std::lround(intst * (v[1] - v[0])) + v[0]; };
1029
1030 switch (effectIndex) {
1031 case WAVEFORM_LIGHT_TICK_INDEX:
1032 volLevel = calc(intensity, mTickEffectVol);
1033 break;
1034 case WAVEFORM_QUICK_RISE_INDEX:
1035 // fall-through
1036 case WAVEFORM_QUICK_FALL_INDEX:
1037 volLevel = calc(intensity, mLongEffectVol);
1038 break;
1039 case WAVEFORM_CLICK_INDEX:
1040 // fall-through
1041 case WAVEFORM_THUD_INDEX:
1042 // fall-through
1043 case WAVEFORM_SPIN_INDEX:
1044 // fall-through
1045 case WAVEFORM_SLOW_RISE_INDEX:
1046 // fall-through
1047 default:
1048 volLevel = calc(intensity, mClickEffectVol);
1049 break;
1050 }
1051
1052 return volLevel;
1053 }
1054
findHapticAlsaDevice(int * card,int * device)1055 bool Vibrator::findHapticAlsaDevice(int *card, int *device) {
1056 std::string line;
1057 std::ifstream myfile(PROC_SND_PCM);
1058 if (myfile.is_open()) {
1059 while (getline(myfile, line)) {
1060 if (line.find(HAPTIC_PCM_DEVICE_SYMBOL) != std::string::npos) {
1061 std::stringstream ss(line);
1062 std::string currentToken;
1063 std::getline(ss, currentToken, ':');
1064 sscanf(currentToken.c_str(), "%d-%d", card, device);
1065 return true;
1066 }
1067 }
1068 myfile.close();
1069 } else {
1070 ALOGE("Failed to read file: %s", PROC_SND_PCM);
1071 }
1072 return false;
1073 }
1074
hasHapticAlsaDevice()1075 bool Vibrator::hasHapticAlsaDevice() {
1076 // We need to call findHapticAlsaDevice once only. Calling in the
1077 // constructor is too early in the boot process and the pcm file contents
1078 // are empty. Hence we make the call here once only right before we need to.
1079 static bool configHapticAlsaDeviceDone = false;
1080 if (!configHapticAlsaDeviceDone) {
1081 if (findHapticAlsaDevice(&mCard, &mDevice)) {
1082 mHasHapticAlsaDevice = true;
1083 configHapticAlsaDeviceDone = true;
1084 } else {
1085 ALOGE("Haptic ALSA device not supported");
1086 }
1087 }
1088 return mHasHapticAlsaDevice;
1089 }
1090
enableHapticPcmAmp(struct pcm ** haptic_pcm,bool enable,int card,int device)1091 bool Vibrator::enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) {
1092 int ret = 0;
1093
1094 if (enable) {
1095 *haptic_pcm = pcm_open(card, device, PCM_OUT, &haptic_nohost_config);
1096 if (!pcm_is_ready(*haptic_pcm)) {
1097 ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm));
1098 goto fail;
1099 }
1100
1101 ret = pcm_prepare(*haptic_pcm);
1102 if (ret < 0) {
1103 ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm));
1104 goto fail;
1105 }
1106
1107 ret = pcm_start(*haptic_pcm);
1108 if (ret < 0) {
1109 ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm));
1110 goto fail;
1111 }
1112
1113 return true;
1114 } else {
1115 if (*haptic_pcm) {
1116 pcm_close(*haptic_pcm);
1117 *haptic_pcm = NULL;
1118 }
1119 return true;
1120 }
1121
1122 fail:
1123 pcm_close(*haptic_pcm);
1124 *haptic_pcm = NULL;
1125 return false;
1126 }
1127
1128 } // namespace vibrator
1129 } // namespace hardware
1130 } // namespace android
1131 } // namespace aidl
1132