| 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 | 38319 | 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 37064 times.
✓ Branch 1 taken 1255 times.
✓ Branch 2 taken 3983 times.
✓ Branch 3 taken 33081 times.
✓ Branch 4 taken 2200 times.
✓ Branch 5 taken 1783 times.
|
38319 | return state == STOPPED || (state == SPINNING_UP && cachedRpmValue == 0); | |
| 34 | } | |||
| 35 | ||||
| 36 | 20586 | 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 18499 times.
✓ Branch 1 taken 2087 times.
✓ Branch 2 taken 1021 times.
✓ Branch 3 taken 17478 times.
✓ Branch 4 taken 988 times.
✓ Branch 5 taken 33 times.
|
20586 | return state == CRANKING || (state == SPINNING_UP && cachedRpmValue > 0); | |
| 39 | } | |||
| 40 | ||||
| 41 | 170037 | bool RpmCalculator::isSpinningUp() const { | ||
| 42 | 170037 | return state == SPINNING_UP; | ||
| 43 | } | |||
| 44 | ||||
| 45 | 533436 | uint32_t RpmCalculator::getRevolutionCounterSinceStart(void) const { | ||
| 46 | 533436 | return revolutionCounterSinceStart; | ||
| 47 | } | |||
| 48 | ||||
| 49 | 67672 | float RpmCalculator::getCachedRpm() const { | ||
| 50 | 67672 | return cachedRpmValue; | ||
| 51 | } | |||
| 52 | ||||
| 53 | 102092 | operation_mode_e lookupOperationMode() { | ||
| 54 |
2/2✓ Branch 0 taken 287 times.
✓ Branch 1 taken 101805 times.
|
2/2✓ Decision 'true' taken 287 times.
✓ Decision 'false' taken 101805 times.
|
102092 | if (engineConfiguration->twoStroke) { |
| 55 | 287 | return TWO_STROKE; | ||
| 56 | } else { | |||
| 57 |
2/2✓ Branch 0 taken 87556 times.
✓ Branch 1 taken 14249 times.
|
101805 | 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 | 1601613 | static bool doesTriggerImplyOperationMode(trigger_type_e type) { | ||
| 65 |
2/2✓ Branch 0 taken 101184 times.
✓ Branch 1 taken 1500429 times.
|
1601613 | 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 1500429 times.
|
1500429 | default: | |
| 75 | 1500429 | 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 | 1601613 | 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 1500429 times.
✓ Branch 2 taken 101184 times.
|
2/2✓ Decision 'true' taken 1500429 times.
✓ Decision 'false' taken 101184 times.
|
1601613 | 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 | 1500429 | 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 | 678 | RpmCalculator::RpmCalculator() : | ||
| 99 | 678 | StoredValueSensor(SensorType::Rpm, 0) | ||
| 100 | { | |||
| 101 | 678 | assignRpmValue(0); | ||
| 102 | 678 | } | ||
| 103 | ||||
| 104 | /** | |||
| 105 | * @return true if there was a full shaft revolution within the last second | |||
| 106 | */ | |||
| 107 | 6686 | bool RpmCalculator::isRunning() const { | ||
| 108 | 6686 | return state == RUNNING; | ||
| 109 | } | |||
| 110 | ||||
| 111 | /** | |||
| 112 | * @return true if engine is spinning (cranking or running) | |||
| 113 | */ | |||
| 114 | 2531 | bool RpmCalculator::checkIfSpinning(efitick_t nowNt) const { | ||
| 115 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2531 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2531 times.
|
2531 | if (getLimpManager()->shutdownController.isEngineStop(nowNt)) { |
| 116 | ✗ | return false; | ||
| 117 | } | |||
| 118 | ||||
| 119 | // Anything below 60 rpm is not running | |||
| 120 | 2531 | bool noRpmEventsForTooLong = lastTdcTimer.getElapsedSeconds(nowNt) > NO_RPM_EVENTS_TIMEOUT_SECS; | ||
| 121 | ||||
| 122 | /** | |||
| 123 | * Also check if there were no trigger events | |||
| 124 | */ | |||
| 125 | 2531 | bool noTriggerEventsForTooLong = !engine->triggerCentral.engineMovedRecently(nowNt); | ||
| 126 | ||||
| 127 |
3/4✓ Branch 0 taken 2361 times.
✓ Branch 1 taken 170 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2361 times.
|
2/2✓ Decision 'true' taken 170 times.
✓ Decision 'false' taken 2361 times.
|
2531 | if (noRpmEventsForTooLong || noTriggerEventsForTooLong) { |
| 128 | 170 | return false; | ||
| 129 | } | |||
| 130 | ||||
| 131 | 2361 | return true; | ||
| 132 | } | |||
| 133 | ||||
| 134 | 26165 | void RpmCalculator::assignRpmValue(float floatRpmValue) { | ||
| 135 | 26165 | previousRpmValue = cachedRpmValue; | ||
| 136 | ||||
| 137 | 26165 | cachedRpmValue = floatRpmValue; | ||
| 138 | ||||
| 139 | 26165 | setValidValue(floatRpmValue, 0); // 0 for current time since RPM sensor never times out | ||
| 140 |
2/2✓ Branch 0 taken 895 times.
✓ Branch 1 taken 25270 times.
|
2/2✓ Decision 'true' taken 895 times.
✓ Decision 'false' taken 25270 times.
|
26165 | if (cachedRpmValue <= 0) { |
| 141 | 895 | oneDegreeUs = NAN; | ||
| 142 | } else { | |||
| 143 | // here it's really important to have more precise float RPM value, see #796 | |||
| 144 | 25270 | oneDegreeUs = getOneDegreeTimeUs(floatRpmValue); | ||
| 145 |
2/2✓ Branch 0 taken 191 times.
✓ Branch 1 taken 25079 times.
|
2/2✓ Decision 'true' taken 191 times.
✓ Decision 'false' taken 25079 times.
|
25270 | 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 | 191 | engine->periodicFastCallback(); | ||
| 151 | } | |||
| 152 | } | |||
| 153 | 26165 | } | ||
| 154 | ||||
| 155 | 24224 | void RpmCalculator::setRpmValue(float value) { | ||
| 156 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24222 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 24222 times.
|
24224 | if (value > MAX_ALLOWED_RPM) { |
| 157 | 2 | value = 0; | ||
| 158 | } | |||
| 159 | ||||
| 160 | 24224 | assignRpmValue(value); | ||
| 161 | 24224 | spinning_state_e oldState = state; | ||
| 162 | // Change state | |||
| 163 |
2/2✓ Branch 0 taken 166 times.
✓ Branch 1 taken 24058 times.
|
2/2✓ Decision 'true' taken 166 times.
✓ Decision 'false' taken 24058 times.
|
24224 | if (cachedRpmValue == 0) { |
| 164 | 166 | state = STOPPED; | ||
| 165 |
2/2✓ Branch 0 taken 19373 times.
✓ Branch 1 taken 4685 times.
|
2/2✓ Decision 'true' taken 19373 times.
✓ Decision 'false' taken 4685 times.
|
24058 | } else if (cachedRpmValue >= engineConfiguration->cranking.rpm) { |
| 166 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 19255 times.
|
2/2✓ Decision 'true' taken 118 times.
✓ Decision 'false' taken 19255 times.
|
19373 | if (state != RUNNING) { |
| 167 | // Store the time the engine started | |||
| 168 | 118 | engineStartTimer.reset(); | ||
| 169 | } | |||
| 170 | ||||
| 171 | 19373 | 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 257 times.
✓ Branch 1 taken 23967 times.
✓ Branch 2 taken 257 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 257 times.
✓ Decision 'false' taken 23967 times.
|
24224 | 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 | 257 | engine->injectionEvents.resetOverlapping(); | ||
| 188 | ||||
| 189 | // reschedule all injection events now that we've reset them | |||
| 190 | 257 | engine->injectionEvents.addFuelEvents(); | ||
| 191 | } | |||
| 192 | #endif | |||
| 193 | 24224 | } | ||
| 194 | ||||
| 195 | 5 | spinning_state_e RpmCalculator::getState() const { | ||
| 196 | 5 | return state; | ||
| 197 | } | |||
| 198 | ||||
| 199 | 3586 | void RpmCalculator::onNewEngineCycle() { | ||
| 200 | 3586 | revolutionCounterSinceBoot++; | ||
| 201 | 3586 | revolutionCounterSinceStart++; | ||
| 202 | 3586 | } | ||
| 203 | ||||
| 204 | 37034 | uint32_t RpmCalculator::getRevolutionCounterM(void) const { | ||
| 205 | 37034 | 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 | 131 | void RpmCalculator::setStopSpinning() { | ||
| 216 | 131 | isSpinning = false; | ||
| 217 | 131 | revolutionCounterSinceStart = 0; | ||
| 218 | 131 | rpmRate = 0; | ||
| 219 | ||||
| 220 |
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) { |
| 221 | 3 | assignRpmValue(0); | ||
| 222 | // needed by 'useNoiselessTriggerDecoder' | |||
| 223 | 3 | engine->triggerCentral.noiseFilter.resetAccumSignalData(); | ||
| 224 | 3 | efiPrintf("engine stopped"); | ||
| 225 | } | |||
| 226 | 131 | state = STOPPED; | ||
| 227 | ||||
| 228 | 131 | engine->onEngineStopped(); | ||
| 229 | 131 | } | ||
| 230 | ||||
| 231 | 38630 | void RpmCalculator::setSpinningUp(efitick_t nowNt) { | ||
| 232 |
2/2✓ Branch 0 taken 1408 times.
✓ Branch 1 taken 37222 times.
|
2/2✓ Decision 'true' taken 1408 times.
✓ Decision 'false' taken 37222 times.
|
38630 | 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 2432 times.
✓ Branch 2 taken 34790 times.
✓ Branch 3 taken 111 times.
✓ Branch 4 taken 2321 times.
✓ Branch 5 taken 111 times.
✓ Branch 6 taken 37111 times.
|
2/2✓ Decision 'true' taken 111 times.
✓ Decision 'false' taken 37111 times.
|
37222 | if (isStopped() && !isSpinning) { |
| 236 | 111 | state = SPINNING_UP; | ||
| 237 | 111 | engine->triggerCentral.instantRpm.spinningEventIndex = 0; | ||
| 238 | 111 | isSpinning = true; | ||
| 239 | } | |||
| 240 | // update variables needed by early instant RPM calc. | |||
| 241 |
6/6✓ Branch 1 taken 4084 times.
✓ Branch 2 taken 33138 times.
✓ Branch 4 taken 2741 times.
✓ Branch 5 taken 1343 times.
✓ Branch 6 taken 2741 times.
✓ Branch 7 taken 34481 times.
|
2/2✓ Decision 'true' taken 2741 times.
✓ Decision 'false' taken 34481 times.
|
37222 | if (isSpinningUp() && !engine->triggerCentral.triggerState.getShaftSynchronized()) { |
| 242 | 2741 | 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 | 33836 | void rpmShaftPositionCallback(trigger_event_e ckpSignalType, | ||
| 254 | uint32_t trgEventIndex, efitick_t nowNt) { | |||
| 255 | ||||
| 256 | 33836 | bool alwaysInstantRpm = engineConfiguration->alwaysInstantRpm; | ||
| 257 | ||||
| 258 | 33836 | RpmCalculator *rpmState = &engine->rpmCalculator; | ||
| 259 | ||||
| 260 |
2/2✓ Branch 0 taken 2531 times.
✓ Branch 1 taken 31305 times.
|
2/2✓ Decision 'true' taken 2531 times.
✓ Decision 'false' taken 31305 times.
|
33836 | if (trgEventIndex == 0) { |
| 261 |
2/2✓ Branch 1 taken 702 times.
✓ Branch 2 taken 1829 times.
|
2/2✓ Decision 'true' taken 702 times.
✓ Decision 'false' taken 1829 times.
|
2531 | if (HAVE_CAM_INPUT()) { |
| 262 | 702 | engine->triggerCentral.validateCamVvtCounters(); | ||
| 263 | } | |||
| 264 | ||||
| 265 | ||||
| 266 | 2531 | bool hadRpmRecently = rpmState->checkIfSpinning(nowNt); | ||
| 267 | ||||
| 268 | 2531 | float periodSeconds = engine->rpmCalculator.lastTdcTimer.getElapsedSecondsAndReset(nowNt); | ||
| 269 | ||||
| 270 |
2/2✓ Branch 0 taken 2361 times.
✓ Branch 1 taken 170 times.
|
2/2✓ Decision 'true' taken 2361 times.
✓ Decision 'false' taken 170 times.
|
2531 | 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 933 times.
|
2/2✓ Decision 'true' taken 1428 times.
✓ Decision 'false' taken 933 times.
|
2361 | 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 | 170 | engine->triggerCentral.instantRpm.movePreSynchTimestamps(); | ||
| 297 | } | |||
| 298 | ||||
| 299 | 2531 | rpmState->onNewEngineCycle(); | ||
| 300 | } | |||
| 301 | ||||
| 302 | ||||
| 303 | // Always update instant RPM even when not spinning up | |||
| 304 | 33836 | engine->triggerCentral.instantRpm.updateInstantRpm( | ||
| 305 | engine->triggerCentral.triggerState.currentCycle.current_index, | |||
| 306 | ||||
| 307 | 33836 | engine->triggerCentral.triggerShape, &engine->triggerCentral.triggerFormDetails, | ||
| 308 | trgEventIndex, nowNt); | |||
| 309 | ||||
| 310 | 33836 | float instantRpm = engine->triggerCentral.instantRpm.getInstantRpm(); | ||
| 311 |
2/2✓ Branch 0 taken 22749 times.
✓ Branch 1 taken 11087 times.
|
2/2✓ Decision 'true' taken 22749 times.
✓ Decision 'false' taken 11087 times.
|
33836 | if (alwaysInstantRpm) { |
| 312 | 22749 | 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 | 33836 | } | ||
| 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 | 1696 | static void onTdcCallback() { | ||
| 333 | #if EFI_UNIT_TEST | |||
| 334 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1696 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1696 times.
|
1696 | if (!engine->needTdcCallback) { |
| 335 | ✗ | return; | ||
| 336 | } | |||
| 337 | #endif /* EFI_UNIT_TEST */ | |||
| 338 | ||||
| 339 | 1696 | float rpm = Sensor::getOrZero(SensorType::Rpm); | ||
| 340 | 1696 | addEngineSnifferTdcEvent(rpm); | ||
| 341 | #if EFI_TOOTH_LOGGER | |||
| 342 | 1696 | 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 | 33836 | void tdcMarkCallback( | ||
| 350 | uint32_t trgEventIndex, efitick_t nowNt) { | |||
| 351 | 33836 | bool isTriggerSynchronizationPoint = trgEventIndex == 0; | ||
| 352 |
5/6✓ Branch 0 taken 2531 times.
✓ Branch 1 taken 31305 times.
✓ Branch 3 taken 2531 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2531 times.
✓ Branch 6 taken 31305 times.
|
2/2✓ Decision 'true' taken 2531 times.
✓ Decision 'false' taken 31305 times.
|
33836 | if (isTriggerSynchronizationPoint && getTriggerCentral()->isEngineSnifferEnabled) { |
| 353 | ||||
| 354 | #if EFI_UNIT_TEST | |||
| 355 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 2471 times.
|
2/2✓ Decision 'true' taken 60 times.
✓ Decision 'false' taken 2471 times.
|
2531 | 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 | 2471 | int revIndex2 = getRevolutionCounter() % 2; | ||
| 363 | 2471 | float rpm = Sensor::getOrZero(SensorType::Rpm); | ||
| 364 | // todo: use tooth event-based scheduling, not just time-based scheduling | |||
| 365 |
2/2✓ Branch 0 taken 2394 times.
✓ Branch 1 taken 77 times.
|
2/2✓ Decision 'true' taken 2394 times.
✓ Decision 'false' taken 77 times.
|
2471 | if (rpm != 0) { |
| 366 |
3/3✓ Branch 2 taken 2394 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 2377 times.
|
2394 | angle_t tdcPosition = tdcPosition(); | |
| 367 | // we need a positive angle offset here | |||
| 368 |
1/1✓ Branch 1 taken 2394 times.
|
2394 | wrapAngle(tdcPosition, "tdcPosition", ObdCode::CUSTOM_ERR_6553); | |
| 369 |
1/1✓ Branch 4 taken 2394 times.
|
2394 | 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 | 22841 | efitick_t scheduleByAngle(scheduling_s *timer, efitick_t nowNt, angle_t angle, action_s const& action) { | ||
| 382 | 22841 | float delayUs = engine->rpmCalculator.oneDegreeUs * angle; | ||
| 383 | ||||
| 384 | 22841 | efitick_t actionTimeNt = sumTickAndFloat(nowNt, USF2NT(delayUs)); | ||
| 385 | ||||
| 386 | 22841 | engine->scheduler.schedule("angle", timer, actionTimeNt, action); | ||
| 387 | ||||
| 388 | 22841 | 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 |