fastcs-pandablocks 0.2.0a3__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.
- fastcs_pandablocks/__init__.py +3 -0
- fastcs_pandablocks/__main__.py +9 -0
- fastcs_pandablocks/_version.py +34 -0
- fastcs_pandablocks/panda/__init__.py +0 -0
- fastcs_pandablocks/panda/blocks/__init__.py +4 -0
- fastcs_pandablocks/panda/blocks/block_controller.py +48 -0
- fastcs_pandablocks/panda/blocks/blocks.py +1034 -0
- fastcs_pandablocks/panda/blocks/data.py +625 -0
- fastcs_pandablocks/panda/blocks/versions.py +69 -0
- fastcs_pandablocks/panda/client_wrapper.py +143 -0
- fastcs_pandablocks/panda/controller.yaml +10 -0
- fastcs_pandablocks/panda/io/arm.py +37 -0
- fastcs_pandablocks/panda/io/bits.py +43 -0
- fastcs_pandablocks/panda/io/default.py +36 -0
- fastcs_pandablocks/panda/io/table.py +38 -0
- fastcs_pandablocks/panda/io/units.py +49 -0
- fastcs_pandablocks/panda/panda_controller.py +125 -0
- fastcs_pandablocks/panda/utils.py +52 -0
- fastcs_pandablocks/types/__init__.py +34 -0
- fastcs_pandablocks/types/_annotations.py +42 -0
- fastcs_pandablocks/types/_string_types.py +117 -0
- fastcs_pandablocks-0.2.0a3.dist-info/METADATA +264 -0
- fastcs_pandablocks-0.2.0a3.dist-info/RECORD +27 -0
- fastcs_pandablocks-0.2.0a3.dist-info/WHEEL +5 -0
- fastcs_pandablocks-0.2.0a3.dist-info/entry_points.txt +2 -0
- fastcs_pandablocks-0.2.0a3.dist-info/licenses/LICENSE +201 -0
- fastcs_pandablocks-0.2.0a3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1034 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import enum
|
|
3
|
+
from collections.abc import Generator
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from fastcs.attributes import Attribute, AttributeIO, AttrR, AttrRW, AttrW
|
|
7
|
+
from fastcs.controllers import BaseController
|
|
8
|
+
from fastcs.datatypes import Bool, Enum, Float, Int, String, Table
|
|
9
|
+
from numpy.typing import DTypeLike
|
|
10
|
+
from pandablocks.commands import TableFieldDetails
|
|
11
|
+
from pandablocks.responses import (
|
|
12
|
+
BitMuxFieldInfo,
|
|
13
|
+
BitOutFieldInfo,
|
|
14
|
+
EnumFieldInfo,
|
|
15
|
+
ExtOutBitsFieldInfo,
|
|
16
|
+
ExtOutFieldInfo,
|
|
17
|
+
FieldInfo,
|
|
18
|
+
PosMuxFieldInfo,
|
|
19
|
+
PosOutFieldInfo,
|
|
20
|
+
ScalarFieldInfo,
|
|
21
|
+
SubtypeTimeFieldInfo,
|
|
22
|
+
TableFieldInfo,
|
|
23
|
+
TimeFieldInfo,
|
|
24
|
+
UintFieldInfo,
|
|
25
|
+
)
|
|
26
|
+
from pandablocks.utils import words_to_table
|
|
27
|
+
|
|
28
|
+
from fastcs_pandablocks.panda.client_wrapper import RawPanda
|
|
29
|
+
from fastcs_pandablocks.panda.io.arm import ArmCommand, ArmIORef
|
|
30
|
+
from fastcs_pandablocks.panda.io.bits import BitGroupOnUpdate
|
|
31
|
+
from fastcs_pandablocks.panda.io.default import DefaultFieldIORef
|
|
32
|
+
from fastcs_pandablocks.panda.io.table import TableFieldIORef
|
|
33
|
+
from fastcs_pandablocks.panda.io.units import TimeUnit, UnitsIORef
|
|
34
|
+
from fastcs_pandablocks.panda.utils import panda_value_to_attribute_value
|
|
35
|
+
from fastcs_pandablocks.types import (
|
|
36
|
+
PandaName,
|
|
37
|
+
RawInitialValuesType,
|
|
38
|
+
ResponseType,
|
|
39
|
+
WidgetGroup,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
from .block_controller import BlockController, BlockControllerVector
|
|
43
|
+
from .data import DataController, DatasetAttributes
|
|
44
|
+
from .versions import VersionController
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Blocks:
|
|
48
|
+
"""A wrapper that handles creating controllers and attributes from introspected
|
|
49
|
+
panda data.
|
|
50
|
+
|
|
51
|
+
Unfortunately attributes and names need to be cached throughout the introspection
|
|
52
|
+
process so having this all in one (huge) file is the nicest way to handle this.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, raw_panda: RawPanda, ios: list[AttributeIO]):
|
|
56
|
+
self._raw_panda = raw_panda
|
|
57
|
+
#: The controllers which should be registered by `PandaController` and are
|
|
58
|
+
#: acccessible by panda name.
|
|
59
|
+
self._introspected_controllers: dict[PandaName, BlockController] = {}
|
|
60
|
+
|
|
61
|
+
#: For controllers we add on the fastcs side which aren't accessible
|
|
62
|
+
#: by panda name.
|
|
63
|
+
self._additional_controllers: dict[str, BaseController] = {}
|
|
64
|
+
|
|
65
|
+
#: For keeping track of ext out bits so that updates in the group can be linked
|
|
66
|
+
self._bits_group_names: list[tuple[PandaName, list[PandaName]]] = []
|
|
67
|
+
|
|
68
|
+
#: For keeping track of dataset records so the :Data:Datasets table
|
|
69
|
+
#: can be updated.
|
|
70
|
+
self._dataset_attributes: dict[PandaName, DatasetAttributes] = {}
|
|
71
|
+
|
|
72
|
+
self._ios = ios
|
|
73
|
+
|
|
74
|
+
def get_attribute(self, panda_name: PandaName) -> Attribute:
|
|
75
|
+
return self._introspected_controllers[
|
|
76
|
+
panda_name.up_to_block()
|
|
77
|
+
].panda_name_to_attribute[panda_name]
|
|
78
|
+
|
|
79
|
+
def controllers(self) -> Generator[tuple[str, BaseController], None, None]:
|
|
80
|
+
for (
|
|
81
|
+
panda_name,
|
|
82
|
+
introspected_controller,
|
|
83
|
+
) in self._introspected_controllers.items():
|
|
84
|
+
yield panda_name.attribute_name, introspected_controller
|
|
85
|
+
|
|
86
|
+
yield from self._additional_controllers.items()
|
|
87
|
+
|
|
88
|
+
# ==================================================================================
|
|
89
|
+
# ====== FOR LINKING AND GENERATING POST INTROSPECTION =============================
|
|
90
|
+
# ==================================================================================
|
|
91
|
+
|
|
92
|
+
async def setup_post_introspection(self):
|
|
93
|
+
await asyncio.gather(
|
|
94
|
+
self._link_bits_groups(),
|
|
95
|
+
self._add_version_block(),
|
|
96
|
+
self._add_pcap_arm(),
|
|
97
|
+
self._add_data_block(),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
async def _link_bits_groups(self):
|
|
101
|
+
for group_panda_name, bit_panda_names in self._bits_group_names:
|
|
102
|
+
group_attribute = self.get_attribute(group_panda_name)
|
|
103
|
+
|
|
104
|
+
bit_attributes: list[AttrRW] = [
|
|
105
|
+
self.get_attribute(panda_name) for panda_name in bit_panda_names
|
|
106
|
+
] # type: ignore
|
|
107
|
+
|
|
108
|
+
assert isinstance(group_attribute, AttrRW)
|
|
109
|
+
update_callback = BitGroupOnUpdate(group_attribute, bit_attributes)
|
|
110
|
+
group_attribute.add_on_update_callback(update_callback)
|
|
111
|
+
|
|
112
|
+
for bit_attribute in bit_attributes:
|
|
113
|
+
bit_attribute.description = (
|
|
114
|
+
"Whether this field is set for capture in "
|
|
115
|
+
f"the `{group_panda_name.up_to_field()}` group."
|
|
116
|
+
)
|
|
117
|
+
bit_attribute.add_on_update_callback(update_callback)
|
|
118
|
+
|
|
119
|
+
# To match all bits before the p4p transport starts.
|
|
120
|
+
await update_callback(group_attribute.get())
|
|
121
|
+
|
|
122
|
+
async def _add_version_block(self):
|
|
123
|
+
idn_response = await self._raw_panda.get("*IDN")
|
|
124
|
+
assert isinstance(idn_response, str)
|
|
125
|
+
self._additional_controllers["Versions"] = VersionController(idn_response)
|
|
126
|
+
|
|
127
|
+
async def _add_pcap_arm(self):
|
|
128
|
+
pcap_name = PandaName("PCAP")
|
|
129
|
+
pcap_block = self._introspected_controllers.get(pcap_name, None)
|
|
130
|
+
if pcap_block is None:
|
|
131
|
+
raise ValueError("Did not receive a PCAP block during introspection.")
|
|
132
|
+
|
|
133
|
+
pcap_block.add_attribute(
|
|
134
|
+
pcap_name + PandaName(field="Arm"),
|
|
135
|
+
AttrRW(
|
|
136
|
+
Enum(ArmCommand),
|
|
137
|
+
description="Arm/Disarm the PandA.",
|
|
138
|
+
io_ref=ArmIORef(self._raw_panda.arm, self._raw_panda.disarm),
|
|
139
|
+
group=WidgetGroup.CAPTURE.value,
|
|
140
|
+
),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
async def _add_data_block(self):
|
|
144
|
+
self._additional_controllers["Data"] = DataController(
|
|
145
|
+
self._raw_panda.data, self._dataset_attributes
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# ==================================================================================
|
|
149
|
+
# ====== FOR PARSING INTROSPECTED DATA =============================================
|
|
150
|
+
# ==================================================================================
|
|
151
|
+
|
|
152
|
+
async def parse_introspected_data(self):
|
|
153
|
+
(
|
|
154
|
+
raw_blocks,
|
|
155
|
+
raw_field_infos,
|
|
156
|
+
raw_labels,
|
|
157
|
+
raw_initial_values,
|
|
158
|
+
) = await self._raw_panda.introspect()
|
|
159
|
+
|
|
160
|
+
for (block_name, block_info), field_info in zip(
|
|
161
|
+
raw_blocks.items(), raw_field_infos, strict=True
|
|
162
|
+
):
|
|
163
|
+
numbered_block_names = (
|
|
164
|
+
[block_name]
|
|
165
|
+
if block_info.number in (None, 1)
|
|
166
|
+
else [
|
|
167
|
+
block_name + PandaName(block_number=number)
|
|
168
|
+
for number in range(1, block_info.number + 1)
|
|
169
|
+
]
|
|
170
|
+
)
|
|
171
|
+
numbered_block_controllers: dict[int, BlockController] = {}
|
|
172
|
+
for number, numbered_block_name in enumerate(numbered_block_names):
|
|
173
|
+
block_initial_values = {
|
|
174
|
+
key: value
|
|
175
|
+
for key, value in raw_initial_values.items()
|
|
176
|
+
if key in numbered_block_name
|
|
177
|
+
}
|
|
178
|
+
label = raw_labels.get(numbered_block_name, None)
|
|
179
|
+
block = BlockController(
|
|
180
|
+
numbered_block_name,
|
|
181
|
+
self._raw_panda.put_value_to_panda,
|
|
182
|
+
label=block_info.description or label,
|
|
183
|
+
ios=self._ios,
|
|
184
|
+
)
|
|
185
|
+
numbered_block_controllers[number + 1] = block
|
|
186
|
+
self.fill_block(block, field_info, block_initial_values)
|
|
187
|
+
self._introspected_controllers[numbered_block_name] = block
|
|
188
|
+
|
|
189
|
+
# If there are numbered controllers, add a ControllerVector
|
|
190
|
+
if len(numbered_block_names) > 1:
|
|
191
|
+
self._additional_controllers[str(block_name)] = BlockControllerVector(
|
|
192
|
+
numbered_block_controllers
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def fill_block(
|
|
196
|
+
self,
|
|
197
|
+
block: BlockController,
|
|
198
|
+
field_infos: dict[PandaName, ResponseType],
|
|
199
|
+
initial_values: RawInitialValuesType,
|
|
200
|
+
):
|
|
201
|
+
for field_panda_name, field_info in field_infos.items():
|
|
202
|
+
full_field_name = block.panda_name + field_panda_name
|
|
203
|
+
field_initial_values = {
|
|
204
|
+
key: value
|
|
205
|
+
for key, value in initial_values.items()
|
|
206
|
+
if key in field_panda_name
|
|
207
|
+
}
|
|
208
|
+
self.add_field_to_block(
|
|
209
|
+
block, full_field_name, field_info, field_initial_values
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def add_field_to_block(
|
|
213
|
+
self,
|
|
214
|
+
parent_block: BlockController,
|
|
215
|
+
field_panda_name: PandaName,
|
|
216
|
+
field_info: ResponseType,
|
|
217
|
+
initial_values: RawInitialValuesType,
|
|
218
|
+
):
|
|
219
|
+
match field_info:
|
|
220
|
+
case TableFieldInfo():
|
|
221
|
+
return self._make_table_field(
|
|
222
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
223
|
+
)
|
|
224
|
+
case TimeFieldInfo(subtype=None):
|
|
225
|
+
self._make_time_param(
|
|
226
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
227
|
+
)
|
|
228
|
+
case SubtypeTimeFieldInfo(type="param"):
|
|
229
|
+
self._make_time_param(
|
|
230
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
231
|
+
)
|
|
232
|
+
case SubtypeTimeFieldInfo(subtype="read"):
|
|
233
|
+
self._make_time_read(
|
|
234
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
235
|
+
)
|
|
236
|
+
case SubtypeTimeFieldInfo(subtype="write"):
|
|
237
|
+
self._make_time_write(parent_block, field_panda_name, field_info)
|
|
238
|
+
|
|
239
|
+
case BitOutFieldInfo():
|
|
240
|
+
self._make_bit_out(
|
|
241
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
242
|
+
)
|
|
243
|
+
case ExtOutBitsFieldInfo(subtype="timestamp"):
|
|
244
|
+
self._make_ext_out(
|
|
245
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
246
|
+
)
|
|
247
|
+
case ExtOutBitsFieldInfo():
|
|
248
|
+
self._make_ext_out_bits(
|
|
249
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
250
|
+
)
|
|
251
|
+
case ExtOutFieldInfo():
|
|
252
|
+
self._make_ext_out(
|
|
253
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
254
|
+
)
|
|
255
|
+
case BitMuxFieldInfo():
|
|
256
|
+
self._make_bit_mux(
|
|
257
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
258
|
+
)
|
|
259
|
+
case FieldInfo(type="param", subtype="bit"):
|
|
260
|
+
self._make_bit_param(
|
|
261
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
262
|
+
)
|
|
263
|
+
case FieldInfo(type="read", subtype="bit"):
|
|
264
|
+
self._make_bit_read(
|
|
265
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
266
|
+
)
|
|
267
|
+
case FieldInfo(type="write", subtype="bit"):
|
|
268
|
+
self._make_bit_write(parent_block, field_panda_name, field_info)
|
|
269
|
+
|
|
270
|
+
case PosOutFieldInfo():
|
|
271
|
+
self._make_pos_out(
|
|
272
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
273
|
+
)
|
|
274
|
+
case PosMuxFieldInfo():
|
|
275
|
+
self._make_pos_mux(
|
|
276
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# TODO: Add scaled as an option to fastcs int so we can have a uint32
|
|
280
|
+
case UintFieldInfo(type="param"):
|
|
281
|
+
self._make_uint_param(
|
|
282
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
283
|
+
)
|
|
284
|
+
case UintFieldInfo(type="read"):
|
|
285
|
+
self._make_uint_read(
|
|
286
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
287
|
+
)
|
|
288
|
+
case UintFieldInfo(type="write"):
|
|
289
|
+
self._make_uint_write(parent_block, field_panda_name, field_info)
|
|
290
|
+
|
|
291
|
+
# Scalar types
|
|
292
|
+
case ScalarFieldInfo(subtype="param"):
|
|
293
|
+
self._make_scalar_param(
|
|
294
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
295
|
+
)
|
|
296
|
+
case ScalarFieldInfo(type="read"):
|
|
297
|
+
self._make_scalar_read(
|
|
298
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
299
|
+
)
|
|
300
|
+
case ScalarFieldInfo(type="write"):
|
|
301
|
+
self._make_scalar_write(parent_block, field_panda_name, field_info)
|
|
302
|
+
|
|
303
|
+
# Int types
|
|
304
|
+
case FieldInfo(type="param", subtype="int"):
|
|
305
|
+
self._make_int_param(
|
|
306
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
307
|
+
)
|
|
308
|
+
case FieldInfo(type="read", subtype="int"):
|
|
309
|
+
self._make_int_read(
|
|
310
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
311
|
+
)
|
|
312
|
+
case FieldInfo(type="write", subtype="int"):
|
|
313
|
+
self._make_int_write(parent_block, field_panda_name, field_info)
|
|
314
|
+
|
|
315
|
+
# Action types
|
|
316
|
+
case FieldInfo(
|
|
317
|
+
type="write",
|
|
318
|
+
subtype="action",
|
|
319
|
+
):
|
|
320
|
+
self._make_action_write(parent_block, field_panda_name, field_info)
|
|
321
|
+
|
|
322
|
+
# Lut types
|
|
323
|
+
case FieldInfo(type="param", subtype="lut"):
|
|
324
|
+
self._make_lut_param(
|
|
325
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
326
|
+
)
|
|
327
|
+
case FieldInfo(type="read", subtype="lut"):
|
|
328
|
+
self._make_lut_read(
|
|
329
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
330
|
+
)
|
|
331
|
+
case FieldInfo(type="write", subtype="lut"):
|
|
332
|
+
self._make_lut_write(parent_block, field_panda_name, field_info)
|
|
333
|
+
|
|
334
|
+
# Enum types
|
|
335
|
+
case EnumFieldInfo(type="param"):
|
|
336
|
+
self._make_enum_param(
|
|
337
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
338
|
+
)
|
|
339
|
+
case EnumFieldInfo(type="read"):
|
|
340
|
+
self._make_enum_read(
|
|
341
|
+
parent_block, field_panda_name, field_info, initial_values
|
|
342
|
+
)
|
|
343
|
+
case EnumFieldInfo(type="write"):
|
|
344
|
+
self._make_enum_write(parent_block, field_panda_name, field_info)
|
|
345
|
+
case _:
|
|
346
|
+
raise ValueError(f"Unknown field type: {type(field_info).__name__}.")
|
|
347
|
+
|
|
348
|
+
def _table_datatypes_from_table_field_details(
|
|
349
|
+
self,
|
|
350
|
+
details: TableFieldDetails,
|
|
351
|
+
) -> DTypeLike:
|
|
352
|
+
match details:
|
|
353
|
+
case TableFieldDetails(subtype="int"):
|
|
354
|
+
return np.int32
|
|
355
|
+
case TableFieldDetails(subtype="uint"):
|
|
356
|
+
return np.uint32
|
|
357
|
+
case TableFieldDetails(subtype="enum"):
|
|
358
|
+
# TODO: replace with string once
|
|
359
|
+
# https://github.com/epics-base/p4p/issues/168
|
|
360
|
+
# is fixed.
|
|
361
|
+
return "U16"
|
|
362
|
+
case _:
|
|
363
|
+
raise RuntimeError("Received unknown datatype for table in panda.")
|
|
364
|
+
|
|
365
|
+
def _make_table_field(
|
|
366
|
+
self,
|
|
367
|
+
parent_block: BlockController,
|
|
368
|
+
panda_name: PandaName,
|
|
369
|
+
field_info: TableFieldInfo,
|
|
370
|
+
initial_values: RawInitialValuesType,
|
|
371
|
+
):
|
|
372
|
+
structured_datatype = [
|
|
373
|
+
(name.lower(), self._table_datatypes_from_table_field_details(details))
|
|
374
|
+
for name, details in field_info.fields.items()
|
|
375
|
+
]
|
|
376
|
+
|
|
377
|
+
initial_value = panda_value_to_attribute_value(
|
|
378
|
+
fastcs_datatype=Table(structured_datatype),
|
|
379
|
+
value=words_to_table(
|
|
380
|
+
words=initial_values[panda_name],
|
|
381
|
+
table_field_info=field_info,
|
|
382
|
+
convert_enum_indices=True,
|
|
383
|
+
),
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
# TODO: Add units IO to update the units field and value of this one PV
|
|
387
|
+
# https://github.com/PandABlocks/PandABlocks-ioc/blob/c1e8056abf3f680fa3840493eb4ac6ca2be31313/src/pandablocks_ioc/ioc.py#L750-L769
|
|
388
|
+
attribute = AttrRW(
|
|
389
|
+
Table(structured_datatype),
|
|
390
|
+
io_ref=TableFieldIORef(
|
|
391
|
+
panda_name, field_info, self._raw_panda.put_value_to_panda
|
|
392
|
+
),
|
|
393
|
+
initial_value=initial_value,
|
|
394
|
+
)
|
|
395
|
+
parent_block.add_attribute(panda_name, attribute)
|
|
396
|
+
|
|
397
|
+
def _make_time_param(
|
|
398
|
+
self,
|
|
399
|
+
parent_block: BlockController,
|
|
400
|
+
panda_name: PandaName,
|
|
401
|
+
field_info: SubtypeTimeFieldInfo | TimeFieldInfo,
|
|
402
|
+
initial_values: RawInitialValuesType,
|
|
403
|
+
):
|
|
404
|
+
# TODO: add an IO for units to scale to get seconds
|
|
405
|
+
# The units come through in the same *CHANGES so there shouldn't
|
|
406
|
+
# be a race condition here.
|
|
407
|
+
# PandaName(block='PULSE', block_number=2, field='WIDTH', sub_field=None): '0',
|
|
408
|
+
# PandaName(..., sub_field='UNITS'): 's',
|
|
409
|
+
|
|
410
|
+
attribute = AttrRW(
|
|
411
|
+
Float(units="s", prec=5),
|
|
412
|
+
io_ref=DefaultFieldIORef(panda_name, self._raw_panda.put_value_to_panda),
|
|
413
|
+
description=field_info.description,
|
|
414
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
415
|
+
initial_value=float(initial_values[panda_name]),
|
|
416
|
+
)
|
|
417
|
+
parent_block.add_attribute(panda_name, attribute)
|
|
418
|
+
|
|
419
|
+
units_enum = Enum(TimeUnit)
|
|
420
|
+
units_name = panda_name + PandaName(sub_field="UNITS")
|
|
421
|
+
units_attribute = AttrRW(
|
|
422
|
+
units_enum,
|
|
423
|
+
io_ref=UnitsIORef(
|
|
424
|
+
attribute, TimeUnit.s, units_name, self._raw_panda.put_value_to_panda
|
|
425
|
+
),
|
|
426
|
+
description=field_info.description,
|
|
427
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
428
|
+
initial_value=TimeUnit.s,
|
|
429
|
+
)
|
|
430
|
+
parent_block.add_attribute(units_name, units_attribute)
|
|
431
|
+
|
|
432
|
+
def _make_time_read(
|
|
433
|
+
self,
|
|
434
|
+
parent_block: BlockController,
|
|
435
|
+
panda_name: PandaName,
|
|
436
|
+
field_info: SubtypeTimeFieldInfo,
|
|
437
|
+
initial_values: RawInitialValuesType,
|
|
438
|
+
):
|
|
439
|
+
attribute = AttrR(
|
|
440
|
+
Float(units="s"),
|
|
441
|
+
description=field_info.description,
|
|
442
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
443
|
+
initial_value=float(initial_values[panda_name]),
|
|
444
|
+
)
|
|
445
|
+
parent_block.add_attribute(panda_name, attribute)
|
|
446
|
+
|
|
447
|
+
def _make_time_write(
|
|
448
|
+
self,
|
|
449
|
+
parent_block: BlockController,
|
|
450
|
+
panda_name: PandaName,
|
|
451
|
+
field_info: SubtypeTimeFieldInfo,
|
|
452
|
+
):
|
|
453
|
+
attribute = AttrW(
|
|
454
|
+
Float(units="s"),
|
|
455
|
+
io_ref=DefaultFieldIORef(panda_name, self._raw_panda.put_value_to_panda),
|
|
456
|
+
description=field_info.description,
|
|
457
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
458
|
+
)
|
|
459
|
+
parent_block.add_attribute(panda_name, attribute)
|
|
460
|
+
|
|
461
|
+
def _make_bit_out(
|
|
462
|
+
self,
|
|
463
|
+
parent_block: BlockController,
|
|
464
|
+
panda_name: PandaName,
|
|
465
|
+
field_info: BitOutFieldInfo,
|
|
466
|
+
initial_values: RawInitialValuesType,
|
|
467
|
+
):
|
|
468
|
+
parent_block.add_attribute(
|
|
469
|
+
panda_name,
|
|
470
|
+
AttrR(
|
|
471
|
+
Bool(),
|
|
472
|
+
description=field_info.description,
|
|
473
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
474
|
+
initial_value=bool(int(initial_values[panda_name])),
|
|
475
|
+
),
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
capture_name = panda_name + PandaName(sub_field="CAPTURE")
|
|
479
|
+
parent_block.add_attribute(
|
|
480
|
+
capture_name,
|
|
481
|
+
AttrRW(
|
|
482
|
+
Bool(),
|
|
483
|
+
group=WidgetGroup.CAPTURE.value,
|
|
484
|
+
initial_value=False,
|
|
485
|
+
),
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
def _make_pos_out(
|
|
489
|
+
self,
|
|
490
|
+
parent_block: BlockController,
|
|
491
|
+
panda_name: PandaName,
|
|
492
|
+
field_info: PosOutFieldInfo,
|
|
493
|
+
initial_values: RawInitialValuesType,
|
|
494
|
+
):
|
|
495
|
+
pos_out = AttrR(
|
|
496
|
+
Int(),
|
|
497
|
+
description=field_info.description,
|
|
498
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
499
|
+
initial_value=int(initial_values[panda_name]),
|
|
500
|
+
)
|
|
501
|
+
parent_block.add_attribute(panda_name, pos_out)
|
|
502
|
+
|
|
503
|
+
scale_panda_name = panda_name + PandaName(sub_field="SCALE")
|
|
504
|
+
scale = AttrRW(
|
|
505
|
+
Float(),
|
|
506
|
+
group=WidgetGroup.CAPTURE.value,
|
|
507
|
+
io_ref=DefaultFieldIORef(
|
|
508
|
+
scale_panda_name, self._raw_panda.put_value_to_panda
|
|
509
|
+
),
|
|
510
|
+
initial_value=float(initial_values[scale_panda_name]),
|
|
511
|
+
)
|
|
512
|
+
parent_block.add_attribute(scale_panda_name, scale)
|
|
513
|
+
|
|
514
|
+
offset_panda_name = panda_name + PandaName(sub_field="OFFSET")
|
|
515
|
+
offset = AttrRW(
|
|
516
|
+
Float(),
|
|
517
|
+
group=WidgetGroup.CAPTURE.value,
|
|
518
|
+
io_ref=DefaultFieldIORef(
|
|
519
|
+
offset_panda_name, self._raw_panda.put_value_to_panda
|
|
520
|
+
),
|
|
521
|
+
initial_value=float(initial_values[offset_panda_name]),
|
|
522
|
+
)
|
|
523
|
+
parent_block.add_attribute(offset_panda_name, offset)
|
|
524
|
+
|
|
525
|
+
scaled_panda_name = panda_name + PandaName(sub_field="SCALED")
|
|
526
|
+
scaled = AttrR(
|
|
527
|
+
Float(),
|
|
528
|
+
group=WidgetGroup.CAPTURE.value,
|
|
529
|
+
description="Value with scaling applied.",
|
|
530
|
+
initial_value=scale.get() * pos_out.get() + offset.get(),
|
|
531
|
+
)
|
|
532
|
+
parent_block.add_attribute(scaled_panda_name, scaled)
|
|
533
|
+
|
|
534
|
+
async def updated_scaled_on_offset_change(*_):
|
|
535
|
+
await scaled.update(scale.get() * pos_out.get() + offset.get())
|
|
536
|
+
|
|
537
|
+
offset.add_on_update_callback(updated_scaled_on_offset_change)
|
|
538
|
+
scale.add_on_update_callback(updated_scaled_on_offset_change)
|
|
539
|
+
pos_out.add_on_update_callback(updated_scaled_on_offset_change)
|
|
540
|
+
|
|
541
|
+
capture_enum = Enum(enum.Enum("Capture", field_info.capture_labels))
|
|
542
|
+
|
|
543
|
+
capture_panda_name = panda_name + PandaName(sub_field="CAPTURE")
|
|
544
|
+
capture_attribute = AttrRW(
|
|
545
|
+
capture_enum,
|
|
546
|
+
description=field_info.description,
|
|
547
|
+
group=WidgetGroup.CAPTURE.value,
|
|
548
|
+
initial_value=capture_enum.members[
|
|
549
|
+
capture_enum.names.index(initial_values[capture_panda_name])
|
|
550
|
+
],
|
|
551
|
+
)
|
|
552
|
+
parent_block.add_attribute(
|
|
553
|
+
capture_panda_name,
|
|
554
|
+
capture_attribute,
|
|
555
|
+
)
|
|
556
|
+
dataset_attribute = AttrRW(
|
|
557
|
+
String(),
|
|
558
|
+
description=(
|
|
559
|
+
"Used to adjust the dataset name to one more scientifically relevant"
|
|
560
|
+
),
|
|
561
|
+
group=WidgetGroup.CAPTURE.value,
|
|
562
|
+
initial_value="",
|
|
563
|
+
)
|
|
564
|
+
parent_block.add_attribute(
|
|
565
|
+
panda_name + PandaName(sub_field="DATASET"),
|
|
566
|
+
dataset_attribute,
|
|
567
|
+
)
|
|
568
|
+
self._dataset_attributes[panda_name] = DatasetAttributes(
|
|
569
|
+
dataset_attribute, capture_attribute
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
def _make_ext_out(
|
|
573
|
+
self,
|
|
574
|
+
parent_block: BlockController,
|
|
575
|
+
panda_name: PandaName,
|
|
576
|
+
field_info: ExtOutFieldInfo,
|
|
577
|
+
initial_values: RawInitialValuesType,
|
|
578
|
+
):
|
|
579
|
+
"""Returns the capture attribtute so we can add a callback in ext out bits.
|
|
580
|
+
|
|
581
|
+
For an ext out bits, we set one capture in the group, wait for the panda
|
|
582
|
+
response that the group is being captutured, and then update all the elements
|
|
583
|
+
in the group.
|
|
584
|
+
"""
|
|
585
|
+
|
|
586
|
+
capture_enum = Enum(enum.Enum("Capture", field_info.capture_labels))
|
|
587
|
+
capture_panda_name = panda_name + PandaName(sub_field="CAPTURE")
|
|
588
|
+
capture_attribute = AttrRW(
|
|
589
|
+
capture_enum,
|
|
590
|
+
description=field_info.description,
|
|
591
|
+
group=WidgetGroup.CAPTURE.value,
|
|
592
|
+
initial_value=capture_enum.enum_cls[initial_values[capture_panda_name]],
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
parent_block.add_attribute(capture_panda_name, capture_attribute)
|
|
596
|
+
|
|
597
|
+
dataset_attribute = AttrRW(
|
|
598
|
+
String(),
|
|
599
|
+
description=(
|
|
600
|
+
"Used to adjust the dataset name to one more scientifically relevant"
|
|
601
|
+
),
|
|
602
|
+
group=WidgetGroup.CAPTURE.value,
|
|
603
|
+
initial_value="",
|
|
604
|
+
)
|
|
605
|
+
parent_block.add_attribute(
|
|
606
|
+
panda_name + PandaName(sub_field="DATASET"),
|
|
607
|
+
dataset_attribute,
|
|
608
|
+
)
|
|
609
|
+
self._dataset_attributes[panda_name] = DatasetAttributes(
|
|
610
|
+
dataset_attribute, capture_attribute
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
def _make_ext_out_bits(
|
|
614
|
+
self,
|
|
615
|
+
parent_block: BlockController,
|
|
616
|
+
panda_name: PandaName,
|
|
617
|
+
field_info: ExtOutBitsFieldInfo,
|
|
618
|
+
initial_values: RawInitialValuesType,
|
|
619
|
+
):
|
|
620
|
+
self._make_ext_out(parent_block, panda_name, field_info, initial_values)
|
|
621
|
+
capture_group_members = [
|
|
622
|
+
PandaName.from_string(label) + PandaName(sub_field="CAPTURE")
|
|
623
|
+
for label in field_info.bits
|
|
624
|
+
if label != ""
|
|
625
|
+
]
|
|
626
|
+
|
|
627
|
+
self._bits_group_names.append(
|
|
628
|
+
(
|
|
629
|
+
panda_name + PandaName(sub_field="CAPTURE"),
|
|
630
|
+
capture_group_members,
|
|
631
|
+
)
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
def _make_bit_mux(
|
|
635
|
+
self,
|
|
636
|
+
parent_block: BlockController,
|
|
637
|
+
panda_name: PandaName,
|
|
638
|
+
bit_mux_field_info: BitMuxFieldInfo,
|
|
639
|
+
initial_values: RawInitialValuesType,
|
|
640
|
+
):
|
|
641
|
+
enum_type = enum.Enum("Labels", bit_mux_field_info.labels)
|
|
642
|
+
parent_block.add_attribute(
|
|
643
|
+
panda_name,
|
|
644
|
+
AttrRW(
|
|
645
|
+
Enum(enum_type),
|
|
646
|
+
description=bit_mux_field_info.description,
|
|
647
|
+
io_ref=DefaultFieldIORef(
|
|
648
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
649
|
+
),
|
|
650
|
+
group=WidgetGroup.INPUTS.value,
|
|
651
|
+
initial_value=enum_type[initial_values[panda_name]],
|
|
652
|
+
),
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
delay_panda_name = panda_name + PandaName(sub_field="DELAY")
|
|
656
|
+
parent_block.add_attribute(
|
|
657
|
+
delay_panda_name,
|
|
658
|
+
AttrRW(
|
|
659
|
+
Int(min=0, max=bit_mux_field_info.max_delay),
|
|
660
|
+
description="Clock delay on input.",
|
|
661
|
+
io_ref=DefaultFieldIORef(
|
|
662
|
+
delay_panda_name, self._raw_panda.put_value_to_panda
|
|
663
|
+
),
|
|
664
|
+
group=WidgetGroup.INPUTS.value,
|
|
665
|
+
initial_value=int(initial_values[delay_panda_name]),
|
|
666
|
+
),
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
def _make_pos_mux(
|
|
670
|
+
self,
|
|
671
|
+
parent_block: BlockController,
|
|
672
|
+
panda_name: PandaName,
|
|
673
|
+
pos_mux_field_info: PosMuxFieldInfo,
|
|
674
|
+
initial_values: RawInitialValuesType,
|
|
675
|
+
):
|
|
676
|
+
enum_type = enum.Enum("Labels", pos_mux_field_info.labels)
|
|
677
|
+
parent_block.add_attribute(
|
|
678
|
+
panda_name,
|
|
679
|
+
AttrRW(
|
|
680
|
+
Enum(enum_type),
|
|
681
|
+
description=pos_mux_field_info.description,
|
|
682
|
+
io_ref=DefaultFieldIORef(
|
|
683
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
684
|
+
),
|
|
685
|
+
group=WidgetGroup.INPUTS.value,
|
|
686
|
+
initial_value=enum_type[initial_values[panda_name]],
|
|
687
|
+
),
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
def _make_uint_param(
|
|
691
|
+
self,
|
|
692
|
+
parent_block: BlockController,
|
|
693
|
+
panda_name: PandaName,
|
|
694
|
+
uint_param_field_info: UintFieldInfo,
|
|
695
|
+
initial_values: RawInitialValuesType,
|
|
696
|
+
):
|
|
697
|
+
parent_block.add_attribute(
|
|
698
|
+
panda_name,
|
|
699
|
+
AttrRW(
|
|
700
|
+
Int(min=0, max=uint_param_field_info.max_val),
|
|
701
|
+
description=uint_param_field_info.description,
|
|
702
|
+
io_ref=DefaultFieldIORef(
|
|
703
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
704
|
+
),
|
|
705
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
706
|
+
initial_value=int(initial_values[panda_name]),
|
|
707
|
+
),
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
def _make_uint_read(
|
|
711
|
+
self,
|
|
712
|
+
parent_block: BlockController,
|
|
713
|
+
panda_name: PandaName,
|
|
714
|
+
uint_read_field_info: UintFieldInfo,
|
|
715
|
+
initial_values: RawInitialValuesType,
|
|
716
|
+
):
|
|
717
|
+
parent_block.add_attribute(
|
|
718
|
+
panda_name,
|
|
719
|
+
AttrR(
|
|
720
|
+
Int(min=0, max=uint_read_field_info.max_val),
|
|
721
|
+
description=uint_read_field_info.description,
|
|
722
|
+
group=WidgetGroup.READBACKS.value,
|
|
723
|
+
initial_value=int(initial_values[panda_name]),
|
|
724
|
+
),
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
def _make_uint_write(
|
|
728
|
+
self,
|
|
729
|
+
parent_block: BlockController,
|
|
730
|
+
panda_name: PandaName,
|
|
731
|
+
uint_write_field_info: UintFieldInfo,
|
|
732
|
+
):
|
|
733
|
+
parent_block.add_attribute(
|
|
734
|
+
panda_name,
|
|
735
|
+
AttrW(
|
|
736
|
+
Int(min=0, max=uint_write_field_info.max_val),
|
|
737
|
+
description=uint_write_field_info.description,
|
|
738
|
+
io_ref=DefaultFieldIORef(
|
|
739
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
740
|
+
),
|
|
741
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
742
|
+
),
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
def _make_int_param(
|
|
746
|
+
self,
|
|
747
|
+
parent_block: BlockController,
|
|
748
|
+
panda_name: PandaName,
|
|
749
|
+
int_param_field_info: FieldInfo,
|
|
750
|
+
initial_values: RawInitialValuesType,
|
|
751
|
+
):
|
|
752
|
+
parent_block.add_attribute(
|
|
753
|
+
panda_name,
|
|
754
|
+
AttrRW(
|
|
755
|
+
Int(),
|
|
756
|
+
description=int_param_field_info.description,
|
|
757
|
+
io_ref=DefaultFieldIORef(
|
|
758
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
759
|
+
),
|
|
760
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
761
|
+
initial_value=int(initial_values[panda_name]),
|
|
762
|
+
),
|
|
763
|
+
)
|
|
764
|
+
|
|
765
|
+
def _make_int_read(
|
|
766
|
+
self,
|
|
767
|
+
parent_block: BlockController,
|
|
768
|
+
panda_name: PandaName,
|
|
769
|
+
int_read_field_info: FieldInfo,
|
|
770
|
+
initial_values: RawInitialValuesType,
|
|
771
|
+
):
|
|
772
|
+
parent_block.add_attribute(
|
|
773
|
+
panda_name,
|
|
774
|
+
AttrR(
|
|
775
|
+
Int(),
|
|
776
|
+
description=int_read_field_info.description,
|
|
777
|
+
group=WidgetGroup.READBACKS.value,
|
|
778
|
+
initial_value=int(initial_values[panda_name]),
|
|
779
|
+
),
|
|
780
|
+
)
|
|
781
|
+
|
|
782
|
+
def _make_int_write(
|
|
783
|
+
self,
|
|
784
|
+
parent_block: BlockController,
|
|
785
|
+
panda_name: PandaName,
|
|
786
|
+
int_write_field_info: FieldInfo,
|
|
787
|
+
):
|
|
788
|
+
parent_block.add_attribute(
|
|
789
|
+
panda_name,
|
|
790
|
+
AttrW(
|
|
791
|
+
Int(),
|
|
792
|
+
description=int_write_field_info.description,
|
|
793
|
+
io_ref=DefaultFieldIORef(
|
|
794
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
795
|
+
),
|
|
796
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
797
|
+
),
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
def _make_scalar_param(
|
|
801
|
+
self,
|
|
802
|
+
parent_block: BlockController,
|
|
803
|
+
panda_name: PandaName,
|
|
804
|
+
scalar_param_field_info: ScalarFieldInfo,
|
|
805
|
+
initial_values: RawInitialValuesType,
|
|
806
|
+
):
|
|
807
|
+
parent_block.add_attribute(
|
|
808
|
+
panda_name,
|
|
809
|
+
AttrRW(
|
|
810
|
+
Float(units=scalar_param_field_info.units),
|
|
811
|
+
description=scalar_param_field_info.description,
|
|
812
|
+
io_ref=DefaultFieldIORef(
|
|
813
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
814
|
+
),
|
|
815
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
816
|
+
initial_value=float(initial_values[panda_name]),
|
|
817
|
+
),
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
def _make_scalar_read(
|
|
821
|
+
self,
|
|
822
|
+
parent_block: BlockController,
|
|
823
|
+
panda_name: PandaName,
|
|
824
|
+
scalar_read_field_info: ScalarFieldInfo,
|
|
825
|
+
initial_values: RawInitialValuesType,
|
|
826
|
+
):
|
|
827
|
+
parent_block.add_attribute(
|
|
828
|
+
panda_name,
|
|
829
|
+
AttrR(
|
|
830
|
+
Float(),
|
|
831
|
+
description=scalar_read_field_info.description,
|
|
832
|
+
group=WidgetGroup.READBACKS.value,
|
|
833
|
+
initial_value=float(initial_values[panda_name]),
|
|
834
|
+
),
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
def _make_scalar_write(
|
|
838
|
+
self,
|
|
839
|
+
parent_block: BlockController,
|
|
840
|
+
panda_name: PandaName,
|
|
841
|
+
scalar_write_field_info: ScalarFieldInfo,
|
|
842
|
+
):
|
|
843
|
+
parent_block.add_attribute(
|
|
844
|
+
panda_name,
|
|
845
|
+
AttrR(
|
|
846
|
+
Float(),
|
|
847
|
+
description=scalar_write_field_info.description,
|
|
848
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
849
|
+
),
|
|
850
|
+
)
|
|
851
|
+
|
|
852
|
+
def _make_bit_param(
|
|
853
|
+
self,
|
|
854
|
+
parent_block: BlockController,
|
|
855
|
+
panda_name: PandaName,
|
|
856
|
+
bit_param_field_info: FieldInfo,
|
|
857
|
+
initial_values: RawInitialValuesType,
|
|
858
|
+
):
|
|
859
|
+
parent_block.add_attribute(
|
|
860
|
+
panda_name,
|
|
861
|
+
AttrRW(
|
|
862
|
+
Bool(),
|
|
863
|
+
description=bit_param_field_info.description,
|
|
864
|
+
io_ref=DefaultFieldIORef(
|
|
865
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
866
|
+
),
|
|
867
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
868
|
+
initial_value=bool(int(initial_values[panda_name])),
|
|
869
|
+
),
|
|
870
|
+
)
|
|
871
|
+
|
|
872
|
+
def _make_bit_read(
|
|
873
|
+
self,
|
|
874
|
+
parent_block: BlockController,
|
|
875
|
+
panda_name: PandaName,
|
|
876
|
+
bit_read_field_info: FieldInfo,
|
|
877
|
+
initial_values: RawInitialValuesType,
|
|
878
|
+
):
|
|
879
|
+
parent_block.add_attribute(
|
|
880
|
+
panda_name,
|
|
881
|
+
AttrR(
|
|
882
|
+
Bool(),
|
|
883
|
+
description=bit_read_field_info.description,
|
|
884
|
+
group=WidgetGroup.READBACKS.value,
|
|
885
|
+
initial_value=bool(int(initial_values[panda_name])),
|
|
886
|
+
),
|
|
887
|
+
)
|
|
888
|
+
|
|
889
|
+
def _make_bit_write(
|
|
890
|
+
self,
|
|
891
|
+
parent_block: BlockController,
|
|
892
|
+
panda_name: PandaName,
|
|
893
|
+
bit_write_field_info: FieldInfo,
|
|
894
|
+
):
|
|
895
|
+
parent_block.add_attribute(
|
|
896
|
+
panda_name,
|
|
897
|
+
AttrW(
|
|
898
|
+
Bool(),
|
|
899
|
+
description=bit_write_field_info.description,
|
|
900
|
+
io_ref=DefaultFieldIORef(
|
|
901
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
902
|
+
),
|
|
903
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
904
|
+
),
|
|
905
|
+
)
|
|
906
|
+
|
|
907
|
+
def _make_action_write(
|
|
908
|
+
self,
|
|
909
|
+
parent_block: BlockController,
|
|
910
|
+
panda_name: PandaName,
|
|
911
|
+
action_write_field_info: FieldInfo,
|
|
912
|
+
):
|
|
913
|
+
parent_block.add_attribute(
|
|
914
|
+
panda_name,
|
|
915
|
+
AttrW(
|
|
916
|
+
Bool(),
|
|
917
|
+
description=action_write_field_info.description,
|
|
918
|
+
io_ref=DefaultFieldIORef(
|
|
919
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
920
|
+
),
|
|
921
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
922
|
+
),
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
def _make_lut_param(
|
|
926
|
+
self,
|
|
927
|
+
parent_block: BlockController,
|
|
928
|
+
panda_name: PandaName,
|
|
929
|
+
lut_param_field_info: FieldInfo,
|
|
930
|
+
initial_values: RawInitialValuesType,
|
|
931
|
+
):
|
|
932
|
+
parent_block.add_attribute(
|
|
933
|
+
panda_name,
|
|
934
|
+
AttrRW(
|
|
935
|
+
String(),
|
|
936
|
+
description=lut_param_field_info.description,
|
|
937
|
+
io_ref=DefaultFieldIORef(
|
|
938
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
939
|
+
),
|
|
940
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
941
|
+
initial_value=initial_values[panda_name],
|
|
942
|
+
),
|
|
943
|
+
)
|
|
944
|
+
|
|
945
|
+
def _make_lut_read(
|
|
946
|
+
self,
|
|
947
|
+
parent_block: BlockController,
|
|
948
|
+
panda_name: PandaName,
|
|
949
|
+
lut_read_field_info: FieldInfo,
|
|
950
|
+
initial_values: RawInitialValuesType,
|
|
951
|
+
):
|
|
952
|
+
parent_block.add_attribute(
|
|
953
|
+
panda_name,
|
|
954
|
+
AttrR(
|
|
955
|
+
String(),
|
|
956
|
+
description=lut_read_field_info.description,
|
|
957
|
+
group=WidgetGroup.READBACKS.value,
|
|
958
|
+
initial_value=initial_values[panda_name],
|
|
959
|
+
),
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
def _make_lut_write(
|
|
963
|
+
self,
|
|
964
|
+
parent_block: BlockController,
|
|
965
|
+
panda_name: PandaName,
|
|
966
|
+
lut_read_field_info: FieldInfo,
|
|
967
|
+
):
|
|
968
|
+
parent_block.add_attribute(
|
|
969
|
+
panda_name,
|
|
970
|
+
AttrR(
|
|
971
|
+
String(),
|
|
972
|
+
description=lut_read_field_info.description,
|
|
973
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
974
|
+
),
|
|
975
|
+
)
|
|
976
|
+
|
|
977
|
+
def _make_enum_param(
|
|
978
|
+
self,
|
|
979
|
+
parent_block: BlockController,
|
|
980
|
+
panda_name: PandaName,
|
|
981
|
+
enum_param_field_info: EnumFieldInfo,
|
|
982
|
+
initial_values: RawInitialValuesType,
|
|
983
|
+
):
|
|
984
|
+
enum_type = enum.Enum("Labels", enum_param_field_info.labels)
|
|
985
|
+
parent_block.add_attribute(
|
|
986
|
+
panda_name,
|
|
987
|
+
AttrRW(
|
|
988
|
+
Enum(enum_type),
|
|
989
|
+
description=enum_param_field_info.description,
|
|
990
|
+
io_ref=DefaultFieldIORef(
|
|
991
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
992
|
+
),
|
|
993
|
+
group=WidgetGroup.PARAMETERS.value,
|
|
994
|
+
initial_value=enum_type[initial_values[panda_name]],
|
|
995
|
+
),
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
def _make_enum_read(
|
|
999
|
+
self,
|
|
1000
|
+
parent_block: BlockController,
|
|
1001
|
+
panda_name: PandaName,
|
|
1002
|
+
enum_read_field_info: EnumFieldInfo,
|
|
1003
|
+
initial_values: RawInitialValuesType,
|
|
1004
|
+
):
|
|
1005
|
+
enum_type = enum.Enum("Labels", enum_read_field_info.labels)
|
|
1006
|
+
|
|
1007
|
+
parent_block.add_attribute(
|
|
1008
|
+
panda_name,
|
|
1009
|
+
AttrR(
|
|
1010
|
+
Enum(enum_type),
|
|
1011
|
+
description=enum_read_field_info.description,
|
|
1012
|
+
group=WidgetGroup.READBACKS.value,
|
|
1013
|
+
initial_value=enum_type[initial_values[panda_name]],
|
|
1014
|
+
),
|
|
1015
|
+
)
|
|
1016
|
+
|
|
1017
|
+
def _make_enum_write(
|
|
1018
|
+
self,
|
|
1019
|
+
parent_block: BlockController,
|
|
1020
|
+
panda_name: PandaName,
|
|
1021
|
+
enum_write_field_info: EnumFieldInfo,
|
|
1022
|
+
):
|
|
1023
|
+
enum_type = enum.Enum("Labels", enum_write_field_info.labels)
|
|
1024
|
+
parent_block.add_attribute(
|
|
1025
|
+
panda_name,
|
|
1026
|
+
AttrW(
|
|
1027
|
+
Enum(enum_type),
|
|
1028
|
+
description=enum_write_field_info.description,
|
|
1029
|
+
io_ref=DefaultFieldIORef(
|
|
1030
|
+
panda_name, self._raw_panda.put_value_to_panda
|
|
1031
|
+
),
|
|
1032
|
+
group=WidgetGroup.OUTPUTS.value,
|
|
1033
|
+
),
|
|
1034
|
+
)
|