• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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