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