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
fillDefaultObd2Frame(size_t numVendorIntegerSensors,size_t numVendorFloatSensors)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
EmulatedVehicleHal(VehiclePropertyStore * propStore)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
get(const VehiclePropValue & requestedPropValue,StatusCode * outStatus)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
set(const VehiclePropValue & propValue)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
isDiagnosticProperty(VehiclePropConfig propConfig)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.
onCreate()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
listProperties()223 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() {
224 return mPropStore->getAllConfigs();
225 }
226
onContinuousPropertyTimer(const std::vector<int32_t> & properties)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
subscribe(int32_t property,int32_t,float sampleRate)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
unsubscribe(int32_t property)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
isContinuousProperty(int32_t propId) const267 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
setPropertyFromVehicle(const VehiclePropValue & propValue)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
getAllProperties() const292 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
293 return mPropStore->readAllValues();
294 }
295
handleGenerateFakeDataRequest(const VehiclePropValue & request)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
onFakeValueGenerated(int32_t propId,float value)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
initStaticConfig()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
initObd2LiveFrame(const VehiclePropConfig & propConfig)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
initObd2FreezeFrame(const VehiclePropConfig & propConfig)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
fillObd2FreezeFrame(const VehiclePropValue & requestedPropValue,VehiclePropValue * outValue)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
clearObd2FreezeFrames(const VehiclePropValue & propValue)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
fillObd2DtcInfo(VehiclePropValue * outValue)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