532 lines
19 KiB
Markdown
532 lines
19 KiB
Markdown
# Architecture Documentation
|
|
|
|
## Overview
|
|
|
|
`pydownloadfwviasrio` implementa un sistema di programmazione flash remota che usa **SRIO-over-TFTP** per comunicare con un target hardware. L'implementazione replica fedelmente il protocollo del software C++ di riferimento (`dwl_fw.cpp`) con workflow identico per garantire compatibilità hardware.
|
|
|
|
### Componenti principali
|
|
|
|
1. **Sender (client)**: Applicazione Python con GUI Tkinter che invia comandi flash via TFTP
|
|
2. **Receiver (target/emulator)**: Server TFTP che decodifica comandi SRIO, gestisce registri flash controller e scrive su flash memory
|
|
3. **SRIO Flash Controller**: Layer che gestisce sequenze registro-flash (MODE_REG, CMD_REG, CTRL_REG, STATUS_REG, FIFO)
|
|
4. **Profiles System**: Configurazione multi-target con supporto GlobalConfig → FlashModel → FlashTarget hierarchy
|
|
|
|
## Protocollo SRIO-over-TFTP
|
|
|
|
### Architettura Registri Flash Controller
|
|
|
|
Il sistema emula un flash controller SRIO con registri mappati in memoria (da `dwl_fw.h`):
|
|
|
|
```c
|
|
// Register addresses (256-byte aligned)
|
|
#define MODE_REG 0x4700002C // Flash mode: 0x00=primary, 0x08=secondary
|
|
#define CMD_REG 0x47000030 // Flash command byte
|
|
#define ADDR_REG 0x47000034 // Flash memory address (32-bit)
|
|
#define NUM_BYTE_REG 0x47000038 // Number of bytes to transfer
|
|
#define CTRL_REG 0x47000060 // Control: 0x01=START, 0x00=END, 0x03=WRITE/READ
|
|
#define TX_FIFO_REG 0x47000400 // TX FIFO (256 bytes for write data)
|
|
#define STATUS_REG 0x47000864 // Status: bit[11]=busy/ack, bit[12]=tx_empty
|
|
#define RX_FIFO_REG 0x47000C00 // RX FIFO (256 bytes for read data/status)
|
|
```
|
|
|
|
### Formato comando TFTP
|
|
|
|
I comandi SRIO vengono codificati nel **filename TFTP** secondo questo schema:
|
|
|
|
```
|
|
$SRIO:<slot>/<address>+<length>
|
|
```
|
|
|
|
**Esempi:**
|
|
- `$SRIO:0x13/0x4700002C+256` → Write 256 byte a MODE_REG (registro)
|
|
- `$SRIO:0x13/0x47000400+256` → Write 256 byte a TX_FIFO_REG (dati flash)
|
|
- `$SRIO:0x13/0x01000000+256` → Write/Read 256 byte flash address 0x01000000
|
|
|
|
### Operazioni Base
|
|
|
|
#### Write Register (TFTP PUT)
|
|
```python
|
|
# Scrive valore 0x06 a MODE_REG
|
|
data = struct.pack('<I', 0x06) # 4 byte little-endian
|
|
padded = data + b'\x00' * 252 # Pad a 256 byte
|
|
client.srio_write(slot="0x13", address=MODE_REG, data=padded)
|
|
```
|
|
|
|
#### Read Register (TFTP GET)
|
|
```python
|
|
# Legge STATUS_REG
|
|
block = client.srio_read(slot="0x13", address=STATUS_REG, length=256)
|
|
status = struct.unpack('<I', block[STATUS_REG & 0xFF : (STATUS_REG & 0xFF)+4])[0]
|
|
```
|
|
|
|
## Workflow Flash Operations (da dwl_fw.cpp)
|
|
|
|
### 1. Inizializzazione QSPI
|
|
|
|
Eseguita automaticamente al primo erase/write/verify (chiamata 2 volte come da `main()` line 713-714):
|
|
|
|
```python
|
|
def op_init_qspi(endpoint):
|
|
"""dwl_fw.cpp line 299-323"""
|
|
# Write Enable
|
|
srio_write_reg(endpoint, MODE_REG, 0x00 + flashport)
|
|
srio_write_reg(endpoint, CMD_REG, 0x06)
|
|
send_request(endpoint)
|
|
|
|
# Write Volatile Config Register (0x61, data=0x6F)
|
|
srio_write_reg(endpoint, MODE_REG, 0x00 + flashport)
|
|
srio_write_reg(endpoint, CMD_REG, 0x61)
|
|
start_request(endpoint)
|
|
srio_write_reg(endpoint, TX_FIFO_REG, 0x6F)
|
|
write_data(endpoint)
|
|
|
|
# Write Enable again
|
|
srio_write_reg(endpoint, MODE_REG, 0x02 + flashport)
|
|
srio_write_reg(endpoint, CMD_REG, 0x06)
|
|
send_request(endpoint)
|
|
|
|
# Enter 4-byte address mode (0xB7)
|
|
srio_write_reg(endpoint, MODE_REG, 0x02 + flashport)
|
|
srio_write_reg(endpoint, CMD_REG, 0xB7)
|
|
send_request(endpoint)
|
|
```
|
|
|
|
**Chiamata nel main:**
|
|
```cpp
|
|
op_init_qspi(endpoint); // Prima chiamata
|
|
op_init_qspi(endpoint); // Seconda chiamata (dwl_fw.cpp line 713-714)
|
|
```
|
|
|
|
### 2. Erase Sector (64KB)
|
|
|
|
```python
|
|
def erase_section(endpoint, address):
|
|
"""dwl_fw.cpp line 580-594"""
|
|
# Write Enable
|
|
srio_write_reg(endpoint, MODE_REG, 0x02 + flashport)
|
|
srio_write_reg(endpoint, CMD_REG, 0x06)
|
|
send_request(endpoint)
|
|
|
|
# Sector Erase command (0xD8)
|
|
srio_write_reg(endpoint, MODE_REG, 0x06 + flashport)
|
|
srio_write_reg(endpoint, ADDR_REG, address)
|
|
srio_write_reg(endpoint, NUM_BYTE_REG, 0x00)
|
|
srio_write_reg(endpoint, CMD_REG, 0xD8)
|
|
send_request(endpoint)
|
|
|
|
def wait_flash(endpoint):
|
|
"""dwl_fw.cpp line 500-513"""
|
|
# Read flash status register (0x05)
|
|
srio_write_reg(endpoint, MODE_REG, 0x06 + flashport)
|
|
srio_write_reg(endpoint, CMD_REG, 0x05)
|
|
read_data(endpoint)
|
|
srio_wait_reg(endpoint, RX_FIFO_REG, bit=0, value=0) # Wait bit[0]=0 (ready)
|
|
end_request(endpoint)
|
|
|
|
# Main erase loop (dwl_fw.cpp line 723-733)
|
|
for i in range(0, file_size, ERASE_BLOCK_SIZE):
|
|
erase_section(endpoint, start_address + i)
|
|
wait_flash_with_retry(endpoint, MAX_RETRY_READ=1000, timeout_us=1000)
|
|
```
|
|
|
|
### 3. Write Flash (256 byte chunks)
|
|
|
|
```python
|
|
def write_flash(endpoint, address, data_256bytes):
|
|
"""dwl_fw.cpp line 555-578"""
|
|
# Write Enable
|
|
srio_write_reg(endpoint, MODE_REG, 0x02 + flashport)
|
|
srio_write_reg(endpoint, CMD_REG, 0x06)
|
|
send_request(endpoint)
|
|
|
|
# Page Program command (0x02)
|
|
srio_write_reg(endpoint, MODE_REG, 0x06 + flashport)
|
|
srio_write_reg(endpoint, ADDR_REG, address)
|
|
srio_write_reg(endpoint, NUM_BYTE_REG, 256)
|
|
srio_write_reg(endpoint, CMD_REG, 0x02)
|
|
start_request(endpoint)
|
|
srio_write_data(endpoint, TX_FIFO_REG, data_256bytes)
|
|
write_data(endpoint)
|
|
|
|
# Main write loop (dwl_fw.cpp line 747-767)
|
|
address = start_address
|
|
for chunk in chunks_256bytes:
|
|
write_flash(endpoint, address, chunk)
|
|
usleep(WRITE_DELAY_US) # 100ms delay (line 562)
|
|
wait_flash_with_retry(endpoint, MAX_RETRY_READ=1000, timeout_us=1000)
|
|
usleep(WAITFLASH_DELAY_US) # 100ms delay (line 564)
|
|
address += 256
|
|
```
|
|
|
|
### 4. Read/Verify Flash
|
|
|
|
```python
|
|
def read_flash(endpoint, address, num_bytes):
|
|
"""dwl_fw.cpp line 344-358"""
|
|
# Fast Read command (0x0B)
|
|
srio_write_reg(endpoint, MODE_REG, 0x06 + flashport)
|
|
srio_write_reg(endpoint, ADDR_REG, address)
|
|
srio_write_reg(endpoint, NUM_BYTE_REG, num_bytes)
|
|
srio_write_reg(endpoint, CMD_REG, 0x0B)
|
|
read_data(endpoint)
|
|
data = srio_read_reg(endpoint, RX_FIFO_REG, num_bytes)
|
|
end_request(endpoint)
|
|
return data
|
|
```
|
|
|
|
### Macro SRIO (dwl_fw.cpp line 235-293)
|
|
|
|
```python
|
|
def start_request(endpoint):
|
|
"""Set CTRL=0x01, wait STATUS[11]=1"""
|
|
srio_write_reg(endpoint, CTRL_REG, 0x01)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=11, value=1)
|
|
|
|
def end_request(endpoint):
|
|
"""Check error bits, set CTRL=0x00, wait STATUS[11]=0"""
|
|
for bit in [1, 4, 5, 6, 10]:
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=bit, value=0)
|
|
srio_write_reg(endpoint, CTRL_REG, 0x00)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=11, value=0)
|
|
|
|
def send_request(endpoint):
|
|
"""Full request: START → WRITE/READ → END"""
|
|
start_request(endpoint)
|
|
srio_write_reg(endpoint, CTRL_REG, 0x03)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=12, value=1)
|
|
srio_write_reg(endpoint, CTRL_REG, 0x01)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=12, value=0)
|
|
end_request(endpoint)
|
|
|
|
def write_data(endpoint):
|
|
"""Write TX_FIFO data to flash"""
|
|
srio_write_reg(endpoint, CTRL_REG, 0x03)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=12, value=1)
|
|
srio_write_reg(endpoint, CTRL_REG, 0x01)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=12, value=0)
|
|
end_request(endpoint)
|
|
|
|
def read_data(endpoint):
|
|
"""Read flash data into RX_FIFO"""
|
|
start_request(endpoint)
|
|
srio_write_reg(endpoint, CTRL_REG, 0x03)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=12, value=1)
|
|
srio_write_reg(endpoint, CTRL_REG, 0x01)
|
|
srio_wait_reg(endpoint, STATUS_REG, bit=12, value=0)
|
|
```
|
|
|
|
## Gestione Profili (Hierarchy System)
|
|
|
|
### Struttura a 3 livelli
|
|
|
|
```
|
|
GlobalConfig
|
|
├─ ip: "192.168.1.100"
|
|
├─ port: 69
|
|
├─ default_target: "TGT-DWL_BRD-1"
|
|
│
|
|
├─ FlashModel (MODEL-1)
|
|
│ ├─ model: "MT25QL128"
|
|
│ ├─ flash_type: "NOR"
|
|
│ ├─ is_4byte_addressing: false
|
|
│ ├─ num_sectors: 256
|
|
│ ├─ golden_start: 0x00000000
|
|
│ ├─ golden_stop: 0x007FFFFF
|
|
│ ├─ user_start: 0x00800000
|
|
│ └─ user_stop: 0x00FFFFFF
|
|
│
|
|
└─ FlashTarget (TGT-1)
|
|
├─ id_target: "TGT-DWL_BRD-1"
|
|
├─ slot_address: 0x13
|
|
├─ architecture: "PowerPC"
|
|
├─ model: "MODEL-1" (→ riferimento a FlashModel)
|
|
├─ golden_binary_path: "C:/firmware/golden.bin"
|
|
└─ user_binary_path: "C:/firmware/user.bin"
|
|
```
|
|
|
|
### Caricamento da targets.ini
|
|
|
|
```ini
|
|
[default]
|
|
ip = 192.168.1.100
|
|
port = 69
|
|
default_target = TGT-DWL_BRD-1
|
|
|
|
[MODEL-1]
|
|
model = MT25QL128
|
|
description = Micron 128Mbit NOR Flash
|
|
flash_type = NOR
|
|
is_4byte_addressing = false
|
|
num_sectors = 256
|
|
golden_start = 0x00000000
|
|
golden_stop = 0x007FFFFF
|
|
user_start = 0x00800000
|
|
user_stop = 0x00FFFFFF
|
|
|
|
[TGT-1]
|
|
id_target = TGT-DWL_BRD-1
|
|
description = Download Board #1
|
|
slot_address = 0x13
|
|
architecture = PowerPC
|
|
model = MODEL-1
|
|
golden_binary_path =
|
|
user_binary_path =
|
|
```
|
|
|
|
### ProfileManager
|
|
|
|
```python
|
|
manager = ProfileManager()
|
|
manager.load_from_ini(Path("targets.ini")) # Carica da INI
|
|
manager.export_to_ini(Path("targets.ini")) # Salva su INI
|
|
manager.save() # Persiste in flash_profiles.json
|
|
manager.load() # Carica da flash_profiles.json
|
|
|
|
# Ottieni target con modello
|
|
target, model = manager.get_target_with_model("TGT-DWL_BRD-1")
|
|
```
|
|
|
|
## File Structure
|
|
|
|
```
|
|
pydownloadfwviasrio/
|
|
├── core/
|
|
│ ├── core.py # FirmwareFlasher (high-level erase/write/verify)
|
|
│ └── srio_flash.py # SRIOFlashController (low-level register protocol)
|
|
├── gui/
|
|
│ └── gui.py # FlasherGUI (Tkinter UI con dual logs)
|
|
├── gui/
|
|
│ └── gui.py # FlasherGUI (Tkinter UI con dual logs)
|
|
├── profiles.py # GlobalConfig, FlashModel, FlashTarget, ProfileManager
|
|
├── tftp_client.py # SimpleTFTPClient + SRIOTFTPClient (TFTP sender)
|
|
└── __main__.py # Entry point
|
|
|
|
tools/
|
|
└── tftp_receiver.py # TFTP server emulator con simulazione flash controller
|
|
|
|
_OLD/
|
|
├── linux_app/
|
|
│ ├── dwl_fw.cpp # ⭐ REFERENCE implementation (native SRIO Linux)
|
|
│ └── dwl_fw.h # Register definitions
|
|
└── Vecchia_app/
|
|
└── FpgaBeamMeUp/ # Vecchia Qt app (SRIO-over-TFTP sender)
|
|
├── fpgaflashengine.cpp
|
|
├── fpgaflashinterface.h
|
|
└── fgpaprogrammer.cpp
|
|
```
|
|
|
|
## GUI Features
|
|
|
|
### Main Window
|
|
|
|
- **Target Selector**: ComboBox con lista target da `flash_profiles.json`
|
|
- **Target Info Panel**: Visualizza IP, porta, slot SRIO, modello flash, aree memoria, path binari golden/user
|
|
- **Operation Buttons**: Erase, Write, Verify, Erase+Write+Verify
|
|
- **Progress Bar**: Barra progresso con percentuale
|
|
- **Dual Log Panels**:
|
|
- **General Log** (sinistra): Messaggi applicazione, errori, progress
|
|
- **TFTP Commands** (destra, monospace): Trace protocollo TFTP (PUT/GET con indirizzi)
|
|
|
|
### Configuration Manager (3 Tabs)
|
|
|
|
1. **Global Tab**: IP, porta TFTP, target di default
|
|
2. **Flash Models Tab**: Lista modelli flash con editor inline (tipo, addressing, settori, aree golden/user)
|
|
3. **Targets Tab**: Lista target con editor inline (slot SRIO, modello, architettura, path binari)
|
|
|
|
### Memory Area Selection Dialog
|
|
|
|
Quando si preme Erase/Write/Verify, appare dialog per scegliere:
|
|
- **Golden Area**: Mostra indirizzo start-stop da modello flash
|
|
- **User Area**: Mostra indirizzo start-stop da modello flash
|
|
- Usa il path binario corrispondente configurato nel target
|
|
|
|
## Testing Locale
|
|
|
|
### 1. Avvia il server TFTP emulator
|
|
```powershell
|
|
python tools/tftp_receiver.py --port 6969 --workdir ./tftp_root
|
|
```
|
|
|
|
Il server:
|
|
- Simula registri SRIO (MODE_REG, CMD_REG, CTRL_REG, STATUS_REG, FIFO)
|
|
- Gestisce state machine flash controller (START/END request, bit polling)
|
|
- Esegue operazioni flash (erase sector → 0xFF, write → salva in file, read → legge da file)
|
|
- Logga tutte le operazioni:
|
|
```
|
|
SRIO WRITE: slot=0x13, addr=0x4700002C, len=256
|
|
MODE_REG = 0x06
|
|
SRIO WRITE: slot=0x13, addr=0x47000030, len=256
|
|
CMD_REG = 0xD8
|
|
SRIO WRITE: slot=0x13, addr=0x47000060, len=256
|
|
CTRL_REG = 0x03 → WRITE/READ_DATA (STATUS[12]=1)
|
|
→ Flash: ERASE sector at 0x01000000
|
|
```
|
|
|
|
### 2. Avvia la GUI
|
|
```powershell
|
|
python -m pydownloadfwviasrio
|
|
```
|
|
|
|
### 3. Configura target di test
|
|
|
|
In Configuration Manager → Global Tab:
|
|
- IP: `127.0.0.1`
|
|
- Port: `6969`
|
|
|
|
Oppure crea target in `targets.ini`:
|
|
```ini
|
|
[TGT-TEST]
|
|
id_target = TGT-TEST-LOCAL
|
|
slot_address = 0x13
|
|
model = MODEL-1
|
|
golden_binary_path = C:/test/golden_test.bin
|
|
user_binary_path = C:/test/user_test.bin
|
|
```
|
|
|
|
### 4. Testa operazioni
|
|
|
|
1. Seleziona target test
|
|
2. Premi "Write" → Scegli "User Area" → Seleziona file binario
|
|
3. Verifica log TFTP panel (destra) per vedere comandi SRIO
|
|
4. Verifica server console per vedere operazioni flash
|
|
|
|
## Compatibilità con Vecchia_app
|
|
|
|
Il protocollo è **100% compatibile** con il formato usato da `FpgaBeamMeUp`:
|
|
- ✅ Stesso schema filename: `$SRIO:<slot>/<address>+<len>`
|
|
- ✅ Stesso chunk size: 256 byte (dwl_fw.cpp DWL_CHUNK_SIZE)
|
|
- ✅ Stesso comportamento TFTP read/write
|
|
- ✅ Stessa sequenza registri flash (da dwl_fw.cpp)
|
|
|
|
**Differenze (miglioramenti):**
|
|
- ✅ **Semplificato**: nessun Qt event loop, nessun layer FpgaFlashEngine/FlashOperation
|
|
- ✅ **Workflow identico a dwl_fw.cpp**: stesso ordine operazioni, stessi delay (100ms)
|
|
- ✅ **Dual log**: separazione log applicazione vs protocollo TFTP
|
|
- ✅ **Testabile**: emulator locale con simulazione completa registri
|
|
- ✅ **Type-safe**: type hints Python, no casting void*
|
|
- ✅ **Cross-platform**: nessuna dipendenza Qt, Windows/Linux ready
|
|
|
|
## Riferimenti Codice Legacy
|
|
|
|
### dwl_fw.cpp (Linux SRIO nativo) ⭐ REFERENCE
|
|
|
|
- **main()**: Sequenza completa erase→write (line 600-792)
|
|
- `op_init_qspi()` x2 (line 713-714)
|
|
- Erase loop con `wait_flash_with_retry()` (line 723-733)
|
|
- Write loop con delay 100ms + wait + delay 100ms (line 747-767)
|
|
- **Macro SRIO**: `start_request()`, `end_request()`, `send_request()`, `write_data()`, `read_data()` (line 235-293)
|
|
- **Flash ops**: `erase_section()`, `write_flash()`, `read_flash()`, `wait_flash()` (line 344-594)
|
|
- **Constants**: `WRITE_DELAY_US=100000`, `WAITFLASH_DELAY_US=100000`, `MAX_RETRY_READ=1000` (line 18-20)
|
|
|
|
### fgpaprogrammer.cpp (Qt SRIO-over-TFTP sender)
|
|
|
|
- **rtgWrite()**: TFTP PUT con filename `$SRIO:<slot>/0x<address>+<len>` (line 194-260)
|
|
- **rtgRead()**: TFTP GET (line 338-410)
|
|
- **Retry logic**: `NUM_REPEAT_WRITE`, `NUM_REPEAT_READ`, exponential backoff (line 225-240)
|
|
|
|
### qgtftptargetsim.cpp (Qt TFTP server emulator)
|
|
|
|
- **bsk_tftpd_receive_delegate()**: Decodifica filename SRIO e gestisce operazioni (line 178-279)
|
|
- **bsk_tftp_mfs_decode_filename()**: Parser filename `$SRIO:` format (line 235)
|
|
|
|
### fpgaflashengine.cpp / fpgaflashinterface.h (Qt flash abstraction)
|
|
|
|
- Layer troppo complesso per le nostre esigenze
|
|
- Usavamo solo per riferimento architetturale (simulator pattern)
|
|
|
|
## Decisioni Architetturali
|
|
|
|
### Perché TFTP e non TCP/UDP custom?
|
|
- ✅ TFTP è standard RFC 1350, testabile con tool esterni (`tftp`, Wireshark)
|
|
- ✅ Target hardware espone già server TFTP funzionante
|
|
- ✅ Compatibilità con infrastruttura esistente
|
|
- ✅ Debugging semplice: filename in chiaro nei log
|
|
|
|
### Perché filename-as-command?
|
|
- ✅ Evita di implementare protocollo binario custom
|
|
- ✅ Parsing trivial (regex su stringa)
|
|
- ✅ Self-documenting (log leggibili)
|
|
- ✅ Compatibile con vecchia app Qt
|
|
|
|
### Perché Python e non C++?
|
|
- ✅ Rapid prototyping e facilità test
|
|
- ✅ Cross-platform senza ricompilare
|
|
- ✅ Type hints moderni (meglio di Qt C++ pre-C++11)
|
|
- ✅ GUI Tkinter nativa (no dipendenze Qt)
|
|
- ✅ TFTP client custom minimale (no `tftpy` issues con `fcntl` Windows)
|
|
|
|
### Perché SRIOFlashController separato da FirmwareFlasher?
|
|
- ✅ **Separation of Concerns**:
|
|
- `SRIOFlashController`: Low-level register protocol (dwl_fw.cpp lines 100-594)
|
|
- `FirmwareFlasher`: High-level flash operations (dwl_fw.cpp main loop)
|
|
- ✅ **Testability**: Posso testare controller SRIO senza file binari
|
|
- ✅ **Reusability**: Controller riutilizzabile per altre operazioni SRIO
|
|
|
|
### Perché dual log panels?
|
|
- ✅ **Debugging**: TFTP trace separato dai messaggi applicazione
|
|
- ✅ **User Experience**: Utente vede progress in General Log, developer vede protocollo in TFTP Log
|
|
- ✅ **Protocol Analysis**: Facile confrontare sequenza TFTP con dwl_fw.cpp
|
|
|
|
## Features Implementate
|
|
|
|
### Core
|
|
- ✅ **SRIO Flash Controller**: Gestione completa registri (MODE, CMD, CTRL, STATUS, FIFO)
|
|
- ✅ **QSPI Init**: `op_init_qspi()` chiamato 2x automaticamente (dwl_fw.cpp line 713-714)
|
|
- ✅ **Erase**: Sector erase 64KB con `wait_flash_with_retry(MAX_RETRY_READ=1000)`
|
|
- ✅ **Write**: 256-byte chunks con delay 100ms + wait + delay 100ms (dwl_fw.cpp line 561-564)
|
|
- ✅ **Verify**: Read back e confronto byte-by-byte
|
|
- ✅ **Retry Logic**: Exponential backoff su timeout TFTP (max 3 attempts)
|
|
- ✅ **Timing**: Delay esatti da dwl_fw.cpp (WRITE_DELAY_US, WAITFLASH_DELAY_US)
|
|
|
|
### GUI
|
|
- ✅ **Target Selection**: ComboBox con lista da flash_profiles.json
|
|
- ✅ **Info Panel**: IP, slot, modello, aree memoria, path binari golden/user
|
|
- ✅ **Dual Logs**: General + TFTP (monospace per trace protocollo)
|
|
- ✅ **Progress Bar**: Percentuale e barra visuale
|
|
- ✅ **Memory Area Dialog**: Selezione golden/user con indirizzi visibili
|
|
- ✅ **Config Manager**: 3 tabs (Global, Models, Targets) con edit inline
|
|
|
|
### Configuration
|
|
- ✅ **INI Support**: Caricamento/salvataggio `targets.ini` format
|
|
- ✅ **JSON Persistence**: `flash_profiles.json` per stato runtime
|
|
- ✅ **3-Level Hierarchy**: GlobalConfig → FlashModel → FlashTarget
|
|
- ✅ **Binary Paths**: golden_binary_path + user_binary_path per target
|
|
- ✅ **Migration**: Tool per convertire vecchi profili (tools/migrate_profiles_json.py)
|
|
|
|
### Testing
|
|
- ✅ **TFTP Server Emulator**: Simulazione completa flash controller
|
|
- Registri SRIO (MODE_REG, CMD_REG, CTRL_REG, STATUS_REG, FIFO)
|
|
- State machine (START/END request, bit polling)
|
|
- Flash operations (erase → 0xFF, write → file, read → file)
|
|
- Logging dettagliato operazioni
|
|
- ✅ **Local Testing**: Server + client su localhost per test senza hardware
|
|
|
|
## Prossimi Step Possibili
|
|
|
|
1. **Logging su File**: Salvare log operazioni in file per audit e debug
|
|
2. **Test Hardware Reale**: Validare con target fisico e confrontare timing con dwl_fw.cpp
|
|
3. **Checksum Verification**: Aggiungere CRC32/MD5 per verifica integrità file
|
|
4. **Batch Operations**: Supporto per programmare multipli target in parallelo
|
|
5. **Profile Import/Export**: Esportazione profili tra macchine diverse
|
|
6. **Wireshark Dissector**: Plugin per decode pacchetti TFTP con `$SRIO:` format
|
|
|
|
## Troubleshooting
|
|
|
|
### TFTP Timeout
|
|
- **Causa**: Server non raggiungibile o firewall blocca porta 69/6969
|
|
- **Soluzione**: Verificare con `ping <ip>`, disabilitare firewall per test, controllare porta con `netstat`
|
|
|
|
### Flash Write Failed
|
|
- **Causa**: QSPI non inizializzato, flash protetto write, bad sector
|
|
- **Soluzione**: Verificare log TFTP per sequenza `op_init_qspi()`, controllare STATUS_REG error bits
|
|
|
|
### Verify Mismatch
|
|
- **Causa**: Flash non scritta correttamente, read timeout, bit flip
|
|
- **Soluzione**: Ripetere erase+write, aumentare retry count, controllare checksum file sorgente
|
|
|
|
### Server Not Responding
|
|
- **Causa**: Server TFTP emulator non avviato, porta già in uso
|
|
- **Soluzione**: `python tools/tftp_receiver.py --port 6969`, controllare con `netstat -an | findstr 6969`
|
|
|
|
|