35#define TRIGGER_WAVEFORM(x) getTriggerCentral()->triggerShape.x
37#if EFI_SHAFT_POSITION_INPUT
59 if (bankIndex >= BANKS_COUNT || camIndex >= CAMS_PER_BANK) {
71 if (std::isnan(oneDegreeUs)) {
80 chibios_rt::CriticalSectionLocker csl;
86 return toothPhase + elapsed / oneDegreeUs;
93 switch (operationMode) {
97 return SYMMETRICAL_CRANK_SENSOR_DIVIDER;
99 return SYMMETRICAL_THREE_TIMES_CRANK_SENSOR_DIVIDER;
101 return SYMMETRICAL_SIX_TIMES_CRANK_SENSOR_DIVIDER;
103 return SYMMETRICAL_TWELVE_TIMES_CRANK_SENSOR_DIVIDER;
115 criticalError(
"unreachable getCrankDivider");
128 return vvtMode != VVT_INACTIVE
129 && vvtMode != VVT_TOYOTA_3_TOOTH
130 && vvtMode != VVT_HONDA_K_INTAKE
131 && vvtMode != VVT_MAP_V_TWIN
133 && vvtMode != VVT_SINGLE_TOOTH;
140 if (totalShift != 0) {
167 if (crankDivider == 1) {
177 case VVT_MITSUBISHI_4G63:
180 case VVT_SINGLE_TOOTH:
182 case VVT_BOSCH_QUICK_START:
184 case VVT_TOYOTA_3TOOTH_UZ:
185 case VVT_TOYOTA_3_TOOTH:
187 case VVT_FORD_COYOTE:
190 case VVT_BARRA_3_PLUS_1:
193 case VVT_MAZDA_SKYACTIV:
195 case VVT_MITSUBISHI_4G69:
196 case VVT_MITSUBISHI_3A92:
197 case VVT_MITSUBISHI_6G72:
198 case VVT_CHRYSLER_PHASER:
199 case VVT_HONDA_K_EXHAUST:
200 case VVT_HONDA_CBR_600:
201 case VVT_SUBARU_7TOOTH:
207 case VVT_HONDA_K_INTAKE:
209 criticalError(
"Honda K Intake is not suitable for engine sync");
225 while (vvtPosition < -
period / 2) {
228 while (vvtPosition >=
period / 2) {
243 if (isImportantFront) {
273 int camIndex = CAM_BY_INDEX(index);
276 if (isRising ^ invertSetting) {
303 case VVT_TOYOTA_3_TOOTH:
308 if ((currentPosition < from || currentPosition > to) &&
309 (currentPosition < from + 360 || currentPosition > to + 360)) {
327 }
else if (index == 1) {
329 }
else if (index == 2) {
331 }
else if (index == 3) {
335 int bankIndex = BANK_BY_INDEX(index);
336 int camIndex = CAM_BY_INDEX(index);
346 const auto& vvtShape = tc->
vvtShape[camIndex];
351 bool vvtUseOnlyRise = !isVvtWithRealDecoder || vvtShape.useOnlyRisingEdges;
354 logVvtFront(vvtUseOnlyRise, isImportantFront, front, nowNt, index);
356 if (!isImportantFront) {
368 if (isVvtWithRealDecoder) {
388 angle_t angleFromPrimarySyncPoint = currentPhase.Value;
390 angle_t currentPosition = angleFromPrimarySyncPoint - tdcPosition();
414 case VVT_HONDA_K_INTAKE:
416 vvtPosition =
wrapVvt(vvtPosition, 180);
435 vvtPosition -= crankOffset;
436 vvtPosition =
wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION);
438 if (absF(angleFromPrimarySyncPoint) < 7) {
448 vvtPosition =
wrapVvt(vvtPosition, FOUR_STROKE_CYCLE_DURATION);
453 tc->
vvtPosition[bankIndex][camIndex] = vvtPosition;
486 bool isPrimary = signalIndex == 0;
487 if (!isPrimary && !TRIGGER_WAVEFORM(needSecondTriggerInput)) {
520 if (!logLogicState) {
579 if (addOppositeEvent) {
619 bool isGapExpected = TRIGGER_WAVEFORM(isSynchronizationNeeded) && triggerState->
getShaftSynchronized() &&
624 allowedPeriod *= TRIGGER_WAVEFORM(syncRatioAvg);
629 efitick_t minAllowedPeriod = 2 * allowedPeriod / 3;
631 efitick_t maxAllowedPeriod = 5 * allowedPeriod / 4;
634 if (currentPeriod >= minAllowedPeriod) {
637 if (!isGapExpected && (maxAllowedPeriod == 0 || currentPeriod <= maxAllowedPeriod)) {
652 auto toothAngle360 = currentPhase;
653 while (toothAngle360 >= 360) {
654 toothAngle360 -= 360;
695 UNUSED(toothIndexForListeners);
705 if (toothIndexForListeners > 2) {
738 if (angleError < -cycle / 2) {
748 float angleSinceLastTooth = estimatedCurrentPhase.Value - lastToothPhase;
749 if (angleSinceLastTooth < 0.5f) {
766 float absError = absF(angleError);
769 if (isRpmEnough && absError > 10 && absError < 180) {
788 int currentToothIndex = p_currentToothIndex;
799 if (nextToothAngle != 0 && loopAllowance == 0) {
803 return nextToothAngle;
835 if (firstEventInAWhile) {
867 int triggerIndexForListeners = decodeResult.Value.CurrentIndex + (crankInternalIndex *
triggerShape.
getSize());
881 chibios_rt::CriticalSectionLocker csl;
887#if TRIGGER_EXTREME_LOGGING
888 efiPrintf(
"trigger %d %d %d", triggerIndexForListeners, getRevolutionCounter(),
time2print(
getTimeNowUs()));
897#if EFI_LOGIC_ANALYZER
903 float expectNextPhase = nextPhase + tdcPosition();
907#if EFI_CDM_INTEGRATION
910 engine->knockLogic(cdmKnockValue);
936#if EFI_PROD_CODE || EFI_SIMULATOR
939 efiPrintf(
"syncEdge=%s",
getSyncEdge(TRIGGER_WAVEFORM(syncEdge)));
940 efiPrintf(
"gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0]));
942 for (
size_t i = 0; i < shape->
getSize(); i++) {
943 efiPrintf(
"event %d %.2f", i, triggerFormDetails->
eventAngles[i]);
953#if EFI_PROD_CODE || EFI_SIMULATOR
959#if (HAL_TRIGGER_USE_PAL == TRUE) && (PAL_USE_CALLBACKS == TRUE)
965 efiPrintf(
"Template %s (%d) trigger %s (%d) syncEdge=%s tdcOffset=%.2f",
970 getSyncEdge(TRIGGER_WAVEFORM(syncEdge)), TRIGGER_WAVEFORM(tdcPosition));
985 efiPrintf(
"expected cycle events %d/%d",
990 boolToString(TRIGGER_WAVEFORM(needSecondTriggerInput)));
993 efiPrintf(
"synchronizationNeeded=%s/isError=%s/total errors=%lu ord_err=%lu/total revolutions=%d/self=%s",
1001 if (TRIGGER_WAVEFORM(isSynchronizationNeeded)) {
1002 efiPrintf(
"gap from %.2f to %.2f", TRIGGER_WAVEFORM(synchronizationRatioFrom[0]), TRIGGER_WAVEFORM(synchronizationRatioTo[0]));
1010 efiPrintf(
"primary trigger simulator: %s %s freq=%d",
1017#if EFI_EMULATE_POSITION_SENSORS
1018 efiPrintf(
"secondary trigger simulator: %s %s phase=%d",
1025 for (
int camInputIndex = 0; camInputIndex<CAM_INPUTS_COUNT;camInputIndex++) {
1027 int camLogicalIndex = camInputIndex % CAMS_PER_BANK;
1030 efiPrintf(
"VVT %d event counters: %d/%d",
1044#if EFI_ENGINE_SNIFFER
1058 bool changed =
false;
1063 changed |= isConfigurationChanged(camInputs[camIndex]);
1064 changed |= isConfigurationChanged(vvtOffsets[camIndex]);
1068 changed |= isConfigurationChanged(triggerGapOverrideFrom[i]);
1069 changed |= isConfigurationChanged(triggerGapOverrideTo[i]);
1073 changed |= isConfigurationChanged(triggerInputPins[i]);
1076 criticalError(
"Please no physical sensors in CAM by MAP mode index=%d %s", i,
hwPortname(
pin));
1081 changed |= isConfigurationChanged(vvtMode[i]);
1084 changed |= isConfigurationChanged(trigger.type);
1085 changed |= isConfigurationChanged(skippedWheelOnCam);
1086 changed |= isConfigurationChanged(twoStroke);
1087 changed |= isConfigurationChanged(globalTriggerAngleOffset);
1088 changed |= isConfigurationChanged(trigger.customTotalToothCount);
1089 changed |= isConfigurationChanged(trigger.customSkippedToothCount);
1090 changed |= isConfigurationChanged(overrideTriggerGaps);
1091 changed |= isConfigurationChanged(gapTrackingLengthOverride);
1092 changed |= isConfigurationChanged(overrideVvtTriggerGaps);
1093 changed |= isConfigurationChanged(gapVvtTrackingLengthOverride);
1096 #if EFI_ENGINE_CONTROL
1101#if EFI_DETAILED_LOGGING
1102 efiPrintf(
"isTriggerConfigChanged=%d", triggerConfigChanged);
1111 if (camIndex == 0) {
1122 if (camVvtValidationIndex == 0) {
1124 }
else if (camVvtValidationIndex == 0xFE &&
vvtCamCounter < 60) {
1143 if (shape.
getSize() >= PWM_PHASE_MAX_COUNT) {
1175 for (; gapIndex < GAP_TRACKING_LENGTH; gapIndex++) {
1196 for (; gapIndex < VVT_TRACKING_LENGTH; gapIndex++) {
1206 for (
int camIndex = 0;camIndex < CAMS_PER_BANK;camIndex++) {
1233 for (
int camIndex = 0; camIndex < CAMS_PER_BANK; camIndex++) {
1268 criticalError(
"First trigger channel not configured while second one is.");
1272 criticalError(
"First bank cam input is required if second bank specified");
1278#if EFI_ENGINE_SNIFFER
1282#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 * getEngine_type_e(engine_type_e value)
const char * getTrigger_type_e(trigger_type_e value)
const char * getSyncEdge(SyncEdge value)
int getCurrentCdmValue(int currentRevolution)
TriggerCentral triggerCentral
int getGlobalConfigurationVersion() const
RpmCalculator rpmCalculator
TunerStudioOutputChannels outputChannels
void updateTriggerConfiguration()
constexpr auto & module()
virtual operation_mode_e getOperationMode() const =0
bool allowTriggerInput() const
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
bool isTriggerDecoderError()
bool isSpinningJustForWatchdog
expected< float > expectedNextPhase
TriggerWaveform triggerShape
void decodeMapCam(int triggerIndexForListeners, efitick_t nowNt, float currentPhase)
bool isToothExpectedNow(efitick_t timestamp)
angle_t vvtPosition[BANKS_COUNT][CAMS_PER_BANK]
TriggerFormDetails triggerFormDetails
void applyCamGapOverride()
bool isMapCamSync(efitick_t nowNt, float currentPhase)
void applyShapesConfiguration()
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 applyTriggerGapOverride()
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
uint32_t orderingErrorCounter
int getSynchronizationCounter() const
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 ...
current_cycle_state_s currentCycle
uint32_t toothDurations[GAP_TRACKING_LENGTH+1]
uint32_t totalTriggerErrorCounter
bool getShaftSynchronized() const
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)
LimpManager * getLimpManager()
TriggerCentral * getTriggerCentral()
EngineRotationState * getEngineRotationState()
EngineState * getEngineState()
static EngineAccessor engine
static constexpr engine_configuration_s * engineConfiguration
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,...)
UNUSED(samplingTimeSeconds)
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)
uint32_t getTimeNowLowerNt()
@ CUSTOM_ERR_TRIGGER_ZERO
@ CUSTOM_PRIMARY_BAD_TOOTH_TIMING
@ CUSTOM_ERR_TRIGGER_WAVEFORM_TOO_LONG
@ CUSTOM_VVT_SYNC_POSITION
@ CUSTOM_ERR_INPUT_DURING_INITIALISATION
@ 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
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
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
bool invertExhaustCamVVTSignal
uint8_t camDecoder2jzPosition
uint8_t camDecoder2jzPrecision
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
uint16_t vvtEventRiseCounter[CAM_INPUTS_COUNT]
uint8_t triggerIgnoredToothCount
float triggerToothAngleError
float mapVvt_MAP_AT_SPECIAL_POINT
uint16_t hwEventCounters[HW_EVENT_TYPES]
angle_t mapCamPrevToothAngle
uint32_t temp_mapVvt_index
float currentEngineDecodedPhase
int8_t mapVvt_MAP_AT_CYCLE_COUNT
uint8_t mapVvt_min_point_counter
uint8_t mapVvt_sync_counter
uint16_t vvtEventFallCounter[CAM_INPUTS_COUNT]
int customSkippedToothCount
int customTotalToothCount
float vvtToothPosition[4]
uint32_t vvtToothDurations0
void setArrayValues(TValue(&array)[TSize], float value)
void LogTriggerCamTooth(bool isRising, efitick_t timestamp, int index)
PwmConfig triggerEmulatorSignals[NUM_EMULATOR_CHANNELS]
static bool vvtWithRealDecoder(vvt_mode_e vvtMode)
static void triggerShapeInfo()
static void reportEventToWaveChart(trigger_event_e ckpSignalType, int triggerEventIndex, bool addOppositeEvent)
int getCrankDivider(operation_mode_e operationMode)
PUBLIC_API_WEAK void boardTriggerCallback(efitick_t timestamp, float currentPhase)
PUBLIC_API_WEAK angle_t customAdjustCustom(TriggerCentral *tc, vvt_mode_e vvtMode)
TriggerDecoderBase initState("init")
void validateTriggerInputs()
void hwHandleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp)
PUBLIC_API_WEAK bool boardAllowTriggerActions()
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)
PUBLIC_API_WEAK bool boardIsSpecialVvtDecoder(vvt_mode_e vvtMode)
static void initVvtShape(int camIndex, TriggerWaveform &shape, const TriggerConfiguration &p_config, TriggerDecoderBase &initState)
PUBLIC_API_WEAK bool skipToothSpecialShape(size_t index, vvt_mode_e vvtMode, angle_t currentPosition)
uint32_t triggerMaxDuration
static angle_t adjustCrankPhase(int camIndex)
void handleVvtCamSignal(TriggerValue front, efitick_t nowNt, int index)
static bool tooSoonToHandleSignal()
void onConfigurationChangeTriggerCallback()
void handleShaftSignal(int signalIndex, bool isRising, efitick_t timestamp)
static void calculateTriggerSynchPoint(const PrimaryTriggerConfiguration &primaryTriggerConfiguration, TriggerWaveform &shape, TriggerDecoderBase &initState)
void hwHandleVvtCamSignal(bool isRising, efitick_t nowNt, int index)
static void resetRunningTriggerCounters()
constexpr bool isTriggerUpEvent(trigger_event_e event)
int getCrankDivider(operation_mode_e operationMode)
TriggerCentral * getTriggerCentral()
void hwHandleVvtCamSignal(TriggerValue front, efitick_t timestamp, int index)
static TriggerWheel eventIndex[4]
bool isUsefulSignal(trigger_event_e signal, const TriggerWaveform &shape)
void wrapAngle(angle_t &angle, const char *msg, ObdCode code)
angle_t wrapAngleMethod(angle_t param, const char *msg="", ObdCode code=ObdCode::OBD_PCM_Processor_Fault)
angle_t getEngineCycle(operation_mode_e operationMode)