32 #if EFI_ENGINE_SNIFFER
37 #define DEBUG_PIN_DELAY US2NT(60)
39 #define TRIGGER_WAVEFORM(x) getTriggerCentral()->triggerShape.x
41 #if EFI_SHAFT_POSITION_INPUT
44 vvtEventRiseCounter(),
45 vvtEventFallCounter(),
66 if (bankIndex >= BANKS_COUNT || camIndex >= CAMS_PER_BANK) {
78 if (std::isnan(oneDegreeUs)) {
87 chibios_rt::CriticalSectionLocker csl;
93 return toothPhase + elapsed / oneDegreeUs;
100 switch (operationMode) {
104 return SYMMETRICAL_CRANK_SENSOR_DIVIDER;
106 return SYMMETRICAL_THREE_TIMES_CRANK_SENSOR_DIVIDER;
108 return SYMMETRICAL_SIX_TIMES_CRANK_SENSOR_DIVIDER;
110 return SYMMETRICAL_TWELVE_TIMES_CRANK_SENSOR_DIVIDER;
122 criticalError(
"unreachable getCrankDivider");
127 return vvtMode != VVT_INACTIVE
128 && vvtMode != VVT_TOYOTA_3_TOOTH
129 && vvtMode != VVT_HONDA_K_INTAKE
130 && vvtMode != VVT_MAP_V_TWIN
131 && vvtMode != VVT_SINGLE_TOOTH;
138 if (totalShift != 0) {
149 for (
int index = 0;index<TRIGGER_INPUT_PIN_COUNT;index++) {
154 for (
int index = 0;index<CAM_INPUTS_COUNT;index++) {
174 if (crankDivider == 1) {
184 case VVT_MITSUBISHI_4G63:
185 case VVT_MITSUBISHI_4G9x:
187 case VVT_SINGLE_TOOTH:
189 case VVT_BOSCH_QUICK_START:
191 case VVT_TOYOTA_3_TOOTH:
193 case VVT_FORD_COYOTE:
196 case VVT_BARRA_3_PLUS_1:
198 case VVT_MAZDA_SKYACTIV:
200 case VVT_MITSUBISHI_4G69:
201 case VVT_MITSUBISHI_3A92:
202 case VVT_MITSUBISHI_6G72:
203 case VVT_MITSUBISHI_6G75:
204 case VVT_HONDA_K_EXHAUST:
205 case VVT_HONDA_CBR_600:
207 case VVT_HONDA_K_INTAKE:
209 criticalError(
"Honda K Intake is not suitable for engine sync");
223 while (vvtPosition < -
period / 2) {
226 while (vvtPosition >=
period / 2) {
248 if (isImportantFront) {
279 }
else if (index == 1) {
281 }
else if (index == 2) {
283 }
else if (index == 3) {
287 int bankIndex = BANK_BY_INDEX(index);
288 int camIndex = CAM_BY_INDEX(index);
298 #ifdef VR_HW_CHECK_MODE
304 for (
int i = 0 ; i < 100 ; i++) {
312 const auto& vvtShape = tc->
vvtShape[camIndex];
317 bool vvtUseOnlyRise = !isVvtWithRealDecoder || vvtShape.useOnlyRisingEdges;
320 logVvtFront(vvtUseOnlyRise, isImportantFront, front, nowNt, index);
322 if (!isImportantFront) {
334 if (isVvtWithRealDecoder) {
357 angle_t angleFromPrimarySyncPoint = currentPhase.Value;
359 angle_t currentPosition = angleFromPrimarySyncPoint - tdcPosition();
377 case VVT_TOYOTA_3_TOOTH:
382 if ((currentPosition < from || currentPosition > to) &&
383 (currentPosition < from + 360 || currentPosition > to + 360)) {
396 case VVT_HONDA_K_INTAKE:
398 vvtPosition =
wrapVvt(vvtPosition, 180);
410 vvtPosition -= crankOffset;
411 vvtPosition =
wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION);
413 if (absF(angleFromPrimarySyncPoint) < 7) {
423 vvtPosition =
wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION);
428 tc->
vvtPosition[bankIndex][camIndex] = vvtPosition;
447 #ifdef VR_HW_CHECK_MODE
453 #if HW_CHECK_ALWAYS_STIMULATE
458 for (
int i = 0 ; i < 100 ; i++) {
476 bool isPrimary = signalIndex == 0;
477 if (!isPrimary && !TRIGGER_WAVEFORM(needSecondTriggerInput)) {
510 if (!logLogicState) {
564 static const bool isUpEvent[4] = {
false,
true,
false,
true };
574 bool isUp =
isUpEvent[(int) ckpSignalType];
577 if (addOppositeEvent) {
617 bool isGapExpected = TRIGGER_WAVEFORM(isSynchronizationNeeded) && triggerState->
getShaftSynchronized() &&
622 allowedPeriod *= TRIGGER_WAVEFORM(syncRatioAvg);
627 efitick_t minAllowedPeriod = 2 * allowedPeriod / 3;
629 efitick_t maxAllowedPeriod = 5 * allowedPeriod / 4;
632 if (currentPeriod >= minAllowedPeriod) {
635 if (!isGapExpected && (maxAllowedPeriod == 0 || currentPeriod <= maxAllowedPeriod)) {
651 auto toothAngle360 = currentPhase;
652 while (toothAngle360 >= 360) {
653 toothAngle360 -= 360;
700 if (angleError < -cycle / 2) {
710 float angleSinceLastTooth = estimatedCurrentPhase.Value - lastToothPhase;
711 if (angleSinceLastTooth < 0.5f) {
728 float absError = absF(angleError);
731 if (isRpmEnough && absError > 10 && absError < 180) {
750 int currentToothIndex = p_currentToothIndex;
761 if (nextToothAngle != 0 && loopAllowance == 0) {
765 return nextToothAngle;
799 if (firstEventInAWhile) {
831 int triggerIndexForListeners = decodeResult.Value.CurrentIndex + (crankInternalIndex *
triggerShape.
getSize());
845 chibios_rt::CriticalSectionLocker csl;
851 #if TRIGGER_EXTREME_LOGGING
852 efiPrintf(
"trigger %d %d %d", triggerIndexForListeners, getRevolutionCounter(),
time2print(
getTimeNowUs()));
862 #if EFI_MAP_AVERAGING
867 #if EFI_LOGIC_ANALYZER
873 float expectNextPhase = nextPhase + tdcPosition();
877 #if EFI_CDM_INTEGRATION
880 engine->knockLogic(cdmKnockValue);
902 #if EFI_PROD_CODE || EFI_SIMULATOR
905 efiPrintf(
"syncEdge=%s",
getSyncEdge(TRIGGER_WAVEFORM(syncEdge)));
906 efiPrintf(
"gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0]));
908 for (
size_t i = 0; i < shape->
getSize(); i++) {
909 efiPrintf(
"event %d %.2f", i, triggerFormDetails->
eventAngles[i]);
919 #if EFI_PROD_CODE || EFI_SIMULATOR
925 #if (HAL_TRIGGER_USE_PAL == TRUE) && (PAL_USE_CALLBACKS == TRUE)
931 efiPrintf(
"Template %s (%d) trigger %s (%d) syncEdge=%s tdcOffset=%.2f",
936 getSyncEdge(TRIGGER_WAVEFORM(syncEdge)), TRIGGER_WAVEFORM(tdcPosition));
951 efiPrintf(
"expected cycle events %d/%d",
956 boolToString(TRIGGER_WAVEFORM(needSecondTriggerInput)));
959 efiPrintf(
"synchronizationNeeded=%s/isError=%s/total errors=%lu ord_err=%lu/total revolutions=%d/self=%s",
967 if (TRIGGER_WAVEFORM(isSynchronizationNeeded)) {
968 efiPrintf(
"gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0]));
976 efiPrintf(
"primary trigger simulator: %s %s freq=%d",
983 #if EFI_EMULATE_POSITION_SENSORS
984 efiPrintf(
"secondary trigger simulator: %s %s phase=%d",
991 for (
int camInputIndex = 0; camInputIndex<CAM_INPUTS_COUNT;camInputIndex++) {
993 int camLogicalIndex = camInputIndex % CAMS_PER_BANK;
996 efiPrintf(
"VVT %d event counters: %d/%d",
1010 #if EFI_ENGINE_SNIFFER
1024 bool changed =
false;
1029 changed |= isConfigurationChanged(camInputs[camIndex]);
1030 changed |= isConfigurationChanged(vvtOffsets[camIndex]);
1034 changed |= isConfigurationChanged(triggerGapOverrideFrom[i]);
1035 changed |= isConfigurationChanged(triggerGapOverrideTo[i]);
1039 changed |= isConfigurationChanged(triggerInputPins[i]);
1042 criticalError(
"Please no physical sensors in CAM by MAP mode index=%d %s", i,
hwPortname(
pin));
1047 changed |= isConfigurationChanged(vvtMode[i]);
1050 changed |= isConfigurationChanged(trigger.type);
1051 changed |= isConfigurationChanged(skippedWheelOnCam);
1052 changed |= isConfigurationChanged(twoStroke);
1053 changed |= isConfigurationChanged(globalTriggerAngleOffset);
1054 changed |= isConfigurationChanged(trigger.customTotalToothCount);
1055 changed |= isConfigurationChanged(trigger.customSkippedToothCount);
1056 changed |= isConfigurationChanged(overrideTriggerGaps);
1057 changed |= isConfigurationChanged(gapTrackingLengthOverride);
1058 changed |= isConfigurationChanged(overrideVvtTriggerGaps);
1059 changed |= isConfigurationChanged(gapVvtTrackingLengthOverride);
1062 #if EFI_ENGINE_CONTROL
1067 #if EFI_DEFAILED_LOGGING
1068 efiPrintf(
"isTriggerConfigChanged=%d", triggerConfigChanged);
1083 if (camVvtValidationIndex == 0) {
1085 }
else if (camVvtValidationIndex == 0xFE &&
vvtCamCounter < 60) {
1104 if (shape.
getSize() >= PWM_PHASE_MAX_COUNT) {
1121 for (
int camIndex = 0;camIndex < CAMS_PER_BANK;camIndex++) {
1144 for (; gapIndex < GAP_TRACKING_LENGTH; gapIndex++) {
1180 for (; gapIndex < VVT_TRACKING_LENGTH; gapIndex++) {
1186 for (
int camIndex = 0; camIndex < CAMS_PER_BANK; camIndex++) {
1220 criticalError(
"First trigger channel not configured while second one is.");
1224 criticalError(
"First bank cam input is required if second bank specified");
1230 #if EFI_ENGINE_SNIFFER
1234 #if EFI_PROD_CODE || EFI_SIMULATOR
const char * getPin_output_mode_e(pin_output_mode_e value)
const char * getVvt_mode_e(vvt_mode_e value)
const char * getTrigger_type_e(trigger_type_e value)
const char * getEngine_type_e(engine_type_e value)
const char * getSyncEdge(SyncEdge value)
int getCurrentCdmValue(int currentRevolution)
TriggerCentral triggerCentral
int getGlobalConfigurationVersion(void) const
RpmCalculator rpmCalculator
constexpr auto & module()
TunerStudioOutputChannels outputChannels
TpsAccelEnrichment tpsAccelEnrichment
void updateTriggerWaveform()
virtual operation_mode_e getOperationMode() const =0
void onFastCallback() override
bool isOld(int globalVersion)
void setNeedsDisambiguation(bool needsDisambiguation)
void resetState() override
angle_t syncEnginePhase(int divider, int remainder, angle_t engineCycle)
bool hasSynchronizedPhase() const
Multi-channel software PWM output configuration.
pwm_config_safe_state_s safe
float getCachedRpm() const
static float getOrZero(SensorType type)
VvtTriggerDecoder vvtState[BANKS_COUNT][CAMS_PER_BANK]
InstantRpmCalculator instantRpm
PrimaryTriggerDecoder triggerState
float m_lastToothPhaseFromSyncPoint
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 isTriggerDecoderError()
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 isTriggerConfigChanged()
void validateCamVvtCounters()
bool directSelfStimulation
bool hwTriggerInputEnabled
bool triggerConfigChangedOnLastConfigurationChange
PrimaryTriggerConfiguration primaryTriggerConfiguration
angle_t currentVVTEventPosition[BANKS_COUNT][CAMS_PER_BANK]
uint32_t engineCycleEventCount
angle_t syncEnginePhaseAndReport(int divider, int remainder)
trigger_config_s TriggerType
int getCrankSynchronizationCounter() const
uint32_t orderingErrorCounter
expected< TriggerDecodeResult > decodeTriggerEvent(const char *msg, const TriggerWaveform &triggerShape, TriggerStateListener *triggerStateListener, const TriggerConfiguration &triggerConfiguration, const trigger_event_e signal, const efitick_t nowNt)
Trigger decoding happens here VR falls are filtered out and some VR noise detection happens prior to ...
bool getShaftSynchronized()
current_cycle_state_s currentCycle
uint32_t toothDurations[GAP_TRACKING_LENGTH+1]
uint32_t totalTriggerErrorCounter
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]
void resetAccumSignalData()
rusEfi console sniffer data buffer
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
const char * boolToString(bool value)
efitimeus_t getTimeNowUs()
int time2print(int64_t time)
EngineRotationState * getEngineRotationState()
LimpManager * getLimpManager()
ExecutorInterface * getExecutorInterface()
EngineState * getEngineState()
TriggerCentral * getTriggerCentral()
void addEngineSnifferVvtEvent(int vvtIndex, FrontDirection frontDirection)
void addEngineSnifferCrankEvent(int wheelIndex, int triggerEventIndex, FrontDirection frontDirection)
void initWaveChart(WaveChart *chart)
rusEfi console wave sniffer
bool warning(ObdCode code, const char *fmt,...)
void firmwareError(ObdCode code, const char *fmt,...)
ioportmask_t criticalErrorLedPin
ioportid_t criticalErrorLedPort
uint32_t ioportmask_t
Digital I/O port sized unsigned type.
GPIO_TypeDef * ioportid_t
Port Identifier.
void writePad(const char *msg, brain_pin_e pin, int bit)
void waTriggerEventListener(trigger_event_e ckpSignalType, uint32_t index, efitick_t edgeTimestamp)
void mainTriggerCallback(uint32_t trgEventIndex, efitick_t edgeTimestamp, angle_t currentPhase, angle_t nextPhase)
void mapAveragingTriggerCallback(uint32_t index, efitick_t edgeTimestamp)
uint32_t getTimeNowLowerNt()
@ CUSTOM_ERR_TRIGGER_ZERO
@ CUSTOM_PRIMARY_BAD_TOOTH_TIMING
@ CUSTOM_ERR_TRIGGER_WAVEFORM_TOO_LONG
@ CUSTOM_VVT_SYNC_POSITION
@ CUSTOM_TRIGGER_EVENT_TYPE
@ CUSTOM_VVT_MODE_NOT_SELECTED
@ CUSTOM_ERR_UNEXPECTED_SHAFT_EVENT
@ OBD_Camshaft_Position_Sensor_Circuit_Range_Performance
@ CUSTOM_PRIMARY_DOUBLED_EDGE
engine_configuration_s * engineConfiguration
const char * hwPortname(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
void tdcMarkCallback(uint32_t trgEventIndex, efitick_t nowNt)
operation_mode_e lookupOperationMode()
void rpmShaftPositionCallback(trigger_event_e ckpSignalType, uint32_t trgEventIndex, efitick_t nowNt)
Shaft position callback used by RPM calculation logic.
@ FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR
@ FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR
@ FOUR_STROKE_THREE_TIMES_CRANK_SENSOR
@ FOUR_STROKE_CRANK_SENSOR
@ FOUR_STROKE_SIX_TIMES_CRANK_SENSOR
@ SHAFT_SECONDARY_FALLING
virtual void scheduleByTimestampNt(const char *msg, scheduling_s *scheduling, efitick_t targetTime, action_s action)=0
Schedule an action to be executed in the future.
size_t eventCount[PWM_PHASE_MAX_WAVE_PER_PWM]
engineSyncCam_e engineSyncCam
float triggerVVTGapOverrideTo[VVT_TRACKING_LENGTH]
Gpio triggerSimulatorPins[TRIGGER_SIMULATOR_PIN_COUNT]
bool invertSecondaryTriggerSignal
int8_t gapTrackingLengthOverride
cranking_parameters_s cranking
uint16_t triggerSimulatorRpm
uint8_t camDecoder2jzPosition
Gpio camInputsDebug[CAM_INPUTS_COUNT]
uint8_t camDecoder2jzPrecision
Gpio triggerInputDebugPins[TRIGGER_INPUT_PIN_COUNT]
vvt_mode_e vvtMode[CAMS_PER_BANK]
brain_input_pin_e logicAnalyzerPins[LOGIC_ANALYZER_CHANNEL_COUNT]
bool invertPrimaryTriggerSignal
scaled_channel< uint8_t, 1, 50 > maxCamPhaseResolveRpm
bool displayLogicLevelsInEngineSniffer
float vvtOffsets[CAM_INPUTS_COUNT]
brain_input_pin_e triggerInputPins[TRIGGER_INPUT_PIN_COUNT]
bool overrideVvtTriggerGaps
pin_output_mode_e triggerSimulatorPinModes[TRIGGER_SIMULATOR_PIN_COUNT]
bool useNoiselessTriggerDecoder
float triggerGapOverrideFrom[GAP_TRACKING_LENGTH]
int8_t gapVvtTrackingLengthOverride
brain_input_pin_e camInputs[CAM_INPUTS_COUNT]
float mapCamDetectionAnglePosition
float triggerVVTGapOverrideFrom[VVT_TRACKING_LENGTH]
float triggerGapOverrideTo[GAP_TRACKING_LENGTH]
scaled_channel< uint16_t, 30, 1 > instantMAPValue
uint8_t triggerIgnoredToothCount
float triggerToothAngleError
float mapVvt_MAP_AT_SPECIAL_POINT
angle_t mapCamPrevToothAngle
uint32_t hwEventCounters[HW_EVENT_TYPES]
float currentEngineDecodedPhase
uint8_t mapVvt_MAP_AT_CYCLE_COUNT
int customSkippedToothCount
int customTotalToothCount
float vvtToothPosition[4]
uint32_t vvtToothDurations0
float triggerSyncGapRatio
void LogTriggerTooth(trigger_event_e tooth, efitick_t timestamp)
PwmConfig triggerEmulatorSignals[NUM_EMULATOR_CHANNELS]
static bool vvtWithRealDecoder(vvt_mode_e vvtMode)
void hwHandleVvtCamSignal(bool isRising, efitick_t timestamp, int index)
static void triggerShapeInfo()
static void reportEventToWaveChart(trigger_event_e ckpSignalType, int triggerEventIndex, bool addOppositeEvent)
int getCrankDivider(operation_mode_e operationMode)
static const bool isUpEvent[4]
static scheduling_s debugToggleScheduling
TriggerDecoderBase initState("init")
void validateTriggerInputs()
void hwHandleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp)
static void logVvtFront(bool useOnlyRise, bool isImportantFront, TriggerValue front, efitick_t nowNt, int index)
void initTriggerCentral()
static const int wheelIndeces[4]
static angle_t wrapVvt(angle_t vvtPosition, int period)
static void turnOffAllDebugFields(void *arg)
static void initVvtShape(TriggerWaveform &shape, const TriggerConfiguration &p_config, TriggerDecoderBase &initState)
uint32_t triggerMaxDuration
static angle_t adjustCrankPhase(int camIndex)
BOARD_WEAK bool boardAllowTriggerActions()
void handleVvtCamSignal(TriggerValue front, efitick_t nowNt, int index)
void onConfigurationChangeTriggerCallback()
void handleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp)
static void calculateTriggerSynchPoint(const PrimaryTriggerConfiguration &primaryTriggerConfiguration, TriggerWaveform &shape, TriggerDecoderBase &initState)
static void resetRunningTriggerCounters()
static TriggerWheel eventIndex[4]
void disableTriggerStimulator()
bool isUsefulSignal(trigger_event_e signal, const TriggerWaveform &shape)
angle_t wrapAngleMethod(angle_t param, const char *msg="", ObdCode code=ObdCode::OBD_PCM_Processor_Fault)
void wrapAngle(angle_t &angle, const char *msg, ObdCode code)
angle_t getEngineCycle(operation_mode_e operationMode)