SXXXXXXX_PyBusMonitor1553/pybusmonitor1553/__main__.py

232 lines
7.7 KiB
Python

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('<H', data_bytes[i:i+2])[0]
raw_words.append(word)
# Accoda aggiornamento invece di usare root.after() diretto
app.queue_message_update(short_name, msg, raw_words)
# Accoda aggiornamento status invece di usare root.after() diretto
app.queue_status_update(True, tx_count[0], rx_count[0], "")
# Wrap scheduler send to count TX
original_send = network.send
def counted_send(data, ip, port):
tx_count[0] += 1
return original_send(data, ip, port)
network.send = counted_send
# Register callback for sent messages (A messages)
def on_message_sent(msg):
if not msg.IS_TRANSMIT: # BC->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()