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
18 #include "Vibrator.h"
19 #include "utils.h"
20
21 #include <cutils/properties.h>
22 #include <hardware/hardware.h>
23 #include <hardware/vibrator.h>
24 #include <log/log.h>
25 #include <utils/Trace.h>
26
27 #include <cinttypes>
28 #include <cmath>
29 #include <fstream>
30 #include <iostream>
31
32 namespace aidl {
33 namespace android {
34 namespace hardware {
35 namespace vibrator {
36
37 static constexpr int8_t MAX_RTP_INPUT = 127;
38 static constexpr int8_t MIN_RTP_INPUT = 0;
39
40 static constexpr char RTP_MODE[] = "rtp";
41 static constexpr char WAVEFORM_MODE[] = "waveform";
42
43 // Use effect #1 in the waveform library for CLICK effect
44 static constexpr uint8_t WAVEFORM_CLICK_EFFECT_INDEX = 1;
45
46 // Use effect #2 in the waveform library for TICK effect
47 static constexpr char WAVEFORM_TICK_EFFECT_INDEX = 2;
48
49 // Use effect #3 in the waveform library for DOUBLE_CLICK effect
50 static constexpr char WAVEFORM_DOUBLE_CLICK_EFFECT_INDEX = 3;
51
52 // Use effect #4 in the waveform library for HEAVY_CLICK effect
53 static constexpr char WAVEFORM_HEAVY_CLICK_EFFECT_INDEX = 4;
54
freqPeriodFormula(std::uint32_t in)55 static std::uint32_t freqPeriodFormula(std::uint32_t in) {
56 return 1000000000 / (24615 * in);
57 }
58
freqPeriodFormulaFloat(std::uint32_t in)59 static float freqPeriodFormulaFloat(std::uint32_t in) {
60 return static_cast<float>(1000000000) / static_cast<float>(24615 * in);
61 }
62
63 using utils::toUnderlying;
64
Vibrator(std::unique_ptr<HwApi> hwapi,std::unique_ptr<HwCal> hwcal)65 Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
66 : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
67 std::string autocal;
68 uint32_t lraPeriod;
69 bool dynamicConfig;
70
71 if (!mHwApi->setState(true)) {
72 ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
73 }
74
75 if (mHwCal->getAutocal(&autocal)) {
76 mHwApi->setAutocal(autocal);
77 }
78 mHwCal->getLraPeriod(&lraPeriod);
79
80 mHwCal->getCloseLoopThreshold(&mCloseLoopThreshold);
81 mHwCal->getDynamicConfig(&dynamicConfig);
82
83 if (dynamicConfig) {
84 uint32_t longFreqencyShift;
85 uint32_t shortVoltageMax, longVoltageMax;
86
87 mHwCal->getLongFrequencyShift(&longFreqencyShift);
88 mHwCal->getShortVoltageMax(&shortVoltageMax);
89 mHwCal->getLongVoltageMax(&longVoltageMax);
90
91 mEffectConfig.reset(new VibrationConfig({
92 .shape = WaveShape::SINE,
93 .odClamp = shortVoltageMax,
94 .olLraPeriod = lraPeriod,
95 }));
96 mSteadyConfig.reset(new VibrationConfig({
97 .shape = WaveShape::SQUARE,
98 .odClamp = longVoltageMax,
99 // 1. Change long lra period to frequency
100 // 2. Get frequency': subtract the frequency shift from the frequency
101 // 3. Get final long lra period after put the frequency' to formula
102 .olLraPeriod = freqPeriodFormula(freqPeriodFormula(lraPeriod) - longFreqencyShift),
103 }));
104 } else {
105 mHwApi->setOlLraPeriod(lraPeriod);
106 }
107
108 mHwCal->getClickDuration(&mClickDuration);
109 mHwCal->getTickDuration(&mTickDuration);
110 mHwCal->getDoubleClickDuration(&mDoubleClickDuration);
111 mHwCal->getHeavyClickDuration(&mHeavyClickDuration);
112 }
113
getCapabilities(int32_t * _aidl_return)114 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
115 ATRACE_NAME("Vibrator::getCapabilities");
116 int32_t ret = IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY;
117 if (mHwApi->hasRtpInput()) {
118 ret |= IVibrator::CAP_AMPLITUDE_CONTROL;
119 }
120 *_aidl_return = ret;
121 return ndk::ScopedAStatus::ok();
122 }
123
on(uint32_t timeoutMs,const char mode[],const std::unique_ptr<VibrationConfig> & config)124 ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, const char mode[],
125 const std::unique_ptr<VibrationConfig> &config) {
126 LoopControl loopMode = LoopControl::OPEN;
127
128 // Open-loop mode is used for short click for over-drive
129 // Close-loop mode is used for long notification for stability
130 if (mode == RTP_MODE && timeoutMs > mCloseLoopThreshold) {
131 loopMode = LoopControl::CLOSE;
132 }
133
134 mHwApi->setCtrlLoop(toUnderlying(loopMode));
135 if (!mHwApi->setDuration(timeoutMs)) {
136 ALOGE("Failed to set duration (%d): %s", errno, strerror(errno));
137 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
138 }
139
140 mHwApi->setMode(mode);
141 if (config != nullptr) {
142 mHwApi->setLraWaveShape(toUnderlying(config->shape));
143 mHwApi->setOdClamp(config->odClamp);
144 mHwApi->setOlLraPeriod(config->olLraPeriod);
145 }
146
147 if (!mHwApi->setActivate(1)) {
148 ALOGE("Failed to activate (%d): %s", errno, strerror(errno));
149 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
150 }
151
152 return ndk::ScopedAStatus::ok();
153 }
154
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)155 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
156 const std::shared_ptr<IVibratorCallback> &callback) {
157 ATRACE_NAME("Vibrator::on");
158 if (callback) {
159 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
160 }
161 return on(timeoutMs, RTP_MODE, mSteadyConfig);
162 }
163
off()164 ndk::ScopedAStatus Vibrator::off() {
165 ATRACE_NAME("Vibrator::off");
166 if (!mHwApi->setActivate(0)) {
167 ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
168 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
169 }
170 return ndk::ScopedAStatus::ok();
171 }
172
setAmplitude(float amplitude)173 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
174 ATRACE_NAME("Vibrator::setAmplitude");
175 if (amplitude <= 0.0f || amplitude > 1.0f) {
176 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
177 }
178
179 int32_t rtp_input = std::round(amplitude * (MAX_RTP_INPUT - MIN_RTP_INPUT) + MIN_RTP_INPUT);
180
181 if (!mHwApi->setRtpInput(rtp_input)) {
182 ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));
183 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
184 }
185
186 return ndk::ScopedAStatus::ok();
187 }
188
setExternalControl(bool enabled)189 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
190 ATRACE_NAME("Vibrator::setExternalControl");
191 ALOGE("Not support in DRV2624 solution, %d", enabled);
192 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
193 }
194
dump(int fd,const char ** args,uint32_t numArgs)195 binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
196 if (fd < 0) {
197 ALOGE("Called debug() with invalid fd.");
198 return STATUS_OK;
199 }
200
201 (void)args;
202 (void)numArgs;
203
204 dprintf(fd, "AIDL:\n");
205
206 dprintf(fd, " Close Loop Thresh: %" PRIu32 "\n", mCloseLoopThreshold);
207 if (mSteadyConfig) {
208 dprintf(fd, " Steady Shape: %" PRIu32 "\n", mSteadyConfig->shape);
209 dprintf(fd, " Steady OD Clamp: %" PRIu32 "\n", mSteadyConfig->odClamp);
210 dprintf(fd, " Steady OL LRA Period: %" PRIu32 "\n", mSteadyConfig->olLraPeriod);
211 }
212 if (mEffectConfig) {
213 dprintf(fd, " Effect Shape: %" PRIu32 "\n", mEffectConfig->shape);
214 dprintf(fd, " Effect OD Clamp: %" PRIu32 "\n", mEffectConfig->odClamp);
215 dprintf(fd, " Effect OL LRA Period: %" PRIu32 "\n", mEffectConfig->olLraPeriod);
216 }
217 dprintf(fd, " Click Duration: %" PRIu32 "\n", mClickDuration);
218 dprintf(fd, " Tick Duration: %" PRIu32 "\n", mTickDuration);
219 dprintf(fd, " Double Click Duration: %" PRIu32 "\n", mDoubleClickDuration);
220 dprintf(fd, " Heavy Click Duration: %" PRIu32 "\n", mHeavyClickDuration);
221
222 dprintf(fd, "\n");
223
224 mHwApi->debug(fd);
225
226 dprintf(fd, "\n");
227
228 mHwCal->debug(fd);
229
230 fsync(fd);
231 return STATUS_OK;
232 }
233
getSupportedEffects(std::vector<Effect> * _aidl_return)234 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
235 *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
236 Effect::DOUBLE_CLICK};
237 return ndk::ScopedAStatus::ok();
238 }
239
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)240 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
241 const std::shared_ptr<IVibratorCallback> &callback,
242 int32_t *_aidl_return) {
243 ATRACE_NAME("Vibrator::perform");
244 ndk::ScopedAStatus status;
245
246 if (callback) {
247 status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
248 } else {
249 status = performEffect(effect, strength, _aidl_return);
250 }
251
252 return status;
253 }
254
convertEffectStrength(EffectStrength strength,uint8_t * outScale)255 static ndk::ScopedAStatus convertEffectStrength(EffectStrength strength, uint8_t *outScale) {
256 uint8_t scale;
257
258 switch (strength) {
259 case EffectStrength::LIGHT:
260 scale = 2; // 50%
261 break;
262 case EffectStrength::MEDIUM:
263 case EffectStrength::STRONG:
264 scale = 0; // 100%
265 break;
266 default:
267 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
268 }
269
270 *outScale = scale;
271
272 return ndk::ScopedAStatus::ok();
273 }
274
getEffectDetails(Effect effect,uint8_t * outIndex,uint32_t * outTimeMs)275 ndk::ScopedAStatus Vibrator::getEffectDetails(Effect effect, uint8_t *outIndex,
276 uint32_t *outTimeMs) {
277 switch (effect) {
278 case Effect::TEXTURE_TICK:
279 *outIndex = WAVEFORM_TICK_EFFECT_INDEX;
280 *outTimeMs = mTickDuration;
281 break;
282 case Effect::CLICK:
283 *outIndex = WAVEFORM_CLICK_EFFECT_INDEX;
284 *outTimeMs = mClickDuration;
285 break;
286 case Effect::DOUBLE_CLICK:
287 *outIndex = WAVEFORM_DOUBLE_CLICK_EFFECT_INDEX;
288 *outTimeMs = mDoubleClickDuration;
289 break;
290 case Effect::TICK:
291 *outIndex = WAVEFORM_TICK_EFFECT_INDEX;
292 *outTimeMs = mTickDuration;
293 break;
294 case Effect::HEAVY_CLICK:
295 *outIndex = WAVEFORM_HEAVY_CLICK_EFFECT_INDEX;
296 *outTimeMs = mHeavyClickDuration;
297 break;
298 default:
299 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
300 }
301
302 return ndk::ScopedAStatus::ok();
303 }
304
performEffect(Effect effect,EffectStrength strength,int32_t * outTimeMs)305 ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
306 int32_t *outTimeMs) {
307 ndk::ScopedAStatus status;
308 uint8_t index;
309 uint32_t timeMS;
310 uint8_t scale;
311
312 status = getEffectDetails(effect, &index, &timeMS);
313 if (!status.isOk()) {
314 return status;
315 }
316
317 status = convertEffectStrength(strength, &scale);
318 if (!status.isOk()) {
319 return status;
320 }
321
322 mHwApi->setSequencer(std::to_string(index) + " 0");
323 mHwApi->setScale(scale);
324 status = on(timeMS, WAVEFORM_MODE, mEffectConfig);
325 if (!status.isOk()) {
326 return status;
327 }
328
329 *outTimeMs = timeMS;
330
331 return ndk::ScopedAStatus::ok();
332 }
333
getSupportedAlwaysOnEffects(std::vector<Effect> * _aidl_return)334 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> *_aidl_return) {
335 *_aidl_return = {
336 Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK,
337 Effect::HEAVY_CLICK, Effect::TEXTURE_TICK,
338 };
339 return ndk::ScopedAStatus::ok();
340 }
341
alwaysOnEnable(int32_t id,Effect effect,EffectStrength strength)342 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
343 if (id != 0) {
344 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
345 }
346
347 ndk::ScopedAStatus status;
348 uint8_t index;
349 uint32_t timeMs;
350 uint8_t scale;
351
352 status = getEffectDetails(effect, &index, &timeMs);
353 if (!status.isOk()) {
354 return status;
355 }
356
357 status = convertEffectStrength(strength, &scale);
358 if (!status.isOk()) {
359 return status;
360 }
361
362 if (!mHwApi->setLpTriggerEffect(index)) {
363 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
364 }
365
366 if (!mHwApi->setLpTriggerScale(scale)) {
367 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
368 }
369
370 return ndk::ScopedAStatus::ok();
371 }
alwaysOnDisable(int32_t id)372 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
373 if (id != 0) {
374 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
375 }
376
377 mHwApi->setLpTriggerEffect(0);
378
379 return ndk::ScopedAStatus::ok();
380 }
381
getCompositionDelayMax(int32_t *)382 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t * /*maxDelayMs*/) {
383 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
384 }
385
getCompositionSizeMax(int32_t *)386 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t * /*maxSize*/) {
387 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
388 }
389
getSupportedPrimitives(std::vector<CompositePrimitive> *)390 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(
391 std::vector<CompositePrimitive> * /*supported*/) {
392 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
393 }
394
getPrimitiveDuration(CompositePrimitive,int32_t *)395 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive /*primitive*/,
396 int32_t * /*durationMs*/) {
397 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
398 }
399
compose(const std::vector<CompositeEffect> &,const std::shared_ptr<IVibratorCallback> &)400 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> & /*composite*/,
401 const std::shared_ptr<IVibratorCallback> & /*callback*/) {
402 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
403 }
404
getResonantFrequency(float * resonantFreqHz)405 ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
406 uint32_t lraPeriod;
407 if(!mHwCal->getLraPeriod(&lraPeriod)) {
408 ALOGE("Failed to get resonant frequency (%d): %s", errno, strerror(errno));
409 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
410 }
411 *resonantFreqHz = freqPeriodFormulaFloat(lraPeriod);
412 return ndk::ScopedAStatus::ok();
413 }
414
getQFactor(float *)415 ndk::ScopedAStatus Vibrator::getQFactor(float * /*qFactor*/) {
416 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
417 }
418
getFrequencyResolution(float *)419 ndk::ScopedAStatus Vibrator::getFrequencyResolution(float * /*freqResolutionHz*/) {
420 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
421 }
422
getFrequencyMinimum(float *)423 ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float * /*freqMinimumHz*/) {
424 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
425 }
426
getBandwidthAmplitudeMap(std::vector<float> *)427 ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> * /*_aidl_return*/) {
428 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
429 }
430
getPwlePrimitiveDurationMax(int32_t *)431 ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t * /*durationMs*/) {
432 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
433 }
434
getPwleCompositionSizeMax(int32_t *)435 ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t * /*maxSize*/) {
436 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
437 }
438
getSupportedBraking(std::vector<Braking> *)439 ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> * /*supported*/) {
440 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
441 }
442
composePwle(const std::vector<PrimitivePwle> &,const std::shared_ptr<IVibratorCallback> &)443 ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> & /*composite*/,
444 const std::shared_ptr<IVibratorCallback> & /*callback*/) {
445 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
446 }
447
448 } // namespace vibrator
449 } // namespace hardware
450 } // namespace android
451 } // namespace aidl
452