# tunie — roadmap: open-sourcing + what's next Two tracks: **getting this into a shippable open-source project**, and the **technical work** still needed to actually tune the bike. Read [CONTEXT.md](CONTEXT.md) first for the full state. --- ## Track A — open-sourcing The code is original; the risk in publishing is the **third-party derived data** and the **flashing capability**. Handle these deliberately before a public repo. ### A1. Legal / IP (do this first) - **No proprietary binaries in the repo.** Already enforced: `*.hex`, `*.dec.bin`, `maps_cache/`, `table_map.json` are gitignored. Keep it that way — map files are Triumph/TuneECU calibration data and must not be redistributed. - **APK-derived data** (`maps.json`, `mapdefs.json`, embedded `c.a`/`s.a`, the AES keys, protocol constants) are facts extracted for **interoperability**. Frame the project explicitly as independent interoperability research on hardware you own. Add a clear NOTICE describing what's derived and why, and cite that it contains no TuneECU source. - **The AES seed/key** enables writing to the ECU. Decide the posture: keep the key/flashing material in a clearly-separated `research/` area with a warning, or gate the write path behind an explicit build flag. Do not make bricking a one-liner. - **License:** pick one (MIT/Apache-2.0 for the tool; note that embedded extracted constants are facts, not licensed code). Add `LICENSE` and a top-level legal/README section. ### A2. Repo hygiene - Move `tunie/` out of the `samplez` grab-bag into its **own repo** for a real project (keep samplez as the scratch mirror if you like). - Add: `CONTRIBUTING.md`, `SECURITY.md` (responsible-disclosure + "don't flash blindly" warning), issue templates, a CHANGELOG. - Reproducible builds: pin deps, document `build_viewer.py` inputs (needs a decompiled APK the repo can't ship — document how to produce it, don't include it). ### A3. Packaging & CI - `pip install tunie` — the `pyproject.toml` is already there; add a wheel build. - CI: run `tests/verify_protocol.py` + the reference-map self-tests (`decode_map.py`, `reconstruct_rom.py`, `table_map.py` — but those need map binaries, so gate them behind a locally-provided fixtures dir / skip in public CI). - Lint/format (ruff/black), type-check (mypy) the `src/tunie` package. ### A4. Docs & polish - A real top-level README with a quickstart, the safety stance, and a screenshot. - Host the viewer as a static page (it's a single self-contained file). - Turn `docs/CONTEXT.md` into a short "how the format works" explainer — it's genuinely novel RE and good for the project's credibility. ### A5. Community - The SuperH ECU community (npkern/FastECU/ScoobyRom authors, TunerPro forums, triumphrat) is the natural audience. A working open Keihin decrypt + table map is a real contribution. Coordinate rather than surprise — some of this overlaps commercial XDF vendors. --- ## Track B — technical, to actually tune the bike Ordered by dependency. Phases 1–2 are safe reads; 3+ is the write path. ### B1. First contact (READ) — the current blocker 1. Identify the VAG KKL chip (`tunie ports`); install CH340 driver if needed. 2. **Confirm the Triumph diagnostic-connector pinout** and build the adapter (K-Line + switched 12V + ground). *This is the one real electrical risk.* 3. `tunie info` — read ECU ID, current map, DTCs. Confirms which stock map is on the bike (should be 20187/20191 for production silencers, mechanical odo). ### B2. ROM dump (READ, deliberate) - Enable `0x35` RequestUpload (currently blocked in the read-only tool) to dump the stock ROM as a recovery image. Do this before any write work. - Cross-check the dump against our decrypt/unpack: a stock dump should reconstruct to the same flat ROM as the matching `.hex`, validating the whole pipeline on the real bike's data. - **Before implementing this ourselves, reverse-engineer TuneECU's own Recovery mode first** (Aug 2026 finding, `../research/TUNING_IMPL_PLAN.md`): TuneECU has a dedicated Recovery function (`menu_recovery` in the decompile, dispatched through the same mode-switch machinery as the rest of `m.java`'s `Ue()`), with a multi-year, multi-ECU-family bug-fix history in the app's own changelog (5DM/7SM, Dorsoduro/Shiver 750, Walbro, Ducati recovery bugs fixed 2019-2021) — real evidence this isn't a trivial retry loop, it's hardened against failure modes only discoverable across many real units. Extracting and understanding that procedure statically, before ever attempting our own upload/write path on the one ECU we have, meaningfully de-risks this phase. **Near-term (not blocked on this):** use TuneECU's own app's "Read Map" for the actual first dump — this reverse-engineering is prep for when `tunie` builds its own upload path for real, not a prerequisite for getting one file off the bike today. ### B3. Finish the calibration model - **Absolute scaling** for fuel and ignition (units), via an XDF cross-check (~€70 OldSkull/Tuniverse) or more RE of `Nc`/`Lb`. Relative editing already works. - **AFR table** dimensions/axes (partly reversed; 128 = λ1.00 confirmed). - **Remaining device flags** (exhaust valve, air flap…) — needs the `x.a()` device layout reverse (`x.t/x.s/x.q` for i27=72) or more single-mod reference maps. - Individual **SAI-vs-O2** isolation — only matters if hand-editing flags; the owner's path (a complete AIRBOXBONNY-style map) sidesteps it. ### B4. Write / flash path (the risky part — bench first) - Port the **flash kernel**: `fenugrec/npkern` explicitly lists SH7054 (untested) — the strongest lead. `miikasyvanen/FastECU` shows a full end-to-end flow. - Finish **seed/key**: which of the 3 AES keys + the seed-block padding (one captured pair from the bike/logging APK settles it). - ~~**ECU flash checksum** at write time.~~ **Solved, Aug 2026** — see `../research/reference-maps/checksum.py`. 16-bit sum-of-words over the flat-ROM calibration region (`0x50000`-`0x60000`, the same range this project's own `table_map.py` already uses), stored in the region's last 2 bytes. Validated against 6 real, unmodified, official downloads — computed matches stored, exact, every time. **Caveat that keeps this from being "done done":** this is the *app-side* checksum TuneECU computes for its own map-info display (flags "*No-OEM"/"Error" on mismatch) — confirmed it's not a hard gate on its own, since a real community file with a stale (unrecomputed) checksum apparently still worked for people. Whether the ECU's own bootloader *also* independently verifies something during the actual `0x36` TransferData sequence is a separate, still-open question — this solves "how do I produce a checksum TuneECU accepts as valid," not necessarily "the ECU's own integrity check." - **Head start already done (Aug 2026):** `../research/WRITE_PATH.md` traced TuneECU's actual shared write/reprogram routine from the mode-flag entry point down through the connection/retry driver into a 5-baud slow-init bit-bang for the Triumph K-line address (`0xD5`) — real protocol detail, not a plan. Traced as far as the post-slow-init handoff (unopened). Read that before starting this section for real; it's ahead-of-time reconnaissance done opportunistically while tracing Recovery mode (`../research/RECOVERY_MODE.md`), not yet validated against a live ECU. - **Recovery**: `v-ladimir/audprog` (AUD debugger) for SH705x un-brick via the PCB debug pins — mandatory backstop when developing a flasher. - Develop against a **spare/bench ECU**, on a stable supply, never the bike's only ECU, and validate output against TuneECU before trusting our own writes. ### B5. Editor completion - Full flat-ROM edit → re-pack → `dc`-encode → `.hex` for **arbitrary** table edits (device flags already round-trip; generalize to any chunk + fix the edit checksum). - In-viewer table editing with axes + a wideband/dyno-oriented diff workflow. ### B6. The owner's actual goal 2-1 exhaust + airbox removal + O2 + SAI delete: 1. Base on `20188Map2009AIRBOXBONNY` (validated: flags off + airbox fueling done). 2. Verify in the viewer (devices off, fuel tables sane vs stock). 3. Flash it — via the tunie write path once it exists, or TuneECU meanwhile. 4. Fine-tune midrange fuel for the 2-1 with a wideband (ideally a dyno). --- ## Immediate next steps (this week, if picking back up) 1. **Cable + pinout** → run `tunie info` on the bike (unblocks everything). 2. Pull `20188Map2009AIRBOXBONNY` into the viewer catalogue and diff it vs stock 20187 so the exact delete-tune changes are visible. 3. Decide the open-source posture on the AES keys / write path (Track A1) before any public repo. ## Risk register | Risk | Status | |---|---| | Software bricking via the read tool | eliminated (write path not implemented) | | Electrical (wrong connector pin) | **live** — confirm pinout before plugging in | | Bad tune from flags-only edit | mitigated by guidance; use a complete map | | Flashing (comms drop / bad checksum) | future — needs bench ECU + recovery tooling | | Legal (redistributing proprietary maps) | mitigated — binaries gitignored | | One ECU, no spare | validate writes against TuneECU; get a spare before B4 |