nsqdriver 0.12.16__cp313-cp313-macosx_10_13_universal2.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_CST.py +260 -0
- nsqdriver/NS_DDS_v3.py +591 -0
- nsqdriver/NS_DDS_v4.py +778 -0
- nsqdriver/NS_MCI.py +594 -0
- nsqdriver/NS_QSYNC.py +780 -0
- nsqdriver/__init__.py +10 -0
- nsqdriver/common.py +20 -0
- nsqdriver/compiler/__init__.py +0 -0
- nsqdriver/compiler/assembler.cpython-313-darwin.so +0 -0
- nsqdriver/compiler/ns_wave.cpython-313-darwin.so +0 -0
- nsqdriver/compiler/ns_wave.pyi +151 -0
- nsqdriver/compiler/py_wave_asm.cpython-313-darwin.so +0 -0
- nsqdriver/compiler/py_wave_asm.pyi +29 -0
- nsqdriver/nswave/__init__.py +9 -0
- nsqdriver/nswave/_asm.pyi +97 -0
- nsqdriver/nswave/_checkers.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_checkers.pyi +47 -0
- nsqdriver/nswave/_errors.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_errors.pyi +24 -0
- nsqdriver/nswave/_functions.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_functions.pyi +34 -0
- nsqdriver/nswave/_ir.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_ir.pyi +283 -0
- nsqdriver/nswave/_ir_pass.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_ir_pass.pyi +7 -0
- nsqdriver/nswave/_optimizations.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_optimizations.pyi +16 -0
- nsqdriver/nswave/_rules.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_rules.pyi +56 -0
- nsqdriver/nswave/_simulator.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_translate.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/_translate.pyi +12 -0
- nsqdriver/nswave/kernel.cpython-313-darwin.so +0 -0
- nsqdriver/nswave/kernel.pyi +57 -0
- nsqdriver/wrapper/AWG_ADC.py +534 -0
- nsqdriver/wrapper/ND_NSMCI.py +245 -0
- nsqdriver/wrapper/__init__.py +0 -0
- nsqdriver-0.12.16.dist-info/METADATA +117 -0
- nsqdriver-0.12.16.dist-info/RECORD +41 -0
- nsqdriver-0.12.16.dist-info/WHEEL +5 -0
- nsqdriver-0.12.16.dist-info/top_level.txt +1 -0
nsqdriver/NS_MCI.py
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
import traceback
|
|
3
|
+
import pickle
|
|
4
|
+
import socket
|
|
5
|
+
import atexit
|
|
6
|
+
import struct
|
|
7
|
+
import warnings
|
|
8
|
+
import xmlrpc.client
|
|
9
|
+
from xmlrpc.client import Transport
|
|
10
|
+
from multiprocessing import shared_memory
|
|
11
|
+
from functools import wraps
|
|
12
|
+
from enum import Enum
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
import waveforms
|
|
18
|
+
HAS_WAVEFORMS = True
|
|
19
|
+
except ImportError as e:
|
|
20
|
+
HAS_WAVEFORMS = False
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from .common import BaseDriver, Quantity, get_coef
|
|
24
|
+
except ImportError as e:
|
|
25
|
+
class BaseDriver:
|
|
26
|
+
def __init__(self, addr, timeout, **kw):
|
|
27
|
+
self.addr = addr
|
|
28
|
+
self.timeout = timeout
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Quantity(object):
|
|
32
|
+
def __init__(self, name: str, value=None, ch: int = 1, unit: str = ''):
|
|
33
|
+
self.name = name
|
|
34
|
+
self.default = dict(value=value, ch=ch, unit=unit)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_coef(*args):
|
|
38
|
+
return '', '', '', ''
|
|
39
|
+
|
|
40
|
+
DEBUG_PRINT = False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def print_debug(*args, **kwargs):
|
|
44
|
+
if DEBUG_PRINT:
|
|
45
|
+
print(*args, **kwargs)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@atexit.register
|
|
49
|
+
def global_system_exit():
|
|
50
|
+
"""
|
|
51
|
+
关闭共享内存
|
|
52
|
+
|
|
53
|
+
:return:
|
|
54
|
+
"""
|
|
55
|
+
SHARED_DEVICE_MEM.close()
|
|
56
|
+
SHARED_DEVICE_MEM.unlink()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def solve_rpc_exception(func):
|
|
60
|
+
@wraps(func)
|
|
61
|
+
def wrapper(*args, **kwargs):
|
|
62
|
+
try:
|
|
63
|
+
return func(*args, **kwargs)
|
|
64
|
+
except xmlrpc.client.Fault as e:
|
|
65
|
+
pack = RPCFaultPack.from_fault(e)
|
|
66
|
+
print(f'************{args[0].__class__}: {args[0].addr}************')
|
|
67
|
+
print(f'*-*-*-*-*-*-*-远程函数报错: {pack.type}::{pack.name} -*-*-*-*-*-*-*-*')
|
|
68
|
+
print(pack.message)
|
|
69
|
+
print(f'*-*-*-*-*-*-*-远程函数报错: {pack.type}::{pack.name} -*-*-*-*-*-*-*-*')
|
|
70
|
+
except TimeoutError as e:
|
|
71
|
+
print(f'************{args[0].__class__}: {args[0].addr}************')
|
|
72
|
+
print(f'Driver报错: 无法连接到 {args[0].addr}\n请检查网络、设备开机状态、设备是否正在程序更新等')
|
|
73
|
+
print(f'{e}')
|
|
74
|
+
print('*****************************')
|
|
75
|
+
raise e
|
|
76
|
+
except socket.timeout as e:
|
|
77
|
+
print(f'************{args[0].__class__}: {args[0].addr}************')
|
|
78
|
+
print(f'Driver报错: 获取数据超时 {e}')
|
|
79
|
+
print('*****************************')
|
|
80
|
+
return wrapper
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class DataMode(str, Enum):
|
|
84
|
+
DIRECT = 'direct'
|
|
85
|
+
NORMAL = 'normal'
|
|
86
|
+
RDMA = 'rdma'
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class Driver(BaseDriver):
|
|
90
|
+
CHs = list(range(1, 25))
|
|
91
|
+
segment = ('ns', '111|112|113|114|115')
|
|
92
|
+
|
|
93
|
+
quants = [
|
|
94
|
+
Quantity('ReInit', value={}, ch=1), # set, 设备重新初始化
|
|
95
|
+
Quantity('Instruction', value=None, ch=1), # set 参数化波形指令队列配置
|
|
96
|
+
# 采集运行参数
|
|
97
|
+
Quantity('Shot', value=1024, ch=1), # set,运行次数
|
|
98
|
+
Quantity('PointNumber', value=16384, unit='point'), # set/get,AD采样点数
|
|
99
|
+
Quantity('TriggerDelay', value=0, ch=1, unit='s'), # set/get,AD采样延时
|
|
100
|
+
Quantity('FrequencyList', value=[], ch=1, unit='Hz'), # set/get,解调频率列表,list,单位Hz
|
|
101
|
+
Quantity('PhaseList', value=[], ch=1, unit='Hz'), # set/get,解调频率列表,list,单位Hz
|
|
102
|
+
Quantity('Coefficient', value=None, ch=1),
|
|
103
|
+
Quantity('DemodulationParam', value=None, ch=1),
|
|
104
|
+
Quantity('CaptureMode'),
|
|
105
|
+
Quantity('StartCapture'), # set,开启采集(执行前复位)
|
|
106
|
+
Quantity('TraceIQ', ch=1), # get,获取原始时域数据
|
|
107
|
+
# 返回:array(shot, point)
|
|
108
|
+
Quantity('IQ', ch=1), # get,获取解调后数据,默认复数返回
|
|
109
|
+
# 系统参数,宏定义修改,open时下发
|
|
110
|
+
# 复数返回:array(shot,frequency)
|
|
111
|
+
# 实数返回:array(IQ,shot,frequency)
|
|
112
|
+
|
|
113
|
+
# 任意波形发生器
|
|
114
|
+
Quantity('Waveform', value=np.array([]), ch=1), # set/get,下发原始波形数据
|
|
115
|
+
Quantity('Delay', value=0, ch=1), # set/get,播放延时
|
|
116
|
+
Quantity('KeepAmp', value=0), # set, 电平是否维持在波形最后一个值, 0:波形播放完成后归0,1:保持波形最后一个值,2:保持波形第一个值
|
|
117
|
+
Quantity('Biasing', value=0, ch=1), # set, 播放延迟
|
|
118
|
+
Quantity('LinSpace', value=[0, 30e-6, 1000], ch=1), # set/get, np.linspace函数,用于生成timeline
|
|
119
|
+
Quantity('Output', value=True, ch=1), # set/get,播放通道开关设置
|
|
120
|
+
Quantity('GenWave', value=None, ch=1), # set/get, 设备接收waveform对象,根据waveform对象直接生成波形
|
|
121
|
+
# set/get, 设备接收IQ分离的waveform对象列表,根据waveform对象列表直接生成波形
|
|
122
|
+
Quantity('GenWaveIQ', value=None, ch=1),
|
|
123
|
+
Quantity('MultiGenWave', value={1: np.ndarray([])}), # 多通道波形同时下发
|
|
124
|
+
Quantity('EnableWaveCache', value=False), # 是否开启waveform缓存
|
|
125
|
+
Quantity('PushWaveCache'), # 使waveform缓存中的波形数据生效
|
|
126
|
+
# 混频相关配置
|
|
127
|
+
Quantity('EnableDAMixer', value=False, ch=1), # DA通道混频模式开关
|
|
128
|
+
Quantity('MixingWave',), # 修改完混频相关参数后,运行混频器
|
|
129
|
+
Quantity('DAIQRate', value=1e9, ch=1), # 基带信号采样率
|
|
130
|
+
Quantity('DALOFreq', value=100e6, ch=1), # 中频信号频率
|
|
131
|
+
Quantity('DALOPhase', value=0, ch=1), # 基带信号相位,弧度制
|
|
132
|
+
Quantity('DASideband', value='lower', ch=1), # 混频后取的边带
|
|
133
|
+
Quantity('DAWindow', value=None, ch=1),
|
|
134
|
+
# 基带信号升采样率时所使用的窗函数,默认不使用任何窗,
|
|
135
|
+
# 可选:None、boxcar、triang、blackman、hamming、hann、bartlett、flattop、parzen、bohman、blackmanharris、nuttall、
|
|
136
|
+
# barthann、cosine、exponential、tukey、taylor
|
|
137
|
+
|
|
138
|
+
# 内触发
|
|
139
|
+
Quantity('GenerateTrig', value=1e7, unit='ns'), # set/get,触发周期单位ns,触发数量=shot
|
|
140
|
+
Quantity('UpdateFirmware', value='', ch=1), # qsync固件更新
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
SystemParameter = {
|
|
144
|
+
'ExcLimit': -1, # 设备traceback打印信息的回溯深度
|
|
145
|
+
'Warning': True, # 开启后台警告上报
|
|
146
|
+
'MixMode': 2, # Mix模式,1:第一奈奎斯特去; 2:第二奈奎斯特区
|
|
147
|
+
'PLLFreq': 100e6, # 参考时钟频率, 单位为Hz
|
|
148
|
+
'RefClock': 'out', # 参考时钟选择: ‘out’:外参考时钟;‘in’:内参考时钟
|
|
149
|
+
'ADrate': 4e9, # AD采样率,单位Hz
|
|
150
|
+
'DArate': 6e9, # DA采样率,单位Hz
|
|
151
|
+
'KeepAmp': 0, # DA波形发射完毕后,保持最后一个值
|
|
152
|
+
'Delay': 0, # 配置DA的原生Delay
|
|
153
|
+
'SegmentSampling': [], # 配置分段采样
|
|
154
|
+
# 'EnableDAMixer': False, # 默认关闭DA混频器
|
|
155
|
+
# 'DASideband': 'lower', # da混频默认使用下边带
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
def __init__(self, addr: str = '', timeout: float = 10.0, **kw):
|
|
159
|
+
super().__init__(addr, timeout, **kw)
|
|
160
|
+
self.fast_rpc = None
|
|
161
|
+
self.handle = None
|
|
162
|
+
self.model = 'NS_MCI' # 默认为设备名字
|
|
163
|
+
self.srate = 6e9
|
|
164
|
+
self.data_mode = DataMode.NORMAL
|
|
165
|
+
self.device_online = True
|
|
166
|
+
self.has_start_capture = False
|
|
167
|
+
self.backend_version = (0, 0, 0)
|
|
168
|
+
print_debug(f'Driver: 实例化成功{addr}')
|
|
169
|
+
|
|
170
|
+
@solve_rpc_exception
|
|
171
|
+
def open(self, **kw):
|
|
172
|
+
"""
|
|
173
|
+
输入IP打开设备,配置默认超时时间为5秒
|
|
174
|
+
打开设备时配置RFSoC采样时钟,采样时钟以参数定义
|
|
175
|
+
"""
|
|
176
|
+
tran = Transport(use_builtin_types=True)
|
|
177
|
+
tran.accept_gzip_encoding = False
|
|
178
|
+
self.handle = xmlrpc.client.ServerProxy(f'http://{self.addr}:10801', transport=tran, allow_none=True,
|
|
179
|
+
use_builtin_types=True)
|
|
180
|
+
self.fast_rpc = FastRPC(self.addr, self.timeout)
|
|
181
|
+
debug = kw.get('debug', False)
|
|
182
|
+
if debug:
|
|
183
|
+
return
|
|
184
|
+
print_debug('Driver: RPC句柄建立成功')
|
|
185
|
+
# 检查目标设备是否在位设备
|
|
186
|
+
result = self.init_device(**kw)
|
|
187
|
+
if result:
|
|
188
|
+
# 在共享内存中注册本设备的ip
|
|
189
|
+
SHARED_DEVICE_MEM.ip = self.addr
|
|
190
|
+
self._show_system_status()
|
|
191
|
+
print(f'{self.addr}开启成功')
|
|
192
|
+
elif result is None:
|
|
193
|
+
...
|
|
194
|
+
else:
|
|
195
|
+
print(self.handle.get_all_status())
|
|
196
|
+
|
|
197
|
+
def init_device(self, **kw):
|
|
198
|
+
try:
|
|
199
|
+
self._connect(self.addr, timeout=1).close()
|
|
200
|
+
except:
|
|
201
|
+
print(f'Driver: {self.addr}不在位,请检查网络重新open')
|
|
202
|
+
self.device_online = False
|
|
203
|
+
return
|
|
204
|
+
# 此时会连接rfsoc的指令接收tcp server
|
|
205
|
+
result = True
|
|
206
|
+
result &= self.handle.start_command(self.timeout)
|
|
207
|
+
print_debug('Driver: 后端rfs网络连接成功')
|
|
208
|
+
|
|
209
|
+
# 配置系统初始值
|
|
210
|
+
system_parameter = kw.get('system_parameter', {})
|
|
211
|
+
values = self.SystemParameter.copy()
|
|
212
|
+
values.update(system_parameter)
|
|
213
|
+
for name, value in values.items():
|
|
214
|
+
if value is not None:
|
|
215
|
+
res = self.fast_rpc.rpc_set(name, value, 0, False)
|
|
216
|
+
if isinstance(res, str):
|
|
217
|
+
print("*********后台提示*********\n", res)
|
|
218
|
+
print_debug('Driver: 后端参数配置成功')
|
|
219
|
+
|
|
220
|
+
# 系统开启前必须进行过一次初始化
|
|
221
|
+
result &= self.__init_system()
|
|
222
|
+
print_debug('Driver: 后端RF配置成功')
|
|
223
|
+
result &= self.fast_rpc.rpc_set('Reset')
|
|
224
|
+
print_debug('Driver: 后端缓存配置成功')
|
|
225
|
+
return result
|
|
226
|
+
|
|
227
|
+
@solve_rpc_exception
|
|
228
|
+
def close(self, **kw):
|
|
229
|
+
"""
|
|
230
|
+
关闭设备
|
|
231
|
+
"""
|
|
232
|
+
...
|
|
233
|
+
|
|
234
|
+
def write(self, name: str, value, **kw):
|
|
235
|
+
channel = kw.get('ch', 1)
|
|
236
|
+
if name in {'Coefficient'}:
|
|
237
|
+
data, f_list, numberOfPoints, phases = get_coef(value, 4e9)
|
|
238
|
+
judg_param = []
|
|
239
|
+
for qu in value['wlist']:
|
|
240
|
+
judg_param.append([qu['phi'], qu['threshold']])
|
|
241
|
+
self.set('JudgParam', judg_param, channel)
|
|
242
|
+
self.set('DemodulationParam', data, channel)
|
|
243
|
+
else:
|
|
244
|
+
return self.set(name, value, channel)
|
|
245
|
+
|
|
246
|
+
def read(self, name: str, **kw):
|
|
247
|
+
channel = kw.get('ch', 1)
|
|
248
|
+
result = self.get(name, channel)
|
|
249
|
+
return result
|
|
250
|
+
|
|
251
|
+
@solve_rpc_exception
|
|
252
|
+
def set(self, name, value=0, channel=1):
|
|
253
|
+
"""
|
|
254
|
+
设置设备属性
|
|
255
|
+
|
|
256
|
+
:param name: 属性名
|
|
257
|
+
"Waveform"| "Amplitude" | "Offset"| "Output"
|
|
258
|
+
:param value: 属性值
|
|
259
|
+
"Waveform" --> 1d np.ndarray & -1 <= value <= 1
|
|
260
|
+
"Amplitude"| "Offset"| "Phase" --> float dB | dB | °
|
|
261
|
+
“PRFNum” 采用内部PRF时,可以通过这个参数控制开启后prf的数量
|
|
262
|
+
"Output" --> bool
|
|
263
|
+
:param channel:通道号
|
|
264
|
+
"""
|
|
265
|
+
if not self.device_online:
|
|
266
|
+
return
|
|
267
|
+
print_debug(f'Driver: set操作被调用{name}')
|
|
268
|
+
if name in {'UpdateFirmware'}:
|
|
269
|
+
self.update_firmware(value)
|
|
270
|
+
return
|
|
271
|
+
elif name in {'ReInit'}:
|
|
272
|
+
if not isinstance(value, dict):
|
|
273
|
+
value = {}
|
|
274
|
+
self.init_device(system_parameter=value)
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
value = RPCValueParser.dump(value)
|
|
278
|
+
func = self.fast_rpc.rpc_set
|
|
279
|
+
name = 'GenWave' if name == 'Waveform' and value[0] == RPCValueParser.dump_tag_waveform else name
|
|
280
|
+
|
|
281
|
+
if self.has_start_capture and name == 'StartCapture':
|
|
282
|
+
return
|
|
283
|
+
self.has_start_capture = name == 'StartCapture'
|
|
284
|
+
|
|
285
|
+
if not func(name, value, channel):
|
|
286
|
+
...
|
|
287
|
+
# raise xmlrpc.client.Fault(400, f'指令{name}执行失败, 请重新open板卡')
|
|
288
|
+
|
|
289
|
+
@solve_rpc_exception
|
|
290
|
+
def get(self, name, channel=1, value=0):
|
|
291
|
+
"""
|
|
292
|
+
查询设备属性,获取数据
|
|
293
|
+
|
|
294
|
+
"""
|
|
295
|
+
if not self.device_online:
|
|
296
|
+
return
|
|
297
|
+
print_debug(f'Driver: get操作被调用{name}')
|
|
298
|
+
self.has_start_capture = False
|
|
299
|
+
if name in {'Trace', 'TraceIQ'} and self.backend_version >= (2, 8, 0):
|
|
300
|
+
data_mode = self.get('DataMode', channel)
|
|
301
|
+
data_mode = DataMode(data_mode) if data_mode else DataMode.NORMAL
|
|
302
|
+
if data_mode == DataMode.DIRECT:
|
|
303
|
+
return self._get_trace_data(channel)
|
|
304
|
+
|
|
305
|
+
func = self.fast_rpc.rpc_get
|
|
306
|
+
tmp = func(name, channel, value)
|
|
307
|
+
tmp = RPCValueParser.load(tmp)
|
|
308
|
+
return tmp
|
|
309
|
+
|
|
310
|
+
def update_firmware(self, file_path, target='all', _id=0):
|
|
311
|
+
if not self.device_online:
|
|
312
|
+
return
|
|
313
|
+
import os
|
|
314
|
+
if not os.path.exists(file_path):
|
|
315
|
+
raise ValueError(f'文件路径: {file_path} 不存在')
|
|
316
|
+
with open(file_path, 'rb') as fp:
|
|
317
|
+
result = self.handle.update_rfs_firmware(fp.read(), target, _id)
|
|
318
|
+
if result:
|
|
319
|
+
print(f'设备{self.addr} 固件更新成功,3s后设备自动重启')
|
|
320
|
+
else:
|
|
321
|
+
print(f'设备{self.addr} 固件更新失败')
|
|
322
|
+
return result
|
|
323
|
+
|
|
324
|
+
def __init_system(self):
|
|
325
|
+
version = self.get('Version')
|
|
326
|
+
if isinstance(version, dict):
|
|
327
|
+
for key in version:
|
|
328
|
+
key: str
|
|
329
|
+
if key.endswith('version'):
|
|
330
|
+
version = version[key][1:].split('-')[0]
|
|
331
|
+
version = tuple(int(v) for v in version.split('.'))
|
|
332
|
+
break
|
|
333
|
+
else:
|
|
334
|
+
version = (0, 0, 0)
|
|
335
|
+
self.backend_version = version
|
|
336
|
+
if version >= (1, 2, 7):
|
|
337
|
+
self.set('InitSystem')
|
|
338
|
+
return True
|
|
339
|
+
else:
|
|
340
|
+
return self.__exec_command('初始化')
|
|
341
|
+
|
|
342
|
+
def __exec_command(self, button_name: str,
|
|
343
|
+
need_feedback=True, file_name=None, check_feedback=True,
|
|
344
|
+
callback=lambda *args: True, wait: int = 0):
|
|
345
|
+
flag = self.handle.execute_command(button_name, need_feedback, file_name, check_feedback)
|
|
346
|
+
if not flag:
|
|
347
|
+
print(f'设备{self.addr}-指令{button_name}执行失败')
|
|
348
|
+
return flag
|
|
349
|
+
|
|
350
|
+
def _get_trace_data(self, channel):
|
|
351
|
+
res = self.get('ShmPath', channel)
|
|
352
|
+
if not res:
|
|
353
|
+
return
|
|
354
|
+
_path, chnl, chnl_num, shots, points = res
|
|
355
|
+
shm = shared_memory.SharedMemory(name=_path, create=False)
|
|
356
|
+
data = np.frombuffer(shm.buf, dtype=np.int16).reshape((chnl_num, shots, points))
|
|
357
|
+
return data[chnl], data
|
|
358
|
+
|
|
359
|
+
def _connect(self, addr=None, port=5001, timeout=None):
|
|
360
|
+
"""
|
|
361
|
+
获取到指定ip的tcp连接
|
|
362
|
+
|
|
363
|
+
:param addr:
|
|
364
|
+
:param port:
|
|
365
|
+
:return:
|
|
366
|
+
"""
|
|
367
|
+
timeout = self.timeout if timeout is None else timeout
|
|
368
|
+
addr = self.addr if addr is None else addr
|
|
369
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
370
|
+
sock.settimeout(timeout+1)
|
|
371
|
+
sock.connect((addr, port))
|
|
372
|
+
return sock
|
|
373
|
+
|
|
374
|
+
def _show_system_status(self):
|
|
375
|
+
keys = ['device_type', 'backend_version', 'ad_num', 'da_num', 'cpu_temp', 'memory_use']
|
|
376
|
+
if self.backend_version >= (2, 1, 0):
|
|
377
|
+
status: dict = self.get("Status")
|
|
378
|
+
else:
|
|
379
|
+
status: dict = self.handle.get_all_status(False)
|
|
380
|
+
_string = [f'*********设备{self.addr}开启成功*********']
|
|
381
|
+
for key in keys:
|
|
382
|
+
_string.append(f'{key}: {status.get(key, "nan")}')
|
|
383
|
+
print('\n'.join(_string))
|
|
384
|
+
if self.backend_version >= (2, 0, 1):
|
|
385
|
+
print('available chnl: ')
|
|
386
|
+
print(self.get('ChnlInfo'))
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
class RPCFaultPack:
|
|
390
|
+
split_flag = '|+*+-*-+*+|*-*|'
|
|
391
|
+
|
|
392
|
+
class FaultType(str, enum.Enum):
|
|
393
|
+
EXCEPTION = 'exception'
|
|
394
|
+
WARNING = 'warning'
|
|
395
|
+
INFO = 'info'
|
|
396
|
+
|
|
397
|
+
def __init__(self, _type: str, name: str, message: str):
|
|
398
|
+
self.type: RPCFaultPack.FaultType = self.FaultType(_type)
|
|
399
|
+
self.name = name
|
|
400
|
+
self.message = message
|
|
401
|
+
|
|
402
|
+
@classmethod
|
|
403
|
+
def from_string(cls, string: str):
|
|
404
|
+
self = cls(cls.FaultType.INFO, '', '')
|
|
405
|
+
self.string = string
|
|
406
|
+
return self
|
|
407
|
+
|
|
408
|
+
@classmethod
|
|
409
|
+
def from_fault(cls, fault: xmlrpc.client.Fault):
|
|
410
|
+
return cls.from_string(fault.faultString)
|
|
411
|
+
|
|
412
|
+
@classmethod
|
|
413
|
+
def from_exception(cls, exc: Exception, limit=0):
|
|
414
|
+
message = traceback.format_exception(exc, limit=limit)
|
|
415
|
+
return cls(cls.FaultType.EXCEPTION, exc.__class__.__name__, ''.join(message))
|
|
416
|
+
|
|
417
|
+
@classmethod
|
|
418
|
+
def from_warning(cls, warns: "list[warnings.WarningMessage]"):
|
|
419
|
+
warn = [str(warn.category.__name__) for warn in warns]
|
|
420
|
+
warn = str(warn[0]) if len(warn) == 1 else str(warn)
|
|
421
|
+
messages = [str(warn.message) for warn in warns]
|
|
422
|
+
return cls(cls.FaultType.WARNING, warn, '\n'.join(messages))
|
|
423
|
+
|
|
424
|
+
@property
|
|
425
|
+
def string(self):
|
|
426
|
+
return self.split_flag.join([self.type, self.name, self.message])
|
|
427
|
+
|
|
428
|
+
@string.setter
|
|
429
|
+
def string(self, value: str):
|
|
430
|
+
_p = value.split(self.split_flag)
|
|
431
|
+
if len(_p) == 1:
|
|
432
|
+
_p = (self.FaultType.INFO, 'Default', _p[0])
|
|
433
|
+
elif len(_p) == 2:
|
|
434
|
+
_p = (self.FaultType.INFO, _p[0], _p[1])
|
|
435
|
+
else:
|
|
436
|
+
_p = _p[:3]
|
|
437
|
+
self.type, self.name, self.message = _p
|
|
438
|
+
|
|
439
|
+
def __str__(self):
|
|
440
|
+
return self.string
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
class FastRPC:
|
|
444
|
+
def __init__(self, address, timeout):
|
|
445
|
+
self.addr = address
|
|
446
|
+
self.timeout = timeout
|
|
447
|
+
|
|
448
|
+
def connect(self):
|
|
449
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
450
|
+
sock.connect((self.addr, 10800))
|
|
451
|
+
sock.settimeout(self.timeout+1)
|
|
452
|
+
return sock
|
|
453
|
+
|
|
454
|
+
def rpc_set(self, *param):
|
|
455
|
+
sock = self.connect()
|
|
456
|
+
a = pickle.dumps(param)
|
|
457
|
+
head = struct.pack('=IIII', *[0x5F5F5F5F, 0x32000001, 0, 16 + len(a)])
|
|
458
|
+
sock.sendall(head)
|
|
459
|
+
sock.sendall(a)
|
|
460
|
+
head = struct.unpack("=IIIII", sock.recv(20))
|
|
461
|
+
# print(head)
|
|
462
|
+
data = sock.recv(head[3] - 20)
|
|
463
|
+
data = pickle.loads(data)
|
|
464
|
+
if head[4]:
|
|
465
|
+
print(data)
|
|
466
|
+
return False
|
|
467
|
+
sock.close()
|
|
468
|
+
return data
|
|
469
|
+
|
|
470
|
+
def rpc_get(self, *param):
|
|
471
|
+
sock = self.connect()
|
|
472
|
+
a = pickle.dumps(param)
|
|
473
|
+
head = struct.pack('=IIII', *[0x5F5F5F5F, 0x32000002, 0, 16 + len(a)])
|
|
474
|
+
sock.sendall(head)
|
|
475
|
+
sock.sendall(a)
|
|
476
|
+
head = struct.unpack("=IIIII", sock.recv(20))
|
|
477
|
+
length = head[3] - 20
|
|
478
|
+
data = []
|
|
479
|
+
while length > 0:
|
|
480
|
+
_data = sock.recv(length)
|
|
481
|
+
length -= len(_data)
|
|
482
|
+
data.append(_data)
|
|
483
|
+
data = pickle.loads(b''.join(data))
|
|
484
|
+
if head[4]:
|
|
485
|
+
raise xmlrpc.client.Fault(400, data)
|
|
486
|
+
sock.close()
|
|
487
|
+
return data
|
|
488
|
+
|
|
489
|
+
def debug_param(self, *param):
|
|
490
|
+
sock = self.connect()
|
|
491
|
+
a = pickle.dumps(param)
|
|
492
|
+
head = struct.pack('=IIII', *[0x5F5F5F5F, 0x32000003, 0, 16 + len(a)])
|
|
493
|
+
sock.sendall(head)
|
|
494
|
+
sock.sendall(a)
|
|
495
|
+
head = struct.unpack("=IIIII", sock.recv(20))
|
|
496
|
+
length = head[3] - 20
|
|
497
|
+
data = []
|
|
498
|
+
while length > 0:
|
|
499
|
+
_data = sock.recv(length)
|
|
500
|
+
length -= len(_data)
|
|
501
|
+
data.append(_data)
|
|
502
|
+
data = pickle.loads(b''.join(data))
|
|
503
|
+
if head[4]:
|
|
504
|
+
print(data)
|
|
505
|
+
return False
|
|
506
|
+
sock.close()
|
|
507
|
+
return data
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
class RPCValueParser:
|
|
511
|
+
"""
|
|
512
|
+
rpc调用格式化工具集
|
|
513
|
+
|
|
514
|
+
"""
|
|
515
|
+
dump_tag_waveform = 'waveform.Waveforms'
|
|
516
|
+
dump_tag_ndarray = 'numpy.ndarray'
|
|
517
|
+
dump_tag_complex = 'complex'
|
|
518
|
+
|
|
519
|
+
@staticmethod
|
|
520
|
+
def dump(value):
|
|
521
|
+
if isinstance(value, np.ndarray):
|
|
522
|
+
value = [RPCValueParser.dump_tag_ndarray, value.tobytes(), str(value.dtype), value.shape]
|
|
523
|
+
elif isinstance(value, float):
|
|
524
|
+
value = float(value)
|
|
525
|
+
elif isinstance(value, int):
|
|
526
|
+
value = int(value)
|
|
527
|
+
elif isinstance(value, np.uint):
|
|
528
|
+
value = int(value)
|
|
529
|
+
elif isinstance(value, complex):
|
|
530
|
+
value = [RPCValueParser.dump_tag_complex, value.real, value.imag]
|
|
531
|
+
elif HAS_WAVEFORMS and isinstance(value, waveforms.Waveform):
|
|
532
|
+
value = [RPCValueParser.dump_tag_waveform, pickle.dumps(value)]
|
|
533
|
+
elif isinstance(value, (list, tuple)):
|
|
534
|
+
value = [RPCValueParser.dump(_v) for _v in value]
|
|
535
|
+
|
|
536
|
+
return value
|
|
537
|
+
|
|
538
|
+
@staticmethod
|
|
539
|
+
def load(value):
|
|
540
|
+
if isinstance(value, list) and len(value) >= 2:
|
|
541
|
+
if value[0] == RPCValueParser.dump_tag_ndarray:
|
|
542
|
+
data = np.frombuffer(value[1], dtype=value[2])
|
|
543
|
+
value = data.reshape(value[3])
|
|
544
|
+
# elif: value[0] == 'numpy.float'
|
|
545
|
+
elif value[0] == RPCValueParser.dump_tag_waveform:
|
|
546
|
+
value = pickle.loads(value[1])
|
|
547
|
+
elif value[0] == RPCValueParser.dump_tag_complex:
|
|
548
|
+
value = complex(value[1], value[2])
|
|
549
|
+
else:
|
|
550
|
+
value = [RPCValueParser.load(_v) for _v in value]
|
|
551
|
+
elif isinstance(value, (list, tuple)):
|
|
552
|
+
value = [RPCValueParser.load(_v) for _v in value]
|
|
553
|
+
return value
|
|
554
|
+
|
|
555
|
+
class InfoSharedList:
|
|
556
|
+
memory_name = 'NS_DEVICE_MEMORY'
|
|
557
|
+
memory_size = 1024 ** 2
|
|
558
|
+
head_size = 32 # memory中前head_size的长度为头部预留信息
|
|
559
|
+
def __init__(self):
|
|
560
|
+
try:
|
|
561
|
+
self._memory = shared_memory.SharedMemory(name=self.memory_name, create=True, size=self.memory_size)
|
|
562
|
+
except FileExistsError:
|
|
563
|
+
self._memory = shared_memory.SharedMemory(name=self.memory_name, create=False, size=self.memory_size)
|
|
564
|
+
|
|
565
|
+
def clear_ip(self):
|
|
566
|
+
_exit_pkl = pickle.dumps(self.ip)
|
|
567
|
+
self._memory.buf[self.head_size:len(_exit_pkl) + self.head_size] = b'\x00' * len(_exit_pkl)
|
|
568
|
+
|
|
569
|
+
@property
|
|
570
|
+
def ip(self):
|
|
571
|
+
try:
|
|
572
|
+
return pickle.loads(self._memory.buf[self.head_size:])
|
|
573
|
+
except pickle.UnpicklingError:
|
|
574
|
+
return []
|
|
575
|
+
|
|
576
|
+
@ip.setter
|
|
577
|
+
def ip(self, value):
|
|
578
|
+
ips = self.ip
|
|
579
|
+
ips.append(value)
|
|
580
|
+
ips = list(set(ips))
|
|
581
|
+
_pkl = pickle.dumps(ips)
|
|
582
|
+
self._memory.buf[self.head_size:len(_pkl) + self.head_size] = _pkl
|
|
583
|
+
|
|
584
|
+
def close(self):
|
|
585
|
+
self._memory.close()
|
|
586
|
+
|
|
587
|
+
def unlink(self):
|
|
588
|
+
try:
|
|
589
|
+
self._memory.unlink()
|
|
590
|
+
except FileNotFoundError as e:
|
|
591
|
+
pass
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
SHARED_DEVICE_MEM = InfoSharedList()
|