No description
  • TypeScript 78.9%
  • C++ 10.4%
  • CSS 8.5%
  • JavaScript 1.5%
  • Dockerfile 0.4%
  • Other 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Rey Koxha a40cec8d2b
All checks were successful
Quality / Static analysis (push) Successful in 16s
Quality / Tests & audit (push) Successful in 13s
PWA: Installation anbieten, wenn der Browser sie zulaesst
Bisher war das Tool zwar installierbar, wies aber nirgends darauf hin - sichtbar
war nur das kleine Symbol in der Adressleiste.

Statt eines aufdringlichen Banners ein dezenter Eintrag "Als App installieren"
unten in der Seitenleiste, direkt ueber den Einstellungen. Er erscheint nur,
wenn Chromium beforeinstallprompt liefert, und verschwindet nach dem Klick
(ein Prompt ist einmalig verwendbar), nach appinstalled sowie wenn die App
ohnehin schon standalone laeuft.

Ausserdem PNG-Icons in 192 und 512 px aus dem vorhandenen SVG ergaenzt: nicht
jeder Browser akzeptiert ein reines SVG-Icon fuer die Installierbarkeit, ohne
PNG bietet er die Installation je nach Version gar nicht erst an.

Geprueft: ohne Angebot kein Eintrag, mit Angebot erscheint er an der richtigen
Stelle, Klick loest den Prompt aus, nach Klick und nach appinstalled ist er
wieder weg - in beiden Sprachen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 22:17:15 +02:00
.gitea/workflows Replace firmware compile CI with a quality pipeline 2026-07-09 14:35:14 +02:00
deploy Add Docker Compose deployment 2026-07-09 14:55:18 +02:00
firmware Add license headers and fix MIT attribution for M93Cx6 2026-07-09 15:14:45 +02:00
public PWA: Installation anbieten, wenn der Browser sie zulaesst 2026-07-28 22:17:15 +02:00
src PWA: Installation anbieten, wenn der Browser sie zulaesst 2026-07-28 22:17:15 +02:00
.dockerignore Add Docker Compose deployment 2026-07-09 14:55:18 +02:00
.gitignore Initial commit 2026-07-09 13:22:09 +02:00
.prettierignore Add ESLint, Prettier and Vitest coverage tooling 2026-07-09 14:35:03 +02:00
.prettierrc.json Add ESLint, Prettier and Vitest coverage tooling 2026-07-09 14:35:03 +02:00
docker-compose.yml Add Docker Compose deployment 2026-07-09 14:55:18 +02:00
Dockerfile Betrieb unter einem URL-Prefix ermoeglichen 2026-07-27 17:13:51 +02:00
eslint.config.js Add ESLint, Prettier and Vitest coverage tooling 2026-07-09 14:35:03 +02:00
index.html Initial commit 2026-07-09 13:22:09 +02:00
LICENSE.md LICENSE.md hinzugefügt 2026-07-09 13:24:21 +02:00
package-lock.json CI: Audit-Befunde beheben (Vitest 4, postcss) 2026-07-28 21:47:18 +02:00
package.json GPL-Hinweise in der Oberflaeche und im Bundle 2026-07-28 22:05:14 +02:00
README.md Add license headers and fix MIT attribution for M93Cx6 2026-07-09 15:14:45 +02:00
tsconfig.json Initial commit 2026-07-09 13:22:09 +02:00
vite.config.ts GPL-Hinweise in der Oberflaeche und im Bundle 2026-07-28 22:05:14 +02:00
vitest.config.ts Tests: Kernlogik deutlich breiter abdecken 2026-07-28 21:53:18 +02:00

Saab CIM Tool icon

Saab CIM Tool

A browser-based tool to read, edit, validate and flash the EEPROM of a Saab CIM (Column Integration Module) using an Arduino as a hardware adapter.

Everything runs client-side in the browser — no installer, no native backend. Serial access uses the Web Serial API; the CIM data format, all checksums and the firmware flasher are implemented in TypeScript. Opening and editing .bin files works in any browser; talking to the adapter needs a Chromium-based one (see Browser support).

This is a browser rewrite of the original Go/Fyne desktop tool roffe/eep by roffe (see Credits). The complete CIM library was ported to TypeScript (src/lib/cim.ts) and verified against real dumps, so the app has no dependency on any private package.

Features

EEPROM operations (Web Serial)

  • Read / Write / Erase the CIM EEPROM with a live progress bar.
  • Verify-after-write: the written data is read back and compared (MD5 + CRC32).
  • Robust read mode: uses the firmware's R command to re-read unstable cells until two reads agree — fewer failed reads on aged EEPROMs.
  • In-browser firmware flasher (STK500v1 / optiboot) — flash the Arduino adapter without avrdude. The avrdude command stays available as a fallback.

File handling

  • Open and edit .bin dumps, multiple at once in file tabs.
  • Drag & drop one or more .bin files anywhere onto the window.
  • Save edited dumps (XOR-encoded, ready to flash).
  • JSON export of the decoded contents as a report.

Inspection & editing

  • Validation of every section against its CRC-16/MCRF4XX checksum, with the two data banks compared for consistency — a healthy dump is reported at a glance.
  • Identity panel: VIN (with live ISO 3779 check-digit validation and model year), PIN, S/N sticker, steering-angle-sensor (SAS) toggle, ISK, PSK, part numbers, MD5/CRC32 fingerprint and programming dates.
  • Key editor: list, add and delete keys with transponder-type detection.
  • Virginize (unmarry): strip VIN, PIN, keys and fault codes so a CIM can be re-married to a car with Tech2.
  • Colour-coded hex viewer with a region legend and hover tooltips mapping every byte to its field.
  • Compare two open dumps byte-by-byte: differing bytes are highlighted and the affected fields are listed.

UI

  • Dark / light theme.
  • Multilingual (English / German), switchable in the header. Adding a language is just another dictionary in src/i18n.ts.
  • Installable PWA that works offline after the first load (public/sw.js).

Hardware & wiring

You need:

  • an Arduino UNO (or Nano),
  • a breadboard and jumper wires,
  • a SOP8 test clip with a flat cable.

Wire the EEPROM to the Arduino as follows:

                    _____
 Chip Select (cs) --|1   8|-- Vcc (pwr)
Serial Clock (sk) --|2   7|--
     Data In (di) --|3   6|-- Org Select (org)
    Data Out (do) --|4   5|-- Vss / GND
                    ¯¯¯¯¯
  Vcc (pwr)          -> Pin 9        Data In (di)  -> Pin 11
  Vss (gnd)          -> GND          Data Out (do) -> Pin 12
  Chip Select (cs)   -> Pin 10       Org (org)     -> Pin 8
  Serial Clock (sk)  -> Pin 7

The red wire of the SOP8 clip marks pin 1 and must point to the corner with the small dot on the EEPROM. Full instructions are in the in-app help (? top-right).

Usage

  1. Flash the adapter firmware onto the Arduino (Sidebar → Flash adapter, or via avrdude, see Firmware).
  2. Wire the SOP8 clip to the CIM's EEPROM as above.
  3. Open the app, click Connect and pick the Arduino's serial port.
  4. Read the EEPROM, inspect/edit it, then Write it back.

To just inspect a dump, use Open (or drag a .bin in) — no hardware required.

Browser support

Task Requirement
Read / write / flash Chrome, Edge or Opera on desktop (Web Serial)
Open / edit / save files Any modern browser

Firmware

The Arduino firmware lives in firmware/ and the compiled image is embedded in the app at src/firmware.hex (current version v2.1.0; see firmware/CHANGELOG.md).

Flash it from the app, or with avrdude:

avrdude -c arduino -P <port> -b 115200 -p atmega328p -D -U flash:w:firmware.hex:i

The v2.1.0 firmware keeps the field-proven EEPROM bit-bang timing byte-for-byte and improves the serial layer (decoupled command buffer, safer parser, i identify and R robust-read commands, smaller flash/RAM footprint).

Verified on real hardware: the STK500v1 flasher was checked against an Arduino Uno (ATmega328P, CH340) — sync, signature (1E 95 0F), a full flash of firmware.hex and a byte-exact read-back. The flashed firmware boots and reports v2.1.0. Only the Web Serial transport itself (vs. Node serialport) is untested; the bytes on the wire are identical.

Project structure

src/
  main.ts          App shell, state, all views wired together
  i18n.ts          Translations (en/de) + t()
  dom.ts           Tiny hyperscript helper + inline SVG icons
  style.css        Design system (theming, layout)
  lib/
    cim.ts         CIM 512-byte parser, validation, editing, serialization
    checksum.ts    CRC-16/MCRF4XX, CRC-32, MD5
    bytes.ts       Hex / byte helpers
    regions.ts     Byte-range map for the hex viewer
    serial.ts      Web Serial adapter (read/write/erase protocol)
    stk500.ts      STK500v1 firmware flasher
    intelhex.ts    Intel HEX parser
  views/           hex, diff, help, shared UI (toast/dialogs)
public/            manifest, icon, service worker
firmware/          Arduino firmware source + M93Cx6 library + CHANGELOG

Development

npm install
npm run dev        # dev server on http://localhost:5173
npm run build      # production build to dist/
Script Purpose
npm run dev Vite dev server
npm run build Type-check + production build
npm test Run the Vitest suite
npm run coverage Tests with coverage thresholds
npm run typecheck tsc --noEmit
npm run lint ESLint
npm run format Prettier check (use format:fix to apply)

The app has no runtime dependencies — everything is build-time tooling and the output is a static bundle.

Deployment (Docker)

A multi-stage image builds the static bundle and serves it with nginx:

docker compose up -d --build

This publishes the app on 127.0.0.1:8080 (override with the CIMTOOL_PORT environment variable) so you can put it behind your own reverse proxy.

HTTPS is required. The Web Serial API only works in a secure context, so the app must be reached over HTTPS (or http://localhost for testing). Over plain HTTP, reading/writing/flashing is unavailable and only file inspection works — terminate TLS at your reverse proxy.

An example NGINX server block for the proxy host is in deploy/reverse-proxy.example.conf; the in-container nginx config is deploy/nginx.conf.

Quality & CI

  • Unit tests (Vitest) cover the pure-logic core: CRC-16/CRC-32/MD5 against known test vectors, parse→serialize round-trip identity, XOR-encoding detection, validation, key editing and the Intel HEX parser. The parser was additionally checked against a real CIM dump (clean validation, byte-exact round-trip).
  • Coverage thresholds are enforced on that core (vitest.config.ts); the DOM UI and hardware I/O layers are intentionally excluded as they aren't meaningfully unit-testable.
  • ESLint + Prettier keep the code consistent.
  • CI (.gitea/workflows/ci.yaml) runs on every push and pull request: a static analysis job (format, lint, type check) and a tests & audit job (coverage + npm audit).

Credits

This project is a browser-based rewrite of roffe/eep by roffe — the original author. The Arduino firmware, the M93Cx6 EEPROM handling and the reverse-engineered CIM data format all originate from that project; this repository ports the tooling to the web and extends the firmware. Many thanks to roffe for the original work.

License

GNU GPL v3 — the same license as the original roffe/eep.

Third-party components

The bundled Arduino M93Cx6 EEPROM library (firmware/M93Cx6.h, firmware/M93Cx6.cpp) by Travis Lesicka is licensed separately under the MIT License, reproduced in firmware/M93Cx6.LICENSE.