11from collections .abc import Callable
2- from dataclasses import dataclass
2+ from dataclasses import asdict , dataclass
33from types import MethodType
44from typing import Any , Literal
55
1515 enum_value_to_index ,
1616)
1717from fastcs .controller import BaseController
18- from fastcs .datatypes import Bool , Float , Int , String , T
18+ from fastcs .datatypes import Bool , DataType , Float , Int , String , T
1919from fastcs .exceptions import FastCSException
2020from fastcs .mapping import Mapping
2121
@@ -27,6 +27,26 @@ class EpicsIOCOptions:
2727 terminal : bool = True
2828
2929
30+ DATATYPE_NAME_TO_RECORD_FIELD = {
31+ "prec" : "PREC" ,
32+ "units" : "EGU" ,
33+ "min" : "DRVL" ,
34+ "max" : "DRVH" ,
35+ "min_alarm" : "LOPR" ,
36+ "max_alarm" : "HOPR" ,
37+ "znam" : "ZNAM" ,
38+ "onam" : "ONAM" ,
39+ }
40+
41+
42+ def datatype_to_epics_fields (datatype : DataType ) -> dict [str , Any ]:
43+ return {
44+ DATATYPE_NAME_TO_RECORD_FIELD [field ]: value
45+ for field , value in asdict (datatype ).items ()
46+ if field in DATATYPE_NAME_TO_RECORD_FIELD
47+ }
48+
49+
3050class EpicsIOC :
3151 def __init__ (self , pv_prefix : str , mapping : Mapping ):
3252 _add_pvi_info (f"{ pv_prefix } :PVI" )
@@ -184,36 +204,38 @@ def _get_input_record(pv: str, attribute: AttrR) -> RecordWrapper:
184204 return builder .mbbIn (pv , ** state_keys , ** attribute_fields )
185205
186206 match attribute .datatype :
187- case Bool (znam , onam ):
188- return builder .boolIn (pv , ZNAM = znam , ONAM = onam , ** attribute_fields )
189- case Int (units , min , max , min_alarm , max_alarm ):
190- return builder .longIn (
207+ case Bool ():
208+ record = builder .boolIn (
209+ pv , ** datatype_to_epics_fields (attribute .datatype ), ** attribute_fields
210+ )
211+ case Int ():
212+ record = builder .longIn (
191213 pv ,
192- EGU = units ,
193- DRVL = min ,
194- DRVH = max ,
195- LOPR = min_alarm ,
196- HOPR = max_alarm ,
214+ ** datatype_to_epics_fields (attribute .datatype ),
197215 ** attribute_fields ,
198216 )
199- case Float (prec , units , min , max , min_alarm , max_alarm ):
200- return builder .aIn (
217+ case Float ():
218+ record = builder .aIn (
201219 pv ,
202- PREC = prec ,
203- EGU = units ,
204- DRVL = min ,
205- DRVH = max ,
206- LOPR = min_alarm ,
207- HOPR = max_alarm ,
220+ ** datatype_to_epics_fields (attribute .datatype ),
208221 ** attribute_fields ,
209222 )
210223 case String ():
211- return builder .longStringIn (pv , ** attribute_fields )
224+ record = builder .longStringIn (
225+ pv , ** datatype_to_epics_fields (attribute .datatype ), ** attribute_fields
226+ )
212227 case _:
213228 raise FastCSException (
214229 f"Unsupported type { type (attribute .datatype )} : { attribute .datatype } "
215230 )
216231
232+ def datatype_updater (datatype : DataType ):
233+ for name , value in datatype_to_epics_fields (datatype ).items ():
234+ record .set_field (name , value )
235+
236+ attribute .add_update_datatype_callback (datatype_updater )
237+ return record
238+
217239
218240def _create_and_link_write_pv (
219241 pv_prefix : str , pv_name : str , attr_name : str , attribute : AttrW [T ]
@@ -262,48 +284,45 @@ def _get_output_record(pv: str, attribute: AttrW, on_update: Callable) -> Any:
262284 )
263285
264286 match attribute .datatype :
265- case Bool (znam , onam ):
266- return builder .boolOut (
287+ case Bool ():
288+ record = builder .boolOut (
267289 pv ,
268- ZNAM = znam ,
269- ONAM = onam ,
290+ ** datatype_to_epics_fields (attribute .datatype ),
270291 always_update = True ,
271292 on_update = on_update ,
272293 )
273- case Int (units , min , max , min_alarm , max_alarm ):
274- return builder .longOut (
294+ case Int ():
295+ record = builder .longOut (
275296 pv ,
276297 always_update = True ,
277298 on_update = on_update ,
278- EGU = units ,
279- DRVL = min ,
280- DRVH = max ,
281- LOPR = min_alarm ,
282- HOPR = max_alarm ,
299+ ** datatype_to_epics_fields (attribute .datatype ),
283300 ** attribute_fields ,
284301 )
285- case Float (prec , units , min , max , min_alarm , max_alarm ):
286- return builder .aOut (
302+ case Float ():
303+ record = builder .aOut (
287304 pv ,
288305 always_update = True ,
289306 on_update = on_update ,
290- PREC = prec ,
291- EGU = units ,
292- DRVL = min ,
293- DRVH = max ,
294- LOPR = min_alarm ,
295- HOPR = max_alarm ,
307+ ** datatype_to_epics_fields (attribute .datatype ),
296308 ** attribute_fields ,
297309 )
298310 case String ():
299- return builder .longStringOut (
311+ record = builder .longStringOut (
300312 pv , always_update = True , on_update = on_update , ** attribute_fields
301313 )
302314 case _:
303315 raise FastCSException (
304316 f"Unsupported type { type (attribute .datatype )} : { attribute .datatype } "
305317 )
306318
319+ def datatype_updater (datatype : DataType ):
320+ for name , value in datatype_to_epics_fields (datatype ).items ():
321+ record .set_field (name , value )
322+
323+ attribute .add_update_datatype_callback (datatype_updater )
324+ return record
325+
307326
308327def _create_and_link_command_pvs (pv_prefix : str , mapping : Mapping ) -> None :
309328 for single_mapping in mapping .get_controller_mappings ():
0 commit comments