aggiunto il salvataggio dei dati del debug delle latenze nei messaggi di sync in csv
This commit is contained in:
parent
3052757f43
commit
5908e72ae3
6
logger_prefs.json
Normal file
6
logger_prefs.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"saved_levels": {
|
||||
"target_simulator.core.sfp_transport": "INFO"
|
||||
},
|
||||
"last_selected": "target_simulator.core.sfp_transport"
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
"scan_limit": 60,
|
||||
"max_range": 100,
|
||||
"geometry": "1492x992+230+258",
|
||||
"last_selected_scenario": "scenario2",
|
||||
"last_selected_scenario": "scenario_dritto",
|
||||
"connection": {
|
||||
"target": {
|
||||
"type": "sfp",
|
||||
|
||||
@ -127,10 +127,6 @@ def build_display_data(
|
||||
t_scenario = scenario.get_target(tid)
|
||||
if t_scenario is not None:
|
||||
sim_target.active = bool(getattr(t_scenario, "active", True))
|
||||
if logger and not sim_target.active:
|
||||
logger.debug(
|
||||
f"PPI Adapter: Target {tid} is INACTIVE (from scenario fallback)"
|
||||
)
|
||||
|
||||
simulated_targets_for_ppi.append(sim_target)
|
||||
|
||||
|
||||
@ -3,8 +3,12 @@ import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
import time
|
||||
import random
|
||||
import os
|
||||
import csv
|
||||
import threading
|
||||
from typing import Dict, Optional, List
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
|
||||
from target_simulator.core.sfp_communicator import SFPCommunicator
|
||||
from target_simulator.gui.payload_router import DebugPayloadRouter
|
||||
@ -51,6 +55,15 @@ class SyncToolWindow(tk.Toplevel):
|
||||
# Statistiche
|
||||
self.latency_values: List[float] = []
|
||||
|
||||
# === Sistema di salvataggio CSV (asincrono e non invasivo) ===
|
||||
self.csv_enabled = False
|
||||
self.csv_filepath: Optional[str] = None
|
||||
self.csv_buffer: deque = deque(maxlen=10000) # Buffer grande per evitare perdite
|
||||
self.csv_lock = threading.Lock()
|
||||
self.csv_writer_thread: Optional[threading.Thread] = None
|
||||
self.csv_stop_event = threading.Event()
|
||||
self.csv_session_start: Optional[float] = None
|
||||
|
||||
self._create_widgets()
|
||||
|
||||
self.protocol("WM_DELETE_WINDOW", self._on_close)
|
||||
@ -96,6 +109,25 @@ class SyncToolWindow(tk.Toplevel):
|
||||
side=tk.LEFT
|
||||
)
|
||||
|
||||
# Riga 3: Salvataggio CSV
|
||||
row3 = ttk.Frame(controls_frame)
|
||||
row3.pack(fill=tk.X, pady=2)
|
||||
|
||||
self.csv_check_var = tk.BooleanVar(value=False)
|
||||
self.csv_checkbox = ttk.Checkbutton(
|
||||
row3,
|
||||
text="Save to CSV",
|
||||
variable=self.csv_check_var,
|
||||
command=self._toggle_csv_save,
|
||||
)
|
||||
self.csv_checkbox.pack(side=tk.LEFT, padx=(0, 10))
|
||||
|
||||
self.csv_status_var = tk.StringVar(value="Not saving")
|
||||
self.csv_status_label = tk.Label(
|
||||
row3, textvariable=self.csv_status_var, foreground="gray"
|
||||
)
|
||||
self.csv_status_label.pack(side=tk.LEFT)
|
||||
|
||||
# === STATISTICHE ===
|
||||
stats_frame = ttk.LabelFrame(main_frame, text="Statistics", padding=5)
|
||||
stats_frame.pack(fill=tk.X, pady=(0, 10))
|
||||
@ -320,6 +352,14 @@ class SyncToolWindow(tk.Toplevel):
|
||||
if len(self.latency_values) > 200:
|
||||
self.latency_values.pop(0)
|
||||
|
||||
# Salva su CSV se abilitato (operazione velocissima, non blocca)
|
||||
if self.csv_enabled and self.csv_session_start is not None:
|
||||
elapsed_s = reception_time - self.csv_session_start
|
||||
server_timetag = result.get("server_timetag", 0)
|
||||
self._add_sample_to_csv_buffer(
|
||||
elapsed_s, cookie, rtt_ms, latency_ms, server_timetag
|
||||
)
|
||||
|
||||
# Aggiorna UI
|
||||
timestamp_str = time.strftime("%H:%M:%S")
|
||||
|
||||
@ -343,10 +383,157 @@ class SyncToolWindow(tk.Toplevel):
|
||||
# Continua il polling
|
||||
self.after(100, self._process_sync_queue)
|
||||
|
||||
def _toggle_csv_save(self):
|
||||
"""Attiva/disattiva il salvataggio CSV asincrono."""
|
||||
if self.csv_check_var.get():
|
||||
# Avvia salvataggio
|
||||
self._start_csv_save()
|
||||
else:
|
||||
# Ferma salvataggio
|
||||
self._stop_csv_save()
|
||||
|
||||
def _start_csv_save(self):
|
||||
"""Avvia il salvataggio CSV in background."""
|
||||
if self.csv_enabled:
|
||||
return # Già attivo
|
||||
|
||||
# Crea nome file con timestamp
|
||||
project_root = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), "..", "..")
|
||||
)
|
||||
temp_dir = os.path.join(project_root, "Temp")
|
||||
os.makedirs(temp_dir, exist_ok=True)
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
self.csv_filepath = os.path.join(temp_dir, f"sync_latency_{timestamp}.csv")
|
||||
self.csv_session_start = time.monotonic()
|
||||
|
||||
# Inizializza il file CSV con header
|
||||
try:
|
||||
with open(self.csv_filepath, "w", newline="") as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(
|
||||
[
|
||||
"elapsed_s",
|
||||
"timestamp",
|
||||
"cookie",
|
||||
"rtt_ms",
|
||||
"latency_ms",
|
||||
"server_timetag",
|
||||
]
|
||||
)
|
||||
self.csv_enabled = True
|
||||
self.csv_stop_event.clear()
|
||||
|
||||
# Avvia thread di scrittura
|
||||
self.csv_writer_thread = threading.Thread(
|
||||
target=self._csv_writer_loop, daemon=True, name="CSVWriterThread"
|
||||
)
|
||||
self.csv_writer_thread.start()
|
||||
|
||||
filename = os.path.basename(self.csv_filepath)
|
||||
self.csv_status_var.set(f"Saving to {filename}")
|
||||
self.csv_status_label.config(foreground="green")
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror(
|
||||
"CSV Error", f"Failed to create CSV file: {e}", parent=self
|
||||
)
|
||||
self.csv_check_var.set(False)
|
||||
self.csv_enabled = False
|
||||
|
||||
def _stop_csv_save(self):
|
||||
"""Ferma il salvataggio CSV."""
|
||||
if not self.csv_enabled:
|
||||
return
|
||||
|
||||
self.csv_enabled = False
|
||||
self.csv_stop_event.set()
|
||||
|
||||
# Attendi che il thread finisca di scrivere i dati rimanenti
|
||||
if self.csv_writer_thread and self.csv_writer_thread.is_alive():
|
||||
self.csv_writer_thread.join(timeout=2.0)
|
||||
|
||||
self.csv_status_var.set("Not saving")
|
||||
self.csv_status_label.config(foreground="gray")
|
||||
|
||||
if self.csv_filepath:
|
||||
filename = os.path.basename(self.csv_filepath)
|
||||
messagebox.showinfo(
|
||||
"CSV Saved",
|
||||
f"Latency data saved to:\n{filename}",
|
||||
parent=self,
|
||||
)
|
||||
|
||||
def _csv_writer_loop(self):
|
||||
"""Thread worker che scrive i dati bufferizzati su disco periodicamente."""
|
||||
while not self.csv_stop_event.is_set():
|
||||
try:
|
||||
# Attendi un po' prima di scrivere (batch writing)
|
||||
time.sleep(1.0)
|
||||
|
||||
# Estrai tutti i dati dal buffer
|
||||
rows_to_write = []
|
||||
with self.csv_lock:
|
||||
while len(self.csv_buffer) > 0:
|
||||
rows_to_write.append(self.csv_buffer.popleft())
|
||||
|
||||
# Scrivi su file (fuori dal lock per non bloccare)
|
||||
if rows_to_write and self.csv_filepath:
|
||||
try:
|
||||
with open(self.csv_filepath, "a", newline="") as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerows(rows_to_write)
|
||||
except Exception:
|
||||
pass # Ignora errori di scrittura per non bloccare
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Flush finale dei dati rimanenti
|
||||
rows_to_write = []
|
||||
with self.csv_lock:
|
||||
while len(self.csv_buffer) > 0:
|
||||
rows_to_write.append(self.csv_buffer.popleft())
|
||||
|
||||
if rows_to_write and self.csv_filepath:
|
||||
try:
|
||||
with open(self.csv_filepath, "a", newline="") as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerows(rows_to_write)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _add_sample_to_csv_buffer(
|
||||
self, elapsed_s: float, cookie: int, rtt_ms: float, latency_ms: float, server_timetag: int
|
||||
):
|
||||
"""Aggiunge un campione al buffer CSV (operazione velocissima, non blocca)."""
|
||||
if not self.csv_enabled:
|
||||
return
|
||||
|
||||
timestamp_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
row = [
|
||||
f"{elapsed_s:.3f}",
|
||||
timestamp_str,
|
||||
cookie,
|
||||
f"{rtt_ms:.3f}",
|
||||
f"{latency_ms:.3f}",
|
||||
server_timetag,
|
||||
]
|
||||
|
||||
with self.csv_lock:
|
||||
self.csv_buffer.append(row)
|
||||
|
||||
def _on_close(self):
|
||||
"""Gestisce la chiusura della finestra."""
|
||||
if self.periodic_active:
|
||||
self.periodic_active = False
|
||||
if self.periodic_after_id:
|
||||
self.after_cancel(self.periodic_after_id)
|
||||
|
||||
# Ferma il salvataggio CSV se attivo
|
||||
if self.csv_enabled:
|
||||
self.csv_check_var.set(False)
|
||||
self._stop_csv_save()
|
||||
|
||||
self.destroy()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user