qlsdk2 0.4.2__tar.gz → 0.5.1__tar.gz

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.
Files changed (75) hide show
  1. qlsdk2-0.5.1/PKG-INFO +57 -0
  2. qlsdk2-0.5.1/README.md +38 -0
  3. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/setup.py +3 -4
  4. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/entity/__init__.py +8 -12
  5. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/persist/rsc_edf.py +42 -13
  6. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/command/__init__.py +32 -24
  7. qlsdk2-0.5.1/src/qlsdk/rsc/device/__init__.py +7 -0
  8. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/device/arskindling.py +4 -2
  9. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/device/base.py +92 -39
  10. qlsdk2-0.5.1/src/qlsdk/rsc/device/c16_rs.py +185 -0
  11. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/device/c256_rs.py +1 -0
  12. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/device/c64_rs.py +3 -2
  13. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/device/c64s1.py +3 -2
  14. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/device/device_factory.py +2 -1
  15. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/interface/device.py +13 -0
  16. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/manager/container.py +27 -23
  17. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/network/discover.py +25 -36
  18. qlsdk2-0.5.1/src/qlsdk/rsc/parser/base-new.py +135 -0
  19. qlsdk2-0.5.1/src/qlsdk/rsc/parser/base.py +157 -0
  20. qlsdk2-0.5.1/src/qlsdk2.egg-info/PKG-INFO +57 -0
  21. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk2.egg-info/SOURCES.txt +2 -0
  22. qlsdk2-0.4.2/PKG-INFO +0 -121
  23. qlsdk2-0.4.2/README.md +0 -93
  24. qlsdk2-0.4.2/src/qlsdk/rsc/device/__init__.py +0 -2
  25. qlsdk2-0.4.2/src/qlsdk/rsc/parser/base.py +0 -69
  26. qlsdk2-0.4.2/src/qlsdk2.egg-info/PKG-INFO +0 -121
  27. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/setup.cfg +0 -0
  28. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/__init__.py +0 -0
  29. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/ar4/__init__.py +0 -0
  30. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/ar4m/__init__.py +0 -0
  31. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/__init__.py +0 -0
  32. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/crc/__init__.py +0 -0
  33. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/crc/crctools.py +0 -0
  34. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/device.py +0 -0
  35. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/exception.py +0 -0
  36. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/filter/__init__.py +0 -0
  37. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/filter/norch.py +0 -0
  38. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/local.py +0 -0
  39. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/message/__init__.py +0 -0
  40. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/message/command.py +0 -0
  41. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/message/tcp.py +0 -0
  42. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/message/udp.py +0 -0
  43. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/network/__init__.py +0 -0
  44. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/network/monitor.py +0 -0
  45. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/core/utils.py +0 -0
  46. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/persist/__init__.py +0 -0
  47. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/persist/ars_edf.py +0 -0
  48. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/persist/edf.py +0 -0
  49. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/persist/stream.py +0 -0
  50. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/__init__.py +0 -0
  51. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/eegion.py +0 -0
  52. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/entity.py +0 -0
  53. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/interface/__init__.py +0 -0
  54. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/interface/command.py +0 -0
  55. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/interface/handler.py +0 -0
  56. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/interface/parser.py +0 -0
  57. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/manager/__init__.py +0 -0
  58. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/manager/search.py +0 -0
  59. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/network/__init__.py +0 -0
  60. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/paradigm.py +0 -0
  61. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/parser/__init__.py +0 -0
  62. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/rsc/proxy.py +0 -0
  63. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/sdk/__init__.py +0 -0
  64. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/sdk/ar4sdk.py +0 -0
  65. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/sdk/hub.py +0 -0
  66. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/sdk/libs/libAr4SDK.dll +0 -0
  67. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/sdk/libs/libwinpthread-1.dll +0 -0
  68. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/x8/__init__.py +0 -0
  69. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk/x8m/__init__.py +0 -0
  70. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk2.egg-info/dependency_links.txt +0 -0
  71. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk2.egg-info/requires.txt +0 -0
  72. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/src/qlsdk2.egg-info/top_level.txt +0 -0
  73. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/test/test.222.py +0 -0
  74. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/test/test.py +0 -0
  75. {qlsdk2-0.4.2 → qlsdk2-0.5.1}/test/test_ar4m.py +0 -0
qlsdk2-0.5.1/PKG-INFO ADDED
@@ -0,0 +1,57 @@
1
+ Metadata-Version: 2.1
2
+ Name: qlsdk2
3
+ Version: 0.5.1
4
+ Summary: SDK for quanlan device
5
+ Home-page: https://github.com/hehuajun/qlsdk
6
+ Author: hehuajun
7
+ Author-email: hehuajun@eegion.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 10
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: loguru>=0.6.0
14
+ Requires-Dist: numpy>=1.23.5
15
+ Requires-Dist: bitarray>=1.5.3
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=6.0; extra == "dev"
18
+ Requires-Dist: twine>=3.0; extra == "dev"
19
+
20
+ # 版本 v0.5.1 (2025-08-04)
21
+
22
+ ## ⚙️ 优化
23
+ #### 修复C16R通道映射的问题
24
+
25
+ #### 支持设置记录参数,在需要保存大量事件时使用
26
+
27
+ #### 订阅队列满的时候,丢弃最早的数据
28
+
29
+
30
+ # 版本 v0.5.0 (2025-07-29)
31
+
32
+ ## 🚀 新特性
33
+
34
+ 1. **C16R设备连接**
35
+ 支持C16R类型设备的搜索与连接
36
+
37
+ 2. **C16R信号采集/停止控制**
38
+ 支持信号采集的参数配置
39
+ 支持信号采集的启动与停止控制
40
+
41
+ 3. **C16R数据自动记录**
42
+ 采集到的信号数据自动保存为bdf文件
43
+
44
+ 4. **C16R采集通道设置**
45
+ - 支持数字模式通道配置
46
+ - 支持名称模式通道配置
47
+ - 支持两种模式混合使用
48
+
49
+ ## ⚙️ 优化
50
+
51
+ 1. **性能提升**
52
+ - 信号接收效率优化
53
+ - 指令拆包方式优化
54
+
55
+ 2. **日志系统改进**
56
+ - 日志级别精细化调整,减少不必要的日志信息
57
+ - 日志文案清晰化
qlsdk2-0.5.1/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # 版本 v0.5.1 (2025-08-04)
2
+
3
+ ## ⚙️ 优化
4
+ #### 修复C16R通道映射的问题
5
+
6
+ #### 支持设置记录参数,在需要保存大量事件时使用
7
+
8
+ #### 订阅队列满的时候,丢弃最早的数据
9
+
10
+
11
+ # 版本 v0.5.0 (2025-07-29)
12
+
13
+ ## 🚀 新特性
14
+
15
+ 1. **C16R设备连接**
16
+ 支持C16R类型设备的搜索与连接
17
+
18
+ 2. **C16R信号采集/停止控制**
19
+ 支持信号采集的参数配置
20
+ 支持信号采集的启动与停止控制
21
+
22
+ 3. **C16R数据自动记录**
23
+ 采集到的信号数据自动保存为bdf文件
24
+
25
+ 4. **C16R采集通道设置**
26
+ - 支持数字模式通道配置
27
+ - 支持名称模式通道配置
28
+ - 支持两种模式混合使用
29
+
30
+ ## ⚙️ 优化
31
+
32
+ 1. **性能提升**
33
+ - 信号接收效率优化
34
+ - 指令拆包方式优化
35
+
36
+ 2. **日志系统改进**
37
+ - 日志级别精细化调整,减少不必要的日志信息
38
+ - 日志文案清晰化
@@ -1,12 +1,12 @@
1
1
  # setup.py
2
2
  import setuptools
3
3
 
4
- with open("README.md", "r") as fh:
4
+ with open("README.md", "r", encoding='utf-8' ) as fh:
5
5
  long_description = fh.read()
6
6
 
7
7
  setuptools.setup(
8
8
  name="qlsdk2",
9
- version="0.4.2",
9
+ version="0.5.1",
10
10
  author="hehuajun",
11
11
  author_email="hehuajun@eegion.com",
12
12
  description="SDK for quanlan device",
@@ -18,13 +18,12 @@ setuptools.setup(
18
18
  classifiers=[
19
19
  "Programming Language :: Python :: 3",
20
20
  "License :: OSI Approved :: MIT License",
21
- "Operating System :: OS Independent",
21
+ "Operating System :: Microsoft :: Windows :: Windows 10",
22
22
  ],
23
23
  python_requires='>=3.9',
24
24
  install_requires=open("requirements.txt").read().splitlines(),
25
25
  include_package_data=True,
26
26
  package_data={
27
- # "qlsdk2": ["/**/*.dll"],
28
27
  "qlsdk": ["./**/*.dll"]
29
28
  }
30
29
  )
@@ -1,18 +1,17 @@
1
1
  from qlsdk.core.utils import to_channels
2
2
  from loguru import logger
3
3
 
4
- class DataPacket(object):
5
- def __init__(self, device_type, device_id, channels, data):
6
- self.data = data
7
- self.channels = None
8
-
9
-
10
- class RscPacket(object):
4
+ class Packet(object):
11
5
  def __init__(self):
12
6
  self.time_stamp = None
13
7
  self.pkg_id = None
14
8
  self.result = None
15
9
  self.channels = None
10
+
11
+
12
+ class RscPacket(Packet):
13
+ def __init__(self):
14
+ super().__init__()
16
15
  self.origin_sample_rate = None
17
16
  self.sample_rate = None
18
17
  self.sample_num = None
@@ -65,12 +64,9 @@ class RscPacket(object):
65
64
  eeg: {self.eeg}
66
65
  """
67
66
 
68
- class ImpedancePacket(object):
67
+ class ImpedancePacket(Packet):
69
68
  def __init__(self):
70
- self.time_stamp = None
71
- self.pkg_id = None
72
- self.result = None
73
- self.channels = None
69
+ super().__init__()
74
70
  self.data_len = None
75
71
  self.impedance = None
76
72
 
@@ -1,4 +1,5 @@
1
1
  from datetime import datetime
2
+ import time
2
3
  from multiprocessing import Lock, Queue
3
4
  from time import time_ns
4
5
  from pyedflib import FILETYPE_BDFPLUS, FILETYPE_EDFPLUS, EdfWriter
@@ -14,7 +15,8 @@ EDF_FILE_TYPE = {
14
15
  }
15
16
 
16
17
  class EDFStreamWriter(Thread):
17
- def __init__(self, channels, sample_frequency, physical_max, digital_min, file_type, file_path):
18
+ def __init__(self, channels, sample_frequency, physical_max, digital_min, file_type, file_path, record_duration=None):
19
+
18
20
  super().__init__()
19
21
  self._writer : EdfWriter = None
20
22
  self.data_queue : Queue = Queue()
@@ -22,6 +24,8 @@ class EDFStreamWriter(Thread):
22
24
  self._points = 0
23
25
  self._duration = 0
24
26
  self._buffer = None
27
+ # 设置edf/bdf文件参数,设置[0.001, 1)可以在1秒内记录多个事件(不建议开启)
28
+ self.record_duration = record_duration
25
29
 
26
30
  # signal info
27
31
  self._channels = channels
@@ -61,9 +65,10 @@ class EDFStreamWriter(Thread):
61
65
  # 数据
62
66
  self.data_queue.put(data)
63
67
 
64
- def trigger(self, onset, desc):
68
+ def trigger(self, onset, desc: str):
65
69
  if self._writer:
66
- self._writer.writeAnnotation(onset, 1, desc)
70
+ logger.trace(f"[{onset} : {desc}]")
71
+ self._writer.writeAnnotation(onset, -1, desc)
67
72
  else:
68
73
  logger.warning("未创建文件,无法写入Trigger标记")
69
74
 
@@ -77,8 +82,9 @@ class EDFStreamWriter(Thread):
77
82
  if self._writer is None:
78
83
  self._init_writer()
79
84
 
80
- while True:
81
- if self._recording or (not self.data_queue.empty()):
85
+ waits = 300
86
+ while waits > 0:
87
+ if not self.data_queue.empty():
82
88
  try:
83
89
  data = self.data_queue.get(timeout=30)
84
90
  if data is None:
@@ -88,13 +94,20 @@ class EDFStreamWriter(Thread):
88
94
  self._points += len(data[1])
89
95
  logger.trace(f"已处理数据点数:{self._points}")
90
96
  self._write_file(data)
97
+ # 有数据重置计数器
98
+ waits = 100 # 重置等待计数器
91
99
  except Exception as e:
92
100
  logger.error(f"异常或超时(30s)结束: {str(e)}")
93
101
  break
94
102
  else:
95
- logger.debug("数据记录完成")
96
- break
103
+ time.sleep(0.1)
104
+ # 记录状态等待30s、非记录状态等待3s
105
+ if self._recording:
106
+ waits -= 1
107
+ else:
108
+ waits -= 10
97
109
 
110
+ logger.info(f"数据记录完成:{self.file_path}")
98
111
  self.close()
99
112
 
100
113
  def _init_writer(self):
@@ -126,6 +139,8 @@ class EDFStreamWriter(Thread):
126
139
  })
127
140
 
128
141
  self._writer.setSignalHeaders(signal_headers)
142
+ if self.record_duration:
143
+ self._writer.setDatarecordDuration(self.record_duration) # 每个数据块1秒
129
144
 
130
145
  def _write_file(self, eeg_data):
131
146
  try:
@@ -159,6 +174,9 @@ class EDFStreamWriter(Thread):
159
174
  # 写入时转置为(样本数, 通道数)格式
160
175
  self._writer.writeSamples(data_float64)
161
176
  self._duration += 1
177
+
178
+ if self._duration % 10 == 0: # 每10秒打印一次进度
179
+ logger.info(f"数据记录中... 文件名:{self.file_path}, 已记录时长: {self._duration}秒")
162
180
 
163
181
  # 用作数据结构一致化处理,通过调用公共类写入edf文件
164
182
  # 入参包含写入edf的全部前置参数
@@ -177,7 +195,7 @@ class RscEDFHandler(object):
177
195
  @author: qlsdk
178
196
  @since: 0.4.0
179
197
  '''
180
- def __init__(self, eeg_sample_rate, physical_max, physical_min, resolution=24, storage_path = None):
198
+ def __init__(self, eeg_sample_rate, physical_max, physical_min, resolution=24, storage_path = None, record_duration=None):
181
199
  # edf文件参数
182
200
  self.physical_max = physical_max
183
201
  self.physical_min = physical_min
@@ -213,6 +231,7 @@ class RscEDFHandler(object):
213
231
  self._total_packets = 0
214
232
  self._lost_packets = 0
215
233
  self._storage_path = storage_path
234
+ self._record_duration = record_duration
216
235
  self._edf_writer_thread = None
217
236
  self._file_prefix = None
218
237
 
@@ -243,6 +262,8 @@ class RscEDFHandler(object):
243
262
  self._device_type = "LJ64S1"
244
263
  elif device_type == 0x60:
245
264
  self._device_type = "ARSKindling"
265
+ elif device_type == 0x339:
266
+ self._device_type = "C16R"
246
267
  else:
247
268
  self._device_type = device_type
248
269
 
@@ -264,17 +285,18 @@ class RscEDFHandler(object):
264
285
  def write(self, packet: RscPacket):
265
286
  # logger.trace(f"packet: {packet}")
266
287
  if packet is None:
288
+ logger.info(f"收到结束信号,即将停止写入数据:{self.file_name}")
267
289
  self._edf_writer_thread.stop_recording()
268
290
  return
269
291
 
270
292
  with self._lock:
271
293
  if self.channels is None:
272
- logger.info(f"开始记录数据到文件...")
294
+ logger.debug(f"开始记录数据到文件...")
273
295
  self.channels = packet.channels
274
296
  self._first_pkg_id = packet.pkg_id if self._first_pkg_id is None else self._first_pkg_id
275
297
  self._first_timestamp = packet.time_stamp if self._first_timestamp is None else self._first_timestamp
276
298
  self._start_time = datetime.now()
277
- logger.info(f"第一个包id: {self._first_pkg_id }, 时间戳:{self._first_timestamp}, 当前时间:{datetime.now().timestamp()} offset: {datetime.now().timestamp() - self._first_timestamp}")
299
+ logger.debug(f"第一个包id: {self._first_pkg_id }, 时间戳:{self._first_timestamp}, 当前时间:{datetime.now().timestamp()} offset: {datetime.now().timestamp() - self._first_timestamp}")
278
300
 
279
301
  if self._last_pkg_id and self._last_pkg_id != packet.pkg_id - 1:
280
302
  self._lost_packets += packet.pkg_id - self._last_pkg_id - 1
@@ -284,7 +306,7 @@ class RscEDFHandler(object):
284
306
  self._total_packets += 1
285
307
 
286
308
  if self._edf_writer_thread is None:
287
- self._edf_writer_thread = EDFStreamWriter(self.channels, self.sample_rate, self.physical_max, self.physical_min, self.file_type, self.file_name)
309
+ self._edf_writer_thread = EDFStreamWriter(self.channels, self.sample_rate, self.physical_max, self.physical_min, self.file_type, self.file_name, self._record_duration)
288
310
  self._edf_writer_thread.set_start_time(self._start_time)
289
311
  self._edf_writer_thread.start()
290
312
  logger.info(f"开始写入数据: {self.file_name}")
@@ -295,9 +317,16 @@ class RscEDFHandler(object):
295
317
  # trigger标记
296
318
  # desc: 标记内容
297
319
  # cur_time: 设备时间时间戳,非设备发出的trigger不要设置
298
- def trigger(self, desc, cur_time=None):
320
+ def trigger(self, desc: str, cur_time=None):
321
+ if self._edf_writer_thread is None:
322
+ logger.warning(f"File writing has not started, discarding trigger {desc}")
323
+ return
324
+
299
325
  if cur_time is None:
300
- onset = datetime.now().timestamp() - self._start_time.timestamp()
326
+ # 计算trigger位置
327
+ if self._start_time:
328
+ onset = datetime.now().timestamp() - self._start_time.timestamp()
329
+ else: onset = 0
301
330
  else:
302
331
  onset = cur_time - self._first_timestamp
303
332
  self._edf_writer_thread.trigger(onset, desc)
@@ -51,15 +51,29 @@ class DeviceCommand(abc.ABC):
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
53
 
54
- """构建消息头"""
55
- return (
56
- DeviceCommand.HEADER_PREFIX
57
- + int(2).to_bytes(1, 'little') # pkgType
58
- + device_type.to_bytes(1, 'little')
59
- + device_id.to_bytes(4, 'little')
60
- + (DeviceCommand.HEADER_LEN + body_len + 2).to_bytes(4, 'little') # +1 for checksum
61
- + self.cmd_code.to_bytes(2, 'little')
62
- )
54
+ #兼容设计
55
+ b_device_type = None
56
+ if device_type > 0xFF:
57
+ b_device_type = int.to_bytes(device_type, 2, 'little')
58
+
59
+ if b_device_type is None:
60
+ return (
61
+ DeviceCommand.HEADER_PREFIX
62
+ + int(2).to_bytes(1, 'little') # pkgType
63
+ + device_type.to_bytes(1, 'little')
64
+ + device_id.to_bytes(4, 'little')
65
+ + (DeviceCommand.HEADER_LEN + body_len + 2).to_bytes(4, 'little') # +1 for checksum
66
+ + self.cmd_code.to_bytes(2, 'little')
67
+ )
68
+ else:
69
+ return (
70
+ DeviceCommand.HEADER_PREFIX
71
+ + b_device_type[0].to_bytes(1, 'little') # pkgType
72
+ + b_device_type[1].to_bytes(1, 'little')
73
+ + device_id.to_bytes(4, 'little')
74
+ + (DeviceCommand.HEADER_LEN + body_len + 2).to_bytes(4, 'little') # +1 for checksum
75
+ + self.cmd_code.to_bytes(2, 'little')
76
+ )
63
77
 
64
78
  def unpack(self, payload: bytes) -> bytes:
65
79
  """解析消息体"""
@@ -70,7 +84,7 @@ class DeviceCommand(abc.ABC):
70
84
  time = int.from_bytes(body[0:8], 'little')
71
85
  # result - 1B
72
86
  result = body[8]
73
- logger.info(f"[{time}]{self.cmd_desc}{'成功' if result == 0 else '失败'}")
87
+ logger.debug(f"[{time}]{self.cmd_desc}{'成功' if result == 0 else '失败'}")
74
88
 
75
89
 
76
90
 
@@ -156,7 +170,7 @@ class QueryBatteryCommand(DeviceCommand):
156
170
  self.device.battery_total = body[12]
157
171
  # state - 1b
158
172
  # state = body[13]
159
- logger.debug(f"电量更新: {self.device}")
173
+ logger.trace(f"电量更新: {self.device}")
160
174
  else:
161
175
  logger.warning(f"QueryBatteryCommand message received but result is failed.")
162
176
 
@@ -200,6 +214,10 @@ class StartImpedanceCommand(DeviceCommand):
200
214
  body += to_bytes(self.device.acq_channels)
201
215
  body += bytes.fromhex('0000000000000000') # 8字节占位符
202
216
  return body
217
+
218
+ def parse_body(self, body):
219
+ logger.info(f"Received StartImpedance response: {body.hex()}")
220
+ return super().parse_body(body)
203
221
 
204
222
 
205
223
  # 停止阻抗测量
@@ -279,7 +297,7 @@ class ImpedanceDataCommand(DeviceCommand):
279
297
  cmd_desc = "阻抗数据"
280
298
 
281
299
  def parse_body(self, body: bytes):
282
- logger.info(f"Received impedance data: {body.hex()}")
300
+ # logger.info(f"Received impedance data: {body.hex()}")
283
301
  packet = ImpedancePacket().transfer(body)
284
302
 
285
303
  # 信号数据
@@ -294,18 +312,8 @@ class SignalDataCommand(DeviceCommand):
294
312
  # 解析数据包
295
313
  packet = RscPacket()
296
314
  packet.transfer(body)
297
-
298
- # 文件写入到edf
299
- if self.device.edf_handler:
300
- self.device.edf_handler.write(packet)
301
-
302
- if len(self.device.signal_consumers) > 0 :
303
- # 信号数字值转物理值
304
- packet.eeg = self.device.eeg2phy(np.array(packet.eeg))
305
-
306
- # 发送数据包到订阅者
307
- for q in list(self.device.signal_consumers.values()):
308
- q.put(packet)
315
+ # 将数据包传递给设备
316
+ self.device.produce(packet)
309
317
 
310
318
 
311
319
 
@@ -0,0 +1,7 @@
1
+ from .base import QLBaseDevice
2
+ from .device_factory import DeviceFactory
3
+
4
+ # import devices
5
+ from .c64_rs import C64RS
6
+ from .c16_rs import C16RS
7
+ from .arskindling import ARSKindling
@@ -167,7 +167,7 @@ class ARSKindling(QLBaseDevice):
167
167
  self._edf_handler.set_device_type(self.device_type)
168
168
  self._edf_handler.set_device_no(self.device_no)
169
169
  self._edf_handler.set_storage_path(self._storage_path)
170
- self._edf_handler.set_file_prefix(self._file_prefix)
170
+ self._edf_handler.set_file_prefix(self._file_prefix if self._file_prefix else 'ARS')
171
171
 
172
172
  @property
173
173
  def edf_handler(self):
@@ -233,6 +233,8 @@ class ARSKindling(QLBaseDevice):
233
233
  # 设置采集参数
234
234
  def set_acq_param(self, channels, sample_rate = 500, sample_range = 188):
235
235
  self._acq_param["original_channels"] = channels
236
+
237
+ # 根据映射关系做通道转换
236
238
  for k in channels.keys():
237
239
  if isinstance(channels[k], list):
238
240
  temp = [k + str(i) for i in channels[k]]
@@ -241,7 +243,7 @@ class ARSKindling(QLBaseDevice):
241
243
  channels[k] = [k + str(channels[k])]
242
244
 
243
245
 
244
-
246
+ # 更新采集参数
245
247
  self._acq_param["channels"] = channels
246
248
  self._acq_param["sample_rate"] = sample_rate
247
249
  self._acq_param["sample_range"] = sample_range