GCC Code Coverage Report


Directory: ./
File: firmware/controllers/math/lambda_monitor.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 38.5% 20 0 52
Functions: 66.7% 4 0 6
Branches: 30.3% 10 0 33
Decisions: 30.0% 9 - 30

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 1120 float LambdaMonitor::getTimeout() const {
18 1120 return engineConfiguration->lambdaProtectionTimeout;
19 }
20
21 1171 bool LambdaMonitorBase::isCut() const {
22 1171 return lambdaMonitorCut;
23 }
24
25 1126 void LambdaMonitorBase::update(float rpm, float load) {
26 1126 bool isGood = isCurrentlyGood(rpm, load);
27 1126 lambdaCurrentlyGood = isGood;
28
2/2
✓ Branch 0 taken 1123 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 1123 times.
✓ Decision 'false' taken 3 times.
1126 if (isGood) {
29 1123 m_timeSinceGoodLambda.reset();
30 }
31
32
1/1
✓ Branch 2 taken 1126 times.
1126 lambdaTimeSinceGood = m_timeSinceGoodLambda.getElapsedSeconds();
33
34
2/2
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1125 times.
2/2
✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 1125 times.
1126 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 1123 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1123 times.
1126 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 1126 }
47
48 1120 bool LambdaMonitorBase::isCurrentlyGood(float rpm, float load) const {
49 // Lambda is always good if disabled
50
1/2
✓ Branch 0 taken 1120 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1120 times.
✗ Decision 'false' not taken.
1120 if (!engineConfiguration->lambdaProtectionEnable) {
51 1120 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