biosignal-device-interface 0.1.311__py3-none-any.whl → 0.2.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- biosignal_device_interface/constants/devices/core/base_device_constants.py +10 -0
- biosignal_device_interface/constants/devices/otb/otb_quattrocento_constants.py +313 -0
- biosignal_device_interface/constants/devices/otb/otb_syncstation_constants.py +233 -0
- biosignal_device_interface/devices/__init__.py +2 -0
- biosignal_device_interface/devices/core/base_device.py +5 -3
- biosignal_device_interface/devices/otb/__init__.py +8 -0
- biosignal_device_interface/devices/otb/otb_muovi.py +4 -5
- biosignal_device_interface/devices/otb/otb_quattrocento.py +332 -0
- biosignal_device_interface/devices/otb/otb_quattrocento_light.py +4 -7
- biosignal_device_interface/devices/otb/otb_syncstation.py +407 -0
- biosignal_device_interface/gui/device_template_widgets/all_devices_widget.py +8 -0
- biosignal_device_interface/gui/device_template_widgets/core/base_device_widget.py +17 -8
- biosignal_device_interface/gui/device_template_widgets/otb/otb_devices_widget.py +8 -0
- biosignal_device_interface/gui/device_template_widgets/otb/otb_muovi_plus_widget.py +9 -9
- biosignal_device_interface/gui/device_template_widgets/otb/otb_muovi_widget.py +9 -9
- biosignal_device_interface/gui/device_template_widgets/otb/otb_quattrocento_light_widget.py +59 -55
- biosignal_device_interface/gui/device_template_widgets/otb/otb_quattrocento_widget.py +260 -0
- biosignal_device_interface/gui/device_template_widgets/otb/otb_syncstation_widget.py +262 -0
- biosignal_device_interface/gui/plot_widgets/biosignal_plot_widget.py +2 -1
- biosignal_device_interface/gui/ui/otb_quattrocento_template_widget.ui +415 -0
- biosignal_device_interface/gui/ui/otb_syncstation_template_widget.ui +732 -0
- biosignal_device_interface/gui/ui_compiled/otb_quattrocento_template_widget.py +318 -0
- biosignal_device_interface/gui/ui_compiled/otb_syncstation_template_widget.py +495 -0
- biosignal_device_interface-0.2.1a1.dist-info/LICENSE +675 -0
- {biosignal_device_interface-0.1.311.dist-info → biosignal_device_interface-0.2.1a1.dist-info}/METADATA +5 -3
- {biosignal_device_interface-0.1.311.dist-info → biosignal_device_interface-0.2.1a1.dist-info}/RECORD +27 -17
- biosignal_device_interface-0.1.311.dist-info/LICENSE +0 -395
- {biosignal_device_interface-0.1.311.dist-info → biosignal_device_interface-0.2.1a1.dist-info}/WHEEL +0 -0
|
@@ -16,9 +16,11 @@ class DeviceType(Enum):
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
_init_ = "value __doc__"
|
|
19
|
+
OTB_QUATTROCENTO = auto(), "OT Bioelettronica Quattrocento"
|
|
19
20
|
OTB_QUATTROCENTO_LIGHT = auto(), "OT Bioelettronica Quattrocento Light"
|
|
20
21
|
OTB_MUOVI = auto(), "OT Bioelettronica Muovi"
|
|
21
22
|
OTB_MUOVI_PLUS = auto(), "OT Bioelettronica Muovi Plus"
|
|
23
|
+
OTB_SYNCSTATION = auto(), "OT Bioelettronica SyncStation"
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
class OTBDeviceType(Enum):
|
|
@@ -27,9 +29,13 @@ class OTBDeviceType(Enum):
|
|
|
27
29
|
Add new devices here.
|
|
28
30
|
"""
|
|
29
31
|
|
|
32
|
+
_init_ = "value __doc__"
|
|
33
|
+
|
|
34
|
+
QUATTROCENTO = auto(), "Quattrocento"
|
|
30
35
|
QUATTROCENTO_LIGHT = auto(), "Quattrocento Light"
|
|
31
36
|
MUOVI = auto(), "Muovi"
|
|
32
37
|
MUOVI_PLUS = auto(), "Muovi Plus"
|
|
38
|
+
SYNCSTATION = auto(), "SyncStation"
|
|
33
39
|
|
|
34
40
|
|
|
35
41
|
class DeviceChannelTypes(Enum):
|
|
@@ -42,10 +48,14 @@ class DeviceChannelTypes(Enum):
|
|
|
42
48
|
|
|
43
49
|
############# CONSTANTS #############
|
|
44
50
|
DEVICE_NAME_DICT: dict[DeviceType | OTBDeviceType, str] = {
|
|
51
|
+
DeviceType.OTB_QUATTROCENTO: "Quattrocento",
|
|
52
|
+
OTBDeviceType.QUATTROCENTO: "Quattrocento",
|
|
45
53
|
DeviceType.OTB_QUATTROCENTO_LIGHT: "Quattrocento Light",
|
|
46
54
|
OTBDeviceType.QUATTROCENTO_LIGHT: "Quattrocento Light",
|
|
47
55
|
DeviceType.OTB_MUOVI: "Muovi",
|
|
48
56
|
OTBDeviceType.MUOVI: "Muovi",
|
|
49
57
|
DeviceType.OTB_MUOVI_PLUS: "Muovi Plus",
|
|
50
58
|
OTBDeviceType.MUOVI_PLUS: "Muovi Plus",
|
|
59
|
+
DeviceType.OTB_SYNCSTATION: "SyncStation",
|
|
60
|
+
OTBDeviceType.SYNCSTATION: "SyncStation",
|
|
51
61
|
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
from aenum import Enum, auto
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Quattrocento constants.
|
|
5
|
+
|
|
6
|
+
Developer: Dominik I. Braun
|
|
7
|
+
Contact: dome.braun@fau.de
|
|
8
|
+
Last Update: 2025-01-14
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# ------- Command Byte Sequences --------
|
|
13
|
+
class QuattrocentoCommandSequence(Enum):
|
|
14
|
+
"""
|
|
15
|
+
Enum class for the different kind of command sequences.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
_init_ = "value __doc__"
|
|
19
|
+
|
|
20
|
+
NONE = auto(), "None"
|
|
21
|
+
ACQ_SETT = auto(), "Acquisition settings command sequence"
|
|
22
|
+
AN_OUT_IN_SEL = auto(), "Select input source and gain for the analog output"
|
|
23
|
+
AN_OUT_CH_SEL = auto(), "Select the channel for the analog output source"
|
|
24
|
+
IN_CONF = auto(), (
|
|
25
|
+
"Configuration command sequence for the eight IN inputs or",
|
|
26
|
+
"configuration for the four MULTIPLE IN inputs",
|
|
27
|
+
)
|
|
28
|
+
CRC = auto(), "Configuration command sequence byte (8 bits)"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ------------ ACQ_SETT BYTE ------------
|
|
32
|
+
# Bit 7 is fixed to 1.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class QuattrocentoDecimMode(Enum):
|
|
36
|
+
"""
|
|
37
|
+
Enum class for the decimation bit of the Quattrocento device.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
_init_ = "value __doc__"
|
|
41
|
+
|
|
42
|
+
INACTIVE = auto(), (
|
|
43
|
+
"Inactive. No decimation. The required sampling",
|
|
44
|
+
"frequency is obtained by sampling the signals",
|
|
45
|
+
"directly at the desired sampling frequency ",
|
|
46
|
+
)
|
|
47
|
+
ACTIVE = auto(), (
|
|
48
|
+
"Active. Decimation active.",
|
|
49
|
+
"The required sampling frequency is obtained by",
|
|
50
|
+
"sampling all the signals at 10240 Hz and then",
|
|
51
|
+
"sending one sample out of 2, 5 or 20, to obtain",
|
|
52
|
+
"the desired number of sample per second.",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class QuattrocentoRecordingMode(Enum):
|
|
57
|
+
"""
|
|
58
|
+
Enum class for the recording bit.
|
|
59
|
+
|
|
60
|
+
If the Trigger OUT has to be used to synchronize the acquisition with
|
|
61
|
+
other instruments, the recording has to be started when the trigger
|
|
62
|
+
channel has a transition. In other words it is the quattrocento that
|
|
63
|
+
generate a signal indicating to the computer when the data has to be
|
|
64
|
+
recorded.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
_init_ = "value __doc__"
|
|
68
|
+
|
|
69
|
+
STOP = auto(), "Stop"
|
|
70
|
+
START = auto(), "Start"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class QuattrocentoSamplingFrequencyMode(Enum):
|
|
74
|
+
"""
|
|
75
|
+
Enum class for the sampling frequencies of the Quattrocento device (2 bits).
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
_init_ = "value __doc__"
|
|
79
|
+
|
|
80
|
+
LOW = auto(), "512 Hz"
|
|
81
|
+
MEDIUM = auto(), "2048 Hz"
|
|
82
|
+
HIGH = auto(), "5120 Hz"
|
|
83
|
+
ULTRA = auto(), "10240 Hz"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class QuattrocentoNumberOfChannelsMode(Enum):
|
|
87
|
+
"""
|
|
88
|
+
Enum class for the number of channels of the Quattrocento device (2 bits).
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
_init_ = "value __doc__"
|
|
92
|
+
|
|
93
|
+
LOW = auto(), "IN1, IN2 and MULTIPLE_IN1 are active."
|
|
94
|
+
MEDIUM = auto(), "IN1-IN4, MULTIPLE_IN1, MULTIPLE_IN2 are active."
|
|
95
|
+
HIGH = auto(), "IN1-IN6, MULTIPLE_IN1-MULTIPLE_IN2 are active."
|
|
96
|
+
ULTRA = auto(), "IN1-IN8, MULTIPLE_IN1-MULTIPLE_IN4 are active."
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class QuattrocentoAcquisitionMode(Enum):
|
|
100
|
+
"""
|
|
101
|
+
Enum class for the acquisition bit.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
_init_ = "value __doc__"
|
|
105
|
+
|
|
106
|
+
INACTIVE = auto(), "Inactive. Data sampling and transfer is not active"
|
|
107
|
+
ACTIVE = auto(), "Active. Data sampling and transfer is active"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class QuattrocentoAcqSettByte:
|
|
111
|
+
"""
|
|
112
|
+
Class for the acquisition settings byte of the Quattrocento device.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def __init__(self):
|
|
116
|
+
self._decimation_mode: QuattrocentoDecimMode = None
|
|
117
|
+
self._recording_mode: QuattrocentoRecordingMode = None
|
|
118
|
+
self._sampling_frequency_mode: QuattrocentoSamplingFrequencyMode = None
|
|
119
|
+
self._sampling_frequency: int = None
|
|
120
|
+
self._number_of_channels_mode: QuattrocentoNumberOfChannelsMode = None
|
|
121
|
+
self._number_of_channels: int = None
|
|
122
|
+
self._acquisition_mode: QuattrocentoAcquisitionMode = (
|
|
123
|
+
QuattrocentoAcquisitionMode
|
|
124
|
+
).INACTIVE
|
|
125
|
+
|
|
126
|
+
def update(
|
|
127
|
+
self,
|
|
128
|
+
decimation_mode: QuattrocentoDecimMode,
|
|
129
|
+
recording_mode: QuattrocentoRecordingMode,
|
|
130
|
+
sampling_frequency_mode: QuattrocentoSamplingFrequencyMode,
|
|
131
|
+
number_of_channels_mode: QuattrocentoNumberOfChannelsMode,
|
|
132
|
+
):
|
|
133
|
+
self._decimation_mode = decimation_mode
|
|
134
|
+
self._recording_mode = recording_mode
|
|
135
|
+
self._sampling_frequency_mode = sampling_frequency_mode
|
|
136
|
+
self._number_of_channels_mode = number_of_channels_mode
|
|
137
|
+
|
|
138
|
+
self._configure()
|
|
139
|
+
|
|
140
|
+
def _configure(self):
|
|
141
|
+
self._set_sampling_frequency()
|
|
142
|
+
self._set_number_of_channels()
|
|
143
|
+
|
|
144
|
+
def _set_sampling_frequency(self) -> None:
|
|
145
|
+
mode = self._sampling_frequency_mode
|
|
146
|
+
match mode:
|
|
147
|
+
case QuattrocentoSamplingFrequencyMode.LOW:
|
|
148
|
+
self._sampling_frequency = 512
|
|
149
|
+
case QuattrocentoSamplingFrequencyMode.MEDIUM:
|
|
150
|
+
self._sampling_frequency = 2048
|
|
151
|
+
case QuattrocentoSamplingFrequencyMode.HIGH:
|
|
152
|
+
self._sampling_frequency = 5120
|
|
153
|
+
case QuattrocentoSamplingFrequencyMode.ULTRA:
|
|
154
|
+
self._sampling_frequency = 10240
|
|
155
|
+
case _:
|
|
156
|
+
raise ValueError("Invalid sampling frequency mode.")
|
|
157
|
+
|
|
158
|
+
def _set_number_of_channels(self) -> None:
|
|
159
|
+
mode = self._number_of_channels_mode
|
|
160
|
+
match mode:
|
|
161
|
+
case QuattrocentoNumberOfChannelsMode.LOW:
|
|
162
|
+
self._number_of_channels = 120
|
|
163
|
+
case QuattrocentoNumberOfChannelsMode.MEDIUM:
|
|
164
|
+
self._number_of_channels = 216
|
|
165
|
+
case QuattrocentoNumberOfChannelsMode.HIGH:
|
|
166
|
+
self._number_of_channels = 312
|
|
167
|
+
case QuattrocentoNumberOfChannelsMode.ULTRA:
|
|
168
|
+
self._number_of_channels = 408
|
|
169
|
+
case _:
|
|
170
|
+
raise ValueError("Invalid number of channels mode.")
|
|
171
|
+
|
|
172
|
+
def get_sampling_frequency(self) -> int:
|
|
173
|
+
return self._sampling_frequency
|
|
174
|
+
|
|
175
|
+
def get_number_of_channels(self) -> int:
|
|
176
|
+
return self._number_of_channels
|
|
177
|
+
|
|
178
|
+
def __int__(self):
|
|
179
|
+
acq_sett_byte = 1 << 7
|
|
180
|
+
acq_sett_byte += (self._decimation_mode.value - 1) << 6
|
|
181
|
+
acq_sett_byte += (self._recording_mode.value - 1) << 5
|
|
182
|
+
acq_sett_byte += (self._sampling_frequency_mode.value - 1) << 3
|
|
183
|
+
acq_sett_byte += (self._number_of_channels_mode.value - 1) << 1
|
|
184
|
+
acq_sett_byte += self._acquisition_mode.value - 1
|
|
185
|
+
|
|
186
|
+
return int(acq_sett_byte)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# ---------- AN_OUT_IN_SEL BYTE ----------
|
|
190
|
+
# Bit 7 and bit 6 are fixed to 0.
|
|
191
|
+
# TODO:
|
|
192
|
+
|
|
193
|
+
# ---------- AN_OUT_CH_SEL BYTE ----------
|
|
194
|
+
# Bit 7 and bit 6 are fixed to 0.
|
|
195
|
+
# TODO:
|
|
196
|
+
|
|
197
|
+
# -- INX_CONF0 and MULTIPLE_INX_CONF0 BYTE --
|
|
198
|
+
# Bit 7 is fixed to 0.
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class QuattrocentoMuscleSelectionMode(Enum):
|
|
202
|
+
"""
|
|
203
|
+
Enum class for the muscle selection mode of the
|
|
204
|
+
Quattrocento device (5 bits).
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class QuattrocentoSensorSelectionMode(Enum):
|
|
209
|
+
"""
|
|
210
|
+
Enum class for the sensor selection mode of the
|
|
211
|
+
Quattrocento device (5 bits).
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
# TODO: "Implement"
|
|
215
|
+
...
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class QuattrocentoSideMode(Enum):
|
|
219
|
+
""""""
|
|
220
|
+
|
|
221
|
+
_init_ = "value __doc__"
|
|
222
|
+
UNDEFINED = auto(), "Undefined"
|
|
223
|
+
LEFT = auto(), "Left"
|
|
224
|
+
RIGHT = auto(), "Right"
|
|
225
|
+
NONE = auto(), "None"
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
# ---------- INX_CONF2 BYTE ----------
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class QuattrocentoHighPassFilterMode(Enum):
|
|
232
|
+
"""
|
|
233
|
+
Enum class for the high-pass filter of INPUT INX or MULTIPLE INX (2 bits).
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
_init_ = "value __doc__"
|
|
237
|
+
|
|
238
|
+
NONE = auto(), "No high-pass filter"
|
|
239
|
+
LOW = auto(), "High-pass filter at 0.7 Hz"
|
|
240
|
+
MEDIUM = auto(), "High-pass filter at 10 Hz"
|
|
241
|
+
HIGH = auto(), "High-pass filter at 100 Hz"
|
|
242
|
+
ULTRA = auto(), "High-pass filter at 200 Hz"
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class QuattrocentoLowPassFilterMode(Enum):
|
|
246
|
+
"""
|
|
247
|
+
Enum class for the low-pass filter of INPUT INX or MULTIPLE INX (2 bits).
|
|
248
|
+
0 -> LOW: 130 Hz
|
|
249
|
+
1 -> MEDIUM: 500 Hz
|
|
250
|
+
2 -> HIGH: 900 Hz
|
|
251
|
+
3 -> ULTRA: 4400 Hz
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
_init_ = "value __doc__"
|
|
255
|
+
|
|
256
|
+
LOW = auto(), "Low-pass filter at 130 Hz"
|
|
257
|
+
MEDIUM = auto(), "Low-pass filter at 500 Hz"
|
|
258
|
+
HIGH = auto(), "Low-pass filter at 900 Hz"
|
|
259
|
+
ULTRA = auto(), "Low-pass filter at 4400 Hz"
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class QuattrocentoDetectionMode(Enum):
|
|
263
|
+
"""
|
|
264
|
+
Enum class for the detection mode of the Quattrocento device (2 bits).
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
_init_ = "value __doc_"
|
|
268
|
+
|
|
269
|
+
NONE = auto(), "No detection"
|
|
270
|
+
MONOPOLAR = auto(), "Monopolar detection"
|
|
271
|
+
BIPOLAR = auto(), "Bipolar detection"
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class QuattrocentoINXConf2Byte:
|
|
275
|
+
"""
|
|
276
|
+
Class for the INX_CONF2 byte of the Quattrocento device.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
def __init__(self):
|
|
280
|
+
self._muscle_selection_mode: QuattrocentoMuscleSelectionMode = None
|
|
281
|
+
self._sensor_selection_mode: QuattrocentoSensorSelectionMode = None
|
|
282
|
+
self._side_mode: QuattrocentoSideMode = QuattrocentoSideMode.UNDEFINED
|
|
283
|
+
self._high_pass_filter: QuattrocentoHighPassFilterMode = None
|
|
284
|
+
self._low_pass_filter: QuattrocentoLowPassFilterMode = None
|
|
285
|
+
self._detection_mode: QuattrocentoDetectionMode = None
|
|
286
|
+
|
|
287
|
+
def update(
|
|
288
|
+
self,
|
|
289
|
+
high_pass_filter: QuattrocentoHighPassFilterMode,
|
|
290
|
+
low_pass_filter: QuattrocentoLowPassFilterMode,
|
|
291
|
+
detection_mode: QuattrocentoDetectionMode,
|
|
292
|
+
):
|
|
293
|
+
self._high_pass_filter = high_pass_filter
|
|
294
|
+
self._low_pass_filter = low_pass_filter
|
|
295
|
+
self._detection_mode = detection_mode
|
|
296
|
+
|
|
297
|
+
def __int__(self):
|
|
298
|
+
input_conf_byte_1 = 0 # TODO: Muscle
|
|
299
|
+
input_conf_byte_2 = 0 # TODO: Sensor + Adapter
|
|
300
|
+
input_conf_byte_3 = (self._side_mode.value - 1) << 6
|
|
301
|
+
input_conf_byte_3 += (self._high_pass_filter.value - 1) << 4
|
|
302
|
+
input_conf_byte_3 += (self._low_pass_filter.value - 1) << 2
|
|
303
|
+
input_conf_byte_3 += self._detection_mode.value - 1
|
|
304
|
+
|
|
305
|
+
return int(
|
|
306
|
+
(input_conf_byte_1 << 16) + (input_conf_byte_2 << 8) + input_conf_byte_3
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
QUATTROCENTO_AUXILIARY_CHANNELS: int = 16
|
|
311
|
+
QUATTROCENTO_SUPPLEMENTARY_CHANNELS: int = 8
|
|
312
|
+
QUATTROCENTO_SAMPLES_PER_FRAME: int = 64
|
|
313
|
+
QUATTROCENTO_BYTES_PER_SAMPLE: int = 2
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Device class for real-time interfacing the OTB Syncstation device.
|
|
3
|
+
Developer: Dominik I. Braun
|
|
4
|
+
Contact: dome.braun@fau.de
|
|
5
|
+
Last Update: 2025-01-09
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Union
|
|
9
|
+
from aenum import Enum, auto
|
|
10
|
+
from biosignal_device_interface.constants.devices.core.base_device_constants import (
|
|
11
|
+
DeviceType,
|
|
12
|
+
DeviceChannelTypes,
|
|
13
|
+
)
|
|
14
|
+
from biosignal_device_interface.constants.devices.otb.otb_muovi_constants import (
|
|
15
|
+
MUOVI_AVAILABLE_CHANNELS_DICT,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SyncStationRecOnMode(Enum):
|
|
20
|
+
"""
|
|
21
|
+
Enum class for the recording on mode of the SyncStation device.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
_init_ = "value __doc__"
|
|
25
|
+
|
|
26
|
+
OFF = auto(), (
|
|
27
|
+
"The PC is not recording the received signals from SyncStation."
|
|
28
|
+
"If the Timestapms.log is closed if it was previously opened."
|
|
29
|
+
)
|
|
30
|
+
ON = auto(), (
|
|
31
|
+
"The PC is recording the signals received by the SyncStation."
|
|
32
|
+
"When triggered, this bit reset the internal timer for the"
|
|
33
|
+
"ramp counter sent on the Accessory Ch2 and start the log of"
|
|
34
|
+
"the timestamps on the internal timestamps.log file"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class SyncStationWorkingMode(Enum):
|
|
39
|
+
"""
|
|
40
|
+
Enum class for the sampling frequency mode of the SyncStation device.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
_init_ = "value __doc__"
|
|
44
|
+
|
|
45
|
+
NONE = 0, "No working mode set."
|
|
46
|
+
EEG = auto(), "EEG Mode Fsamp 500 Hz, DC coupled, 24 bit resolution."
|
|
47
|
+
EMG = (
|
|
48
|
+
auto(),
|
|
49
|
+
"EMG Mode Fsamp 2000 Hz, high pass filter at 10 Hz*, 16 bit resolution",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SyncStationDetectionMode(Enum):
|
|
54
|
+
"""
|
|
55
|
+
Enum class for the detection mode of the SyncStation device.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
_init_ = "value __doc__"
|
|
59
|
+
|
|
60
|
+
NONE = 0, "No detection mode set."
|
|
61
|
+
MONOPOLAR_GAIN_HIGH = auto(), (
|
|
62
|
+
"Monopolar Mode. High gain. 32 monopolar bioelectrical signals + 6 accessory signals. "
|
|
63
|
+
"Resolution is 286.1 nV and range +/-9.375 mV."
|
|
64
|
+
)
|
|
65
|
+
MONOPOLAR_GAIN_LOW = auto(), (
|
|
66
|
+
"Monopolar Mode. Low gain. 32 monopolar bioelectrical signals + 6 accessory signals. "
|
|
67
|
+
"Resolution is 572.2nV and range +/-18.75 mV."
|
|
68
|
+
)
|
|
69
|
+
IMPEDANCE_CHECK = auto(), "Impedance Check on all 32 + 6 channels."
|
|
70
|
+
TEST = auto(), "Ramps on all 32 + 6 channels."
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SyncStationProbeConfigMode(Enum):
|
|
74
|
+
"""
|
|
75
|
+
Enum class for the probe configuration mode of the SyncStation device.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
_init_ = "value __doc__"
|
|
79
|
+
|
|
80
|
+
NONE = 0, "No probe configuration mode set."
|
|
81
|
+
MUOVI_PROBE_ONE = auto(), "Probe configuration mode for Muovi probe one."
|
|
82
|
+
MUOVI_PROBE_TWO = auto(), "Probe configuration mode for Muovi probe two."
|
|
83
|
+
MUOVI_PROBE_THREE = auto(), "Probe configuration mode for Muovi probe three."
|
|
84
|
+
MUOVI_PROBE_FOUR = auto(), "Probe configuration mode for Muovi probe four."
|
|
85
|
+
MUOVI_PLUS_PROBE_ONE = auto(), "Probe configuration mode for Muovi Plus probe one."
|
|
86
|
+
MUOVI_PLUS_PROBE_TWO = auto(), "Probe configuration mode for Muovi Plus probe two."
|
|
87
|
+
DUE_PLUS_PROBE_ONE = (
|
|
88
|
+
auto(),
|
|
89
|
+
"Probe configuration mode for Due Plus probe one.",
|
|
90
|
+
)
|
|
91
|
+
DUE_PLUS_PROBE_TWO = (
|
|
92
|
+
auto(),
|
|
93
|
+
"Probe configuration mode for Due Plus probe two.",
|
|
94
|
+
)
|
|
95
|
+
DUE_PLUS_PROBE_THREE = (
|
|
96
|
+
auto(),
|
|
97
|
+
"Probe configuration mode for Due Plus probe three.",
|
|
98
|
+
)
|
|
99
|
+
DUE_PLUS_PROBE_FOUR = (
|
|
100
|
+
auto(),
|
|
101
|
+
"Probe configuration mode for Due Plus probe four.",
|
|
102
|
+
)
|
|
103
|
+
DUE_PLUS_PROBE_FIVE = (
|
|
104
|
+
auto(),
|
|
105
|
+
"Probe configuration mode for Due Plus probe five.",
|
|
106
|
+
)
|
|
107
|
+
DUE_PLUS_PROBE_SIX = (
|
|
108
|
+
auto(),
|
|
109
|
+
"Probe configuration mode for Due Plus probe six.",
|
|
110
|
+
)
|
|
111
|
+
DUE_PLUS_PROBE_SEVEN = (
|
|
112
|
+
auto(),
|
|
113
|
+
"Probe configuration mode for Due Plus probe seven.",
|
|
114
|
+
)
|
|
115
|
+
DUE_PLUS_PROBE_EIGHT = (
|
|
116
|
+
auto(),
|
|
117
|
+
"Probe configuration mode for Due Plus probe eight.",
|
|
118
|
+
)
|
|
119
|
+
DUE_PLUS_PROBE_NINE = (
|
|
120
|
+
auto(),
|
|
121
|
+
"Probe configuration mode for Due Plus probe nine.",
|
|
122
|
+
)
|
|
123
|
+
DUE_PLUS_PROBE_TEN = (
|
|
124
|
+
auto(),
|
|
125
|
+
"Probe configuration mode for Due Plus probe ten.",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# DICTS
|
|
130
|
+
|
|
131
|
+
SYNCSTATION_CHARACTERISTICS_DICT: Dict[str, int] = {
|
|
132
|
+
DeviceChannelTypes.ALL: 6,
|
|
133
|
+
"bytes_per_sample": 2,
|
|
134
|
+
"channel_information": {
|
|
135
|
+
SyncStationWorkingMode.EEG: {
|
|
136
|
+
"sampling_frequency": 500,
|
|
137
|
+
"bytes_per_sample": 3,
|
|
138
|
+
"frame_size": 5,
|
|
139
|
+
},
|
|
140
|
+
SyncStationWorkingMode.EMG: {
|
|
141
|
+
"sampling_frequency": 2000,
|
|
142
|
+
"bytes_per_sample": 2,
|
|
143
|
+
"frame_size": 10,
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
"number_of_packages": 32,
|
|
147
|
+
"package_size": 1460,
|
|
148
|
+
"FPS": 50,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# TODO: Load information from Device Constants directly!
|
|
152
|
+
PROBE_CHARACTERISTICS_DICT: Dict[
|
|
153
|
+
SyncStationProbeConfigMode, Dict[str, Union[str, int]]
|
|
154
|
+
] = {
|
|
155
|
+
SyncStationProbeConfigMode.MUOVI_PROBE_ONE: MUOVI_AVAILABLE_CHANNELS_DICT[
|
|
156
|
+
DeviceType.OTB_MUOVI
|
|
157
|
+
],
|
|
158
|
+
SyncStationProbeConfigMode.MUOVI_PROBE_TWO: MUOVI_AVAILABLE_CHANNELS_DICT[
|
|
159
|
+
DeviceType.OTB_MUOVI
|
|
160
|
+
],
|
|
161
|
+
SyncStationProbeConfigMode.MUOVI_PROBE_THREE: MUOVI_AVAILABLE_CHANNELS_DICT[
|
|
162
|
+
DeviceType.OTB_MUOVI
|
|
163
|
+
],
|
|
164
|
+
SyncStationProbeConfigMode.MUOVI_PROBE_FOUR: MUOVI_AVAILABLE_CHANNELS_DICT[
|
|
165
|
+
DeviceType.OTB_MUOVI
|
|
166
|
+
],
|
|
167
|
+
SyncStationProbeConfigMode.MUOVI_PLUS_PROBE_ONE: MUOVI_AVAILABLE_CHANNELS_DICT[
|
|
168
|
+
DeviceType.OTB_MUOVI_PLUS
|
|
169
|
+
],
|
|
170
|
+
SyncStationProbeConfigMode.MUOVI_PLUS_PROBE_TWO: MUOVI_AVAILABLE_CHANNELS_DICT[
|
|
171
|
+
DeviceType.OTB_MUOVI_PLUS
|
|
172
|
+
],
|
|
173
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_ONE: {
|
|
174
|
+
DeviceChannelTypes.ALL: 8,
|
|
175
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
176
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
177
|
+
},
|
|
178
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_TWO: {
|
|
179
|
+
DeviceChannelTypes.ALL: 8,
|
|
180
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
181
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
182
|
+
},
|
|
183
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_THREE: {
|
|
184
|
+
DeviceChannelTypes.ALL: 8,
|
|
185
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
186
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
187
|
+
},
|
|
188
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_FOUR: {
|
|
189
|
+
DeviceChannelTypes.ALL: 8,
|
|
190
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
191
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
192
|
+
},
|
|
193
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_FIVE: {
|
|
194
|
+
DeviceChannelTypes.ALL: 8,
|
|
195
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
196
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
197
|
+
},
|
|
198
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_SIX: {
|
|
199
|
+
DeviceChannelTypes.ALL: 8,
|
|
200
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
201
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
202
|
+
},
|
|
203
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_SEVEN: {
|
|
204
|
+
DeviceChannelTypes.ALL: 8,
|
|
205
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
206
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
207
|
+
},
|
|
208
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_EIGHT: {
|
|
209
|
+
DeviceChannelTypes.ALL: 8,
|
|
210
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
211
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
212
|
+
},
|
|
213
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_NINE: {
|
|
214
|
+
DeviceChannelTypes.ALL: 8,
|
|
215
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
216
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
217
|
+
},
|
|
218
|
+
SyncStationProbeConfigMode.DUE_PLUS_PROBE_TEN: {
|
|
219
|
+
DeviceChannelTypes.ALL: 8,
|
|
220
|
+
DeviceChannelTypes.BIOSIGNAL: 2,
|
|
221
|
+
DeviceChannelTypes.AUXILIARY: 6,
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
SYNCSTATION_CONVERSION_FACTOR_DICT: dict[SyncStationDetectionMode, int] = {
|
|
226
|
+
SyncStationDetectionMode.MONOPOLAR_GAIN_HIGH: 572.2e-6,
|
|
227
|
+
SyncStationDetectionMode.MONOPOLAR_GAIN_LOW: 286.1e-6,
|
|
228
|
+
}
|
|
229
|
+
"""
|
|
230
|
+
Dictionary to get the gain of the Muovi detection mode. \\
|
|
231
|
+
The keys are the detection modes of the Muovi device. \\
|
|
232
|
+
The values are the gain of the detection mode in V.
|
|
233
|
+
"""
|
|
@@ -73,7 +73,7 @@ class BaseDevice(QObject):
|
|
|
73
73
|
self._connection_timeout_timer.setInterval(1000)
|
|
74
74
|
|
|
75
75
|
# Device Status
|
|
76
|
-
self.
|
|
76
|
+
self.is_connected: bool = False
|
|
77
77
|
self._is_configured: bool = False
|
|
78
78
|
self._is_streaming: bool = False
|
|
79
79
|
|
|
@@ -114,7 +114,7 @@ class BaseDevice(QObject):
|
|
|
114
114
|
bool:
|
|
115
115
|
Success of the disconnection attempt.
|
|
116
116
|
"""
|
|
117
|
-
self.
|
|
117
|
+
self.is_connected = False
|
|
118
118
|
self.connect_toggled.emit(False)
|
|
119
119
|
self._is_configured = False
|
|
120
120
|
self.configure_toggled.emit(False)
|
|
@@ -299,7 +299,7 @@ class BaseDevice(QObject):
|
|
|
299
299
|
"""
|
|
300
300
|
self._connection_settings = settings
|
|
301
301
|
|
|
302
|
-
if self.
|
|
302
|
+
if self.is_connected:
|
|
303
303
|
if self._is_streaming:
|
|
304
304
|
self.toggle_streaming()
|
|
305
305
|
|
|
@@ -395,6 +395,8 @@ class BaseDevice(QObject):
|
|
|
395
395
|
or "wifi" in interface.lower()
|
|
396
396
|
or "wireless" in interface.lower()
|
|
397
397
|
or "en0" in interface.lower()
|
|
398
|
+
or "wlp" in interface.lower()
|
|
399
|
+
or "wln" in interface.lower()
|
|
398
400
|
):
|
|
399
401
|
for address in addresses:
|
|
400
402
|
# Check if the address is an IPv4 address and not a loopback or virtual address
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
from biosignal_device_interface.devices.otb.otb_quattrocento import OTBQuattrocento
|
|
1
2
|
from biosignal_device_interface.devices.otb.otb_quattrocento_light import (
|
|
2
3
|
OTBQuattrocentoLight,
|
|
3
4
|
)
|
|
4
5
|
from biosignal_device_interface.devices.otb.otb_muovi import OTBMuovi
|
|
6
|
+
from biosignal_device_interface.devices.otb.otb_syncstation import OTBSyncStation
|
|
5
7
|
|
|
6
8
|
# Widgets
|
|
7
9
|
# All OTB Devices Widget
|
|
@@ -16,6 +18,12 @@ from biosignal_device_interface.gui.device_template_widgets.otb.otb_muovi_widget
|
|
|
16
18
|
from biosignal_device_interface.gui.device_template_widgets.otb.otb_muovi_plus_widget import (
|
|
17
19
|
OTBMuoviPlusWidget,
|
|
18
20
|
)
|
|
21
|
+
from biosignal_device_interface.gui.device_template_widgets.otb.otb_quattrocento_widget import (
|
|
22
|
+
OTBQuattrocentoWidget,
|
|
23
|
+
)
|
|
19
24
|
from biosignal_device_interface.gui.device_template_widgets.otb.otb_quattrocento_light_widget import (
|
|
20
25
|
OTBQuattrocentoLightWidget,
|
|
21
26
|
)
|
|
27
|
+
from biosignal_device_interface.gui.device_template_widgets.otb.otb_syncstation_widget import (
|
|
28
|
+
OTBSyncStationWidget,
|
|
29
|
+
)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# Python Libraries
|
|
2
1
|
"""
|
|
3
2
|
Device class for real-time interfacing the Muovi device.
|
|
4
3
|
Developer: Dominik I. Braun
|
|
@@ -101,9 +100,9 @@ class OTBMuovi(BaseDevice):
|
|
|
101
100
|
|
|
102
101
|
self._client_socket.readyRead.connect(self._read_data)
|
|
103
102
|
|
|
104
|
-
if not self.
|
|
105
|
-
self.
|
|
106
|
-
self.connect_toggled.emit(self.
|
|
103
|
+
if not self.is_connected:
|
|
104
|
+
self.is_connected = True
|
|
105
|
+
self.connect_toggled.emit(self.is_connected)
|
|
107
106
|
self._connection_timeout_timer.stop()
|
|
108
107
|
return True
|
|
109
108
|
|
|
@@ -130,7 +129,7 @@ class OTBMuovi(BaseDevice):
|
|
|
130
129
|
) -> None:
|
|
131
130
|
super().configure_device(params)
|
|
132
131
|
|
|
133
|
-
if not self.
|
|
132
|
+
if not self.is_connected or self._client_socket is None:
|
|
134
133
|
return
|
|
135
134
|
|
|
136
135
|
# Check if detection mode is valid for working mode (Case EEG -> MONOPOLAR_GAIN_4 => MONOPOLAR_GAIN_8)
|