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