Merge changes from topic 'vhal-def-refactor' into oc-dev

am: ccc1d2e736

Change-Id: If3ebe7e1c54a2bc68b4ba0065ba3b62eb158b02e
This commit is contained in:
Pavel Maltsev 2017-04-06 07:05:39 +00:00 committed by android-build-merger
commit 3e942409a9
19 changed files with 1403 additions and 1201 deletions

View file

@ -25,6 +25,7 @@ LOCAL_SRC_FILES := \
common/src/SubscriptionManager.cpp \
common/src/VehicleHalManager.cpp \
common/src/VehicleObjectPool.cpp \
common/src/VehiclePropertyStore.cpp \
common/src/VehicleUtils.cpp \
LOCAL_C_INCLUDES := \
@ -72,9 +73,10 @@ include $(CLEAR_VARS)
LOCAL_MODULE:= $(vhal_v2_0)-default-impl-lib
LOCAL_SRC_FILES:= \
impl/vhal_v2_0/DefaultVehicleHal.cpp \
impl/vhal_v2_0/EmulatedVehicleHal.cpp \
impl/vhal_v2_0/VehicleEmulator.cpp \
impl/vhal_v2_0/PipeComm.cpp \
impl/vhal_v2_0/SocketComm.cpp
impl/vhal_v2_0/SocketComm.cpp \
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/impl/vhal_v2_0

View file

@ -21,14 +21,16 @@
#include <iostream>
#include <vhal_v2_0/VehicleHalManager.h>
#include <vhal_v2_0/DefaultVehicleHal.h>
#include <vhal_v2_0/EmulatedVehicleHal.h>
using namespace android;
using namespace android::hardware;
using namespace android::hardware::automotive::vehicle::V2_0;
int main(int /* argc */, char* /* argv */ []) {
auto hal = std::make_unique<impl::DefaultVehicleHal>();
auto store = std::make_unique<VehiclePropertyStore>();
auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());
auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
auto service = std::make_unique<VehicleHalManager>(hal.get());
configureRpcThreadpool(1, true /* callerWillJoin */);

View file

@ -0,0 +1,104 @@
/*
* 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_PropertyDb_H_
#define android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_
#include <cstdint>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
/**
* Encapsulates work related to storing and accessing configuration, storing and modifying
* vehicle property values.
*
* VehiclePropertyValues stored in a sorted map thus it makes easier to get range of values, e.g.
* to get value for all areas for particular property.
*
* This class is thread-safe, however it uses blocking synchronization across all methods.
*/
class VehiclePropertyStore {
public:
/* Function that used to calculate unique token for given VehiclePropValue */
using TokenFunction = std::function<int64_t(const VehiclePropValue& value)>;
private:
struct RecordConfig {
VehiclePropConfig propConfig;
TokenFunction tokenFunction;
};
struct RecordId {
int32_t prop;
int32_t area;
int64_t token;
bool operator==(const RecordId& other) const;
bool operator<(const RecordId& other) const;
};
using PropertyMap = std::map<RecordId, VehiclePropValue>;
using PropertyMapRange = std::pair<PropertyMap::const_iterator, PropertyMap::const_iterator>;
public:
void registerProperty(const VehiclePropConfig& config, TokenFunction tokenFunc = nullptr);
/* Stores provided value. Returns true if value was written returns false if config for
* example wasn't registered. */
bool writeValue(const VehiclePropValue& propValue);
void removeValue(const VehiclePropValue& propValue);
void removeValuesForProperty(int32_t propId);
std::vector<VehiclePropValue> readAllValues() const;
std::vector<VehiclePropValue> readValuesForProperty(int32_t propId) const;
std::unique_ptr<VehiclePropValue> readValueOrNull(const VehiclePropValue& request) const;
std::unique_ptr<VehiclePropValue> readValueOrNull(int32_t prop, int32_t area = 0,
int64_t token = 0) const;
std::vector<VehiclePropConfig> getAllConfigs() const;
const VehiclePropConfig* getConfigOrNull(int32_t propId) const;
const VehiclePropConfig* getConfigOrDie(int32_t propId) const;
private:
RecordId getRecordIdLocked(const VehiclePropValue& valuePrototype) const;
const VehiclePropValue* getValueOrNullLocked(const RecordId& recId) const;
PropertyMapRange findRangeLocked(int32_t propId) const;
private:
using MuxGuard = std::lock_guard<std::mutex>;
mutable std::mutex mLock;
std::unordered_map<int32_t /* VehicleProperty */, RecordConfig> mConfigs;
PropertyMap mPropertyValues; // Sorted map of RecordId : VehiclePropValue.
};
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android
#endif //android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_

View file

@ -0,0 +1,172 @@
/*
* 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.
*/
#define LOG_TAG "VehiclePropertyStore"
#include <android/log.h>
#include <common/include/vhal_v2_0/VehicleUtils.h>
#include "VehiclePropertyStore.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
return prop == other.prop && area == other.area && token == other.token;
}
bool VehiclePropertyStore::RecordId::operator<(const VehiclePropertyStore::RecordId& other) const {
return prop < other.prop
|| (prop == other.prop && area < other.area)
|| (prop == other.prop && area == other.area && token < other.token);
}
void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
VehiclePropertyStore::TokenFunction tokenFunc) {
MuxGuard g(mLock);
mConfigs.insert({ config.prop, RecordConfig { config, tokenFunc } });
}
bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue) {
MuxGuard g(mLock);
if (!mConfigs.count(propValue.prop)) return false;
RecordId recId = getRecordIdLocked(propValue);
VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
if (valueToUpdate == nullptr) {
mPropertyValues.insert({ recId, propValue });
} else {
valueToUpdate->timestamp = propValue.timestamp;
valueToUpdate->value = propValue.value;
}
return true;
}
void VehiclePropertyStore::removeValue(const VehiclePropValue& propValue) {
MuxGuard g(mLock);
RecordId recId = getRecordIdLocked(propValue);
auto it = mPropertyValues.find(recId);
if (it != mPropertyValues.end()) {
mPropertyValues.erase(it);
}
}
void VehiclePropertyStore::removeValuesForProperty(int32_t propId) {
MuxGuard g(mLock);
auto range = findRangeLocked(propId);
mPropertyValues.erase(range.first, range.second);
}
std::vector<VehiclePropValue> VehiclePropertyStore::readAllValues() const {
MuxGuard g(mLock);
std::vector<VehiclePropValue> allValues;
allValues.reserve(mPropertyValues.size());
for (auto&& it : mPropertyValues) {
allValues.push_back(it.second);
}
return allValues;
}
std::vector<VehiclePropValue> VehiclePropertyStore::readValuesForProperty(int32_t propId) const {
std::vector<VehiclePropValue> values;
MuxGuard g(mLock);
auto range = findRangeLocked(propId);
for (auto it = range.first; it != range.second; ++it) {
values.push_back(it->second);
}
return values;
}
std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
const VehiclePropValue& request) const {
MuxGuard g(mLock);
RecordId recId = getRecordIdLocked(request);
const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
}
std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
int32_t prop, int32_t area, int64_t token) const {
RecordId recId = {prop, isGlobalProp(prop) ? 0 : area, token };
MuxGuard g(mLock);
const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
}
std::vector<VehiclePropConfig> VehiclePropertyStore::getAllConfigs() const {
MuxGuard g(mLock);
std::vector<VehiclePropConfig> configs;
configs.reserve(mConfigs.size());
for (auto&& recordConfigIt: mConfigs) {
configs.push_back(recordConfigIt.second.propConfig);
}
return configs;
}
const VehiclePropConfig* VehiclePropertyStore::getConfigOrNull(int32_t propId) const {
MuxGuard g(mLock);
auto recordConfigIt = mConfigs.find(propId);
return recordConfigIt != mConfigs.end() ? &recordConfigIt->second.propConfig : nullptr;
}
const VehiclePropConfig* VehiclePropertyStore::getConfigOrDie(int32_t propId) const {
auto cfg = getConfigOrNull(propId);
if (!cfg) {
ALOGW("%s: config not found for property: 0x%x", __func__, propId);
abort();
}
return cfg;
}
VehiclePropertyStore::RecordId VehiclePropertyStore::getRecordIdLocked(
const VehiclePropValue& valuePrototype) const {
RecordId recId = {
.prop = valuePrototype.prop,
.area = isGlobalProp(valuePrototype.prop) ? 0 : valuePrototype.areaId,
.token = 0
};
auto it = mConfigs.find(recId.prop);
if (it == mConfigs.end()) return {};
if (it->second.tokenFunction != nullptr) {
recId.token = it->second.tokenFunction(valuePrototype);
}
return recId;
}
const VehiclePropValue* VehiclePropertyStore::getValueOrNullLocked(
const VehiclePropertyStore::RecordId& recId) const {
auto it = mPropertyValues.find(recId);
return it == mPropertyValues.end() ? nullptr : &it->second;
}
VehiclePropertyStore::PropertyMapRange VehiclePropertyStore::findRangeLocked(int32_t propId) const {
// Based on the fact that mPropertyValues is a sorted map by RecordId.
auto beginIt = mPropertyValues.lower_bound( RecordId { propId, INT32_MIN, 0 });
auto endIt = mPropertyValues.lower_bound( RecordId { propId + 1, INT32_MIN, 0 });
return PropertyMapRange { beginIt, endIt };
}
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android

View file

@ -33,176 +33,257 @@ const int32_t kHvacPowerProperties[] = {
toInt(VehicleProperty::HVAC_FAN_DIRECTION),
};
const VehiclePropConfig kVehicleProperties[] = {
struct ConfigDeclaration {
VehiclePropConfig config;
/* This value will be used as an initial value for the property. If this field is specified for
* property that supports multiple areas then it will be used for all areas unless particular
* area is overridden in initialAreaValue field. */
VehiclePropValue::RawValue initialValue;
/* Use initialAreaValues if it is necessary to specify different values per each area. */
std::map<int32_t, VehiclePropValue::RawValue> initialAreaValues;
};
const ConfigDeclaration kVehicleProperties[] {
{
.prop = toInt(VehicleProperty::INFO_MAKE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
.config = {
.prop = toInt(VehicleProperty::INFO_MAKE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
.initialValue = { .stringValue = "Toy Vehicle" }
},
{
.config = {
.prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .floatValues = {0.0f} }
},
{
.prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.config = {
.prop = toInt(VehicleProperty::CURRENT_GEAR),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .int32Values = { toInt(VehicleGear::GEAR_PARK) } }
},
{
.prop = toInt(VehicleProperty::CURRENT_GEAR),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.config = {
.prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .int32Values = {1} }
},
{
.prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.config = {
.prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .int32Values = {0} }
},
{
.prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.config = {
.prop = toInt(VehicleProperty::HVAC_POWER_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1),
// TODO(bryaneyler): Ideally, this is generated dynamically from
// kHvacPowerProperties.
.configString = "0x12400500,0x12400501" // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION
},
.initialValue = { .int32Values = {1} }
},
{
.prop = toInt(VehicleProperty::HVAC_POWER_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1),
// TODO(bryaneyler): Ideally, this is generated dynamically from
// kHvacPowerProperties.
.configString = "0x12400500,0x12400501" // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION
.config = {
.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas =
VehicleAreaWindow::FRONT_WINDSHIELD
| VehicleAreaWindow::REAR_WINDSHIELD
},
.initialValue = { .int32Values = {0} } // Will be used for all areas.
},
{
.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas =
VehicleAreaWindow::FRONT_WINDSHIELD
| VehicleAreaWindow::REAR_WINDSHIELD
.config = {
.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1)
},
.initialValue = { .int32Values = {1} }
},
{
.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1)
.config = {
.prop = toInt(VehicleProperty::HVAC_AC_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1)
},
.initialValue = { .int32Values = {1} }
},
{
.prop = toInt(VehicleProperty::HVAC_AC_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1)
.config = {
.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1)
},
.initialValue = { .int32Values = {1} }
},
{
.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1)
.config = {
.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1),
.areaConfigs = {
VehicleAreaConfig {
.areaId = toInt(VehicleAreaZone::ROW_1),
.minInt32Value = 1,
.maxInt32Value = 7
}
}
},
.initialValue = { .int32Values = {3} }
},
{
.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1),
.areaConfigs = {
VehicleAreaConfig {
.areaId = toInt(VehicleAreaZone::ROW_1),
.minInt32Value = 1,
.maxInt32Value = 7
.config = {
.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1),
},
.initialValue = { .int32Values = { toInt(VehicleHvacFanDirection::FACE) } }
},
{
.config = {
.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas =
VehicleAreaZone::ROW_1_LEFT
| VehicleAreaZone::ROW_1_RIGHT,
.areaConfigs = {
VehicleAreaConfig {
.areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
.minFloatValue = 16,
.maxFloatValue = 32,
},
VehicleAreaConfig {
.areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
.minFloatValue = 16,
.maxFloatValue = 32,
}
}
},
.initialAreaValues = {
{
toInt(VehicleAreaZone::ROW_1_LEFT),
{ .floatValues = {16} }
}, {
toInt(VehicleAreaZone::ROW_1_RIGHT),
{ .floatValues = {20} }
}
}
},
{
.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas = toInt(VehicleAreaZone::ROW_1),
.config = {
.prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
.access = VehiclePropertyAccess::READ,
// TODO(bryaneyler): Support ON_CHANGE as well.
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 1.0f,
.maxSampleRate = 2.0f,
},
.initialValue = { .floatValues = {25.0f} }
},
{
.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.supportedAreas =
VehicleAreaZone::ROW_1_LEFT
| VehicleAreaZone::ROW_1_RIGHT,
.areaConfigs = {
VehicleAreaConfig {
.areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
.minFloatValue = 16,
.maxFloatValue = 32,
},
VehicleAreaConfig {
.areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
.minFloatValue = 16,
.maxFloatValue = 32,
.config = {
.prop = toInt(VehicleProperty::NIGHT_MODE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .int32Values = {0} }
},
{
.config = {
.prop = toInt(VehicleProperty::DRIVING_STATUS),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .int32Values = { toInt(VehicleDrivingStatus::UNRESTRICTED) } }
},
{
.config = {
.prop = toInt(VehicleProperty::GEAR_SELECTION),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .int32Values = { toInt(VehicleGear::GEAR_PARK) } }
},
{
.config = {
.prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
.initialValue = { .floatValues = { 123000.0f } } // In Milliliters
},
{
.config = {
.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.areaConfigs = {
VehicleAreaConfig {
.minInt32Value = 0,
.maxInt32Value = 10
}
}
}
},
.initialValue = { .int32Values = {7} }
},
{
.prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
.access = VehiclePropertyAccess::READ,
// TODO(bryaneyler): Support ON_CHANGE as well.
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 1.0f,
.maxSampleRate = 2.0f,
.config = {
.prop = toInt(VehicleProperty::IGNITION_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = { .int32Values = { toInt(VehicleIgnitionState::ON) } }
},
{
.prop = toInt(VehicleProperty::NIGHT_MODE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
{
.prop = toInt(VehicleProperty::DRIVING_STATUS),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
{
.prop = toInt(VehicleProperty::GEAR_SELECTION),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
{
.prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
{
.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.areaConfigs = {
VehicleAreaConfig {
.minInt32Value = 0,
.maxInt32Value = 10
}
}
},
{
.prop = toInt(VehicleProperty::IGNITION_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
{
.prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
.maxSampleRate = 10, // 10 Hz, every 100 ms
.config = {
.prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
.maxSampleRate = 10, // 10 Hz, every 100 ms
},
.initialValue = { .floatValues = {101.0f} }
}
};

View file

@ -1,689 +0,0 @@
/*
* Copyright (C) 2016 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 "DefaultVehicleHal_v2_0"
#include <android/log.h>
#include <algorithm>
#include <android-base/properties.h>
#include <cstdio>
#include "DefaultVehicleHal.h"
#include "PipeComm.h"
#include "SocketComm.h"
#include "VehicleHalProto.pb.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
void DefaultVehicleHal::doGetConfig(emulator::EmulatorMessage& rxMsg,
emulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = listProperties();
emulator::VehiclePropGet getProp = rxMsg.prop(0);
respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
for (auto& config : configs) {
// Find the config we are looking for
if (config.prop == getProp.prop()) {
emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
respMsg.set_status(emulator::RESULT_OK);
break;
}
}
}
void DefaultVehicleHal::doGetConfigAll(emulator::EmulatorMessage& /* rxMsg */,
emulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = listProperties();
respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
respMsg.set_status(emulator::RESULT_OK);
for (auto& config : configs) {
emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
}
}
void DefaultVehicleHal::doGetProperty(emulator::EmulatorMessage& rxMsg,
emulator::EmulatorMessage& respMsg) {
int32_t areaId = 0;
emulator::VehiclePropGet getProp = rxMsg.prop(0);
int32_t propId = getProp.prop();
emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
VehiclePropValue* val;
respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
if (getProp.has_area_id()) {
areaId = getProp.area_id();
}
{
std::lock_guard<std::mutex> lock(mPropsMutex);
val = getVehiclePropValueLocked(propId, areaId);
if (val != nullptr) {
emulator::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, val);
status = emulator::RESULT_OK;
}
}
respMsg.set_status(status);
}
void DefaultVehicleHal::doGetPropertyAll(emulator::EmulatorMessage& /* rxMsg */,
emulator::EmulatorMessage& respMsg) {
respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
respMsg.set_status(emulator::RESULT_OK);
{
std::lock_guard<std::mutex> lock(mPropsMutex);
for (auto& prop : mProps) {
emulator::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, prop.second->get());
}
}
}
void DefaultVehicleHal::doSetProperty(emulator::EmulatorMessage& rxMsg,
emulator::EmulatorMessage& respMsg) {
emulator::VehiclePropValue protoVal = rxMsg.value(0);
VehiclePropValue val;
respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
val.prop = protoVal.prop();
val.areaId = protoVal.area_id();
val.timestamp = elapsedRealtimeNano();
// Copy value data if it is set. This automatically handles complex data types if needed.
if (protoVal.has_string_value()) {
val.value.stringValue = protoVal.string_value().c_str();
}
if (protoVal.has_bytes_value()) {
std::vector<uint8_t> tmp(protoVal.bytes_value().begin(), protoVal.bytes_value().end());
val.value.bytes = tmp;
}
if (protoVal.int32_values_size() > 0) {
std::vector<int32_t> int32Values = std::vector<int32_t>(protoVal.int32_values_size());
for (int i=0; i<protoVal.int32_values_size(); i++) {
int32Values[i] = protoVal.int32_values(i);
}
val.value.int32Values = int32Values;
}
if (protoVal.int64_values_size() > 0) {
std::vector<int64_t> int64Values = std::vector<int64_t>(protoVal.int64_values_size());
for (int i=0; i<protoVal.int64_values_size(); i++) {
int64Values[i] = protoVal.int64_values(i);
}
val.value.int64Values = int64Values;
}
if (protoVal.float_values_size() > 0) {
std::vector<float> floatValues = std::vector<float>(protoVal.float_values_size());
for (int i=0; i<protoVal.float_values_size(); i++) {
floatValues[i] = protoVal.float_values(i);
}
val.value.floatValues = floatValues;
}
if (updateProperty(val) == StatusCode::OK) {
// Send property up to VehicleHalManager via callback
auto& pool = *getValuePool();
VehiclePropValuePtr v = pool.obtain(val);
doHalEvent(std::move(v));
respMsg.set_status(emulator::RESULT_OK);
} else {
respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
}
}
// This function should only be called while mPropsMutex is locked.
VehiclePropValue* DefaultVehicleHal::getVehiclePropValueLocked(int32_t propId, int32_t areaId) {
if (getPropArea(propId) == VehicleArea::GLOBAL) {
// In VehicleHal, global properties have areaId = -1. We use 0.
areaId = 0;
}
auto prop = mProps.find(std::make_pair(propId, areaId));
if (prop != mProps.end()) {
return prop->second->get();
}
ALOGW("%s: Property not found: propId = 0x%x, areaId = 0x%x", __func__, propId, areaId);
return nullptr;
}
void DefaultVehicleHal::parseRxProtoBuf(std::vector<uint8_t>& msg) {
emulator::EmulatorMessage rxMsg;
emulator::EmulatorMessage respMsg;
if (rxMsg.ParseFromArray(msg.data(), msg.size())) {
switch (rxMsg.msg_type()) {
case emulator::GET_CONFIG_CMD:
doGetConfig(rxMsg, respMsg);
break;
case emulator::GET_CONFIG_ALL_CMD:
doGetConfigAll(rxMsg, respMsg);
break;
case emulator::GET_PROPERTY_CMD:
doGetProperty(rxMsg, respMsg);
break;
case emulator::GET_PROPERTY_ALL_CMD:
doGetPropertyAll(rxMsg, respMsg);
break;
case emulator::SET_PROPERTY_CMD:
doSetProperty(rxMsg, respMsg);
break;
default:
ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
break;
}
// Send the reply
txMsg(respMsg);
} else {
ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
}
}
// Copies internal VehiclePropConfig data structure to protobuf VehiclePropConfig
void DefaultVehicleHal::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg) {
protoCfg->set_prop(cfg.prop);
protoCfg->set_access(toInt(cfg.access));
protoCfg->set_change_mode(toInt(cfg.changeMode));
protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
if (!isGlobalProp(cfg.prop)) {
protoCfg->set_supported_areas(cfg.supportedAreas);
}
for (auto& configElement : cfg.configArray) {
protoCfg->add_config_array(configElement);
}
if (cfg.configString.size() > 0) {
protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
}
// Populate the min/max values based on property type
switch (getPropType(cfg.prop)) {
case VehiclePropertyType::STRING:
case VehiclePropertyType::BOOLEAN:
case VehiclePropertyType::INT32_VEC:
case VehiclePropertyType::FLOAT_VEC:
case VehiclePropertyType::BYTES:
case VehiclePropertyType::COMPLEX:
// Do nothing. These types don't have min/max values
break;
case VehiclePropertyType::INT64:
if (cfg.areaConfigs.size() > 0) {
emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
}
break;
case VehiclePropertyType::FLOAT:
if (cfg.areaConfigs.size() > 0) {
emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
}
break;
case VehiclePropertyType::INT32:
if (cfg.areaConfigs.size() > 0) {
emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
}
break;
default:
ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
break;
}
protoCfg->set_min_sample_rate(cfg.minSampleRate);
protoCfg->set_max_sample_rate(cfg.maxSampleRate);
}
// Copies internal VehiclePropValue data structure to protobuf VehiclePropValue
void DefaultVehicleHal::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
const VehiclePropValue* val) {
protoVal->set_prop(val->prop);
protoVal->set_value_type(toInt(getPropType(val->prop)));
protoVal->set_timestamp(val->timestamp);
protoVal->set_area_id(val->areaId);
// Copy value data if it is set.
// - for bytes and strings, this is indicated by size > 0
// - for int32, int64, and float, copy the values if vectors have data
if (val->value.stringValue.size() > 0) {
protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
}
if (val->value.bytes.size() > 0) {
protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
}
for (auto& int32Value : val->value.int32Values) {
protoVal->add_int32_values(int32Value);
}
for (auto& int64Value : val->value.int64Values) {
protoVal->add_int64_values(int64Value);
}
for (auto& floatValue : val->value.floatValues) {
protoVal->add_float_values(floatValue);
}
}
void DefaultVehicleHal::rxMsg() {
int numBytes = 0;
while (mExit == 0) {
std::vector<uint8_t> msg = mComm->read();
if (msg.size() > 0) {
// Received a message.
parseRxProtoBuf(msg);
} else {
// This happens when connection is closed
ALOGD("%s: numBytes=%d, msgSize=%d", __func__, numBytes,
static_cast<int32_t>(msg.size()));
break;
}
}
}
void DefaultVehicleHal::rxThread() {
bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
if (isEmulator) {
// Initialize pipe to Emulator
mComm.reset(new PipeComm);
} else {
// Initialize socket over ADB
mComm.reset(new SocketComm);
}
int retVal = mComm->open();
if (retVal == 0) {
// Comms are properly opened
while (mExit == 0) {
retVal = mComm->connect();
if (retVal >= 0) {
rxMsg();
}
// Check every 100ms for a new connection
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
}
// This function sets the default value of a property if we are interested in setting it.
// TODO: Co-locate the default values with the configuration structure, to make it easier to
// add new properties and their defaults.
void DefaultVehicleHal::setDefaultValue(VehiclePropValue* prop) {
switch (prop->prop) {
case toInt(VehicleProperty::INFO_MAKE):
prop->value.stringValue = "Default Car";
break;
case toInt(VehicleProperty::PERF_VEHICLE_SPEED):
prop->value.floatValues[0] = 0;
break;
case toInt(VehicleProperty::CURRENT_GEAR):
prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK);
break;
case toInt(VehicleProperty::PARKING_BRAKE_ON):
prop->value.int32Values[0] = 1;
break;
case toInt(VehicleProperty::FUEL_LEVEL_LOW):
prop->value.int32Values[0] = 0;
break;
case toInt(VehicleProperty::HVAC_POWER_ON):
prop->value.int32Values[0] = 1;
break;
case toInt(VehicleProperty::HVAC_DEFROSTER):
prop->value.int32Values[0] = 0;
break;
case toInt(VehicleProperty::HVAC_RECIRC_ON):
prop->value.int32Values[0] = 1;
break;
case toInt(VehicleProperty::HVAC_AC_ON):
prop->value.int32Values[0] = 1;
break;
case toInt(VehicleProperty::HVAC_AUTO_ON):
prop->value.int32Values[0] = 1;
break;
case toInt(VehicleProperty::HVAC_FAN_SPEED):
prop->value.int32Values[0] = 3;
break;
case toInt(VehicleProperty::HVAC_FAN_DIRECTION):
prop->value.int32Values[0] = toInt(VehicleHvacFanDirection::FACE);
break;
case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
prop->value.floatValues[0] = 16;
break;
case toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE):
prop->value.floatValues[0] = 25;
break;
case toInt(VehicleProperty::NIGHT_MODE):
prop->value.int32Values[0] = 0;
break;
case toInt(VehicleProperty::DRIVING_STATUS):
prop->value.int32Values[0] = toInt(VehicleDrivingStatus::UNRESTRICTED);
break;
case toInt(VehicleProperty::GEAR_SELECTION):
prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK);
break;
case toInt(VehicleProperty::INFO_FUEL_CAPACITY):
prop->value.floatValues[0] = 123000.0f; // In milliliters
break;
case toInt(VehicleProperty::ENGINE_OIL_TEMP):
prop->value.floatValues[0] = 101;
break;
case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
prop->value.int32Values[0] = 7;
break;
case toInt(VehicleProperty::IGNITION_STATE):
prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON);
break;
default:
ALOGW("%s: propId=0x%x not found", __func__, prop->prop);
break;
}
}
// Transmit a reply back to the emulator
void DefaultVehicleHal::txMsg(emulator::EmulatorMessage& txMsg) {
int numBytes = txMsg.ByteSize();
std::vector<uint8_t> msg(numBytes);
if (txMsg.SerializeToArray(msg.data(), msg.size())) {
int retVal = 0;
// Send the message
if (mExit == 0) {
mComm->write(msg);
}
if (retVal < 0) {
ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
}
} else {
ALOGE("%s: SerializeToString failed!", __func__);
}
}
// Updates the property value held in the HAL
StatusCode DefaultVehicleHal::updateProperty(const VehiclePropValue& propValue) {
auto propId = propValue.prop;
auto areaId = propValue.areaId;
StatusCode status = StatusCode::INVALID_ARG;
{
std::lock_guard<std::mutex> lock(mPropsMutex);
VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId);
if (internalPropValue != nullptr) {
internalPropValue->value = propValue.value;
internalPropValue->timestamp = propValue.timestamp;
status = StatusCode::OK;
}
}
return status;
}
VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
auto areaId = requestedPropValue.areaId;
auto& pool = *getValuePool();
auto propId = requestedPropValue.prop;
StatusCode status;
VehiclePropValuePtr v = nullptr;
switch (propId) {
default:
{
std::lock_guard<std::mutex> lock(mPropsMutex);
VehiclePropValue *internalPropValue = getVehiclePropValueLocked(propId, areaId);
if (internalPropValue != nullptr) {
v = pool.obtain(*internalPropValue);
}
}
if (v != nullptr) {
status = StatusCode::OK;
} else {
status = StatusCode::INVALID_ARG;
}
break;
}
*outStatus = status;
return v;
}
StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
auto propId = propValue.prop;
StatusCode status;
switch (propId) {
default:
if (mHvacPowerProps.count(propId)) {
std::lock_guard<std::mutex> lock(mPropsMutex);
auto hvacPowerOn = getVehiclePropValueLocked(toInt(VehicleProperty::HVAC_POWER_ON),
toInt(VehicleAreaZone::ROW_1));
if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
&& hvacPowerOn->value.int32Values[0] == 0) {
status = StatusCode::NOT_AVAILABLE;
break;
}
}
status = updateProperty(propValue);
if (status == StatusCode::OK) {
// Send property update to emulator
emulator::EmulatorMessage msg;
emulator::VehiclePropValue *val = msg.add_value();
populateProtoVehiclePropValue(val, &propValue);
msg.set_status(emulator::RESULT_OK);
msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
txMsg(msg);
}
break;
}
return status;
}
V2_0::StatusCode DefaultVehicleHal::addCustomProperty(int32_t property,
std::unique_ptr<CustomVehiclePropertyHandler>&& handler) {
mProps[std::make_pair(property, 0)] = std::move(handler);
ALOGW("%s: Added custom property: propId = 0x%x", __func__, property);
return StatusCode::OK;
}
// Parse supported properties list and generate vector of property values to hold current values.
void DefaultVehicleHal::onCreate() {
// Initialize member variables
mExit = 0;
for (auto& prop : kHvacPowerProperties) {
mHvacPowerProps.insert(prop);
}
// Get the list of configurations supported by this HAL
std::vector<VehiclePropConfig> configs = listProperties();
for (auto& cfg : configs) {
VehiclePropertyType propType = getPropType(cfg.prop);
int32_t supportedAreas = cfg.supportedAreas;
int32_t vecSize;
// Set the vector size based on property type
switch (propType) {
case VehiclePropertyType::BOOLEAN:
case VehiclePropertyType::INT32:
case VehiclePropertyType::INT64:
case VehiclePropertyType::FLOAT:
vecSize = 1;
break;
case VehiclePropertyType::INT32_VEC:
case VehiclePropertyType::FLOAT_VEC:
case VehiclePropertyType::BYTES:
// TODO: Add proper support for these types
vecSize = 1;
break;
case VehiclePropertyType::STRING:
// Require individual handling
vecSize = 0;
break;
case VehiclePropertyType::COMPLEX:
switch (cfg.prop) {
default:
// Need to handle each complex property separately
break;
}
continue;
default:
ALOGE("%s: propType=0x%x not found", __func__, propType);
vecSize = 0;
break;
}
// A global property will have supportedAreas = 0
if (getPropArea(cfg.prop) == VehicleArea::GLOBAL) {
supportedAreas = 0;
}
// This loop is a do-while so it executes at least once to handle global properties
do {
int32_t curArea = supportedAreas;
// Clear the right-most bit of supportedAreas
supportedAreas &= supportedAreas - 1;
// Set curArea to the previously cleared bit
curArea ^= supportedAreas;
// Create a separate instance for each individual zone
std::unique_ptr<VehiclePropValue> prop = createVehiclePropValue(propType, vecSize);
prop->areaId = curArea;
prop->prop = cfg.prop;
setDefaultValue(prop.get());
std::unique_ptr<CustomVehiclePropertyHandler> handler;
handler.reset(new StoredValueCustomVehiclePropertyHandler());
handler->set(*prop);
mProps[std::make_pair(prop->prop, prop->areaId)] =
std::move(handler);
} while (supportedAreas != 0);
}
// Start rx thread
mThread = std::thread(&DefaultVehicleHal::rxThread, this);
}
void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
VehiclePropValuePtr v;
auto& pool = *getValuePool();
for (int32_t property : properties) {
if (isContinuousProperty(property)) {
// In real implementation this value should be read from sensor, random
// value used for testing purpose only.
std::lock_guard<std::mutex> lock(mPropsMutex);
VehiclePropValue *internalPropValue = getVehiclePropValueLocked(property);
if (internalPropValue != nullptr) {
v = pool.obtain(*internalPropValue);
}
if (VehiclePropertyType::FLOAT == getPropType(property)) {
// Just get some randomness to continuous properties to see slightly differnt values
// on the other end.
v->value.floatValues[0] = v->value.floatValues[0] + std::rand() % 5;
}
} else {
ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
}
if (v.get()) {
v->timestamp = elapsedRealtimeNano();
doHalEvent(std::move(v));
}
}
}
StatusCode DefaultVehicleHal::subscribe(int32_t property, int32_t,
float sampleRate) {
ALOGI("subscribe called for property: 0x%x, sampleRate: %f", property, sampleRate);
if (isContinuousProperty(property)) {
mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
}
return StatusCode::OK;
}
StatusCode DefaultVehicleHal::unsubscribe(int32_t property) {
ALOGI("%s propId: 0x%x", __func__, property);
if (isContinuousProperty(property)) {
mRecurrentTimer.unregisterRecurrentEvent(property);
}
return StatusCode::OK;
}
const VehiclePropConfig* DefaultVehicleHal::getPropConfig(int32_t propId) const {
auto it = mPropConfigMap.find(propId);
return it == mPropConfigMap.end() ? nullptr : it->second;
}
bool DefaultVehicleHal::isContinuousProperty(int32_t propId) const {
const VehiclePropConfig* config = getPropConfig(propId);
if (config == nullptr) {
ALOGW("Config not found for property: 0x%x", propId);
return false;
}
return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
}
} // impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android

View file

@ -1,189 +0,0 @@
/*
* Copyright (C) 2016 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_DefaultVehicleHal_H_
#define android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
#include <map>
#include <memory>
#include <sys/socket.h>
#include <thread>
#include <unordered_set>
#include <utils/SystemClock.h>
#include "CommBase.h"
#include "VehicleHalProto.pb.h"
#include <vhal_v2_0/RecurrentTimer.h>
#include <vhal_v2_0/VehicleHal.h>
#include "DefaultConfig.h"
#include "VehicleHalProto.pb.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
class DefaultVehicleHal : public VehicleHal {
public:
class CustomVehiclePropertyHandler {
public:
virtual VehiclePropValue* get() = 0;
virtual StatusCode set(const VehiclePropValue& propValue) = 0;
virtual ~CustomVehiclePropertyHandler() = default;
};
protected:
class StoredValueCustomVehiclePropertyHandler :
public CustomVehiclePropertyHandler {
public:
VehiclePropValue* get() override {
return mPropValue.get();
}
StatusCode set(const VehiclePropValue& propValue) {
*mPropValue = propValue;
return StatusCode::OK;
}
private:
std::unique_ptr<VehiclePropValue> mPropValue{new VehiclePropValue()};
};
public:
DefaultVehicleHal() : mRecurrentTimer(
std::bind(&DefaultVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) {
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
mPropConfigMap[kVehicleProperties[i].prop] = &kVehicleProperties[i];
}
}
~DefaultVehicleHal() override {
// Notify thread to finish and wait for it to terminate
mExit = 1;
// Close emulator socket if it is open
mComm->stop();
mThread.join();
}
std::vector<VehiclePropConfig> listProperties() override {
return std::vector<VehiclePropConfig>(std::begin(kVehicleProperties),
std::end(kVehicleProperties));
}
VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
StatusCode* outStatus) override;
void onCreate() override;
StatusCode set(const VehiclePropValue& propValue) override;
StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
StatusCode unsubscribe(int32_t property) override;
/**
* Add custom property information to this HAL instance.
*
* This is useful for allowing later versions of Vehicle HAL to coalesce
* the list of properties they support with a previous version of the HAL.
*
* @param property The identifier of the new property
* @param handler The object that will handle get/set requests
* @return OK on success, an error code on failure
*/
virtual StatusCode addCustomProperty(int32_t,
std::unique_ptr<CustomVehiclePropertyHandler>&&);
/**
* Add custom property information to this HAL instance.
*
* This is useful for allowing later versions of Vehicle HAL to coalesce
* the list of properties they support with a previous version of the HAL.
*
* @param initialValue The initial value for the new property. This is not
* constant data, as later set() operations can change
* this value at will
* @return OK on success, an error code on failure
*/
virtual StatusCode addCustomProperty(
const VehiclePropValue& initialValue) {
std::unique_ptr<CustomVehiclePropertyHandler> handler;
handler.reset(new StoredValueCustomVehiclePropertyHandler());
StatusCode setResponse = handler->set(initialValue);
if (StatusCode::OK == setResponse) {
return addCustomProperty(initialValue.prop,
std::move(handler));
} else {
return setResponse;
}
}
private:
void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
void doGetConfigAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId = 0);
const VehiclePropConfig* getPropConfig(int32_t propId) const;
bool isContinuousProperty(int32_t propId) const;
void parseRxProtoBuf(std::vector<uint8_t>& msg);
void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg);
void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
const VehiclePropValue* val);
void setDefaultValue(VehiclePropValue* prop);
void rxMsg();
void rxThread();
void txMsg(emulator::EmulatorMessage& txMsg);
StatusCode updateProperty(const VehiclePropValue& propValue);
constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
}
void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
private:
std::map<
std::pair<int32_t /*VehicleProperty*/, int32_t /*areaId*/>,
std::unique_ptr<CustomVehiclePropertyHandler>> mProps;
std::atomic<int> mExit;
std::unordered_set<int32_t> mHvacPowerProps;
std::mutex mPropsMutex;
std::thread mThread;
std::unique_ptr<CommBase> mComm{nullptr};
RecurrentTimer mRecurrentTimer;
std::unordered_map<int32_t, const VehiclePropConfig*> mPropConfigMap;
};
} // impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android
#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_

View file

@ -0,0 +1,185 @@
/*
* Copyright (C) 2016 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 "DefaultVehicleHal_v2_0"
#include <android/log.h>
#include "EmulatedVehicleHal.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
: mPropStore(propStore),
mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer,
this, std::placeholders::_1)) {
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
mPropStore->registerProperty(kVehicleProperties[i].config);
}
}
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
VehiclePropValuePtr v = nullptr;
auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
if (internalPropValue != nullptr) {
v = getValuePool()->obtain(*internalPropValue);
}
*outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
return v;
}
StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
if (mHvacPowerProps.count(propValue.prop)) {
auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON),
toInt(VehicleAreaZone::ROW_1));
if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
&& hvacPowerOn->value.int32Values[0] == 0) {
return StatusCode::NOT_AVAILABLE;
}
}
if (!mPropStore->writeValue(propValue)) {
return StatusCode::INVALID_ARG;
}
getEmulatorOrDie()->doSetValueFromClient(propValue);
return StatusCode::OK;
}
// Parse supported properties list and generate vector of property values to hold current values.
void EmulatedVehicleHal::onCreate() {
for (auto& it : kVehicleProperties) {
VehiclePropConfig cfg = it.config;
int32_t supportedAreas = cfg.supportedAreas;
// A global property will have supportedAreas = 0
if (isGlobalProp(cfg.prop)) {
supportedAreas = 0;
}
// This loop is a do-while so it executes at least once to handle global properties
do {
int32_t curArea = supportedAreas;
supportedAreas &= supportedAreas - 1; // Clear the right-most bit of supportedAreas.
curArea ^= supportedAreas; // Set curArea to the previously cleared bit.
// Create a separate instance for each individual zone
VehiclePropValue prop = {
.prop = cfg.prop,
.areaId = curArea,
};
if (it.initialAreaValues.size() > 0) {
auto valueForAreaIt = it.initialAreaValues.find(curArea);
if (valueForAreaIt != it.initialAreaValues.end()) {
prop.value = valueForAreaIt->second;
} else {
ALOGW("%s failed to get default value for prop 0x%x area 0x%x",
__func__, cfg.prop, curArea);
}
} else {
prop.value = it.initialValue;
}
mPropStore->writeValue(prop);
} while (supportedAreas != 0);
}
}
std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() {
return mPropStore->getAllConfigs();
}
void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
VehiclePropValuePtr v;
auto& pool = *getValuePool();
for (int32_t property : properties) {
if (isContinuousProperty(property)) {
auto internalPropValue = mPropStore->readValueOrNull(property);
if (internalPropValue != nullptr) {
v = pool.obtain(*internalPropValue);
}
} else {
ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
}
if (v.get()) {
v->timestamp = elapsedRealtimeNano();
doHalEvent(std::move(v));
}
}
}
StatusCode EmulatedVehicleHal::subscribe(int32_t property, int32_t,
float sampleRate) {
ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
if (isContinuousProperty(property)) {
mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
}
return StatusCode::OK;
}
StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
ALOGI("%s propId: 0x%x", __func__, property);
if (isContinuousProperty(property)) {
mRecurrentTimer.unregisterRecurrentEvent(property);
}
return StatusCode::OK;
}
bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
if (config == nullptr) {
ALOGW("Config not found for property: 0x%x", propId);
return false;
}
return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
}
bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
if (mPropStore->writeValue(propValue)) {
doHalEvent(getValuePool()->obtain(propValue));
return true;
} else {
return false;
}
}
std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
return mPropStore->readAllValues();
}
} // impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,88 @@
/*
* Copyright (C) 2016 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_EmulatedVehicleHal_H_
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_
#include <map>
#include <memory>
#include <sys/socket.h>
#include <thread>
#include <unordered_set>
#include <utils/SystemClock.h>
#include "VehicleHalProto.pb.h"
#include <vhal_v2_0/RecurrentTimer.h>
#include <vhal_v2_0/VehicleHal.h>
#include "vhal_v2_0/VehiclePropertyStore.h"
#include "DefaultConfig.h"
#include "VehicleHalProto.pb.h"
#include "VehicleEmulator.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
/** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
public:
EmulatedVehicleHal(VehiclePropertyStore* propStore);
~EmulatedVehicleHal() = default;
// Methods from VehicleHal
void onCreate() override;
std::vector<VehiclePropConfig> listProperties() override;
VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
StatusCode* outStatus) override;
StatusCode set(const VehiclePropValue& propValue) override;
StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
StatusCode unsubscribe(int32_t property) override;
// Methods from EmulatedVehicleHalIface
bool setPropertyFromVehicle(const VehiclePropValue& propValue) override;
std::vector<VehiclePropValue> getAllProperties() const override;
private:
constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
}
void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
bool isContinuousProperty(int32_t propId) const;
private:
VehiclePropertyStore* mPropStore;
std::unordered_set<int32_t> mHvacPowerProps;
RecurrentTimer mRecurrentTimer;
};
} // impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android
#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_

View file

@ -0,0 +1,360 @@
/*
* 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.
*/
#define LOG_TAG "VehicleEmulator_v2_0"
#include <android/log.h>
#include <algorithm>
#include <android-base/properties.h>
#include <utils/SystemClock.h>
#include <vhal_v2_0/VehicleUtils.h>
#include "PipeComm.h"
#include "SocketComm.h"
#include "VehicleEmulator.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
std::unique_ptr<CommBase> CommFactory::create() {
bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
if (isEmulator) {
return std::make_unique<PipeComm>();
} else {
return std::make_unique<SocketComm>();
}
}
VehicleEmulator::~VehicleEmulator() {
mExit = true; // Notify thread to finish and wait for it to terminate.
mComm->stop(); // Close emulator socket if it is open.
if (mThread.joinable()) mThread.join();
}
void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
emulator::EmulatorMessage msg;
emulator::VehiclePropValue *val = msg.add_value();
populateProtoVehiclePropValue(val, &propValue);
msg.set_status(emulator::RESULT_OK);
msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
txMsg(msg);
}
void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
emulator::VehiclePropGet getProp = rxMsg.prop(0);
respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
for (auto& config : configs) {
// Find the config we are looking for
if (config.prop == getProp.prop()) {
emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
respMsg.set_status(emulator::RESULT_OK);
break;
}
}
}
void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage& /* rxMsg */,
VehicleEmulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
respMsg.set_status(emulator::RESULT_OK);
for (auto& config : configs) {
emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
}
}
void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
int32_t areaId = 0;
emulator::VehiclePropGet getProp = rxMsg.prop(0);
int32_t propId = getProp.prop();
emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
if (getProp.has_area_id()) {
areaId = getProp.area_id();
}
{
VehiclePropValue request = { .prop = propId, .areaId = areaId };
StatusCode halStatus;
auto val = mHal->get(request, &halStatus);
if (val != nullptr) {
emulator::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, val.get());
status = emulator::RESULT_OK;
}
}
respMsg.set_status(status);
}
void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage& /* rxMsg */,
VehicleEmulator::EmulatorMessage& respMsg) {
respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
respMsg.set_status(emulator::RESULT_OK);
{
for (const auto& prop : mHal->getAllProperties()) {
emulator::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, &prop);
}
}
}
void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
emulator::VehiclePropValue protoVal = rxMsg.value(0);
VehiclePropValue val = {
.prop = protoVal.prop(),
.areaId = protoVal.area_id(),
.timestamp = elapsedRealtimeNano(),
};
respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
// Copy value data if it is set. This automatically handles complex data types if needed.
if (protoVal.has_string_value()) {
val.value.stringValue = protoVal.string_value().c_str();
}
if (protoVal.has_bytes_value()) {
val.value.bytes = std::vector<uint8_t> { protoVal.bytes_value().begin(),
protoVal.bytes_value().end() };
}
if (protoVal.int32_values_size() > 0) {
val.value.int32Values = std::vector<int32_t> { protoVal.int32_values().begin(),
protoVal.int32_values().end() };
}
if (protoVal.int64_values_size() > 0) {
val.value.int64Values = std::vector<int64_t> { protoVal.int64_values().begin(),
protoVal.int64_values().end() };
}
if (protoVal.float_values_size() > 0) {
val.value.floatValues = std::vector<float> { protoVal.float_values().begin(),
protoVal.float_values().end() };
}
bool halRes = mHal->setPropertyFromVehicle(val);
respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY);
}
void VehicleEmulator::txMsg(emulator::EmulatorMessage& txMsg) {
int numBytes = txMsg.ByteSize();
std::vector<uint8_t> msg(static_cast<size_t>(numBytes));
if (!txMsg.SerializeToArray(msg.data(), static_cast<int32_t>(msg.size()))) {
ALOGE("%s: SerializeToString failed!", __func__);
return;
}
if (mExit) {
ALOGW("%s: unable to transmit a message, connection closed", __func__);
return;
}
// Send the message
int retVal = mComm->write(msg);
if (retVal < 0) {
ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
}
}
void VehicleEmulator::parseRxProtoBuf(std::vector<uint8_t>& msg) {
emulator::EmulatorMessage rxMsg;
emulator::EmulatorMessage respMsg;
if (rxMsg.ParseFromArray(msg.data(), static_cast<int32_t>(msg.size()))) {
switch (rxMsg.msg_type()) {
case emulator::GET_CONFIG_CMD:
doGetConfig(rxMsg, respMsg);
break;
case emulator::GET_CONFIG_ALL_CMD:
doGetConfigAll(rxMsg, respMsg);
break;
case emulator::GET_PROPERTY_CMD:
doGetProperty(rxMsg, respMsg);
break;
case emulator::GET_PROPERTY_ALL_CMD:
doGetPropertyAll(rxMsg, respMsg);
break;
case emulator::SET_PROPERTY_CMD:
doSetProperty(rxMsg, respMsg);
break;
default:
ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
break;
}
// Send the reply
txMsg(respMsg);
} else {
ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
}
}
void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg) {
protoCfg->set_prop(cfg.prop);
protoCfg->set_access(toInt(cfg.access));
protoCfg->set_change_mode(toInt(cfg.changeMode));
protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
if (!isGlobalProp(cfg.prop)) {
protoCfg->set_supported_areas(cfg.supportedAreas);
}
for (auto& configElement : cfg.configArray) {
protoCfg->add_config_array(configElement);
}
if (cfg.configString.size() > 0) {
protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
}
// Populate the min/max values based on property type
switch (getPropType(cfg.prop)) {
case VehiclePropertyType::STRING:
case VehiclePropertyType::BOOLEAN:
case VehiclePropertyType::INT32_VEC:
case VehiclePropertyType::FLOAT_VEC:
case VehiclePropertyType::BYTES:
case VehiclePropertyType::COMPLEX:
// Do nothing. These types don't have min/max values
break;
case VehiclePropertyType::INT64:
if (cfg.areaConfigs.size() > 0) {
emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
}
break;
case VehiclePropertyType::FLOAT:
if (cfg.areaConfigs.size() > 0) {
emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
}
break;
case VehiclePropertyType::INT32:
if (cfg.areaConfigs.size() > 0) {
emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
}
break;
default:
ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
break;
}
protoCfg->set_min_sample_rate(cfg.minSampleRate);
protoCfg->set_max_sample_rate(cfg.maxSampleRate);
}
void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
const VehiclePropValue* val) {
protoVal->set_prop(val->prop);
protoVal->set_value_type(toInt(getPropType(val->prop)));
protoVal->set_timestamp(val->timestamp);
protoVal->set_area_id(val->areaId);
// Copy value data if it is set.
// - for bytes and strings, this is indicated by size > 0
// - for int32, int64, and float, copy the values if vectors have data
if (val->value.stringValue.size() > 0) {
protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
}
if (val->value.bytes.size() > 0) {
protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
}
for (auto& int32Value : val->value.int32Values) {
protoVal->add_int32_values(int32Value);
}
for (auto& int64Value : val->value.int64Values) {
protoVal->add_int64_values(int64Value);
}
for (auto& floatValue : val->value.floatValues) {
protoVal->add_float_values(floatValue);
}
}
void VehicleEmulator::rxMsg() {
while (!mExit) {
std::vector<uint8_t> msg = mComm->read();
if (msg.size() > 0) {
// Received a message.
parseRxProtoBuf(msg);
} else {
// This happens when connection is closed
ALOGD("%s: msgSize=%zu", __func__, msg.size());
break;
}
}
}
void VehicleEmulator::rxThread() {
if (mExit) return;
int retVal = mComm->open();
if (retVal != 0) mExit = true;
// Comms are properly opened
while (!mExit) {
retVal = mComm->connect();
if (retVal >= 0) {
rxMsg();
}
// Check every 100ms for a new connection
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
} // impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,115 @@
/*
* 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_VehicleHalEmulator_H_
#define android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
#include <memory>
#include <thread>
#include <vector>
#include "vhal_v2_0/VehicleHal.h"
#include "CommBase.h"
#include "VehicleHalProto.pb.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
class VehicleEmulator; // Forward declaration.
/** Extension of VehicleHal that used by VehicleEmulator. */
class EmulatedVehicleHalIface : public VehicleHal {
public:
virtual bool setPropertyFromVehicle(const VehiclePropValue& propValue) = 0;
virtual std::vector<VehiclePropValue> getAllProperties() const = 0;
void registerEmulator(VehicleEmulator* emulator) {
ALOGI("%s, emulator: %p", __func__, emulator);
std::lock_guard<std::mutex> g(mEmulatorLock);
mEmulator = emulator;
}
protected:
VehicleEmulator* getEmulatorOrDie() {
std::lock_guard<std::mutex> g(mEmulatorLock);
ALOGI("%s, emulator: %p", __func__, mEmulator);
assert(mEmulator != nullptr);
return mEmulator;
}
private:
mutable std::mutex mEmulatorLock;
VehicleEmulator* mEmulator;
};
struct CommFactory {
static std::unique_ptr<CommBase> create();
};
/**
* Emulates vehicle by providing controlling interface from host side either through ADB or Pipe.
*/
class VehicleEmulator {
public:
VehicleEmulator(EmulatedVehicleHalIface* hal,
std::unique_ptr<CommBase> comm = CommFactory::create())
: mHal { hal },
mComm(comm.release()),
mThread { &VehicleEmulator::rxThread, this} {
mHal->registerEmulator(this);
}
virtual ~VehicleEmulator();
void doSetValueFromClient(const VehiclePropValue& propValue);
private:
using EmulatorMessage = emulator::EmulatorMessage;
void doGetConfig(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
void doGetConfigAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
void doGetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
void doGetPropertyAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
void doSetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
void txMsg(emulator::EmulatorMessage& txMsg);
void parseRxProtoBuf(std::vector<uint8_t>& msg);
void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg);
void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
const VehiclePropValue* val);
void rxMsg();
void rxThread();
private:
std::atomic<bool> mExit { false };
EmulatedVehicleHalIface* mHal;
std::unique_ptr<CommBase> mComm;
std::thread mThread;
};
} // impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android
#endif // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_

View file

@ -49,7 +49,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE:= $(vhal_v2_1)-default-impl-lib
LOCAL_SRC_FILES:= \
impl/vhal_v2_1/DefaultVehicleHal.cpp \
impl/vhal_v2_1/EmulatedVehicleHal.cpp \
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/impl/vhal_v2_1 \

View file

@ -55,8 +55,7 @@ public:
const std::vector<uint8_t>& getSensorsBitmask() const;
// Given a stringValue, fill in a VehiclePropValue
void fillPropValue(V2_0::VehiclePropValue *propValue,
std::string dtc) const;
void fillPropValue(const std::string& dtc, V2_0::VehiclePropValue *propValue) const;
private:
class BitmaskInVector {

View file

@ -99,8 +99,8 @@ const std::vector<uint8_t>& Obd2SensorStore::getSensorsBitmask() const {
return mSensorsBitmask.getBitmask();
}
void Obd2SensorStore::fillPropValue(V2_0::VehiclePropValue *propValue,
std::string dtc) const {
void Obd2SensorStore::fillPropValue(const std::string& dtc,
V2_0::VehiclePropValue *propValue) const {
propValue->timestamp = elapsedRealtimeNano();
propValue->value.int32Values = getIntegerSensors();
propValue->value.floatValues = getFloatSensors();

View file

@ -28,41 +28,50 @@ namespace V2_1 {
namespace impl {
// Some handy constants to avoid conversions from enum to int.
constexpr int OBD2_LIVE_FRAME = (int) V2_1::VehicleProperty::OBD2_LIVE_FRAME;
constexpr int OBD2_FREEZE_FRAME = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME;
constexpr int OBD2_FREEZE_FRAME_INFO = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO;
constexpr int OBD2_FREEZE_FRAME_CLEAR = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR;
constexpr int VEHICLE_MAP_SERVICE = (int) V2_1::VehicleProperty::VEHICLE_MAP_SERVICE;
constexpr int WHEEL_TICK = (int) V2_1::VehicleProperty::WHEEL_TICK;
const V2_0::VehiclePropConfig kVehicleProperties[] = {
{
.prop = V2_0::toInt(V2_1::VehicleProperty::WHEEL_TICK),
.prop = WHEEL_TICK,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::CONTINUOUS,
},
{
.prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME),
.prop = OBD2_LIVE_FRAME,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE,
.configArray = {0,0}
},
{
.prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME),
.prop = OBD2_FREEZE_FRAME,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE,
.configArray = {0,0}
},
{
.prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO),
.prop = OBD2_FREEZE_FRAME_INFO,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
},
{
.prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR),
.prop = OBD2_FREEZE_FRAME_CLEAR,
.access = V2_0::VehiclePropertyAccess::WRITE,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
},
{
.prop = V2_0::toInt(VehicleProperty::VEHICLE_MAP_SERVICE),
.prop = VEHICLE_MAP_SERVICE,
.access = V2_0::VehiclePropertyAccess::READ_WRITE,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
}

View file

@ -1,96 +0,0 @@
/*
* Copyright (C) 2016 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_1_impl_DefaultVehicleHal_H_
#define android_hardware_automotive_vehicle_V2_1_impl_DefaultVehicleHal_H_
#include <memory>
#include <utils/SystemClock.h>
#include <vhal_v2_0/VehicleHal.h>
#include <vhal_v2_0/DefaultVehicleHal.h>
#include <vhal_v2_1/Obd2SensorStore.h>
#include "DefaultConfig.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_1 {
namespace impl {
using namespace std::placeholders;
class DefaultVehicleHal : public V2_0::VehicleHal {
public:
DefaultVehicleHal(V2_0::impl::DefaultVehicleHal* vhal20) :
mVehicleHal20(vhal20) {}
std::vector<V2_0::VehiclePropConfig> listProperties() override {
std::vector<V2_0::VehiclePropConfig> propConfigs(mVehicleHal20->listProperties());
// Join Vehicle Hal 2.0 and 2.1 configs.
propConfigs.insert(propConfigs.end(),
std::begin(kVehicleProperties),
std::end(kVehicleProperties));
return propConfigs;
}
VehiclePropValuePtr get(const V2_0::VehiclePropValue& requestedPropValue,
V2_0::StatusCode* outStatus) override;
V2_0::StatusCode set(const V2_0::VehiclePropValue& propValue) override;
V2_0::StatusCode subscribe(int32_t property,
int32_t areas,
float sampleRate) override {
return mVehicleHal20->subscribe(property, areas, sampleRate);
}
V2_0::StatusCode unsubscribe(int32_t property) override {
return mVehicleHal20->unsubscribe(property);
}
void onCreate() override;
private:
void initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig,
V2_0::VehiclePropValue* liveObd2Frame);
void initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig);
V2_0::StatusCode fillObd2FreezeFrame(const V2_0::VehiclePropValue& requestedPropValue,
V2_0::VehiclePropValue* v);
V2_0::StatusCode fillObd2DtcInfo(V2_0::VehiclePropValue *v);
V2_0::StatusCode clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue);
private:
V2_0::impl::DefaultVehicleHal* mVehicleHal20;
std::vector<std::unique_ptr<V2_0::VehiclePropValue>> mFreezeObd2Frames;
};
} // impl
} // namespace V2_1
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android
#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_

View file

@ -21,7 +21,7 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include "DefaultVehicleHal.h"
#include "EmulatedVehicleHal.h"
#include "VehicleHalProto.pb.h"
#define DEBUG_SOCKET (33452)
@ -120,118 +120,103 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(
return sensorStore;
}
void DefaultVehicleHal::initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig,
V2_0::VehiclePropValue* liveObd2Frame) {
auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0],
propConfig.configArray[1]);
sensorStore->fillPropValue(liveObd2Frame, "");
liveObd2Frame->prop = V2_0::toInt(VehicleProperty::OBD2_LIVE_FRAME);
void EmulatedVehicleHal::initObd2LiveFrame(const V2_0::VehiclePropConfig& propConfig) {
auto liveObd2Frame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0);
auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
static_cast<size_t>(propConfig.configArray[1]));
sensorStore->fillPropValue("", liveObd2Frame.get());
liveObd2Frame->prop = OBD2_LIVE_FRAME;
mPropStore->writeValue(*liveObd2Frame);
}
void DefaultVehicleHal::initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig) {
auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0],
propConfig.configArray[1]);
void EmulatedVehicleHal::initObd2FreezeFrame(const V2_0::VehiclePropConfig& propConfig) {
auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
static_cast<size_t>(propConfig.configArray[1]));
mFreezeObd2Frames.push_back(
createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
mFreezeObd2Frames.push_back(
createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
mFreezeObd2Frames.push_back(
createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
sensorStore->fillPropValue(mFreezeObd2Frames[0].get(), "P0070");
sensorStore->fillPropValue(mFreezeObd2Frames[1].get(), "P0102");
sensorStore->fillPropValue(mFreezeObd2Frames[2].get(), "P0123");
static std::vector<std::string> sampleDtcs = { "P0070", "P0102" "P0123" };
for (auto&& dtc : sampleDtcs) {
auto freezeFrame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0);
sensorStore->fillPropValue(dtc, freezeFrame.get());
mPropStore->writeValue(*freezeFrame);
}
}
template<typename Iterable>
typename Iterable::const_iterator findPropValueAtTimestamp(
const Iterable& frames,
int64_t timestamp) {
return std::find_if(frames.begin(),
frames.end(),
[timestamp] (const std::unique_ptr<V2_0::VehiclePropValue>&
propValue) -> bool {
return propValue->timestamp == timestamp;
});
}
V2_0::StatusCode DefaultVehicleHal::fillObd2FreezeFrame(
V2_0::StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(
const V2_0::VehiclePropValue& requestedPropValue,
V2_0::VehiclePropValue* v) {
V2_0::VehiclePropValue* outValue) {
if (requestedPropValue.value.int64Values.size() != 1) {
ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp");
return V2_0::StatusCode::INVALID_ARG;
}
auto timestamp = requestedPropValue.value.int64Values[0];
auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames,
timestamp);
if(mFreezeObd2Frames.end() == freezeFrameIter) {
auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
if(freezeFrame == nullptr) {
ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
return V2_0::StatusCode::INVALID_ARG;
}
const auto& freezeFrame = *freezeFrameIter;
v->prop = V2_0::toInt(VehicleProperty::OBD2_FREEZE_FRAME);
v->value.int32Values = freezeFrame->value.int32Values;
v->value.floatValues = freezeFrame->value.floatValues;
v->value.bytes = freezeFrame->value.bytes;
v->value.stringValue = freezeFrame->value.stringValue;
v->timestamp = freezeFrame->timestamp;
outValue->prop = OBD2_FREEZE_FRAME;
outValue->value.int32Values = freezeFrame->value.int32Values;
outValue->value.floatValues = freezeFrame->value.floatValues;
outValue->value.bytes = freezeFrame->value.bytes;
outValue->value.stringValue = freezeFrame->value.stringValue;
outValue->timestamp = freezeFrame->timestamp;
return V2_0::StatusCode::OK;
}
V2_0::StatusCode DefaultVehicleHal::clearObd2FreezeFrames(
const V2_0::VehiclePropValue& propValue) {
V2_0::StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue) {
if (propValue.value.int64Values.size() == 0) {
mFreezeObd2Frames.clear();
mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
return V2_0::StatusCode::OK;
} else {
for(int64_t timestamp: propValue.value.int64Values) {
auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames,
timestamp);
if(mFreezeObd2Frames.end() == freezeFrameIter) {
auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
if(freezeFrame == nullptr) {
ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
return V2_0::StatusCode::INVALID_ARG;
}
mFreezeObd2Frames.erase(freezeFrameIter);
mPropStore->removeValue(*freezeFrame);
}
}
return V2_0::StatusCode::OK;
}
V2_0::StatusCode DefaultVehicleHal::fillObd2DtcInfo(V2_0::VehiclePropValue* v) {
V2_0::StatusCode EmulatedVehicleHal::fillObd2DtcInfo(V2_0::VehiclePropValue* outValue) {
std::vector<int64_t> timestamps;
for(const auto& freezeFrame: mFreezeObd2Frames) {
timestamps.push_back(freezeFrame->timestamp);
for(const auto& freezeFrame: mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) {
timestamps.push_back(freezeFrame.timestamp);
}
v->value.int64Values = timestamps;
outValue->value.int64Values = timestamps;
return V2_0::StatusCode::OK;
}
void DefaultVehicleHal::onCreate() {
mVehicleHal20->init(getValuePool(),
std::bind(&DefaultVehicleHal::doHalEvent, this, _1),
std::bind(&DefaultVehicleHal::doHalPropertySetError, this, _1, _2, _3));
void EmulatedVehicleHal::onCreate() {
V2_0::impl::EmulatedVehicleHal::onCreate();
std::vector<V2_0::VehiclePropConfig> configs = listProperties();
for (auto& cfg : configs) {
switch(cfg.prop) {
case V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME): {
auto liveObd2Frame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0);
initObd2LiveFrame(cfg, liveObd2Frame.get());
mVehicleHal20->addCustomProperty(*liveObd2Frame);
initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
}
void EmulatedVehicleHal::initStaticConfig() {
for (auto&& cfg = std::begin(kVehicleProperties); cfg != std::end(kVehicleProperties); ++cfg) {
V2_0::VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
switch (cfg->prop) {
case OBD2_FREEZE_FRAME: {
tokenFunction = [] (const V2_0::VehiclePropValue& propValue) {
return propValue.timestamp;
};
break;
}
break;
case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME):
initObd2FreezeFrame(cfg);
break;
default:
break;
}
mPropStore->registerProperty(*cfg, tokenFunction);
}
}
DefaultVehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
EmulatedVehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
const V2_0::VehiclePropValue& requestedPropValue,
V2_0::StatusCode* outStatus) {
@ -240,34 +225,30 @@ DefaultVehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
auto& pool = *getValuePool();
switch (propId) {
case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME):
case OBD2_FREEZE_FRAME:
v = pool.obtainComplex();
*outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
return v;
case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO):
case OBD2_FREEZE_FRAME_INFO:
v = pool.obtainComplex();
*outStatus = fillObd2DtcInfo(v.get());
return v;
default:
return mVehicleHal20->get(requestedPropValue, outStatus);
return V2_0::impl::EmulatedVehicleHal::get(requestedPropValue, outStatus);
}
}
V2_0::StatusCode DefaultVehicleHal::set(
const V2_0::VehiclePropValue& propValue) {
V2_0::StatusCode EmulatedVehicleHal::set(const V2_0::VehiclePropValue& propValue) {
auto propId = propValue.prop;
switch (propId) {
case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR):
case OBD2_FREEZE_FRAME_CLEAR:
return clearObd2FreezeFrames(propValue);
break;
case V2_0::toInt(V2_1::VehicleProperty::VEHICLE_MAP_SERVICE):
case VEHICLE_MAP_SERVICE:
// Placeholder for future implementation of VMS property in the default hal. For now, just
// returns OK; otherwise, hal clients crash with property not supported.
return V2_0::StatusCode::OK;
break;
default:
return mVehicleHal20->set(propValue);
return V2_0::impl::EmulatedVehicleHal::set(propValue);
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (C) 2016 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_1_impl_EmulatedVehicleHal_H_
#define android_hardware_automotive_vehicle_V2_1_impl_EmulatedVehicleHal_H_
#include <memory>
#include <utils/SystemClock.h>
#include <vhal_v2_0/EmulatedVehicleHal.h>
#include <vhal_v2_0/VehicleHal.h>
#include <vhal_v2_0/VehiclePropertyStore.h>
#include <vhal_v2_1/Obd2SensorStore.h>
#include "DefaultConfig.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_1 {
namespace impl {
using namespace std::placeholders;
class EmulatedVehicleHal : public V2_0::impl::EmulatedVehicleHal {
public:
EmulatedVehicleHal(V2_0::VehiclePropertyStore* propStore)
: V2_0::impl::EmulatedVehicleHal(propStore), mPropStore(propStore) {
initStaticConfig();
}
VehiclePropValuePtr get(const V2_0::VehiclePropValue& requestedPropValue,
V2_0::StatusCode* outStatus) override;
V2_0::StatusCode set(const V2_0::VehiclePropValue& propValue) override;
void onCreate() override;
private:
void initStaticConfig();
void initObd2LiveFrame(const V2_0::VehiclePropConfig& propConfig);
void initObd2FreezeFrame(const V2_0::VehiclePropConfig& propConfig);
V2_0::StatusCode fillObd2FreezeFrame(const V2_0::VehiclePropValue& requestedPropValue,
V2_0::VehiclePropValue* outValue);
V2_0::StatusCode fillObd2DtcInfo(V2_0::VehiclePropValue *outValue);
V2_0::StatusCode clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue);
private:
V2_0::VehiclePropertyStore* mPropStore;
};
} // impl
} // namespace V2_1
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android
#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_

View file

@ -23,9 +23,10 @@
#include <android/hardware/automotive/vehicle/2.1/IVehicle.h>
#include <vhal_v2_0/VehicleHalManager.h>
#include <vhal_v2_0/DefaultVehicleHal.h>
#include <vhal_v2_0/VehiclePropertyStore.h>
#include <vhal_v2_0/EmulatedVehicleHal.h>
#include <vhal_v2_1/DefaultVehicleHal.h>
#include <vhal_v2_1/EmulatedVehicleHal.h>
using namespace android;
using namespace android::hardware;
@ -80,10 +81,10 @@ private:
};
int main(int /* argc */, char* /* argv */ []) {
auto halImpl20 = std::make_unique<V2_0::impl::DefaultVehicleHal>();
auto halImpl21 = std::make_unique<V2_1::impl::DefaultVehicleHal>(halImpl20.get());
auto vehicleManager = std::make_unique<V2_0::VehicleHalManager>(halImpl21.get());
auto store = std::make_unique<V2_0::VehiclePropertyStore>();
auto hal = std::make_unique<V2_1::impl::EmulatedVehicleHal>(store.get());
auto emulator = std::make_unique<V2_0::impl::VehicleEmulator>(hal.get());
auto vehicleManager = std::make_unique<V2_0::VehicleHalManager>(hal.get());
Vehicle_V2_1 vehicle21(vehicleManager.get());