ariel-tcu 0.17.2__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.
@@ -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,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
- 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
 
@@ -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
- 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
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
- if is_control_server_active(endpoint):
224
- rich.print("Ariel TCU: [green]active")
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")
@@ -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