Added support for multiple VHAL generators
Using priority queue to schedule multiple VHAL event generators
Bug: 76017041
Test: atest VehicleHALTest
Change-Id: I6bc8071cafd12334dfe37d4f3808530836aec4df
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 22ab079..65e9133 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -64,6 +64,7 @@
"impl/vhal_v2_0/SocketComm.cpp",
"impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
"impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
+ "impl/vhal_v2_0/GeneratorHub.cpp",
],
local_include_dirs: ["common/include/vhal_v2_0"],
export_include_dirs: ["impl"],
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 4ae94c0..77885c5 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
@@ -68,33 +68,39 @@
enum class FakeDataCommand : int32_t {
/**
* Starts linear fake data generation. Caller must provide additional data:
- * int32Values[1] - VehicleProperty to which command applies
+ * int32Values[1] - vehicle property to which command applies
* int64Values[0] - periodic interval in nanoseconds
* floatValues[0] - 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. When reaching to max value, the current value will be set to min.
- * It should be non-negative, otherwise the behavior is undefined.
+ * 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
+ /** Stops linear fake data generation that was triggered by StartLinear commands.
+ * int32Values[1] - vehicle property 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:
+ * Starts JSON-based fake data generation. It iterates through JSON-encoded VHAL events from a
+ * file and inject them to VHAL. The iteration can be repeated multiple times or infinitely.
+ * Caller must provide additional data:
+ * int32Values[1] - number of iterations. If it is not provided or -1. The iteration will be
+ * repeated infinite times.
* stringValue - path to the fake values JSON file
*/
StartJson = 2,
/**
- * Stops JSON-based fake data generation. No additional arguments needed.
+ * Stops JSON-based fake data generation. As multiple JSON-based generation can happen at the
+ * same time. Caller must provide the path of fake value JSON file to stop the corresponding
+ * generation:
+ * stringValue - path to the fake values JSON file
*/
StopJson = 3,
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 07695bf..0e5897a 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
@@ -92,10 +92,8 @@
mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
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))) {
+ mGeneratorHub(
+ std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
initStaticConfig();
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -343,19 +341,54 @@
switch (command) {
case FakeDataCommand::StartLinear: {
ALOGI("%s, FakeDataCommand::StartLinear", __func__);
- return mLinearFakeValueGenerator->start(request);
+ if (v.int32Values.size() < 2) {
+ ALOGE("%s: expected property ID in int32Values", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ if (!v.int64Values.size()) {
+ ALOGE("%s: interval is not provided in int64Values", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ if (v.floatValues.size() < 3) {
+ ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
+ v.floatValues.size());
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = v.int32Values[1];
+ mGeneratorHub.registerGenerator(cookie,
+ std::make_unique<LinearFakeValueGenerator>(request));
+ break;
}
case FakeDataCommand::StartJson: {
ALOGI("%s, FakeDataCommand::StartJson", __func__);
- return mJsonFakeValueGenerator->start(request);
+ if (v.stringValue.empty()) {
+ ALOGE("%s: path to JSON file is missing", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = std::hash<std::string>()(v.stringValue);
+ mGeneratorHub.registerGenerator(cookie,
+ std::make_unique<JsonFakeValueGenerator>(request));
+ break;
}
case FakeDataCommand::StopLinear: {
ALOGI("%s, FakeDataCommand::StopLinear", __func__);
- return mLinearFakeValueGenerator->stop(request);
+ if (v.int32Values.size() < 2) {
+ ALOGE("%s: expected property ID in int32Values", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = v.int32Values[1];
+ mGeneratorHub.unregisterGenerator(cookie);
+ break;
}
case FakeDataCommand::StopJson: {
ALOGI("%s, FakeDataCommand::StopJson", __func__);
- return mJsonFakeValueGenerator->stop(request);
+ if (v.stringValue.empty()) {
+ ALOGE("%s: path to JSON file is missing", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = std::hash<std::string>()(v.stringValue);
+ mGeneratorHub.unregisterGenerator(cookie);
+ break;
}
case FakeDataCommand::KeyPress: {
ALOGI("%s, FakeDataCommand::KeyPress", __func__);
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 c188aef..ec59690 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,8 +30,7 @@
#include "vhal_v2_0/VehiclePropertyStore.h"
#include "DefaultConfig.h"
-#include "FakeValueGenerator.h"
-
+#include "GeneratorHub.h"
#include "VehicleEmulator.h"
namespace android {
@@ -85,8 +84,7 @@
VehiclePropertyStore* mPropStore;
std::unordered_set<int32_t> mHvacPowerProps;
RecurrentTimer mRecurrentTimer;
- std::unique_ptr<FakeValueGenerator> mLinearFakeValueGenerator;
- std::unique_ptr<FakeValueGenerator> mJsonFakeValueGenerator;
+ GeneratorHub mGeneratorHub;
};
} // 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 1eeb88d..d6ad77d 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
@@ -27,28 +27,22 @@
namespace impl {
-using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
-using MuxGuard = std::lock_guard<std::mutex>;
-
class FakeValueGenerator {
public:
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;
+
+ virtual VehiclePropValue nextEvent() = 0;
+
+ virtual bool hasNext() = 0;
};
-} // impl
+using Clock = std::chrono::steady_clock;
+using Nanos = std::chrono::nanoseconds;
+using TimePoint = std::chrono::time_point<Clock, Nanos>;
+
+using FakeValueGeneratorPtr = std::unique_ptr<FakeValueGenerator>;
+
+} // namespace impl
} // namespace V2_0
} // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
new file mode 100644
index 0000000..548285a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 "GeneratorHub"
+
+#include <log/log.h>
+
+#include "GeneratorHub.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+GeneratorHub::GeneratorHub(const OnHalEvent& onHalEvent)
+ : mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {}
+
+void GeneratorHub::registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator) {
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ // Register only if the generator can produce event
+ if (generator->hasNext()) {
+ // Push the next event if it is a new generator
+ if (mGenerators.find(cookie) == mGenerators.end()) {
+ ALOGI("%s: Registering new generator, cookie: %d", __func__, cookie);
+ mEventQueue.push({cookie, generator->nextEvent()});
+ }
+ mGenerators[cookie] = std::move(generator);
+ ALOGI("%s: Registered generator, cookie: %d", __func__, cookie);
+ }
+ }
+ mCond.notify_one();
+}
+
+void GeneratorHub::unregisterGenerator(int32_t cookie) {
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ mGenerators.erase(cookie);
+ }
+ mCond.notify_one();
+ ALOGI("%s: Unregistered generator, cookie: %d", __func__, cookie);
+}
+
+void GeneratorHub::run() {
+ while (true) {
+ std::unique_lock<std::mutex> g(mLock);
+ // Pop events whose generator does not exist (may be already unregistered)
+ while (!mEventQueue.empty()
+ && mGenerators.find(mEventQueue.top().cookie) == mGenerators.end()) {
+ mEventQueue.pop();
+ }
+ // Wait until event queue is not empty
+ mCond.wait(g, [this] { return !mEventQueue.empty(); });
+
+ const VhalEvent& curEvent = mEventQueue.top();
+
+ TimePoint eventTime(Nanos(curEvent.val.timestamp));
+ // Wait until the soonest event happen
+ if (mCond.wait_until(g, eventTime) != std::cv_status::timeout) {
+ // It is possible that a new generator is registered and produced a sooner event, or current
+ // generator is unregistered, in this case the thread will re-evaluate the soonest event
+ ALOGI("Something happened while waiting");
+ continue;
+ }
+ // Now it's time to handle current event.
+ mOnHalEvent(curEvent.val);
+ // Update queue by popping current event and producing next event from the same generator
+ int32_t cookie = curEvent.cookie;
+ mEventQueue.pop();
+ if (hasNext(cookie)) {
+ mEventQueue.push({cookie, mGenerators[cookie]->nextEvent()});
+ } else {
+ ALOGI("%s: Generator ended, unregister it, cookie: %d", __func__, cookie);
+ mGenerators.erase(cookie);
+ }
+ }
+}
+
+bool GeneratorHub::hasNext(int32_t cookie) {
+ return mGenerators.find(cookie) != mGenerators.end() && mGenerators[cookie]->hasNext();
+}
+
+} // 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/GeneratorHub.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
new file mode 100644
index 0000000..dcf6a4f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
@@ -0,0 +1,97 @@
+/*
+ * 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_GeneratorHub_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <iostream>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+
+#include "FakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * This is the scheduler for all VHAL event generators. It manages all generators and uses priority
+ * queue to maintain generated events ordered by timestamp. The scheduler uses a single thread to
+ * keep querying and updating the event queue to make sure events from all generators are produced
+ * in order.
+ */
+class GeneratorHub {
+private:
+ struct VhalEvent {
+ int32_t cookie; // Cookie is used to find the associated generator.
+ VehiclePropValue val;
+ };
+ // Comparator used by priority queue to keep track of soonest event.
+ struct GreaterByTime {
+ bool operator()(const VhalEvent& lhs, const VhalEvent& rhs) const {
+ return lhs.val.timestamp > rhs.val.timestamp;
+ }
+ };
+
+ using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
+
+public:
+ GeneratorHub(const OnHalEvent& onHalEvent);
+ ~GeneratorHub() = default;
+
+ /**
+ * Register a new generator. The generator will be discarded if it could not produce next event.
+ * The existing generator will be overridden if it has the same cookie.
+ */
+ void registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator);
+
+ void unregisterGenerator(int32_t cookie);
+
+private:
+ /**
+ * Main loop of the single thread to producing event and updating event queue.
+ */
+ void run();
+
+ bool hasNext(int32_t cookie);
+
+private:
+ std::priority_queue<VhalEvent, std::vector<VhalEvent>, GreaterByTime> mEventQueue;
+ std::unordered_map<int32_t, FakeValueGeneratorPtr> mGenerators;
+ OnHalEvent mOnHalEvent;
+
+ mutable std::mutex mLock;
+ std::condition_variable mCond;
+ std::thread mThread;
+};
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_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
index 88b8f86..c293c0a 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -31,57 +31,48 @@
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) {
+JsonFakeValueGenerator::JsonFakeValueGenerator(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;
+ mGenCfg = {
+ .index = 0,
+ .events = parseFakeValueJson(ifs),
+ };
+ // Iterate infinitely if repetition number is not provided
+ mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1];
}
-StatusCode JsonFakeValueGenerator::stop(const VehiclePropValue& request) {
- const auto& v = request.value;
- if (!v.stringValue.empty()) {
- ALOGI("%s: %s", __func__, v.stringValue.c_str());
+VehiclePropValue JsonFakeValueGenerator::nextEvent() {
+ VehiclePropValue generatedValue;
+ if (!hasNext()) {
+ return generatedValue;
}
+ TimePoint eventTime = Clock::now();
+ if (mGenCfg.index != 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.
+ eventTime += Nanos(mGenCfg.events[mGenCfg.index].timestamp -
+ mGenCfg.events[mGenCfg.index - 1].timestamp);
+ }
+ generatedValue = mGenCfg.events[mGenCfg.index];
+ generatedValue.timestamp = eventTime.time_since_epoch().count();
- {
- MuxGuard g(mLock);
+ mGenCfg.index++;
+ if (mGenCfg.index == mGenCfg.events.size()) {
mGenCfg.index = 0;
- mGenCfg.events.clear();
+ if (mNumOfIterations > 0) {
+ mNumOfIterations--;
+ }
}
- mCond.notify_one();
- return StatusCode::OK;
+ return generatedValue;
+}
+
+bool JsonFakeValueGenerator::hasNext() {
+ return mNumOfIterations != 0 && mGenCfg.events.size() > 0;
}
std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) {
@@ -141,30 +132,6 @@
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
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
index 51da4c5..43c8b9d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
@@ -17,11 +17,8 @@
#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>
@@ -37,32 +34,25 @@
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;
+ JsonFakeValueGenerator(const VehiclePropValue& request);
+ ~JsonFakeValueGenerator() = default;
+
+ VehiclePropValue nextEvent();
+
+ bool hasNext();
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};
+ int32_t mNumOfIterations;
};
} // namespace impl
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
index 8cb9322..7bdc97c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
@@ -29,101 +29,48 @@
namespace impl {
-LinearFakeValueGenerator::LinearFakeValueGenerator(const OnHalEvent& onHalEvent)
- : mOnHalEvent(onHalEvent),
- mRecurrentTimer(std::bind(&LinearFakeValueGenerator::onTimer, this, std::placeholders::_1)) {}
-
-StatusCode LinearFakeValueGenerator::start(const VehiclePropValue& request) {
+LinearFakeValueGenerator::LinearFakeValueGenerator(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;
+ mGenCfg = GeneratorCfg{
+ .propId = v.int32Values[1],
+ .initialValue = v.floatValues[0],
+ .currentValue = v.floatValues[0],
+ .dispersion = v.floatValues[1],
+ .increment = v.floatValues[2],
+ .interval = Nanos(v.int64Values[0]),
+ };
}
-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;
+VehiclePropValue LinearFakeValueGenerator::nextEvent() {
+ mGenCfg.currentValue += mGenCfg.increment;
+ if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) {
+ mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion;
}
- int32_t propId = v.int32Values[1];
-
- MuxGuard g(mLock);
- if (propId == 0) {
- // Remove all.
- for (auto&& it : mGenCfg) {
- removeLocked(it.first);
- }
- } else {
- removeLocked(propId);
+ VehiclePropValue event = {.prop = mGenCfg.propId};
+ auto& value = event.value;
+ switch (getPropType(event.prop)) {
+ case VehiclePropertyType::INT32:
+ value.int32Values.resize(1);
+ value.int32Values[0] = static_cast<int32_t>(mGenCfg.currentValue);
+ break;
+ case VehiclePropertyType::INT64:
+ value.int64Values.resize(1);
+ value.int64Values[0] = static_cast<int64_t>(mGenCfg.currentValue);
+ break;
+ case VehiclePropertyType::FLOAT:
+ value.floatValues.resize(1);
+ value.floatValues[0] = mGenCfg.currentValue;
+ break;
+ default:
+ ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop);
}
- return StatusCode::OK;
+ TimePoint eventTime = Clock::now() + mGenCfg.interval;
+ event.timestamp = eventTime.time_since_epoch().count();
+ return event;
}
-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);
- }
+bool LinearFakeValueGenerator::hasNext() {
+ return true;
}
} // namespace impl
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
index fe6d097..d3b666d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
@@ -17,8 +17,6 @@
#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 {
@@ -36,27 +34,24 @@
// to the client.
struct GeneratorCfg {
- float initialValue; //
+ int32_t propId;
+ 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.
+ Nanos interval;
};
public:
- LinearFakeValueGenerator(const OnHalEvent& onHalEvent);
+ LinearFakeValueGenerator(const VehiclePropValue& request);
~LinearFakeValueGenerator() = default;
- StatusCode start(const VehiclePropValue& request) override;
- StatusCode stop(const VehiclePropValue& request) override;
+
+ VehiclePropValue nextEvent();
+
+ bool hasNext();
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;
+ GeneratorCfg mGenCfg;
};
} // namespace impl