rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
limp_manager.cpp
Go to the documentation of this file.
1#include "pch.h"
2
3#include "limp_manager.h"
4#include "fuel_math.h"
6
7#if EFI_ENGINE_CONTROL
8
9#define CLEANUP_MODE_TPS 90
10
11#if EFI_SHAFT_POSITION_INPUT
12static bool noFiringUntilVvtSync() {
13 auto operationMode = getEngineRotationState()->getOperationMode();
14
16 // in rare cases engines do not like random sequential mode
17 return true;
18 }
19 if (isGdiEngine()) {
20#if EFI_PROD_CODE
21 criticalError("For GDI please configure CAM and require sync for ignition");
22#endif
23 }
24
25 if (engineConfiguration->ignitionMode == IM_ONE_COIL) {
26 // distributor routes to the correct cylinder, no need to worry about sync
27 return false;
28 }
29
30 // Symmetrical crank modes require cam sync before firing
31 // non-symmetrical cranks can use faster spin-up mode (firing in wasted/batch before VVT sync)
32 // Examples include Nissan MR/VQ, Miata NB, etc
33 return
34 operationMode == FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR ||
35 operationMode == FOUR_STROKE_THREE_TIMES_CRANK_SENSOR ||
37}
38#endif // EFI_SHAFT_POSITION_INPUT
39
43
45 // User-configured hard RPM limit, either constant or CLT-lookup
49
50 // Require configurable rpm drop before resuming
52
54
56 m_fuelCorrection = 1.0f + fuelAdded / 100;
57}
58
59void LimpManager::updateState(float rpm, efitick_t nowNt) {
62
63#if EFI_SHAFT_POSITION_INPUT && !EFI_UNIT_TEST
64 if (!m_ignitionOn
65 && !engine->triggerCentral.directSelfStimulation // useful to try things on real ECU even without ignition voltage
66 ) {
69 }
70#endif
71
73 if (externalGdiCanBusComms.getElapsedSeconds() > 1) {
75 }
76 }
77
79 allowSpark.clear(ClearReason::Lua);
80 }
81
83 allowFuel.clear(ClearReason::Lua);
84 }
85
86 updateRevLimit(rpm);
90 }
91
93 allowSpark.clear(ClearReason::HardLimit);
94 }
95 }
96
97#if EFI_SHAFT_POSITION_INPUT
98 if (engine->lambdaMonitor.isCut()) {
100 }
101
104 // Any engine that requires cam-assistance for a full crank sync (symmetrical crank) can't schedule until we have cam sync
105 // examples:
106 // NB2, Nissan VQ/MR: symmetrical crank wheel and we need to make sure no spark happens out of sync
107 // VTwin Harley: uneven firing order, so we need "cam" MAP sync to make sure no spark happens out of sync
110 }
111
112 // Force fuel limiting on the fault rev limit
113 if (rpm > m_faultRevLimit) {
114 allowFuel.clear(m_rpmLimitReason);
115 }
116
117 // Limit fuel only on boost pressure (limiting spark bends valves)
119 if (mapCut != 0) {
120 // require drop of 'boostCutPressureHyst' kPa to resume fuel
122 allowFuel.clear(ClearReason::BoostCut);
123 }
124 }
125
127 bool hasOilpSensor = Sensor::hasSensor(SensorType::OilPressure);
129 uint16_t minOilPressure = engineConfiguration->minOilPressureAfterStart;
130
131 // Only check if the setting is enabled and you have an oil pressure sensor
132 if (minOilPressure > 0 && hasOilpSensor) {
133 // Has it been long enough we should have pressure?
134 bool isTimedOut = engine->rpmCalculator.getSecondsSinceEngineStart(nowNt) > 5.0f;
135
136 // Only check before timed out
137 if (!isTimedOut) {
138 if (oilp) {
139 // We had oil pressure! Set the flag.
140 if (oilp.Value > minOilPressure) {
142 }
143 }
144 }
145
146 // If time is up, the sensor works, and no pressure, kill the engine.
147 if (isTimedOut && !m_hadOilPressureAfterStart) {
149 }
150 }
151
153 float minPressure = interpolate2d(rpm, config->minimumOilPressureBins, config->minimumOilPressureValues);
154 bool isPressureSufficient = oilp.Value > minPressure;
155
156 if (isPressureSufficient) {
157 m_lowOilPressureTimer.reset(nowNt);
158 }
159
162 }
163 }
164
165 // check the maximum oil pressure
166 float maxOilPressure = interpolate2d(rpm, config->maximumOilPressureBins, config->maximumOilPressureValues);
167 if (maxOilPressure > 0 && hasOilpSensor) {
168 if (oilp.Value < maxOilPressure) {
169 m_highOilPressureTimer.reset(nowNt);
170 }
173 }
174 }
175
176 } else {
177 // reset state in case of stalled engine
179 m_lowOilPressureTimer.reset(nowNt);
180 }
181
182 // If we're in engine stop mode, inhibit fuel
183 if (shutdownController.isEngineStop(nowNt)) {
184 /**
185 * todo: we need explicit clarification on why do we cut fuel but do not cut spark here!
186 */
188 }
189
190 {
191 // todo: we need to add some tests of this?
192 // If duty cycle is high, impose a fuel cut rev limiter.
193 // This is safer than attempting to limp along with injectors or a pump that are out of flow.
194 // Two conditions will trigger a cut:
195 // - An instantaneous excursion above maxInjectorDutyInstant
196 // - A sustained excursion above maxInjectorDutySustained for a duration of >= maxInjectorDutySustainedTimeout
197 // Only reset once below 20% duty to force the driver to lift off the pedal
198
199 auto injDutyCycle = getInjectorDutyCycle(rpm);
200 bool isOverInstantDutyCycle = injDutyCycle > engineConfiguration->maxInjectorDutyInstant;
201 bool isOverSustainedDutyCycle = injDutyCycle > engineConfiguration->maxInjectorDutySustained;
202 bool isUnderLowDuty = injDutyCycle < 20;
203
204 if (!isOverSustainedDutyCycle) {
205 // Duty cycle is OK, reset timer.
206 m_injectorDutySustainedTimer.reset(nowNt);
207 }
208
209 // True if isOverSustainedDutyCycle has been true for longer than the timeout
210 bool sustainedLimitTimedOut = m_injectorDutySustainedTimer.hasElapsedSec(engineConfiguration->maxInjectorDutySustainedTimeout);
211
212 bool someLimitTripped = isOverInstantDutyCycle || sustainedLimitTimedOut;
213
214 if (m_injectorDutyCutHysteresis.test(someLimitTripped, isUnderLowDuty)) {
216 warning(ObdCode::CUSTOM_TOO_LONG_FUEL_INJECTION, "Injector duty cycle cut %.1f", injDutyCycle);
217 }
218 }
219
220 {
221 // GDI Fuel cut
222 bool isGDIDriverInjectorTimeTooLong = engine->engineState.injectionDuration > engineConfiguration->mc33_t_hold_tot;
223
224 if (isGdiEngine() && isGDIDriverInjectorTimeTooLong) {
225 allowFuel.clear(ClearReason::GdiLimits);
226 warning(ObdCode::CUSTOM_TOO_LONG_FUEL_INJECTION, "Injection duration excess PT2001 limits time: %.4f", engine->engineState.injectionDuration);
227 }
228 }
229
230 // If the pedal is pushed while not running, cut fuel to clear a flood condition.
235 }
236#endif // EFI_SHAFT_POSITION_INPUT
237
238 if (!engine->isMainRelayEnabled()) {
239/*
240todo AndreiKA this change breaks 22 unit tests?
241 allowFuel.clear();
242 allowSpark.clear();
243*/
244 }
245
246#if EFI_LAUNCH_CONTROL
247 // Fuel cut if launch control engaged
249 allowFuel.clear(ClearReason::LaunchCut);
250 }
251
252 // Spark cut if launch control engaged
254 allowSpark.clear(ClearReason::LaunchCut);
255 }
256#endif // EFI_LAUNCH_CONTROL
257
258 m_transientAllowInjection = allowFuel;
259 m_transientAllowIgnition = allowSpark;
260
262 // Tracks the last time any cut happened
263 m_lastCutTime.reset(nowNt);
264 }
265}
266
268 m_ignitionOn = ignitionOn;
269}
270
275
284
285void LimpManager::setFaultRevLimit(int limit, ClearReason rpmLimitReason) {
286 // Only allow decreasing the limit
287 // aka uses the limit of the worst fault to yet occur
288 if (limit < m_faultRevLimit) {
289 m_faultRevLimit = limit;
290 m_rpmLimitReason = rpmLimitReason;
291 }
292}
293
294#if EFI_ELECTRONIC_THROTTLE_BODY
298#endif // EFI_ELECTRONIC_THROTTLE_BODY
299
303
305 if (!m_allowInjection) {
306 return {false, m_allowInjection.clearReason};
307 }
310 }
311 return {true, ClearReason::None};
312}
313
315 if (!m_allowIgnition) {
316 return {false, m_allowIgnition.clearReason};
317 }
320 }
321 return {true, ClearReason::None};
322}
323
329
332 return 1.0f; // no correction
333 return m_fuelCorrection;
334}
335
337 return m_lastCutTime.getElapsedSeconds();
338}
339#endif // EFI_ENGINE_CONTROL
ClearReason clearReason
void clear(ClearReason p_clearReason)
TriggerCentral triggerCentral
Definition engine.h:318
bool etbIgnoreJamProtection
Definition engine.h:297
bool isMainRelayEnabled() const
Definition engine.cpp:539
LaunchControlBase launchController
Definition engine.h:220
EngineState engineState
Definition engine.h:344
RpmCalculator rpmCalculator
Definition engine.h:306
LambdaMonitor lambdaMonitor
Definition engine.h:236
virtual operation_mode_e getOperationMode() const =0
floatms_t injectionDuration
bool test(float value, float rising, float falling)
Definition hysteresis.h:31
bool isLaunchFuelRpmRetardCondition() const
bool isLaunchSparkRpmRetardCondition() const
Clearable m_transientAllowInjection
angle_t m_timingRetard
Clearable m_allowInjection
Hysteresis m_revLimitHysteresis
Timer m_lowOilPressureTimer
Clearable m_allowIgnition
float getTimeSinceAnyCut() const
int32_t m_faultRevLimit
Clearable m_allowEtb
Timer m_highOilPressureTimer
LimpState allowInjection() const
bool m_hadOilPressureAfterStart
MaxLimitWithHysteresis m_boostCutHysteresis
ClearReason m_rpmLimitReason
Timer m_injectorDutySustainedTimer
Clearable m_allowTriggerInput
bool allowTriggerInput() const
void updateState(float rpm, efitick_t nowNt)
LimpState allowIgnition() const
Clearable m_transientAllowIgnition
void reportEtbProblem()
float getLimitingFuelCorrection() const
void updateRevLimit(float rpm)
bool allowElectronicThrottle() const
void onFastCallback() override
void setFaultRevLimit(int limit, ClearReason rpmLimitReason)
angle_t getLimitingTimingRetard() const
void onIgnitionStateChanged(bool ignitionOn) override
Timer m_lastCutTime
float m_fuelCorrection
Hysteresis m_injectorDutyCutHysteresis
ShutdownController shutdownController
Timer externalGdiCanBusComms
bool checkIfLimitIsExceeded(const float value, const float maxLimit, const float hysteresis)
bool hasSynchronizedPhase() const
float getSecondsSinceEngineStart(efitick_t nowNt) const
bool isRunning() const
virtual bool hasSensor() const
Definition sensor.h:141
virtual SensorResult get() const =0
static float getOrZero(SensorType type)
Definition sensor.h:83
bool isEngineStop(efitick_t nowNt) const
PrimaryTriggerDecoder triggerState
float interpolateClamped(float x1, float y1, float x2, float y2, float x)
efitick_t getTimeNowNt()
Definition efitime.cpp:19
EngineRotationState * getEngineRotationState()
Definition engine.cpp:573
static EngineAccessor engine
Definition engine.h:413
static constexpr persistent_config_s * config
static constexpr engine_configuration_s * engineConfiguration
bool warning(ObdCode code, const char *fmt,...)
percent_t getInjectorDutyCycle(float rpm)
bool isGdiEngine()
static bool noFiringUntilVvtSync()
ClearReason
Definition limp_manager.h:9
Main logic header.
@ CUSTOM_TOO_LONG_FUEL_INJECTION
@ FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR
@ FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR
@ FOUR_STROKE_THREE_TIMES_CRANK_SENSOR
@ DriverThrottleIntent
scaled_channel< uint8_t, 1, 100 > maximumOilPressureBins[4]
scaled_channel< uint8_t, 1, 10 > minimumOilPressureValues[8]
scaled_channel< int16_t, 1, 1 > cltRevLimitRpmBins[CLT_LIMITER_CURVE_SIZE]
scaled_channel< uint8_t, 1, 100 > minimumOilPressureBins[8]
scaled_channel< uint8_t, 1, 10 > maximumOilPressureValues[4]