ariel-tcu 0.17.3__py3-none-any.whl → 0.18.0__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.18.0.dist-info/METADATA +40 -0
- ariel_tcu-0.18.0.dist-info/RECORD +16 -0
- {ariel_tcu-0.17.3.dist-info → ariel_tcu-0.18.0.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 +62 -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/METADATA +0 -14
- ariel_tcu-0.17.3.dist-info/RECORD +0 -15
- {ariel_tcu-0.17.3.dist-info → ariel_tcu-0.18.0.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,13 +40,37 @@ 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
|
|
|
47
65
|
|
|
48
66
|
class TcuControlServer(ControlServer):
|
|
49
67
|
def __init__(self, simulator: bool = False):
|
|
68
|
+
"""Initialisation of an Ariel TCU Control Server.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
simulator (bool): Indicates whether to operate in simulator mode.
|
|
72
|
+
"""
|
|
73
|
+
|
|
50
74
|
super().__init__()
|
|
51
75
|
|
|
52
76
|
multiprocessing.current_process().name = PROCESS_NAME
|
|
@@ -158,6 +182,7 @@ def start(
|
|
|
158
182
|
):
|
|
159
183
|
"""Starts the Ariel TCU Control Server."""
|
|
160
184
|
|
|
185
|
+
# noinspection PyBroadException
|
|
161
186
|
try:
|
|
162
187
|
controller = TcuControlServer(simulator)
|
|
163
188
|
controller.serve()
|
|
@@ -169,9 +194,6 @@ def start(
|
|
|
169
194
|
sys.exit(exit_code)
|
|
170
195
|
except Exception:
|
|
171
196
|
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
197
|
|
|
176
198
|
return 0
|
|
177
199
|
|
|
@@ -182,14 +204,11 @@ def stop():
|
|
|
182
204
|
|
|
183
205
|
with RegistryClient() as reg:
|
|
184
206
|
service = reg.discover_service(SERVICE_TYPE)
|
|
185
|
-
rich.print("service = ", service)
|
|
186
207
|
|
|
187
208
|
if service:
|
|
188
209
|
proxy = ServiceProxy(protocol="tcp", hostname=service["host"], port=service["metadata"]["service_port"])
|
|
189
210
|
proxy.quit_server()
|
|
190
211
|
else:
|
|
191
|
-
# *_, device_type, controller_type = get_hexapod_controller_pars(device_id)
|
|
192
|
-
|
|
193
212
|
try:
|
|
194
213
|
with TcuProxy() as tcu_proxy:
|
|
195
214
|
with tcu_proxy.get_service_proxy() as sp:
|
|
@@ -202,26 +221,34 @@ def stop():
|
|
|
202
221
|
def status():
|
|
203
222
|
"""Requests the status information from the Ariel TCU Control Server."""
|
|
204
223
|
|
|
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
|
|
224
|
+
if COMMANDING_PORT != 0:
|
|
225
|
+
endpoint = connect_address(PROTOCOL, HOSTNAME, COMMANDING_PORT)
|
|
226
|
+
port = COMMANDING_PORT
|
|
227
|
+
service_port = SERVICE_PORT
|
|
228
|
+
monitoring_port = MONITORING_PORT
|
|
222
229
|
|
|
223
|
-
|
|
224
|
-
|
|
230
|
+
else:
|
|
231
|
+
with RegistryClient() as reg:
|
|
232
|
+
service = reg.discover_service(SERVICE_TYPE)
|
|
233
|
+
|
|
234
|
+
if service:
|
|
235
|
+
protocol = service.get("protocol", "tcp")
|
|
236
|
+
hostname = service["host"]
|
|
237
|
+
port = service["port"]
|
|
238
|
+
service_port = service["metadata"]["service_port"]
|
|
239
|
+
monitoring_port = service["metadata"]["monitoring_port"]
|
|
240
|
+
endpoint = connect_address(protocol, hostname, port)
|
|
241
|
+
else:
|
|
242
|
+
rich.print(
|
|
243
|
+
f"[red]The Ariel TCU Control Server isn't registered as a service. The Control Server cannot be "
|
|
244
|
+
f"contacted without the required information from the service registry.[/]"
|
|
245
|
+
)
|
|
246
|
+
rich.print("Ariel TCU: [red]not active")
|
|
247
|
+
return
|
|
248
|
+
|
|
249
|
+
# noinspection PyUnboundLocalVariable
|
|
250
|
+
if is_control_server_active(endpoint, timeout=2):
|
|
251
|
+
rich.print(f"Ariel TCU: [green]active -> {endpoint}")
|
|
225
252
|
|
|
226
253
|
with TcuProxy() as tcu:
|
|
227
254
|
sim = tcu.is_simulator()
|
|
@@ -229,8 +256,11 @@ def status():
|
|
|
229
256
|
ip = tcu.get_ip_address()
|
|
230
257
|
rich.print(f"mode: {'simulator' if sim else 'device'}{'' if connected else ' not'} connected")
|
|
231
258
|
rich.print(f"hostname: {ip}")
|
|
259
|
+
# noinspection PyUnboundLocalVariable
|
|
232
260
|
rich.print(f"commanding port: {port}")
|
|
261
|
+
# noinspection PyUnboundLocalVariable
|
|
233
262
|
rich.print(f"service port: {service_port}")
|
|
263
|
+
# noinspection PyUnboundLocalVariable
|
|
234
264
|
rich.print(f"monitoring port: {monitoring_port}")
|
|
235
265
|
else:
|
|
236
266
|
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
|
|