Mark device-flag confidence honestly (SAI confirmed, O2 probable)

The NO-SAI-NO-O2 reference map bundles SAI + O2 + airbox deletes, so it validates
the three flag bytes as a GROUP but doesn't isolate O2 individually; no single-mod
map exists and the x.a() device-layout branch for this ECU is too nested to trace.

- SAI @ 0x53801: confirmed (code lc() -> Devices[0] via fe[33], + the delete map).
- O2 @ 0x53818/0x53819: probable (2 O2 sensors declared off <-> 2 adjacent bytes
  cleared; 865 has no air-flap so airbox removal is fuel-only).

Viewer now shows confirmed/probable badges and a warning that flags alone are not
a tune: O2 delete forces open-loop and needs fuel enrichment, so prefer flashing a
complete matching delete map over hand-toggling a stock one. See DEVICES.md.
This commit is contained in:
2026-08-11 08:16:22 -05:00
parent eaa804fc35
commit 80c9373ded
4 changed files with 53 additions and 19 deletions

View File

@@ -45,8 +45,24 @@ checksum is computed at flash time and is out of scope for the read/edit tool.)
## Confidence ## Confidence
- Flag **locations** (0x53801 / 0x53818 / 0x53819) and semantics (1/0): **validated** - **SAI = 0x53801: ~90% (high).** Two independent confirmations: the device-name
against a real NO-SAI-NO-O2 map. logic in `l.java` `lc()` resolves `Devices[0]=SAI` via `fe[33]` to exactly
- SAI-vs-O2 **labeling** of the three bytes: strong (order + delete semantics); 0x53801, AND the real NO-SAI map cleared precisely that byte.
final SAI-only-vs-O2-only separation would need a single-delete reference map or - **O2 sensors = 0x53818 / 0x53819: ~80% (probable).** The map declares "NO O²
a DTC/bench check. 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.

View File

@@ -103,9 +103,9 @@ def _extract_romdefs(args) -> dict:
# Validated against a NO-SAI-NO-O2 reference map (see research DEVICES.md). # Validated against a NO-SAI-NO-O2 reference map (see research DEVICES.md).
"deviceFe": 33, "deviceFe": 33,
"devices": [ "devices": [
{"name": "SAI (Secondary Air Injection)", "rel": 0x00}, {"name": "SAI (Secondary Air Injection)", "rel": 0x00, "confidence": "confirmed"},
{"name": "O2 sensor", "rel": 0x17}, {"name": "O2 sensor 1", "rel": 0x17, "confidence": "probable"},
{"name": "O2 sensor (2)", "rel": 0x18}, {"name": "O2 sensor 2", "rel": 0x18, "confidence": "probable"},
], ],
} }

View File

@@ -128,13 +128,19 @@
<div style="overflow:auto"><table id="tgrid" class="mono" style="font-size:11px"></table></div> <div style="overflow:auto"><table id="tgrid" class="mono" style="font-size:11px"></table></div>
<div class="card" id="tdevices" style="margin-top:16px;max-width:520px"> <div class="card" id="tdevices" style="margin-top:16px;max-width:520px">
<h3>Device flags <span class="badge">Map A</span></h3> <h3>Device flags <span class="badge">Map A</span></h3>
<div class="note">Toggle emissions/hardware devices. Validated against a real <div class="note">Emissions/hardware device flags (1=on, 0=off).
NO-SAI-NO-O2 map. Uncheck to delete; then Export the edited map.</div> <span style="color:var(--ok)">SAI = confirmed</span>;
<span style="color:var(--target)">O2 = probable</span> (validated as a group vs a
real NO-SAI-NO-O2 map, but not individually isolated).</div>
<div id="tdevlist"></div> <div id="tdevlist"></div>
<div class="hint" style="margin-top:10px;color:var(--hot)"><b>⚠ Flags alone are not a tune.</b>
Disabling O2 forces open-loop — the bike runs only on the base fuel map. On a stock map that
can run lean/rough. A proper delete pairs flags-off with fuel enrichment. Prefer flashing a
complete, matching delete map over hand-toggling a stock one.</div>
<button id="tdevExport" class="chip" style="border-color:var(--ok);color:var(--ok);margin-top:10px">⭳ Export edited .hex</button> <button id="tdevExport" class="chip" style="border-color:var(--ok);color:var(--ok);margin-top:10px">⭳ Export edited .hex</button>
<span class="count" id="tdevdirty"></span> <span class="count" id="tdevdirty"></span>
<div class="hint" style="margin-top:8px">Export re-encodes the map's distribution format. <div class="hint" style="margin-top:8px">Export re-encodes the distribution format only; the ECU-flash
The separate ECU-flash checksum is applied by the flashing tool at write time.</div> checksum is applied by the flashing tool at write time.</div>
</div> </div>
</div> </div>
</section> </section>
@@ -381,7 +387,10 @@ else {
const on=TA.rom[d.off]!==0; const on=TA.rom[d.off]!==0;
const row=document.createElement('label'); const row=document.createElement('label');
row.className='item'; row.style.cursor='pointer'; row.className='item'; row.style.cursor='pointer';
row.innerHTML=`<input type="checkbox" ${on?'checked':''}> <span>${d.name} const badge=d.confidence==='confirmed'
? '<span class="badge" style="background:var(--ok)">confirmed</span>'
: '<span class="badge">probable</span>';
row.innerHTML=`<input type="checkbox" ${on?'checked':''}> <span>${d.name} ${badge}
<span style="color:var(--dim)">· 0x${d.off.toString(16)} = ${TA.rom[d.off]}</span></span>`; <span style="color:var(--dim)">· 0x${d.off.toString(16)} = ${TA.rom[d.off]}</span></span>`;
row.querySelector('input').onchange=e=>{ row.querySelector('input').onchange=e=>{
setDeviceByte(TA, d.off, e.target.checked?1:0); setDeviceByte(TA, d.off, e.target.checked?1:0);

File diff suppressed because one or more lines are too long