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 syncAndReport (int divider, int remainder)
 
void handleShaftSignal (trigger_event_e signal, efitick_t timestamp)
 
int getHwEventCounter (int index) const
 
void resetCounters ()
 
void validateCamVvtCounters ()
 
void updateWaveform ()
 
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 {}
 

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 1194 of file trigger_central.cpp.

1194  {
1195  // we want to make sure that configuration has changed AND that change has changed trigger specifically
1197  triggerConfigChangedOnLastConfigurationChange = false; // whoever has called the method is supposed to react to changes
1198  return result;
1199 }
int getGlobalConfigurationVersion(void) const
Definition: engine.cpp:300
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 644 of file trigger_central.cpp.

644  {
645  isDecodingMapCam = engineConfiguration->vvtMode[0] == VVT_MAP_V_TWIN &&
647  if (isDecodingMapCam) {
648  // 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.
649  auto toothAngle360 = currentPhase;
650  while (toothAngle360 >= 360) {
651  toothAngle360 -= 360;
652  }
653 
654  if (mapCamPrevToothAngle < engineConfiguration->mapCamDetectionAnglePosition && toothAngle360 > engineConfiguration->mapCamDetectionAnglePosition) {
655  // we are somewhere close to 'mapCamDetectionAnglePosition'
656 
657  // warning: hack hack hack
659 
660  // Compute diff against the last time we were here
661  float diff = map - mapCamPrevCycleValue;
662  mapCamPrevCycleValue = map;
663 
664  if (diff > 0) {
665  mapVvt_map_peak++;
667  mapVvt_MAP_AT_CYCLE_COUNT = revolutionCounter - prevChangeAtCycle;
668  prevChangeAtCycle = revolutionCounter;
669 
670  hwHandleVvtCamSignal(TriggerValue::RISE, timestamp, /*index*/0);
671  hwHandleVvtCamSignal(TriggerValue::FALL, timestamp, /*index*/0);
672 #if EFI_UNIT_TEST
673  // hack? feature? existing unit test relies on VVT phase available right away
674  // but current implementation which is based on periodicFastCallback would only make result available on NEXT tooth
676 #endif // EFI_UNIT_TEST
677  }
678 
680  mapVvt_MAP_AT_DIFF = diff;
681  }
682 
683  mapCamPrevToothAngle = toothAngle360;
684  }
685 }
TunerStudioOutputChannels outputChannels
Definition: engine.h:96
void onFastCallback() override
static float getOrZero(SensorType type)
Definition: sensor.h:92
float mapCamPrevCycleValue
int getCrankSynchronizationCounter() const
LimpManager * getLimpManager()
Definition: engine.cpp:595
TriggerCentral * getTriggerCentral()
Definition: engine.cpp:589
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 144 of file trigger_central.h.

144  {
146  }
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 131 of file trigger_central.h.

131  {
132  constexpr float oneRevolutionLimitInSeconds = 60.0 / RPM_LOW_THRESHOLD;
133  auto maxAverageToothTime = oneRevolutionLimitInSeconds / triggerShape.getSize();
134 
135  // Some triggers may have long gaps (with many teeth), don't count that as stopped!
136  auto maxAllowedGap = maxAverageToothTime * 10;
137 
138  // Clamp between 0.1 seconds ("instant" for a human) and worst case of one engine cycle on low tooth count wheel
139  maxAllowedGap = clampF(0.1f, maxAllowedGap, oneRevolutionLimitInSeconds);
140 
141  return getSecondsSinceTriggerEvent(nowNt) < maxAllowedGap;
142  }
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:

◆ 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 (cisnan(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:262
floatus_t oneDegreeUs
float m_lastToothPhaseFromSyncPoint
float floatus_t
Definition: rusefi_types.h:71

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 127 of file trigger_central.h.

127  {
128  return m_lastEventTimer.getElapsedSeconds(nowNt);
129  }

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 750 of file trigger_central.cpp.

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

◆ isToothExpectedNow()

bool TriggerCentral::isToothExpectedNow ( efitick_t  timestamp)
private

Definition at line 687 of file trigger_central.cpp.

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

1202  {
1204 }

◆ isTriggerDecoderError()

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

Definition at line 1234 of file trigger_central.cpp.

1234  {
1235  return triggerErrorDetection.sum(6) > 4;
1236 }
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 61 of file trigger_central.h.

61  {
62 #if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
64  // Nothing to do here if there's a problem with the trigger shape
65  return;
66  }
67 
69 #endif
70  }
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 558 of file trigger_central.cpp.

558  {
559  memset(hwEventCounters, 0, sizeof(hwEventCounters));
560 }

Referenced by resetRunningTriggerCounters().

Here is the caller graph for this function:

◆ syncAndReport()

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

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:572
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 1108 of file trigger_central.cpp.

1108  {
1109  // Re-read config in case it's changed
1111  for (int camIndex = 0;camIndex < CAMS_PER_BANK;camIndex++) {
1112  vvtTriggerConfiguration[camIndex].update();
1113  }
1114 
1116 
1117  /**
1118  * this is only useful while troubleshooting a new trigger shape in the field
1119  * in very VERY rare circumstances
1120  */
1122  int gapIndex = 0;
1123 
1125 
1126  // copy however many the user wants
1127  for (; gapIndex < engineConfiguration->gapTrackingLengthOverride; gapIndex++) {
1128  float gapOverrideFrom = engineConfiguration->triggerGapOverrideFrom[gapIndex];
1129  float gapOverrideTo = engineConfiguration->triggerGapOverrideTo[gapIndex];
1130  TRIGGER_WAVEFORM(setTriggerSynchronizationGap3(/*gapIndex*/gapIndex, gapOverrideFrom, gapOverrideTo));
1131  }
1132 
1133  // fill the remainder with the default gaps
1134  for (; gapIndex < GAP_TRACKING_LENGTH; gapIndex++) {
1135  triggerShape.synchronizationRatioFrom[gapIndex] = NAN;
1136  triggerShape.synchronizationRatioTo[gapIndex] = NAN;
1137  }
1138  }
1139 
1141  int length = triggerShape.getLength();
1142  engineCycleEventCount = length;
1143 
1144  efiAssertVoid(ObdCode::CUSTOM_SHAPE_LEN_ZERO, length > 0, "shapeLength=0");
1145 
1146  triggerErrorDetection.clear();
1147 
1148  /**
1149  * 'initState' instance of TriggerDecoderBase is used only to initialize 'this' TriggerWaveform instance
1150  * #192 BUG real hardware trigger events could be coming even while we are initializing trigger
1151  */
1153  triggerShape,
1154  initState);
1155  }
1156 
1158  int gapIndex = 0;
1159 
1160  TriggerWaveform *shape = &vvtShape[0];
1161 
1162  for (; gapIndex < engineConfiguration->gapVvtTrackingLengthOverride; gapIndex++) {
1163  float gapOverrideFrom = engineConfiguration->triggerVVTGapOverrideFrom[gapIndex];
1164  float gapOverrideTo = engineConfiguration->triggerVVTGapOverrideTo[gapIndex];
1165  shape->synchronizationRatioFrom[gapIndex] = gapOverrideFrom;
1166  shape->synchronizationRatioTo[gapIndex] = gapOverrideTo;
1167  }
1168  // fill the remainder with the default gaps
1169  for (; gapIndex < VVT_TRACKING_LENGTH; gapIndex++) {
1170  shape->synchronizationRatioFrom[gapIndex] = NAN;
1171  shape->synchronizationRatioTo[gapIndex] = NAN;
1172  }
1173  }
1174 
1175  for (int camIndex = 0; camIndex < CAMS_PER_BANK; camIndex++) {
1176  // todo: should 'vvtWithRealDecoder' be used here?
1177  if (engineConfiguration->vvtMode[camIndex] != VVT_INACTIVE) {
1178  initVvtShape(
1179  vvtShape[camIndex],
1180  vvtTriggerConfiguration[camIndex],
1181  initState
1182  );
1183  }
1184  }
1185 
1186  // This is not the right place for this, but further refactoring has to happen before it can get moved.
1188 
1189 }
TriggerCentral triggerCentral
Definition: engine.h:275
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]
@ 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 1070 of file trigger_central.cpp.

1070  {
1071  // micro-optimized 'crankSynchronizationCounter % 256'
1072  int camVvtValidationIndex = triggerState.getCrankSynchronizationCounter() & 0xFF;
1073  if (camVvtValidationIndex == 0) {
1074  vvtCamCounter = 0;
1075  } else if (camVvtValidationIndex == 0xFE && vvtCamCounter < 60) {
1076  // magic logic: we expect at least 60 CAM/VVT events for each 256 trigger cycles, otherwise throw a code
1077  warning(ObdCode::OBD_Camshaft_Position_Sensor_Circuit_Range_Performance, "No Camshaft Position Sensor signals");
1078  }
1079 }
@ 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 157 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 111 of file trigger_central.h.

Referenced by handleShaftSignal(), and updateWaveform().

◆ expectedNextPhase

expected<float> TriggerCentral::expectedNextPhase = unexpected
private

Definition at line 210 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 196 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 102 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 206 of file trigger_central.h.

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

◆ m_lastToothTimer

Timer TriggerCentral::m_lastToothTimer
private

Definition at line 204 of file trigger_central.h.

Referenced by getCurrentEnginePhase(), and handleShaftSignal().

◆ mapCamPrevCycleValue

float TriggerCentral::mapCamPrevCycleValue = 0

Definition at line 104 of file trigger_central.h.

Referenced by decodeMapCam().

◆ noiseFilter

TriggerNoiseFilter TriggerCentral::noiseFilter

◆ prevChangeAtCycle

int TriggerCentral::prevChangeAtCycle = 0

Definition at line 105 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 116 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 90 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 161 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 169 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: