From 794fc4f9ff910541f78d12621b3291630de14674 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Tue, 11 Apr 2017 12:42:28 -0700 Subject: [PATCH] Adding a custom property to the default VHAL impl This property is supposed to be used mostly from e2e tests (a simple test-case is provided in separate CL) Test: make -j && runtest -x packages/services/Car/tests/vehiclehal_test/ Bug: b/36510399 Change-Id: I09b24f22ab328eee1ef6add60901ed03bf046874 --- .../default/impl/vhal_v2_0/DefaultConfig.h | 45 +++++++ .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 88 +++++++++++- .../impl/vhal_v2_0/EmulatedVehicleHal.h | 5 + .../impl/vhal_v2_0/FakeValueGenerator.h | 127 ++++++++++++++++++ 4 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h index bf16a9b6e3..c4f935ba7a 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h @@ -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), @@ -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), @@ -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, + }, } }; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp index 0ac6adadea..ea40cc5184 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp @@ -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); @@ -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)); @@ -176,6 +187,81 @@ std::vector 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(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(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 diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index e0874e24a2..009485d4b7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -34,6 +34,7 @@ #include "DefaultConfig.h" #include "VehicleHalProto.pb.h" #include "VehicleEmulator.h" +#include "FakeValueGenerator.h" namespace android { namespace hardware { @@ -67,6 +68,9 @@ private: return std::chrono::nanoseconds(static_cast(1000000000L / hz)); } + StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); + void onFakeValueGenerated(int32_t propId, float value); + void onContinuousPropertyTimer(const std::vector& properties); bool isContinuousProperty(int32_t propId) const; @@ -74,6 +78,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set mHvacPowerProps; RecurrentTimer mRecurrentTimer; + FakeValueGenerator mFakeValueGenerator; }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h new file mode 100644 index 0000000000..7bbbb08f15 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h @@ -0,0 +1,127 @@ +/* + * 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 + +#include + +#include + +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; + + 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& 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; + + mutable std::mutex mLock; + OnHalEvent mOnHalEvent; + RecurrentTimer mRecurrentTimer; + std::unordered_map mGenCfg; +}; + + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + + +#endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_