RemoteRF 2.0.4__tar.gz → 2.0.7__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 (56) hide show
  1. {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7}/PKG-INFO +2 -2
  2. {remoterf-2.0.4 → remoterf-2.0.7}/README.md +1 -1
  3. {remoterf-2.0.4 → remoterf-2.0.7}/setup.py +1 -1
  4. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/grpc_pb2.py +46 -46
  5. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/process_arg.py +102 -62
  6. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/dynamic_v2.py +49 -1
  7. remoterf-2.0.7/src/remoteRF/drivers/support/uhd_dsp.py +76 -0
  8. remoterf-2.0.7/src/remoteRF/drivers/usrp/usrp_remote.py +8 -0
  9. {remoterf-2.0.4 → remoterf-2.0.7/src/remoterf.egg-info}/PKG-INFO +2 -2
  10. remoterf-2.0.7/src/remoterf.egg-info/SOURCES.txt +51 -0
  11. remoterf-2.0.7/src/remoterf.egg-info/top_level.txt +1 -0
  12. {remoterf-2.0.4 → remoterf-2.0.7}/tests/test_dynamic_v2.py +47 -1
  13. remoterf-2.0.7/tests/test_process_arg.py +218 -0
  14. remoterf-2.0.4/LICENSE +0 -21
  15. remoterf-2.0.4/src/remoteRF/drivers/usrp/usrp_remote.py +0 -8
  16. remoterf-2.0.4/src/remoteRF.egg-info/SOURCES.txt +0 -55
  17. remoterf-2.0.4/src/remoteRF.egg-info/top_level.txt +0 -1
  18. remoterf-2.0.4/tests/test_process_arg.py +0 -110
  19. {remoterf-2.0.4 → remoterf-2.0.7}/MANIFEST.in +0 -0
  20. {remoterf-2.0.4 → remoterf-2.0.7}/setup.cfg +0 -0
  21. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/__init__.py +0 -0
  22. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/__init__.py +0 -0
  23. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/__init__.py +0 -0
  24. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/grpc_pb2_grpc.py +0 -0
  25. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/v2_codec.py +0 -0
  26. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/tos_notice.txt +0 -0
  27. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/__init__.py +0 -0
  28. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/ansi_codes.py +0 -0
  29. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/api_token.py +0 -0
  30. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/list_string.py +0 -0
  31. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/config/__init__.py +0 -0
  32. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/config/cert_fetcher.py +0 -0
  33. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/config/config.py +0 -0
  34. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/__init__.py +0 -0
  35. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/acc_login.py +0 -0
  36. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/app.py +0 -0
  37. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/banner_note.txt +0 -0
  38. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/dynamic_v2_transport.py +0 -0
  39. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/grpc_acc.py +0 -0
  40. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/grpc_client.py +0 -0
  41. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/v2_errors.py +0 -0
  42. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/__init__.py +0 -0
  43. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/adalm_pluto/__init__.py +0 -0
  44. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/adalm_pluto/pluto_remote.py +0 -0
  45. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/dynamic_device.py +0 -0
  46. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/support/__init__.py +0 -0
  47. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/support/uhd.py +0 -0
  48. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/support/uhd_v2.py +0 -0
  49. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/usrp/__init__.py +0 -0
  50. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/usrp/usrp_remote.pyi +0 -0
  51. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/remoterf_cli.py +0 -0
  52. {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/version.py +0 -0
  53. {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7/src/remoterf.egg-info}/dependency_links.txt +0 -0
  54. {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7/src/remoterf.egg-info}/entry_points.txt +0 -0
  55. {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7/src/remoterf.egg-info}/requires.txt +0 -0
  56. {remoterf-2.0.4 → remoterf-2.0.7}/tests/test_dynamic_device_codegen.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 2.0.4
3
+ Version: 2.0.7
4
4
  Summary: A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.
5
5
  Author: Ethan Ge
6
6
  Author-email: ethoGalaxy@gmail.com
@@ -55,7 +55,7 @@ pip install remoterf # Install remoteRF
55
55
 
56
56
  ## NI USRP-2901 / B200-family
57
57
 
58
- After reserving a server-local `usrp` inventory entry, fetch or refresh its
58
+ After reserving a server-local or HostRF-owned `usrp` inventory entry, fetch or refresh its
59
59
  Dynamic v2 package with the reservation token:
60
60
 
61
61
  ```python
@@ -29,7 +29,7 @@ pip install remoterf # Install remoteRF
29
29
 
30
30
  ## NI USRP-2901 / B200-family
31
31
 
32
- After reserving a server-local `usrp` inventory entry, fetch or refresh its
32
+ After reserving a server-local or HostRF-owned `usrp` inventory entry, fetch or refresh its
33
33
  Dynamic v2 package with the reservation token:
34
34
 
35
35
  ```python
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
6
6
 
7
7
  setup(
8
8
  name="remoterf",
9
- version="2.0.4",
9
+ version="2.0.7",
10
10
  author="Ethan Ge",
11
11
  author_email="ethoGalaxy@gmail.com",
12
12
  description="A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.",
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
24
24
 
25
25
 
26
26
 
27
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ngrpc.proto\x12\tremote_rf\"\xa2\x01\n\x11GenericRPCRequest\x12\x15\n\rfunction_name\x18\x01 \x01(\t\x12\x34\n\x04\x61rgs\x18\x02 \x03(\x0b\x32&.remote_rf.GenericRPCRequest.ArgsEntry\x1a@\n\tArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x96\x01\n\x12GenericRPCResponse\x12;\n\x07results\x18\x01 \x03(\x0b\x32*.remote_rf.GenericRPCResponse.ResultsEntry\x1a\x43\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x19\n\nArrayShape\x12\x0b\n\x03\x64im\x18\x01 \x03(\x05\"+\n\rComplexNumber\x12\x0c\n\x04real\x18\x01 \x01(\x02\x12\x0c\n\x04imag\x18\x02 \x01(\x02\"a\n\x11\x43omplexNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12&\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32\x18.remote_rf.ComplexNumber\"D\n\x0eRealNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12\x0c\n\x04\x64\x61ta\x18\x02 \x03(\x02\"\xed\x01\n\x08\x41rgument\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x15\n\x0bint64_value\x18\x02 \x01(\x03H\x00\x12\x15\n\x0b\x66loat_value\x18\x03 \x01(\x02H\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12\x35\n\rcomplex_array\x18\x05 \x01(\x0b\x32\x1c.remote_rf.ComplexNumpyArrayH\x00\x12/\n\nreal_array\x18\x06 \x01(\x0b\x32\x19.remote_rf.RealNumpyArrayH\x00\x12\x14\n\njson_value\x18\x07 \x01(\tH\x00\x42\x07\n\x05value\":\n\x0cNDArrayValue\x12\r\n\x05\x64type\x18\x01 \x01(\t\x12\r\n\x05shape\x18\x02 \x03(\x03\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\xe9\x01\n\x0c\x44ynamicValue\x12\x14\n\nnull_value\x18\x01 \x01(\x08H\x00\x12\x14\n\nbool_value\x18\x02 \x01(\x08H\x00\x12\x15\n\x0bint64_value\x18\x03 \x01(\x12H\x00\x12\x16\n\x0c\x64ouble_value\x18\x04 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x05 \x01(\tH\x00\x12\x15\n\x0b\x62ytes_value\x18\x06 \x01(\x0cH\x00\x12\x14\n\njson_value\x18\x07 \x01(\tH\x00\x12\x30\n\rndarray_value\x18\x08 \x01(\x0b\x32\x17.remote_rf.NDArrayValueH\x00\x42\x07\n\x05value\"B\n\nNamedValue\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.remote_rf.DynamicValue\"B\n\x08Mutation\x12\x0e\n\x06target\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.remote_rf.DynamicValue\"\xb0\x01\n\rErrorEnvelope\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x14\n\x0c\x64\x65tails_json\x18\x03 \x01(\t\x12\x0e\n\x06method\x18\x04 \x01(\t\x12\x18\n\x10native_exception\x18\x05 \x01(\t\x12\x13\n\x0buhd_version\x18\x06 \x01(\t\x12\x11\n\tretryable\x18\x07 \x01(\x08\x12\x18\n\x10\x66\x61tal_to_session\x18\x08 \x01(\x08\"s\n\x10NegotiateRequest\x12\x17\n\x0fschema_versions\x18\x01 \x03(\t\x12!\n\x19\x63ontrol_protocol_versions\x18\x02 \x03(\t\x12#\n\x1bstreaming_protocol_versions\x18\x03 \x03(\t\"\x9a\x01\n\x11NegotiateResponse\x12\x16\n\x0eschema_version\x18\x01 \x01(\t\x12 \n\x18\x63ontrol_protocol_version\x18\x02 \x01(\t\x12\"\n\x1astreaming_protocol_version\x18\x03 \x01(\t\x12\'\n\x05\x65rror\x18\x04 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\":\n\x10GetSchemaRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x17\n\x0fschema_versions\x18\x02 \x03(\t\"~\n\x11GetSchemaResponse\x12\x16\n\x0eschema_version\x18\x01 \x01(\t\x12\x13\n\x0bschema_json\x18\x02 \x01(\t\x12\x13\n\x0bschema_hash\x18\x03 \x01(\t\x12\'\n\x05\x65rror\x18\x04 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"\x88\x01\n\x12OpenSessionRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x1d\n\x15requested_schema_hash\x18\x02 \x01(\t\x12 \n\x18\x63ontrol_protocol_version\x18\x03 \x01(\t\x12\"\n\x1astreaming_protocol_version\x18\x04 \x01(\t\"\xee\x01\n\x13OpenSessionResponse\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x15\n\rdevice_handle\x18\x02 \x01(\t\x12\x13\n\x0bschema_json\x18\x03 \x01(\t\x12\x13\n\x0bschema_hash\x18\x04 \x01(\t\x12\x19\n\x11\x63\x61pabilities_json\x18\x05 \x01(\t\x12\x13\n\x0buhd_version\x18\x06 \x01(\t\x12\x0f\n\x07uhd_abi\x18\x07 \x01(\t\x12\x18\n\x10hardware_profile\x18\x08 \x01(\t\x12\'\n\x05\x65rror\x18\t \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"}\n\rInvokeRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x0e\n\x06handle\x18\x02 \x01(\t\x12\x0e\n\x06method\x18\x03 \x01(\t\x12\x13\n\x0boverload_id\x18\x04 \x01(\t\x12#\n\x04\x61rgs\x18\x05 \x03(\x0b\x32\x15.remote_rf.NamedValue\"\x8a\x01\n\x0eInvokeResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.remote_rf.DynamicValue\x12&\n\tmutations\x18\x02 \x03(\x0b\x32\x13.remote_rf.Mutation\x12\'\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"8\n\x12\x43loseHandleRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x0e\n\x06handle\x18\x02 \x01(\t\")\n\x13\x43loseSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\"H\n\rCloseResponse\x12\x0e\n\x06\x63losed\x18\x01 \x01(\x08\x12\'\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"\xea\x03\n\x0bSampleFrame\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x0e\n\x06handle\x18\x02 \x01(\t\x12\x12\n\ngeneration\x18\x03 \x01(\x04\x12\x14\n\x0coperation_id\x18\x04 \x01(\t\x12\x10\n\x08sequence\x18\x05 \x01(\x04\x12-\n\tdirection\x18\x06 \x01(\x0e\x32\x1a.remote_rf.SampleDirection\x12(\n\x04kind\x18\x07 \x01(\x0e\x32\x1a.remote_rf.SampleFrameKind\x12\r\n\x05\x64type\x18\x08 \x01(\t\x12\r\n\x05shape\x18\t \x03(\x03\x12\x10\n\x08\x63hannels\x18\n \x03(\r\x12\x14\n\x0csample_count\x18\x0b \x01(\x04\x12\x0f\n\x07payload\x18\x0c \x01(\x0c\x12\x15\n\rmetadata_json\x18\r \x01(\t\x12\x18\n\x10\x64\x65vice_time_secs\x18\x0e \x01(\x01\x12\x0f\n\x07\x63redits\x18\x0f \x01(\r\x12\x13\n\x0btimeout_sec\x18\x10 \x01(\x01\x12\x12\n\none_packet\x18\x11 \x01(\x08\x12\x15\n\rend_of_stream\x18\x12 \x01(\x08\x12\x11\n\tcancelled\x18\x13 \x01(\x08\x12\'\n\x05\x65rror\x18\x14 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\x12\r\n\x05\x66lags\x18\x15 \x01(\x04*e\n\x0fSampleDirection\x12 \n\x1cSAMPLE_DIRECTION_UNSPECIFIED\x10\x00\x12\x17\n\x13SAMPLE_DIRECTION_RX\x10\x01\x12\x17\n\x13SAMPLE_DIRECTION_TX\x10\x02*\xf2\x01\n\x0fSampleFrameKind\x12\x1c\n\x18SAMPLE_FRAME_UNSPECIFIED\x10\x00\x12\x15\n\x11SAMPLE_FRAME_OPEN\x10\x01\x12\x18\n\x14SAMPLE_FRAME_REQUEST\x10\x02\x12\x15\n\x11SAMPLE_FRAME_DATA\x10\x03\x12\x17\n\x13SAMPLE_FRAME_RESULT\x10\x04\x12\x17\n\x13SAMPLE_FRAME_CREDIT\x10\x05\x12\x17\n\x13SAMPLE_FRAME_CANCEL\x10\x06\x12\x16\n\x12SAMPLE_FRAME_CLOSE\x10\x07\x12\x16\n\x12SAMPLE_FRAME_ERROR\x10\x08\x32Q\n\nGenericRPC\x12\x43\n\x04\x43\x61ll\x12\x1c.remote_rf.GenericRPCRequest\x1a\x1d.remote_rf.GenericRPCResponse2\xc1\x03\n\x10\x44ynamicControlV2\x12\x46\n\tNegotiate\x12\x1b.remote_rf.NegotiateRequest\x1a\x1c.remote_rf.NegotiateResponse\x12\x46\n\tGetSchema\x12\x1b.remote_rf.GetSchemaRequest\x1a\x1c.remote_rf.GetSchemaResponse\x12L\n\x0bOpenSession\x12\x1d.remote_rf.OpenSessionRequest\x1a\x1e.remote_rf.OpenSessionResponse\x12=\n\x06Invoke\x12\x18.remote_rf.InvokeRequest\x1a\x19.remote_rf.InvokeResponse\x12\x46\n\x0b\x43loseHandle\x12\x1d.remote_rf.CloseHandleRequest\x1a\x18.remote_rf.CloseResponse\x12H\n\x0c\x43loseSession\x12\x1e.remote_rf.CloseSessionRequest\x1a\x18.remote_rf.CloseResponse2R\n\x0cSampleDataV1\x12\x42\n\x0cSampleStream\x12\x16.remote_rf.SampleFrame\x1a\x16.remote_rf.SampleFrame(\x01\x30\x01\x42\x1e\n\x10\x63om.example.demoB\nDemoProtosb\x06proto3')
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ngrpc.proto\x12\tremote_rf\"\xa2\x01\n\x11GenericRPCRequest\x12\x15\n\rfunction_name\x18\x01 \x01(\t\x12\x34\n\x04\x61rgs\x18\x02 \x03(\x0b\x32&.remote_rf.GenericRPCRequest.ArgsEntry\x1a@\n\tArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x96\x01\n\x12GenericRPCResponse\x12;\n\x07results\x18\x01 \x03(\x0b\x32*.remote_rf.GenericRPCResponse.ResultsEntry\x1a\x43\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x19\n\nArrayShape\x12\x0b\n\x03\x64im\x18\x01 \x03(\x05\"+\n\rComplexNumber\x12\x0c\n\x04real\x18\x01 \x01(\x02\x12\x0c\n\x04imag\x18\x02 \x01(\x02\"a\n\x11\x43omplexNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12&\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32\x18.remote_rf.ComplexNumber\"D\n\x0eRealNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12\x0c\n\x04\x64\x61ta\x18\x02 \x03(\x02\"\xb6\x02\n\x08\x41rgument\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x15\n\x0bint64_value\x18\x02 \x01(\x03H\x00\x12\x15\n\x0b\x66loat_value\x18\x03 \x01(\x02H\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12\x35\n\rcomplex_array\x18\x05 \x01(\x0b\x32\x1c.remote_rf.ComplexNumpyArrayH\x00\x12/\n\nreal_array\x18\x06 \x01(\x0b\x32\x19.remote_rf.RealNumpyArrayH\x00\x12\x14\n\njson_value\x18\x07 \x01(\tH\x00\x12\x15\n\x0b\x62ytes_value\x18\x08 \x01(\x0cH\x00\x12\x30\n\rndarray_value\x18\t \x01(\x0b\x32\x17.remote_rf.NDArrayValueH\x00\x42\x07\n\x05value\":\n\x0cNDArrayValue\x12\r\n\x05\x64type\x18\x01 \x01(\t\x12\r\n\x05shape\x18\x02 \x03(\x03\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\xe9\x01\n\x0c\x44ynamicValue\x12\x14\n\nnull_value\x18\x01 \x01(\x08H\x00\x12\x14\n\nbool_value\x18\x02 \x01(\x08H\x00\x12\x15\n\x0bint64_value\x18\x03 \x01(\x12H\x00\x12\x16\n\x0c\x64ouble_value\x18\x04 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x05 \x01(\tH\x00\x12\x15\n\x0b\x62ytes_value\x18\x06 \x01(\x0cH\x00\x12\x14\n\njson_value\x18\x07 \x01(\tH\x00\x12\x30\n\rndarray_value\x18\x08 \x01(\x0b\x32\x17.remote_rf.NDArrayValueH\x00\x42\x07\n\x05value\"B\n\nNamedValue\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.remote_rf.DynamicValue\"B\n\x08Mutation\x12\x0e\n\x06target\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.remote_rf.DynamicValue\"\xb0\x01\n\rErrorEnvelope\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x14\n\x0c\x64\x65tails_json\x18\x03 \x01(\t\x12\x0e\n\x06method\x18\x04 \x01(\t\x12\x18\n\x10native_exception\x18\x05 \x01(\t\x12\x13\n\x0buhd_version\x18\x06 \x01(\t\x12\x11\n\tretryable\x18\x07 \x01(\x08\x12\x18\n\x10\x66\x61tal_to_session\x18\x08 \x01(\x08\"s\n\x10NegotiateRequest\x12\x17\n\x0fschema_versions\x18\x01 \x03(\t\x12!\n\x19\x63ontrol_protocol_versions\x18\x02 \x03(\t\x12#\n\x1bstreaming_protocol_versions\x18\x03 \x03(\t\"\x9a\x01\n\x11NegotiateResponse\x12\x16\n\x0eschema_version\x18\x01 \x01(\t\x12 \n\x18\x63ontrol_protocol_version\x18\x02 \x01(\t\x12\"\n\x1astreaming_protocol_version\x18\x03 \x01(\t\x12\'\n\x05\x65rror\x18\x04 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\":\n\x10GetSchemaRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x17\n\x0fschema_versions\x18\x02 \x03(\t\"~\n\x11GetSchemaResponse\x12\x16\n\x0eschema_version\x18\x01 \x01(\t\x12\x13\n\x0bschema_json\x18\x02 \x01(\t\x12\x13\n\x0bschema_hash\x18\x03 \x01(\t\x12\'\n\x05\x65rror\x18\x04 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"\x88\x01\n\x12OpenSessionRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x1d\n\x15requested_schema_hash\x18\x02 \x01(\t\x12 \n\x18\x63ontrol_protocol_version\x18\x03 \x01(\t\x12\"\n\x1astreaming_protocol_version\x18\x04 \x01(\t\"\xee\x01\n\x13OpenSessionResponse\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x15\n\rdevice_handle\x18\x02 \x01(\t\x12\x13\n\x0bschema_json\x18\x03 \x01(\t\x12\x13\n\x0bschema_hash\x18\x04 \x01(\t\x12\x19\n\x11\x63\x61pabilities_json\x18\x05 \x01(\t\x12\x13\n\x0buhd_version\x18\x06 \x01(\t\x12\x0f\n\x07uhd_abi\x18\x07 \x01(\t\x12\x18\n\x10hardware_profile\x18\x08 \x01(\t\x12\'\n\x05\x65rror\x18\t \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"}\n\rInvokeRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x0e\n\x06handle\x18\x02 \x01(\t\x12\x0e\n\x06method\x18\x03 \x01(\t\x12\x13\n\x0boverload_id\x18\x04 \x01(\t\x12#\n\x04\x61rgs\x18\x05 \x03(\x0b\x32\x15.remote_rf.NamedValue\"\x8a\x01\n\x0eInvokeResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.remote_rf.DynamicValue\x12&\n\tmutations\x18\x02 \x03(\x0b\x32\x13.remote_rf.Mutation\x12\'\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"8\n\x12\x43loseHandleRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x0e\n\x06handle\x18\x02 \x01(\t\")\n\x13\x43loseSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\"H\n\rCloseResponse\x12\x0e\n\x06\x63losed\x18\x01 \x01(\x08\x12\'\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\"\xea\x03\n\x0bSampleFrame\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x0e\n\x06handle\x18\x02 \x01(\t\x12\x12\n\ngeneration\x18\x03 \x01(\x04\x12\x14\n\x0coperation_id\x18\x04 \x01(\t\x12\x10\n\x08sequence\x18\x05 \x01(\x04\x12-\n\tdirection\x18\x06 \x01(\x0e\x32\x1a.remote_rf.SampleDirection\x12(\n\x04kind\x18\x07 \x01(\x0e\x32\x1a.remote_rf.SampleFrameKind\x12\r\n\x05\x64type\x18\x08 \x01(\t\x12\r\n\x05shape\x18\t \x03(\x03\x12\x10\n\x08\x63hannels\x18\n \x03(\r\x12\x14\n\x0csample_count\x18\x0b \x01(\x04\x12\x0f\n\x07payload\x18\x0c \x01(\x0c\x12\x15\n\rmetadata_json\x18\r \x01(\t\x12\x18\n\x10\x64\x65vice_time_secs\x18\x0e \x01(\x01\x12\x0f\n\x07\x63redits\x18\x0f \x01(\r\x12\x13\n\x0btimeout_sec\x18\x10 \x01(\x01\x12\x12\n\none_packet\x18\x11 \x01(\x08\x12\x15\n\rend_of_stream\x18\x12 \x01(\x08\x12\x11\n\tcancelled\x18\x13 \x01(\x08\x12\'\n\x05\x65rror\x18\x14 \x01(\x0b\x32\x18.remote_rf.ErrorEnvelope\x12\r\n\x05\x66lags\x18\x15 \x01(\x04*e\n\x0fSampleDirection\x12 \n\x1cSAMPLE_DIRECTION_UNSPECIFIED\x10\x00\x12\x17\n\x13SAMPLE_DIRECTION_RX\x10\x01\x12\x17\n\x13SAMPLE_DIRECTION_TX\x10\x02*\xf2\x01\n\x0fSampleFrameKind\x12\x1c\n\x18SAMPLE_FRAME_UNSPECIFIED\x10\x00\x12\x15\n\x11SAMPLE_FRAME_OPEN\x10\x01\x12\x18\n\x14SAMPLE_FRAME_REQUEST\x10\x02\x12\x15\n\x11SAMPLE_FRAME_DATA\x10\x03\x12\x17\n\x13SAMPLE_FRAME_RESULT\x10\x04\x12\x17\n\x13SAMPLE_FRAME_CREDIT\x10\x05\x12\x17\n\x13SAMPLE_FRAME_CANCEL\x10\x06\x12\x16\n\x12SAMPLE_FRAME_CLOSE\x10\x07\x12\x16\n\x12SAMPLE_FRAME_ERROR\x10\x08\x32Q\n\nGenericRPC\x12\x43\n\x04\x43\x61ll\x12\x1c.remote_rf.GenericRPCRequest\x1a\x1d.remote_rf.GenericRPCResponse2\xc1\x03\n\x10\x44ynamicControlV2\x12\x46\n\tNegotiate\x12\x1b.remote_rf.NegotiateRequest\x1a\x1c.remote_rf.NegotiateResponse\x12\x46\n\tGetSchema\x12\x1b.remote_rf.GetSchemaRequest\x1a\x1c.remote_rf.GetSchemaResponse\x12L\n\x0bOpenSession\x12\x1d.remote_rf.OpenSessionRequest\x1a\x1e.remote_rf.OpenSessionResponse\x12=\n\x06Invoke\x12\x18.remote_rf.InvokeRequest\x1a\x19.remote_rf.InvokeResponse\x12\x46\n\x0b\x43loseHandle\x12\x1d.remote_rf.CloseHandleRequest\x1a\x18.remote_rf.CloseResponse\x12H\n\x0c\x43loseSession\x12\x1e.remote_rf.CloseSessionRequest\x1a\x18.remote_rf.CloseResponse2R\n\x0cSampleDataV1\x12\x42\n\x0cSampleStream\x12\x16.remote_rf.SampleFrame\x1a\x16.remote_rf.SampleFrame(\x01\x30\x01\x42\x1e\n\x10\x63om.example.demoB\nDemoProtosb\x06proto3')
28
28
 
29
29
  _globals = globals()
30
30
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -36,10 +36,10 @@ if not _descriptor._USE_C_DESCRIPTORS:
36
36
  _globals['_GENERICRPCREQUEST_ARGSENTRY']._serialized_options = b'8\001'
37
37
  _globals['_GENERICRPCRESPONSE_RESULTSENTRY']._loaded_options = None
38
38
  _globals['_GENERICRPCRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
39
- _globals['_SAMPLEDIRECTION']._serialized_start=3213
40
- _globals['_SAMPLEDIRECTION']._serialized_end=3314
41
- _globals['_SAMPLEFRAMEKIND']._serialized_start=3317
42
- _globals['_SAMPLEFRAMEKIND']._serialized_end=3559
39
+ _globals['_SAMPLEDIRECTION']._serialized_start=3286
40
+ _globals['_SAMPLEDIRECTION']._serialized_end=3387
41
+ _globals['_SAMPLEFRAMEKIND']._serialized_start=3390
42
+ _globals['_SAMPLEFRAMEKIND']._serialized_end=3632
43
43
  _globals['_GENERICRPCREQUEST']._serialized_start=26
44
44
  _globals['_GENERICRPCREQUEST']._serialized_end=188
45
45
  _globals['_GENERICRPCREQUEST_ARGSENTRY']._serialized_start=124
@@ -57,45 +57,45 @@ if not _descriptor._USE_C_DESCRIPTORS:
57
57
  _globals['_REALNUMPYARRAY']._serialized_start=514
58
58
  _globals['_REALNUMPYARRAY']._serialized_end=582
59
59
  _globals['_ARGUMENT']._serialized_start=585
60
- _globals['_ARGUMENT']._serialized_end=822
61
- _globals['_NDARRAYVALUE']._serialized_start=824
62
- _globals['_NDARRAYVALUE']._serialized_end=882
63
- _globals['_DYNAMICVALUE']._serialized_start=885
64
- _globals['_DYNAMICVALUE']._serialized_end=1118
65
- _globals['_NAMEDVALUE']._serialized_start=1120
66
- _globals['_NAMEDVALUE']._serialized_end=1186
67
- _globals['_MUTATION']._serialized_start=1188
68
- _globals['_MUTATION']._serialized_end=1254
69
- _globals['_ERRORENVELOPE']._serialized_start=1257
70
- _globals['_ERRORENVELOPE']._serialized_end=1433
71
- _globals['_NEGOTIATEREQUEST']._serialized_start=1435
72
- _globals['_NEGOTIATEREQUEST']._serialized_end=1550
73
- _globals['_NEGOTIATERESPONSE']._serialized_start=1553
74
- _globals['_NEGOTIATERESPONSE']._serialized_end=1707
75
- _globals['_GETSCHEMAREQUEST']._serialized_start=1709
76
- _globals['_GETSCHEMAREQUEST']._serialized_end=1767
77
- _globals['_GETSCHEMARESPONSE']._serialized_start=1769
78
- _globals['_GETSCHEMARESPONSE']._serialized_end=1895
79
- _globals['_OPENSESSIONREQUEST']._serialized_start=1898
80
- _globals['_OPENSESSIONREQUEST']._serialized_end=2034
81
- _globals['_OPENSESSIONRESPONSE']._serialized_start=2037
82
- _globals['_OPENSESSIONRESPONSE']._serialized_end=2275
83
- _globals['_INVOKEREQUEST']._serialized_start=2277
84
- _globals['_INVOKEREQUEST']._serialized_end=2402
85
- _globals['_INVOKERESPONSE']._serialized_start=2405
86
- _globals['_INVOKERESPONSE']._serialized_end=2543
87
- _globals['_CLOSEHANDLEREQUEST']._serialized_start=2545
88
- _globals['_CLOSEHANDLEREQUEST']._serialized_end=2601
89
- _globals['_CLOSESESSIONREQUEST']._serialized_start=2603
90
- _globals['_CLOSESESSIONREQUEST']._serialized_end=2644
91
- _globals['_CLOSERESPONSE']._serialized_start=2646
92
- _globals['_CLOSERESPONSE']._serialized_end=2718
93
- _globals['_SAMPLEFRAME']._serialized_start=2721
94
- _globals['_SAMPLEFRAME']._serialized_end=3211
95
- _globals['_GENERICRPC']._serialized_start=3561
96
- _globals['_GENERICRPC']._serialized_end=3642
97
- _globals['_DYNAMICCONTROLV2']._serialized_start=3645
98
- _globals['_DYNAMICCONTROLV2']._serialized_end=4094
99
- _globals['_SAMPLEDATAV1']._serialized_start=4096
100
- _globals['_SAMPLEDATAV1']._serialized_end=4178
60
+ _globals['_ARGUMENT']._serialized_end=895
61
+ _globals['_NDARRAYVALUE']._serialized_start=897
62
+ _globals['_NDARRAYVALUE']._serialized_end=955
63
+ _globals['_DYNAMICVALUE']._serialized_start=958
64
+ _globals['_DYNAMICVALUE']._serialized_end=1191
65
+ _globals['_NAMEDVALUE']._serialized_start=1193
66
+ _globals['_NAMEDVALUE']._serialized_end=1259
67
+ _globals['_MUTATION']._serialized_start=1261
68
+ _globals['_MUTATION']._serialized_end=1327
69
+ _globals['_ERRORENVELOPE']._serialized_start=1330
70
+ _globals['_ERRORENVELOPE']._serialized_end=1506
71
+ _globals['_NEGOTIATEREQUEST']._serialized_start=1508
72
+ _globals['_NEGOTIATEREQUEST']._serialized_end=1623
73
+ _globals['_NEGOTIATERESPONSE']._serialized_start=1626
74
+ _globals['_NEGOTIATERESPONSE']._serialized_end=1780
75
+ _globals['_GETSCHEMAREQUEST']._serialized_start=1782
76
+ _globals['_GETSCHEMAREQUEST']._serialized_end=1840
77
+ _globals['_GETSCHEMARESPONSE']._serialized_start=1842
78
+ _globals['_GETSCHEMARESPONSE']._serialized_end=1968
79
+ _globals['_OPENSESSIONREQUEST']._serialized_start=1971
80
+ _globals['_OPENSESSIONREQUEST']._serialized_end=2107
81
+ _globals['_OPENSESSIONRESPONSE']._serialized_start=2110
82
+ _globals['_OPENSESSIONRESPONSE']._serialized_end=2348
83
+ _globals['_INVOKEREQUEST']._serialized_start=2350
84
+ _globals['_INVOKEREQUEST']._serialized_end=2475
85
+ _globals['_INVOKERESPONSE']._serialized_start=2478
86
+ _globals['_INVOKERESPONSE']._serialized_end=2616
87
+ _globals['_CLOSEHANDLEREQUEST']._serialized_start=2618
88
+ _globals['_CLOSEHANDLEREQUEST']._serialized_end=2674
89
+ _globals['_CLOSESESSIONREQUEST']._serialized_start=2676
90
+ _globals['_CLOSESESSIONREQUEST']._serialized_end=2717
91
+ _globals['_CLOSERESPONSE']._serialized_start=2719
92
+ _globals['_CLOSERESPONSE']._serialized_end=2791
93
+ _globals['_SAMPLEFRAME']._serialized_start=2794
94
+ _globals['_SAMPLEFRAME']._serialized_end=3284
95
+ _globals['_GENERICRPC']._serialized_start=3634
96
+ _globals['_GENERICRPC']._serialized_end=3715
97
+ _globals['_DYNAMICCONTROLV2']._serialized_start=3718
98
+ _globals['_DYNAMICCONTROLV2']._serialized_end=4167
99
+ _globals['_SAMPLEDATAV1']._serialized_start=4169
100
+ _globals['_SAMPLEDATAV1']._serialized_end=4251
101
101
  # @@protoc_insertion_point(module_scope)
@@ -1,10 +1,55 @@
1
- from ..grpc import grpc_pb2, grpc_pb2_grpc
1
+ """Serialization helpers for the legacy GenericRPC protocol."""
2
+ from __future__ import annotations
3
+
2
4
  import json
5
+ import math
6
+ from typing import Any
7
+
3
8
  import numpy as np
4
9
 
10
+ from ..grpc import grpc_pb2
11
+
5
12
  _JSON_TYPE_KEY = "__remoterf_json_type__"
13
+ _MAX_NDARRAY_BYTES = 64 * 1024 * 1024
14
+ _MAX_NDARRAY_DIMENSIONS = 8
15
+ _SUPPORTED_NDARRAY_KINDS = {"b", "i", "u", "f", "c"}
16
+
17
+
18
+ def _validate_ndarray(dtype: np.dtype, shape) -> int:
19
+ """Return the expected payload length for a safe numeric ndarray."""
20
+ if dtype.hasobject or dtype.kind not in _SUPPORTED_NDARRAY_KINDS:
21
+ raise ValueError(f"unsupported ndarray dtype: {dtype}")
22
+
23
+ normalized_shape = tuple(int(item) for item in shape)
24
+ if (
25
+ len(normalized_shape) > _MAX_NDARRAY_DIMENSIONS
26
+ or any(item < 0 for item in normalized_shape)
27
+ ):
28
+ raise ValueError("invalid ndarray shape")
29
+
30
+ expected = math.prod(normalized_shape) * dtype.itemsize
31
+ if expected > _MAX_NDARRAY_BYTES:
32
+ raise ValueError(f"ndarray exceeds {_MAX_NDARRAY_BYTES} bytes")
33
+ return expected
6
34
 
7
- def _json_safe(value):
35
+
36
+ def _decode_ndarray(descriptor: grpc_pb2.NDArrayValue) -> np.ndarray:
37
+ try:
38
+ dtype = np.dtype(descriptor.dtype)
39
+ except (TypeError, ValueError) as exc:
40
+ raise ValueError(f"invalid ndarray dtype: {descriptor.dtype!r}") from exc
41
+
42
+ shape = tuple(int(item) for item in descriptor.shape)
43
+ expected = _validate_ndarray(dtype, shape)
44
+ actual = len(descriptor.data)
45
+ if actual != expected:
46
+ raise ValueError(
47
+ f"ndarray byte length mismatch: expected {expected}, got {actual}"
48
+ )
49
+ return np.frombuffer(descriptor.data, dtype=dtype).reshape(shape).copy()
50
+
51
+
52
+ def _json_safe(value: Any):
8
53
  if hasattr(value, "as_payload"):
9
54
  return _json_safe(value.as_payload())
10
55
  if isinstance(value, np.ndarray):
@@ -27,21 +72,26 @@ def _json_safe(value):
27
72
  "complex": False,
28
73
  "data": array.tolist(),
29
74
  }
30
- if isinstance(value, (np.bool_,)):
75
+ if isinstance(value, np.bool_):
31
76
  return bool(value)
32
- if isinstance(value, (np.integer,)):
77
+ if isinstance(value, np.integer):
33
78
  return int(value)
34
- if isinstance(value, (np.floating,)):
79
+ if isinstance(value, np.floating):
35
80
  return float(value)
36
81
  if isinstance(value, complex):
37
- return {_JSON_TYPE_KEY: "complex", "real": float(value.real), "imag": float(value.imag)}
82
+ return {
83
+ _JSON_TYPE_KEY: "complex",
84
+ "real": float(value.real),
85
+ "imag": float(value.imag),
86
+ }
38
87
  if isinstance(value, dict):
39
88
  return {str(key): _json_safe(item) for key, item in value.items()}
40
89
  if isinstance(value, (list, tuple)):
41
90
  return [_json_safe(item) for item in value]
42
91
  return value
43
92
 
44
- def _json_restore(value):
93
+
94
+ def _json_restore(value: Any):
45
95
  if isinstance(value, dict):
46
96
  kind = value.get(_JSON_TYPE_KEY)
47
97
  if kind == "ndarray":
@@ -58,30 +108,36 @@ def _json_restore(value):
58
108
  return [_json_restore(item) for item in value]
59
109
  return value
60
110
 
61
- def unmap_arg(arg):
62
- if arg.HasField('int64_value'):
111
+
112
+ def unmap_arg(arg: grpc_pb2.Argument):
113
+ kind = arg.WhichOneof("value")
114
+ if kind == "int64_value":
63
115
  return arg.int64_value
64
- elif arg.HasField('float_value'):
116
+ if kind == "float_value":
65
117
  return arg.float_value
66
- elif arg.HasField('string_value'):
118
+ if kind == "string_value":
67
119
  return arg.string_value
68
- elif arg.HasField('bool_value'):
120
+ if kind == "bool_value":
69
121
  return arg.bool_value
70
- elif arg.HasField('real_array'):
122
+ if kind == "ndarray_value":
123
+ return _decode_ndarray(arg.ndarray_value)
124
+ if kind == "real_array":
71
125
  shape = tuple(arg.real_array.shape.dim)
72
126
  return np.array(arg.real_array.data, dtype=np.float64).reshape(shape)
73
- elif arg.HasField('complex_array'):
127
+ if kind == "complex_array":
74
128
  shape = tuple(arg.complex_array.shape.dim)
75
- data = [complex(c.real, c.imag) for c in arg.complex_array.data]
129
+ data = [complex(item.real, item.imag) for item in arg.complex_array.data]
76
130
  return np.array(data, dtype=np.complex64).reshape(shape)
77
- elif arg.HasField('json_value'):
131
+ if kind == "json_value":
78
132
  return _json_restore(json.loads(arg.json_value))
79
- else:
80
- raise ValueError(f"Unknown argument type during unmapping: {arg}")
81
-
82
- def map_arg(value):
133
+ if kind == "bytes_value":
134
+ return bytes(arg.bytes_value)
135
+ raise ValueError(f"Unknown argument type during unmapping: {arg}")
136
+
137
+
138
+ def map_arg(value: Any) -> grpc_pb2.Argument:
83
139
  arg = grpc_pb2.Argument()
84
-
140
+
85
141
  if isinstance(value, (bool, np.bool_)):
86
142
  arg.bool_value = bool(value)
87
143
  elif hasattr(value, "as_payload"):
@@ -94,6 +150,8 @@ def map_arg(value):
94
150
  arg.float_value = float(value)
95
151
  elif isinstance(value, str):
96
152
  arg.string_value = value
153
+ elif isinstance(value, (bytes, bytearray, memoryview)):
154
+ arg.bytes_value = bytes(value)
97
155
  elif isinstance(value, (list, tuple)):
98
156
  try:
99
157
  array = np.asarray(value)
@@ -110,51 +168,33 @@ def map_arg(value):
110
168
  elif isinstance(value, np.ndarray):
111
169
  if value.dtype == object:
112
170
  raise ValueError(f"Cannot map object-dtype array: {value!r}")
113
- if value.dtype.kind not in {"b", "i", "u", "f", "c"}:
114
- arg.json_value = json.dumps(_json_safe(value.tolist()), separators=(",", ":"))
171
+ if value.dtype.kind not in _SUPPORTED_NDARRAY_KINDS:
172
+ arg.json_value = json.dumps(
173
+ _json_safe(value.tolist()), separators=(",", ":")
174
+ )
115
175
  return arg
116
- if np.iscomplexobj(value):
117
- complex_array = arg.complex_array
118
- complex_array.shape.dim.extend(value.shape)
119
- for num in value.ravel():
120
- complex_num = complex_array.data.add()
121
- complex_num.real = float(num.real)
122
- complex_num.imag = float(num.imag)
123
- else:
124
- float_array = arg.real_array
125
- float_array.shape.dim.extend(value.shape)
126
- float_array.data.extend(np.asarray(value, dtype=np.float32).ravel())
176
+
177
+ array = np.asarray(value)
178
+ _validate_ndarray(array.dtype, array.shape)
179
+ if not array.flags.c_contiguous:
180
+ array = np.ascontiguousarray(array)
181
+ descriptor = arg.ndarray_value
182
+ descriptor.dtype = array.dtype.str
183
+ descriptor.shape.extend(array.shape)
184
+ descriptor.data = array.tobytes(order="C")
127
185
  else:
128
186
  raise ValueError(f"Unknown argument type during mapping: {value}")
129
187
  return arg
130
-
131
- def map_array_proto(np_array):
132
- arg = grpc_pb2.Argument()
133
-
134
- # Check if the array is complex
135
- if np.iscomplexobj(np_array):
136
- complex_array = grpc_pb2.ComplexArray()
137
- for num in np_array.flat:
138
- complex_number = complex_array.data.add()
139
- complex_number.real = num.real
140
- complex_number.imag = num.imag
141
- arg.complex_array.CopyFrom(complex_array)
142
- else:
143
- # Handle as a regular float array
144
- float_array = grpc_pb2.FloatArray()
145
- float_array.data.extend(np_array.flat)
146
- arg.float_array.CopyFrom(float_array)
147
188
 
148
- return arg
149
189
 
150
- def unmap_array_proto(arg):
151
- # Check which type of array is available and convert appropriately
152
- if arg.HasField('complex_array'):
153
- # Convert ComplexArray to a numpy array of complex numbers
154
- data = [complex(cn.real, cn.imag) for cn in arg.complex_array.data]
155
- return np.array(data, dtype=np.complex64)
156
- elif arg.HasField('float_array'):
157
- # Convert FloatArray to a numpy array of floats
158
- return np.array(arg.float_array.data, dtype=np.float32)
159
- else:
190
+ def map_array_proto(np_array) -> grpc_pb2.Argument:
191
+ """Backward-compatible wrapper around :func:`map_arg`."""
192
+ return map_arg(np.asarray(np_array))
193
+
194
+
195
+ def unmap_array_proto(arg: grpc_pb2.Argument) -> np.ndarray:
196
+ """Backward-compatible array-only wrapper around :func:`unmap_arg`."""
197
+ value = unmap_arg(arg)
198
+ if not isinstance(value, np.ndarray):
160
199
  raise ValueError("Argument does not contain a recognizable array.")
200
+ return value
@@ -14,7 +14,16 @@ import numpy as np
14
14
 
15
15
  from ..core.dynamic_v2_transport import DynamicV2Transport
16
16
  from ..core.v2_errors import RemoteRFProtocolError
17
- from .support import uhd_v2
17
+ from .support import uhd_dsp, uhd_v2
18
+
19
+ _REMOTE_STREAM_BATCH_SAMPS = 64 * 1024
20
+ _CPU_FORMAT_DTYPES = {
21
+ "fc32": np.dtype(np.complex64),
22
+ "fc64": np.dtype(np.complex128),
23
+ "f32": np.dtype(np.float32),
24
+ "f64": np.dtype(np.float64),
25
+ "s16": np.dtype(np.int16),
26
+ }
18
27
 
19
28
  _SUPPORTED_SAMPLE_DTYPES = {
20
29
  np.dtype(np.complex64),
@@ -295,6 +304,7 @@ class RemoteHandleProxy:
295
304
  self._generation = int(generation)
296
305
  self._closed = False
297
306
  self._channels = []
307
+ self._cpu_format = "fc32"
298
308
  self._sequence = 1
299
309
  self._finalizer = weakref.finalize(
300
310
  self,
@@ -358,6 +368,20 @@ class RemoteHandleProxy:
358
368
  class RXStreamer(RemoteHandleProxy):
359
369
  _type_id = "uhd.usrp.RXStreamer"
360
370
 
371
+ def get_max_num_samps(self):
372
+ """Return the efficient RemoteRF batch size, bounded by wire limits."""
373
+ self._ensure_open()
374
+ maximum_bytes = int(
375
+ self._owner._capabilities.get("remote_resource_limits", {}).get(
376
+ "maximum_sample_payload_bytes",
377
+ 4 * 1024 * 1024,
378
+ )
379
+ )
380
+ dtype = _CPU_FORMAT_DTYPES.get(self._cpu_format, np.dtype(np.complex64))
381
+ channels = max(1, len(self._channels))
382
+ payload_samps = maximum_bytes // (dtype.itemsize * channels)
383
+ return max(1, min(_REMOTE_STREAM_BATCH_SAMPS, payload_samps))
384
+
361
385
  def recv(self, buffs, *args, **kwargs):
362
386
  self._ensure_open()
363
387
  buffer = np.asarray(buffs)
@@ -436,6 +460,20 @@ class RXStreamer(RemoteHandleProxy):
436
460
  class TXStreamer(RemoteHandleProxy):
437
461
  _type_id = "uhd.usrp.TXStreamer"
438
462
 
463
+ def get_max_num_samps(self):
464
+ """Return the efficient RemoteRF batch size, bounded by wire limits."""
465
+ self._ensure_open()
466
+ maximum_bytes = int(
467
+ self._owner._capabilities.get("remote_resource_limits", {}).get(
468
+ "maximum_sample_payload_bytes",
469
+ 4 * 1024 * 1024,
470
+ )
471
+ )
472
+ dtype = _CPU_FORMAT_DTYPES.get(self._cpu_format, np.dtype(np.complex64))
473
+ channels = max(1, len(self._channels))
474
+ payload_samps = maximum_bytes // (dtype.itemsize * channels)
475
+ return max(1, min(_REMOTE_STREAM_BATCH_SAMPS, payload_samps))
476
+
439
477
  def send(self, buffs, *args, **kwargs):
440
478
  self._ensure_open()
441
479
  samples = np.asarray(buffs)
@@ -684,6 +722,9 @@ def build_uhd_bindings(schema: dict, *, transport_factory=DynamicV2Transport):
684
722
  stream_args = bound["__args__"][0]
685
723
  if stream_args is not None:
686
724
  proxy._channels = list(getattr(stream_args, "channels", ()) or ())
725
+ proxy._cpu_format = str(
726
+ getattr(stream_args, "cpu_format", "fc32") or "fc32"
727
+ ).lower()
687
728
  return proxy
688
729
  return uhd_v2.decode_snapshot(result)
689
730
 
@@ -770,6 +811,13 @@ def build_uhd_bindings(schema: dict, *, transport_factory=DynamicV2Transport):
770
811
  TXMetadataEventCode=uhd_v2.TXMetadataEventCode,
771
812
  SensorValue=uhd_v2.SensorValue,
772
813
  )
814
+ uhd.dsp = types.SimpleNamespace(
815
+ signals=types.SimpleNamespace(
816
+ get_continuous_tone=uhd_dsp.get_continuous_tone,
817
+ get_power_dbfs=uhd_dsp.get_power_dbfs,
818
+ get_usrp_power=uhd_dsp.make_get_usrp_power(uhd),
819
+ )
820
+ )
773
821
  uhd.filters = types.SimpleNamespace(
774
822
  FilterType=uhd_v2.FilterType,
775
823
  FilterInfoBase=uhd_v2.FilterInfoBase,
@@ -0,0 +1,76 @@
1
+ """Client-local signal helpers compatible with :mod:`uhd.dsp.signals`."""
2
+ from __future__ import annotations
3
+
4
+ import math
5
+
6
+ import numpy as np
7
+
8
+
9
+ def get_continuous_tone(
10
+ rate,
11
+ freq,
12
+ ampl,
13
+ desired_size=None,
14
+ max_size=None,
15
+ waveform="sine",
16
+ ):
17
+ """Generate a repeatable complex waveform using UHD's public semantics."""
18
+ desired_size = desired_size or float(rate)
19
+ max_size = max_size or 100e6
20
+ assert rate > freq
21
+
22
+ common = math.gcd(int(rate), int(freq))
23
+ reduced_rate = int(rate) / common
24
+ reduced_freq = int(freq) / common
25
+ length = int(max(reduced_freq * reduced_rate, 1))
26
+ normalized_freq = freq / rate
27
+
28
+ if waveform in {"sine", "square"}:
29
+ phase = 2j * np.pi * normalized_freq * np.arange(length)
30
+ tone = np.exp(phase).astype(np.complex64, copy=False)
31
+ tone = np.sign(tone) * ampl if waveform == "square" else tone * ampl
32
+ elif waveform == "ramp":
33
+ indexes = np.arange(length)
34
+ tone = np.asarray(
35
+ 2 * (indexes * normalized_freq - np.floor(0.5 + indexes * normalized_freq)),
36
+ dtype=np.complex64,
37
+ )
38
+ elif waveform == "const":
39
+ tone = np.ones(length, dtype=np.complex64) * ampl
40
+ else:
41
+ raise KeyError(f"Invalid waveform type: `{waveform}'")
42
+
43
+ if length < desired_size:
44
+ tone = np.tile(tone, int(desired_size // length))
45
+ if length > max_size:
46
+ raise ValueError("Cannot create a TX buffer! Rate/Freq ratio is too odd.")
47
+ return tone
48
+
49
+
50
+ def get_power_dbfs(signal):
51
+ """Return variance power in dB relative to digital full scale."""
52
+ return 10 * np.log10(np.var(signal))
53
+
54
+
55
+ def make_get_usrp_power(uhd_module):
56
+ """Bind the receive-power helper to a generated UHD compatibility module."""
57
+
58
+ def get_usrp_power(streamer, num_samps=1e6, chan=0):
59
+ sample_count = int(num_samps)
60
+ receive_buffer = np.zeros(
61
+ (streamer.get_num_channels(), sample_count),
62
+ dtype=np.complex64,
63
+ )
64
+ metadata = uhd_module.types.RXMetadata()
65
+ command = uhd_module.types.StreamCMD(uhd_module.types.StreamMode.num_done)
66
+ command.num_samps = sample_count
67
+ command.stream_now = True
68
+ streamer.issue_stream_cmd(command)
69
+ received = streamer.recv(receive_buffer, metadata, 5.0)
70
+ if received != sample_count:
71
+ raise RuntimeError(
72
+ "ERROR! get_usrp_power(): Did not receive the correct number of samples!"
73
+ )
74
+ return get_power_dbfs(receive_buffer[chan])
75
+
76
+ return get_usrp_power