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.
- {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7}/PKG-INFO +2 -2
- {remoterf-2.0.4 → remoterf-2.0.7}/README.md +1 -1
- {remoterf-2.0.4 → remoterf-2.0.7}/setup.py +1 -1
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/grpc_pb2.py +46 -46
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/process_arg.py +102 -62
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/dynamic_v2.py +49 -1
- remoterf-2.0.7/src/remoteRF/drivers/support/uhd_dsp.py +76 -0
- remoterf-2.0.7/src/remoteRF/drivers/usrp/usrp_remote.py +8 -0
- {remoterf-2.0.4 → remoterf-2.0.7/src/remoterf.egg-info}/PKG-INFO +2 -2
- remoterf-2.0.7/src/remoterf.egg-info/SOURCES.txt +51 -0
- remoterf-2.0.7/src/remoterf.egg-info/top_level.txt +1 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/tests/test_dynamic_v2.py +47 -1
- remoterf-2.0.7/tests/test_process_arg.py +218 -0
- remoterf-2.0.4/LICENSE +0 -21
- remoterf-2.0.4/src/remoteRF/drivers/usrp/usrp_remote.py +0 -8
- remoterf-2.0.4/src/remoteRF.egg-info/SOURCES.txt +0 -55
- remoterf-2.0.4/src/remoteRF.egg-info/top_level.txt +0 -1
- remoterf-2.0.4/tests/test_process_arg.py +0 -110
- {remoterf-2.0.4 → remoterf-2.0.7}/MANIFEST.in +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/setup.cfg +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/grpc/v2_codec.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/tos_notice.txt +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/ansi_codes.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/api_token.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/common/utils/list_string.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/config/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/config/cert_fetcher.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/config/config.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/acc_login.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/app.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/banner_note.txt +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/dynamic_v2_transport.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/grpc_acc.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/grpc_client.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/core/v2_errors.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/adalm_pluto/pluto_remote.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/dynamic_device.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/support/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/support/uhd.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/support/uhd_v2.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/usrp/__init__.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/drivers/usrp/usrp_remote.pyi +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/remoterf_cli.py +0 -0
- {remoterf-2.0.4 → remoterf-2.0.7}/src/remoteRF/version.py +0 -0
- {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7/src/remoterf.egg-info}/dependency_links.txt +0 -0
- {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7/src/remoterf.egg-info}/entry_points.txt +0 -0
- {remoterf-2.0.4/src/remoteRF.egg-info → remoterf-2.0.7/src/remoterf.egg-info}/requires.txt +0 -0
- {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.
|
|
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.
|
|
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\"\
|
|
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=
|
|
40
|
-
_globals['_SAMPLEDIRECTION']._serialized_end=
|
|
41
|
-
_globals['_SAMPLEFRAMEKIND']._serialized_start=
|
|
42
|
-
_globals['_SAMPLEFRAMEKIND']._serialized_end=
|
|
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=
|
|
61
|
-
_globals['_NDARRAYVALUE']._serialized_start=
|
|
62
|
-
_globals['_NDARRAYVALUE']._serialized_end=
|
|
63
|
-
_globals['_DYNAMICVALUE']._serialized_start=
|
|
64
|
-
_globals['_DYNAMICVALUE']._serialized_end=
|
|
65
|
-
_globals['_NAMEDVALUE']._serialized_start=
|
|
66
|
-
_globals['_NAMEDVALUE']._serialized_end=
|
|
67
|
-
_globals['_MUTATION']._serialized_start=
|
|
68
|
-
_globals['_MUTATION']._serialized_end=
|
|
69
|
-
_globals['_ERRORENVELOPE']._serialized_start=
|
|
70
|
-
_globals['_ERRORENVELOPE']._serialized_end=
|
|
71
|
-
_globals['_NEGOTIATEREQUEST']._serialized_start=
|
|
72
|
-
_globals['_NEGOTIATEREQUEST']._serialized_end=
|
|
73
|
-
_globals['_NEGOTIATERESPONSE']._serialized_start=
|
|
74
|
-
_globals['_NEGOTIATERESPONSE']._serialized_end=
|
|
75
|
-
_globals['_GETSCHEMAREQUEST']._serialized_start=
|
|
76
|
-
_globals['_GETSCHEMAREQUEST']._serialized_end=
|
|
77
|
-
_globals['_GETSCHEMARESPONSE']._serialized_start=
|
|
78
|
-
_globals['_GETSCHEMARESPONSE']._serialized_end=
|
|
79
|
-
_globals['_OPENSESSIONREQUEST']._serialized_start=
|
|
80
|
-
_globals['_OPENSESSIONREQUEST']._serialized_end=
|
|
81
|
-
_globals['_OPENSESSIONRESPONSE']._serialized_start=
|
|
82
|
-
_globals['_OPENSESSIONRESPONSE']._serialized_end=
|
|
83
|
-
_globals['_INVOKEREQUEST']._serialized_start=
|
|
84
|
-
_globals['_INVOKEREQUEST']._serialized_end=
|
|
85
|
-
_globals['_INVOKERESPONSE']._serialized_start=
|
|
86
|
-
_globals['_INVOKERESPONSE']._serialized_end=
|
|
87
|
-
_globals['_CLOSEHANDLEREQUEST']._serialized_start=
|
|
88
|
-
_globals['_CLOSEHANDLEREQUEST']._serialized_end=
|
|
89
|
-
_globals['_CLOSESESSIONREQUEST']._serialized_start=
|
|
90
|
-
_globals['_CLOSESESSIONREQUEST']._serialized_end=
|
|
91
|
-
_globals['_CLOSERESPONSE']._serialized_start=
|
|
92
|
-
_globals['_CLOSERESPONSE']._serialized_end=
|
|
93
|
-
_globals['_SAMPLEFRAME']._serialized_start=
|
|
94
|
-
_globals['_SAMPLEFRAME']._serialized_end=
|
|
95
|
-
_globals['_GENERICRPC']._serialized_start=
|
|
96
|
-
_globals['_GENERICRPC']._serialized_end=
|
|
97
|
-
_globals['_DYNAMICCONTROLV2']._serialized_start=
|
|
98
|
-
_globals['_DYNAMICCONTROLV2']._serialized_end=
|
|
99
|
-
_globals['_SAMPLEDATAV1']._serialized_start=
|
|
100
|
-
_globals['_SAMPLEDATAV1']._serialized_end=
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
75
|
+
if isinstance(value, np.bool_):
|
|
31
76
|
return bool(value)
|
|
32
|
-
if isinstance(value,
|
|
77
|
+
if isinstance(value, np.integer):
|
|
33
78
|
return int(value)
|
|
34
|
-
if isinstance(value,
|
|
79
|
+
if isinstance(value, np.floating):
|
|
35
80
|
return float(value)
|
|
36
81
|
if isinstance(value, complex):
|
|
37
|
-
return {
|
|
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
|
-
|
|
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
|
-
|
|
62
|
-
|
|
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
|
-
|
|
116
|
+
if kind == "float_value":
|
|
65
117
|
return arg.float_value
|
|
66
|
-
|
|
118
|
+
if kind == "string_value":
|
|
67
119
|
return arg.string_value
|
|
68
|
-
|
|
120
|
+
if kind == "bool_value":
|
|
69
121
|
return arg.bool_value
|
|
70
|
-
|
|
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
|
-
|
|
127
|
+
if kind == "complex_array":
|
|
74
128
|
shape = tuple(arg.complex_array.shape.dim)
|
|
75
|
-
data = [complex(
|
|
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
|
-
|
|
131
|
+
if kind == "json_value":
|
|
78
132
|
return _json_restore(json.loads(arg.json_value))
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
|
114
|
-
arg.json_value = json.dumps(
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|