From 3213d61e5b60c44f36282bf5d4f39f33a238d244 Mon Sep 17 00:00:00 2001 From: VALLONGOL Date: Wed, 29 Oct 2025 11:10:59 +0100 Subject: [PATCH] sistemata la comunicazione via json, da sistemare quella mediante comando semplice tgtset/tgtinit --- settings.json | 2 +- target_simulator/core/sfp_communicator.py | 38 ++++++++++++++++ .../gui/connection_settings_window.py | 4 +- target_simulator/gui/sfp_debug_window.py | 44 ++++++++++++++++--- tools/udp_test_send.py | 2 +- 5 files changed, 79 insertions(+), 11 deletions(-) diff --git a/settings.json b/settings.json index adca711..9219dab 100644 --- a/settings.json +++ b/settings.json @@ -17,7 +17,7 @@ }, "sfp": { "ip": "127.0.0.1", - "port": 60001, + "port": 60003, "local_port": 60002, "use_json_protocol": true } diff --git a/target_simulator/core/sfp_communicator.py b/target_simulator/core/sfp_communicator.py index dfec95b..8b376b6 100644 --- a/target_simulator/core/sfp_communicator.py +++ b/target_simulator/core/sfp_communicator.py @@ -19,6 +19,7 @@ from target_simulator.utils.logger import get_logger from target_simulator.gui.payload_router import DebugPayloadRouter from target_simulator.analysis.simulation_state_hub import SimulationStateHub from target_simulator.config import DEBUG_CONFIG +import json class SFPCommunicator(CommunicatorInterface): @@ -219,6 +220,8 @@ class SFPCommunicator(CommunicatorInterface): # --- JSON Protocol Logic for scenario initialization --- self.logger.debug("Using JSON protocol for scenario initialization.") json_command = command_builder.build_json_update(scenario.get_all_targets()) + # Compact the JSON payload to a single-line string before saving/sending + json_command = self._compact_json_if_needed(json_command) self._save_json_payload_to_temp(json_command, "sfp_scenario_init") if not self._send_single_command(json_command): @@ -262,6 +265,8 @@ class SFPCommunicator(CommunicatorInterface): # Expect a single command string which is the JSON payload json_payload = commands[0] + # Compact JSON for live updates before saving/sending + json_payload = self._compact_json_if_needed(json_payload) self._save_json_payload_to_temp(json_payload, "sfp_live_update") return self._send_single_command(json_payload) else: @@ -275,8 +280,41 @@ class SFPCommunicator(CommunicatorInterface): def _send_single_command(self, command: str) -> bool: if not self.transport or not self._destination: return False + # As a final safeguard, compact JSON payloads here as well + try: + command = self._compact_json_if_needed(command) + except Exception: + pass return self.transport.send_script_command(command, self._destination) + def _compact_json_if_needed(self, command: str) -> str: + """If the command is a JSON document (starts with { or [), return a compact + single-line JSON string (no unnecessary spaces/newlines) with a trailing newline. + Otherwise return the original command unchanged. + """ + if not isinstance(command, str): + try: + command = str(command) + except Exception: + return command + + s = command.strip() + if not s: + return command + + if not (s.startswith("{") or s.startswith("[")): + return command + + try: + obj = json.loads(s) + compact = json.dumps(obj, separators=(',', ':')) + if not compact.endswith("\n"): + compact += "\n" + return compact + except Exception: + # If parsing fails, return original command (avoid changing it) + return command + @staticmethod def test_connection(config: Dict[str, Any]) -> bool: local_port = config.get("local_port") diff --git a/target_simulator/gui/connection_settings_window.py b/target_simulator/gui/connection_settings_window.py index 5bcedc7..05eab86 100644 --- a/target_simulator/gui/connection_settings_window.py +++ b/target_simulator/gui/connection_settings_window.py @@ -64,7 +64,7 @@ class ConnectionSettingsWindow(tk.Toplevel): target_cfg.get("serial", {}).get("baudrate", 9600) ) self.target_vars["sfp_ip"].set(target_sfp_cfg.get("ip", "127.0.0.1")) - self.target_vars["sfp_port"].set(target_sfp_cfg.get("port", 60001)) + self.target_vars["sfp_port"].set(target_sfp_cfg.get("port", 60003)) self.target_vars["sfp_local_port"].set(target_sfp_cfg.get("local_port", 60002)) self.target_vars["sfp_use_json"].set( target_sfp_cfg.get("use_json_protocol", False) @@ -93,7 +93,7 @@ class ConnectionSettingsWindow(tk.Toplevel): lru_cfg.get("serial", {}).get("baudrate", 9600) ) self.lru_vars["sfp_ip"].set(lru_sfp_cfg.get("ip", "127.0.0.1")) - self.lru_vars["sfp_port"].set(lru_sfp_cfg.get("port", 60001)) + self.lru_vars["sfp_port"].set(lru_sfp_cfg.get("port", 60003)) self.lru_vars["sfp_local_port"].set(lru_sfp_cfg.get("local_port", 60002)) self.lru_vars["sfp_use_json"].set(lru_sfp_cfg.get("use_json_protocol", False)) # Select the correct notebook tab for lru diff --git a/target_simulator/gui/sfp_debug_window.py b/target_simulator/gui/sfp_debug_window.py index 9f935e4..89063ab 100644 --- a/target_simulator/gui/sfp_debug_window.py +++ b/target_simulator/gui/sfp_debug_window.py @@ -76,7 +76,7 @@ class SfpDebugWindow(tk.Toplevel): self.image_area_size = 150 self.ip_var = tk.StringVar(value="127.0.0.1") self.local_port_var = tk.StringVar(value="60002") - self.server_port_var = tk.StringVar(value="60001") + self.server_port_var = tk.StringVar(value="60003") self.script_var = tk.StringVar(value="print('hello from client')") self.tgt_id_var = tk.IntVar(value=DEF_TEST_ID) self.tgt_range_var = tk.DoubleVar(value=DEF_TEST_RANGE) @@ -677,9 +677,10 @@ class SfpDebugWindow(tk.Toplevel): command_str = command_builder.build_tgtset_from_target_state( temp_target, include_flags=True ) - command_str = command_str.strip() - if not command_str.endswith("\n"): - command_str += "\n" + # Normalize/prefix legacy textual commands so the server receives the + # expected leading '$' and a trailing newline. Also log the final + # payload shown exactly as sent. + command_str = self._ensure_legacy_prefixed(command_str) self._log_to_widget(f"Built command: {command_str!r}", "INFO") success = self.shared_communicator._send_single_command(command_str) @@ -818,6 +819,8 @@ class SfpDebugWindow(tk.Toplevel): return try: command_str = self.script_var.get() + # Ensure legacy/textual script commands are prefixed with '$' as expected by server + command_str = self._ensure_legacy_prefixed(command_str) self.shared_communicator._send_single_command(command_str) except (ValueError, tk.TclError) as e: self._log_to_widget( @@ -833,6 +836,8 @@ class SfpDebugWindow(tk.Toplevel): return False try: + # Normalize legacy textual commands (prefix with $) before sending. + command_str = self._ensure_legacy_prefixed(command_str) success = self.shared_communicator._send_single_command(command_str) if success: self._log_to_widget(f"Successfully sent command: {command_str}", "INFO") @@ -908,9 +913,7 @@ class SfpDebugWindow(tk.Toplevel): return False else: command_str = command_builder.build_tgtset_selective(target_id, updates) - command_str = command_str.strip() - if command_str and not command_str.endswith("\n"): - command_str = command_str + "\n" + # _on_send_simple_command will normalize/prefix as needed return self._on_send_simple_command(command_str) except (ValueError, tk.TclError) as e: self._log_to_widget(f"ERROR: Invalid input for tgtset: {e}", "ERROR") @@ -1329,6 +1332,33 @@ class SfpDebugWindow(tk.Toplevel): self.log_tab.config(state=tk.DISABLED) self.log_tab.see(tk.END) + def _ensure_legacy_prefixed(self, command: str) -> str: + """Normalize textual/legacy commands: ensure they end with a newline. + + If the string looks like JSON (starts with '{' or '['), do not alter it + other than ensuring a trailing newline. Bytes are decoded as UTF-8. + Former behavior prefixed '$' to legacy commands; that has been removed + because the DSP expects plain 'tgtset' commands. + """ + try: + if isinstance(command, (bytes, bytearray)): + s = command.decode("utf-8") + else: + s = str(command) + except Exception: + s = str(command) + + s = s.strip() + if not s: + return s + + # If it looks like JSON (starts with { or [), leave structure intact + # but ensure a trailing newline. For legacy textual commands, do not + # add any special prefix — just ensure newline. + if not s.endswith("\n"): + s = s + "\n" + return s + def _on_save_ris_csv(self): try: import csv diff --git a/tools/udp_test_send.py b/tools/udp_test_send.py index 1c06e47..fcf0317 100644 --- a/tools/udp_test_send.py +++ b/tools/udp_test_send.py @@ -10,7 +10,7 @@ import os from target_simulator.core.sfp_transport import SfpTransport LISTEN_IP = "127.0.0.1" -LISTEN_PORT = 60001 +LISTEN_PORT = 60003 CLIENT_BIND_PORT = 60002 received = []