Merge "Enable vehicle HAL to be controlled via ADB"
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
index a346507..e822044 100644
--- a/automotive/vehicle/2.0/default/Android.mk
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -41,6 +41,28 @@
include $(BUILD_STATIC_LIBRARY)
###############################################################################
+# Vehicle HAL Protobuf library
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-proto-files-under, impl/proto)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_MODULE := $(module_prefix)-libproto-native
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STRIP_MODULE := keep_symbols
+
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(generated_sources_dir)/proto/$(LOCAL_PATH)/impl/proto
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+###############################################################################
# Vehicle default VehicleHAL implementation
###############################################################################
include $(CLEAR_VARS)
@@ -55,9 +77,13 @@
libhidltransport \
libhwbinder \
liblog \
+ libprotobuf-cpp-lite \
libutils \
$(module_prefix) \
+LOCAL_STATIC_LIBRARIES := \
+ $(module_prefix)-libproto-native
+
include $(BUILD_STATIC_LIBRARY)
@@ -114,7 +140,11 @@
libhidltransport \
libhwbinder \
liblog \
+ libprotobuf-cpp-lite \
libutils \
$(module_prefix) \
+LOCAL_STATIC_LIBRARIES := \
+ $(module_prefix)-libproto-native
+
include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
index 344a984..1ee4d47 100644
--- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
@@ -1,4 +1,4 @@
service vehicle-hal-2.0 /system/bin/hw/android.hardware.automotive.vehicle@2.0-service
class hal
user vehicle_network
- group system
+ group system inet
diff --git a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
index 1c26759..88717a9 100644
--- a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
@@ -14,12 +14,17 @@
* limitations under the License.
*/
-#include "DefaultVehicleHal.h"
+#define LOG_TAG "DefaultVehicleHal"
#include <algorithm>
-
-#define LOG_TAG "default_vehicle"
#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 {
@@ -29,144 +34,157 @@
namespace impl {
-VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
- const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
- *outStatus = StatusCode::OK;
+void DefaultVehicleHal::doGetConfig(emulator::EmulatorMessage& rxMsg,
+ emulator::EmulatorMessage& respMsg) {
+ std::vector<VehiclePropConfig> configs = listProperties();
+ emulator::VehiclePropGet getProp = rxMsg.prop(0);
- VehiclePropValuePtr v;
- auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
- int32_t areaId = requestedPropValue.areaId;
- auto& pool = *getValuePool();
+ respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
+ respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
- switch (property) {
- case VehicleProperty::INFO_MAKE:
- v = pool.obtainString("Default Car");
+ 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;
- case VehicleProperty::HVAC_FAN_SPEED:
- v = pool.obtainInt32(mFanSpeed);
- break;
- case VehicleProperty::HVAC_POWER_ON:
- v = pool.obtainBoolean(mHvacPowerOn);
- break;
- case VehicleProperty::HVAC_RECIRC_ON:
- v = pool.obtainBoolean(mHvacRecircOn);
- break;
- case VehicleProperty::HVAC_AC_ON:
- v = pool.obtainBoolean(mHvacAcOn);
- break;
- case VehicleProperty::HVAC_AUTO_ON:
- v = pool.obtainBoolean(mHvacAutoOn);
- break;
- case VehicleProperty::HVAC_FAN_DIRECTION:
- v = pool.obtainInt32(toInt(mFanDirection));
- break;
- case VehicleProperty::HVAC_DEFROSTER:
- bool defroster;
- *outStatus = getHvacDefroster(areaId, &defroster);
- if (StatusCode::OK == *outStatus) {
- v = pool.obtainBoolean(defroster);
- }
- break;
- case VehicleProperty::HVAC_TEMPERATURE_SET:
- float value;
- *outStatus = getHvacTemperature(requestedPropValue.areaId,
- &value);
- if (StatusCode::OK == *outStatus) {
- v = pool.obtainFloat(value);
- }
- break;
- case VehicleProperty::INFO_FUEL_CAPACITY:
- v = pool.obtainFloat(0.75f);
- break;
- case VehicleProperty::DISPLAY_BRIGHTNESS:
- v = pool.obtainInt32(mBrightness);
- break;
- case VehicleProperty::NIGHT_MODE:
- v = pool.obtainBoolean(false);
- break;
- case VehicleProperty::GEAR_SELECTION:
- v = pool.obtainInt32(toInt(VehicleGear::GEAR_PARK));
- break;
- case VehicleProperty::DRIVING_STATUS:
- v = pool.obtainInt32(toInt(VehicleDrivingStatus::UNRESTRICTED));
- break;
- case VehicleProperty::IGNITION_STATE:
- v = pool.obtainInt32(toInt(VehicleIgnitionState::ACC));
- break;
- case VehicleProperty::OBD2_LIVE_FRAME:
- v = pool.obtainComplex();
- *outStatus = fillObd2LiveFrame(&v);
- break;
- case VehicleProperty::OBD2_FREEZE_FRAME:
- v = pool.obtainComplex();
- *outStatus = fillObd2FreezeFrame(&v);
- break;
- default:
- *outStatus = StatusCode::INVALID_ARG;
+ }
}
-
- if (StatusCode::OK == *outStatus && v.get() != nullptr) {
- v->prop = toInt(property);
- v->areaId = areaId;
- v->timestamp = elapsedRealtimeNano();
- }
-
- return v;
}
-StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
- auto property = static_cast<VehicleProperty>(propValue.prop);
- const auto& v = propValue.value;
+void DefaultVehicleHal::doGetConfigAll(emulator::EmulatorMessage& /* rxMsg */,
+ emulator::EmulatorMessage& respMsg) {
+ std::vector<VehiclePropConfig> configs = listProperties();
- StatusCode status = StatusCode::OK;
+ respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
+ respMsg.set_status(emulator::RESULT_OK);
- switch (property) {
- case VehicleProperty::HVAC_POWER_ON:
- mHvacPowerOn = v.int32Values[0] == 1;
- break;
- case VehicleProperty::HVAC_RECIRC_ON:
- mHvacRecircOn = v.int32Values[0] == 1;
- break;
- case VehicleProperty::HVAC_AC_ON:
- mHvacAcOn = v.int32Values[0] == 1;
- break;
- case VehicleProperty::HVAC_AUTO_ON:
- mHvacAutoOn = v.int32Values[0] == 1;
- break;
- case VehicleProperty::HVAC_DEFROSTER:
- status = setHvacDefroster(propValue.areaId, v.int32Values[0] == 1);
- break;
- case VehicleProperty::HVAC_FAN_DIRECTION:
- mFanDirection =
- static_cast<VehicleHvacFanDirection>(v.int32Values[0]);
- break;
- case VehicleProperty::HVAC_FAN_SPEED:
- mFanSpeed = v.int32Values[0];
- break;
- case VehicleProperty::HVAC_TEMPERATURE_SET:
- status = setHvacTemperature(propValue.areaId, v.floatValues[0]);
- break;
- case VehicleProperty::DISPLAY_BRIGHTNESS:
- mBrightness = v.int32Values[0];
- break;
- default:
- status = StatusCode::INVALID_ARG;
+ for (auto& config : configs) {
+ emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ populateProtoVehicleConfig(protoCfg, config);
}
-
- return status;
}
-void DefaultVehicleHal::onCreate() {
- const auto& propConfigs(listProperties());
- auto obd2LiveFramePropConfig = std::find_if(
- propConfigs.begin(),
- propConfigs.end(),
- [] (VehiclePropConfig config) -> bool {
- return (config.prop == toInt(VehicleProperty::OBD2_LIVE_FRAME));
- });
+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]));
+ obd2LiveFramePropConfig.configArray[0],
+ obd2LiveFramePropConfig.configArray[1]));
// precalculate OBD2 sensor values
mObd2SensorStore->setIntegerSensor(
Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS,
@@ -246,56 +264,461 @@
Obd2FloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
}
-StatusCode DefaultVehicleHal::getHvacTemperature(int32_t areaId,
- float* outValue) {
- if (areaId == toInt(VehicleAreaZone::ROW_1_LEFT)) {
- *outValue = mRow1LeftHvacTemperatureSet;
- } else if (areaId == toInt(VehicleAreaZone::ROW_1_RIGHT)) {
- *outValue = mRow1RightHvacTemperatureSet;
- } else {
- return StatusCode::INVALID_ARG;
+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;
}
- return StatusCode::OK;
+
+ // Send the reply
+ txMsg(respMsg);
}
-StatusCode DefaultVehicleHal::setHvacTemperature(
- int32_t areaId, float value) {
- if (areaId == toInt(VehicleAreaZone::ROW_1_LEFT)) {
- mRow1LeftHvacTemperatureSet = value;
- } else if (areaId == toInt(VehicleAreaZone::ROW_1_RIGHT)) {
- mRow1RightHvacTemperatureSet = value;
- } else {
- return StatusCode::INVALID_ARG;
+// 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);
}
- return StatusCode::OK;
+
+ 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);
}
-StatusCode DefaultVehicleHal::getHvacDefroster(int32_t areaId,
- bool* outValue) {
- ALOGI("Getting Hvac defroster for area: 0x%x", areaId);
+// 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);
- if (areaId == toInt(VehicleAreaWindow::FRONT_WINDSHIELD)) {
- *outValue = mFrontDefroster;
- } else if (areaId == toInt(VehicleAreaWindow::REAR_WINDSHIELD)) {
- *outValue = mRearDefroster;
- } else {
- ALOGE("Unable to get hvac defroster for area: 0x%x", areaId);
- return StatusCode::INVALID_ARG;
+ // 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());
}
- ALOGI("Getting Hvac defroster for area: 0x%x, OK", areaId);
- return StatusCode::OK;
+ 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);
+ }
}
-StatusCode DefaultVehicleHal::setHvacDefroster(int32_t areaId, bool value) {
- if (areaId == toInt(VehicleAreaWindow::FRONT_WINDSHIELD)) {
- mFrontDefroster = value;
- } else if (areaId == toInt(VehicleAreaWindow::REAR_WINDSHIELD)) {
- mRearDefroster = value;
- } else {
- return StatusCode::INVALID_ARG;
+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);
}
- return StatusCode::OK;
+
+ 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) {
diff --git a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
index ccedeeb..edfc224 100644
--- a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
@@ -21,8 +21,12 @@
#include <VehicleHal.h>
#include <impl/DefaultConfig.h>
-#include <vehicle_hal_manager/Obd2SensorStore.h>
+#include <sys/socket.h>
+#include <thread>
#include <utils/SystemClock.h>
+#include <vehicle_hal_manager/Obd2SensorStore.h>
+#include "VehicleHalProto.pb.h"
+
namespace android {
namespace hardware {
@@ -34,6 +38,23 @@
class DefaultVehicleHal : public VehicleHal {
public:
+ DefaultVehicleHal() : mThread() {}
+ ~DefaultVehicleHal() override {
+ // Notify thread to finish and wait for it to terminate
+ mExit = 1;
+
+ // Close emulator socket if it is open
+ {
+ std::lock_guard<std::mutex> lock(mTxMutex);
+ if (mCurSocket != -1) {
+ close(mCurSocket);
+ mCurSocket = -1;
+ }
+ }
+
+ mThread.join();
+ }
+
std::vector<VehiclePropConfig> listProperties() override {
return std::vector<VehiclePropConfig>(std::begin(kVehicleProperties),
std::end(kVehicleProperties));
@@ -46,38 +67,47 @@
StatusCode set(const VehiclePropValue& propValue) override;
- StatusCode subscribe(int32_t /*property*/,
- int32_t /*areas*/,
- float /*sampleRate*/) override {
- // TODO(pavelm): implement
+ StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) {
+ ALOGD("%s: not implemented: prop=0x%x, areas=0x%x, rate=%f", __FUNCTION__, property,
+ areas, sampleRate);
return StatusCode::OK;
}
- StatusCode unsubscribe(int32_t /*property*/) override {
- // TODO(pavelm): implement
+ StatusCode unsubscribe(int32_t property) {
+ ALOGD("%s: not implemented: prop=0x%x", __FUNCTION__, property);
return StatusCode::OK;
}
private:
- StatusCode getHvacTemperature(int32_t areaId, float* outValue);
- StatusCode setHvacTemperature(int32_t areaId, float value);
- StatusCode getHvacDefroster(int32_t areaId, bool* outValue);
- StatusCode setHvacDefroster(int32_t areaId, bool value);
+ 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);
+ void initObd2LiveFrame(VehiclePropConfig& obd2LiveFramePropConfig);
+ 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);
+ void rxThread(void);
+ void txMsg(emulator::EmulatorMessage& txMsg);
+ StatusCode updateProperty(const VehiclePropValue& propValue);
StatusCode fillObd2LiveFrame(VehiclePropValuePtr* v);
StatusCode fillObd2FreezeFrame(VehiclePropValuePtr* v);
private:
- int32_t mFanSpeed = 3;
- int32_t mBrightness = 7;
- float mRow1LeftHvacTemperatureSet = 16;
- float mRow1RightHvacTemperatureSet = 22;
- bool mFrontDefroster = false;
- bool mRearDefroster = false;
- bool mHvacPowerOn = true;
- bool mHvacRecircOn = true;
- bool mHvacAcOn = true;
- bool mHvacAutoOn = true;
- VehicleHvacFanDirection mFanDirection = VehicleHvacFanDirection::FACE;
+ // TODO: Use a hashtable to support indexing props
+ std::vector<std::unique_ptr<VehiclePropValue>> mProps;
+ std::atomic<int> mCurSocket;
+ std::atomic<int> mExit;
std::unique_ptr<Obd2SensorStore> mObd2SensorStore{nullptr};
+ std::mutex mPropsMutex;
+ int mSocket;
+ std::mutex mTxMutex;
+ std::thread mThread;
};
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/proto/VehicleHalProto.proto
new file mode 100644
index 0000000..86433f5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/proto/VehicleHalProto.proto
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package emulator;
+
+// CMD messages are from workstation --> VHAL
+// RESP messages are from VHAL --> workstation
+enum MsgType {
+ GET_CONFIG_CMD = 0;
+ GET_CONFIG_RESP = 1;
+ GET_CONFIG_ALL_CMD = 2;
+ GET_CONFIG_ALL_RESP = 3;
+ GET_PROPERTY_CMD = 4;
+ GET_PROPERTY_RESP = 5;
+ GET_PROPERTY_ALL_CMD = 6;
+ GET_PROPERTY_ALL_RESP = 7;
+ SET_PROPERTY_CMD = 8;
+ SET_PROPERTY_RESP = 9;
+ SET_PROPERTY_ASYNC = 10;
+}
+enum Status {
+ RESULT_OK = 0;
+ ERROR_UNKNOWN = 1;
+ ERROR_UNIMPLEMENTED_CMD = 2;
+ ERROR_INVALID_PROPERTY = 3;
+ ERROR_INVALID_AREA_ID = 4;
+ ERROR_PROPERTY_UNINITIALIZED = 5;
+ ERROR_WRITE_ONLY_PROPERTY = 6;
+ ERROR_MEMORY_ALLOC_FAILED = 7;
+ ERROR_INVALID_OPERATION = 8;
+}
+
+message VehicleAreaConfig {
+ required int32 area_id = 1;
+ optional sint32 min_int32_value = 2;
+ optional sint32 max_int32_value = 3;
+ optional sint64 min_int64_value = 4;
+ optional sint64 max_int64_value = 5;
+ optional float min_float_value = 6;
+ optional float max_float_value = 7;
+}
+
+message VehiclePropConfig {
+ required int32 prop = 1;
+ optional int32 access = 2;
+ optional int32 change_mode = 3;
+ optional int32 value_type = 4;
+ optional int32 supported_areas = 5;
+ repeated VehicleAreaConfig area_configs = 6;
+ optional int32 config_flags = 7;
+ repeated int32 config_array = 8;
+ optional string config_string = 9;
+ optional float min_sample_rate = 10;
+ optional float max_sample_rate = 11;
+};
+
+message VehiclePropValue {
+ // common data
+ required int32 prop = 1;
+ optional int32 value_type = 2;
+ optional int64 timestamp = 3; // required for valid data from HAL, skipped for set
+
+ // values
+ optional int32 area_id = 4;
+ repeated sint32 int32_values = 5; // this also covers boolean value.
+ repeated sint64 int64_values = 6;
+ repeated float float_values = 7;
+ optional string string_value = 8;
+ optional bytes bytes_value = 9;
+};
+
+// This structure is used to notify what values to get from the Vehicle HAL
+message VehiclePropGet {
+ required int32 prop = 1;
+ optional int32 area_id = 2;
+};
+
+message EmulatorMessage {
+ required MsgType msg_type = 1;
+ optional Status status = 2; // Only for RESP messages
+ repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands
+ repeated VehiclePropConfig config = 4;
+ repeated VehiclePropValue value = 5;
+};