Loading automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h +3 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,9 @@ class FakeVehicleHardware : public IVehicleHardware { const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const; bool isHvacPropAndHvacNotAvailable(int32_t propId, int32_t areaId) const; VhalResult<void> isAdasPropertyAvailable(int32_t adasStatePropertyId) const; VhalResult<void> synchronizeHvacTemp(int32_t hvacDualOnAreaId, std::optional<float> newTempC) const; std::optional<int32_t> getSyncedAreaIdIfHvacDualOn(int32_t hvacTemperatureSetAreaId) const; std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations(); Loading automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +81 −0 Original line number Diff line number Diff line Loading @@ -601,6 +601,65 @@ VhalResult<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& val return {}; } VhalResult<void> FakeVehicleHardware::synchronizeHvacTemp(int32_t hvacDualOnAreaId, std::optional<float> newTempC) const { auto hvacTemperatureSetResults = mServerSidePropStore->readValuesForProperty( toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); if (!hvacTemperatureSetResults.ok()) { return StatusError(StatusCode::NOT_AVAILABLE) << "Failed to get HVAC_TEMPERATURE_SET, error: " << getErrorMsg(hvacTemperatureSetResults); } auto& hvacTemperatureSetValues = hvacTemperatureSetResults.value(); std::optional<float> tempCToSynchronize = newTempC; for (size_t i = 0; i < hvacTemperatureSetValues.size(); i++) { int32_t areaId = hvacTemperatureSetValues[i]->areaId; if ((hvacDualOnAreaId & areaId) != areaId) { continue; } if (hvacTemperatureSetValues[i]->status != VehiclePropertyStatus::AVAILABLE) { continue; } // When HVAC_DUAL_ON is initially enabled, synchronize all area IDs // to the temperature of the first area ID, which is the driver's. if (!tempCToSynchronize.has_value()) { tempCToSynchronize = hvacTemperatureSetValues[i]->value.floatValues[0]; continue; } auto updatedValue = std::move(hvacTemperatureSetValues[i]); updatedValue->value.floatValues[0] = tempCToSynchronize.value(); updatedValue->timestamp = elapsedRealtimeNano(); // This will trigger a property change event for the current hvac property value. auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue), /*updateStatus=*/true, VehiclePropertyStore::EventMode::ALWAYS); if (!writeResult.ok()) { return StatusError(getErrorCode(writeResult)) << "Failed to write value into property store, error: " << getErrorMsg(writeResult); } } return {}; } std::optional<int32_t> FakeVehicleHardware::getSyncedAreaIdIfHvacDualOn( int32_t hvacTemperatureSetAreaId) const { auto hvacDualOnResults = mServerSidePropStore->readValuesForProperty(toInt(VehicleProperty::HVAC_DUAL_ON)); if (!hvacDualOnResults.ok()) { return std::nullopt; } auto& hvacDualOnValues = hvacDualOnResults.value(); for (size_t i = 0; i < hvacDualOnValues.size(); i++) { if ((hvacDualOnValues[i]->areaId & hvacTemperatureSetAreaId) == hvacTemperatureSetAreaId && hvacDualOnValues[i]->value.int32Values.size() == 1 && hvacDualOnValues[i]->value.int32Values[0] == 1) { return hvacDualOnValues[i]->areaId; } } return std::nullopt; } FakeVehicleHardware::ValueResultType FakeVehicleHardware::getUserHalProp( const VehiclePropValue& value) const { auto propId = value.prop; Loading Loading @@ -853,6 +912,28 @@ VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValu case toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION): *isSpecialValue = true; return setHvacTemperatureValueSuggestion(value); case toInt(VehicleProperty::HVAC_TEMPERATURE_SET): if (value.value.floatValues.size() != 1) { *isSpecialValue = true; return StatusError(StatusCode::INVALID_ARG) << "HVAC_DUAL_ON requires only one float value"; } if (auto hvacDualOnAreaId = getSyncedAreaIdIfHvacDualOn(value.areaId); hvacDualOnAreaId.has_value()) { *isSpecialValue = true; return synchronizeHvacTemp(hvacDualOnAreaId.value(), value.value.floatValues[0]); } return {}; case toInt(VehicleProperty::HVAC_DUAL_ON): if (value.value.int32Values.size() != 1) { *isSpecialValue = true; return StatusError(StatusCode::INVALID_ARG) << "HVAC_DUAL_ON requires only one int32 value"; } if (value.value.int32Values[0] == 1) { synchronizeHvacTemp(value.areaId, std::nullopt); } return {}; case toInt(VehicleProperty::LANE_CENTERING_ASSIST_COMMAND): { isAdasPropertyAvailableResult = isAdasPropertyAvailable(toInt(VehicleProperty::LANE_CENTERING_ASSIST_STATE)); Loading automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -1889,6 +1889,101 @@ TEST_F(FakeVehicleHardwareTest, testHvacPowerOnSendCurrentHvacPropValues) { } } TEST_F(FakeVehicleHardwareTest, testHvacDualOnSynchronizesTemp) { auto hvacDualOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_DUAL_ON))); auto hvacTemperatureSetConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET))); EXPECT_NE(hvacDualOnConfig, nullptr); EXPECT_NE(hvacTemperatureSetConfig, nullptr); for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) { int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId; subscribe(toInt(VehicleProperty::HVAC_TEMPERATURE_SET), hvacTemperatureSetAreaId, /*sampleRateHz*/ 0); } for (auto& hvacDualOnConfig : hvacDualOnConfig->areaConfigs) { int32_t hvacDualOnAreaId = hvacDualOnConfig.areaId; subscribe(toInt(VehicleProperty::HVAC_DUAL_ON), hvacDualOnAreaId, /*sampleRateHz*/ 0); StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_DUAL_ON), .areaId = hvacDualOnAreaId, .value.int32Values = {1}}); EXPECT_EQ(status, StatusCode::OK); // Verify there's an event for all HVAC_TEMPERATURE_SET // area IDs covered by the HVAC_DUAL_ON area ID auto events = getChangedProperties(); std::unordered_set<float> temperatureValues; for (const auto& event : events) { // Ignore HVAC_DUAL_ON event if (event.prop == toInt(VehicleProperty::HVAC_DUAL_ON)) { continue; } EXPECT_EQ(event.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); EXPECT_EQ((hvacDualOnAreaId & event.areaId), event.areaId); EXPECT_EQ(1u, event.value.floatValues.size()); temperatureValues.insert(event.value.floatValues[0]); } // Verify that the temperature value is the same for all events // Ie the temperature in all area IDs are synchronized EXPECT_EQ(1u, temperatureValues.size()); clearChangedProperties(); // Verify when any HVAC_TEMPERATURE_SET area ID is changed all // area IDs covered by the HVAC_DUAL_ON area ID are also changed for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) { int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId; if ((hvacDualOnAreaId & hvacTemperatureSetAreaId) != hvacTemperatureSetAreaId) { continue; } float expectedValue = 25; status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = hvacTemperatureSetAreaId, .value.floatValues = {expectedValue}}); EXPECT_EQ(status, StatusCode::OK); events = getChangedProperties(); for (const auto& event : events) { EXPECT_EQ(event.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); EXPECT_EQ(1u, event.value.floatValues.size()); EXPECT_EQ(expectedValue, event.value.floatValues[0]); } clearChangedProperties(); } status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_DUAL_ON), .areaId = hvacDualOnAreaId, .value.int32Values = {0}}); EXPECT_EQ(status, StatusCode::OK); // When HVAC_DUAL_ON is disabled, there should be no events created // for HVAC_TEMPERATURE_SET ie no temperature synchronization. events = getChangedProperties(); EXPECT_EQ(1u, events.size()); EXPECT_EQ(events[0].prop, toInt(VehicleProperty::HVAC_DUAL_ON)); EXPECT_EQ(events[0].areaId, hvacDualOnAreaId); clearChangedProperties(); // Verify when any HVAC_TEMPERATURE_SET area ID is // changed other area IDs do not change. for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) { int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId; if ((hvacDualOnAreaId & hvacTemperatureSetAreaId) != hvacTemperatureSetAreaId) { continue; } float expectedValue = 24; status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = hvacTemperatureSetAreaId, .value.floatValues = {expectedValue}}); EXPECT_EQ(status, StatusCode::OK); events = getChangedProperties(); EXPECT_EQ(1u, events.size()); EXPECT_EQ(events[0].prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); EXPECT_EQ(events[0].areaId, hvacTemperatureSetAreaId); EXPECT_EQ(1u, events[0].value.floatValues.size()); EXPECT_EQ(expectedValue, events[0].value.floatValues[0]); clearChangedProperties(); } } } TEST_F(FakeVehicleHardwareTest, testGetAdasPropNotAvailable) { std::unordered_map<int32_t, std::vector<int32_t>> adasEnabledPropToDependentProps = { { Loading Loading
automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h +3 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,9 @@ class FakeVehicleHardware : public IVehicleHardware { const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const; bool isHvacPropAndHvacNotAvailable(int32_t propId, int32_t areaId) const; VhalResult<void> isAdasPropertyAvailable(int32_t adasStatePropertyId) const; VhalResult<void> synchronizeHvacTemp(int32_t hvacDualOnAreaId, std::optional<float> newTempC) const; std::optional<int32_t> getSyncedAreaIdIfHvacDualOn(int32_t hvacTemperatureSetAreaId) const; std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations(); Loading
automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +81 −0 Original line number Diff line number Diff line Loading @@ -601,6 +601,65 @@ VhalResult<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& val return {}; } VhalResult<void> FakeVehicleHardware::synchronizeHvacTemp(int32_t hvacDualOnAreaId, std::optional<float> newTempC) const { auto hvacTemperatureSetResults = mServerSidePropStore->readValuesForProperty( toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); if (!hvacTemperatureSetResults.ok()) { return StatusError(StatusCode::NOT_AVAILABLE) << "Failed to get HVAC_TEMPERATURE_SET, error: " << getErrorMsg(hvacTemperatureSetResults); } auto& hvacTemperatureSetValues = hvacTemperatureSetResults.value(); std::optional<float> tempCToSynchronize = newTempC; for (size_t i = 0; i < hvacTemperatureSetValues.size(); i++) { int32_t areaId = hvacTemperatureSetValues[i]->areaId; if ((hvacDualOnAreaId & areaId) != areaId) { continue; } if (hvacTemperatureSetValues[i]->status != VehiclePropertyStatus::AVAILABLE) { continue; } // When HVAC_DUAL_ON is initially enabled, synchronize all area IDs // to the temperature of the first area ID, which is the driver's. if (!tempCToSynchronize.has_value()) { tempCToSynchronize = hvacTemperatureSetValues[i]->value.floatValues[0]; continue; } auto updatedValue = std::move(hvacTemperatureSetValues[i]); updatedValue->value.floatValues[0] = tempCToSynchronize.value(); updatedValue->timestamp = elapsedRealtimeNano(); // This will trigger a property change event for the current hvac property value. auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue), /*updateStatus=*/true, VehiclePropertyStore::EventMode::ALWAYS); if (!writeResult.ok()) { return StatusError(getErrorCode(writeResult)) << "Failed to write value into property store, error: " << getErrorMsg(writeResult); } } return {}; } std::optional<int32_t> FakeVehicleHardware::getSyncedAreaIdIfHvacDualOn( int32_t hvacTemperatureSetAreaId) const { auto hvacDualOnResults = mServerSidePropStore->readValuesForProperty(toInt(VehicleProperty::HVAC_DUAL_ON)); if (!hvacDualOnResults.ok()) { return std::nullopt; } auto& hvacDualOnValues = hvacDualOnResults.value(); for (size_t i = 0; i < hvacDualOnValues.size(); i++) { if ((hvacDualOnValues[i]->areaId & hvacTemperatureSetAreaId) == hvacTemperatureSetAreaId && hvacDualOnValues[i]->value.int32Values.size() == 1 && hvacDualOnValues[i]->value.int32Values[0] == 1) { return hvacDualOnValues[i]->areaId; } } return std::nullopt; } FakeVehicleHardware::ValueResultType FakeVehicleHardware::getUserHalProp( const VehiclePropValue& value) const { auto propId = value.prop; Loading Loading @@ -853,6 +912,28 @@ VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValu case toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION): *isSpecialValue = true; return setHvacTemperatureValueSuggestion(value); case toInt(VehicleProperty::HVAC_TEMPERATURE_SET): if (value.value.floatValues.size() != 1) { *isSpecialValue = true; return StatusError(StatusCode::INVALID_ARG) << "HVAC_DUAL_ON requires only one float value"; } if (auto hvacDualOnAreaId = getSyncedAreaIdIfHvacDualOn(value.areaId); hvacDualOnAreaId.has_value()) { *isSpecialValue = true; return synchronizeHvacTemp(hvacDualOnAreaId.value(), value.value.floatValues[0]); } return {}; case toInt(VehicleProperty::HVAC_DUAL_ON): if (value.value.int32Values.size() != 1) { *isSpecialValue = true; return StatusError(StatusCode::INVALID_ARG) << "HVAC_DUAL_ON requires only one int32 value"; } if (value.value.int32Values[0] == 1) { synchronizeHvacTemp(value.areaId, std::nullopt); } return {}; case toInt(VehicleProperty::LANE_CENTERING_ASSIST_COMMAND): { isAdasPropertyAvailableResult = isAdasPropertyAvailable(toInt(VehicleProperty::LANE_CENTERING_ASSIST_STATE)); Loading
automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -1889,6 +1889,101 @@ TEST_F(FakeVehicleHardwareTest, testHvacPowerOnSendCurrentHvacPropValues) { } } TEST_F(FakeVehicleHardwareTest, testHvacDualOnSynchronizesTemp) { auto hvacDualOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_DUAL_ON))); auto hvacTemperatureSetConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET))); EXPECT_NE(hvacDualOnConfig, nullptr); EXPECT_NE(hvacTemperatureSetConfig, nullptr); for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) { int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId; subscribe(toInt(VehicleProperty::HVAC_TEMPERATURE_SET), hvacTemperatureSetAreaId, /*sampleRateHz*/ 0); } for (auto& hvacDualOnConfig : hvacDualOnConfig->areaConfigs) { int32_t hvacDualOnAreaId = hvacDualOnConfig.areaId; subscribe(toInt(VehicleProperty::HVAC_DUAL_ON), hvacDualOnAreaId, /*sampleRateHz*/ 0); StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_DUAL_ON), .areaId = hvacDualOnAreaId, .value.int32Values = {1}}); EXPECT_EQ(status, StatusCode::OK); // Verify there's an event for all HVAC_TEMPERATURE_SET // area IDs covered by the HVAC_DUAL_ON area ID auto events = getChangedProperties(); std::unordered_set<float> temperatureValues; for (const auto& event : events) { // Ignore HVAC_DUAL_ON event if (event.prop == toInt(VehicleProperty::HVAC_DUAL_ON)) { continue; } EXPECT_EQ(event.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); EXPECT_EQ((hvacDualOnAreaId & event.areaId), event.areaId); EXPECT_EQ(1u, event.value.floatValues.size()); temperatureValues.insert(event.value.floatValues[0]); } // Verify that the temperature value is the same for all events // Ie the temperature in all area IDs are synchronized EXPECT_EQ(1u, temperatureValues.size()); clearChangedProperties(); // Verify when any HVAC_TEMPERATURE_SET area ID is changed all // area IDs covered by the HVAC_DUAL_ON area ID are also changed for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) { int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId; if ((hvacDualOnAreaId & hvacTemperatureSetAreaId) != hvacTemperatureSetAreaId) { continue; } float expectedValue = 25; status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = hvacTemperatureSetAreaId, .value.floatValues = {expectedValue}}); EXPECT_EQ(status, StatusCode::OK); events = getChangedProperties(); for (const auto& event : events) { EXPECT_EQ(event.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); EXPECT_EQ(1u, event.value.floatValues.size()); EXPECT_EQ(expectedValue, event.value.floatValues[0]); } clearChangedProperties(); } status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_DUAL_ON), .areaId = hvacDualOnAreaId, .value.int32Values = {0}}); EXPECT_EQ(status, StatusCode::OK); // When HVAC_DUAL_ON is disabled, there should be no events created // for HVAC_TEMPERATURE_SET ie no temperature synchronization. events = getChangedProperties(); EXPECT_EQ(1u, events.size()); EXPECT_EQ(events[0].prop, toInt(VehicleProperty::HVAC_DUAL_ON)); EXPECT_EQ(events[0].areaId, hvacDualOnAreaId); clearChangedProperties(); // Verify when any HVAC_TEMPERATURE_SET area ID is // changed other area IDs do not change. for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) { int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId; if ((hvacDualOnAreaId & hvacTemperatureSetAreaId) != hvacTemperatureSetAreaId) { continue; } float expectedValue = 24; status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = hvacTemperatureSetAreaId, .value.floatValues = {expectedValue}}); EXPECT_EQ(status, StatusCode::OK); events = getChangedProperties(); EXPECT_EQ(1u, events.size()); EXPECT_EQ(events[0].prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); EXPECT_EQ(events[0].areaId, hvacTemperatureSetAreaId); EXPECT_EQ(1u, events[0].value.floatValues.size()); EXPECT_EQ(expectedValue, events[0].value.floatValues[0]); clearChangedProperties(); } } } TEST_F(FakeVehicleHardwareTest, testGetAdasPropNotAvailable) { std::unordered_map<int32_t, std::vector<int32_t>> adasEnabledPropToDependentProps = { { Loading