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

Commit 3c464673 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Support hvac temperature synchronization in VHAL" into main

parents b9f9fc94 ea25b1f4
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 = {
            {