diff --git a/mipi_test_interactive.py b/mipi_test_interactive.py index 6030fc2..7902535 100644 --- a/mipi_test_interactive.py +++ b/mipi_test_interactive.py @@ -494,6 +494,12 @@ def _set_timebase(scale, points): def _arm_and_wait(timeout=20): + """Single acquisition via :DIGitize + *OPC?. + :DIGitize holds the SCPI bus until it triggers — if it times out we close + and reopen the VXI-11 link to abort the pending RPC so subsequent writes + to a fresh connection succeed. :SINGle + status polling is NOT used: on + this scope it generates QUERY UNTERMINATED errors that break later acquires.""" + global scope prev_timeout = scope.timeout try: scope.timeout = timeout + 5 @@ -501,9 +507,27 @@ def _arm_and_wait(timeout=20): return scope.ask("*OPC?").strip() == "1" except Exception as e: print(f" ACQUIRE ERROR: {e}") + try: + scope.close() + except Exception: + pass + time.sleep(2.0) + for attempt in range(3): + try: + scope = vxi11.Instrument(SCOPE_IP) + scope.timeout = 30 + scope.write(":STOP") + time.sleep(0.2) + break + except Exception as re: + print(f" SCOPE RECONNECT ERROR (attempt {attempt+1}): {re}") + time.sleep(1.0) return False finally: - scope.timeout = prev_timeout + try: + scope.timeout = prev_timeout + except Exception: + pass def _save_pass(tag, iteration, ts): @@ -596,7 +620,7 @@ def _arm_scope_for_clk_startup() -> None: print(" CLK STARTUP: scope armed on CLK+ falling edge.") -def _collect_clk_startup(ts: str, iteration: int, timeout: float = 10.0) -> list[str]: +def _collect_clk_startup(ts: str, iteration: int, timeout: float = 3.0) -> list[str]: """ Poll for CLK startup trigger, save, transfer, and analyse the capture. Returns LP summary strings (empty list if trigger timed out). @@ -617,6 +641,11 @@ def _collect_clk_startup(ts: str, iteration: int, timeout: float = 10.0) -> list if not triggered: print(" CLK STARTUP: trigger timeout — CLK may already be in continuous HS.") + try: + scope.write(":STOP") # abort the pending :SINGle before reconfiguring + time.sleep(0.2) + except Exception: + pass _restore_hs_config() return [] @@ -700,6 +729,10 @@ def dual_capture(iteration: int) -> str: else: print(" RIGOL CH2: IRQ read failed.") _restore_hs_config() + try: + requests.put(URL, json={"state": "on"}, timeout=1) + except Exception: + pass # ── Pass 2: HS signal quality ────────────────────────────────────────── print(" PASS 2: SIGNAL QUALITY...") @@ -708,6 +741,10 @@ def dual_capture(iteration: int) -> str: _save_pass("sig", iteration, ts) else: print(" SKIPPING SIG SAVE.") + try: + requests.put(URL, json={"state": "on"}, timeout=1) + except Exception: + pass # ── Pass 3: frame/protocol structure ────────────────────────────────── print(" PASS 3: FRAME STRUCTURE...") @@ -721,8 +758,11 @@ def dual_capture(iteration: int) -> str: _fetch_registers(ts, iteration) # ── Restore default timebase ────────────────────────────────────────── - _set_timebase(5e-9, 500_000) - scope.write(":RUN") + try: + _set_timebase(5e-9, 500_000) + scope.write(":RUN") + except Exception as e: + print(f" WARNING: scope restore failed: {e}") return ts @@ -1281,6 +1321,14 @@ def run_interactive_test() -> None: # ── Pixel clock configuration ────────────────────────────────────────── config = prompt_for_config() + # Flush any stale SCPI state from previous runs (QUERY UNTERMINATED errors etc.) + try: + scope.write("*CLS") + scope.write(":STOP") + time.sleep(0.3) + except Exception as e: + print(f" WARNING: scope pre-flush failed: {e}") + print("\nINTERACTIVE FLICKER TEST STARTED.") print("Each iteration: display ON → 3-pass capture → LP analysis → Claude check.") print("The display stays ON while Claude and the operator assess the frame.")