Files
samplez/tunie/research/COMMUNITY_TUNING.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

728 lines
44 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Community tuning knowledge — SAI/O2/exhaust, 865 twin
External research (Aug 2026), collected while deciding how to fuel-map the
2010 T100 for an Arrow 2-in-1 system. This is **secondhand community/vendor
information**, not independently verified against our own reversing — cross-
check against `reference-maps/DEVICES.md` and `TABLES.md` before trusting it
over what we've actually decoded.
## The standard mod order
Community consensus (multiple sources) for the air-cooled 865 twin:
1. O2 sensor removal
2. SAI (secondary air injection) elimination
3. Airbox baffle/snorkel removal
4. Free-flowing exhaust
5. Re-tune to match
"Once you've made these mods, you want to tune your engine to take full
advantage of them" — each step changes what the engine ingests/exhausts, so
tuning last is deliberate, not incidental.
[triumphbonneville.org: EFI Tuning – Triumph Twin Power](https://triumphbonneville.org/efi-tuning-triumph-twin-power/)
## IMPORTANT correction to our own assumption: what the TuneECU checkbox actually does
Multiple independent forum threads describe the SAI/O2 checkboxes in TuneECU's
own Map Edit → Parameters → Devices screen (the same UI our `viewer/` mimics,
and the same bytes we found at `0x53801`/`0x53818`/`0x53819`) as **only
suppressing the fault-code/CEL logic for a missing sensor — not a functional
open-loop switch**:
> "This does not disable either system though, only stops the CEL appearing."
> "Simply unchecking the box in TuneECU will only prevent warning lights from
> appearing — it won't actually disable the hardware itself. The sensor will
> still function unless physically removed or blocked off."
[triumphrat.net: Desactivate the O2 sensor on TuneECU](https://www.triumphrat.net/threads/desactivate-the-o2-sensor-on-tuneecu.200858/),
[thespeedtriple.com: How to turn off O2 sensor on TuneECU](https://www.thespeedtriple.com/threads/how-to-turn-off-o2-sensor-on-tuneecu-to-eliminate-check-engine-light.39850/)
**This needs reconciling with `DEVICES.md`**, which currently states flipping
these bytes "forces the ECU open-loop." The two claims aren't necessarily
contradictory — `DEVICES.md` also notes the real NO-SAI/NO-O2 reference map
changed *two more bytes* beyond the three device flags (`0x5369C`, `0x536AB`,
described there as "idle/open-loop trim that comes with removing the O2
feedback"). It's plausible the **device-enable bytes alone only gate the DTC
logic**, and the *actual* closed-loop-vs-open-loop fueling behavior lives in
those separate trim bytes (or elsewhere, e.g. the lambda-target curve at
`fe[2]`/`0x52260` noted in `TABLES.md`). Until we isolate that separately,
**do not assume our hand-toggled `derived/*-noSAI-noO2.hex` files change
fueling behavior** — they very likely only suppress fault codes, matching what
these threads describe. Treat them as "silences the CEL for missing
hardware," not "retunes for open loop." Real open-loop fueling probably
requires touching the lambda-target curve too — worth a dedicated diff pass
against a real delete map that isolates just the trim bytes from the device
flags.
Practical implication carried over from these threads: **if you physically
remove the O2 sensors, they must actually be unplugged/removed** — leaving
them wired with the checkbox off does not change what the ECU reads from
them, per the community description above.
## TuneECU map catalogue IDs seen in the wild (verify before trusting)
Forum threads reference these Bonneville map IDs for O2/SAI removal +
aftermarket exhaust:
| ID | Claimed to be | Checked against our `maps.json` |
|---|---|---|
| `20516` | "aftermarket exhaust... SAI/O2 removed" | **Wrong bike for us** — actually `ecu='E'`, America/Speedmaster, **LCD odometer**. Not compatible with the 2010 mechanical-odo T100. |
| `20500` | "OEM Arrow 2-2, up to E25" | `ecu='8'`, **LCD odometer**. Wrong generation for us. |
| `20505` | "OEM Arrow 2-2, up to E10" | `ecu='8'`, **LCD odometer**. Wrong generation for us. |
| `20507` | "aftermarket silencers, up to E25" | `ecu='8'`, **LCD odometer**. Wrong generation for us. |
None of these are usable for the mechanical-odo 2010 T100 — they're all a
later ECU generation (post-2016 water-cooled-era Bonnevilles use LCD
odometers and a different `ecu` type code in the catalogue). **Lesson: always
cross-check a forum-cited map ID against `maps.json`'s `ecu`/odometer fields
before using it** — the ID numbering isn't obviously tied to hardware
generation, and it's easy to grab the wrong one.
[triumphrat.net: Tune ECU Mapping for O2 and SAI removal - Bonneville](https://www.triumphrat.net/threads/tune-ecu-mapping-for-o2-and-sai-removal-bonneville.755058/)
No official TuneECU catalogue entry for the **mechanical-odo** Bonneville
(any exhaust, any of the ~163 entries we have) ships with SAI/O2 off — see
prior finding, still holds after this search.
## Commercial alternatives to a hand-toggled map
Several vendors sell purpose-built, dyno-derived 865-twin tunes rather than a
flag flip on a stock map — the safer route per our own `DEVICES.md`
recommendation:
- **Triumph Twin Power (TTP)**, run by Mike Cripps — "865 EFI Tune Map 3" is
built for Stage 1 mods (aftermarket exhaust incl. Arrow, SAI removed, O2
removed), delivered via TuneECU/TuneLoader software or mail-in ECU
reprogram. TTP reportedly offers **17 different Bonneville tune variants**
for different mod combinations. Currently listed out of stock on their
site.
[triumphtwinpower.com: 865 EFI tune map 3](https://www.triumphtwinpower.com/bonnevillet100-performance-tune-3.php?review=all),
[triumphbonneville.org write-up](https://triumphbonneville.org/efi-tuning-triumph-twin-power/)
- **DNK TuneWorks** — $275, mail-in ECU service. Explicitly offers
"Enable/Disable Secondary Air Injection" and O2 sensors as a configurable
option, plus top-speed-limiter removal, AFR/timing optimization at full
throttle, deceleration-pop reduction, and speedometer correction (relevant
since our bike's mechanical odo/speedo would need correction if final
gearing or wheel/tire size changes).
[dnktuneworks.com: Bonneville T100/SE (865)](https://dnktuneworks.com/product/triumph-bonneville-900/)
- **British Customs** tuning guide recommends, for 2008–2017 air-cooled
Bonneville/T100: the catalogue "Arrow 2-2" maps for slip-ons, "Arrow 2-1"
for full systems/performance packages, or a custom tune from DNK/TTP —
explicitly warns against self-tuning without dyno validation ("an incorrect
tune can create running issues or even cause damage to your bike").
[britishcustoms.com: Triumph Motorcycle Tuning Guide](https://britishcustoms.com/blogs/bc-blog/triumph-motorcycle-tuning-guide)
## Full ROM-level tuning path (beyond TuneECU's catalogue)
For editing tables directly rather than picking from TuneECU's preset list:
- **OldSkullTuning** and **Tuniverse** sell XDF definition files (~€70) for
TunerPro, covering the Keihin **SH7054** (our ECU family) and the related
**SH72531**. The XDF exposes fuel tables, spark advance by gear, idle
speed, RPM limiter, and **"lambda deactivation"** as editable parameters —
the last one likely corresponds to the AFR/lambda curve we already located
at flat-ROM `0x52260` (`fe[2]` in `TABLES.md`), which is a stronger lead on
where real open-loop behavior is actually controlled versus the device
on/off bytes.
[oldskulltuning.com: Triumph Keihin SH7054 TunerPro Maps](https://oldskulltuning.com/triumph-keihin-sh7054-tunerpro-maps/)
- This path requires a **ROM dump** (Phase 2 in `docs/ROADMAP.md`, not yet
implemented — `tunie` is read-only by construction) — XDF+TunerPro edits
the raw ROM, not the encrypted download-format `.hex` our `decode_map.py`/
`toggle_devices.py` work with. Two different file formats, same underlying
address space.
## Practical procedural notes from the community (unverified, for later)
- One installation note (TTP-specific, may not generalize): during whatever
post-flash adaptation/reset procedure applies, "pull out the cold start
knob only long enough to get your engine started" — leaving it out too long
during the reset apparently corrupts the adaptation and forces a restart of
the procedure from a cold engine. Relevant once we're actually flashing;
irrelevant to read-only work now.
- Community sentiment is split on hand-toggling checkboxes on a stock map:
several threads describe doing exactly that (download OEM aftermarket-
silencer map, untick SAI/O2 in Map Edit, reflash, clear codes) as a known,
common shortcut — but per the correction above, that shortcut may only be
silencing warning lights, not actually retuning for open loop. Worth
weighing against a matched TTP/DNK map before trusting it as a real tune.
## Existing tunes for airbox removal + 2-1 exhaust (Aug 2026)
**TTP did/does sell exactly this combination** — but it's paid, and every
variant is currently out of stock (consistent with the TTP-closure finding
above):
| Tune | Mods | Price | Stock |
|---|---|---|---|
| `865 EFI Tune Map 1 2-1` | 2-1 exhaust + Breathe HiFlo intake **cover** (airbox shell kept) + DNA filter + O2 removal + Stage 1 ignition | £130 (~$177 USD) | Out of stock |
| **`865 EFI Tune Map 2 2-1`** | 2-1 exhaust + intake cover + **airbox baffle removed** (not full removal) + DNA filter + O2 removal — **best match to this build**, and the exact combo the Aug 2026 dyno data above (69.02 BHP/54.38 ft-lb) is for | £130 (~$177 USD) | Out of stock |
| `865 EFI Tune Map 11 2-1` | **Full airbox removal** + pod filters + 2-1 exhaust + O2/SAI removal (per customer reviews: "removed the O2's and fitted a 2/1 tec pipe", "Air box removed... 2 into 1 with O2 sensors and air injection system removed") | not listed | Out of stock |
| `865 EFI Tune Map 13` | Long free-flow silencers (Arrow 2-2 named explicitly, not 2-1) + pod filters + performance cams + O2 removal | £130 (~$177 USD) | Out of stock |
[triumphtwinpower.com: 865 EFI tune map 1 2-1](https://www.triumphtwinpower.com/bonnevillet100-performance-tune-1-2-1.php?review=all),
[triumphtwinpower.com: 865 EFI tune map 2 2-1](https://www.triumphtwinpower.com/bonnevillet100-performance-tune-2-2-1.php),
[triumphtwinpower.com: 865 EFI tune map 11 2-1](https://www.triumphtwinpower.com/bonnevillet100-performance-tune-11-2-1.php?review=all&ro=2),
[triumphtwinpower.com: 865 EFI tune map 13](https://www.triumphtwinpower.com/bonnevillet100-performance-tune-13.php)
**Site-wide stock-status trap, found Aug 2026:** TTP's master listing page
(`triumph-bonneville-t100-865-efi-tunes.php`) shows every single tune as
"In stock" — this is wrong, a catalogue-display artifact, not real
inventory. Verified directly: `Tune 2 2-1`'s own product page clearly
shows "We don't currently have that one in stock." **Always check the
individual product page, never trust the listing page's stock column.**
**Free, from TuneECU's own catalogue: none.** Dumped and grepped all 163
Bonneville entries in `maps.json` for any of "air[box]", "race",
"perform[ance]", "competition", "track", "open" (as in open/velocity-stack
airbox) — zero matches, on top of the earlier zero matches for
delete/SAI/O2/lambda language. TuneECU never shipped an official Bonneville
calibration that assumes the airbox is removed, at any exhaust
configuration, free or otherwise. The only two "airbox removed" reference
points that exist anywhere are: the paid, currently-unavailable TTP tunes
above, and the single community `2009AIRBOXBONNY.hex` file (aftermarket
silencers, not Arrow, not in this repo).
**Checked catalogue-wide, not just Bonneville:** grepped all 1811 entries in
`maps.json` (every Triumph model TuneECU covers) for "airbox"/"air box"/
"velocity stack"/"open filter"/"race filter"/"competition filter" — **zero
matches, for any model.** TuneECU has never shipped an official
airbox-removed calibration for anything. There's no "independent airbox
tune" sitting in the free catalogue to pair with the independent Arrow 2-1
tune (`20262`) — the airbox side of this doesn't exist as a catalogue entry
at all, official or otherwise, so there's nothing free to merge in the first
place. And even if there were, the overlap finding two sections up means a
byte-level merge of two independent deltas isn't sound anyway — this closes
off the "merge two catalogue tunes" idea from both directions (no second
input map to merge, and the merge mechanism itself doesn't work at the byte
level).
**Bottom line: no free airbox-removal-matched tune exists for this bike,
from TuneECU or anywhere else found so far.** If airbox removal stays in
the plan, the realistic options are (a) pay for TTP stock to return, (b) a
DNK Tuneworks mail-in tune, or (c) run without airbox removal and keep just
Arrow 2-1 + SAI-flag-off, which *is* fully covered by the free catalogue
(`derived/20262-noSAI-only.hex`) plus the resistor swap above.
## Can we build "Arrow 2-in-1 + airbox removal + SAI delete" ourselves?
Split by what's actually being asked, because the answer is different for
each piece:
**"Suppress the SAI fault code so the resistor-swapped solenoid doesn't
throw a DTC" — yes, solved, already built.** This is exactly what the
`0x53801` device-enable byte is for, per the checkbox research above (it's
specifically a fault-suppression toggle, not an engine-behavior one) — so
using it for this purpose is squarely its intended function, not a misuse.
`toggle_devices.py --only-sai` produces this on any base map:
```
derived/20262-noSAI-only.hex (Arrow 2-in-1, t202, E10, SAI flag off)
derived/20313-noSAI-only.hex (Arrow 2-in-1, t203, E10, SAI flag off — same tune, see PERMUTATIONS.md)
```
Verified byte-identical to the stock `20262`/`20313` Arrow calibration except
the single SAI flag (`1 -> 0`). No effect on the O2 flag, so this doesn't
touch anything O2/closed-loop related — narrowly scoped to exactly the
resistor-solenoid scenario. This part carries the confidence level
`DEVICES.md` already assigns to that offset (~90%, corroborated two
independent ways).
**"Airbox removal, fuel-matched to Arrow 2-in-1" — no, not with what we
have.** `research/reference-maps/PERMUTATIONS.md` (full cross-diff of all 12
official mechanical-odo Bonneville calibrations) found that exhaust-delta
and fuel-delta bytes overlap heavily (4149 of 4809 fuel-delta bytes sit
inside the exhaust-delta footprint) — different mods' corrections land on
the *same* fuel-table cells, so byte-level composition isn't valid; it would
overwrite one correction with another rather than combining them. We also
don't have an airbox-removal reference for the Arrow-2-in-1 case at all —
the one community airbox/SAI/O2-delete file we know of
(`2009AIRBOXBONNY.hex`) is for **stock aftermarket silencers, not Arrow**,
and isn't currently in this repo to even re-derive a delta from.
**Bottom line:** flip the SAI flag on `20262`/`20313` now — that solves the
actual near-term problem (no DTC once the resistor goes in) and is
low-risk since it's using the flag for exactly what it does. Don't try to
DIY the airbox-removal fuel enrichment on top of Arrow 2-in-1 — that's
either a real dyno tune (DNK, since TTP's storefront is effectively wound
down) or the bigger table-level-arithmetic project noted in
`PERMUTATIONS.md`, not something the current byte-diff tooling can do
safely.
## Open questions this raises for our own reversing
- Isolate whether `0x5369C`/`0x536AB` (or the lambda curve at `0x52260`) are
what actually changes fueling behavior, separate from the three device-
enable bytes — would resolve the discrepancy between "DEVICES.md says
open-loop" and "forums say checkbox is CEL-only."
- If we can get a second community NO-SAI/NO-O2 reference `.hex` (ideally
Arrow-specific) independent of `20188Map2009AIRBOXBONNY.hex`, diffing three
maps instead of two would separate device-flag bytes from fuel/trim bytes
more confidently than the current single-diff derivation.
## FOUND: tuneecu.net's own custom-map archive (Aug 2026, supersedes below)
The `2009AIRBOXBONNY.hex` we'd been treating as unreachable was never behind
a forum paywall — it's sitting in **`tuneecu.net`'s own site**, one click
from the page the user asked us to check
(`TuneECU_En/mapedit.html` -> nav -> `Links&Downloads` -> `Map_Database.html`
-> `Twin_Custom_Tune_list.html`, the community/custom-map equivalent of the
official `Twin_OEM_Tune_list.html` catalogue `maps.json` was built from).
Downloaded directly, no forum account needed:
- `20188Map2009AIRBOXBONNY.hex` — the file `DEVICES.md` was built from.
Re-diffed against a fresh `20188Map.hex`: **reproduces exactly** — same
1428-byte/0.36% diff, same three device-flag bytes, same two trim bytes.
`DEVICES.md`'s findings are now independently re-verified, not resting on
an unreachable prior-session file.
- `20500MapAirboxBonnie_LCD.hex` — a second delete map, **Arrow 2-in-2 +
airbox removal + no SAI + no O2**, closer to what we actually want than
the aftermarket-silencer one. Caveat: **LCD odometer**, wrong ECU
generation for the mechanical-odo T100 — and confirmed *not* portable:
reading its bytes at the mechanical-odo device-flag offset (`0x53801`)
gives garbage (`255`, not `0`/`1`), because the calibration-metadata
pointer table (`fe`, `TABLES.md`) is per-map-signature, not a fixed
address across ECU generations. Useful as a *second data point on the
delta shape*, not as a byte-for-byte reference for our bike.
- `904bigvalvegasflowed790cam44mmTBshortExhaust.hex` — a built-engine
(big-valve head, cams, 44mm throttle bodies) custom tune. Not relevant to
a stock-engine delete/exhaust question, noted for completeness.
Both usable files are now in `reference-maps/` (not gitignore-lost this
time — the `.hex` gitignore rule is at the samplez repo root, these are
committed-adjacent working files, just excluded from git; keep them on disk
locally for future sessions).
## What the real device-flag file tells us about composing Arrow + delete
With `20188Map2009AIRBOXBONNY.hex` in hand, checked precisely which of its
1428 changed bytes overlap with the Arrow 2-in-1 exhaust delta
(`20187`->`20262`, 7548 bytes, from `PERMUTATIONS.md`):
- **1344 of 1428 delete-delta bytes (94%) overlap the exhaust delta** — as
expected from the earlier finding, both land on the same main VE/fuel
table cells.
- **The 7 bytes outside the fuel-table regions** are the ones that actually
matter, and they split cleanly into two groups:
| Bytes | In exhaust delta too? | Composable? |
|---|---|---|
| `0x53801`, `0x53818`, `0x53819` (SAI, O2×2 device flags) | **No — untouched by the Arrow delta** (both maps hold `1` there) | **Yes, cleanly.** Confirms `toggle_devices.py` applied to `20262`/`20313` is a sound, conflict-free composition — this is exactly what `derived/20262-noSAI-noO2.hex` already does. |
| `0x5369C` (104→69 under Arrow, vs. 255→117 under delete), `0x536AB` (125→133 under Arrow, vs. 128→138 under delete) | **Yes — both maps change these two idle/open-loop trim bytes, to different values** | **Yes, both — see correction below.** Initially treated as a conflict because `0x5369C` was read as unsigned; in signed space there's no conflict, both compose additively. |
**Update (Aug 2026): both trim bytes compose, not just one.** The
"genuine conflict" on `0x5369C` was an artifact of unsigned byte reading —
see the full correction further down this document
(`TABLES.md` established the table is signed). With correct signed
arithmetic, `0x5369C` composes the same way `0x536AB` does, saturating at
`+127` rather than needing to be excluded. `compose_arrow_delete.py` now
composes both.
- The three device flags: safe, already done, zero risk of stepping on the
Arrow calibration.
- The two idle-trim bytes: both now composed with signed arithmetic.
- The remaining fuller table-level VE arithmetic project
from `PERMUTATIONS.md`, if the main-table overlap (the 1344 bytes) is worth
resolving too, is still open — that's a materially bigger project than
these two isolated bytes.
- The big 1344-byte overlap in the main VE tables remains the real unsolved
part — same conclusion as `PERMUTATIONS.md`: needs 16-bit-cell arithmetic
composition, not byte-patching, to combine "richer for Arrow" and "richer
for no-O2-feedback" into one number per cell rather than picking one.
## The two conflicting bytes, resolved (Aug 2026)
Dug into `0x5369C` and `0x536AB` individually rather than treating them as
one problem. Pulled the same two addresses across all four E10/E25 x
production/aftermarket stock pairs (`20187`/`20191` production,
`20188`/`20192` aftermarket) to see whether each byte behaves like a small
linear trim or something else:
| Byte | 20187 (prod E10) | 20191 (prod E25) | 20188 (after E10) | 20192 (after E25) | 20262 (Arrow) | delete |
|---|---|---|---|---|---|---|
| `0x5369C` | 104 | 104 | **255** | **255** | 69 | 117 |
| `0x536AB` | 125 | 125 | 128 | 128 | 133 | 138 |
**`0x536AB` is a normal trim byte** — smoothly increasing, tightly clustered
values regardless of exhaust family or fuel type. Composed it additively:
`arrow(133) + [delete(138) - aftermarket_stock(128)] = 143`.
**`0x5369C` — correction, Aug 2026: this conclusion was wrong, built on an
unsigned reading.** At the time, `255` looked like an exhaust-family
sentinel distinct from the ~69-104 held elsewhere, so the byte was left
untouched rather than composed. `TABLES.md` later established this whole
table is **signed** two's-complement (-128..127), confirmed from two
independent code paths in the TuneECU app itself. Redone in signed space,
unsigned `255` is simply signed **-1** — an entirely ordinary, near-neutral
value. There is no sentinel, no regime conflict, no reason to exclude it.
Composed the same way `0x536AB` always was: `stock188=-1`, `delete=+117`,
`delta=+118`; `arrow=+69 + 118 = +187`, clamped to the signed max `+127`.
The correction genuinely wants this cell pushed to its richest possible
value at this RPM point — clamping to `+127` is the right outcome, not a
sign the byte doesn't compose. `compose_arrow_delete.py` now composes both
bytes; `derived/20262-arrow-delete-composed.hex` regenerated accordingly.
Built the result: `research/reference-maps/compose_arrow_delete.py`, output
in `derived/20262-arrow-delete-composed.hex` and
`derived/20313-arrow-delete-composed.hex` — Arrow 2-in-1 E10, all three
device flags off, the one genuinely composable trim byte combined, the
one non-composable trim byte deliberately left alone with the reasoning
recorded in the script's docstring.
**What's still outstanding:** the ~1340-byte overlap in the main VE fuel
tables (`PERMUTATIONS.md`) — this session resolved the two *isolated*
device-adjacent bytes, not the big fuel-table composition question, which
still needs 16-bit-cell arithmetic rather than a two-byte spot fix.
## Minor: FAQ confirms device checkboxes are conditionally available
`tuneecu.net/FAQ.html` (German) has a direct question: "Why can't I disable
my lambda sensor under Map Edit, or the checkbox won't uncheck?" Answer
(old Windows version specific): some options need a double-click to take
effect, "but there are also options that are not executable [at all]" —
i.e. device toggles can be locked/unavailable depending on model/ECU
variant. Consistent with `DEVICES.md`'s note that the device-layout logic
(`x.a()`) branches per ECU variant, and with this session's discovery of a
device flag at `0x53822` on the America map that may not even exist as a
concept on the Bonneville. Also: site-wide notice that tuneecu.net "will no
longer be updated after September 2024" — the whole project (not just TTP)
is in wind-down/archive mode, worth knowing before relying on it long-term.
## Major find: a documented no-dyno road-tuning method (Aug 2026)
Buried in the crawled mirror: `Dr_Feinbeins_kleine_Abstimmfibel/t5_kleine_abstimmfibel.htm`
("Dr. Feinbein's little tuning primer", German, dated 2003, credited to
TuneBoy/TuneEdit author Wayne Macdonald's tooling). It's a complete,
concrete methodology for correcting the main fuel table **on the road,
without a dyno**, using a wideband O2 sensor and a datalogger. Summarized in
English (this project's translation, not an official one):
**The tables it names** (TuneEdit/TuneBoy terms — same Keihin/Sagem
architecture TuneECU works with, though possibly not 1:1 identical naming
to TuneECU's own UI):
- **FuelMap** — intake air mass in mg, indexed by throttle position (TP)
and RPM. This is our `F1-F4` main fuel tables.
- **AF1** — target air/fuel ratio at part load, indexed by load and RPM.
Example given: 13.0-13.5:1 for good part-throttle drivability.
- **AF2** — target AFR at full load. Example: 12.5:1 for max power (richer
than stoich 14.7:1, leaner than part-load — the classic power-vs-driveability
split). Note "full load" isn't the same as "throttle fully open" — at low
RPM, full load is reached well before 100% throttle.
- **Fuel%trim table** — a **separate 2D correction table** (author states
"15x24" values) overlaid on the FuelMap, used *specifically* for this
road-tuning workflow. **This is distinct from the "Idle Fuel Trim (CO)"
1D/32-entry array we identified above** — two different named trim
concepts in the same architecture, easy to conflate. Fuel%trim is reset
to 0 before each measurement pass and has a **"Commit trims to main
tables"** function that permanently bakes the correction into the FuelMap
and zeroes the trim table again — i.e. it's explicitly a *working*
table, not persistent tune data.
**The method, condensed:**
1. Fit a wideband O2 sensor (temporary controller, e.g. under the seat) —
either replacing the stock narrowband sensor, or via a bung welded into
the exhaust on bikes with no stock sensor. **Disconnect the stock
sensor and run a tune with closed-loop trim disabled** for the duration
— you're substituting your own live AFR reading for the ECU's.
2. Start from a base tune with **AF1 and AF2 both set flat to 13.0** (rich
enough to be measurement-safe, no lean risk) and **Fuel%trim table
zeroed**.
3. Mark the throttle grip at positions roughly matching the FuelMap's TP
breakpoints. On a quiet straight road, hold each throttle position
steady through the RPM range (3rd gear, steady climb from ~1500rpm to
redline), 3 measurement passes per throttle position, logging RPM,
current TP row + offset to the next row, target AFR, and measured AFR.
4. In a spreadsheet, for each logged point, note where it falls between
two Fuel%trim table breakpoints (interpolate by the offset), and enter
the measured-vs-target AFR discrepancy into that Fuel%trim cell.
5. **"Commit trims to main tables"** — bakes the correction into the
permanent FuelMap, zeroes Fuel%trim again, flash back to the bike,
repeat. Author reports 3-4 iterations converges to only small residual
corrections.
6. Once the FuelMap itself is corrected, set real AF1/AF2 target curves
(not the flat 13.0 placeholder) and do a final commit — that's the
finished road tune.
7. **A dyno session afterward is optional, not required** — author notes
it should only need fine-tuning via Fuel%trim at that point, "not much
should come out of it" if the road-tuning was done properly.
**Why this matters for the airbox-removal plan:** this is a real,
documented alternative to paying for TTP/DNK — the hardware cost is a
wideband O2 sensor + controller + a cheap datalogger/laptop setup, not a
tuner's fee. It directly targets the exact problem airbox removal creates
(the main FuelMap no longer matches real airflow) using the manufacturer's
own table structure, correcting *measured reality* rather than guessing at
composed deltas the way this project's own `PERMUTATIONS.md`/
`compose_arrow_delete.py` work has been attempting. Worth serious
consideration as the actual path forward once the airbox mod happens,
independent of whether a commercial tune is ever obtained.
**Caveat resolved — confirmed present in the current Android app.**
`TuneECU_En/android.html` describes, in TuneECU's own current UI terms,
the identical mechanism the 2003 German guide used:
> "From the 'F' or 'I' screen, the corresponding corrections **F Trim**
> table can be displayed by swiping towards the right." ... "**F Trim
> global**: Use the F Trim table for all 'F' tables." ... "**Commit
> trims**: Apply each Trim table to the F & I table and reset the F Trim
> tables." ... "**Import table PCIII/V**: Import a table PCIII or V in the
> trim tables."
Same names (F Trim / I Trim, not "Fuel%trim" — terminology drifted slightly
from the 2003 TuneEdit doc but the mechanism is identical), same "commit"
semantics (bake trim into the main table, reset trim to zero), and it works
for both F (fuel) and I (ignition) tables, on the actively-maintained
Android app, not a defunct Windows tool. **The road-tuning method above is
directly usable today**, not archaeology — this is the real, current path
to a properly airbox-matched fuel table without paying a tuner.
Also from `android.html`'s UI walkthrough, confirms the **Devices** menu's
full generic list (bike-dependent which ones actually show/work, per the
FAQ note above): **SAI, O2 probe, Immobilizer** (example given: Ducati
Monster), **Traction control, instrument-cluster deactivation** (example:
Daytona 675 — lets the engine start without the dash connected). This is a
strong candidate identity for the unexplained `0x53822` flag found on the
America dyno tune last session — likely traction control or
instrument-cluster-deactivate on that model, not something that exists as
a concept on the Bonneville at all. Not confirmed, but a much better lead
than "unknown."
## Major find: a real dyno tune on our exact ECU generation, airbox removed (Aug 2026)
The full `Twin_Custom_Tune_list.html` listing (8 Bonneville/Thruxton/America
entries total, not just the 3 found via keyword search) contains one entry
much closer to what we actually want than `2009AIRBOXBONNY.hex`:
**`20184dynoTuneSteveO2-Disable.hex`** — America/Speedmaster, **mechanical
odometer**, base map `20184` (same `t201` mechanical-odo family as our
Bonneville, `ecu='0'`). Description: "Open pipe aftermarket K&N air filter
short slash cut foran pipe's and the air box **intake snorkel removed**,
**O2-probes disabled**, tune read from 08 America, mechanical odometer." A
real, named tuner's ("Steve") dyno-derived tune, not a hand-toggled stock
map — airbox snorkel removed + open pipes + O2 disabled, on our exact ECU
family.
[tuneecu.net: Twin_Custom_Tune_list.html](https://tuneecu.net/Twin_Custom_Tune_list.html)
Base map `20184` itself isn't live on tuneecu.fr any more; diffed against
the closest available stock baseline, `20186` (America, aftermarket
silencers, mechanical odo — same family, later revision, same relationship
as `20187`->`20191` for Bonneville).
**Confirms device flags a third time, independently:** `SAI=1` (left ON —
this tuner chose not to delete SAI, only O2), `O2 sensor 1/2 = 0` (both
off). Same offsets, third different base map, third confirmation beyond
`DEVICES.md`'s original 90%/80%.
**Revises the "two conflicting trim bytes" model from earlier this
session — it undersold the complexity.** This more aggressive tune (open
pipes, not just aftermarket mufflers) doesn't touch just `0x5369C`/`0x536AB`
in isolation — it rewrites **nearly every byte from `0x53690` to
`0x536AF`** (a ~32-byte span). That means `0x5369C`/`0x536AB` aren't
standalone scalar trims; they're two cells inside a **larger fuel-trim
table** (glossary confirms TuneECU's own concept of "Idle fuel trim" and
"Off idle fuel trim" as dedicated percentage tables, distinct from the main
F/L tables — this is almost certainly one of those). The Bonneville-family
comparison only touched 2 of this table's ~32 cells because that delta was
conservative (aftermarket mufflers only); this dyno tune's more aggressive
mods (open pipes) moved most of the table.
**Also found a new device flag** at `0x53822` (index 33 past `0x53801`,
i.e. one slot past the two O2 sensors) that this tune also disabled —
purpose not yet identified; may not even apply to the Bonneville's specific
device list (America/Speedmaster could have a different `Devices` array
length/order — `x.a()` branch is per-ECU-variant per `DEVICES.md`).
**And a whole new region, `0x50010`-`0x50C21`, extensively rewritten** —
not yet mapped to any named parameter. Glossary terms that likely live here
given what changed: ignition timing, rev limiter, injector pulse
time/short-term fuel trim. Not analyzed further this session.
**What this means for "have the tune ready for airbox removal":** real
progress, but the earlier two-byte fix (`compose_arrow_delete.py`) is now
known to be an incomplete model, not a finished one — it correctly handles
the 3 device flags and gets lucky on `0x536AB` being a small/isolated
correction for the *Bonneville* delta specifically, but a real
airbox-removal delta (per this more representative reference) touches a
32-byte trim table plus a further ~50-byte region neither previous
composition attempt accounted for. **Don't treat
`derived/20262-arrow-delete-composed.hex` as airbox-ready** — it isn't; it
was scoped to the SAI/O2 solenoid-removal problem specifically, not airbox
removal. Mapping the `0x53690-0x536AF` trim table's axis (RPM? gear? load
bin?) and the `0x50010-0x50C21` region is the actual next step before a
real airbox-removal composition is possible, and is a bigger project than
what's been done so far — worth scoping separately when picked back up.
## Second reference map search (Aug 2026): superseded by the find above, kept for history
Searched map-sharing threads, direct filename variants, and vendor sites for
a second independent NO-SAI/NO-O2 `.hex` to cross-diff against
`20188Map2009AIRBOXBONNY.hex`. Found nothing. One forum result was explicit:
> "There's just one map available for TuneECU for 2009 bikes or 2010 with the
> mechanical speedo... called [20188Map]2009AIRBOXBONNY.hex"
That file appears to be the **only** SAI/O2-delete map that ever circulated
for the mechanical-odo generation — originally derived from a British
Customs PowerCommander III map (no airbox, K&N pods, British Customs
mufflers). Everything else that surfaces (`20500`/`20505`/`20507`/`20516`,
`20498...LCD`) is confirmed LCD-odometer, wrong ECU generation.
**Caveat on our own `DEVICES.md` findings:** we don't currently have
`2009AIRBOXBONNY.hex` sitting in the repo (`.hex` is gitignored, and it
wasn't re-fetched this session) — `DEVICES.md`'s SAI/O2 offsets rest on a
prior analysis of a file we'd need to re-download to double-check. All its
known links are forum attachments behind the same `tollbit.*` paywall
blocking automated fetches here; getting it requires a forum login.
## Resolved: what physically removing O2 sensors actually changes
Closed-loop (O2-corrected) operation only runs in a narrow band: **idle and
steady low-to-mid throttle** (roughly <40% throttle, constant speed, warmed
up). **Acceleration and wide-open throttle are already open-loop on the
stock map** — the O2 sensor has zero influence there, stock or modified.
[motofomo.com: Open Loop vs Closed Loop](https://motofomo.com/open-loop-vs-closed-loop-fuel-injection/),
[racext.com: Understanding Fuel Injection and Tuning](https://racext.com/understanding-fuel-injection-and-tuning-open-vs-closed-loop/)
So **physically** removing/unplugging the sensors is a real behavioral
change (forces open-loop everywhere, richer/more consistent idle-cruise
fueling, cools the air-cooled top end, reduces snatchy off-idle response per
`RESEARCH.md` §9) — genuinely different from the checkbox-only CEL
suppression documented above. But two things temper "O2 delete = more
power":
1. **It only affects idle/cruise/part-throttle**, since WOT was already
open-loop. Peak-power gain from the O2 delete *by itself* is close to
zero — the actual power comes from the exhaust/airbox flow changes, and
O2 delete is what lets a richer fuel table for those changes stick
without the ECU fighting it.
2. **Unplugging without a matching richer map is a net negative**, not
neutral — you lose the live correction that was keeping idle/cruise from
running lean, with nothing filling in for it. Several sources describe
the ECU's adaptive/long-term trim quietly "learning" a custom map back
toward stock stoichiometric if the O2 sensor stays connected and active,
which is the flip-side risk (custom tune silently undone rather than
running lean).
[drdyno.com: O2 sensors and closed-loop systems](http://drdyno.com/AIM_2010-07.html)
Conclusion: SAI/O2 delete is a prerequisite that lets a richer tune hold, not
a horsepower mod on its own. The `derived/*-noSAI-noO2.hex` files in this
repo very likely only silence fault codes (per the checkbox finding above);
even a fully "correct" flag-and-fuel-table delete mainly buys cleaner
idle/cruise behavior, not peak power.
## SAI removal: actual risk profile (Aug 2026)
For someone who's already pulled the physical SAI plumbing (valves/hoses)
but left the solenoid wired up:
- **No engine-damage risk.** SAI only injects fresh air into the exhaust
port, downstream of combustion — it doesn't touch fueling, lubrication, or
cooling. There's nothing about removing it that can hurt the engine
mechanically.
- **The clicking solenoid is normal and harmless.** With plumbing removed
but the solenoid still electrically connected, "it will keep clicking
merrily away without throwing any ECU codes" — the ECU is still commanding
it on its usual duty cycle; there's just nothing downstream for it to
move. To actually silence it: replace the solenoid with a ~50 Ω resistor
(mimics the coil's electrical load so the ECU sees a normal circuit and
stops trying to drive it), or just leave the physical solenoid connected
even if unplumbed — either satisfies the ECU without the noise. Simply
unplugging the solenoid's connector, by contrast, opens the circuit and
*will* trigger a DTC — the software SAI-disable flag exists specifically
for that case, again consistent with the earlier CEL-suppression finding.
[triumphrat.net: Air injection removal](https://www.triumphrat.net/threads/air-injection-removal.846474/)
- **Deceleration popping cuts both ways depending on exhaust.** SAI air
helps combust unburned fuel present in the exhaust under deceleration. On
an aftermarket pipe (different backpressure/scavenging than stock), SAI
presence is reported as a *cause* of decel popping, not a cure — deleting
it is the fix, matching this project's own `RESEARCH.md` §9 guidance to
disable SAI before tuning for an aftermarket system.
[triumphrat.net: Bonneville Exhaust Popping Troubleshooting](https://www.triumphrat.net/threads/bonneville-exhaust-popping-troubleshooting-help.85412/)
- **Real risk is regulatory, not mechanical.** SAI is emissions hardware;
removing it is a tamper concern only where emissions testing/inspection
applies to the bike (varies by province/state; many jurisdictions exempt
older motorcycles). Not an engine-safety question.
- **One genuine fueling interaction, now moot for this bike:** if the O2
sensor sits downstream of the SAI injection point *and* SAI is still
actively pumping air (not just electrically connected with the plumbing
removed), the extra O2 in the exhaust can bias closed-loop trim toward
reading falsely lean, causing the ECU to over-fuel to compensate — this is
the exact mechanism behind `RESEARCH.md` §9's "SAI corrupts AFR readings
on a dyno." With the plumbing physically removed (no air actually being
injected any more, solenoid clicking into nothing), this interaction is
already eliminated regardless of what the software flag says.
## Practical: silencing a removed SAI solenoid with a resistor (Aug 2026)
For anyone who's already pulled the SAI plumbing (valves/hoses) and just
wants the leftover solenoid clicking to stop, without touching the ECU:
The ECU doesn't know or care whether it's driving a real solenoid coil or a
plain resistor — it only checks that the circuit shows plausible
resistance/current when it commands the output. Two resistor values show up
in the community as working substitutes for the solenoid itself:
| Resistor | Wattage | Notes |
|---|---|---|
| 50 Ω | **10 W** (must be this high, or it overheats) | Closer match to the solenoid coil's actual current draw |
| 470 Ω | 0.5 W | Simpler/smaller part, most commonly recommended, plenty of margin |
[triumphrat.net: Air injection solenoid replacement resistor needed](https://www.triumphrat.net/threads/air-injection-solenoid-replacement-resistor-needed.629554/)
Procedure: disconnect the battery negative terminal first (working on
ECU-monitored wiring), unplug the solenoid from the harness connector
(leave the harness-side connector), wire the resistor across the two
harness-side pins that used to feed the coil (push-fit into the connector
pins for a quick fix, or crimp/solder + heat-shrink for something
weatherproof/permanent), reconnect the battery, clear any DTC.
This is purely an electrical placebo for the ECU's continuity check — no
functional link to fueling, and separate from the SAI *software* enable
flag (`0x53801`), which per the earlier finding is about warning-light
suppression, not actuator behavior. A bare disconnected plug (no resistor)
*will* throw an open-circuit DTC; a resistor avoids that without needing the
software flag at all. The two are complementary, not substitutes — see next
section for why you likely still want the flag too.
## Dyno data: exhaust/intake stages, quantified (TTP, 865 EFI twin)
Triumph Twin Power publishes an actual dyno comparison for this engine family
that answers "how much does each stage actually gain":
| Stage | Mods | Peak power | Peak torque | Notes |
|---|---|---|---|---|
| Stock | SAI removed only | 60.64 BHP | 46.84 ft-lb | torque dip 3500–5500 rpm |
| Stage 1 (Tune 1) | Venturi/performance intake **cover** (airbox *not* fully removed) + TORS exhaust + matching TTP tune | 64.06 BHP (**+5.6%**) | 50.78 ft-lb (**+8.4%**) | max torque +15.9% @ 4200 rpm; balanced midrange |
| Stage 1.5 (Tune 2) | Stage 1 + **airbox internal baffle removed** (shell kept) + TORS + matching tune | 63.40 BHP (+4.5%) | 51.91 ft-lb (**+10.8%**) | max torque +16.8% @ 4200 rpm |
| **Stage 1.5 + 2-1 (Tune 2, 2-1)** | Stage 1.5 (baffle removed, airbox shell kept) + **2-1 exhaust system** + matching tune | **69.02 BHP (+13.8%)** | **54.38 ft-lb (+16.0%)** | **max torque +26.6% @ 4100 rpm** — closest published data point to a bare Arrow-2-1 + baffle-removal build |
| Stage 2 (Tune 12) | **Full airbox removal** + pod filters + short free-flow silencers + matching TTP tune | 69.31 BHP (**+14.3%**) | 54.14 ft-lb (**+15.6%**) | max torque +21.0% @ 4300 rpm; more top-end, less mid vs Stage 1.5+2-1 |
[triumphtwinpower.com: EFI Model Comparison](https://www.triumphtwinpower.com/triumph-twin-power-torque-model-comparison.php),
[triumphtwinpower.com: Breathe Evolution](https://www.triumphtwinpower.com/triumph-twin-power-breathe-evolution.php),
[triumphtwinpower.com: Bonneville/Thruxton airbox & exhaust tuning](https://www.triumphtwinpower.com/triumph-bonneville-thruxton-airbox-exhaust-tuning.php) (Aug 2026 addition — the Stage 1.5+2-1 row, closest published match to a 2-in-1 exhaust + baffle-only airbox mod, found via `triumph-twin-power-x-files.php`)
Key takeaway: **exhaust + intake cover + matched tune alone is real but
modest** (~5–8%); **baffle removal alone adds more torque than power** (Stage
1.5's torque gain nearly matches full removal, its power gain doesn't);
**pairing baffle removal with a 2-1 exhaust gets within a rounding error of
full airbox removal** (69.02 vs 69.31 BHP, 54.38 vs 54.14 ft-lb) —
i.e. per this data, **you may not need to go all the way to full pod-filter
airbox removal once a 2-1 exhaust is already fitted; the lighter baffle-only
mod gets nearly all of the same gain.** In all cases the number that matters
is "matched tune," not the hardware alone — TTP's own comparison doesn't show
standalone gains without their tune paired to each stage.
Their "Breathe Evolution" intake cover (a snorkel/cover swap, not full
removal) claims to track full pod-filter airbox removal almost exactly up to
~6000 rpm, with full removal only pulling ahead above that — i.e. most of the
"lose the airbox" gain is available without fully deleting it, up until
you're spending real time above 6k rpm.
**Airbox internal baffle removal — mechanical procedure**, per TTP's own
guide: 1–1.5 hours, requires removing seat, rear mudguard, side covers, air
intake, battery, and fuse box to access and slide out the baffle from the
airbox's right side. Tools: 3/4/5mm Allen keys, T30 Torx, large flat/cross
screwdrivers, 8/10mm sockets/spanners. **Warning specific to carbureted
bikes** (not this EFI bike, but worth knowing if cross-referencing): a
brittle sensor clip breaks easily during removal on carb models. The guide
itself doesn't address any fuel-map/ECU implications of the baffle removal —
purely a mechanical how-to, tuning is treated as a separate step (their own
tune, in TTP's case).