rtint 0.0.3__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.
- rtint/_version.py +24 -0
- rtint/rtint_acquisition.py +327 -0
- rtint/rtint_counter.py +202 -0
- rtint/rtint_ethercat.py +127 -0
- rtint/rtint_filter.py +872 -0
- rtint/rtint_generator.py +577 -0
- rtint/rtint_hardware.py +336 -0
- rtint/rtint_lut.py +143 -0
- rtint/rtint_motor.py +191 -0
- rtint/rtint_parameter.py +105 -0
- rtint/rtint_regul.py +310 -0
- rtint/rtint_signal.py +42 -0
- rtint/rtint_trigger.py +107 -0
- rtint/rtint_utils.py +648 -0
- rtint-0.0.3.dist-info/METADATA +74 -0
- rtint-0.0.3.dist-info/RECORD +19 -0
- rtint-0.0.3.dist-info/WHEEL +5 -0
- rtint-0.0.3.dist-info/licenses/LICENSE +238 -0
- rtint-0.0.3.dist-info/top_level.txt +1 -0
rtint/rtint_parameter.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# This file is part of the mechatronic project
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) Beamline Control Unit, ESRF
|
|
4
|
+
# Distributed under the GNU LGPLv3. See LICENSE for more info.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
REAL-TIME TARGET PARAMETERS
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
from collections.abc import MutableSequence
|
|
12
|
+
from treelib import Tree
|
|
13
|
+
from tabulate import tabulate
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RtintHdwParameterController:
|
|
17
|
+
def __init__(self, tg):
|
|
18
|
+
self._tg = tg
|
|
19
|
+
self._system = tg._system
|
|
20
|
+
self._program = tg._program
|
|
21
|
+
self._param_tree = self._program.tree.params
|
|
22
|
+
|
|
23
|
+
self._set_attr_root_params()
|
|
24
|
+
self._set_default_params()
|
|
25
|
+
|
|
26
|
+
def __info__(self, debug=False):
|
|
27
|
+
if self._root_params is None:
|
|
28
|
+
return "\n No parameters in the model"
|
|
29
|
+
lines = [["Name", "Value"]]
|
|
30
|
+
for parameter in self._root_params:
|
|
31
|
+
lines.append([parameter, repr(getattr(self, parameter))])
|
|
32
|
+
return "\n" + tabulate(lines, headers="firstrow", tablefmt="grid", stralign="left")
|
|
33
|
+
|
|
34
|
+
# Used to automatically add "root parameters" as attributes for easy access/modification
|
|
35
|
+
def _set_attr_root_params(self):
|
|
36
|
+
for param_name in self._root_params:
|
|
37
|
+
setattr(self.__class__, param_name, RtintParam(self, param_name))
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def _root_params(self):
|
|
41
|
+
return [
|
|
42
|
+
param
|
|
43
|
+
for param in self._param_tree
|
|
44
|
+
if (self._program.name not in param and param[-1] != "_")
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
# Set default params as defined in the YML file
|
|
48
|
+
def _set_default_params(self):
|
|
49
|
+
params_yml = self._tg._config.get("default_parameters")
|
|
50
|
+
if params_yml is None:
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
for param in params_yml:
|
|
54
|
+
try:
|
|
55
|
+
if isinstance(param["value"], MutableSequence):
|
|
56
|
+
self.set(param["path"], np.array(param["value"]))
|
|
57
|
+
else:
|
|
58
|
+
self.set(param["path"], param["value"])
|
|
59
|
+
except Exception:
|
|
60
|
+
print(
|
|
61
|
+
f"Default parameter with path \"{param['path']}\" does not exist in the model"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def _tree(self):
|
|
66
|
+
tree = Tree()
|
|
67
|
+
root = self._program.name
|
|
68
|
+
tree.create_node(root, root)
|
|
69
|
+
|
|
70
|
+
for path in self._param_tree:
|
|
71
|
+
parts = path.split("/")
|
|
72
|
+
parent = root
|
|
73
|
+
for i, p in enumerate(parts[1:], 1): # start at index 1
|
|
74
|
+
node_id = "/".join(
|
|
75
|
+
parts[: i + 1]
|
|
76
|
+
) # build unique identifier up to this level
|
|
77
|
+
if not tree.contains(node_id):
|
|
78
|
+
tree.create_node(p, node_id, parent=parent)
|
|
79
|
+
parent = node_id
|
|
80
|
+
|
|
81
|
+
return tree
|
|
82
|
+
|
|
83
|
+
def set(self, param_name, value):
|
|
84
|
+
# Automatically add "model_name" if necessary
|
|
85
|
+
if "/" in param_name:
|
|
86
|
+
param_name = self._program.name + "/" + param_name
|
|
87
|
+
self._param_tree[param_name].value = value
|
|
88
|
+
|
|
89
|
+
def get(self, param_name):
|
|
90
|
+
# Automatically add "model_name" if necessary
|
|
91
|
+
if "/" in param_name:
|
|
92
|
+
param_name = self._program.name + "/" + param_name
|
|
93
|
+
return self._param_tree[param_name].value
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class RtintParam:
|
|
97
|
+
def __init__(self, param_ctl, param_name):
|
|
98
|
+
self._param_ctl = param_ctl
|
|
99
|
+
self._name = param_name
|
|
100
|
+
|
|
101
|
+
def __get__(self, obj, objtype):
|
|
102
|
+
return self._param_ctl.get(self._name)
|
|
103
|
+
|
|
104
|
+
def __set__(self, obj, value):
|
|
105
|
+
self._param_ctl.set(self._name, value)
|
rtint/rtint_regul.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# This file is part of the mechatronic project
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) Beamline Control Unit, ESRF
|
|
4
|
+
# Distributed under the GNU LGPLv3. See LICENSE for more info.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
REAL-TIME TARGET REGULATOR
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import enum
|
|
12
|
+
from tabulate import tabulate
|
|
13
|
+
|
|
14
|
+
RED = "\033[31m"
|
|
15
|
+
GREEN = "\033[32m"
|
|
16
|
+
RESET = "\033[0m"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RegulState(enum.IntEnum):
|
|
20
|
+
Off = 0
|
|
21
|
+
On = 1
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class RegulError(enum.IntEnum):
|
|
25
|
+
NoError = 0
|
|
26
|
+
MinInput = 1
|
|
27
|
+
MaxInput = 2
|
|
28
|
+
MinOutput = 3
|
|
29
|
+
MaxOutput = 4
|
|
30
|
+
ExtError = 5
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RtintHdwRegulController:
|
|
34
|
+
def __init__(self, tg):
|
|
35
|
+
self._tg = tg
|
|
36
|
+
self._reguls: dict[str, RtintHdwRegul] | None = None
|
|
37
|
+
self._load()
|
|
38
|
+
|
|
39
|
+
def __info__(self, debug=False):
|
|
40
|
+
if self._reguls is None:
|
|
41
|
+
return "\n No Regulator in the model"
|
|
42
|
+
|
|
43
|
+
if debug:
|
|
44
|
+
lines = [["Name", "Path", "Wanted", "State", "Error", "Input", "Output"]]
|
|
45
|
+
else:
|
|
46
|
+
lines = [["Name", "Wanted", "State"]]
|
|
47
|
+
|
|
48
|
+
for _regul in self._reguls.values():
|
|
49
|
+
if debug:
|
|
50
|
+
lines.append(
|
|
51
|
+
[
|
|
52
|
+
_regul._name,
|
|
53
|
+
_regul._unique_name,
|
|
54
|
+
_regul.wanted,
|
|
55
|
+
_regul.ctrl_status.name,
|
|
56
|
+
_regul.ctrl_error.name,
|
|
57
|
+
_regul.error_signal,
|
|
58
|
+
_regul.command_signal,
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
lines.append([_regul._name, _regul.wanted, _regul.ctrl_status.name])
|
|
63
|
+
return "\n" + tabulate(lines, headers="firstrow", tablefmt="grid", stralign="left")
|
|
64
|
+
|
|
65
|
+
def _load(self):
|
|
66
|
+
reguls = self._tg._get_all_objects_from_key("bliss_regulator")
|
|
67
|
+
if len(reguls) > 0:
|
|
68
|
+
self._reguls = {}
|
|
69
|
+
for regul in reguls:
|
|
70
|
+
tg_regul = RtintHdwRegul(self._tg, regul)
|
|
71
|
+
|
|
72
|
+
if hasattr(self, tg_regul._name):
|
|
73
|
+
print(
|
|
74
|
+
f"{RED}WARNING: Regulator '{tg_regul._name}' already exists{RESET}"
|
|
75
|
+
)
|
|
76
|
+
return
|
|
77
|
+
else:
|
|
78
|
+
setattr(self, tg_regul._name, tg_regul)
|
|
79
|
+
self._reguls[tg_regul._name] = tg_regul
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class RtintHdwRegul:
|
|
83
|
+
def __init__(self, tg, unique_name):
|
|
84
|
+
self._tg = tg
|
|
85
|
+
self._unique_name = unique_name
|
|
86
|
+
|
|
87
|
+
def __info__(self):
|
|
88
|
+
lines = []
|
|
89
|
+
lines.append(["Name", self._name])
|
|
90
|
+
wanted_str = f"{GREEN}True{RESET}" if self.wanted else f"{RED}False{RESET}"
|
|
91
|
+
lines.append(["Wanted", wanted_str])
|
|
92
|
+
if self.ctrl_status == 0:
|
|
93
|
+
lines.append(["State", f"{RED}{self.ctrl_status.name}{RESET}"])
|
|
94
|
+
lines.append(["Error", f"{RED}{self.ctrl_error.name}{RESET}"])
|
|
95
|
+
if self.ctrl_error != 0:
|
|
96
|
+
lines.append(
|
|
97
|
+
[
|
|
98
|
+
" Output at error",
|
|
99
|
+
"["
|
|
100
|
+
+ ", ".join(f"{x:.2g}" for x in np.ravel(self.command_fault))
|
|
101
|
+
+ "]",
|
|
102
|
+
]
|
|
103
|
+
)
|
|
104
|
+
lines.append(
|
|
105
|
+
[
|
|
106
|
+
" Intput at error",
|
|
107
|
+
"["
|
|
108
|
+
+ ", ".join(f"{x:.2g}" for x in np.ravel(self.error_fault))
|
|
109
|
+
+ "]",
|
|
110
|
+
]
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
lines.append(["State", f"{GREEN}{self.ctrl_status.name}{RESET}"])
|
|
114
|
+
lines.append(["", ""])
|
|
115
|
+
lines.append(
|
|
116
|
+
[
|
|
117
|
+
"Current Error",
|
|
118
|
+
"[" + ", ".join(f"{x:.2g}" for x in np.ravel(self.error_signal)) + "]",
|
|
119
|
+
]
|
|
120
|
+
)
|
|
121
|
+
lines.append(
|
|
122
|
+
[
|
|
123
|
+
"Current Command",
|
|
124
|
+
"["
|
|
125
|
+
+ ", ".join(f"{x:.2g}" for x in np.ravel(self.command_signal))
|
|
126
|
+
+ "]",
|
|
127
|
+
]
|
|
128
|
+
)
|
|
129
|
+
lines.append(["", ""])
|
|
130
|
+
lines.append(
|
|
131
|
+
[
|
|
132
|
+
"Error Limits",
|
|
133
|
+
"["
|
|
134
|
+
+ ", ".join(
|
|
135
|
+
f"{x:.2g}" for x in [self.error_lower_limit, self.error_upper_limit]
|
|
136
|
+
)
|
|
137
|
+
+ "]",
|
|
138
|
+
]
|
|
139
|
+
)
|
|
140
|
+
lines.append(
|
|
141
|
+
[
|
|
142
|
+
"Command Limits",
|
|
143
|
+
"["
|
|
144
|
+
+ ", ".join(
|
|
145
|
+
f"{x:.2g}"
|
|
146
|
+
for x in [self.command_lower_limit, self.command_upper_limit]
|
|
147
|
+
)
|
|
148
|
+
+ "]",
|
|
149
|
+
]
|
|
150
|
+
)
|
|
151
|
+
return tabulate(lines, tablefmt="plain", stralign="right")
|
|
152
|
+
|
|
153
|
+
def _tree(self):
|
|
154
|
+
print("Parameters:")
|
|
155
|
+
self._tg.parameter._tree.subtree(
|
|
156
|
+
self._tg._program.name + "/" + self._unique_name
|
|
157
|
+
).show()
|
|
158
|
+
print("Signals:")
|
|
159
|
+
self._tg.signal._tree.subtree(
|
|
160
|
+
self._tg._program.name + "/" + self._unique_name
|
|
161
|
+
).show()
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def _name(self):
|
|
165
|
+
return self._tg.parameter.get(
|
|
166
|
+
f"{self._unique_name}/bliss_regulator/String"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def error_lower_limit(self):
|
|
171
|
+
"""Minimum allowed input (usually control error)"""
|
|
172
|
+
return self._tg.parameter.get(f"{self._unique_name}/error_lower_limit")
|
|
173
|
+
|
|
174
|
+
@error_lower_limit.setter
|
|
175
|
+
def error_lower_limit(self, value):
|
|
176
|
+
if value < self.error_upper_limit:
|
|
177
|
+
self._tg.parameter.set(
|
|
178
|
+
f"{self._unique_name}/error_lower_limit", value
|
|
179
|
+
)
|
|
180
|
+
else:
|
|
181
|
+
raise ValueError(
|
|
182
|
+
f"error_lower_limit {value} must be < {self.error_upper_limit}"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def error_upper_limit(self):
|
|
187
|
+
"""Maximum allowed input (usually control error)"""
|
|
188
|
+
return self._tg.parameter.get(f"{self._unique_name}/error_upper_limit")
|
|
189
|
+
|
|
190
|
+
@error_upper_limit.setter
|
|
191
|
+
def error_upper_limit(self, value):
|
|
192
|
+
if value > self.error_lower_limit:
|
|
193
|
+
self._tg.parameter.set(
|
|
194
|
+
f"{self._unique_name}/error_upper_limit", value
|
|
195
|
+
)
|
|
196
|
+
else:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
f"error_upper_limit {value} must be > {self.error_lower_limit}"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def command_lower_limit(self):
|
|
203
|
+
"""Mimum allowed output (usually control command signal)"""
|
|
204
|
+
return self._tg.parameter.get(f"{self._unique_name}/command_lower_limit")
|
|
205
|
+
|
|
206
|
+
@command_lower_limit.setter
|
|
207
|
+
def command_lower_limit(self, value):
|
|
208
|
+
if value < self.command_upper_limit:
|
|
209
|
+
self._tg.parameter.set(
|
|
210
|
+
f"{self._unique_name}/command_lower_limit", value
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
raise ValueError(
|
|
214
|
+
f"command_lower_limit {value} must be < {self.command_upper_limit}"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def command_upper_limit(self):
|
|
219
|
+
"""Maximum allowed output (usually control command signal)"""
|
|
220
|
+
return self._tg.parameter.get(f"{self._unique_name}/command_upper_limit")
|
|
221
|
+
|
|
222
|
+
@command_upper_limit.setter
|
|
223
|
+
def command_upper_limit(self, value):
|
|
224
|
+
if value > self.command_lower_limit:
|
|
225
|
+
self._tg.parameter.set(
|
|
226
|
+
f"{self._unique_name}/command_upper_limit", value
|
|
227
|
+
)
|
|
228
|
+
else:
|
|
229
|
+
raise ValueError(
|
|
230
|
+
f"command_upper_limit {value} must be > {self.command_lower_limit}"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def error_fault(self):
|
|
235
|
+
"""Stored input (usually error signal) when the regul was last turned OFF."""
|
|
236
|
+
return self._tg.signal.get(f"{self._unique_name}/error_fault")
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def command_fault(self):
|
|
240
|
+
"""Stored command signal when the regul was last turned OFF."""
|
|
241
|
+
return self._tg.signal.get(f"{self._unique_name}/command_fault")
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def wanted(self):
|
|
245
|
+
"""Is the regul is wanted?"""
|
|
246
|
+
return bool(int(self._tg.signal.get(f"{self._unique_name}/ctrl_wanted")))
|
|
247
|
+
|
|
248
|
+
def on(self):
|
|
249
|
+
"""Turn the regul ON"""
|
|
250
|
+
self.reset_error()
|
|
251
|
+
self._tg.parameter.set(f"{self._unique_name}/wanted/Value", 1)
|
|
252
|
+
|
|
253
|
+
def off(self):
|
|
254
|
+
"""Turn the regul OFF"""
|
|
255
|
+
self._tg.parameter.set(f"{self._unique_name}/wanted/Value", 0)
|
|
256
|
+
|
|
257
|
+
def reset_error(self):
|
|
258
|
+
"""If the regul was OFF due to too large input or output, reset the error to be
|
|
259
|
+
able to turn it ON again."""
|
|
260
|
+
reset_error = int(
|
|
261
|
+
self._tg.parameter.get(f"{self._unique_name}/reset_error/Bias")
|
|
262
|
+
)
|
|
263
|
+
self._tg.parameter.set(
|
|
264
|
+
f"{self._unique_name}/reset_error/Bias", reset_error + 1
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def fault_time(self):
|
|
269
|
+
"""IF the regul goes from ON to OFF, time it takes to put the command signal at zero."""
|
|
270
|
+
return self._tg.parameter.get(f"{self._unique_name}/fault_time")
|
|
271
|
+
|
|
272
|
+
@fault_time.setter
|
|
273
|
+
def fault_time(self, value):
|
|
274
|
+
if value <= 0:
|
|
275
|
+
raise ValueError("fault_time must be positive")
|
|
276
|
+
self._tg.parameter.set(f"{self._unique_name}/fault_time", value)
|
|
277
|
+
|
|
278
|
+
@property
|
|
279
|
+
def fault_output(self):
|
|
280
|
+
"""IF the regul goes from ON to OFF, the output signal will be fault_output."""
|
|
281
|
+
return self._tg.parameter.get(f"{self._unique_name}/fault_output")
|
|
282
|
+
|
|
283
|
+
@fault_output.setter
|
|
284
|
+
def fault_output(self, value):
|
|
285
|
+
self._tg.parameter.set(f"{self._unique_name}/fault_output", value)
|
|
286
|
+
|
|
287
|
+
@property
|
|
288
|
+
def ctrl_error(self):
|
|
289
|
+
"""It regul is OFF due to some error, display this error."""
|
|
290
|
+
# 0:no_error 1:min_input_reached 2:max_input_reached 3:min_output_reached 4:max_output_reached 5:ext_error
|
|
291
|
+
return RegulError(
|
|
292
|
+
int(self._tg.signal.get(f"{self._unique_name}/ctrl_error"))
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def ctrl_status(self):
|
|
297
|
+
# 0:off 1:on
|
|
298
|
+
return RegulState(
|
|
299
|
+
int(self._tg.signal.get(f"{self._unique_name}/ctrl_status"))
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
def error_signal(self):
|
|
304
|
+
"""Regul input, usually error signal."""
|
|
305
|
+
return self._tg.signal.get(f"{self._unique_name}/error_signal")
|
|
306
|
+
|
|
307
|
+
@property
|
|
308
|
+
def command_signal(self):
|
|
309
|
+
"""Regul output, usually command signal."""
|
|
310
|
+
return self._tg.signal.get(f"{self._unique_name}/command_signal")
|
rtint/rtint_signal.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# This file is part of the mechatronic project
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) Beamline Control Unit, ESRF
|
|
4
|
+
# Distributed under the GNU LGPLv3. See LICENSE for more info.
|
|
5
|
+
|
|
6
|
+
from treelib import Tree
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
SIGNALS
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RtintHdwSignalController:
|
|
14
|
+
def __init__(self, tg):
|
|
15
|
+
self._tg = tg
|
|
16
|
+
self._system = tg._system
|
|
17
|
+
self._program = tg._program
|
|
18
|
+
self._signal_tree = tg._program.tree.signals
|
|
19
|
+
|
|
20
|
+
def __info__(self):
|
|
21
|
+
self._tree.show()
|
|
22
|
+
return ""
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def _tree(self):
|
|
26
|
+
tree = Tree()
|
|
27
|
+
root = self._program.name
|
|
28
|
+
tree.create_node(root, root)
|
|
29
|
+
|
|
30
|
+
for path in self._signal_tree:
|
|
31
|
+
parts = path.split("/")
|
|
32
|
+
parent = root
|
|
33
|
+
for p in parts[1:]:
|
|
34
|
+
node_id = "/".join(parts[: parts.index(p) + 1]) # unique identifier
|
|
35
|
+
if not tree.contains(node_id):
|
|
36
|
+
tree.create_node(p, node_id, parent=parent)
|
|
37
|
+
parent = node_id
|
|
38
|
+
|
|
39
|
+
return tree
|
|
40
|
+
|
|
41
|
+
def get(self, signal_path):
|
|
42
|
+
return self._signal_tree[self._program.name + "/" + signal_path].value
|
rtint/rtint_trigger.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# This file is part of the mechatronic project
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) Beamline Control Unit, ESRF
|
|
4
|
+
# Distributed under the GNU LGPLv3. See LICENSE for more info.
|
|
5
|
+
|
|
6
|
+
from tabulate import tabulate
|
|
7
|
+
|
|
8
|
+
RED = "\033[31m"
|
|
9
|
+
GREEN = "\033[32m"
|
|
10
|
+
RESET = "\033[0m"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
REAL-TIME TARGET triggers
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RtintHdwTriggerController:
|
|
19
|
+
def __init__(self, tg):
|
|
20
|
+
self._tg = tg
|
|
21
|
+
self._triggers: dict[str, RtintHdwTrigger] | None = None
|
|
22
|
+
self._load()
|
|
23
|
+
|
|
24
|
+
def __info__(self, debug=False):
|
|
25
|
+
if self._triggers is None:
|
|
26
|
+
return "\n No trigger in the model"
|
|
27
|
+
|
|
28
|
+
if debug:
|
|
29
|
+
lines = [["Name", "Path", "Trigger Number"]]
|
|
30
|
+
else:
|
|
31
|
+
lines = [["Name"]]
|
|
32
|
+
|
|
33
|
+
for _trigger in self._triggers.values():
|
|
34
|
+
if debug:
|
|
35
|
+
lines.append(
|
|
36
|
+
[_trigger._name, _trigger._unique_name, _trigger.trig_number]
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
lines.append([_trigger._name])
|
|
40
|
+
return "\n" + tabulate(lines, headers="firstrow", tablefmt="grid", stralign="left")
|
|
41
|
+
|
|
42
|
+
def _load(self):
|
|
43
|
+
triggers = self._tg._get_all_objects_from_key("bliss_trigger")
|
|
44
|
+
if len(triggers) > 0:
|
|
45
|
+
self._triggers = {}
|
|
46
|
+
for trigger in triggers:
|
|
47
|
+
tg_trigger = RtintHdwTrigger(self._tg, trigger)
|
|
48
|
+
|
|
49
|
+
if hasattr(self, tg_trigger._name):
|
|
50
|
+
print(
|
|
51
|
+
f"{RED}WARNING: Trigger '{tg_trigger._name}' already exists{RESET}"
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
else:
|
|
55
|
+
setattr(self, tg_trigger._name, tg_trigger)
|
|
56
|
+
self._triggers[tg_trigger._name] = tg_trigger
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class RtintHdwTrigger:
|
|
60
|
+
def __init__(self, tg, unique_name):
|
|
61
|
+
self._tg = tg
|
|
62
|
+
self._unique_name = unique_name
|
|
63
|
+
|
|
64
|
+
def __info__(self):
|
|
65
|
+
lines = []
|
|
66
|
+
lines.append(["Name", self._name])
|
|
67
|
+
lines.append(["Unique Name", self._unique_name])
|
|
68
|
+
lines.append(["", ""])
|
|
69
|
+
lines.append(["Number of trigs", self.trig_number])
|
|
70
|
+
return tabulate(lines, tablefmt="plain", stralign="right")
|
|
71
|
+
|
|
72
|
+
def _tree(self):
|
|
73
|
+
print("Parameters:")
|
|
74
|
+
self._tg.parameter._tree.subtree(
|
|
75
|
+
self._tg._program.name + "/" + self._unique_name
|
|
76
|
+
).show()
|
|
77
|
+
print("Signals:")
|
|
78
|
+
self._tg.signal._tree.subtree(
|
|
79
|
+
self._tg._program.name + "/" + self._unique_name
|
|
80
|
+
).show()
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def _name(self):
|
|
84
|
+
return self._tg.parameter.get(
|
|
85
|
+
f"{self._unique_name}/bliss_trigger/String"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def trig_number(self):
|
|
90
|
+
return int(self._tg.signal.get(f"{self._unique_name}/trig_number"))
|
|
91
|
+
|
|
92
|
+
def reset_trig_number(self):
|
|
93
|
+
self._tg.parameter.set(f"{self._unique_name}/start_trigger/Bias", 0)
|
|
94
|
+
reset_trigger = int(
|
|
95
|
+
self._tg.parameter.get(f"{self._unique_name}/reset_trig_number/Bias")
|
|
96
|
+
)
|
|
97
|
+
self._tg.parameter.set(
|
|
98
|
+
f"{self._unique_name}/reset_trig_number/Bias", reset_trigger + 1
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def trig(self):
|
|
102
|
+
bias = int(
|
|
103
|
+
self._tg.parameter.get(f"{self._unique_name}/start_trigger/Bias")
|
|
104
|
+
)
|
|
105
|
+
self._tg.parameter.set(
|
|
106
|
+
f"{self._unique_name}/start_trigger/Bias", bias + 1
|
|
107
|
+
)
|