RemoteRF 2.1.10__tar.gz → 2.2.1__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 (99) hide show
  1. {remoterf-2.1.10/src/remoterf.egg-info → remoterf-2.2.1}/PKG-INFO +15 -15
  2. {remoterf-2.1.10 → remoterf-2.2.1}/README.md +14 -14
  3. {remoterf-2.1.10 → remoterf-2.2.1}/pyproject.toml +4 -4
  4. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/config/config.py +1 -1
  5. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/app.py +5 -6
  6. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/direct_path.py +15 -6
  7. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/grpc_client.py +4 -3
  8. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/dynamic_device.py +8 -8
  9. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/dynamic_v2.py +1 -1
  10. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/ti_mmwave/__init__.py +1 -1
  11. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/ti_mmwave/ti_mmwave_remote.py +1 -1
  12. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/remoterf_cli.py +46 -32
  13. {remoterf-2.1.10 → remoterf-2.2.1/src/remoterf.egg-info}/PKG-INFO +15 -15
  14. remoterf-2.2.1/src/remoterf.egg-info/SOURCES.txt +93 -0
  15. remoterf-2.2.1/src/remoterf.egg-info/entry_points.txt +2 -0
  16. remoterf-2.2.1/src/remoterf.egg-info/top_level.txt +1 -0
  17. remoterf-2.1.10/src/remoteRF.py → remoterf-2.2.1/src/remoterf.py +9 -9
  18. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_banner.py +5 -5
  19. remoterf-2.2.1/tests/test_cli_login_fresh.py +82 -0
  20. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_config_address.py +1 -1
  21. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_deployment_accounts.py +26 -26
  22. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_direct_path_fixed.py +3 -3
  23. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_direct_path_partner.py +3 -3
  24. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_direct_path_race.py +4 -4
  25. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_dynamic_device_codegen.py +29 -29
  26. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_dynamic_v2.py +24 -12
  27. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_federated_devices.py +7 -7
  28. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_fetch_idl_fallback.py +7 -7
  29. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_finish_prompt.py +3 -3
  30. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_gate_i_direct_path.py +56 -10
  31. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_grpc_client_target.py +4 -4
  32. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_homes.py +57 -29
  33. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_native_account_credentials.py +3 -3
  34. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_native_devices.py +2 -2
  35. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_partner_dynamic_v2.py +6 -6
  36. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_pluto_virtual.py +3 -3
  37. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_process_arg.py +4 -4
  38. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_remoterf_cli.py +7 -7
  39. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_ti_mmwave.py +12 -12
  40. {remoterf-2.1.10 → remoterf-2.2.1}/tests/test_upgrade_rescue.py +12 -12
  41. remoterf-2.1.10/src/remoterf.egg-info/SOURCES.txt +0 -93
  42. remoterf-2.1.10/src/remoterf.egg-info/entry_points.txt +0 -2
  43. remoterf-2.1.10/src/remoterf.egg-info/top_level.txt +0 -1
  44. remoterf-2.1.10/tests/test_cli_login_fresh.py +0 -54
  45. {remoterf-2.1.10 → remoterf-2.2.1}/LICENSE +0 -0
  46. {remoterf-2.1.10 → remoterf-2.2.1}/setup.cfg +0 -0
  47. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/__init__.py +0 -0
  48. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/__init__.py +0 -0
  49. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/__init__.py +0 -0
  50. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/deployment_capabilities.proto +0 -0
  51. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/deployment_capabilities_pb2.py +0 -0
  52. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/deployment_capabilities_pb2_grpc.py +0 -0
  53. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/grpc.proto +0 -0
  54. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/grpc_pb2.py +0 -0
  55. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/grpc_pb2_grpc.py +0 -0
  56. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/grpc/v2_codec.py +0 -0
  57. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/tos_notice.txt +0 -0
  58. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/utils/__init__.py +0 -0
  59. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/utils/ansi_codes.py +0 -0
  60. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/utils/api_token.py +0 -0
  61. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/utils/banner.py +0 -0
  62. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/utils/list_string.py +0 -0
  63. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/common/utils/process_arg.py +0 -0
  64. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/config/__init__.py +0 -0
  65. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/config/cert_fetcher.py +0 -0
  66. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/__init__.py +0 -0
  67. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/acc_login.py +0 -0
  68. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/banner_note.txt +0 -0
  69. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/dynamic_v2_transport.py +0 -0
  70. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/grpc_acc.py +0 -0
  71. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/secure_channel.py +0 -0
  72. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/core/v2_errors.py +0 -0
  73. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/deployment/__init__.py +0 -0
  74. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/deployment/backend.py +0 -0
  75. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/deployment/direct.py +0 -0
  76. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/deployment/homes.py +0 -0
  77. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/deployment/http.py +0 -0
  78. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/deployment/state.py +0 -0
  79. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/__init__.py +0 -0
  80. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/_virtual.py +0 -0
  81. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/adalm_pluto/__init__.py +0 -0
  82. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/adalm_pluto/adalm_pluto_remote.py +0 -0
  83. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/hackrf/__init__.py +0 -0
  84. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/hackrf/hackrf_remote.py +0 -0
  85. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/rtl_sdr/__init__.py +0 -0
  86. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/rtl_sdr/rtl_sdr_remote.py +0 -0
  87. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/sim_sdr/__init__.py +0 -0
  88. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/sim_sdr/sim_sdr_remote.py +0 -0
  89. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/support/__init__.py +0 -0
  90. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/support/ti_mmwave.py +0 -0
  91. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/support/uhd.py +0 -0
  92. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/support/uhd_dsp.py +0 -0
  93. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/support/uhd_v2.py +0 -0
  94. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/usrp/__init__.py +0 -0
  95. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/usrp/usrp_remote.py +0 -0
  96. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/drivers/usrp/usrp_remote.pyi +0 -0
  97. {remoterf-2.1.10/src/remoteRF → remoterf-2.2.1/src/remoterf}/version.py +0 -0
  98. {remoterf-2.1.10 → remoterf-2.2.1}/src/remoterf.egg-info/dependency_links.txt +0 -0
  99. {remoterf-2.1.10 → remoterf-2.2.1}/src/remoterf.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 2.1.10
3
+ Version: 2.2.1
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-email: Ethan Ge <ethoGalaxy@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -43,13 +43,13 @@ python --version
43
43
 
44
44
  ## Installation
45
45
 
46
- Use the package manager [pip](https://pip.pypa.io/en/stable/) to install remoteRF. It is recommended that you install this package within a [virtual environment](https://docs.python.org/3/library/venv.html).
46
+ Use the package manager [pip](https://pip.pypa.io/en/stable/) to install remoterf. It is recommended that you install this package within a [virtual environment](https://docs.python.org/3/library/venv.html).
47
47
 
48
48
  ```bash
49
49
  python3 -m venv venv # Create virtual environment
50
50
  source venv/bin/activate # Activate virtual environment
51
51
 
52
- pip install remoterf # Install remoteRF
52
+ pip install remoterf # Install remoterf
53
53
  ```
54
54
 
55
55
  ## NI USRP-2901, Ettus B205-mini, B200-family, and USRP N210
@@ -64,7 +64,7 @@ After reserving a server-local `usrp` inventory entry, fetch or refresh its
64
64
  Dynamic v2 package with the reservation token:
65
65
 
66
66
  ```python
67
- from remoteRF.drivers import ensure_driver
67
+ from remoterf.drivers import ensure_driver
68
68
 
69
69
  ensure_driver(token="reservation-token")
70
70
  ```
@@ -72,7 +72,7 @@ ensure_driver(token="reservation-token")
72
72
  Both supported initialization forms then use the same generated runtime:
73
73
 
74
74
  ```python
75
- from remoteRF.drivers.usrp import uhd
75
+ from remoterf.drivers.usrp import uhd
76
76
 
77
77
  with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
78
78
  print(usrp.remoterf_capabilities)
@@ -80,7 +80,7 @@ with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
80
80
  ```
81
81
 
82
82
  ```python
83
- from remoteRF.drivers.usrp import MultiUSRP
83
+ from remoterf.drivers.usrp import MultiUSRP
84
84
 
85
85
  usrp = MultiUSRP("reservation-token")
86
86
  try:
@@ -94,7 +94,7 @@ leading region reported by native UHD is changed on a partial receive:
94
94
 
95
95
  ```python
96
96
  import numpy as np
97
- from remoteRF.drivers.usrp import uhd
97
+ from remoterf.drivers.usrp import uhd
98
98
 
99
99
  with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
100
100
  stream_args = uhd.usrp.StreamArgs("fc32", "sc16")
@@ -108,7 +108,7 @@ with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
108
108
 
109
109
  The generated package includes native-like namespaces, aliases, overload
110
110
  stubs, deterministic `close()`, context managers, opaque session-bound
111
- handles, and typed errors in `remoteRF.core.v2_errors`. Streamers are never
111
+ handles, and typed errors in `remoterf.core.v2_errors`. Streamers are never
112
112
  silently recreated after a disconnect; reopen a new device session and
113
113
  configure a new stream explicitly.
114
114
 
@@ -123,12 +123,12 @@ RTL-SDR clients are generated from the server's `rtl_sdr` schema. The machine
123
123
  running client code does not need `librtlsdr` or PyRtlSdr:
124
124
 
125
125
  ```python
126
- from remoteRF.drivers import ensure_driver
126
+ from remoterf.drivers import ensure_driver
127
127
 
128
128
  token = "reservation-token"
129
129
  ensure_driver(token=token)
130
130
 
131
- from remoteRF.drivers.rtl_sdr import RtlSdr
131
+ from remoterf.drivers.rtl_sdr import RtlSdr
132
132
 
133
133
  sdr = RtlSdr(token)
134
134
  sdr.sample_rate = 2_048_000
@@ -160,12 +160,12 @@ machine physically connected to the radar needs `pyserial` or a CP210x driver.
160
160
  The initial parser profile supports xWR68xx mmWave SDK 3 out-of-box TLV output.
161
161
 
162
162
  ```python
163
- from remoteRF.drivers import ensure_driver
163
+ from remoterf.drivers import ensure_driver
164
164
 
165
165
  token = "reservation-token"
166
166
  ensure_driver(token=token)
167
167
 
168
- from remoteRF.drivers.ti_mmwave import TiMmWave, decode_frame
168
+ from remoterf.drivers.ti_mmwave import TiMmWave, decode_frame
169
169
 
170
170
  radar = TiMmWave(token)
171
171
  print(radar.device_info)
@@ -323,7 +323,7 @@ Here is a explained sample script to get you going!
323
323
  #### Python Script:
324
324
 
325
325
  ```python
326
- from remoteRF.drivers.adalm_pluto import * # Imports device Pluto SDR remote drivers. Change depending on desired device.
326
+ from remoterf.drivers.adalm_pluto import * # Imports device Pluto SDR remote drivers. Change depending on desired device.
327
327
 
328
328
  sdr = adi.Pluto( # Device initialization.
329
329
  token = 'example_token' # Place the prior token here.
@@ -332,12 +332,12 @@ sdr = adi.Pluto( # Device initialization.
332
332
  # You can now use this 'sdr' as you normally would with the default Pluto drivers.
333
333
  ```
334
334
 
335
- If converting a existing `non-remoteRF` compatible script:
335
+ If converting a existing `non-remoterf` compatible script:
336
336
 
337
337
  ```diff
338
338
  - import existing_device_drivers
339
339
 
340
- + from remoteRF.drivers.device_drivers import *
340
+ + from remoterf.drivers.device_drivers import *
341
341
 
342
342
  - device = device(init)
343
343
 
@@ -18,13 +18,13 @@ python --version
18
18
 
19
19
  ## Installation
20
20
 
21
- Use the package manager [pip](https://pip.pypa.io/en/stable/) to install remoteRF. It is recommended that you install this package within a [virtual environment](https://docs.python.org/3/library/venv.html).
21
+ Use the package manager [pip](https://pip.pypa.io/en/stable/) to install remoterf. It is recommended that you install this package within a [virtual environment](https://docs.python.org/3/library/venv.html).
22
22
 
23
23
  ```bash
24
24
  python3 -m venv venv # Create virtual environment
25
25
  source venv/bin/activate # Activate virtual environment
26
26
 
27
- pip install remoterf # Install remoteRF
27
+ pip install remoterf # Install remoterf
28
28
  ```
29
29
 
30
30
  ## NI USRP-2901, Ettus B205-mini, B200-family, and USRP N210
@@ -39,7 +39,7 @@ After reserving a server-local `usrp` inventory entry, fetch or refresh its
39
39
  Dynamic v2 package with the reservation token:
40
40
 
41
41
  ```python
42
- from remoteRF.drivers import ensure_driver
42
+ from remoterf.drivers import ensure_driver
43
43
 
44
44
  ensure_driver(token="reservation-token")
45
45
  ```
@@ -47,7 +47,7 @@ ensure_driver(token="reservation-token")
47
47
  Both supported initialization forms then use the same generated runtime:
48
48
 
49
49
  ```python
50
- from remoteRF.drivers.usrp import uhd
50
+ from remoterf.drivers.usrp import uhd
51
51
 
52
52
  with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
53
53
  print(usrp.remoterf_capabilities)
@@ -55,7 +55,7 @@ with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
55
55
  ```
56
56
 
57
57
  ```python
58
- from remoteRF.drivers.usrp import MultiUSRP
58
+ from remoterf.drivers.usrp import MultiUSRP
59
59
 
60
60
  usrp = MultiUSRP("reservation-token")
61
61
  try:
@@ -69,7 +69,7 @@ leading region reported by native UHD is changed on a partial receive:
69
69
 
70
70
  ```python
71
71
  import numpy as np
72
- from remoteRF.drivers.usrp import uhd
72
+ from remoterf.drivers.usrp import uhd
73
73
 
74
74
  with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
75
75
  stream_args = uhd.usrp.StreamArgs("fc32", "sc16")
@@ -83,7 +83,7 @@ with uhd.usrp.MultiUSRP(token="reservation-token") as usrp:
83
83
 
84
84
  The generated package includes native-like namespaces, aliases, overload
85
85
  stubs, deterministic `close()`, context managers, opaque session-bound
86
- handles, and typed errors in `remoteRF.core.v2_errors`. Streamers are never
86
+ handles, and typed errors in `remoterf.core.v2_errors`. Streamers are never
87
87
  silently recreated after a disconnect; reopen a new device session and
88
88
  configure a new stream explicitly.
89
89
 
@@ -98,12 +98,12 @@ RTL-SDR clients are generated from the server's `rtl_sdr` schema. The machine
98
98
  running client code does not need `librtlsdr` or PyRtlSdr:
99
99
 
100
100
  ```python
101
- from remoteRF.drivers import ensure_driver
101
+ from remoterf.drivers import ensure_driver
102
102
 
103
103
  token = "reservation-token"
104
104
  ensure_driver(token=token)
105
105
 
106
- from remoteRF.drivers.rtl_sdr import RtlSdr
106
+ from remoterf.drivers.rtl_sdr import RtlSdr
107
107
 
108
108
  sdr = RtlSdr(token)
109
109
  sdr.sample_rate = 2_048_000
@@ -135,12 +135,12 @@ machine physically connected to the radar needs `pyserial` or a CP210x driver.
135
135
  The initial parser profile supports xWR68xx mmWave SDK 3 out-of-box TLV output.
136
136
 
137
137
  ```python
138
- from remoteRF.drivers import ensure_driver
138
+ from remoterf.drivers import ensure_driver
139
139
 
140
140
  token = "reservation-token"
141
141
  ensure_driver(token=token)
142
142
 
143
- from remoteRF.drivers.ti_mmwave import TiMmWave, decode_frame
143
+ from remoterf.drivers.ti_mmwave import TiMmWave, decode_frame
144
144
 
145
145
  radar = TiMmWave(token)
146
146
  print(radar.device_info)
@@ -298,7 +298,7 @@ Here is a explained sample script to get you going!
298
298
  #### Python Script:
299
299
 
300
300
  ```python
301
- from remoteRF.drivers.adalm_pluto import * # Imports device Pluto SDR remote drivers. Change depending on desired device.
301
+ from remoterf.drivers.adalm_pluto import * # Imports device Pluto SDR remote drivers. Change depending on desired device.
302
302
 
303
303
  sdr = adi.Pluto( # Device initialization.
304
304
  token = 'example_token' # Place the prior token here.
@@ -307,12 +307,12 @@ sdr = adi.Pluto( # Device initialization.
307
307
  # You can now use this 'sdr' as you normally would with the default Pluto drivers.
308
308
  ```
309
309
 
310
- If converting a existing `non-remoteRF` compatible script:
310
+ If converting a existing `non-remoterf` compatible script:
311
311
 
312
312
  ```diff
313
313
  - import existing_device_drivers
314
314
 
315
- + from remoteRF.drivers.device_drivers import *
315
+ + from remoterf.drivers.device_drivers import *
316
316
 
317
317
  - device = device(init)
318
318
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "remoterf"
7
- version = "2.1.10"
7
+ version = "2.2.1"
8
8
  description = "A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts."
9
9
  readme = "README.md"
10
10
  license = "GPL-3.0-or-later"
@@ -31,12 +31,12 @@ classifiers = [
31
31
  ]
32
32
 
33
33
  [project.scripts]
34
- remoterf = "remoteRF.remoterf_cli:main"
34
+ remoterf = "remoterf.remoterf_cli:main"
35
35
 
36
36
  [tool.setuptools]
37
37
  package-dir = { "" = "src" }
38
- # src/remoteRF.py: see its docstring (upgrades from 2.0.7-2.0.13).
39
- py-modules = ["remoteRF"]
38
+ # src/remoterf.py: see its docstring (upgrades from 2.0.14-2.1.x).
39
+ py-modules = ["remoterf"]
40
40
 
41
41
  [tool.setuptools.packages.find]
42
42
  where = ["src"]
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- # src/remoteRF/core/remoterf_config.py
16
+ # src/remoterf/core/remoterf_config.py
17
17
 
18
18
  from __future__ import annotations
19
19
 
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- from remoteRF.core.grpc_client import addr as server_addr, handle_admin_command
16
+ from remoterf.core.grpc_client import addr as server_addr, handle_admin_command
17
17
  from . import *
18
18
  from ..common.utils import *
19
19
 
@@ -536,10 +536,9 @@ def _federated_reservations_for_range(start_day, end_day):
536
536
 
537
537
  def _federated_reserve_slot(device_id, chosen_day, chosen_slot, slot_start_str, slot_end_str):
538
538
  handle = account.reserve_device(device_id, chosen_slot[0], chosen_slot[1])
539
- printf("Reservation successful for ", (Sty.BOLD, Sty.GREEN), f"{chosen_day.strftime('%Y-%m-%d')} {slot_start_str}-{slot_end_str}.", Sty.CYAN)
540
- printf("Your device handle -> ", Sty.BOLD, f"{handle}", (Sty.BOLD, Sty.GREEN))
541
- printf("Use it where a token goes, e.g. adi.Pluto(\"" + handle + "\"); it works while you are logged in to this home.", Sty.DEFAULT)
542
- printf("The first call can take ~20 s while the radio powers on.", Sty.GRAY)
539
+ # Worded as a lab account's reservation; the handle goes where a token goes.
540
+ printf("Reservation successful on device ", (Sty.BOLD, Sty.GREEN), f"{str(device_id).rsplit(':', 1)[-1]}", Sty.MAGENTA, " for ", Sty.DEFAULT, f"{chosen_day.strftime('%Y-%m-%d')} {slot_start_str}-{slot_end_str}.", Sty.CYAN)
541
+ printf("Your Token -> ", Sty.BOLD, f"{handle}", (Sty.BOLD, Sty.GREEN))
543
542
  account.install_reserved_driver(handle, device_id)
544
543
 
545
544
 
@@ -1062,7 +1061,7 @@ def enroll(code=None):
1062
1061
  # register. Here we are already logged in somewhere, so strip it -- and
1063
1062
  # say so if it names a different lab than this one.
1064
1063
  try:
1065
- from remoteRF.deployment import homes
1064
+ from remoterf.deployment import homes
1066
1065
 
1067
1066
  host, code = homes.parse_code(code)
1068
1067
  except Exception: # noqa: BLE001 - not in that form; send as typed
@@ -50,11 +50,18 @@ import threading
50
50
  import time
51
51
  from typing import Callable, Optional
52
52
 
53
- from aioice import Candidate, Connection
54
- from aioquic.asyncio.protocol import QuicConnectionProtocol
55
- from aioquic.quic import events
56
- from aioquic.quic.configuration import QuicConfiguration
57
- from aioquic.quic.connection import QuicConnection
53
+ try:
54
+ from aioice import Candidate, Connection
55
+ from aioquic.asyncio.protocol import QuicConnectionProtocol
56
+ from aioquic.quic import events
57
+ from aioquic.quic.configuration import QuicConfiguration
58
+ from aioquic.quic.connection import QuicConnection
59
+
60
+ _BROKEN = None
61
+ except Exception as _exc: # noqa: BLE001 - e.g. conda swapped in a cryptography pip's pyOpenSSL cannot use
62
+ Candidate = Connection = QuicConnectionProtocol = QuicConfiguration = QuicConnection = object
63
+ events = None
64
+ _BROKEN = f"{type(_exc).__name__}: {_exc}"
58
65
 
59
66
  from ..common.grpc import grpc_pb2
60
67
  from ..common.utils import map_arg, unmap_arg
@@ -136,7 +143,7 @@ STUN_SECONDS = 1.5 # a STUN server answers in milliseconds or not at all
136
143
 
137
144
 
138
145
  def enabled() -> bool:
139
- return os.getenv("REMOTERF_DIRECT", "1").strip().lower() not in {"0", "off", "no", "false"}
146
+ return _BROKEN is None and os.getenv("REMOTERF_DIRECT", "1").strip().lower() not in {"0", "off", "no", "false"}
140
147
 
141
148
 
142
149
  def wants(function_name: str) -> bool:
@@ -742,6 +749,8 @@ def current(token: Optional[str] = None) -> Optional[DirectPath]:
742
749
 
743
750
  def describe() -> str:
744
751
  """What device calls use right now, for the shell."""
752
+ if _BROKEN is not None:
753
+ return f"relay (direct path unavailable: {_BROKEN}; fix: pip install --force-reinstall remoterf)"
745
754
  if not enabled():
746
755
  return "relay (direct path disabled: REMOTERF_DIRECT=0)"
747
756
  path = _path
@@ -225,15 +225,16 @@ def _device_token(function_name, args):
225
225
  def rpc_client(*, function_name, args, connection=None):
226
226
  global tcp_calls
227
227
  tcp_calls += 1
228
- ref = _federated_ref(function_name, args) if connection is None else None
229
- if ref is not None:
230
- return _finish(_federated_call(ref, function_name, args))
231
228
  wire = os.getenv("REMOTERF_RX_WIRE", "i16").strip().lower()
232
229
  if wire and function_name.endswith(":rx:CALL0"):
233
230
  # Gate I slice 3: c64 halves the samples on the wire, i16 (the default)
234
231
  # quarters them when they are integer IQ; the driver still sees a complex
235
232
  # array. REMOTERF_RX_WIRE="" or "c128" opts out (servers ignore unknown).
233
+ # Also through a HOME, whose relay caps each response at ~768 KiB.
236
234
  args = {**args, "wire": map_arg(wire)}
235
+ ref = _federated_ref(function_name, args) if connection is None else None
236
+ if ref is not None:
237
+ return _finish(_federated_call(ref, function_name, args))
237
238
  if connection is None and direct_path.wants(function_name):
238
239
  path = direct_path.current(token=_device_token(function_name, args))
239
240
  if path is not None:
@@ -24,7 +24,7 @@ When a device is reserved, call install_driver(device_id) to:
24
24
 
25
25
  After install_driver() the user can do:
26
26
 
27
- from remoteRF.drivers.pluto import *
27
+ from remoterf.drivers.pluto import *
28
28
  sdr = adi.Pluto(token)
29
29
 
30
30
  On first device init, pass device_id to also check for schema updates:
@@ -158,7 +158,7 @@ def _client_class_name(schema: dict) -> str:
158
158
  return str(schema.get("client_class") or _default_class_name(schema.get("device_type", "unknown")))
159
159
 
160
160
 
161
- _CLIENT_MODULE_PREFIX = "remoteRF.drivers.support."
161
+ _CLIENT_MODULE_PREFIX = "remoterf.drivers.support."
162
162
  _CLIENT_CTOR_SENTINELS = {"$self", "$result"}
163
163
  _CLIENT_OBJECT_KINDS = {
164
164
  "module",
@@ -1405,7 +1405,7 @@ _DRIVERS_DIR = Path(__file__).parent
1405
1405
 
1406
1406
  def _write_driver_files(schema: dict) -> Path:
1407
1407
  pkg_dir = _write_v2_driver_files(schema) if str(schema.get("schema_version")) == "2.0" else _write_v1_driver_files(schema)
1408
- stale = f"remoteRF.drivers.{pkg_dir.name}"
1408
+ stale = f"remoterf.drivers.{pkg_dir.name}"
1409
1409
  for name in [m for m in sys.modules if m == stale or m.startswith(stale + ".")]:
1410
1410
  del sys.modules[name]
1411
1411
  return pkg_dir
@@ -1570,10 +1570,10 @@ def ensure_driver(*, token: str = None, device_id: int = None, device_name: str
1570
1570
  the reservation (and therefore never had install_driver run automatically).
1571
1571
  Pass the reservation token — the server resolves which device it belongs to.
1572
1572
 
1573
- from remoteRF.drivers import ensure_driver
1573
+ from remoterf.drivers import ensure_driver
1574
1574
  ensure_driver(token=token)
1575
1575
 
1576
- from remoteRF.drivers.pluto import *
1576
+ from remoterf.drivers.pluto import *
1577
1577
  sdr = adi.Pluto(token)
1578
1578
 
1579
1579
  One IDL:get_drivers RPC is always made (to resolve device_type and hash).
@@ -1611,7 +1611,7 @@ def ensure_driver(*, token: str = None, device_id: int = None, device_name: str
1611
1611
  f"Driver for '{device_type}' updated "
1612
1612
  f"(was {(current_hash or '?')[:16]}…, "
1613
1613
  f"now {schema.get('schema_hash','?')[:16]}…).\n"
1614
- f"Reimport before continuing: from remoteRF.drivers.{device_type} import *"
1614
+ f"Reimport before continuing: from remoterf.drivers.{device_type} import *"
1615
1615
  )
1616
1616
 
1617
1617
 
@@ -1653,7 +1653,7 @@ def install_driver_if_stale(*, token: str, current_hash: str) -> bool:
1653
1653
  If the driver was reinstalled, reimport the package before using the
1654
1654
  new class:
1655
1655
 
1656
- from remoteRF.drivers.pluto import *
1656
+ from remoterf.drivers.pluto import *
1657
1657
  """
1658
1658
  schema = fetch_idl(token=token, prefer_v2=True)
1659
1659
  if schema.get("schema_hash") == current_hash:
@@ -1666,6 +1666,6 @@ def install_driver_if_stale(*, token: str, current_hash: str) -> bool:
1666
1666
  print(
1667
1667
  f"Driver for '{device_type}' updated "
1668
1668
  f"(was {current_hash[:16]}…, now {schema.get('schema_hash','?')[:16]}…).\n"
1669
- f"Reimport before continuing: from remoteRF.drivers.{device_type} import *"
1669
+ f"Reimport before continuing: from remoterf.drivers.{device_type} import *"
1670
1670
  )
1671
1671
  return True
@@ -678,7 +678,7 @@ def build_uhd_bindings(schema: dict, *, transport_factory=DynamicV2Transport):
678
678
  if install_driver_if_stale(token=self.token, current_hash=schema["schema_hash"]):
679
679
  raise RemoteRFProtocolError(
680
680
  f"the server's {device_type} driver changed and the local copy "
681
- f"was updated; reimport remoteRF.drivers.{device_type} and retry",
681
+ f"was updated; reimport remoterf.drivers.{device_type} and retry",
682
682
  details=dict(exc.details),
683
683
  ) from exc
684
684
  raise
@@ -19,7 +19,7 @@ from . import ti_mmwave_remote as adi
19
19
  from .ti_mmwave_remote import TiMmWave
20
20
 
21
21
  __all__ = ["adi", "TiMmWave"]
22
- ti_mmwave = _import_module("remoteRF.drivers.support.ti_mmwave")
22
+ ti_mmwave = _import_module("remoterf.drivers.support.ti_mmwave")
23
23
  __all__.append("ti_mmwave")
24
24
  if hasattr(ti_mmwave, "bind_client_class"):
25
25
  ti_mmwave.bind_client_class("TiMmWave", TiMmWave)
@@ -18,7 +18,7 @@
18
18
 
19
19
  _PREFIX = "Ti_mmwave"
20
20
  _SCHEMA_HASH = "sha256:320a89d95075a472d7899ff2f98b9fdee05c0be96fa5651bf5c4f0e5d276a1c4"
21
- _CLIENT_MODULES = {'ti_mmwave': 'remoteRF.drivers.support.ti_mmwave'}
21
+ _CLIENT_MODULES = {'ti_mmwave': 'remoterf.drivers.support.ti_mmwave'}
22
22
  _CLIENT_OBJECTS = {}
23
23
 
24
24
  from importlib import import_module as _import_module
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- # src/remoteRF/cli.py
16
+ # src/remoterf/cli.py
17
17
  from __future__ import annotations
18
18
 
19
19
  import argparse
@@ -39,10 +39,10 @@ def _installed_version() -> str:
39
39
 
40
40
  def _connected_server(timeout_seconds: float = SERVER_CONNECT_TIMEOUT_SECONDS) -> str | None:
41
41
  """Return the configured endpoint only after its gRPC channel is ready."""
42
- from remoteRF.deployment.state import load_target
42
+ from remoterf.deployment.state import load_target
43
43
  target = load_target()
44
44
  if target and target['transport'] == 'https-json':
45
- from remoteRF.deployment.backend import selected_backend
45
+ from remoterf.deployment.backend import selected_backend
46
46
  backend = selected_backend()
47
47
  try:
48
48
  return backend.transport.origin
@@ -50,7 +50,7 @@ def _connected_server(timeout_seconds: float = SERVER_CONNECT_TIMEOUT_SECONDS) -
50
50
  backend.close()
51
51
  import grpc
52
52
 
53
- from remoteRF.core.grpc_client import active_endpoint, get_active_channel
53
+ from remoterf.core.grpc_client import active_endpoint, get_active_channel
54
54
 
55
55
  try:
56
56
  channel = get_active_channel()
@@ -97,8 +97,8 @@ def _read_dotenv_kv(path: Path) -> dict[str, str]:
97
97
  return out
98
98
 
99
99
  def _ensure_config_present() -> tuple[bool, str]:
100
- from remoteRF.deployment.state import load_target
101
- from remoteRF.deployment.direct import resolve_active_profile
100
+ from remoterf.deployment.state import load_target
101
+ from remoterf.deployment.direct import resolve_active_profile
102
102
  target = load_target()
103
103
  if target and target['transport'] == 'https-json':
104
104
  return True, ''
@@ -189,7 +189,7 @@ def _account_shell(*, register: bool, enrollment_code: str | None = None,
189
189
  if _connected_server() is None:
190
190
  _print_server_unavailable()
191
191
  return 2
192
- from remoteRF.core.acc_login import main as account_main
192
+ from remoterf.core.acc_login import main as account_main
193
193
  return int(
194
194
  account_main(
195
195
  register=register,
@@ -218,9 +218,9 @@ def _use_global(*, register: bool, show_banner: bool = True) -> int:
218
218
  A Global-native account is complete on its own: it needs no deployment
219
219
  HOME, and having one grants no access to any deployment.
220
220
  """
221
- from remoteRF.deployment import homes
222
- from remoteRF.deployment.backend import HttpsJsonAccountBackend
223
- from remoteRF.deployment.state import origin, select_target
221
+ from remoterf.deployment import homes
222
+ from remoterf.deployment.backend import HttpsJsonAccountBackend
223
+ from remoterf.deployment.state import origin, select_target
224
224
 
225
225
  try:
226
226
  selected = origin(_global_origin())
@@ -249,7 +249,7 @@ def _working(label: str):
249
249
  if not sys.stdout.isatty():
250
250
  yield
251
251
  return
252
- from remoteRF.common.utils.banner import supports_unicode
252
+ from remoterf.common.utils.banner import supports_unicode
253
253
 
254
254
  frames = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" if supports_unicode() else "|/-\\"
255
255
  stop = threading.Event()
@@ -294,7 +294,7 @@ def _reason(exc: BaseException) -> str:
294
294
 
295
295
 
296
296
  def _use_home(name: str, *, register: bool, enrollment_code: str | None = None) -> int:
297
- from remoteRF.deployment import homes
297
+ from remoterf.deployment import homes
298
298
 
299
299
  try:
300
300
  home = homes.load_home(name)
@@ -312,25 +312,39 @@ def _use_home(name: str, *, register: bool, enrollment_code: str | None = None)
312
312
  )
313
313
 
314
314
 
315
+ def _agree_to_tos() -> bool:
316
+ """Every registration is a fresh agreement, whoever is at the keyboard --
317
+ and starting one forgets the old agreement, so backing out here means
318
+ the next login asks too."""
319
+ from remoterf.config.config import _confirm_tos, forget_tos_agreement, remember_tos_agreement
320
+
321
+ forget_tos_agreement()
322
+ if not _confirm_tos("Do you agree to the RemoteRF Terms of Service? [y/N]: ",
323
+ "Registration cancelled."):
324
+ return False
325
+ remember_tos_agreement()
326
+ return True
327
+
328
+
329
+ def _register_global() -> int:
330
+ """`remoterf -r global`: straight to a Global account, same agreement as -r."""
331
+ print_client_banner(_installed_version(), server="")
332
+ if not _agree_to_tos():
333
+ return 1
334
+ return _use_global(register=True, show_banner=False)
335
+
336
+
315
337
  def _register() -> int:
316
338
  """`remoterf -r`: a deployment enrollment code, or a Global account."""
317
339
  from remoterf_federation_core import ValidationError
318
340
 
319
- from remoteRF.deployment import homes
320
-
321
- from remoteRF.config.config import _confirm_tos, forget_tos_agreement, remember_tos_agreement
341
+ from remoterf.deployment import homes
322
342
 
323
343
  # The banner opens the session; the target is not known yet, so the shell
324
344
  # below must not print it a second time.
325
345
  print_client_banner(_installed_version(), server="")
326
- # Every registration is a fresh agreement, whoever is at the keyboard --
327
- # and starting one forgets the old agreement, so backing out here means
328
- # the next login asks too.
329
- forget_tos_agreement()
330
- if not _confirm_tos("Do you agree to the RemoteRF Terms of Service? [y/N]: ",
331
- "Registration cancelled."):
346
+ if not _agree_to_tos():
332
347
  return 1
333
- remember_tos_agreement()
334
348
  try:
335
349
  entered = input('Enrollment code (Enter for a RemoteRF Global account): ').strip()
336
350
  except (EOFError, KeyboardInterrupt):
@@ -362,8 +376,8 @@ def _register() -> int:
362
376
 
363
377
 
364
378
  def _login(target: str | None) -> int:
365
- from remoteRF.config.config import require_tos_for_login
366
- from remoteRF.deployment import homes
379
+ from remoterf.config.config import require_tos_for_login
380
+ from remoterf.deployment import homes
367
381
 
368
382
  if not require_tos_for_login():
369
383
  return 1
@@ -404,7 +418,7 @@ def _print_pick_a_target() -> int:
404
418
 
405
419
 
406
420
  def _print_homes() -> int:
407
- from remoteRF.deployment import homes
421
+ from remoterf.deployment import homes
408
422
 
409
423
  homes.migrate_legacy_target()
410
424
  saved = homes.homes()
@@ -434,8 +448,8 @@ def main() -> int:
434
448
  return 0
435
449
 
436
450
  if argv[0] in ("--register", "-register", "-r"):
437
- if len(argv) == 2 and argv[1] == "global":
438
- return _use_global(register=True)
451
+ if len(argv) == 2 and argv[1].lstrip("-") == "global":
452
+ return _register_global()
439
453
  if len(argv) > 1:
440
454
  print("ERROR: --register takes no arguments (or 'global')")
441
455
  return 2
@@ -451,14 +465,14 @@ def main() -> int:
451
465
  return _print_homes()
452
466
 
453
467
  if argv[0] in ("--version", "-version", "-v"):
454
- from remoteRF.version import main as version_main
468
+ from remoterf.version import main as version_main
455
469
 
456
470
  print("RemoteRF version:", end=" ")
457
471
  version_main()
458
472
  return 0
459
473
 
460
474
  if argv[0] in ("--config", "-config", "-c"):
461
- from remoteRF.config.config import configure, wipe_config
475
+ from remoterf.config.config import configure, wipe_config
462
476
 
463
477
  addr = None
464
478
  wipe = False
@@ -527,13 +541,13 @@ def main() -> int:
527
541
  return int(wipe_config(yes=yes))
528
542
 
529
543
  if addr is not None:
530
- from remoteRF.deployment.state import origin, select_target, select_direct
544
+ from remoterf.deployment.state import origin, select_target, select_direct
531
545
  # Explicit host:port (even with a scheme) remains direct by default.
532
546
  stripped = addr.strip().split('://', 1)[-1]
533
547
  use_https = account_transport == 'https-json' or (':' not in stripped and account_transport != 'grpc')
534
548
  if use_https:
535
- from remoteRF.deployment.backend import HttpsJsonAccountBackend
536
- from remoteRF.config.config import _confirm_tos
549
+ from remoterf.deployment.backend import HttpsJsonAccountBackend
550
+ from remoterf.config.config import _confirm_tos
537
551
  try:
538
552
  selected_origin = origin(addr)
539
553
  if not _confirm_tos():