1 /*
2 * Copyright (C) 2024 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 #ifndef VIBRATOR_HAL_PWLE_V2_UTILS_H
18 #define VIBRATOR_HAL_PWLE_V2_UTILS_H
19
20 #include <aidl/android/hardware/vibrator/IVibrator.h>
21 #include "test_utils.h"
22
23 using aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
24 using aidl::android::hardware::vibrator::IVibrator;
25 using aidl::android::hardware::vibrator::PwleV2Primitive;
26
27 namespace aidl {
28 namespace android {
29 namespace hardware {
30 namespace vibrator {
31 namespace testing {
32 namespace pwlev2 {
33
34 static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE = 16;
35 static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000;
36 static constexpr int32_t COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20;
37 static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL = 10;
38
39 namespace {
40 /**
41 * Returns a vector of (frequency in Hz, acceleration in dB) pairs, where the acceleration
42 * value denotes the minimum output required at the corresponding frequency to be perceptible
43 * by a human.
44 */
getMinPerceptibleLevel()45 static std::vector<std::pair<float, float>> getMinPerceptibleLevel() {
46 return {{0.4f, -97.81f}, {2.0f, -69.86f}, {3.0f, -62.81f}, {4.0f, -58.81f},
47 {5.0f, -56.69f}, {6.0f, -54.77f}, {7.2f, -52.85f}, {8.0f, -51.77f},
48 {8.64f, -50.84f}, {10.0f, -48.90f}, {10.37f, -48.52f}, {12.44f, -46.50f},
49 {14.93f, -44.43f}, {15.0f, -44.35f}, {17.92f, -41.96f}, {20.0f, -40.36f},
50 {21.5f, -39.60f}, {25.0f, -37.48f}, {25.8f, -36.93f}, {30.0f, -34.31f},
51 {35.0f, -33.13f}, {40.0f, -32.81f}, {50.0f, -31.94f}, {60.0f, -31.77f},
52 {70.0f, -31.59f}, {72.0f, -31.55f}, {80.0f, -31.77f}, {86.4f, -31.94f},
53 {90.0f, -31.73f}, {100.0f, -31.90f}, {103.68f, -31.77f}, {124.42f, -31.70f},
54 {149.3f, -31.38f}, {150.0f, -31.35f}, {179.16f, -31.02f}, {200.0f, -30.86f},
55 {215.0f, -30.35f}, {250.0f, -28.98f}, {258.0f, -28.68f}, {300.0f, -26.81f},
56 {400.0f, -19.81f}};
57 }
58
interpolateLinearly(const std::vector<float> & xAxis,const std::vector<float> & yAxis,float x)59 static float interpolateLinearly(const std::vector<float>& xAxis, const std::vector<float>& yAxis,
60 float x) {
61 EXPECT_TRUE(!xAxis.empty());
62 EXPECT_TRUE(xAxis.size() == yAxis.size());
63
64 if (x <= xAxis.front()) return yAxis.front();
65 if (x >= xAxis.back()) return yAxis.back();
66
67 auto it = std::upper_bound(xAxis.begin(), xAxis.end(), x);
68 int i = std::distance(xAxis.begin(), it) - 1; // Index of the lower bound
69
70 const float& x0 = xAxis[i];
71 const float& y0 = yAxis[i];
72 const float& x1 = xAxis[i + 1];
73 const float& y1 = yAxis[i + 1];
74
75 return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
76 }
77
minPerceptibleDbCurve(float frequency)78 static float minPerceptibleDbCurve(float frequency) {
79 // Initialize minPerceptibleMap only once
80 static auto minPerceptibleMap = []() -> std::function<float(float)> {
81 static std::vector<float> minPerceptibleFrequencies;
82 static std::vector<float> minPerceptibleAccelerations;
83
84 auto minPerceptibleLevel = getMinPerceptibleLevel();
85 // Sort the 'minPerceptibleLevel' data in ascending order based on the
86 // frequency values (first element of each pair).
87 std::sort(minPerceptibleLevel.begin(), minPerceptibleLevel.end(),
88 [](const auto& a, const auto& b) { return a.first < b.first; });
89
90 for (const auto& entry : minPerceptibleLevel) {
91 minPerceptibleFrequencies.push_back(entry.first);
92 minPerceptibleAccelerations.push_back(entry.second);
93 }
94
95 return [&](float freq) {
96 return interpolateLinearly(minPerceptibleFrequencies, minPerceptibleAccelerations,
97 freq);
98 };
99 }();
100
101 return minPerceptibleMap(frequency);
102 }
103
convertSensitivityLevelToDecibel(int sl,float frequency)104 static float convertSensitivityLevelToDecibel(int sl, float frequency) {
105 return sl + minPerceptibleDbCurve(frequency);
106 }
107
convertDecibelToAcceleration(float db)108 static float convertDecibelToAcceleration(float db) {
109 return std::pow(10.0f, db / 20.0f);
110 }
111 } // namespace
112
convertSensitivityLevelToAcceleration(int sl,float frequency)113 static float convertSensitivityLevelToAcceleration(int sl, float frequency) {
114 return pwlev2::convertDecibelToAcceleration(
115 pwlev2::convertSensitivityLevelToDecibel(sl, frequency));
116 }
117
getPwleV2FrequencyMinHz(const std::shared_ptr<IVibrator> & vibrator)118 static float getPwleV2FrequencyMinHz(const std::shared_ptr<IVibrator>& vibrator) {
119 std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
120 EXPECT_OK(vibrator->getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
121 EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
122 // We can't use ASSERT_TRUE() above because this is a non-void function,
123 // but we need to return to assure we don't crash from a null dereference.
124 if (frequencyToOutputAccelerationMap.empty()) {
125 return std::numeric_limits<float>::quiet_NaN();
126 }
127
128 auto entry = std::min_element(
129 frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
130 [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
131
132 return entry->frequencyHz;
133 }
134
getPwleV2FrequencyMaxHz(const std::shared_ptr<IVibrator> & vibrator)135 static float getPwleV2FrequencyMaxHz(const std::shared_ptr<IVibrator>& vibrator) {
136 std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
137 EXPECT_OK(vibrator->getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
138 EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
139 // We can't use ASSERT_TRUE() above because this is a non-void function,
140 // but we need to return to assure we don't crash from a null dereference.
141 if (frequencyToOutputAccelerationMap.empty()) {
142 return std::numeric_limits<float>::quiet_NaN();
143 }
144
145 auto entry = std::max_element(
146 frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
147 [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
148
149 return entry->frequencyHz;
150 }
151
composeValidPwleV2Effect(const std::shared_ptr<IVibrator> & vibrator)152 static CompositePwleV2 composeValidPwleV2Effect(const std::shared_ptr<IVibrator>& vibrator) {
153 int32_t minDurationMs;
154 EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
155 int32_t maxDurationMs;
156 EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs));
157 float minFrequency = getPwleV2FrequencyMinHz(vibrator);
158 float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
159 int32_t maxCompositionSize;
160 EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
161
162 CompositePwleV2 composite;
163
164 composite.pwlePrimitives.emplace_back(0.1f, minFrequency, minDurationMs);
165 composite.pwlePrimitives.emplace_back(0.5f, maxFrequency, maxDurationMs);
166
167 float variedFrequency = (minFrequency + maxFrequency) / 2.0f;
168 for (int i = 0; i < maxCompositionSize - 2; i++) {
169 composite.pwlePrimitives.emplace_back(0.7f, variedFrequency, minDurationMs);
170 }
171
172 return composite;
173 }
174
composePwleV2EffectWithTooManyPoints(const std::shared_ptr<IVibrator> & vibrator)175 static CompositePwleV2 composePwleV2EffectWithTooManyPoints(
176 const std::shared_ptr<IVibrator>& vibrator) {
177 int32_t minDurationMs, maxCompositionSize;
178 EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
179 EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
180 float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
181
182 std::vector<PwleV2Primitive> pwleEffect(maxCompositionSize + 1); // +1 to exceed the limit
183
184 std::fill(pwleEffect.begin(), pwleEffect.end(),
185 PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency, minDurationMs));
186
187 CompositePwleV2 composite;
188 composite.pwlePrimitives = pwleEffect;
189
190 return composite;
191 }
192
getPwleV2SharpnessRange(const std::shared_ptr<IVibrator> & vibrator,std::vector<FrequencyAccelerationMapEntry> freqToOutputAccelerationMap)193 static std::pair<float, float> getPwleV2SharpnessRange(
194 const std::shared_ptr<IVibrator>& vibrator,
195 std::vector<FrequencyAccelerationMapEntry> freqToOutputAccelerationMap) {
196 std::pair<float, float> sharpnessRange = {-1, -1};
197
198 // Sort the entries by frequency in ascending order
199 std::sort(freqToOutputAccelerationMap.begin(), freqToOutputAccelerationMap.end(),
200 [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
201
202 for (const auto& entry : freqToOutputAccelerationMap) {
203 float minAcceptableOutputAcceleration = convertSensitivityLevelToAcceleration(
204 pwlev2::COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL, entry.frequencyHz);
205
206 if (sharpnessRange.first < 0 &&
207 minAcceptableOutputAcceleration <= entry.maxOutputAccelerationGs) {
208 sharpnessRange.first = entry.frequencyHz; // Found the lower bound
209 } else if (sharpnessRange.first >= 0 &&
210 minAcceptableOutputAcceleration >= entry.maxOutputAccelerationGs) {
211 sharpnessRange.second = entry.frequencyHz; // Found the upper bound
212 return sharpnessRange;
213 }
214 }
215
216 if (sharpnessRange.first >= 0) {
217 // If only the lower bound was found, set the upper bound to the max frequency.
218 sharpnessRange.second = getPwleV2FrequencyMaxHz(vibrator);
219 }
220
221 return sharpnessRange;
222 }
223 } // namespace pwlev2
224 } // namespace testing
225 } // namespace vibrator
226 } // namespace hardware
227 } // namespace android
228 } // namespace aidl
229 #endif // VIBRATOR_HAL_PWLE_V2_UTILS_H
230