blob: 29e7d1830e7eac2d46c73811f026bc6d4f3e20da [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
Lais Andradea3c332f2024-06-20 10:46:06 +010042// Service specific error code used for vendor vibration effects.
43static constexpr int32_t ERROR_CODE_INVALID_DURATION = 1;
44
Steven Morelandd44007e2019-10-24 18:12:46 -070045ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
chasewu8af5e842022-03-22 01:42:24 +080046 LOG(VERBOSE) << "Vibrator reporting capabilities";
Steven Morelandd44007e2019-10-24 18:12:46 -070047 *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
Steven Morelandc0b92d52019-11-05 13:31:41 -080048 IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +090049 IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
Vince Leung4bae4f92021-02-03 06:21:58 +000050 IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
Vince Leung823cf5f2021-02-11 02:21:57 +000051 IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
Lais Andradea3c332f2024-06-20 10:46:06 +010052 IVibrator::CAP_COMPOSE_PWLE_EFFECTS | IVibrator::CAP_PERFORM_VENDOR_EFFECTS;
Steven Morelandd44007e2019-10-24 18:12:46 -070053 return ndk::ScopedAStatus::ok();
54}
55
56ndk::ScopedAStatus Vibrator::off() {
chasewu8af5e842022-03-22 01:42:24 +080057 LOG(VERBOSE) << "Vibrator off";
Steven Morelandd44007e2019-10-24 18:12:46 -070058 return ndk::ScopedAStatus::ok();
59}
60
61ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
62 const std::shared_ptr<IVibratorCallback>& callback) {
chasewu8af5e842022-03-22 01:42:24 +080063 LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
Steven Morelandd44007e2019-10-24 18:12:46 -070064 if (callback != nullptr) {
Simon Bowden608655b2022-06-01 12:09:41 +000065 // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
66 // which may be asynchronously destructed.
67 // If "this" is needed, use [sharedThis = this->ref<Vibrator>()].
68 std::thread([timeoutMs, callback] {
chasewu8af5e842022-03-22 01:42:24 +080069 LOG(VERBOSE) << "Starting on on another thread";
Steven Morelandd44007e2019-10-24 18:12:46 -070070 usleep(timeoutMs * 1000);
chasewu8af5e842022-03-22 01:42:24 +080071 LOG(VERBOSE) << "Notifying on complete";
Steven Morelandf57ad9b2019-11-27 16:04:52 -080072 if (!callback->onComplete().isOk()) {
73 LOG(ERROR) << "Failed to call onComplete";
74 }
Steven Morelandd44007e2019-10-24 18:12:46 -070075 }).detach();
76 }
77 return ndk::ScopedAStatus::ok();
78}
79
80ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
81 const std::shared_ptr<IVibratorCallback>& callback,
82 int32_t* _aidl_return) {
chasewu8af5e842022-03-22 01:42:24 +080083 LOG(VERBOSE) << "Vibrator perform";
Steven Morelandd44007e2019-10-24 18:12:46 -070084
85 if (effect != Effect::CLICK && effect != Effect::TICK) {
86 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
87 }
88 if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
89 strength != EffectStrength::STRONG) {
90 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
91 }
92
93 constexpr size_t kEffectMillis = 100;
94
95 if (callback != nullptr) {
Simon Bowden608655b2022-06-01 12:09:41 +000096 std::thread([callback] {
chasewu8af5e842022-03-22 01:42:24 +080097 LOG(VERBOSE) << "Starting perform on another thread";
Steven Morelandd44007e2019-10-24 18:12:46 -070098 usleep(kEffectMillis * 1000);
chasewu8af5e842022-03-22 01:42:24 +080099 LOG(VERBOSE) << "Notifying perform complete";
Steven Morelandd44007e2019-10-24 18:12:46 -0700100 callback->onComplete();
101 }).detach();
102 }
103
104 *_aidl_return = kEffectMillis;
105 return ndk::ScopedAStatus::ok();
106}
107
Lais Andradea3c332f2024-06-20 10:46:06 +0100108ndk::ScopedAStatus Vibrator::performVendorEffect(
109 const VendorEffect& effect, const std::shared_ptr<IVibratorCallback>& callback) {
110 LOG(VERBOSE) << "Vibrator perform vendor effect";
111 EffectStrength strength = effect.strength;
112 if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
113 strength != EffectStrength::STRONG) {
114 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
115 }
116 float scale = effect.scale;
117 if (scale <= 0) {
118 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
119 }
Lais Andrade4526faf2024-08-09 11:57:20 +0100120 float vendorScale = effect.vendorScale;
121 if (vendorScale <= 0) {
122 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
123 }
Lais Andradea3c332f2024-06-20 10:46:06 +0100124
125 int32_t durationMs = 0;
126 if (!effect.vendorData.getInt("DURATION_MS", &durationMs) || durationMs <= 0) {
127 return ndk::ScopedAStatus::fromServiceSpecificError(ERROR_CODE_INVALID_DURATION);
128 }
129
130 if (callback != nullptr) {
131 std::thread([callback, durationMs] {
132 LOG(VERBOSE) << "Starting perform on another thread for durationMs:" << durationMs;
133 usleep(durationMs * 1000);
134 LOG(VERBOSE) << "Notifying perform vendor effect complete";
135 callback->onComplete();
136 }).detach();
137 }
138
139 return ndk::ScopedAStatus::ok();
140}
141
Steven Moreland2932b222019-11-05 14:30:17 -0800142ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
143 *_aidl_return = {Effect::CLICK, Effect::TICK};
144 return ndk::ScopedAStatus::ok();
145}
146
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900147ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
chasewu8af5e842022-03-22 01:42:24 +0800148 LOG(VERBOSE) << "Vibrator set amplitude: " << amplitude;
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900149 if (amplitude <= 0.0f || amplitude > 1.0f) {
Steven Morelandd44007e2019-10-24 18:12:46 -0700150 return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
151 }
152 return ndk::ScopedAStatus::ok();
153}
154
155ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
chasewu8af5e842022-03-22 01:42:24 +0800156 LOG(VERBOSE) << "Vibrator set external control: " << enabled;
Steven Morelandd44007e2019-10-24 18:12:46 -0700157 return ndk::ScopedAStatus::ok();
158}
159
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900160ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs) {
chasewu8af5e842022-03-22 01:42:24 +0800161 *maxDelayMs = COMPOSE_DELAY_MAX_MS;
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900162 return ndk::ScopedAStatus::ok();
163}
164
165ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) {
chasewu8af5e842022-03-22 01:42:24 +0800166 *maxSize = COMPOSE_SIZE_MAX;
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900167 return ndk::ScopedAStatus::ok();
168}
169
Harpreet \"Eli\" Sangha523e2962020-01-21 16:15:42 +0900170ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) {
171 *supported = {
172 CompositePrimitive::NOOP, CompositePrimitive::CLICK,
173 CompositePrimitive::THUD, CompositePrimitive::SPIN,
174 CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
Harpreet \"Eli\" Sanghafe5d3982020-01-17 14:46:37 +0900175 CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
Vince Leungdeb46ec2020-12-22 00:03:16 +0000176 CompositePrimitive::LOW_TICK,
Harpreet \"Eli\" Sangha523e2962020-01-21 16:15:42 +0900177 };
178 return ndk::ScopedAStatus::ok();
179}
180
181ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
182 int32_t* durationMs) {
Lais Andrade3c7f0d92021-06-16 10:20:09 +0000183 std::vector<CompositePrimitive> supported;
184 getSupportedPrimitives(&supported);
185 if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
186 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
187 }
Harpreet \"Eli\" Sangha523e2962020-01-21 16:15:42 +0900188 if (primitive != CompositePrimitive::NOOP) {
189 *durationMs = 100;
190 } else {
191 *durationMs = 0;
192 }
193 return ndk::ScopedAStatus::ok();
194}
195
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900196ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
197 const std::shared_ptr<IVibratorCallback>& callback) {
chasewu8af5e842022-03-22 01:42:24 +0800198 if (composite.size() > COMPOSE_SIZE_MAX) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900199 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
200 }
201
Harpreet \"Eli\" Sangha13ef28c2020-01-23 13:22:07 +0900202 std::vector<CompositePrimitive> supported;
203 getSupportedPrimitives(&supported);
204
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900205 for (auto& e : composite) {
chasewu8af5e842022-03-22 01:42:24 +0800206 if (e.delayMs > COMPOSE_DELAY_MAX_MS) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900207 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
208 }
Harpreet \"Eli\" Sangha7aec5022020-03-11 06:00:55 +0900209 if (e.scale < 0.0f || e.scale > 1.0f) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900210 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
211 }
Harpreet \"Eli\" Sangha13ef28c2020-01-23 13:22:07 +0900212 if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900213 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
214 }
215 }
216
Simon Bowden608655b2022-06-01 12:09:41 +0000217 // The thread may theoretically outlive the vibrator, so take a proper reference to it.
218 std::thread([sharedThis = this->ref<Vibrator>(), composite, callback] {
chasewu8af5e842022-03-22 01:42:24 +0800219 LOG(VERBOSE) << "Starting compose on another thread";
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900220
221 for (auto& e : composite) {
222 if (e.delayMs) {
223 usleep(e.delayMs * 1000);
224 }
chasewu8af5e842022-03-22 01:42:24 +0800225 LOG(VERBOSE) << "triggering primitive " << static_cast<int>(e.primitive) << " @ scale "
226 << e.scale;
Harpreet \"Eli\" Sanghab075a6a2020-04-10 15:11:58 +0900227
228 int32_t durationMs;
Simon Bowden608655b2022-06-01 12:09:41 +0000229 sharedThis->getPrimitiveDuration(e.primitive, &durationMs);
Harpreet \"Eli\" Sanghab075a6a2020-04-10 15:11:58 +0900230 usleep(durationMs * 1000);
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900231 }
232
233 if (callback != nullptr) {
chasewu8af5e842022-03-22 01:42:24 +0800234 LOG(VERBOSE) << "Notifying perform complete";
Harpreet \"Eli\" Sanghaf4de5b02019-10-23 09:25:52 +0900235 callback->onComplete();
236 }
237 }).detach();
238
239 return ndk::ScopedAStatus::ok();
240}
241
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +0900242ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) {
243 return getSupportedEffects(_aidl_return);
244}
245
246ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
247 std::vector<Effect> effects;
248 getSupportedAlwaysOnEffects(&effects);
249
250 if (std::find(effects.begin(), effects.end(), effect) == effects.end()) {
251 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
252 } else {
chasewu8af5e842022-03-22 01:42:24 +0800253 LOG(VERBOSE) << "Enabling always-on ID " << id << " with " << toString(effect) << "/"
254 << toString(strength);
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +0900255 return ndk::ScopedAStatus::ok();
256 }
257}
258
259ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
chasewu8af5e842022-03-22 01:42:24 +0800260 LOG(VERBOSE) << "Disabling always-on ID " << id;
Harpreet \"Eli\" Sangha63624092019-09-09 11:04:54 +0900261 return ndk::ScopedAStatus::ok();
262}
263
Vince Leung4bae4f92021-02-03 06:21:58 +0000264ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) {
chasewu8af5e842022-03-22 01:42:24 +0800265 *resonantFreqHz = RESONANT_FREQUENCY_HZ;
Vince Leung4bae4f92021-02-03 06:21:58 +0000266 return ndk::ScopedAStatus::ok();
267}
268
269ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) {
chasewu8af5e842022-03-22 01:42:24 +0800270 *qFactor = Q_FACTOR;
Vince Leung4bae4f92021-02-03 06:21:58 +0000271 return ndk::ScopedAStatus::ok();
272}
273
Vince Leung823cf5f2021-02-11 02:21:57 +0000274ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
275 *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
276 return ndk::ScopedAStatus::ok();
277}
278
279ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
280 *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
281 return ndk::ScopedAStatus::ok();
282}
283
284ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
chasewu8af5e842022-03-22 01:42:24 +0800285 // The output BandwidthAmplitudeMap will be as below and the maximum
286 // amplitude 1.0 will be set on RESONANT_FREQUENCY_HZ
287 // {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,
288 // 0.96, 0.95, 0.94, 0.93, 0.92, 0.91, 0.9}
289 int32_t capabilities = 0;
290 int halfMapSize = PWLE_BW_MAP_SIZE / 2;
291 Vibrator::getCapabilities(&capabilities);
292 if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
293 std::vector<float> bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, PWLE_LEVEL_MAX);
294 for (int i = 0; i < halfMapSize; ++i) {
295 bandwidthAmplitudeMap[halfMapSize + i + 1] =
296 bandwidthAmplitudeMap[halfMapSize + i] - 0.01;
297 bandwidthAmplitudeMap[halfMapSize - i - 1] =
298 bandwidthAmplitudeMap[halfMapSize - i] - 0.01;
299 }
300 *_aidl_return = bandwidthAmplitudeMap;
301 return ndk::ScopedAStatus::ok();
302 } else {
303 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
304 }
Vince Leung823cf5f2021-02-11 02:21:57 +0000305}
306
307ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
308 *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
309 return ndk::ScopedAStatus::ok();
310}
311
312ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
chasewu8af5e842022-03-22 01:42:24 +0800313 *maxSize = COMPOSE_PWLE_SIZE_MAX;
Vince Leung823cf5f2021-02-11 02:21:57 +0000314 return ndk::ScopedAStatus::ok();
315}
316
317ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
318 *supported = {
319 Braking::NONE,
320 Braking::CLAB,
321 };
322 return ndk::ScopedAStatus::ok();
323}
324
325void resetPreviousEndAmplitudeEndFrequency(float &prevEndAmplitude, float &prevEndFrequency) {
326 const float reset = -1.0;
327 prevEndAmplitude = reset;
328 prevEndFrequency = reset;
329}
330
331void incrementIndex(int &index) {
332 index += 1;
333}
334
335void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
336 pwleBuilder << ",C" << segmentIdx << ":1";
337 pwleBuilder << ",B" << segmentIdx << ":0";
338 pwleBuilder << ",AR" << segmentIdx << ":0";
339 pwleBuilder << ",V" << segmentIdx << ":0";
340}
341
342void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
343 float amplitude, float frequency) {
344 pwleBuilder << ",T" << segmentIdx << ":" << duration;
345 pwleBuilder << ",L" << segmentIdx << ":" << amplitude;
346 pwleBuilder << ",F" << segmentIdx << ":" << frequency;
347 constructActiveDefaults(pwleBuilder, segmentIdx);
348}
349
350void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
351 Braking brakingType) {
352 pwleBuilder << ",T" << segmentIdx << ":" << duration;
353 pwleBuilder << ",L" << segmentIdx << ":" << 0;
354 pwleBuilder << ",F" << segmentIdx << ":" << 0;
355 pwleBuilder << ",C" << segmentIdx << ":0";
356 pwleBuilder << ",B" << segmentIdx << ":"
357 << static_cast<std::underlying_type<Braking>::type>(brakingType);
358 pwleBuilder << ",AR" << segmentIdx << ":0";
359 pwleBuilder << ",V" << segmentIdx << ":0";
360}
361
362ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
363 const std::shared_ptr<IVibratorCallback> &callback) {
364 std::ostringstream pwleBuilder;
365 std::string pwleQueue;
366
367 int compositionSizeMax;
368 getPwleCompositionSizeMax(&compositionSizeMax);
369 if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
370 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
371 }
372
373 float prevEndAmplitude;
374 float prevEndFrequency;
375 resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
376
377 int segmentIdx = 0;
378 uint32_t totalDuration = 0;
379
380 pwleBuilder << "S:0,WF:4,RP:0,WT:0";
381
382 for (auto &e : composite) {
383 switch (e.getTag()) {
384 case PrimitivePwle::active: {
385 auto active = e.get<PrimitivePwle::active>();
386 if (active.duration < 0 ||
387 active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
388 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
389 }
390 if (active.startAmplitude < PWLE_LEVEL_MIN ||
391 active.startAmplitude > PWLE_LEVEL_MAX ||
392 active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
393 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
394 }
395 if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
396 active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
397 active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
398 active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
399 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
400 }
401
402 if (!((active.startAmplitude == prevEndAmplitude) &&
403 (active.startFrequency == prevEndFrequency))) {
404 constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
405 active.startFrequency);
406 incrementIndex(segmentIdx);
407 }
408
409 constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
410 active.endAmplitude, active.endFrequency);
411 incrementIndex(segmentIdx);
412
413 prevEndAmplitude = active.endAmplitude;
414 prevEndFrequency = active.endFrequency;
415 totalDuration += active.duration;
416 break;
417 }
418 case PrimitivePwle::braking: {
419 auto braking = e.get<PrimitivePwle::braking>();
420 if (braking.braking > Braking::CLAB) {
421 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
422 }
423 if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
424 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
425 }
426
427 constructBrakingSegment(pwleBuilder, segmentIdx, 0, braking.braking);
428 incrementIndex(segmentIdx);
429
430 constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking);
431 incrementIndex(segmentIdx);
432
433 resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
434 totalDuration += braking.duration;
435 break;
436 }
437 }
438 }
439
Simon Bowden608655b2022-06-01 12:09:41 +0000440 std::thread([totalDuration, callback] {
chasewu8af5e842022-03-22 01:42:24 +0800441 LOG(VERBOSE) << "Starting composePwle on another thread";
Vince Leung823cf5f2021-02-11 02:21:57 +0000442 usleep(totalDuration * 1000);
443 if (callback != nullptr) {
chasewu8af5e842022-03-22 01:42:24 +0800444 LOG(VERBOSE) << "Notifying compose PWLE complete";
Vince Leung823cf5f2021-02-11 02:21:57 +0000445 callback->onComplete();
446 }
447 }).detach();
448
449 return ndk::ScopedAStatus::ok();
450}
451
Steven Morelandd44007e2019-10-24 18:12:46 -0700452} // namespace vibrator
453} // namespace hardware
454} // namespace android
455} // namespace aidl