ca1a514f23
## Backend — Session & playback - Add SessionController (QML-facing live/review controller) with loadedFile property for active-file highlight binding - Add SessionModel, FramePlayer, and CsvRecorder for state machine, frame seek/step/speed, and CSV recording - Add SensorEditor for per-sensor value overrides (replace + offset)
47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
"""Append live frames"""
|
|
from __future__ import annotations
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Optional, TextIO
|
|
|
|
|
|
from pygui.backend.frame import Frame
|
|
from pygui.backend.zwafer_models import Sensor
|
|
|
|
class CsvRecorder:
|
|
def __init__(self) -> None:
|
|
self._file_handle: Optional[TextIO] = None
|
|
self._oath: Optional[str] = None
|
|
|
|
|
|
@property
|
|
def is_recording(self) -> bool:
|
|
return self._file_handle is not None
|
|
|
|
|
|
def start(self, path: str, sensors:list[Sensor], serial: str = "") -> None:
|
|
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
file_handle = open(path, "w", encoding="utf-8", newline ="")
|
|
file_handle.write(f"Wafer ID={serial}\n")
|
|
file_handle.write(f"Acquisition Date={datetime.now():%m/%d/%Y}\n")
|
|
file_handle.write("Label," + ",".join(s.label for s in sensors) + "\n")
|
|
file_handle.write("X (mm)," + ",".join(str(s.x) for s in sensors) + "\n")
|
|
file_handle.write("Y (mm)," + ",".join(str(s.y) for s in sensors) + "\n")
|
|
file_handle.write("data\n")
|
|
file_handle.flush()
|
|
self._file_handle, self._path = file_handle, path
|
|
|
|
def write(self, frame: Frame) -> None:
|
|
if self._file_handle is None:
|
|
return
|
|
row = [f"{frame.time:.3f}"] + [f"{v:.3f}" for v in frame.values]
|
|
self._file_handle.write(",".join(row) + "\n")
|
|
self._file_handle.flush()
|
|
|
|
def stop(self) -> Optional[str]:
|
|
if self._file_handle is None:
|
|
return None
|
|
self._file_handle.close()
|
|
path, self._file_handle, self._path = self._path, None, None
|
|
return path
|