remoteRF-server 1.0.6__tar.gz → 1.0.8__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.
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/PKG-INFO +5 -5
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/README.md +4 -4
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/pyproject.toml +1 -1
- {remoterf_server-1.0.6/src/remoteRF_server/drivers/adalm_pluto → remoterf_server-1.0.8/src/remoteRF_server/common/idl}/pluto_schema.py +128 -5
- {remoterf_server-1.0.6/src/remoteRF_server/common/idl → remoterf_server-1.0.8/src/remoteRF_server/drivers/adalm_pluto}/pluto_schema.py +128 -5
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/usrp/usrp_schema.py +49 -4
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/device_manager.py +69 -3
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/serverrf_cli.py +7 -2
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server.egg-info/PKG-INFO +5 -5
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_default_usrp_schema.py +50 -1
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_dynamic_v2.py +7 -3
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_idl_schema.py +47 -2
- remoterf_server-1.0.8/tests/test_pluto_compat.py +221 -0
- remoterf_server-1.0.6/tests/test_pluto_compat.py +0 -99
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/setup.cfg +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/grpc/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/grpc/v2_codec.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/idl/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/idl/device_schema.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/idl/pluto_mimo_schema.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/idl/schema.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/idl/v2.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/utils/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/utils/api_token.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/utils/db_connection.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/utils/db_location.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/utils/list_string.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/common/utils/process_arg.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/adalm_pluto/pluto_mimo_schema.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/usrp/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/usrp/policy.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/usrp/uhd_manifest.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/host/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/host/host_auth_token.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/host/host_directory_store.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/host/host_tunnel_server.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/acc_perms.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/cert_provider.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/dynamic_v2.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/grpc_server.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/reservation.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/rpc_manager.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/user_group_cli.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/user_group_handler.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/v2_errors.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/tools/__init__.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/tools/gen_certs.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/tools/gist_status.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/tools/gist_status_testing.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/tools/introspect_uhd.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server.egg-info/SOURCES.txt +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server.egg-info/dependency_links.txt +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server.egg-info/entry_points.txt +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server.egg-info/requires.txt +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server.egg-info/top_level.txt +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_cert_provider.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_process_arg.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_reservation_timestamps.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_rpc_manager_calln.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_usrp_client_server_hardware.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_usrp_client_server_localhost.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_usrp_remoterf_rx_hardware.py +0 -0
- {remoterf_server-1.0.6 → remoterf_server-1.0.8}/tests/test_usrp_uhd410_hardware.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: remoteRF-server
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
4
4
|
Summary: RemoteRF server-side control package
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -334,13 +334,13 @@ separate policy file. This includes transmit controls, transmit streaming,
|
|
|
334
334
|
GPIO/register methods, and property-tree writes. `usrp_policy.yml` is not read
|
|
335
335
|
or required by the current server.
|
|
336
336
|
|
|
337
|
-
RemoteRF
|
|
337
|
+
RemoteRF forces `UHD_LOG_CONSOLE_LEVEL=off` before importing UHD so native UHD
|
|
338
338
|
messages do not overwrite the interactive `serverrf` prompt. To temporarily
|
|
339
|
-
restore UHD diagnostics, set
|
|
340
|
-
before starting the server:
|
|
339
|
+
restore UHD diagnostics, explicitly set `REMOTERF_UHD_CONSOLE_LEVEL` to a level
|
|
340
|
+
such as `warning`, `info`, or `debug` before starting the server:
|
|
341
341
|
|
|
342
342
|
```bash
|
|
343
|
-
|
|
343
|
+
REMOTERF_UHD_CONSOLE_LEVEL=warning serverrf -s
|
|
344
344
|
```
|
|
345
345
|
|
|
346
346
|
On every qualified target, generate the introspection record and enforce the
|
|
@@ -319,13 +319,13 @@ separate policy file. This includes transmit controls, transmit streaming,
|
|
|
319
319
|
GPIO/register methods, and property-tree writes. `usrp_policy.yml` is not read
|
|
320
320
|
or required by the current server.
|
|
321
321
|
|
|
322
|
-
RemoteRF
|
|
322
|
+
RemoteRF forces `UHD_LOG_CONSOLE_LEVEL=off` before importing UHD so native UHD
|
|
323
323
|
messages do not overwrite the interactive `serverrf` prompt. To temporarily
|
|
324
|
-
restore UHD diagnostics, set
|
|
325
|
-
before starting the server:
|
|
324
|
+
restore UHD diagnostics, explicitly set `REMOTERF_UHD_CONSOLE_LEVEL` to a level
|
|
325
|
+
such as `warning`, `info`, or `debug` before starting the server:
|
|
326
326
|
|
|
327
327
|
```bash
|
|
328
|
-
|
|
328
|
+
REMOTERF_UHD_CONSOLE_LEVEL=warning serverrf -s
|
|
329
329
|
```
|
|
330
330
|
|
|
331
331
|
On every qualified target, generate the introspection record and enforce the
|
|
@@ -8,6 +8,26 @@ import subprocess
|
|
|
8
8
|
import re
|
|
9
9
|
import adi
|
|
10
10
|
|
|
11
|
+
|
|
12
|
+
def _normalize_channels(value):
|
|
13
|
+
"""Restore channel lists after numeric lists cross the legacy RPC codec."""
|
|
14
|
+
if hasattr(value, "tolist"):
|
|
15
|
+
value = value.tolist()
|
|
16
|
+
if isinstance(value, tuple):
|
|
17
|
+
value = list(value)
|
|
18
|
+
if not isinstance(value, list):
|
|
19
|
+
return value
|
|
20
|
+
|
|
21
|
+
channels = []
|
|
22
|
+
for channel in value:
|
|
23
|
+
if not isinstance(channel, str):
|
|
24
|
+
integer = int(channel)
|
|
25
|
+
if channel == integer:
|
|
26
|
+
channel = integer
|
|
27
|
+
channels.append(channel)
|
|
28
|
+
return channels
|
|
29
|
+
|
|
30
|
+
|
|
11
31
|
# == PLUTO Connection Logic ==
|
|
12
32
|
|
|
13
33
|
def connect_pluto(*, serial: str):
|
|
@@ -50,7 +70,7 @@ class PlutoSchema(DeviceSchema):
|
|
|
50
70
|
|
|
51
71
|
device_type = "adalm_pluto"
|
|
52
72
|
client_class = "Pluto"
|
|
53
|
-
driver_version = "0.0.
|
|
73
|
+
driver_version = "0.0.2"
|
|
54
74
|
|
|
55
75
|
@staticmethod
|
|
56
76
|
def make_device(**kwargs):
|
|
@@ -85,13 +105,13 @@ class PlutoSchema(DeviceSchema):
|
|
|
85
105
|
|
|
86
106
|
@idl_expose(kind="get")
|
|
87
107
|
def get_rx_hardwaregain_chan0(self):
|
|
88
|
-
"""RX hardware gain (dB). pyadi-iio attribute:
|
|
89
|
-
return self.device.
|
|
108
|
+
"""RX hardware gain (dB). pyadi-iio attribute: rx_hardwaregain_chan0"""
|
|
109
|
+
return self.device.rx_hardwaregain_chan0
|
|
90
110
|
|
|
91
111
|
@idl_expose(kind="set")
|
|
92
112
|
def set_rx_hardwaregain_chan0(self, value):
|
|
93
|
-
"""RX hardware gain (dB). pyadi-iio attribute:
|
|
94
|
-
self.device.
|
|
113
|
+
"""RX hardware gain (dB). pyadi-iio attribute: rx_hardwaregain_chan0"""
|
|
114
|
+
self.device.rx_hardwaregain_chan0 = value
|
|
95
115
|
|
|
96
116
|
@idl_expose(kind="get")
|
|
97
117
|
def get_tx_hardwaregain_chan0(self):
|
|
@@ -180,6 +200,109 @@ class PlutoSchema(DeviceSchema):
|
|
|
180
200
|
"""Disable the internal DDS tone generator."""
|
|
181
201
|
self.device.disable_dds()
|
|
182
202
|
|
|
203
|
+
# region DDS
|
|
204
|
+
|
|
205
|
+
@idl_expose(kind="call")
|
|
206
|
+
def call_dds_single_tone(self, frequency, scale, channel=0):
|
|
207
|
+
"""Generate one complex DDS tone on the selected TX channel."""
|
|
208
|
+
self.device.dds_single_tone(frequency, scale, channel)
|
|
209
|
+
|
|
210
|
+
@idl_expose(kind="call")
|
|
211
|
+
def call_dds_dual_tone(
|
|
212
|
+
self,
|
|
213
|
+
frequency1,
|
|
214
|
+
scale1,
|
|
215
|
+
frequency2,
|
|
216
|
+
scale2,
|
|
217
|
+
channel=0,
|
|
218
|
+
):
|
|
219
|
+
"""Generate two complex DDS tones on the selected TX channel."""
|
|
220
|
+
self.device.dds_dual_tone(
|
|
221
|
+
frequency1,
|
|
222
|
+
scale1,
|
|
223
|
+
frequency2,
|
|
224
|
+
scale2,
|
|
225
|
+
channel,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
@idl_expose(kind="get")
|
|
229
|
+
def get_dds_frequencies(self):
|
|
230
|
+
return self.device.dds_frequencies
|
|
231
|
+
|
|
232
|
+
@idl_expose(kind="set")
|
|
233
|
+
def set_dds_frequencies(self, value):
|
|
234
|
+
self.device.dds_frequencies = value
|
|
235
|
+
|
|
236
|
+
@idl_expose(kind="get")
|
|
237
|
+
def get_dds_scales(self):
|
|
238
|
+
return self.device.dds_scales
|
|
239
|
+
|
|
240
|
+
@idl_expose(kind="set")
|
|
241
|
+
def set_dds_scales(self, value):
|
|
242
|
+
self.device.dds_scales = value
|
|
243
|
+
|
|
244
|
+
@idl_expose(kind="get")
|
|
245
|
+
def get_dds_phases(self):
|
|
246
|
+
return self.device.dds_phases
|
|
247
|
+
|
|
248
|
+
@idl_expose(kind="set")
|
|
249
|
+
def set_dds_phases(self, value):
|
|
250
|
+
self.device.dds_phases = value
|
|
251
|
+
|
|
252
|
+
@idl_expose(kind="get")
|
|
253
|
+
def get_dds_enabled(self):
|
|
254
|
+
return self.device.dds_enabled
|
|
255
|
+
|
|
256
|
+
@idl_expose(kind="set")
|
|
257
|
+
def set_dds_enabled(self, value):
|
|
258
|
+
self.device.dds_enabled = value
|
|
259
|
+
|
|
260
|
+
# endregion
|
|
261
|
+
|
|
262
|
+
# region channel configuration
|
|
263
|
+
|
|
264
|
+
@idl_expose(kind="get")
|
|
265
|
+
def get_rx_enabled_channels(self):
|
|
266
|
+
return self.device.rx_enabled_channels
|
|
267
|
+
|
|
268
|
+
@idl_expose(kind="set")
|
|
269
|
+
def set_rx_enabled_channels(self, value):
|
|
270
|
+
self.device.rx_enabled_channels = _normalize_channels(value)
|
|
271
|
+
|
|
272
|
+
@idl_expose(kind="get")
|
|
273
|
+
def get_tx_enabled_channels(self):
|
|
274
|
+
return self.device.tx_enabled_channels
|
|
275
|
+
|
|
276
|
+
@idl_expose(kind="set")
|
|
277
|
+
def set_tx_enabled_channels(self, value):
|
|
278
|
+
self.device.tx_enabled_channels = _normalize_channels(value)
|
|
279
|
+
|
|
280
|
+
@idl_expose(kind="get")
|
|
281
|
+
def get_rx_annotated(self):
|
|
282
|
+
return self.device.rx_annotated
|
|
283
|
+
|
|
284
|
+
@idl_expose(kind="set")
|
|
285
|
+
def set_rx_annotated(self, value):
|
|
286
|
+
self.device.rx_annotated = value
|
|
287
|
+
|
|
288
|
+
@idl_expose(kind="get")
|
|
289
|
+
def get_rx_output_type(self):
|
|
290
|
+
return self.device.rx_output_type
|
|
291
|
+
|
|
292
|
+
@idl_expose(kind="set")
|
|
293
|
+
def set_rx_output_type(self, value):
|
|
294
|
+
self.device.rx_output_type = value
|
|
295
|
+
|
|
296
|
+
@idl_expose(kind="get")
|
|
297
|
+
def get_rx_channel_names(self):
|
|
298
|
+
return self.device.rx_channel_names
|
|
299
|
+
|
|
300
|
+
@idl_expose(kind="get")
|
|
301
|
+
def get_tx_channel_names(self):
|
|
302
|
+
return self.device.tx_channel_names
|
|
303
|
+
|
|
304
|
+
# endregion
|
|
305
|
+
|
|
183
306
|
# endregion
|
|
184
307
|
|
|
185
308
|
# region ip / repr
|
|
@@ -8,6 +8,26 @@ import subprocess
|
|
|
8
8
|
import re
|
|
9
9
|
import adi
|
|
10
10
|
|
|
11
|
+
|
|
12
|
+
def _normalize_channels(value):
|
|
13
|
+
"""Restore channel lists after numeric lists cross the legacy RPC codec."""
|
|
14
|
+
if hasattr(value, "tolist"):
|
|
15
|
+
value = value.tolist()
|
|
16
|
+
if isinstance(value, tuple):
|
|
17
|
+
value = list(value)
|
|
18
|
+
if not isinstance(value, list):
|
|
19
|
+
return value
|
|
20
|
+
|
|
21
|
+
channels = []
|
|
22
|
+
for channel in value:
|
|
23
|
+
if not isinstance(channel, str):
|
|
24
|
+
integer = int(channel)
|
|
25
|
+
if channel == integer:
|
|
26
|
+
channel = integer
|
|
27
|
+
channels.append(channel)
|
|
28
|
+
return channels
|
|
29
|
+
|
|
30
|
+
|
|
11
31
|
# == PLUTO Connection Logic ==
|
|
12
32
|
|
|
13
33
|
def connect_pluto(*, serial: str):
|
|
@@ -50,7 +70,7 @@ class PlutoSchema(DeviceSchema):
|
|
|
50
70
|
|
|
51
71
|
device_type = "adalm_pluto"
|
|
52
72
|
client_class = "Pluto"
|
|
53
|
-
driver_version = "0.0.
|
|
73
|
+
driver_version = "0.0.2"
|
|
54
74
|
|
|
55
75
|
@staticmethod
|
|
56
76
|
def make_device(**kwargs):
|
|
@@ -85,13 +105,13 @@ class PlutoSchema(DeviceSchema):
|
|
|
85
105
|
|
|
86
106
|
@idl_expose(kind="get")
|
|
87
107
|
def get_rx_hardwaregain_chan0(self):
|
|
88
|
-
"""RX hardware gain (dB). pyadi-iio attribute:
|
|
89
|
-
return self.device.
|
|
108
|
+
"""RX hardware gain (dB). pyadi-iio attribute: rx_hardwaregain_chan0"""
|
|
109
|
+
return self.device.rx_hardwaregain_chan0
|
|
90
110
|
|
|
91
111
|
@idl_expose(kind="set")
|
|
92
112
|
def set_rx_hardwaregain_chan0(self, value):
|
|
93
|
-
"""RX hardware gain (dB). pyadi-iio attribute:
|
|
94
|
-
self.device.
|
|
113
|
+
"""RX hardware gain (dB). pyadi-iio attribute: rx_hardwaregain_chan0"""
|
|
114
|
+
self.device.rx_hardwaregain_chan0 = value
|
|
95
115
|
|
|
96
116
|
@idl_expose(kind="get")
|
|
97
117
|
def get_tx_hardwaregain_chan0(self):
|
|
@@ -180,6 +200,109 @@ class PlutoSchema(DeviceSchema):
|
|
|
180
200
|
"""Disable the internal DDS tone generator."""
|
|
181
201
|
self.device.disable_dds()
|
|
182
202
|
|
|
203
|
+
# region DDS
|
|
204
|
+
|
|
205
|
+
@idl_expose(kind="call")
|
|
206
|
+
def call_dds_single_tone(self, frequency, scale, channel=0):
|
|
207
|
+
"""Generate one complex DDS tone on the selected TX channel."""
|
|
208
|
+
self.device.dds_single_tone(frequency, scale, channel)
|
|
209
|
+
|
|
210
|
+
@idl_expose(kind="call")
|
|
211
|
+
def call_dds_dual_tone(
|
|
212
|
+
self,
|
|
213
|
+
frequency1,
|
|
214
|
+
scale1,
|
|
215
|
+
frequency2,
|
|
216
|
+
scale2,
|
|
217
|
+
channel=0,
|
|
218
|
+
):
|
|
219
|
+
"""Generate two complex DDS tones on the selected TX channel."""
|
|
220
|
+
self.device.dds_dual_tone(
|
|
221
|
+
frequency1,
|
|
222
|
+
scale1,
|
|
223
|
+
frequency2,
|
|
224
|
+
scale2,
|
|
225
|
+
channel,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
@idl_expose(kind="get")
|
|
229
|
+
def get_dds_frequencies(self):
|
|
230
|
+
return self.device.dds_frequencies
|
|
231
|
+
|
|
232
|
+
@idl_expose(kind="set")
|
|
233
|
+
def set_dds_frequencies(self, value):
|
|
234
|
+
self.device.dds_frequencies = value
|
|
235
|
+
|
|
236
|
+
@idl_expose(kind="get")
|
|
237
|
+
def get_dds_scales(self):
|
|
238
|
+
return self.device.dds_scales
|
|
239
|
+
|
|
240
|
+
@idl_expose(kind="set")
|
|
241
|
+
def set_dds_scales(self, value):
|
|
242
|
+
self.device.dds_scales = value
|
|
243
|
+
|
|
244
|
+
@idl_expose(kind="get")
|
|
245
|
+
def get_dds_phases(self):
|
|
246
|
+
return self.device.dds_phases
|
|
247
|
+
|
|
248
|
+
@idl_expose(kind="set")
|
|
249
|
+
def set_dds_phases(self, value):
|
|
250
|
+
self.device.dds_phases = value
|
|
251
|
+
|
|
252
|
+
@idl_expose(kind="get")
|
|
253
|
+
def get_dds_enabled(self):
|
|
254
|
+
return self.device.dds_enabled
|
|
255
|
+
|
|
256
|
+
@idl_expose(kind="set")
|
|
257
|
+
def set_dds_enabled(self, value):
|
|
258
|
+
self.device.dds_enabled = value
|
|
259
|
+
|
|
260
|
+
# endregion
|
|
261
|
+
|
|
262
|
+
# region channel configuration
|
|
263
|
+
|
|
264
|
+
@idl_expose(kind="get")
|
|
265
|
+
def get_rx_enabled_channels(self):
|
|
266
|
+
return self.device.rx_enabled_channels
|
|
267
|
+
|
|
268
|
+
@idl_expose(kind="set")
|
|
269
|
+
def set_rx_enabled_channels(self, value):
|
|
270
|
+
self.device.rx_enabled_channels = _normalize_channels(value)
|
|
271
|
+
|
|
272
|
+
@idl_expose(kind="get")
|
|
273
|
+
def get_tx_enabled_channels(self):
|
|
274
|
+
return self.device.tx_enabled_channels
|
|
275
|
+
|
|
276
|
+
@idl_expose(kind="set")
|
|
277
|
+
def set_tx_enabled_channels(self, value):
|
|
278
|
+
self.device.tx_enabled_channels = _normalize_channels(value)
|
|
279
|
+
|
|
280
|
+
@idl_expose(kind="get")
|
|
281
|
+
def get_rx_annotated(self):
|
|
282
|
+
return self.device.rx_annotated
|
|
283
|
+
|
|
284
|
+
@idl_expose(kind="set")
|
|
285
|
+
def set_rx_annotated(self, value):
|
|
286
|
+
self.device.rx_annotated = value
|
|
287
|
+
|
|
288
|
+
@idl_expose(kind="get")
|
|
289
|
+
def get_rx_output_type(self):
|
|
290
|
+
return self.device.rx_output_type
|
|
291
|
+
|
|
292
|
+
@idl_expose(kind="set")
|
|
293
|
+
def set_rx_output_type(self, value):
|
|
294
|
+
self.device.rx_output_type = value
|
|
295
|
+
|
|
296
|
+
@idl_expose(kind="get")
|
|
297
|
+
def get_rx_channel_names(self):
|
|
298
|
+
return self.device.rx_channel_names
|
|
299
|
+
|
|
300
|
+
@idl_expose(kind="get")
|
|
301
|
+
def get_tx_channel_names(self):
|
|
302
|
+
return self.device.tx_channel_names
|
|
303
|
+
|
|
304
|
+
# endregion
|
|
305
|
+
|
|
183
306
|
# endregion
|
|
184
307
|
|
|
185
308
|
# region ip / repr
|
{remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/drivers/usrp/usrp_schema.py
RENAMED
|
@@ -11,7 +11,10 @@ import os
|
|
|
11
11
|
|
|
12
12
|
def _configure_uhd_console_logging():
|
|
13
13
|
"""Keep native UHD logs out of the interactive server console by default."""
|
|
14
|
-
os.environ
|
|
14
|
+
os.environ["UHD_LOG_CONSOLE_LEVEL"] = os.getenv(
|
|
15
|
+
"REMOTERF_UHD_CONSOLE_LEVEL",
|
|
16
|
+
"off",
|
|
17
|
+
)
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
_configure_uhd_console_logging()
|
|
@@ -95,6 +98,31 @@ def _payload_type(value):
|
|
|
95
98
|
return None
|
|
96
99
|
|
|
97
100
|
|
|
101
|
+
def _tune_request_policy(value, current):
|
|
102
|
+
"""Translate a portable policy name back to UHD's native enum value."""
|
|
103
|
+
if not isinstance(value, str):
|
|
104
|
+
return value
|
|
105
|
+
name = value.rsplit(".", 1)[-1].upper()
|
|
106
|
+
policy_types = (
|
|
107
|
+
type(current),
|
|
108
|
+
getattr(getattr(uhd, "types", None), "TuneRequestPolicy", None),
|
|
109
|
+
getattr(getattr(uhd, "types", None), "tune_request_policy", None),
|
|
110
|
+
getattr(
|
|
111
|
+
getattr(getattr(uhd, "libpyuhd", None), "types", None),
|
|
112
|
+
"tune_request_policy",
|
|
113
|
+
None,
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
for policy_type in policy_types:
|
|
117
|
+
if policy_type is None:
|
|
118
|
+
continue
|
|
119
|
+
for candidate in (name, name.lower(), f"POLICY_{name}"):
|
|
120
|
+
native = getattr(policy_type, candidate, None)
|
|
121
|
+
if native is not None:
|
|
122
|
+
return native
|
|
123
|
+
return value
|
|
124
|
+
|
|
125
|
+
|
|
98
126
|
def _require_dict(value, method):
|
|
99
127
|
if not isinstance(value, dict):
|
|
100
128
|
raise TypeError(
|
|
@@ -156,7 +184,16 @@ def _construct(value):
|
|
|
156
184
|
return uhd.usrp.SubdevSpec(value["spec"])
|
|
157
185
|
|
|
158
186
|
if kind == "TuneRequest":
|
|
159
|
-
|
|
187
|
+
# Older generated clients used ``args`` for constructor arguments.
|
|
188
|
+
# Current TuneRequest snapshots use that same key for UHD's DeviceAddr
|
|
189
|
+
# field, so only sequences may be interpreted as constructor arguments.
|
|
190
|
+
raw_args = value.get("args", ())
|
|
191
|
+
legacy_constructor_args = isinstance(raw_args, (list, tuple))
|
|
192
|
+
args = (
|
|
193
|
+
[_construct(item) for item in raw_args]
|
|
194
|
+
if legacy_constructor_args
|
|
195
|
+
else []
|
|
196
|
+
)
|
|
160
197
|
kwargs = {
|
|
161
198
|
key: _construct(item)
|
|
162
199
|
for key, item in value.get("kwargs", {}).items()
|
|
@@ -171,10 +208,18 @@ def _construct(value):
|
|
|
171
208
|
obj = constructor(*args, **kwargs)
|
|
172
209
|
for field in (
|
|
173
210
|
"rf_freq", "dsp_freq", "rf_freq_policy", "dsp_freq_policy",
|
|
174
|
-
"
|
|
211
|
+
"args",
|
|
175
212
|
):
|
|
213
|
+
if field == "args" and legacy_constructor_args:
|
|
214
|
+
continue
|
|
176
215
|
if field in value and hasattr(obj, field):
|
|
177
|
-
|
|
216
|
+
converted = _construct(value[field])
|
|
217
|
+
if field in {"rf_freq_policy", "dsp_freq_policy"}:
|
|
218
|
+
converted = _tune_request_policy(
|
|
219
|
+
converted,
|
|
220
|
+
getattr(obj, field),
|
|
221
|
+
)
|
|
222
|
+
setattr(obj, field, converted)
|
|
178
223
|
return obj
|
|
179
224
|
|
|
180
225
|
if kind == "DeviceAddr":
|
{remoterf_server-1.0.6 → remoterf_server-1.0.8}/src/remoteRF_server/server/device_manager.py
RENAMED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import os
|
|
6
6
|
import re
|
|
7
7
|
import shutil
|
|
8
|
+
import hashlib
|
|
8
9
|
import time
|
|
9
10
|
import yaml
|
|
10
11
|
import threading
|
|
@@ -419,10 +420,60 @@ def _driver_registers_type(path: Path, device_type: str) -> bool:
|
|
|
419
420
|
pattern = rf"(?:idl_register|register_driver)\(\s*['\"]{re.escape(device_type)}['\"]\s*\)"
|
|
420
421
|
return re.search(pattern, text) is not None
|
|
421
422
|
|
|
422
|
-
def
|
|
423
|
+
def _driver_sha256(path: Path) -> str:
|
|
424
|
+
digest = hashlib.sha256()
|
|
425
|
+
with path.open("rb") as handle:
|
|
426
|
+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
|
427
|
+
digest.update(chunk)
|
|
428
|
+
return digest.hexdigest()
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def _managed_driver_marker(target: Path) -> Path:
|
|
432
|
+
return target.with_name(f".{target.name}.remoterf-managed")
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def _refresh_managed_driver(
|
|
436
|
+
target: Path,
|
|
437
|
+
source: Path,
|
|
438
|
+
*,
|
|
439
|
+
legacy_hashes: tuple[str, ...] = (),
|
|
440
|
+
) -> bool:
|
|
441
|
+
"""Refresh an unmodified RemoteRF-managed schema and preserve user edits."""
|
|
442
|
+
marker = _managed_driver_marker(target)
|
|
443
|
+
try:
|
|
444
|
+
target_hash = _driver_sha256(target)
|
|
445
|
+
marker_hash = marker.read_text(encoding="utf-8").strip() if marker.exists() else ""
|
|
446
|
+
except OSError:
|
|
447
|
+
return False
|
|
448
|
+
|
|
449
|
+
if target_hash != marker_hash and target_hash not in legacy_hashes:
|
|
450
|
+
return False
|
|
451
|
+
|
|
452
|
+
try:
|
|
453
|
+
source_hash = _driver_sha256(source)
|
|
454
|
+
if target_hash != source_hash:
|
|
455
|
+
shutil.copy2(source, target)
|
|
456
|
+
marker.write_text(source_hash + "\n", encoding="utf-8")
|
|
457
|
+
except OSError:
|
|
458
|
+
return False
|
|
459
|
+
return True
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def _seed_default_driver(
|
|
463
|
+
filename: str,
|
|
464
|
+
*device_types: str,
|
|
465
|
+
legacy_hashes: tuple[str, ...] = (),
|
|
466
|
+
) -> None:
|
|
423
467
|
drivers_dir = get_drivers_dir()
|
|
424
468
|
target = drivers_dir / filename
|
|
469
|
+
source = _packaged_driver_schema_path(filename)
|
|
425
470
|
if target.exists() or target.is_symlink():
|
|
471
|
+
if target.is_file() and source.exists():
|
|
472
|
+
_refresh_managed_driver(
|
|
473
|
+
target,
|
|
474
|
+
source,
|
|
475
|
+
legacy_hashes=legacy_hashes,
|
|
476
|
+
)
|
|
426
477
|
return
|
|
427
478
|
|
|
428
479
|
try:
|
|
@@ -437,13 +488,16 @@ def _seed_default_driver(filename: str, *device_types: str) -> None:
|
|
|
437
488
|
if any(_driver_registers_type(driver_file, device_type) for device_type in device_types):
|
|
438
489
|
return
|
|
439
490
|
|
|
440
|
-
source = _packaged_driver_schema_path(filename)
|
|
441
491
|
if not source.exists():
|
|
442
492
|
print(f"Warning: default driver schema source is missing: {source}")
|
|
443
493
|
return
|
|
444
494
|
|
|
445
495
|
try:
|
|
446
496
|
shutil.copy2(source, target)
|
|
497
|
+
_managed_driver_marker(target).write_text(
|
|
498
|
+
_driver_sha256(source) + "\n",
|
|
499
|
+
encoding="utf-8",
|
|
500
|
+
)
|
|
447
501
|
print(f"Created default driver config at {target}")
|
|
448
502
|
except OSError as e:
|
|
449
503
|
print(f"Warning: could not create default driver config {target}: {e}")
|
|
@@ -453,7 +507,19 @@ def _seed_default_pluto_drivers() -> None:
|
|
|
453
507
|
_seed_default_driver("pluto_mimo_schema.py", "adalm_pluto_mimo")
|
|
454
508
|
|
|
455
509
|
def _seed_default_usrp_driver() -> None:
|
|
456
|
-
_seed_default_driver(
|
|
510
|
+
_seed_default_driver(
|
|
511
|
+
"usrp_schema.py",
|
|
512
|
+
"usrp",
|
|
513
|
+
legacy_hashes=(
|
|
514
|
+
# Previously shipped built-in copies. These are safe to refresh;
|
|
515
|
+
# any edited/custom schema has a different digest and is preserved.
|
|
516
|
+
"ec30aaadb1e8edec289de01e4f997aa3c8b59d3fd0a69c5ac94b37b05dac7a65",
|
|
517
|
+
"baf29cd0f22e84891b546c30c963cddb02bc93db0efb50fe32cc743c8600c227",
|
|
518
|
+
"01360d017359d6cb65761b78b5c2bb570b8f2f55e8ab280ba23d6813deddb233",
|
|
519
|
+
"ca32b958759a5f7933e10426a320ca74e7546734524749ea510de83cf5084397",
|
|
520
|
+
"0d185cd24571bae2d5f75d6c28164694918a86b20854b96fe9b77c475ca28ed1",
|
|
521
|
+
),
|
|
522
|
+
)
|
|
457
523
|
|
|
458
524
|
def _load_all_drivers() -> None:
|
|
459
525
|
_seed_default_pluto_drivers()
|
|
@@ -339,8 +339,13 @@ def _serve(*, headless: bool = False) -> int:
|
|
|
339
339
|
|
|
340
340
|
# UHD writes native log messages to stderr/std::clog. Set this before the
|
|
341
341
|
# server imports device drivers so those messages cannot corrupt the
|
|
342
|
-
# interactive prompt.
|
|
343
|
-
|
|
342
|
+
# interactive prompt. RemoteRF keeps this off even when the surrounding
|
|
343
|
+
# shell has a noisy UHD default; diagnostics require an explicit RemoteRF
|
|
344
|
+
# opt-in.
|
|
345
|
+
os.environ["UHD_LOG_CONSOLE_LEVEL"] = os.getenv(
|
|
346
|
+
"REMOTERF_UHD_CONSOLE_LEVEL",
|
|
347
|
+
"off",
|
|
348
|
+
)
|
|
344
349
|
|
|
345
350
|
from remoteRF_server.server.grpc_server import (
|
|
346
351
|
headless_main,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: remoteRF-server
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
4
4
|
Summary: RemoteRF server-side control package
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -334,13 +334,13 @@ separate policy file. This includes transmit controls, transmit streaming,
|
|
|
334
334
|
GPIO/register methods, and property-tree writes. `usrp_policy.yml` is not read
|
|
335
335
|
or required by the current server.
|
|
336
336
|
|
|
337
|
-
RemoteRF
|
|
337
|
+
RemoteRF forces `UHD_LOG_CONSOLE_LEVEL=off` before importing UHD so native UHD
|
|
338
338
|
messages do not overwrite the interactive `serverrf` prompt. To temporarily
|
|
339
|
-
restore UHD diagnostics, set
|
|
340
|
-
before starting the server:
|
|
339
|
+
restore UHD diagnostics, explicitly set `REMOTERF_UHD_CONSOLE_LEVEL` to a level
|
|
340
|
+
such as `warning`, `info`, or `debug` before starting the server:
|
|
341
341
|
|
|
342
342
|
```bash
|
|
343
|
-
|
|
343
|
+
REMOTERF_UHD_CONSOLE_LEVEL=warning serverrf -s
|
|
344
344
|
```
|
|
345
345
|
|
|
346
346
|
On every qualified target, generate the introspection record and enforce the
|