From cff54ae7aa515806b96e08c38f34158e3f715cc0 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Wed, 3 Sep 2025 17:20:23 -0500 Subject: [PATCH 1/3] idle A/C add: use isAcEnabled method it accounts for all things A/C actuation, post switch demand (but pre-delay) --- firmware/controllers/actuators/ac_control.cpp | 5 +++++ firmware/controllers/actuators/ac_control.h | 1 + firmware/controllers/actuators/idle_thread.cpp | 6 ++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/firmware/controllers/actuators/ac_control.cpp b/firmware/controllers/actuators/ac_control.cpp index f25d72c54d..d37666c9b3 100644 --- a/firmware/controllers/actuators/ac_control.cpp +++ b/firmware/controllers/actuators/ac_control.cpp @@ -87,3 +87,8 @@ void AcController::onSlowCallback() { bool AcController::isAcEnabled() const { return m_acEnabled; } + +// accounts for A/C delay +bool AcController::isAcCompressorEnabled() const { + return acCompressorState; +} diff --git a/firmware/controllers/actuators/ac_control.h b/firmware/controllers/actuators/ac_control.h index e16c8b8c30..682dc1e698 100644 --- a/firmware/controllers/actuators/ac_control.h +++ b/firmware/controllers/actuators/ac_control.h @@ -10,6 +10,7 @@ class AcController : public ac_control_s, public EngineModule { void onSlowCallback() override; virtual bool isAcEnabled() const; + virtual bool isAcCompressorEnabled() const; Timer timeSinceStateChange; diff --git a/firmware/controllers/actuators/idle_thread.cpp b/firmware/controllers/actuators/idle_thread.cpp index d8f03be127..a12f70020d 100644 --- a/firmware/controllers/actuators/idle_thread.cpp +++ b/firmware/controllers/actuators/idle_thread.cpp @@ -30,8 +30,7 @@ IIdleController::TargetInfo IdleController::getTargetRpm(float clt) { // Why do we bump based on button not based on actual A/C relay state? // Because AC output has a delay to allow idle bump to happen first, so that the airflow increase gets a head start on the load increase // alternator duty cycle has a similar logic - targetRpmAcBump = (!hasAcPressure() || engine->module().unmock().acPressureSwitchState) - && engine->module().unmock().acButtonState ? engineConfiguration->acIdleRpmBump : 0; + targetRpmAcBump = engine->module().unmock().isAcEnabled() ? engineConfiguration->acIdleRpmBump : 0; auto target = targetRpmByClt + targetRpmAcBump + luaAddRpm; @@ -131,8 +130,7 @@ percent_t IdleController::getRunningOpenLoop(float rpm, float clt, SensorResult openLoopBase = running; // Now we bump it by the AC/fan amount if necessary - openLoopAcBump = (!hasAcPressure() || engine->module().unmock().acPressureSwitchState) - && engine->module().unmock().acButtonState ? engineConfiguration->acIdleExtraOffset : 0; + openLoopAcBump = engine->module().unmock().isAcEnabled() ? engineConfiguration->acIdleExtraOffset : 0; openLoopFanBump = (enginePins.fanRelay.getLogicValue() ? engineConfiguration->fan1ExtraIdle : 0) + (enginePins.fanRelay2.getLogicValue() ? engineConfiguration->fan2ExtraIdle : 0); From 5552767ce95aa3e142f38ba1a6a1245030f41f90 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Wed, 3 Sep 2025 17:21:49 -0500 Subject: [PATCH 2/3] changelog --- firmware/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/CHANGELOG.md b/firmware/CHANGELOG.md index a79d1b2920..9f230e7eff 100644 --- a/firmware/CHANGELOG.md +++ b/firmware/CHANGELOG.md @@ -40,7 +40,7 @@ or - MAF filtering for better transient response - Minimum injector pulse width setting - Allow selection of DTC severity #625 - - AC pressure switch & startup delay (#623, #660, #661, #662) + - AC pressure switch & startup delay (#623, #660, #661, #662, #663) - Y axis override for VVT target - Feature to skip initial trigger pulses for noisy triggers #634 - VVT open loop "hold" table #638 From a05f73e8f914d63f2265989586136115b06b41c0 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Wed, 3 Sep 2025 19:30:56 -0500 Subject: [PATCH 3/3] ? --- unit_tests/tests/test_idle_controller.cpp | 40 +++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/unit_tests/tests/test_idle_controller.cpp b/unit_tests/tests/test_idle_controller.cpp index ca18300613..33a659ecce 100644 --- a/unit_tests/tests/test_idle_controller.cpp +++ b/unit_tests/tests/test_idle_controller.cpp @@ -181,9 +181,16 @@ TEST(idle_v2, runningOpenLoopBasic) { TEST(idle_v2, runningFanAcBump) { EngineTestHelper eth(engine_type_e::TEST_ENGINE); - IdleController dut; + //IdleController dut; + + engine->rpmCalculator.setRpmValue(1000); + Sensor::setMockValue(SensorType::Rpm, 1000); engineConfiguration->manIdlePosition = 50; + engineConfiguration->maxAcRpm = 5000; + engineConfiguration->maxAcClt = 200; + engineConfiguration->maxAcTps = 100; + engineConfiguration->acIdleExtraOffset = 9; engineConfiguration->fan1ExtraIdle = 7; engineConfiguration->fan2ExtraIdle = 3; @@ -193,12 +200,19 @@ TEST(idle_v2, runningFanAcBump) { // Start with fan off enginePins.fanRelay.setValue(0); + //auto dut = engine->module(); + // Should be base position - EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(0, 10, 0)); + EXPECT_FLOAT_EQ(50, engine->module()->getRunningOpenLoop(0, 10, 0)); // Turn on A/C! + //engineConfiguration->acSwitch = Gpio::G1; + //setMockState(engineConfiguration->acSwitch, true); engine->module()->acButtonState = true; - EXPECT_FLOAT_EQ(50 + 9, dut.getRunningOpenLoop(0, 10, 0)); + //engineConfiguration->acPressureSwitch = Gpio::G2; + engine->module()->onSlowCallback(); + + EXPECT_FLOAT_EQ(50 + 9, engine->module()->getRunningOpenLoop(0, 10, 0)); engine->module()->acButtonState = false; // Begin A/C Pressure Switch testing @@ -207,40 +221,46 @@ TEST(idle_v2, runningFanAcBump) { //setMockState(engineConfiguration->acSwitch, false); //setMockState(engineConfiguration->acPressureSwitch, false); engine->module()->acPressureSwitchState = false; - EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(0, 10, 0)); + engine->module()->onSlowCallback(); + EXPECT_FLOAT_EQ(50, engine->module()->getRunningOpenLoop(0, 10, 0)); //setMockState(engineConfiguration->acSwitch, true); engine->module()->acButtonState = true; - EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(0, 10, 0)); + engine->module()->onSlowCallback(); + EXPECT_FLOAT_EQ(50, engine->module()->getRunningOpenLoop(0, 10, 0)); //setMockState(engineConfiguration->acPressureSwitch, true); engine->module()->acPressureSwitchState = true; - EXPECT_FLOAT_EQ(50 + 9, dut.getRunningOpenLoop(0, 10, 0)); + engine->module()->onSlowCallback(); + EXPECT_FLOAT_EQ(50 + 9, engine->module()->getRunningOpenLoop(0, 10, 0)); //setMockState(engineConfiguration->acSwitch, false); engine->module()->acButtonState = false; - EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(0, 10, 0)); + engine->module()->onSlowCallback(); + EXPECT_FLOAT_EQ(50, engine->module()->getRunningOpenLoop(0, 10, 0)); //engineConfiguration->acSwitch = Gpio::Unassigned; //setMockState(engineConfiguration->acPressureSwitch, false); engineConfiguration->acPressureSwitch = Gpio::Unassigned; engine->module()->acPressureSwitchState = false; + engine->module()->onSlowCallback(); // End A/C Pressure Switch testing // Turn the fan on! enginePins.fanRelay.setValue(1); - EXPECT_FLOAT_EQ(50 + 7, dut.getRunningOpenLoop(0, 10, 0)); + EXPECT_FLOAT_EQ(50 + 7, engine->module()->getRunningOpenLoop(0, 10, 0)); enginePins.fanRelay.setValue(0); // Turn on the other fan! enginePins.fanRelay2.setValue(1); - EXPECT_FLOAT_EQ(50 + 3, dut.getRunningOpenLoop(0, 10, 0)); + EXPECT_FLOAT_EQ(50 + 3, engine->module()->getRunningOpenLoop(0, 10, 0)); // Turn on everything! engine->module()->acButtonState = true; enginePins.fanRelay.setValue(1); enginePins.fanRelay2.setValue(1); - EXPECT_FLOAT_EQ(50 + 9 + 7 + 3, dut.getRunningOpenLoop(0, 10, 0)); + engine->module()->onSlowCallback(); + EXPECT_FLOAT_EQ(50 + 9 + 7 + 3, engine->module()->getRunningOpenLoop(0, 10, 0)); } TEST(idle_v2, runningOpenLoopTpsTaper) {