Home | History | Annotate | Download | only in vhal_v2_0
      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 
     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 
     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 
    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 
    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 
    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.
    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 
    223 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties()  {
    224     return mPropStore->getAllConfigs();
    225 }
    226 
    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 
    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 
    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 
    267 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 
    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 
    292 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const  {
    293     return mPropStore->readAllValues();
    294 }
    295 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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