Skip to content

Releases

Beta v0.4.3

Choose a tag to compare

@github-actions github-actions released this 17 Oct 20:26

🚀 sh705x-emu Beta v0.4.3 — compare two flashes, change a map and watch the firmware use it; GDS2 sees live data

The map browser learns what calibration editors do: compare this flash with another file,
copy or save a map, and change a cell. The change goes into the emulated ECU, and its next
lookups use it. The J2534 DLL now delivers the frames GDS2's Data Display streams on.

Context: four changes on top of 0.4.2, checked against the Astra J's own flash
(A17DTJ, Denso, SH7059, NCLSW420AX36), and with GDS2 in a virtual machine.

Deliverables:

  • sh705x-v0.4.3-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 9, versionName
    0.4.3. Signed with the same key as 0.3.x and 0.4.x, so they install over them.
  • sh705x_j2534_x86.dll and sh705x_j2534_x64.dll with register.ps1.

No firmware comes with any of them.


1. Comparing with another flash

  • "Compare with a flash…" reads a second image from your disk. Each map is read from
    the same descriptor in both files; maps whose cells live in RAM, or whose shape differs
    in the other file, are marked as not comparable.
  • The list marks each map that differs with its changed-cell count (Δ100), and the
    filter DIFF keeps only those.
  • "Differences" shows each cell as this → other, coloured by the size of the change,
    with the count and the largest change above.
  • The other file is kept only in memory; "Stop comparing" drops it.

2. Copying and saving a map

  • "Copy" puts the map on the clipboard as tab-separated text, axes included, ready for
    a spreadsheet. "Save CSV…" writes the same with commas.

3. Changing a map in the emulated ECU

  • In "Table", click a cell, type the value in physical units and press Set (or
    Enter). It is encoded in the map's own format: float, or 8/16 bits with the descriptor's
    scale and offset. A value out of range is refused, and the limits are shown.
  • It is written to the emulated flash and, when the firmware reads that map from a RAM
    copy, to that copy too. The maps shown and the lookup checks are re-read, so no false
    "mismatch" appears.
  • Changed cells are underlined. "Revert this map" puts back the loaded flash's bytes.
    "Save flash as…" writes the image with the changes. Its checksum is not recomputed:
    it is for the emulator and for study, not for an ECU.
  • Checked end to end on the Astra's flash: with the boost target (0x9DADC) raised
    10 % while idling, each later lookup returns exactly the changed map's interpolation
    (test a_changed_map_is_what_the_firmware_reads, which runs when SH705X_FLASH is set).
  • Only the emulator's memory changes. Nothing is sent to a car.

4. J2534: GDS2's Data Display streams live

  • GDS2 opens an ISO 15765 channel with a flow-control filter for the ECU's replies and a
    pass filter for 0x5E8, where the ECU streams the periodic data it was asked for.
    Those frames are single CAN frames outside any flow-control pair, and the DLL dropped
    them, so GDS2 reported lost communication. Raw frames that only a pass filter claims are
    now delivered. GDS2's Data Display then shows the emulated engine's parameters live, at
    1000 rpm as set in the emulator.

5. Smaller fixes

  • A map the whole-ROM scan finds no master call for, but which the firmware does look up,
    is no longer called "unused" nor dimmed in the list. The scan misses it because the
    firmware reaches it another way.
  • Reading a map from a descriptor that points near the end of the address space no longer
    overflows in debug builds.

6. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.4.2; same key, same data. The in-app updater offers it. The
    map changes in §1–§3 are in the Windows window only this time.
  • J2534: replace the DLLs and run register.ps1 again as administrator. The DLL file
    names did not change.

Checked against an Opel Astra J 1.7 CDTI (A17DTJ) in the emulator and with GDS2. Windows
programs built by the release workflow from the tagged commit, checked to import no Visual
C++ runtime. Release APKs built from the tagged commit and signed with the same key as
0.3.x and 0.4.x (certificate SHA-256 5ff00c0a…f515c2).

Beta v0.4.2

Choose a tag to compare

@github-actions github-actions released this 16 Oct 16:54

🚀 sh705x-emu Beta v0.4.2 — the replay drive, corrected; a whole-ROM map scan; and a J2534 door

A fix to replay so the turbo vanes follow the car instead of their stop; a scan of the
whole ROM for every map and curve; and a J2534 pass-thru DLL so GDS2 and other Windows
diagnostic tools talk to the emulated ECU as if through a real adapter.

Context: five changes on top of 0.4.1, checked against the Astra J's own flash
(A17DTJ, Denso, SH7059, NCLSW420AX36) and a drive recorded from the car.

Deliverables:

  • sh705x-v0.4.2-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 8, versionName
    0.4.2. Signed with the same key as 0.3.x, 0.4.0 and 0.4.1, so they install over them.
  • sh705x_j2534_x86.dll and sh705x_j2534_x64.dll with register.ps1: the J2534
    pass-thru DLL for 32-bit tools (GDS2) and 64-bit ones.

No firmware comes with any of them.


1. replay drives the turbo right

  • The plant builds manifold pressure as resting pressure + the turbocharger's boost.
    replay was feeding it the recorded manifold pressure as the resting value, so the
    boost was counted twice: the firmware saw too much pressure, opened the vanes to their
    stop, and the VGT command sat near 11 % against the car's ~58 %.
  • It now feeds the barometer as the resting pressure, which is what "no boost" means.
    The vanes follow the car: the VGT median error drops from 30.2 % to 4.3 %.

2. Comparing two images, and the per-cell table

  • --compare <other.bin> replays the same route through a second flash and lists only
    the cells where the two images compute a different setpoint — rpm, pedal, setpoint,
    each image's value and the difference — or says they agree everywhere.
  • --out <file.csv> writes the recorded and computed setpoint of every cell.
  • Two more setpoints are read when the route logs them: desired EGR (0x002C) and the
    EGR command (0x32A8).
  • tools/route_cells.py now groups the samples by polling round (a round ends when an
    identifier repeats or more than --round-ms has passed), so each cell is a real
    operating point rather than a stride of rows. Setpoint columns the route never logged
    are left empty.

3. catalog: every map in the ROM, read or not

  • sh705x catalog (and the map browser in the GUI) scans the whole ROM for map and
    curve descriptors and lists them — axes, size, address — whether or not the firmware
    read them during the run. It finds the maps the live view cannot, because nothing has
    touched them yet.

4. j2534: GDS2 and other tools reach the emulated ECU

  • A J2534 (04.04) pass-thru DLL whose "adapter" is the emulator's SM3 (sh705x sm3) over
    TCP. Registered with register.ps1, J2534 applications on the machine — or in a virtual
    machine that reaches it over the network — list it beside real adapters and talk CAN and
    ISO 15765 to the emulated ECU. The vendor's own DLL cannot: it pairs with the physical
    adapter first and takes no address.
  • The DLL finds the SM3 at SH705X_SM3, or server=host:port in
    %ProgramData%\sh705x\j2534.ini, or 127.0.0.1:777.

5. The SM3 opening handshake

  • sh705x sm3 now answers the opening exchange with the same lengths the car's Scanmatik
    gives, so tools that check them accept the emulated adapter.

6. The in-app updater lists the installers

  • The Android updater checked for "install unknown apps" first and, without it, sent you to
    a settings screen — which some phones lock, dead-ending the update. It now offers the
    installer list first: Install With Options (through Shizuku) installs on its own
    authority and needs no such permission. The system installer is asked for only when it is
    the only option.

7. What was measured

On the Astra's flash, the Coruña–Santiago–Cangas route, 87 cells (558 494 samples):

setpoint median |error| p90 |error| constant-guess median
desired rail pressure 3.03 MPa 53.4 MPa 28.05 MPa
desired air mass 1.42 g/s 8.30 g/s 32.70 g/s
VGT 4.32 % 10.97 % 9.02 %
desired boost 17.50 kPa 80.0 kPa 57.69 kPa
torque 35.0 N·m 134.5 N·m 102.25 N·m

Rail pressure, air mass and now VGT land well inside a constant guess: the firmware
explains them. Boost and torque depend on the fuel injected, which is 0 in the emulator
without injection, so they do not match yet.


8. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.4.1; same key, same data. Install this one by hand once:
    phones on 0.4.1 or earlier carry the old in-app updater (§6), which cannot install it on
    a phone that locks "install unknown apps". Open the APK with Install With Options this
    time; from 0.4.2 on, the in-app updater works.
  • J2534: place the two DLLs where you like and run register.ps1 as administrator
    (see its header for the -Dll32/-Dll64/-Server arguments).

Checked against an Opel Astra J 1.7 CDTI (A17DTJ) in the emulator. Windows programs built
by the release workflow from the tagged commit, checked to import no Visual C++ runtime.
Release APKs built from the tagged commit and signed with the same key as 0.3.x, 0.4.0 and
0.4.1 (certificate SHA-256 5ff00c0a…f515c2).

Beta v0.4.1

Choose a tag to compare

@github-actions github-actions released this 14 Oct 15:13

🚀 sh705x-emu Beta v0.4.1 — a recorded drive against the firmware, and standard names

A replay command that drives the firmware through every operating point of a recorded
route and says how far each of its setpoints lands from what the car asked for; the SAE
name for every standard OBD-II PID; and maps grids that say at a glance what they hold.

Context: three additions on top of 0.4.0, checked against the Astra J's own flash
(A17DTJ, Denso, SH7059, NCLSW420AX36) and a 224 000-sample drive recorded from the car.

Deliverables:

  • sh705x-v0.4.1-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 7, versionName
    0.4.1. Signed with the same key as 0.3.x and 0.4.0, so they install over them.

No firmware comes with any of them.


1. sh705x replay

python tools/route_cells.py <route.csv.gz> --out cells.csv
sh705x replay --flash <flash.bin> --eeprom <eeprom.bin> --cells cells.csv
  • tools/route_cells.py (standard library only) bins a recorded route by engine speed
    and pedal travel and keeps the median of each input and setpoint per cell. It turns the
    pedal's sensor 1 into travel with the ECU's own calibration (19.6 % at rest, 70 % at full).
  • replay sets each cell's pedal, coolant, intake air, boost, barometric pressure and
    air mass, lets the firmware settle, and compares five setpoints with the recorded ones:
    desired rail pressure, desired boost, VGT, desired air mass and torque. The cells run in
    parallel, as maps does.

2. Standard PID names

  • A parameter profile is a generic list and can hang another module's label on a low
    identifier. For 0x00–0xFF the emulator now uses the fixed SAE J1979 name instead
    (0x000C → "Engine speed", 0x000B → "Intake manifold absolute pressure").
  • Higher identifiers keep the profile's name. It shows wherever variables are named: the
    maps window on Windows and the maps tab on Android.

3. maps says what a grid holds

  • Under each setpoint: empty, all zero, constant at a value, or the range it spans. "The
    same at every point" now carries the value, so a grid of zeros reads as such.

4. What was measured

On the Astra's flash, a route of 59 cells (223 979 samples, Coruña–Santiago–Cangas):

setpoint median |error| p90 |error|
desired rail pressure 1.89 MPa 32.3 MPa
desired air mass 2.08 g/s 8.30 g/s
desired boost 15.6 kPa 56.9 kPa
VGT 30.2 % 48.6 %
torque 27.0 N·m 80.0 N·m

Rail pressure and air mass follow the car. Boost, VGT and torque depend on the fuel
injected, which is 0 in the emulator without injection, so they do not match yet.


5. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.4.0 (or let the app's update detector find it); same key,
    same data.

Checked against an Opel Astra J 1.7 CDTI (A17DTJ) in the emulator. Windows programs built
by the release workflow from the tagged commit, checked to import no Visual C++ runtime.
Release APKs built from the tagged commit and signed with the same key as 0.3.x and 0.4.0
(certificate SHA-256 5ff00c0a…f515c2).

Beta v0.4.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 21:12

🚀 sh705x-emu Beta v0.4.0 — plugins beside the ECU, and an app that updates itself

WebAssembly plugins that ride the ECU's CAN bus, read the memory they declare and write
RAM, each in a sandbox with a budget per call — installed from a file or from your own
repository, public or private, exactly as opendash does. And an Android app that finds its
own new releases on GitHub and installs them.

Context: the plugin host and the update detector on top of 0.3.2, checked against the
Astra J's own flash (A17DTJ, Denso, SH7059, NCLSW420AX36) and on an Android emulator.

Why plugins: the emulator's CAN bus already lets other nodes answer the ECU
(ADR-0005). A plugin is that node, made
installable: it hears the frames the ECU sends and puts frames back on the bus, so you
can stand in for a module the car talks to without touching the emulator's own code
(ADR-0008). Anything specific to a car stays
in a private plugin repository, out of this one.

Deliverables:

  • sh705x-v0.4.0-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 6, versionName
    0.4.0. Signed with the same key as 0.3.x, so they install over it.

No firmware comes with any of them.


1. The plugins

  • Format: a .wasm carrying a JSON manifest in its sh705x-plugin section. It runs on
    wasmi, with 20 million units of fuel per call, so a plugin that loops forever is stopped
    and the rest of the machine goes on.
  • API 1:
    • send, read, write, log and now_us;
    • init, on_frame (every frame the ECU sends) and tick (every tick_us).
  • Sandbox: a plugin reads only the memory its manifest names (up to 64 KiB) and writes
    only RAM (FFFE_8000..FFFF_C000); any write outside is refused and logged.
  • Sources: install from a file, or from GitHub, GitLab, Gitea or a plain HTTPS index —
    with a per-source token for private repositories, the same URLs and headers as opendash.
  • SDK and example: plugins/sdk (the sh705x-plugin crate, a manifest! macro and
    read/write/log/send helpers) and plugins/abs-node, which stands in for the ABS:
    it sends 0x1E9 every 21.4 ms, and with it the Astra stops reporting U0121 (no ABS).

2. On each platform

  • Windows: a Plugins window — load, enable, see each plugin's log and errors, add a
    source and install from it.
  • Android: a Plugins tab (the 5th), the same, plus loading the enabled plugins at
    power-on. Needs the network permission for remote sources.

3. The app updates itself

  • Ported from opendash: at start-up (you can turn it off) and by hand, under a new
    Updates section, it asks GitHub for the newest release, compares versions by number,
    downloads the APK for the phone's ABI and hands it to the installer.
  • It never interrupts: the dialog does not appear while the ECU is running.

4. What was measured

  • With the Astra's flash and EEPROM, no node, 8 s of idle: U0121 is reported. With the
    abs-node plugin: no U0121; it hears 3250 frames in 5 s and reads 750 rpm.
  • A write outside RAM is refused and logged; a plugin looping in tick is stopped, the
    others keep running.
  • A private GitHub source serves its index with a token and gives a helpful 404 without one.
  • On the Android emulator: install from a file, from an HTTPS source, load at power-on
    across a power cycle; the update detector found a newer release, downloaded its APK and
    requested the install permission.

5. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.3.x; same key, same data.

Checked against an Opel Astra J 1.7 CDTI (A17DTJ) in the emulator, and on a Pixel Android
emulator (API 36, x86_64). Windows programs built by the release workflow from the tagged
commit, checked to import no Visual C++ runtime. Release APKs built from the tagged commit
and signed with the same key as 0.3.x (certificate SHA-256 5ff00c0a…f515c2).

Beta v0.3.2

Choose a tag to compare

@github-actions github-actions released this 12 Oct 20:59

🚀 sh705x-emu Beta v0.3.2 — the condition 65 fault codes share

The Astra's condition 0, which 65 of its fault codes need before their results count, read
from the firmware and described on each code that needs it. On Windows and on Android.

Context: one commit on top of 0.3.1, checked against the Astra J's own flash
(A17DTJ, Denso, SH7059, NCLSW420AX36).

Theme: 0.3.1 showed which of a code's conditions are met; this one says what the most
common of them is. It is the ECU's go-ahead for its electrical tests: the ignition on, the
battery in range and the start-up over. Without it, a low battery would read as sensor
circuits out of range.

Deliverables:

  • sh705x-v0.3.2-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 5, versionName
    0.3.2. Signed with the same key as 0.3.1, so they install over it.

No firmware comes with any of them.


1. Condition 0

65 of the Astra's 202 codes need it, and 36 need nothing else. They are mostly the circuit
high and low tests of the sensors:

  • the MAF, the coolant and intake temperatures;
  • the pedal, the boost and barometric pressures;
  • the rail pressure, the fuel temperature and level;
  • the EGR position, the 5 V references;
  • the exhaust temperatures, the DPF pressure sensor (P2455 among them).

The flag is set when all three of these hold:

  1. The battery between 10 and 16 V. With 1 V of hysteresis: it comes in between 11 and
    15 V, and drops out under 10 or over 16. Measured: started at 9.5, 10.5, 15.5 or 16.5 V
    it is never met; at 12 or 14 V it is.
  2. The ignition on, and the start-up over:
    • The ignition: input AN14 after a 4.01 divider, on above 4.5 V and off below 4.0,
      two readings alike in a row, held a few runs after it drops.
    • The start-up: 56 runs in a row, about 0.8 s, after the start-up routine sets
      port D's PD4.
  3. A third part that is always met on this calibration: it waits for a flag or for the
    engine turning, but both its delays are calibrated to 0.

At idle, and with the ignition on and the engine still, it is met 1.06 s after power-on.


2. In the emulator

  • Each code that needs condition 0 says what it is, beside whether it is met now (as
    condition 1 already did for P0101).
  • Tests:
    • it is met once the DPF fault has been provoked;
    • with the battery at 9.5 V it is never met.

3. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.3.1; same key, same data.

Checked against an Opel Astra J 1.7 CDTI (A17DTJ): its flash at warm idle and with the
ignition on in the emulator, the battery set from 9.5 to 16.5 V, the flag's writes watched.
Windows programs built by the release workflow from the tagged commit, checked to import no
Visual C++ runtime. Release APKs built from the tagged commit and signed with the same key as
0.3.1 (certificate SHA-256 5ff00c0a…f515c2).

Beta v0.3.1

Choose a tag to compare

@github-actions github-actions released this 12 Oct 19:47

🚀 sh705x-emu Beta v0.3.1 — why a failing test is not yet a fault

The fault codes page now tells the tests the ECU counted from those it threw away, and
which of a code's conditions are met. The fault code tables are also found in the flash
from its code rather than looked up by calibration. On Windows and on Android.

Context: one commit on top of 0.3.0, checked against the Astra J's own flash
(A17DTJ, Denso, SH7059, NCLSW420AX36).

Theme: in 0.3.0, P0101's test failed at every run at idle and the code never went
pending. This version shows why: the ECU only counts a code's results while its
conditions are met, and P0101's need 1500 to 4000 rpm among others.

Deliverables:

  • sh705x-v0.3.1-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 4, versionName
    0.3.1. Signed with the same key as 0.3.0, so they install over it.

No firmware comes with any of them.


1. The headline

0.3.0 0.3.1
A code's tests how many ran and failed and how many the ECU counted
Its conditions — each one, and whether it is met now
The tables known for the Astra's calibration only found from the code, on any flash laid out the same way

2. Counted or thrown away

  • The conditions: every test reports through one routine. That routine only passes the
    result on to the one that counts it (the routine that reads tables A, B and C) when the
    code's conditions are met. A code lists up to three, each a flag in RAM.
  • What the emulator shows: it probes the counting routine as well, so each code shows
    how many of its results counted, and its conditions as they are now: met or not.
  • P0101 at idle:
    • its test compares the air per stroke, brought to 25 °C and 101.325 kPa, with two maps
      over engine speed;
    • at idle it is under the lower limit and the test fails; at 2000 rpm it passes;
    • its results only count while condition 1 is met: 1500 to 4000 rpm, five other
      quantities under their limits and condition 0 met, 125 times in a row;
    • so at idle it fails and is never counted.

3. The tables, found

The fault code tables are no longer a constant for one calibration:

  • The counting routine: a function that loads three tables of n words one after
    another (A, B and C).
  • The reporter: the routine that calls it, called from many places with a constant
    index under n.
  • The codes: the table of n words that looks like codes and is loaded from the most
    places.
  • The reactions and the conditions: tables loaded by routines the reporter calls.

On the Astra's four dumps (the original, two workshop files and a later read) it finds
exactly what this project found by hand, in about 56 ms. It still does with half the codes
disabled. No other calibration has been tried: on one laid out differently it may find
nothing, and the page says so.


4. The rest

  • Screenshots: the faults page on Windows and on Android, and the Android
    oscilloscope with its time axis as the code now draws it.
  • Tests:
    • the layout found on the Astra's flash, also with codes disabled, and none on a flash
      without the code;
    • P0101 failing at idle, uncounted, condition 1 not met and 2 met;
    • P2455 counted once its fault is provoked.
  • CI builds and tests both, as before.

5. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.3.0; same key, same data.

Checked against an Opel Astra J 1.7 CDTI (A17DTJ): its flash at warm idle in the emulator,
and at 2000 and 2500 rpm with the plants held. Windows programs built by the release workflow
from the tagged commit, checked to import no Visual C++ runtime. Release APKs built from the
tagged commit and signed with the same key as 0.3.0 (certificate SHA-256 5ff00c0a…f515c2).

Beta v0.3.0

Choose a tag to compare

@github-actions github-actions released this 12 Oct 18:25

🚀 sh705x-emu Beta v0.3.0 — fault codes live, and an oscilloscope on the pins

The calibration's fault codes with their tests running live, and an oscilloscope on the
ECU's pins: the inputs, the PWM outputs and the injector channel, held on an edge and
measured. On Windows and on Android.

Context: two commits on top of 0.2.0, checked against the Astra J's own flash
(A17DTJ, Denso, SH7059, NCLSW420AX36).

Theme: 0.2.0 showed what the firmware reads; this one shows what it tests and what
it drives. A fault code is no longer just a line on a scan tool: you see its test run,
fail, and become the code the ECU reports, and the maps that test reads. And the PWM the
firmware computes is no longer a percentage: it is a waveform on a time base.

Deliverables:

  • sh705x-v0.3.0-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 3, versionName
    0.3.0. Signed with the same key as 0.2.0, so they install over it.

No firmware comes with any of them.


1. The headline

0.2.0 0.3.0
Fault codes the ones the ECU reports, over OBD all 202, enabled or not, each test live
A code's test — how often it runs, how often it fails, where, which maps it reads
Stopping on a code — "Stop at its next test"
The ECU's outputs duty percentages in the engine view waveforms, on 10 µs to 50 ms a division
Measuring a pin — frequency, period and duty per channel, an edge trigger, a cursor

2. Fault codes, live

  • From the flash: on the Astra's calibration the table holds 202 codes (194 enabled).
    Each comes with:
    • its tables A, B and C (A and C both 0 disable a code, as a workshop file does);
    • what the ECU does while it is active (raising the idle, among others).
  • Their tests, probed: every test reports through one routine, with the code's index
    and its result (0 passed, 1 failed). The emulator probes it alongside the maps and
    counts, per code, the tests, the failures, the last result and where it was tested
    from.
    • At idle 193 of the 202 are tested.
    • With the DPF sensor at the top of its range, P2455's test starts failing and the ECU
      reports the code.
  • Where each is tested: the function that reports it, read from the code, and the maps
    that function reads, each a link to the map. For example, P0101 (MAF range or
    performance) reads two.
  • "Read the codes" asks the ECU for its confirmed (03) and pending (07) codes.
  • "Stop at its next test" stops where the firmware next reports that code's test.
  • Descriptions: the emulator brings them for the codes this project has met, in its
    own words, and your own file can add the rest.

3. An oscilloscope on the pins

  • Inputs (crank, cam, MAF): every edge at the cycle the chip took it.
  • PWM outputs of ATU-II channels 6 and 7 (SCV, throttle, VGT, swirl flaps, EGR): drawn
    from the timer's counter, period and duty. Exact between register changes, which are
    placed when the emulator next looks (half a millisecond at most in real time).
  • The one-shot outputs of channel 8, where the injectors are: each pulse, exact.
  • Controls:
    • time base from 10 µs to 50 ms a division;
    • a trigger on either edge of any channel (auto, normal or single, with how much comes
      before it);
    • hold, and a cursor that reads the time from the trigger;
    • each channel's frequency, period and duty.

At idle on the Astra:

Signal Measured Check
Crank 750 Hz, 50 % 60 teeth at 750 rpm
SCV 250 Hz, 53.5–54.8 % the duty its registers give
VGT 300 Hz —
EGR opening drive 200 Hz —

4. On Windows and on Android

  • Windows: "Scope" opens the oscilloscope, and the maps window has a second page,
    "Fault codes".
  • Android: two new tabs, "Faults" and "Scope". The scope's traces come first and the
    controls below them.

5. The rest

  • Tests for the new parts:
    • the code table and its reports against what this project found by hand;
    • a provoked fault seen tested, reported and stopped at;
    • PWM traces and their measures, on a synthetic waveform and on the Astra's SCV;
    • the windows and the app's frames drawn and read.
  • A bug the tests caught: a PWM period that had started before cycle 0 overflowed. It
    is worked out signed now.
  • CI builds and tests both, as before.

6. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.2.0; same key, same data.

Checked against an Opel Astra J 1.7 CDTI (A17DTJ): its flash at warm idle in the emulator,
with a fault provoked on the DPF sensor. Windows programs built by the release workflow from
the tagged commit, checked to import no Visual C++ runtime. Release APKs built from the tagged
commit and signed with the same key as 0.2.0 (certificate SHA-256 5ff00c0a…f515c2).

Beta v0.2.0

Choose a tag to compare

@github-actions github-actions released this 12 Oct 02:17

🚀 sh705x-emu Beta v0.2.0 — the calibration maps, as the firmware reads them

Every map the ECU reads, drawn whole from its own descriptor, with where the firmware is
on it right now, where each of its inputs comes from and where its result goes: on
Windows and on Android, live, in slow motion, or a lookup at a time.

Context: four commits on top of 0.1.0, checked against the Astra J's own flash
(A17DTJ, Denso, SH7059, NCLSW420AX36).

Theme: 0.1.0 let you watch the engine; this one opens the calibration. A remap tool
shows a map as a table; here you see the firmware read it: which cell, from which line
of code, with which variables, and what it does with the result.

Deliverables:

  • sh705x-v0.2.0-beta-windows-x86_64.zip: sh705x-gui.exe and sh705x.exe, which
    carry their own C runtime.
  • app-arm64-v8a-release.apk and app-x86_64-release.apk: versionCode 2, versionName
    0.2.0. Signed with the same key as 0.1.0, so they install over it.

No firmware comes with any of them, and no catalogue of names either: those you
load from your own files.


1. The headline

0.1.0 0.2.0
Calibration maps listed by sh705x touched, on the command line drawn live in the window and the app: heat map, surface, table, curve
Where the firmware is on a map — the cell it reads, now, and the trail of its last lookups
Where a value comes from — each input traced to a variable, a routine or another map
Names — the sensors found by moving them; an opendash profile read at run time
Stopping on a map a breakpoint by hand "Stop at its next lookup"

2. Every lookup, without stopping the ECU

Denso firmware reads its maps through a few interpolation routines that take the map's
descriptor in R4 and its inputs in FR4 and FR5, and return the result in FR0. The
emulator now:

  • finds those routines in the flash by itself, by counting which call targets get a
    valid descriptor: on the Astra, 0x7128 (3D) and 0x70B4 (2D), the same the map
    catalogue's Ghidra tools found;
  • probes them without stopping the machine: every call is recorded with its
    registers on the way in and FR0 on the way out. With the maps open it runs about 6 %
    slower (1.23 → 1.16 times real time, best of six runs each); closed, the run loop is
    the same as before;
  • reads each map from its own descriptor, in physical units: sizes, axes, the cell
    type (float, u8, u16, s8, s16) and the scale and offset it carries.

Checked: at idle the Astra reads 594 maps, all decoded, and on all 18 352
lookups
of half a second the result the firmware gets is exactly the decoded map's
interpolation.


3. Where each value comes from

For each place a map is read from, the code around the call is read: back from the call
to where each input register was loaded, and forward to where the result is stored. An
input is a variable in RAM, the result of a routine (the engine speed), or the result of
another map, which becomes a link to it; and each map lists the maps that read what it
gives.

Checked live: stopped at 5000 real lookups across 616 call sites, 2617 of the 2625
variables named as an input hold exactly the value the firmware passes
(99.7 %). The
others are routine results (mostly the engine speed) or other maps: the chain from
"fuel → torque" (09CEB8) into the next map shows up on its own.


4. Names

  • With the emulator: what this project found in the Astra's calibration (the engine
    speed routine, the torque and fuel asked, the setpoints of the engine view), used only
    when the flash is that calibration.
  • "Find the sensors": every sensor is moved one way and the other for a moment, and
    the variables that follow it in all three states take its name: 16 sensors on the
    Astra. The 5 V references and the oil switch are left alone, and the engine is put
    back: it idles where it did and no fault is left behind (checked).
  • "Read an opendash profile…": a parameter profile (opendash's profiles.txt); the
    emulated ECU is asked for each identifier in three engine states, and the variable that
    holds the answer every time takes its name. Checked against two this project found
    another way: Desired Fuel Rail Pressure lands on FFFEF924 and Torque Delivered on
    FFFEFC4C. Parameters that read 0 without injection cannot be placed.
  • "Read map labels…": labels by descriptor.

Profiles and labels are read from your disk at run time and never kept with the
emulator
: such catalogues are often someone else's data.


5. On Windows

"Maps" opens a window with the list (filter by address, name or 2D/3D; follow the latest
lookup), the map in four views, its call sites as links into the code view, and "Stop at
its next lookup", which runs the ECU and stops where the firmware next reads that map, to
go on an instruction or a tooth at a time.

6. On Android

A "Maps" tab beside the engine: the same list, the map as a heat map (tap a cell for its
value), a surface turned with a finger, a table or a curve, where each value comes from,
the names, and "Stop at its next lookup". The maps are traced only while the tab is open.


7. The rest

  • Tests for the new parts: the probes on a hand-written program; descriptors read and
    refused; the masters, the decoding and the call sites checked against the Astra's
    flash; a stop at one map passing all the others; naming that leaves no fault; the map
    window drawn in every view; the app's map layout on the JVM.
  • CI builds and tests both, as before.
  • The repository is public, under GPL-3.0-or-later.

8. Upgrading

  • Windows: unzip over the old folder.
  • Android: install over 0.1.0; same key, same data.

Checked against an Opel Astra J 1.7 CDTI (A17DTJ): its flash, at warm idle in the
emulator, and its own diagnostic answers for the profile's identifiers. Windows programs
built by the release workflow from the tagged commit, checked to import no Visual C++
runtime. Release APKs built from the tagged commit and signed with the same key as 0.1.0
(certificate SHA-256 5ff00c0a…f515c2).

Beta v0.1.0

Choose a tag to compare

@github-actions github-actions released this 11 Oct 22:52

🚀 sh705x-emu Beta v0.1.0 — an engine ECU's own firmware, running without the car

The first release: an emulator for Denso engine ECUs built on the Renesas SH705x, which
runs the ECU's own firmware, unmodified, on a simulated engine, on Windows and on Android.

Context: the first target is the ECU of an Opel Astra J 1.7 CDTI (A17DTJ, Denso,
SH7059, software NCLSW420AX36). Everything below was checked against that car's own
flash and EEPROM, and where the car could answer, against the car.

Theme: from a CPU core to an engine that idles. The firmware boots, talks
diagnostics on its CAN bus, closes its own loops through simulated actuators, and holds
the engine at idle on the torque it asks for, as the car does.

Deliverables:

  • sh705x-v0.1.0-beta-windows-x86_64.zip: sh705x-gui.exe (the window) and
    sh705x.exe (the command line). They carry their own C runtime: they run on any
    64-bit Windows with nothing else installed.
  • app-arm64-v8a-release.apk (phones) and app-x86_64-release.apk (the Android
    emulator, x86 devices): versionCode 1, versionName 0.1.0, minSdk 26, English and
    Spanish. Signed with the same key as opendash and Rustify.

No firmware comes with any of them. Bring your own flash dump (1.5 MB) and, if you
have it, the EEPROM dump (8 KB).


1. The headline

What it does Checked against
Core Every SH-2E instruction, the FPU rounding toward zero as the chip does Ghidra's disassembler on all 65 536 codes, an exact rational oracle, mutation testing
Boot The Astra's flash from reset to its background loop the same 196 669 register accesses as Ghidra's emulator
Diagnostics OBD and GMLAN over its emulated CAN bus the car: 231 recorded answers come back with the same shape, 108 byte for byte
Engine Idles on the firmware's own torque the car at warm idle: 750 rpm, 12 N·m, 7.0 mm³, EGR a third open, 5.2 g/s of air
Speed 1.26 to 1.36 times faster than real time i7-10870H, with the EEPROM, CAN and the engine turning

2. The ECU, emulated

  • The chip. The SH-2E core, and the on-chip peripherals the firmware uses: the
    interrupt controller, timers (CMT), DMA, serial ports, the A/D converter, HCAN-II and
    the ATU-II's input captures, tooth channel, one-shot pulses and PWM outputs. The
    firmware boots with no status bit forced.
  • The board. The four 93C86 EEPROMs, with the order of their blocks proven from a
    record that only fits one way; the status chips that watch the output stages, so no
    fault is pending at idle; the injector driver on SCI0. A PCMflash dump is served as it
    is.
  • The car around it. A 60-4 crank wheel and a 4+1 cam wheel, every sensor in
    physical units through the curve the firmware itself applies, the MAF as a frequency,
    and the other nodes on the bus (the ABS, and the rest of the car standing still).

3. An engine that idles on its own

Plants for the suction control valve, the EGR valve and the fresh air it leaves, and the
turbocharger close the firmware's own loops. With them, a simulated crankshaft turns on
the torque the firmware asks for, and its idle governor settles where the car does:

Emulator The car, warm idle
Engine speed 750 rpm 750 rpm
Torque / fuel asked 12.0 N·m / 7.02 mm³ 12.0 N·m / 7.0 mm³
EGR / fresh air 33 % open / 5.2 g/s a third open / 5.2 g/s
SCV current 2249 mA for 2250 asked on its setpoint

4. Diagnostics, from your usual tools

  • ELM327 over TCP (sh705x serve): any diagnostic app that talks to an ELM327 over
    Wi-Fi can be pointed at the emulator.
  • An emulated Scanmatik SM3 (sh705x sm3): opendash connects to it as it would to
    the real adapter.
  • A console in the window, in virtual time.

OBD modes 01, 03 and 09 (the VIN, over ISO-TP) and GMLAN service 1A answer as the car
does. Faults can be provoked: an output stage reporting a short (--status), a sensor out
of range (--adc).


5. Comparing calibrations

  • sh705x maps runs the same speed × pedal grid against two flash images, on the
    plants, and shows where the second differs: fuel and torque, rail pressure, SCV, air
    flow, boost, VGT, EGR, throttle, load.
  • sh705x touched lists the maps the firmware reads in a scenario, with their inputs
    and results, named in words, marking those a second image changes.

6. Watching it work

  • The window. It opens on a load screen: choose the images with the system's dialog,
    type their paths, or drop the files onto it. Then registers, the code around the PC
    with breakpoints, memory, CAN traffic, interrupts, sensors as sliders, and the console.
  • Step by step. An instruction, a crank tooth or an input edge at a time, and slow
    motion down to a thousandth of real time.
  • The engine view. The crank and cam wheels turning under their sensors, the four
    cylinders, and charts in ECU time of what the firmware asks for against what the plants
    give back. Each column keeps its minimum and maximum, so a move faster than a pixel
    still shows: the EGR drive stepping every few milliseconds is there at full speed.

7. On Android

The same core, in Kotlin and Compose: the engine view on a phone.

  • Loading. Pick the dumps with the system's file picker. The app asks for no
    permissions and keeps the dumps in memory only.
  • Running. "Idle on its torque" starts the engine as on the desktop; slow motion,
    "Next tooth" and "Next edge" work the same.
  • Theme. It starts in a dark theme; light, or the system's, is a tap away.

On the Android emulator (x86_64, software GPU) it holds 750 rpm at 0.66 times real time.
How fast it runs on a real phone has not been measured yet.


8. What it does not do, and why

  • It does not inject. The ECU will not inject until the immobilizer authorizes it,
    and that side is not emulated, by choice: the emulator shows what the ECU does
    without that authorization, as with a key it does not recognise. The rail pressure is
    therefore the sensor as set, not a combustion, and with the car's EEPROM the idle rises
    to 1000 rpm (P160D).
  • The cylinders' phase is assumed. Where cylinder 1's top dead centre falls relative
    to the gap is not known; the engine view says so.
  • Not yet: checking it against a real ECU on an FPGA-driven bench, and the ECU itself
    on an FPGA.

9. Installing

  • Windows: unzip and run sh705x-gui.exe. sh705x.exe help lists the command line.
  • Android: install the APK for your device. It is the first version, so there is
    nothing to update from.
  • From source: cargo build --release; the Android app with ./gradlew :app:assembleRelease in android/, with the NDK and cargo-ndk (see the README).

Licensed GPL-3.0-or-later.


Checked against an Opel Astra J 1.7 CDTI (A17DTJ): its flash and EEPROM dumps, a
diagnostic sweep of the car's engine ECU and its GMLAN identifiers recorded from the car,
and its live values at warm idle. Windows programs built by the release workflow from the
tagged commit, checked to import no Visual C++ runtime. Release APKs built from the tagged
commit, signed with opendash's and Rustify's key (certificate SHA-256
5ff00c0a…f515c2, the same in all three), installed and started on the Android
emulator.