SXXXXXXX_PyMsc/pymsc/core/monitor.py
2025-12-10 11:47:46 +01:00

78 lines
2.5 KiB
Python

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)