1
1
import asyncio
2
- from dataclasses import dataclass
2
+ from typing import Generic , TypeVar
3
3
4
4
from bluesky .protocols import HasName , Movable
5
5
from ophyd_async .core import (
@@ -26,18 +26,18 @@ class StopState(StrictEnum):
26
26
STOP = "STOP"
27
27
28
28
29
- class FastValveControlRequest (StrictEnum ):
29
+ class ValveControlRequest (StrictEnum ):
30
30
OPEN = "Open"
31
31
CLOSE = "Close"
32
32
RESET = "Reset"
33
- ARM = "Arm"
34
- DISARM = "Disarm"
35
33
36
34
37
- class ValveControlRequest (StrictEnum ):
38
- OPEN = "Open"
39
- CLOSE = "Close"
40
- RESET = "Reset"
35
+ class FastValveControlRequest (StrictEnum ):
36
+ OPEN = ValveControlRequest .OPEN .value
37
+ CLOSE = ValveControlRequest .CLOSE .value
38
+ RESET = ValveControlRequest .RESET .value
39
+ ARM = "Arm"
40
+ DISARM = "Disarm"
41
41
42
42
43
43
class ValveOpenSeqRequest (StrictEnum ):
@@ -60,138 +60,89 @@ class ValveState(StrictEnum):
60
60
61
61
62
62
class FastValveState (StrictEnum ):
63
- FAULT = "Fault"
64
- OPEN = "Open"
63
+ FAULT = ValveState . FAULT . value
64
+ OPEN = ValveState . OPEN . value
65
65
OPEN_ARMED = "Open Armed"
66
- CLOSED = "Closed"
66
+ CLOSED = ValveState . CLOSED . value
67
67
CLOSED_ARMED = "Closed Armed"
68
68
NONE = "Unused"
69
69
70
70
71
- @dataclass
72
- class AllValvesControlState :
73
- valve_1 : ValveControlRequest | None = None
74
- valve_3 : ValveControlRequest | None = None
75
- valve_5 : FastValveControlRequest | None = None
76
- valve_6 : FastValveControlRequest | None = None
71
+ TValveControlRequest = TypeVar (
72
+ "TValveControlRequest" , bound = ValveControlRequest | FastValveControlRequest
73
+ )
74
+
77
75
76
+ class ValveControl (
77
+ StandardReadable , Movable [TValveControlRequest ], Generic [TValveControlRequest ]
78
+ ):
79
+ def __init__ (
80
+ self ,
81
+ prefix : str ,
82
+ valve_control_type : type [TValveControlRequest ],
83
+ name : str = "" ,
84
+ ):
85
+ with self .add_children_as_readables ():
86
+ self .control = epics_signal_rw (valve_control_type , prefix + ":CON" )
87
+ self .open = epics_signal_rw (int , prefix + ":OPENSEQ" )
88
+ super ().__init__ (name )
78
89
79
- class AllValvesControl (StandardReadable , Movable [AllValvesControlState ]):
90
+ @AsyncStatus .wrap
91
+ async def set (self , value : TValveControlRequest ):
92
+ if value .value == "Open" :
93
+ await self .open .set (ValveOpenSeqRequest .OPEN_SEQ .value )
94
+ await asyncio .sleep (OPENSEQ_PULSE_LENGTH )
95
+ await self .open .set (ValveOpenSeqRequest .INACTIVE .value )
96
+ else :
97
+ await self .control .set (value )
98
+
99
+
100
+ class AllValvesControl (StandardReadable ):
80
101
"""
81
- valves 2, 4, 7, 8 are not controlled by the IOC,
82
- as they are under manual control.
83
- fast_valves: tuple[int, ...] = (5, 6)
84
- slow_valves: tuple[int, ...] = (1, 3)
102
+ The default IOC for this device only controls
103
+ specific valves. Other valves are under manual
104
+ control.
85
105
"""
86
106
87
107
def __init__ (
88
108
self ,
89
109
prefix : str ,
90
110
name : str = "" ,
91
- fast_valves : tuple [int , ...] = (5 , 6 ),
92
- slow_valves : tuple [int , ...] = (1 , 3 ),
111
+ fast_valves_numbers : tuple [int , ...] = (5 , 6 ),
112
+ slow_valves_numbers : tuple [int , ...] = (1 , 3 ),
93
113
) -> None :
94
- self .fast_valves = fast_valves
95
- self .slow_valves = slow_valves
96
114
with self .add_children_as_readables ():
97
115
self .valve_states : DeviceVector [SignalR [ValveState ]] = DeviceVector (
98
116
{
99
117
i : epics_signal_r (ValveState , f"{ prefix } V{ i } :STA" )
100
- for i in self . slow_valves
118
+ for i in slow_valves_numbers
101
119
}
102
120
)
103
121
self .fast_valve_states : DeviceVector [SignalR [FastValveState ]] = (
104
122
DeviceVector (
105
123
{
106
124
i : epics_signal_r (FastValveState , f"{ prefix } V{ i } :STA" )
107
- for i in self . fast_valves
125
+ for i in fast_valves_numbers
108
126
}
109
127
)
110
128
)
111
129
112
- self .fast_valve_control : DeviceVector [FastValveControl ] = DeviceVector (
113
- {i : FastValveControl (f"{ prefix } V{ i } " ) for i in self .fast_valves }
114
- )
130
+ self .fast_valve_control = {
131
+ i : ValveControl (f"{ prefix } V{ i } " , FastValveControlRequest )
132
+ for i in fast_valves_numbers
133
+ }
115
134
116
- self .valve_control : DeviceVector [ValveControl ] = DeviceVector (
117
- {i : ValveControl (f"{ prefix } V{ i } " ) for i in self .slow_valves }
118
- )
119
-
120
- super ().__init__ (name )
135
+ self .slow_valve_control = {
136
+ i : ValveControl (f"{ prefix } V{ i } " , ValveControlRequest )
137
+ for i in slow_valves_numbers
138
+ }
121
139
122
- async def set_valve (
123
- self ,
124
- valve : int ,
125
- value : ValveControlRequest | FastValveControlRequest ,
126
- ):
127
- if valve in self .slow_valves and (isinstance (value , ValveControlRequest )):
128
- if value == ValveControlRequest .OPEN :
129
- await self .valve_control [valve ].set (ValveOpenSeqRequest .OPEN_SEQ )
130
- await asyncio .sleep (OPENSEQ_PULSE_LENGTH )
131
- await self .valve_control [valve ].set (ValveOpenSeqRequest .INACTIVE )
132
- else :
133
- await self .valve_control [valve ].set (value )
134
-
135
- elif valve in self .fast_valves and (isinstance (value , FastValveControlRequest )):
136
- if value == FastValveControlRequest .OPEN :
137
- await self .fast_valve_control [valve ].set (ValveOpenSeqRequest .OPEN_SEQ )
138
- await asyncio .sleep (OPENSEQ_PULSE_LENGTH )
139
- await self .fast_valve_control [valve ].set (ValveOpenSeqRequest .INACTIVE )
140
- else :
141
- await self .fast_valve_control [valve ].set (value )
140
+ all_valves = self .fast_valve_control | self .slow_valve_control
142
141
143
- @AsyncStatus .wrap
144
- async def set (self , value : AllValvesControlState ):
145
- await asyncio .gather (
146
- * (
147
- self .set_valve (int (i [- 1 ]), value )
148
- for i , value in value .__dict__ .items ()
149
- if value is not None
150
- )
151
- )
152
-
153
-
154
- class ValveControl (
155
- StandardReadable , Movable [ValveControlRequest | ValveOpenSeqRequest ]
156
- ):
157
- def __init__ (self , prefix : str , name : str = "" ) -> None :
158
- with self .add_children_as_readables ():
159
- self .close = epics_signal_rw (ValveControlRequest , prefix + ":CON" )
160
- self .open = epics_signal_rw (int , prefix + ":OPENSEQ" )
142
+ self .valve_control : DeviceVector [ValveControl ] = DeviceVector (all_valves )
161
143
162
144
super ().__init__ (name )
163
145
164
- def set (self , value : ValveControlRequest | ValveOpenSeqRequest ) -> AsyncStatus :
165
- set_status = None
166
-
167
- if isinstance (value , ValveControlRequest ):
168
- set_status = self .close .set (value )
169
- elif isinstance (value , ValveOpenSeqRequest ):
170
- set_status = self .open .set (value .value )
171
-
172
- return set_status
173
-
174
-
175
- class FastValveControl (
176
- StandardReadable , Movable [FastValveControlRequest | ValveOpenSeqRequest ]
177
- ):
178
- def __init__ (self , prefix : str , name : str = "" ) -> None :
179
- with self .add_children_as_readables ():
180
- self .close = epics_signal_rw (FastValveControlRequest , prefix + ":CON" )
181
- self .open = epics_signal_rw (int , prefix + ":OPENSEQ" )
182
-
183
- super ().__init__ (name )
184
-
185
- def set (self , value : FastValveControlRequest | ValveOpenSeqRequest ) -> AsyncStatus :
186
- set_status = None
187
-
188
- if isinstance (value , FastValveControlRequest ):
189
- set_status = self .close .set (value )
190
- elif isinstance (value , ValveOpenSeqRequest ):
191
- set_status = self .open .set (value .value )
192
-
193
- return set_status
194
-
195
146
196
147
class Pump (StandardReadable ):
197
148
def __init__ (self , prefix : str , name : str = "" ) -> None :
0 commit comments