97 lines
3.4 KiB
Python
97 lines
3.4 KiB
Python
import threading, queue, time, csv, os, statistics
|
|
|
|
class DeviceWorker:
|
|
def __init__(self, sm, dev, outdir,
|
|
filter_window_size=10, interval=0.1):
|
|
self.sm = sm
|
|
self.dev = dev
|
|
self.serial = getattr(dev, "serial", "UNKNOWN")
|
|
self.filter_window_size = filter_window_size
|
|
self.interval = interval
|
|
self.outdir = outdir
|
|
|
|
self.cmdq = queue.Queue()
|
|
self.stop_evt = threading.Event()
|
|
self.running = False
|
|
|
|
self.reader_t = threading.Thread(target=self.reader_loop, daemon=True)
|
|
self.writer_t = threading.Thread(target=self.writer_loop, daemon=True)
|
|
self.writer_q = queue.Queue(maxsize=50) # 1 Wert/Sek → reicht dicke
|
|
|
|
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 set_mode(self, ch, mode):
|
|
key = {0:"A",1:"B"}.get(ch, str(ch).upper())
|
|
self.dev.channels[key].mode = mode
|
|
|
|
def reader_loop(self):
|
|
last_log = 0.0
|
|
while not self.stop_evt.is_set():
|
|
# Start/Stop Kommandos
|
|
try:
|
|
cmd, _ = self.cmdq.get_nowait()
|
|
if cmd == "start" and not self.running:
|
|
self.sm.start()
|
|
self.running = True
|
|
elif cmd == "stop" and self.running:
|
|
self.running = False
|
|
self.sm.stop()
|
|
except queue.Empty:
|
|
pass
|
|
|
|
if not self.running:
|
|
time.sleep(0.05)
|
|
continue
|
|
|
|
try:
|
|
# exakt wie dein Single-Loop:
|
|
samples = self.dev.read(self.filter_window_size, -1) # ggf. read(n)
|
|
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 logging
|
|
try:
|
|
self.writer_q.put((now, vA, vB), timeout=0.2)
|
|
last_log = now
|
|
except queue.Full:
|
|
pass # selten, bei 1Hz praktisch nie
|
|
except Exception as e:
|
|
print(f"[{self.serial}] Read-Fehler: {e}")
|
|
time.sleep(0.02)
|
|
|
|
# Loop-Rate wie bei dir:
|
|
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() # 1 Zeile/Sek → ok
|
|
except Exception as e:
|
|
print(f"[{self.serial}] Writer-Fehler: {e}")
|
|
finally:
|
|
print(f"[{self.serial}] Datei geschlossen: {fn}")
|
|
|
|
def shutdown(self):
|
|
self.stop()
|
|
self.stop_evt.set() |