21 KiB
Piano di Migrazione: GrifoScope → PyBusMonitor1553
📊 Situazione Attuale
Sistema a 3 Componenti
┌─────────────────┐ UDP 1553 ┌─────────────────┐
│ GrifoScope │◄────────────────────────►│ Radar Server │
│ (BusMonitor) │ Port 50553 ← 60553 │ (Target Real) │
│ C++/Qt │ │ │
└─────────────────┘ └─────────────────┘
▲
│ DA SOSTITUIRE CON
▼
┌─────────────────┐ UDP 1553 ┌─────────────────┐
│PyBusMonitor1553 │◄────────────────────────►│ Radar Server │
│ (BusMonitor) │ Port 51553 ← 61553 │ (Target Real) │
│ Python │ │ │
└─────────────────┘ └─────────────────┘
Obiettivo: Far funzionare PyBusMonitor1553 esattamente come GrifoScope per comunicare con il Radar Server.
🔍 Analisi del Comportamento di GrifoScope
1. Architettura di Comunicazione (qg1553overudp.cpp)
GrifoScope usa un pattern Bus Controller (BC) che:
Inizializzazione (Qg1553OverUdp::Implementation::BusGenerator())
// Bind sulla porta locale 60553 (60000 + 1553)
s.bind(networkInterface(), 60000+1553);
// Indirizzo destinazione: broadcast o IP specifico radar
rtAddress = networkBroadcast(); // Es: 127.0.0.255
// Registra messaggi A (BC→RT, tr=0):
addMsg<msg_rdr_settings_and_parameters_t>(1, 0); // A1
addMsg<msg_rdr_operation_command_t>(2, 0); // A2
addMsg<msg_graphic_setting_t>(3, 0); // A3
addMsg<msg_nav_data_and_cursor_t>(4, 0); // A4
addMsg<msg_inu_high_speed_t>(5, 0); // A5
// Registra messaggi B (RT→BC, tr=1):
addMsg<msg_settings_tellback_t>(15, 1); // B6
addMsg<msg_rdr_status_tellback_t>(16, 1); // B7
CRITICO: GrifoScope invia datagrammi multi-messaggio:
struct b1553_datagram_t {
uint16_t number_of_messages;
b1553_raw_message_t msgs[20]; // Fino a 20 messaggi in un frame
};
Trasmissione Ciclica (doWork())
// Timer a 10 secondi (10000 µs) per invio frame completo
scheduler->start(10000); // 100 Hz
// Ogni ciclo invia TUTTI i messaggi registrati in UN solo UDP datagram
s.writeDatagram(&msg, sizeof(msg), rtAddress, 50000+1553);
Differenza Critica con PyBusMonitor:
- GrifoScope → 1 datagram UDP con tutti i messaggi A1-A5 + request B6-B7
- PyBusMonitor → multi datagram (uno per messaggio) con scheduler separato
2. Formato Pacchetto UDP1553 (udp1553_types.h, b1553_udp.cpp)
Header UDP1553 (64 bytes - già implementato ✅)
struct udp_1553_header_t {
uint16_t marker1553; // 0x1553
uint8_t vmajor, vminor; // Version
uint16_t otype; // 0x4342 ("BC") o 0x5452 ("RT")
uint8_t ta; // Terminal Address (0=BC, 20=RT)
uint8_t flags;
uint32_t fcounter; // Frame counter
uint32_t mcounter; // Master counter
// ... altri campi timing/debug
};
Blocco Messaggio (ripetuto N volte)
0x3C3C // MARKER_BEGIN
CW // Command Word (RT, TR, SA, WC)
SW // Status Word (solo RT replies)
ERRCODE // Error code
reserved[2] // 8 bytes reserved
DATA[wc] // Payload (wc words, Big Endian)
~CW // Inverted command word
0x3E3E // MARKER_END
Terminatore Frame
0x5315 // MARKER_END_1553
⚠️ Problema Rilevato nel Dispatcher:
Il parser PyBusMonitor ha già logica per multi-messaggio MA ha bug con terminatori (vedi dispatcher.py linee 180-220). GrifoScope usa layout fisso.
3. Sequenza di Startup Radar (g346_a1a2.cpp)
GrifoScope implementa sequenza di sicurezza obbligatoria:
void GrifoMsg_A2B7::startProtection() {
dSilence.setFromUser(1); // RF SILENCE = ON
dStby.setFromUser(1); // STANDBY = ON
}
Workflow Startup (già parzialmente implementato ✅):
| Fase | Durata | STANDBY | SILENCE | Azione |
|---|---|---|---|---|
| 1 - Protection | 2-3 cicli | ON | ON | Stato sicuro, radar non risponde |
| 2 - Activation | 1 ciclo | OFF | OFF | Comando attivazione |
| 3 - Transition | 6 cicli (~240ms) | OFF | OFF | Radar elabora cambio modo |
| 4 - Operational | continuo | OFF | OFF | Monitoraggio B7 transition_status |
Implementazione Python: Vedi RadarController.apply_startup_sequence() - già corretto ✅
4. Gestione Request/Reply (b1553_udp.cpp)
GrifoScope usa pattern request-response:
// INVIO (BC → RT):
// - A1-A5: Comandi con tr=0, payload pieno
// - B6-B7: Richieste con tr=1, payload vuoto (solo CW)
// RICEZIONE (RT → BC):
// Radar risponde con stesso SA, tr=1, payload pieno
if (cw.str.tr == 1) { // RT→BC reply
// Copia dati nel buffer locale
memcpy(local_buffer[sa], data, wc*2);
}
Ciclo Tipico:
- GrifoScope invia frame con A1-A5 (comandi) + B6-B7 (request vuote)
- Radar risponde con frame separato contenente B6-B7 (dati pieni)
- GrifoScope aggiorna display con tellback B7
PyBusMonitor Status:
- ✅ Invia A-messages (comandi)
- ⚠️ Invia B-requests MA non usa formato corretto (vedi sotto)
🔧 Differenze Critiche da Risolvere
Riepilogo:
- ❌ 2 problemi CRITICI da risolvere (Multi-Message, B-Request)
- ✅ 3 aspetti già corretti (Porte, Endianness, Startup)
❌ PROBLEMA 1: Formato Multi-Messaggio
GrifoScope:
UDP Header (64 bytes)
↓
0x3C3C | CW_A1 | ... | DATA_A1[32] | ~CW_A1 | 0x3E3E
0x3C3C | CW_A2 | ... | DATA_A2[32] | ~CW_A2 | 0x3E3E
0x3C3C | CW_A3 | ... | DATA_A3[32] | ~CW_A3 | 0x3E3E
0x3C3C | CW_A4 | ... | DATA_A4[32] | ~CW_A4 | 0x3E3E
0x3C3C | CW_A5 | ... | DATA_A5[32] | ~CW_A5 | 0x3E3E
0x3C3C | CW_B6 | ... | [EMPTY] | ~CW_B6 | 0x3E3E ← REQUEST
0x3C3C | CW_B7 | ... | [EMPTY] | ~CW_B7 | 0x3E3E ← REQUEST
0x5315 (END marker)
PyBusMonitor Attuale (scheduler.py):
- Invia messaggi A/B in frame separati
- Usa rate diversi (50Hz, 25Hz, 6.25Hz)
- Non raggruppa i messaggi
Radar potrebbe aspettarsi frame singolo con tutti i messaggi sincronizzati!
❌ PROBLEMA 2: B-Messages Request Format
GrifoScope per richieste B (RT→BC):
// B6/B7 request: tr=1, wc=32, payload=0 bytes (solo header)
addMsg<msg_settings_tellback_t>(15, 1); // SA=15, tr=1, wc=32
PyBusMonitor Attuale:
# B-messages hanno payload pieno (32 words) anche in TX
self.msg_b7 = msgs.MsgB7() # Crea con _data[32] inizializzato
ERRORE: B-requests dovrebbero avere:
tr = 1(RT transmit) ✅wc = 32✅- Payload VUOTO (0 bytes data) ❌ → Attualmente 64 bytes
✅ PROBLEMA 3: Porte UDP - RISOLTO
VERIFICATO: Le porte sono già correttamente allineate!
GrifoScope: 60000+1553 = 61553 (RX), 50000+1553 = 51553 (TX)
PyBusMonitor: RX_PORT = 61553, TARGET_PORT = 51553
✅ Nessuna modifica necessaria
✅ PROBLEMA 4: Endianness e Bit Numbering - GIÀ CORRETTO
VERIFICATO:
- ✅ Payload: Big Endian (network byte order) - OK
- ✅ Headers: Little Endian - OK
- ✅ Bit numbering: MSB=0 convention - OK nei field descriptors
CRITICO da verificare:
- Inverted CW (
~cw) deve usare bitwise NOT su 16-bit - Alcuni radar potrebbero essere sensibili a byte swap in
~CW
⚠️ PROBLEMA 5: Porte UDP - FALSO ALLARME ✅
VERIFICATO: Le porte sono già allineate correttamente!
Da verificare con test reale:
- Inverted CW (
~cw) usa bitwise NOT su 16-bit (già implementato ✅) - Layout terminatore:
inv_cw (LE) → MARKER_END (LE)(già implementato ✅) ❌Discrepanza di 1000 porte→ ✅ IDENTICHE - Nessun problema
⚠️ PROBLEMA 6: Dispatcher Multi-Message Bug
File dispatcher.py linee 180-250 contiene workaround per terminatori:
# Accept if LE matches expected and control marker is correct
if (inv_cw_le == expected_inv_cw) and (ctrl_le == MARKER_END):
accepted = True
# Else try BE, fallback scans, etc...
Issue: Logica troppo permissiva causa falsi positivi. GrifoScope usa layout fisso:
DATA[wc] → inv_cw (LE) → MARKER_END (LE)
✅ Cosa Funziona Già (Non Toccare)
- Message Definitions (
lib1553/messages/) - ✅ Corrette vs C++ ICD - Field Descriptors (
fields.py) - ✅ MSB=0 bit numbering - PacketBuilder (
packet_builder.py) - ✅ UDP1553 header format - Startup Sequence (
controller.py) - ✅ STANDBY/SILENCE phases - Navigation Data - ✅ Validity flags (inverse logic)
🎯 Piano d'Azione
FASE 1: Verifica Compatibilità Formato (Diagnostica)
Obiettivo: Catturare traffico GrifoScope reale e confrontare con PyBusMonitor
Task 1.1: Cattura Pacchetti GrifoScope
# Usa Wireshark o tcpdump per catturare:
# - GrifoScope → Radar (porta 50553)
# - Radar → GrifoScope (porta 60553)
# Salva PCAP e analizza:
python tools/analyze_wireshark_dump.py grifoscope_capture.pcap
Deliverable: File con layout esatto frame GrifoScope
Task 1.2: Confronto Binario
# tools/compare_grifoscope_packets.py
# Compara:
# - Header fields (fcounter, mcounter, etc.)
# - Message order (A1-A5, B6-B7)
# - Word count per messaggio
# - Payload content (campo per campo)
Deliverable: Report discrepanze
FASE 2: Fix Formato B-Request (Codice)
Problema: B-messages inviate con payload pieno invece di vuoto
Task 2.1: Modificare PacketBuilder
# pybusmonitor1553/core/packet_builder.py
def build_message_block(self, message, force_empty_payload=False):
"""
Args:
force_empty_payload: Se True, invia solo header senza data
(usato per B-requests)
"""
if force_empty_payload:
# tr=1, wc=32 MA data_bytes=0
return header_bytes + inv_cw + marker_end
else:
# tr=0 o tr=1 con payload
return header_bytes + data_bytes + inv_cw + marker_end
Task 2.2: Flag nelle Message Class
# lib1553/message_base.py
class MessageBase:
IS_TRANSMIT = False # Existing
REQUEST_MODE = False # NEW: True per B-requests (no payload)
# lib1553/messages/msg_b7.py
class MsgB7(MessageBase):
IS_TRANSMIT = True
REQUEST_MODE = True # ← B-messages sono requests!
Deliverable: B-requests inviate con 0 data bytes
FASE 3: Implementare Frame Multi-Messaggio (Architettura)
Problema: Inviare tutti i messaggi in UN frame come GrifoScope
Task 3.1: Nuovo Builder Pattern
# pybusmonitor1553/core/packet_builder.py
def build_multi_message_frame(self, messages):
"""
Costruisce frame singolo con N messaggi (stile GrifoScope).
Args:
messages: Lista [MsgA1, MsgA2, ..., MsgB7]
Returns:
bytes: UDP datagram completo
"""
frame = UDP1553Header(...) # 64 bytes
for msg in messages:
# Determina se request (B-msg) o command (A-msg)
is_request = getattr(msg, 'REQUEST_MODE', False)
frame += build_message_block(msg, force_empty_payload=is_request)
frame += MARKER_END_1553
return frame
Task 3.2: Modificare Scheduler
# pybusmonitor1553/core/scheduler.py
class TrafficScheduler:
def __init__(self, controller, network):
self.mode = 'GRIFOSCOPE' # NEW: 'LEGACY' o 'GRIFOSCOPE'
def _schedule_grifoscope_mode(self):
"""
Invia frame singolo con tutti i messaggi ogni 40ms (25 Hz).
"""
messages = [
self.controller.msg_a1,
self.controller.msg_a2,
self.controller.msg_a3,
self.controller.msg_a4,
self.controller.msg_a5,
self.controller.msg_b6, # Request
self.controller.msg_b7, # Request
]
frame = self.builder.build_multi_message_frame(messages)
self.network.send(frame, self.target_ip, self.target_port)
Deliverable: Modalità compatibile GrifoScope attivabile via flag
FASE 4: Fix Dispatcher Multi-Message (Parser)
Problema: Parser troppo permissivo con terminatori
Task 4.1: Semplificare Logica
# pybusmonitor1553/core/dispatcher.py
def parse_packet(self, raw_data):
# REMOVE: Fallback scans, BE/LE alternation
# USE: Strict layout matching GrifoScope
# Expected: DATA → inv_cw (LE) → MARKER_END (LE)
inv_cw, ctrl_marker = struct.unpack_from('<HH', raw_data, offset)
if inv_cw != expected_inv_cw:
raise ValueError(f"Invalid ~CW at offset {offset}")
if ctrl_marker != MARKER_END:
raise ValueError(f"Invalid MARKER_END at offset {offset}")
```Network Configuration** (Config) - ✅ OPZIONALE
#### Task 5.1: ~~Porte UDP~~ - GIÀ CORRETTE ✅
Le porte sono identiche a GrifoScope. Nessuna modifica necessaria.
#### Task 5.2: Broadcast vs Unicast (Opzionale)
```python
# Verificare con test reale se radar richiede broadcast
# GrifoScope usa: rtAddress = networkBroadcast()
# Può essere 127.0.0.255 (broadcast) o 127.0.0.1 (unicast)
BROADCAST_MODE = os.getenv('PYBM_BROADCAST', 'false').lower() == 'true'
if BROADCAST_MODE:
TARGET_IP = "127.0.0.255" # Broadcast locale
else:
TARGET_IP = "127.0.0.1" # Unicast (default attuale)
Deliverable: Test con radar reale determinerà necessità TARGET_IP = "127.0.0.255" # Broadcast locale else: TARGET_IP = "127.0.0.1"
**Deliverable**: Flag ambiente per compatibilità totale
---
### **FASE 6: Testing con Radar Reale** (Validazione)
#### Task 6.1: Test di Connessione
```bash
# 1. Stop GrifoScope
# 2. Avvia PyBusMonitor in GRIFOSCOPE_MODE
export PYBM_GRIFOSCOPE_MODE=true
python -m pybusmonitor1553
# 3. Verifica:
# - Radar risponde con B-messages?
# - Transition status in B7 arriva a OPERATIONAL?
# - Display radar mostra parametri corretti?
Task 6.2: Confronto Comportamentale
| Metrica | GrifoScope | PyBusMonitor | Status |
|---|---|---|---|
| Radar risponde | ✅ SI | ❓ DA VERIFICARE | |
| B7 transition complete | ✅ 6 cicli | ❓ DA VERIFICARE | |
| Parametri radar aggiornati | ✅ SI | ❓ DA VERIFICARE | |
| Frame rate | 100 Hz | 25 Hz → 100 Hz | TODO |
Deliverable: Report test con radar vivo
📁 Struttura Modifiche al Codice
pybusmonitor1553/
├── core/
│ ├── packet_builder.py # ✏️ MODIFY: Multi-message frame
│ ├── scheduler.py # ✏️ MODIFY: GRIFOSCOPE mode
│ ├── dispatcher.py # ✏️ FIX: Strict terminator parsing
│ └── controller.py # ✅ OK (startup sequence già corretto)
├── lib1553/
│ ├── message_base.py # ✏️ ADD: REQUEST_MODE flag
│ └── messages/
│ ├── msg_b*.py # ✏️ SET: REQUEST_MODE = True
└── __main__.py # ✏️ ADD: GRIFOSCOPE_MODE env var
tools/
├── compare_grifoscope_packets.py # 🆕 NEW: Binary comparison
├── analyze_wireshark_dump.py # 🆕 NEW: PCAP parser
└── simple_rt_responder.py # ✅ OK (test tool)
doc/
└── GrifoScope-Migration-Plan.md # 📄 THIS FILE
🚦 Roadmap Implementazione
Sprint 1 (Settimana 1): Diagnostica
- Cattura traffico GrifoScope con Wireshark
- Analizza formato esatto frame
- Identifica differenze vs PyBusMonitor
- Scrivi tool
compare_grifoscope_packets.py
Sprint 2 (Settimana 2): Fix Formato
- Implementa
REQUEST_MODEflag - Modifica
PacketBuilder.build_message_block() - Test con
simple_rt_responder.py - Verifica B-requests inviate senza payload
Sprint 3 (Settimana 3): Multi-Message
- Implementa
build_multi_message_frame() - Aggiungi
GRIFOSCOPEmode a scheduler - Test frame rate (25 Hz vs 100 Hz)
- Benchmark performance
Sprint 4 (Settimana 4): Integration
- Fix dispatcher strict parsing
- Allinea porte (60553/50553)
- Test con radar simulato
- ⭐ TEST CON RADAR REALE
Sprint 5 (Settimana 5): Hardening
- Handle edge cases (timeout, packet loss)
- Logging migliorato per debug
- Documentazione operativa
- Training team su modalità GrifoScope
⚠️ Rischi e Mitigazioni
| Rischio | Probabilità | Impatto | Mitigazione |
|---|---|---|---|
| Radar hardcoded su porte GrifoScope | Alta | Alto | Usare stesse porte in GRIFOSCOPE_MODE |
| Frame format incompatibile | Media | Alto | Cattura PCAP prima di modifiche |
| ✅ RISOLTO | - | Porte già allineate (61553/51553) | |
| Frame format incompatibile | Media | Alto | Cattura PCAP prima di modifiche |
| Timing critico (100 Hz) | Media | Medio | Benchmark Python threading performance |
| Radar richiede broadcast IP | Bassa | Medio | Test con 127.0.0.255 vs 127.0.0.1 |
| Radar richiede checksum/CRC | Bassa | Alto | Analizza header errcode field |
📊 Metriche di Successo
Criteri di Accettazione
✅ MUST HAVE:
- Radar risponde ai comandi A-messages
- Radar invia B-messages di tellback
- Transition status raggiunge OPERATIONAL
- Zero crash o errori di parsing
✅ SHOULD HAVE: 5. Frame rate = 100 Hz (come GrifoScope) 6. Latenza < 10ms per ciclo 7. Compatibilità backward con modalità legacy
✅ NICE TO HAVE: 8. GUI mostra differenze GrifoScope vs PyBusMonitor 9. Tool di diagnostica automatico 10. Documentazione completa workflow
🔗 Riferimenti
File Chiave C++
cpp/GrifoScope/GrifoScope/QgExt/qg1553overudp.cpp- Logica trasmissionecpp/GrifoScope/GrifoSdkEif/dev/Portable/ext/b1553_udp.cpp- Parser radar-sidecpp/GrifoScope/GrifoMCS/GADS/MCS/MCS_G346/g346/g346_a1a2.cpp- Startup sequence
File Chiave Python
pybusmonitor1553/core/dispatcher.py- Parser UDP1553pybusmonitor1553/core/packet_builder.py- Builder framepybusmonitor1553/core/scheduler.py- Timing messaggipybusmonitor1553/core/controller.py- Startup radar
Documentazione
doc/ICD-Implementation-Notes.md- Discrepanze ICD vs C++doc/Technical-Architecture.md- Architettura sistema.github/copilot-instructions.md- Regole sviluppo
🎓 Note per il Team
Approccio Incrementale
- Non stravolgere l'architettura esistente - Aggiungi modalità compatibilità
- Mantieni backward compatibility - Flag
GRIFOSCOPE_MODEopzionale - Test continuo - Ogni modifica deve passare pytest + test manuale
- Cattura prima, modifica dopo - PCAP è la fonte di verità
Debug Tips
# Abilita logging verbose
export PYBM_LOG_LEVEL=DEBUG
# Cattura pacchetti in tempo reale
python tools/network_sniffer.py --source python --debug
# Confronta con GrifoScope
diff captured_a_messages_commands_grifoscope.txt \
captured_a_messages_commands_python.txt
Quando Chiamare Aiuto
- ❌ Radar non risponde dopo 3 cicli di debug
- ❌ Crash sistematico su parse multi-message
- ❌ Performance < 25 Hz su hardware target
- ❌ Discrepanze ICD non documentate nel C++
✨ Conclusioni
Status Attuale: PyBusMonitor ha ~80% delle funzionalità necessarie.
Gap Principali:
- ❌ Frame multi-messaggio (vs singoli datagram)
- ❌ B-requests con payload vuoto
- ⚠️ Porte UDP diverse
Effort Stimato:
- Fase 1-2: 1 settimana (diagnostica 85% delle funzionalità necessarie.
Gap Principali (solo 2!):
- ❌ Frame multi-messaggio (vs singoli datagram)
- ❌ B-requests con payload vuoto
Già Corretti ✅:
- ✅ Porte UDP (61553/51553 come GrifoScope)
- ✅ Endianness (Big Endian payload, Little Endian header)
- ✅ Startup sequence (STANDBY/SILENCE)
- ✅ Field descriptors (MSB=0 bit numbering)
Effort Stimato (rivisto):
- Fase 1-2: 1 settimana (diagnostica + B-request fix)
- Fase 3-4: 1.5 settimane (multi-message + dispatcher)
- Fase 5-6: 0.5 settimane (test radar + validazione)
Total: ~3 settimane per compatibilità completa ⚡
Priorità:
- CRITICA - B-request format (blocca risposte radar)
- ALTA - Multi-message frame (timing/formato)
- MEDIA - Dispatcher cleanup (funziona ma migliorabile)
- BASSA - Broadcast IP (test opziona
Domande? → Apri issue su GitHub o discuti con team lead.
Documento creato: 2025-12-15
Versione: 1.0
Autore: AI Assistant + Team PyBusMonitor