rusEFI
The most advanced open source ECU
trigger_central.h
Go to the documentation of this file.
1 /*
2  * @file trigger_central.h
3  *
4  * @date Feb 23, 2014
5  * @author Andrey Belomutskiy, (c) 2012-2020
6  */
7 
8 #pragma once
9 
10 #include "rusefi_enums.h"
11 #include "listener_array.h"
12 #include "trigger_decoder.h"
13 #include "instant_rpm_calculator.h"
15 #include <rusefi/timer.h>
16 #include "pin_repository.h"
17 #include "local_version_holder.h"
18 #include "cyclic_buffer.h"
19 
20 #define MAP_CAM_BUFFER 64
21 
22 #ifndef RPM_LOW_THRESHOLD
23 // no idea what is the best value, 25 is as good as any other guess
24 #define RPM_LOW_THRESHOLD 25
25 #endif
26 
27 class Engine;
28 typedef void (*ShaftPositionListener)(trigger_event_e signal, uint32_t index, efitick_t edgeTimestamp);
29 
30 #define HAVE_CAM_INPUT() (isBrainPinValid(engineConfiguration->camInputs[0]))
31 
33 public:
34  void resetAccumSignalData();
35  bool noiseFilter(efitick_t nowNt,
36  TriggerDecoderBase* triggerState,
37  trigger_event_e signal);
38 
39  efitick_t lastSignalTimes[HW_EVENT_TYPES];
40  efitick_t accumSignalPeriods[HW_EVENT_TYPES];
41  efitick_t accumSignalPrevPeriods[HW_EVENT_TYPES];
42 };
43 
44 /**
45  * Maybe merge TriggerCentral and TriggerState classes into one class?
46  * Probably not: we have an instance of TriggerState which is used for trigger initialization,
47  * also composition probably better than inheritance here
48  */
49 class TriggerCentral final : public trigger_central_s {
50 public:
52  /**
53  * we have two kinds of sync:
54  * this method is about detecting of exact engine phase with 720 degree precision usually based on cam wheel decoding
55  * not to be confused with a totally different trigger _wheel_ sync which could be either crank wheel sync or cam wheel sync
56  */
57  angle_t syncEnginePhaseAndReport(int divider, int remainder);
58  void handleShaftSignal(trigger_event_e signal, efitick_t timestamp);
59  int getHwEventCounter(int index) const;
60  void resetCounters();
62  void updateWaveform();
63 
64  angle_t findNextTriggerToothAngle(int nextToothIndex);
65 
67 
69 #if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
71  // Nothing to do here if there's a problem with the trigger shape
72  return;
73  }
74 
76 #endif
77  }
78 
79  // this is useful at least for real hardware integration testing - maybe a proper solution would be to simply
80  // GND input pins instead of leaving them floating
81  bool hwTriggerInputEnabled = true;
82 
83  cyclic_buffer<int> triggerErrorDetection;
84 
85  /**
86  * See also triggerSimulatorRpm
87  */
88  bool directSelfStimulation = false;
89 
91 #if CAMS_PER_BANK == 1
92  VvtTriggerConfiguration vvtTriggerConfiguration[CAMS_PER_BANK] = {{"VVT1 ", 0}};
93 #else
94  VvtTriggerConfiguration vvtTriggerConfiguration[CAMS_PER_BANK] = {{"VVT1 ", 0}, {"VVT2 ", 1}};
95 #endif
96 
98 
99  /**
100  * By the way:
101  * 'cranking' means engine is not stopped and the rpm are below crankingRpm
102  * 'running' means RPM are above crankingRpm
103  * 'spinning' means the engine is not stopped
104  */
105  // todo: combine with other RpmCalculator fields?
106  /**
107  * this is set to true each time we register a trigger tooth signal
108  */
110 
113 
114  /**
115  * value of 'triggerShape.getLength()'
116  * pre-calculating this value is a performance optimization
117  */
118  uint32_t engineCycleEventCount = 0;
119  /**
120  * true if a recent configuration change has changed any of the trigger settings which
121  * we have not adjusted for yet
122  */
124 
126 #if EFI_UNIT_TEST
127  bool isTriggerConfigChanged();
128 #endif // EFI_UNIT_TEST
129 
130  bool isTriggerDecoderError();
131 
132  expected<float> getCurrentEnginePhase(efitick_t nowNt) const;
133 
134  float getSecondsSinceTriggerEvent(efitick_t nowNt) const {
135  return m_lastEventTimer.getElapsedSeconds(nowNt);
136  }
137 
138  bool engineMovedRecently(efitick_t nowNt) const {
139  // todo: this user-defined property is a quick solution, proper fix https://github.com/rusefi/rusefi/issues/6593 is needed
141  return false;
142  }
143 
144  constexpr float oneRevolutionLimitInSeconds = 60.0 / RPM_LOW_THRESHOLD;
145  auto maxAverageToothTime = oneRevolutionLimitInSeconds / triggerShape.getSize();
146 
147  // Some triggers may have long gaps (with many teeth), don't count that as stopped!
148  auto maxAllowedGap = maxAverageToothTime * 10;
149 
150  // Clamp between 0.1 seconds ("instant" for a human) and worst case of one engine cycle on low tooth count wheel
151  maxAllowedGap = clampF(0.1f, maxAllowedGap, oneRevolutionLimitInSeconds);
152 
153  return getSecondsSinceTriggerEvent(nowNt) < maxAllowedGap;
154  }
155 
156  bool engineMovedRecently() const {
158  }
159 
161 
162  int vvtEventRiseCounter[CAM_INPUTS_COUNT];
163  int vvtEventFallCounter[CAM_INPUTS_COUNT];
164 
165  angle_t getVVTPosition(uint8_t bankIndex, uint8_t camIndex);
166 
167 #if EFI_UNIT_TEST
168  // latest VVT event position (could be not synchronization event)
169  angle_t currentVVTEventPosition[BANKS_COUNT][CAMS_PER_BANK];
170 #endif // EFI_UNIT_TEST
171 
172  // synchronization event position
173  angle_t vvtPosition[BANKS_COUNT][CAMS_PER_BANK];
174 
175 #if EFI_SHAFT_POSITION_INPUT
177 #endif //EFI_SHAFT_POSITION_INPUT
178 
180 
181  VvtTriggerDecoder vvtState[BANKS_COUNT][CAMS_PER_BANK] = {
182  {
183  "VVT B1 Int",
184 #if CAMS_PER_BANK >= 2
185  "VVT B1 Exh"
186 #endif
187  },
188 #if BANKS_COUNT >= 2
189  {
190  "VVT B2 Int",
191 #if CAMS_PER_BANK >= 2
192  "VVT B1 Exh"
193 #endif
194  }
195 #endif
196  };
197 
198  TriggerWaveform vvtShape[CAMS_PER_BANK];
199 
201 
202  // Keep track of the last time we got a valid trigger event
204 
205  /**
206  * this is based on engineSnifferRpmThreshold settings and current RPM
207  */
209 
210 private:
211  void decodeMapCam(efitick_t nowNt, float currentPhase);
212 
213  bool isToothExpectedNow(efitick_t timestamp);
214 
215  // Time since the last tooth
217  // Phase of the last tooth relative to the sync point
219 
220  // At what engine phase do we expect the next tooth to arrive?
221  // Used for checking whether your trigger pattern is correct.
222  expected<float> expectedNextPhase = unexpected;
223 };
224 
225 void triggerInfo(void);
226 void hwHandleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp);
227 void handleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp);
228 void hwHandleVvtCamSignal(TriggerValue front, efitick_t timestamp, int index);
229 void hwHandleVvtCamSignal(bool isRising, efitick_t timestamp, int index);
230 void handleVvtCamSignal(TriggerValue front, efitick_t timestamp, int index);
231 
232 void validateTriggerInputs();
233 
234 void initTriggerCentral();
235 
237 
239 
240 #define SYMMETRICAL_CRANK_SENSOR_DIVIDER (2 * 2)
241 #define SYMMETRICAL_THREE_TIMES_CRANK_SENSOR_DIVIDER (3 * 2)
242 #define SYMMETRICAL_SIX_TIMES_CRANK_SENSOR_DIVIDER (6 * 2)
243 #define SYMMETRICAL_TWELVE_TIMES_CRANK_SENSOR_DIVIDER (12 * 2)
244 
246 int getCrankDivider(operation_mode_e operationMode);
Definition: engine.h:90
VvtTriggerDecoder vvtState[BANKS_COUNT][CAMS_PER_BANK]
bool engineMovedRecently() const
float getSecondsSinceTriggerEvent(efitick_t nowNt) const
InstantRpmCalculator instantRpm
PrimaryTriggerDecoder triggerState
float m_lastToothPhaseFromSyncPoint
bool engineMovedRecently(efitick_t nowNt) const
angle_t findNextTriggerToothAngle(int nextToothIndex)
angle_t getVVTPosition(uint8_t bankIndex, uint8_t camIndex)
TriggerWaveform vvtShape[CAMS_PER_BANK]
LocalVersionHolder triggerVersion
int getHwEventCounter(int index) const
int vvtEventFallCounter[CAM_INPUTS_COUNT]
bool isSpinningJustForWatchdog
expected< float > expectedNextPhase
TriggerWaveform triggerShape
bool isToothExpectedNow(efitick_t timestamp)
angle_t vvtPosition[BANKS_COUNT][CAMS_PER_BANK]
TriggerFormDetails triggerFormDetails
void handleShaftSignal(trigger_event_e signal, efitick_t timestamp)
float mapCamPrevCycleValue
TriggerNoiseFilter noiseFilter
bool checkIfTriggerConfigChanged()
cyclic_buffer< int > triggerErrorDetection
VvtTriggerConfiguration vvtTriggerConfiguration[CAMS_PER_BANK]
void decodeMapCam(efitick_t nowNt, float currentPhase)
int vvtEventRiseCounter[CAM_INPUTS_COUNT]
expected< float > getCurrentEnginePhase(efitick_t nowNt) const
bool directSelfStimulation
bool hwTriggerInputEnabled
bool triggerConfigChangedOnLastConfigurationChange
void prepareTriggerShape()
PrimaryTriggerConfiguration primaryTriggerConfiguration
angle_t currentVVTEventPosition[BANKS_COUNT][CAMS_PER_BANK]
uint32_t engineCycleEventCount
angle_t syncEnginePhaseAndReport(int divider, int remainder)
void prepareEventAngles(TriggerWaveform *shape)
efitick_t accumSignalPrevPeriods[HW_EVENT_TYPES]
bool noiseFilter(efitick_t nowNt, TriggerDecoderBase *triggerState, trigger_event_e signal)
efitick_t accumSignalPeriods[HW_EVENT_TYPES]
efitick_t lastSignalTimes[HW_EVENT_TYPES]
Trigger shape has all the fields needed to describe and decode trigger signal.
size_t getSize() const
efitick_t getTimeNowNt()
Definition: efitime.cpp:19
engine_configuration_s * engineConfiguration
I/O pin registry header.
Fundamental rusEFI enumerable types live here.
operation_mode_e
Definition: rusefi_enums.h:251
float angle_t
Definition: rusefi_types.h:59
trigger_event_e
TriggerValue
void handleVvtCamSignal(TriggerValue front, efitick_t timestamp, int index)
int getCrankDivider(operation_mode_e operationMode)
void validateTriggerInputs()
void hwHandleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp)
void(* ShaftPositionListener)(trigger_event_e signal, uint32_t index, efitick_t edgeTimestamp)
void initTriggerCentral()
void triggerInfo(void)
int isSignalDecoderError(void)
void onConfigurationChangeTriggerCallback()
void handleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp)
void hwHandleVvtCamSignal(TriggerValue front, efitick_t timestamp, int index)
TriggerCentral * getTriggerCentral()
Definition: engine.cpp:609