| 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 | 50005 | bool RegisteredOutputPin::isPinConfigurationChanged() { | ||
| 98 | 50005 | brain_pin_e curPin = *(brain_pin_e *) ((void *) (&((char*)&activeConfiguration)[m_pinOffset])); | ||
| 99 | 50005 | brain_pin_e newPin = *(brain_pin_e *) ((void *) (&((char*) engineConfiguration)[m_pinOffset])); | ||
| 100 | 50005 | bool pinChanged = curPin != newPin; | ||
| 101 | ||||
| 102 |
2/2✓ Branch 0 taken 2778 times.
✓ Branch 1 taken 47227 times.
|
2/2✓ Decision 'true' taken 2778 times.
✓ Decision 'false' taken 47227 times.
|
50005 | if (!m_hasPinMode) { |
| 103 | 2778 | return pinChanged; | ||
| 104 | } | |||
| 105 | ||||
| 106 | 47227 | pin_output_mode_e curMode = *(pin_output_mode_e *) ((void *) (&((char*)&activeConfiguration)[m_pinModeOffset])); | ||
| 107 | 47227 | pin_output_mode_e newMode = *(pin_output_mode_e *) ((void *) (&((char*) engineConfiguration)[m_pinModeOffset])); | ||
| 108 |
3/4✓ Branch 0 taken 47107 times.
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 47107 times.
|
47227 | return pinChanged || curMode != newMode; | |
| 109 | } | |||
| 110 | ||||
| 111 | 25003 | void RegisteredOutputPin::init() { | ||
| 112 | 25003 | 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 23614 times.
✓ Branch 1 taken 1389 times.
|
2/2✓ Decision 'true' taken 23614 times.
✓ Decision 'false' taken 1389 times.
|
25003 | if (m_hasPinMode) { |
| 116 | 23614 | newMode = *(pin_output_mode_e *) ((void *) (&((char*) engineConfiguration)[m_pinModeOffset])); | ||
| 117 | } else { | |||
| 118 | 1389 | newMode = OM_DEFAULT; | ||
| 119 | } | |||
| 120 | ||||
| 121 |
2/2✓ Branch 1 taken 116 times.
✓ Branch 2 taken 24887 times.
|
2/2✓ Decision 'true' taken 116 times.
✓ Decision 'false' taken 24887 times.
|
25003 | if (isPinConfigurationChanged()) { |
| 122 | 116 | this->initPin(registrationName, newPin, newMode); | ||
| 123 | } | |||
| 124 | 25003 | } | ||
| 125 | ||||
| 126 | 25002 | void RegisteredOutputPin::unregister() { | ||
| 127 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 24998 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 24998 times.
|
25002 | if (isPinConfigurationChanged()) { |
| 128 | 4 | OutputPin::deInit(); | ||
| 129 | } | |||
| 130 | 25002 | } | ||
| 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 | 1003 | bool EnginePins::stopPins() { | ||
| 215 | 1003 | bool result = false; | ||
| 216 |
2/2✓ Branch 0 taken 12036 times.
✓ Branch 1 taken 1003 times.
|
2/2✓ Decision 'true' taken 12036 times.
✓ Decision 'false' taken 1003 times.
|
13039 | for (int i = 0; i < MAX_CYLINDER_COUNT; i++) { |
| 217 | 12036 | result |= coils[i].stop(); | ||
| 218 | 12036 | result |= injectors[i].stop(); | ||
| 219 | 12036 | result |= injectorsStage2[i].stop(); | ||
| 220 | 12036 | result |= trailingCoils[i].stop(); | ||
| 221 | } | |||
| 222 |
2/2✓ Branch 0 taken 2006 times.
✓ Branch 1 taken 1003 times.
|
2/2✓ Decision 'true' taken 2006 times.
✓ Decision 'false' taken 1003 times.
|
3009 | for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) { |
| 223 | 2006 | result |= auxValve[i].stop(); | ||
| 224 | } | |||
| 225 | 1003 | return result; | ||
| 226 | } | |||
| 227 | ||||
| 228 | 1389 | void EnginePins::unregisterPins() { | ||
| 229 | 1389 | stopInjectionPins(); | ||
| 230 | 1389 | stopIgnitionPins(); | ||
| 231 | #if EFI_AUX_VALVES | |||
| 232 | 1389 | stopAuxValves(); | ||
| 233 | #endif | |||
| 234 | ||||
| 235 | #if EFI_ELECTRONIC_THROTTLE_BODY | |||
| 236 | 1389 | unregisterEtbPins(); | ||
| 237 | #endif /* EFI_ELECTRONIC_THROTTLE_BODY */ | |||
| 238 | ||||
| 239 | // todo: add pinMode | |||
| 240 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1389 times.
|
1389 | unregisterOutputIfPinChanged(sdCsPin, sdCardCsPin); | |
| 241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1389 times.
|
1389 | unregisterOutputIfPinChanged(accelerometerCs, accelerometerCsPin); | |
| 242 | ||||
| 243 | 1389 | RegisteredOutputPin * pin = registeredOutputHead; | ||
| 244 |
2/2✓ Branch 0 taken 25002 times.
✓ Branch 1 taken 1389 times.
|
2/2✓ Decision 'true' taken 25002 times.
✓ Decision 'false' taken 1389 times.
|
26391 | while (pin != nullptr) { |
| 245 | 25002 | pin->unregister(); | ||
| 246 | 25002 | pin = pin->next; | ||
| 247 | } | |||
| 248 | 1389 | } | ||
| 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 | 1389 | void EnginePins::startPins() { | ||
| 259 | #if EFI_ENGINE_CONTROL | |||
| 260 | 1389 | startInjectionPins(); | ||
| 261 | 1389 | startIgnitionPins(); | ||
| 262 | #endif /* EFI_ENGINE_CONTROL */ | |||
| 263 | ||||
| 264 | #if EFI_AUX_VALVES | |||
| 265 | 1389 | startAuxValves(); | ||
| 266 | #endif // EFI_AUX_VALVES | |||
| 267 | ||||
| 268 | 1389 | RegisteredOutputPin * pin = registeredOutputHead; | ||
| 269 |
2/2✓ Branch 0 taken 25002 times.
✓ Branch 1 taken 1389 times.
|
2/2✓ Decision 'true' taken 25002 times.
✓ Decision 'false' taken 1389 times.
|
26391 | while (pin != nullptr) { |
| 270 | 25002 | pin->init(); | ||
| 271 | 25002 | pin = pin->next; | ||
| 272 | } | |||
| 273 | 1389 | } | ||
| 274 | ||||
| 275 | 1755 | void EnginePins::reset() { | ||
| 276 |
2/2✓ Branch 0 taken 21060 times.
✓ Branch 1 taken 1755 times.
|
2/2✓ Decision 'true' taken 21060 times.
✓ Decision 'false' taken 1755 times.
|
22815 | for (int i = 0; i < MAX_CYLINDER_COUNT;i++) { |
| 277 | 21060 | injectors[i].reset(); | ||
| 278 | 21060 | coils[i].reset(); | ||
| 279 | 21060 | trailingCoils[i].reset(); | ||
| 280 | } | |||
| 281 | 1755 | } | ||
| 282 | ||||
| 283 | 1389 | void EnginePins::stopIgnitionPins() { | ||
| 284 |
2/2✓ Branch 0 taken 16668 times.
✓ Branch 1 taken 1389 times.
|
2/2✓ Decision 'true' taken 16668 times.
✓ Decision 'false' taken 1389 times.
|
18057 | for (int i = 0; i < MAX_CYLINDER_COUNT; i++) { |
| 285 |
2/4✓ Branch 2 taken 16668 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16668 times.
|
16668 | unregisterOutputIfPinOrModeChanged(enginePins.coils[i], ignitionPins[i], ignitionPinMode); | |
| 286 |
2/4✓ Branch 2 taken 16668 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16668 times.
|
16668 | unregisterOutputIfPinOrModeChanged(enginePins.trailingCoils[i], trailingCoilPins[i], ignitionPinMode); | |
| 287 | } | |||
| 288 | 1389 | } | ||
| 289 | ||||
| 290 | 1389 | void EnginePins::stopInjectionPins() { | ||
| 291 |
2/2✓ Branch 0 taken 16668 times.
✓ Branch 1 taken 1389 times.
|
2/2✓ Decision 'true' taken 16668 times.
✓ Decision 'false' taken 1389 times.
|
18057 | for (int i = 0; i < MAX_CYLINDER_COUNT; i++) { |
| 292 |
2/4✓ Branch 2 taken 16668 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16668 times.
|
16668 | unregisterOutputIfPinOrModeChanged(enginePins.injectors[i], injectionPins[i], injectionPinMode); | |
| 293 |
2/4✓ Branch 2 taken 16668 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16668 times.
|
16668 | unregisterOutputIfPinOrModeChanged(enginePins.injectorsStage2[i], injectionPinsStage2[i], injectionPinMode); | |
| 294 | } | |||
| 295 | 1389 | } | ||
| 296 | ||||
| 297 | #if EFI_AUX_VALVES | |||
| 298 | 1389 | void EnginePins::stopAuxValves() { | ||
| 299 |
2/2✓ Branch 0 taken 2778 times.
✓ Branch 1 taken 1389 times.
|
2/2✓ Decision 'true' taken 2778 times.
✓ Decision 'false' taken 1389 times.
|
4167 | for (int i = 0; i < AUX_DIGITAL_VALVE_COUNT; i++) { |
| 300 | 2778 | 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 2776 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2776 times.
|
2778 | if (isConfigurationChanged(auxValves[i])) { |
| 303 | 2 | (output)->deInit(); | ||
| 304 | } | |||
| 305 | } | |||
| 306 | 1389 | } | ||
| 307 | ||||
| 308 | 1389 | 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 | 1389 | } | ||
| 319 | #endif // EFI_AUX_VALVES | |||
| 320 | ||||
| 321 | 1389 | 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 | 1389 | } | ||
| 336 | ||||
| 337 | 1389 | 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 | 1389 | } | ||
| 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 | 584 | void EnginePins::resetForUnitTest() { | ||
| 407 | 584 | RegisteredOutputPin * pin = registeredOutputHead; | ||
| 408 |
2/2✓ Branch 0 taken 10512 times.
✓ Branch 1 taken 584 times.
|
2/2✓ Decision 'true' taken 10512 times.
✓ Decision 'false' taken 584 times.
|
11096 | while (pin != nullptr) { |
| 409 | 10512 | pin->brainPin = Gpio::Unassigned; | ||
| 410 | 10512 | pin = pin->next; | ||
| 411 | } | |||
| 412 | 584 | } | ||
| 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 | 56204 | const char *NamedOutputPin::getName() const { | ||
| 423 | 56204 | return name; | ||
| 424 | } | |||
| 425 | ||||
| 426 | 51 | void NamedOutputPin::setName(const char* p_name) { | ||
| 427 | 51 | name = p_name; | ||
| 428 | 51 | } | ||
| 429 | ||||
| 430 | 20017 | const char *NamedOutputPin::getShortName() const { | ||
| 431 |
2/2✓ Branch 0 taken 97 times.
✓ Branch 1 taken 19920 times.
|
20017 | return shortName == nullptr ? name : shortName; | |
| 432 | } | |||
| 433 | ||||
| 434 | #if EFI_UNIT_TEST | |||
| 435 | extern bool verboseMode; | |||
| 436 | #endif // EFI_UNIT_TEST | |||
| 437 | ||||
| 438 | 9668 | void NamedOutputPin::setHigh() { | ||
| 439 | 9668 | setHigh(nullptr); | ||
| 440 | 9668 | } | ||
| 441 | ||||
| 442 | 9687 | void NamedOutputPin::setHigh(const char *msg) { | ||
| 443 | #if EFI_UNIT_TEST | |||
| 444 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9687 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 9687 times.
|
9687 | 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 | 9687 | setValue(msg, true); | ||
| 454 | ||||
| 455 | #if EFI_ENGINE_SNIFFER | |||
| 456 | 9687 | addEngineSnifferOutputPinEvent(this, FrontDirection::UP); | ||
| 457 | #endif /* EFI_ENGINE_SNIFFER */ | |||
| 458 | 9687 | } | ||
| 459 | ||||
| 460 | 10312 | void NamedOutputPin::setLow() { | ||
| 461 | 10312 | setLow(nullptr); | ||
| 462 | 10312 | } | ||
| 463 | ||||
| 464 | 10330 | void NamedOutputPin::setLow(const char *msg) { | ||
| 465 | #if EFI_UNIT_TEST | |||
| 466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10330 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 10330 times.
|
10330 | if (verboseMode) { |
| 467 | ✗ | efiPrintf("pin %s goes low", name); | ||
| 468 | } | |||
| 469 | #endif // EFI_UNIT_TEST | |||
| 470 | ||||
| 471 | // turn off the output | |||
| 472 | 10330 | setValue(msg, false); | ||
| 473 | ||||
| 474 | #if EFI_ENGINE_SNIFFER | |||
| 475 | 10330 | addEngineSnifferOutputPinEvent(this, FrontDirection::DOWN); | ||
| 476 | #endif /* EFI_ENGINE_SNIFFER */ | |||
| 477 | 10330 | } | ||
| 478 | ||||
| 479 | 50150 | bool NamedOutputPin::stop() { | ||
| 480 | #if EFI_GPIO_HARDWARE | |||
| 481 |
5/6✓ Branch 1 taken 50150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 50146 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 50146 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 50146 times.
|
50150 | 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 | 50146 | return false; | ||
| 488 | } | |||
| 489 | ||||
| 490 | 24173 | 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 24124 times.
|
2/2✓ Decision 'true' taken 49 times.
✓ Decision 'false' taken 24124 times.
|
24173 | 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 | 24173 | currentLogicValue = 0; | ||
| 499 | 24173 | } | ||
| 500 | ||||
| 501 | 24 | IgnitionOutputPin::IgnitionOutputPin() { | ||
| 502 | 24 | reset(); | ||
| 503 | 24 | } | ||
| 504 | ||||
| 505 | 6283 | void IgnitionOutputPin::setHigh() { | ||
| 506 | 6283 | 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 5672 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.
|
6283 | switch (coilIndex) { | |
| 509 |
1/1✓ Decision 'true' taken 5672 times.
|
5672 | case 0: | |
| 510 | 5672 | engine->outputChannels.coilState1 = true; | ||
| 511 | 5672 | 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 | 6283 | } | ||
| 529 | ||||
| 530 | 6945 | void IgnitionOutputPin::setLow() { | ||
| 531 | 6945 | 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 6301 times.
✓ Branch 1 taken 152 times.
✓ Branch 2 taken 310 times.
✓ Branch 3 taken 69 times.
✓ Branch 4 taken 57 times.
✓ Branch 5 taken 56 times.
✗ Branch 6 not taken.
|
6945 | switch (coilIndex) { | |
| 534 |
1/1✓ Decision 'true' taken 6301 times.
|
6301 | case 0: | |
| 535 | 6301 | engine->outputChannels.coilState1 = false; | ||
| 536 | 6301 | break; | ||
| 537 |
1/1✓ Decision 'true' taken 152 times.
|
152 | case 1: | |
| 538 | 152 | engine->outputChannels.coilState2 = false; | ||
| 539 | 152 | break; | ||
| 540 |
1/1✓ Decision 'true' taken 310 times.
|
310 | case 2: | |
| 541 | 310 | engine->outputChannels.coilState3 = false; | ||
| 542 | 310 | break; | ||
| 543 |
1/1✓ Decision 'true' taken 69 times.
|
69 | case 3: | |
| 544 | 69 | engine->outputChannels.coilState4 = false; | ||
| 545 | 69 | break; | ||
| 546 |
1/1✓ Decision 'true' taken 57 times.
|
57 | case 4: | |
| 547 | 57 | engine->outputChannels.coilState5 = false; | ||
| 548 | 57 | break; | ||
| 549 |
1/1✓ Decision 'true' taken 56 times.
|
56 | case 5: | |
| 550 | 56 | engine->outputChannels.coilState6 = false; | ||
| 551 | 56 | break; | ||
| 552 | } | |||
| 553 | 6945 | } | ||
| 554 | ||||
| 555 | 42144 | void IgnitionOutputPin::reset() { | ||
| 556 | 42144 | signalFallSparkId = 0; | ||
| 557 | 42144 | } | ||
| 558 | ||||
| 559 | 58919 | 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 | 58919 | return true; | ||
| 568 | #endif /* EFI_GPIO_HARDWARE */ | |||
| 569 | } | |||
| 570 | ||||
| 571 | 6321 | void OutputPin::toggle() { | ||
| 572 | 6321 | setValue("toggle", !getLogicValue()); | ||
| 573 | 6321 | } | ||
| 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 | 13554 | void OutputPin::setValue(int logicValue, bool isForce) { | ||
| 594 | 13554 | setValue(nullptr, logicValue, isForce); | ||
| 595 | 13554 | } | ||
| 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 | 42123 | void OutputPin::setValue(const char *msg, int logicValue, bool isForce) { | ||
| 605 | UNUSED(msg); | |||
| 606 |
3/8✓ Branch 1 taken 42123 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42123 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 42123 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 42123 times.
|
42123 | 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 26187 times.
✓ Branch 1 taken 15936 times.
|
2/2✓ Decision 'true' taken 26187 times.
✓ Decision 'false' taken 15936 times.
|
42123 | if (currentLogicValue != logicValue) { |
| 617 | 26187 | 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 42123 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 42123 times.
|
42123 | 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 | 42123 | currentLogicValue = logicValue; | ||
| 641 | ||||
| 642 | // Nothing else to do if not configured | |||
| 643 |
2/2✓ Branch 1 taken 41666 times.
✓ Branch 2 taken 457 times.
|
2/2✓ Decision 'true' taken 41666 times.
✓ Decision 'false' taken 457 times.
|
42123 | if (!isBrainPinValid(brainPin)) { |
| 644 | 41666 | 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 | 1655533 | 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 | 1655533 | 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 | 584 | 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 | 584 | enginePins.debugTriggerSync.initPin("debug: sync", engineConfiguration->debugTriggerSync); | ||
| 700 | #endif // EFI_SHAFT_POSITION_INPUT | |||
| 701 | ||||
| 702 | 584 | enginePins.o2heater.initPin("O2 heater", engineConfiguration->o2heaterPin); | ||
| 703 | ||||
| 704 | #endif /* EFI_GPIO_HARDWARE */ | |||
| 705 | 584 | } | ||
| 706 | ||||
| 707 | 1179 | void OutputPin::initPin(const char *p_msg, brain_pin_e p_brainPin) { | ||
| 708 | 1179 | initPin(p_msg, p_brainPin, OM_DEFAULT); | ||
| 709 | 1178 | } | ||
| 710 | ||||
| 711 | 1299 | void OutputPin::initPin(const char *msg, brain_pin_e p_brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError) { | ||
| 712 | #if EFI_UNIT_TEST | |||
| 713 | 1299 | pinToggleCounter = 0; | ||
| 714 | #endif | |||
| 715 | ||||
| 716 |
2/2✓ Branch 1 taken 1175 times.
✓ Branch 2 taken 124 times.
|
2/2✓ Decision 'true' taken 1175 times.
✓ Decision 'false' taken 124 times.
|
1299 | if (!isBrainPinValid(p_brainPin)) { |
| 717 | 1175 | 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 |