• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "custom_vibration_matcher.h"
17 
18 #include "sensors_errors.h"
19 #include "vibrator_hdi_connection.h"
20 
21 #undef LOG_TAG
22 #define LOG_TAG "CustomVibrationMatcher"
23 
24 namespace OHOS {
25 namespace Sensors {
26 namespace {
27 constexpr int32_t FREQUENCY_MIN = 0;
28 constexpr int32_t FREQUENCY_MAX = 100;
29 constexpr int32_t INTENSITY_MIN = 0;
30 constexpr int32_t INTENSITY_MAX = 100;
31 constexpr int32_t VIBRATOR_DELAY = 20;
32 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
33 constexpr int32_t CONTINUOUS_GRADE_NUM = 8;
34 constexpr int32_t CONTINUOUS_GRADE_MASK = 100;
35 constexpr float ROUND_OFFSET = 0.5;
36 constexpr float CONTINUOUS_GRADE_SCALE = 100. / 8;
37 constexpr float INTENSITY_WEIGHT = 0.5;
38 constexpr float FREQUENCY_WEIGHT = 0.5;
39 constexpr float WEIGHT_SUM_INIT = 100;
40 constexpr int32_t EFFECT_ID_BOUNDARY = 1000;
41 constexpr int32_t DURATION_MAX = 1600;
42 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
43 constexpr float CURVE_INTENSITY_SCALE = 100.00;
44 constexpr float EPSILON = 0.00001;
45 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
46 constexpr int32_t SLICE_STEP = 50;
47 constexpr int32_t CONTINUOUS_VIBRATION_DURATION_MIN = 15;
48 constexpr int32_t INDEX_MIN_RESTRICT = 1;
49 constexpr int32_t WAVE_INFO_DIMENSION = 3;
50 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
51 }  // namespace
52 
CustomVibrationMatcher()53 CustomVibrationMatcher::CustomVibrationMatcher()
54 {
55 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
56     auto &VibratorDevice = VibratorHdiConnection::GetInstance();
57     int32_t ret = VibratorDevice.GetAllWaveInfo(hdfWaveInfos_);
58     if (ret != ERR_OK) {
59         MISC_HILOGE("GetAllWaveInfo failed infoSize:%{public}zu", hdfWaveInfos_.size());
60         return;
61     }
62     if (!hdfWaveInfos_.empty()) {
63         for (auto it = hdfWaveInfos_.begin(); it != hdfWaveInfos_.end(); ++it) {
64             MISC_HILOGI("waveId:%{public}d, intensity:%{public}f, frequency:%{public}f, duration:%{public}d",
65                 it->waveId, it->intensity, it->frequency, it->duration);
66         }
67         NormalizedWaveInfo();
68     }
69 }
70 
NormalizedWaveInfo()71 void CustomVibrationMatcher::NormalizedWaveInfo()
72 {
73     CALL_LOG_ENTER;
74     auto firstIt = hdfWaveInfos_.begin();
75     float maxIntensity = firstIt->intensity;
76     float minFrequency = firstIt->frequency;
77     float maxFrequency = firstIt->frequency;
78     for (auto it = hdfWaveInfos_.begin(); it != hdfWaveInfos_.end(); ++it) {
79         maxIntensity = (maxIntensity > it->intensity) ? maxIntensity : it->intensity;
80         minFrequency = (minFrequency < it->frequency) ? minFrequency : it->frequency;
81         maxFrequency = (maxFrequency > it->frequency) ? maxFrequency : it->frequency;
82     }
83 
84     float intensityEqualValue = maxIntensity / INTENSITY_MAX;
85     float frequencyEqualValue = (maxFrequency - minFrequency) / FREQUENCY_MAX;
86     if ((std::abs(intensityEqualValue) <= EPSILON) || (std::abs(frequencyEqualValue) <= EPSILON)) {
87         MISC_HILOGE("The equal value of intensity or frequency is zero");
88         return;
89     }
90     for (auto it = hdfWaveInfos_.begin(); it != hdfWaveInfos_.end(); ++it) {
91         std::vector<int32_t> normalizedValue;
92         normalizedValue.push_back(static_cast<int32_t>(it->intensity / intensityEqualValue));
93         normalizedValue.push_back(static_cast<int32_t>((it->frequency - minFrequency) / frequencyEqualValue));
94         normalizedValue.push_back(it->duration);
95         waveInfos_[it->waveId] = normalizedValue;
96     }
97     for (auto it = waveInfos_.begin(); it != waveInfos_.end(); ++it) {
98         MISC_HILOGI("waveId:%{public}d, intensity:%{public}d, frequency:%{public}d, duration:%{public}d",
99             it->first, it->second[0], it->second[1], it->second[WAVE_INFO_DIMENSION - 1]);
100     }
101 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
102 }
103 
GetInstance()104 CustomVibrationMatcher &CustomVibrationMatcher::GetInstance()
105 {
106     static CustomVibrationMatcher instance;
107     return instance;
108 }
109 
110 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
TransformTime(const VibratePackage & package,std::vector<CompositeEffect> & compositeEffects)111 int32_t CustomVibrationMatcher::TransformTime(const VibratePackage &package,
112     std::vector<CompositeEffect> &compositeEffects)
113 {
114     CALL_LOG_ENTER;
115     VibratePattern flatPattern = MixedWaveProcess(package);
116     if (flatPattern.events.empty()) {
117         MISC_HILOGE("The events of pattern is empty");
118         return ERROR;
119     }
120     int32_t frontTime = 0;
121     for (const VibrateEvent &event : flatPattern.events) {
122         TimeEffect timeEffect;
123         timeEffect.delay = event.time - frontTime;
124         timeEffect.time = event.duration;
125         timeEffect.intensity = event.intensity;
126         timeEffect.frequency = event.frequency;
127         CompositeEffect compositeEffect;
128         compositeEffect.timeEffect = timeEffect;
129         compositeEffects.push_back(compositeEffect);
130         frontTime = event.time;
131     }
132     TimeEffect timeEffect;
133     timeEffect.delay = flatPattern.events.back().duration;
134     timeEffect.time = 0;
135     timeEffect.intensity = 0;
136     timeEffect.frequency = 0;
137     CompositeEffect compositeEffect;
138     compositeEffect.timeEffect = timeEffect;
139     compositeEffects.push_back(compositeEffect);
140     return SUCCESS;
141 }
142 
TransformEffect(const VibratePackage & package,std::vector<CompositeEffect> & compositeEffects)143 int32_t CustomVibrationMatcher::TransformEffect(const VibratePackage &package,
144     std::vector<CompositeEffect> &compositeEffects)
145 {
146     CALL_LOG_ENTER;
147     VibratePattern flatPattern = MixedWaveProcess(package);
148     if (flatPattern.events.empty()) {
149         MISC_HILOGE("The events of pattern is empty");
150         return ERROR;
151     }
152     int32_t preStartTime = flatPattern.startTime;
153     int32_t preDuration = 0;
154     for (const VibrateEvent &event : flatPattern.events) {
155         if ((event.tag == EVENT_TAG_CONTINUOUS) || waveInfos_.empty()) {
156             PrimitiveEffect primitiveEffect;
157             primitiveEffect.delay = event.time - preStartTime;
158             primitiveEffect.effectId = event.duration;
159             primitiveEffect.intensity = event.intensity;
160             CompositeEffect compositeEffect;
161             compositeEffect.primitiveEffect = primitiveEffect;
162             compositeEffects.push_back(compositeEffect);
163             preStartTime = event.time;
164             preDuration = event.duration;
165         } else if (event.tag == EVENT_TAG_TRANSIENT) {
166             ProcessTransientEvent(event, preStartTime, preDuration, compositeEffects);
167         } else {
168             MISC_HILOGE("Unknown event tag, tag:%{public}d", event.tag);
169             return ERROR;
170         }
171     }
172     PrimitiveEffect primitiveEffect;
173     primitiveEffect.delay = preDuration;
174     primitiveEffect.effectId = 0;
175     primitiveEffect.intensity = 0;
176     CompositeEffect compositeEffect;
177     compositeEffect.primitiveEffect = primitiveEffect;
178     compositeEffects.push_back(compositeEffect);
179     return SUCCESS;
180 }
181 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
182 
MixedWaveProcess(const VibratePackage & package)183 VibratePattern CustomVibrationMatcher::MixedWaveProcess(const VibratePackage &package)
184 {
185     VibratePattern outputPattern;
186     std::vector<VibrateEvent> &outputEvents = outputPattern.events;
187     for (const VibratePattern &pattern : package.patterns) {
188         for (VibrateEvent event : pattern.events) {
189             event.time += pattern.startTime;
190             PreProcessEvent(event);
191             if ((outputEvents.empty()) || (outputEvents.back().tag == EVENT_TAG_TRANSIENT)) {
192                 outputEvents.emplace_back(event);
193             } else if ((event.time >= (outputEvents.back().time + outputEvents.back().duration))) {
194                 int32_t diffTime = event.time - outputEvents.back().time - outputEvents.back().duration;
195                 outputEvents.back().duration += ((diffTime < VIBRATOR_DELAY) ? (diffTime - VIBRATOR_DELAY) : 0);
196                 outputEvents.back().duration = std::max(outputEvents.back().duration, 0);
197                 outputEvents.emplace_back(event);
198             } else {
199                 VibrateEvent &lastEvent = outputEvents.back();
200                 VibrateEvent newEvent = {
201                     .tag = EVENT_TAG_CONTINUOUS,
202                     .time = lastEvent.time,
203                     .duration = std::max(lastEvent.time + lastEvent.duration, event.time + event.duration)
204                         - lastEvent.time,
205                     .intensity = lastEvent.intensity,
206                     .frequency = lastEvent.frequency,
207                     .index = lastEvent.index,
208                     .points = MergeCurve(lastEvent.points, event.points),
209                 };
210                 outputEvents.pop_back();
211                 outputEvents.push_back(newEvent);
212             }
213         }
214     }
215     return outputPattern;
216 }
217 
PreProcessEvent(VibrateEvent & event)218 void CustomVibrationMatcher::PreProcessEvent(VibrateEvent &event)
219 {
220     if (event.points.empty()) {
221         VibrateCurvePoint startPoint = {
222             .time = 0,
223             .intensity = INTENSITY_MAX,
224             .frequency = 0,
225         };
226         event.points.push_back(startPoint);
227         VibrateCurvePoint endPoint = {
228             .time = event.duration,
229             .intensity = INTENSITY_MAX,
230             .frequency = 0,
231         };
232         event.points.push_back(endPoint);
233     }
234 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
235     event.duration = std::max(event.duration, CONTINUOUS_VIBRATION_DURATION_MIN);
236 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
237     for (VibrateCurvePoint &curvePoint : event.points) {
238         curvePoint.time += event.time;
239         curvePoint.intensity *= (event.intensity / CURVE_INTENSITY_SCALE);
240         curvePoint.intensity = std::max(curvePoint.intensity, INTENSITY_MIN);
241         curvePoint.intensity = std::min(curvePoint.intensity, INTENSITY_MAX);
242         curvePoint.frequency += event.frequency;
243         curvePoint.frequency = std::max(curvePoint.frequency, FREQUENCY_MIN);
244         curvePoint.frequency = std::min(curvePoint.frequency, FREQUENCY_MAX);
245     }
246 }
247 
MergeCurve(const std::vector<VibrateCurvePoint> & curveLeft,const std::vector<VibrateCurvePoint> & curveRight)248 std::vector<VibrateCurvePoint> CustomVibrationMatcher::MergeCurve(const std::vector<VibrateCurvePoint> &curveLeft,
249     const std::vector<VibrateCurvePoint> &curveRight)
250 {
251     if (curveLeft.empty()) {
252         return curveRight;
253     }
254     if (curveRight.empty()) {
255         return curveLeft;
256     }
257     int32_t overlapLeft = std::max(curveLeft.front().time, curveRight.front().time);
258     int32_t overlapRight = std::min(curveLeft.back().time, curveRight.back().time);
259     std::vector<VibrateCurvePoint> newCurve;
260     size_t i = 0;
261     size_t j = 0;
262     while (i < curveLeft.size() || j < curveRight.size()) {
263         while (i < curveLeft.size() && ((curveLeft[i].time < overlapLeft) || (curveLeft[i].time > overlapRight) ||
264               (j == curveRight.size()))) {
265             newCurve.push_back(curveLeft[i]);
266             ++i;
267         }
268         while (j < curveRight.size() && ((curveRight[j].time < overlapLeft) || (curveRight[j].time > overlapRight) ||
269               (i == curveLeft.size()))) {
270             newCurve.push_back(curveRight[j]);
271             ++j;
272         }
273         VibrateCurvePoint newCurvePoint;
274         if (i < curveLeft.size() && j < curveRight.size()) {
275             if ((curveLeft[i].time < curveRight[j].time) && (j > 0)) {
276                 int32_t intensity = Interpolation(curveRight[j - 1].time, curveRight[j].time,
277                     curveRight[j - 1].intensity, curveRight[j].intensity, curveLeft[i].time);
278                 int32_t frequency = Interpolation(curveRight[j - 1].time, curveRight[j].time,
279                     curveRight[j - 1].frequency, curveRight[j].frequency, curveLeft[i].time);
280                 newCurvePoint.time = curveLeft[i].time;
281                 newCurvePoint.intensity = std::max(curveLeft[i].intensity, intensity);
282                 newCurvePoint.frequency = (curveLeft[i].frequency + frequency) / 2;
283                 ++i;
284             } else if ((curveLeft[i].time > curveRight[j].time) && (i > 0)) {
285                 int32_t intensity = Interpolation(curveLeft[i - 1].time, curveLeft[i].time,
286                     curveLeft[i - 1].intensity, curveLeft[i].intensity, curveRight[j].time);
287                 int32_t frequency = Interpolation(curveLeft[i - 1].time, curveLeft[i].time,
288                     curveLeft[i - 1].frequency, curveLeft[i].frequency, curveRight[j].time);
289                 newCurvePoint.time = curveRight[j].time;
290                 newCurvePoint.intensity = std::max(curveRight[j].intensity, intensity);
291                 newCurvePoint.frequency = (curveRight[j].frequency + frequency) / 2;
292                 ++j;
293             } else {
294                 newCurvePoint.time = curveRight[i].time;
295                 newCurvePoint.intensity = std::max(curveLeft[i].intensity, curveRight[j].intensity);
296                 newCurvePoint.frequency = (curveLeft[i].frequency + curveRight[j].frequency) / 2;
297                 ++i;
298                 ++j;
299             }
300             newCurve.push_back(newCurvePoint);
301         }
302     }
303     return newCurve;
304 }
305 
306 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
ProcessContinuousEvent(const VibrateEvent & event,int32_t & preStartTime,int32_t & preDuration,std::vector<CompositeEffect> & compositeEffects)307 void CustomVibrationMatcher::ProcessContinuousEvent(const VibrateEvent &event, int32_t &preStartTime,
308     int32_t &preDuration, std::vector<CompositeEffect> &compositeEffects)
309 {
310     if (event.duration < 2 * SLICE_STEP) {
311         VibrateSlice slice = {
312             .time = event.time,
313             .duration = event.duration,
314             .intensity = event.intensity,
315             .frequency = event.frequency,
316         };
317         ProcessContinuousEventSlice(slice, preStartTime, preDuration, compositeEffects);
318         return;
319     }
320     const std::vector<VibrateCurvePoint> &curve = event.points;
321     int32_t endTime = curve.back().time;
322     int32_t curTime = curve.front().time;
323     int32_t curIntensity = curve.front().intensity;
324     int32_t curFrequency = curve.front().frequency;
325     int32_t nextTime = 0;
326     int32_t i = 0;
327     while (curTime < endTime) {
328         int32_t nextIntensity = 0;
329         int32_t nextFrequency = 0;
330         if ((endTime - curTime) >= (2 * SLICE_STEP)) {
331             nextTime = curTime + SLICE_STEP;
332         } else {
333             nextTime = endTime;
334         }
335         while (curve[i].time < nextTime) {
336             ++i;
337         }
338         if (i < INDEX_MIN_RESTRICT) {
339             curTime = nextTime;
340             continue;
341         }
342         nextIntensity = Interpolation(curve[i - 1].time, curve[i].time, curve[i - 1].intensity, curve[i].intensity,
343             nextTime);
344         nextFrequency = Interpolation(curve[i - 1].time, curve[i].time, curve[i - 1].frequency, curve[i].frequency,
345             nextTime);
346         VibrateSlice slice = {
347             .time = curTime,
348             .duration = nextTime - curTime,
349             .intensity = (curIntensity + nextIntensity) / 2,
350             .frequency = (curFrequency + nextFrequency) / 2,
351         };
352         ProcessContinuousEventSlice(slice, preStartTime, preDuration, compositeEffects);
353         curTime = nextTime;
354         curIntensity = nextIntensity;
355         curFrequency = nextFrequency;
356     }
357 }
358 
ProcessContinuousEventSlice(const VibrateSlice & slice,int32_t & preStartTime,int32_t & preDuration,std::vector<CompositeEffect> & compositeEffects)359 void CustomVibrationMatcher::ProcessContinuousEventSlice(const VibrateSlice &slice, int32_t &preStartTime,
360     int32_t &preDuration, std::vector<CompositeEffect> &compositeEffects)
361 {
362     int32_t grade = -1;
363     if (slice.intensity == INTENSITY_MAX) {
364         grade = CONTINUOUS_GRADE_NUM - 1;
365     } else {
366         grade = round(slice.intensity / CONTINUOUS_GRADE_SCALE + ROUND_OFFSET) - 1;
367     }
368     if ((!compositeEffects.empty()) && (slice.time == preStartTime + preDuration)) {
369         PrimitiveEffect &prePrimitiveEffect = compositeEffects.back().primitiveEffect;
370         int32_t preEffectId = prePrimitiveEffect.effectId;
371         int32_t preGrade = preEffectId % CONTINUOUS_GRADE_MASK;
372         int32_t mergeDuration = preDuration + slice.duration;
373         if (preEffectId > EFFECT_ID_BOUNDARY && preGrade == grade && mergeDuration < DURATION_MAX) {
374             prePrimitiveEffect.effectId = mergeDuration * CONTINUOUS_GRADE_MASK + grade;
375             preDuration = mergeDuration;
376             return;
377         }
378     }
379     PrimitiveEffect primitiveEffect;
380     primitiveEffect.delay = slice.time - preStartTime;
381     primitiveEffect.effectId = slice.duration * CONTINUOUS_GRADE_MASK + grade;
382     CompositeEffect compositeEffect;
383     compositeEffect.primitiveEffect = primitiveEffect;
384     compositeEffects.push_back(compositeEffect);
385     preStartTime = slice.time;
386     preDuration = slice.duration;
387 }
388 
ProcessTransientEvent(const VibrateEvent & event,int32_t & preStartTime,int32_t & preDuration,std::vector<CompositeEffect> & compositeEffects)389 void CustomVibrationMatcher::ProcessTransientEvent(const VibrateEvent &event, int32_t &preStartTime,
390     int32_t &preDuration, std::vector<CompositeEffect> &compositeEffects)
391 {
392     int32_t matchId = 0;
393     float minWeightSum = WEIGHT_SUM_INIT;
394     for (const auto &transientInfo : waveInfos_) {
395         int32_t id = transientInfo.first;
396         const std::vector<int32_t> &info = transientInfo.second;
397         float intensityDistance = std::abs(event.intensity - info[0]);
398         float frequencyDistance = std::abs(event.frequency - info[1]);
399         float weightSum = INTENSITY_WEIGHT * intensityDistance + FREQUENCY_WEIGHT * frequencyDistance;
400         if (weightSum < minWeightSum) {
401             minWeightSum = weightSum;
402             matchId = id;
403         }
404     }
405     PrimitiveEffect primitiveEffect;
406     primitiveEffect.delay = event.time - preStartTime;
407     primitiveEffect.effectId = (-matchId);
408     primitiveEffect.intensity = INTENSITY_MAX;
409     CompositeEffect compositeEffect;
410     compositeEffect.primitiveEffect = primitiveEffect;
411     compositeEffects.push_back(compositeEffect);
412     preStartTime = event.time;
413     preDuration = event.duration;
414 }
415 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
416 
Interpolation(int32_t x1,int32_t x2,int32_t y1,int32_t y2,int32_t x)417 int32_t CustomVibrationMatcher::Interpolation(int32_t x1, int32_t x2, int32_t y1, int32_t y2, int32_t x)
418 {
419     if (x1 == x2) {
420         return y1;
421     }
422     float delta_y = static_cast<float>(y2 - y1);
423     float delta_x = static_cast<float>(x2 - x1);
424     return y1 + delta_y / delta_x * (x - x1);
425 }
426 }  // namespace Sensors
427 }  // namespace OHOS
428