remoteRF-server 1.0.8__tar.gz → 1.0.10__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 (73) hide show
  1. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/PKG-INFO +1 -1
  2. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/pyproject.toml +1 -1
  3. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/usrp/uhd_manifest.py +16 -1
  4. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/usrp/usrp_schema.py +1 -1
  5. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/device_manager.py +12 -1
  6. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/dynamic_v2.py +43 -7
  7. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server.egg-info/PKG-INFO +1 -1
  8. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_dynamic_v2.py +22 -5
  9. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_pluto_compat.py +22 -1
  10. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_usrp_client_server_localhost.py +3 -10
  11. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/README.md +0 -0
  12. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/setup.cfg +0 -0
  13. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/__init__.py +0 -0
  14. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/__init__.py +0 -0
  15. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/grpc/__init__.py +0 -0
  16. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
  17. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
  18. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
  19. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
  20. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/grpc/v2_codec.py +0 -0
  21. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/idl/__init__.py +0 -0
  22. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/idl/device_schema.py +0 -0
  23. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/idl/pluto_mimo_schema.py +0 -0
  24. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/idl/pluto_schema.py +0 -0
  25. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/idl/schema.py +0 -0
  26. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/idl/v2.py +0 -0
  27. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/utils/__init__.py +0 -0
  28. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
  29. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/utils/api_token.py +0 -0
  30. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/utils/db_connection.py +0 -0
  31. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/utils/db_location.py +0 -0
  32. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/utils/list_string.py +0 -0
  33. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/common/utils/process_arg.py +0 -0
  34. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/__init__.py +0 -0
  35. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
  36. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/adalm_pluto/pluto_mimo_schema.py +0 -0
  37. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
  38. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/adalm_pluto/pluto_schema.py +0 -0
  39. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/usrp/__init__.py +0 -0
  40. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/drivers/usrp/policy.py +0 -0
  41. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/host/__init__.py +0 -0
  42. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/host/host_auth_token.py +0 -0
  43. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/host/host_directory_store.py +0 -0
  44. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/host/host_tunnel_server.py +0 -0
  45. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/__init__.py +0 -0
  46. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/acc_perms.py +0 -0
  47. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/cert_provider.py +0 -0
  48. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/grpc_server.py +0 -0
  49. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/reservation.py +0 -0
  50. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/rpc_manager.py +0 -0
  51. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/user_group_cli.py +0 -0
  52. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/user_group_handler.py +0 -0
  53. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/server/v2_errors.py +0 -0
  54. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/serverrf_cli.py +0 -0
  55. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/tools/__init__.py +0 -0
  56. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/tools/gen_certs.py +0 -0
  57. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/tools/gist_status.py +0 -0
  58. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/tools/gist_status_testing.py +0 -0
  59. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server/tools/introspect_uhd.py +0 -0
  60. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server.egg-info/SOURCES.txt +0 -0
  61. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server.egg-info/dependency_links.txt +0 -0
  62. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server.egg-info/entry_points.txt +0 -0
  63. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server.egg-info/requires.txt +0 -0
  64. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/src/remoteRF_server.egg-info/top_level.txt +0 -0
  65. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_cert_provider.py +0 -0
  66. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_default_usrp_schema.py +0 -0
  67. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_idl_schema.py +0 -0
  68. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_process_arg.py +0 -0
  69. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_reservation_timestamps.py +0 -0
  70. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_rpc_manager_calln.py +0 -0
  71. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_usrp_client_server_hardware.py +0 -0
  72. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/tests/test_usrp_remoterf_rx_hardware.py +0 -0
  73. {remoterf_server-1.0.8 → remoterf_server-1.0.10}/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.8
3
+ Version: 1.0.10
4
4
  Summary: RemoteRF server-side control package
5
5
  Requires-Python: >=3.10
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"
7
- version = "1.0.8"
7
+ version = "1.0.10"
8
8
  description = "RemoteRF server-side control package"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
@@ -1076,6 +1076,8 @@ def _objects() -> list[dict]:
1076
1076
  object_type("uhd", kind="namespace"),
1077
1077
  object_type("uhd.usrp", kind="namespace"),
1078
1078
  object_type("uhd.types", kind="namespace"),
1079
+ object_type("uhd.dsp", kind="namespace"),
1080
+ object_type("uhd.dsp.signals", kind="namespace"),
1079
1081
  object_type("uhd.filters", kind="namespace"),
1080
1082
  object_type("uhd.property", kind="namespace"),
1081
1083
  value(
@@ -1537,7 +1539,7 @@ ERRORS = (
1537
1539
  )
1538
1540
 
1539
1541
 
1540
- def build_usrp_schema_v2(driver_version: str = "0.0.1") -> dict:
1542
+ def build_usrp_schema_v2(driver_version: str = "0.0.2") -> dict:
1541
1543
  signatures = _signatures()
1542
1544
  for additions in (
1543
1545
  _control_signatures(),
@@ -1580,6 +1582,11 @@ def build_usrp_schema_v2(driver_version: str = "0.0.1") -> dict:
1580
1582
  coverage[f"{item['owner']}.{item['name']}"] = "implemented"
1581
1583
 
1582
1584
  declared_owners = {item["owner"] for item in methods}
1585
+ coverage.update({
1586
+ "uhd.dsp.signals.get_continuous_tone": "implemented",
1587
+ "uhd.dsp.signals.get_power_dbfs": "implemented",
1588
+ "uhd.dsp.signals.get_usrp_power": "implemented",
1589
+ })
1583
1590
  for item in _objects():
1584
1591
  path = item["python_path"]
1585
1592
  if item["kind"] == "value_class":
@@ -1603,6 +1610,14 @@ def build_usrp_schema_v2(driver_version: str = "0.0.1") -> dict:
1603
1610
  else "deferred"
1604
1611
  )
1605
1612
 
1613
+ # Remote streamers advertise an efficient RPC batch size rather than the
1614
+ # device transport's packet size. The server coalesces native RX packets,
1615
+ # while UHD's native TX send already accepts a larger host buffer.
1616
+ for owner in ("uhd.usrp.RXStreamer", "uhd.usrp.TXStreamer"):
1617
+ coverage[f"{owner}.get_max_num_samps"] = (
1618
+ "implemented_with_documented_remote_difference"
1619
+ )
1620
+
1606
1621
  return build_schema(
1607
1622
  device_type="usrp",
1608
1623
  client_class="MultiUSRP",
@@ -503,7 +503,7 @@ class UsrpSchema(DeviceSchema):
503
503
  device_type = "usrp"
504
504
  client_class = "MultiUSRP"
505
505
  client_objects = _uhd_client_objects()
506
- driver_version = "0.0.1"
506
+ driver_version = "0.0.2"
507
507
  session_scoped = True
508
508
 
509
509
  def __init__(self):
@@ -502,8 +502,19 @@ def _seed_default_driver(
502
502
  except OSError as e:
503
503
  print(f"Warning: could not create default driver config {target}: {e}")
504
504
 
505
+ _LEGACY_PLUTO_SCHEMA_HASHES = (
506
+ # Built-in 0.0.1 schema shipped before managed-driver markers existed.
507
+ # An exact hash match is safe to upgrade; locally edited copies differ.
508
+ "a3697eeef55827e0db7705685f8fe64b615468dd26057211de8b5805b9ecf583",
509
+ )
510
+
511
+
505
512
  def _seed_default_pluto_drivers() -> None:
506
- _seed_default_driver("pluto_schema.py", "adalm_pluto")
513
+ _seed_default_driver(
514
+ "pluto_schema.py",
515
+ "adalm_pluto",
516
+ legacy_hashes=_LEGACY_PLUTO_SCHEMA_HASHES,
517
+ )
507
518
  _seed_default_driver("pluto_mimo_schema.py", "adalm_pluto_mimo")
508
519
 
509
520
  def _seed_default_usrp_driver() -> None:
@@ -1346,14 +1346,50 @@ class SampleDataV1Servicer(grpc_pb2_grpc.SampleDataV1Servicer):
1346
1346
  "UHD 4.10 Python RXStreamer.recv binding"
1347
1347
  )
1348
1348
  timeout = _sample_timeout(request.timeout_sec)
1349
+ deadline = time.monotonic() + timeout
1350
+ count = 0
1351
+ metadata_snapshot = snapshot_native(metadata)
1349
1352
  with entry.lock:
1350
- count = entry.value.recv(
1351
- buffer,
1352
- metadata,
1353
- timeout,
1354
- )
1353
+ while count < int(request.sample_count):
1354
+ remaining = max(0.0, deadline - time.monotonic())
1355
+ if count and remaining <= 0.0:
1356
+ break
1357
+ current_metadata = (
1358
+ metadata
1359
+ if count == 0
1360
+ else self._metadata_object(
1361
+ session.schema,
1362
+ "RXMetadata",
1363
+ request.metadata_json,
1364
+ )
1365
+ )
1366
+ target = buffer[..., count:]
1367
+ received = int(
1368
+ entry.value.recv(
1369
+ target,
1370
+ current_metadata,
1371
+ timeout if count == 0 else remaining,
1372
+ )
1373
+ )
1374
+ if received < 0 or received > target.shape[-1]:
1375
+ raise RemoteRFProtocolError(
1376
+ "native RX returned an invalid sample count"
1377
+ )
1378
+ current_snapshot = snapshot_native(current_metadata)
1379
+ error_code = str(
1380
+ current_snapshot.get("error_code", "none")
1381
+ ).rsplit(".", 1)[-1].lower()
1382
+ has_error = error_code not in {
1383
+ "none",
1384
+ "error_code_none",
1385
+ }
1386
+ if count == 0 or has_error:
1387
+ metadata = current_metadata
1388
+ metadata_snapshot = current_snapshot
1389
+ count += received
1390
+ if received == 0 or has_error:
1391
+ break
1355
1392
  session_manager.get(session.session_id)
1356
- count = int(count)
1357
1393
  if count < 0 or count > int(request.sample_count):
1358
1394
  raise RemoteRFProtocolError(
1359
1395
  "native RX returned an invalid sample count"
@@ -1381,7 +1417,7 @@ class SampleDataV1Servicer(grpc_pb2_grpc.SampleDataV1Servicer):
1381
1417
  sample_count=count,
1382
1418
  payload=payload,
1383
1419
  metadata_json=json.dumps(
1384
- snapshot_native(metadata),
1420
+ metadata_snapshot,
1385
1421
  sort_keys=True,
1386
1422
  separators=(",", ":"),
1387
1423
  ),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoteRF-server
3
- Version: 1.0.8
3
+ Version: 1.0.10
4
4
  Summary: RemoteRF server-side control package
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -173,6 +173,16 @@ class DynamicV2ServerTests(unittest.TestCase):
173
173
  self.assertIn("uhd.filters.AnalogFilterLP", object_paths)
174
174
  self.assertIn("uhd.filters.DigitalFilterFIRI16", object_paths)
175
175
  self.assertIn("uhd.filters.FilterType", object_paths)
176
+ self.assertIn("uhd.dsp", object_paths)
177
+ self.assertIn("uhd.dsp.signals", object_paths)
178
+ self.assertEqual(
179
+ schema["coverage"]["uhd.dsp.signals.get_continuous_tone"],
180
+ "implemented",
181
+ )
182
+ self.assertEqual(
183
+ schema["coverage"]["uhd.usrp.RXStreamer.get_max_num_samps"],
184
+ "implemented_with_documented_remote_difference",
185
+ )
176
186
  assert_release_coverage(schema)
177
187
 
178
188
  def test_promoted_signatures_preserve_native_defaults_and_parameter_kinds(self):
@@ -423,7 +433,7 @@ class DynamicV2ServerTests(unittest.TestCase):
423
433
  self.assertTrue(manager.close(session.session_id))
424
434
  self.assertTrue(inventory.live.closed)
425
435
 
426
- def test_binary_rx_stream_returns_only_native_received_prefix(self):
436
+ def test_binary_rx_stream_coalesces_native_packets(self):
427
437
  inventory = FakeInventorySchema()
428
438
  context = {
429
439
  "schema": inventory,
@@ -533,14 +543,21 @@ class DynamicV2ServerTests(unittest.TestCase):
533
543
  )
534
544
  data = responses[-1]
535
545
  self.assertEqual(data.kind, grpc_pb2.SAMPLE_FRAME_DATA)
536
- self.assertEqual(data.sample_count, 2)
537
- self.assertEqual(len(data.payload), 2 * np.dtype(np.complex64).itemsize)
546
+ self.assertEqual(data.sample_count, 4)
547
+ self.assertEqual(len(data.payload), 4 * np.dtype(np.complex64).itemsize)
538
548
  np.testing.assert_array_equal(
539
549
  np.frombuffer(data.payload, dtype=np.complex64),
540
- np.array([1 + 2j, 3 + 4j], dtype=np.complex64),
550
+ np.array(
551
+ [1 + 2j, 3 + 4j, 1 + 2j, 3 + 4j],
552
+ dtype=np.complex64,
553
+ ),
541
554
  )
542
555
  self.assertEqual(json.loads(data.metadata_json)["error_code"], "none")
543
- self.assertEqual(
556
+ self.assertGreater(
557
+ manager.get_handle(session, handle).value.last_timeout,
558
+ 0.0,
559
+ )
560
+ self.assertLessEqual(
544
561
  manager.get_handle(session, handle).value.last_timeout,
545
562
  0.1,
546
563
  )
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import sys
4
4
  import types
5
5
  import unittest
6
- from unittest.mock import patch
6
+ from unittest.mock import call, patch
7
7
 
8
8
  import numpy as np
9
9
 
@@ -216,6 +216,27 @@ class PlutoCompatTests(unittest.TestCase):
216
216
  self.assertEqual(ident, "104473f6")
217
217
  self.assertEqual(dtype, "adalm_pluto")
218
218
 
219
+ def test_legacy_builtin_pluto_schema_is_registered_for_auto_upgrade(self) -> None:
220
+ expected_hash = (
221
+ "a3697eeef55827e0db7705685f8fe64b615468dd26057211de8b5805b9ecf583"
222
+ )
223
+ self.assertIn(expected_hash, device_manager._LEGACY_PLUTO_SCHEMA_HASHES)
224
+
225
+ with patch.object(device_manager, "_seed_default_driver") as seed:
226
+ device_manager._seed_default_pluto_drivers()
227
+
228
+ self.assertEqual(
229
+ seed.call_args_list,
230
+ [
231
+ call(
232
+ "pluto_schema.py",
233
+ "adalm_pluto",
234
+ legacy_hashes=device_manager._LEGACY_PLUTO_SCHEMA_HASHES,
235
+ ),
236
+ call("pluto_mimo_schema.py", "adalm_pluto_mimo"),
237
+ ],
238
+ )
239
+
219
240
 
220
241
  if __name__ == "__main__":
221
242
  unittest.main()
@@ -217,7 +217,7 @@ class USRPClientServerLocalhostTests(unittest.TestCase):
217
217
  with device.get_rx_stream(stream_args) as streamer:
218
218
  self.assertEqual(
219
219
  streamer.get_max_num_samps(),
220
- 256,
220
+ 64 * 1024,
221
221
  )
222
222
  samples = np.full(
223
223
  4,
@@ -231,18 +231,11 @@ class USRPClientServerLocalhostTests(unittest.TestCase):
231
231
  0.25,
232
232
  )
233
233
 
234
- self.assertEqual(count, 2)
234
+ self.assertEqual(count, 4)
235
235
  np.testing.assert_array_equal(
236
236
  samples[:count],
237
237
  np.array(
238
- [1 + 2j, 3 + 4j],
239
- dtype=np.complex64,
240
- ),
241
- )
242
- np.testing.assert_array_equal(
243
- samples[count:],
244
- np.array(
245
- [99 + 0j, 99 + 0j],
238
+ [1 + 2j, 3 + 4j, 1 + 2j, 3 + 4j],
246
239
  dtype=np.complex64,
247
240
  ),
248
241
  )