qlsdk2 0.5.1.1__py3-none-any.whl → 0.6.0a1__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 +95 -20
- qlsdk/core/message/udp.py +9 -1
- qlsdk/entity/__init__.py +0 -0
- qlsdk/entity/message.py +0 -0
- qlsdk/entity/signal.py +0 -0
- qlsdk/interface/__init__.py +10 -0
- qlsdk/interface/analyzer.py +2 -0
- qlsdk/interface/collector.py +10 -0
- qlsdk/interface/device.py +2 -0
- qlsdk/interface/parser.py +13 -0
- qlsdk/interface/stimulator.py +2 -0
- qlsdk/interface/store.py +2 -0
- qlsdk/persist/rsc_edf.py +2 -0
- qlsdk/rsc/command/__init__.py +4 -4
- qlsdk/rsc/device/__init__.py +2 -1
- qlsdk/rsc/device/base.py +60 -27
- qlsdk/rsc/device/c256_rs.py +25 -32
- qlsdk/rsc/device/device_factory.py +1 -0
- qlsdk/rsc/interface/device.py +22 -85
- qlsdk/rsc/interface/parser.py +6 -0
- qlsdk/rsc/manager/container.py +10 -2
- qlsdk/rsc/network/discover.py +2 -0
- qlsdk/rsc/parser/__init__.py +2 -1
- qlsdk/rsc/parser/base.py +1 -1
- qlsdk/rsc/parser/rsc.py +130 -0
- {qlsdk2-0.5.1.1.dist-info → qlsdk2-0.6.0a1.dist-info}/METADATA +16 -7
- {qlsdk2-0.5.1.1.dist-info → qlsdk2-0.6.0a1.dist-info}/RECORD +29 -18
- {qlsdk2-0.5.1.1.dist-info → qlsdk2-0.6.0a1.dist-info}/WHEEL +1 -1
- {qlsdk2-0.5.1.1.dist-info → qlsdk2-0.6.0a1.dist-info}/top_level.txt +0 -0
qlsdk/core/entity/__init__.py
CHANGED
|
@@ -21,33 +21,37 @@ class RscPacket(Packet):
|
|
|
21
21
|
self.trigger = None
|
|
22
22
|
self.eeg = None
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
@staticmethod
|
|
25
|
+
def transfer(body: bytes) -> 'RscPacket':
|
|
26
|
+
packet = RscPacket()
|
|
27
|
+
packet.time_stamp = int.from_bytes(body[0:8], 'little')
|
|
28
|
+
packet.result = body[8]
|
|
29
|
+
packet.pkg_id = int.from_bytes(body[9: 13], 'little')
|
|
30
|
+
logger.trace(f"pkg_id: {packet.pkg_id}")
|
|
31
|
+
packet.channels = to_channels(body[13: 45])
|
|
32
|
+
packet.origin_sample_rate = int.from_bytes(body[45: 49], 'little')
|
|
33
|
+
packet.sample_rate = int.from_bytes(body[49: 53], 'little')
|
|
34
|
+
packet.sample_num = int.from_bytes(body[53: 57], 'little')
|
|
35
|
+
packet.resolution = int(int(body[57]) / 8)
|
|
36
|
+
packet.filter = body[58]
|
|
37
|
+
packet.data_len = int.from_bytes(body[59: 63], 'little')
|
|
36
38
|
# 步径 相同通道的点间隔
|
|
37
|
-
step = int(len(
|
|
38
|
-
self.trigger = [int.from_bytes(body[i:i+4], 'little') for i in range(63, len(body) - 3, step)]
|
|
39
|
+
step = int(len(packet.channels) * packet.resolution + 4)
|
|
39
40
|
b_eeg = body[63:]
|
|
40
|
-
ch_num = len(
|
|
41
|
-
|
|
41
|
+
ch_num = len(packet.channels)
|
|
42
|
+
# 字节序列(4Cn{channel_size}){sample_num})
|
|
43
|
+
packet.trigger = [int.from_bytes(b_eeg[j * step : j * step + 4], 'little', signed=False) for j in range(packet.sample_num)]
|
|
44
|
+
|
|
45
|
+
packet.eeg = [
|
|
42
46
|
[
|
|
43
|
-
int.from_bytes(b_eeg[i *
|
|
44
|
-
for j in range(
|
|
47
|
+
int.from_bytes(b_eeg[i * packet.resolution + 4 + j * step:i * packet.resolution + 4 + j * step + 3], 'big', signed=True)
|
|
48
|
+
for j in range(packet.sample_num)
|
|
45
49
|
]
|
|
46
50
|
for i in range(ch_num)
|
|
47
51
|
]
|
|
48
52
|
|
|
49
53
|
# logger.trace(self)
|
|
50
|
-
return
|
|
54
|
+
return packet
|
|
51
55
|
|
|
52
56
|
def __str__(self):
|
|
53
57
|
return f"""
|
|
@@ -86,4 +90,75 @@ class ImpedancePacket(Packet):
|
|
|
86
90
|
channels: {self.channels}
|
|
87
91
|
data len: {self.data_len}
|
|
88
92
|
impedance: {self.impedance}
|
|
89
|
-
"""
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class C256RSPacket(Packet):
|
|
97
|
+
def __init__(self):
|
|
98
|
+
super().__init__()
|
|
99
|
+
self.origin_sample_rate = None
|
|
100
|
+
self.sample_rate = None
|
|
101
|
+
self.sample_num = None
|
|
102
|
+
self.resolution = None
|
|
103
|
+
self.filter = None
|
|
104
|
+
self.data_len = None
|
|
105
|
+
self.trigger = None
|
|
106
|
+
self.eeg = None
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def transfer(body: bytes) -> 'RscPacket':
|
|
110
|
+
packet = RscPacket()
|
|
111
|
+
packet.time_stamp = int.from_bytes(body[0:8], 'little')
|
|
112
|
+
packet.result = body[8]
|
|
113
|
+
packet.pkg_id = int.from_bytes(body[9: 13], 'little')
|
|
114
|
+
packet.channels = to_channels(body[13: 45])
|
|
115
|
+
logger.trace(f"pkg_id: {packet.pkg_id}, channels: {packet.channels}")
|
|
116
|
+
|
|
117
|
+
packet.origin_sample_rate = int.from_bytes(body[45: 49], 'little')
|
|
118
|
+
packet.sample_rate = int.from_bytes(body[49: 53], 'little')
|
|
119
|
+
packet.sample_num = int.from_bytes(body[53: 57], 'little')
|
|
120
|
+
packet.resolution = int(int(body[57]) / 8)
|
|
121
|
+
packet.filter = body[58]
|
|
122
|
+
packet.data_len = int.from_bytes(body[59: 63], 'little')
|
|
123
|
+
|
|
124
|
+
# 数据块
|
|
125
|
+
b_eeg = body[63:]
|
|
126
|
+
# 根据值域分割数组-代表设备的4个模块
|
|
127
|
+
ranges = [(1, 64), (65, 128), (129, 192), (193, 256)]
|
|
128
|
+
sub_channels = [[x for x in packet.channels if low <= x <= high] for low, high in ranges]
|
|
129
|
+
# 只处理选中的模块
|
|
130
|
+
sub_channels = [_ for _ in sub_channels if len(_) > 0]
|
|
131
|
+
# 步径 相同通道的点间隔
|
|
132
|
+
step = int(len(packet.channels) * packet.resolution + 4 * len(sub_channels))
|
|
133
|
+
offset = 0
|
|
134
|
+
|
|
135
|
+
# 分按子模块处理
|
|
136
|
+
for channels in sub_channels:
|
|
137
|
+
logger.trace(f"子数组: {channels} 长度: {len(channels)}")
|
|
138
|
+
channel_size = len(channels)
|
|
139
|
+
|
|
140
|
+
# 模块没有选中通道的,跳过
|
|
141
|
+
if channel_size == 0:
|
|
142
|
+
continue
|
|
143
|
+
|
|
144
|
+
# 只保留第一个有效模块的trigger,其他的模块是冗余信息,无实际含义
|
|
145
|
+
if packet.trigger is None:
|
|
146
|
+
packet.trigger = [int.from_bytes(b_eeg[j * step : j * step + 4], 'little', signed=False) for j in range(packet.sample_num)]
|
|
147
|
+
logger.trace(f"trigger: {packet.trigger}")
|
|
148
|
+
trigger_positions = [index for index, value in enumerate(packet.trigger) if value != 0]
|
|
149
|
+
if len(trigger_positions) > 0:
|
|
150
|
+
logger.debug(f"Trigger触发点位置: {trigger_positions}, 触发点时间戳: {[packet.time_stamp + int(pos * 1000 / packet.sample_rate) for pos in trigger_positions]}")
|
|
151
|
+
|
|
152
|
+
eeg = [
|
|
153
|
+
[
|
|
154
|
+
int.from_bytes(b_eeg[offset + step * j + 4 + k * packet.resolution : offset + step * j + 7 + k * packet.resolution], 'big', signed=True)
|
|
155
|
+
for j in range(packet.sample_num)
|
|
156
|
+
]
|
|
157
|
+
for k in range(channel_size)
|
|
158
|
+
]
|
|
159
|
+
packet.eeg = packet.eeg + eeg if packet.eeg else eeg
|
|
160
|
+
|
|
161
|
+
offset += 4 + channel_size * packet.resolution
|
|
162
|
+
|
|
163
|
+
logger.trace(packet)
|
|
164
|
+
return packet
|
qlsdk/core/message/udp.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from time import timezone
|
|
4
4
|
from qlsdk.core.crc import check_crc, crc16
|
|
5
|
-
from qlsdk.core.local import get_ip
|
|
5
|
+
from qlsdk.core.local import get_ip, get_ips
|
|
6
6
|
|
|
7
7
|
from loguru import logger
|
|
8
8
|
|
|
@@ -72,6 +72,14 @@ class UDPMessage(object):
|
|
|
72
72
|
if server_ip is None:
|
|
73
73
|
server_ip = get_ip()
|
|
74
74
|
|
|
75
|
+
return UDPMessage._search_(device_id, server_ip, server_port)
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def _search_(device_id : str, server_ip : str, server_port : int=19216):
|
|
79
|
+
# 服务端Ip
|
|
80
|
+
if server_ip is None:
|
|
81
|
+
raise ValueError("server_ip is None")
|
|
82
|
+
|
|
75
83
|
logger.debug(f"search device {device_id} on {server_ip}:{server_port}")
|
|
76
84
|
|
|
77
85
|
message = bytearray(28)
|
qlsdk/entity/__init__.py
ADDED
|
File without changes
|
qlsdk/entity/message.py
ADDED
|
File without changes
|
qlsdk/entity/signal.py
ADDED
|
File without changes
|
qlsdk/interface/store.py
ADDED
qlsdk/persist/rsc_edf.py
CHANGED
|
@@ -260,6 +260,8 @@ class RscEDFHandler(object):
|
|
|
260
260
|
self._device_type = "C64RS"
|
|
261
261
|
elif device_type == 0x40:
|
|
262
262
|
self._device_type = "LJ64S1"
|
|
263
|
+
elif device_type == 0x51:
|
|
264
|
+
self._device_type = "C256RS"
|
|
263
265
|
elif device_type == 0x60:
|
|
264
266
|
self._device_type = "ARSKindling"
|
|
265
267
|
elif device_type == 0x339:
|
qlsdk/rsc/command/__init__.py
CHANGED
|
@@ -309,11 +309,11 @@ class SignalDataCommand(DeviceCommand):
|
|
|
309
309
|
return super().unpack(payload)
|
|
310
310
|
|
|
311
311
|
def parse_body(self, body: bytes):
|
|
312
|
-
# 解析数据包
|
|
313
|
-
packet = RscPacket()
|
|
314
|
-
packet.transfer(body)
|
|
312
|
+
# # 解析数据包
|
|
313
|
+
# packet = RscPacket()
|
|
314
|
+
# packet.transfer(body)
|
|
315
315
|
# 将数据包传递给设备
|
|
316
|
-
self.device.produce(
|
|
316
|
+
self.device.produce(body)
|
|
317
317
|
|
|
318
318
|
|
|
319
319
|
|
qlsdk/rsc/device/__init__.py
CHANGED
qlsdk/rsc/device/base.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
from multiprocessing import Queue
|
|
3
2
|
from threading import Thread
|
|
4
3
|
from time import sleep, time_ns
|
|
@@ -8,10 +7,9 @@ from loguru import logger
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
from qlsdk.core.entity import RscPacket
|
|
10
9
|
from qlsdk.core.utils import to_bytes
|
|
11
|
-
from qlsdk.persist import RscEDFHandler
|
|
12
10
|
from qlsdk.rsc.interface import IDevice, IParser
|
|
13
|
-
from qlsdk.rsc.parser import TcpMessageParser
|
|
14
11
|
from qlsdk.rsc.command import StartImpedanceCommand, StopImpedanceCommand, StartStimulationCommand, StopStimulationCommand, SetAcquisitionParamCommand, StartAcquisitionCommand, StopAcquisitionCommand
|
|
12
|
+
from qlsdk.rsc.parser.base import TcpMessageParser
|
|
15
13
|
|
|
16
14
|
class QLBaseDevice(IDevice):
|
|
17
15
|
def __init__(self, socket):
|
|
@@ -137,12 +135,18 @@ class QLBaseDevice(IDevice):
|
|
|
137
135
|
self._record_duration = record_duration
|
|
138
136
|
|
|
139
137
|
# 数据包处理
|
|
140
|
-
def produce(self,
|
|
141
|
-
if
|
|
138
|
+
def produce(self, body: bytes, type:Literal['signal', 'impedance']="signal"):
|
|
139
|
+
if body is None: return
|
|
142
140
|
|
|
143
141
|
# 处理信号数据
|
|
144
|
-
self._signal_wrapper(
|
|
145
|
-
|
|
142
|
+
data = self._signal_wrapper(body)
|
|
143
|
+
# logger.debug("pkg_id: {}, eeg len: {}".format(data.pkg_id, len(data.eeg)))
|
|
144
|
+
#
|
|
145
|
+
trigger_positions = [index for index, value in enumerate(data.trigger) if value != 0]
|
|
146
|
+
if len(trigger_positions) > 0:
|
|
147
|
+
# logger.debug(f"Trigger触发点位置: {trigger_positions}, 触发点时间戳: {[data.time_stamp + int(pos * 1000 / data.sample_rate) for pos in trigger_positions]}")
|
|
148
|
+
for pos in trigger_positions:
|
|
149
|
+
self.trigger(data.trigger[pos])
|
|
146
150
|
# 存储
|
|
147
151
|
if self.storage_enable:
|
|
148
152
|
self._write_signal(data)
|
|
@@ -159,9 +163,9 @@ class QLBaseDevice(IDevice):
|
|
|
159
163
|
|
|
160
164
|
q.put(data)
|
|
161
165
|
|
|
162
|
-
# 信号数据转换
|
|
163
|
-
def _signal_wrapper(self,
|
|
164
|
-
|
|
166
|
+
# 信号数据转换
|
|
167
|
+
def _signal_wrapper(self, body: bytes):
|
|
168
|
+
return RscPacket().transfer(body)
|
|
165
169
|
|
|
166
170
|
def _write_signal(self, data: RscPacket):
|
|
167
171
|
# 文件写入到edf
|
|
@@ -175,8 +179,10 @@ class QLBaseDevice(IDevice):
|
|
|
175
179
|
def start_listening(self):
|
|
176
180
|
|
|
177
181
|
try:
|
|
182
|
+
# 启动消息解析器
|
|
178
183
|
self.start_message_parser()
|
|
179
184
|
|
|
185
|
+
# 启动消息监听器
|
|
180
186
|
self.start_message_listening()
|
|
181
187
|
except Exception as e:
|
|
182
188
|
logger.error(f"设备{self.device_no}准备失败: {str(e)}")
|
|
@@ -188,7 +194,22 @@ class QLBaseDevice(IDevice):
|
|
|
188
194
|
logger.trace(f"设备{self.device_no}停止socket监听")
|
|
189
195
|
self._listening = False
|
|
190
196
|
self._parser.stop()
|
|
191
|
-
|
|
197
|
+
|
|
198
|
+
def read_msg(self, size: int) -> bytes:
|
|
199
|
+
try:
|
|
200
|
+
self.socket.settimeout(2.0)
|
|
201
|
+
return self.socket.recv(size)
|
|
202
|
+
except Exception as e:
|
|
203
|
+
logger.error(f"read_msg exception: {str(e)}")
|
|
204
|
+
raise ValueError("read_msg exception") from e
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def from_parent(cls, parent:IDevice) -> IDevice:
|
|
208
|
+
rlt = cls(parent.socket)
|
|
209
|
+
rlt.device_id = parent.device_id
|
|
210
|
+
rlt._device_no = parent.device_no
|
|
211
|
+
return rlt
|
|
212
|
+
|
|
192
213
|
@property
|
|
193
214
|
def device_type(self) -> int:
|
|
194
215
|
return self._device_type
|
|
@@ -196,18 +217,21 @@ class QLBaseDevice(IDevice):
|
|
|
196
217
|
def start_message_parser(self) -> None:
|
|
197
218
|
self._parser = TcpMessageParser(self)
|
|
198
219
|
self._parser.start()
|
|
199
|
-
logger.debug("
|
|
220
|
+
logger.debug("RSC消息解析器已启动")
|
|
200
221
|
|
|
201
222
|
def start_message_listening(self) -> None:
|
|
202
223
|
def _accept():
|
|
203
224
|
while self._listening:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
225
|
+
try:
|
|
226
|
+
# 缓冲区4M
|
|
227
|
+
data = self.socket.recv(4096*1024)
|
|
228
|
+
if not data:
|
|
229
|
+
logger.warning(f"设备[{self.device_name}]连接结束")
|
|
230
|
+
break
|
|
231
|
+
self._parser.append(data)
|
|
232
|
+
except Exception as e:
|
|
233
|
+
logger.debug(f"设备[{self.device_name}]接收数据异常: {str(e)}")
|
|
208
234
|
break
|
|
209
|
-
|
|
210
|
-
self._parser.append(data)
|
|
211
235
|
|
|
212
236
|
# 启动数据接收线程
|
|
213
237
|
self._listening = True
|
|
@@ -252,11 +276,6 @@ class QLBaseDevice(IDevice):
|
|
|
252
276
|
def init_edf_handler(self):
|
|
253
277
|
logger.warning("init_edf_handler not implemented in base class, should be overridden in subclass")
|
|
254
278
|
pass
|
|
255
|
-
# self._edf_handler = RscEDFHandler(self.sample_rate, self.sample_range * 1000 , - self.sample_range * 1000, self.resolution)
|
|
256
|
-
# self._edf_handler.set_device_type(self.device_type)
|
|
257
|
-
# self._edf_handler.set_device_no(self.device_no)
|
|
258
|
-
# self._edf_handler.set_storage_path(self._storage_path)
|
|
259
|
-
# self._edf_handler.set_file_prefix(self._file_prefix)
|
|
260
279
|
|
|
261
280
|
# eeg数字值转物理值
|
|
262
281
|
def eeg2phy(self, digital:int):
|
|
@@ -444,12 +463,26 @@ class QLBaseDevice(IDevice):
|
|
|
444
463
|
|
|
445
464
|
return body
|
|
446
465
|
|
|
466
|
+
def disconnect(self):
|
|
467
|
+
logger.info(f"[断开设备-{self.device_no}]的连接...")
|
|
468
|
+
self._listening = False
|
|
469
|
+
try:
|
|
470
|
+
sleep(0.1)
|
|
471
|
+
self.socket.shutdown(2)
|
|
472
|
+
self.socket.close()
|
|
473
|
+
logger.info(f"[设备-{self.device_no}]设备连接已断开")
|
|
474
|
+
except Exception as e:
|
|
475
|
+
logger.error(f"断开设备连接异常: {str(e)}")
|
|
476
|
+
|
|
477
|
+
# 关闭解析器
|
|
478
|
+
self._parser.stop()
|
|
479
|
+
|
|
447
480
|
def __str__(self):
|
|
448
481
|
return f'''
|
|
449
482
|
Device:
|
|
450
483
|
Name: {self.device_name},
|
|
451
484
|
Type: {hex(self.device_type) if self.device_type else None},
|
|
452
|
-
ID: {self.
|
|
485
|
+
ID: {self.device_no if self.device_no else None},
|
|
453
486
|
Software: {self.software_version},
|
|
454
487
|
Hardware: {self.hardware_version},
|
|
455
488
|
Connect Time: {self.connect_time},
|
|
@@ -459,8 +492,8 @@ class QLBaseDevice(IDevice):
|
|
|
459
492
|
Battery Total: {str(self.battery_total) + "%" if self.battery_total else None}
|
|
460
493
|
'''
|
|
461
494
|
|
|
462
|
-
def __eq__(self, other):
|
|
463
|
-
return self.
|
|
495
|
+
def __eq__(self, other:IDevice):
|
|
496
|
+
return self.device_type == other.device_type and self.device_no == other.device_no
|
|
464
497
|
|
|
465
498
|
def __hash__(self):
|
|
466
|
-
return hash((self.
|
|
499
|
+
return hash((self.device_type, self.device_no))
|
qlsdk/rsc/device/c256_rs.py
CHANGED
|
@@ -5,15 +5,15 @@ from time import sleep, time_ns
|
|
|
5
5
|
from typing import Any, Dict, Literal
|
|
6
6
|
|
|
7
7
|
from loguru import logger
|
|
8
|
+
from qlsdk.core.entity import C256RSPacket
|
|
8
9
|
from qlsdk.persist import RscEDFHandler
|
|
9
|
-
from qlsdk.rsc.
|
|
10
|
+
from qlsdk.rsc.device.device_factory import DeviceFactory
|
|
10
11
|
from qlsdk.rsc.command import *
|
|
11
|
-
from qlsdk.rsc.parser.base import TcpMessageParser
|
|
12
12
|
from qlsdk.rsc.device.base import QLBaseDevice
|
|
13
13
|
|
|
14
14
|
class C256RS(QLBaseDevice):
|
|
15
15
|
|
|
16
|
-
device_type =
|
|
16
|
+
device_type = 0x51 # C64RS设备类型标识符
|
|
17
17
|
|
|
18
18
|
def __init__(self, socket):
|
|
19
19
|
super().__init__(socket)
|
|
@@ -125,13 +125,13 @@ class C256RS(QLBaseDevice):
|
|
|
125
125
|
self._edf_handler = None
|
|
126
126
|
self.storage_enable = True
|
|
127
127
|
|
|
128
|
-
self._parser: IParser =
|
|
129
|
-
self._parser.start()
|
|
128
|
+
# self._parser: IParser = RSCMessageParser(self)
|
|
129
|
+
# self._parser.start()
|
|
130
130
|
|
|
131
131
|
# 启动数据接收线程
|
|
132
|
-
self._accept = Thread(target=self.accept)
|
|
133
|
-
self._accept.daemon = True
|
|
134
|
-
self._accept.start()
|
|
132
|
+
# self._accept = Thread(target=self.accept)
|
|
133
|
+
# self._accept.daemon = True
|
|
134
|
+
# self._accept.start()
|
|
135
135
|
|
|
136
136
|
@property
|
|
137
137
|
def device_no(self):
|
|
@@ -140,21 +140,14 @@ class C256RS(QLBaseDevice):
|
|
|
140
140
|
@device_no.setter
|
|
141
141
|
def device_no(self, value: str):
|
|
142
142
|
self._device_no = value
|
|
143
|
-
|
|
144
|
-
@classmethod
|
|
145
|
-
def from_parent(cls, parent:IDevice) -> IDevice:
|
|
146
|
-
rlt = cls(parent.socket)
|
|
147
|
-
rlt.device_id = parent.device_id
|
|
148
|
-
rlt._device_no = parent.device_no
|
|
149
|
-
return rlt
|
|
150
|
-
|
|
143
|
+
|
|
151
144
|
|
|
152
145
|
def init_edf_handler(self):
|
|
153
146
|
self._edf_handler = RscEDFHandler(self.sample_rate, self.sample_range * 1000 , - self.sample_range * 1000, self.resolution)
|
|
154
147
|
self._edf_handler.set_device_type(self.device_type)
|
|
155
|
-
self._edf_handler.set_device_no(self.
|
|
148
|
+
self._edf_handler.set_device_no(self.device_no)
|
|
156
149
|
self._edf_handler.set_storage_path(self._storage_path)
|
|
157
|
-
self._edf_handler.set_file_prefix(self._file_prefix)
|
|
150
|
+
self._edf_handler.set_file_prefix(self._file_prefix if self._file_prefix else 'C256RS')
|
|
158
151
|
|
|
159
152
|
@property
|
|
160
153
|
def edf_handler(self):
|
|
@@ -169,7 +162,7 @@ class C256RS(QLBaseDevice):
|
|
|
169
162
|
@property
|
|
170
163
|
def acq_channels(self):
|
|
171
164
|
if self._acq_channels is None:
|
|
172
|
-
self._acq_channels = [i for i in range(1,
|
|
165
|
+
self._acq_channels = [i for i in range(1, 256)]
|
|
173
166
|
return self._acq_channels
|
|
174
167
|
@property
|
|
175
168
|
def sample_range(self):
|
|
@@ -199,15 +192,15 @@ class C256RS(QLBaseDevice):
|
|
|
199
192
|
|
|
200
193
|
# 接收socket消息
|
|
201
194
|
def accept(self):
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
self._parser.append(data)
|
|
195
|
+
pass
|
|
196
|
+
# while True:
|
|
197
|
+
# # 缓冲去4M
|
|
198
|
+
# data = self.socket.recv(4096*1024)
|
|
199
|
+
# if not data:
|
|
200
|
+
# logger.warning(f"设备{self.device_name}连接结束")
|
|
201
|
+
# break
|
|
210
202
|
|
|
203
|
+
# self._parser.append(data)
|
|
211
204
|
|
|
212
205
|
# socket发送数据
|
|
213
206
|
def send(self, data):
|
|
@@ -226,9 +219,8 @@ class C256RS(QLBaseDevice):
|
|
|
226
219
|
self._sample_rate = sample_rate
|
|
227
220
|
self._sample_range = sample_range
|
|
228
221
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
pass
|
|
222
|
+
def _signal_wrapper(self, body: bytes):
|
|
223
|
+
return C256RSPacket().transfer(body)
|
|
232
224
|
|
|
233
225
|
def start_impedance(self):
|
|
234
226
|
logger.info("启动阻抗测量")
|
|
@@ -297,7 +289,7 @@ class C256RS(QLBaseDevice):
|
|
|
297
289
|
|
|
298
290
|
# 数据队列
|
|
299
291
|
if q is None:
|
|
300
|
-
q = Queue(maxsize=
|
|
292
|
+
q = Queue(maxsize=10240000) # 10M缓存
|
|
301
293
|
|
|
302
294
|
# 队列名称
|
|
303
295
|
if topic is None:
|
|
@@ -362,4 +354,5 @@ class C256RS(QLBaseDevice):
|
|
|
362
354
|
def __hash__(self):
|
|
363
355
|
return hash((self.device_name, self.device_type, self.device_id))
|
|
364
356
|
|
|
365
|
-
|
|
357
|
+
|
|
358
|
+
DeviceFactory.register(C256RS.device_type, C256RS)
|
qlsdk/rsc/interface/device.py
CHANGED
|
@@ -10,118 +10,55 @@ class IDevice(ABC):
|
|
|
10
10
|
pass
|
|
11
11
|
|
|
12
12
|
def set_device_type(self, value: int):
|
|
13
|
-
|
|
13
|
+
raise NotImplementedError("Not Supported")
|
|
14
14
|
|
|
15
15
|
def set_storage_path(self, path: str):
|
|
16
|
-
|
|
16
|
+
raise NotImplementedError("Not Supported")
|
|
17
17
|
|
|
18
18
|
def set_file_prefix(self, pre: str):
|
|
19
|
-
|
|
19
|
+
raise NotImplementedError("Not Supported")
|
|
20
20
|
|
|
21
21
|
def set_acq_param(self, channels, sample_rate = 500, sample_range = 188):
|
|
22
|
-
|
|
22
|
+
raise NotImplementedError("Not Supported")
|
|
23
23
|
|
|
24
24
|
@property
|
|
25
25
|
def device_no(self) -> str:
|
|
26
26
|
pass
|
|
27
27
|
|
|
28
|
-
def
|
|
29
|
-
|
|
28
|
+
def read_msg(self, size: int) -> bytes:
|
|
29
|
+
raise NotImplementedError("Not Supported")
|
|
30
|
+
|
|
31
|
+
def produce(self, body: bytes, type:Literal['signal', 'impedance']="signal") -> None:
|
|
32
|
+
raise NotImplementedError("Not Supported")
|
|
30
33
|
|
|
31
34
|
def start_listening(self):
|
|
32
|
-
|
|
35
|
+
raise NotImplementedError("Not Supported")
|
|
33
36
|
|
|
34
37
|
def stop_listening(self):
|
|
35
|
-
|
|
38
|
+
raise NotImplementedError("Not Supported")
|
|
36
39
|
|
|
37
40
|
def set_device_no(self, value: str):
|
|
38
|
-
|
|
41
|
+
raise NotImplementedError("Not Supported")
|
|
39
42
|
|
|
40
43
|
def from_parent(cls, parent) :
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def start_implementation(self) -> None:
|
|
44
|
-
pass
|
|
45
|
-
|
|
46
|
-
def stop_implementation(self) -> None:
|
|
47
|
-
pass
|
|
44
|
+
raise NotImplementedError("Not Supported")
|
|
48
45
|
|
|
49
46
|
def start_acquisition(self) -> None:
|
|
50
|
-
|
|
47
|
+
raise NotImplementedError("Not Supported")
|
|
51
48
|
|
|
52
49
|
def stop_acquisition(self) -> None:
|
|
53
|
-
|
|
50
|
+
raise NotImplementedError("Not Supported")
|
|
54
51
|
|
|
55
52
|
def subscribe(self, type="signal") -> None:
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
raise NotImplementedError("Not Supported")
|
|
58
54
|
def unsubscribe(self, topic) -> None:
|
|
59
|
-
|
|
55
|
+
raise NotImplementedError("Not Supported")
|
|
60
56
|
|
|
61
57
|
def start_stimulation(self, type="signal", duration=0) -> None:
|
|
62
|
-
|
|
58
|
+
raise NotImplementedError("Not Supported")
|
|
63
59
|
|
|
64
60
|
def stop_stimulation(self) -> None:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class RscDevice(IDevice):
|
|
73
|
-
def __init__(self, socket):
|
|
74
|
-
super().__init__(socket)
|
|
75
|
-
|
|
76
|
-
def start_implementation(self):
|
|
77
|
-
"""
|
|
78
|
-
Start the device implementation
|
|
79
|
-
"""
|
|
80
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
81
|
-
|
|
82
|
-
def stop_implementation(self):
|
|
83
|
-
"""
|
|
84
|
-
Stop the device implementation
|
|
85
|
-
"""
|
|
86
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
87
|
-
|
|
88
|
-
def start_acquisition(self):
|
|
89
|
-
"""
|
|
90
|
-
Start data acquisition
|
|
91
|
-
"""
|
|
92
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
93
|
-
|
|
94
|
-
def stop_acquisition(self):
|
|
95
|
-
"""
|
|
96
|
-
Stop data acquisition
|
|
97
|
-
"""
|
|
98
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
99
|
-
|
|
100
|
-
def subscribe(self, type="signal"):
|
|
101
|
-
"""
|
|
102
|
-
Subscribe to data of a specific type (default is "signal")
|
|
103
|
-
"""
|
|
104
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
105
|
-
|
|
106
|
-
def unsubscribe(self, topic):
|
|
107
|
-
"""
|
|
108
|
-
Unsubscribe from a specific topic
|
|
109
|
-
"""
|
|
110
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
111
|
-
|
|
112
|
-
def start_stimulation(self, type="signal", duration=0):
|
|
113
|
-
"""
|
|
114
|
-
Start stimulation of a specific type (default is "signal") for a given duration
|
|
115
|
-
"""
|
|
116
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
117
|
-
|
|
118
|
-
def stop_stimulation(self):
|
|
119
|
-
"""
|
|
120
|
-
Stop stimulation
|
|
121
|
-
"""
|
|
122
|
-
raise NotImplementedError("This method should be overridden by subclasses")
|
|
123
|
-
|
|
124
|
-
class ProxyDevice(IDevice):
|
|
125
|
-
def __init__(self, socket, proxy_socket):
|
|
126
|
-
super().__init__(socket)
|
|
127
|
-
self.proxy_socket = proxy_socket
|
|
61
|
+
raise NotImplementedError("Not Supported")
|
|
62
|
+
def disconnect(self) -> None:
|
|
63
|
+
raise NotImplementedError("Not Supported")
|
|
64
|
+
|
qlsdk/rsc/interface/parser.py
CHANGED
qlsdk/rsc/manager/container.py
CHANGED
|
@@ -90,11 +90,11 @@ class DeviceContainer(object):
|
|
|
90
90
|
device.start_listening()
|
|
91
91
|
# GET_DEVICE_INFO
|
|
92
92
|
msg = GetDeviceInfoCommand.build(device).pack()
|
|
93
|
-
logger.
|
|
93
|
+
logger.debug(f"发送获取设备信息命令: {msg.hex()}")
|
|
94
94
|
device.send(msg)
|
|
95
95
|
# 添加设备
|
|
96
96
|
while True:
|
|
97
|
-
if device.
|
|
97
|
+
if device.device_no:
|
|
98
98
|
real_device = DeviceFactory.create_device(device)
|
|
99
99
|
device.stop_listening()
|
|
100
100
|
real_device.start_listening()
|
|
@@ -117,6 +117,14 @@ class DeviceContainer(object):
|
|
|
117
117
|
# 标记设备为已连接
|
|
118
118
|
self._broadcaster.mark_device_as_connected(device.device_no)
|
|
119
119
|
|
|
120
|
+
def remove_device(self, device_no:str=None):
|
|
121
|
+
if device_no is None:
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
if device_no in self._devices:
|
|
125
|
+
del self._devices[device_no]
|
|
126
|
+
logger.info(f"从设备列表移除设备[{device_no}],已连接设备数量:{len(self._devices)}")
|
|
127
|
+
|
|
120
128
|
def get_device(self, device_no:str=None)->IDevice:
|
|
121
129
|
logger.info(f"已连接设备数量:{len(self._devices)}")
|
|
122
130
|
if len(self._devices) == 0:
|
qlsdk/rsc/network/discover.py
CHANGED
|
@@ -4,6 +4,7 @@ from threading import Thread, Lock
|
|
|
4
4
|
from loguru import logger
|
|
5
5
|
|
|
6
6
|
from qlsdk.core.message import UDPMessage
|
|
7
|
+
from qlsdk.core.local import get_ips
|
|
7
8
|
|
|
8
9
|
'''
|
|
9
10
|
广播器类,用于发送和接收设备广播消息
|
|
@@ -55,6 +56,7 @@ class UdpBroadcaster:
|
|
|
55
56
|
def broadcast_devices(self):
|
|
56
57
|
|
|
57
58
|
while self.running:
|
|
59
|
+
ips = get_ips()
|
|
58
60
|
with self.lock:
|
|
59
61
|
for device_id in self.devices_to_broadcast:
|
|
60
62
|
message = UDPMessage.search(device_id)
|
qlsdk/rsc/parser/__init__.py
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
from .base import TcpMessageParser
|
|
1
|
+
from .base import TcpMessageParser
|
|
2
|
+
from .rsc import RSCMessageParser
|
qlsdk/rsc/parser/base.py
CHANGED
|
@@ -53,7 +53,7 @@ class TcpMessageParser(IParser):
|
|
|
53
53
|
buf_len = get_len(self.buffer)
|
|
54
54
|
|
|
55
55
|
if buf_len < self.header_len:
|
|
56
|
-
logger.trace(f"
|
|
56
|
+
logger.trace(f"等待数据中...: expect: {self.header_len}, actual: {buf_len}")
|
|
57
57
|
if not self.__fill_from_cache():
|
|
58
58
|
time.sleep(0.1)
|
|
59
59
|
continue
|
qlsdk/rsc/parser/rsc.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from multiprocessing import Lock
|
|
2
|
+
from qlsdk.rsc.interface import IDevice, IParser
|
|
3
|
+
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from threading import Thread
|
|
6
|
+
from time import time_ns
|
|
7
|
+
from qlsdk.rsc.command import CommandFactory
|
|
8
|
+
|
|
9
|
+
class RSCMessageParser(IParser):
|
|
10
|
+
def __init__(self, device : IDevice):
|
|
11
|
+
# 待解析的数据来源于该设备
|
|
12
|
+
self.device = device
|
|
13
|
+
self.running = False
|
|
14
|
+
|
|
15
|
+
# 缓冲区-用于处理数据
|
|
16
|
+
self.buffer:bytearray = bytearray()
|
|
17
|
+
# 读写锁-用于临时缓冲区(避免读写冲突)
|
|
18
|
+
self._lock = Lock()
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def header(self):
|
|
22
|
+
return b'\x5A\xA5'
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def header_len(self):
|
|
26
|
+
return 14
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def cmd_pos(self):
|
|
30
|
+
return 12
|
|
31
|
+
|
|
32
|
+
def set_device(self, device):
|
|
33
|
+
self.device = device
|
|
34
|
+
|
|
35
|
+
def append(self, value):
|
|
36
|
+
print(f"append value len: {len(value)}")
|
|
37
|
+
def __parser__(self):
|
|
38
|
+
logger.info("数据解析开始")
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
while self.running:
|
|
42
|
+
|
|
43
|
+
# 查找消息头
|
|
44
|
+
while len(self.buffer) < len(self.header):
|
|
45
|
+
read_data = self.device.read_msg(1)
|
|
46
|
+
if read_data is None:
|
|
47
|
+
if self.running:
|
|
48
|
+
continue
|
|
49
|
+
else:
|
|
50
|
+
break
|
|
51
|
+
if read_data[0] == self.header[len(self.buffer)]:
|
|
52
|
+
self.buffer.extend(read_data)
|
|
53
|
+
else:
|
|
54
|
+
self.buffer.clear()
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
if len(self.buffer) < len(self.header):
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# 判断消息头
|
|
62
|
+
while len(self.buffer) < self.header_len:
|
|
63
|
+
read_data = self.device.read_msg(self.header_len - len(self.buffer))
|
|
64
|
+
if read_data is None:
|
|
65
|
+
if self.running:
|
|
66
|
+
continue
|
|
67
|
+
else:
|
|
68
|
+
break
|
|
69
|
+
self.buffer.extend(read_data)
|
|
70
|
+
|
|
71
|
+
# # 移动下标(指向包长度的位置)
|
|
72
|
+
# self.buffer.seek(self.start_pos + 8)
|
|
73
|
+
# 包总长度
|
|
74
|
+
pkg_len = int.from_bytes(self.buffer[8:12], 'little')
|
|
75
|
+
# 256*32K = 8388608
|
|
76
|
+
# 太长2M
|
|
77
|
+
if pkg_len > 2048000:
|
|
78
|
+
print(f"error message pkg_len={pkg_len} > 1000000")
|
|
79
|
+
self.buffer.clear()
|
|
80
|
+
continue
|
|
81
|
+
# 太短
|
|
82
|
+
if pkg_len < self.header_len:
|
|
83
|
+
print(f"error message pkg_len={pkg_len} < {self.header_len}")
|
|
84
|
+
self.buffer.clear()
|
|
85
|
+
continue
|
|
86
|
+
|
|
87
|
+
# 读取消息体
|
|
88
|
+
while len(self.buffer) < pkg_len:
|
|
89
|
+
read_data = self.device.read_msg(pkg_len - len(self.buffer))
|
|
90
|
+
if read_data is None:
|
|
91
|
+
if self.running:
|
|
92
|
+
continue
|
|
93
|
+
else:
|
|
94
|
+
break
|
|
95
|
+
self.buffer.extend(read_data)
|
|
96
|
+
|
|
97
|
+
if len(self.buffer) < pkg_len:
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
# msg_crc = self.buffer[-2:]
|
|
101
|
+
# cal_crc = (bytes_buffer, len(bytes_buffer) - 2)
|
|
102
|
+
# if cal_crc != msg_crc:
|
|
103
|
+
# print(f'crc fail {cal_crc} {msg_crc}')
|
|
104
|
+
# if cal_crc != msg_crc:
|
|
105
|
+
# print(f'crc fail {cal_crc} {msg_crc}')
|
|
106
|
+
|
|
107
|
+
self.unpack(self.buffer)
|
|
108
|
+
self.buffer.clear()
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.error(f"数据解析异常: {e}")
|
|
112
|
+
|
|
113
|
+
logger.info(f"数据解析结束:{self.running}")
|
|
114
|
+
|
|
115
|
+
def unpack(self, packet):
|
|
116
|
+
# 提取指令码
|
|
117
|
+
cmd_code = int.from_bytes(packet[self.cmd_pos : self.cmd_pos + 2], 'little')
|
|
118
|
+
cmd_class = CommandFactory.create_command(cmd_code)
|
|
119
|
+
instance = cmd_class(self.device)
|
|
120
|
+
instance.parse_body(packet[self.header_len:-2])
|
|
121
|
+
return instance
|
|
122
|
+
|
|
123
|
+
def start(self):
|
|
124
|
+
self.running = True
|
|
125
|
+
parser = Thread(target=self.__parser__, daemon=True)
|
|
126
|
+
parser.start()
|
|
127
|
+
|
|
128
|
+
def stop(self):
|
|
129
|
+
self.running = False
|
|
130
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: qlsdk2
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0a1
|
|
4
4
|
Summary: SDK for quanlan device
|
|
5
5
|
Home-page: https://github.com/hehuajun/qlsdk
|
|
6
6
|
Author: hehuajun
|
|
@@ -10,12 +10,21 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
10
10
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
11
11
|
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
|
-
Requires-Dist: loguru
|
|
14
|
-
Requires-Dist: numpy
|
|
15
|
-
Requires-Dist: bitarray
|
|
13
|
+
Requires-Dist: loguru>=0.6.0
|
|
14
|
+
Requires-Dist: numpy>=1.23.5
|
|
15
|
+
Requires-Dist: bitarray>=1.5.3
|
|
16
16
|
Provides-Extra: dev
|
|
17
|
-
Requires-Dist: pytest
|
|
18
|
-
Requires-Dist: twine
|
|
17
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
18
|
+
Requires-Dist: twine>=3.0; extra == "dev"
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: author-email
|
|
21
|
+
Dynamic: classifier
|
|
22
|
+
Dynamic: description
|
|
23
|
+
Dynamic: description-content-type
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: requires-dist
|
|
26
|
+
Dynamic: requires-python
|
|
27
|
+
Dynamic: summary
|
|
19
28
|
|
|
20
29
|
## **v0.5.1.1** (2025-08-24)
|
|
21
30
|
#### 🐛 Bug Fixed
|
|
@@ -8,19 +8,29 @@ qlsdk/core/local.py,sha256=vbison4XZtS4SNYLJ9CqBhetEcukdviTWmvtdA1efkQ,811
|
|
|
8
8
|
qlsdk/core/utils.py,sha256=yfCiLpufO96I68MLs6Drc6IECRjcQ-If8sXn7RaRHrk,4241
|
|
9
9
|
qlsdk/core/crc/__init__.py,sha256=kaYSr6KN5g4U49xlxAvT2lnEeGtwX4Dz1ArwKDvUIIY,143
|
|
10
10
|
qlsdk/core/crc/crctools.py,sha256=sDeE6CMccQX2cRAyMQK0SZUk1fa50XMuwqXau5UX5C8,4242
|
|
11
|
-
qlsdk/core/entity/__init__.py,sha256=
|
|
11
|
+
qlsdk/core/entity/__init__.py,sha256=LOS5k_cIA-NYnvE94KUXCBUU_uu1v8FcXf7L399j8Yg,6610
|
|
12
12
|
qlsdk/core/filter/__init__.py,sha256=YIWIzDUKN30mq2JTr53ZGblggZfC_rLUp2FSRrsQFgU,36
|
|
13
13
|
qlsdk/core/filter/norch.py,sha256=5RdIBX5eqs5w5nmVAnCB3ESSuAT_vVBZ2g-dg6HMZdY,1858
|
|
14
14
|
qlsdk/core/message/__init__.py,sha256=sHuavOyHf4bhH6VdDpTA1EsCh7Q-XsPHcFiItpVz3Rs,51
|
|
15
15
|
qlsdk/core/message/command.py,sha256=94AyM6qmgVHQ8qzNLczdL8iY6N-2uEP5oBU6kD6pOG8,12102
|
|
16
16
|
qlsdk/core/message/tcp.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
qlsdk/core/message/udp.py,sha256=
|
|
17
|
+
qlsdk/core/message/udp.py,sha256=e_w35NSlgmhptzlMNGee7rE7KVgeLDO2WhE6FEnuy-0,3387
|
|
18
18
|
qlsdk/core/network/__init__.py,sha256=9Ww0cGgBEU_TVrwmgiDz20zA2fMFgepI_kOF4ggHcS0,1111
|
|
19
19
|
qlsdk/core/network/monitor.py,sha256=QqjjPwSr1kgqDTTySp5bpalZmsBQTaAWSxrfPLdROZo,1810
|
|
20
|
+
qlsdk/entity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
qlsdk/entity/message.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
qlsdk/entity/signal.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
qlsdk/interface/__init__.py,sha256=zvXbyjbMWlPBt7AhD7fF4JwTrDqwkdyH8rH2xkmslGE,123
|
|
24
|
+
qlsdk/interface/analyzer.py,sha256=-muX0wWUn2e-PvUJicSstCGXHJZw2yP7Er1soJsWybw,26
|
|
25
|
+
qlsdk/interface/collector.py,sha256=ye9dVjRVYfCjeJsGV8Jc4ppwp58qKW5_u5e8IIcvL4U,190
|
|
26
|
+
qlsdk/interface/device.py,sha256=09Z2KQ1dj6gP-7CdPXfMvT8YhyadgqIfo4rf6PAyXog,24
|
|
27
|
+
qlsdk/interface/parser.py,sha256=00Ds01Xp9eUPwx7okL4B1Bl0_fRbgaxfm_2GOeWoZiM,248
|
|
28
|
+
qlsdk/interface/stimulator.py,sha256=MJbgiI-4qTMjbdhcBAZe8zb10hV9x8yhFCPL3Iq_QyI,28
|
|
29
|
+
qlsdk/interface/store.py,sha256=694WQnnrtXThP44JkQlBXzghvqA0PwHKK3uA640aiUo,23
|
|
20
30
|
qlsdk/persist/__init__.py,sha256=b8qk1aOU6snEMCQNYDl1ijV3-2gwBmMt76fiAzNk1E8,107
|
|
21
31
|
qlsdk/persist/ars_edf.py,sha256=_pYtHqucB-utMw-xUXZc9IB8_8ThbLFpTl_-WBQR-Sc,10555
|
|
22
32
|
qlsdk/persist/edf.py,sha256=ETngb86CfkIUJYWmw86QR445MvTFC7Edk_CH9nyNgtY,7857
|
|
23
|
-
qlsdk/persist/rsc_edf.py,sha256
|
|
33
|
+
qlsdk/persist/rsc_edf.py,sha256=-L8Qv_d39rog6vrIEBnO5yYnxCr6yfL4qUlM72AaFJg,13392
|
|
24
34
|
qlsdk/persist/stream.py,sha256=TCVF1sqDrHiYBsJC27At66AaCs-_blXeXA_WXdJiIVA,5828
|
|
25
35
|
qlsdk/rsc/__init__.py,sha256=hOMiN0eYn4jYo7O4_0IPlQT0hD15SqqCQUihOVlTZvs,269
|
|
26
36
|
qlsdk/rsc/device_manager.py,sha256=1ucd-lzHkNeQPKPzXV6OBkAMqPp_vOcsLyS-9TJ7wRc,4448
|
|
@@ -29,29 +39,30 @@ qlsdk/rsc/eegion.py,sha256=lxrktO-3Z_MYdFIwc4NxvgLM5AL5kU3UItjH6tsKmHY,11670
|
|
|
29
39
|
qlsdk/rsc/entity.py,sha256=-fRWFkVWp9d8Y1uh6GiacXC5scdeEKNiNFf3aziGdCE,17751
|
|
30
40
|
qlsdk/rsc/paradigm.py,sha256=DGfwY36sMdPIMRjbGo661GvUTEwsRRi3jrmG405mSTk,12840
|
|
31
41
|
qlsdk/rsc/proxy.py,sha256=9CPdGNGWremwBUh4GvlXAykYB-x_BEPPLqsNvwuwIDE,2736
|
|
32
|
-
qlsdk/rsc/command/__init__.py,sha256=
|
|
42
|
+
qlsdk/rsc/command/__init__.py,sha256=DiuXvKQepVTc5hkHSB_YAAZPxobN2a7tYXpI7kZ3GQM,12296
|
|
33
43
|
qlsdk/rsc/command/message.py,sha256=nTdG-Vp4MBnltyrgedAWiKD6kzOaPrg58Z_hq6yjhys,12220
|
|
34
|
-
qlsdk/rsc/device/__init__.py,sha256=
|
|
44
|
+
qlsdk/rsc/device/__init__.py,sha256=BzY9lRfssGPUlJ1ys-v3CWNgGihg7mPa2T4X0tl0Vg4,214
|
|
35
45
|
qlsdk/rsc/device/arskindling.py,sha256=owci6MEGjyWqohEXzPdKj_ESeVIZKgO53StVj6Tmi18,15002
|
|
36
|
-
qlsdk/rsc/device/base.py,sha256=
|
|
46
|
+
qlsdk/rsc/device/base.py,sha256=oQ4Ev0LkDiJZXTqqTd6zqzzsn4ijYXkTLDUJKF0mn5U,19157
|
|
37
47
|
qlsdk/rsc/device/c16_rs.py,sha256=BHQRHOnsTMAKgqSXaAS2RjPIklZQAl2CVfe6i_iX-i4,5928
|
|
38
|
-
qlsdk/rsc/device/c256_rs.py,sha256=
|
|
48
|
+
qlsdk/rsc/device/c256_rs.py,sha256=CVnxxegyTNHQAfFVda6lQITQGGB-A958TEaqz7RjLq8,13883
|
|
39
49
|
qlsdk/rsc/device/c64_rs.py,sha256=cZIioIRGgd4Ub0ieho4_XujBNo8AQgJEjXcqgcEkyFQ,13644
|
|
40
50
|
qlsdk/rsc/device/c64s1.py,sha256=L7nKmsoMCGj6GMjHYfYkKgkBtrGfP516kQHQ5I1FAUE,13986
|
|
41
|
-
qlsdk/rsc/device/device_factory.py,sha256=
|
|
51
|
+
qlsdk/rsc/device/device_factory.py,sha256=6cPhm3pPGrVXA1s1HePFLjZqmhNI1vOAucFI0VRD_Y0,1317
|
|
42
52
|
qlsdk/rsc/interface/__init__.py,sha256=xeRzIlQSB7ZSf4r5kLfH5cDQLzCyWeJAReG8Xq5nOE0,70
|
|
43
53
|
qlsdk/rsc/interface/command.py,sha256=1s5Lxb_ejsd-JNvKMqU2aFSnOoW-_cx01VSD3czxmQI,199
|
|
44
|
-
qlsdk/rsc/interface/device.py,sha256=
|
|
54
|
+
qlsdk/rsc/interface/device.py,sha256=__ap7aJFaaktzMaZ253MMeZy9vgvJmX0Hha1dISGkOk,2064
|
|
45
55
|
qlsdk/rsc/interface/handler.py,sha256=ADDe_a2RAxGMuooLyivH0JBPTGBcFP2JaTVX41R1A4w,198
|
|
46
|
-
qlsdk/rsc/interface/parser.py,sha256=
|
|
56
|
+
qlsdk/rsc/interface/parser.py,sha256=Z4PND5LXcJ_8CQ-OIq3KlOEVOceU1hKUuZkoFSIGGLM,334
|
|
47
57
|
qlsdk/rsc/manager/__init__.py,sha256=4ljT3mR8YPBDQur46B5xPqK5tjLKlsWfgCJVuA0gs-8,40
|
|
48
|
-
qlsdk/rsc/manager/container.py,sha256=
|
|
58
|
+
qlsdk/rsc/manager/container.py,sha256=S6E0_ZXejC_YM_kzMQQHr7daPJPbVwZINBbYhreFW5w,5389
|
|
49
59
|
qlsdk/rsc/manager/search.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
60
|
qlsdk/rsc/network/__init__.py,sha256=PfYiqXS2pZV__uegQ1TjaeYhY1pefZ_shwE_X5HNVbs,23
|
|
51
|
-
qlsdk/rsc/network/discover.py,sha256=
|
|
52
|
-
qlsdk/rsc/parser/__init__.py,sha256=
|
|
61
|
+
qlsdk/rsc/network/discover.py,sha256=GRXP0WxxIorDZWXq1X5CPAV60raSRvNiVwMQE8647XA,3044
|
|
62
|
+
qlsdk/rsc/parser/__init__.py,sha256=cVKk06bRYOnwE3XMoksGlatKJSaZE1GVrYypQm-9aro,69
|
|
53
63
|
qlsdk/rsc/parser/base-new.py,sha256=cAOy1V_1fAJyGq7bm7uLxpW41DbkllWOprnfWKpjtsQ,5116
|
|
54
|
-
qlsdk/rsc/parser/base.py,sha256=
|
|
64
|
+
qlsdk/rsc/parser/base.py,sha256=VoVYoy2B583EohRRLPX3GcRiuQxT7RG7-y24WgICP2k,5702
|
|
65
|
+
qlsdk/rsc/parser/rsc.py,sha256=RuBqsg5KZNio7mTyM14svQEeU0_0CLhnRmfbP0NBM2o,4724
|
|
55
66
|
qlsdk/sdk/__init__.py,sha256=v9LKP-5qXCqnAsCkiRE9LDb5Tagvl_Qd_fqrw7y9yd4,68
|
|
56
67
|
qlsdk/sdk/ar4sdk.py,sha256=tugH3UUeNebdka78AzLyrtAXbYQQE3iFJ227zUit6tY,27261
|
|
57
68
|
qlsdk/sdk/hub.py,sha256=uEOGZBZtMDCWlV8G2TZe6FAo6eTPcwHAW8zdqr1eq_0,1571
|
|
@@ -59,7 +70,7 @@ qlsdk/sdk/libs/libAr4SDK.dll,sha256=kZp9_DRwPdAJ5OgTFQSqS8tEETxUs7YmmETuBP2g60U,
|
|
|
59
70
|
qlsdk/sdk/libs/libwinpthread-1.dll,sha256=W77ySaDQDi0yxpnQu-ifcU6-uHKzmQpcvsyx2J9j5eg,52224
|
|
60
71
|
qlsdk/x8/__init__.py,sha256=FDpDK7GAYL-g3vzfU9U_V03QzoYoxH9YLm93PjMlANg,4870
|
|
61
72
|
qlsdk/x8m/__init__.py,sha256=cLeUqEEj65qXw4Qa4REyxoLh6T24anSqPaKe9_lR340,634
|
|
62
|
-
qlsdk2-0.
|
|
63
|
-
qlsdk2-0.
|
|
64
|
-
qlsdk2-0.
|
|
65
|
-
qlsdk2-0.
|
|
73
|
+
qlsdk2-0.6.0a1.dist-info/METADATA,sha256=noX9rMQ0g9zxwyRCgDOQct_z1PBF-S5hEauk3d4x9Sk,2019
|
|
74
|
+
qlsdk2-0.6.0a1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
75
|
+
qlsdk2-0.6.0a1.dist-info/top_level.txt,sha256=2CHzn0SY-NIBVyBl07Suh-Eo8oBAQfyNPtqQ_aDatBg,6
|
|
76
|
+
qlsdk2-0.6.0a1.dist-info/RECORD,,
|
|
File without changes
|