From 7e120a0f72813430db296f6a04142faa53aa585e Mon Sep 17 00:00:00 2001 From: VALLONGOL Date: Fri, 31 Oct 2025 11:22:02 +0100 Subject: [PATCH] aggiunto reset target iniziale prima dello start della simulazione mediante comandi json --- scenarios.json | 386 ++++++++++++++++++++++- settings.json | 2 +- target_simulator/core/command_builder.py | 78 ++++- target_simulator/gui/main_view.py | 50 ++- 4 files changed, 501 insertions(+), 15 deletions(-) diff --git a/scenarios.json b/scenarios.json index 187e2d6..061cb48 100644 --- a/scenarios.json +++ b/scenarios.json @@ -1,5 +1,385 @@ { - "s1": { - "a": 1 - } + "scenario1": { + "name": "scenario1", + "targets": [ + { + "target_id": 0, + "active": true, + "traceable": true, + "trajectory": [ + { + "maneuver_type": "Fly to Point", + "duration_s": 10.0, + "target_altitude_ft": 10000.0, + "target_range_nm": 20.0, + "target_azimuth_deg": 0.0 + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 100.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 1670.9318999999994, + "target_heading_deg": 10.0 + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 400.0, + "target_altitude_ft": 10000.0, + "target_range_nm": 25.0, + "target_azimuth_deg": -20.0 + } + ], + "use_spline": false + } + ] + }, + "scenario2": { + "name": "scenario2", + "targets": [ + { + "target_id": 0, + "active": true, + "traceable": true, + "trajectory": [ + { + "maneuver_type": "Fly to Point", + "duration_s": 10.0, + "target_range_nm": 10.0, + "target_azimuth_deg": -3.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 0.0, + "target_heading_deg": 0.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 200.0, + "target_range_nm": 20.0, + "target_azimuth_deg": 10.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 200.0, + "target_range_nm": 30.0, + "target_azimuth_deg": -10.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 200.0, + "target_range_nm": 35.0, + "target_azimuth_deg": 10.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 200.0, + "target_range_nm": 35.0, + "target_azimuth_deg": 30.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 200.0, + "target_range_nm": 20.0, + "target_azimuth_deg": 45.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + } + ], + "use_spline": true + }, + { + "target_id": 1, + "active": true, + "traceable": true, + "trajectory": [ + { + "maneuver_type": "Fly to Point", + "duration_s": 10.0, + "target_range_nm": 10.0, + "target_azimuth_deg": 10.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 10.0, + "target_range_nm": 20.0, + "target_azimuth_deg": 20.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 30.0, + "target_range_nm": 30.0, + "target_azimuth_deg": 30.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 30.0, + "target_range_nm": 35.0, + "target_azimuth_deg": -10.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + } + ], + "use_spline": true + }, + { + "target_id": 2, + "active": true, + "traceable": true, + "trajectory": [ + { + "maneuver_type": "Fly to Point", + "duration_s": 1.0, + "target_range_nm": 28.0, + "target_azimuth_deg": 0.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 180.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 300.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 180.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Dynamic Maneuver", + "duration_s": 9.0, + "maneuver_speed_fps": 1519.0289999999995, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 9.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 100.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 1012.686, + "target_heading_deg": -90.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + } + ], + "use_spline": false + } + ] + }, + "scenario3": { + "name": "scenario3", + "targets": [ + { + "target_id": 0, + "active": true, + "traceable": true, + "trajectory": [ + { + "maneuver_type": "Fly to Point", + "duration_s": 10.0, + "target_range_nm": 5.0, + "target_azimuth_deg": 0.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 180.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 20.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 90.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 10.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 180.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 20.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 90.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 30.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": -180.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + } + ], + "use_spline": true + } + ] + }, + "scenario_9g": { + "name": "scenario2", + "targets": [ + { + "target_id": 2, + "active": true, + "traceable": true, + "trajectory": [ + { + "maneuver_type": "Fly to Point", + "duration_s": 1.0, + "target_range_nm": 28.0, + "target_azimuth_deg": 0.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 180.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 300.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 180.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Dynamic Maneuver", + "duration_s": 9.0, + "maneuver_speed_fps": 1519.0289999999995, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 9.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly for Duration", + "duration_s": 100.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 1012.686, + "target_heading_deg": -90.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + } + ], + "use_spline": false + } + ] + }, + "scenario_dritto": { + "name": "scenario_dritto", + "targets": [ + { + "target_id": 0, + "active": true, + "traceable": true, + "trajectory": [ + { + "maneuver_type": "Fly to Point", + "duration_s": 1.0, + "target_range_nm": 20.0, + "target_azimuth_deg": -45.0, + "target_altitude_ft": 10000.0, + "target_velocity_fps": 506.343, + "target_heading_deg": 90.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + }, + { + "maneuver_type": "Fly to Point", + "duration_s": 100.0, + "target_range_nm": 20.0, + "target_azimuth_deg": 45.0, + "target_altitude_ft": 10000.0, + "longitudinal_acceleration_g": 0.0, + "lateral_acceleration_g": 0.0, + "vertical_acceleration_g": 0.0, + "turn_direction": "Right" + } + ], + "use_spline": false + } + ] + } } \ No newline at end of file diff --git a/settings.json b/settings.json index b97507c..fbb94c9 100644 --- a/settings.json +++ b/settings.json @@ -3,7 +3,7 @@ "scan_limit": 60, "max_range": 100, "geometry": "1599x1089+587+179", - "last_selected_scenario": null, + "last_selected_scenario": "scenario1", "connection": { "target": { "type": "sfp", diff --git a/target_simulator/core/command_builder.py b/target_simulator/core/command_builder.py index d8d350d..1c78520 100644 --- a/target_simulator/core/command_builder.py +++ b/target_simulator/core/command_builder.py @@ -7,7 +7,7 @@ Constructs MMI command strings based on high-level data models. import json from typing import Dict, Any, List, Optional -from .models import Target +from .models import Target, Waypoint, ManeuverType from target_simulator.utils.logger import get_logger logger = get_logger(__name__) @@ -173,3 +173,79 @@ def build_acunlatch() -> str: def build_reset() -> str: """Builds the 'reset' command.""" return "reset" + + +def build_json_reset_ids(max_id: int = 31, max_bytes: int = 1020) -> list[str]: + """ + Build one or more compact JSON payload strings that contain target entries + for IDs 0..max_id with all numeric fields zeroed and flags cleared. This + mirrors the behaviour of the SFP debug window's "Reset IDs" action and + returns a list of newline-terminated compact JSON payloads that fit within + the provided transport size limit. + + Args: + max_id: Highest target id to include (inclusive). Defaults to 31. + max_bytes: Maximum bytes allowed per payload (transport limit). + + Returns: + List of JSON payload strings (each ends with '\n'). + """ + targets = [] + for tid in range(0, max_id + 1): + wp = Waypoint( + maneuver_type=ManeuverType.FLY_TO_POINT, + target_range_nm=0.0, + target_azimuth_deg=0.0, + target_altitude_ft=0.0, + target_velocity_fps=0.0, + target_heading_deg=0.0, + ) + t = Target(target_id=tid, trajectory=[wp]) + t.active = False + t.traceable = False + t.restart = False + t.current_range_nm = 0.0 + t.current_azimuth_deg = 0.0 + t.current_velocity_fps = 0.0 + t.current_heading_deg = 0.0 + t.current_altitude_ft = 0.0 + targets.append(t) + + import json as _json + + def build_compact_payload(tlist: list[Target]) -> str: + s = build_json_update(tlist) + try: + obj = _json.loads(s) + compact = _json.dumps(obj, separators=(",", ":")) + except Exception: + compact = s.replace("\n", "").replace("\r", "") + return compact + + n = len(targets) + batch_size = n + while batch_size > 0: + payload = build_compact_payload(targets[:batch_size]) + if len(payload.encode("utf-8")) <= max_bytes: + break + batch_size -= 1 + + if batch_size == 0: + # As a defensive fallback, return the full list as a single (possibly + # oversize) payload so callers can attempt to send it and handle errors. + payload = build_compact_payload(targets) + if not payload.endswith("\n"): + payload = payload + "\n" + return [payload] + + payloads: list[str] = [] + i = 0 + while i < n: + j = min(i + batch_size, n) + p = build_compact_payload(targets[i:j]) + if not p.endswith("\n"): + p = p + "\n" + payloads.append(p) + i = j + + return payloads diff --git a/target_simulator/gui/main_view.py b/target_simulator/gui/main_view.py index 3e80273..88f37ef 100644 --- a/target_simulator/gui/main_view.py +++ b/target_simulator/gui/main_view.py @@ -722,20 +722,50 @@ class MainView(tk.Tk): use_json = False if use_json: - # The server expects a single JSON payload to perform a reset. - json_reset = '{"CMD":"reset"}\n' - commands_to_send = [json_reset] - self.logger.info("Using JSON reset payload for radar reset.") + # Use the same Reset IDs JSON payload sequence as provided by the + # SFP debug window: build one-or-more compact JSON payloads that + # explicitly disable all target IDs and send them in order. + try: + json_payloads = command_builder.build_json_reset_ids() + self.logger.info( + "Using JSON Reset IDs payloads for radar reset (parts=%d).", + len(json_payloads), + ) + except Exception: + self.logger.exception( + "Failed to build Reset IDs JSON payloads; falling back to simple JSON reset." + ) + json_payloads = ['{"CMD":"reset"}\n'] + commands_to_send = json_payloads else: # Legacy textual reset sequence (no leading $; newline-terminated strings) commands_to_send = [prep_command, reset_command + "\n"] - if not self.target_communicator.send_commands(commands_to_send): - self.logger.error("Failed to send preparatory/reset commands to the radar.") - messagebox.showerror( - "Reset Error", "Failed to send reset command to the radar." - ) - return False + # When using JSON protocol, send each payload part individually. + if use_json: + all_ok = True + for payload in commands_to_send: + try: + ok = self.target_communicator.send_commands([payload]) + except Exception: + self.logger.exception("Exception while sending JSON reset payload") + ok = False + if not ok: + all_ok = False + self.logger.error("Failed to send JSON reset payload part.") + break + if not all_ok: + messagebox.showerror( + "Reset Error", "Failed to send reset payload(s) to the radar." + ) + return False + else: + if not self.target_communicator.send_commands(commands_to_send): + self.logger.error("Failed to send preparatory/reset commands to the radar.") + messagebox.showerror( + "Reset Error", "Failed to send reset command to the radar." + ) + return False self.logger.info( "Successfully sent preparatory and atomic reset commands: %s",