| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | /** | |||
| 2 | * @file trigger_structure.h | |||
| 3 | * | |||
| 4 | * rusEFI defines trigger shape programmatically in C code | |||
| 5 | * For integration we have exportAllTriggers export | |||
| 6 | * | |||
| 7 | * @date Dec 22, 2013 | |||
| 8 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
| 9 | */ | |||
| 10 | ||||
| 11 | #pragma once | |||
| 12 | ||||
| 13 | #include "state_sequence.h" | |||
| 14 | ||||
| 15 | #define FOUR_STROKE_ENGINE_CYCLE 720 | |||
| 16 | ||||
| 17 | #define TRIGGER_GAP_DEVIATION 0.25f | |||
| 18 | #define TRIGGER_GAP_DEVIATION_LOW (1.0f - TRIGGER_GAP_DEVIATION) | |||
| 19 | #define TRIGGER_GAP_DEVIATION_HIGH (1.0f + TRIGGER_GAP_DEVIATION) | |||
| 20 | ||||
| 21 | #if EFI_ENABLE_ASSERTS | |||
| 22 | #define assertAngleRange(angle, msg, code) if (angle > 10000000 || angle < -10000000) { firmwareError(code, "angle range %s %d", msg, (int)angle);angle = 0;} | |||
| 23 | #else | |||
| 24 | #define assertAngleRange(angle, msg, code) {UNUSED(code);} | |||
| 25 | #endif | |||
| 26 | ||||
| 27 | // Shifts angle into the [0..720) range for four stroke and [0..360) for two stroke | |||
| 28 | // See also wrapVvt | |||
| 29 | void wrapAngle(angle_t& angle, const char* msg, ObdCode code); | |||
| 30 | ||||
| 31 | // proper method avoids un-wrapped state of variables | |||
| 32 | 33847 | inline angle_t wrapAngleMethod(angle_t param, const char *msg = "", ObdCode code = ObdCode::OBD_PCM_Processor_Fault) { | ||
| 33 | 33847 | wrapAngle(param, msg, code); | ||
| 34 | 33847 | return param; | ||
| 35 | } | |||
| 36 | ||||
| 37 | class TriggerDecoderBase; | |||
| 38 | class TriggerFormDetails; | |||
| 39 | class TriggerConfiguration; | |||
| 40 | ||||
| 41 | #include "sync_edge.h" | |||
| 42 | ||||
| 43 | /** | |||
| 44 | * @brief Trigger shape has all the fields needed to describe and decode trigger signal. | |||
| 45 | * @see TriggerState for trigger decoder state which works based on this trigger shape model | |||
| 46 | */ | |||
| 47 | class TriggerWaveform { | |||
| 48 | public: | |||
| 49 | TriggerWaveform(); | |||
| 50 | void initializeTriggerWaveform(operation_mode_e triggerOperationMode, const trigger_config_s &triggerType, bool isCrankWheel = true); | |||
| 51 | void setShapeDefinitionError(bool value); | |||
| 52 | ||||
| 53 | /** | |||
| 54 | * Simplest trigger shape does not require any synchronization - for example if there is only | |||
| 55 | * one primary channel tooth each raising (or falling depending on configuration) front would synchronize | |||
| 56 | */ | |||
| 57 | bool isSynchronizationNeeded; | |||
| 58 | ||||
| 59 | /** | |||
| 60 | * trigger meta information: is second wheel mounted on crank shaft ('false') or cam shaft ('true') | |||
| 61 | */ | |||
| 62 | bool isSecondWheelCam; | |||
| 63 | /** | |||
| 64 | * number of consecutive trigger gaps needed to synchronize | |||
| 65 | */ | |||
| 66 | int gapTrackingLength = 1; | |||
| 67 | /** | |||
| 68 | * special case for triggers which do not provide exact TDC location | |||
| 69 | * For example pick-up in distributor with mechanical ignition firing order control. | |||
| 70 | */ | |||
| 71 | bool shapeWithoutTdc = false; | |||
| 72 | /** | |||
| 73 | * this flag tells us if we should ignore events on second input channel | |||
| 74 | * that's the way to ignore noise from the disconnected wire | |||
| 75 | */ | |||
| 76 | bool needSecondTriggerInput = false; | |||
| 77 | /** | |||
| 78 | * true value here means that we do not have a valid trigger configuration | |||
| 79 | */ | |||
| 80 | bool shapeDefinitionError = false; | |||
| 81 | ||||
| 82 | /** | |||
| 83 | * this variable is incremented after each trigger shape redefinition | |||
| 84 | */ | |||
| 85 | int version = 0; | |||
| 86 | ||||
| 87 | /** | |||
| 88 | * Depending on trigger shape, we use between one and three previous gap ranges to detect synchronization. | |||
| 89 | * | |||
| 90 | * Usually second or third gap is not needed, but some crazy triggers like 36-2-2-2 require two consecutive | |||
| 91 | * gaps ratios to sync | |||
| 92 | */ | |||
| 93 | ||||
| 94 | float synchronizationRatioFrom[GAP_TRACKING_LENGTH]; | |||
| 95 | float synchronizationRatioTo[GAP_TRACKING_LENGTH]; | |||
| 96 | ||||
| 97 | ||||
| 98 | /** | |||
| 99 | * used by NoiselessTriggerDecoder (See TriggerCentral::handleShaftSignal()) | |||
| 100 | */ | |||
| 101 | int syncRatioAvg; | |||
| 102 | ||||
| 103 | ||||
| 104 | /** | |||
| 105 | * Trigger indexes within trigger cycle are counted from synchronization point, and all | |||
| 106 | * engine processes are defined in angles from TDC. | |||
| 107 | * | |||
| 108 | * That's the angle distance from trigger event #0 and actual engine TDC | |||
| 109 | * | |||
| 110 | * see also globalTriggerAngleOffset | |||
| 111 | */ | |||
| 112 | angle_t tdcPosition; | |||
| 113 | ||||
| 114 | /** | |||
| 115 | * In case of a multi-channel trigger, do we want to sync based on primary channel only? | |||
| 116 | * See also gapBothDirections | |||
| 117 | */ | |||
| 118 | bool useOnlyPrimaryForSync; | |||
| 119 | ||||
| 120 | // Which edge(s) to consider for finding the sync point: rise, fall, or both | |||
| 121 | SyncEdge syncEdge; | |||
| 122 | ||||
| 123 | // If true, falling edges should be fully ignored on this trigger shape. | |||
| 124 | bool useOnlyRisingEdges; | |||
| 125 | ||||
| 126 | void calculateExpectedEventCounts(); | |||
| 127 | ||||
| 128 | size_t getExpectedEventCount(TriggerWheel channelIndex) const; | |||
| 129 | ||||
| 130 | /** | |||
| 131 | * This is used for signal validation | |||
| 132 | */ | |||
| 133 | size_t expectedEventCount[PWM_PHASE_MAX_WAVE_PER_PWM]; | |||
| 134 | ||||
| 135 | #if EFI_UNIT_TEST | |||
| 136 | /** | |||
| 137 | * These signals are used for trigger export only | |||
| 138 | */ | |||
| 139 | TriggerWheel triggerSignalIndeces[PWM_PHASE_MAX_COUNT]; | |||
| 140 | TriggerValue triggerSignalStates[PWM_PHASE_MAX_COUNT]; | |||
| 141 | // see also 'doesTriggerImplyOperationMode' | |||
| 142 | // todo: reuse doesTriggerImplyOperationMode instead of separate field only which is only used for metadata anyway? | |||
| 143 | bool knownOperationMode = true; | |||
| 144 | #endif | |||
| 145 | ||||
| 146 | /** | |||
| 147 | * wave.phaseCount is total count of shaft events per CAM or CRANK shaft revolution. | |||
| 148 | * TODO this should be migrated to CRANKshaft revolution, this would go together | |||
| 149 | * this variable is public for performance reasons (I want to avoid costs of method if it's not inlined) | |||
| 150 | * but name is supposed to hint at the fact that decoders should not be assigning to it | |||
| 151 | * Please use "getSize()" function to read this value | |||
| 152 | */ | |||
| 153 | MultiChannelStateSequenceWithData<PWM_PHASE_MAX_COUNT> wave; | |||
| 154 | ||||
| 155 | bool isRiseEvent[PWM_PHASE_MAX_COUNT]; | |||
| 156 | ||||
| 157 | /** | |||
| 158 | * @param angle (0..1] | |||
| 159 | */ | |||
| 160 | void addEvent(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex = TriggerWheel::T_PRIMARY); | |||
| 161 | /* (0..720] angle range | |||
| 162 | * Deprecated! many usages should be replaced by addEvent360 | |||
| 163 | */ | |||
| 164 | void addEvent720(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex = TriggerWheel::T_PRIMARY); | |||
| 165 | ||||
| 166 | /** | |||
| 167 | * this method helps us use real world 360 degrees shape for FOUR_STROKE_CAM_SENSOR and FOUR_STROKE_CRANK_SENSOR | |||
| 168 | */ | |||
| 169 | void addEvent360(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex = TriggerWheel::T_PRIMARY); | |||
| 170 | ||||
| 171 | void addToothRiseFall(angle_t angle, angle_t width = 10, TriggerWheel const channelIndex = TriggerWheel::T_PRIMARY); | |||
| 172 | // fun: yet another inconsistency, right?! | |||
| 173 | void addToothFallRise(angle_t angle, angle_t width = 10, TriggerWheel const channelIndex = TriggerWheel::T_PRIMARY); | |||
| 174 | ||||
| 175 | /** | |||
| 176 | * This version of the method is best when same wheel could be mounted either on crank or cam | |||
| 177 | * | |||
| 178 | * This version of 'addEvent...' family considers the angle duration of operationMode in this trigger | |||
| 179 | * For example, (0..180] for FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR | |||
| 180 | * | |||
| 181 | * TODO: one day kill all usages with FOUR_STROKE_CAM_SENSOR 720 cycle and add runtime prohibition | |||
| 182 | * TODO: for FOUR_STROKE_CAM_SENSOR addEvent360 is the way to go | |||
| 183 | * | |||
| 184 | * @param angle (0..360] or (0..720] depending on configuration | |||
| 185 | */ | |||
| 186 | void addEventAngle(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex = TriggerWheel::T_PRIMARY); | |||
| 187 | ||||
| 188 | /* (0..720] angle range | |||
| 189 | * Deprecated? | |||
| 190 | */ | |||
| 191 | void addEventClamped(angle_t angle, TriggerValue const state, TriggerWheel const channelIndex, float filterLeft, float filterRight); | |||
| 192 | operation_mode_e getWheelOperationMode() const; | |||
| 193 | ||||
| 194 | void initialize(operation_mode_e operationMode, SyncEdge syncEdge); | |||
| 195 | void setTriggerSynchronizationGap(float syncRatio); | |||
| 196 | /** | |||
| 197 | * note that index is in reverse order comparing with chronological order on the documentation images | |||
| 198 | * https://github.com/rusefi/rusefi/wiki/All-Supported-Triggers | |||
| 199 | */ | |||
| 200 | void setTriggerSynchronizationGap3(int index, float syncRatioFrom, float syncRatioTo); | |||
| 201 |
1/1✓ Decision 'true' taken 4007 times.
|
4007 | void setTriggerSynchronizationGap4(int index, float syncRatio) { | |
| 202 | 4007 | setTriggerSynchronizationGap3(index, syncRatio * TRIGGER_GAP_DEVIATION_LOW, syncRatio * TRIGGER_GAP_DEVIATION_HIGH); | ||
| 203 | 4007 | } | ||
| 204 | void setTriggerSynchronizationGap2(float syncRatioFrom, float syncRatioTo); | |||
| 205 | void setSecondTriggerSynchronizationGap(float syncRatio); | |||
| 206 | void setSecondTriggerSynchronizationGap2(float syncRatioFrom, float syncRatioTo); | |||
| 207 | void setThirdTriggerSynchronizationGap(float syncRatio); | |||
| 208 | /** | |||
| 209 | * this one is per CRANKshaft revolution | |||
| 210 | */ | |||
| 211 | size_t getLength() const; | |||
| 212 | size_t getSize() const; | |||
| 213 | ||||
| 214 | int getTriggerWaveformSynchPointIndex() const; | |||
| 215 | ||||
| 216 | /** | |||
| 217 | * This private method should only be used to prepare the array of pre-calculated values | |||
| 218 | * See eventAngles array | |||
| 219 | */ | |||
| 220 | angle_t getAngle(int phaseIndex) const; | |||
| 221 | ||||
| 222 | angle_t getCycleDuration() const; | |||
| 223 | ||||
| 224 | // Returns true if this trigger alone can fully sync the current engine for sequential mode. | |||
| 225 | bool needsDisambiguation() const; | |||
| 226 | ||||
| 227 | /** | |||
| 228 | * index of synchronization event within TriggerWaveform | |||
| 229 | * See findTriggerZeroEventIndex() | |||
| 230 | */ | |||
| 231 | int triggerShapeSynchPointIndex; | |||
| 232 | ||||
| 233 | void initializeSyncPoint( | |||
| 234 | TriggerDecoderBase& state, | |||
| 235 | const TriggerConfiguration& triggerConfiguration | |||
| 236 | ); | |||
| 237 | ||||
| 238 | uint16_t findAngleIndex(TriggerFormDetails *details, angle_t angle) const; | |||
| 239 | ||||
| 240 | /** | |||
| 241 | * These angles are in trigger DESCRIPTION coordinates - i.e. the way you add events while declaring trigger shape | |||
| 242 | */ | |||
| 243 | angle_t getSwitchAngle(int index) const; | |||
| 244 | private: | |||
| 245 | ||||
| 246 | /** | |||
| 247 | * This variable is used to confirm that events are added in the right order. | |||
| 248 | * todo: this variable is probably not needed, could be reimplemented by accessing by index | |||
| 249 | */ | |||
| 250 | angle_t previousAngle; | |||
| 251 | /** | |||
| 252 | * this is part of performance optimization | |||
| 253 | */ | |||
| 254 | operation_mode_e operationMode; | |||
| 255 | }; | |||
| 256 | ||||
| 257 | /** | |||
| 258 | * Misc values calculated from TriggerWaveform | |||
| 259 | */ | |||
| 260 | class TriggerFormDetails { | |||
| 261 | public: | |||
| 262 | void prepareEventAngles(TriggerWaveform *shape); | |||
| 263 | ||||
| 264 | /** | |||
| 265 | * These angles are in event coordinates - with synchronization point located at angle zero. | |||
| 266 | * These values are pre-calculated for performance reasons. | |||
| 267 | */ | |||
| 268 | angle_t eventAngles[2 * PWM_PHASE_MAX_COUNT]; | |||
| 269 | }; | |||
| 270 |