from dataclasses import dataclass, field from typing import List, Callable, Optional import threading import time @dataclass class MonDecoded: cw_raw: int sw: int error_code: int sa: int tr: int rt: int wc: int data: bytes timetag: float @dataclass class MonitorInfo: buffer: List[MonDecoded] = field(default_factory=list) total_message: int = 0 processed_message: int = 0 size: int = 0 class MonitorBuffer: """Thread-safe monitor buffer providing driver-like API. Methods: - append(entry: MonDecoded): add one decoded message - set_isr(callback): register ISR callback - enable_isr(enable=True): enable/disable ISR invocation - get_raw_buffer(): snapshot and clear internal buffer """ def __init__(self, buf_size: int = 512, isr_threshold: Optional[int] = None): self._lock = threading.Lock() self._buffer: List[MonDecoded] = [] self._buf_size = buf_size self._isr_threshold = isr_threshold if isr_threshold is not None else max(1, buf_size // 2) self._isr: Optional[Callable[[MonitorInfo], None]] = None self._isr_enabled = False def set_isr(self, callback: Callable[[MonitorInfo], None]): self._isr = callback def enable_isr(self, enable: bool = True): self._isr_enabled = bool(enable) def append(self, entry: MonDecoded): with self._lock: self._buffer.append(entry) total = len(self._buffer) # Optionally cap buffer to buf_size (drop oldest) if len(self._buffer) > self._buf_size: # drop oldest self._buffer = self._buffer[-self._buf_size:] # Check threshold outside lock for quick return if total >= self._isr_threshold and self._isr_enabled and self._isr: # build snapshot with self._lock: snapshot = MonitorInfo(buffer=list(self._buffer), total_message=len(self._buffer), processed_message=0, size=len(self._buffer)) # call ISR in daemon thread try: threading.Thread(target=self._isr, args=(snapshot,), daemon=True).start() except Exception: pass def get_raw_buffer(self) -> MonitorInfo: with self._lock: snapshot = MonitorInfo(buffer=list(self._buffer), total_message=len(self._buffer), processed_message=0, size=len(self._buffer)) self._buffer = [] return snapshot def size(self) -> int: with self._lock: return len(self._buffer)