rusEFI
The most advanced open source ECU
Public Member Functions | Data Fields | Private Member Functions | Private Attributes
TriggerCentral Class Referencefinal

#include <trigger_central.h>

Inheritance diagram for TriggerCentral:
Inheritance graph
[legend]
Collaboration diagram for TriggerCentral:
Collaboration graph
[legend]

Public Member Functions

 TriggerCentral ()
 
angle_t syncEnginePhaseAndReport (int divider, int remainder)
 
void handleShaftSignal (trigger_event_e signal, efitick_t timestamp)
 
int getHwEventCounter (int index) const
 
void resetCounters ()
 
void validateCamVvtCounters ()
 
void updateWaveform ()
 
angle_t findNextTriggerToothAngle (int nextToothIndex)
 
void prepareTriggerShape ()
 
bool checkIfTriggerConfigChanged ()
 
bool isTriggerConfigChanged ()
 
bool isTriggerDecoderError ()
 
expected< float > getCurrentEnginePhase (efitick_t nowNt) const
 
float getSecondsSinceTriggerEvent (efitick_t nowNt) const
 
bool engineMovedRecently (efitick_t nowNt) const
 
bool engineMovedRecently () const
 
angle_t getVVTPosition (uint8_t bankIndex, uint8_t camIndex)
 

Data Fields

InstantRpmCalculator instantRpm
 
bool hwTriggerInputEnabled = true
 
cyclic_buffer< int > triggerErrorDetection
 
bool directSelfStimulation = false
 
PrimaryTriggerConfiguration primaryTriggerConfiguration
 
VvtTriggerConfiguration vvtTriggerConfiguration [CAMS_PER_BANK] = {{"VVT1 ", 0}}
 
LocalVersionHolder triggerVersion
 
bool isSpinningJustForWatchdog = false
 
float mapCamPrevCycleValue = 0
 
int prevChangeAtCycle = 0
 
uint32_t engineCycleEventCount = 0
 
bool triggerConfigChangedOnLastConfigurationChange = false
 
TriggerNoiseFilter noiseFilter
 
int vvtEventRiseCounter [CAM_INPUTS_COUNT]
 
int vvtEventFallCounter [CAM_INPUTS_COUNT]
 
angle_t currentVVTEventPosition [BANKS_COUNT][CAMS_PER_BANK]
 
angle_t vvtPosition [BANKS_COUNT][CAMS_PER_BANK]
 
PrimaryTriggerDecoder triggerState
 
TriggerWaveform triggerShape
 
VvtTriggerDecoder vvtState [BANKS_COUNT][CAMS_PER_BANK]
 
TriggerWaveform vvtShape [CAMS_PER_BANK]
 
TriggerFormDetails triggerFormDetails
 
Timer m_lastEventTimer
 
bool isEngineSnifferEnabled = false
 
- Data Fields inherited from trigger_central_s
uint32_t hwEventCounters [HW_EVENT_TYPES]
 
uint32_t vvtCamCounter = (uint32_t)0
 
float mapVvt_MAP_AT_SPECIAL_POINT = (float)0
 
float mapVvt_MAP_AT_DIFF = (float)0
 
uint8_t mapVvt_MAP_AT_CYCLE_COUNT = (uint8_t)0
 
uint8_t mapVvt_map_peak = (uint8_t)0
 
uint8_t alignmentFill_at_38 [2]
 
float currentEngineDecodedPhase = (float)0
 
float triggerToothAngleError = (float)0
 
uint8_t triggerIgnoredToothCount = (uint8_t)0
 
uint8_t alignmentFill_at_49 [3]
 
angle_t mapCamPrevToothAngle = (angle_t)0
 
bool isDecodingMapCam: 1 {}
 
bool unusedBit_13_1: 1 {}
 
bool unusedBit_13_2: 1 {}
 
bool unusedBit_13_3: 1 {}
 
bool unusedBit_13_4: 1 {}
 
bool unusedBit_13_5: 1 {}
 
bool unusedBit_13_6: 1 {}
 
bool unusedBit_13_7: 1 {}
 
bool unusedBit_13_8: 1 {}
 
bool unusedBit_13_9: 1 {}
 
bool unusedBit_13_10: 1 {}
 
bool unusedBit_13_11: 1 {}
 
bool unusedBit_13_12: 1 {}
 
bool unusedBit_13_13: 1 {}
 
bool unusedBit_13_14: 1 {}
 
bool unusedBit_13_15: 1 {}
 
bool unusedBit_13_16: 1 {}
 
bool unusedBit_13_17: 1 {}
 
bool unusedBit_13_18: 1 {}
 
bool unusedBit_13_19: 1 {}
 
bool unusedBit_13_20: 1 {}
 
bool unusedBit_13_21: 1 {}
 
bool unusedBit_13_22: 1 {}
 
bool unusedBit_13_23: 1 {}
 
bool unusedBit_13_24: 1 {}
 
bool unusedBit_13_25: 1 {}
 
bool unusedBit_13_26: 1 {}
 
bool unusedBit_13_27: 1 {}
 
bool unusedBit_13_28: 1 {}
 
bool unusedBit_13_29: 1 {}
 
bool unusedBit_13_30: 1 {}
 
bool unusedBit_13_31: 1 {}
 
uint32_t triggerElapsedUs = (uint32_t)0
 

Private Member Functions

void decodeMapCam (efitick_t nowNt, float currentPhase)
 
bool isToothExpectedNow (efitick_t timestamp)
 

Private Attributes

Timer m_lastToothTimer
 
float m_lastToothPhaseFromSyncPoint
 
expected< float > expectedNextPhase = unexpected
 

Detailed Description

Maybe merge TriggerCentral and TriggerState classes into one class? Probably not: we have an instance of TriggerState which is used for trigger initialization, also composition probably better than inheritance here

Definition at line 49 of file trigger_central.h.

Constructor & Destructor Documentation

◆ TriggerCentral()

TriggerCentral::TriggerCentral ( )

Definition at line 43 of file trigger_central.cpp.

43  :
46  vvtPosition(),
47  triggerState("TRG")
48 {
49  memset(&hwEventCounters, 0, sizeof(hwEventCounters));
52 }
void resetState() override
PrimaryTriggerDecoder triggerState
int vvtEventFallCounter[CAM_INPUTS_COUNT]
angle_t vvtPosition[BANKS_COUNT][CAMS_PER_BANK]
TriggerNoiseFilter noiseFilter
int vvtEventRiseCounter[CAM_INPUTS_COUNT]
uint32_t hwEventCounters[HW_EVENT_TYPES]
Here is the call graph for this function:

Member Function Documentation

◆ checkIfTriggerConfigChanged()

bool TriggerCentral::checkIfTriggerConfigChanged ( )
Returns
true if configuration just changed, and if that change has affected trigger

Definition at line 1205 of file trigger_central.cpp.

1205  {
1206  // we want to make sure that configuration has changed AND that change has changed trigger specifically
1208  triggerConfigChangedOnLastConfigurationChange = false; // whoever has called the method is supposed to react to changes
1209  return result;
1210 }
int getGlobalConfigurationVersion(void) const
Definition: engine.cpp:315
bool isOld(int globalVersion)
LocalVersionHolder triggerVersion
bool triggerConfigChangedOnLastConfigurationChange
Engine * engine
Here is the call graph for this function:

◆ decodeMapCam()

void TriggerCentral::decodeMapCam ( efitick_t  nowNt,
float  currentPhase 
)
private

Definition at line 646 of file trigger_central.cpp.

646  {
647  isDecodingMapCam = engineConfiguration->vvtMode[0] == VVT_MAP_V_TWIN &&
649  if (isDecodingMapCam) {
650  // we are trying to figure out which 360 half of the total 720 degree cycle is which, so we compare those in 360 degree sense.
651  auto toothAngle360 = currentPhase;
652  while (toothAngle360 >= 360) {
653  toothAngle360 -= 360;
654  }
655 
656  if (mapCamPrevToothAngle < engineConfiguration->mapCamDetectionAnglePosition && toothAngle360 > engineConfiguration->mapCamDetectionAnglePosition) {
657  // we are somewhere close to 'mapCamDetectionAnglePosition'
658 
659  // warning: hack hack hack
661 
662  // Compute diff against the last time we were here
663  float diff = map - mapCamPrevCycleValue;
664  mapCamPrevCycleValue = map;
665 
666  if (diff > 0) {
667  mapVvt_map_peak++;
669  mapVvt_MAP_AT_CYCLE_COUNT = revolutionCounter - prevChangeAtCycle;
670  prevChangeAtCycle = revolutionCounter;
671 
672  hwHandleVvtCamSignal(TriggerValue::RISE, timestamp, /*index*/0);
673  hwHandleVvtCamSignal(TriggerValue::FALL, timestamp, /*index*/0);
674 #if EFI_UNIT_TEST
675  // hack? feature? existing unit test relies on VVT phase available right away
676  // but current implementation which is based on periodicFastCallback would only make result available on NEXT tooth
678 #endif // EFI_UNIT_TEST
679  }
680 
682  mapVvt_MAP_AT_DIFF = diff;
683  }
684 
685  mapCamPrevToothAngle = toothAngle360;
686  }
687 }
TunerStudioOutputChannels outputChannels
Definition: engine.h:99
void onFastCallback() override
static float getOrZero(SensorType type)
Definition: sensor.h:92
float mapCamPrevCycleValue
int getCrankSynchronizationCounter() const
LimpManager * getLimpManager()
Definition: engine.cpp:615
TriggerCentral * getTriggerCentral()
Definition: engine.cpp:609
engine_configuration_s * engineConfiguration
scaled_channel< uint16_t, 30, 1 > instantMAPValue
void hwHandleVvtCamSignal(bool isRising, efitick_t timestamp, int index)

Referenced by handleShaftSignal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ engineMovedRecently() [1/2]

bool TriggerCentral::engineMovedRecently ( ) const
inline

Definition at line 156 of file trigger_central.h.

156  {
158  }
bool engineMovedRecently() const
efitick_t getTimeNowNt()
Definition: efitime.cpp:19
Here is the call graph for this function:

◆ engineMovedRecently() [2/2]

bool TriggerCentral::engineMovedRecently ( efitick_t  nowNt) const
inline

Definition at line 138 of file trigger_central.h.

138  {
139  // todo: this user-defined property is a quick solution, proper fix https://github.com/rusefi/rusefi/issues/6593 is needed
141  return false;
142  }
143 
144  constexpr float oneRevolutionLimitInSeconds = 60.0 / RPM_LOW_THRESHOLD;
145  auto maxAverageToothTime = oneRevolutionLimitInSeconds / triggerShape.getSize();
146 
147  // Some triggers may have long gaps (with many teeth), don't count that as stopped!
148  auto maxAllowedGap = maxAverageToothTime * 10;
149 
150  // Clamp between 0.1 seconds ("instant" for a human) and worst case of one engine cycle on low tooth count wheel
151  maxAllowedGap = clampF(0.1f, maxAllowedGap, oneRevolutionLimitInSeconds);
152 
153  return getSecondsSinceTriggerEvent(nowNt) < maxAllowedGap;
154  }
float getSecondsSinceTriggerEvent(efitick_t nowNt) const
TriggerWaveform triggerShape
size_t getSize() const

Referenced by applyIACposition(), RpmCalculator::checkIfSpinning(), EtbController::checkStatus(), Engine::efiWatchdog(), getAcrState(), RpmCalculator::onSlowCallback(), and FuelPumpController::onSlowCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ findNextTriggerToothAngle()

angle_t TriggerCentral::findNextTriggerToothAngle ( int  nextToothIndex)

Definition at line 749 of file trigger_central.cpp.

749  {
750  int currentToothIndex = p_currentToothIndex;
751  // TODO: is this logic to compute next trigger tooth angle correct?
752  angle_t nextToothAngle = 0;
753 
754  int loopAllowance = 2 * engineCycleEventCount + 1000;
755  do {
756  // I don't love this.
757  currentToothIndex = (currentToothIndex + 1) % engineCycleEventCount;
758  nextToothAngle = getTriggerCentral()->triggerFormDetails.eventAngles[currentToothIndex] - tdcPosition();
759  wrapAngle(nextToothAngle, "nextEnginePhase", ObdCode::CUSTOM_ERR_6555);
760  } while (nextToothAngle == currentEngineDecodedPhase && --loopAllowance > 0); // '==' for float works here since both values come from 'eventAngles' array
761  if (nextToothAngle != 0 && loopAllowance == 0) {
762  // HW CI fails here, looks like we sometimes change trigger while still handling it?
763  firmwareError(ObdCode::CUSTOM_ERR_TRIGGER_ZERO, "handleShaftSignal unexpected loop end %d %d %f %f", p_currentToothIndex, engineCycleEventCount, nextToothAngle, currentEngineDecodedPhase);
764  }
765  return nextToothAngle;
766 }
TriggerFormDetails triggerFormDetails
uint32_t engineCycleEventCount
angle_t eventAngles[2 *PWM_PHASE_MAX_COUNT]
void firmwareError(ObdCode code, const char *fmt,...)
@ CUSTOM_ERR_TRIGGER_ZERO
@ CUSTOM_ERR_6555
float angle_t
Definition: rusefi_types.h:59
void wrapAngle(angle_t &angle, const char *msg, ObdCode code)

Referenced by handleShaftSignal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCurrentEnginePhase()

expected< float > TriggerCentral::getCurrentEnginePhase ( efitick_t  nowNt) const
Returns
angle since trigger synchronization point, NOT angle since TDC.

Definition at line 75 of file trigger_central.cpp.

75  {
77 
78  if (std::isnan(oneDegreeUs)) {
79  return unexpected;
80  }
81 
82  float elapsed;
83  float toothPhase;
84 
85  {
86  // under lock to avoid mismatched tooth phase and time
87  chibios_rt::CriticalSectionLocker csl;
88 
89  elapsed = m_lastToothTimer.getElapsedUs(nowNt);
90  toothPhase = m_lastToothPhaseFromSyncPoint;
91  }
92 
93  return toothPhase + elapsed / oneDegreeUs;
94 }
RpmCalculator rpmCalculator
Definition: engine.h:273
floatus_t oneDegreeUs
float m_lastToothPhaseFromSyncPoint
float floatus_t
Definition: rusefi_types.h:69

Referenced by getAcrState(), handleVvtCamSignal(), isToothExpectedNow(), onFastAdcComplete(), and rpmShaftPositionCallback().

Here is the caller graph for this function:

◆ getHwEventCounter()

int TriggerCentral::getHwEventCounter ( int  index) const

Definition at line 60 of file trigger_central.cpp.

60  {
61  return hwEventCounters[index];
62 }

Referenced by canDashboardHaltech(), sendQcBenchEventCounters(), triggerInfo(), and updateTunerStudioState().

Here is the caller graph for this function:

◆ getSecondsSinceTriggerEvent()

float TriggerCentral::getSecondsSinceTriggerEvent ( efitick_t  nowNt) const
inline

Definition at line 134 of file trigger_central.h.

134  {
135  return m_lastEventTimer.getElapsedSeconds(nowNt);
136  }

Referenced by engineMovedRecently().

Here is the caller graph for this function:

◆ getVVTPosition()

angle_t TriggerCentral::getVVTPosition ( uint8_t  bankIndex,
uint8_t  camIndex 
)

Definition at line 65 of file trigger_central.cpp.

65  {
66  if (bankIndex >= BANKS_COUNT || camIndex >= CAMS_PER_BANK) {
67  return NAN;
68  }
69  return vvtPosition[bankIndex][camIndex];
70 }

Referenced by HpfpLobe::findNextLobe(), VvtController::observePlant(), populateFrame(), readGppwmChannel(), and updateVvtSensors().

Here is the caller graph for this function:

◆ handleShaftSignal()

void TriggerCentral::handleShaftSignal ( trigger_event_e  signal,
efitick_t  timestamp 
)

This method is NOT invoked for VR falls.

If we only have a crank position sensor with four stroke, here we are extending crank revolutions with a 360 degree cycle into a four stroke, 720 degrees cycle.

Definition at line 771 of file trigger_central.cpp.

771  {
773  // trigger is broken, we cannot do anything here
774  warning(ObdCode::CUSTOM_ERR_UNEXPECTED_SHAFT_EVENT, "Shaft event while trigger is mis-configured");
775  // magic value to indicate a problem
776  hwEventCounters[0] = 155;
777  return;
778  }
779 
780  // This code gathers some statistics on signals and compares accumulated periods to filter interference
782  if (!noiseFilter.noiseFilter(timestamp, &triggerState, signal)) {
783  return;
784  }
785  if (!isUsefulSignal(signal, triggerShape)) {
786  return;
787  }
788  }
789 
790  if (!isToothExpectedNow(timestamp)) {
792  return;
793  }
794 
796 
797 #if EFI_HD_ACR
798  bool firstEventInAWhile = m_lastEventTimer.hasElapsedSec(1);
799  if (firstEventInAWhile) {
800  // let's open that valve on first sign of movement
801  engine->module<HarleyAcr>()->updateAcr();
802  }
803 #endif // EFI_HD_ACR
804 
805  if (boardAllowTriggerActions()) {
806  m_lastEventTimer.reset(timestamp);
807  }
808 
809  int eventIndex = (int) signal;
810  efiAssertVoid(ObdCode::CUSTOM_TRIGGER_EVENT_TYPE, eventIndex >= 0 && eventIndex < HW_EVENT_TYPES, "signal type");
812 
813  // Decode the trigger!
814  auto decodeResult = triggerState.decodeTriggerEvent(
815  "trigger",
816  triggerShape,
817  engine,
819  signal, timestamp);
820 
821  // Don't propagate state if we don't know where we are
822  if (decodeResult) {
824 
825  /**
826  * If we only have a crank position sensor with four stroke, here we are extending crank revolutions with a 360 degree
827  * cycle into a four stroke, 720 degrees cycle.
828  */
829  int crankDivider = getCrankDivider(triggerShape.getWheelOperationMode());
830  int crankInternalIndex = triggerState.getCrankSynchronizationCounter() % crankDivider;
831  int triggerIndexForListeners = decodeResult.Value.CurrentIndex + (crankInternalIndex * triggerShape.getSize());
832 
833  reportEventToWaveChart(signal, triggerIndexForListeners, triggerShape.useOnlyRisingEdges);
834 
835  // Look up this tooth's angle from the sync point. If this tooth is the sync point, we'll get 0 here.
836  auto currentPhaseFromSyncPoint = getTriggerCentral()->triggerFormDetails.eventAngles[triggerIndexForListeners];
837 
838  // Adjust so currentPhase is in engine-space angle, not trigger-space angle
839  currentEngineDecodedPhase = wrapAngleMethod(currentPhaseFromSyncPoint - tdcPosition(), "currentEnginePhase", ObdCode::CUSTOM_ERR_6555);
840 
841  // Record precise time and phase of the engine. This is used for VVT decode, and to check that the
842  // trigger pattern selected matches reality (ie, we check the next tooth is where we think it should be)
843  {
844  // under lock to avoid mismatched tooth phase and time
845  chibios_rt::CriticalSectionLocker csl;
846 
847  m_lastToothTimer.reset(timestamp);
848  m_lastToothPhaseFromSyncPoint = currentPhaseFromSyncPoint;
849  }
850 
851 #if TRIGGER_EXTREME_LOGGING
852  efiPrintf("trigger %d %d %d", triggerIndexForListeners, getRevolutionCounter(), time2print(getTimeNowUs()));
853 #endif /* TRIGGER_EXTREME_LOGGING */
854 
855  // Update engine RPM
856  rpmShaftPositionCallback(signal, triggerIndexForListeners, timestamp);
857 
858  // Schedule the TDC mark
859  tdcMarkCallback(triggerIndexForListeners, timestamp);
860 
861 #if !EFI_UNIT_TEST
862 #if EFI_MAP_AVERAGING
863  mapAveragingTriggerCallback(triggerIndexForListeners, timestamp);
864 #endif /* EFI_MAP_AVERAGING */
865 #endif /* EFI_UNIT_TEST */
866 
867 #if EFI_LOGIC_ANALYZER
868  waTriggerEventListener(signal, triggerIndexForListeners, timestamp);
869 #endif
870 
871  angle_t nextPhase = findNextTriggerToothAngle(triggerIndexForListeners);
872 
873  float expectNextPhase = nextPhase + tdcPosition();
874  wrapAngle(expectNextPhase, "nextEnginePhase", ObdCode::CUSTOM_ERR_6555);
875  expectedNextPhase = expectNextPhase;
876 
877 #if EFI_CDM_INTEGRATION
878  if (trgEventIndex == 0 && isBrainPinValid(engineConfiguration->cdmInputPin)) {
880  engine->knockLogic(cdmKnockValue);
881  }
882 #endif /* EFI_CDM_INTEGRATION */
883 
884  if (engine->rpmCalculator.getCachedRpm() > 0 && triggerIndexForListeners == 0) {
886  }
887 
888  // Handle ignition and injection
889  mainTriggerCallback(triggerIndexForListeners, timestamp, currentEngineDecodedPhase, nextPhase);
890 
891  // Decode the MAP based "cam" sensor
893  } else {
894  // We don't have sync, but report to the wave chart anyway as index 0.
896 
897  expectedNextPhase = unexpected;
898  }
899 }
int getCurrentCdmValue(int currentRevolution)
constexpr auto & module()
Definition: engine.h:177
TpsAccelEnrichment tpsAccelEnrichment
Definition: engine.h:283
float getCachedRpm() const
angle_t findNextTriggerToothAngle(int nextToothIndex)
bool isSpinningJustForWatchdog
expected< float > expectedNextPhase
bool isToothExpectedNow(efitick_t timestamp)
void decodeMapCam(efitick_t nowNt, float currentPhase)
PrimaryTriggerConfiguration primaryTriggerConfiguration
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 noiseFilter(efitick_t nowNt, TriggerDecoderBase *triggerState, trigger_event_e signal)
operation_mode_e getWheelOperationMode() const
efitimeus_t getTimeNowUs()
Definition: efitime.cpp:26
int time2print(int64_t time)
Definition: efitime.h:25
bool warning(ObdCode code, const char *fmt,...)
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)
@ CUSTOM_TRIGGER_EVENT_TYPE
@ CUSTOM_ERR_UNEXPECTED_SHAFT_EVENT
@ ShaftPositionListeners
bool isBrainPinValid(brain_pin_e brainPin)
void tdcMarkCallback(uint32_t trgEventIndex, efitick_t nowNt)
void rpmShaftPositionCallback(trigger_event_e ckpSignalType, uint32_t trgEventIndex, efitick_t nowNt)
Shaft position callback used by RPM calculation logic.
static void reportEventToWaveChart(trigger_event_e ckpSignalType, int triggerEventIndex, bool addOppositeEvent)
int getCrankDivider(operation_mode_e operationMode)
BOARD_WEAK bool boardAllowTriggerActions()
static TriggerWheel eventIndex[4]
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)

Referenced by handleShaftSignal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isToothExpectedNow()

bool TriggerCentral::isToothExpectedNow ( efitick_t  timestamp)
private

Definition at line 689 of file trigger_central.cpp.

689  {
690  // Check that the expected next phase (from the last tooth) is close to the actual current phase:
691  // basically, check that the tooth width is correct
692  auto estimatedCurrentPhase = getCurrentEnginePhase(timestamp);
693  auto lastToothPhase = m_lastToothPhaseFromSyncPoint;
694 
695  if (expectedNextPhase && estimatedCurrentPhase) {
696  float angleError = expectedNextPhase.Value - estimatedCurrentPhase.Value;
697 
698  // Wrap around correctly at the end of the cycle
699  float cycle = getEngineState()->engineCycle;
700  if (angleError < -cycle / 2) {
701  angleError += cycle;
702  }
703 
704  triggerToothAngleError = angleError;
705 
706  // Only perform checks if engine is spinning quickly
707  // All kinds of garbage happens while cranking
708  if (Sensor::getOrZero(SensorType::Rpm) > 1000) {
709  // Now compute how close we are to the last tooth decoded
710  float angleSinceLastTooth = estimatedCurrentPhase.Value - lastToothPhase;
711  if (angleSinceLastTooth < 0.5f) {
712  // This tooth came impossibly early, ignore it
713  // This rejects things like doubled edges, for example:
714  // |-| |----------------
715  // | | |
716  // ____________| |_|
717  // 1 2
718  // #1 will be decoded
719  // #2 will be ignored
720  // We're not sure which edge was the "real" one, but they were close enough
721  // together that it doesn't really matter.
722  warning(ObdCode::CUSTOM_PRIMARY_DOUBLED_EDGE, "doubled trigger edge after %.2f deg at #%d", angleSinceLastTooth, triggerState.currentCycle.current_index);
723 
724  return false;
725  }
726 
727  // Absolute error from last tooth
728  float absError = absF(angleError);
729  float isRpmEnough = Sensor::getOrZero(SensorType::Rpm) > 1000;
730  // TODO: configurable threshold
731  if (isRpmEnough && absError > 10 && absError < 180) {
732  // This tooth came at a very unexpected time, ignore it
734 
735  // TODO: this causes issues with some real engine logs, should it?
736  // return false;
737  }
738  }
739  } else {
741  }
742 
743  // We aren't ready to reject unexpected teeth, so accept this tooth
744  return true;
745 }
angle_t engineCycle
Definition: engine_state.h:27
expected< float > getCurrentEnginePhase(efitick_t nowNt) const
current_cycle_state_s currentCycle
EngineState * getEngineState()
Definition: engine.cpp:596
@ CUSTOM_PRIMARY_BAD_TOOTH_TIMING
@ CUSTOM_PRIMARY_DOUBLED_EDGE

Referenced by handleShaftSignal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isTriggerConfigChanged()

bool TriggerCentral::isTriggerConfigChanged ( )

Definition at line 1213 of file trigger_central.cpp.

1213  {
1215 }

◆ isTriggerDecoderError()

bool TriggerCentral::isTriggerDecoderError ( )
Returns
TRUE is something is wrong with trigger decoding

Definition at line 1245 of file trigger_central.cpp.

1245  {
1246  return triggerErrorDetection.sum(6) > 4;
1247 }
cyclic_buffer< int > triggerErrorDetection

Referenced by isTriggerErrorNow(), and triggerInfo().

Here is the caller graph for this function:

◆ prepareTriggerShape()

void TriggerCentral::prepareTriggerShape ( )
inline

Definition at line 68 of file trigger_central.h.

68  {
69 #if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
71  // Nothing to do here if there's a problem with the trigger shape
72  return;
73  }
74 
76 #endif
77  }
void prepareEventAngles(TriggerWaveform *shape)

Referenced by prepareOutputSignals().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resetCounters()

void TriggerCentral::resetCounters ( )

Definition at line 560 of file trigger_central.cpp.

560  {
561  memset(hwEventCounters, 0, sizeof(hwEventCounters));
562 }

Referenced by resetRunningTriggerCounters().

Here is the caller graph for this function:

◆ syncEnginePhaseAndReport()

angle_t TriggerCentral::syncEnginePhaseAndReport ( int  divider,
int  remainder 
)

we have two kinds of sync: this method is about detecting of exact engine phase with 720 degree precision usually based on cam wheel decoding not to be confused with a totally different trigger wheel sync which could be either crank wheel sync or cam wheel sync

Definition at line 134 of file trigger_central.cpp.

134  {
135  angle_t engineCycle = getEngineCycle(getEngineRotationState()->getOperationMode());
136 
137  angle_t totalShift = triggerState.syncEnginePhase(divider, remainder, engineCycle);
138  if (totalShift != 0) {
139  // Reset instant RPM, since the engine phase has now changed, invalidating the tooth history buffer
140  // maybe TODO: could/should we rotate the buffer around to re-align it instead? Is that worth it?
142  }
143  return totalShift;
144 }
angle_t syncEnginePhase(int divider, int remainder, angle_t engineCycle)
InstantRpmCalculator instantRpm
EngineRotationState * getEngineRotationState()
Definition: engine.cpp:592
angle_t getEngineCycle(operation_mode_e operationMode)

Referenced by adjustCrankPhase().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ updateWaveform()

void TriggerCentral::updateWaveform ( )

this is only useful while troubleshooting a new trigger shape in the field in very VERY rare circumstances

'initState' instance of TriggerDecoderBase is used only to initialize 'this' TriggerWaveform instance #192 BUG real hardware trigger events could be coming even while we are initializing trigger

Definition at line 1118 of file trigger_central.cpp.

1118  {
1119  // Re-read config in case it's changed
1121  for (int camIndex = 0;camIndex < CAMS_PER_BANK;camIndex++) {
1122  vvtTriggerConfiguration[camIndex].update();
1123  }
1124 
1126 
1127  /**
1128  * this is only useful while troubleshooting a new trigger shape in the field
1129  * in very VERY rare circumstances
1130  */
1132  int gapIndex = 0;
1133 
1135 
1136  // copy however many the user wants
1137  for (; gapIndex < engineConfiguration->gapTrackingLengthOverride; gapIndex++) {
1138  float gapOverrideFrom = engineConfiguration->triggerGapOverrideFrom[gapIndex];
1139  float gapOverrideTo = engineConfiguration->triggerGapOverrideTo[gapIndex];
1140  triggerShape.setTriggerSynchronizationGap3(/*gapIndex*/gapIndex, gapOverrideFrom, gapOverrideTo);
1141  }
1142 
1143  // fill the remainder with the default gaps
1144  for (; gapIndex < GAP_TRACKING_LENGTH; gapIndex++) {
1145  triggerShape.synchronizationRatioFrom[gapIndex] = NAN;
1146  triggerShape.synchronizationRatioTo[gapIndex] = NAN;
1147  }
1148  }
1149 
1151  int length = triggerShape.getLength();
1152  engineCycleEventCount = length;
1153 
1154  efiAssertVoid(ObdCode::CUSTOM_SHAPE_LEN_ZERO, length > 0, "shapeLength=0");
1155 
1156  triggerErrorDetection.clear();
1157 
1158  /**
1159  * 'initState' instance of TriggerDecoderBase is used only to initialize 'this' TriggerWaveform instance
1160  * #192 BUG real hardware trigger events could be coming even while we are initializing trigger
1161  */
1163  triggerShape,
1164  initState);
1165  }
1166 
1168  int gapIndex = 0;
1169 
1170  TriggerWaveform *shape = &vvtShape[0];
1172 
1173  for (; gapIndex < engineConfiguration->gapVvtTrackingLengthOverride; gapIndex++) {
1174  float gapOverrideFrom = engineConfiguration->triggerVVTGapOverrideFrom[gapIndex];
1175  float gapOverrideTo = engineConfiguration->triggerVVTGapOverrideTo[gapIndex];
1176  shape->synchronizationRatioFrom[gapIndex] = gapOverrideFrom;
1177  shape->synchronizationRatioTo[gapIndex] = gapOverrideTo;
1178  }
1179  // fill the remainder with the default gaps
1180  for (; gapIndex < VVT_TRACKING_LENGTH; gapIndex++) {
1181  shape->synchronizationRatioFrom[gapIndex] = NAN;
1182  shape->synchronizationRatioTo[gapIndex] = NAN;
1183  }
1184  }
1185 
1186  for (int camIndex = 0; camIndex < CAMS_PER_BANK; camIndex++) {
1187  // todo: should 'vvtWithRealDecoder' be used here?
1188  if (engineConfiguration->vvtMode[camIndex] != VVT_INACTIVE) {
1189  initVvtShape(
1190  vvtShape[camIndex],
1191  vvtTriggerConfiguration[camIndex],
1192  initState
1193  );
1194  }
1195  }
1196 
1197  // This is not the right place for this, but further refactoring has to happen before it can get moved.
1199 
1200 }
TriggerCentral triggerCentral
Definition: engine.h:286
void setNeedsDisambiguation(bool needsDisambiguation)
TriggerWaveform vvtShape[CAMS_PER_BANK]
VvtTriggerConfiguration vvtTriggerConfiguration[CAMS_PER_BANK]
trigger_config_s TriggerType
Trigger shape has all the fields needed to describe and decode trigger signal.
bool needsDisambiguation() const
float synchronizationRatioFrom[GAP_TRACKING_LENGTH]
void initializeTriggerWaveform(operation_mode_e triggerOperationMode, const trigger_config_s &triggerType)
size_t getLength() const
float synchronizationRatioTo[GAP_TRACKING_LENGTH]
void setTriggerSynchronizationGap3(int index, float syncRatioFrom, float syncRatioTo)
@ CUSTOM_SHAPE_LEN_ZERO
operation_mode_e lookupOperationMode()
TriggerDecoderBase initState("init")
static void initVvtShape(TriggerWaveform &shape, const TriggerConfiguration &p_config, TriggerDecoderBase &initState)
static void calculateTriggerSynchPoint(const PrimaryTriggerConfiguration &primaryTriggerConfiguration, TriggerWaveform &shape, TriggerDecoderBase &initState)

Referenced by Engine::updateTriggerWaveform().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validateCamVvtCounters()

void TriggerCentral::validateCamVvtCounters ( )

Definition at line 1080 of file trigger_central.cpp.

1080  {
1081  // micro-optimized 'crankSynchronizationCounter % 256'
1082  int camVvtValidationIndex = triggerState.getCrankSynchronizationCounter() & 0xFF;
1083  if (camVvtValidationIndex == 0) {
1084  vvtCamCounter = 0;
1085  } else if (camVvtValidationIndex == 0xFE && vvtCamCounter < 60) {
1086  // magic logic: we expect at least 60 CAM/VVT events for each 256 trigger cycles, otherwise throw a code
1087  warning(ObdCode::OBD_Camshaft_Position_Sensor_Circuit_Range_Performance, "No Camshaft Position Sensor signals");
1088  }
1089 }
@ OBD_Camshaft_Position_Sensor_Circuit_Range_Performance

Referenced by rpmShaftPositionCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

Field Documentation

◆ currentVVTEventPosition

angle_t TriggerCentral::currentVVTEventPosition[BANKS_COUNT][CAMS_PER_BANK]

Definition at line 169 of file trigger_central.h.

Referenced by handleVvtCamSignal().

◆ directSelfStimulation

bool TriggerCentral::directSelfStimulation = false

◆ engineCycleEventCount

uint32_t TriggerCentral::engineCycleEventCount = 0

value of 'triggerShape.getLength()' pre-calculating this value is a performance optimization

Definition at line 118 of file trigger_central.h.

Referenced by findNextTriggerToothAngle(), and updateWaveform().

◆ expectedNextPhase

expected<float> TriggerCentral::expectedNextPhase = unexpected
private

Definition at line 222 of file trigger_central.h.

Referenced by handleShaftSignal(), and isToothExpectedNow().

◆ hwTriggerInputEnabled

bool TriggerCentral::hwTriggerInputEnabled = true

◆ instantRpm

InstantRpmCalculator TriggerCentral::instantRpm

◆ isEngineSnifferEnabled

bool TriggerCentral::isEngineSnifferEnabled = false

this is based on engineSnifferRpmThreshold settings and current RPM

Definition at line 208 of file trigger_central.h.

Referenced by TriggerDecoderBase::decodeTriggerEvent(), and Engine::updateSlowSensors().

◆ isSpinningJustForWatchdog

bool TriggerCentral::isSpinningJustForWatchdog = false

By the way: 'cranking' means engine is not stopped and the rpm are below crankingRpm 'running' means RPM are above crankingRpm 'spinning' means the engine is not stopped this is set to true each time we register a trigger tooth signal

Definition at line 109 of file trigger_central.h.

Referenced by Engine::efiWatchdog(), and handleShaftSignal().

◆ m_lastEventTimer

Timer TriggerCentral::m_lastEventTimer

◆ m_lastToothPhaseFromSyncPoint

float TriggerCentral::m_lastToothPhaseFromSyncPoint
private

Definition at line 218 of file trigger_central.h.

Referenced by getCurrentEnginePhase(), handleShaftSignal(), and isToothExpectedNow().

◆ m_lastToothTimer

Timer TriggerCentral::m_lastToothTimer
private

Definition at line 216 of file trigger_central.h.

Referenced by getCurrentEnginePhase(), and handleShaftSignal().

◆ mapCamPrevCycleValue

float TriggerCentral::mapCamPrevCycleValue = 0

Definition at line 111 of file trigger_central.h.

Referenced by decodeMapCam().

◆ noiseFilter

TriggerNoiseFilter TriggerCentral::noiseFilter

◆ prevChangeAtCycle

int TriggerCentral::prevChangeAtCycle = 0

Definition at line 112 of file trigger_central.h.

Referenced by decodeMapCam().

◆ primaryTriggerConfiguration

PrimaryTriggerConfiguration TriggerCentral::primaryTriggerConfiguration

◆ triggerConfigChangedOnLastConfigurationChange

bool TriggerCentral::triggerConfigChangedOnLastConfigurationChange = false

true if a recent configuration change has changed any of the trigger settings which we have not adjusted for yet

Definition at line 123 of file trigger_central.h.

Referenced by checkIfTriggerConfigChanged(), isTriggerConfigChanged(), and onConfigurationChangeTriggerCallback().

◆ triggerErrorDetection

cyclic_buffer<int> TriggerCentral::triggerErrorDetection

◆ triggerFormDetails

TriggerFormDetails TriggerCentral::triggerFormDetails

◆ triggerShape

TriggerWaveform TriggerCentral::triggerShape

◆ triggerState

PrimaryTriggerDecoder TriggerCentral::triggerState

◆ triggerVersion

LocalVersionHolder TriggerCentral::triggerVersion

Definition at line 97 of file trigger_central.h.

Referenced by checkIfTriggerConfigChanged().

◆ vvtEventFallCounter

int TriggerCentral::vvtEventFallCounter[CAM_INPUTS_COUNT]

◆ vvtEventRiseCounter

int TriggerCentral::vvtEventRiseCounter[CAM_INPUTS_COUNT]

◆ vvtPosition

angle_t TriggerCentral::vvtPosition[BANKS_COUNT][CAMS_PER_BANK]

Definition at line 173 of file trigger_central.h.

Referenced by getVVTPosition(), and handleVvtCamSignal().

◆ vvtShape

TriggerWaveform TriggerCentral::vvtShape[CAMS_PER_BANK]

◆ vvtState

VvtTriggerDecoder TriggerCentral::vvtState[BANKS_COUNT][CAMS_PER_BANK]
Initial value:
= {
{
"VVT B1 Int",
#if CAMS_PER_BANK >= 2
"VVT B1 Exh"
#endif
},
#if BANKS_COUNT >= 2
{
"VVT B2 Int",
#if CAMS_PER_BANK >= 2
"VVT B1 Exh"
#endif
}
#endif
}

Definition at line 181 of file trigger_central.h.

Referenced by handleVvtCamSignal(), and Engine::OnTriggerSynchronizationLost().

◆ vvtTriggerConfiguration

VvtTriggerConfiguration TriggerCentral::vvtTriggerConfiguration = {{"VVT1 ", 0}}

The documentation for this class was generated from the following files: