diff --git a/target_simulator/core/models.py b/target_simulator/core/models.py index a9ab439..276179c 100644 --- a/target_simulator/core/models.py +++ b/target_simulator/core/models.py @@ -11,7 +11,9 @@ from typing import Dict, List, Optional, Tuple # --- Constants --- MIN_TARGET_ID = 0 -MAX_TARGET_ID = 15 +# Increase allowed max target id to 32 (inclusive). Historically this was 15 +# but RIS/firmware can address up to 32 targets in current deployments. +MAX_TARGET_ID = 32 KNOTS_TO_FPS = 1.68781 FPS_TO_KNOTS = 1 / KNOTS_TO_FPS NM_TO_FT = 6076.12 diff --git a/target_simulator/gui/payload_router.py b/target_simulator/gui/payload_router.py index d576259..a84b508 100644 --- a/target_simulator/gui/payload_router.py +++ b/target_simulator/gui/payload_router.py @@ -16,7 +16,7 @@ import json import ctypes import time from queue import Queue, Full -from typing import Dict, Optional, Any, List, Callable +from typing import Dict, Optional, Any, List, Callable, Tuple from target_simulator.core.sfp_structures import SFPHeader, SfpRisStatusPayload from target_simulator.analysis.simulation_state_hub import SimulationStateHub @@ -100,8 +100,14 @@ class DebugPayloadRouter: with self._lock: self._latest_payloads[flow_id] = payload - def _parse_ris_payload_to_targets(self, payload: bytearray) -> List[Target]: - targets = [] + def _parse_ris_payload_to_targets(self, payload: bytearray) -> Tuple[List[Target], List[int]]: + """ + Parse RIS payload and return a tuple: + - list of Target objects for entries with flags != 0 (active targets) + - list of integer target IDs present with flags == 0 (inactive) + """ + targets: List[Target] = [] + inactive_ids: List[int] = [] try: parsed_payload = SfpRisStatusPayload.from_buffer_copy(payload) for i, ris_target in enumerate(parsed_payload.tgt.tgt): @@ -140,14 +146,19 @@ class DebugPayloadRouter: except (ValueError, TypeError): target.current_heading_deg = 0.0 targets.append(target) + else: + try: + inactive_ids.append(int(i)) + except Exception: + pass except Exception: self._logger.exception( f"{self._log_prefix} Failed to parse RIS payload into Target objects." ) - return targets + return targets, inactive_ids def _handle_ris_status(self, payload: bytearray): - real_targets = self._parse_ris_payload_to_targets(payload) + real_targets, inactive_ids = self._parse_ris_payload_to_targets(payload) if self._hub: try: @@ -164,6 +175,15 @@ class DebugPayloadRouter: # Non-fatal: continue even if packet recording fails pass + # If payload included inactive targets (flags==0), clear their stored + # real data so they disappear from the PPI immediately. + try: + for tid in (inactive_ids or []): + if hasattr(self._hub, "clear_real_target_data"): + self._hub.clear_real_target_data(tid) + except Exception: + self._logger.debug("Failed to clear inactive target data in hub", exc_info=True) + # Add real states for active targets for target in real_targets: state_tuple = ( diff --git a/target_simulator/gui/ppi_display.py b/target_simulator/gui/ppi_display.py index 7aa016f..26cf9d3 100644 --- a/target_simulator/gui/ppi_display.py +++ b/target_simulator/gui/ppi_display.py @@ -58,7 +58,8 @@ class PPIDisplay(ttk.Frame): self.show_sim_points_var = tk.BooleanVar(value=True) self.show_real_points_var = tk.BooleanVar(value=True) self.show_sim_trail_var = tk.BooleanVar(value=False) - self.show_real_trail_var = tk.BooleanVar(value=True) + # Default: do not show real trails unless the user enables them. + self.show_real_trail_var = tk.BooleanVar(value=False) self.canvas = None self._create_controls() self._create_plot()