refactor: normalize data directory naming, and consolidate serial connection handling
This commit is contained in:
@@ -309,9 +309,11 @@ class SessionController(QObject):
|
|||||||
|
|
||||||
# The new binary protocol sends payload of (sensorCount * 2) bytes
|
# The new binary protocol sends payload of (sensorCount * 2) bytes
|
||||||
# Each sensor is a big-endian 16-bit value (Sign-Magnitude).
|
# Each sensor is a big-endian 16-bit value (Sign-Magnitude).
|
||||||
|
expected_sensors = 80 if (family_code or "") == "X" else 244
|
||||||
|
|
||||||
def parse_binary_frame(payload: bytes, seq: int) -> Frame:
|
def parse_binary_frame(payload: bytes, seq: int) -> Frame:
|
||||||
values = []
|
values = []
|
||||||
num_sensors = min(80, len(payload) // 2)
|
num_sensors = min(expected_sensors, len(payload) // 2)
|
||||||
for i in range(num_sensors):
|
for i in range(num_sensors):
|
||||||
high_byte = payload[i * 2]
|
high_byte = payload[i * 2]
|
||||||
low_byte = payload[i * 2 + 1]
|
low_byte = payload[i * 2 + 1]
|
||||||
@@ -333,13 +335,9 @@ class SessionController(QObject):
|
|||||||
self._last = None
|
self._last = None
|
||||||
self._last_raw_frame = None
|
self._last_raw_frame = None
|
||||||
|
|
||||||
try:
|
transport = SerialPort.open_port(port, timeout=1)
|
||||||
transport = pyserial.Serial(port, SerialPort.BAUDRATE, timeout=1)
|
|
||||||
except Exception as exc:
|
|
||||||
log.warning("Baud rate %d failed on %s, falling back to 115200: %s", SerialPort.BAUDRATE, port, exc)
|
|
||||||
transport = pyserial.Serial(port, 115200, timeout=1)
|
|
||||||
# Send 'D2' command padded to 512 bytes to start the stream
|
# Send 'D2' command padded to 512 bytes to start the stream
|
||||||
cmd = b"D2" + (b"F" * 510)
|
cmd = b"D2" + SerialPort.COMMAND_PAD.encode()
|
||||||
transport.write(cmd)
|
transport.write(cmd)
|
||||||
|
|
||||||
def on_error(exc: Exception):
|
def on_error(exc: Exception):
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# ===== Backend Data Constants =====
|
||||||
|
|
||||||
|
DEFAULT_DATA_DIR_NAME = "isc_data"
|
||||||
@@ -10,6 +10,7 @@ from PySide6.QtWidgets import QFileDialog, QMessageBox
|
|||||||
|
|
||||||
from pygui.backend.data.csv_file_metadata import CSVFileMetadata
|
from pygui.backend.data.csv_file_metadata import CSVFileMetadata
|
||||||
from pygui.backend.wafer.zwafer_parser import ZWaferParser
|
from pygui.backend.wafer.zwafer_parser import ZWaferParser
|
||||||
|
from pygui.backend.data.constants import DEFAULT_DATA_DIR_NAME
|
||||||
|
|
||||||
|
|
||||||
# ===== File Browser Model =====
|
# ===== File Browser Model =====
|
||||||
@@ -232,7 +233,7 @@ class FileBrowser(QObject):
|
|||||||
QStandardPaths.DocumentsLocation
|
QStandardPaths.DocumentsLocation
|
||||||
)
|
)
|
||||||
base_dir = Path(documents_dir) if documents_dir else (Path.home() / "Documents")
|
base_dir = Path(documents_dir) if documents_dir else (Path.home() / "Documents")
|
||||||
return base_dir / "ISC_DATA"
|
return base_dir / DEFAULT_DATA_DIR_NAME
|
||||||
|
|
||||||
def _set_current_directory(self, directory: Path) -> None:
|
def _set_current_directory(self, directory: Path) -> None:
|
||||||
normalized = Path(directory)
|
normalized = Path(directory)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from typing import Any
|
|||||||
from PySide6.QtCore import QObject, Property, QDateTime, QStandardPaths, Signal, Slot
|
from PySide6.QtCore import QObject, Property, QDateTime, QStandardPaths, Signal, Slot
|
||||||
|
|
||||||
from pygui.backend.data.local_settings import LocalSettings
|
from pygui.backend.data.local_settings import LocalSettings
|
||||||
|
from pygui.backend.data.constants import DEFAULT_DATA_DIR_NAME
|
||||||
|
|
||||||
|
|
||||||
MASTER_FAMILIES = ("A", "B", "C", "D", "E", "F", "P", "X", "Z")
|
MASTER_FAMILIES = ("A", "B", "C", "D", "E", "F", "P", "X", "Z")
|
||||||
@@ -52,7 +53,7 @@ class LocalSettingsModel(QObject):
|
|||||||
QStandardPaths.DocumentsLocation
|
QStandardPaths.DocumentsLocation
|
||||||
)
|
)
|
||||||
base_dir = Path(documents_dir) if documents_dir else (Path.home() / "Documents")
|
base_dir = Path(documents_dir) if documents_dir else (Path.home() / "Documents")
|
||||||
return base_dir / "ISC_DATA"
|
return base_dir / DEFAULT_DATA_DIR_NAME
|
||||||
|
|
||||||
def _new_defaults(self) -> dict[str, Any]:
|
def _new_defaults(self) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -46,28 +46,16 @@ class SerialPort:
|
|||||||
self._port_name = port_name
|
self._port_name = port_name
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Context manager for scoped port access
|
# Port opening (shared between scoped and long-lived use)
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
@contextmanager
|
@staticmethod
|
||||||
def _open(self, timeout: float | None = None) -> Iterator[pyserial.Serial]:
|
def open_port(port_name: str, timeout: float | None = None) -> pyserial.Serial:
|
||||||
"""Open the serial port, yield it, then close on exit."""
|
"""Open a serial port with baud-rate fallback.
|
||||||
try:
|
|
||||||
port = pyserial.Serial(
|
Tries SerialPort.BAUDRATE first, falls back to 115200 on failure.
|
||||||
self._port_name,
|
The caller owns the lifecycle of the returned Serial object."""
|
||||||
self.BAUDRATE,
|
kwargs = dict(
|
||||||
parity=pyserial.PARITY_NONE,
|
|
||||||
bytesize=8,
|
|
||||||
stopbits=pyserial.STOPBITS_ONE,
|
|
||||||
xonxoff=False,
|
|
||||||
rtscts=False,
|
|
||||||
dsrdtr=False,
|
|
||||||
)
|
|
||||||
except Exception as exc:
|
|
||||||
log.warning("Baud rate %d failed on %s, falling back to 115200: %s", self.BAUDRATE, self._port_name, exc)
|
|
||||||
port = pyserial.Serial(
|
|
||||||
self._port_name,
|
|
||||||
115200,
|
|
||||||
parity=pyserial.PARITY_NONE,
|
parity=pyserial.PARITY_NONE,
|
||||||
bytesize=8,
|
bytesize=8,
|
||||||
stopbits=pyserial.STOPBITS_ONE,
|
stopbits=pyserial.STOPBITS_ONE,
|
||||||
@@ -76,7 +64,22 @@ class SerialPort:
|
|||||||
dsrdtr=False,
|
dsrdtr=False,
|
||||||
)
|
)
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
port.timeout = timeout
|
kwargs["timeout"] = timeout
|
||||||
|
|
||||||
|
try:
|
||||||
|
return pyserial.Serial(port_name, SerialPort.BAUDRATE, **kwargs)
|
||||||
|
except Exception as exc:
|
||||||
|
log.warning("Baud rate %d failed on %s, falling back to 115200: %s", SerialPort.BAUDRATE, port_name, exc)
|
||||||
|
return pyserial.Serial(port_name, 115200, **kwargs)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Context manager for scoped port access
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def _open(self, timeout: float | None = None) -> Iterator[pyserial.Serial]:
|
||||||
|
"""Open the serial port, yield it, then close on exit."""
|
||||||
|
port = self.open_port(self._port_name, timeout=timeout)
|
||||||
try:
|
try:
|
||||||
yield port
|
yield port
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
Reference in New Issue
Block a user