qlsdk2 0.6.0__py3-none-any.whl → 0.6.0a2__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.
- qlsdk/core/entity/__init__.py +32 -90
- qlsdk/persist/ars_edf.py +101 -80
- qlsdk/persist/rsc_edf.py +12 -20
- qlsdk/rsc/command/__init__.py +12 -26
- qlsdk/rsc/device/arskindling.py +310 -248
- qlsdk/rsc/device/base.py +82 -158
- qlsdk/rsc/device/c16_rs.py +5 -1
- qlsdk/rsc/device/c256_rs.py +327 -11
- qlsdk/rsc/device/c64_rs.py +332 -2
- qlsdk/rsc/device/c64s1.py +340 -4
- qlsdk/rsc/interface/device.py +1 -22
- qlsdk/rsc/paradigm.py +6 -127
- qlsdk/rsc/parser/base.py +6 -11
- {qlsdk2-0.6.0.dist-info → qlsdk2-0.6.0a2.dist-info}/METADATA +1 -1
- {qlsdk2-0.6.0.dist-info → qlsdk2-0.6.0a2.dist-info}/RECORD +17 -17
- {qlsdk2-0.6.0.dist-info → qlsdk2-0.6.0a2.dist-info}/WHEEL +0 -0
- {qlsdk2-0.6.0.dist-info → qlsdk2-0.6.0a2.dist-info}/top_level.txt +0 -0
qlsdk/core/entity/__init__.py
CHANGED
|
@@ -19,8 +19,7 @@ class RscPacket(Packet):
|
|
|
19
19
|
self.filter = None
|
|
20
20
|
self.data_len = None
|
|
21
21
|
self.trigger = None
|
|
22
|
-
self.eeg = None
|
|
23
|
-
self.eeg_p = None # 物理值
|
|
22
|
+
self.eeg = None
|
|
24
23
|
|
|
25
24
|
@staticmethod
|
|
26
25
|
def transfer(body: bytes) -> 'RscPacket':
|
|
@@ -51,68 +50,47 @@ class RscPacket(Packet):
|
|
|
51
50
|
for i in range(ch_num)
|
|
52
51
|
]
|
|
53
52
|
|
|
54
|
-
logger.trace(
|
|
55
|
-
|
|
53
|
+
# logger.trace(self)
|
|
56
54
|
return packet
|
|
57
|
-
|
|
58
|
-
def copy(self) -> 'RscPacket':
|
|
59
|
-
packet = RscPacket()
|
|
60
|
-
packet.time_stamp = self.time_stamp
|
|
61
|
-
packet.pkg_id = self.pkg_id
|
|
62
|
-
packet.result = self.result
|
|
63
|
-
packet.channels = self.channels
|
|
64
|
-
packet.origin_sample_rate = self.origin_sample_rate
|
|
65
|
-
packet.sample_rate = self.sample_rate
|
|
66
|
-
packet.sample_num = self.sample_num
|
|
67
|
-
packet.resolution = self.resolution
|
|
68
|
-
packet.filter = self.filter
|
|
69
|
-
packet.data_len = self.data_len
|
|
70
|
-
packet.trigger = self.trigger
|
|
71
|
-
packet.eeg = self.eeg
|
|
72
|
-
return packet
|
|
73
55
|
|
|
74
56
|
def __str__(self):
|
|
75
|
-
return f"""
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
57
|
+
return f"""
|
|
58
|
+
time_stamp: {self.time_stamp}
|
|
59
|
+
pkg_id: {self.pkg_id}
|
|
60
|
+
origin_sample_rate: {self.origin_sample_rate}
|
|
61
|
+
sample_rate: {self.sample_rate}
|
|
62
|
+
sample_num: {self.sample_num}
|
|
63
|
+
resolution: {self.resolution}
|
|
64
|
+
filter: {self.filter}
|
|
65
|
+
channels: {self.channels}
|
|
66
|
+
data len: {self.data_len}
|
|
67
|
+
trigger: {self.trigger}
|
|
68
|
+
eeg: {self.eeg}
|
|
69
|
+
"""
|
|
82
70
|
|
|
83
71
|
class ImpedancePacket(Packet):
|
|
84
72
|
def __init__(self):
|
|
85
73
|
super().__init__()
|
|
74
|
+
self.data_len = None
|
|
86
75
|
self.impedance = None
|
|
87
76
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# packet.sample_rate = int.from_bytes(body[45: 49], 'little')
|
|
96
|
-
# packet.sample_len = int.from_bytes(body[49: 53], 'little')
|
|
97
|
-
# packet.resolution = int(int(body[53]) / 8)
|
|
98
|
-
# packet.filter = int(int(body[54]) / 8)
|
|
99
|
-
# packet.wave_type = int(int(body[55]) / 8)
|
|
100
|
-
# packet.wave_freq = int.from_bytes(body[56: 60], 'little')
|
|
101
|
-
# packet.data_len = int.from_bytes(body[60: 64], 'little')
|
|
102
|
-
b_impedance = body[64:]
|
|
103
|
-
packet.impedance = [int.from_bytes(b_impedance[j * 4 : j * 4 + 4], 'little', signed=False) for j in range(len(packet.channels))]
|
|
104
|
-
|
|
105
|
-
logger.trace(f"impedance: {packet}")
|
|
77
|
+
def transfer(self, body:bytes) -> 'ImpedancePacket':
|
|
78
|
+
self.time_stamp = int.from_bytes(body[0:8], 'little')
|
|
79
|
+
self.result = body[8]
|
|
80
|
+
self.pkg_id = int.from_bytes(body[9: 13], 'little')
|
|
81
|
+
self.channels = to_channels(body[13: 45])
|
|
82
|
+
|
|
83
|
+
logger.debug(f"impedance: {self}")
|
|
106
84
|
|
|
107
|
-
return packet
|
|
108
|
-
|
|
109
85
|
def __str__(self):
|
|
110
|
-
return f"""
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
86
|
+
return f"""
|
|
87
|
+
time_stamp: {self.time_stamp}
|
|
88
|
+
pkg_id: {self.pkg_id}
|
|
89
|
+
result: {self.result}
|
|
90
|
+
channels: {self.channels}
|
|
91
|
+
data len: {self.data_len}
|
|
92
|
+
impedance: {self.impedance}
|
|
93
|
+
"""
|
|
116
94
|
|
|
117
95
|
|
|
118
96
|
class C256RSPacket(Packet):
|
|
@@ -183,40 +161,4 @@ class C256RSPacket(Packet):
|
|
|
183
161
|
offset += 4 + channel_size * packet.resolution
|
|
184
162
|
|
|
185
163
|
logger.trace(packet)
|
|
186
|
-
return packet
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
class C256ImpedancePacket(Packet):
|
|
190
|
-
def __init__(self):
|
|
191
|
-
super().__init__()
|
|
192
|
-
self.impedance = None
|
|
193
|
-
|
|
194
|
-
@staticmethod
|
|
195
|
-
def transfer(body:bytes) -> 'ImpedancePacket':
|
|
196
|
-
packet = ImpedancePacket()
|
|
197
|
-
packet.time_stamp = int.from_bytes(body[0:8], 'little')
|
|
198
|
-
# packet.result = body[8]
|
|
199
|
-
packet.pkg_id = int.from_bytes(body[9: 13], 'little')
|
|
200
|
-
packet.channels = to_channels(body[13: 45])
|
|
201
|
-
# packet.sample_rate = int.from_bytes(body[45: 49], 'little')
|
|
202
|
-
# packet.sample_len = int.from_bytes(body[49: 53], 'little')
|
|
203
|
-
# packet.resolution = int(int(body[53]) / 8)
|
|
204
|
-
# packet.filter = int(int(body[54]) / 8)
|
|
205
|
-
# packet.wave_type = int(int(body[55]) / 8)
|
|
206
|
-
# packet.wave_freq = int.from_bytes(body[56: 60], 'little')
|
|
207
|
-
# packet.data_len = int.from_bytes(body[60: 64], 'little')
|
|
208
|
-
b_impedance = body[64:]
|
|
209
|
-
packet.impedance = [int.from_bytes(b_impedance[j : j + 4], 'little', signed=False) for j in range(len(packet.channels))]
|
|
210
|
-
|
|
211
|
-
logger.trace(f"impedance: {packet}")
|
|
212
|
-
|
|
213
|
-
def __str__(self):
|
|
214
|
-
return f"""
|
|
215
|
-
time_stamp: {self.time_stamp}
|
|
216
|
-
pkg_id: {self.pkg_id}
|
|
217
|
-
result: {self.result}
|
|
218
|
-
channels: {self.channels}
|
|
219
|
-
data len: {self.data_len}
|
|
220
|
-
impedance: {self.impedance}
|
|
221
|
-
"""
|
|
222
|
-
|
|
164
|
+
return packet
|
qlsdk/persist/ars_edf.py
CHANGED
|
@@ -85,67 +85,67 @@ class ARSKindlingEDFHandler(object):
|
|
|
85
85
|
"D" : [7, 8, 5, 6, 3, 4, 1, 2, 9, 10, 11, 12, 13, 14],
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
88
|
+
self._channel_mapping = {
|
|
89
|
+
1: "D7",
|
|
90
|
+
2: "D8",
|
|
91
|
+
3: "D5",
|
|
92
|
+
4: "D6",
|
|
93
|
+
5: "D3",
|
|
94
|
+
6: "D4",
|
|
95
|
+
7: "D1",
|
|
96
|
+
8: "D2",
|
|
97
|
+
9: "D9",
|
|
98
|
+
10: "D10",
|
|
99
|
+
11: "D11",
|
|
100
|
+
12: "D12",
|
|
101
|
+
13: "D13",
|
|
102
|
+
14: "D14",
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
104
|
+
17: "C7",
|
|
105
|
+
18: "C8",
|
|
106
|
+
19: "C5",
|
|
107
|
+
20: "C6",
|
|
108
|
+
21: "C3",
|
|
109
|
+
22: "C4",
|
|
110
|
+
23: "C1",
|
|
111
|
+
24: "C2",
|
|
112
|
+
25: "C9",
|
|
113
|
+
26: "C10",
|
|
114
|
+
27: "C11",
|
|
115
|
+
28: "C12",
|
|
116
|
+
29: "C13",
|
|
117
|
+
30: "C14",
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
33: "B7",
|
|
120
|
+
34: "B8",
|
|
121
|
+
35: "B5",
|
|
122
|
+
36: "B6",
|
|
123
|
+
37: "B3",
|
|
124
|
+
38: "B4",
|
|
125
|
+
39: "B1",
|
|
126
|
+
40: "B2",
|
|
127
|
+
41: "B9",
|
|
128
|
+
42: "B10",
|
|
129
|
+
43: "B11",
|
|
130
|
+
44: "B12",
|
|
131
|
+
45: "B13",
|
|
132
|
+
46: "B14",
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
134
|
+
49: "A7",
|
|
135
|
+
50: "A8",
|
|
136
|
+
51: "A5",
|
|
137
|
+
52: "A6",
|
|
138
|
+
53: "A3",
|
|
139
|
+
54: "A4",
|
|
140
|
+
55: "A1",
|
|
141
|
+
56: "A2",
|
|
142
|
+
57: "A9",
|
|
143
|
+
58: "A10",
|
|
144
|
+
59: "A11",
|
|
145
|
+
60: "A12",
|
|
146
|
+
61: "A13",
|
|
147
|
+
62: "A14"
|
|
148
|
+
}
|
|
149
149
|
|
|
150
150
|
self._lock = Lock()
|
|
151
151
|
|
|
@@ -172,8 +172,6 @@ class ARSKindlingEDFHandler(object):
|
|
|
172
172
|
self._device_type = "C64RS"
|
|
173
173
|
elif device_type == 0x40:
|
|
174
174
|
self._device_type = "LJ64S1"
|
|
175
|
-
elif device_type == 0x60:
|
|
176
|
-
self._device_type = "ArsKindling"
|
|
177
175
|
else:
|
|
178
176
|
self._device_type = hex(device_type)
|
|
179
177
|
|
|
@@ -197,32 +195,55 @@ class ARSKindlingEDFHandler(object):
|
|
|
197
195
|
if packet is None:
|
|
198
196
|
# self._edf_writer_thread.stop_recording()
|
|
199
197
|
for k in self._edf_handler.keys():
|
|
200
|
-
self._edf_handler[k].
|
|
198
|
+
self._edf_handler[k].append(None)
|
|
201
199
|
return
|
|
202
200
|
|
|
203
|
-
#按分区写入数据
|
|
201
|
+
#按分区写入数据
|
|
202
|
+
|
|
204
203
|
for k in self._channel_spilt.keys():
|
|
205
|
-
logger.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
logger.info(f'分区{k}, {self._channel_spilt[k]}')
|
|
205
|
+
p = packet
|
|
206
|
+
self.writeA(p, self._channel_spilt[k], k)
|
|
207
|
+
|
|
208
|
+
# with self._lock:
|
|
209
|
+
# if self.channels is None:
|
|
210
|
+
# logger.info(f"开始记录数据到文件...")
|
|
211
|
+
# self.channels = packet.channels
|
|
212
|
+
# self._first_pkg_id = packet.pkg_id if self._first_pkg_id is None else self._first_pkg_id
|
|
213
|
+
# self._first_timestamp = packet.time_stamp if self._first_timestamp is None else self._first_timestamp
|
|
214
|
+
# self._start_time = datetime.now()
|
|
215
|
+
# logger.info(f"第一个包id: {self._first_pkg_id }, 时间戳:{self._first_timestamp}, 当前时间:{datetime.now().timestamp()} offset: {datetime.now().timestamp() - self._first_timestamp}")
|
|
216
|
+
|
|
217
|
+
# if self._last_pkg_id and self._last_pkg_id != packet.pkg_id - 1:
|
|
218
|
+
# self._lost_packets += packet.pkg_id - self._last_pkg_id - 1
|
|
219
|
+
# logger.warning(f"数据包丢失: {self._last_pkg_id} -> {packet.pkg_id}, 丢包数: {packet.pkg_id - self._last_pkg_id - 1}")
|
|
220
|
+
|
|
221
|
+
# self._last_pkg_id = packet.pkg_id
|
|
222
|
+
# self._total_packets += 1
|
|
223
|
+
|
|
224
|
+
# if self._edf_writer_thread is None:
|
|
225
|
+
# self._edf_writer_thread = EDFStreamWriter(self.channels, self.sample_rate, self.physical_max, self.physical_min, self.file_type, self.file_name)
|
|
226
|
+
# self._edf_writer_thread.set_start_time(self._start_time)
|
|
227
|
+
# self._edf_writer_thread.start()
|
|
228
|
+
# logger.info(f"开始写入数据: {self.file_name}")
|
|
229
|
+
|
|
230
|
+
# self._edf_writer_thread.append(packet.eeg)
|
|
209
231
|
|
|
210
|
-
def writeA(self, packet: RscPacket, name='A'):
|
|
232
|
+
def writeA(self, packet: RscPacket, channel_filter, name='A'):
|
|
211
233
|
# 参数检查
|
|
212
|
-
if packet is None:
|
|
234
|
+
if packet is None or channel_filter is None:
|
|
213
235
|
logger.warning("空数据,忽略")
|
|
214
236
|
return
|
|
215
|
-
|
|
216
|
-
channels = packet.channels.get(name, None)
|
|
217
|
-
eeg = packet.eeg.get(name, None)
|
|
218
237
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
238
|
+
channel_pos = intersection_positions(packet.channels, channel_filter)
|
|
239
|
+
|
|
240
|
+
if channel_pos is None or len(channel_pos) == 0 :
|
|
241
|
+
logger.debug(f"没有指定分区{name}的通道,跳过")
|
|
242
|
+
pass
|
|
222
243
|
|
|
223
244
|
# 分区数据包写入
|
|
224
245
|
if name not in self._edf_handler.keys():
|
|
225
|
-
edf_handler = RscEDFHandler(self.sample_rate, self.
|
|
246
|
+
edf_handler = RscEDFHandler(self.sample_rate, self.digital_max , self.digital_min, self.resolution)
|
|
226
247
|
edf_handler.set_device_type(self._device_type)
|
|
227
248
|
edf_handler.set_device_no(self._device_no)
|
|
228
249
|
edf_handler.set_storage_path(self._storage_path)
|
|
@@ -230,12 +251,15 @@ class ARSKindlingEDFHandler(object):
|
|
|
230
251
|
logger.info(f"开始写入分区{name}的数据到文件")
|
|
231
252
|
self._edf_handler[name] = edf_handler
|
|
232
253
|
|
|
254
|
+
# 保留本分区的通道和数据
|
|
255
|
+
channels = [packet.channels[p] for p in channel_pos]
|
|
256
|
+
eeg = [packet.eeg[p] for p in channel_pos]
|
|
257
|
+
|
|
233
258
|
# 新建数据包实例
|
|
234
259
|
data = RscPacket()
|
|
235
260
|
data.time_stamp = packet.time_stamp
|
|
236
261
|
data.pkg_id = packet.pkg_id
|
|
237
|
-
|
|
238
|
-
data.channels = self.channel_display(channels, name)
|
|
262
|
+
data.channels = channels
|
|
239
263
|
data.origin_sample_rate = packet.origin_sample_rate
|
|
240
264
|
data.sample_rate = packet.sample_rate
|
|
241
265
|
data.sample_num = packet.sample_num
|
|
@@ -252,6 +276,3 @@ class ARSKindlingEDFHandler(object):
|
|
|
252
276
|
# trigger现在(20250702)多个分区共享, 分发到所有分区文件中标记
|
|
253
277
|
for k in self._edf_handler.keys():
|
|
254
278
|
self._edf_handler[k].trigger(desc, cur_time)
|
|
255
|
-
|
|
256
|
-
def channel_display(self, channel, name: str):
|
|
257
|
-
return [f'{name}-{channel_id}' for channel_id in channel]
|
qlsdk/persist/rsc_edf.py
CHANGED
|
@@ -15,7 +15,7 @@ EDF_FILE_TYPE = {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
class EDFStreamWriter(Thread):
|
|
18
|
-
def __init__(self, channels, sample_frequency, physical_max,
|
|
18
|
+
def __init__(self, channels, sample_frequency, physical_max, digital_min, file_type, file_path, record_duration=None):
|
|
19
19
|
|
|
20
20
|
super().__init__()
|
|
21
21
|
self._writer : EdfWriter = None
|
|
@@ -32,7 +32,7 @@ class EDFStreamWriter(Thread):
|
|
|
32
32
|
self._n_channels = len(channels)
|
|
33
33
|
self.sample_frequency = sample_frequency
|
|
34
34
|
self.physical_max = physical_max
|
|
35
|
-
self.physical_min =
|
|
35
|
+
self.physical_min = digital_min
|
|
36
36
|
# 和位数相关,edf 16 bits/bdf 24 bits
|
|
37
37
|
self.digital_max = 8388607 if file_type == EDF_FILE_TYPE['bdf'] else 32767
|
|
38
38
|
self.digital_min = -8388608 if file_type == EDF_FILE_TYPE['bdf'] else -32768
|
|
@@ -46,7 +46,6 @@ class EDFStreamWriter(Thread):
|
|
|
46
46
|
self.equipment = "equipment"
|
|
47
47
|
self.patient_code = "patient_code"
|
|
48
48
|
self.patient_name = "patient_name"
|
|
49
|
-
logger.info(f'digital_max:{self.digital_max}, digital_min:{self.digital_min}, physical_max:{self.physical_max}, physical_min:{self.physical_min}')
|
|
50
49
|
|
|
51
50
|
def set_channels(self, channels):
|
|
52
51
|
self._channels = channels
|
|
@@ -62,7 +61,7 @@ class EDFStreamWriter(Thread):
|
|
|
62
61
|
self._recording = False
|
|
63
62
|
|
|
64
63
|
def append(self, data):
|
|
65
|
-
if data
|
|
64
|
+
if data:
|
|
66
65
|
# 数据
|
|
67
66
|
self.data_queue.put(data)
|
|
68
67
|
|
|
@@ -128,7 +127,6 @@ class EDFStreamWriter(Thread):
|
|
|
128
127
|
|
|
129
128
|
# 配置通道参数
|
|
130
129
|
signal_headers = []
|
|
131
|
-
logger.trace(f"sf: {self.sample_frequency}, pm: {self.physical_max}, pn: {self.physical_min}, dm: {self.digital_max}, dn: {self.digital_min}")
|
|
132
130
|
for ch in range(self._n_channels):
|
|
133
131
|
signal_headers.append({
|
|
134
132
|
"label": f'channels {self._channels[ch]}',
|
|
@@ -171,16 +169,14 @@ class EDFStreamWriter(Thread):
|
|
|
171
169
|
# 写入1秒的数据
|
|
172
170
|
def _write_block(self, block):
|
|
173
171
|
logger.trace(f"写入数据: {block}")
|
|
174
|
-
# 转换数据类型为float64
|
|
175
|
-
|
|
176
|
-
logger.trace(f"写入数据-real: {data_input}")
|
|
172
|
+
# 转换数据类型为float64
|
|
173
|
+
data_float64 = block.astype(np.float64)
|
|
177
174
|
# 写入时转置为(样本数, 通道数)格式
|
|
178
|
-
self._writer.writeSamples(
|
|
175
|
+
self._writer.writeSamples(data_float64)
|
|
179
176
|
self._duration += 1
|
|
180
177
|
|
|
181
178
|
if self._duration % 10 == 0: # 每10秒打印一次进度
|
|
182
179
|
logger.info(f"数据记录中... 文件名:{self.file_path}, 已记录时长: {self._duration}秒")
|
|
183
|
-
|
|
184
180
|
|
|
185
181
|
# 用作数据结构一致化处理,通过调用公共类写入edf文件
|
|
186
182
|
# 入参包含写入edf的全部前置参数
|
|
@@ -204,7 +200,7 @@ class RscEDFHandler(object):
|
|
|
204
200
|
self.physical_max = physical_max
|
|
205
201
|
self.physical_min = physical_min
|
|
206
202
|
self.digital_max = 8388607 if resolution == 24 else 32767
|
|
207
|
-
self.digital_min = -
|
|
203
|
+
self.digital_min = -8388607 if resolution == 24 else - 32768
|
|
208
204
|
self.file_type = EDF_FILE_TYPE["bdf"] if resolution == 24 else EDF_FILE_TYPE["edf"]
|
|
209
205
|
# 点分辨率
|
|
210
206
|
self.resolution = resolution
|
|
@@ -230,8 +226,8 @@ class RscEDFHandler(object):
|
|
|
230
226
|
self._end_time = None
|
|
231
227
|
self._patient_code = "patient_code"
|
|
232
228
|
self._patient_name = "patient_name"
|
|
233
|
-
self._device_type = "
|
|
234
|
-
self._device_no = "
|
|
229
|
+
self._device_type = "24130032"
|
|
230
|
+
self._device_no = "24130032"
|
|
235
231
|
self._total_packets = 0
|
|
236
232
|
self._lost_packets = 0
|
|
237
233
|
self._storage_path = storage_path
|
|
@@ -246,7 +242,7 @@ class RscEDFHandler(object):
|
|
|
246
242
|
suffix = "bdf" if self.resolution == 24 else "edf"
|
|
247
243
|
|
|
248
244
|
# 文件名称
|
|
249
|
-
file_name = f"{self._file_prefix}_{self._device_no}_{self._start_time.strftime('%y%m%d%H%M
|
|
245
|
+
file_name = f"{self._file_prefix}_{self._device_no}_{self._start_time.strftime('%y%m%d%H%I%M')}.{suffix}" if self._file_prefix else f"{self._device_no}_{self._start_time.strftime('%y%m%d%H%I%M')}.{suffix}"
|
|
250
246
|
|
|
251
247
|
if self._storage_path:
|
|
252
248
|
try:
|
|
@@ -264,8 +260,6 @@ class RscEDFHandler(object):
|
|
|
264
260
|
self._device_type = "C64RS"
|
|
265
261
|
elif device_type == 0x40:
|
|
266
262
|
self._device_type = "LJ64S1"
|
|
267
|
-
elif device_type == 0x45:
|
|
268
|
-
self._device_type = "C256RS"
|
|
269
263
|
elif device_type == 0x51:
|
|
270
264
|
self._device_type = "C256RS"
|
|
271
265
|
elif device_type == 0x60:
|
|
@@ -296,8 +290,6 @@ class RscEDFHandler(object):
|
|
|
296
290
|
logger.info(f"收到结束信号,即将停止写入数据:{self.file_name}")
|
|
297
291
|
self._edf_writer_thread.stop_recording()
|
|
298
292
|
return
|
|
299
|
-
|
|
300
|
-
logger.debug(f"packet: {packet}")
|
|
301
293
|
|
|
302
294
|
with self._lock:
|
|
303
295
|
if self.channels is None:
|
|
@@ -320,7 +312,6 @@ class RscEDFHandler(object):
|
|
|
320
312
|
self._edf_writer_thread.set_start_time(self._start_time)
|
|
321
313
|
self._edf_writer_thread.start()
|
|
322
314
|
logger.info(f"开始写入数据: {self.file_name}")
|
|
323
|
-
self._edf_writer_thread.equipment = f'{self._device_type}_{self._device_no}'
|
|
324
315
|
|
|
325
316
|
self._edf_writer_thread.append(packet.eeg)
|
|
326
317
|
|
|
@@ -340,4 +331,5 @@ class RscEDFHandler(object):
|
|
|
340
331
|
else: onset = 0
|
|
341
332
|
else:
|
|
342
333
|
onset = cur_time - self._first_timestamp
|
|
343
|
-
self._edf_writer_thread.trigger(onset, desc)
|
|
334
|
+
self._edf_writer_thread.trigger(onset, desc)
|
|
335
|
+
|
qlsdk/rsc/command/__init__.py
CHANGED
|
@@ -48,9 +48,8 @@ class DeviceCommand(abc.ABC):
|
|
|
48
48
|
"""构建消息体"""
|
|
49
49
|
return b''
|
|
50
50
|
def pack_header(self, body_len: int) -> bytes:
|
|
51
|
-
|
|
51
|
+
device_id = int(self.device.device_id) if self.device and self.device.device_id else 0
|
|
52
52
|
device_type = int(self.device.device_type) if self.device and self.device.device_type else 0
|
|
53
|
-
device_id = bytes.fromhex(self.device.device_id)[::-1] if self.device.device_id else bytes.fromhex('00000000')
|
|
54
53
|
|
|
55
54
|
#兼容设计
|
|
56
55
|
b_device_type = None
|
|
@@ -62,7 +61,7 @@ class DeviceCommand(abc.ABC):
|
|
|
62
61
|
DeviceCommand.HEADER_PREFIX
|
|
63
62
|
+ int(2).to_bytes(1, 'little') # pkgType
|
|
64
63
|
+ device_type.to_bytes(1, 'little')
|
|
65
|
-
+ device_id
|
|
64
|
+
+ device_id.to_bytes(4, 'little')
|
|
66
65
|
+ (DeviceCommand.HEADER_LEN + body_len + 2).to_bytes(4, 'little') # +1 for checksum
|
|
67
66
|
+ self.cmd_code.to_bytes(2, 'little')
|
|
68
67
|
)
|
|
@@ -205,15 +204,6 @@ class StopAcquisitionCommand(DeviceCommand):
|
|
|
205
204
|
class SetImpedanceParamCommand(DeviceCommand):
|
|
206
205
|
cmd_code = 0x411
|
|
207
206
|
cmd_desc = "设置阻抗测量参数"
|
|
208
|
-
def pack_body(self):
|
|
209
|
-
|
|
210
|
-
return self.device.gen_set_impedance_param()
|
|
211
|
-
def parse_body(self, body):
|
|
212
|
-
result = body[8]
|
|
213
|
-
if result == 0x00:
|
|
214
|
-
logger.info("阻抗测量参数设置成功")
|
|
215
|
-
else:
|
|
216
|
-
logger.warning(f"阻抗测量参数设置失败: {int(result)}")
|
|
217
207
|
|
|
218
208
|
# 启动阻抗测量
|
|
219
209
|
class StartImpedanceCommand(DeviceCommand):
|
|
@@ -221,16 +211,13 @@ class StartImpedanceCommand(DeviceCommand):
|
|
|
221
211
|
cmd_desc = "启动阻抗测量"
|
|
222
212
|
def pack_body(self):
|
|
223
213
|
body = bytes.fromhex('0000')
|
|
224
|
-
body += to_bytes(self.device.
|
|
214
|
+
body += to_bytes(self.device.acq_channels)
|
|
225
215
|
body += bytes.fromhex('0000000000000000') # 8字节占位符
|
|
226
216
|
return body
|
|
227
217
|
|
|
228
218
|
def parse_body(self, body):
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
logger.info("阻抗测量启动成功")
|
|
232
|
-
else:
|
|
233
|
-
logger.warning(f"阻抗测量启动失败: {int(result)}")
|
|
219
|
+
logger.info(f"Received StartImpedance response: {body.hex()}")
|
|
220
|
+
return super().parse_body(body)
|
|
234
221
|
|
|
235
222
|
|
|
236
223
|
# 停止阻抗测量
|
|
@@ -246,7 +233,7 @@ class StartStimulationCommand(DeviceCommand):
|
|
|
246
233
|
cmd_code = 0x48C
|
|
247
234
|
cmd_desc = "启动刺激"
|
|
248
235
|
def pack_body(self):
|
|
249
|
-
return self.device.
|
|
236
|
+
return self.device.stim_paradigm.to_bytes()
|
|
250
237
|
# return bytes.fromhex('01000000000000008813000000000000010000000000000000000140420f00640064000000803f0000010000000000000000000000000000000000000000008813000000000000')
|
|
251
238
|
def parse_body(self, body: bytes):
|
|
252
239
|
# time - 8B
|
|
@@ -256,9 +243,8 @@ class StartStimulationCommand(DeviceCommand):
|
|
|
256
243
|
# error_channel - 8B
|
|
257
244
|
# error_channel= int.from_bytes(body[9:17], 'big')
|
|
258
245
|
channels = to_channels(body[9:17])
|
|
259
|
-
logger.
|
|
260
|
-
|
|
261
|
-
self.device.trigger(f"通道 {channels} 刺激开始")
|
|
246
|
+
logger.success(f"通道 {channels} 刺激开始")
|
|
247
|
+
self.device.trigger(f"通道 {channels} 刺激开始")
|
|
262
248
|
# error_type - 1B
|
|
263
249
|
error_type = body[17]
|
|
264
250
|
|
|
@@ -282,9 +268,8 @@ class StopStimulationNotifyCommand(DeviceCommand):
|
|
|
282
268
|
# error_channel - 8B
|
|
283
269
|
# error_channel= int.from_bytes(body[9:17], 'big')
|
|
284
270
|
channels = to_channels(body[9:17])
|
|
285
|
-
logger.
|
|
286
|
-
|
|
287
|
-
self.device.trigger(f"通道 {channels} 刺激结束", time)
|
|
271
|
+
logger.success(f"通道 {channels} 刺激结束")
|
|
272
|
+
self.device.trigger(f"通道 {channels} 刺激结束", time)
|
|
288
273
|
# error_type - 1B
|
|
289
274
|
error_type = body[17]
|
|
290
275
|
# 刺激信息
|
|
@@ -312,7 +297,8 @@ class ImpedanceDataCommand(DeviceCommand):
|
|
|
312
297
|
cmd_desc = "阻抗数据"
|
|
313
298
|
|
|
314
299
|
def parse_body(self, body: bytes):
|
|
315
|
-
|
|
300
|
+
# logger.info(f"Received impedance data: {body.hex()}")
|
|
301
|
+
packet = ImpedancePacket().transfer(body)
|
|
316
302
|
|
|
317
303
|
# 信号数据
|
|
318
304
|
class SignalDataCommand(DeviceCommand):
|