rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
sensor_checker.cpp
Go to the documentation of this file.
1#include "pch.h"
2
3// Decode what OBD code we should use for a particular [sensor, code] problem
4static ObdCode getCode(SensorType type, UnexpectedCode code) {
5 switch (type) {
8 switch (code) {
9 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;
16 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 default: break;
21 } break;
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;
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
41 switch (code) {
42 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 case UnexpectedCode::Inconsistent: return ObdCode::OBD_PPS_Correlation;
46 default: break;
47 } break;
49 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 default: break;
54 } 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;
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 return ObdCode::None;
89}
90
91inline const char* describeUnexpected(UnexpectedCode code) {
92 switch (code) {
93 case UnexpectedCode::Timeout: return "has timed out";
94 case UnexpectedCode::High: return "input too high";
95 case UnexpectedCode::Low: return "input too low";
96 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
104static void check(SensorType type) {
105 // Don't check sensors we don't have
106 if (!Sensor::hasSensor(type)) {
107 return;
108 }
109
110 auto result = Sensor::get(type);
111
112 // If the sensor is OK, nothing to check.
113 if (result) {
114 return;
115 }
116
117 ObdCode code = getCode(type, result.Code);
118
119 if (code != ObdCode::None) {
120 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
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
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
153static 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
167PUBLIC_API_WEAK void boardSensorChecker() {
168}
169
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 bool shouldCheck = m_ignitionIsOn && m_timeSinceIgnOff.hasElapsedSec(5);
174 m_analogSensorsShouldWork = shouldCheck;
175 if (!shouldCheck) {
176 return;
177 }
178
179 // Check sensors
186
190
193
196
198
199#if EFI_PROD_CODE
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++) {
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++) {
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
264}
265
267 m_ignitionIsOn = ignitionOn;
268
269 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}
ObdCode analogGetDiagnostic()
uint8_t code
Definition bluetooth.cpp:40
FuelComputer fuelComputer
Definition engine.h:139
InjectorOutputPin injectors[MAX_CYLINDER_COUNT]
Definition efi_gpio.h:127
IgnitionOutputPin coils[MAX_CYLINDER_COUNT]
Definition efi_gpio.h:129
brain_pin_diag_e getDiag() const
Definition efi_gpio.cpp:678
virtual bool hasSensor() const
Definition sensor.h:141
virtual SensorResult get() const =0
const char * getSensorName() const
Definition sensor.h:130
EnginePins enginePins
Definition efi_gpio.cpp:24
static EngineAccessor engine
Definition engine.h:413
bool warning(ObdCode code, const char *fmt,...)
UNUSED(samplingTimeSeconds)
ObdCode
@ OBD_Clt_Timeout
@ OBD_Map_High
@ OBD_Iat_High
@ OBD_TPS1_Secondary_High
@ OBD_TPS1_Primary_Low
@ OBD_TPS2_Secondary_Low
@ OBD_PPS_Primary_Timeout
@ OBD_TPS1_Primary_High
@ OBD_PPS_Primary_High
@ OBD_Injector_Circuit_1
@ OBD_TPS2_Secondary_High
@ OBD_TPS2_Primary_Low
@ OBD_Ignition_Circuit_1
@ OBD_TPS1_Correlation
@ OBD_PPS_Secondary_High
@ OBD_FlexSensor_High
@ OBD_TPS2_Primary_Timeout
@ OBD_TPS1_Secondary_Timeout
@ OBD_Clt_High
@ OBD_TPS2_Primary_High
@ OBD_TPS2_Correlation
@ OBD_PPS_Correlation
@ OBD_TPS1_Primary_Timeout
@ OBD_Map_Timeout
@ OBD_PPS_Secondary_Low
@ OBD_PPS_Secondary_Timeout
@ OBD_PPS_Primary_Low
@ OBD_FlexSensor_Low
@ OBD_Injector_Circuit_1_High
@ OBD_TPS1_Secondary_Low
@ OBD_TPS2_Secondary_Timeout
@ OBD_FlexSensor_Timeout
@ OBD_Iat_Timeout
@ OBD_Injector_Circuit_1_Low
void pinDiag2string(char *buffer, size_t size, brain_pin_diag_e pin_diag)
bool isBrainPinValid(brain_pin_e brainPin)
brain_pin_diag_e
static ObdCode getCode(SensorType type, UnexpectedCode code)
static ObdCode getCodeForIgnition(int idx, brain_pin_diag_e diag)
static ObdCode getCodeForInjector(int idx, brain_pin_diag_e diag)
static void check(SensorType type)
static uint8_t getTSErrorCode(brain_pin_diag_e diag)
const char * describeUnexpected(UnexpectedCode code)
PUBLIC_API_WEAK void boardSensorChecker()
SensorType
Definition sensor_type.h:18
@ FuelEthanolPercent
@ AcceleratorPedalPrimary
@ AcceleratorPedalSecondary
state("state", SensorCategory.SENSOR_INPUTS, FieldType.INT8, 1871, 1.0, -1.0, -1.0, "")
brain_pin_e pin
Definition stm32_adc.cpp:15
void onSlowCallback() override
Timer m_timeSinceIgnOff
void onIgnitionStateChanged(bool ignitionOn) override
bool m_analogSensorsShouldWork
TunerStudioOutputChannels * getTunerStudioOutputChannels()
Definition engine.cpp:581