remoterf 0.0.7.27__py3-none-any.whl

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.

Potentially problematic release.


This version of remoterf might be problematic. Click here for more details.

@@ -0,0 +1,52 @@
1
+ from .grpc_client import rpc_client
2
+ from ..common.utils import *
3
+
4
+ import datetime
5
+
6
+ class RemoteRFAccount:
7
+ def __init__(self, username:str=None, password:str=None, email:str=None):
8
+ self.username = username
9
+ self.password = password
10
+ self.email = email
11
+
12
+ def create_user(self):
13
+ response = rpc_client(function_name="ACC:create_user", args={"un":map_arg(self.username), "pw":map_arg(self.password), "em":map_arg(self.email)})
14
+ if 'UC' in response.results:
15
+ print(f'User {unmap_arg(response.results["UC"])} successfully created.')
16
+ return True
17
+ elif 'UE' in response.results:
18
+ print(f'Error: {unmap_arg(response.results["UE"])}')
19
+ return False
20
+
21
+ def login_user(self):
22
+ username = self.username
23
+ password = self.password
24
+ response = rpc_client(function_name="ACC:login", args={"un":map_arg(username), "pw":map_arg(password)})
25
+ if 'UC' in response.results:
26
+ print(f'User {unmap_arg(response.results["UC"])} successful login.')
27
+ return True
28
+ elif 'UE' in response.results:
29
+ print(f'Error: {unmap_arg(response.results["UE"])}')
30
+ return False
31
+
32
+ def reserve_device(self, device_id:int, start_time:datetime, end_time:datetime):
33
+ response = rpc_client(function_name="ACC:reserve_device", args={"un":map_arg(self.username), "pw":map_arg(self.password), "dd":map_arg(device_id), "st":map_arg(int(start_time.timestamp())), "et":map_arg(int(end_time.timestamp()))})
34
+
35
+ if 'ace' in response.results:
36
+ raise Exception(f'{unmap_arg(response.results["ace"])}')
37
+ elif 'Token' in response.results:
38
+ return unmap_arg(response.results["Token"])
39
+
40
+ def get_reservations(self):
41
+ return rpc_client(function_name='ACC:get_res', args={"un":map_arg(self.username), "pw":map_arg(self.password)})
42
+
43
+ def get_devices(self):
44
+ return rpc_client(function_name='ACC:get_dev', args={"un":map_arg(self.username), "pw":map_arg(self.password)})
45
+
46
+ def cancel_reservation(self, res_id:int):
47
+ return rpc_client(function_name='ACC:cancel_res', args={"un":map_arg(self.username), "pw":map_arg(self.password), "res_id":map_arg(res_id)})
48
+
49
+ def get_perms(self):
50
+ return rpc_client(function_name='ACC:get_perms', args={"un":map_arg(self.username), "pw":map_arg(self.password)})
51
+
52
+
@@ -0,0 +1,97 @@
1
+ import socket
2
+ import getpass
3
+ from pathlib import Path
4
+
5
+ import grpc
6
+ from ..common.grpc import grpc_pb2
7
+ from ..common.grpc import grpc_pb2_grpc
8
+ from ..common.utils import *
9
+
10
+ # wlab credentials
11
+ server_ip = '164.67.195.207'
12
+ server_port = '61005'
13
+
14
+ options = [
15
+ ('grpc.max_send_message_length', 100 * 1024 * 1024),
16
+ ('grpc.max_receive_message_length', 100 * 1024 * 1024),
17
+ ]
18
+
19
+ # Server.crt
20
+ certs_path = Path(__file__).resolve().parent.parent/'core'/'certs'/'server.crt'
21
+ with certs_path.open('rb') as f:
22
+ trusted_certs = f.read()
23
+
24
+ credentials = grpc.ssl_channel_credentials(root_certificates=trusted_certs)
25
+ channel = grpc.secure_channel(f'{server_ip}:{server_port}', credentials, options=options)
26
+ stub = grpc_pb2_grpc.GenericRPCStub(channel)
27
+
28
+ tcp_calls = 0
29
+
30
+ def get_tcp_calls():
31
+ return tcp_calls
32
+
33
+ def rpc_client(*, function_name, args):
34
+ global tcp_calls
35
+ tcp_calls += 1
36
+ # print(tcp_calls)
37
+ # if not is_connected:
38
+ # response = rpc_client(function_name="UserLogin", args={"username": grpc_pb2.Argument(string_value=input("Username: ")), "password": grpc_pb2.Argument(string_value=getpass.getpass("Password: ")), "client_ip": grpc_pb2.Argument(string_value=local_ip)})
39
+ # if (response.results['status'].string_value == 'Success'):
40
+ # print("Login successful.")
41
+ # is_connected = True
42
+
43
+ # TODO: Handle user login
44
+
45
+ # print(f"Opening connection to {server_ip}:{server_port}")
46
+
47
+ # TODO: Handle Errors
48
+
49
+ # print(f"Calling function: {function_name}")
50
+ response = stub.Call(grpc_pb2.GenericRPCRequest(function_name=function_name, args=args))
51
+
52
+ if 'a' in response.results:
53
+ print(f"Error: {unmap_arg(response.results['a'])}")
54
+ exit()
55
+
56
+ if 'UE' in response.results:
57
+ print(f"UserError: {unmap_arg(response.results['UE'])}")
58
+ input("Hit enter to continue...")
59
+
60
+
61
+ return response
62
+
63
+ #region Example Usage
64
+
65
+ # if __name__ == '__main__':
66
+ # args={
67
+ # "key1": grpc_pb2.Argument(string_value="Hello"),
68
+ # "key2": grpc_pb2.Argument(int32_value=123),
69
+ # "key3": grpc_pb2.Argument(float_value=4.56),
70
+ # "key4": grpc_pb2.Argument(bool_value=True),
71
+ # "client_ip": grpc_pb2.Argument(string_value=local_ip)
72
+ # }
73
+
74
+ # response = rpc_client(function_name="echo", args=args)
75
+
76
+ # if 'client_ip' in response.results:
77
+ # del response.results['client_ip']
78
+
79
+ # # Print results
80
+ # print("Received response:")
81
+ # for key, arg in response.results.items():
82
+ # # Decode the oneof fields
83
+ # if arg.HasField('string_value'):
84
+ # value = arg.string_value
85
+ # elif arg.HasField('int32_value'):
86
+ # value = arg.int32_value
87
+ # elif arg.HasField('float_value'):
88
+ # value = arg.float_value
89
+ # elif arg.HasField('bool_value'):
90
+ # value = arg.bool_value
91
+ # else:
92
+ # value = "Undefined"
93
+
94
+ # print(f"{key}: {value}")
95
+
96
+ #endregion
97
+
File without changes
@@ -0,0 +1 @@
1
+ from . import pluto_remote as adi
@@ -0,0 +1,250 @@
1
+ from ...core.grpc_client import rpc_client
2
+ from ...common.utils import *
3
+ from ...common.grpc import grpc_pb2
4
+ from ...core.grpc_client import get_tcp_calls
5
+
6
+ def try_get(function_name, token):
7
+ try:
8
+ return unmap_arg(rpc_client(function_name=f"Pluto:{function_name}:GET", args={'a':map_arg(token)}).results[function_name])
9
+ except Exception as e:
10
+ input(f"Error: {e}\nHit enter to continue...")
11
+ return None
12
+
13
+ def try_set(function_name, value, token):
14
+ try:
15
+ rpc_client(function_name=f"Pluto:{function_name}:SET", args={function_name: map_arg(value), 'a':map_arg(token)})
16
+ except Exception as e:
17
+ input(f"Error: {e}\nHit enter to continue...")
18
+
19
+ def try_call_0_arg(function_name, token): # 0 argument call
20
+ try:
21
+ response = rpc_client(
22
+ function_name=f"Pluto:{function_name}:CALL0",
23
+ args={
24
+ 'a': map_arg(token)
25
+ }
26
+ )
27
+ return unmap_arg(response.results[function_name])
28
+ except Exception as e:
29
+ input(f"RPC_0_call Error: {e}\nHit enter to continue...")
30
+ return None
31
+
32
+ def try_call_1_arg(function_name, arg, token): # 1 argument call
33
+ try:
34
+ response = rpc_client(
35
+ function_name=f"Pluto:{function_name}:CALL1",
36
+ args={
37
+ 'a': map_arg(token),
38
+ 'arg1': map_arg(arg)
39
+ }
40
+ )
41
+ # The server should return something like {function_name: <something>}
42
+ return unmap_arg(response.results[function_name])
43
+ except Exception as e:
44
+ input(f"RPC_1_call Error: {e}\nHit enter to continue...")
45
+ return None
46
+
47
+ class rx_def:
48
+ pass
49
+
50
+ class tx_def:
51
+ pass
52
+
53
+ class rx_tx_def(rx_def, tx_def):
54
+ pass
55
+
56
+ class ad9364(rx_tx_def):
57
+ pass
58
+
59
+ class Pluto: # client
60
+
61
+ def __init__(self, token='', debug=False):
62
+ self.token = token
63
+ try_set(function_name="ip", value=token)
64
+
65
+ if debug:
66
+ print("Pluto Remote Client Initialized.")
67
+
68
+ def api_token(self, token:str) -> None:
69
+ self.token = token
70
+
71
+ # PlutoSDR
72
+
73
+ _device_name = "PlutoSDR"
74
+ _uri_auto = "ip:pluto.local"
75
+
76
+ def __repr__(self): # ! UNTESTED !
77
+ return try_get("__repr__", self.token)
78
+
79
+ #region ad9364
80
+ """AD9364 Transceiver"""
81
+
82
+ @property
83
+ def filter(self):
84
+ return try_get("filter", self.token)
85
+
86
+ @filter.setter
87
+ def filter(self, value):
88
+ try_set("filter", value, self.token)
89
+
90
+ @property
91
+ def loopback(self):
92
+ """loopback: Set loopback mode. Options are:
93
+ 0 (Disable), 1 (Digital), 2 (RF)"""
94
+ return try_get("loopback", self.token)
95
+
96
+ @loopback.setter
97
+ def loopback(self, value):
98
+ try_set("loopback", value, self.token)
99
+
100
+ @property
101
+ def gain_control_mode_chan0(self):
102
+ """gain_control_mode_chan0: Mode of receive path AGC. Options are:
103
+ slow_attack, fast_attack, manual"""
104
+ return try_get("gain_control_mode_chan0", self.token)
105
+
106
+ @gain_control_mode_chan0.setter
107
+ def gain_control_mode_chan0(self, value):
108
+ try_set("gain_control_mode_chan0", value, self.token)
109
+
110
+ @property
111
+ def rx_hardwaregain_chan0(self):
112
+ """rx_hardwaregain_chan0: Gain applied to RX path. Only applicable when
113
+ gain_control_mode is set to 'manual'"""
114
+ return try_get("rx_hardwaregain_chan0", self.token)
115
+
116
+ @rx_hardwaregain_chan0.setter
117
+ def rx_hardwaregain_chan0(self, value):
118
+ try_set("rx_hardwaregain_chan0", value, self.token)
119
+
120
+ @property
121
+ def tx_hardwaregain_chan0(self):
122
+ """tx_hardwaregain_chan0: Attenuation applied to TX path"""
123
+ return try_get("tx_hardwaregain_chan0", self.token)
124
+
125
+ @tx_hardwaregain_chan0.setter
126
+ def tx_hardwaregain_chan0(self, value):
127
+ try_set("tx_hardwaregain_chan0", value, self.token)
128
+
129
+ @property
130
+ def rx_rf_bandwidth(self):
131
+ """rx_rf_bandwidth: Bandwidth of front-end analog filter of RX path"""
132
+ return try_get("rx_rf_bandwidth", self.token)
133
+
134
+ @rx_rf_bandwidth.setter
135
+ def rx_rf_bandwidth(self, value):
136
+ try_set("rx_rf_bandwidth", value, self.token)
137
+
138
+ @property
139
+ def tx_rf_bandwidth(self):
140
+ """tx_rf_bandwidth: Bandwidth of front-end analog filter of TX path"""
141
+ return try_get("tx_rf_bandwidth", self.token)
142
+
143
+ @tx_rf_bandwidth.setter
144
+ def tx_rf_bandwidth(self, value):
145
+ try_set("tx_rf_bandwidth", value, self.token)
146
+
147
+ @property
148
+ def sample_rate(self): # ! UNTESTED !
149
+ """sample_rate: Sample rate RX and TX paths in samples per second"""
150
+ return try_get("sample_rate", self.token)
151
+
152
+ @sample_rate.setter
153
+ def sample_rate(self, rate): # ! UNTESTED !
154
+ try_set("sample_rate", rate, self.token)
155
+
156
+ @property
157
+ def rx_lo(self):
158
+ """rx_lo: Carrier frequency of RX path"""
159
+ return try_get("rx_lo", self.token)
160
+
161
+ @rx_lo.setter
162
+ def rx_lo(self, value):
163
+ try_set("rx_lo", value, self.token)
164
+
165
+ @property
166
+ def tx_lo(self):
167
+ """tx_lo: Carrier frequency of TX path"""
168
+ return try_get("tx_lo", self.token)
169
+
170
+ @tx_lo.setter
171
+ def tx_lo(self, value):
172
+ try_set("tx_lo", value, self.token)
173
+
174
+ @property
175
+ def tx_cyclic_buffer(self):
176
+ """tx_cyclic_buffer: Size of cyclic buffer"""
177
+ return try_get("tx_cyclic_buffer", self.token)
178
+
179
+ @tx_cyclic_buffer.setter
180
+ def tx_cyclic_buffer(self, value):
181
+ try_set("tx_cyclic_buffer", value, self.token)
182
+
183
+ def tx_destroy_buffer(self):
184
+ try_call_0_arg("tx_destroy_buffer", self.token)
185
+
186
+ def rx_destroy_buffer(self):
187
+ try_call_0_arg("rx_destroy_buffer", self.token)
188
+
189
+ #endregion
190
+
191
+ #region rx_def
192
+
193
+ def rx(self):
194
+ return try_get("rx", self.token)
195
+
196
+ @property
197
+ def rx_buffer_size(self):
198
+ return try_get("rx_buffer_size", self.token)
199
+
200
+ @rx_buffer_size.setter
201
+ def rx_buffer_size(self, value):
202
+ try_set("rx_buffer_size", value, self.token)
203
+
204
+ #endregion
205
+
206
+ #region tx_def
207
+
208
+ def tx(self, value):
209
+ return try_call_1_arg("tx", value, self.token)
210
+
211
+ # @tx.setter
212
+ # def tx(self, value):
213
+ # try_set("tx", value, self.token)
214
+
215
+ #endregion
216
+
217
+ #region tx
218
+
219
+ #endregion
220
+
221
+ #region _dec_int_fpga_filter
222
+
223
+ """Decimator and interpolator fpga filter controls"""
224
+
225
+ def _get_rates(self, dev, output): # ! UNTESTED !
226
+ """Get the decimation and interpolation rates"""
227
+ return try_get("rates", self.token)
228
+
229
+ @property
230
+ def rx_dec8_filter_en(self) -> bool: # ! UNTESTED !
231
+ """rx_dec8_filter_en: Enable decimate by 8 filter in FPGA"""
232
+ return try_get("rx_dec8_filter_en", self.token)
233
+
234
+ @rx_dec8_filter_en.setter
235
+ def rx_dec8_filter_en(self, value: bool): # ! UNTESTED !
236
+ """rx_dec8_filter_en: Enable decimate by 8 filter in FPGA"""
237
+ return try_set("rx_dec8_filter_en", value, self.token)
238
+
239
+ @property
240
+ def tx_int8_filter_en(self) -> bool: # ! UNTESTED !
241
+ """tx_int8_filter_en: Enable interpolate by 8 filter in FPGA"""
242
+ return try_get("tx_int8_filter_en", self.token)
243
+
244
+ @tx_int8_filter_en.setter
245
+ def tx_int8_filter_en(self, value: bool): # ! UNTESTED !
246
+ """tx_int8_filter_en: Enable interpolate by 8 filter in FPGA"""
247
+ return try_set("tx_int8_filter_en", value, self.token)
248
+
249
+ #endregion
250
+
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.1
2
+ Name: remoterf
3
+ Version: 0.0.7.27
4
+ Summary: A python API to remotely access signal centric hardware. Client-side only!
5
+ Author: Ethan Ge
6
+ Author-email: ethoGalaxy@gmail.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: grpcio==1.71.0
13
+ Requires-Dist: protobuf
14
+ Requires-Dist: numpy
15
+ Requires-Dist: prompt-toolkit
16
+ Requires-Dist: python-dotenv
17
+
18
+ # Remote RF
19
+
20
+ A python API to remotely access signal centric hardware.
21
+
22
+ Courtesy of Wireless Lab @ UCLA. - Ethan Ge
23
+
24
+ ## Prerequisites
25
+
26
+ - **Python 3.10**: This package works in Python 3.10+. If you don’t have Python installed, you can download it from the [official Python website](https://www.python.org/downloads/).
27
+
28
+ To check your current Python version, open a terminal and run:
29
+
30
+ ```bash
31
+ python --version
32
+ ```
33
+
34
+ - **UCLA VPN**: Please ensure that you are connected to the UCLA VPN. You can download and configure the VPN client from the following link: [UCLA VPN Client Download](https://www.it.ucla.edu/it-support-center/services/virtual-private-network-vpn-clients). If you’re not connected to the VPN, you will not have access to the lab servers.
35
+
36
+ ## Installation
37
+
38
+ 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).
39
+
40
+ ```bash
41
+ python3 -m venv venv # Create virtual environment
42
+ source venv/bin/activate # Activate virtual environment
43
+
44
+ pip install remoteRF # Install remoteRF
45
+ ```
46
+
47
+ If `pip install` doesn't work, you can clone the [source](https://github.com/WirelessLabAtUCLA/RemoteRF-Client) directly from github.
48
+
49
+ <!-- 1. **Clone the repository:**
50
+ ```bash
51
+ git clone https://github.com/WirelessLabAtUCLA/RemoteRF-Client
52
+ cd repository-name
53
+ ```
54
+ 2. **Install the package using** `pip` **in editable mode:**
55
+ ```bash
56
+ pip install -e .
57
+ ```
58
+ This command installs the package in "editable" mode, allowing for modifications to the local code without reinstalling. For more details on installing packages from local directories, refer to Python Packaging: [Installing from Local Archives](https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-packages-from-local-archives). -->
59
+
60
+ ## Reservation
61
+
62
+ Usage of the platform requires you to register a account and reserve a device in order to run scripts remotely.
63
+
64
+ ### 1. **Start UCLA VPN**
65
+
66
+ - Start the CISCO Secure client, login and connect to any of the options.
67
+
68
+ ### 2. **Register a account**:
69
+ ```bash
70
+ remoterf-login
71
+ # Run in the terminal
72
+ # where the Python library is installed
73
+
74
+ # Typically, this will be the terminal where you’ve activated the virtual environment if you’re using one
75
+ ```
76
+
77
+ - Input `r` to register a account, or `l` to login to a existing one.
78
+
79
+ <!-- 2. **You will be prompted with this**: -->
80
+ ```bash
81
+ Welcome to Remote RF Account System.
82
+ Please login or register to continue. (l/r):
83
+ ```
84
+
85
+ - Once in, input `help` to see all avaliable commands.
86
+
87
+ ### 3. **Reserve Device**:
88
+ ```bash
89
+ getdev # To view all avaliable devices
90
+
91
+ # Note the device ID. You will need this later to reserve said device
92
+ ```
93
+
94
+ ```bash
95
+ getres # To view times not avaliable
96
+
97
+ # Optionally, you can also view all reservations, and determine a time slot you want a specific device reserved
98
+ ```
99
+ ```bash
100
+ perms # To view your permissions
101
+
102
+ # Depending on your permission levels, you will be given different restrictions
103
+ ```
104
+
105
+ ```bash
106
+ resdev # To reserve a device
107
+
108
+ # Input the number of days you want to view, and it will display available reservations in that time span.
109
+
110
+ Reservation successful. Thy Token -> example_token
111
+
112
+ # Take note of this token. You will need it to actually access the device.
113
+ ```
114
+
115
+ ## Remote Access
116
+
117
+ With this token, you can now run scripts remotely. Please keep in mind that you MUST be connected to the UCLA VPN for this to work.
118
+ Here is a explained sample script to get you going!
119
+
120
+ #### Python Script:
121
+
122
+ ```python
123
+ from remoteRF.drivers.adalm_pluto import * # Imports device Pluto SDR remote drivers. Change depending on desired device.
124
+
125
+ sdr = adi.Pluto( # Device initialization.
126
+ token = 'example_token' # Place the prior token here.
127
+ )
128
+
129
+ # You can now use this 'sdr' as you normally would with the default Pluto drivers.
130
+ ```
131
+
132
+ If converting a existing `non-remoteRF` compatible script:
133
+
134
+ ```diff
135
+ - import existing_device_drivers
136
+
137
+ + from remoteRF.drivers.device_drivers import *
138
+
139
+ - device = device(init)
140
+
141
+ + device = device(token = 'sample_token')
142
+ ```
143
+
144
+ Nothing else needs changing!
145
+
146
+ ## Closing
147
+
148
+ This is fundamentally a experimental platform, and there will be many unknown bugs and issues. Some devices do not have universal support for all its functions at the moment, I am working on that aspect.
149
+
150
+ **So please submit feedback!**
@@ -0,0 +1,30 @@
1
+ remoteRF/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ remoteRF/common/__init__.py,sha256=8naT0ZphJxv_6uz7RRGvqfNB-UEznkzipJSVPD5n6iM,40
3
+ remoteRF/common/grpc/__init__.py,sha256=GYLHC7riDbjdx2cNOhWymt0GLZ4mtGhuzZAXVRfNynw,37
4
+ remoteRF/common/grpc/grpc_pb2.py,sha256=iMdLw3xly_2WjirEmVaxf7I8iiUmk-3YRqqIiRdNkPs,4082
5
+ remoteRF/common/grpc/grpc_pb2_grpc.py,sha256=NofKaB3t0nAm_uxDgA5WXhWcsRWqsyfuMEEdBrosVKk,3368
6
+ remoteRF/common/utils/__init__.py,sha256=JTP8gH-340HZI4F8oagPW-kxRCoVUnQB-_acmgXPaK4,204
7
+ remoteRF/common/utils/ansi_codes.py,sha256=knGLOJK-lyDjfQHL0Upq5UPTg6J_6WYldga-ZOaerSs,3052
8
+ remoteRF/common/utils/api_token.py,sha256=CdgnAIcKqhkJB_XqrshgJVZzfQIO-xeR8hVMi5bYPSI,1260
9
+ remoteRF/common/utils/list_string.py,sha256=qsch666vX2e3CZ2W5EdYi62dOk37k1v2yPpHHm47a7A,156
10
+ remoteRF/common/utils/process_arg.py,sha256=J1REqgjm-1daqTBdVASgDd-16y-KneOJpCZXPEOklVk,2971
11
+ remoteRF/core/__init__.py,sha256=XQiCe8kyzM7XLxA883-uDndBmbr-NXo1uvtMJT2h6oA,73
12
+ remoteRF/core/acc_login.py,sha256=UcY3rDLAwHoJ9lYXRfm26z_6yJX0JSoKv-u1mF6n0Gs,49
13
+ remoteRF/core/app.py,sha256=WLVEReY7QgEuRUq2LS5H_X9yp4hoQnMoY-DW7BBNR6I,21215
14
+ remoteRF/core/grpc_acc.py,sha256=bspLTzblhqYVVEFPwdvXrDZjREBWJVvD_SaT_cja6kU,2441
15
+ remoteRF/core/grpc_client.py,sha256=UMWAV7o_UX2MdcSSgCqC3hXwMmicWU-M7NO3RCTXYIo,3037
16
+ remoteRF/core/certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ remoteRF/core/certs/ca.crt,sha256=Rp8V8Mi413an0rO_dy7sH32j77ppVP1POZ-g7_eVtDU,2004
18
+ remoteRF/core/certs/ca.key,sha256=h5UQDlCcf7munMLTROYk6TGt9Guf0ar9aHoRPlsR2sk,3272
19
+ remoteRF/core/certs/cert.pem,sha256=d90GwpyubEcyp1WUcyMCpn93HI8RUY96sMg5ynHrIMM,1127
20
+ remoteRF/core/certs/key.pem,sha256=cWJ4BYX47boqXBcPmN5r_9KqYS4gLyGXnHGPMwwrNMo,1704
21
+ remoteRF/core/certs/server.crt,sha256=lV7KfCMA2Yz0ysDT5GcoNawDAg9uvtS33eZvycWOR10,1151
22
+ remoteRF/core/certs/server.key,sha256=F4hVXkENhugrpnHEYNesdvXJByvJ-_9Fxbiqf0Akn-U,1704
23
+ remoteRF/drivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ remoteRF/drivers/adalm_pluto/__init__.py,sha256=_IOOeQXR6paCP7Eciw2aeKBUNvZs-jeBTwW8QqUlFyU,33
25
+ remoteRF/drivers/adalm_pluto/pluto_remote.py,sha256=nXzc-V57ZGOwxK54t3w4d1aOpH1onSlhEkD1sxYPgC4,7457
26
+ remoterf-0.0.7.27.dist-info/METADATA,sha256=tLvMUjBS3wRmrJYrPdII9TumygbMlOppcF1fTQVmwJ0,4928
27
+ remoterf-0.0.7.27.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
28
+ remoterf-0.0.7.27.dist-info/entry_points.txt,sha256=TweiWBwjbPs3G5Xgx3kF7LqP3r-0Iy1BstMoX0mVnTM,64
29
+ remoterf-0.0.7.27.dist-info/top_level.txt,sha256=XQJoVTmAOsHV9qtPSP_QSh0ma4jKxsDkxn4IjM_ZuZk,9
30
+ remoterf-0.0.7.27.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.2.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ remoterf-login = remoteRF.core.acc_login:main
@@ -0,0 +1 @@
1
+ remoteRF