From cd5eb6a77cbd98b4de03ae19867b869d7a93acb8 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 27 Jun 2021 15:51:34 -0700 Subject: [PATCH] Move AC logic out of FSIO (#2872) * new impl * remove fsio * inject "is ac active" to fan * include the correct code * include * test * more AC features * AC switch vs. actual AC indicators * include * duh --- firmware/console/binary/tunerstudio_outputs.h | 2 +- firmware/console/status_loop.cpp | 1 - firmware/controllers/actuators/ac_control.cpp | 72 +++++++++++++++++++ firmware/controllers/actuators/ac_control.h | 6 ++ .../controllers/actuators/fan_control.cpp | 10 +-- firmware/controllers/actuators/fan_control.h | 2 +- firmware/controllers/algo/engine.cpp | 4 +- firmware/controllers/controllers.mk | 1 + firmware/controllers/core/fsio_impl.cpp | 12 ---- firmware/controllers/system_fsio.h | 2 - firmware/controllers/system_fsio.txt | 2 - firmware/integration/rusefi_config.txt | 5 +- firmware/tunerstudio/rusefi.input | 9 ++- unit_tests/tests/test_fan_control.cpp | 17 ++--- 14 files changed, 107 insertions(+), 38 deletions(-) create mode 100644 firmware/controllers/actuators/ac_control.cpp create mode 100644 firmware/controllers/actuators/ac_control.h diff --git a/firmware/console/binary/tunerstudio_outputs.h b/firmware/console/binary/tunerstudio_outputs.h index 46049220e0..7d05dd52b8 100644 --- a/firmware/console/binary/tunerstudio_outputs.h +++ b/firmware/console/binary/tunerstudio_outputs.h @@ -71,7 +71,7 @@ struct TunerStudioOutputChannels { unsigned int isCltError : 1; // bit 19 unsigned int isMapError : 1; // bit 20 unsigned int isIatError : 1; // bit 21 - unsigned int unusedAt22 : 1; // bit 22 + unsigned int acState : 1; // bit 22 - 1 if AC is engaged, 0 otherwise unsigned int isTriggerError : 1; // bit 23 unsigned int hasCriticalError : 1; // bit 24 unsigned int isWarnNow : 1; // bit 25 diff --git a/firmware/console/status_loop.cpp b/firmware/console/status_loop.cpp index dabeb2e3da..67f7c05673 100644 --- a/firmware/console/status_loop.cpp +++ b/firmware/console/status_loop.cpp @@ -729,7 +729,6 @@ void updateTunerStudioState(TunerStudioOutputChannels *tsOutputChannels DECLARE_ tsOutputChannels->clutchUpState = engine->clutchUpState; tsOutputChannels->clutchDownState = engine->clutchDownState; tsOutputChannels->brakePedalState = engine->brakePedalState; - tsOutputChannels->acSwitchState = engine->acSwitchState; #if EFI_ENGINE_CONTROL // tCharge depends on the previous state, so we should use the stored value. diff --git a/firmware/controllers/actuators/ac_control.cpp b/firmware/controllers/actuators/ac_control.cpp new file mode 100644 index 0000000000..97319c20e9 --- /dev/null +++ b/firmware/controllers/actuators/ac_control.cpp @@ -0,0 +1,72 @@ +#include "ac_control.h" +#include "engine.h" + +#include "deadband.h" +#include "efi_gpio.h" +#include "sensor.h" +#include "tunerstudio_outputs.h" + +EXTERN_ENGINE; + +// Deadbands to prevent rapid switching on/off of AC +static Deadband<200> maxRpmDeadband; +static Deadband<5> maxCltDeadband; +static Deadband<5> maxTpsDeadband; + +static bool getAcState(DECLARE_ENGINE_PARAMETER_SIGNATURE) { + auto rpm = Sensor::get(SensorType::Rpm).value_or(0); + + // Engine too slow, disable + if (rpm < 500) { + return false; + } + + // Engine too fast, disable + auto maxRpm = CONFIG(maxAcRpm); + if (maxRpm != 0) { + if (maxRpmDeadband.gt(rpm, maxRpm)) { + return false; + } + } + + auto clt = Sensor::get(SensorType::Clt); + + // No AC with failed CLT + if (!clt) { + return false; + } + + // Engine too hot, disable + auto maxClt = CONFIG(maxAcClt); + if (maxClt != 0) { + if (maxCltDeadband.gt(maxClt, clt.Value)) { + return false; + } + } + + // TPS too high, disable + auto maxTps = CONFIG(maxAcTps); + if (maxTps != 0) { + auto tps = Sensor::get(SensorType::Tps1).value_or(0); + + if (maxTpsDeadband.gt(maxTps, tps)) { + return false; + } + } + + // All conditions allow AC, simply pass thru switch + return ENGINE(acSwitchState); +} + +bool updateAc(DECLARE_ENGINE_PARAMETER_SIGNATURE) { + bool isEnabled = getAcState(PASS_ENGINE_PARAMETER_SIGNATURE); + + enginePins.acRelay.setValue(isEnabled); + +#if EFI_TUNER_STUDIO + tsOutputChannels.acSwitchState = engine->acSwitchState; + tsOutputChannels.acState = isEnabled; +#endif // EFI_TUNER_STUDIO + + return isEnabled; +} diff --git a/firmware/controllers/actuators/ac_control.h b/firmware/controllers/actuators/ac_control.h new file mode 100644 index 0000000000..ad33fc6960 --- /dev/null +++ b/firmware/controllers/actuators/ac_control.h @@ -0,0 +1,6 @@ +#pragma once + +#include "engine_ptr.h" + +// Returns true if AC is currently active +bool updateAc(DECLARE_ENGINE_PARAMETER_SIGNATURE); diff --git a/firmware/controllers/actuators/fan_control.cpp b/firmware/controllers/actuators/fan_control.cpp index d3a278cfdf..28e49afe16 100644 --- a/firmware/controllers/actuators/fan_control.cpp +++ b/firmware/controllers/actuators/fan_control.cpp @@ -7,13 +7,13 @@ EXTERN_ENGINE; -static void fanControl(OutputPin& pin, int8_t fanOnTemp, int8_t fanOffTemp, bool enableWithAc DECLARE_ENGINE_PARAMETER_SUFFIX) { +static void fanControl(bool acActive, OutputPin& pin, int8_t fanOnTemp, int8_t fanOffTemp, bool enableWithAc DECLARE_ENGINE_PARAMETER_SUFFIX) { auto [cltValid, clt] = Sensor::get(SensorType::Clt); if (!cltValid) { // If CLT is broken, turn the fan on pin.setValue(true); - } else if (enableWithAc && ENGINE(acSwitchState)) { + } else if (enableWithAc && acActive) { pin.setValue(true); } else if (clt > fanOnTemp) { // If hot, turn the fan on @@ -26,13 +26,13 @@ static void fanControl(OutputPin& pin, int8_t fanOnTemp, int8_t fanOffTemp, bool } } -void updateFans(DECLARE_ENGINE_PARAMETER_SIGNATURE) { +void updateFans(bool acActive DECLARE_ENGINE_PARAMETER_SUFFIX) { #if EFI_PROD_CODE if (isRunningBenchTest()) { return; // let's not mess with bench testing } #endif - fanControl(enginePins.fanRelay, CONFIG(fanOnTemperature), CONFIG(fanOffTemperature), CONFIG(enableFan1WithAc) PASS_ENGINE_PARAMETER_SUFFIX); - fanControl(enginePins.fanRelay2, CONFIG(fan2OnTemperature), CONFIG(fan2OffTemperature), CONFIG(enableFan2WithAc) PASS_ENGINE_PARAMETER_SUFFIX); + fanControl(acActive, enginePins.fanRelay, CONFIG(fanOnTemperature), CONFIG(fanOffTemperature), CONFIG(enableFan1WithAc) PASS_ENGINE_PARAMETER_SUFFIX); + fanControl(acActive, enginePins.fanRelay2, CONFIG(fan2OnTemperature), CONFIG(fan2OffTemperature), CONFIG(enableFan2WithAc) PASS_ENGINE_PARAMETER_SUFFIX); } diff --git a/firmware/controllers/actuators/fan_control.h b/firmware/controllers/actuators/fan_control.h index d98572c399..dc5a1046e7 100644 --- a/firmware/controllers/actuators/fan_control.h +++ b/firmware/controllers/actuators/fan_control.h @@ -2,4 +2,4 @@ #include "engine_ptr.h" -void updateFans(DECLARE_ENGINE_PARAMETER_SIGNATURE); +void updateFans(bool acActive DECLARE_ENGINE_PARAMETER_SUFFIX); diff --git a/firmware/controllers/algo/engine.cpp b/firmware/controllers/algo/engine.cpp index e667e78e2a..3d4f10d982 100644 --- a/firmware/controllers/algo/engine.cpp +++ b/firmware/controllers/algo/engine.cpp @@ -35,6 +35,7 @@ #include "dynoview.h" #include "boost_control.h" #include "fan_control.h" +#include "ac_control.h" #if EFI_MC33816 #include "mc33816.h" #endif // EFI_MC33816 @@ -229,7 +230,8 @@ void Engine::periodicSlowCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) { runHardcodedFsio(PASS_ENGINE_PARAMETER_SIGNATURE); #endif /* EFI_FSIO */ - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + bool acActive = updateAc(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(acActive PASS_ENGINE_PARAMETER_SUFFIX); updateGppwm(); diff --git a/firmware/controllers/controllers.mk b/firmware/controllers/controllers.mk index b66af648ff..83e6285e2d 100644 --- a/firmware/controllers/controllers.mk +++ b/firmware/controllers/controllers.mk @@ -12,6 +12,7 @@ CONTROLLERSSRC = CONTROLLERS_SRC_CPP = \ $(CONTROLLERS_DIR)/actuators/electronic_throttle.cpp \ + $(CONTROLLERS_DIR)/actuators/ac_control.cpp \ $(CONTROLLERS_DIR)/actuators/alternator_controller.cpp \ $(CONTROLLERS_DIR)/actuators/boost_control.cpp \ $(CONTROLLERS_DIR)/actuators/dc_motors.cpp \ diff --git a/firmware/controllers/core/fsio_impl.cpp b/firmware/controllers/core/fsio_impl.cpp index 0e3fbc0e04..bffb332f88 100644 --- a/firmware/controllers/core/fsio_impl.cpp +++ b/firmware/controllers/core/fsio_impl.cpp @@ -105,7 +105,6 @@ FsioPointers::FsioPointers() : fsioLogics() { static FsioPointers state; -static LEElement * acRelayLogic; static LEElement * fuelPumpLogic; static LEElement * starterRelayDisableLogic; @@ -497,10 +496,6 @@ void runFsio(DECLARE_ENGINE_PARAMETER_SIGNATURE) { */ enginePins.o2heater.setValue(engine->rpmCalculator.isRunning()); - if (isBrainPinValid(CONFIG(acRelayPin))) { - setPinState("A/C", &enginePins.acRelay, acRelayLogic PASS_ENGINE_PARAMETER_SUFFIX); - } - #if EFI_ENABLE_ENGINE_WARNING if (engineConfiguration->useFSIO4ForSeriousEngineWarning) { updateValueOrWarning(MAGIC_OFFSET_FOR_ENGINE_WARNING, "eng warning", &ENGINE(fsioState.isEngineWarning) PASS_ENGINE_PARAMETER_SUFFIX); @@ -567,7 +562,6 @@ static void showFsio(const char *msg, LEElement *element) { static void showFsioInfo(void) { #if EFI_PROD_CODE || EFI_SIMULATOR efiPrintf("sys used %d/user used %d", sysPool.getSize(), userPool.getSize()); - showFsio("a/c", acRelayLogic); showFsio("fuel", fuelPumpLogic); for (int i = 0; i < CAM_INPUTS_COUNT ; i++) { @@ -690,8 +684,6 @@ void initFsioImpl(DECLARE_ENGINE_PARAMETER_SIGNATURE) { fuelPumpLogic = sysPool.parseExpression(FUEL_PUMP_LOGIC); #endif /* EFI_FUEL_PUMP */ - acRelayLogic = sysPool.parseExpression(AC_RELAY_LOGIC); - #if EFI_MAIN_RELAY_CONTROL if (isBrainPinValid(CONFIG(mainRelayPin))) mainRelayLogic = sysPool.parseExpression(MAIN_RELAY_LOGIC); @@ -767,10 +759,6 @@ void runHardcodedFsio(DECLARE_ENGINE_PARAMETER_SIGNATURE) { if (isBrainPinValid(CONFIG(starterRelayDisablePin))) { enginePins.starterRelayDisable.setValue(engine->rpmCalculator.getRpm() < engineConfiguration->cranking.rpm); } - // see AC_RELAY_LOGIC - if (isBrainPinValid(CONFIG(acRelayPin))) { - enginePins.acRelay.setValue(getAcToggle(PASS_ENGINE_PARAMETER_SIGNATURE) && engine->rpmCalculator.getRpm() > 850); - } // see FUEL_PUMP_LOGIC if (isBrainPinValid(CONFIG(fuelPumpPin))) { enginePins.fuelPumpRelay.setValue((getTimeNowSeconds() < engine->triggerActivitySecond + engineConfiguration->startUpFuelPumpDuration) || (engine->rpmCalculator.getRpm() > 0)); diff --git a/firmware/controllers/system_fsio.h b/firmware/controllers/system_fsio.h index 262352a77e..299f999226 100644 --- a/firmware/controllers/system_fsio.h +++ b/firmware/controllers/system_fsio.h @@ -21,8 +21,6 @@ // Human-readable: coolant > 120 #define TOO_HOT_LOGIC "coolant 120 >" -// Human-readable: ac_on_switch & (rpm > 850) -#define AC_RELAY_LOGIC "ac_on_switch rpm 850 > &" // Combined RPM, CLT and VBATT warning light // Human-readable: (rpm > fsio_setting(2)) | ((coolant > fsio_setting(3)) | (vbatt < fsio_setting(4))) diff --git a/firmware/controllers/system_fsio.txt b/firmware/controllers/system_fsio.txt index 469112f5d1..b9b719ba9a 100644 --- a/firmware/controllers/system_fsio.txt +++ b/firmware/controllers/system_fsio.txt @@ -13,8 +13,6 @@ FUEL_PUMP_LOGIC=((time_since_boot >= 0) & (time_since_boot < startup_fuel_pump_d TOO_HOT_LOGIC=coolant > 120 -AC_RELAY_LOGIC=ac_on_switch & (rpm > 850) - # Combined RPM, CLT and VBATT warning light COMBINED_WARNING_LIGHT=(rpm > fsio_setting(2)) | ((coolant > fsio_setting(3)) | (vbatt < fsio_setting(4))) diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index 11082fea9f..45def6fa2b 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1182,7 +1182,10 @@ custom pin_mode_e 1 bits, U08, @OFFSET@, [0:6], @@pin_mode_e_enum@@ ! todo: rename field remove 'ms' since unusual case of dual-purpose field - it could be either ms or percent float tachPulseDuractionMs;;"", 1, 0, 0, 100, 2 - int unused1708;;"units", 1, 0, -20, 100, 0 + uint16_t maxAcRpm;+Above this RPM, disable AC. Set to 0 to disable check.;"rpm", 1, 0, 0, 10000, 0 + uint8_t maxAcTps;+Above this TPS, disable AC. Set to 0 to disable check.;"%", 1, 0, 0, 100, 0 + uint8_t maxAcClt;+Above this CLT, disable AC to prevent overheating the engine. Set to 0 to disable check.;"deg C", 1, 0, 0, 150, 0 + float wwaeTau;+Length of time the deposited wall fuel takes to dissipate after the start of acceleration. ;"Seconds", 1, 0, 0, 3, 2 pid_s alternatorControl; diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index f00b68cc6e..32c3cafac1 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -199,6 +199,7 @@ enable2ndByteCanID = false ; ind_map_error = bits, U32, 0, [20:20], "true", "false"; ind_iat_error = bits, U32, 0, [21:21], "true", "false"; + acState = bits, U32, 0, [22:22], "true", "false"; ind_isTriggerError = bits, U32, 0, [23:23], "true", "false"; ind_hasFatalError=bits, U32, 0, [24:24], "true", "false"; ind_isWarnNow =bits, U32, 0, [25:25], "true", "false"; @@ -1203,7 +1204,8 @@ gaugeCategory = DynoView indicator = { clutchUpState }, "clutch", "cltch Up", white, black, red, black indicator = { clutchDownState }, "clutch", "cltch Down", white, black, yellow, black indicator = { brakePedalIndicator }, "brake", "brake down", white, black, red, black - indicator = { acSwitchState }, "AC off", "AC on", white, black, blue, white + indicator = { acSwitchState }, "AC switch off", "AC switch on", white, black, blue, white + indicator = { acState }, "AC off", "AC on", white, black, blue, white indicator = { isIdleClosedLoop }, "not idling", "idling", white, black, green, black indicator = { isIdleCoasting }, "not coasting", "coasting", white, black, green, black @@ -1392,6 +1394,7 @@ menuDialog = main subMenu = starterRelay, "Starter Disable relay" subMenu = fuelPump, "Fuel pump" subMenu = fanSetting, "Fan" + subMenu = acSettings, "Air Conditioning" subMenu = tachSettings, "Tachometer" subMenu = malfunction, "Check engine light" subMenu = statusLeds, "Status LEDs" @@ -2698,11 +2701,13 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" dialog = acSettings, "A/C Settings" field = "A/C Relay", acRelayPin field = "A/C Relay Mode", acRelayPinMode + field = "Max RPM", maxAcRpm + field = "Max CLT", maxAcClt + field = "Max TPS", maxAcTps dialog = fanSetting, "Fan Settings" panel = fan1Settings panel = fan2Settings - panel = acSettings dialog = fuelPump, "Fuel Pump" field = "Pin", fuelPumpPin diff --git a/unit_tests/tests/test_fan_control.cpp b/unit_tests/tests/test_fan_control.cpp index 1240d2235f..54f204d594 100644 --- a/unit_tests/tests/test_fan_control.cpp +++ b/unit_tests/tests/test_fan_control.cpp @@ -9,41 +9,38 @@ TEST(FanControl, fan1) { engineConfiguration->fanOnTemperature = 90; engineConfiguration->fanOffTemperature = 80; engineConfiguration->enableFan1WithAc = false; - engine->acSwitchState = false; // Cold, fan should be off Sensor::setMockValue(SensorType::Clt, 75); - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(false PASS_ENGINE_PARAMETER_SUFFIX); EXPECT_EQ(false, enginePins.fanRelay.getLogicValue()); // Between thresholds, should still be off Sensor::setMockValue(SensorType::Clt, 85); - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(false PASS_ENGINE_PARAMETER_SUFFIX); EXPECT_EQ(false, enginePins.fanRelay.getLogicValue()); // Hot, fan should turn on Sensor::setMockValue(SensorType::Clt, 95); - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(false PASS_ENGINE_PARAMETER_SUFFIX); EXPECT_EQ(true, enginePins.fanRelay.getLogicValue()); // Between thresholds, should stay on Sensor::setMockValue(SensorType::Clt, 85); - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(false PASS_ENGINE_PARAMETER_SUFFIX); EXPECT_EQ(true, enginePins.fanRelay.getLogicValue()); // Below threshold, should turn off Sensor::setMockValue(SensorType::Clt, 75); - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(false PASS_ENGINE_PARAMETER_SUFFIX); EXPECT_EQ(false, enginePins.fanRelay.getLogicValue()); engineConfiguration->enableFan1WithAc = true; // Now AC is on, fan should turn on! - engine->acSwitchState = true; - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(true PASS_ENGINE_PARAMETER_SUFFIX); EXPECT_EQ(true, enginePins.fanRelay.getLogicValue()); // Turn off AC, fan should turn off too. - engine->acSwitchState = false; - updateFans(PASS_ENGINE_PARAMETER_SIGNATURE); + updateFans(false PASS_ENGINE_PARAMETER_SUFFIX); EXPECT_EQ(false, enginePins.fanRelay.getLogicValue()); }