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 #include "utils.h"
19
20 #include <android/looper.h>
21 #include <android/sensor.h>
22 #include <cutils/properties.h>
23 #include <hardware/hardware.h>
24 #include <hardware/vibrator.h>
25 #include <log/log.h>
26 #include <utils/Errors.h>
27 #include <utils/Trace.h>
28
29 #include <cinttypes>
30 #include <cmath>
31 #include <fstream>
32 #include <iostream>
33 #include <numeric>
34
35 namespace aidl {
36 namespace android {
37 namespace hardware {
38 namespace vibrator {
39
40 using ::android::NO_ERROR;
41 using ::android::UNEXPECTED_NULL;
42
43 static constexpr int8_t MAX_RTP_INPUT = 127;
44 static constexpr int8_t MIN_RTP_INPUT = 0;
45
46 static constexpr char RTP_MODE[] = "rtp";
47 static constexpr char WAVEFORM_MODE[] = "waveform";
48
49 // Use effect #1 in the waveform library for CLICK effect
50 static constexpr char WAVEFORM_CLICK_EFFECT_SEQ[] = "1 0";
51
52 // Use effect #2 in the waveform library for TICK effect
53 static constexpr char WAVEFORM_TICK_EFFECT_SEQ[] = "2 0";
54
55 // Use effect #3 in the waveform library for DOUBLE_CLICK effect
56 static constexpr char WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ[] = "3 0";
57
58 // Use effect #4 in the waveform library for HEAVY_CLICK effect
59 static constexpr char WAVEFORM_HEAVY_CLICK_EFFECT_SEQ[] = "4 0";
60
61 // UT team design those target G values
62 static constexpr std::array<float, 5> EFFECT_TARGET_G = {0.19, 0.30, 0.39, 0.66, 0.75};
63 static constexpr std::array<float, 3> STEADY_TARGET_G = {1.5, 1.145, 0.82};
64
65 struct SensorContext {
66 ASensorEventQueue *queue;
67 };
68 static std::vector<float> sXAxleData;
69 static std::vector<float> sYAxleData;
70 static uint64_t sEndTime = 0;
71 static struct timespec sGetTime;
72
73 #define MAX_VOLTAGE 3.2
74 #define FLOAT_EPS 1e-7
75 #define SENSOR_DATA_NUM 20
76 // Set sensing period to 2s
77 #define SENSING_PERIOD 2000000000
78 #define VIBRATION_MOTION_TIME_THRESHOLD 100
79 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
80
GSensorCallback(int fd,int events,void * data)81 int GSensorCallback(__attribute__((unused)) int fd, __attribute__((unused)) int events,
82 void *data) {
83 ASensorEvent event;
84 int event_count = 0;
85 SensorContext *context = reinterpret_cast<SensorContext *>(data);
86 event_count = ASensorEventQueue_getEvents(context->queue, &event, 1);
87 sXAxleData.push_back(event.data[0]);
88 sYAxleData.push_back(event.data[1]);
89 return 1;
90 }
91 // TODO: b/152305970
PollGSensor()92 int32_t PollGSensor() {
93 int err = NO_ERROR, counter = 0;
94 ASensorManager *sensorManager = nullptr;
95 ASensorRef GSensor;
96 ALooper *looper;
97 struct SensorContext context = {nullptr};
98
99 // Get proximity sensor events from the NDK
100 sensorManager = ASensorManager_getInstanceForPackage("");
101 if (!sensorManager) {
102 ALOGI("Chase %s: Sensor manager is NULL.\n", __FUNCTION__);
103 err = UNEXPECTED_NULL;
104 return 0;
105 }
106 GSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_GRAVITY);
107 if (GSensor == nullptr) {
108 ALOGE("%s:Chase Unable to get g sensor\n", __func__);
109 } else {
110 looper = ALooper_forThread();
111 if (looper == nullptr) {
112 looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
113 }
114 context.queue =
115 ASensorManager_createEventQueue(sensorManager, looper, 0, GSensorCallback, &context);
116
117 err = ASensorEventQueue_registerSensor(context.queue, GSensor, 0, 0);
118 if (err != NO_ERROR) {
119 ALOGE("Chase %s: Error %d registering G sensor with event queue.\n", __FUNCTION__, err);
120 return 0;
121 }
122 if (err < 0) {
123 ALOGE("%s:Chase Unable to register for G sensor events\n", __func__);
124 } else {
125 for (counter = 0; counter < SENSOR_DATA_NUM; counter++) {
126 ALooper_pollOnce(5, nullptr, nullptr, nullptr);
127 }
128 }
129 }
130 if (sensorManager != nullptr && context.queue != nullptr) {
131 ASensorEventQueue_disableSensor(context.queue, GSensor);
132 ASensorManager_destroyEventQueue(sensorManager, context.queue);
133 }
134
135 return 0;
136 }
137
138 // Temperature protection upper bound 10°C and lower bound 5°C
139 static constexpr int32_t TEMP_UPPER_BOUND = 10000;
140 static constexpr int32_t TEMP_LOWER_BOUND = 5000;
141 // Steady vibration's voltage in lower bound guarantee
142 static uint32_t STEADY_VOLTAGE_LOWER_BOUND = 90; // 1.8 Vpeak
143
freqPeriodFormula(std::uint32_t in)144 static std::uint32_t freqPeriodFormula(std::uint32_t in) {
145 return 1000000000 / (24615 * in);
146 }
147
convertLevelsToOdClamp(float voltageLevel,uint32_t lraPeriod)148 static std::uint32_t convertLevelsToOdClamp(float voltageLevel, uint32_t lraPeriod) {
149 float odClamp;
150
151 odClamp = voltageLevel /
152 ((21.32 / 1000.0) *
153 sqrt(1.0 - (static_cast<float>(freqPeriodFormula(lraPeriod)) * 8.0 / 10000.0)));
154
155 return round(odClamp);
156 }
157
targetGToVlevelsUnderLinearEquation(std::array<float,4> inputCoeffs,float targetG)158 static float targetGToVlevelsUnderLinearEquation(std::array<float, 4> inputCoeffs, float targetG) {
159 // Implement linear equation to get voltage levels, f(x) = ax + b
160 // 0 to 3.2 is our valid output
161 float outPutVal = 0.0f;
162 outPutVal = (targetG - inputCoeffs[1]) / inputCoeffs[0];
163 if ((outPutVal > FLOAT_EPS) && (outPutVal <= MAX_VOLTAGE)) {
164 return outPutVal;
165 } else {
166 return 0.0f;
167 }
168 }
169
targetGToVlevelsUnderCubicEquation(std::array<float,4> inputCoeffs,float targetG)170 static float targetGToVlevelsUnderCubicEquation(std::array<float, 4> inputCoeffs, float targetG) {
171 // Implement cubic equation to get voltage levels, f(x) = ax^3 + bx^2 + cx + d
172 // 0 to 3.2 is our valid output
173 float AA = 0.0f, BB = 0.0f, CC = 0.0f, Delta = 0.0f;
174 float Y1 = 0.0f, Y2 = 0.0f, K = 0.0f, T = 0.0f, sita = 0.0f;
175 float outPutVal = 0.0f;
176 float oneHalf = 1.0 / 2.0, oneThird = 1.0 / 3.0;
177 float cosSita = 0.0f, sinSitaSqrt3 = 0.0f, sqrtA = 0.0f;
178
179 AA = inputCoeffs[1] * inputCoeffs[1] - 3.0 * inputCoeffs[0] * inputCoeffs[2];
180 BB = inputCoeffs[1] * inputCoeffs[2] - 9.0 * inputCoeffs[0] * (inputCoeffs[3] - targetG);
181 CC = inputCoeffs[2] * inputCoeffs[2] - 3.0 * inputCoeffs[1] * (inputCoeffs[3] - targetG);
182
183 Delta = BB * BB - 4.0 * AA * CC;
184
185 // There are four discriminants in Shengjin formula.
186 // https://zh.wikipedia.org/wiki/%E4%B8%89%E6%AC%A1%E6%96%B9%E7%A8%8B#%E7%9B%9B%E9%87%91%E5%85%AC%E5%BC%8F%E6%B3%95
187 if ((fabs(AA) <= FLOAT_EPS) && (fabs(BB) <= FLOAT_EPS)) {
188 // Case 1: A = B = 0
189 outPutVal = -inputCoeffs[1] / (3 * inputCoeffs[0]);
190 if ((outPutVal > FLOAT_EPS) && (outPutVal <= MAX_VOLTAGE)) {
191 return outPutVal;
192 }
193 return 0.0f;
194 } else if (Delta > FLOAT_EPS) {
195 // Case 2: Delta > 0
196 Y1 = AA * inputCoeffs[1] + 3.0 * inputCoeffs[0] * (-BB + pow(Delta, oneHalf)) / 2.0;
197 Y2 = AA * inputCoeffs[1] + 3.0 * inputCoeffs[0] * (-BB - pow(Delta, oneHalf)) / 2.0;
198
199 if ((Y1 < -FLOAT_EPS) && (Y2 > FLOAT_EPS)) {
200 return (-inputCoeffs[1] + pow(-Y1, oneThird) - pow(Y2, oneThird)) /
201 (3.0 * inputCoeffs[0]);
202 } else if ((Y1 > FLOAT_EPS) && (Y2 < -FLOAT_EPS)) {
203 return (-inputCoeffs[1] - pow(Y1, oneThird) + pow(-Y2, oneThird)) /
204 (3.0 * inputCoeffs[0]);
205 } else if ((Y1 < -FLOAT_EPS) && (Y2 < -FLOAT_EPS)) {
206 return (-inputCoeffs[1] + pow(-Y1, oneThird) + pow(-Y2, oneThird)) /
207 (3.0 * inputCoeffs[0]);
208 } else {
209 return (-inputCoeffs[1] - pow(Y1, oneThird) - pow(Y2, oneThird)) /
210 (3.0 * inputCoeffs[0]);
211 }
212 return 0.0f;
213 } else if (Delta < -FLOAT_EPS) {
214 // Case 3: Delta < 0
215 T = (2 * AA * inputCoeffs[1] - 3 * inputCoeffs[0] * BB) / (2 * AA * sqrt(AA));
216 sita = acos(T);
217 cosSita = cos(sita / 3);
218 sinSitaSqrt3 = sqrt(3.0) * sin(sita / 3);
219 sqrtA = sqrt(AA);
220
221 outPutVal = (-inputCoeffs[1] - 2 * sqrtA * cosSita) / (3 * inputCoeffs[0]);
222 if ((outPutVal > FLOAT_EPS) && (outPutVal <= MAX_VOLTAGE)) {
223 return outPutVal;
224 }
225 outPutVal = (-inputCoeffs[1] + sqrtA * (cosSita + sinSitaSqrt3)) / (3 * inputCoeffs[0]);
226 if ((outPutVal > FLOAT_EPS) && (outPutVal <= MAX_VOLTAGE)) {
227 return outPutVal;
228 }
229 outPutVal = (-inputCoeffs[1] + sqrtA * (cosSita - sinSitaSqrt3)) / (3 * inputCoeffs[0]);
230 if ((outPutVal > FLOAT_EPS) && (outPutVal <= MAX_VOLTAGE)) {
231 return outPutVal;
232 }
233 return 0.0f;
234 } else if (Delta <= FLOAT_EPS) {
235 // Case 4: Delta = 0
236 K = BB / AA;
237 outPutVal = (-inputCoeffs[1] / inputCoeffs[0] + K);
238 if ((outPutVal > FLOAT_EPS) && (outPutVal <= MAX_VOLTAGE)) {
239 return outPutVal;
240 }
241 outPutVal = (-K / 2);
242 if ((outPutVal > FLOAT_EPS) && (outPutVal <= MAX_VOLTAGE)) {
243 return outPutVal;
244 }
245 return 0.0f;
246 } else {
247 // Exception handling
248 return 0.0f;
249 }
250 }
251
vLevelsToTargetGUnderCubicEquation(std::array<float,4> inputCoeffs,float vLevel)252 static float vLevelsToTargetGUnderCubicEquation(std::array<float, 4> inputCoeffs, float vLevel) {
253 float inputVoltage = 0.0f;
254 inputVoltage = vLevel * MAX_VOLTAGE;
255 return inputCoeffs[0] * pow(inputVoltage, 3) + inputCoeffs[1] * pow(inputVoltage, 2) +
256 inputCoeffs[2] * inputVoltage + inputCoeffs[3];
257 }
258
motionAwareness()259 static bool motionAwareness() {
260 float avgX = 0.0, avgY = 0.0;
261 uint64_t current_time = 0;
262 clock_gettime(CLOCK_MONOTONIC, &sGetTime);
263 current_time = ((uint64_t)sGetTime.tv_sec * 1000 * 1000 * 1000) + sGetTime.tv_nsec;
264
265 if ((current_time - sEndTime) > SENSING_PERIOD) {
266 sXAxleData.clear();
267 sYAxleData.clear();
268 PollGSensor();
269 clock_gettime(CLOCK_MONOTONIC, &sGetTime);
270 sEndTime = ((uint64_t)sGetTime.tv_sec * 1000 * 1000 * 1000) + sGetTime.tv_nsec;
271 }
272
273 avgX = std::accumulate(sXAxleData.begin(), sXAxleData.end(), 0.0) / sXAxleData.size();
274 avgY = std::accumulate(sYAxleData.begin(), sYAxleData.end(), 0.0) / sYAxleData.size();
275
276 if ((avgX > -1.3) && (avgX < 1.3) && (avgY > -0.8) && (avgY < 0.8)) {
277 return false;
278 } else {
279 return true;
280 }
281 }
282
283 using utils::toUnderlying;
284
Vibrator(std::unique_ptr<HwApi> hwapi,std::unique_ptr<HwCal> hwcal)285 Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
286 : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
287 std::string autocal;
288 uint32_t lraPeriod = 0, lpTrigSupport = 0;
289 bool hasEffectCoeffs = false, hasSteadyCoeffs = false;
290 std::array<float, 4> effectCoeffs = {0};
291 std::array<float, 4> steadyCoeffs = {0};
292
293 if (!mHwApi->setState(true)) {
294 ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
295 }
296
297 if (mHwCal->getAutocal(&autocal)) {
298 mHwApi->setAutocal(autocal);
299 }
300 mHwCal->getLraPeriod(&lraPeriod);
301
302 mHwCal->getCloseLoopThreshold(&mCloseLoopThreshold);
303 mHwCal->getDynamicConfig(&mDynamicConfig);
304
305 if (mDynamicConfig) {
306 uint8_t i = 0;
307 float tempVolLevel = 0.0f;
308 float tempAmpMax = 0.0f;
309 uint32_t longFreqencyShift = 0;
310 uint32_t shortVoltageMax = 0, longVoltageMax = 0;
311 uint32_t shape = 0;
312
313 mHwCal->getLongFrequencyShift(&longFreqencyShift);
314 mHwCal->getShortVoltageMax(&shortVoltageMax);
315 mHwCal->getLongVoltageMax(&longVoltageMax);
316
317 hasEffectCoeffs = mHwCal->getEffectCoeffs(&effectCoeffs);
318 for (i = 0; i < 5; i++) {
319 if (hasEffectCoeffs) {
320 // Use linear approach to get the target voltage levels
321 if ((effectCoeffs[2] == 0) && (effectCoeffs[3] == 0)) {
322 tempVolLevel =
323 targetGToVlevelsUnderLinearEquation(effectCoeffs, EFFECT_TARGET_G[i]);
324 mEffectTargetOdClamp[i] = convertLevelsToOdClamp(tempVolLevel, lraPeriod);
325 } else {
326 // Use cubic approach to get the target voltage levels
327 tempVolLevel =
328 targetGToVlevelsUnderCubicEquation(effectCoeffs, EFFECT_TARGET_G[i]);
329 mEffectTargetOdClamp[i] = convertLevelsToOdClamp(tempVolLevel, lraPeriod);
330 }
331 } else {
332 mEffectTargetOdClamp[i] = shortVoltageMax;
333 }
334 }
335 // Add a boundary protection for level 5 only, since
336 // some devices might not be able to reach the maximum target G
337 if ((mEffectTargetOdClamp[4] <= 0) || (mEffectTargetOdClamp[4] > shortVoltageMax)) {
338 mEffectTargetOdClamp[4] = shortVoltageMax;
339 }
340
341 mHwCal->getEffectShape(&shape);
342 mEffectConfig.reset(new VibrationConfig({
343 .shape = (shape == UINT32_MAX) ? WaveShape::SINE : static_cast<WaveShape>(shape),
344 .odClamp = &mEffectTargetOdClamp[0],
345 .olLraPeriod = lraPeriod,
346 }));
347
348 hasSteadyCoeffs = mHwCal->getSteadyCoeffs(&steadyCoeffs);
349 if (hasSteadyCoeffs) {
350 for (i = 0; i < 3; i++) {
351 // Use cubic approach to get the steady target voltage levels
352 // For steady level 3 voltage which is used for non-motion voltage, we use
353 // interpolation method to calculate the voltage via 20% of MAX
354 // voltage, 60% of MAX voltage and steady level 3 target G
355 if (i == 2) {
356 tempVolLevel = ((STEADY_TARGET_G[2] -
357 vLevelsToTargetGUnderCubicEquation(steadyCoeffs, 0.2)) *
358 0.4 * MAX_VOLTAGE) /
359 (vLevelsToTargetGUnderCubicEquation(steadyCoeffs, 0.6) -
360 vLevelsToTargetGUnderCubicEquation(steadyCoeffs, 0.2)) +
361 0.2 * MAX_VOLTAGE;
362 } else {
363 tempVolLevel =
364 targetGToVlevelsUnderCubicEquation(steadyCoeffs, STEADY_TARGET_G[i]);
365 }
366 mSteadyTargetOdClamp[i] = convertLevelsToOdClamp(tempVolLevel, lraPeriod);
367 if ((mSteadyTargetOdClamp[i] <= 0) || (mSteadyTargetOdClamp[i] > longVoltageMax)) {
368 mSteadyTargetOdClamp[i] = longVoltageMax;
369 }
370 }
371 } else {
372 mSteadyTargetOdClamp[0] =
373 mHwCal->getSteadyAmpMax(&tempAmpMax)
374 ? round((STEADY_TARGET_G[0] / tempAmpMax) * longVoltageMax)
375 : longVoltageMax;
376 mSteadyTargetOdClamp[2] =
377 mHwCal->getSteadyAmpMax(&tempAmpMax)
378 ? round((STEADY_TARGET_G[2] / tempAmpMax) * longVoltageMax)
379 : longVoltageMax;
380 }
381 mHwCal->getSteadyShape(&shape);
382 mSteadyConfig.reset(new VibrationConfig({
383 .shape = (shape == UINT32_MAX) ? WaveShape::SQUARE : static_cast<WaveShape>(shape),
384 .odClamp = &mSteadyTargetOdClamp[0],
385 .olLraPeriod = lraPeriod,
386 }));
387 mSteadyOlLraPeriod = lraPeriod;
388 // 1. Change long lra period to frequency
389 // 2. Get frequency': subtract the frequency shift from the frequency
390 // 3. Get final long lra period after put the frequency' to formula
391 mSteadyOlLraPeriodShift =
392 freqPeriodFormula(freqPeriodFormula(lraPeriod) - longFreqencyShift);
393 } else {
394 mHwApi->setOlLraPeriod(lraPeriod);
395 }
396
397 mHwCal->getClickDuration(&mClickDuration);
398 mHwCal->getTickDuration(&mTickDuration);
399 mHwCal->getDoubleClickDuration(&mDoubleClickDuration);
400 mHwCal->getHeavyClickDuration(&mHeavyClickDuration);
401
402 // This enables effect #1 from the waveform library to be triggered by SLPI
403 // while the AP is in suspend mode
404 // For default setting, we will enable this feature if that project did not
405 // set the lptrigger config
406 mHwCal->getTriggerEffectSupport(&lpTrigSupport);
407 if (!mHwApi->setLpTriggerEffect(lpTrigSupport)) {
408 ALOGW("Failed to set LP trigger mode (%d): %s", errno, strerror(errno));
409 }
410 }
411
getCapabilities(int32_t * _aidl_return)412 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
413 ATRACE_NAME("Vibrator::getCapabilities");
414 int32_t ret = 0;
415 if (mHwApi->hasRtpInput()) {
416 ret |= IVibrator::CAP_AMPLITUDE_CONTROL;
417 }
418 *_aidl_return = ret;
419 return ndk::ScopedAStatus::ok();
420 }
421
on(uint32_t timeoutMs,const char mode[],const std::unique_ptr<VibrationConfig> & config,const int8_t volOffset)422 ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, const char mode[],
423 const std::unique_ptr<VibrationConfig> &config,
424 const int8_t volOffset) {
425 LoopControl loopMode = LoopControl::OPEN;
426
427 // Open-loop mode is used for short click for over-drive
428 // Close-loop mode is used for long notification for stability
429 if (mode == RTP_MODE && timeoutMs > mCloseLoopThreshold) {
430 loopMode = LoopControl::CLOSE;
431 }
432
433 mHwApi->setCtrlLoop(toUnderlying(loopMode));
434 if (!mHwApi->setDuration(timeoutMs)) {
435 ALOGE("Failed to set duration (%d): %s", errno, strerror(errno));
436 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
437 }
438
439 mHwApi->setMode(mode);
440 if (config != nullptr) {
441 mHwApi->setLraWaveShape(toUnderlying(config->shape));
442 mHwApi->setOdClamp(config->odClamp[volOffset]);
443 mHwApi->setOlLraPeriod(config->olLraPeriod);
444 }
445
446 if (!mHwApi->setActivate(1)) {
447 ALOGE("Failed to activate (%d): %s", errno, strerror(errno));
448 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
449 }
450
451 return ndk::ScopedAStatus::ok();
452 }
453
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)454 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
455 const std::shared_ptr<IVibratorCallback> &callback) {
456 ATRACE_NAME("Vibrator::on");
457
458 if (callback) {
459 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
460 }
461
462 if (mDynamicConfig) {
463 int temperature = 0;
464 mHwApi->getPATemp(&temperature);
465 if (temperature > TEMP_UPPER_BOUND) {
466 mSteadyConfig->odClamp = &mSteadyTargetOdClamp[0];
467 mSteadyConfig->olLraPeriod = mSteadyOlLraPeriod;
468 // TODO: b/162346934 This a compromise way to bypass the motion
469 // awareness delay
470 if ((timeoutMs > VIBRATION_MOTION_TIME_THRESHOLD) && (!motionAwareness())) {
471 return on(timeoutMs, RTP_MODE, mSteadyConfig, 2);
472 }
473 } else if (temperature < TEMP_LOWER_BOUND) {
474 mSteadyConfig->odClamp = &STEADY_VOLTAGE_LOWER_BOUND;
475 mSteadyConfig->olLraPeriod = mSteadyOlLraPeriodShift;
476 }
477 }
478
479 return on(timeoutMs, RTP_MODE, mSteadyConfig, 0);
480 }
481
off()482 ndk::ScopedAStatus Vibrator::off() {
483 ATRACE_NAME("Vibrator::off");
484 if (!mHwApi->setActivate(0)) {
485 ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
486 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
487 }
488 return ndk::ScopedAStatus::ok();
489 }
490
setAmplitude(float amplitude)491 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
492 ATRACE_NAME("Vibrator::setAmplitude");
493 if (amplitude <= 0.0f || amplitude > 1.0f) {
494 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
495 }
496
497 int32_t rtp_input = std::round(amplitude * (MAX_RTP_INPUT - MIN_RTP_INPUT) + MIN_RTP_INPUT);
498
499 if (!mHwApi->setRtpInput(rtp_input)) {
500 ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));
501 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
502 }
503
504 return ndk::ScopedAStatus::ok();
505 }
506
setExternalControl(bool enabled)507 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
508 ATRACE_NAME("Vibrator::setExternalControl");
509 ALOGE("Not support in DRV2624 solution, %d", enabled);
510 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
511 }
512
dump(int fd,const char ** args,uint32_t numArgs)513 binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
514 if (fd < 0) {
515 ALOGE("Called debug() with invalid fd.");
516 return STATUS_OK;
517 }
518
519 (void)args;
520 (void)numArgs;
521
522 dprintf(fd, "AIDL:\n");
523
524 dprintf(fd, " Close Loop Thresh: %" PRIu32 "\n", mCloseLoopThreshold);
525 if (mSteadyConfig) {
526 dprintf(fd, " Steady Shape: %" PRIu32 "\n", mSteadyConfig->shape);
527 dprintf(fd, " Steady OD Clamp: %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
528 mSteadyConfig->odClamp[0], mSteadyConfig->odClamp[1], mSteadyConfig->odClamp[2]);
529 dprintf(fd, " Steady OL LRA Period: %" PRIu32 "\n", mSteadyConfig->olLraPeriod);
530 }
531 if (mEffectConfig) {
532 dprintf(fd, " Effect Shape: %" PRIu32 "\n", mEffectConfig->shape);
533 dprintf(fd,
534 " Effect OD Clamp: %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
535 mEffectConfig->odClamp[0], mEffectConfig->odClamp[1], mEffectConfig->odClamp[2],
536 mEffectConfig->odClamp[3], mEffectConfig->odClamp[4]);
537 dprintf(fd, " Effect OL LRA Period: %" PRIu32 "\n", mEffectConfig->olLraPeriod);
538 }
539 dprintf(fd, " Click Duration: %" PRIu32 "\n", mClickDuration);
540 dprintf(fd, " Tick Duration: %" PRIu32 "\n", mTickDuration);
541 dprintf(fd, " Double Click Duration: %" PRIu32 "\n", mDoubleClickDuration);
542 dprintf(fd, " Heavy Click Duration: %" PRIu32 "\n", mHeavyClickDuration);
543
544 dprintf(fd, "\n");
545
546 mHwApi->debug(fd);
547
548 dprintf(fd, "\n");
549
550 mHwCal->debug(fd);
551
552 fsync(fd);
553 return STATUS_OK;
554 }
555
getSupportedEffects(std::vector<Effect> * _aidl_return)556 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
557 *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
558 Effect::DOUBLE_CLICK};
559 return ndk::ScopedAStatus::ok();
560 }
561
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)562 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
563 const std::shared_ptr<IVibratorCallback> &callback,
564 int32_t *_aidl_return) {
565 ATRACE_NAME("Vibrator::perform");
566 ndk::ScopedAStatus status;
567
568 if (callback) {
569 status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
570 } else {
571 status = performEffect(effect, strength, _aidl_return);
572 }
573
574 return status;
575 }
576
performEffect(Effect effect,EffectStrength strength,int32_t * outTimeMs)577 ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
578 int32_t *outTimeMs) {
579 ndk::ScopedAStatus status;
580 uint32_t timeMS;
581 int8_t volOffset;
582
583 switch (strength) {
584 case EffectStrength::LIGHT:
585 volOffset = 0;
586 break;
587 case EffectStrength::MEDIUM:
588 volOffset = 1;
589 break;
590 case EffectStrength::STRONG:
591 volOffset = 1;
592 break;
593 default:
594 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
595 break;
596 }
597
598 switch (effect) {
599 case Effect::TEXTURE_TICK:
600 mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
601 timeMS = mTickDuration;
602 volOffset = TEXTURE_TICK;
603 break;
604 case Effect::CLICK:
605 mHwApi->setSequencer(WAVEFORM_CLICK_EFFECT_SEQ);
606 timeMS = mClickDuration;
607 volOffset += CLICK;
608 break;
609 case Effect::DOUBLE_CLICK:
610 mHwApi->setSequencer(WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ);
611 timeMS = mDoubleClickDuration;
612 volOffset += CLICK;
613 break;
614 case Effect::TICK:
615 mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
616 timeMS = mTickDuration;
617 volOffset += TICK;
618 break;
619 case Effect::HEAVY_CLICK:
620 mHwApi->setSequencer(WAVEFORM_HEAVY_CLICK_EFFECT_SEQ);
621 timeMS = mHeavyClickDuration;
622 volOffset += HEAVY_CLICK;
623 break;
624 default:
625 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
626 }
627 status = on(timeMS, WAVEFORM_MODE, mEffectConfig, volOffset);
628 if (!status.isOk()) {
629 return status;
630 }
631
632 *outTimeMs = timeMS;
633
634 return ndk::ScopedAStatus::ok();
635 }
636
getSupportedAlwaysOnEffects(std::vector<Effect> *)637 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> * /*_aidl_return*/) {
638 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
639 }
640
alwaysOnEnable(int32_t,Effect,EffectStrength)641 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t /*id*/, Effect /*effect*/,
642 EffectStrength /*strength*/) {
643 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
644 }
alwaysOnDisable(int32_t)645 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) {
646 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
647 }
648
getCompositionDelayMax(int32_t *)649 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t * /*maxDelayMs*/) {
650 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
651 }
652
getCompositionSizeMax(int32_t *)653 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t * /*maxSize*/) {
654 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
655 }
656
getSupportedPrimitives(std::vector<CompositePrimitive> *)657 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive> * /*supported*/) {
658 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
659 }
660
getPrimitiveDuration(CompositePrimitive,int32_t *)661 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive /*primitive*/,
662 int32_t * /*durationMs*/) {
663 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
664 }
665
compose(const std::vector<CompositeEffect> &,const std::shared_ptr<IVibratorCallback> &)666 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> & /*composite*/,
667 const std::shared_ptr<IVibratorCallback> & /*callback*/) {
668 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
669 }
670
671 } // namespace vibrator
672 } // namespace hardware
673 } // namespace android
674 } // namespace aidl
675