rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
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 applyShapesConfiguration ()
 
angle_t findNextTriggerToothAngle (int nextToothIndex)
 
void prepareTriggerShape ()
 
bool checkIfTriggerConfigChanged ()
 
bool isTriggerConfigChanged ()
 
bool isTriggerDecoderError ()
 
expected< floatgetCurrentEnginePhase (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)
 
void applyCamGapOverride ()
 
bool isMapCamSync (efitick_t nowNt, float currentPhase)
 

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
 
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
uint16_t hwEventCounters [HW_EVENT_TYPES] = {}
 
uint16_t vvtEventRiseCounter [CAM_INPUTS_COUNT] = {}
 
uint16_t vvtEventFallCounter [CAM_INPUTS_COUNT] = {}
 
uint16_t vvtCamCounter = (uint16_t)0
 
uint8_t alignmentFill_at_26 [2] = {}
 
float mapVvt_MAP_AT_SPECIAL_POINT = (float)0
 
float mapVvt_MAP_AT_DIFF = (float)0
 
int8_t mapVvt_MAP_AT_CYCLE_COUNT = (int8_t)0
 
uint8_t mapVvt_sync_counter = (uint8_t)0
 
uint8_t mapVvt_min_point_counter = (uint8_t)0
 
uint8_t alignmentFill_at_39 [1] = {}
 
uint32_t temp_mapVvt_index = (uint32_t)0
 
float mapVvt_CycleDelta = (float)0
 
float currentEngineDecodedPhase = (float)0
 
float triggerToothAngleError = (float)0
 
uint8_t triggerIgnoredToothCount = (uint8_t)0
 
uint8_t alignmentFill_at_57 [3] = {}
 
angle_t mapCamPrevToothAngle = (angle_t)0
 
bool isDecodingMapCam: 1 {}
 
bool unusedBit_19_1: 1 {}
 
bool unusedBit_19_2: 1 {}
 
bool unusedBit_19_3: 1 {}
 
bool unusedBit_19_4: 1 {}
 
bool unusedBit_19_5: 1 {}
 
bool unusedBit_19_6: 1 {}
 
bool unusedBit_19_7: 1 {}
 
bool unusedBit_19_8: 1 {}
 
bool unusedBit_19_9: 1 {}
 
bool unusedBit_19_10: 1 {}
 
bool unusedBit_19_11: 1 {}
 
bool unusedBit_19_12: 1 {}
 
bool unusedBit_19_13: 1 {}
 
bool unusedBit_19_14: 1 {}
 
bool unusedBit_19_15: 1 {}
 
bool unusedBit_19_16: 1 {}
 
bool unusedBit_19_17: 1 {}
 
bool unusedBit_19_18: 1 {}
 
bool unusedBit_19_19: 1 {}
 
bool unusedBit_19_20: 1 {}
 
bool unusedBit_19_21: 1 {}
 
bool unusedBit_19_22: 1 {}
 
bool unusedBit_19_23: 1 {}
 
bool unusedBit_19_24: 1 {}
 
bool unusedBit_19_25: 1 {}
 
bool unusedBit_19_26: 1 {}
 
bool unusedBit_19_27: 1 {}
 
bool unusedBit_19_28: 1 {}
 
bool unusedBit_19_29: 1 {}
 
bool unusedBit_19_30: 1 {}
 
bool unusedBit_19_31: 1 {}
 
uint32_t triggerElapsedUs = (uint32_t)0
 

Private Member Functions

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

Private Attributes

Timer m_lastToothTimer
 
float m_lastToothPhaseFromSyncPoint
 
expected< floatexpectedNextPhase = 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 39 of file trigger_central.cpp.

39 :
41 triggerState("TRG")
42{
46}
PrimaryTriggerDecoder triggerState
angle_t vvtPosition[BANKS_COUNT][CAMS_PER_BANK]
TriggerNoiseFilter noiseFilter
uint16_t hwEventCounters[HW_EVENT_TYPES]
void setArrayValues(TValue(&array)[TSize], float value)
Here is the call graph for this function:

Member Function Documentation

◆ applyCamGapOverride()

void TriggerCentral::applyCamGapOverride ( )

Definition at line 1182 of file trigger_central.cpp.

1182 {
1184 int gapIndex = 0;
1185
1186 TriggerWaveform *shape = &vvtShape[0];
1188
1189 for (; gapIndex < engineConfiguration->gapVvtTrackingLengthOverride; gapIndex++) {
1190 float gapOverrideFrom = engineConfiguration->triggerVVTGapOverrideFrom[gapIndex];
1191 float gapOverrideTo = engineConfiguration->triggerVVTGapOverrideTo[gapIndex];
1192 shape->synchronizationRatioFrom[gapIndex] = gapOverrideFrom;
1193 shape->synchronizationRatioTo[gapIndex] = gapOverrideTo;
1194 }
1195 // fill the remainder with the default gaps
1196 for (; gapIndex < VVT_TRACKING_LENGTH; gapIndex++) {
1197 shape->synchronizationRatioFrom[gapIndex] = NAN;
1198 shape->synchronizationRatioTo[gapIndex] = NAN;
1199 }
1200 }
1201}
TriggerWaveform vvtShape[CAMS_PER_BANK]
Trigger shape has all the fields needed to describe and decode trigger signal.
float synchronizationRatioFrom[GAP_TRACKING_LENGTH]
float synchronizationRatioTo[GAP_TRACKING_LENGTH]
static constexpr engine_configuration_s * engineConfiguration

Referenced by applyShapesConfiguration(), and initVvtShape().

Here is the caller graph for this function:

◆ applyShapesConfiguration()

void TriggerCentral::applyShapesConfiguration ( )

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

1203 {
1204 // Re-read config in case it's changed
1206 for (int camIndex = 0;camIndex < CAMS_PER_BANK;camIndex++) {
1207 vvtTriggerConfiguration[camIndex].update();
1208 }
1209
1211
1213
1215 int length = triggerShape.getLength();
1216 engineCycleEventCount = length;
1217
1218 efiAssertVoid(ObdCode::CUSTOM_SHAPE_LEN_ZERO, length > 0, "shapeLength=0");
1219
1220 triggerErrorDetection.clear();
1221
1222 /**
1223 * 'initState' instance of TriggerDecoderBase is used only to initialize 'this' TriggerWaveform instance
1224 * #192 BUG real hardware trigger events could be coming even while we are initializing trigger
1225 */
1228 initState);
1229 }
1230
1232
1233 for (int camIndex = 0; camIndex < CAMS_PER_BANK; camIndex++) {
1234 // todo: should 'vvtWithRealDecoder' be used here?
1235 if (engineConfiguration->vvtMode[camIndex] != VVT_INACTIVE) {
1237 camIndex,
1238 vvtShape[camIndex],
1239 vvtTriggerConfiguration[camIndex],
1240 initState
1241 );
1242 }
1243 }
1244
1245 // This is not the right place for this, but further refactoring has to happen before it can get moved.
1247
1248}
TriggerCentral triggerCentral
Definition engine.h:318
void setNeedsDisambiguation(bool needsDisambiguation)
TriggerWaveform triggerShape
cyclic_buffer< int > triggerErrorDetection
VvtTriggerConfiguration vvtTriggerConfiguration[CAMS_PER_BANK]
PrimaryTriggerConfiguration primaryTriggerConfiguration
uint32_t engineCycleEventCount
trigger_config_s TriggerType
bool needsDisambiguation() const
void initializeTriggerWaveform(operation_mode_e triggerOperationMode, const trigger_config_s &triggerType, bool isCrankWheel=true)
size_t getLength() const
static EngineAccessor engine
Definition engine.h:413
@ CUSTOM_SHAPE_LEN_ZERO
operation_mode_e lookupOperationMode()
TriggerDecoderBase initState("init")
static void initVvtShape(int camIndex, TriggerWaveform &shape, const TriggerConfiguration &p_config, TriggerDecoderBase &initState)
static void calculateTriggerSynchPoint(const PrimaryTriggerConfiguration &primaryTriggerConfiguration, TriggerWaveform &shape, TriggerDecoderBase &initState)

Referenced by Engine::updateTriggerConfiguration().

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

◆ applyTriggerGapOverride()

void TriggerCentral::applyTriggerGapOverride ( )
private

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

Definition at line 1157 of file trigger_central.cpp.

1157 {
1158 /**
1159 * this is only useful while troubleshooting a new trigger shape in the field
1160 * in very VERY rare circumstances
1161 */
1163 int gapIndex = 0;
1164
1166
1167 // copy however many the user wants
1168 for (; gapIndex < engineConfiguration->gapTrackingLengthOverride; gapIndex++) {
1169 float gapOverrideFrom = engineConfiguration->triggerGapOverrideFrom[gapIndex];
1170 float gapOverrideTo = engineConfiguration->triggerGapOverrideTo[gapIndex];
1171 triggerShape.setTriggerSynchronizationGap3(/*gapIndex*/gapIndex, gapOverrideFrom, gapOverrideTo);
1172 }
1173
1174 // fill the remainder with the default gaps
1175 for (; gapIndex < GAP_TRACKING_LENGTH; gapIndex++) {
1176 triggerShape.synchronizationRatioFrom[gapIndex] = NAN;
1177 triggerShape.synchronizationRatioTo[gapIndex] = NAN;
1178 }
1179 }
1180}
void setTriggerSynchronizationGap3(int index, float syncRatioFrom, float syncRatioTo)

Referenced by applyShapesConfiguration().

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

◆ checkIfTriggerConfigChanged()

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

Definition at line 1253 of file trigger_central.cpp.

1253 {
1254 // we want to make sure that configuration has changed AND that change has changed trigger specifically
1256 triggerConfigChangedOnLastConfigurationChange = false; // whoever has called the method is supposed to react to changes
1257 return result;
1258}
int getGlobalConfigurationVersion() const
Definition engine.cpp:289
bool isOld(int globalVersion)
LocalVersionHolder triggerVersion
bool triggerConfigChangedOnLastConfigurationChange
Here is the call graph for this function:

◆ decodeMapCam()

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

Definition at line 694 of file trigger_central.cpp.

694 {
695 UNUSED(toothIndexForListeners);
696
697 isDecodingMapCam = engineConfiguration->vvtMode[0] == VVT_MAP_V_TWIN &&
699 if (isDecodingMapCam) {
700
701
702#ifdef TEMP_V_TWIN
703 mapAtAngle[toothIndexForListeners] = engine->outputChannels.instantMAPValue;
704
705 if (toothIndexForListeners > 2) {
706 if (mapAtAngle[toothIndexForListeners - 2] > mapAtAngle[toothIndexForListeners - 1] &&
707 mapAtAngle[toothIndexForListeners - 1] < mapAtAngle[toothIndexForListeners - 0]) {
709 }
710
711 }
712#endif
713
714
715 if (isMapCamSync(timestamp, currentPhase)) {
716 hwHandleVvtCamSignal(TriggerValue::RISE, timestamp, /*index*/0);
717 hwHandleVvtCamSignal(TriggerValue::FALL, timestamp, /*index*/0);
718#if EFI_UNIT_TEST
719 // hack? feature? existing unit test relies on VVT phase available right away
720 // but current implementation which is based on periodicFastCallback would only make result available on NEXT tooth
722#endif // EFI_UNIT_TEST
723 }
724 }
725}
TunerStudioOutputChannels outputChannels
Definition engine.h:109
void onFastCallback() override
static float getOrZero(SensorType type)
Definition sensor.h:83
bool isMapCamSync(efitick_t nowNt, float currentPhase)
LimpManager * getLimpManager()
Definition engine.cpp:596
UNUSED(samplingTimeSeconds)
scaled_channel< uint16_t, 30, 1 > instantMAPValue
float mapAtAngle[200]
void hwHandleVvtCamSignal(TriggerValue front, 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

Referenced by engineMovedRecently().

Here is the call graph for this function:
Here is the caller 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) || directSelfStimulation;
154 }
float getSecondsSinceTriggerEvent(efitick_t nowNt) const
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 787 of file trigger_central.cpp.

787 {
788 int currentToothIndex = p_currentToothIndex;
789 // TODO: is this logic to compute next trigger tooth angle correct?
790 angle_t nextToothAngle = 0;
791
792 int loopAllowance = 2 * engineCycleEventCount + 1000;
793 do {
794 // I don't love this.
795 currentToothIndex = (currentToothIndex + 1) % engineCycleEventCount;
796 nextToothAngle = getTriggerCentral()->triggerFormDetails.eventAngles[currentToothIndex] - tdcPosition();
797 wrapAngle(nextToothAngle, "nextEnginePhase", ObdCode::CUSTOM_ERR_6555);
798 } while (nextToothAngle == currentEngineDecodedPhase && --loopAllowance > 0); // '==' for float works here since both values come from 'eventAngles' array
799 if (nextToothAngle != 0 && loopAllowance == 0) {
800 // HW CI fails here, looks like we sometimes change trigger while still handling it?
801 firmwareError(ObdCode::CUSTOM_ERR_TRIGGER_ZERO, "handleShaftSignal unexpected loop end %d %d %f %f", p_currentToothIndex, engineCycleEventCount, nextToothAngle, currentEngineDecodedPhase);
802 }
803 return nextToothAngle;
804}
TriggerFormDetails triggerFormDetails
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
TriggerCentral * getTriggerCentral()
Definition engine.cpp:590
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 68 of file trigger_central.cpp.

68 {
70
71 if (std::isnan(oneDegreeUs)) {
72 return unexpected;
73 }
74
75 float elapsed;
76 float toothPhase;
77
78 {
79 // under lock to avoid mismatched tooth phase and time
80 chibios_rt::CriticalSectionLocker csl;
81
82 elapsed = m_lastToothTimer.getElapsedUs(nowNt);
84 }
85
86 return toothPhase + elapsed / oneDegreeUs;
87}
RpmCalculator rpmCalculator
Definition engine.h:306
floatus_t oneDegreeUs
float m_lastToothPhaseFromSyncPoint

Referenced by getAcrState(), handleVvtCamSignal(), isToothExpectedNow(), HpfpController::pinTurnOff(), and HpfpController::pinTurnOn().

Here is the caller graph for this function:

◆ getHwEventCounter()

int TriggerCentral::getHwEventCounter ( int  index) const

Definition at line 54 of file trigger_central.cpp.

54 {
55 return hwEventCounters[index];
56}

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

58 {
59 if (bankIndex >= BANKS_COUNT || camIndex >= CAMS_PER_BANK) {
60 return NAN;
61 }
62 return vvtPosition[bankIndex][camIndex];
63}

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

809 {
811 // trigger is broken, we cannot do anything here
812 warning(ObdCode::CUSTOM_ERR_UNEXPECTED_SHAFT_EVENT, "Shaft event while trigger is mis-configured");
813 return;
814 }
815
816 // This code gathers some statistics on signals and compares accumulated periods to filter interference
818 if (!noiseFilter.noiseFilter(timestamp, &triggerState, signal)) {
819 return;
820 }
821 if (!isUsefulSignal(signal, triggerShape)) {
822 return;
823 }
824 }
825
826 if (!isToothExpectedNow(timestamp)) {
828 return;
829 }
830
832
833#if EFI_HD_ACR
834 bool firstEventInAWhile = m_lastEventTimer.hasElapsedSec(1);
835 if (firstEventInAWhile) {
836 // let's open that valve on first sign of movement
837 engine->module<HarleyAcr>()->updateAcr();
838 }
839#endif // EFI_HD_ACR
840
842 m_lastEventTimer.reset(timestamp);
843 }
844
845 int eventIndex = (int) signal;
846 efiAssertVoid(ObdCode::CUSTOM_TRIGGER_EVENT_TYPE, eventIndex >= 0 && eventIndex < HW_EVENT_TYPES, "signal type");
848
849 // Decode the trigger!
850 auto decodeResult = triggerState.decodeTriggerEvent(
851 "trigger",
853 engine,
855 signal, timestamp);
856
857 // Don't propagate state if we don't know where we are
858 if (decodeResult) {
860
861 /**
862 * If we only have a crank position sensor with four stroke, here we are extending crank revolutions with a 360 degree
863 * cycle into a four stroke, 720 degrees cycle.
864 */
866 int crankInternalIndex = triggerState.getSynchronizationCounter() % crankDivider;
867 int triggerIndexForListeners = decodeResult.Value.CurrentIndex + (crankInternalIndex * triggerShape.getSize());
868
869 reportEventToWaveChart(signal, triggerIndexForListeners, triggerShape.useOnlyRisingEdges);
870
871 // Look up this tooth's angle from the sync point. If this tooth is the sync point, we'll get 0 here.
872 auto currentPhaseFromSyncPoint = getTriggerCentral()->triggerFormDetails.eventAngles[triggerIndexForListeners];
873
874 // Adjust so currentPhase is in engine-space angle, not trigger-space angle
875 currentEngineDecodedPhase = wrapAngleMethod(currentPhaseFromSyncPoint - tdcPosition(), "currentEnginePhase", ObdCode::CUSTOM_ERR_6555);
876
877 // Record precise time and phase of the engine. This is used for VVT decode, and to check that the
878 // trigger pattern selected matches reality (ie, we check the next tooth is where we think it should be)
879 {
880 // under lock to avoid mismatched tooth phase and time
881 chibios_rt::CriticalSectionLocker csl;
882
883 m_lastToothTimer.reset(timestamp);
884 m_lastToothPhaseFromSyncPoint = currentPhaseFromSyncPoint;
885 }
886
887#if TRIGGER_EXTREME_LOGGING
888 efiPrintf("trigger %d %d %d", triggerIndexForListeners, getRevolutionCounter(), time2print(getTimeNowUs()));
889#endif /* TRIGGER_EXTREME_LOGGING */
890
891 // Update engine RPM
892 rpmShaftPositionCallback(signal, triggerIndexForListeners, timestamp);
893
894 // Schedule the TDC mark
895 tdcMarkCallback(triggerIndexForListeners, timestamp);
896
897#if EFI_LOGIC_ANALYZER
898 waTriggerEventListener(signal, triggerIndexForListeners, timestamp);
899#endif
900
901 angle_t nextPhase = findNextTriggerToothAngle(triggerIndexForListeners);
902
903 float expectNextPhase = nextPhase + tdcPosition();
904 wrapAngle(expectNextPhase, "nextEnginePhase", ObdCode::CUSTOM_ERR_6555);
905 expectedNextPhase = expectNextPhase;
906
907#if EFI_CDM_INTEGRATION
908 if (trgEventIndex == 0 && isBrainPinValid(engineConfiguration->cdmInputPin)) {
910 engine->knockLogic(cdmKnockValue);
911 }
912#endif /* EFI_CDM_INTEGRATION */
913
914 if (engine->rpmCalculator.getCachedRpm() > 0 && triggerIndexForListeners == 0) {
915 engine->module<TpsAccelEnrichment>()->onEngineCycleTps();
916 }
917
918 // Handle ignition and injection
919 mainTriggerCallback(triggerIndexForListeners, timestamp, currentEngineDecodedPhase, nextPhase);
920
921 temp_mapVvt_index = triggerIndexForListeners / 2;
922
923 // Decode the MAP based "cam" sensor
925
927 } else {
928 // We don't have sync, but report to the wave chart anyway as index 0.
930
931 expectedNextPhase = unexpected;
932 }
933}
int getCurrentCdmValue(int currentRevolution)
constexpr auto & module()
Definition engine.h:200
float getCachedRpm() const
angle_t findNextTriggerToothAngle(int nextToothIndex)
expected< float > expectedNextPhase
void decodeMapCam(int triggerIndexForListeners, efitick_t nowNt, float currentPhase)
bool isToothExpectedNow(efitick_t timestamp)
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 ...
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:22
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)
@ 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)
PUBLIC_API_WEAK void boardTriggerCallback(efitick_t timestamp, float currentPhase)
PUBLIC_API_WEAK bool boardAllowTriggerActions()
int getCrankDivider(operation_mode_e operationMode)
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:

◆ isMapCamSync()

bool TriggerCentral::isMapCamSync ( efitick_t  nowNt,
float  currentPhase 
)

Definition at line 648 of file trigger_central.cpp.

648 {
649 UNUSED(timestamp);
650
651 // 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.
652 auto toothAngle360 = currentPhase;
653 while (toothAngle360 >= 360) {
654 toothAngle360 -= 360;
655 }
656
657 bool result;
658 if (mapCamPrevToothAngle < engineConfiguration->mapCamDetectionAnglePosition && toothAngle360 > engineConfiguration->mapCamDetectionAnglePosition) {
659 // we are somewhere close to 'mapCamDetectionAnglePosition'
660
661 // warning: hack hack hack
663
664 // Compute diff against the last time we were here
665 float instantMapDiffBetweenReadoutAngles = map - mapCamPrevCycleValue;
667
668 if (instantMapDiffBetweenReadoutAngles > engineConfiguration->mapSyncThreshold) {
670 int revolutionCounter = getTriggerCentral()->triggerState.getSynchronizationCounter();
671 mapVvt_MAP_AT_CYCLE_COUNT = revolutionCounter - prevChangeAtCycle;
672 prevChangeAtCycle = revolutionCounter;
673 result = true;
674 } else {
675 result = false;
676 }
677
679 mapVvt_MAP_AT_DIFF = instantMapDiffBetweenReadoutAngles;
680 } else {
681 result = false;
682 }
683
684 mapCamPrevToothAngle = toothAngle360;
685 return result;
686}

Referenced by decodeMapCam().

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

727 {
728 // Check that the expected next phase (from the last tooth) is close to the actual current phase:
729 // basically, check that the tooth width is correct
730 auto estimatedCurrentPhase = getCurrentEnginePhase(timestamp);
731 auto lastToothPhase = m_lastToothPhaseFromSyncPoint;
732
733 if (expectedNextPhase && estimatedCurrentPhase) {
734 float angleError = expectedNextPhase.Value - estimatedCurrentPhase.Value;
735
736 // Wrap around correctly at the end of the cycle
737 float cycle = getEngineState()->engineCycle;
738 if (angleError < -cycle / 2) {
739 angleError += cycle;
740 }
741
742 triggerToothAngleError = angleError;
743
744 // Only perform checks if engine is spinning quickly
745 // All kinds of garbage happens while cranking
747 // Now compute how close we are to the last tooth decoded
748 float angleSinceLastTooth = estimatedCurrentPhase.Value - lastToothPhase;
749 if (angleSinceLastTooth < 0.5f) {
750 // This tooth came impossibly early, ignore it
751 // This rejects things like doubled edges, for example:
752 // |-| |----------------
753 // | | |
754 // ____________| |_|
755 // 1 2
756 // #1 will be decoded
757 // #2 will be ignored
758 // We're not sure which edge was the "real" one, but they were close enough
759 // together that it doesn't really matter.
760 warning(ObdCode::CUSTOM_PRIMARY_DOUBLED_EDGE, "doubled trigger edge after %.2f deg at #%d", angleSinceLastTooth, triggerState.currentCycle.current_index);
761
762 return false;
763 }
764
765 // Absolute error from last tooth
766 float absError = absF(angleError);
767 float isRpmEnough = Sensor::getOrZero(SensorType::Rpm) > 1000;
768 // TODO: configurable threshold
769 if (isRpmEnough && absError > 10 && absError < 180) {
770 // This tooth came at a very unexpected time, ignore it
772
773 // TODO: this causes issues with some real engine logs, should it?
774 // return false;
775 }
776 }
777 } else {
779 }
780
781 // We aren't ready to reject unexpected teeth, so accept this tooth
782 return true;
783}
angle_t engineCycle
expected< float > getCurrentEnginePhase(efitick_t nowNt) const
current_cycle_state_s currentCycle
EngineState * getEngineState()
Definition engine.cpp:577
@ 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 1261 of file trigger_central.cpp.

◆ isTriggerDecoderError()

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

Definition at line 1293 of file trigger_central.cpp.

1293 {
1294 return triggerErrorDetection.sum(6) > 4;
1295}

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

563 {
564 memset(hwEventCounters, 0, sizeof(hwEventCounters));
565}

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

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

◆ validateCamVvtCounters()

void TriggerCentral::validateCamVvtCounters ( )

Definition at line 1119 of file trigger_central.cpp.

1119 {
1120 // micro-optimized 'synchronizationCounter % 256'
1121 int camVvtValidationIndex = triggerState.getSynchronizationCounter() & 0xFF;
1122 if (camVvtValidationIndex == 0) {
1123 vvtCamCounter = 0;
1124 } else if (camVvtValidationIndex == 0xFE && vvtCamCounter < 60) {
1125 // magic logic: we expect at least 60 CAM/VVT events for each 256 trigger cycles, otherwise throw a code
1126 warning(ObdCode::OBD_Camshaft_Position_Sensor_Circuit_Range_Performance, "No Camshaft Position Sensor signals");
1127 }
1128}
@ 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 166 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 applyShapesConfiguration(), and findNextTriggerToothAngle().

◆ 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 205 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 isMapCamSync().

◆ noiseFilter

TriggerNoiseFilter TriggerCentral::noiseFilter

◆ prevChangeAtCycle

int TriggerCentral::prevChangeAtCycle = 0

Definition at line 112 of file trigger_central.h.

Referenced by isMapCamSync().

◆ 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().

◆ vvtPosition

angle_t TriggerCentral::vvtPosition[BANKS_COUNT][CAMS_PER_BANK]

Definition at line 170 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 178 of file trigger_central.h.

178 {
179 {
180 "VVT B1 Int",
181#if CAMS_PER_BANK >= 2
182 "VVT B1 Exh"
183#endif
184 },
185#if BANKS_COUNT >= 2
186 {
187 "VVT B2 Int",
188#if CAMS_PER_BANK >= 2
189 "VVT B1 Exh"
190#endif
191 }
192#endif
193 };

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

◆ vvtTriggerConfiguration

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

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