remoteRF-server-testing 0.0.11__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.11 → remoterf_server_testing-0.0.13}/PKG-INFO +1 -1
  2. {remoterf_server_testing-0.0.11 → 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.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/device_manager.py +54 -3
  5. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/serverrf_cli.py +83 -17
  6. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/gist_status.py +1 -1
  7. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/PKG-INFO +1 -1
  8. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/SOURCES.txt +1 -0
  9. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/README.md +0 -0
  10. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/setup.cfg +0 -0
  11. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/__init__.py +0 -0
  12. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/__init__.py +0 -0
  13. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/__init__.py +0 -0
  14. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
  15. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
  16. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
  17. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
  18. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/__init__.py +0 -0
  19. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/device_schema.py +0 -0
  20. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/pluto_schema.py +0 -0
  21. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/idl/schema.py +0 -0
  22. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/__init__.py +0 -0
  23. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
  24. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/api_token.py +0 -0
  25. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/db_connection.py +0 -0
  26. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/db_location.py +0 -0
  27. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/list_string.py +0 -0
  28. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/common/utils/process_arg.py +0 -0
  29. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/drivers/__init__.py +0 -0
  30. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
  31. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
  32. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/__init__.py +0 -0
  33. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/host_auth_token.py +0 -0
  34. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/host_directory_store.py +0 -0
  35. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/host/host_tunnel_server.py +0 -0
  36. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/__init__.py +0 -0
  37. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/acc_perms.py +0 -0
  38. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/cert_provider.py +0 -0
  39. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/grpc_server.py +0 -0
  40. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/reservation.py +0 -0
  41. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/rpc_manager.py +0 -0
  42. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/user_group_cli.py +0 -0
  43. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/server/user_group_handler.py +0 -0
  44. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/__init__.py +0 -0
  45. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/gen_certs.py +0 -0
  46. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server/tools/gist_status_testing.py +0 -0
  47. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/dependency_links.txt +0 -0
  48. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/entry_points.txt +0 -0
  49. {remoterf_server_testing-0.0.11 → remoterf_server_testing-0.0.13}/src/remoteRF_server_testing.egg-info/requires.txt +0 -0
  50. {remoterf_server_testing-0.0.11 → 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.11
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.11"
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:
@@ -5,6 +5,8 @@ import os
5
5
  import subprocess
6
6
  import shutil
7
7
  import re
8
+ import ssl
9
+ import ipaddress
8
10
  from pathlib import Path
9
11
  from typing import Optional, Dict, List, Tuple
10
12
  from datetime import datetime, timezone
@@ -53,6 +55,59 @@ def _fmt_remaining(na_utc: datetime) -> str:
53
55
  return f"{days}d {hours}h {mins}m"
54
56
 
55
57
 
58
+ _STATIC_IP_ENV_KEYS: Tuple[str, ...] = ("STATIC_IP", "SERVER_IP")
59
+
60
+
61
+ def _is_ip_address(value: str) -> bool:
62
+ try:
63
+ ipaddress.ip_address((value or "").strip())
64
+ return True
65
+ except ValueError:
66
+ return False
67
+
68
+
69
+ def _x509_static_ip(cert_path: Path) -> str:
70
+ if not cert_path.exists():
71
+ raise FileNotFoundError(f"server cert not found: {cert_path}")
72
+
73
+ try:
74
+ cert = ssl._ssl._test_decode_cert(str(cert_path))
75
+ except FileNotFoundError:
76
+ raise
77
+ except Exception as e:
78
+ raise ValueError(f"could not parse server cert {cert_path}: {e}") from e
79
+
80
+ for name, value in cert.get("subjectAltName", []):
81
+ if name.lower() == "ip address":
82
+ ip = (value or "").strip()
83
+ if ip:
84
+ return ip
85
+
86
+ for group in cert.get("subject", []):
87
+ for name, value in group:
88
+ if name.lower() != "commonname":
89
+ continue
90
+ cn = (value or "").strip()
91
+ if _is_ip_address(cn):
92
+ return cn
93
+
94
+ raise ValueError(f"server cert does not contain an IP SAN or IP common name: {cert_path}")
95
+
96
+
97
+ def _resolve_static_ip(kv: Dict[str, str]) -> Tuple[Optional[str], str, Optional[str]]:
98
+ env_path = _server_env_path()
99
+ for key in _STATIC_IP_ENV_KEYS:
100
+ value = (kv.get(key, "") or "").strip()
101
+ if value:
102
+ return value, f"{env_path} ({key})", None
103
+
104
+ cert_path = _certs_dir() / "server.crt"
105
+ try:
106
+ return _x509_static_ip(cert_path), str(cert_path), None
107
+ except (FileNotFoundError, ValueError) as e:
108
+ return None, str(cert_path), str(e)
109
+
110
+
56
111
  # -----------------------------
57
112
  # Repo-local server config locations
58
113
  # -----------------------------
@@ -126,7 +181,7 @@ def print_help() -> None:
126
181
  "Port options:\n"
127
182
  " --main-port <int> Set GRPC_PORT\n"
128
183
  " --cert-port <int> Set CERT_PORT\n"
129
- " --show | -s Show current ports\n"
184
+ " --show | -s Show current ports and static IP\n"
130
185
  " -w | --wipe [-y] Wipe ONLY port config (server.env)\n"
131
186
  "\n"
132
187
  "Hosts:\n"
@@ -139,12 +194,12 @@ def print_help() -> None:
139
194
  "Devices:\n"
140
195
  " serverrf -d | --device [options]\n"
141
196
  "\n"
142
- "Device options:\n"
143
- " --add --pluto <id:name:iio_serial> Add device (fails if gid OR serial already used)\n"
144
- " --remove <id> Remove device\n"
145
- " --edit-name <id> <name> Override device NAME for existing device\n"
146
- " --show | -s Show all devices\n"
147
- " -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"
148
203
 
149
204
  "\n"
150
205
  "Cert options (for --gen-certs):\n"
@@ -525,20 +580,27 @@ def _gen_certs(
525
580
 
526
581
  def _config_show_ports() -> int:
527
582
  p = _server_env_path()
528
- if not p.exists():
529
- print(f"No port config found (missing {p}).")
530
- return 0
531
-
532
583
  kv = _read_env_kv(p)
533
- if not kv:
534
- print("Port config is empty.")
535
- return 0
536
584
 
537
585
  print(f"Port config: {p}")
586
+ if not p.exists():
587
+ print(" (missing)")
588
+ elif not kv:
589
+ print(" (empty)")
590
+
538
591
  if "GRPC_PORT" in kv:
539
- print(f" GRPC_PORT={kv['GRPC_PORT']}")
592
+ print(f" MAIN_PORT={kv['GRPC_PORT']}")
540
593
  if "CERT_PORT" in kv:
541
594
  print(f" CERT_PORT={kv['CERT_PORT']}")
595
+
596
+ static_ip, source, err = _resolve_static_ip(kv)
597
+ if static_ip:
598
+ print(f" STATIC_IP={static_ip}")
599
+ if source != f"{p} (STATIC_IP)":
600
+ print(f" STATIC_IP_SOURCE={source}")
601
+ else:
602
+ print(" STATIC_IP=(not set)")
603
+ print(f" STATIC_IP_ERROR={err or f'could not resolve from {source}'}")
542
604
  return 0
543
605
 
544
606
 
@@ -766,8 +828,12 @@ def _wipe_devices_only(*, yes: bool) -> int:
766
828
  def main() -> int:
767
829
  argv = list(sys.argv[1:])
768
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
+
769
835
  # help
770
- if len(argv) == 0 or argv[0] in ("--help", "-h", "-help", "--h"):
836
+ if argv[0] in ("--help", "-h", "-help", "--h"):
771
837
  print_help()
772
838
  return 0
773
839
 
@@ -1256,7 +1322,7 @@ def main() -> int:
1256
1322
  return 2
1257
1323
 
1258
1324
  print("Host token created and stored at ~/.config/remoterf/db/hosts_auth.env")
1259
- 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}"')
1260
1326
  return 0
1261
1327
 
1262
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.11
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