|
1 | 1 | import asyncio |
2 | | -from collections.abc import Callable |
3 | | -from dataclasses import asdict |
4 | 2 | from typing import Any, Literal |
5 | 3 |
|
6 | 4 | from softioc import builder, softioc |
7 | 5 | from softioc.asyncio_dispatcher import AsyncioDispatcher |
8 | 6 | from softioc.pythonSoftIoc import RecordWrapper |
9 | 7 |
|
10 | 8 | from fastcs.attributes import AttrR, AttrRW, AttrW |
11 | | -from fastcs.datatypes import Bool, DataType, DType_T, Enum, Float, Int, String, Waveform |
12 | | -from fastcs.exceptions import FastCSError |
| 9 | +from fastcs.datatypes import DType_T, Waveform |
13 | 10 | from fastcs.logging import bind_logger |
14 | 11 | from fastcs.methods import Command |
15 | 12 | from fastcs.tracer import Tracer |
16 | 13 | from fastcs.transports.controller_api import ControllerAPI |
17 | 14 | from fastcs.transports.epics import EpicsIOCOptions |
18 | 15 | from fastcs.transports.epics.ca.util import ( |
19 | | - DATATYPE_FIELD_TO_IN_RECORD_FIELD, |
20 | | - DATATYPE_FIELD_TO_OUT_RECORD_FIELD, |
21 | | - DEFAULT_STRING_WAVEFORM_LENGTH, |
22 | | - MBB_MAX_CHOICES, |
| 16 | + _make_in_record, |
| 17 | + _make_out_record, |
23 | 18 | cast_from_epics_type, |
24 | 19 | cast_to_epics_type, |
25 | | - create_state_keys, |
26 | 20 | ) |
27 | 21 | from fastcs.transports.epics.util import controller_pv_prefix |
28 | 22 | from fastcs.util import snake_to_pascal |
@@ -196,164 +190,6 @@ async def async_record_set(value: DType_T): |
196 | 190 | attribute.add_on_update_callback(async_record_set) |
197 | 191 |
|
198 | 192 |
|
199 | | -def _make_in_record(pv: str, attribute: AttrR) -> RecordWrapper: |
200 | | - attribute_record_metadata = { |
201 | | - "DESC": attribute.description, |
202 | | - "initial_value": cast_to_epics_type(attribute.datatype, attribute.get()), |
203 | | - } |
204 | | - |
205 | | - match attribute.datatype: |
206 | | - case Bool(): |
207 | | - record = builder.boolIn( |
208 | | - pv, ZNAM="False", ONAM="True", **attribute_record_metadata |
209 | | - ) |
210 | | - case Int(): |
211 | | - record = builder.longIn( |
212 | | - pv, |
213 | | - LOPR=attribute.datatype.min_alarm, |
214 | | - HOPR=attribute.datatype.max_alarm, |
215 | | - EGU=attribute.datatype.units, |
216 | | - **attribute_record_metadata, |
217 | | - ) |
218 | | - case Float(): |
219 | | - record = builder.aIn( |
220 | | - pv, |
221 | | - LOPR=attribute.datatype.min_alarm, |
222 | | - HOPR=attribute.datatype.max_alarm, |
223 | | - EGU=attribute.datatype.units, |
224 | | - PREC=attribute.datatype.prec, |
225 | | - **attribute_record_metadata, |
226 | | - ) |
227 | | - case String(): |
228 | | - record = builder.longStringIn( |
229 | | - pv, |
230 | | - length=attribute.datatype.length or DEFAULT_STRING_WAVEFORM_LENGTH, |
231 | | - **attribute_record_metadata, |
232 | | - ) |
233 | | - case Enum(): |
234 | | - if len(attribute.datatype.members) > MBB_MAX_CHOICES: |
235 | | - record = builder.longStringIn( |
236 | | - pv, |
237 | | - **attribute_record_metadata, |
238 | | - ) |
239 | | - else: |
240 | | - attribute_record_metadata.update(create_state_keys(attribute.datatype)) |
241 | | - record = builder.mbbIn( |
242 | | - pv, |
243 | | - **attribute_record_metadata, |
244 | | - ) |
245 | | - case Waveform(): |
246 | | - record = builder.WaveformIn( |
247 | | - pv, length=attribute.datatype.shape[0], **attribute_record_metadata |
248 | | - ) |
249 | | - case _: |
250 | | - raise FastCSError( |
251 | | - f"EPICS unsupported datatype on {attribute}: {attribute.datatype}" |
252 | | - ) |
253 | | - |
254 | | - def datatype_updater(datatype: DataType): |
255 | | - for name, value in asdict(datatype).items(): |
256 | | - if name in DATATYPE_FIELD_TO_IN_RECORD_FIELD: |
257 | | - record.set_field(DATATYPE_FIELD_TO_IN_RECORD_FIELD[name], value) |
258 | | - |
259 | | - attribute.add_update_datatype_callback(datatype_updater) |
260 | | - return record |
261 | | - |
262 | | - |
263 | | -def _make_out_record( |
264 | | - pv: str, |
265 | | - attribute: AttrW | AttrRW, |
266 | | - on_update: Callable, |
267 | | -) -> RecordWrapper: |
268 | | - attribute_record_metadata = { |
269 | | - "DESC": attribute.description, |
270 | | - "initial_value": cast_to_epics_type( |
271 | | - attribute.datatype, |
272 | | - attribute.get() |
273 | | - if isinstance(attribute, AttrR) |
274 | | - else attribute.datatype.initial_value, |
275 | | - ), |
276 | | - } |
277 | | - |
278 | | - update = {"on_update": on_update, "always_update": True, "blocking": True} |
279 | | - |
280 | | - match attribute.datatype: |
281 | | - case Bool(): |
282 | | - record = builder.boolOut( |
283 | | - pv, ZNAM="False", ONAM="True", **update, **attribute_record_metadata |
284 | | - ) |
285 | | - case Int(): |
286 | | - record = builder.longOut( |
287 | | - pv, |
288 | | - LOPR=attribute.datatype.min_alarm, |
289 | | - HOPR=attribute.datatype.max_alarm, |
290 | | - EGU=attribute.datatype.units, |
291 | | - DRVL=attribute.datatype.min, |
292 | | - DRVH=attribute.datatype.max, |
293 | | - **update, |
294 | | - **attribute_record_metadata, |
295 | | - ) |
296 | | - case Float(): |
297 | | - record = builder.aOut( |
298 | | - pv, |
299 | | - LOPR=attribute.datatype.min_alarm, |
300 | | - HOPR=attribute.datatype.max_alarm, |
301 | | - EGU=attribute.datatype.units, |
302 | | - PREC=attribute.datatype.prec, |
303 | | - DRVL=attribute.datatype.min, |
304 | | - DRVH=attribute.datatype.max, |
305 | | - **update, |
306 | | - **attribute_record_metadata, |
307 | | - ) |
308 | | - case String(): |
309 | | - record = builder.longStringOut( |
310 | | - pv, |
311 | | - length=attribute.datatype.length or DEFAULT_STRING_WAVEFORM_LENGTH, |
312 | | - **update, |
313 | | - **attribute_record_metadata, |
314 | | - ) |
315 | | - case Enum(): |
316 | | - if len(attribute.datatype.members) > MBB_MAX_CHOICES: |
317 | | - datatype: Enum = attribute.datatype |
318 | | - |
319 | | - def _verify_in_datatype(_, value): |
320 | | - return value in datatype.names |
321 | | - |
322 | | - record = builder.longStringOut( |
323 | | - pv, |
324 | | - validate=_verify_in_datatype, |
325 | | - **update, |
326 | | - **attribute_record_metadata, |
327 | | - ) |
328 | | - |
329 | | - else: |
330 | | - attribute_record_metadata.update(create_state_keys(attribute.datatype)) |
331 | | - record = builder.mbbOut( |
332 | | - pv, |
333 | | - **update, |
334 | | - **attribute_record_metadata, |
335 | | - ) |
336 | | - case Waveform(): |
337 | | - record = builder.WaveformOut( |
338 | | - pv, |
339 | | - length=attribute.datatype.shape[0], |
340 | | - **update, |
341 | | - **attribute_record_metadata, |
342 | | - ) |
343 | | - case _: |
344 | | - raise FastCSError( |
345 | | - f"EPICS unsupported datatype on {attribute}: {attribute.datatype}" |
346 | | - ) |
347 | | - |
348 | | - def datatype_updater(datatype: DataType): |
349 | | - for name, value in asdict(datatype).items(): |
350 | | - if name in DATATYPE_FIELD_TO_OUT_RECORD_FIELD: |
351 | | - record.set_field(DATATYPE_FIELD_TO_OUT_RECORD_FIELD[name], value) |
352 | | - |
353 | | - attribute.add_update_datatype_callback(datatype_updater) |
354 | | - return record |
355 | | - |
356 | | - |
357 | 193 | def _create_and_link_write_pv( |
358 | 194 | pv_prefix: str, pv_name: str, attr_name: str, attribute: AttrW[DType_T] |
359 | 195 | ) -> None: |
|
0 commit comments