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
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 bf16a9b..c4f935b 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 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),
@@ -64,6 +83,24 @@
{
.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),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -284,6 +321,14 @@
.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 0ac6ada..ea40cc5 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 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 @@
}
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 @@
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
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 e0874e2..009485d 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 @@
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;
@@ -74,6 +78,7 @@
VehiclePropertyStore* mPropStore;
std::unordered_set<int32_t> 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 0000000..7bbbb08
--- /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 <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_