diff --git a/CoreLibrary/Driver.py b/CoreLibrary/Driver.py new file mode 100644 index 0000000..3ba5193 --- /dev/null +++ b/CoreLibrary/Driver.py @@ -0,0 +1,34 @@ +from abc import ABC, abstractmethod + + +class Driver(ABC): + """docstring for Model.""" + + + + @abstractmethod + def exit(self): + """ + disconnecting device + """ + pass + + @abstractmethod + def set_config(self, config: dict) -> None: + """ + Setzen von Parameter die sich nie ändern Addresse usw. + """ + pass + + @abstractmethod + def get_config(self) -> dict: + pass + + + @abstractmethod + def get_status(self) -> dict: + """ + Returns a dict from status information. These values are not needed for analysis + """ + pass + diff --git a/CoreLibrary/ExampleCombined.py b/CoreLibrary/ExampleCombined.py new file mode 100644 index 0000000..8cb6b91 --- /dev/null +++ b/CoreLibrary/ExampleCombined.py @@ -0,0 +1,81 @@ +import logging +from datetime import datetime +from queue import Queue +from random import random +from threading import Thread, Event +from time import sleep + +from Driver import Driver +from Sensor import Sensor + +LOGGER = logging.getLogger() + + +class ExampleDriverWorker(Thread): + """Communicates with the measuring hardware. Here we only produce random data.""" + + def __init__(self, message_queue): + super().__init__(name="Measure") + self.message_queue = message_queue + self.produceData = Event() + self.exit_request = Event() + self.prev = 0 + + def run(self): + """Worker method of a python Thread. Called when the Thread is started.""" + while not self.exit_request.is_set(): + if self.produceData.is_set(): + temp = self.prev + random() / 100.0 + self.prev = temp + ts = datetime.utcnow() + self.message_queue.put((ts, temp)) + else: + pass + sleep(1) + +class ExampleDriver(Driver, Sensor): + """docstring for Model.""" + + def __init__(self): + super(Driver, self).__init__() + self.measureQueue = Queue() + self.measureThread = ExampleDriverWorker(self.measureQueue) + self.measureThread.start() + self.measureThread.produceData.set() + self.speed = 10 + self.running = False + + def exit(self): + self.measureThread.exit_request.set() + + def set_config(self, config: dict): + self.speed = config["speed"] + + def get_config(self): + return {"speed": self.speed} + pass + + def get_status(self): + return {"running": self.running} + + def start_measuring(self): + self.measureThread.produceData.set() + logging.info("I started meas") + + def stop_measuring(self): + self.measureThread.produceData.clear() + logging.info("I stopped meas") + + def exit(self): + self.stop_measuring() + self.measureThread.exit_request.set() + + @property + def get_data(self): + time = [] + val = [] + while not self.measureQueue.empty(): + t, data = self.measureQueue.get() + time.append(t) + val.append(data) + return time, val diff --git a/ExampleDriver.py b/CoreLibrary/ExampleDriver.py similarity index 91% rename from ExampleDriver.py rename to CoreLibrary/ExampleDriver.py index 9db1c68..3d8119c 100644 --- a/ExampleDriver.py +++ b/CoreLibrary/ExampleDriver.py @@ -2,7 +2,7 @@ from abc import abstractmethod from threading import Thread, Event from time import sleep from queue import Queue -from driver import Driver +from CoreLibrary.Driver import Driver import logging LOGGER = logging.getLogger() @@ -13,6 +13,7 @@ class ExampleDriverWorker(Thread): def __init__(self, message_queue): super().__init__(name="Driver") + self.produceData = Event() self.exit_request = Event() def run(self): @@ -36,12 +37,11 @@ class ExampleDriver(Driver): def exit(self): self.measureThread.exit_request.set() - def set_config(self, config): + def set_config(self, config: dict): self.speed = config["speed"] def get_status(self): return {"running": self.running} - @abstractmethod def get_config(self): pass diff --git a/ExampleSensor.py b/CoreLibrary/ExampleSensor.py similarity index 97% rename from ExampleSensor.py rename to CoreLibrary/ExampleSensor.py index 3b76dd5..03d364a 100644 --- a/ExampleSensor.py +++ b/CoreLibrary/ExampleSensor.py @@ -3,7 +3,7 @@ from threading import Thread, Event from time import sleep from queue import Queue from random import random -from sensor import Sensor +from CoreLibrary.Sensor import Sensor import logging LOGGER = logging.getLogger() diff --git a/measurement.py b/CoreLibrary/Measurement.py similarity index 87% rename from measurement.py rename to CoreLibrary/Measurement.py index b53309e..487732e 100644 --- a/measurement.py +++ b/CoreLibrary/Measurement.py @@ -1,8 +1,14 @@ import os - class Measurement: - def __init__(self, name, path=None, comment=None): + """ + Handle data and write it in a file + """ + + def attach(self, sensor): + pass + + def __init__(self, name, path=None, comment=None, writer=None): self.name = name self.path = os.path.join(path or "./meas_values", self.name) os.makedirs(self.path) @@ -31,4 +37,4 @@ class Measurement: file.write("Version 0.1\n") if comment: file.write(comment + "\n") - file.write("More descriptions of relevant parameters\n") + file.write("More descriptions of relevant parameters\n") \ No newline at end of file diff --git a/CoreLibrary/Param_Model.py b/CoreLibrary/Param_Model.py new file mode 100644 index 0000000..40f1691 --- /dev/null +++ b/CoreLibrary/Param_Model.py @@ -0,0 +1,59 @@ +from time import sleep +from threading import Thread, Event + +from CoreLibrary.ExampleDriver import ExampleDriver +from CoreLibrary.ExampleSensor import ExampleSensor +from CoreLibrary.Measurement import Measurement +from CoreLibrary.Plot_Data import Plot_Data + + +class ExampleDriverWorker(Thread): + """Communicates with the measuring hardware. Here we only produce random data.""" + + def __init__(self, pd): + super().__init__(name="Data_Worker") + self.exit_request = Event() + self.pd = pd + + def run(self): + """Worker method of a python Thread. Called when the Thread is started.""" + while not self.exit_request.is_set(): + self.pd.refresh() + sleep(1) + + +class Param_Model: + def __init__(self): + self.drivers = {"treib1": ExampleDriver()} + self.sensors = {"mess1": ExampleSensor()} + self.__plot_data = [] + self.__measurement = [] + + def new_measurement(self, name=None, writer=None) -> Measurement: + mess = Measurement(name=name) + self.__measurement.append(mess) + return mess + + def get_plot_data(self): + plot_data = Plot_Data() + self.__plot_data.append(plot_data) + return plot_data + + def refresh(self): + for name, sens in self.sensors: + data = sens.get_data + for meas in self.__measurement: + meas.append_data(name, data) + for pd in self.__plot_data: + pd.append_data(name, data) + + def stop_measuring(self): + for sens in self.sensors.items(): + sens.stop_measuring() + pass + + def start_measuring(self): + pass + + def exit(self): + pass diff --git a/plot_data.py b/CoreLibrary/Plot_Data.py similarity index 97% rename from plot_data.py rename to CoreLibrary/Plot_Data.py index 710e52a..e2eb81e 100644 --- a/plot_data.py +++ b/CoreLibrary/Plot_Data.py @@ -1,8 +1,9 @@ -import numpy as np from datetime import datetime, timedelta +import numpy as np -class PlotData: + +class Plot_Data: def __init__(self): # resolution * timeout must be at least 2-3 times higher then the slowest refresh rate @@ -60,7 +61,7 @@ class PlotData: def drop_old(self): for key in self.queues: time = np.array(self.queues[key][0]) - old = self.data["time"][-1] - (self.timeout) + old = self.data["time"][-1] - self.timeout if time.size > 2: drop_index = np.where(time < old)[0] if len(drop_index) is not 0: diff --git a/sensor.py b/CoreLibrary/Sensor.py similarity index 100% rename from sensor.py rename to CoreLibrary/Sensor.py diff --git a/CoreLibrary/mess.py b/CoreLibrary/mess.py new file mode 100644 index 0000000..59b4c23 --- /dev/null +++ b/CoreLibrary/mess.py @@ -0,0 +1,29 @@ +from time import sleep + +from CoreLibrary.Param_Model import Param_Model +from CoreLibrary.Measurement import Measurement + + +def main(param_model: Param_Model): + sensor = param_model.sensors["mess1"] + driver = param_model.drivers["treib1"] + driver.set_config({"speed": 2}) + status = driver.get_status() + + for speed in [1.0, 2.0, 3.0]: + print(speed) + driver.set_config({"speed": speed}) + + measurement = param_model.new_measurement(name=f"penis_{speed}", writer="CSV") + measurement.attach("mess1") + + sensor.start_measuring() + sleep(1) + sensor.stop_measuring() + print("test") + sensor.exit() + driver.exit() + +if __name__ == '__main__': + pd = Param_Model() + main(pd) \ No newline at end of file diff --git a/Diagramm1.dia.autosave b/Diagramm1.dia.autosave new file mode 100644 index 0000000..513ab4d Binary files /dev/null and b/Diagramm1.dia.autosave differ diff --git a/FemtoDLPVA100F.py b/FemtoDLPVA100F.py deleted file mode 100644 index c8ec872..0000000 --- a/FemtoDLPVA100F.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python3 - -# from driver.Luci10 import Luci10 -import logging -from numpy import floor -from time import sleep -from threading import Thread, Event -from sensor import Sensor -from driver import Driver - -LOGGER = logging.getLogger() - - -class FemtoDLPVA100FWorker(Thread): - def __init__( - self, - name="FemtoDLPVA100F Worker", - index=1, - delay=0.2, - ): - super().__init__() - self.exit_request = Event() - self.dc = Event() - self.low_noise = Event() - self.lsbA = Event() - self.msbA = Event() - self.lsbB = Event() - self.msbB = Event() - - self.overload_a = False - self.overload_b = False - - self.name = name - # self.luci = Luci10(printer=False) - self.index = index - self.delay = delay - - def run(self): - while not self.exit_request.is_set(): - - byte_a, byte_b = 0, 0 - if self.lsbA.is_set(): - byte_a |= 0b00000010 # Set 2nd bit to 1 - if self.msbA.is_set(): - byte_a += 4 - if self.lsbB.is_set(): - byte_b += 2 - if self.msbB.is_set(): - byte_b += 4 - if self.dc.is_set(): - byte_a += 8 - byte_b += 8 - if self.low_noise.is_set(): - byte_a += 16 - byte_b += 16 - - # self.luci.led_on() - # self.luci.write_bytes(self.index, byte_a, byte_b) - # self.luci.led_off() - - LOGGER.debug(f"({self.name}) write bytes A, B: {byte_a:b}, {byte_b:b}") - - sleep(self.delay) - - -class FemtoDLPVA100F(Driver): - def __init__(self, name="FemtoDLPVA100F", index=1): - - self.name = name - # self.luci = Luci10(printer=False) - self.index = index - - self.overload_A = False - self.overload_B = False - self.check_overload() - - self.femtoThread = FemtoDLPVA100FWorker() - self.femtoThread.dc.set() - self.femtoThread.low_noise.set() - self.femtoThread.lsbA.clear() - self.femtoThread.msbA.clear() - self.femtoThread.lsbB.clear() - self.femtoThread.msbB.clear() - - self.femtoThread.start() - - self.dc = True - self.low_noise = True - self.exp_a = 1 - self.exp_b = 1 - - def check_overload(self): - overload_A = self.check_overload_a() - overload_B = self.check_overload_b() - return overload_A, overload_B - - def get_status(self): - a, b = self.check_overload() - return {"overload_a": a, "overload_b": b} - - def check_overload_a(self): - return False - # self.luci.led_on() - # self.overload_A = not self.luci.get_status_pin5(self.index) - # self.luci.led_off() - LOGGER.info(f"({self.name:s}) overload A: {self.overload_A}") - return self.overload_A - - def check_overload_b(self): - return True - # self.luci.led_on() - # self.overload_B = not self.luci.get_status_pin6(self.index) - # self.luci.led_off() - LOGGER.info(f"({self.name:s}) overload B: {self.overload_B}") - return self.overload_B - - def exit(self): - self.femtoThread.exit_request.set() - LOGGER.info("(%s) Thread closed." % self.name) - - def get_config(self): - config = { - "dc": self.dc, - "low_noise": self.low_noise, - "exp_a": self.exp_a, - "exp_b": self.exp_b, - } - LOGGER.info("(%s) config: %s" % (self.name, config)) - - return config - - def set_config(self, config): - # TODO proper dict parsing - exp_a = 1 - exp_b = 1 - dc = True - low_noise = True - self.dc = dc - if dc: - self.set_dc() - else: - self.reset_dc() - # TODO reduce spam - if low_noise: - self.set_low_noise() - self.low_noise = True - else: - self.reset_low_noise() - self.low_noise = False - - self.set_exponent_a(exp_a=exp_a) - self.exp_a = exp_a - self.set_exponent_b(exp_b=exp_b) - self.exp_b = exp_b - - def set_dc(self): - self.femtoThread.dc.set() - LOGGER.info("(%s) dc is set to %s" % (self.name, True)) - - def reset_dc(self): - self.femtoThread.dc.clear() - LOGGER.info("(%s) dc is set to %s" % (self.name, False)) - - def set_low_noise(self): - self.femtoThread.low_noise.set() - LOGGER.info("(%s) low noise is set to %s" % (self.name, True)) - - def reset_low_noise(self): - self.femtoThread.low_noise.clear() - LOGGER.info("(%s) low noise is set to %s" % (self.name, False)) - - def set_exponent_a( - self, - exp_a=1, - ): - if exp_a < 1: - exp_a = 1 - if exp_a > 4: - exp_a = 4 - - if (exp_a % 2) == 0: - self.femtoThread.lsbA.set() - else: - self.femtoThread.lsbA.clear() - - if (floor((exp_a - 1) / 2) - 1) == 0: - self.femtoThread.msbA.set() - else: - self.femtoThread.msbA.clear() - - LOGGER.debug("(%s) exponent a = %i" % (self.name, exp_a)) - - def set_exponent_b( - self, - exp_b=1, - ): - if exp_b < 1: - exp_b = 1 - if exp_b > 4: - exp_b = 4 - - if (exp_b % 2) == 0: - self.femtoThread.lsbB.set() - else: - self.femtoThread.lsbB.clear() - - if (floor((exp_b - 1) / 2) - 1) == 0: - self.femtoThread.msbB.set() - else: - self.femtoThread.msbB.clear() - - LOGGER.debug("(%s) exponent a = %i" % (self.name, exp_b)) diff --git a/driver.py b/driver.py deleted file mode 100644 index bc49c35..0000000 --- a/driver.py +++ /dev/null @@ -1,21 +0,0 @@ -from abc import ABC, abstractmethod - - -class Driver(ABC): - """docstring for Model.""" - - @abstractmethod - def exit(self): - pass - - @abstractmethod - def set_config(self, config): - pass - - @abstractmethod - def get_status(self): - pass - - @abstractmethod - def get_config(self): - pass diff --git a/model.py b/model.py deleted file mode 100644 index 9921382..0000000 --- a/model.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -API for scripting measurements and drivers - -Data: -- dict with sensor data (temp, pressure, current) -- dict with drivers (magnetic field control) -""" -from datetime import datetime -from threading import Event, Thread -from time import sleep -from FemtoDLPVA100F import FemtoDLPVA100F -from measurement import Measurement -from plot_data import PlotData -from ExampleSensor import ExampleSensor - - -class DataGrabber(Thread): - def __init__(self, sensors, drivers, plot_data): - super().__init__() - self.measurement = None - self.sensors = sensors - self.drivers = drivers - self.plot_data = plot_data - self.exit_request = Event() - - def run(self): - while not self.exit_request.is_set(): - for name, sens in self.sensors.items(): - dat = sens.get_data - self.plot_data.append_data(name, dat) - if self.measurement is not None: - self.measurement.append_data(name, dat) - sleep(1) - - -class Model: - def __init__(self): - self.plot_data = PlotData() - a = ExampleSensor() - self.sensors = {"temp": a, "multi": ExampleSensor()} - self.drivers = [] - self.measurement = None - self.data_grabber = DataGrabber(self.sensors, self.drivers, self.plot_data) - self.data_grabber.start() - - def start_measuring(self, meas_name=""): - name = meas_name or f"meas_{datetime.utcnow().isoformat().replace(':', '-')}" - self.measurement = Measurement(name) - self.data_grabber.measurement = self.measurement - - def save_measuring(self, path="temp_temp.csv"): - print("Has no use delete me maybe") - - def stop_measuring(self): - self.measurement = None - self.data_grabber.measurement = None - - def clear(self): - self.plot_data.clear() - - def exit(self): - self.data_grabber.exit_request.set() - for sens in self.sensors.values(): - sens.exit() - - -""" - init() - sensoren = [] - - - for mag in range(10): - drive_to_value("MagnetFelied1", mag) - start_measuring("volt", "filename") - - - - - -""" diff --git a/my_control_script.py b/my_control_script.py deleted file mode 100644 index 425c6f7..0000000 --- a/my_control_script.py +++ /dev/null @@ -1,17 +0,0 @@ -from time import sleep -import model - - -def main(param_model): - param_model.start_measuring() - with open("script_output.log", "w") as my_file: - for i in range(20): - sleep(0.5) - x, y = param_model.sensors["temp"].get_data - my_file.write(f"x: {x}, y: {y}\n") - param_model.stop_measuring() - - -if __name__ == "__main__": - print("wrong call") - # main(model.Model()) diff --git a/plotView.py b/plotView.py index 442176a..ad7b60f 100644 --- a/plotView.py +++ b/plotView.py @@ -24,13 +24,13 @@ LOGGER = logging.getLogger("mylogger") class PlotPanel(wx.Panel): - def __init__(self, parent, model, plotLambda, updateLambda): + def __init__(self, parent, pd, plotLambda, updateLambda): super().__init__(parent, -1) self.plotLambda = plotLambda self.updateLambda = updateLambda - self.model = model + self.pd = pd self.fig = Figure((15, 10), 75) self.canvas = FigureCanvas(self, -1, self.fig) self.toolbar = NavigationToolbar(self.canvas) # matplotlib toolbar @@ -46,7 +46,7 @@ class PlotPanel(wx.Panel): self.Bind(wx.EVT_PAINT, self.on_paint, self) self.ax = self.fig.add_subplot() self.fig.legend() - (self.im,) = self.plotLambda(self.ax,self.model.plot_data.data) + (self.im,) = self.plotLambda(self.ax,self.pd.data) self.toolbar.update() # Not sure why this is needed - ADS def get_toolbar(self): @@ -55,7 +55,7 @@ class PlotPanel(wx.Panel): return self.toolbar def on_paint(self, event): - dat = self.model.plot_data.data + dat = self.pd.data self.updateLambda(self.im, dat) self.ax.relim() self.ax.autoscale_view() diff --git a/view.py b/view.py index dccabc4..fcf051d 100644 --- a/view.py +++ b/view.py @@ -8,7 +8,6 @@ import importlib.machinery import logging from threading import Thread import wx -from model import Model # begin wxGlade: dependencies # end wxGlade @@ -22,6 +21,9 @@ from matplotlib.backends.backend_wxagg import ( NavigationToolbar2WxAgg as NavigationToolbar, ) from matplotlib.figure import Figure + +from CoreLibrary.Param_Model import Param_Model +#from plotView import PlotPanel from plotView import PlotPanel LOGGER = logging.getLogger("myLogger") @@ -36,7 +38,8 @@ LOGGER = logging.getLogger("myLogger") class MyFrame(wx.Frame): def __init__(self, *args, **kwds): - self.model = Model() + self.model = Param_Model() + self.pd = self.model.get_plot_data() # begin wxGlade: MyFrame.__init__ kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE @@ -100,14 +103,14 @@ class MyFrame(wx.Frame): self.tabs = wx.Notebook(self.panel_1, wx.ID_ANY) grid_sizer_main.Add(self.tabs, (0, 1), (1, 1), wx.EXPAND, 0) - plot = lambda ax, dat: ax.plot(dat["time"], dat["temp"]) - update = lambda im, dat: im.set_data(dat["time"], dat["temp"]) - self.plot_1 = PlotPanel(self.tabs, self.model, plot, update) + plot = lambda ax, dat: ax.plot(dat["time"], dat["mess1"]) + update = lambda im, dat: im.set_data(dat["time"], dat["mess1"]) + self.plot_1 = PlotPanel(self.tabs, self.pd, plot, update) self.tabs.AddPage(self.plot_1, "Temp") - plot = lambda ax, dat: ax.plot(dat["time"], dat["multi"]) - update = lambda im, dat: im.set_data(dat["time"], dat["multi"]) - self.plot_2 = PlotPanel(self.tabs, self.model, plot, update) + plot = lambda ax, dat: ax.plot(dat["time"], dat["mess1"]) + update = lambda im, dat: im.set_data(dat["time"], dat["mess1"]) + self.plot_2 = PlotPanel(self.tabs, self.pd, plot, update) self.tabs.AddPage(self.plot_2, "Multi") @@ -171,6 +174,7 @@ class MyFrame(wx.Frame): def update(self, event): #Repaint gui self.tabs.Refresh() + self.model.refresh() #Unlock if script is finished if self.runner_thread is not None: if not self.runner_thread.is_alive():