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 char WAVEFORM_CLICK_EFFECT_SEQ[] = "1 0";
45 
46 // Use effect #2 in the waveform library for TICK effect
47 static constexpr char WAVEFORM_TICK_EFFECT_SEQ[] = "2 0";
48 
49 // Use effect #3 in the waveform library for DOUBLE_CLICK effect
50 static constexpr char WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ[] = "3 0";
51 
52 // Use effect #4 in the waveform library for HEAVY_CLICK effect
53 static constexpr char WAVEFORM_HEAVY_CLICK_EFFECT_SEQ[] = "4 0";
54 
freqPeriodFormula(std::uint32_t in)55 static std::uint32_t freqPeriodFormula(std::uint32_t in) {
56     return 1000000000 / (24615 * in);
57 }
58 
59 using utils::toUnderlying;
60 
Vibrator(std::unique_ptr<HwApi> hwapi,std::unique_ptr<HwCal> hwcal)61 Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
62     : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
63     std::string autocal;
64     uint32_t lraPeriod;
65     bool dynamicConfig;
66 
67     if (!mHwApi->setState(true)) {
68         ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
69     }
70 
71     if (mHwCal->getAutocal(&autocal)) {
72         mHwApi->setAutocal(autocal);
73     }
74     mHwCal->getLraPeriod(&lraPeriod);
75 
76     mHwCal->getCloseLoopThreshold(&mCloseLoopThreshold);
77     mHwCal->getDynamicConfig(&dynamicConfig);
78 
79     if (dynamicConfig) {
80         uint32_t longFreqencyShift;
81         uint32_t shortVoltageMax, longVoltageMax;
82 
83         mHwCal->getLongFrequencyShift(&longFreqencyShift);
84         mHwCal->getShortVoltageMax(&shortVoltageMax);
85         mHwCal->getLongVoltageMax(&longVoltageMax);
86 
87         mEffectConfig.reset(new VibrationConfig({
88                 .shape = WaveShape::SINE,
89                 .odClamp = shortVoltageMax,
90                 .olLraPeriod = lraPeriod,
91         }));
92         mSteadyConfig.reset(new VibrationConfig({
93                 .shape = WaveShape::SQUARE,
94                 .odClamp = longVoltageMax,
95                 // 1. Change long lra period to frequency
96                 // 2. Get frequency': subtract the frequency shift from the frequency
97                 // 3. Get final long lra period after put the frequency' to formula
98                 .olLraPeriod = freqPeriodFormula(freqPeriodFormula(lraPeriod) - longFreqencyShift),
99         }));
100     } else {
101         mHwApi->setOlLraPeriod(lraPeriod);
102     }
103 
104     mHwCal->getClickDuration(&mClickDuration);
105     mHwCal->getTickDuration(&mTickDuration);
106     mHwCal->getDoubleClickDuration(&mDoubleClickDuration);
107     mHwCal->getHeavyClickDuration(&mHeavyClickDuration);
108 
109     // This enables effect #1 from the waveform library to be triggered by SLPI
110     // while the AP is in suspend mode
111     if (!mHwApi->setLpTriggerEffect(1)) {
112         ALOGW("Failed to set LP trigger mode (%d): %s", errno, strerror(errno));
113     }
114 }
115 
getCapabilities(int32_t * _aidl_return)116 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
117     ATRACE_NAME("Vibrator::getCapabilities");
118     int32_t ret = 0;
119     if (mHwApi->hasRtpInput()) {
120         ret |= IVibrator::CAP_AMPLITUDE_CONTROL;
121     }
122     *_aidl_return = ret;
123     return ndk::ScopedAStatus::ok();
124 }
125 
on(uint32_t timeoutMs,const char mode[],const std::unique_ptr<VibrationConfig> & config)126 ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, const char mode[],
127                                 const std::unique_ptr<VibrationConfig> &config) {
128     LoopControl loopMode = LoopControl::OPEN;
129 
130     // Open-loop mode is used for short click for over-drive
131     // Close-loop mode is used for long notification for stability
132     if (mode == RTP_MODE && timeoutMs > mCloseLoopThreshold) {
133         loopMode = LoopControl::CLOSE;
134     }
135 
136     mHwApi->setCtrlLoop(toUnderlying(loopMode));
137     if (!mHwApi->setDuration(timeoutMs)) {
138         ALOGE("Failed to set duration (%d): %s", errno, strerror(errno));
139         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
140     }
141 
142     mHwApi->setMode(mode);
143     if (config != nullptr) {
144         mHwApi->setLraWaveShape(toUnderlying(config->shape));
145         mHwApi->setOdClamp(config->odClamp);
146         mHwApi->setOlLraPeriod(config->olLraPeriod);
147     }
148 
149     if (!mHwApi->setActivate(1)) {
150         ALOGE("Failed to activate (%d): %s", errno, strerror(errno));
151         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
152     }
153 
154     return ndk::ScopedAStatus::ok();
155 }
156 
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)157 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
158                                 const std::shared_ptr<IVibratorCallback> &callback) {
159     ATRACE_NAME("Vibrator::on");
160     if (callback) {
161         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
162     }
163     return on(timeoutMs, RTP_MODE, mSteadyConfig);
164 }
165 
off()166 ndk::ScopedAStatus Vibrator::off() {
167     ATRACE_NAME("Vibrator::off");
168     if (!mHwApi->setActivate(0)) {
169         ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
170         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
171     }
172     return ndk::ScopedAStatus::ok();
173 }
174 
setAmplitude(float amplitude)175 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
176     ATRACE_NAME("Vibrator::setAmplitude");
177     if (amplitude <= 0.0f || amplitude > 1.0f) {
178         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
179     }
180 
181     int32_t rtp_input = std::round(amplitude * (MAX_RTP_INPUT - MIN_RTP_INPUT) + MIN_RTP_INPUT);
182 
183     if (!mHwApi->setRtpInput(rtp_input)) {
184         ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));
185         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
186     }
187 
188     return ndk::ScopedAStatus::ok();
189 }
190 
setExternalControl(bool enabled)191 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
192     ATRACE_NAME("Vibrator::setExternalControl");
193     ALOGE("Not support in DRV2624 solution, %d", enabled);
194     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
195 }
196 
dump(int fd,const char ** args,uint32_t numArgs)197 binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
198     if (fd < 0) {
199         ALOGE("Called debug() with invalid fd.");
200         return STATUS_OK;
201     }
202 
203     (void)args;
204     (void)numArgs;
205 
206     dprintf(fd, "AIDL:\n");
207 
208     dprintf(fd, "  Close Loop Thresh: %" PRIu32 "\n", mCloseLoopThreshold);
209     if (mSteadyConfig) {
210         dprintf(fd, "  Steady Shape: %" PRIu32 "\n", mSteadyConfig->shape);
211         dprintf(fd, "  Steady OD Clamp: %" PRIu32 "\n", mSteadyConfig->odClamp);
212         dprintf(fd, "  Steady OL LRA Period: %" PRIu32 "\n", mSteadyConfig->olLraPeriod);
213     }
214     if (mEffectConfig) {
215         dprintf(fd, "  Effect Shape: %" PRIu32 "\n", mEffectConfig->shape);
216         dprintf(fd, "  Effect OD Clamp: %" PRIu32 "\n", mEffectConfig->odClamp);
217         dprintf(fd, "  Effect OL LRA Period: %" PRIu32 "\n", mEffectConfig->olLraPeriod);
218     }
219     dprintf(fd, "  Click Duration: %" PRIu32 "\n", mClickDuration);
220     dprintf(fd, "  Tick Duration: %" PRIu32 "\n", mTickDuration);
221     dprintf(fd, "  Double Click Duration: %" PRIu32 "\n", mDoubleClickDuration);
222     dprintf(fd, "  Heavy Click Duration: %" PRIu32 "\n", mHeavyClickDuration);
223 
224     dprintf(fd, "\n");
225 
226     mHwApi->debug(fd);
227 
228     dprintf(fd, "\n");
229 
230     mHwCal->debug(fd);
231 
232     fsync(fd);
233     return STATUS_OK;
234 }
235 
getSupportedEffects(std::vector<Effect> * _aidl_return)236 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect> *_aidl_return) {
237     *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK,
238                      Effect::DOUBLE_CLICK};
239     return ndk::ScopedAStatus::ok();
240 }
241 
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)242 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
243                                      const std::shared_ptr<IVibratorCallback> &callback,
244                                      int32_t *_aidl_return) {
245     ATRACE_NAME("Vibrator::perform");
246     ndk::ScopedAStatus status;
247 
248     if (callback) {
249         status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
250     } else {
251         status = performEffect(effect, strength, _aidl_return);
252     }
253 
254     return status;
255 }
256 
convertEffectStrength(EffectStrength strength,uint8_t * outScale)257 static ndk::ScopedAStatus convertEffectStrength(EffectStrength strength, uint8_t *outScale) {
258     uint8_t scale;
259 
260     switch (strength) {
261         case EffectStrength::LIGHT:
262             scale = 2;  // 50%
263             break;
264         case EffectStrength::MEDIUM:
265         case EffectStrength::STRONG:
266             scale = 0;  // 100%
267             break;
268         default:
269             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
270     }
271 
272     *outScale = scale;
273 
274     return ndk::ScopedAStatus::ok();
275 }
276 
performEffect(Effect effect,EffectStrength strength,int32_t * outTimeMs)277 ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength,
278                                            int32_t *outTimeMs) {
279     ndk::ScopedAStatus status;
280     uint32_t timeMS = 0;
281     uint8_t scale;
282 
283     switch (effect) {
284         case Effect::TEXTURE_TICK:
285             mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
286             timeMS = mTickDuration;
287             break;
288         case Effect::CLICK:
289             mHwApi->setSequencer(WAVEFORM_CLICK_EFFECT_SEQ);
290             timeMS = mClickDuration;
291             break;
292         case Effect::DOUBLE_CLICK:
293             mHwApi->setSequencer(WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ);
294             timeMS = mDoubleClickDuration;
295             break;
296         case Effect::TICK:
297             mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
298             timeMS = mTickDuration;
299             break;
300         case Effect::HEAVY_CLICK:
301             mHwApi->setSequencer(WAVEFORM_HEAVY_CLICK_EFFECT_SEQ);
302             timeMS = mHeavyClickDuration;
303             break;
304         default:
305             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
306     }
307 
308     status = convertEffectStrength(strength, &scale);
309     if (!status.isOk()) {
310         return status;
311     }
312 
313     mHwApi->setScale(scale);
314     status = on(timeMS, WAVEFORM_MODE, mEffectConfig);
315     if (!status.isOk()) {
316         return status;
317     }
318 
319     *outTimeMs = timeMS;
320 
321     return ndk::ScopedAStatus::ok();
322 }
323 
getSupportedAlwaysOnEffects(std::vector<Effect> *)324 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> * /*_aidl_return*/) {
325     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
326 }
327 
alwaysOnEnable(int32_t,Effect,EffectStrength)328 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t /*id*/, Effect /*effect*/,
329                                             EffectStrength /*strength*/) {
330     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
331 }
alwaysOnDisable(int32_t)332 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) {
333     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
334 }
335 
getCompositionDelayMax(int32_t *)336 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t * /*maxDelayMs*/) {
337     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
338 }
339 
getCompositionSizeMax(int32_t *)340 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t * /*maxSize*/) {
341     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
342 }
343 
getSupportedPrimitives(std::vector<CompositePrimitive> *)344 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(
345         std::vector<CompositePrimitive> * /*supported*/) {
346     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
347 }
348 
getPrimitiveDuration(CompositePrimitive,int32_t *)349 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive /*primitive*/,
350                                                   int32_t * /*durationMs*/) {
351     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
352 }
353 
compose(const std::vector<CompositeEffect> &,const std::shared_ptr<IVibratorCallback> &)354 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> & /*composite*/,
355                                      const std::shared_ptr<IVibratorCallback> & /*callback*/) {
356     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
357 }
358 
359 }  // namespace vibrator
360 }  // namespace hardware
361 }  // namespace android
362 }  // namespace aidl
363