Trace from the W177, line by line¶
This page goes through the traces of the first test on a real car: Mercedes A 180 d
(W177, diesel), adapter FORScan ELMconfig (ELM327 v1.5, CH340) at /dev/ttyUSB0,
38400 baud, engine off, ignition on, 2026-10-09. How the test went and what was fixed
afterwards is described under First test at the car.
Note
Redacted. The serial number of the VIN (positions 12 to 17) is replaced with
000000, in the hex bytes as well as in plain text. Otherwise the lines are unchanged.
All byte examples on this page are checked against the code by
tests/unit/test_docs_examples.py; the whole diagnosis trace runs as a regression test
(tests/verification/test_real_car.py, traces in
tests/fixtures/traces/mercedes_w177/).
Each line of a trace (--trace) has the time since opening the port in seconds, the
direction (>> to the adapter, << from the adapter) and the text, with \r for the
line break. > at the end is the prompt: the adapter is ready for the next command.
The format is described under Sessions, report and trace.
Connection setup¶
0.016 >> ATZ\r
0.817 << \r\rELM327 v1.5\r\r>
0.817 >> ATE0\r
0.825 << ATE0\rOK\r\r>
0.826 >> ATL0\r
0.834 << OK\r\r>
0.834 >> ATS0\r
0.843 << OK\r\r>
0.843 >> ATH0\r
0.852 << OK\r\r>
0.852 >> ATSP0\r
0.861 << OK\r\r>
0.861 >> ATRV\r
0.875 << 11.2V\r\r>
ATZ resets the adapter and takes about 0.8 s. The response to ATE0 (echo off) still
includes the echo, after that no more. ATL0, ATS0, ATH0 switch off linefeed,
spaces and headers, ATSP0 selects the automatic protocol search (Communication with the ELM327).
ATRV is the voltage the adapter itself measures at pin 16: 11.2 V.
Right after plugging in, the very first command looked different:
0.024 >> ATZ\r
0.033 << ATZ\r?\r\r>
The adapter rejected the first ATZ with ?, probably because of a garbage byte in
the adapter’s buffer. Since this test, an ATZ answered with ? is repeated once; the
second time it returned ELM327 v1.5 as above.
Protocol search and four control units¶
0.925 >> 0100\r
1.255 << SEARCHING...\r410098180001\r410098180001\r410098180011\r410098180001\r\r>
1.255 >> ATDPN\r
1.264 << A7\r\r>
1.264 >> ATDP\r
1.282 << AUTO, ISO 15765-4 (CAN 29/500)\r\r>
The first 0100 starts the protocol search (SEARCHING...); after 0.3 s it is done.
Then four lines follow: four control units answer the request, each with its list
of supported PIDs. ATDPN reports A7: A means “found automatically”, 7 is
ISO 15765-4 CAN with 29-bit addresses and 500 kbit/s. Hence can=True, so the count
byte is read for trouble codes (Response formats).
One line taken apart:
Bytes |
Meaning |
|---|---|
|
positive response to mode 01, PID 00 |
|
bit mask: PIDs |
|
the same, one of the control units additionally reports |
The order of the four lines is not fixed: in the live trace the same response came as
…0001, …0011, …0001, …0001. Without headers a line can therefore not be
assigned to a control unit. obd-diag treats each line as a response of its own and
evaluates it by content, not by position.
Fewer and fewer control units answer the further lists (0120 to 0180, in the live
trace). Together the vehicle offers these PIDs:
List |
Responses |
supported PIDs |
|---|---|---|
|
4 |
|
|
4 |
|
|
3 |
|
|
2 |
|
|
2 |
|
obd-diag now reads 68, 6C, 6D, 70 and 85 (intake air, throttle, rail
pressure, boost pressure, AdBlue; PID formulas), decoded according to J1979 but without
a real response from the W177 yet: this trace did not query them. 88 and 92 are
pure status bit fields and stay out. The next test on the car should record the new
values.
Control module voltage (PID 42)¶
1.290 >> 0142\r
1.320 << 41422EDC\r\r>
Only one control unit answers. 2E DC is 11996 mV, so 12.0 V, a good 0.8 V more
than the 11.2 V from ATRV. The adapter measures at pin 16, often behind a protection
diode, and therefore shows less. Since this test obd-diag reads PID 42 when ATRV is
below 11.8 V and takes the control unit’s value if it is plausible (5 to 30 V). This
query did not exist yet in the test itself; the line comes from the live trace of the
same session and is inserted at this point in the regression test.
Trouble codes¶
1.332 >> 03\r
1.562 << 4301D218\r4300\r4300\r4300\r\r>
1.612 >> 07\r
1.701 << 4700\r4700\r4700\r4700\r\r>
1.752 >> 0A\r
1.837 << 4A00\r\r>
Response |
Meaning |
|---|---|
|
mode 03, count byte |
|
three control units: no stored codes |
|
no pending codes (mode 07) |
|
no permanent codes (mode 0A); only one control unit answers |
D2 18 decoded: the upper two bits of D (11) give U (network), the next two
(01) the 1, the rest 2 18: U1218. The 1 in second place means
manufacturer-specific, which is why the catalog has no text for it
(Reading and clearing trouble codes).
Readiness (mode 01 PID 01)¶
1.887 >> 0101\r
1.973 << 4101000EEB20\r410100040000\r4101000C0200\r4101010C0000\r\r>
Byte A is the check engine light (bit 7) and the number of codes (bits 0 to 6), B the general monitors and the engine type (bit 3), C and D the engine-specific monitors (OBD-II services).
Response |
MIL |
Codes |
Diesel |
Monitors |
|---|---|---|---|---|
|
off |
0 |
yes |
six complete, exhaust gas sensor incomplete |
|
off |
0 |
no |
components only |
|
off |
0 |
yes |
components, NOx aftertreatment |
|
off |
1 |
yes |
components only |
The first is probably the engine control unit, the fourth the one with U1218 (it
reports the one code). The order of the lines means nothing, though: without headers
the responses come sorted differently for every request (in the second test
00 04 00 00 was in front as well). obd-diag combines the four (combine_readiness):
the engine type is decided by the control units that support engine-specific monitors
(byte C not 0), here the three diesel lines. The second control unit does report bit
B3 = 0, but has no monitors in C/D and therefore only counts for the general monitors
from byte B. Per monitor the worst state counts, the MIL is on if one reports it, and the
codes are added up. Result: check engine light off, one code, diesel, everything
complete except the exhaust gas sensor, misfire not supported.
Freeze frame (mode 02)¶
2.023 >> 020200\r
2.091 << 4202000000\r4202000000\r4202000000\r420200D218\r\r>
2.141 >> 020400\r
2.201 << 42040000\r\r>
2.251 >> 020500\r
2.312 << 4205004D\r\r>
2.362 >> 020C00\r
2.422 << 420C000000\r\r>
2.473 >> 020D00\r
2.529 << 420D0000\r\r>
020200 asks which code triggered the freeze frame (frame 00). Three control units
answer 00 00: no freeze frame. One answers D2 18, so U1218. Before this test
obd-diag took the first line and showed “unknown”; now the line with a code counts.
The values after that only come from this one control unit: load 00 = 0 %, coolant
4D = 77 − 40 = 37 °C, engine speed 00 00 = 0, speed 00 = 0. So the code was
stored while stationary with a half-warm engine.
VIN (mode 09 PID 02)¶
2.579 >> 0902\r
2.656 << 014\r0:490201574444\r1:31373730303331\r2:4A303030303030\r\r>
A multi-frame ISO-TP response in ELM format (Response formats): 014 is 20 bytes
of payload, namely 49 02 01 (response, PID, count) and the 17 characters of the VIN
in ASCII. Assembled: WDD1770031J000000.
Positions |
Value |
Meaning |
|---|---|---|
1 to 3 |
|
manufacturer code (WMI): Mercedes-Benz, Germany |
4 to 9 |
|
vehicle description, including the model series 177 |
10 |
|
at Mercedes the steering side, not a model year |
11 |
|
at Mercedes the plant |
12 to 17 |
|
serial number, redacted here |
Before this test obd-diag showed the model year “2001” from position 10. European Mercedes VINs do not encode a model year there, so obd-diag no longer shows one for them (VIN decoding). A check digit (position 9) is not mandatory outside North America; it “differs”, and that is not an error.
Live data¶
obd-diag live --duration 20 --record --trace, engine off. Before the first round
prepare_live reads the PID lists 0100 to 0180 (above) and ATRV once. Of the
default values the W177 supports all except the intake air temperature (0F), which is
therefore dropped without a message. One round:
2.185 >> 010C\r
2.254 << 410C0000\r410C0000\r410C0000\r410C0000\r\r>
2.305 >> 010D\r
2.373 << 410D00\r410D00\r410D00\r410D00\r\r>
2.423 >> 0105\r
2.488 << 41053B\r41053B\r41053B\r41053B\r\r>
2.538 >> 0104\r
2.602 << 410400\r410400\r410400\r410400\r\r>
2.652 >> 0142\r
2.709 << 41422EDC\r\r>
Engine speed 0, speed 0, coolant 3B = 59 − 40 = 19 °C, load 0 %, control module
voltage 12.0 V. There are a good 50 ms between two requests: that is the minimum gap
obd-diag keeps before every request to the vehicle (Safety concept).
The next rounds start at 7.1 s, 12.1 s and 17.1 s, so every 5 s instead of every
second. The reason was the throttling at low battery voltage: ATRV reported 11.2 V.
The control module voltage rose from 11.996 to 12.007 V over the four rounds. Since
this test, live data also cross-checks a low ATRV with PID 42; with 12.0 V from the
control unit it would not have been throttled.
What the trace does not show¶
The first attempt. With the ignition off, the protocol search after the first
0100ended withUNABLE TO CONNECT; obd-diag aborted, only AT commands and this one0100had been sent. Only with the ignition on did the control units answer. Since PR #8 the message for this is “No control unit responds. Switch the ignition on (the engine may stay off), select HS-CAN on adapters with an MS/HS-CAN switch and try again.”Which control unit is which. That would need headers (
ATH1): then every line carries its CAN address, for example18 DA F1 10(Response formats). obd-diag only switches them on when multi-frame responses of several control units get mixed. That was not necessary here, because only the VIN is multi-frame and only one control unit sends it.Clearing. Mode 04 did not occur; clearing is still locked (Reading and clearing trouble codes).