fix
This commit is contained in:
parent
dc5269e595
commit
5602c20cb3
@ -1,4 +1,7 @@
|
|||||||
import threading, queue, time, csv, os, statistics
|
import os, sys, time, csv, statistics, threading, queue
|
||||||
|
|
||||||
|
scriptDir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
DEFAULT_OUTDIR = os.path.join(scriptDir, "logs")
|
||||||
|
|
||||||
class DeviceWorker:
|
class DeviceWorker:
|
||||||
"""
|
"""
|
||||||
@ -8,10 +11,11 @@ class DeviceWorker:
|
|||||||
- 1 Hz Logging (eine CSV-Zeile pro Sekunde)
|
- 1 Hz Logging (eine CSV-Zeile pro Sekunde)
|
||||||
Wichtig: kontrolliert NICHT die Session!
|
Wichtig: kontrolliert NICHT die Session!
|
||||||
"""
|
"""
|
||||||
def __init__(self, dev, outdir="./logs", filter_window_size=10, interval=0.1):
|
def __init__(self, dev, outdir=DEFAULT_OUTDIR, filter_window_size=10, interval=0.1):
|
||||||
self.dev = dev
|
self.dev = dev
|
||||||
self.serial = getattr(dev, "serial", "UNKNOWN")
|
self.serial = getattr(dev, "serial", "UNKNOWN")
|
||||||
self.outdir = outdir
|
self.outdir = outdir
|
||||||
|
self._log_path = None
|
||||||
self.filter_window_size = filter_window_size
|
self.filter_window_size = filter_window_size
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
|
|
||||||
@ -25,30 +29,27 @@ class DeviceWorker:
|
|||||||
|
|
||||||
# ---- API ----
|
# ---- API ----
|
||||||
def start(self):
|
def start(self):
|
||||||
|
print(f"[{self.serial}] Worker.start()")
|
||||||
if not self._reader_t.is_alive(): self._reader_t.start()
|
if not self._reader_t.is_alive(): self._reader_t.start()
|
||||||
if not self._writer_t.is_alive(): self._writer_t.start()
|
if not self._writer_t.is_alive(): self._writer_t.start()
|
||||||
self._cmdq.put(("start", None))
|
self._cmdq.put(("start", None))
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
print(f"[{self.serial}] Worker.stop()")
|
||||||
self._cmdq.put(("stop", None))
|
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):
|
def _reader_loop(self):
|
||||||
|
print(f"[{self.serial}] Reader gestartet (interval={self.interval}, n={self.filter_window_size})")
|
||||||
last_log = 0.0
|
last_log = 0.0
|
||||||
while not self._stop_evt.is_set():
|
while not self._stop_evt.is_set():
|
||||||
# Kommandos
|
|
||||||
try:
|
try:
|
||||||
cmd, _ = self._cmdq.get_nowait()
|
cmd, _ = self._cmdq.get_nowait()
|
||||||
if cmd == "start": self._running = True
|
if cmd == "start":
|
||||||
elif cmd == "stop": self._running = False
|
self._running = True
|
||||||
|
print(f"[{self.serial}] RUNNING")
|
||||||
|
elif cmd == "stop":
|
||||||
|
self._running = False
|
||||||
|
print(f"[{self.serial}] STOPPED")
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -57,9 +58,12 @@ class DeviceWorker:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# wie im Single-Logger: n Samples holen, mitteln
|
# WÄHLE HIER DIE SIGNATUR, DIE DEIN SINGLE-LOGGER NUTZT:
|
||||||
# WICHTIG: kleiner Timeout, damit der Thread nie "fest" hängt
|
# Beispiel A (deine Datei ließ 'read(n, 500, True)' vermuten):
|
||||||
samples = self.dev.read(self.filter_window_size, 50) # timeout ~50 ms
|
samples = self.dev.read(self.filter_window_size, 500, True)
|
||||||
|
# Beispiel B (andere pysmu-Versionen):
|
||||||
|
# samples = self.dev.read(self.filter_window_size, -1)
|
||||||
|
|
||||||
if not samples:
|
if not samples:
|
||||||
time.sleep(self.interval)
|
time.sleep(self.interval)
|
||||||
continue
|
continue
|
||||||
@ -68,34 +72,38 @@ class DeviceWorker:
|
|||||||
vB = statistics.mean(row[2] for row in samples)
|
vB = statistics.mean(row[2] for row in samples)
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now - last_log >= 1.0: # 1 Hz ins File
|
if now - last_log >= 1.0:
|
||||||
try:
|
self._writer_q.put((now, vA, vB))
|
||||||
self._writer_q.put((now, vA, vB), timeout=0.2)
|
|
||||||
last_log = now
|
last_log = now
|
||||||
except queue.Full:
|
|
||||||
pass
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[{self.serial}] Read-Fehler: {e}")
|
print(f"[{self.serial}] Read-Fehler: {e}")
|
||||||
time.sleep(0.02)
|
time.sleep(0.05)
|
||||||
|
|
||||||
# Loop-Takt exakt wie beim Single-Logger
|
|
||||||
time.sleep(max(0.05, self.interval))
|
time.sleep(max(0.05, self.interval))
|
||||||
|
|
||||||
def _writer_loop(self):
|
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:
|
try:
|
||||||
with open(fn, "w", newline="") as f:
|
os.makedirs(self.outdir, exist_ok=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[{self.serial}] os.makedirs-Fehler für '{self.outdir}': {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._log_path = os.path.join(self.outdir, f"{time.strftime('%Y%m%d_%H%M%S')}_{self.serial}.csv")
|
||||||
|
print(f"[{self.serial}] Writer startet → {self._log_path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self._log_path, "w", newline="") as f:
|
||||||
w = csv.writer(f)
|
w = csv.writer(f)
|
||||||
w.writerow(["timestamp", "A", "B"])
|
w.writerow(["timestamp", "A", "B"]) # Datei wird JETZT angelegt
|
||||||
while not (self._stop_evt.is_set() and self._writer_q.empty()):
|
while not (self._stop_evt.is_set() and self._writer_q.empty()):
|
||||||
try:
|
try:
|
||||||
ts, vA, vB = self._writer_q.get(timeout=0.5)
|
ts, vA, vB = self._writer_q.get(timeout=0.5)
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
continue
|
continue
|
||||||
w.writerow([ts, vA, vB])
|
w.writerow([ts, vA, vB])
|
||||||
f.flush() # bei 1 Hz ok
|
f.flush()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[{self.serial}] Writer-Fehler: {e}")
|
print(f"[{self.serial}] Writer-Fehler ({self._log_path}): {e}")
|
||||||
finally:
|
finally:
|
||||||
print(f"[{self.serial}] Datei geschlossen: {fn}")
|
print(f"[{self.serial}] Writer beendet: {self._log_path}")
|
||||||
@ -1,7 +1,10 @@
|
|||||||
import sys
|
import sys, os
|
||||||
from PyQt5.QtWidgets import QApplication, QWidget, QListWidget, QListWidgetItem, QVBoxLayout, QPushButton, QLabel, QHBoxLayout
|
from PyQt5.QtWidgets import QApplication, QWidget, QListWidget, QListWidgetItem, QVBoxLayout, QPushButton, QLabel, QHBoxLayout
|
||||||
from multi_logger import MultiLogger
|
from multi_logger import MultiLogger
|
||||||
|
|
||||||
|
scriptDir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
DEFAULT_OUTDIR = os.path.join(scriptDir, "logs")
|
||||||
|
|
||||||
class ListItemWidget(QWidget):
|
class ListItemWidget(QWidget):
|
||||||
def __init__(self, label, worker):
|
def __init__(self, label, worker):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -48,11 +51,9 @@ class MainWindow(QWidget):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# 1) Logger + Geräte
|
# 1) Logger + Geräte
|
||||||
ml = MultiLogger(outdir="./logs", filter_window_size=10, interval=0.1)
|
ml = MultiLogger(outdir=DEFAULT_OUTDIR, filter_window_size=10, interval=0.1)
|
||||||
print("Gefundene Geräte:", [w.serial for w in ml.workers])
|
print("Gefundene Geräte:", [w.serial for w in ml.workers])
|
||||||
ml.set_default_modes()
|
ml.set_default_modes()
|
||||||
|
|
||||||
# 2) Session EINMAL im Hauptthread starten (wie beim Single-Logger!)
|
|
||||||
ml.start_session()
|
ml.start_session()
|
||||||
|
|
||||||
# 3) GUI
|
# 3) GUI
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user