Adalm1000_Logger/device_worker.py
Vincent Hanewinkel dc5269e595 test
2025-08-14 23:01:45 +02:00

101 lines
3.6 KiB
Python

import threading, queue, time, csv, os, statistics
class DeviceWorker:
"""
Arbeitet genau wie dein Single-Gerät-Logger:
- filter_window_size Rohsamples pro Loop
- ~10 Hz Loop (interval=0.1)
- 1 Hz Logging (eine CSV-Zeile pro Sekunde)
Wichtig: kontrolliert NICHT die Session!
"""
def __init__(self, dev, outdir="./logs", filter_window_size=10, interval=0.1):
self.dev = dev
self.serial = getattr(dev, "serial", "UNKNOWN")
self.outdir = outdir
self.filter_window_size = filter_window_size
self.interval = interval
self._running = False
self._stop_evt = threading.Event()
self._cmdq = queue.Queue()
self._writer_q = queue.Queue(maxsize=50)
self._reader_t = threading.Thread(target=self._reader_loop, daemon=True)
self._writer_t = threading.Thread(target=self._writer_loop, daemon=True)
# ---- API ----
def start(self):
if not self._reader_t.is_alive(): self._reader_t.start()
if not self._writer_t.is_alive(): self._writer_t.start()
self._cmdq.put(("start", None))
def stop(self):
self._cmdq.put(("stop", None))
def shutdown(self):
self.stop()
self._stop_evt.set()
def set_mode(self, ch, mode):
key = {0: "A", 1: "B"}.get(ch, str(ch).upper())
self.dev.channels[key].mode = mode
# ---- Threads ----
def _reader_loop(self):
last_log = 0.0
while not self._stop_evt.is_set():
# Kommandos
try:
cmd, _ = self._cmdq.get_nowait()
if cmd == "start": self._running = True
elif cmd == "stop": self._running = False
except queue.Empty:
pass
if not self._running:
time.sleep(0.05)
continue
try:
# wie im Single-Logger: n Samples holen, mitteln
# WICHTIG: kleiner Timeout, damit der Thread nie "fest" hängt
samples = self.dev.read(self.filter_window_size, 50) # timeout ~50 ms
if not samples:
time.sleep(self.interval)
continue
vA = statistics.mean(row[0] for row in samples)
vB = statistics.mean(row[2] for row in samples)
now = time.time()
if now - last_log >= 1.0: # 1 Hz ins File
try:
self._writer_q.put((now, vA, vB), timeout=0.2)
last_log = now
except queue.Full:
pass
except Exception as e:
print(f"[{self.serial}] Read-Fehler: {e}")
time.sleep(0.02)
# Loop-Takt exakt wie beim Single-Logger
time.sleep(max(0.05, self.interval))
def _writer_loop(self):
os.makedirs(self.outdir, exist_ok=True)
fn = os.path.join(self.outdir, f"{time.strftime('%Y%m%d_%H%M%S')}_{self.serial}.csv")
try:
with open(fn, "w", newline="") as f:
w = csv.writer(f)
w.writerow(["timestamp", "A", "B"])
while not (self._stop_evt.is_set() and self._writer_q.empty()):
try:
ts, vA, vB = self._writer_q.get(timeout=0.5)
except queue.Empty:
continue
w.writerow([ts, vA, vB])
f.flush() # bei 1 Hz ok
except Exception as e:
print(f"[{self.serial}] Writer-Fehler: {e}")
finally:
print(f"[{self.serial}] Datei geschlossen: {fn}")