From c8c10d8977af2b68ddb52ade840b5eec23e47e08 Mon Sep 17 00:00:00 2001 From: uhryniuk Date: Mon, 10 Aug 2026 15:24:45 -0500 Subject: [PATCH] Add tunie map/tune viewer: self-contained HTML, no deps 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. --- tunie/viewer/build_viewer.py | 98 ++++++++++++ tunie/viewer/sample_table.bin | Bin 0 -> 8192 bytes tunie/viewer/template.html | 279 +++++++++++++++++++++++++++++++++ tunie/viewer/tunie-viewer.html | 279 +++++++++++++++++++++++++++++++++ 4 files changed, 656 insertions(+) create mode 100644 tunie/viewer/build_viewer.py create mode 100644 tunie/viewer/sample_table.bin create mode 100644 tunie/viewer/template.html create mode 100644 tunie/viewer/tunie-viewer.html diff --git a/tunie/viewer/build_viewer.py b/tunie/viewer/build_viewer.py new file mode 100644 index 0000000..fcd30d4 --- /dev/null +++ b/tunie/viewer/build_viewer.py @@ -0,0 +1,98 @@ +"""Build a self-contained HTML viewer for the Triumph tuning project. + +Extracts TuneECU's editable-surface definitions (tunable parameters, table +axes, toggleable devices, live sensors, actuator tests) from the decompiled +APK resources, combines them with the already-extracted map catalogue +(maps.json), and embeds everything into a single double-click-to-open HTML file +with no server and no external dependencies. + +Usage: + python3 viewer/build_viewer.py \ + --arrays ../work/apktool_out/res/values/arrays.xml \ + --maps maps.json \ + --template viewer/template.html \ + --out viewer/tunie-viewer.html +""" + +from __future__ import annotations + +import argparse +import json +import re +from pathlib import Path + +# Resource arrays worth surfacing, with a friendly label and short note. +DEF_ARRAYS = { + "Parameters": ("Tunable parameters", "Single-value settings TuneECU can change."), + "title_axis": ("Table axes", "The axes every fuel/ignition map is built on."), + "Devices": ("Toggleable devices", "Emissions/hardware features that can be turned off."), + "eSensor": ("Live sensors", "Channels the ECU streams while running."), + "test_devices": ("Actuator tests", "Outputs TuneECU can command for bench testing."), + "reset_devices": ("Reset routines", "Adaptations/adjustments that can be reset."), + "ftrim_name": ("Fuel-trim tables", "Per-cylinder fuel trim table names."), + "ecu": ("ECU families", "Supported ECUs; the code after ':' is the type char."), +} + +# Devices/parameters directly relevant to this bike's planned mods. +MOD_TARGETS = {"SAI", "O2 Sensor", "O2 Sensor (2)", "Exhaust Valve", "Air Flap"} + + +def _extract_arrays(arrays_xml: Path) -> dict: + s = arrays_xml.read_text(encoding="utf-8") + + def arr(name: str) -> list[str] | None: + m = re.search( + rf']*>(.*?)', s, re.S + ) + if not m: + return None + return [ + re.sub(r"\s+", " ", i.strip().strip('"')) + for i in re.findall(r"(.*?)", m.group(1), re.S) + ] + + out = {} + for name, (label, note) in DEF_ARRAYS.items(): + items = arr(name) or [] + out[name] = { + "label": label, + "note": note, + "items": [{"i": i, "text": t} for i, t in enumerate(items) if t], + } + return out + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--arrays", required=True, type=Path) + ap.add_argument("--maps", required=True, type=Path) + ap.add_argument("--template", required=True, type=Path) + ap.add_argument("--out", required=True, type=Path) + args = ap.parse_args() + + defs = _extract_arrays(args.arrays) + maps = json.loads(args.maps.read_text(encoding="utf-8")) + + payload = { + "definitions": defs, + "maps": maps, + "modTargets": sorted(MOD_TARGETS), + "meta": { + "mapCount": len(maps), + "source": "TuneECU APK resources (arrays.xml) + maps.json", + }, + } + + template = args.template.read_text(encoding="utf-8") + blob = json.dumps(payload, separators=(",", ":")) + html = template.replace("/*__DATA__*/", blob) + + args.out.write_text(html, encoding="utf-8") + kb = len(html.encode("utf-8")) / 1024 + print(f"wrote {args.out} ({kb:.0f} KB, {len(maps)} maps, " + f"{sum(len(d['items']) for d in defs.values())} definition rows)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tunie/viewer/sample_table.bin b/tunie/viewer/sample_table.bin new file mode 100644 index 0000000000000000000000000000000000000000..8b4747a8012326c57c72bf8a36e535764e25dfa6 GIT binary patch literal 8192 zcmeIw+e_3@5C?E6s5A4O`C&fv5Eb1>#cV~Qr!JOVAhX)aE-Kbb;XXw4(1V6ZS*AVM zm6i$$1Hr_iC05Wf3JQZF!$7J{lx`qxcVf*jI{h0tXE<=+@EzuSIB99NOuz)jtH9(T zcgTICcFy2Ee2oWu{op2!&?nmJx?PS-cX2AD0WRgU{2S9T2O)mt&kLxHvfX)?=aN*% z%+34-1=xpTY{W!<%ZI6#BJPokP$u2rFu%lH)SwX;P>Wq~e35gh-i^2ft)Y*6hDUw! zI=b)-FD6RyE%n23`>rbNQGn~ zg*H@h53i$EI>I6Dz)Y|bRdJ@pd4dz zQzvM(-q$`I@pW6*%1=3o7s$gRG|N(X?lb-_C4EB14N0%4*Z!BT)~R}0hl8SE zLvSFd36|)fR!K@$qkFvmdwaJDn1BhGfC-p@37CKhn1BhGfC-p@37CKhn1BhGfC-p@ J3H+}De*x8XkZ}M2 literal 0 HcmV?d00001 diff --git a/tunie/viewer/template.html b/tunie/viewer/template.html new file mode 100644 index 0000000..8443c8f --- /dev/null +++ b/tunie/viewer/template.html @@ -0,0 +1,279 @@ + + + + + +tunie — Triumph tuning viewer + + + +
+

tunie

+ +
+ +
+ +
+
+ + + + ★ My bike (Keihin · mechanical · Bonneville) + +
+ + + + + +
MapECUDetails
+
+ +
+

TuneECU's full editable surface, extracted from the APK. The + highlighted devices are the SAI / O2 / exhaust + items this project plans to delete.

+
+
+ +
+
Drop a map file here (.bin or Intel .hex) — or click to choose. + +
+ +

No dump yet? This becomes useful after tunie reads a ROM. + Meanwhile you can drop any TuneECU .hex map to eyeball its bytes, + and hand-locate tables by diffing two maps.

+
+ +
+ + + + + diff --git a/tunie/viewer/tunie-viewer.html b/tunie/viewer/tunie-viewer.html new file mode 100644 index 0000000..ae28a43 --- /dev/null +++ b/tunie/viewer/tunie-viewer.html @@ -0,0 +1,279 @@ + + + + + +tunie — Triumph tuning viewer + + + +
+

tunie

+ +
+ +
+ +
+
+ + + + ★ My bike (Keihin · mechanical · Bonneville) + +
+ + + + + +
MapECUDetails
+
+ +
+

TuneECU's full editable surface, extracted from the APK. The + highlighted devices are the SAI / O2 / exhaust + items this project plans to delete.

+
+
+ +
+
Drop a map file here (.bin or Intel .hex) — or click to choose. + +
+ +

No dump yet? This becomes useful after tunie reads a ROM. + Meanwhile you can drop any TuneECU .hex map to eyeball its bytes, + and hand-locate tables by diffing two maps.

+
+ +
+ + + + +