• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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