modificato l'invio del reset con il comando json corretto

This commit is contained in:
VALLONGOL 2025-10-29 13:43:50 +01:00
parent 17cd4ea79f
commit ca13144c1d
7 changed files with 296 additions and 172 deletions

View File

@ -1,168 +1,5 @@
{ {
"scenario1": { "s1": {
"name": "scenario1", "a": 1
"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",
"target_velocity_fps": 1670.9318999999994,
"target_heading_deg": 10.0,
"duration_s": 300.0,
"target_altitude_ft": 10000.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
}
]
}
]
},
"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": 1.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": 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": false
}
]
} }
} }

View File

@ -1,5 +1,5 @@
{ {
"s1": { "s1": {
"foo": 123 "a": 1
} }
} }

168
scenarios.json.bak2 Normal file
View File

@ -0,0 +1,168 @@
{
"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",
"target_velocity_fps": 1670.9318999999994,
"target_heading_deg": 10.0,
"duration_s": 300.0,
"target_altitude_ft": 10000.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
}
]
}
]
},
"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": 1.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": 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": false
}
]
}
}

5
scenarios.json.bak3 Normal file
View File

@ -0,0 +1,5 @@
{
"s1": {
"foo": 123
}
}

View File

@ -706,10 +706,29 @@ class MainView(tk.Tk):
) )
reset_command = "tgtset /-s" reset_command = "tgtset /-s"
# Some radar servers require adjusting internal parameters. # Some radar servers require adjusting internal parameters for legacy mode.
prep_command = "$mex.t_rows=80" # Use the non-$ textual commands and ensure newline termination per the
# user's request: send exactly "mex.t_rows=80\n" and "tgtset /-s\n".
prep_command = "mex.t_rows=80\n"
commands_to_send = [prep_command, reset_command] # If the communicator was configured to use the JSON protocol, send
# the JSON reset command expected by the server. Otherwise, fall back
# to the legacy prep + atomic reset command sequence.
try:
use_json = bool(
getattr(self.target_communicator, "_use_json_protocol", False)
)
except Exception:
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.")
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): if not self.target_communicator.send_commands(commands_to_send):
self.logger.error("Failed to send preparatory/reset commands to the radar.") self.logger.error("Failed to send preparatory/reset commands to the radar.")

View File

@ -416,6 +416,15 @@ class SfpDebugWindow(tk.Toplevel):
command_builder.build_tgtreset() command_builder.build_tgtreset()
), ),
).pack(side=tk.LEFT, padx=4) ).pack(side=tk.LEFT, padx=4)
# Add a dedicated Reset button that sends either the JSON reset
# payload or the legacy textual reset sequence depending on the
# selected send mode. The legacy textual commands are sent exactly
# as requested (no leading '$', newline-terminated lines).
ttk.Button(
quick_cmd_frame,
text="reset",
command=self._on_send_reset_button,
).pack(side=tk.LEFT, padx=4)
ttk.Button( ttk.Button(
quick_cmd_frame, quick_cmd_frame,
text="pause", text="pause",
@ -827,6 +836,38 @@ class SfpDebugWindow(tk.Toplevel):
f"ERROR: Invalid input for script sending: {e}", "ERROR" f"ERROR: Invalid input for script sending: {e}", "ERROR"
) )
def _on_send_reset_button(self):
"""Send a reset to the radar: JSON reset if JSON mode selected,
otherwise send legacy textual reset lines exactly as requested by the user.
"""
if not self.shared_communicator or not self.shared_communicator.is_open:
self._log_to_widget("ERROR: Cannot send reset, not connected.", "ERROR")
messagebox.showerror(
"Connection Error", "Communicator is not connected.", parent=self
)
return False
try:
if self.send_mode_var.get() == "json":
json_payload = '{"CMD":"reset"}'
# Ensure trailing newline
if not json_payload.endswith("\n"):
json_payload = json_payload + "\n"
self._log_to_widget("Sending JSON reset payload...", "INFO")
return self._on_send_simple_command(json_payload)
else:
# Legacy textual reset: send precisely 'mex.t_rows=80' and 'tgtset /-s' each newline-terminated
cmd1 = "mex.t_rows=80\n"
cmd2 = "tgtset /-s\n"
self._log_to_widget("Sending legacy reset sequence...", "INFO")
ok1 = self._on_send_simple_command(cmd1)
ok2 = self._on_send_simple_command(cmd2)
return bool(ok1 and ok2)
except Exception:
self.logger.exception("Failed to send reset command from debug window")
self._log_to_widget("ERROR: Failed to send reset.", "ERROR")
return False
def _on_send_simple_command(self, command_str: str): def _on_send_simple_command(self, command_str: str):
if not self.shared_communicator or not self.shared_communicator.is_open: if not self.shared_communicator or not self.shared_communicator.is_open:
self._log_to_widget("ERROR: Cannot send command, not connected.", "ERROR") self._log_to_widget("ERROR: Cannot send command, not connected.", "ERROR")

View File

@ -1,3 +1,57 @@
import logging
from unittest.mock import Mock
import pytest
from target_simulator.gui import main_view as mv
def _make_minimal_mainview_with_comm(use_json: bool):
# Bypass __init__ to avoid Tkinter initialization in tests
inst = mv.MainView.__new__(mv.MainView)
# Provide a simple logger
inst.logger = logging.getLogger("test.main_view")
# Mock communicator
comm = Mock()
comm.is_open = True
# Emulate the internal flag used by MainView to decide JSON vs legacy
setattr(comm, "_use_json_protocol", use_json)
comm.send_commands.return_value = True
inst.target_communicator = comm
# Mock simulation hub: immediate empty state so reset returns quickly
hub = Mock()
hub.has_active_real_targets.return_value = False
inst.simulation_hub = hub
return inst, comm
def test_reset_uses_json_when_configured():
inst, comm = _make_minimal_mainview_with_comm(use_json=True)
ok = inst._reset_radar_state()
assert ok is True
# send_commands should be called once with the JSON reset payload
assert comm.send_commands.called
sent = comm.send_commands.call_args[0][0]
assert isinstance(sent, list)
assert sent == ['{"CMD":"reset"}\n']
def test_reset_uses_legacy_when_not_configured():
inst, comm = _make_minimal_mainview_with_comm(use_json=False)
ok = inst._reset_radar_state()
assert ok is True
assert comm.send_commands.called
sent = comm.send_commands.call_args[0][0]
assert isinstance(sent, list)
assert sent == ["mex.t_rows=80\n", "tgtset /-s\n"]
import pytest import pytest
from target_simulator.gui.main_view import MainView from target_simulator.gui.main_view import MainView
from target_simulator.core.models import Target from target_simulator.core.models import Target
@ -40,7 +94,7 @@ def test_reset_radar_state_sends_atomic_tgtset(main_view):
# Expect success # Expect success
assert result is True assert result is True
# Verify that two commands were sent: preparatory $mex.t_rows=80 then tgtset /-s # Verify that two commands were sent: preparatory mex.t_rows=80 then tgtset /-s
assert len(mv.target_communicator.sent_commands) == 2 assert len(mv.target_communicator.sent_commands) == 2
assert mv.target_communicator.sent_commands[0].strip() == "$mex.t_rows=80" assert mv.target_communicator.sent_commands[0].strip() == "mex.t_rows=80"
assert mv.target_communicator.sent_commands[1].strip() == "tgtset /-s" assert mv.target_communicator.sent_commands[1].strip() == "tgtset /-s"