# Integrazione di pybusmonitor1553 con ARTOS / uso come modulo Questo documento descrive come caricare, configurare e utilizzare il modulo `pybusmonitor1553` all'interno di un'applicazione esterna (es. ARTOS Collector). Fornisce istruzioni chiare per l'inizializzazione, il controllo, la ricezione/invio di messaggi e le pratiche consigliate per l'integrazione. ## Scopo - Consentire a un'applicazione esterna di usare `pybusmonitor1553` come modulo aggiuntivo. - Fornire esempi pratici per inizializzazione, registrazione callback, invio comandi, registrazione/replay e diagnostica. ## Componenti chiave - `BusMonitorCore` — controller principale e interfaccia di alto livello per integrazione. - `ConnectionManager` — gestisce import lazy e loop di invio/ricezione. - Libreria dei messaggi: `Grifo_E_1553lib` (inclusa nel package). - Esempio di riferimento: `examples/artos_integration_example.py`. ## Requisiti - Python compatibile con il repository. - Le dipendenze del repository devono essere installate (usare l'ambiente del progetto). - Accesso di rete UDP alle porte usate per invio/ricezione. - Variabili d'ambiente utili: - `PYBM_RX_IP` (bind, default `127.0.0.1`) - `PYBM_RX_PORT` (porta ricezione, default `5002`) - `PYBM_TX_PORT` (porta invio, default `5001`) ## Installazione e avvio rapido Eseguire il monitor standalone (GUI): ```bash python -m pybusmonitor1553 ``` Per usare il modulo da un'altra applicazione, importare e istanziare `BusMonitorCore` (vedi esempi sotto). ## Pattern di integrazione consigliato Sequenza tipica quando si usa `pybusmonitor1553` come modulo: 1. Creare istanza: `bm = BusMonitorCore()` 2. Inizializzare: `bm.initialize(config)` (config opzionale, altrimenti usa env) 3. Registrare callback: `bm.register_callback(label, callback)` 4. Avviare sessione: `bm.start_session()` 5. Fermare sessione: `bm.stop_session()` 6. Usare: `get_status()`, `get_message(label)`, `wait_for_message(label, timeout)` per interrogazioni e sincronizzazioni ## API principali (sintesi) - `BusMonitorCore()` — crea l'istanza del modulo. - `initialize(config: Dict) -> bool` — importa la libreria dei messaggi e prepara i wrapper. - `config` può contenere `'ip'`, `'send_port'`, `'recv_port'`. - `start_session()` / `stop_session()` — avvia/ferma i loop di invio/ricezione. - `register_callback(label: str, callback: Callable)` — callback chiamata al ricevimento di messaggi (argomento: oggetto messaggio). - `get_status() -> Dict` — restituisce stato corrente: `is_running`, `connected`, `messages_count`, `recording`, `recorded_events`, `errors`. - `get_message(label: str) -> Optional[Any]` — ottiene il wrapper del messaggio. - `get_all_messages() -> Dict[str, Any]` — lista wrapper disponibili. - `wait_for_message(label: str, timeout: float) -> bool` — blocca fino al messaggio o timeout. - `start_recording(filepath: Optional[Path])`, `stop_recording(save: bool=True)`, `load_recording(filepath: Path)` — registrazione e replay. ### Note importanti sulle callback - I callback vengono invocati dal thread di ricezione: devono essere non-bloccanti. Per elaborazioni pesanti, spostare il lavoro su un worker thread o una coda. ## Come inviare comandi / modificare messaggi 1. Recuperare il wrapper: ```python msg = bm.get_message("A2") ``` 2. Modificare campi usando l'API dei field (varia per messaggio): ```python try: msg.message.rdr_mode_command.set_master_mode(1) except Exception: msg.message.rdr_mode_command.raw = 1 # Invio esplicito se supportato if hasattr(msg, 'send'): msg.send() ``` 3. Se il wrapper non espone `.send()`, assicurarsi che il `MajorFrame`/send-loop sia attivo con `start_session()`. ## Esempio di integrazione (snippet) ```python from pybusmonitor1553.core.bus_monitor_core import BusMonitorCore bm = BusMonitorCore() config = {'ip': '127.0.0.1', 'send_port': 5001, 'recv_port': 5002} if not bm.initialize(config): raise RuntimeError("Impossibile inizializzare BusMonitor1553") def on_a2(msg): print("A2 ricevuto:", msg) bm.register_callback("msg_a2", on_a2) bm.start_recording() bm.start_session() if bm.wait_for_message("msg_a2", timeout=5.0): print("A2 arrivato") print(bm.get_status()) bm.stop_recording(save=True) bm.stop_session() ``` Per un esempio completo e commentato vedere: `examples/artos_integration_example.py`. ## Best practices - Non bloccare i callback: usare code/worker. - Verificare `initialize()` e `manager.import_error` per diagnosi di import. - Usare `wait_for_message` per sincronizzare test automatizzati. - Usare `start_recording`/`stop_recording` per acquisire eventi di test e riprodurli. - Per modifiche ai messaggi, consultare le definizioni in `Grifo_E_1553lib.messages`. ## Logging e diagnostica - Abilitare logging di debug: ```python import logging logging.basicConfig(level=logging.DEBUG) ``` - Controllare `bm.get_status()['errors']` e `bm.manager.import_error` per problemi di import/bind. ## Testing e validazione - Usare `examples/artos_integration_example.py` come caso di test. - Controlli chiave: - `initialize()` ritorna `True`. - `start_session()` attiva `is_running` e `connected`. - `wait_for_message()` e le callback vengono eseguite entro i timeout previsti. ## Troubleshooting rapido - ImportError libreria messaggi: controllare `bm.manager.import_error`. - Nessun messaggio ricevuto: verificare bind IP/porte e che `init_recv_sock()` non fallisca. - Callback non chiamata: verificare label usata (es. `"msg_a2"` vs `"A2"`) con `get_all_messages()`. - Invio non funzionante: assicurarsi che il send-loop sia attivo (`start_session()`) e che il wrapper supporti `.send()`. ## Riferimenti nel repository - Codice core: [pybusmonitor1553/core/bus_monitor_core.py](pybusmonitor1553/core/bus_monitor_core.py) - Gestione connessioni: [pybusmonitor1553/core/connection_manager.py](pybusmonitor1553/core/connection_manager.py) - Esempio ARTOS: [examples/artos_integration_example.py](examples/artos_integration_example.py) - Entrypoint GUI: [pybusmonitor1553/__main__.py](pybusmonitor1553/__main__.py) --- Se vuoi, posso aggiungere al documento esempi specifici per l'invio di A2/A1 con i nomi dei campi letti dalle definizioni nel pacchetto `Grifo_E_1553lib`. ## Esempi dettagliati: A1/A2 (comandi) e B6/B7 (stato) Qui sotto trovi esempi pratici completi che mostrano come impostare comandi su A1/A2 e come leggere stati/tellback su B6/B7. Gli snippet assumono che `bm` sia un'istanza inizializzata di `BusMonitorCore` e che la sessione sia avviata (`start_session()`). ### 1) Esempio: inviare comando A1 (impostazioni / parametri) Questo esempio mostra come ottenere il wrapper A1, modificare un campo e inviare il messaggio (se il wrapper espone `.send()`). Si forniscono fallback per l'accesso ai campi. ```python from pathlib import Path from pybusmonitor1553.core.bus_monitor_core import BusMonitorCore bm = BusMonitorCore() bm.initialize({'ip': '127.0.0.1'}) bm.start_session() # Recupera wrapper A1 msg_a1 = bm.get_message('A1') if msg_a1 is None: raise RuntimeError('Wrapper A1 non trovato') # Esempio: impostare un parametro nelle impostazioni operative (campo `settings`) try: # API field-specific: usare i metodi esposti da RDROperationalSettings se disponibili # Qui usiamo il campo `settings` presente in MsgRdrSettingsAndParameters if hasattr(msg_a1.message.settings, 'set_history_level'): msg_a1.message.settings.set_history_level(4) else: msg_a1.message.settings.raw = 4 except Exception: raise # Invio esplicito se disponibile if hasattr(msg_a1, 'send'): msg_a1.send() else: # Se non c'è send, MajorFrame invierà A1 al prossimo ciclo se configurato print('Invio A1: il wrapper non espone .send(); MajorFrame invierà il valore al prossimo frame') print('A1 inviato / aggiornato') bm.stop_session() ``` ### 2) Esempio: inviare comando A2 (modalità / comandi radar) L'esempio mostra come cambiare la modalità principale (campo `rdr_mode_command`) in A2. ```python bm = BusMonitorCore() bm.initialize({}) bm.start_session() msg_a2 = bm.get_message('A2') if msg_a2 is None: raise RuntimeError('Wrapper A2 non trovato') # Impostare modalità radar (campo `rdr_mode_command` presente in MsgRdrOperationCommand) try: if hasattr(msg_a2.message.rdr_mode_command, 'set_master_mode'): msg_a2.message.rdr_mode_command.set_master_mode(1) # valore ICD di esempio else: msg_a2.message.rdr_mode_command.raw = 1 except Exception: raise if hasattr(msg_a2, 'send'): msg_a2.send() else: print('A2 aggiornato (MajorFrame invierà il dato)') bm.stop_session() ``` ### 3) Esempio: leggere stato B6 (RdrSettingsAndParametersTellback) B6 viene usato come tellback per ottenere impostazioni e parametri dal radar. Questo snippet mostra come registrare una callback per lettura asincrona e come leggere il valore al volo. ```python bm = BusMonitorCore() bm.initialize({}) bm.start_session() def on_b6(msg): try: # I campi nel tellback usano suffissi _tellback (es. settings_tellback) settings_tb = getattr(msg.message, 'settings_tellback', None) freq_tb = getattr(msg.message, 'frequency_tellback', None) print('B6 ricevuto: settings_tellback=', settings_tb, ' frequency_tellback=', freq_tb) except Exception as e: print('Errore nella callback B6:', e) bm.register_callback('msg_b6', on_b6) # Alternativa: lettura sincrona via get_message + accesso a campi tellback msg_b6 = bm.get_message('B6') if msg_b6: try: print('B6 - settings_tellback.raw:', getattr(msg_b6.message, 'settings_tellback').raw) except Exception: pass import time time.sleep(2) bm.stop_session() ``` ### 4) Esempio: leggere stato B7 (RdrStatusTellback) B7 contiene lo stato operativo; l'esempio mostra lettura e callback. ```python bm = BusMonitorCore() bm.initialize({}) bm.start_session() def on_b7(msg): try: # Il tellback per lo stato usa il campo `rdr_mode_tellback` e param*_tellback rdr_status = getattr(msg.message, 'rdr_mode_tellback', None) print('B7 ricevuto: rdr_mode_tellback=', rdr_status) except Exception as e: print('Errore nella callback B7:', e) bm.register_callback('msg_b7', on_b7) # Lettura diretta msg_b7 = bm.get_message('B7') if msg_b7: try: print('B7 - rdr_mode_tellback:', getattr(msg_b7.message, 'rdr_mode_tellback')) except Exception: pass time.sleep(2) bm.stop_session() ``` ### Note sui nomi dei campi - I nomi dei campi usati negli esempi (`settings`, `rdr_mode_command`, `status`, ecc.) sono quelli comunemente esposti dai wrappers interni ma possono variare a seconda della versione delle classi in `Grifo_E_1553lib.messages`. - Per conoscere i nomi esatti, usare `print(sorted(dir(msg.message)))` sul wrapper ottenuto da `get_message()` oppure consultare i file in `pybusmonitor1553/Grifo_E_1553lib/messages/`. ### Raccomandazioni finali - Testare gli snippet in un ambiente di laboratorio prima di usarli in produzione. - Proteggere i percorsi critici (callback, invio) con try/except e logging.