2022-07-30 14:08:48 -07:00
|
|
|
#include "pch.h"
|
|
|
|
|
|
|
|
// Decode what OBD code we should use for a particular [sensor, code] problem
|
2023-04-11 16:32:47 -07:00
|
|
|
static ObdCode getCode(SensorType type, UnexpectedCode code) {
|
2022-07-30 14:08:48 -07:00
|
|
|
switch (type) {
|
|
|
|
case SensorType::Tps1:
|
|
|
|
case SensorType::Tps1Primary:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_TPS1_Primary_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_TPS1_Primary_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_TPS1_Primary_High;
|
|
|
|
case UnexpectedCode::Inconsistent: return ObdCode::OBD_TPS1_Correlation;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
case SensorType::Tps1Secondary:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_TPS1_Secondary_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_TPS1_Secondary_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_TPS1_Secondary_High;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
case SensorType::Tps2:
|
|
|
|
case SensorType::Tps2Primary:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_TPS2_Primary_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_TPS2_Primary_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_TPS2_Primary_High;
|
|
|
|
case UnexpectedCode::Inconsistent: return ObdCode::OBD_TPS2_Correlation;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
case SensorType::Tps2Secondary:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_TPS2_Secondary_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_TPS2_Secondary_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_TPS2_Secondary_High;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case SensorType::AcceleratorPedal:
|
|
|
|
case SensorType::AcceleratorPedalPrimary:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_PPS_Primary_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_PPS_Primary_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_PPS_Primary_High;
|
|
|
|
case UnexpectedCode::Inconsistent: return ObdCode::OBD_PPS_Correlation;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
case SensorType::AcceleratorPedalSecondary:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_PPS_Secondary_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_PPS_Secondary_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_PPS_Secondary_High;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case SensorType::Map:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_Map_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_Map_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_Map_High;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
case SensorType::Clt:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_Clt_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_Clt_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_Clt_High;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
case SensorType::Iat:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_Iat_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_Iat_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_Iat_High;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
case SensorType::FuelEthanolPercent:
|
|
|
|
switch (code) {
|
2023-04-11 17:01:34 -07:00
|
|
|
case UnexpectedCode::Timeout: return ObdCode::OBD_FlexSensor_Timeout;
|
|
|
|
case UnexpectedCode::Low: return ObdCode::OBD_FlexSensor_Low;
|
|
|
|
case UnexpectedCode::High: return ObdCode::OBD_FlexSensor_High;
|
2022-07-30 14:08:48 -07:00
|
|
|
default: break;
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-04-11 17:01:34 -07:00
|
|
|
return ObdCode::None;
|
2022-07-30 14:08:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline const char* describeUnexpected(UnexpectedCode code) {
|
|
|
|
switch (code) {
|
|
|
|
case UnexpectedCode::Timeout: return "has timed out";
|
|
|
|
case UnexpectedCode::High: return "input too high";
|
|
|
|
case UnexpectedCode::Low: return "input too low";
|
|
|
|
case UnexpectedCode::Inconsistent: return "is inconsistent";
|
|
|
|
case UnexpectedCode::Configuration: return "is misconfigured";
|
|
|
|
case UnexpectedCode::Unknown:
|
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check(SensorType type) {
|
|
|
|
// Don't check sensors we don't have
|
|
|
|
if (!Sensor::hasSensor(type)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto result = Sensor::get(type);
|
|
|
|
|
|
|
|
// If the sensor is OK, nothing to check.
|
|
|
|
if (result) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-11 16:32:47 -07:00
|
|
|
ObdCode code = getCode(type, result.Code);
|
2022-07-30 14:08:48 -07:00
|
|
|
|
2023-04-11 17:01:34 -07:00
|
|
|
if (code != ObdCode::None) {
|
2022-07-30 14:08:48 -07:00
|
|
|
warning(code, "Sensor fault: %s %s", Sensor::getSensorName(type), describeUnexpected(result.Code));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:24:28 -07:00
|
|
|
#if BOARD_EXT_GPIOCHIPS > 0 && EFI_PROD_CODE
|
2023-11-05 12:55:29 -08:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2023-04-11 16:32:47 -07:00
|
|
|
static ObdCode getCodeForInjector(int idx, brain_pin_diag_e diag) {
|
2023-11-23 06:48:10 -08:00
|
|
|
if (idx < 0 || idx >= MAX_CYLINDER_COUNT) {
|
2023-04-11 17:01:34 -07:00
|
|
|
return ObdCode::None;
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-03 02:30:13 -08:00
|
|
|
if ((diag & PIN_OPEN) || (diag & PIN_SHORT_TO_GND)) {
|
|
|
|
return (ObdCode)((int)ObdCode::OBD_Injector_Circuit_1_Low + (idx * 3));
|
|
|
|
} else if ((diag & PIN_SHORT_TO_BAT) || (diag & PIN_OVERLOAD)) {
|
|
|
|
return (ObdCode)((int)ObdCode::OBD_Injector_Circuit_1_High + (idx * 3));
|
|
|
|
}
|
2022-08-01 12:41:47 -07:00
|
|
|
|
2024-01-03 02:30:13 -08:00
|
|
|
/* else common error code */
|
2023-04-11 17:01:34 -07:00
|
|
|
return (ObdCode)((int)ObdCode::OBD_Injector_Circuit_1 + idx);
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
2023-11-05 12:55:29 -08:00
|
|
|
#endif // EFI_ENGINE_CONTROL
|
2022-08-01 12:41:47 -07:00
|
|
|
|
2023-04-11 16:32:47 -07:00
|
|
|
static ObdCode getCodeForIgnition(int idx, brain_pin_diag_e diag) {
|
2023-11-23 06:48:10 -08:00
|
|
|
if (idx < 0 || idx >= MAX_CYLINDER_COUNT) {
|
2023-04-11 17:01:34 -07:00
|
|
|
return ObdCode::None;
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: do something more intelligent with `diag`?
|
|
|
|
UNUSED(diag);
|
|
|
|
|
2023-04-11 17:01:34 -07:00
|
|
|
return (ObdCode)((int)ObdCode::OBD_Ignition_Circuit_1 + idx);
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
2024-01-04 04:17:15 -08:00
|
|
|
|
|
|
|
static uint8_t getTSErrorCode(brain_pin_diag_e diag)
|
|
|
|
{
|
|
|
|
/* Error codes reported to TS:
|
|
|
|
* 0 - output is not used
|
|
|
|
* 1 - ok status/no diagnostic available (TODO: separate codes)
|
|
|
|
* >1 - see brain_pin_diag_e, first least significant 1-bit position + 1 *
|
2024-03-15 17:09:32 -07:00
|
|
|
* Keep in sync with outputDiagErrorList in tunerstudio.template.ini
|
2024-01-04 04:17:15 -08:00
|
|
|
* Note:
|
|
|
|
* diag can be combination of few errors,
|
|
|
|
* while we report only one error to simplify hadling on TS side
|
|
|
|
* find position of least significant 1-bit */
|
|
|
|
return __builtin_ffs(diag) + 1;
|
|
|
|
}
|
2023-11-04 19:34:28 -07:00
|
|
|
#endif // BOARD_EXT_GPIOCHIPS > 0 && EFI_PROD_CODE
|
2022-08-01 12:41:47 -07:00
|
|
|
|
2024-05-19 12:32:18 -07:00
|
|
|
PUBLIC_API_WEAK void boardSensorChecker() {
|
|
|
|
}
|
|
|
|
|
2022-07-30 14:08:48 -07:00
|
|
|
void SensorChecker::onSlowCallback() {
|
|
|
|
// Don't check when the ignition is off, or when it was just turned on (let things stabilize)
|
|
|
|
// TODO: also inhibit checking if we just did a flash burn, since that blocks the ECU for a few seconds.
|
2022-11-30 19:20:09 -08:00
|
|
|
bool shouldCheck = m_ignitionIsOn && m_timeSinceIgnOff.hasElapsedSec(5);
|
|
|
|
m_analogSensorsShouldWork = shouldCheck;
|
2023-04-11 13:06:38 -07:00
|
|
|
if (!shouldCheck) {
|
2022-07-30 14:08:48 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-01 12:41:47 -07:00
|
|
|
// Check sensors
|
2022-07-30 14:08:48 -07:00
|
|
|
check(SensorType::Tps1Primary);
|
|
|
|
check(SensorType::Tps1Secondary);
|
|
|
|
check(SensorType::Tps1);
|
|
|
|
check(SensorType::Tps2Primary);
|
|
|
|
check(SensorType::Tps2Secondary);
|
|
|
|
check(SensorType::Tps2);
|
|
|
|
|
2022-11-30 19:20:09 -08:00
|
|
|
check(SensorType::AcceleratorPedalPrimary);
|
|
|
|
check(SensorType::AcceleratorPedalSecondary);
|
|
|
|
check(SensorType::AcceleratorPedal);
|
2022-07-30 14:08:48 -07:00
|
|
|
|
|
|
|
check(SensorType::Map);
|
2022-11-30 19:20:09 -08:00
|
|
|
check(SensorType::Map2);
|
2022-07-30 14:08:48 -07:00
|
|
|
|
|
|
|
check(SensorType::Clt);
|
|
|
|
check(SensorType::Iat);
|
|
|
|
|
|
|
|
check(SensorType::FuelEthanolPercent);
|
2022-08-01 12:41:47 -07:00
|
|
|
|
|
|
|
// only bother checking these if we have GPIO chips actually capable of reporting an error
|
|
|
|
#if BOARD_EXT_GPIOCHIPS > 0 && EFI_PROD_CODE
|
2024-01-04 04:17:15 -08:00
|
|
|
TunerStudioOutputChannels *state = getTunerStudioOutputChannels();
|
2022-08-01 12:41:47 -07:00
|
|
|
// Check injectors
|
2023-11-05 09:09:25 -08:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2023-11-23 06:48:10 -08:00
|
|
|
int unhappyInjector = 0;
|
2022-10-30 06:47:53 -07:00
|
|
|
for (size_t i = 0; i < efi::size(enginePins.injectors); i++) {
|
2022-08-01 12:41:47 -07:00
|
|
|
InjectorOutputPin& pin = enginePins.injectors[i];
|
|
|
|
|
|
|
|
// Skip not-configured pins
|
|
|
|
if (!isBrainPinValid(pin.brainPin)) {
|
2024-01-04 04:17:15 -08:00
|
|
|
state->injectorDiagnostic[i] = 0;
|
2022-08-01 12:41:47 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto diag = pin.getDiag();
|
2024-01-28 07:35:14 -08:00
|
|
|
if (diag != PIN_OK && diag != PIN_UNKNOWN) {
|
2023-11-23 06:48:10 -08:00
|
|
|
unhappyInjector = 1 + i;
|
2023-09-11 04:07:43 -07:00
|
|
|
auto code = getCodeForInjector(i, diag);
|
2022-08-01 12:41:47 -07:00
|
|
|
|
|
|
|
char description[32];
|
|
|
|
pinDiag2string(description, efi::size(description), diag);
|
2023-09-11 04:07:43 -07:00
|
|
|
warning(code, "Injector %d fault: %s", i + 1, description);
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
2024-01-04 04:17:15 -08:00
|
|
|
state->injectorDiagnostic[i] = getTSErrorCode(diag);
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
2023-11-23 06:48:10 -08:00
|
|
|
engine->fuelComputer.brokenInjector = unhappyInjector;
|
|
|
|
engine->fuelComputer.injectorHwIssue = (unhappyInjector != 0);
|
2023-11-05 09:09:25 -08:00
|
|
|
#endif // EFI_ENGINE_CONTROL
|
2022-08-01 12:41:47 -07:00
|
|
|
|
|
|
|
// Check ignition
|
2022-10-30 06:47:53 -07:00
|
|
|
for (size_t i = 0; i < efi::size(enginePins.injectors); i++) {
|
2022-08-01 12:41:47 -07:00
|
|
|
IgnitionOutputPin& pin = enginePins.coils[i];
|
|
|
|
|
|
|
|
// Skip not-configured pins
|
|
|
|
if (!isBrainPinValid(pin.brainPin)) {
|
2024-01-04 04:17:15 -08:00
|
|
|
state->ignitorDiagnostic[i] = 0;
|
2022-08-01 12:41:47 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto diag = pin.getDiag();
|
2024-01-28 07:35:14 -08:00
|
|
|
if (diag != PIN_OK && diag != PIN_UNKNOWN) {
|
2023-09-11 04:07:43 -07:00
|
|
|
auto code = getCodeForIgnition(i, diag);
|
2022-08-01 12:41:47 -07:00
|
|
|
|
|
|
|
char description[32];
|
|
|
|
pinDiag2string(description, efi::size(description), diag);
|
2023-09-11 04:07:43 -07:00
|
|
|
warning(code, "Ignition %d fault: %s", i + 1, description);
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
2024-01-04 04:17:15 -08:00
|
|
|
state->ignitorDiagnostic[i] = getTSErrorCode(diag);
|
2022-08-01 12:41:47 -07:00
|
|
|
}
|
|
|
|
#endif // BOARD_EXT_GPIOCHIPS > 0
|
2024-05-19 12:32:18 -07:00
|
|
|
boardSensorChecker();
|
2022-07-30 14:08:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void SensorChecker::onIgnitionStateChanged(bool ignitionOn) {
|
|
|
|
m_ignitionIsOn = ignitionOn;
|
|
|
|
|
|
|
|
if (!ignitionOn) {
|
|
|
|
// timer keeps track of how long since the state was turned to on (ie, how long ago was it last off)
|
|
|
|
m_timeSinceIgnOff.reset();
|
|
|
|
}
|
|
|
|
}
|