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