diff --git a/.idea/other.xml b/.idea/other.xml
index 68993fb7f5a484c71dff26561ff419536660b6ff..652bf24a6b4262f54bba0aebbd9c8687bdbe1a23 100644
--- a/.idea/other.xml
+++ b/.idea/other.xml
@@ -2,5 +2,6 @@
<project version="4">
<component name="PySciProjectComponent">
<option name="PY_SCI_VIEW" value="true" />
+ <option name="PY_MATPLOTLIB_IN_TOOLWINDOW" value="false" />
</component>
</project>
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 1b5a61786e1991d6ddc796dc199d2be81401407b..9a1ec908e2a77ed7fee2924df4ed7e0e5194bc40 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,10 +8,10 @@ pyqtgraph
# add the git repo
git+https://gitlab.tugraz.at/flexsensor-public/modules/fswidgets.git@develop
-git+https://gitlab.tugraz.at/flexsensor-public/modules/confighandler.git@develop
-git+https://gitlab.tugraz.at/flexsensor-public/modules/cmp.git@develop
+#git+https://gitlab.tugraz.at/flexsensor-public/modules/confighandler.git@develop
+#git+https://gitlab.tugraz.at/flexsensor-public/modules/cmp.git@develop
# Local installs
-#../confighandler
+../tools/confighandler
#../captdevicecontrol
-#../modules/cmp
\ No newline at end of file
+../tools/cmp
\ No newline at end of file
diff --git a/src/CaptDeviceControl/CaptDeviceConfig.py b/src/CaptDeviceControl/CaptDeviceConfig.py
index fdc0a46616cf6bad4c4c52ef7f3695641bade73f..6cf17efee94e3987efcfeaddb8a6b5107da4cb54 100644
--- a/src/CaptDeviceControl/CaptDeviceConfig.py
+++ b/src/CaptDeviceControl/CaptDeviceConfig.py
@@ -4,25 +4,39 @@ Author(s): Christoph Schmidt <christoph.schmidt@tugraz.at>
Created: 2023-10-19 12:35
Package Version:
"""
+import logging
+
import confighandler as cfg
class CaptDeviceConfig(cfg.ConfigNode):
def __init__(self) -> None:
- super().__init__()
+ super().__init__(internal_log=True, internal_log_level=logging.DEBUG)
self.sample_rate = cfg.Field(500, friendly_name="Sample rate",
description="Sample rate of the device")
self.streaming_rate = cfg.Field(500, friendly_name="Streaming rate",
description="Streaming rate in Hz (should be below 1kHz)")
- self.ain_channel = cfg.Field(0, friendly_name="Analog In Channel",
- description="Analog in channel. Defines which channel is used for capturing.")
+
+ self.ain_channel = cfg.Field(
+ cfg.SelectableList([0, 1],
+ description=["Channel 0", "Channel 1"],
+ selected_index=0,
+ ),
+ friendly_name="Analog In Channel",
+ description="Analog in channel. Defines which channel is used for capturing.")
+
self.show_simulator = cfg.Field(True, friendly_name="Show Simulators",
description="Show available simulators in the device list "
"provided by the DreamWaves API.")
- self.streaming_history = cfg.Field(2000, friendly_name="Streaming history (ms)",
- description="Defines the range of the stream in ms")
+ self.streaming_history = cfg.Field(
+ cfg.SelectableList([100, 200, 500 ,1000, 2000, 5000, 10000, 20000, 30000],
+ description=["100 ms", "200 ms", "500 ms", "1 s", "2 s", "5 s", "10 s", "20 s", "30 s"],
+ selected_index=3,
+ ),
+ friendly_name="Streaming history",
+ description="Defines the range of the stream in ms")
diff --git a/src/CaptDeviceControl/controller/AD2CaptDeviceSimulator.py b/src/CaptDeviceControl/controller/AD2CaptDeviceSimulator.py
index 98bbd5f2f12402f2617165a0c9d6208f160d9adc..409122e384efe449fb25e79a7f5ed99ee147870b 100644
--- a/src/CaptDeviceControl/controller/AD2CaptDeviceSimulator.py
+++ b/src/CaptDeviceControl/controller/AD2CaptDeviceSimulator.py
@@ -38,7 +38,7 @@ class AD2CaptDeviceSimulator(BaseAD2CaptDevice):
}
@Slot()
- def start_capture(self, capture):
+ def start_capturing_process(self, capture):
if capture:
self.logger.info(f"[{self.pref} Task] Setting up device for capturing.")
diff --git a/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py b/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py
index 4b7c50a74836bc124f1bf80a7ed142b183a45419..e573e3b5944f95dc39eab564bc8a90d36238d859 100644
--- a/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py
+++ b/src/CaptDeviceControl/controller/BaseAD2CaptDevice.py
@@ -5,92 +5,178 @@ import time
from abc import abstractmethod
from collections import deque
-from PySide6.QtCore import QObject, QThreadPool
+import cmp
+from PySide6.QtCore import QObject, QThreadPool, Signal
+
from numpy import ndarray
from rich.logging import RichHandler
-
from CaptDeviceControl.model.AD2CaptDeviceModel import AD2CaptDeviceModel, AD2CaptDeviceSignals
from CaptDeviceControl.model.AD2Constants import AD2Constants
from multiprocessing import Process, Queue, Value, Lock
from CaptDeviceControl.controller.mp_AD2Capture.MPCaptDeviceControl import MPCaptDeviceControl
+from CaptDeviceControl.controller.mp_AD2Capture.MPCaptDevice import MPCaptDevice
-class BaseAD2CaptDevice(QObject):
+class BaseAD2CaptDevice(cmp.CProcessControl):
+ dwf_version_changed = Signal(str, name="dwf_version_changed")
+ discovered_devices_changed = Signal(list, name="discovered_devices_changed")
- def __init__(self, ad2capt_model: AD2CaptDeviceModel, start_capture_flag: Value):
- super().__init__()
- self.model = ad2capt_model
+ selected_device_index_changed = Signal(int, name="selected_device_index_changed")
+ device_connected_changed = Signal(bool, name="connected_changed")
+ device_name_changed = Signal(str, name="device_name_changed")
+ device_serial_number_changed = Signal(str, name="device_serial_number_changed")
- self.pref = "AD2CaptDev"
+ ain_channels_changed = Signal(list, name="ain_channels_changed")
+ ain_buffer_size_changed = Signal(int, name="ain_buffer_size_changed")
+ analog_in_bits_changed = Signal(int, name="analog_in_bits_changed")
+ analog_in_buffer_size_changed = Signal(int, name="analog_in_buffer_size_changed")
+ analog_in_channel_range_changed = Signal(tuple, name="analog_in_channel_range_changed")
+ analog_in_offset_changed = Signal(tuple, name="analog_in_offset_changed")
+
+ open_device_finished = Signal(int, name="open_device_finished")
+ close_device_finished = Signal(name="close_device_finished")
- self.handler = RichHandler(rich_tracebacks=True)
- self.logger = logging.getLogger(f"AD2Controller({os.getpid()})")
- self.logger.handlers = [self.handler]
- self.logger.setLevel(logging.DEBUG)
- formatter = logging.Formatter('%(name)s %(message)s')
- self.handler.setFormatter(formatter)
+ device_state_changed = Signal(AD2Constants.DeviceState, name="device_state_changed")
+ capture_process_state_changed = Signal(AD2Constants.CapturingState, name="capture_process_state_changed")
- self.signals = AD2CaptDeviceSignals()
+ def __init__(self, ad2capt_model: AD2CaptDeviceModel, start_capture_flag: Value):
+ super().__init__(
+ internal_log=True,
+ internal_log_level=logging.DEBUG)
+
+ self.model = ad2capt_model
+
+ self.pref = "AD2CaptDev"
self.thread_manager = QThreadPool()
self.kill_thread = False
- # self.thread_manager.setMaxThreadCount(3)
- # self.thread_manager.se
- # self.thread_manager.setThreadPriority(QThread.HighestPriority)
self.lock = Lock()
- #self.proc = None
self.stream_data_queue = Queue()
self.capture_data_queue = Queue()
- #self.state_queue = Queue()
if start_capture_flag is None:
self.start_capture_flag = Value('i', 0, lock=self.lock)
else:
self.start_capture_flag = start_capture_flag
self.kill_capture_flag = Value('i', 0, lock=self.lock)
- #self.end_process_flag = Value('i', False, lock=self.lock)
# Number of sa
- self.streaming_data_dqueue: deque = None # a dqueue, initialize later
-
- self.status_dqueue = deque(maxlen=int(1))
- self.unconsumed_capture_data = 0
+ self.streaming_dqueue: deque = None # a dqueue, initialize later
+
+ self.register_child_process(
+ MPCaptDevice,
+ self.stream_data_queue,
+ self.capture_data_queue,
+ self.start_capture_flag,
+ self.kill_capture_flag
+ )
+ self.connect_signals()
+ self._connect_config_signals()
+
+ def connect_signals(self):
+ self.dwf_version_changed.connect(self._on_dwf_version_changed)
+ self.discovered_devices_changed.connect(self.on_discovered_devices_changed)
+
+ self.selected_device_index_changed.connect(self.on_selected_device_index_changed)
+
+ self.device_connected_changed.connect(
+ lambda x: type(self.model.device_information).device_connected.fset(self.model.device_information, x))
+ self.device_name_changed.connect(
+ lambda x: type(self.model.device_information).device_name.fset(self.model.device_information, x))
+ self.device_serial_number_changed.connect(
+ lambda x: type(self.model.device_information).device_serial_number.fset(self.model.device_information, x))
+
+ self.ain_channels_changed.connect(
+ lambda x: type(self.model.analog_in).ain_channels.fset(self.model.analog_in, x))
+ self.ain_buffer_size_changed.connect(
+ lambda x: type(self.model.analog_in).ain_buffer_size.fset(self.model.analog_in, x))
+ self.analog_in_bits_changed.connect(
+ lambda x: type(self.model.analog_in).ain_bits.fset(self.model.analog_in, x))
+ self.analog_in_buffer_size_changed.connect(
+ lambda x: type(self.model.analog_in).ain_buffer_size.fset(self.model.analog_in, x))
+ self.analog_in_channel_range_changed.connect(
+ lambda x: type(self.model.analog_in).ai.fset(self.model.analog_in, x))
+ self.analog_in_offset_changed.connect(
+ lambda x: type(self.model.analog_in).ain_offset.fset(self.model.analog_in, x))
+
+ self.device_state_changed.connect(
+ lambda x: type(self.model.device_information).device_state.fset(self.model.device_information, x))
+ self.capture_process_state_changed.connect(
+ lambda x: type(self.model.capturing_information).device_capturing_state.fset(self.model.capturing_information, x))
+
+
+ self.open_device_finished.connect(self.on_open_device_finished)
+
+ def _connect_config_signals(self):
+ self.model.ad2captdev_config.streaming_history.connect(self._on_streaming_history_changed)
+ # ==================================================================================================================
+ # Device control
+ # ==================================================================================================================
+ @cmp.CProcessControl.register_function(open_device_finished)
+ def open_device(self, device_index):
+ """
+ Opens the device with the given id.
+ :param device_id:
+ :return:
+ """
- self.mpcaptdevicecontrol = MPCaptDeviceControl(self.model,
- self.stream_data_queue,
- self.capture_data_queue,
- self.start_capture_flag,
- self.kill_capture_flag,
- enable_internal_logging=False)
+ def on_open_device_finished(self, device_handle: int):
+ self.logger.info(f"Opening device finished with handle {device_handle}")
- #self.mpcaptdevicecontrol.discover_connected_devices_finished.connect(
- # lambda x: type(self.model).connected_devices.fset(self.model, x))
+ def close_device(self):
+ pass
+ # self.close_device()
+
+ @cmp.CProcessControl.register_function(capture_process_state_changed)
+ def start_capturing_process(self, sample_rate: float, ain_channel: int):
+ """
+ Starts the capturing process.
+ :param sample_rate:
+ :param ain_channel:
+ :return:
+ """
+ self.streaming_dqueue = deque(maxlen=self.model.capturing_information.streaming_deque_length)
+ self.thread_manager.start(self.qt_consume_data)
+ self.thread_manager.start(self.qt_stream_data)
+ def _on_streaming_history_changed(self, history: float):
+ self.streaming_dqueue = deque(maxlen=self.model.capturing_information.streaming_deque_length)
- #self.mpcaptdevicecontrol.connected_devices()
+ # ==================================================================================================================
+ # DWF Version
+ # ==================================================================================================================
+ def _on_dwf_version_changed(self, version):
+ self.model.dwf_version = version
- def device_selected_index_changed(self):
- print(self.model.device_information.device_index)
- self.mpcaptdevicecontrol.ain_channels(self.model.device_information.device_index)
- #self.mpcaptdevicecontrol
- def connect_device(self, device_id):
- self.mpcaptdevicecontrol.open_device(device_id)
- self.mpcaptdevicecontrol.start_capture(
- self.model.sample_rate,
- self.model.device_information.device_index)
- self.start_device_process()
- return True
+ # ==================================================================================================================
+ # Discover connected devices
+ # ==================================================================================================================
+ @cmp.CProcessControl.register_function(discovered_devices_changed)
+ def discover_connected_devices(self):
+ """
+ Discover connected devices and update the model.
+ :return:
+ """
- def close_device(self):
- self.mpcaptdevicecontrol.close_device()
+ def on_discovered_devices_changed(self, devices: list):
+ self.model.device_information.connected_devices = devices
+ # ==================================================================================================================
+ # Selected device index
+ # ==================================================================================================================
+ @cmp.CProcessControl.register_function(discovered_devices_changed)
+ def selected_device_index(self, index):
+ """
+ Sets the selected device index.
+ :param index: The index of the device.
+ """
- def discover_connected_devices(self):
- self.mpcaptdevicecontrol.connected_devices()
+ def on_selected_device_index_changed(self, index):
+ self.model.device_information.selected_device_index = index
@abstractmethod
def update_device_information(self):
@@ -118,14 +204,14 @@ class BaseAD2CaptDevice(QObject):
def _init_device_parameters(self):
pass
- #sample_rate = int(self.model.ad2captdev_config.get_sample_rate())
- #total_samples = int(self.model.ad2captdev_config.get_total_samples())
- #channel = 0 # TODO Read channel from input
-
- #self.model.sample_rate = int(sample_rate)
- #self.model.n_samples = int(total_samples)
- #self.model.selected_ain_channel = int(channel)
- #self.logger.info(f"AD2 device initialized {self.model.selected_ain_channel} with "
+ # sample_rate = int(self.model.ad2captdev_config.get_sample_rate())
+ # total_samples = int(self.model.ad2captdev_config.get_total_samples())
+ # channel = 0 # TODO Read channel from input
+
+ # self.model.sample_rate = int(sample_rate)
+ # self.model.n_samples = int(total_samples)
+ # self.model.selected_ain_channel = int(channel)
+ # self.logger.info(f"AD2 device initialized {self.model.selected_ain_channel} with "
# f"acquisition rate {self.model.sample_rate} Hz and "
# f"samples {self.model.n_samples}")
@@ -136,70 +222,67 @@ class BaseAD2CaptDevice(QObject):
self.model.recorded_samples = []
self.model.recorded_sample_stream = []
- def start_capture(self, clear=True):
- print(f"Start capture. Clear {clear}")
- self.start_capture_flag.value = 1
- if clear:
- self.model.recorded_samples = []
- self.model.recorded_sample_stream = []
- self.model.start_recording = True
- self.model.stop_recording = False
- self.model.device_capturing_state = AD2Constants.CapturingState.RUNNING()
+ # def start_capture(self, clear=True):
+ # print(f"Start capture. Clear {clear}")
+ # self.start_capture_flag.value = 1
+ # if clear:
+ # self.model.recorded_samples = []
+ # self.model.recorded_sample_stream = []
+ # self.model.start_recording = True
+ # self.model.stop_recording = False
+ # self.model.device_capturing_state = AD2Constants.CapturingState.RUNNING()
def stop_capture(self):
- print("Stop capture")
self.start_capture_flag.value = 0
- self.model.start_recording = False
- if self.model.reset_recording:
- self.model.device_capturing_state = AD2Constants.CapturingState.STOPPED()
- self.model.stop_recording = True
- else:
- self.model.device_capturing_state = AD2Constants.CapturingState.PAUSED()
+ def start_capture(self, clear=True):
+ self.start_capture_flag.value = 1
- def capture(self, start, clear=True):
- if start:
- self.start_capture(clear)
+ def reset_capture(self):
+ self.logger.info(f"[{self.pref} Task] Resetting capture...")
+ if self.model.capturing_information.device_capturing_state == AD2Constants.CapturingState.RUNNING():
+ self.stop_capture()
+ self.model.capturing_information.recorded_samples = []
+ self.start_capture()
else:
self.stop_capture()
-
- def reset_capture(self):
- self.logger.info("Resetting captured samples for new measurement.")
- self.model.recorded_samples = []
+ self.model.capturing_information.recorded_samples = []
self.model.measurement_time = 0
- self.model.capturing_finished = False
+
+
# ==================================================================================================================
def start_device_process(self):
self.logger.info(f"[{self.pref} Task] Starting capturing process...")
- #self.logger.debug(f"Dataqueue maxlen={int(self.model.duration_streaming_history * self.model.sample_rate)}")
- self.streaming_data_dqueue = deque(maxlen=int(self.model.duration_streaming_history * self.model.sample_rate))
- #print(self.model.duration_streaming_history * self.model.sample_rate)
- self.stream_data_queue.maxsize = int(self.model.duration_streaming_history * self.model.sample_rate)
- #self.proc = Process(target=mp_capture,
+ # self.logger.debug(f"Dataqueue maxlen={int(self.model.duration_streaming_history * self.model.sample_rate)}")
+
+ # self.proc = Process(target=mp_capture,
# args=(
# self.stream_data_queue, self.capture_data_queue, self.state_queue,
# self.start_capture_flag, self.end_process_flag,
# device_id, self.model.selected_ain_channel, self.model.sample_rate)
# )
- #self.proc.start()
+ # self.proc.start()
# self.thread_manager.moveToThread(())
- self.thread_manager.start(self.qt_consume_data)
- self.thread_manager.start(self.qt_stream_data)
- #self.thread_manager.start(self.qt_get_state)
-
+
+ # self.thread_manager.start(self.qt_get_state)
+
def qt_consume_data(self):
while True:
+ t = time.time()
try:
- capt_data = self.capture_data_queue.get()
- if isinstance(capt_data, ndarray):
- print(f"Capt data queue size {self.capture_data_queue.qsize()}")
- # for d in stream_data:
- # self.model.recorded_samples.append(d)
+ capture_data = self.capture_data_queue.get(block=True)
+ if isinstance(capture_data, ndarray):
+ # print(f"Stream data queue size {len(stream_data)}")
+ for d in capture_data:
+ self.model.capturing_information.recorded_samples.append(d)
+ t_end = time.time()
+ # print(f"Time to get data {t_end-t}")
except Exception as e:
- self.logger.info(f"Error while consuming data {e}")
- self.logger.info("Capture Data consume thread ended")
+ self.logger.info(f"Timeout reached. No data in queue {self.stream_data_queue.qsize()} or"
+ f"{e}")
+ self.logger.info("Streaming data consume thread ended")
def qt_stream_data(self):
while True:
@@ -207,11 +290,11 @@ class BaseAD2CaptDevice(QObject):
try:
stream_data = self.stream_data_queue.get(block=True)
if isinstance(stream_data, ndarray):
- #print(f"Stream data queue size {self.stream_data_queue.qsize()}")
+ # print(f"Stream data queue size {len(stream_data)}")
for d in stream_data:
- self.streaming_data_dqueue.append(d)
+ self.streaming_dqueue.append(d)
t_end = time.time()
- #print(f"Time to get data {t_end-t}")
+ # print(f"Time to get data {t_end-t}")
except Exception as e:
self.logger.info(f"Timeout reached. No data in queue {self.stream_data_queue.qsize()} or"
f"{e}")
@@ -221,14 +304,11 @@ class BaseAD2CaptDevice(QObject):
while not self.kill_thread and not bool(self.end_process_flag.value):
while self.state_queue.qsize() > 0:
self._set_ad2state_from_process(self.state_queue.get())
- #time.sleep(0.1)
+ # time.sleep(0.1)
self.logger.info("Status data consume thread ended")
# ==================================================================================================================
# Destructor
# ==================================================================================================================
def exit(self):
- self.mpcaptdevicecontrol.safe_exit()
-
-
-
\ No newline at end of file
+ self.mpcaptdevicecontrol.safe_exit()
diff --git a/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDevice.py b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDevice.py
index b2c5af756bd6632f83adde689de824f0f8775c7d..39e1c305013c720f8f04760ab895c7d5b28e307a 100644
--- a/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDevice.py
+++ b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDevice.py
@@ -7,12 +7,14 @@ from multiprocessing import Queue, Value
import cmp
import numpy as np
+from cmp.CProperty import CProperty
from constants.dwfconstants import enumfilterType, enumfilterDemo, enumfilterUSB, acqmodeRecord, DwfStateConfig, \
DwfStatePrefill, DwfStateArmed
+from CaptDeviceControl.model.AD2Constants import AD2Constants
-class MPCaptDevice(cmp.CProcess):
+class MPCaptDevice(cmp.CProcess, ):
@staticmethod
def timeit(func):
def wrapper(self, *args, **kwargs):
@@ -20,17 +22,22 @@ class MPCaptDevice(cmp.CProcess):
res = func(self, *args, **kwargs)
time_stop = time.time()
print(f"Function {func.__name__} took {time_stop - time_start} seconds.")
- return res #time_stop - time_start
+ return res # time_stop - time_start
return wrapper
- def __init__(self, state_queue, cmd_queue,
+ def __init__(self, state_queue: Queue, cmd_queue: Queue,
streaming_data_queue: Queue, capture_data_queue: Queue,
start_capture_flag: Value,
kill_capture_flag: Value,
- enable_internal_logging):
- super().__init__(state_queue, cmd_queue, enable_internal_logging=enable_internal_logging)
-
+ kill_flag: Value,
+ internal_log, internal_log_level):
+ super().__init__(state_queue, cmd_queue,
+ kill_flag=kill_flag,
+ internal_log=internal_log,
+ internal_log_level=internal_log_level)
+
+ self._device_capturing = False
self._c_samples = None
self._c_corrupted = None
self._c_lost = None
@@ -42,42 +49,110 @@ class MPCaptDevice(cmp.CProcess):
self.stream_data_queue = streaming_data_queue
self.capture_data_queue = capture_data_queue
- self.logger, self.ha = None, None
-
self.dwf = None
self.hdwf = None
# Capture data counters
+ self._selected_device_index = 0
self._dwf_version = None
self._device_serial_number: str = ""
self._device_name: str = ""
self._connected = False
+ self._connected_devices = []
+
self._samples_lost = 0
self._samples_corrupted = 0
- def postrun_init(self):
- self.logger, self.ha = self.create_new_logger(f"{self.__class__.__name__}/({os.getpid()})")
+ # ==================================================================================================================
+ # Getter and Setter
+ # ==================================================================================================================
+
+ @CProperty
+ def dwf_version(self):
+ return self._dwf_version
+
+ @dwf_version.setter(emit_to='dwf_version_changed')
+ def dwf_version(self, value):
+ self._dwf_version = value
+
+ @CProperty
+ def connected_devices(self) -> list:
+ return self._connected_devices
+
+ @connected_devices.setter(emit_to='connected_devices_changed')
+ def connected_devices(self, value: list):
+ self._connected_devices = value
+
+ @cmp.CProcess.register_signal(signal_name='selected_device_index_changed')
+ def selected_device_index(self, device_index: int):
+ # self.logger.debug(f"*** Selected device index {device_index}.")
+ self._selected_device_index = device_index
+ # If the selected device index change, we need to update the device information
+ self.device_name = self.get_device_name(self._selected_device_index)
+ self.device_serial_number = self.get_device_serial_number(self._selected_device_index)
+
+ self.ain_channels = self.get_ain_channels(self._selected_device_index)
+ self.ain_buffer_size = self.get_ain_buffer_size(self._selected_device_index)
+ return self._selected_device_index
+
+ @CProperty
+ def device_name(self):
+ return self._device_name
+
+ @device_name.setter(emit_to='device_name_changed')
+ def device_name(self, value):
+ self._device_name = value
+
+ @CProperty
+ def device_serial_number(self):
+ return self._device_serial_number
+ @device_serial_number.setter(emit_to='device_serial_number_changed')
+ def device_serial_number(self, value):
+ self._device_serial_number = value
+
+ @CProperty
+ def connected(self):
+ return self._connected
+
+ @connected.setter(emit_to='device_connected_changed')
+ def connected(self, value):
+ self._connected = value
+
+ @CProperty
+ def ain_channels(self, device_id):
+ return self._ain_channels
+
+ @ain_channels.setter(emit_to='ain_channels_changed')
+ def ain_channels(self, value):
+ self.logger.info("Setting ain channels.")
+ self._ain_channels = value
+
+ # ==================================================================================================================
+ #
+ # ==================================================================================================================
+ def postrun_init(self):
if sys.platform.startswith("win"):
self.dwf = cdll.dwf
elif sys.platform.startswith("darwin"):
self.dwf = cdll.LoadLibrary("/Library/Frameworks/dwf.framework/dwf")
else:
self.dwf = cdll.LoadLibrary("libdwf.so")
- self._connected = self.connected()
- self.hdwf = c_int()
+ # self._connected = self.connected()
+ self.dwf_version = self.get_dwf_version()
+ #@CProperty
+ #def device_capturing(self, capturing: bool):
+ # return self._device_capturing
- @cmp.CProcess.register_for_signal('_changed')
- def device_capturing(self, capturing: bool):
- self.logger.info(f"Device capturing: {capturing}")
- return capturing
+ #@device_capturing.setter(emit_to='device_capturing_changed')
+ #def device_capturing(self, capturing: bool):
+ # self._device_capturing = capturing
- @cmp.CProcess.register_for_signal('_changed')
- def dwf_version(self):
+ def get_dwf_version(self) -> str:
self.logger.debug(f"Getting DWF version information...")
version = create_string_buffer(16)
self.dwf.FDwfGetVersion(version)
@@ -86,8 +161,9 @@ class MPCaptDevice(cmp.CProcess):
# ==================================================================================================================
# Device Enumeration without connecting to the device
# ==================================================================================================================
- @cmp.CProcess.register_for_signal('_changed')
- def connected_devices(self):
+ @cmp.CProcess.register_signal()
+ def discover_connected_devices(self):
+
self.logger.info(f"Discovering connected devices...")
# enumerate connected devices
connected_devices = []
@@ -102,24 +178,69 @@ class MPCaptDevice(cmp.CProcess):
# filter, type = (c_int32(enumfilterType.value | enumfilterDemo.value), 'DEMO')
self.logger.debug(f"Filtering {type} devices...")
self.dwf.FDwfEnum(filter, byref(cDevice))
- num_of_connected_devices = cDevice
+
self.logger.debug(f"Found {cDevice.value} {type} devices.")
for iDevice in range(0, cDevice.value):
connected_devices.append({
'type': type,
'device_id': int(iDevice),
- 'device_name': self.device_name(iDevice),
- 'serial_number': self.device_serial_number(iDevice)
+ 'device_name': self.get_device_name(iDevice),
+ 'serial_number': self.get_device_serial_number(iDevice)
})
# _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.")
self.logger.info(f"Found {len(connected_devices)} devices.")
return connected_devices
- @cmp.CProcess.register_for_signal('_changed')
- def ain_channels(self, device_id) -> list:
+ # ==================================================================================================================
+ # Functions for opening and closing the device
+ # ==================================================================================================================
+ @cmp.CProcess.register_signal()
+ def open_device(self, device_index) -> int:
+ """
+ Opens the device and returns the handle.
+ :return: Device handle.
+ """
+ self.selected_device_index(device_index)
+ if self.hdwf is not None or not isinstance(self.hdwf, c_int):
+ self.hdwf = c_int()
+
+ self.logger.debug(f"Opening device {self._selected_device_index}...")
+ self._dwf_version = self.get_dwf_version()
+
+ # Opens the device specified by idxDevice. The device handle is returned in hdwf. If idxDevice is -1, the
+ # first available device is opened.
+ self.dwf.FDwfDeviceOpen(c_int(self._selected_device_index), byref(self.hdwf))
+
+ self._device_name = self.get_device_name(self._selected_device_index)
+ self._device_serial_number = self.get_device_serial_number(self._selected_device_index)
+
+ if self.hdwf.value == 0:
+ szerr = create_string_buffer(512)
+ self.dwf.FDwfGetLastErrorMsg(szerr)
+ err = szerr.value.decode("utf-8")
+ self.logger.error(f"Failed to open device: {err}")
+ # ad2_state.connected = False
+ raise Exception(f"Failed to open device: {err}")
+ else:
+ self.logger.info(f"Device opened: {self._device_name} "
+ f"({self._device_serial_number})")
+ self.connected = self.device_connected()
+ self.device_state(AD2Constants.DeviceState.ACQ_NOT_STARTED())
+ return int(self.hdwf.value)
+
+ def close_device(self):
+ # self.dwf.FDwfAnalogOutReset(self.hdwf, c_int(channel))
+ self.logger.info(f"[Task] Closing device...")
+ self.dwf.FDwfDeviceClose(self.hdwf)
+ self.hdwf.value = 0
+ self._connected = self.connected()
+ self.logger.info(f"[Task] Device closed.")
+
+ # ==================================================================================================================
+ # Device Information
+ # ==================================================================================================================
+ def get_ain_channels(self, device_id) -> list:
cInfo = c_int()
self.dwf.FDwfEnumConfigInfo(c_int(device_id), c_int(1), byref(cInfo))
ain_channels = cInfo.value
@@ -132,14 +253,12 @@ class MPCaptDevice(cmp.CProcess):
self.logger.debug(f"Device {device_id} has {ain_channels} analog input channels.")
return list(range(0, ain_channels))
- @cmp.CProcess.register_for_signal('_changed')
- def ain_buffer_size(self, device_id) -> int:
+ def get_ain_buffer_size(self, device_id) -> int:
cInfo = c_int()
self.dwf.FDwfEnumConfigInfo(c_int(device_id), c_int(7), byref(cInfo))
return cInfo.value
- @cmp.CProcess.register_for_signal('_changed')
- def device_name(self, device_index: int) -> str:
+ def get_device_name(self, device_index: int) -> str:
try:
devicename = create_string_buffer(64)
self.dwf.FDwfEnumDeviceName(c_int(device_index), devicename)
@@ -148,8 +267,7 @@ class MPCaptDevice(cmp.CProcess):
self.logger.error(f"Error while reading device name: {e}")
raise Exception(f"Error while reading device name: {e}")
- @cmp.CProcess.register_for_signal('_changed')
- def device_serial_number(self, device_index: int) -> str:
+ def get_device_serial_number(self, device_index: int) -> str:
try:
serialnum = create_string_buffer(16)
self.dwf.FDwfEnumSN(c_int(device_index), serialnum)
@@ -161,8 +279,7 @@ class MPCaptDevice(cmp.CProcess):
# ==================================================================================================================
# Device connection status
# ==================================================================================================================
- @cmp.CProcess.register_for_signal('_changed')
- def connected(self) -> bool:
+ def device_connected(self) -> bool:
if self.hdwf is None or self.hdwf.value == 0:
szerr = create_string_buffer(512)
self.dwf.FDwfGetLastErrorMsg(szerr)
@@ -195,7 +312,7 @@ class MPCaptDevice(cmp.CProcess):
self.logger.error(f"Can not read the AnalogIn Channel Count. Device not connected.")
raise Exception(f"Can not read the AnalogIn Channel Count. Device not connected.")
- @cmp.CProcess.register_for_signal('_changed')
+ @cmp.CProcess.register_signal('_changed')
def analog_in_bits(self) -> int:
"""
Retrieves the number bits used by the AnalogIn ADC. The oscilloscope channel settings are identical
@@ -212,7 +329,7 @@ class MPCaptDevice(cmp.CProcess):
self.logger.error(f"Can not read the AnalogIn Bits. Device not connected.")
raise Exception(f"Can not read the AnalogIn Bits. Device not connected.")
- @cmp.CProcess.register_for_signal('_changed')
+ @cmp.CProcess.register_signal('_changed')
def analog_in_buffer_size(self) -> tuple:
"""
Returns the minimum and maximum allowable buffer sizes for the instrument. The oscilloscope
@@ -230,7 +347,7 @@ class MPCaptDevice(cmp.CProcess):
self.logger.error(f"Can not read the AnalogIn Buffer Size. Device not connected.")
raise Exception(f"Can not read the AnalogIn Buffer Size. Device not connected.")
- @cmp.CProcess.register_for_signal('_changed')
+ @cmp.CProcess.register_signal('_changed')
def analog_in_channel_range_info(self) -> tuple:
"""
Returns the minimum and maximum range, peak to peak values, and the number of adjustable steps.
@@ -251,7 +368,7 @@ class MPCaptDevice(cmp.CProcess):
self.logger.error(f"Can not read the AnalogIn Channel Range. Device not connected.")
raise Exception(f"Can not read the AnalogIn Channel Range. Device not connected.")
- @cmp.CProcess.register_for_signal('_changed')
+ @cmp.CProcess.register_signal('_changed')
def analog_in_offset(self) -> tuple:
""" Returns the minimum and maximum offset levels supported, and the number of adjustable steps"""
if self.connected():
@@ -265,60 +382,21 @@ class MPCaptDevice(cmp.CProcess):
self.logger.error(f"Can not read the AnalogIn Offset. Device not connected.")
raise Exception(f"Can not read the AnalogIn Offset. Device not connected.")
- # ==================================================================================================================
- # Functions for opening and closing the device
- # ==================================================================================================================
- @cmp.CProcess.register_for_signal()
- def open_device(self, device_index):
- """
- Opens the device and returns the handle.
- :return: Device handle.
- """
- self.logger.debug(f"Opening device {device_index}...")
- self._dwf_version = self.dwf_version()
-
- # Opens the device specified by idxDevice. The device handle is returned in hdwf. If idxDevice is -1, the
- # first available device is opened.
- self.dwf.FDwfDeviceOpen(c_int(device_index), byref(self.hdwf))
-
- self._device_name = self.device_name(device_index)
- self._device_serial_number = self.device_serial_number(device_index)
-
- if self.hdwf.value == 0:
- szerr = create_string_buffer(512)
- self.dwf.FDwfGetLastErrorMsg(szerr)
- err = szerr.value.decode("utf-8")
- self.logger.error(f"Failed to open device: {err}")
- # ad2_state.connected = False
- raise Exception(f"Failed to open device: {err}")
- else:
- self.logger.info(f"Device opened: {self._device_name} "
- f"({self._device_serial_number})")
- self._connected = self.connected()
-
- def close_device(self):
- # self.dwf.FDwfAnalogOutReset(self.hdwf, c_int(channel))
- self.logger.info(f"[Task] Closing device...")
- self.dwf.FDwfDeviceClose(self.hdwf)
- self.hdwf.value = 0
- self._connected = self.connected()
- self.logger.info(f"[Task] Device closed.")
-
# ==================================================================================================================
# Function for setting up the acquisition
# ==================================================================================================================
def setup_acquisition(self, sample_rate: float, ain_channel: int):
- #self.dwf.FDwfAnalogInStatus(self.hdwf, c_int(1),
+ # self.dwf.FDwfAnalogInStatus(self.hdwf, c_int(1),
# byref(self._ain_device_state)) # Variable to receive the acquisition state
self.logger.info(f"[Task] Setup for acquisition on channel {ain_channel} with rate {sample_rate} Hz.")
self.dwf.FDwfAnalogInChannelEnableSet(self.hdwf, c_int(ain_channel), c_int(1))
self.dwf.FDwfAnalogInChannelRangeSet(self.hdwf, c_int(ain_channel), c_double(5))
self.dwf.FDwfAnalogInAcquisitionModeSet(self.hdwf, acqmodeRecord)
self.dwf.FDwfAnalogInFrequencySet(self.hdwf, c_double(sample_rate))
- self.dwf.FDwfAnalogInRecordLengthSet(self.hdwf, c_double(1)) # -1 infinite record length
+ self.dwf.FDwfAnalogInRecordLengthSet(self.hdwf, c_double(0)) # -1 infinite record length
self.dwf.FDwfAnalogInConfigure(self.hdwf, c_int(1), c_int(0))
# Variable to receive the acquisition state
- #self.dwf.FDwfAnalogInStatus(self.hdwf, c_int(1), byref(self._ain_device_state))
+ # self.dwf.FDwfAnalogInStatus(self.hdwf, c_int(1), byref(self._ain_device_state))
self.logger.info(f"[Task] Wait 2 seconds for the offset to stabilize.")
# wait at least 2 seconds for the offset to stabilize
time.sleep(2)
@@ -374,160 +452,122 @@ class MPCaptDevice(cmp.CProcess):
raise Exception(f"Error while getting data from device: {e}")
return ptr_rgd_samples, c_available
- def start_capture(self, sample_rate: float, ain_channel: int):
+ @cmp.CProcess.register_signal(signal_name='device_state_changed')
+ def device_state(self, state):
+ return state
+
+ @cmp.CProcess.register_signal(signal_name='capture_process_state_changed')
+ def capture_process_state(self, state):
+ return state
+
+ # ==================================================================================================================
+ #
+ # ==================================================================================================================
+ @cmp.CProcess.register_signal()
+ def start_capturing_process(self, sample_rate: float, ain_channel: int):
"""
Captures data from the device and puts it into a queue.
:param ain_channel:
:param sample_rate:
:return: None
"""
- self.close_device()
-
- 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")
-
- cDevice = c_int()
- hdwf = c_int()
- filter, type = (c_int32(enumfilterType.value | enumfilterDemo.value | enumfilterUSB.value), 'USB')
- dwf.FDwfEnum(filter, byref(cDevice))
- dwf.FDwfDeviceOpen(c_int(3), byref(hdwf))
+ self.logger.info(f"Starting capture on channel {ain_channel} with rate {sample_rate} Hz.")
+ hdwf = self.hdwf
+ self.device_state(AD2Constants.DeviceState.DEV_CAPT_SETUP())
ain_channel = int(0)
- self.logger.debug("Generating AM sine wave...")
- dwf.FDwfAnalogOutNodeEnableSet(hdwf, c_int(ain_channel), c_int(0), c_int(1)) # carrier
- dwf.FDwfAnalogOutNodeFunctionSet(hdwf, c_int(ain_channel), c_int(0), c_int(1)) # sine
- dwf.FDwfAnalogOutNodeFrequencySet(hdwf, c_int(ain_channel), c_int(0), c_double(1))
- dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, c_int(ain_channel), c_int(0), c_double(1))
- dwf.FDwfAnalogOutConfigure(hdwf, c_int(ain_channel), c_int(1))
- time.sleep(1)
- self.logger.debug(f"Sine wave on output channel {ain_channel} configured.")
+ self.setup_sine_wave(ain_channel)
- # FDwfAnalogInStatus(HDWF hdwf, BOOL fReadData, DwfState* psts)
- self.logger.info(f"[Task] Setup for acquisition on channel {ain_channel} with rate {sample_rate} Hz.")
- dwf.FDwfAnalogInChannelEnableSet(hdwf, c_int(ain_channel), c_int(1))
- dwf.FDwfAnalogInChannelRangeSet(hdwf, c_int(ain_channel), c_double(5))
- dwf.FDwfAnalogInAcquisitionModeSet(hdwf, acqmodeRecord)
- dwf.FDwfAnalogInFrequencySet(hdwf, c_double(sample_rate))
- dwf.FDwfAnalogInRecordLengthSet(hdwf, c_double(9999)) # -1 infinite record length
+ self.setup_acquisition(sample_rate, ain_channel)
# Variable to receive the acquisition state
# self.dwf.FDwfAnalogInStatus(self.hdwf, c_int(1), byref(self._ain_device_state))
- self.logger.info(f"[Task] Wait 2 seconds for the offset to stabilize.")
+ # self.logger.info(f"[Task] Wait 2 seconds for the offset to stabilize.")
# wait at least 2 seconds for the offset to stabilize
time.sleep(2)
- self.logger.info(f"[Task] Setup for acquisition done.")
+ # self.logger.info(f"[Task] Setup for acquisition done.")
# Creates a Sin Wave on the Analog Out Channel 0
- self.logger.info("Configuring acquisition. Starting oscilloscope.")
+ # self.logger.info("Configuring acquisition. Starting oscilloscope.")
# Configures the instrument and start or stop the acquisition. To reset the Auto trigger timeout, set
self.dwf.FDwfAnalogInConfigure(hdwf, c_int(0), c_int(1))
- self.logger.info("Device configured. Starting acquisition.")
+ # self.logger.info("Device configured. Starting acquisition.")
time_capture_started = 0
capture_samples = 0
capture_started = False
capture_ended = False
-
-
cAvailable = c_int()
cLost = c_int()
cCorrupted = c_int()
cSamples = 0
- sts = c_byte()
-
+ sts = c_byte()
try:
- #self.dwf.FDwfAnalogOutReset(self.hdwf, c_int(0))
- dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts))
- while self.kill_capture_flag.value == int(False):
- self._c_samples = 0
+ # self.dwf.FDwfAnalogOutReset(self.hdwf, c_int(0))
+ ##plt.ion()
+ ##hl, = plt.plot([], [])
+ self.device_state(AD2Constants.DeviceState.DEV_CAPT_STREAMING())
+ while self.kill_capture_flag.value == int(False):
+ self.dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts))
+ # self._c_samples = 0
time_start = time.time()
# 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
-
- if self._c_samples == 0 and (
- sts == DwfStateConfig or
- sts == DwfStatePrefill or
- sts == DwfStateArmed):
- # self.logger.info("Device in idle state. Waiting for acquisition to start.")
+ if sts == DwfStateConfig or sts == DwfStatePrefill or sts == DwfStateArmed:
+ # self.device_state(AD2Constants.DeviceState.ACQ_NOT_STARTED())
continue # Acquisition not yet started.
- dwf.FDwfAnalogInStatusRecord(hdwf, byref(cAvailable), byref(cLost), byref(cCorrupted))
+ self.dwf.FDwfAnalogInStatusRecord(hdwf, byref(cAvailable), byref(cLost), byref(cCorrupted))
# self.dwf.FDwfAnalogInStatusSamplesValid(self.hdwf, byref(self.cValid))
if cAvailable.value == 0:
- #print("Nothing available")
+ # self.device_state(AD2Constants.DeviceState.NO_SAMPLES_AVAILABLE())
continue
- print(f"Available: {cAvailable.value}")
- # if cSamples + cAvailable.value > self.ad2capt_model.n_samples:
- # cAvailable = c_int(self.ad2capt_model.n_samples - cSamples)
- # time_rgdsamples_start = time.time()
-
- # arr = [None] * cAvailable.value
- # time_rgdsamples_stop = time.time()
- # time_rgdsamples = time_rgdsamples_stop - time_rgdsamples_start
- # print(f"rgd_samples took {time_rgdsamples} seconds")
rgd_samples = (c_double * cAvailable.value)()
# Get the data from the device and store it in rgd_samples
- dwf.FDwfAnalogInStatusData(hdwf,
- c_int(ain_channel),
- byref(rgd_samples),
- cAvailable)
+ self.dwf.FDwfAnalogInStatusData(hdwf, c_int(0), byref(rgd_samples), cAvailable)
- #self._c_samples += self._c_available.value
+ arr = np.array(rgd_samples, copy=True)
iteration_time = time.time() - time_start
- print(f"Got data from device: len {cAvailable.value},"
- f"time {iteration_time} seconds.")
-
- # Convert the data to a numpy array and put it into the queue
- # self.logger.info("Convert data to numpy array and put it into the queue.")
-
- # num_sent_samples = 0
- if len(rgd_samples) > 0:
- #arr =
- print(f"I send {len(np.array(rgd_samples))} samples to the queue.")
- self.stream_data_queue.put(np.array(rgd_samples))
- #np.delete(arr
- else:
- print(f"rgd_samples is empty.")
-
- # if self.start_capture_flag.value == int(True):
- # if not capture_started:
- # self.device_capturing(True)
- # time_capture_started = time.time()
- # self.logger.info(
- # "**************************** Starting command received. Acquisition started.")
- # capture_started = True
- # capture_ended = False
- # capture_samples = 0
- # #capture_samples = capture_samples + len(arr)
- # #self.capture_data_queue.put(arr)
- # elif self.start_capture_flag.value == int(False):
- #
- # if not capture_ended and capture_started:
- # self.device_capturing(False)
- # time_capture_stopped = time.time()
- # time_captured = time_capture_stopped - time_capture_started
- # self.logger.info(
- # "**************************** Stopping command received. Acquisition stopped.")
- # self.logger.info(
- # f"Acquisition stopped after {time_captured} seconds. Captured {capture_samples} "
- # f"samples. Resulting in a time of {capture_samples / sample_rate} s.")
- # capture_ended = True
- # capture_started = False
- # #self.capture_data_queue.put(arr)
- # self._c_samples += self._c_available.value
+ self.stream_data_queue.put(arr)
+
+ # #np.delete(arr
+ # else:
+ # print(f"rgd_samples is empty.")
+
+ if self.start_capture_flag.value == int(True) :
+ if not capture_started:
+ self.capture_process_state(AD2Constants.CapturingState.RUNNING())
+ self.logger.info(
+ "**************************** START command received. Acquisition started.")
+ time_capture_started = time.time()
+ capture_started = True
+ capture_ended = False
+ # capture_samples = capture_samples + len(arr)
+ self.capture_data_queue.put(arr)
+ elif self.start_capture_flag.value == int(False) and capture_started:
+ capture_started = False
+ capture_ended = True
+ self.logger.info(
+ "**************************** STOP command received. Acquisition stopped.")
+ self.capture_process_state(AD2Constants.CapturingState.STOPPED())
+ time_capture_stopped = time.time()
+ time_captured = time_capture_stopped - time_capture_started
+ self.logger.info(
+ f"Acquisition stopped after {time_captured} seconds. Captured {capture_samples} "
+ f"samples. Resulting in a time of {capture_samples / sample_rate} s.")
+ # capture_ended = True
+ # capture_started = False
+ # # self.capture_data_queue.put(arr)
+ #self._c_samples += self._c_available.value
@@ -554,3 +594,22 @@ class MPCaptDevice(cmp.CProcess):
self.dwf.FDwfAnalogOutConfigure(self.hdwf, c_int(channel), c_int(1))
time.sleep(1)
self.logger.debug(f"Sine wave on output channel {channel} configured.")
+
+
+if __name__ == "__main__":
+ state_queue = Queue()
+ cmd_queue = Queue()
+
+ streaming_data_queue = Queue()
+ capture_data_queue = Queue()
+ start_capture_flag = Value('i', 0)
+ kill_capture_flag = Value('i', 0)
+
+ mpcapt = MPCaptDevice(state_queue, cmd_queue,
+ streaming_data_queue,
+ capture_data_queue,
+ start_capture_flag,
+ kill_capture_flag, False
+ )
+ mpcapt.logger, _ = mpcapt.create_new_logger("MPCaptDevice")
+ mpcapt.start_capture(1000, 0)
diff --git a/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py
index 62ff7ea32df0b4a881b12ad663811ae0362d3ba7..537c1c1384e1c638595446650af53c83ef02644b 100644
--- a/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py
+++ b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceControl.py
@@ -1,31 +1,34 @@
+import logging
import os
import cmp
from PySide6.QtCore import Signal
-from CaptDeviceControl.controller.mp_AD2Capture.MPCaptDevice import MPCaptDevice
+
from CaptDeviceControl.model.AD2CaptDeviceModel import AD2CaptDeviceSignals, AD2CaptDeviceModel
from CaptDeviceControl.model.AD2Constants import AD2Constants
-
class MPCaptDeviceControl(cmp.CProcessControl):
- connected_devices_changed = Signal(list)
- ain_channels_changed = Signal(list)
- ain_buffer_size_changed = Signal(int)
- dwf_version_changed = Signal(str)
- device_name_changed = Signal(str)
- device_serial_number_changed = Signal(str)
- connected_changed = Signal(bool)
- open_device_finished = Signal()
- close_device_finished = Signal()
- analog_in_bits_changed = Signal(int)
- analog_in_buffer_size_changed = Signal(int)
- analog_in_channel_range_changed = Signal(tuple)
- analog_in_offset_changed = Signal(tuple)
- device_capturing_changed = Signal(bool)
+ connected_devices_changed = Signal(list, name="connected_devices_changed")
+
+
+
+
+ device_capturing_state_changed = Signal(AD2Constants.CapturingState, name="device_capturing_state_changed")
+
+
+ open_device_finished = Signal(name="open_device_finished")
+ close_device_finished = Signal(name="close_device_finished")
+
+ analog_in_bits_changed = Signal(int, name="analog_in_bits_changed")
+ analog_in_buffer_size_changed = Signal(int, name="analog_in_buffer_size_changed")
+ analog_in_channel_range_changed = Signal(tuple, name="analog_in_channel_range_changed")
+ analog_in_offset_changed = Signal(tuple, name="analog_in_offset_changed")
+
+ device_capturing_changed = Signal(bool, name="device_capturing_changed")
def __init__(self,
model: AD2CaptDeviceModel,
@@ -34,16 +37,19 @@ class MPCaptDeviceControl(cmp.CProcessControl):
start_capture_flag,
kill_capture_flag,
parent=None,
- enable_internal_logging=False):
- super().__init__(parent, enable_internal_logging=enable_internal_logging)
+ internal_log=True,
+ internal_log_level=logging.DEBUG):
+ super().__init__(parent,
+ internal_log=internal_log,
+ internal_log_level=internal_log_level)
self.model = model
self.register_child_process(
- MPCaptDevice(self.state_queue, self.cmd_queue,
+ MPCaptDevice,
streaming_data_queue,
capturing_data_queue,
start_capture_flag,
- kill_capture_flag,
- enable_internal_logging=enable_internal_logging))
+ kill_capture_flag
+ )
self.logger, self.logger_handler = self.create_new_logger(f"{self.__class__.__name__}({os.getpid()})")
@@ -57,14 +63,13 @@ class MPCaptDeviceControl(cmp.CProcessControl):
lambda x: type(model.device_information).device_serial_number.fset(model.device_information, x))
self.connected_changed.connect(
lambda x: type(model.device_information).device_connected.fset(model.device_information, x))
+ self.device_capturing_state_changed.connect(
+ lambda x: type(model).device_capturing_state.fset(model, x))
+ self.device_state_changed.connect(
+ lambda x: type(model).device_state.fset(model, x))
# Analog In Information
- self.ain_channels_changed.connect(lambda x: type(model.analog_in).ain_channels.fset(model.analog_in, x))
- self.ain_buffer_size_changed.connect(lambda x: type(model.analog_in).ain_buffer_size.fset(model.analog_in, x))
- self.analog_in_bits_changed.connect(lambda x: type(model.analog_in).ain_bits.fset(model.analog_in, x))
- self.analog_in_buffer_size_changed.connect(lambda x: type(model.analog_in).ain_buffer_size.fset(model.analog_in, x))
- self.analog_in_channel_range_changed.connect(lambda x: type(model.analog_in).ai.fset(model.analog_in, x))
- self.analog_in_offset_changed.connect(lambda x: type(model.analog_in).ain_offset.fset(model.analog_in, x))
+
self.device_capturing_changed.connect(self.on_capturing_state_changed)
@@ -74,15 +79,20 @@ class MPCaptDeviceControl(cmp.CProcessControl):
else:
self.model.device_capturing_state = AD2Constants.CapturingState.STOPPED()
- @cmp.CProcessControl.register_function()
+ @cmp.CProcessControl.register_function(connected_devices_changed)
def connected_devices(self):
self.logger.info("Discovering connected devices.")
+ # Setter for the selected device index
@cmp.CProcessControl.register_function()
- def ain_channels(self, device_id):
- self.logger.info(f"Reading available analog input channels for device {device_id}.")
+ def selected_device_index(self, device_index: int):
+ self.logger.info(f"Selected device index {device_index}.")
- @cmp.CProcessControl.register_function()
+ #@cmp.CProcessControl.register_function(ain_channels_changed)
+ #def ain_channels(self, device_id):
+ # self.logger.info(f"Reading available analog input channels for device {device_id}.")
+
+ @cmp.CProcessControl.register_function(open_device_finished)
def open_device(self, device_index):
self.logger.info(f"Opening device {device_index}.")
diff --git a/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceSceleton.py b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceSceleton.py
new file mode 100644
index 0000000000000000000000000000000000000000..a456c7e2b12d6279e55f6b340b874975e2681f5d
--- /dev/null
+++ b/src/CaptDeviceControl/controller/mp_AD2Capture/MPCaptDeviceSceleton.py
@@ -0,0 +1,7 @@
+class MPCaptDeviceSceleton():
+
+ def discover_connected_devices(self):
+ """
+ This function is called to discover the connected devices.
+ :return:
+ """
\ No newline at end of file
diff --git a/src/CaptDeviceControl/controller/mp_AD2Capture/__init__.py b/src/CaptDeviceControl/controller/mp_AD2Capture/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/CaptDeviceControl/model/AD2CaptDeviceModel.py b/src/CaptDeviceControl/model/AD2CaptDeviceModel.py
index 5a9c6bc1d3c47d8072ac0f2d993f9cc3b8f57433..7223d033aacb35de3a50c6978f9c0c3244e92d6c 100644
--- a/src/CaptDeviceControl/model/AD2CaptDeviceModel.py
+++ b/src/CaptDeviceControl/model/AD2CaptDeviceModel.py
@@ -1,12 +1,12 @@
-from ctypes import c_int, Array, c_byte
+from ctypes import c_int, Array
from PySide6.QtCore import QObject, Signal
from CaptDeviceControl.model.AD2Constants import AD2Constants
from CaptDeviceControl.CaptDeviceConfig import CaptDeviceConfig as Config
-from CaptDeviceControl.model.AD2CaptDeviceAnalogInModel import AD2CaptDeviceAnalogInModel
-from CaptDeviceControl.model.AD2CaptDeviceInformationModel import AD2CaptDeviceInformationSignals, \
- AD2CaptDeviceInformationModel
+from model.submodels.AD2CaptDeviceAnalogInModel import AD2CaptDeviceAnalogInModel
+from model.submodels.AD2CaptDeviceCapturingModel import AD2CaptDeviceCapturingModel
+from model.submodels.AD2CaptDeviceInformationModel import AD2CaptDeviceInformationModel
# from MeasurementData.Properties.AD2CaptDeviceProperties import AD2CaptDeviceProperties
@@ -16,6 +16,7 @@ class AD2CaptDeviceSignals(QObject):
def __init__(self, parent=None):
super().__init__(parent)
+
ad2captdev_config_changed = Signal(Config)
# WaveForms Runtime (DWF) Information
@@ -47,6 +48,8 @@ class AD2CaptDeviceSignals(QObject):
reset_recording_changed = Signal(bool)
capturing_finished_changed = Signal(bool)
+ device_state_changed = Signal(AD2Constants.DeviceState)
+
# Multiprocessing Information
pid_changed = Signal(int)
@@ -85,42 +88,24 @@ class AD2CaptDeviceModel:
def __init__(self, ad2captdev_config: Config):
self.signals = AD2CaptDeviceSignals()
self.ad2captdev_config = ad2captdev_config
+ self.ad2captdev_config.autosave(enable=True, path="./")
# WaveForms Runtime (DWF) Information
self._dwf_version: str = "Unknown"
+ # Multiprocessing Information
+ self._pid: int = 0
self.device_information = AD2CaptDeviceInformationModel()
self.analog_in = AD2CaptDeviceAnalogInModel(self.ad2captdev_config)
-
+ self.capturing_information = AD2CaptDeviceCapturingModel(self.ad2captdev_config)
# Acquisition Settings
- self._sample_rate: int = self.ad2captdev_config.sample_rate.value
- self._streaming_rate: int = self.ad2captdev_config.streaming_rate.value
-
- self._duration_streaming_history: float = 0
# Analog Out Information
self.aout_channels: list = []
- # Acquired Signal Information
- self._recorded_samples: list = []
- self._recording_time: float = 0
- self._samples_captured: int = 0
- self._samples_lost: int = 0
- self._samples_corrupted: int = 0
- self._capturing_finished: bool = False
- # Actually for the worker, these are the samples that have not been consumed yet by the UI thread.
- self._unconsumed_stream_samples: int = 0
- self._unconsumed_capture_samples: int = 0
- # Recording Flags (starting, stopping and pausing)
- self._device_capturing_state: AD2Constants.CapturingState = AD2Constants.CapturingState.STOPPED()
- self._start_recording = False
- self._stop_recording = True
- self._reset_recording = True
- # Multiprocessing Information
- self._pid: int = 0
# ==============================================================================================================
# Delete later
@@ -167,37 +152,8 @@ class AD2CaptDeviceModel:
self._dwf_version = value
self.signals.dwf_version_changed.emit(self.dwf_version)
- # ==================================================================================================================
- # Acquisition Settings
- # ==================================================================================================================
- @property
- def sample_rate(self):
- return self._sample_rate
-
- @sample_rate.setter
- def sample_rate(self, value):
- self._sample_rate = value
- self.ad2captdev_config.sample_rate.set(self._sample_rate)
- self.signals.sample_rate_changed.emit(self._sample_rate)
-
- @property
- def streaming_rate(self):
- return self._sample_rate
-
- @streaming_rate.setter
- def streaming_rate(self, value):
- self._streaming_rate = value
- self.ad2captdev_config.streaming_rate.set(self._streaming_rate)
- self.signals.streaming_rate_changed.emit(self._streaming_rate)
- @property
- def duration_streaming_history(self) -> float:
- return self._duration_streaming_history
- @duration_streaming_history.setter
- def duration_streaming_history(self, value: float):
- self._duration_streaming_history = value
- self.signals.duration_streaming_history_changed.emit(self.duration_streaming_history)
# ==================================================================================================================
# Analog Out Information
@@ -211,104 +167,6 @@ class AD2CaptDeviceModel:
self._aout_channels = value
self.signals.aout_channels_changed.emit(self.aout_channels)
- # ==================================================================================================================
- # Acquired Signal Information
- # ==================================================================================================================
- @property
- def recorded_samples(self) -> list:
- return self._recorded_samples
-
- @recorded_samples.setter
- def recorded_samples(self, value: list):
- self._recorded_samples = value
- self.samples_captured = len(self._recorded_samples)
- # self.signals.num_of_current_recorded_samples_changed.emit(self.num_of_current_recorded_samples)
- self.signals.recorded_samples_changed.emit(self.recorded_samples)
-
- @property
- def recording_time(self) -> float:
- return self._recording_time
-
- @recording_time.setter
- def recording_time(self, value: float):
- self._recording_time = value
- self.signals.recording_time_changed.emit(self.recording_time)
-
- @property
- def samples_captured(self) -> int:
- return self._samples_captured
-
- @samples_captured.setter
- def samples_captured(self, value: int):
- self._samples_captured = value
- self.signals.samples_captured_changed.emit(self.samples_captured)
-
- @property
- def samples_lost(self) -> int:
- return self._samples_lost
-
- @samples_lost.setter
- def samples_lost(self, value: int):
- self._samples_lost = value
- self.signals.samples_lost_changed.emit(self.samples_lost)
-
- @property
- def samples_corrupted(self) -> int:
- return self._samples_corrupted
-
- @samples_corrupted.setter
- def samples_corrupted(self, value: int):
- self._samples_corrupted = value
- self.signals.samples_corrupted_changed.emit(self.samples_corrupted)
-
- @property
- def capturing_finished(self) -> bool:
- return self._capturing_finished
-
- @capturing_finished.setter
- def capturing_finished(self, value: bool):
- self._capturing_finished = value
- print(f"Set _capturing_finished to {self._capturing_finished}")
- self.signals.capturing_finished_changed.emit(self._capturing_finished)
-
- # ==================================================================================================================
- # Recording Flags (starting, stopping and pausing)
- # ==================================================================================================================
- @property
- def device_capturing_state(self) -> AD2Constants.CapturingState:
- return self._device_capturing_state
-
- @device_capturing_state.setter
- def device_capturing_state(self, value: int):
- self._device_capturing_state = value
- self.signals.device_capturing_state_changed.emit(self.device_capturing_state)
-
- @property
- def start_recording(self) -> bool:
- return self._start_recording
-
- @start_recording.setter
- def start_recording(self, value: bool):
- self._start_recording = value
- self.signals.start_recording_changed.emit(self._start_recording)
-
- @property
- def stop_recording(self) -> bool:
- return self._stop_recording
-
- @stop_recording.setter
- def stop_recording(self, value: bool):
- self._stop_recording = value
- self.signals.stop_recording_changed.emit(self.stop_recording)
-
- @property
- def reset_recording(self):
- return self._reset_recording
-
- @reset_recording.setter
- def reset_recording(self, value):
- self._reset_recording = value
- self.signals.reset_recording_changed.emit(self._reset_recording)
# ==================================================================================================================
# Multiprocessing Flags
@@ -322,23 +180,18 @@ class AD2CaptDeviceModel:
self._pid = value
self.signals.pid_changed.emit(self.pid)
- @property
- def unconsumed_stream_samples(self) -> int:
- return self._unconsumed_stream_samples
- @unconsumed_stream_samples.setter
- def unconsumed_stream_samples(self, value: int):
- self._unconsumed_stream_samples = value
- self.signals.unconsumed_stream_samples_changed.emit(self.unconsumed_stream_samples)
@property
- def unconsumed_capture_samples(self) -> int:
- return self._unconsumed_capture_samples
+ def device_state(self) -> AD2Constants.DeviceState:
+ return self._device_state
+
+ @device_state.setter
+ def device_state(self, value: AD2Constants.DeviceState):
+ #print(f"Set device_state to {value}")
+ self._device_state = value
+ self.signals.device_state_changed.emit(self._device_state)
- @unconsumed_capture_samples.setter
- def unconsumed_capture_samples(self, value: int):
- self._unconsumed_capture_samples = value
- self.signals.unconsumed_capture_samples_changed.emit(self.unconsumed_capture_samples)
# ==================================================================================================================
# ==================================================================================================================
diff --git a/src/CaptDeviceControl/model/AD2CaptDeviceProperties.py b/src/CaptDeviceControl/model/AD2CaptDeviceProperties.py
index 251327b339915b9bca80ba782ed9c6a6ec1b1ede..09a54b839c829753e6b14ad93f19f14709be62a7 100644
--- a/src/CaptDeviceControl/model/AD2CaptDeviceProperties.py
+++ b/src/CaptDeviceControl/model/AD2CaptDeviceProperties.py
@@ -7,6 +7,7 @@ class AD2CaptDeviceProperties(GenericProperties):
measurement_time: float):
super().__init__()
# Laser properties
+
self._samples_lost: float = self.to_float(samples_lost)
self._samples_currputed: float = self.to_float(samples_currputed)
self._sample_rate: float = self.to_float(acquisition_rate)
diff --git a/src/CaptDeviceControl/model/AD2CaptDeviceSignals.py b/src/CaptDeviceControl/model/AD2CaptDeviceSignals.py
index 81f119f75525d46bf37bfaddff45d65e97a7399b..fad77f2290b7065d725d6d2ac800d7ae396a0a0a 100644
--- a/src/CaptDeviceControl/model/AD2CaptDeviceSignals.py
+++ b/src/CaptDeviceControl/model/AD2CaptDeviceSignals.py
@@ -19,6 +19,8 @@ class AD2CaptDeviceSignals(QObject):
# WaveForms Runtime (DWF) Information
dwf_version_changed = Signal(str)
+ # Multiprocessing Information
+ pid_changed = Signal(int)
# Connected Device Information
num_of_discovered_devices_changed = Signal(int)
@@ -31,11 +33,6 @@ class AD2CaptDeviceSignals(QObject):
serial_number_changed = Signal(str)
device_index_changed = Signal(int)
- # Acquisition Settings
- sample_rate_changed = Signal(int)
- streaming_rate_changed = Signal(int)
- selected_ain_channel_changed = Signal(int)
- duration_streaming_history_changed = Signal(int)
# Analog In Information
ain_channels_changed = Signal(list)
@@ -46,51 +43,7 @@ class AD2CaptDeviceSignals(QObject):
# Analog Out Information
aout_channels_changed = Signal(list)
- # Acquired Signal Information
- recorded_samples_changed = Signal(list)
- recording_time_changed = Signal(float)
- samples_captured_changed = Signal(int)
- samples_lost_changed = Signal(int)
- samples_corrupted_changed = Signal(int)
- # Actually for the worker, these are the samples that have not been consumed yet by the UI thread.
- unconsumed_stream_samples_changed = Signal(int)
- unconsumed_capture_samples_changed = Signal(int)
-
- # Recording Flags (starting, stopping and pausing)
- device_capturing_state_changed = Signal(AD2Constants.CapturingState)
- start_recording_changed = Signal(bool)
- stop_recording_changed = Signal(bool)
- reset_recording_changed = Signal(bool)
- capturing_finished_changed = Signal(bool)
-
- # Multiprocessing Information
- pid_changed = Signal(int)
-
- # ==================================================================================================================
- # Delete later
- # Signals for device information
- hwdf_changed = Signal(int)
-
- device_ready_changed = Signal(bool)
-
- # Signals for reporting if samples were lost or corrupted
- fLost_changed = Signal(int)
- fCorrupted_changed = Signal(int)
- # Acquisition information
-
- n_samples_changed = Signal(int)
-
- # Recording settings for starting, stopping and pausing
- # Signal if new samples have been aquired
- all_recorded_samples_changed = Signal(list)
- num_of_current_recorded_samples_changed = Signal(int)
- measurement_time_changed = Signal(float)
- ad2_settings = Signal(dict)
- error = Signal(str)
- ad2_is_capturing = Signal(bool)
- ad2_set_acquisition = Signal(bool)
- ad2_captured_value = Signal(list)
diff --git a/src/CaptDeviceControl/model/AD2Constants.py b/src/CaptDeviceControl/model/AD2Constants.py
index a534f0d6fab671aa746a38d589b3ae5523bad326..575d9926551585ae6971e669ff31451d6a41b6ae 100644
--- a/src/CaptDeviceControl/model/AD2Constants.py
+++ b/src/CaptDeviceControl/model/AD2Constants.py
@@ -8,13 +8,45 @@ class AD2Constants:
return 1
@staticmethod
- def PAUSED(description: bool= False):
+ def PAUSED(description: bool = False):
if description:
return "Capturing paused"
return 2
@staticmethod
- def STOPPED(description: bool= False):
+ def STOPPED(description: bool = False):
if description:
return "Capturing stopped"
return 3
+
+ class DeviceState():
+
+ @staticmethod
+ def ACQ_NOT_STARTED(description: bool = False):
+ if description:
+ return "Acquisition not started"
+ return 4
+
+ @staticmethod
+ def DEV_CAPT_SETUP(description: bool = False):
+ if description:
+ return "Device setting up"
+ return 5
+
+ @staticmethod
+ def DEV_CAPT_STREAMING(description: bool = False):
+ if description:
+ return "Device streaming"
+ return 6
+
+ @staticmethod
+ def NO_SAMPLES_AVAILABLE(description: bool = False):
+ if description:
+ return "No samples available"
+ return 7
+
+ @staticmethod
+ def SAMPLES_AVAILABLE(description: bool = False):
+ if description:
+ return "Samples streaming"
+ return 8
diff --git a/src/CaptDeviceControl/model/AD2CaptDeviceAnalogInModel.py b/src/CaptDeviceControl/model/submodels/AD2CaptDeviceAnalogInModel.py
similarity index 100%
rename from src/CaptDeviceControl/model/AD2CaptDeviceAnalogInModel.py
rename to src/CaptDeviceControl/model/submodels/AD2CaptDeviceAnalogInModel.py
diff --git a/src/CaptDeviceControl/model/submodels/AD2CaptDeviceCapturingModel.py b/src/CaptDeviceControl/model/submodels/AD2CaptDeviceCapturingModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d32e92b6b86df82f77d04261d3016ade5eed4b3
--- /dev/null
+++ b/src/CaptDeviceControl/model/submodels/AD2CaptDeviceCapturingModel.py
@@ -0,0 +1,216 @@
+from ctypes import c_int, Array
+
+from PySide6.QtCore import QObject, Signal
+
+from CaptDeviceConfig import CaptDeviceConfig
+from model.AD2Constants import AD2Constants
+
+
+class AD2CaptDeviceCapturingSignals(QObject):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ # Acquisition Settings
+ sample_rate_changed = Signal(int)
+ streaming_rate_changed = Signal(int)
+ selected_ain_channel_changed = Signal(int)
+ streaming_history_changed = Signal(int)
+ # Acquired Signal Information
+ recorded_samples_changed = Signal(list)
+ recording_time_changed = Signal(float)
+ samples_captured_changed = Signal(int)
+ samples_lost_changed = Signal(int)
+ samples_corrupted_changed = Signal(int)
+ # Actually for the worker, these are the samples that have not been consumed yet by the UI thread.
+ unconsumed_stream_samples_changed = Signal(int)
+ unconsumed_capture_samples_changed = Signal(int)
+
+ # Recording Flags (starting, stopping and pausing)
+ device_capturing_state_changed = Signal(AD2Constants.CapturingState)
+ start_recording_changed = Signal(bool)
+ stop_recording_changed = Signal(bool)
+ reset_recording_changed = Signal(bool)
+ capturing_finished_changed = Signal(bool)
+
+class AD2CaptDeviceCapturingModel:
+ def __init__(self, config: CaptDeviceConfig):
+ self.signals = AD2CaptDeviceCapturingSignals()
+ self.config = config
+
+ # Acquired Signal Information
+ # The number of recorded samples
+ self._recorded_samples: list = []
+ # The length of the recording
+ self._recording_time: float = 0
+
+ # Number of the captured, lost and corrupted samples
+ self._number_samples_captured: int = 0
+ self._number_samples_lost: int = 0
+ self._number_samples_corrupted: int = 0
+
+ # Flag if the capturing is finished
+ self._capturing_finished: bool = False
+
+ # Actually for the worker, these are the samples that have not been consumed yet by the UI thread.
+ self._unconsumed_stream_samples: int = 0
+ self._unconsumed_capture_samples: int = 0
+
+ # Recording Flags (starting, stopping and pausing)
+ self._device_capturing_state: AD2Constants.CapturingState = AD2Constants.CapturingState.STOPPED()
+ self._start_recording = False
+ self._stop_recording = True
+ self._reset_recording = True
+
+# ==================================================================================================================
+ # Acquired Signal Information
+ # ==================================================================================================================
+ @property
+ def recorded_samples(self) -> list:
+ return self._recorded_samples
+
+ @recorded_samples.setter
+ def recorded_samples(self, value: list):
+ self._recorded_samples = value
+ self.samples_captured = len(self._recorded_samples)
+ # self.signals.num_of_current_recorded_samples_changed.emit(self.num_of_current_recorded_samples)
+ self.signals.recorded_samples_changed.emit(self.recorded_samples)
+
+ @property
+ def recording_time(self) -> float:
+ return self._recording_time
+
+ @recording_time.setter
+ def recording_time(self, value: float):
+ self._recording_time = value
+ self.signals.recording_time_changed.emit(self.recording_time)
+
+ @property
+ def samples_captured(self) -> int:
+ return self._samples_captured
+
+ @samples_captured.setter
+ def samples_captured(self, value: int):
+ self._samples_captured = value
+ self.signals.samples_captured_changed.emit(self.samples_captured)
+
+ @property
+ def samples_lost(self) -> int:
+ return self._samples_lost
+
+ @samples_lost.setter
+ def samples_lost(self, value: int):
+ self._samples_lost = value
+ self.signals.samples_lost_changed.emit(self.samples_lost)
+
+ @property
+ def samples_corrupted(self) -> int:
+ return self._samples_corrupted
+
+ @samples_corrupted.setter
+ def samples_corrupted(self, value: int):
+ self._samples_corrupted = value
+ self.signals.samples_corrupted_changed.emit(self.samples_corrupted)
+
+ @property
+ def capturing_finished(self) -> bool:
+ return self._capturing_finished
+
+ @capturing_finished.setter
+ def capturing_finished(self, value: bool):
+ self._capturing_finished = value
+ #print(f"Set _capturing_finished to {self._capturing_finished}")
+ self.signals.capturing_finished_changed.emit(self._capturing_finished)
+
+ # ==================================================================================================================
+ # Recording Flags (starting, stopping and pausing)
+ # ==================================================================================================================
+ @property
+ def device_capturing_state(self) -> AD2Constants.CapturingState:
+ return self._device_capturing_state
+
+ @device_capturing_state.setter
+ def device_capturing_state(self, value: int):
+ #print(f"Set device_capturing_state to {value}")
+ self._device_capturing_state = value
+ self.signals.device_capturing_state_changed.emit(self.device_capturing_state)
+
+ @property
+ def start_recording(self) -> bool:
+ return self._start_recording
+
+ @start_recording.setter
+ def start_recording(self, value: bool):
+ self._start_recording = value
+ self.signals.start_recording_changed.emit(self._start_recording)
+
+ @property
+ def stop_recording(self) -> bool:
+ return self._stop_recording
+
+ @stop_recording.setter
+ def stop_recording(self, value: bool):
+ self._stop_recording = value
+ self.signals.stop_recording_changed.emit(self.stop_recording)
+
+ @property
+ def reset_recording(self):
+ return self._reset_recording
+
+ @reset_recording.setter
+ def reset_recording(self, value):
+ self._reset_recording = value
+ self.signals.reset_recording_changed.emit(self._reset_recording)
+
+ @property
+ def unconsumed_stream_samples(self) -> int:
+ return self._unconsumed_stream_samples
+
+ @unconsumed_stream_samples.setter
+ def unconsumed_stream_samples(self, value: int):
+ self._unconsumed_stream_samples = value
+ self.signals.unconsumed_stream_samples_changed.emit(self.unconsumed_stream_samples)
+
+ @property
+ def unconsumed_capture_samples(self) -> int:
+ return self._unconsumed_capture_samples
+
+ @unconsumed_capture_samples.setter
+ def unconsumed_capture_samples(self, value: int):
+ self._unconsumed_capture_samples = value
+ self.signals.unconsumed_capture_samples_changed.emit(self.unconsumed_capture_samples)
+
+
+ @property
+ def streaming_history(self) -> float:
+ return self.config.streaming_history.get()
+
+ @streaming_history.setter
+ def streaming_history(self, value: float):
+ self.config.streaming_history.set(value)
+ self.signals.streaming_history_changed.emit(self.streaming_history)
+
+ @property
+ def streaming_rate(self):
+ return self.config.streaming_rate.get()
+
+ @streaming_rate.setter
+ def streaming_rate(self, value):
+ self.config.streaming_rate.set(value)
+ self.signals.streaming_rate_changed.emit(self.streaming_rate)
+
+ @property
+ def streaming_deque_length(self):
+ return int((self.streaming_history / 1000) * self.sample_rate)
+
+ # ==================================================================================================================
+ # Acquisition Settings
+ # ==================================================================================================================
+ @property
+ def sample_rate(self):
+ return self.config.sample_rate.get()
+
+ @sample_rate.setter
+ def sample_rate(self, value):
+ self.config.sample_rate.set(self.value)
+ self.signals.sample_rate_changed.emit(self.sample_rate)
+
diff --git a/src/CaptDeviceControl/model/AD2CaptDeviceInformationModel.py b/src/CaptDeviceControl/model/submodels/AD2CaptDeviceInformationModel.py
similarity index 89%
rename from src/CaptDeviceControl/model/AD2CaptDeviceInformationModel.py
rename to src/CaptDeviceControl/model/submodels/AD2CaptDeviceInformationModel.py
index 0e0734369f20745e1b067661b5cc2b75cc969280..d3668721a3d9cf04ab8b376029a812115d2095bb 100644
--- a/src/CaptDeviceControl/model/AD2CaptDeviceInformationModel.py
+++ b/src/CaptDeviceControl/model/submodels/AD2CaptDeviceInformationModel.py
@@ -2,11 +2,14 @@ from ctypes import c_int, Array
from PySide6.QtCore import QObject, Signal
+from model.AD2Constants import AD2Constants
+
class AD2CaptDeviceInformationSignals(QObject):
def __init__(self, parent=None):
super().__init__(parent)
+
# Connected Device Information
num_of_connected_devices_changed = Signal(int)
connected_devices_changed = Signal(list)
@@ -17,6 +20,7 @@ class AD2CaptDeviceInformationSignals(QObject):
device_name_changed = Signal(str)
device_serial_number_changed = Signal(str)
device_index_changed = Signal(int)
+ device_state_changed = Signal(AD2Constants.DeviceState)
class AD2CaptDeviceInformationModel:
@@ -32,6 +36,7 @@ class AD2CaptDeviceInformationModel:
self._device_connected: bool = False
self._device_name: str = "Unknown"
self._device_serial_number: str = "Unknown"
+ self._device_state: AD2Constants.DeviceState = AD2Constants.DeviceState.ACQ_NOT_STARTED()
# ==================================================================================================================
# Connected Device Information
@@ -115,3 +120,12 @@ class AD2CaptDeviceInformationModel:
else:
self._device_index = int(value)
self.signals.device_serial_number_changed.emit(self.device_index)
+
+ @property
+ def device_state(self) -> AD2Constants.DeviceState:
+ return self._device_state
+
+ @device_state.setter
+ def device_state(self, value: AD2Constants.DeviceState):
+ self._device_state = value
+ self.signals.device_state_changed.emit(self.device_state)
diff --git a/src/CaptDeviceControl/model/submodels/__init__.py b/src/CaptDeviceControl/model/submodels/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/CaptDeviceControl/resources/resources.qrc b/src/CaptDeviceControl/resources/resources.qrc
index 45317f091765e81669b48dca86b1e91fcd0f1ac5..8f4b0d10c0437c79298cb18d2e317f2f184e10dc 100644
--- a/src/CaptDeviceControl/resources/resources.qrc
+++ b/src/CaptDeviceControl/resources/resources.qrc
@@ -1,5 +1,6 @@
<RCC>
<qresource prefix="icons">
+ <file>icons/cil-record.png</file>
<file>icons/cil-airplane-mode-off.png</file>
<file>icons/cil-alarm.png</file>
<file>icons/cil-align-left.png</file>
@@ -258,4 +259,11 @@
<file>icons/cil-input.png</file>
<file>icons/cil-pen-alt.png</file>
</qresource>
+ <qresource prefix="icons-svg">
+ <file>icons-svg/cil-reload.svg</file>
+ <file>icons-svg/cil-media-record.svg</file>
+ <file>icons-svg/cil-media-pause.svg</file>
+ <file>icons-svg/cil-media-stop.svg</file>
+ <file>icons-svg/cil-media-play.svg</file>
+ </qresource>
</RCC>
diff --git a/src/CaptDeviceControl/resources_rc.py b/src/CaptDeviceControl/resources_rc.py
index 53c16bfe87666f60d472be235f2aaf5d152204c3..65554a6403aa52c26b1afce89f503cabc95eda51 100644
--- a/src/CaptDeviceControl/resources_rc.py
+++ b/src/CaptDeviceControl/resources_rc.py
@@ -1,11 +1,886 @@
# Resource object code (Python 3)
# Created by: object code
-# Created by: The Resource Compiler for Qt version 6.5.3
+# Created by: The Resource Compiler for Qt version 6.6.1
# WARNING! All changes made in this file will be lost!
from PySide6 import QtCore
qt_resource_data = b"\
+\x00\x00\x0c\xf5\
+<\
+?xml version=\x221.\
+0\x22 encoding=\x22utf\
+-8\x22?>\x0d\x0a<!-- Gene\
+rator: Adobe Ill\
+ustrator 24.1.2,\
+ SVG Export Plug\
+-In . SVG Versio\
+n: 6.00 Build 0)\
+ -->\x0d\x0a<svg vers\
+ion=\x221.1\x22 id=\x22Eb\
+ene_1\x22 xmlns=\x22ht\
+tp://www.w3.org/\
+2000/svg\x22 xmlns:\
+xlink=\x22http://ww\
+w.w3.org/1999/xl\
+ink\x22 x=\x220px\x22 y=\x22\
+0px\x22\x0d\x0a\x09 viewBox=\
+\x220 0 16 16\x22 styl\
+e=\x22enable-backgr\
+ound:new 0 0 16 \
+16;\x22 xml:space=\x22\
+preserve\x22>\x0d\x0a<sty\
+le type=\x22text/cs\
+s\x22>\x0d\x0a\x09.st0{fill:\
+#B70000;stroke:#\
+B70000;stroke-wi\
+dth:0.875;stroke\
+-miterlimit:10;}\
+\x0d\x0a</style>\x0d\x0a<ima\
+ge style=\x22displa\
+y:none;overflow:\
+visible;\x22 width=\
+\x2216\x22 height=\x2216\x22\
+ xlink:href=\x22dat\
+a:image/png;base\
+64,iVBORw0KGgoAA\
+AANSUhEUgAAABAAA\
+AAQCAYAAAAf8/9hA\
+AAACXBIWXMAAAsTA\
+AALEwEAmpwYAAAG\x0d\
+\x0avmlUWHRYTUw6Y29\
+tLmFkb2JlLnhtcAA\
+AAAAAPD94cGFja2V\
+0IGJlZ2luPSLvu78\
+iIGlkPSJXNU0w\x0d\x0aT\
+XBDZWhpSHpyZVN6T\
+lRjemtjOWQiPz4gP\
+Hg6eG1wbWV0YSB4b\
+Wxuczp4PSJhZG9iZ\
+TpuczptZXRh\x0d\x0aLyI\
+geDp4bXB0az0iQWR\
+vYmUgWE1QIENvcmU\
+gNi4wLWMwMDIgNzk\
+uMTY0MzYwLCAyMDI\
+wLzAyLzEz\x0d\x0aLTAxO\
+jA3OjIyICAgICAgI\
+CAiPiA8cmRmOlJER\
+iB4bWxuczpyZGY9I\
+mh0dHA6Ly93d3cud\
+zMub3Jn\x0d\x0aLzE5OTk\
+vMDIvMjItcmRmLXN\
+5bnRheC1ucyMiPiA\
+8cmRmOkRlc2NyaXB\
+0aW9uIHJkZjphYm9\
+1dD0i\x0d\x0aIiB4bWxuc\
+zp4bXA9Imh0dHA6L\
+y9ucy5hZG9iZS5jb\
+20veGFwLzEuMC8iI\
+HhtbG5zOmRjPSJod\
+HRw\x0d\x0aOi8vcHVybC5\
+vcmcvZGMvZWxlbWV\
+udHMvMS4xLyIgeG1\
+sbnM6cGhvdG9zaG9\
+wPSJodHRwOi8vbnM\
+u\x0d\x0aYWRvYmUuY29tL\
+3Bob3Rvc2hvcC8xL\
+jAvIiB4bWxuczp4b\
+XBNTT0iaHR0cDovL\
+25zLmFkb2JlLmNv\x0d\
+\x0abS94YXAvMS4wL21\
+tLyIgeG1sbnM6c3R\
+FdnQ9Imh0dHA6Ly9\
+ucy5hZG9iZS5jb20\
+veGFwLzEuMC9z\x0d\x0aV\
+HlwZS9SZXNvdXJjZ\
+UV2ZW50IyIgeG1wO\
+kNyZWF0b3JUb29sP\
+SJBZG9iZSBQaG90b\
+3Nob3AgMjEu\x0d\x0aMCA\
+oV2luZG93cykiIHh\
+tcDpDcmVhdGVEYXR\
+lPSIyMDIwLTAzLTA\
+zVDA5OjUwOjM5LTA\
+zOjAwIiB4\x0d\x0abXA6T\
+W9kaWZ5RGF0ZT0iM\
+jAyMy0xMi0xOVQxM\
+jozMjoxMyswMTowM\
+CIgeG1wOk1ldGFkY\
+XRhRGF0\x0d\x0aZT0iMjA\
+yMy0xMi0xOVQxMjo\
+zMjoxMyswMTowMCI\
+gZGM6Zm9ybWF0PSJ\
+pbWFnZS9wbmciIHB\
+ob3Rv\x0d\x0ac2hvcDpDb\
+2xvck1vZGU9IjMiI\
+HBob3Rvc2hvcDpJQ\
+0NQcm9maWxlPSJzU\
+kdCIElFQzYxOTY2L\
+TIu\x0d\x0aMSIgeG1wTU0\
+6SW5zdGFuY2VJRD0\
+ieG1wLmlpZDo2ZmQ\
+3OTdlNi02ZmY0LTl\
+hNDQtOTU1Ny02Nzk\
+5\x0d\x0aZmU4OGJlZjkiI\
+HhtcE1NOkRvY3VtZ\
+W50SUQ9ImFkb2JlO\
+mRvY2lkOnBob3Rvc\
+2hvcDo2Zjk3ZDcx\x0d\
+\x0aOS01M2RlLTZlNDU\
+tOGZmNS0wNjI5NGY\
+0Y2I3MWIiIHhtcE1\
+NOk9yaWdpbmFsRG9\
+jdW1lbnRJRD0i\x0d\x0ae\
+G1wLmRpZDpkZDVkM\
+2EzZS1hMDQ2LTUxN\
+DYtOGU3YS0xNGI2M\
+mVlYjM1MGQiPiA8e\
+G1wTU06SGlz\x0d\x0adG9\
+yeT4gPHJkZjpTZXE\
++IDxyZGY6bGkgc3R\
+FdnQ6YWN0aW9uPSJ\
+jcmVhdGVkIiBzdEV\
+2dDppbnN0\x0d\x0aYW5jZ\
+UlEPSJ4bXAuaWlkO\
+mRkNWQzYTNlLWEwN\
+DYtNTE0Ni04ZTdhL\
+TE0YjYyZWViMzUwZ\
+CIgc3RF\x0d\x0adnQ6d2h\
+lbj0iMjAyMC0wMy0\
+wM1QwOTo1MDozOS0\
+wMzowMCIgc3RFdnQ\
+6c29mdHdhcmVBZ2V\
+udD0i\x0d\x0aQWRvYmUgU\
+GhvdG9zaG9wIDIxL\
+jAgKFdpbmRvd3MpI\
+i8+IDxyZGY6bGkgc\
+3RFdnQ6YWN0aW9uP\
+SJz\x0d\x0aYXZlZCIgc3R\
+FdnQ6aW5zdGFuY2V\
+JRD0ieG1wLmlpZDp\
+jYTk4ZDRkYS03YmY\
+zLWYyNDMtODIyOC1\
+j\x0d\x0aOWI5YjI4ZWZlM\
+GIiIHN0RXZ0OndoZ\
+W49IjIwMjAtMDUtM\
+DJUMTc6NTg6MjUtM\
+DM6MDAiIHN0RXZ0\x0d\
+\x0aOnNvZnR3YXJlQWd\
+lbnQ9IkFkb2JlIFB\
+ob3Rvc2hvcCAyMS4\
+wIChXaW5kb3dzKSI\
+gc3RFdnQ6Y2hh\x0d\x0ab\
+mdlZD0iLyIvPiA8c\
+mRmOmxpIHN0RXZ0O\
+mFjdGlvbj0ic2F2Z\
+WQiIHN0RXZ0Omluc\
+3RhbmNlSUQ9\x0d\x0aInh\
+tcC5paWQ6NmZkNzk\
+3ZTYtNmZmNC05YTQ\
+0LTk1NTctNjc5OWZ\
+lODhiZWY5IiBzdEV\
+2dDp3aGVu\x0d\x0aPSIyM\
+DIzLTEyLTE5VDEyO\
+jMyOjEzKzAxOjAwI\
+iBzdEV2dDpzb2Z0d\
+2FyZUFnZW50PSJBZ\
+G9iZSBQ\x0d\x0aaG90b3N\
+ob3AgMjEuMSAoV2l\
+uZG93cykiIHN0RXZ\
+0OmNoYW5nZWQ9Ii8\
+iLz4gPC9yZGY6U2V\
+xPiA8\x0d\x0aL3htcE1NO\
+khpc3Rvcnk+IDwvc\
+mRmOkRlc2NyaXB0a\
+W9uPiA8L3JkZjpSR\
+EY+IDwveDp4bXBtZ\
+XRh\x0d\x0aPiA8P3hwYWN\
+rZXQgZW5kPSJyIj8\
++h4q0ZgAAAJVJREF\
+UOMutk0EKgzAQRWc\
+l9Cqas9YsDPQupbc\
+o\x0d\x0a6j10YcRi/8BEw\
+oAFM128RZL5DzKZ0\
+E5EihrcwQAWoZe9W\
+tfniwp04AP2E/jsA\
+W5awOHnj6DmJZlD\x0d\
+\x0aEC6EE10SNGArEHC\
+mYUFbEE60JN0uFQw\
+siAZBtAom6xXe1iZ\
+6FjjDMzrLIIW/jrL\
+5M+XwaHswghXM\x0d\x0a3\
+G3Zc7r+C1ipxmHV0\
+UIdAAAAAElFTkSuQ\
+mCC\x22>\x0d\x0a</image>\x0d\
+\x0a<circle class=\x22\
+st0\x22 cx=\x228\x22 cy=\x22\
+8\x22 r=\x227\x22/>\x0d\x0a</sv\
+g>\x0d\x0a\
+\x00\x00\x0c\x1f\
+<\
+?xml version=\x221.\
+0\x22 encoding=\x22utf\
+-8\x22?>\x0d\x0a<!-- Gene\
+rator: Adobe Ill\
+ustrator 24.1.2,\
+ SVG Export Plug\
+-In . SVG Versio\
+n: 6.00 Build 0)\
+ -->\x0d\x0a<svg vers\
+ion=\x221.1\x22 id=\x22Eb\
+ene_1\x22 xmlns=\x22ht\
+tp://www.w3.org/\
+2000/svg\x22 xmlns:\
+xlink=\x22http://ww\
+w.w3.org/1999/xl\
+ink\x22 x=\x220px\x22 y=\x22\
+0px\x22\x0d\x0a\x09 viewBox=\
+\x220 0 16 16\x22 styl\
+e=\x22enable-backgr\
+ound:new 0 0 16 \
+16;\x22 xml:space=\x22\
+preserve\x22>\x0d\x0a<sty\
+le type=\x22text/cs\
+s\x22>\x0d\x0a\x09.st0{fill:\
+none;stroke:#FF0\
+000;stroke-width\
+:2;stroke-miterl\
+imit:10;}\x0d\x0a</sty\
+le>\x0d\x0a<image styl\
+e=\x22display:none;\
+overflow:visible\
+;\x22 width=\x2216\x22 he\
+ight=\x2216\x22 xlink:\
+href=\x22data:image\
+/png;base64,iVBO\
+Rw0KGgoAAAANSUhE\
+UgAAABAAAAAQCAYA\
+AAAf8/9hAAAACXBI\
+WXMAAAsTAAALEwEA\
+mpwYAAAF\x0d\x0a8WlUWH\
+RYTUw6Y29tLmFkb2\
+JlLnhtcAAAAAAAPD\
+94cGFja2V0IGJlZ2\
+luPSLvu78iIGlkPS\
+JXNU0w\x0d\x0aTXBDZWhp\
+SHpyZVN6TlRjemtj\
+OWQiPz4gPHg6eG1w\
+bWV0YSB4bWxuczp4\
+PSJhZG9iZTpuczpt\
+ZXRh\x0d\x0aLyIgeDp4bX\
+B0az0iQWRvYmUgWE\
+1QIENvcmUgNS42LW\
+MxNDggNzkuMTY0MD\
+M2LCAyMDE5LzA4Lz\
+Ez\x0d\x0aLTAxOjA2OjU3\
+ICAgICAgICAiPiA8\
+cmRmOlJERiB4bWxu\
+czpyZGY9Imh0dHA6\
+Ly93d3cudzMub3Jn\
+\x0d\x0aLzE5OTkvMDIvMj\
+ItcmRmLXN5bnRheC\
+1ucyMiPiA8cmRmOk\
+Rlc2NyaXB0aW9uIH\
+JkZjphYm91dD0i\x0d\x0a\
+IiB4bWxuczp4bXA9\
+Imh0dHA6Ly9ucy5h\
+ZG9iZS5jb20veGFw\
+LzEuMC8iIHhtbG5z\
+OmRjPSJodHRw\x0d\x0aOi\
+8vcHVybC5vcmcvZG\
+MvZWxlbWVudHMvMS\
+4xLyIgeG1sbnM6cG\
+hvdG9zaG9wPSJodH\
+RwOi8vbnMu\x0d\x0aYWRv\
+YmUuY29tL3Bob3Rv\
+c2hvcC8xLjAvIiB4\
+bWxuczp4bXBNTT0i\
+aHR0cDovL25zLmFk\
+b2JlLmNv\x0d\x0abS94YX\
+AvMS4wL21tLyIgeG\
+1sbnM6c3RFdnQ9Im\
+h0dHA6Ly9ucy5hZG\
+9iZS5jb20veGFwLz\
+EuMC9z\x0d\x0aVHlwZS9S\
+ZXNvdXJjZUV2ZW50\
+IyIgeG1wOkNyZWF0\
+b3JUb29sPSJBZG9i\
+ZSBQaG90b3Nob3Ag\
+MjEu\x0d\x0aMCAoV2luZG\
+93cykiIHhtcDpDcm\
+VhdGVEYXRlPSIyMD\
+IwLTAzLTAzVDA5Oj\
+UwOjQxLTAzOjAwIi\
+B4\x0d\x0abXA6TW9kaWZ5\
+RGF0ZT0iMjAyMC0w\
+NS0wMlQxNzo1OTox\
+Ny0wMzowMCIgeG1w\
+Ok1ldGFkYXRhRGF0\
+\x0d\x0aZT0iMjAyMC0wNS\
+0wMlQxNzo1OToxNy\
+0wMzowMCIgZGM6Zm\
+9ybWF0PSJpbWFnZS\
+9wbmciIHBob3Rv\x0d\x0a\
+c2hvcDpDb2xvck1v\
+ZGU9IjMiIHBob3Rv\
+c2hvcDpJQ0NQcm9m\
+aWxlPSJzUkdCIElF\
+QzYxOTY2LTIu\x0d\x0aMS\
+IgeG1wTU06SW5zdG\
+FuY2VJRD0ieG1wLm\
+lpZDoyYWE1NDM0YS\
+04MDgyLTI5NGYtYW\
+I2OC1kZWNk\x0d\x0aYWY2\
+NjUzMWIiIHhtcE1N\
+OkRvY3VtZW50SUQ9\
+ImFkb2JlOmRvY2lk\
+OnBob3Rvc2hvcDo3\
+MGNiMzhj\x0d\x0aMy02NT\
+VhLTg3NDUtYTYyZi\
+00MWZjN2RmZDdjMT\
+UiIHhtcE1NOk9yaW\
+dpbmFsRG9jdW1lbn\
+RJRD0i\x0d\x0aeG1wLmRp\
+ZDo2OTUyZjdmMS1l\
+MmI4LWQxNDMtODkz\
+Ni01MjE1M2E3NDRk\
+YjUiPiA8eG1wTU06\
+SGlz\x0d\x0adG9yeT4gPH\
+JkZjpTZXE+IDxyZG\
+Y6bGkgc3RFdnQ6YW\
+N0aW9uPSJjcmVhdG\
+VkIiBzdEV2dDppbn\
+N0\x0d\x0aYW5jZUlEPSJ4\
+bXAuaWlkOjY5NTJm\
+N2YxLWUyYjgtZDE0\
+My04OTM2LTUyMTUz\
+YTc0NGRiNSIgc3RF\
+\x0d\x0adnQ6d2hlbj0iMj\
+AyMC0wMy0wM1QwOT\
+o1MDo0MS0wMzowMC\
+Igc3RFdnQ6c29mdH\
+dhcmVBZ2VudD0i\x0d\x0a\
+QWRvYmUgUGhvdG9z\
+aG9wIDIxLjAgKFdp\
+bmRvd3MpIi8+IDxy\
+ZGY6bGkgc3RFdnQ6\
+YWN0aW9uPSJz\x0d\x0aYX\
+ZlZCIgc3RFdnQ6aW\
+5zdGFuY2VJRD0ieG\
+1wLmlpZDoyYWE1ND\
+M0YS04MDgyLTI5NG\
+YtYWI2OC1k\x0d\x0aZWNk\
+YWY2NjUzMWIiIHN0\
+RXZ0OndoZW49IjIw\
+MjAtMDUtMDJUMTc6\
+NTk6MTctMDM6MDAi\
+IHN0RXZ0\x0d\x0aOnNvZn\
+R3YXJlQWdlbnQ9Ik\
+Fkb2JlIFBob3Rvc2\
+hvcCAyMS4wIChXaW\
+5kb3dzKSIgc3RFdn\
+Q6Y2hh\x0d\x0abmdlZD0i\
+LyIvPiA8L3JkZjpT\
+ZXE+IDwveG1wTU06\
+SGlzdG9yeT4gPC9y\
+ZGY6RGVzY3JpcHRp\
+b24+\x0d\x0aIDwvcmRmOl\
+JERj4gPC94OnhtcG\
+1ldGE+IDw/eHBhY2\
+tldCBlbmQ9InIiPz\
+5YgjJvAAAAvUlEQV\
+Q4\x0d\x0ay9XTQQrCMBAF\
+0DR14y08UkHciCCK\
+tXouRUStot6n7nIA\
+T+AfmJRPSDWIGxcP\
+BtL+TqdT45wzKlNc\
+\x0d\x0ah+TMUm0MBXzFUF\
+oBd6jh3OECWxj4Tj\
+ngCjeYwBoqslIzaG\
+DuX4cDjjBOaFs6KG\
+MBJ1hq3dNhsVzP\x0d\x0a\
+6ncBJU06fHL0uv8J\
+yFID/BDzyBbaT0OU\
+g2nCZ9zrbrQBPnkD\
+D9jpxoUbKA7whGGs\
+A1nPhW5c1UE2\x0d\x0adA\
+T9n/5MPGmbqL3vBV\
+WG3M95a5ACAAAAAE\
+lFTkSuQmCC\x22>\x0d\x0a</\
+image>\x0d\x0a<rect x=\
+\x221.96\x22 y=\x222.01\x22 \
+class=\x22st0\x22 widt\
+h=\x2212\x22 height=\x221\
+2\x22/>\x0d\x0a</svg>\x0d\x0a\
+\x00\x00\x0d\x8d\
+<\
+?xml version=\x221.\
+0\x22 encoding=\x22utf\
+-8\x22?>\x0d\x0a<!-- Gene\
+rator: Adobe Ill\
+ustrator 24.1.2,\
+ SVG Export Plug\
+-In . SVG Versio\
+n: 6.00 Build 0)\
+ -->\x0d\x0a<svg vers\
+ion=\x221.1\x22 id=\x22Eb\
+ene_1\x22 xmlns=\x22ht\
+tp://www.w3.org/\
+2000/svg\x22 xmlns:\
+xlink=\x22http://ww\
+w.w3.org/1999/xl\
+ink\x22 x=\x220px\x22 y=\x22\
+0px\x22\x0d\x0a\x09 viewBox=\
+\x220 0 16 16\x22 styl\
+e=\x22enable-backgr\
+ound:new 0 0 16 \
+16;\x22 xml:space=\x22\
+preserve\x22>\x0d\x0a<sty\
+le type=\x22text/cs\
+s\x22>\x0d\x0a\x09.st0{fill:\
+none;stroke:#FFF\
+FFF;stroke-width\
+:2;stroke-miterl\
+imit:10;}\x0d\x0a</sty\
+le>\x0d\x0a<image styl\
+e=\x22display:none;\
+overflow:visible\
+;\x22 width=\x2216\x22 he\
+ight=\x2216\x22 xlink:\
+href=\x22data:image\
+/png;base64,iVBO\
+Rw0KGgoAAAANSUhE\
+UgAAABAAAAAQCAYA\
+AAAf8/9hAAAACXBI\
+WXMAAAsTAAALEwEA\
+mpwYAAAF\x0d\x0a8WlUWH\
+RYTUw6Y29tLmFkb2\
+JlLnhtcAAAAAAAPD\
+94cGFja2V0IGJlZ2\
+luPSLvu78iIGlkPS\
+JXNU0w\x0d\x0aTXBDZWhp\
+SHpyZVN6TlRjemtj\
+OWQiPz4gPHg6eG1w\
+bWV0YSB4bWxuczp4\
+PSJhZG9iZTpuczpt\
+ZXRh\x0d\x0aLyIgeDp4bX\
+B0az0iQWRvYmUgWE\
+1QIENvcmUgNS42LW\
+MxNDggNzkuMTY0MD\
+M2LCAyMDE5LzA4Lz\
+Ez\x0d\x0aLTAxOjA2OjU3\
+ICAgICAgICAiPiA8\
+cmRmOlJERiB4bWxu\
+czpyZGY9Imh0dHA6\
+Ly93d3cudzMub3Jn\
+\x0d\x0aLzE5OTkvMDIvMj\
+ItcmRmLXN5bnRheC\
+1ucyMiPiA8cmRmOk\
+Rlc2NyaXB0aW9uIH\
+JkZjphYm91dD0i\x0d\x0a\
+IiB4bWxuczp4bXA9\
+Imh0dHA6Ly9ucy5h\
+ZG9iZS5jb20veGFw\
+LzEuMC8iIHhtbG5z\
+OmRjPSJodHRw\x0d\x0aOi\
+8vcHVybC5vcmcvZG\
+MvZWxlbWVudHMvMS\
+4xLyIgeG1sbnM6cG\
+hvdG9zaG9wPSJodH\
+RwOi8vbnMu\x0d\x0aYWRv\
+YmUuY29tL3Bob3Rv\
+c2hvcC8xLjAvIiB4\
+bWxuczp4bXBNTT0i\
+aHR0cDovL25zLmFk\
+b2JlLmNv\x0d\x0abS94YX\
+AvMS4wL21tLyIgeG\
+1sbnM6c3RFdnQ9Im\
+h0dHA6Ly9ucy5hZG\
+9iZS5jb20veGFwLz\
+EuMC9z\x0d\x0aVHlwZS9S\
+ZXNvdXJjZUV2ZW50\
+IyIgeG1wOkNyZWF0\
+b3JUb29sPSJBZG9i\
+ZSBQaG90b3Nob3Ag\
+MjEu\x0d\x0aMCAoV2luZG\
+93cykiIHhtcDpDcm\
+VhdGVEYXRlPSIyMD\
+IwLTAzLTAzVDA5Oj\
+UwOjQxLTAzOjAwIi\
+B4\x0d\x0abXA6TW9kaWZ5\
+RGF0ZT0iMjAyMC0w\
+NS0wMlQxNzo1OToz\
+MS0wMzowMCIgeG1w\
+Ok1ldGFkYXRhRGF0\
+\x0d\x0aZT0iMjAyMC0wNS\
+0wMlQxNzo1OTozMS\
+0wMzowMCIgZGM6Zm\
+9ybWF0PSJpbWFnZS\
+9wbmciIHBob3Rv\x0d\x0a\
+c2hvcDpDb2xvck1v\
+ZGU9IjMiIHBob3Rv\
+c2hvcDpJQ0NQcm9m\
+aWxlPSJzUkdCIElF\
+QzYxOTY2LTIu\x0d\x0aMS\
+IgeG1wTU06SW5zdG\
+FuY2VJRD0ieG1wLm\
+lpZDo0MjE3MGE2Zi\
+02NzM1LWNkNDYtYm\
+JiZS00MWYx\x0d\x0aODEy\
+YmNkMWEiIHhtcE1N\
+OkRvY3VtZW50SUQ9\
+ImFkb2JlOmRvY2lk\
+OnBob3Rvc2hvcDpm\
+OGI5YmJj\x0d\x0aMS0yND\
+BjLWVmNGQtODUxYS\
+03Y2Y3NzAwYzM5Yz\
+UiIHhtcE1NOk9yaW\
+dpbmFsRG9jdW1lbn\
+RJRD0i\x0d\x0aeG1wLmRp\
+ZDphNGFkNjEzYy02\
+ODg4LTExNDQtYjMy\
+OS1jOWQ4NDA3MmZm\
+MTgiPiA8eG1wTU06\
+SGlz\x0d\x0adG9yeT4gPH\
+JkZjpTZXE+IDxyZG\
+Y6bGkgc3RFdnQ6YW\
+N0aW9uPSJjcmVhdG\
+VkIiBzdEV2dDppbn\
+N0\x0d\x0aYW5jZUlEPSJ4\
+bXAuaWlkOmE0YWQ2\
+MTNjLTY4ODgtMTE0\
+NC1iMzI5LWM5ZDg0\
+MDcyZmYxOCIgc3RF\
+\x0d\x0adnQ6d2hlbj0iMj\
+AyMC0wMy0wM1QwOT\
+o1MDo0MS0wMzowMC\
+Igc3RFdnQ6c29mdH\
+dhcmVBZ2VudD0i\x0d\x0a\
+QWRvYmUgUGhvdG9z\
+aG9wIDIxLjAgKFdp\
+bmRvd3MpIi8+IDxy\
+ZGY6bGkgc3RFdnQ6\
+YWN0aW9uPSJz\x0d\x0aYX\
+ZlZCIgc3RFdnQ6aW\
+5zdGFuY2VJRD0ieG\
+1wLmlpZDo0MjE3MG\
+E2Zi02NzM1LWNkND\
+YtYmJiZS00\x0d\x0aMWYx\
+ODEyYmNkMWEiIHN0\
+RXZ0OndoZW49IjIw\
+MjAtMDUtMDJUMTc6\
+NTk6MzEtMDM6MDAi\
+IHN0RXZ0\x0d\x0aOnNvZn\
+R3YXJlQWdlbnQ9Ik\
+Fkb2JlIFBob3Rvc2\
+hvcCAyMS4wIChXaW\
+5kb3dzKSIgc3RFdn\
+Q6Y2hh\x0d\x0abmdlZD0i\
+LyIvPiA8L3JkZjpT\
+ZXE+IDwveG1wTU06\
+SGlzdG9yeT4gPC9y\
+ZGY6RGVzY3JpcHRp\
+b24+\x0d\x0aIDwvcmRmOl\
+JERj4gPC94OnhtcG\
+1ldGE+IDw/eHBhY2\
+tldCBlbmQ9InIiPz\
+7XVRw9AAABMklEQV\
+Q4\x0d\x0ay6XTvyvFURgG\
+8HsvUeKidAcLm4GB\
+/Ig/AYsySgYpg91C\
+KaWUQVI2DGKSYiWD\
+yaJQGNxB6vMX2I/l\
+\x0d\x0aXJ2+vtdieDvnvO\
+d5n573Pc8phBAKaa\
+Ahm0vzaMYGekIIhS\
+yolOx7MYh+tCf5Mt\
+4w+osgAqZxgxc8\x0d\x0a\
+4BHP2I3FRdxjKE/B\
+Jj6xjG60ohMjuMAr\
+JnCH4RBC4Uc2VlBF\
+d94MImY5YqoY+FGA\
+Cj4wFs9NcW2J\x0d\x0a0q\
+9xiVN8xehLCVZwmX\
+0FNGISC5jDPGYxhb\
+aU4AjrtaJ6LeRFje\
+AEq3kEKKEhG1mCbR\
+z8R8E43tFa\x0d\x0az42p\
+yX4RRMAFDlPrRtOU\
+UKyroHaJLjzhGOUc\
+BTO4QiWei2kLpYTk\
+PDruDFvYw230/1K2\
+lXofaQJr\x0d\x0a2McOFt\
+Hx5wxqsv7qN2+Q33\
+rmA2LZnv3JAAAAAE\
+lFTkSuQmCC\x22>\x0d\x0a</\
+image>\x0d\x0a<path cl\
+ass=\x22st0\x22 d=\x22M11\
+.95,12.6c-1.06,0\
+.91-2.44,1.46-3.\
+95,1.46c-3.35,0-\
+6.06-2.71-6.06-6\
+.06S4.65,1.94,8,\
+1.94\x0d\x0a\x09c2.64,0,4\
+.88,1.69,5.72,4.\
+04\x22/>\x0d\x0a<line cla\
+ss=\x22st0\x22 x1=\x2215.\
+04\x22 y1=\x225.88\x22 x2\
+=\x228.36\x22 y2=\x225.88\
+\x22/>\x0d\x0a<line class\
+=\x22st0\x22 x1=\x2214.07\
+\x22 y1=\x220.76\x22 x2=\x22\
+14.07\x22 y2=\x226.85\x22\
+/>\x0d\x0a</svg>\x0d\x0a\
+\x00\x00\x0c\x9a\
+<\
+?xml version=\x221.\
+0\x22 encoding=\x22utf\
+-8\x22?>\x0d\x0a<!-- Gene\
+rator: Adobe Ill\
+ustrator 24.1.2,\
+ SVG Export Plug\
+-In . SVG Versio\
+n: 6.00 Build 0)\
+ -->\x0d\x0a<svg vers\
+ion=\x221.1\x22 id=\x22Eb\
+ene_1\x22 xmlns=\x22ht\
+tp://www.w3.org/\
+2000/svg\x22 xmlns:\
+xlink=\x22http://ww\
+w.w3.org/1999/xl\
+ink\x22 x=\x220px\x22 y=\x22\
+0px\x22\x0d\x0a\x09 viewBox=\
+\x220 0 16 16\x22 styl\
+e=\x22enable-backgr\
+ound:new 0 0 16 \
+16;\x22 xml:space=\x22\
+preserve\x22>\x0d\x0a<sty\
+le type=\x22text/cs\
+s\x22>\x0d\x0a\x09.st0{fill:\
+none;stroke:#FFD\
+400;stroke-width\
+:1.5119;stroke-m\
+iterlimit:10;}\x0d\x0a\
+</style>\x0d\x0a<image\
+ style=\x22display:\
+none;overflow:vi\
+sible;\x22 width=\x221\
+6\x22 height=\x2216\x22 x\
+link:href=\x22data:\
+image/png;base64\
+,iVBORw0KGgoAAAA\
+NSUhEUgAAABAAAAA\
+QCAYAAAAf8/9hAAA\
+ACXBIWXMAAAsTAAA\
+LEwEAmpwYAAAF\x0d\x0a8\
+WlUWHRYTUw6Y29tL\
+mFkb2JlLnhtcAAAA\
+AAAPD94cGFja2V0I\
+GJlZ2luPSLvu78iI\
+GlkPSJXNU0w\x0d\x0aTXB\
+DZWhpSHpyZVN6TlR\
+jemtjOWQiPz4gPHg\
+6eG1wbWV0YSB4bWx\
+uczp4PSJhZG9iZTp\
+uczptZXRh\x0d\x0aLyIge\
+Dp4bXB0az0iQWRvY\
+mUgWE1QIENvcmUgN\
+S42LWMxNDggNzkuM\
+TY0MDM2LCAyMDE5L\
+zA4LzEz\x0d\x0aLTAxOjA\
+2OjU3ICAgICAgICA\
+iPiA8cmRmOlJERiB\
+4bWxuczpyZGY9Imh\
+0dHA6Ly93d3cudzM\
+ub3Jn\x0d\x0aLzE5OTkvM\
+DIvMjItcmRmLXN5b\
+nRheC1ucyMiPiA8c\
+mRmOkRlc2NyaXB0a\
+W9uIHJkZjphYm91d\
+D0i\x0d\x0aIiB4bWxuczp\
+4bXA9Imh0dHA6Ly9\
+ucy5hZG9iZS5jb20\
+veGFwLzEuMC8iIHh\
+tbG5zOmRjPSJodHR\
+w\x0d\x0aOi8vcHVybC5vc\
+mcvZGMvZWxlbWVud\
+HMvMS4xLyIgeG1sb\
+nM6cGhvdG9zaG9wP\
+SJodHRwOi8vbnMu\x0d\
+\x0aYWRvYmUuY29tL3B\
+ob3Rvc2hvcC8xLjA\
+vIiB4bWxuczp4bXB\
+NTT0iaHR0cDovL25\
+zLmFkb2JlLmNv\x0d\x0ab\
+S94YXAvMS4wL21tL\
+yIgeG1sbnM6c3RFd\
+nQ9Imh0dHA6Ly9uc\
+y5hZG9iZS5jb20ve\
+GFwLzEuMC9z\x0d\x0aVHl\
+wZS9SZXNvdXJjZUV\
+2ZW50IyIgeG1wOkN\
+yZWF0b3JUb29sPSJ\
+BZG9iZSBQaG90b3N\
+ob3AgMjEu\x0d\x0aMCAoV\
+2luZG93cykiIHhtc\
+DpDcmVhdGVEYXRlP\
+SIyMDIwLTAzLTAzV\
+DA5OjUwOjQxLTAzO\
+jAwIiB4\x0d\x0abXA6TW9\
+kaWZ5RGF0ZT0iMjA\
+yMC0wNS0wMlQxNzo\
+1OToxNS0wMzowMCI\
+geG1wOk1ldGFkYXR\
+hRGF0\x0d\x0aZT0iMjAyM\
+C0wNS0wMlQxNzo1O\
+ToxNS0wMzowMCIgZ\
+GM6Zm9ybWF0PSJpb\
+WFnZS9wbmciIHBob\
+3Rv\x0d\x0ac2hvcDpDb2x\
+vck1vZGU9IjMiIHB\
+ob3Rvc2hvcDpJQ0N\
+Qcm9maWxlPSJzUkd\
+CIElFQzYxOTY2LTI\
+u\x0d\x0aMSIgeG1wTU06S\
+W5zdGFuY2VJRD0ie\
+G1wLmlpZDowNmM0Z\
+DA3Ni0xMjA5LWRkN\
+DMtOGYxNy0zMmYx\x0d\
+\x0aMjU4NWUzZmUiIHh\
+tcE1NOkRvY3VtZW5\
+0SUQ9ImFkb2JlOmR\
+vY2lkOnBob3Rvc2h\
+vcDo3MmNhODVm\x0d\x0aO\
+C1kNWY0LTkwNDItY\
+TIxYS1mMDhhOTdlN\
+jE2ZTciIHhtcE1NO\
+k9yaWdpbmFsRG9jd\
+W1lbnRJRD0i\x0d\x0aeG1\
+wLmRpZDplYTU5ZmU\
+zMC04MzcxLWM1NGM\
+tYTJhZi1jY2U0NzA\
+4Y2Q3OTgiPiA8eG1\
+wTU06SGlz\x0d\x0adG9ye\
+T4gPHJkZjpTZXE+I\
+DxyZGY6bGkgc3RFd\
+nQ6YWN0aW9uPSJjc\
+mVhdGVkIiBzdEV2d\
+DppbnN0\x0d\x0aYW5jZUl\
+EPSJ4bXAuaWlkOmV\
+hNTlmZTMwLTgzNzE\
+tYzU0Yy1hMmFmLWN\
+jZTQ3MDhjZDc5OCI\
+gc3RF\x0d\x0adnQ6d2hlb\
+j0iMjAyMC0wMy0wM\
+1QwOTo1MDo0MS0wM\
+zowMCIgc3RFdnQ6c\
+29mdHdhcmVBZ2Vud\
+D0i\x0d\x0aQWRvYmUgUGh\
+vdG9zaG9wIDIxLjA\
+gKFdpbmRvd3MpIi8\
++IDxyZGY6bGkgc3R\
+FdnQ6YWN0aW9uPSJ\
+z\x0d\x0aYXZlZCIgc3RFd\
+nQ6aW5zdGFuY2VJR\
+D0ieG1wLmlpZDowN\
+mM0ZDA3Ni0xMjA5L\
+WRkNDMtOGYxNy0z\x0d\
+\x0aMmYxMjU4NWUzZmU\
+iIHN0RXZ0OndoZW4\
+9IjIwMjAtMDUtMDJ\
+UMTc6NTk6MTUtMDM\
+6MDAiIHN0RXZ0\x0d\x0aO\
+nNvZnR3YXJlQWdlb\
+nQ9IkFkb2JlIFBob\
+3Rvc2hvcCAyMS4wI\
+ChXaW5kb3dzKSIgc\
+3RFdnQ6Y2hh\x0d\x0abmd\
+lZD0iLyIvPiA8L3J\
+kZjpTZXE+IDwveG1\
+wTU06SGlzdG9yeT4\
+gPC9yZGY6RGVzY3J\
+pcHRpb24+\x0d\x0aIDwvc\
+mRmOlJERj4gPC94O\
+nhtcG1ldGE+IDw/e\
+HBhY2tldCBlbmQ9I\
+nIiPz6cfMcpAAAA7\
+ElEQVQ4\x0d\x0aje3SsS5\
+EURDG8RsRncI7bKW\
+TEK2gVWgICSLYu55\
+F6wVEhHBjd2UfQUj\
+QEMIDyC/e4mjmynG\
+z3SoV\x0d\x0ak/nOzJx/5\
+uR8RUqpGCWKlFKBV\
+fRwhUsM0IneFI7Rj\
+941TtDKAQNU2MA2j\
+vAWvQV8YhdtbOED7\
+RzQ\x0d\x0axWa9Flp4Dr2\
+E+3xtXKDMAT0cZgP\
+zGWART6EnIveHAco\
+MMIuXIYCx5vw/4A8\
+B3dp5cZ5rfONj6PE\
+M\x0d\x0a8MtIN9jJANN4D\
+b2Mh4aRqto3deEU7\
+zjDOe5wmz1HXKrCh\
+V9YzwEt7OMgcgcz9\
+dpYidoeSqxh8gcw\x0d\
+\x0aSnwDnYsY9wIGXmY\
+AAAAASUVORK5CYII\
+=\x22>\x0d\x0a</image>\x0d\x0a<\
+rect x=\x222.2\x22 y=\x22\
+2\x22 class=\x22st0\x22 w\
+idth=\x224\x22 height=\
+\x2212\x22/>\x0d\x0a<rect x=\
+\x229.8\x22 y=\x222\x22 clas\
+s=\x22st0\x22 width=\x224\
+\x22 height=\x2212\x22/>\x0d\
+\x0a</svg>\x0d\x0a\
+\x00\x00\x02\xb3\
+<\
+?xml version=\x221.\
+0\x22 encoding=\x22utf\
+-8\x22?>\x0d\x0a<!-- Gene\
+rator: Adobe Ill\
+ustrator 24.1.2,\
+ SVG Export Plug\
+-In . SVG Versio\
+n: 6.00 Build 0)\
+ -->\x0d\x0a<svg vers\
+ion=\x221.1\x22 id=\x22Eb\
+ene_1\x22 xmlns=\x22ht\
+tp://www.w3.org/\
+2000/svg\x22 xmlns:\
+xlink=\x22http://ww\
+w.w3.org/1999/xl\
+ink\x22 x=\x220px\x22 y=\x22\
+0px\x22\x0d\x0a\x09 viewBox=\
+\x220 0 16 16\x22 styl\
+e=\x22enable-backgr\
+ound:new 0 0 16 \
+16;\x22 xml:space=\x22\
+preserve\x22>\x0d\x0a<sty\
+le type=\x22text/cs\
+s\x22>\x0d\x0a\x09.st0{fill:\
+none;stroke:#24D\
+115;stroke-width\
+:1.9944;stroke-l\
+inecap:round;str\
+oke-linejoin:rou\
+nd;stroke-miterl\
+imit:10;}\x0d\x0a</sty\
+le>\x0d\x0a<polygon cl\
+ass=\x22st0\x22 points\
+=\x223.5,14 3.5,1.7\
+6 13.6,7.88 \x22/>\x0d\
+\x0a<g>\x0d\x0a</g>\x0d\x0a<g>\x0d\
+\x0a</g>\x0d\x0a<g>\x0d\x0a</g>\
+\x0d\x0a<g>\x0d\x0a</g>\x0d\x0a<g>\
+\x0d\x0a</g>\x0d\x0a<g>\x0d\x0a</g\
+>\x0d\x0a<g>\x0d\x0a</g>\x0d\x0a<g\
+>\x0d\x0a</g>\x0d\x0a<g>\x0d\x0a</\
+g>\x0d\x0a<g>\x0d\x0a</g>\x0d\x0a<\
+g>\x0d\x0a</g>\x0d\x0a</svg>\
+\x0d\x0a\
\x00\x00\x07b\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@@ -6700,6 +7575,131 @@ ft\x03\x98\xa0\xb4\x06\x10\x0b\x90j\x00\x0b\x94\x0e\x01\
Z\x1a\x88\xf7@\xd3\x02\xd1\xd1\x88\x9e\x90\xd0\xd94\
N\xca\x14\xe7FJ\x0d\x00\x00\x00\x12\xd9\xf2\x1b\xc9=\
\xce\x00\x00\x00\x00IEND\xaeB`\x82\
+\x00\x00\x07\xad\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\
+\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\
+\x01\x00\x9a\x9c\x18\x00\x00\x06\xbeiTXtXML\
+:com.adobe.xmp\x00\x00\
+\x00\x00\x00<?xpacket beg\
+in=\x22\xef\xbb\xbf\x22 id=\x22W5M\
+0MpCehiHzreSzNTc\
+zkc9d\x22?> <x:xmpm\
+eta xmlns:x=\x22ado\
+be:ns:meta/\x22 x:x\
+mptk=\x22Adobe XMP \
+Core 6.0-c002 79\
+.164360, 2020/02\
+/13-01:07:22 \
+ \x22> <rdf:RDF \
+xmlns:rdf=\x22http:\
+//www.w3.org/199\
+9/02/22-rdf-synt\
+ax-ns#\x22> <rdf:De\
+scription rdf:ab\
+out=\x22\x22 xmlns:xmp\
+=\x22http://ns.adob\
+e.com/xap/1.0/\x22 \
+xmlns:dc=\x22http:/\
+/purl.org/dc/ele\
+ments/1.1/\x22 xmln\
+s:photoshop=\x22htt\
+p://ns.adobe.com\
+/photoshop/1.0/\x22\
+ xmlns:xmpMM=\x22ht\
+tp://ns.adobe.co\
+m/xap/1.0/mm/\x22 x\
+mlns:stEvt=\x22http\
+://ns.adobe.com/\
+xap/1.0/sType/Re\
+sourceEvent#\x22 xm\
+p:CreatorTool=\x22A\
+dobe Photoshop 2\
+1.0 (Windows)\x22 x\
+mp:CreateDate=\x222\
+020-03-03T09:50:\
+39-03:00\x22 xmp:Mo\
+difyDate=\x222023-1\
+2-19T12:32:13+01\
+:00\x22 xmp:Metadat\
+aDate=\x222023-12-1\
+9T12:32:13+01:00\
+\x22 dc:format=\x22ima\
+ge/png\x22 photosho\
+p:ColorMode=\x223\x22 \
+photoshop:ICCPro\
+file=\x22sRGB IEC61\
+966-2.1\x22 xmpMM:I\
+nstanceID=\x22xmp.i\
+id:6fd797e6-6ff4\
+-9a44-9557-6799f\
+e88bef9\x22 xmpMM:D\
+ocumentID=\x22adobe\
+:docid:photoshop\
+:6f97d719-53de-6\
+e45-8ff5-06294f4\
+cb71b\x22 xmpMM:Ori\
+ginalDocumentID=\
+\x22xmp.did:dd5d3a3\
+e-a046-5146-8e7a\
+-14b62eeb350d\x22> \
+<xmpMM:History> \
+<rdf:Seq> <rdf:l\
+i stEvt:action=\x22\
+created\x22 stEvt:i\
+nstanceID=\x22xmp.i\
+id:dd5d3a3e-a046\
+-5146-8e7a-14b62\
+eeb350d\x22 stEvt:w\
+hen=\x222020-03-03T\
+09:50:39-03:00\x22 \
+stEvt:softwareAg\
+ent=\x22Adobe Photo\
+shop 21.0 (Windo\
+ws)\x22/> <rdf:li s\
+tEvt:action=\x22sav\
+ed\x22 stEvt:instan\
+ceID=\x22xmp.iid:ca\
+98d4da-7bf3-f243\
+-8228-c9b9b28efe\
+0b\x22 stEvt:when=\x22\
+2020-05-02T17:58\
+:25-03:00\x22 stEvt\
+:softwareAgent=\x22\
+Adobe Photoshop \
+21.0 (Windows)\x22 \
+stEvt:changed=\x22/\
+\x22/> <rdf:li stEv\
+t:action=\x22saved\x22\
+ stEvt:instanceI\
+D=\x22xmp.iid:6fd79\
+7e6-6ff4-9a44-95\
+57-6799fe88bef9\x22\
+ stEvt:when=\x22202\
+3-12-19T12:32:13\
++01:00\x22 stEvt:so\
+ftwareAgent=\x22Ado\
+be Photoshop 21.\
+1 (Windows)\x22 stE\
+vt:changed=\x22/\x22/>\
+ </rdf:Seq> </xm\
+pMM:History> </r\
+df:Description> \
+</rdf:RDF> </x:x\
+mpmeta> <?xpacke\
+t end=\x22r\x22?>\x87\x8a\xb4f\x00\
+\x00\x00\x95IDAT8\xcb\xad\x93A\x0a\x830\x10\
+Eg%\xf4*\x9a\xb3\xd6,\x0c\xf4.\xa5\xb7(\xea\
+=ta\xc4b\xff\xc0D\xc2\x80\x053]\xbcE\x92\
+\xf9\x0f2\x99\xd0ND\x8a\x1a\xdc\xc1\x00\x16\xa1\x97\xbd\
+Z\xd7\xe7\x8b\x0at\xe0\x03\xf6\x13\xf8\xec\x01nZ\xc0\
+\xe1\xe7\x8f\xa0\xe6%\x99C\x10.\x84\x13]\x124`\
++\x10p\xa6aA[\x10N\xb4$\xdd.\x15\x0c,\
+\x88\x06A\xb4\x0a&\xeb\x15\xde\xd6&z\x168\xc33\
+:\xcb \x85\xbf\x8e\xb2\xf93\xe5\xf0h{0\x82\x15\
+\xcc\xdcm\xd9s\xba\xfe\x0bX\xa9\xc6a\xd5\xd1B\x1d\
+\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x07{\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@@ -30587,6 +31587,34 @@ qt_resource_name = b"\
\x00o\xa6S\
\x00i\
\x00c\x00o\x00n\x00s\
+\x00\x09\
+\x06V\x95\x87\
+\x00i\
+\x00c\x00o\x00n\x00s\x00-\x00s\x00v\x00g\
+\x00\x14\
+\x07^\x97G\
+\x00c\
+\x00i\x00l\x00-\x00m\x00e\x00d\x00i\x00a\x00-\x00r\x00e\x00c\x00o\x00r\x00d\x00.\
+\x00s\x00v\x00g\
+\x00\x12\
+\x06B\x83G\
+\x00c\
+\x00i\x00l\x00-\x00m\x00e\x00d\x00i\x00a\x00-\x00s\x00t\x00o\x00p\x00.\x00s\x00v\
+\x00g\
+\x00\x0e\
+\x0a\x9eH\xc7\
+\x00c\
+\x00i\x00l\x00-\x00r\x00e\x00l\x00o\x00a\x00d\x00.\x00s\x00v\x00g\
+\x00\x13\
+\x0e\x8d\xdag\
+\x00c\
+\x00i\x00l\x00-\x00m\x00e\x00d\x00i\x00a\x00-\x00p\x00a\x00u\x00s\x00e\x00.\x00s\
+\x00v\x00g\
+\x00\x12\
+\x0f\xad\x82\xe7\
+\x00c\
+\x00i\x00l\x00-\x00m\x00e\x00d\x00i\x00a\x00-\x00p\x00l\x00a\x00y\x00.\x00s\x00v\
+\x00g\
\x00\x10\
\x00\xa4\xda'\
\x00c\
@@ -30845,6 +31873,10 @@ qt_resource_name = b"\
\x00c\
\x00i\x00l\x00-\x00a\x00r\x00r\x00o\x00w\x00-\x00l\x00e\x00f\x00t\x00.\x00p\x00n\
\x00g\
+\x00\x0e\
+\x09nZ\xe7\
+\x00c\
+\x00i\x00l\x00-\x00r\x00e\x00c\x00o\x00r\x00d\x00.\x00p\x00n\x00g\
\x00\x0d\
\x09e\xcd\xe7\
\x00c\
@@ -31770,525 +32802,541 @@ qt_resource_name = b"\
"
qt_resource_struct = b"\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x09\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
+\x00\x00\x00\x10\x00\x02\x00\x00\x00\x05\x00\x00\x00\x04\
\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x02\x00\x00\x01\x01\x00\x00\x00\x03\
+\x00\x00\x00V\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xf9\
+\x00\x00\x01\x8c\x82\x0a\x8e\x98\
+\x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\x8c\x82\x1by\xc8\
+\x00\x00\x00\x80\x00\x00\x00\x00\x00\x01\x00\x00\x19\x1c\
+\x00\x00\x01\x8c\x820\xf4\x8b\
+\x00\x00\x00\xa2\x00\x00\x00\x00\x00\x01\x00\x00&\xad\
+\x00\x00\x01\x8c\x82\x09\xe1%\
+\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x003K\
+\x00\x00\x01\x8c\x82\x01\xdf*\
+\x00\x00\x00\x00\x00\x02\x00\x00\x01\x02\x00\x00\x00\x0a\
\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x07\xee\x00\x00\x00\x00\x00\x01\x00\x01W\xfe\
+\x00\x00\x08\xd6\x00\x00\x00\x00\x00\x01\x00\x01\x8e\x00\
\x00\x00\x01\x88v;G>\
-\x00\x00\x1f\x00\x00\x00\x00\x00\x00\x01\x00\x05Zx\
+\x00\x00 \x0a\x00\x00\x00\x00\x00\x01\x00\x05\x98+\
\x00\x00\x01\x88v;F\xfe\
-\x00\x00\x03\xbc\x00\x00\x00\x00\x00\x01\x00\x00\x9el\
+\x00\x00\x04\xa4\x00\x00\x00\x00\x00\x01\x00\x00\xd4n\
\x00\x00\x01\x88v;G$\
-\x00\x00\x08\x16\x00\x00\x00\x00\x00\x01\x00\x01_V\
+\x00\x00\x08\xfe\x00\x00\x00\x00\x00\x01\x00\x01\x95X\
\x00\x00\x01\x88v;F\x05\
-\x00\x00\x02,\x00\x00\x00\x00\x00\x01\x00\x00[L\
+\x00\x00\x03\x14\x00\x00\x00\x00\x00\x01\x00\x00\x91N\
\x00\x00\x01\x88v;F\xa7\
-\x00\x00&\xce\x00\x00\x00\x00\x00\x01\x00\x06\xbf*\
+\x00\x00'\xd8\x00\x00\x00\x00\x00\x01\x00\x06\xfc\xdd\
\x00\x00\x01\x88v;F\xa8\
-\x00\x00$\xf2\x00\x00\x00\x00\x00\x01\x00\x06k\xd3\
+\x00\x00%\xfc\x00\x00\x00\x00\x00\x01\x00\x06\xa9\x86\
\x00\x00\x01\x88v;E\xf1\
-\x00\x00\x02\xc6\x00\x00\x00\x00\x00\x01\x00\x00y1\
+\x00\x00\x03\xae\x00\x00\x00\x00\x00\x01\x00\x00\xaf3\
\x00\x00\x01\x88v;Fj\
-\x00\x00\x13\x9c\x00\x00\x00\x00\x00\x01\x00\x03\x5c\x9c\
+\x00\x00\x14\xa6\x00\x00\x00\x00\x00\x01\x00\x03\x9aO\
\x00\x00\x01\x88v;E\xf2\
-\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x00\xf8\x00\x00\x00\x00\x00\x01\x00\x006\x02\
\x00\x00\x01\x88v;F\x9d\
-\x00\x00\x14\xe4\x00\x00\x00\x00\x00\x01\x00\x03\x98n\
+\x00\x00\x15\xee\x00\x00\x00\x00\x00\x01\x00\x03\xd6!\
\x00\x00\x01\x88v;F#\
-\x00\x00\x0f\xe2\x00\x00\x00\x00\x00\x01\x00\x02\xc7M\
+\x00\x00\x10\xec\x00\x00\x00\x00\x00\x01\x00\x03\x05\x00\
\x00\x00\x01\x88v;F\x84\
-\x00\x00\x04\xf2\x00\x00\x00\x00\x00\x01\x00\x00\xd18\
+\x00\x00\x05\xda\x00\x00\x00\x00\x00\x01\x00\x01\x07:\
\x00\x00\x01\x88v;F\x86\
-\x00\x00%\x0c\x00\x00\x00\x00\x00\x01\x00\x06sx\
+\x00\x00&\x16\x00\x00\x00\x00\x00\x01\x00\x06\xb1+\
\x00\x00\x01\x88v;F\xcc\
-\x00\x00\x1d\xb6\x00\x00\x00\x00\x00\x01\x00\x05\x1f\x9e\
+\x00\x00\x1e\xc0\x00\x00\x00\x00\x00\x01\x00\x05]Q\
\x00\x00\x01\x88v;F\x1d\
-\x00\x00\x17,\x00\x00\x00\x00\x00\x01\x00\x04\x00\xf5\
+\x00\x00\x186\x00\x00\x00\x00\x00\x01\x00\x04>\xa8\
\x00\x00\x01\x88v;E\xfb\
-\x00\x00\x01\xda\x00\x00\x00\x00\x00\x01\x00\x00L\x8d\
+\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x00\x82\x8f\
\x00\x00\x01\x88v;F3\
-\x00\x00\x02T\x00\x00\x00\x00\x00\x01\x00\x00b\xd9\
+\x00\x00\x03<\x00\x00\x00\x00\x00\x01\x00\x00\x98\xdb\
\x00\x00\x01\x88v;G=\
-\x00\x00\x1c\xfa\x00\x00\x00\x00\x00\x01\x00\x05\x01/\
+\x00\x00\x1e\x04\x00\x00\x00\x00\x00\x01\x00\x05>\xe2\
\x00\x00\x01\x88v;F6\
-\x00\x00\x1f\xb0\x00\x00\x00\x00\x00\x01\x00\x05q\xb2\
+\x00\x00 \xba\x00\x00\x00\x00\x00\x01\x00\x05\xafe\
\x00\x00\x01\x88v;F\x99\
-\x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00&\xac\
+\x00\x00\x01\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x5c\xae\
\x00\x00\x01\x88v;G\x14\
-\x00\x00\x00V\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xd1\
+\x00\x00\x01>\x00\x00\x00\x00\x00\x01\x00\x00D\xd3\
\x00\x00\x01\x88v;F;\
-\x00\x00!\xfa\x00\x00\x00\x00\x00\x01\x00\x05\xd3\xa5\
+\x00\x00#\x04\x00\x00\x00\x00\x00\x01\x00\x06\x11X\
\x00\x00\x01\x88v;G\x16\
-\x00\x00(\x90\x00\x00\x00\x00\x00\x01\x00\x07\x10|\
+\x00\x00)\x9a\x00\x00\x00\x00\x00\x01\x00\x07N/\
\x00\x00\x01\x88v;F\x9b\
-\x00\x00\x10D\x00\x00\x00\x00\x00\x01\x00\x02\xd6$\
+\x00\x00\x11N\x00\x00\x00\x00\x00\x01\x00\x03\x13\xd7\
\x00\x00\x01\x88v;E\xf3\
-\x00\x00\x1a*\x00\x00\x00\x00\x00\x01\x00\x04\x82\x7f\
+\x00\x00\x1b4\x00\x00\x00\x00\x00\x01\x00\x04\xc02\
\x00\x00\x01\x88v;Fv\
-\x00\x00\x0c\xae\x00\x00\x00\x00\x00\x01\x00\x028`\
+\x00\x00\x0d\xb8\x00\x00\x00\x00\x00\x01\x00\x02v\x13\
\x00\x00\x01\x88v;Fq\
-\x00\x00\x17\xe4\x00\x00\x00\x00\x00\x01\x00\x04\x1er\
+\x00\x00\x18\xee\x00\x00\x00\x00\x00\x01\x00\x04\x5c%\
\x00\x00\x01\x88v;Fp\
-\x00\x00\x12\x88\x00\x00\x00\x00\x00\x01\x00\x03/\xab\
+\x00\x00\x13\x92\x00\x00\x00\x00\x00\x01\x00\x03m^\
\x00\x00\x01\x88v;F5\
-\x00\x00\x1f\x8e\x00\x00\x00\x00\x00\x01\x00\x05p\xdc\
+\x00\x00 \x98\x00\x00\x00\x00\x00\x01\x00\x05\xae\x8f\
\x00\x00\x01\x88v;GE\
-\x00\x00$\xd0\x00\x00\x00\x00\x00\x01\x00\x06d0\
+\x00\x00%\xda\x00\x00\x00\x00\x00\x01\x00\x06\xa1\xe3\
\x00\x00\x01\x88v;F\x94\
-\x00\x00\x098\x00\x00\x00\x00\x00\x01\x00\x01\x93\x91\
+\x00\x00\x0a \x00\x00\x00\x00\x00\x01\x00\x01\xc9\x93\
\x00\x00\x01\x88v;F\x09\
-\x00\x00\x15\x82\x00\x00\x00\x00\x00\x01\x00\x03\xb5\xcc\
+\x00\x00\x16\x8c\x00\x00\x00\x00\x00\x01\x00\x03\xf3\x7f\
\x00\x00\x01\x88v;Ff\
-\x00\x00\x1bh\x00\x00\x00\x00\x00\x01\x00\x04\xbe%\
+\x00\x00\x1cr\x00\x00\x00\x00\x00\x01\x00\x04\xfb\xd8\
\x00\x00\x01\x88v;F\xa4\
-\x00\x00\x0a(\x00\x00\x00\x00\x00\x01\x00\x01\xb9\xe0\
+\x00\x00\x0b2\x00\x00\x00\x00\x00\x01\x00\x01\xf7\x93\
\x00\x00\x01\x88v;F\xb7\
-\x00\x00\x1e$\x00\x00\x00\x00\x00\x01\x00\x055s\
+\x00\x00\x1f.\x00\x00\x00\x00\x00\x01\x00\x05s&\
\x00\x00\x01\x88v;FA\
-\x00\x00\x0c\xf8\x00\x00\x00\x00\x00\x01\x00\x02G\xa4\
+\x00\x00\x0e\x02\x00\x00\x00\x00\x00\x01\x00\x02\x85W\
\x00\x00\x01\x88v;FI\
-\x00\x00\x11\xb8\x00\x00\x00\x00\x00\x01\x00\x03\x0aR\
+\x00\x00\x12\xc2\x00\x00\x00\x00\x00\x01\x00\x03H\x05\
\x00\x00\x01\x88v;G@\
-\x00\x00\x0b\xe0\x00\x00\x00\x00\x00\x01\x00\x02\x13i\
+\x00\x00\x0c\xea\x00\x00\x00\x00\x00\x01\x00\x02Q\x1c\
\x00\x00\x01\x88v;F \
-\x00\x00\x06\x1c\x00\x00\x00\x00\x00\x01\x00\x01\x06 \
+\x00\x00\x07\x04\x00\x00\x00\x00\x00\x01\x00\x01<\x22\
\x00\x00\x01\x88v;F\xc4\
-\x00\x00\x17\x86\x00\x00\x00\x00\x00\x01\x00\x04\x0f\xce\
+\x00\x00\x18\x90\x00\x00\x00\x00\x00\x01\x00\x04M\x81\
\x00\x00\x01\x88v;F\xc7\
-\x00\x00\x19^\x00\x00\x00\x00\x00\x01\x00\x04b\xa0\
+\x00\x00\x1ah\x00\x00\x00\x00\x00\x01\x00\x04\xa0S\
\x00\x00\x01\x88v;F\xa0\
-\x00\x00':\x00\x00\x00\x00\x00\x01\x00\x06\xd5D\
+\x00\x00(D\x00\x00\x00\x00\x00\x01\x00\x07\x12\xf7\
\x00\x00\x01\x88v;G\x03\
-\x00\x00\x1e\xa0\x00\x00\x00\x00\x00\x01\x00\x05K\xaa\
+\x00\x00\x1f\xaa\x00\x00\x00\x00\x00\x01\x00\x05\x89]\
\x00\x00\x01\x88v;G\x05\
-\x00\x00\x0dT\x00\x00\x00\x00\x00\x01\x00\x02V\x94\
+\x00\x00\x0e^\x00\x00\x00\x00\x00\x01\x00\x02\x94G\
\x00\x00\x01\x88v;F\x0d\
-\x00\x00\x1fd\x00\x00\x00\x00\x00\x01\x00\x05i?\
+\x00\x00 n\x00\x00\x00\x00\x00\x01\x00\x05\xa6\xf2\
\x00\x00\x01\x88v;G/\
-\x00\x00\x03\xfc\x00\x00\x00\x00\x00\x01\x00\x00\xa5w\
+\x00\x00\x04\xe4\x00\x00\x00\x00\x00\x01\x00\x00\xdby\
\x00\x00\x01\x88v;F\xcb\
-\x00\x00!\xd0\x00\x00\x00\x00\x00\x01\x00\x05\xcc\x0b\
+\x00\x00\x22\xda\x00\x00\x00\x00\x00\x01\x00\x06\x09\xbe\
\x00\x00\x01\x88v;G\x18\
-\x00\x00\x22\xd8\x00\x00\x00\x00\x00\x01\x00\x05\xff\x99\
+\x00\x00#\xe2\x00\x00\x00\x00\x00\x01\x00\x06=L\
\x00\x00\x01\x88v;F\x87\
-\x00\x00\x06\xb8\x00\x00\x00\x00\x00\x01\x00\x01#\xfa\
+\x00\x00\x07\xa0\x00\x00\x00\x00\x00\x01\x00\x01Y\xfc\
\x00\x00\x01\x88v;FN\
-\x00\x00\x03V\x00\x00\x00\x00\x00\x01\x00\x00\x8f\xc0\
+\x00\x00\x04>\x00\x00\x00\x00\x00\x01\x00\x00\xc5\xc2\
\x00\x00\x01\x88v;F{\
-\x00\x00\x04x\x00\x00\x00\x00\x00\x01\x00\x00\xbc\x1d\
+\x00\x00\x05`\x00\x00\x00\x00\x00\x01\x00\x00\xf2\x1f\
\x00\x00\x01\x88v;G<\
-\x00\x00\x17\xb0\x00\x00\x00\x00\x00\x01\x00\x04\x17U\
+\x00\x00\x18\xba\x00\x00\x00\x00\x00\x01\x00\x04U\x08\
\x00\x00\x01\x88v;G:\
-\x00\x00!6\x00\x00\x00\x00\x00\x01\x00\x05\xaf(\
+\x00\x00\x22@\x00\x00\x00\x00\x00\x01\x00\x05\xec\xdb\
\x00\x00\x01\x88v;F\x98\
-\x00\x00\x1e|\x00\x00\x00\x00\x00\x01\x00\x05C\xf0\
+\x00\x00\x1f\x86\x00\x00\x00\x00\x00\x01\x00\x05\x81\xa3\
\x00\x00\x01\x88v;F\xd8\
-\x00\x00#\xc0\x00\x00\x00\x00\x00\x01\x00\x060`\
+\x00\x00$\xca\x00\x00\x00\x00\x00\x01\x00\x06n\x13\
\x00\x00\x01\x88v;G*\
-\x00\x00\x02\xa8\x00\x00\x00\x00\x00\x01\x00\x00q\xc6\
+\x00\x00\x03\x90\x00\x00\x00\x00\x00\x01\x00\x00\xa7\xc8\
\x00\x00\x01\x88v;F`\
-\x00\x00\x1a\x96\x00\x00\x00\x00\x00\x01\x00\x04\x91\x84\
+\x00\x00\x1b\xa0\x00\x00\x00\x00\x00\x01\x00\x04\xcf7\
\x00\x00\x01\x88v;E\xfd\
-\x00\x00\x0c\xd6\x00\x00\x00\x00\x00\x01\x00\x02@\x19\
+\x00\x00\x0d\xe0\x00\x00\x00\x00\x00\x01\x00\x02}\xcc\
\x00\x00\x01\x88v;FH\
-\x00\x00\x09\xa2\x00\x00\x00\x00\x00\x01\x00\x01\xa3\x0e\
+\x00\x00\x0a\xac\x00\x00\x00\x00\x00\x01\x00\x01\xe0\xc1\
\x00\x00\x01\x88v;F\xda\
-\x00\x00\x18\xa8\x00\x00\x00\x00\x00\x01\x00\x04<\xa5\
+\x00\x00\x19\xb2\x00\x00\x00\x00\x00\x01\x00\x04zX\
\x00\x00\x01\x88v;G\x0b\
-\x00\x00#Z\x00\x00\x00\x00\x00\x01\x00\x06\x19\x98\
+\x00\x00$d\x00\x00\x00\x00\x00\x01\x00\x06WK\
\x00\x00\x01\x88v;F+\
-\x00\x00\x22\x18\x00\x00\x00\x00\x00\x01\x00\x05\xda\xe3\
+\x00\x00#\x22\x00\x00\x00\x00\x00\x01\x00\x06\x18\x96\
\x00\x00\x01\x88v;F\x9f\
-\x00\x00\x12\xcc\x00\x00\x00\x00\x00\x01\x00\x037S\
+\x00\x00\x13\xd6\x00\x00\x00\x00\x00\x01\x00\x03u\x06\
\x00\x00\x01\x88v;F\xbf\
-\x00\x00 B\x00\x00\x00\x00\x00\x01\x00\x05\x87\xd0\
+\x00\x00!L\x00\x00\x00\x00\x00\x01\x00\x05\xc5\x83\
\x00\x00\x01\x88v;F\xbb\
-\x00\x00\x05\xf6\x00\x00\x00\x00\x00\x01\x00\x00\xfe\x7f\
+\x00\x00\x06\xde\x00\x00\x00\x00\x00\x01\x00\x014\x81\
\x00\x00\x01\x88v;F\x0e\
-\x00\x00 \xf0\x00\x00\x00\x00\x00\x01\x00\x05\xa5\xba\
+\x00\x00!\xfa\x00\x00\x00\x00\x00\x01\x00\x05\xe3m\
\x00\x00\x01\x88v;F\xe5\
-\x00\x00&l\x00\x00\x00\x00\x00\x01\x00\x06\xaf\xd2\
+\x00\x00'v\x00\x00\x00\x00\x00\x01\x00\x06\xed\x85\
\x00\x00\x01\x88v;F\xe0\
-\x00\x00\x16\x04\x00\x00\x00\x00\x00\x01\x00\x03\xcb\xd4\
+\x00\x00\x17\x0e\x00\x00\x00\x00\x00\x01\x00\x04\x09\x87\
\x00\x00\x01\x88v;G#\
-\x00\x00\x1f8\x00\x00\x00\x00\x00\x01\x00\x05a\xba\
+\x00\x00 B\x00\x00\x00\x00\x00\x01\x00\x05\x9fm\
\x00\x00\x01\x88v;F\xad\
-\x00\x00\x07\x12\x00\x00\x00\x00\x00\x01\x00\x013\x09\
+\x00\x00\x07\xfa\x00\x00\x00\x00\x00\x01\x00\x01i\x0b\
\x00\x00\x01\x88v;Ft\
-\x00\x00\x08n\x00\x00\x00\x00\x00\x01\x00\x01n\xbc\
+\x00\x00\x09V\x00\x00\x00\x00\x00\x01\x00\x01\xa4\xbe\
\x00\x00\x01\x88v;F|\
-\x00\x00\x14\xb8\x00\x00\x00\x00\x00\x01\x00\x03\x91\x18\
+\x00\x00\x15\xc2\x00\x00\x00\x00\x00\x01\x00\x03\xce\xcb\
\x00\x00\x01\x88v;FB\
-\x00\x00\x0d\x96\x00\x00\x00\x00\x00\x01\x00\x02e\xfd\
+\x00\x00\x0e\xa0\x00\x00\x00\x00\x00\x01\x00\x02\xa3\xb0\
\x00\x00\x01\x88v;F\xaf\
-\x00\x00\x1e\xd8\x00\x00\x00\x00\x00\x01\x00\x05R\xfe\
+\x00\x00\x1f\xe2\x00\x00\x00\x00\x00\x01\x00\x05\x90\xb1\
\x00\x00\x01\x88v;G\x13\
-\x00\x00\x22\xac\x00\x00\x00\x00\x00\x01\x00\x05\xf8t\
+\x00\x00#\xb6\x00\x00\x00\x00\x00\x01\x00\x066'\
\x00\x00\x01\x88v;E\xff\
-\x00\x00\x1a\xc0\x00\x00\x00\x00\x00\x01\x00\x04\x98\xb6\
+\x00\x00\x1b\xca\x00\x00\x00\x00\x00\x01\x00\x04\xd6i\
\x00\x00\x01\x88v;F\xa1\
-\x00\x00\x16\xd4\x00\x00\x00\x00\x00\x01\x00\x03\xf1\xc0\
+\x00\x00\x17\xde\x00\x00\x00\x00\x00\x01\x00\x04/s\
\x00\x00\x01\x88v;Fr\
-\x00\x00\x22l\x00\x00\x00\x00\x00\x01\x00\x05\xe9\x0a\
+\x00\x00#v\x00\x00\x00\x00\x00\x01\x00\x06&\xbd\
\x00\x00\x01\x88v;F~\
-\x00\x00\x0c\x02\x00\x00\x00\x00\x00\x01\x00\x02\x1a\xfd\
+\x00\x00\x0d\x0c\x00\x00\x00\x00\x00\x01\x00\x02X\xb0\
\x00\x00\x01\x88v;G-\
-\x00\x00)\x84\x00\x00\x00\x00\x00\x01\x00\x07<\xae\
+\x00\x00*\x8e\x00\x00\x00\x00\x00\x01\x00\x07za\
\x00\x00\x01\x88v;F\xab\
-\x00\x00\x0d\xec\x00\x00\x00\x00\x00\x01\x00\x02t\xd1\
+\x00\x00\x0e\xf6\x00\x00\x00\x00\x00\x01\x00\x02\xb2\x84\
\x00\x00\x01\x88v;F\x19\
-\x00\x00\x13~\x00\x00\x00\x00\x00\x01\x00\x03U:\
+\x00\x00\x14\x88\x00\x00\x00\x00\x00\x01\x00\x03\x92\xed\
\x00\x00\x01\x88v;F(\
-\x00\x00\x16\x86\x00\x00\x00\x00\x00\x01\x00\x03\xe2c\
+\x00\x00\x17\x90\x00\x00\x00\x00\x00\x01\x00\x04 \x16\
\x00\x00\x01\x88v;G\x10\
-\x00\x00#\x82\x00\x00\x00\x00\x00\x01\x00\x06!8\
+\x00\x00$\x8c\x00\x00\x00\x00\x00\x01\x00\x06^\xeb\
\x00\x00\x01\x88v;F'\
-\x00\x00$J\x00\x00\x00\x00\x00\x01\x00\x06FC\
+\x00\x00%T\x00\x00\x00\x00\x00\x01\x00\x06\x83\xf6\
\x00\x00\x01\x88v;G\x1a\
-\x00\x00\x150\x00\x00\x00\x00\x00\x01\x00\x03\xa7\x06\
+\x00\x00\x16:\x00\x00\x00\x00\x00\x01\x00\x03\xe4\xb9\
\x00\x00\x01\x88v;F\x97\
-\x00\x00\x08\xbc\x00\x00\x00\x00\x00\x01\x00\x01}s\
+\x00\x00\x09\xa4\x00\x00\x00\x00\x00\x01\x00\x01\xb3u\
\x00\x00\x01\x88v;F]\
-\x00\x00&\x9a\x00\x00\x00\x00\x00\x01\x00\x06\xb7w\
+\x00\x00'\xa4\x00\x00\x00\x00\x00\x01\x00\x06\xf5*\
\x00\x00\x01\x88v;Fb\
-\x00\x00'\x1c\x00\x00\x00\x00\x00\x01\x00\x06\xcd\xb1\
+\x00\x00(&\x00\x00\x00\x00\x00\x01\x00\x07\x0bd\
\x00\x00\x01\x88v;F\xfa\
-\x00\x00\x15\x0e\x00\x00\x00\x00\x00\x01\x00\x03\x9f\xaf\
+\x00\x00\x16\x18\x00\x00\x00\x00\x00\x01\x00\x03\xddb\
\x00\x00\x01\x88v;F\xe8\
-\x00\x00(F\x00\x00\x00\x00\x00\x01\x00\x07\x01\xff\
+\x00\x00)P\x00\x00\x00\x00\x00\x01\x00\x07?\xb2\
\x00\x00\x01\x88v;F\xa6\
-\x00\x00\x16R\x00\x00\x00\x00\x00\x01\x00\x03\xda\xda\
+\x00\x00\x17\x5c\x00\x00\x00\x00\x00\x01\x00\x04\x18\x8d\
\x00\x00\x01\x88v;F\x81\
-\x00\x00!V\x00\x00\x00\x00\x00\x01\x00\x05\xb6\x7f\
+\x00\x00\x22`\x00\x00\x00\x00\x00\x01\x00\x05\xf42\
\x00\x00\x01\x88v;F\xc8\
-\x00\x00\x14,\x00\x00\x00\x00\x00\x01\x00\x03z\xce\
+\x00\x00\x156\x00\x00\x00\x00\x00\x01\x00\x03\xb8\x81\
\x00\x00\x01\x88v;F\xc1\
-\x00\x00\x0fb\x00\x00\x00\x00\x00\x01\x00\x02\xb0\xcd\
+\x00\x00\x10l\x00\x00\x00\x00\x00\x01\x00\x02\xee\x80\
\x00\x00\x01\x88v;F\x1e\
-\x00\x00\x018\x00\x00\x00\x00\x00\x01\x00\x00.\x18\
+\x00\x00\x02 \x00\x00\x00\x00\x00\x01\x00\x00d\x1a\
\x00\x00\x01\x88v;FU\
-\x00\x00\x0ab\x00\x00\x00\x00\x00\x01\x00\x01\xc8\xce\
+\x00\x00\x0bl\x00\x00\x00\x00\x00\x01\x00\x02\x06\x81\
\x00\x00\x01\x88v;F/\
-\x00\x00\x1b\x10\x00\x00\x00\x00\x00\x01\x00\x04\xa7x\
+\x00\x00\x1c\x1a\x00\x00\x00\x00\x00\x01\x00\x04\xe5+\
\x00\x00\x01\x88v;F\xec\
-\x00\x00\x0e@\x00\x00\x00\x00\x00\x01\x00\x02\x83\xad\
+\x00\x00\x0fJ\x00\x00\x00\x00\x00\x01\x00\x02\xc1`\
\x00\x00\x01\x88v;Fu\
-\x00\x00\x1a\x0a\x00\x00\x00\x00\x00\x01\x00\x04z\xdb\
+\x00\x00\x1b\x14\x00\x00\x00\x00\x00\x01\x00\x04\xb8\x8e\
\x00\x00\x01\x88v;FD\
-\x00\x00\x1f\xe2\x00\x00\x00\x00\x00\x01\x00\x05x\xd0\
+\x00\x00 \xec\x00\x00\x00\x00\x00\x01\x00\x05\xb6\x83\
\x00\x00\x01\x88v;Fa\
-\x00\x00\x05\x22\x00\x00\x00\x00\x00\x01\x00\x00\xd8\xbe\
+\x00\x00\x06\x0a\x00\x00\x00\x00\x00\x01\x00\x01\x0e\xc0\
\x00\x00\x01\x88v;F0\
-\x00\x00\x10\x18\x00\x00\x00\x00\x00\x01\x00\x02\xce\xc6\
+\x00\x00\x11\x22\x00\x00\x00\x00\x00\x01\x00\x03\x0cy\
\x00\x00\x01\x88v;E\xf6\
-\x00\x00\x09\x82\x00\x00\x00\x00\x00\x01\x00\x01\xa2\x12\
+\x00\x00\x0a\x8c\x00\x00\x00\x00\x00\x01\x00\x01\xdf\xc5\
\x00\x00\x01\x88v;GH\
-\x00\x00\x13\xe0\x00\x00\x00\x00\x00\x01\x00\x03k\xeb\
+\x00\x00\x14\xea\x00\x00\x00\x00\x00\x01\x00\x03\xa9\x9e\
\x00\x00\x01\x88v;G'\
-\x00\x00\x1c\x1e\x00\x00\x00\x00\x00\x01\x00\x04\xdb\xd0\
+\x00\x00\x1d(\x00\x00\x00\x00\x00\x01\x00\x05\x19\x83\
\x00\x00\x01\x88v;G%\
-\x00\x00\x15\x5c\x00\x00\x00\x00\x00\x01\x00\x03\xae\x82\
+\x00\x00\x16f\x00\x00\x00\x00\x00\x01\x00\x03\xec5\
\x00\x00\x01\x88v;G\x1c\
-\x00\x00&4\x00\x00\x00\x00\x00\x01\x00\x06\xa8\x0b\
+\x00\x00'>\x00\x00\x00\x00\x00\x01\x00\x06\xe5\xbe\
\x00\x00\x01\x88v;E\xf7\
-\x00\x00\x01V\x00\x00\x00\x00\x00\x01\x00\x005\xa8\
+\x00\x00\x02>\x00\x00\x00\x00\x00\x01\x00\x00k\xaa\
\x00\x00\x01\x88v;F\x06\
-\x00\x00\x122\x00\x00\x00\x00\x00\x01\x00\x03 \x94\
+\x00\x00\x13<\x00\x00\x00\x00\x00\x01\x00\x03^G\
\x00\x00\x01\x88v;FW\
-\x00\x00\x09\xbe\x00\x00\x00\x00\x00\x01\x00\x01\xaa\x89\
+\x00\x00\x0a\xc8\x00\x00\x00\x00\x00\x01\x00\x01\xe8<\
\x00\x00\x01\x88v;F\x1b\
-\x00\x00%\xec\x00\x00\x00\x00\x00\x01\x00\x06\x99\x1c\
+\x00\x00&\xf6\x00\x00\x00\x00\x00\x01\x00\x06\xd6\xcf\
\x00\x00\x01\x88v;G\x0e\
-\x00\x00'\xee\x00\x00\x00\x00\x00\x01\x00\x06\xf3\x0a\
+\x00\x00(\xf8\x00\x00\x00\x00\x00\x01\x00\x070\xbd\
\x00\x00\x01\x88v;G!\
-\x00\x00\x22\xf2\x00\x00\x00\x00\x00\x01\x00\x06\x07\x22\
+\x00\x00#\xfc\x00\x00\x00\x00\x00\x01\x00\x06D\xd5\
\x00\x00\x01\x88v;FY\
-\x00\x00\x0bx\x00\x00\x00\x00\x00\x01\x00\x01\xfc\x8b\
+\x00\x00\x0c\x82\x00\x00\x00\x00\x00\x01\x00\x02:>\
\x00\x00\x01\x88v;F\x80\
-\x00\x00\x1c\x96\x00\x00\x00\x00\x00\x01\x00\x04\xf2B\
+\x00\x00\x1d\xa0\x00\x00\x00\x00\x00\x01\x00\x05/\xf5\
\x00\x00\x01\x88v;FM\
-\x00\x00\x030\x00\x00\x00\x00\x00\x01\x00\x00\x88M\
+\x00\x00\x04\x18\x00\x00\x00\x00\x00\x01\x00\x00\xbeO\
\x00\x00\x01\x88v;F\x8c\
-\x00\x00\x1d\x8a\x00\x00\x00\x00\x00\x01\x00\x05\x17\xe5\
+\x00\x00\x1e\x94\x00\x00\x00\x00\x00\x01\x00\x05U\x98\
\x00\x00\x01\x88v;G\x01\
-\x00\x00!\xa6\x00\x00\x00\x00\x00\x01\x00\x05\xc4\x9c\
+\x00\x00\x22\xb0\x00\x00\x00\x00\x00\x01\x00\x06\x02O\
\x00\x00\x01\x88v;F\x8a\
-\x00\x00(\xbe\x00\x00\x00\x00\x00\x01\x00\x07\x17\x96\
+\x00\x00)\xc8\x00\x00\x00\x00\x00\x01\x00\x07UI\
\x00\x00\x01\x88v;F\x02\
-\x00\x00\x0f\x1c\x00\x00\x00\x00\x00\x01\x00\x02\xa9(\
+\x00\x00\x10&\x00\x00\x00\x00\x00\x01\x00\x02\xe6\xdb\
\x00\x00\x01\x88v;F7\
-\x00\x00\x14\x0c\x00\x00\x00\x00\x00\x01\x00\x03s\x85\
+\x00\x00\x15\x16\x00\x00\x00\x00\x00\x01\x00\x03\xb18\
\x00\x00\x01\x88v;F2\
-\x00\x00\x22\x8c\x00\x00\x00\x00\x00\x01\x00\x05\xf0\xb7\
+\x00\x00#\x96\x00\x00\x00\x00\x00\x01\x00\x06.j\
\x00\x00\x01\x88v;G\x1d\
-\x00\x00\x19\xe2\x00\x00\x00\x00\x00\x01\x00\x04yU\
+\x00\x00\x1a\xec\x00\x00\x00\x00\x00\x01\x00\x04\xb7\x08\
\x00\x00\x01\x88v;GL\
-\x00\x00\x03\x82\x00\x00\x00\x00\x00\x01\x00\x00\x97E\
+\x00\x00\x04j\x00\x00\x00\x00\x00\x01\x00\x00\xcdG\
\x00\x00\x01\x88v;F\xdd\
-\x00\x00\x0a\xd4\x00\x00\x00\x00\x00\x01\x00\x01\xdeN\
+\x00\x00\x0b\xde\x00\x00\x00\x00\x00\x01\x00\x02\x1c\x01\
\x00\x00\x01\x88v;Fe\
-\x00\x00\x06\xe4\x00\x00\x00\x00\x00\x01\x00\x01+\x82\
+\x00\x00\x07\xcc\x00\x00\x00\x00\x00\x01\x00\x01a\x84\
\x00\x00\x01\x88v;F\xac\
-\x00\x00\x0aD\x00\x00\x00\x00\x00\x01\x00\x01\xc1X\
+\x00\x00\x0bN\x00\x00\x00\x00\x00\x01\x00\x01\xff\x0b\
\x00\x00\x01\x88v;FI\
-\x00\x00 \x9a\x00\x00\x00\x00\x00\x01\x00\x05\x96\xde\
+\x00\x00!\xa4\x00\x00\x00\x00\x00\x01\x00\x05\xd4\x91\
\x00\x00\x01\x88v;F\x96\
-\x00\x00\x0c,\x00\x00\x00\x00\x00\x01\x00\x02\x22\x91\
+\x00\x00\x0d6\x00\x00\x00\x00\x00\x01\x00\x02`D\
\x00\x00\x01\x88v;F\x0a\
-\x00\x00%h\x00\x00\x00\x00\x00\x01\x00\x06\x82\xa6\
+\x00\x00&r\x00\x00\x00\x00\x00\x01\x00\x06\xc0Y\
\x00\x00\x01\x88v;F\xb1\
-\x00\x00$p\x00\x00\x00\x00\x00\x01\x00\x06M\x94\
+\x00\x00%z\x00\x00\x00\x00\x00\x01\x00\x06\x8bG\
\x00\x00\x01\x88v;F\xea\
-\x00\x00\x19B\x00\x00\x00\x00\x00\x01\x00\x04[\x0f\
+\x00\x00\x1aL\x00\x00\x00\x00\x00\x01\x00\x04\x98\xc2\
\x00\x00\x01\x88v;F\x0f\
-\x00\x00'r\x00\x00\x00\x00\x00\x01\x00\x06\xdcF\
+\x00\x00(|\x00\x00\x00\x00\x00\x01\x00\x07\x19\xf9\
\x00\x00\x01\x88v;F\x07\
-\x00\x00\x1cr\x00\x00\x00\x00\x00\x01\x00\x04\xea\x90\
+\x00\x00\x1d|\x00\x00\x00\x00\x00\x01\x00\x05(C\
\x00\x00\x01\x88v;F\x8e\
-\x00\x00$\x92\x00\x00\x00\x00\x00\x01\x00\x06UN\
+\x00\x00%\x9c\x00\x00\x00\x00\x00\x01\x00\x06\x93\x01\
\x00\x00\x01\x88v;F\x17\
-\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\x1f$\
+\x00\x00\x01\xd2\x00\x00\x00\x00\x00\x01\x00\x00U&\
\x00\x00\x01\x88v;F\xf6\
-\x00\x00\x22:\x00\x00\x00\x00\x00\x01\x00\x05\xe2\x01\
+\x00\x00#D\x00\x00\x00\x00\x00\x01\x00\x06\x1f\xb4\
\x00\x00\x01\x88v;F\x01\
-\x00\x00\x02\x0c\x00\x00\x00\x00\x00\x01\x00\x00S\xed\
+\x00\x00\x02\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x89\xef\
\x00\x00\x01\x88v;F\xdb\
-\x00\x00%\xbc\x00\x00\x00\x00\x00\x01\x00\x06\x91\xaf\
+\x00\x00&\xc6\x00\x00\x00\x00\x00\x01\x00\x06\xcfb\
\x00\x00\x01\x88v;F\x15\
-\x00\x00!v\x00\x00\x00\x00\x00\x01\x00\x05\xbd$\
+\x00\x00\x22\x80\x00\x00\x00\x00\x00\x01\x00\x05\xfa\xd7\
\x00\x00\x01\x88v;F\xc3\
-\x00\x00\x09b\x00\x00\x00\x00\x00\x01\x00\x01\x9a\x93\
+\x00\x00\x0al\x00\x00\x00\x00\x00\x01\x00\x01\xd8F\
\x00\x00\x01\x88v;G2\
-\x00\x00\x08\xfe\x00\x00\x00\x00\x00\x01\x00\x01\x85\x00\
+\x00\x00\x09\xe6\x00\x00\x00\x00\x00\x01\x00\x01\xbb\x02\
\x00\x00\x01\x88v;F\xc5\
-\x00\x00)\x1a\x00\x00\x00\x00\x00\x01\x00\x07&+\
+\x00\x00\x0aJ\x00\x00\x00\x00\x00\x01\x00\x01\xd0\x95\
+\x00\x00\x01\x8c\x81\xd9 \xf7\
+\x00\x00*$\x00\x00\x00\x00\x00\x01\x00\x07c\xde\
\x00\x00\x01\x88v;F\xf7\
-\x00\x00\x02\x86\x00\x00\x00\x00\x00\x01\x00\x00jX\
+\x00\x00\x03n\x00\x00\x00\x00\x00\x01\x00\x00\xa0Z\
\x00\x00\x01\x88v;FP\
-\x00\x00\x0e\xa4\x00\x00\x00\x00\x00\x01\x00\x02\x92{\
+\x00\x00\x0f\xae\x00\x00\x00\x00\x00\x01\x00\x02\xd0.\
\x00\x00\x01\x88v;F\xf9\
-\x00\x00\x006\x00\x00\x00\x00\x00\x01\x00\x00\x07f\
+\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x00=h\
\x00\x00\x01\x88v;FE\
-\x00\x00)\xc2\x00\x00\x00\x00\x00\x01\x00\x07K\xdc\
+\x00\x00*\xcc\x00\x00\x00\x00\x00\x01\x00\x07\x89\x8f\
\x00\x00\x01\x88v;F\xb8\
-\x00\x00\x13\x08\x00\x00\x00\x00\x00\x01\x00\x03>\x9f\
+\x00\x00\x14\x12\x00\x00\x00\x00\x00\x01\x00\x03|R\
\x00\x00\x01\x88v;F\xeb\
-\x00\x00)6\x00\x00\x00\x00\x00\x01\x00\x07-\xd3\
+\x00\x00*@\x00\x00\x00\x00\x00\x01\x00\x07k\x86\
\x00\x00\x01\x88v;FC\
-\x00\x00\x06\x8c\x00\x00\x00\x00\x00\x01\x00\x01\x1c\xa8\
+\x00\x00\x07t\x00\x00\x00\x00\x00\x01\x00\x01R\xaa\
\x00\x00\x01\x88v;E\xf5\
-\x00\x00&\xf4\x00\x00\x00\x00\x00\x01\x00\x06\xc6{\
+\x00\x00'\xfe\x00\x00\x00\x00\x00\x01\x00\x07\x04.\
\x00\x00\x01\x88v;F&\
-\x00\x00\x19\x80\x00\x00\x00\x00\x00\x01\x00\x04jb\
+\x00\x00\x1a\x8a\x00\x00\x00\x00\x00\x01\x00\x04\xa8\x15\
\x00\x00\x01\x88v;FS\
-\x00\x00 ~\x00\x00\x00\x00\x00\x01\x00\x05\x8fR\
+\x00\x00!\x88\x00\x00\x00\x00\x00\x01\x00\x05\xcd\x05\
\x00\x00\x01\x88v;FQ\
-\x00\x00\x19\x1a\x00\x00\x00\x00\x00\x01\x00\x04Sw\
+\x00\x00\x1a$\x00\x00\x00\x00\x00\x01\x00\x04\x91*\
\x00\x00\x01\x88v;F\x1a\
-\x00\x00\x0f\xb6\x00\x00\x00\x00\x00\x01\x00\x02\xbf\x9e\
+\x00\x00\x10\xc0\x00\x00\x00\x00\x00\x01\x00\x02\xfdQ\
\x00\x00\x01\x88v;G\x0c\
-\x00\x00#<\x00\x00\x00\x00\x00\x01\x00\x06\x0f\x88\
+\x00\x00$F\x00\x00\x00\x00\x00\x01\x00\x06M;\
\x00\x00\x01\x88v\xe8\xa8x\
-\x00\x00!\x18\x00\x00\x00\x00\x00\x01\x00\x05\xad\x17\
+\x00\x00\x22\x22\x00\x00\x00\x00\x00\x01\x00\x05\xea\xca\
\x00\x00\x01\x88v\xecih\
-\x00\x00\x0b\x9c\x00\x00\x00\x00\x00\x01\x00\x02\x04H\
+\x00\x00\x0c\xa6\x00\x00\x00\x00\x00\x01\x00\x02A\xfb\
\x00\x00\x01\x88v;F\xf4\
-\x00\x00(\xec\x00\x00\x00\x00\x00\x01\x00\x07\x1e\xb7\
+\x00\x00)\xf6\x00\x00\x00\x00\x00\x01\x00\x07\x5cj\
\x00\x00\x01\x88v;Fl\
-\x00\x00\x13(\x00\x00\x00\x00\x00\x01\x00\x03F\x04\
+\x00\x00\x142\x00\x00\x00\x00\x00\x01\x00\x03\x83\xb7\
\x00\x00\x01\x88v;F\xe7\
-\x00\x00\x01\x90\x00\x00\x00\x00\x00\x01\x00\x00=]\
+\x00\x00\x02x\x00\x00\x00\x00\x00\x01\x00\x00s_\
\x00\x00\x01\x88v;G\x0f\
-\x00\x00\x05\xa4\x00\x00\x00\x00\x00\x01\x00\x00\xef\x85\
+\x00\x00\x06\x8c\x00\x00\x00\x00\x00\x01\x00\x01%\x87\
\x00\x00\x01\x88v;F\x83\
-\x00\x00\x06f\x00\x00\x00\x00\x00\x01\x00\x01\x15\x1f\
+\x00\x00\x07N\x00\x00\x00\x00\x00\x01\x00\x01K!\
\x00\x00\x01\x88v;Fn\
-\x00\x00$\x1a\x00\x00\x00\x00\x00\x01\x00\x06>\xd0\
+\x00\x00%$\x00\x00\x00\x00\x00\x01\x00\x06|\x83\
\x00\x00\x01\x88v;G3\
-\x00\x00 \xc0\x00\x00\x00\x00\x00\x01\x00\x05\x9e5\
+\x00\x00!\xca\x00\x00\x00\x00\x00\x01\x00\x05\xdb\xe8\
\x00\x00\x01\x88v;G5\
-\x00\x00\x04Z\x00\x00\x00\x00\x00\x01\x00\x00\xb4\xa3\
+\x00\x00\x05B\x00\x00\x00\x00\x00\x01\x00\x00\xea\xa5\
\x00\x00\x01\x88v;F\x90\
-\x00\x00\x16\xa4\x00\x00\x00\x00\x00\x01\x00\x03\xea\x07\
+\x00\x00\x17\xae\x00\x00\x00\x00\x00\x01\x00\x04'\xba\
\x00\x00\x01\x88v;G7\
-\x00\x00\x18\xea\x00\x00\x00\x00\x00\x01\x00\x04K\xdb\
+\x00\x00\x19\xf4\x00\x00\x00\x00\x00\x01\x00\x04\x89\x8e\
\x00\x00\x01\x88v;G6\
-\x00\x00&\x0a\x00\x00\x00\x00\x00\x01\x00\x06\xa0\xae\
+\x00\x00'\x14\x00\x00\x00\x00\x00\x01\x00\x06\xdea\
\x00\x00\x01\x88v;F*\
-\x00\x00\x11\xde\x00\x00\x00\x00\x00\x01\x00\x03\x12\x08\
+\x00\x00\x12\xe8\x00\x00\x00\x00\x00\x01\x00\x03O\xbb\
\x00\x00\x01\x88v;F\xfc\
-\x00\x00\x02\xf2\x00\x00\x00\x00\x00\x01\x00\x00\x80\xac\
+\x00\x00\x03\xda\x00\x00\x00\x00\x00\x01\x00\x00\xb6\xae\
\x00\x00\x01\x88v;F=\
-\x00\x00'\xa8\x00\x00\x00\x00\x00\x01\x00\x06\xe3\xfd\
+\x00\x00(\xb2\x00\x00\x00\x00\x00\x01\x00\x07!\xb0\
\x00\x00\x01\x88v;F\x5c\
-\x00\x00\x0a\x0a\x00\x00\x00\x00\x00\x01\x00\x01\xb2x\
+\x00\x00\x0b\x14\x00\x00\x00\x00\x00\x01\x00\x01\xf0+\
\x00\x00\x01\x88v;F\xb3\
-\x00\x00\x05\x84\x00\x00\x00\x00\x00\x01\x00\x00\xe8\x16\
+\x00\x00\x06l\x00\x00\x00\x00\x00\x01\x00\x01\x1e\x18\
\x00\x00\x01\x88v;F,\
-\x00\x00$\xb0\x00\x00\x00\x00\x00\x01\x00\x06\x5c\xc1\
+\x00\x00%\xba\x00\x00\x00\x00\x00\x01\x00\x06\x9at\
\x00\x00\x01\x88v;F\x8b\
-\x00\x00)\xa2\x00\x00\x00\x00\x00\x01\x00\x07D\x22\
+\x00\x00*\xac\x00\x00\x00\x00\x00\x01\x00\x07\x81\xd5\
\x00\x00\x01\x88v;E\xfa\
-\x00\x00\x1bH\x00\x00\x00\x00\x00\x01\x00\x04\xb6\xa0\
+\x00\x00\x1cR\x00\x00\x00\x00\x00\x01\x00\x04\xf4S\
\x00\x00\x01\x88v;G\x02\
-\x00\x00\x08\x90\x00\x00\x00\x00\x00\x01\x00\x01u\xea\
+\x00\x00\x09x\x00\x00\x00\x00\x00\x01\x00\x01\xab\xec\
\x00\x00\x01\x88v;G\x1f\
-\x00\x00\x15\xa8\x00\x00\x00\x00\x00\x01\x00\x03\xbd\x0b\
+\x00\x00\x16\xb2\x00\x00\x00\x00\x00\x01\x00\x03\xfa\xbe\
\x00\x00\x01\x88v;F$\
-\x00\x00\x09\x1c\x00\x00\x00\x00\x00\x01\x00\x01\x8b\xf3\
+\x00\x00\x0a\x04\x00\x00\x00\x00\x00\x01\x00\x01\xc1\xf5\
\x00\x00\x01\x88v;FZ\
-\x00\x00\x04\xd4\x00\x00\x00\x00\x00\x01\x00\x00\xc9\xb6\
+\x00\x00\x05\xbc\x00\x00\x00\x00\x00\x01\x00\x00\xff\xb8\
\x00\x00\x01\x88v;F\xd2\
-\x00\x00\x1eT\x00\x00\x00\x00\x00\x01\x00\x05<\xcc\
+\x00\x00\x1f^\x00\x00\x00\x00\x00\x01\x00\x05z\x7f\
\x00\x00\x01\x88v;F\x0b\
-\x00\x00\x05\xd8\x00\x00\x00\x00\x00\x01\x00\x00\xf7\x01\
+\x00\x00\x06\xc0\x00\x00\x00\x00\x00\x01\x00\x01-\x03\
\x00\x00\x01\x88v;F\xd5\
-\x00\x00\x10\xde\x00\x00\x00\x00\x00\x01\x00\x02\xec\xa9\
+\x00\x00\x11\xe8\x00\x00\x00\x00\x00\x01\x00\x03*\x5c\
\x00\x00\x01\x88v;FR\
-\x00\x00\x0e\xca\x00\x00\x00\x00\x00\x01\x00\x02\x9a\x17\
+\x00\x00\x0f\xd4\x00\x00\x00\x00\x00\x01\x00\x02\xd7\xca\
\x00\x00\x01\x88v;F\xb4\
-\x00\x00 \x16\x00\x00\x00\x00\x00\x01\x00\x05\x80P\
+\x00\x00! \x00\x00\x00\x00\x00\x01\x00\x05\xbe\x03\
\x00\x00\x01\x88v;G \
-\x00\x00\x11R\x00\x00\x00\x00\x00\x01\x00\x02\xfb!\
+\x00\x00\x12\x5c\x00\x00\x00\x00\x00\x01\x00\x038\xd4\
\x00\x00\x01\x88v;FG\
-\x00\x00#\xec\x00\x00\x00\x00\x00\x01\x00\x067\x80\
+\x00\x00$\xf6\x00\x00\x00\x00\x00\x01\x00\x06u3\
\x00\x00\x01\x88v;F\x22\
-\x00\x00(j\x00\x00\x00\x00\x00\x01\x00\x07\x09V\
+\x00\x00)t\x00\x00\x00\x00\x00\x01\x00\x07G\x09\
\x00\x00\x01\x88v;F\xa3\
-\x00\x00'\xc6\x00\x00\x00\x00\x00\x01\x00\x06\xebA\
+\x00\x00(\xd0\x00\x00\x00\x00\x00\x01\x00\x07(\xf4\
\x00\x00\x01\x88v;G\x06\
-\x00\x00\x1d>\x00\x00\x00\x00\x00\x01\x00\x05\x08\xd6\
+\x00\x00\x1eH\x00\x00\x00\x00\x00\x01\x00\x05F\x89\
\x00\x00\x01\x88v;Fm\
-\x00\x00\x12V\x00\x00\x00\x00\x00\x01\x00\x03(\x14\
+\x00\x00\x13`\x00\x00\x00\x00\x00\x01\x00\x03e\xc7\
\x00\x00\x01\x88v;FF\
-\x00\x00\x0f\x8e\x00\x00\x00\x00\x00\x01\x00\x02\xb8t\
+\x00\x00\x10\x98\x00\x00\x00\x00\x00\x01\x00\x02\xf6'\
\x00\x00\x01\x88v;F\x11\
-\x00\x00\x070\x00\x00\x00\x00\x00\x01\x00\x01:[\
+\x00\x00\x08\x18\x00\x00\x00\x00\x00\x01\x00\x01p]\
\x00\x00\x01\x88v;F\x12\
-\x00\x00(\x1e\x00\x00\x00\x00\x00\x01\x00\x06\xfa\xa4\
+\x00\x00)(\x00\x00\x00\x00\x00\x01\x00\x078W\
\x00\x00\x01\x88v;F\x13\
-\x00\x00\x10\xae\x00\x00\x00\x00\x00\x01\x00\x02\xe4\xf4\
+\x00\x00\x11\xb8\x00\x00\x00\x00\x00\x01\x00\x03\x22\xa7\
\x00\x00\x01\x88v;Fd\
-\x00\x00\x09\xe2\x00\x00\x00\x00\x00\x01\x00\x01\xb1\xc8\
+\x00\x00\x0a\xec\x00\x00\x00\x00\x00\x01\x00\x01\xef{\
\x00\x00\x01\x88v;GI\
-\x00\x00\x1b\xbe\x00\x00\x00\x00\x00\x01\x00\x04\xcd2\
+\x00\x00\x1c\xc8\x00\x00\x00\x00\x00\x01\x00\x05\x0a\xe5\
\x00\x00\x01\x88v;FK\
-\x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x00\x16j\
+\x00\x00\x01z\x00\x00\x00\x00\x00\x01\x00\x00Ll\
\x00\x00\x01\x88v;GF\
-\x00\x00\x14V\x00\x00\x00\x00\x00\x01\x00\x03\x81\xda\
+\x00\x00\x15`\x00\x00\x00\x00\x00\x01\x00\x03\xbf\x8d\
\x00\x00\x01\x88v;F:\
-\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x01\x00\x05.T\
+\x00\x00\x1f\x0a\x00\x00\x00\x00\x00\x01\x00\x05l\x07\
\x00\x00\x01\x88v;F\xde\
-\x00\x00\x0b\xbe\x00\x00\x00\x00\x00\x01\x00\x02\x0b\xc9\
+\x00\x00\x0c\xc8\x00\x00\x00\x00\x00\x01\x00\x02I|\
\x00\x00\x01\x88v;F\xb0\
-\x00\x00\x14\x92\x00\x00\x00\x00\x00\x01\x00\x03\x89\x82\
+\x00\x00\x15\x9c\x00\x00\x00\x00\x00\x01\x00\x03\xc75\
\x00\x00\x01\x88v;GD\
-\x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x17f\
+\x00\x00\x01\xa2\x00\x00\x00\x00\x00\x01\x00\x00Mh\
\x00\x00\x01\x88v;F\xcf\
-\x00\x00\x0bL\x00\x00\x00\x00\x00\x01\x00\x01\xf5\x05\
+\x00\x00\x0cV\x00\x00\x00\x00\x00\x01\x00\x022\xb8\
\x00\x00\x01\x88v;FV\
-\x00\x00\x0b\x1c\x00\x00\x00\x00\x00\x01\x00\x01\xedz\
+\x00\x00\x0c&\x00\x00\x00\x00\x00\x01\x00\x02+-\
\x00\x00\x01\x88v;F\xef\
-\x00\x00\x10v\x00\x00\x00\x00\x00\x01\x00\x02\xddq\
+\x00\x00\x11\x80\x00\x00\x00\x00\x00\x01\x00\x03\x1b$\
\x00\x00\x01\x88v;FF\
-\x00\x00\x12\x10\x00\x00\x00\x00\x00\x01\x00\x03\x19G\
+\x00\x00\x13\x1a\x00\x00\x00\x00\x00\x01\x00\x03V\xfa\
\x00\x00\x01\x88v;G0\
-\x00\x00\x0d\xc6\x00\x00\x00\x00\x00\x01\x00\x02ml\
+\x00\x00\x0e\xd0\x00\x00\x00\x00\x00\x01\x00\x02\xab\x1f\
\x00\x00\x01\x88v;G\x12\
-\x00\x00\x0e\xf4\x00\x00\x00\x00\x00\x01\x00\x02\xa1\xdb\
+\x00\x00\x0f\xfe\x00\x00\x00\x00\x00\x01\x00\x02\xdf\x8e\
\x00\x00\x01\x88v;FC\
-\x00\x00\x15\xd4\x00\x00\x00\x00\x00\x01\x00\x03\xc4V\
+\x00\x00\x16\xde\x00\x00\x00\x00\x00\x01\x00\x04\x02\x09\
\x00\x00\x01\x88v;F\x16\
-\x00\x00\x0d\x1a\x00\x00\x00\x00\x00\x01\x00\x02O\x11\
+\x00\x00\x0e$\x00\x00\x00\x00\x00\x01\x00\x02\x8c\xc4\
\x00\x00\x01\x88v;F\xbd\
-\x00\x00\x11\x18\x00\x00\x00\x00\x00\x01\x00\x02\xf3\xd0\
+\x00\x00\x12\x22\x00\x00\x00\x00\x00\x01\x00\x031\x83\
\x00\x00\x01\x88v;F\xc0\
-\x00\x00\x1df\x00\x00\x00\x00\x00\x01\x00\x05\x10H\
+\x00\x00\x1ep\x00\x00\x00\x00\x00\x01\x00\x05M\xfb\
\x00\x00\x01\x88v;GB\
-\x00\x00\x18\x14\x00\x00\x00\x00\x00\x01\x00\x04%\xe4\
+\x00\x00\x19\x1e\x00\x00\x00\x00\x00\x01\x00\x04c\x97\
\x00\x00\x01\x88v;FJ\
-\x00\x00\x04\x1e\x00\x00\x00\x00\x00\x01\x00\x00\xac\xed\
+\x00\x00\x05\x06\x00\x00\x00\x00\x00\x01\x00\x00\xe2\xef\
\x00\x00\x01\x88v;F\x03\
-\x00\x00\x1a\xea\x00\x00\x00\x00\x00\x01\x00\x04\x9f\xdd\
+\x00\x00\x1b\xf4\x00\x00\x00\x00\x00\x01\x00\x04\xdd\x90\
\x00\x00\x01\x88v;G\x19\
-\x00\x00%2\x00\x00\x00\x00\x00\x01\x00\x06{,\
+\x00\x00&<\x00\x00\x00\x00\x00\x01\x00\x06\xb8\xdf\
\x00\x00\x01\x88v;F\xb5\
-\x00\x00\x18\x8a\x00\x00\x00\x00\x00\x01\x00\x045\x04\
+\x00\x00\x19\x94\x00\x00\x00\x00\x00\x01\x00\x04r\xb7\
\x00\x00\x01\x88v;Fx\
-\x00\x00\x1b\x94\x00\x00\x00\x00\x00\x01\x00\x04\xc5\xc3\
+\x00\x00\x1c\x9e\x00\x00\x00\x00\x00\x01\x00\x05\x03v\
\x00\x00\x01\x88v;G(\
-\x00\x00\x0c\x88\x00\x00\x00\x00\x00\x01\x00\x020\xaa\
+\x00\x00\x0d\x92\x00\x00\x00\x00\x00\x01\x00\x02n]\
\x00\x00\x01\x88v;F\xff\
-\x00\x00\x16\x22\x00\x00\x00\x00\x00\x01\x00\x03\xd38\
+\x00\x00\x17,\x00\x00\x00\x00\x00\x01\x00\x04\x10\xeb\
\x00\x00\x01\x88v;E\xf9\
-\x00\x00)X\x00\x00\x00\x00\x00\x01\x00\x075B\
+\x00\x00*b\x00\x00\x00\x00\x00\x01\x00\x07r\xf5\
\x00\x00\x01\x88v;Fi\
-\x00\x00\x07\xae\x00\x00\x00\x00\x00\x01\x00\x01PW\
+\x00\x00\x08\x96\x00\x00\x00\x00\x00\x01\x00\x01\x86Y\
\x00\x00\x01\x88v;F8\
-\x00\x00\x0en\x00\x00\x00\x00\x00\x01\x00\x02\x8b5\
+\x00\x00\x0fx\x00\x00\x00\x00\x00\x01\x00\x02\xc8\xe8\
\x00\x00\x01\x88v;F\xc9\
-\x00\x00\x1aV\x00\x00\x00\x00\x00\x01\x00\x04\x8aP\
+\x00\x00\x1b`\x00\x00\x00\x00\x00\x01\x00\x04\xc8\x03\
\x00\x00\x01\x88v;F>\
-\x00\x00\x0a\x8a\x00\x00\x00\x00\x00\x01\x00\x01\xcf\xbf\
+\x00\x00\x0b\x94\x00\x00\x00\x00\x00\x01\x00\x02\x0dr\
\x00\x00\x01\x88v;F\xe2\
-\x00\x00\x17Z\x00\x00\x00\x00\x00\x01\x00\x04\x08(\
+\x00\x00\x18d\x00\x00\x00\x00\x00\x01\x00\x04E\xdb\
\x00\x00\x01\x88v;F.\
-\x00\x00#\x16\x00\x00\x00\x00\x00\x01\x00\x06\x0eB\
+\x00\x00$ \x00\x00\x00\x00\x00\x01\x00\x06K\xf5\
\x00\x00\x01\x88v;GK\
-\x00\x00\x1b,\x00\x00\x00\x00\x00\x01\x00\x04\xaf\x09\
+\x00\x00\x1c6\x00\x00\x00\x00\x00\x01\x00\x04\xec\xbc\
\x00\x00\x01\x88v;F\x88\
-\x00\x00\x11\x80\x00\x00\x00\x00\x00\x01\x00\x03\x02\xc0\
+\x00\x00\x12\x8a\x00\x00\x00\x00\x00\x01\x00\x03@s\
\x00\x00\x01\x88v;F?\
-\x00\x00\x07X\x00\x00\x00\x00\x00\x01\x00\x01A\xd8\
+\x00\x00\x08@\x00\x00\x00\x00\x00\x01\x00\x01w\xda\
\x00\x00\x01\x88v;F\xb9\
-\x00\x00\x05P\x00\x00\x00\x00\x00\x01\x00\x00\xe0o\
+\x00\x00\x068\x00\x00\x00\x00\x00\x01\x00\x01\x16q\
\x00\x00\x01\x88v;G9\
-\x00\x00\x1b\xf0\x00\x00\x00\x00\x00\x01\x00\x04\xd4V\
+\x00\x00\x1c\xfa\x00\x00\x00\x00\x00\x01\x00\x05\x12\x09\
\x00\x00\x01\x88v;Fy\
-\x00\x00\x13L\x00\x00\x00\x00\x00\x01\x00\x03M\x85\
+\x00\x00\x14V\x00\x00\x00\x00\x00\x01\x00\x03\x8b8\
\x00\x00\x01\x88v;F\xd0\
-\x00\x00\x04\xac\x00\x00\x00\x00\x00\x01\x00\x00\xc2\xba\
+\x00\x00\x05\x94\x00\x00\x00\x00\x00\x01\x00\x00\xf8\xbc\
\x00\x00\x01\x88v;F\xf2\
-\x00\x00\x0a\xb6\x00\x00\x00\x00\x00\x01\x00\x01\xd7K\
+\x00\x00\x0b\xc0\x00\x00\x00\x00\x00\x01\x00\x02\x14\xfe\
\x00\x00\x01\x88v;F\xee\
-\x00\x00\x18\xca\x00\x00\x00\x00\x00\x01\x00\x04D\x07\
+\x00\x00\x19\xd4\x00\x00\x00\x00\x00\x01\x00\x04\x81\xba\
\x00\x00\x01\x88v;F\xd7\
-\x00\x00\x19\xb6\x00\x00\x00\x00\x00\x01\x00\x04q\x8f\
+\x00\x00\x1a\xc0\x00\x00\x00\x00\x00\x01\x00\x04\xafB\
\x00\x00\x01\x88v;G,\
-\x00\x00\x0dn\x00\x00\x00\x00\x00\x01\x00\x02^O\
+\x00\x00\x0ex\x00\x00\x00\x00\x00\x01\x00\x02\x9c\x02\
\x00\x00\x01\x88v;F\xcd\
-\x00\x00\x01\xae\x00\x00\x00\x00\x00\x01\x00\x00D\xf7\
+\x00\x00\x02\x96\x00\x00\x00\x00\x00\x01\x00\x00z\xf9\
\x00\x00\x01\x88v;F\xa9\
-\x00\x00\x068\x00\x00\x00\x00\x00\x01\x00\x01\x0d\xcb\
+\x00\x00\x07 \x00\x00\x00\x00\x00\x01\x00\x01C\xcd\
\x00\x00\x01\x88v;F@\
-\x00\x00\x13\xb6\x00\x00\x00\x00\x00\x01\x00\x03d<\
+\x00\x00\x14\xc0\x00\x00\x00\x00\x00\x01\x00\x03\xa1\xef\
\x00\x00\x01\x88v;F\x93\
-\x00\x00\x0cX\x00\x00\x00\x00\x00\x01\x00\x02)\x97\
+\x00\x00\x0db\x00\x00\x00\x00\x00\x01\x00\x02gJ\
\x00\x00\x01\x88v;F\x9c\
-\x00\x00\x1d\xe8\x00\x00\x00\x00\x00\x01\x00\x05'\x1c\
+\x00\x00\x1e\xf2\x00\x00\x00\x00\x00\x01\x00\x05d\xcf\
\x00\x00\x01\x88v;GA\
-\x00\x00%\x98\x00\x00\x00\x00\x00\x01\x00\x06\x8a\x15\
+\x00\x00&\xa2\x00\x00\x00\x00\x00\x01\x00\x06\xc7\xc8\
\x00\x00\x01\x88v;G\x09\
-\x00\x00\x0e\x14\x00\x00\x00\x00\x00\x01\x00\x02|/\
+\x00\x00\x0f\x1e\x00\x00\x00\x00\x00\x01\x00\x02\xb9\xe2\
\x00\x00\x01\x88v;Fg\
-\x00\x00#\xa0\x00\x00\x00\x00\x00\x01\x00\x06(\xc0\
+\x00\x00$\xaa\x00\x00\x00\x00\x00\x01\x00\x06fs\
\x00\x00\x01\x88v;F\x91\
-\x00\x00\x0a\xfc\x00\x00\x00\x00\x00\x01\x00\x01\xe5\xf2\
+\x00\x00\x0c\x06\x00\x00\x00\x00\x00\x01\x00\x02#\xa5\
\x00\x00\x01\x88v;F\xd3\
-\x00\x00\x1c\xc2\x00\x00\x00\x00\x00\x01\x00\x04\xf9\x88\
+\x00\x00\x1d\xcc\x00\x00\x00\x00\x00\x01\x00\x057;\
\x00\x00\x01\x88v;G+\
-\x00\x00\x18F\x00\x00\x00\x00\x00\x01\x00\x04-u\
+\x00\x00\x19P\x00\x00\x00\x00\x00\x01\x00\x04k(\
\x00\x00\x01\x88v;F^\
-\x00\x00\x1cJ\x00\x00\x00\x00\x00\x01\x00\x04\xe3\x1b\
+\x00\x00\x1dT\x00\x00\x00\x00\x00\x01\x00\x05 \xce\
\x00\x00\x01\x88v;F\xe3\
-\x00\x00\x17\x0c\x00\x00\x00\x00\x00\x01\x00\x03\xf9?\
+\x00\x00\x18\x16\x00\x00\x00\x00\x00\x01\x00\x046\xf2\
\x00\x00\x01\x88v;F\xf1\
-\x00\x00\x07\x84\x00\x00\x00\x00\x00\x01\x00\x01I\x13\
+\x00\x00\x08l\x00\x00\x00\x00\x00\x01\x00\x01\x7f\x15\
\x00\x00\x01\x88v;F\xba\
-\x00\x00\x08N\x00\x00\x00\x00\x00\x01\x00\x01g\x09\
+\x00\x00\x096\x00\x00\x00\x00\x00\x01\x00\x01\x9d\x0b\
\x00\x00\x01\x88v;G\x08\
"
diff --git a/src/CaptDeviceControl/view/AD2CaptDeviceView.py b/src/CaptDeviceControl/view/AD2CaptDeviceView.py
index 4246c8d339b5a29ee845b219ff920b263e9be2e2..eb5aab560f8392234d05e546e354982dea2486af 100644
--- a/src/CaptDeviceControl/view/AD2CaptDeviceView.py
+++ b/src/CaptDeviceControl/view/AD2CaptDeviceView.py
@@ -16,12 +16,17 @@ from CaptDeviceControl.controller.BaseAD2CaptDevice import BaseAD2CaptDevice
from CaptDeviceControl.model.AD2CaptDeviceModel import AD2CaptDeviceModel
from CaptDeviceControl.model.AD2Constants import AD2Constants
from CaptDeviceControl.view.Ui_AD2ControlWindow import Ui_AD2ControlWindow
+from CaptDeviceControl.view.Ui_AD2ControlWindowNew import Ui_AD2ControlWindowNew
from CaptDeviceControl.view.widget.WidgetCapturingInformation import WidgetCapturingInformation, WidgetDeviceInformation
-from CaptDeviceControl.constants.dwfconstants import DwfStateReady, DwfStateConfig, DwfStatePrefill, DwfStateArmed, DwfStateWait, \
+from CaptDeviceControl.constants.dwfconstants import DwfStateReady, DwfStateConfig, DwfStatePrefill, DwfStateArmed, \
+ DwfStateWait, \
DwfStateTriggered, DwfStateRunning, DwfStateDone
from fswidgets import PlayPushButton
+from model.submodels.AD2CaptDeviceAnalogInModel import AD2CaptDeviceAnalogInModel
+from model.submodels.AD2CaptDeviceCapturingModel import AD2CaptDeviceCapturingModel
+
class ControlWindow(QMainWindow):
@@ -37,9 +42,9 @@ class ControlWindow(QMainWindow):
self.controller = controller
self.model = model
- self._ui = Ui_AD2ControlWindow()
+ self._ui = Ui_AD2ControlWindowNew()
self._ui.setupUi(self)
- # self._ui.btn_start_capture = PlayPushButton(self._ui.btn_start_capture)
+ # self._ui.btn_start_capture = PlayPushButton(self._ui.btn_start_capture)
#
@@ -58,92 +63,257 @@ class ControlWindow(QMainWindow):
# Timer for periodically updating the plot
self.capture_update_timer = QTimer()
self.capture_update_timer.setInterval(10)
- #self.capture_update_timer.timeout.connect(self._on_capture_update_plot)
+ self.capture_update_timer.timeout.connect(self._on_capture_update_plot)
self.stream_update_timer = QTimer()
self.stream_update_timer.setInterval(40)
self.stream_update_timer.timeout.connect(self._on_stream_update_timer_timeout)
+ # self.stream_update_timer.start()
self.stream_samples_frequency = 1000
self.stream_n = 1
# Connect the signals and controls
+ self._connect_config_properties()
self._connect_controls()
self._connect_signals()
- self._init_other_ui_elements()
- self._ui.cb_duration_streaming_history.setCurrentIndex(5)
+ # self._init_other_ui_elements()
+ # self._ui.cb_duration_streaming_history.setCurrentIndex(5)
self.controller.discover_connected_devices()
-
- self.model.sample_rate = self.model.ad2captdev_config.sample_rate.value
+ self._ui.sb_acquisition_rate.setValue(self.model.capturing_information.sample_rate)
+ # self._ui.cb_duration_streaming_history.set(self.model.capturing_information.streaming_history)
# ==================================================================================================================
#
# ==================================================================================================================
+ def _add_menues(self):
+ pass
+
+ def _connect_config_properties(self):
+ # Connect the Controls that are also Settings
+ self.model.ad2captdev_config.streaming_history.view.add_new_view(self._ui.cb_streaming_history)
+
+ # Selected Analog IN Channel
+ self.model.ad2captdev_config.ain_channel.view.add_new_view(self._ui.cb_channel_select)
+ # self.model.ad2captdev_config.ain_channel.connect_property(
+ # self.model.analog_in, AD2CaptDeviceAnalogInModel.selected_ain_channel,
+ # )
+
def _connect_controls(self):
- self._ui.btn_connect.clicked.connect(self.on_btn_connect_to_device_clicked)
- self._ui.btn_start_capture.clicked.connect(self.on_btn_start_capture_clicked)
- self._ui.btn_stop.clicked.connect(self.on_btn_stop_clicked)
+ self._ui.cb_device_select.currentIndexChanged.connect(self._on_ui_selected_index_changed)
- self._ui.cb_device_select.currentIndexChanged.connect(self._on_device_selected_changed)
- self._ui.cb_channel_select.currentIndexChanged.connect(self._ui_on_selected_ain_changed)
+ self._ui.btn_connect.clicked.connect(self._on_ui_btn_connect_clicked)
- self._ui.sb_acquisition_rate.valueChanged.connect(self._ui_on_sample_rate_changed)
- #self.model.ad2captdev_config.sample_rate.view.add_new_view(self._ui.sb_acquisition_rate)
+ self._ui.sb_acquisition_rate.valueChanged.connect(self._on_ui_sample_rate_changed)
- #self.model.ad2captdev_config.ain_channel.view.add_new_view(self._ui.cb_channel_select)
- #()
+ # Connect the buttons
+ #self._ui.btn_stop.clicked.connect(self.on_btn_stop_clicked)
+ self._ui.btn_play.clicked.connect(
+ lambda: self.controller.start_capturing_process(
+ self.model.capturing_information.sample_rate,
+ self.model.analog_in.selected_ain_channel)
+ )
+ self._ui.btn_record.clicked.connect(self._ui_on_btn_recording_clicked)
+ self._ui.btn_reset.clicked.connect(self._ui_on_btn_reset_clicked)
- self._ui.cb_duration_streaming_history.currentIndexChanged.connect(
- self._on_cb_duration_streaming_history_currentIndexChanged)
+ # self._ui.cb_channel_select.currentIndexChanged.connect(self._ui_on_selected_ain_changed)
def _connect_signals(self):
- # WaveForms Runtime (DWF) Information
self.model.signals.dwf_version_changed.connect(self._on_dwf_version_changed)
- # Connected Device Information
- self.model.device_information.signals.num_of_connected_devices_changed.connect(self._on_num_of_connected_devices_changed)
self.model.device_information.signals.connected_devices_changed.connect(self._on_connected_devices_changed)
-
- # Device information
+ self.model.device_information.signals.device_state_changed.connect(self._on_device_state_changed)
self.model.device_information.signals.device_connected_changed.connect(self._on_connected_changed)
+ self.model.capturing_information.signals.sample_rate_changed.connect(self._on_model_sample_rate_changed)
+ self.model.capturing_information.signals.device_capturing_state_changed.connect(
+ self._on_capture_process_state_changed)
+
+ # # WaveForms Runtime (DWF) Information
+ # # Connected Device Information
+ # self.model.device_information.signals.num_of_connected_devices_changed.connect(self._on_num_of_connected_devices_changed)
+ # #self.model.device_information.signals.discovered_devices_changed.connect(self._on_connected_devices_changed)
+ # Device information
self.model.device_information.signals.device_name_changed.connect(self._on_device_name_changed)
- self.model.device_information.signals.device_serial_number_changed.connect(self._on_device_serial_number_changed)
- self.model.device_information.signals.device_index_changed.connect(self._on_device_index_changed)
+ self.model.device_information.signals.device_serial_number_changed.connect(
+ self._on_device_serial_number_changed)
+ # self.model.device_information.signals.device_index_changed.connect(self._on_device_index_changed)
+ # self.model.device_information.selected_device_index_changed.connect(self._on_selected_device_index_changed)
+ # # Acquisition Settings
+ # self.model.capturing_information.signals.streaming_history.connect(self.)
+ # # Analog In Information
+ # self.model.analog_in.signals.selected_ain_channel_changed.connect(self._model_on_selected_ain_changed)
+ # self.model.analog_in.signals.ain_channels_changed.connect(self._on_ain_channels_changed)
+ # self.model.analog_in.signals.ain_buffer_size_changed.connect(self._on_ain_buffer_size_changed)
+ # self.model.analog_in.signals.ain_bits_changed.connect(self._on_ain_bits_changed)
+ # self.model.analog_in.signals.ain_device_state_changed.connect(self._on_ain_device_state_changed)
+ # # Analog Out Information
+ # self.model.signals.aout_channels_changed.connect(self._on_aout_channels_changed)
+ # # Acquired Signal Information
+ # #self.model.signals.recorded_samples_changed.connect(self._on_recorded_samples_changed)
+ # #self.model.signals.recording_time_changed.connect(self._on_recording_time_changed)
+ # #self.model.signals.samples_captured_changed.connect(self._on_samples_captured_changed)
+ # self.model.signals.samples_lost_changed.connect(self._on_samples_lost_changed)
+ # self.model.signals.samples_corrupted_changed.connect(self._on_samples_corrupted_changed)
+ # # Recording Flags (starting, stopping and pausing)
+ # self.model.signals.device_capturing_state_changed.connect(self._on_device_capturing_state_changed)
+ # self.model.signals.start_recording_changed.connect(self._on_start_recording_changed)
+ # self.model.signals.stop_recording_changed.connect(self._on_stop_recording_changed)
+ # self.model.signals.reset_recording_changed.connect(self._on_reset_recording_changed)
+ # # Multiprocessing Information
+ # self.model.signals.pid_changed.connect(self._on_pid_changed)
+ # # Plotting Timer (periodically updating the plot)
+ # # self.capture_update_timer.timeout.connect(self._on_capture_update_plot)
+
+ def _on_dwf_version_changed(self, dwf_version):
+ """
+ Gets called if the DWF version changes. Updates the UI.
+ :param dwf_version: The DWF version
+ """
+ self.dev_info.dwf_version = dwf_version
+
+ def _on_connected_devices_changed(self, connected_devices: list):
+ """
+ Gets called if the connected devices changed. Populates the combobox with the list of the connected devices.
+ :param connected_devices:
+ :return:
+ """
+ self._ui.cb_device_select.clear()
+ for it, dev in enumerate(connected_devices):
+ dev: dict
+ # 'type': type, 'device_id', 'device_name', 'serial_number'
+ self._ui.cb_device_select.addItem(f"{it}: {dev['type']}{dev['device_id']} - {dev['device_name']}")
+ self._ui.cb_device_select.setCurrentIndex(0)
+
+ def _on_device_state_changed(self, capturing):
+ if capturing == AD2Constants.DeviceState.ACQ_NOT_STARTED():
+ self.capt_info.led_device_state.set_color(color="yellow")
+ self.capt_info.lbl_device_state.setText(AD2Constants.DeviceState.ACQ_NOT_STARTED(True))
+ elif capturing == AD2Constants.DeviceState.NO_SAMPLES_AVAILABLE:
+ self.capt_info.led_device_state.set_color(color="red")
+ self.capt_info.lbl_device_state.setText(AD2Constants.DeviceState.NO_SAMPLES_AVAILABLE(True))
+ elif capturing == AD2Constants.DeviceState.SAMPLES_AVAILABLE():
+ self.capt_info.led_device_state.set_color(color="green")
+ self.capt_info.lbl_device_state.setText(AD2Constants.DeviceState.SAMPLES_AVAILABLE(True))
+ elif capturing == AD2Constants.DeviceState.DEV_CAPT_SETUP():
+ self.capt_info.led_device_state.set_color(color="yellow")
+ self.capt_info.lbl_device_state.setText(AD2Constants.DeviceState.DEV_CAPT_SETUP(True))
+ self._ui.btn_pause.setEnabled(True)
+ self._ui.btn_stop.setEnabled(True)
+ self._ui.btn_record.setEnabled(False)
+ self._ui.btn_reset.setEnabled(False)
+ self._ui.btn_play.setEnabled(False)
+ elif capturing == AD2Constants.DeviceState.DEV_CAPT_STREAMING():
+ self.capt_info.led_device_state.set_color(color="green")
+ self.capt_info.lbl_device_state.setText(AD2Constants.DeviceState.DEV_CAPT_STREAMING(True))
+ self._ui.btn_pause.setEnabled(True)
+ self._ui.btn_stop.setEnabled(True)
+ self._ui.btn_record.setEnabled(True)
+ self._ui.btn_reset.setEnabled(True)
+ self._ui.btn_play.setEnabled(True)
+ self._ui.btn_play.setChecked(True)
+ self.stream_update_timer.start()
+
+ # ==================================================================================================================
+ # UI Slots
+ # ==================================================================================================================
+ def _on_ui_btn_connect_clicked(self):
+ if self.model.device_information.device_connected:
+ self.controller.close_device()
+ self._ui.btn_connect.setText("Connect")
+ else:
+ try:
+ self.controller.open_device(self.model.device_information.selected_device_index)
+ self.controller.start_capturing_process(
+ self.model.capturing_information.sample_rate
+ )
+ except Exception as e:
+ self.logger.error(f"Error: {e}")
+ self._ui.btn_connect.setText("Disconnect")
+
+ def _on_ui_sample_rate_changed(self, sample_rate: int):
+ self.model.sample_rate = sample_rate
+
+ def _on_model_sample_rate_changed(self, sample_rate: int):
+ self._ui.sb_acquisition_rate.setRange(1, 1e9)
+ self._ui.sb_acquisition_rate.setValue(sample_rate)
+
+ def _ui_on_btn_recording_clicked(self):
+ if self._ui.btn_record.isChecked():
+ print("Start Recording")
+ self.capture_update_timer.start()
+ self.controller.start_capture()
+ else:
+ print("Stop Recording")
+ #self._ui.btn_record.setChecked(False)
+ self.controller.stop_capture()
+
+ def _ui_on_btn_reset_clicked(self):
+ self.controller.reset_capture()
+
+ # ==================================================================================================================
+ # Device information changed
+ # ==================================================================================================================
+ def _on_connected_changed(self, connected):
+ if connected:
+ self.capt_info.lbl_conn_state.setText("Connected")
+ self.capt_info.led_conn_state.set_color(color="green")
+ self._ui.btn_pause.setEnabled(False)
+ self._ui.btn_stop.setEnabled(False)
+ self._ui.btn_record.setEnabled(False)
+ self._ui.btn_reset.setEnabled(False)
+ self._ui.btn_play.setEnabled(True)
+ self._ui.btn_connect.setText("Disconnect")
+ else:
+ self.capt_info.lbl_conn_state.setText("Not connected")
+ self._ui.btn_connect.setText("Connect")
+ self._ui.btn_pause.setEnabled(False)
+ self._ui.btn_stop.setEnabled(False)
+ self._ui.btn_record.setEnabled(False)
+ self._ui.btn_reset.setEnabled(False)
+ self._ui.btn_play.setEnabled(False)
+ self.capt_info.led_conn_state.set_color(color="red")
+
+ # ============== Recording Flags (starting, stopping and pausing)
+ def _on_capture_process_state_changed(self, capturing):
+ if capturing == AD2Constants.CapturingState.RUNNING():
+ self.capt_info.led_is_capt.set_color(color="green")
+ self.capt_info.lbl_is_capt.setText(AD2Constants.CapturingState.RUNNING(True))
+ self._ui.btn_record.setChecked(True)
+ elif capturing == AD2Constants.CapturingState.PAUSED():
+ self.capt_info.led_is_capt.set_color(color="yellow")
+ self.capt_info.lbl_is_capt.setText(AD2Constants.CapturingState.PAUSED(True))
+ elif capturing == AD2Constants.CapturingState.STOPPED():
+ self.capt_info.led_is_capt.set_color(color="red")
+ self.capt_info.lbl_is_capt.setText(AD2Constants.CapturingState.STOPPED(True))
+ self._ui.btn_record.setChecked(False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- # Acquisition Settings
- self.model.signals.sample_rate_changed.connect(self._model_on_sample_rate_changed)
- # Analog In Information
- self.model.analog_in.signals.selected_ain_channel_changed.connect(self._model_on_selected_ain_changed)
- self.model.analog_in.signals.ain_channels_changed.connect(self._on_ain_channels_changed)
- self.model.analog_in.signals.ain_buffer_size_changed.connect(self._on_ain_buffer_size_changed)
- self.model.analog_in.signals.ain_bits_changed.connect(self._on_ain_bits_changed)
- self.model.analog_in.signals.ain_device_state_changed.connect(self._on_ain_device_state_changed)
- # Analog Out Information
- self.model.signals.aout_channels_changed.connect(self._on_aout_channels_changed)
- # Acquired Signal Information
- #self.model.signals.recorded_samples_changed.connect(self._on_recorded_samples_changed)
- #self.model.signals.recording_time_changed.connect(self._on_recording_time_changed)
- #self.model.signals.samples_captured_changed.connect(self._on_samples_captured_changed)
- self.model.signals.samples_lost_changed.connect(self._on_samples_lost_changed)
- self.model.signals.samples_corrupted_changed.connect(self._on_samples_corrupted_changed)
- # Recording Flags (starting, stopping and pausing)
- self.model.signals.device_capturing_state_changed.connect(self._on_device_capturing_state_changed)
- self.model.signals.start_recording_changed.connect(self._on_start_recording_changed)
- self.model.signals.stop_recording_changed.connect(self._on_stop_recording_changed)
- self.model.signals.reset_recording_changed.connect(self._on_reset_recording_changed)
- # Multiprocessing Information
- self.model.signals.pid_changed.connect(self._on_pid_changed)
- # Plotting Timer (periodically updating the plot)
- # self.capture_update_timer.timeout.connect(self._on_capture_update_plot)
# ==================================================================================================================
#
@@ -168,64 +338,35 @@ class ControlWindow(QMainWindow):
return area
- def _init_other_ui_elements(self):
- self._ui.cb_duration_streaming_history.addItem("100ms", 0.1)
- self._ui.cb_duration_streaming_history.addItem("200ms", 0.2)
- self._ui.cb_duration_streaming_history.addItem("500ms", 0.5)
- self._ui.cb_duration_streaming_history.addItem("1s", 1)
- self._ui.cb_duration_streaming_history.addItem("2s", 2)
- self._ui.cb_duration_streaming_history.addItem("5s", 5)
- self._ui.cb_duration_streaming_history.addItem("10s", 10)
- self._ui.cb_duration_streaming_history.addItem("20s", 20)
- self._ui.cb_duration_streaming_history.addItem("30s", 30)
- self._ui.cb_duration_streaming_history.addItem("1min", 60)
- self._ui.cb_duration_streaming_history.addItem("2min", 120)
- self._ui.cb_duration_streaming_history.addItem("5min", 300)
+ # def _init_other_ui_elements(self):
+ # self._ui.cb_duration_streaming_history.addItem("100ms", 0.1)
+ # self._ui.cb_duration_streaming_history.addItem("200ms", 0.2)
+ # self._ui.cb_duration_streaming_history.addItem("500ms", 0.5)
+ # self._ui.cb_duration_streaming_history.addItem("1s", 1)
+ # self._ui.cb_duration_streaming_history.addItem("2s", 2)
+ # self._ui.cb_duration_streaming_history.addItem("5s", 5)
+ ## self._ui.cb_duration_streaming_history.addItem("10s", 10)
+ # self._ui.cb_duration_streaming_history.addItem("20s", 20)
+ # self._ui.cb_duration_streaming_history.addItem("30s", 30)
+ # self._ui.cb_duration_streaming_history.addItem("1min", 60)
+ # self._ui.cb_duration_streaming_history.addItem("2min", 120)
+ # self._ui.cb_duration_streaming_history.addItem("5min", 300)
# ==================================================================================================================
# Slots for Model
# ==================================================================================================================
- def _on_device_selected_changed(self, index):
- self.model.device_information.device_index = index
- self.controller.device_selected_index_changed()
+ def _on_ui_selected_index_changed(self, index):
+ self.controller.selected_device_index(index)
+ # self.controller.device_selected_index_changed()
+ # self.controller.mpcaptdevicecontrol.selected_device_index(index)
# First populate the AIn box+
- #m: dict = self.model.connected_devices[index]
- #self.model.ain_channels = list(range(0, int(m['analog_in_channels'])))
-
-
- def _on_dwf_version_changed(self, dwf_version):
- self.dev_info.dwf_version = dwf_version
- # self.ad2_settings['DWF Version'] = dwf_version
- # self.update_ad2_settings_list_view()
+ # m: dict = self.model.connected_devices[index]
+ # self.model.ain_channels = list(range(0, int(m['analog_in_channels'])))
# ============== Connected Device Information
def _on_num_of_connected_devices_changed(self, num_of_connected_devices):
pass
- def _on_connected_devices_changed(self, connected_devices: list):
- self._ui.cb_device_select.clear()
- for it, dev in enumerate(connected_devices):
- dev: dict
- # 'type': type, 'device_id', 'device_name', 'serial_number'
- self._ui.cb_device_select.addItem(f"{it}: {dev['type']}{dev['device_id']} - {dev['device_name']}")
- self._ui.cb_device_select.setCurrentIndex(0)
-
- # ============== Device information
- def _on_connected_changed(self, connected):
- if connected:
- self.capt_info.lbl_conn_state.setText("Connected")
- self.capt_info.led_conn_state.set_color(color="green")
- self._ui.btn_start_capture.setEnabled(True)
- self._ui.btn_connect.setText("Disconnect")
- self.stream_update_timer.start()
- self.capture_update_timer.start()
- else:
- self.capt_info.lbl_conn_state.setText("Not connected")
- self._ui.btn_connect.setText("Connect")
- self._ui.btn_start_capture.setEnabled(False)
- self._ui.btn_stop.setEnabled(False)
- self.capt_info.led_conn_state.set_color(color="red")
-
def _on_device_name_changed(self, device_name):
self.dev_info.device_name = device_name
# self.ad2_settings['Device Name'] = device_name
@@ -236,31 +377,21 @@ class ControlWindow(QMainWindow):
# self.ad2_settings['Serial Number'] = serial_number
self.update_ad2_settings_list_view()
- def _on_device_index_changed(self, device_index):
- print(device_index)
-
# ============== Acquisition Settings
-
- def _model_on_sample_rate_changed(self, sample_rate: int):
- self._ui.sb_acquisition_rate.setRange(1, 1e9)
- self._ui.sb_acquisition_rate.setValue(sample_rate)
-
- def _ui_on_sample_rate_changed(self, sample_rate: int):
- self.model.sample_rate = sample_rate
-
def _model_on_selected_ain_changed(self, channel):
""" Gets called if the model is changed directly (should modify the UI)"""
self._on_selected_ain_channel_changed(channel)
self._ui.cb_channel_select.setCurrentIndex(channel)
+
def _ui_on_selected_ain_changed(self, channel):
""" Gets called if the ui changes the field (should modify the model) """
self._on_selected_ain_channel_changed(channel)
self.model.selected_ain_channel = channel
+
def _on_selected_ain_channel_changed(self, channel):
self.dev_info.analog_in_channel = channel
-
# ============== Analog In Information
def _on_ain_channels_changed(self, list_of_ad_ins):
self._ui.cb_channel_select.clear()
@@ -323,8 +454,8 @@ class ControlWindow(QMainWindow):
# ============== Acquired Signal Information
def _on_recorded_samples_changed(self, recorded_samples):
pass
- #print(recorded_samples)
- #self._ui.lcd_captured_samples.display(len(recorded_samples))
+ # print(recorded_samples)
+ # self._ui.lcd_captured_samples.display(len(recorded_samples))
def _on_recording_time_changed(self, recording_time):
self._ui.lcd_sampled_time.display(recording_time)
@@ -339,24 +470,11 @@ class ControlWindow(QMainWindow):
def _on_samples_corrupted_changed(self, samples_corrupted):
self._ui.lcd_samples_corrupted.display(samples_corrupted)
- # ============== Recording Flags (starting, stopping and pausing)
- def _on_device_capturing_state_changed(self, capturing):
- if capturing == AD2Constants.CapturingState.RUNNING():
- self.capt_info.led_is_capt.set_color(color="green")
- self.capt_info.lbl_is_capt.setText(AD2Constants.CapturingState.RUNNING(True))
- elif capturing == AD2Constants.CapturingState.PAUSED():
- self.capt_info.led_is_capt.set_color(color="yellow")
- self.capt_info.lbl_is_capt.setText(AD2Constants.CapturingState.PAUSED(True))
- elif capturing == AD2Constants.CapturingState.STOPPED():
- self.capt_info.led_is_capt.set_color(color="red")
- self.capt_info.lbl_is_capt.setText(AD2Constants.CapturingState.STOPPED(True))
- self.update_ad2_settings_list_view()
-
def _on_start_recording_changed(self, start_recording):
self.logger.debug(f"Start Recording: {start_recording}")
if start_recording:
self._ui.btn_stop.setEnabled(True)
- #self._ui.btn_start_capture.setStyleSheet(PlayPushButton.style_pause())
+ # self._ui.btn_start_capture.setStyleSheet(PlayPushButton.style_pause())
self._ui.btn_start_capture.pause()
self._ui.btn_start_capture.setText("Pause Capture")
@@ -364,13 +482,13 @@ class ControlWindow(QMainWindow):
self.logger.debug(f"Stop Recording: {stop_recording}")
if stop_recording:
self._ui.btn_stop.setEnabled(False)
- #self._ui.btn_start_capture.setStyleSheet(CSSPlayPushButton.style_play())
+ # self._ui.btn_start_capture.setStyleSheet(CSSPlayPushButton.style_play())
self._ui.btn_start_capture.play()
self._ui.btn_start_capture.setText("Start Capture")
def _on_pause_recording_changed(self, pause_recording):
self._ui.btn_stop.setEnabled(True)
- #self._ui.btn_start_capture.setStyleSheet(CSSPlayPushButton.style_play())
+ # self._ui.btn_start_capture.setStyleSheet(CSSPlayPushButton.style_play())
self._ui.btn_start_capture.play()
def _on_reset_recording_changed(self, reset_recording):
@@ -383,76 +501,46 @@ class ControlWindow(QMainWindow):
# ============== Plotting
def _on_capture_update_plot(self):
- if len(self.model.recorded_samples) > 0:
+ if len(self.model.capturing_information.recorded_samples) > 0:
self.scope_captured.clear()
# print(self.ad2device.recorded_samples)
- d = self.model.recorded_samples[::self.stream_n]
+ d = self.model.capturing_information.recorded_samples[::self.stream_n]
self.scope_captured.plot(
- x=np.arange(0, len(d))/self.stream_samples_frequency,
+ x=np.arange(0, len(d)) / self.stream_samples_frequency,
y=d, pen=pg.mkPen(width=1)
)
# print(f"Length: {len(self.controller.recorded_sample_stream)}")
- if len(self.controller.status_dqueue) > 0:
+ #if len(self.controller.status_dqueue) > 0:
# print(self.controller.status_dqueue)
- self.model.samples_captured = self.controller.status_dqueue[-1]["captured"]
+ # self.model.samples_captured = self.controller.status_dqueue[-1]["captured"]
# self.model.samples_lost = d[1]["lost"]
# self.model.samples_corrupted = d[1]["corrupted"]
- self._ui.lcd_unconsumed_capture.display(self.model.unconsumed_capture_samples)
+ #self._ui.lcd_unconsumed_capture.display(self.model.unconsumed_capture_samples)
def _on_stream_update_timer_timeout(self):
self.scope_original.clear()
# print(self.ad2device.recorded_samples)
+
self.scope_original.plot(
- np.array(self.controller.streaming_data_dqueue),#[::100],
+ np.array(self.controller.streaming_dqueue), # [::100],
pen=pg.mkPen(width=1))
- self._ui.lcd_unconsumed_stream.display(self.model.unconsumed_stream_samples)
-
+ # self._ui.lcd_unconsumed_stream.display(self.model.capturing_information.unconsumed_stream_samples)
# ==================================================================================================================
#
# ==================================================================================================================
- def on_btn_connect_to_device_clicked(self):
- print(self.model.device_information.device_connected)
- if self.model.device_information.device_connected:
- self.controller.close_device()
- self._ui.btn_connect.setText("Connect")
- else:
- try:
- self.controller.connect_device(self._ui.cb_device_select.currentIndex())
- # self.plot_update_timer.setInterval(0.1)
- #self.stream_n = int(self.model.sample_rate / self.stream_samples_frequency)
- except Exception as e:
- # self.status_bar.setStyleSheet('border: 0; color: red;')
- # self.status_bar.showMessage(f"Error: {e}")
- self.logger.error(f"Error: {e}")
- self._ui.btn_connect.setText("Disconnect")
-
- def on_btn_start_capture_clicked(self):
- if self.model.device_capturing_state == AD2Constants.CapturingState.STOPPED() or \
- self.model.device_capturing_state == AD2Constants.CapturingState.PAUSED():
- self.controller.start_capture(clear=self.model.reset_recording)
- elif self.model.device_capturing_state == AD2Constants.CapturingState.RUNNING():
- self.model.reset_recording = False
- self.controller.stop_capture()
-
- def on_btn_stop_clicked(self):
-
- self.model.reset_recording = True
- self.controller.stop_capture()
- self._ui.btn_start_capture.setText("Start Capture")
- self._ui.btn_stop.setEnabled(False)
- self.capture_update_timer.stop()
- self.scope_captured.clear()
- self.scope_captured.plot(self.model.recorded_samples, pen=pg.mkPen(width=1))
def closeEvent(self, event):
super(ControlWindow, self).closeEvent(event)
- def _on_cb_duration_streaming_history_currentIndexChanged(self, index):
- self.model.duration_streaming_history = self._ui.cb_duration_streaming_history.currentData()
- self.controller.streaming_data_dqueue = deque(maxlen=int(self.model.duration_streaming_history * self.model.sample_rate))
+ # def _on_cb_duration_streaming_history_currentIndexChanged(self, index):#
+ # self.model.duration_streaming_history = self._ui.cb_duration_streaming_history.currentData()
+ # self.controller.streaming_dqueue = deque(
+ # maxlen=int(
+ # self.model.duration_streaming_history *
+ # self.model.capturing_information.streaming_history))
# ==================================================================================================================
#
@@ -486,4 +574,3 @@ class ControlWindow(QMainWindow):
print("Destroyed")
self.controller.exit()
self.destroyed.emit()
-
\ No newline at end of file
diff --git a/src/CaptDeviceControl/view/Ui_AD2ControlWindow.py b/src/CaptDeviceControl/view/Ui_AD2ControlWindow.py
index 288514f9ea6b59555137c84a7eb29ee8c121f513..eefbb039e0a035ec32181a023b0245475f4973c6 100644
--- a/src/CaptDeviceControl/view/Ui_AD2ControlWindow.py
+++ b/src/CaptDeviceControl/view/Ui_AD2ControlWindow.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'AD2ControlWindow.ui'
##
-## Created by: Qt User Interface Compiler version 6.5.3
+## Created by: Qt User Interface Compiler version 6.6.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
diff --git a/src/CaptDeviceControl/view/widget/WidgetCapturingInformation.py b/src/CaptDeviceControl/view/widget/WidgetCapturingInformation.py
index cd76bd5351740fc8975335ce602a35de9cbede72..775551ea09498327e4f2d0b69af323a671835f23 100644
--- a/src/CaptDeviceControl/view/widget/WidgetCapturingInformation.py
+++ b/src/CaptDeviceControl/view/widget/WidgetCapturingInformation.py
@@ -19,16 +19,17 @@ class WidgetCapturingInformation(QWidget):
layout.addWidget(self.led_conn_state, 0, 0)
layout.addWidget(self.lbl_conn_state, 0, 1)
+ self.lbl_is_capt = QLabel("Not capturing")
+ self.led_is_capt = LEDIndicatorWidget(color="red")
+ layout.addWidget(self.led_is_capt, 1, 0)
+ layout.addWidget(self.lbl_is_capt, 1, 1)
self.lbl_device_state = QLabel("Device State Unknown")
self.led_device_state = LEDIndicatorWidget(color="gray")
layout.addWidget(self.led_device_state, 2, 0)
layout.addWidget(self.lbl_device_state, 2, 1)
- self.lbl_is_capt = QLabel("Not capturing")
- self.led_is_capt = LEDIndicatorWidget(color="red")
- layout.addWidget(self.led_is_capt, 1, 0)
- layout.addWidget(self.lbl_is_capt, 1, 1)
+
grid_group_box.setLayout(layout)
self.layout.addWidget(grid_group_box)