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:
Pavel Maltsev 2017-04-17 21:23:51 +00:00 committed by android-build-merger
commit 753f3b0d1e
4 changed files with 264 additions and 1 deletions

View file

@ -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,
},
}
};

View file

@ -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

View file

@ -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

View file

@ -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_