• 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 const 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     VibratorIdentifierIPC identifier;
58     identifier.deviceId = -1;
59     identifier.vibratorId = -1;
60     int32_t ret = VibratorDevice.GetAllWaveInfo(identifier, hdfWaveInfos_);
61     if (ret != ERR_OK) {
62         MISC_HILOGE("GetAllWaveInfo failed infoSize:%{public}zu", hdfWaveInfos_.size());
63         return;
64     }
65     if (!hdfWaveInfos_.empty()) {
66         for (const auto &info : hdfWaveInfos_) {
67             MISC_HILOGI("waveId:%{public}d, intensity:%{public}f, frequency:%{public}f, duration:%{public}d",
68                 info.waveId, info.intensity, info.frequency, info.duration);
69         }
70         NormalizedWaveInfo();
71     }
72 }
73 
CustomVibrationMatcher(const VibratorIdentifierIPC & identifier,const std::vector<HdfWaveInformation> & waveInfo)74 CustomVibrationMatcher::CustomVibrationMatcher(const VibratorIdentifierIPC& identifier,
75     const std::vector<HdfWaveInformation> &waveInfo)
76 {
77     hdfWaveInfos_ = waveInfo;
78     if (!hdfWaveInfos_.empty()) {
79         for (const auto &info : hdfWaveInfos_) {
80             MISC_HILOGI("waveId:%{public}d, intensity:%{public}f, frequency:%{public}f, duration:%{public}d",
81                 info.waveId, info.intensity, info.frequency, info.duration);
82         }
83         NormalizedWaveInfo();
84     }
85 }
86 
NormalizedWaveInfo()87 void CustomVibrationMatcher::NormalizedWaveInfo()
88 {
89     CALL_LOG_ENTER;
90     auto firstIt = hdfWaveInfos_.begin();
91     float maxIntensity = firstIt->intensity;
92     float minFrequency = firstIt->frequency;
93     float maxFrequency = firstIt->frequency;
94     for (const auto &info : hdfWaveInfos_) {
95         maxIntensity = (maxIntensity > info.intensity) ? maxIntensity : info.intensity;
96         minFrequency = (minFrequency < info.frequency) ? minFrequency : info.frequency;
97         maxFrequency = (maxFrequency > info.frequency) ? maxFrequency : info.frequency;
98     }
99 
100     float intensityEqualValue = maxIntensity / INTENSITY_MAX;
101     float frequencyEqualValue = (maxFrequency - minFrequency) / FREQUENCY_MAX;
102     if ((std::abs(intensityEqualValue) <= EPSILON) || (std::abs(frequencyEqualValue) <= EPSILON)) {
103         MISC_HILOGE("The equal value of intensity or frequency is zero");
104         return;
105     }
106     for (const auto &info : hdfWaveInfos_) {
107         std::vector<int32_t> normalizedValue;
108         normalizedValue.push_back(static_cast<int32_t>(info.intensity / intensityEqualValue));
109         normalizedValue.push_back(static_cast<int32_t>((info.frequency - minFrequency) / frequencyEqualValue));
110         normalizedValue.push_back(info.duration);
111         waveInfos_[info.waveId] = normalizedValue;
112     }
113     for (const auto &info : waveInfos_) {
114         MISC_HILOGI("waveId:%{public}d, intensity:%{public}d, frequency:%{public}d, duration:%{public}d",
115             info.first, info.second[0], info.second[1], info.second[WAVE_INFO_DIMENSION - 1]);
116     }
117 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
118 }
119 
GetInstance()120 CustomVibrationMatcher &CustomVibrationMatcher::GetInstance()
121 {
122     static CustomVibrationMatcher instance;
123     return instance;
124 }
125 
126 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
TransformTime(const VibratePackage & package,std::vector<CompositeEffect> & compositeEffects)127 int32_t CustomVibrationMatcher::TransformTime(const VibratePackage &package,
128     std::vector<CompositeEffect> &compositeEffects)
129 {
130     CALL_LOG_ENTER;
131     VibratePattern flatPattern = MixedWaveProcess(package);
132     if (flatPattern.events.empty()) {
133         MISC_HILOGE("The events of pattern is empty");
134         return ERROR;
135     }
136     int32_t frontTime = 0;
137     for (const VibrateEvent &event : flatPattern.events) {
138         TimeEffect timeEffect;
139         timeEffect.delay = event.time - frontTime;
140         timeEffect.time = event.duration;
141         timeEffect.intensity = event.intensity;
142         timeEffect.frequency = event.frequency;
143         CompositeEffect compositeEffect;
144         compositeEffect.timeEffect = timeEffect;
145         compositeEffects.push_back(compositeEffect);
146         frontTime = event.time;
147     }
148     TimeEffect timeEffect;
149     timeEffect.delay = flatPattern.events.back().duration;
150     timeEffect.time = 0;
151     timeEffect.intensity = 0;
152     timeEffect.frequency = 0;
153     CompositeEffect compositeEffect;
154     compositeEffect.timeEffect = timeEffect;
155     compositeEffects.push_back(compositeEffect);
156     return SUCCESS;
157 }
158 
TransformEffect(const VibratePackage & package,std::vector<CompositeEffect> & compositeEffects)159 int32_t CustomVibrationMatcher::TransformEffect(const VibratePackage &package,
160     std::vector<CompositeEffect> &compositeEffects)
161 {
162     CALL_LOG_ENTER;
163     VibratePattern flatPattern = MixedWaveProcess(package);
164     if (flatPattern.events.empty()) {
165         MISC_HILOGE("The events of pattern is empty");
166         return ERROR;
167     }
168     int32_t preStartTime = flatPattern.startTime;
169     int32_t preDuration = 0;
170     for (const VibrateEvent &event : flatPattern.events) {
171         if ((event.tag == EVENT_TAG_CONTINUOUS) || waveInfos_.empty()) {
172             PrimitiveEffect primitiveEffect;
173             primitiveEffect.delay = event.time - preStartTime;
174             primitiveEffect.effectId = event.duration;
175             primitiveEffect.intensity = event.intensity;
176             CompositeEffect compositeEffect;
177             compositeEffect.primitiveEffect = primitiveEffect;
178             compositeEffects.push_back(compositeEffect);
179             preStartTime = event.time;
180             preDuration = event.duration;
181         } else if (event.tag == EVENT_TAG_TRANSIENT) {
182             ProcessTransientEvent(event, preStartTime, preDuration, compositeEffects);
183         } else {
184             MISC_HILOGE("Unknown event tag, tag:%{public}d", event.tag);
185             return ERROR;
186         }
187     }
188     PrimitiveEffect primitiveEffect;
189     primitiveEffect.delay = preDuration;
190     primitiveEffect.effectId = 0;
191     primitiveEffect.intensity = 0;
192     CompositeEffect compositeEffect;
193     compositeEffect.primitiveEffect = primitiveEffect;
194     compositeEffects.push_back(compositeEffect);
195     return SUCCESS;
196 }
197 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
198 
MixedWaveProcess(const VibratePackage & package)199 VibratePattern CustomVibrationMatcher::MixedWaveProcess(const VibratePackage &package)
200 {
201     VibratePattern outputPattern;
202     std::vector<VibrateEvent> &outputEvents = outputPattern.events;
203     for (const VibratePattern &pattern : package.patterns) {
204         for (VibrateEvent event : pattern.events) {
205             event.time += pattern.startTime;
206             PreProcessEvent(event);
207             if ((outputEvents.empty()) || (outputEvents.back().tag == EVENT_TAG_TRANSIENT)) {
208                 outputEvents.emplace_back(event);
209             } else if ((event.time >= (outputEvents.back().time + outputEvents.back().duration))) {
210                 int32_t diffTime = event.time - outputEvents.back().time - outputEvents.back().duration;
211                 outputEvents.back().duration += ((diffTime < VIBRATOR_DELAY) ? (diffTime - VIBRATOR_DELAY) : 0);
212                 outputEvents.back().duration = std::max(outputEvents.back().duration, 0);
213                 outputEvents.emplace_back(event);
214             } else {
215                 VibrateEvent &lastEvent = outputEvents.back();
216                 VibrateEvent newEvent = {
217                     .tag = EVENT_TAG_CONTINUOUS,
218                     .time = lastEvent.time,
219                     .duration = std::max(lastEvent.time + lastEvent.duration, event.time + event.duration)
220                         - lastEvent.time,
221                     .intensity = lastEvent.intensity,
222                     .frequency = lastEvent.frequency,
223                     .index = lastEvent.index,
224                     .points = MergeCurve(lastEvent.points, event.points),
225                 };
226                 outputEvents.pop_back();
227                 outputEvents.push_back(newEvent);
228             }
229         }
230     }
231     return outputPattern;
232 }
233 
PreProcessEvent(VibrateEvent & event)234 void CustomVibrationMatcher::PreProcessEvent(VibrateEvent &event)
235 {
236     if (event.points.empty()) {
237         VibrateCurvePoint startPoint = {
238             .time = 0,
239             .intensity = INTENSITY_MAX,
240             .frequency = 0,
241         };
242         event.points.push_back(startPoint);
243         VibrateCurvePoint endPoint = {
244             .time = event.duration,
245             .intensity = INTENSITY_MAX,
246             .frequency = 0,
247         };
248         event.points.push_back(endPoint);
249     }
250 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
251     event.duration = std::max(event.duration, CONTINUOUS_VIBRATION_DURATION_MIN);
252 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
253     for (VibrateCurvePoint &curvePoint : event.points) {
254         curvePoint.time += event.time;
255         curvePoint.intensity *= (event.intensity / CURVE_INTENSITY_SCALE);
256         curvePoint.intensity = std::max(curvePoint.intensity, INTENSITY_MIN);
257         curvePoint.intensity = std::min(curvePoint.intensity, INTENSITY_MAX);
258         curvePoint.frequency += event.frequency;
259         curvePoint.frequency = std::max(curvePoint.frequency, FREQUENCY_MIN);
260         curvePoint.frequency = std::min(curvePoint.frequency, FREQUENCY_MAX);
261     }
262 }
263 
MergeCurve(const std::vector<VibrateCurvePoint> & curveLeft,const std::vector<VibrateCurvePoint> & curveRight)264 std::vector<VibrateCurvePoint> CustomVibrationMatcher::MergeCurve(const std::vector<VibrateCurvePoint> &curveLeft,
265     const std::vector<VibrateCurvePoint> &curveRight)
266 {
267     if (curveLeft.empty()) {
268         return curveRight;
269     }
270     if (curveRight.empty()) {
271         return curveLeft;
272     }
273     int32_t overlapLeft = std::max(curveLeft.front().time, curveRight.front().time);
274     int32_t overlapRight = std::min(curveLeft.back().time, curveRight.back().time);
275     std::vector<VibrateCurvePoint> newCurve;
276     size_t i = 0;
277     size_t j = 0;
278     while (i < curveLeft.size() || j < curveRight.size()) {
279         while (i < curveLeft.size() && ((curveLeft[i].time < overlapLeft) || (curveLeft[i].time > overlapRight) ||
280               (j == curveRight.size()))) {
281             newCurve.push_back(curveLeft[i]);
282             ++i;
283         }
284         while (j < curveRight.size() && ((curveRight[j].time < overlapLeft) || (curveRight[j].time > overlapRight) ||
285               (i == curveLeft.size()))) {
286             newCurve.push_back(curveRight[j]);
287             ++j;
288         }
289         VibrateCurvePoint newCurvePoint;
290         if (i < curveLeft.size() && j < curveRight.size()) {
291             if ((curveLeft[i].time < curveRight[j].time) && (j > 0)) {
292                 int32_t intensity = Interpolation(curveRight[j - 1].time, curveRight[j].time,
293                     curveRight[j - 1].intensity, curveRight[j].intensity, curveLeft[i].time);
294                 int32_t frequency = Interpolation(curveRight[j - 1].time, curveRight[j].time,
295                     curveRight[j - 1].frequency, curveRight[j].frequency, curveLeft[i].time);
296                 newCurvePoint.time = curveLeft[i].time;
297                 newCurvePoint.intensity = std::max(curveLeft[i].intensity, intensity);
298                 newCurvePoint.frequency = (curveLeft[i].frequency + frequency) / 2;
299                 ++i;
300             } else if ((curveLeft[i].time > curveRight[j].time) && (i > 0)) {
301                 int32_t intensity = Interpolation(curveLeft[i - 1].time, curveLeft[i].time,
302                     curveLeft[i - 1].intensity, curveLeft[i].intensity, curveRight[j].time);
303                 int32_t frequency = Interpolation(curveLeft[i - 1].time, curveLeft[i].time,
304                     curveLeft[i - 1].frequency, curveLeft[i].frequency, curveRight[j].time);
305                 newCurvePoint.time = curveRight[j].time;
306                 newCurvePoint.intensity = std::max(curveRight[j].intensity, intensity);
307                 newCurvePoint.frequency = (curveRight[j].frequency + frequency) / 2;
308                 ++j;
309             } else {
310                 newCurvePoint.time = curveRight[i].time;
311                 newCurvePoint.intensity = std::max(curveLeft[i].intensity, curveRight[j].intensity);
312                 newCurvePoint.frequency = (curveLeft[i].frequency + curveRight[j].frequency) / 2;
313                 ++i;
314                 ++j;
315             }
316             newCurve.push_back(newCurvePoint);
317         }
318     }
319     return newCurve;
320 }
321 
322 #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR
ProcessContinuousEvent(const VibrateEvent & event,int32_t & preStartTime,int32_t & preDuration,std::vector<CompositeEffect> & compositeEffects)323 void CustomVibrationMatcher::ProcessContinuousEvent(const VibrateEvent &event, int32_t &preStartTime,
324     int32_t &preDuration, std::vector<CompositeEffect> &compositeEffects)
325 {
326     if (event.duration < 2 * SLICE_STEP) {
327         VibrateSlice slice = {
328             .time = event.time,
329             .duration = event.duration,
330             .intensity = event.intensity,
331             .frequency = event.frequency,
332         };
333         ProcessContinuousEventSlice(slice, preStartTime, preDuration, compositeEffects);
334         return;
335     }
336     const std::vector<VibrateCurvePoint> &curve = event.points;
337     int32_t endTime = curve.back().time;
338     int32_t curTime = curve.front().time;
339     int32_t curIntensity = curve.front().intensity;
340     int32_t curFrequency = curve.front().frequency;
341     int32_t nextTime = 0;
342     int32_t i = 0;
343     while (curTime < endTime) {
344         int32_t nextIntensity = 0;
345         int32_t nextFrequency = 0;
346         if ((endTime - curTime) >= (2 * SLICE_STEP)) {
347             nextTime = curTime + SLICE_STEP;
348         } else {
349             nextTime = endTime;
350         }
351         while (curve[i].time < nextTime) {
352             ++i;
353         }
354         if (i < INDEX_MIN_RESTRICT) {
355             curTime = nextTime;
356             continue;
357         }
358         nextIntensity = Interpolation(curve[i - 1].time, curve[i].time, curve[i - 1].intensity, curve[i].intensity,
359             nextTime);
360         nextFrequency = Interpolation(curve[i - 1].time, curve[i].time, curve[i - 1].frequency, curve[i].frequency,
361             nextTime);
362         VibrateSlice slice = {
363             .time = curTime,
364             .duration = nextTime - curTime,
365             .intensity = (curIntensity + nextIntensity) / 2,
366             .frequency = (curFrequency + nextFrequency) / 2,
367         };
368         ProcessContinuousEventSlice(slice, preStartTime, preDuration, compositeEffects);
369         curTime = nextTime;
370         curIntensity = nextIntensity;
371         curFrequency = nextFrequency;
372     }
373 }
374 
ProcessContinuousEventSlice(const VibrateSlice & slice,int32_t & preStartTime,int32_t & preDuration,std::vector<CompositeEffect> & compositeEffects)375 void CustomVibrationMatcher::ProcessContinuousEventSlice(const VibrateSlice &slice, int32_t &preStartTime,
376     int32_t &preDuration, std::vector<CompositeEffect> &compositeEffects)
377 {
378     int32_t grade = -1;
379     if (slice.intensity == INTENSITY_MAX) {
380         grade = CONTINUOUS_GRADE_NUM - 1;
381     } else {
382         grade = round(slice.intensity / CONTINUOUS_GRADE_SCALE + ROUND_OFFSET) - 1;
383     }
384     if ((!compositeEffects.empty()) && (slice.time == preStartTime + preDuration)) {
385         PrimitiveEffect &prePrimitiveEffect = compositeEffects.back().primitiveEffect;
386         int32_t preEffectId = prePrimitiveEffect.effectId;
387         int32_t preGrade = preEffectId % CONTINUOUS_GRADE_MASK;
388         int32_t mergeDuration = preDuration + slice.duration;
389         if (preEffectId > EFFECT_ID_BOUNDARY && preGrade == grade && mergeDuration < DURATION_MAX) {
390             prePrimitiveEffect.effectId = mergeDuration * CONTINUOUS_GRADE_MASK + grade;
391             preDuration = mergeDuration;
392             return;
393         }
394     }
395     PrimitiveEffect primitiveEffect;
396     primitiveEffect.delay = slice.time - preStartTime;
397     primitiveEffect.effectId = slice.duration * CONTINUOUS_GRADE_MASK + grade;
398     CompositeEffect compositeEffect;
399     compositeEffect.primitiveEffect = primitiveEffect;
400     compositeEffects.push_back(compositeEffect);
401     preStartTime = slice.time;
402     preDuration = slice.duration;
403 }
404 
ProcessTransientEvent(const VibrateEvent & event,int32_t & preStartTime,int32_t & preDuration,std::vector<CompositeEffect> & compositeEffects)405 void CustomVibrationMatcher::ProcessTransientEvent(const VibrateEvent &event, int32_t &preStartTime,
406     int32_t &preDuration, std::vector<CompositeEffect> &compositeEffects)
407 {
408     int32_t matchId = 0;
409     float minWeightSum = WEIGHT_SUM_INIT;
410     for (const auto &transientInfo : waveInfos_) {
411         int32_t id = transientInfo.first;
412         const std::vector<int32_t> &info = transientInfo.second;
413         float intensityDistance = std::abs(event.intensity - info[0]);
414         float frequencyDistance = std::abs(event.frequency - info[1]);
415         float weightSum = INTENSITY_WEIGHT * intensityDistance + FREQUENCY_WEIGHT * frequencyDistance;
416         if (weightSum < minWeightSum) {
417             minWeightSum = weightSum;
418             matchId = id;
419         }
420     }
421     PrimitiveEffect primitiveEffect;
422     primitiveEffect.delay = event.time - preStartTime;
423     primitiveEffect.effectId = (-matchId);
424     primitiveEffect.intensity = INTENSITY_MAX;
425     CompositeEffect compositeEffect;
426     compositeEffect.primitiveEffect = primitiveEffect;
427     compositeEffects.push_back(compositeEffect);
428     preStartTime = event.time;
429     preDuration = event.duration;
430 }
431 #endif // HDF_DRIVERS_INTERFACE_VIBRATOR
432 
Interpolation(int32_t x1,int32_t x2,int32_t y1,int32_t y2,int32_t x)433 int32_t CustomVibrationMatcher::Interpolation(int32_t x1, int32_t x2, int32_t y1, int32_t y2, int32_t x)
434 {
435     if (x1 == x2) {
436         return y1;
437     }
438     float delta_y = static_cast<float>(y2 - y1);
439     float delta_x = static_cast<float>(x2 - x1);
440     return y1 + delta_y / delta_x * (x - x1);
441 }
442 }  // namespace Sensors
443 }  // namespace OHOS
444