2015-07-10 06:01:56 -07:00
/**
* @ file trigger_decoder . cpp
*
* @ date Dec 24 , 2013
2020-01-07 21:02:40 -08:00
* @ author Andrey Belomutskiy , ( c ) 2012 - 2020
2015-07-10 06:01:56 -07:00
*
2019-09-03 20:35:49 -07:00
*
*
* enable trigger_details
2020-04-10 10:19:54 -07:00
* DBG_TRIGGER_COUNTERS = 5
* set debug_mode 5
2019-09-03 20:35:49 -07:00
*
2015-07-10 06:01:56 -07:00
* This file is part of rusEfi - see http : //rusefi.com
*
* rusEfi is free software ; you can redistribute it and / or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation ; either
* version 3 of the License , or ( at your option ) any later version .
*
* rusEfi is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along with this program .
* If not , see < http : //www.gnu.org/licenses/>.
*/
2022-09-15 18:45:48 -07:00
# include <rusefi/isnan.h>
# include <rusefi/math.h>
2022-09-15 19:06:16 -07:00
# include "global_shared.h"
2022-09-15 18:45:48 -07:00
# include "loggingcentral.h"
# include "error_handling.h"
2022-11-05 12:18:50 -07:00
# include "perf_trace.h"
2022-09-15 18:45:48 -07:00
# include "engine_configuration.h"
# include "trigger_central.h"
# include "trigger_decoder.h"
2022-11-05 18:43:12 -07:00
/**
* decoder depends on current RPM for error condition logic
*/
2022-09-15 18:45:48 -07:00
# include "sensor.h"
# include "engine_state.h"
# include "engine_math.h"
2022-11-05 18:43:12 -07:00
/**
* decoder uses TriggerStimulatorHelper in findTriggerZeroEventIndex
*/
2015-09-23 18:02:33 -07:00
# include "trigger_simulator.h"
2015-09-12 18:03:09 -07:00
2023-03-21 16:39:39 -07:00
# ifndef NOISE_RATIO_THRESHOLD
# define NOISE_RATIO_THRESHOLD 3000
# endif
2022-05-31 21:55:34 -07:00
TriggerDecoderBase : : TriggerDecoderBase ( const char * name )
: name ( name )
{
2023-05-24 11:28:33 -07:00
TriggerDecoderBase : : resetState ( ) ;
2019-01-31 14:55:23 -08:00
}
2022-05-10 01:41:39 -07:00
bool TriggerDecoderBase : : getShaftSynchronized ( ) {
2021-07-03 07:37:03 -07:00
return shaft_is_synchronized ;
}
2022-05-10 01:41:39 -07:00
void TriggerDecoderBase : : setShaftSynchronized ( bool value ) {
2019-08-18 12:53:38 -07:00
if ( value ) {
if ( ! shaft_is_synchronized ) {
// just got synchronized
mostRecentSyncTime = getTimeNowNt ( ) ;
}
} else {
// sync loss
mostRecentSyncTime = 0 ;
}
shaft_is_synchronized = value ;
}
2022-11-05 21:32:38 -07:00
void TriggerDecoderBase : : resetState ( ) {
2019-08-18 12:53:38 -07:00
setShaftSynchronized ( false ) ;
2019-01-31 14:55:23 -08:00
toothed_previous_time = 0 ;
memset ( toothDurations , 0 , sizeof ( toothDurations ) ) ;
2022-09-07 19:24:28 -07:00
crankSynchronizationCounter = 0 ;
2019-01-31 14:55:23 -08:00
totalTriggerErrorCounter = 0 ;
orderingErrorCounter = 0 ;
2022-05-10 13:55:28 -07:00
m_timeSinceDecodeError . init ( ) ;
2019-01-31 14:55:23 -08:00
prevSignal = SHAFT_PRIMARY_FALLING ;
startOfCycleNt = 0 ;
resetCurrentCycleState ( ) ;
totalEventCountBase = 0 ;
isFirstEvent = true ;
}
2023-03-21 16:39:39 -07:00
void TriggerDecoderBase : : setTriggerErrorState ( int errorIncrement ) {
2022-05-10 13:55:28 -07:00
m_timeSinceDecodeError . reset ( ) ;
2023-03-21 16:39:39 -07:00
totalTriggerErrorCounter + = errorIncrement ;
2020-01-26 03:28:33 -08:00
}
2022-05-10 01:41:39 -07:00
void TriggerDecoderBase : : resetCurrentCycleState ( ) {
2019-01-31 14:55:23 -08:00
memset ( currentCycle . eventCount , 0 , sizeof ( currentCycle . eventCount ) ) ;
currentCycle . current_index = 0 ;
}
2022-04-16 14:07:57 -07:00
# if EFI_SHAFT_POSITION_INPUT
2022-05-31 21:55:34 -07:00
PrimaryTriggerDecoder : : PrimaryTriggerDecoder ( const char * name )
: TriggerDecoderBase ( name )
{
2019-01-31 14:55:23 -08:00
}
2019-04-12 19:07:03 -07:00
# if ! EFI_PROD_CODE
2015-07-10 06:01:56 -07:00
bool printTriggerDebug = false ;
2020-07-19 12:47:21 -07:00
bool printTriggerTrace = false ;
2015-07-10 06:01:56 -07:00
# endif /* ! EFI_PROD_CODE */
2022-05-10 01:41:39 -07:00
void TriggerWaveform : : initializeSyncPoint ( TriggerDecoderBase & state ,
2022-05-30 16:36:47 -07:00
const TriggerConfiguration & triggerConfiguration ) {
triggerShapeSynchPointIndex = state . findTriggerZeroEventIndex ( * this , triggerConfiguration ) ;
2020-08-26 17:57:11 -07:00
}
2022-05-29 10:49:00 -07:00
void TriggerFormDetails : : prepareEventAngles ( TriggerWaveform * shape ) {
2021-07-02 16:49:00 -07:00
int triggerShapeSynchPointIndex = shape - > triggerShapeSynchPointIndex ;
if ( triggerShapeSynchPointIndex = = EFI_ERROR_CODE ) {
return ;
}
2021-11-24 19:17:29 -08:00
angle_t firstAngle = shape - > getAngle ( triggerShapeSynchPointIndex ) ;
2023-04-11 17:01:34 -07:00
assertAngleRange ( firstAngle , " firstAngle " , ObdCode : : CUSTOM_TRIGGER_SYNC_ANGLE ) ;
2018-12-25 19:47:29 -08:00
2019-02-02 22:49:41 -08:00
int riseOnlyIndex = 0 ;
2018-12-25 19:47:29 -08:00
2022-03-22 13:53:24 -07:00
size_t length = shape - > getLength ( ) ;
2020-08-25 09:45:18 -07:00
2022-05-29 10:49:00 -07:00
memset ( eventAngles , 0 , sizeof ( eventAngles ) ) ;
2020-08-24 21:59:07 -07:00
2021-07-17 20:27:20 -07:00
// this may be <length for some triggers like symmetrical crank Miata NB
2022-03-22 13:53:24 -07:00
size_t triggerShapeLength = shape - > getSize ( ) ;
2021-07-17 20:27:20 -07:00
2023-04-11 17:01:34 -07:00
assertAngleRange ( shape - > triggerShapeSynchPointIndex , " triggerShapeSynchPointIndex " , ObdCode : : CUSTOM_TRIGGER_SYNC_ANGLE2 ) ;
efiAssertVoid ( ObdCode : : CUSTOM_TRIGGER_CYCLE , getTriggerCentral ( ) - > engineCycleEventCount ! = 0 , " zero engineCycleEventCount " ) ;
2021-07-17 20:27:20 -07:00
2022-03-22 13:53:24 -07:00
for ( size_t eventIndex = 0 ; eventIndex < length ; eventIndex + + ) {
2018-12-25 19:47:29 -08:00
if ( eventIndex = = 0 ) {
// explicit check for zero to avoid issues where logical zero is not exactly zero due to float nature
2022-05-29 10:49:00 -07:00
eventAngles [ 0 ] = 0 ;
2018-12-25 19:47:29 -08:00
// this value would be used in case of front-only
2022-05-29 10:49:00 -07:00
eventAngles [ 1 ] = 0 ;
2018-12-25 19:47:29 -08:00
} else {
2021-07-17 20:27:20 -07:00
// Rotate the trigger around so that the sync point is at position 0
auto wrappedIndex = ( shape - > triggerShapeSynchPointIndex + eventIndex ) % length ;
// Compute this tooth's position within the trigger definition
// (wrap, as the trigger def may be smaller than total trigger length)
auto triggerDefinitionIndex = wrappedIndex % triggerShapeLength ;
// Compute the relative angle of this tooth to the sync point's tooth
float angle = shape - > getAngle ( wrappedIndex ) - firstAngle ;
2023-04-11 17:01:34 -07:00
efiAssertVoid ( ObdCode : : CUSTOM_TRIGGER_CYCLE , ! cisnan ( angle ) , " trgSyncNaN " ) ;
2021-07-17 20:27:20 -07:00
// Wrap the angle back in to [0, 720)
2023-04-11 17:01:34 -07:00
fixAngle ( angle , " trgSync " , ObdCode : : CUSTOM_TRIGGER_SYNC_ANGLE_RANGE ) ;
2021-07-17 20:27:20 -07:00
2022-09-25 15:49:54 -07:00
if ( shape - > useOnlyRisingEdges ) {
2023-04-11 17:01:34 -07:00
efiAssertVoid ( ObdCode : : OBD_PCM_Processor_Fault , triggerDefinitionIndex < triggerShapeLength , " trigger shape fail " ) ;
2021-07-17 20:27:20 -07:00
assertIsInBounds ( triggerDefinitionIndex , shape - > isRiseEvent , " isRise " ) ;
// In case this is a rising event, replace the following fall event with the rising as well
2019-02-02 22:49:41 -08:00
if ( shape - > isRiseEvent [ triggerDefinitionIndex ] ) {
riseOnlyIndex + = 2 ;
2022-05-29 10:49:00 -07:00
eventAngles [ riseOnlyIndex ] = angle ;
eventAngles [ riseOnlyIndex + 1 ] = angle ;
2018-12-25 19:47:29 -08:00
}
} else {
2022-05-29 10:49:00 -07:00
eventAngles [ eventIndex ] = angle ;
2018-12-25 19:47:29 -08:00
}
}
}
}
2022-05-10 01:41:39 -07:00
int64_t TriggerDecoderBase : : getTotalEventCounter ( ) const {
2018-12-25 19:47:29 -08:00
return totalEventCountBase + currentCycle . current_index ;
}
2022-09-07 19:24:28 -07:00
int TriggerDecoderBase : : getCrankSynchronizationCounter ( ) const {
return crankSynchronizationCounter ;
2018-12-25 19:47:29 -08:00
}
2022-11-05 21:32:38 -07:00
void PrimaryTriggerDecoder : : resetState ( ) {
TriggerDecoderBase : : resetState ( ) ;
2021-12-27 09:09:38 -08:00
2022-06-09 14:21:22 -07:00
resetHasFullSync ( ) ;
2021-12-27 09:09:38 -08:00
}
2018-12-25 19:47:29 -08:00
2022-05-10 01:41:39 -07:00
bool TriggerDecoderBase : : isValidIndex ( const TriggerWaveform & triggerShape ) const {
2020-10-05 11:22:59 -07:00
return currentCycle . current_index < triggerShape . getSize ( ) ;
2015-09-24 19:02:47 -07:00
}
2022-09-11 00:46:50 -07:00
static TriggerWheel eventIndex [ 4 ] = { TriggerWheel : : T_PRIMARY , TriggerWheel : : T_PRIMARY , TriggerWheel : : T_SECONDARY , TriggerWheel : : T_SECONDARY } ;
2022-09-10 23:57:35 -07:00
static TriggerValue eventType [ 4 ] = { TriggerValue : : FALL , TriggerValue : : RISE , TriggerValue : : FALL , TriggerValue : : RISE } ;
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
# if EFI_UNIT_TEST
2020-07-19 12:47:21 -07:00
# define PRINT_INC_INDEX if (printTriggerTrace) {\
2017-03-03 19:07:25 -08:00
printf ( " nextTriggerEvent index=%d \r \n " , currentCycle . current_index ) ; \
}
# else
# define PRINT_INC_INDEX {}
# endif /* EFI_UNIT_TEST */
2015-07-10 06:01:56 -07:00
# define nextTriggerEvent() \
{ \
2022-05-31 21:55:34 -07:00
if ( useOnlyRisingEdgeForTrigger ) { currentCycle . current_index + + ; } \
2015-09-08 20:01:07 -07:00
currentCycle . current_index + + ; \
2017-03-03 19:07:25 -08:00
PRINT_INC_INDEX ; \
2015-07-10 06:01:56 -07:00
}
2022-05-10 01:41:39 -07:00
int TriggerDecoderBase : : getCurrentIndex ( ) const {
2018-02-05 14:25:01 -08:00
return currentCycle . current_index ;
}
2018-02-05 14:29:16 -08:00
2022-05-10 01:41:39 -07:00
angle_t PrimaryTriggerDecoder : : syncEnginePhase ( int divider , int remainder , angle_t engineCycle ) {
2023-04-11 17:01:34 -07:00
efiAssert ( ObdCode : : OBD_PCM_Processor_Fault , remainder < divider , " syncEnginePhase " , false ) ;
2021-07-21 22:02:37 -07:00
angle_t totalShift = 0 ;
2022-09-07 19:24:28 -07:00
while ( getCrankSynchronizationCounter ( ) % divider ! = remainder ) {
2021-07-05 20:51:13 -07:00
/**
* we are here if we ' ve detected the cam sensor within the wrong crank phase
* let ' s increase the trigger event counter , that would adjust the state of
* virtual crank - based trigger
*/
2022-09-07 18:45:59 -07:00
incrementShaftSynchronizationCounter ( ) ;
2021-07-21 22:02:37 -07:00
totalShift + = engineCycle / divider ;
2021-07-05 15:28:26 -07:00
}
2021-12-30 22:21:21 -08:00
// Allow injection/ignition to happen, we've now fully sync'd the crank based on new cam information
2022-05-09 21:52:29 -07:00
m_hasSynchronizedPhase = true ;
2021-12-30 22:21:21 -08:00
2022-05-09 12:46:36 -07:00
if ( totalShift > 0 ) {
2022-08-09 17:32:39 -07:00
camResyncCounter + + ;
2022-05-09 12:46:36 -07:00
}
2021-07-21 22:02:37 -07:00
return totalShift ;
2021-07-05 15:28:26 -07:00
}
2022-09-07 18:45:59 -07:00
void TriggerDecoderBase : : incrementShaftSynchronizationCounter ( ) {
2022-09-07 19:24:28 -07:00
crankSynchronizationCounter + + ;
2018-02-05 14:29:16 -08:00
}
2022-05-10 13:55:28 -07:00
void PrimaryTriggerDecoder : : onTriggerError ( ) {
// On trigger error, we've lost full sync
2022-06-09 14:21:22 -07:00
resetHasFullSync ( ) ;
2022-05-10 13:55:28 -07:00
}
2022-09-04 06:15:24 -07:00
void PrimaryTriggerDecoder : : onNotEnoughTeeth ( int /*actual*/ , int /*expected*/ ) {
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_PRIMARY_NOT_ENOUGH_TEETH , " primary trigger error: not enough teeth between sync points: expected %d/%d got %d/%d " ,
2022-09-15 18:45:48 -07:00
getTriggerCentral ( ) - > triggerShape . getExpectedEventCount ( TriggerWheel : : T_PRIMARY ) ,
getTriggerCentral ( ) - > triggerShape . getExpectedEventCount ( TriggerWheel : : T_SECONDARY ) ,
2022-09-04 06:15:24 -07:00
currentCycle . eventCount [ 0 ] ,
currentCycle . eventCount [ 1 ] ) ;
}
void PrimaryTriggerDecoder : : onTooManyTeeth ( int /*actual*/ , int /*expected*/ ) {
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_PRIMARY_TOO_MANY_TEETH , " primary trigger error: too many teeth between sync points: expected %d/%d got %d/%d " ,
2022-09-15 18:45:48 -07:00
getTriggerCentral ( ) - > triggerShape . getExpectedEventCount ( TriggerWheel : : T_PRIMARY ) ,
getTriggerCentral ( ) - > triggerShape . getExpectedEventCount ( TriggerWheel : : T_SECONDARY ) ,
2022-09-04 06:15:24 -07:00
currentCycle . eventCount [ 0 ] ,
currentCycle . eventCount [ 1 ] ) ;
}
2022-09-10 23:16:47 -07:00
const char * getTrigger_event_e ( trigger_event_e value ) {
switch ( value ) {
case SHAFT_PRIMARY_FALLING :
return " SHAFT_PRIMARY_FALLING " ;
case SHAFT_PRIMARY_RISING :
return " SHAFT_PRIMARY_RISING " ;
case SHAFT_SECONDARY_FALLING :
return " SHAFT_SECONDARY_FALLING " ;
case SHAFT_SECONDARY_RISING :
return " SHAFT_SECONDARY_RISING " ;
}
return NULL ;
}
2022-09-10 23:57:35 -07:00
const char * getTrigger_value_e ( TriggerValue value ) {
2022-09-10 23:16:47 -07:00
switch ( value ) {
2022-09-10 23:57:35 -07:00
case TriggerValue : : FALL :
return " TriggerValue::FALL " ;
case TriggerValue : : RISE :
return " TriggerValue::RISE " ;
2022-09-10 23:16:47 -07:00
}
return NULL ;
}
2022-09-04 06:15:24 -07:00
void VvtTriggerDecoder : : onNotEnoughTeeth ( int actual , int expected ) {
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_CAM_NOT_ENOUGH_TEETH , " cam %s trigger error: not enough teeth between sync points: actual %d expected %d " , name , actual , expected ) ;
2022-09-04 06:15:24 -07:00
}
void VvtTriggerDecoder : : onTooManyTeeth ( int actual , int expected ) {
2023-04-11 17:01:34 -07:00
warning ( ObdCode : : CUSTOM_CAM_TOO_MANY_TEETH , " cam %s trigger error: too many teeth between sync points: %d > %d " , name , actual , expected ) ;
2022-09-04 06:15:24 -07:00
}
2022-05-10 01:41:39 -07:00
bool TriggerDecoderBase : : validateEventCounters ( const TriggerWaveform & triggerShape ) const {
2022-05-10 13:55:28 -07:00
// We can check if things are fine by comparing the number of events in a cycle with the expected number of event.
2020-01-26 03:35:51 -08:00
bool isDecodingError = false ;
2020-01-26 06:00:46 -08:00
for ( int i = 0 ; i < PWM_PHASE_MAX_WAVE_PER_PWM ; i + + ) {
2022-09-11 00:46:50 -07:00
isDecodingError | = ( currentCycle . eventCount [ i ] ! = triggerShape . getExpectedEventCount ( ( TriggerWheel ) i ) ) ;
2020-01-26 03:35:51 -08:00
}
2019-01-23 19:06:42 -08:00
# if EFI_UNIT_TEST
2022-05-13 15:48:26 -07:00
printf ( " validateEventCounters: isDecodingError=%d \n " , isDecodingError ) ;
if ( isDecodingError ) {
for ( int i = 0 ; i < PWM_PHASE_MAX_WAVE_PER_PWM ; i + + ) {
2022-09-11 00:46:50 -07:00
printf ( " count: cur=%d exp=%d \n " , currentCycle . eventCount [ i ] , triggerShape . getExpectedEventCount ( ( TriggerWheel ) i ) ) ;
2022-05-13 15:48:26 -07:00
}
}
2019-01-23 19:06:42 -08:00
# endif /* EFI_UNIT_TEST */
return isDecodingError ;
}
2022-05-10 01:41:39 -07:00
void TriggerDecoderBase : : onShaftSynchronization (
2021-11-20 22:01:27 -08:00
bool wasSynchronized ,
2020-08-26 14:30:13 -07:00
const efitick_t nowNt ,
2020-10-05 11:22:59 -07:00
const TriggerWaveform & triggerShape ) {
2019-01-23 19:31:16 -08:00
startOfCycleNt = nowNt ;
resetCurrentCycleState ( ) ;
2021-11-20 22:01:27 -08:00
if ( wasSynchronized ) {
2022-09-07 18:45:59 -07:00
incrementShaftSynchronizationCounter ( ) ;
2021-11-20 22:01:27 -08:00
} else {
// We have just synchronized, this is the zeroth revolution
2022-09-07 19:24:28 -07:00
crankSynchronizationCounter = 0 ;
2021-11-20 22:01:27 -08:00
}
2020-10-05 11:22:59 -07:00
totalEventCountBase + = triggerShape . getSize ( ) ;
2019-01-23 19:31:16 -08:00
2019-04-12 19:07:03 -07:00
# if EFI_UNIT_TEST
2019-01-23 19:31:16 -08:00
if ( printTriggerDebug ) {
2019-05-14 16:24:18 -07:00
printf ( " onShaftSynchronization index=%d %d \r \n " ,
2019-01-23 19:31:16 -08:00
currentCycle . current_index ,
2022-09-07 19:24:28 -07:00
crankSynchronizationCounter ) ;
2019-01-23 19:31:16 -08:00
}
# endif /* EFI_UNIT_TEST */
}
2022-09-23 17:39:41 -07:00
static bool shouldConsiderEdge ( const TriggerWaveform & triggerShape , TriggerWheel triggerWheel , TriggerValue edge ) {
if ( triggerWheel ! = TriggerWheel : : T_PRIMARY & & triggerShape . useOnlyPrimaryForSync ) {
// Non-primary events ignored
return false ;
}
switch ( triggerShape . syncEdge ) {
case SyncEdge : : Both : return true ;
2022-09-25 15:49:54 -07:00
case SyncEdge : : RiseOnly :
2022-09-23 17:39:41 -07:00
case SyncEdge : : Rise : return edge = = TriggerValue : : RISE ;
case SyncEdge : : Fall : return edge = = TriggerValue : : FALL ;
}
// how did we get here?
// assert(false)?
return false ;
}
2015-07-10 06:01:56 -07:00
/**
* @ brief Trigger decoding happens here
2020-07-30 16:24:55 -07:00
* VR falls are filtered out and some VR noise detection happens prior to invoking this method , for
* Hall this method is invoked every time we have a fall or rise on one of the trigger sensors .
2015-07-10 06:01:56 -07:00
* This method changes the state of trigger_state_s data structure according to the trigger event
2015-08-22 08:02:10 -07:00
* @ param signal type of event which just happened
* @ param nowNt current time
2015-07-10 06:01:56 -07:00
*/
2022-05-28 06:01:45 -07:00
expected < TriggerDecodeResult > TriggerDecoderBase : : decodeTriggerEvent (
2022-03-21 17:39:47 -07:00
const char * msg ,
2020-10-05 11:22:59 -07:00
const TriggerWaveform & triggerShape ,
2020-10-04 16:29:26 -07:00
TriggerStateListener * triggerStateListener ,
2020-10-05 11:22:59 -07:00
const TriggerConfiguration & triggerConfiguration ,
2020-08-23 22:21:42 -07:00
const trigger_event_e signal ,
2020-08-23 23:01:50 -07:00
const efitick_t nowNt ) {
2020-04-29 07:53:35 -07:00
ScopePerf perf ( PE : : DecodeTriggerEvent ) ;
2019-10-11 17:43:21 -07:00
2021-03-07 13:35:58 -08:00
if ( previousEventTimer . getElapsedSecondsAndReset ( nowNt ) > 1 ) {
2020-01-26 09:02:54 -08:00
/**
* We are here if there is a time gap between now and previous shaft event - that means the engine is not running .
* That means we have lost synchronization since the engine is not running : )
*/
setShaftSynchronized ( false ) ;
if ( triggerStateListener ) {
triggerStateListener - > OnTriggerSynchronizationLost ( ) ;
}
}
2022-09-25 15:49:54 -07:00
bool useOnlyRisingEdgeForTrigger = triggerShape . useOnlyRisingEdges ;
2018-12-25 09:27:34 -08:00
2023-04-11 17:01:34 -07:00
efiAssert ( ObdCode : : CUSTOM_TRIGGER_UNEXPECTED , signal < = SHAFT_SECONDARY_RISING , " unexpected signal " , unexpected ) ;
2015-07-10 06:01:56 -07:00
2022-09-11 00:46:50 -07:00
TriggerWheel triggerWheel = eventIndex [ signal ] ;
2022-09-10 23:57:35 -07:00
TriggerValue type = eventType [ signal ] ;
2015-07-10 06:01:56 -07:00
2022-05-10 13:55:28 -07:00
// Check that we didn't get the same edge twice in a row - that should be impossible
if ( ! useOnlyRisingEdgeForTrigger & & prevSignal = = signal ) {
2015-07-10 06:01:56 -07:00
orderingErrorCounter + + ;
}
2022-05-10 13:55:28 -07:00
prevSignal = signal ;
2015-07-10 06:01:56 -07:00
2022-09-11 00:46:50 -07:00
currentCycle . eventCount [ ( int ) triggerWheel ] + + ;
2015-07-10 06:01:56 -07:00
2021-01-01 11:07:52 -08:00
if ( toothed_previous_time > nowNt ) {
2023-04-11 17:01:34 -07:00
firmwareError ( ObdCode : : CUSTOM_OBD_93 , " [%s] toothed_previous_time after nowNt prev=%d now=%d " , msg , toothed_previous_time , nowNt ) ;
2021-01-01 11:07:52 -08:00
}
2019-01-22 20:15:33 -08:00
2021-03-07 13:35:58 -08:00
efitick_t currentDurationLong = isFirstEvent ? 0 : nowNt - toothed_previous_time ;
2015-07-10 06:01:56 -07:00
/**
* For performance reasons , we want to work with 32 bit values . If there has been more then
* 10 seconds since previous trigger event we do not really care .
*/
2018-10-21 11:03:51 -07:00
toothDurations [ 0 ] =
2020-01-19 19:23:41 -08:00
currentDurationLong > 10 * NT_PER_SECOND ? 10 * NT_PER_SECOND : currentDurationLong ;
2015-07-10 06:01:56 -07:00
2022-09-23 17:39:41 -07:00
if ( ! shouldConsiderEdge ( triggerShape , triggerWheel , type ) ) {
2019-04-12 19:07:03 -07:00
# if EFI_UNIT_TEST
2020-07-19 12:47:21 -07:00
if ( printTriggerTrace ) {
2019-12-02 07:03:50 -08:00
printf ( " %s isLessImportant %s now=%d index=%d \r \n " ,
2022-05-30 16:36:47 -07:00
getTrigger_type_e ( triggerConfiguration . TriggerType . type ) ,
2015-09-22 20:01:31 -07:00
getTrigger_event_e ( signal ) ,
2019-12-02 07:03:50 -08:00
( int ) nowNt ,
2017-03-03 19:07:25 -08:00
currentCycle . current_index ) ;
2015-07-10 06:01:56 -07:00
}
2017-05-25 20:23:51 -07:00
# endif /* EFI_UNIT_TEST */
2015-07-10 06:01:56 -07:00
2022-06-23 20:11:29 -07:00
// For less important events we simply increment the index.
nextTriggerEvent ( ) ;
2015-09-13 13:01:38 -07:00
} else {
2020-10-04 16:29:26 -07:00
# if !EFI_PROD_CODE
2020-07-19 12:47:21 -07:00
if ( printTriggerTrace ) {
2022-08-27 19:26:56 -07:00
printf ( " %s event %s %lld \r \n " ,
2022-05-30 16:36:47 -07:00
getTrigger_type_e ( triggerConfiguration . TriggerType . type ) ,
2015-09-22 20:01:31 -07:00
getTrigger_event_e ( signal ) ,
nowNt ) ;
2020-07-19 11:17:15 -07:00
printf ( " decodeTriggerEvent ratio %.2f: current=%d previous=%d \r \n " , 1.0 * toothDurations [ 0 ] / toothDurations [ 1 ] ,
2018-10-21 09:29:41 -07:00
toothDurations [ 0 ] , toothDurations [ 1 ] ) ;
2015-09-23 20:01:40 -07:00
}
2015-07-10 06:01:56 -07:00
# endif
2020-10-04 16:29:26 -07:00
isFirstEvent = false ;
2016-01-11 14:01:33 -08:00
bool isSynchronizationPoint ;
2021-07-03 07:37:03 -07:00
bool wasSynchronized = getShaftSynchronized ( ) ;
2015-07-10 06:01:56 -07:00
2020-10-05 11:22:59 -07:00
if ( triggerShape . isSynchronizationNeeded ) {
2022-05-08 05:50:27 -07:00
triggerSyncGapRatio = ( float ) toothDurations [ 0 ] / toothDurations [ 1 ] ;
2019-09-03 16:30:51 -07:00
2023-03-21 16:39:39 -07:00
if ( wasSynchronized & & triggerSyncGapRatio > NOISE_RATIO_THRESHOLD ) {
setTriggerErrorState ( 100 ) ;
}
2022-05-30 16:36:47 -07:00
isSynchronizationPoint = isSyncPoint ( triggerShape , triggerConfiguration . TriggerType . type ) ;
2019-11-10 09:39:47 -08:00
if ( isSynchronizationPoint ) {
2020-10-04 16:29:26 -07:00
enginePins . debugTriggerSync . toggle ( ) ;
2019-11-10 09:39:47 -08:00
}
2017-03-04 17:19:14 -08:00
2019-07-22 14:38:52 -07:00
/**
* todo : technically we can afford detailed logging even with 60 / 2 as long as low RPM
* todo : figure out exact threshold as a function of RPM and tooth count ?
2020-10-05 11:22:59 -07:00
* Open question what is ' triggerShape . getSize ( ) ' for 60 / 2 is it 58 or 58 * 2 or 58 * 4 ?
2019-07-22 14:38:52 -07:00
*/
2021-11-17 00:54:21 -08:00
bool silentTriggerError = triggerShape . getSize ( ) > 40 & & engineConfiguration - > silentTriggerError ;
2019-07-22 14:38:52 -07:00
2019-10-29 18:12:44 -07:00
# if EFI_PROD_CODE || EFI_SIMULATOR
2022-09-13 23:17:04 -07:00
bool verbose = getTriggerCentral ( ) - > isEngineSnifferEnabled & & triggerConfiguration . VerboseTriggerSynchDetails ;
2022-06-18 12:18:45 -07:00
if ( verbose | | ( someSortOfTriggerError ( ) & & ! silentTriggerError ) ) {
2022-08-22 19:52:48 -07:00
const char * prefix = verbose ? " [vrb] " : " [err] " ;
2021-04-07 09:16:23 -07:00
2020-10-05 11:22:59 -07:00
for ( int i = 0 ; i < triggerShape . gapTrackingLength ; i + + ) {
float ratioFrom = triggerShape . syncronizationRatioFrom [ i ] ;
2019-12-25 12:05:02 -08:00
if ( cisnan ( ratioFrom ) ) {
// we do not track gap at this depth
continue ;
}
2018-10-28 12:42:15 -07:00
float gap = 1.0 * toothDurations [ i ] / toothDurations [ i + 1 ] ;
2019-06-25 17:51:29 -07:00
if ( cisnan ( gap ) ) {
2022-08-22 19:52:48 -07:00
efiPrintf ( " %s index=%d NaN gap, you have noise issues? " ,
i ,
prefix
) ;
2019-06-25 17:51:29 -07:00
} else {
2022-06-17 19:11:09 -07:00
float ratioTo = triggerShape . syncronizationRatioTo [ i ] ;
bool gapOk = isInRange ( ratioFrom , gap , ratioTo ) ;
2022-08-22 19:52:48 -07:00
efiPrintf ( " %s %srpm=%d time=%d eventIndex=%d gapIndex=%d: %s gap=%.3f expected from %.3f to %.3f error=%s " ,
prefix ,
2020-10-05 13:42:50 -07:00
triggerConfiguration . PrintPrefix ,
2022-01-20 20:32:59 -08:00
( int ) Sensor : : getOrZero ( SensorType : : Rpm ) ,
2022-09-11 10:06:03 -07:00
/* cast is needed to make sure we do not put 64 bit value to stack*/ ( int ) getTimeNowS ( ) ,
2021-05-23 17:06:19 -07:00
currentCycle . current_index ,
2018-10-28 12:42:15 -07:00
i ,
2022-06-17 19:11:09 -07:00
gapOk ? " Y " : " n " ,
2018-10-28 12:42:15 -07:00
gap ,
2019-12-25 12:05:02 -08:00
ratioFrom ,
2022-06-17 19:11:09 -07:00
ratioTo ,
2022-05-10 13:55:28 -07:00
boolToString ( someSortOfTriggerError ( ) ) ) ;
2019-06-25 17:51:29 -07:00
}
2018-10-21 08:27:14 -07:00
}
2019-08-24 22:35:36 -07:00
}
2015-07-10 06:01:56 -07:00
# else
2020-07-19 12:47:21 -07:00
if ( printTriggerTrace ) {
2018-10-28 12:42:15 -07:00
float gap = 1.0 * toothDurations [ 0 ] / toothDurations [ 1 ] ;
2020-10-05 11:22:59 -07:00
for ( int i = 0 ; i < triggerShape . gapTrackingLength ; i + + ) {
2018-10-28 12:42:15 -07:00
float gap = 1.0 * toothDurations [ i ] / toothDurations [ i + 1 ] ;
2021-07-21 20:08:56 -07:00
printf ( " %sindex=%d: gap=%.2f expected from %.2f to %.2f error=%s \r \n " ,
triggerConfiguration . PrintPrefix ,
2018-10-28 12:42:15 -07:00
i ,
gap ,
2020-10-05 11:22:59 -07:00
triggerShape . syncronizationRatioFrom [ i ] ,
triggerShape . syncronizationRatioTo [ i ] ,
2022-05-10 13:55:28 -07:00
boolToString ( someSortOfTriggerError ( ) ) ) ;
2018-10-28 12:42:15 -07:00
}
2019-08-24 22:35:36 -07:00
}
2015-07-10 06:01:56 -07:00
# endif /* EFI_PROD_CODE */
2015-09-23 20:01:40 -07:00
} else {
/**
2017-03-03 18:57:28 -08:00
* We are here in case of a wheel without synchronization - we just need to count events ,
* synchronization point simply happens once we have the right number of events
*
* in case of noise the counter could be above the expected number of events , that ' s why ' more or equals ' and not just ' equals '
2015-09-23 20:01:40 -07:00
*/
2017-03-03 18:49:55 -08:00
2022-09-25 15:49:54 -07:00
unsigned int endOfCycleIndex = triggerShape . getSize ( ) - ( useOnlyRisingEdgeForTrigger ? 2 : 1 ) ;
2017-03-03 18:49:55 -08:00
2021-07-03 07:37:03 -07:00
isSynchronizationPoint = ! getShaftSynchronized ( ) | | ( currentCycle . current_index > = endOfCycleIndex ) ;
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
# if EFI_UNIT_TEST
2020-07-19 12:47:21 -07:00
if ( printTriggerTrace ) {
2020-10-04 16:29:26 -07:00
printf ( " decodeTriggerEvent sync=%d isSynchronizationPoint=%d index=%d size=%d \r \n " ,
2021-07-03 07:37:03 -07:00
getShaftSynchronized ( ) ,
2020-10-04 16:29:26 -07:00
isSynchronizationPoint ,
currentCycle . current_index ,
2020-10-05 11:22:59 -07:00
triggerShape . getSize ( ) ) ;
2017-05-25 20:23:51 -07:00
}
# endif /* EFI_UNIT_TEST */
2015-09-23 20:01:40 -07:00
}
2019-04-12 19:07:03 -07:00
# if EFI_UNIT_TEST
2020-07-19 12:47:21 -07:00
if ( printTriggerTrace ) {
printf ( " decodeTriggerEvent %s isSynchronizationPoint=%d index=%d %s \r \n " ,
2022-05-30 16:36:47 -07:00
getTrigger_type_e ( triggerConfiguration . TriggerType . type ) ,
2015-09-08 20:01:07 -07:00
isSynchronizationPoint , currentCycle . current_index ,
2015-07-10 06:01:56 -07:00
getTrigger_event_e ( signal ) ) ;
}
2017-05-25 20:23:51 -07:00
# endif /* EFI_UNIT_TEST */
2015-07-10 06:01:56 -07:00
2015-09-23 20:01:40 -07:00
if ( isSynchronizationPoint ) {
2022-05-13 15:48:26 -07:00
bool isDecodingError = validateEventCounters ( triggerShape ) ;
2022-05-10 13:55:28 -07:00
2022-05-13 15:48:26 -07:00
if ( triggerStateListener ) {
2022-05-10 13:55:28 -07:00
triggerStateListener - > OnTriggerSyncronization ( wasSynchronized , isDecodingError ) ;
2022-05-13 15:48:26 -07:00
}
2022-05-10 13:55:28 -07:00
2022-05-13 15:48:26 -07:00
// If we got a sync point, but the wrong number of events since the last sync point
// One of two things has happened:
// - We missed a tooth, and this is the real sync point
// - Due to some mistake in timing, we found what looks like a sync point but actually isn't
// In either case, we should wait for another sync point before doing anything to try and run an engine,
// so we clear the synchronized flag.
if ( wasSynchronized & & isDecodingError ) {
setTriggerErrorState ( ) ;
2022-09-04 06:15:24 -07:00
onNotEnoughTeeth ( currentCycle . current_index , triggerShape . getSize ( ) ) ;
2022-05-13 15:48:26 -07:00
// Something wrong, no longer synchronized
setShaftSynchronized ( false ) ;
// This is a decoding error
onTriggerError ( ) ;
} else {
// If this was the first sync point OR no decode error, we're synchronized!
setShaftSynchronized ( true ) ;
2020-01-22 10:25:35 -08:00
}
2020-01-24 10:42:09 -08:00
// this call would update duty cycle values
2022-06-23 20:11:29 -07:00
nextTriggerEvent ( ) ;
2015-07-10 06:01:56 -07:00
2022-05-30 19:39:57 -07:00
onShaftSynchronization ( wasSynchronized , nowNt , triggerShape ) ;
2018-04-25 23:11:51 -07:00
} else { /* if (!isSynchronizationPoint) */
2022-06-23 20:11:29 -07:00
nextTriggerEvent ( ) ;
2015-09-23 20:01:40 -07:00
}
2015-07-10 06:01:56 -07:00
2020-10-05 11:22:59 -07:00
for ( int i = triggerShape . gapTrackingLength ; i > 0 ; i - - ) {
2018-10-21 11:55:52 -07:00
toothDurations [ i ] = toothDurations [ i - 1 ] ;
}
2015-09-23 20:01:40 -07:00
toothed_previous_time = nowNt ;
2023-01-03 12:44:13 -08:00
# if EFI_UNIT_TEST
if ( wasSynchronized ) {
int uiGapIndex = ( currentCycle . current_index ) % triggerShape . getLength ( ) ;
gapRatio [ uiGapIndex ] = triggerSyncGapRatio ;
}
# endif // EFI_UNIT_TEST
2015-09-13 13:01:38 -07:00
}
2022-05-10 13:55:28 -07:00
2022-05-13 15:48:26 -07:00
if ( getShaftSynchronized ( ) & & ! isValidIndex ( triggerShape ) ) {
2022-05-10 13:55:28 -07:00
// We've had too many events since the last sync point, we should have seen a sync point by now.
// This is a trigger error.
// let's not show a warning if we are just starting to spin
if ( Sensor : : getOrZero ( SensorType : : Rpm ) ! = 0 ) {
setTriggerErrorState ( ) ;
2022-09-04 06:15:24 -07:00
onTooManyTeeth ( currentCycle . current_index , triggerShape . getSize ( ) ) ;
2015-09-25 06:06:35 -07:00
}
2015-09-24 19:02:47 -07:00
2022-05-10 13:55:28 -07:00
onTriggerError ( ) ;
2022-05-13 15:48:26 -07:00
setShaftSynchronized ( false ) ;
2022-05-28 06:01:45 -07:00
return unexpected ;
2022-05-10 13:55:28 -07:00
}
2015-09-13 13:01:38 -07:00
2018-03-10 17:58:51 -08:00
// Needed for early instant-RPM detection
2020-01-22 10:25:35 -08:00
if ( triggerStateListener ) {
2019-12-05 22:57:11 -08:00
triggerStateListener - > OnTriggerStateProperState ( nowNt ) ;
2018-03-10 17:58:51 -08:00
}
2022-05-10 13:55:28 -07:00
triggerStateIndex = currentCycle . current_index ;
2022-05-28 06:01:45 -07:00
if ( getShaftSynchronized ( ) ) {
return TriggerDecodeResult { currentCycle . current_index } ;
} else {
return unexpected ;
}
2015-07-10 06:01:56 -07:00
}
2022-05-10 01:41:39 -07:00
bool TriggerDecoderBase : : isSyncPoint ( const TriggerWaveform & triggerShape , trigger_type_e triggerType ) const {
2021-12-31 12:47:25 -08:00
// Miata NB needs a special decoder.
// The problem is that the crank wheel only has 4 teeth, also symmetrical, so the pattern
// is long-short-long-short for one crank rotation.
// A quick acceleration can result in two successive "short gaps", so we see
// long-short-short-short-long instead of the correct long-short-long-short-long
// This logic expands the lower bound on a "long" tooth, then compares the last
// tooth to the current one.
// Instead of detecting short/long, this logic first checks for "maybe short" and "maybe long",
// then simply tests longer vs. shorter instead of absolute value.
2023-05-31 22:56:40 -07:00
if ( triggerType = = trigger_type_e : : TT_MIATA_VVT ) {
2021-12-31 12:47:25 -08:00
auto secondGap = ( float ) toothDurations [ 1 ] / toothDurations [ 2 ] ;
2022-05-08 06:14:50 -07:00
bool currentGapOk = isInRange ( triggerShape . syncronizationRatioFrom [ 0 ] , ( float ) triggerSyncGapRatio , triggerShape . syncronizationRatioTo [ 0 ] ) ;
2021-12-31 12:47:25 -08:00
bool secondGapOk = isInRange ( triggerShape . syncronizationRatioFrom [ 1 ] , secondGap , triggerShape . syncronizationRatioTo [ 1 ] ) ;
// One or both teeth was impossible range, this is not the sync point
if ( ! currentGapOk | | ! secondGapOk ) {
return false ;
}
// If both teeth are in the range of possibility, return whether this gap is
// shorter than the last or not. If it is, this is the sync point.
2022-05-08 05:50:27 -07:00
return triggerSyncGapRatio < secondGap ;
2021-12-31 12:47:25 -08:00
}
2021-12-30 08:39:04 -08:00
for ( int i = 0 ; i < triggerShape . gapTrackingLength ; i + + ) {
auto from = triggerShape . syncronizationRatioFrom [ i ] ;
auto to = triggerShape . syncronizationRatioTo [ i ] ;
if ( cisnan ( from ) ) {
// don't check this gap, skip it
continue ;
}
// This is transformed to avoid a division and use a cheaper multiply instead
// toothDurations[i] / toothDurations[i+1] > from
// is an equivalent comparison to
// toothDurations[i] > toothDurations[i+1] * from
bool isGapCondition =
( toothDurations [ i ] > toothDurations [ i + 1 ] * from
& & toothDurations [ i ] < toothDurations [ i + 1 ] * to ) ;
if ( ! isGapCondition ) {
return false ;
}
}
return true ;
}
2015-07-10 06:01:56 -07:00
/**
* Trigger shape is defined in a way which is convenient for trigger shape definition
* On the other hand , trigger decoder indexing begins from synchronization event .
*
2019-12-07 22:09:39 -08:00
* This function finds the index of synchronization event within TriggerWaveform
2015-07-10 06:01:56 -07:00
*/
2022-05-10 01:41:39 -07:00
uint32_t TriggerDecoderBase : : findTriggerZeroEventIndex (
2020-10-05 11:22:59 -07:00
TriggerWaveform & shape ,
2022-05-30 16:36:47 -07:00
const TriggerConfiguration & triggerConfiguration ) {
2019-04-12 19:07:03 -07:00
# if EFI_PROD_CODE
2023-06-11 20:17:13 -07:00
efiAssert ( ObdCode : : CUSTOM_ERR_ASSERT , assertRemainingStack ( ) , " findPos " , - 1 ) ;
2015-09-13 07:01:39 -07:00
# endif
2015-07-10 06:01:56 -07:00
2020-01-21 21:40:26 -08:00
2022-11-05 21:32:38 -07:00
resetState ( ) ;
2015-09-13 07:01:39 -07:00
2020-10-05 11:22:59 -07:00
if ( shape . shapeDefinitionError ) {
2017-02-23 11:00:03 -08:00
return 0 ;
}
2022-11-05 21:17:24 -07:00
expected < uint32_t > syncIndex = TriggerStimulatorHelper : : findTriggerSyncPoint ( shape ,
2020-08-23 22:21:42 -07:00
triggerConfiguration ,
2020-10-05 11:22:59 -07:00
* this ) ;
2022-11-05 21:10:50 -07:00
if ( ! syncIndex ) {
return EFI_ERROR_CODE ;
2015-07-10 06:01:56 -07:00
}
2021-11-20 22:01:27 -08:00
// Assert that we found the sync point on the very first revolution
2023-04-11 17:01:34 -07:00
efiAssert ( ObdCode : : CUSTOM_ERR_ASSERT , getCrankSynchronizationCounter ( ) = = 0 , " findZero_revCounter " , EFI_ERROR_CODE ) ;
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
# if EFI_UNIT_TEST
2017-03-04 05:55:53 -08:00
if ( printTriggerDebug ) {
2017-03-04 06:06:06 -08:00
printf ( " findTriggerZeroEventIndex: syncIndex located %d! \r \n " , syncIndex ) ;
2017-03-04 05:55:53 -08:00
}
# endif /* EFI_UNIT_TEST */
2022-11-05 21:17:24 -07:00
TriggerStimulatorHelper : : assertSyncPosition ( triggerConfiguration ,
2022-11-05 21:10:50 -07:00
syncIndex . Value , * this , shape ) ;
2015-07-10 06:01:56 -07:00
2022-11-05 21:10:50 -07:00
return syncIndex . Value % shape . getSize ( ) ;
2015-07-10 06:01:56 -07:00
}
# endif /* EFI_SHAFT_POSITION_INPUT */
2022-08-22 20:42:48 -07:00