1 /*
2 * Copyright (C) 2021 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 <glob.h>
20 #include <hardware/hardware.h>
21 #include <hardware/vibrator.h>
22 #include <linux/input.h>
23 #include <log/log.h>
24 #include <stdio.h>
25 #include <utils/Trace.h>
26
27 #include <cinttypes>
28 #include <cmath>
29 #include <fstream>
30 #include <iostream>
31 #include <sstream>
32
33 #ifndef ARRAY_SIZE
34 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
35 #endif
36
37 #define PROC_SND_PCM "/proc/asound/pcm"
38 #define HAPTIC_PCM_DEVICE_SYMBOL "haptic nohost playback"
39
40 namespace aidl {
41 namespace android {
42 namespace hardware {
43 namespace vibrator {
44 static constexpr uint8_t FF_CUSTOM_DATA_LEN = 2;
45 static constexpr uint16_t FF_CUSTOM_DATA_LEN_MAX_COMP = 2044; // (COMPOSE_SIZE_MAX + 1) * 8 + 4
46
47 static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100;
48
49 static constexpr uint32_t WAVEFORM_LONG_VIBRATION_THRESHOLD_MS = 50;
50
51 static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
52
53 static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby
54 static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling
55 static constexpr uint32_t MAX_TIME_MS = UINT16_MAX;
56
57 static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100);
58 static constexpr auto POLLING_TIMEOUT = 20;
59 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000;
60
61 /* nsections is 8 bits. Need to preserve 1 section for the first delay before the first effect. */
62 static constexpr int32_t COMPOSE_SIZE_MAX = 254;
63 static constexpr int32_t COMPOSE_PWLE_SIZE_MAX_DEFAULT = 127;
64
65 // Measured resonant frequency, f0_measured, is represented by Q10.14 fixed
66 // point format on cs40l26 devices. The expression to calculate f0 is:
67 // f0 = f0_measured / 2^Q14_BIT_SHIFT
68 // See the LRA Calibration Support documentation for more details.
69 static constexpr int32_t Q14_BIT_SHIFT = 14;
70
71 // Measured Q factor, q_measured, is represented by Q8.16 fixed
72 // point format on cs40l26 devices. The expression to calculate q is:
73 // q = q_measured / 2^Q16_BIT_SHIFT
74 // See the LRA Calibration Support documentation for more details.
75 static constexpr int32_t Q16_BIT_SHIFT = 16;
76
77 static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
78
79 static constexpr float PWLE_LEVEL_MIN = 0.0;
80 static constexpr float PWLE_LEVEL_MAX = 1.0;
81 static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 0.25;
82 static constexpr float PWLE_FREQUENCY_MIN_HZ = 0.25;
83 static constexpr float PWLE_FREQUENCY_MAX_HZ = 1023.75;
84 static constexpr float PWLE_BW_MAP_SIZE =
85 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
86
87 static struct pcm_config haptic_nohost_config = {
88 .channels = 1,
89 .rate = 48000,
90 .period_size = 80,
91 .period_count = 2,
92 .format = PCM_FORMAT_S16_LE,
93 };
94
amplitudeToScale(float amplitude,float maximum)95 static uint16_t amplitudeToScale(float amplitude, float maximum) {
96 float ratio = 100; /* Unit: % */
97 if (maximum != 0)
98 ratio = amplitude / maximum * 100;
99
100 if (maximum == 0 || ratio > 100)
101 ratio = 100;
102
103 return std::round(ratio);
104 }
105
106 enum class AlwaysOnId : uint32_t {
107 GPIO_RISE,
108 GPIO_FALL,
109 };
110
111 enum WaveformBankID : uint8_t {
112 RAM_WVFRM_BANK,
113 ROM_WVFRM_BANK,
114 OWT_WVFRM_BANK,
115 };
116
117 enum WaveformIndex : uint16_t {
118 /* Physical waveform */
119 WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0,
120 WAVEFORM_RESERVED_INDEX_1 = 1,
121 WAVEFORM_CLICK_INDEX = 2,
122 WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3,
123 WAVEFORM_THUD_INDEX = 4,
124 WAVEFORM_SPIN_INDEX = 5,
125 WAVEFORM_QUICK_RISE_INDEX = 6,
126 WAVEFORM_SLOW_RISE_INDEX = 7,
127 WAVEFORM_QUICK_FALL_INDEX = 8,
128 WAVEFORM_LIGHT_TICK_INDEX = 9,
129 WAVEFORM_LOW_TICK_INDEX = 10,
130 WAVEFORM_RESERVED_MFG_1,
131 WAVEFORM_RESERVED_MFG_2,
132 WAVEFORM_RESERVED_MFG_3,
133 WAVEFORM_MAX_PHYSICAL_INDEX,
134 /* OWT waveform */
135 WAVEFORM_COMPOSE = WAVEFORM_MAX_PHYSICAL_INDEX,
136 WAVEFORM_PWLE,
137 /*
138 * Refer to <linux/input.h>, the WAVEFORM_MAX_INDEX must not exceed 96.
139 * #define FF_GAIN 0x60 // 96 in decimal
140 * #define FF_MAX_EFFECTS FF_GAIN
141 */
142 WAVEFORM_MAX_INDEX,
143 };
144
145 std::vector<CompositePrimitive> defaultSupportedPrimitives = {
146 ndk::enum_range<CompositePrimitive>().begin(), ndk::enum_range<CompositePrimitive>().end()};
147
min(int x,int y)148 static int min(int x, int y) {
149 return x < y ? x : y;
150 }
151
152 struct dspmem_chunk {
153 uint8_t *head;
154 uint8_t *current;
155 uint8_t *max;
156 int bytes;
157
158 uint32_t cache;
159 int cachebits;
160 };
161
dspmem_chunk_create(void * data,int size)162 static dspmem_chunk *dspmem_chunk_create(void *data, int size) {
163 auto ch = new dspmem_chunk{
164 .head = reinterpret_cast<uint8_t *>(data),
165 .current = reinterpret_cast<uint8_t *>(data),
166 .max = reinterpret_cast<uint8_t *>(data) + size,
167 };
168
169 return ch;
170 }
171
dspmem_chunk_end(struct dspmem_chunk * ch)172 static bool dspmem_chunk_end(struct dspmem_chunk *ch) {
173 return ch->current == ch->max;
174 }
175
dspmem_chunk_bytes(struct dspmem_chunk * ch)176 static int dspmem_chunk_bytes(struct dspmem_chunk *ch) {
177 return ch->bytes;
178 }
179
dspmem_chunk_write(struct dspmem_chunk * ch,int nbits,uint32_t val)180 static int dspmem_chunk_write(struct dspmem_chunk *ch, int nbits, uint32_t val) {
181 int nwrite, i;
182
183 nwrite = min(24 - ch->cachebits, nbits);
184 ch->cache <<= nwrite;
185 ch->cache |= val >> (nbits - nwrite);
186 ch->cachebits += nwrite;
187 nbits -= nwrite;
188
189 if (ch->cachebits == 24) {
190 if (dspmem_chunk_end(ch))
191 return -ENOSPC;
192
193 ch->cache &= 0xFFFFFF;
194 for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= 8)
195 *ch->current++ = (ch->cache & 0xFF000000) >> 24;
196
197 ch->bytes += sizeof(ch->cache);
198 ch->cachebits = 0;
199 }
200
201 if (nbits)
202 return dspmem_chunk_write(ch, nbits, val);
203
204 return 0;
205 }
206
dspmem_chunk_flush(struct dspmem_chunk * ch)207 static int dspmem_chunk_flush(struct dspmem_chunk *ch) {
208 if (!ch->cachebits)
209 return 0;
210
211 return dspmem_chunk_write(ch, 24 - ch->cachebits, 0);
212 }
213
214 std::vector<struct ff_effect> mFfEffects;
215
Vibrator(std::unique_ptr<HwApi> hwapi,std::unique_ptr<HwCal> hwcal)216 Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
217 : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)), mAsyncHandle(std::async([] {})) {
218 int32_t longFrequencyShift;
219 std::string caldata{8, '0'};
220 uint32_t calVer;
221
222 glob_t inputEventPaths;
223 if (glob("/dev/input/event*", 0, nullptr, &inputEventPaths)) {
224 ALOGE("Fail to get input event paths (%d): %s", errno, strerror(errno));
225 return;
226 }
227
228 int fd = -1;
229 uint32_t val = 0;
230 char str[20] = {0x00};
231 const char *inputEventName = std::getenv("INPUT_EVENT_NAME");
232 for (uint8_t retry = 0; retry < 3; retry++) {
233 for (int i = 0; i < inputEventPaths.gl_pathc; i++) {
234 fd = TEMP_FAILURE_RETRY(open(inputEventPaths.gl_pathv[i], O_RDWR));
235 if (fd > 0) {
236 if (ioctl(fd, EVIOCGBIT(0, sizeof(val)), &val) > 0 && (val & (1 << EV_FF)) &&
237 ioctl(fd, EVIOCGNAME(sizeof(str)), &str) > 0 &&
238 strcmp(str, inputEventName) == 0) {
239 mInputFd.reset(fd);
240 ALOGI("Control %s through %s", inputEventName, inputEventPaths.gl_pathv[i]);
241 break;
242 }
243 close(fd);
244 }
245 }
246 if (mInputFd.ok()) {
247 break;
248 }
249
250 sleep(1);
251 ALOGW("Retry to search the input");
252 }
253 globfree(&inputEventPaths);
254 if (!mInputFd.ok()) {
255 ALOGE("Fail to get an input event with name %s", inputEventName);
256 return;
257 }
258
259 /*
260 * Create custom effects for all physical waveforms.
261 * 1. Set the initial duration for the corresponding RAM waveform.
262 * 2. Write to the force feedback driver. If the waveform firmware is not loaded,
263 * retry at most 10 times and then abort the constructor.
264 * 3. Store the effect ID.
265 */
266 uint8_t retry = 0;
267 mFfEffects.resize(WAVEFORM_MAX_INDEX);
268 mEffectDurations.resize(WAVEFORM_MAX_INDEX);
269 mEffectDurations = {
270 1000, 100, 30, 1000, 300, 130, 150, 500, 100, 15, 20, 1000, 1000, 1000,
271 }; /* 11+3 waveforms. The duration must < UINT16_MAX */
272
273 uint8_t effectIndex = 0;
274
275 for (effectIndex = 0; effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX; effectIndex++) {
276 mFfEffects[effectIndex] = {
277 .type = FF_PERIODIC,
278 .id = -1,
279 .replay.length = static_cast<uint16_t>(mEffectDurations[effectIndex]),
280 .u.periodic.waveform = FF_CUSTOM,
281 .u.periodic.custom_data = new int16_t[2]{RAM_WVFRM_BANK, effectIndex},
282 .u.periodic.custom_len = FF_CUSTOM_DATA_LEN,
283 };
284
285 while (true) {
286 if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[effectIndex]) < 0) {
287 ALOGE("Failed upload effect %d (%d): %s", effectIndex, errno, strerror(errno));
288
289 if (retry < 10) {
290 sleep(1);
291 ALOGW("Retry #%u", ++retry);
292 continue;
293 } else {
294 ALOGE("Retried but the initialization was failed!");
295 return;
296 }
297 }
298 mFfEffects[effectIndex].id = effectIndex;
299 break;
300 }
301 }
302 if (effectIndex != WAVEFORM_MAX_PHYSICAL_INDEX) {
303 ALOGE("Incomplete effect initialization!");
304 return;
305 }
306
307 /* Initiate placeholders for OWT effects. */
308 for (effectIndex = WAVEFORM_MAX_PHYSICAL_INDEX; effectIndex < WAVEFORM_MAX_INDEX;
309 effectIndex++) {
310 mFfEffects[effectIndex] = {
311 .type = FF_PERIODIC,
312 .id = -1,
313 .replay.length = 0,
314 .u.periodic.waveform = FF_CUSTOM,
315 .u.periodic.custom_data = nullptr,
316 .u.periodic.custom_len = 0,
317 };
318 }
319
320 if (mHwCal->getF0(&caldata)) {
321 mHwApi->setF0(caldata);
322 }
323 if (mHwCal->getRedc(&caldata)) {
324 mHwApi->setRedc(caldata);
325 }
326 if (mHwCal->getQ(&caldata)) {
327 mHwApi->setQ(caldata);
328 }
329
330 mHwCal->getLongFrequencyShift(&longFrequencyShift);
331 if (longFrequencyShift > 0) {
332 mF0Offset = longFrequencyShift * std::pow(2, 14);
333 } else if (longFrequencyShift < 0) {
334 mF0Offset = std::pow(2, 24) - std::abs(longFrequencyShift) * std::pow(2, 14);
335 } else {
336 mF0Offset = 0;
337 }
338
339 mHwCal->getVersion(&calVer);
340 if (calVer == 2) {
341 mHwCal->getTickVolLevels(&mTickEffectVol);
342 mHwCal->getClickVolLevels(&mClickEffectVol);
343 mHwCal->getLongVolLevels(&mLongEffectVol);
344 } else {
345 ALOGW("Unsupported calibration version!");
346 }
347
348 mIsUnderExternalControl = false;
349
350 mIsChirpEnabled = mHwCal->isChirpEnabled();
351
352 mHwCal->getSupportedPrimitives(&mSupportedPrimitivesBits);
353 if (mSupportedPrimitivesBits > 0) {
354 for (auto e : defaultSupportedPrimitives) {
355 if (mSupportedPrimitivesBits & (1 << uint32_t(e))) {
356 mSupportedPrimitives.emplace_back(e);
357 }
358 }
359 } else {
360 for (auto e : defaultSupportedPrimitives) {
361 mSupportedPrimitivesBits |= (1 << uint32_t(e));
362 }
363 mSupportedPrimitives = defaultSupportedPrimitives;
364 }
365 }
366
getCapabilities(int32_t * _aidl_return)367 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
368 ATRACE_NAME("Vibrator::getCapabilities");
369
370 int32_t ret = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
371 IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_ALWAYS_ON_CONTROL |
372 IVibrator::CAP_GET_RESONANT_FREQUENCY | IVibrator::CAP_GET_Q_FACTOR;
373 if (hasHapticAlsaDevice()) {
374 ret |= IVibrator::CAP_EXTERNAL_CONTROL;
375 }
376 if (mHwApi->hasOwtFreeSpace()) {
377 ret |= IVibrator::CAP_COMPOSE_EFFECTS;
378
379 if (mIsChirpEnabled) {
380 ret |= IVibrator::CAP_FREQUENCY_CONTROL | IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
381 }
382 }
383 *_aidl_return = ret;
384 return ndk::ScopedAStatus::ok();
385 }
386
off()387 ndk::ScopedAStatus Vibrator::off() {
388 ATRACE_NAME("Vibrator::off");
389 if (mActiveId < 0) {
390 return ndk::ScopedAStatus::ok();
391 }
392
393 struct input_event play = {
394 .type = EV_FF,
395 .code = static_cast<uint16_t>(mActiveId),
396 .value = 0,
397 };
398
399 if (write(mInputFd, (const void *)&play, sizeof(play)) != sizeof(play)) {
400 ALOGE("Failed to stop effect %d (%d): %s", play.code, errno, strerror(errno));
401 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
402 }
403
404 mActiveId = -1;
405 setGlobalAmplitude(false);
406 mHwApi->setF0Offset(0);
407 return ndk::ScopedAStatus::ok();
408 }
409
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)410 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
411 const std::shared_ptr<IVibratorCallback> &callback) {
412 ATRACE_NAME("Vibrator::on");
413 if (timeoutMs > MAX_TIME_MS) {
414 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
415 }
416 const uint16_t index = (timeoutMs < WAVEFORM_LONG_VIBRATION_THRESHOLD_MS)
417 ? WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX
418 : WAVEFORM_LONG_VIBRATION_EFFECT_INDEX;
419 if (MAX_COLD_START_LATENCY_MS <= MAX_TIME_MS - timeoutMs) {
420 timeoutMs += MAX_COLD_START_LATENCY_MS;
421 }
422 setGlobalAmplitude(true);
423 mHwApi->setF0Offset(mF0Offset);
424 return on(timeoutMs, index, callback);
425 }
426
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)427 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
428 const std::shared_ptr<IVibratorCallback> &callback,
429 int32_t *_aidl_return) {
430 ATRACE_NAME("Vibrator::perform");
431 return performEffect(effect, strength, callback, _aidl_return);
432 }
433
getSupportedEffects(std::vector<Effect> * _aidl_return)434 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
435 *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
436 Effect::DOUBLE_CLICK};
437 return ndk::ScopedAStatus::ok();
438 }
439
setAmplitude(float amplitude)440 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
441 ATRACE_NAME("Vibrator::setAmplitude");
442 if (amplitude <= 0.0f || amplitude > 1.0f) {
443 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
444 }
445
446 mLongEffectScale = amplitude;
447 if (!isUnderExternalControl()) {
448 return setGlobalAmplitude(true);
449 } else {
450 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
451 }
452 }
453
setExternalControl(bool enabled)454 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
455 ATRACE_NAME("Vibrator::setExternalControl");
456 setGlobalAmplitude(enabled);
457
458 if (mHasHapticAlsaDevice) {
459 if (!enableHapticPcmAmp(&mHapticPcm, enabled, mCard, mDevice)) {
460 ALOGE("Failed to %s haptic pcm device: %d", (enabled ? "enable" : "disable"), mDevice);
461 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
462 }
463 }
464
465 mIsUnderExternalControl = enabled;
466 return ndk::ScopedAStatus::ok();
467 }
468
getCompositionDelayMax(int32_t * maxDelayMs)469 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t *maxDelayMs) {
470 ATRACE_NAME("Vibrator::getCompositionDelayMax");
471 *maxDelayMs = COMPOSE_DELAY_MAX_MS;
472 return ndk::ScopedAStatus::ok();
473 }
474
getCompositionSizeMax(int32_t * maxSize)475 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t *maxSize) {
476 ATRACE_NAME("Vibrator::getCompositionSizeMax");
477 *maxSize = COMPOSE_SIZE_MAX;
478 return ndk::ScopedAStatus::ok();
479 }
480
getSupportedPrimitives(std::vector<CompositePrimitive> * supported)481 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive> *supported) {
482 *supported = mSupportedPrimitives;
483 return ndk::ScopedAStatus::ok();
484 }
485
getPrimitiveDuration(CompositePrimitive primitive,int32_t * durationMs)486 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
487 int32_t *durationMs) {
488 ndk::ScopedAStatus status;
489 uint32_t effectIndex;
490 if (primitive != CompositePrimitive::NOOP) {
491 status = getPrimitiveDetails(primitive, &effectIndex);
492 if (!status.isOk()) {
493 return status;
494 }
495
496 *durationMs = mEffectDurations[effectIndex];
497 } else {
498 *durationMs = 0;
499 }
500 return ndk::ScopedAStatus::ok();
501 }
502
compose(const std::vector<CompositeEffect> & composite,const std::shared_ptr<IVibratorCallback> & callback)503 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composite,
504 const std::shared_ptr<IVibratorCallback> &callback) {
505 ATRACE_NAME("Vibrator::compose");
506 uint16_t size;
507 uint16_t nextEffectDelay;
508
509 auto ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_COMP]{0x00},
510 FF_CUSTOM_DATA_LEN_MAX_COMP);
511
512 if (composite.size() > COMPOSE_SIZE_MAX || composite.empty()) {
513 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
514 }
515
516 /* Check if there is a wait before the first effect. */
517 nextEffectDelay = composite.front().delayMs;
518 if (nextEffectDelay > COMPOSE_DELAY_MAX_MS || nextEffectDelay < 0) {
519 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
520 } else if (nextEffectDelay > 0) {
521 size = composite.size() + 1;
522 } else {
523 size = composite.size();
524 }
525
526 dspmem_chunk_write(ch, 8, 0); /* Padding */
527 dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & size)); /* nsections */
528 dspmem_chunk_write(ch, 8, 0); /* repeat */
529 uint8_t header_count = ch->bytes;
530
531 /* Insert 1 section for a wait before the first effect. */
532 if (nextEffectDelay) {
533 dspmem_chunk_write(ch, 32, 0); /* amplitude, index, repeat & flags */
534 dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */
535 }
536
537 for (uint32_t i_curr = 0, i_next = 1; i_curr < composite.size(); i_curr++, i_next++) {
538 auto &e_curr = composite[i_curr];
539 uint32_t effectIndex = 0;
540 uint32_t effectVolLevel = 0;
541 if (e_curr.scale < 0.0f || e_curr.scale > 1.0f) {
542 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
543 }
544
545 if (e_curr.primitive != CompositePrimitive::NOOP) {
546 ndk::ScopedAStatus status;
547 status = getPrimitiveDetails(e_curr.primitive, &effectIndex);
548 if (!status.isOk()) {
549 return status;
550 }
551 effectVolLevel = intensityToVolLevel(e_curr.scale, effectIndex);
552 }
553
554 /* Fetch the next composite effect delay and fill into the current section */
555 nextEffectDelay = 0;
556 if (i_next < composite.size()) {
557 auto &e_next = composite[i_next];
558 int32_t delay = e_next.delayMs;
559
560 if (delay > COMPOSE_DELAY_MAX_MS || delay < 0) {
561 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
562 }
563 nextEffectDelay = delay;
564 }
565
566 if (effectIndex == 0 && nextEffectDelay == 0) {
567 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
568 }
569
570 dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & effectVolLevel)); /* amplitude */
571 dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & effectIndex)); /* index */
572 dspmem_chunk_write(ch, 8, 0); /* repeat */
573 dspmem_chunk_write(ch, 8, 0); /* flags */
574 dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */
575 }
576 dspmem_chunk_flush(ch);
577 if (header_count == ch->bytes) {
578 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
579 } else {
580 return performEffect(0 /*ignored*/, 0 /*ignored*/, ch, callback);
581 }
582 }
583
on(uint32_t timeoutMs,uint32_t effectIndex,const std::shared_ptr<IVibratorCallback> & callback)584 ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex,
585 const std::shared_ptr<IVibratorCallback> &callback) {
586 if (effectIndex > WAVEFORM_MAX_INDEX) {
587 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
588 }
589 if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) {
590 ALOGE("Previous vibration pending.");
591 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
592 }
593
594 /* Update duration for long/short vibration. */
595 if (effectIndex == WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX ||
596 effectIndex == WAVEFORM_LONG_VIBRATION_EFFECT_INDEX) {
597 mFfEffects[effectIndex].replay.length = static_cast<uint16_t>(timeoutMs);
598 if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[effectIndex]) < 0) {
599 ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno));
600 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
601 }
602 }
603
604 /* Play the event now. */
605 struct input_event play = {
606 .type = EV_FF,
607 .code = static_cast<uint16_t>(effectIndex),
608 .value = 1,
609 };
610 if (write(mInputFd, (const void *)&play, sizeof(play)) != sizeof(play)) {
611 ALOGE("Failed to play effect %d (%d): %s", play.code, errno, strerror(errno));
612 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
613 }
614
615 mActiveId = play.code;
616
617 mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
618
619 return ndk::ScopedAStatus::ok();
620 }
621
setEffectAmplitude(float amplitude,float maximum)622 ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) {
623 uint16_t scale = amplitudeToScale(amplitude, maximum);
624 struct input_event gain = {
625 .type = EV_FF,
626 .code = FF_GAIN,
627 .value = scale,
628 };
629 if (write(mInputFd, (const void *)&gain, sizeof(gain)) != sizeof(gain)) {
630 ALOGE("Failed to set the gain to %u (%d): %s", scale, errno, strerror(errno));
631 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
632 }
633 return ndk::ScopedAStatus::ok();
634 }
635
setGlobalAmplitude(bool set)636 ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) {
637 uint8_t amplitude = set ? roundf(mLongEffectScale * mLongEffectVol[1]) : VOLTAGE_SCALE_MAX;
638 if (!set) {
639 mLongEffectScale = 1.0; // Reset the scale for the later new effect.
640 }
641 return setEffectAmplitude(amplitude, VOLTAGE_SCALE_MAX);
642 }
643
getSupportedAlwaysOnEffects(std::vector<Effect> * _aidl_return)644 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> *_aidl_return) {
645 *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK};
646 return ndk::ScopedAStatus::ok();
647 }
648
alwaysOnEnable(int32_t id,Effect effect,EffectStrength strength)649 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
650 ndk::ScopedAStatus status;
651 uint32_t effectIndex;
652 uint32_t timeMs;
653 uint32_t volLevel;
654 uint16_t scale;
655 status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
656 if (!status.isOk()) {
657 return status;
658 }
659
660 scale = amplitudeToScale(volLevel, VOLTAGE_SCALE_MAX);
661
662 switch (static_cast<AlwaysOnId>(id)) {
663 case AlwaysOnId::GPIO_RISE:
664 // mHwApi->setGpioRiseIndex(effectIndex);
665 // mHwApi->setGpioRiseScale(scale);
666 return ndk::ScopedAStatus::ok();
667 case AlwaysOnId::GPIO_FALL:
668 // mHwApi->setGpioFallIndex(effectIndex);
669 // mHwApi->setGpioFallScale(scale);
670 return ndk::ScopedAStatus::ok();
671 }
672
673 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
674 }
alwaysOnDisable(int32_t id)675 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
676 switch (static_cast<AlwaysOnId>(id)) {
677 case AlwaysOnId::GPIO_RISE:
678 // mHwApi->setGpioRiseIndex(0);
679 return ndk::ScopedAStatus::ok();
680 case AlwaysOnId::GPIO_FALL:
681 // mHwApi->setGpioFallIndex(0);
682 return ndk::ScopedAStatus::ok();
683 }
684
685 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
686 }
687
getResonantFrequency(float * resonantFreqHz)688 ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
689 std::string caldata{8, '0'};
690 if (!mHwCal->getF0(&caldata)) {
691 ALOGE("Failed to get resonant frequency (%d): %s", errno, strerror(errno));
692 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
693 }
694 *resonantFreqHz = static_cast<float>(std::stoul(caldata, nullptr, 16)) / (1 << Q14_BIT_SHIFT);
695
696 return ndk::ScopedAStatus::ok();
697 }
698
getQFactor(float * qFactor)699 ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
700 std::string caldata{8, '0'};
701 if (!mHwCal->getQ(&caldata)) {
702 ALOGE("Failed to get q factor (%d): %s", errno, strerror(errno));
703 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
704 }
705 *qFactor = static_cast<float>(std::stoul(caldata, nullptr, 16)) / (1 << Q16_BIT_SHIFT);
706
707 return ndk::ScopedAStatus::ok();
708 }
709
getFrequencyResolution(float * freqResolutionHz)710 ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
711 int32_t capabilities;
712 Vibrator::getCapabilities(&capabilities);
713 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
714 *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
715 return ndk::ScopedAStatus::ok();
716 } else {
717 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
718 }
719 }
720
getFrequencyMinimum(float * freqMinimumHz)721 ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
722 int32_t capabilities;
723 Vibrator::getCapabilities(&capabilities);
724 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
725 *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
726 return ndk::ScopedAStatus::ok();
727 } else {
728 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
729 }
730 }
731
getBandwidthAmplitudeMap(std::vector<float> * _aidl_return)732 ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
733 // TODO(b/170919640): complete implementation
734 int32_t capabilities;
735 Vibrator::getCapabilities(&capabilities);
736 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
737 std::vector<float> bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, 1.0);
738 *_aidl_return = bandwidthAmplitudeMap;
739 return ndk::ScopedAStatus::ok();
740 } else {
741 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
742 }
743 }
744
getPwlePrimitiveDurationMax(int32_t * durationMs)745 ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
746 int32_t capabilities;
747 Vibrator::getCapabilities(&capabilities);
748 if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
749 *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
750 return ndk::ScopedAStatus::ok();
751 } else {
752 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
753 }
754 }
755
getPwleCompositionSizeMax(int32_t * maxSize)756 ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
757 int32_t capabilities;
758 Vibrator::getCapabilities(&capabilities);
759 if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
760 *maxSize = COMPOSE_PWLE_SIZE_MAX_DEFAULT;
761 return ndk::ScopedAStatus::ok();
762 } else {
763 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
764 }
765 }
766
getSupportedBraking(std::vector<Braking> * supported)767 ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
768 int32_t capabilities;
769 Vibrator::getCapabilities(&capabilities);
770 if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
771 *supported = {
772 Braking::NONE,
773 Braking::CLAB,
774 };
775 return ndk::ScopedAStatus::ok();
776 } else {
777 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
778 }
779 }
780
setPwle(const std::string & pwleQueue)781 ndk::ScopedAStatus Vibrator::setPwle(const std::string &pwleQueue) {
782 if (!mHwApi->setPwle(pwleQueue)) {
783 ALOGE("Failed to write \"%s\" to pwle (%d): %s", pwleQueue.c_str(), errno, strerror(errno));
784 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
785 }
786
787 return ndk::ScopedAStatus::ok();
788 }
789
resetPreviousEndAmplitudeEndFrequency(float * prevEndAmplitude,float * prevEndFrequency)790 static void resetPreviousEndAmplitudeEndFrequency(float *prevEndAmplitude,
791 float *prevEndFrequency) {
792 const float reset = -1.0;
793 *prevEndAmplitude = reset;
794 *prevEndFrequency = reset;
795 }
796
incrementIndex(int * index)797 static void incrementIndex(int *index) {
798 *index += 1;
799 }
800
constructActiveDefaults(std::ostringstream & pwleBuilder,const int & segmentIdx)801 static void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
802 pwleBuilder << ",C" << segmentIdx << ":1";
803 pwleBuilder << ",B" << segmentIdx << ":0";
804 pwleBuilder << ",AR" << segmentIdx << ":0";
805 pwleBuilder << ",V" << segmentIdx << ":0";
806 }
807
constructActiveSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,float amplitude,float frequency)808 static void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx,
809 int duration, float amplitude, float frequency) {
810 pwleBuilder << ",T" << segmentIdx << ":" << duration;
811 pwleBuilder << ",L" << segmentIdx << ":" << amplitude;
812 pwleBuilder << ",F" << segmentIdx << ":" << frequency;
813 constructActiveDefaults(pwleBuilder, segmentIdx);
814 }
815
constructBrakingSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,Braking brakingType)816 static void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx,
817 int duration, Braking brakingType) {
818 pwleBuilder << ",T" << segmentIdx << ":" << duration;
819 pwleBuilder << ",L" << segmentIdx << ":" << 0;
820 pwleBuilder << ",F" << segmentIdx << ":" << PWLE_FREQUENCY_MIN_HZ;
821 pwleBuilder << ",C" << segmentIdx << ":0";
822 pwleBuilder << ",B" << segmentIdx << ":"
823 << static_cast<std::underlying_type<Braking>::type>(brakingType);
824 pwleBuilder << ",AR" << segmentIdx << ":0";
825 pwleBuilder << ",V" << segmentIdx << ":0";
826 }
827
composePwle(const std::vector<PrimitivePwle> & composite,const std::shared_ptr<IVibratorCallback> & callback)828 ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
829 const std::shared_ptr<IVibratorCallback> &callback) {
830 ATRACE_NAME("Vibrator::composePwle");
831 std::ostringstream pwleBuilder;
832 std::string pwleQueue;
833 int32_t capabilities;
834 Vibrator::getCapabilities(&capabilities);
835 if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) == 0) {
836 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
837 }
838
839 if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
840 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
841 }
842
843 float prevEndAmplitude;
844 float prevEndFrequency;
845 resetPreviousEndAmplitudeEndFrequency(&prevEndAmplitude, &prevEndFrequency);
846
847 int segmentIdx = 0;
848 uint32_t totalDuration = 0;
849
850 pwleBuilder << "S:0,WF:4,RP:0,WT:0";
851
852 for (auto &e : composite) {
853 switch (e.getTag()) {
854 case PrimitivePwle::active: {
855 auto active = e.get<PrimitivePwle::active>();
856 if (active.duration < 0 ||
857 active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
858 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
859 }
860 if (active.startAmplitude < PWLE_LEVEL_MIN ||
861 active.startAmplitude > PWLE_LEVEL_MAX ||
862 active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
863 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
864 }
865 if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
866 active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
867 active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
868 active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
869 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
870 }
871
872 if (!((active.startAmplitude == prevEndAmplitude) &&
873 (active.startFrequency == prevEndFrequency))) {
874 constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
875 active.startFrequency);
876 incrementIndex(&segmentIdx);
877 }
878
879 constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
880 active.endAmplitude, active.endFrequency);
881 incrementIndex(&segmentIdx);
882
883 prevEndAmplitude = active.endAmplitude;
884 prevEndFrequency = active.endFrequency;
885 totalDuration += active.duration;
886 break;
887 }
888 case PrimitivePwle::braking: {
889 auto braking = e.get<PrimitivePwle::braking>();
890 if (braking.braking > Braking::CLAB) {
891 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
892 }
893 if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
894 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
895 }
896
897 constructBrakingSegment(pwleBuilder, segmentIdx, 0, braking.braking);
898 incrementIndex(&segmentIdx);
899
900 constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking);
901 incrementIndex(&segmentIdx);
902
903 resetPreviousEndAmplitudeEndFrequency(&prevEndAmplitude, &prevEndFrequency);
904 totalDuration += braking.duration;
905 break;
906 }
907 }
908 }
909
910 pwleQueue = pwleBuilder.str();
911 ALOGD("composePwle queue: (%s)", pwleQueue.c_str());
912
913 ndk::ScopedAStatus status = setPwle(pwleQueue);
914 if (!status.isOk()) {
915 ALOGE("Failed to write pwle queue");
916 return status;
917 }
918
919 // mHwApi->setEffectIndex(WAVEFORM_UNSAVED_TRIGGER_QUEUE_INDEX);
920
921 totalDuration += MAX_COLD_START_LATENCY_MS;
922 // mHwApi->setDuration(MAX_TIME_MS);
923
924 // mHwApi->setActivate(1);
925
926 mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
927
928 return ndk::ScopedAStatus::ok();
929 }
930
isUnderExternalControl()931 bool Vibrator::isUnderExternalControl() {
932 return mIsUnderExternalControl;
933 }
934
dump(int fd,const char ** args,uint32_t numArgs)935 binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
936 if (fd < 0) {
937 ALOGE("Called debug() with invalid fd.");
938 return STATUS_OK;
939 }
940
941 (void)args;
942 (void)numArgs;
943
944 dprintf(fd, "AIDL:\n");
945
946 dprintf(fd, " F0 Offset: %" PRIu32 "\n", mF0Offset);
947
948 dprintf(fd, " Voltage Levels:\n");
949 dprintf(fd, " Tick Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mTickEffectVol[0],
950 mTickEffectVol[1]);
951 dprintf(fd, " Click Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mClickEffectVol[0],
952 mClickEffectVol[1]);
953 dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mLongEffectVol[0],
954 mLongEffectVol[1]);
955
956 dprintf(fd, " FF effect:\n");
957 dprintf(fd, " Physical waveform:\n");
958 dprintf(fd, "\tId\tIndex\tt ->\tt'\n");
959 for (uint8_t effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) {
960 dprintf(fd, "\t%d\t%d\t%d\t%d\n", mFfEffects[effectId].id,
961 mFfEffects[effectId].u.periodic.custom_data[1], mEffectDurations[effectId],
962 mFfEffects[effectId].replay.length);
963 }
964 dprintf(fd, " OWT waveform:\n");
965 dprintf(fd, "\tId\tBytes\tData\n");
966 for (uint8_t effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX;
967 effectId++) {
968 uint32_t numBytes = mFfEffects[effectId].u.periodic.custom_len * 2;
969 std::stringstream ss;
970 ss << " ";
971 for (int i = 0; i < numBytes; i++) {
972 ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex
973 << (uint16_t)(*(
974 reinterpret_cast<uint8_t *>(mFfEffects[effectId].u.periodic.custom_data) +
975 i))
976 << " ";
977 }
978 dprintf(fd, "\t%d\t%d\t{%s}\n", mFfEffects[effectId].id, numBytes, ss.str().c_str());
979 }
980
981 dprintf(fd, "\n");
982 dprintf(fd, "\n");
983
984 mHwApi->debug(fd);
985
986 dprintf(fd, "\n");
987
988 mHwCal->debug(fd);
989
990 fsync(fd);
991 return STATUS_OK;
992 }
993
findHapticAlsaDevice(int * card,int * device)994 bool Vibrator::findHapticAlsaDevice(int *card, int *device) {
995 std::string line;
996 std::ifstream myfile(PROC_SND_PCM);
997 if (myfile.is_open()) {
998 while (getline(myfile, line)) {
999 if (line.find(HAPTIC_PCM_DEVICE_SYMBOL) != std::string::npos) {
1000 std::stringstream ss(line);
1001 std::string currentToken;
1002 std::getline(ss, currentToken, ':');
1003 sscanf(currentToken.c_str(), "%d-%d", card, device);
1004 return true;
1005 }
1006 }
1007 myfile.close();
1008 } else {
1009 ALOGE("Failed to read file: %s", PROC_SND_PCM);
1010 }
1011 return false;
1012 }
1013
hasHapticAlsaDevice()1014 bool Vibrator::hasHapticAlsaDevice() {
1015 // We need to call findHapticAlsaDevice once only. Calling in the
1016 // constructor is too early in the boot process and the pcm file contents
1017 // are empty. Hence we make the call here once only right before we need to.
1018 static bool configHapticAlsaDeviceDone = false;
1019 if (!configHapticAlsaDeviceDone) {
1020 if (findHapticAlsaDevice(&mCard, &mDevice)) {
1021 mHasHapticAlsaDevice = true;
1022 configHapticAlsaDeviceDone = true;
1023 } else {
1024 ALOGE("Haptic ALSA device not supported");
1025 }
1026 }
1027 return mHasHapticAlsaDevice;
1028 }
1029
enableHapticPcmAmp(struct pcm ** haptic_pcm,bool enable,int card,int device)1030 bool Vibrator::enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) {
1031 int ret = 0;
1032
1033 if (enable) {
1034 *haptic_pcm = pcm_open(card, device, PCM_OUT, &haptic_nohost_config);
1035 if (!pcm_is_ready(*haptic_pcm)) {
1036 ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm));
1037 goto fail;
1038 }
1039
1040 ret = pcm_prepare(*haptic_pcm);
1041 if (ret < 0) {
1042 ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm));
1043 goto fail;
1044 }
1045
1046 ret = pcm_start(*haptic_pcm);
1047 if (ret < 0) {
1048 ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm));
1049 goto fail;
1050 }
1051
1052 return true;
1053 } else {
1054 if (*haptic_pcm) {
1055 pcm_close(*haptic_pcm);
1056 *haptic_pcm = NULL;
1057 }
1058 return true;
1059 }
1060
1061 fail:
1062 pcm_close(*haptic_pcm);
1063 *haptic_pcm = NULL;
1064 return false;
1065 }
1066
getSimpleDetails(Effect effect,EffectStrength strength,uint32_t * outEffectIndex,uint32_t * outTimeMs,uint32_t * outVolLevel)1067 ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
1068 uint32_t *outEffectIndex, uint32_t *outTimeMs,
1069 uint32_t *outVolLevel) {
1070 uint32_t effectIndex;
1071 uint32_t timeMs;
1072 float intensity;
1073 uint32_t volLevel;
1074 switch (strength) {
1075 case EffectStrength::LIGHT:
1076 intensity = 0.5f;
1077 break;
1078 case EffectStrength::MEDIUM:
1079 intensity = 0.7f;
1080 break;
1081 case EffectStrength::STRONG:
1082 intensity = 1.0f;
1083 break;
1084 default:
1085 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1086 }
1087
1088 switch (effect) {
1089 case Effect::TEXTURE_TICK:
1090 effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
1091 intensity *= 0.5f;
1092 break;
1093 case Effect::TICK:
1094 effectIndex = WAVEFORM_CLICK_INDEX;
1095 intensity *= 0.5f;
1096 break;
1097 case Effect::CLICK:
1098 effectIndex = WAVEFORM_CLICK_INDEX;
1099 intensity *= 0.7f;
1100 break;
1101 case Effect::HEAVY_CLICK:
1102 effectIndex = WAVEFORM_CLICK_INDEX;
1103 intensity *= 1.0f;
1104 break;
1105 default:
1106 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1107 }
1108
1109 volLevel = intensityToVolLevel(intensity, effectIndex);
1110 timeMs = mEffectDurations[effectIndex] + MAX_COLD_START_LATENCY_MS;
1111
1112 *outEffectIndex = effectIndex;
1113 *outTimeMs = timeMs;
1114 *outVolLevel = volLevel;
1115 return ndk::ScopedAStatus::ok();
1116 }
1117
getCompoundDetails(Effect effect,EffectStrength strength,uint32_t * outTimeMs,dspmem_chunk * outCh)1118 ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
1119 uint32_t *outTimeMs, dspmem_chunk *outCh) {
1120 ndk::ScopedAStatus status;
1121 uint32_t timeMs = 0;
1122 uint32_t thisEffectIndex;
1123 uint32_t thisTimeMs;
1124 uint32_t thisVolLevel;
1125 switch (effect) {
1126 case Effect::DOUBLE_CLICK:
1127 dspmem_chunk_write(outCh, 8, 0); /* Padding */
1128 dspmem_chunk_write(outCh, 8, 2); /* nsections */
1129 dspmem_chunk_write(outCh, 8, 0); /* repeat */
1130
1131 status = getSimpleDetails(Effect::CLICK, strength, &thisEffectIndex, &thisTimeMs,
1132 &thisVolLevel);
1133 if (!status.isOk()) {
1134 return status;
1135 }
1136 timeMs += thisTimeMs;
1137
1138 dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisVolLevel)); /* amplitude */
1139 dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisEffectIndex)); /* index */
1140 dspmem_chunk_write(outCh, 8, 0); /* repeat */
1141 dspmem_chunk_write(outCh, 8, 0); /* flags */
1142 dspmem_chunk_write(outCh, 16,
1143 (uint16_t)(0xFFFF & WAVEFORM_DOUBLE_CLICK_SILENCE_MS)); /* delay */
1144
1145 timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
1146
1147 status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisEffectIndex, &thisTimeMs,
1148 &thisVolLevel);
1149 if (!status.isOk()) {
1150 return status;
1151 }
1152 timeMs += thisTimeMs;
1153
1154 dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisVolLevel)); /* amplitude */
1155 dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisEffectIndex)); /* index */
1156 dspmem_chunk_write(outCh, 8, 0); /* repeat */
1157 dspmem_chunk_write(outCh, 8, 0); /* flags */
1158 dspmem_chunk_write(outCh, 16, 0); /* delay */
1159 dspmem_chunk_flush(outCh);
1160
1161 break;
1162 default:
1163 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1164 }
1165
1166 *outTimeMs = timeMs;
1167
1168 return ndk::ScopedAStatus::ok();
1169 }
1170
getPrimitiveDetails(CompositePrimitive primitive,uint32_t * outEffectIndex)1171 ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive,
1172 uint32_t *outEffectIndex) {
1173 uint32_t effectIndex;
1174 uint32_t primitiveBit = 1 << int32_t(primitive);
1175 if ((primitiveBit & mSupportedPrimitivesBits) == 0x0) {
1176 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1177 }
1178
1179 switch (primitive) {
1180 case CompositePrimitive::NOOP:
1181 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1182 case CompositePrimitive::CLICK:
1183 effectIndex = WAVEFORM_CLICK_INDEX;
1184 break;
1185 case CompositePrimitive::THUD:
1186 effectIndex = WAVEFORM_THUD_INDEX;
1187 break;
1188 case CompositePrimitive::SPIN:
1189 effectIndex = WAVEFORM_SPIN_INDEX;
1190 break;
1191 case CompositePrimitive::QUICK_RISE:
1192 effectIndex = WAVEFORM_QUICK_RISE_INDEX;
1193 break;
1194 case CompositePrimitive::SLOW_RISE:
1195 effectIndex = WAVEFORM_SLOW_RISE_INDEX;
1196 break;
1197 case CompositePrimitive::QUICK_FALL:
1198 effectIndex = WAVEFORM_QUICK_FALL_INDEX;
1199 break;
1200 case CompositePrimitive::LIGHT_TICK:
1201 effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
1202 break;
1203 case CompositePrimitive::LOW_TICK:
1204 effectIndex = WAVEFORM_LOW_TICK_INDEX;
1205 break;
1206 default:
1207 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1208 }
1209
1210 *outEffectIndex = effectIndex;
1211
1212 return ndk::ScopedAStatus::ok();
1213 }
1214
uploadOwtEffect(uint8_t * owtData,uint32_t numBytes,uint32_t * outEffectIndex)1215 ndk::ScopedAStatus Vibrator::uploadOwtEffect(uint8_t *owtData, uint32_t numBytes,
1216 uint32_t *outEffectIndex) {
1217 if (owtData == nullptr) {
1218 ALOGE("Invalid waveform bank");
1219 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1220 }
1221
1222 bool isPwle = (*reinterpret_cast<uint16_t *>(owtData) != 0x0000);
1223 WaveformIndex targetId = isPwle ? WAVEFORM_PWLE : WAVEFORM_COMPOSE;
1224
1225 /* Erase the created OWT waveform. */
1226 bool isCreated = (mFfEffects[targetId].id != -1);
1227 if (isCreated && ioctl(mInputFd, EVIOCRMFF, mFfEffects[targetId].id) < 0) {
1228 ALOGW("Failed to erase effect %d(%d) (%d): %s", targetId, mFfEffects[targetId].id, errno,
1229 strerror(errno));
1230 mFfEffects[targetId].id = -1;
1231 }
1232
1233 uint32_t freeBytes;
1234 mHwApi->getOwtFreeSpace(&freeBytes);
1235 if (numBytes > freeBytes) {
1236 ALOGE("Effect %d length: %d > %d!", targetId, numBytes, freeBytes);
1237 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1238 }
1239
1240 /* Create a new OWT waveform to update the PWLE or composite effect. */
1241 mFfEffects[targetId].id = -1; /* New Effect */
1242 mFfEffects[targetId].u.periodic.custom_len = numBytes / 2; /* # of 16-bit elements */
1243 delete[](mFfEffects[targetId].u.periodic.custom_data);
1244 mFfEffects[targetId].u.periodic.custom_data =
1245 new int16_t[mFfEffects[targetId].u.periodic.custom_len]{0x0000};
1246 if (mFfEffects[targetId].u.periodic.custom_data == nullptr) {
1247 ALOGE("Failed to allocate memory for custom data\n");
1248 return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
1249 }
1250 memcpy(mFfEffects[targetId].u.periodic.custom_data, owtData, numBytes);
1251
1252 if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[targetId]) < 0) {
1253 ALOGE("Failed to upload effect %d (%d): %s", targetId, errno, strerror(errno));
1254 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
1255 }
1256
1257 *outEffectIndex = mFfEffects[targetId].id;
1258
1259 return ndk::ScopedAStatus::ok();
1260 }
1261
performEffect(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * outTimeMs)1262 ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
1263 const std::shared_ptr<IVibratorCallback> &callback,
1264 int32_t *outTimeMs) {
1265 ndk::ScopedAStatus status;
1266 uint32_t effectIndex;
1267 uint32_t timeMs = 0;
1268 uint32_t volLevel;
1269 dspmem_chunk *ch = nullptr;
1270
1271 switch (effect) {
1272 case Effect::TEXTURE_TICK:
1273 // fall-through
1274 case Effect::TICK:
1275 // fall-through
1276 case Effect::CLICK:
1277 // fall-through
1278 case Effect::HEAVY_CLICK:
1279 status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
1280 break;
1281 case Effect::DOUBLE_CLICK:
1282 ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_COMP]{0x00},
1283 FF_CUSTOM_DATA_LEN_MAX_COMP);
1284 status = getCompoundDetails(effect, strength, &timeMs, ch);
1285 break;
1286 default:
1287 status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1288 break;
1289 }
1290 if (!status.isOk()) {
1291 goto exit;
1292 }
1293
1294 status = performEffect(static_cast<uint16_t>(effectIndex), volLevel, ch, callback);
1295
1296 exit:
1297 *outTimeMs = timeMs;
1298 return status;
1299 }
1300
performEffect(uint32_t effectIndex,uint32_t volLevel,dspmem_chunk * ch,const std::shared_ptr<IVibratorCallback> & callback)1301 ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
1302 dspmem_chunk *ch,
1303 const std::shared_ptr<IVibratorCallback> &callback) {
1304 if (ch) {
1305 ndk::ScopedAStatus status = uploadOwtEffect(ch->head, dspmem_chunk_bytes(ch), &effectIndex);
1306 delete ch;
1307 if (!status.isOk()) {
1308 return status;
1309 }
1310 setEffectAmplitude(VOLTAGE_SCALE_MAX, VOLTAGE_SCALE_MAX);
1311 } else {
1312 setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
1313 }
1314
1315 return on(MAX_TIME_MS, effectIndex, callback);
1316 }
1317
waitForComplete(std::shared_ptr<IVibratorCallback> && callback)1318 void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) {
1319 if (!mHwApi->pollVibeState("Vibe state: Haptic\n", POLLING_TIMEOUT)) {
1320 ALOGE("Fail to get state \"Haptic\"");
1321 }
1322 mHwApi->pollVibeState("Vibe state: Stopped\n");
1323
1324 if (callback) {
1325 auto ret = callback->onComplete();
1326 if (!ret.isOk()) {
1327 ALOGE("Failed completion callback: %d", ret.getExceptionCode());
1328 }
1329 }
1330 }
1331
intensityToVolLevel(float intensity,uint32_t effectIndex)1332 uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) {
1333 uint32_t volLevel;
1334 auto calc = [](float intst, std::array<uint32_t, 2> v) -> uint32_t {
1335 return std::lround(intst * (v[1] - v[0])) + v[0];
1336 };
1337
1338 switch (effectIndex) {
1339 case WAVEFORM_LIGHT_TICK_INDEX:
1340 volLevel = calc(intensity, mTickEffectVol);
1341 break;
1342 case WAVEFORM_QUICK_RISE_INDEX:
1343 // fall-through
1344 case WAVEFORM_QUICK_FALL_INDEX:
1345 volLevel = calc(intensity, mLongEffectVol);
1346 break;
1347 case WAVEFORM_CLICK_INDEX:
1348 // fall-through
1349 case WAVEFORM_THUD_INDEX:
1350 // fall-through
1351 case WAVEFORM_SPIN_INDEX:
1352 // fall-through
1353 case WAVEFORM_SLOW_RISE_INDEX:
1354 // fall-through
1355 default:
1356 volLevel = calc(intensity, mClickEffectVol);
1357 break;
1358 }
1359 return volLevel;
1360 }
1361
1362 } // namespace vibrator
1363 } // namespace hardware
1364 } // namespace android
1365 } // namespace aidl
1366