blob: 88717a935e1dd89a8a9b755fa06bee987a0012fc [file] [log] [blame]
/*
* 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"
#include <algorithm>
#include <android/log.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "DefaultVehicleHal.h"
#include "VehicleHalProto.pb.h"
#define DEBUG_SOCKET (33452)
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& propVal : mProps) {
emulator::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, propVal.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();
// 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;
}
for (auto& prop : mProps) {
if ((prop->prop == propId) && (prop->areaId == areaId)) {
return prop.get();
}
}
ALOGW("%s: Property not found: propId = 0x%x, areaId = 0x%x", __FUNCTION__, propId, areaId);
return nullptr;
}
void DefaultVehicleHal::initObd2LiveFrame(VehiclePropConfig& obd2LiveFramePropConfig) {
mObd2SensorStore.reset(new Obd2SensorStore(
obd2LiveFramePropConfig.configArray[0],
obd2LiveFramePropConfig.configArray[1]));
// precalculate OBD2 sensor values
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS,
toInt(FuelSystemStatus::CLOSED_LOOP));
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::IGNITION_MONITORS_SUPPORTED,
toInt(IgnitionMonitorKind::SPARK));
mObd2SensorStore->setIntegerSensor(Obd2IntegerSensorIndex::IGNITION_SPECIFIC_MONITORS,
CommonIgnitionMonitors::COMPONENTS_AVAILABLE |
CommonIgnitionMonitors::MISFIRE_AVAILABLE |
SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE |
SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS,
toInt(SecondaryAirStatus::FROM_OUTSIDE_OR_OFF));
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1);
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::FUEL_TYPE, toInt(FuelType::GASOLINE));
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::ENGINE_RPM, 1250.);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::VEHICLE_SPEED, 40.);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::TIMING_ADVANCE, 2.5);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::THROTTLE_POSITION, 19.75);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE, -0.373);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1, 190.);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094);
mObd2SensorStore->setFloatSensor(
Obd2FloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
}
void DefaultVehicleHal::parseRxProtoBuf(std::vector<uint8_t>& msg) {
emulator::EmulatorMessage rxMsg;
emulator::EmulatorMessage respMsg;
std::string str(reinterpret_cast<const char*>(msg.data()), msg.size());
rxMsg.ParseFromString(str);
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", __FUNCTION__, rxMsg.msg_type());
respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
break;
}
// Send the reply
txMsg(respMsg);
}
// 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", __FUNCTION__, 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(void) {
int numBytes = 0;
int32_t msgSize;
do {
// This is a variable length message.
// Read the number of bytes to rx over the socket
numBytes = read(mCurSocket, &msgSize, sizeof(msgSize));
if (numBytes != sizeof(msgSize)) {
// This happens when connection is closed
ALOGD("%s: numBytes=%d, expected=4", __FUNCTION__, numBytes);
break;
}
std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize);
numBytes = read(mCurSocket, msg.data(), msgSize);
if ((numBytes == msgSize) && (msgSize > 0)) {
// Received a message.
parseRxProtoBuf(msg);
} else {
// This happens when connection is closed
ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize);
break;
}
} while (mExit == 0);
}
void DefaultVehicleHal::rxThread(void) {
// Initialize the socket
{
int retVal;
struct sockaddr_in servAddr;
mSocket = socket(AF_INET, SOCK_STREAM, 0);
if (mSocket < 0) {
ALOGE("%s: socket() failed, mSocket=%d, errno=%d", __FUNCTION__, mSocket, errno);
mSocket = -1;
return;
}
bzero(&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = INADDR_ANY;
servAddr.sin_port = htons(DEBUG_SOCKET);
retVal = bind(mSocket, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr));
if(retVal < 0) {
ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno);
close(mSocket);
mSocket = -1;
return;
}
listen(mSocket, 1);
// Set the socket to be non-blocking so we can poll it continouously
fcntl(mSocket, F_SETFL, O_NONBLOCK);
}
while (mExit == 0) {
struct sockaddr_in cliAddr;
socklen_t cliLen = sizeof(cliAddr);
int cSocket = accept(mSocket, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen);
if (cSocket >= 0) {
{
std::lock_guard<std::mutex> lock(mTxMutex);
mCurSocket = cSocket;
}
ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSocket);
rxMsg();
ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, cSocket);
{
std::lock_guard<std::mutex> lock(mTxMutex);
mCurSocket = -1;
}
}
// TODO: Use a blocking socket?
// Check every 100ms for a new socket connection
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// Shutdown the socket
close(mSocket);
mSocket = -1;
}
// 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::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::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] = 0.75f;
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;
case toInt(VehicleProperty::OBD2_LIVE_FRAME):
// OBD2 is handled separately
break;
case toInt(VehicleProperty::OBD2_FREEZE_FRAME):
// OBD2 is handled separately
break;
default:
ALOGW("%s: propId=0x%x not found", __FUNCTION__, prop->prop);
break;
}
}
// Transmit a reply back to the emulator
void DefaultVehicleHal::txMsg(emulator::EmulatorMessage& txMsg) {
std::string msgString;
if (txMsg.SerializeToString(&msgString)) {
int32_t msgLen = msgString.length();
int retVal = 0;
// TODO: Prepend the message length to the string without a copy
msgString.insert(0, reinterpret_cast<char*>(&msgLen), 4);
// Send the message
{
std::lock_guard<std::mutex> lock(mTxMutex);
if (mCurSocket != -1) {
retVal = write(mCurSocket, msgString.data(), msgString.size());
}
}
if (retVal < 0) {
ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __FUNCTION__, retVal, errno);
}
} else {
ALOGE("%s: SerializeToString failed!", __FUNCTION__);
}
}
// 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 = elapsedRealtimeNano();
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) {
case toInt(VehicleProperty::OBD2_LIVE_FRAME):
v = pool.obtainComplex();
status = fillObd2LiveFrame(&v);
break;
case toInt(VehicleProperty::OBD2_FREEZE_FRAME):
v = pool.obtainComplex();
status = fillObd2FreezeFrame(&v);
break;
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) {
StatusCode 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);
}
return status;
}
// Parse supported properties list and generate vector of property values to hold current values.
void DefaultVehicleHal::onCreate() {
// Initialize member variables
mCurSocket = -1;
mExit = 0;
mSocket = -1;
// 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) {
case toInt(VehicleProperty::OBD2_LIVE_FRAME):
initObd2LiveFrame(cfg);
break;
default:
// Need to handle each complex property separately
break;
}
continue;
break;
case VehiclePropertyType::MASK:
default:
ALOGW("%s: propType=0x%x not found", __FUNCTION__, 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());
mProps.push_back(std::move(prop));
} while (supportedAreas != 0);
}
// Start rx thread
mThread = std::thread(&DefaultVehicleHal::rxThread, this);
}
StatusCode DefaultVehicleHal::fillObd2LiveFrame(VehiclePropValuePtr* v) {
(*v)->value.int32Values = mObd2SensorStore->getIntegerSensors();
(*v)->value.floatValues = mObd2SensorStore->getFloatSensors();
(*v)->value.bytes = mObd2SensorStore->getSensorsBitmask();
return StatusCode::OK;
}
StatusCode DefaultVehicleHal::fillObd2FreezeFrame(VehiclePropValuePtr* v) {
(*v)->value.int32Values = mObd2SensorStore->getIntegerSensors();
(*v)->value.floatValues = mObd2SensorStore->getFloatSensors();
(*v)->value.bytes = mObd2SensorStore->getSensorsBitmask();
(*v)->value.stringValue = "P0010";
return StatusCode::OK;
}
} // impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android