RemoteRF 2.1.10__tar.gz → 2.2.0__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.1.10/src/remoterf.egg-info → remoterf-2.2.0}/PKG-INFO +15 -15
- {remoterf-2.1.10 → remoterf-2.2.0}/README.md +14 -14
- {remoterf-2.1.10 → remoterf-2.2.0}/pyproject.toml +4 -4
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/config/config.py +1 -1
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/app.py +2 -2
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/dynamic_device.py +8 -8
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/dynamic_v2.py +1 -1
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/ti_mmwave/__init__.py +1 -1
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/ti_mmwave/ti_mmwave_remote.py +1 -1
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/remoterf_cli.py +22 -22
- {remoterf-2.1.10 → remoterf-2.2.0/src/remoterf.egg-info}/PKG-INFO +15 -15
- remoterf-2.2.0/src/remoterf.egg-info/SOURCES.txt +93 -0
- remoterf-2.2.0/src/remoterf.egg-info/entry_points.txt +2 -0
- remoterf-2.2.0/src/remoterf.egg-info/top_level.txt +1 -0
- remoterf-2.1.10/src/remoteRF.py → remoterf-2.2.0/src/remoterf.py +9 -9
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_banner.py +5 -5
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_cli_login_fresh.py +8 -8
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_config_address.py +1 -1
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_deployment_accounts.py +26 -26
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_direct_path_fixed.py +3 -3
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_direct_path_partner.py +3 -3
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_direct_path_race.py +4 -4
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_dynamic_device_codegen.py +29 -29
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_dynamic_v2.py +24 -12
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_federated_devices.py +7 -7
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_fetch_idl_fallback.py +7 -7
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_finish_prompt.py +3 -3
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_gate_i_direct_path.py +24 -10
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_grpc_client_target.py +4 -4
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_homes.py +54 -27
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_native_account_credentials.py +3 -3
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_native_devices.py +2 -2
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_partner_dynamic_v2.py +6 -6
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_pluto_virtual.py +3 -3
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_process_arg.py +4 -4
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_remoterf_cli.py +7 -7
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_ti_mmwave.py +12 -12
- {remoterf-2.1.10 → remoterf-2.2.0}/tests/test_upgrade_rescue.py +12 -12
- remoterf-2.1.10/src/remoterf.egg-info/SOURCES.txt +0 -93
- remoterf-2.1.10/src/remoterf.egg-info/entry_points.txt +0 -2
- remoterf-2.1.10/src/remoterf.egg-info/top_level.txt +0 -1
- {remoterf-2.1.10 → remoterf-2.2.0}/LICENSE +0 -0
- {remoterf-2.1.10 → remoterf-2.2.0}/setup.cfg +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/deployment_capabilities.proto +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/deployment_capabilities_pb2.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/deployment_capabilities_pb2_grpc.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/grpc.proto +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/grpc_pb2.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/grpc/v2_codec.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/tos_notice.txt +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/utils/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/utils/ansi_codes.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/utils/api_token.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/utils/banner.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/utils/list_string.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/common/utils/process_arg.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/config/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/config/cert_fetcher.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/acc_login.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/banner_note.txt +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/direct_path.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/dynamic_v2_transport.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/grpc_acc.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/grpc_client.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/secure_channel.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/core/v2_errors.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/deployment/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/deployment/backend.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/deployment/direct.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/deployment/homes.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/deployment/http.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/deployment/state.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/_virtual.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/adalm_pluto/adalm_pluto_remote.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/hackrf/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/hackrf/hackrf_remote.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/rtl_sdr/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/rtl_sdr/rtl_sdr_remote.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/sim_sdr/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/sim_sdr/sim_sdr_remote.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/support/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/support/ti_mmwave.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/support/uhd.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/support/uhd_dsp.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/support/uhd_v2.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/usrp/__init__.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/usrp/usrp_remote.py +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/usrp/usrp_remote.pyi +0 -0
- {remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/version.py +0 -0
- {remoterf-2.1.10 → remoterf-2.2.0}/src/remoterf.egg-info/dependency_links.txt +0 -0
- {remoterf-2.1.10 → remoterf-2.2.0}/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.
|
|
3
|
+
Version: 2.2.0
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
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
|
|
126
|
+
from remoterf.drivers import ensure_driver
|
|
127
127
|
|
|
128
128
|
token = "reservation-token"
|
|
129
129
|
ensure_driver(token=token)
|
|
130
130
|
|
|
131
|
-
from
|
|
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
|
|
163
|
+
from remoterf.drivers import ensure_driver
|
|
164
164
|
|
|
165
165
|
token = "reservation-token"
|
|
166
166
|
ensure_driver(token=token)
|
|
167
167
|
|
|
168
|
-
from
|
|
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
|
|
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-
|
|
335
|
+
If converting a existing `non-remoterf` compatible script:
|
|
336
336
|
|
|
337
337
|
```diff
|
|
338
338
|
- import existing_device_drivers
|
|
339
339
|
|
|
340
|
-
+ from
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
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
|
|
101
|
+
from remoterf.drivers import ensure_driver
|
|
102
102
|
|
|
103
103
|
token = "reservation-token"
|
|
104
104
|
ensure_driver(token=token)
|
|
105
105
|
|
|
106
|
-
from
|
|
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
|
|
138
|
+
from remoterf.drivers import ensure_driver
|
|
139
139
|
|
|
140
140
|
token = "reservation-token"
|
|
141
141
|
ensure_driver(token=token)
|
|
142
142
|
|
|
143
|
-
from
|
|
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
|
|
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-
|
|
310
|
+
If converting a existing `non-remoterf` compatible script:
|
|
311
311
|
|
|
312
312
|
```diff
|
|
313
313
|
- import existing_device_drivers
|
|
314
314
|
|
|
315
|
-
+ from
|
|
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.
|
|
7
|
+
version = "2.2.0"
|
|
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 = "
|
|
34
|
+
remoterf = "remoterf.remoterf_cli:main"
|
|
35
35
|
|
|
36
36
|
[tool.setuptools]
|
|
37
37
|
package-dir = { "" = "src" }
|
|
38
|
-
# src/
|
|
39
|
-
py-modules = ["
|
|
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/
|
|
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
|
|
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
|
|
|
@@ -1062,7 +1062,7 @@ def enroll(code=None):
|
|
|
1062
1062
|
# register. Here we are already logged in somewhere, so strip it -- and
|
|
1063
1063
|
# say so if it names a different lab than this one.
|
|
1064
1064
|
try:
|
|
1065
|
-
from
|
|
1065
|
+
from remoterf.deployment import homes
|
|
1066
1066
|
|
|
1067
1067
|
host, code = homes.parse_code(code)
|
|
1068
1068
|
except Exception: # noqa: BLE001 - not in that form; send as typed
|
|
@@ -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
|
|
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 = "
|
|
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"
|
|
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
|
|
1573
|
+
from remoterf.drivers import ensure_driver
|
|
1574
1574
|
ensure_driver(token=token)
|
|
1575
1575
|
|
|
1576
|
-
from
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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("
|
|
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)
|
{remoterf-2.1.10/src/remoteRF → remoterf-2.2.0/src/remoterf}/drivers/ti_mmwave/ti_mmwave_remote.py
RENAMED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
_PREFIX = "Ti_mmwave"
|
|
20
20
|
_SCHEMA_HASH = "sha256:320a89d95075a472d7899ff2f98b9fdee05c0be96fa5651bf5c4f0e5d276a1c4"
|
|
21
|
-
_CLIENT_MODULES = {'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/
|
|
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
|
|
42
|
+
from remoterf.deployment.state import load_target
|
|
43
43
|
target = load_target()
|
|
44
44
|
if target and target['transport'] == 'https-json':
|
|
45
|
-
from
|
|
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
|
|
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
|
|
101
|
-
from
|
|
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
|
|
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
|
|
222
|
-
from
|
|
223
|
-
from
|
|
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
|
|
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
|
|
297
|
+
from remoterf.deployment import homes
|
|
298
298
|
|
|
299
299
|
try:
|
|
300
300
|
home = homes.load_home(name)
|
|
@@ -316,9 +316,9 @@ def _register() -> int:
|
|
|
316
316
|
"""`remoterf -r`: a deployment enrollment code, or a Global account."""
|
|
317
317
|
from remoterf_federation_core import ValidationError
|
|
318
318
|
|
|
319
|
-
from
|
|
319
|
+
from remoterf.deployment import homes
|
|
320
320
|
|
|
321
|
-
from
|
|
321
|
+
from remoterf.config.config import _confirm_tos, forget_tos_agreement, remember_tos_agreement
|
|
322
322
|
|
|
323
323
|
# The banner opens the session; the target is not known yet, so the shell
|
|
324
324
|
# below must not print it a second time.
|
|
@@ -362,8 +362,8 @@ def _register() -> int:
|
|
|
362
362
|
|
|
363
363
|
|
|
364
364
|
def _login(target: str | None) -> int:
|
|
365
|
-
from
|
|
366
|
-
from
|
|
365
|
+
from remoterf.config.config import require_tos_for_login
|
|
366
|
+
from remoterf.deployment import homes
|
|
367
367
|
|
|
368
368
|
if not require_tos_for_login():
|
|
369
369
|
return 1
|
|
@@ -404,7 +404,7 @@ def _print_pick_a_target() -> int:
|
|
|
404
404
|
|
|
405
405
|
|
|
406
406
|
def _print_homes() -> int:
|
|
407
|
-
from
|
|
407
|
+
from remoterf.deployment import homes
|
|
408
408
|
|
|
409
409
|
homes.migrate_legacy_target()
|
|
410
410
|
saved = homes.homes()
|
|
@@ -451,14 +451,14 @@ def main() -> int:
|
|
|
451
451
|
return _print_homes()
|
|
452
452
|
|
|
453
453
|
if argv[0] in ("--version", "-version", "-v"):
|
|
454
|
-
from
|
|
454
|
+
from remoterf.version import main as version_main
|
|
455
455
|
|
|
456
456
|
print("RemoteRF version:", end=" ")
|
|
457
457
|
version_main()
|
|
458
458
|
return 0
|
|
459
459
|
|
|
460
460
|
if argv[0] in ("--config", "-config", "-c"):
|
|
461
|
-
from
|
|
461
|
+
from remoterf.config.config import configure, wipe_config
|
|
462
462
|
|
|
463
463
|
addr = None
|
|
464
464
|
wipe = False
|
|
@@ -527,13 +527,13 @@ def main() -> int:
|
|
|
527
527
|
return int(wipe_config(yes=yes))
|
|
528
528
|
|
|
529
529
|
if addr is not None:
|
|
530
|
-
from
|
|
530
|
+
from remoterf.deployment.state import origin, select_target, select_direct
|
|
531
531
|
# Explicit host:port (even with a scheme) remains direct by default.
|
|
532
532
|
stripped = addr.strip().split('://', 1)[-1]
|
|
533
533
|
use_https = account_transport == 'https-json' or (':' not in stripped and account_transport != 'grpc')
|
|
534
534
|
if use_https:
|
|
535
|
-
from
|
|
536
|
-
from
|
|
535
|
+
from remoterf.deployment.backend import HttpsJsonAccountBackend
|
|
536
|
+
from remoterf.config.config import _confirm_tos
|
|
537
537
|
try:
|
|
538
538
|
selected_origin = origin(addr)
|
|
539
539
|
if not _confirm_tos():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: remoterf
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
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
|
|
126
|
+
from remoterf.drivers import ensure_driver
|
|
127
127
|
|
|
128
128
|
token = "reservation-token"
|
|
129
129
|
ensure_driver(token=token)
|
|
130
130
|
|
|
131
|
-
from
|
|
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
|
|
163
|
+
from remoterf.drivers import ensure_driver
|
|
164
164
|
|
|
165
165
|
token = "reservation-token"
|
|
166
166
|
ensure_driver(token=token)
|
|
167
167
|
|
|
168
|
-
from
|
|
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
|
|
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-
|
|
335
|
+
If converting a existing `non-remoterf` compatible script:
|
|
336
336
|
|
|
337
337
|
```diff
|
|
338
338
|
- import existing_device_drivers
|
|
339
339
|
|
|
340
|
-
+ from
|
|
340
|
+
+ from remoterf.drivers.device_drivers import *
|
|
341
341
|
|
|
342
342
|
- device = device(init)
|
|
343
343
|
|