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.
@@ -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
- - 0020: TSM commands;
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, cargo2: int = 0x1777) -> str:
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
- cargo2 (int): Cargo 2 part of the command string.
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=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 sys
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
- endpoint = connect_address(PROTOCOL, HOSTNAME, COMMANDING_PORT)
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
- with RegistryClient() as reg:
206
- service = reg.discover_service(SERVICE_TYPE)
207
-
208
- if service:
209
- protocol = service.get("protocol", "tcp")
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
- if is_control_server_active(endpoint):
224
- rich.print("Ariel TCU: [green]active")
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")
@@ -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()
@@ -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
- logger = logging.getLogger("egse.ariel.tcu")
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
- logger.warning("Couldn't establish connection to the Ariel TCU, check the log messages.")
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