kill engine if no oil pressure (#2800)

* min oil pressure for crank

* do it time-based

* rename field

* include

* fix existing test

* tests

* fix logic

* more test

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2021-06-16 14:20:28 -07:00 committed by GitHub
parent 850d19aaa9
commit 3a30f038ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 139 additions and 11 deletions

View File

@ -27,6 +27,9 @@ All notable user-facing or behavior-altering changes will be documented in this
## Month 202x Release - "Release Name"
### Added
- "inhibit start until oil pressure" prevents starting the engine with no/low oil pressure #2799
# 2021 May "Piercing Day"
### Fixed
- LCD screen works again #2576

View File

@ -177,7 +177,7 @@ void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
updateLaunchConditions(PASS_ENGINE_PARAMETER_SIGNATURE);
#endif //EFI_LAUNCH_CONTROL
engine->limpManager.updateState(rpm);
engine->limpManager.updateState(rpm, nowNt);
#endif // EFI_ENGINE_CONTROL
}

View File

@ -161,6 +161,11 @@ void RpmCalculator::setRpmValue(float value) {
if (rpmValue == 0) {
state = STOPPED;
} else if (rpmValue >= CONFIG(cranking.rpm)) {
if (state != RUNNING) {
// Store the time the engine started
engineStartTimer.reset();
}
state = RUNNING;
} else if (state == STOPPED || state == SPINNING_UP) {
/**
@ -311,6 +316,10 @@ void rpmShaftPositionCallback(trigger_event_e ckpSignalType,
}
}
float RpmCalculator::getTimeSinceEngineStart(efitick_t nowNt) const {
return engineStartTimer.getElapsedSeconds(nowNt);
}
static scheduling_s tdcScheduler[2];
static char rpmBuffer[_MAX_FILLER];

View File

@ -105,6 +105,10 @@ public:
* see also SC_RPM_ACCEL
*/
float getRpmAcceleration() const;
// Get elapsed time (seconds) since the engine transitioned to the running state.
float getTimeSinceEngineStart(efitick_t nowNt) const;
/**
* this is RPM on previous engine cycle.
*/
@ -153,6 +157,8 @@ private:
* Needed by spinning-up logic.
*/
bool isSpinning = false;
Timer engineStartTimer;
};
// Just a getter for rpmValue which also handles mockRpm if not EFI_PROD_CODE

View File

@ -4,7 +4,7 @@
EXTERN_ENGINE;
void LimpManager::updateState(int rpm) {
void LimpManager::updateState(int rpm, efitick_t nowNt) {
Clearable allowFuel = CONFIG(isInjectionEnabled);
Clearable allowSpark = CONFIG(isIgnitionEnabled);
@ -31,6 +31,36 @@ void LimpManager::updateState(int rpm) {
}
}
if (ENGINE(rpmCalculator).isRunning()) {
uint16_t minOilPressure = CONFIG(minOilPressureAfterStart);
// Only check if the setting is enabled
if (minOilPressure > 0) {
// Has it been long enough we should have pressure?
bool isTimedOut = ENGINE(rpmCalculator).getTimeSinceEngineStart(nowNt) > 5.0f;
// Only check before timed out
if (!isTimedOut) {
auto oilp = Sensor::get(SensorType::OilPressure);
if (oilp) {
// We had oil pressure! Set the flag.
if (oilp.Value > minOilPressure) {
m_hadOilPressureAfterStart = true;
}
}
}
// If time is up, the sensor works, and no pressure, kill the engine.
if (isTimedOut && !m_hadOilPressureAfterStart) {
allowFuel.clear();
}
}
} else {
// reset state in case of stalled engine
m_hadOilPressureAfterStart = false;
}
m_transientAllowInjection = allowFuel;
m_transientAllowIgnition = allowSpark;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "engine_ptr.h"
#include "rusefi_types.h"
#include <cstdint>
@ -27,7 +28,7 @@ public:
DECLARE_ENGINE_PTR;
// This is called from periodicFastCallback to update internal state
void updateState(int rpm);
void updateState(int rpm, efitick_t nowNt);
// Other subsystems call these APIs to determine their behavior
bool allowElectronicThrottle() const;
@ -54,4 +55,6 @@ private:
bool m_transientAllowInjection = true;
bool m_transientAllowIgnition = true;
bool m_hadOilPressureAfterStart = false;
};

View File

@ -625,7 +625,8 @@ custom ignition_mode_e 4 bits, U32, @OFFSET@, [0:1], "Single Coil", "Indiv
ignition_mode_e ignitionMode;+Single coil = distributor\nIndividual coils = one coil per cylinder (COP, coil-near-plug), requires sequential mode\nWasted spark = Fires pairs of cylinders together, either one coil per pair of cylinders or one coil per cylinder\nTwo distributors = A pair of distributors, found on some BMW, Toyota and other engines\nset ignition_mode X
int8_t gapTrackingLengthOverride;;"count",1,0,0,@@GAP_TRACKING_LENGTH@@,0
int8_t[3] unusedOldIgnitionOffset;;"unused",1,0,0,1,0
int8_t[1] unusedOldIgnitionOffset;;"unused",1,0,0,1,0
uint16_t minOilPressureAfterStart;+Expected oil pressure after starting the engine. If oil pressure does not reach this level within 5 seconds of engine start, fuel will be cut. Set to 0 to disable and always allow starting.;"kPa",1,0,0,1000,0
custom timing_mode_e 4 bits, U32, @OFFSET@, [0:0], "dynamic", "fixed"
timing_mode_e timingMode;+Dynamic uses the timing map to decide the ignition timing, Static timing fixes the timing to the value set below (only use for checking static timing with a timing light).

View File

@ -3046,6 +3046,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00"
field = "Cut spark on RPM limit", cutSparkOnHardLimit
field = "RPM hard limit", rpmHardLimit, { cutFuelOnHardLimit || cutSparkOnHardLimit }
field = "Boost cut pressure", boostCutPressure
field = "Minimum oil pressure after start", minOilPressureAfterStart
dialog = etbLimits, "Electronic Throttle Limiting"
field = "Smoothly close the throttle to limit RPM."

View File

@ -29,17 +29,17 @@ TEST(limp, revLimit) {
INJECT_ENGINE_REFERENCE(&dut);
// Under rev limit, inj/ign allowed
dut.updateState(2000);
dut.updateState(2000, 0);
EXPECT_TRUE(dut.allowIgnition());
EXPECT_TRUE(dut.allowInjection());
// Over rev limit, no injection
dut.updateState(3000);
dut.updateState(3000, 0);
EXPECT_FALSE(dut.allowIgnition());
EXPECT_FALSE(dut.allowInjection());
// Now recover back to under limit
dut.updateState(2000);
dut.updateState(2000, 0);
EXPECT_TRUE(dut.allowIgnition());
EXPECT_TRUE(dut.allowInjection());
}
@ -55,22 +55,97 @@ TEST(limp, boostCut) {
// Below threshold, injection allowed
Sensor::setMockValue(SensorType::Map, 80);
dut.updateState(1000);
dut.updateState(1000, 0);
EXPECT_TRUE(dut.allowInjection());
// Above threshold, injection cut
Sensor::setMockValue(SensorType::Map, 120);
dut.updateState(1000);
dut.updateState(1000, 0);
EXPECT_FALSE(dut.allowInjection());
// Below threshold, should recover
Sensor::setMockValue(SensorType::Map, 80);
dut.updateState(1000);
dut.updateState(1000, 0);
EXPECT_TRUE(dut.allowInjection());
// SPECIAL CASE: threshold of 0 means never boost cut
engineConfiguration->boostCutPressure = 0;
Sensor::setMockValue(SensorType::Map, 500);
dut.updateState(1000);
dut.updateState(1000, 0);
EXPECT_TRUE(dut.allowInjection());
}
extern int timeNowUs;
TEST(limp, oilPressureFailureCase) {
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
engineConfiguration->minOilPressureAfterStart = 200;
LimpManager dut;
INJECT_ENGINE_REFERENCE(&dut);
// Low oil pressure!
Sensor::setMockValue(SensorType::OilPressure, 50);
// Start the engine
ENGINE(rpmCalculator).setRpmValue(1000);
// update & check: injection should be allowed
dut.updateState(1000, getTimeNowNt());
EXPECT_TRUE(dut.allowInjection());
// 4.5 seconds later, should still be allowed (even though pressure is low)
timeNowUs += 4.5e6;
dut.updateState(1000, getTimeNowNt());
EXPECT_TRUE(dut.allowInjection());
// 1 second later (5.5 since start), injection should cut
timeNowUs += 1.0e6;
dut.updateState(1000, getTimeNowNt());
ASSERT_FALSE(dut.allowInjection());
// But then oil pressure arrives!
// Injection still isn't allowed, since now we're late.
Sensor::setMockValue(SensorType::OilPressure, 250);
dut.updateState(1000, getTimeNowNt());
ASSERT_FALSE(dut.allowInjection());
}
TEST(limp, oilPressureSuccessCase) {
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
engineConfiguration->minOilPressureAfterStart = 200;
LimpManager dut;
INJECT_ENGINE_REFERENCE(&dut);
// Low oil pressure!
Sensor::setMockValue(SensorType::OilPressure, 50);
// Start the engine
ENGINE(rpmCalculator).setRpmValue(1000);
// update & check: injection should be allowed
dut.updateState(1000, getTimeNowNt());
EXPECT_TRUE(dut.allowInjection());
// 4.5 seconds later, should still be allowed (even though pressure is low)
timeNowUs += 4.5e6;
dut.updateState(1000, getTimeNowNt());
EXPECT_TRUE(dut.allowInjection());
// But then oil pressure arrives!
Sensor::setMockValue(SensorType::OilPressure, 250);
dut.updateState(1000, getTimeNowNt());
ASSERT_TRUE(dut.allowInjection());
// 1 second later (5.5 since start), injection should be allowed since we saw pressure before the timeout
timeNowUs += 1.0e6;
dut.updateState(1000, getTimeNowNt());
ASSERT_TRUE(dut.allowInjection());
// Later, we lose oil pressure, but engine should stay running
timeNowUs += 10e6;
Sensor::setMockValue(SensorType::OilPressure, 10);
dut.updateState(1000, getTimeNowNt());
ASSERT_TRUE(dut.allowInjection());
}