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