Reverse-engineered the Triumph Keihin map format from the TuneECU loader
(l.java zc/sc/Nc) and data classes c/r/s/t.java, and turned the viewer's table
tab into a working editor.
extract_mapdefs.py pulls the table directory out of the decompiled app into
mapdefs.json: r.a/s.a/t.a (calibration directory, 8-int records keyed by the
map's offset-20 signature) -> c.a (48-int calibration metadata) -> c.b (32-int
groups = 16 offset/length pairs each), yielding 413 candidate table offsets.
FORMAT.md documents the header magic (0x18008060 masked), the directory chain,
and the write-back checksum.
The viewer now edits: pick a known table offset (or set it manually), toggle
edit mode, click a cell to change its value, and the bytes are rewritten with
the running 16-bit checksum patched by (old - new) exactly as TuneECU does,
then Download the modified copy. Verified: editing 2016->9999 with the checksum
word at 0 yields 57553 = (0 + 2016 - 9999) & 0xffff.
Geometry offsets are read-confident but not yet validated against a real map
binary; FORMAT.md flags this. Editing/checksum stay local to a downloaded copy;
the flash write path remains out of the read-only tunie tool.
A single double-click-to-open HTML viewer (no server, no external refs) with
three tabs: browse/filter the 1811-map catalogue (with a "my bike" filter for
mechanical-odo Keihin Bonneville maps), see TuneECU's full editable surface
(tunable parameters, table axes, toggleable devices with SAI/O2/exhaust flagged
as mod targets, live sensors, actuator tests) extracted from the APK resources,
and a drag-drop .bin/.hex table viewer that renders bytes as a configurable
heatmap grid + hex dump for when a ROM dump lands.
build_viewer.py regenerates the HTML from arrays.xml + maps.json.
A Python tool to safely read the Keihin ECU on a 2010 Bonneville T100 over
K-Line (KKL cable) or a Bluetooth ELM327, plus the reverse-engineering research
behind it. Phase 1 (read-only comms) of an open tuning toolchain to replace the
closed TuneECU app.
Read-only by construction: safety.assert_read_only() runs on every outbound
request before it hits the wire and refuses all write/flash services (0x27,
0x31, 0x34/0x36, 0x35, 0x37, 0x14, 0x11, 0x2E) and programming sessions, so a
bug cannot brick the ECU. Verified frames match TuneECU byte-for-byte in
tests/verify_protocol.py.
Protocol constants recovered from the TuneECU APK (not guessed): ECU address
0xD5, K-Line tester 0xF5, format byte 0x80|len, additive mod-256 checksum.
Includes the full TuneECU map catalogue (1811 entries) extracted to maps.json,
searchable and filterable by ECU type and mechanical-vs-LCD odometer.
research/ documents the Security Access seed/key algorithm, recovered as
standard AES-128 (three embedded keys), with a self-testing reference impl
verified against FIPS-197. This is write-path material, kept outside the
read-only package.
STATUS.md and README.md capture full context, the risk register, and where we
left off: comms built but not yet run against the bike; next step is wiring the
VAG KKL cable to the Triumph connector and running the first scan.
Motorcycle ride telemetry recorder: foreground service records GPS to a
local Room database and streams batches to a REST endpoint when one is
configured. Debug build, signed with the debug key so it installs directly
via adb install or a file manager.
com.rippr / versionCode 1 / minSdk 26 / targetSdk 35
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>