1 /*
2 * Copyright (C) 2019 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-impl/Vibrator.h"
18
19 #include <android-base/logging.h>
20 #include <thread>
21
22 namespace aidl {
23 namespace android {
24 namespace hardware {
25 namespace vibrator {
26
27 static constexpr int32_t COMPOSE_DELAY_MAX_MS = 1000;
28 static constexpr int32_t COMPOSE_SIZE_MAX = 256;
29 static constexpr int32_t COMPOSE_PWLE_SIZE_MAX = 127;
30
31 static constexpr float Q_FACTOR = 11.0;
32 static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
33 static constexpr float PWLE_LEVEL_MIN = 0.0;
34 static constexpr float PWLE_LEVEL_MAX = 1.0;
35 static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
36 static constexpr float PWLE_FREQUENCY_MIN_HZ = 140.0;
37 static constexpr float RESONANT_FREQUENCY_HZ = 150.0;
38 static constexpr float PWLE_FREQUENCY_MAX_HZ = 160.0;
39 static constexpr float PWLE_BW_MAP_SIZE =
40 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
41
getCapabilities(int32_t * _aidl_return)42 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
43 LOG(VERBOSE) << "Vibrator reporting capabilities";
44 *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
45 IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
46 IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
47 IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
48 IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
49 IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
50 return ndk::ScopedAStatus::ok();
51 }
52
off()53 ndk::ScopedAStatus Vibrator::off() {
54 LOG(VERBOSE) << "Vibrator off";
55 return ndk::ScopedAStatus::ok();
56 }
57
on(int32_t timeoutMs,const std::shared_ptr<IVibratorCallback> & callback)58 ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
59 const std::shared_ptr<IVibratorCallback>& callback) {
60 LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
61 if (callback != nullptr) {
62 // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
63 // which may be asynchronously destructed.
64 // If "this" is needed, use [sharedThis = this->ref<Vibrator>()].
65 std::thread([timeoutMs, callback] {
66 LOG(VERBOSE) << "Starting on on another thread";
67 usleep(timeoutMs * 1000);
68 LOG(VERBOSE) << "Notifying on complete";
69 if (!callback->onComplete().isOk()) {
70 LOG(ERROR) << "Failed to call onComplete";
71 }
72 }).detach();
73 }
74 return ndk::ScopedAStatus::ok();
75 }
76
perform(Effect effect,EffectStrength strength,const std::shared_ptr<IVibratorCallback> & callback,int32_t * _aidl_return)77 ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
78 const std::shared_ptr<IVibratorCallback>& callback,
79 int32_t* _aidl_return) {
80 LOG(VERBOSE) << "Vibrator perform";
81
82 if (effect != Effect::CLICK && effect != Effect::TICK) {
83 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
84 }
85 if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
86 strength != EffectStrength::STRONG) {
87 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
88 }
89
90 constexpr size_t kEffectMillis = 100;
91
92 if (callback != nullptr) {
93 std::thread([callback] {
94 LOG(VERBOSE) << "Starting perform on another thread";
95 usleep(kEffectMillis * 1000);
96 LOG(VERBOSE) << "Notifying perform complete";
97 callback->onComplete();
98 }).detach();
99 }
100
101 *_aidl_return = kEffectMillis;
102 return ndk::ScopedAStatus::ok();
103 }
104
getSupportedEffects(std::vector<Effect> * _aidl_return)105 ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
106 *_aidl_return = {Effect::CLICK, Effect::TICK};
107 return ndk::ScopedAStatus::ok();
108 }
109
setAmplitude(float amplitude)110 ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
111 LOG(VERBOSE) << "Vibrator set amplitude: " << amplitude;
112 if (amplitude <= 0.0f || amplitude > 1.0f) {
113 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
114 }
115 return ndk::ScopedAStatus::ok();
116 }
117
setExternalControl(bool enabled)118 ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
119 LOG(VERBOSE) << "Vibrator set external control: " << enabled;
120 return ndk::ScopedAStatus::ok();
121 }
122
getCompositionDelayMax(int32_t * maxDelayMs)123 ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs) {
124 *maxDelayMs = COMPOSE_DELAY_MAX_MS;
125 return ndk::ScopedAStatus::ok();
126 }
127
getCompositionSizeMax(int32_t * maxSize)128 ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) {
129 *maxSize = COMPOSE_SIZE_MAX;
130 return ndk::ScopedAStatus::ok();
131 }
132
getSupportedPrimitives(std::vector<CompositePrimitive> * supported)133 ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) {
134 *supported = {
135 CompositePrimitive::NOOP, CompositePrimitive::CLICK,
136 CompositePrimitive::THUD, CompositePrimitive::SPIN,
137 CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
138 CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
139 CompositePrimitive::LOW_TICK,
140 };
141 return ndk::ScopedAStatus::ok();
142 }
143
getPrimitiveDuration(CompositePrimitive primitive,int32_t * durationMs)144 ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
145 int32_t* durationMs) {
146 std::vector<CompositePrimitive> supported;
147 getSupportedPrimitives(&supported);
148 if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
149 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
150 }
151 if (primitive != CompositePrimitive::NOOP) {
152 *durationMs = 100;
153 } else {
154 *durationMs = 0;
155 }
156 return ndk::ScopedAStatus::ok();
157 }
158
compose(const std::vector<CompositeEffect> & composite,const std::shared_ptr<IVibratorCallback> & callback)159 ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
160 const std::shared_ptr<IVibratorCallback>& callback) {
161 if (composite.size() > COMPOSE_SIZE_MAX) {
162 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
163 }
164
165 std::vector<CompositePrimitive> supported;
166 getSupportedPrimitives(&supported);
167
168 for (auto& e : composite) {
169 if (e.delayMs > COMPOSE_DELAY_MAX_MS) {
170 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
171 }
172 if (e.scale < 0.0f || e.scale > 1.0f) {
173 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
174 }
175 if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
176 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
177 }
178 }
179
180 // The thread may theoretically outlive the vibrator, so take a proper reference to it.
181 std::thread([sharedThis = this->ref<Vibrator>(), composite, callback] {
182 LOG(VERBOSE) << "Starting compose on another thread";
183
184 for (auto& e : composite) {
185 if (e.delayMs) {
186 usleep(e.delayMs * 1000);
187 }
188 LOG(VERBOSE) << "triggering primitive " << static_cast<int>(e.primitive) << " @ scale "
189 << e.scale;
190
191 int32_t durationMs;
192 sharedThis->getPrimitiveDuration(e.primitive, &durationMs);
193 usleep(durationMs * 1000);
194 }
195
196 if (callback != nullptr) {
197 LOG(VERBOSE) << "Notifying perform complete";
198 callback->onComplete();
199 }
200 }).detach();
201
202 return ndk::ScopedAStatus::ok();
203 }
204
getSupportedAlwaysOnEffects(std::vector<Effect> * _aidl_return)205 ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) {
206 return getSupportedEffects(_aidl_return);
207 }
208
alwaysOnEnable(int32_t id,Effect effect,EffectStrength strength)209 ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
210 std::vector<Effect> effects;
211 getSupportedAlwaysOnEffects(&effects);
212
213 if (std::find(effects.begin(), effects.end(), effect) == effects.end()) {
214 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
215 } else {
216 LOG(VERBOSE) << "Enabling always-on ID " << id << " with " << toString(effect) << "/"
217 << toString(strength);
218 return ndk::ScopedAStatus::ok();
219 }
220 }
221
alwaysOnDisable(int32_t id)222 ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
223 LOG(VERBOSE) << "Disabling always-on ID " << id;
224 return ndk::ScopedAStatus::ok();
225 }
226
getResonantFrequency(float * resonantFreqHz)227 ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
228 *resonantFreqHz = RESONANT_FREQUENCY_HZ;
229 return ndk::ScopedAStatus::ok();
230 }
231
getQFactor(float * qFactor)232 ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
233 *qFactor = Q_FACTOR;
234 return ndk::ScopedAStatus::ok();
235 }
236
getFrequencyResolution(float * freqResolutionHz)237 ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
238 *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
239 return ndk::ScopedAStatus::ok();
240 }
241
getFrequencyMinimum(float * freqMinimumHz)242 ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
243 *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
244 return ndk::ScopedAStatus::ok();
245 }
246
getBandwidthAmplitudeMap(std::vector<float> * _aidl_return)247 ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
248 // The output BandwidthAmplitudeMap will be as below and the maximum
249 // amplitude 1.0 will be set on RESONANT_FREQUENCY_HZ
250 // {0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1, 0.99, 0.98, 0.97,
251 // 0.96, 0.95, 0.94, 0.93, 0.92, 0.91, 0.9}
252 int32_t capabilities = 0;
253 int halfMapSize = PWLE_BW_MAP_SIZE / 2;
254 Vibrator::getCapabilities(&capabilities);
255 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
256 std::vector<float> bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, PWLE_LEVEL_MAX);
257 for (int i = 0; i < halfMapSize; ++i) {
258 bandwidthAmplitudeMap[halfMapSize + i + 1] =
259 bandwidthAmplitudeMap[halfMapSize + i] - 0.01;
260 bandwidthAmplitudeMap[halfMapSize - i - 1] =
261 bandwidthAmplitudeMap[halfMapSize - i] - 0.01;
262 }
263 *_aidl_return = bandwidthAmplitudeMap;
264 return ndk::ScopedAStatus::ok();
265 } else {
266 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
267 }
268 }
269
getPwlePrimitiveDurationMax(int32_t * durationMs)270 ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
271 *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
272 return ndk::ScopedAStatus::ok();
273 }
274
getPwleCompositionSizeMax(int32_t * maxSize)275 ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
276 *maxSize = COMPOSE_PWLE_SIZE_MAX;
277 return ndk::ScopedAStatus::ok();
278 }
279
getSupportedBraking(std::vector<Braking> * supported)280 ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
281 *supported = {
282 Braking::NONE,
283 Braking::CLAB,
284 };
285 return ndk::ScopedAStatus::ok();
286 }
287
resetPreviousEndAmplitudeEndFrequency(float & prevEndAmplitude,float & prevEndFrequency)288 void resetPreviousEndAmplitudeEndFrequency(float &prevEndAmplitude, float &prevEndFrequency) {
289 const float reset = -1.0;
290 prevEndAmplitude = reset;
291 prevEndFrequency = reset;
292 }
293
incrementIndex(int & index)294 void incrementIndex(int &index) {
295 index += 1;
296 }
297
constructActiveDefaults(std::ostringstream & pwleBuilder,const int & segmentIdx)298 void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
299 pwleBuilder << ",C" << segmentIdx << ":1";
300 pwleBuilder << ",B" << segmentIdx << ":0";
301 pwleBuilder << ",AR" << segmentIdx << ":0";
302 pwleBuilder << ",V" << segmentIdx << ":0";
303 }
304
constructActiveSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,float amplitude,float frequency)305 void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
306 float amplitude, float frequency) {
307 pwleBuilder << ",T" << segmentIdx << ":" << duration;
308 pwleBuilder << ",L" << segmentIdx << ":" << amplitude;
309 pwleBuilder << ",F" << segmentIdx << ":" << frequency;
310 constructActiveDefaults(pwleBuilder, segmentIdx);
311 }
312
constructBrakingSegment(std::ostringstream & pwleBuilder,const int & segmentIdx,int duration,Braking brakingType)313 void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
314 Braking brakingType) {
315 pwleBuilder << ",T" << segmentIdx << ":" << duration;
316 pwleBuilder << ",L" << segmentIdx << ":" << 0;
317 pwleBuilder << ",F" << segmentIdx << ":" << 0;
318 pwleBuilder << ",C" << segmentIdx << ":0";
319 pwleBuilder << ",B" << segmentIdx << ":"
320 << static_cast<std::underlying_type<Braking>::type>(brakingType);
321 pwleBuilder << ",AR" << segmentIdx << ":0";
322 pwleBuilder << ",V" << segmentIdx << ":0";
323 }
324
composePwle(const std::vector<PrimitivePwle> & composite,const std::shared_ptr<IVibratorCallback> & callback)325 ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
326 const std::shared_ptr<IVibratorCallback> &callback) {
327 std::ostringstream pwleBuilder;
328 std::string pwleQueue;
329
330 int compositionSizeMax;
331 getPwleCompositionSizeMax(&compositionSizeMax);
332 if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
333 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
334 }
335
336 float prevEndAmplitude;
337 float prevEndFrequency;
338 resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
339
340 int segmentIdx = 0;
341 uint32_t totalDuration = 0;
342
343 pwleBuilder << "S:0,WF:4,RP:0,WT:0";
344
345 for (auto &e : composite) {
346 switch (e.getTag()) {
347 case PrimitivePwle::active: {
348 auto active = e.get<PrimitivePwle::active>();
349 if (active.duration < 0 ||
350 active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
351 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
352 }
353 if (active.startAmplitude < PWLE_LEVEL_MIN ||
354 active.startAmplitude > PWLE_LEVEL_MAX ||
355 active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
356 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
357 }
358 if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
359 active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
360 active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
361 active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
362 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
363 }
364
365 if (!((active.startAmplitude == prevEndAmplitude) &&
366 (active.startFrequency == prevEndFrequency))) {
367 constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
368 active.startFrequency);
369 incrementIndex(segmentIdx);
370 }
371
372 constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
373 active.endAmplitude, active.endFrequency);
374 incrementIndex(segmentIdx);
375
376 prevEndAmplitude = active.endAmplitude;
377 prevEndFrequency = active.endFrequency;
378 totalDuration += active.duration;
379 break;
380 }
381 case PrimitivePwle::braking: {
382 auto braking = e.get<PrimitivePwle::braking>();
383 if (braking.braking > Braking::CLAB) {
384 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
385 }
386 if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
387 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
388 }
389
390 constructBrakingSegment(pwleBuilder, segmentIdx, 0, braking.braking);
391 incrementIndex(segmentIdx);
392
393 constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking);
394 incrementIndex(segmentIdx);
395
396 resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
397 totalDuration += braking.duration;
398 break;
399 }
400 }
401 }
402
403 std::thread([totalDuration, callback] {
404 LOG(VERBOSE) << "Starting composePwle on another thread";
405 usleep(totalDuration * 1000);
406 if (callback != nullptr) {
407 LOG(VERBOSE) << "Notifying compose PWLE complete";
408 callback->onComplete();
409 }
410 }).detach();
411
412 return ndk::ScopedAStatus::ok();
413 }
414
415 } // namespace vibrator
416 } // namespace hardware
417 } // namespace android
418 } // namespace aidl
419