rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
efi_gpio.cpp
Go to the documentation of this file.
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
14
15#if HW_HELLEN
16#include "hellen_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
25
26static 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
29static 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
32static const char* const trailShortNames[] = { "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "rA", "rB", "rD" };
33
34const char *vvtNames[] = {
35 "VVT1",
36 "VVT2",
37 "VVT3",
38 "VVT4"};
39
40const char *laNames[] = {
41 "input1",
42 "input2",
43 "input3",
44 "input4"};
45
46// these short names are part of engine sniffer protocol
47static 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
50static 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
53static 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
56static 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
59static 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
62static const char* const auxValveShortNames[] = { "a1", "a2"};
63
65
66RegisteredNamedOutputPin::RegisteredNamedOutputPin(const char *p_name, size_t pinOffset,
67 size_t pinModeOffset) : RegisteredOutputPin(p_name, pinOffset, pinModeOffset) {
68}
69
70RegisteredNamedOutputPin::RegisteredNamedOutputPin(const char *p_name, size_t pinOffset) :
71 RegisteredOutputPin(p_name, pinOffset) {
72}
73
74RegisteredOutputPin::RegisteredOutputPin(const char *p_registrationName, size_t pinOffset,
75 size_t pinModeOffset)
77 , registrationName(p_registrationName)
78 , m_pinOffset(static_cast<uint16_t>(pinOffset))
79 , m_hasPinMode(true)
80 , 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
84}
85
86RegisteredOutputPin::RegisteredOutputPin(const char *p_registrationName, size_t pinOffset)
88 , registrationName(p_registrationName)
89 , m_pinOffset(static_cast<uint16_t>(pinOffset))
90 , m_hasPinMode(false)
91 , 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
95}
96
98#if EFI_PROD_CODE
99 brain_pin_e curPin = *(brain_pin_e *) ((void *) (&((char*)&activeConfiguration)[m_pinOffset]));
100 brain_pin_e newPin = *(brain_pin_e *) ((void *) (&((char*) engineConfiguration)[m_pinOffset]));
101 bool pinChanged = curPin != newPin;
102
103 if (!m_hasPinMode) {
104 return pinChanged;
105 }
106
107 pin_output_mode_e curMode = *(pin_output_mode_e *) ((void *) (&((char*)&activeConfiguration)[m_pinModeOffset]));
108 pin_output_mode_e newMode = *(pin_output_mode_e *) ((void *) (&((char*) engineConfiguration)[m_pinModeOffset]));
109 return pinChanged || curMode != newMode;
110#else
111 return true;
112#endif // EFI_PROD_CODE
113}
114
116 brain_pin_e newPin = *(brain_pin_e *) ((void *) (&((char*) engineConfiguration)[m_pinOffset]));
117
118 pin_output_mode_e newMode;
119 if (m_hasPinMode) {
120 newMode = *(pin_output_mode_e *) ((void *) (&((char*) engineConfiguration)[m_pinModeOffset]));
121 } else {
122 newMode = OM_DEFAULT;
123 }
124
126 this->initPin(registrationName, newPin, newMode);
127 }
128}
129
135
136#define CONFIG_OFFSET(x) (offsetof(engine_configuration_s, x))
137// todo: pin and pinMode should be combined into a composite entity
138// todo: one of the impediments is code generator hints handling (we need custom hints and those are not handled nice for fields of structs?)
139#define CONFIG_PIN_OFFSETS(x) CONFIG_OFFSET(x##Pin), CONFIG_OFFSET(x##PinMode)
140
141// offset of X within engineConfiguration, plus offset of Y within X
142// decltype(engine_configuration_s::x) resolves the typename of the struct X inside engineConfiguration
143#define CONFIG_OFFSET2(x, y) (offsetof(engine_configuration_s, x) + offsetof(decltype(engine_configuration_s::x), y))
144#define CONFIG_PIN_OFFSETS2(x, y) CONFIG_OFFSET2(x, y##Pin), CONFIG_OFFSET2(x, y##PinMode)
145
147 // [tag:coding_by_convention] 'mainRelay' member here uses 'mainRelayPin' and 'mainRelayPinMode' configuration fields
148 mainRelay("Main Relay", CONFIG_PIN_OFFSETS(mainRelay)),
149 hpfpValve("HPFP Valve", CONFIG_PIN_OFFSETS(hpfpValve)),
150 starterControl("Starter Relay", CONFIG_PIN_OFFSETS(starterControl)),
151 starterRelayDisable("Starter Disable Relay", CONFIG_PIN_OFFSETS(starterRelayDisable)),
152 fanRelay("Fan Relay", CONFIG_PIN_OFFSETS(fan)),
153 fanRelay2("Fan Relay 2", CONFIG_PIN_OFFSETS(fan2)),
154 acRelay("A/C Relay", CONFIG_PIN_OFFSETS(acRelay)),
155 fuelPumpRelay("Fuel pump Relay", CONFIG_PIN_OFFSETS(fuelPump)),
156 nitrousRelay("Nitrous Relay", CONFIG_PIN_OFFSETS(nitrousRelay)),
157#if EFI_HD_ACR
158 harleyAcr("Harley ACR", CONFIG_OFFSET(acrPin)),
159 harleyAcr2("Harley ACR 2", CONFIG_OFFSET(acrPin2)),
160#endif // EFI_HD_ACR
161 boostPin("Boost", CONFIG_PIN_OFFSETS(boostControl)),
162 idleSolenoidPin("Idle Valve", CONFIG_OFFSET2(idle, solenoidPin), CONFIG_OFFSET2(idle, solenoidPinMode)),
163 secondIdleSolenoidPin("Idle Valve#2", CONFIG_OFFSET(secondSolenoidPin), CONFIG_OFFSET2(idle, solenoidPinMode)),
164 alternatorPin("Alternator control", CONFIG_PIN_OFFSETS(alternatorControl)),
165 checkEnginePin("checkEnginePin", CONFIG_PIN_OFFSETS(malfunctionIndicator)),
166 tachOut("tachOut", CONFIG_PIN_OFFSETS(tachOutput)),
167 triggerDecoderErrorPin("led: trigger debug", CONFIG_PIN_OFFSETS(triggerError)),
168 speedoOut("speedoOut", CONFIG_OFFSET(speedometerOutputPin))
169{
170 hpfpValve.setName("hpfp");
171#if EFI_HD_ACR
172 harleyAcr.setName("acr");
173#endif // EFI_HD_ACR
174
175 static_assert(efi::size(sparkNames) >= MAX_CYLINDER_COUNT, "Too many ignition pins");
176 static_assert(efi::size(trailNames) >= MAX_CYLINDER_COUNT, "Too many ignition pins");
177 static_assert(efi::size(injectorNames) >= MAX_CYLINDER_COUNT, "Too many injection pins");
178 for (int i = 0; i < MAX_CYLINDER_COUNT;i++) {
182
185
189
193 }
194
195 static_assert(efi::size(auxValveShortNames) >= AUX_DIGITAL_VALVE_COUNT, "Too many aux valve pins");
196 for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT;i++) {
198 }
199}
200
201/**
202 * Sets the value of the pin. On this layer the value is assigned as is, without any conversion.
203 */
204
205#define unregisterOutputIfPinChanged(output, pin) { \
206 if (isConfigurationChanged(pin)) { \
207 (output).deInit(); \
208 } \
209}
210
211#define unregisterOutputIfPinOrModeChanged(output, pin, mode) { \
212 if (isPinOrModeChanged(pin, mode)) { \
213 (output).deInit(); \
214 } \
215}
216
218 bool result = false;
219 for (int i = 0; i < MAX_CYLINDER_COUNT; i++) {
220 result |= coils[i].stop();
221 result |= injectors[i].stop();
222 result |= injectorsStage2[i].stop();
223 result |= trailingCoils[i].stop();
224 }
225 for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) {
226 result |= auxValve[i].stop();
227 }
228 return result;
229}
230
234#if EFI_AUX_VALVES
236#endif
237
238#if EFI_ELECTRONIC_THROTTLE_BODY
240#endif /* EFI_ELECTRONIC_THROTTLE_BODY */
241
242 // todo: add pinMode
243 unregisterOutputIfPinChanged(sdCsPin, sdCardCsPin);
244 unregisterOutputIfPinChanged(accelerometerCs, accelerometerCsPin);
245
247 while (pin != nullptr) {
248 pin->unregister();
249 pin = pin->next;
250 }
251}
252
255 while (pin != nullptr) {
256 efiPrintf("%s %d", pin->getRegistrationName(), pin->currentLogicValue);
257 pin = pin->next;
258 }
259}
260
262#if EFI_ENGINE_CONTROL
265#endif /* EFI_ENGINE_CONTROL */
266
267#if EFI_AUX_VALVES
269#endif // EFI_AUX_VALVES
270
272 while (pin != nullptr) {
273 pin->init();
274 pin = pin->next;
275 }
276}
277
279 for (int i = 0; i < MAX_CYLINDER_COUNT;i++) {
280 injectors[i].reset();
281 coils[i].reset();
282 trailingCoils[i].reset();
283 }
284}
285
287 for (int i = 0; i < MAX_CYLINDER_COUNT; i++) {
288 unregisterOutputIfPinOrModeChanged(enginePins.coils[i], ignitionPins[i], ignitionPinMode);
289 unregisterOutputIfPinOrModeChanged(enginePins.trailingCoils[i], trailingCoilPins[i], ignitionPinMode);
290 }
291}
292
294 for (int i = 0; i < MAX_CYLINDER_COUNT; i++) {
295 unregisterOutputIfPinOrModeChanged(enginePins.injectors[i], injectionPins[i], injectionPinMode);
296 unregisterOutputIfPinOrModeChanged(enginePins.injectorsStage2[i], injectionPinsStage2[i], injectionPinMode);
297 }
298}
299
300#if EFI_AUX_VALVES
302 for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) {
303 NamedOutputPin *output = &enginePins.auxValve[i];
304 // todo: do we need auxValveMode and reuse code?
305 if (isConfigurationChanged(auxValves[i])) {
306 (output)->deInit();
307 }
308 }
309}
310
312#if EFI_PROD_CODE
313 for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) {
314 NamedOutputPin *output = &enginePins.auxValve[i];
315 // todo: do we need auxValveMode and reuse code?
316 if (isConfigurationChanged(auxValves[i])) {
317 output->initPin(output->getName(), engineConfiguration->auxValves[i]);
318 }
319 }
320#endif /* EFI_PROD_CODE */
321}
322#endif // EFI_AUX_VALVES
323
325#if EFI_PROD_CODE
326 for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) {
327 NamedOutputPin *trailingOutput = &enginePins.trailingCoils[i];
328 if (isPinOrModeChanged(trailingCoilPins[i], ignitionPinMode)) {
330 }
331
332 NamedOutputPin *output = &enginePins.coils[i];
333 if (isPinOrModeChanged(ignitionPins[i], ignitionPinMode)) {
335 }
336 }
337#endif /* EFI_PROD_CODE */
338}
339
341#if EFI_PROD_CODE
342 // todo: should we move this code closer to the injection logic?
343 for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) {
344 NamedOutputPin *output = &enginePins.injectors[i];
345 if (isPinOrModeChanged(injectionPins[i], injectionPinMode)) {
346 output->initPin(output->getName(), engineConfiguration->injectionPins[i],
348 }
349
350 output = &enginePins.injectorsStage2[i];
351 if (isPinOrModeChanged(injectionPinsStage2[i], injectionPinMode)) {
354 }
355 }
356#endif /* EFI_PROD_CODE */
357}
358
360 switch(index) {
361#if EFI_VVT_PID
362 case BENCH_VVT0_VALVE:
363 return getVvtOutputPin(0);
364 case BENCH_VVT1_VALVE:
365 return getVvtOutputPin(1);
366 case BENCH_VVT2_VALVE:
367 return getVvtOutputPin(2);
368 case BENCH_VVT3_VALVE:
369 return getVvtOutputPin(3);
370#endif // EFI_VVT_PID
371 case BENCH_MAIN_RELAY:
372 return &mainRelay;
373 case BENCH_HPFP_VALVE:
374 return &hpfpValve;
375 case BENCH_FUEL_PUMP:
376 return &fuelPumpRelay;
378 return &starterControl;
380 return &checkEnginePin;
382 return &acRelay;
383 case BENCH_FAN_RELAY:
384 return &fanRelay;
385#if EFI_HD_ACR
386 case HD_ACR:
387 return &harleyAcr;
388 case HD_ACR2:
389 return &harleyAcr2;
390#endif
391 case BENCH_IDLE_VALVE:
392 return &idleSolenoidPin;
394 return &fanRelay;
395 default:
396 criticalError("Unexpected bench pin %d", index);
397 }
398 return nullptr;
399}
400
403
405 name = p_name;
406}
407
408const char *NamedOutputPin::getName() const {
409 return name;
410}
411
412void NamedOutputPin::setName(const char* p_name) {
413 name = p_name;
414}
415
416const char *NamedOutputPin::getShortName() const {
417 return shortName == nullptr ? name : shortName;
418}
419
420#if EFI_UNIT_TEST
421extern bool verboseMode;
422#endif // EFI_UNIT_TEST
423
425 setHigh(nullptr);
426}
427
428void NamedOutputPin::setHigh(const char *msg) {
429#if EFI_UNIT_TEST
430 if (verboseMode) {
431 efiPrintf("pin %s goes high", name);
432 }
433#endif // EFI_UNIT_TEST
434#if EFI_DEFAILED_LOGGING
435// signal->hi_time = hTimeNow();
436#endif /* EFI_DEFAILED_LOGGING */
437
438 // turn the output level ACTIVE
439 setValue(msg, true);
440
441#if EFI_ENGINE_SNIFFER
443#endif /* EFI_ENGINE_SNIFFER */
444}
445
447 setLow(nullptr);
448}
449
450void NamedOutputPin::setLow(const char *msg) {
451#if EFI_UNIT_TEST
452 if (verboseMode) {
453 efiPrintf("pin %s goes low", name);
454 }
455#endif // EFI_UNIT_TEST
456
457 // turn off the output
458 setValue(msg, false);
459
460#if EFI_ENGINE_SNIFFER
462#endif /* EFI_ENGINE_SNIFFER */
463}
464
466#if EFI_GPIO_HARDWARE
467 if (isInitialized() && getLogicValue()) {
468 setValue("stop", false);
469 efiPrintf("turning off %s", name);
470 return true;
471 }
472#endif /* EFI_GPIO_HARDWARE */
473 return false;
474}
475
477 // If this injector was open, close it and reset state
478 if (overlappingCounter != 0) {
480 setValue("reset", 0);
481 }
482
483 // todo: this could be refactored by calling some super-reset method
485}
486
490
493 // this is NASTY but what's the better option? bytes? At cost of 22 extra bytes in output status packet?
494 switch (coilIndex) {
495 case 0:
497 break;
498 case 1:
500 break;
501 case 2:
503 break;
504 case 3:
506 break;
507 case 4:
509 break;
510 case 5:
512 break;
513 }
514}
515
518 // this is NASTY but what's the better option? bytes? At cost of 22 extra bytes in output status packet?
519 switch (coilIndex) {
520 case 0:
522 break;
523 case 1:
525 break;
526 case 2:
528 break;
529 case 3:
531 break;
532 case 4:
534 break;
535 case 5:
537 break;
538 }
539}
540
544
546#if EFI_GPIO_HARDWARE && EFI_PROD_CODE
547#if (BOARD_EXT_GPIOCHIPS > 0)
548 if (ext)
549 return true;
550#endif /* (BOARD_EXT_GPIOCHIPS > 0) */
551 return m_port != NULL;
552#else /* EFI_GPIO_HARDWARE */
553 return true;
554#endif /* EFI_GPIO_HARDWARE */
555}
556
558 setValue("toggle", !getLogicValue());
559}
560
561bool OutputPin::getAndSet(int logicValue) {
562 bool oldValue = getLogicValue();
563 setValue(logicValue);
564 return oldValue;
565}
566
567// This function is only used on real hardware
568#if EFI_PROD_CODE
569void OutputPin::setOnchipValue(int electricalValue) {
571 // todo: make 'setOnchipValue' or 'reportsetOnchipValueError' virtual and override for NamedOutputPin?
572 warning(ObdCode::CUSTOM_ERR_6586, "attempting to change unassigned pin");
573 return;
574 }
575 palWritePad(m_port, m_pin, electricalValue);
576}
577#endif // EFI_PROD_CODE
578
579void OutputPin::setValue(int logicValue, bool isForce) {
580 setValue(nullptr, logicValue, isForce);
581}
582
583#if EFI_SIMULATOR
588#endif // EFI_SIMULATOR
589
590void OutputPin::setValue(const char *msg, int logicValue, bool isForce) {
591 UNUSED(msg);
592 if ((isHwQcMode() || getOutputOnTheBenchTest() == this) && !isForce) {
593 return;
594 }
595
596#if ENABLE_PERF_TRACE
597// todo: https://github.com/rusefi/rusefi/issues/1638
598// ScopePerf perf(PE::OutputPinSetValue);
599#endif // ENABLE_PERF_TRACE
600
601#if EFI_UNIT_TEST
602 if (currentLogicValue != logicValue) {
604 }
605#endif // EFI_UNIT_TEST
606
607#if EFI_SIMULATOR
608 if (currentLogicValue != logicValue) {
609 if (pinToggleCounter > 0) {
611 durationsInStateMs[1] = pinToggleTimer.getElapsedUs() / 1000;
612 }
614 pinToggleTimer.reset();
615 }
616#endif // EFI_SIMULATOR
617
618#if EFI_UNIT_TEST
619 if (verboseMode) {
620 efiPrintf("pin goes %d", logicValue);
621 }
622#endif // EFI_UNIT_TEST
623
624 // Always store the current logical value of the pin (so it can be
625 // used internally even if not connected to a real hardware pin)
626 currentLogicValue = logicValue;
627
628 // Nothing else to do if not configured
630 return;
631 }
632
633 efiAssertVoid(ObdCode::CUSTOM_ERR_6622, mode <= OM_OPENDRAIN_INVERTED, "invalid pin_output_mode_e");
634 int electricalValue = getElectricalValue(logicValue, mode);
635
636#if EFI_PROD_CODE
637 #if (BOARD_EXT_GPIOCHIPS > 0)
638 if (!this->ext) {
639 setOnchipValue(electricalValue);
640 } else {
641 /* external pin */
642 gpiochips_writePad(this->brainPin, logicValue);
643 /* TODO: check return value */
644 }
645 #else
646 setOnchipValue(electricalValue);
647 #endif
648#else /* EFI_PROD_CODE */
649 setMockState(brainPin, electricalValue);
650#endif /* EFI_PROD_CODE */
651}
652
654 // Compare against 1 since it could also be INITIAL_PIN_STATE (which means logical 0, but we haven't initialized the pin yet)
655 return currentLogicValue == 1;
656}
657
659 assertOMode(mode);
660 this->mode = outputMode;
661 setValue(false, /*force*/true); // initial state
662}
663
665#if EFI_PROD_CODE
666#if BOARD_EXT_GPIOCHIPS > 0
669 }
670#endif
671#endif /* EFI_PROD_CODE */
672 // TODO: add hook to board code for custom diagnostic, like it is done on S105
673 return PIN_UNKNOWN;
674}
675
677#if EFI_GPIO_HARDWARE
678
679#if HAL_USE_SPI
681#endif /* HAL_USE_SPI */
682
683#if EFI_SHAFT_POSITION_INPUT
684 // todo: migrate remaining OutputPin to RegisteredOutputPin in order to get consistent dynamic pin init/deinit
686#endif // EFI_SHAFT_POSITION_INPUT
687
689
690#endif /* EFI_GPIO_HARDWARE */
691}
692
693void OutputPin::initPin(const char *p_msg, brain_pin_e p_brainPin) {
694 initPin(p_msg, p_brainPin, OM_DEFAULT);
695}
696
697void OutputPin::initPin(const char *msg, brain_pin_e p_brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError) {
698#if EFI_UNIT_TEST
700#endif
701
702 if (!isBrainPinValid(p_brainPin)) {
703 return;
704 }
705
706 // Enter a critical section so that other threads can't change the pin state out from underneath us
707 chibios_rt::CriticalSectionLocker csl;
708
709 if (!forceInitWithFatalError && hasFirmwareError()) {
710 // Don't allow initializing more pins if we have a fatal error.
711 // Pins should have just been reset, so we shouldn't try to init more.
712 return;
713 }
714
715 // Check that this OutputPin isn't already assigned to another pin (reinit is allowed to change mode)
716 // To avoid this error, call deInit() first
717 if (isBrainPinValid(brainPin) && brainPin != p_brainPin) {
718 firmwareError(ObdCode::CUSTOM_OBD_PIN_CONFLICT, "outputPin [%s] already assigned, cannot reassign without unregister first", msg);
719 return;
720 }
721
722 if (outputMode > OM_OPENDRAIN_INVERTED) {
723 firmwareError(ObdCode::CUSTOM_INVALID_MODE_SETTING, "%s invalid pin_output_mode_e %d %s",
724 msg,
725 outputMode,
726 hwPortname(p_brainPin)
727 );
728 return;
729 }
730
731#if EFI_GPIO_HARDWARE && EFI_PROD_CODE
732 iomode_t l_mode = (outputMode == OM_DEFAULT || outputMode == OM_INVERTED) ?
733 PAL_MODE_OUTPUT_PUSHPULL : PAL_MODE_OUTPUT_OPENDRAIN;
734
735 #if (BOARD_EXT_GPIOCHIPS > 0)
736 this->ext = false;
737 #endif
738 if (brain_pin_is_onchip(p_brainPin)) {
739 m_port = getHwPort(msg, p_brainPin);
740 m_pin = getHwPin(msg, p_brainPin);
741
742 // Validate port
743 if (!m_port) {
744 criticalError("OutputPin::initPin got invalid port for pin idx %d", static_cast<int>(p_brainPin));
745 return;
746 }
747 }
748 #if (BOARD_EXT_GPIOCHIPS > 0)
749 else {
750 this->ext = true;
751 }
752 #endif
753#endif // briefly leave the include guard because we need to set default state in tests
754
755 brainPin = p_brainPin;
756
757 // The order of the next two calls may look strange, which is a good observation.
758 // We call them in this order so that the pin is set to a known state BEFORE
759 // it's enabled. Enabling the pin then setting it could result in a (brief)
760 // mystery state being driven on the pin (potentially dangerous).
761 setDefaultPinState(outputMode);
762
763#if EFI_GPIO_HARDWARE && EFI_PROD_CODE
764 efiSetPadMode(msg, brainPin, l_mode);
766 // todo: handle OM_OPENDRAIN and OM_OPENDRAIN_INVERTED as well
767 if (outputMode == OM_DEFAULT || outputMode == OM_INVERTED) {
768#ifndef DISABLE_PIN_STATE_VALIDATION
769 int actualValue = palReadPad(m_port, m_pin);
770 // we had enough drama with pin configuration in board.h and else that we shall self-check
771
772 const int logicalValue =
773 (outputMode == OM_INVERTED)
774 ? !actualValue
775 : actualValue;
776
777 // if the pin was set to logical 1, then set an error and disable the pin so that things don't catch fire
778 if (logicalValue) {
779 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));
781 }
782#endif
783 }
784 }
785#endif /* EFI_GPIO_HARDWARE */
786}
787
789 // Unregister under lock - we don't want other threads mucking with the pin while we're trying to turn it off
790 chibios_rt::CriticalSectionLocker csl;
791
792 // nothing to do if not registered in the first place
794 return;
795 }
796
797#if (BOARD_EXT_GPIOCHIPS > 0)
798 ext = false;
799#endif // (BOARD_EXT_GPIOCHIPS > 0)
800
801 efiPrintf("unregistering %s", hwPortname(brainPin));
802
803#if EFI_GPIO_HARDWARE && EFI_PROD_CODE
805#endif /* EFI_GPIO_HARDWARE */
806
807 // Clear the pin so that it won't get set any more
809}
810
811#if EFI_GPIO_HARDWARE
812
813// questionable trick: we avoid using 'getHwPort' and 'getHwPin' in case of errors in order to increase the changes of turning the LED
814// by reducing stack requirement
818
819#if EFI_PROD_CODE
820static void initErrorLed(Gpio led) {
821 enginePins.errorLedPin.initPin("led: CRITICAL status", led, (LED_PIN_MODE));
822 criticalErrorLedPort = getHwPort("CRITICAL", led);
823 criticalErrorLedPin = getHwPin("CRITICAL", led);
824 criticalErrorLedState = (LED_PIN_MODE == OM_INVERTED) ? 0 : 1;
825}
826#endif /* EFI_PROD_CODE */
827
829#if EFI_PROD_CODE
830 initErrorLed(LED_CRITICAL_ERROR_BRAIN_PIN);
831
833#endif /* EFI_PROD_CODE */
834}
835
836/**
837 * This method is part of fatal error handling.
838 * The whole method is pretty naive, but that's at least something.
839 */
841 for (int i = 0; i < MAX_CYLINDER_COUNT; i++) {
842 enginePins.injectors[i].setValue(false);
843 enginePins.coils[i].setValue(false);
845 }
848 enginePins.checkEnginePin.setValue(true); // yes this one can go ON
849#if EFI_PROD_CODE && HW_HELLEN
851#endif
852}
853#endif /* EFI_GPIO_HARDWARE */
854
static SimplePwm alternatorControl("alt")
const char * getPin_output_mode_e(pin_output_mode_e value)
const OutputPin * getOutputOnTheBenchTest()
Utility methods related to bench testing.
void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode)
bool isHwQcMode()
TunerStudioOutputChannels outputChannels
Definition engine.h:102
RegisteredOutputPin harleyAcr2
Definition efi_gpio.h:95
RegisteredNamedOutputPin harleyAcr
Definition efi_gpio.h:94
OutputPin accelerometerCs
Definition efi_gpio.h:124
static void debug()
Definition efi_gpio.cpp:253
void startPins()
Definition efi_gpio.cpp:261
InjectorOutputPin injectorsStage2[MAX_CYLINDER_COUNT]
Definition efi_gpio.h:127
RegisteredOutputPin mainRelay
Definition efi_gpio.h:76
NamedOutputPin auxValve[AUX_DIGITAL_VALVE_COUNT]
Definition efi_gpio.h:130
void startAuxValves()
Definition efi_gpio.cpp:311
void startIgnitionPins()
Definition efi_gpio.cpp:324
OutputPin o2heater
Definition efi_gpio.h:98
RegisteredOutputPin fanRelay
Definition efi_gpio.h:86
IgnitionOutputPin trailingCoils[MAX_CYLINDER_COUNT]
Definition efi_gpio.h:129
OutputPin errorLedPin
Definition efi_gpio.h:104
RegisteredOutputPin starterControl
Definition efi_gpio.h:82
OutputPin debugTriggerSync
Definition efi_gpio.h:109
void startInjectionPins()
Definition efi_gpio.cpp:340
void stopInjectionPins()
Definition efi_gpio.cpp:293
void reset()
Definition efi_gpio.cpp:278
InjectorOutputPin injectors[MAX_CYLINDER_COUNT]
Definition efi_gpio.h:126
void stopAuxValves()
Definition efi_gpio.cpp:301
bool stopPins()
Definition efi_gpio.cpp:217
RegisteredOutputPin fuelPumpRelay
Definition efi_gpio.h:91
void unregisterPins()
Definition efi_gpio.cpp:231
RegisteredOutputPin acRelay
Definition efi_gpio.h:90
OutputPin * getOutputPinForBenchMode(bench_mode_e idx)
Definition efi_gpio.cpp:359
IgnitionOutputPin coils[MAX_CYLINDER_COUNT]
Definition efi_gpio.h:128
OutputPin sdCsPin
Definition efi_gpio.h:123
RegisteredOutputPin checkEnginePin
Definition efi_gpio.h:117
RegisteredOutputPin idleSolenoidPin
Definition efi_gpio.h:111
RegisteredNamedOutputPin hpfpValve
Definition efi_gpio.h:80
void stopIgnitionPins()
Definition efi_gpio.cpp:286
void setHigh() override
Definition efi_gpio.cpp:491
void setLow() override
Definition efi_gpio.cpp:516
const char * getName() const
Definition efi_gpio.cpp:408
virtual void setLow()
Definition efi_gpio.cpp:446
void setName(const char *)
Definition efi_gpio.cpp:412
const char * shortName
Definition efi_output.h:129
const char * name
Definition efi_output.h:133
virtual void setHigh()
Definition efi_gpio.cpp:424
const char * getShortName() const
Definition efi_gpio.cpp:416
Single output pin reference and state.
Definition efi_output.h:50
Timer pinToggleTimer
Definition efi_output.h:81
brain_pin_diag_e getDiag() const
Definition efi_gpio.cpp:664
uint32_t durationsInStateMs[2]
Definition efi_output.h:82
void resetToggleStats()
Definition efi_gpio.cpp:584
void deInit()
Definition efi_gpio.cpp:788
void initPin(const char *msg, brain_pin_e brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError=false)
Definition efi_gpio.cpp:697
bool getLogicValue() const
Definition efi_gpio.cpp:653
pin_output_mode_e mode
Definition efi_output.h:105
void setOnchipValue(int electricalValue)
Definition efi_gpio.cpp:569
bool getAndSet(int logicValue)
Definition efi_gpio.cpp:561
void setValue(const char *msg, int logicValue, bool isForce=false)
Definition efi_gpio.cpp:590
void toggle()
Definition efi_gpio.cpp:557
int8_t currentLogicValue
Definition efi_output.h:94
ioportid_t m_port
Definition efi_output.h:72
bool isInitialized() const
Definition efi_gpio.cpp:545
int pinToggleCounter
Definition efi_output.h:77
uint8_t m_pin
Definition efi_output.h:73
brain_pin_e brainPin
Definition efi_output.h:87
void setDefaultPinState(pin_output_mode_e mode)
Definition efi_gpio.cpp:658
RegisteredNamedOutputPin(const char *name, size_t pinOffset, size_t pinModeOffset)
Definition efi_gpio.cpp:66
const char *const registrationName
Definition efi_gpio.h:53
RegisteredOutputPin(const char *registrationName, size_t pinOffset, size_t pinModeOffset)
Definition efi_gpio.cpp:74
const uint16_t m_pinModeOffset
Definition efi_gpio.h:56
const bool m_hasPinMode
Definition efi_gpio.h:55
bool isPinConfigurationChanged()
Definition efi_gpio.cpp:97
const uint16_t m_pinOffset
Definition efi_gpio.h:54
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
@ Unassigned
@ Invalid
int gpiochips_writePad(brain_pin_e pin, int value)
Set value to gpio of gpiochip.
Definition core.cpp:335
brain_pin_diag_e gpiochips_getDiag(brain_pin_e pin)
Get diagnostic for given gpio.
Definition core.cpp:373
ioportmask_t criticalErrorLedPin
Definition efi_gpio.cpp:816
bool verboseMode
const char * laNames[]
Definition efi_gpio.cpp:40
static const char *const auxValveShortNames[]
Definition efi_gpio.cpp:62
static const char *const trailNames[]
Definition efi_gpio.cpp:29
static const char *const injectorNames[]
Definition efi_gpio.cpp:50
static RegisteredOutputPin * registeredOutputHead
Definition efi_gpio.cpp:64
void initPrimaryPins()
Definition efi_gpio.cpp:828
ioportid_t criticalErrorLedPort
Definition efi_gpio.cpp:815
static const char *const sparkShortNames[]
Definition efi_gpio.cpp:47
uint8_t criticalErrorLedState
Definition efi_gpio.cpp:817
void turnAllPinsOff()
Definition efi_gpio.cpp:840
static const char *const injectorStage2Names[]
Definition efi_gpio.cpp:56
EnginePins enginePins
Definition efi_gpio.cpp:24
static const char *const sparkNames[]
Definition efi_gpio.cpp:26
static const char *const injectorShortNames[]
Definition efi_gpio.cpp:53
static const char *const injectorStage2ShortNames[]
Definition efi_gpio.cpp:59
const char * vvtNames[]
Definition efi_gpio.cpp:34
static void initErrorLed(Gpio led)
Definition efi_gpio.cpp:820
void initMiscOutputPins()
Definition efi_gpio.cpp:676
static const char *const trailShortNames[]
Definition efi_gpio.cpp:32
ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
EnginePins enginePins
Definition efi_gpio.cpp:24
ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
void unregisterEtbPins()
static Engine *const engine
Definition engine.h:389
engine_configuration_s & activeConfiguration
static constexpr engine_configuration_s * engineConfiguration
void addEngineSnifferOutputPinEvent(NamedOutputPin *pin, FrontDirection frontDirection)
rusEfi console wave sniffer
bench_mode_e
@ BENCH_AC_COMPRESSOR_RELAY
@ BENCH_FAN_RELAY
@ BENCH_VVT0_VALVE
@ BENCH_MAIN_RELAY
@ HD_ACR2
@ BENCH_IDLE_VALVE
@ HD_ACR
@ BENCH_CHECK_ENGINE_LIGHT
@ BENCH_VVT3_VALVE
@ BENCH_VVT1_VALVE
@ BENCH_FAN_RELAY_2
@ BENCH_HPFP_VALVE
@ BENCH_FUEL_PUMP
@ BENCH_STARTER_ENABLE_RELAY
@ BENCH_VVT2_VALVE
bool warning(ObdCode code, const char *fmt,...)
void firmwareError(ObdCode code, const char *fmt,...)
uint32_t ioportmask_t
Digital I/O port sized unsigned type.
Definition hal_pal_lld.h:78
GPIO_TypeDef * ioportid_t
Port Identifier.
uint32_t iomode_t
Digital I/O modes.
Definition hal_pal_lld.h:83
void hellenDisableEnSilently()
void efiSetPadUnused(brain_pin_e brainPin)
Definition io_pins.cpp:20
void setMockState(brain_pin_e pin, bool state)
Definition io_pins.cpp:129
UNUSED(samplingTimeSeconds)
@ CUSTOM_INVALID_MODE_SETTING
@ CUSTOM_OBD_PIN_CONFLICT
@ CUSTOM_ERR_6622
@ CUSTOM_ERR_6586
const char * hwPortname(brain_pin_e brainPin)
bool brain_pin_is_onchip(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
brain_pin_diag_e
pin_output_mode_e
starterRelayDisable("starterRelayDisable", SensorCategory.SENSOR_INPUTS, FieldType.INT8, 401, 1.0, -10000.0, 10000.0, "")
bool verboseMode
brain_pin_e pin
Definition stm32_adc.cpp:15
OutputPin * getVvtOutputPin(int index)
Definition vvt.cpp:146