Merge "Adding a custom property to the default VHAL impl" into oc-dev am: 69c42429d1
am: 7bac03deb2
Change-Id: I1ece0ab7a50274e4957155e01d4db50b9b52e645
This commit is contained in:
commit
753f3b0d1e
4 changed files with 264 additions and 1 deletions
|
@ -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,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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<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
|
||||
|
|
|
@ -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<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 @@ private:
|
|||
VehiclePropertyStore* mPropStore;
|
||||
std::unordered_set<int32_t> mHvacPowerProps;
|
||||
RecurrentTimer mRecurrentTimer;
|
||||
FakeValueGenerator mFakeValueGenerator;
|
||||
};
|
||||
|
||||
} // impl
|
||||
|
|
|
@ -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_
|
Loading…
Reference in a new issue