GCC Code Coverage Report


Directory: ./
File: firmware/controllers/trigger/trigger_decoder.h
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 94.7% 18 0 19
Functions: 90.9% 10 0 11
Branches: -% 0 0 0
Decisions: -% 0 - 0

Line Branch Decision Exec Source
1 /**
2 * @file trigger_decoder.h
3 *
4 * @date Dec 24, 2013
5 * @author Andrey Belomutskiy, (c) 2012-2020
6 */
7
8 #pragma once
9
10 #include "trigger_structure.h"
11 #include "trigger_state_generated.h"
12 #include "trigger_state_primary_generated.h"
13 #include <rusefi/timer.h>
14
15 const char *getTrigger_event_e(trigger_event_e value);
16 const char *getTrigger_value_e(TriggerValue value);
17
18 struct TriggerStateListener {
19 #if EFI_SHAFT_POSITION_INPUT
20 virtual void OnTriggerStateProperState(efitick_t nowNt, size_t triggerStateIndex) = 0;
21 virtual void OnTriggerSynchronization(bool wasSynchronized, bool isDecodingError) = 0;
22 virtual void OnTriggerSynchronizationLost() = 0;
23 // todo: replace this dirty hack with proper collection (linked list?) of listeners
24 virtual TriggerStateListener* nextListener() = 0;
25 #endif // EFI_SHAFT_POSITION_INPUT
26 };
27
28 class TriggerConfiguration {
29 public:
30 2185 explicit TriggerConfiguration(const char* printPrefix) : PrintPrefix(printPrefix) {}
31 void update();
32
33 const char* const PrintPrefix;
34 bool VerboseTriggerSynchDetails;
35 trigger_config_s TriggerType;
36
37 protected:
38 virtual bool isVerboseTriggerSynchDetails() const = 0;
39 public:
40 virtual trigger_config_s getType() const = 0;
41 };
42
43 class PrimaryTriggerConfiguration final : public TriggerConfiguration {
44 public:
45 677 PrimaryTriggerConfiguration() : TriggerConfiguration("TRG ") {}
46
47 protected:
48 bool isVerboseTriggerSynchDetails() const override;
49 trigger_config_s getType() const override;
50 };
51
52 class VvtTriggerConfiguration final : public TriggerConfiguration {
53 public:
54 const int index;
55
56 1354 VvtTriggerConfiguration(const char * prefix, const int p_index) : TriggerConfiguration(prefix), index(p_index) {
57 1354 }
58
59 protected:
60 bool isVerboseTriggerSynchDetails() const override;
61 trigger_config_s getType() const override;
62 };
63
64 typedef struct {
65 /**
66 * index within trigger revolution, from 0 to trigger event count
67 */
68 uint32_t current_index;
69 /**
70 * Number of actual events of each channel within current trigger cycle, these
71 * values are used to detect trigger signal errors.
72 * see TriggerWaveform
73 */
74 size_t eventCount[PWM_PHASE_MAX_WAVE_PER_PWM];
75
76 } current_cycle_state_s;
77
78 struct TriggerDecodeResult {
79 uint32_t CurrentIndex;
80 };
81
82 /**
83 * @see TriggerWaveform for trigger wheel shape definition
84 */
85 class TriggerDecoderBase : public trigger_state_s {
86 public:
87 TriggerDecoderBase(const char* name);
88
89 void printGaps(const char * prefix,
90 const TriggerConfiguration& triggerConfiguration,
91 const TriggerWaveform& triggerShape);
92
93 /**
94 * current trigger processing index, between zero and #size
95 */
96 int getCurrentIndex() const;
97 int getSynchronizationCounter() const;
98 /**
99 * this is important for crank-based virtual trigger and VVT magic
100 */
101 void incrementShaftSynchronizationCounter();
102
103 #if EFI_UNIT_TEST
104 /**
105 * used only for trigger export
106 */
107 float gapRatio[PWM_PHASE_MAX_COUNT * 6];
108 #endif // EFI_UNIT_TEST
109
110 int64_t getTotalEventCounter() const;
111
112 expected<TriggerDecodeResult> decodeTriggerEvent(
113 const char *msg,
114 const TriggerWaveform& triggerShape,
115 TriggerStateListener* triggerStateListener,
116 const TriggerConfiguration& triggerConfiguration,
117 const trigger_event_e signal,
118 const efitick_t nowNt);
119
120 void onShaftSynchronization(
121 bool wasSynchronized,
122 const efitick_t nowNt,
123 const TriggerWaveform& triggerShape);
124
125 bool isValidIndex(const TriggerWaveform& triggerShape) const;
126
127 /**
128 * TRUE if we know where we are
129 */
130 bool shaft_is_synchronized = false;
131 efitick_t mostRecentSyncTime;
132
133 Timer previousEventTimer;
134
135 /**
136 * current duration at index zero and previous durations are following
137 */
138 uint32_t toothDurations[GAP_TRACKING_LENGTH + 1];
139
140 efitick_t toothed_previous_time;
141
142 current_cycle_state_s currentCycle;
143 const char* const name;
144
145 /**
146 * how many times since ECU reboot we had unexpected number of teeth in trigger cycle
147 */
148 uint32_t totalTriggerErrorCounter;
149 uint32_t orderingErrorCounter;
150
151 virtual void resetState();
152 void setShaftSynchronized(bool value);
153 bool getShaftSynchronized() const;
154
155 /**
156 * this is start of real trigger cycle
157 * for virtual double trigger see timeAtVirtualZeroNt
158 */
159 efitick_t startOfCycleNt;
160
161 uint32_t findTriggerZeroEventIndex(
162 TriggerWaveform& shape,
163 const TriggerConfiguration& triggerConfiguration
164 );
165
166 196181 bool someSortOfTriggerError() const {
167 196181 return !m_timeSinceDecodeError.hasElapsedSec(0.3);
168 }
169
170 protected:
171 // Called when some problem is detected with trigger decoding.
172 // That means either:
173 // - Too many events without a sync point
174 // - Saw a sync point but the wrong number of events in the cycle
175 39 virtual void onTriggerError() { }
176
177 12 virtual void onNotEnoughTeeth(int, int) { }
178 virtual void onTooManyTeeth(int, int) { }
179
180 private:
181 void setTriggerErrorState(int errorIncrement = 1);
182 void resetCurrentCycleState();
183 bool isSyncPoint(const TriggerWaveform& triggerShape, trigger_type_e triggerType) const;
184
185 int getEventCountersError(const TriggerWaveform& triggerShape) const;
186
187 trigger_event_e prevSignal;
188 int64_t totalEventCountBase;
189
190 bool isFirstEvent;
191
192 Timer m_timeSinceDecodeError;
193 };
194
195 /**
196 * the reason for sub-class is simply to save RAM but not having statistics in the trigger initialization instance
197 */
198 class PrimaryTriggerDecoder : public TriggerDecoderBase, public trigger_state_primary_s {
199 public:
200 PrimaryTriggerDecoder(const char* name);
201 void resetState() override;
202
203 1785 void resetHasFullSync() {
204 // If this trigger doesn't need disambiguation, we already have phase sync
205 1785 m_hasSynchronizedPhase = !m_needsDisambiguation;
206 1785 }
207
208 /**
209 * returns zero if we were lucky to have correct engine phase, otherwise angle of engine phase correction which was applied.
210 */
211 angle_t syncEnginePhase(int divider, int remainder, angle_t engineCycle);
212
213 // Returns true if syncEnginePhase has been called,
214 // i.e. if we have enough VVT information to have full sync on
215 // an indeterminate crank pattern
216 123711 bool hasSynchronizedPhase() const {
217 123711 return m_hasSynchronizedPhase;
218 }
219
220 908 void setNeedsDisambiguation(bool needsDisambiguation) {
221 908 m_needsDisambiguation = needsDisambiguation;
222
223 908 resetHasFullSync();
224 908 }
225
226 void onTriggerError() override;
227
228 void onNotEnoughTeeth(int actual, int expected) override;
229 void onTooManyTeeth(int actual, int expected) override;
230
231 private:
232
233 bool m_needsDisambiguation = false;
234 };
235
236 class VvtTriggerDecoder : public TriggerDecoderBase {
237 public:
238 2708 VvtTriggerDecoder(const char* p_name) : TriggerDecoderBase(p_name) { }
239
240 void onNotEnoughTeeth(int actual, int expected) override;
241 void onTooManyTeeth(int actual, int expected) override;
242 };
243
244 angle_t getEngineCycle(operation_mode_e operationMode);
245