Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /** | |||
2 | * @file efi_gpio.cpp | |||
3 | * @brief EFI-related GPIO code | |||
4 | * | |||
5 | * @date Sep 26, 2014 | |||
6 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
7 | */ | |||
8 | ||||
9 | #include "pch.h" | |||
10 | #include "bench_test.h" | |||
11 | #include "engine_sniffer.h" | |||
12 | ||||
13 | #include "drivers/gpio/gpio_ext.h" | |||
14 | ||||
15 | #if HW_HELLEN | |||
16 | #include "hellen_all_meta.h" | |||
17 | #endif // HW_HELLEN | |||
18 | ||||
19 | #if EFI_ELECTRONIC_THROTTLE_BODY | |||
20 | #include "electronic_throttle.h" | |||
21 | #endif /* EFI_ELECTRONIC_THROTTLE_BODY */ | |||
22 | ||||
23 | // todo: clean this mess, this should become 'static'/private | |||
24 | EnginePins enginePins; | |||
25 | ||||
26 | static const char* const sparkNames[] = { "Coil 1", "Coil 2", "Coil 3", "Coil 4", "Coil 5", "Coil 6", "Coil 7", "Coil 8", | |||
27 | "Coil 9", "Coil 10", "Coil 11", "Coil 12"}; | |||
28 | ||||
29 | static const char* const trailNames[] = { "Trail 1", "Trail 2", "Trail 3", "Trail 4", "Trail 5", "Trail 6", "Trail 7", "Trail 8", | |||
30 | "Trail 9", "Trail 10", "Trail 11", "Trail 12"}; | |||
31 | ||||
32 | static const char* const trailShortNames[] = { "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "rA", "rB", "rD" }; | |||
33 | ||||
34 | const char *vvtNames[] = { | |||
35 | "VVT1", | |||
36 | "VVT2", | |||
37 | "VVT3", | |||
38 | "VVT4"}; | |||
39 | ||||
40 | const char *laNames[] = { | |||
41 | "input1", | |||
42 | "input2", | |||
43 | "input3", | |||
44 | "input4"}; | |||
45 | ||||
46 | // these short names are part of engine sniffer protocol | |||
47 | static const char* const sparkShortNames[] = { PROTOCOL_COIL_SHORT_PREFIX "1", PROTOCOL_COIL_SHORT_PREFIX "2", "c3", "c4", "c5", "c6", "c7", "c8", | |||
48 | "c9", "cA", "cB", "cD"}; | |||
49 | ||||
50 | static const char* const injectorNames[] = { "Injector 1", "Injector 2", "Injector 3", "Injector 4", "Injector 5", "Injector 6", | |||
51 | "Injector 7", "Injector 8", "Injector 9", "Injector 10", "Injector 11", "Injector 12"}; | |||
52 | ||||
53 | static const char* const injectorShortNames[] = { PROTOCOL_INJ_SHORT_PREFIX "1", PROTOCOL_INJ_SHORT_PREFIX "2", "i3", "i4", "i5", "i6", "i7", "i8", | |||
54 | "i9", "iA", "iB", "iC"}; | |||
55 | ||||
56 | static const char* const injectorStage2Names[] = { "Injector Second Stage 1", "Injector Second Stage 2", "Injector Second Stage 3", "Injector Second Stage 4", "Injector Second Stage 5", "Injector Second Stage 6", | |||
57 | "Injector Second Stage 7", "Injector Second Stage 8", "Injector Second Stage 9", "Injector Second Stage 10", "Injector Second Stage 11", "Injector Second Stage 12"}; | |||
58 | ||||
59 | static const char* const injectorStage2ShortNames[] = { PROTOCOL_INJ_STAGE2_SHORT_PREFIX "1", PROTOCOL_INJ_STAGE2_SHORT_PREFIX "2", "j3", "j4", "j5", "j6", "j7", "j8", | |||
60 | "j9", "jA", "jB", "jC"}; | |||
61 | ||||
62 | static const char* const auxValveShortNames[] = { "a1", "a2"}; | |||
63 | ||||
64 | static RegisteredOutputPin * registeredOutputHead = nullptr; | |||
65 | ||||
66 | 1 | RegisteredNamedOutputPin::RegisteredNamedOutputPin(const char *p_name, size_t pinOffset, | ||
67 | 1 | size_t pinModeOffset) : RegisteredOutputPin(p_name, pinOffset, pinModeOffset) { | ||
68 | 1 | } | ||
69 | ||||
70 | ✗ | RegisteredNamedOutputPin::RegisteredNamedOutputPin(const char *p_name, size_t pinOffset) : | ||
71 | ✗ | RegisteredOutputPin(p_name, pinOffset) { | ||
72 | ✗ | } | ||
73 | ||||
74 | 17 | RegisteredOutputPin::RegisteredOutputPin(const char *p_registrationName, size_t pinOffset, | ||
75 | 16 | size_t pinModeOffset) | ||
76 | 17 | : next(registeredOutputHead) | ||
77 | 17 | , registrationName(p_registrationName) | ||
78 | 17 | , m_pinOffset(static_cast<uint16_t>(pinOffset)) | ||
79 | 17 | , m_hasPinMode(true) | ||
80 | 17 | , m_pinModeOffset(static_cast<uint16_t>(pinModeOffset)) | ||
81 | { | |||
82 | // adding into head of the list is so easy and since we do not care about order that's what we shall do | |||
83 | 17 | registeredOutputHead = this; | ||
84 | 17 | } | ||
85 | ||||
86 | 1 | RegisteredOutputPin::RegisteredOutputPin(const char *p_registrationName, size_t pinOffset) | ||
87 | 1 | : next(registeredOutputHead) | ||
88 | 1 | , registrationName(p_registrationName) | ||
89 | 1 | , m_pinOffset(static_cast<uint16_t>(pinOffset)) | ||
90 | 1 | , m_hasPinMode(false) | ||
91 | 1 | , m_pinModeOffset(-1) | ||
92 | { | |||
93 | // adding into head of the list is so easy and since we do not care about order that's what we shall do | |||
94 | 1 | registeredOutputHead = this; | ||
95 | 1 | } | ||
96 | ||||
97 | 49861 | bool RegisteredOutputPin::isPinConfigurationChanged() { | ||
98 | 49861 | brain_pin_e curPin = *(brain_pin_e *) ((void *) (&((char*)&activeConfiguration)[m_pinOffset])); | ||
99 | 49861 | brain_pin_e newPin = *(brain_pin_e *) ((void *) (&((char*) engineConfiguration)[m_pinOffset])); | ||
100 | 49861 | bool pinChanged = curPin != newPin; | ||
101 | ||||
102 |
2/2✓ Branch 0 taken 2770 times.
✓ Branch 1 taken 47091 times.
|
2/2✓ Decision 'true' taken 2770 times.
✓ Decision 'false' taken 47091 times.
|
49861 | if (!m_hasPinMode) { |
103 | 2770 | return pinChanged; | ||
104 | } | |||
105 | ||||
106 | 47091 | pin_output_mode_e curMode = *(pin_output_mode_e *) ((void *) (&((char*)&activeConfiguration)[m_pinModeOffset])); | ||
107 | 47091 | pin_output_mode_e newMode = *(pin_output_mode_e *) ((void *) (&((char*) engineConfiguration)[m_pinModeOffset])); | ||
108 |
3/4✓ Branch 0 taken 46971 times.
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46971 times.
|
47091 | return pinChanged || curMode != newMode; | |
109 | } | |||
110 | ||||
111 | 24931 | void RegisteredOutputPin::init() { | ||
112 | 24931 | brain_pin_e newPin = *(brain_pin_e *) ((void *) (&((char*) engineConfiguration)[m_pinOffset])); | ||
113 | ||||
114 | pin_output_mode_e newMode; | |||
115 |
2/2✓ Branch 0 taken 23546 times.
✓ Branch 1 taken 1385 times.
|
2/2✓ Decision 'true' taken 23546 times.
✓ Decision 'false' taken 1385 times.
|
24931 | if (m_hasPinMode) { |
116 | 23546 | newMode = *(pin_output_mode_e *) ((void *) (&((char*) engineConfiguration)[m_pinModeOffset])); | ||
117 | } else { | |||
118 | 1385 | newMode = OM_DEFAULT; | ||
119 | } | |||
120 | ||||
121 |
2/2✓ Branch 1 taken 116 times.
✓ Branch 2 taken 24815 times.
|
2/2✓ Decision 'true' taken 116 times.
✓ Decision 'false' taken 24815 times.
|
24931 | if (isPinConfigurationChanged()) { |
122 | 116 | this->initPin(registrationName, newPin, newMode); | ||
123 | } | |||
124 | 24931 | } | ||
125 | ||||
126 | 24930 | void RegisteredOutputPin::unregister() { | ||
127 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 24926 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 24926 times.
|
24930 | if (isPinConfigurationChanged()) { |
128 | 4 | OutputPin::deInit(); | ||
129 | } | |||
130 | 24930 | } | ||
131 | ||||
132 | #define CONFIG_OFFSET(x) (offsetof(engine_configuration_s, x)) | |||
133 | // todo: pin and pinMode should be combined into a composite entity | |||
134 | // todo: one of the impediments is code generator hints handling (we need custom hints and those are not handled nice for fields of structs?) | |||
135 | #define CONFIG_PIN_OFFSETS(x) CONFIG_OFFSET(x##Pin), CONFIG_OFFSET(x##PinMode) | |||
136 | ||||
137 | // offset of X within engineConfiguration, plus offset of Y within X | |||
138 | // decltype(engine_configuration_s::x) resolves the typename of the struct X inside engineConfiguration | |||
139 | #define CONFIG_OFFSET2(x, y) (offsetof(engine_configuration_s, x) + offsetof(decltype(engine_configuration_s::x), y)) | |||
140 | #define CONFIG_PIN_OFFSETS2(x, y) CONFIG_OFFSET2(x, y##Pin), CONFIG_OFFSET2(x, y##PinMode) | |||
141 | ||||
142 | 1 | EnginePins::EnginePins() : | ||
143 | // [tag:coding_by_convention] 'mainRelay' member here uses 'mainRelayPin' and 'mainRelayPinMode' configuration fields | |||
144 | 1 | mainRelay("Main Relay", CONFIG_PIN_OFFSETS(mainRelay)), | ||
145 | 1 | hpfpValve("HPFP Valve", CONFIG_PIN_OFFSETS(hpfpValve)), | ||
146 | 1 | starterControl("Starter Relay", CONFIG_PIN_OFFSETS(starterControl)), | ||
147 | 1 | starterRelayDisable("Starter Disable Relay", CONFIG_PIN_OFFSETS(starterRelayDisable)), | ||
148 | 1 | fanRelay("Fan Relay", CONFIG_PIN_OFFSETS(fan)), | ||
149 | 1 | fanRelay2("Fan Relay 2", CONFIG_PIN_OFFSETS(fan2)), | ||
150 | 1 | acRelay("A/C Relay", CONFIG_PIN_OFFSETS(acRelay)), | ||
151 | 1 | fuelPumpRelay("Fuel pump Relay", CONFIG_PIN_OFFSETS(fuelPump)), | ||
152 | 1 | nitrousRelay("Nitrous Relay", CONFIG_PIN_OFFSETS(nitrousRelay)), | ||
153 | 1 | vvlRelay("VVL Relay", CONFIG_PIN_OFFSETS(vvlRelay)), | ||
154 | #if EFI_HD_ACR | |||
155 | harleyAcr("Harley ACR", CONFIG_OFFSET(acrPin)), | |||
156 | harleyAcr2("Harley ACR 2", CONFIG_OFFSET(acrPin2)), | |||
157 | #endif // EFI_HD_ACR | |||
158 | 1 | boostPin("Boost", CONFIG_PIN_OFFSETS(boostControl)), | ||
159 | 1 | idleSolenoidPin("Idle Valve", CONFIG_OFFSET2(idle, solenoidPin), CONFIG_OFFSET2(idle, solenoidPinMode)), | ||
160 | 1 | secondIdleSolenoidPin("Idle Valve#2", CONFIG_OFFSET(secondSolenoidPin), CONFIG_OFFSET2(idle, solenoidPinMode)), | ||
161 | 1 | alternatorPin("Alternator control", CONFIG_PIN_OFFSETS(alternatorControl)), | ||
162 | 1 | checkEnginePin("checkEnginePin", CONFIG_PIN_OFFSETS(malfunctionIndicator)), | ||
163 | 1 | tachOut("tachOut", CONFIG_PIN_OFFSETS(tachOutput)), | ||
164 | 1 | triggerDecoderErrorPin("led: trigger debug", CONFIG_PIN_OFFSETS(triggerError)), | ||
165 |
14/14✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 time.
✓ Branch 12 taken 12 times.
✓ Branch 13 taken 1 time.
✓ Branch 15 taken 12 times.
✓ Branch 16 taken 1 time.
✓ Branch 18 taken 12 times.
✓ Branch 19 taken 1 time.
✓ Branch 21 taken 12 times.
✓ Branch 22 taken 1 time.
✓ Branch 24 taken 2 times.
✓ Branch 25 taken 1 time.
✓ Branch 26 taken 5 times.
✓ Branch 27 taken 1 time.
|
64 | speedoOut("speedoOut", CONFIG_OFFSET(speedometerOutputPin)) | |
166 | { | |||
167 | 1 | hpfpValve.setName("hpfp"); | ||
168 | #if EFI_HD_ACR | |||
169 | harleyAcr.setName("acr"); | |||
170 | #endif // EFI_HD_ACR | |||
171 | ||||
172 | static_assert(efi::size(sparkNames) >= MAX_CYLINDER_COUNT, "Too many ignition pins"); | |||
173 | static_assert(efi::size(trailNames) >= MAX_CYLINDER_COUNT, "Too many ignition pins"); | |||
174 | static_assert(efi::size(injectorNames) >= MAX_CYLINDER_COUNT, "Too many injection pins"); | |||
175 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 time.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 1 time.
|
13 | for (int i = 0; i < MAX_CYLINDER_COUNT;i++) { |
176 | 12 | enginePins.coils[i].coilIndex = i; | ||
177 | 12 | enginePins.coils[i].setName(sparkNames[i]); | ||
178 | 12 | enginePins.coils[i].shortName = sparkShortNames[i]; | ||
179 | ||||
180 | 12 | enginePins.trailingCoils[i].setName(trailNames[i]); | ||
181 | 12 | enginePins.trailingCoils[i].shortName = trailShortNames[i]; | ||
182 | ||||
183 | 12 | enginePins.injectors[i].injectorIndex = i; | ||
184 | 12 | enginePins.injectors[i].setName(injectorNames[i]); | ||
185 | 12 | enginePins.injectors[i].shortName = injectorShortNames[i]; | ||
186 | ||||
187 | 12 | enginePins.injectorsStage2[i].injectorIndex = i; | ||
188 | 12 | enginePins.injectorsStage2[i].setName(injectorStage2Names[i]); | ||
189 | 12 | enginePins.injectorsStage2[i].shortName = injectorStage2ShortNames[i]; | ||
190 | } | |||
191 | ||||
192 | static_assert(efi::size(auxValveShortNames) >= AUX_DIGITAL_VALVE_COUNT, "Too many aux valve pins"); | |||
193 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 time.
|
3 | for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT;i++) { |
194 | 2 | enginePins.auxValve[i].setName(auxValveShortNames[i]); | ||
195 | } | |||
196 | 1 | } | ||
197 | ||||
198 | /** | |||
199 | * Sets the value of the pin. On this layer the value is assigned as is, without any conversion. | |||
200 | */ | |||
201 | ||||
202 | #define unregisterOutputIfPinChanged(output, pin) { \ | |||
203 | if (isConfigurationChanged(pin)) { \ | |||
204 | (output).deInit(); \ | |||
205 | } \ | |||
206 | } | |||
207 | ||||
208 | #define unregisterOutputIfPinOrModeChanged(output, pin, mode) { \ | |||
209 | if (isPinOrModeChanged(pin, mode)) { \ | |||
210 | (output).deInit(); \ | |||
211 | } \ | |||
212 | } | |||
213 | ||||
214 | 1002 | bool EnginePins::stopPins() { | ||
215 | 1002 | bool result = false; | ||
216 |
2/2✓ Branch 0 taken 12024 times.
✓ Branch 1 taken 1002 times.
|
2/2✓ Decision 'true' taken 12024 times.
✓ Decision 'false' taken 1002 times.
|
13026 | for (int i = 0; i < MAX_CYLINDER_COUNT; i++) { |
217 | 12024 | result |= coils[i].stop(); | ||
218 | 12024 | result |= injectors[i].stop(); | ||
219 | 12024 | result |= injectorsStage2[i].stop(); | ||
220 | 12024 | result |= trailingCoils[i].stop(); | ||
221 | } | |||
222 |
2/2✓ Branch 0 taken 2004 times.
✓ Branch 1 taken 1002 times.
|
2/2✓ Decision 'true' taken 2004 times.
✓ Decision 'false' taken 1002 times.
|
3006 | for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) { |
223 | 2004 | result |= auxValve[i].stop(); | ||
224 | } | |||
225 | 1002 | return result; | ||
226 | } | |||
227 | ||||
228 | 1385 | void EnginePins::unregisterPins() { | ||
229 | 1385 | stopInjectionPins(); | ||
230 | 1385 | stopIgnitionPins(); | ||
231 | #if EFI_AUX_VALVES | |||
232 | 1385 | stopAuxValves(); | ||
233 | #endif | |||
234 | ||||
235 | #if EFI_ELECTRONIC_THROTTLE_BODY | |||
236 | 1385 | unregisterEtbPins(); | ||
237 | #endif /* EFI_ELECTRONIC_THROTTLE_BODY */ | |||
238 | ||||
239 | // todo: add pinMode | |||
240 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1385 times.
|
1385 | unregisterOutputIfPinChanged(sdCsPin, sdCardCsPin); | |
241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1385 times.
|
1385 | unregisterOutputIfPinChanged(accelerometerCs, accelerometerCsPin); | |
242 | ||||
243 | 1385 | RegisteredOutputPin * pin = registeredOutputHead; | ||
244 |
2/2✓ Branch 0 taken 24930 times.
✓ Branch 1 taken 1385 times.
|
2/2✓ Decision 'true' taken 24930 times.
✓ Decision 'false' taken 1385 times.
|
26315 | while (pin != nullptr) { |
245 | 24930 | pin->unregister(); | ||
246 | 24930 | pin = pin->next; | ||
247 | } | |||
248 | 1385 | } | ||
249 | ||||
250 | ✗ | void EnginePins::debug() { | ||
251 | ✗ | RegisteredOutputPin * pin = registeredOutputHead; | ||
252 | ✗ | while (pin != nullptr) { | ||
253 | ✗ | efiPrintf("%s %d", pin->getRegistrationName(), pin->currentLogicValue); | ||
254 | ✗ | pin = pin->next; | ||
255 | } | |||
256 | ✗ | } | ||
257 | ||||
258 | 1385 | void EnginePins::startPins() { | ||
259 | #if EFI_ENGINE_CONTROL | |||
260 | 1385 | startInjectionPins(); | ||
261 | 1385 | startIgnitionPins(); | ||
262 | #endif /* EFI_ENGINE_CONTROL */ | |||
263 | ||||
264 | #if EFI_AUX_VALVES | |||
265 | 1385 | startAuxValves(); | ||
266 | #endif // EFI_AUX_VALVES | |||
267 | ||||
268 | 1385 | RegisteredOutputPin * pin = registeredOutputHead; | ||
269 |
2/2✓ Branch 0 taken 24930 times.
✓ Branch 1 taken 1385 times.
|
2/2✓ Decision 'true' taken 24930 times.
✓ Decision 'false' taken 1385 times.
|
26315 | while (pin != nullptr) { |
270 | 24930 | pin->init(); | ||
271 | 24930 | pin = pin->next; | ||
272 | } | |||
273 | 1385 | } | ||
274 | ||||
275 | 1752 | void EnginePins::reset() { | ||
276 |
2/2✓ Branch 0 taken 21024 times.
✓ Branch 1 taken 1752 times.
|
2/2✓ Decision 'true' taken 21024 times.
✓ Decision 'false' taken 1752 times.
|
22776 | for (int i = 0; i < MAX_CYLINDER_COUNT;i++) { |
277 | 21024 | injectors[i].reset(); | ||
278 | 21024 | coils[i].reset(); | ||
279 | 21024 | trailingCoils[i].reset(); | ||
280 | } | |||
281 | 1752 | } | ||
282 | ||||
283 | 1385 | void EnginePins::stopIgnitionPins() { | ||
284 |
2/2✓ Branch 0 taken 16620 times.
✓ Branch 1 taken 1385 times.
|
2/2✓ Decision 'true' taken 16620 times.
✓ Decision 'false' taken 1385 times.
|
18005 | for (int i = 0; i < MAX_CYLINDER_COUNT; i++) { |
285 |
2/4✓ Branch 2 taken 16620 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16620 times.
|
16620 | unregisterOutputIfPinOrModeChanged(enginePins.coils[i], ignitionPins[i], ignitionPinMode); | |
286 |
2/4✓ Branch 2 taken 16620 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16620 times.
|
16620 | unregisterOutputIfPinOrModeChanged(enginePins.trailingCoils[i], trailingCoilPins[i], ignitionPinMode); | |
287 | } | |||
288 | 1385 | } | ||
289 | ||||
290 | 1385 | void EnginePins::stopInjectionPins() { | ||
291 |
2/2✓ Branch 0 taken 16620 times.
✓ Branch 1 taken 1385 times.
|
2/2✓ Decision 'true' taken 16620 times.
✓ Decision 'false' taken 1385 times.
|
18005 | for (int i = 0; i < MAX_CYLINDER_COUNT; i++) { |
292 |
2/4✓ Branch 2 taken 16620 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16620 times.
|
16620 | unregisterOutputIfPinOrModeChanged(enginePins.injectors[i], injectionPins[i], injectionPinMode); | |
293 |
2/4✓ Branch 2 taken 16620 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16620 times.
|
16620 | unregisterOutputIfPinOrModeChanged(enginePins.injectorsStage2[i], injectionPinsStage2[i], injectionPinMode); | |
294 | } | |||
295 | 1385 | } | ||
296 | ||||
297 | #if EFI_AUX_VALVES | |||
298 | 1385 | void EnginePins::stopAuxValves() { | ||
299 |
2/2✓ Branch 0 taken 2770 times.
✓ Branch 1 taken 1385 times.
|
2/2✓ Decision 'true' taken 2770 times.
✓ Decision 'false' taken 1385 times.
|
4155 | for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) { |
300 | 2770 | NamedOutputPin *output = &enginePins.auxValve[i]; | ||
301 | // todo: do we need auxValveMode and reuse code? | |||
302 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2768 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2768 times.
|
2770 | if (isConfigurationChanged(auxValves[i])) { |
303 | 2 | (output)->deInit(); | ||
304 | } | |||
305 | } | |||
306 | 1385 | } | ||
307 | ||||
308 | 1385 | void EnginePins::startAuxValves() { | ||
309 | #if EFI_PROD_CODE | |||
310 | for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) { | |||
311 | NamedOutputPin *output = &enginePins.auxValve[i]; | |||
312 | // todo: do we need auxValveMode and reuse code? | |||
313 | if (isConfigurationChanged(auxValves[i])) { | |||
314 | output->initPin(output->getName(), engineConfiguration->auxValves[i]); | |||
315 | } | |||
316 | } | |||
317 | #endif /* EFI_PROD_CODE */ | |||
318 | 1385 | } | ||
319 | #endif // EFI_AUX_VALVES | |||
320 | ||||
321 | 1385 | void EnginePins::startIgnitionPins() { | ||
322 | #if EFI_PROD_CODE | |||
323 | for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) { | |||
324 | NamedOutputPin *trailingOutput = &enginePins.trailingCoils[i]; | |||
325 | if (isPinOrModeChanged(trailingCoilPins[i], ignitionPinMode)) { | |||
326 | trailingOutput->initPin(trailingOutput->getName(), engineConfiguration->trailingCoilPins[i], engineConfiguration->ignitionPinMode); | |||
327 | } | |||
328 | ||||
329 | NamedOutputPin *output = &enginePins.coils[i]; | |||
330 | if (isPinOrModeChanged(ignitionPins[i], ignitionPinMode)) { | |||
331 | output->initPin(output->getName(), engineConfiguration->ignitionPins[i], engineConfiguration->ignitionPinMode); | |||
332 | } | |||
333 | } | |||
334 | #endif /* EFI_PROD_CODE */ | |||
335 | 1385 | } | ||
336 | ||||
337 | 1385 | void EnginePins::startInjectionPins() { | ||
338 | #if EFI_PROD_CODE | |||
339 | // todo: should we move this code closer to the injection logic? | |||
340 | for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) { | |||
341 | NamedOutputPin *output = &enginePins.injectors[i]; | |||
342 | if (isPinOrModeChanged(injectionPins[i], injectionPinMode)) { | |||
343 | output->initPin(output->getName(), engineConfiguration->injectionPins[i], | |||
344 | engineConfiguration->injectionPinMode); | |||
345 | } | |||
346 | ||||
347 | output = &enginePins.injectorsStage2[i]; | |||
348 | if (isPinOrModeChanged(injectionPinsStage2[i], injectionPinMode)) { | |||
349 | output->initPin(output->getName(), engineConfiguration->injectionPinsStage2[i], | |||
350 | engineConfiguration->injectionPinMode); | |||
351 | } | |||
352 | } | |||
353 | #endif /* EFI_PROD_CODE */ | |||
354 | 1385 | } | ||
355 | ||||
356 | ✗ | OutputPin *EnginePins::getOutputPinForBenchMode(bench_mode_e index) { | ||
357 | ✗ | switch(index) { | ||
358 | #if EFI_VVT_PID | |||
359 | case BENCH_VVT0_VALVE: | |||
360 | return getVvtOutputPin(0); | |||
361 | case BENCH_VVT1_VALVE: | |||
362 | return getVvtOutputPin(1); | |||
363 | case BENCH_VVT2_VALVE: | |||
364 | return getVvtOutputPin(2); | |||
365 | case BENCH_VVT3_VALVE: | |||
366 | return getVvtOutputPin(3); | |||
367 | #endif // EFI_VVT_PID | |||
368 | ✗ | case BENCH_MAIN_RELAY: | ||
369 | ✗ | return &mainRelay; | ||
370 | ✗ | case BENCH_HPFP_VALVE: | ||
371 | ✗ | return &hpfpValve; | ||
372 | ✗ | case BENCH_FUEL_PUMP: | ||
373 | ✗ | return &fuelPumpRelay; | ||
374 | ✗ | case BENCH_STARTER_ENABLE_RELAY: | ||
375 | ✗ | return &starterControl; | ||
376 | ✗ | case BENCH_CHECK_ENGINE_LIGHT: | ||
377 | ✗ | return &checkEnginePin; | ||
378 | ✗ | case BENCH_AC_COMPRESSOR_RELAY: | ||
379 | ✗ | return &acRelay; | ||
380 | ✗ | case BENCH_FAN_RELAY: | ||
381 | ✗ | return &fanRelay; | ||
382 | #if EFI_HD_ACR | |||
383 | case HD_ACR: | |||
384 | return &harleyAcr; | |||
385 | case HD_ACR2: | |||
386 | return &harleyAcr2; | |||
387 | #endif | |||
388 | ✗ | case BENCH_IDLE_VALVE: | ||
389 | ✗ | return &idleSolenoidPin; | ||
390 | ✗ | case BENCH_FAN_RELAY_2: | ||
391 | ✗ | return &fanRelay; | ||
392 | ✗ | default: | ||
393 | ✗ | criticalError("Unexpected bench pin %d", index); | ||
394 | } | |||
395 | ✗ | return nullptr; | ||
396 | } | |||
397 | ||||
398 | #if EFI_UNIT_TEST | |||
399 | /* | |||
400 | * this function goes through the whole pin repository and sets them all to "GPIO::Unassigned", | |||
401 | * this is done as a clean-up for testing, since several motor configurations can have conflicting pins | |||
402 | * at the same time the productive de-init uses "isPinConfigurationChanged" to reset only the pins that have been changed, | |||
403 | * so in order for it to be properly de-initialized as it is done in prod, all pins are re-configured as unassigned, | |||
404 | * previously unused pins by tests will not be de-initialized since the configuration on them will be the same (Unassigned => Unassigned) | |||
405 | */ | |||
406 | 583 | void EnginePins::resetForUnitTest() { | ||
407 | 583 | RegisteredOutputPin * pin = registeredOutputHead; | ||
408 |
2/2✓ Branch 0 taken 10494 times.
✓ Branch 1 taken 583 times.
|
2/2✓ Decision 'true' taken 10494 times.
✓ Decision 'false' taken 583 times.
|
11077 | while (pin != nullptr) { |
409 | 10494 | pin->brainPin = Gpio::Unassigned; | ||
410 | 10494 | pin = pin->next; | ||
411 | } | |||
412 | 583 | } | ||
413 | #endif | |||
414 | ||||
415 | 56 | NamedOutputPin::NamedOutputPin() : OutputPin() { | ||
416 | 56 | } | ||
417 | ||||
418 | 1 | NamedOutputPin::NamedOutputPin(const char *p_name) : OutputPin() { | ||
419 | 1 | name = p_name; | ||
420 | 1 | } | ||
421 | ||||
422 | 41591 | const char *NamedOutputPin::getName() const { | ||
423 | 41591 | return name; | ||
424 | } | |||
425 | ||||
426 | 51 | void NamedOutputPin::setName(const char* p_name) { | ||
427 | 51 | name = p_name; | ||
428 | 51 | } | ||
429 | ||||
430 | 18607 | const char *NamedOutputPin::getShortName() const { | ||
431 |
2/2✓ Branch 0 taken 97 times.
✓ Branch 1 taken 18510 times.
|
18607 | return shortName == nullptr ? name : shortName; | |
432 | } | |||
433 | ||||
434 | #if EFI_UNIT_TEST | |||
435 | extern bool verboseMode; | |||
436 | #endif // EFI_UNIT_TEST | |||
437 | ||||
438 | 8899 | void NamedOutputPin::setHigh() { | ||
439 | 8899 | setHigh(nullptr); | ||
440 | 8899 | } | ||
441 | ||||
442 | 8918 | void NamedOutputPin::setHigh(const char *msg) { | ||
443 | #if EFI_UNIT_TEST | |||
444 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8918 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 8918 times.
|
8918 | if (verboseMode) { |
445 | ✗ | efiPrintf("pin %s goes high", name); | ||
446 | } | |||
447 | #endif // EFI_UNIT_TEST | |||
448 | #if EFI_DETAILED_LOGGING | |||
449 | // signal->hi_time = hTimeNow(); | |||
450 | #endif /* EFI_DETAILED_LOGGING */ | |||
451 | ||||
452 | // turn the output level ACTIVE | |||
453 | 8918 | setValue(msg, true); | ||
454 | ||||
455 | #if EFI_ENGINE_SNIFFER | |||
456 | 8918 | addEngineSnifferOutputPinEvent(this, FrontDirection::UP); | ||
457 | #endif /* EFI_ENGINE_SNIFFER */ | |||
458 | 8918 | } | ||
459 | ||||
460 | 9671 | void NamedOutputPin::setLow() { | ||
461 | 9671 | setLow(nullptr); | ||
462 | 9671 | } | ||
463 | ||||
464 | 9689 | void NamedOutputPin::setLow(const char *msg) { | ||
465 | #if EFI_UNIT_TEST | |||
466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9689 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 9689 times.
|
9689 | if (verboseMode) { |
467 | ✗ | efiPrintf("pin %s goes low", name); | ||
468 | } | |||
469 | #endif // EFI_UNIT_TEST | |||
470 | ||||
471 | // turn off the output | |||
472 | 9689 | setValue(msg, false); | ||
473 | ||||
474 | #if EFI_ENGINE_SNIFFER | |||
475 | 9689 | addEngineSnifferOutputPinEvent(this, FrontDirection::DOWN); | ||
476 | #endif /* EFI_ENGINE_SNIFFER */ | |||
477 | 9689 | } | ||
478 | ||||
479 | 50100 | bool NamedOutputPin::stop() { | ||
480 | #if EFI_GPIO_HARDWARE | |||
481 |
5/6✓ Branch 1 taken 50100 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 50096 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 50096 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 50096 times.
|
50100 | if (isInitialized() && getLogicValue()) { |
482 | 4 | setValue("stop", false); | ||
483 | 4 | efiPrintf("turning off %s", name); | ||
484 | 4 | return true; | ||
485 | } | |||
486 | #endif /* EFI_GPIO_HARDWARE */ | |||
487 | 50096 | return false; | ||
488 | } | |||
489 | ||||
490 | 24053 | void InjectorOutputPin::reset() { | ||
491 | // If this injector was open, close it and reset state | |||
492 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 24004 times.
|
2/2✓ Decision 'true' taken 49 times.
✓ Decision 'false' taken 24004 times.
|
24053 | if (overlappingCounter != 0) { |
493 | 49 | overlappingCounter = 0; | ||
494 | 49 | setValue("reset", 0); | ||
495 | } | |||
496 | ||||
497 | // todo: this could be refactored by calling some super-reset method | |||
498 | 24053 | currentLogicValue = 0; | ||
499 | 24053 | } | ||
500 | ||||
501 | 24 | IgnitionOutputPin::IgnitionOutputPin() { | ||
502 | 24 | reset(); | ||
503 | 24 | } | ||
504 | ||||
505 | 5506 | void IgnitionOutputPin::setHigh() { | ||
506 | 5506 | NamedOutputPin::setHigh(); | ||
507 | // this is NASTY but what's the better option? bytes? At cost of 22 extra bytes in output status packet? | |||
508 |
6/7✓ Branch 0 taken 4895 times.
✓ Branch 1 taken 147 times.
✓ Branch 2 taken 291 times.
✓ Branch 3 taken 67 times.
✓ Branch 4 taken 55 times.
✓ Branch 5 taken 51 times.
✗ Branch 6 not taken.
|
5506 | switch (coilIndex) { | |
509 |
1/1✓ Decision 'true' taken 4895 times.
|
4895 | case 0: | |
510 | 4895 | engine->outputChannels.coilState1 = true; | ||
511 | 4895 | break; | ||
512 |
1/1✓ Decision 'true' taken 147 times.
|
147 | case 1: | |
513 | 147 | engine->outputChannels.coilState2 = true; | ||
514 | 147 | break; | ||
515 |
1/1✓ Decision 'true' taken 291 times.
|
291 | case 2: | |
516 | 291 | engine->outputChannels.coilState3 = true; | ||
517 | 291 | break; | ||
518 |
1/1✓ Decision 'true' taken 67 times.
|
67 | case 3: | |
519 | 67 | engine->outputChannels.coilState4 = true; | ||
520 | 67 | break; | ||
521 |
1/1✓ Decision 'true' taken 55 times.
|
55 | case 4: | |
522 | 55 | engine->outputChannels.coilState5 = true; | ||
523 | 55 | break; | ||
524 |
1/1✓ Decision 'true' taken 51 times.
|
51 | case 5: | |
525 | 51 | engine->outputChannels.coilState6 = true; | ||
526 | 51 | break; | ||
527 | } | |||
528 | 5506 | } | ||
529 | ||||
530 | 6296 | void IgnitionOutputPin::setLow() { | ||
531 | 6296 | NamedOutputPin::setLow(); | ||
532 | // this is NASTY but what's the better option? bytes? At cost of 22 extra bytes in output status packet? | |||
533 |
6/7✓ Branch 0 taken 5594 times.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 347 times.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 62 times.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
|
6296 | switch (coilIndex) { | |
534 |
1/1✓ Decision 'true' taken 5594 times.
|
5594 | case 0: | |
535 | 5594 | engine->outputChannels.coilState1 = false; | ||
536 | 5594 | break; | ||
537 |
1/1✓ Decision 'true' taken 157 times.
|
157 | case 1: | |
538 | 157 | engine->outputChannels.coilState2 = false; | ||
539 | 157 | break; | ||
540 |
1/1✓ Decision 'true' taken 347 times.
|
347 | case 2: | |
541 | 347 | engine->outputChannels.coilState3 = false; | ||
542 | 347 | break; | ||
543 |
1/1✓ Decision 'true' taken 75 times.
|
75 | case 3: | |
544 | 75 | engine->outputChannels.coilState4 = false; | ||
545 | 75 | break; | ||
546 |
1/1✓ Decision 'true' taken 62 times.
|
62 | case 4: | |
547 | 62 | engine->outputChannels.coilState5 = false; | ||
548 | 62 | break; | ||
549 |
1/1✓ Decision 'true' taken 61 times.
|
61 | case 5: | |
550 | 61 | engine->outputChannels.coilState6 = false; | ||
551 | 61 | break; | ||
552 | } | |||
553 | 6296 | } | ||
554 | ||||
555 | 42072 | void IgnitionOutputPin::reset() { | ||
556 | 42072 | signalFallSparkId = 0; | ||
557 | 42072 | } | ||
558 | ||||
559 | 58196 | bool OutputPin::isInitialized() const { | ||
560 | #if EFI_GPIO_HARDWARE && EFI_PROD_CODE | |||
561 | #if (BOARD_EXT_GPIOCHIPS > 0) | |||
562 | if (ext) | |||
563 | return true; | |||
564 | #endif /* (BOARD_EXT_GPIOCHIPS > 0) */ | |||
565 | return m_port != NULL; | |||
566 | #else /* EFI_GPIO_HARDWARE */ | |||
567 | 58196 | return true; | ||
568 | #endif /* EFI_GPIO_HARDWARE */ | |||
569 | } | |||
570 | ||||
571 | 5426 | void OutputPin::toggle() { | ||
572 | 5426 | setValue("toggle", !getLogicValue()); | ||
573 | 5426 | } | ||
574 | ||||
575 | 2 | bool OutputPin::getAndSet(int logicValue) { | ||
576 | 2 | bool oldValue = getLogicValue(); | ||
577 | 2 | setValue(logicValue); | ||
578 | 2 | return oldValue; | ||
579 | } | |||
580 | ||||
581 | // This function is only used on real hardware | |||
582 | #if EFI_PROD_CODE | |||
583 | void OutputPin::setOnchipValue(int electricalValue) { | |||
584 | if (brainPin == Gpio::Unassigned || brainPin == Gpio::Invalid) { | |||
585 | // todo: make 'setOnchipValue' or 'reportsetOnchipValueError' virtual and override for NamedOutputPin? | |||
586 | warning(ObdCode::CUSTOM_ERR_6586, "attempting to change unassigned pin"); | |||
587 | return; | |||
588 | } | |||
589 | palWritePad(m_port, m_pin, electricalValue); | |||
590 | } | |||
591 | #endif // EFI_PROD_CODE | |||
592 | ||||
593 | 12767 | void OutputPin::setValue(int logicValue, bool isForce) { | ||
594 | 12767 | setValue(nullptr, logicValue, isForce); | ||
595 | 12767 | } | ||
596 | ||||
597 | #if EFI_SIMULATOR | |||
598 | void OutputPin::resetToggleStats() { | |||
599 | durationsInStateMs[0] = durationsInStateMs[1] = 0; | |||
600 | pinToggleCounter = 0; | |||
601 | } | |||
602 | #endif // EFI_SIMULATOR | |||
603 | ||||
604 | 39029 | void OutputPin::setValue(const char *msg, int logicValue, bool isForce) { | ||
605 | UNUSED(msg); | |||
606 |
3/8✓ Branch 1 taken 39029 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 39029 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 39029 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 39029 times.
|
39029 | if ((isHwQcMode() || getOutputOnTheBenchTest() == this) && !isForce) { |
607 | ✗ | return; | ||
608 | } | |||
609 | ||||
610 | #if ENABLE_PERF_TRACE | |||
611 | // todo: https://github.com/rusefi/rusefi/issues/1638 | |||
612 | // ScopePerf perf(PE::OutputPinSetValue); | |||
613 | #endif // ENABLE_PERF_TRACE | |||
614 | ||||
615 | #if EFI_UNIT_TEST | |||
616 |
2/2✓ Branch 0 taken 23754 times.
✓ Branch 1 taken 15275 times.
|
2/2✓ Decision 'true' taken 23754 times.
✓ Decision 'false' taken 15275 times.
|
39029 | if (currentLogicValue != logicValue) { |
617 | 23754 | pinToggleCounter++; | ||
618 | } | |||
619 | #endif // EFI_UNIT_TEST | |||
620 | ||||
621 | #if EFI_SIMULATOR | |||
622 | if (currentLogicValue != logicValue) { | |||
623 | if (pinToggleCounter > 0) { | |||
624 | durationsInStateMs[0] = durationsInStateMs[1]; | |||
625 | durationsInStateMs[1] = pinToggleTimer.getElapsedUs() / 1000; | |||
626 | } | |||
627 | pinToggleCounter++; | |||
628 | pinToggleTimer.reset(); | |||
629 | } | |||
630 | #endif // EFI_SIMULATOR | |||
631 | ||||
632 | #if EFI_UNIT_TEST | |||
633 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39029 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 39029 times.
|
39029 | if (verboseMode) { |
634 | ✗ | efiPrintf("pin goes %d", logicValue); | ||
635 | } | |||
636 | #endif // EFI_UNIT_TEST | |||
637 | ||||
638 | // Always store the current logical value of the pin (so it can be | |||
639 | // used internally even if not connected to a real hardware pin) | |||
640 | 39029 | currentLogicValue = logicValue; | ||
641 | ||||
642 | // Nothing else to do if not configured | |||
643 |
2/2✓ Branch 1 taken 38572 times.
✓ Branch 2 taken 457 times.
|
2/2✓ Decision 'true' taken 38572 times.
✓ Decision 'false' taken 457 times.
|
39029 | if (!isBrainPinValid(brainPin)) { |
644 | 38572 | return; | ||
645 | } | |||
646 | ||||
647 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 457 times.
|
457 | efiAssertVoid(ObdCode::CUSTOM_ERR_6622, mode <= OM_OPENDRAIN_INVERTED, "invalid pin_output_mode_e"); | |
648 |
8/10✓ Branch 0 taken 194 times.
✓ Branch 1 taken 263 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 193 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 260 times.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 260 times.
|
457 | int electricalValue = getElectricalValue(logicValue, mode); | |
649 | ||||
650 | #if EFI_PROD_CODE | |||
651 | #if (BOARD_EXT_GPIOCHIPS > 0) | |||
652 | if (!this->ext) { | |||
653 | setOnchipValue(electricalValue); | |||
654 | } else { | |||
655 | /* external pin */ | |||
656 | gpiochips_writePad(this->brainPin, logicValue); | |||
657 | /* TODO: check return value */ | |||
658 | } | |||
659 | #else | |||
660 | setOnchipValue(electricalValue); | |||
661 | #endif | |||
662 | #else /* EFI_PROD_CODE */ | |||
663 | 457 | setMockState(brainPin, electricalValue); | ||
664 | #endif /* EFI_PROD_CODE */ | |||
665 | } | |||
666 | ||||
667 | 1630269 | bool OutputPin::getLogicValue() const { | ||
668 | // Compare against 1 since it could also be INITIAL_PIN_STATE (which means logical 0, but we haven't initialized the pin yet) | |||
669 | 1630269 | return currentLogicValue == 1; | ||
670 | } | |||
671 | ||||
672 | 123 | void OutputPin::setDefaultPinState(pin_output_mode_e outputMode) { | ||
673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
123 | assertOMode(mode); | |
674 | 123 | this->mode = outputMode; | ||
675 | 123 | setValue(false, /*force*/true); // initial state | ||
676 | } | |||
677 | ||||
678 | ✗ | brain_pin_diag_e OutputPin::getDiag() const { | ||
679 | #if EFI_PROD_CODE | |||
680 | #if BOARD_EXT_GPIOCHIPS > 0 | |||
681 | if (!brain_pin_is_onchip(brainPin)) { | |||
682 | return gpiochips_getDiag(brainPin); | |||
683 | } | |||
684 | #endif | |||
685 | #endif /* EFI_PROD_CODE */ | |||
686 | // TODO: add hook to board code for custom diagnostic, like it is done on S105 | |||
687 | ✗ | return PIN_UNKNOWN; | ||
688 | } | |||
689 | ||||
690 | 583 | void initMiscOutputPins() { | ||
691 | #if EFI_GPIO_HARDWARE | |||
692 | ||||
693 | #if HAL_USE_SPI | |||
694 | enginePins.sdCsPin.initPin("SD CS", engineConfiguration->sdCardCsPin); | |||
695 | #endif /* HAL_USE_SPI */ | |||
696 | ||||
697 | #if EFI_SHAFT_POSITION_INPUT | |||
698 | // todo: migrate remaining OutputPin to RegisteredOutputPin in order to get consistent dynamic pin init/deinit | |||
699 | 583 | enginePins.debugTriggerSync.initPin("debug: sync", engineConfiguration->debugTriggerSync); | ||
700 | #endif // EFI_SHAFT_POSITION_INPUT | |||
701 | ||||
702 | 583 | enginePins.o2heater.initPin("O2 heater", engineConfiguration->o2heaterPin); | ||
703 | ||||
704 | #endif /* EFI_GPIO_HARDWARE */ | |||
705 | 583 | } | ||
706 | ||||
707 | 1177 | void OutputPin::initPin(const char *p_msg, brain_pin_e p_brainPin) { | ||
708 | 1177 | initPin(p_msg, p_brainPin, OM_DEFAULT); | ||
709 | 1176 | } | ||
710 | ||||
711 | 1297 | void OutputPin::initPin(const char *msg, brain_pin_e p_brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError) { | ||
712 | #if EFI_UNIT_TEST | |||
713 | 1297 | pinToggleCounter = 0; | ||
714 | #endif | |||
715 | ||||
716 |
2/2✓ Branch 1 taken 1173 times.
✓ Branch 2 taken 124 times.
|
2/2✓ Decision 'true' taken 1173 times.
✓ Decision 'false' taken 124 times.
|
1297 | if (!isBrainPinValid(p_brainPin)) { |
717 | 1173 | return; | ||
718 | } | |||
719 | ||||
720 | // Enter a critical section so that other threads can't change the pin state out from underneath us | |||
721 | chibios_rt::CriticalSectionLocker csl; | |||
722 | ||||
723 |
2/4✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 124 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 124 times.
|
124 | if (!forceInitWithFatalError && hasFirmwareError()) { |
724 | // Don't allow initializing more pins if we have a fatal error. | |||
725 | // Pins should have just been reset, so we shouldn't try to init more. | |||
726 | ✗ | return; | ||
727 | } | |||
728 | ||||
729 | // Check that this OutputPin isn't already assigned to another pin (reinit is allowed to change mode) | |||
730 | // To avoid this error, call deInit() first | |||
731 |
6/6✓ Branch 1 taken 59 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 58 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 123 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 123 times.
|
124 | if (isBrainPinValid(brainPin) && brainPin != p_brainPin) { |
732 | 1 | firmwareError(ObdCode::CUSTOM_OBD_PIN_CONFLICT, "outputPin [%s] already assigned, cannot reassign without unregister first", msg); | ||
733 | ✗ | return; | ||
734 | } | |||
735 | ||||
736 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 123 times.
|
123 | if (outputMode > OM_OPENDRAIN_INVERTED) { |
737 | ✗ | firmwareError(ObdCode::CUSTOM_INVALID_MODE_SETTING, "%s invalid pin_output_mode_e %d %s", | ||
738 | msg, | |||
739 | outputMode, | |||
740 | hwPortname(p_brainPin) | |||
741 | ); | |||
742 | ✗ | return; | ||
743 | } | |||
744 | ||||
745 | #if EFI_GPIO_HARDWARE && EFI_PROD_CODE | |||
746 | iomode_t l_mode = (outputMode == OM_DEFAULT || outputMode == OM_INVERTED) ? | |||
747 | PAL_MODE_OUTPUT_PUSHPULL : PAL_MODE_OUTPUT_OPENDRAIN; | |||
748 | ||||
749 | #if (BOARD_EXT_GPIOCHIPS > 0) | |||
750 | this->ext = false; | |||
751 | #endif | |||
752 | if (brain_pin_is_onchip(p_brainPin)) { | |||
753 | m_port = getHwPort(msg, p_brainPin); | |||
754 | m_pin = getHwPin(msg, p_brainPin); | |||
755 | ||||
756 | // Validate port | |||
757 | if (!m_port) { | |||
758 | criticalError("OutputPin::initPin got invalid port for pin idx %d", static_cast<int>(p_brainPin)); | |||
759 | return; | |||
760 | } | |||
761 | } | |||
762 | #if (BOARD_EXT_GPIOCHIPS > 0) | |||
763 | else { | |||
764 | this->ext = true; | |||
765 | } | |||
766 | #endif | |||
767 | #endif // briefly leave the include guard because we need to set default state in tests | |||
768 | ||||
769 | 123 | brainPin = p_brainPin; | ||
770 | ||||
771 | // The order of the next two calls may look strange, which is a good observation. | |||
772 | // We call them in this order so that the pin is set to a known state BEFORE | |||
773 | // it's enabled. Enabling the pin then setting it could result in a (brief) | |||
774 | // mystery state being driven on the pin (potentially dangerous). | |||
775 | 123 | setDefaultPinState(outputMode); | ||
776 | ||||
777 | #if EFI_GPIO_HARDWARE && EFI_PROD_CODE | |||
778 | efiSetPadMode(msg, brainPin, l_mode); | |||
779 | if (brain_pin_is_onchip(brainPin)) { | |||
780 | // todo: handle OM_OPENDRAIN and OM_OPENDRAIN_INVERTED as well | |||
781 | if (outputMode == OM_DEFAULT || outputMode == OM_INVERTED) { | |||
782 | #ifndef DISABLE_PIN_STATE_VALIDATION | |||
783 | int actualValue = palReadPad(m_port, m_pin); | |||
784 | // we had enough drama with pin configuration in board.h and else that we shall self-check | |||
785 | ||||
786 | const int logicalValue = | |||
787 | (outputMode == OM_INVERTED) | |||
788 | ? !actualValue | |||
789 | : actualValue; | |||
790 | ||||
791 | // if the pin was set to logical 1, then set an error and disable the pin so that things don't catch fire | |||
792 | if (logicalValue) { | |||
793 | criticalError("HARDWARE VALIDATION FAILED %s: unexpected startup pin state %s actual value=%d logical value=%d mode=%s", msg, hwPortname(brainPin), actualValue, logicalValue, getPin_output_mode_e(outputMode)); | |||
794 | OutputPin::deInit(); | |||
795 | } | |||
796 | #endif | |||
797 | } | |||
798 | } | |||
799 | #endif /* EFI_GPIO_HARDWARE */ | |||
800 | } | |||
801 | ||||
802 | 7 | void OutputPin::deInit() { | ||
803 | 7 | efiPrintf("unregistering %s", hwPortname(brainPin)); | ||
804 | ||||
805 | // Unregister under lock - we don't want other threads mucking with the pin while we're trying to turn it off | |||
806 | chibios_rt::CriticalSectionLocker csl; | |||
807 | ||||
808 | // nothing to do if not registered in the first place | |||
809 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 2 times.
|
7 | if (!isBrainPinValid(brainPin)) { |
810 | 5 | return; | ||
811 | } | |||
812 | ||||
813 | #if (BOARD_EXT_GPIOCHIPS > 0) | |||
814 | 2 | ext = false; | ||
815 | #endif // (BOARD_EXT_GPIOCHIPS > 0) | |||
816 | ||||
817 | #if EFI_GPIO_HARDWARE && EFI_PROD_CODE | |||
818 | efiSetPadUnused(brainPin); | |||
819 | #endif /* EFI_GPIO_HARDWARE */ | |||
820 | ||||
821 | // Clear the pin so that it won't get set any more | |||
822 | 2 | brainPin = Gpio::Unassigned; | ||
823 | } | |||
824 | ||||
825 | #if EFI_GPIO_HARDWARE | |||
826 | ||||
827 | // questionable trick: we avoid using 'getHwPort' and 'getHwPin' in case of errors in order to increase the changes of turning the LED | |||
828 | // by reducing stack requirement | |||
829 | ioportid_t criticalErrorLedPort; | |||
830 | ioportmask_t criticalErrorLedPin; | |||
831 | uint8_t criticalErrorLedState; | |||
832 | ||||
833 | #if EFI_PROD_CODE | |||
834 | static void initErrorLed(Gpio led) { | |||
835 | enginePins.errorLedPin.initPin("led: CRITICAL status", led, (LED_PIN_MODE)); | |||
836 | criticalErrorLedPort = getHwPort("CRITICAL", led); | |||
837 | criticalErrorLedPin = getHwPin("CRITICAL", led); | |||
838 | criticalErrorLedState = (LED_PIN_MODE == OM_INVERTED) ? 0 : 1; | |||
839 | } | |||
840 | #endif /* EFI_PROD_CODE */ | |||
841 | ||||
842 | ✗ | void initPrimaryPins() { | ||
843 | #if EFI_PROD_CODE | |||
844 | initErrorLed(LED_CRITICAL_ERROR_BRAIN_PIN); | |||
845 | ||||
846 | addConsoleAction("gpio_pins", EnginePins::debug); | |||
847 | #endif /* EFI_PROD_CODE */ | |||
848 | ✗ | } | ||
849 | ||||
850 | /** | |||
851 | * This method is part of fatal error handling. | |||
852 | * The whole method is pretty naive, but that's at least something. | |||
853 | */ | |||
854 | ✗ | void turnAllPinsOff() { | ||
855 | ✗ | for (int i = 0; i < MAX_CYLINDER_COUNT; i++) { | ||
856 | ✗ | enginePins.injectors[i].setValue(false); | ||
857 | ✗ | enginePins.coils[i].setValue(false); | ||
858 | ✗ | enginePins.trailingCoils[i].setValue(false); | ||
859 | } | |||
860 | ✗ | enginePins.mainRelay.setValue(false); | ||
861 | ✗ | enginePins.fuelPumpRelay.setValue(false); | ||
862 | ✗ | enginePins.checkEnginePin.setValue(true); // yes this one can go ON | ||
863 | #if EFI_PROD_CODE && HW_HELLEN | |||
864 | hellenDisableEnSilently(); | |||
865 | #endif | |||
866 | ✗ | } | ||
867 | #endif /* EFI_GPIO_HARDWARE */ | |||
868 | ||||
869 |