| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | /** | |||
| 2 | * @file main_trigger_callback.cpp | |||
| 3 | * @brief Main logic is here! | |||
| 4 | * | |||
| 5 | * See http://rusefi.com/docs/html/ | |||
| 6 | * | |||
| 7 | * @date Feb 7, 2013 | |||
| 8 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
| 9 | * | |||
| 10 | * This file is part of rusEfi - see http://rusefi.com | |||
| 11 | * | |||
| 12 | * rusEfi is free software; you can redistribute it and/or modify it under the terms of | |||
| 13 | * the GNU General Public License as published by the Free Software Foundation; either | |||
| 14 | * version 3 of the License, or (at your option) any later version. | |||
| 15 | * | |||
| 16 | * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without | |||
| 17 | * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 18 | * GNU General Public License for more details. | |||
| 19 | * | |||
| 20 | * You should have received a copy of the GNU General Public License along with this program. | |||
| 21 | * If not, see <http://www.gnu.org/licenses/>. | |||
| 22 | */ | |||
| 23 | ||||
| 24 | #include "pch.h" | |||
| 25 | ||||
| 26 | #if EFI_PRINTF_FUEL_DETAILS | |||
| 27 | bool printFuelDebug = false; | |||
| 28 | #endif // EFI_PRINTF_FUEL_DETAILS | |||
| 29 | ||||
| 30 | #if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT | |||
| 31 | ||||
| 32 | #include "main_trigger_callback.h" | |||
| 33 | #include "trigger_central.h" | |||
| 34 | #include "spark_logic.h" | |||
| 35 | #include "advance_map.h" | |||
| 36 | #include "cyclic_buffer.h" | |||
| 37 | #include "fuel_math.h" | |||
| 38 | #include "cdm_ion_sense.h" | |||
| 39 | #include "local_version_holder.h" | |||
| 40 | #include "event_queue.h" | |||
| 41 | #include "injector_model.h" | |||
| 42 | #include "injection_gpio.h" | |||
| 43 | ||||
| 44 | #if EFI_LAUNCH_CONTROL | |||
| 45 | #include "launch_control.h" | |||
| 46 | #endif // EFI_LAUNCH_CONTROL | |||
| 47 | ||||
| 48 | #include "backup_ram.h" | |||
| 49 | ||||
| 50 | 656 | void endSimultaneousInjection(InjectionEvent* event) { | ||
| 51 | 656 | endSimultaneousInjectionOnlyTogglePins(); | ||
| 52 | 656 | event->update(); | ||
| 53 | 656 | } | ||
| 54 | ||||
| 55 | 673 | void turnInjectionPinLow(InjectionEvent *event) { | ||
| 56 | 673 | efitick_t nowNt = getTimeNowNt(); | ||
| 57 | ||||
| 58 |
2/2✓ Branch 1 taken 1346 times.
✓ Branch 2 taken 673 times.
|
2/2✓ Decision 'true' taken 1346 times.
✓ Decision 'false' taken 673 times.
|
2019 | for (size_t i = 0; i < efi::size(event->outputs); i++) { |
| 59 | 1346 | InjectorOutputPin *output = event->outputs[i]; | ||
| 60 |
2/2✓ Branch 0 taken 877 times.
✓ Branch 1 taken 469 times.
|
2/2✓ Decision 'true' taken 877 times.
✓ Decision 'false' taken 469 times.
|
1346 | if (output) { |
| 61 | 877 | output->close(nowNt); | ||
| 62 | } | |||
| 63 | } | |||
| 64 | 673 | event->update(); | ||
| 65 | 673 | } | ||
| 66 | ||||
| 67 | ✗ | static void turnInjectionPinLowStage2(InjectionEvent* event) { | ||
| 68 | ✗ | efitick_t nowNt = getTimeNowNt(); | ||
| 69 | ||||
| 70 | ✗ | for (size_t i = 0; i < efi::size(event->outputsStage2); i++) { | ||
| 71 | ✗ | InjectorOutputPin *output = event->outputsStage2[i]; | ||
| 72 | ✗ | if (output) { | ||
| 73 | ✗ | output->close(nowNt); | ||
| 74 | } | |||
| 75 | } | |||
| 76 | ✗ | } | ||
| 77 | ||||
| 78 | 121243 | void InjectionEvent::onTriggerTooth(efitick_t nowNt, float currentPhase, float nextPhase) { | ||
| 79 | 121243 | auto eventAngle = injectionStartAngle; | ||
| 80 | ||||
| 81 | // Determine whether our angle is going to happen before (or near) the next tooth | |||
| 82 |
3/3✓ Branch 1 taken 121243 times.
✓ Branch 3 taken 111950 times.
✓ Branch 4 taken 9293 times.
|
2/2✓ Decision 'true' taken 111950 times.
✓ Decision 'false' taken 9293 times.
|
121243 | if (!isPhaseInRange(eventAngle, currentPhase, nextPhase)) { |
| 83 | 111950 | return; | ||
| 84 | } | |||
| 85 | ||||
| 86 | // Select fuel mass from the correct cylinder | |||
| 87 |
1/1✓ Branch 1 taken 9293 times.
|
9293 | auto injectionMassGrams = getEngineState()->injectionMass[this->cylinderNumber]; | |
| 88 | ||||
| 89 | // Perform wall wetting adjustment on fuel mass, not duration, so that | |||
| 90 | // it's correct during fuel pressure (injector flow) or battery voltage (deadtime) transients | |||
| 91 | // TODO: is it correct to wall wet on both pulses? | |||
| 92 |
1/1✓ Branch 1 taken 9293 times.
|
9293 | injectionMassGrams = wallFuel.adjust(injectionMassGrams); | |
| 93 | ||||
| 94 | // Disable staging in simultaneous mode | |||
| 95 |
3/3✓ Branch 0 taken 987 times.
✓ Branch 1 taken 8306 times.
✓ Branch 3 taken 8306 times.
|
9293 | float stage2Fraction = isSimultaneous ? 0 : getEngineState()->injectionStage2Fraction; | |
| 96 | ||||
| 97 | // Compute fraction of fuel on stage 2, remainder goes on stage 1 | |||
| 98 | 9293 | const float injectionMassStage2 = stage2Fraction * injectionMassGrams; | ||
| 99 | 9293 | float injectionMassStage1 = injectionMassGrams - injectionMassStage2; | ||
| 100 | ||||
| 101 | #if EFI_VEHICLE_SPEED | |||
| 102 | { | |||
| 103 | // Log this fuel as consumed | |||
| 104 | ||||
| 105 |
2/2✓ Branch 1 taken 9293 times.
✓ Branch 4 taken 9293 times.
|
9293 | bool isCranking = getEngineRotationState()->isCranking(); | |
| 106 |
4/4✓ Branch 0 taken 992 times.
✓ Branch 1 taken 8301 times.
✓ Branch 3 taken 992 times.
✓ Branch 6 taken 8301 times.
|
9293 | int numberOfInjections = isCranking ? getNumberOfInjections(engineConfiguration->crankingInjectionMode) : getNumberOfInjections(engineConfiguration->injectionMode); | |
| 107 | ||||
| 108 | 9293 | float actualInjectedMass = numberOfInjections * (injectionMassStage1 + injectionMassStage2); | ||
| 109 | ||||
| 110 | #ifdef MODULE_ODOMETER | |||
| 111 |
2/2✓ Branch 1 taken 9293 times.
✓ Branch 5 taken 9293 times.
|
9293 | engine->module<TripOdometer>()->consumeFuel(actualInjectedMass, nowNt); | |
| 112 | #endif // MODULE_ODOMETER | |||
| 113 | ||||
| 114 | } | |||
| 115 | #endif // EFI_VEHICLE_SPEED | |||
| 116 | ||||
| 117 |
2/2✓ Branch 1 taken 9293 times.
✓ Branch 5 taken 9293 times.
|
9293 | const floatms_t injectionDurationStage1 = engine->module<InjectorModelPrimary>()->getInjectionDuration(injectionMassStage1); | |
| 118 |
4/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 9292 times.
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
|
9293 | const floatms_t injectionDurationStage2 = injectionMassStage2 > 0 ? engine->module<InjectorModelSecondary>()->getInjectionDuration(injectionMassStage2) : 0; | |
| 119 | ||||
| 120 | #if EFI_PRINTF_FUEL_DETAILS | |||
| 121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9293 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 9293 times.
|
9293 | if (printFuelDebug) { |
| 122 | ✗ | printf("fuel injectionDuration=%.2fms adjusted=%.2fms\n", | ||
| 123 | ✗ | getEngineState()->injectionDuration, | ||
| 124 | injectionDurationStage1); | |||
| 125 | } | |||
| 126 | #endif /*EFI_PRINTF_FUEL_DETAILS */ | |||
| 127 | ||||
| 128 |
2/2✓ Branch 0 taken 3070 times.
✓ Branch 1 taken 6223 times.
|
2/2✓ Decision 'true' taken 3070 times.
✓ Decision 'false' taken 6223 times.
|
9293 | if (this->cylinderNumber == 0) { |
| 129 |
2/2✓ Branch 1 taken 893 times.
✓ Branch 2 taken 2177 times.
|
2/2✓ Decision 'true' taken 893 times.
✓ Decision 'false' taken 2177 times.
|
3070 | if (engine->outputChannels.actualLastInjection) { |
| 130 | 893 | engine->outputChannels.actualLastInjectionRatio = injectionDurationStage1 / engine->outputChannels.actualLastInjection; | ||
| 131 | } else { | |||
| 132 | 2177 | engine->outputChannels.actualLastInjectionRatio = 0; | ||
| 133 | } | |||
| 134 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3070 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3070 times.
|
3070 | if (engine->outputChannels.actualLastInjectionStage2) { |
| 135 | ✗ | engine->outputChannels.actualLastInjectionRatioStage2 = injectionDurationStage2 / engine->outputChannels.actualLastInjectionStage2; | ||
| 136 | } else { | |||
| 137 | 3070 | engine->outputChannels.actualLastInjectionRatioStage2 = 0; | ||
| 138 | } | |||
| 139 | 3070 | engine->outputChannels.actualLastInjection = injectionDurationStage1; | ||
| 140 | 3070 | engine->outputChannels.actualLastInjectionStage2 = injectionDurationStage2; | ||
| 141 | } | |||
| 142 | ||||
| 143 |
3/6✓ Branch 1 taken 9293 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9293 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9293 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 9293 times.
|
9293 | if (std::isnan(injectionDurationStage1) || std::isnan(injectionDurationStage2)) { |
| 144 | ✗ | warning(ObdCode::CUSTOM_OBD_NAN_INJECTION, "NaN injection pulse"); | ||
| 145 | ✗ | return; | ||
| 146 | } | |||
| 147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9293 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 9293 times.
|
9293 | if (injectionDurationStage1 < 0) { |
| 148 | ✗ | warning(ObdCode::CUSTOM_OBD_NEG_INJECTION, "Negative injection pulse %.2f", injectionDurationStage1); | ||
| 149 | ✗ | return; | ||
| 150 | } | |||
| 151 | ||||
| 152 | // If somebody commanded an impossibly short injection, do nothing. | |||
| 153 | // Durations under 50us-ish aren't safe for the scheduler | |||
| 154 | // as their order may be swapped, resulting in a stuck open injector | |||
| 155 | // see https://github.com/rusefi/rusefi/pull/596 for more details | |||
| 156 |
2/2✓ Branch 0 taken 7747 times.
✓ Branch 1 taken 1546 times.
|
2/2✓ Decision 'true' taken 7747 times.
✓ Decision 'false' taken 1546 times.
|
9293 | if (injectionDurationStage1 < 0.050f) |
| 157 | { | |||
| 158 | #if EFI_PROD_CODE | |||
| 159 | warning(ObdCode::CUSTOM_OBD_impossibly_short_INJECTION, "Short pulse %.2f", injectionDurationStage1); | |||
| 160 | #endif | |||
| 161 | 7747 | return; | ||
| 162 | } | |||
| 163 | ||||
| 164 | 1546 | floatus_t durationUsStage1 = MS2US(injectionDurationStage1); | ||
| 165 | 1546 | floatus_t durationUsStage2 = MS2US(injectionDurationStage2); | ||
| 166 | ||||
| 167 | // Only bother with the second stage if it's long enough to be relevant | |||
| 168 | 1546 | bool hasStage2Injection = durationUsStage2 > 50; | ||
| 169 | ||||
| 170 | #if EFI_PRINTF_FUEL_DETAILS | |||
| 171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1546 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1546 times.
|
1546 | if (printFuelDebug) { |
| 172 | ✗ | InjectorOutputPin *output = outputs[0]; | ||
| 173 | ✗ | printf("handleFuelInjectionEvent fuelout %s injection_duration %dus engineCycleDuration=%.1fms\t\n", output->getName(), (int)durationUsStage1, | ||
| 174 | ✗ | (int)MS2US(getCrankshaftRevolutionTimeMs(Sensor::getOrZero(SensorType::Rpm))) / 1000.0); | ||
| 175 | } | |||
| 176 | #endif /*EFI_PRINTF_FUEL_DETAILS */ | |||
| 177 | ||||
| 178 | 1546 | action_s startAction, endActionStage1, endActionStage2; | ||
| 179 | // We use different callbacks based on whether we're running sequential mode or not - everything else is the same | |||
| 180 |
2/2✓ Branch 0 taken 745 times.
✓ Branch 1 taken 801 times.
|
2/2✓ Decision 'true' taken 745 times.
✓ Decision 'false' taken 801 times.
|
1546 | if (isSimultaneous) { |
| 181 | 745 | startAction = action_s::make<startSimultaneousInjection>(); | ||
| 182 | 745 | endActionStage1 = action_s::make<endSimultaneousInjection>(this); | ||
| 183 | } else { | |||
| 184 | 801 | auto const taggedPointer{TaggedPointer<decltype(this)>::make(this, hasStage2Injection)}; | ||
| 185 | ||||
| 186 | // sequential or batch | |||
| 187 | 801 | startAction = action_s::make<turnInjectionPinHigh>( taggedPointer.getRaw() ); | ||
| 188 | 801 | endActionStage1 = action_s::make<turnInjectionPinLow>( this ); | ||
| 189 | 801 | endActionStage2 = action_s::make<turnInjectionPinLowStage2>( this ); | ||
| 190 | } | |||
| 191 | ||||
| 192 | // Correctly wrap injection start angle | |||
| 193 | 1546 | float angleFromNow = eventAngle - currentPhase; | ||
| 194 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1544 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1544 times.
|
1546 | if (angleFromNow < 0) { |
| 195 |
1/1✓ Branch 1 taken 2 times.
|
2 | angleFromNow += getEngineState()->engineCycle; | |
| 196 | } | |||
| 197 | ||||
| 198 | // Schedule opening (stage 1 + stage 2 open together) | |||
| 199 |
1/1✓ Branch 1 taken 1546 times.
|
1546 | efitick_t startTime = scheduleByAngle(nullptr, nowNt, angleFromNow, startAction); | |
| 200 | ||||
| 201 | // Schedule closing stage 1 | |||
| 202 | 1546 | efitick_t turnOffTimeStage1 = startTime + US2NT((int)durationUsStage1); | ||
| 203 |
2/2✓ Branch 1 taken 1546 times.
✓ Branch 4 taken 1546 times.
|
1546 | getScheduler()->schedule("inj", nullptr, turnOffTimeStage1, endActionStage1); | |
| 204 | ||||
| 205 | // Schedule closing stage 2 (if applicable) | |||
| 206 |
5/6✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1545 times.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 1545 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 1545 times.
|
1546 | if (hasStage2Injection && endActionStage2) { |
| 207 | 1 | efitick_t turnOffTimeStage2 = startTime + US2NT((int)durationUsStage2); | ||
| 208 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
|
1 | getScheduler()->schedule("inj stage 2", nullptr, turnOffTimeStage2, endActionStage2); | |
| 209 | } | |||
| 210 | ||||
| 211 | #if EFI_DETAILED_LOGGING | |||
| 212 | printf("scheduling injection angle=%.2f/delay=%d injectionDuration=%d %d\r\n", angleFromNow, (int)NT2US(startTime - nowNt), (int)durationUsStage1, (int)durationUsStage2); | |||
| 213 | #endif | |||
| 214 | #if EFI_DETAILED_LOGGING | |||
| 215 | efiPrintf("handleFuel pin=%s eventIndex %d duration=%.2fms %d", outputs[0]->name, | |||
| 216 | injEventIndex, | |||
| 217 | injectionDurationStage1, | |||
| 218 | getRevolutionCounter()); | |||
| 219 | efiPrintf("handleFuel pin=%s delay=%.2f %d", outputs[0]->name, NT2US(startTime - nowNt), | |||
| 220 | getRevolutionCounter()); | |||
| 221 | #endif /* EFI_DETAILED_LOGGING */ | |||
| 222 | } | |||
| 223 | ||||
| 224 | 33522 | static void handleFuel(efitick_t nowNt, float currentPhase, float nextPhase) { | ||
| 225 | 33522 | ScopePerf perf(PE::HandleFuel); | ||
| 226 | ||||
| 227 | efiAssertVoid(ObdCode::CUSTOM_STACK_6627, hasLotsOfRemainingStack(), "lowstck#3"); | |||
| 228 | ||||
| 229 |
2/2✓ Branch 1 taken 33522 times.
✓ Branch 4 taken 33522 times.
|
33522 | LimpState limitedFuelState = getLimpManager()->allowInjection(); | |
| 230 | ||||
| 231 | // todo: eliminate state copy logic by giving limpManager it's owm limp_manager.txt and leveraging LiveData | |||
| 232 | 33522 | engine->outputChannels.fuelCutReason = (int8_t)limitedFuelState.reason; | ||
| 233 | 33522 | bool limitedFuel = !limitedFuelState.value; | ||
| 234 |
2/2✓ Branch 0 taken 2345 times.
✓ Branch 1 taken 31177 times.
|
2/2✓ Decision 'true' taken 2345 times.
✓ Decision 'false' taken 31177 times.
|
33522 | if (limitedFuel) { |
| 235 | 2345 | return; | ||
| 236 | } | |||
| 237 | ||||
| 238 | // This is called in the fast callback already, but since we may have just achieved engine sync (and RPM) | |||
| 239 | // for the first time, force update the schedule so that we can inject immediately if necessary | |||
| 240 |
1/1✓ Branch 1 taken 31177 times.
|
31177 | FuelSchedule *fs = getFuelSchedule(); | |
| 241 |
2/2✓ Branch 0 taken 99 times.
✓ Branch 1 taken 31078 times.
|
2/2✓ Decision 'true' taken 99 times.
✓ Decision 'false' taken 31078 times.
|
31177 | if (!fs->isReady) { |
| 242 |
1/1✓ Branch 1 taken 99 times.
|
99 | fs->addFuelEvents(); | |
| 243 | } | |||
| 244 | ||||
| 245 | #if FUEL_MATH_EXTREME_LOGGING | |||
| 246 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31177 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 31177 times.
|
31177 | if (printFuelDebug) { |
| 247 | ✗ | efiPrintf("handleFuel [%.1f, %.1f) %d", currentPhase, nextPhase, getRevolutionCounter()); | ||
| 248 | } | |||
| 249 | #endif /* FUEL_MATH_EXTREME_LOGGING */ | |||
| 250 | ||||
| 251 |
1/1✓ Branch 1 taken 31177 times.
|
31177 | fs->onTriggerTooth(nowNt, currentPhase, nextPhase); | |
| 252 | } | |||
| 253 | ||||
| 254 | /** | |||
| 255 | * This is the main trigger event handler. | |||
| 256 | * Both injection and ignition are controlled from this method. | |||
| 257 | */ | |||
| 258 | 33836 | void mainTriggerCallback(uint32_t trgEventIndex, efitick_t edgeTimestamp, angle_t currentPhase, angle_t nextPhase) { | ||
| 259 | 33836 | ScopePerf perf(PE::MainTriggerCallback); | ||
| 260 | ||||
| 261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33836 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 33836 times.
|
33836 | if (hasFirmwareError()) { |
| 262 | /** | |||
| 263 | * In case on a major error we should not process any more events. | |||
| 264 | */ | |||
| 265 | ✗ | return; | ||
| 266 | } | |||
| 267 | ||||
| 268 |
1/1✓ Branch 1 taken 33836 times.
|
33836 | float rpm = engine->rpmCalculator.getCachedRpm(); | |
| 269 |
2/2✓ Branch 0 taken 314 times.
✓ Branch 1 taken 33522 times.
|
2/2✓ Decision 'true' taken 314 times.
✓ Decision 'false' taken 33522 times.
|
33836 | if (rpm == 0) { |
| 270 | // this happens while we just start cranking | |||
| 271 | ||||
| 272 | // todo: check for 'trigger->is_synchnonized?' | |||
| 273 | 314 | return; | ||
| 274 | } | |||
| 275 | ||||
| 276 |
2/2✓ Branch 0 taken 2444 times.
✓ Branch 1 taken 31078 times.
|
2/2✓ Decision 'true' taken 2444 times.
✓ Decision 'false' taken 31078 times.
|
33522 | if (trgEventIndex == 0) { |
| 277 | ||||
| 278 |
4/4✓ Branch 1 taken 2444 times.
✓ Branch 4 taken 2444 times.
✓ Branch 6 taken 87 times.
✓ Branch 7 taken 2357 times.
|
2/2✓ Decision 'true' taken 87 times.
✓ Decision 'false' taken 2357 times.
|
2444 | if (getTriggerCentral()->checkIfTriggerConfigChanged()) { |
| 279 |
1/1✓ Branch 1 taken 87 times.
|
87 | getIgnitionEvents()->isReady = false; // we need to rebuild complete ignition schedule | |
| 280 |
1/1✓ Branch 1 taken 87 times.
|
87 | getFuelSchedule()->isReady = false; | |
| 281 | // moved 'triggerIndexByAngle' into trigger initialization (why was it invoked from here if it's only about trigger shape & optimization?) | |||
| 282 | // see updateTriggerConfiguration() -> prepareOutputSignals() | |||
| 283 | ||||
| 284 | // we need this to apply new 'triggerIndexByAngle' values | |||
| 285 |
1/1✓ Branch 1 taken 87 times.
|
87 | engine->periodicFastCallback(); | |
| 286 | } | |||
| 287 | } | |||
| 288 | ||||
| 289 | 1039182 | engine->engineModules.apply_all([=](auto & m) { | ||
| 290 | 1039182 | m.onEnginePhase(rpm, edgeTimestamp, currentPhase, nextPhase); | ||
| 291 |
2/2✓ Branch 1 taken 100566 times.
✓ Branch 5 taken 33522 times.
|
1039182 | }); | |
| 292 | ||||
| 293 | /** | |||
| 294 | * For fuel we schedule start of injection based on trigger angle, and then inject for | |||
| 295 | * specified duration of time | |||
| 296 | */ | |||
| 297 | handleFuel(edgeTimestamp, currentPhase, nextPhase); | |||
| 298 | ||||
| 299 | engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth( | |||
| 300 | rpm, edgeTimestamp, currentPhase, nextPhase); | |||
| 301 | ||||
| 302 | /** | |||
| 303 | * For spark we schedule both start of coil charge and actual spark based on trigger angle | |||
| 304 | */ | |||
| 305 | onTriggerEventSparkLogic(rpm, edgeTimestamp, currentPhase, nextPhase); | |||
| 306 | } | |||
| 307 | ||||
| 308 | #endif /* EFI_ENGINE_CONTROL */ | |||
| 309 |