blob: 01602abffb1693379608e2532112aa1f48799ddc [file] [log] [blame]
Steven Morelandd44007e2019-10-24 18:12:46 -07001/*
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
Steven Moreland8ba8c032019-11-18 16:23:39 -080017#include "vibrator-impl/Vibrator.h"
Steven Morelandd44007e2019-10-24 18:12:46 -070018
19#include <android-base/logging.h>
20#include <thread>
21
22namespace aidl {
23namespace android {
24namespace hardware {
25namespace vibrator {
26
chasewu8af5e842022-03-22 01:42:24 +080027static constexpr int32_t COMPOSE_DELAY_MAX_MS = 1000;
28static constexpr int32_t COMPOSE_SIZE_MAX = 256;
29static constexpr int32_t COMPOSE_PWLE_SIZE_MAX = 127;
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +090030
chasewu8af5e842022-03-22 01:42:24 +080031static constexpr float Q_FACTOR = 11.0;
Vince Leung823cf5f2021-02-11 02:21:57 +000032static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
33static constexpr float PWLE_LEVEL_MIN = 0.0;
chasewu8af5e842022-03-22 01:42:24 +080034static constexpr float PWLE_LEVEL_MAX = 1.0;
Vince Leung823cf5f2021-02-11 02:21:57 +000035static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
36static constexpr float PWLE_FREQUENCY_MIN_HZ = 140.0;
chasewu8af5e842022-03-22 01:42:24 +080037static constexpr float RESONANT_FREQUENCY_HZ = 150.0;
Vince Leung823cf5f2021-02-11 02:21:57 +000038static constexpr float PWLE_FREQUENCY_MAX_HZ = 160.0;
chasewu8af5e842022-03-22 01:42:24 +080039static constexpr float PWLE_BW_MAP_SIZE =
40 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
Vince Leung4bae4f92021-02-03 06:21:58 +000041
Steven Morelandd44007e2019-10-24 18:12:46 -070042ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
chasewu8af5e842022-03-22 01:42:24 +080043 LOG(VERBOSE) << "Vibrator reporting capabilities";
Steven Morelandd44007e2019-10-24 18:12:46 -070044 *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
Steven Morelandc0b92d52019-11-05 13:31:41 -080045 IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +090046 IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
Vince Leung4bae4f92021-02-03 06:21:58 +000047 IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
Vince Leung823cf5f2021-02-11 02:21:57 +000048 IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
49 IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
Steven Morelandd44007e2019-10-24 18:12:46 -070050 return ndk::ScopedAStatus::ok();
51}
52
53ndk::ScopedAStatus Vibrator::off() {
chasewu8af5e842022-03-22 01:42:24 +080054 LOG(VERBOSE) << "Vibrator off";
Steven Morelandd44007e2019-10-24 18:12:46 -070055 return ndk::ScopedAStatus::ok();
56}
57
58ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
59 const std::shared_ptr<IVibratorCallback>& callback) {
chasewu8af5e842022-03-22 01:42:24 +080060 LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
Steven Morelandd44007e2019-10-24 18:12:46 -070061 if (callback != nullptr) {
Simon Bowden608655b2022-06-01 12:09:41 +000062 // 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] {
chasewu8af5e842022-03-22 01:42:24 +080066 LOG(VERBOSE) << "Starting on on another thread";
Steven Morelandd44007e2019-10-24 18:12:46 -070067 usleep(timeoutMs * 1000);
chasewu8af5e842022-03-22 01:42:24 +080068 LOG(VERBOSE) << "Notifying on complete";
Steven Morelandf57ad9b2019-11-27 16:04:52 -080069 if (!callback->onComplete().isOk()) {
70 LOG(ERROR) << "Failed to call onComplete";
71 }
Steven Morelandd44007e2019-10-24 18:12:46 -070072 }).detach();
73 }
74 return ndk::ScopedAStatus::ok();
75}
76
77ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
78 const std::shared_ptr<IVibratorCallback>& callback,
79 int32_t* _aidl_return) {
chasewu8af5e842022-03-22 01:42:24 +080080 LOG(VERBOSE) << "Vibrator perform";
Steven Morelandd44007e2019-10-24 18:12:46 -070081
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) {
Simon Bowden608655b2022-06-01 12:09:41 +000093 std::thread([callback] {
chasewu8af5e842022-03-22 01:42:24 +080094 LOG(VERBOSE) << "Starting perform on another thread";
Steven Morelandd44007e2019-10-24 18:12:46 -070095 usleep(kEffectMillis * 1000);
chasewu8af5e842022-03-22 01:42:24 +080096 LOG(VERBOSE) << "Notifying perform complete";
Steven Morelandd44007e2019-10-24 18:12:46 -070097 callback->onComplete();
98 }).detach();
99 }
100
101 *_aidl_return = kEffectMillis;
102 return ndk::ScopedAStatus::ok();
103}
104
Steven Moreland2932b222019-11-05 14:30:17 -0800105ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
106 *_aidl_return = {Effect::CLICK, Effect::TICK};
107 return ndk::ScopedAStatus::ok();
108}
109
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900110ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
chasewu8af5e842022-03-22 01:42:24 +0800111 LOG(VERBOSE) << "Vibrator set amplitude: " << amplitude;
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900112 if (amplitude <= 0.0f || amplitude > 1.0f) {
Steven Morelandd44007e2019-10-24 18:12:46 -0700113 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
114 }
115 return ndk::ScopedAStatus::ok();
116}
117
118ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
chasewu8af5e842022-03-22 01:42:24 +0800119 LOG(VERBOSE) << "Vibrator set external control: " << enabled;
Steven Morelandd44007e2019-10-24 18:12:46 -0700120 return ndk::ScopedAStatus::ok();
121}
122
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900123ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs) {
chasewu8af5e842022-03-22 01:42:24 +0800124 *maxDelayMs = COMPOSE_DELAY_MAX_MS;
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900125 return ndk::ScopedAStatus::ok();
126}
127
128ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) {
chasewu8af5e842022-03-22 01:42:24 +0800129 *maxSize = COMPOSE_SIZE_MAX;
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900130 return ndk::ScopedAStatus::ok();
131}
132
Harpreet \"Eli\" Sangha523e2962020-01-21 16:15:42 +0900133ndk::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,
Harpreet \"Eli\" Sanghafe5d3982020-01-17 14:46:37 +0900138 CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
Vince Leungdeb46ec2020-12-22 00:03:16 +0000139 CompositePrimitive::LOW_TICK,
Harpreet \"Eli\" Sangha523e2962020-01-21 16:15:42 +0900140 };
141 return ndk::ScopedAStatus::ok();
142}
143
144ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
145 int32_t* durationMs) {
Lais Andrade3c7f0d92021-06-16 10:20:09 +0000146 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 }
Harpreet \"Eli\" Sangha523e2962020-01-21 16:15:42 +0900151 if (primitive != CompositePrimitive::NOOP) {
152 *durationMs = 100;
153 } else {
154 *durationMs = 0;
155 }
156 return ndk::ScopedAStatus::ok();
157}
158
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900159ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
160 const std::shared_ptr<IVibratorCallback>& callback) {
chasewu8af5e842022-03-22 01:42:24 +0800161 if (composite.size() > COMPOSE_SIZE_MAX) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900162 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
163 }
164
Harpreet \"Eli\" Sangha13ef28c2020-01-23 13:22:07 +0900165 std::vector<CompositePrimitive> supported;
166 getSupportedPrimitives(&supported);
167
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900168 for (auto& e : composite) {
chasewu8af5e842022-03-22 01:42:24 +0800169 if (e.delayMs > COMPOSE_DELAY_MAX_MS) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900170 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
171 }
Harpreet \"Eli\" Sangha7aec5022020-03-11 06:00:55 +0900172 if (e.scale < 0.0f || e.scale > 1.0f) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900173 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
174 }
Harpreet \"Eli\" Sangha13ef28c2020-01-23 13:22:07 +0900175 if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900176 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
177 }
178 }
179
Simon Bowden608655b2022-06-01 12:09:41 +0000180 // The thread may theoretically outlive the vibrator, so take a proper reference to it.
181 std::thread([sharedThis = this->ref<Vibrator>(), composite, callback] {
chasewu8af5e842022-03-22 01:42:24 +0800182 LOG(VERBOSE) << "Starting compose on another thread";
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900183
184 for (auto& e : composite) {
185 if (e.delayMs) {
186 usleep(e.delayMs * 1000);
187 }
chasewu8af5e842022-03-22 01:42:24 +0800188 LOG(VERBOSE) << "triggering primitive " << static_cast<int>(e.primitive) << " @ scale "
189 << e.scale;
Harpreet \"Eli\" Sanghab075a6a2020-04-10 15:11:58 +0900190
191 int32_t durationMs;
Simon Bowden608655b2022-06-01 12:09:41 +0000192 sharedThis->getPrimitiveDuration(e.primitive, &durationMs);
Harpreet \"Eli\" Sanghab075a6a2020-04-10 15:11:58 +0900193 usleep(durationMs * 1000);
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900194 }
195
196 if (callback != nullptr) {
chasewu8af5e842022-03-22 01:42:24 +0800197 LOG(VERBOSE) << "Notifying perform complete";
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900198 callback->onComplete();
199 }
200 }).detach();
201
202 return ndk::ScopedAStatus::ok();
203}
204
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +0900205ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) {
206 return getSupportedEffects(_aidl_return);
207}
208
209ndk::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 {
chasewu8af5e842022-03-22 01:42:24 +0800216 LOG(VERBOSE) << "Enabling always-on ID " << id << " with " << toString(effect) << "/"
217 << toString(strength);
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +0900218 return ndk::ScopedAStatus::ok();
219 }
220}
221
222ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
chasewu8af5e842022-03-22 01:42:24 +0800223 LOG(VERBOSE) << "Disabling always-on ID " << id;
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +0900224 return ndk::ScopedAStatus::ok();
225}
226
Vince Leung4bae4f92021-02-03 06:21:58 +0000227ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
chasewu8af5e842022-03-22 01:42:24 +0800228 *resonantFreqHz = RESONANT_FREQUENCY_HZ;
Vince Leung4bae4f92021-02-03 06:21:58 +0000229 return ndk::ScopedAStatus::ok();
230}
231
232ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
chasewu8af5e842022-03-22 01:42:24 +0800233 *qFactor = Q_FACTOR;
Vince Leung4bae4f92021-02-03 06:21:58 +0000234 return ndk::ScopedAStatus::ok();
235}
236
Vince Leung823cf5f2021-02-11 02:21:57 +0000237ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
238 *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
239 return ndk::ScopedAStatus::ok();
240}
241
242ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
243 *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
244 return ndk::ScopedAStatus::ok();
245}
246
247ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
chasewu8af5e842022-03-22 01:42:24 +0800248 // 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 }
Vince Leung823cf5f2021-02-11 02:21:57 +0000268}
269
270ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
271 *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
272 return ndk::ScopedAStatus::ok();
273}
274
275ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
chasewu8af5e842022-03-22 01:42:24 +0800276 *maxSize = COMPOSE_PWLE_SIZE_MAX;
Vince Leung823cf5f2021-02-11 02:21:57 +0000277 return ndk::ScopedAStatus::ok();
278}
279
280ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
281 *supported = {
282 Braking::NONE,
283 Braking::CLAB,
284 };
285 return ndk::ScopedAStatus::ok();
286}
287
288void resetPreviousEndAmplitudeEndFrequency(float &prevEndAmplitude, float &prevEndFrequency) {
289 const float reset = -1.0;
290 prevEndAmplitude = reset;
291 prevEndFrequency = reset;
292}
293
294void incrementIndex(int &index) {
295 index += 1;
296}
297
298void 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
305void 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
313void 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
325ndk::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
Simon Bowden608655b2022-06-01 12:09:41 +0000403 std::thread([totalDuration, callback] {
chasewu8af5e842022-03-22 01:42:24 +0800404 LOG(VERBOSE) << "Starting composePwle on another thread";
Vince Leung823cf5f2021-02-11 02:21:57 +0000405 usleep(totalDuration * 1000);
406 if (callback != nullptr) {
chasewu8af5e842022-03-22 01:42:24 +0800407 LOG(VERBOSE) << "Notifying compose PWLE complete";
Vince Leung823cf5f2021-02-11 02:21:57 +0000408 callback->onComplete();
409 }
410 }).detach();
411
412 return ndk::ScopedAStatus::ok();
413}
414
Steven Morelandd44007e2019-10-24 18:12:46 -0700415} // namespace vibrator
416} // namespace hardware
417} // namespace android
418} // namespace aidl