GCC Code Coverage Report


Directory: ./
File: firmware/controllers/trigger/decoders/trigger_universal.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 96.8% 91 0 94
Functions: 100.0% 11 0 11
Branches: 82.1% 23 0 28
Decisions: 87.5% 7 - 8

Line Branch Decision Exec Source
1 /*
2 * @file trigger_universal.cpp
3 *
4 * @date Jan 3, 2017
5 * @author Andrey Belomutskiy, (c) 2012-2020
6 */
7
8 #include "pch.h"
9
10 #include "trigger_universal.h"
11
12 /**
13 * @see getCycleDuration
14 */
15 128350 angle_t getEngineCycle(operation_mode_e operationMode) {
16
2/2
✓ Branch 0 taken 2826 times.
✓ Branch 1 taken 125524 times.
128350 return operationMode == TWO_STROKE ? 360 : FOUR_STROKE_ENGINE_CYCLE;
17 }
18
19 /**
20 * last fall aligned at 720 and skipped area is right before 720
21 */
22 277 void addSkippedToothTriggerEvents(TriggerWheel wheel, TriggerWaveform *s, int totalTeethCount, int skippedCount,
23 float toothWidthPercentage, float offset, float engineCycle, float filterLeft, float filterRight) {
24
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 277 times.
277 criticalAssertVoid(totalTeethCount > 0, "total count");
25
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 277 times.
277 criticalAssertVoid(skippedCount >= 0, "skipped count");
26
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 277 times.
277 criticalAssertVoid(toothWidthPercentage < 1, "toothWidthPercentage");
27
28 277 float oneTooth = engineCycle / totalTeethCount;
29
30
2/2
✓ Branch 0 taken 4632 times.
✓ Branch 1 taken 277 times.
2/2
✓ Decision 'true' taken 4632 times.
✓ Decision 'false' taken 277 times.
4909 for (int i = 0; i < totalTeethCount - skippedCount - 1; i++) {
31 4632 float angleDown = oneTooth * (i + (1 - toothWidthPercentage));
32 4632 float angleUp = oneTooth * (i + 1);
33 4632 s->addEventClamped(offset + angleDown, TriggerValue::RISE, wheel, filterLeft, filterRight);
34 4632 s->addEventClamped(offset + angleUp, TriggerValue::FALL, wheel, filterLeft, filterRight);
35 }
36
37 277 float angleDown = oneTooth * (totalTeethCount - skippedCount - 1 + (1 - toothWidthPercentage));
38 277 s->addEventClamped(offset + angleDown, TriggerValue::RISE, wheel, filterLeft, filterRight);
39 // custom handling of last event in order to avoid rounding error
40 277 s->addEventClamped(offset + engineCycle, TriggerValue::FALL, wheel, filterLeft, filterRight);
41 }
42
43 242 void initializeSkippedToothTrigger(TriggerWaveform *s, int totalTeethCount, int skippedCount,
44 operation_mode_e operationMode, SyncEdge syncEdge) {
45
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 242 times.
242 if (totalTeethCount <= 0) {
46 firmwareError(ObdCode::CUSTOM_OBD_TRIGGER_WAVEFORM, "Invalid total tooth count for missing tooth decoder: %d", totalTeethCount);
47 s->setShapeDefinitionError(true);
48 return;
49 }
50
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 efiAssertVoid(ObdCode::CUSTOM_NULL_SHAPE, s != NULL, "TriggerWaveform is NULL");
51
52 242 s->initialize(operationMode, syncEdge);
53
54 #if EFI_UNIT_TEST
55 242 s->knownOperationMode = false;
56 #endif // EFI_UNIT_TEST
57
58 242 s->setTriggerSynchronizationGap(skippedCount + 1);
59
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 152 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 4 times.
2/2
✓ Decision 'true' taken 86 times.
✓ Decision 'false' taken 156 times.
242 if (totalTeethCount > 6 && skippedCount > 0) {
60 // this gap is not required to synch on perfect signal but is needed to handle to reject cranking transition noise and potentially high rev noise as well
61 86 s->setSecondTriggerSynchronizationGap(1);
62 }
63
4/4
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 115 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 99 times.
242 s->shapeWithoutTdc = (totalTeethCount > 1) && (skippedCount == 0);
64
4/4
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 120 times.
✓ Branch 2 taken 97 times.
✓ Branch 3 taken 25 times.
242 s->isSynchronizationNeeded = (totalTeethCount > 2) && (skippedCount != 0);
65
66
67 242 addSkippedToothTriggerEvents(TriggerWheel::T_PRIMARY, s, totalTeethCount, skippedCount, 0.5, 0, getEngineCycle(operationMode),
68 NO_LEFT_FILTER, NO_RIGHT_FILTER);
69 }
70
71 520 void configureOnePlusOne(TriggerWaveform *s) {
72 520 s->initialize(FOUR_STROKE_CAM_SENSOR, SyncEdge::Rise);
73
74 520 s->addEvent360( 90, TriggerValue::RISE, TriggerWheel::T_PRIMARY);
75 520 s->addEvent360(180, TriggerValue::FALL, TriggerWheel::T_PRIMARY);
76
77 520 s->addEvent360(270, TriggerValue::RISE, TriggerWheel::T_SECONDARY);
78 520 s->addEvent360(360, TriggerValue::FALL, TriggerWheel::T_SECONDARY);
79
80 520 s->isSynchronizationNeeded = false;
81 520 s->useOnlyPrimaryForSync = true;
82 520 }
83
84 1 void configure3_1_cam(TriggerWaveform *s) {
85 1 s->initialize(FOUR_STROKE_CAM_SENSOR, SyncEdge::RiseOnly);
86
87
88 1 const float crankW = 360 / 3 / 2;
89
90
91 1 TriggerWheel crank = TriggerWheel::T_SECONDARY;
92
93 1 s->addEvent720(10, TriggerValue::RISE, TriggerWheel::T_PRIMARY);
94 1 s->addEvent720(50, TriggerValue::FALL, TriggerWheel::T_PRIMARY);
95
96
97 1 float a = 2 * crankW;
98
99 // #1/3
100 1 s->addEvent720(a += crankW, TriggerValue::RISE, crank);
101 1 s->addEvent720(a += crankW, TriggerValue::FALL, crank);
102 // #2/3
103 1 s->addEvent720(a += crankW, TriggerValue::RISE, crank);
104 1 s->addEvent720(a += crankW, TriggerValue::FALL, crank);
105 // #3/3
106 1 a += crankW;
107 1 a += crankW;
108
109 // 2nd #1/3
110 1 s->addEvent720(a += crankW, TriggerValue::RISE, crank);
111 1 s->addEvent720(a += crankW, TriggerValue::FALL, crank);
112
113 // 2nd #2/3
114 1 s->addEvent720(a += crankW, TriggerValue::RISE, crank);
115 1 s->addEvent720(a += crankW, TriggerValue::FALL, crank);
116
117 1 s->isSynchronizationNeeded = false;
118 1 }
119
120 /**
121 * https://rusefi.com/forum/viewtopic.php?f=5&t=1977
122 */
123 1 void configureKawaKX450F(TriggerWaveform *s) {
124 1 float engineCycle = FOUR_STROKE_ENGINE_CYCLE;
125 1 s->initialize(FOUR_STROKE_CRANK_SENSOR, SyncEdge::Rise);
126
127 1 s->setTriggerSynchronizationGap(2.28);
128
129 1 float toothWidth = 3 / 20.0;
130
131 1 addSkippedToothTriggerEvents(TriggerWheel::T_PRIMARY, s, 18, 0, toothWidth, 0, engineCycle,
132 NO_LEFT_FILTER, 720 - 39);
133
134 1 s->addToothRiseFall(360, /* width*/10.80);
135 1 }
136
137 // TT_VVT_BOSCH_QUICK_START
138 17 void configureQuickStartSenderWheel(TriggerWaveform *s) {
139 // todo: most cam wheels are defined as 'SyncEdge::Rise' or 'SyncEdge::RiseOnly' shall we unify?
140 17 s->initialize(FOUR_STROKE_CAM_SENSOR, SyncEdge::Fall);
141
142 // our preference is to sync not too close to crank sync point
143 17 s->setTriggerSynchronizationGap(0.645);
144 17 s->setSecondTriggerSynchronizationGap(1.556);
145
146 17 s->addToothRiseFall(90, /* width*/ 70);
147 17 s->addToothRiseFall(130, /* width*/ 20);
148 17 s->addToothRiseFall(220, /* width*/ 20);
149 17 s->addToothRiseFall(360, /* width*/ 70);
150 17 }
151
152 15 static void commonSymmetrical(TriggerWaveform* s, int count, float gapFrom, float gapTo) {
153 15 s->shapeWithoutTdc = true;
154
155 // Sync after 2 good teeth
156
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 15 times.
2/2
✓ Decision 'true' taken 30 times.
✓ Decision 'false' taken 15 times.
45 for (size_t i = 0; i < 2; i++) {
157 /**
158 * https://github.com/rusefi/rusefi/issues/4943#issuecomment-1376289608
159 * gaps would be nice during running but horrible during running
160 * Hopefully we do not want variable gap logic yet?
161 */
162 30 s->setTriggerSynchronizationGap3(i, gapFrom, gapTo);
163 }
164
165 15 float width = 360 / count;
166
167 // Just a single tooth with 50% duty cycle
168 15 s->addEventAngle(width / 2, TriggerValue::FALL, TriggerWheel::T_PRIMARY);
169 15 s->addEventAngle(width, TriggerValue::RISE, TriggerWheel::T_PRIMARY);
170 15 }
171
172 // Useful for:
173 // - Honda 24+1 (set this on crank primary, single tooth cam)
174 // - AEM 24+1 CAS wheel (same config as Honda)
175 3 void configure12ToothCrank(TriggerWaveform* s) {
176 3 s->initialize(FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR, SyncEdge::RiseOnly);
177
178 // 2JZ would be global trigger offset 65 but same wheel could be Honda, not hard coding for now
179 3 commonSymmetrical(s, 12, 0.2f, 3.4f);
180 3 }
181
182 11 void configure3ToothCrank(TriggerWaveform* s) {
183 11 s->initialize(FOUR_STROKE_THREE_TIMES_CRANK_SENSOR, SyncEdge::RiseOnly);
184 11 commonSymmetrical(s, 3, 0.5, 1.4);
185 11 }
186
187 1 void configure6ToothCrank(TriggerWaveform* s) {
188 1 s->initialize(FOUR_STROKE_SIX_TIMES_CRANK_SENSOR, SyncEdge::RiseOnly);
189 1 commonSymmetrical(s, 6, 0.7, 1.4);
190 1 }
191