No description
  • TypeScript 78.4%
  • C++ 11.4%
  • CSS 8.8%
  • JavaScript 0.8%
  • HTML 0.3%
  • Other 0.3%
Find a file
Rey Koxha 47342b2f30
All checks were successful
Quality / Static analysis (push) Successful in 19s
Quality / Tests & audit (push) Successful in 14s
Add license headers and fix MIT attribution for M93Cx6
Legal hygiene for the GPL-3.0 project and its bundled MIT component:

- Restore the MIT license notice (Travis Lesicka, "Copyright (c) 2017 Servant707")
  to firmware/M93Cx6.{h,cpp} — it was missing, which the MIT terms require. Add
  firmware/M93Cx6.LICENSE with the full text.
- Add a GPL-3.0 header to firmware.ino crediting the original roffe/eep and noting
  the bundled MIT library.
- Add SPDX GPL-3.0-or-later + copyright headers to the first-party TypeScript
  sources and stylesheet.
- Note the third-party MIT component in the README and firmware CHANGELOG.

Firmware recompiled: byte-identical to the embedded src/firmware.hex (comments
only). All quality gates green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 15:14:45 +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 Add ESLint, Prettier and Vitest coverage tooling 2026-07-09 14:35:03 +02:00
src Add license headers and fix MIT attribution for M93Cx6 2026-07-09 15:14:45 +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 Add Docker Compose deployment 2026-07-09 14:55:18 +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 Add ESLint, Prettier and Vitest coverage tooling 2026-07-09 14:35:03 +02:00
package.json Add ESLint, Prettier and Vitest coverage tooling 2026-07-09 14:35:03 +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
vitest.config.ts Add ESLint, Prettier and Vitest coverage tooling 2026-07-09 14:35:03 +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.