Reading ECU faults (DTC)
This note shows how to configure the device to report which faults the vehicle has —the same codes a workshop scan tool shows— and how to integrate them into a platform.
Until now the device reported whether the vehicle had faults and how many: the equivalent of the dashboard warning light. With the DTC module it reports which ones.
Requires firmware from the 1.09.27 series, which at the time of publishing this note is a
T (pre-release) version delivered via FOTA on request. OBD2 support arrived in T9; with an
earlier T the device only reads J1939. Check with >QVR< before starting.
Compatibility
Rinho Zero IoT has no CAN transceiver: it cannot read vehicle faults.
1. What you get
| Vehicle | Protocol | What it reports |
|---|---|---|
| Truck, bus, machinery, agriculture | J1939 | SPN (which component fails), FMI (how it fails), reporting ECU, occurrence count and dashboard lamps |
| Car, pickup, light utility | OBD2 | The full standard code (P0301, P0420, U0100) and the reporting ECU |
Everything travels over the device’s normal protocol (UDP/TCP/SMS), with queueing, retries and acknowledgement. No extra hardware required: it uses the CAN connection the device already has, and works the same with the CANBUS Contactless (inductive) accessory.
2. Check the bus protocol
This is the step that prevents most problems. The configured protocol must match the vehicle:
>QCXCAN<| Vehicle | Expected protocol |
|---|---|
| Truck, heavy machinery, agriculture | J1939 |
| Car, pickup, light utility | OBDII |
If the protocol does not match the vehicle, the module reports zero faults every time, even with the dashboard lit. It is the most frequent cause of “it doesn’t work”.
3. Enable reading
A single command sets everything in motion:
>SCXDTC1,3,0,1,GP<| Field | Value | Meaning |
|---|---|---|
| 1st | 1 | Enables reading (factory default is 0) |
| 2nd | 3 | Seconds without seeing a code before clearing it |
| 3rd | 0 | Reserved (vehicle clearing, no effect yet) |
| 4th | 1 | Automatic report on new fault or resolution |
| 5th | GP | Report destination: main GPRS |
Verification: >QCXDTC< → RCXDTC1,3,0,1,GP
During commissioning, use LOG as the destination (>SCXDTC1,3,0,1,LOG<): reports are stored in
the device and retrieved together with >QDL+< at the end of the trip, without depending on the
server being up. Once validated, switch to GP.
With the first field at 0 (factory default) the module is completely inactive: it allocates no
memory and does not touch the bus.
4. Query the status
>QDTC<| Response | Meaning |
|---|---|
RDTC0 | Reading the bus, no active faults — a valid result |
RDTC2;J:00:100:1:4;J:00:1761:1:12 | Two active faults (truck) |
RDTC1;O:00:P0301:0:0 | One active fault (light vehicle) |
RDTCNA | Reading is disabled |
On OBD2 the device polls the ECU every 30 seconds: after enabling, wait one cycle before trusting a zero response. On J1939 the ECU broadcasts faults on its own and reading is immediate.
5. What the platform receives
With autorpt=1, every time a new fault appears or all of them clear, a
DF report arrives:
>RDF00020826143512;2;J:00:100:1:4;J:00:1761:1:12<
│ │ │ │
│ │ │ └─ fault list
│ │ └──────── active count (0 = all cleared)
│ └─────────────── date and time OF THE EVENT (ddmmyy hhmmss)
└────────────────── report numberThree things that simplify integration:
- Every report is a full snapshot. No state to rebuild on the server side.
- Date and time are those of the fault, not of transmission: if the vehicle was out of coverage, the report waits in the queue and reports when it actually happened once signal returns.
- Count of zero = resolution. When the last fault disappears, the notice arrives.
It can also be requested at any moment, without waiting for a fault:
>QDF< // direct response over the asking channel
>GDF00H< // queues the report to the configured destination6. Interpreting the codes
J1939
J:00:100:1:4The engine ECU (00) reports that oil pressure (SPN 100) is below the normal range (FMI 1), and
it occurred 4 times.
The FMI tells the type of fault, and that difference changes the diagnosis:
| FMI | Meaning |
|---|---|
| 0 / 1 | Value above / below normal range |
| 2 | Erratic or intermittent data |
| 3 / 4 | Short to power / short to ground |
| 5 / 6 | Open circuit / over-current |
| 7 | Mechanical system not responding |
| 12 | Component damaged |
| 31 | Condition exists, no further detail |
Fuel pressure with FMI 1 is genuinely low pressure (filter, pump). With FMI 5 it is an open circuit: the sensor was disconnected or a wire was cut.
Reference SPNs: 100 oil pressure · 110 coolant temperature · 94 fuel pressure · 190 RPM · 168 battery voltage · 651-656 injectors 1 to 6 · 1761 AdBlue/urea level · 3226 NOx sensor (SCR).
OBD2
O:00:P0301:0:0The engine ECU (00) reports a cylinder 1 misfire (P0301).
| Letter | System |
|---|---|
P | Powertrain |
C | Chassis (brakes, suspension, steering) |
B | Body (airbag, comfort) |
U | Network / module communication |
The last two fields are zero: FMI and occurrence count are J1939 fields, OBD2 does not transmit them.
Codes come out in standard format (SAE J1939 and J2012). Text descriptions (“Catalyst System Efficiency…”) are resolved on the platform with the public tables of the standard, as everywhere else in the market.
7. Reacting in the vehicle, without the server
Faults are event engine triggers: they combine with ignition, speed, inputs or geofences like any other signal.
| Signal | Activates when |
|---|---|
DTC00 | There is at least one active fault |
DTC01 | A new fault appeared |
DTC02 | A dashboard lamp is on (J1939 only) |
DTC03 | All faults were cleared |
// New fault → immediate report to the server
>SRL05E;TRG=DTC01+;ACC={GDF00H}<
// Dashboard lamp on → output to a buzzer in the cabin
>SRL07E;TRG=DTC02+;ACC={SSSXP0011}<
// New fault with ignition on → SMS notice to the supervisor
>SRL08E;TRG=DTC01+;CND=IGN;ACC={GTX01H;@SM0;TXT=Active fault}<For numeric conditions there are the EVAL functions:
>EVAL DTCN()< // number of active faults
>EVAL DTCH(100)< // 1 if oil pressure is in fault (J1939)
>EVAL DTC(2)< // 1 if a dashboard lamp is onAnd the 'DTC' token inserts the full list into any user report:
>SUC00 $ID faults:'DTC'<8. If no fault shows up
In order, most frequent first:
- The protocol does not match the vehicle —
>QCXCAN<:J1939on a truck,OBDIIon a light vehicle. - Reading is disabled —
>QDTC<answersRDTCNA. Enable it withSCXDTC. - The firmware T is earlier than 9 and the vehicle is light —
>QVR<. OBD2 support arrived in1.09.27.T9. - The 30-second OBD2 cycle has not elapsed — wait one more round.
- The vehicle has no active faults —
RDTC0is a correct result. Cross-check with the dashboard or a scan tool. - The ECU does not publish faults — not all of them broadcast on the bus (J1939) or answer Mode 03 (OBD2), the same as with the VIN. Confirm by checking whether other engine data arrives (RPM, temperature) with ECU.
If faults appear in >QDTC< but no report arrives: check the 4th field of SCXDTC (must be 1)
and the 5th, the destination. With LOG the report does not go over the network: it stays in the
device and is retrieved with >QDL+<.
9. Current scope
| Function | Status |
|---|---|
| Active J1939 faults, one or several ECUs, one or several codes | ✅ |
| Active OBD2 faults, one or several ECUs | ✅ |
| Automatic, on-demand and rule-driven reporting | ✅ |
| Signals, EVAL functions and template token | ✅ |
Clearing the device list (CDTC) | ✅ |
| Clearing faults on the vehicle (DM11 / Mode 04) | ❌ Planned |
| Stored or pending faults (DM2 / Mode 07) | ❌ Planned |
| Dashboard lamps on OBD2 | ❌ J1939 only |
DTCH() over OBD2 codes | ❌ J1939 only (searches by SPN) |
Limits: up to 32 simultaneous faults in the device table and about 15 per frame (the reported count is always the real one). On J1939 the module is listen-only and transmits nothing on the bus; on OBD2 it polls every 30 seconds, just like a scan tool plugged into the diagnostic connector.
See Also
- CXDTC Command - Full command reference
- DF Report - Fault report format
- CXCAN Command - Bus protocol selection
- ECU Command - Engine telemetry