# First ECU read (KKL cable) — offline quick reference Pull this up locally, no signal needed. Everything here is already known/ confirmed as of tonight (2026-08-26) — nothing depends on being online. Bluetooth (vLinker MC+) is parked for now: it needed a full unpair/re-pair after nearly every attempt tonight (likely the adapter's own KWP firmware, not something software fixes) — the KKL cable sidesteps that whole class of problem, which is why it's next. ## ⚠ Current KKL cable (`/dev/cu.usbserial-A50285BI`) — confirmed bad, 2026-08-26 Both fast and slow init failed in a way that points at the cable itself, not wiring/pinout/software: - **Fast init**: `timed out waiting for 1 bytes, got 0 (none)` — failed at the very first echo check, right after transmitting. K-Line is half-duplex: your own transmission always echoes back on a working line. Zero bytes back, not even the echo, means RX isn't picking up anything at all. - **Slow init**: `expected sync byte 0x55, got 00` — not silence this time, a real `0x00` byte. Consistent with RX stuck permanently low (a UART can't frame a start bit without a high→low transition, so a dead-low line reads back as a stream of `0x00`s). Both symptoms match a well-known, common failure mode for cheap "VAG-COM 409.1 KKL" cables: a bare FTDI FT232R with **no real K-Line transceiver chip** (should be something like an L9637) actually soldered in. TX may weakly drive the line, but RX never sees a clean signal, including its own echo. Nothing in `tunie`'s K-Line code looks suspect — echo-consumption and 5-baud timing both match spec exactly. **Before writing this cable off for good**, one more isolated check next time it's plugged in — independent of any init timing: ```sh /Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10 -m tunie.cli raw --port /dev/cu.usbserial-A50285BI --baud 10400 --command AA --hex ``` If that returns nothing at all, that's about as clean a "cable is dead" confirmation as possible without a scope — worth getting a known-good KKL cable (or leaning on the Bluetooth path / TuneECU's own bundled cable) rather than continuing to debug this one in software. ## Before you plug anything in - [ ] **Connector location and shape checked.** Real accounts from other owners on this same ECU family describe it as a standard **16-pin OBD-II-style plug, in front of the fusebox, behind the tank, no tools needed**. If it matches, plug in directly. **If it looks different/ smaller/non-standard, stop** — that's the one real electrical risk here. - [ ] **Pull the headlight AND taillight fuses before connecting anything** — protects the battery (Keihin ECUs are sensitive to voltage drop) and doubles as a safety interlock. Fuse numbers are bike-specific, check the fusebox cover. - [ ] Battery tender/maintainer connected (a real smart tender, not a bare trickle charger). - [ ] Ignition **on**, engine **off**. Kill switch in run position. - [ ] KKL cable plugged in. ## Step 1 — confirm the port shows up ```sh cd /Users/dylan/dojo/samplez/tunie /Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10 -m tunie.cli ports ``` Look for an FTDI/USB-serial entry (last confirmed working port this session: `/dev/cu.usbserial-A50285BI` — but ports can renumber, trust what this actually prints over memory). If nothing FTDI-looking shows up, stop here — that's a driver/cable problem, not a bike problem. ## Step 2 — raw wiring smoke test (new tonight, do this before `info`) K-Line is half-duplex: anything you write is normally echoed straight back over the wire if the adapter and wiring are electrically sound. This new `tunie raw` command proves that *before* risking a real protocol handshake: ```sh /Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10 -m tunie.cli raw --port /dev/cu.usbserial-A50285BI --baud 10400 --command ATZ ``` - **Exact echo of `ATZ` comes back** → wiring/pinout/adapter proven sound. This is the *good* result for K-Line (unlike Bluetooth, where an echo would mean something else). Move on to Step 3. - **Nothing comes back at all** → wiring/pinout/driver issue. Don't bother with `info` yet — recheck the connector, recheck `tunie ports`, confirm the FTDI driver is actually bound to that device. ## Step 3 — the real read ```sh /Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10 -m tunie.cli info --port /dev/cu.usbserial-A50285BI --adapter kline --retries 5 ``` If fast init times out, slow init is a normal fallback, not a sign of a deeper problem: ```sh /Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10 -m tunie.cli info --port /dev/cu.usbserial-A50285BI --adapter kline --init slow --retries 5 ``` Add `-v` before `info` (i.e. `tunie.cli -v info ...`) if you want every raw frame logged — only useful for troubleshooting a failed connection. ## What changed tonight (fixed, already in the code you'll be running) - `tunie` now sends a `TesterPresent` keep-alive between every read during the interrogation sweep, so a long scan can't let the ECU's diagnostic session lapse partway through (this was a real bug, found by tracing TuneECU's own decompiled code — `m.java`'s `hd()` does the same thing). - Connection cleanup now always runs even when every retry fails — no more stale handles left open after a failed attempt. - Bad-port errors are now a clean message, not a raw Python traceback. None of tonight's fixes were K-Line-specific bugs (they were mostly found chasing the Bluetooth adapter), but they all apply to this path too and none of them introduced anything new to worry about — `tests/verify_protocol.py` passes clean as of the last edit. ## How you'll know it's done Normal synchronous command — no background process. It prints a result (success or a friendly error) and returns you to the shell prompt. **Prompt back = done.** A few seconds to ~30s, longer if retries kick in. Retries are automatic and visible: ``` Attempt 1/5 failed (...); retrying in 5s... ``` This does **not** power-cycle the bike for you — if all retries fail, that's the signal a real ignition off/on cycle is worth trying, not just re-running the command again. Every run writes its own timestamped file to `tunie/logs/` regardless of outcome: ``` (full session log: logs/tunie-info-20260826-201432.txt) ``` `ls -t logs/` shows the newest one first if you lose track. ## Reading the output - **"Queries that did not answer" is normal**, not a failure — the sweep deliberately probes a range of manufacturer-defined record numbers. - **The record under `0x94`** (software part number) is what to cross-check afterward against `maps.json` to confirm exactly which stock calibration is on the bike. - **DTCs will most likely say "none reported"** unless something's actually faulting right now. ## If the connection won't work In order: 1. Ignition on, engine off — the ECU sleeps otherwise, most common miss. 2. Re-check the connector pinout before suspecting anything else. 3. Try `--init slow` if fast init times out (Step 3 above). 4. Real ignition off/on power cycle if software retries don't help. 5. If `raw` in Step 2 got nothing back at all, this is a wiring/adapter problem — no amount of retrying `info` will fix that on its own. ## While you're at it - **Watch the battery voltage manually** — `tunie` doesn't read/display it. Multimeter on the terminals, or the bike's dash if it shows one. Below ~12.5V connection attempts get flaky; ~12.2V is the "stop and recharge" point. - Multiple attempts before success is normal — don't read one failed try as a real problem. ## After you're done Turn ignition off. Bring the log file back — paste its contents into a conversation with me, or just tell me the map ID under `0x94` and I'll cross-check it against `maps.json` directly.