nsqdriver 0.3.1__cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.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.

Potentially problematic release.


This version of nsqdriver might be problematic. Click here for more details.

nsqdriver/NS_QSYNC.py ADDED
@@ -0,0 +1,669 @@
1
+ import atexit
2
+ import socket
3
+ import struct
4
+ import threading
5
+ import time
6
+ import enum
7
+ import pickle
8
+ from concurrent.futures import ThreadPoolExecutor
9
+ from concurrent.futures import wait as wait_futures
10
+ from multiprocessing import shared_memory
11
+ from functools import lru_cache, wraps
12
+ from typing import Union, TYPE_CHECKING, Tuple, Iterable
13
+
14
+ try:
15
+ from .common import BaseDriver, Quantity, QInteger
16
+ except ImportError as e:
17
+ class BaseDriver:
18
+ def __init__(self, addr, timeout, **kw):
19
+ self.addr = addr
20
+ self.timeout = timeout
21
+
22
+
23
+ class Quantity(object):
24
+ def __init__(self, name: str, value=None, ch: int = 1, unit: str = ''):
25
+ self.name = name
26
+ self.default = dict(value=value, ch=ch, unit=unit)
27
+
28
+
29
+ class QInteger:
30
+ def __init__(self, name, value=None, unit='', ch=None,
31
+ get_cmd='', set_cmd='', ):
32
+ self.name = name
33
+
34
+
35
+ if TYPE_CHECKING:
36
+ from backend.board_parser import MCIBoard
37
+ from concurrent.futures import Future
38
+
39
+ THREAD_POOL = ThreadPoolExecutor(max_workers=10)
40
+ _scanning_lock = threading.Lock()
41
+ _scanning_stop_event = threading.Event()
42
+ DEVICE_SET = set()
43
+
44
+ DEBUG_PRINT = False
45
+
46
+
47
+ def print_debug(*args, **kwargs):
48
+ if DEBUG_PRINT:
49
+ print(*args, **kwargs)
50
+
51
+
52
+ @atexit.register
53
+ def global_system_exit():
54
+ THREAD_POOL.shutdown(wait=False)
55
+ SHARED_DEVICE_MEM.close()
56
+ try:
57
+ SHARED_DEVICE_MEM.unlink()
58
+ except FileNotFoundError as e:
59
+ pass
60
+
61
+
62
+ def retry(times):
63
+ def decorator(func):
64
+ @wraps(func)
65
+ def wrapper(*args, **kwargs):
66
+ _times = times-1
67
+ while not func(*args, **kwargs) and _times > 0:
68
+ _times -= 1
69
+ return _times != 0
70
+ return wrapper
71
+ return decorator
72
+
73
+
74
+ class Driver(BaseDriver):
75
+ class ScannMode(enum.IntEnum):
76
+ """!
77
+ @detail QC/QR等被同步设备的发现方式,'local': 本地共享内存扫描, 'remote': 网络udp扫描
78
+ """
79
+ local = 0
80
+ """local: 本地共享内存扫描
81
+
82
+ - NS_MCI中的Driver每实例化一次,就会在SharedMemory中记录一次自己的ip
83
+ - 系统进行同步时,会对SharedMemory中记录的QC/QR设备ip进行同步
84
+ - 只有程序整体退出的时候才会清空这片缓存
85
+ """
86
+ remote = 1
87
+ """remote: 网络udp扫描
88
+
89
+ - import 本文件后,会建立一个独立线程间断广播UDP包,扫描局域网内的QC/QR设备,记录被扫描到的设备ip
90
+ - 系统进行同步时,会对扫描到的QC/QR设备ip进行同步
91
+ - 注意:这种方式比较粗暴,会影响局域网内正在运行的设备
92
+ """
93
+ alone = 2
94
+ """alone: 单机运行模式
95
+
96
+ - QC/QR设备单独运行时使用本模式,默认使用QC/QR设备板内的QSYNC做设备内的系统同步
97
+ - 系统进行同步时,会判断QSYNC Driver的ip是否为QC/QR设备的ip
98
+ """
99
+
100
+ _scanning_lock = _scanning_lock
101
+ _device_set = DEVICE_SET
102
+
103
+ icd_head_reset = 0x41000002
104
+ icd_head_status = 0x4100000E
105
+ icd_head_cmd_2 = 0x31000015
106
+ icd_head_cmd_3 = 0x410000B1
107
+ icd_head_cmd_4 = 0x31000013
108
+ icd_head_cmd_5 = 0x410000B2
109
+ icd_head_cmd_6 = 0x3100001A
110
+ icd_head_cmd_7 = 0x410000B3
111
+ CHs = list(range(1, 17))
112
+
113
+ quants = [
114
+ QInteger('TRIG'),
115
+ Quantity('SystemSync', value=None, ch=1), # set/get,运行次数
116
+ Quantity('GenerateTrig', value=None, unit='s'), # set/get,触发周期单位s,触发数量=shot
117
+ Quantity('ResetTrig', value=None),
118
+ Quantity('Shot', value=1024, ch=1), # set/get, 运行次数
119
+ Quantity('TrigPeriod', value=200e-6, ch=1), # set/get, 触发周期
120
+ Quantity('TrigWidth', value=800e-9, ch=1), # set/get, 触发周期
121
+ Quantity('TrigDelay', value=0, ch=1), # set/get, 触发周期
122
+ Quantity('TrigFrom', value=0, ch=1), # Trig来源: 0:内部产生;1:外部输入
123
+ Quantity('RefClock', value='out', ch=1), # 参考时钟选择: ‘out’:外参考时钟;‘in’:内参考时钟
124
+ Quantity('DiscoveryMode', value=ScannMode.local, ch=1), # QC/QR等被同步设备的发现方式,见DiscoveryMode说明
125
+ Quantity('UpdateFirmware', value='', ch=1), # qsync固件更新
126
+ ]
127
+
128
+ SystemParameter = {
129
+ 'RefClock': 'out', # 参考时钟选择: ‘out’:外参考时钟;‘in’:内参考时钟
130
+ 'TrigFrom': 0, # Trig来源: 0:内部产生;1:外部输入
131
+ 'TrigPeriod': 200e-6, # 触发信号重复周期
132
+ 'TrigWidth': 800e-9, # 触发信号高电平宽度 单位s
133
+ 'TrigDelay': 0, # 触发信号相对开启通知的延迟
134
+ 'DiscoveryMode': ScannMode.local, # QC/QR等被同步设备的发现方式,见DiscoveryMode说明
135
+ }
136
+
137
+ def __init__(self, addr: str = '', timeout: float = 10.0, **kw):
138
+ super().__init__(addr, timeout, **kw)
139
+ self.handle = None
140
+ self.model = 'NS_QSYNC' # 默认为设备名字
141
+ self.srate = None
142
+ self.gen_trig_num = 0
143
+ self.addr = addr
144
+
145
+ self.param = {'Shot': 1024, 'period': 200e-6, 'MixMode': 2}
146
+ print_debug(f'QSYNC: 实例化成功{addr}')
147
+
148
+ @property
149
+ def device_set(self):
150
+ mode = self.param.get('DiscoveryMode', self.ScannMode.local)
151
+ if mode is self.ScannMode.local:
152
+ return set(SHARED_DEVICE_MEM.ip)
153
+ elif mode is self.ScannMode.alone:
154
+ if self.addr in SHARED_DEVICE_MEM.ip:
155
+ return {self.addr}
156
+ else:
157
+ raise RuntimeError('qsync处于alone模式下,只能控制QC/QR内的qsync,请确认对应QC/QR设备是否已经open成功')
158
+ elif mode is self.ScannMode.remote:
159
+ return self._device_set.copy()
160
+ else:
161
+ return set()
162
+
163
+ def open(self, **kw):
164
+ """!
165
+ 输入IP打开设备,配置默认超时时间为5秒
166
+ 打开设备时配置RFSoC采样时钟,采样时钟以参数定义
167
+ @param kw:
168
+ @return:
169
+ """
170
+ # 配置系统初始值
171
+ system_parameter = kw.get('system_parameter', {})
172
+ values = self.SystemParameter.copy()
173
+ values.update(system_parameter)
174
+ for name, value in values.items():
175
+ if value is not None:
176
+ self.set(name, value, 1)
177
+
178
+ # self.sync_system()
179
+ status = self.get('Status')
180
+ print(f'*********QSYNC{self.addr}开启成功*********\n'
181
+ f'core_temp: {status[0]}℃\n'
182
+ f'10M_locked: {status[1] if len(status) > 1 else "nan"}')
183
+ print(f'qsync {self.addr} opened successfully')
184
+
185
+ def close(self, **kw):
186
+ """
187
+ 关闭设备
188
+ """
189
+ # self.handle.release_dma()
190
+ # self.handle.close()
191
+ ...
192
+
193
+ def write(self, name: str, value, **kw):
194
+ channel = kw.get('ch', 1)
195
+ return self.set(name, value, channel)
196
+
197
+ def read(self, name: str, **kw):
198
+ channel = kw.get('ch', 1)
199
+ result = self.get(name, channel)
200
+ return result
201
+
202
+ def set(self, name, value=None, channel=1):
203
+ """!
204
+ 设置设备属性
205
+ @param name:
206
+ @param value:
207
+ @param channel:
208
+ @return:
209
+ """
210
+ print_debug(f'QSYNC: set操作被调用{name}')
211
+ if name in {'SystemSync', 'ReInit'}:
212
+ self.sync_system()
213
+ elif name == 'TRIG':
214
+ value = self.param['TrigPeriod']
215
+ data = self.__fmt_qsync_start(
216
+ self.param['TrigFrom'], value, self.param['Shot'],
217
+ self.param['TrigWidth'], self.param['TrigDelay']
218
+ )
219
+ self._send_command(data, connect_timeout=2)
220
+ self.gen_trig_num += 1
221
+ elif name == 'GenerateTrig':
222
+ value = self.param['TrigPeriod'] if value is None else value
223
+ data = self.__fmt_qsync_start(
224
+ self.param['TrigFrom'], value, self.param['Shot'],
225
+ self.param['TrigWidth'], self.param['TrigDelay']
226
+ )
227
+ self._send_command(data, connect_timeout=2)
228
+ self.gen_trig_num += 1
229
+ elif name == 'ResetTrig':
230
+ data = self.__fmt_qsync_common(self.icd_head_reset)
231
+ self._send_command(data)
232
+ elif name == 'RefClock':
233
+ self.change_ref(value)
234
+ elif name == 'UpdateFirmware':
235
+ self.update_firmware(value)
236
+
237
+ else:
238
+ self.param[name] = value
239
+
240
+ def get(self, name, channel=1, value=0):
241
+ """!
242
+ 查询设备属性,获取数据
243
+ @param name:
244
+ @param channel:
245
+ @param value:
246
+ @return:
247
+ """
248
+ print_debug(f'QSYNC: get操作被调用{name}')
249
+ if name == 'Status':
250
+ cmd_data = self.__fmt_qsync_common(self.icd_head_status)
251
+ data = DeviceCmdHandle.send_command(cmd_data, addr=self.addr, return_fdk=True)
252
+ data = struct.unpack('I' * (len(data) // 4), data)
253
+ return data
254
+ return self.param.get(name, None)
255
+
256
+ def sync_system(self):
257
+ """
258
+ 全系统同步流程
259
+
260
+ :return:
261
+ """
262
+ if Driver._scanning_lock.acquire(timeout=10):
263
+ Driver._scanning_lock.release()
264
+ if len(self.device_set) == 0:
265
+ return
266
+
267
+ data = self.__fmt_qsync_common(self.icd_head_reset)
268
+ self._send_command(data)
269
+
270
+ result = True
271
+ if self.param.get('DiscoveryMode', self.ScannMode.local) != self.ScannMode.alone:
272
+ data = self.__fmt_qsync_common(self.icd_head_reset)
273
+ result &= self._sendto_fake_qsync(data)
274
+ data = self.__fmt_qsync_ref_from('out')
275
+ result &= self._sendto_fake_qsync(data)
276
+ result &= self._sendto_device(self.icd_head_cmd_2)
277
+ result &= self._sendto_qsync(self.icd_head_cmd_3)
278
+ result &= self._sendto_device(self.icd_head_cmd_4)
279
+ result &= self._sendto_qsync(self.icd_head_cmd_5)
280
+ result &= self._sendto_device(self.icd_head_cmd_6, 30)
281
+ result &= self._sendto_qsync(self.icd_head_cmd_7)
282
+
283
+ print(f'System synchronization {"succeeded" if result else "FAILED"}')
284
+
285
+ def change_ref(self, value='out'):
286
+ self.param['RefClock'] = value
287
+ self.set('ResetTrig')
288
+ data = self.__fmt_qsync_ref_from(value)
289
+ self._send_command(data)
290
+
291
+ def _sendto_device(self, cmd_head, timeout=2):
292
+ """!
293
+ 将指令发送给设备
294
+ @param cmd_head:
295
+ @param timeout:
296
+ @return:
297
+ """
298
+ cmd_data = self.__fmt_qsync_common(cmd_head)
299
+ devices = list(self.device_set)
300
+ futures = [
301
+ THREAD_POOL.submit(DeviceCmdHandle.send_command, cmd_data, 0, addr, 5000, True, False, timeout)
302
+ for addr in devices
303
+ ]
304
+ wait_futures(futures)
305
+ result = all(future.result() for future in futures)
306
+ for idx, future in enumerate(futures):
307
+ if not future.result():
308
+ print(f'device: {devices[idx]}系统同步过程 {hex(cmd_head)} 执行失败')
309
+ return result
310
+
311
+ def _sendto_fake_qsync(self, cmd_data, timeout=2):
312
+ devices = list(self.device_set)
313
+ futures = [
314
+ THREAD_POOL.submit(self._send_command, cmd_data, 0, addr, 5001, True, False, timeout)
315
+ for addr in devices if addr != self.addr
316
+ ]
317
+ wait_futures(futures)
318
+ result = all(future.result() for future in futures)
319
+ for idx, future in enumerate(futures):
320
+ if not future.result():
321
+ print(f'device: {devices[idx]}系统同步过程 {cmd_data[4:12]} 执行失败')
322
+ return result
323
+
324
+ def _sendto_qsync(self, cmd_head: int):
325
+ """!
326
+ 将指令发送给qsync
327
+
328
+ @param cmd_head:
329
+ @return:
330
+ """
331
+ cmd_data = self.__fmt_qsync_common(cmd_head)
332
+ if not self._send_command(cmd_data, connect_timeout=2):
333
+ print(f'qsync: 系统同步过程 {hex(cmd_head)} 执行失败')
334
+ return False
335
+ return True
336
+
337
+ def update_firmware(self, file_path, boards=None):
338
+ """!
339
+ 固件更新
340
+
341
+ @param file_path: 固件路径
342
+ @param boards:
343
+ @return:
344
+ """
345
+ import os
346
+ if not os.path.exists(file_path):
347
+ raise ValueError(f'文件路径: {file_path} 不存在')
348
+ with open(file_path, 'rb') as fp:
349
+ cmd_data = self.__fmt_update_firmware(fp.read())
350
+ if not self._send_command(cmd_data):
351
+ print(f'qsync: 固件更新 执行失败')
352
+
353
+ def _connect(self, addr=None, port=5001, timeout=None):
354
+ """!
355
+ 获取到指定ip的tcp连接
356
+
357
+ @param addr:
358
+ @param port:
359
+ @return:
360
+ """
361
+ timeout = self.timeout if timeout is None else timeout
362
+ addr = self.addr if addr is None else addr
363
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
364
+ sock.settimeout(timeout)
365
+ sock.connect((addr, port))
366
+ return sock
367
+
368
+ @retry(3)
369
+ def _send_command(self, data: Union[str, bytes], wait=0, addr=None, port=5001,
370
+ check_feedback=True, return_fdk=False, connect_timeout=10):
371
+ """!
372
+ 发送指定内容到后端
373
+
374
+ @param data: 指令内容
375
+ @param wait: 指令发送完成后,等待一段时间再接收反馈,阻塞式等待
376
+ @param addr: 后端IP
377
+ @param port: 后端端口
378
+ @param check_feedback: 是否解析反馈
379
+ @param connect_timeout:
380
+ @return:
381
+ """
382
+ command_bak = data
383
+ try:
384
+ sock = self._connect(addr=addr, port=port, timeout=connect_timeout)
385
+ except Exception as e:
386
+ print(f'device: {addr}无法连接 {e}')
387
+ return False
388
+
389
+ try:
390
+ sock.sendall(memoryview(data))
391
+
392
+ time.sleep(wait)
393
+ _feedback = sock.recv(20)
394
+ if check_feedback:
395
+ if not _feedback.startswith(b'\xcf\xcf\xcf\xcf'):
396
+ print('返回指令包头错误')
397
+ return False
398
+ if command_bak[4:8] != _feedback[4:8]:
399
+ print('返回指令ID错误')
400
+ return False
401
+ # print(_feedback)
402
+ _feedback = struct.unpack('=IIIII', _feedback)
403
+ if _feedback[4] != 0:
404
+ print('指令成功下发,但执行失败')
405
+ return False
406
+ except Exception as e:
407
+ print(f'device: {addr}指令{command_bak[:4]}发送失败 {e}')
408
+ return False
409
+ finally:
410
+ sock.close()
411
+ return True
412
+
413
+ @lru_cache(maxsize=32)
414
+ def __fmt_qsync_common(self, head):
415
+ cmd_pack = (
416
+ 0x5F5F5F5F,
417
+ head,
418
+ 0x00000000,
419
+ 16,
420
+ )
421
+
422
+ return struct.pack('=' + 'I' * len(cmd_pack), *cmd_pack)
423
+
424
+ @lru_cache(maxsize=16)
425
+ def __fmt_qsync_ref_from(self, _from):
426
+ if _from == 'in':
427
+ _from = 0
428
+ elif _from == 'out':
429
+ _from = 1
430
+ else:
431
+ _from = 0
432
+ cmd_pack = (
433
+ 0x5F5F5F5F,
434
+ 0x4100000F,
435
+ 0x00000000,
436
+ 20,
437
+ _from
438
+ )
439
+
440
+ return struct.pack('=' + 'I' * len(cmd_pack), *cmd_pack)
441
+
442
+ @lru_cache(maxsize=32)
443
+ def __fmt_qsync_start(self, src, period, shots, width, delay):
444
+ cmd_pack = (
445
+ 0x5F5F5F5F,
446
+ 0x41000001,
447
+ 0x00000000,
448
+ 36,
449
+ int(src),
450
+ int(period * 1e9) & 0xFFFFFFFF,
451
+ int(shots),
452
+ int(width * 1e9) & 0xFFFFFFFF,
453
+ int(delay * 1e9) & 0xFFFFFFFF
454
+ )
455
+
456
+ return struct.pack('=' + 'I' * len(cmd_pack), *cmd_pack)
457
+
458
+ @staticmethod
459
+ def __fmt_update_firmware(file_data):
460
+ cmd_pack = (
461
+ 0x5F5F5F5F,
462
+ 0x31000006,
463
+ 0x00000000,
464
+ 16 + len(file_data),
465
+ )
466
+ return struct.pack('=' + 'I' * len(cmd_pack), *cmd_pack) + file_data
467
+
468
+ # DG645兼容
469
+ def Trigger_singleshot(self):
470
+ self.set('GenerateTrig')
471
+
472
+ def Convention_init(self, rate=5000, **kwds):
473
+ self.set('ResetTrig')
474
+ self.set('Shot', 0xFFFFFFFF)
475
+ self.set('TrigPeriod', 1 / rate)
476
+ self.set('GenerateTrig')
477
+
478
+ def BurstMode_init(self, count=2048, delay=200e-6, period=200e-6, source=0, **kwds):
479
+ self.set('ResetTrig')
480
+ self.set('Shot', count)
481
+ self.set('TrigPeriod', period)
482
+ self.set('TrigDelay', delay)
483
+ self.set('TrigFrom', source)
484
+
485
+ def startGun(self):
486
+ self.Trigger_singleshot()
487
+
488
+
489
+ def do_scanning():
490
+ """
491
+ 扫描板卡
492
+
493
+ :return:
494
+ """
495
+ while True:
496
+ dest = ('<broadcast>', 5003)
497
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
498
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
499
+ addrs = socket.getaddrinfo(socket.gethostname(), None)
500
+ addr = [addr[4][0] for addr in addrs if addr[4][0].startswith('192.168.1.')]
501
+ _bind = False
502
+ _port = 15000
503
+ with _scanning_lock:
504
+ while not _bind:
505
+ try:
506
+ s.bind((addr[0], _port))
507
+ _bind = True
508
+ except Exception as e:
509
+ _port += 1
510
+ if _port >= 30000:
511
+ raise e
512
+ s.sendto(b"____\x20\x00\x002\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00", dest)
513
+ s.settimeout(3)
514
+
515
+ try:
516
+ while True:
517
+ (feedback, _addr) = s.recvfrom(20)
518
+ if feedback:
519
+ DEVICE_SET.add(_addr[0])
520
+ except Exception as e:
521
+ s.close()
522
+ time.sleep(5)
523
+
524
+
525
+ class DeviceCmdHandle:
526
+ """!
527
+ @brief 封装与QC/QR设备间的交互
528
+ """
529
+ error_map = {b'\x1a\x00\x001': {1: '指令Resync执行失败',
530
+ 2: 'REFCLK not Detected',
531
+ 3: 'Clock Maybe unstable, DAC Settings Error',
532
+ 4: 'Clock Maybe unstable, ADC Settings Error',
533
+ 5: 'SYSREF(External TRIG) not Detected, MTS failed / Sample Rate not Support',
534
+ 7: 'ADC Calibration Failed'}
535
+ }
536
+
537
+ @staticmethod
538
+ def packing_result(boards: Iterable["MCIBoard"],
539
+ futures: Iterable["Future"],
540
+ cmd_data: memoryview,
541
+ head: bytes) -> Tuple[bytes, list]:
542
+ res = []
543
+ errors = []
544
+ for board, future in zip(boards, futures):
545
+ if board.has_ip and board.has_dma:
546
+ _id = (board.dma_id & 0xFF) << 24
547
+ _res = struct.unpack('IIIII', future.result())[-1] & 0xFFFFFF
548
+ if _res:
549
+ errors.append(f'指令{cmd_data[4:8].tobytes()}向{board.board_ip}转发失败\n')
550
+ res.append(_id + _res)
551
+ return b''.join((head, cmd_data[4:12], struct.pack('=I' + 'I' * len(res), 16 + len(res) * 4, *res))), errors
552
+
553
+ @staticmethod
554
+ def packing_fake_result(boards: Iterable["MCIBoard"], cmd_data: memoryview, head: bytes) -> bytes:
555
+ res = []
556
+ for board in boards:
557
+ if board.has_ip and board.has_dma:
558
+ _id = (board.dma_id & 0xFF) << 24
559
+ res.append(_id + 0)
560
+ return b''.join((head, cmd_data[4:12], struct.pack('=I' + 'I' * len(res), 16 + len(res) * 4, *res)))
561
+
562
+ @classmethod
563
+ def unpacking_result(cls, _feedback, _res, command_bak, addr):
564
+ cmd_id = command_bak[4:8]
565
+ if not _feedback.startswith(b'\xcf\xcf\xcf\xcf'):
566
+ print(f'设备{addr}-指令{cmd_id}-返回指令包头错误')
567
+ return False
568
+ if cmd_id != _feedback[4:8]:
569
+ print(f'设备{addr}-指令{cmd_id}-返回指令ID错误{_feedback[4:8]}')
570
+ return False
571
+ if len(_res) % 4 != 0:
572
+ print(f'设备{addr}-指令{cmd_id}-返回结果{_res}长度错误')
573
+ return False
574
+ command_status = True
575
+ results = struct.unpack('I' * (len(_res) // 4), _res)
576
+ for result in results:
577
+ board_id = (result & 0xFF000000) >> 24
578
+ board_res = result & 0xFFFFFF
579
+ error_map = cls.error_map.get(command_bak[4:8], {})
580
+ if board_res:
581
+ print(f'设备{addr}-板卡{board_id}-指令{cmd_id}-{error_map.get(board_res, "执行失败")}')
582
+ command_status &= False
583
+ return command_status
584
+
585
+ @classmethod
586
+ def send_command(cls, data: Union[str, bytes], wait=0, addr=None, port=5001,
587
+ check_feedback=True, return_fdk=False, connect_timeout=None):
588
+ """!
589
+ 发送指定内容到后端
590
+
591
+ @param data: 指令内容
592
+ @param wait: 指令发送完成后,等待一段时间再接收反馈,阻塞式等待
593
+ @param addr: 后端IP
594
+ @param port: 后端端口
595
+ @param check_feedback:
596
+ @param return_fdk:
597
+ @param connect_timeout:
598
+ @return:
599
+ """
600
+ command_bak = data
601
+ try:
602
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
603
+ sock.settimeout(connect_timeout)
604
+ sock.connect((addr, port))
605
+ except Exception as e:
606
+ print(e)
607
+ return False
608
+
609
+ try:
610
+ sock.sendall(memoryview(data))
611
+
612
+ time.sleep(wait)
613
+ _feedback = sock.recv(16)
614
+ if check_feedback:
615
+ _res = sock.recv(struct.unpack('I', _feedback[12:16])[0] - 16)
616
+ if return_fdk:
617
+ return _res
618
+ else:
619
+ return cls.unpacking_result(_feedback, _res, command_bak, addr)
620
+ except Exception as e:
621
+ print(e)
622
+ return False
623
+ finally:
624
+ sock.close()
625
+ return True
626
+
627
+
628
+ class InfoSharedList:
629
+ memory_name = 'NS_DEVICE_MEMORY'
630
+ memory_size = 1024 ** 2
631
+ head_size = 32 # memory中前head_size的长度为头部预留信息
632
+
633
+ def __init__(self):
634
+ try:
635
+ self._memory = shared_memory.SharedMemory(name=self.memory_name, create=True, size=self.memory_size)
636
+ except FileExistsError:
637
+ self._memory = shared_memory.SharedMemory(name=self.memory_name, create=False, size=self.memory_size)
638
+
639
+ def clear_ip(self):
640
+ _exit_pkl = pickle.dumps(self.ip)
641
+ self._memory.buf[self.head_size:len(_exit_pkl) + self.head_size] = b'\x00' * len(_exit_pkl)
642
+
643
+ @property
644
+ def ip(self):
645
+ try:
646
+ return pickle.loads(self._memory.buf[self.head_size:])
647
+ except pickle.UnpicklingError:
648
+ return []
649
+
650
+ @ip.setter
651
+ def ip(self, value):
652
+ ips = self.ip
653
+ ips.append(value)
654
+ ips = list(set(ips))
655
+ _pkl = pickle.dumps(ips)
656
+ self._memory.buf[self.head_size:len(_pkl) + self.head_size] = _pkl
657
+
658
+ def close(self):
659
+ self._memory.close()
660
+
661
+ def unlink(self):
662
+ try:
663
+ self._memory.unlink()
664
+ except FileNotFoundError as e:
665
+ pass
666
+
667
+
668
+ # threading.Thread(target=do_scanning, daemon=True, name='qsync_scanning_device').start()
669
+ SHARED_DEVICE_MEM = InfoSharedList()
nsqdriver/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+ from .NS_MCI import Driver as MCIDriver
2
+ from .NS_QSYNC import Driver as QSYNCDriver
3
+ from .NS_CST import Driver as CSTDriver
4
+ from .compiler.ns_wave import InsChannel
5
+ from .compiler.py_wave_asm import nsw_config, AssemblyError
6
+
7
+ version_pack = (0, 3, 1)
8
+
9
+ __version__ = '.'.join(str(_) for _ in version_pack)
10
+ __all__ = ['MCIDriver', 'QSYNCDriver', 'CSTDriver', 'InsChannel']
nsqdriver/common.py ADDED
@@ -0,0 +1,20 @@
1
+ class Quantity(object):
2
+ def __init__(self, name: str, value=None, ch: int = 1, unit: str = ''):
3
+ self.name = name
4
+ self.default = dict(value=value, ch=ch, unit=unit)
5
+
6
+
7
+ class QInteger:
8
+ def __init__(self, name, value=None, unit='', ch=None,
9
+ get_cmd='', set_cmd='',):
10
+ self.name = name
11
+
12
+
13
+ class BaseDriver:
14
+ def __init__(self, addr, timeout, **kw):
15
+ self.addr = addr
16
+ self.timeout = timeout
17
+
18
+
19
+ def get_coef(*args):
20
+ return '', '', '', ''
File without changes