From e72aa8314ee77f3b6dcfd9d579818f682b2a8247 Mon Sep 17 00:00:00 2001 From: VALLONGOL Date: Fri, 7 Nov 2025 10:49:07 +0100 Subject: [PATCH] sistemato posizionamento in azimuth dei target --- target_simulator/gui/payload_router.py | 74 +++++++++++++++++++++++++- target_simulator/gui/ppi_display.py | 2 +- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/target_simulator/gui/payload_router.py b/target_simulator/gui/payload_router.py index 41fb1a1..b3aa24b 100644 --- a/target_simulator/gui/payload_router.py +++ b/target_simulator/gui/payload_router.py @@ -78,7 +78,11 @@ class DebugPayloadRouter: ord("M"): lambda p: self._update_last_payload("MFD", p), ord("S"): lambda p: self._update_last_payload("SAR", p), ord("B"): lambda p: self._update_last_payload("BIN", p), - ord("J"): lambda p: self._update_last_payload("JSON", p), + # JSON payloads may contain antenna nav fields (ant_nav_az / ant_nav_el). + # Route JSON to a dedicated handler that will both store the raw + # payload and, when possible, extract antenna az/el to update the hub + # so the PPI antenna sweep can animate even when using JSON protocol. + ord("J"): self._handle_json_payload, ord("R"): self._handle_ris_status, ord("r"): self._handle_ris_status, } @@ -341,6 +345,74 @@ class DebugPayloadRouter: except Exception: self._logger.exception("Failed to generate text/JSON for RIS debug view.") + def _handle_json_payload(self, payload: bytearray): + """ + Handle JSON payloads. Store raw JSON and, if present, extract + antenna navigation fields (ant_nav_az / ant_nav_el) and propagate + them to the SimulationStateHub so the PPI antenna can animate. + """ + try: + # Always store the raw payload for debug inspection + self._update_last_payload("JSON", payload) + + if not self._hub: + return + + # Try to decode and parse JSON + try: + text = payload.decode("utf-8") + obj = json.loads(text) + except Exception: + return + + # The JSON may follow the same structure as the RIS debug JSON + # we generate elsewhere: {"scenario": {...}, "targets": [...]} + def _find_scenario_field(dct, key): + if not isinstance(dct, dict): + return None + # Direct scenario container + sc = dct.get("scenario") or dct.get("sc") or dct + if isinstance(sc, dict) and key in sc: + return sc.get(key) + # Top-level key + if key in dct: + return dct.get(key) + # Nested search + for v in dct.values(): + if isinstance(v, dict) and key in v: + return v.get(key) + return None + + plat_az = _find_scenario_field(obj, "ant_nav_az") or _find_scenario_field( + obj, "platform_azimuth" + ) + if plat_az is not None: + try: + # Values may be in radians or degrees; if small absolute + # value (< 2*pi) assume radians and convert. + val = float(plat_az) + if abs(val) <= (2 * math.pi + 0.01): + az_deg = math.degrees(val) + else: + az_deg = val + self._hub.set_antenna_azimuth(az_deg, timestamp=time.monotonic()) + except Exception: + pass + + # Optionally capture elevation for future UI use + plat_el = _find_scenario_field(obj, "ant_nav_el") or _find_scenario_field( + obj, "platform_elevation" + ) + if plat_el is not None: + try: + _ = float(plat_el) + # For now we don't store elevation in the hub; leave as TODO. + except Exception: + pass + + except Exception: + self._logger.exception("Error handling JSON payload") + def get_and_clear_latest_payloads(self) -> Dict[str, Any]: with self._lock: new_payloads = self._latest_payloads diff --git a/target_simulator/gui/ppi_display.py b/target_simulator/gui/ppi_display.py index 1f1e9f5..a22b6b7 100644 --- a/target_simulator/gui/ppi_display.py +++ b/target_simulator/gui/ppi_display.py @@ -214,7 +214,7 @@ class PPIDisplay(ttk.Frame): fig.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.05) self.ax = fig.add_subplot(111, projection="polar", facecolor="#2E2E2E") self.ax.set_theta_zero_location("N") - self.ax.set_theta_direction(-1) # Clockwise + # self.ax.set_theta_direction(-1) # Clockwise <- RIGA RIMOSSA self.ax.set_rlabel_position(90) self.ax.set_ylim(0, self.range_var.get()) angles_deg = np.arange(0, 360, 30)