====== CAN bus access ====== There are two very different ways onto the vehicle bus. **Know which is which.** ===== Route A — via the companion MCU (works for control) ===== The head unit talks to a **companion MCU over UART** (''/dev/ttymxc3'' @115200). The MCU bridges to the vehicle CAN bus. The UART is owned by the ''carmanager'' CarService; other apps reach it through a system service (AIDL). The MCU frame carries a "send CAN control frame" address and a control-type selector (air-conditioning, charging, dashboard, …). This is the route that actually **reads decoded values and sends control commands**. The head unit never sees raw CAN frames here, only decoded register values. ===== Route B — the OBD2 port (diagnostics, not control) ===== The OBD2 socket is a **query-only diagnostic gateway**. Through it you can enumerate all **24 on-board ECUs**, read their **fault codes and data** (including a live battery-measurement block), and clear codes — but you **cannot control anything** without the manufacturer's Security-Access key. It does **not** carry the internal broadcasts, so it is no use for sniffing live signals. Full write-up — the ECU map, what is readable, how to decode raw values, clearing codes, and the safety caveats: **→ [[obd2|OBD-II diagnostics]].** ===== Safety checklist for tapping the internal (TBox) CAN bus ===== The internal bus is **live and possibly safety-relevant** (unlike the isolated OBD2 gateway): - **Listen-only (silent) mode first.** A normal CAN node still transmits ACK bits, and at the wrong bitrate emits error frames that can disturb real ECUs. Use the adapter's hardware listen-only mode to identify bus/bitrate before ever transmitting. - **Measure termination.** With the car off, measure CAN-H/CAN-L: **~60 Ω** = already terminated both ends (add nothing); **~120 Ω** = only one end. Keep the stub short. - **Confirm the bitrate** (sweep 500k → 250k → 125k in listen-only) before going active. - **Non-destructive tap** — back-probe or T-tap; never cut or pierce the harness. Tie adapter ground to chassis ground. Never short CAN-H/L to 12 V or to each other. - **Parked only.** Connect with the car asleep, then wake it to capture. Never probe a bus while the vehicle could move. - **Identify the right bus by correlation** — trigger a known signal (e.g. AC on, or a lock/unlock) and watch which frames change. ===== Decoded signal keys ===== The head unit works with a registry of **~461 action-ID keys** — the values it reads (**GET**) and commands it sends (**SET**) over the MCU/CAN bridge. These are the ''CarService.getInt(id)'' / ''sendCmd(id,…)'' keys, **not** raw CAN arbitration IDs (those sit a layer below in the MCU protocol). **→ Full list, grouped by domain: [[cansignals|CAN signal reference]].** The battery/powertrain subset — the signals most people ask for — is below. ==== Battery & powertrain ==== The U5 has a **split HV pack (A + B)**, each reporting its own SoC / voltage / current. Read with ''getInt(id)'' while the car is awake. ^ Signal ^ ID ^ Constant ^ Unit / note ^ | Overall SoC | 3335 | ''WARN_BMS_STATE_OF_CHARGE'' | % | | Pack A (main) voltage | 3455 | ''CARSET_PACK_BMS_VOLTAGE'' | V — //live sample ≈ 356 V// | | Pack A (main) current | 3456 | ''CARSET_PACK_BMS_CURRENT'' | A | | Pack A SoC | 3457 | ''CARSET_PACK_A_SOC'' | % | | Pack B voltage | 3458 | ''CARSET_PACK_B_VOLTAGE'' | V | | Pack B current | 3459 | ''CARSET_PACK_B_CURRENT'' | A | | Pack B SoC | 3460 | ''CARSET_PACK_B_SOC'' | % | | Driving range | 3461 | ''CARSET_VCU_DRIVING_RANGE'' | km | | Energy mode | 3462 | ''CARSET_VCU_ENERGY_MODE'' | | | BMS warning lamp | 3323 | ''WARN_BMS_WARN_LAMP'' | telltale | | Thermal-runaway warning | 3340 | ''WARN_BMS_THERMALRUNAWAY'' | telltale | | Charge time | 492 | ''CARSET_CHARGE_TIME'' | SET/est. | | Discharge (V2L) request | 491 | ''CARSET_DISCHARGE_REQ'' | SET | **No State-of-Health (SoH).** The firmware decodes SoC but there is **no SoH / capacity / cell-voltage key** — SoH would have to come from a raw BMS CAN frame or a UDS diagnostic read (see [[roadmap]]). **Reading live (adb, car awake):** the canbus service logs decoded values under logtag ''Canbus_SET'' (e.g. ''D/Canbus_SET: mPackBMSVoltage: 355.9''). The vehicle CAN only broadcasts while the car is awake — values go quiet a short while after it parks/locks. ===== Probing signals live ===== The [[dev#adc_telemetry|ADC Telemetry]] app has a built-in probe (it already binds ''ICanbusService''), so you can read or command any [[cansignals|key]] from a shell — handy for checking whether a signal really exists, what it reports, and in which state. Build/install and signing basics are on the [[dev|development]] page. **Read** — ''geti'' = getInt, ''getf'' = getFloat, ''geta'' = getIntArray: S=com.example.carmqtt/.BridgeService adb shell am startservice -n $S --es op geti --ei key 3457 # pack-1 SoC adb shell am startservice -n $S --es op getf --ei key 3455 # pack-1 voltage adb shell am startservice -n $S --es op geta --ei key 3464 # doors [FL,FR,RL,RR] adb logcat -d -s CarMqtt.Probe # read the results Example output: getf key=3455 -> getFloat=355.5 geti key=3460 -> getInt=0 (pack-2 SoC — 0: this car is single-pack) geta key=3464 -> getIntArray=[1, 0, 0, 0] (driver door open) **Command** — ''send'' = sendData(action,val). **⚠ this actuates the vehicle — only in a safe state:** adb shell am startservice -n $S --es op send --ei key 103 --ei val 1 # A/C ON Notes: after (re)installing the app give it ~1 s to rebind the canbus service (a probe fired too early logs ''canbus service NOT bound''); a value of **-1 / 0** usually means the signal is at its init default (not populated on this car — as with pack 2).