fix st
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
@ -46,6 +47,7 @@ UI_BACKLOG_TAIL_THRESHOLD_MULTIPLIER = 2
|
||||
UI_BACKLOG_LATEST_ONLY_THRESHOLD_MULTIPLIER = 4
|
||||
UI_HEAVY_REFRESH_BACKLOG_MULTIPLIER = 2
|
||||
UI_HEAVY_REFRESH_MAX_STRIDE = 4
|
||||
UI_DATA_WAIT_NOTE_AFTER_S = 3.0
|
||||
DEFAULT_MAIN_WINDOW_WIDTH = 1200
|
||||
DEFAULT_MAIN_WINDOW_HEIGHT = 680
|
||||
MIN_MAIN_WINDOW_WIDTH = 640
|
||||
@ -93,6 +95,60 @@ def sanitize_image_for_display(data: Optional[np.ndarray]) -> Optional[np.ndarra
|
||||
return arr
|
||||
|
||||
|
||||
def set_image_rect_if_ready(image_item, x: float, y: float, width: float, height: float) -> bool:
|
||||
"""Set ImageItem geometry only when the image payload has valid dimensions."""
|
||||
try:
|
||||
x_val = float(x)
|
||||
y_val = float(y)
|
||||
width_val = float(width)
|
||||
height_val = float(height)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
if not (
|
||||
np.isfinite(x_val)
|
||||
and np.isfinite(y_val)
|
||||
and np.isfinite(width_val)
|
||||
and np.isfinite(height_val)
|
||||
and width_val > 0.0
|
||||
and height_val > 0.0
|
||||
):
|
||||
return False
|
||||
|
||||
has_payload = False
|
||||
try:
|
||||
payload = getattr(image_item, "image", None)
|
||||
if payload is not None:
|
||||
arr = np.asarray(payload)
|
||||
has_payload = arr.ndim >= 2 and arr.shape[0] > 0 and arr.shape[1] > 0
|
||||
except Exception:
|
||||
has_payload = False
|
||||
|
||||
if not has_payload:
|
||||
try:
|
||||
img_w = image_item.width()
|
||||
img_h = image_item.height()
|
||||
has_payload = (
|
||||
img_w is not None
|
||||
and img_h is not None
|
||||
and np.isfinite(float(img_w))
|
||||
and np.isfinite(float(img_h))
|
||||
and float(img_w) > 0.0
|
||||
and float(img_h) > 0.0
|
||||
)
|
||||
except Exception:
|
||||
has_payload = False
|
||||
|
||||
if not has_payload:
|
||||
return False
|
||||
|
||||
try:
|
||||
image_item.setRect(x_val, y_val, width_val, height_val)
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def resolve_axis_bounds(
|
||||
values: Optional[np.ndarray],
|
||||
*,
|
||||
@ -478,6 +534,12 @@ def run_pyqtgraph(args) -> None:
|
||||
or getattr(args, "parser_16_bit_x2", False)
|
||||
or getattr(args, "parser_test", False)
|
||||
)
|
||||
if not sys.platform.startswith("win"):
|
||||
display_name = os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")
|
||||
if not display_name:
|
||||
sys.stderr.write(
|
||||
"[warn] DISPLAY/WAYLAND_DISPLAY not set. GUI windows may not open over plain SSH without desktop/X forwarding.\n"
|
||||
)
|
||||
try:
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtCore, QtWidgets # type: ignore
|
||||
@ -743,6 +805,7 @@ def run_pyqtgraph(args) -> None:
|
||||
fft_imag_enabled = True
|
||||
fft_mode = "symmetric"
|
||||
status_note = ""
|
||||
waiting_data_note = ""
|
||||
status_note_expires_at: Optional[float] = None
|
||||
status_dirty = True
|
||||
range_change_in_progress = False
|
||||
@ -750,6 +813,7 @@ def run_pyqtgraph(args) -> None:
|
||||
last_queue_backlog = 0
|
||||
last_backlog_skipped = 0
|
||||
last_heavy_refresh_stride = 1
|
||||
last_packet_processed_at: Optional[float] = None
|
||||
fixed_ylim: Optional[Tuple[float, float]] = None
|
||||
if args.ylim:
|
||||
try:
|
||||
@ -772,13 +836,13 @@ def run_pyqtgraph(args) -> None:
|
||||
disp_raw = sanitize_image_for_display(runtime.ring.get_display_raw_decimated(RAW_WATERFALL_MAX_POINTS))
|
||||
if disp_raw is not None:
|
||||
img.setImage(disp_raw, autoLevels=False)
|
||||
img.setRect(0, f_min, max_sweeps, max(1e-9, f_max - f_min))
|
||||
set_image_rect_if_ready(img, 0.0, f_min, float(max_sweeps), max(1e-9, f_max - f_min))
|
||||
p_img.setRange(xRange=(0, max_sweeps - 1), yRange=(f_min, f_max), padding=0)
|
||||
p_line.setXRange(f_min, f_max, padding=0)
|
||||
disp_fft = sanitize_image_for_display(runtime.ring.get_display_fft_linear())
|
||||
if disp_fft is not None:
|
||||
img_fft.setImage(disp_fft, autoLevels=False)
|
||||
img_fft.setRect(0, 0.0, max_sweeps, 1.0)
|
||||
set_image_rect_if_ready(img_fft, 0.0, 0.0, float(max_sweeps), 1.0)
|
||||
p_spec.setRange(xRange=(0, max_sweeps - 1), yRange=(0.0, 1.0), padding=0)
|
||||
p_fft.setXRange(0.0, 1.0, padding=0)
|
||||
|
||||
@ -790,14 +854,14 @@ def run_pyqtgraph(args) -> None:
|
||||
)
|
||||
if freq_bounds is not None:
|
||||
f_min, f_max = freq_bounds
|
||||
img.setRect(0, f_min, max_sweeps, f_max - f_min)
|
||||
set_image_rect_if_ready(img, 0.0, f_min, float(max_sweeps), f_max - f_min)
|
||||
p_img.setRange(xRange=(0, max_sweeps - 1), yRange=(f_min, f_max), padding=0)
|
||||
p_line.setXRange(f_min, f_max, padding=0)
|
||||
|
||||
distance_bounds = resolve_axis_bounds(runtime.ring.distance_axis)
|
||||
if distance_bounds is not None:
|
||||
d_min, d_max = distance_bounds
|
||||
img_fft.setRect(0, d_min, max_sweeps, d_max - d_min)
|
||||
set_image_rect_if_ready(img_fft, 0.0, d_min, float(max_sweeps), d_max - d_min)
|
||||
p_spec.setRange(xRange=(0, max_sweeps - 1), yRange=(d_min, d_max), padding=0)
|
||||
|
||||
def resolve_curve_xs(size: int) -> np.ndarray:
|
||||
@ -839,6 +903,20 @@ def run_pyqtgraph(args) -> None:
|
||||
status_note_expires_at = None
|
||||
status_dirty = True
|
||||
|
||||
def refresh_waiting_data_note() -> None:
|
||||
nonlocal waiting_data_note, status_dirty
|
||||
now = time.time()
|
||||
idle_s = (now - ui_started_at) if last_packet_processed_at is None else (now - last_packet_processed_at)
|
||||
new_note = ""
|
||||
if idle_s >= UI_DATA_WAIT_NOTE_AFTER_S:
|
||||
if processed_frames <= 0:
|
||||
new_note = f"ожидание данных: нет свипов {idle_s:.1f} c"
|
||||
else:
|
||||
new_note = f"ожидание данных: нет новых свипов {idle_s:.1f} c"
|
||||
if new_note != waiting_data_note:
|
||||
waiting_data_note = new_note
|
||||
status_dirty = True
|
||||
|
||||
def log_debug_event(name: str, message: str, *, every: int = DEBUG_FRAME_LOG_EVERY) -> None:
|
||||
count = int(debug_event_counts.get(name, 0)) + 1
|
||||
debug_event_counts[name] = count
|
||||
@ -1442,6 +1520,7 @@ def run_pyqtgraph(args) -> None:
|
||||
|
||||
def drain_queue() -> int:
|
||||
nonlocal processed_frames, ui_frames_skipped, last_queue_backlog, last_backlog_skipped, last_heavy_refresh_stride
|
||||
nonlocal last_packet_processed_at
|
||||
pending_packets: List[SweepPacket] = []
|
||||
while True:
|
||||
try:
|
||||
@ -1518,6 +1597,7 @@ def run_pyqtgraph(args) -> None:
|
||||
runtime.current_info = info
|
||||
refresh_current_window(push_to_ring=True)
|
||||
processed_frames += 1
|
||||
last_packet_processed_at = time.time()
|
||||
if processed_frames % DEBUG_FRAME_LOG_EVERY == 0:
|
||||
try:
|
||||
queue_size = queue.qsize()
|
||||
@ -1559,6 +1639,7 @@ def run_pyqtgraph(args) -> None:
|
||||
return
|
||||
update_ticks += 1
|
||||
clear_expired_status_note()
|
||||
refresh_waiting_data_note()
|
||||
|
||||
changed = drain_queue() > 0
|
||||
redraw_needed = changed or runtime.plot_dirty
|
||||
@ -1898,6 +1979,8 @@ def run_pyqtgraph(args) -> None:
|
||||
status_payload["peak_a"] = runtime.current_peak_amplitude
|
||||
base_status = format_status_kv(status_payload) if status_payload else ""
|
||||
status_parts = []
|
||||
if waiting_data_note:
|
||||
status_parts.append(waiting_data_note)
|
||||
if status_note:
|
||||
status_parts.append(status_note)
|
||||
if last_backlog_skipped > 0:
|
||||
|
||||
Reference in New Issue
Block a user