Download ZIP Propose a change
Name Last commit message Last updated
cli Publish 1.0.0 7d ago
docs Publish 1.0.0 7d ago
templates Publish 1.0.0 7d ago
webapp Publish 1.0.0 7d ago
install.sh Publish 1.0.0 7d ago
package.json Publish 1.0.0 7d ago
page.json Initial commit: app/lan7800-programmer 7d ago
README.md Initial commit: app/lan7800-programmer 7d ago
SKILL.md Publish 1.0.0 7d ago
uninstall.sh Publish 1.0.0 7d ago

LAN7800 EEPROM Programmer (Core v1)

MPLAB-Connect-parity EEPROM tool for the Microchip LAN7800 USB-3.1→GbE controller (VID 0x0424 / PID 0x7800 only). Read the EEPROM to a .bin, edit MAC / VID / PID / bcdDevice / strings / serial with a byte-exact preview, and program a physical adapter with verify-after-write.

Webapp with an EEPROM loaded — byte-exact preview and field editor

Device scan — enumerate attached LAN7800 adapters

lan7800-programmer/
  docs/     register map, .bin layout, MPLAB parity checklist (read first)
  cli/      the engine — pluggable backends + AI-oriented CLI (single source of truth)
  webapp/   Hydrogen app; shells out to the CLI (holds no EEPROM logic)

Access method (decided)

Primary backend is the in-tree lan78xx driver via ethtool, exactly what Microchip's own "LAN78xx EEPROM/OTP Programming on Linux" article recommends:

  • Read: ethtool -e <iface> raw on
  • Write: ethtool -E <iface> magic 0x78A5 offset <o> value <v> (one byte/call; the driver handles EWEN internally)

The backend is pluggable (cli/lan7800/backends/) so a driver-independent libusb vendor-command path (for blank chips) can be added later without touching field logic.

Safety model (important)

  • Reads are free. Inspect, dump, preview, verify — none of these change hardware.
  • Physical writes are gated. The only commands that touch an adapter are program and erase, and both refuse unless --force-physical-write is passed. In the Symphony mesh, the operator/agent sets that flag only after a cleared mesh escalate PROCEED. The webapp never sets it — POST /program returns 423 with the exact command for a human to run.
  • Verify-after-write is mandatory (program re-reads and diffs; fails loud).
  • Anti-brick: byte0 signature 0xA5 is only written deliberately; a cleared signature is recoverable (device falls back to OTP/CSR defaults). Stay in 0–511. Keep a backup: lan7800prog read --iface <if> --out backup.bin.

CLI quickstart

cd cli
python3 lan7800prog scan                                           # FREE — enumerate LAN7800s
python3 lan7800prog read-device --out dump.bin                     # FREE — connected device
#   auto-picks the backend: a lan78xx netdev -> ethtool, else the driver-independent
#   libusb path (needs a one-time udev rule; run `lan7800prog udev-rule` to print it)
python3 lan7800prog new --out base.bin        # default LAN7800 template (or --blank)
python3 lan7800prog read --iface enx00800f780000 --out dump.bin    # FREE (specific iface)
python3 lan7800prog info --in dump.bin        # parse & print (fields, config flags, LED/GPIO)
python3 lan7800prog --json info --iface enp0s20u1                  # machine-readable

# edit fields -> new .bin (no hardware), then preview
python3 lan7800prog edit --in base.bin --out out.bin \
  --mac 00:80:0F:12:34:56 --vid 0x0424 --pid 0x7800 --serial SN0001 \
  --set-string product="LAN7800 GbE" --ensure-signature

# LED / GPIO (offsets authoritative; per-bit encoding VERIFY vs datasheet §15)
python3 lan7800prog edit --in base.bin --out out.bin \
  --set-led 0=10 --led-enable 0=1 --led-blink 2 \
  --set-gpio 3=out,push-pull,1 --gpio-wake 3=1,1 \
  --set-raw 0x48=01                # authoritative raw-byte fallback

# compare a device against an image (FREE)
python3 lan7800prog verify --iface enp0s20u1 --image out.bin

# GATED — only after a mesh-escalate PROCEED:
python3 lan7800prog program --iface enp0s20u1 --image out.bin --force-physical-write

Every command supports --json (machine output) and otherwise prints OK: / ERROR: + Hint: lines.

Webapp

cd webapp && PORT=8747 python3 server.py     # http://127.0.0.1:8747

Scan for devices enumerates attached LAN7800s (pick one to target). Load is a native file picker (uploads the .bin to the server). Edit MAC/VID/PID/ strings/serial and the LED/GPIO panel, watch the live byte-exact preview, save. Program to device is intentionally gated and returns the command to run under escalation. State is on the server (GET /state, GET /console, GET /scan) so it is AI-drivable.

Tests (offline, no hardware)

cd cli && python3 tests/test_eeprom.py       # 10/10 field round-trips on a synthetic .bin

Field layout & VERIFY caveats

Layout follows docs/01-eeprom-mechanism.md (datasheet DS00001992G Table 10-2 + lan78xx.c). Two assumptions are flagged for confirmation against a real dump and centralized in cli/lan7800/eeprom.py so they flip in one place:

  • MAC octet order (MAC_LITTLE_ENDIAN) — stored little-endian per the doc.
  • VID/PID location — inside the SS/HS/FS USB device-descriptor blocks pointed to by the word-unit pointers at 0x31/0x35/0x39; writes hit all present blocks.

Scope

Core v1 = read→dump, edit MAC/VID/PID/bcdDevice/strings/serial, signature 0xA5, verify-after-write, load/save raw .bin, device scan, file-picker load, and LED/GPIO editing (LED per-pin enable + 16 modes + blink; GPIO direction/ drive/output/wake). LED/GPIO byte offsets are authoritative (LED 0x0B–0x0D, 0x58–0x59; GPIO 0x07/0x0E/0x48–0x4F) but the per-bit encoding is best-effort — confirm against datasheet §15 or a real dump; a --set-raw byte-level fallback is always available. If a USB descriptor block is pointed into one of these fixed register ranges, info reports the collision and named LED/GPIO writes to the colliding byte are blocked (use --set-raw only if you truly intend it) so a descriptor is never silently corrupted. Not in v1 (see docs/02-mplab-connect-parity.md → ADVANCED): OTP, MAC ranges / mass production, PME/wake-frame filters, string-heap relocation (v1 edits strings in place only), INI/TOML source format.