# Capitolo 5: Modalità di Esecuzione

[← Workflow Test](04_Sistema_Test_Workflow_Logica.md) | [Torna all'Indice](00_INDEX.md) | [Prossimo: GUI →](06_Interfaccia_Grafica_GUI.md)

---

## 5.1 Panoramica Modalità

Il sistema supporta **due modalità di esecuzione** distinte, progettate per coprire scenari diversi:

| Modalità | Uso Principale | Hardware Richiesto | Velocità | Determinismo |
|----------|----------------|-------------------|----------|--------------|
| **Hardware** (`--target`) | Validation su radar reale, test integrazione | Radar + 1553 + Seriale + Power | ~60-80s/run | Basso (timing reali) |
| **Simulazione** (`--simulate`) | Development, debugging, regression testing | Solo PC | ~10-15s/run | Alto (mock deterministici) |

### 5.1.1 Quando Usare Quale Modalità

**Usa Hardware Mode quando**:
- ✅ Validazione finale prima del rilascio
- ✅ Test di integrazione HW/SW
- ✅ Identificazione timing issues o race conditions
- ✅ Verifica comportamento sotto condizioni reali (temperatura, EMI, ecc.)
- ✅ Cattura failure intermittenti

**Usa Simulation Mode quando**:
- ✅ Sviluppo locale senza accesso hardware
- ✅ Debugging rapido di logica test
- ✅ Regression testing in CI/CD pipeline
- ✅ Test scenari rari (failure multipli, edge cases)
- ✅ Validazione modifiche codice senza rischio hardware

## 5.2 Modalità Hardware (`--target`)

### 5.2.1 Configurazione Hardware

**Setup Fisico Richiesto**:
```
┌─────────────────────────────────────────────────────────┐
│                      Test PC                             │
│  ┌──────────────────────────────────────────────────┐  │
│  │  GRIFO_M_PBIT.py                                 │  │
│  │  - Python 3.8                                    │  │
│  │  - interpreter.pyd (1553 driver)                 │  │
│  │  - pyserial (serial driver)                      │  │
│  └───┬──────────────────────────────────────┬───────┘  │
└──────┼──────────────────────────────────────┼──────────┘
       │                                      │
       │ 1553 Bus                             │ Serial RS-232
       ↓                                      ↓
┌──────────────────────────────────────────────────────────┐
│                    GRIFO Radar                            │
│  - RT Address: 1                                          │
│  - 1553 Messages: A1-A5 (BC→RT), B6-B9 (RT→BC)          │
│  - Serial Port: 115200 baud, 8N1                         │
└───────────────────────────┬──────────────────────────────┘
                            │
                            │ Power Control
                            ↓
                    ┌────────────────┐
                    │   BrainBox     │
                    │  (Power Relay) │
                    └────────────────┘
```

**Connessioni Fisiche**:
1. **1553 Bus**: Scheda 1553 PC ↔ Radar (BC-RT topology)
2. **Seriale**: COM port PC ↔ Radar RS-232
3. **Power Control** (opzionale): BrainBox COM port ↔ PC

### 5.2.2 Esecuzione Hardware

**Launcher Script: `run_target.bat`**

```batch
@echo off
REM ============================================================
REM run_target.bat - Execute test on real GRIFO hardware
REM ============================================================

echo ╔════════════════════════════════════════════════════════╗
echo ║   GRIFO M-PBIT Test - HARDWARE MODE (--target)         ║
echo ╚════════════════════════════════════════════════════════╝
echo.

REM Check hardware connections
echo [INFO] Checking hardware connections...
echo   - 1553 Bus: Check BC-RT connection
echo   - Serial Port: COM4 (verify in Device Manager)
echo   - Power Control: BrainBox on COM3
echo.

pause

REM Set Python path (use embedded Python from PlatformSimulator)
set PYTHON_HOME=%~dp0PlatformSimulator\bin
set PATH=%PYTHON_HOME%;%PATH%

REM Navigate to scripts directory
cd TestEnvironment\scripts

REM Execute test with target mode
echo [INFO] Starting test execution...
python GRIFO_M_PBIT.py --target --runs 10

REM Check exit code
if %ERRORLEVEL% NEQ 0 (
    echo [ERROR] Test execution failed with error code %ERRORLEVEL%
    pause
    exit /b %ERRORLEVEL%
)

echo.
echo [SUCCESS] Test completed successfully
echo [INFO] Reports saved to: TestEnvironment\pdf_reports\
echo.

pause
```

**Esecuzione Diretta**:
```bash
# Dalla root del repository
cd TestEnvironment/scripts
python GRIFO_M_PBIT.py --target --runs 10 --scenario random
```

**Parametri CLI Disponibili**:
```bash
python GRIFO_M_PBIT.py --target \
    --runs 10 \                    # Numero ripetizioni (default: 10)
    --scenario random \            # Scenario test (default: random)
    --no-gui \                     # Disabilita GUI (solo log)
    --com-port COM4 \              # Override COM port seriale
    --brainbox-port COM3           # Override BrainBox port
```

### 5.2.3 Workflow Hardware Mode

```
1. INITIALIZATION
   ├─ Load 1553 driver (_interpreter.pyd)
   ├─ Connect serial port (COM4, 115200 baud)
   ├─ Initialize BrainBox (COM3)
   └─ Start GUI monitor (if enabled)

2. PRE-TEST CHECKS
   ├─ Verify 1553 communication (ping radar)
   ├─ Check serial port responsive
   └─ Test BrainBox power control

3. TEST EXECUTION
   FOR each run:
       ├─ Power OFF radar (via BrainBox)
       ├─ Wait discharge (4s)
       ├─ Power ON radar (via BrainBox)
       ├─ Wait initialization (1.5s)
       ├─ Configure 1553 messages (A1/A2/A4/A5)
       ├─ Execute PBIT (send command via A2)
       ├─ Monitor completion (poll B6 bit_available)
       ├─ Verify B6 status (12 fields)
       ├─ Drill-down B8 (if failures)
       ├─ Parse serial buffer (%%E, %%F, RECYCLE)
       ├─ Target test (if scenario enabled)
       ├─ Aggregate statistics
       └─ Update GUI

4. POST-TEST
   ├─ Generate PDF report
   ├─ Export CSV statistics
   ├─ Export JSON data
   ├─ Power OFF radar (safe shutdown)
   └─ Disconnect serial/1553
```

### 5.2.4 Troubleshooting Hardware Mode

**Problema: "1553 Communication Lost"**
```
Cause: Radar non risponde su bus 1553
Solutions:
  1. Verificare cablaggio 1553 (terminazioni corrette)
  2. Controllare alimentazione radar
  3. Verificare RT address configurato (deve essere 1)
  4. Controllare driver 1553 installato correttamente
```

**Problema: "Serial Port Open Failed"**
```
Cause: Porta seriale non accessibile
Solutions:
  1. Verificare COM port in Device Manager
  2. Chiudere altri programmi che usano la porta (PuTTY, HyperTerminal)
  3. Verificare permessi utente (potrebbe richiedere admin)
  4. Controllare cavo USB-to-Serial funzionante
```

**Problema: "BrainBox Not Responding"**
```
Cause: Power control non funzionante
Solutions:
  1. Verificare BrainBox connesso e acceso
  2. Controllare COM port BrainBox (default: COM3)
  3. Test manuale: python -c "import brainbox_interface; bb = brainbox_interface.BrainBoxInterface('COM3'); print(bb.power_on(1))"
  4. Workaround: Disabilitare power cycling automatico, controllare manualmente
```

## 5.3 Modalità Simulazione (`--simulate`)

### 5.3.1 Principi Simulazione

La modalità simulazione **non richiede hardware** e usa **mock objects** per emulare risposte radar.

**Vantaggi**:
- ⚡ **Velocità**: 6-8x più veloce del hardware (no power cycling, no wait reali)
- 🎯 **Determinismo**: Risultati ripetibili e prevedibili
- 🔧 **Debug Friendly**: Logging dettagliato, breakpoint funzionanti
- 🚀 **CI/CD Ready**: Eseguibile in pipeline automatiche

**Limitazioni**:
- ❌ Non cattura timing issues reali
- ❌ Non testa integrazione HW/SW
- ❌ Mock behavior potrebbe divergere da hardware reale

### 5.3.2 Esecuzione Simulazione

**Launcher Script: `run_simulate.bat`**

```batch
@echo off
REM ============================================================
REM run_simulate.bat - Execute test in SIMULATION mode
REM Uses embedded Python from PlatformSimulator/bin
REM ============================================================

echo ╔════════════════════════════════════════════════════════╗
echo ║   GRIFO M-PBIT Test - SIMULATION MODE                 ║
echo ╚════════════════════════════════════════════════════════╝
echo.

REM Use embedded Python with all dependencies
set PYTHON_HOME=%~dp0PlatformSimulator\bin
set PATH=%PYTHON_HOME%;%PYTHON_HOME%\DLLs;%PATH%

echo [INFO] Using embedded Python: %PYTHON_HOME%\python.exe
echo [INFO] Starting simulation...
echo.

REM Navigate to scripts and execute
cd TestEnvironment\scripts
python GRIFO_M_PBIT.py --simulate --runs 10 --scenario random

echo.
echo [INFO] Simulation completed
echo [INFO] Reports: TestEnvironment\pdf_reports\
echo.

pause
```

**Launcher Script Semplificato: `run_simulate_simple.bat`**

```batch
@echo off
REM Uses system Python (must have dependencies installed)

echo [INFO] Using system Python
cd TestEnvironment\scripts
python GRIFO_M_PBIT.py --simulate --runs 10
pause
```

**Esecuzione Diretta**:
```bash
# Dalla root del repository
python TestEnvironment/scripts/GRIFO_M_PBIT.py --simulate --runs 10 --scenario tgtgen
```

### 5.3.3 Sistema Mock Objects

**Architettura Mock**:
```python
# File: GRIFO_M_PBIT_mock.py

class MockGrifo1553Interface:
    """
    Mock per theGrifo1553 singleton.
    Emula risposte 1553 basate su scenario configurato.
    """
    
    def __init__(self, scenario_config: Dict):
        self.scenario = scenario_config
        self.message_data = {}  # Simulated message values
        self._init_message_defaults()
        self._apply_scenario_failures()
    
    def check(self, RT: int, expected: Any, msg: str, field: str) -> Tuple[bool, str]:
        """Simula check 1553 field"""
        actual = self.get(RT, msg, field)
        return (actual == expected, "")
    
    def get(self, RT: int, msg: str, field: str) -> Any:
        """Ritorna valore simulato per campo"""
        key = f"{msg}.{field}"
        return self.message_data.get(key, "false")  # Default: no failure
    
    def set(self, RT: int, value: Any, msg: str, field: str, commitChanges: bool = False) -> Tuple[bool, str]:
        """Simula set 1553 field (memorizza valore)"""
        key = f"{msg}.{field}"
        self.message_data[key] = value
        return (True, "")
    
    def _init_message_defaults(self):
        """Inizializza valori default messaggi"""
        # B6 defaults (all LRU OK)
        for field in B6_FIELDS:
            self.message_data[f"B6_MsgRdrSettingsAndParametersTellback.{field}"] = "false"
        
        # B6 bit_available = false initially (PBIT not done)
        self.message_data["B6_MsgRdrSettingsAndParametersTellback.b6_t1_bit_available"] = "false"
        
        # B8 defaults (all tests PASS)
        for field in B8_FIELDS:
            self.message_data[f"B8_MsgBitReport.{field}"] = "false"
        
        # B9 defaults (no target)
        self.message_data["B9_MsgRdrTrackAndTargetsData.b9_t1_rng"] = 0
    
    def _apply_scenario_failures(self):
        """Applica failure configurati in scenario"""
        failures = self.scenario.get('expected_failures', [])
        failure_probs = self.scenario.get('failure_probability', {})
        
        for field_short_name, probability in failure_probs.items():
            # Decide casualmente se applicare failure
            if random.random() < probability:
                # Map short name → full field name
                full_field = f"b6_t1_{field_short_name}"
                self.message_data[f"B6_MsgRdrSettingsAndParametersTellback.{full_field}"] = "true"
```

**Mock BrainBox**:
```python
class MockBrainBox:
    """Mock per theBrainBox singleton"""
    
    def __init__(self):
        self.power_state = False
    
    def power_on(self, channel: int = 1) -> bool:
        logging.info(f"[MOCK] BrainBox: Power ON channel {channel}")
        self.power_state = True
        return True
    
    def power_off(self, channel: int = 1) -> bool:
        logging.info(f"[MOCK] BrainBox: Power OFF channel {channel}")
        self.power_state = False
        return True
    
    def get_status(self, channel: int = 1) -> str:
        return "ON" if self.power_state else "OFF"
```

**Mock Serial Terminal**:
```python
class MockSerialTerminal:
    """Mock per serial terminal"""
    
    def __init__(self, scenario_config: Dict):
        self.scenario = scenario_config
        self.buffer = []
        self._generate_mock_messages()
    
    def _generate_mock_messages(self):
        """Genera messaggi seriali simulati basati su scenario"""
        # Messaggi base
        self.buffer.append("[15:24:30.000] GRIFO Radar v3.2 - Startup")
        self.buffer.append("[15:24:31.000] Initialization complete")
        
        # Aggiungi %%E se scenario prevede errori
        if self.scenario.get('serial_error_rate', 0) > 0:
            self.buffer.append("[15:24:35.123] %%E Memory allocation warning")
        
        # Aggiungi RECYCLE se previsto
        if 'recycle' in self.scenario.get('serial_events', []):
            self.buffer.append("[15:24:36.456] %%F Critical fault detected")
            self.buffer.append("[15:24:36.789] RECYCLE event - processor restarting")
        
        # Messaggi PBIT
        self.buffer.append("[15:24:50.000] PBIT COMPLETED in 15.2 seconds")
        self.buffer.append("[15:24:50.100] BIT AVAILABLE")
    
    def readline(self, timeout: float = 1.0) -> str:
        """Ritorna prossimo messaggio dal buffer"""
        if self.buffer:
            return self.buffer.pop(0)
        return ""
    
    def connect(self):
        logging.info("[MOCK] Serial: Connected (simulated)")
    
    def disconnect(self):
        logging.info("[MOCK] Serial: Disconnected (simulated)")
```

### 5.3.4 Monkey Patching

**Come Mock Viene Iniettato**:
```python
# In GRIFO_M_PBIT.py

if args.simulate:
    # Import mock implementations
    from GRIFO_M_PBIT_mock import (
        MockGrifo1553Interface,
        MockBrainBox,
        MockSerialTerminal
    )
    
    # Load scenario configuration
    scenario_config = SCENARIOS[args.scenario]
    
    # Replace global singletons with mock objects
    import leo_grifo_1553
    import leo_grifo_io_box
    
    leo_grifo_1553.theGrifo1553 = MockGrifo1553Interface(scenario_config)
    leo_grifo_io_box.theBrainBox = MockBrainBox()
    
    # Use mock terminal instead of real serial
    terminal = MockSerialTerminal(scenario_config)
    
    logging.info("SIMULATION MODE: Mock objects injected")
else:
    # Use real hardware interfaces
    from leo_grifo_1553 import theGrifo1553
    from leo_grifo_io_box import theBrainBox
    terminal = SerialTerminal(port='COM4', baudrate=115200)
    
    logging.info("HARDWARE MODE: Real interfaces loaded")
```

**Vantaggi Monkey Patching**:
- ✅ Test code **identico** per hardware e simulazione
- ✅ Nessun `if simulate:` scattered nel codice
- ✅ Mock trasparente (stessa API)

### 5.3.5 Timing Simulation

Mock objects simulano anche **timing realistici**:

```python
class MockGrifo1553Interface:
    def wait_pbit_completion(self, timeout: float) -> Tuple[bool, float, str]:
        """Simula PBIT completion con timing realistico"""
        # Simula PBIT duration (15-20 secondi)
        pbit_duration = random.uniform(15.0, 20.0)
        
        # Simula attesa (velocità 10x per simulazione)
        time.sleep(pbit_duration / 10.0)  # 1.5-2 secondi reali
        
        # Imposta bit_available = true
        self.message_data["B6_MsgRdrSettingsAndParametersTellback.b6_t1_bit_available"] = "true"
        
        return (True, pbit_duration, 'completed')
```

**Speedup Factor**: Simulazione è **~6-8x più veloce** grazie a:
- ⏩ No power cycling fisico (5s → 0.5s)
- ⏩ PBIT simulato ridotto (18s → 2s)
- ⏩ No wait hardware stabilization

## 5.4 Parametri di Configurazione

### 5.4.1 Parametri Command Line

**Sintassi Completa**:
```bash
python GRIFO_M_PBIT.py \
    [--target | --simulate] \              # OBBLIGATORIO: modalità
    [--runs N] \                           # Numero ripetizioni (default: 10)
    [--scenario NAME] \                    # Scenario test (default: random)
    [--no-gui] \                           # Disabilita GUI
    [--com-port PORT] \                    # Serial port (default: COM4)
    [--brainbox-port PORT] \               # BrainBox port (default: COM3)
    [--export-csv] \                       # Forza export CSV (default: auto)
    [--no-export-csv]                      # Disabilita export CSV
```

**Esempi**:
```bash
# Simulazione rapida 5 run scenario perfect
python GRIFO_M_PBIT.py --simulate --runs 5 --scenario perfect

# Hardware 20 run scenario random senza GUI
python GRIFO_M_PBIT.py --target --runs 20 --scenario random --no-gui

# Simulazione target detection
python GRIFO_M_PBIT.py --simulate --runs 10 --scenario tgtgen

# Hardware con COM port custom
python GRIFO_M_PBIT.py --target --com-port COM5 --brainbox-port COM6
```

### 5.4.2 Costanti Configurabili

**File: `GRIFO_M_PBIT.py` (sezione CONFIGURATION)**

```python
# ===== TEST EXECUTION =====
NUMBER_OF_REPETITIONS = 10           # Default runs
PBIT_SEC_TIME = 182                  # PBIT timeout (secondi)
COMM_LOSS_THRESHOLD = 20             # Iterations senza messaggi = comm loss

# ===== TARGET DETECTION =====
TARGET_DETECTION_TIMEOUT_SEC = 20.0  # Timeout target test
TARGET_EXPECTED_RANGE = 2536         # Range atteso (ICD units)
TARGET_RANGE_TOLERANCE_LOW = -1000   # Tolerance bassa
TARGET_RANGE_TOLERANCE_HIGH = 200    # Tolerance alta
TARGET_HIT_THRESHOLD = 2             # Numero detection richieste

# ===== SERIAL CONFIGURATION =====
SERIAL_PORT = 'COM4'                 # Default serial port
SERIAL_BAUDRATE = 115200             # Baud rate
SERIAL_TIMEOUT = 1.0                 # Read timeout

# ===== POWER CONTROL =====
BRAINBOX_PORT = 'COM3'               # BrainBox COM port
POWER_OFF_WAIT_BEFORE = 1.0          # Attesa pre-spegnimento
POWER_OFF_WAIT_AFTER = 4.0           # Attesa post-spegnimento (discharge)
POWER_ON_WAIT_AFTER = 1.5            # Attesa post-accensione (init)

# ===== KNOWN FAILURES =====
KNOWN_FAILURES = [
    "b6_t1_antenna_drive_unit_status",
    "b6_t1_waveguide_pressurization_status"
]

# ===== OUTPUT =====
EXPORT_STATISTICS_CSV = True         # Export CSV automatico
```

### 5.4.3 Scenari Custom

**Definire Scenario Personalizzato**:

```python
# In GRIFO_M_PBIT.py, aggiungi a SCENARIOS dict

SCENARIOS['my_custom_scenario'] = {
    'name': 'My Custom Test',
    'description': 'Custom failure pattern for specific test case',
    'expected_failures': [
        'processor_1_status'
    ],
    'failure_probability': {
        'processor_1_status': 0.50,  # 50% chance
        'receiver_status': 0.30       # 30% chance
    },
    'serial_events': [
        {'type': 'error', 'count': 3},    # 3 %%E messages
        {'type': 'recycle', 'iteration': 2}  # RECYCLE at run 2
    ],
    'target_gen': {
        'distance': 3000,                 # 3km target
        'appeared_after_cycles': 5,
        'heading': 900,
        'x_pos': 1000,
        'y_pos': 1000
    }
}
```

**Esecuzione**:
```bash
python GRIFO_M_PBIT.py --simulate --scenario my_custom_scenario
```

## 5.5 Comparazione Modalità

### 5.5.1 Tabella Comparativa

| Caratteristica | Hardware Mode | Simulation Mode |
|----------------|---------------|-----------------|
| **Hardware richiesto** | Radar + PC + 1553 + Serial | Solo PC |
| **Tempo/run** | 60-80 secondi | 10-15 secondi |
| **Setup time** | ~5 minuti | ~30 secondi |
| **Determinismo** | Basso (timing variabili) | Alto (ripetibile) |
| **Debug** | Difficile (timing critici) | Facile (breakpoint OK) |
| **Failure detection** | Reali + intermittenti | Solo configurati |
| **CI/CD** | No (hardware-dependent) | Sì (fully automated) |
| **Cost** | Alto (tempo + hardware) | Basso (solo CPU) |
| **Use case** | Final validation | Development, regression |

### 5.5.2 Workflow Raccomandato

```
Development Cycle:
1. [SIMULATE] Develop new test logic locally
2. [SIMULATE] Debug and iterate quickly
3. [SIMULATE] Run regression suite (all scenarios)
4. [HARDWARE] Execute validation run (1-2 scenarios)
5. [HARDWARE] Long-duration stress test (100+ runs)
6. [SIMULATE] Re-run regression after fixes

CI/CD Pipeline:
1. Commit → [SIMULATE] Quick smoke test (5 runs)
2. PR → [SIMULATE] Full regression (all scenarios, 10 runs each)
3. Merge → [HARDWARE] Nightly validation (selected scenarios)
4. Release → [HARDWARE] Extensive validation (all scenarios, 50+ runs)
```

---

[← Workflow Test](04_Sistema_Test_Workflow_Logica.md) | [Torna all'Indice](00_INDEX.md) | [Prossimo: GUI →](06_Interfaccia_Grafica_GUI.md)
