Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +45 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,25 @@ namespace V2_0 { namespace impl { /* * This property is used for test purpose to generate fake events. * * It has the following format: * * int32Values[0] - command (1 - start fake data generation, 0 - stop) * int32Values[1] - VehicleProperty to which command applies * * For start command, additional data should be provided: * int64Values[0] - periodic interval in nanoseconds * floatValues[0] - initial value * floatValues[1] - dispersion defines min and max range relative to initial value * floatValues[2] - increment, with every timer tick the value will be incremented by this amount */ const int32_t kGenerateFakeDataControllingProperty = 0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::COMPLEX; const int32_t kHvacPowerProperties[] = { toInt(VehicleProperty::HVAC_FAN_SPEED), toInt(VehicleProperty::HVAC_FAN_DIRECTION), Loading Loading @@ -62,6 +81,24 @@ const ConfigDeclaration kVehicleProperties[] { .initialValue = { .floatValues = {0.0f} } }, { .config = { .prop = toInt(VehicleProperty::PERF_ODOMETER), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, .initialValue = { .floatValues = {0.0f} } }, { .config = { .prop = toInt(VehicleProperty::ENGINE_RPM), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::CONTINUOUS, }, .initialValue = { .floatValues = {0.0f} } }, { .config = { .prop = toInt(VehicleProperty::CURRENT_GEAR), Loading Loading @@ -284,6 +321,14 @@ const ConfigDeclaration kVehicleProperties[] { .maxSampleRate = 10, // 10 Hz, every 100 ms }, .initialValue = { .floatValues = {101.0f} } }, { .config = { .prop = kGenerateFakeDataControllingProperty, .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, } }; Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +87 −1 Original line number Diff line number Diff line Loading @@ -27,11 +27,18 @@ namespace V2_0 { namespace impl { enum class FakeDataCommand : int32_t { Stop = 0, Start = 1, }; EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) : mPropStore(propStore), mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) { this, std::placeholders::_1)), mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1, std::placeholders::_2)) { for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { mPropStore->registerProperty(kVehicleProperties[i].config); Loading @@ -52,6 +59,10 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( } StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { if (propValue.prop == kGenerateFakeDataControllingProperty) { return handleGenerateFakeDataRequest(propValue); }; if (mHvacPowerProps.count(propValue.prop)) { auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON), toInt(VehicleAreaZone::ROW_1)); Loading Loading @@ -176,6 +187,81 @@ std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const { return mPropStore->readAllValues(); } StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) { ALOGI("%s", __func__); const auto& v = request.value; if (v.int32Values.size() < 2) { ALOGE("%s: expected at least 2 elements in int32Values, got: %zu", __func__, v.int32Values.size()); return StatusCode::INVALID_ARG; } FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]); int32_t propId = v.int32Values[1]; switch (command) { case FakeDataCommand::Start: { if (!v.int64Values.size()) { ALOGE("%s: interval is not provided in int64Values", __func__); return StatusCode::INVALID_ARG; } auto interval = std::chrono::nanoseconds(v.int64Values[0]); if (v.floatValues.size() < 3) { ALOGE("%s: expected at least 3 element sin floatValues, got: %zu", __func__, v.floatValues.size()); return StatusCode::INVALID_ARG; } float initialValue = v.floatValues[0]; float dispersion = v.floatValues[1]; float increment = v.floatValues[2]; ALOGI("%s, propId: %d, initalValue: %f", __func__, propId, initialValue); mFakeValueGenerator.startGeneratingHalEvents( interval, propId, initialValue, dispersion, increment); break; } case FakeDataCommand::Stop: { ALOGI("%s, FakeDataCommandStop", __func__); mFakeValueGenerator.stopGeneratingHalEvents(propId); break; } default: { ALOGE("%s: unexpected command: %d", __func__, command); return StatusCode::INVALID_ARG; } } return StatusCode::OK; } void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) { VehiclePropValuePtr updatedPropValue {}; switch (getPropType(propId)) { case VehiclePropertyType::FLOAT: updatedPropValue = getValuePool()->obtainFloat(value); break; case VehiclePropertyType::INT32: updatedPropValue = getValuePool()->obtainInt32(static_cast<int32_t>(value)); break; default: ALOGE("%s: data type for property: 0x%x not supported", __func__, propId); return; } if (updatedPropValue) { updatedPropValue->prop = propId; updatedPropValue->areaId = 0; // Add area support if necessary. updatedPropValue->timestamp = elapsedRealtimeNano(); mPropStore->writeValue(*updatedPropValue); auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode; if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) { doHalEvent(move(updatedPropValue)); } } } } // impl } // namespace V2_0 Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +5 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include "DefaultConfig.h" #include "VehicleHalProto.pb.h" #include "VehicleEmulator.h" #include "FakeValueGenerator.h" namespace android { namespace hardware { Loading Loading @@ -67,6 +68,9 @@ private: return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz)); } StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); void onFakeValueGenerated(int32_t propId, float value); void onContinuousPropertyTimer(const std::vector<int32_t>& properties); bool isContinuousProperty(int32_t propId) const; Loading @@ -74,6 +78,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set<int32_t> mHvacPowerProps; RecurrentTimer mRecurrentTimer; FakeValueGenerator mFakeValueGenerator; }; } // impl Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h 0 → 100644 +127 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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_V2_0_impl_FakeHalEventGenerator_H_ #define android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_ #include <chrono> #include <android/hardware/automotive/vehicle/2.0/types.h> #include <vhal_v2_0/RecurrentTimer.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace V2_0 { namespace impl { class FakeValueGenerator { 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 { float initialValue; // float currentValue; // Should be in range (initialValue +/- 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. }; public: using OnHalEvent = std::function<void(int32_t propId, float value)>; FakeValueGenerator(const OnHalEvent& onHalEvent) : mOnHalEvent(onHalEvent), mRecurrentTimer(std::bind(&FakeValueGenerator::onTimer, this, std::placeholders::_1)) {} ~FakeValueGenerator() = default; void startGeneratingHalEvents(std::chrono::nanoseconds interval, int propId, float initialValue, float dispersion, float increment) { MuxGuard g(mLock); removeLocked(propId); mGenCfg.insert({propId, GeneratorCfg { .initialValue = initialValue, .currentValue = initialValue, .dispersion = dispersion, .increment = increment, }}); mRecurrentTimer.registerRecurrentEvent(interval, propId); } void stopGeneratingHalEvents(int propId) { MuxGuard g(mLock); if (propId == 0) { // Remove all. for (auto&& it : mGenCfg) { removeLocked(it.first); } } else { removeLocked(propId); } } private: void removeLocked(int propId) { if (mGenCfg.erase(propId)) { mRecurrentTimer.unregisterRecurrentEvent(propId); } } void onTimer(const std::vector<int32_t>& properties) { MuxGuard g(mLock); for (int32_t propId : properties) { auto& cfg = mGenCfg[propId]; cfg.currentValue += cfg.increment; if (cfg.currentValue > cfg.initialValue + cfg.dispersion) { cfg.currentValue = cfg.initialValue - cfg.dispersion; } mOnHalEvent(propId, cfg.currentValue); } } private: using MuxGuard = std::lock_guard<std::mutex>; mutable std::mutex mLock; OnHalEvent mOnHalEvent; RecurrentTimer mRecurrentTimer; std::unordered_map<int32_t, GeneratorCfg> mGenCfg; }; } // impl } // namespace V2_0 } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_ Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +45 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,25 @@ namespace V2_0 { namespace impl { /* * This property is used for test purpose to generate fake events. * * It has the following format: * * int32Values[0] - command (1 - start fake data generation, 0 - stop) * int32Values[1] - VehicleProperty to which command applies * * For start command, additional data should be provided: * int64Values[0] - periodic interval in nanoseconds * floatValues[0] - initial value * floatValues[1] - dispersion defines min and max range relative to initial value * floatValues[2] - increment, with every timer tick the value will be incremented by this amount */ const int32_t kGenerateFakeDataControllingProperty = 0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::COMPLEX; const int32_t kHvacPowerProperties[] = { toInt(VehicleProperty::HVAC_FAN_SPEED), toInt(VehicleProperty::HVAC_FAN_DIRECTION), Loading Loading @@ -62,6 +81,24 @@ const ConfigDeclaration kVehicleProperties[] { .initialValue = { .floatValues = {0.0f} } }, { .config = { .prop = toInt(VehicleProperty::PERF_ODOMETER), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, .initialValue = { .floatValues = {0.0f} } }, { .config = { .prop = toInt(VehicleProperty::ENGINE_RPM), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::CONTINUOUS, }, .initialValue = { .floatValues = {0.0f} } }, { .config = { .prop = toInt(VehicleProperty::CURRENT_GEAR), Loading Loading @@ -284,6 +321,14 @@ const ConfigDeclaration kVehicleProperties[] { .maxSampleRate = 10, // 10 Hz, every 100 ms }, .initialValue = { .floatValues = {101.0f} } }, { .config = { .prop = kGenerateFakeDataControllingProperty, .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, } }; Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +87 −1 Original line number Diff line number Diff line Loading @@ -27,11 +27,18 @@ namespace V2_0 { namespace impl { enum class FakeDataCommand : int32_t { Stop = 0, Start = 1, }; EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) : mPropStore(propStore), mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) { this, std::placeholders::_1)), mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1, std::placeholders::_2)) { for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { mPropStore->registerProperty(kVehicleProperties[i].config); Loading @@ -52,6 +59,10 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( } StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { if (propValue.prop == kGenerateFakeDataControllingProperty) { return handleGenerateFakeDataRequest(propValue); }; if (mHvacPowerProps.count(propValue.prop)) { auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON), toInt(VehicleAreaZone::ROW_1)); Loading Loading @@ -176,6 +187,81 @@ std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const { return mPropStore->readAllValues(); } StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) { ALOGI("%s", __func__); const auto& v = request.value; if (v.int32Values.size() < 2) { ALOGE("%s: expected at least 2 elements in int32Values, got: %zu", __func__, v.int32Values.size()); return StatusCode::INVALID_ARG; } FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]); int32_t propId = v.int32Values[1]; switch (command) { case FakeDataCommand::Start: { if (!v.int64Values.size()) { ALOGE("%s: interval is not provided in int64Values", __func__); return StatusCode::INVALID_ARG; } auto interval = std::chrono::nanoseconds(v.int64Values[0]); if (v.floatValues.size() < 3) { ALOGE("%s: expected at least 3 element sin floatValues, got: %zu", __func__, v.floatValues.size()); return StatusCode::INVALID_ARG; } float initialValue = v.floatValues[0]; float dispersion = v.floatValues[1]; float increment = v.floatValues[2]; ALOGI("%s, propId: %d, initalValue: %f", __func__, propId, initialValue); mFakeValueGenerator.startGeneratingHalEvents( interval, propId, initialValue, dispersion, increment); break; } case FakeDataCommand::Stop: { ALOGI("%s, FakeDataCommandStop", __func__); mFakeValueGenerator.stopGeneratingHalEvents(propId); break; } default: { ALOGE("%s: unexpected command: %d", __func__, command); return StatusCode::INVALID_ARG; } } return StatusCode::OK; } void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) { VehiclePropValuePtr updatedPropValue {}; switch (getPropType(propId)) { case VehiclePropertyType::FLOAT: updatedPropValue = getValuePool()->obtainFloat(value); break; case VehiclePropertyType::INT32: updatedPropValue = getValuePool()->obtainInt32(static_cast<int32_t>(value)); break; default: ALOGE("%s: data type for property: 0x%x not supported", __func__, propId); return; } if (updatedPropValue) { updatedPropValue->prop = propId; updatedPropValue->areaId = 0; // Add area support if necessary. updatedPropValue->timestamp = elapsedRealtimeNano(); mPropStore->writeValue(*updatedPropValue); auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode; if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) { doHalEvent(move(updatedPropValue)); } } } } // impl } // namespace V2_0 Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +5 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include "DefaultConfig.h" #include "VehicleHalProto.pb.h" #include "VehicleEmulator.h" #include "FakeValueGenerator.h" namespace android { namespace hardware { Loading Loading @@ -67,6 +68,9 @@ private: return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz)); } StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); void onFakeValueGenerated(int32_t propId, float value); void onContinuousPropertyTimer(const std::vector<int32_t>& properties); bool isContinuousProperty(int32_t propId) const; Loading @@ -74,6 +78,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set<int32_t> mHvacPowerProps; RecurrentTimer mRecurrentTimer; FakeValueGenerator mFakeValueGenerator; }; } // impl Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h 0 → 100644 +127 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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_V2_0_impl_FakeHalEventGenerator_H_ #define android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_ #include <chrono> #include <android/hardware/automotive/vehicle/2.0/types.h> #include <vhal_v2_0/RecurrentTimer.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace V2_0 { namespace impl { class FakeValueGenerator { 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 { float initialValue; // float currentValue; // Should be in range (initialValue +/- 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. }; public: using OnHalEvent = std::function<void(int32_t propId, float value)>; FakeValueGenerator(const OnHalEvent& onHalEvent) : mOnHalEvent(onHalEvent), mRecurrentTimer(std::bind(&FakeValueGenerator::onTimer, this, std::placeholders::_1)) {} ~FakeValueGenerator() = default; void startGeneratingHalEvents(std::chrono::nanoseconds interval, int propId, float initialValue, float dispersion, float increment) { MuxGuard g(mLock); removeLocked(propId); mGenCfg.insert({propId, GeneratorCfg { .initialValue = initialValue, .currentValue = initialValue, .dispersion = dispersion, .increment = increment, }}); mRecurrentTimer.registerRecurrentEvent(interval, propId); } void stopGeneratingHalEvents(int propId) { MuxGuard g(mLock); if (propId == 0) { // Remove all. for (auto&& it : mGenCfg) { removeLocked(it.first); } } else { removeLocked(propId); } } private: void removeLocked(int propId) { if (mGenCfg.erase(propId)) { mRecurrentTimer.unregisterRecurrentEvent(propId); } } void onTimer(const std::vector<int32_t>& properties) { MuxGuard g(mLock); for (int32_t propId : properties) { auto& cfg = mGenCfg[propId]; cfg.currentValue += cfg.increment; if (cfg.currentValue > cfg.initialValue + cfg.dispersion) { cfg.currentValue = cfg.initialValue - cfg.dispersion; } mOnHalEvent(propId, cfg.currentValue); } } private: using MuxGuard = std::lock_guard<std::mutex>; mutable std::mutex mLock; OnHalEvent mOnHalEvent; RecurrentTimer mRecurrentTimer; std::unordered_map<int32_t, GeneratorCfg> mGenCfg; }; } // impl } // namespace V2_0 } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_