diff --git a/utils/BUILD.gn b/utils/BUILD.gn index 71226809b08b469a78b1b3747e3848f3b69e4426..58d6f7aa06dbe534ea599352d87cbd4ac24de144 100644 --- a/utils/BUILD.gn +++ b/utils/BUILD.gn @@ -18,5 +18,6 @@ group("miscdevice_utils_target") { deps = [ "common:libmiscdevice_utils", "haptic_decoder/oh_json:libvibrator_decoder", + "haptic_decoder/he_json:libhe_vibrator_decoder", ] } diff --git a/utils/haptic_decoder/he_json/BUILD.gn b/utils/haptic_decoder/he_json/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a3170c5d1114bbf9a1f0f86ae37d1437d8522a5c --- /dev/null +++ b/utils/haptic_decoder/he_json/BUILD.gn @@ -0,0 +1,43 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("./../../../miscdevice.gni") + +ohos_shared_library("libhe_vibrator_decoder") { + sources = [ + "src/he_vibrator_decoder.cpp", + "src/he_vibrator_decoder_factory.cpp", + ] + + include_dirs = [ + "include", + "$SUBSYSTEM_DIR/utils/common/include", + "$SUBSYSTEM_DIR/utils/haptic_decoder/interface", + "//third_party/cJSON", + ] + + deps = [ + "//third_party/cJSON:cjson", + "$SUBSYSTEM_DIR/utils/common:libmiscdevice_utils" + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "c_utils:utils", + "hilog:libhilog", + ] + + part_name = "miscdevice" + subsystem_name = "sensors" +} diff --git a/utils/haptic_decoder/he_json/include/he_vibrator_decoder.h b/utils/haptic_decoder/he_json/include/he_vibrator_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..ce9164ddbd1dcef7040495dd9ded2ca322310e8c --- /dev/null +++ b/utils/haptic_decoder/he_json/include/he_vibrator_decoder.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Shanghai Ruisheng Kaitai Acoustic Science Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HE_VIBRATOR_DECODER_H +#define HE_VIBRATOR_DECODER_H + +#include +#include + +#include "i_vibrator_decoder.h" +#include "json_parser.h" + +namespace OHOS { +namespace Sensors { +class HEVibratorDecoder : public IVibratorDecoder { +public: + HEVibratorDecoder() = default; + ~HEVibratorDecoder() = default; + int32_t DecodeEffect(const RawFileDescriptor &rawFd, VibratePackage &patternPackage) override; +private: + int32_t ParseVersion(const JsonParser &parser); + int32_t ParsePatternList(const JsonParser& parser, cJSON* patternListJSON, VibratePackage& pkg); + int32_t ParsePattern(const JsonParser &parser, cJSON *patternJSON, VibratePattern &pattern); + int32_t ParseEvent(const JsonParser &parser, cJSON *eventJSON, VibrateEvent &event); + int32_t ParseCurve(const JsonParser &parser, cJSON *curveJSON, VibrateEvent &event); + bool CheckEventParameters(const VibrateEvent& event); +}; +} // namespace Sensors +} // namespace OHOS +#endif // HE_VIBRATOR_DECODER_H \ No newline at end of file diff --git a/utils/haptic_decoder/he_json/include/he_vibrator_decoder_factory.h b/utils/haptic_decoder/he_json/include/he_vibrator_decoder_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..d6d4bb37aad76cfc5eae793a7bce5b34eb2a65b0 --- /dev/null +++ b/utils/haptic_decoder/he_json/include/he_vibrator_decoder_factory.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Shanghai Ruisheng Kaitai Acoustic Science Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HE_VIBRATOR_DECODER_FACTORY_H +#define HE_VIBRATOR_DECODER_FACTORY_H + +#include "i_vibrator_decoder_factory.h" + +namespace OHOS { +namespace Sensors { +class HEVibratorDecoderFactory : public IVibratorDecoderFactory { +public: + HEVibratorDecoderFactory() = default; + ~HEVibratorDecoderFactory() = default; + IVibratorDecoder *CreateDecoder() override; +}; +} // namespace Sensors +} // namespace OHOS +#endif // HE_VIBRATOR_DECODER_FACTORY_H \ No newline at end of file diff --git a/utils/haptic_decoder/he_json/src/he_vibrator_decoder.cpp b/utils/haptic_decoder/he_json/src/he_vibrator_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..33295a1379a516c4da05eb9618efe5c3f9f44a34 --- /dev/null +++ b/utils/haptic_decoder/he_json/src/he_vibrator_decoder.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2023 Shanghai Ruisheng Kaitai Acoustic Science Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "he_vibrator_decoder.h" + +#include "sensors_errors.h" + + +namespace OHOS { +namespace Sensors { +using namespace OHOS::HiviewDFX; +namespace { +constexpr int32_t EVENT_NUM_MAX = 16; +constexpr int32_t SUPPORTED_HE_VERSION_1 = 1; +constexpr int32_t SUPPORTED_HE_VERSION_2 = 2; +constexpr int32_t INDEX_MIN = 0; +constexpr int32_t INDEX_MAX = 2; +constexpr int32_t TRANSIENT_VIBRATION_DURATION = 48; +constexpr int32_t INTENSITY_MIN = 0; +constexpr int32_t INTENSITY_MAX = 100; +constexpr int32_t CONTINUOUS_FREQUENCY_MIN = 0; +constexpr int32_t CONTINUOUS_FREQUENCY_MAX = 100; +constexpr int32_t TRANSIENT_FREQUENCY_MIN = -50; +constexpr int32_t TRANSIENT_FREQUENCY_MAX = 150; +constexpr uint32_t CURVE_POINT_NUM_MIN = 4; +constexpr uint32_t CURVE_POINT_NUM_MAX = 16; +constexpr int32_t CURVE_INTENSITY_MIN = 0; +constexpr int32_t CURVE_INTENSITY_MAX = 100; +constexpr int32_t CURVE_INTENSITY_SCALE = 100; +constexpr int32_t CURVE_FREQUENCY_MIN = -100; +constexpr int32_t CURVE_FREQUENCY_MAX = 100; +constexpr int32_t CONTINUOUS_DURATION_MAX = 5000; +constexpr HiLogLabel LABEL = { LOG_CORE, MISC_LOG_DOMAIN, "HEVibratorDecoder" }; +} // namespace + +int32_t HEVibratorDecoder::DecodeEffect(const RawFileDescriptor &rawFd, VibratePackage &pkg) +{ + JsonParser parser(rawFd); + int32_t version = ParseVersion(parser); + pkg.patterns.clear(); + switch (version) { + case SUPPORTED_HE_VERSION_1: { + cJSON *patternJSON = parser.GetObjectItem("Pattern"); + CHKPR(patternJSON, ERROR); + VibratePattern pattern; + pattern.startTime = 0; + int32_t ret = ParsePattern(parser, patternJSON, pattern); + CHKCR((ret == SUCCESS), ERROR, "parse pattern fail!"); + pkg.patterns.emplace_back(pattern); + break; + } + case SUPPORTED_HE_VERSION_2: { + cJSON *patternListJSON = parser.GetObjectItem("PatternList"); + CHKPR(patternListJSON, ERROR); + int32_t ret = ParsePatternList(parser, patternListJSON, pkg); + CHKCR((ret == SUCCESS), ERROR, "parse pattern list fail!"); + break; + } + default: { + MISC_HILOGE("unsupported version %d", version); + return ERROR; + } + } + return SUCCESS; +} + +int32_t HEVibratorDecoder::ParseVersion(const JsonParser &parser) +{ + cJSON *metadataJSON = parser.GetObjectItem("Metadata"); + CHKPR(metadataJSON, ERROR); + cJSON *versionJSON = parser.GetObjectItem(metadataJSON, "Version"); + CHKPR(versionJSON, ERROR); + return versionJSON->valueint; +} + +int32_t HEVibratorDecoder::ParsePatternList(const JsonParser &parser, cJSON *patternListJSON, VibratePackage &pkg) +{ + if (!parser.IsArray(patternListJSON)) { + MISC_HILOGE("The value of pattern list is not array!"); + return ERROR; + } + int32_t size = parser.GetArraySize(patternListJSON); + if (size <= 0) { + MISC_HILOGE("The size of pattern list is 0!"); + return ERROR; + } + int32_t previousPattternTime = -1; + for (int32_t i = 0; i < size; i++) { + cJSON *patternListItemJSON = parser.GetArrayItem(patternListJSON, i); + CHKPR(patternListItemJSON, ERROR); + cJSON *timeJSON = parser.GetObjectItem(patternListItemJSON, "AbsoluteTime"); + CHKPR(timeJSON, ERROR); + int32_t time = timeJSON->valueint; + if (time <= previousPattternTime) { + MISC_HILOGE("The value of absolute time %d is invalid!", time); + return ERROR; + } + previousPattternTime = time; + cJSON *patternJSON = parser.GetObjectItem(patternListItemJSON, "Pattern"); + CHKPR(patternJSON, ERROR); + VibratePattern pattern; + pattern.startTime = time; + int32_t ret = ParsePattern(parser, patternJSON, pattern); + CHKCR((ret == SUCCESS), ERROR, "parse pattern fail!"); + pkg.patterns.emplace_back(pattern); + } + return SUCCESS; +} + +int32_t HEVibratorDecoder::ParsePattern(const JsonParser &parser, cJSON *patternJSON, VibratePattern &pattern) +{ + if (!parser.IsArray(patternJSON)) { + MISC_HILOGE("The value of pattern is not array"); + return ERROR; + } + int32_t size = parser.GetArraySize(patternJSON); + if (size <= 0 || size > EVENT_NUM_MAX) { + MISC_HILOGE("The size of pattern is out of bounds, size:%{public}d", size); + return ERROR; + } + int32_t previousEventTime = 0; + for (int32_t i = 0; i < size; i++) { + cJSON *patternItemJSON = parser.GetArrayItem(patternJSON, i); + CHKPR(patternItemJSON, ERROR); + cJSON *eventJSON = parser.GetObjectItem(patternItemJSON, "Event"); + CHKPR(eventJSON, ERROR); + VibrateEvent event; + int32_t ret = ParseEvent(parser, eventJSON, event); + CHKCR((ret == SUCCESS), ERROR, "parse event fail!"); + if (event.time < previousEventTime) { + MISC_HILOGE("The value of absolute time %d is invalid!", event.time); + return ERROR; + } + previousEventTime = event.time; + pattern.events.emplace_back(event); + } + return SUCCESS; +} + +int32_t HEVibratorDecoder::ParseEvent(const JsonParser &parser, cJSON *eventJSON, VibrateEvent &event) +{ + cJSON *typeJSON = parser.GetObjectItem(eventJSON, "Type"); + CHKPR(typeJSON, ERROR); + std::string type = typeJSON->valuestring; + if (type == "transient") { + event.tag = EVENT_TAG_TRANSIENT; + event.duration = TRANSIENT_VIBRATION_DURATION; + } else if (type == "continuous") { + event.tag = EVENT_TAG_CONTINUOUS; + cJSON *durationJSON = parser.GetObjectItem(eventJSON, "Duration"); + CHKPR(durationJSON, ERROR); + event.duration = durationJSON->valueint; + } else { + MISC_HILOGE("Unknown event type %{public}s", type.c_str()); + return ERROR; + } + cJSON *indexJSON = parser.GetObjectItem(eventJSON, "Index"); + if (indexJSON != NULL) { + event.index = indexJSON->valueint; + } else { + event.index = 0; + } + cJSON *timeJSON = parser.GetObjectItem(eventJSON, "RelativeTime"); + CHKPR(timeJSON, ERROR); + event.time = timeJSON->valueint; + cJSON *paramJSON = parser.GetObjectItem(eventJSON, "Parameters"); + CHKPR(paramJSON, ERROR); + cJSON *intensityJSON = parser.GetObjectItem(paramJSON, "Intensity"); + CHKPR(intensityJSON, ERROR); + event.intensity = intensityJSON->valueint; + cJSON *frequencyJSON = parser.GetObjectItem(paramJSON, "Frequency"); + CHKPR(frequencyJSON, ERROR); + event.frequency = frequencyJSON->valueint; + if (event.tag == EVENT_TAG_CONTINUOUS) { + cJSON *curveJSON = parser.GetObjectItem(paramJSON, "Curve"); + CHKPR(curveJSON, ERROR); + int32_t ret = ParseCurve(parser, curveJSON, event); + if (ret != SUCCESS) { + MISC_HILOGE("Parse curve fail, startTime:%{public}d", event.time); + return ERROR; + } + } + if (!CheckEventParameters(event)) { + MISC_HILOGE("Parameter check of vibration event failed, startTime:%{public}d", event.time); + return ERROR; + } + return SUCCESS; +} + +int32_t HEVibratorDecoder::ParseCurve(const JsonParser &parser, cJSON *curveJSON, VibrateEvent &event) +{ + if (!parser.IsArray(curveJSON)) { + MISC_HILOGE("The value of curve is not array"); + return ERROR; + } + size_t size = parser.GetArraySize(curveJSON); + if ((size < CURVE_POINT_NUM_MIN) || (size > CURVE_POINT_NUM_MAX)) { + MISC_HILOGE("The size of curve point is out of bounds, size:%{public}zu", size); + return ERROR; + } + int32_t previousCurveTime = -1; + for (size_t i = 0; i < size; i++) { + VibrateCurvePoint point; + cJSON *itemJSON = parser.GetArrayItem(curveJSON, i); + CHKPR(itemJSON, ERROR); + cJSON *timeJSON = parser.GetObjectItem(itemJSON, "Time"); + CHKPR(timeJSON, ERROR); + point.time = timeJSON->valueint; + if (point.time <= previousCurveTime || point.time > event.duration) { + MISC_HILOGE("The time of curve point is invalid, time:%{public}d", point.time); + return ERROR; + } + previousCurveTime = point.time; + cJSON *intensityJSON = parser.GetObjectItem(itemJSON, "Intensity"); + CHKPR(intensityJSON, ERROR); + point.intensity = (intensityJSON->valuedouble) * CURVE_INTENSITY_SCALE; + if (point.intensity < CURVE_INTENSITY_MIN || point.intensity > CURVE_INTENSITY_MAX) { + MISC_HILOGE("The intensity of curve point is invalid, intensity:%{public}d", point.intensity); + return ERROR; + } + cJSON *frequencyJSON = parser.GetObjectItem(itemJSON, "Frequency"); + CHKPR(frequencyJSON, ERROR); + point.frequency = frequencyJSON->valueint; + if (point.frequency < CURVE_FREQUENCY_MIN || point.frequency > CURVE_FREQUENCY_MAX) { + MISC_HILOGE("The freq of curve point is invalid, freq:%{public}d", point.frequency); + return ERROR; + } + event.points.emplace_back(point); + } + return SUCCESS; +} + +bool HEVibratorDecoder::CheckEventParameters(const VibrateEvent &event) +{ + if (event.time < 0) { + MISC_HILOGE("The event startTime is out of range, startTime:%{public}d", event.time); + return false; + } + if (event.index < INDEX_MIN || event.index > INDEX_MAX) { + MISC_HILOGE("The event index is out of range, index:%{public}d", event.index); + return false; + } + if (event.intensity < INTENSITY_MIN || event.intensity > INTENSITY_MAX) { + MISC_HILOGE("The event intensity is out of range, intensity:%{public}d", event.intensity); + return false; + } + if (event.tag == EVENT_TAG_TRANSIENT) { + if (event.frequency < TRANSIENT_FREQUENCY_MIN || event.frequency > TRANSIENT_FREQUENCY_MAX) { + MISC_HILOGE("The transient event frequency is out of range, frequency:%{public}d", event.frequency); + return false; + } + } else if (event.tag == EVENT_TAG_CONTINUOUS) { + if (event.frequency < CONTINUOUS_FREQUENCY_MIN || event.frequency > CONTINUOUS_FREQUENCY_MAX) { + MISC_HILOGE("The continuous event frequency is out of range, frequency:%{public}d", event.frequency); + return false; + } + if (event.duration <= 0 || event.duration > CONTINUOUS_DURATION_MAX) { + MISC_HILOGE("The continuous event duration is out of range, duration:%{public}d", event.duration); + return false; + } + int32_t pointNum = event.points.size(); + if (pointNum < CURVE_POINT_NUM_MIN || pointNum > CURVE_POINT_NUM_MAX) { + MISC_HILOGE("The points size is out of range, size:%{public}d", pointNum); + return false; + } + if (event.points[0].time != 0 || event.points[0].intensity != 0) { + MISC_HILOGE("The fist curve point is invalivd, time %{public}d, insentsity %{public}d", + event.points[0].time, event.points[0].intensity); + return false; + } + if (event.points[pointNum - 1].time != event.duration || event.points[pointNum - 1].intensity != 0) { + MISC_HILOGE("The last curve point is invalivd, time %{public}d, insentsity %{public}d", + event.points[pointNum - 1].time, event.points[pointNum - 1].intensity); + return false; + } + } else { + MISC_HILOGE("The event tag is unknown, tag:%{public}d", event.tag); + return false; + } + return true; +} +} // namespace Sensors +} // namespace OHOS \ No newline at end of file diff --git a/utils/haptic_decoder/he_json/src/he_vibrator_decoder_factory.cpp b/utils/haptic_decoder/he_json/src/he_vibrator_decoder_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb3207bbd4e6497fee6200b6031b34f0431573c7 --- /dev/null +++ b/utils/haptic_decoder/he_json/src/he_vibrator_decoder_factory.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Shanghai Ruisheng Kaitai Acoustic Science Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "he_vibrator_decoder_factory.h" +#include "he_vibrator_decoder.h" +#include "sensors_errors.h" + +namespace OHOS { +namespace Sensors { +using namespace OHOS::HiviewDFX; +namespace { +constexpr HiLogLabel LABEL = { LOG_CORE, MISC_LOG_DOMAIN, "HEVibratorDecoderFactory" }; +} // namespace +IVibratorDecoder *HEVibratorDecoderFactory::CreateDecoder() +{ + CALL_LOG_ENTER; + return new HEVibratorDecoder(); +} +} // namespace Sensors +} // namespace OHOS \ No newline at end of file