• 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 "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