Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | #pragma once | |||
2 | ||||
3 | #include "shutdown_controller.h" | |||
4 | #include "max_limit_with_hysteresis.h" | |||
5 | ||||
6 | #include <cstdint> | |||
7 | ||||
8 | // Keep this list in sync with fuelIgnCutCodeList in tunerstudio.template.ini! | |||
9 | enum class ClearReason : uint8_t { | |||
10 | None, // 0 | |||
11 | Fatal, // 1 | |||
12 | Settings, // 2 | |||
13 | HardLimit, // 3 | |||
14 | EtbFaultRevLimit, // 4 means 1500 RPM limit in case of ETB fault | |||
15 | BoostCut, // 5 | |||
16 | OilPressure, // 6 | |||
17 | StopRequested, // 7 | |||
18 | EtbProblem, // 8 | |||
19 | LaunchCut, // 9 | |||
20 | InjectorDutyCycle, // 10 | |||
21 | FloodClear, // 11 | |||
22 | EnginePhase, // 12 | |||
23 | KickStart, // 13 | |||
24 | IgnitionOff, // 14 | |||
25 | Lua, // 15 | |||
26 | ACR, // 16 - Harley Automatic Compression Release | |||
27 | LambdaProtection, // 17 | |||
28 | GdiComms, // 18 | |||
29 | PleaseBrake, // 19 | |||
30 | FatalErrorRevLimit, // 20 | |||
31 | GdiLimits, // 21 | |||
32 | GdiPumpLimit, // 22 | |||
33 | ||||
34 | // Keep this list in sync with fuelIgnCutCodeList in tunerstudio.template.ini! | |||
35 | // todo: add a code generator between ClearReason and fuelIgnCutCodeList in tunerstudio.template.ini | |||
36 | }; | |||
37 | ||||
38 | enum class EtbStatus : uint8_t { | |||
39 | None, // 0 | |||
40 | EngineStopped, // 1 | |||
41 | TpsError, // 2 | |||
42 | PpsError, // 3 | |||
43 | IntermittentTps, // 4 | |||
44 | AutoTune, // 5 | |||
45 | Lua, // 6 | |||
46 | AutoCalibrate, // 7 | |||
47 | NotConfigured, // 8 | |||
48 | Redundancy, // 9 | |||
49 | IntermittentPps, // 10 | |||
50 | JamDetected, // 11 | |||
51 | // keep this list in sync with etbCutCodeList in tunerstudio.template.ini! | |||
52 | }; | |||
53 | ||||
54 | // Only allows clearing the value, but never resetting it. | |||
55 | class Clearable { | |||
56 | public: | |||
57 | 2752 | Clearable() : m_value(true) {} | ||
58 | 3706 | Clearable(bool value) : m_value(value) { | ||
59 |
2/2✓ Branch 0 taken 107 times.
✓ Branch 1 taken 3599 times.
|
2/2✓ Decision 'true' taken 107 times.
✓ Decision 'false' taken 3599 times.
|
3706 | if (!m_value) { |
60 | 107 | clearReason = ClearReason::Settings; | ||
61 | } | |||
62 | 3706 | } | ||
63 | ||||
64 | 112 | void clear(ClearReason p_clearReason) { | ||
65 |
1/2✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 112 times.
✗ Decision 'false' not taken.
|
112 | if (m_value) { |
66 | 112 | m_value = false; | ||
67 | 112 | clearReason = p_clearReason; | ||
68 | } | |||
69 | 112 | } | ||
70 | ||||
71 | 193388 | operator bool() const { | ||
72 | 193388 | return m_value; | ||
73 | } | |||
74 | ||||
75 | ClearReason clearReason = ClearReason::None; | |||
76 | private: | |||
77 | bool m_value = true; | |||
78 | }; | |||
79 | ||||
80 | struct LimpState { | |||
81 | const bool value; | |||
82 | const ClearReason reason; | |||
83 | ||||
84 | // Implicit conversion operator to bool, so you can do things like if (myResult) { ... } | |||
85 | 61 | constexpr explicit operator bool() const { | ||
86 | 61 | return value; | ||
87 | } | |||
88 | }; | |||
89 | ||||
90 | class LimpManager : public EngineModule { | |||
91 | public: | |||
92 | ShutdownController shutdownController; | |||
93 | // Mockable<> interface | |||
94 | using interface_t = LimpManager; | |||
95 | ||||
96 | // This is called from periodicFastCallback to update internal state | |||
97 | void updateState(float rpm, efitick_t nowNt); | |||
98 | ||||
99 | void onFastCallback() override; | |||
100 | void onIgnitionStateChanged(bool ignitionOn) override; | |||
101 | ||||
102 | // Other subsystems call these APIs to determine their behavior | |||
103 | bool allowElectronicThrottle() const; | |||
104 | ||||
105 | LimpState allowInjection() const; | |||
106 | LimpState allowIgnition() const; | |||
107 | ||||
108 | float getTimeSinceAnyCut() const; | |||
109 | ||||
110 | bool allowTriggerInput() const; | |||
111 | ||||
112 | void updateRevLimit(float rpm); | |||
113 | angle_t getLimitingTimingRetard() const; | |||
114 | float getLimitingFuelCorrection() const; | |||
115 | ||||
116 | // Other subsystems call these APIs to indicate a problem has occurred | |||
117 | void reportEtbProblem(); | |||
118 | void fatalError(); | |||
119 | Timer externalGdiCanBusComms; | |||
120 | ||||
121 | private: | |||
122 | void setFaultRevLimit(int limit, ClearReason rpmLimitReason); | |||
123 | ||||
124 | Hysteresis m_revLimitHysteresis; | |||
125 | MaxLimitWithHysteresis<> m_boostCutHysteresis; | |||
126 | Hysteresis m_injectorDutyCutHysteresis; | |||
127 | ||||
128 | // Start with no fault rev limit | |||
129 | int32_t m_faultRevLimit = INT32_MAX; | |||
130 | ||||
131 | Clearable m_allowEtb; | |||
132 | Clearable m_allowInjection; | |||
133 | Clearable m_allowIgnition; | |||
134 | Clearable m_allowTriggerInput; | |||
135 | ||||
136 | Clearable m_transientAllowInjection = true; | |||
137 | Clearable m_transientAllowIgnition = true; | |||
138 | ||||
139 | bool m_hadOilPressureAfterStart = false; | |||
140 | ||||
141 | // Ignition switch state | |||
142 | bool m_ignitionOn = false; | |||
143 | ||||
144 | angle_t m_timingRetard = 0; | |||
145 | float m_fuelCorrection = 1.0f; | |||
146 | ||||
147 | // todo: migrate to engineState->desiredRpmLimit to get this variable logged | |||
148 | float m_revLimit; | |||
149 | ClearReason m_rpmLimitReason = ClearReason::None; | |||
150 | float resumeRpm; | |||
151 | ||||
152 | // Tracks how long since a cut (ignition or fuel) was active for any reason | |||
153 | Timer m_lastCutTime; | |||
154 | ||||
155 | // Tracks how long injector duty has been over the sustained limit | |||
156 | Timer m_injectorDutySustainedTimer; | |||
157 | ||||
158 | // Tracks how long oil pressure has been out of thresholds | |||
159 | Timer m_lowOilPressureTimer; | |||
160 | Timer m_highOilPressureTimer; | |||
161 | }; | |||
162 | ||||
163 | #if EFI_ENGINE_CONTROL | |||
164 | LimpManager * getLimpManager(); | |||
165 | #endif // EFI_ENGINE_CONTROL | |||
166 | ||||
167 | ||||
168 |