Loading automotive/vehicle/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,9 @@ }, { "name": "FakeVehicleHardwareTest" }, { "name": "FakeVehicleHalValueGeneratorsTest" } ] } automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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 android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_ #define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_ #include "FakeValueGenerator.h" #include <json/json.h> #include <iostream> #include <vector> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { class JsonFakeValueGenerator : public FakeValueGenerator { public: // Create a new JSON fake value generator. {@code request.value.stringValue} is the JSON file // name. {@code request.value.int32Values[1]} if exists, is the number of iterations. If // {@code int32Values} has less than 2 elements, number of iterations would be set to -1, which // means iterate indefinitely. explicit JsonFakeValueGenerator( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request); // Create a new JSON fake value generator using the specified JSON file path. All the events // in the JSON file would be generated for number of {@code iteration}. If iteration is 0, no // value would be generated. If iteration is less than 0, it would iterate indefinitely. explicit JsonFakeValueGenerator(const std::string& path, int32_t iteration); // Create a new JSON fake value generator using the specified JSON file path. All the events // in the JSON file would be generated once. explicit JsonFakeValueGenerator(const std::string& path); ~JsonFakeValueGenerator() = default; std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent() override; const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>& getAllEvents(); private: size_t mEventIndex = 0; std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> mEvents; long mLastEventTimestamp = 0; int32_t mNumOfIterations = 0; void setBit(std::vector<uint8_t>& bytes, size_t idx); void init(const std::string& path, int32_t iteration); }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_ automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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 android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_ #define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_ #include "FakeValueGenerator.h" namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { class LinearFakeValueGenerator : public FakeValueGenerator { public: // A linear value generator initialized using values in request. // int32Values[1]: propId // floatValues[0]: middleValue and currentValue // floatValues[1]: dispersion // floatValues[2]: increment // int64Values[0]: interval // {@code propId} must be INT32 or INT64 or FLOAT type. explicit LinearFakeValueGenerator( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request); // A linear value generator in range [middleValue - dispersion, middleValue + dispersion), // starts at 'currentValue' and at each 'interval', increase by 'increment' and loop back if // exceeds middleValue + dispersion. {@code propId} must be INT32 or INT64 or FLOAT type. explicit LinearFakeValueGenerator(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval); ~LinearFakeValueGenerator() = default; std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent() override; private: // In every timer tick we may want to generate new value based on initial value for debug // purpose. It's better to have sequential values to see if events gets delivered in order // to the client. struct GeneratorCfg { int32_t propId; float middleValue; float currentValue; // Should be in range (middleValue +/- dispersion). float dispersion; // Defines minimum and maximum value based on initial value. float increment; // Value that we will be added to currentValue with each timer tick. int64_t interval; long lastEventTimestamp; }; GeneratorCfg mGenCfg; void initGenCfg(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval); }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_ automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp 0 → 100644 +256 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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. */ #define LOG_TAG "JsonFakeValueGenerator" #include "JsonFakeValueGenerator.h" #include <fstream> #include <type_traits> #include <typeinfo> #include <VehicleUtils.h> #include <android/binder_enums.h> #include <utils/Log.h> #include <utils/SystemClock.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { namespace { using ::aidl::android::hardware::automotive::vehicle::DiagnosticFloatSensorIndex; using ::aidl::android::hardware::automotive::vehicle::DiagnosticIntegerSensorIndex; using ::aidl::android::hardware::automotive::vehicle::RawPropValues; using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; template <class T> int getLastIndex() { auto range = ::ndk::enum_range<T>(); auto it = range.begin(); while (std::next(it) != range.end()) { it++; } return toInt(*it); } bool isDiagnosticProperty(int32_t prop) { return prop == toInt(VehicleProperty::OBD2_LIVE_FRAME) || prop == toInt(VehicleProperty::OBD2_FREEZE_FRAME); } void setBit(std::vector<uint8_t>& bytes, size_t idx) { uint8_t mask = 1 << (idx % 8); bytes[idx / 8] |= mask; } template <typename T> void copyJsonArray(const Json::Value& jsonArray, std::vector<T>& dest) { dest.resize(jsonArray.size()); for (Json::Value::ArrayIndex i = 0; i < jsonArray.size(); i++) { if (std::is_same<T, int32_t>::value) { dest[i] = jsonArray[i].asInt(); } else if (std::is_same<T, int64_t>::value) { dest[i] = jsonArray[i].asInt64(); } else if (std::is_same<T, float>::value) { dest[i] = jsonArray[i].asFloat(); } } } void copyMixedValueJson(const Json::Value& jsonValue, RawPropValues& dest) { copyJsonArray(jsonValue["int32Values"], dest.int32Values); copyJsonArray(jsonValue["int64Values"], dest.int64Values); copyJsonArray(jsonValue["floatValues"], dest.floatValues); dest.stringValue = jsonValue["stringValue"].asString(); } std::vector<uint8_t> generateDiagnosticBytes(const RawPropValues& diagnosticValue) { size_t lastIntegerSensorIndex = static_cast<size_t>(getLastIndex<DiagnosticIntegerSensorIndex>()); size_t lastFloatSensorIndex = static_cast<size_t>(getLastIndex<DiagnosticFloatSensorIndex>()); size_t byteSize = (lastIntegerSensorIndex + lastFloatSensorIndex + 2); std::vector<uint8_t> bytes((byteSize + 7) / 8); auto& int32Values = diagnosticValue.int32Values; for (size_t i = 0; i < int32Values.size(); i++) { if (int32Values[i] != 0) { setBit(bytes, i); } } auto& floatValues = diagnosticValue.floatValues; for (size_t i = 0; i < floatValues.size(); i++) { if (floatValues[i] != 0.0) { setBit(bytes, i + lastIntegerSensorIndex + 1); } } return bytes; } std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is) { std::vector<VehiclePropValue> fakeVhalEvents; Json::CharReaderBuilder builder; Json::Value rawEvents; std::string errorMessage; if (!Json::parseFromStream(builder, is, &rawEvents, &errorMessage)) { ALOGE("%s: Failed to parse fake data JSON file. Error: %s", __func__, errorMessage.c_str()); return fakeVhalEvents; } for (Json::Value::ArrayIndex i = 0; i < rawEvents.size(); i++) { Json::Value rawEvent = rawEvents[i]; if (!rawEvent.isObject()) { ALOGE("%s: VHAL JSON event should be an object, %s", __func__, rawEvent.toStyledString().c_str()); continue; } if (rawEvent["prop"].empty() || rawEvent["areaId"].empty() || rawEvent["value"].empty() || rawEvent["timestamp"].empty()) { ALOGE("%s: VHAL JSON event has missing fields, skip it, %s", __func__, rawEvent.toStyledString().c_str()); continue; } VehiclePropValue event = { .timestamp = rawEvent["timestamp"].asInt64(), .areaId = rawEvent["areaId"].asInt(), .prop = rawEvent["prop"].asInt(), }; Json::Value rawEventValue = rawEvent["value"]; auto& value = event.value; int32_t count; switch (getPropType(event.prop)) { case VehiclePropertyType::BOOLEAN: case VehiclePropertyType::INT32: value.int32Values.resize(1); value.int32Values[0] = rawEventValue.asInt(); break; case VehiclePropertyType::INT64: value.int64Values.resize(1); value.int64Values[0] = rawEventValue.asInt64(); break; case VehiclePropertyType::FLOAT: value.floatValues.resize(1); value.floatValues[0] = rawEventValue.asFloat(); break; case VehiclePropertyType::STRING: value.stringValue = rawEventValue.asString(); break; case VehiclePropertyType::INT32_VEC: value.int32Values.resize(rawEventValue.size()); count = 0; for (auto& it : rawEventValue) { value.int32Values[count++] = it.asInt(); } break; case VehiclePropertyType::MIXED: copyMixedValueJson(rawEventValue, value); if (isDiagnosticProperty(event.prop)) { value.byteValues = generateDiagnosticBytes(value); } break; default: ALOGE("%s: unsupported type for property: 0x%x", __func__, event.prop); continue; } fakeVhalEvents.push_back(event); } return fakeVhalEvents; } } // namespace JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path) { init(path, 1); } JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path, int32_t iteration) { init(path, iteration); } JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) { const auto& v = request.value; // Iterate infinitely if iteration number is not provided int32_t numOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1]; init(v.stringValue, numOfIterations); } void JsonFakeValueGenerator::init(const std::string& path, int32_t iteration) { std::ifstream ifs(path); if (!ifs) { ALOGE("%s: couldn't open %s for parsing.", __func__, path.c_str()); return; } mEvents = parseFakeValueJson(ifs); mNumOfIterations = iteration; } const std::vector<VehiclePropValue>& JsonFakeValueGenerator::getAllEvents() { return mEvents; } std::optional<VehiclePropValue> JsonFakeValueGenerator::nextEvent() { if (mNumOfIterations == 0 || mEvents.size() == 0) { return std::nullopt; } VehiclePropValue generatedValue = mEvents[mEventIndex]; if (mLastEventTimestamp == 0) { mLastEventTimestamp = elapsedRealtimeNano(); } else { long nextEventTime = 0; if (mEventIndex > 0) { // All events (start from 2nd one) are supposed to happen in the future with a delay // equals to the duration between previous and current event. nextEventTime = mLastEventTimestamp + (mEvents[mEventIndex].timestamp - mEvents[mEventIndex - 1].timestamp); } else { // We are starting another iteration, immediately send the next event after 1ms. nextEventTime = mLastEventTimestamp + 1000000; } // Prevent overflow. assert(nextEventTime > mLastEventTimestamp); mLastEventTimestamp = nextEventTime; } mEventIndex++; if (mEventIndex == mEvents.size()) { mEventIndex = 0; if (mNumOfIterations > 0) { mNumOfIterations--; } } generatedValue.timestamp = mLastEventTimestamp; return generatedValue; } } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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. */ #define LOG_TAG "LinearFakeValueGenerator" #include "LinearFakeValueGenerator.h" #include <VehicleUtils.h> #include <utils/Log.h> #include <utils/SystemClock.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; LinearFakeValueGenerator::LinearFakeValueGenerator(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval) { initGenCfg(propId, middleValue, initValue, dispersion, increment, interval); } LinearFakeValueGenerator::LinearFakeValueGenerator(const VehiclePropValue& request) { const auto& v = request.value; initGenCfg(v.int32Values[1], v.floatValues[0], v.floatValues[0], v.floatValues[1], v.floatValues[2], v.int64Values[0]); } void LinearFakeValueGenerator::initGenCfg(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval) { // Other types are not supported. assert(getPropType(propId) == VehicleProperty::INT32 || getPropType(propId) == VehicleProperty::INT64 || getPropType(propId) == VehicleProperty::FLOAT); if (initValue < middleValue - dispersion || initValue >= middleValue + dispersion) { ALOGW("%s: invalid initValue: %f, out of range, default to %f", __func__, initValue, middleValue); initValue = middleValue; } mGenCfg = GeneratorCfg{ .propId = propId, .middleValue = middleValue, .currentValue = initValue, .dispersion = dispersion, .increment = increment, .interval = interval, }; } std::optional<VehiclePropValue> LinearFakeValueGenerator::nextEvent() { VehiclePropValue event = { .prop = mGenCfg.propId, }; auto& value = event.value; switch (getPropType(event.prop)) { case VehiclePropertyType::INT32: value.int32Values = {static_cast<int32_t>(mGenCfg.currentValue)}; break; case VehiclePropertyType::INT64: value.int64Values = {static_cast<int64_t>(mGenCfg.currentValue)}; break; case VehiclePropertyType::FLOAT: value.floatValues = {mGenCfg.currentValue}; break; default: ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop); } if (mGenCfg.lastEventTimestamp == 0) { mGenCfg.lastEventTimestamp = elapsedRealtimeNano(); } else { long nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval; // Prevent overflow. assert(nextEventTime > mGenCfg.lastEventTimestamp); mGenCfg.lastEventTimestamp = nextEventTime; } event.timestamp = mGenCfg.lastEventTimestamp; mGenCfg.currentValue += mGenCfg.increment; if (mGenCfg.currentValue >= mGenCfg.middleValue + mGenCfg.dispersion) { // Wrap around, (i - d) + c - (i + d) = c - 2 * d mGenCfg.currentValue = mGenCfg.currentValue - 2 * mGenCfg.dispersion; } return event; } } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android Loading
automotive/vehicle/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,9 @@ }, { "name": "FakeVehicleHardwareTest" }, { "name": "FakeVehicleHalValueGeneratorsTest" } ] }
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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 android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_ #define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_ #include "FakeValueGenerator.h" #include <json/json.h> #include <iostream> #include <vector> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { class JsonFakeValueGenerator : public FakeValueGenerator { public: // Create a new JSON fake value generator. {@code request.value.stringValue} is the JSON file // name. {@code request.value.int32Values[1]} if exists, is the number of iterations. If // {@code int32Values} has less than 2 elements, number of iterations would be set to -1, which // means iterate indefinitely. explicit JsonFakeValueGenerator( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request); // Create a new JSON fake value generator using the specified JSON file path. All the events // in the JSON file would be generated for number of {@code iteration}. If iteration is 0, no // value would be generated. If iteration is less than 0, it would iterate indefinitely. explicit JsonFakeValueGenerator(const std::string& path, int32_t iteration); // Create a new JSON fake value generator using the specified JSON file path. All the events // in the JSON file would be generated once. explicit JsonFakeValueGenerator(const std::string& path); ~JsonFakeValueGenerator() = default; std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent() override; const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>& getAllEvents(); private: size_t mEventIndex = 0; std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> mEvents; long mLastEventTimestamp = 0; int32_t mNumOfIterations = 0; void setBit(std::vector<uint8_t>& bytes, size_t idx); void init(const std::string& path, int32_t iteration); }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_JsonFakeValueGenerator_H_
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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 android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_ #define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_ #include "FakeValueGenerator.h" namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { class LinearFakeValueGenerator : public FakeValueGenerator { public: // A linear value generator initialized using values in request. // int32Values[1]: propId // floatValues[0]: middleValue and currentValue // floatValues[1]: dispersion // floatValues[2]: increment // int64Values[0]: interval // {@code propId} must be INT32 or INT64 or FLOAT type. explicit LinearFakeValueGenerator( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request); // A linear value generator in range [middleValue - dispersion, middleValue + dispersion), // starts at 'currentValue' and at each 'interval', increase by 'increment' and loop back if // exceeds middleValue + dispersion. {@code propId} must be INT32 or INT64 or FLOAT type. explicit LinearFakeValueGenerator(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval); ~LinearFakeValueGenerator() = default; std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent() override; private: // In every timer tick we may want to generate new value based on initial value for debug // purpose. It's better to have sequential values to see if events gets delivered in order // to the client. struct GeneratorCfg { int32_t propId; float middleValue; float currentValue; // Should be in range (middleValue +/- dispersion). float dispersion; // Defines minimum and maximum value based on initial value. float increment; // Value that we will be added to currentValue with each timer tick. int64_t interval; long lastEventTimestamp; }; GeneratorCfg mGenCfg; void initGenCfg(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval); }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_LinearFakeValueGenerator_H_
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp 0 → 100644 +256 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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. */ #define LOG_TAG "JsonFakeValueGenerator" #include "JsonFakeValueGenerator.h" #include <fstream> #include <type_traits> #include <typeinfo> #include <VehicleUtils.h> #include <android/binder_enums.h> #include <utils/Log.h> #include <utils/SystemClock.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { namespace { using ::aidl::android::hardware::automotive::vehicle::DiagnosticFloatSensorIndex; using ::aidl::android::hardware::automotive::vehicle::DiagnosticIntegerSensorIndex; using ::aidl::android::hardware::automotive::vehicle::RawPropValues; using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; template <class T> int getLastIndex() { auto range = ::ndk::enum_range<T>(); auto it = range.begin(); while (std::next(it) != range.end()) { it++; } return toInt(*it); } bool isDiagnosticProperty(int32_t prop) { return prop == toInt(VehicleProperty::OBD2_LIVE_FRAME) || prop == toInt(VehicleProperty::OBD2_FREEZE_FRAME); } void setBit(std::vector<uint8_t>& bytes, size_t idx) { uint8_t mask = 1 << (idx % 8); bytes[idx / 8] |= mask; } template <typename T> void copyJsonArray(const Json::Value& jsonArray, std::vector<T>& dest) { dest.resize(jsonArray.size()); for (Json::Value::ArrayIndex i = 0; i < jsonArray.size(); i++) { if (std::is_same<T, int32_t>::value) { dest[i] = jsonArray[i].asInt(); } else if (std::is_same<T, int64_t>::value) { dest[i] = jsonArray[i].asInt64(); } else if (std::is_same<T, float>::value) { dest[i] = jsonArray[i].asFloat(); } } } void copyMixedValueJson(const Json::Value& jsonValue, RawPropValues& dest) { copyJsonArray(jsonValue["int32Values"], dest.int32Values); copyJsonArray(jsonValue["int64Values"], dest.int64Values); copyJsonArray(jsonValue["floatValues"], dest.floatValues); dest.stringValue = jsonValue["stringValue"].asString(); } std::vector<uint8_t> generateDiagnosticBytes(const RawPropValues& diagnosticValue) { size_t lastIntegerSensorIndex = static_cast<size_t>(getLastIndex<DiagnosticIntegerSensorIndex>()); size_t lastFloatSensorIndex = static_cast<size_t>(getLastIndex<DiagnosticFloatSensorIndex>()); size_t byteSize = (lastIntegerSensorIndex + lastFloatSensorIndex + 2); std::vector<uint8_t> bytes((byteSize + 7) / 8); auto& int32Values = diagnosticValue.int32Values; for (size_t i = 0; i < int32Values.size(); i++) { if (int32Values[i] != 0) { setBit(bytes, i); } } auto& floatValues = diagnosticValue.floatValues; for (size_t i = 0; i < floatValues.size(); i++) { if (floatValues[i] != 0.0) { setBit(bytes, i + lastIntegerSensorIndex + 1); } } return bytes; } std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is) { std::vector<VehiclePropValue> fakeVhalEvents; Json::CharReaderBuilder builder; Json::Value rawEvents; std::string errorMessage; if (!Json::parseFromStream(builder, is, &rawEvents, &errorMessage)) { ALOGE("%s: Failed to parse fake data JSON file. Error: %s", __func__, errorMessage.c_str()); return fakeVhalEvents; } for (Json::Value::ArrayIndex i = 0; i < rawEvents.size(); i++) { Json::Value rawEvent = rawEvents[i]; if (!rawEvent.isObject()) { ALOGE("%s: VHAL JSON event should be an object, %s", __func__, rawEvent.toStyledString().c_str()); continue; } if (rawEvent["prop"].empty() || rawEvent["areaId"].empty() || rawEvent["value"].empty() || rawEvent["timestamp"].empty()) { ALOGE("%s: VHAL JSON event has missing fields, skip it, %s", __func__, rawEvent.toStyledString().c_str()); continue; } VehiclePropValue event = { .timestamp = rawEvent["timestamp"].asInt64(), .areaId = rawEvent["areaId"].asInt(), .prop = rawEvent["prop"].asInt(), }; Json::Value rawEventValue = rawEvent["value"]; auto& value = event.value; int32_t count; switch (getPropType(event.prop)) { case VehiclePropertyType::BOOLEAN: case VehiclePropertyType::INT32: value.int32Values.resize(1); value.int32Values[0] = rawEventValue.asInt(); break; case VehiclePropertyType::INT64: value.int64Values.resize(1); value.int64Values[0] = rawEventValue.asInt64(); break; case VehiclePropertyType::FLOAT: value.floatValues.resize(1); value.floatValues[0] = rawEventValue.asFloat(); break; case VehiclePropertyType::STRING: value.stringValue = rawEventValue.asString(); break; case VehiclePropertyType::INT32_VEC: value.int32Values.resize(rawEventValue.size()); count = 0; for (auto& it : rawEventValue) { value.int32Values[count++] = it.asInt(); } break; case VehiclePropertyType::MIXED: copyMixedValueJson(rawEventValue, value); if (isDiagnosticProperty(event.prop)) { value.byteValues = generateDiagnosticBytes(value); } break; default: ALOGE("%s: unsupported type for property: 0x%x", __func__, event.prop); continue; } fakeVhalEvents.push_back(event); } return fakeVhalEvents; } } // namespace JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path) { init(path, 1); } JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path, int32_t iteration) { init(path, iteration); } JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) { const auto& v = request.value; // Iterate infinitely if iteration number is not provided int32_t numOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1]; init(v.stringValue, numOfIterations); } void JsonFakeValueGenerator::init(const std::string& path, int32_t iteration) { std::ifstream ifs(path); if (!ifs) { ALOGE("%s: couldn't open %s for parsing.", __func__, path.c_str()); return; } mEvents = parseFakeValueJson(ifs); mNumOfIterations = iteration; } const std::vector<VehiclePropValue>& JsonFakeValueGenerator::getAllEvents() { return mEvents; } std::optional<VehiclePropValue> JsonFakeValueGenerator::nextEvent() { if (mNumOfIterations == 0 || mEvents.size() == 0) { return std::nullopt; } VehiclePropValue generatedValue = mEvents[mEventIndex]; if (mLastEventTimestamp == 0) { mLastEventTimestamp = elapsedRealtimeNano(); } else { long nextEventTime = 0; if (mEventIndex > 0) { // All events (start from 2nd one) are supposed to happen in the future with a delay // equals to the duration between previous and current event. nextEventTime = mLastEventTimestamp + (mEvents[mEventIndex].timestamp - mEvents[mEventIndex - 1].timestamp); } else { // We are starting another iteration, immediately send the next event after 1ms. nextEventTime = mLastEventTimestamp + 1000000; } // Prevent overflow. assert(nextEventTime > mLastEventTimestamp); mLastEventTimestamp = nextEventTime; } mEventIndex++; if (mEventIndex == mEvents.size()) { mEventIndex = 0; if (mNumOfIterations > 0) { mNumOfIterations--; } } generatedValue.timestamp = mLastEventTimestamp; return generatedValue; } } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * 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. */ #define LOG_TAG "LinearFakeValueGenerator" #include "LinearFakeValueGenerator.h" #include <VehicleUtils.h> #include <utils/Log.h> #include <utils/SystemClock.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; LinearFakeValueGenerator::LinearFakeValueGenerator(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval) { initGenCfg(propId, middleValue, initValue, dispersion, increment, interval); } LinearFakeValueGenerator::LinearFakeValueGenerator(const VehiclePropValue& request) { const auto& v = request.value; initGenCfg(v.int32Values[1], v.floatValues[0], v.floatValues[0], v.floatValues[1], v.floatValues[2], v.int64Values[0]); } void LinearFakeValueGenerator::initGenCfg(int32_t propId, float middleValue, float initValue, float dispersion, float increment, int64_t interval) { // Other types are not supported. assert(getPropType(propId) == VehicleProperty::INT32 || getPropType(propId) == VehicleProperty::INT64 || getPropType(propId) == VehicleProperty::FLOAT); if (initValue < middleValue - dispersion || initValue >= middleValue + dispersion) { ALOGW("%s: invalid initValue: %f, out of range, default to %f", __func__, initValue, middleValue); initValue = middleValue; } mGenCfg = GeneratorCfg{ .propId = propId, .middleValue = middleValue, .currentValue = initValue, .dispersion = dispersion, .increment = increment, .interval = interval, }; } std::optional<VehiclePropValue> LinearFakeValueGenerator::nextEvent() { VehiclePropValue event = { .prop = mGenCfg.propId, }; auto& value = event.value; switch (getPropType(event.prop)) { case VehiclePropertyType::INT32: value.int32Values = {static_cast<int32_t>(mGenCfg.currentValue)}; break; case VehiclePropertyType::INT64: value.int64Values = {static_cast<int64_t>(mGenCfg.currentValue)}; break; case VehiclePropertyType::FLOAT: value.floatValues = {mGenCfg.currentValue}; break; default: ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop); } if (mGenCfg.lastEventTimestamp == 0) { mGenCfg.lastEventTimestamp = elapsedRealtimeNano(); } else { long nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval; // Prevent overflow. assert(nextEventTime > mGenCfg.lastEventTimestamp); mGenCfg.lastEventTimestamp = nextEventTime; } event.timestamp = mGenCfg.lastEventTimestamp; mGenCfg.currentValue += mGenCfg.increment; if (mGenCfg.currentValue >= mGenCfg.middleValue + mGenCfg.dispersion) { // Wrap around, (i - d) + c - (i + d) = c - 2 * d mGenCfg.currentValue = mGenCfg.currentValue - 2 * mGenCfg.dispersion; } return event; } } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android