1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #define LOG_TAG "DefaultVehicleHal_v2_0" 17 18 #include <android/log.h> 19 #include <android-base/macros.h> 20 21 #include "EmulatedVehicleHal.h" 22 #include "Obd2SensorStore.h" 23 24 namespace android { 25 namespace hardware { 26 namespace automotive { 27 namespace vehicle { 28 namespace V2_0 { 29 30 namespace impl { 31 32 static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors, 33 size_t numVendorFloatSensors) { 34 std::unique_ptr<Obd2SensorStore> sensorStore( 35 new Obd2SensorStore(numVendorIntegerSensors, numVendorFloatSensors)); 36 37 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS, 38 toInt(Obd2FuelSystemStatus::CLOSED_LOOP)); 39 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0); 40 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_MONITORS_SUPPORTED, 41 toInt(Obd2IgnitionMonitorKind::SPARK)); 42 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_SPECIFIC_MONITORS, 43 Obd2CommonIgnitionMonitors::COMPONENTS_AVAILABLE | 44 Obd2CommonIgnitionMonitors::MISFIRE_AVAILABLE | 45 Obd2SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE | 46 Obd2SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE); 47 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35); 48 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS, 49 toInt(Obd2SecondaryAirStatus::FROM_OUTSIDE_OR_OFF)); 50 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1); 51 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500); 52 sensorStore->setIntegerSensor( 53 DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0); 54 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51); 55 sensorStore->setIntegerSensor( 56 DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365); 57 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30); 58 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12); 59 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18); 60 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1); 61 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_TYPE, 62 toInt(Obd2FuelType::GASOLINE)); 63 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153); 64 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16); 65 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16); 66 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16); 67 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16); 68 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5); 69 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ENGINE_RPM, 1250.); 70 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::VEHICLE_SPEED, 40.); 71 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::TIMING_ADVANCE, 2.5); 72 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::THROTTLE_POSITION, 19.75); 73 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265); 74 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824); 75 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE, 76 -0.373); 77 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1, 78 190.); 79 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.); 80 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306); 81 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188); 82 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094); 83 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024); 84 85 return sensorStore; 86 } 87 88 enum class FakeDataCommand : int32_t { 89 Stop = 0, 90 Start = 1, 91 }; 92 93 EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) 94 : mPropStore(propStore), 95 mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), 96 mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, 97 this, std::placeholders::_1)), 98 mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated, 99 this, std::placeholders::_1, std::placeholders::_2)) { 100 initStaticConfig(); 101 for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { 102 mPropStore->registerProperty(kVehicleProperties[i].config); 103 } 104 } 105 106 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( 107 const VehiclePropValue& requestedPropValue, StatusCode* outStatus) { 108 auto propId = requestedPropValue.prop; 109 auto& pool = *getValuePool(); 110 VehiclePropValuePtr v = nullptr; 111 112 switch (propId) { 113 case OBD2_FREEZE_FRAME: 114 v = pool.obtainComplex(); 115 *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get()); 116 break; 117 case OBD2_FREEZE_FRAME_INFO: 118 v = pool.obtainComplex(); 119 *outStatus = fillObd2DtcInfo(v.get()); 120 break; 121 default: 122 auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue); 123 if (internalPropValue != nullptr) { 124 v = getValuePool()->obtain(*internalPropValue); 125 } 126 127 *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG; 128 break; 129 } 130 131 return v; 132 } 133 134 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { 135 if (propValue.prop == kGenerateFakeDataControllingProperty) { 136 StatusCode status = handleGenerateFakeDataRequest(propValue); 137 if (status != StatusCode::OK) { 138 return status; 139 } 140 } else if (mHvacPowerProps.count(propValue.prop)) { 141 auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON), 142 toInt(VehicleAreaZone::ROW_1)); 143 144 if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1 145 && hvacPowerOn->value.int32Values[0] == 0) { 146 return StatusCode::NOT_AVAILABLE; 147 } 148 } else if (propValue.prop == OBD2_FREEZE_FRAME_CLEAR) { 149 return clearObd2FreezeFrames(propValue); 150 } else if (propValue.prop == VEHICLE_MAP_SERVICE) { 151 // Placeholder for future implementation of VMS property in the default hal. For now, just 152 // returns OK; otherwise, hal clients crash with property not supported. 153 return StatusCode::OK; 154 } 155 156 if (!mPropStore->writeValue(propValue)) { 157 return StatusCode::INVALID_ARG; 158 } 159 160 getEmulatorOrDie()->doSetValueFromClient(propValue); 161 162 return StatusCode::OK; 163 } 164 165 static bool isDiagnosticProperty(VehiclePropConfig propConfig) { 166 switch (propConfig.prop) { 167 case OBD2_LIVE_FRAME: 168 case OBD2_FREEZE_FRAME: 169 case OBD2_FREEZE_FRAME_CLEAR: 170 case OBD2_FREEZE_FRAME_INFO: 171 return true; 172 } 173 return false; 174 } 175 176 // Parse supported properties list and generate vector of property values to hold current values. 177 void EmulatedVehicleHal::onCreate() { 178 for (auto& it : kVehicleProperties) { 179 VehiclePropConfig cfg = it.config; 180 int32_t supportedAreas = cfg.supportedAreas; 181 182 if (isDiagnosticProperty(cfg)) { 183 // do not write an initial empty value for the diagnostic properties 184 // as we will initialize those separately. 185 continue; 186 } 187 188 // A global property will have supportedAreas = 0 189 if (isGlobalProp(cfg.prop)) { 190 supportedAreas = 0; 191 } 192 193 // This loop is a do-while so it executes at least once to handle global properties 194 do { 195 int32_t curArea = supportedAreas; 196 supportedAreas &= supportedAreas - 1; // Clear the right-most bit of supportedAreas. 197 curArea ^= supportedAreas; // Set curArea to the previously cleared bit. 198 199 // Create a separate instance for each individual zone 200 VehiclePropValue prop = { 201 .prop = cfg.prop, 202 .areaId = curArea, 203 }; 204 if (it.initialAreaValues.size() > 0) { 205 auto valueForAreaIt = it.initialAreaValues.find(curArea); 206 if (valueForAreaIt != it.initialAreaValues.end()) { 207 prop.value = valueForAreaIt->second; 208 } else { 209 ALOGW("%s failed to get default value for prop 0x%x area 0x%x", 210 __func__, cfg.prop, curArea); 211 } 212 } else { 213 prop.value = it.initialValue; 214 } 215 mPropStore->writeValue(prop); 216 217 } while (supportedAreas != 0); 218 } 219 initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME)); 220 initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME)); 221 } 222 223 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() { 224 return mPropStore->getAllConfigs(); 225 } 226 227 void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) { 228 VehiclePropValuePtr v; 229 230 auto& pool = *getValuePool(); 231 232 for (int32_t property : properties) { 233 if (isContinuousProperty(property)) { 234 auto internalPropValue = mPropStore->readValueOrNull(property); 235 if (internalPropValue != nullptr) { 236 v = pool.obtain(*internalPropValue); 237 } 238 } else { 239 ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property); 240 } 241 242 if (v.get()) { 243 v->timestamp = elapsedRealtimeNano(); 244 doHalEvent(std::move(v)); 245 } 246 } 247 } 248 249 StatusCode EmulatedVehicleHal::subscribe(int32_t property, int32_t, 250 float sampleRate) { 251 ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate); 252 253 if (isContinuousProperty(property)) { 254 mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property); 255 } 256 return StatusCode::OK; 257 } 258 259 StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) { 260 ALOGI("%s propId: 0x%x", __func__, property); 261 if (isContinuousProperty(property)) { 262 mRecurrentTimer.unregisterRecurrentEvent(property); 263 } 264 return StatusCode::OK; 265 } 266 267 bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const { 268 const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId); 269 if (config == nullptr) { 270 ALOGW("Config not found for property: 0x%x", propId); 271 return false; 272 } 273 return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS; 274 } 275 276 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) { 277 if (propValue.prop == kGenerateFakeDataControllingProperty) { 278 StatusCode status = handleGenerateFakeDataRequest(propValue); 279 if (status != StatusCode::OK) { 280 return false; 281 } 282 } 283 284 if (mPropStore->writeValue(propValue)) { 285 doHalEvent(getValuePool()->obtain(propValue)); 286 return true; 287 } else { 288 return false; 289 } 290 } 291 292 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const { 293 return mPropStore->readAllValues(); 294 } 295 296 StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) { 297 ALOGI("%s", __func__); 298 const auto& v = request.value; 299 if (v.int32Values.size() < 2) { 300 ALOGE("%s: expected at least 2 elements in int32Values, got: %zu", __func__, 301 v.int32Values.size()); 302 return StatusCode::INVALID_ARG; 303 } 304 305 FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]); 306 int32_t propId = v.int32Values[1]; 307 308 switch (command) { 309 case FakeDataCommand::Start: { 310 if (!v.int64Values.size()) { 311 ALOGE("%s: interval is not provided in int64Values", __func__); 312 return StatusCode::INVALID_ARG; 313 } 314 auto interval = std::chrono::nanoseconds(v.int64Values[0]); 315 316 if (v.floatValues.size() < 3) { 317 ALOGE("%s: expected at least 3 element sin floatValues, got: %zu", __func__, 318 v.floatValues.size()); 319 return StatusCode::INVALID_ARG; 320 } 321 float initialValue = v.floatValues[0]; 322 float dispersion = v.floatValues[1]; 323 float increment = v.floatValues[2]; 324 325 ALOGI("%s, propId: %d, initalValue: %f", __func__, propId, initialValue); 326 mFakeValueGenerator.startGeneratingHalEvents( 327 interval, propId, initialValue, dispersion, increment); 328 329 break; 330 } 331 case FakeDataCommand::Stop: { 332 ALOGI("%s, FakeDataCommandStop", __func__); 333 mFakeValueGenerator.stopGeneratingHalEvents(propId); 334 break; 335 } 336 default: { 337 ALOGE("%s: unexpected command: %d", __func__, command); 338 return StatusCode::INVALID_ARG; 339 } 340 } 341 return StatusCode::OK; 342 } 343 344 void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) { 345 VehiclePropValuePtr updatedPropValue {}; 346 switch (getPropType(propId)) { 347 case VehiclePropertyType::FLOAT: 348 updatedPropValue = getValuePool()->obtainFloat(value); 349 break; 350 case VehiclePropertyType::INT32: 351 updatedPropValue = getValuePool()->obtainInt32(static_cast<int32_t>(value)); 352 break; 353 default: 354 ALOGE("%s: data type for property: 0x%x not supported", __func__, propId); 355 return; 356 357 } 358 359 if (updatedPropValue) { 360 updatedPropValue->prop = propId; 361 updatedPropValue->areaId = 0; // Add area support if necessary. 362 updatedPropValue->timestamp = elapsedRealtimeNano(); 363 mPropStore->writeValue(*updatedPropValue); 364 auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode; 365 if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) { 366 doHalEvent(move(updatedPropValue)); 367 } 368 } 369 } 370 371 void EmulatedVehicleHal::initStaticConfig() { 372 for (auto&& it = std::begin(kVehicleProperties); it != std::end(kVehicleProperties); ++it) { 373 const auto& cfg = it->config; 374 VehiclePropertyStore::TokenFunction tokenFunction = nullptr; 375 376 switch (cfg.prop) { 377 case OBD2_FREEZE_FRAME: { 378 tokenFunction = [](const VehiclePropValue& propValue) { 379 return propValue.timestamp; 380 }; 381 break; 382 } 383 default: 384 break; 385 } 386 387 mPropStore->registerProperty(cfg, tokenFunction); 388 } 389 } 390 391 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) { 392 auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0); 393 auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]), 394 static_cast<size_t>(propConfig.configArray[1])); 395 sensorStore->fillPropValue("", liveObd2Frame.get()); 396 liveObd2Frame->prop = OBD2_LIVE_FRAME; 397 398 mPropStore->writeValue(*liveObd2Frame); 399 } 400 401 void EmulatedVehicleHal::initObd2FreezeFrame(const VehiclePropConfig& propConfig) { 402 auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]), 403 static_cast<size_t>(propConfig.configArray[1])); 404 405 static std::vector<std::string> sampleDtcs = {"P0070", 406 "P0102" 407 "P0123"}; 408 for (auto&& dtc : sampleDtcs) { 409 auto freezeFrame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0); 410 sensorStore->fillPropValue(dtc, freezeFrame.get()); 411 freezeFrame->prop = OBD2_FREEZE_FRAME; 412 413 mPropStore->writeValue(*freezeFrame); 414 } 415 } 416 417 StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue, 418 VehiclePropValue* outValue) { 419 if (requestedPropValue.value.int64Values.size() != 1) { 420 ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp"); 421 return StatusCode::INVALID_ARG; 422 } 423 auto timestamp = requestedPropValue.value.int64Values[0]; 424 auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp); 425 if (freezeFrame == nullptr) { 426 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); 427 return StatusCode::INVALID_ARG; 428 } 429 outValue->prop = OBD2_FREEZE_FRAME; 430 outValue->value.int32Values = freezeFrame->value.int32Values; 431 outValue->value.floatValues = freezeFrame->value.floatValues; 432 outValue->value.bytes = freezeFrame->value.bytes; 433 outValue->value.stringValue = freezeFrame->value.stringValue; 434 outValue->timestamp = freezeFrame->timestamp; 435 return StatusCode::OK; 436 } 437 438 StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const VehiclePropValue& propValue) { 439 if (propValue.value.int64Values.size() == 0) { 440 mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME); 441 return StatusCode::OK; 442 } else { 443 for (int64_t timestamp : propValue.value.int64Values) { 444 auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp); 445 if (freezeFrame == nullptr) { 446 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); 447 return StatusCode::INVALID_ARG; 448 } 449 mPropStore->removeValue(*freezeFrame); 450 } 451 } 452 return StatusCode::OK; 453 } 454 455 StatusCode EmulatedVehicleHal::fillObd2DtcInfo(VehiclePropValue* outValue) { 456 std::vector<int64_t> timestamps; 457 for (const auto& freezeFrame : mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) { 458 timestamps.push_back(freezeFrame.timestamp); 459 } 460 outValue->value.int64Values = timestamps; 461 outValue->prop = OBD2_FREEZE_FRAME_INFO; 462 return StatusCode::OK; 463 } 464 465 } // impl 466 467 } // namespace V2_0 468 } // namespace vehicle 469 } // namespace automotive 470 } // namespace hardware 471 } // namespace android 472