Merge "Support hvac temperature synchronization in VHAL" into main

This commit is contained in:
Treehugger Robot
2023-11-01 23:02:08 +00:00
committed by Android (Google) Code Review
3 changed files with 179 additions and 0 deletions

View File

@@ -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();

View File

@@ -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;
@@ -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));

View File

@@ -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 = {
{