Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /* | |||
2 | * @file trigger_central.cpp | |||
3 | * Here we have a bunch of higher-level methods which are not directly related to actual signal decoding | |||
4 | * | |||
5 | * @date Feb 23, 2014 | |||
6 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
7 | */ | |||
8 | ||||
9 | #include "pch.h" | |||
10 | ||||
11 | #include "trigger_central.h" | |||
12 | #include "trigger_decoder.h" | |||
13 | #include "main_trigger_callback.h" | |||
14 | #include "listener_array.h" | |||
15 | #include "logic_analyzer.h" | |||
16 | ||||
17 | #include "local_version_holder.h" | |||
18 | #include "trigger_simulator.h" | |||
19 | #include "trigger_emulator_algo.h" | |||
20 | ||||
21 | #include "map_averaging.h" | |||
22 | #include "main_trigger_callback.h" | |||
23 | #include "status_loop.h" | |||
24 | #include "engine_sniffer.h" | |||
25 | #include "auto_generated_sync_edge.h" | |||
26 | ||||
27 | #if EFI_TUNER_STUDIO | |||
28 | #include "tunerstudio.h" | |||
29 | #endif /* EFI_TUNER_STUDIO */ | |||
30 | ||||
31 | #if EFI_ENGINE_SNIFFER | |||
32 | WaveChart waveChart; | |||
33 | #endif /* EFI_ENGINE_SNIFFER */ | |||
34 | ||||
35 | #define TRIGGER_WAVEFORM(x) getTriggerCentral()->triggerShape.x | |||
36 | ||||
37 | #if EFI_SHAFT_POSITION_INPUT | |||
38 | ||||
39 | 677 | TriggerCentral::TriggerCentral() : | ||
40 |
4/4✓ Branch 0 taken 2708 times.
✓ Branch 1 taken 1354 times.
✓ Branch 2 taken 1354 times.
✓ Branch 3 taken 677 times.
|
4739 | vvtPosition(), | |
41 |
2/2✓ Branch 14 taken 1354 times.
✓ Branch 15 taken 677 times.
|
2708 | triggerState("TRG") | |
42 | { | |||
43 | 677 | setArrayValues(hwEventCounters, 0); | ||
44 | 677 | triggerState.resetState(); | ||
45 | 677 | noiseFilter.resetAccumSignalData(); | ||
46 | 677 | } | ||
47 | ||||
48 | 795 | void TriggerNoiseFilter::resetAccumSignalData() { | ||
49 | 795 | memset(lastSignalTimes, 0xff, sizeof(lastSignalTimes)); // = -1 | ||
50 | 795 | memset(accumSignalPeriods, 0, sizeof(accumSignalPeriods)); | ||
51 | 795 | memset(accumSignalPrevPeriods, 0, sizeof(accumSignalPrevPeriods)); | ||
52 | 795 | } | ||
53 | ||||
54 | 2091816 | int TriggerCentral::getHwEventCounter(int index) const { | ||
55 | 2091816 | return hwEventCounters[index]; | ||
56 | } | |||
57 | ||||
58 | 2099790 | angle_t TriggerCentral::getVVTPosition(uint8_t bankIndex, uint8_t camIndex) { | ||
59 |
2/4✓ Branch 0 taken 2099790 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2099790 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2099790 times.
|
2099790 | if (bankIndex >= BANKS_COUNT || camIndex >= CAMS_PER_BANK) { |
60 | ✗ | return NAN; | ||
61 | } | |||
62 | 2099790 | return vvtPosition[bankIndex][camIndex]; | ||
63 | } | |||
64 | ||||
65 | /** | |||
66 | * @return angle since trigger synchronization point, NOT angle since TDC. | |||
67 | */ | |||
68 | 38879 | expected<float> TriggerCentral::getCurrentEnginePhase(efitick_t nowNt) const { | ||
69 | 38879 | floatus_t oneDegreeUs = engine->rpmCalculator.oneDegreeUs; | ||
70 | ||||
71 |
2/2✓ Branch 1 taken 2670 times.
✓ Branch 2 taken 36209 times.
|
2/2✓ Decision 'true' taken 2670 times.
✓ Decision 'false' taken 36209 times.
|
38879 | if (std::isnan(oneDegreeUs)) { |
72 | 2670 | return unexpected; | ||
73 | } | |||
74 | ||||
75 | float elapsed; | |||
76 | float toothPhase; | |||
77 | ||||
78 | { | |||
79 | // under lock to avoid mismatched tooth phase and time | |||
80 | chibios_rt::CriticalSectionLocker csl; | |||
81 | ||||
82 | 36209 | elapsed = m_lastToothTimer.getElapsedUs(nowNt); | ||
83 | 36209 | toothPhase = m_lastToothPhaseFromSyncPoint; | ||
84 | } | |||
85 | ||||
86 | 36209 | return toothPhase + elapsed / oneDegreeUs; | ||
87 | } | |||
88 | ||||
89 | /** | |||
90 | * todo: why is this method NOT reciprocal to getRpmMultiplier?! | |||
91 | */ | |||
92 | 32063 | int getCrankDivider(operation_mode_e operationMode) { | ||
93 |
5/7✓ Branch 0 taken 19919 times.
✓ Branch 1 taken 785 times.
✓ Branch 2 taken 1974 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 213 times.
✓ Branch 5 taken 9172 times.
✗ Branch 6 not taken.
|
32063 | switch (operationMode) { | |
94 |
1/1✓ Decision 'true' taken 19919 times.
|
19919 | case FOUR_STROKE_CRANK_SENSOR: | |
95 | 19919 | return 2; | ||
96 |
1/1✓ Decision 'true' taken 785 times.
|
785 | case FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR: | |
97 | 785 | return SYMMETRICAL_CRANK_SENSOR_DIVIDER; | ||
98 |
1/1✓ Decision 'true' taken 1974 times.
|
1974 | case FOUR_STROKE_THREE_TIMES_CRANK_SENSOR: | |
99 | 1974 | return SYMMETRICAL_THREE_TIMES_CRANK_SENSOR_DIVIDER; | ||
100 | ✗ | case FOUR_STROKE_SIX_TIMES_CRANK_SENSOR: | ||
101 | ✗ | return SYMMETRICAL_SIX_TIMES_CRANK_SENSOR_DIVIDER; | ||
102 |
1/1✓ Decision 'true' taken 213 times.
|
213 | case FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR: | |
103 | 213 | return SYMMETRICAL_TWELVE_TIMES_CRANK_SENSOR_DIVIDER; | ||
104 |
1/1✓ Decision 'true' taken 9172 times.
|
9172 | case OM_NONE: | |
105 | case FOUR_STROKE_CAM_SENSOR: | |||
106 | case TWO_STROKE: | |||
107 | // That's easy - trigger cycle matches engine cycle | |||
108 |
1/1✓ Decision 'true' taken 9172 times.
|
9172 | return 1; | |
109 | /* let's NOT handle default in order to benefit from -Werror=switch */ | |||
110 | } | |||
111 | /** | |||
112 | wow even while we explicitly handle all enumerations in the switch above we still need a return statement due to | |||
113 | https://stackoverflow.com/questions/34112483/gcc-how-best-to-handle-warning-about-unreachable-end-of-function-after-switch | |||
114 | */ | |||
115 | ✗ | criticalError("unreachable getCrankDivider"); | ||
116 | ✗ | return 1; | ||
117 | } | |||
118 | ||||
119 | 3132 | PUBLIC_API_WEAK bool boardIsSpecialVvtDecoder(vvt_mode_e vvtMode) { | ||
120 | UNUSED(vvtMode); | |||
121 | ||||
122 | 3132 | return false; | ||
123 | } | |||
124 | ||||
125 | 31489 | PUBLIC_API_WEAK void boardTriggerCallback(efitick_t timestamp, float currentPhase) { UNUSED(timestamp); UNUSED(currentPhase); } | ||
126 | ||||
127 | 3400 | static bool vvtWithRealDecoder(vvt_mode_e vvtMode) { | ||
128 | return vvtMode != VVT_INACTIVE | |||
129 |
2/2✓ Branch 0 taken 3327 times.
✓ Branch 1 taken 73 times.
|
3400 | && vvtMode != VVT_TOYOTA_3_TOOTH /* VVT_2JZ is an unusual 3/0 missed tooth symmetrical wheel */ | |
130 |
2/2✓ Branch 0 taken 3136 times.
✓ Branch 1 taken 191 times.
|
3327 | && vvtMode != VVT_HONDA_K_INTAKE | |
131 |
2/2✓ Branch 0 taken 3132 times.
✓ Branch 1 taken 4 times.
|
3136 | && vvtMode != VVT_MAP_V_TWIN | |
132 |
1/2✓ Branch 1 taken 3132 times.
✗ Branch 2 not taken.
|
3132 | && !boardIsSpecialVvtDecoder(vvtMode) | |
133 |
3/4✓ Branch 0 taken 3400 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2808 times.
✓ Branch 3 taken 324 times.
|
6800 | && vvtMode != VVT_SINGLE_TOOTH; | |
134 | } | |||
135 | ||||
136 | 574 | angle_t TriggerCentral::syncEnginePhaseAndReport(int divider, int remainder) { | ||
137 | 574 | angle_t engineCycle = getEngineCycle(getEngineRotationState()->getOperationMode()); | ||
138 | ||||
139 | 574 | angle_t totalShift = triggerState.syncEnginePhase(divider, remainder, engineCycle); | ||
140 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 537 times.
|
2/2✓ Decision 'true' taken 37 times.
✓ Decision 'false' taken 537 times.
|
574 | if (totalShift != 0) { |
141 | // Reset instant RPM, since the engine phase has now changed, invalidating the tooth history buffer | |||
142 | // maybe TODO: could/should we rotate the buffer around to re-align it instead? Is that worth it? | |||
143 | 37 | instantRpm.resetInstantRpm(); | ||
144 | } | |||
145 | 574 | return totalShift; | ||
146 | } | |||
147 | ||||
148 | ✗ | PUBLIC_API_WEAK angle_t customAdjustCustom(TriggerCentral *tc, vvt_mode_e vvtMode) { | ||
149 | UNUSED(tc); | |||
150 | UNUSED(vvtMode); | |||
151 | ||||
152 | ✗ | return 0; | ||
153 | } | |||
154 | ||||
155 | 571 | static angle_t adjustCrankPhase(int camIndex) { | ||
156 | 571 | float maxSyncThreshold = engineConfiguration->maxCamPhaseResolveRpm; | ||
157 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 571 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 571 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 571 times.
|
571 | if (maxSyncThreshold != 0 && Sensor::getOrZero(SensorType::Rpm) > maxSyncThreshold) { |
158 | // The user has elected to stop trying to resolve crank phase after some RPM. | |||
159 | // Maybe their cam sensor only works at low RPM or something. | |||
160 | // Anyway, don't try to change crank phase at all, and return that we made no change. | |||
161 | ✗ | return 0; | ||
162 | } | |||
163 | ||||
164 | 571 | operation_mode_e operationMode = getEngineRotationState()->getOperationMode(); | ||
165 | ||||
166 | 571 | auto crankDivider = getCrankDivider(operationMode); | ||
167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 571 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 571 times.
|
571 | if (crankDivider == 1) { |
168 | // Crank divider of 1 means there's no ambiguity, so don't try to resolve it | |||
169 | ✗ | return 0; | ||
170 | } | |||
171 | ||||
172 | 571 | TriggerCentral *tc = getTriggerCentral(); | ||
173 | ||||
174 | 571 | vvt_mode_e vvtMode = engineConfiguration->vvtMode[camIndex]; | ||
175 |
2/6✓ Branch 0 taken 16 times.
✓ Branch 1 taken 555 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
571 | switch (vvtMode) { | |
176 |
1/1✓ Decision 'true' taken 16 times.
|
16 | case VVT_MAP_V_TWIN: | |
177 | case VVT_MITSUBISHI_4G63: | |||
178 | case VVT_UNUSED_17: | |||
179 |
1/1✓ Decision 'true' taken 16 times.
|
16 | return tc->syncEnginePhaseAndReport(crankDivider, 1); | |
180 |
1/1✓ Decision 'true' taken 555 times.
|
555 | case VVT_SINGLE_TOOTH: | |
181 | case VVT_NISSAN_VQ: | |||
182 | case VVT_BOSCH_QUICK_START: | |||
183 | case VVT_MIATA_NB: | |||
184 | case VVT_TOYOTA_3TOOTH_UZ: | |||
185 | case VVT_TOYOTA_3_TOOTH: | |||
186 | case VVT_TOYOTA_4_1: | |||
187 | case VVT_FORD_COYOTE: | |||
188 | case VVT_DEV: | |||
189 | case VVT_FORD_ST170: | |||
190 | case VVT_BARRA_3_PLUS_1: | |||
191 | case VVT_NISSAN_MR: | |||
192 | case VVT_HR12DDR_IN: | |||
193 | case VVT_MAZDA_SKYACTIV: | |||
194 | case VVT_MAZDA_L: | |||
195 | case VVT_MITSUBISHI_4G69: | |||
196 | case VVT_MITSUBISHI_3A92: | |||
197 | case VVT_MITSUBISHI_6G72: | |||
198 | case VVT_CHRYSLER_PHASER: | |||
199 | case VVT_HONDA_K_EXHAUST: | |||
200 | case VVT_HONDA_CBR_600: | |||
201 | case VVT_SUBARU_7TOOTH: | |||
202 |
1/1✓ Decision 'true' taken 555 times.
|
555 | return tc->syncEnginePhaseAndReport(crankDivider, 0); | |
203 | ✗ | case VVT_CUSTOM_25: | ||
204 | case VVT_CUSTOM_26: | |||
205 | ✗ | return customAdjustCustom(tc, vvtMode); | ||
206 | ||||
207 | ✗ | case VVT_HONDA_K_INTAKE: | ||
208 | // with 4 evenly spaced tooth we cannot use this wheel for engine sync | |||
209 | ✗ | criticalError("Honda K Intake is not suitable for engine sync"); | ||
210 | [[fallthrough]]; | |||
211 | ✗ | case VVT_CUSTOM_1: | ||
212 | case VVT_CUSTOM_2: | |||
213 | case VVT_INACTIVE: | |||
214 | // do nothing | |||
215 | ✗ | return 0; | ||
216 | } | |||
217 | ✗ | return 0; | ||
218 | } | |||
219 | ||||
220 | /** | |||
221 | * See also wrapAngle | |||
222 | */ | |||
223 | 745 | static angle_t wrapVvt(angle_t vvtPosition, int period) { | ||
224 | // Wrap VVT position in to the range [-360, 360) | |||
225 |
2/2✓ Branch 0 taken 3640 times.
✓ Branch 1 taken 745 times.
|
2/2✓ Decision 'true' taken 3640 times.
✓ Decision 'false' taken 745 times.
|
4385 | while (vvtPosition < -period / 2) { |
226 | 3640 | vvtPosition += period; | ||
227 | } | |||
228 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 745 times.
|
2/2✓ Decision 'true' taken 198 times.
✓ Decision 'false' taken 745 times.
|
943 | while (vvtPosition >= period / 2) { |
229 | 198 | vvtPosition -= period; | ||
230 | } | |||
231 | 745 | return vvtPosition; | ||
232 | } | |||
233 | ||||
234 | 3400 | static void logVvtFront(bool useOnlyRise, bool isImportantFront, TriggerValue front, efitick_t nowNt, int index) { | ||
235 |
4/4✓ Branch 0 taken 1745 times.
✓ Branch 1 taken 1655 times.
✓ Branch 2 taken 416 times.
✓ Branch 3 taken 1329 times.
|
2/2✓ Decision 'true' taken 2071 times.
✓ Decision 'false' taken 1329 times.
|
3400 | if (!useOnlyRise || engineConfiguration->displayLogicLevelsInEngineSniffer) { |
236 | // If we care about both edges OR displayLogicLevel is set, log every front exactly as it is | |||
237 | 2071 | addEngineSnifferVvtEvent(index, front == TriggerValue::RISE ? FrontDirection::UP : FrontDirection::DOWN); | ||
238 | ||||
239 | #if EFI_TOOTH_LOGGER | |||
240 | 2071 | LogTriggerCamTooth(front == TriggerValue::RISE, nowNt, index); | ||
241 | #endif /* EFI_TOOTH_LOGGER */ | |||
242 | } else { | |||
243 |
2/2✓ Branch 0 taken 820 times.
✓ Branch 1 taken 509 times.
|
2/2✓ Decision 'true' taken 820 times.
✓ Decision 'false' taken 509 times.
|
1329 | if (isImportantFront) { |
244 | // On the important edge, log a rise+fall pair, and nothing on the real falling edge | |||
245 | 820 | addEngineSnifferVvtEvent(index, FrontDirection::UP); | ||
246 | 820 | addEngineSnifferVvtEvent(index, FrontDirection::DOWN); | ||
247 | ||||
248 | #if EFI_TOOTH_LOGGER | |||
249 | 820 | LogTriggerCamTooth(true, nowNt, index); | ||
250 | 820 | LogTriggerCamTooth(false, nowNt, index); | ||
251 | #endif /* EFI_TOOTH_LOGGER */ | |||
252 | } | |||
253 | } | |||
254 | 3400 | } | ||
255 | ||||
256 | 61810 | static bool tooSoonToHandleSignal() { | ||
257 | #if EFI_PROD_CODE | |||
258 | extern bool main_loop_started; | |||
259 | if (!main_loop_started) { | |||
260 | warning(ObdCode::CUSTOM_ERR_INPUT_DURING_INITIALISATION, "event too early"); | |||
261 | return true; | |||
262 | } | |||
263 | #endif //EFI_PROD_CODE | |||
264 | 61810 | return false; | ||
265 | } | |||
266 | ||||
267 | /** | |||
268 | * This function is called by all "hardware" trigger inputs: | |||
269 | * - Hardware triggers | |||
270 | * - Trigger replay from CSV (unit tests) | |||
271 | */ | |||
272 | 2894 | void hwHandleVvtCamSignal(bool isRising, efitick_t nowNt, int index) { | ||
273 | 2894 | int camIndex = CAM_BY_INDEX(index); | ||
274 |
2/2✓ Branch 0 taken 2669 times.
✓ Branch 1 taken 225 times.
|
2894 | bool invertSetting = camIndex == 0 ? engineConfiguration->invertCamVVTSignal : engineConfiguration->invertExhaustCamVVTSignal; | |
275 | ||||
276 |
2/2✓ Branch 0 taken 1453 times.
✓ Branch 1 taken 1441 times.
|
2/2✓ Decision 'true' taken 1453 times.
✓ Decision 'false' taken 1441 times.
|
2894 | if (isRising ^ invertSetting) { |
277 | 1453 | hwHandleVvtCamSignal(TriggerValue::RISE, nowNt, index); | ||
278 | } else { | |||
279 | 1441 | hwHandleVvtCamSignal(TriggerValue::FALL, nowNt, index); | ||
280 | } | |||
281 | 2894 | } | ||
282 | ||||
283 | // 'invertCamVVTSignal' is already accounted by the time this method is invoked | |||
284 | 3400 | void hwHandleVvtCamSignal(TriggerValue front, efitick_t nowNt, int index) { | ||
285 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3400 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3400 times.
|
3400 | if (tooSoonToHandleSignal()) { |
286 | ✗ | return; | ||
287 | } | |||
288 | 3400 | TriggerCentral *tc = getTriggerCentral(); | ||
289 |
2/4✓ Branch 0 taken 3400 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3400 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3400 times.
|
3400 | if (tc->directSelfStimulation || !tc->hwTriggerInputEnabled) { |
290 | // sensor noise + self-stim = loss of trigger sync | |||
291 | ✗ | return; | ||
292 | } | |||
293 | 3400 | handleVvtCamSignal(front, nowNt, index); | ||
294 | } | |||
295 | ||||
296 | /** | |||
297 | * @returns true if tooth should be ignored | |||
298 | */ | |||
299 | 702 | PUBLIC_API_WEAK bool skipToothSpecialShape(size_t index, vvt_mode_e vvtMode, angle_t currentPosition) { | ||
300 | UNUSED(index); | |||
301 | ||||
302 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 669 times.
|
702 | switch(vvtMode) { | |
303 |
1/1✓ Decision 'true' taken 33 times.
|
33 | case VVT_TOYOTA_3_TOOTH: | |
304 | { | |||
305 | 33 | int from = engineConfiguration->camDecoder2jzPosition - engineConfiguration->camDecoder2jzPrecision; | ||
306 | 33 | int to = engineConfiguration->camDecoder2jzPosition + engineConfiguration->camDecoder2jzPrecision; | ||
307 | // we do not know if we are in sync or out of sync, so we have to be looking for both possibilities | |||
308 |
3/4✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 1 time.
|
2/2✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 1 time.
|
33 | if ((currentPosition < from || currentPosition > to) && |
309 |
3/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
32 | (currentPosition < from + 360 || currentPosition > to + 360)) { | |
310 | // outside of the expected range | |||
311 | 32 | return true; | ||
312 | } | |||
313 | } | |||
314 | 1 | break; | ||
315 |
1/1✓ Decision 'true' taken 669 times.
|
669 | default: | |
316 | ||||
317 | // else, do nothing | |||
318 | 669 | break; | ||
319 | } | |||
320 | 670 | return false; | ||
321 | } | |||
322 | ||||
323 | 3400 | void handleVvtCamSignal(TriggerValue front, efitick_t nowNt, int index) { | ||
324 |
1/1✓ Branch 1 taken 3400 times.
|
3400 | TriggerCentral *tc = getTriggerCentral(); | |
325 |
2/2✓ Branch 0 taken 2939 times.
✓ Branch 1 taken 461 times.
|
2/2✓ Decision 'true' taken 2939 times.
✓ Decision 'false' taken 461 times.
|
3400 | if (index == 0) { |
326 | 2939 | engine->outputChannels.vvtChannel1 = front == TriggerValue::RISE; | ||
327 |
2/2✓ Branch 0 taken 227 times.
✓ Branch 1 taken 234 times.
|
2/2✓ Decision 'true' taken 227 times.
✓ Decision 'false' taken 234 times.
|
461 | } else if (index == 1) { |
328 | 227 | engine->outputChannels.vvtChannel2 = front == TriggerValue::RISE; | ||
329 |
2/2✓ Branch 0 taken 232 times.
✓ Branch 1 taken 2 times.
|
2/2✓ Decision 'true' taken 232 times.
✓ Decision 'false' taken 2 times.
|
234 | } else if (index == 2) { |
330 | 232 | engine->outputChannels.vvtChannel3 = front == TriggerValue::RISE; | ||
331 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
|
2 | } else if (index == 3) { |
332 | 2 | engine->outputChannels.vvtChannel4 = front == TriggerValue::RISE; | ||
333 | } | |||
334 | ||||
335 | 3400 | int bankIndex = BANK_BY_INDEX(index); | ||
336 | 3400 | int camIndex = CAM_BY_INDEX(index); | ||
337 |
2/2✓ Branch 0 taken 1860 times.
✓ Branch 1 taken 1540 times.
|
2/2✓ Decision 'true' taken 1860 times.
✓ Decision 'false' taken 1540 times.
|
3400 | if (front == TriggerValue::RISE) { |
338 | 1860 | tc->vvtEventRiseCounter[index]++; | ||
339 | } else { | |||
340 | 1540 | tc->vvtEventFallCounter[index]++; | ||
341 | } | |||
342 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3400 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3400 times.
|
3400 | if (engineConfiguration->vvtMode[camIndex] == VVT_INACTIVE) { |
343 | ✗ | warning(ObdCode::CUSTOM_VVT_MODE_NOT_SELECTED, "VVT: event on %d but no mode", camIndex); | ||
344 | } | |||
345 | ||||
346 | 3400 | const auto& vvtShape = tc->vvtShape[camIndex]; | ||
347 | ||||
348 |
1/1✓ Branch 2 taken 3400 times.
|
3400 | bool isVvtWithRealDecoder = vvtWithRealDecoder(engineConfiguration->vvtMode[camIndex]); | |
349 | ||||
350 | // Non real decoders only use the rising edge | |||
351 |
4/4✓ Branch 0 taken 2808 times.
✓ Branch 1 taken 592 times.
✓ Branch 2 taken 1153 times.
✓ Branch 3 taken 1655 times.
|
3400 | bool vvtUseOnlyRise = !isVvtWithRealDecoder || vvtShape.useOnlyRisingEdges; | |
352 |
4/4✓ Branch 0 taken 1745 times.
✓ Branch 1 taken 1655 times.
✓ Branch 2 taken 1029 times.
✓ Branch 3 taken 716 times.
|
3400 | bool isImportantFront = !vvtUseOnlyRise || (front == TriggerValue::RISE); | |
353 | ||||
354 |
1/1✓ Branch 1 taken 3400 times.
|
3400 | logVvtFront(vvtUseOnlyRise, isImportantFront, front, nowNt, index); | |
355 | ||||
356 |
2/2✓ Branch 0 taken 716 times.
✓ Branch 1 taken 2684 times.
|
2/2✓ Decision 'true' taken 716 times.
✓ Decision 'false' taken 2684 times.
|
3400 | if (!isImportantFront) { |
357 | // This edge is unimportant, ignore it. | |||
358 | 716 | return; | ||
359 | } | |||
360 | ||||
361 | // If the main trigger is not synchronized, don't decode VVT yet | |||
362 |
3/3✓ Branch 1 taken 2684 times.
✓ Branch 3 taken 180 times.
✓ Branch 4 taken 2504 times.
|
2/2✓ Decision 'true' taken 180 times.
✓ Decision 'false' taken 2504 times.
|
2684 | if (!tc->triggerState.getShaftSynchronized()) { |
363 | 180 | return; | ||
364 | } | |||
365 | ||||
366 | 2504 | TriggerDecoderBase& vvtDecoder = tc->vvtState[bankIndex][camIndex]; | ||
367 | ||||
368 |
2/2✓ Branch 0 taken 2075 times.
✓ Branch 1 taken 429 times.
|
2/2✓ Decision 'true' taken 2075 times.
✓ Decision 'false' taken 429 times.
|
2504 | if (isVvtWithRealDecoder) { |
369 |
3/3✓ Branch 0 taken 1312 times.
✓ Branch 1 taken 763 times.
✓ Branch 3 taken 2075 times.
|
4150 | vvtDecoder.decodeTriggerEvent( | |
370 | "vvt", | |||
371 | vvtShape, | |||
372 | nullptr, | |||
373 | 2075 | tc->vvtTriggerConfiguration[camIndex], | ||
374 | front == TriggerValue::RISE ? SHAFT_PRIMARY_RISING : SHAFT_PRIMARY_FALLING, nowNt); | |||
375 | 2075 | vvtDecoder.vvtToothDurations0 = (uint32_t)NT2US(vvtDecoder.toothDurations[0]); | ||
376 | } | |||
377 | ||||
378 | // here we count all cams together | |||
379 | 2504 | tc->vvtCamCounter++; | ||
380 | ||||
381 |
1/1✓ Branch 2 taken 2504 times.
|
2504 | auto currentPhase = tc->getCurrentEnginePhase(nowNt); | |
382 |
2/2✓ Branch 1 taken 56 times.
✓ Branch 2 taken 2448 times.
|
2/2✓ Decision 'true' taken 56 times.
✓ Decision 'false' taken 2448 times.
|
2504 | if (!currentPhase) { |
383 | // If we couldn't resolve engine speed (yet primary trigger is sync'd), this | |||
384 | // probably means that we have partial crank sync, but not RPM information yet | |||
385 | 56 | return; | ||
386 | } | |||
387 | ||||
388 | 2448 | angle_t angleFromPrimarySyncPoint = currentPhase.Value; | ||
389 | // convert trigger cycle angle into engine cycle angle | |||
390 |
3/3✓ Branch 1 taken 2448 times.
✓ Branch 3 taken 166 times.
✓ Branch 4 taken 2282 times.
|
2448 | angle_t currentPosition = angleFromPrimarySyncPoint - tdcPosition(); | |
391 | // https://github.com/rusefi/rusefi/issues/1713 currentPosition could be negative that's expected | |||
392 | ||||
393 | #if EFI_UNIT_TEST | |||
394 | 2448 | tc->currentVVTEventPosition[bankIndex][camIndex] = currentPosition; | ||
395 | #endif // EFI_UNIT_TEST | |||
396 | ||||
397 | 2448 | tc->triggerState.vvtCurrentPosition = currentPosition; | ||
398 | ||||
399 |
4/4✓ Branch 0 taken 2023 times.
✓ Branch 1 taken 425 times.
✓ Branch 2 taken 1746 times.
✓ Branch 3 taken 277 times.
|
2/2✓ Decision 'true' taken 1746 times.
✓ Decision 'false' taken 702 times.
|
2448 | if (isVvtWithRealDecoder && vvtDecoder.currentCycle.current_index != 0) { |
400 | // this is not sync tooth - exiting | |||
401 | 1746 | return; | ||
402 | } | |||
403 | ||||
404 | 702 | auto vvtPosition = engineConfiguration->vvtOffsets[bankIndex * CAMS_PER_BANK + camIndex] - currentPosition; | ||
405 | 702 | tc->triggerState.vvtToothPosition[index] = vvtPosition; | ||
406 | ||||
407 |
1/1✓ Branch 2 taken 702 times.
|
702 | bool skipTooth = skipToothSpecialShape(index, engineConfiguration->vvtMode[camIndex], currentPosition); | |
408 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 670 times.
|
2/2✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 670 times.
|
702 | if (skipTooth) { |
409 | 32 | return; | ||
410 | } | |||
411 | ||||
412 | // this could be just an 'if' but let's have it expandable for future use :) | |||
413 |
2/2✓ Branch 1 taken 75 times.
✓ Branch 2 taken 595 times.
|
670 | switch(engineConfiguration->vvtMode[camIndex]) { | |
414 |
1/1✓ Decision 'true' taken 75 times.
|
75 | case VVT_HONDA_K_INTAKE: | |
415 | // honda K has four tooth in VVT intake trigger, so we just wrap each of those to 720 / 4 | |||
416 | 75 | vvtPosition = wrapVvt(vvtPosition, 180); | ||
417 | 75 | break; | ||
418 |
1/1✓ Decision 'true' taken 595 times.
|
595 | default: | |
419 | // else, do nothing | |||
420 | 595 | break; | ||
421 | } | |||
422 | ||||
423 | #if EFI_PROD_CODE | |||
424 | if (!isBrainPinValid(engineConfiguration->camInputs[engineConfiguration->engineSyncCam]) && | |||
425 | engineConfiguration->vvtMode[engineConfiguration->engineSyncCam] != VVT_MAP_V_TWIN) { | |||
426 | criticalError("Selected engine sync input not configured: %d", engineConfiguration->engineSyncCam); | |||
427 | } | |||
428 | #endif // EFI_PROD_CODE | |||
429 | ||||
430 | // Only do engine sync using one cam, other cams just provide VVT position. | |||
431 |
2/2✓ Branch 0 taken 571 times.
✓ Branch 1 taken 99 times.
|
2/2✓ Decision 'true' taken 571 times.
✓ Decision 'false' taken 99 times.
|
670 | if (index == engineConfiguration->engineSyncCam) { |
432 |
1/1✓ Branch 1 taken 571 times.
|
571 | angle_t crankOffset = adjustCrankPhase(camIndex); | |
433 | // vvtPosition was calculated against wrong crank zero position. Now that we have adjusted crank position we | |||
434 | // shall adjust vvt position as well | |||
435 | 571 | vvtPosition -= crankOffset; | ||
436 | 571 | vvtPosition = wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION); | ||
437 | ||||
438 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 571 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 571 times.
|
571 | if (absF(angleFromPrimarySyncPoint) < 7) { |
439 | /** | |||
440 | * we prefer not to have VVT sync right at trigger sync so that we do not have phase detection error if things happen a bit in | |||
441 | * wrong order due to belt flex or else | |||
442 | * https://github.com/rusefi/rusefi/issues/3269 | |||
443 | */ | |||
444 | ✗ | warning(ObdCode::CUSTOM_VVT_SYNC_POSITION, "VVT sync position too close to trigger sync"); | ||
445 | } | |||
446 | } else { | |||
447 | // Not using this cam for engine sync, just wrap the value in to the reasonable range | |||
448 | 99 | vvtPosition = wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION); | ||
449 | } | |||
450 | ||||
451 | // Only record VVT position if we have full engine sync - may be bogus before that point | |||
452 |
2/2✓ Branch 1 taken 654 times.
✓ Branch 2 taken 16 times.
|
2/2✓ Decision 'true' taken 654 times.
✓ Decision 'false' taken 16 times.
|
670 | if (tc->triggerState.hasSynchronizedPhase()) { |
453 | 654 | tc->vvtPosition[bankIndex][camIndex] = vvtPosition; | ||
454 | } else { | |||
455 | 16 | tc->vvtPosition[bankIndex][camIndex] = 0; | ||
456 | } | |||
457 | } | |||
458 | ||||
459 | int triggerReentrant = 0; | |||
460 | int maxTriggerReentrant = 0; | |||
461 | uint32_t triggerDuration; | |||
462 | uint32_t triggerMaxDuration = 0; | |||
463 | ||||
464 | /** | |||
465 | * This function is called by all "hardware" trigger inputs: | |||
466 | * - Hardware triggers | |||
467 | * - Trigger replay from CSV (unit tests) | |||
468 | */ | |||
469 | 58410 | void hwHandleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp) { | ||
470 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 58410 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 58410 times.
|
58410 | if (tooSoonToHandleSignal()) { |
471 | ✗ | return; | ||
472 | } | |||
473 |
1/1✓ Branch 1 taken 58410 times.
|
58410 | TriggerCentral *tc = getTriggerCentral(); | |
474 | 58410 | ScopePerf perf(PE::HandleShaftSignal); | ||
475 | ||||
476 |
2/4✓ Branch 0 taken 58410 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 58410 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 58410 times.
|
58410 | if (tc->directSelfStimulation || !tc->hwTriggerInputEnabled) { |
477 | // sensor noise + self-stim = loss of trigger sync | |||
478 | ✗ | return; | ||
479 | } | |||
480 | ||||
481 |
1/1✓ Branch 1 taken 58410 times.
|
58410 | handleShaftSignal(signalIndex, isRising, timestamp); | |
482 | } | |||
483 | ||||
484 | // Handle all shaft signals - hardware or emulated both | |||
485 | 67207 | void handleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp) { | ||
486 | 67207 | bool isPrimary = signalIndex == 0; | ||
487 |
4/6✓ Branch 0 taken 726 times.
✓ Branch 1 taken 66481 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 726 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 67207 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 67207 times.
|
67207 | if (!isPrimary && !TRIGGER_WAVEFORM(needSecondTriggerInput)) { |
488 | ✗ | return; | ||
489 | } | |||
490 | ||||
491 | trigger_event_e signal; | |||
492 | // todo: add support for 3rd channel | |||
493 |
2/2✓ Branch 0 taken 33623 times.
✓ Branch 1 taken 33584 times.
|
2/2✓ Decision 'true' taken 33623 times.
✓ Decision 'false' taken 33584 times.
|
67207 | if (isRising) { |
494 |
2/2✓ Branch 0 taken 33259 times.
✓ Branch 1 taken 364 times.
|
67246 | signal = isPrimary ? | |
495 |
2/2✓ Branch 0 taken 1207 times.
✓ Branch 1 taken 32052 times.
|
33259 | (engineConfiguration->invertPrimaryTriggerSignal ? SHAFT_PRIMARY_FALLING : SHAFT_PRIMARY_RISING) : | |
496 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 210 times.
|
364 | (engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_FALLING : SHAFT_SECONDARY_RISING); | |
497 | } else { | |||
498 |
2/2✓ Branch 0 taken 33222 times.
✓ Branch 1 taken 362 times.
|
67168 | signal = isPrimary ? | |
499 |
2/2✓ Branch 0 taken 1205 times.
✓ Branch 1 taken 32017 times.
|
33222 | (engineConfiguration->invertPrimaryTriggerSignal ? SHAFT_PRIMARY_RISING : SHAFT_PRIMARY_FALLING) : | |
500 |
2/2✓ Branch 0 taken 153 times.
✓ Branch 1 taken 209 times.
|
362 | (engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_RISING : SHAFT_SECONDARY_FALLING); | |
501 | } | |||
502 |
2/2✓ Branch 0 taken 66481 times.
✓ Branch 1 taken 726 times.
|
2/2✓ Decision 'true' taken 66481 times.
✓ Decision 'false' taken 726 times.
|
67207 | if (isPrimary) { |
503 | 66481 | engine->outputChannels.triggerChannel1 = signal == SHAFT_PRIMARY_RISING; | ||
504 | } else { | |||
505 | 726 | engine->outputChannels.triggerChannel2 = signal == SHAFT_SECONDARY_RISING; | ||
506 | } | |||
507 | ||||
508 | // Don't accept trigger input in case of some problems | |||
509 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 67207 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 67207 times.
|
67207 | if (!getLimpManager()->allowTriggerInput()) { |
510 | ✗ | return; | ||
511 | } | |||
512 | ||||
513 | #if EFI_TOOTH_LOGGER | |||
514 | // Log to the Tunerstudio tooth logger | |||
515 | // We want to do this before anything else as we | |||
516 | // actually want to capture any noise/jitter that may be occurring | |||
517 | ||||
518 |
3/4✓ Branch 0 taken 966 times.
✓ Branch 1 taken 66241 times.
✓ Branch 3 taken 966 times.
✗ Branch 4 not taken.
|
67207 | bool logLogicState = engineConfiguration->displayLogicLevelsInEngineSniffer && getTriggerCentral()->triggerShape.useOnlyRisingEdges; | |
519 | ||||
520 |
2/2✓ Branch 0 taken 66241 times.
✓ Branch 1 taken 966 times.
|
2/2✓ Decision 'true' taken 66241 times.
✓ Decision 'false' taken 966 times.
|
67207 | if (!logLogicState) { |
521 | // we log physical state even if displayLogicLevelsInEngineSniffer if both fronts are used by decoder | |||
522 | 66241 | LogTriggerTooth(signal, timestamp); | ||
523 | } | |||
524 | ||||
525 | #endif /* EFI_TOOTH_LOGGER */ | |||
526 | ||||
527 | // for effective noise filtering, we need both signal edges, | |||
528 | // so we pass them to handleShaftSignal() and defer this test | |||
529 |
2/2✓ Branch 0 taken 65299 times.
✓ Branch 1 taken 1908 times.
|
2/2✓ Decision 'true' taken 65299 times.
✓ Decision 'false' taken 1908 times.
|
67207 | if (!engineConfiguration->useNoiselessTriggerDecoder) { |
530 |
2/2✓ Branch 2 taken 29902 times.
✓ Branch 3 taken 35397 times.
|
2/2✓ Decision 'true' taken 29902 times.
✓ Decision 'false' taken 35397 times.
|
65299 | if (!isUsefulSignal(signal, getTriggerCentral()->triggerShape)) { |
531 | /** | |||
532 | * no need to process VR falls further | |||
533 | */ | |||
534 | 29902 | return; | ||
535 | } | |||
536 | } | |||
537 | ||||
538 | #if EFI_TOOTH_LOGGER | |||
539 |
2/2✓ Branch 0 taken 483 times.
✓ Branch 1 taken 36822 times.
|
2/2✓ Decision 'true' taken 483 times.
✓ Decision 'false' taken 36822 times.
|
37305 | if (logLogicState) { |
540 | // first log rising normally | |||
541 | 483 | LogTriggerTooth(signal, timestamp); | ||
542 | // in 'logLogicState' mode we log opposite front right after logical rising away | |||
543 |
1/2✓ Branch 0 taken 483 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 483 times.
✗ Decision 'false' not taken.
|
483 | if (signal == SHAFT_PRIMARY_RISING) { |
544 | 483 | LogTriggerTooth(SHAFT_PRIMARY_FALLING, timestamp); | ||
545 | } else { | |||
546 | ✗ | LogTriggerTooth(SHAFT_SECONDARY_FALLING, timestamp); | ||
547 | } | |||
548 | } | |||
549 | #endif /* EFI_TOOTH_LOGGER */ | |||
550 | ||||
551 | 37305 | uint32_t triggerHandlerEntryTime = getTimeNowLowerNt(); | ||
552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37305 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 37305 times.
|
37305 | if (triggerReentrant > maxTriggerReentrant) |
553 | ✗ | maxTriggerReentrant = triggerReentrant; | ||
554 | 37305 | triggerReentrant++; | ||
555 | ||||
556 | 37305 | getTriggerCentral()->handleShaftSignal(signal, timestamp); | ||
557 | ||||
558 | 37305 | triggerReentrant--; | ||
559 | 37305 | triggerDuration = getTimeNowLowerNt() - triggerHandlerEntryTime; | ||
560 | 37305 | triggerMaxDuration = maxI(triggerMaxDuration, triggerDuration); | ||
561 | } | |||
562 | ||||
563 | ✗ | void TriggerCentral::resetCounters() { | ||
564 | ✗ | memset(hwEventCounters, 0, sizeof(hwEventCounters)); | ||
565 | ✗ | } | ||
566 | ||||
567 | static const int wheelIndeces[4] = { 0, 0, 1, 1}; | |||
568 | ||||
569 | 36337 | static void reportEventToWaveChart(trigger_event_e ckpSignalType, int triggerEventIndex, bool addOppositeEvent) { | ||
570 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 36337 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 36337 times.
|
36337 | if (!getTriggerCentral()->isEngineSnifferEnabled) { // this is here just as a shortcut so that we avoid engine sniffer as soon as possible |
571 | ✗ | return; // engineSnifferRpmThreshold is accounted for inside getTriggerCentral()->isEngineSnifferEnabled | ||
572 | } | |||
573 | ||||
574 | 36337 | int wheelIndex = wheelIndeces[(int )ckpSignalType]; | ||
575 | ||||
576 | 36337 | bool isUp = isTriggerUpEvent(ckpSignalType); | ||
577 | ||||
578 |
2/2✓ Branch 0 taken 33604 times.
✓ Branch 1 taken 2733 times.
|
36337 | addEngineSnifferCrankEvent(wheelIndex, triggerEventIndex, isUp ? FrontDirection::UP : FrontDirection::DOWN); | |
579 |
2/2✓ Branch 0 taken 30875 times.
✓ Branch 1 taken 5462 times.
|
2/2✓ Decision 'true' taken 30875 times.
✓ Decision 'false' taken 5462 times.
|
36337 | if (addOppositeEvent) { |
580 | // let's add the opposite event right away | |||
581 |
1/2✓ Branch 0 taken 30875 times.
✗ Branch 1 not taken.
|
30875 | addEngineSnifferCrankEvent(wheelIndex, triggerEventIndex, isUp ? FrontDirection::DOWN : FrontDirection::UP); | |
582 | } | |||
583 | } | |||
584 | ||||
585 | /** | |||
586 | * This is used to filter noise spikes (interference) in trigger signal. See | |||
587 | * The basic idea is to use not just edges, but the average amount of time the signal stays in '0' or '1'. | |||
588 | * So we update 'accumulated periods' to track where the signal is. | |||
589 | * And then compare between the current period and previous, with some tolerance (allowing for the wheel speed change). | |||
590 | * @return true if the signal is passed through. | |||
591 | */ | |||
592 | 1908 | bool TriggerNoiseFilter::noiseFilter(efitick_t nowNt, | ||
593 | TriggerDecoderBase * triggerState, | |||
594 | trigger_event_e signal) { | |||
595 | // todo: find a better place for these defs | |||
596 | static const trigger_event_e opposite[4] = { SHAFT_PRIMARY_RISING, SHAFT_PRIMARY_FALLING, SHAFT_SECONDARY_RISING, SHAFT_SECONDARY_FALLING }; | |||
597 | static const TriggerWheel triggerIdx[4] = { TriggerWheel::T_PRIMARY, TriggerWheel::T_PRIMARY, TriggerWheel::T_SECONDARY, TriggerWheel:: T_SECONDARY }; | |||
598 | // we process all trigger channels independently | |||
599 | 1908 | TriggerWheel ti = triggerIdx[signal]; | ||
600 | // falling is opposite to rising, and vise versa | |||
601 | 1908 | trigger_event_e os = opposite[signal]; | ||
602 | ||||
603 | // todo: currently only primary channel is filtered, because there are some weird trigger types on other channels | |||
604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1908 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1908 times.
|
1908 | if (ti != TriggerWheel::T_PRIMARY) |
605 | ✗ | return true; | ||
606 | ||||
607 | // update period accumulator: for rising signal, we update '0' accumulator, and for falling - '1' | |||
608 |
2/2✓ Branch 1 taken 1894 times.
✓ Branch 2 taken 14 times.
|
2/2✓ Decision 'true' taken 1894 times.
✓ Decision 'false' taken 14 times.
|
1908 | if (lastSignalTimes[signal] != -1) |
609 | 1894 | accumSignalPeriods[signal] += nowNt - lastSignalTimes[signal]; | ||
610 | // save current time for this trigger channel | |||
611 | 1908 | lastSignalTimes[signal] = nowNt; | ||
612 | ||||
613 | // now we want to compare current accumulated period to the stored one | |||
614 | 1908 | efitick_t currentPeriod = accumSignalPeriods[signal]; | ||
615 | // the trick is to compare between different | |||
616 | 1908 | efitick_t allowedPeriod = accumSignalPrevPeriods[os]; | ||
617 | ||||
618 | // but first check if we're expecting a gap | |||
619 |
3/4✓ Branch 1 taken 1908 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1771 times.
✓ Branch 5 taken 137 times.
|
3679 | bool isGapExpected = TRIGGER_WAVEFORM(isSynchronizationNeeded) && triggerState->getShaftSynchronized() && | |
620 |
2/2✓ Branch 3 taken 32 times.
✓ Branch 4 taken 1739 times.
|
1771 | (triggerState->currentCycle.eventCount[(int)ti] + 1) == TRIGGER_WAVEFORM(getExpectedEventCount(ti)); | |
621 | ||||
622 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1876 times.
|
2/2✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 1876 times.
|
1908 | if (isGapExpected) { |
623 | // usually we need to extend the period for gaps, based on the trigger info | |||
624 | 32 | allowedPeriod *= TRIGGER_WAVEFORM(syncRatioAvg); | ||
625 | } | |||
626 | ||||
627 | // also we need some margin for rapidly changing trigger-wheel speed, | |||
628 | // that's why we expect the period to be no less than 2/3 of the previous period (this is just an empirical 'magic' coef.) | |||
629 | 1908 | efitick_t minAllowedPeriod = 2 * allowedPeriod / 3; | ||
630 | // but no longer than 5/4 of the previous 'normal' period | |||
631 | 1908 | efitick_t maxAllowedPeriod = 5 * allowedPeriod / 4; | ||
632 | ||||
633 | // above all, check if the signal comes not too early | |||
634 |
2/2✓ Branch 0 taken 1864 times.
✓ Branch 1 taken 44 times.
|
2/2✓ Decision 'true' taken 1864 times.
✓ Decision 'false' taken 44 times.
|
1908 | if (currentPeriod >= minAllowedPeriod) { |
635 | // now we store this period as a reference for the next time, | |||
636 | // BUT we store only 'normal' periods, and ignore too long periods (i.e. gaps) | |||
637 |
6/6✓ Branch 0 taken 1847 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1825 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 1580 times.
✓ Branch 5 taken 245 times.
|
2/2✓ Decision 'true' taken 1602 times.
✓ Decision 'false' taken 262 times.
|
1864 | if (!isGapExpected && (maxAllowedPeriod == 0 || currentPeriod <= maxAllowedPeriod)) { |
638 | 1602 | accumSignalPrevPeriods[signal] = currentPeriod; | ||
639 | } | |||
640 | // reset accumulator | |||
641 | 1864 | accumSignalPeriods[signal] = 0; | ||
642 | 1864 | return true; | ||
643 | } | |||
644 | // all premature or extra-long events are ignored - treated as interference | |||
645 | 44 | return false; | ||
646 | } | |||
647 | ||||
648 | 46 | bool TriggerCentral::isMapCamSync(efitick_t timestamp, float currentPhase) { | ||
649 | UNUSED(timestamp); | |||
650 | ||||
651 | // we are trying to figure out which 360 half of the total 720 degree cycle is which, so we compare those in 360 degree sense. | |||
652 | 46 | auto toothAngle360 = currentPhase; | ||
653 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 46 times.
|
2/2✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 46 times.
|
66 | while (toothAngle360 >= 360) { |
654 | 20 | toothAngle360 -= 360; | ||
655 | } | |||
656 | ||||
657 | bool result; | |||
658 |
4/4✓ Branch 0 taken 25 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 2 times.
|
2/2✓ Decision 'true' taken 23 times.
✓ Decision 'false' taken 23 times.
|
46 | if (mapCamPrevToothAngle < engineConfiguration->mapCamDetectionAnglePosition && toothAngle360 > engineConfiguration->mapCamDetectionAnglePosition) { |
659 | // we are somewhere close to 'mapCamDetectionAnglePosition' | |||
660 | ||||
661 | // warning: hack hack hack | |||
662 | 23 | float map = engine->outputChannels.instantMAPValue; | ||
663 | ||||
664 | // Compute diff against the last time we were here | |||
665 | 23 | float instantMapDiffBetweenReadoutAngles = map - mapCamPrevCycleValue; | ||
666 | 23 | mapCamPrevCycleValue = map; | ||
667 | ||||
668 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 21 times.
|
23 | if (instantMapDiffBetweenReadoutAngles > engineConfiguration->mapSyncThreshold) { |
669 | 2 | mapVvt_sync_counter++; | ||
670 | 2 | int revolutionCounter = getTriggerCentral()->triggerState.getSynchronizationCounter(); | ||
671 | 2 | mapVvt_MAP_AT_CYCLE_COUNT = revolutionCounter - prevChangeAtCycle; | ||
672 | 2 | prevChangeAtCycle = revolutionCounter; | ||
673 | 2 | result = true; | ||
674 | } else { | |||
675 | 21 | result = false; | ||
676 | } | |||
677 | ||||
678 | 23 | mapVvt_MAP_AT_SPECIAL_POINT = map; | ||
679 | 23 | mapVvt_MAP_AT_DIFF = instantMapDiffBetweenReadoutAngles; | ||
680 | 23 | } else { | ||
681 | 23 | result = false; | ||
682 | } | |||
683 | ||||
684 | 46 | mapCamPrevToothAngle = toothAngle360; | ||
685 | 46 | return result; | ||
686 | } | |||
687 | ||||
688 | #ifdef TEMP_V_TWIN | |||
689 | ||||
690 | float mapAtAngle[200]; | |||
691 | ||||
692 | #endif | |||
693 | ||||
694 | 31489 | void TriggerCentral::decodeMapCam(int toothIndexForListeners, efitick_t timestamp, float currentPhase) { | ||
695 | UNUSED(toothIndexForListeners); | |||
696 | ||||
697 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 31443 times.
|
31535 | isDecodingMapCam = engineConfiguration->vvtMode[0] == VVT_MAP_V_TWIN && | |
698 |
1/2✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
|
46 | Sensor::getOrZero(SensorType::Rpm) < engineConfiguration->cranking.rpm; | |
699 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 31443 times.
|
2/2✓ Decision 'true' taken 46 times.
✓ Decision 'false' taken 31443 times.
|
31489 | if (isDecodingMapCam) { |
700 | ||||
701 | ||||
702 | #ifdef TEMP_V_TWIN | |||
703 | mapAtAngle[toothIndexForListeners] = engine->outputChannels.instantMAPValue; | |||
704 | ||||
705 | if (toothIndexForListeners > 2) { | |||
706 | if (mapAtAngle[toothIndexForListeners - 2] > mapAtAngle[toothIndexForListeners - 1] && | |||
707 | mapAtAngle[toothIndexForListeners - 1] < mapAtAngle[toothIndexForListeners - 0]) { | |||
708 | mapVvt_min_point_counter++; | |||
709 | } | |||
710 | ||||
711 | } | |||
712 | #endif | |||
713 | ||||
714 | ||||
715 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 44 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 44 times.
|
46 | if (isMapCamSync(timestamp, currentPhase)) { |
716 | 2 | hwHandleVvtCamSignal(TriggerValue::RISE, timestamp, /*index*/0); | ||
717 | 2 | hwHandleVvtCamSignal(TriggerValue::FALL, timestamp, /*index*/0); | ||
718 | #if EFI_UNIT_TEST | |||
719 | // hack? feature? existing unit test relies on VVT phase available right away | |||
720 | // but current implementation which is based on periodicFastCallback would only make result available on NEXT tooth | |||
721 | 2 | getLimpManager()->onFastCallback(); | ||
722 | #endif // EFI_UNIT_TEST | |||
723 | } | |||
724 | } | |||
725 | 31489 | } | ||
726 | ||||
727 | 36338 | bool TriggerCentral::isToothExpectedNow(efitick_t timestamp) { | ||
728 | // Check that the expected next phase (from the last tooth) is close to the actual current phase: | |||
729 | // basically, check that the tooth width is correct | |||
730 |
1/1✓ Branch 2 taken 36338 times.
|
36338 | auto estimatedCurrentPhase = getCurrentEnginePhase(timestamp); | |
731 | 36338 | auto lastToothPhase = m_lastToothPhaseFromSyncPoint; | ||
732 | ||||
733 |
6/6✓ Branch 1 taken 31394 times.
✓ Branch 2 taken 4944 times.
✓ Branch 4 taken 31090 times.
✓ Branch 5 taken 304 times.
✓ Branch 6 taken 31090 times.
✓ Branch 7 taken 5248 times.
|
2/2✓ Decision 'true' taken 31090 times.
✓ Decision 'false' taken 5248 times.
|
36338 | if (expectedNextPhase && estimatedCurrentPhase) { |
734 | 31090 | float angleError = expectedNextPhase.Value - estimatedCurrentPhase.Value; | ||
735 | ||||
736 | // Wrap around correctly at the end of the cycle | |||
737 |
1/1✓ Branch 1 taken 31090 times.
|
31090 | float cycle = getEngineState()->engineCycle; | |
738 |
2/2✓ Branch 0 taken 2198 times.
✓ Branch 1 taken 28892 times.
|
2/2✓ Decision 'true' taken 2198 times.
✓ Decision 'false' taken 28892 times.
|
31090 | if (angleError < -cycle / 2) { |
739 | 2198 | angleError += cycle; | ||
740 | } | |||
741 | ||||
742 | 31090 | triggerToothAngleError = angleError; | ||
743 | ||||
744 | // Only perform checks if engine is spinning quickly | |||
745 | // All kinds of garbage happens while cranking | |||
746 |
3/3✓ Branch 1 taken 31090 times.
✓ Branch 3 taken 13681 times.
✓ Branch 4 taken 17409 times.
|
2/2✓ Decision 'true' taken 13681 times.
✓ Decision 'false' taken 17409 times.
|
31090 | if (Sensor::getOrZero(SensorType::Rpm) > 1000) { |
747 | // Now compute how close we are to the last tooth decoded | |||
748 | 13681 | float angleSinceLastTooth = estimatedCurrentPhase.Value - lastToothPhase; | ||
749 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 13680 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 13680 times.
|
13681 | if (angleSinceLastTooth < 0.5f) { |
750 | // This tooth came impossibly early, ignore it | |||
751 | // This rejects things like doubled edges, for example: | |||
752 | // |-| |---------------- | |||
753 | // | | | | |||
754 | // ____________| |_| | |||
755 | // 1 2 | |||
756 | // #1 will be decoded | |||
757 | // #2 will be ignored | |||
758 | // We're not sure which edge was the "real" one, but they were close enough | |||
759 | // together that it doesn't really matter. | |||
760 |
1/1✓ Branch 1 taken 1 time.
|
1 | warning(ObdCode::CUSTOM_PRIMARY_DOUBLED_EDGE, "doubled trigger edge after %.2f deg at #%d", angleSinceLastTooth, triggerState.currentCycle.current_index); | |
761 | ||||
762 | 1 | return false; | ||
763 | } | |||
764 | ||||
765 | // Absolute error from last tooth | |||
766 | 13680 | float absError = absF(angleError); | ||
767 |
2/3✓ Branch 1 taken 13680 times.
✓ Branch 3 taken 13680 times.
✗ Branch 4 not taken.
|
13680 | float isRpmEnough = Sensor::getOrZero(SensorType::Rpm) > 1000; | |
768 | // TODO: configurable threshold | |||
769 |
5/6✓ Branch 0 taken 13680 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 13506 times.
✓ Branch 4 taken 169 times.
✓ Branch 5 taken 5 times.
|
2/2✓ Decision 'true' taken 169 times.
✓ Decision 'false' taken 13511 times.
|
13680 | if (isRpmEnough && absError > 10 && absError < 180) { |
770 | // This tooth came at a very unexpected time, ignore it | |||
771 |
1/1✓ Branch 1 taken 169 times.
|
169 | warning(ObdCode::CUSTOM_PRIMARY_BAD_TOOTH_TIMING, "tooth #%d error of %.1f", triggerState.currentCycle.current_index, angleError); | |
772 | ||||
773 | // TODO: this causes issues with some real engine logs, should it? | |||
774 | // return false; | |||
775 | } | |||
776 | } | |||
777 | } else { | |||
778 | 5248 | triggerToothAngleError = 0; | ||
779 | } | |||
780 | ||||
781 | // We aren't ready to reject unexpected teeth, so accept this tooth | |||
782 | 36337 | return true; | ||
783 | } | |||
784 | ||||
785 | 36337 | PUBLIC_API_WEAK bool boardAllowTriggerActions() { return true; } | ||
786 | ||||
787 | 31489 | angle_t TriggerCentral::findNextTriggerToothAngle(int p_currentToothIndex) { | ||
788 | 31489 | int currentToothIndex = p_currentToothIndex; | ||
789 | // TODO: is this logic to compute next trigger tooth angle correct? | |||
790 | 31489 | angle_t nextToothAngle = 0; | ||
791 | ||||
792 | 31489 | int loopAllowance = 2 * engineCycleEventCount + 1000; | ||
793 | do { | |||
794 | // I don't love this. | |||
795 | 77923 | currentToothIndex = (currentToothIndex + 1) % engineCycleEventCount; | ||
796 |
4/4✓ Branch 1 taken 77923 times.
✓ Branch 5 taken 77923 times.
✓ Branch 7 taken 910 times.
✓ Branch 8 taken 77013 times.
|
77923 | nextToothAngle = getTriggerCentral()->triggerFormDetails.eventAngles[currentToothIndex] - tdcPosition(); | |
797 |
1/1✓ Branch 1 taken 77923 times.
|
77923 | wrapAngle(nextToothAngle, "nextEnginePhase", ObdCode::CUSTOM_ERR_6555); | |
798 |
6/6✓ Branch 0 taken 46454 times.
✓ Branch 1 taken 31469 times.
✓ Branch 2 taken 46434 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 46434 times.
✓ Branch 5 taken 31489 times.
|
0/1? Decision couldn't be analyzed.
|
77923 | } while (nextToothAngle == currentEngineDecodedPhase && --loopAllowance > 0); // '==' for float works here since both values come from 'eventAngles' array |
799 |
3/4✓ Branch 0 taken 30282 times.
✓ Branch 1 taken 1207 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30282 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 31489 times.
|
31489 | if (nextToothAngle != 0 && loopAllowance == 0) { |
800 | // HW CI fails here, looks like we sometimes change trigger while still handling it? | |||
801 | ✗ | firmwareError(ObdCode::CUSTOM_ERR_TRIGGER_ZERO, "handleShaftSignal unexpected loop end %d %d %f %f", p_currentToothIndex, engineCycleEventCount, nextToothAngle, currentEngineDecodedPhase); | ||
802 | } | |||
803 | 31489 | return nextToothAngle; | ||
804 | } | |||
805 | ||||
806 | /** | |||
807 | * This method is NOT invoked for VR falls. | |||
808 | */ | |||
809 | 37307 | void TriggerCentral::handleShaftSignal(trigger_event_e signal, efitick_t timestamp) { | ||
810 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37307 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 37307 times.
|
37307 | if (triggerShape.shapeDefinitionError) { |
811 | // trigger is broken, we cannot do anything here | |||
812 | ✗ | warning(ObdCode::CUSTOM_ERR_UNEXPECTED_SHAFT_EVENT, "Shaft event while trigger is mis-configured"); | ||
813 | ✗ | return; | ||
814 | } | |||
815 | ||||
816 | // This code gathers some statistics on signals and compares accumulated periods to filter interference | |||
817 |
2/2✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 35399 times.
|
2/2✓ Decision 'true' taken 1908 times.
✓ Decision 'false' taken 35399 times.
|
37307 | if (engineConfiguration->useNoiselessTriggerDecoder) { |
818 |
3/3✓ Branch 1 taken 1908 times.
✓ Branch 3 taken 44 times.
✓ Branch 4 taken 1864 times.
|
2/2✓ Decision 'true' taken 44 times.
✓ Decision 'false' taken 1864 times.
|
1908 | if (!noiseFilter.noiseFilter(timestamp, &triggerState, signal)) { |
819 | 44 | return; | ||
820 | } | |||
821 |
3/3✓ Branch 1 taken 1864 times.
✓ Branch 3 taken 925 times.
✓ Branch 4 taken 939 times.
|
2/2✓ Decision 'true' taken 925 times.
✓ Decision 'false' taken 939 times.
|
1864 | if (!isUsefulSignal(signal, triggerShape)) { |
822 | 925 | return; | ||
823 | } | |||
824 | } | |||
825 | ||||
826 |
3/3✓ Branch 1 taken 36338 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 36337 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 36337 times.
|
36338 | if (!isToothExpectedNow(timestamp)) { |
827 | 1 | triggerIgnoredToothCount++; | ||
828 | 1 | return; | ||
829 | } | |||
830 | ||||
831 | 36337 | isSpinningJustForWatchdog = true; | ||
832 | ||||
833 | #if EFI_HD_ACR | |||
834 | bool firstEventInAWhile = m_lastEventTimer.hasElapsedSec(1); | |||
835 | if (firstEventInAWhile) { | |||
836 | // let's open that valve on first sign of movement | |||
837 | engine->module<HarleyAcr>()->updateAcr(); | |||
838 | } | |||
839 | #endif // EFI_HD_ACR | |||
840 | ||||
841 |
2/3✓ Branch 1 taken 36337 times.
✓ Branch 3 taken 36337 times.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 36337 times.
✗ Decision 'false' not taken.
|
36337 | if (boardAllowTriggerActions()) { |
842 |
1/1✓ Branch 1 taken 36337 times.
|
36337 | m_lastEventTimer.reset(timestamp); | |
843 | } | |||
844 | ||||
845 | 36337 | int eventIndex = (int) signal; | ||
846 |
2/5✓ Branch 0 taken 36337 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36337 times.
✗ Branch 5 not taken.
|
36337 | efiAssertVoid(ObdCode::CUSTOM_TRIGGER_EVENT_TYPE, eventIndex >= 0 && eventIndex < HW_EVENT_TYPES, "signal type"); | |
847 | 36337 | hwEventCounters[eventIndex]++; | ||
848 | ||||
849 | // Decode the trigger! | |||
850 | 36337 | auto decodeResult = triggerState.decodeTriggerEvent( | ||
851 | "trigger", | |||
852 |
1/1✓ Branch 1 taken 36337 times.
|
36337 | triggerShape, | |
853 | engine, | |||
854 | primaryTriggerConfiguration, | |||
855 | signal, timestamp); | |||
856 | ||||
857 | // Don't propagate state if we don't know where we are | |||
858 |
2/2✓ Branch 1 taken 31489 times.
✓ Branch 2 taken 4848 times.
|
2/2✓ Decision 'true' taken 31489 times.
✓ Decision 'false' taken 4848 times.
|
36337 | if (decodeResult) { |
859 | 31489 | ScopePerf perf(PE::ShaftPositionListeners); | ||
860 | ||||
861 | /** | |||
862 | * If we only have a crank position sensor with four stroke, here we are extending crank revolutions with a 360 degree | |||
863 | * cycle into a four stroke, 720 degrees cycle. | |||
864 | */ | |||
865 |
2/2✓ Branch 1 taken 31489 times.
✓ Branch 4 taken 31489 times.
|
31489 | int crankDivider = getCrankDivider(triggerShape.getWheelOperationMode()); | |
866 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | int crankInternalIndex = triggerState.getSynchronizationCounter() % crankDivider; | |
867 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | int triggerIndexForListeners = decodeResult.Value.CurrentIndex + (crankInternalIndex * triggerShape.getSize()); | |
868 | ||||
869 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | reportEventToWaveChart(signal, triggerIndexForListeners, triggerShape.useOnlyRisingEdges); | |
870 | ||||
871 | // Look up this tooth's angle from the sync point. If this tooth is the sync point, we'll get 0 here. | |||
872 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | auto currentPhaseFromSyncPoint = getTriggerCentral()->triggerFormDetails.eventAngles[triggerIndexForListeners]; | |
873 | ||||
874 | // Adjust so currentPhase is in engine-space angle, not trigger-space angle | |||
875 |
4/4✓ Branch 1 taken 31489 times.
✓ Branch 3 taken 455 times.
✓ Branch 4 taken 31034 times.
✓ Branch 6 taken 31489 times.
|
31489 | currentEngineDecodedPhase = wrapAngleMethod(currentPhaseFromSyncPoint - tdcPosition(), "currentEnginePhase", ObdCode::CUSTOM_ERR_6555); | |
876 | ||||
877 | // Record precise time and phase of the engine. This is used for VVT decode, and to check that the | |||
878 | // trigger pattern selected matches reality (ie, we check the next tooth is where we think it should be) | |||
879 | { | |||
880 | // under lock to avoid mismatched tooth phase and time | |||
881 | chibios_rt::CriticalSectionLocker csl; | |||
882 | ||||
883 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | m_lastToothTimer.reset(timestamp); | |
884 | 31489 | m_lastToothPhaseFromSyncPoint = currentPhaseFromSyncPoint; | ||
885 | } | |||
886 | ||||
887 | #if TRIGGER_EXTREME_LOGGING | |||
888 | efiPrintf("trigger %d %d %d", triggerIndexForListeners, getRevolutionCounter(), time2print(getTimeNowUs())); | |||
889 | #endif /* TRIGGER_EXTREME_LOGGING */ | |||
890 | ||||
891 | // Update engine RPM | |||
892 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | rpmShaftPositionCallback(signal, triggerIndexForListeners, timestamp); | |
893 | ||||
894 | // Schedule the TDC mark | |||
895 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | tdcMarkCallback(triggerIndexForListeners, timestamp); | |
896 | ||||
897 | #if EFI_LOGIC_ANALYZER | |||
898 | waTriggerEventListener(signal, triggerIndexForListeners, timestamp); | |||
899 | #endif | |||
900 | ||||
901 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | angle_t nextPhase = findNextTriggerToothAngle(triggerIndexForListeners); | |
902 | ||||
903 |
3/3✓ Branch 2 taken 31489 times.
✓ Branch 4 taken 455 times.
✓ Branch 5 taken 31034 times.
|
31489 | float expectNextPhase = nextPhase + tdcPosition(); | |
904 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | wrapAngle(expectNextPhase, "nextEnginePhase", ObdCode::CUSTOM_ERR_6555); | |
905 | 31489 | expectedNextPhase = expectNextPhase; | ||
906 | ||||
907 | #if EFI_CDM_INTEGRATION | |||
908 | if (trgEventIndex == 0 && isBrainPinValid(engineConfiguration->cdmInputPin)) { | |||
909 | int cdmKnockValue = getCurrentCdmValue(getTriggerCentral()->triggerState.getSynchronizationCounter()); | |||
910 | engine->knockLogic(cdmKnockValue); | |||
911 | } | |||
912 | #endif /* EFI_CDM_INTEGRATION */ | |||
913 | ||||
914 |
7/7✓ Branch 1 taken 31489 times.
✓ Branch 3 taken 31184 times.
✓ Branch 4 taken 305 times.
✓ Branch 5 taken 2250 times.
✓ Branch 6 taken 28934 times.
✓ Branch 7 taken 2250 times.
✓ Branch 8 taken 29239 times.
|
2/2✓ Decision 'true' taken 2250 times.
✓ Decision 'false' taken 29239 times.
|
31489 | if (engine->rpmCalculator.getCachedRpm() > 0 && triggerIndexForListeners == 0) { |
915 |
2/2✓ Branch 1 taken 2250 times.
✓ Branch 5 taken 2250 times.
|
2250 | engine->module<TpsAccelEnrichment>()->onEngineCycleTps(); | |
916 | } | |||
917 | ||||
918 | // Handle ignition and injection | |||
919 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | mainTriggerCallback(triggerIndexForListeners, timestamp, currentEngineDecodedPhase, nextPhase); | |
920 | ||||
921 | 31489 | temp_mapVvt_index = triggerIndexForListeners / 2; | ||
922 | ||||
923 | // Decode the MAP based "cam" sensor | |||
924 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | decodeMapCam(temp_mapVvt_index, timestamp, currentEngineDecodedPhase); | |
925 | ||||
926 |
1/1✓ Branch 1 taken 31489 times.
|
31489 | boardTriggerCallback(timestamp, currentEngineDecodedPhase); | |
927 | } else { | |||
928 | // We don't have sync, but report to the wave chart anyway as index 0. | |||
929 |
1/1✓ Branch 1 taken 4848 times.
|
4848 | reportEventToWaveChart(signal, 0, triggerShape.useOnlyRisingEdges); | |
930 | ||||
931 | 4848 | expectedNextPhase = unexpected; | ||
932 | } | |||
933 | } | |||
934 | ||||
935 | ✗ | static void triggerShapeInfo() { | ||
936 | #if EFI_PROD_CODE || EFI_SIMULATOR | |||
937 | TriggerWaveform *shape = &getTriggerCentral()->triggerShape; | |||
938 | TriggerFormDetails *triggerFormDetails = &getTriggerCentral()->triggerFormDetails; | |||
939 | efiPrintf("syncEdge=%s", getSyncEdge(TRIGGER_WAVEFORM(syncEdge))); | |||
940 | efiPrintf("gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0])); | |||
941 | ||||
942 | for (size_t i = 0; i < shape->getSize(); i++) { | |||
943 | efiPrintf("event %d %.2f", i, triggerFormDetails->eventAngles[i]); | |||
944 | } | |||
945 | #endif | |||
946 | ✗ | } | ||
947 | ||||
948 | #if EFI_PROD_CODE | |||
949 | extern PwmConfig triggerEmulatorSignals[NUM_EMULATOR_CHANNELS]; | |||
950 | #endif /* #if EFI_PROD_CODE */ | |||
951 | ||||
952 | ✗ | void triggerInfo(void) { | ||
953 | #if EFI_PROD_CODE || EFI_SIMULATOR | |||
954 | ||||
955 | TriggerCentral *tc = getTriggerCentral(); | |||
956 | TriggerWaveform *ts = &tc->triggerShape; | |||
957 | ||||
958 | ||||
959 | #if (HAL_TRIGGER_USE_PAL == TRUE) && (PAL_USE_CALLBACKS == TRUE) | |||
960 | efiPrintf("trigger PAL mode %d", tc->hwTriggerInputEnabled); | |||
961 | #else | |||
962 | ||||
963 | #endif /* HAL_TRIGGER_USE_PAL */ | |||
964 | ||||
965 | efiPrintf("Template %s (%d) trigger %s (%d) syncEdge=%s tdcOffset=%.2f", | |||
966 | getEngine_type_e(engineConfiguration->engineType), | |||
967 | (int)engineConfiguration->engineType, | |||
968 | getTrigger_type_e(engineConfiguration->trigger.type), | |||
969 | (int)engineConfiguration->trigger.type, | |||
970 | getSyncEdge(TRIGGER_WAVEFORM(syncEdge)), TRIGGER_WAVEFORM(tdcPosition)); | |||
971 | ||||
972 | if (engineConfiguration->trigger.type == trigger_type_e::TT_TOOTHED_WHEEL) { | |||
973 | efiPrintf("total %d/skipped %d", engineConfiguration->trigger.customTotalToothCount, | |||
974 | engineConfiguration->trigger.customSkippedToothCount); | |||
975 | } | |||
976 | ||||
977 | ||||
978 | efiPrintf("trigger#1 event counters up=%d/down=%d", tc->getHwEventCounter(0), | |||
979 | tc->getHwEventCounter(1)); | |||
980 | ||||
981 | if (ts->needSecondTriggerInput) { | |||
982 | efiPrintf("trigger#2 event counters up=%d/down=%d", tc->getHwEventCounter(2), | |||
983 | tc->getHwEventCounter(3)); | |||
984 | } | |||
985 | efiPrintf("expected cycle events %d/%d", | |||
986 | TRIGGER_WAVEFORM(getExpectedEventCount(TriggerWheel::T_PRIMARY)), | |||
987 | TRIGGER_WAVEFORM(getExpectedEventCount(TriggerWheel::T_SECONDARY))); | |||
988 | ||||
989 | efiPrintf("trigger type=%d/need2ndChannel=%s", (int)engineConfiguration->trigger.type, | |||
990 | boolToString(TRIGGER_WAVEFORM(needSecondTriggerInput))); | |||
991 | ||||
992 | ||||
993 | efiPrintf("synchronizationNeeded=%s/isError=%s/total errors=%lu ord_err=%lu/total revolutions=%d/self=%s", | |||
994 | boolToString(ts->isSynchronizationNeeded), | |||
995 | boolToString(tc->isTriggerDecoderError()), | |||
996 | tc->triggerState.totalTriggerErrorCounter, | |||
997 | tc->triggerState.orderingErrorCounter, | |||
998 | tc->triggerState.getSynchronizationCounter(), | |||
999 | boolToString(tc->directSelfStimulation)); | |||
1000 | ||||
1001 | if (TRIGGER_WAVEFORM(isSynchronizationNeeded)) { | |||
1002 | efiPrintf("gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0])); | |||
1003 | } | |||
1004 | ||||
1005 | #endif /* EFI_PROD_CODE || EFI_SIMULATOR */ | |||
1006 | ||||
1007 | #if EFI_PROD_CODE | |||
1008 | ||||
1009 | efiPrintf("primary trigger input: %s", hwPortname(engineConfiguration->triggerInputPins[0])); | |||
1010 | efiPrintf("primary trigger simulator: %s %s freq=%d", | |||
1011 | hwPortname(engineConfiguration->triggerSimulatorPins[0]), | |||
1012 | getPin_output_mode_e(engineConfiguration->triggerSimulatorPinModes[0]), | |||
1013 | engineConfiguration->triggerSimulatorRpm); | |||
1014 | ||||
1015 | if (ts->needSecondTriggerInput) { | |||
1016 | efiPrintf("secondary trigger input: %s", hwPortname(engineConfiguration->triggerInputPins[1])); | |||
1017 | #if EFI_EMULATE_POSITION_SENSORS | |||
1018 | efiPrintf("secondary trigger simulator: %s %s phase=%d", | |||
1019 | hwPortname(engineConfiguration->triggerSimulatorPins[1]), | |||
1020 | getPin_output_mode_e(engineConfiguration->triggerSimulatorPinModes[1]), triggerEmulatorSignals[0].safe.phaseIndex); | |||
1021 | #endif /* EFI_EMULATE_POSITION_SENSORS */ | |||
1022 | } | |||
1023 | ||||
1024 | ||||
1025 | for (int camInputIndex = 0; camInputIndex<CAM_INPUTS_COUNT;camInputIndex++) { | |||
1026 | if (isBrainPinValid(engineConfiguration->camInputs[camInputIndex])) { | |||
1027 | int camLogicalIndex = camInputIndex % CAMS_PER_BANK; | |||
1028 | efiPrintf("VVT input: %s mode %s", hwPortname(engineConfiguration->camInputs[camInputIndex]), | |||
1029 | getVvt_mode_e(engineConfiguration->vvtMode[camLogicalIndex])); | |||
1030 | efiPrintf("VVT %d event counters: %d/%d", | |||
1031 | camInputIndex, | |||
1032 | tc->vvtEventRiseCounter[camInputIndex], tc->vvtEventFallCounter[camInputIndex]); | |||
1033 | } | |||
1034 | } | |||
1035 | ||||
1036 | efiPrintf("primary logic input: %s", hwPortname(engineConfiguration->logicAnalyzerPins[0])); | |||
1037 | efiPrintf("secondary logic input: %s", hwPortname(engineConfiguration->logicAnalyzerPins[1])); | |||
1038 | ||||
1039 | ||||
1040 | efiPrintf("totalTriggerHandlerMaxTime=%lu", triggerMaxDuration); | |||
1041 | ||||
1042 | #endif /* EFI_PROD_CODE */ | |||
1043 | ||||
1044 | #if EFI_ENGINE_SNIFFER | |||
1045 | ✗ | efiPrintf("engine sniffer current size=%d", waveChart.getSize()); | ||
1046 | #endif /* EFI_ENGINE_SNIFFER */ | |||
1047 | ||||
1048 | ✗ | } | ||
1049 | ||||
1050 | ✗ | static void resetRunningTriggerCounters() { | ||
1051 | #if !EFI_UNIT_TEST | |||
1052 | getTriggerCentral()->resetCounters(); | |||
1053 | triggerInfo(); | |||
1054 | #endif | |||
1055 | ✗ | } | ||
1056 | ||||
1057 | 219 | void onConfigurationChangeTriggerCallback() { | ||
1058 | 219 | bool changed = false; | ||
1059 | // todo: how do we static_assert here? | |||
1060 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 219 times.
|
219 | criticalAssertVoid(efi::size(engineConfiguration->camInputs) == efi::size(engineConfiguration->vvtOffsets), "sizes"); | |
1061 | ||||
1062 |
2/2✓ Branch 1 taken 876 times.
✓ Branch 2 taken 219 times.
|
2/2✓ Decision 'true' taken 876 times.
✓ Decision 'false' taken 219 times.
|
1095 | for (size_t camIndex = 0; camIndex < efi::size(engineConfiguration->camInputs); camIndex++) { |
1063 | 876 | changed |= isConfigurationChanged(camInputs[camIndex]); | ||
1064 | 876 | changed |= isConfigurationChanged(vvtOffsets[camIndex]); | ||
1065 | } | |||
1066 | ||||
1067 |
2/2✓ Branch 1 taken 3942 times.
✓ Branch 2 taken 219 times.
|
2/2✓ Decision 'true' taken 3942 times.
✓ Decision 'false' taken 219 times.
|
4161 | for (size_t i = 0; i < efi::size(engineConfiguration->triggerGapOverrideFrom); i++) { |
1068 | 3942 | changed |= isConfigurationChanged(triggerGapOverrideFrom[i]); | ||
1069 | 3942 | changed |= isConfigurationChanged(triggerGapOverrideTo[i]); | ||
1070 | } | |||
1071 | ||||
1072 |
2/2✓ Branch 1 taken 438 times.
✓ Branch 2 taken 219 times.
|
2/2✓ Decision 'true' taken 438 times.
✓ Decision 'false' taken 219 times.
|
657 | for (size_t i = 0; i < efi::size(engineConfiguration->triggerInputPins); i++) { |
1073 | 438 | changed |= isConfigurationChanged(triggerInputPins[i]); | ||
1074 | 438 | Gpio pin = engineConfiguration->camInputs[i]; | ||
1075 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 438 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 438 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 438 times.
|
438 | if (engineConfiguration->vvtMode[0] == VVT_MAP_V_TWIN && isBrainPinValid(pin)) { |
1076 | ✗ | criticalError("Please no physical sensors in CAM by MAP mode index=%d %s", i, hwPortname(pin)); | ||
1077 | } | |||
1078 | } | |||
1079 | ||||
1080 |
2/2✓ Branch 1 taken 438 times.
✓ Branch 2 taken 219 times.
|
2/2✓ Decision 'true' taken 438 times.
✓ Decision 'false' taken 219 times.
|
657 | for (size_t i = 0; i < efi::size(engineConfiguration->vvtMode); i++) { |
1081 | 438 | changed |= isConfigurationChanged(vvtMode[i]); | ||
1082 | } | |||
1083 | ||||
1084 | 219 | changed |= isConfigurationChanged(trigger.type); | ||
1085 | 219 | changed |= isConfigurationChanged(skippedWheelOnCam); | ||
1086 | 219 | changed |= isConfigurationChanged(twoStroke); | ||
1087 | 219 | changed |= isConfigurationChanged(globalTriggerAngleOffset); | ||
1088 | 219 | changed |= isConfigurationChanged(trigger.customTotalToothCount); | ||
1089 | 219 | changed |= isConfigurationChanged(trigger.customSkippedToothCount); | ||
1090 | 219 | changed |= isConfigurationChanged(overrideTriggerGaps); | ||
1091 | 219 | changed |= isConfigurationChanged(gapTrackingLengthOverride); | ||
1092 | 219 | changed |= isConfigurationChanged(overrideVvtTriggerGaps); | ||
1093 | 219 | changed |= isConfigurationChanged(gapVvtTrackingLengthOverride); | ||
1094 | ||||
1095 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 111 times.
|
2/2✓ Decision 'true' taken 108 times.
✓ Decision 'false' taken 111 times.
|
219 | if (changed) { |
1096 | #if EFI_ENGINE_CONTROL | |||
1097 | 108 | engine->updateTriggerConfiguration(); | ||
1098 | 108 | getTriggerCentral()->noiseFilter.resetAccumSignalData(); | ||
1099 | #endif | |||
1100 | } | |||
1101 | #if EFI_DETAILED_LOGGING | |||
1102 | efiPrintf("isTriggerConfigChanged=%d", triggerConfigChanged); | |||
1103 | #endif /* EFI_DETAILED_LOGGING */ | |||
1104 | ||||
1105 | // we do not want to miss two updates in a row | |||
1106 |
4/4✓ Branch 1 taken 114 times.
✓ Branch 2 taken 105 times.
✓ Branch 3 taken 107 times.
✓ Branch 4 taken 7 times.
|
219 | getTriggerCentral()->triggerConfigChangedOnLastConfigurationChange = getTriggerCentral()->triggerConfigChangedOnLastConfigurationChange || changed; | |
1107 | } | |||
1108 | ||||
1109 | 80 | static void initVvtShape(int camIndex, TriggerWaveform& shape, const TriggerConfiguration& p_config, TriggerDecoderBase &initState) { | ||
1110 | 80 | shape.initializeTriggerWaveform(FOUR_STROKE_CAM_SENSOR, p_config.TriggerType, /*isCrank*/ false); | ||
1111 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 4 times.
|
2/2✓ Decision 'true' taken 76 times.
✓ Decision 'false' taken 4 times.
|
80 | if (camIndex == 0) { |
1112 | // at the moment we only support override of first cam | |||
1113 | // nasty code: this implicitly adjusts 'shape' parameter | |||
1114 | 76 | getTriggerCentral()->applyCamGapOverride(); | ||
1115 | } | |||
1116 | 80 | shape.initializeSyncPoint(initState, p_config); | ||
1117 | 80 | } | ||
1118 | ||||
1119 | 702 | void TriggerCentral::validateCamVvtCounters() { | ||
1120 | // micro-optimized 'synchronizationCounter % 256' | |||
1121 | 702 | int camVvtValidationIndex = triggerState.getSynchronizationCounter() & 0xFF; | ||
1122 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 691 times.
|
2/2✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 691 times.
|
702 | if (camVvtValidationIndex == 0) { |
1123 | 11 | vvtCamCounter = 0; | ||
1124 |
4/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 687 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 689 times.
|
691 | } else if (camVvtValidationIndex == 0xFE && vvtCamCounter < 60) { |
1125 | // magic logic: we expect at least 60 CAM/VVT events for each 256 trigger cycles, otherwise throw a code | |||
1126 | 2 | warning(ObdCode::OBD_Camshaft_Position_Sensor_Circuit_Range_Performance, "No Camshaft Position Sensor signals"); | ||
1127 | } | |||
1128 | 702 | } | ||
1129 | /** | |||
1130 | * Calculate 'shape.triggerShapeSynchPointIndex' value using 'TriggerDecoderBase *state' | |||
1131 | */ | |||
1132 | 905 | static void calculateTriggerSynchPoint( | ||
1133 | const PrimaryTriggerConfiguration &primaryTriggerConfiguration, | |||
1134 | TriggerWaveform& shape, | |||
1135 | TriggerDecoderBase& initState) { | |||
1136 | ||||
1137 | #if EFI_PROD_CODE | |||
1138 | efiAssertVoid(ObdCode::CUSTOM_TRIGGER_STACK, hasLotsOfRemainingStack(), "calc s"); | |||
1139 | #endif | |||
1140 | ||||
1141 | 905 | shape.initializeSyncPoint(initState, primaryTriggerConfiguration); | ||
1142 | ||||
1143 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 905 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 905 times.
|
905 | if (shape.getSize() >= PWM_PHASE_MAX_COUNT) { |
1144 | // todo: by the time we are here we had already modified a lot of RAM out of bounds! | |||
1145 | ✗ | firmwareError(ObdCode::CUSTOM_ERR_TRIGGER_WAVEFORM_TOO_LONG, "Trigger length above maximum: %d", shape.getSize()); | ||
1146 | ✗ | shape.setShapeDefinitionError(true); | ||
1147 | ✗ | return; | ||
1148 | } | |||
1149 | ||||
1150 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 905 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 905 times.
|
905 | if (shape.getSize() == 0) { |
1151 | ✗ | firmwareError(ObdCode::CUSTOM_ERR_TRIGGER_ZERO, "triggerShape size is zero"); | ||
1152 | } | |||
1153 | } | |||
1154 | ||||
1155 | TriggerDecoderBase initState("init"); | |||
1156 | ||||
1157 | 905 | void TriggerCentral::applyTriggerGapOverride() { | ||
1158 | /** | |||
1159 | * this is only useful while troubleshooting a new trigger shape in the field | |||
1160 | * in very VERY rare circumstances | |||
1161 | */ | |||
1162 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 883 times.
|
2/2✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 883 times.
|
905 | if (engineConfiguration->overrideTriggerGaps) { |
1163 | 22 | int gapIndex = 0; | ||
1164 | ||||
1165 | 22 | triggerShape.gapTrackingLength = engineConfiguration->gapTrackingLengthOverride; | ||
1166 | ||||
1167 | // copy however many the user wants | |||
1168 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 22 times.
|
2/2✓ Decision 'true' taken 64 times.
✓ Decision 'false' taken 22 times.
|
86 | for (; gapIndex < engineConfiguration->gapTrackingLengthOverride; gapIndex++) { |
1169 | 64 | float gapOverrideFrom = engineConfiguration->triggerGapOverrideFrom[gapIndex]; | ||
1170 | 64 | float gapOverrideTo = engineConfiguration->triggerGapOverrideTo[gapIndex]; | ||
1171 | 64 | triggerShape.setTriggerSynchronizationGap3(/*gapIndex*/gapIndex, gapOverrideFrom, gapOverrideTo); | ||
1172 | } | |||
1173 | ||||
1174 | // fill the remainder with the default gaps | |||
1175 |
2/2✓ Branch 0 taken 332 times.
✓ Branch 1 taken 22 times.
|
2/2✓ Decision 'true' taken 332 times.
✓ Decision 'false' taken 22 times.
|
354 | for (; gapIndex < GAP_TRACKING_LENGTH; gapIndex++) { |
1176 | 332 | triggerShape.synchronizationRatioFrom[gapIndex] = NAN; | ||
1177 | 332 | triggerShape.synchronizationRatioTo[gapIndex] = NAN; | ||
1178 | } | |||
1179 | } | |||
1180 | 905 | } | ||
1181 | ||||
1182 | 981 | void TriggerCentral::applyCamGapOverride() { | ||
1183 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 981 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 981 times.
|
981 | if (engineConfiguration->overrideVvtTriggerGaps) { |
1184 | ✗ | int gapIndex = 0; | ||
1185 | ||||
1186 | ✗ | TriggerWaveform *shape = &vvtShape[0]; | ||
1187 | ✗ | shape->gapTrackingLength = engineConfiguration->gapVvtTrackingLengthOverride; | ||
1188 | ||||
1189 | ✗ | for (; gapIndex < engineConfiguration->gapVvtTrackingLengthOverride; gapIndex++) { | ||
1190 | ✗ | float gapOverrideFrom = engineConfiguration->triggerVVTGapOverrideFrom[gapIndex]; | ||
1191 | ✗ | float gapOverrideTo = engineConfiguration->triggerVVTGapOverrideTo[gapIndex]; | ||
1192 | ✗ | shape->synchronizationRatioFrom[gapIndex] = gapOverrideFrom; | ||
1193 | ✗ | shape->synchronizationRatioTo[gapIndex] = gapOverrideTo; | ||
1194 | } | |||
1195 | // fill the remainder with the default gaps | |||
1196 | ✗ | for (; gapIndex < VVT_TRACKING_LENGTH; gapIndex++) { | ||
1197 | ✗ | shape->synchronizationRatioFrom[gapIndex] = NAN; | ||
1198 | ✗ | shape->synchronizationRatioTo[gapIndex] = NAN; | ||
1199 | } | |||
1200 | } | |||
1201 | 981 | } | ||
1202 | ||||
1203 | 905 | void TriggerCentral::applyShapesConfiguration() { | ||
1204 | // Re-read config in case it's changed | |||
1205 | 905 | primaryTriggerConfiguration.update(); | ||
1206 |
2/2✓ Branch 0 taken 1810 times.
✓ Branch 1 taken 905 times.
|
2/2✓ Decision 'true' taken 1810 times.
✓ Decision 'false' taken 905 times.
|
2715 | for (int camIndex = 0;camIndex < CAMS_PER_BANK;camIndex++) { |
1207 | 1810 | vvtTriggerConfiguration[camIndex].update(); | ||
1208 | } | |||
1209 | ||||
1210 | 905 | triggerShape.initializeTriggerWaveform(lookupOperationMode(), primaryTriggerConfiguration.TriggerType); | ||
1211 | ||||
1212 | 905 | applyTriggerGapOverride(); | ||
1213 | ||||
1214 |
1/2✓ Branch 0 taken 905 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 905 times.
✗ Decision 'false' not taken.
|
905 | if (!triggerShape.shapeDefinitionError) { |
1215 | 905 | int length = triggerShape.getLength(); | ||
1216 | 905 | engineCycleEventCount = length; | ||
1217 | ||||
1218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 905 times.
|
905 | efiAssertVoid(ObdCode::CUSTOM_SHAPE_LEN_ZERO, length > 0, "shapeLength=0"); | |
1219 | ||||
1220 | 905 | triggerErrorDetection.clear(); | ||
1221 | ||||
1222 | /** | |||
1223 | * 'initState' instance of TriggerDecoderBase is used only to initialize 'this' TriggerWaveform instance | |||
1224 | * #192 BUG real hardware trigger events could be coming even while we are initializing trigger | |||
1225 | */ | |||
1226 | 905 | calculateTriggerSynchPoint(primaryTriggerConfiguration, | ||
1227 | 905 | triggerShape, | ||
1228 | initState); | |||
1229 | } | |||
1230 | ||||
1231 | 905 | applyCamGapOverride(); | ||
1232 | ||||
1233 |
2/2✓ Branch 0 taken 1810 times.
✓ Branch 1 taken 905 times.
|
2/2✓ Decision 'true' taken 1810 times.
✓ Decision 'false' taken 905 times.
|
2715 | for (int camIndex = 0; camIndex < CAMS_PER_BANK; camIndex++) { |
1234 | // todo: should 'vvtWithRealDecoder' be used here? | |||
1235 |
2/2✓ Branch 1 taken 80 times.
✓ Branch 2 taken 1730 times.
|
2/2✓ Decision 'true' taken 80 times.
✓ Decision 'false' taken 1730 times.
|
1810 | if (engineConfiguration->vvtMode[camIndex] != VVT_INACTIVE) { |
1236 | 160 | initVvtShape( | ||
1237 | camIndex, | |||
1238 | 80 | vvtShape[camIndex], | ||
1239 | 80 | vvtTriggerConfiguration[camIndex], | ||
1240 | initState | |||
1241 | ); | |||
1242 | } | |||
1243 | } | |||
1244 | ||||
1245 | // This is not the right place for this, but further refactoring has to happen before it can get moved. | |||
1246 | 905 | triggerState.setNeedsDisambiguation(engine->triggerCentral.triggerShape.needsDisambiguation()); | ||
1247 | ||||
1248 | } | |||
1249 | ||||
1250 | /** | |||
1251 | * @returns true if configuration just changed, and if that change has affected trigger | |||
1252 | */ | |||
1253 | 2250 | bool TriggerCentral::checkIfTriggerConfigChanged() { | ||
1254 | // we want to make sure that configuration has changed AND that change has changed trigger specifically | |||
1255 |
4/4✓ Branch 2 taken 111 times.
✓ Branch 3 taken 2139 times.
✓ Branch 4 taken 86 times.
✓ Branch 5 taken 25 times.
|
2250 | bool result = triggerVersion.isOld(engine->getGlobalConfigurationVersion()) && triggerConfigChangedOnLastConfigurationChange; | |
1256 | 2250 | triggerConfigChangedOnLastConfigurationChange = false; // whoever has called the method is supposed to react to changes | ||
1257 | 2250 | return result; | ||
1258 | } | |||
1259 | ||||
1260 | #if EFI_UNIT_TEST | |||
1261 | 123 | bool TriggerCentral::isTriggerConfigChanged() { | ||
1262 | 123 | return triggerConfigChangedOnLastConfigurationChange; | ||
1263 | } | |||
1264 | #endif // EFI_UNIT_TEST | |||
1265 | ||||
1266 | 802 | void validateTriggerInputs() { | ||
1267 |
4/6✓ Branch 1 taken 795 times.
✓ Branch 2 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 795 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 802 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 802 times.
|
802 | if (!isBrainPinValid(engineConfiguration->triggerInputPins[0]) && isBrainPinValid(engineConfiguration->triggerInputPins[1])) { |
1268 | ✗ | criticalError("First trigger channel not configured while second one is."); | ||
1269 | } | |||
1270 | ||||
1271 |
4/6✓ Branch 1 taken 791 times.
✓ Branch 2 taken 11 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 791 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 802 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 802 times.
|
802 | if (!isBrainPinValid(engineConfiguration->camInputs[0]) && isBrainPinValid(engineConfiguration->camInputs[2])) { |
1272 | ✗ | criticalError("First bank cam input is required if second bank specified"); | ||
1273 | } | |||
1274 | 802 | } | ||
1275 | ||||
1276 | ✗ | void initTriggerCentral() { | ||
1277 | ||||
1278 | #if EFI_ENGINE_SNIFFER | |||
1279 | ✗ | initWaveChart(&waveChart); | ||
1280 | #endif /* EFI_ENGINE_SNIFFER */ | |||
1281 | ||||
1282 | #if EFI_PROD_CODE || EFI_SIMULATOR | |||
1283 | addConsoleAction(CMD_TRIGGERINFO, triggerInfo); | |||
1284 | addConsoleAction("trigger_shape_info", triggerShapeInfo); | |||
1285 | addConsoleAction("reset_trigger", resetRunningTriggerCounters); | |||
1286 | #endif // EFI_PROD_CODE || EFI_SIMULATOR | |||
1287 | ||||
1288 | ✗ | } | ||
1289 | ||||
1290 | /** | |||
1291 | * @return TRUE is something is wrong with trigger decoding | |||
1292 | */ | |||
1293 | ✗ | bool TriggerCentral::isTriggerDecoderError() { | ||
1294 | ✗ | return triggerErrorDetection.sum(6) > 4; | ||
1295 | } | |||
1296 | ||||
1297 | #endif // EFI_SHAFT_POSITION_INPUT | |||
1298 |