ariel-tcu 0.17.3__py3-none-any.whl → 0.17.4__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.
- ariel_tcu/settings.yaml +4 -0
- {ariel_tcu-0.17.3.dist-info → ariel_tcu-0.17.4.dist-info}/METADATA +1 -1
- ariel_tcu-0.17.4.dist-info/RECORD +16 -0
- {ariel_tcu-0.17.3.dist-info → ariel_tcu-0.17.4.dist-info}/entry_points.txt +3 -0
- egse/ariel/tcu/__init__.py +12 -7
- egse/ariel/tcu/tcu.py +108 -16
- egse/ariel/tcu/tcu_cmd_utils.py +65 -8
- egse/ariel/tcu/tcu_cs.py +56 -32
- egse/ariel/tcu/tcu_devif.py +27 -0
- egse/ariel/tcu/tcu_protocol.py +2 -2
- egse/ariel/tcu/tcu_ui.py +693 -0
- ariel_tcu-0.17.3.dist-info/RECORD +0 -15
- {ariel_tcu-0.17.3.dist-info → ariel_tcu-0.17.4.dist-info}/WHEEL +0 -0
egse/ariel/tcu/tcu_cmd_utils.py
CHANGED
|
@@ -11,7 +11,7 @@ Reference documents:
|
|
|
11
11
|
- RD02: ARIEL TCU Data Handling (ARIEL-IEEC-PL-TN-007), v1.0
|
|
12
12
|
- RD03: TCU code provided by Vladimiro Noce (priv. comm.)
|
|
13
13
|
- RD04: ARIEL Telescope Control Unit Design Description Document (ARIEL-IEEC-PL-DD-001), v1.10
|
|
14
|
-
- RD05: ARIEL TCU FW Architecture Design(ARIEL-IEEC-PL-DD-002), v1.5
|
|
14
|
+
- RD05: ARIEL TCU FW Architecture Design (ARIEL-IEEC-PL-DD-002), v1.5
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
from enum import StrEnum
|
|
@@ -263,7 +263,7 @@ def _create_write_cmd_string(
|
|
|
263
263
|
|
|
264
264
|
Note that this function should not be called directly in the `@dynamic_command` decorator (in the `cmd_string`
|
|
265
265
|
attribute), as this will increase the transaction identifier without actually calling the function (merely
|
|
266
|
-
importing the interface in which such a decorator call is made will increase the transaction identifier)
|
|
266
|
+
importing the interface in which such a decorator call is made will increase the transaction identifier).
|
|
267
267
|
|
|
268
268
|
Args:
|
|
269
269
|
cmd_address (CommandAddress | str | int): Identifier of the commanded device.
|
|
@@ -289,7 +289,7 @@ def _create_read_cmd_string(
|
|
|
289
289
|
|
|
290
290
|
Note that this function should not be called directly in the `@dynamic_command` decorator (in the `cmd_string`
|
|
291
291
|
attribute), as this will increase the transaction identifier without actually calling the function (merely
|
|
292
|
-
importing the interface in which such a decorator call is made will increase the transaction identifier)
|
|
292
|
+
importing the interface in which such a decorator call is made will increase the transaction identifier)>
|
|
293
293
|
|
|
294
294
|
Args:
|
|
295
295
|
cmd_address (CommandAddress | str | int): Identifier of the commanded device.
|
|
@@ -327,7 +327,8 @@ def _create_cmd_string(
|
|
|
327
327
|
- 0001: M2MD axis-1 commands;
|
|
328
328
|
- 0002: M2MD axis-2 commands;
|
|
329
329
|
- 0003: M2MD axis-3 commands;
|
|
330
|
-
-
|
|
330
|
+
- 0004: TSM commands;
|
|
331
|
+
- 0005: HK commands
|
|
331
332
|
- BBBB: Command identifier, internal to the commanded device;
|
|
332
333
|
- CCCC: First 16-bit cargo word;
|
|
333
334
|
- DDDD: Second 16-bit cargo word;
|
|
@@ -335,7 +336,7 @@ def _create_cmd_string(
|
|
|
335
336
|
|
|
336
337
|
Note that this function should not be called directly in the `@dynamic_command` decorator (in the `cmd_string`
|
|
337
338
|
attribute), as this will increase the transaction identifier without actually calling the function (merely
|
|
338
|
-
importing the interface in which such a decorator call is made will increase the transaction identifier)
|
|
339
|
+
importing the interface in which such a decorator call is made will increase the transaction identifier).
|
|
339
340
|
|
|
340
341
|
Args:
|
|
341
342
|
packet_type (PacketType): Type of the packet (read or write).
|
|
@@ -792,18 +793,18 @@ def get_prof_gen_axis_speed(axis: CommandAddress | str | int) -> str:
|
|
|
792
793
|
return _create_read_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_SPEED)
|
|
793
794
|
|
|
794
795
|
|
|
795
|
-
def set_prof_gen_axis_speed(axis: CommandAddress | str | int,
|
|
796
|
+
def set_prof_gen_axis_speed(axis: CommandAddress | str | int, speed: int = 0x1777) -> str:
|
|
796
797
|
"""Builds the command string for the M2MD PROF_GEN_AXIS_SPEED write command.
|
|
797
798
|
|
|
798
799
|
Args:
|
|
799
800
|
axis (CommandAddress | str | int): Axis to which the command is sent.
|
|
800
|
-
|
|
801
|
+
speed (int): Cargo 2 part of the command string.
|
|
801
802
|
|
|
802
803
|
Returns:
|
|
803
804
|
Command string for the M2MD PROF_GEN_AXIS_SPEED write command.
|
|
804
805
|
"""
|
|
805
806
|
|
|
806
|
-
return _create_write_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_SPEED, cargo2=
|
|
807
|
+
return _create_write_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_SPEED, cargo2=speed)
|
|
807
808
|
|
|
808
809
|
|
|
809
810
|
def get_prof_gen_axis_state_start(axis: CommandAddress | str | int) -> str:
|
|
@@ -1387,3 +1388,59 @@ def hk_acq_counter() -> str:
|
|
|
1387
1388
|
"""
|
|
1388
1389
|
|
|
1389
1390
|
return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.HK_ACQ_COUNTER)
|
|
1391
|
+
|
|
1392
|
+
|
|
1393
|
+
def general_cmd():
|
|
1394
|
+
"""Decorator for general TCU commands.
|
|
1395
|
+
|
|
1396
|
+
This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
|
|
1397
|
+
component of the TCU that the command is for (which is necessary in the TCU UI).
|
|
1398
|
+
"""
|
|
1399
|
+
|
|
1400
|
+
def decorator(func):
|
|
1401
|
+
func.target_comp = "GENERAL"
|
|
1402
|
+
return func
|
|
1403
|
+
|
|
1404
|
+
return decorator
|
|
1405
|
+
|
|
1406
|
+
|
|
1407
|
+
def m2md_cmd():
|
|
1408
|
+
"""Decorator for M2MD commands.
|
|
1409
|
+
|
|
1410
|
+
This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
|
|
1411
|
+
component of the TCU that the command is for (which is necessary in the TCU UI).
|
|
1412
|
+
"""
|
|
1413
|
+
|
|
1414
|
+
def decorator(func):
|
|
1415
|
+
func.target_comp = "M2MD"
|
|
1416
|
+
return func
|
|
1417
|
+
|
|
1418
|
+
return decorator
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
def tsm_cmd():
|
|
1422
|
+
"""Decorator for TSM commands.
|
|
1423
|
+
|
|
1424
|
+
This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
|
|
1425
|
+
component of the TCU that the command is for (which is necessary in the TCU UI).
|
|
1426
|
+
"""
|
|
1427
|
+
|
|
1428
|
+
def decorator(func):
|
|
1429
|
+
func.target_comp = "TSM"
|
|
1430
|
+
return func
|
|
1431
|
+
|
|
1432
|
+
return decorator
|
|
1433
|
+
|
|
1434
|
+
|
|
1435
|
+
def hk_cmd():
|
|
1436
|
+
"""Decorator for HK commands.
|
|
1437
|
+
|
|
1438
|
+
This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
|
|
1439
|
+
component of the TCU that the command is for (which is necessary in the TCU UI).
|
|
1440
|
+
"""
|
|
1441
|
+
|
|
1442
|
+
def decorator(func):
|
|
1443
|
+
func.target_comp = "HK"
|
|
1444
|
+
return func
|
|
1445
|
+
|
|
1446
|
+
return decorator
|
egse/ariel/tcu/tcu_cs.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""Control Server for the Ariel Telescope Control Unit (TCU)."""
|
|
2
2
|
|
|
3
|
-
import multiprocessing
|
|
4
3
|
import logging
|
|
5
|
-
import
|
|
4
|
+
import multiprocessing
|
|
6
5
|
from typing import Annotated
|
|
7
6
|
|
|
8
|
-
import zmq
|
|
9
|
-
import typer
|
|
10
7
|
import rich
|
|
8
|
+
import sys
|
|
9
|
+
import typer
|
|
10
|
+
import zmq
|
|
11
11
|
|
|
12
12
|
from egse.ariel.tcu import (
|
|
13
13
|
COMMANDING_PORT,
|
|
@@ -19,13 +19,13 @@ from egse.ariel.tcu import (
|
|
|
19
19
|
PROCESS_NAME,
|
|
20
20
|
SERVICE_TYPE,
|
|
21
21
|
)
|
|
22
|
+
from egse.ariel.tcu.tcu import TcuProxy
|
|
23
|
+
from egse.ariel.tcu.tcu_protocol import TcuProtocol
|
|
22
24
|
from egse.control import is_control_server_active, ControlServer
|
|
23
25
|
from egse.registry.client import RegistryClient
|
|
24
26
|
from egse.services import ServiceProxy
|
|
25
27
|
from egse.storage import store_housekeeping_information
|
|
26
28
|
from egse.zmq_ser import connect_address, get_port_number
|
|
27
|
-
from egse.ariel.tcu.tcu_protocol import TcuProtocol
|
|
28
|
-
from egse.ariel.tcu.tcu import TcuProxy
|
|
29
29
|
|
|
30
30
|
logger = logging.getLogger("egse.ariel.tcu")
|
|
31
31
|
|
|
@@ -40,7 +40,25 @@ def is_tcu_cs_active(timeout: float = 0.5) -> bool:
|
|
|
40
40
|
True if the Ariel TCU Control Server is running and replied with the expected answer; False otherwise.
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
if COMMANDING_PORT != 0:
|
|
44
|
+
protocol = PROTOCOL
|
|
45
|
+
hostname = HOSTNAME
|
|
46
|
+
port = COMMANDING_PORT
|
|
47
|
+
|
|
48
|
+
else:
|
|
49
|
+
with RegistryClient() as reg:
|
|
50
|
+
service = reg.discover_service(SERVICE_TYPE)
|
|
51
|
+
|
|
52
|
+
if service:
|
|
53
|
+
protocol = service.get("protocol", "tcp")
|
|
54
|
+
hostname = service["host"]
|
|
55
|
+
port = service["port"]
|
|
56
|
+
|
|
57
|
+
else:
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
# noinspection PyUnboundLocalVariable
|
|
61
|
+
endpoint = connect_address(protocol, hostname, port)
|
|
44
62
|
|
|
45
63
|
return is_control_server_active(endpoint, timeout)
|
|
46
64
|
|
|
@@ -158,6 +176,7 @@ def start(
|
|
|
158
176
|
):
|
|
159
177
|
"""Starts the Ariel TCU Control Server."""
|
|
160
178
|
|
|
179
|
+
# noinspection PyBroadException
|
|
161
180
|
try:
|
|
162
181
|
controller = TcuControlServer(simulator)
|
|
163
182
|
controller.serve()
|
|
@@ -169,9 +188,6 @@ def start(
|
|
|
169
188
|
sys.exit(exit_code)
|
|
170
189
|
except Exception:
|
|
171
190
|
logger.exception("Cannot start the Ariel TCU Control Server")
|
|
172
|
-
# The above line does exactly the same as the traceback, but on the logger
|
|
173
|
-
# import traceback
|
|
174
|
-
# traceback.print_exc(file=sys.stdout)
|
|
175
191
|
|
|
176
192
|
return 0
|
|
177
193
|
|
|
@@ -182,14 +198,11 @@ def stop():
|
|
|
182
198
|
|
|
183
199
|
with RegistryClient() as reg:
|
|
184
200
|
service = reg.discover_service(SERVICE_TYPE)
|
|
185
|
-
rich.print("service = ", service)
|
|
186
201
|
|
|
187
202
|
if service:
|
|
188
203
|
proxy = ServiceProxy(protocol="tcp", hostname=service["host"], port=service["metadata"]["service_port"])
|
|
189
204
|
proxy.quit_server()
|
|
190
205
|
else:
|
|
191
|
-
# *_, device_type, controller_type = get_hexapod_controller_pars(device_id)
|
|
192
|
-
|
|
193
206
|
try:
|
|
194
207
|
with TcuProxy() as tcu_proxy:
|
|
195
208
|
with tcu_proxy.get_service_proxy() as sp:
|
|
@@ -202,26 +215,34 @@ def stop():
|
|
|
202
215
|
def status():
|
|
203
216
|
"""Requests the status information from the Ariel TCU Control Server."""
|
|
204
217
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
hostname = service["host"]
|
|
211
|
-
port = service["port"]
|
|
212
|
-
service_port = service["metadata"]["service_port"]
|
|
213
|
-
monitoring_port = service["metadata"]["monitoring_port"]
|
|
214
|
-
endpoint = connect_address(protocol, hostname, port)
|
|
215
|
-
else:
|
|
216
|
-
rich.print(
|
|
217
|
-
f"[red]The Ariel TCU Control Server isn't registered as a service. The Control Server cannot be "
|
|
218
|
-
f"contacted without the required information from the service registry.[/]"
|
|
219
|
-
)
|
|
220
|
-
rich.print("Ariel TCU: [red]not active")
|
|
221
|
-
return
|
|
218
|
+
if COMMANDING_PORT != 0:
|
|
219
|
+
endpoint = connect_address(PROTOCOL, HOSTNAME, COMMANDING_PORT)
|
|
220
|
+
port = COMMANDING_PORT
|
|
221
|
+
service_port = SERVICE_PORT
|
|
222
|
+
monitoring_port = MONITORING_PORT
|
|
222
223
|
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
else:
|
|
225
|
+
with RegistryClient() as reg:
|
|
226
|
+
service = reg.discover_service(SERVICE_TYPE)
|
|
227
|
+
|
|
228
|
+
if service:
|
|
229
|
+
protocol = service.get("protocol", "tcp")
|
|
230
|
+
hostname = service["host"]
|
|
231
|
+
port = service["port"]
|
|
232
|
+
service_port = service["metadata"]["service_port"]
|
|
233
|
+
monitoring_port = service["metadata"]["monitoring_port"]
|
|
234
|
+
endpoint = connect_address(protocol, hostname, port)
|
|
235
|
+
else:
|
|
236
|
+
rich.print(
|
|
237
|
+
f"[red]The Ariel TCU Control Server isn't registered as a service. The Control Server cannot be "
|
|
238
|
+
f"contacted without the required information from the service registry.[/]"
|
|
239
|
+
)
|
|
240
|
+
rich.print("Ariel TCU: [red]not active")
|
|
241
|
+
return
|
|
242
|
+
|
|
243
|
+
# noinspection PyUnboundLocalVariable
|
|
244
|
+
if is_control_server_active(endpoint, timeout=2):
|
|
245
|
+
rich.print(f"Ariel TCU: [green]active -> {endpoint}")
|
|
225
246
|
|
|
226
247
|
with TcuProxy() as tcu:
|
|
227
248
|
sim = tcu.is_simulator()
|
|
@@ -229,8 +250,11 @@ def status():
|
|
|
229
250
|
ip = tcu.get_ip_address()
|
|
230
251
|
rich.print(f"mode: {'simulator' if sim else 'device'}{'' if connected else ' not'} connected")
|
|
231
252
|
rich.print(f"hostname: {ip}")
|
|
253
|
+
# noinspection PyUnboundLocalVariable
|
|
232
254
|
rich.print(f"commanding port: {port}")
|
|
255
|
+
# noinspection PyUnboundLocalVariable
|
|
233
256
|
rich.print(f"service port: {service_port}")
|
|
257
|
+
# noinspection PyUnboundLocalVariable
|
|
234
258
|
rich.print(f"monitoring port: {monitoring_port}")
|
|
235
259
|
else:
|
|
236
260
|
rich.print("Ariel TCU: [red]not active")
|
egse/ariel/tcu/tcu_devif.py
CHANGED
|
@@ -11,6 +11,8 @@ from egse.settings import Settings
|
|
|
11
11
|
logger = logging.getLogger(__name__)
|
|
12
12
|
DEVICE_SETTINGS = Settings.load("Ariel TCU Controller")
|
|
13
13
|
|
|
14
|
+
EXPECTED_TRANSACTION_ID = -1
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
class TcuError(Exception):
|
|
16
18
|
"""Generic TCU error for low-level classes."""
|
|
@@ -102,3 +104,28 @@ class TcuDeviceInterface(DeviceConnectionInterface, DeviceTransport):
|
|
|
102
104
|
self.arduino.write(command.encode("utf-8"))
|
|
103
105
|
time.sleep(0.05)
|
|
104
106
|
return self.arduino.readline()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class TcuHexInterface(DeviceTransport):
|
|
110
|
+
"""Transport class to generate the hex strings that are sent to the TCU."""
|
|
111
|
+
|
|
112
|
+
def trans(self, command: str) -> bytes:
|
|
113
|
+
"""Returns the given command string as bytes.
|
|
114
|
+
|
|
115
|
+
This can be used to:
|
|
116
|
+
|
|
117
|
+
- Test whether the command string is built correctly (and the transaction identifier is incremented for
|
|
118
|
+
each command call);
|
|
119
|
+
- Generate the hex string that is sent to the TCU, such that it can be displayed in the TCU UI.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
command (str): Command string to encode.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Encoded command string.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
global EXPECTED_TRANSACTION_ID
|
|
129
|
+
EXPECTED_TRANSACTION_ID += 1
|
|
130
|
+
|
|
131
|
+
return command.encode()
|
egse/ariel/tcu/tcu_protocol.py
CHANGED
|
@@ -15,7 +15,7 @@ from egse.zmq_ser import bind_address
|
|
|
15
15
|
|
|
16
16
|
_HERE = Path(__file__).parent
|
|
17
17
|
DEVICE_SETTINGS = Settings.load(filename="tcu.yaml", location=_HERE)
|
|
18
|
-
|
|
18
|
+
LOGGER = logging.getLogger("egse.ariel.tcu")
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class TcuCommand(ClientServerCommand):
|
|
@@ -47,7 +47,7 @@ class TcuProtocol(DynamicCommandProtocol):
|
|
|
47
47
|
try:
|
|
48
48
|
self.tcu.connect()
|
|
49
49
|
except ConnectionError:
|
|
50
|
-
|
|
50
|
+
LOGGER.warning("Couldn't establish connection to the Ariel TCU, check the log messages.")
|
|
51
51
|
|
|
52
52
|
# self.metrics = define_metrics("TCU")
|
|
53
53
|
|