firmware/controllers/engine_cycle/rpm_calculator.cpp
| 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 | 531081 | float RpmCalculator::getRpmAcceleration() const { | ||
| 28 | 531081 | return rpmRate; | ||
| 29 | } | |||
| 30 | ||||
| 31 | 38357 | 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 37084 times.
✓ Branch 1 taken 1273 times.
✓ Branch 2 taken 4312 times.
✓ Branch 3 taken 32772 times.
✓ Branch 4 taken 2597 times.
✓ Branch 5 taken 1715 times.
|
38357 | return state == STOPPED || (state == SPINNING_UP && cachedRpmValue == 0); | |
| 34 | } | |||
| 35 | ||||
| 36 | 461357 | 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 344442 times.
✓ Branch 1 taken 116915 times.
✓ Branch 2 taken 100827 times.
✓ Branch 3 taken 243615 times.
✓ Branch 4 taken 27859 times.
✓ Branch 5 taken 72968 times.
|
461357 | return state == CRANKING || (state == SPINNING_UP && cachedRpmValue > 0); | |
| 39 | } | |||
| 40 | ||||
| 41 | 169291 | bool RpmCalculator::isSpinningUp() const { | ||
| 42 | 169291 | return state == SPINNING_UP; | ||
| 43 | } | |||
| 44 | ||||
| 45 | 742868 | uint32_t RpmCalculator::getRevolutionCounterSinceStart(void) const { | ||
| 46 | 742868 | return revolutionCounterSinceStart; | ||
| 47 | } | |||
| 48 | ||||
| 49 | 66906 | float RpmCalculator::getCachedRpm() const { | ||
| 50 | 66906 | return cachedRpmValue; | ||
| 51 | } | |||
| 52 | ||||
| 53 | 24287 | float RpmCalculator::getMinCrankingRpm() const { | ||
| 54 | 24287 | return minCrankingRpm; | ||
| 55 | } | |||
| 56 | ||||
| 57 | 202342 | operation_mode_e lookupOperationMode() { | ||
| 58 |
2/2✓ Branch 0 taken 16879 times.
✓ Branch 1 taken 185463 times.
|
2/2✓ Decision 'true' taken 16879 times.
✓ Decision 'false' taken 185463 times.
|
202342 | if (engineConfiguration->twoStroke) { |
| 59 | 16879 | return TWO_STROKE; | ||
| 60 | } else { | |||
| 61 |
2/2✓ Branch 0 taken 143793 times.
✓ Branch 1 taken 41670 times.
|
185463 | return engineConfiguration->skippedWheelOnCam ? FOUR_STROKE_CAM_SENSOR : FOUR_STROKE_CRANK_SENSOR; | |
| 62 | } | |||
| 63 | } | |||
| 64 | ||||
| 65 | #if EFI_SHAFT_POSITION_INPUT | |||
| 66 | // see also in TunerStudio project '[doesTriggerImplyOperationMode] tag | |||
| 67 | // this is related to 'knownOperationMode' flag | |||
| 68 | 1922522 | static bool doesTriggerImplyOperationMode(trigger_type_e type) { | ||
| 69 |
2/2✓ Branch 0 taken 201414 times.
✓ Branch 1 taken 1721108 times.
|
1922522 | switch (type) { | |
| 70 |
1/1✓ Decision 'true' taken 201414 times.
|
201414 | case trigger_type_e::TT_TOOTHED_WHEEL: | |
| 71 | case trigger_type_e::TT_HALF_MOON: | |||
| 72 | case trigger_type_e::TT_3_1_CAM: // huh why is this trigger with CAM suffix right in the name on this exception list?! | |||
| 73 | case trigger_type_e::TT_36_2_2_2: // this trigger is special due to rotary application https://github.com/rusefi/rusefi/issues/5566 | |||
| 74 | case trigger_type_e::TT_TOOTHED_WHEEL_60_2: | |||
| 75 | case trigger_type_e::TT_TOOTHED_WHEEL_36_1: | |||
| 76 | // These modes could be either cam or crank speed | |||
| 77 |
1/1✓ Decision 'true' taken 201414 times.
|
201414 | return false; | |
| 78 |
1/1✓ Decision 'true' taken 1721108 times.
|
1721108 | default: | |
| 79 | 1721108 | return true; | ||
| 80 | } | |||
| 81 | } | |||
| 82 | #endif // EFI_SHAFT_POSITION_INPUT | |||
| 83 | ||||
| 84 | // todo: move to triggerCentral/triggerShape since has nothing to do with rotation state! | |||
| 85 | 1922522 | operation_mode_e RpmCalculator::getOperationMode() const { | ||
| 86 | #if EFI_SHAFT_POSITION_INPUT | |||
| 87 | // Ignore user-provided setting for well known triggers. | |||
| 88 |
2/2✓ Branch 1 taken 1721108 times.
✓ Branch 2 taken 201414 times.
|
2/2✓ Decision 'true' taken 1721108 times.
✓ Decision 'false' taken 201414 times.
|
1922522 | if (doesTriggerImplyOperationMode(engineConfiguration->trigger.type)) { |
| 89 | // For example for Miata NA, there is no reason to allow user to set FOUR_STROKE_CRANK_SENSOR | |||
| 90 | 1721108 | return engine->triggerCentral.triggerShape.getWheelOperationMode(); | ||
| 91 | } else | |||
| 92 | #endif // EFI_SHAFT_POSITION_INPUT | |||
| 93 | { | |||
| 94 | // For example 36-1, could be on either cam or crank, so we have to ask the user | |||
| 95 | 201414 | return lookupOperationMode(); | ||
| 96 | } | |||
| 97 | } | |||
| 98 | ||||
| 99 | ||||
| 100 | #if EFI_SHAFT_POSITION_INPUT | |||
| 101 | ||||
| 102 | 696 | RpmCalculator::RpmCalculator() : | ||
| 103 | 696 | StoredValueSensor(SensorType::Rpm, 0) | ||
| 104 | { | |||
| 105 | 696 | assignRpmValue(0); | ||
| 106 | 696 | } | ||
| 107 | ||||
| 108 | /** | |||
| 109 | * @return true if there was a full shaft revolution within the last second | |||
| 110 | */ | |||
| 111 | 276857 | bool RpmCalculator::isRunning() const { | ||
| 112 | 276857 | return state == RUNNING; | ||
| 113 | } | |||
| 114 | ||||
| 115 | /** | |||
| 116 | * @return true if engine is spinning (cranking or running) | |||
| 117 | */ | |||
| 118 | 2538 | bool RpmCalculator::checkIfSpinning(efitick_t nowNt) const { | ||
| 119 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2538 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2538 times.
|
2538 | if (getLimpManager()->shutdownController.isEngineStop(nowNt)) { |
| 120 | ✗ | return false; | ||
| 121 | } | |||
| 122 | ||||
| 123 | // Anything below 60 rpm is not running | |||
| 124 | 2538 | bool noRpmEventsForTooLong = lastTdcTimer.getElapsedSeconds(nowNt) > NO_RPM_EVENTS_TIMEOUT_SECS; | ||
| 125 | ||||
| 126 | /** | |||
| 127 | * Also check if there were no trigger events | |||
| 128 | */ | |||
| 129 | 2538 | bool noTriggerEventsForTooLong = !engine->triggerCentral.engineMovedRecently(nowNt); | ||
| 130 | ||||
| 131 |
3/4✓ Branch 0 taken 2370 times.
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2370 times.
|
2/2✓ Decision 'true' taken 168 times.
✓ Decision 'false' taken 2370 times.
|
2538 | if (noRpmEventsForTooLong || noTriggerEventsForTooLong) { |
| 132 | 168 | return false; | ||
| 133 | } | |||
| 134 | ||||
| 135 | 2370 | return true; | ||
| 136 | } | |||
| 137 | ||||
| 138 | 26129 | void RpmCalculator::assignRpmValue(float floatRpmValue) { | ||
| 139 | 26129 | previousRpmValue = cachedRpmValue; | ||
| 140 | ||||
| 141 | 26129 | cachedRpmValue = floatRpmValue; | ||
| 142 | ||||
| 143 | 26129 | setValidValue(floatRpmValue, 0); // 0 for current time since RPM sensor never times out | ||
| 144 |
2/2✓ Branch 0 taken 915 times.
✓ Branch 1 taken 25214 times.
|
2/2✓ Decision 'true' taken 915 times.
✓ Decision 'false' taken 25214 times.
|
26129 | if (cachedRpmValue <= 0) { |
| 145 | 915 | oneDegreeUs = NAN; | ||
| 146 | } else { | |||
| 147 | // here it's really important to have more precise float RPM value, see #796 | |||
| 148 | 25214 | oneDegreeUs = getOneDegreeTimeUs(floatRpmValue); | ||
| 149 |
2/2✓ Branch 0 taken 193 times.
✓ Branch 1 taken 25021 times.
|
2/2✓ Decision 'true' taken 193 times.
✓ Decision 'false' taken 25021 times.
|
25214 | if (previousRpmValue == 0) { |
| 150 | /** | |||
| 151 | * this would make sure that we have good numbers for first cranking revolution | |||
| 152 | * #275 cranking could be improved | |||
| 153 | */ | |||
| 154 | 193 | engine->periodicFastCallback(); | ||
| 155 | } | |||
| 156 | } | |||
| 157 | 26129 | } | ||
| 158 | ||||
| 159 | 24237 | void RpmCalculator::setRpmValue(float value) { | ||
| 160 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24235 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 24235 times.
|
24237 | if (value > MAX_ALLOWED_RPM) { |
| 161 | 2 | value = 0; | ||
| 162 | } | |||
| 163 | ||||
| 164 | 24237 | assignRpmValue(value); | ||
| 165 | 24237 | spinning_state_e oldState = state; | ||
| 166 | // Change state | |||
| 167 |
2/2✓ Branch 0 taken 167 times.
✓ Branch 1 taken 24070 times.
|
2/2✓ Decision 'true' taken 167 times.
✓ Decision 'false' taken 24070 times.
|
24237 | if (cachedRpmValue == 0) { |
| 168 | // Reset minCrankingRpm between attempts | |||
| 169 | 167 | minCrankingRpm = 0; | ||
| 170 | 167 | state = STOPPED; | ||
| 171 |
2/2✓ Branch 0 taken 19393 times.
✓ Branch 1 taken 4677 times.
|
2/2✓ Decision 'true' taken 19393 times.
✓ Decision 'false' taken 4677 times.
|
24070 | } else if (cachedRpmValue >= engineConfiguration->cranking.rpm) { |
| 172 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 19273 times.
|
2/2✓ Decision 'true' taken 120 times.
✓ Decision 'false' taken 19273 times.
|
19393 | if (state != RUNNING) { |
| 173 | // Store the time the engine started | |||
| 174 | 120 | engineStartTimer.reset(); | ||
| 175 | } | |||
| 176 | ||||
| 177 | 19393 | state = RUNNING; | ||
| 178 |
4/4✓ Branch 0 taken 4640 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 4597 times.
|
2/2✓ Decision 'true' taken 80 times.
✓ Decision 'false' taken 4597 times.
|
4677 | } else if (state == STOPPED || state == SPINNING_UP) { |
| 179 | /** | |||
| 180 | * We are here if RPM is above zero but we have not seen running RPM yet. | |||
| 181 | * This gives us cranking hysteresis - a drop of RPM during running is still running, not cranking. | |||
| 182 | */ | |||
| 183 |
4/4✓ Branch 0 taken 79 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 2 times.
|
2/2✓ Decision 'true' taken 78 times.
✓ Decision 'false' taken 2 times.
|
80 | if (value < minCrankingRpm || minCrankingRpm == 0) |
| 184 | 78 | minCrankingRpm = value; | ||
| 185 | 80 | state = CRANKING; | ||
| 186 | } | |||
| 187 | #if EFI_ENGINE_CONTROL | |||
| 188 | // This presumably fixes injection mode change for cranking-to-running transition. | |||
| 189 | // 'isSimultaneous' flag should be updated for events if injection modes differ for cranking and running. | |||
| 190 |
3/4✓ Branch 0 taken 260 times.
✓ Branch 1 taken 23977 times.
✓ Branch 2 taken 260 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 260 times.
✓ Decision 'false' taken 23977 times.
|
24237 | if (state != oldState && engineConfiguration->crankingInjectionMode != engineConfiguration->injectionMode) { |
| 191 | // Reset the state of all injectors: when we change fueling modes, we could | |||
| 192 | // immediately reschedule an injection that's currently underway. That will cause | |||
| 193 | // the injector's overlappingCounter to get out of sync with reality. As the fix, | |||
| 194 | // every injector's state is forcibly reset just before we could cause that to happen. | |||
| 195 | 260 | engine->injectionEvents.resetOverlapping(); | ||
| 196 | ||||
| 197 | // reschedule all injection events now that we've reset them | |||
| 198 | 260 | engine->injectionEvents.addFuelEvents(); | ||
| 199 | } | |||
| 200 | #endif | |||
| 201 | 24237 | } | ||
| 202 | ||||
| 203 | 8 | spinning_state_e RpmCalculator::getState() const { | ||
| 204 | 8 | return state; | ||
| 205 | } | |||
| 206 | ||||
| 207 | 3593 | void RpmCalculator::onNewEngineCycle() { | ||
| 208 | 3593 | revolutionCounterSinceBoot++; | ||
| 209 | 3593 | revolutionCounterSinceStart++; | ||
| 210 | 3593 | } | ||
| 211 | ||||
| 212 | 37377 | uint32_t RpmCalculator::getRevolutionCounterM(void) const { | ||
| 213 | 37377 | return revolutionCounterSinceBoot; | ||
| 214 | } | |||
| 215 | ||||
| 216 | ✗ | void RpmCalculator::onSlowCallback() { | ||
| 217 | // Stop the engine if it's been too long since we got a trigger event | |||
| 218 | ✗ | if (!engine->triggerCentral.engineMovedRecently(getTimeNowNt())) { | ||
| 219 | ✗ | setStopSpinning(); | ||
| 220 | } | |||
| 221 | ✗ | } | ||
| 222 | ||||
| 223 | 131 | void RpmCalculator::setStopSpinning() { | ||
| 224 | 131 | isSpinning = false; | ||
| 225 | 131 | revolutionCounterSinceStart = 0; | ||
| 226 | 131 | rpmRate = 0; | ||
| 227 | ||||
| 228 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 128 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 128 times.
|
131 | if (cachedRpmValue != 0) { |
| 229 | 3 | assignRpmValue(0); | ||
| 230 | // needed by 'useNoiselessTriggerDecoder' | |||
| 231 | 3 | engine->triggerCentral.noiseFilter.resetAccumSignalData(); | ||
| 232 | 3 | efiPrintf("engine stopped"); | ||
| 233 | } | |||
| 234 | 131 | state = STOPPED; | ||
| 235 | ||||
| 236 | 131 | engine->onEngineStopped(); | ||
| 237 | 131 | } | ||
| 238 | ||||
| 239 | 38650 | void RpmCalculator::setSpinningUp(efitick_t nowNt) { | ||
| 240 |
2/2✓ Branch 0 taken 1408 times.
✓ Branch 1 taken 37242 times.
|
2/2✓ Decision 'true' taken 1408 times.
✓ Decision 'false' taken 37242 times.
|
38650 | if (!engineConfiguration->isFasterEngineSpinUpEnabled) |
| 241 | 1408 | return; | ||
| 242 | // Only a completely stopped and non-spinning engine can enter the spinning-up state. | |||
| 243 |
6/6✓ Branch 1 taken 2829 times.
✓ Branch 2 taken 34413 times.
✓ Branch 3 taken 111 times.
✓ Branch 4 taken 2718 times.
✓ Branch 5 taken 111 times.
✓ Branch 6 taken 37131 times.
|
2/2✓ Decision 'true' taken 111 times.
✓ Decision 'false' taken 37131 times.
|
37242 | if (isStopped() && !isSpinning) { |
| 244 | 111 | state = SPINNING_UP; | ||
| 245 | 111 | engine->triggerCentral.instantRpm.spinningEventIndex = 0; | ||
| 246 | 111 | isSpinning = true; | ||
| 247 | } | |||
| 248 | // update variables needed by early instant RPM calc. | |||
| 249 |
6/6✓ Branch 1 taken 4413 times.
✓ Branch 2 taken 32829 times.
✓ Branch 4 taken 3138 times.
✓ Branch 5 taken 1275 times.
✓ Branch 6 taken 3138 times.
✓ Branch 7 taken 34104 times.
|
2/2✓ Decision 'true' taken 3138 times.
✓ Decision 'false' taken 34104 times.
|
37242 | if (isSpinningUp() && !engine->triggerCentral.triggerState.getShaftSynchronized()) { |
| 250 | 3138 | engine->triggerCentral.instantRpm.setLastEventTimeForInstantRpm(nowNt); | ||
| 251 | } | |||
| 252 | } | |||
| 253 | ||||
| 254 | /** | |||
| 255 | * @brief Shaft position callback used by RPM calculation logic. | |||
| 256 | * | |||
| 257 | * This callback should always be the first of trigger callbacks because other callbacks depend of values | |||
| 258 | * updated here. | |||
| 259 | * This callback is invoked on interrupt thread. | |||
| 260 | */ | |||
| 261 | 33453 | void rpmShaftPositionCallback(trigger_event_e ckpSignalType, | ||
| 262 | uint32_t trgEventIndex, efitick_t nowNt) { | |||
| 263 | ||||
| 264 | 33453 | bool alwaysInstantRpm = engineConfiguration->alwaysInstantRpm; | ||
| 265 | ||||
| 266 | 33453 | RpmCalculator *rpmState = &engine->rpmCalculator; | ||
| 267 | ||||
| 268 |
2/2✓ Branch 0 taken 2538 times.
✓ Branch 1 taken 30915 times.
|
2/2✓ Decision 'true' taken 2538 times.
✓ Decision 'false' taken 30915 times.
|
33453 | if (trgEventIndex == 0) { |
| 269 |
2/2✓ Branch 1 taken 702 times.
✓ Branch 2 taken 1836 times.
|
2/2✓ Decision 'true' taken 702 times.
✓ Decision 'false' taken 1836 times.
|
2538 | if (HAVE_CAM_INPUT()) { |
| 270 | 702 | engine->triggerCentral.validateCamVvtCounters(); | ||
| 271 | } | |||
| 272 | ||||
| 273 | ||||
| 274 | 2538 | bool hadRpmRecently = rpmState->checkIfSpinning(nowNt); | ||
| 275 | ||||
| 276 | 2538 | float periodSeconds = engine->rpmCalculator.lastTdcTimer.getElapsedSecondsAndReset(nowNt); | ||
| 277 | ||||
| 278 |
2/2✓ Branch 0 taken 2370 times.
✓ Branch 1 taken 168 times.
|
2/2✓ Decision 'true' taken 2370 times.
✓ Decision 'false' taken 168 times.
|
2538 | if (hadRpmRecently) { |
| 279 | /** | |||
| 280 | * Four stroke cycle is two crankshaft revolutions | |||
| 281 | * | |||
| 282 | * We always do '* 2' because the event signal is already adjusted to 'per engine cycle' | |||
| 283 | * and each revolution of crankshaft consists of two engine cycles revolutions | |||
| 284 | * | |||
| 285 | */ | |||
| 286 |
2/2✓ Branch 0 taken 1437 times.
✓ Branch 1 taken 933 times.
|
2/2✓ Decision 'true' taken 1437 times.
✓ Decision 'false' taken 933 times.
|
2370 | if (!alwaysInstantRpm) { |
| 287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1437 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1437 times.
|
1437 | if (periodSeconds == 0) { |
| 288 | ✗ | rpmState->setRpmValue(0); | ||
| 289 | ✗ | rpmState->rpmRate = 0; | ||
| 290 | } else { | |||
| 291 | // todo: extract utility method? see duplication with high_pressure_pump.cpp | |||
| 292 | 1437 | int mult = (int)getEngineCycle(getEngineRotationState()->getOperationMode()) / 360; | ||
| 293 | 1437 | float rpm = 60 * mult / periodSeconds; | ||
| 294 | ||||
| 295 | 1437 | auto rpmDelta = rpm - rpmState->previousRpmValue; | ||
| 296 | 1437 | rpmState->rpmRate = rpmDelta / (mult * periodSeconds); | ||
| 297 | ||||
| 298 | 1437 | rpmState->setRpmValue(rpm); | ||
| 299 | } | |||
| 300 | } | |||
| 301 | } else { | |||
| 302 | // we are here only once trigger is synchronized for the first time | |||
| 303 | // while transitioning from 'spinning' to 'running' | |||
| 304 | 168 | engine->triggerCentral.instantRpm.movePreSynchTimestamps(); | ||
| 305 | } | |||
| 306 | ||||
| 307 | 2538 | rpmState->onNewEngineCycle(); | ||
| 308 | } | |||
| 309 | ||||
| 310 | ||||
| 311 | // Always update instant RPM even when not spinning up | |||
| 312 | 33453 | engine->triggerCentral.instantRpm.updateInstantRpm( | ||
| 313 | engine->triggerCentral.triggerState.currentCycle.current_index, | |||
| 314 | ||||
| 315 | 33453 | engine->triggerCentral.triggerShape, &engine->triggerCentral.triggerFormDetails, | ||
| 316 | trgEventIndex, nowNt); | |||
| 317 | ||||
| 318 | 33453 | float instantRpm = engine->triggerCentral.instantRpm.getInstantRpm(); | ||
| 319 |
2/2✓ Branch 0 taken 22749 times.
✓ Branch 1 taken 10704 times.
|
2/2✓ Decision 'true' taken 22749 times.
✓ Decision 'false' taken 10704 times.
|
33453 | if (alwaysInstantRpm) { |
| 320 | 22749 | rpmState->setRpmValue(instantRpm); | ||
| 321 |
2/2✓ Branch 1 taken 1193 times.
✓ Branch 2 taken 9511 times.
|
2/2✓ Decision 'true' taken 1193 times.
✓ Decision 'false' taken 9511 times.
|
10704 | } else if (rpmState->isSpinningUp()) { |
| 322 | 1193 | rpmState->assignRpmValue(instantRpm); | ||
| 323 | #if 0 | |||
| 324 | efiPrintf("** RPM: idx=%d sig=%d iRPM=%d", trgEventIndex, ckpSignalType, instantRpm); | |||
| 325 | #else | |||
| 326 | UNUSED(ckpSignalType); | |||
| 327 | #endif | |||
| 328 | } | |||
| 329 | 33453 | } | ||
| 330 | ||||
| 331 | 12 | float RpmCalculator::getSecondsSinceEngineStart(efitick_t nowNt) const { | ||
| 332 | 12 | return engineStartTimer.getElapsedSeconds(nowNt); | ||
| 333 | } | |||
| 334 | ||||
| 335 | ||||
| 336 | /** | |||
| 337 | * This callback has nothing to do with actual engine control, it just sends a Top Dead Center mark to the rusEfi console | |||
| 338 | * digital sniffer. | |||
| 339 | */ | |||
| 340 | 1702 | static void onTdcCallback() { | ||
| 341 | #if EFI_UNIT_TEST | |||
| 342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1702 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1702 times.
|
1702 | if (!engine->needTdcCallback) { |
| 343 | ✗ | return; | ||
| 344 | } | |||
| 345 | #endif /* EFI_UNIT_TEST */ | |||
| 346 | ||||
| 347 | 1702 | float rpm = Sensor::getOrZero(SensorType::Rpm); | ||
| 348 | 1702 | addEngineSnifferTdcEvent(rpm); | ||
| 349 | #if EFI_TOOTH_LOGGER | |||
| 350 | 1702 | LogTriggerTopDeadCenter(getTimeNowNt()); | ||
| 351 | #endif /* EFI_TOOTH_LOGGER */ | |||
| 352 | } | |||
| 353 | ||||
| 354 | /** | |||
| 355 | * This trigger callback schedules the actual physical TDC callback in relation to trigger synchronization point. | |||
| 356 | */ | |||
| 357 | 33453 | void tdcMarkCallback( | ||
| 358 | uint32_t trgEventIndex, efitick_t nowNt) { | |||
| 359 | 33453 | bool isTriggerSynchronizationPoint = trgEventIndex == 0; | ||
| 360 |
5/6✓ Branch 0 taken 2538 times.
✓ Branch 1 taken 30915 times.
✓ Branch 3 taken 2538 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2538 times.
✓ Branch 6 taken 30915 times.
|
2/2✓ Decision 'true' taken 2538 times.
✓ Decision 'false' taken 30915 times.
|
33453 | if (isTriggerSynchronizationPoint && getTriggerCentral()->isEngineSnifferEnabled) { |
| 361 | ||||
| 362 | #if EFI_UNIT_TEST | |||
| 363 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 2478 times.
|
2/2✓ Decision 'true' taken 60 times.
✓ Decision 'false' taken 2478 times.
|
2538 | if (!engine->tdcMarkEnabled) { |
| 364 | 60 | return; | ||
| 365 | } | |||
| 366 | #endif // EFI_UNIT_TEST | |||
| 367 | ||||
| 368 | ||||
| 369 | // two instances of scheduling_s are needed to properly handle event overlap | |||
| 370 | 2478 | int revIndex2 = getRevolutionCounter() % 2; | ||
| 371 | 2478 | float rpm = Sensor::getOrZero(SensorType::Rpm); | ||
| 372 | // todo: use tooth event-based scheduling, not just time-based scheduling | |||
| 373 |
2/2✓ Branch 0 taken 2400 times.
✓ Branch 1 taken 78 times.
|
2/2✓ Decision 'true' taken 2400 times.
✓ Decision 'false' taken 78 times.
|
2478 | if (rpm != 0) { |
| 374 |
3/3✓ Branch 2 taken 2400 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 2383 times.
|
2400 | angle_t tdcPosition = tdcPosition(); | |
| 375 | // we need a positive angle offset here | |||
| 376 |
1/1✓ Branch 1 taken 2400 times.
|
2400 | wrapAngle(tdcPosition, "tdcPosition", ObdCode::CUSTOM_ERR_6553); | |
| 377 |
1/1✓ Branch 4 taken 2400 times.
|
2400 | scheduleByAngle(&engine->tdcScheduler[revIndex2], nowNt, tdcPosition, action_s::make<onTdcCallback>()); | |
| 378 | } | |||
| 379 | } | |||
| 380 | } | |||
| 381 | ||||
| 382 | /** | |||
| 383 | * Schedules a callback 'angle' degree of crankshaft from now. | |||
| 384 | * The callback would be executed once after the duration of time which | |||
| 385 | * it takes the crankshaft to rotate to the specified angle. | |||
| 386 | * | |||
| 387 | * @return tick time of scheduled action | |||
| 388 | */ | |||
| 389 | 22858 | efitick_t scheduleByAngle(scheduling_s *timer, efitick_t nowNt, angle_t angle, action_s const& action) { | ||
| 390 | 22858 | float delayUs = engine->rpmCalculator.oneDegreeUs * angle; | ||
| 391 | ||||
| 392 | 22858 | efitick_t actionTimeNt = sumTickAndFloat(nowNt, USF2NT(delayUs)); | ||
| 393 | ||||
| 394 | 22858 | engine->scheduler.schedule("angle", timer, actionTimeNt, action); | ||
| 395 | ||||
| 396 | 22858 | return actionTimeNt; | ||
| 397 | } | |||
| 398 | ||||
| 399 | #else | |||
| 400 | RpmCalculator::RpmCalculator() : | |||
| 401 | StoredValueSensor(SensorType::Rpm, 0) | |||
| 402 | { | |||
| 403 | ||||
| 404 | } | |||
| 405 | ||||
| 406 | #endif /* EFI_SHAFT_POSITION_INPUT */ | |||
| 407 | ||||
| 408 |