aggiunta nella finestra di debug sfp l'interpretazione dei dati header
This commit is contained in:
parent
3bee128952
commit
ead6c13ba2
BIN
TN-IMGSER GRIFO Video over IP Rev.A1.pdf
Normal file
BIN
TN-IMGSER GRIFO Video over IP Rev.A1.pdf
Normal file
Binary file not shown.
@ -43,7 +43,7 @@ class SfpTransport:
|
|||||||
"""Manages SFP communication and payload reassembly."""
|
"""Manages SFP communication and payload reassembly."""
|
||||||
|
|
||||||
# --- INIZIO MODIFICHE ---
|
# --- INIZIO MODIFICHE ---
|
||||||
def __init__(self, host: str, port: int, payload_handlers: Dict[int, PayloadHandler], ack_config: Optional[Dict[int, int]] = None):
|
def __init__(self, host: str, port: int, payload_handlers: Dict[int, PayloadHandler], ack_config: Optional[Dict[int, int]] = None, raw_packet_callback: Optional[Callable[[bytes, tuple], None]] = None):
|
||||||
"""
|
"""
|
||||||
Initializes the SFP Transport layer.
|
Initializes the SFP Transport layer.
|
||||||
|
|
||||||
@ -64,6 +64,8 @@ class SfpTransport:
|
|||||||
self._payload_handlers = payload_handlers
|
self._payload_handlers = payload_handlers
|
||||||
# --- INIZIO MODIFICHE ---
|
# --- INIZIO MODIFICHE ---
|
||||||
self._ack_config = ack_config if ack_config is not None else {}
|
self._ack_config = ack_config if ack_config is not None else {}
|
||||||
|
# Optional callback invoked with (raw_packet_bytes, addr) for every packet received
|
||||||
|
self._raw_packet_callback = raw_packet_callback
|
||||||
# --- FINE MODIFICHE ---
|
# --- FINE MODIFICHE ---
|
||||||
self._socket: Optional[socket.socket] = None
|
self._socket: Optional[socket.socket] = None
|
||||||
self._receiver_thread: Optional[threading.Thread] = None
|
self._receiver_thread: Optional[threading.Thread] = None
|
||||||
@ -127,6 +129,12 @@ class SfpTransport:
|
|||||||
data, addr = self._socket.recvfrom(65535)
|
data, addr = self._socket.recvfrom(65535)
|
||||||
if not data:
|
if not data:
|
||||||
continue
|
continue
|
||||||
|
# Deliver raw packet to optional callback for inspection (non-blocking best-effort)
|
||||||
|
try:
|
||||||
|
if self._raw_packet_callback:
|
||||||
|
self._raw_packet_callback(data, addr)
|
||||||
|
except Exception:
|
||||||
|
logger.exception(f"{log_prefix} raw_packet_callback raised an exception")
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
continue
|
continue
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|||||||
@ -39,6 +39,8 @@ class DebugPayloadRouter:
|
|||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
# Buffer to store the last received payload for each flow type
|
# Buffer to store the last received payload for each flow type
|
||||||
self._latest_payloads: Dict[str, bytearray] = {}
|
self._latest_payloads: Dict[str, bytearray] = {}
|
||||||
|
# Buffer to store the last raw packet received (bytes, addr)
|
||||||
|
self._last_raw_packet: Optional[tuple] = None
|
||||||
logging.info(f"{self._log_prefix} Initialized.")
|
logging.info(f"{self._log_prefix} Initialized.")
|
||||||
|
|
||||||
def get_handlers(self) -> Dict[int, PayloadHandler]:
|
def get_handlers(self) -> Dict[int, PayloadHandler]:
|
||||||
@ -69,6 +71,17 @@ class DebugPayloadRouter:
|
|||||||
self._latest_payloads = {}
|
self._latest_payloads = {}
|
||||||
return new_payloads
|
return new_payloads
|
||||||
|
|
||||||
|
def update_raw_packet(self, raw_bytes: bytes, addr: tuple):
|
||||||
|
"""Store the last raw packet received (overwritten by subsequent packets)."""
|
||||||
|
with self._lock:
|
||||||
|
self._last_raw_packet = (raw_bytes, addr)
|
||||||
|
|
||||||
|
def get_and_clear_raw_packet(self) -> Optional[tuple]:
|
||||||
|
with self._lock:
|
||||||
|
pkt = self._last_raw_packet
|
||||||
|
self._last_raw_packet = None
|
||||||
|
return pkt
|
||||||
|
|
||||||
# --- Main Debug Window Class ---
|
# --- Main Debug Window Class ---
|
||||||
|
|
||||||
class SfpDebugWindow(tk.Toplevel):
|
class SfpDebugWindow(tk.Toplevel):
|
||||||
@ -131,6 +144,16 @@ class SfpDebugWindow(tk.Toplevel):
|
|||||||
self.notebook.add(self.mfd_tab["frame"], text="MFD Image")
|
self.notebook.add(self.mfd_tab["frame"], text="MFD Image")
|
||||||
self.sar_tab = self._create_image_tab("SAR Image")
|
self.sar_tab = self._create_image_tab("SAR Image")
|
||||||
self.notebook.add(self.sar_tab["frame"], text="SAR Image")
|
self.notebook.add(self.sar_tab["frame"], text="SAR Image")
|
||||||
|
# Raw SFP packet view
|
||||||
|
self.raw_tab = scrolledtext.ScrolledText(self.notebook, state=tk.DISABLED, wrap=tk.NONE, font=("Consolas", 9))
|
||||||
|
self.notebook.add(self.raw_tab, text="SFP Raw")
|
||||||
|
# Configure visual tags for flags (set/unset)
|
||||||
|
try:
|
||||||
|
self.raw_tab.tag_config("flag_set", background="#d4ffd4", foreground="#006400")
|
||||||
|
self.raw_tab.tag_config("flag_unset", background="#f0f0f0", foreground="#808080")
|
||||||
|
self.raw_tab.tag_config("hdr_field", foreground="#000080")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
self.bin_tab = scrolledtext.ScrolledText(self.notebook, state=tk.DISABLED, wrap=tk.NONE, font=("Consolas", 10))
|
self.bin_tab = scrolledtext.ScrolledText(self.notebook, state=tk.DISABLED, wrap=tk.NONE, font=("Consolas", 10))
|
||||||
self.notebook.add(self.bin_tab, text="Binary (Hex)")
|
self.notebook.add(self.bin_tab, text="Binary (Hex)")
|
||||||
self.json_tab = scrolledtext.ScrolledText(self.notebook, state=tk.DISABLED, wrap=tk.WORD, font=("Consolas", 10))
|
self.json_tab = scrolledtext.ScrolledText(self.notebook, state=tk.DISABLED, wrap=tk.WORD, font=("Consolas", 10))
|
||||||
@ -220,6 +243,13 @@ class SfpDebugWindow(tk.Toplevel):
|
|||||||
else:
|
else:
|
||||||
self._log_to_widget("Connection failed. Check IP/Port and logs.", "ERROR")
|
self._log_to_widget("Connection failed. Check IP/Port and logs.", "ERROR")
|
||||||
self.sfp_transport = None
|
self.sfp_transport = None
|
||||||
|
# Register raw packet callback regardless of start result (safe no-op if None)
|
||||||
|
if self.sfp_transport:
|
||||||
|
# Provide the router.update_raw_packet method as callback
|
||||||
|
try:
|
||||||
|
self.sfp_transport._raw_packet_callback = self.payload_router.update_raw_packet
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("Failed to register raw_packet_callback on SfpTransport")
|
||||||
|
|
||||||
def _on_disconnect(self):
|
def _on_disconnect(self):
|
||||||
if self.sfp_transport:
|
if self.sfp_transport:
|
||||||
@ -260,6 +290,121 @@ class SfpDebugWindow(tk.Toplevel):
|
|||||||
# Reschedule the next check
|
# Reschedule the next check
|
||||||
self.after(self.GUI_POLL_INTERVAL_MS, self._process_latest_payloads)
|
self.after(self.GUI_POLL_INTERVAL_MS, self._process_latest_payloads)
|
||||||
|
|
||||||
|
# Also check and display last raw packet
|
||||||
|
raw_pkt = self.payload_router.get_and_clear_raw_packet()
|
||||||
|
if raw_pkt:
|
||||||
|
raw_bytes, addr = raw_pkt
|
||||||
|
self._display_raw_packet(raw_bytes, addr)
|
||||||
|
|
||||||
|
def _display_raw_packet(self, raw_bytes: bytes, addr: tuple):
|
||||||
|
"""Show the raw SFP packet bytes and the parsed header (if possible)."""
|
||||||
|
try:
|
||||||
|
header_size = SFPHeader.size()
|
||||||
|
if len(raw_bytes) < header_size:
|
||||||
|
raise ValueError("Packet smaller than SFP header")
|
||||||
|
|
||||||
|
header = SFPHeader.from_buffer_copy(raw_bytes)
|
||||||
|
body = raw_bytes[header_size:]
|
||||||
|
|
||||||
|
# Build a compact two-column header table to save horizontal space
|
||||||
|
field_list = [
|
||||||
|
"SFP_MARKER", "SFP_DIRECTION", "SFP_PROT_VER", "SFP_PT_SPARE",
|
||||||
|
"SFP_TAG", "SFP_SRC", "SFP_FLOW", "SFP_TID",
|
||||||
|
"SFP_FLAGS", "SFP_WIN", "SFP_ERR", "SFP_ERR_INFO",
|
||||||
|
"SFP_TOTFRGAS", "SFP_FRAG", "SFP_RECTYPE", "SFP_RECSPARE",
|
||||||
|
"SFP_PLDAP", "SFP_PLEXT", "SFP_RECCOUNTER", "SFP_PLSIZE",
|
||||||
|
"SFP_TOTSIZE", "SFP_PLOFFSET"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Collect (label, value) pairs, handle FLAGS specially
|
||||||
|
pairs = []
|
||||||
|
flag_val = None
|
||||||
|
for f in field_list:
|
||||||
|
try:
|
||||||
|
val = getattr(header, f)
|
||||||
|
except Exception:
|
||||||
|
val = '<N/A>'
|
||||||
|
if f == 'SFP_FLAGS':
|
||||||
|
flag_val = val
|
||||||
|
# still include placeholder for alignment; actual flags printed later
|
||||||
|
pairs.append((f, f"{val} (0x{val:X})" if isinstance(val, int) else str(val)))
|
||||||
|
continue
|
||||||
|
if isinstance(val, int):
|
||||||
|
pairs.append((f, f"{val} (0x{val:X})"))
|
||||||
|
else:
|
||||||
|
pairs.append((f, str(val)))
|
||||||
|
|
||||||
|
# Render two columns: pair up items two-per-line
|
||||||
|
self.raw_tab.config(state=tk.NORMAL)
|
||||||
|
self.raw_tab.delete("1.0", tk.END)
|
||||||
|
self.raw_tab.insert(tk.END, f"From {addr}\n\nSFP Header:\n\n", "hdr_field")
|
||||||
|
col_width = 36 # width for each column block
|
||||||
|
for i in range(0, len(pairs), 2):
|
||||||
|
left = pairs[i]
|
||||||
|
right = pairs[i+1] if (i+1) < len(pairs) else None
|
||||||
|
left_text = f"{left[0]:12s}: {left[1]}"
|
||||||
|
if right:
|
||||||
|
right_text = f"{right[0]:12s}: {right[1]}"
|
||||||
|
# Pad left_text to column width then append right_text
|
||||||
|
line = f"{left_text:<{col_width}} {right_text}"
|
||||||
|
else:
|
||||||
|
line = left_text
|
||||||
|
self.raw_tab.insert(tk.END, line + "\n", "hdr_field")
|
||||||
|
|
||||||
|
# FLAG decoding: example bits mapping (adjust if protocol defines differently)
|
||||||
|
# Let's assume bit0 = ACK, bit1 = MORE, bit2 = RESERVED, etc.
|
||||||
|
flag_defs = [
|
||||||
|
(0, "ACK"),
|
||||||
|
(1, "MORE"),
|
||||||
|
(2, "RESV2"),
|
||||||
|
(3, "RESV3"),
|
||||||
|
(4, "RESV4"),
|
||||||
|
(5, "RESV5"),
|
||||||
|
(6, "RESV6"),
|
||||||
|
(7, "RESV7"),
|
||||||
|
]
|
||||||
|
|
||||||
|
flag_line_start = self.raw_tab.index(tk.END)
|
||||||
|
self.raw_tab.insert(tk.END, f"SFP_FLAGS : {flag_val} (0x{flag_val:X}) ")
|
||||||
|
# Append colored flag labels
|
||||||
|
for bit, name in flag_defs:
|
||||||
|
is_set = False
|
||||||
|
try:
|
||||||
|
is_set = bool((flag_val >> bit) & 1)
|
||||||
|
except Exception:
|
||||||
|
is_set = False
|
||||||
|
tag = "flag_set" if is_set else "flag_unset"
|
||||||
|
self.raw_tab.insert(tk.END, f" [{name}]", tag)
|
||||||
|
|
||||||
|
# Fixed legend text for flags (always visible)
|
||||||
|
self.raw_tab.insert(tk.END, "\n\nFlags legend:\n", "hdr_field")
|
||||||
|
legend_map = {
|
||||||
|
"ACK": "Acknowledgement requested/received",
|
||||||
|
"MORE": "More fragments follow (not final fragment)",
|
||||||
|
"RESV2": "Reserved",
|
||||||
|
"RESV3": "Reserved",
|
||||||
|
"RESV4": "Reserved",
|
||||||
|
"RESV5": "Reserved",
|
||||||
|
"RESV6": "Reserved",
|
||||||
|
"RESV7": "Reserved",
|
||||||
|
}
|
||||||
|
for _, name in flag_defs:
|
||||||
|
desc = legend_map.get(name, "")
|
||||||
|
self.raw_tab.insert(tk.END, f" {name:6s}: {desc}\n")
|
||||||
|
|
||||||
|
self.raw_tab.insert(tk.END, "\nBODY (hex):\n")
|
||||||
|
self.raw_tab.insert(tk.END, self._format_hex_dump(body))
|
||||||
|
self.raw_tab.config(state=tk.DISABLED)
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
text = f"Failed to format raw packet: {e}\n\nRaw dump:\n"
|
||||||
|
text += self._format_hex_dump(raw_bytes)
|
||||||
|
|
||||||
|
self.raw_tab.config(state=tk.NORMAL)
|
||||||
|
self.raw_tab.delete("1.0", tk.END)
|
||||||
|
self.raw_tab.insert("1.0", text)
|
||||||
|
self.raw_tab.config(state=tk.DISABLED)
|
||||||
|
|
||||||
def _display_image_data(self, payload: bytearray, tab_widgets: Dict[str, Any], photo_attr: str):
|
def _display_image_data(self, payload: bytearray, tab_widgets: Dict[str, Any], photo_attr: str):
|
||||||
"""Parses an image payload and displays it. Now handles simplified structure."""
|
"""Parses an image payload and displays it. Now handles simplified structure."""
|
||||||
try:
|
try:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user