feat(skills): gb-cart-flasher - lettura/scrittura cartucce Game Boy con FlashGBX e lettore USB (Joey Jr, GBxCart RW, GBFlash, Game Bub)
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
---
|
||||
name: gb-cart-flasher
|
||||
description: >
|
||||
Legge e scrive ROM e salvataggi su cartucce Game Boy, Game Boy Color e Game Boy
|
||||
Advance con un programmatore di cartucce USB (Joey Jr, GBxCart RW, GBFlash, Game Bub,
|
||||
cloni/repro) pilotato dalla CLI di FlashGBX. Usare quando l'utente chiede di
|
||||
identificare il lettore di cartucce collegato, fare un test di connessione, leggere
|
||||
le informazioni della cartuccia, fare il backup di ROM o salvataggi, scrivere/flashare
|
||||
una ROM su una cartuccia riscrivibile, ripristinare un backup, o diagnosticare errori
|
||||
di lettura/scrittura ("No devices found", dump incoerenti, scrittura fallita). NON
|
||||
usare per emulatori (PyBoy, mGBA), per compilare ROM (GBDK/SDCC, vedere la skill di
|
||||
progetto), per cartucce di altre console, né per organizzare file ROM su disco.
|
||||
---
|
||||
|
||||
# Programmatore di cartucce Game Boy (FlashGBX + lettore USB)
|
||||
|
||||
## Outcome
|
||||
Cartuccia letta/scritta con **prova verificabile**: info della cartuccia prima e dopo,
|
||||
backup del contenuto precedente salvato su file, rilettura post-scrittura confrontata
|
||||
per hash con il file sorgente. Nessuna scrittura senza backup e consenso dell'utente.
|
||||
|
||||
## Preconditions
|
||||
- Lettore collegato e alimentato via USB; cartuccia inserita nel verso corretto
|
||||
(per Game Boy Camera: viti verso l'alto) e contatti puliti.
|
||||
- `flashgbx` disponibile (`flashgbx --version` o `python3 -m FlashGBX`); in alternativa
|
||||
AppImage/.deb dal repo Lesserkuma/FlashGBX.
|
||||
- Permessi sulla seriale: utente nel gruppo `dialout` (Debian/Fedora) o `uucp`
|
||||
(Arch/Steam Deck), oppure udev rule, oppure `sudo chmod 0666 /dev/ttyACM*` temporaneo.
|
||||
- Modalità corretta: `--mode dmg` per GB/GBC, `--mode agb` per GBA.
|
||||
|
||||
## Non-negotiable gates
|
||||
1. **Prima di ogni scrittura**: `--action backup-rom` del contenuto attuale + conferma
|
||||
esplicita dell'utente (la scrittura è irreversibile sul supporto fisico; il ripristino
|
||||
è possibile solo riscrivendo il backup).
|
||||
2. **Il titolo nell'header non identifica il contenuto**: hack/bootleg/repro mantengono
|
||||
l'header del gioco originale (caso reale: un bootleg di Super Mario Land letto come
|
||||
`SUPER MARIOLAND`). Per identificare davvero la ROM, avviarla in emulatore (PyBoy).
|
||||
3. **Originale ≠ riscrivibile**: le cartucce Nintendo originali sono mask ROM (sola
|
||||
lettura). Sono scrivibili solo flashcart e repro con chip flash. Indizio tipico di
|
||||
repro: FlashGBX avverte *"the checksum is not correct … normal for reproduction
|
||||
cartridges"*; conferma definitiva: l'autodetect del profilo flash riesce in scrittura.
|
||||
4. **Non inventare profili flash**: usare `--flashcart-type autodetect`. Se l'autodetect
|
||||
fallisce, leggere i profili in `<config>/FlashGBX/flashcarts/*.txt` e chiedere
|
||||
all'utente prima di forzarne uno.
|
||||
5. **Non disattivare la verifica**: non usare `--no-verify-write` salvo richiesta esplicita.
|
||||
6. **Voltaggio**: di default 3,3 V; `--force-5v` solo se la scrittura fallisce e il chip
|
||||
lo richiede (5 V può danneggiare alcuni chip). Non usarlo "a caso".
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Identificare il lettore (read-only)
|
||||
```bash
|
||||
lsusb
|
||||
ls -l /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
|
||||
journalctl -k --no-pager | grep -iE "cdc_acm|ch341|usb.*tty" | tail -20
|
||||
```
|
||||
VID:PID attesi (vedi `references/hardware-usb.md`): Joey Jr `0483:5740`,
|
||||
GBxCart RW / GBFlash `1a86:7523`, Game Bub `1209:b010`. Un device CDC generico
|
||||
"STM32 Virtual ComPort" è quasi sempre un Joey Jr (o clone).
|
||||
|
||||
### 2. Test di connessione + info cartuccia (read-only)
|
||||
```bash
|
||||
flashgbx --cli --mode dmg --action info
|
||||
```
|
||||
Attesi: riga `Connected to <device> – Firmware <ver> (/dev/ttyXXX)` e il blocco
|
||||
`Cartridge Information:` con ROM Title, ROM Size, Mapper Type, Save Type, Boot Logo.
|
||||
`Boot Logo: OK` + checksum coerente = lettura buona. Output non conforme → contatti
|
||||
sporchi, cartuccia non inserita o modalità sbagliata (`dmg` vs `agb`).
|
||||
|
||||
### 3. Backup del contenuto attuale (obbligatorio prima di scrivere)
|
||||
```bash
|
||||
mkdir -p "$HOME/gb-cart-backups"
|
||||
flashgbx --cli --mode dmg --action backup-rom --overwrite "$HOME/gb-cart-backups/<titolo>_$(date +%F).gb"
|
||||
```
|
||||
Registrare hash e CRC32 stampati da FlashGBX. Lo stesso comando con
|
||||
`--action backup-save` salva la SRAM (usa `--save-filename-add-datetime` per non
|
||||
sovrascrivere; `--store-rtc` se la cartuccia ha un RTC).
|
||||
|
||||
### 4. Scrittura della ROM (azione irreversibile)
|
||||
Dopo il gate 1 (backup + consenso):
|
||||
```bash
|
||||
printf 'y\n' | flashgbx --cli --mode dmg --action flash-rom \
|
||||
--flashcart-type autodetect /percorso/rom.gb
|
||||
```
|
||||
- Atteso: riga `Flashcart Profile: …` con il profilo scelto, poi
|
||||
**`The ROM was written and verified successfully!`**.
|
||||
- `--compare-sectors` (default on) riscrive solo i settori diversi.
|
||||
- `--prefer-chip-erase` se la scheda supporta sia sector sia full chip erase.
|
||||
- ROM più corta del chip: normale, si scrive dall'indirizzo 0; una ROM "ROM only"
|
||||
da 32 KiB parte comunque su schede MBC1/MBC5 perché a reset i banchi 0 e 1 mappano
|
||||
i primi 32 KiB. FlashGBX avvisa solo se il file è **più grande** del chip.
|
||||
- In CLI non interattiva i prompt di conferma (`[y/N]`) vanno alimentati con `printf 'y\n'`
|
||||
oppure si usa la modalità interattiva (`--action interactive`).
|
||||
|
||||
### 5. Verifica (exit criteria)
|
||||
1. Ripetere `--action info`: deve mostrare il **nuovo** ROM Title / ROM Size.
|
||||
2. Rileggere la ROM e confrontarla con il sorgente:
|
||||
```bash
|
||||
printf 'y\n' | flashgbx --cli --mode dmg --action backup-rom --overwrite /tmp/verify.gb
|
||||
cmp /tmp/verify.gb /percorso/rom.gb && echo IDENTICI
|
||||
```
|
||||
3. Conservare il backup del contenuto precedente e riportare all'utente:
|
||||
device+firmware, profilo flash, tensione, hash del backup e della verifica.
|
||||
4. Registrare l'evidenza in memoria condivisa (qmem: progetto della skill o `host-<host>`)
|
||||
con path dei file e hash — non duplicare qui la procedura.
|
||||
|
||||
## Troubleshooting (dettaglio in `references/cartucce-profili-errori.md`)
|
||||
- *"No devices found"* con GBxCart RW/GBFlash su Linux: il modulo `brltty` cattura i
|
||||
CH340/341 → rimuoverlo/blacklistarlo.
|
||||
- Errori di lettura intermittenti o dump incoerenti: pulire i contatti con IPA 99%,
|
||||
reinserire la cartuccia, evitare hub USB non alimentati.
|
||||
- `Auto-detection failed` in scrittura: `--flashcart-type` con il nome esatto del profilo.
|
||||
- Scrittura fallita a 3,3 V: ritentare con `--force-5v` solo dopo aver verificato il chip.
|
||||
- Salvataggi "batteryless" (ROM patchate senza batteria): servono `--dmg-savetype
|
||||
batteryless` e `--bl-offset/--bl-size/--bl-layout`.
|
||||
|
||||
## Salvataggio
|
||||
- La procedura vive qui; in qmem vanno solo **puntatori** a questa skill ed **evidenze
|
||||
di esecuzione** (device, firmware, profilo, tensione, path, hash) nei progetti
|
||||
`gb-cart-flasher` (evidenze generiche) e `host-<hostname>` (dettagli macchina-specifici:
|
||||
gruppo/permessi, udev, seriali, lettore posseduto).
|
||||
|
||||
## Resource loading
|
||||
- `references/flashgbx-cli.md` — riferimento completo CLI di FlashGBX (azioni, opzioni,
|
||||
parsing output, exit code, config dir, GUI).
|
||||
- `references/hardware-usb.md` — VID:PID dei lettori, udev/permessi, firmware, modalità
|
||||
DMG/AGB, conflitti driver.
|
||||
- `references/cartucce-profili-errori.md` — mask ROM vs repro/flashcart, categorie di
|
||||
cartucce scrivibili, tensione/erase, batteryless, catalogo errori.
|
||||
- `scripts/gb-cart.sh` — wrapper deterministico (detect/info/backup/flash con backup
|
||||
obbligatorio e confronto hash finale).
|
||||
@@ -0,0 +1,73 @@
|
||||
# Cartucce, profili flash ed errori
|
||||
|
||||
## Che cartuccia ho davanti?
|
||||
| Tipo | ROM | Riscrivibile | Note |
|
||||
|---|---|---|---|
|
||||
| Originale Nintendo (GB/GBC/GBA) | mask ROM | **no** | solo backup; la scrittura fallisce o non ha effetto |
|
||||
| Repro / bootleg (PCB cinesi) | chip flash (spesso più capiente dell'header) | **sì** | spesso MBC1/MBC5 emulati; riscrivibili con FlashGBX |
|
||||
| Flashcart moderne (insideGadgets, EZ-Flash, ModRetro, MidnightTrace, GBFlash…) | flash + eventuale FRAM/SRAM | **sì** | profili dedicati in FlashGBX |
|
||||
| Cartuccia di sviluppo / dev cart | flash, header libero | **sì** | può richiedere profilo manuale |
|
||||
| Multicart / X-in-1 | flash grande + menu | **sì** | riscrivibile, ma il menu va ricostruito |
|
||||
|
||||
Indizi operativi:
|
||||
- **`the checksum is not correct … normal for reproduction cartridges`** → quasi sempre repro.
|
||||
- L'header dichiara `ROM Size` minore del chip reale (es. 64 KiB dichiarati su un flash da
|
||||
4 MiB): normale, i repro usano chip grandi per più giochi.
|
||||
- L'autodetect del profilo flash **riesce** durante la scrittura → chip flash presente e
|
||||
quindi cartuccia riscrivibile; se fallisce su una cartuccia "originale" è il comportamento
|
||||
atteso (mask ROM).
|
||||
|
||||
**Il titolo nell'header non prova l'identità del gioco.** Hack, traduzioni e bootleg
|
||||
conservano l'header originale (caso reale: un bootleg di Super Mario Land con Pikachu
|
||||
letto come `SUPER MARIOLAND`, `MBC1`, 64 KiB). Per sapere cosa c'è davvero dentro:
|
||||
avviare il dump in emulatore (PyBoy headless: `pyboy` con `window="null"`, `tick()` senza
|
||||
argomenti — con `tick(1, False)` lo schermo non si aggiorna) o confrontare con un dump noto.
|
||||
|
||||
## Header e mapper: perché una ROM "ROM only" da 32 KiB parte su una scheda MBC
|
||||
A reset MBC1 e MBC5 mappano il banco 0 a `0x0000-0x3FFF` e il banco 1 a `0x4000-0x7FFF`:
|
||||
una ROM da 32 KiB occupa esattamente quei due banchi, quindi parte anche se l'header
|
||||
dichiara `cart type 0x00 (ROM only)` e la scheda monta un MBC. Scrivere una ROM più
|
||||
piccola del chip è quindi normale; FlashGBX avvisa solo se il file è **più grande** del
|
||||
flash disponibile.
|
||||
|
||||
## Scrittura: tensione, erase, verifica
|
||||
- **Tensione**: default 3,3 V. Alcuni chip richiedono 5 V → `--force-5v`, ma 5 V può
|
||||
danneggiare chip non tolleranti: provarlo solo dopo un errore e con cartuccia sacrificabile.
|
||||
- **Erase**: `sector erase` (più veloce, solo i settori da riscrivere) di default quando
|
||||
disponibile; `--prefer-chip-erase` per cancellare tutto il chip (utile dopo scritture
|
||||
parziali o contenuti corrotti).
|
||||
- **`--compare-sectors`** (default on) salta i settori già identici: meno usura, ma non
|
||||
ripara settori logicamente corretti e fisicamente deboli.
|
||||
- **Verifica**: FlashGBX rilegge e confronta da sé (`written and verified successfully`).
|
||||
Aggiungere comunque una rilettura indipendente con `cmp`/`sha256sum` per l'evidenza.
|
||||
|
||||
## Salvataggi
|
||||
- Tipi: `None`, `SRAM` (con batteria), `FRAM`, `EEPROM`, **batteryless** (dati dentro la ROM).
|
||||
- Batteryless: servono `--dmg-savetype batteryless` e `--bl-offset/--bl-size/--bl-layout`
|
||||
(0 = continuo, 1 = prima metà del banco ROM, 2 = seconda metà).
|
||||
- RTC (Pokémon Oro/Argento, ecc.): `--store-rtc` in backup; il ripristino dei registri RTC
|
||||
è supportato solo da alcuni profili.
|
||||
- Su repro con ROM patchate "batteryless" il backup/restore del save può non funzionare:
|
||||
ROM e salvataggio condividono lo stesso chip flash (il dump completo contiene anche il save).
|
||||
|
||||
## Catalogo errori
|
||||
| Sintomo | Causa probabile | Azione |
|
||||
|---|---|---|
|
||||
| `No devices found` | permessi, `brltty` sui CH340/341, cavo solo-carica, porta occupata | gruppo `dialout`/`uucp` o udev; rimuovere `brltty`; collegare diretto; chiudere altri programmi |
|
||||
| `Couldn't read cartridge header` | cartuccia non inserita/contatti sporchi, `--mode` sbagliato | pulire con IPA 99%, reinserire, correggere `dmg`/`agb` |
|
||||
| `Invalid data was detected …` | lettura instabile o header incoerente | pulire i contatti; `--ignore-bad-header` solo se l'incoerenza è voluta/nota |
|
||||
| `Auto-detection failed` in scrittura | chip flash non in tabella, alimentazione, contatti | verificare il profilo in `<config>/FlashGBX/flashcarts/*.txt` e passarlo con `--flashcart-type`; chiedere conferma all'utente |
|
||||
| `The ROM was dumped, but the checksum is not correct` | repro/bootleg/prototipo/overdump | non è di per sé un errore: valutare `Boot Logo: OK` e un secondo dump identico |
|
||||
| Scrittura fallita a 3,3 V | chip che richiede 5 V | ritentare con `--force-5v` (rischio dichiarato) |
|
||||
| Scrittura fallita senza altri indizi | profilo sbagliato o chip usurato | provare `--prefer-chip-erase`, poi profilo manuale; cartuccia possibile a fine vita |
|
||||
| `The target file … already exists` | file di backup già presente | `--overwrite` o nome nuovo (`--save-filename-add-datetime`) |
|
||||
| `seems to support ROMs that are up to X, but the file is bigger` | file troppo grande per il profilo | verificare di aver scelto la ROM giusta |
|
||||
| Game Boy Camera non letta | inserita al contrario | contatti/viti verso l'alto |
|
||||
|
||||
## Buone pratiche di verifica
|
||||
1. **Due dump identici** della stessa cartuccia (hash uguali) per escludere letture instabili;
|
||||
su cartuccia originale il checksum globale deve tornare.
|
||||
2. Conservare il dump con hash nel nome o in un `SHA256SUMS` accanto al file.
|
||||
3. Per un dump di conservazione: due lettori diversi o due sessioni diverse prima di
|
||||
dichiararlo valido.
|
||||
4. Non distribuire ROM di giochi commerciali: la copia è per uso personale/backup.
|
||||
@@ -0,0 +1,91 @@
|
||||
# FlashGBX — riferimento CLI
|
||||
|
||||
Autore: Lesserkuma (github.com/Lesserkuma/FlashGBX, GPL-3.0-or-later).
|
||||
Verificato su **FlashGBX 5.0.1** (Python 3.10+; su questa macchina Python 3.14, pyserial 3.5).
|
||||
Installazione: `pip3 install "FlashGBX[qt6]"` (o `[qt5]`, o senza extra per la sola CLI),
|
||||
oppure AppImage/.deb dai release GitHub. Launcher tipico: `flashgbx` oppure
|
||||
`python3 -m FlashGBX`. `python3 -m FlashGBX --version` per la versione.
|
||||
|
||||
## Modalità di esecuzione
|
||||
- **GUI** (default): senza argomenti, oppure doppio click.
|
||||
- **CLI**: `--cli`, oppure automaticamente se si passa `--mode` o `--action`.
|
||||
- **Console interattiva**: `--action interactive` (comandi manuali sul device).
|
||||
- Config dir: `~/.config/FlashGBX` su Linux (opzione `--cfgdir appdata|subdir`);
|
||||
contiene `settings.ini`, i profili flashcart (`flashcarts/*.txt`) e i log.
|
||||
|
||||
## Sintassi
|
||||
```
|
||||
flashgbx [--cli] --mode {dmg,agb} --action <azione> [opzioni] [path]
|
||||
```
|
||||
`path` è facoltativo in lettura (default `auto` = nome generato), **obbligatorio in scrittura**.
|
||||
Se manca e l'azione lo richiede, la CLI lo chiede a terminale.
|
||||
|
||||
## Azioni (`--action`)
|
||||
| Azione | Effetto | Scrive sulla cartuccia |
|
||||
|---|---|---|
|
||||
| `info` | legge l'header e stampa `Cartridge Information` | no |
|
||||
| `backup-rom` | dump della ROM su file | no |
|
||||
| `flash-rom` | scrittura di una ROM (richiede backup + consenso) | **sì** |
|
||||
| `backup-save` | dump della SRAM/save (+ RTC se `--store-rtc`) | no |
|
||||
| `restore-save` | riscrive la SRAM da file | **sì** |
|
||||
| `erase-save` | cancella la SRAM | **sì** |
|
||||
| `gbcamera-extract` | estrae le foto da un backup di Game Boy Camera | no |
|
||||
| `interactive` | console interattiva sul device | dipende |
|
||||
| `fwupdate-joeyjr` (e simili) | aggiorna il firmware del lettore, se supportato | — |
|
||||
|
||||
## Opzioni principali (CLI)
|
||||
Generali: `--cli`, `--mode dmg|agb`, `--action`, `--overwrite`, `--language`,
|
||||
`--cfgdir appdata|subdir`, `--debug`, `--reset`, `--wait`.
|
||||
|
||||
Device: `--device-port /dev/ttyACM0` (forza la porta), `--device-limit-baudrate`.
|
||||
|
||||
Scrittura ROM: `--flashcart-type autodetect|<nome profilo>` (default `autodetect`),
|
||||
`--prefer-chip-erase` (full chip erase invece di sector erase),
|
||||
`--force-5v` (forza 5 V, default 3,3 V), `--no-verify-write`,
|
||||
`--compare-sectors` (default **on**: riscrive solo i settori diversi).
|
||||
|
||||
Cartuccia/header: `--ignore-bad-header` (non si ferma se l'header è incoerente),
|
||||
`--dmg-romsize`, `--dmg-mbc`, `--dmg-savetype`, `--agb-romsize`, `--agb-savetype`,
|
||||
`--bl-offset`, `--bl-size`, `--bl-layout 0|1|2` (salvataggi batteryless),
|
||||
`--store-rtc`, `--keep-calibration` (e-Reader).
|
||||
|
||||
Backup/save: `--save-filename-add-datetime`, `--generate-dump-report`,
|
||||
`--gbcamera-palette`, `--gbcamera-outfile-format`, `--gbcamera-extract`.
|
||||
|
||||
## Esempi
|
||||
```bash
|
||||
# info cartuccia DMG
|
||||
flashgbx --cli --mode dmg --action info
|
||||
|
||||
# backup ROM (non sovrascrive per default: chiede)
|
||||
flashgbx --cli --mode dmg --action backup-rom --overwrite ~/gb-cart-backups/mario.gb
|
||||
|
||||
# scrittura con autodetect del chip flash, non interattiva
|
||||
printf 'y\n' | flashgbx --cli --mode dmg --action flash-rom \
|
||||
--flashcart-type autodetect ~/roms/gioco.gb
|
||||
|
||||
# save backup di una cartuccia GBA con data nel nome file
|
||||
flashgbx --cli --mode agb --action backup-save --save-filename-add-datetime ~/saves/
|
||||
|
||||
# force del chip (autodetect fallito) e 5 V
|
||||
flashgbx --cli --mode dmg --action flash-rom \
|
||||
--flashcart-type "insideGadgets 4 MiB (S29GL032M)" --force-5v ~/roms/gioco.gb
|
||||
```
|
||||
|
||||
## Output e parsing
|
||||
- Connessione: `Connected to <Device> – Firmware <ver> (<data>) on /dev/ttyXXX`.
|
||||
- Info: blocco `Cartridge Information:` con `ROM Title`, `Revision`, `Platform`,
|
||||
`Real Time Clock`, `Boot Logo`, `ROM Checksum`, `ROM Size`, `Save Type`, `Mapper Type`.
|
||||
- Scrittura: `Flashcart Profile:` + `The following ROM file will now be written …`,
|
||||
barra di avanzamento con `\r` (nei log: `tr '\r' '\n'`), quindi
|
||||
`The ROM was written and verified successfully!` (o messaggio d'errore in rosso).
|
||||
- Backup: stampa `CRC32` e `SHA-1`; se il **checksum globale** della ROM non torna,
|
||||
avvisa che è normale per repro/bootleg/prototipi — non è di per sé un errore di lettura,
|
||||
ma va interpretato insieme a `Boot Logo: OK`.
|
||||
- Progresso/prompt: i `[y/N]` in modalità non interattiva vanno alimentati da stdin.
|
||||
- Exit code: 0 = successo; 1 = errore (header illeggibile, dati non validi, ecc.).
|
||||
|
||||
## Alternative coperte
|
||||
Lo stesso tool pilota **GBxCart RW**, **GBFlash**, **Joey Jr** e **Game Bub**; la scelta
|
||||
del driver è automatica in base a VID:PID. Per hardware non supportato servono i tool
|
||||
del produttore (es. YAGB per l'omonimo dumper STM32) o librerie specifiche (pyGBx).
|
||||
@@ -0,0 +1,57 @@
|
||||
# Hardware, USB e permessi
|
||||
|
||||
## Tabella VID:PID dei lettori supportati da FlashGBX
|
||||
| Lettore | VID:PID | Chip/ifaccia | Note |
|
||||
|---|---|---|---|
|
||||
| **Joey Jr** (BennVenn) | `0483:5740` | STM32 USB CDC (`cdc_acm`) | si presenta come "STM32 Virtual ComPort"; supportato da firmware CFW `cfw_id = L` (FlashGBX avvisa se gira il firmware GUI del venditore) |
|
||||
| **GBxCart RW** (insideGadgets) | `1a86:7523` | CH340/CH341 (`ch341`) | richiede profilo flashcart; attenzione al conflitto `brltty` |
|
||||
| **GBFlash** (simonkwng) | `1a86:7523` | CH340/CH341 | testato v1.2/v1.3 |
|
||||
| **Game Bub** | `1209:b010` | CDC | PID di progetto (pid.codes) |
|
||||
|
||||
Un device `0483:5740` che *non* risponde al protocollo può essere un qualsiasi
|
||||
progetto STM32 generico (es. dumper DIY, programmer SPI → `flashrom -p serprog`).
|
||||
Percorsi tipici: `/dev/ttyACM0` (CDC), `/dev/ttyUSB0` (CH340).
|
||||
|
||||
## Identificazione rapida
|
||||
```bash
|
||||
lsusb # VID:PID + produttore
|
||||
ls -l /dev/ttyACM* /dev/ttyUSB* # porta e gruppo
|
||||
udevadm info -q property -n /dev/ttyACM0 # ID_VENDOR_ID, ID_MODEL, ID_SERIAL
|
||||
journalctl -k --no-pager | grep -iE "cdc_acm|ch341|ttyACM|ttyUSB" | tail
|
||||
```
|
||||
FlashGBX conferma l'identità con la riga
|
||||
`Connected to Joey Jr – Firmware L15 (…) on /dev/ttyACM0`.
|
||||
|
||||
## Permessi
|
||||
1. Gruppo seriale (permanente, richiede nuovo login): `sudo usermod -a -G dialout $USER`
|
||||
(Fedora/Debian) o `uucp` (Arch/Steam Deck).
|
||||
2. Regola udev permanente, es. `/etc/udev/rules.d/50-flashgbx.rules`:
|
||||
```
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0666"
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE="0666"
|
||||
```
|
||||
poi `sudo udevadm control --reload-rules && sudo udevadm trigger`.
|
||||
3. Temporaneo: `sudo chmod 0666 /dev/ttyACM0` (da rinnovare a ogni riconnessione).
|
||||
|
||||
Verifica del gruppo: `id | tr ',' '\n' | grep -E 'dialout|uucp'`.
|
||||
`crw-rw---- root dialout` + utente in `dialout` = accesso in scrittura senza sudo.
|
||||
|
||||
## Conflitti noti
|
||||
- **`brltty`** (driver per display braille) cattura i chip CH340/CH341: con GBxCart RW o
|
||||
GBFlash "No devices found" anche con cavo dati valido → `sudo dnf remove brltty` /
|
||||
`sudo apt remove brltty` o blacklist del modulo, poi reboot. Non riguarda il Joey Jr.
|
||||
- Cavi USB solo-carica: la porta compare ma non comunica.
|
||||
- Hub USB non alimentati o porte frontali: errori intermittenti → collegare diretto.
|
||||
- Altri programmi che aprono la seriale (ModemManager, IDE, monitor seriale) possono
|
||||
bloccare la porta: chiuderli.
|
||||
|
||||
## Firmware del lettore
|
||||
- Joey Jr: aggiornabile da FlashGBX (`Firmware Update for Joey Jr` in GUI, oppure
|
||||
`--action fwupdate-joeyjr`). Firmware più recenti di quelli noti al tool producono
|
||||
un avviso non bloccante. Il firmware "GUI" del venditore non è compatibile con FlashGBX.
|
||||
- GBFlash/GBxCart RW: aggiornamento con gli strumenti del produttore.
|
||||
|
||||
## Modalità piattaforma
|
||||
- `--mode dmg` → Game Boy / Game Boy Color (DMG). Copre anche le repro GB in formato DMG.
|
||||
- `--mode agb` → Game Boy Advance. La modalità sbagliata produce header illeggibili o
|
||||
richieste di `--ignore-bad-header`: correggerla prima di ogni altra diagnosi.
|
||||
Executable
+132
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
# gb-cart.sh — wrapper deterministico per FlashGBX (lettore di cartucce Game Boy).
|
||||
# Niente path macchina-specifici: usa $HOME e le variabili d'ambiente.
|
||||
#
|
||||
# GB_MODE=dmg|agb modalità piattaforma (default: dmg)
|
||||
# FLASHGBX=flashgbx eseguibile (default: flashgbx dal PATH)
|
||||
# GB_BACKUP_DIR=... cartella backup (default: $HOME/gb-cart-backups)
|
||||
#
|
||||
# Uso:
|
||||
# gb-cart.sh detect
|
||||
# gb-cart.sh info
|
||||
# gb-cart.sh backup-rom [file.gb]
|
||||
# gb-cart.sh backup-save [file.sav]
|
||||
# gb-cart.sh flash-rom rom.gb [--flashcart-type NAME] [--force-5v] ...
|
||||
# gb-cart.sh verify file.gb
|
||||
#
|
||||
# flash-rom fa SEMPRE il backup del contenuto attuale prima di scrivere e chiede
|
||||
# conferma esplicita (GB_CART_ASSUME_YES=1 per l'uso non interattivo, consapevole).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
GB_MODE="${GB_MODE:-dmg}"
|
||||
FLASHGBX="${FLASHGBX:-flashgbx}"
|
||||
GB_BACKUP_DIR="${GB_BACKUP_DIR:-$HOME/gb-cart-backups}"
|
||||
STAMP="$(date +%Y-%m-%d_%H%M%S)"
|
||||
|
||||
die() { printf 'errore: %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
usage() { awk 'NR==1{next} /^#/{sub(/^# ?/,""); print; next} {exit}' "$0"; }
|
||||
|
||||
require_flashgbx() {
|
||||
command -v "$FLASHGBX" >/dev/null 2>&1 || die "eseguibile '$FLASHGBX' non trovato (FLASHGBX=path)"
|
||||
}
|
||||
|
||||
run() { # esegue flashgbx alimentando i prompt [y/N] con 'y'
|
||||
printf 'y\ny\ny\n' | "$FLASHGBX" --cli --mode "$GB_MODE" "$@" 2>&1 | tr '\r' '\n'
|
||||
}
|
||||
|
||||
cmd_detect() {
|
||||
echo "== lsusb (lettori noti: 0483:5740 Joey Jr | 1a86:7523 GBxCart RW/GBFlash | 1209:b010 Game Bub) =="
|
||||
(lsusb || true) | grep -iE "0483:5740|1a86:7523|1209:b010|STM32|Serial|CH34" || echo " nessun lettore noto in lsusb"
|
||||
echo "== porte seriali =="
|
||||
local ports
|
||||
ports="$(ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null || true)"
|
||||
if [ -n "$ports" ]; then
|
||||
# shellcheck disable=SC2086
|
||||
ls -l $ports
|
||||
else
|
||||
echo " nessuna /dev/ttyACM* o /dev/ttyUSB*"
|
||||
fi
|
||||
echo "== gruppi utente (serve dialout o uucp) =="
|
||||
id -nG
|
||||
}
|
||||
|
||||
cmd_info() { require_flashgbx; run --action info; }
|
||||
|
||||
cmd_backup_rom() {
|
||||
require_flashgbx
|
||||
local out="${1:-}"
|
||||
mkdir -p "$GB_BACKUP_DIR"
|
||||
[ -n "$out" ] || out="$GB_BACKUP_DIR/rom_${STAMP}.gb"
|
||||
echo ">> backup ROM in $out"
|
||||
run --action backup-rom --overwrite "$out"
|
||||
echo ">> hash del backup:"
|
||||
sha256sum "$out"
|
||||
}
|
||||
|
||||
cmd_backup_save() {
|
||||
require_flashgbx
|
||||
local out="${1:-}"
|
||||
mkdir -p "$GB_BACKUP_DIR"
|
||||
[ -n "$out" ] || out="$GB_BACKUP_DIR/save_${STAMP}.sav"
|
||||
echo ">> backup salvataggio in $out"
|
||||
run --action backup-save --overwrite --save-filename-add-datetime "$out"
|
||||
[ -f "$out" ] && sha256sum "$out" || echo " (nessun file .sav prodotto: verificare il Save Type o i nomi generati)"
|
||||
}
|
||||
|
||||
cmd_flash_rom() {
|
||||
require_flashgbx
|
||||
local rom="${1:-}"; shift || true
|
||||
[ -n "$rom" ] && [ -f "$rom" ] || die "serve il percorso di una ROM esistente"
|
||||
echo ">> ROM sorgente: $rom"
|
||||
sha256sum "$rom"
|
||||
echo
|
||||
echo ">> 1/2 backup obbligatorio del contenuto attuale"
|
||||
cmd_backup_rom
|
||||
echo
|
||||
if [ "${GB_CART_ASSUME_YES:-0}" != "1" ]; then
|
||||
printf 'La scrittura sovrascrive il contenuto della cartuccia ed è irreversibile.\nProcedo? [y/N] '
|
||||
read -r answer
|
||||
[ "$answer" = "y" ] || [ "$answer" = "Y" ] || die "annullato dall'utente"
|
||||
fi
|
||||
echo ">> 2/2 scrittura"
|
||||
run --action flash-rom --flashcart-type "${FLASHCART_TYPE:-autodetect}" "$@" "$rom"
|
||||
echo
|
||||
echo ">> verifica: rilettura indipendente e confronto hash"
|
||||
local verify="$GB_BACKUP_DIR/verify_${STAMP}.gb"
|
||||
run --action backup-rom --overwrite "$verify"
|
||||
if cmp -s "$verify" "$rom"; then
|
||||
echo "OK: la ROM riletta è identica alla sorgente"
|
||||
sha256sum "$verify"
|
||||
else
|
||||
echo "ATTENZIONE: la rilettura differisce dalla sorgente — NON considerare riuscita la scrittura" >&2
|
||||
sha256sum "$verify" "$rom"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_verify() {
|
||||
require_flashgbx
|
||||
local rom="${1:-}"
|
||||
[ -n "$rom" ] && [ -f "$rom" ] || die "serve il file di riferimento"
|
||||
mkdir -p "$GB_BACKUP_DIR"
|
||||
local verify="$GB_BACKUP_DIR/verify_${STAMP}.gb"
|
||||
run --action backup-rom --overwrite "$verify"
|
||||
if cmp -s "$verify" "$rom"; then
|
||||
echo "OK: contenuto della cartuccia identico a $rom"; sha256sum "$verify"
|
||||
else
|
||||
echo "DIFFERENZE rispetto a $rom:" >&2; sha256sum "$verify" "$rom"; exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
detect) shift; cmd_detect "$@" ;;
|
||||
info) shift; cmd_info "$@" ;;
|
||||
backup-rom) shift; cmd_backup_rom "$@" ;;
|
||||
backup-save) shift; cmd_backup_save "$@" ;;
|
||||
flash-rom) shift; cmd_flash_rom "$@" ;;
|
||||
verify) shift; cmd_verify "$@" ;;
|
||||
""|-h|--help|help) usage ;;
|
||||
*) die "comando sconosciuto: $1 (vedi --help)" ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user