From f624e2807b4b9d052d6182d6e0135145cc7ffd41 Mon Sep 17 00:00:00 2001
From: Christoph Schmidt <christoph.,schmidt@tugraz.at>
Date: Fri, 1 Dec 2023 20:06:18 +0100
Subject: [PATCH] Removed unused files. Process exits now with window close

---
 examples/main.py                              |   2 +-
 .../controller/BaseAD2CaptDevice.py           |  55 +--
 .../mp_AD2Capture/AD2StateMPSetter.py         | 297 ----------------
 .../mp_AD2Capture/MPCaptDeviceControl.py      |   4 +-
 .../mp_AD2Capture/MPDeviceControl.py          | 336 ------------------
 .../view/AD2CaptDeviceView.py                 |   6 +
 6 files changed, 14 insertions(+), 686 deletions(-)
 delete mode 100644 src/CaptDeviceControl/controller/mp_AD2Capture/AD2StateMPSetter.py
 delete mode 100644 src/CaptDeviceControl/controller/mp_AD2Capture/MPDeviceControl.py

diff --git a/examples/main.py b/examples/main.py
index 963bcc6..f065632 100644
--- a/examples/main.py
+++ b/examples/main.py
@@ -2,7 +2,7 @@ import logging
 import sys
 import os
 
-sys.path.append('../src')
+sys.path.append('./src')
 
 from PySide6.QtWidgets import QApplication
 from rich.logging import RichHandler
diff --git a/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py b/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py
index dfad80f..4b7c50a 100644
--- a/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py
+++ b/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py
@@ -1,5 +1,6 @@
 import logging
 import os
+import sys
 import time
 from abc import abstractmethod
 from collections import deque
@@ -8,8 +9,7 @@ from PySide6.QtCore import QObject, QThreadPool
 from numpy import ndarray
 from rich.logging import RichHandler
 
-from CaptDeviceControl.controller.mp_AD2Capture.AD2StateMPSetter import AD2State
-from CaptDeviceControl.controller.mp_AD2Capture.MPDeviceControl import mp_capture
+
 from CaptDeviceControl.model.AD2CaptDeviceModel import AD2CaptDeviceModel, AD2CaptDeviceSignals
 from CaptDeviceControl.model.AD2Constants import AD2Constants
 from multiprocessing import Process, Queue, Value, Lock
@@ -224,56 +224,11 @@ class BaseAD2CaptDevice(QObject):
             #time.sleep(0.1)
         self.logger.info("Status data consume thread ended")
 
-    def _set_ad2state_from_process(self, ad2state: AD2State):
-        # print(ad2state.__dict__)
-        self.model.pid = ad2state.pid
-
-        self.model.dwf_version = ad2state.dwf_version
-
-        self.model.connected = ad2state.connected
-        self.model.device_name = ad2state.device_name
-        self.model.device_serial_number = ad2state.device_serial_number
-        self.model.device_index = ad2state.device_index
-
-        if ad2state.acquisition_state == AD2Constants.CapturingState.RUNNING():
-            self.logger.info("[START ACQ] Started acquisition")
-            self.model.capturing_finished = False
-            self.model.start_recording = True
-            self.model.stop_recording = False
-        elif ad2state.acquisition_state == AD2Constants.CapturingState.STOPPED():
-            if self.model.start_recording:
-                self.model.capturing_finished = True
-                self.logger.info(f"[STOP ACQ] Finished acquisition {self.model.capturing_finished}.")
-                # Emit a signal,  that the Capturing has finished
-            self.model.start_recording = False
-            self.model.stop_recording = True
-        self.model.device_capturing_state = ad2state.acquisition_state
-
-        self.model.sample_rate = ad2state.sample_rate
-        self.model.selected_ain_channel = ad2state.selected_ain_channel
-
-        self.model.ain_channels = ad2state.ain_channels
-        self.model.ain_buffer_size = ad2state.ain_buffer_size
-        self.model.ain_bits = ad2state.ain_bits
-        self.model.ain_device_state = ad2state.ain_device_state
-
-        self.model.recording_time = ad2state.recording_time
-
     # ==================================================================================================================
     # Destructor
     # ==================================================================================================================
-    def stop_process(self):
-        #self.end_process_flag.value = True
-
-        time_start = time.time()
-        #while self.proc.is_alive():
-        #    time.sleep(0.1)
-        self.logger.warning(f"AD2 process exited after {time.time()-time_start}s")
-        self.kill_thread = True
-
-    def __del__(self):
-        self.logger.info("Exiting AD2 controller")
-        self.stop_process()
-        self.logger.warning("AD2 controller exited")
+    def exit(self):
+       self.mpcaptdevicecontrol.safe_exit()
+
 
         
\ No newline at end of file
diff --git a/src/CaptDeviceControl/controller/mp_AD2Capture/AD2StateMPSetter.py b/src/CaptDeviceControl/controller/mp_AD2Capture/AD2StateMPSetter.py
deleted file mode 100644
index f1f0827..0000000
--- a/src/CaptDeviceControl/controller/mp_AD2Capture/AD2StateMPSetter.py
+++ /dev/null
@@ -1,297 +0,0 @@
-from ctypes import c_int, c_byte
-
-from CaptDeviceControl.model.AD2Constants import AD2Constants
-
-class AD2State:
-    def __init__(self):
-        # Multiprocessing Information
-        self._pid = None
-        self._ppid = None
-
-        # WaveForms Runtime (DWF) Information
-        self._dwf_version: str = "Unknown"
-
-        # Device information
-        self._connected: bool = False
-        self._device_name: str = "Unknown"
-        self._serial_number: str = "Unknown"
-        self._device_index: int = -1
-
-        # Acquisition Settings
-        self._sample_rate: int = -1
-        self._selected_ain_channel: int = -1
-
-        # Analog In Information
-        self._ain_channels: list = []
-        self._ain_buffer_size: int = -1
-        self._ain_bits: int = -1
-        self._ain_device_state: c_byte = c_byte()
-
-        # Analog Out Information
-        self._aout_channels: list = []
-
-        # Acquired Signal Information
-        self._acquisition_state: int = AD2Constants.CapturingState.STOPPED()
-
-        self._time_capture_started: float = -1  # The time the capturing has started
-        self._time_capture_ended: float = -1  # The time the capturing has ended
-        self._recording_time: float = -1
-
-        self._samples_captured: int = 0
-        self._samples_lost: int = -1
-        self._samples_corrupted: int = -1
-
-        # Device Status
-        self._device_ready: bool = False
-        self._device_capturing = False
-
-
-    def reinit(self, fields: dict):
-        for k, v in fields.items():
-            setattr(self, k, v)
-
-    # =========== Multiprocessing Information
-    @property
-    def pid(self):
-        return self._pid
-
-    @property
-    def ppid(self):
-        return self._ppid
-
-    # =========== WaveForms Runtime (DWF) Information
-    @property
-    def dwf_version(self):
-        return self._dwf_version
-
-    # =========== Device Information
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def device_name(self):
-        return self._device_name
-
-    @property
-    def device_serial_number(self):
-        return self._serial_number
-
-    @property
-    def device_index(self):
-        return self._device_index
-
-    # ========== Acquisition Settings
-    @property
-    def sample_rate(self):
-        return self._sample_rate
-
-    @property
-    def selected_ain_channel(self):
-        return self._selected_ain_channel
-
-    # =========== Analog In Information
-    @property
-    def ain_channels(self):
-        return self._ain_channels
-
-    @property
-    def ain_buffer_size(self):
-        return self._ain_buffer_size
-
-    @property
-    def ain_bits(self):
-        return self._ain_bits
-
-    @property
-    def ain_device_state(self):
-        return self._ain_device_state
-
-    # =========== Analog Out Information
-    @property
-    def aout_channels(self):
-        return self._aout_channels
-
-    # =========== Acquired Signal Information
-    @property
-    def acquisition_state(self):
-        return self._acquisition_state
-
-    @property
-    def time_capture_started(self) -> float:
-        """The time the capturing has started"""
-        return self._time_capture_started
-
-    @property
-    def time_capture_ended(self) -> float:
-        """The time the capturing has ended"""
-        return self._time_capture_ended
-
-    @property
-    def recording_time(self):
-        return self._recording_time
-
-    @property
-    def samples_captured(self):
-        return self._samples_captured
-
-    @property
-    def samples_lost(self):
-        return self._samples_lost
-
-    @property
-    def samples_corrupted(self):
-        return self._samples_corrupted
-
-    # =========== Device Status
-    @property
-    def device_ready(self):
-        return self._device_ready
-
-    @property
-    def device_capturing(self):
-        return self._device_capturing
-
-
-class AD2StateMPSetter(AD2State):
-
-    def __init__(self, state_queue):
-        super().__init__()
-        self._state_queue = state_queue
-
-    # =========== Multiprocessing Information
-    @AD2State.pid.setter
-    def pid(self, value):
-        self._pid = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.ppid.setter
-    def ppid(self, value):
-        self._ppid = value
-        self._state_queue.put(self.to_simple_class())
-
-    # =========== WaveForms Runtime (DWF) Information
-    @AD2State.dwf_version.setter
-    def dwf_version(self, value):
-
-        self._dwf_version = value
-        self._state_queue.put(self.to_simple_class())
-
-    # =========== Device Information
-    @AD2State.connected.setter
-    def connected(self, value):
-        self._connected = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.device_name.setter
-    def device_name(self, value):
-        self._device_name = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.device_serial_number.setter
-    def device_serial_number(self, value):
-        self._serial_number = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.device_index.setter
-    def device_index(self, value):
-        self._device_index = value
-        self._state_queue.put(self.to_simple_class())
-
-    # ========== Acquisition Settings
-    @AD2State.sample_rate.setter
-    def sample_rate(self, value):
-        self._sample_rate = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.selected_ain_channel.setter
-    def selected_ain_channel(self, value):
-        self._selected_ain_channel = value
-        self._state_queue.put(self.to_simple_class())
-
-    # =========== Analog In Information
-    @AD2State.ain_channels.setter
-    def ain_channels(self, value):
-        self._ain_channels = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.ain_buffer_size.setter
-    def ain_buffer_size(self, value):
-        self._ain_buffer_size = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.ain_bits.setter
-    def ain_bits(self, value):
-        self._ain_bits = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.ain_device_state.setter
-    def ain_device_state(self, value):
-        self._ain_device_state = value
-        self._state_queue.put(self.to_simple_class())
-
-    # =========== Analog Out Information
-    @AD2State.aout_channels.setter
-    def aout_channels(self, value):
-        self._aout_channels = value
-        self._state_queue.put(self.to_simple_class())
-
-    # =========== Acquired Signal Information
-    @AD2State.acquisition_state.setter
-    def acquisition_state(self, value):
-        self._acquisition_state = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.time_capture_ended.setter
-    def time_capture_started(self, value: float):
-        """The time the capturing has started"""
-        self._time_capture_started = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.time_capture_ended.setter
-    def time_capture_ended(self, value: float):
-        self._time_capture_ended = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.recording_time.setter
-    def recording_time(self, value):
-        self._recording_time = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.samples_captured.setter
-    def samples_captured(self, value):
-        self._samples_captured = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.samples_lost.setter
-    def samples_lost(self, value):
-        self._samples_lost = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.samples_corrupted.setter
-    def samples_corrupted(self, value):
-        self._samples_corrupted = value
-        self._state_queue.put(self.to_simple_class())
-
-    # =========== Device Status
-    @AD2State.device_ready.setter
-    def device_ready(self, value):
-        self._device_ready = value
-        self._state_queue.put(self.to_simple_class())
-
-    @AD2State.device_capturing.setter
-    def device_capturing(self, value):
-        self._device_capturing = value
-        self._state_queue.put(self.to_simple_class())
-
-    def to_simple_class(self) -> AD2State:
-        exclude = ["_state_queue"]
-        ad2state = AD2State()
-        to_dict = {}
-        for item, value in self.__dict__.items():
-            if item in exclude:
-                continue
-            else:
-                to_dict[item] = value
-        ad2state.reinit(to_dict)
-        return ad2state
diff --git a/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py
index 5b73a81..62ff7ea 100644
--- a/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py
+++ b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py
@@ -4,8 +4,8 @@ import cmp
 from PySide6.QtCore import Signal
 
 from CaptDeviceControl.controller.mp_AD2Capture.MPCaptDevice import MPCaptDevice
-from model.AD2CaptDeviceModel import AD2CaptDeviceSignals, AD2CaptDeviceModel
-from model.AD2Constants import AD2Constants
+from CaptDeviceControl.model.AD2CaptDeviceModel import AD2CaptDeviceSignals, AD2CaptDeviceModel
+from CaptDeviceControl.model.AD2Constants import AD2Constants
 
 
 class MPCaptDeviceControl(cmp.CProcessControl):
diff --git a/src/CaptDeviceControl/controller/mp_AD2Capture/MPDeviceControl.py b/src/CaptDeviceControl/controller/mp_AD2Capture/MPDeviceControl.py
deleted file mode 100644
index e669235..0000000
--- a/src/CaptDeviceControl/controller/mp_AD2Capture/MPDeviceControl.py
+++ /dev/null
@@ -1,336 +0,0 @@
-"""
-File for methods that run the multiporcessing capture.
-Here we can init the device capturing and stream the data using ques.
-(c) Christoph Schmidt, 2023
-christoph.schmidt@tugraz.at
-"""
-
-import os
-import random
-import sys
-import time
-from ctypes import c_int, byref, c_double, cdll, create_string_buffer, c_int32, CDLL
-
-from CaptDeviceControl.controller.mp_AD2Capture.AD2StateMPSetter import AD2StateMPSetter
-from CaptDeviceControl.model.AD2Constants import AD2Constants
-from CaptDeviceControl.constants.dwfconstants import acqmodeRecord, DwfStateConfig, DwfStatePrefill, DwfStateArmed, enumfilterType, \
-    enumfilterUSB, enumfilterDemo
-
-
-# ======================================================================================================================
-# Process logging function
-# ======================================================================================================================
-def _mp_log_debug(msg, prefix="AD2 Thread"):
-    print(f"DBG  | [{prefix}/{os.getpid()}]: {msg}")
-
-
-def _mp_log_error(msg, prefix="AD2 Thread"):
-    print(f"ERR  | [{prefix}/{os.getpid()}]: {msg}")
-
-
-def _mp_log_info(msg, prefix="AD2 Thread"):
-    print(f"INF  | [{prefix}/{os.getpid()}]: {msg}")
-
-
-def _mp_log_warning(msg, prefix="AD2 Thread"):
-    print(f"WARN | [{prefix}/{os.getpid()}]: {msg}")
-
-
-# ======================================================================================================================
-# Process Main function, used for capturing and streaming data
-# ======================================================================================================================
-def mp_capture(stream_data_queue, capture_data_queue, state_queue,
-               start_capture, end_process,
-               device_id, channel, sample_rate):
-    """
-    Captures data from the device and puts it into a queue.
-    :param capture_data_queue:
-    :param state_queue:
-    :param start_capture:
-    :param end_process:
-    :param device_id:
-    :param sample_rate:
-    :param stream_data_queue: Queue to put the data into.
-    :param channel: Channel to capture data from.
-    :return: None
-    """
-
-    time_capture_started = 0
-    capturing_notified = False
-
-    ad2_state = AD2StateMPSetter(state_queue)
-    ad2_state.pid = os.getpid()
-    ad2_state.ppid = os.getppid()
-    # Print pid and ppid
-    _mp_log_info(f"Starting capture thread, pid={ad2_state.pid}, ppid={ad2_state.ppid}")
-
-    ad2_state.selected_ain_channel = channel
-    ad2_state.sample_rate = sample_rate
-    ad2_state.device_index = device_id
-    _mp_log_debug(f"Setting up device {ad2_state.device_index} with "
-                  f"channel {ad2_state.selected_ain_channel} and "
-                  f"acquisition rate {ad2_state.sample_rate} Hz")
-
-    dwf, hdwf = _mp_open_device(device_id, ad2_state)
-
-    # acquisition_state = c_byte()
-
-    cAvailable = c_int()
-    cLost = c_int()
-    cCorrupted = c_int()
-
-    # FDwfAnalogInStatus(HDWF hdwf, BOOL fReadData, DwfState* psts)
-    _t_setup_aquisition(dwf, hdwf, ad2_state)
-    _t_setup_sine_wave(dwf, hdwf, ad2_state)
-
-    _mp_log_info("Configuring acquisition. Starting oscilloscope.")
-    # FDwfAnalogInConfigure(HDWF hdwf, int fReconfigure, int fStart)
-    # Configures the instrument and start or stop the acquisition. To reset the Auto trigger timeout, set
-    # fReconfigure to TRUE.
-    # hdwf – Interface handle.
-    # fReconfigure – Configure the device.
-    # fStart – Start the acquisition.
-    dwf.FDwfAnalogInConfigure(hdwf, c_int(0), c_int(1))
-
-    _mp_log_info("Device configured. Starting acquisition.")
-
-    cSamples = 0
-    ad2_state.device_ready = True
-    capture_samples = 0
-    print(end_process.value)
-    while end_process.value == int(False):
-        # Checks the state of the acquisition. To read the data from the device, set fReadData to TRUE. For
-        # single acquisition mode, the data will be read only when the acquisition is finished
-        dwf.FDwfAnalogInStatus(hdwf, c_int(1),
-                               byref(ad2_state.ain_device_state))  # Variable to receive the acquisition state
-
-        if cSamples == 0 and (
-                ad2_state.ain_device_state == DwfStateConfig or
-                ad2_state.ain_device_state == DwfStatePrefill or
-                ad2_state.ain_device_state == DwfStateArmed):
-            _mp_log_info("Device in idle state. Waiting for acquisition to start.")
-            continue  # Acquisition not yet started.
-
-        dwf.FDwfAnalogInStatusRecord(hdwf,
-                                     byref(cAvailable),
-                                     byref(cLost),
-                                     byref(cCorrupted))
-        cSamples += cLost.value
-
-        if cLost.value:
-            ad2_state.samples_lost += cLost.value
-        if cCorrupted.value:
-            ad2_state.samples_corrupted += cCorrupted.value
-
-        # self.dwf.FDwfAnalogInStatusSamplesValid(self.hdwf, byref(self.cValid))
-        if cAvailable.value == 0:
-            continue
-        else:
-            # print(f"Available: {cAvailable.value}")
-            # if cSamples + cAvailable.value > self.ad2capt_model.n_samples:
-            #    cAvailable = c_int(self.ad2capt_model.n_samples - cSamples)
-            rgdSamples = (c_double * cAvailable.value)()
-
-            dwf.FDwfAnalogInStatusData(hdwf, c_int(ad2_state.selected_ain_channel), byref(rgdSamples),
-                                       cAvailable)  # get channel data
-            # Print how many samples are available
-            status = {"available": cAvailable.value, 'captured': 0, 'lost': cLost.value,
-                      'corrupted': cCorrupted.value, "time": time.time()}
-            #print(status)
-            time.sleep(random.random())
-            #print(len(rgdSamples))
-            stream_data_queue.put(
-                ([(float(s)) for s in rgdSamples], status)
-            )
-
-            if start_capture.value == 1:
-                if not capturing_notified:
-                    time_capture_started = time.time()
-                    capture_samples = 0
-                    _mp_log_info("Starting command recieved. Acquisition started.")
-                    ad2_state.acquisition_state = AD2Constants.CapturingState.RUNNING()
-                    capturing_notified = True
-                capture_samples = capture_samples + len(rgdSamples)
-                status = {
-                    "available": cAvailable.value,
-                    "captured": capture_samples,
-                    "lost": cLost.value,
-                    "corrupted": cCorrupted.value,
-                    "recording_time": time.time() - time_capture_started}
-                capture_data_queue.put(([float(s) for s in rgdSamples], status))
-                # capture_data_queue.put([float(s) for s in rgdSamples])
-            elif start_capture.value == 0:
-                if capturing_notified:
-                    ad2_state.acquisition_state = AD2Constants.CapturingState.STOPPED()
-                    time_capture_stopped = time.time()
-                    time_captured = time_capture_stopped - time_capture_started
-                    ad2_state.recording_time = time_captured
-                    _mp_log_info(f"Acquisition stopped after {time_captured} seconds. Captured {capture_samples} "
-                                 f"samples. Resulting in a time of {capture_samples / ad2_state.sample_rate} s.")
-                    status = {
-                        "available": cAvailable.value,
-                        "captured": capture_samples,
-                        "lost": cLost.value,
-                        "corrupted": cCorrupted.value,
-                        "recording_time": time.time() - time_capture_started}
-                    capture_data_queue.put(([float(s) for s in rgdSamples], status))
-
-                    capturing_notified = False
-            cSamples += cAvailable.value
-
-    _mp_close_device(dwf, hdwf, channel, ad2_state)
-
-
-def _mp_update_device_information(dwf, hdwf, ad2_state: AD2StateMPSetter):
-    in_channel = c_int()
-    out_channel = c_int()
-    buffer_size = c_int()
-    # Get the  Analog In Channels and Buffer Size
-    dwf.FDwfAnalogInChannelCount(hdwf, byref(in_channel))
-    ad2_state.ain_channels = list(range(0, int(in_channel.value)))
-    dwf.FDwfAnalogInBufferSizeInfo(hdwf, 0, byref(buffer_size))
-
-    # Get the Analog Out Channels and Buffer Size
-    ad2_state.analog_analog_in_buffer_size = int(buffer_size.value)
-    dwf.FDwfAnalogOutCount(hdwf, byref(out_channel))
-    ad2_state.aout_channels = list(range(0, int(out_channel.value)))
-
-    # # Select the first Analog In Channel
-    # ad2_state.selected_channel = ad2_state.list_of_analog_in_channels[0]
-
-
-def _mp_get_dwf_information(dwf, ad2_state: AD2StateMPSetter):
-    _mp_log_debug(f"Getting DWF version information...")
-    version = create_string_buffer(16)
-    dwf.FDwfGetVersion(version)
-    ad2_state.dwf_version = version.value.decode("utf-8")
-    _mp_log_debug(f"DWF Version: {ad2_state.dwf_version}")
-
-# ======================================================================================================================
-# Setup the device
-# ======================================================================================================================
-def _t_setup_sine_wave(dwf, hdwf, ad2_state: AD2StateMPSetter):
-    _mp_log_debug("Generating AM sine wave...")
-    dwf.FDwfAnalogOutNodeEnableSet(hdwf, c_int(0), c_int(0), c_int(1))  # carrier
-    dwf.FDwfAnalogOutNodeFunctionSet(hdwf, c_int(0), c_int(0), c_int(1))  # sine
-    dwf.FDwfAnalogOutNodeFrequencySet(hdwf, c_int(0), c_int(0), c_double(0.1))
-    dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, c_int(0), c_int(0), c_double(1))
-    # dwf.FDwfAnalogOutNodeOffsetSet(hdwf, c_int(0), c_int(0), c_double(0.5))
-    # dwf.FDwfAnalogOutNodeEnableSet(hdwf, c_int(0), c_int(2), c_int(1))  # AM
-    # dwf.FDwfAnalogOutNodeFunctionSet(hdwf, c_int(0), c_int(2), c_int(3))  # triangle
-    # dwf.FDwfAnalogOutNodeFrequencySet(hdwf, c_int(0), c_int(2), c_double(0.1))
-    # dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, c_int(0), c_int(2), c_double(50))
-    dwf.FDwfAnalogOutConfigure(hdwf, c_int(0), c_int(1))
-    _mp_log_debug("Sine wave on output channel 0 configured.")
-
-
-def _t_setup_aquisition(dwf, hdwf, ad2_state: AD2StateMPSetter):
-    dwf.FDwfAnalogInStatus(hdwf, c_int(1),
-                           byref(ad2_state.ain_device_state))  # Variable to receive the acquisition state
-    _mp_log_info(f"[Task] Setup for acquisition on channel"
-                 f" {ad2_state.selected_ain_channel} with rate {ad2_state.sample_rate} Hz.")
-    dwf.FDwfAnalogInChannelEnableSet(hdwf, c_int(ad2_state.selected_ain_channel), c_int(1))
-    dwf.FDwfAnalogInChannelRangeSet(hdwf, c_int(ad2_state.selected_ain_channel), c_double(5))
-    dwf.FDwfAnalogInAcquisitionModeSet(hdwf, acqmodeRecord)
-    dwf.FDwfAnalogInFrequencySet(hdwf, c_double(ad2_state.sample_rate))
-    dwf.FDwfAnalogInRecordLengthSet(hdwf, 0)  # -1 infinite record length
-
-    # Variable to receive the acquisition state
-    dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(ad2_state.ain_device_state))
-    _mp_log_info(f"[Task] Wait 2 seconds for the offset to stabilize.")
-    # wait at least 2 seconds for the offset to stabilize
-    time.sleep(2)
-    _mp_log_info(f"[Task] Setup for acquisition done.")
-
-
-def _mp_discover_connected_devices(dwf):
-    _mp_log_info(f"Discovering connected devices...")
-    num_of_connected_devices = 0
-
-    devicename = create_string_buffer(64)
-    serialnum = create_string_buffer(16)
-
-    for iDevice in enumerate_devices(dwf, show_demo_devices=True):
-        dwf.FDwfEnumDeviceName(c_int(iDevice), devicename)
-        dwf.FDwfEnumSN(c_int(iDevice), serialnum)
-        connected_devices.append({
-            'type': type,
-            'device_id': int(iDevice),
-            'device_name': str(devicename.value.decode('UTF-8')),
-            'serial_number': str(serialnum.value.decode('UTF-8'))
-        })
-        #_mp_log_debug(f"Found {type} device: {devicename.value.decode('UTF-8')} ({serialnum.value.decode('UTF-8')})")
-    # print(connected_devices)
-    # print(f"Discoverd {len(self.model.connected_devices)} devices.")
-    return connected_devices
-
-def enumerate_devices(dwf: CDLL, show_demo_devices=False) -> list:
-    """
-    Enumerates all connected devices. Function is used to discover all connected, compatible devices.
-    Builds an internal list of detected devices filtered by the enumfilter parameter. It must be called
-    before using other FDwfEnum functions because they obtain information about enumerated devices
-    from this list identified by the device index.
-    :param show_demo_devices: Specify if demo devices should be shown.
-    :return: A list from 0 to n devices.
-    """
-    if show_demo_devices:
-        enum_filter = c_int32(enumfilterType.value | enumfilterUSB.value | enumfilterDemo.value)
-    else:
-        enum_filter = c_int32(enumfilterType.value | enumfilterUSB.value)
-
-    cDevice = c_int()
-    dwf.FDwfEnum(enum_filter, byref(cDevice))
-    return list(range(0, cDevice.value))
-
-def _mp_open_device(ad2_state: AD2StateMPSetter):
-    """
-    Opens the device and returns the handle.
-    :return: Device handle.
-    """
-    _mp_log_debug(f"Importing dwf library for {sys.platform}...")
-    if sys.platform.startswith("win"):
-        dwf = cdll.dwf
-    elif sys.platform.startswith("darwin"):
-        dwf = cdll.LoadLibrary("/Library/Frameworks/dwf.framework/dwf")
-    else:
-        dwf = cdll.LoadLibrary("libdwf.so")
-    hdwf = c_int()
-
-    _mp_get_dwf_information(dwf, ad2_state)
-    # This is needed, otherwise, the device is not found.
-    _mp_discover_connected_devices(dwf)
-
-    # Opens the device specified by idxDevice. The device handle is returned in hdwf. If idxDevice is -1, the
-    # first available device is opened.
-    _mp_log_info(f"[Task] Opening device #{ad2_state.device_index}...")
-    dwf.FDwfDeviceOpen(c_int(ad2_state.device_index), byref(hdwf))
-
-    devicename = create_string_buffer(64)
-    serialnum = create_string_buffer(16)
-
-    dwf.FDwfEnumDeviceName(c_int(ad2_state.device_index), devicename)
-    dwf.FDwfEnumSN(c_int(ad2_state.device_index), serialnum)
-
-    ad2_state.device_name = str(devicename.value.decode("utf-8"))
-    ad2_state.device_serial_number = str(serialnum.value.decode("utf-8")).replace("SN:", "")
-    # open device
-
-    if hdwf.value == 0:
-        szerr = create_string_buffer(512)
-        dwf.FDwfGetLastErrorMsg(szerr)
-        _mp_log_error(f"Failed to open device: {szerr.value}")
-        ad2_state.connected = False
-        raise Exception(f"Failed to open device: {szerr.value}")
-    else:
-        _mp_log_info(f"Device opened: {ad2_state.device_name} ({ad2_state.device_serial_number})")
-        ad2_state.connected = True
-
-    return dwf, hdwf
-
-
-def _mp_close_device(dwf, hdwf, channel, ad2_state: AD2StateMPSetter):
-    dwf.FDwfAnalogOutReset(hdwf, c_int(channel))
-    _mp_log_info(f"[Task] Closing device...")
-    dwf.FDwfDeviceClose(hdwf)
-    ad2_state.connected = False
-    _mp_log_info(f"[Task] Device closed.")
diff --git a/src/CaptDeviceControl/view/AD2CaptDeviceView.py b/src/CaptDeviceControl/view/AD2CaptDeviceView.py
index 46dfb25..4246c8d 100644
--- a/src/CaptDeviceControl/view/AD2CaptDeviceView.py
+++ b/src/CaptDeviceControl/view/AD2CaptDeviceView.py
@@ -481,3 +481,9 @@ class ControlWindow(QMainWindow):
         else:
             item = QStandardItem(str(data))
             parent.appendRow(item)
+
+    def closeEvent(self, args):
+        print("Destroyed")
+        self.controller.exit()
+        self.destroyed.emit()
+        
\ No newline at end of file
-- 
GitLab