| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | #include "pch.h" | |||
| 2 | ||||
| 3 | // Decode what OBD code we should use for a particular [sensor, code] problem | |||
| 4 | 14 | static ObdCode getCode(SensorType type, UnexpectedCode code) { | ||
| 5 |
4/11✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
14 | switch (type) { | |
| 6 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case SensorType::Tps1: | |
| 7 | case SensorType::Tps1Primary: | |||
| 8 |
1/5✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1/1✓ Decision 'true' taken 2 times.
|
2 | switch (code) { |
| 9 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case UnexpectedCode::Timeout: return ObdCode::OBD_TPS1_Primary_Timeout; | |
| 10 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_TPS1_Primary_Low; | ||
| 11 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_TPS1_Primary_High; | ||
| 12 | ✗ | case UnexpectedCode::Inconsistent: return ObdCode::OBD_TPS1_Correlation; | ||
| 13 | ✗ | default: break; | ||
| 14 | ✗ | } break; | ||
| 15 |
1/1✓ Decision 'true' taken 4 times.
|
4 | case SensorType::Tps1Secondary: | |
| 16 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | switch (code) { | |
| 17 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_TPS1_Secondary_Timeout; | ||
| 18 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_TPS1_Secondary_Low; | ||
| 19 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_TPS1_Secondary_High; | ||
| 20 |
1/1✓ Decision 'true' taken 4 times.
|
4 | default: break; | |
| 21 | 4 | } break; | ||
| 22 | ✗ | case SensorType::Tps2: | ||
| 23 | case SensorType::Tps2Primary: | |||
| 24 | ✗ | switch (code) { | ||
| 25 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_TPS2_Primary_Timeout; | ||
| 26 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_TPS2_Primary_Low; | ||
| 27 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_TPS2_Primary_High; | ||
| 28 | ✗ | case UnexpectedCode::Inconsistent: return ObdCode::OBD_TPS2_Correlation; | ||
| 29 | ✗ | default: break; | ||
| 30 | ✗ | } break; | ||
| 31 | ✗ | case SensorType::Tps2Secondary: | ||
| 32 | ✗ | switch (code) { | ||
| 33 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_TPS2_Secondary_Timeout; | ||
| 34 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_TPS2_Secondary_Low; | ||
| 35 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_TPS2_Secondary_High; | ||
| 36 | ✗ | default: break; | ||
| 37 | ✗ | } break; | ||
| 38 | ||||
| 39 |
1/1✓ Decision 'true' taken 4 times.
|
4 | case SensorType::AcceleratorPedal: | |
| 40 | case SensorType::AcceleratorPedalPrimary: | |||
| 41 |
2/5✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
1/1✓ Decision 'true' taken 4 times.
|
4 | switch (code) { |
| 42 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case UnexpectedCode::Timeout: return ObdCode::OBD_PPS_Primary_Timeout; | |
| 43 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_PPS_Primary_Low; | ||
| 44 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_PPS_Primary_High; | ||
| 45 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case UnexpectedCode::Inconsistent: return ObdCode::OBD_PPS_Correlation; | |
| 46 | ✗ | default: break; | ||
| 47 | ✗ | } break; | ||
| 48 |
1/1✓ Decision 'true' taken 4 times.
|
4 | case SensorType::AcceleratorPedalSecondary: | |
| 49 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | switch (code) { | |
| 50 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_PPS_Secondary_Timeout; | ||
| 51 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_PPS_Secondary_Low; | ||
| 52 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_PPS_Secondary_High; | ||
| 53 |
1/1✓ Decision 'true' taken 4 times.
|
4 | default: break; | |
| 54 | 4 | } break; | ||
| 55 | ||||
| 56 | ✗ | case SensorType::Map: | ||
| 57 | ✗ | switch (code) { | ||
| 58 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_Map_Timeout; | ||
| 59 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_Map_Low; | ||
| 60 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_Map_High; | ||
| 61 | ✗ | default: break; | ||
| 62 | ✗ | } break; | ||
| 63 | ✗ | case SensorType::Clt: | ||
| 64 | ✗ | switch (code) { | ||
| 65 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_Clt_Timeout; | ||
| 66 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_Clt_Low; | ||
| 67 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_Clt_High; | ||
| 68 | ✗ | default: break; | ||
| 69 | ✗ | } break; | ||
| 70 | ✗ | case SensorType::Iat: | ||
| 71 | ✗ | switch (code) { | ||
| 72 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_Iat_Timeout; | ||
| 73 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_Iat_Low; | ||
| 74 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_Iat_High; | ||
| 75 | ✗ | default: break; | ||
| 76 | ✗ | } break; | ||
| 77 | ✗ | case SensorType::FuelEthanolPercent: | ||
| 78 | ✗ | switch (code) { | ||
| 79 | ✗ | case UnexpectedCode::Timeout: return ObdCode::OBD_FlexSensor_Timeout; | ||
| 80 | ✗ | case UnexpectedCode::Low: return ObdCode::OBD_FlexSensor_Low; | ||
| 81 | ✗ | case UnexpectedCode::High: return ObdCode::OBD_FlexSensor_High; | ||
| 82 | ✗ | default: break; | ||
| 83 | ✗ | } break; | ||
| 84 | ✗ | default: | ||
| 85 | ✗ | break; | ||
| 86 | } | |||
| 87 | ||||
| 88 | 8 | return ObdCode::None; | ||
| 89 | } | |||
| 90 | ||||
| 91 | 6 | inline const char* describeUnexpected(UnexpectedCode code) { | ||
| 92 |
2/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
6 | switch (code) { | |
| 93 |
1/1✓ Decision 'true' taken 4 times.
|
4 | case UnexpectedCode::Timeout: return "has timed out"; | |
| 94 | ✗ | case UnexpectedCode::High: return "input too high"; | ||
| 95 | ✗ | case UnexpectedCode::Low: return "input too low"; | ||
| 96 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case UnexpectedCode::Inconsistent: return "is inconsistent"; | |
| 97 | ✗ | case UnexpectedCode::Configuration: return "is misconfigured"; | ||
| 98 | ✗ | case UnexpectedCode::Unknown: | ||
| 99 | default: | |||
| 100 | ✗ | return "unknown"; | ||
| 101 | } | |||
| 102 | } | |||
| 103 | ||||
| 104 | 1246 | static void check(SensorType type) { | ||
| 105 | // Don't check sensors we don't have | |||
| 106 |
3/3✓ Branch 1 taken 1246 times.
✓ Branch 3 taken 1044 times.
✓ Branch 4 taken 202 times.
|
2/2✓ Decision 'true' taken 1044 times.
✓ Decision 'false' taken 202 times.
|
1246 | if (!Sensor::hasSensor(type)) { |
| 107 | 1044 | return; | ||
| 108 | } | |||
| 109 | ||||
| 110 |
1/1✓ Branch 2 taken 202 times.
|
202 | auto result = Sensor::get(type); | |
| 111 | ||||
| 112 | // If the sensor is OK, nothing to check. | |||
| 113 |
2/2✓ Branch 1 taken 188 times.
✓ Branch 2 taken 14 times.
|
2/2✓ Decision 'true' taken 188 times.
✓ Decision 'false' taken 14 times.
|
202 | if (result) { |
| 114 | 188 | return; | ||
| 115 | } | |||
| 116 | ||||
| 117 | 14 | ObdCode code = getCode(type, result.Code); | ||
| 118 | ||||
| 119 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8 times.
|
2/2✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 8 times.
|
14 | if (code != ObdCode::None) { |
| 120 |
2/2✓ Branch 2 taken 6 times.
✓ Branch 5 taken 6 times.
|
6 | warning(code, "Sensor fault: %s %s", Sensor::getSensorName(type), describeUnexpected(result.Code)); | |
| 121 | } | |||
| 122 | } | |||
| 123 | ||||
| 124 | #if BOARD_EXT_GPIOCHIPS > 0 && EFI_PROD_CODE | |||
| 125 | #if EFI_ENGINE_CONTROL | |||
| 126 | static ObdCode getCodeForInjector(int idx, brain_pin_diag_e diag) { | |||
| 127 | if (idx < 0 || idx >= MAX_CYLINDER_COUNT) { | |||
| 128 | return ObdCode::None; | |||
| 129 | } | |||
| 130 | ||||
| 131 | if ((diag & PIN_OPEN) || (diag & PIN_SHORT_TO_GND)) { | |||
| 132 | return (ObdCode)((int)ObdCode::OBD_Injector_Circuit_1_Low + (idx * 3)); | |||
| 133 | } else if ((diag & PIN_SHORT_TO_BAT) || (diag & PIN_OVERLOAD)) { | |||
| 134 | return (ObdCode)((int)ObdCode::OBD_Injector_Circuit_1_High + (idx * 3)); | |||
| 135 | } | |||
| 136 | ||||
| 137 | /* else common error code */ | |||
| 138 | return (ObdCode)((int)ObdCode::OBD_Injector_Circuit_1 + idx); | |||
| 139 | } | |||
| 140 | #endif // EFI_ENGINE_CONTROL | |||
| 141 | ||||
| 142 | static ObdCode getCodeForIgnition(int idx, brain_pin_diag_e diag) { | |||
| 143 | if (idx < 0 || idx >= MAX_CYLINDER_COUNT) { | |||
| 144 | return ObdCode::None; | |||
| 145 | } | |||
| 146 | ||||
| 147 | // TODO: do something more intelligent with `diag`? | |||
| 148 | UNUSED(diag); | |||
| 149 | ||||
| 150 | return (ObdCode)((int)ObdCode::OBD_Ignition_Circuit_1 + idx); | |||
| 151 | } | |||
| 152 | ||||
| 153 | static uint8_t getTSErrorCode(brain_pin_diag_e diag) { | |||
| 154 | /* Error codes reported to TS: | |||
| 155 | * 0 - output is not used | |||
| 156 | * 1 - ok status/no diagnostic available (TODO: separate codes) | |||
| 157 | * >1 - see brain_pin_diag_e, first least significant 1-bit position + 1 * | |||
| 158 | * Keep in sync with outputDiagErrorList in tunerstudio.template.ini | |||
| 159 | * Note: | |||
| 160 | * diag can be combination of few errors, | |||
| 161 | * while we report only one error to simplify handling on TS side | |||
| 162 | * find position of least significant 1-bit */ | |||
| 163 | return __builtin_ffs(diag) + TS_ENUM_OFFSET; | |||
| 164 | } | |||
| 165 | #endif // BOARD_EXT_GPIOCHIPS > 0 && EFI_PROD_CODE | |||
| 166 | ||||
| 167 | 89 | PUBLIC_API_WEAK void boardSensorChecker() { | ||
| 168 | 89 | } | ||
| 169 | ||||
| 170 | 1090 | void SensorChecker::onSlowCallback() { | ||
| 171 | // Don't check when the ignition is off, or when it was just turned on (let things stabilize) | |||
| 172 | // TODO: also inhibit checking if we just did a flash burn, since that blocks the ECU for a few seconds. | |||
| 173 |
3/4✓ Branch 0 taken 89 times.
✓ Branch 1 taken 1001 times.
✓ Branch 3 taken 89 times.
✗ Branch 4 not taken.
|
1090 | bool shouldCheck = m_ignitionIsOn && m_timeSinceIgnOff.hasElapsedSec(5); | |
| 174 | 1090 | m_analogSensorsShouldWork = shouldCheck; | ||
| 175 |
2/2✓ Branch 0 taken 1001 times.
✓ Branch 1 taken 89 times.
|
2/2✓ Decision 'true' taken 1001 times.
✓ Decision 'false' taken 89 times.
|
1090 | if (!shouldCheck) { |
| 176 | 1001 | return; | ||
| 177 | } | |||
| 178 | ||||
| 179 | // Check sensors | |||
| 180 | 89 | check(SensorType::Tps1Primary); | ||
| 181 | 89 | check(SensorType::Tps1Secondary); | ||
| 182 | 89 | check(SensorType::Tps1); | ||
| 183 | 89 | check(SensorType::Tps2Primary); | ||
| 184 | 89 | check(SensorType::Tps2Secondary); | ||
| 185 | 89 | check(SensorType::Tps2); | ||
| 186 | ||||
| 187 | 89 | check(SensorType::AcceleratorPedalPrimary); | ||
| 188 | 89 | check(SensorType::AcceleratorPedalSecondary); | ||
| 189 | 89 | check(SensorType::AcceleratorPedal); | ||
| 190 | ||||
| 191 | 89 | check(SensorType::Map); | ||
| 192 | 89 | check(SensorType::Map2); | ||
| 193 | ||||
| 194 | 89 | check(SensorType::Clt); | ||
| 195 | 89 | check(SensorType::Iat); | ||
| 196 | ||||
| 197 | 89 | check(SensorType::FuelEthanolPercent); | ||
| 198 | ||||
| 199 | #if EFI_PROD_CODE | |||
| 200 | TunerStudioOutputChannels *state = getTunerStudioOutputChannels(); | |||
| 201 | // only bother checking these if we have GPIO chips actually capable of reporting an error | |||
| 202 | #if BOARD_EXT_GPIOCHIPS > 0 | |||
| 203 | #if EFI_ENGINE_CONTROL | |||
| 204 | // Check injectors | |||
| 205 | int unhappyInjector = 0; | |||
| 206 | for (size_t i = 0; i < efi::size(enginePins.injectors); i++) { | |||
| 207 | InjectorOutputPin& pin = enginePins.injectors[i]; | |||
| 208 | ||||
| 209 | // Skip not-configured pins | |||
| 210 | if (!isBrainPinValid(pin.brainPin)) { | |||
| 211 | state->injectorDiagnostic[i] = 0; | |||
| 212 | continue; | |||
| 213 | } | |||
| 214 | ||||
| 215 | auto diag = pin.getDiag(); | |||
| 216 | if (diag != PIN_OK && diag != PIN_UNKNOWN) { | |||
| 217 | unhappyInjector = 1 + i; | |||
| 218 | auto code = getCodeForInjector(i, diag); | |||
| 219 | ||||
| 220 | char description[32]; | |||
| 221 | pinDiag2string(description, efi::size(description), diag); | |||
| 222 | warning(code, "Injector %d fault: %s", i + 1, description); | |||
| 223 | } | |||
| 224 | state->injectorDiagnostic[i] = getTSErrorCode(diag); | |||
| 225 | } | |||
| 226 | engine->fuelComputer.brokenInjector = unhappyInjector; | |||
| 227 | engine->fuelComputer.injectorHwIssue = (unhappyInjector != 0); | |||
| 228 | #endif // EFI_ENGINE_CONTROL | |||
| 229 | ||||
| 230 | // Check ignition | |||
| 231 | for (size_t i = 0; i < efi::size(enginePins.injectors); i++) { | |||
| 232 | IgnitionOutputPin& pin = enginePins.coils[i]; | |||
| 233 | ||||
| 234 | // Skip not-configured pins | |||
| 235 | if (!isBrainPinValid(pin.brainPin)) { | |||
| 236 | state->ignitorDiagnostic[i] = 0; | |||
| 237 | continue; | |||
| 238 | } | |||
| 239 | ||||
| 240 | auto diag = pin.getDiag(); | |||
| 241 | if (diag != PIN_OK && diag != PIN_UNKNOWN) { | |||
| 242 | auto code = getCodeForIgnition(i, diag); | |||
| 243 | ||||
| 244 | char description[32]; | |||
| 245 | pinDiag2string(description, efi::size(description), diag); | |||
| 246 | warning(code, "Ignition %d fault: %s", i + 1, description); | |||
| 247 | } | |||
| 248 | state->ignitorDiagnostic[i] = getTSErrorCode(diag); | |||
| 249 | } | |||
| 250 | #endif // BOARD_EXT_GPIOCHIPS > 0 | |||
| 251 | ||||
| 252 | // Check ADC(s) and analog inputs | |||
| 253 | auto code = analogGetDiagnostic(); | |||
| 254 | if (code != ObdCode::None) { | |||
| 255 | /* TODO: map to more OBD codes? */ | |||
| 256 | warning(code, "Analog subsystem fault"); | |||
| 257 | state->isAnalogFailure = true; | |||
| 258 | } else { | |||
| 259 | state->isAnalogFailure = false; | |||
| 260 | } | |||
| 261 | #endif // EFI_PROD_CODE | |||
| 262 | ||||
| 263 | 89 | boardSensorChecker(); | ||
| 264 | } | |||
| 265 | ||||
| 266 | 3 | void SensorChecker::onIgnitionStateChanged(bool ignitionOn) { | ||
| 267 | 3 | m_ignitionIsOn = ignitionOn; | ||
| 268 | ||||
| 269 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
|
3 | if (!ignitionOn) { |
| 270 | // timer keeps track of how long since the state was turned to on (ie, how long ago was it last off) | |||
| 271 | ✗ | m_timeSinceIgnOff.reset(); | ||
| 272 | } | |||
| 273 | 3 | } | ||
| 274 |