diff options
author | Chao Yan <aceyansf@google.com> | 2018-04-17 11:32:39 -0700 |
---|---|---|
committer | Chao Yan <aceyansf@google.com> | 2018-05-10 11:05:28 -0700 |
commit | f63c2cad23924ec0f62d534bbe88350c5088d579 (patch) | |
tree | 16f437859c101b7c8c9871b0cfc83bc6834d9c11 /automotive | |
parent | adf9e18c01c3bf25858aacc380c16aa465b0ef34 (diff) | |
download | platform_hardware_interfaces-f63c2cad23924ec0f62d534bbe88350c5088d579.tar.gz platform_hardware_interfaces-f63c2cad23924ec0f62d534bbe88350c5088d579.tar.bz2 platform_hardware_interfaces-f63c2cad23924ec0f62d534bbe88350c5088d579.zip |
Added fake VHAL value generator based on JSON file
Note: It only supports a single generation task at any time. Mixed value
properties like diagnostics frame is not implemented yet. It only
supports properties with ON_CHANGE mode for now.
Bug: 76017041
Test: lunch bat_land-userdebug & m -j8; adb push <json_data>
/data/local/tmp; use python emulator to inject fake value "start" command
specifying the JSON data path on device; verify values on KitchenSink app
Change-Id: Ic964ef52a19422bab7015fe54c7e4c5ef8b47a55
Diffstat (limited to 'automotive')
9 files changed, 557 insertions, 160 deletions
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index 774bc4f8cb..22ab079f33 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -62,6 +62,8 @@ cc_library_static { "impl/vhal_v2_0/VehicleEmulator.cpp", "impl/vhal_v2_0/PipeComm.cpp", "impl/vhal_v2_0/SocketComm.cpp", + "impl/vhal_v2_0/LinearFakeValueGenerator.cpp", + "impl/vhal_v2_0/JsonFakeValueGenerator.cpp", ], local_include_dirs: ["common/include/vhal_v2_0"], export_include_dirs: ["impl"], @@ -71,6 +73,7 @@ cc_library_static { "libprotobuf-cpp-lite", ], static_libs: [ + "libjsoncpp", "libqemu_pipe", "android.hardware.automotive.vehicle@2.0-libproto-native", ], @@ -107,6 +110,7 @@ cc_binary { "android.hardware.automotive.vehicle@2.0-manager-lib", "android.hardware.automotive.vehicle@2.0-default-impl-lib", "android.hardware.automotive.vehicle@2.0-libproto-native", + "libjsoncpp", "libqemu_pipe", ], } 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 56813ce414..6236087da2 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 @@ -42,38 +42,66 @@ constexpr int WHEEL_TICK = (int)VehicleProperty::WHEEL_TICK; constexpr int ALL_WHEELS = (int)(Wheel::LEFT_FRONT | Wheel::RIGHT_FRONT | Wheel::LEFT_REAR | Wheel::RIGHT_REAR); -/* - * This property is used for test purpose to generate fake events. - * - * It has the following format: - * - * int32Values[0] - command (see FakeDataCommand below for possible values) - * int32Values[1] - VehicleProperty to which command applies +/** + * This property is used for test purpose to generate fake events. Here is the test package that + * is referencing this property definition: packages/services/Car/tests/vehiclehal_test */ const int32_t kGenerateFakeDataControllingProperty = 0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED; +/** + * FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty. + * All those commands can be send independently with each other. And each will override the one sent + * previously. + * + * The controlling property has the following format: + * + * int32Values[0] - command enum defined in FakeDataCommand + * + * The format of the arguments is defined for each command type as below: + */ enum class FakeDataCommand : int32_t { - /** Stops generating of fake data that was triggered by Start command */ - Stop = 0, - /** - * Starts fake data generation. Caller must provide additional data: + * Starts linear fake data generation. Caller must provide additional data: + * int32Values[1] - VehicleProperty to which command applies * int64Values[0] - periodic interval in nanoseconds * floatValues[0] - initial value - * floatValues[1] - dispersion defines min and max range relative to initial value + * floatValues[1] - dispersion defines the min/max value relative to initial value, where + * max = initial_value + dispersion, min = initial_value - dispersion. + * Dispersion should be non-negative, otherwise the behavior is undefined. * floatValues[2] - increment, with every timer tick the value will be incremented by this - * amount + * amount. When reaching to max value, the current value will be set to min. + * It should be non-negative, otherwise the behavior is undefined. + */ + StartLinear = 0, + + /** Stops generating of fake data that was triggered by Start commands. + * int32Values[1] - VehicleProperty to which command applies. VHAL will stop the + * corresponding linear generation for that property. + */ + StopLinear = 1, + + /** + * Starts JSON-based fake data generation. Caller must provide a string value specifying + * the path to fake value JSON file: + * stringValue - path to the fake values JSON file + */ + StartJson = 2, + + /** + * Stops JSON-based fake data generation. No additional arguments needed. */ - Start = 1, + StopJson = 3, /** * Injects key press event (HAL incorporates UP/DOWN acction and triggers 2 HAL events for every - * key-press). Caller must provide the following data: int32Values[2] - Android key code + * key-press). We set the enum with high number to leave space for future start/stop commands. + * Caller must provide the following data: + * int32Values[2] - Android key code * int32Values[3] - target display (0 - for main display, 1 - for instrument cluster, see - * VehicleDisplay) + * VehicleDisplay) */ - KeyPress = 2, + KeyPress = 100, }; const int32_t kHvacPowerProperties[] = { 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 2eb905dce1..fb54195852 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 @@ -19,6 +19,8 @@ #include <android-base/macros.h> #include "EmulatedVehicleHal.h" +#include "JsonFakeValueGenerator.h" +#include "LinearFakeValueGenerator.h" #include "Obd2SensorStore.h" namespace android { @@ -88,10 +90,12 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) : mPropStore(propStore), mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), - mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, - this, std::placeholders::_1)), - mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated, - this, std::placeholders::_1, std::placeholders::_2)) { + mRecurrentTimer( + std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), + mLinearFakeValueGenerator(std::make_unique<LinearFakeValueGenerator>( + std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))), + mJsonFakeValueGenerator(std::make_unique<JsonFakeValueGenerator>( + std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))) { initStaticConfig(); for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { mPropStore->registerProperty(kVehicleProperties[i].config); @@ -328,42 +332,29 @@ std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const { 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()); + if (!v.int32Values.size()) { + ALOGE("%s: expected at least \"command\" field in int32Values", __func__); 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::StartLinear: { + ALOGI("%s, FakeDataCommand::StartLinear", __func__); + return mLinearFakeValueGenerator->start(request); } - case FakeDataCommand::Stop: { - ALOGI("%s, FakeDataCommand::Stop", __func__); - mFakeValueGenerator.stopGeneratingHalEvents(propId); - break; + case FakeDataCommand::StartJson: { + ALOGI("%s, FakeDataCommand::StartJson", __func__); + return mJsonFakeValueGenerator->start(request); + } + case FakeDataCommand::StopLinear: { + ALOGI("%s, FakeDataCommand::StopLinear", __func__); + return mLinearFakeValueGenerator->stop(request); + } + case FakeDataCommand::StopJson: { + ALOGI("%s, FakeDataCommand::StopJson", __func__); + return mJsonFakeValueGenerator->stop(request); } case FakeDataCommand::KeyPress: { ALOGI("%s, FakeDataCommand::KeyPress", __func__); @@ -374,7 +365,6 @@ StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropVa doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display)); break; } - default: { ALOGE("%s: unexpected command: %d", __func__, command); return StatusCode::INVALID_ARG; @@ -396,30 +386,16 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp( return keyEvent; } -void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) { +void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) { + ALOGD("%s: %s", __func__, toString(value).c_str()); static constexpr bool shouldUpdateStatus = false; - 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; - - } - + VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value); if (updatedPropValue) { - updatedPropValue->prop = propId; - updatedPropValue->areaId = 0; // Add area support if necessary. updatedPropValue->timestamp = elapsedRealtimeNano(); updatedPropValue->status = VehiclePropertyStatus::AVAILABLE; mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus); - auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode; + auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode; if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) { doHalEvent(move(updatedPropValue)); } 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 d291dbad82..c188aefe20 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 @@ -30,9 +30,10 @@ #include "vhal_v2_0/VehiclePropertyStore.h" #include "DefaultConfig.h" -#include "VehicleEmulator.h" #include "FakeValueGenerator.h" +#include "VehicleEmulator.h" + namespace android { namespace hardware { namespace automotive { @@ -66,7 +67,7 @@ private: } StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); - void onFakeValueGenerated(int32_t propId, float value); + void onFakeValueGenerated(const VehiclePropValue& value); VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay); @@ -84,7 +85,8 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set<int32_t> mHvacPowerProps; RecurrentTimer mRecurrentTimer; - FakeValueGenerator mFakeValueGenerator; + std::unique_ptr<FakeValueGenerator> mLinearFakeValueGenerator; + std::unique_ptr<FakeValueGenerator> mJsonFakeValueGenerator; }; } // 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 index 7bbbb08f15..1eeb88dffe 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h @@ -14,15 +14,11 @@ * 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> +#ifndef android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_ #include <android/hardware/automotive/vehicle/2.0/types.h> -#include <vhal_v2_0/RecurrentTimer.h> - namespace android { namespace hardware { namespace automotive { @@ -31,89 +27,27 @@ 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. - }; +using OnHalEvent = std::function<void(const VehiclePropValue& event)>; +using MuxGuard = std::lock_guard<std::mutex>; +class FakeValueGenerator { 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; + virtual ~FakeValueGenerator() = default; + /** + * Starts generating VHAL events + * + * @param request in VehiclePropValue with required information to start fake data generation + * @return StatusCode of the start request + */ + virtual StatusCode start(const VehiclePropValue& request) = 0; + /** + * Stops generating VHAL events + * @param request in VehiclePropValue with required information to stop fake data generation + * @return StatusCode of the stop request + */ + virtual StatusCode stop(const VehiclePropValue& request) = 0; }; - } // impl } // namespace V2_0 @@ -122,6 +56,4 @@ private: } // namespace hardware } // namespace android - - -#endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_ +#endif // android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp new file mode 100644 index 0000000000..88b8f865c5 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2018 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 <fstream> + +#include <log/log.h> +#include <vhal_v2_0/VehicleUtils.h> + +#include "JsonFakeValueGenerator.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +JsonFakeValueGenerator::JsonFakeValueGenerator(const OnHalEvent& onHalEvent) + : mOnHalEvent(onHalEvent), mThread(&JsonFakeValueGenerator::loop, this) {} + +JsonFakeValueGenerator::~JsonFakeValueGenerator() { + mStopRequested = true; + { + MuxGuard g(mLock); + mGenCfg.index = 0; + mGenCfg.events.clear(); + } + mCond.notify_one(); + if (mThread.joinable()) { + mThread.join(); + } +} + +StatusCode JsonFakeValueGenerator::start(const VehiclePropValue& request) { + const auto& v = request.value; + if (v.stringValue.empty()) { + ALOGE("%s: path to JSON file is missing", __func__); + return StatusCode::INVALID_ARG; + } + const char* file = v.stringValue.c_str(); + std::ifstream ifs(file); + if (!ifs) { + ALOGE("%s: couldn't open %s for parsing.", __func__, file); + return StatusCode::INTERNAL_ERROR; + } + std::vector<VehiclePropValue> fakeVhalEvents = parseFakeValueJson(ifs); + + { + MuxGuard g(mLock); + mGenCfg = {0, fakeVhalEvents}; + } + mCond.notify_one(); + return StatusCode::OK; +} + +StatusCode JsonFakeValueGenerator::stop(const VehiclePropValue& request) { + const auto& v = request.value; + if (!v.stringValue.empty()) { + ALOGI("%s: %s", __func__, v.stringValue.c_str()); + } + + { + MuxGuard g(mLock); + mGenCfg.index = 0; + mGenCfg.events.clear(); + } + mCond.notify_one(); + return StatusCode::OK; +} + +std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) { + std::vector<VehiclePropValue> fakeVhalEvents; + + Json::Reader reader; + Json::Value rawEvents; + if (!reader.parse(is, rawEvents)) { + ALOGE("%s: Failed to parse fake data JSON file. Error: %s", __func__, + reader.getFormattedErrorMessages().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 = {.prop = rawEvent["prop"].asInt(), + .areaId = rawEvent["areaId"].asInt(), + .timestamp = rawEvent["timestamp"].asInt64()}; + + Json::Value rawEventValue = rawEvent["value"]; + auto& value = event.value; + 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; + default: + ALOGE("%s: unsupported type for property: 0x%x with value: %s", __func__, + event.prop, rawEventValue.asString().c_str()); + continue; + } + fakeVhalEvents.push_back(event); + } + return fakeVhalEvents; +} + +void JsonFakeValueGenerator::loop() { + static constexpr auto kInvalidTime = TimePoint(Nanos::max()); + + while (!mStopRequested) { + auto nextEventTime = kInvalidTime; + { + MuxGuard g(mLock); + if (mGenCfg.index < mGenCfg.events.size()) { + mOnHalEvent(mGenCfg.events[mGenCfg.index]); + } + if (!mGenCfg.events.empty() && mGenCfg.index < mGenCfg.events.size() - 1) { + Nanos intervalNano = + static_cast<Nanos>(mGenCfg.events[mGenCfg.index + 1].timestamp - + mGenCfg.events[mGenCfg.index].timestamp); + nextEventTime = Clock::now() + intervalNano; + } + mGenCfg.index++; + } + + std::unique_lock<std::mutex> g(mLock); + mCond.wait_until(g, nextEventTime); + } +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h new file mode 100644 index 0000000000..51da4c5383 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 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_JsonFakeValueGenerator_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_ + +#include <atomic> +#include <chrono> +#include <condition_variable> +#include <iostream> +#include <thread> + +#include <json/json.h> + +#include "FakeValueGenerator.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +class JsonFakeValueGenerator : public FakeValueGenerator { +private: + using Nanos = std::chrono::nanoseconds; + using Clock = std::chrono::steady_clock; + using TimePoint = std::chrono::time_point<Clock, Nanos>; + + struct GeneratorCfg { + size_t index; + std::vector<VehiclePropValue> events; + }; + +public: + JsonFakeValueGenerator(const OnHalEvent& onHalEvent); + ~JsonFakeValueGenerator(); + StatusCode start(const VehiclePropValue& request) override; + StatusCode stop(const VehiclePropValue& request) override; + +private: + std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is); + void loop(); + +private: + OnHalEvent mOnHalEvent; + std::thread mThread; + mutable std::mutex mLock; + std::condition_variable mCond; + GeneratorCfg mGenCfg; + std::atomic_bool mStopRequested{false}; +}; + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp new file mode 100644 index 0000000000..8cb9322fa6 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2018 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 <log/log.h> +#include <vhal_v2_0/VehicleUtils.h> + +#include "LinearFakeValueGenerator.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +LinearFakeValueGenerator::LinearFakeValueGenerator(const OnHalEvent& onHalEvent) + : mOnHalEvent(onHalEvent), + mRecurrentTimer(std::bind(&LinearFakeValueGenerator::onTimer, this, std::placeholders::_1)) {} + +StatusCode LinearFakeValueGenerator::start(const VehiclePropValue& request) { + const auto& v = request.value; + if (v.int32Values.size() < 2) { + ALOGE("%s: expected property ID in int32Values", __func__); + return StatusCode::INVALID_ARG; + } + int32_t propId = v.int32Values[1]; + + 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 elements in 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]; + + MuxGuard g(mLock); + removeLocked(propId); + mGenCfg.insert({propId, GeneratorCfg{ + .initialValue = initialValue, + .currentValue = initialValue, + .dispersion = dispersion, + .increment = increment,}}); + + mRecurrentTimer.registerRecurrentEvent(interval, propId); + return StatusCode::OK; +} + +StatusCode LinearFakeValueGenerator::stop(const VehiclePropValue& request) { + const auto& v = request.value; + if (v.int32Values.size() < 2) { + ALOGE("%s: expected property ID in int32Values", __func__); + return StatusCode::INVALID_ARG; + } + int32_t propId = v.int32Values[1]; + + MuxGuard g(mLock); + if (propId == 0) { + // Remove all. + for (auto&& it : mGenCfg) { + removeLocked(it.first); + } + } else { + removeLocked(propId); + } + return StatusCode::OK; +} + +void LinearFakeValueGenerator::removeLocked(int propId) { + if (mGenCfg.erase(propId)) { + mRecurrentTimer.unregisterRecurrentEvent(propId); + } +} + +void LinearFakeValueGenerator::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; + } + VehiclePropValue event = {.prop = propId}; + auto& value = event.value; + switch (getPropType(event.prop)) { + case VehiclePropertyType::INT32: + value.int32Values.resize(1); + value.int32Values[0] = static_cast<int32_t>(cfg.currentValue); + break; + case VehiclePropertyType::INT64: + value.int64Values.resize(1); + value.int64Values[0] = static_cast<int64_t>(cfg.currentValue); + break; + case VehiclePropertyType::FLOAT: + value.floatValues.resize(1); + value.floatValues[0] = cfg.currentValue; + break; + default: + ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop); + continue; + } + mOnHalEvent(event); + } +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h new file mode 100644 index 0000000000..fe6d097962 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 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_LinearFakeValueGenerator_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_ + +#include <vhal_v2_0/RecurrentTimer.h> + +#include "FakeValueGenerator.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +class LinearFakeValueGenerator : public 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: + LinearFakeValueGenerator(const OnHalEvent& onHalEvent); + ~LinearFakeValueGenerator() = default; + StatusCode start(const VehiclePropValue& request) override; + StatusCode stop(const VehiclePropValue& request) override; + +private: + void removeLocked(int propId); + void onTimer(const std::vector<int32_t>& properties); + +private: + mutable std::mutex mLock; + OnHalEvent mOnHalEvent; + RecurrentTimer mRecurrentTimer; + std::unordered_map<int32_t, GeneratorCfg> mGenCfg; +}; + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_ |