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 "JsonFakeValueGenerator.h"
23 #include "LinearFakeValueGenerator.h"
24 #include "Obd2SensorStore.h"
25
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace vehicle {
30 namespace V2_0 {
31
32 namespace impl {
33
fillDefaultObd2Frame(size_t numVendorIntegerSensors,size_t numVendorFloatSensors)34 static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors,
35 size_t numVendorFloatSensors) {
36 std::unique_ptr<Obd2SensorStore> sensorStore(
37 new Obd2SensorStore(numVendorIntegerSensors, numVendorFloatSensors));
38
39 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
40 toInt(Obd2FuelSystemStatus::CLOSED_LOOP));
41 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0);
42 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_MONITORS_SUPPORTED,
43 toInt(Obd2IgnitionMonitorKind::SPARK));
44 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_SPECIFIC_MONITORS,
45 Obd2CommonIgnitionMonitors::COMPONENTS_AVAILABLE |
46 Obd2CommonIgnitionMonitors::MISFIRE_AVAILABLE |
47 Obd2SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE |
48 Obd2SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE);
49 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35);
50 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS,
51 toInt(Obd2SecondaryAirStatus::FROM_OUTSIDE_OR_OFF));
52 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1);
53 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500);
54 sensorStore->setIntegerSensor(
55 DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0);
56 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51);
57 sensorStore->setIntegerSensor(
58 DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365);
59 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30);
60 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12);
61 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18);
62 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1);
63 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_TYPE,
64 toInt(Obd2FuelType::GASOLINE));
65 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153);
66 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16);
67 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16);
68 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16);
69 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16);
70 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5);
71 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ENGINE_RPM, 1250.);
72 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::VEHICLE_SPEED, 40.);
73 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::TIMING_ADVANCE, 2.5);
74 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::THROTTLE_POSITION, 19.75);
75 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265);
76 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824);
77 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE,
78 -0.373);
79 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1,
80 190.);
81 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.);
82 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306);
83 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188);
84 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094);
85 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
86
87 return sensorStore;
88 }
89
EmulatedVehicleHal(VehiclePropertyStore * propStore)90 EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
91 : mPropStore(propStore),
92 mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
93 mRecurrentTimer(
94 std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
95 mGeneratorHub(
96 std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
97 initStaticConfig();
98 for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
99 mPropStore->registerProperty(kVehicleProperties[i].config);
100 }
101 }
102
get(const VehiclePropValue & requestedPropValue,StatusCode * outStatus)103 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
104 const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
105 auto propId = requestedPropValue.prop;
106 auto& pool = *getValuePool();
107 VehiclePropValuePtr v = nullptr;
108
109 switch (propId) {
110 case OBD2_FREEZE_FRAME:
111 v = pool.obtainComplex();
112 *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
113 break;
114 case OBD2_FREEZE_FRAME_INFO:
115 v = pool.obtainComplex();
116 *outStatus = fillObd2DtcInfo(v.get());
117 break;
118 default:
119 auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
120 if (internalPropValue != nullptr) {
121 v = getValuePool()->obtain(*internalPropValue);
122 }
123
124 *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
125 break;
126 }
127
128 return v;
129 }
130
set(const VehiclePropValue & propValue)131 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
132 static constexpr bool shouldUpdateStatus = false;
133
134 if (propValue.prop == kGenerateFakeDataControllingProperty) {
135 StatusCode status = handleGenerateFakeDataRequest(propValue);
136 if (status != StatusCode::OK) {
137 return status;
138 }
139 } else if (mHvacPowerProps.count(propValue.prop)) {
140 auto hvacPowerOn = mPropStore->readValueOrNull(
141 toInt(VehicleProperty::HVAC_POWER_ON),
142 (VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT |
143 VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
144 VehicleAreaSeat::ROW_2_RIGHT));
145
146 if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
147 && hvacPowerOn->value.int32Values[0] == 0) {
148 return StatusCode::NOT_AVAILABLE;
149 }
150 } else {
151 // Handle property specific code
152 switch (propValue.prop) {
153 case OBD2_FREEZE_FRAME_CLEAR:
154 return clearObd2FreezeFrames(propValue);
155 case VEHICLE_MAP_SERVICE:
156 // Placeholder for future implementation of VMS property in the default hal. For
157 // now, just returns OK; otherwise, hal clients crash with property not supported.
158 return StatusCode::OK;
159 case AP_POWER_STATE_REPORT:
160 switch (propValue.value.int32Values[0]) {
161 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
162 case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
163 case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
164 // CPMS is in WAIT_FOR_VHAL state, simply move to ON
165 doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
166 break;
167 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
168 case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
169 // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
170 doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
171 break;
172 case toInt(VehicleApPowerStateReport::ON):
173 case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
174 case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
175 // Do nothing
176 break;
177 default:
178 // Unknown state
179 break;
180 }
181 break;
182 }
183 }
184
185 if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
186 // Android side cannot set property status - this value is the
187 // purview of the HAL implementation to reflect the state of
188 // its underlying hardware
189 return StatusCode::INVALID_ARG;
190 }
191 auto currentPropValue = mPropStore->readValueOrNull(propValue);
192
193 if (currentPropValue == nullptr) {
194 return StatusCode::INVALID_ARG;
195 }
196 if (currentPropValue->status != VehiclePropertyStatus::AVAILABLE) {
197 // do not allow Android side to set() a disabled/error property
198 return StatusCode::NOT_AVAILABLE;
199 }
200
201 if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) {
202 return StatusCode::INVALID_ARG;
203 }
204
205 getEmulatorOrDie()->doSetValueFromClient(propValue);
206 doHalEvent(getValuePool()->obtain(propValue));
207
208 return StatusCode::OK;
209 }
210
isDiagnosticProperty(VehiclePropConfig propConfig)211 static bool isDiagnosticProperty(VehiclePropConfig propConfig) {
212 switch (propConfig.prop) {
213 case OBD2_LIVE_FRAME:
214 case OBD2_FREEZE_FRAME:
215 case OBD2_FREEZE_FRAME_CLEAR:
216 case OBD2_FREEZE_FRAME_INFO:
217 return true;
218 }
219 return false;
220 }
221
222 // Parse supported properties list and generate vector of property values to hold current values.
onCreate()223 void EmulatedVehicleHal::onCreate() {
224 static constexpr bool shouldUpdateStatus = true;
225
226 for (auto& it : kVehicleProperties) {
227 VehiclePropConfig cfg = it.config;
228 int32_t numAreas = cfg.areaConfigs.size();
229
230 if (isDiagnosticProperty(cfg)) {
231 // do not write an initial empty value for the diagnostic properties
232 // as we will initialize those separately.
233 continue;
234 }
235
236 // A global property will have only a single area
237 if (isGlobalProp(cfg.prop)) {
238 numAreas = 1;
239 }
240
241 for (int i = 0; i < numAreas; i++) {
242 int32_t curArea;
243
244 if (isGlobalProp(cfg.prop)) {
245 curArea = 0;
246 } else {
247 curArea = cfg.areaConfigs[i].areaId;
248 }
249
250 // Create a separate instance for each individual zone
251 VehiclePropValue prop = {
252 .prop = cfg.prop,
253 .areaId = curArea,
254 };
255
256 if (it.initialAreaValues.size() > 0) {
257 auto valueForAreaIt = it.initialAreaValues.find(curArea);
258 if (valueForAreaIt != it.initialAreaValues.end()) {
259 prop.value = valueForAreaIt->second;
260 } else {
261 ALOGW("%s failed to get default value for prop 0x%x area 0x%x",
262 __func__, cfg.prop, curArea);
263 }
264 } else {
265 prop.value = it.initialValue;
266 }
267 mPropStore->writeValue(prop, shouldUpdateStatus);
268 }
269 }
270 initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
271 initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
272 }
273
listProperties()274 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() {
275 return mPropStore->getAllConfigs();
276 }
277
onContinuousPropertyTimer(const std::vector<int32_t> & properties)278 void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
279 VehiclePropValuePtr v;
280
281 auto& pool = *getValuePool();
282
283 for (int32_t property : properties) {
284 if (isContinuousProperty(property)) {
285 auto internalPropValue = mPropStore->readValueOrNull(property);
286 if (internalPropValue != nullptr) {
287 v = pool.obtain(*internalPropValue);
288 }
289 } else {
290 ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
291 }
292
293 if (v.get()) {
294 v->timestamp = elapsedRealtimeNano();
295 doHalEvent(std::move(v));
296 }
297 }
298 }
299
subscribe(int32_t property,float sampleRate)300 StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
301 ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
302
303 if (isContinuousProperty(property)) {
304 mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
305 }
306 return StatusCode::OK;
307 }
308
unsubscribe(int32_t property)309 StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
310 ALOGI("%s propId: 0x%x", __func__, property);
311 if (isContinuousProperty(property)) {
312 mRecurrentTimer.unregisterRecurrentEvent(property);
313 }
314 return StatusCode::OK;
315 }
316
isContinuousProperty(int32_t propId) const317 bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
318 const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
319 if (config == nullptr) {
320 ALOGW("Config not found for property: 0x%x", propId);
321 return false;
322 }
323 return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
324 }
325
setPropertyFromVehicle(const VehiclePropValue & propValue)326 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
327 static constexpr bool shouldUpdateStatus = true;
328
329 if (propValue.prop == kGenerateFakeDataControllingProperty) {
330 StatusCode status = handleGenerateFakeDataRequest(propValue);
331 if (status != StatusCode::OK) {
332 return false;
333 }
334 }
335
336 if (mPropStore->writeValue(propValue, shouldUpdateStatus)) {
337 doHalEvent(getValuePool()->obtain(propValue));
338 return true;
339 } else {
340 return false;
341 }
342 }
343
getAllProperties() const344 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
345 return mPropStore->readAllValues();
346 }
347
handleGenerateFakeDataRequest(const VehiclePropValue & request)348 StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
349 ALOGI("%s", __func__);
350 const auto& v = request.value;
351 if (!v.int32Values.size()) {
352 ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
353 return StatusCode::INVALID_ARG;
354 }
355
356 FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
357
358 switch (command) {
359 case FakeDataCommand::StartLinear: {
360 ALOGI("%s, FakeDataCommand::StartLinear", __func__);
361 if (v.int32Values.size() < 2) {
362 ALOGE("%s: expected property ID in int32Values", __func__);
363 return StatusCode::INVALID_ARG;
364 }
365 if (!v.int64Values.size()) {
366 ALOGE("%s: interval is not provided in int64Values", __func__);
367 return StatusCode::INVALID_ARG;
368 }
369 if (v.floatValues.size() < 3) {
370 ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
371 v.floatValues.size());
372 return StatusCode::INVALID_ARG;
373 }
374 int32_t cookie = v.int32Values[1];
375 mGeneratorHub.registerGenerator(cookie,
376 std::make_unique<LinearFakeValueGenerator>(request));
377 break;
378 }
379 case FakeDataCommand::StartJson: {
380 ALOGI("%s, FakeDataCommand::StartJson", __func__);
381 if (v.stringValue.empty()) {
382 ALOGE("%s: path to JSON file is missing", __func__);
383 return StatusCode::INVALID_ARG;
384 }
385 int32_t cookie = std::hash<std::string>()(v.stringValue);
386 mGeneratorHub.registerGenerator(cookie,
387 std::make_unique<JsonFakeValueGenerator>(request));
388 break;
389 }
390 case FakeDataCommand::StopLinear: {
391 ALOGI("%s, FakeDataCommand::StopLinear", __func__);
392 if (v.int32Values.size() < 2) {
393 ALOGE("%s: expected property ID in int32Values", __func__);
394 return StatusCode::INVALID_ARG;
395 }
396 int32_t cookie = v.int32Values[1];
397 mGeneratorHub.unregisterGenerator(cookie);
398 break;
399 }
400 case FakeDataCommand::StopJson: {
401 ALOGI("%s, FakeDataCommand::StopJson", __func__);
402 if (v.stringValue.empty()) {
403 ALOGE("%s: path to JSON file is missing", __func__);
404 return StatusCode::INVALID_ARG;
405 }
406 int32_t cookie = std::hash<std::string>()(v.stringValue);
407 mGeneratorHub.unregisterGenerator(cookie);
408 break;
409 }
410 case FakeDataCommand::KeyPress: {
411 ALOGI("%s, FakeDataCommand::KeyPress", __func__);
412 int32_t keyCode = request.value.int32Values[2];
413 int32_t display = request.value.int32Values[3];
414 doHalEvent(
415 createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
416 doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
417 break;
418 }
419 default: {
420 ALOGE("%s: unexpected command: %d", __func__, command);
421 return StatusCode::INVALID_ARG;
422 }
423 }
424 return StatusCode::OK;
425 }
426
createApPowerStateReq(VehicleApPowerStateReq state,int32_t param)427 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq(
428 VehicleApPowerStateReq state, int32_t param) {
429 auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
430 req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
431 req->areaId = 0;
432 req->timestamp = elapsedRealtimeNano();
433 req->status = VehiclePropertyStatus::AVAILABLE;
434 req->value.int32Values[0] = toInt(state);
435 req->value.int32Values[1] = param;
436 return req;
437 }
438
createHwInputKeyProp(VehicleHwKeyInputAction action,int32_t keyCode,int32_t targetDisplay)439 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
440 VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
441 auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
442 keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
443 keyEvent->areaId = 0;
444 keyEvent->timestamp = elapsedRealtimeNano();
445 keyEvent->status = VehiclePropertyStatus::AVAILABLE;
446 keyEvent->value.int32Values[0] = toInt(action);
447 keyEvent->value.int32Values[1] = keyCode;
448 keyEvent->value.int32Values[2] = targetDisplay;
449 return keyEvent;
450 }
451
onFakeValueGenerated(const VehiclePropValue & value)452 void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
453 ALOGD("%s: %s", __func__, toString(value).c_str());
454 static constexpr bool shouldUpdateStatus = false;
455
456 VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
457 if (updatedPropValue) {
458 updatedPropValue->timestamp = elapsedRealtimeNano();
459 updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
460 mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
461 auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
462 if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
463 doHalEvent(std::move(updatedPropValue));
464 }
465 }
466 }
467
initStaticConfig()468 void EmulatedVehicleHal::initStaticConfig() {
469 for (auto&& it = std::begin(kVehicleProperties); it != std::end(kVehicleProperties); ++it) {
470 const auto& cfg = it->config;
471 VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
472
473 switch (cfg.prop) {
474 case OBD2_FREEZE_FRAME: {
475 tokenFunction = [](const VehiclePropValue& propValue) {
476 return propValue.timestamp;
477 };
478 break;
479 }
480 default:
481 break;
482 }
483
484 mPropStore->registerProperty(cfg, tokenFunction);
485 }
486 }
487
initObd2LiveFrame(const VehiclePropConfig & propConfig)488 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) {
489 static constexpr bool shouldUpdateStatus = true;
490
491 auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
492 auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
493 static_cast<size_t>(propConfig.configArray[1]));
494 sensorStore->fillPropValue("", liveObd2Frame.get());
495 liveObd2Frame->prop = OBD2_LIVE_FRAME;
496
497 mPropStore->writeValue(*liveObd2Frame, shouldUpdateStatus);
498 }
499
initObd2FreezeFrame(const VehiclePropConfig & propConfig)500 void EmulatedVehicleHal::initObd2FreezeFrame(const VehiclePropConfig& propConfig) {
501 static constexpr bool shouldUpdateStatus = true;
502
503 auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
504 static_cast<size_t>(propConfig.configArray[1]));
505
506 static std::vector<std::string> sampleDtcs = {"P0070",
507 "P0102"
508 "P0123"};
509 for (auto&& dtc : sampleDtcs) {
510 auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
511 sensorStore->fillPropValue(dtc, freezeFrame.get());
512 freezeFrame->prop = OBD2_FREEZE_FRAME;
513
514 mPropStore->writeValue(*freezeFrame, shouldUpdateStatus);
515 }
516 }
517
fillObd2FreezeFrame(const VehiclePropValue & requestedPropValue,VehiclePropValue * outValue)518 StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue,
519 VehiclePropValue* outValue) {
520 if (requestedPropValue.value.int64Values.size() != 1) {
521 ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp");
522 return StatusCode::INVALID_ARG;
523 }
524 auto timestamp = requestedPropValue.value.int64Values[0];
525 auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
526 if (freezeFrame == nullptr) {
527 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
528 return StatusCode::INVALID_ARG;
529 }
530 outValue->prop = OBD2_FREEZE_FRAME;
531 outValue->value.int32Values = freezeFrame->value.int32Values;
532 outValue->value.floatValues = freezeFrame->value.floatValues;
533 outValue->value.bytes = freezeFrame->value.bytes;
534 outValue->value.stringValue = freezeFrame->value.stringValue;
535 outValue->timestamp = freezeFrame->timestamp;
536 return StatusCode::OK;
537 }
538
clearObd2FreezeFrames(const VehiclePropValue & propValue)539 StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
540 if (propValue.value.int64Values.size() == 0) {
541 mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
542 return StatusCode::OK;
543 } else {
544 for (int64_t timestamp : propValue.value.int64Values) {
545 auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
546 if (freezeFrame == nullptr) {
547 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
548 return StatusCode::INVALID_ARG;
549 }
550 mPropStore->removeValue(*freezeFrame);
551 }
552 }
553 return StatusCode::OK;
554 }
555
fillObd2DtcInfo(VehiclePropValue * outValue)556 StatusCode EmulatedVehicleHal::fillObd2DtcInfo(VehiclePropValue* outValue) {
557 std::vector<int64_t> timestamps;
558 for (const auto& freezeFrame : mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) {
559 timestamps.push_back(freezeFrame.timestamp);
560 }
561 outValue->value.int64Values = timestamps;
562 outValue->prop = OBD2_FREEZE_FRAME_INFO;
563 return StatusCode::OK;
564 }
565
566 } // impl
567
568 } // namespace V2_0
569 } // namespace vehicle
570 } // namespace automotive
571 } // namespace hardware
572 } // namespace android
573