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 17#define LOG_TAG "DefaultVehicleHal_v2_0" 18#include <android/log.h> 19 20#include "EmulatedVehicleHal.h" 21 22namespace android { 23namespace hardware { 24namespace automotive { 25namespace vehicle { 26namespace V2_0 { 27 28namespace impl { 29 30enum class FakeDataCommand : int32_t { 31 Stop = 0, 32 Start = 1, 33}; 34 35EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) 36 : mPropStore(propStore), 37 mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), 38 mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, 39 this, std::placeholders::_1)), 40 mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated, 41 this, std::placeholders::_1, std::placeholders::_2)) { 42 43 for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { 44 mPropStore->registerProperty(kVehicleProperties[i].config); 45 } 46} 47 48VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( 49 const VehiclePropValue& requestedPropValue, StatusCode* outStatus) { 50 VehiclePropValuePtr v = nullptr; 51 52 auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue); 53 if (internalPropValue != nullptr) { 54 v = getValuePool()->obtain(*internalPropValue); 55 } 56 57 *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG; 58 return v; 59} 60 61StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { 62 if (propValue.prop == kGenerateFakeDataControllingProperty) { 63 return handleGenerateFakeDataRequest(propValue); 64 }; 65 66 if (mHvacPowerProps.count(propValue.prop)) { 67 auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON), 68 toInt(VehicleAreaZone::ROW_1)); 69 70 if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1 71 && hvacPowerOn->value.int32Values[0] == 0) { 72 return StatusCode::NOT_AVAILABLE; 73 } 74 } 75 76 if (!mPropStore->writeValue(propValue)) { 77 return StatusCode::INVALID_ARG; 78 } 79 80 getEmulatorOrDie()->doSetValueFromClient(propValue); 81 82 return StatusCode::OK; 83} 84 85// Parse supported properties list and generate vector of property values to hold current values. 86void EmulatedVehicleHal::onCreate() { 87 for (auto& it : kVehicleProperties) { 88 VehiclePropConfig cfg = it.config; 89 int32_t supportedAreas = cfg.supportedAreas; 90 91 // A global property will have supportedAreas = 0 92 if (isGlobalProp(cfg.prop)) { 93 supportedAreas = 0; 94 } 95 96 // This loop is a do-while so it executes at least once to handle global properties 97 do { 98 int32_t curArea = supportedAreas; 99 supportedAreas &= supportedAreas - 1; // Clear the right-most bit of supportedAreas. 100 curArea ^= supportedAreas; // Set curArea to the previously cleared bit. 101 102 // Create a separate instance for each individual zone 103 VehiclePropValue prop = { 104 .prop = cfg.prop, 105 .areaId = curArea, 106 }; 107 if (it.initialAreaValues.size() > 0) { 108 auto valueForAreaIt = it.initialAreaValues.find(curArea); 109 if (valueForAreaIt != it.initialAreaValues.end()) { 110 prop.value = valueForAreaIt->second; 111 } else { 112 ALOGW("%s failed to get default value for prop 0x%x area 0x%x", 113 __func__, cfg.prop, curArea); 114 } 115 } else { 116 prop.value = it.initialValue; 117 } 118 mPropStore->writeValue(prop); 119 120 } while (supportedAreas != 0); 121 } 122} 123 124std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() { 125 return mPropStore->getAllConfigs(); 126} 127 128void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) { 129 VehiclePropValuePtr v; 130 131 auto& pool = *getValuePool(); 132 133 for (int32_t property : properties) { 134 if (isContinuousProperty(property)) { 135 auto internalPropValue = mPropStore->readValueOrNull(property); 136 if (internalPropValue != nullptr) { 137 v = pool.obtain(*internalPropValue); 138 } 139 } else { 140 ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property); 141 } 142 143 if (v.get()) { 144 v->timestamp = elapsedRealtimeNano(); 145 doHalEvent(std::move(v)); 146 } 147 } 148} 149 150StatusCode EmulatedVehicleHal::subscribe(int32_t property, int32_t, 151 float sampleRate) { 152 ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate); 153 154 if (isContinuousProperty(property)) { 155 mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property); 156 } 157 return StatusCode::OK; 158} 159 160StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) { 161 ALOGI("%s propId: 0x%x", __func__, property); 162 if (isContinuousProperty(property)) { 163 mRecurrentTimer.unregisterRecurrentEvent(property); 164 } 165 return StatusCode::OK; 166} 167 168bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const { 169 const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId); 170 if (config == nullptr) { 171 ALOGW("Config not found for property: 0x%x", propId); 172 return false; 173 } 174 return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS; 175} 176 177bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) { 178 if (mPropStore->writeValue(propValue)) { 179 doHalEvent(getValuePool()->obtain(propValue)); 180 return true; 181 } else { 182 return false; 183 } 184} 185 186std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const { 187 return mPropStore->readAllValues(); 188} 189 190StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) { 191 ALOGI("%s", __func__); 192 const auto& v = request.value; 193 if (v.int32Values.size() < 2) { 194 ALOGE("%s: expected at least 2 elements in int32Values, got: %zu", __func__, 195 v.int32Values.size()); 196 return StatusCode::INVALID_ARG; 197 } 198 199 FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]); 200 int32_t propId = v.int32Values[1]; 201 202 switch (command) { 203 case FakeDataCommand::Start: { 204 if (!v.int64Values.size()) { 205 ALOGE("%s: interval is not provided in int64Values", __func__); 206 return StatusCode::INVALID_ARG; 207 } 208 auto interval = std::chrono::nanoseconds(v.int64Values[0]); 209 210 if (v.floatValues.size() < 3) { 211 ALOGE("%s: expected at least 3 element sin floatValues, got: %zu", __func__, 212 v.floatValues.size()); 213 return StatusCode::INVALID_ARG; 214 } 215 float initialValue = v.floatValues[0]; 216 float dispersion = v.floatValues[1]; 217 float increment = v.floatValues[2]; 218 219 ALOGI("%s, propId: %d, initalValue: %f", __func__, propId, initialValue); 220 mFakeValueGenerator.startGeneratingHalEvents( 221 interval, propId, initialValue, dispersion, increment); 222 223 break; 224 } 225 case FakeDataCommand::Stop: { 226 ALOGI("%s, FakeDataCommandStop", __func__); 227 mFakeValueGenerator.stopGeneratingHalEvents(propId); 228 break; 229 } 230 default: { 231 ALOGE("%s: unexpected command: %d", __func__, command); 232 return StatusCode::INVALID_ARG; 233 } 234 } 235 return StatusCode::OK; 236} 237 238void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) { 239 VehiclePropValuePtr updatedPropValue {}; 240 switch (getPropType(propId)) { 241 case VehiclePropertyType::FLOAT: 242 updatedPropValue = getValuePool()->obtainFloat(value); 243 break; 244 case VehiclePropertyType::INT32: 245 updatedPropValue = getValuePool()->obtainInt32(static_cast<int32_t>(value)); 246 break; 247 default: 248 ALOGE("%s: data type for property: 0x%x not supported", __func__, propId); 249 return; 250 251 } 252 253 if (updatedPropValue) { 254 updatedPropValue->prop = propId; 255 updatedPropValue->areaId = 0; // Add area support if necessary. 256 updatedPropValue->timestamp = elapsedRealtimeNano(); 257 mPropStore->writeValue(*updatedPropValue); 258 auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode; 259 if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) { 260 doHalEvent(move(updatedPropValue)); 261 } 262 } 263} 264 265} // impl 266 267} // namespace V2_0 268} // namespace vehicle 269} // namespace automotive 270} // namespace hardware 271} // namespace android 272