Phase 2: extract headless core modules (sras_format, scan_geometry, config)

- core/sras_format.py: THE v6 implementation — create_scan_file (writer,
  byte-identical to the old one, enforced against the Phase-0 goldens),
  SrasFile parser with frontier/truncation walk, and zero-copy mmap
  load_angle/load_row views for multi-GB files
- core/scan_geometry.py: ScanPlan/AngleGeometry dataclasses, build_plan
  (rotated-bbox trig from MainWindow._build_scan_params), travel-limit
  validate_plan (limits now a StageLimits dataclass, not literals buried
  in the worker), format_eta + EtaEstimator (bounded deque)
- core/config.py: ScanDefaults dataclass replaces the module-import-time
  dict globals. FIXES: editing any main-window port used to rewrite
  aui_defaults.json without helios_port, silently reverting the Helios
  port every time (test_helios_port_survives_partial_update covers it).
  Also drops the inert laser_freq_hz plumbing — scans always used the
  LASER_FREQ_HZ constant.
- hardware/serial_util.py: shared 8N1 open + scored port enumeration
  (promoted from t3r_control_panel); helios_laser and the panel use it
- sc3_aui_app.py and sras_scan_manager.py migrated onto core (three
  format implementations down to one); ScanWorker now takes a ScanPlan
- tests: byte-identical writer vs golden, frontier over every truncation
  variant, mmap==eager, geometry vs golden fixtures + invariants, config
  round-trip. 28 passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Thomas Ales
2026-07-28 10:20:44 -05:00
parent 67aabde4b6
commit dff9f69d78
15 changed files with 1117 additions and 809 deletions
+6 -13
View File
@@ -3,12 +3,13 @@ Helios Laser System Driver
Basic implementation for controlling the Helios pulsed laser.
"""
import serial
import time
import logging
from typing import Optional, List
from enum import Enum
from hardware.serial_util import open_8n1
logger = logging.getLogger(__name__)
@@ -42,10 +43,9 @@ class HeliosLaser:
@staticmethod
def list_available_ports() -> List[str]:
"""List available serial ports"""
import serial.tools.list_ports
ports = serial.tools.list_ports.comports()
return [port.device for port in ports]
"""List available serial ports, likeliest devices first."""
from hardware.serial_util import list_port_devices
return list_port_devices()
def connect(self, port: str = None) -> bool:
"""
@@ -65,14 +65,7 @@ class HeliosLaser:
return False
try:
self.serial = serial.Serial(
port=self.port,
baudrate=9600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=self.timeout
)
self.serial = open_8n1(self.port, baudrate=9600, timeout=self.timeout)
time.sleep(0.1) # Allow time for connection to stabilize
self.is_connected = True
logger.info(f"Connected to Helios laser on {self.port}")