# Flash procedure — Arrow 2-1 + SAI/O2 delete Pull this up offline, no signal needed. Written 2026-09-08 for the Lonelec OBD2 adapter attempt. Checksum re-verified valid immediately before writing this doc — `computed=748a stored=748a MATCH`. ## 0. The file **`tunie/research/reference-maps/derived/20262-arrow-delete-composed.hex`** - Base: `20262`, TuneECU's own official Arrow 2-in-1 calibration. - SAI + both O2 sensors disabled (device flags). - Two idle-mixture (Idle Fuel Trim/CO) bytes corrected toward richer. - Flash checksum patched and verified valid. - **What it is NOT**: the main VE fuel tables (the ones governing fueling across the rev range) are untouched stock-Arrow calibration. This is the correct, safe starting point — not a finished tune. Expect a wideband pass later, not perfection today. - Safe to flash regardless of whether the O2 sensors are physically installed or removed — SAI/O2-off is a software flag the ECU obeys either way (see prior session notes if you want the full reasoning). ## 1. Preconditions — confirm every one before connecting - [ ] Battery tender/maintainer connected (real smart tender, not a bare trickle charger). - [ ] **Phone plugged into a charger and staying plugged in for the entire session** — not just charged beforehand. TuneECU re-checks phone battery live at the moment you tap reprogram (must be ≥16%, or 0%/failed-read, which also passes); a mid-session drain is what most likely blocked a prior attempt, independent of the bike itself. - [ ] **Pull the headlight AND taillight fuses** — reduces electrical load during the write, which matters more here than for a plain read: a genuine ECU-side busy/reject (KWP negative response, NRC 0x21 `busyRepeatRequest`) is a real failure mode tied to voltage sag *under load*, not resting voltage. Fuse numbers are bike-specific, check the fusebox cover. - [ ] **Ignition on, engine off, kill switch in RUN position — confirmed root cause (2026-09-09).** The "Unable to open programing session (Battery low?)" / `ERR_PSESSION` error chased at length in an earlier session turned out to be caused by the **kill switch being in the OFF position**, not battery voltage, not the cable. Check this first, before anything else on this list, if the error recurs — it's the simplest and now-confirmed explanation. - [ ] Lonelec adapter connected and confirmed talking (see Step 2). - [ ] No other app/process holding the adapter's serial/BT channel. ## 2. Confirm the link before touching anything programming-related Same principle as every prior session: prove the link is alive with the lightest possible check before risking a real operation. - Open TuneECU, connect via the Lonelec adapter, and get to a normal **live diagnostics / read** screen first. Confirm you can read ECU ID and current map info cleanly — this is the same "read" capability that already worked with the old Bluetooth vLinker adapter, so it's a low bar, not the real test. - If diagnostics don't come up clean, stop here. Don't proceed to programming on a link that hasn't proven itself first. ## 3. Read/backup the current map before writing anything - Use TuneECU's own **Read Map** to pull the bike's current calibration and save it locally. This is your rollback reference and also confirms end-to-end read capability on this exact adapter before you ever risk a write. - Note the map ID it reports — should be a stock production/aftermarket ID (20187/20191 family) unless it was already flashed. ## 4. Load the tune file - In TuneECU, open **`20262-arrow-delete-composed.hex`** (the file from Step 0). - Before writing, visually confirm in the app's map-info display: - SAI: **off** - O2 Sensor / O2 Sensor (2): **off** - Checksum: should show valid (not flagged `*No-OEM`/`Error`) — if it does show an error here despite our own `checksum.py` confirming valid, stop and re-verify rather than overriding it. ## 5. Reprogram - Tap reprogram. Expect TuneECU's standard confirmation dialogs (write-caution / void-warranty) — confirm through them, that's normal. - **Do not disconnect the adapter, close the app, let the phone sleep, or turn off ignition once the write actually starts.** A programming session interrupted mid-write is the one genuinely bad outcome here — everything upstream of this point has been reversible; this step is not. - Watch for the "Battery low?" / `ERR_PSESSION` message specifically — **check the kill switch is in RUN first** (confirmed root cause, see Section 1). If it recurs with the kill switch already correct, new adapter, phone charging, and fuses pulled, that's when to check bike voltage *under load* (multimeter clipped on during the attempt) rather than assume it's the same cable issue as before. - Let it run to completion. Do not interrupt for anything short of a genuine emergency. ## 6. After a successful write - Read the map back and confirm the ID/checksum match what you just flashed. - Check DTCs — some may appear immediately after a flash and clear themselves on the next few ignition cycles; don't panic at one DTC right after writing. - Idle the bike, listen/watch for anything obviously wrong (stalling, extreme richness/leanness, warning lights) before riding it anywhere. - Turn ignition off, remove the tender, reinstall the fuses you pulled. ## 7. If the write fails partway through - **Do not panic-disconnect further.** Per our own `RECOVERY_MODE.md` research: TuneECU has a dedicated Recovery function specifically for this — same underlying mechanism as a normal reprogram, gated by whether the currently-loaded file decodes as valid (not by live ECU state). If TuneECU offers "Run the ECU Recovery?", that's the expected, designed-for path — not a sign everything is lost. - If recovery also fails to reach the ECU at all: this is exactly the scenario `v-ladimir/audprog` (AUD debugger, SH705x un-brick via PCB debug pins) exists for — a real, known backstop, not guesswork. Not needed unless recovery mode itself can't establish contact. ## Quick reference — exact paths ``` Tune file: tunie/research/reference-maps/derived/20262-arrow-delete-composed.hex Checksum verify (if you want to re-check locally before flashing): cd tunie/research/reference-maps /Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10 checksum.py derived/20262-arrow-delete-composed.hex ```