====== OBD-II diagnostics ====== What you can and cannot get from the OBD-II socket on the U5, worked out by probing it with a cheap USB-CAN adapter and cross-checking against the head unit's own readouts. Short version: **you can read a great deal, but you cannot write anything without the manufacturer's secret key.** See [[canbus|CAN bus]] for how this port differs from the internal buses. ===== The port is a query-only diagnostic gateway ===== * OBD-II **pin 6 = CAN-H, pin 14 = CAN-L** (ground on 4/5, permanent 12 V on 16). This is the only CAN pair on the connector — no second bus, no automotive Ethernet / DoIP. * **Passive listening is silent** at every bitrate — nothing is broadcast here. * **Active requests are answered** at **500 kbit/s, 11-bit** (ISO 15765-4). 29-bit and other bitrates stay silent. * The port sits on a **dedicated diagnostic CAN that dead-ends at the central gateway**. The gateway bridges the car's separate internal buses — **powertrain, chassis, body/comfort, infotainment, telematics** — and **routes** each request to the target ECU. So you can reach every ECU through it, but the connector never carries the live internal broadcasts. You can **poll**; you cannot **sniff** here. This is a genuine central-gateway firewall. ===== Generic OBD-II — any scan tool ===== Standard emissions services work, addressed functionally to **0x7DF** (responses on **0x7E8**): * **Mode 09** — VIN (''09 02'') and calibration IDs. * **Mode 03 / 07 / 0A** — stored / pending / permanent DTCs. * **Mode 01** — live PIDs. The primary powertrain endpoint (**0x7E0**) reports a supported-PID bitmask of ''BF FB FF F7'' and, usefully on an EV, **PID 0x5B** ("hybrid/EV battery remaining charge"). * **Mode 04** — clear emissions DTCs (see //Clearing fault codes// below). As on any EV, generic OBD exposes little — VIN, generic fault codes, a couple of values (mostly 0 while parked). Everything interesting — real SoC, pack voltage, cell data — lives in the **manufacturer UDS** layer below. ===== The ECU map (UDS) ===== The gateway **routes UDS requests to the internal ECUs**. Enumerate them **gently** with a single functional **TesterPresent** (''3E 00'' → 0x7DF): it changes nothing, yet every reachable ECU answers from its own ID. On the U5 this finds **24 ECUs**. Response ID = request ID **+ 8** (e.g. 0x701 → 0x709). ^ Request ID ^ Notes ^ | **0x7E0** | Generic-OBD powertrain endpoint. Answers Mode-01 but **rejects all UDS** (serviceNotSupported). | | **0x7E1** | **Battery management system** — pack voltage / current / SoC / cell data live here (below). | | **0x7E2, 0x7E3** | Powertrain pair (consecutive part numbers) — motor/charge electronics. | | **0x700–0x707, 0x710–0x713, 0x720–0x727, 0x730–0x736, 0x7AC** | Body / chassis / comfort controllers (BCM, HVAC, ESP, EPS, airbag, steering, cluster, seats, tailgate, TPMS, …). | The internal ECUs reachable this way are the usual EV set: **BMS, VCU, motor controller, on-board charger, gear selector** (powertrain); **BCM, A/C module, PTC/compressor, seat heaters, tailgate, low-speed warning** (body); **ESP, EPS, iBooster, airbag, steering-angle sensor, cameras/radars** (chassis); **head unit, instrument cluster** (infotainment); **T-Box** (telematics). Exact address↔module mapping is only confirmed for 0x7E0/0x7E1; the rest is inferred from the data and address block. ===== Reading data (non-destructive) ===== In the **default session** (no session change) you can typically: * **0x19 ReadDTCInformation** — stored fault codes, decoded (''19 02 FF'' = report by status mask). * **0x22 ReadDataByIdentifier** — read data by 16-bit DID. The **identification block** (DIDs ''0xF180''–''0xF1FF'') returns, on most ECUs: a part number in an ''8619xxxxx'' scheme, a supplier code (''CS-000xxx''), a programming date, and the VIN (''0xF190''). Example from one ECU: part ''861923101B'', supplier ''CS-000029'', programmed **2021-11-10**. Sweeping these across all 24 ECUs builds a full part-number / build map of the car — no public Aiways ECU list exists otherwise. The **BMS (0x7E1)** carries a live measurement block around DIDs **''0x8800''–''0x887F''** — roughly **120 aggregate battery values**: pack voltage, current, cell voltages, SoC, temperatures, and status words. This is where the numbers the head unit does //not// expose (cell min/max, temperatures, state-of-health) should live. ===== ⚠ Do not disturb the car while it is used ===== A **broad scan** — sweeping many ECU addresses and forcing an **extended session** (''10 03'') — makes ECUs **stop their normal CAN broadcasts**. The instrument cluster then flags the "missing" modules with **warning icons**, and a downstream display can **freeze on a substituted value** (we saw the outside-temperature reading stick). It is **read-only and reverts** once probing stops, but: * **Never run a broad/aggressive scan while driving** — an ECU dropping off the bus mid-drive is unsafe. * Prefer the **gentle method**: functional discovery + **default-session reads only** (0x19 / 0x22), no session control. A single-ECU default-session read does not disturb the dash. ===== The fault codes you will see ===== The last two hex digits of a DTC are the standardised **failure-type byte**: **…88 = CAN Bus Off**, **…87 = missing message / timeout**, **…82/83 = rolling-counter / checksum**. So a `U…87` / `U…88` code means **"lost communication"**, not a real hardware event. A consequence: any bus or power interruption — **including an aggressive scan** — makes many modules log "lost communication" against each other **at once**. After a heavy scan expect a **long list of U-codes** (and contiguous B-/C-code ranges); these are **artifacts, self-clearing over clean drive cycles**. The codes worth attention are the **powertrain P-codes**, which point at real sensor / HV faults. Read them all with 0x19 first, then judge. ===== Battery management fault codes ===== Manufacturer-specific codes (second character `1`, e.g. ''P110C00'') turn out to be properly documented and genuinely EV-relevant — HV contactor voltage checks, BMS current-sensor faults, CAN gateway message timeouts, crash/airbag signalling. None of them are combustion-engine leftovers. The following battery-management codes have been identified and confirmed: ^ Code ^ Meaning ^ | ''P112868'' | CAN collision (crash) signal fault | | ''U11FA87'' | Gateway message 0x2BB timeout | | ''U11FB87'' | Gateway message 0x2DF timeout | | ''U11FC87'' | Gateway message 0x3AA timeout | | ''U11FD87'' | Gateway message 0x050 timeout | | ''U11FE87'' | Gateway message 0x2F1 timeout | | ''U11FF87'' | Gateway message 0x195 timeout | | ''U120087'' | Gateway message 0x37F timeout | | ''U120187'' | Gateway message 0x28C timeout | | ''U120287'' | Gateway message 0x17D timeout | | ''U002888'' | CAN bus disabled (bus off ≥3 s while awake) | | ''U00BA88'' | DC fast-charge CAN bus disabled | | ''U10BA87'' | DC fast-charge message timeout (charge controller) | | ''U112182'' | Airbag ECU crash-message counter fault | | ''U112183'' | Airbag ECU crash-message checksum fault | | ''U011187'' | Communication loss with the BMS (message 0x2C7 missing 10 s) | | ''P110364'' | Main-relay downstream voltage plausibility fault | | ''P110386'' | Main-relay voltage invalid | | ''P11021C'' | Battery voltage out of allowable range | | ''P11081C'' | Internal current sensor (CAB) supply voltage faulty | | ''P110A1C'' | Internal current sensor (LEM) supply voltage faulty | | ''P110C00'' | 12 V supply shuts down abnormally | | ''P11011D'' | Shunt current out of allowable range | | ''P110162'' | Shunt current signal plausibility check failed | | ''P110164'' | Shunt current sensor self-learn fault | | ''P110167'' | Shunt current sensor fault | | ''P110192'' | Current measurement fault in two circuits | | ''P110711'' | Internal current sensor (Iem) shorted to ground | | ''P110712'' | Internal current sensor (Iem) shorted to supply | | ''P110264'' | Battery signal plausibility check failed | | ''P110286'' | Invalid battery voltage signal | | ''P110464'' | DC fast-charge relay downstream voltage plausibility fault | | ''P110486'' | DC charging voltage invalid | | ''P11B467'' | DC fast-charge voltage fault | | ''P11051D'' | Hall current sensor reading out of range | | ''P110562'' | Hall current signal plausibility check failed | | ''P110564'' | Hall current sensor self-learn fault | | ''P110567'' | Defective Hall current sensor | | ''P110592'' | Deviation between bus current from different sensors too large | | ''P110609'' | Internal current sensor (CAB) fault | | ''P11061C'' | Internal current sensor (CAB) supply voltage faulty | | ''P110692'' | Interior current sensor (CAB) fault after BMS self-test | | ''P115B92'' | Simultaneous failure of two current-circuit sensors | | ''U11F487'' | Internal current sensor (CAB) message timeout | Every code here clears automatically if absent for 40 drive cycles, or via a diagnostic tool. The standard repair escalation is: cross-check codes on other modules → inspect harness/connector → check HV harness insulation resistance (target >1.5 MΩ, ≥120 MΩ for the PTC heater, at 500 V DC) → replace the battery pack assembly as a unit — there is no component-level BMS board repair path. By contrast, the **generic/SAE codes** (second character `0`, e.g. the ''P02C1''/''P01C1'' seen during live scans above) sit in ranges the standard defines for combustion-engine subsystems — ''P02xx'' is nominally "fuel injector circuit," meaningless on this car. The ECU reporting them self-identifies over Mode 09 as **''HPCM-HybridPtCtrl''** ("Hybrid Powertrain Control Module") — a real hint its diagnostic software is inherited from a hybrid/ICE platform, with some legacy generic checks never fully pruned for the pure-EV variant. Treat unexplained generic P0-range codes with suspicion; the manufacturer-specific P1xx range is the trustworthy one. Charging-system codes have also turned up, though only as bare identifiers so far (no definitions found yet): ''P120019'', ''P120119'', ''P122000'', ''P122100'', ''P128A19'', ''P128B98'', ''P12A500''. If anyone can pin down what these mean, please add it here. Coverage note: a systematic search turned up fault-code documentation **only** for the battery-management codes above and this bare charging-system list — nothing yet for ESP, parking brake, brake booster, steering, HVAC, or body-electrics modules. If your car throws a code in one of those areas, this wiki doesn't have it documented — please add whatever you find. ===== Decoding the raw values ===== There is no public scaling for the manufacturer DIDs, so raw values are decoded by **correlation** — read a DID while you know the true value from another source (the head unit's decoded readout is ideal), and find the field + scale that match. A field is only trustworthy once you can make it **move**: switch a big HV load (A/C compressor) on and off and watch which fields track. Confirmed on the BMS (0x7E1) this way: * **Pack voltage** = DID **''0x8871''** (raw = volts; read 407 vs head-unit 406.9 V). * **Pack current** = DID **''0x887b''** (rises with load; identified by the A/C on/off test). State-of-charge and the 12 V system voltage have plausible candidates but are **not yet nailed** — near-constant signals need the car in **different states** (a drive, a charge) before their field and scale can be confirmed. The decoded numbers sanity-check against the known pack spec (≈**268–417 V** range, **24 modules**, cell **2.8–4.35 V**), so e.g. a ''0x882d'' reading of ≈**4.01 V** is a real cell voltage. A logger that records reference values and DIDs together across normal driving is the clean way to finish the map. ===== Clearing fault codes ===== Clearing DTCs is the one "write" normally allowed **without** Security Access (it is needed for repair): * **Generic — Mode 04** (''ClearDiagnosticInformation''): send ''04'' to 0x7DF / 0x7E0. Clears emissions DTCs and freeze frames. * **Manufacturer — UDS service 0x14**: send ''14 FF FF FF'' ("clear all groups") to a specific ECU (e.g. 0x7E1). Clears that module's stored DTCs, usually in the default session. Notes: clearing **masks real faults** (good and bad alike) — read the codes first. **Permanent DTCs** cannot be cleared by a tool; the ECU clears them itself after its readiness monitors pass. A 12 V battery disconnect resets volatile display state but does **not** clear stored DTCs (non-volatile) — for that you need a clear command. ===== Waking the car ===== Diagnostic requests on this port **wake the gateway and addressed ECUs** for diagnostics (that is how a scan tool works on a parked car). That is a diagnostic wake only — it does **not** power up the HV system, close the main contactors, or start climate. Those are actuation functions behind Security Access. ===== What is locked — and the one interesting exception ===== Everything that **changes or actuates** — writing configuration (0x2E), actuator tests (0x2F), routines (0x31), ECU reset (0x11), flashing (0x34/0x36/0x37) — sits behind **Security Access (0x27)**. The gateway answers a **seed** request, but the **key algorithm is an OEM secret** that is not public for this car. So in practice **OBD-II here is read-only**: fault codes and data yes, control no. **The interesting exception:** a dealer tool activates functions like HV power-up or preconditioning via a **security-gated routine (0x31)** over this **same diagnostic CAN**. So the diagnostic port is not architecturally a dead end for control — with the correct Security-Access key, **remote preconditioning could in principle be commanded straight over OBD-II**, no internal-bus tap required. The key is the missing piece (see [[roadmap]]). ===== It is all standard ===== Under the hood this is plain **UDS (ISO 14229)** over **ISO-TP (ISO 15765-2)** on 500 k / 11-bit CAN — nothing proprietary at the wire level. That means standard open tools work: a small ISO-TP + UDS client in Python, or off-the-shelf car-diagnostic tools, will talk to this car. What is //not// open is the **data dictionary** (which DID means what, with what scaling) and the **Security-Access key** — both live in the manufacturer's diagnostic database. ===== Wiring & tools ===== A **CANable-class USB-CAN adapter** (gs_usb) on **500 k / 11-bit**, driven from Python (raw frames + a small ISO-TP layer for multi-frame UDS). * Wire **CAN-H → OBD pin 6, CAN-L → OBD pin 14**, ground to pin 4/5. Getting this wrong looks exactly like a dead bus. * Adapter DIPs: **Boot OFF** (run), **R120 OFF** (the OBD-II bus is already terminated 2×120 Ω). A DIP change only takes effect after a full unplug/replug. * Confirm wiring by watching the adapter's TX **and** RX LEDs blink during an active probe.