rusefi/firmware/controllers/trigger/decoders/trigger_structure.cpp

787 lines
24 KiB
C++

/**
* @file trigger_structure.cpp
*
* @date Jan 20, 2014
* @author Andrey Belomutskiy, (c) 2012-2020
*
* 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/>.
*/
#include "pch.h"
#include "trigger_chrysler.h"
#include "trigger_ford.h"
#include "trigger_gm.h"
#include "trigger_nissan.h"
#include "trigger_mazda.h"
#include "trigger_misc.h"
#include "trigger_mitsubishi.h"
#include "trigger_renault.h"
#include "trigger_subaru.h"
#include "trigger_suzuki.h"
#include "trigger_structure.h"
#include "trigger_toyota.h"
#include "trigger_renix.h"
#include "trigger_rover.h"
#include "trigger_honda.h"
#include "trigger_vw.h"
#include "trigger_universal.h"
#include "trigger_mercedes.h"
#if EFI_SENSOR_CHART
#include "sensor_chart.h"
#endif /* EFI_SENSOR_CHART */
TriggerWaveform::TriggerWaveform() {
initialize(OM_NONE, SyncEdge::Rise);
}
void TriggerWaveform::initialize(operation_mode_e p_operationMode, SyncEdge p_syncEdge) {
operationMode = p_operationMode;
syncEdge = p_syncEdge;
isSynchronizationNeeded = true; // that's default value
isSecondWheelCam = false;
needSecondTriggerInput = false;
shapeWithoutTdc = false;
// If RiseOnly, ignore falling edges completely.
useOnlyRisingEdges = syncEdge == SyncEdge::RiseOnly;
setTriggerSynchronizationGap(2);
for (int gapIndex = 1; gapIndex < GAP_TRACKING_LENGTH ; gapIndex++) {
// NaN means do not use this gap ratio
setTriggerSynchronizationGap3(gapIndex, NAN, 100000);
}
gapTrackingLength = 1;
tdcPosition = 0;
shapeDefinitionError = false;
useOnlyPrimaryForSync = false;
triggerShapeSynchPointIndex = 0;
memset(expectedEventCount, 0, sizeof(expectedEventCount));
wave.reset();
wave.waveCount = TRIGGER_INPUT_PIN_COUNT;
wave.phaseCount = 0;
previousAngle = 0;
memset(isRiseEvent, 0, sizeof(isRiseEvent));
#if EFI_UNIT_TEST
memset(&triggerSignalIndeces, 0, sizeof(triggerSignalIndeces));
memset(&triggerSignalStates, 0, sizeof(triggerSignalStates));
knownOperationMode = true;
#endif // EFI_UNIT_TEST
}
size_t TriggerWaveform::getSize() const {
return wave.phaseCount;
}
int TriggerWaveform::getTriggerWaveformSynchPointIndex() const {
return triggerShapeSynchPointIndex;
}
/**
* physical primary trigger duration
* @see getEngineCycle
* @see getCrankDivider
*/
angle_t TriggerWaveform::getCycleDuration() const {
switch (operationMode) {
case FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR:
return FOUR_STROKE_CYCLE_DURATION / SYMMETRICAL_CRANK_SENSOR_DIVIDER;
case FOUR_STROKE_THREE_TIMES_CRANK_SENSOR:
return FOUR_STROKE_CYCLE_DURATION / SYMMETRICAL_THREE_TIMES_CRANK_SENSOR_DIVIDER;
case FOUR_STROKE_SIX_TIMES_CRANK_SENSOR:
return FOUR_STROKE_CYCLE_DURATION / SYMMETRICAL_SIX_TIMES_CRANK_SENSOR_DIVIDER;
case FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR:
return FOUR_STROKE_CYCLE_DURATION / SYMMETRICAL_TWELVE_TIMES_CRANK_SENSOR_DIVIDER;
case FOUR_STROKE_CRANK_SENSOR:
case TWO_STROKE:
return TWO_STROKE_CYCLE_DURATION;
case OM_NONE:
case FOUR_STROKE_CAM_SENSOR:
return FOUR_STROKE_CYCLE_DURATION;
}
criticalError("unreachable getCycleDuration");
return 0;
}
bool TriggerWaveform::needsDisambiguation() const {
switch (getWheelOperationMode()) {
case FOUR_STROKE_CRANK_SENSOR:
case FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR:
case FOUR_STROKE_THREE_TIMES_CRANK_SENSOR:
case FOUR_STROKE_SIX_TIMES_CRANK_SENSOR:
case FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR:
return true;
case FOUR_STROKE_CAM_SENSOR:
case TWO_STROKE:
case OM_NONE:
return false;
/* let's NOT handle default in order to benefit from -Werror=switch */
}
criticalError("unreachable needsDisambiguation");
return true;
}
/**
* Trigger event count equals engine cycle event count if we have a cam sensor.
* Two trigger cycles make one engine cycle in case of a four stroke engine If we only have a cranksensor.
*
* 'engine->engineCycleEventCount' hold a pre-calculated copy of this value as a performance optimization
*/
size_t TriggerWaveform::getLength() const {
/**
* 24 for FOUR_STROKE_TWELVE_TIMES_CRANK_SENSOR
* 6 for FOUR_STROKE_THREE_TIMES_CRANK_SENSOR
* 4 for FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR
* 2 for FOUR_STROKE_CRANK_SENSOR
* 1 otherwise
*/
int multiplier = getEngineCycle(operationMode) / getCycleDuration();
return multiplier * getSize();
}
angle_t TriggerWaveform::getAngle(int index) const {
/**
* FOUR_STROKE_CRANK_SENSOR magic:
* We have two crank shaft revolutions for each engine cycle
* See also trigger_central.cpp
* See also getEngineCycleEventCount()
*/
efiAssert(ObdCode::CUSTOM_ERR_ASSERT, wave.phaseCount != 0, "shapeSize=0", NAN);
int crankCycle = index / wave.phaseCount;
int remainder = index % wave.phaseCount;
auto cycleStartAngle = getCycleDuration() * crankCycle;
auto positionWithinCycle = getSwitchAngle(remainder);
return cycleStartAngle + positionWithinCycle;
}
void TriggerWaveform::addEventClamped(angle_t angle, TriggerValue const stateParam, TriggerWheel const channelIndex, float filterLeft, float filterRight) {
if (angle > filterLeft && angle < filterRight) {
#if EFI_UNIT_TEST
// printf("addEventClamped %f %s\r\n", angle, getTrigger_value_e(stateParam));
#endif /* EFI_UNIT_TEST */
addEvent(angle / getEngineCycle(operationMode), stateParam, channelIndex);
}
}
/**
* See also Engine#getOperationMode which accounts for additional settings which are
* needed to resolve precise mode for vague wheels
*/
operation_mode_e TriggerWaveform::getWheelOperationMode() const {
return operationMode;
}
#if EFI_UNIT_TEST
extern bool printTriggerDebug;
#endif
size_t TriggerWaveform::getExpectedEventCount(TriggerWheel channelIndex) const {
return expectedEventCount[(int)channelIndex];
}
void TriggerWaveform::calculateExpectedEventCounts() {
if (!useOnlyRisingEdges) {
for (size_t i = 0; i < efi::size(expectedEventCount); i++) {
if (getExpectedEventCount((TriggerWheel)i) % 2 != 0) {
firmwareError(ObdCode::ERROR_TRIGGER_DRAMA, "Trigger: should be even number of events index=%d count=%d", i, getExpectedEventCount((TriggerWheel)i));
}
}
}
bool isSingleToothOnPrimaryChannel = useOnlyRisingEdges ? getExpectedEventCount(TriggerWheel::T_PRIMARY) == 1 : getExpectedEventCount(TriggerWheel::T_PRIMARY) == 2;
// todo: next step would be to set 'isSynchronizationNeeded' automatically based on the logic we have here
if (!shapeWithoutTdc && isSingleToothOnPrimaryChannel != !isSynchronizationNeeded) {
firmwareError(ObdCode::ERROR_TRIGGER_DRAMA, "shapeWithoutTdc isSynchronizationNeeded isSingleToothOnPrimaryChannel constraint violation");
}
if (isSingleToothOnPrimaryChannel) {
useOnlyPrimaryForSync = true;
} else {
if (getExpectedEventCount(TriggerWheel::T_SECONDARY) == 0 && useOnlyPrimaryForSync) {
firmwareError(ObdCode::ERROR_TRIGGER_DRAMA, "why would you set useOnlyPrimaryForSync with only one trigger wheel?");
}
}
// todo: move the following logic from below here
// if (!useOnlyRisingEdgeForTrigger || stateParam == TriggerValue::RISE) {
// expectedEventCount[channelIndex]++;
// }
}
/**
* See header for documentation
*/
void TriggerWaveform::addEvent720(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex) {
addEvent(angle / FOUR_STROKE_CYCLE_DURATION, state, channelIndex);
}
void TriggerWaveform::addEvent360(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex) {
efiAssertVoid(ObdCode::CUSTOM_OMODE_UNDEF, operationMode == FOUR_STROKE_CAM_SENSOR || operationMode == FOUR_STROKE_CRANK_SENSOR, "Not a mode for 360");
#define CRANK_MODE_MULTIPLIER 2.0f
addEvent(CRANK_MODE_MULTIPLIER * angle / FOUR_STROKE_CYCLE_DURATION, state, channelIndex);
}
void TriggerWaveform::addToothRiseFall(angle_t angle, angle_t width, TriggerWheel const channelIndex) {
addEvent360(angle - width, TriggerValue::RISE, channelIndex);
addEvent360(angle, TriggerValue::FALL, channelIndex);
}
void TriggerWaveform::addEventAngle(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex) {
addEvent(angle / getCycleDuration(), state, channelIndex);
}
void TriggerWaveform::addEvent(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex) {
efiAssertVoid(ObdCode::CUSTOM_OMODE_UNDEF, operationMode != OM_NONE, "operationMode not set");
if (channelIndex == TriggerWheel:: T_SECONDARY) {
needSecondTriggerInput = true;
}
#if EFI_UNIT_TEST
if (printTriggerDebug) {
printf("addEvent2 %.2f i=%d r/f=%d\r\n", angle, channelIndex, state);
}
#endif
#if EFI_UNIT_TEST
assertIsInBounds(wave.phaseCount, triggerSignalIndeces, "trigger shape overflow");
triggerSignalIndeces[wave.phaseCount] = channelIndex;
triggerSignalStates[wave.phaseCount] = state;
#endif // EFI_UNIT_TEST
// todo: the whole 'useOnlyRisingEdgeForTrigger' parameter and logic should not be here
// todo: see calculateExpectedEventCounts
// related calculation should be done once trigger is initialized outside of trigger shape scope
if (!useOnlyRisingEdges || state == TriggerValue::RISE) {
expectedEventCount[(int)channelIndex]++;
}
if (angle <= 0 || angle > 1) {
firmwareError(ObdCode::CUSTOM_ERR_6599, "angle should be positive not above 1: index=%d angle %f", channelIndex, angle);
return;
}
if (wave.phaseCount > 0) {
if (angle <= previousAngle) {
warning(ObdCode::CUSTOM_ERR_TRG_ANGLE_ORDER, "invalid angle order %s %s: new=%.2f/%f and prev=%.2f/%f, size=%d",
getTriggerWheel(channelIndex),
getTrigger_value_e(state),
angle, angle * getCycleDuration(),
previousAngle, previousAngle * getCycleDuration(),
wave.phaseCount);
setShapeDefinitionError(true);
return;
}
}
previousAngle = angle;
if (wave.phaseCount == 0) {
wave.phaseCount = 1;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
wave.setChannelState(i, /* switchIndex */ 0, TriggerValue::FALL);
}
isRiseEvent[0] = TriggerValue::RISE == state;
wave.setSwitchTime(0, angle);
wave.setChannelState((int)channelIndex, /* channelIndex */ 0, /* value */ state);
return;
}
if (wave.findAngleMatch(angle)) {
warning(ObdCode::CUSTOM_ERR_SAME_ANGLE, "same angle: not supported");
setShapeDefinitionError(true);
return;
}
int index = wave.findInsertionAngle(angle);
/**
* todo: it would be nice to be able to provide trigger angles without sorting them externally
* The idea here is to shift existing data - including handling high vs low state of the signals
*/
// todo: does this logic actually work? I think it does not! due to broken state handling
/*
for (int i = size - 1; i >= index; i--) {
for (int j = 0; j < PWM_PHASE_MAX_WAVE_PER_PWM; j++) {
wave.waves[j].pinStates[i + 1] = wave.getChannelState(j, index);
}
wave.setSwitchTime(i + 1, wave.getSwitchTime(i));
}
*/
isRiseEvent[index] = TriggerValue::RISE == state;
if ((unsigned)index != wave.phaseCount) {
firmwareError(ObdCode::ERROR_TRIGGER_DRAMA, "are we ever here?");
}
wave.phaseCount++;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
pin_state_t value = wave.getChannelState(/* channelIndex */i, index - 1);
wave.setChannelState(i, index, value);
}
wave.setSwitchTime(index, angle);
wave.setChannelState((int)channelIndex, index, state);
}
angle_t TriggerWaveform::getSwitchAngle(int index) const {
return getCycleDuration() * wave.getSwitchTime(index);
}
void TriggerWaveform::setTriggerSynchronizationGap2(float syncRatioFrom, float syncRatioTo) {
setTriggerSynchronizationGap3(/*gapIndex*/0, syncRatioFrom, syncRatioTo);
}
void TriggerWaveform::setTriggerSynchronizationGap3(int gapIndex, float syncRatioFrom, float syncRatioTo) {
isSynchronizationNeeded = true;
criticalAssertVoid(gapIndex >= 0 && gapIndex < GAP_TRACKING_LENGTH, "gapIndex out of range");
synchronizationRatioFrom[gapIndex] = syncRatioFrom;
synchronizationRatioTo[gapIndex] = syncRatioTo;
if (gapIndex == 0) {
// we have a special case here - only sync with one gap has this feature
this->syncRatioAvg = (int)efiRound((syncRatioFrom + syncRatioTo) * 0.5f, 1.0f);
}
gapTrackingLength = maxI(1 + gapIndex, gapTrackingLength);
#if EFI_UNIT_TEST
if (printTriggerDebug) {
printf("setTriggerSynchronizationGap3 %d %.2f %.2f\r\n", gapIndex, syncRatioFrom, syncRatioTo);
}
#endif /* EFI_UNIT_TEST */
}
uint16_t TriggerWaveform::findAngleIndex(TriggerFormDetails *details, angle_t targetAngle) const {
size_t engineCycleEventCount = getLength();
efiAssert(ObdCode::CUSTOM_ERR_ASSERT, engineCycleEventCount != 0 && engineCycleEventCount <= 0xFFFF,
"engineCycleEventCount", 0);
uint32_t left = 0;
uint32_t right = engineCycleEventCount - 1;
/**
* Let's find the last trigger angle which is less or equal to the desired angle
* todo: extract binary search as template method?
*/
do {
uint32_t middle = (left + right) / 2;
if (details->eventAngles[middle] <= targetAngle) {
left = middle + 1;
} else {
right = middle - 1;
}
} while (left <= right);
left -= 1;
if (useOnlyRisingEdges) {
left &= ~1U;
}
return left;
}
void TriggerWaveform::setShapeDefinitionError(bool value) {
shapeDefinitionError = value;
}
void TriggerWaveform::setTriggerSynchronizationGap(float syncRatio) {
setTriggerSynchronizationGap3(/*gapIndex*/0, syncRatio * TRIGGER_GAP_DEVIATION_LOW, syncRatio * TRIGGER_GAP_DEVIATION_HIGH);
}
void TriggerWaveform::setSecondTriggerSynchronizationGap(float syncRatio) {
setTriggerSynchronizationGap3(/*gapIndex*/1, syncRatio * TRIGGER_GAP_DEVIATION_LOW, syncRatio * TRIGGER_GAP_DEVIATION_HIGH);
}
void TriggerWaveform::setSecondTriggerSynchronizationGap2(float syncRatioFrom, float syncRatioTo) {
setTriggerSynchronizationGap3(/*gapIndex*/1, syncRatioFrom, syncRatioTo);
}
void TriggerWaveform::setThirdTriggerSynchronizationGap(float syncRatio) {
setTriggerSynchronizationGap3(/*gapIndex*/2, syncRatio * TRIGGER_GAP_DEVIATION_LOW, syncRatio * TRIGGER_GAP_DEVIATION_HIGH);
}
/**
* External logger is needed because at this point our logger is not yet initialized
*/
void TriggerWaveform::initializeTriggerWaveform(operation_mode_e triggerOperationMode, const trigger_config_s &triggerType) {
#if EFI_PROD_CODE
efiAssertVoid(ObdCode::CUSTOM_ERR_6641, hasLotsOfRemainingStack(), "init t");
efiPrintf("initializeTriggerWaveform(%s/%d)", getTrigger_type_e(triggerType.type), (int)triggerType.type);
#endif
shapeDefinitionError = false;
switch (triggerType.type) {
case trigger_type_e::TT_TOOTHED_WHEEL:
initializeSkippedToothTrigger(this, triggerType.customTotalToothCount,
triggerType.customSkippedToothCount, triggerOperationMode, SyncEdge::RiseOnly);
break;
case trigger_type_e::TT_MAZDA_MIATA_NA:
initializeMazdaMiataNaShape(this);
break;
case trigger_type_e::TT_MAZDA_MIATA_VVT_TEST:
initializeMazdaMiataVVtTestShape(this);
break;
case trigger_type_e::TT_SUZUKI_G13B:
initializeSuzukiG13B(this);
break;
case trigger_type_e::TT_FORD_TFI_PIP:
configureFordPip(this);
break;
case trigger_type_e::TT_FORD_ST170:
configureFordST170(this);
break;
case trigger_type_e::TT_VVT_MIATA_NB:
initializeMazdaMiataVVtCamShape(this);
break;
case trigger_type_e::TT_RENIX_66_2_2_2:
initializeRenix66_2_2(this);
break;
case trigger_type_e::TT_RENIX_44_2_2:
initializeRenix44_2_2(this);
break;
case trigger_type_e::TT_MIATA_VVT:
initializeMazdaMiataNb2Crank(this);
break;
case trigger_type_e::TT_DODGE_NEON_1995:
case trigger_type_e::TT_DODGE_NEON_1995_ONLY_CRANK:
configureNeon1995TriggerWaveformOnlyCrank(this);
break;
case trigger_type_e::TT_DODGE_STRATUS:
configureDodgeStratusTriggerWaveform(this);
break;
case trigger_type_e::TT_DODGE_NEON_2003_CAM:
configureNeon2003TriggerWaveformCam(this);
break;
case trigger_type_e::TT_DODGE_NEON_2003_CRANK:
configureNeon2003TriggerWaveformCam(this);
// configureNeon2003TriggerWaveformCrank(triggerShape);
break;
case trigger_type_e::TT_FORD_ASPIRE:
configureFordAspireTriggerWaveform(this);
break;
case trigger_type_e::TT_VVT_NISSAN_VQ35:
initializeNissanVQvvt(this);
break;
case trigger_type_e::TT_VVT_MITSU_6G72:
initializeVvt6G72(this);
break;
case trigger_type_e::TT_VVT_MITSUBISHI_3A92:
initializeVvt3A92(this);
break;
case trigger_type_e::TT_VVT_TOYOTA_4_1:
initializeSkippedToothTrigger(this, 4, 1, triggerOperationMode, SyncEdge::RiseOnly);
setTriggerSynchronizationGap3(/*gapIndex*/0, /*from*/1.60, 2.40);
setTriggerSynchronizationGap3(/*gapIndex*/1, /*from*/0.75, 1.25);
break;
case trigger_type_e::TT_NISSAN_QR25:
initializeNissanQR25crank(this);
break;
case trigger_type_e::TT_NISSAN_VQ30:
initializeNissanVQ30cam(this);
break;
case trigger_type_e::TT_NISSAN_VQ35:
initializeNissanVQ35crank(this);
break;
case trigger_type_e::TT_NISSAN_MR18_CRANK:
initializeNissanMR18crank(this);
break;
case trigger_type_e::TT_NISSAN_MR18_CAM_VVT:
initializeNissanMRvvt(this);
break;
case trigger_type_e::TT_KAWA_KX450F:
configureKawaKX450F(this);
break;
case trigger_type_e::TT_SKODA_FAVORIT:
setSkodaFavorit(this);
break;
case trigger_type_e::TT_GM_60_2_2_2:
configureGm60_2_2_2(this);
break;
case trigger_type_e::TT_GM_7X:
configureGmTriggerWaveform(this);
break;
case trigger_type_e::TT_MAZDA_DOHC_1_4:
configureMazdaProtegeLx(this);
break;
case trigger_type_e::TT_ONE_PLUS_ONE:
configureOnePlusOne(this);
break;
case trigger_type_e::TT_3_1_CAM:
configure3_1_cam(this);
break;
case trigger_type_e::TT_MERCEDES_2_SEGMENT:
setMercedesTwoSegment(this);
break;
case trigger_type_e::TT_HALF_MOON:
/** @note TT_HALF_MOON setup events as 180 and 360 degrees. It uses SyncEdge::Rise
* for additional phase align on falling edge and will not work with non-
* symmetrical blind type where open and closed sections are not equal */
initializeSkippedToothTrigger(this, 1, 0, triggerOperationMode, SyncEdge::Rise);
break;
case trigger_type_e::TT_NARROW_SINGLE_TOOTH:
/** different from TT_HALF_MOON */
initializeSkippedToothTrigger(this, 1, 0, triggerOperationMode, SyncEdge::RiseOnly);
break;
case trigger_type_e::TT_MAZDA_SOHC_4:
configureMazdaProtegeSOHC(this);
break;
case trigger_type_e::TT_DAIHATSU_3_CYL:
configureDaihatsu3cyl(this);
break;
case trigger_type_e::TT_DAIHATSU_4_CYL:
configureDaihatsu4cyl(this);
break;
case trigger_type_e::TT_VVT_TOYOTA_3_TOOTH:
initializeSkippedToothTrigger(this, 3, 0, triggerOperationMode, SyncEdge::RiseOnly);
break;
case trigger_type_e::TT_36_2_1_1:
initialize36_2_1_1(this);
break;
case trigger_type_e::TT_36_2_1:
initialize36_2_1(this);
break;
case trigger_type_e::TT_TOOTHED_WHEEL_32_2:
initializeSkippedToothTrigger(this, 32, 2, triggerOperationMode, SyncEdge::RiseOnly);
// todo: why is this 32/2 asking for third gap while 60/2 is happy with just two gaps?
// method above sets second gap, here we add third
// this third gap is not required to sync on perfect signal but is needed to handle to reject cranking transition noise
setThirdTriggerSynchronizationGap(1);
break;
case trigger_type_e::TT_TOOTHED_WHEEL_60_2:
initializeSkippedToothTrigger(this, 60, 2, triggerOperationMode, SyncEdge::RiseOnly);
break;
case trigger_type_e::TT_TOOTHED_WHEEL_36_2:
initializeSkippedToothTrigger(this, 36, 2, triggerOperationMode, SyncEdge::RiseOnly);
setTriggerSynchronizationGap3(/*gapIndex*/0, /*from*/1.6, 3.5);
setTriggerSynchronizationGap3(/*gapIndex*/1, /*from*/0.7, 1.3); // second gap is not required to synch on perfect signal but is needed to handle to reject cranking transition noise
break;
case trigger_type_e::TT_60_2_VW:
setVwConfiguration(this);
break;
case trigger_type_e::TT_TOOTHED_WHEEL_36_1:
initializeSkippedToothTrigger(this, 36, 1, triggerOperationMode, SyncEdge::RiseOnly);
break;
case trigger_type_e::TT_VVT_BOSCH_QUICK_START:
configureQuickStartSenderWheel(this);
break;
case trigger_type_e::TT_VVT_BARRA_3_PLUS_1:
configureBarra3plus1cam(this);
break;
case trigger_type_e::TT_HONDA_K_CAM_4_1:
configureHondaK_4_1(this);
break;
case trigger_type_e::TT_HONDA_K_CRANK_12_1:
configureHondaK_12_1(this);
break;
case trigger_type_e::TT_SUBARU_EZ30:
initializeSubaruEZ30(this);
break;
case trigger_type_e::TT_VVT_MAZDA_SKYACTIV:
initializeMazdaSkyactivCam(this);
break;
case trigger_type_e::TT_BENELLI_TRE:
configureBenelli(this);
break;
case trigger_type_e::TT_MITSU_4G63_CRANK:
initializeMitsubishi4gSymmetricalCrank(this);
break;
case trigger_type_e::TT_VVT_FORD_COYOTE:
configureFordCoyote(this);
break;
case trigger_type_e::TT_60DEG_TOOTH:
/** @note
* Have a something like TT_ONE_PHASED trigger with
* externally setuped blind width will be a good
* approach to utilize ::Rise(and::Both in future)
* with both edges phase-sync, but to stay simple I suggest
* just to use another enum for each trigger type. */
configure60degSingleTooth(this);
break;
case trigger_type_e::TT_60_2_2_F3R:
initialize60_2_2_Renault_F(this);
break;
case trigger_type_e::TT_VVT_MITSUBISHI_4G69:
initializeMitsubishi4G69Cam(this);
break;
case trigger_type_e::TT_MITSU_4G63_CAM:
initializeMitsubishi4g63Cam(this);
break;
case trigger_type_e::TT_MITSU_4G9x_CAM:
initializeMitsubishi4g9xCam(this);
break;
case trigger_type_e::TT_1_16:
configureOnePlus16(this);
break;
case trigger_type_e::TT_HONDA_CBR_600:
configureHondaCbr600(this);
break;
case trigger_type_e::TT_CHRYSLER_NGC_36_2_2:
configureChryslerNGC_36_2_2(this);
break;
case trigger_type_e::TT_DODGE_RAM:
initDodgeRam(this);
break;
case trigger_type_e::TT_JEEP_4_CYL:
initJeep_XJ_4cyl_2500(this);
break;
case trigger_type_e::TT_JEEP_18_2_2_2:
initJeep18_2_2_2(this);
break;
case trigger_type_e::TT_SUBARU_7_6:
initializeSubaru7_6(this);
break;
case trigger_type_e::TT_36_2_2_2:
initialize36_2_2_2(this);
break;
case trigger_type_e::TT_2JZ_3_34_SIMULATION_ONLY:
initialize2jzGE3_34_simulation_shape(this);
break;
case trigger_type_e::TT_3_TOOTH_CRANK:
configure3ToothCrank(this);
break;
case trigger_type_e::TT_6_TOOTH_CRANK:
configure6ToothCrank(this);
break;
case trigger_type_e::TT_12_TOOTH_CRANK:
configure12ToothCrank(this);
break;
case trigger_type_e::TT_NISSAN_SR20VE:
initializeNissanSR20VE_4(this);
break;
case trigger_type_e::TT_ROVER_K:
initializeRoverK(this);
break;
case trigger_type_e::TT_FIAT_IAW_P8:
configureFiatIAQ_P8(this);
break;
case trigger_type_e::TT_TRI_TACH:
configureTriTach(this);
break;
case trigger_type_e::TT_GM_24x_5:
initGmLS24_5deg(this);
break;
case trigger_type_e::TT_GM_24x_3:
initGmLS24_3deg(this);
break;
case trigger_type_e::TT_SUBARU_7_WITHOUT_6:
initializeSubaruOnly7(this);
break;
case trigger_type_e::TT_SUBARU_SVX:
initializeSubaru_SVX(this);
break;
case trigger_type_e::TT_SUBARU_SVX_CRANK_1:
initializeSubaru_SVX(this);
break;
case trigger_type_e::TT_SUBARU_SVX_CAM_VVT:
initializeSubaru_SVX(this);
break;
default:
setShapeDefinitionError(true);
warning(ObdCode::CUSTOM_ERR_NO_SHAPE, "initializeTriggerWaveform() not implemented: %d", triggerType.type);
}
/**
* Feb 2019 suggestion: it would be an improvement to remove 'expectedEventCount' logic from 'addEvent'
* and move it here, after all events were added.
*/
calculateExpectedEventCounts();
version++;
if (!shapeDefinitionError) {
wave.checkSwitchTimes(getCycleDuration());
}
}