2015-07-10 06:01:56 -07:00
/*
* @ file trigger_central . cpp
2017-12-12 14:26:23 -08:00
* Here we have a bunch of higher - level methods which are not directly related to actual signal decoding
2015-07-10 06:01:56 -07:00
*
* @ date Feb 23 , 2014
2020-01-07 21:02:40 -08:00
* @ author Andrey Belomutskiy , ( c ) 2012 - 2020
2015-07-10 06:01:56 -07:00
*/
2021-07-25 22:05:17 -07:00
# include "pch.h"
2022-09-07 12:56:45 -07:00
2015-07-10 06:01:56 -07:00
# include "trigger_central.h"
# include "trigger_decoder.h"
# include "main_trigger_callback.h"
# include "listener_array.h"
2020-10-17 05:00:11 -07:00
# include "hip9011.h"
# include "logic_analyzer.h"
2019-03-31 14:44:34 -07:00
2019-03-31 13:56:13 -07:00
# include "local_version_holder.h"
2017-10-16 11:08:45 -07:00
# include "trigger_simulator.h"
2021-04-22 18:23:20 -07:00
# include "trigger_emulator_algo.h"
2015-07-10 06:01:56 -07:00
2020-10-03 22:43:02 -07:00
# include "map_averaging.h"
# include "main_trigger_callback.h"
2021-11-05 17:02:15 -07:00
# include "status_loop.h"
2022-09-10 21:18:08 -07:00
# include "engine_sniffer.h"
2022-09-23 17:39:41 -07:00
# include "auto_generated_sync_edge.h"
2020-10-03 22:43:02 -07:00
2019-07-06 17:15:49 -07:00
# if EFI_TUNER_STUDIO
# include "tunerstudio.h"
# endif /* EFI_TUNER_STUDIO */
# if EFI_ENGINE_SNIFFER
WaveChart waveChart ;
# endif /* EFI_ENGINE_SNIFFER */
2021-07-13 17:15:55 -07:00
static scheduling_s debugToggleScheduling ;
2021-07-16 14:18:03 -07:00
# define DEBUG_PIN_DELAY US2NT(60)
2021-07-13 17:15:55 -07:00
2022-11-06 17:47:57 -08:00
# define TRIGGER_WAVEFORM(x) getTriggerCentral()->triggerShape.x
2022-04-16 14:24:31 -07:00
# if EFI_SHAFT_POSITION_INPUT
2021-11-30 16:31:54 -08:00
TriggerCentral : : TriggerCentral ( ) :
2021-10-24 12:30:17 -07:00
vvtEventRiseCounter ( ) ,
vvtEventFallCounter ( ) ,
2022-05-31 21:55:34 -07:00
vvtPosition ( ) ,
triggerState ( " TRG " )
2021-10-24 12:30:17 -07:00
{
2021-11-30 16:31:54 -08:00
memset ( & hwEventCounters , 0 , sizeof ( hwEventCounters ) ) ;
2022-11-05 21:32:38 -07:00
triggerState . resetState ( ) ;
2020-01-27 21:16:33 -08:00
noiseFilter . resetAccumSignalData ( ) ;
2019-01-31 14:55:23 -08:00
}
2020-01-27 21:16:33 -08:00
void TriggerNoiseFilter : : resetAccumSignalData ( ) {
2019-01-31 14:55:23 -08:00
memset ( lastSignalTimes , 0xff , sizeof ( lastSignalTimes ) ) ; // = -1
memset ( accumSignalPeriods , 0 , sizeof ( accumSignalPeriods ) ) ;
memset ( accumSignalPrevPeriods , 0 , sizeof ( accumSignalPrevPeriods ) ) ;
}
2019-06-08 06:51:36 -07:00
int TriggerCentral : : getHwEventCounter ( int index ) const {
2019-01-31 14:55:23 -08:00
return hwEventCounters [ index ] ;
}
2021-03-25 04:39:23 -07:00
angle_t TriggerCentral : : getVVTPosition ( uint8_t bankIndex , uint8_t camIndex ) {
2021-05-27 02:50:59 -07:00
if ( bankIndex > = BANKS_COUNT | | camIndex > = CAMS_PER_BANK ) {
return NAN ;
}
2021-03-25 04:39:23 -07:00
return vvtPosition [ bankIndex ] [ camIndex ] ;
2020-01-30 22:49:10 -08:00
}
2021-12-02 13:52:16 -08:00
/**
* @ return angle since trigger synchronization point , NOT angle since TDC .
*/
2021-11-04 02:46:16 -07:00
expected < float > TriggerCentral : : getCurrentEnginePhase ( efitick_t nowNt ) const {
floatus_t oneDegreeUs = engine - > rpmCalculator . oneDegreeUs ;
2024-07-22 12:05:17 -07:00
if ( std : : isnan ( oneDegreeUs ) ) {
2021-11-04 02:46:16 -07:00
return unexpected ;
}
2022-08-12 05:08:23 -07:00
float elapsed ;
float toothPhase ;
{
// under lock to avoid mismatched tooth phase and time
chibios_rt : : CriticalSectionLocker csl ;
elapsed = m_lastToothTimer . getElapsedUs ( nowNt ) ;
toothPhase = m_lastToothPhaseFromSyncPoint ;
}
return toothPhase + elapsed / oneDegreeUs ;
2021-11-04 02:46:16 -07:00
}
2021-07-05 20:51:13 -07:00
/**
* todo : why is this method NOT reciprocal to getRpmMultiplier ? !
*/
2024-01-15 14:28:47 -08:00
int getCrankDivider ( operation_mode_e operationMode ) {
2021-07-05 20:51:13 -07:00
switch ( operationMode ) {
case FOUR_STROKE_CRANK_SENSOR :
return 2 ;
case FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR :
return SYMMETRICAL_CRANK_SENSOR_DIVIDER ;
case FOUR_STROKE_THREE_TIMES_CRANK_SENSOR :
return SYMMETRICAL_THREE_TIMES_CRANK_SENSOR_DIVIDER ;
2024-01-15 10:04:38 -08:00
case FOUR_STROKE_SIX_TIMES_CRANK_SENSOR :
return SYMMETRICAL_SIX_TIMES_CRANK_SENSOR_DIVIDER ;
2022-05-17 18:38:24 -07:00
case FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR :
return SYMMETRICAL_TWELVE_TIMES_CRANK_SENSOR_DIVIDER ;
2024-01-15 17:36:44 -08:00
case OM_NONE :
2021-07-05 20:51:13 -07:00
case FOUR_STROKE_CAM_SENSOR :
case TWO_STROKE :
// That's easy - trigger cycle matches engine cycle
return 1 ;
2024-01-15 17:36:44 -08:00
/* let's NOT handle default in order to benefit from -Werror=switch */
2021-07-05 20:51:13 -07:00
}
2024-01-15 17:36:44 -08:00
/**
wow even while we explicitly handle all enumerations in the switch above we still need a return statement due to
https : //stackoverflow.com/questions/34112483/gcc-how-best-to-handle-warning-about-unreachable-end-of-function-after-switch
*/
criticalError ( " unreachable getCrankDivider " ) ;
return 1 ;
2021-07-05 20:51:13 -07:00
}
2020-08-29 15:37:13 -07:00
static bool vvtWithRealDecoder ( vvt_mode_e vvtMode ) {
2021-07-03 06:43:27 -07:00
return vvtMode ! = VVT_INACTIVE
2023-09-14 13:53:16 -07:00
& & vvtMode ! = VVT_TOYOTA_3_TOOTH /* VVT_2JZ is an unusual 3/0 missed tooth symmetrical wheel */
2022-09-24 20:25:36 -07:00
& & vvtMode ! = VVT_HONDA_K_INTAKE
2022-08-31 21:18:06 -07:00
& & vvtMode ! = VVT_MAP_V_TWIN
2023-08-03 17:24:22 -07:00
& & vvtMode ! = VVT_SINGLE_TOOTH ;
2020-08-29 15:37:13 -07:00
}
2024-05-06 10:44:12 -07:00
angle_t TriggerCentral : : syncEnginePhaseAndReport ( int divider , int remainder ) {
2022-09-13 22:34:52 -07:00
angle_t engineCycle = getEngineCycle ( getEngineRotationState ( ) - > getOperationMode ( ) ) ;
2021-07-21 22:02:37 -07:00
2022-11-06 08:41:27 -08:00
angle_t totalShift = triggerState . syncEnginePhase ( divider , remainder , engineCycle ) ;
if ( totalShift ! = 0 ) {
// Reset instant RPM, since the engine phase has now changed, invalidating the tooth history buffer
// maybe TODO: could/should we rotate the buffer around to re-align it instead? Is that worth it?
2022-11-06 08:56:18 -08:00
instantRpm . resetInstantRpm ( ) ;
2022-11-06 08:41:27 -08:00
}
return totalShift ;
2021-07-05 20:51:13 -07:00
}
2021-07-13 17:15:55 -07:00
static void turnOffAllDebugFields ( void * arg ) {
( void ) arg ;
# if EFI_PROD_CODE
for ( int index = 0 ; index < TRIGGER_INPUT_PIN_COUNT ; index + + ) {
2022-10-22 05:39:55 -07:00
if ( isBrainPinValid ( engineConfiguration - > triggerInputDebugPins [ index ] ) ) {
2021-11-17 00:54:21 -08:00
writePad ( " trigger debug " , engineConfiguration - > triggerInputDebugPins [ index ] , 0 ) ;
2021-07-13 17:15:55 -07:00
}
}
for ( int index = 0 ; index < CAM_INPUTS_COUNT ; index + + ) {
2022-10-22 05:39:55 -07:00
if ( isBrainPinValid ( engineConfiguration - > camInputsDebug [ index ] ) ) {
2021-11-17 00:54:21 -08:00
writePad ( " cam debug " , engineConfiguration - > camInputsDebug [ index ] , 0 ) ;
2021-07-13 17:15:55 -07:00
}
}
# endif /* EFI_PROD_CODE */
}
2021-11-16 01:15:29 -08:00
static angle_t adjustCrankPhase ( int camIndex ) {
2022-05-09 21:22:50 -07:00
float maxSyncThreshold = engineConfiguration - > maxCamPhaseResolveRpm ;
if ( maxSyncThreshold ! = 0 & & Sensor : : getOrZero ( SensorType : : Rpm ) > maxSyncThreshold ) {
// The user has elected to stop trying to resolve crank phase after some RPM.
// Maybe their cam sensor only works at low RPM or something.
// Anyway, don't try to change crank phase at all, and return that we made no change.
return 0 ;
}
2022-09-13 22:34:52 -07:00
operation_mode_e operationMode = getEngineRotationState ( ) - > getOperationMode ( ) ;
2021-07-21 22:02:37 -07:00
2023-06-28 18:12:38 -07:00
auto crankDivider = getCrankDivider ( operationMode ) ;
if ( crankDivider = = 1 ) {
// Crank divider of 1 means there's no ambiguity, so don't try to resolve it
return 0 ;
}
TriggerCentral * tc = getTriggerCentral ( ) ;
2022-01-18 21:48:25 -08:00
vvt_mode_e vvtMode = engineConfiguration - > vvtMode [ camIndex ] ;
switch ( vvtMode ) {
2022-08-31 21:18:06 -07:00
case VVT_MAP_V_TWIN :
2023-01-23 17:23:40 -08:00
case VVT_MITSUBISHI_4G63 :
2023-02-16 20:22:34 -08:00
case VVT_MITSUBISHI_4G9x :
2024-05-06 10:44:12 -07:00
return tc - > syncEnginePhaseAndReport ( crankDivider , 1 ) ;
2023-08-03 17:24:22 -07:00
case VVT_SINGLE_TOOTH :
2022-01-18 22:30:16 -08:00
case VVT_NISSAN_VQ :
case VVT_BOSCH_QUICK_START :
2022-01-31 15:20:43 -08:00
case VVT_MIATA_NB :
2023-09-14 13:53:16 -07:00
case VVT_TOYOTA_3_TOOTH :
2022-01-18 21:48:25 -08:00
case VVT_TOYOTA_4_1 :
2023-05-13 10:27:37 -07:00
case VVT_FORD_COYOTE :
2024-07-04 10:58:20 -07:00
case VVT_DEV :
2022-01-18 21:48:25 -08:00
case VVT_FORD_ST170 :
case VVT_BARRA_3_PLUS_1 :
case VVT_NISSAN_MR :
2022-08-31 19:12:45 -07:00
case VVT_MAZDA_SKYACTIV :
2024-05-27 21:07:57 -07:00
case VVT_MAZDA_L :
2023-08-24 22:10:03 -07:00
case VVT_MITSUBISHI_4G69 :
2022-03-19 19:23:04 -07:00
case VVT_MITSUBISHI_3A92 :
2023-11-08 11:51:12 -08:00
case VVT_MITSUBISHI_6G72 :
2022-03-19 19:23:04 -07:00
case VVT_MITSUBISHI_6G75 :
2022-09-24 20:49:30 -07:00
case VVT_HONDA_K_EXHAUST :
2024-02-04 06:19:30 -08:00
case VVT_HONDA_CBR_600 :
2024-05-06 10:44:12 -07:00
return tc - > syncEnginePhaseAndReport ( crankDivider , 0 ) ;
2022-09-24 20:49:30 -07:00
case VVT_HONDA_K_INTAKE :
2023-05-16 20:00:18 -07:00
// with 4 evenly spaced tooth we cannot use this wheel for engine sync
2023-08-20 19:23:44 -07:00
criticalError ( " Honda K Intake is not suitable for engine sync " ) ;
2023-05-16 20:07:23 -07:00
[[fallthrough]] ;
2021-07-21 22:02:37 -07:00
case VVT_INACTIVE :
// do nothing
return 0 ;
}
2022-01-18 21:48:25 -08:00
return 0 ;
2021-07-21 22:02:37 -07:00
}
2021-12-02 14:05:47 -08:00
/**
* See also wrapAngle
*/
2021-10-28 16:26:59 -07:00
static angle_t wrapVvt ( angle_t vvtPosition , int period ) {
2021-07-21 22:02:37 -07:00
// Wrap VVT position in to the range [-360, 360)
2021-10-28 16:26:59 -07:00
while ( vvtPosition < - period / 2 ) {
vvtPosition + = period ;
2021-07-21 22:02:37 -07:00
}
2021-10-28 16:26:59 -07:00
while ( vvtPosition > = period / 2 ) {
vvtPosition - = period ;
2021-07-21 22:02:37 -07:00
}
return vvtPosition ;
}
2022-11-07 07:52:17 -08:00
static void logVvtFront ( bool useOnlyRise , bool isImportantFront , TriggerValue front , efitick_t nowNt , int index ) {
2022-10-22 05:39:55 -07:00
if ( isImportantFront & & isBrainPinValid ( engineConfiguration - > camInputsDebug [ index ] ) ) {
2021-10-28 07:30:05 -07:00
# if EFI_PROD_CODE
2021-11-17 00:54:21 -08:00
writePad ( " cam debug " , engineConfiguration - > camInputsDebug [ index ] , 1 ) ;
2021-10-28 07:30:05 -07:00
# endif /* EFI_PROD_CODE */
2022-09-13 22:53:17 -07:00
getExecutorInterface ( ) - > scheduleByTimestampNt ( " dbg_on " , & debugToggleScheduling , nowNt + DEBUG_PIN_DELAY , & turnOffAllDebugFields ) ;
2021-10-28 07:30:05 -07:00
}
2022-11-07 07:52:17 -08:00
if ( ! useOnlyRise | | engineConfiguration - > displayLogicLevelsInEngineSniffer ) {
// If we care about both edges OR displayLogicLevel is set, log every front exactly as it is
addEngineSnifferVvtEvent ( index , front = = TriggerValue : : RISE ? FrontDirection : : UP : FrontDirection : : DOWN ) ;
2021-10-28 07:30:05 -07:00
# if EFI_TOOTH_LOGGER
2022-11-07 07:52:17 -08:00
LogTriggerTooth ( front = = TriggerValue : : RISE ? SHAFT_SECONDARY_RISING : SHAFT_SECONDARY_FALLING , nowNt ) ;
2021-10-28 07:30:05 -07:00
# endif /* EFI_TOOTH_LOGGER */
2022-11-07 07:52:17 -08:00
} else {
if ( isImportantFront ) {
// On the important edge, log a rise+fall pair, and nothing on the real falling edge
2022-09-10 21:18:08 -07:00
addEngineSnifferVvtEvent ( index , FrontDirection : : UP ) ;
addEngineSnifferVvtEvent ( index , FrontDirection : : DOWN ) ;
2022-11-07 07:52:17 -08:00
2021-10-28 07:30:05 -07:00
# if EFI_TOOTH_LOGGER
2021-11-16 01:15:29 -08:00
LogTriggerTooth ( SHAFT_SECONDARY_RISING , nowNt ) ;
2022-11-07 07:52:17 -08:00
LogTriggerTooth ( SHAFT_SECONDARY_FALLING , nowNt ) ;
2021-10-28 07:30:05 -07:00
# endif /* EFI_TOOTH_LOGGER */
}
}
}
2023-02-28 02:11:28 -08:00
void hwHandleVvtCamSignal ( bool isRising , efitick_t timestamp , int index ) {
hwHandleVvtCamSignal ( isRising ? TriggerValue : : RISE : TriggerValue : : FALL , timestamp , index ) ;
}
2023-02-20 21:08:22 -08:00
// 'invertCamVVTSignal' is already accounted by the time this method is invoked
2022-09-10 23:57:35 -07:00
void hwHandleVvtCamSignal ( TriggerValue front , efitick_t nowNt , int index ) {
2022-09-13 23:06:52 -07:00
TriggerCentral * tc = getTriggerCentral ( ) ;
if ( tc - > directSelfStimulation | | ! tc - > hwTriggerInputEnabled ) {
2022-05-29 07:42:08 -07:00
// sensor noise + self-stim = loss of trigger sync
return ;
}
2023-10-26 10:04:30 -07:00
handleVvtCamSignal ( front , nowNt , index ) ;
}
2022-05-29 07:42:08 -07:00
2023-10-26 10:04:30 -07:00
void handleVvtCamSignal ( TriggerValue front , efitick_t nowNt , int index ) {
TriggerCentral * tc = getTriggerCentral ( ) ;
2023-02-20 21:08:22 -08:00
if ( index = = 0 ) {
engine - > outputChannels . vvtChannel1 = front = = TriggerValue : : RISE ;
2023-04-22 05:32:30 -07:00
} else if ( index = = 1 ) {
engine - > outputChannels . vvtChannel2 = front = = TriggerValue : : RISE ;
2023-10-07 08:03:53 -07:00
} else if ( index = = 2 ) {
engine - > outputChannels . vvtChannel3 = front = = TriggerValue : : RISE ;
} else if ( index = = 3 ) {
engine - > outputChannels . vvtChannel4 = front = = TriggerValue : : RISE ;
2023-02-20 21:08:22 -08:00
}
2023-10-07 09:34:32 -07:00
int bankIndex = BANK_BY_INDEX ( index ) ;
int camIndex = CAM_BY_INDEX ( index ) ;
2022-09-10 23:57:35 -07:00
if ( front = = TriggerValue : : RISE ) {
2021-10-23 16:01:31 -07:00
tc - > vvtEventRiseCounter [ index ] + + ;
2019-09-02 18:02:08 -07:00
} else {
2021-10-23 16:01:31 -07:00
tc - > vvtEventFallCounter [ index ] + + ;
2019-09-02 18:02:08 -07:00
}
2021-11-17 00:54:21 -08:00
if ( engineConfiguration - > vvtMode [ camIndex ] = = VVT_INACTIVE ) {
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_VVT_MODE_NOT_SELECTED , " VVT: event on %d but no mode " , camIndex ) ;
2021-07-03 08:08:22 -07:00
}
2019-09-02 18:02:08 -07:00
2024-03-15 11:04:10 -07:00
# ifdef VR_HW_CHECK_MODE
2020-12-21 10:33:09 -08:00
// some boards do not have hardware VR input LEDs which makes such boards harder to validate
// from experience we know that assembly mistakes happen and quality control is required
extern ioportid_t criticalErrorLedPort ;
extern ioportmask_t criticalErrorLedPin ;
for ( int i = 0 ; i < 100 ; i + + ) {
// turning pin ON and busy-waiting a bit
palWritePad ( criticalErrorLedPort , criticalErrorLedPin , 1 ) ;
}
palWritePad ( criticalErrorLedPort , criticalErrorLedPin , 0 ) ;
# endif // VR_HW_CHECK_MODE
2022-11-07 07:52:17 -08:00
const auto & vvtShape = tc - > vvtShape [ camIndex ] ;
2020-05-15 13:35:18 -07:00
2022-11-07 07:52:17 -08:00
bool isVvtWithRealDecoder = vvtWithRealDecoder ( engineConfiguration - > vvtMode [ camIndex ] ) ;
2021-07-02 17:12:31 -07:00
2022-11-07 07:52:17 -08:00
// Non real decoders only use the rising edge
bool vvtUseOnlyRise = ! isVvtWithRealDecoder | | vvtShape . useOnlyRisingEdges ;
bool isImportantFront = ! vvtUseOnlyRise | | ( front = = TriggerValue : : RISE ) ;
2019-09-02 18:02:08 -07:00
2022-11-07 07:52:17 -08:00
logVvtFront ( vvtUseOnlyRise , isImportantFront , front , nowNt , index ) ;
if ( ! isImportantFront ) {
// This edge is unimportant, ignore it.
2016-08-23 20:03:01 -07:00
return ;
}
2021-12-27 21:00:26 -08:00
// If the main trigger is not synchronized, don't decode VVT yet
if ( ! tc - > triggerState . getShaftSynchronized ( ) ) {
2017-08-11 11:02:15 -07:00
return ;
}
2022-05-10 13:55:28 -07:00
TriggerDecoderBase & vvtDecoder = tc - > vvtState [ bankIndex ] [ camIndex ] ;
2021-12-06 14:04:05 -08:00
2022-05-10 13:55:28 -07:00
if ( isVvtWithRealDecoder ) {
2022-05-10 01:41:39 -07:00
vvtDecoder . decodeTriggerEvent (
2022-03-21 17:39:47 -07:00
" vvt " ,
2022-11-07 07:52:17 -08:00
vvtShape ,
2020-08-26 21:06:10 -07:00
nullptr ,
2022-09-13 23:06:52 -07:00
tc - > vvtTriggerConfiguration [ camIndex ] ,
2022-09-10 23:57:35 -07:00
front = = TriggerValue : : RISE ? SHAFT_PRIMARY_RISING : SHAFT_PRIMARY_FALLING , nowNt ) ;
2021-12-06 14:04:05 -08:00
// yes we log data from all VVT channels into same fields for now
2022-05-10 01:41:39 -07:00
tc - > triggerState . vvtSyncGapRatio = vvtDecoder . triggerSyncGapRatio ;
2023-03-21 06:45:08 -07:00
tc - > triggerState . vvtToothDurations0 = ( uint32_t ) NT2US ( vvtDecoder . toothDurations [ 0 ] ) ;
2022-05-10 01:41:39 -07:00
tc - > triggerState . vvtStateIndex = vvtDecoder . currentCycle . current_index ;
2021-10-28 07:36:41 -07:00
}
2020-08-26 21:06:10 -07:00
2023-09-27 20:22:18 -07:00
// here we count all cams together
2019-09-02 11:47:05 -07:00
tc - > vvtCamCounter + + ;
2016-08-20 19:02:12 -07:00
2021-12-27 21:00:26 -08:00
auto currentPhase = tc - > getCurrentEnginePhase ( nowNt ) ;
if ( ! currentPhase ) {
// If we couldn't resolve engine speed (yet primary trigger is sync'd), this
// probably means that we have partial crank sync, but not RPM information yet
return ;
}
2022-06-23 20:11:29 -07:00
angle_t angleFromPrimarySyncPoint = currentPhase . Value ;
// convert trigger cycle angle into engine cycle angle
angle_t currentPosition = angleFromPrimarySyncPoint - tdcPosition ( ) ;
2020-08-23 08:49:46 -07:00
// https://github.com/rusefi/rusefi/issues/1713 currentPosition could be negative that's expected
2020-05-10 08:54:21 -07:00
2021-01-26 19:54:25 -08:00
# if EFI_UNIT_TEST
2021-02-08 17:38:38 -08:00
tc - > currentVVTEventPosition [ bankIndex ] [ camIndex ] = currentPosition ;
2021-01-26 19:54:25 -08:00
# endif // EFI_UNIT_TEST
2022-05-08 05:50:27 -07:00
tc - > triggerState . vvtCurrentPosition = currentPosition ;
2020-05-10 08:54:21 -07:00
2022-05-10 13:55:28 -07:00
if ( isVvtWithRealDecoder & & vvtDecoder . currentCycle . current_index ! = 0 ) {
2022-01-18 21:25:35 -08:00
// this is not sync tooth - exiting
return ;
}
2023-10-06 11:38:27 -07:00
auto vvtPosition = engineConfiguration - > vvtOffsets [ bankIndex * CAMS_PER_BANK + camIndex ] - currentPosition ;
tc - > triggerState . vvtToothPosition [ index ] = vvtPosition ;
2021-02-08 18:50:31 -08:00
switch ( engineConfiguration - > vvtMode [ camIndex ] ) {
2023-09-14 13:53:16 -07:00
case VVT_TOYOTA_3_TOOTH :
2023-09-09 21:22:38 -07:00
{
int from = engineConfiguration - > camDecoder2jzPosition - engineConfiguration - > camDecoder2jzPrecision ;
int to = engineConfiguration - > camDecoder2jzPosition + engineConfiguration - > camDecoder2jzPrecision ;
2020-05-15 13:35:18 -07:00
// we do not know if we are in sync or out of sync, so we have to be looking for both possibilities
2023-09-10 07:34:06 -07:00
if ( ( currentPosition < from | | currentPosition > to ) & &
( currentPosition < from + 360 | | currentPosition > to + 360 ) ) {
2020-05-10 15:03:11 -07:00
// outside of the expected range
return ;
}
2023-09-09 21:22:38 -07:00
}
2020-05-10 15:10:50 -07:00
break ;
2020-05-10 12:22:50 -07:00
default :
// else, do nothing
break ;
2020-05-10 08:54:04 -07:00
}
2016-11-11 20:02:49 -08:00
2023-03-29 19:57:31 -07:00
// this could be just an 'if' but let's have it expandable for future use :)
switch ( engineConfiguration - > vvtMode [ camIndex ] ) {
case VVT_HONDA_K_INTAKE :
// honda K has four tooth in VVT intake trigger, so we just wrap each of those to 720 / 4
vvtPosition = wrapVvt ( vvtPosition , 180 ) ;
break ;
default :
// else, do nothing
break ;
}
2024-08-19 13:59:23 -07:00
# if EFI_PROD_CODE
2024-08-21 21:08:52 -07:00
if ( ! isBrainPinValid ( engineConfiguration - > camInputs [ engineConfiguration - > engineSyncCam ] ) & &
engineConfiguration - > vvtMode [ engineConfiguration - > engineSyncCam ] ! = VVT_MAP_V_TWIN ) {
2024-08-21 16:30:46 -07:00
criticalError ( " Selected engine sync input not configured: %d " , engineConfiguration - > engineSyncCam ) ;
2024-08-19 13:59:23 -07:00
}
# endif // EFI_PROD_CODE
2022-09-08 13:15:36 -07:00
// Only do engine sync using one cam, other cams just provide VVT position.
if ( index = = engineConfiguration - > engineSyncCam ) {
angle_t crankOffset = adjustCrankPhase ( camIndex ) ;
// vvtPosition was calculated against wrong crank zero position. Now that we have adjusted crank position we
// shall adjust vvt position as well
vvtPosition - = crankOffset ;
vvtPosition = wrapVvt ( vvtPosition , FOUR_STROKE_CYCLE_DURATION ) ;
if ( absF ( angleFromPrimarySyncPoint ) < 7 ) {
/**
* we prefer not to have VVT sync right at trigger sync so that we do not have phase detection error if things happen a bit in
* wrong order due to belt flex or else
* https : //github.com/rusefi/rusefi/issues/3269
*/
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_VVT_SYNC_POSITION , " VVT sync position too close to trigger sync " ) ;
2022-09-08 13:15:36 -07:00
}
} else {
// Not using this cam for engine sync, just wrap the value in to the reasonable range
vvtPosition = wrapVvt ( vvtPosition , FOUR_STROKE_CYCLE_DURATION ) ;
2022-06-23 20:11:29 -07:00
}
2021-10-28 08:40:31 -07:00
2022-09-08 13:15:36 -07:00
// Only record VVT position if we have full engine sync - may be bogus before that point
if ( tc - > triggerState . hasSynchronizedPhase ( ) ) {
tc - > vvtPosition [ bankIndex ] [ camIndex ] = vvtPosition ;
} else {
tc - > vvtPosition [ bankIndex ] [ camIndex ] = 0 ;
2021-10-02 22:48:34 -07:00
}
2016-08-20 19:02:12 -07:00
}
2021-12-01 22:06:40 -08:00
int triggerReentrant = 0 ;
int maxTriggerReentrant = 0 ;
2019-05-10 20:52:55 -07:00
uint32_t triggerDuration ;
uint32_t triggerMaxDuration = 0 ;
2021-04-22 21:45:36 -07:00
/**
2023-02-20 20:40:31 -08:00
* This function is called by all " hardware " trigger inputs :
2021-06-28 07:06:22 -07:00
* - Hardware triggers
* - Trigger replay from CSV ( unit tests )
2021-04-22 21:45:36 -07:00
*/
2021-11-16 01:15:29 -08:00
void hwHandleShaftSignal ( int signalIndex , bool isRising , efitick_t timestamp ) {
2022-09-13 23:06:52 -07:00
TriggerCentral * tc = getTriggerCentral ( ) ;
2021-06-28 07:06:22 -07:00
ScopePerf perf ( PE : : HandleShaftSignal ) ;
2024-03-15 11:04:10 -07:00
# ifdef VR_HW_CHECK_MODE
2020-12-20 08:17:38 -08:00
// some boards do not have hardware VR input LEDs which makes such boards harder to validate
// from experience we know that assembly mistakes happen and quality control is required
extern ioportid_t criticalErrorLedPort ;
extern ioportmask_t criticalErrorLedPin ;
2021-04-22 18:23:20 -07:00
# if HW_CHECK_ALWAYS_STIMULATE
disableTriggerStimulator ( ) ;
# endif // HW_CHECK_ALWAYS_STIMULATE
2020-12-20 08:17:38 -08:00
for ( int i = 0 ; i < 100 ; i + + ) {
// turning pin ON and busy-waiting a bit
palWritePad ( criticalErrorLedPort , criticalErrorLedPin , 1 ) ;
}
palWritePad ( criticalErrorLedPort , criticalErrorLedPin , 0 ) ;
# endif // VR_HW_CHECK_MODE
2022-09-13 23:06:52 -07:00
if ( tc - > directSelfStimulation | | ! tc - > hwTriggerInputEnabled ) {
2022-05-29 07:42:08 -07:00
// sensor noise + self-stim = loss of trigger sync
return ;
}
2021-11-16 01:15:29 -08:00
handleShaftSignal ( signalIndex , isRising , timestamp ) ;
2021-04-22 21:45:36 -07:00
}
2021-06-28 07:06:22 -07:00
// Handle all shaft signals - hardware or emulated both
2021-11-16 01:15:29 -08:00
void handleShaftSignal ( int signalIndex , bool isRising , efitick_t timestamp ) {
2021-06-28 07:06:22 -07:00
bool isPrimary = signalIndex = = 0 ;
if ( ! isPrimary & & ! TRIGGER_WAVEFORM ( needSecondTriggerInput ) ) {
return ;
}
trigger_event_e signal ;
// todo: add support for 3rd channel
if ( isRising ) {
signal = isPrimary ?
( engineConfiguration - > invertPrimaryTriggerSignal ? SHAFT_PRIMARY_FALLING : SHAFT_PRIMARY_RISING ) :
( engineConfiguration - > invertSecondaryTriggerSignal ? SHAFT_SECONDARY_FALLING : SHAFT_SECONDARY_RISING ) ;
} else {
signal = isPrimary ?
( engineConfiguration - > invertPrimaryTriggerSignal ? SHAFT_PRIMARY_RISING : SHAFT_PRIMARY_FALLING ) :
( engineConfiguration - > invertSecondaryTriggerSignal ? SHAFT_SECONDARY_RISING : SHAFT_SECONDARY_FALLING ) ;
}
2023-02-20 21:08:22 -08:00
if ( isPrimary ) {
engine - > outputChannels . triggerChannel1 = signal = = SHAFT_PRIMARY_RISING ;
} else {
engine - > outputChannels . triggerChannel2 = signal = = SHAFT_SECONDARY_RISING ;
}
2021-04-22 21:45:36 -07:00
// Don't accept trigger input in case of some problems
2022-09-13 23:17:04 -07:00
if ( ! getLimpManager ( ) - > allowTriggerInput ( ) ) {
2021-04-22 21:45:36 -07:00
return ;
}
2019-07-07 12:22:46 -07:00
# if EFI_TOOTH_LOGGER
2019-07-06 17:48:58 -07:00
// Log to the Tunerstudio tooth logger
// We want to do this before anything else as we
2019-07-07 12:22:46 -07:00
// actually want to capture any noise/jitter that may be occurring
2020-04-17 09:14:45 -07:00
2022-11-08 18:48:39 -08:00
bool logLogicState = engineConfiguration - > displayLogicLevelsInEngineSniffer & & getTriggerCentral ( ) - > triggerShape . useOnlyRisingEdges ;
2020-04-17 09:14:45 -07:00
if ( ! logLogicState ) {
// we log physical state even if displayLogicLevelsInEngineSniffer if both fronts are used by decoder
2021-11-16 01:15:29 -08:00
LogTriggerTooth ( signal , timestamp ) ;
2020-04-17 09:14:45 -07:00
}
2019-07-07 12:22:46 -07:00
# endif /* EFI_TOOTH_LOGGER */
2019-07-06 17:48:58 -07:00
2023-05-30 22:41:20 -07:00
// for effective noise filtering, we need both signal edges,
2018-04-25 23:11:51 -07:00
// so we pass them to handleShaftSignal() and defer this test
2021-11-17 00:54:21 -08:00
if ( ! engineConfiguration - > useNoiselessTriggerDecoder ) {
2022-09-25 15:49:54 -07:00
if ( ! isUsefulSignal ( signal , getTriggerCentral ( ) - > triggerShape ) ) {
2020-07-30 16:24:55 -07:00
/**
* no need to process VR falls further
*/
2018-04-25 23:11:51 -07:00
return ;
}
2017-10-16 11:08:45 -07:00
}
2020-04-17 09:14:45 -07:00
2022-04-28 14:32:39 -07:00
if ( engineConfiguration - > triggerInputDebugPins [ signalIndex ] ! = Gpio : : Unassigned ) {
2021-07-13 17:33:27 -07:00
# if EFI_PROD_CODE
2021-11-17 00:54:21 -08:00
writePad ( " trigger debug " , engineConfiguration - > triggerInputDebugPins [ signalIndex ] , 1 ) ;
2021-07-13 17:33:27 -07:00
# endif /* EFI_PROD_CODE */
2022-09-13 23:06:52 -07:00
getExecutorInterface ( ) - > scheduleByTimestampNt ( " dbg_off " , & debugToggleScheduling , timestamp + DEBUG_PIN_DELAY , & turnOffAllDebugFields ) ;
2021-07-13 17:33:27 -07:00
}
2020-04-17 11:02:10 -07:00
# if EFI_TOOTH_LOGGER
2020-04-17 09:14:45 -07:00
if ( logLogicState ) {
2021-12-29 13:18:21 -08:00
// first log rising normally
2021-11-16 01:15:29 -08:00
LogTriggerTooth ( signal , timestamp ) ;
2021-12-29 13:18:21 -08:00
// in 'logLogicState' mode we log opposite front right after logical rising away
2020-04-17 09:14:45 -07:00
if ( signal = = SHAFT_PRIMARY_RISING ) {
2021-11-16 01:15:29 -08:00
LogTriggerTooth ( SHAFT_PRIMARY_FALLING , timestamp ) ;
2020-04-17 09:14:45 -07:00
} else {
2021-11-16 01:15:29 -08:00
LogTriggerTooth ( SHAFT_SECONDARY_FALLING , timestamp ) ;
2020-04-17 09:14:45 -07:00
}
}
2020-04-17 11:02:10 -07:00
# endif /* EFI_TOOTH_LOGGER */
2020-04-17 09:14:45 -07:00
2019-05-07 16:32:08 -07:00
uint32_t triggerHandlerEntryTime = getTimeNowLowerNt ( ) ;
2021-12-01 22:06:40 -08:00
if ( triggerReentrant > maxTriggerReentrant )
maxTriggerReentrant = triggerReentrant ;
triggerReentrant + + ;
2020-03-22 16:06:29 -07:00
2022-09-13 23:06:52 -07:00
getTriggerCentral ( ) - > handleShaftSignal ( signal , timestamp ) ;
2020-03-22 16:06:29 -07:00
2021-12-01 22:06:40 -08:00
triggerReentrant - - ;
2019-05-07 16:32:08 -07:00
triggerDuration = getTimeNowLowerNt ( ) - triggerHandlerEntryTime ;
2021-01-31 19:41:17 -08:00
triggerMaxDuration = maxI ( triggerMaxDuration , triggerDuration ) ;
2015-07-10 06:01:56 -07:00
}
void TriggerCentral : : resetCounters ( ) {
memset ( hwEventCounters , 0 , sizeof ( hwEventCounters ) ) ;
}
2022-09-10 21:18:08 -07:00
static const bool isUpEvent [ 4 ] = { false , true , false , true } ;
static const int wheelIndeces [ 4 ] = { 0 , 0 , 1 , 1 } ;
2015-07-10 06:01:56 -07:00
2022-09-25 15:49:54 -07:00
static void reportEventToWaveChart ( trigger_event_e ckpSignalType , int triggerEventIndex , bool addOppositeEvent ) {
2022-09-13 23:17:04 -07:00
if ( ! getTriggerCentral ( ) - > isEngineSnifferEnabled ) { // this is here just as a shortcut so that we avoid engine sniffer as soon as possible
return ; // engineSnifferRpmThreshold is accounted for inside getTriggerCentral()->isEngineSnifferEnabled
2017-05-25 20:23:22 -07:00
}
2022-09-10 21:18:08 -07:00
int wheelIndex = wheelIndeces [ ( int ) ckpSignalType ] ;
2017-05-25 20:23:22 -07:00
2016-01-11 14:01:33 -08:00
bool isUp = isUpEvent [ ( int ) ckpSignalType ] ;
2015-07-10 06:01:56 -07:00
2022-09-10 21:18:08 -07:00
addEngineSnifferCrankEvent ( wheelIndex , triggerEventIndex , isUp ? FrontDirection : : UP : FrontDirection : : DOWN ) ;
2022-09-25 15:49:54 -07:00
if ( addOppositeEvent ) {
2015-07-10 06:01:56 -07:00
// let's add the opposite event right away
2022-09-10 21:18:08 -07:00
addEngineSnifferCrankEvent ( wheelIndex , triggerEventIndex , isUp ? FrontDirection : : DOWN : FrontDirection : : UP ) ;
2015-07-10 06:01:56 -07:00
}
}
2018-04-25 23:11:51 -07:00
/**
2023-05-30 22:41:20 -07:00
* This is used to filter noise spikes ( interference ) in trigger signal . See
2018-04-25 23:11:51 -07:00
* The basic idea is to use not just edges , but the average amount of time the signal stays in ' 0 ' or ' 1 ' .
2023-05-30 22:41:20 -07:00
* So we update ' accumulated periods ' to track where the signal is .
2018-04-25 23:11:51 -07:00
* And then compare between the current period and previous , with some tolerance ( allowing for the wheel speed change ) .
* @ return true if the signal is passed through .
*/
2020-01-27 21:16:33 -08:00
bool TriggerNoiseFilter : : noiseFilter ( efitick_t nowNt ,
2022-05-10 01:41:39 -07:00
TriggerDecoderBase * triggerState ,
2021-11-16 01:15:29 -08:00
trigger_event_e signal ) {
2018-04-25 23:11:51 -07:00
// todo: find a better place for these defs
2022-06-01 18:24:20 -07:00
static const trigger_event_e opposite [ 4 ] = { SHAFT_PRIMARY_RISING , SHAFT_PRIMARY_FALLING , SHAFT_SECONDARY_RISING , SHAFT_SECONDARY_FALLING } ;
2022-09-11 00:46:50 -07:00
static const TriggerWheel triggerIdx [ 4 ] = { TriggerWheel : : T_PRIMARY , TriggerWheel : : T_PRIMARY , TriggerWheel : : T_SECONDARY , TriggerWheel : : T_SECONDARY } ;
2018-04-25 23:11:51 -07:00
// we process all trigger channels independently
2022-09-11 00:46:50 -07:00
TriggerWheel ti = triggerIdx [ signal ] ;
2018-04-25 23:11:51 -07:00
// falling is opposite to rising, and vise versa
trigger_event_e os = opposite [ signal ] ;
2023-05-30 22:41:20 -07:00
2018-04-25 23:11:51 -07:00
// todo: currently only primary channel is filtered, because there are some weird trigger types on other channels
2022-09-11 00:46:50 -07:00
if ( ti ! = TriggerWheel : : T_PRIMARY )
2018-04-25 23:11:51 -07:00
return true ;
2023-05-30 22:41:20 -07:00
2018-04-25 23:11:51 -07:00
// update period accumulator: for rising signal, we update '0' accumulator, and for falling - '1'
if ( lastSignalTimes [ signal ] ! = - 1 )
accumSignalPeriods [ signal ] + = nowNt - lastSignalTimes [ signal ] ;
// save current time for this trigger channel
lastSignalTimes [ signal ] = nowNt ;
2023-05-30 22:41:20 -07:00
// now we want to compare current accumulated period to the stored one
2018-04-25 23:11:51 -07:00
efitick_t currentPeriod = accumSignalPeriods [ signal ] ;
// the trick is to compare between different
efitick_t allowedPeriod = accumSignalPrevPeriods [ os ] ;
// but first check if we're expecting a gap
2021-07-03 07:37:03 -07:00
bool isGapExpected = TRIGGER_WAVEFORM ( isSynchronizationNeeded ) & & triggerState - > getShaftSynchronized ( ) & &
2022-09-11 00:46:50 -07:00
( triggerState - > currentCycle . eventCount [ ( int ) ti ] + 1 ) = = TRIGGER_WAVEFORM ( getExpectedEventCount ( ti ) ) ;
2023-05-30 22:41:20 -07:00
2018-04-25 23:11:51 -07:00
if ( isGapExpected ) {
// usually we need to extend the period for gaps, based on the trigger info
2019-12-07 22:09:39 -08:00
allowedPeriod * = TRIGGER_WAVEFORM ( syncRatioAvg ) ;
2018-04-25 23:11:51 -07:00
}
2023-05-30 22:41:20 -07:00
2018-04-25 23:11:51 -07:00
// also we need some margin for rapidly changing trigger-wheel speed,
// that's why we expect the period to be no less than 2/3 of the previous period (this is just an empirical 'magic' coef.)
efitick_t minAllowedPeriod = 2 * allowedPeriod / 3 ;
// but no longer than 5/4 of the previous 'normal' period
efitick_t maxAllowedPeriod = 5 * allowedPeriod / 4 ;
2023-05-30 22:41:20 -07:00
2018-04-25 23:11:51 -07:00
// above all, check if the signal comes not too early
if ( currentPeriod > = minAllowedPeriod ) {
// now we store this period as a reference for the next time,
// BUT we store only 'normal' periods, and ignore too long periods (i.e. gaps)
if ( ! isGapExpected & & ( maxAllowedPeriod = = 0 | | currentPeriod < = maxAllowedPeriod ) ) {
accumSignalPrevPeriods [ signal ] = currentPeriod ;
}
// reset accumulator
accumSignalPeriods [ signal ] = 0 ;
return true ;
}
// all premature or extra-long events are ignored - treated as interference
return false ;
}
2022-05-28 06:01:45 -07:00
void TriggerCentral : : decodeMapCam ( efitick_t timestamp , float currentPhase ) {
2023-08-09 02:49:06 -07:00
isDecodingMapCam = engineConfiguration - > vvtMode [ 0 ] = = VVT_MAP_V_TWIN & &
Sensor : : getOrZero ( SensorType : : Rpm ) < engineConfiguration - > cranking . rpm ;
if ( isDecodingMapCam ) {
2022-05-28 06:01:45 -07:00
// 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.
auto toothAngle360 = currentPhase ;
while ( toothAngle360 > = 360 ) {
toothAngle360 - = 360 ;
}
if ( mapCamPrevToothAngle < engineConfiguration - > mapCamDetectionAnglePosition & & toothAngle360 > engineConfiguration - > mapCamDetectionAnglePosition ) {
// we are somewhere close to 'mapCamDetectionAnglePosition'
// warning: hack hack hack
float map = engine - > outputChannels . instantMAPValue ;
// Compute diff against the last time we were here
float diff = map - mapCamPrevCycleValue ;
mapCamPrevCycleValue = map ;
if ( diff > 0 ) {
mapVvt_map_peak + + ;
2022-09-13 23:06:52 -07:00
int revolutionCounter = getTriggerCentral ( ) - > triggerState . getCrankSynchronizationCounter ( ) ;
2022-05-28 06:01:45 -07:00
mapVvt_MAP_AT_CYCLE_COUNT = revolutionCounter - prevChangeAtCycle ;
prevChangeAtCycle = revolutionCounter ;
2022-09-10 23:57:35 -07:00
hwHandleVvtCamSignal ( TriggerValue : : RISE , timestamp , /*index*/ 0 ) ;
hwHandleVvtCamSignal ( TriggerValue : : FALL , timestamp , /*index*/ 0 ) ;
2022-05-28 06:01:45 -07:00
# if EFI_UNIT_TEST
// hack? feature? existing unit test relies on VVT phase available right away
// but current implementation which is based on periodicFastCallback would only make result available on NEXT tooth
2022-10-04 17:36:03 -07:00
getLimpManager ( ) - > onFastCallback ( ) ;
2022-05-28 06:01:45 -07:00
# endif // EFI_UNIT_TEST
}
mapVvt_MAP_AT_SPECIAL_POINT = map ;
mapVvt_MAP_AT_DIFF = diff ;
}
mapCamPrevToothAngle = toothAngle360 ;
}
}
2023-01-10 13:07:17 -08:00
bool TriggerCentral : : isToothExpectedNow ( efitick_t timestamp ) {
// Check that the expected next phase (from the last tooth) is close to the actual current phase:
// basically, check that the tooth width is correct
auto estimatedCurrentPhase = getCurrentEnginePhase ( timestamp ) ;
auto lastToothPhase = m_lastToothPhaseFromSyncPoint ;
if ( expectedNextPhase & & estimatedCurrentPhase ) {
float angleError = expectedNextPhase . Value - estimatedCurrentPhase . Value ;
// Wrap around correctly at the end of the cycle
float cycle = getEngineState ( ) - > engineCycle ;
if ( angleError < - cycle / 2 ) {
angleError + = cycle ;
}
triggerToothAngleError = angleError ;
// Only perform checks if engine is spinning quickly
// All kinds of garbage happens while cranking
if ( Sensor : : getOrZero ( SensorType : : Rpm ) > 1000 ) {
// Now compute how close we are to the last tooth decoded
float angleSinceLastTooth = estimatedCurrentPhase . Value - lastToothPhase ;
if ( angleSinceLastTooth < 0.5f ) {
// This tooth came impossibly early, ignore it
// This rejects things like doubled edges, for example:
// |-| |----------------
// | | |
// ____________| |_|
// 1 2
// #1 will be decoded
// #2 will be ignored
// We're not sure which edge was the "real" one, but they were close enough
// together that it doesn't really matter.
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_PRIMARY_DOUBLED_EDGE , " doubled trigger edge after %.2f deg at #%d " , angleSinceLastTooth , triggerState . currentCycle . current_index ) ;
2023-01-10 13:07:17 -08:00
return false ;
}
// Absolute error from last tooth
float absError = absF ( angleError ) ;
float isRpmEnough = Sensor : : getOrZero ( SensorType : : Rpm ) > 1000 ;
// TODO: configurable threshold
if ( isRpmEnough & & absError > 10 & & absError < 180 ) {
// This tooth came at a very unexpected time, ignore it
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_PRIMARY_BAD_TOOTH_TIMING , " tooth #%d error of %.1f " , triggerState . currentCycle . current_index , angleError ) ;
2023-01-10 13:07:17 -08:00
// TODO: this causes issues with some real engine logs, should it?
// return false;
}
}
} else {
triggerToothAngleError = 0 ;
}
// We aren't ready to reject unexpected teeth, so accept this tooth
return true ;
}
2024-07-27 09:36:35 -07:00
PUBLIC_API_WEAK bool boardAllowTriggerActions ( ) { return true ; }
2024-03-29 12:48:16 -07:00
2024-05-07 08:39:06 -07:00
angle_t TriggerCentral : : findNextTriggerToothAngle ( int p_currentToothIndex ) {
int currentToothIndex = p_currentToothIndex ;
// TODO: is this logic to compute next trigger tooth angle correct?
2024-05-12 08:12:48 -07:00
angle_t nextToothAngle = 0 ;
2024-05-07 08:39:06 -07:00
int loopAllowance = 2 * engineCycleEventCount + 1000 ;
do {
// I don't love this.
currentToothIndex = ( currentToothIndex + 1 ) % engineCycleEventCount ;
2024-05-12 08:12:48 -07:00
nextToothAngle = getTriggerCentral ( ) - > triggerFormDetails . eventAngles [ currentToothIndex ] - tdcPosition ( ) ;
wrapAngle ( nextToothAngle , " nextEnginePhase " , ObdCode : : CUSTOM_ERR_6555 ) ;
} while ( nextToothAngle = = currentEngineDecodedPhase & & - - loopAllowance > 0 ) ; // '==' for float works here since both values come from 'eventAngles' array
if ( nextToothAngle ! = 0 & & loopAllowance = = 0 ) {
// HW CI fails here, looks like we sometimes change trigger while still handling it?
firmwareError ( ObdCode : : CUSTOM_ERR_TRIGGER_ZERO , " handleShaftSignal unexpected loop end %d %d %f %f " , p_currentToothIndex , engineCycleEventCount , nextToothAngle , currentEngineDecodedPhase ) ;
2024-05-07 08:39:06 -07:00
}
2024-05-12 08:12:48 -07:00
return nextToothAngle ;
2024-05-07 08:39:06 -07:00
}
2020-07-30 16:24:55 -07:00
/**
* This method is NOT invoked for VR falls .
*/
2021-11-16 01:15:29 -08:00
void TriggerCentral : : handleShaftSignal ( trigger_event_e signal , efitick_t timestamp ) {
2017-03-01 19:37:10 -08:00
if ( triggerShape . shapeDefinitionError ) {
2017-02-23 17:24:06 -08:00
// trigger is broken, we cannot do anything here
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_ERR_UNEXPECTED_SHAFT_EVENT , " Shaft event while trigger is mis-configured " ) ;
2019-08-07 17:13:30 -07:00
// magic value to indicate a problem
hwEventCounters [ 0 ] = 155 ;
2017-02-23 17:24:06 -08:00
return ;
}
2018-04-25 23:11:51 -07:00
// This code gathers some statistics on signals and compares accumulated periods to filter interference
2021-11-17 00:54:21 -08:00
if ( engineConfiguration - > useNoiselessTriggerDecoder ) {
2021-11-16 01:15:29 -08:00
if ( ! noiseFilter . noiseFilter ( timestamp , & triggerState , signal ) ) {
2018-04-25 23:11:51 -07:00
return ;
}
2022-09-25 15:49:54 -07:00
if ( ! isUsefulSignal ( signal , triggerShape ) ) {
2018-04-25 23:11:51 -07:00
return ;
}
}
2023-01-10 13:07:17 -08:00
if ( ! isToothExpectedNow ( timestamp ) ) {
triggerIgnoredToothCount + + ;
return ;
}
2022-09-13 23:24:41 -07:00
isSpinningJustForWatchdog = true ;
2015-07-10 06:01:56 -07:00
2024-03-29 16:53:39 -07:00
# if EFI_HD_ACR
2023-11-12 22:08:56 -08:00
bool firstEventInAWhile = m_lastEventTimer . hasElapsedSec ( 1 ) ;
if ( firstEventInAWhile ) {
// let's open that valve on first sign of movement
2023-11-13 14:23:32 -08:00
engine - > module < HarleyAcr > ( ) - > updateAcr ( ) ;
2023-11-12 22:08:56 -08:00
}
2024-03-29 16:53:39 -07:00
# endif // EFI_HD_ACR
if ( boardAllowTriggerActions ( ) ) {
m_lastEventTimer . reset ( timestamp ) ;
}
2020-12-03 08:13:45 -08:00
2015-07-10 06:01:56 -07:00
int eventIndex = ( int ) signal ;
2023-04-11 17:01:34 -07:00
efiAssertVoid ( ObdCode : : CUSTOM_TRIGGER_EVENT_TYPE , eventIndex > = 0 & & eventIndex < HW_EVENT_TYPES , " signal type " ) ;
2015-07-10 06:01:56 -07:00
hwEventCounters [ eventIndex ] + + ;
2022-05-28 06:01:45 -07:00
// Decode the trigger!
auto decodeResult = triggerState . decodeTriggerEvent (
2022-03-21 17:39:47 -07:00
" trigger " ,
triggerShape ,
2020-08-23 22:21:42 -07:00
engine ,
2022-09-13 22:53:17 -07:00
primaryTriggerConfiguration ,
2020-08-23 23:01:50 -07:00
signal , timestamp ) ;
2015-07-10 06:01:56 -07:00
2022-05-28 06:01:45 -07:00
// Don't propagate state if we don't know where we are
if ( decodeResult ) {
ScopePerf perf ( PE : : ShaftPositionListeners ) ;
2015-07-10 06:01:56 -07:00
2022-05-28 06:01:45 -07:00
/**
* 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 .
*/
2022-09-04 22:16:24 -07:00
int crankDivider = getCrankDivider ( triggerShape . getWheelOperationMode ( ) ) ;
2022-09-07 19:24:28 -07:00
int crankInternalIndex = triggerState . getCrankSynchronizationCounter ( ) % crankDivider ;
2022-05-29 10:49:00 -07:00
int triggerIndexForListeners = decodeResult . Value . CurrentIndex + ( crankInternalIndex * triggerShape . getSize ( ) ) ;
2015-07-15 17:01:33 -07:00
2022-09-25 15:49:54 -07:00
reportEventToWaveChart ( signal , triggerIndexForListeners , triggerShape . useOnlyRisingEdges ) ;
2022-05-28 06:01:45 -07:00
2022-08-12 05:08:23 -07:00
// Look up this tooth's angle from the sync point. If this tooth is the sync point, we'll get 0 here.
2022-09-13 23:06:52 -07:00
auto currentPhaseFromSyncPoint = getTriggerCentral ( ) - > triggerFormDetails . eventAngles [ triggerIndexForListeners ] ;
2022-08-12 05:08:23 -07:00
2022-08-31 21:46:45 -07:00
// Adjust so currentPhase is in engine-space angle, not trigger-space angle
2023-04-11 17:01:34 -07:00
currentEngineDecodedPhase = wrapAngleMethod ( currentPhaseFromSyncPoint - tdcPosition ( ) , " currentEnginePhase " , ObdCode : : CUSTOM_ERR_6555 ) ;
2019-10-13 13:14:08 -07:00
2022-09-23 20:49:28 -07:00
// Record precise time and phase of the engine. This is used for VVT decode, and to check that the
// trigger pattern selected matches reality (ie, we check the next tooth is where we think it should be)
2022-08-12 05:08:23 -07:00
{
// under lock to avoid mismatched tooth phase and time
chibios_rt : : CriticalSectionLocker csl ;
m_lastToothTimer . reset ( timestamp ) ;
m_lastToothPhaseFromSyncPoint = currentPhaseFromSyncPoint ;
}
2019-04-12 19:07:03 -07:00
# if TRIGGER_EXTREME_LOGGING
2024-04-29 15:25:43 -07:00
efiPrintf ( " trigger %d %d %d " , triggerIndexForListeners , getRevolutionCounter ( ) , time2print ( getTimeNowUs ( ) ) ) ;
2020-07-20 10:38:33 -07:00
# endif /* TRIGGER_EXTREME_LOGGING */
2016-10-31 17:02:09 -07:00
2022-05-28 06:01:45 -07:00
// Update engine RPM
2021-11-16 01:15:29 -08:00
rpmShaftPositionCallback ( signal , triggerIndexForListeners , timestamp ) ;
2020-10-03 22:43:02 -07:00
2022-05-28 06:01:45 -07:00
// Schedule the TDC mark
2021-11-16 01:15:29 -08:00
tdcMarkCallback ( triggerIndexForListeners , timestamp ) ;
2020-10-03 22:43:02 -07:00
# if !EFI_UNIT_TEST
2020-10-17 05:00:11 -07:00
# if EFI_MAP_AVERAGING
2021-11-16 01:15:29 -08:00
mapAveragingTriggerCallback ( triggerIndexForListeners , timestamp ) ;
2020-10-17 05:00:11 -07:00
# endif /* EFI_MAP_AVERAGING */
2020-10-03 22:43:02 -07:00
# endif /* EFI_UNIT_TEST */
2020-10-17 05:00:11 -07:00
# if EFI_LOGIC_ANALYZER
2021-11-16 01:15:29 -08:00
waTriggerEventListener ( signal , triggerIndexForListeners , timestamp ) ;
2020-10-17 05:00:11 -07:00
# endif
2020-10-03 22:43:02 -07:00
2024-05-07 08:39:06 -07:00
angle_t nextPhase = findNextTriggerToothAngle ( triggerIndexForListeners ) ;
2022-06-24 14:43:23 -07:00
2023-01-10 13:07:17 -08:00
float expectNextPhase = nextPhase + tdcPosition ( ) ;
2023-04-11 17:01:34 -07:00
wrapAngle ( expectNextPhase , " nextEnginePhase " , ObdCode : : CUSTOM_ERR_6555 ) ;
2023-01-10 13:07:17 -08:00
expectedNextPhase = expectNextPhase ;
2022-08-31 20:49:38 -07:00
# if EFI_CDM_INTEGRATION
2023-01-10 13:07:17 -08:00
if ( trgEventIndex = = 0 & & isBrainPinValid ( engineConfiguration - > cdmInputPin ) ) {
int cdmKnockValue = getCurrentCdmValue ( getTriggerCentral ( ) - > triggerState . getCrankSynchronizationCounter ( ) ) ;
engine - > knockLogic ( cdmKnockValue ) ;
}
2022-08-31 20:49:38 -07:00
# endif /* EFI_CDM_INTEGRATION */
2023-01-10 13:07:17 -08:00
if ( engine - > rpmCalculator . getCachedRpm ( ) > 0 & & triggerIndexForListeners = = 0 ) {
2024-08-01 21:45:54 -07:00
engine - > module < TpsAccelEnrichment > ( ) - > onEngineCycleTps ( ) ;
2023-01-10 13:07:17 -08:00
}
2022-09-15 21:06:57 -07:00
2022-05-28 06:01:45 -07:00
// Handle ignition and injection
2022-10-08 20:13:14 -07:00
mainTriggerCallback ( triggerIndexForListeners , timestamp , currentEngineDecodedPhase , nextPhase ) ;
2021-11-05 17:02:15 -07:00
2022-05-28 06:01:45 -07:00
// Decode the MAP based "cam" sensor
2022-10-08 20:13:14 -07:00
decodeMapCam ( timestamp , currentEngineDecodedPhase ) ;
2022-05-28 06:01:45 -07:00
} else {
2022-06-24 14:43:23 -07:00
// We don't have sync, but report to the wave chart anyway as index 0.
2022-09-25 15:49:54 -07:00
reportEventToWaveChart ( signal , 0 , triggerShape . useOnlyRisingEdges ) ;
2023-01-10 13:07:17 -08:00
expectedNextPhase = unexpected ;
2015-07-10 06:01:56 -07:00
}
}
2021-11-15 04:02:34 -08:00
static void triggerShapeInfo ( ) {
2019-04-12 19:07:03 -07:00
# if EFI_PROD_CODE || EFI_SIMULATOR
2022-09-13 23:06:52 -07:00
TriggerWaveform * shape = & getTriggerCentral ( ) - > triggerShape ;
TriggerFormDetails * triggerFormDetails = & getTriggerCentral ( ) - > triggerFormDetails ;
2022-09-23 17:39:41 -07:00
efiPrintf ( " syncEdge=%s " , getSyncEdge ( TRIGGER_WAVEFORM ( syncEdge ) ) ) ;
2023-09-09 16:53:18 -07:00
efiPrintf ( " gap from %.2f to %.2f " , TRIGGER_WAVEFORM ( synchronizationRatioFrom [ 0 ] ) , TRIGGER_WAVEFORM ( synchronizationRatioTo [ 0 ] ) ) ;
2015-07-10 06:01:56 -07:00
2020-08-24 21:59:07 -07:00
for ( size_t i = 0 ; i < shape - > getSize ( ) ; i + + ) {
2021-04-21 09:53:13 -07:00
efiPrintf ( " event %d %.2f " , i , triggerFormDetails - > eventAngles [ i ] ) ;
2015-07-10 06:01:56 -07:00
}
# endif
}
2019-04-12 19:07:03 -07:00
# if EFI_PROD_CODE
2023-10-26 13:06:50 -07:00
extern PwmConfig triggerEmulatorSignals [ NUM_EMULATOR_CHANNELS ] ;
2015-07-10 06:01:56 -07:00
# endif /* #if EFI_PROD_CODE */
void triggerInfo ( void ) {
2019-04-12 19:07:03 -07:00
# if EFI_PROD_CODE || EFI_SIMULATOR
2015-07-10 06:01:56 -07:00
2022-09-13 23:06:52 -07:00
TriggerCentral * tc = getTriggerCentral ( ) ;
TriggerWaveform * ts = & tc - > triggerShape ;
2015-07-10 06:01:56 -07:00
2019-08-06 20:56:35 -07:00
# if (HAL_TRIGGER_USE_PAL == TRUE) && (PAL_USE_CALLBACKS == TRUE)
2022-09-13 23:06:52 -07:00
efiPrintf ( " trigger PAL mode %d " , tc - > hwTriggerInputEnabled ) ;
2019-08-06 20:56:35 -07:00
# else
2019-08-06 19:17:18 -07:00
# endif /* HAL_TRIGGER_USE_PAL */
2022-11-08 18:48:39 -08:00
efiPrintf ( " Template %s (%d) trigger %s (%d) syncEdge=%s tdcOffset=%.2f " ,
2024-06-10 18:05:42 -07:00
getEngine_type_e ( engineConfiguration - > engineType ) ,
( int ) engineConfiguration - > engineType ,
getTrigger_type_e ( engineConfiguration - > trigger . type ) ,
( int ) engineConfiguration - > trigger . type ,
2022-11-08 18:48:39 -08:00
getSyncEdge ( TRIGGER_WAVEFORM ( syncEdge ) ) , TRIGGER_WAVEFORM ( tdcPosition ) ) ;
2015-07-10 06:01:56 -07:00
2023-05-31 22:56:40 -07:00
if ( engineConfiguration - > trigger . type = = trigger_type_e : : TT_TOOTHED_WHEEL ) {
2021-04-21 09:53:13 -07:00
efiPrintf ( " total %d/skipped %d " , engineConfiguration - > trigger . customTotalToothCount ,
2015-07-10 06:01:56 -07:00
engineConfiguration - > trigger . customSkippedToothCount ) ;
}
2022-09-13 23:06:52 -07:00
efiPrintf ( " trigger#1 event counters up=%d/down=%d " , tc - > getHwEventCounter ( 0 ) ,
tc - > getHwEventCounter ( 1 ) ) ;
2015-07-10 06:01:56 -07:00
2017-03-01 19:18:25 -08:00
if ( ts - > needSecondTriggerInput ) {
2022-09-13 23:06:52 -07:00
efiPrintf ( " trigger#2 event counters up=%d/down=%d " , tc - > getHwEventCounter ( 2 ) ,
tc - > getHwEventCounter ( 3 ) ) ;
2015-07-10 06:01:56 -07:00
}
2022-09-11 00:46:50 -07:00
efiPrintf ( " expected cycle events %d/%d " ,
TRIGGER_WAVEFORM ( getExpectedEventCount ( TriggerWheel : : T_PRIMARY ) ) ,
TRIGGER_WAVEFORM ( getExpectedEventCount ( TriggerWheel : : T_SECONDARY ) ) ) ;
2015-07-10 06:01:56 -07:00
2024-06-10 00:51:14 -07:00
efiPrintf ( " trigger type=%d/need2ndChannel=%s " , ( int ) engineConfiguration - > trigger . type ,
2019-12-07 22:09:39 -08:00
boolToString ( TRIGGER_WAVEFORM ( needSecondTriggerInput ) ) ) ;
2015-07-10 06:01:56 -07:00
2022-09-13 23:06:52 -07:00
2024-06-10 00:51:14 -07:00
efiPrintf ( " synchronizationNeeded=%s/isError=%s/total errors=%lu ord_err=%lu/total revolutions=%d/self=%s " ,
2015-07-10 06:01:56 -07:00
boolToString ( ts - > isSynchronizationNeeded ) ,
2022-09-13 23:06:52 -07:00
boolToString ( tc - > isTriggerDecoderError ( ) ) ,
tc - > triggerState . totalTriggerErrorCounter ,
tc - > triggerState . orderingErrorCounter ,
tc - > triggerState . getCrankSynchronizationCounter ( ) ,
boolToString ( tc - > directSelfStimulation ) ) ;
2015-07-10 06:01:56 -07:00
2019-12-07 22:09:39 -08:00
if ( TRIGGER_WAVEFORM ( isSynchronizationNeeded ) ) {
2023-09-09 16:53:18 -07:00
efiPrintf ( " gap from %.2f to %.2f " , TRIGGER_WAVEFORM ( synchronizationRatioFrom [ 0 ] ) , TRIGGER_WAVEFORM ( synchronizationRatioTo [ 0 ] ) ) ;
2015-07-10 06:01:56 -07:00
}
2017-05-19 18:52:10 -07:00
# endif /* EFI_PROD_CODE || EFI_SIMULATOR */
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
# if EFI_PROD_CODE
2021-10-23 16:01:31 -07:00
2021-11-17 00:54:21 -08:00
efiPrintf ( " primary trigger input: %s " , hwPortname ( engineConfiguration - > triggerInputPins [ 0 ] ) ) ;
2021-04-21 09:53:13 -07:00
efiPrintf ( " primary trigger simulator: %s %s freq=%d " ,
2021-11-17 00:54:21 -08:00
hwPortname ( engineConfiguration - > triggerSimulatorPins [ 0 ] ) ,
getPin_output_mode_e ( engineConfiguration - > triggerSimulatorPinModes [ 0 ] ) ,
2023-03-27 01:13:04 -07:00
engineConfiguration - > triggerSimulatorRpm ) ;
2015-07-10 06:01:56 -07:00
2017-03-01 19:18:25 -08:00
if ( ts - > needSecondTriggerInput ) {
2021-11-17 00:54:21 -08:00
efiPrintf ( " secondary trigger input: %s " , hwPortname ( engineConfiguration - > triggerInputPins [ 1 ] ) ) ;
2019-04-12 19:07:03 -07:00
# if EFI_EMULATE_POSITION_SENSORS
2021-04-21 09:53:13 -07:00
efiPrintf ( " secondary trigger simulator: %s %s phase=%d " ,
2021-11-17 00:54:21 -08:00
hwPortname ( engineConfiguration - > triggerSimulatorPins [ 1 ] ) ,
2023-10-26 13:06:50 -07:00
getPin_output_mode_e ( engineConfiguration - > triggerSimulatorPinModes [ 1 ] ) , triggerEmulatorSignals [ 0 ] . safe . phaseIndex ) ;
2015-07-10 06:01:56 -07:00
# endif /* EFI_EMULATE_POSITION_SENSORS */
}
2021-10-28 13:46:54 -07:00
for ( int camInputIndex = 0 ; camInputIndex < CAM_INPUTS_COUNT ; camInputIndex + + ) {
if ( isBrainPinValid ( engineConfiguration - > camInputs [ camInputIndex ] ) ) {
int camLogicalIndex = camInputIndex % CAMS_PER_BANK ;
efiPrintf ( " VVT input: %s mode %s " , hwPortname ( engineConfiguration - > camInputs [ camInputIndex ] ) ,
getVvt_mode_e ( engineConfiguration - > vvtMode [ camLogicalIndex ] ) ) ;
efiPrintf ( " VVT %d event counters: %d/%d " ,
camInputIndex ,
2022-09-13 23:06:52 -07:00
tc - > vvtEventRiseCounter [ camInputIndex ] , tc - > vvtEventFallCounter [ camInputIndex ] ) ;
2021-10-28 13:46:54 -07:00
}
}
2021-11-17 00:54:21 -08:00
efiPrintf ( " primary logic input: %s " , hwPortname ( engineConfiguration - > logicAnalyzerPins [ 0 ] ) ) ;
efiPrintf ( " secondary logic input: %s " , hwPortname ( engineConfiguration - > logicAnalyzerPins [ 1 ] ) ) ;
2015-07-10 06:01:56 -07:00
2024-06-10 00:51:14 -07:00
efiPrintf ( " totalTriggerHandlerMaxTime=%lu " , triggerMaxDuration ) ;
2015-07-10 06:01:56 -07:00
# endif /* EFI_PROD_CODE */
2022-06-17 19:10:48 -07:00
# if EFI_ENGINE_SNIFFER
efiPrintf ( " engine sniffer current size=%d " , waveChart . getSize ( ) ) ;
# endif /* EFI_ENGINE_SNIFFER */
2015-07-10 06:01:56 -07:00
}
static void resetRunningTriggerCounters ( ) {
2019-04-12 19:07:03 -07:00
# if !EFI_UNIT_TEST
2022-09-13 23:24:41 -07:00
getTriggerCentral ( ) - > resetCounters ( ) ;
2015-07-10 06:01:56 -07:00
triggerInfo ( ) ;
# endif
}
2021-11-16 01:15:29 -08:00
void onConfigurationChangeTriggerCallback ( ) {
2019-07-12 18:13:24 -07:00
bool changed = false ;
2021-07-03 09:26:31 -07:00
// todo: how do we static_assert here?
2023-09-05 18:28:39 -07:00
criticalAssertVoid ( efi : : size ( engineConfiguration - > camInputs ) = = efi : : size ( engineConfiguration - > vvtOffsets ) , " sizes " ) ;
2021-07-03 09:26:31 -07:00
2021-11-17 00:54:21 -08:00
for ( size_t camIndex = 0 ; camIndex < efi : : size ( engineConfiguration - > camInputs ) ; camIndex + + ) {
2021-07-03 09:26:31 -07:00
changed | = isConfigurationChanged ( camInputs [ camIndex ] ) ;
changed | = isConfigurationChanged ( vvtOffsets [ camIndex ] ) ;
2019-07-12 18:13:24 -07:00
}
2021-11-17 00:54:21 -08:00
for ( size_t i = 0 ; i < efi : : size ( engineConfiguration - > triggerGapOverrideFrom ) ; i + + ) {
2021-10-30 07:45:32 -07:00
changed | = isConfigurationChanged ( triggerGapOverrideFrom [ i ] ) ;
changed | = isConfigurationChanged ( triggerGapOverrideTo [ i ] ) ;
2021-05-23 17:52:18 -07:00
}
2021-11-17 00:54:21 -08:00
for ( size_t i = 0 ; i < efi : : size ( engineConfiguration - > triggerInputPins ) ; i + + ) {
2021-06-25 16:38:42 -07:00
changed | = isConfigurationChanged ( triggerInputPins [ i ] ) ;
2024-04-04 08:32:42 -07:00
Gpio pin = engineConfiguration - > camInputs [ i ] ;
if ( engineConfiguration - > vvtMode [ 0 ] = = VVT_MAP_V_TWIN & & isBrainPinValid ( pin ) ) {
criticalError ( " Please no physical sensors in CAM by MAP mode index=%d %s " , i , hwPortname ( pin ) ) ;
2023-11-13 13:55:17 -08:00
}
2021-06-25 16:38:42 -07:00
}
2021-11-17 00:54:21 -08:00
for ( size_t i = 0 ; i < efi : : size ( engineConfiguration - > vvtMode ) ; i + + ) {
2021-07-03 09:42:07 -07:00
changed | = isConfigurationChanged ( vvtMode [ i ] ) ;
}
2021-06-25 16:38:42 -07:00
changed | = isConfigurationChanged ( trigger . type ) ;
2022-04-02 22:11:53 -07:00
changed | = isConfigurationChanged ( skippedWheelOnCam ) ;
changed | = isConfigurationChanged ( twoStroke ) ;
2021-06-25 16:38:42 -07:00
changed | = isConfigurationChanged ( globalTriggerAngleOffset ) ;
changed | = isConfigurationChanged ( trigger . customTotalToothCount ) ;
changed | = isConfigurationChanged ( trigger . customSkippedToothCount ) ;
changed | = isConfigurationChanged ( overrideTriggerGaps ) ;
2023-11-30 16:24:14 -08:00
changed | = isConfigurationChanged ( gapTrackingLengthOverride ) ;
changed | = isConfigurationChanged ( overrideVvtTriggerGaps ) ;
changed | = isConfigurationChanged ( gapVvtTrackingLengthOverride ) ;
2021-06-25 16:38:42 -07:00
2018-02-03 10:08:11 -08:00
if ( changed ) {
2019-04-12 19:07:03 -07:00
# if EFI_ENGINE_CONTROL
2022-04-02 16:27:18 -07:00
engine - > updateTriggerWaveform ( ) ;
2022-09-15 19:12:49 -07:00
getTriggerCentral ( ) - > noiseFilter . resetAccumSignalData ( ) ;
2018-02-03 17:43:31 -08:00
# endif
2018-02-03 10:08:11 -08:00
}
2018-03-04 17:43:38 -08:00
# if EFI_DEFAILED_LOGGING
2021-11-15 17:22:05 -08:00
efiPrintf ( " isTriggerConfigChanged=%d " , triggerConfigChanged ) ;
2018-03-04 17:43:38 -08:00
# endif /* EFI_DEFAILED_LOGGING */
2018-02-04 09:46:57 -08:00
// we do not want to miss two updates in a row
2022-09-15 20:07:08 -07:00
getTriggerCentral ( ) - > triggerConfigChangedOnLastConfigurationChange = getTriggerCentral ( ) - > triggerConfigChangedOnLastConfigurationChange | | changed ;
2017-06-26 11:31:10 -07:00
}
2023-11-01 09:12:50 -07:00
static void initVvtShape ( TriggerWaveform & shape , const TriggerConfiguration & p_config , TriggerDecoderBase & initState ) {
shape . initializeTriggerWaveform ( FOUR_STROKE_CAM_SENSOR , p_config . TriggerType ) ;
shape . initializeSyncPoint ( initState , p_config ) ;
2022-09-13 23:45:31 -07:00
}
2022-11-05 18:43:12 -07:00
void TriggerCentral : : validateCamVvtCounters ( ) {
// micro-optimized 'crankSynchronizationCounter % 256'
int camVvtValidationIndex = triggerState . getCrankSynchronizationCounter ( ) & 0xFF ;
if ( camVvtValidationIndex = = 0 ) {
vvtCamCounter = 0 ;
} else if ( camVvtValidationIndex = = 0xFE & & vvtCamCounter < 60 ) {
// magic logic: we expect at least 60 CAM/VVT events for each 256 trigger cycles, otherwise throw a code
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : OBD_Camshaft_Position_Sensor_Circuit_Range_Performance , " No Camshaft Position Sensor signals " ) ;
2022-11-05 18:43:12 -07:00
}
}
/**
* Calculate ' shape . triggerShapeSynchPointIndex ' value using ' TriggerDecoderBase * state '
*/
static void calculateTriggerSynchPoint (
2022-11-05 22:32:59 -07:00
const PrimaryTriggerConfiguration & primaryTriggerConfiguration ,
2022-11-05 18:43:12 -07:00
TriggerWaveform & shape ,
2022-11-05 22:32:59 -07:00
TriggerDecoderBase & initState ) {
2022-11-05 18:43:12 -07:00
# if EFI_PROD_CODE
2023-06-24 23:08:53 -07:00
efiAssertVoid ( ObdCode : : CUSTOM_TRIGGER_STACK , hasLotsOfRemainingStack ( ) , " calc s " ) ;
2022-11-05 18:43:12 -07:00
# endif
2022-11-05 22:32:59 -07:00
shape . initializeSyncPoint ( initState , primaryTriggerConfiguration ) ;
2022-11-05 18:43:12 -07:00
if ( shape . getSize ( ) > = PWM_PHASE_MAX_COUNT ) {
// todo: by the time we are here we had already modified a lot of RAM out of bounds!
2023-04-11 17:01:34 -07:00
firmwareError ( ObdCode : : CUSTOM_ERR_TRIGGER_WAVEFORM_TOO_LONG , " Trigger length above maximum: %d " , shape . getSize ( ) ) ;
2022-11-05 18:43:12 -07:00
shape . setShapeDefinitionError ( true ) ;
return ;
}
if ( shape . getSize ( ) = = 0 ) {
2023-04-11 17:01:34 -07:00
firmwareError ( ObdCode : : CUSTOM_ERR_TRIGGER_ZERO , " triggerShape size is zero " ) ;
2022-11-05 18:43:12 -07:00
}
}
2023-01-03 05:38:23 -08:00
TriggerDecoderBase initState ( " init " ) ;
2022-09-13 23:45:31 -07:00
2023-01-03 05:38:23 -08:00
void TriggerCentral : : updateWaveform ( ) {
2022-09-13 23:45:31 -07:00
// Re-read config in case it's changed
primaryTriggerConfiguration . update ( ) ;
for ( int camIndex = 0 ; camIndex < CAMS_PER_BANK ; camIndex + + ) {
vvtTriggerConfiguration [ camIndex ] . update ( ) ;
}
2023-03-02 21:21:40 -08:00
triggerShape . initializeTriggerWaveform ( lookupOperationMode ( ) , primaryTriggerConfiguration . TriggerType ) ;
2022-09-13 23:45:31 -07:00
/**
* this is only useful while troubleshooting a new trigger shape in the field
* in very VERY rare circumstances
*/
if ( engineConfiguration - > overrideTriggerGaps ) {
int gapIndex = 0 ;
2024-07-22 11:41:19 -07:00
triggerShape . gapTrackingLength = engineConfiguration - > gapTrackingLengthOverride ;
2024-02-19 14:16:57 -08:00
2022-09-13 23:45:31 -07:00
// copy however many the user wants
for ( ; gapIndex < engineConfiguration - > gapTrackingLengthOverride ; gapIndex + + ) {
float gapOverrideFrom = engineConfiguration - > triggerGapOverrideFrom [ gapIndex ] ;
float gapOverrideTo = engineConfiguration - > triggerGapOverrideTo [ gapIndex ] ;
2024-07-22 11:41:19 -07:00
triggerShape . setTriggerSynchronizationGap3 ( /*gapIndex*/ gapIndex , gapOverrideFrom , gapOverrideTo ) ;
2022-09-13 23:45:31 -07:00
}
// fill the remainder with the default gaps
for ( ; gapIndex < GAP_TRACKING_LENGTH ; gapIndex + + ) {
2023-09-09 16:53:18 -07:00
triggerShape . synchronizationRatioFrom [ gapIndex ] = NAN ;
triggerShape . synchronizationRatioTo [ gapIndex ] = NAN ;
2022-09-13 23:45:31 -07:00
}
}
if ( ! triggerShape . shapeDefinitionError ) {
2022-11-05 20:50:03 -07:00
int length = triggerShape . getLength ( ) ;
engineCycleEventCount = length ;
2023-04-11 17:01:34 -07:00
efiAssertVoid ( ObdCode : : CUSTOM_SHAPE_LEN_ZERO , length > 0 , " shapeLength=0 " ) ;
2022-11-05 20:50:03 -07:00
2022-11-05 22:32:59 -07:00
triggerErrorDetection . clear ( ) ;
2022-09-13 23:45:31 -07:00
/**
* ' 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
*/
2022-11-05 22:32:59 -07:00
calculateTriggerSynchPoint ( primaryTriggerConfiguration ,
2022-09-13 23:45:31 -07:00
triggerShape ,
initState ) ;
}
2023-11-30 14:58:22 -08:00
if ( engineConfiguration - > overrideVvtTriggerGaps ) {
int gapIndex = 0 ;
TriggerWaveform * shape = & vvtShape [ 0 ] ;
2024-07-22 11:55:52 -07:00
shape - > gapTrackingLength = engineConfiguration - > gapVvtTrackingLengthOverride ;
2023-11-30 14:58:22 -08:00
for ( ; gapIndex < engineConfiguration - > gapVvtTrackingLengthOverride ; gapIndex + + ) {
float gapOverrideFrom = engineConfiguration - > triggerVVTGapOverrideFrom [ gapIndex ] ;
float gapOverrideTo = engineConfiguration - > triggerVVTGapOverrideTo [ gapIndex ] ;
shape - > synchronizationRatioFrom [ gapIndex ] = gapOverrideFrom ;
shape - > synchronizationRatioTo [ gapIndex ] = gapOverrideTo ;
}
// fill the remainder with the default gaps
for ( ; gapIndex < VVT_TRACKING_LENGTH ; gapIndex + + ) {
shape - > synchronizationRatioFrom [ gapIndex ] = NAN ;
shape - > synchronizationRatioTo [ gapIndex ] = NAN ;
}
}
2022-09-13 23:45:31 -07:00
for ( int camIndex = 0 ; camIndex < CAMS_PER_BANK ; camIndex + + ) {
// todo: should 'vvtWithRealDecoder' be used here?
if ( engineConfiguration - > vvtMode [ camIndex ] ! = VVT_INACTIVE ) {
initVvtShape (
vvtShape [ camIndex ] ,
vvtTriggerConfiguration [ camIndex ] ,
initState
) ;
}
}
// This is not the right place for this, but further refactoring has to happen before it can get moved.
triggerState . setNeedsDisambiguation ( engine - > triggerCentral . triggerShape . needsDisambiguation ( ) ) ;
}
2017-07-05 19:22:24 -07:00
/**
* @ returns true if configuration just changed , and if that change has affected trigger
*/
2021-11-16 01:15:29 -08:00
bool TriggerCentral : : checkIfTriggerConfigChanged ( ) {
2022-09-15 20:07:08 -07:00
// we want to make sure that configuration has changed AND that change has changed trigger specifically
bool result = triggerVersion . isOld ( engine - > getGlobalConfigurationVersion ( ) ) & & triggerConfigChangedOnLastConfigurationChange ;
triggerConfigChangedOnLastConfigurationChange = false ; // whoever has called the method is supposed to react to changes
2018-02-04 09:46:57 -08:00
return result ;
2017-06-26 11:31:10 -07:00
}
2022-09-15 20:07:08 -07:00
# if EFI_UNIT_TEST
2021-11-16 01:15:29 -08:00
bool TriggerCentral : : isTriggerConfigChanged ( ) {
2022-09-15 20:07:08 -07:00
return triggerConfigChangedOnLastConfigurationChange ;
2018-03-10 17:58:51 -08:00
}
2022-09-15 20:07:08 -07:00
# endif // EFI_UNIT_TEST
2018-03-10 17:58:51 -08:00
2021-11-16 01:15:29 -08:00
void validateTriggerInputs ( ) {
2022-10-22 05:39:55 -07:00
if ( ! isBrainPinValid ( engineConfiguration - > triggerInputPins [ 0 ] ) & & isBrainPinValid ( engineConfiguration - > triggerInputPins [ 1 ] ) ) {
2024-04-26 20:38:10 -07:00
criticalError ( " First trigger channel not configured while second one is. " ) ;
2021-08-03 19:14:22 -07:00
}
2022-10-22 05:39:55 -07:00
if ( ! isBrainPinValid ( engineConfiguration - > camInputs [ 0 ] ) & & isBrainPinValid ( engineConfiguration - > camInputs [ 2 ] ) ) {
2023-08-20 19:23:44 -07:00
criticalError ( " First bank cam input is required if second bank specified " ) ;
2021-08-03 19:14:22 -07:00
}
}
2021-04-21 11:28:48 -07:00
void initTriggerCentral ( ) {
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
# if EFI_ENGINE_SNIFFER
2015-07-10 06:01:56 -07:00
initWaveChart ( & waveChart ) ;
2015-07-15 18:01:45 -07:00
# endif /* EFI_ENGINE_SNIFFER */
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
# if EFI_PROD_CODE || EFI_SIMULATOR
2019-07-14 12:22:02 -07:00
addConsoleAction ( CMD_TRIGGERINFO , triggerInfo ) ;
2015-07-10 06:01:56 -07:00
addConsoleAction ( " trigger_shape_info " , triggerShapeInfo ) ;
addConsoleAction ( " reset_trigger " , resetRunningTriggerCounters ) ;
2020-08-23 23:01:50 -07:00
# endif // EFI_PROD_CODE || EFI_SIMULATOR
2015-07-10 06:01:56 -07:00
}
2020-08-23 23:01:50 -07:00
/**
* @ return TRUE is something is wrong with trigger decoding
*/
2021-11-16 01:15:29 -08:00
bool TriggerCentral : : isTriggerDecoderError ( ) {
2022-09-13 23:35:55 -07:00
return triggerErrorDetection . sum ( 6 ) > 4 ;
2020-08-23 23:01:50 -07:00
}
# endif // EFI_SHAFT_POSITION_INPUT