220 lines
7.2 KiB
Python
220 lines
7.2 KiB
Python
import time
|
|
import sys
|
|
import os
|
|
import argparse
|
|
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
|
|
|
|
#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
|
|
|
|
print("--------------------------------------------------")
|
|
print(" PyBusMonitor1553 - Active Controller (GUI Mode)")
|
|
print("--------------------------------------------------")
|
|
|
|
# Initialize Tkinter
|
|
root = tk.Tk()
|
|
app = BusMonitorApp(root)
|
|
|
|
# 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 menu actions
|
|
def on_connect():
|
|
network.start()
|
|
scheduler.start()
|
|
app.update_connection_status(True, tx_count[0], rx_count[0], "")
|
|
|
|
def on_disconnect():
|
|
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
|
|
|
|
# Start networking
|
|
network.register_callback(on_packet)
|
|
network.start()
|
|
scheduler.start()
|
|
|
|
# Update initial status
|
|
app.update_connection_status(True, 0, 0, "")
|
|
|
|
print(f"GUI Running.")
|
|
print(f"RX: {RX_IP}:{RX_PORT} | TX: {TARGET_IP}:{TARGET_PORT}")
|
|
|
|
# Handle window close
|
|
def on_closing():
|
|
scheduler.stop()
|
|
network.stop()
|
|
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() |