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
|
2019-12-07 22:09:39 -08:00
|
|
|
* 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
|
|
|
*/
|
2021-07-25 22:05:17 -07:00
|
|
|
|
|
|
|
#include "pch.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;
|
|
|
|
}
|
|
|
|
|
2021-11-21 01:56:07 -08:00
|
|
|
bool needEvent(const int currentIndex, const MultiChannelStateSequence & mcss, int channelIndex) {
|
2021-11-10 16:47:27 -08:00
|
|
|
int prevIndex = getPreviousIndex(currentIndex, mcss.phaseCount);
|
2020-10-05 11:22:59 -07:00
|
|
|
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
|
|
|
|
2023-06-22 12:45:55 -07:00
|
|
|
#if !EFI_SHAFT_POSITION_INPUT
|
|
|
|
fail("EFI_SHAFT_POSITION_INPUT required to have EFI_EMULATE_POSITION_SENSORS")
|
|
|
|
#endif
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "trigger_emulator_algo.h"
|
|
|
|
#include "trigger_central.h"
|
2017-03-03 21:17:53 -08:00
|
|
|
#include "trigger_simulator.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
TriggerEmulatorHelper::TriggerEmulatorHelper() {
|
|
|
|
}
|
|
|
|
|
2020-04-26 14:40:12 -07:00
|
|
|
static OutputPin emulatorOutputs[PWM_PHASE_MAX_WAVE_PER_PWM];
|
2020-04-24 11:00:06 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void TriggerEmulatorHelper::handleEmulatorCallback(const MultiChannelStateSequence& multiChannelStateSequence, int stateIndex) {
|
2020-01-09 10:19:11 -08:00
|
|
|
efitick_t stamp = getTimeNowNt();
|
|
|
|
|
2018-02-05 14:41:05 -08:00
|
|
|
// todo: code duplication with TriggerStimulatorHelper::feedSimulatedEvent?
|
2022-04-16 14:04:35 -07:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
2021-06-25 07:55:46 -07:00
|
|
|
for (size_t i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
|
2021-11-10 16:47:27 -08:00
|
|
|
if (needEvent(stateIndex, multiChannelStateSequence, i)) {
|
2022-09-25 07:10:31 -07:00
|
|
|
bool isRise = TriggerValue::RISE == multiChannelStateSequence.getChannelState(/*phaseIndex*/i, stateIndex);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2022-09-25 07:10:31 -07:00
|
|
|
isRise ^= (i == 0 && engineConfiguration->invertPrimaryTriggerSignal);
|
|
|
|
isRise ^= (i == 1 && engineConfiguration->invertSecondaryTriggerSignal);
|
|
|
|
|
|
|
|
handleShaftSignal(i, isRise, stamp);
|
2020-04-24 11:00:06 -07:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2022-04-16 14:04:35 -07:00
|
|
|
#endif // EFI_SHAFT_POSITION_INPUT
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2023-03-02 20:54:42 -08:00
|
|
|
// same is used for either self or external trigger simulation
|
2023-03-02 20:24:59 -08:00
|
|
|
PwmConfig triggerEmulatorSignal;
|
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
|
|
|
|
2021-06-26 21:54:38 -07:00
|
|
|
/**
|
|
|
|
* todo: why is this method NOT reciprocal to getCrankDivider?!
|
|
|
|
* todo: oh this method has only one usage? there must me another very similar method!
|
|
|
|
*/
|
|
|
|
static float getRpmMultiplier(operation_mode_e mode) {
|
2021-07-05 19:44:20 -07:00
|
|
|
if (mode == FOUR_STROKE_THREE_TIMES_CRANK_SENSOR) {
|
|
|
|
return SYMMETRICAL_THREE_TIMES_CRANK_SENSOR_DIVIDER / 2;
|
|
|
|
} else if (mode == FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR) {
|
|
|
|
return SYMMETRICAL_CRANK_SENSOR_DIVIDER / 2;
|
2022-05-17 18:38:24 -07:00
|
|
|
} else if (mode == FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR) {
|
|
|
|
return SYMMETRICAL_TWELVE_TIMES_CRANK_SENSOR_DIVIDER / 2;
|
2021-06-26 21:54:38 -07:00
|
|
|
} else if (mode == FOUR_STROKE_CAM_SENSOR) {
|
|
|
|
return 0.5;
|
|
|
|
} else if (mode == FOUR_STROKE_CRANK_SENSOR) {
|
|
|
|
// unit test coverage still runs if the value below is changed to '2' not a great sign!
|
|
|
|
return 1;
|
|
|
|
}
|
2022-05-17 18:38:24 -07:00
|
|
|
|
2021-06-26 21:54:38 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void setTriggerEmulatorRPM(int rpm) {
|
2023-03-27 01:13:04 -07:00
|
|
|
engineConfiguration->triggerSimulatorRpm = 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) {
|
2023-03-02 20:24:59 -08:00
|
|
|
triggerEmulatorSignal.setFrequency(NAN);
|
2015-07-10 06:01:56 -07:00
|
|
|
} else {
|
2022-09-13 22:34:52 -07:00
|
|
|
float rpmM = getRpmMultiplier(getEngineRotationState()->getOperationMode());
|
2017-07-10 19:08:55 -07:00
|
|
|
float rPerSecond = rpm * rpmM / 60.0; // per minute converted to per second
|
2023-03-02 20:24:59 -08:00
|
|
|
triggerEmulatorSignal.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
|
|
|
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Emulating position sensor(s). RPM=%d", rpm);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
static void updateTriggerWaveformIfNeeded(PwmConfig *state) {
|
2018-02-03 14:08:07 -08:00
|
|
|
if (atTriggerVersion < engine->triggerCentral.triggerShape.version) {
|
|
|
|
atTriggerVersion = engine->triggerCentral.triggerShape.version;
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Stimulator: updating trigger shape: %d/%d %d", atTriggerVersion,
|
2022-09-11 10:06:03 -07:00
|
|
|
engine->getGlobalConfigurationVersion(), getTimeNowMs());
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
|
2019-12-07 22:09:39 -08:00
|
|
|
TriggerWaveform *s = &engine->triggerCentral.triggerShape;
|
2021-11-21 01:56:07 -08:00
|
|
|
copyPwmParameters(state, &s->wave);
|
2015-07-10 06:01:56 -07:00
|
|
|
state->safe.periodNt = -1; // this would cause loop re-initialization
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static TriggerEmulatorHelper helper;
|
2020-04-24 11:00:06 -07:00
|
|
|
static bool hasStimPins = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-06-25 08:50:23 -07:00
|
|
|
static bool hasInitTriggerEmulator = false;
|
|
|
|
|
|
|
|
# if !EFI_UNIT_TEST
|
|
|
|
|
2019-04-12 17:15:18 -07:00
|
|
|
static void emulatorApplyPinState(int stateIndex, PwmConfig *state) /* pwm_gen_callback */ {
|
2023-06-24 23:21:38 -07:00
|
|
|
assertStackVoid("emulator", ObdCode::STACK_USAGE_MISC, EXPECTED_REMAINING_STACK);
|
2022-09-13 23:06:52 -07:00
|
|
|
if (engine->triggerCentral.directSelfStimulation) {
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* this callback would invoke the input signal handlers directly
|
|
|
|
*/
|
2021-11-10 16:47:27 -08:00
|
|
|
helper.handleEmulatorCallback(
|
2021-11-10 04:01:20 -08:00
|
|
|
*state->multiChannelStateSequence,
|
2021-06-25 09:01:59 -07:00
|
|
|
stateIndex);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2020-04-23 19:38:14 -07:00
|
|
|
|
|
|
|
#if EFI_PROD_CODE
|
2020-04-24 11:00:06 -07:00
|
|
|
// Only set pins if they're configured - no need to waste the cycles otherwise
|
2020-10-16 08:04:27 -07:00
|
|
|
else if (hasStimPins) {
|
2020-04-24 11:00:06 -07:00
|
|
|
applyPinState(stateIndex, state);
|
|
|
|
}
|
2020-04-23 19:38:14 -07:00
|
|
|
#endif /* EFI_PROD_CODE */
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2023-03-02 21:36:17 -08:00
|
|
|
static bool hackVvtSim = false;
|
|
|
|
|
|
|
|
static TriggerWaveform * getTriggerForEmulation() {
|
|
|
|
#if EFI_SIMULATOR
|
|
|
|
if (hackVvtSim) {
|
|
|
|
static TriggerWaveform mShape;
|
|
|
|
trigger_config_s triggerType;
|
2023-05-31 23:18:48 -07:00
|
|
|
triggerType.type = trigger_type_e::TT_MAZDA_MIATA_NA;
|
2023-03-02 21:36:17 -08:00
|
|
|
mShape.initializeTriggerWaveform(FOUR_STROKE_CAM_SENSOR, triggerType);
|
|
|
|
return &mShape;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return &engine->triggerCentral.triggerShape;
|
|
|
|
}
|
|
|
|
|
2022-10-27 23:41:20 -07:00
|
|
|
static void startSimulatedTriggerSignal() {
|
2021-03-11 05:38:52 -08:00
|
|
|
// No need to start more than once
|
|
|
|
if (hasInitTriggerEmulator) {
|
|
|
|
return;
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2023-03-02 21:36:17 -08:00
|
|
|
TriggerWaveform *s = getTriggerForEmulation();
|
2023-03-27 01:13:04 -07:00
|
|
|
setTriggerEmulatorRPM(engineConfiguration->triggerSimulatorRpm);
|
2023-03-02 20:24:59 -08:00
|
|
|
triggerEmulatorSignal.weComplexInit("position sensor",
|
2019-01-09 05:50:51 -08:00
|
|
|
&engine->executor,
|
2021-11-21 01:56:07 -08:00
|
|
|
&s->wave,
|
2021-11-10 04:01:20 -08:00
|
|
|
updateTriggerWaveformIfNeeded, (pwm_gen_callback*)emulatorApplyPinState);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-03-11 05:38:52 -08:00
|
|
|
hasInitTriggerEmulator = true;
|
|
|
|
}
|
|
|
|
|
2023-03-02 20:54:42 -08:00
|
|
|
// self-stimulation
|
|
|
|
// see below for trigger output generator
|
2023-04-19 17:29:33 -07:00
|
|
|
void enableTriggerStimulator(bool incGlobalConfiguration) {
|
2022-10-27 23:41:20 -07:00
|
|
|
startSimulatedTriggerSignal();
|
2022-09-13 23:06:52 -07:00
|
|
|
engine->triggerCentral.directSelfStimulation = true;
|
2022-10-21 20:29:39 -07:00
|
|
|
engine->rpmCalculator.Register();
|
2023-04-19 17:29:33 -07:00
|
|
|
if (incGlobalConfiguration) {
|
2023-04-19 19:09:48 -07:00
|
|
|
incrementGlobalConfigurationVersion("trgSim");
|
2023-04-19 17:29:33 -07:00
|
|
|
}
|
2021-03-11 05:38:52 -08:00
|
|
|
}
|
|
|
|
|
2023-03-02 20:54:42 -08:00
|
|
|
// start generating trigger signal on physical outputs
|
|
|
|
// similar but different from self-stimulation
|
2021-03-11 05:38:52 -08:00
|
|
|
void enableExternalTriggerStimulator() {
|
2022-10-27 23:41:20 -07:00
|
|
|
startSimulatedTriggerSignal();
|
2022-09-13 23:06:52 -07:00
|
|
|
engine->triggerCentral.directSelfStimulation = false;
|
2023-04-19 19:09:48 -07:00
|
|
|
incrementGlobalConfigurationVersion("extTrg");
|
2021-03-11 05:38:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void disableTriggerStimulator() {
|
2022-09-13 23:06:52 -07:00
|
|
|
engine->triggerCentral.directSelfStimulation = false;
|
2023-03-02 20:24:59 -08:00
|
|
|
triggerEmulatorSignal.stop();
|
2021-03-11 05:38:52 -08:00
|
|
|
hasInitTriggerEmulator = false;
|
2023-04-19 19:09:48 -07:00
|
|
|
incrementGlobalConfigurationVersion("disTrg");
|
2021-03-11 05:38:52 -08:00
|
|
|
}
|
|
|
|
|
2020-04-24 11:00:06 -07:00
|
|
|
void onConfigurationChangeRpmEmulatorCallback(engine_configuration_s *previousConfiguration) {
|
2023-03-27 01:13:04 -07:00
|
|
|
if (engineConfiguration->triggerSimulatorRpm ==
|
|
|
|
previousConfiguration->triggerSimulatorRpm) {
|
2020-04-24 11:00:06 -07:00
|
|
|
return;
|
|
|
|
}
|
2023-03-27 01:13:04 -07:00
|
|
|
setTriggerEmulatorRPM(engineConfiguration->triggerSimulatorRpm);
|
2020-04-24 11:00:06 -07:00
|
|
|
}
|
|
|
|
|
2023-03-02 21:36:17 -08:00
|
|
|
static void hackVvtSimulation() {
|
|
|
|
disableTriggerStimulator();
|
|
|
|
hackVvtSim = true;
|
|
|
|
enableTriggerStimulator();
|
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void initTriggerEmulator() {
|
2021-10-20 07:38:01 -07:00
|
|
|
efiPrintf("Emulating %s", getEngine_type_e(engineConfiguration->engineType));
|
2020-04-24 11:00:06 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
startTriggerEmulatorPins();
|
2020-12-17 22:30:17 -08:00
|
|
|
|
2023-03-02 20:54:42 -08:00
|
|
|
addConsoleActionI(CMD_RPM, setTriggerEmulatorRPM);
|
2023-03-02 21:36:17 -08:00
|
|
|
#if 0
|
|
|
|
hackVvtSimulation();
|
|
|
|
#endif
|
|
|
|
addConsoleAction("sim_mitsu", hackVvtSimulation);
|
2020-12-08 02:07:03 -08:00
|
|
|
}
|
|
|
|
|
2021-06-25 09:28:55 -07:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void startTriggerEmulatorPins() {
|
2020-12-08 02:07:03 -08:00
|
|
|
hasStimPins = false;
|
|
|
|
for (size_t i = 0; i < efi::size(emulatorOutputs); i++) {
|
2023-03-02 20:24:59 -08:00
|
|
|
triggerEmulatorSignal.outputPins[i] = &emulatorOutputs[i];
|
2020-04-24 11:00:06 -07:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
brain_pin_e pin = engineConfiguration->triggerSimulatorPins[i];
|
2020-04-24 11:00:06 -07:00
|
|
|
|
|
|
|
// Only bother trying to set output pins if they're configured
|
2021-01-08 17:01:26 -08:00
|
|
|
if (isBrainPinValid(pin)) {
|
2020-04-24 11:00:06 -07:00
|
|
|
hasStimPins = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if EFI_PROD_CODE
|
2021-06-25 16:38:42 -07:00
|
|
|
if (isConfigurationChanged(triggerSimulatorPins[i])) {
|
2023-03-02 20:24:59 -08:00
|
|
|
triggerEmulatorSignal.outputPins[i]->initPin("Trigger emulator", pin,
|
2023-02-25 00:31:12 -08:00
|
|
|
engineConfiguration->triggerSimulatorPinModes[i]);
|
2021-06-25 16:38:42 -07:00
|
|
|
}
|
2020-12-08 02:30:12 -08:00
|
|
|
#endif // EFI_PROD_CODE
|
2020-04-24 11:00:06 -07:00
|
|
|
}
|
2020-12-08 01:52:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void stopTriggerEmulatorPins() {
|
2021-06-25 16:38:42 -07:00
|
|
|
#if EFI_PROD_CODE
|
2020-12-08 02:07:03 -08:00
|
|
|
for (size_t i = 0; i < efi::size(emulatorOutputs); i++) {
|
2021-06-25 16:38:42 -07:00
|
|
|
if (isConfigurationChanged(triggerSimulatorPins[i])) {
|
2023-03-02 20:24:59 -08:00
|
|
|
triggerEmulatorSignal.outputPins[i]->deInit();
|
2021-06-25 16:38:42 -07:00
|
|
|
}
|
2020-12-08 02:07:03 -08:00
|
|
|
}
|
2021-06-25 16:38:42 -07:00
|
|
|
#endif // EFI_PROD_CODE
|
2020-12-08 01:52:49 -08:00
|
|
|
}
|
|
|
|
|
2017-05-15 05:51:40 -07:00
|
|
|
#endif /* EFI_EMULATE_POSITION_SENSORS */
|