import time import sys import os import argparse import logging import tkinter as tk from .core.network import UdpHandler from .core.dispatcher import MessageDispatcher from .core.scheduler import TrafficScheduler from .core.controller import RadarController from .utils.printer import dump_message from .gui.main_window import BusMonitorApp logger = logging.getLogger(__name__) #Configuration RX_IP = os.getenv("PYBM_RX_IP", "127.0.0.1") RX_PORT = int(os.getenv("PYBM_RX_PORT", str(61553))) TARGET_IP = os.getenv("PYBM_TARGET_IP", "127.0.0.1") TARGET_PORT = int(os.getenv("PYBM_TARGET_PORT", "51553")) def main_cli(): """Command-line interface mode (original behavior)""" print("--------------------------------------------------") print(" PyBusMonitor1553 - Active Controller (CLI Mode)") print("--------------------------------------------------") # 1. Initialize Components dispatcher = MessageDispatcher() network = UdpHandler(rx_ip=RX_IP, rx_port=RX_PORT) # 2. Initialize Radar Logic Controller radar_ctrl = RadarController() # 3. Initialize Scheduler with the Controller scheduler = TrafficScheduler(network, radar_ctrl, TARGET_IP, TARGET_PORT) # 4. Define the callback for received messages def on_packet(data, addr): header, messages = dispatcher.parse_packet(data) if messages: for msg in messages: if msg.IS_TRANSMIT: print(f"\n[RX] {msg.__class__.__name__} from RT{header.ta if header else '?'}") dump_message(msg) elif header and header.errors != 0: print(f"[RX] Server Error Code: {header.errors}") # 5. Start everything network.register_callback(on_packet) network.start() scheduler.start() print(f"System Running.") print(f"RX: {RX_IP}:{RX_PORT} | TX: {TARGET_IP}:{TARGET_PORT}") print("Press Ctrl+C to stop.") try: while True: time.sleep(1) except KeyboardInterrupt: print("\nStopping...") finally: scheduler.stop() network.stop() sys.exit(0) def main_gui(): """Graphical user interface mode""" # Enable quiet mode for scheduler from .core import scheduler as sched_module sched_module.QUIET_MODE = True # Initialize Tkinter root = tk.Tk() app = BusMonitorApp(root) # Log banner AFTER TkinterLogger is initialized logger.info("=" * 50) logger.info("PyBusMonitor1553 - Active Controller (GUI Mode)") logger.info("=" * 50) # Initialize Components dispatcher = MessageDispatcher() network = UdpHandler(rx_ip=RX_IP, rx_port=RX_PORT) radar_ctrl = RadarController() scheduler = TrafficScheduler(network, radar_ctrl, TARGET_IP, TARGET_PORT) # Counters for status bar tx_count = [0] rx_count = [0] # Define the callback for received messages def on_packet(data, addr): header, messages = dispatcher.parse_packet(data) rx_count[0] += 1 if messages: for msg in messages: if msg.IS_TRANSMIT: msg_name = msg.__class__.__name__ # Convert MsgB6 -> B6, MsgA1 -> A1, etc. short_name = msg_name.replace("Msg", "") # Extract raw words if available raw_words = [] if hasattr(msg, '_raw_data') and msg._raw_data: import struct data_bytes = msg._raw_data for i in range(0, len(data_bytes), 2): if i + 1 < len(data_bytes): word = struct.unpack('RT messages (A messages) msg_name = msg.__class__.__name__ short_name = msg_name.replace("Msg", "") # Extract raw words from current message state raw_words = [] if hasattr(msg, '_data'): raw_words = list(msg._data)[:32] # Copy first 32 words # Accoda aggiornamento invece di usare root.after() diretto app.queue_message_update(short_name, msg, raw_words) scheduler.register_sent_callback(on_message_sent) # Wire up RUN/STOP button actions def on_connect(): """Called when RUN button is pressed""" logger.info("Applying default radar configuration...") radar_ctrl.apply_defaults() # Apply defaults only when RUN is pressed logger.info("Starting network and scheduler...") network.start() scheduler.start() app.update_connection_status(True, tx_count[0], rx_count[0], "") def on_disconnect(): """Called when STOP button is pressed""" logger.info("Stopping scheduler and network...") scheduler.stop() network.stop() app.update_connection_status(False, tx_count[0], rx_count[0], "") app._on_connect = on_connect app._on_disconnect = on_disconnect # Register callback but DON'T start automatically - wait for RUN button network.register_callback(on_packet) # Update initial status (disconnected) app.update_connection_status(False, 0, 0, "") logger.info(f"GUI Ready - RX: {RX_IP}:{RX_PORT} | TX: {TARGET_IP}:{TARGET_PORT}") logger.info("Press RUN to start communication") # Handle window close def on_closing(): if scheduler._running: scheduler.stop() if network._running: network.stop() app.shutdown() root.destroy() root.protocol("WM_DELETE_WINDOW", on_closing) # Run the GUI main loop try: root.mainloop() except KeyboardInterrupt: on_closing() def main(): """Main entry point with mode selection""" global TARGET_IP, TARGET_PORT parser = argparse.ArgumentParser( description='PyBusMonitor1553 - MIL-STD-1553 Bus Monitor', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=''' Examples: python -m pybusmonitor1553 # Launch GUI mode (default) python -m pybusmonitor1553 --cli # Launch CLI mode python -m pybusmonitor1553 --gui # Launch GUI mode explicitly ''' ) parser.add_argument('--cli', action='store_true', help='Run in command-line interface mode') parser.add_argument('--gui', action='store_true', help='Run in graphical user interface mode (default)') parser.add_argument('--target', type=str, default=None, help=f'Target IP address (default: {TARGET_IP})') parser.add_argument('--port', type=int, default=None, help=f'Target port (default: {TARGET_PORT})') args = parser.parse_args() # Update globals if specified if args.target: TARGET_IP = args.target if args.port: TARGET_PORT = args.port if args.cli: main_cli() else: main_gui() if __name__ == "__main__": main()