| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | #include "pch.h" | |||
| 2 | ||||
| 3 | #include "lambda_monitor.h" | |||
| 4 | ||||
| 5 | #if EFI_SHAFT_POSITION_INPUT | |||
| 6 | ||||
| 7 | ✗ | float LambdaMonitor::getMaxAllowedLambda(float rpm, float load) const { | ||
| 8 | return | |||
| 9 | ✗ | engine->fuelComputer.targetLambda | ||
| 10 | ✗ | + interpolate3d( | ||
| 11 | ✗ | config->lambdaMaxDeviationTable, | ||
| 12 | ✗ | config->lambdaMaxDeviationLoadBins, load, | ||
| 13 | ✗ | config->lambdaMaxDeviationRpmBins, rpm | ||
| 14 | ✗ | ); | ||
| 15 | } | |||
| 16 | ||||
| 17 | 1101 | float LambdaMonitor::getTimeout() const { | ||
| 18 | 1101 | return engineConfiguration->lambdaProtectionTimeout; | ||
| 19 | } | |||
| 20 | ||||
| 21 | 1152 | bool LambdaMonitorBase::isCut() const { | ||
| 22 | 1152 | return lambdaMonitorCut; | ||
| 23 | } | |||
| 24 | ||||
| 25 | 1107 | void LambdaMonitorBase::update(float rpm, float load) { | ||
| 26 | 1107 | bool isGood = isCurrentlyGood(rpm, load); | ||
| 27 | 1107 | lambdaCurrentlyGood = isGood; | ||
| 28 |
2/2✓ Branch 0 taken 1104 times.
✓ Branch 1 taken 3 times.
|
2/2✓ Decision 'true' taken 1104 times.
✓ Decision 'false' taken 3 times.
|
1107 | if (isGood) { |
| 29 | 1104 | m_timeSinceGoodLambda.reset(); | ||
| 30 | } | |||
| 31 | ||||
| 32 |
1/1✓ Branch 2 taken 1107 times.
|
1107 | lambdaTimeSinceGood = m_timeSinceGoodLambda.getElapsedSeconds(); | |
| 33 | ||||
| 34 |
2/2✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1106 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 1106 times.
|
1107 | if (m_timeSinceGoodLambda.hasElapsedSec(getTimeout())) { |
| 35 | // Things have been bad long enough, cut! | |||
| 36 | 1 | lambdaMonitorCut = true; | ||
| 37 | } | |||
| 38 | ||||
| 39 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1104 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1104 times.
|
1107 | if (lambdaMonitorCut) { |
| 40 | // If things are back to normal, cancel the cut and force a reset | |||
| 41 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 2 times.
|
3 | if (restoreConditionsMet(rpm, load)) { |
| 42 | 1 | lambdaMonitorCut = false; | ||
| 43 | 1 | m_timeSinceGoodLambda.reset(); | ||
| 44 | } | |||
| 45 | } | |||
| 46 | 1107 | } | ||
| 47 | ||||
| 48 | 1101 | bool LambdaMonitorBase::isCurrentlyGood(float rpm, float load) const { | ||
| 49 | // Lambda is always good if disabled | |||
| 50 |
1/2✓ Branch 0 taken 1101 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 1101 times.
✗ Decision 'false' not taken.
|
1101 | if (!engineConfiguration->lambdaProtectionEnable) { |
| 51 | 1101 | return true; | ||
| 52 | } | |||
| 53 | ||||
| 54 | // Below min RPM, don't check | |||
| 55 | ✗ | if (rpm < engineConfiguration->lambdaProtectionMinRpm) { | ||
| 56 | ✗ | return true; | ||
| 57 | } | |||
| 58 | ||||
| 59 | // Below min load, don't check | |||
| 60 | ✗ | if (load < engineConfiguration->lambdaProtectionMinLoad) { | ||
| 61 | ✗ | return true; | ||
| 62 | } | |||
| 63 | ||||
| 64 | // Below min TPS, don't check | |||
| 65 | ✗ | if (Sensor::getOrZero(SensorType::Tps1) <= engineConfiguration->lambdaProtectionMinTps) { | ||
| 66 | ✗ | return true; | ||
| 67 | } | |||
| 68 | ||||
| 69 | // Pause checking if DFCO was active recently | |||
| 70 | ✗ | auto timeSinceDfco = engine->module<DfcoController>()->getTimeSinceCut(); | ||
| 71 | ✗ | if (timeSinceDfco < engineConfiguration->noFuelTrimAfterDfcoTime) { | ||
| 72 | ✗ | return true; | ||
| 73 | } | |||
| 74 | ||||
| 75 | // Pause checking if some other cut was active recently | |||
| 76 | ✗ | auto timeSinceFuelCut = engine->module<LimpManager>()->getTimeSinceAnyCut(); | ||
| 77 | // TODO: should this duration be configurable? | |||
| 78 | ✗ | if (timeSinceFuelCut < 2) { | ||
| 79 | ✗ | return true; | ||
| 80 | } | |||
| 81 | ||||
| 82 | // TODO: multiple banks | |||
| 83 | ✗ | if (auto lambda = Sensor::get(SensorType::Lambda1)) { | ||
| 84 | ✗ | if (lambda.Value < getMaxAllowedLambda(rpm, load)) { | ||
| 85 | // Lambda is OK, we're good. | |||
| 86 | ✗ | return true; | ||
| 87 | } | |||
| 88 | } else { | |||
| 89 | // Broken lambda sensor doesn't imply bad lambda | |||
| 90 | ||||
| 91 | // TODO: can/should we be smarter here? | |||
| 92 | ✗ | return true; | ||
| 93 | } | |||
| 94 | ||||
| 95 | // All checks failed, lambda is currently bad. | |||
| 96 | ✗ | return false; | ||
| 97 | } | |||
| 98 | ||||
| 99 | ✗ | bool LambdaMonitorBase::restoreConditionsMet(float rpm, float load) const { | ||
| 100 | ✗ | if (rpm > engineConfiguration->lambdaProtectionRestoreRpm) { | ||
| 101 | ✗ | return false; | ||
| 102 | } | |||
| 103 | ||||
| 104 | ✗ | if (load > engineConfiguration->lambdaProtectionRestoreLoad) { | ||
| 105 | ✗ | return false; | ||
| 106 | } | |||
| 107 | ||||
| 108 | ✗ | if (Sensor::getOrZero(SensorType::Tps1) > engineConfiguration->lambdaProtectionRestoreTps) { | ||
| 109 | ✗ | return false; | ||
| 110 | } | |||
| 111 | ||||
| 112 | ✗ | return true; | ||
| 113 | } | |||
| 114 | #endif // EFI_SHAFT_POSITION_INPUT | |||
| 115 |