2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file trigger_decoder.h
|
|
|
|
*
|
|
|
|
* @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-12-05 21:07:27 -08:00
|
|
|
#pragma once
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-09-16 19:26:57 -07:00
|
|
|
#include "global.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "trigger_structure.h"
|
|
|
|
#include "engine_configuration.h"
|
2019-09-03 16:30:51 -07:00
|
|
|
#include "trigger_state_generated.h"
|
2022-08-24 15:11:05 -07:00
|
|
|
#include "trigger_state_primary_generated.h"
|
2021-03-07 13:35:58 -08:00
|
|
|
#include "timer.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2022-09-10 23:16:47 -07:00
|
|
|
const char *getTrigger_event_e(trigger_event_e value);
|
2022-09-10 23:57:35 -07:00
|
|
|
const char *getTrigger_value_e(TriggerValue value);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-02-26 15:16:35 -08:00
|
|
|
struct TriggerStateListener {
|
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
|
|
|
virtual void OnTriggerStateProperState(efitick_t nowNt) = 0;
|
2022-05-10 13:55:28 -07:00
|
|
|
virtual void OnTriggerSyncronization(bool wasSynchronized, bool isDecodingError) = 0;
|
2020-02-26 15:16:35 -08:00
|
|
|
virtual void OnTriggerSynchronizationLost() = 0;
|
2020-08-23 22:21:42 -07:00
|
|
|
#endif // EFI_SHAFT_POSITION_INPUT
|
|
|
|
};
|
|
|
|
|
2021-11-16 13:52:11 -08:00
|
|
|
class TriggerConfiguration {
|
2020-08-23 22:21:42 -07:00
|
|
|
public:
|
2020-10-05 13:42:50 -07:00
|
|
|
explicit TriggerConfiguration(const char* printPrefix) : PrintPrefix(printPrefix) {}
|
|
|
|
void update();
|
|
|
|
|
|
|
|
const char* const PrintPrefix;
|
|
|
|
bool UseOnlyRisingEdgeForTrigger;
|
|
|
|
bool VerboseTriggerSynchDetails;
|
2022-05-30 16:36:47 -07:00
|
|
|
trigger_config_s TriggerType;
|
2020-10-05 13:42:50 -07:00
|
|
|
|
|
|
|
protected:
|
2020-08-23 23:01:50 -07:00
|
|
|
virtual bool isUseOnlyRisingEdgeForTrigger() const = 0;
|
|
|
|
virtual bool isVerboseTriggerSynchDetails() const = 0;
|
2022-05-30 16:36:47 -07:00
|
|
|
virtual trigger_config_s getType() const = 0;
|
2019-12-05 22:57:11 -08:00
|
|
|
};
|
|
|
|
|
2022-09-13 22:53:17 -07:00
|
|
|
class PrimaryTriggerConfiguration final : public TriggerConfiguration {
|
|
|
|
public:
|
|
|
|
PrimaryTriggerConfiguration() : TriggerConfiguration("TRG ") {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool isUseOnlyRisingEdgeForTrigger() const override;
|
|
|
|
bool isVerboseTriggerSynchDetails() const override;
|
|
|
|
trigger_config_s getType() const override;
|
|
|
|
};
|
|
|
|
|
|
|
|
class VvtTriggerConfiguration final : public TriggerConfiguration {
|
|
|
|
public:
|
|
|
|
const int index;
|
|
|
|
|
|
|
|
VvtTriggerConfiguration(const char * prefix, const int index) : TriggerConfiguration(prefix), index(index) {
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool isUseOnlyRisingEdgeForTrigger() const override;
|
|
|
|
bool isVerboseTriggerSynchDetails() const override;
|
|
|
|
trigger_config_s getType() const override;
|
|
|
|
};
|
|
|
|
|
2015-09-08 20:01:07 -07:00
|
|
|
typedef struct {
|
|
|
|
/**
|
|
|
|
* index within trigger revolution, from 0 to trigger event count
|
|
|
|
*/
|
|
|
|
uint32_t current_index;
|
|
|
|
/**
|
2015-09-12 13:01:43 -07:00
|
|
|
* Number of actual events of each channel within current trigger cycle, these
|
|
|
|
* values are used to detect trigger signal errors.
|
2019-12-07 22:09:39 -08:00
|
|
|
* see TriggerWaveform
|
2015-09-08 20:01:07 -07:00
|
|
|
*/
|
2021-07-13 11:50:10 -07:00
|
|
|
size_t eventCount[PWM_PHASE_MAX_WAVE_PER_PWM];
|
2021-04-06 22:21:28 -07:00
|
|
|
|
2015-09-08 20:01:07 -07:00
|
|
|
} current_cycle_state_s;
|
|
|
|
|
2022-05-28 06:01:45 -07:00
|
|
|
struct TriggerDecodeResult {
|
|
|
|
uint32_t CurrentIndex;
|
|
|
|
};
|
|
|
|
|
2018-02-05 14:16:34 -08:00
|
|
|
/**
|
2019-12-07 22:09:39 -08:00
|
|
|
* @see TriggerWaveform for trigger wheel shape definition
|
2018-02-05 14:16:34 -08:00
|
|
|
*/
|
2022-05-10 01:41:39 -07:00
|
|
|
class TriggerDecoderBase : public trigger_state_s {
|
2015-07-10 06:01:56 -07:00
|
|
|
public:
|
2022-05-31 21:55:34 -07:00
|
|
|
TriggerDecoderBase(const char* name);
|
2018-02-05 14:16:34 -08:00
|
|
|
/**
|
|
|
|
* current trigger processing index, between zero and #size
|
|
|
|
*/
|
2019-01-15 17:24:36 -08:00
|
|
|
int getCurrentIndex() const;
|
2022-09-07 19:24:28 -07:00
|
|
|
int getCrankSynchronizationCounter() const;
|
2016-08-23 19:02:18 -07:00
|
|
|
/**
|
|
|
|
* this is important for crank-based virtual trigger and VVT magic
|
|
|
|
*/
|
2022-09-07 18:45:59 -07:00
|
|
|
void incrementShaftSynchronizationCounter();
|
2021-07-05 21:09:35 -07:00
|
|
|
|
2022-09-11 13:08:11 -07:00
|
|
|
int64_t getTotalEventCounter() const;
|
2019-12-05 22:05:19 -08:00
|
|
|
|
2022-05-28 06:01:45 -07:00
|
|
|
expected<TriggerDecodeResult> decodeTriggerEvent(
|
2022-03-21 17:39:47 -07:00
|
|
|
const char *msg,
|
2020-10-05 11:22:59 -07:00
|
|
|
const TriggerWaveform& triggerShape,
|
|
|
|
TriggerStateListener* triggerStateListener,
|
|
|
|
const TriggerConfiguration& triggerConfiguration,
|
2020-08-23 22:21:42 -07:00
|
|
|
const trigger_event_e signal,
|
2022-09-11 13:08:11 -07:00
|
|
|
const efitick_t nowNt);
|
2019-12-05 22:05:19 -08:00
|
|
|
|
2020-08-26 14:30:13 -07:00
|
|
|
void 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);
|
2020-01-26 09:02:54 -08:00
|
|
|
|
2020-10-05 11:22:59 -07:00
|
|
|
bool isValidIndex(const TriggerWaveform& triggerShape) const;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* TRUE if we know where we are
|
|
|
|
*/
|
|
|
|
bool shaft_is_synchronized;
|
2019-12-21 18:11:09 -08:00
|
|
|
efitick_t mostRecentSyncTime;
|
2021-03-07 13:35:58 -08:00
|
|
|
|
|
|
|
Timer previousEventTimer;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-01-26 03:28:33 -08:00
|
|
|
void setTriggerErrorState();
|
|
|
|
|
2018-10-21 09:29:41 -07:00
|
|
|
/**
|
|
|
|
* current duration at index zero and previous durations are following
|
|
|
|
*/
|
2018-10-23 00:47:30 -07:00
|
|
|
uint32_t toothDurations[GAP_TRACKING_LENGTH + 1];
|
2018-10-21 08:27:14 -07:00
|
|
|
|
2019-12-21 18:11:09 -08:00
|
|
|
efitick_t toothed_previous_time;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2015-09-08 20:01:07 -07:00
|
|
|
current_cycle_state_s currentCycle;
|
2022-05-31 21:55:34 -07:00
|
|
|
const char* const name;
|
2017-12-12 15:04:54 -08:00
|
|
|
|
2015-08-17 20:02:01 -07:00
|
|
|
/**
|
|
|
|
* how many times since ECU reboot we had unexpected number of teeth in trigger cycle
|
|
|
|
*/
|
2015-07-10 06:01:56 -07:00
|
|
|
uint32_t totalTriggerErrorCounter;
|
|
|
|
uint32_t orderingErrorCounter;
|
|
|
|
|
2021-12-27 09:09:38 -08:00
|
|
|
virtual void resetTriggerState();
|
2019-08-18 12:53:38 -07:00
|
|
|
void setShaftSynchronized(bool value);
|
2021-07-03 07:37:03 -07:00
|
|
|
bool getShaftSynchronized();
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2016-08-22 20:04:55 -07:00
|
|
|
/**
|
|
|
|
* this is start of real trigger cycle
|
|
|
|
* for virtual double trigger see timeAtVirtualZeroNt
|
|
|
|
*/
|
2016-08-20 19:02:12 -07:00
|
|
|
efitick_t startOfCycleNt;
|
2020-01-21 21:40:26 -08:00
|
|
|
|
2020-10-05 11:22:59 -07:00
|
|
|
uint32_t findTriggerZeroEventIndex(
|
|
|
|
TriggerWaveform& shape,
|
2022-05-30 16:36:47 -07:00
|
|
|
const TriggerConfiguration& triggerConfiguration
|
2020-08-23 23:07:58 -07:00
|
|
|
);
|
2020-01-21 21:40:26 -08:00
|
|
|
|
2022-05-10 13:55:28 -07:00
|
|
|
bool someSortOfTriggerError() const {
|
2022-05-19 06:43:42 -07:00
|
|
|
return !m_timeSinceDecodeError.getElapsedSeconds(1);
|
2022-05-10 13:55:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
// Called when some problem is detected with trigger decoding.
|
|
|
|
// That means either:
|
|
|
|
// - Too many events without a sync point
|
|
|
|
// - Saw a sync point but the wrong number of events in the cycle
|
|
|
|
virtual void onTriggerError() { }
|
|
|
|
|
2022-09-11 12:25:58 -07:00
|
|
|
virtual void onNotEnoughTeeth(int, int) { }
|
|
|
|
virtual void onTooManyTeeth(int, int) { }
|
2022-09-04 06:15:24 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
private:
|
2015-09-08 20:01:07 -07:00
|
|
|
void resetCurrentCycleState();
|
2021-12-30 08:39:04 -08:00
|
|
|
bool isSyncPoint(const TriggerWaveform& triggerShape, trigger_type_e triggerType) const;
|
2015-09-08 20:01:07 -07:00
|
|
|
|
2022-05-10 13:55:28 -07:00
|
|
|
bool validateEventCounters(const TriggerWaveform& triggerShape) const;
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
trigger_event_e prevSignal;
|
2019-12-21 18:11:09 -08:00
|
|
|
int64_t totalEventCountBase;
|
2021-12-09 18:59:51 -08:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
bool isFirstEvent;
|
2022-05-10 13:55:28 -07:00
|
|
|
|
|
|
|
Timer m_timeSinceDecodeError;
|
2015-07-10 06:01:56 -07:00
|
|
|
};
|
|
|
|
|
2019-01-24 18:12:55 -08:00
|
|
|
// we only need 90 degrees of events so /4 or maybe even /8 should work?
|
|
|
|
#define PRE_SYNC_EVENTS (PWM_PHASE_MAX_COUNT / 4)
|
|
|
|
|
2017-05-18 13:39:04 -07:00
|
|
|
|
|
|
|
/**
|
2019-12-05 21:07:27 -08:00
|
|
|
* the reason for sub-class is simply to save RAM but not having statistics in the trigger initialization instance
|
2017-05-18 13:39:04 -07:00
|
|
|
*/
|
2022-08-24 15:11:05 -07:00
|
|
|
class PrimaryTriggerDecoder : public TriggerDecoderBase, public trigger_state_primary_s {
|
2017-05-18 13:16:55 -07:00
|
|
|
public:
|
2022-05-31 21:55:34 -07:00
|
|
|
PrimaryTriggerDecoder(const char* name);
|
2021-12-27 09:09:38 -08:00
|
|
|
void resetTriggerState() override;
|
2021-01-14 17:45:55 -08:00
|
|
|
|
2022-06-09 14:21:22 -07:00
|
|
|
void resetHasFullSync() {
|
|
|
|
// If this trigger doesn't need disambiguation, we already have phase sync
|
|
|
|
m_hasSynchronizedPhase = !m_needsDisambiguation;
|
|
|
|
}
|
|
|
|
|
2022-05-09 12:46:36 -07:00
|
|
|
angle_t syncEnginePhase(int divider, int remainder, angle_t engineCycle);
|
|
|
|
|
2021-01-14 17:45:55 -08:00
|
|
|
float getInstantRpm() const {
|
|
|
|
return m_instantRpm;
|
|
|
|
}
|
|
|
|
|
2017-12-03 20:58:48 -08:00
|
|
|
/**
|
|
|
|
* timestamp of each trigger wheel tooth
|
|
|
|
*/
|
2017-05-18 13:16:55 -07:00
|
|
|
uint32_t timeOfLastEvent[PWM_PHASE_MAX_COUNT];
|
2019-01-24 18:12:55 -08:00
|
|
|
|
|
|
|
int spinningEventIndex = 0;
|
|
|
|
// todo: change the implementation to reuse 'timeOfLastEvent'
|
|
|
|
uint32_t spinningEvents[PRE_SYNC_EVENTS];
|
2017-12-03 20:58:48 -08:00
|
|
|
/**
|
|
|
|
* instant RPM calculated at this trigger wheel tooth
|
|
|
|
*/
|
2017-05-18 13:16:55 -07:00
|
|
|
float instantRpmValue[PWM_PHASE_MAX_COUNT];
|
2018-03-10 17:58:51 -08:00
|
|
|
/**
|
|
|
|
* Stores last non-zero instant RPM value to fix early instability
|
|
|
|
*/
|
2019-01-13 20:20:19 -08:00
|
|
|
float prevInstantRpmValue = 0;
|
2021-11-16 01:15:29 -08:00
|
|
|
void movePreSynchTimestamps();
|
2021-01-14 17:45:55 -08:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
|
2021-11-09 04:03:27 -08:00
|
|
|
void updateInstantRpm(
|
|
|
|
TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
|
2021-11-16 01:15:29 -08:00
|
|
|
uint32_t index, efitick_t nowNt);
|
2019-01-31 14:55:23 -08:00
|
|
|
#endif
|
2018-03-10 17:58:51 -08:00
|
|
|
/**
|
|
|
|
* Update timeOfLastEvent[] on every trigger event - even without synchronization
|
|
|
|
* Needed for early spin-up RPM detection.
|
|
|
|
*/
|
2021-11-16 01:15:29 -08:00
|
|
|
void setLastEventTimeForInstantRpm(efitick_t nowNt);
|
2021-01-14 17:45:55 -08:00
|
|
|
|
2022-05-09 12:46:36 -07:00
|
|
|
// Returns true if syncEnginePhase has been called,
|
|
|
|
// i.e. if we have enough VVT information to have full sync on
|
|
|
|
// an indeterminite crank pattern
|
|
|
|
bool hasSynchronizedPhase() const {
|
2022-05-09 21:52:29 -07:00
|
|
|
return m_hasSynchronizedPhase;
|
2022-05-09 12:46:36 -07:00
|
|
|
}
|
|
|
|
|
2022-06-09 14:21:22 -07:00
|
|
|
void setNeedsDisambiguation(bool needsDisambiguation) {
|
|
|
|
m_needsDisambiguation = needsDisambiguation;
|
|
|
|
|
|
|
|
resetHasFullSync();
|
|
|
|
}
|
|
|
|
|
2022-05-10 13:55:28 -07:00
|
|
|
void onTriggerError() override;
|
|
|
|
|
2022-09-04 06:15:24 -07:00
|
|
|
void onNotEnoughTeeth(int actual, int expected) override;
|
|
|
|
void onTooManyTeeth(int actual, int expected) override;
|
|
|
|
|
2021-01-14 17:45:55 -08:00
|
|
|
private:
|
2021-11-09 04:03:27 -08:00
|
|
|
float calculateInstantRpm(
|
|
|
|
TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
|
2021-11-16 01:15:29 -08:00
|
|
|
uint32_t index, efitick_t nowNt);
|
2021-01-14 17:45:55 -08:00
|
|
|
|
2022-09-06 18:38:35 -07:00
|
|
|
void resetInstantRpm();
|
|
|
|
|
2021-01-14 17:45:55 -08:00
|
|
|
float m_instantRpm = 0;
|
|
|
|
float m_instantRpmRatio = 0;
|
|
|
|
|
2022-06-09 14:21:22 -07:00
|
|
|
bool m_needsDisambiguation = false;
|
2017-05-18 13:16:55 -07:00
|
|
|
};
|
|
|
|
|
2022-05-31 21:55:34 -07:00
|
|
|
class VvtTriggerDecoder : public TriggerDecoderBase {
|
|
|
|
public:
|
|
|
|
VvtTriggerDecoder(const char* name) : TriggerDecoderBase(name) { }
|
2022-09-04 06:15:24 -07:00
|
|
|
|
|
|
|
void onNotEnoughTeeth(int actual, int expected) override;
|
|
|
|
void onTooManyTeeth(int actual, int expected) override;
|
2022-05-31 21:55:34 -07:00
|
|
|
};
|
2022-05-10 01:41:39 -07:00
|
|
|
|
2016-01-14 21:01:42 -08:00
|
|
|
angle_t getEngineCycle(operation_mode_e operationMode);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void prepareEventAngles(TriggerWaveform *shape, TriggerFormDetails *details);
|