rusefi-1/firmware/controllers/trigger/trigger_emulator_algo.cpp

243 lines
7.9 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file trigger_emulator_algo.cpp
*
2015-09-23 18:02:33 -07:00
* This file is about producing real electrical signals which emulate trigger signal based on
* a known TriggerWaveform.
2015-09-23 18:02:33 -07:00
*
* Historically this implementation was implemented based on PwmConfig which is maybe not the
* best way to implement it. (todo: why is not the best way?)
*
* A newer implementation of pretty much the same thing is TriggerStimulatorHelper
* todo: one emulator should be enough! another one should be eliminated
*
2015-07-10 06:01:56 -07:00
* @date Mar 3, 2014
2020-01-13 18:57:43 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2015-07-10 06:01:56 -07:00
*/
#include "state_sequence.h"
2018-09-16 19:26:57 -07:00
#include "global.h"
2019-10-08 00:14:21 -07:00
#include "efi_gpio.h"
#include "pin_repository.h"
2015-07-10 06:01:56 -07:00
2019-03-03 21:40:22 -08:00
int getPreviousIndex(const int currentIndex, const int size) {
return (currentIndex + size - 1) % size;
}
bool needEvent(const int currentIndex, const int size, const MultiChannelStateSequence& mcss, int channelIndex) {
2019-03-03 22:10:31 -08:00
int prevIndex = getPreviousIndex(currentIndex, size);
pin_state_t previousValue = mcss.getChannelState(channelIndex, /*phaseIndex*/prevIndex);
pin_state_t currentValue = mcss.getChannelState(channelIndex, /*phaseIndex*/currentIndex);
2019-03-03 22:10:31 -08:00
return previousValue != currentValue;
}
2019-04-12 19:07:03 -07:00
#if EFI_EMULATE_POSITION_SENSORS
2015-07-10 06:01:56 -07:00
2019-01-20 21:10:09 -08:00
#include "engine.h"
2015-07-10 06:01:56 -07:00
#include "trigger_emulator_algo.h"
#include "engine_configuration.h"
#include "trigger_central.h"
2017-03-03 21:17:53 -08:00
#include "trigger_simulator.h"
#include "settings.h"
2020-04-26 14:40:12 -07:00
#include "pwm_generator_logic.h"
2015-07-10 06:01:56 -07:00
TriggerEmulatorHelper::TriggerEmulatorHelper() {
}
EXTERN_ENGINE;
2015-07-10 06:01:56 -07:00
2020-04-26 14:40:12 -07:00
static OutputPin emulatorOutputs[PWM_PHASE_MAX_WAVE_PER_PWM];
2021-06-25 09:01:59 -07:00
void TriggerEmulatorHelper::handleEmulatorCallback(const int size, const MultiChannelStateSequence& multiChannelStateSequence, int stateIndex DECLARE_ENGINE_PARAMETER_SUFFIX) {
efitick_t stamp = getTimeNowNt();
2018-02-05 14:41:05 -08:00
// todo: code duplication with TriggerStimulatorHelper::feedSimulatedEvent?
2017-03-03 21:08:56 -08:00
2021-06-25 07:55:46 -07:00
for (size_t i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
2021-06-25 09:01:59 -07:00
if (needEvent(stateIndex, size, multiChannelStateSequence, i)) {
pin_state_t currentValue = multiChannelStateSequence.getChannelState(/*phaseIndex*/i, stateIndex);
constexpr trigger_event_e riseEvents[] = { SHAFT_PRIMARY_RISING, SHAFT_SECONDARY_RISING, SHAFT_3RD_RISING };
constexpr trigger_event_e fallEvents[] = { SHAFT_PRIMARY_FALLING, SHAFT_SECONDARY_FALLING, SHAFT_3RD_FALLING };
2015-07-10 06:01:56 -07:00
trigger_event_e event = (currentValue ? riseEvents : fallEvents)[i];
2015-07-10 06:01:56 -07:00
handleShaftSignal2(event, stamp PASS_ENGINE_PARAMETER_SUFFIX);
}
2015-07-10 06:01:56 -07:00
}
}
/*
* todo: should we simply re-use instances used by trigger_decoder?
* todo: since we are emulating same shape we are decoding
*/
static pin_state_t pinStates1[PWM_PHASE_MAX_COUNT];
static pin_state_t pinStates2[PWM_PHASE_MAX_COUNT];
static pin_state_t pinStates3[PWM_PHASE_MAX_COUNT];
static SingleChannelStateSequence waves[PWM_PHASE_MAX_WAVE_PER_PWM] = { SingleChannelStateSequence(pinStates1), SingleChannelStateSequence(pinStates2),
SingleChannelStateSequence(pinStates3) };
static SingleChannelStateSequence sr[PWM_PHASE_MAX_WAVE_PER_PWM] = { waves[0], waves[1], waves[2] };
2015-07-10 06:01:56 -07:00
2020-08-24 22:07:32 -07:00
static float pwmSwitchTimesBuffer[PWM_PHASE_MAX_COUNT];
2015-07-10 06:01:56 -07:00
2020-08-24 22:07:32 -07:00
PwmConfig triggerSignal(pwmSwitchTimesBuffer, sr);
2015-07-10 06:01:56 -07:00
2018-02-03 14:08:07 -08:00
static int atTriggerVersion = 0;
2015-07-10 06:01:56 -07:00
2015-07-15 18:01:45 -07:00
#if EFI_ENGINE_SNIFFER
#include "engine_sniffer.h"
2015-07-10 06:01:56 -07:00
extern WaveChart waveChart;
2015-07-15 18:01:45 -07:00
#endif /* EFI_ENGINE_SNIFFER */
2015-07-10 06:01:56 -07:00
2017-05-15 20:28:49 -07:00
void setTriggerEmulatorRPM(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
engineConfiguration->triggerSimulatorFrequency = rpm;
2015-07-10 06:01:56 -07:00
/**
* All we need to do here is to change the periodMs
* togglePwmState() would see that the periodMs has changed and act accordingly
*/
if (rpm == 0) {
2018-01-21 12:31:59 -08:00
triggerSignal.setFrequency(NAN);
2015-07-10 06:01:56 -07:00
} else {
float rpmM = getRpmMultiplier(engine->getOperationMode(PASS_ENGINE_PARAMETER_SIGNATURE));
float rPerSecond = rpm * rpmM / 60.0; // per minute converted to per second
triggerSignal.setFrequency(rPerSecond);
2015-07-10 06:01:56 -07:00
}
2019-12-21 17:43:11 -08:00
engine->resetEngineSnifferIfInTestMode();
2015-07-10 06:01:56 -07:00
efiPrintf("Emulating position sensor(s). RPM=%d", rpm);
2015-07-10 06:01:56 -07:00
}
static void updateTriggerWaveformIfNeeded(PwmConfig *state DECLARE_ENGINE_PARAMETER_SUFFIX) {
2018-02-03 14:08:07 -08:00
if (atTriggerVersion < engine->triggerCentral.triggerShape.version) {
atTriggerVersion = engine->triggerCentral.triggerShape.version;
efiPrintf("Stimulator: updating trigger shape: %d/%d %d", atTriggerVersion,
engine->getGlobalConfigurationVersion(), currentTimeMillis());
2015-07-10 06:01:56 -07:00
TriggerWaveform *s = &engine->triggerCentral.triggerShape;
2018-12-25 07:13:00 -08:00
pin_state_t *pinStates[PWM_PHASE_MAX_WAVE_PER_PWM] = {
s->wave.channels[0].pinStates,
s->wave.channels[1].pinStates,
s->wave.channels[2].pinStates };
2015-07-10 06:01:56 -07:00
copyPwmParameters(state, s->getSize(), s->wave.switchTimes, PWM_PHASE_MAX_WAVE_PER_PWM, pinStates);
state->safe.periodNt = -1; // this would cause loop re-initialization
}
}
static TriggerEmulatorHelper helper;
static bool hasStimPins = false;
2015-07-10 06:01:56 -07:00
static bool hasInitTriggerEmulator = false;
# if !EFI_UNIT_TEST
static void emulatorApplyPinState(int stateIndex, PwmConfig *state) /* pwm_gen_callback */ {
if (engine->directSelfStimulation) {
2015-07-10 06:01:56 -07:00
/**
* this callback would invoke the input signal handlers directly
*/
2021-06-25 09:01:59 -07:00
helper.handleEmulatorCallback(state->phaseCount,
state->multiChannelStateSequence,
stateIndex);
2015-07-10 06:01:56 -07:00
}
#if EFI_PROD_CODE
// Only set pins if they're configured - no need to waste the cycles otherwise
else if (hasStimPins) {
applyPinState(stateIndex, state);
}
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
}
static void initTriggerPwm(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
// No need to start more than once
if (hasInitTriggerEmulator) {
return;
}
2015-07-10 06:01:56 -07:00
TriggerWaveform *s = &engine->triggerCentral.triggerShape;
setTriggerEmulatorRPM(engineConfiguration->triggerSimulatorFrequency PASS_ENGINE_PARAMETER_SUFFIX);
2018-12-25 07:13:00 -08:00
pin_state_t *pinStates[PWM_PHASE_MAX_WAVE_PER_PWM] = {
s->wave.channels[0].pinStates,
s->wave.channels[1].pinStates,
s->wave.channels[2].pinStates };
int phaseCount = s->getSize();
assertIsInBounds(phaseCount - 1, pwmSwitchTimesBuffer, "pwmSwitchTimesBuffer");
triggerSignal.weComplexInit("position sensor",
&engine->executor,
phaseCount, s->wave.switchTimes, PWM_PHASE_MAX_WAVE_PER_PWM,
pinStates, updateTriggerWaveformIfNeeded, (pwm_gen_callback*)emulatorApplyPinState);
2015-07-10 06:01:56 -07:00
hasInitTriggerEmulator = true;
}
void enableTriggerStimulator() {
initTriggerPwm();
engine->directSelfStimulation = true;
}
void enableExternalTriggerStimulator() {
initTriggerPwm();
engine->directSelfStimulation = false;
}
void disableTriggerStimulator() {
engine->directSelfStimulation = false;
triggerSignal.stop();
hasInitTriggerEmulator = false;
}
void initTriggerEmulatorLogic(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
addConsoleActionI(CMD_RPM, setTriggerEmulatorRPM);
2015-07-10 06:01:56 -07:00
}
void onConfigurationChangeRpmEmulatorCallback(engine_configuration_s *previousConfiguration) {
if (engineConfiguration->triggerSimulatorFrequency ==
previousConfiguration->triggerSimulatorFrequency) {
return;
}
setTriggerEmulatorRPM(engineConfiguration->triggerSimulatorFrequency);
}
void initTriggerEmulator(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
efiPrintf("Emulating %s", getConfigurationName(engineConfiguration->engineType));
startTriggerEmulatorPins(PASS_ENGINE_PARAMETER_SIGNATURE);
2020-12-17 22:30:17 -08:00
initTriggerEmulatorLogic(PASS_ENGINE_PARAMETER_SIGNATURE);
}
2021-06-25 09:28:55 -07:00
#endif /* EFI_UNIT_TEST */
void startTriggerEmulatorPins(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
hasStimPins = false;
for (size_t i = 0; i < efi::size(emulatorOutputs); i++) {
triggerSignal.outputPins[i] = &emulatorOutputs[i];
brain_pin_e pin = CONFIG(triggerSimulatorPins)[i];
// Only bother trying to set output pins if they're configured
if (isBrainPinValid(pin)) {
hasStimPins = true;
}
#if EFI_PROD_CODE
if (isConfigurationChanged(triggerSimulatorPins[i])) {
triggerSignal.outputPins[i]->initPin("Trigger emulator", pin,
&CONFIG(triggerSimulatorPinModes)[i]);
}
#endif // EFI_PROD_CODE
}
}
void stopTriggerEmulatorPins() {
#if EFI_PROD_CODE
for (size_t i = 0; i < efi::size(emulatorOutputs); i++) {
if (isConfigurationChanged(triggerSimulatorPins[i])) {
triggerSignal.outputPins[i]->deInit();
}
}
#endif // EFI_PROD_CODE
}
2017-05-15 05:51:40 -07:00
#endif /* EFI_EMULATE_POSITION_SENSORS */