1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Vibrator.h"
18 
19 #include <android-base/properties.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 <map>
31 #include <sstream>
32 
33 #include "Stats.h"
34 
35 #ifndef ARRAY_SIZE
36 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
37 #endif
38 
39 #define PROC_SND_PCM "/proc/asound/pcm"
40 #define HAPTIC_PCM_DEVICE_SYMBOL "haptic nohost playback"
41 
42 namespace aidl {
43 namespace android {
44 namespace hardware {
45 namespace vibrator {
46 
47 #ifdef HAPTIC_TRACE
48 #define HAPTICS_TRACE(...) ALOGD(__VA_ARGS__)
49 #else
50 #define HAPTICS_TRACE(...)
51 #endif
52 
53 static constexpr uint32_t BASE_CONTINUOUS_EFFECT_OFFSET = 32768;
54 
55 static constexpr uint32_t WAVEFORM_EFFECT_0_20_LEVEL = 0;
56 static constexpr uint32_t WAVEFORM_EFFECT_1_00_LEVEL = 4;
57 static constexpr uint32_t WAVEFORM_EFFECT_LEVEL_MINIMUM = 4;
58 
59 static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100;
60 
61 static constexpr uint32_t WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0;
62 static constexpr uint32_t WAVEFORM_LONG_VIBRATION_THRESHOLD_MS = 50;
63 static constexpr uint32_t WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3 + BASE_CONTINUOUS_EFFECT_OFFSET;
64 
65 static constexpr uint32_t WAVEFORM_CLICK_INDEX = 2;
66 static constexpr uint32_t WAVEFORM_THUD_INDEX = 4;
67 static constexpr uint32_t WAVEFORM_SPIN_INDEX = 5;
68 static constexpr uint32_t WAVEFORM_QUICK_RISE_INDEX = 6;
69 static constexpr uint32_t WAVEFORM_SLOW_RISE_INDEX = 7;
70 static constexpr uint32_t WAVEFORM_QUICK_FALL_INDEX = 8;
71 static constexpr uint32_t WAVEFORM_LIGHT_TICK_INDEX = 9;
72 static constexpr uint32_t WAVEFORM_LOW_TICK_INDEX = 10;
73 
74 static constexpr uint32_t WAVEFORM_UNSAVED_TRIGGER_QUEUE_INDEX = 65529;
75 static constexpr uint32_t WAVEFORM_TRIGGER_QUEUE_INDEX = 65534;
76 static constexpr uint32_t VOLTAGE_GLOBAL_SCALE_LEVEL = 5;
77 static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
78 
79 static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6;  // I2C Transaction + DSP Return-From-Standby
80 static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1;  // ALERT Irq Handling
81 static constexpr uint32_t MAX_TIME_MS = UINT32_MAX;
82 
83 static constexpr float AMP_ATTENUATE_STEP_SIZE = 0.125f;
84 static constexpr float EFFECT_FREQUENCY_KHZ = 48.0f;
85 
86 static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100);
87 static constexpr auto POLLING_TIMEOUT = 20;
88 
89 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000;
90 static constexpr int32_t COMPOSE_SIZE_MAX = 127;
91 static constexpr int32_t COMPOSE_PWLE_SIZE_LIMIT = 82;
92 static constexpr int32_t CS40L2X_PWLE_LENGTH_MAX = 4094;
93 
94 // Measured resonant frequency, f0_measured, is represented by Q10.14 fixed
95 // point format on cs40l2x devices. The expression to calculate f0 is:
96 //   f0 = f0_measured / 2^Q14_BIT_SHIFT
97 // See the LRA Calibration Support documentation for more details.
98 static constexpr int32_t Q14_BIT_SHIFT = 14;
99 
100 // Measured Q factor, q_measured, is represented by Q8.16 fixed
101 // point format on cs40l2x devices. The expression to calculate q is:
102 //   q = q_measured / 2^Q16_BIT_SHIFT
103 // See the LRA Calibration Support documentation for more details.
104 static constexpr int32_t Q16_BIT_SHIFT = 16;
105 
106 // Measured ReDC, redc_measured, is represented by Q7.17 fixed
107 // point format on cs40l2x devices. The expression to calculate redc is:
108 //   redc = redc_measured * 5.857 / 2^Q17_BIT_SHIFT
109 // See the LRA Calibration Support documentation for more details.
110 static constexpr int32_t Q17_BIT_SHIFT = 17;
111 
112 static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 999;
113 static constexpr float PWLE_LEVEL_MIN = 0.0f;
114 static constexpr float PWLE_LEVEL_MAX = 1.0f;
115 static constexpr float CS40L2X_PWLE_LEVEL_MAX = 0.99f;
116 static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0f;
117 static constexpr float PWLE_FREQUENCY_MIN_HZ = 30.0f;
118 static constexpr float RESONANT_FREQUENCY_DEFAULT = 145.0f;
119 static constexpr float PWLE_FREQUENCY_MAX_HZ = 300.0f;
120 static constexpr float PWLE_BW_MAP_SIZE =
121     1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
122 static constexpr float RAMP_DOWN_CONSTANT = 1048.576f;
123 static constexpr float RAMP_DOWN_TIME_MS = 0.0f;
124 
125 static struct pcm_config haptic_nohost_config = {
126     .channels = 1,
127     .rate = 48000,
128     .period_size = 80,
129     .period_count = 2,
130     .format = PCM_FORMAT_S16_LE,
131 };
132 
amplitudeToScale(float amplitude,float maximum)133 static uint8_t amplitudeToScale(float amplitude, float maximum) {
134     return std::round((-20 * std::log10(amplitude / static_cast<float>(maximum))) /
135                       (AMP_ATTENUATE_STEP_SIZE));
136 }
137 
138 // Discrete points of frequency:max_level pairs as recommended by the document
139 #if defined(LUXSHARE_ICT_081545)
140 static std::map<float, float> discretePwleMaxLevels = {{120.0, 0.4},  {130.0, 0.31}, {140.0, 0.14},
141                                                        {145.0, 0.09}, {150.0, 0.15}, {160.0, 0.35},
142                                                        {170.0, 0.4}};
143 // Discrete points of frequency:max_level pairs as recommended by the document
144 #elif defined(LUXSHARE_ICT_LT_XLRA1906D)
145 static std::map<float, float> discretePwleMaxLevels = {{145.0, 0.38}, {150.0, 0.35}, {160.0, 0.35},
146                                                        {170.0, 0.15}, {180.0, 0.35}, {190.0, 0.35},
147                                                        {200.0, 0.38}};
148 #else
149 static std::map<float, float> discretePwleMaxLevels = {};
150 #endif
151 
152 // Initialize all limits to 0.4 according to the document Max. Allowable Chirp Levels
153 #if defined(LUXSHARE_ICT_081545)
154 std::vector<float> pwleMaxLevelLimitMap(PWLE_BW_MAP_SIZE, 0.4);
155 // Initialize all limits to 0.38 according to the document Max. Allowable Chirp Levels
156 #elif defined(LUXSHARE_ICT_LT_XLRA1906D)
157 std::vector<float> pwleMaxLevelLimitMap(PWLE_BW_MAP_SIZE, 0.38);
158 #else
159 std::vector<float> pwleMaxLevelLimitMap(PWLE_BW_MAP_SIZE, 1.0);
160 #endif
161 
createPwleMaxLevelLimitMap()162 void Vibrator::createPwleMaxLevelLimitMap() {
163     HAPTICS_TRACE("createPwleMaxLevelLimitMap()");
164     int32_t capabilities;
165     Vibrator::getCapabilities(&capabilities);
166     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
167         std::map<float, float>::iterator itr0, itr1;
168 
169         if (discretePwleMaxLevels.empty()) {
170             return;
171         }
172         if (discretePwleMaxLevels.size() == 1) {
173             itr0 = discretePwleMaxLevels.begin();
174             float pwleMaxLevelLimitMapIdx =
175                     (itr0->first - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ;
176             pwleMaxLevelLimitMap[pwleMaxLevelLimitMapIdx] = itr0->second;
177             return;
178         }
179 
180         itr0 = discretePwleMaxLevels.begin();
181         itr1 = std::next(itr0, 1);
182 
183         while (itr1 != discretePwleMaxLevels.end()) {
184             float x0 = itr0->first;
185             float y0 = itr0->second;
186             float x1 = itr1->first;
187             float y1 = itr1->second;
188             float pwleMaxLevelLimitMapIdx =
189                     (itr0->first - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ;
190 
191             // FixLater: avoid floating point loop counters
192             // NOLINTBEGIN(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
193             for (float xp = x0; xp < (x1 + PWLE_FREQUENCY_RESOLUTION_HZ);
194                  xp += PWLE_FREQUENCY_RESOLUTION_HZ) {
195                 // NOLINTEND(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
196                 float yp = y0 + ((y1 - y0) / (x1 - x0)) * (xp - x0);
197 
198                 pwleMaxLevelLimitMap[pwleMaxLevelLimitMapIdx++] = yp;
199             }
200 
201             itr0++;
202             itr1++;
203         }
204     }
205 }
206 
207 enum class AlwaysOnId : uint32_t {
208     GPIO_RISE,
209     GPIO_FALL,
210 };
211 
Vibrator(std::unique_ptr<HwApi> hwapi,std::unique_ptr<HwCal> hwcal,std::unique_ptr<StatsApi> statsapi)212 Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal,
213                    std::unique_ptr<StatsApi> statsapi)
214     : mHwApi(std::move(hwapi)),
215       mHwCal(std::move(hwcal)),
216       mStatsApi(std::move(statsapi)),
217       mAsyncHandle(std::async([] {})) {
218     int32_t longFreqencyShift;
219     uint32_t calVer;
220     uint32_t caldata;
221     uint32_t effectCount;
222 
223     if (!mHwApi->setState(true)) {
224         mStatsApi->logError(kHwApiError);
225         ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
226     }
227 
228     if (mHwCal->getF0(&caldata)) {
229         mHwApi->setF0(caldata);
230         mResonantFrequency = static_cast<float>(caldata) / (1 << Q14_BIT_SHIFT);
231     } else {
232         mStatsApi->logError(kHwApiError);
233         ALOGE("Failed to get resonant frequency (%d): %s, using default resonant HZ: %f", errno,
234               strerror(errno), RESONANT_FREQUENCY_DEFAULT);
235         mResonantFrequency = RESONANT_FREQUENCY_DEFAULT;
236     }
237     if (mHwCal->getRedc(&caldata)) {
238         mHwApi->setRedc(caldata);
239         mRedc = caldata;
240     }
241     if (mHwCal->getQ(&caldata)) {
242         mHwApi->setQ(caldata);
243     }
244 
245     mHwCal->getLongFrequencyShift(&longFreqencyShift);
246     if (longFreqencyShift > 0) {
247         mF0Offset = longFreqencyShift * std::pow(2, 14);
248     } else if (longFreqencyShift < 0) {
249         mF0Offset = std::pow(2, 24) - std::abs(longFreqencyShift) * std::pow(2, 14);
250     } else {
251         mF0Offset = 0;
252     }
253 
254     mHwCal->getVersion(&calVer);
255     if (calVer == 1) {
256         std::array<uint32_t, 6> volLevels;
257         mHwCal->getVolLevels(&volLevels);
258         /*
259          * Given voltage levels for two intensities, assuming a linear function,
260          * solve for 'f(0)' in 'v = f(i) = a + b * i' (i.e 'v0 - (v1 - v0) / ((i1 - i0) / i0)').
261          */
262         mClickEffectVol[0] = std::max(std::lround(volLevels[WAVEFORM_EFFECT_0_20_LEVEL] -
263                                              (volLevels[WAVEFORM_EFFECT_1_00_LEVEL] -
264                                               volLevels[WAVEFORM_EFFECT_0_20_LEVEL]) /
265                                                      4.0f),
266                                  static_cast<long>(WAVEFORM_EFFECT_LEVEL_MINIMUM));
267         mClickEffectVol[1] = volLevels[WAVEFORM_EFFECT_1_00_LEVEL];
268         mTickEffectVol = mClickEffectVol;
269         mLongEffectVol[0] = 0;
270         mLongEffectVol[1] = volLevels[VOLTAGE_GLOBAL_SCALE_LEVEL];
271     } else {
272         mHwCal->getTickVolLevels(&mTickEffectVol);
273         mHwCal->getClickVolLevels(&mClickEffectVol);
274         mHwCal->getLongVolLevels(&mLongEffectVol);
275     }
276     HAPTICS_TRACE("Vibrator(hwapi, hwcal:%u)", calVer);
277 
278     mHwApi->getEffectCount(&effectCount);
279     mEffectDurations.resize(effectCount);
280     for (size_t effectIndex = 0; effectIndex < effectCount; effectIndex++) {
281         mHwApi->setEffectIndex(effectIndex);
282         uint32_t effectDuration;
283         if (mHwApi->getEffectDuration(&effectDuration)) {
284             mEffectDurations[effectIndex] = std::ceil(effectDuration / EFFECT_FREQUENCY_KHZ);
285         }
286     }
287 
288     mHwApi->setClabEnable(true);
289 
290     if (!(getPwleCompositionSizeMax(&mCompositionSizeMax).isOk())) {
291         mStatsApi->logError(kInitError);
292         ALOGE("Failed to get pwle composition size max, using default size: %d",
293               COMPOSE_PWLE_SIZE_LIMIT);
294         mCompositionSizeMax = COMPOSE_PWLE_SIZE_LIMIT;
295     }
296 
297     mIsChirpEnabled = mHwCal->isChirpEnabled();
298     createPwleMaxLevelLimitMap();
299     mGenerateBandwidthAmplitudeMapDone = false;
300     mBandwidthAmplitudeMap = generateBandwidthAmplitudeMap();
301     mIsUnderExternalControl = false;
302     setPwleRampDown();
303 }
304 
getCapabilities(int32_t * _aidl_return)305 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
306     HAPTICS_TRACE("getCapabilities(_aidl_return)");
307     ATRACE_NAME("Vibrator::getCapabilities");
308     int32_t ret = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
309                   IVibrator::CAP_COMPOSE_EFFECTS | IVibrator::CAP_ALWAYS_ON_CONTROL |
310                   IVibrator::CAP_GET_RESONANT_FREQUENCY | IVibrator::CAP_GET_Q_FACTOR;
311     if (mHwApi->hasEffectScale()) {
312         ret |= IVibrator::CAP_AMPLITUDE_CONTROL;
313     }
314     if (mHwApi->hasAspEnable() || hasHapticAlsaDevice()) {
315         ret |= IVibrator::CAP_EXTERNAL_CONTROL;
316     }
317     if (mHwApi->hasPwle() && mIsChirpEnabled) {
318         ret |= IVibrator::CAP_FREQUENCY_CONTROL | IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
319     }
320     *_aidl_return = ret;
321     return ndk::ScopedAStatus::ok();
322 }
323 
off()324 ndk::ScopedAStatus Vibrator::off() {
325     HAPTICS_TRACE("off()");
326     ATRACE_NAME("Vibrator::off");
327     ALOGD("off");
328     setGlobalAmplitude(false);
329     mHwApi->setF0Offset(0);
330     if (!mHwApi->setActivate(0)) {
331         mStatsApi->logError(kHwApiError);
332         ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
333         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
334     }
335     mActiveId = -1;
336     return ndk::ScopedAStatus::ok();
337 }
338 
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)339 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
340                                 const std::shared_ptr<IVibratorCallback> &callback) {
341     HAPTICS_TRACE("on(timeoutMs:%u, callback)", timeoutMs);
342     ATRACE_NAME("Vibrator::on");
343     ALOGD("on");
344     mStatsApi->logLatencyStart(kWaveformEffectLatency);
345     const uint32_t index = timeoutMs < WAVEFORM_LONG_VIBRATION_THRESHOLD_MS
346                                    ? WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX
347                                    : WAVEFORM_LONG_VIBRATION_EFFECT_INDEX;
348     mStatsApi->logWaveform(index, timeoutMs);
349     if (MAX_COLD_START_LATENCY_MS <= UINT32_MAX - timeoutMs) {
350         timeoutMs += MAX_COLD_START_LATENCY_MS;
351     }
352     setGlobalAmplitude(true);
353     mHwApi->setF0Offset(mF0Offset);
354     return on(timeoutMs, index, callback);
355 }
356 
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)357 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
358                                      const std::shared_ptr<IVibratorCallback> &callback,
359                                      int32_t *_aidl_return) {
360     HAPTICS_TRACE("perform(effect:%s, strength:%s, callback, _aidl_return)",
361                   toString(effect).c_str(), toString(strength).c_str());
362     ATRACE_NAME("Vibrator::perform");
363     ALOGD("perform");
364 
365     mStatsApi->logLatencyStart(kPrebakedEffectLatency);
366 
367     return performEffect(effect, strength, callback, _aidl_return);
368 }
369 
getSupportedEffects(std::vector<Effect> * _aidl_return)370 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
371     HAPTICS_TRACE("getSupportedEffects(_aidl_return)");
372     *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
373                      Effect::DOUBLE_CLICK};
374     return ndk::ScopedAStatus::ok();
375 }
376 
setAmplitude(float amplitude)377 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
378     HAPTICS_TRACE("setAmplitude(amplitude:%f)", amplitude);
379     ATRACE_NAME("Vibrator::setAmplitude");
380     if (amplitude <= 0.0f || amplitude > 1.0f) {
381         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
382     }
383 
384     if (!isUnderExternalControl()) {
385         return setEffectAmplitude(amplitude, 1.0);
386     } else {
387         mStatsApi->logError(kUnsupportedOpError);
388         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
389     }
390 }
391 
setExternalControl(bool enabled)392 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
393     HAPTICS_TRACE("setExternalControl(enabled:%u)", enabled);
394     ATRACE_NAME("Vibrator::setExternalControl");
395     setGlobalAmplitude(enabled);
396 
397     if (isUnderExternalControl() == enabled) {
398         if (enabled) {
399             ALOGE("Restart the external process.");
400             if (mHasHapticAlsaDevice) {
401                 if (!enableHapticPcmAmp(&mHapticPcm, !enabled, mCard, mDevice)) {
402                     mStatsApi->logError(kAlsaFailError);
403                     ALOGE("Failed to %s haptic pcm device: %d", (enabled ? "enable" : "disable"),
404                           mDevice);
405                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
406                 }
407             }
408             if (mHwApi->hasAspEnable()) {
409                 if (!mHwApi->setAspEnable(!enabled)) {
410                     mStatsApi->logError(kHwApiError);
411                     ALOGE("Failed to set external control (%d): %s", errno, strerror(errno));
412                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
413                 }
414             }
415         } else {
416             ALOGE("The external control is already disabled.");
417             return ndk::ScopedAStatus::ok();
418         }
419     }
420     if (mHasHapticAlsaDevice) {
421         if (!enableHapticPcmAmp(&mHapticPcm, enabled, mCard, mDevice)) {
422             mStatsApi->logError(kAlsaFailError);
423             ALOGE("Failed to %s haptic pcm device: %d", (enabled ? "enable" : "disable"), mDevice);
424             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
425         }
426     }
427     if (mHwApi->hasAspEnable()) {
428         if (!mHwApi->setAspEnable(enabled)) {
429             mStatsApi->logError(kHwApiError);
430             ALOGE("Failed to set external control (%d): %s", errno, strerror(errno));
431             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
432         }
433     }
434 
435     mIsUnderExternalControl = enabled;
436     return ndk::ScopedAStatus::ok();
437 }
438 
getCompositionDelayMax(int32_t * maxDelayMs)439 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t *maxDelayMs) {
440     HAPTICS_TRACE("getCompositionDelayMax(maxDelayMs)");
441     ATRACE_NAME("Vibrator::getCompositionDelayMax");
442     *maxDelayMs = COMPOSE_DELAY_MAX_MS;
443     return ndk::ScopedAStatus::ok();
444 }
445 
getCompositionSizeMax(int32_t * maxSize)446 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t *maxSize) {
447     HAPTICS_TRACE("getCompositionSizeMax(maxSize)");
448     ATRACE_NAME("Vibrator::getCompositionSizeMax");
449     *maxSize = COMPOSE_SIZE_MAX;
450     return ndk::ScopedAStatus::ok();
451 }
452 
getSupportedPrimitives(std::vector<CompositePrimitive> * supported)453 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive> *supported) {
454     HAPTICS_TRACE("getSupportedPrimitives(supported)");
455     *supported = {
456             CompositePrimitive::NOOP,       CompositePrimitive::CLICK,
457             CompositePrimitive::THUD,       CompositePrimitive::SPIN,
458             CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
459             CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
460             CompositePrimitive::LOW_TICK,
461     };
462     return ndk::ScopedAStatus::ok();
463 }
464 
getPrimitiveDuration(CompositePrimitive primitive,int32_t * durationMs)465 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
466                                                   int32_t *durationMs) {
467     HAPTICS_TRACE("getPrimitiveDuration(primitive:%s, durationMs)", toString(primitive).c_str());
468     ndk::ScopedAStatus status;
469     uint32_t effectIndex;
470 
471     if (primitive != CompositePrimitive::NOOP) {
472         status = getPrimitiveDetails(primitive, &effectIndex);
473         if (!status.isOk()) {
474             return status;
475         }
476 
477         *durationMs = mEffectDurations[effectIndex];
478     } else {
479         *durationMs = 0;
480     }
481 
482     return ndk::ScopedAStatus::ok();
483 }
484 
compose(const std::vector<CompositeEffect> & composite,const std::shared_ptr<IVibratorCallback> & callback)485 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composite,
486                                      const std::shared_ptr<IVibratorCallback> &callback) {
487     HAPTICS_TRACE("compose(composite, callback)");
488     ATRACE_NAME("Vibrator::compose");
489     ALOGD("compose");
490     std::ostringstream effectBuilder;
491     std::string effectQueue;
492 
493     mStatsApi->logLatencyStart(kCompositionEffectLatency);
494 
495     if (composite.size() > COMPOSE_SIZE_MAX) {
496         mStatsApi->logError(kBadCompositeError);
497         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
498     }
499     const std::scoped_lock<std::mutex> lock(mTotalDurationMutex);
500 
501     // Reset the mTotalDuration
502     mTotalDuration = 0;
503     for (auto &e : composite) {
504         if (e.scale < 0.0f || e.scale > 1.0f) {
505             mStatsApi->logError(kBadCompositeError);
506             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
507         }
508 
509         if (e.delayMs) {
510             if (e.delayMs > COMPOSE_DELAY_MAX_MS) {
511                 mStatsApi->logError(kBadCompositeError);
512                 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
513             }
514             effectBuilder << e.delayMs << ",";
515             mTotalDuration += e.delayMs;
516         }
517         if (e.primitive != CompositePrimitive::NOOP) {
518             ndk::ScopedAStatus status;
519             uint32_t effectIndex;
520 
521             status = getPrimitiveDetails(e.primitive, &effectIndex);
522             mStatsApi->logPrimitive(effectIndex);
523             if (!status.isOk()) {
524                 mStatsApi->logError(kBadCompositeError);
525                 return status;
526             }
527 
528             effectBuilder << effectIndex << "." << intensityToVolLevel(e.scale, effectIndex) << ",";
529             mTotalDuration += mEffectDurations[effectIndex];
530         }
531     }
532 
533     if (effectBuilder.tellp() == 0) {
534         mStatsApi->logError(kComposeFailError);
535         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
536     }
537 
538     effectBuilder << 0;
539 
540     effectQueue = effectBuilder.str();
541 
542     return performEffect(0 /*ignored*/, 0 /*ignored*/, &effectQueue, callback);
543 }
544 
on(uint32_t timeoutMs,uint32_t effectIndex,const std::shared_ptr<IVibratorCallback> & callback)545 ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex,
546                                 const std::shared_ptr<IVibratorCallback> &callback) {
547     HAPTICS_TRACE("on(timeoutMs:%u, effectIndex:%u, callback)", timeoutMs, effectIndex);
548     if (isUnderExternalControl()) {
549         setExternalControl(false);
550         ALOGE("Device is under external control mode. Force to disable it to prevent chip hang "
551               "problem.");
552     }
553     if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) {
554         mStatsApi->logError(kAsyncFailError);
555         ALOGE("Previous vibration pending: prev: %d, curr: %d", mActiveId, effectIndex);
556         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
557     }
558 
559     ALOGD("on");
560     mHwApi->setEffectIndex(effectIndex);
561     mHwApi->setDuration(timeoutMs);
562     mStatsApi->logLatencyEnd();
563     mHwApi->setActivate(1);
564     // Using the mToalDuration for composed effect.
565     // For composed effect, we set the UINT32_MAX to the duration sysfs node,
566     // but it not a practical way to use it to monitor the total duration time.
567     if (timeoutMs != UINT32_MAX) {
568         const std::scoped_lock<std::mutex> lock(mTotalDurationMutex);
569         mTotalDuration = timeoutMs;
570     }
571 
572     mActiveId = effectIndex;
573 
574     mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
575 
576     return ndk::ScopedAStatus::ok();
577 }
578 
setEffectAmplitude(float amplitude,float maximum)579 ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) {
580     HAPTICS_TRACE("setEffectAmplitude(amplitude:%f, maximum:%f)", amplitude, maximum);
581     int32_t scale = amplitudeToScale(amplitude, maximum);
582 
583     if (!mHwApi->setEffectScale(scale)) {
584         mStatsApi->logError(kHwApiError);
585         ALOGE("Failed to set effect amplitude (%d): %s", errno, strerror(errno));
586         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
587     }
588 
589     return ndk::ScopedAStatus::ok();
590 }
591 
setGlobalAmplitude(bool set)592 ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) {
593     HAPTICS_TRACE("setGlobalAmplitude(set:%u)", set);
594     uint8_t amplitude = set ? mLongEffectVol[1] : VOLTAGE_SCALE_MAX;
595     int32_t scale = amplitudeToScale(amplitude, VOLTAGE_SCALE_MAX);
596 
597     if (!mHwApi->setGlobalScale(scale)) {
598         mStatsApi->logError(kHwApiError);
599         ALOGE("Failed to set global amplitude (%d): %s", errno, strerror(errno));
600         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
601     }
602 
603     return ndk::ScopedAStatus::ok();
604 }
605 
getSupportedAlwaysOnEffects(std::vector<Effect> * _aidl_return)606 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> *_aidl_return) {
607     HAPTICS_TRACE("getSupportedAlwaysOnEffects(_aidl_return)");
608     *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK};
609     return ndk::ScopedAStatus::ok();
610 }
611 
alwaysOnEnable(int32_t id,Effect effect,EffectStrength strength)612 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
613     HAPTICS_TRACE("alwaysOnEnable(id:%d, effect:%s, strength:%s)", id, toString(effect).c_str(),
614                   toString(strength).c_str());
615     ndk::ScopedAStatus status;
616     uint32_t effectIndex;
617     uint32_t timeMs;
618     uint32_t volLevel;
619     uint32_t scale;
620 
621     status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
622     if (!status.isOk()) {
623         return status;
624     }
625 
626     scale = amplitudeToScale(volLevel, VOLTAGE_SCALE_MAX);
627 
628     switch (static_cast<AlwaysOnId>(id)) {
629         case AlwaysOnId::GPIO_RISE:
630             mHwApi->setGpioRiseIndex(effectIndex);
631             mHwApi->setGpioRiseScale(scale);
632             return ndk::ScopedAStatus::ok();
633         case AlwaysOnId::GPIO_FALL:
634             mHwApi->setGpioFallIndex(effectIndex);
635             mHwApi->setGpioFallScale(scale);
636             return ndk::ScopedAStatus::ok();
637     }
638 
639     mStatsApi->logError(kUnsupportedOpError);
640     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
641 }
642 
alwaysOnDisable(int32_t id)643 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
644     HAPTICS_TRACE("alwaysOnDisable(id: %d)", id);
645     switch (static_cast<AlwaysOnId>(id)) {
646         case AlwaysOnId::GPIO_RISE:
647             mHwApi->setGpioRiseIndex(0);
648             return ndk::ScopedAStatus::ok();
649         case AlwaysOnId::GPIO_FALL:
650             mHwApi->setGpioFallIndex(0);
651             return ndk::ScopedAStatus::ok();
652     }
653 
654     mStatsApi->logError(kUnsupportedOpError);
655     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
656 }
657 
getResonantFrequency(float * resonantFreqHz)658 ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
659     HAPTICS_TRACE("getResonantFrequency(resonantFreqHz)");
660     *resonantFreqHz = mResonantFrequency;
661 
662     return ndk::ScopedAStatus::ok();
663 }
664 
getQFactor(float * qFactor)665 ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
666     HAPTICS_TRACE("getQFactor(qFactor)");
667     uint32_t caldata;
668     if (!mHwCal->getQ(&caldata)) {
669         mStatsApi->logError(kHwCalError);
670         ALOGE("Failed to get q factor (%d): %s", errno, strerror(errno));
671         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
672     }
673     *qFactor = static_cast<float>(caldata) / (1 << Q16_BIT_SHIFT);
674 
675     return ndk::ScopedAStatus::ok();
676 }
677 
getFrequencyResolution(float * freqResolutionHz)678 ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
679     HAPTICS_TRACE("getFrequencyResolution(freqResolutionHz)");
680     int32_t capabilities;
681     Vibrator::getCapabilities(&capabilities);
682     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
683         *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
684         return ndk::ScopedAStatus::ok();
685     } else {
686         mStatsApi->logError(kUnsupportedOpError);
687         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
688     }
689 }
690 
getFrequencyMinimum(float * freqMinimumHz)691 ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
692     HAPTICS_TRACE("getFrequencyMinimum(freqMinimumHz)");
693     int32_t capabilities;
694     Vibrator::getCapabilities(&capabilities);
695     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
696         *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
697         return ndk::ScopedAStatus::ok();
698     } else {
699         mStatsApi->logError(kUnsupportedOpError);
700         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
701     }
702 }
703 
redcToFloat(uint32_t redcMeasured)704 static float redcToFloat(uint32_t redcMeasured) {
705     HAPTICS_TRACE("redcToFloat(redcMeasured: %u)", redcMeasured);
706     return redcMeasured * 5.857 / (1 << Q17_BIT_SHIFT);
707 }
708 
generateBandwidthAmplitudeMap()709 std::vector<float> Vibrator::generateBandwidthAmplitudeMap() {
710     HAPTICS_TRACE("generateBandwidthAmplitudeMap()");
711     // Use constant Q Factor of 10 from HW's suggestion
712     const float qFactor = 10.0f;
713     const float blSys = 1.1f;
714     const float gravity = 9.81f;
715     const float maxVoltage = 12.3f;
716     float deviceMass = 0, locCoeff = 0;
717 
718     mHwCal->getDeviceMass(&deviceMass);
719     mHwCal->getLocCoeff(&locCoeff);
720     if (!deviceMass || !locCoeff) {
721         mStatsApi->logError(kInitError);
722         ALOGE("Failed to get Device Mass: %f and Loc Coeff: %f", deviceMass, locCoeff);
723         return std::vector<float>();
724     }
725 
726     // Resistance value need to be retrieved from calibration file
727     if (!mRedc) {
728         mStatsApi->logError(kInitError);
729         ALOGE("Failed to get redc");
730         return std::vector<float>();
731     }
732     const float rSys = redcToFloat(mRedc);
733 
734     std::vector<float> bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, 1.0);
735 
736     const float wnSys = mResonantFrequency * 2 * M_PI;
737 
738     float frequencyHz = PWLE_FREQUENCY_MIN_HZ;
739     float frequencyRadians = 0.0f;
740     float vLevel = 0.4f;
741     float vSys = (mLongEffectVol[1] / 100.0) * maxVoltage * vLevel;
742     float maxAsys = 0;
743 
744     for (int i = 0; i < PWLE_BW_MAP_SIZE; i++) {
745         frequencyRadians = frequencyHz * 2 * M_PI;
746         vLevel = pwleMaxLevelLimitMap[i];
747         vSys = (mLongEffectVol[1] / 100.0) * maxVoltage * vLevel;
748 
749         float var1 = pow((pow(wnSys, 2) - pow(frequencyRadians, 2)), 2);
750         float var2 = pow((wnSys * frequencyRadians / qFactor), 2);
751 
752         float psysAbs = sqrt(var1 + var2);
753         // The equation and all related details: b/170919640#comment5
754         float amplitudeSys = (vSys * blSys * locCoeff / rSys / deviceMass) *
755                              pow(frequencyRadians, 2) / psysAbs / gravity;
756         // Record the maximum acceleration for the next for loop
757         if (amplitudeSys > maxAsys)
758             maxAsys = amplitudeSys;
759 
760         bandwidthAmplitudeMap[i] = amplitudeSys;
761         frequencyHz += PWLE_FREQUENCY_RESOLUTION_HZ;
762     }
763     // Scaled the map between 0.00 and 1.00
764     if (maxAsys > 0) {
765         for (int j = 0; j < PWLE_BW_MAP_SIZE; j++) {
766             bandwidthAmplitudeMap[j] = std::floor((bandwidthAmplitudeMap[j] / maxAsys) * 100) / 100;
767         }
768         mGenerateBandwidthAmplitudeMapDone = true;
769     } else {
770         return std::vector<float>();
771     }
772 
773     return bandwidthAmplitudeMap;
774 }
775 
getBandwidthAmplitudeMap(std::vector<float> * _aidl_return)776 ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
777     HAPTICS_TRACE("getBandwidthAmplitudeMap(_aidl_return)");
778     int32_t capabilities;
779     Vibrator::getCapabilities(&capabilities);
780     if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
781         if (!mGenerateBandwidthAmplitudeMapDone) {
782             mBandwidthAmplitudeMap = generateBandwidthAmplitudeMap();
783         }
784         *_aidl_return = mBandwidthAmplitudeMap;
785         return (!mBandwidthAmplitudeMap.empty())
786                        ? ndk::ScopedAStatus::ok()
787                        : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
788     } else {
789         mStatsApi->logError(kUnsupportedOpError);
790         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
791     }
792 }
793 
getPwlePrimitiveDurationMax(int32_t * durationMs)794 ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
795     HAPTICS_TRACE("getPwlePrimitiveDurationMax(durationMs)");
796     int32_t capabilities;
797     Vibrator::getCapabilities(&capabilities);
798     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
799         *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
800         return ndk::ScopedAStatus::ok();
801     } else {
802         mStatsApi->logError(kUnsupportedOpError);
803         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
804     }
805 }
806 
getPwleCompositionSizeMax(int32_t * maxSize)807 ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
808     HAPTICS_TRACE("getPwleCompositionSizeMax(maxSize)");
809     int32_t capabilities;
810     Vibrator::getCapabilities(&capabilities);
811     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
812         uint32_t segments;
813         if (!mHwApi->getAvailablePwleSegments(&segments)) {
814             mStatsApi->logError(kHwApiError);
815             ALOGE("Failed to get availablePwleSegments (%d): %s", errno, strerror(errno));
816             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
817         }
818         *maxSize = (segments > COMPOSE_PWLE_SIZE_LIMIT) ? COMPOSE_PWLE_SIZE_LIMIT : segments;
819         mCompositionSizeMax = *maxSize;
820         return ndk::ScopedAStatus::ok();
821     } else {
822         mStatsApi->logError(kUnsupportedOpError);
823         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
824     }
825 }
826 
getSupportedBraking(std::vector<Braking> * supported)827 ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
828     HAPTICS_TRACE("getSupportedBraking(supported)");
829     int32_t capabilities;
830     Vibrator::getCapabilities(&capabilities);
831     if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
832         *supported = {
833             Braking::NONE,
834             Braking::CLAB,
835         };
836         return ndk::ScopedAStatus::ok();
837     } else {
838         mStatsApi->logError(kUnsupportedOpError);
839         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
840     }
841 }
842 
setPwle(const std::string & pwleQueue)843 ndk::ScopedAStatus Vibrator::setPwle(const std::string &pwleQueue) {
844     HAPTICS_TRACE("setPwle(pwleQueue:%s)", pwleQueue.c_str());
845     if (!mHwApi->setPwle(pwleQueue)) {
846         mStatsApi->logError(kHwApiError);
847         ALOGE("Failed to write \"%s\" to pwle (%d): %s", pwleQueue.c_str(), errno, strerror(errno));
848         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
849     }
850 
851     return ndk::ScopedAStatus::ok();
852 }
853 
incrementIndex(int * index)854 static void incrementIndex(int *index) {
855     *index += 1;
856 }
857 
constructActiveDefaults(std::ostringstream & pwleBuilder,const int & segmentIdx)858 static void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
859     HAPTICS_TRACE("constructActiveDefaults(pwleBuilder, segmentIdx:%d)", segmentIdx);
860     pwleBuilder << ",C" << segmentIdx << ":1";
861     pwleBuilder << ",B" << segmentIdx << ":0";
862     pwleBuilder << ",AR" << segmentIdx << ":0";
863     pwleBuilder << ",V" << segmentIdx << ":0";
864 }
865 
constructActiveSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,float amplitude,float frequency)866 static void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx,
867                                    int duration, float amplitude, float frequency) {
868     HAPTICS_TRACE(
869             "constructActiveSegment(pwleBuilder, segmentIdx:%d, duration:%d, amplitude:%f, "
870             "frequency:%f)",
871             segmentIdx, duration, amplitude, frequency);
872     pwleBuilder << ",T" << segmentIdx << ":" << duration;
873     pwleBuilder << ",L" << segmentIdx << ":" << std::setprecision(1) << amplitude;
874     pwleBuilder << ",F" << segmentIdx << ":" << std::lroundf(frequency);
875     constructActiveDefaults(pwleBuilder, segmentIdx);
876 }
877 
constructBrakingSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,Braking brakingType,float frequency)878 static void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx,
879                                     int duration, Braking brakingType, float frequency) {
880     HAPTICS_TRACE(
881             "constructActiveSegment(pwleBuilder, segmentIdx:%d, duration:%d, brakingType:%s, "
882             "frequency:%f)",
883             segmentIdx, duration, toString(brakingType).c_str(), frequency);
884     pwleBuilder << ",T" << segmentIdx << ":" << duration;
885     pwleBuilder << ",L" << segmentIdx << ":" << 0;
886     pwleBuilder << ",F" << segmentIdx << ":" << std::lroundf(frequency);
887     pwleBuilder << ",C" << segmentIdx << ":0";
888     pwleBuilder << ",B" << segmentIdx << ":"
889                 << static_cast<std::underlying_type<Braking>::type>(brakingType);
890     pwleBuilder << ",AR" << segmentIdx << ":0";
891     pwleBuilder << ",V" << segmentIdx << ":0";
892 }
893 
composePwle(const std::vector<PrimitivePwle> & composite,const std::shared_ptr<IVibratorCallback> & callback)894 ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
895                                          const std::shared_ptr<IVibratorCallback> &callback) {
896     HAPTICS_TRACE("composePwle(composite, callback)");
897     ATRACE_NAME("Vibrator::composePwle");
898     std::ostringstream pwleBuilder;
899     std::string pwleQueue;
900 
901     mStatsApi->logLatencyStart(kPwleEffectLatency);
902 
903     if (!mIsChirpEnabled) {
904         mStatsApi->logError(kUnsupportedOpError);
905         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
906     }
907 
908     if (composite.size() <= 0 || composite.size() > mCompositionSizeMax) {
909         mStatsApi->logError(kBadCompositeError);
910         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
911     }
912 
913     float prevEndAmplitude = 0;
914     float prevEndFrequency = mResonantFrequency;
915 
916     int segmentIdx = 0;
917     uint32_t totalDuration = 0;
918 
919     pwleBuilder << "S:0,WF:4,RP:0,WT:0";
920 
921     for (auto &e : composite) {
922         switch (e.getTag()) {
923             case PrimitivePwle::active: {
924                 auto active = e.get<PrimitivePwle::active>();
925                 if (active.duration < 0 ||
926                     active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
927                     mStatsApi->logError(kBadCompositeError);
928                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
929                 }
930                 if (active.startAmplitude < PWLE_LEVEL_MIN ||
931                     active.startAmplitude > PWLE_LEVEL_MAX ||
932                     active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
933                     mStatsApi->logError(kBadCompositeError);
934                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
935                 }
936                 if (active.startAmplitude > CS40L2X_PWLE_LEVEL_MAX) {
937                     active.startAmplitude = CS40L2X_PWLE_LEVEL_MAX;
938                 }
939                 if (active.endAmplitude > CS40L2X_PWLE_LEVEL_MAX) {
940                     active.endAmplitude = CS40L2X_PWLE_LEVEL_MAX;
941                 }
942 
943                 if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
944                     active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
945                     active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
946                     active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
947                     mStatsApi->logError(kBadCompositeError);
948                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
949                 }
950 
951                 // clip to the hard limit on input level from pwleMaxLevelLimitMap
952                 float maxLevelLimit =
953                     pwleMaxLevelLimitMap[active.startFrequency / PWLE_FREQUENCY_RESOLUTION_HZ - 1];
954                 if (active.startAmplitude > maxLevelLimit) {
955                     active.startAmplitude = maxLevelLimit;
956                 }
957                 maxLevelLimit =
958                     pwleMaxLevelLimitMap[active.endFrequency / PWLE_FREQUENCY_RESOLUTION_HZ - 1];
959                 if (active.endAmplitude > maxLevelLimit) {
960                     active.endAmplitude = maxLevelLimit;
961                 }
962 
963                 if (!((active.startAmplitude == prevEndAmplitude) &&
964                       (active.startFrequency == prevEndFrequency))) {
965                     constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
966                                            active.startFrequency);
967                     incrementIndex(&segmentIdx);
968                 }
969 
970                 constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
971                                        active.endAmplitude, active.endFrequency);
972                 incrementIndex(&segmentIdx);
973 
974                 prevEndAmplitude = active.endAmplitude;
975                 prevEndFrequency = active.endFrequency;
976                 totalDuration += active.duration;
977                 break;
978             }
979             case PrimitivePwle::braking: {
980                 auto braking = e.get<PrimitivePwle::braking>();
981                 if (braking.braking > Braking::CLAB) {
982                     mStatsApi->logError(kBadPrimitiveError);
983                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
984                 }
985                 if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
986                     mStatsApi->logError(kBadPrimitiveError);
987                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
988                 }
989 
990                 constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking,
991                                         prevEndFrequency);
992                 incrementIndex(&segmentIdx);
993 
994                 prevEndAmplitude = 0;
995                 totalDuration += braking.duration;
996                 break;
997             }
998         }
999     }
1000 
1001     pwleQueue = pwleBuilder.str();
1002     ALOGD("composePwle queue: (%s)", pwleQueue.c_str());
1003 
1004     if (pwleQueue.size() > CS40L2X_PWLE_LENGTH_MAX) {
1005         ALOGE("PWLE string too large(%u)", static_cast<uint32_t>(pwleQueue.size()));
1006         mStatsApi->logError(kPwleConstructionFailError);
1007         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
1008     } else {
1009         ALOGD("PWLE string : %u", static_cast<uint32_t>(pwleQueue.size()));
1010         ndk::ScopedAStatus status = setPwle(pwleQueue);
1011         if (!status.isOk()) {
1012             mStatsApi->logError(kPwleConstructionFailError);
1013             ALOGE("Failed to write pwle queue");
1014             return status;
1015         }
1016     }
1017     setEffectAmplitude(VOLTAGE_SCALE_MAX, VOLTAGE_SCALE_MAX);
1018     mHwApi->setEffectIndex(WAVEFORM_UNSAVED_TRIGGER_QUEUE_INDEX);
1019 
1020     totalDuration += MAX_COLD_START_LATENCY_MS;
1021     mHwApi->setDuration(totalDuration);
1022     {
1023         const std::scoped_lock<std::mutex> lock(mTotalDurationMutex);
1024         mTotalDuration = totalDuration;
1025     }
1026 
1027     mStatsApi->logLatencyEnd();
1028     mHwApi->setActivate(1);
1029 
1030     mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback);
1031 
1032     return ndk::ScopedAStatus::ok();
1033 }
1034 
isUnderExternalControl()1035 bool Vibrator::isUnderExternalControl() {
1036     HAPTICS_TRACE("isUnderExternalControl()");
1037     return mIsUnderExternalControl;
1038 }
1039 
dump(int fd,const char ** args,uint32_t numArgs)1040 binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
1041     HAPTICS_TRACE("dump(fd:%d, args, numArgs:%u)", fd, numArgs);
1042     if (fd < 0) {
1043         ALOGE("Called debug() with invalid fd.");
1044         return STATUS_OK;
1045     }
1046 
1047     (void)args;
1048     (void)numArgs;
1049 
1050     dprintf(fd, "AIDL:\n");
1051 
1052     dprintf(fd, "  F0 Offset: %" PRIu32 "\n", mF0Offset);
1053 
1054     dprintf(fd, "  Voltage Levels:\n");
1055     dprintf(fd, "    Tick Effect Min: %" PRIu32 " Max: %" PRIu32 "\n",
1056             mTickEffectVol[0], mTickEffectVol[1]);
1057     dprintf(fd, "    Click Effect Min: %" PRIu32 " Max: %" PRIu32 "\n",
1058             mClickEffectVol[0], mClickEffectVol[1]);
1059     dprintf(fd, "    Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n",
1060             mLongEffectVol[0], mLongEffectVol[1]);
1061 
1062     dprintf(fd, "  Effect Durations:");
1063     for (auto d : mEffectDurations) {
1064         dprintf(fd, " %" PRIu32, d);
1065     }
1066     dprintf(fd, "\n");
1067 
1068     dprintf(fd, "\n");
1069 
1070     mHwApi->debug(fd);
1071 
1072     dprintf(fd, "\n");
1073 
1074     mHwCal->debug(fd);
1075 
1076     dprintf(fd, "\n");
1077 
1078     mStatsApi->debug(fd);
1079 
1080     fsync(fd);
1081     return STATUS_OK;
1082 }
1083 
getSimpleDetails(Effect effect,EffectStrength strength,uint32_t * outEffectIndex,uint32_t * outTimeMs,uint32_t * outVolLevel)1084 ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
1085                                               uint32_t *outEffectIndex, uint32_t *outTimeMs,
1086                                               uint32_t *outVolLevel) {
1087     HAPTICS_TRACE(
1088             "getSimpleDetails(effect:%s, strength:%s, outEffectIndex, outTimeMs"
1089             ", outVolLevel)",
1090             toString(effect).c_str(), toString(strength).c_str());
1091     uint32_t effectIndex;
1092     uint32_t timeMs;
1093     float intensity;
1094     uint32_t volLevel;
1095 
1096     switch (strength) {
1097         case EffectStrength::LIGHT:
1098             intensity = 0.5f;
1099             break;
1100         case EffectStrength::MEDIUM:
1101             intensity = 0.7f;
1102             break;
1103         case EffectStrength::STRONG:
1104             intensity = 1.0f;
1105             break;
1106         default:
1107             mStatsApi->logError(kUnsupportedOpError);
1108             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1109     }
1110 
1111     switch (effect) {
1112         case Effect::TEXTURE_TICK:
1113             effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
1114             intensity *= 0.5f;
1115             break;
1116         case Effect::TICK:
1117             effectIndex = WAVEFORM_CLICK_INDEX;
1118             intensity *= 0.5f;
1119             break;
1120         case Effect::CLICK:
1121             effectIndex = WAVEFORM_CLICK_INDEX;
1122             intensity *= 0.7f;
1123             break;
1124         case Effect::HEAVY_CLICK:
1125             effectIndex = WAVEFORM_CLICK_INDEX;
1126             intensity *= 1.0f;
1127             break;
1128         default:
1129             mStatsApi->logError(kUnsupportedOpError);
1130             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1131     }
1132 
1133     volLevel = intensityToVolLevel(intensity, effectIndex);
1134     timeMs = mEffectDurations[effectIndex] + MAX_COLD_START_LATENCY_MS;
1135     {
1136         const std::scoped_lock<std::mutex> lock(mTotalDurationMutex);
1137         mTotalDuration = timeMs;
1138     }
1139 
1140     *outEffectIndex = effectIndex;
1141     *outTimeMs = timeMs;
1142     *outVolLevel = volLevel;
1143 
1144     return ndk::ScopedAStatus::ok();
1145 }
1146 
getCompoundDetails(Effect effect,EffectStrength strength,uint32_t * outTimeMs,uint32_t *,std::string * outEffectQueue)1147 ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
1148                                                 uint32_t *outTimeMs, uint32_t * /*outVolLevel*/,
1149                                                 std::string *outEffectQueue) {
1150     HAPTICS_TRACE(
1151             "getCompoundDetails(effect:%s, strength:%s, outTimeMs, outVolLevel, outEffectQueue)",
1152             toString(effect).c_str(), toString(strength).c_str());
1153     ndk::ScopedAStatus status;
1154     uint32_t timeMs;
1155     std::ostringstream effectBuilder;
1156     uint32_t thisEffectIndex;
1157     uint32_t thisTimeMs;
1158     uint32_t thisVolLevel;
1159 
1160     switch (effect) {
1161         case Effect::DOUBLE_CLICK:
1162             timeMs = 0;
1163 
1164             status = getSimpleDetails(Effect::CLICK, strength, &thisEffectIndex, &thisTimeMs,
1165                                       &thisVolLevel);
1166             if (!status.isOk()) {
1167                 return status;
1168             }
1169             effectBuilder << thisEffectIndex << "." << thisVolLevel;
1170             timeMs += thisTimeMs;
1171 
1172             effectBuilder << ",";
1173 
1174             effectBuilder << WAVEFORM_DOUBLE_CLICK_SILENCE_MS;
1175             timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
1176 
1177             effectBuilder << ",";
1178 
1179             status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisEffectIndex, &thisTimeMs,
1180                                       &thisVolLevel);
1181             if (!status.isOk()) {
1182                 return status;
1183             }
1184             effectBuilder << thisEffectIndex << "." << thisVolLevel;
1185             timeMs += thisTimeMs;
1186             {
1187                 const std::scoped_lock<std::mutex> lock(mTotalDurationMutex);
1188                 mTotalDuration = timeMs;
1189             }
1190 
1191             break;
1192         default:
1193             mStatsApi->logError(kUnsupportedOpError);
1194             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1195     }
1196 
1197     *outTimeMs = timeMs;
1198     *outEffectQueue = effectBuilder.str();
1199 
1200     return ndk::ScopedAStatus::ok();
1201 }
1202 
getPrimitiveDetails(CompositePrimitive primitive,uint32_t * outEffectIndex)1203 ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive,
1204                                                  uint32_t *outEffectIndex) {
1205     HAPTICS_TRACE("getPrimitiveDetails(primitive:%s, outEffectIndex)", toString(primitive).c_str());
1206     uint32_t effectIndex;
1207 
1208     switch (primitive) {
1209         case CompositePrimitive::NOOP:
1210             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1211         case CompositePrimitive::CLICK:
1212             effectIndex = WAVEFORM_CLICK_INDEX;
1213             break;
1214         case CompositePrimitive::THUD:
1215             effectIndex = WAVEFORM_THUD_INDEX;
1216             break;
1217         case CompositePrimitive::SPIN:
1218             effectIndex = WAVEFORM_SPIN_INDEX;
1219             break;
1220         case CompositePrimitive::QUICK_RISE:
1221             effectIndex = WAVEFORM_QUICK_RISE_INDEX;
1222             break;
1223         case CompositePrimitive::SLOW_RISE:
1224             effectIndex = WAVEFORM_SLOW_RISE_INDEX;
1225             break;
1226         case CompositePrimitive::QUICK_FALL:
1227             effectIndex = WAVEFORM_QUICK_FALL_INDEX;
1228             break;
1229         case CompositePrimitive::LIGHT_TICK:
1230             effectIndex = WAVEFORM_LIGHT_TICK_INDEX;
1231             break;
1232         case CompositePrimitive::LOW_TICK:
1233             effectIndex = WAVEFORM_LOW_TICK_INDEX;
1234             break;
1235         default:
1236             mStatsApi->logError(kUnsupportedOpError);
1237             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1238     }
1239 
1240     *outEffectIndex = effectIndex;
1241 
1242     return ndk::ScopedAStatus::ok();
1243 }
1244 
setEffectQueue(const std::string & effectQueue)1245 ndk::ScopedAStatus Vibrator::setEffectQueue(const std::string &effectQueue) {
1246     HAPTICS_TRACE("setEffectQueue(effectQueue:%s)", effectQueue.c_str());
1247     if (!mHwApi->setEffectQueue(effectQueue)) {
1248         ALOGE("Failed to write \"%s\" to effect queue (%d): %s", effectQueue.c_str(), errno,
1249               strerror(errno));
1250         mStatsApi->logError(kHwApiError);
1251         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
1252     }
1253 
1254     return ndk::ScopedAStatus::ok();
1255 }
1256 
performEffect(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * outTimeMs)1257 ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
1258                                            const std::shared_ptr<IVibratorCallback> &callback,
1259                                            int32_t *outTimeMs) {
1260     HAPTICS_TRACE("performEffect(effect:%s, strength:%s, callback, outTimeMs)",
1261                   toString(effect).c_str(), toString(strength).c_str());
1262     ndk::ScopedAStatus status;
1263     uint32_t effectIndex;
1264     uint32_t timeMs = 0;
1265     uint32_t volLevel;
1266     std::string effectQueue;
1267 
1268     switch (effect) {
1269         case Effect::TEXTURE_TICK:
1270             // fall-through
1271         case Effect::TICK:
1272             // fall-through
1273         case Effect::CLICK:
1274             // fall-through
1275         case Effect::HEAVY_CLICK:
1276             status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
1277             break;
1278         case Effect::DOUBLE_CLICK:
1279             status = getCompoundDetails(effect, strength, &timeMs, &volLevel, &effectQueue);
1280             break;
1281         default:
1282             mStatsApi->logError(kUnsupportedOpError);
1283             status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1284             break;
1285     }
1286     if (!status.isOk()) {
1287         goto exit;
1288     }
1289 
1290     status = performEffect(effectIndex, volLevel, &effectQueue, callback);
1291 
1292 exit:
1293 
1294     *outTimeMs = timeMs;
1295     return status;
1296 }
1297 
performEffect(uint32_t effectIndex,uint32_t volLevel,const std::string * effectQueue,const std::shared_ptr<IVibratorCallback> & callback)1298 ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
1299                                            const std::string *effectQueue,
1300                                            const std::shared_ptr<IVibratorCallback> &callback) {
1301     HAPTICS_TRACE("performEffect(effectIndex:%u, volLevel:%u, effectQueue:%s, callback)",
1302                   effectIndex, volLevel, effectQueue->c_str());
1303     if (effectQueue && !effectQueue->empty()) {
1304         ndk::ScopedAStatus status = setEffectQueue(*effectQueue);
1305         if (!status.isOk()) {
1306             return status;
1307         }
1308         setEffectAmplitude(VOLTAGE_SCALE_MAX, VOLTAGE_SCALE_MAX);
1309         effectIndex = WAVEFORM_TRIGGER_QUEUE_INDEX;
1310     } else {
1311         setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
1312     }
1313 
1314     return on(MAX_TIME_MS, effectIndex, callback);
1315 }
1316 
waitForComplete(std::shared_ptr<IVibratorCallback> && callback)1317 void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) {
1318     HAPTICS_TRACE("waitForComplete(callback)");
1319     ALOGD("waitForComplete");
1320     uint32_t duration;
1321     {
1322         const std::scoped_lock<std::mutex> lock(mTotalDurationMutex);
1323         duration = ((mTotalDuration + POLLING_TIMEOUT) < UINT32_MAX)
1324                            ? mTotalDuration + POLLING_TIMEOUT
1325                            : UINT32_MAX;
1326     }
1327     if (!mHwApi->pollVibeState(false, duration)) {
1328         ALOGE("Timeout(%u)! Fail to poll STOP state", duration);
1329     } else {
1330         ALOGD("waitForComplete: Get STOP! Set active to 0.");
1331     }
1332     mHwApi->setActivate(false);
1333 
1334     if (callback) {
1335         auto ret = callback->onComplete();
1336         if (!ret.isOk()) {
1337             mStatsApi->logError(kAsyncFailError);
1338             ALOGE("Failed completion callback: %d", ret.getExceptionCode());
1339         }
1340     }
1341 }
1342 
intensityToVolLevel(float intensity,uint32_t effectIndex)1343 uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) {
1344     HAPTICS_TRACE("intensityToVolLevel(intensity:%f, effectIndex:%u)", intensity, effectIndex);
1345     uint32_t volLevel;
1346     auto calc = [](float intst, std::array<uint32_t, 2> v) -> uint32_t {
1347                 return std::lround(intst * (v[1] - v[0])) + v[0]; };
1348 
1349     switch (effectIndex) {
1350         case WAVEFORM_LIGHT_TICK_INDEX:
1351             volLevel = calc(intensity, mTickEffectVol);
1352             break;
1353         case WAVEFORM_QUICK_RISE_INDEX:
1354             // fall-through
1355         case WAVEFORM_QUICK_FALL_INDEX:
1356             volLevel = calc(intensity, mLongEffectVol);
1357             break;
1358         case WAVEFORM_CLICK_INDEX:
1359             // fall-through
1360         case WAVEFORM_THUD_INDEX:
1361             // fall-through
1362         case WAVEFORM_SPIN_INDEX:
1363             // fall-through
1364         case WAVEFORM_SLOW_RISE_INDEX:
1365             // fall-through
1366         default:
1367             volLevel = calc(intensity, mClickEffectVol);
1368             break;
1369     }
1370 
1371     return volLevel;
1372 }
1373 
findHapticAlsaDevice(int * card,int * device)1374 bool Vibrator::findHapticAlsaDevice(int *card, int *device) {
1375     HAPTICS_TRACE("findHapticAlsaDevice(card, device)");
1376     std::string line;
1377     std::ifstream myfile(PROC_SND_PCM);
1378     if (myfile.is_open()) {
1379         while (getline(myfile, line)) {
1380             if (line.find(HAPTIC_PCM_DEVICE_SYMBOL) != std::string::npos) {
1381                 std::stringstream ss(line);
1382                 std::string currentToken;
1383                 std::getline(ss, currentToken, ':');
1384                 sscanf(currentToken.c_str(), "%d-%d", card, device);
1385                 return true;
1386             }
1387         }
1388         myfile.close();
1389     } else {
1390         mStatsApi->logError(kAlsaFailError);
1391         ALOGE("Failed to read file: %s", PROC_SND_PCM);
1392     }
1393     return false;
1394 }
1395 
hasHapticAlsaDevice()1396 bool Vibrator::hasHapticAlsaDevice() {
1397     HAPTICS_TRACE("hasHapticAlsaDevice()");
1398     // We need to call findHapticAlsaDevice once only. Calling in the
1399     // constructor is too early in the boot process and the pcm file contents
1400     // are empty. Hence we make the call here once only right before we need to.
1401     static bool configHapticAlsaDeviceDone = false;
1402     if (!configHapticAlsaDeviceDone) {
1403         if (findHapticAlsaDevice(&mCard, &mDevice)) {
1404             mHasHapticAlsaDevice = true;
1405             configHapticAlsaDeviceDone = true;
1406         } else {
1407             mStatsApi->logError(kAlsaFailError);
1408             ALOGE("Haptic ALSA device not supported");
1409         }
1410     }
1411     return mHasHapticAlsaDevice;
1412 }
1413 
enableHapticPcmAmp(struct pcm ** haptic_pcm,bool enable,int card,int device)1414 bool Vibrator::enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) {
1415     HAPTICS_TRACE("enableHapticPcmAmp(pcm, enable:%u, card:%d, device:%d)", enable, card, device);
1416     int ret = 0;
1417 
1418     if (enable) {
1419         *haptic_pcm = pcm_open(card, device, PCM_OUT, &haptic_nohost_config);
1420         if (!pcm_is_ready(*haptic_pcm)) {
1421             ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm));
1422             goto fail;
1423         }
1424 
1425         ret = pcm_prepare(*haptic_pcm);
1426         if (ret < 0) {
1427             ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm));
1428             goto fail;
1429         }
1430 
1431         ret = pcm_start(*haptic_pcm);
1432         if (ret < 0) {
1433             ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm));
1434             goto fail;
1435         }
1436 
1437         return true;
1438     } else {
1439         if (*haptic_pcm) {
1440             pcm_close(*haptic_pcm);
1441             *haptic_pcm = NULL;
1442         }
1443         return true;
1444     }
1445 
1446 fail:
1447     pcm_close(*haptic_pcm);
1448     *haptic_pcm = NULL;
1449     return false;
1450 }
1451 
setPwleRampDown()1452 void Vibrator::setPwleRampDown() {
1453     HAPTICS_TRACE("setPwleRampDown()");
1454     // The formula for calculating the ramp down coefficient to be written into
1455     // pwle_ramp_down is as follows:
1456     //    Crd = 1048.576 / Trd
1457     // where Trd is the desired ramp down time in seconds
1458     // pwle_ramp_down accepts only 24 bit integers values
1459 
1460     if (RAMP_DOWN_TIME_MS != 0.0) {
1461         const float seconds = RAMP_DOWN_TIME_MS / 1000;
1462         const auto ramp_down_coefficient = static_cast<uint32_t>(RAMP_DOWN_CONSTANT / seconds);
1463         if (!mHwApi->setPwleRampDown(ramp_down_coefficient)) {
1464             mStatsApi->logError(kHwApiError);
1465             ALOGE("Failed to write \"%d\" to pwle_ramp_down (%d): %s", ramp_down_coefficient, errno,
1466                   strerror(errno));
1467         }
1468     } else {
1469         // Turn off the low level PWLE Ramp Down feature
1470         if (!mHwApi->setPwleRampDown(0)) {
1471             mStatsApi->logError(kHwApiError);
1472             ALOGE("Failed to write 0 to pwle_ramp_down (%d): %s", errno, strerror(errno));
1473         }
1474     }
1475 }
1476 
1477 }  // namespace vibrator
1478 }  // namespace hardware
1479 }  // namespace android
1480 }  // namespace aidl
1481