Decode your cars OEM CAN signals

CAN Decoder — Build Guide

Build a CAN capture and decode pipeline with AI. Core: USB adapter + Mac. Recommended: phone GPS + map for much better signal discovery.

What You're Building

Core (required): capture CAN traffic from a USB adapter and decode signals.

Optional but strongly recommended: record GPS and visualize on a map. This gives you — and the AI — much better context when figuring out what each CAN ID means.

Why GPS + map matter for decoding

Raw CAN captures are hard to interpret alone. GPS altitude turns a drive into a natural experiment — hills give you predictable physical changes to hunt for in the data. You can ask the AI things like:

  • "Find RPM — it should be much higher when driving up hills"
  • "Find coolant temp — it should increase as we climb and decrease as we descend"

The map makes those altitude changes visible and easy to line up with CAN timestamps. Give the AI a capture with GPS and it can correlate bytes to real terrain instead of guessing from raw hex.

Hardware & OBD-II wiring

Required

  • USB CAN adapter (CANable, XCAN-USB/PCAN clone)
  • OBD-II breakout cable (often included) or jumper wires pushed into the OBD-II port pins
  • Mac laptop

Recommended

  • iPhone on Personal Hotspot (phone controls capture; Mac stays plugged into CAN)
  • Mapbox access token (free tier is fine, for map demo)

OBD-II wiring

Most USB-CAN kits use a standard OBD-II cable. Or use jumper wires inserted directly into the OBD-II socket on pins 6, 14, and 5.

Pin Function
6 CAN High
14 CAN Low
5 Signal ground (connect adapter GND here)
16 +12V (some adapters need this for power)
  • Bitrate is usually 500 kbit/s on OBD-II CAN.
  • Adapter CAN H → pin 6, CAN L → pin 14, GND → pin 5.

OBD-II may not show OEM traffic

The OBD port is meant for diagnostics. On many vehicles the gateway filters the bus — you see OBD request/response traffic (e.g. 0x7DF, 0x7E0) but not the full OEM broadcast frames where RPM, coolant, throttle, etc. actually live.

Quick check: if you only see diagnostic IDs and never high-rate broadcast IDs while the engine runs, OBD sniffing won't work for decoding on that vehicle.

If OEM CAN is filtered, tapping the bus elsewhere (ECU, BCM, harness) is vehicle-specific and risky — probably not worth it for this guide.

Roles

Device Role
MacBook Server — CAN adapter, capture files, HTTPS API. Set up once, leave running in the car.
Phone Remote control — open one page, tap Start / Stop. GPS streams automatically while recording.
Capture format (CSV)

Use CSV for everything — simple for humans and AI to read, easy to join on timestamp.

CAN capture (capture-<timestamp>.csv):

timestamp,can_id,data0,data1,data2,data3,data4,data5,data6,data7
1718190000.123,0x1F9,00,00,1A,F0,00,00,00,00

timestamp = Unix epoch seconds (wall clock, UTC) — same basis as GPS

GPS log (gps-<timestamp>.csv):

timestamp,datetime_utc,latitude,longitude,speed_kmh,altitude_m,heading_deg,fix_quality,satellites,source

Signal definitions (signals.csv):

name,can_id,start_bit,length,endian,signed,factor,offset,unit,notes
RPM,0x1F9,16,16,little,false,0.125,0,RPM,payload bytes 2-3 BE16; physical = raw / 8
Engine Coolant Temperature,0x551,0,8,little,false,1,-40,°C,payload byte 0; physical = raw - 40

One row per decoded signal. The map and analysis tools read this file to know how to extract values from raw CAN frames.

Build order + AI prompts
1. CAN sniffer CLI
Build cansniffer.py with python-can: --list, --probe, live frame print,
--log to CSV with Unix epoch timestamp per frame, --bitrate (500k default),
slcan + pcan support.

CSV columns: timestamp, can_id, data0..data7 (hex or decimal).
2. Capture server (Mac)
Build cansniffer_gui.py: HTTPS server on :8765. Mac connects to USB CAN adapter.

Desktop page (optional): bitrate select, live frame preview, session status.

Mobile page at / (or /capture): large Start / Stop buttons only.
On Start: begin CAN logging to captures/<session>/capture-*.csv and accept GPS posts.
On Stop: flush files and end session. Rotate capture CSV at 100k frames.

Mac is always the server; phone is the remote control.

HTTPS is required for phone GPS. iPhone Safari blocks navigator.geolocation on plain http://.

HTTPS prompt (add when building step 2 or 4)

Add HTTPS to the capture server using a self-signed certificate:

- On first start, if certs are missing, run openssl via subprocess to create:
  .certs/server.pem and .certs/server-key.pem
  (openssl req -x509 -newkey rsa:2048 -nodes -days 3650 -subj "/CN=REVVGAUGE-CAN")
- Wrap the HTTPServer with ssl.SSLContext (TLS 1.2+), load_cert_chain
- Bind 0.0.0.0 so the phone can reach the Mac over hotspot
- Print https:// URLs (not http) including Mac LAN IP for phone access
- Require openssl on the Mac (pre-installed on macOS)

On iPhone: user accepts the certificate warning once (Show Details → visit website).
Without HTTPS, GPS will not work on the phone.
3. Find your vehicle's signals
Analyze capture-*.csv (and gps-*.csv if available) to discover CAN signals.
Use terrain context where possible: RPM higher uphill, coolant rising on climbs, etc.

Write results to signals.csv with columns:
name, can_id, start_bit, length, endian, signed, factor, offset, unit, notes

One row per signal (RPM, throttle, coolant, gear, …). Document the byte layout
and formula in notes so humans and AI can verify later.
4. Mobile capture + GPS (optional, recommended)
On the same HTTPS server, mobile Start/Stop also enables phone GPS automatically:
- Start → navigator.geolocation.watchPosition() + POST /api/gps (~1 Hz)
- GPS rows append to gps-*.csv in the active session folder
- Stop → stop GPS watch and close session

Columns: timestamp (Unix epoch), lat, lon, speed_kmh, altitude, heading.
Show https://<mac-ip>:8765/ on Mac at startup. Phone joins via hotspot.
5. Merge GPS + CAN (optional, recommended)
Build session_data.py: load capture-*.csv, gps-*.csv, and signals.csv.
Join GPS to CAN on timestamp (±3s). Apply signals.csv to decode frame bytes.
Output GeoJSON for the map.
6. Map (optional, recommended)
Build map_demo/server.py (:8766) + Mapbox frontend: session picker,
route colored by speed/RPM/throttle, hover tooltips.
First test

Minimum (CAN only — Mac)

  1. Plug CAN adapter into Mac, start server: python sniff/cansniffer_gui.py
  2. On Mac browser: Start capture, run engine / drive briefly, Stop
  3. Check session folder has capture-*.csv
  4. Ask AI to analyze the capture and produce signals.csv (see step 3 prompt)

Recommended (phone control + map)

Mac stays in the car as server; you drive with your phone:

  1. Mac: python sniff/cansniffer_gui.py (set bitrate once if needed)
  2. iPhone hotspot on → Mac connected
  3. iPhone Safari: open https://<mac-ip>:8765/ (accept cert warning once)
  4. Tap Start, drive 5+ min on a hilly route, tap Stop
  5. Check session folder on Mac has capture-*.csv and gps-*.csv
  6. MAPBOX_ACCESS_TOKEN=pk... python sniff/map_demo/server.py → review route on map
  7. Feed capture + GPS + map context to AI for signals.csv

Prompting AI with GPS context

When asking AI to decode unknown signals, include:

  • The capture-*.csv from the session
  • The gps-*.csv from the same session (if available)
  • A physical expectation tied to terrain: "RPM should rise on uphill sections", "coolant should warm on long climbs and cool on descents"

Example:

Here's a CAN capture CSV and matching GPS CSV from the same drive.
Altitude climbs ~200 m between timestamps 1718190000 and 1718190120, then drops on the way back.
Find RPM — it should be noticeably higher on the uphill sections.
Find coolant temp — it should trend up while climbing and down while descending.

Write confirmed signals to signals.csv in the standard format.
Sync model (GPS + CAN)

If you add GPS, both CSVs join on wall-clock timestamp — no separate stitch step.

Source Time
GPS CSV timestamp = Unix epoch
CAN CSV timestamp = Unix epoch

Both use the same clock. Mac and iPhone should be on the same network (hotspot) with reasonable clock sync.

Common fixes
  • No frames → ignition on, try 500k bitrate; check pins 6/14 (CAN H/L) and ground on pin 5
  • Frames but only OBD diagnostic IDs → vehicle likely filters OEM CAN at the OBD port; tapping elsewhere is out of scope
  • No GPS → must use https:// (not http); accept self-signed cert on phone once; allow location on first Start
  • SSL / connection errors → another process may be on port 8765; stop old server and restart
  • No RPM on map → check signals.csv CAN IDs and byte layout for your vehicle
  • One adapter = one app → close other CAN tools first
  • Decoding stuck → record a GPS session on a hilly route; give AI both CSVs with terrain-based prompts

Tip: Build core capture on the Mac first. Add the phone Start/Stop page when you're ready to decode — hills + GPS give AI much better signal-discovery context.