GCC Code Coverage Report


Directory: ./
File: unit_tests/tests/test_idle_controller.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 100.0% 377 0 377
Functions: 100.0% 71 0 71
Branches: 61.0% 531 0 871
Decisions: 100.0% 14 - 14

Line Branch Decision Exec Source
1 /*
2 * @file test_idle_controller.cpp
3 *
4 * @date Oct 17, 2013
5 * @author Andrey Belomutskiy, (c) 2012-2020
6 */
7
8 #include "pch.h"
9
10 #include "efi_pid.h"
11 #include "idle_thread.h"
12 #include "electronic_throttle.h"
13
14 using ::testing::StrictMock;
15 using ::testing::_;
16
17 using ICP = IIdleController::Phase;
18 using TgtInfo = IIdleController::TargetInfo;
19
20 4 TEST(idle_v2, timingPid) {
21
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
22
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
23
24 1 engineConfiguration->useIdleTimingPidControl = true;
25
26 1 engineConfiguration->idleTimingPid.pFactor = 0.1;
27 1 engineConfiguration->idleTimingPid.minValue = -10;
28 1 engineConfiguration->idleTimingPid.maxValue = 10;
29 1 engineConfiguration->idleTimingSoftEntryTime = 0.0f;
30
1/1
✓ Branch 1 taken 1 time.
1 dut.init();
31
32 // Check that out of idle mode it doesn't do anything
33
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Cranking));
34
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Coasting));
35
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Running));
36
37 // Check that it works in idle mode
38
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(-5, dut.getIdleTimingAdjustment(1050, 1000, ICP::Idling));
39
40 // ...but not when disabled
41 1 engineConfiguration->useIdleTimingPidControl = false;
42
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(0, dut.getIdleTimingAdjustment(1050, 1000, ICP::Idling));
43
44 1 engineConfiguration->useIdleTimingPidControl = true;
45
46
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(5, dut.getIdleTimingAdjustment(950, 1000, ICP::Idling));
47
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(2.5, dut.getIdleTimingAdjustment(975, 1000, ICP::Idling));
48
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(0, dut.getIdleTimingAdjustment(1000, 1000, ICP::Idling));
49
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(-2.5, dut.getIdleTimingAdjustment(1025, 1000, ICP::Idling));
50
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(-5, dut.getIdleTimingAdjustment(1050, 1000, ICP::Idling));
51 2 }
52
53 4 TEST(idle_v2, testTargetRpm) {
54
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
55
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
56
57
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 time.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 1 time.
17 for (size_t i = 0; i < efi::size(config->cltIdleRpmBins); i++) {
58 16 config->cltIdleRpmBins[i] = i * 10;
59 16 config->cltIdleRpm[i] = i * 100;
60 }
61
62 1 engineConfiguration->idlePidRpmUpperLimit = 50;
63
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ((TgtInfo{100, 150, 175}), dut.getTargetRpm(10));
64
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ((TgtInfo{500, 550, 575}), dut.getTargetRpm(50));
65
66 1 engineConfiguration->idlePidRpmUpperLimit = 73;
67
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ((TgtInfo{100, 173, 209.5}), dut.getTargetRpm(10));
68
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ((TgtInfo{500, 573, 609.5}), dut.getTargetRpm(50));
69 2 }
70
71 4 TEST(idle_v2, testDeterminePhase) {
72
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
73
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
74
75 // TPS threshold 5% for easy test
76 1 engineConfiguration->idlePidDeactivationTpsThreshold = 5;
77
78 // Max VSS for idle is 10kph
79 1 engineConfiguration->maxIdleVss = 10;
80
81 1 TgtInfo targetInfo;
82 // Phase determination should ignore this!
83 1 targetInfo.ClosedLoopTarget = 9999;
84
85 // Idling threshold is 1000 + 100 rpm
86 1 targetInfo.IdleEntryRpm = 1000 + 100;
87 1 targetInfo.IdleExitRpm = 1000 + 100;
88
89 // First test stopped engine
90
1/1
✓ Branch 1 taken 1 time.
1 engine->rpmCalculator.setRpmValue(0);
91
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Cranking, dut.determinePhase(0, targetInfo, unexpected, 0, 10));
92
93 // Now engine is running!
94 // Controller doesn't need this other than for isCranking()
95
1/1
✓ Branch 1 taken 1 time.
1 engine->rpmCalculator.setRpmValue(1000);
96
97 // Test invalid TPS, but inside the idle window
98
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Running, dut.determinePhase(1000, targetInfo, unexpected, 0, 10));
99
100 // Valid TPS should now be inside the zone
101
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Idling, dut.determinePhase(1000, targetInfo, 0, 0, 10));
102
103 // Inside the zone, but vehicle speed too fast
104
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Running, dut.determinePhase(1000, targetInfo, 0, 25, 10));
105
106 // Check that shortly after cranking, the cranking taper inhibits closed loop idle
107
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::CrankToIdleTaper, dut.determinePhase(1000, targetInfo, 0, 0, 0.5f));
108
109 // Above TPS threshold should be outside the zone
110
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Running, dut.determinePhase(1000, targetInfo, 10, 0, 10));
111
112 // Above target, below (target + upperLimit) should be in idle zone
113
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Idling, dut.determinePhase(1099, targetInfo, 0, 0, 10));
114
115 // above upper limit and on throttle should be out of idle zone
116
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Running, dut.determinePhase(1101, targetInfo, 10, 0, 10));
117
118 // Below TPS but above RPM should be outside the zone
119
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Coasting, dut.determinePhase(1101, targetInfo, 0, 0, 10));
120
3/7
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✗ Branch 19 not taken.
✗ Branch 24 not taken.
✗ Branch 27 not taken.
1 EXPECT_EQ(ICP::Coasting, dut.determinePhase(5000, targetInfo, 0, 0, 10));
121 2 }
122
123 4 TEST(idle_v2, crankingOpenLoop) {
124
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
125
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
126
127
128
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 1 time.
9 for (size_t i = 0; i < efi::size(config->cltCrankingCorrBins); i++) {
129 8 config->cltCrankingCorrBins[i] = i * 10;
130 // 50 as base idle value
131 8 config->cltCrankingCorr[i] = 50 * i * 0.1f;
132
133 // different values in running so we can tell which one is used
134 8 config->cltIdleCorrBins[i] = i * 10;
135 8 config->cltIdleCorrTable[0][i] = i * 0.2f;
136 8 config->cltIdleCorrTable[1][i] = i * 0.2f;
137 }
138
139
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(5, dut.getCrankingOpenLoop(10));
140
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getCrankingOpenLoop(50));
141 2 }
142
143 4 TEST(idle_v2, runningOpenLoopBasic) {
144
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
145
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
146
147
148
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 1 time.
9 for (size_t i = 0; i < efi::size(config->cltIdleCorrBins); i++) {
149 8 config->cltIdleCorrBins[i] = i * 10;
150 8 config->cltIdleCorrTable[0][i] = 50 * (i * 0.1f);
151 8 config->cltIdleCorrTable[1][i] = 50 * (i * 0.1f);
152 }
153
154
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(5, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 10, 0));
155
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 50, 0));
156 2 }
157
158 4 TEST(idle_v2, runningFanAcBump) {
159
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
160
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
161
162 1 engineConfiguration->acIdleExtraOffset = 9;
163 1 engineConfiguration->fan1ExtraIdle = 7;
164 1 engineConfiguration->fan2ExtraIdle = 3;
165
166 1 setTable(config->cltIdleCorrTable, 50.0f);
167
168 // Start with fan off
169
1/1
✓ Branch 1 taken 1 time.
1 enginePins.fanRelay.setValue(0);
170
171 // Should be base position
172
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 10, 0));
173
174 // Turn on AC!
175
1/1
✓ Branch 1 taken 1 time.
1 engine->module<AcController>()->acButtonState = true;
176
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50 + 9, dut.getRunningOpenLoop(IIdleController::Phase::Idling, 0, 10, 0));
177
1/1
✓ Branch 1 taken 1 time.
1 engine->module<AcController>()->acButtonState = false;
178
179 // Turn the fan on!
180
1/1
✓ Branch 1 taken 1 time.
1 enginePins.fanRelay.setValue(1);
181
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50 + 7, dut.getRunningOpenLoop(IIdleController::Phase::Idling, 0, 10, 0));
182
1/1
✓ Branch 1 taken 1 time.
1 enginePins.fanRelay.setValue(0);
183
184 // Turn on the other fan!
185
1/1
✓ Branch 1 taken 1 time.
1 enginePins.fanRelay2.setValue(1);
186
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50 + 3, dut.getRunningOpenLoop(IIdleController::Phase::Idling, 0, 10, 0));
187
188 // Turn on everything!
189
1/1
✓ Branch 1 taken 1 time.
1 engine->module<AcController>()->acButtonState = true;
190
1/1
✓ Branch 1 taken 1 time.
1 enginePins.fanRelay.setValue(1);
191
1/1
✓ Branch 1 taken 1 time.
1 enginePins.fanRelay2.setValue(1);
192
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50 + 9 + 7 + 3, dut.getRunningOpenLoop(IIdleController::Phase::Idling, 0, 10, 0));
193 2 }
194
195 // This can be seen as a kind of some close-loop logic, please read:
196 // https://github.com/rusefi/rusefi/issues/6977
197 4 TEST(idle_v2, idleAdderShouldNotAffectNonIdleAreas) {
198
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
199
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
200
201 1 engineConfiguration->acIdleExtraOffset = 9;
202
203 1 setTable(config->cltIdleCorrTable, 50.0f);
204
205 // Should be base position
206
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 10, 0));
207
208 // [A/C ON && Phase::Cranking] => should be equal to base time
209
1/1
✓ Branch 1 taken 1 time.
1 engine->module<AcController>()->acButtonState = true;
210
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 10, 0));
211
212 // [A/C ON && Phase::Running] => should be equal to base time plus a/c extra offset
213
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50 + 9, dut.getRunningOpenLoop(IIdleController::Phase::Idling, 0, 10, 0));
214 2 }
215
216 4 TEST(idle_v2, runningOpenLoopTpsTaper) {
217
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
218
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
219
220 // Zero out base tempco table
221 1 setTable(config->cltIdleCorrTable, 0.0f);
222
223 // Add 50% idle position
224 1 engineConfiguration->iacByTpsTaper = 50;
225 // At 10% TPS
226 1 engineConfiguration->idlePidDeactivationTpsThreshold = 10;
227
228 // Check in-bounds points
229
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(0, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 0, 0));
230
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 0, 5));
231
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 0, 10));
232
233 // Check out of bounds - shouldn't leave the interval [0, 10]
234
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(0, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 0, -5));
235
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(IIdleController::Phase::Cranking, 0, 0, 20));
236 2 }
237
238 4 TEST(idle_v2, runningOpenLoopTpsTaperWithDashpot) {
239
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
240
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
241
242 // Zero out base tempco table
243 1 setTable(config->cltIdleCorrTable, 0.0f);
244
245 // Add 50% idle position
246 1 engineConfiguration->iacByTpsTaper = 50;
247 // At 10% TPS
248 1 engineConfiguration->idlePidDeactivationTpsThreshold = 10;
249
250 // set hold and decay time
251 1 engineConfiguration->iacByTpsHoldTime = 10; // 10 secs
252 1 engineConfiguration->iacByTpsDecayTime = 10; // 10 secs
253
254 // save the lastTimeRunningUs time - let it be the start of the hold phase
255
1/1
✓ Branch 1 taken 1 time.
1 advanceTimeUs(5'000'000);
256 // full throttle = max.iac
257
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(ICP::Running, 0, 0, 100));
258
259 // jump to the end of the 'hold' phase of dashpot
260
1/1
✓ Branch 1 taken 1 time.
1 advanceTimeUs(10'000'000);
261
262 // change the state to idle (release the pedal) - but still 100% max.iac!
263
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(ICP::Idling, 0, 0, 0));
264 // now we're in the middle of decay
265
1/1
✓ Branch 1 taken 1 time.
1 advanceTimeUs(5'000'000);
266 // 50% decay (50% of 50 is 25)
267
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getRunningOpenLoop(ICP::Idling, 0, 0, 0));
268 // now the decay is finished
269
1/1
✓ Branch 1 taken 1 time.
1 advanceTimeUs(5'000'000);
270 // no correction
271
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(0, dut.getRunningOpenLoop(ICP::Idling, 0, 0, 0));
272 // still react to the pedal
273
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getRunningOpenLoop(ICP::Idling, 0, 0, 10));
274 2 }
275
276 struct MockOpenLoopIdler : public IdleController {
277
2/2
✓ Branch 3 taken 2 times.
✓ Branch 6 taken 2 times.
11 MOCK_METHOD(float, getCrankingOpenLoop, (float clt), (const, override));
278
5/5
✓ Branch 3 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 11 taken 2 times.
✓ Branch 15 taken 2 times.
✓ Branch 18 taken 2 times.
10 MOCK_METHOD(float, getRunningOpenLoop, (IIdleController::Phase phase, float rpm, float clt, SensorResult tps), (override));
279 };
280
281 4 TEST(idle_v2, testOpenLoopCranking) {
282
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
283
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockOpenLoopIdler> dut;
284
285
7/7
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 19 taken 1 time.
✓ Branch 22 taken 1 time.
✓ Branch 25 taken 1 time.
1 EXPECT_CALL(dut, getCrankingOpenLoop(30)).WillOnce(Return(44));
286
287 // Should return the value from getCrankingOpenLoop, and ignore running numbers
288
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(44, dut.getOpenLoop(ICP::Cranking, 0, 30, 0, 0));
289 2 }
290
291 4 TEST(idle_v2, openLoopRunningTaper) {
292
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
293
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockOpenLoopIdler> dut;
294
295
10/10
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 17 taken 1 time.
✓ Branch 20 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
✓ Branch 33 taken 1 time.
✓ Branch 36 taken 1 time.
✓ Branch 39 taken 1 time.
1 EXPECT_CALL(dut, getRunningOpenLoop(ICP::CrankToIdleTaper, 0, 30, SensorResult(0))).WillRepeatedly(Return(25));
296
10/10
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 17 taken 1 time.
✓ Branch 20 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
✓ Branch 33 taken 1 time.
✓ Branch 36 taken 1 time.
✓ Branch 39 taken 1 time.
1 EXPECT_CALL(dut, getRunningOpenLoop(ICP::Running, 0, 30, SensorResult(0))).WillRepeatedly(Return(25));
297
7/7
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 19 taken 1 time.
✓ Branch 22 taken 1 time.
✓ Branch 25 taken 1 time.
1 EXPECT_CALL(dut, getCrankingOpenLoop(30)).WillRepeatedly(Return(75));
298
299 // 0 cycles - no taper yet, pure cranking value
300
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(75, dut.getOpenLoop(ICP::Running, 0, 30, 0, 0));
301
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(75, dut.getOpenLoop(ICP::CrankToIdleTaper, 0, 30, 0, 0));
302
303 // 1/2 taper - half way, 50% each value -> outputs 50
304
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getOpenLoop(ICP::Running, 0, 30, 0, 0.5f));
305
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(50, dut.getOpenLoop(ICP::CrankToIdleTaper, 0, 30, 0, 0.5f));
306
307 // 1x taper - fully tapered, should be running value
308
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::Running, 0, 30, 0, 1.0f));
309
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::CrankToIdleTaper, 0, 30, 0, 1.0f));
310
311 // 2x taper - still fully tapered, should be running value
312
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::Running, 0, 30, 0, 2.0f));
313
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getOpenLoop(ICP::CrankToIdleTaper, 0, 30, 0, 2.0f));
314 2 }
315
316 4 TEST(idle_v2, getCrankingTaperFraction) {
317
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
318
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<MockOpenLoopIdler> dut;
319 1 const float mockedTemperature = 50;
320
321 1 setArrayValues(config->afterCrankingIACtaperDuration, 500);
322
323 // 0 cycles - no taper yet, pure cranking value
324
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(0, dut.getCrankingTaperFraction(mockedTemperature));
325
326 // 250 cycles - half way, 50% each value -> outputs 50
327
2/2
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 250 times.
✓ Decision 'false' taken 1 time.
251 for (size_t i = 0; i < 250; i++) {
328
1/1
✓ Branch 1 taken 250 times.
250 engine->rpmCalculator.onNewEngineCycle();
329 }
330
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(0.5f, dut.getCrankingTaperFraction(mockedTemperature));
331
332 // 500 cycles - fully tapered, should be running value
333
2/2
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 250 times.
✓ Decision 'false' taken 1 time.
251 for (size_t i = 0; i < 250; i++) {
334
1/1
✓ Branch 1 taken 250 times.
250 engine->rpmCalculator.onNewEngineCycle();
335 }
336
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(1, dut.getCrankingTaperFraction(mockedTemperature));
337
338 // 1000 cycles - still fully tapered, should be running value
339
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 500 times.
✓ Decision 'false' taken 1 time.
501 for (size_t i = 0; i < 500; i++) {
340
1/1
✓ Branch 1 taken 500 times.
500 engine->rpmCalculator.onNewEngineCycle();
341 }
342
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(2, dut.getCrankingTaperFraction(mockedTemperature));
343 2 }
344
345 4 TEST(idle_v2, openLoopCoastingTable) {
346
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
347
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
348
349 // enable & configure feature
350 1 engineConfiguration->useIacTableForCoasting = true;
351
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 1 time.
17 for (size_t i = 0; i < CLT_CURVE_SIZE; i++) {
352 16 config->iacCoastingRpmBins[i] = 100 * i;
353 16 config->iacCoasting[i] = 5 * i;
354 }
355
356
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(40, dut.getOpenLoop(ICP::Coasting, 800, 0, 0, 2));
357
3/7
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
1 EXPECT_FLOAT_EQ(75, dut.getOpenLoop(ICP::Coasting, 1500, 0, 0, 2));
358 2 }
359
360 4 TEST(idle_v2, closedLoopBasic) {
361
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
362
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
363
1/1
✓ Branch 1 taken 1 time.
1 dut.init();
364
365 // Not testing PID here, so we can set very simple PID gains
366 1 engineConfiguration->idleRpmPid.pFactor = 0.5; // 0.5 output per 1 RPM error = 50% per 100 rpm
367 1 engineConfiguration->idleRpmPid.iFactor = 0;
368 1 engineConfiguration->idleRpmPid.dFactor = 0;
369 1 engineConfiguration->idleRpmPid.iFactor = 0;
370 1 engineConfiguration->idleRpmPid.periodMs = 0;
371 1 engineConfiguration->idleRpmPid.minValue = -50;
372 1 engineConfiguration->idleRpmPid.maxValue = 50;
373
374 1 engineConfiguration->idlePidRpmDeadZone = 0;
375
376 // burn one update then advance time 5 seconds to avoid difficulty from wasResetPid
377
1/1
✓ Branch 1 taken 1 time.
1 dut.getClosedLoop(ICP::Idling, 0, 900, 900);
378
1/1
✓ Branch 1 taken 1 time.
1 advanceTimeUs(5'000'000);
379
380 // Test above target, should return negative
381
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(-25, dut.getClosedLoop(ICP::Idling, 0, /*rpm*/ 950, /*tgt*/ 900));
382
383 // Below target, should return positive
384
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(25, dut.getClosedLoop(ICP::Idling, 0, /*rpm*/ 850, /*tgt*/ 900));
385 2 }
386
387 4 TEST(idle_v2, closedLoopDeadzone) {
388
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
389
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
390
1/1
✓ Branch 1 taken 1 time.
1 dut.init();
391
392
393 // Not testing PID here, so we can set very simple PID gains
394 1 engineConfiguration->idleRpmPid.pFactor = 0.5; // 0.5 output per 1 RPM error = 50% per 100 rpm
395 1 engineConfiguration->idleRpmPid.iFactor = 0;
396 1 engineConfiguration->idleRpmPid.dFactor = 0;
397 1 engineConfiguration->idleRpmPid.iFactor = 0;
398 1 engineConfiguration->idleRpmPid.periodMs = 0;
399 1 engineConfiguration->idleRpmPid.minValue = -50;
400 1 engineConfiguration->idleRpmPid.maxValue = 50;
401
402 1 engineConfiguration->idlePidRpmDeadZone = 25;
403
404 // burn one then advance time 5 seconds to avoid difficulty from wasResetPid
405
1/1
✓ Branch 1 taken 1 time.
1 dut.getClosedLoop(ICP::Idling, 0, 900, 900);
406
1/1
✓ Branch 1 taken 1 time.
1 advanceTimeUs(5'000'000);
407
408 // Test above target, should return negative
409
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(-25, dut.getClosedLoop(ICP::Idling, 0, /*rpm*/ 950, /*tgt*/ 900));
410
411 // Inside deadzone, should return same as last time
412
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_FLOAT_EQ(-25, dut.getClosedLoop(ICP::Idling, 0, /*rpm*/ 900, /*tgt*/ 900));
413 2 }
414
415 4 TEST(idle_v2, RunningToIdleTransition) {
416
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
417
1/1
✓ Branch 2 taken 1 time.
1 IdleController dut;
418
1/1
✓ Branch 1 taken 1 time.
1 dut.init();
419
420 1 engineConfiguration->idleRpmPid.pFactor = 0.0040; // 0.5 output per 1 RPM error = 50% per 100 rpm
421 1 engineConfiguration->idleRpmPid.iFactor = 0.0040;
422 1 engineConfiguration->idleRpmPid.dFactor = 0.0001;
423 1 engineConfiguration->idleRpmPid.periodMs = 0;
424 1 engineConfiguration->idleRpmPid.minValue = -50;
425 1 engineConfiguration->idleRpmPid.maxValue = 50;
426
427 1 SensorResult expectedTps = 0;
428 1 float expectedClt = 37;
429
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::DriverThrottleIntent, expectedTps.Value);
430
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Clt, expectedClt);
431
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::VehicleSpeed, 15.0);
432
433 // we are on running state still, so 0 idle position
434
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(0, dut.getClosedLoop(ICP::Running, expectedTps.Value, 950, 1100));
435
1/1
✓ Branch 2 taken 1 time.
1 dut.getIdlePid()->postState(engine->outputChannels.idleStatus);
436
437
2/6
✓ Branch 3 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 11 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
1 EXPECT_EQ(0, engine->outputChannels.idleStatus.dTerm);
438
2/6
✓ Branch 3 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 11 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
1 EXPECT_EQ(0, engine->outputChannels.idleStatus.iTerm);
439
2/6
✓ Branch 3 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 11 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
1 EXPECT_EQ(0, engine->outputChannels.idleStatus.pTerm);
440
441 // now we are idling
442
1/1
✓ Branch 1 taken 1 time.
1 dut.getClosedLoop(ICP::Idling, expectedTps.Value, 950, 1100);
443
1/1
✓ Branch 1 taken 1 time.
1 advanceTimeUs(5'000'000);
444
445
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_NEAR(3.603, dut.getClosedLoop(ICP::Idling, expectedTps.Value, 950, 1100), EPS2D);
446
1/1
✓ Branch 2 taken 1 time.
1 dut.getIdlePid()->postState(engine->outputChannels.idleStatus);
447
448
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_NEAR(3, engine->outputChannels.idleStatus.dTerm, EPS2D);
449
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_NEAR(0, engine->outputChannels.idleStatus.iTerm, EPS2D);
450
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(0.6, engine->outputChannels.idleStatus.pTerm, EPS2D);
451
452 // still idle, add some error:
453
3/7
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
1 EXPECT_NEAR(1.086, dut.getClosedLoop(ICP::Idling, expectedTps.Value, 950, 1120), EPS2D);
454
1/1
✓ Branch 2 taken 1 time.
1 dut.getIdlePid()->postState(engine->outputChannels.idleStatus);
455
456
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_NEAR(0.4, engine->outputChannels.idleStatus.dTerm, EPS2D);
457
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_NEAR(0.01, engine->outputChannels.idleStatus.iTerm, EPS2D);
458
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(0.68, engine->outputChannels.idleStatus.pTerm, EPS2D);
459
460 // back to running mode, should reset all:
461
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(0, dut.getClosedLoop(ICP::Running, expectedTps.Value, 950, 1100));
462
1/1
✓ Branch 2 taken 1 time.
1 dut.getIdlePid()->postState(engine->outputChannels.idleStatus);
463
464 // first cycle we set shouldResetPid / mustResetPid, now we test the reset:
465
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(0, dut.getClosedLoop(ICP::Running, expectedTps.Value, 400, 1100));
466
1/1
✓ Branch 2 taken 1 time.
1 dut.getIdlePid()->postState(engine->outputChannels.idleStatus);
467
468
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_NEAR(0, engine->outputChannels.idleStatus.dTerm, EPS2D);
469
2/6
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
1 EXPECT_NEAR(0, engine->outputChannels.idleStatus.iTerm, EPS2D);
470
2/6
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
1 EXPECT_NEAR(0, engine->outputChannels.idleStatus.pTerm, EPS2D);
471 2 }
472
473 struct IntegrationIdleMock : public IdleController {
474
2/2
✓ Branch 3 taken 3 times.
✓ Branch 6 taken 3 times.
6 MOCK_METHOD(TargetInfo, getTargetRpm, (float clt), (override));
475
6/6
✓ Branch 3 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 11 taken 3 times.
✓ Branch 15 taken 3 times.
✓ Branch 19 taken 3 times.
✓ Branch 22 taken 3 times.
6 MOCK_METHOD(ICP, determinePhase, (float rpm, TargetInfo targetRpm, SensorResult tps, float vss, float crankingTaperFraction), (override));
476
6/6
✓ Branch 3 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 11 taken 3 times.
✓ Branch 15 taken 3 times.
✓ Branch 19 taken 3 times.
✓ Branch 22 taken 3 times.
6 MOCK_METHOD(float, getOpenLoop, (ICP phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction), (override));
477
5/5
✓ Branch 3 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 11 taken 2 times.
✓ Branch 15 taken 2 times.
✓ Branch 18 taken 2 times.
4 MOCK_METHOD(float, getClosedLoop, (ICP phase, float tps, float rpm, float target), (override));
478
2/2
✓ Branch 3 taken 3 times.
✓ Branch 6 taken 3 times.
6 MOCK_METHOD(float, getCrankingTaperFraction, (float clt), (const, override));
479 };
480
481 4 TEST(idle_v2, IntegrationManual) {
482
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
483
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<IntegrationIdleMock> dut;
484
485 1 SensorResult expectedTps = 1;
486 1 float expectedClt = 37;
487
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::DriverThrottleIntent, expectedTps.Value);
488
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Clt, expectedClt);
489
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::VehicleSpeed, 15.0);
490
491 1 TgtInfo target{1000, 1100, 1100};
492
493 // Target of 1000 rpm
494
4/4
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 12 taken 1 time.
3 EXPECT_CALL(dut, getTargetRpm(expectedClt))
495
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(target));
496
497 // 30% of the way through cranking taper
498
4/4
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 12 taken 1 time.
3 EXPECT_CALL(dut, getCrankingTaperFraction(expectedClt))
499
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(0.3f));
500
501 // Determine phase will claim we're idling
502
8/8
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 21 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
3 EXPECT_CALL(dut, determinePhase(950, target, expectedTps, 15, 0.3f))
503
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(ICP::Idling));
504
505 // Open loop should be asked for an open loop position
506
8/8
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 21 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
3 EXPECT_CALL(dut, getOpenLoop(ICP::Idling, 950, expectedClt, expectedTps, 0.3f))
507
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(13));
508
509 // getClosedLoop() should not be called!
510
511
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(13, dut.getIdlePosition(950));
512 2 }
513
514 4 TEST(idle_v2, IntegrationAutomatic) {
515
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
516
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<IntegrationIdleMock> dut;
517
518 1 engineConfiguration->idleMode = idle_mode_e::IM_AUTO;
519
520 1 SensorResult expectedTps = 1;
521 1 float expectedClt = 37;
522
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::DriverThrottleIntent, expectedTps.Value);
523
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Clt, expectedClt);
524
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::VehicleSpeed, 15.0);
525
526 1 TgtInfo target{1000, 1100, 1100};
527
528 // Target of 1000 rpm
529
4/4
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 12 taken 1 time.
3 EXPECT_CALL(dut, getTargetRpm(expectedClt))
530
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(target));
531
532 // 40% of the way through cranking taper
533
4/4
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 12 taken 1 time.
3 EXPECT_CALL(dut, getCrankingTaperFraction(expectedClt))
534
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(0.4f));
535
536 // Determine phase will claim we're idling
537
8/8
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 21 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
3 EXPECT_CALL(dut, determinePhase(950, target, expectedTps, 15, 0.4f))
538
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(ICP::Idling));
539
540 // Open loop should be asked for an open loop position
541
8/8
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 21 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
3 EXPECT_CALL(dut, getOpenLoop(ICP::Idling, 950, expectedClt, expectedTps, 0.4f))
542
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(13));
543
544 // Closed loop should get called
545
7/7
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 17 taken 1 time.
✓ Branch 20 taken 1 time.
✓ Branch 24 taken 1 time.
3 EXPECT_CALL(dut, getClosedLoop(ICP::Idling, expectedTps.Value, 950, 1000))
546
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(7));
547
548 // Result should be open + closed
549
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(13 + 7, dut.getIdlePosition(950));
550 2 }
551
552 4 TEST(idle_v2, IntegrationClamping) {
553
1/1
✓ Branch 2 taken 1 time.
1 EngineTestHelper eth(engine_type_e::TEST_ENGINE);
554
1/1
✓ Branch 2 taken 1 time.
1 StrictMock<IntegrationIdleMock> dut;
555
556 1 engineConfiguration->idleMode = idle_mode_e::IM_AUTO;
557
558 1 SensorResult expectedTps = 1;
559 1 float expectedClt = 37;
560
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::DriverThrottleIntent, expectedTps.Value);
561
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::Clt, expectedClt);
562
1/1
✓ Branch 1 taken 1 time.
1 Sensor::setMockValue(SensorType::VehicleSpeed, 15.0);
563 1 TgtInfo target{1000, 1100, 1100};
564
565 // Target of 1000 rpm
566
4/4
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 12 taken 1 time.
3 EXPECT_CALL(dut, getTargetRpm(expectedClt))
567
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(target));
568
569 // 50% of the way through cranking taper
570
4/4
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 12 taken 1 time.
3 EXPECT_CALL(dut, getCrankingTaperFraction(expectedClt))
571
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(0.5f));
572
573 // Determine phase will claim we're idling
574
8/8
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 21 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
3 EXPECT_CALL(dut, determinePhase(950, target, expectedTps, 15, 0.5f))
575
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(ICP::Idling));
576
577 // Open loop should be asked for an open loop position
578
8/8
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 21 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 28 taken 1 time.
3 EXPECT_CALL(dut, getOpenLoop(ICP::Idling, 950, expectedClt, expectedTps, 0.5f))
579
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(75));
580
581 // Closed loop should get called
582
7/7
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 17 taken 1 time.
✓ Branch 20 taken 1 time.
✓ Branch 24 taken 1 time.
3 EXPECT_CALL(dut, getClosedLoop(ICP::Idling, expectedTps.Value, 950, 1000))
583
3/3
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
3 .WillOnce(Return(75));
584
585 // Result would be 75 + 75 = 150, but it should clamp to 100
586
3/7
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 21 not taken.
✗ Branch 24 not taken.
1 EXPECT_EQ(100, dut.getIdlePosition(950));
587 2 }
588