Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /** | |||
2 | * @file rpm_calculator.cpp | |||
3 | * @brief RPM calculator | |||
4 | * | |||
5 | * Here we listen to position sensor events in order to figure our if engine is currently running or not. | |||
6 | * Actual getRpm() is calculated once per crankshaft revolution, based on the amount of time passed | |||
7 | * since the start of previous shaft revolution. | |||
8 | * | |||
9 | * We also have 'instant RPM' logic separate from this 'cycle RPM' logic. Open question is why do we not use | |||
10 | * instant RPM instead of cycle RPM more often. | |||
11 | * | |||
12 | * @date Jan 1, 2013 | |||
13 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
14 | */ | |||
15 | ||||
16 | #include "pch.h" | |||
17 | ||||
18 | #include "trigger_central.h" | |||
19 | ||||
20 | #include "engine_sniffer.h" | |||
21 | ||||
22 | // See RpmCalculator::checkIfSpinning() | |||
23 | #ifndef NO_RPM_EVENTS_TIMEOUT_SECS | |||
24 | #define NO_RPM_EVENTS_TIMEOUT_SECS 2 | |||
25 | #endif /* NO_RPM_EVENTS_TIMEOUT_SECS */ | |||
26 | ||||
27 | 522957 | float RpmCalculator::getRpmAcceleration() const { | ||
28 | 522957 | return rpmRate; | ||
29 | } | |||
30 | ||||
31 | 35967 | bool RpmCalculator::isStopped() const { | ||
32 | // Spinning-up with zero RPM means that the engine is not ready yet, and is treated as 'stopped'. | |||
33 |
6/6✓ Branch 0 taken 34723 times.
✓ Branch 1 taken 1244 times.
✓ Branch 2 taken 3979 times.
✓ Branch 3 taken 30744 times.
✓ Branch 4 taken 2196 times.
✓ Branch 5 taken 1783 times.
|
35967 | return state == STOPPED || (state == SPINNING_UP && cachedRpmValue == 0); | |
34 | } | |||
35 | ||||
36 | 19882 | bool RpmCalculator::isCranking() const { | ||
37 | // Spinning-up with non-zero RPM is suitable for all engine math, as good as cranking | |||
38 |
6/6✓ Branch 0 taken 17795 times.
✓ Branch 1 taken 2087 times.
✓ Branch 2 taken 1020 times.
✓ Branch 3 taken 16775 times.
✓ Branch 4 taken 987 times.
✓ Branch 5 taken 33 times.
|
19882 | return state == CRANKING || (state == SPINNING_UP && cachedRpmValue > 0); | |
39 | } | |||
40 | ||||
41 | 167714 | bool RpmCalculator::isSpinningUp() const { | ||
42 | 167714 | return state == SPINNING_UP; | ||
43 | } | |||
44 | ||||
45 | 525349 | uint32_t RpmCalculator::getRevolutionCounterSinceStart(void) const { | ||
46 | 525349 | return revolutionCounterSinceStart; | ||
47 | } | |||
48 | ||||
49 | 62978 | float RpmCalculator::getCachedRpm() const { | ||
50 | 62978 | return cachedRpmValue; | ||
51 | } | |||
52 | ||||
53 | 102089 | operation_mode_e lookupOperationMode() { | ||
54 |
2/2✓ Branch 0 taken 287 times.
✓ Branch 1 taken 101802 times.
|
2/2✓ Decision 'true' taken 287 times.
✓ Decision 'false' taken 101802 times.
|
102089 | if (engineConfiguration->twoStroke) { |
55 | 287 | return TWO_STROKE; | ||
56 | } else { | |||
57 |
2/2✓ Branch 0 taken 87553 times.
✓ Branch 1 taken 14249 times.
|
101802 | return engineConfiguration->skippedWheelOnCam ? FOUR_STROKE_CAM_SENSOR : FOUR_STROKE_CRANK_SENSOR; | |
58 | } | |||
59 | } | |||
60 | ||||
61 | #if EFI_SHAFT_POSITION_INPUT | |||
62 | // see also in TunerStudio project '[doesTriggerImplyOperationMode] tag | |||
63 | // this is related to 'knownOperationMode' flag | |||
64 | 1577124 | static bool doesTriggerImplyOperationMode(trigger_type_e type) { | ||
65 |
2/2✓ Branch 0 taken 101184 times.
✓ Branch 1 taken 1475940 times.
|
1577124 | switch (type) { | |
66 |
1/1✓ Decision 'true' taken 101184 times.
|
101184 | case trigger_type_e::TT_TOOTHED_WHEEL: | |
67 | case trigger_type_e::TT_HALF_MOON: | |||
68 | case trigger_type_e::TT_3_1_CAM: // huh why is this trigger with CAM suffix right in the name on this exception list?! | |||
69 | case trigger_type_e::TT_36_2_2_2: // this trigger is special due to rotary application https://github.com/rusefi/rusefi/issues/5566 | |||
70 | case trigger_type_e::TT_TOOTHED_WHEEL_60_2: | |||
71 | case trigger_type_e::TT_TOOTHED_WHEEL_36_1: | |||
72 | // These modes could be either cam or crank speed | |||
73 |
1/1✓ Decision 'true' taken 101184 times.
|
101184 | return false; | |
74 |
1/1✓ Decision 'true' taken 1475940 times.
|
1475940 | default: | |
75 | 1475940 | return true; | ||
76 | } | |||
77 | } | |||
78 | #endif // EFI_SHAFT_POSITION_INPUT | |||
79 | ||||
80 | // todo: move to triggerCentral/triggerShape since has nothing to do with rotation state! | |||
81 | 1577124 | operation_mode_e RpmCalculator::getOperationMode() const { | ||
82 | #if EFI_SHAFT_POSITION_INPUT | |||
83 | // Ignore user-provided setting for well known triggers. | |||
84 |
2/2✓ Branch 1 taken 1475940 times.
✓ Branch 2 taken 101184 times.
|
2/2✓ Decision 'true' taken 1475940 times.
✓ Decision 'false' taken 101184 times.
|
1577124 | if (doesTriggerImplyOperationMode(engineConfiguration->trigger.type)) { |
85 | // For example for Miata NA, there is no reason to allow user to set FOUR_STROKE_CRANK_SENSOR | |||
86 | 1475940 | return engine->triggerCentral.triggerShape.getWheelOperationMode(); | ||
87 | } else | |||
88 | #endif // EFI_SHAFT_POSITION_INPUT | |||
89 | { | |||
90 | // For example 36-1, could be on either cam or crank, so we have to ask the user | |||
91 | 101184 | return lookupOperationMode(); | ||
92 | } | |||
93 | } | |||
94 | ||||
95 | ||||
96 | #if EFI_SHAFT_POSITION_INPUT | |||
97 | ||||
98 | 677 | RpmCalculator::RpmCalculator() : | ||
99 | 677 | StoredValueSensor(SensorType::Rpm, 0) | ||
100 | { | |||
101 | 677 | assignRpmValue(0); | ||
102 | 677 | } | ||
103 | ||||
104 | /** | |||
105 | * @return true if there was a full shaft revolution within the last second | |||
106 | */ | |||
107 | 6740 | bool RpmCalculator::isRunning() const { | ||
108 | 6740 | return state == RUNNING; | ||
109 | } | |||
110 | ||||
111 | /** | |||
112 | * @return true if engine is spinning (cranking or running) | |||
113 | */ | |||
114 | 2335 | bool RpmCalculator::checkIfSpinning(efitick_t nowNt) const { | ||
115 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2335 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2335 times.
|
2335 | if (getLimpManager()->shutdownController.isEngineStop(nowNt)) { |
116 | ✗ | return false; | ||
117 | } | |||
118 | ||||
119 | // Anything below 60 rpm is not running | |||
120 | 2335 | bool noRpmEventsForTooLong = lastTdcTimer.getElapsedSeconds(nowNt) > NO_RPM_EVENTS_TIMEOUT_SECS; | ||
121 | ||||
122 | /** | |||
123 | * Also check if there were no trigger events | |||
124 | */ | |||
125 | 2335 | bool noTriggerEventsForTooLong = !engine->triggerCentral.engineMovedRecently(nowNt); | ||
126 | ||||
127 |
3/4✓ Branch 0 taken 2168 times.
✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2168 times.
|
2/2✓ Decision 'true' taken 167 times.
✓ Decision 'false' taken 2168 times.
|
2335 | if (noRpmEventsForTooLong || noTriggerEventsForTooLong) { |
128 | 167 | return false; | ||
129 | } | |||
130 | ||||
131 | 2168 | return true; | ||
132 | } | |||
133 | ||||
134 | 23817 | void RpmCalculator::assignRpmValue(float floatRpmValue) { | ||
135 | 23817 | previousRpmValue = cachedRpmValue; | ||
136 | ||||
137 | 23817 | cachedRpmValue = floatRpmValue; | ||
138 | ||||
139 | 23817 | setValidValue(floatRpmValue, 0); // 0 for current time since RPM sensor never times out | ||
140 |
2/2✓ Branch 0 taken 885 times.
✓ Branch 1 taken 22932 times.
|
2/2✓ Decision 'true' taken 885 times.
✓ Decision 'false' taken 22932 times.
|
23817 | if (cachedRpmValue <= 0) { |
141 | 885 | oneDegreeUs = NAN; | ||
142 | } else { | |||
143 | // here it's really important to have more precise float RPM value, see #796 | |||
144 | 22932 | oneDegreeUs = getOneDegreeTimeUs(floatRpmValue); | ||
145 |
2/2✓ Branch 0 taken 187 times.
✓ Branch 1 taken 22745 times.
|
2/2✓ Decision 'true' taken 187 times.
✓ Decision 'false' taken 22745 times.
|
22932 | if (previousRpmValue == 0) { |
146 | /** | |||
147 | * this would make sure that we have good numbers for first cranking revolution | |||
148 | * #275 cranking could be improved | |||
149 | */ | |||
150 | 187 | engine->periodicFastCallback(); | ||
151 | } | |||
152 | } | |||
153 | 23817 | } | ||
154 | ||||
155 | 21877 | void RpmCalculator::setRpmValue(float value) { | ||
156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21877 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 21877 times.
|
21877 | if (value > MAX_ALLOWED_RPM) { |
157 | ✗ | value = 0; | ||
158 | } | |||
159 | ||||
160 | 21877 | assignRpmValue(value); | ||
161 | 21877 | spinning_state_e oldState = state; | ||
162 | // Change state | |||
163 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 21720 times.
|
2/2✓ Decision 'true' taken 157 times.
✓ Decision 'false' taken 21720 times.
|
21877 | if (cachedRpmValue == 0) { |
164 | 157 | state = STOPPED; | ||
165 |
2/2✓ Branch 0 taken 17035 times.
✓ Branch 1 taken 4685 times.
|
2/2✓ Decision 'true' taken 17035 times.
✓ Decision 'false' taken 4685 times.
|
21720 | } else if (cachedRpmValue >= engineConfiguration->cranking.rpm) { |
166 |
2/2✓ Branch 0 taken 114 times.
✓ Branch 1 taken 16921 times.
|
2/2✓ Decision 'true' taken 114 times.
✓ Decision 'false' taken 16921 times.
|
17035 | if (state != RUNNING) { |
167 | // Store the time the engine started | |||
168 | 114 | engineStartTimer.reset(); | ||
169 | } | |||
170 | ||||
171 | 17035 | state = RUNNING; | ||
172 |
4/4✓ Branch 0 taken 4650 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 4605 times.
|
2/2✓ Decision 'true' taken 80 times.
✓ Decision 'false' taken 4605 times.
|
4685 | } else if (state == STOPPED || state == SPINNING_UP) { |
173 | /** | |||
174 | * We are here if RPM is above zero but we have not seen running RPM yet. | |||
175 | * This gives us cranking hysteresis - a drop of RPM during running is still running, not cranking. | |||
176 | */ | |||
177 | 80 | state = CRANKING; | ||
178 | } | |||
179 | #if EFI_ENGINE_CONTROL | |||
180 | // This presumably fixes injection mode change for cranking-to-running transition. | |||
181 | // 'isSimultaneous' flag should be updated for events if injection modes differ for cranking and running. | |||
182 |
3/4✓ Branch 0 taken 250 times.
✓ Branch 1 taken 21627 times.
✓ Branch 2 taken 250 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 250 times.
✓ Decision 'false' taken 21627 times.
|
21877 | if (state != oldState && engineConfiguration->crankingInjectionMode != engineConfiguration->injectionMode) { |
183 | // Reset the state of all injectors: when we change fueling modes, we could | |||
184 | // immediately reschedule an injection that's currently underway. That will cause | |||
185 | // the injector's overlappingCounter to get out of sync with reality. As the fix, | |||
186 | // every injector's state is forcibly reset just before we could cause that to happen. | |||
187 | 250 | engine->injectionEvents.resetOverlapping(); | ||
188 | ||||
189 | // reschedule all injection events now that we've reset them | |||
190 | 250 | engine->injectionEvents.addFuelEvents(); | ||
191 | } | |||
192 | #endif | |||
193 | 21877 | } | ||
194 | ||||
195 | 5 | spinning_state_e RpmCalculator::getState() const { | ||
196 | 5 | return state; | ||
197 | } | |||
198 | ||||
199 | 3390 | void RpmCalculator::onNewEngineCycle() { | ||
200 | 3390 | revolutionCounterSinceBoot++; | ||
201 | 3390 | revolutionCounterSinceStart++; | ||
202 | 3390 | } | ||
203 | ||||
204 | 43324 | uint32_t RpmCalculator::getRevolutionCounterM(void) const { | ||
205 | 43324 | return revolutionCounterSinceBoot; | ||
206 | } | |||
207 | ||||
208 | ✗ | void RpmCalculator::onSlowCallback() { | ||
209 | // Stop the engine if it's been too long since we got a trigger event | |||
210 | ✗ | if (!engine->triggerCentral.engineMovedRecently(getTimeNowNt())) { | ||
211 | ✗ | setStopSpinning(); | ||
212 | } | |||
213 | ✗ | } | ||
214 | ||||
215 | 130 | void RpmCalculator::setStopSpinning() { | ||
216 | 130 | isSpinning = false; | ||
217 | 130 | revolutionCounterSinceStart = 0; | ||
218 | 130 | rpmRate = 0; | ||
219 | ||||
220 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 127 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 127 times.
|
130 | if (cachedRpmValue != 0) { |
221 | 3 | assignRpmValue(0); | ||
222 | // needed by 'useNoiselessTriggerDecoder' | |||
223 | 3 | engine->triggerCentral.noiseFilter.resetAccumSignalData(); | ||
224 | 3 | efiPrintf("engine stopped"); | ||
225 | } | |||
226 | 130 | state = STOPPED; | ||
227 | ||||
228 | 130 | engine->onEngineStopped(); | ||
229 | 130 | } | ||
230 | ||||
231 | 36279 | void RpmCalculator::setSpinningUp(efitick_t nowNt) { | ||
232 |
2/2✓ Branch 0 taken 1408 times.
✓ Branch 1 taken 34871 times.
|
2/2✓ Decision 'true' taken 1408 times.
✓ Decision 'false' taken 34871 times.
|
36279 | if (!engineConfiguration->isFasterEngineSpinUpEnabled) |
233 | 1408 | return; | ||
234 | // Only a completely stopped and non-spinning engine can enter the spinning-up state. | |||
235 |
6/6✓ Branch 1 taken 2418 times.
✓ Branch 2 taken 32453 times.
✓ Branch 3 taken 110 times.
✓ Branch 4 taken 2308 times.
✓ Branch 5 taken 110 times.
✓ Branch 6 taken 34761 times.
|
2/2✓ Decision 'true' taken 110 times.
✓ Decision 'false' taken 34761 times.
|
34871 | if (isStopped() && !isSpinning) { |
236 | 110 | state = SPINNING_UP; | ||
237 | 110 | engine->triggerCentral.instantRpm.spinningEventIndex = 0; | ||
238 | 110 | isSpinning = true; | ||
239 | } | |||
240 | // update variables needed by early instant RPM calc. | |||
241 |
6/6✓ Branch 1 taken 4079 times.
✓ Branch 2 taken 30792 times.
✓ Branch 4 taken 2737 times.
✓ Branch 5 taken 1342 times.
✓ Branch 6 taken 2737 times.
✓ Branch 7 taken 32134 times.
|
2/2✓ Decision 'true' taken 2737 times.
✓ Decision 'false' taken 32134 times.
|
34871 | if (isSpinningUp() && !engine->triggerCentral.triggerState.getShaftSynchronized()) { |
242 | 2737 | engine->triggerCentral.instantRpm.setLastEventTimeForInstantRpm(nowNt); | ||
243 | } | |||
244 | } | |||
245 | ||||
246 | /** | |||
247 | * @brief Shaft position callback used by RPM calculation logic. | |||
248 | * | |||
249 | * This callback should always be the first of trigger callbacks because other callbacks depend of values | |||
250 | * updated here. | |||
251 | * This callback is invoked on interrupt thread. | |||
252 | */ | |||
253 | 31489 | void rpmShaftPositionCallback(trigger_event_e ckpSignalType, | ||
254 | uint32_t trgEventIndex, efitick_t nowNt) { | |||
255 | ||||
256 | 31489 | bool alwaysInstantRpm = engineConfiguration->alwaysInstantRpm; | ||
257 | ||||
258 | 31489 | RpmCalculator *rpmState = &engine->rpmCalculator; | ||
259 | ||||
260 |
2/2✓ Branch 0 taken 2335 times.
✓ Branch 1 taken 29154 times.
|
2/2✓ Decision 'true' taken 2335 times.
✓ Decision 'false' taken 29154 times.
|
31489 | if (trgEventIndex == 0) { |
261 |
2/2✓ Branch 1 taken 702 times.
✓ Branch 2 taken 1633 times.
|
2/2✓ Decision 'true' taken 702 times.
✓ Decision 'false' taken 1633 times.
|
2335 | if (HAVE_CAM_INPUT()) { |
262 | 702 | engine->triggerCentral.validateCamVvtCounters(); | ||
263 | } | |||
264 | ||||
265 | ||||
266 | 2335 | bool hadRpmRecently = rpmState->checkIfSpinning(nowNt); | ||
267 | ||||
268 | 2335 | float periodSeconds = engine->rpmCalculator.lastTdcTimer.getElapsedSecondsAndReset(nowNt); | ||
269 | ||||
270 |
2/2✓ Branch 0 taken 2168 times.
✓ Branch 1 taken 167 times.
|
2/2✓ Decision 'true' taken 2168 times.
✓ Decision 'false' taken 167 times.
|
2335 | if (hadRpmRecently) { |
271 | /** | |||
272 | * Four stroke cycle is two crankshaft revolutions | |||
273 | * | |||
274 | * We always do '* 2' because the event signal is already adjusted to 'per engine cycle' | |||
275 | * and each revolution of crankshaft consists of two engine cycles revolutions | |||
276 | * | |||
277 | */ | |||
278 |
2/2✓ Branch 0 taken 1428 times.
✓ Branch 1 taken 740 times.
|
2/2✓ Decision 'true' taken 1428 times.
✓ Decision 'false' taken 740 times.
|
2168 | if (!alwaysInstantRpm) { |
279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1428 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1428 times.
|
1428 | if (periodSeconds == 0) { |
280 | ✗ | rpmState->setRpmValue(0); | ||
281 | ✗ | rpmState->rpmRate = 0; | ||
282 | } else { | |||
283 | // todo: extract utility method? see duplication with high_pressure_pump.cpp | |||
284 | 1428 | int mult = (int)getEngineCycle(getEngineRotationState()->getOperationMode()) / 360; | ||
285 | 1428 | float rpm = 60 * mult / periodSeconds; | ||
286 | ||||
287 | 1428 | auto rpmDelta = rpm - rpmState->previousRpmValue; | ||
288 | 1428 | rpmState->rpmRate = rpmDelta / (mult * periodSeconds); | ||
289 | ||||
290 | 1428 | rpmState->setRpmValue(rpm); | ||
291 | } | |||
292 | } | |||
293 | } else { | |||
294 | // we are here only once trigger is synchronized for the first time | |||
295 | // while transitioning from 'spinning' to 'running' | |||
296 | 167 | engine->triggerCentral.instantRpm.movePreSynchTimestamps(); | ||
297 | } | |||
298 | ||||
299 | 2335 | rpmState->onNewEngineCycle(); | ||
300 | } | |||
301 | ||||
302 | ||||
303 | // Always update instant RPM even when not spinning up | |||
304 | 31489 | engine->triggerCentral.instantRpm.updateInstantRpm( | ||
305 | engine->triggerCentral.triggerState.currentCycle.current_index, | |||
306 | ||||
307 | 31489 | engine->triggerCentral.triggerShape, &engine->triggerCentral.triggerFormDetails, | ||
308 | trgEventIndex, nowNt); | |||
309 | ||||
310 | 31489 | float instantRpm = engine->triggerCentral.instantRpm.getInstantRpm(); | ||
311 |
2/2✓ Branch 0 taken 20402 times.
✓ Branch 1 taken 11087 times.
|
2/2✓ Decision 'true' taken 20402 times.
✓ Decision 'false' taken 11087 times.
|
31489 | if (alwaysInstantRpm) { |
312 | 20402 | rpmState->setRpmValue(instantRpm); | ||
313 |
2/2✓ Branch 1 taken 1260 times.
✓ Branch 2 taken 9827 times.
|
2/2✓ Decision 'true' taken 1260 times.
✓ Decision 'false' taken 9827 times.
|
11087 | } else if (rpmState->isSpinningUp()) { |
314 | 1260 | rpmState->assignRpmValue(instantRpm); | ||
315 | #if 0 | |||
316 | efiPrintf("** RPM: idx=%d sig=%d iRPM=%d", trgEventIndex, ckpSignalType, instantRpm); | |||
317 | #else | |||
318 | UNUSED(ckpSignalType); | |||
319 | #endif | |||
320 | } | |||
321 | 31489 | } | ||
322 | ||||
323 | 12 | float RpmCalculator::getSecondsSinceEngineStart(efitick_t nowNt) const { | ||
324 | 12 | return engineStartTimer.getElapsedSeconds(nowNt); | ||
325 | } | |||
326 | ||||
327 | ||||
328 | /** | |||
329 | * This callback has nothing to do with actual engine control, it just sends a Top Dead Center mark to the rusEfi console | |||
330 | * digital sniffer. | |||
331 | */ | |||
332 | 1503 | static void onTdcCallback() { | ||
333 | #if EFI_UNIT_TEST | |||
334 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1503 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1503 times.
|
1503 | if (!engine->needTdcCallback) { |
335 | ✗ | return; | ||
336 | } | |||
337 | #endif /* EFI_UNIT_TEST */ | |||
338 | ||||
339 | 1503 | float rpm = Sensor::getOrZero(SensorType::Rpm); | ||
340 | 1503 | addEngineSnifferTdcEvent(rpm); | ||
341 | #if EFI_TOOTH_LOGGER | |||
342 | 1503 | LogTriggerTopDeadCenter(getTimeNowNt()); | ||
343 | #endif /* EFI_TOOTH_LOGGER */ | |||
344 | } | |||
345 | ||||
346 | /** | |||
347 | * This trigger callback schedules the actual physical TDC callback in relation to trigger synchronization point. | |||
348 | */ | |||
349 | 31489 | void tdcMarkCallback( | ||
350 | uint32_t trgEventIndex, efitick_t nowNt) { | |||
351 | 31489 | bool isTriggerSynchronizationPoint = trgEventIndex == 0; | ||
352 |
5/6✓ Branch 0 taken 2335 times.
✓ Branch 1 taken 29154 times.
✓ Branch 3 taken 2335 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2335 times.
✓ Branch 6 taken 29154 times.
|
2/2✓ Decision 'true' taken 2335 times.
✓ Decision 'false' taken 29154 times.
|
31489 | if (isTriggerSynchronizationPoint && getTriggerCentral()->isEngineSnifferEnabled) { |
353 | ||||
354 | #if EFI_UNIT_TEST | |||
355 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 2275 times.
|
2/2✓ Decision 'true' taken 60 times.
✓ Decision 'false' taken 2275 times.
|
2335 | if (!engine->tdcMarkEnabled) { |
356 | 60 | return; | ||
357 | } | |||
358 | #endif // EFI_UNIT_TEST | |||
359 | ||||
360 | ||||
361 | // two instances of scheduling_s are needed to properly handle event overlap | |||
362 | 2275 | int revIndex2 = getRevolutionCounter() % 2; | ||
363 | 2275 | float rpm = Sensor::getOrZero(SensorType::Rpm); | ||
364 | // todo: use tooth event-based scheduling, not just time-based scheduling | |||
365 |
2/2✓ Branch 0 taken 2200 times.
✓ Branch 1 taken 75 times.
|
2/2✓ Decision 'true' taken 2200 times.
✓ Decision 'false' taken 75 times.
|
2275 | if (rpm != 0) { |
366 |
3/3✓ Branch 2 taken 2200 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 2183 times.
|
2200 | angle_t tdcPosition = tdcPosition(); | |
367 | // we need a positive angle offset here | |||
368 |
1/1✓ Branch 1 taken 2200 times.
|
2200 | wrapAngle(tdcPosition, "tdcPosition", ObdCode::CUSTOM_ERR_6553); | |
369 |
1/1✓ Branch 4 taken 2200 times.
|
2200 | scheduleByAngle(&engine->tdcScheduler[revIndex2], nowNt, tdcPosition, action_s::make<onTdcCallback>()); | |
370 | } | |||
371 | } | |||
372 | } | |||
373 | ||||
374 | /** | |||
375 | * Schedules a callback 'angle' degree of crankshaft from now. | |||
376 | * The callback would be executed once after the duration of time which | |||
377 | * it takes the crankshaft to rotate to the specified angle. | |||
378 | * | |||
379 | * @return tick time of scheduled action | |||
380 | */ | |||
381 | 21406 | efitick_t scheduleByAngle(scheduling_s *timer, efitick_t nowNt, angle_t angle, action_s const& action) { | ||
382 | 21406 | float delayUs = engine->rpmCalculator.oneDegreeUs * angle; | ||
383 | ||||
384 | 21406 | efitick_t actionTimeNt = sumTickAndFloat(nowNt, USF2NT(delayUs)); | ||
385 | ||||
386 | 21406 | engine->scheduler.schedule("angle", timer, actionTimeNt, action); | ||
387 | ||||
388 | 21406 | return actionTimeNt; | ||
389 | } | |||
390 | ||||
391 | #else | |||
392 | RpmCalculator::RpmCalculator() : | |||
393 | StoredValueSensor(SensorType::Rpm, 0) | |||
394 | { | |||
395 | ||||
396 | } | |||
397 | ||||
398 | #endif /* EFI_SHAFT_POSITION_INPUT */ | |||
399 | ||||
400 |