remoteRF-server-testing 0.0.12__tar.gz → 0.0.13__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 (50) hide show
  1. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/PKG-INFO +1 -1
  2. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/pyproject.toml +1 -1
  3. remoterf_server_testing-0.0.13/src/remoteRF_server/drivers/adalm_pluto/pluto_schema.py +228 -0
  4. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/device_manager.py +54 -3
  5. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/serverrf_cli.py +13 -9
  6. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/gist_status.py +1 -1
  7. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/PKG-INFO +1 -1
  8. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/SOURCES.txt +1 -0
  9. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/README.md +0 -0
  10. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/setup.cfg +0 -0
  11. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/__init__.py +0 -0
  12. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/__init__.py +0 -0
  13. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/__init__.py +0 -0
  14. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
  15. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
  16. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
  17. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
  18. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/__init__.py +0 -0
  19. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/device_schema.py +0 -0
  20. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/pluto_schema.py +0 -0
  21. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/schema.py +0 -0
  22. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/__init__.py +0 -0
  23. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
  24. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/api_token.py +0 -0
  25. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/db_connection.py +0 -0
  26. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/db_location.py +0 -0
  27. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/list_string.py +0 -0
  28. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/process_arg.py +0 -0
  29. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/drivers/__init__.py +0 -0
  30. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
  31. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
  32. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/__init__.py +0 -0
  33. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/host_auth_token.py +0 -0
  34. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/host_directory_store.py +0 -0
  35. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/host_tunnel_server.py +0 -0
  36. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/__init__.py +0 -0
  37. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/acc_perms.py +0 -0
  38. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/cert_provider.py +0 -0
  39. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/grpc_server.py +0 -0
  40. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/reservation.py +0 -0
  41. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/rpc_manager.py +0 -0
  42. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/user_group_cli.py +0 -0
  43. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/user_group_handler.py +0 -0
  44. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/__init__.py +0 -0
  45. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/gen_certs.py +0 -0
  46. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/gist_status_testing.py +0 -0
  47. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/dependency_links.txt +0 -0
  48. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/entry_points.txt +0 -0
  49. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/requires.txt +0 -0
  50. {remoterf_server_testing-0.0.12 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoteRF-server-testing
3
- Version: 0.0.12
3
+ Version: 0.0.13
4
4
  Summary: RemoteRF server-side control package
5
5
  Requires-Python: >=3.8
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "remoteRF-server-testing"
7
- version = "0.0.12"
7
+ version = "0.0.13"
8
8
  description = "RemoteRF server-side control package"
9
9
  requires-python = ">=3.8"
10
10
  dependencies = [
@@ -0,0 +1,228 @@
1
+ # SAMPLE schema for ADI Pluto SDR.
2
+ # Place into -> ~/.config/remoterf/drivers and restart server to utilize!
3
+
4
+
5
+ from remoteRF_server.common.idl import DeviceSchema, idl_register, idl_expose
6
+
7
+ import subprocess
8
+ import re
9
+ import adi
10
+
11
+ # == PLUTO Connection Logic ==
12
+
13
+ def connect_pluto(*, serial: str):
14
+ serial = (serial or "").strip()
15
+ if not serial:
16
+ print("A Pluto serial must be provided")
17
+ return None
18
+
19
+ try:
20
+ out = subprocess.check_output(
21
+ ["iio_info", "-s"],
22
+ text=True,
23
+ stderr=subprocess.STDOUT
24
+ )
25
+
26
+ usb = None
27
+ for line in out.splitlines():
28
+ if (f"serial={serial}" in line) or (f"hw_serial={serial}" in line):
29
+ m = re.search(r"\[usb:([^\]]+)\]", line)
30
+ if m:
31
+ usb = m.group(1).strip()
32
+ break
33
+
34
+ if not usb:
35
+ print(f"No device found with serial {serial}")
36
+ return None
37
+
38
+ dev = adi.Pluto(f"usb:{usb}")
39
+ print(f"Connected to Pluto serial={serial} via usb:{usb}")
40
+ return dev
41
+
42
+ except Exception as e:
43
+ print(f"Failed to connect to Pluto serial={serial}: {e}")
44
+ return None
45
+
46
+ # ========================= PLUTO Schema =========================
47
+
48
+ @idl_register("pluto")
49
+ class PlutoSchema(DeviceSchema):
50
+
51
+ device_type = "pluto"
52
+ driver_version = "0.0.1"
53
+
54
+ @staticmethod
55
+ def make_device(**kwargs):
56
+ serial = kwargs.get("serial")
57
+ return connect_pluto(serial=serial)
58
+
59
+ # region ad9364
60
+
61
+ @idl_expose(kind="get")
62
+ def get_filter(self):
63
+ return self.device.filter
64
+
65
+ @idl_expose(kind="set")
66
+ def set_filter(self, value):
67
+ self.device.filter = value
68
+
69
+ @idl_expose(kind="get")
70
+ def get_loopback(self):
71
+ return self.device.loopback
72
+
73
+ @idl_expose(kind="set")
74
+ def set_loopback(self, value):
75
+ self.device.loopback = value
76
+
77
+ @idl_expose(kind="get")
78
+ def get_gain_control_mode_chan0(self):
79
+ return self.device.gain_control_mode_chan0
80
+
81
+ @idl_expose(kind="set")
82
+ def set_gain_control_mode_chan0(self, value):
83
+ self.device.gain_control_mode_chan0 = value
84
+
85
+ @idl_expose(kind="get")
86
+ def get_hardwaregain_chan0(self):
87
+ """RX hardware gain (dB). pyadi-iio attribute: hardwaregain_chan0"""
88
+ return self.device.hardwaregain_chan0
89
+
90
+ @idl_expose(kind="set")
91
+ def set_hardwaregain_chan0(self, value):
92
+ """RX hardware gain (dB). pyadi-iio attribute: hardwaregain_chan0"""
93
+ self.device.hardwaregain_chan0 = value
94
+
95
+ @idl_expose(kind="get")
96
+ def get_tx_hardwaregain_chan0(self):
97
+ return self.device.tx_hardwaregain_chan0
98
+
99
+ @idl_expose(kind="set")
100
+ def set_tx_hardwaregain_chan0(self, value):
101
+ self.device.tx_hardwaregain_chan0 = value
102
+
103
+ @idl_expose(kind="get")
104
+ def get_rx_rf_bandwidth(self):
105
+ return self.device.rx_rf_bandwidth
106
+
107
+ @idl_expose(kind="set")
108
+ def set_rx_rf_bandwidth(self, value):
109
+ self.device.rx_rf_bandwidth = value
110
+
111
+ @idl_expose(kind="get")
112
+ def get_tx_rf_bandwidth(self):
113
+ return self.device.tx_rf_bandwidth
114
+
115
+ @idl_expose(kind="set")
116
+ def set_tx_rf_bandwidth(self, value):
117
+ self.device.tx_rf_bandwidth = value
118
+
119
+ @idl_expose(kind="get")
120
+ def get_sample_rate(self):
121
+ return self.device.sample_rate
122
+
123
+ @idl_expose(kind="set")
124
+ def set_sample_rate(self, value):
125
+ self.device.sample_rate = value
126
+
127
+ @idl_expose(kind="get")
128
+ def get_rx_lo(self):
129
+ return self.device.rx_lo
130
+
131
+ @idl_expose(kind="set")
132
+ def set_rx_lo(self, value):
133
+ self.device.rx_lo = value
134
+
135
+ @idl_expose(kind="get")
136
+ def get_tx_lo(self):
137
+ return self.device.tx_lo
138
+
139
+ @idl_expose(kind="set")
140
+ def set_tx_lo(self, value):
141
+ self.device.tx_lo = value
142
+
143
+ @idl_expose(kind="get")
144
+ def get_tx_cyclic_buffer(self):
145
+ return self.device.tx_cyclic_buffer
146
+
147
+ @idl_expose(kind="set")
148
+ def set_tx_cyclic_buffer(self, value):
149
+ self.device.tx_cyclic_buffer = value
150
+
151
+ # region RX/TX
152
+
153
+ @idl_expose(kind="call")
154
+ def call_rx(self):
155
+ return self.device.rx()
156
+
157
+ @idl_expose(kind="get")
158
+ def get_rx_buffer_size(self):
159
+ return self.device.rx_buffer_size
160
+
161
+ @idl_expose(kind="set")
162
+ def set_rx_buffer_size(self, value):
163
+ self.device.rx_buffer_size = value
164
+
165
+ @idl_expose(kind="call")
166
+ def call_rx_destroy_buffer(self):
167
+ self.device.rx_destroy_buffer()
168
+
169
+ @idl_expose(kind="call")
170
+ def call_tx(self, value):
171
+ self.device.tx(value)
172
+
173
+ @idl_expose(kind="call")
174
+ def call_tx_destroy_buffer(self):
175
+ self.device.tx_destroy_buffer()
176
+
177
+ @idl_expose(kind="call")
178
+ def call_disable_dds(self):
179
+ """Disable the internal DDS tone generator."""
180
+ self.device.disable_dds()
181
+
182
+ # endregion
183
+
184
+ # region ip / repr
185
+
186
+ @idl_expose(kind="call")
187
+ def call_ip(self):
188
+ """Return a connection identifier for this device (ping / verify)."""
189
+ try:
190
+ return str(self.device.uri)
191
+ except AttributeError:
192
+ return str(self.device._uri_auto)
193
+
194
+ @idl_expose(kind="get")
195
+ def get_repr(self):
196
+ """Return repr() of the underlying device object."""
197
+ return repr(self.device)
198
+
199
+ # endregion
200
+
201
+ # region _dec_int_fpga_filter
202
+
203
+ @idl_expose(kind="get")
204
+ def get_rx_dec8_filter_en(self):
205
+ """rx_dec8_filter_en: Enable decimate-by-8 filter in FPGA"""
206
+ return bool(self.device.rx_dec8_filter_en)
207
+
208
+ @idl_expose(kind="set")
209
+ def set_rx_dec8_filter_en(self, value):
210
+ """rx_dec8_filter_en: Enable decimate-by-8 filter in FPGA"""
211
+ self.device.rx_dec8_filter_en = value
212
+
213
+ @idl_expose(kind="get")
214
+ def get_tx_int8_filter_en(self):
215
+ """tx_int8_filter_en: Enable interpolate-by-8 filter in FPGA"""
216
+ return bool(self.device.tx_int8_filter_en)
217
+
218
+ @idl_expose(kind="set")
219
+ def set_tx_int8_filter_en(self, value):
220
+ """tx_int8_filter_en: Enable interpolate-by-8 filter in FPGA"""
221
+ self.device.tx_int8_filter_en = value
222
+
223
+ @idl_expose(kind="get")
224
+ def get_rates(self):
225
+ """Get decimation/interpolation rates from the FPGA filter block."""
226
+ return self.device._get_rates(self.device._rxadc, False)
227
+
228
+ # endregion
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  import re
7
+ import shutil
7
8
  import time
8
9
  import yaml
9
10
  import threading
@@ -12,7 +13,7 @@ from pathlib import Path
12
13
  from typing import Dict, Tuple, Optional, Any, List, Iterator
13
14
  from contextlib import contextmanager
14
15
 
15
- from ..common.utils import validate_token, get_remoterf_root
16
+ from ..common.utils import validate_token, get_remoterf_root, get_drivers_dir
16
17
  from ..common.idl.schema import get_driver_class, load_drivers
17
18
  from ..host import host_tunnel_server as hts
18
19
 
@@ -245,10 +246,19 @@ def _get_master_token() -> str:
245
246
  return ""
246
247
 
247
248
  def _devices_yaml_path() -> Path:
248
- p1 = _cfg_dir() / "devices.yml"
249
+ cfg_dir = _cfg_dir()
250
+ p1 = cfg_dir / "devices.yml"
249
251
  if p1.exists():
250
252
  return p1
251
- return _cfg_dir() / "devices.yaml"
253
+ p2 = cfg_dir / "devices.yaml"
254
+ if p2.exists():
255
+ return p2
256
+ try:
257
+ cfg_dir.mkdir(parents=True, exist_ok=True)
258
+ p1.touch(exist_ok=True)
259
+ except OSError as e:
260
+ print(f"Warning: could not create empty devices config {p1}: {e}")
261
+ return p1
252
262
 
253
263
  def _load_device_records() -> Dict[int, Dict[str, str]]:
254
264
  path = _devices_yaml_path()
@@ -376,7 +386,48 @@ def _init_from_env() -> None:
376
386
 
377
387
  # Load built-in drivers, then any user-supplied drivers from the config dir.
378
388
  # Importing the module triggers @idl_register, which adds the class to the registry.
389
+ def _packaged_pluto_schema_path() -> Path:
390
+ return Path(__file__).resolve().parents[1] / "drivers" / "adalm_pluto" / "pluto_schema.py"
391
+
392
+ def _driver_registers_pluto(path: Path) -> bool:
393
+ try:
394
+ text = path.read_text(encoding="utf-8")
395
+ except OSError:
396
+ return False
397
+ return re.search(r"(?:idl_register|register_driver)\(\s*['\"]pluto['\"]\s*\)", text) is not None
398
+
399
+ def _seed_default_pluto_driver() -> None:
400
+ drivers_dir = get_drivers_dir()
401
+ target = drivers_dir / "pluto_schema.py"
402
+ if target.exists() or target.is_symlink():
403
+ return
404
+
405
+ try:
406
+ drivers_dir.mkdir(parents=True, exist_ok=True)
407
+ except OSError as e:
408
+ print(f"Warning: could not create drivers directory {drivers_dir}: {e}")
409
+ return
410
+
411
+ for driver_file in drivers_dir.glob("*.py"):
412
+ if driver_file.name.startswith("_"):
413
+ continue
414
+ if _driver_registers_pluto(driver_file):
415
+ return
416
+
417
+ source = _packaged_pluto_schema_path()
418
+ if not source.exists():
419
+ print(f"Warning: default Pluto schema source is missing: {source}")
420
+ return
421
+
422
+ try:
423
+ shutil.copy2(source, target)
424
+ print(f"Created default Pluto driver config at {target}")
425
+ except OSError as e:
426
+ print(f"Warning: could not create default Pluto driver config {target}: {e}")
427
+
379
428
  def _load_all_drivers() -> None:
429
+ _seed_default_pluto_driver()
430
+
380
431
  try:
381
432
  from ..common.idl import pluto_schema as _ # noqa: F401
382
433
  except Exception as e:
@@ -194,12 +194,12 @@ def print_help() -> None:
194
194
  "Devices:\n"
195
195
  " serverrf -d | --device [options]\n"
196
196
  "\n"
197
- "Device options:\n"
198
- " --add --pluto <id:name:iio_serial> Add device (fails if gid OR serial already used)\n"
199
- " --remove <id> Remove device\n"
200
- " --edit-name <id> <name> Override device NAME for existing device\n"
201
- " --show | -s Show all devices\n"
202
- " -w | --wipe [-y] Wipe ONLY device config (devices.env)\n"
197
+ # "Device options:\n"
198
+ # " --add --pluto <id:name:iio_serial> Add device (fails if gid OR serial already used)\n"
199
+ # " --remove <id> Remove device\n"
200
+ # " --edit-name <id> <name> Override device NAME for existing device\n"
201
+ # " --show | -s Show all devices\n"
202
+ # " -w | --wipe [-y] Wipe ONLY device config (devices.env)\n"
203
203
 
204
204
  "\n"
205
205
  "Cert options (for --gen-certs):\n"
@@ -589,7 +589,7 @@ def _config_show_ports() -> int:
589
589
  print(" (empty)")
590
590
 
591
591
  if "GRPC_PORT" in kv:
592
- print(f" GRPC_PORT={kv['GRPC_PORT']}")
592
+ print(f" MAIN_PORT={kv['GRPC_PORT']}")
593
593
  if "CERT_PORT" in kv:
594
594
  print(f" CERT_PORT={kv['CERT_PORT']}")
595
595
 
@@ -828,8 +828,12 @@ def _wipe_devices_only(*, yes: bool) -> int:
828
828
  def main() -> int:
829
829
  argv = list(sys.argv[1:])
830
830
 
831
+ if len(argv) == 0:
832
+ print("invalid args, expect serverrf <args>, run serverrf --help for more info", file=sys.stderr)
833
+ return 2
834
+
831
835
  # help
832
- if len(argv) == 0 or argv[0] in ("--help", "-h", "-help", "--h"):
836
+ if argv[0] in ("--help", "-h", "-help", "--h"):
833
837
  print_help()
834
838
  return 0
835
839
 
@@ -1318,7 +1322,7 @@ def main() -> int:
1318
1322
  return 2
1319
1323
 
1320
1324
  print("Host token created and stored at ~/.config/remoterf/db/hosts_auth.env")
1321
- print(f'To config host:\n hostrf --config --host {host_token_create_id} "{token}"')
1325
+ print(f'On the host you want to setup, run the following:\n hostrf --config --host {host_token_create_id} "{token}"')
1322
1326
  return 0
1323
1327
 
1324
1328
  # ----------------
@@ -111,7 +111,7 @@ def start_status_publisher() -> None:
111
111
  return
112
112
 
113
113
  if _load_gist_env() is None:
114
- print("[gist_status] off (not configured; see README gist docs)", file=sys.stderr)
114
+ # print("[gist_status] off (not configured; see README gist docs)", file=sys.stderr)
115
115
  return
116
116
 
117
117
  t = threading.Thread(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoteRF-server-testing
3
- Version: 0.0.12
3
+ Version: 0.0.13
4
4
  Summary: RemoteRF server-side control package
5
5
  Requires-Python: >=3.8
6
6
  Description-Content-Type: text/markdown
@@ -22,6 +22,7 @@ src/remoteRF_server/common/utils/process_arg.py
22
22
  src/remoteRF_server/drivers/__init__.py
23
23
  src/remoteRF_server/drivers/adalm_pluto/__init__.py
24
24
  src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py
25
+ src/remoteRF_server/drivers/adalm_pluto/pluto_schema.py
25
26
  src/remoteRF_server/host/__init__.py
26
27
  src/remoteRF_server/host/host_auth_token.py
27
28
  src/remoteRF_server/host/host_directory_store.py