fome-fw/firmware/controllers/trigger/trigger_decoder.cpp

764 lines
24 KiB
C++
Raw Normal View History

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
* 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/>.
*/
#include "pch.h"
#include "os_access.h"
2015-07-10 06:01:56 -07:00
#include "obd_error_codes.h"
#include "trigger_decoder.h"
#include "cyclic_buffer.h"
2015-09-13 13:01:38 -07:00
#include "trigger_central.h"
2015-09-23 18:02:33 -07:00
#include "trigger_simulator.h"
2015-09-12 18:03:09 -07:00
2019-04-12 19:07:03 -07:00
#if EFI_SENSOR_CHART
2015-09-12 18:03:09 -07:00
#include "sensor_chart.h"
#endif
2015-07-10 06:01:56 -07:00
2019-01-31 14:55:23 -08:00
TriggerState::TriggerState() {
resetTriggerState();
}
2021-07-03 07:37:03 -07:00
bool TriggerState::getShaftSynchronized() {
return shaft_is_synchronized;
}
void TriggerState::setShaftSynchronized(bool value) {
if (value) {
if (!shaft_is_synchronized) {
// just got synchronized
mostRecentSyncTime = getTimeNowNt();
}
} else {
// sync loss
mostRecentSyncTime = 0;
}
shaft_is_synchronized = value;
}
2019-01-31 14:55:23 -08:00
void TriggerState::resetTriggerState() {
setShaftSynchronized(false);
2019-01-31 14:55:23 -08:00
toothed_previous_time = 0;
memset(toothDurations, 0, sizeof(toothDurations));
totalRevolutionCounter = 0;
totalTriggerErrorCounter = 0;
orderingErrorCounter = 0;
lastDecodingErrorTime = US2NT(-10000000LL);
someSortOfTriggerError = false;
memset(toothDurations, 0, sizeof(toothDurations));
curSignal = SHAFT_PRIMARY_FALLING;
prevSignal = SHAFT_PRIMARY_FALLING;
startOfCycleNt = 0;
resetCurrentCycleState();
memset(expectedTotalTime, 0, sizeof(expectedTotalTime));
totalEventCountBase = 0;
isFirstEvent = true;
}
2020-01-26 03:28:33 -08:00
void TriggerState::setTriggerErrorState() {
lastDecodingErrorTime = getTimeNowNt();
someSortOfTriggerError = true;
}
2019-01-31 14:55:23 -08:00
void TriggerState::resetCurrentCycleState() {
memset(currentCycle.eventCount, 0, sizeof(currentCycle.eventCount));
memset(currentCycle.timeOfPreviousEventNt, 0, sizeof(currentCycle.timeOfPreviousEventNt));
#if EFI_UNIT_TEST
memcpy(currentCycle.totalTimeNtCopy, currentCycle.totalTimeNt, sizeof(currentCycle.totalTimeNt));
#endif
2019-01-31 14:55:23 -08:00
memset(currentCycle.totalTimeNt, 0, sizeof(currentCycle.totalTimeNt));
currentCycle.current_index = 0;
}
TriggerStateWithRunningStatistics::TriggerStateWithRunningStatistics() :
//https://en.cppreference.com/w/cpp/language/zero_initialization
timeOfLastEvent(), instantRpmValue()
{
}
2019-04-12 19:07:03 -07:00
#if EFI_SHAFT_POSITION_INPUT
2015-07-10 06:01:56 -07: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
float actualSynchGap;
#endif /* ! EFI_PROD_CODE */
void TriggerWaveform::initializeSyncPoint(TriggerState& state,
const TriggerConfiguration& triggerConfiguration,
const trigger_config_s& triggerConfig) {
triggerShapeSynchPointIndex = state.findTriggerZeroEventIndex(*this,
2020-08-26 17:57:11 -07:00
triggerConfiguration, triggerConfig);
}
/**
* Calculate 'shape.triggerShapeSynchPointIndex' value using 'TriggerState *state'
*/
void calculateTriggerSynchPoint(
TriggerWaveform& shape,
TriggerState& state) {
state.resetTriggerState();
2019-04-12 19:07:03 -07:00
#if EFI_PROD_CODE
2020-01-27 21:16:33 -08:00
efiAssertVoid(CUSTOM_TRIGGER_STACK, getCurrentRemainingStack() > EXPECTED_REMAINING_STACK, "calc s");
#endif
2020-01-26 11:20:55 -08:00
engine->triggerErrorDetection.clear();
shape.initializeSyncPoint(state,
engine->primaryTriggerConfiguration,
engineConfiguration->trigger);
int length = shape.getLength();
engine->engineCycleEventCount = length;
efiAssertVoid(CUSTOM_SHAPE_LEN_ZERO, length > 0, "shapeLength=0");
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!
firmwareError(CUSTOM_ERR_TRIGGER_WAVEFORM_TOO_LONG, "Trigger length above maximum: %d", length);
shape.setShapeDefinitionError(true);
return;
}
if (shape.getSize() == 0) {
2020-08-26 21:06:10 -07:00
firmwareError(CUSTOM_ERR_TRIGGER_ZERO, "triggerShape size is zero");
}
2020-08-25 09:45:18 -07:00
}
2020-08-25 09:45:18 -07:00
void prepareEventAngles(TriggerWaveform *shape,
TriggerFormDetails *details) {
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);
2020-08-25 09:45:18 -07:00
assertAngleRange(firstAngle, "firstAngle", CUSTOM_TRIGGER_SYNC_ANGLE);
int riseOnlyIndex = 0;
2020-08-25 09:45:18 -07:00
int length = shape->getLength();
2020-08-24 21:59:07 -07:00
memset(details->eventAngles, 0, sizeof(details->eventAngles));
// this may be <length for some triggers like symmetrical crank Miata NB
int triggerShapeLength = shape->getSize();
assertAngleRange(shape->triggerShapeSynchPointIndex, "triggerShapeSynchPointIndex", CUSTOM_TRIGGER_SYNC_ANGLE2);
efiAssertVoid(CUSTOM_TRIGGER_CYCLE, engine->engineCycleEventCount != 0, "zero engineCycleEventCount");
for (int eventIndex = 0; eventIndex < length; eventIndex++) {
if (eventIndex == 0) {
// explicit check for zero to avoid issues where logical zero is not exactly zero due to float nature
2020-08-24 21:59:07 -07:00
details->eventAngles[0] = 0;
// this value would be used in case of front-only
2020-08-24 21:59:07 -07:00
details->eventAngles[1] = 0;
} else {
// 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;
2020-01-27 21:16:33 -08:00
efiAssertVoid(CUSTOM_TRIGGER_CYCLE, !cisnan(angle), "trgSyncNaN");
// Wrap the angle back in to [0, 720)
2020-01-27 21:16:33 -08:00
fixAngle(angle, "trgSync", CUSTOM_TRIGGER_SYNC_ANGLE_RANGE);
if (engineConfiguration->useOnlyRisingEdgeForTrigger) {
efiAssertVoid(OBD_PCM_Processor_Fault, triggerDefinitionIndex < triggerShapeLength, "trigger shape fail");
assertIsInBounds(triggerDefinitionIndex, shape->isRiseEvent, "isRise");
// In case this is a rising event, replace the following fall event with the rising as well
if (shape->isRiseEvent[triggerDefinitionIndex]) {
riseOnlyIndex += 2;
2020-08-24 21:59:07 -07:00
details->eventAngles[riseOnlyIndex] = angle;
details->eventAngles[riseOnlyIndex + 1] = angle;
}
} else {
2020-08-24 21:59:07 -07:00
details->eventAngles[eventIndex] = angle;
}
}
}
}
int64_t TriggerState::getTotalEventCounter() const {
return totalEventCountBase + currentCycle.current_index;
}
2019-01-15 17:24:36 -08:00
int TriggerState::getTotalRevolutionCounter() const {
return totalRevolutionCounter;
}
void TriggerStateWithRunningStatistics::movePreSynchTimestamps() {
// here we take timestamps of events which happened prior to synchronization and place them
// at appropriate locations
auto triggerSize = getTriggerSize();
int eventsToCopy = minI(spinningEventIndex, triggerSize);
size_t firstSrc;
size_t firstDst;
if (eventsToCopy >= triggerSize) {
// Only copy one trigger length worth of events, filling the whole buffer
firstSrc = spinningEventIndex - triggerSize;
firstDst = 0;
} else {
// There is less than one full cycle, copy to the end of the buffer
firstSrc = 0;
firstDst = triggerSize - spinningEventIndex;
}
memcpy(timeOfLastEvent + firstDst, spinningEvents + firstSrc, eventsToCopy * sizeof(timeOfLastEvent[0]));
}
float TriggerStateWithRunningStatistics::calculateInstantRpm(
TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
uint32_t current_index, efitick_t nowNt) {
assertIsInBoundsWithResult((int)current_index, timeOfLastEvent, "calc timeOfLastEvent", 0);
// Record the time of this event so we can calculate RPM from it later
timeOfLastEvent[current_index] = nowNt;
// Determine where we currently are in the revolution
2020-08-24 21:59:07 -07:00
angle_t currentAngle = triggerFormDetails->eventAngles[current_index];
if (cisnan(currentAngle)) {
return NOISY_RPM;
}
// Hunt for a tooth ~90 degrees ago to compare to the current time
angle_t previousAngle = currentAngle - 90;
2019-11-03 18:19:13 -08:00
fixAngle(previousAngle, "prevAngle", CUSTOM_ERR_TRIGGER_ANGLE_RANGE);
int prevIndex = triggerShape.findAngleIndex(triggerFormDetails, previousAngle);
// now let's get precise angle for that event
2020-08-24 21:59:07 -07:00
angle_t prevIndexAngle = triggerFormDetails->eventAngles[prevIndex];
efitick_t time90ago = timeOfLastEvent[prevIndex];
if (time90ago == 0) {
return prevInstantRpmValue;
}
// we are OK to subtract 32 bit value from more precise 64 bit since the result would 32 bit which is
// OK for small time differences like this one
uint32_t time = nowNt - time90ago;
angle_t angleDiff = currentAngle - prevIndexAngle;
// Wrap the angle in to the correct range (ie, could be -630 when we want +90)
fixAngle(angleDiff, "angleDiff", CUSTOM_ERR_6561);
// just for safety
if (time == 0)
return prevInstantRpmValue;
float instantRpm = (60000000.0 / 360 * US_TO_NT_MULTIPLIER) * angleDiff / time;
assertIsInBoundsWithResult((int)current_index, instantRpmValue, "instantRpmValue", 0);
instantRpmValue[current_index] = instantRpm;
// This fixes early RPM instability based on incomplete data
if (instantRpm < RPM_LOW_THRESHOLD) {
return prevInstantRpmValue;
}
prevInstantRpmValue = instantRpm;
m_instantRpmRatio = instantRpm / instantRpmValue[prevIndex];
return instantRpm;
}
void TriggerStateWithRunningStatistics::setLastEventTimeForInstantRpm(efitick_t nowNt) {
2021-07-03 07:37:03 -07:00
if (getShaftSynchronized()) {
return;
}
// here we remember tooth timestamps which happen prior to synchronization
if (spinningEventIndex >= PRE_SYNC_EVENTS) {
// too many events while trying to find synchronization point
// todo: better implementation would be to shift here or use cyclic buffer so that we keep last
// 'PRE_SYNC_EVENTS' events
return;
}
spinningEvents[spinningEventIndex++] = nowNt;
}
void TriggerStateWithRunningStatistics::updateInstantRpm(
TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
uint32_t index, efitick_t nowNt) {
m_instantRpm = calculateInstantRpm(triggerShape, triggerFormDetails, index,
nowNt);
2019-04-12 19:07:03 -07:00
#if EFI_SENSOR_CHART
if (engine->sensorChartMode == SC_RPM_ACCEL || engine->sensorChartMode == SC_DETAILED_RPM) {
2020-08-24 21:59:07 -07:00
angle_t currentAngle = triggerFormDetails->eventAngles[currentCycle.current_index];
if (engineConfiguration->sensorChartMode == SC_DETAILED_RPM) {
scAddData(currentAngle, m_instantRpm);
} else {
scAddData(currentAngle, m_instantRpmRatio);
}
}
#endif /* EFI_SENSOR_CHART */
}
bool TriggerState::isValidIndex(const TriggerWaveform& triggerShape) const {
return currentCycle.current_index < triggerShape.getSize();
2015-09-24 19:02:47 -07:00
}
2015-07-10 06:01:56 -07:00
static trigger_wheel_e eventIndex[6] = { T_PRIMARY, T_PRIMARY, T_SECONDARY, T_SECONDARY, T_CHANNEL_3, T_CHANNEL_3 };
2016-06-11 20:02:58 -07:00
static trigger_value_e eventType[6] = { TV_FALL, TV_RISE, TV_FALL, TV_RISE, TV_FALL, TV_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() \
{ \
2015-09-12 13:01:43 -07:00
uint32_t prevTime = currentCycle.timeOfPreviousEventNt[triggerWheel]; \
2015-07-10 06:01:56 -07:00
if (prevTime != 0) { \
/* even event - apply the value*/ \
2015-09-08 20:01:07 -07:00
currentCycle.totalTimeNt[triggerWheel] += (nowNt - prevTime); \
currentCycle.timeOfPreviousEventNt[triggerWheel] = 0; \
2015-07-10 06:01:56 -07:00
} else { \
/* odd event - start accumulation */ \
2015-09-08 20:01:07 -07:00
currentCycle.timeOfPreviousEventNt[triggerWheel] = nowNt; \
2015-07-10 06:01:56 -07:00
} \
if (triggerConfiguration.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
}
#define considerEventForGap() (!triggerShape.useOnlyPrimaryForSync || isPrimary)
2017-03-18 18:36:51 -07:00
#define needToSkipFall(type) ((!triggerShape.gapBothDirections) && (( triggerShape.useRiseEdge) && (type != TV_RISE)))
#define needToSkipRise(type) ((!triggerShape.gapBothDirections) && ((!triggerShape.useRiseEdge) && (type != TV_FALL)))
2017-03-18 18:36:51 -07:00
2019-01-15 17:24:36 -08:00
int TriggerState::getCurrentIndex() const {
2018-02-05 14:25:01 -08:00
return currentCycle.current_index;
}
2018-02-05 14:29:16 -08:00
2019-09-02 11:47:05 -07:00
void TriggerCentral::validateCamVvtCounters() {
// micro-optimized 'totalRevolutionCounter % 256'
2019-09-02 11:47:05 -07:00
int camVvtValidationIndex = triggerState.getTotalRevolutionCounter() & 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
warning(OBD_Camshaft_Position_Sensor_Circuit_Range_Performance, "no CAM signals");
}
}
angle_t TriggerState::syncSymmetricalCrank(int divider, int remainder, angle_t engineCycle) {
efiAssert(OBD_PCM_Processor_Fault, remainder < divider, "syncSymmetricalCrank", false);
angle_t totalShift = 0;
while (getTotalRevolutionCounter() % divider != remainder) {
/**
* 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
*/
2021-07-05 15:28:26 -07:00
incrementTotalEventCounter();
totalShift += engineCycle / divider;
2021-07-05 15:28:26 -07:00
}
return totalShift;
2021-07-05 15:28:26 -07:00
}
2018-02-05 14:29:16 -08:00
void TriggerState::incrementTotalEventCounter() {
totalRevolutionCounter++;
}
bool TriggerState::validateEventCounters(const TriggerWaveform& triggerShape) const {
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++) {
2021-06-26 19:17:07 -07:00
isDecodingError |= (currentCycle.eventCount[i] != triggerShape.getExpectedEventCount(i));
2020-01-26 03:35:51 -08:00
}
#if EFI_UNIT_TEST
printf("sync point: isDecodingError=%d\r\n", isDecodingError);
if (isDecodingError) {
2020-01-26 06:00:46 -08:00
for (int i = 0;i < PWM_PHASE_MAX_WAVE_PER_PWM;i++) {
2021-06-26 19:17:07 -07:00
printf("count: cur=%d exp=%d\r\n", currentCycle.eventCount[i], triggerShape.getExpectedEventCount(i));
2020-01-26 03:35:51 -08:00
}
}
#endif /* EFI_UNIT_TEST */
return isDecodingError;
}
2020-08-26 14:30:13 -07:00
void TriggerState::onShaftSynchronization(
const TriggerStateCallback triggerCycleCallback,
bool wasSynchronized,
2020-08-26 14:30:13 -07:00
const efitick_t nowNt,
const TriggerWaveform& triggerShape) {
2020-01-24 10:42:09 -08:00
2020-01-26 09:02:54 -08:00
if (triggerCycleCallback) {
triggerCycleCallback(this);
}
startOfCycleNt = nowNt;
resetCurrentCycleState();
if (wasSynchronized) {
incrementTotalEventCounter();
} else {
// We have just synchronized, this is the zeroth revolution
totalRevolutionCounter = 0;
}
totalEventCountBase += triggerShape.getSize();
2019-04-12 19:07:03 -07:00
#if EFI_UNIT_TEST
if (printTriggerDebug) {
printf("onShaftSynchronization index=%d %d\r\n",
currentCycle.current_index,
totalRevolutionCounter);
}
#endif /* EFI_UNIT_TEST */
}
2015-07-10 06:01:56 -07:00
/**
* @brief Trigger decoding happens here
* 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
*/
2020-08-26 14:30:13 -07:00
void TriggerState::decodeTriggerEvent(
const TriggerWaveform& triggerShape,
2020-08-23 22:21:42 -07:00
const TriggerStateCallback triggerCycleCallback,
TriggerStateListener* triggerStateListener,
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) {
ScopePerf perf(PE::DecodeTriggerEvent);
2019-10-11 17:43:21 -07: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();
}
}
bool useOnlyRisingEdgeForTrigger = triggerConfiguration.UseOnlyRisingEdgeForTrigger;
2018-12-25 09:27:34 -08:00
2020-01-27 21:16:33 -08:00
efiAssertVoid(CUSTOM_TRIGGER_UNEXPECTED, signal <= SHAFT_3RD_RISING, "unexpected signal");
2015-07-10 06:01:56 -07:00
trigger_wheel_e triggerWheel = eventIndex[signal];
2016-06-11 20:02:58 -07:00
trigger_value_e type = eventType[signal];
2015-07-10 06:01:56 -07:00
2018-12-25 09:27:34 -08:00
if (!useOnlyRisingEdgeForTrigger && curSignal == prevSignal) {
2015-07-10 06:01:56 -07:00
orderingErrorCounter++;
}
prevSignal = curSignal;
curSignal = signal;
2015-09-08 20:01:07 -07:00
currentCycle.eventCount[triggerWheel]++;
2015-07-10 06:01:56 -07:00
2021-01-01 11:07:52 -08:00
if (toothed_previous_time > nowNt) {
firmwareError(CUSTOM_OBD_93, "toothed_previous_time after nowNt %d %d", toothed_previous_time, nowNt);
}
2019-01-22 20:15:33 -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] =
currentDurationLong > 10 * NT_PER_SECOND ? 10 * NT_PER_SECOND : currentDurationLong;
2015-07-10 06:01:56 -07:00
2016-01-11 14:01:33 -08:00
bool isPrimary = triggerWheel == T_PRIMARY;
2015-07-15 20:07:51 -07:00
if (needToSkipFall(type) || needToSkipRise(type) || (!considerEventForGap())) {
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",
getTrigger_type_e(triggerConfiguration.TriggerType),
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
/**
* For less important events we simply increment the index.
*/
nextTriggerEvent()
;
2015-09-13 13:01:38 -07:00
} else {
#if !EFI_PROD_CODE
2020-07-19 12:47:21 -07:00
if (printTriggerTrace) {
2015-09-22 20:01:31 -07:00
printf("%s event %s %d\r\n",
getTrigger_type_e(triggerConfiguration.TriggerType),
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
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
if (triggerShape.isSynchronizationNeeded) {
2019-09-03 16:30:51 -07:00
currentGap = 1.0 * toothDurations[0] / toothDurations[1];
if (engineConfiguration->debugMode == DBG_TRIGGER_COUNTERS) {
2019-04-12 19:07:03 -07:00
#if EFI_TUNER_STUDIO
tsOutputChannels.debugFloatField6 = currentGap;
tsOutputChannels.debugIntField3 = currentCycle.current_index;
#endif /* EFI_TUNER_STUDIO */
2017-05-12 19:31:02 -07:00
}
2019-07-12 18:31:58 -07:00
bool isSync = true;
for (int i = 0; i < triggerShape.gapTrackingLength; i++) {
bool isGapCondition = cisnan(triggerShape.syncronizationRatioFrom[i]) || (toothDurations[i] > toothDurations[i + 1] * triggerShape.syncronizationRatioFrom[i]
&& toothDurations[i] < toothDurations[i + 1] * triggerShape.syncronizationRatioTo[i]);
2019-07-12 18:31:58 -07:00
isSync &= isGapCondition;
2018-10-28 12:42:15 -07:00
}
2018-10-28 12:42:15 -07:00
isSynchronizationPoint = isSync;
if (isSynchronizationPoint) {
enginePins.debugTriggerSync.toggle();
}
/**
* 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?
* Open question what is 'triggerShape.getSize()' for 60/2 is it 58 or 58*2 or 58*4?
*/
bool silentTriggerError = triggerShape.getSize() > 40 && engineConfiguration->silentTriggerError;
2019-08-24 22:35:36 -07:00
#if EFI_UNIT_TEST
actualSynchGap = 1.0 * toothDurations[0] / toothDurations[1];
#endif /* EFI_UNIT_TEST */
2018-10-28 12:42:15 -07:00
#if EFI_PROD_CODE || EFI_SIMULATOR
if (triggerConfiguration.VerboseTriggerSynchDetails || (someSortOfTriggerError && !silentTriggerError)) {
int rpm = GET_RPM();
floatms_t engineCycleDuration = getEngineCycleDuration(rpm);
2021-05-23 17:06:19 -07:00
if (!engineConfiguration->useOnlyRisingEdgeForTrigger) {
int time = currentCycle.totalTimeNt[0];
efiPrintf("%s duty %f %d",
name,
time / engineCycleDuration,
time
);
2021-05-23 17:06:19 -07:00
}
for (int i = 0;i<triggerShape.gapTrackingLength;i++) {
float ratioFrom = triggerShape.syncronizationRatioFrom[i];
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];
if (cisnan(gap)) {
efiPrintf("index=%d NaN gap, you have noise issues?",
i);
} else {
2021-07-21 20:08:56 -07:00
efiPrintf("%srpm=%d time=%d eventIndex=%d gapIndex=%d: gap=%.3f expected from %.3f to %.3f error=%s",
triggerConfiguration.PrintPrefix,
2020-08-29 14:25:42 -07:00
GET_RPM(),
/* cast is needed to make sure we do not put 64 bit value to stack*/ (int)getTimeNowSeconds(),
2021-05-23 17:06:19 -07:00
currentCycle.current_index,
2018-10-28 12:42:15 -07:00
i,
gap,
ratioFrom,
triggerShape.syncronizationRatioTo[i],
boolToString(someSortOfTriggerError));
}
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];
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,
triggerShape.syncronizationRatioFrom[i],
triggerShape.syncronizationRatioTo[i],
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
unsigned int endOfCycleIndex = triggerShape.getSize() - (triggerConfiguration.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) {
printf("decodeTriggerEvent sync=%d isSynchronizationPoint=%d index=%d size=%d\r\n",
2021-07-03 07:37:03 -07:00
getShaftSynchronized(),
isSynchronizationPoint,
currentCycle.current_index,
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",
getTrigger_type_e(triggerConfiguration.TriggerType),
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) {
2020-01-22 10:25:35 -08:00
if (triggerStateListener) {
triggerStateListener->OnTriggerSyncronization(wasSynchronized);
}
2020-01-24 10:42:09 -08:00
setShaftSynchronized(true);
// this call would update duty cycle values
nextTriggerEvent()
;
2015-07-10 06:01:56 -07:00
onShaftSynchronization(triggerCycleCallback, wasSynchronized, nowNt, triggerShape);
2015-07-10 06:01:56 -07:00
} else { /* if (!isSynchronizationPoint) */
2015-09-23 20:01:40 -07:00
nextTriggerEvent()
;
}
2015-07-10 06:01:56 -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;
2015-09-13 13:01:38 -07:00
}
2021-07-03 07:37:03 -07:00
if (getShaftSynchronized() && !isValidIndex(triggerShape) && triggerStateListener) {
2020-01-26 00:33:45 -08:00
triggerStateListener->OnTriggerInvalidIndex(currentCycle.current_index);
return;
2015-09-25 06:06:35 -07:00
}
if (someSortOfTriggerError) {
if (getTimeNowNt() - lastDecodingErrorTime > NT_PER_SECOND) {
2015-09-25 06:06:35 -07:00
someSortOfTriggerError = false;
}
2015-09-24 19:02:47 -07:00
}
2015-09-13 13:01:38 -07:00
// Needed for early instant-RPM detection
2020-01-22 10:25:35 -08:00
if (triggerStateListener) {
triggerStateListener->OnTriggerStateProperState(nowNt);
}
2015-07-10 06:01:56 -07:00
}
2018-02-05 14:30:19 -08:00
static void onFindIndexCallback(TriggerState *state) {
2015-07-10 06:01:56 -07:00
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
// todo: that's not the best place for this intermediate data storage, fix it!
2015-09-08 20:01:07 -07:00
state->expectedTotalTime[i] = state->currentCycle.totalTimeNt[i];
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.
*
* This function finds the index of synchronization event within TriggerWaveform
2015-07-10 06:01:56 -07:00
*/
uint32_t TriggerState::findTriggerZeroEventIndex(
TriggerWaveform& shape,
const TriggerConfiguration& triggerConfiguration,
const trigger_config_s& triggerConfig) {
UNUSED(triggerConfig);
2019-04-12 19:07:03 -07:00
#if EFI_PROD_CODE
2019-02-23 09:33:49 -08:00
efiAssert(CUSTOM_ERR_ASSERT, getCurrentRemainingStack() > 128, "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
resetTriggerState();
2015-09-13 07:01:39 -07:00
if (shape.shapeDefinitionError) {
2017-02-23 11:00:03 -08:00
return 0;
}
2015-07-10 06:01:56 -07:00
TriggerStimulatorHelper helper;
2020-08-23 22:21:42 -07:00
uint32_t syncIndex = helper.findTriggerSyncPoint(shape,
triggerConfiguration,
*this);
2017-03-04 05:55:53 -08:00
if (syncIndex == EFI_ERROR_CODE) {
return syncIndex;
2015-07-10 06:01:56 -07:00
}
// Assert that we found the sync point on the very first revolution
efiAssert(CUSTOM_ERR_ASSERT, getTotalRevolutionCounter() == 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 */
2015-07-10 06:01:56 -07:00
/**
* Now that we have just located the synch point, we can simulate the whole cycle
* in order to calculate expected duty cycle
*
* todo: add a comment why are we doing '2 * shape->getSize()' here?
*/
2020-08-23 22:21:42 -07:00
helper.assertSyncPositionAndSetDutyCycle(onFindIndexCallback, triggerConfiguration,
syncIndex, *this, shape);
2015-07-10 06:01:56 -07:00
return syncIndex % shape.getSize();
2015-07-10 06:01:56 -07:00
}
#endif /* EFI_SHAFT_POSITION_INPUT */