Main relay shutdown rebase (#3880)

* aggregate

* main relay controller handles delayed shutoff

* main relay controller handles delayed shutdown

Co-authored-by: Matthew Kennedy <matthewkennedy@outlook.com>
Co-authored-by: rusefillc <sdfsdfqsf2334234234>
This commit is contained in:
rusefillc 2022-02-02 00:45:11 -05:00 committed by GitHub
parent 9b8de47b72
commit 42deca0fd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 49 additions and 12 deletions

View File

@ -650,6 +650,7 @@ static void updateIgnition(int rpm) {
} }
static void updateFlags() { static void updateFlags() {
engine->outputChannels.isMainRelayOn = enginePins.mainRelay.getLogicValue();
engine->outputChannels.isFuelPumpOn = enginePins.fuelPumpRelay.getLogicValue(); engine->outputChannels.isFuelPumpOn = enginePins.fuelPumpRelay.getLogicValue();
engine->outputChannels.isFanOn = enginePins.fanRelay.getLogicValue(); engine->outputChannels.isFanOn = enginePins.fanRelay.getLogicValue();
engine->outputChannels.isFan2On = enginePins.fanRelay2.getLogicValue(); engine->outputChannels.isFan2On = enginePins.fanRelay2.getLogicValue();

View File

@ -6,7 +6,20 @@ void MainRelayController::onSlowCallback() {
isBenchTest = engine->isInMainRelayBench(); isBenchTest = engine->isInMainRelayBench();
#if EFI_MAIN_RELAY_CONTROL #if EFI_MAIN_RELAY_CONTROL
mainRelayState = isBenchTest | hasIgnitionVoltage; hasIgnitionVoltage = Sensor::getOrZero(SensorType::BatteryVoltage) > 5;
if (hasIgnitionVoltage) {
m_lastIgnitionTime.reset();
}
delayedShutoffRequested = engine->module<MainRelayController>()->needsDelayedShutoff();
// Query whether any engine modules want to keep the lights on
// todo: fix this amazing C++ lambda magic
// delayedShutoffRequested = engine->engineModules.aggregate([](auto& m, bool prev) { return m->needsDelayedShutoff() | prev; }, false);
// TODO: delayed shutoff timeout?
mainRelayState = isBenchTest | hasIgnitionVoltage | delayedShutoffRequested;
#else // not EFI_MAIN_RELAY_CONTROL #else // not EFI_MAIN_RELAY_CONTROL
mainRelayState = !isBenchTest; mainRelayState = !isBenchTest;
#endif #endif
@ -14,6 +27,9 @@ void MainRelayController::onSlowCallback() {
enginePins.mainRelay.setValue(mainRelayState); enginePins.mainRelay.setValue(mainRelayState);
} }
void MainRelayController::onIgnitionStateChanged(bool ignitionOn) { bool MainRelayController::needsDelayedShutoff() {
hasIgnitionVoltage = ignitionOn; // Prevent main relay from turning off if we had igniton voltage in the past 1 second
// This avoids accidentally killing the car during a transient, for example
// right when the starter is engaged.
return !m_lastIgnitionTime.hasElapsedSec(1);
} }

View File

@ -3,7 +3,11 @@
#include "engine_module.h" #include "engine_module.h"
#include "main_relay_generated.h" #include "main_relay_generated.h"
struct MainRelayController : public EngineModule, public main_relay_s { class MainRelayController : public EngineModule, public main_relay_s {
public:
void onSlowCallback() override; void onSlowCallback() override;
void onIgnitionStateChanged(bool ignitionOn) override; bool needsDelayedShutoff() override;
private:
Timer m_lastIgnitionTime;
}; };

View File

@ -13,4 +13,7 @@ public:
// Called whenever the ignition switch state changes // Called whenever the ignition switch state changes
virtual void onIgnitionStateChanged(bool /*ignitionOn*/) { } virtual void onIgnitionStateChanged(bool /*ignitionOn*/) { }
// Queried to determine whether this module needs a delayed shutoff, defaults to false
virtual bool needsDelayedShutoff() { return false; }
}; };

View File

@ -1274,6 +1274,7 @@ gaugeCategory = DynoView
; minor info ; minor info
indicator = { isFanOn }, "fan off", "fan on", white, black, green, black indicator = { isFanOn }, "fan off", "fan on", white, black, green, black
indicator = { isFan2On }, "fan 2 off", "fan 2 on", white, black, green, black indicator = { isFan2On }, "fan 2 off", "fan 2 on", white, black, green, black
indicator = { isMainRelayOn }, "main relay off", "main relay on", white, black, green, black
indicator = { isCylinderCleanupActivated}, "no cyl cleanup", "cyl cleanup", white, black, yellow, black indicator = { isCylinderCleanupActivated}, "no cyl cleanup", "cyl cleanup", white, black, yellow, black
indicator = { isFuelPumpOn}, "pump off", "pump on", white, black, green, black indicator = { isFuelPumpOn}, "pump off", "pump on", white, black, green, black
indicator = { clutchUpState }, "Clutch Up", "clutch Up", white, black, red, black indicator = { clutchUpState }, "Clutch Up", "clutch Up", white, black, red, black

View File

@ -45,6 +45,14 @@ struct type_list {
others.apply_all(f); others.apply_all(f);
} }
// Applies an accumulator function over the sequence of elements.
// The specified seed value is used as the initial accumulator value,
// and the specified function is used to select the result value.
template<typename return_t, typename func_t>
auto aggregate(func_t const& accumulator, return_t seed) {
return others.aggregate(accumulator, first.aggregate(accumulator, seed));
}
/* /*
* Return the container object for type get_t. * Return the container object for type get_t.
* *
@ -92,6 +100,11 @@ public:
f(me); f(me);
} }
template<typename return_t, typename func_t>
auto aggregate(func_t const& accumulator, return_t seed) {
return accumulator(me, seed);
}
template<typename has_t> template<typename has_t>
static constexpr bool has() { static constexpr bool has() {
return std::is_same_v<has_t, base_t>; return std::is_same_v<has_t, base_t>;

View File

@ -2,18 +2,17 @@
#include "main_relay.h" #include "main_relay.h"
TEST(MainRelay, mr) { TEST(MainRelay, mainRelayLogic) {
EngineTestHelper eth(TEST_ENGINE); EngineTestHelper eth(TEST_ENGINE);
MainRelayController dut; MainRelayController dut;
// Ignition is off, MR is off // Ignition is off, MR is off
dut.onIgnitionStateChanged(false);
dut.onSlowCallback(); dut.onSlowCallback();
EXPECT_EQ(enginePins.mainRelay.getLogicValue(), false); EXPECT_EQ(enginePins.mainRelay.getLogicValue(), false);
// Ignition is now on, MR is on // Battery above threshold - MR is on
dut.onIgnitionStateChanged(true); Sensor::setMockValue(SensorType::BatteryVoltage, 13);
dut.onSlowCallback(); dut.onSlowCallback();
EXPECT_EQ(enginePins.mainRelay.getLogicValue(), true); EXPECT_EQ(enginePins.mainRelay.getLogicValue(), true);
} }