Files
samplez/tunie/research/reference-maps/DEVICES.md
uhryniuk 4aa5da53d2 Commit tune maps and research so tunes are reachable from the phone
Removes the *.hex/maps_cache gitignore rule (explicit user call, reversing
the earlier no-redistribution stance) so the official TuneECU catalogue
maps, derived SAI/O2-delete composites, and the checksum/composition
tooling are actually available to pull up on a phone browser when using
the real TuneECU app. Also folds in tonight's KWP2000 fixes (TesterPresent
keep-alive, connect-failure cleanup, slow-init StartCommunication fix) and
the accumulated research docs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FP2GaxS9HkUdL5sLBnjKje
2026-08-27 01:34:05 -05:00

157 lines
8.5 KiB
Markdown

# Device-enable flags (SAI / O2 / lambda) — validated
**Aug 2026 update:** re-fetched `20188Map2009AIRBOXBONNY.hex` from its real
source — it's in `tuneecu.net`'s own custom-map archive
(`Twin_Custom_Tune_list.html`, not a forum attachment as previously assumed),
not gitignore-lost this time. Re-ran the diff against a freshly downloaded
stock `20188Map.hex` and **every claim below reproduced exactly**: same
1428-byte diff (0.36%), same three device-flag bytes, same two trim bytes.
The file now lives in this directory (`20188Map2009AIRBOXBONNY.hex`,
`20187/88/91/92Map.hex`) rather than resting on memory of a prior session.
See `../COMMUNITY_TUNING.md` for the new composability findings (device
flags vs. Arrow exhaust delta) this re-verification enabled.
## How they were found
Both stock reference maps (20187, 20188) have SAI and O2 **active**, so diffing
them can't reveal the delete flags. The confirmation came from a community map
that explicitly disables them:
`20188Map2009AIRBOXBONNY.hex` — "Bonneville, aftermarket exhaust, mechanical
odometer, NO AIR BOX, K&N, British Custom mufflers, **NO SAI, NO O² SENSORS**".
Same base as stock 20188, so the diff isolates the deletes.
Diff (flat ROM) of that map vs stock 20188 = 0.36%, split into:
- the fuel tables (airbox/K&N enrichment — expected), and
- a small cluster in the device-config region at **0x53801…0x53819**.
## The flags
They are a **byte-boolean array** at flat-ROM `base + fe[33]` (= `0x50000 + 0x3801
= 0x53801`), one byte per device, **1 = enabled, 0 = disabled**.
The delete map changed exactly three bytes from 1 → 0:
| Flat-ROM offset | Stock | Deleted | Device |
|---|---|---|---|
| `0x53801` | 1 | 0 | **SAI** (Secondary Air Injection) |
| `0x53818` | 1 | 0 | **O2 sensor** |
| `0x53819` | 1 | 0 | **O2 sensor (2)** |
SAI is the first flag in the array; the two O2 sensors are the last two —
consistent with the `Devices` resource order (SAI = index 0; O2 Sensor / O2
Sensor (2)). The three-byte change matching "NO SAI, NO O²" is unambiguous.
To disable a device: set its byte to `0`. (The `0x5369C`/`0x536AB` bytes that
also changed are idle/open-loop trim that comes with removing the O2 feedback,
not device-enable flags.)
## Editing / export
The downloaded `.hex` format's integrity is the `dc` stream cipher + the unpack
directory; the `caXX` bytes in the header/tail are map-ID metadata, **not** a
calibration checksum. So a device toggle = flip the byte in the flat ROM, re-pack
to the decoded layout, and `dc`-encode back to `.hex`. (The separate *ECU flash*
checksum is computed at flash time and is out of scope for the read/edit tool.)
## Confidence
- **SAI = 0x53801: ~90% (high).** Two independent confirmations: the device-name
logic in `l.java` `lc()` resolves `Devices[0]=SAI` via `fe[33]` to exactly
0x53801, AND the real NO-SAI map cleared precisely that byte.
- **O2 sensors = 0x53818 / 0x53819: ~80% (probable).** The map declares "NO O²
SENSORS" (the twin has two) and exactly two adjacent boolean bytes cleared
beyond SAI; the 865 has no air-flap, so airbox removal is fuel-only (no flag).
Not independently isolated — no single-mod reference map exists, and the exact
`x.a()` device-layout branch for this ECU (i27=72) is too deeply nested to
trace reliably.
## The real-world caveat (more important than the labels)
Correct flags are **not** a good tune by themselves. Disabling O2 forces the ECU
**open-loop**: it stops live fuel trim and runs entirely on the base fuel map.
Stock maps assume closed-loop trim at idle/cruise, so an O2-delete on an otherwise
stock map can run lean/rough. A proper delete pairs flags-off with fuel enrichment
(which is exactly why the AIRBOXBONNY reference map also changed the fuel tables).
**Recommendation:** flash a complete, known-good delete map matching the hardware
(exhaust/filters), not hand-toggled flags on a stock map. The checkbox editor is
for understanding/building a map, not a one-click safe delete.
## `0x53822` — the extra flag found on the America dyno tune (Aug 2026)
Pushed on identifying this (index 33 past the `0x53801` base, one slot
past the two O2 sensors — see `COMMUNITY_TUNING.md`'s original finding on
`20184dynoTuneSteveO2-Disable.hex`). Real, bounded progress, not a full
resolution:
**Found the actual device name list** — `R.array.Devices` in
`arrays.xml:3-18`, 15 entries: `SAI, Exhaust Valve, O2 Sensor, 2nd
Throttle, Air Flap, EPC, O2 Sensor (2), Purge Valve, Idle Speed Control,
Traction Control, Immobilizer, Instruments, ABS, Speed Sensor (non ABS),
Race ECU`. This independently confirms and extends the existing SAI(0)/O2
Sensor(23)/O2 Sensor(2)(24) findings above — matches exactly, real data.
**Found the mechanism**: `l.java`'s `lc()` (`l.java:5742`) resolves the
per-device flat-ROM byte-boolean array from three packed nibble-encoded
constants (`x.t`/`x.s`/`x.q` in the decompile referenced by
`docs/ROADMAP.md`), looked up against `R.array.Devices` by index. **This
confirms flat-ROM byte position and `Devices[]` array index are not the
same thing** — SAI (array index 0) sits at byte 0, but O2 Sensor (array
index 2) sits at byte 23, O2 Sensor (2) (array index 6) sits at byte 24 —
a bike-specific sparse remapping, not a fixed formula.
**Where it stops:** the specific per-family constants that would decode
byte 33 precisely require tracing which branch of `x.java`'s ~46
assignments to the relevant classifier variable applies to Bonneville/T100
specifically. `docs/ROADMAP.md`'s existing note cites `i27=72` as the
anchor for this ECU family from a prior research pass, but that exact
comparison doesn't appear in this decompile snapshot — likely version
drift (this decompile's changelog shows APK updates through v6.4.36, June
2026; the `i27=72` note may predate that). Didn't find a reliable
replacement anchor without a much larger, low-confidence search across all
46 assignment sites.
**Best-supported guess, reasoning not proof:** narrowing the 12 unassigned
`Devices[]` names by plausibility for a 2010 mechanical-odo Bonneville/
America-class twin — **Purge Valve** (this project's own `system1.html`
research already documents a "Canister Purge Valve, California models
only" on this ECU family — a real, independently-corroborated candidate),
**Idle Speed Control** (the ISC stepper motor genuinely exists on this
engine), and **Immobilizer** (period-correct fuel-injected Triumphs
commonly used transponder immobilizers) are the most plausible of the 12;
**Exhaust Valve**, **2nd Throttle**, **ABS**, **Traction Control**, **Race
ECU** are implausible for this specific bike/era and can likely be ruled
out. Not confirmed — a genuine guess ranked by plausibility, not a finding.
**Update (Aug 2026) — independently verified, raises confidence further:**
checked `tests.html` in this project's own site mirror directly and found
a distinct, real testable menu entry: **"Purge Control Valve (Only bikes
with charcoal canister) — Activate the purge valve, listen for a very
quiet noise,"** listed right alongside its own separate "SAI" test entry.
This confirms Purge Valve is a real, independent device on this ECU
family with its own dedicated test/enable path, not a guess — genuinely
strengthens (does not yet prove) the byte-33 hypothesis. Also confirms
from the same list: "Air Flap (675 Daytona)" is explicitly Daytona-675-only,
matching this document's elimination reasoning above. (Surfaced by an
external research pass, then independently confirmed here directly
against this project's own source rather than trusted secondhand — see
`../EXTERNAL_RESEARCH_NOTES.md`.)
**What would actually resolve this:** a second real-world reference map
where the specific device at byte 33 changes state with a documented
description (the same technique that resolved SAI/O2 originally) would
settle it definitively without needing the `x.t`/`x.s`/`x.q` trace at all.
## Open question raised by community research (unresolved)
Multiple forum threads describe TuneECU's own SAI/O2 checkboxes (the same UI
these bytes drive) as **only suppressing the fault-code/CEL logic**, not
actually forcing open-loop fueling — see `../COMMUNITY_TUNING.md`. That's in
tension with "disabling O2 forces open-loop" above. Possible reconciliation:
the three device-enable bytes gate DTC logic only, and the *fueling* behavior
change lives in the other bytes the real delete-map diff also touched
(`0x5369C`, `0x536AB`) or in the lambda-target curve (`fe[2]`/`0x52260`,
`TABLES.md`). Not yet isolated — needs a second independent delete-map diff
to separate device flags from fuel/trim bytes.