# Profile Management System

## Overview

Il sistema di gestione dei profili è stato completamente ristrutturato per supportare una configurazione gerarchica a tre livelli che rispecchia fedelmente il formato `targets.ini` della vecchia applicazione C++/Qt.

## Struttura

### 1. GlobalConfig
Configurazione globale del sistema:
- **ip**: Indirizzo IP per la comunicazione SRIO
- **port**: Porta per comunicazione TFTP/SRIO
- **srio_base**: Indirizzo base SRIO (es. 0x500000)
- **fpga_base**: Indirizzo base FPGA (es. 0x0)
- **fpga_sector**: Dimensione settore FPGA (es. 0x010000)
- **smart**: Flag modalità smart (0 o 1)
- **section**: Sezione flash di default (es. "APP1")
- **default_target**: Target di default da usare

### 2. FlashModel
Definizione riutilizzabile di modelli FPGA:
- **id_model**: ID univoco del modello (0, 1, 2, ...)
- **model**: Nome del modello (es. "xcku040", "rfif")
- **description**: Descrizione leggibile
- **flash_type**: Tipo di flash (0 o 1)
- **is_4byte_addressing**: True per indirizzamento a 4 byte
- **num_sectors**: Numero totale di settori
- **golden_start/stop**: Area Golden (firmware di boot)
- **user_start/stop**: Area User (firmware applicativo)
- **test_address**: Indirizzo opzionale per test

### 3. FlashTarget
Target specifico (FPGA installata):
- **id_target**: ID univoco del target (es. "EIF_FPGA1")
- **description**: Descrizione leggibile
- **slot_address**: Indirizzo slot SRIO (es. 0x13)
- **architecture**: Architettura (es. "Xilinx", "RFIF")
- **name**: Nome del target
- **file_prefix**: Prefisso per i file firmware
- **id_model**: Riferimento all'ID del modello
- **binary_path**: Path opzionale al file binario

## Utilizzo

### Caricamento da INI

```python
from pathlib import Path
from pydownloadfwviasrio.profiles import ProfileManager

# Crea manager e carica da targets.ini
manager = ProfileManager()
manager.load_from_ini(Path("_OLD/Vecchia_app/FpgaBeamMeUp/targets.ini"))

# Salva in formato JSON
manager.config_path = Path("flash_profiles.json")
manager.save()
```

### Caricamento da JSON

```python
from pydownloadfwviasrio.profiles import ProfileManager

# Carica configurazione esistente
manager = ProfileManager(Path("flash_profiles.json"))

# Accedi alla configurazione globale
print(f"IP: {manager.global_config.ip}")
print(f"Port: {manager.global_config.port}")
```

### Accesso ai Target e Modelli

```python
# Ottieni un target specifico
target = manager.get_target("AESA_RFIF")
if target:
    print(f"Slot: 0x{target.slot_address:02X}")
    print(f"Architecture: {target.architecture}")

# Ottieni il modello associato
model = manager.get_model(target.id_model)
if model:
    print(f"Model: {model.model}")
    print(f"Sectors: {model.num_sectors}")
    print(f"Addressing: {'4-byte' if model.is_4byte_addressing else '3-byte'}")

# O usa il metodo comodo per ottenere entrambi
result = manager.get_target_with_model("AESA_RFIF")
if result:
    target, model = result
    # ... usa target e model
```

### Iterazione sui Target

```python
# Lista tutti i target disponibili
for id_target in manager.list_targets():
    target = manager.get_target(id_target)
    model = manager.get_model(target.id_model)
    print(f"{id_target}: {target.description}")
    print(f"  Model: {model.model} ({model.description})")
```

### Aggiunta/Modifica

```python
from pydownloadfwviasrio.profiles import FlashModel, FlashTarget

# Aggiungi un nuovo modello
new_model = FlashModel(
    id_model=3,
    model="xcku115",
    description="512Mbit xcku115",
    flash_type=1,
    is_4byte_addressing=True,
    num_sectors=1024,
    golden_start=0x00000000,
    golden_stop=0x01FFFFFF,
    user_start=0x02000000,
    user_stop=0x03FFFFFF,
)
manager.add_model(new_model)

# Aggiungi un nuovo target
new_target = FlashTarget(
    id_target="TEST_FPGA1",
    description="Test FPGA 0x20",
    slot_address=0x20,
    architecture="Xilinx",
    name="TEST_FPGA1",
    file_prefix="TEST_FPGA1",
    id_model=3,  # Riferimento al modello appena creato
)
manager.add_target(new_target)

# Salva le modifiche
manager.save()
```

### Esportazione in INI

```python
# Esporta la configurazione in formato INI
manager.export_to_ini(Path("new_targets.ini"))
```

## Vantaggi della Nuova Struttura

1. **DRY (Don't Repeat Yourself)**: I modelli si definiscono una volta sola e vengono referenziati dai target
2. **Manutenibilità**: Modifiche al modello si propagano automaticamente a tutti i target che lo usano
3. **Estensibilità**: Facile aggiungere nuovi target senza duplicare configurazioni
4. **Retrocompatibilità**: Supporta sia formato JSON che INI
5. **Type Safety**: Uso di dataclass con type hints per validazione automatica

## Migrazione da Vecchio Formato

Il vecchio formato (lista di `FlashProfile`) è deprecato ma ancora supportato per retrocompatibilità.
Per convertire:

```python
from pydownloadfwviasrio.profiles import initialize_from_targets_ini

# Conversione automatica da targets.ini
manager = initialize_from_targets_ini(
    ini_path=Path("_OLD/Vecchia_app/FpgaBeamMeUp/targets.ini"),
    json_path=Path("flash_profiles.json")
)
```

## File di Configurazione Iniziali

Il progetto include già un file `flash_profiles.json` generato dal `targets.ini` originale con:
- **3 modelli**: xcku040, xcku060, rfif
- **9 target**: EIF_FPGA1/2, XIF1_FPGA1/2, XIF2_FPGA1/2, DFE_FPGA1/2, AESA_RFIF

## Script di Utilità

Nella cartella `tools/` sono disponibili:

- **convert_ini_to_json.py**: Converte targets.ini in flash_profiles.json
- **example_profile_usage.py**: Esempio completo di utilizzo del sistema
- **test_conversion.py**: Test di conversione bidirezionale INI ↔ JSON

## Esempio Completo

```python
from pathlib import Path
from pydownloadfwviasrio.profiles import ProfileManager

# Carica configurazione
manager = ProfileManager(Path("flash_profiles.json"))

# Ottieni target di default con modello
default_id = manager.global_config.default_target
result = manager.get_target_with_model(default_id)

if result:
    target, model = result
    
    print(f"Programming target: {target.id_target}")
    print(f"Slot address: 0x{target.slot_address:02X}")
    print(f"IP:Port: {manager.global_config.ip}:{manager.global_config.port}")
    print(f"Model: {model.model}")
    print(f"Flash type: {model.flash_type}")
    print(f"Addressing: {'4-byte' if model.is_4byte_addressing else '3-byte'}")
    print(f"Golden area: 0x{model.golden_start:08X} - 0x{model.golden_stop:08X}")
    print(f"User area: 0x{model.user_start:08X} - 0x{model.user_stop:08X}")
    
    # Qui puoi usare questi dati per la programmazione...
```
