- TypeScript 78.9%
- C++ 10.4%
- CSS 8.5%
- JavaScript 1.5%
- Dockerfile 0.4%
- Other 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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> |
||
| .gitea/workflows | ||
| deploy | ||
| firmware | ||
| public | ||
| src | ||
| .dockerignore | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc.json | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.js | ||
| index.html | ||
| LICENSE.md | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
| vitest.config.ts | ||
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
Rcommand 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. Theavrdudecommand stays available as a fallback.
File handling
- Open and edit
.bindumps, multiple at once in file tabs. - Drag & drop one or more
.binfiles 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
- Flash the adapter firmware onto the Arduino (Sidebar → Flash adapter, or via
avrdude, see Firmware). - Wire the SOP8 clip to the CIM's EEPROM as above.
- Open the app, click Connect and pick the Arduino's serial port.
- 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 offirmware.hexand a byte-exact read-back. The flashed firmware boots and reportsv2.1.0. Only the Web Serial transport itself (vs. Nodeserialport) 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://localhostfor 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.