Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea25b1f4 authored by Aaqib Ismail's avatar Aaqib Ismail
Browse files

Support hvac temperature synchronization in VHAL

Bug: 306055692
Test: atest FakeVehicleHardwareTest
Change-Id: Ibfdfb7ae45854c969070757b0d809be0e9b6a9ed
parent 65194564
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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();

+81 −0
Original line number Diff line number Diff line
@@ -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));
+95 −0
Original line number Diff line number Diff line
@@ -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 = {
            {