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 (cisnan(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:
195 case VVT_BARRA_3_PLUS_1:
197 case VVT_MAZDA_SKYACTIV:
198 case VVT_MITSUBISHI_4G69:
199 case VVT_MITSUBISHI_3A92:
200 case VVT_MITSUBISHI_6G72:
201 case VVT_MITSUBISHI_6G75:
202 case VVT_HONDA_K_EXHAUST:
203 case VVT_HONDA_CBR_600:
205 case VVT_HONDA_K_INTAKE:
207 criticalError(
"Honda K Intake is not suitable for engine sync");
221 while (vvtPosition < -
period / 2) {
224 while (vvtPosition >=
period / 2) {
246 if (isImportantFront) {
277 }
else if (index == 1) {
279 }
else if (index == 2) {
281 }
else if (index == 3) {
285 int bankIndex = BANK_BY_INDEX(index);
286 int camIndex = CAM_BY_INDEX(index);
296 #ifdef VR_HW_CHECK_MODE
302 for (
int i = 0 ; i < 100 ; i++) {
310 const auto& vvtShape = tc->
vvtShape[camIndex];
315 bool vvtUseOnlyRise = !isVvtWithRealDecoder || vvtShape.useOnlyRisingEdges;
318 logVvtFront(vvtUseOnlyRise, isImportantFront, front, nowNt, index);
320 if (!isImportantFront) {
332 if (isVvtWithRealDecoder) {
355 angle_t angleFromPrimarySyncPoint = currentPhase.Value;
357 angle_t currentPosition = angleFromPrimarySyncPoint - tdcPosition();
375 case VVT_TOYOTA_3_TOOTH:
380 if ((currentPosition < from || currentPosition > to) &&
381 (currentPosition < from + 360 || currentPosition > to + 360)) {
394 case VVT_HONDA_K_INTAKE:
396 vvtPosition =
wrapVvt(vvtPosition, 180);
408 vvtPosition -= crankOffset;
409 vvtPosition =
wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION);
411 if (absF(angleFromPrimarySyncPoint) < 7) {
421 vvtPosition =
wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION);
426 tc->
vvtPosition[bankIndex][camIndex] = vvtPosition;
445 #ifdef VR_HW_CHECK_MODE
451 #if HW_CHECK_ALWAYS_STIMULATE
456 for (
int i = 0 ; i < 100 ; i++) {
474 bool isPrimary = signalIndex == 0;
475 if (!isPrimary && !TRIGGER_WAVEFORM(needSecondTriggerInput)) {
508 if (!logLogicState) {
562 static const bool isUpEvent[4] = {
false,
true,
false,
true };
572 bool isUp =
isUpEvent[(int) ckpSignalType];
575 if (addOppositeEvent) {
615 bool isGapExpected = TRIGGER_WAVEFORM(isSynchronizationNeeded) && triggerState->
getShaftSynchronized() &&
620 allowedPeriod *= TRIGGER_WAVEFORM(syncRatioAvg);
625 efitick_t minAllowedPeriod = 2 * allowedPeriod / 3;
627 efitick_t maxAllowedPeriod = 5 * allowedPeriod / 4;
630 if (currentPeriod >= minAllowedPeriod) {
633 if (!isGapExpected && (maxAllowedPeriod == 0 || currentPeriod <= maxAllowedPeriod)) {
649 auto toothAngle360 = currentPhase;
650 while (toothAngle360 >= 360) {
651 toothAngle360 -= 360;
698 if (angleError < -cycle / 2) {
708 float angleSinceLastTooth = estimatedCurrentPhase.Value - lastToothPhase;
709 if (angleSinceLastTooth < 0.5f) {
726 float absError = absF(angleError);
729 if (isRpmEnough && absError > 10 && absError < 180) {
748 int currentToothIndex = p_currentToothIndex;
759 if (nextPhase != 0 && loopAllowance == 0) {
796 if (firstEventInAWhile) {
828 int triggerIndexForListeners = decodeResult.Value.CurrentIndex + (crankInternalIndex *
triggerShape.
getSize());
842 chibios_rt::CriticalSectionLocker csl;
848 #if TRIGGER_EXTREME_LOGGING
849 efiPrintf(
"trigger %d %d %d", triggerIndexForListeners, getRevolutionCounter(),
time2print(
getTimeNowUs()));
859 #if EFI_MAP_AVERAGING
864 #if EFI_LOGIC_ANALYZER
870 float expectNextPhase = nextPhase + tdcPosition();
874 #if EFI_CDM_INTEGRATION
877 engine->knockLogic(cdmKnockValue);
899 #if EFI_PROD_CODE || EFI_SIMULATOR
902 efiPrintf(
"syncEdge=%s",
getSyncEdge(TRIGGER_WAVEFORM(syncEdge)));
903 efiPrintf(
"gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0]));
905 for (
size_t i = 0; i < shape->
getSize(); i++) {
906 efiPrintf(
"event %d %.2f", i, triggerFormDetails->
eventAngles[i]);
916 #if EFI_PROD_CODE || EFI_SIMULATOR
922 #if (HAL_TRIGGER_USE_PAL == TRUE) && (PAL_USE_CALLBACKS == TRUE)
928 efiPrintf(
"Template %s (%d) trigger %s (%d) syncEdge=%s tdcOffset=%.2f",
931 getSyncEdge(TRIGGER_WAVEFORM(syncEdge)), TRIGGER_WAVEFORM(tdcPosition));
946 efiPrintf(
"expected cycle events %d/%d",
951 boolToString(TRIGGER_WAVEFORM(needSecondTriggerInput)));
954 efiPrintf(
"synchronizationNeeded=%s/isError=%s/total errors=%d ord_err=%d/total revolutions=%d/self=%s",
962 if (TRIGGER_WAVEFORM(isSynchronizationNeeded)) {
963 efiPrintf(
"gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0]));
971 efiPrintf(
"primary trigger simulator: %s %s freq=%d",
978 #if EFI_EMULATE_POSITION_SENSORS
979 efiPrintf(
"secondary trigger simulator: %s %s phase=%d",
986 for (
int camInputIndex = 0; camInputIndex<CAM_INPUTS_COUNT;camInputIndex++) {
988 int camLogicalIndex = camInputIndex % CAMS_PER_BANK;
991 efiPrintf(
"VVT %d event counters: %d/%d",
1005 #if EFI_ENGINE_SNIFFER
1019 bool changed =
false;
1024 changed |= isConfigurationChanged(camInputs[camIndex]);
1025 changed |= isConfigurationChanged(vvtOffsets[camIndex]);
1029 changed |= isConfigurationChanged(triggerGapOverrideFrom[i]);
1030 changed |= isConfigurationChanged(triggerGapOverrideTo[i]);
1034 changed |= isConfigurationChanged(triggerInputPins[i]);
1037 criticalError(
"Please no physical sensors in CAM by MAP mode index=%d %s", i,
hwPortname(
pin));
1042 changed |= isConfigurationChanged(vvtMode[i]);
1045 changed |= isConfigurationChanged(trigger.type);
1046 changed |= isConfigurationChanged(skippedWheelOnCam);
1047 changed |= isConfigurationChanged(twoStroke);
1048 changed |= isConfigurationChanged(globalTriggerAngleOffset);
1049 changed |= isConfigurationChanged(trigger.customTotalToothCount);
1050 changed |= isConfigurationChanged(trigger.customSkippedToothCount);
1051 changed |= isConfigurationChanged(overrideTriggerGaps);
1052 changed |= isConfigurationChanged(gapTrackingLengthOverride);
1053 changed |= isConfigurationChanged(overrideVvtTriggerGaps);
1054 changed |= isConfigurationChanged(gapVvtTrackingLengthOverride);
1057 #if EFI_ENGINE_CONTROL
1062 #if EFI_DEFAILED_LOGGING
1063 efiPrintf(
"isTriggerConfigChanged=%d", triggerConfigChanged);
1078 if (camVvtValidationIndex == 0) {
1080 }
else if (camVvtValidationIndex == 0xFE &&
vvtCamCounter < 60) {
1099 if (shape.
getSize() >= PWM_PHASE_MAX_COUNT) {
1116 for (
int camIndex = 0;camIndex < CAMS_PER_BANK;camIndex++) {
1135 TRIGGER_WAVEFORM(setTriggerSynchronizationGap3(gapIndex, gapOverrideFrom, gapOverrideTo));
1139 for (; gapIndex < GAP_TRACKING_LENGTH; gapIndex++) {
1174 for (; gapIndex < VVT_TRACKING_LENGTH; gapIndex++) {
1180 for (
int camIndex = 0; camIndex < CAMS_PER_BANK; camIndex++) {
1214 criticalError(
"First trigger channel not configured while second one is.");
1218 criticalError(
"First bank cam input is required if second bank specified");
1224 #if EFI_ENGINE_SNIFFER
1228 #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 timeNt, action_s action)=0
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)