rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
trigger_emulator_algo.cpp
Go to the documentation of this file.
1/**
2 * @file trigger_emulator_algo.cpp
3 *
4 * This file is about producing real electrical signals which emulate trigger signal based on
5 * a known TriggerWaveform.
6 *
7 * Historically this implementation was implemented based on PwmConfig which is maybe not the
8 * best way to implement it. (todo: why is not the best way?)
9 *
10 * A newer implementation of pretty much the same thing is TriggerStimulatorHelper
11 * todo: one emulator should be enough! another one should be eliminated
12 *
13 * @date Mar 3, 2014
14 * @author Andrey Belomutskiy, (c) 2012-2020
15 */
16
17#include "pch.h"
18
19int getPreviousIndex(const int currentIndex, const int size) {
20 return (currentIndex + size - 1) % size;
21}
22
23bool needEvent(const int currentIndex, const MultiChannelStateSequence & mcss, int channelIndex) {
24 int prevIndex = getPreviousIndex(currentIndex, mcss.phaseCount);
25 pin_state_t previousValue = mcss.getChannelState(channelIndex, /*phaseIndex*/prevIndex);
26 pin_state_t currentValue = mcss.getChannelState(channelIndex, /*phaseIndex*/currentIndex);
27
28 return previousValue != currentValue;
29}
30
31#if EFI_EMULATE_POSITION_SENSORS
32
33#if !EFI_SHAFT_POSITION_INPUT
34 fail("EFI_SHAFT_POSITION_INPUT required to have EFI_EMULATE_POSITION_SENSORS")
35#endif
36
38#include "trigger_central.h"
39#include "trigger_simulator.h"
40
42}
43
44static OutputPin emulatorOutputs[NUM_EMULATOR_CHANNELS][PWM_PHASE_MAX_WAVE_PER_PWM];
45
46void TriggerEmulatorHelper::handleEmulatorCallback(int channel, const MultiChannelStateSequence& multiChannelStateSequence, int stateIndex) {
47 efitick_t stamp = getTimeNowNt();
48
49 // todo: code duplication with TriggerStimulatorHelper::feedSimulatedEvent?
50#if EFI_SHAFT_POSITION_INPUT
51 for (size_t i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
52 if (needEvent(stateIndex, multiChannelStateSequence, i)) {
53 bool isRise = TriggerValue::RISE == multiChannelStateSequence.getChannelState(/*phaseIndex*/i, stateIndex);
54
57
58 if (channel == 0) {
59 handleShaftSignal(i, isRise, stamp);
60 } else {
61 handleVvtCamSignal(isRise ? TriggerValue::RISE : TriggerValue::FALL, stamp, INDEX_BY_BANK_CAM(channel - 1, i));
62 }
63 }
64 }
65#endif // EFI_SHAFT_POSITION_INPUT
66}
67
68// same is used for either self or external trigger simulation
69PwmConfig triggerEmulatorSignals[NUM_EMULATOR_CHANNELS];
71
72static int atTriggerVersions[NUM_EMULATOR_CHANNELS] = { 0 };
73
74/**
75 * todo: why is this method NOT reciprocal to getCrankDivider?!
76 * todo: oh this method has only one usage? there must me another very similar method!
77 */
79 switch (mode) {
86 case OM_NONE:
87 return getCrankDivider(mode) / 2.0;
88 case TWO_STROKE:
89 // unit test coverage still runs if the value below is changed to '2' not a great sign!
90 // but HW CI insists that we have '1' here
91 return 1;
92 };
93 criticalError("We should not have reach this line");
94 return 1;
95}
96
97void setTriggerEmulatorRPM(int rpm) {
98 criticalAssertVoid(rpm >= 0 && rpm <= 30000, "emulator RPM out of range");
99
101 /**
102 * All we need to do here is to change the periodMs
103 * togglePwmState() would see that the periodMs has changed and act accordingly
104 */
105 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
106 float rPerSecond = NAN;
107 if (rpm != 0) {
108 // use 0.5 multiplier for cam
109 float rpmM = (channel == 0) ? getRpmMultiplier(getEngineRotationState()->getOperationMode()) : 0.5f;
110 rPerSecond = rpm * rpmM / 60.0; // per minute converted to per second
111 }
113 }
114
116
117 efiPrintf("Emulating position sensor(s). RPM=%d", rpm);
118}
119
121 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
123 continue;
124
127 efiPrintf("Stimulator: updating trigger shape for ch%d: %d/%d %ld", channel, atTriggerVersions[channel],
129
131 state->safe.periodNt = -1; // this would cause loop re-initialization
132 }
133 }
134}
135
137static bool hasStimPins = false;
138
139static bool hasInitTriggerEmulator = false;
140
141#if EFI_PROD_CODE
142PUBLIC_API_WEAK void onTriggerEmulatorPinState(int, int) { }
143#endif /* EFI_PROD_CODE */
144
145# if !EFI_UNIT_TEST
146
147static void emulatorApplyPinState(int stateIndex, PwmConfig *state) /* pwm_gen_callback */ {
148 assertStackVoid("emulator", ObdCode::STACK_USAGE_MISC, EXPECTED_REMAINING_STACK);
150 /**
151 * this callback would invoke the input signal handlers directly
152 */
153 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
155 continue;
157 *state->multiChannelStateSequence,
158 stateIndex);
159 }
160 }
161
162#if EFI_PROD_CODE
163 // Only set pins if they're configured - no need to waste the cycles otherwise
164 else if (hasStimPins) {
165 applyPinState(stateIndex, state);
166
167 // this allows any arbitrary code to synchronize with the trigger emulator
168 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
170 continue;
172 }
173 }
174#endif /* EFI_PROD_CODE */
175}
176
178 // No need to start more than once
180 return;
181 }
182
183 // store the crank+cam waveforms
185 for (int cami = 0; cami < CAMS_PER_BANK; cami++) {
187 }
188
190
191 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
193 if (s->getSize() == 0)
194 continue;
197 &s->wave,
199 }
201}
202
203// self-stimulation
204// see below for trigger output generator
205void enableTriggerStimulator(bool incGlobalConfiguration) {
209 if (incGlobalConfiguration) {
211 }
212}
213
214// start generating trigger signal on physical outputs
215// similar but different from self-stimulation
221
224 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
226 }
229}
230
238
246
247#endif /* EFI_UNIT_TEST */
248
250 hasStimPins = false;
251 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
252 for (size_t i = 0; i < efi::size(emulatorOutputs[channel]); i++) {
254
255#if EFI_PROD_CODE
257
258 pin_output_mode_e outputMode;
259 if (channel == 0) {
262 } else if (channel == 1 && i == 0) {
265 } else {
266 // todo: add pin configs for cam simulator channels
267 continue;
268 }
269
270 // Only bother trying to set output pins if they're configured
271 if (isBrainPinValid(pin)) {
272 hasStimPins = true;
273 }
274
275 if (isConfigurationChanged(triggerSimulatorPins[i])) {
276 triggerEmulatorSignals[channel].outputPins[i]->initPin("Trigger emulator", pin,
277 outputMode);
278 }
279#endif // EFI_PROD_CODE
280 }
281 }
282}
283
285#if EFI_PROD_CODE
286 for (int channel = 0; channel < NUM_EMULATOR_CHANNELS; channel++) {
287 // todo: add pin configs for cam simulator channels
288 if (channel != 0)
289 continue;
290 for (size_t i = 0; i < efi::size(emulatorOutputs[channel]); i++) {
291 if (isConfigurationChanged(triggerSimulatorPins[i])) {
293 }
294 }
295 }
296#endif // EFI_PROD_CODE
297}
298
299#endif /* EFI_EMULATE_POSITION_SENSORS */
uint16_t channel
Definition adc_inputs.h:104
const char * getEngine_type_e(engine_type_e value)
uint8_t version
TriggerCentral triggerCentral
Definition engine.h:318
int getGlobalConfigurationVersion() const
Definition engine.cpp:289
SingleTimerExecutor scheduler
Definition engine.h:271
RpmCalculator rpmCalculator
Definition engine.h:306
void resetEngineSnifferIfInTestMode()
Definition engine.cpp:53
virtual operation_mode_e getOperationMode() const =0
virtual pin_state_t getChannelState(int channelIndex, int phaseIndex) const =0
Single output pin reference and state.
Definition efi_output.h:49
void deInit()
Definition efi_gpio.cpp:802
void initPin(const char *msg, brain_pin_e brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError=false)
Definition efi_gpio.cpp:711
Multi-channel software PWM output configuration.
OutputPin * outputPins[PWM_PHASE_MAX_WAVE_PER_PWM]
void weComplexInit(Scheduler *executor, MultiChannelStateSequence const *seq, pwm_cycle_callback *pwmCycleCallback, pwm_gen_callback *callback)
void setFrequency(float frequency)
bool Register()
Definition sensor.cpp:131
TriggerWaveform vvtShape[CAMS_PER_BANK]
TriggerWaveform triggerShape
void handleEmulatorCallback(int channel, const MultiChannelStateSequence &mcss, int stateIndex)
Trigger shape has all the fields needed to describe and decode trigger signal.
MultiChannelStateSequenceWithData< PWM_PHASE_MAX_COUNT > wave
size_t getSize() const
void addConsoleActionI(const char *token, VoidInt callback)
Register a console command with one Integer parameter.
efitick_t getTimeNowNt()
Definition efitime.cpp:19
efitimems_t getTimeNowMs()
Returns the 32 bit number of milliseconds since the board initialization.
Definition efitime.cpp:34
EngineRotationState * getEngineRotationState()
Definition engine.cpp:573
static EngineAccessor engine
Definition engine.h:413
void incrementGlobalConfigurationVersion(const char *msg)
static constexpr engine_configuration_s * engineConfiguration
@ STACK_USAGE_MISC
bool isBrainPinValid(brain_pin_e brainPin)
void applyPinState(int stateIndex, PwmConfig *state)
void copyPwmParameters(PwmConfig *state, MultiChannelStateSequence const *seq)
operation_mode_e
@ FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR
@ FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR
@ FOUR_STROKE_THREE_TIMES_CRANK_SENSOR
@ FOUR_STROKE_CRANK_SENSOR
@ OM_NONE
@ FOUR_STROKE_CAM_SENSOR
@ TWO_STROKE
@ FOUR_STROKE_SIX_TIMES_CRANK_SENSOR
pin_output_mode_e
state("state", SensorCategory.SENSOR_INPUTS, FieldType.INT8, 1871, 1.0, -1.0, -1.0, "")
TriggerValue
brain_pin_e pin
Definition stm32_adc.cpp:15
pin_output_mode_e triggerSimulatorPinModes[TRIGGER_SIMULATOR_PIN_COUNT]
composite packet size
int getCrankDivider(operation_mode_e operationMode)
void handleVvtCamSignal(TriggerValue front, efitick_t nowNt, int index)
void handleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp)
PwmConfig triggerEmulatorSignals[NUM_EMULATOR_CHANNELS]
void disableTriggerStimulator()
void setTriggerEmulatorRPM(int rpm)
static float getRpmMultiplier(operation_mode_e mode)
void startTriggerEmulatorPins()
void onConfigurationChangeRpmEmulatorCallback(engine_configuration_s *previousConfiguration)
void initTriggerEmulator()
static void emulatorApplyPinState(int stateIndex, PwmConfig *state)
void stopTriggerEmulatorPins()
void enableExternalTriggerStimulator()
static void updateTriggerWaveformIfNeeded(PwmConfig *state)
static bool hasStimPins
fail("EFI_SHAFT_POSITION_INPUT required to have EFI_EMULATE_POSITION_SENSORS") TriggerEmulatorHelper
int getPreviousIndex(const int currentIndex, const int size)
static TriggerEmulatorHelper helper
bool needEvent(const int currentIndex, const MultiChannelStateSequence &mcss, int channelIndex)
static OutputPin emulatorOutputs[NUM_EMULATOR_CHANNELS][PWM_PHASE_MAX_WAVE_PER_PWM]
PUBLIC_API_WEAK void onTriggerEmulatorPinState(int, int)
static int atTriggerVersions[NUM_EMULATOR_CHANNELS]
void enableTriggerStimulator(bool incGlobalConfiguration)
TriggerWaveform * triggerEmulatorWaveforms[NUM_EMULATOR_CHANNELS]
static bool hasInitTriggerEmulator
static void startSimulatedTriggerSignal()
bool needEvent(const int currentIndex, const MultiChannelStateSequence &mcss, int channelIndex)