RemoteRF 2.0.1__tar.gz → 2.0.3__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 (44) hide show
  1. {remoterf-2.0.1/src/remoteRF.egg-info → remoterf-2.0.3}/PKG-INFO +1 -1
  2. {remoterf-2.0.1 → remoterf-2.0.3}/setup.py +1 -1
  3. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/grpc/grpc_pb2.py +7 -7
  4. remoterf-2.0.3/src/remoteRF/common/utils/process_arg.py +157 -0
  5. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/core/app.py +7 -2
  6. remoterf-2.0.3/src/remoteRF/drivers/dynamic_device.py +1452 -0
  7. remoterf-2.0.3/src/remoteRF/drivers/support/__init__.py +1 -0
  8. remoterf-2.0.3/src/remoteRF/drivers/support/uhd.py +397 -0
  9. {remoterf-2.0.1 → remoterf-2.0.3/src/remoteRF.egg-info}/PKG-INFO +1 -1
  10. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF.egg-info/SOURCES.txt +5 -1
  11. remoterf-2.0.3/tests/test_dynamic_device_codegen.py +964 -0
  12. remoterf-2.0.3/tests/test_process_arg.py +110 -0
  13. remoterf-2.0.1/src/remoteRF/common/utils/process_arg.py +0 -82
  14. remoterf-2.0.1/src/remoteRF/drivers/dynamic_device.py +0 -322
  15. {remoterf-2.0.1 → remoterf-2.0.3}/LICENSE +0 -0
  16. {remoterf-2.0.1 → remoterf-2.0.3}/MANIFEST.in +0 -0
  17. {remoterf-2.0.1 → remoterf-2.0.3}/README.md +0 -0
  18. {remoterf-2.0.1 → remoterf-2.0.3}/setup.cfg +0 -0
  19. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/__init__.py +0 -0
  20. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/__init__.py +0 -0
  21. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/grpc/__init__.py +0 -0
  22. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/grpc/grpc_pb2_grpc.py +0 -0
  23. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/tos_notice.txt +0 -0
  24. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/utils/__init__.py +0 -0
  25. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/utils/ansi_codes.py +0 -0
  26. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/utils/api_token.py +0 -0
  27. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/common/utils/list_string.py +0 -0
  28. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/config/__init__.py +0 -0
  29. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/config/cert_fetcher.py +0 -0
  30. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/config/config.py +0 -0
  31. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/core/__init__.py +0 -0
  32. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/core/acc_login.py +0 -0
  33. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/core/banner_note.txt +0 -0
  34. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/core/grpc_acc.py +0 -0
  35. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/core/grpc_client.py +0 -0
  36. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/drivers/__init__.py +0 -0
  37. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/drivers/adalm_pluto/__init__.py +0 -0
  38. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/drivers/adalm_pluto/pluto_remote.py +0 -0
  39. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/remoterf_cli.py +0 -0
  40. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF/version.py +0 -0
  41. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF.egg-info/dependency_links.txt +0 -0
  42. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF.egg-info/entry_points.txt +0 -0
  43. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF.egg-info/requires.txt +0 -0
  44. {remoterf-2.0.1 → remoterf-2.0.3}/src/remoteRF.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 2.0.1
3
+ Version: 2.0.3
4
4
  Summary: A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.
5
5
  Author: Ethan Ge
6
6
  Author-email: ethoGalaxy@gmail.com
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
6
6
 
7
7
  setup(
8
8
  name="remoterf",
9
- version="2.0.1",
9
+ version="2.0.3",
10
10
  author="Ethan Ge",
11
11
  author_email="ethoGalaxy@gmail.com",
12
12
  description="A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.",
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: grpc.proto
5
- # Protobuf Python Version: 5.29.0
5
+ # Protobuf Python Version: 5.27.1
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -12,8 +12,8 @@ from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
14
  5,
15
- 29,
16
- 0,
15
+ 27,
16
+ 1,
17
17
  '',
18
18
  'grpc.proto'
19
19
  )
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
24
24
 
25
25
 
26
26
 
27
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ngrpc.proto\x12\tremote_rf\"\xa2\x01\n\x11GenericRPCRequest\x12\x15\n\rfunction_name\x18\x01 \x01(\t\x12\x34\n\x04\x61rgs\x18\x02 \x03(\x0b\x32&.remote_rf.GenericRPCRequest.ArgsEntry\x1a@\n\tArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x96\x01\n\x12GenericRPCResponse\x12;\n\x07results\x18\x01 \x03(\x0b\x32*.remote_rf.GenericRPCResponse.ResultsEntry\x1a\x43\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x19\n\nArrayShape\x12\x0b\n\x03\x64im\x18\x01 \x03(\x05\"+\n\rComplexNumber\x12\x0c\n\x04real\x18\x01 \x01(\x02\x12\x0c\n\x04imag\x18\x02 \x01(\x02\"a\n\x11\x43omplexNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12&\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32\x18.remote_rf.ComplexNumber\"D\n\x0eRealNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12\x0c\n\x04\x64\x61ta\x18\x02 \x03(\x02\"\xd7\x01\n\x08\x41rgument\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x15\n\x0bint64_value\x18\x02 \x01(\x03H\x00\x12\x15\n\x0b\x66loat_value\x18\x03 \x01(\x02H\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12\x35\n\rcomplex_array\x18\x05 \x01(\x0b\x32\x1c.remote_rf.ComplexNumpyArrayH\x00\x12/\n\nreal_array\x18\x06 \x01(\x0b\x32\x19.remote_rf.RealNumpyArrayH\x00\x42\x07\n\x05value2Q\n\nGenericRPC\x12\x43\n\x04\x43\x61ll\x12\x1c.remote_rf.GenericRPCRequest\x1a\x1d.remote_rf.GenericRPCResponseB\x1e\n\x10\x63om.example.demoB\nDemoProtosb\x06proto3')
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ngrpc.proto\x12\tremote_rf\"\xa2\x01\n\x11GenericRPCRequest\x12\x15\n\rfunction_name\x18\x01 \x01(\t\x12\x34\n\x04\x61rgs\x18\x02 \x03(\x0b\x32&.remote_rf.GenericRPCRequest.ArgsEntry\x1a@\n\tArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x96\x01\n\x12GenericRPCResponse\x12;\n\x07results\x18\x01 \x03(\x0b\x32*.remote_rf.GenericRPCResponse.ResultsEntry\x1a\x43\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.remote_rf.Argument:\x02\x38\x01\"\x19\n\nArrayShape\x12\x0b\n\x03\x64im\x18\x01 \x03(\x05\"+\n\rComplexNumber\x12\x0c\n\x04real\x18\x01 \x01(\x02\x12\x0c\n\x04imag\x18\x02 \x01(\x02\"a\n\x11\x43omplexNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12&\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32\x18.remote_rf.ComplexNumber\"D\n\x0eRealNumpyArray\x12$\n\x05shape\x18\x01 \x01(\x0b\x32\x15.remote_rf.ArrayShape\x12\x0c\n\x04\x64\x61ta\x18\x02 \x03(\x02\"\xed\x01\n\x08\x41rgument\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x15\n\x0bint64_value\x18\x02 \x01(\x03H\x00\x12\x15\n\x0b\x66loat_value\x18\x03 \x01(\x02H\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12\x35\n\rcomplex_array\x18\x05 \x01(\x0b\x32\x1c.remote_rf.ComplexNumpyArrayH\x00\x12/\n\nreal_array\x18\x06 \x01(\x0b\x32\x19.remote_rf.RealNumpyArrayH\x00\x12\x14\n\njson_value\x18\x07 \x01(\tH\x00\x42\x07\n\x05value2Q\n\nGenericRPC\x12\x43\n\x04\x43\x61ll\x12\x1c.remote_rf.GenericRPCRequest\x1a\x1d.remote_rf.GenericRPCResponseB\x1e\n\x10\x63om.example.demoB\nDemoProtosb\x06proto3')
28
28
 
29
29
  _globals = globals()
30
30
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -53,7 +53,7 @@ if not _descriptor._USE_C_DESCRIPTORS:
53
53
  _globals['_REALNUMPYARRAY']._serialized_start=514
54
54
  _globals['_REALNUMPYARRAY']._serialized_end=582
55
55
  _globals['_ARGUMENT']._serialized_start=585
56
- _globals['_ARGUMENT']._serialized_end=800
57
- _globals['_GENERICRPC']._serialized_start=802
58
- _globals['_GENERICRPC']._serialized_end=883
56
+ _globals['_ARGUMENT']._serialized_end=822
57
+ _globals['_GENERICRPC']._serialized_start=824
58
+ _globals['_GENERICRPC']._serialized_end=905
59
59
  # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,157 @@
1
+ from ..grpc import grpc_pb2, grpc_pb2_grpc
2
+ import json
3
+ import numpy as np
4
+
5
+ _JSON_TYPE_KEY = "__remoterf_json_type__"
6
+
7
+ def _json_safe(value):
8
+ if hasattr(value, "as_payload"):
9
+ return _json_safe(value.as_payload())
10
+ if isinstance(value, np.ndarray):
11
+ if value.dtype == object:
12
+ raise ValueError(f"Cannot JSON-map object-dtype array: {value!r}")
13
+ array = np.asarray(value)
14
+ if np.iscomplexobj(array):
15
+ data = [[float(num.real), float(num.imag)] for num in array.ravel()]
16
+ return {
17
+ _JSON_TYPE_KEY: "ndarray",
18
+ "dtype": str(array.dtype),
19
+ "shape": list(array.shape),
20
+ "complex": True,
21
+ "data": data,
22
+ }
23
+ return {
24
+ _JSON_TYPE_KEY: "ndarray",
25
+ "dtype": str(array.dtype),
26
+ "shape": list(array.shape),
27
+ "complex": False,
28
+ "data": array.tolist(),
29
+ }
30
+ if isinstance(value, (np.bool_,)):
31
+ return bool(value)
32
+ if isinstance(value, (np.integer,)):
33
+ return int(value)
34
+ if isinstance(value, (np.floating,)):
35
+ return float(value)
36
+ if isinstance(value, complex):
37
+ return {_JSON_TYPE_KEY: "complex", "real": float(value.real), "imag": float(value.imag)}
38
+ if isinstance(value, dict):
39
+ return {str(key): _json_safe(item) for key, item in value.items()}
40
+ if isinstance(value, (list, tuple)):
41
+ return [_json_safe(item) for item in value]
42
+ return value
43
+
44
+ def _json_restore(value):
45
+ if isinstance(value, dict):
46
+ kind = value.get(_JSON_TYPE_KEY)
47
+ if kind == "ndarray":
48
+ shape = tuple(value.get("shape", ()))
49
+ dtype = value.get("dtype")
50
+ if value.get("complex"):
51
+ data = [complex(real, imag) for real, imag in value.get("data", [])]
52
+ return np.array(data, dtype=dtype or np.complex64).reshape(shape)
53
+ return np.array(value.get("data", []), dtype=dtype).reshape(shape)
54
+ if kind == "complex":
55
+ return complex(value.get("real", 0.0), value.get("imag", 0.0))
56
+ return {key: _json_restore(item) for key, item in value.items()}
57
+ if isinstance(value, list):
58
+ return [_json_restore(item) for item in value]
59
+ return value
60
+
61
+ def unmap_arg(arg):
62
+ if arg.HasField('int64_value'):
63
+ return arg.int64_value
64
+ elif arg.HasField('float_value'):
65
+ return arg.float_value
66
+ elif arg.HasField('string_value'):
67
+ return arg.string_value
68
+ elif arg.HasField('bool_value'):
69
+ return arg.bool_value
70
+ elif arg.HasField('real_array'):
71
+ shape = tuple(arg.real_array.shape.dim)
72
+ return np.array(arg.real_array.data, dtype=np.float64).reshape(shape)
73
+ elif arg.HasField('complex_array'):
74
+ shape = tuple(arg.complex_array.shape.dim)
75
+ data = [complex(c.real, c.imag) for c in arg.complex_array.data]
76
+ return np.array(data, dtype=np.complex64).reshape(shape)
77
+ elif arg.HasField('json_value'):
78
+ return _json_restore(json.loads(arg.json_value))
79
+ else:
80
+ raise ValueError(f"Unknown argument type during unmapping: {arg}")
81
+
82
+ def map_arg(value):
83
+ arg = grpc_pb2.Argument()
84
+
85
+ if isinstance(value, (bool, np.bool_)):
86
+ arg.bool_value = bool(value)
87
+ elif hasattr(value, "as_payload"):
88
+ return map_arg(value.as_payload())
89
+ elif value is None or isinstance(value, dict):
90
+ arg.json_value = json.dumps(_json_safe(value), separators=(",", ":"))
91
+ elif isinstance(value, (int, np.integer)):
92
+ arg.int64_value = int(value)
93
+ elif isinstance(value, (float, np.floating)):
94
+ arg.float_value = float(value)
95
+ elif isinstance(value, str):
96
+ arg.string_value = value
97
+ elif isinstance(value, (list, tuple)):
98
+ try:
99
+ array = np.asarray(value)
100
+ except Exception:
101
+ arg.json_value = json.dumps(_json_safe(value), separators=(",", ":"))
102
+ return arg
103
+ if array.dtype == object:
104
+ try:
105
+ array = np.stack(value)
106
+ except Exception:
107
+ arg.json_value = json.dumps(_json_safe(value), separators=(",", ":"))
108
+ return arg
109
+ return map_arg(array)
110
+ elif isinstance(value, np.ndarray):
111
+ if value.dtype == object:
112
+ raise ValueError(f"Cannot map object-dtype array: {value!r}")
113
+ if np.iscomplexobj(value):
114
+ complex_array = arg.complex_array
115
+ complex_array.shape.dim.extend(value.shape)
116
+ for num in value.ravel():
117
+ complex_num = complex_array.data.add()
118
+ complex_num.real = float(num.real)
119
+ complex_num.imag = float(num.imag)
120
+ else:
121
+ float_array = arg.real_array
122
+ float_array.shape.dim.extend(value.shape)
123
+ float_array.data.extend(np.asarray(value, dtype=np.float32).ravel())
124
+ else:
125
+ raise ValueError(f"Unknown argument type during mapping: {value}")
126
+ return arg
127
+
128
+ def map_array_proto(np_array):
129
+ arg = grpc_pb2.Argument()
130
+
131
+ # Check if the array is complex
132
+ if np.iscomplexobj(np_array):
133
+ complex_array = grpc_pb2.ComplexArray()
134
+ for num in np_array.flat:
135
+ complex_number = complex_array.data.add()
136
+ complex_number.real = num.real
137
+ complex_number.imag = num.imag
138
+ arg.complex_array.CopyFrom(complex_array)
139
+ else:
140
+ # Handle as a regular float array
141
+ float_array = grpc_pb2.FloatArray()
142
+ float_array.data.extend(np_array.flat)
143
+ arg.float_array.CopyFrom(float_array)
144
+
145
+ return arg
146
+
147
+ def unmap_array_proto(arg):
148
+ # Check which type of array is available and convert appropriately
149
+ if arg.HasField('complex_array'):
150
+ # Convert ComplexArray to a numpy array of complex numbers
151
+ data = [complex(cn.real, cn.imag) for cn in arg.complex_array.data]
152
+ return np.array(data, dtype=np.complex64)
153
+ elif arg.HasField('float_array'):
154
+ # Convert FloatArray to a numpy array of floats
155
+ return np.array(arg.float_array.data, dtype=np.float32)
156
+ else:
157
+ raise ValueError("Argument does not contain a recognizable array.")
@@ -17,6 +17,7 @@ session = PromptSession()
17
17
  DEFAULT_TIMEZONE_NOTE = "All times are in Pacific Time (Los Angeles)"
18
18
  DEFAULT_TOS_URL = "https://remoterf.net/tos"
19
19
  SERVER_TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
20
+ BANNER_CREDIT = "Created at UCLA by E. Ge and I. Roberts."
20
21
 
21
22
 
22
23
  def _banner_note() -> str:
@@ -28,6 +29,10 @@ def _banner_note() -> str:
28
29
  return text or DEFAULT_TIMEZONE_NOTE
29
30
 
30
31
 
32
+ def _banner_details() -> str:
33
+ return f"\n{BANNER_CREDIT}\nCurrent version: {print_my_version()}\n{_banner_note()}"
34
+
35
+
31
36
  def _tos_notice_text() -> str:
32
37
  notice_path = Path(__file__).resolve().parents[1] / "common" / "tos_notice.txt"
33
38
  try:
@@ -66,7 +71,7 @@ def _format_reservation_range(start_time: datetime.datetime, end_time: datetime.
66
71
  return f"{start} - {end}"
67
72
 
68
73
  def welcome():
69
- printf(f"Welcome to the RemoteRF Platform", (Sty.BOLD, Sty.BLUE), f"\nCurrent version: {print_my_version()} \n{_banner_note()}", (Sty.GRAY))
74
+ printf(f"Welcome to the RemoteRF Platform", (Sty.BOLD, Sty.BLUE), _banner_details(), (Sty.GRAY))
70
75
  try:
71
76
  inpu = session.prompt(stylize("Please ", Sty.DEFAULT, "login", Sty.GREEN, " or ", Sty.DEFAULT, "register", Sty.RED, " to continue. (", Sty.DEFAULT, 'l', Sty.GREEN, "/", Sty.DEFAULT, 'r', Sty.RED, "): ", Sty.DEFAULT))
72
77
  if inpu == 'r':
@@ -103,7 +108,7 @@ def welcome():
103
108
  exit()
104
109
 
105
110
  def title():
106
- printf(f"Welcome to the RemoteRF Platform", (Sty.BOLD, Sty.BLUE), f"\nCurrent version: {print_my_version()} \n{_banner_note()}", (Sty.GRAY))
111
+ printf(f"Welcome to the RemoteRF Platform", (Sty.BOLD, Sty.BLUE), _banner_details(), (Sty.GRAY))
107
112
  printf("Terms of Service: ", Sty.BOLD, _tos_url(), Sty.DEFAULT)
108
113
  # printf(f"Logged in as: ", Sty.DEFAULT, f'{account.username}', Sty.MAGENTA)
109
114
  printf(f"Input ", Sty.DEFAULT, "'help' ", Sty.BRIGHT_GREEN, "for a list of avaliable commands.", Sty.DEFAULT)