SXXXXXXX_PyMsc/pymsc/__main__.py
2026-01-12 09:15:25 +01:00

235 lines
9.4 KiB
Python

# -*- coding: utf-8 -*-
"""
ARTOS - Advanced Radar Test & Orchestration System
Main entry point for the modular docking GUI.
"""
import sys
import os
import logging
import threading
import time
from datetime import datetime
# Add external logger module to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '_external', 'externals', 'python-tkinter-logger'))
# Ensure local imports work correctly
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from pymsc.core.bus_1553_module import Bus1553Module
from pymsc.gui.main_docking_window import MainDockingWindow
from pymsc.utils.profiler import print_stats, save_stats_to_csv
# Global flag to control the time update thread
_time_update_running = False
_time_update_thread = None
_logger_system = None
def update_radar_datetime_periodically(bus_module):
"""
Background thread that updates msg_a1 date and time every 2 seconds.
This keeps the radar's mission clock synchronized with system time.
Args:
bus_module: Bus1553Module instance to access MessageDB
"""
global _time_update_running
logger = logging.getLogger('ARTOS.TimeSync')
logger.info("Date/time update thread started (2-second interval)")
# Get MessageDB from BusMonitorCore (the correct instance that's being used)
try:
messagedb = bus_module.core._messagedb
if messagedb is None:
logger.error("MessageDB not cached in BusMonitorCore - date/time sync disabled")
return
except AttributeError as e:
logger.error(f"Could not access MessageDB from bus_module: {e}")
return
# Wait for MessageDB to be populated
max_wait = 10 # seconds
waited = 0
while _time_update_running and waited < max_wait:
all_messages = messagedb.getAllMessages()
if "A1" in all_messages:
logger.info(f"A1 message found in MessageDB - starting date/time synchronization")
break
time.sleep(0.5)
waited += 0.5
if waited >= max_wait:
available_keys = list(messagedb.getAllMessages().keys()) if messagedb else []
logger.error(f"A1 message not found in MessageDB after {max_wait}s. Available: {available_keys}")
return
while _time_update_running:
try:
now = datetime.now()
# Get the actual A1 message singleton that gets sent to the radar
all_messages = messagedb.getAllMessages()
if "A1" not in all_messages:
logger.warning("A1 message disappeared from MessageDB")
time.sleep(2.0)
continue
a1_msg = messagedb.getMessage("A1")
# Update date fields in the actual message structure
year = now.year % 100
a1_msg.message.date_of_mission.set_year_of_mission(year)
a1_msg.message.date_of_mission.set_month_of_mission(now.month)
a1_msg.message.date_of_mission.set_day_of_mission(now.day)
# Update time field: seconds since midnight divided by 2 (LSB = 2s)
seconds_since_midnight = now.hour * 3600 + now.minute * 60 + now.second
a1_msg.message.time_of_mission.set(seconds_since_midnight // 2)
# The message will be sent automatically by the periodic frame sender
except Exception as e:
logger.error(f"Error updating date/time: {e}", exc_info=True)
# Sleep for 2 seconds before next update
time.sleep(2.0)
logger.info("Date/time update thread stopped")
def main():
"""
ARTOS Application Entry Point.
Initializes the 1553 bus module and launches the modular docking GUI.
"""
# Create logs directory first
os.makedirs('logs', exist_ok=True)
# Initialize TkinterLogger IMMEDIATELY (before any logging)
# This ensures consistent formatting from the start
from tkinter_logger import TkinterLogger
# Create logger system without Tkinter widget initially (console + file only)
global _logger_system
_logger_system = TkinterLogger(tk_root=None)
_logger_system.setup(
enable_console=True,
enable_file=True,
file_path='logs/artos.log',
file_max_bytes=10 * 1024 * 1024, # 10MB
file_backup_count=5,
enable_tkinter=False, # Will add Tkinter handler later
root_level=logging.INFO
)
logger = logging.getLogger('ARTOS')
logger.info("=" * 60)
logger.info("Starting ARTOS - Advanced Radar Test & Orchestration System")
logger.info("=" * 60)
try:
# Initialize the 1553 bus module
logger.info("Initializing Bus 1553 Module...")
bus_module = Bus1553Module()
# Configure bus communication
config = {
'udp_send_ip': '127.0.0.1',
'udp_send_port': 51553,
'udp_recv_ip': '0.0.0.0',
'udp_recv_port': 61553
}
if bus_module.initialize(config):
logger.info("Bus 1553 Module initialized successfully.")
else:
logger.warning("Bus 1553 Module initialization returned False.")
# Start 1553 communication session automatically
logger.info("Starting 1553 Bus communication session...")
bus_module.start_session()
logger.info("1553 Bus session started - ready to communicate with radar.")
# Initialize date and time of mission with current date/time
logger.info("Setting current date and time in mission parameters...")
# Wait a moment for MessageDB to be fully populated
time.sleep(0.5)
try:
# Get MessageDB from BusMonitorCore (the correct instance that's being used)
messagedb = bus_module.core._messagedb
if messagedb is None:
logger.warning("MessageDB not cached in BusMonitorCore")
logger.info("Date/time will be set by periodic update thread once MessageDB is available")
else:
# Check if A1 message exists in MessageDB
all_messages = messagedb.getAllMessages()
if "A1" not in all_messages:
logger.warning(f"A1 message not yet in MessageDB. Available messages: {list(all_messages.keys())}")
logger.info("Date/time will be set by periodic update thread once A1 is available")
else:
now = datetime.now()
# Get the actual A1 message singleton that gets sent to the radar
a1_msg = messagedb.getMessage("A1")
# Set date: year (last 2 digits), month, day
year = now.year % 100 # Last 2 digits (e.g., 2026 -> 26)
a1_msg.message.date_of_mission.set_year_of_mission(year)
a1_msg.message.date_of_mission.set_month_of_mission(now.month)
a1_msg.message.date_of_mission.set_day_of_mission(now.day)
# Set time: seconds since midnight divided by 2 (LSB = 2s)
seconds_since_midnight = now.hour * 3600 + now.minute * 60 + now.second
a1_msg.message.time_of_mission.set(seconds_since_midnight // 2)
logger.info(f"Mission date/time set to: {now.strftime('%Y-%m-%d %H:%M:%S')}")
logger.info(f" - Year: {year}, Month: {now.month}, Day: {now.day}")
logger.info(f" - Time value (secs//2): {seconds_since_midnight // 2}")
except Exception as e:
logger.error(f"Failed to initialize date/time: {e}", exc_info=True)
# Start periodic date/time update thread (every 2 seconds)
# This keeps msg_a1 (Radar Settings) date/time synchronized with system time
global _time_update_running, _time_update_thread
_time_update_running = True
_time_update_thread = threading.Thread(
target=update_radar_datetime_periodically,
args=(bus_module,), # Pass bus_module to access MessageDB
daemon=True,
name="RadarTimeSync"
)
_time_update_thread.start()
logger.info("Started periodic date/time synchronization (msg_a1, every 2 seconds)")
# Create and launch the modular docking GUI
logger.info("Launching ARTOS Docking GUI...")
app = MainDockingWindow(bus_module, logger_system=_logger_system)
# Start widget refresh loops to display live data
logger.info("Starting GUI refresh loops...")
app._start_refresh()
logger.info("GUI refresh active - widgets will update automatically.")
# Store cleanup references in app for use in _on_close
app._cleanup_time_thread = lambda: setattr(globals(), '_time_update_running', False)
app._time_update_thread = _time_update_thread
# Note: MainDockingWindow handles WM_DELETE_WINDOW with its own _on_close()
# which calls os._exit(0) for immediate termination
# Start the GUI main loop
logger.info("ARTOS GUI ready. Starting main loop...")
app.run()
except Exception as e:
logger.error(f"Critical error during ARTOS startup: {e}", exc_info=True)
sys.exit(1)
if __name__ == "__main__":
main()