sistemata visualizzazione target e scenario, aggiunta visualizzazione raw e semplificata

This commit is contained in:
VALLONGOL 2025-10-17 15:13:52 +02:00
parent 42f019e0a1
commit ea7a2533c1
3 changed files with 198 additions and 66 deletions

View File

@ -208,7 +208,7 @@ class RisScenario(ctypes.Structure):
("longitude", ctypes.c_float),
("ant_nav_az", ctypes.c_float),
("ant_nav_el", ctypes.c_float),
("spare2", ctypes.c_uint32 * 7),
("spare2", ctypes.c_uint32 * 8),
]

View File

@ -66,6 +66,38 @@ class SfpDebugWindow(tk.Toplevel):
self.ip_var = tk.StringVar(value="127.0.0.1")
self.port_var = tk.StringVar(value="60002")
# Master mode names (from C++ enum ordering) — used to display readable mode
# NOTE: keep in sync with the C++ enum if it changes
self._master_mode_names = [
"idle_master_mode",
"int_bit_master_mode",
"gm_master_mode",
"dbs_master_mode",
"rws_master_mode",
"vs_master_mode",
"acm_master_mode",
"tws_master_mode",
"sea_low_master_mode",
"sea_high_master_mode",
"gmti_master_mode",
"bcn_master_mode",
"sam_master_mode",
"ta_master_mode",
"wa_master_mode",
"stt_master_mode",
"dtt_master_mode",
"sstt_master_mode",
"acq_master_mode",
"ftt_master_mode",
"agr_master_mode",
"sar_master_mode",
"invalid_master_mode_",
"xtst_dummy_mode",
"xtst_hw_validation_mode",
"boot_master_mode",
"master_mode_id_cardinality_",
]
# --- Connection Frame (IP / Port / Connect controls) ---
conn_frame = ttk.Frame(self)
conn_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=(5, 2))
@ -611,6 +643,27 @@ class SfpDebugWindow(tk.Toplevel):
import json
struct = json.loads(payload.decode("utf-8")) if isinstance(payload, (bytes, bytearray)) else payload
# Debug: log keys and a short sample of the payload to help
# diagnose any label/value mismatches coming from the server.
try:
if isinstance(struct, dict):
scenario_preview = struct.get("scenario")
#self.logger.debug("RIS payload keys: %s", list(struct.keys()))
#if isinstance(scenario_preview, dict):
#self.logger.debug("RIS scenario keys: %s", list(scenario_preview.keys()))
targets_preview = struct.get("targets")
if isinstance(targets_preview, list):
sample_keys = [list(t.keys()) for t in targets_preview[:3] if isinstance(t, dict)]
#self.logger.debug("RIS targets sample keys (first 3): %s", sample_keys)
# Also put a concise message in the Raw Log widget for convenience
try:
msg = f"RIS JSON: scenario_keys={len(scenario_preview) if isinstance(scenario_preview, dict) else 0}, targets={len(targets_preview) if isinstance(targets_preview, list) else 0}"
#self._log_to_widget(msg, "DEBUG")
except Exception:
pass
except Exception:
# Never raise from debug logging
pass
# scenario table (field, value)
for iid in self.scenario_tree.get_children():
self.scenario_tree.delete(iid)
@ -671,6 +724,15 @@ class SfpDebugWindow(tk.Toplevel):
except Exception:
return str(v)
def try_float(v):
"""Attempt to convert value to float; return None on failure."""
try:
return float(v)
except Exception:
return None
# collect rows first so we can log the exact label->value mapping
scenario_rows = []
for label, key, unit in order:
if key in scenario:
val = scenario.get(key)
@ -691,33 +753,38 @@ class SfpDebugWindow(tk.Toplevel):
else:
# simplified view: show converted value and unit adjacent to number
if key in ("platform_azimuth", "true_heading"):
if isinstance(val, (int, float)):
conv = to_deg(val)
fv = try_float(val)
if fv is not None:
conv = to_deg(fv)
display_val = fmt_simplified_number(conv, "°", dec_simp)
else:
display_val = str(val)
elif key in ("ant_nav_az", "ant_nav_el"):
if isinstance(val, (int, float)):
conv = to_deg(val)
fv = try_float(val)
if fv is not None:
conv = to_deg(fv)
display_val = fmt_simplified_number(conv, "°", dec_simp)
else:
display_val = str(val)
elif key in ("vx", "vy", "vz"):
if isinstance(val, (int, float)):
conv = m_s_to_ft_s(val)
fv = try_float(val)
if fv is not None:
conv = m_s_to_ft_s(fv)
display_val = fmt_simplified_number(conv, "ft/s", dec_simp)
else:
display_val = str(val)
elif key == "baro_altitude":
if isinstance(val, (int, float)):
conv = m_to_ft(val)
fv = try_float(val)
if fv is not None:
conv = m_to_ft(fv)
display_val = fmt_simplified_number(conv, "ft", dec_simp)
else:
display_val = str(val)
elif key in ("latitude", "longitude"):
if isinstance(val, (int, float)):
fv = try_float(val)
if fv is not None:
# show decimal degrees with higher precision per request
display_val = f"{float(val):.{8}f} °"
display_val = f"{fv:.{8}f} °"
else:
display_val = str(val)
elif key == "flags":
@ -726,12 +793,41 @@ class SfpDebugWindow(tk.Toplevel):
except Exception:
display_val = str(val)
elif key == "mode":
display_val = str(int(val)) if isinstance(val, (int, float)) else str(val)
# Map numeric mode to human-friendly short name
try:
midx = int(val)
if 0 <= midx < len(self._master_mode_names):
name = self._master_mode_names[midx]
# strip trailing parts like '_master_mode' or '_mode' or trailing underscores
short = name
for suffix in ("_master_mode", "_mode", "_master_mode_", "_"):
if short.endswith(suffix):
short = short[: -len(suffix)]
# also remove any remaining 'master' parts
short = short.replace("master", "").strip("_")
display_val = short
else:
display_val = str(midx)
except Exception:
display_val = str(val)
else:
display_val = str(val)
# Show label without unit; unit is appended to the value in simplified view
self.scenario_tree.insert("", tk.END, values=(f"{label}", display_val))
# collect the pair for logging and insertion
scenario_rows.append((label, display_val))
# Log the label->value pairs for diagnosis (concise)
try:
preview = ", ".join(f"{l}={v}" for l, v in scenario_rows)
#self.logger.debug("Scenario label->value: %s", preview)
# also write a shorter message to Raw Log for visibility
#self._log_to_widget(f"Scenario preview: {preview}", "DEBUG")
except Exception:
pass
# Now insert collected rows into the Treeview
for l, v in scenario_rows:
self.scenario_tree.insert("", tk.END, values=(f"{l}", v))
# targets
for iid in self.ris_tree.get_children():
@ -751,28 +847,37 @@ class SfpDebugWindow(tk.Toplevel):
view_mode = self.scenario_view_mode.get() if hasattr(self, "scenario_view_mode") else "simplified"
dec_simp = int(self.simplified_decimals.get() if hasattr(self, "simplified_decimals") else 4)
for t in targets:
try:
# normalize index (accept common aliases)
idx = t.get("index")
if idx is None:
idx = t.get("idx")
if idx is None:
idx = t.get("#")
# normalize flags and format consistently
raw_flags = t.get("flags", t.get("flag", 0))
try:
flags_val = int(raw_flags)
flags_display = f"{flags_val} (0x{flags_val:X})"
except Exception:
flags_display = str(raw_flags)
if view_mode == "raw":
# format raw with reasonable precision
try:
heading_raw = float(t.get("heading"))
heading_val = f"{heading_raw:.6f}"
except Exception:
heading_val = str(t.get("heading"))
try:
x_raw = float(t.get("x"))
y_raw = float(t.get("y"))
z_raw = float(t.get("z"))
x_val = f"{x_raw:.6f}"
y_val = f"{y_raw:.6f}"
z_val = f"{z_raw:.6f}"
except Exception:
x_val = t.get("x")
y_val = t.get("y")
z_val = t.get("z")
# format raw with reasonable precision using try_float
hfv = try_float(t.get("heading"))
heading_val = f"{hfv:.6f}" if hfv is not None else str(t.get("heading"))
xfv = try_float(t.get("x"))
yfv = try_float(t.get("y"))
zfv = try_float(t.get("z"))
x_val = f"{xfv:.6f}" if xfv is not None else t.get("x")
y_val = f"{yfv:.6f}" if yfv is not None else t.get("y")
z_val = f"{zfv:.6f}" if zfv is not None else t.get("z")
vals = (
t.get("index"),
t.get("flags"),
idx,
flags_display,
heading_val,
x_val,
y_val,
@ -780,34 +885,44 @@ class SfpDebugWindow(tk.Toplevel):
)
else:
# simplified: converted values with units next to number
try:
heading = float(t.get("heading"))
heading_deg = heading * (180.0 / 3.141592653589793)
hfv = try_float(t.get("heading"))
if hfv is not None:
heading_deg = hfv * (180.0 / 3.141592653589793)
heading_val = f"{heading_deg:.{dec_simp}f} °"
except Exception:
else:
heading_val = str(t.get("heading"))
try:
x = float(t.get("x"))
y = float(t.get("y"))
z_m = float(t.get("z"))
x_val = f"{x:.{dec_simp}f} m"
y_val = f"{y:.{dec_simp}f} m"
z_val = f"{(z_m * 3.280839895):.{dec_simp}f} ft"
except Exception:
x_val = str(t.get("x"))
y_val = str(t.get("y"))
xfv = try_float(t.get("x"))
yfv = try_float(t.get("y"))
zfv = try_float(t.get("z"))
x_val = f"{xfv:.{dec_simp}f} m" if xfv is not None else str(t.get("x"))
y_val = f"{yfv:.{dec_simp}f} m" if yfv is not None else str(t.get("y"))
if zfv is not None:
z_val = f"{(zfv * 3.280839895):.{dec_simp}f} ft"
else:
z_val = str(t.get("z"))
vals = (
t.get("index"),
t.get("flags"),
idx,
flags_display,
heading_val,
x_val,
y_val,
z_val,
)
# ensure we always insert a 6-tuple (Treeview expects 6 columns)
if not isinstance(vals, (list, tuple)) or len(vals) != 6:
# fallback: make a safe 6-element tuple
vals = (idx, flags_display, "", "", "", "")
self.ris_tree.insert("", tk.END, values=vals)
except Exception as _e:
# on malformed target entries, insert a visible placeholder
try:
self.ris_tree.insert("", tk.END, values=(None, None, str(t.get("heading")), str(t.get("x")), str(t.get("y")), str(t.get("z"))))
except Exception:
pass
except Exception:
# ignore malformed JSON for now
pass

17
todo.md Normal file
View File

@ -0,0 +1,17 @@
code da fare
leggere le informazioni dell'antenna del messaggio di stato
leggere la flag per capire se il target è attivo
scomporre il campo flag in bit per avere le informazioni dello stato del target (attivo, tracable)
fare simulazione con moviumento dell'aereo letto da protocollo
visualizzare informaizoni dinamiche dell'areo durante la simulazione
sull'edito, se seleziono una manovra, vederla colorata di un altro colore sulla preview per capire cosa sto toccando.
aggiungere visualizzazione nell'editor su ris_status in questo modo:
1) dati raw, dati come vengono spediti, senza conversioni
2) dati convertiti secondo intefaccia gui del mission computer
3) dati dei target in range/elevation
la visualizzazione ppi in simulazione se tiene conto della rotazione del ptazimuth dovrebbe ruotare in modo che il cono di scansione dell'antenna si muove
di conseguenza. Immagino che la mappa ppi sia sempre diretta a nord, quindi quando io con l'aereo vado a nord tutto torna
se invece cambio direzione dell'aereo la mappa ruota e quindi ruotano anche le label attorno in modo che siano sempre riferite al muso dell'aereo.
Quindi dovremmo inserire una nuova legenda oltre a quella attuale che indichi che il nord è sempra. per ricordare all'utente che la ppi è verso l'alto.