1- """ophyd-async devices and utilities for communicating with IBEX blocks."""
1+ """bluesky devices and utilities for communicating with IBEX blocks."""
22
33import asyncio
44import logging
6262class BlockWriteConfig (Generic [T ]):
6363 """Configuration settings for writing to blocks.
6464
65- use_completion_callback:
66- Whether to wait for an EPICS completion callback while setting
67- this block. Defaults to true, which is appropriate for most blocks.
65+ These settings control how a block write is determined to be 'complete'. A block
66+ write should only be marked as complete when the equipment has physically reached
67+ the correct state, not just when the equipment has been told to move to the correct
68+ state.
6869
69- set_success_func:
70- An arbitrary function which is called to decide whether the block has
71- set successfully yet or not. The function takes (setpoint, actual) as arguments and
72- should return true if the value has successfully set and is "ready", or False otherwise.
73-
74- This can be used to implement arbitrary tolerance behaviour. For example::
75-
76- def check(setpoint: T, actual: T) -> bool:
77- return setpoint - 0.1 <= actual <= setpoint + 0.1
70+ For example, during a scan of a block against a detector, the detector will be read
71+ as soon as the block declares the write as 'complete'.
72+ """
7873
79- If use_completion_callback is True, the completion callback must complete before
80- set_success_func is ever called.
74+ use_completion_callback : bool = True
75+ """
76+ Whether to wait for an EPICS completion callback while setting
77+ this block. Defaults to :py:obj:`True`, which is appropriate for most blocks.
78+ """
8179
82- Executing this function should be "fast" (i.e. the function should not sleep), and it should
83- not do any external I/O.
80+ set_success_func : Callable [[T , T ], bool ] | None = None
81+ """
82+ An arbitrary function which is called to decide whether the block has
83+ set successfully yet or not. The function takes ``(setpoint, actual)`` as arguments and
84+ should return :py:obj:`True` if the value has successfully set and is "ready", or
85+ :py:obj:`False` otherwise.
8486
85- Defaults to None, which means no check is applied.
87+ This can be used to implement arbitrary tolerance behaviour. For example::
8688
87- set_timeout_s:
88- A timeout, in seconds, on the value being set successfully. The timeout
89- applies to the EPICS completion callback (if enabled) and the set success function
90- (if provided), and excludes any configured settle time.
89+ def check(setpoint: T, actual: T) -> bool:
90+ return setpoint - 0.1 <= actual <= setpoint + 0.1
9191
92- Defaults to None, which means no timeout.
92+ If use_completion_callback is True, the completion callback must complete before
93+ ``set_success_func`` is ever called.
9394
94- settle_time_s:
95- A wait time, in seconds, which is unconditionally applied just before the set
96- status is marked as complete. Defaults to zero.
95+ Executing this function should be "fast" (i.e. the function should not sleep), and it should
96+ not do any external I/O.
9797
98- use_global_moving_flag:
99- Whether to wait for the IBEX global moving indicator to return "stationary". This is useful
100- for compound moves, where changing a single block may cause multiple underlying axes to
101- move, and all movement needs to be complete before the set is considered complete. Defaults
102- to False.
98+ Defaults to :py:obj:`None`, which means no check is applied.
99+ """
103100
104- timeout_is_error:
105- Whether a write timeout is considered an error. Defaults to True. If False, a set will be
106- marked as complete without error even if the block has not given a completion callback or
107- satisfied set_success_func within settle_time_s.
101+ set_timeout_s : float | None = None
102+ """
103+ A timeout, in seconds, on the value being set successfully. The timeout
104+ applies to the EPICS completion callback (if enabled) and the set success function
105+ (if provided), and excludes any configured settle time.
108106
107+ Defaults to :py:obj:`None`, which means no timeout.
109108 """
110109
111- use_completion_callback : bool = True
112- set_success_func : Callable [[T , T ], bool ] | None = None
113- set_timeout_s : float | None = None
114110 settle_time_s : float = 0.0
111+ """
112+ A wait time, in seconds, which is unconditionally applied just before the set
113+ status is marked as complete. Defaults to zero.
114+ """
115+
115116 use_global_moving_flag : bool = False
117+ """
118+ Whether to wait for the IBEX global moving indicator to return "stationary". This is useful
119+ for compound moves, where changing a single block may cause multiple underlying axes to
120+ move, and all movement needs to be complete before the set is considered complete.
121+ """
122+
116123 timeout_is_error : bool = True
124+ """
125+ Whether a write timeout is considered an error. Defaults to True. If False, a set will be
126+ marked as complete without error even if the block has not given a completion callback or
127+ satisfied ``set_success_func`` within ``settle_time_s``.
128+ """
117129
118130
119131class RunControl (StandardReadable ):
120132 """Subdevice for common run-control signals."""
121133
122134 def __init__ (self , prefix : str , name : str = "" ) -> None :
123- """Create a run control wrapper for a block.
135+ """Subdevice for common run-control signals.
136+
137+ .. note::
124138
125- Usually run control should be accessed via the run_control property on a block, rather
126- than by constructing an instance of this class directly.
139+ Run control should be accessed via the `` run_control`` property on a block,
140+ rather than by constructing an instance of this class directly.
127141
128142 Args:
129- prefix: the run-control prefix, e.g. " IN:INSTRUMENT:CS:SB:blockname:RC:"
143+ prefix: the run-control prefix, e.g. `` IN:INSTRUMENT:CS:SB:blockname:RC:``
130144 name: ophyd device name
131145
132146 """
@@ -148,13 +162,14 @@ def __init__(self, prefix: str, name: str = "") -> None:
148162
149163
150164class BlockR (StandardReadable , Triggerable , Generic [T ]):
151- """Device representing an IBEX readable block of arbitrary data type ."""
165+ """Read-only block."""
152166
153167 def __init__ (self , datatype : type [T ], prefix : str , block_name : str ) -> None :
154- """Create a new read-only block.
168+ """Device representing an IBEX readable block of arbitrary data type .
155169
156170 Args:
157- datatype: the type of data in this block (e.g. str, int, float)
171+ datatype: the type of data in this block
172+ (e.g. :py:obj:`str`, :py:obj:`int`, :py:obj:`float`)
158173 prefix: the current instrument's PV prefix
159174 block_name: the name of the block
160175
@@ -170,9 +185,13 @@ def __init__(self, datatype: type[T], prefix: str, block_name: str) -> None:
170185
171186 @AsyncStatus .wrap
172187 async def trigger (self ) -> None :
173- """Blocks need to be triggerable to be used in adaptive scans .
188+ """Blocks do not do anything when triggered .
174189
175- They do not do anything when triggered.
190+ This method implements :py:obj:`bluesky.protocols.Triggerable`,
191+ and should not be called directly.
192+
193+ This empty implementation is provided to allow using blocks in
194+ adaptive scans.
176195 """
177196
178197 def __repr__ (self ) -> str :
@@ -192,16 +211,22 @@ def __init__(
192211 write_config : BlockWriteConfig [T ] | None = None ,
193212 sp_suffix : str = ":SP" ,
194213 ) -> None :
195- """Create a new read-write block.
214+ """Device representing an IBEX read/write block of arbitrary data type.
215+
216+ The setpoint is not added to ``read()`` by default. For most cases where setpoint readback
217+ functionality is desired, :py:obj:`~ibex_bluesky_core.devices.block.BlockRwRbv` is a more
218+ suitable type.
196219
197- The setpoint is not added to read() by default. For most cases where setpoint readback
198- functionality is desired, BlockRwRbv is a more suitable type.
220+ If you *explicitly* need to read the setpoint from a
221+ :py:obj:`~ibex_bluesky_core.devices.block.BlockRw`, you can do so in a plan with:
199222
200- If you *explicitly* need to read the setpoint from a BlockRw, you can do so in a plan with::
223+ .. code-block:: python
201224
202225 import bluesky.plan_stubs as bps
203- block: BlockRw = ...
204- bps.read(block.setpoint)
226+
227+ def plan():
228+ block: BlockRw = ...
229+ yield from bps.rd(block.setpoint)
205230
206231 But note that this does not read back the setpoint from hardware, but rather the setpoint
207232 which was last sent by EPICS.
@@ -230,7 +255,21 @@ def __init__(
230255
231256 @AsyncStatus .wrap
232257 async def set (self , value : T ) -> None :
233- """Set the setpoint of this block."""
258+ """Set the setpoint of this block.
259+
260+ This method implements :py:obj:`bluesky.protocols.Movable`, and should not be
261+ called directly.
262+
263+ From a plan, set a block using:
264+
265+ .. code-block:: python
266+
267+ import bluesky.plan_stubs as bps
268+
269+ def my_plan():
270+ block = BlockRw(...)
271+ yield from bps.mv(block, value)
272+ """
234273
235274 async def do_set (setpoint : T ) -> None :
236275 logger .info ("Setting Block %s to %s" , self .name , setpoint )
@@ -305,10 +344,10 @@ def __init__(
305344 * ,
306345 write_config : BlockWriteConfig [T ] | None = None ,
307346 ) -> None :
308- """Create a new read/write/setpoint readback block.
347+ """Device representing an IBEX read/write/setpoint readback block of arbitrary data type .
309348
310- The setpoint readback is added to read(), but not hints(), by default. If you do not need
311- a setpoint readback, choose BlockRw instead of BlockRwRbv .
349+ The setpoint readback is added to read(), but not hints(), by default. If you do not have
350+ a setpoint readback, use :py:obj:`~ibex_bluesky_core.devices.block. BlockRw` instead.
312351
313352 Args:
314353 datatype: the type of data in this block (e.g. str, int, float)
@@ -327,7 +366,32 @@ def __init__(
327366 )
328367
329368 async def locate (self ) -> Location [T ]:
330- """Get the current 'location' of this block."""
369+ """Get the current :py:obj:`~bluesky.protocols.Location` of this block.
370+
371+ This method implements :py:obj:`bluesky.protocols.Locatable`, and should not be
372+ called directly.
373+
374+ From a plan, locate a block using:
375+
376+ .. code-block:: python
377+
378+ import bluesky.plan_stubs as bps
379+
380+ def my_plan():
381+ block: BlockRwRbv = ...
382+ location = yield from bps.locate(block)
383+
384+ If you only need the current value, rather than the value and the setpoint-readback, use:
385+
386+ .. code-block:: python
387+
388+ import bluesky.plan_stubs as bps
389+
390+ def my_plan():
391+ block: BlockRwRbv = ...
392+ value = yield from bps.rd(block)
393+
394+ """
331395 logger .info ("locating block %s" , self .name )
332396 actual , sp_rbv = await asyncio .gather (
333397 self .readback .get_value (),
@@ -401,7 +465,7 @@ def __repr__(self) -> str:
401465 def set ( # pyright: ignore
402466 self , value : float , timeout : CalculatableTimeout = CALCULATE_TIMEOUT
403467 ) -> WatchableAsyncStatus [float ]:
404- """Pass through set to superclass .
468+ """Pass through `` set`` to :py:obj:`ophyd_async.epics.motor.Motor.set` .
405469
406470 This is needed so that type-checker correctly understands the type of set.
407471
@@ -415,7 +479,7 @@ def set( # pyright: ignore
415479def block_r (datatype : type [T ], block_name : str ) -> BlockR [T ]:
416480 """Get a local read-only block for the current instrument.
417481
418- See documentation of BlockR for more information.
482+ See documentation of :py:obj:`~ibex_bluesky_core.devices.block. BlockR` for more information.
419483 """
420484 return BlockR (datatype = datatype , prefix = get_pv_prefix (), block_name = block_name )
421485
@@ -429,7 +493,7 @@ def block_rw(
429493) -> BlockRw [T ]:
430494 """Get a local read-write block for the current instrument.
431495
432- See documentation of BlockRw for more information.
496+ See documentation of :py:obj:`~ibex_bluesky_core.devices.block. BlockRw` for more information.
433497 """
434498 return BlockRw (
435499 datatype = datatype ,
@@ -445,7 +509,7 @@ def block_w(
445509) -> BlockRw [T ]:
446510 """Get a write-only block for the current instrument.
447511
448- This is actually just : obj:`ibex_bluesky_core.devices.block.BlockRw` but with no SP suffix.
512+ This is a :py: obj:`~ ibex_bluesky_core.devices.block.BlockRw` instance with no SP suffix.
449513 """
450514 return BlockRw (
451515 datatype = datatype ,
@@ -461,7 +525,7 @@ def block_rw_rbv(
461525) -> BlockRwRbv [T ]:
462526 """Get a local read/write/setpoint readback block for the current instrument.
463527
464- See documentation of BlockRwRbv for more information.
528+ See documentation of :py:obj:`~ibex_bluesky_core.devices.block. BlockRwRbv` for more information.
465529 """
466530 return BlockRwRbv (
467531 datatype = datatype , prefix = get_pv_prefix (), block_name = block_name , write_config = write_config
@@ -471,6 +535,6 @@ def block_rw_rbv(
471535def block_mot (block_name : str ) -> BlockMot :
472536 """Get a local block pointing at a motor record for the local instrument.
473537
474- See documentation of BlockMot for more information.
538+ See documentation of :py:obj:`~ibex_bluesky_core.devices.block. BlockMot` for more information.
475539 """
476540 return BlockMot (prefix = get_pv_prefix (), block_name = block_name )
0 commit comments