Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /** | |||
2 | * @file ignition_state.cpp | |||
3 | * | |||
4 | * @date Mar 27, 2013 | |||
5 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
6 | * | |||
7 | * This file is part of rusEfi - see http://rusefi.com | |||
8 | * | |||
9 | * rusEfi is free software; you can redistribute it and/or modify it under the terms of | |||
10 | * the GNU General Public License as published by the Free Software Foundation; either | |||
11 | * version 3 of the License, or (at your option) any later version. | |||
12 | * | |||
13 | * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without | |||
14 | * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
15 | * GNU General Public License for more details. | |||
16 | * | |||
17 | * You should have received a copy of the GNU General Public License along with this program. | |||
18 | * If not, see <http://www.gnu.org/licenses/>. | |||
19 | */ | |||
20 | ||||
21 | #include "pch.h" | |||
22 | ||||
23 | #include "idle_thread.h" | |||
24 | #include "launch_control.h" | |||
25 | #include "gppwm_channel.h" | |||
26 | ||||
27 | #if EFI_ENGINE_CONTROL | |||
28 | ||||
29 | // TODO: wow move this into engineState at least for context not to leak from test to test! | |||
30 | // todo: reset this between cranking attempts?! #2735 | |||
31 | float minCrankingRpm = 0; | |||
32 | ||||
33 | static Map3D<TRACTION_CONTROL_ETB_DROP_SLIP_SIZE, TRACTION_CONTROL_ETB_DROP_SPEED_SIZE, int8_t, uint16_t, uint8_t> tcTimingDropTable{"tct"}; | |||
34 | static Map3D<TRACTION_CONTROL_ETB_DROP_SLIP_SIZE, TRACTION_CONTROL_ETB_DROP_SPEED_SIZE, int8_t, uint16_t, uint8_t> tcSparkSkipTable{"tcs"}; | |||
35 | ||||
36 | #if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT | |||
37 | ||||
38 | /** | |||
39 | * @return ignition timing angle advance before TDC | |||
40 | */ | |||
41 | 1105 | angle_t getRunningAdvance(float rpm, float engineLoad) { | ||
42 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1103 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1103 times.
|
1105 | if (std::isnan(engineLoad)) { |
43 | 2 | warning(ObdCode::CUSTOM_NAN_ENGINE_LOAD, "NaN engine load"); | ||
44 | 2 | return NAN; | ||
45 | } | |||
46 | ||||
47 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1103 times.
|
1103 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(engineLoad), "invalid el", NAN); | |
48 | ||||
49 | // compute base ignition angle from main table | |||
50 | 1103 | float advanceAngle = IgnitionState::getInterpolatedIgnitionAngle(rpm, engineLoad); | ||
51 | ||||
52 | 1103 | float vehicleSpeed = Sensor::getOrZero(SensorType::VehicleSpeed); | ||
53 | 1103 | float wheelSlip = Sensor::getOrZero(SensorType::WheelSlipRatio); | ||
54 |
1/1✓ Branch 2 taken 1103 times.
|
1103 | engine->ignitionState.tractionAdvanceDrop = tcTimingDropTable.getValue(wheelSlip, vehicleSpeed); | |
55 | 1103 | engine->engineState.tractionControlSparkSkip = tcSparkSkipTable.getValue(wheelSlip, vehicleSpeed); | ||
56 | 1103 | engine->engineState.updateSparkSkip(); | ||
57 | ||||
58 | 1103 | advanceAngle += engine->ignitionState.tractionAdvanceDrop; | ||
59 | ||||
60 | #if EFI_ANTILAG_SYSTEM | |||
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1103 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1103 times.
|
1103 | if (engine->antilagController.isAntilagCondition) { |
62 | ✗ | float throttleIntent = Sensor::getOrZero(SensorType::DriverThrottleIntent); | ||
63 | ✗ | engine->antilagController.timingALSCorrection = interpolate3d( | ||
64 | ✗ | config->ALSTimingRetardTable, | ||
65 | ✗ | config->alsIgnRetardLoadBins, throttleIntent, | ||
66 | ✗ | config->alsIgnRetardrpmBins, rpm | ||
67 | ); | |||
68 | ✗ | advanceAngle += engine->antilagController.timingALSCorrection; | ||
69 | } | |||
70 | #endif /* EFI_ANTILAG_SYSTEM */ | |||
71 | ||||
72 | // Add any adjustments if configured | |||
73 |
2/2✓ Branch 1 taken 4412 times.
✓ Branch 2 taken 1103 times.
|
2/2✓ Decision 'true' taken 4412 times.
✓ Decision 'false' taken 1103 times.
|
5515 | for (size_t i = 0; i < efi::size(config->ignBlends); i++) { |
74 | 4412 | auto result = calculateBlend(config->ignBlends[i], rpm, engineLoad); | ||
75 | ||||
76 | 4412 | engine->outputChannels.ignBlendParameter[i] = result.BlendParameter; | ||
77 | 4412 | engine->outputChannels.ignBlendBias[i] = result.Bias; | ||
78 | 4412 | engine->outputChannels.ignBlendOutput[i] = result.Value; | ||
79 | 4412 | engine->outputChannels.ignBlendYAxis[i] = result.TableYAxis; | ||
80 | ||||
81 | 4412 | advanceAngle += result.Value; | ||
82 | } | |||
83 | ||||
84 | // get advance from the separate table for Idle | |||
85 | #if EFI_IDLE_CONTROL | |||
86 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1096 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1098 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1105 times.
|
1110 | if (engineConfiguration->useSeparateAdvanceForIdle && |
87 |
3/4✓ Branch 3 taken 2 times.
✓ Branch 4 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
|
7 | (engine->module<IdleController>()->isIdlingOrTaper() || engine->module<IdleController>()->isCoastingAdvance())) { | |
88 |
1/1✓ Branch 1 taken 5 times.
|
5 | float idleAdvance = interpolate2d(rpm, config->idleAdvanceBins, config->idleAdvance); | |
89 | ||||
90 |
1/1✓ Branch 2 taken 5 times.
|
5 | auto tps = Sensor::get(SensorType::DriverThrottleIntent); | |
91 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
|
5 | if (tps) { |
92 | // interpolate between idle table and normal (running) table using TPS threshold | |||
93 | // 0 TPS -> idle table | |||
94 | // 1/2 threshold -> idle table | |||
95 | // idle threshold -> normal table | |||
96 | 5 | float idleThreshold = engineConfiguration->idlePidDeactivationTpsThreshold; | ||
97 |
1/1✓ Branch 1 taken 5 times.
|
5 | advanceAngle = interpolateClamped(idleThreshold / 2, idleAdvance, idleThreshold, advanceAngle, tps.Value); | |
98 | } | |||
99 | } | |||
100 | #endif | |||
101 | ||||
102 | #if EFI_IDLE_CONTROL | |||
103 | // reset ignition table dot, see #8198 | |||
104 |
6/6✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1096 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 1098 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1098 times.
|
1103 | if(engineConfiguration->useSeparateAdvanceForIdle && engine->module<IdleController>()->isIdlingOrTaper()){ |
105 | 5 | engine->ignitionState.rpmForIgnitionIdleTableDot = rpm; | ||
106 | 5 | engine->ignitionState.rpmForIgnitionTableDot = -1; | ||
107 | 5 | engine->ignitionState.loadForIgnitionTableDot = -1; | ||
108 | } else { | |||
109 | 1098 | engine->ignitionState.rpmForIgnitionIdleTableDot = -1; | ||
110 | 1098 | engine->ignitionState.rpmForIgnitionTableDot = rpm; | ||
111 | 1098 | engine->ignitionState.loadForIgnitionTableDot = engineLoad; | ||
112 | } | |||
113 | #endif | |||
114 | ||||
115 | #if EFI_LAUNCH_CONTROL | |||
116 |
4/4✓ Branch 0 taken 92 times.
✓ Branch 1 taken 1011 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 28 times.
|
2/2✓ Decision 'true' taken 64 times.
✓ Decision 'false' taken 1039 times.
|
1103 | if (engineConfiguration->launchControlEnabled && engineConfiguration->enableLaunchRetard) { |
117 | 64 | const float launchAngle = engineConfiguration->launchTimingRetard; | ||
118 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 52 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 52 times.
|
64 | if (engine->launchController.isPreLaunchCondition) { |
119 | 12 | const int launchRpm = engineConfiguration->launchRpm; | ||
120 | 12 | const int smoothRetardStartRpm = (launchRpm - engineConfiguration->launchRpmWindow); | ||
121 | 12 | const int smoothRetardEndRpm = (launchRpm - engineConfiguration->launchCorrectionsEndRpm); | ||
122 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 12 times.
✗ Decision 'false' not taken.
|
12 | if (smoothRetardStartRpm <= rpm) { |
123 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 8 times.
|
12 | if (engineConfiguration->launchSmoothRetard && (rpm <= smoothRetardEndRpm)) { |
124 | // https://github.com/rusefi/rusefi/issues/5611#issuecomment-2130431696 | |||
125 | 4 | return interpolateClamped(smoothRetardStartRpm, advanceAngle, smoothRetardEndRpm, launchAngle, rpm); | ||
126 | } else { | |||
127 | 8 | return launchAngle; | ||
128 | } | |||
129 | } | |||
130 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 42 times.
|
2/2✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 42 times.
|
52 | } else if (engine->launchController.isLaunchCondition) { |
131 | 10 | return launchAngle; | ||
132 | } | |||
133 | } | |||
134 |
2/2✓ Branch 0 taken 557 times.
✓ Branch 1 taken 524 times.
|
1081 | if (engineConfiguration->torqueReductionEnabled | |
135 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 546 times.
|
557 | && engine->shiftTorqueReductionController.isFlatShiftConditionSatisfied | |
136 | ) { | |||
137 | 11 | return engine->shiftTorqueReductionController.getTorqueReductionIgnitionRetard(); | ||
138 | } | |||
139 |
6/6✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1058 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 1066 times.
|
1070 | if (engineConfiguration->nitrousControlEnabled && engine->module<NitrousController>()->isNitrousCondition) { | |
140 | 4 | advanceAngle -= engineConfiguration->nitrousIgnitionRetard; | ||
141 | } | |||
142 | #endif /* EFI_LAUNCH_CONTROL */ | |||
143 | ||||
144 | #ifdef MODULE_VVL_CONTROLLER | |||
145 | 1070 | advanceAngle += engine->module<VvlController>().unmock().getTimingModifier(); | ||
146 | #endif /* MODULE_VVL_CONTROLLER */ | |||
147 | ||||
148 | 1070 | return advanceAngle; | ||
149 | } | |||
150 | ||||
151 | 1120 | angle_t getCltTimingCorrection(float engineLoad) { | ||
152 |
1/1✓ Branch 2 taken 1120 times.
|
1120 | const auto clt = Sensor::get(SensorType::Clt); | |
153 | ||||
154 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1120 times.
|
1120 | if (!clt) | |
155 | ✗ | return 0; // this error should be already reported somewhere else, let's just handle it | ||
156 | ||||
157 | 2240 | return interpolate3d( | ||
158 | 1120 | config->ignitionCltCorrTable, | ||
159 | 1120 | config->ignitionCltCorrLoadBins, engineLoad, | ||
160 |
1/1✓ Branch 1 taken 1120 times.
|
1120 | config->ignitionCltCorrTempBins, clt.Value | |
161 | 1120 | ); | ||
162 | } | |||
163 | ||||
164 | 1120 | void IgnitionState::updateAdvanceCorrections(float engineLoad) { | ||
165 |
1/1✓ Branch 2 taken 1120 times.
|
1120 | cltTimingCorrection = getCltTimingCorrection(engineLoad); | |
166 | 1120 | } | ||
167 | ||||
168 | 961 | angle_t getAdvanceCorrections(float engineLoad) { | ||
169 |
1/1✓ Branch 2 taken 961 times.
|
961 | auto iat = Sensor::get(SensorType::Iat); | |
170 | ||||
171 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 961 times.
|
961 | if (!iat) { | |
172 | ✗ | engine->ignitionState.timingIatCorrection = 0; | ||
173 | } else { | |||
174 | 1922 | engine->ignitionState.timingIatCorrection = interpolate3d( | ||
175 | 961 | config->ignitionIatCorrTable, | ||
176 | 961 | config->ignitionIatCorrLoadBins, engineLoad, | ||
177 |
1/1✓ Branch 1 taken 961 times.
|
961 | config->ignitionIatCorrTempBins, iat.Value | |
178 | ); | |||
179 | } | |||
180 | ||||
181 | #if EFI_IDLE_CONTROL | |||
182 | 961 | float instantRpm = engine->triggerCentral.instantRpm.getInstantRpm(); | ||
183 | ||||
184 |
2/2✓ Branch 2 taken 961 times.
✓ Branch 6 taken 961 times.
|
961 | engine->ignitionState.timingPidCorrection = engine->module<IdleController>()->getIdleTimingAdjustment(instantRpm); | |
185 | #endif // EFI_IDLE_CONTROL | |||
186 | ||||
187 |
2/2✓ Branch 2 taken 961 times.
✓ Branch 6 taken 961 times.
|
961 | engine->ignitionState.dfcoTimingRetard = engine->module<DfcoController>()->getTimingRetard(); | |
188 | ||||
189 | #if EFI_TUNER_STUDIO | |||
190 | 961 | engine->outputChannels.multiSparkCounter = engine->engineState.multispark.count; | ||
191 | #endif /* EFI_TUNER_STUDIO */ | |||
192 | ||||
193 | 961 | return engine->ignitionState.timingIatCorrection | ||
194 | 961 | + engine->ignitionState.cltTimingCorrection | ||
195 | 961 | + engine->ignitionState.timingPidCorrection | ||
196 | 1922 | - engine->ignitionState.dfcoTimingRetard; | ||
197 | } | |||
198 | ||||
199 | /** | |||
200 | * @return ignition timing angle advance before TDC for Cranking | |||
201 | */ | |||
202 | 130 | angle_t getCrankingAdvance(float rpm, float engineLoad) { | ||
203 | // get advance from the separate table for Cranking | |||
204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
|
130 | if (engineConfiguration->useSeparateAdvanceForCranking) { | |
205 | ✗ | return interpolate2d(rpm, config->crankingAdvanceBins, config->crankingAdvance); | ||
206 | } | |||
207 | ||||
208 | // Interpolate the cranking timing angle to the earlier running angle for faster engine start | |||
209 | 130 | angle_t crankingToRunningTransitionAngle = getRunningAdvance(engineConfiguration->cranking.rpm, engineLoad); | ||
210 | // interpolate not from zero, but starting from min. possible rpm detected | |||
211 |
4/4✓ Branch 0 taken 127 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 42 times.
|
130 | if (rpm < minCrankingRpm || minCrankingRpm == 0) | |
212 | 88 | minCrankingRpm = rpm; | ||
213 | 130 | return interpolateClamped(minCrankingRpm, engineConfiguration->crankingTimingAngle, engineConfiguration->cranking.rpm, crankingToRunningTransitionAngle, rpm); | ||
214 | } | |||
215 | #endif // EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT | |||
216 | ||||
217 | 1122 | angle_t IgnitionState::getAdvance(float rpm, float engineLoad) { | ||
218 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1122 times.
|
1122 | if (std::isnan(engineLoad)) { | |
219 | ✗ | return 0; // any error should already be reported | ||
220 | } | |||
221 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 1089 times.
|
1122 | if (engineConfiguration->timingMode == TM_FIXED) { | |
222 | // fixed timing is the simple: cranking/running does not matter, no corrections! | |||
223 | 33 | return engineConfiguration->fixedTiming; | ||
224 | } | |||
225 | ||||
226 | angle_t angle; | |||
227 | ||||
228 | 1089 | bool isCranking = engine->rpmCalculator.isCranking(); | ||
229 |
2/2✓ Branch 0 taken 129 times.
✓ Branch 1 taken 960 times.
|
1089 | if (isCranking) { | |
230 | 129 | angle = getCrankingAdvance(rpm, engineLoad); | ||
231 |
2/4✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 129 times.
|
129 | assertAngleRange(angle, "crAngle", ObdCode::CUSTOM_ERR_ANGLE_CR); | |
232 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 129 times.
|
129 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(angle), "cr_AngleN", 0); | |
233 | } else { | |||
234 | 960 | angle = getRunningAdvance(rpm, engineLoad); | ||
235 | ||||
236 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 960 times.
|
960 | if (std::isnan(angle)) { | |
237 | ✗ | warning(ObdCode::CUSTOM_ERR_6610, "NaN angle from table"); | ||
238 | ✗ | return 0; | ||
239 | } | |||
240 | } | |||
241 | ||||
242 | // Allow if we're either not cranking OR allowed to correct in cranking | |||
243 |
3/4✓ Branch 0 taken 129 times.
✓ Branch 1 taken 960 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 129 times.
|
1089 | bool allowCorrections = !isCranking || engineConfiguration->useAdvanceCorrectionsForCranking; | |
244 | ||||
245 |
2/2✓ Branch 0 taken 960 times.
✓ Branch 1 taken 129 times.
|
1089 | if (allowCorrections) { | |
246 | 960 | angle_t correction = getAdvanceCorrections(engineLoad); | ||
247 |
1/2✓ Branch 1 taken 960 times.
✗ Branch 2 not taken.
|
960 | if (!std::isnan(correction)) { // correction could be NaN during settings update | |
248 | 960 | angle += correction; | ||
249 | } | |||
250 | } | |||
251 | ||||
252 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1089 times.
|
1089 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(angle), "_AngleN5", 0); | |
253 | 1089 | return angle; | ||
254 | } | |||
255 | ||||
256 | 1122 | angle_t IgnitionState::getWrappedAdvance(const float rpm, const float engineLoad) { | ||
257 |
1/1✓ Branch 2 taken 1122 times.
|
1122 | angle_t angle = getAdvance(rpm, engineLoad) * luaTimingMult + luaTimingAdd; | |
258 |
1/1✓ Branch 1 taken 1122 times.
|
1122 | wrapAngle(angle, "getWrappedAdvance", ObdCode::CUSTOM_ERR_ADCANCE_CALC_ANGLE); | |
259 | 1122 | return angle; | ||
260 | } | |||
261 | ||||
262 | PUBLIC_API_WEAK_SOMETHING_WEIRD | |||
263 | 4513 | angle_t getCylinderIgnitionTrim(size_t cylinderNumber, float rpm, float ignitionLoad) { | ||
264 | 4513 | return IgnitionState::getInterpolatedIgnitionTrim(cylinderNumber, rpm, ignitionLoad); | ||
265 | } | |||
266 | ||||
267 | 1141 | size_t getMultiSparkCount(float rpm) { | ||
268 | // Compute multispark (if enabled) | |||
269 | 2282 | if (engineConfiguration->multisparkEnable | ||
270 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 2 times.
|
13 | && rpm <= engineConfiguration->multisparkMaxRpm | |
271 |
5/6✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1128 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 1130 times.
|
1154 | && engineConfiguration->multisparkMaxExtraSparkCount > 0) { | |
272 | // For zero RPM, disable multispark. We don't yet know the engine speed, so multispark may not be safe. | |||
273 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 10 times.
|
11 | if (rpm == 0) { | |
274 | 1 | return 0; | ||
275 | } | |||
276 | ||||
277 | 10 | floatus_t multiDelay = 1000.0f * engineConfiguration->multisparkSparkDuration; | ||
278 | 10 | floatus_t multiDwell = 1000.0f * engineConfiguration->multisparkDwell; | ||
279 | ||||
280 | // dwell times are below 10 seconds here so we use 32 bit type for performance reasons | |||
281 | 10 | engine->engineState.multispark.delay = (uint32_t)USF2NT(multiDelay); | ||
282 | 10 | engine->engineState.multispark.dwell = (uint32_t)USF2NT(multiDwell); | ||
283 | ||||
284 | 10 | constexpr float usPerDegreeAt1Rpm = 60e6 / 360; | ||
285 | 10 | floatus_t usPerDegree = usPerDegreeAt1Rpm / rpm; | ||
286 | ||||
287 | // How long is there for sparks? The user configured an angle, convert to time. | |||
288 | 10 | floatus_t additionalSparksUs = usPerDegree * engineConfiguration->multisparkMaxSparkingAngle; | ||
289 | // How long does one spark take? | |||
290 | 10 | floatus_t oneSparkTime = multiDelay + multiDwell; | ||
291 | ||||
292 | // How many sparks can we fit in the alloted time? | |||
293 | 10 | float sparksFitInTime = additionalSparksUs / oneSparkTime; | ||
294 | ||||
295 | // Take the floor (convert to uint8_t) - we want to undershoot, not overshoot | |||
296 | 10 | uint32_t floored = sparksFitInTime; | ||
297 | ||||
298 | // Allow no more than the maximum number of extra sparks | |||
299 | 10 | return minI(floored, engineConfiguration->multisparkMaxExtraSparkCount); | ||
300 | } else { | |||
301 | 1130 | return 0; | ||
302 | } | |||
303 | } | |||
304 | ||||
305 | 587 | void initIgnitionAdvanceControl() { | ||
306 | 587 | tcTimingDropTable.initTable(engineConfiguration->tractionControlTimingDrop, engineConfiguration->tractionControlSlipBins, engineConfiguration->tractionControlSpeedBins); | ||
307 | 587 | tcSparkSkipTable.initTable(engineConfiguration->tractionControlIgnitionSkip, engineConfiguration->tractionControlSlipBins, engineConfiguration->tractionControlSpeedBins); | ||
308 | 587 | } | ||
309 | ||||
310 | /** | |||
311 | * @return Spark dwell time, in milliseconds. 0 if tables are not ready. | |||
312 | */ | |||
313 | 1124 | floatms_t IgnitionState::getSparkDwell(float rpm, bool isCranking) { | ||
314 | float dwellMs; | |||
315 |
2/2✓ Branch 0 taken 145 times.
✓ Branch 1 taken 979 times.
|
1124 | if (isCranking) { | |
316 | 145 | dwellMs = engineConfiguration->ignitionDwellForCrankingMs; | ||
317 | } else { | |||
318 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 979 times.
|
979 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(rpm), "invalid rpm", NAN); | |
319 | ||||
320 | 979 | baseDwell = interpolate2d(rpm, config->sparkDwellRpmBins, config->sparkDwellValues); | ||
321 | 979 | dwellVoltageCorrection = interpolate2d( | ||
322 | Sensor::getOrZero(SensorType::BatteryVoltage), | |||
323 | 979 | config->dwellVoltageCorrVoltBins, | ||
324 | 979 | config->dwellVoltageCorrValues | ||
325 | ); | |||
326 | ||||
327 | // for compat (table full of zeroes) | |||
328 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 979 times.
|
979 | if (dwellVoltageCorrection < 0.1f) { | |
329 | ✗ | dwellVoltageCorrection = 1; | ||
330 | } | |||
331 | ||||
332 | 979 | dwellMs = baseDwell * dwellVoltageCorrection; | ||
333 | } | |||
334 | ||||
335 |
3/6✓ Branch 1 taken 1124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1124 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1124 times.
|
1124 | if (std::isnan(dwellMs) || dwellMs <= 0) { | |
336 | // this could happen during engine configuration reset | |||
337 | ✗ | warning(ObdCode::CUSTOM_ERR_DWELL_DURATION, "invalid dwell: %.2f at rpm=%.0f", dwellMs, rpm); | ||
338 | ✗ | return 0; | ||
339 | } | |||
340 | 1124 | return dwellMs; | ||
341 | } | |||
342 | ||||
343 | 1124 | void IgnitionState::updateDwell(float rpm, bool isCranking) { | ||
344 | 1124 | sparkDwell = getSparkDwell(rpm, isCranking); | ||
345 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1124 times.
|
1124 | dwellDurationAngle = std::isnan(rpm) ? NAN : getDwell() / getOneDegreeTimeMs(rpm); | |
346 | 1124 | } | ||
347 | ||||
348 | 560916 | floatms_t IgnitionState::getDwell() const { | ||
349 | 560916 | return sparkDwell; | ||
350 | } | |||
351 | ||||
352 | 1120 | angle_t IgnitionState::getTrailingSparkAngle(const float rpm, const float engineLoad){ | ||
353 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1120 times.
|
1120 | if (std::isnan(engineLoad)) { | |
354 | // default value from: https://github.com/rusefi/rusefi/commit/86683afca22ed1a8af8fd5ac9231442e2124646e#diff-6e80cdd8c55add68105618ad9e8954170a47f59814201dadd2b888509d6b2e39R176 | |||
355 | ✗ | return 10; | ||
356 | } | |||
357 | 2240 | return interpolate3d( | ||
358 | 1120 | config->trailingSparkTable, | ||
359 | 1120 | config->trailingSparkLoadBins, engineLoad, | ||
360 | 1120 | config->trailingSparkRpmBins, rpm | ||
361 | 1120 | ); | ||
362 | } | |||
363 | ||||
364 | 4513 | angle_t IgnitionState::getSparkHardwareLatencyCorrection(){ | ||
365 | // time => degree | |||
366 | 4513 | angle_t correction = engineConfiguration->sparkHardwareLatencyCorrection / engine->rpmCalculator.oneDegreeUs; | ||
367 | ||||
368 |
2/2✓ Branch 1 taken 1206 times.
✓ Branch 2 taken 3307 times.
|
4513 | if (!std::isnan(correction)) { | |
369 | 1206 | return correction; | ||
370 | } | |||
371 | 3307 | return 0; | ||
372 | } | |||
373 | ||||
374 | 1103 | angle_t IgnitionState::getInterpolatedIgnitionAngle(const float rpm, const float ignitionLoad) { | ||
375 | 2206 | return interpolate3d( | ||
376 | 1103 | config->ignitionTable, | ||
377 | 1103 | config->ignitionLoadBins, ignitionLoad, | ||
378 | 1103 | config->ignitionRpmBins, rpm | ||
379 | 1103 | ); | ||
380 | } | |||
381 | ||||
382 | 4513 | angle_t IgnitionState::getInterpolatedIgnitionTrim( | ||
383 | const size_t cylinderNumber, | |||
384 | const float rpm, | |||
385 | const float ignitionLoad | |||
386 | ) { | |||
387 | 9026 | return interpolate3d( | ||
388 | 4513 | config->ignTrims[cylinderNumber].table, | ||
389 | 4513 | config->ignTrimLoadBins, ignitionLoad, | ||
390 | 4513 | config->ignTrimRpmBins, rpm | ||
391 | 4513 | ); | ||
392 | } | |||
393 | ||||
394 | #endif // EFI_ENGINE_CONTROL | |||
395 |