qlsdk2 0.6.0a3__tar.gz → 0.6.0a5__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 (82) hide show
  1. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/PKG-INFO +1 -1
  2. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/setup.py +1 -1
  3. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/entity/__init__.py +57 -11
  4. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/command/__init__.py +2 -3
  5. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/base.py +8 -4
  6. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/c256_rs.py +3 -9
  7. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/c64_rs.py +1 -29
  8. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/paradigm.py +124 -4
  9. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk2.egg-info/PKG-INFO +1 -1
  10. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/README.md +0 -0
  11. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/setup.cfg +0 -0
  12. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/__init__.py +0 -0
  13. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/ar4/__init__.py +0 -0
  14. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/ar4m/__init__.py +0 -0
  15. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/__init__.py +0 -0
  16. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/crc/__init__.py +0 -0
  17. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/crc/crctools.py +0 -0
  18. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/device.py +0 -0
  19. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/exception.py +0 -0
  20. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/filter/__init__.py +0 -0
  21. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/filter/norch.py +0 -0
  22. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/local.py +0 -0
  23. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/message/__init__.py +0 -0
  24. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/message/command.py +0 -0
  25. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/message/tcp.py +0 -0
  26. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/message/udp.py +0 -0
  27. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/network/__init__.py +0 -0
  28. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/network/monitor.py +0 -0
  29. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/core/utils.py +0 -0
  30. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/entity/__init__.py +0 -0
  31. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/entity/message.py +0 -0
  32. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/entity/signal.py +0 -0
  33. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/interface/__init__.py +0 -0
  34. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/interface/analyzer.py +0 -0
  35. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/interface/collector.py +0 -0
  36. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/interface/device.py +0 -0
  37. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/interface/parser.py +0 -0
  38. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/interface/stimulator.py +0 -0
  39. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/interface/store.py +0 -0
  40. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/persist/__init__.py +0 -0
  41. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/persist/ars_edf.py +0 -0
  42. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/persist/edf.py +0 -0
  43. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/persist/rsc_edf.py +0 -0
  44. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/persist/stream.py +0 -0
  45. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/__init__.py +0 -0
  46. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/__init__.py +0 -0
  47. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/arskindling.py +0 -0
  48. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/c16_rs.py +0 -0
  49. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/c64s1.py +0 -0
  50. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/device/device_factory.py +0 -0
  51. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/eegion.py +0 -0
  52. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/entity.py +0 -0
  53. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/interface/__init__.py +0 -0
  54. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/interface/command.py +0 -0
  55. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/interface/device.py +0 -0
  56. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/interface/handler.py +0 -0
  57. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/interface/parser.py +0 -0
  58. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/manager/__init__.py +0 -0
  59. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/manager/container.py +0 -0
  60. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/manager/search.py +0 -0
  61. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/network/__init__.py +0 -0
  62. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/network/discover.py +0 -0
  63. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/parser/__init__.py +0 -0
  64. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/parser/base-new.py +0 -0
  65. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/parser/base.py +0 -0
  66. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/parser/rsc.py +0 -0
  67. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/rsc/proxy.py +0 -0
  68. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/sdk/__init__.py +0 -0
  69. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/sdk/ar4sdk.py +0 -0
  70. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/sdk/hub.py +0 -0
  71. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/sdk/libs/libAr4SDK.dll +0 -0
  72. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/sdk/libs/libwinpthread-1.dll +0 -0
  73. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/x8/__init__.py +0 -0
  74. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk/x8m/__init__.py +0 -0
  75. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk2.egg-info/SOURCES.txt +0 -0
  76. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk2.egg-info/dependency_links.txt +0 -0
  77. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk2.egg-info/requires.txt +0 -0
  78. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/src/qlsdk2.egg-info/top_level.txt +0 -0
  79. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/test/test.222.py +0 -0
  80. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/test/test.py +0 -0
  81. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/test/test_ar4m.py +0 -0
  82. {qlsdk2-0.6.0a3 → qlsdk2-0.6.0a5}/test/test_bdf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qlsdk2
3
- Version: 0.6.0a3
3
+ Version: 0.6.0a5
4
4
  Summary: SDK for quanlan device
5
5
  Home-page: https://github.com/hehuajun/qlsdk
6
6
  Author: hehuajun
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8' ) as fh:
6
6
 
7
7
  setuptools.setup(
8
8
  name="qlsdk2",
9
- version="0.6.0a3",
9
+ version="0.6.0a5",
10
10
  author="hehuajun",
11
11
  author_email="hehuajun@eegion.com",
12
12
  description="SDK for quanlan device",
@@ -72,24 +72,34 @@ class RscPacket(Packet):
72
72
  class ImpedancePacket(Packet):
73
73
  def __init__(self):
74
74
  super().__init__()
75
- self.data_len = None
76
75
  self.impedance = None
77
76
 
78
- def transfer(self, body:bytes) -> 'ImpedancePacket':
79
- self.time_stamp = int.from_bytes(body[0:8], 'little')
80
- self.result = body[8]
81
- self.pkg_id = int.from_bytes(body[9: 13], 'little')
82
- self.channels = to_channels(body[13: 45])
83
-
84
- logger.trace(f"impedance: {self}")
77
+ @staticmethod
78
+ def transfer(body:bytes) -> 'ImpedancePacket':
79
+ packet = ImpedancePacket()
80
+ packet.time_stamp = int.from_bytes(body[0:8], 'little')
81
+ # packet.result = body[8]
82
+ packet.pkg_id = int.from_bytes(body[9: 13], 'little')
83
+ packet.channels = to_channels(body[13: 45])
84
+ # packet.sample_rate = int.from_bytes(body[45: 49], 'little')
85
+ # packet.sample_len = int.from_bytes(body[49: 53], 'little')
86
+ # packet.resolution = int(int(body[53]) / 8)
87
+ # packet.filter = int(int(body[54]) / 8)
88
+ # packet.wave_type = int(int(body[55]) / 8)
89
+ # packet.wave_freq = int.from_bytes(body[56: 60], 'little')
90
+ # packet.data_len = int.from_bytes(body[60: 64], 'little')
91
+ b_impedance = body[64:]
92
+ packet.impedance = [int.from_bytes(b_impedance[j * 4 : j * 4 + 4], 'little', signed=False) for j in range(len(packet.channels))]
93
+
94
+ logger.trace(f"impedance: {packet}")
85
95
 
96
+ return packet
97
+
86
98
  def __str__(self):
87
99
  return f"""
88
100
  time_stamp: {self.time_stamp}
89
101
  pkg_id: {self.pkg_id}
90
- result: {self.result}
91
102
  channels: {self.channels}
92
- data len: {self.data_len}
93
103
  impedance: {self.impedance}
94
104
  """
95
105
 
@@ -162,4 +172,40 @@ class C256RSPacket(Packet):
162
172
  offset += 4 + channel_size * packet.resolution
163
173
 
164
174
  logger.trace(packet)
165
- return packet
175
+ return packet
176
+
177
+
178
+ class C256ImpedancePacket(Packet):
179
+ def __init__(self):
180
+ super().__init__()
181
+ self.impedance = None
182
+
183
+ @staticmethod
184
+ def transfer(body:bytes) -> 'ImpedancePacket':
185
+ packet = ImpedancePacket()
186
+ packet.time_stamp = int.from_bytes(body[0:8], 'little')
187
+ # packet.result = body[8]
188
+ packet.pkg_id = int.from_bytes(body[9: 13], 'little')
189
+ packet.channels = to_channels(body[13: 45])
190
+ # packet.sample_rate = int.from_bytes(body[45: 49], 'little')
191
+ # packet.sample_len = int.from_bytes(body[49: 53], 'little')
192
+ # packet.resolution = int(int(body[53]) / 8)
193
+ # packet.filter = int(int(body[54]) / 8)
194
+ # packet.wave_type = int(int(body[55]) / 8)
195
+ # packet.wave_freq = int.from_bytes(body[56: 60], 'little')
196
+ # packet.data_len = int.from_bytes(body[60: 64], 'little')
197
+ b_impedance = body[64:]
198
+ packet.impedance = [int.from_bytes(b_impedance[j : j + 4], 'little', signed=False) for j in range(len(packet.channels))]
199
+
200
+ logger.trace(f"impedance: {packet}")
201
+
202
+ def __str__(self):
203
+ return f"""
204
+ time_stamp: {self.time_stamp}
205
+ pkg_id: {self.pkg_id}
206
+ result: {self.result}
207
+ channels: {self.channels}
208
+ data len: {self.data_len}
209
+ impedance: {self.impedance}
210
+ """
211
+
@@ -233,7 +233,7 @@ class StartStimulationCommand(DeviceCommand):
233
233
  cmd_code = 0x48C
234
234
  cmd_desc = "启动刺激"
235
235
  def pack_body(self):
236
- return self.device.stim_paradigm.to_bytes()
236
+ return self.device.get_stim_param()
237
237
  # return bytes.fromhex('01000000000000008813000000000000010000000000000000000140420f00640064000000803f0000010000000000000000000000000000000000000000008813000000000000')
238
238
  def parse_body(self, body: bytes):
239
239
  # time - 8B
@@ -297,8 +297,7 @@ class ImpedanceDataCommand(DeviceCommand):
297
297
  cmd_desc = "阻抗数据"
298
298
 
299
299
  def parse_body(self, body: bytes):
300
- # logger.info(f"Received impedance data: {body.hex()}")
301
- packet = ImpedancePacket().transfer(body)
300
+ self.device.produce(body, type="impedance")
302
301
 
303
302
  # 信号数据
304
303
  class SignalDataCommand(DeviceCommand):
@@ -9,6 +9,7 @@ from qlsdk.core.entity import RscPacket, ImpedancePacket
9
9
  from qlsdk.core.utils import to_bytes
10
10
  from qlsdk.rsc.interface import IDevice, IParser
11
11
  from qlsdk.rsc.command import StartImpedanceCommand, StopImpedanceCommand, StartStimulationCommand, StopStimulationCommand, SetAcquisitionParamCommand, StartAcquisitionCommand, StopAcquisitionCommand
12
+ from qlsdk.rsc.paradigm import StimulationParadigm
12
13
  from qlsdk.rsc.parser.base import TcpMessageParser
13
14
 
14
15
  class QLBaseDevice(IDevice):
@@ -91,7 +92,7 @@ class QLBaseDevice(IDevice):
91
92
  ]
92
93
  }
93
94
 
94
- self.stim_paradigm = None
95
+ self.stim_paradigm: StimulationParadigm = None
95
96
 
96
97
  signal_info = {
97
98
  "param" : None,
@@ -144,7 +145,7 @@ class QLBaseDevice(IDevice):
144
145
  self._produce_impedance(body)
145
146
 
146
147
  def _produce_impedance(self, body: bytes):
147
- packet = ImpedancePacket().transfer(body)
148
+ packet = ImpedancePacket.transfer(body)
148
149
  # 分发阻抗数据包给订阅者
149
150
  if len(self._impedance_consumer) > 0:
150
151
  for topic, q in self._impedance_consumer.items():
@@ -354,7 +355,7 @@ class QLBaseDevice(IDevice):
354
355
  self.stim_paradigm = param
355
356
 
356
357
  # 设置采集参数
357
- def set_acq_param(self, channels, sample_rate = 500, sample_range = 188):
358
+ def set_acq_param(self, channels, sample_rate:Literal[188, 375, 563, 750, 1125, 2250, 4500] = 500, sample_range:Literal[250, 500, 1000, 2000, 4000, 8000, 16000, 32000] = 188):
358
359
  self._acq_param["channels"] = channels
359
360
  self._acq_param["sample_rate"] = sample_rate
360
361
  self._acq_param["sample_range"] = sample_range
@@ -389,6 +390,9 @@ class QLBaseDevice(IDevice):
389
390
  t = Thread(target=self._stop_stimulation_trigger, args=(self.stim_paradigm.duration,), daemon=True)
390
391
  t.start()
391
392
 
393
+ def get_stim_param(self) -> bytes:
394
+ return self.stim_paradigm.to_bytes()
395
+
392
396
  def _stop_stimulation_trigger(self, duration):
393
397
  delay = duration
394
398
  while delay > 0:
@@ -446,7 +450,7 @@ class QLBaseDevice(IDevice):
446
450
 
447
451
  # 数据队列
448
452
  if q is None:
449
- q = Queue(maxsize=1000)
453
+ q = Queue(maxsize=1024 * 1024)
450
454
 
451
455
  # 订阅生理电信号数据
452
456
  if type == "signal":
@@ -199,15 +199,6 @@ class C256RS(QLBaseDevice):
199
199
  def set_stim_param(self, param):
200
200
  self.stim_paradigm = param
201
201
 
202
- # 设置采集参数
203
- def set_acq_param(self, channels, sample_rate = 500, sample_range = 188):
204
- self._acq_param["channels"] = channels
205
- self._acq_param["sample_rate"] = sample_rate
206
- self._acq_param["sample_range"] = sample_range
207
- self._acq_channels = channels
208
- self._sample_rate = sample_rate
209
- self._sample_range = sample_range
210
-
211
202
  def _signal_wrapper(self, body: bytes):
212
203
  return C256RSPacket().transfer(body)
213
204
 
@@ -234,6 +225,9 @@ class C256RS(QLBaseDevice):
234
225
  t = Thread(target=self._stop_stimulation_trigger, args=(self.stim_paradigm.duration,))
235
226
  t.start()
236
227
 
228
+ def get_stim_param(self) -> bytes:
229
+ return self.stim_paradigm.to_bytes_c256()
230
+
237
231
  def _stop_stimulation_trigger(self, duration):
238
232
  delay = duration
239
233
  while delay > 0:
@@ -285,35 +285,7 @@ class C64RS(QLBaseDevice):
285
285
  if self._edf_handler:
286
286
  # 发送结束标识
287
287
  self.edf_handler.write(None)
288
-
289
- # 订阅实时数据
290
- def subscribe(self, topic:str=None, q : Queue=None, type : Literal["signal","impedance"]="signal"):
291
-
292
- # 数据队列
293
- if q is None:
294
- q = Queue(maxsize=1000)
295
-
296
- # 队列名称
297
- if topic is None:
298
- topic = f"{type}_{time_ns()}"
299
-
300
- # 订阅生理电信号数据
301
- if type == "signal":
302
- # topic唯一,用来区分不同的订阅队列(下同)
303
- if topic in list(self.__signal_consumer.keys()):
304
- logger.warning(f"exists {type} subscribe of {topic}")
305
- else:
306
- self.__signal_consumer[topic] = q
307
-
308
- # 订阅阻抗数据
309
- if type == "impedance":
310
- if topic in list(self.__signal_consumer.keys()):
311
- logger.warning(f"exists {type} subscribe of {topic}")
312
- else:
313
- self.__impedance_consumer[topic] = q
314
-
315
- return topic, q
316
-
288
+
317
289
  def trigger(self, desc):
318
290
  if self._edf_handler:
319
291
  self.edf_handler.trigger(desc)
@@ -61,6 +61,22 @@ class StimulationChannel(ABC):
61
61
 
62
62
  return result
63
63
 
64
+ def to_bytes_c256(self):
65
+ result = self.channel_id.to_bytes(1, 'little')
66
+ result += self.wave_form.to_bytes(1, 'little')
67
+
68
+ result += self._to_bytes_c256()
69
+
70
+ result += int(self.delay_time).to_bytes(4, 'little')
71
+ result += int(self.ramp_up * 1000).to_bytes(4, 'little')
72
+ result += int((self.duration + self.ramp_up) * 1000).to_bytes(4, 'little')
73
+ result += int(self.ramp_down * 1000).to_bytes(4, 'little')
74
+
75
+ return result
76
+
77
+ def _to_bytes_c256(self):
78
+ return bytes.fromhex("00000000000000000000000000000000000000000000000000000000")
79
+
64
80
  def _ext_bytes(self):
65
81
  return bytes.fromhex("00000000000000000000000000000000")
66
82
 
@@ -99,6 +115,9 @@ class DCStimulation(StimulationChannel):
99
115
  "delay_time": self.delay_time
100
116
  }
101
117
 
118
+ def _to_bytes_c256(self):
119
+ return int(self.current_max * 1000 ).to_bytes(2, 'little') + bytes.fromhex("0000000000000000000000000000000000000000000000000000")
120
+
102
121
  def from_json(self, param):
103
122
  pass
104
123
  def __str__(self):
@@ -140,9 +159,19 @@ class SquareWaveStimulation(StimulationChannel):
140
159
  result += int((self.duration + self.ramp_up) * 1000).to_bytes(4, 'little')
141
160
  result += int(self.ramp_down * 1000).to_bytes(4, 'little')
142
161
 
143
- return result
144
-
145
- # 刺激模式-交流
162
+ return result
163
+
164
+ def _to_bytes_c256(self):
165
+ result = int(self.current_max * 1000000 ).to_bytes(4, 'little')
166
+ result += int(self.frequency).to_bytes(2, 'little')
167
+ result += bytes.fromhex("0000")
168
+ result += struct.pack('<f', self.duty_cycle)
169
+ result = int(self.current_min * 1000000 ).to_bytes(4, 'little')
170
+ result += self._ext_bytes()
171
+ return result
172
+
173
+
174
+ # 刺激模式-正弦
146
175
  class ACStimulation(StimulationChannel):
147
176
  '''
148
177
  channel_id: int, 通道编号,从0开始
@@ -177,6 +206,15 @@ class ACStimulation(StimulationChannel):
177
206
 
178
207
  def from_json(self, param):
179
208
  pass
209
+
210
+ def _to_bytes_c256(self):
211
+ result = int(self.current_max * 1000 ).to_bytes(2, 'little')
212
+ result += bytes.fromhex("0000")
213
+ result += struct.pack('<f', self.frequency)
214
+ result += struct.pack('<f', self.phase_position)
215
+ result += self._ext_bytes()
216
+ return result
217
+
180
218
  def __str__(self):
181
219
  return f"ACStimulation(channel_id={self.channel_id}, waveform={self.waveform}, current={self.current_max}, duration={self.duration}, ramp_up={self.ramp_up}, ramp_down={self.ramp_down}, frequency={self.frequency}, phase_position={self.phase_position}, duration_delay={self.duration_delay})"
182
220
 
@@ -230,6 +268,15 @@ class PulseStimulation(StimulationChannel):
230
268
 
231
269
  return result
232
270
 
271
+ def _to_bytes_c256(self):
272
+ result = int(self.current_max * 1000000 ).to_bytes(4, 'little')
273
+ result += int(self.frequency).to_bytes(2, 'little')
274
+ result += bytes.fromhex("0000")
275
+ result += struct.pack('<f', self.duty_cycle)
276
+ result = int(self.current_min * 1000000 ).to_bytes(4, 'little')
277
+ result += self._ext_bytes()
278
+ return result
279
+
233
280
  def to_json(self):
234
281
  return {
235
282
  "channel_id": self.channel_id,
@@ -287,6 +334,17 @@ class StimulationParadigm(object):
287
334
  result += channel.to_bytes()
288
335
  return result
289
336
 
337
+ def to_bytes_c256(self):
338
+ result = to_bytes(list(self.channels.keys()), 256)
339
+ result += int(self.duration * 1000).to_bytes(4, 'little')
340
+ result += int(self.interval_time).to_bytes(4, 'little')
341
+ result += int(self.characteristic).to_bytes(4, 'little')
342
+ result += int(self.mode).to_bytes(1, 'little')
343
+ result += int(self.repeats).to_bytes(4, 'little')
344
+ for channel in self.channels.values():
345
+ result += channel.to_bytes()
346
+ return result
347
+
290
348
  def to_json(self):
291
349
  # Convert the object to JSON for transmission
292
350
  return {
@@ -306,8 +364,70 @@ class StimulationParadigm(object):
306
364
  def clear(self):
307
365
  self.channels = None
308
366
  self.duration = None
309
- self.interval_time = 0
367
+ self.interval_time = 25000
310
368
  self.characteristic = 1
311
369
  self.mode = 0
312
370
  self.repeats = 0
313
371
 
372
+
373
+ # 刺激范式
374
+ class C256StimulationParadigm(object):
375
+ def __init__(self):
376
+ self.channels = None
377
+ self.duration = None
378
+ self.interval_time = 0
379
+ self.characteristic = 1
380
+ self.mode = 0
381
+ self.repeats = 0
382
+
383
+ def add_channel(self, channel: StimulationChannel, update=False):
384
+ if self.channels is None:
385
+ self.channels = {}
386
+ channel_id = channel.channel_id + 1
387
+ if channel_id in self.channels.keys():
388
+ logger.warning(f"Channel {channel_id} already exists")
389
+ if update:
390
+ self.channels[channel_id] = channel
391
+ else:
392
+ self.channels[channel_id] = channel
393
+
394
+ # 计算刺激时间
395
+ duration = channel.duration + channel.ramp_up + channel.ramp_down
396
+ if self.duration is None or duration > self.duration:
397
+ self.duration = duration
398
+
399
+
400
+ def to_bytes(self):
401
+ result = to_bytes(list(self.channels.keys()), 64)
402
+ result += int(self.duration * 1000).to_bytes(4, 'little')
403
+ result += int(self.interval_time).to_bytes(4, 'little')
404
+ result += int(self.characteristic).to_bytes(4, 'little')
405
+ result += int(self.mode).to_bytes(1, 'little')
406
+ result += int(self.repeats).to_bytes(4, 'little')
407
+ for channel in self.channels.values():
408
+ result += channel.to_bytes()
409
+ return result
410
+
411
+ def to_json(self):
412
+ # Convert the object to JSON for transmission
413
+ return {
414
+ "channels": list(self.channels.keys()),
415
+ "duration": self.duration,
416
+ "interval_time": self.interval_time,
417
+ "characteristic": self.characteristic,
418
+ "mode": self.mode,
419
+ "repeats": self.repeats,
420
+ "stim": [channel.to_json() for channel in self.channels.values()]
421
+ }
422
+
423
+ # @staticmethod
424
+ # def from_json(param: Dict[str, Any]):
425
+ # pass
426
+
427
+ def clear(self):
428
+ self.channels = None
429
+ self.duration = None
430
+ self.interval_time = 0
431
+ self.characteristic = 1
432
+ self.mode = 0
433
+ self.repeats = 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qlsdk2
3
- Version: 0.6.0a3
3
+ Version: 0.6.0a5
4
4
  Summary: SDK for quanlan device
5
5
  Home-page: https://github.com/hehuajun/qlsdk
6
6
  Author: hehuajun
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes