Merge changes from topic 'vhal-def-refactor' into oc-dev
am: ccc1d2e736
Change-Id: If3ebe7e1c54a2bc68b4ba0065ba3b62eb158b02e
This commit is contained in:
commit
3e942409a9
19 changed files with 1403 additions and 1201 deletions
|
@ -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
|
||||
|
|
|
@ -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 */);
|
||||
|
|
|
@ -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_
|
|
@ -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
|
|
@ -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} }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
115
automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
Normal file
115
automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
Normal 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_
|
|
@ -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 \
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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_
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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_
|
|
@ -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());
|
||||
|
||||
|
|
Loading…
Reference in a new issue