ophyd-async 0.3a2__py3-none-any.whl → 0.3a4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. ophyd_async/_version.py +1 -1
  2. ophyd_async/core/__init__.py +35 -11
  3. ophyd_async/core/async_status.py +2 -0
  4. ophyd_async/core/detector.py +8 -9
  5. ophyd_async/core/device.py +22 -9
  6. ophyd_async/core/flyer.py +2 -2
  7. ophyd_async/core/mock_signal_backend.py +86 -0
  8. ophyd_async/core/mock_signal_utils.py +149 -0
  9. ophyd_async/core/signal.py +140 -49
  10. ophyd_async/core/signal_backend.py +2 -2
  11. ophyd_async/core/{sim_signal_backend.py → soft_signal_backend.py} +29 -39
  12. ophyd_async/core/standard_readable.py +211 -24
  13. ophyd_async/epics/_backend/_aioca.py +17 -13
  14. ophyd_async/epics/_backend/_p4p.py +28 -18
  15. ophyd_async/epics/_backend/common.py +17 -17
  16. ophyd_async/epics/areadetector/__init__.py +4 -4
  17. ophyd_async/epics/areadetector/aravis.py +7 -9
  18. ophyd_async/epics/areadetector/controllers/__init__.py +2 -1
  19. ophyd_async/epics/areadetector/controllers/kinetix_controller.py +49 -0
  20. ophyd_async/epics/areadetector/controllers/vimba_controller.py +66 -0
  21. ophyd_async/epics/areadetector/drivers/__init__.py +6 -0
  22. ophyd_async/epics/areadetector/drivers/ad_base.py +12 -10
  23. ophyd_async/epics/areadetector/drivers/aravis_driver.py +7 -5
  24. ophyd_async/epics/areadetector/drivers/kinetix_driver.py +27 -0
  25. ophyd_async/epics/areadetector/drivers/pilatus_driver.py +5 -2
  26. ophyd_async/epics/areadetector/drivers/vimba_driver.py +63 -0
  27. ophyd_async/epics/areadetector/kinetix.py +46 -0
  28. ophyd_async/epics/areadetector/pilatus.py +7 -12
  29. ophyd_async/epics/areadetector/single_trigger_det.py +14 -6
  30. ophyd_async/epics/areadetector/utils.py +2 -12
  31. ophyd_async/epics/areadetector/vimba.py +43 -0
  32. ophyd_async/epics/areadetector/writers/hdf_writer.py +6 -3
  33. ophyd_async/epics/areadetector/writers/nd_file_hdf.py +21 -18
  34. ophyd_async/epics/areadetector/writers/nd_plugin.py +6 -7
  35. ophyd_async/epics/demo/__init__.py +19 -22
  36. ophyd_async/epics/motion/motor.py +16 -13
  37. ophyd_async/epics/pvi/pvi.py +11 -11
  38. ophyd_async/epics/signal/signal.py +1 -1
  39. ophyd_async/log.py +130 -0
  40. ophyd_async/panda/_hdf_panda.py +3 -3
  41. ophyd_async/panda/writers/_hdf_writer.py +3 -3
  42. ophyd_async/protocols.py +26 -3
  43. ophyd_async/sim/demo/sim_motor.py +14 -12
  44. ophyd_async/sim/pattern_generator.py +9 -9
  45. ophyd_async/sim/sim_pattern_detector_writer.py +2 -2
  46. ophyd_async/sim/sim_pattern_generator.py +2 -2
  47. {ophyd_async-0.3a2.dist-info → ophyd_async-0.3a4.dist-info}/METADATA +20 -3
  48. ophyd_async-0.3a4.dist-info/RECORD +85 -0
  49. ophyd_async-0.3a2.dist-info/RECORD +0 -76
  50. {ophyd_async-0.3a2.dist-info → ophyd_async-0.3a4.dist-info}/LICENSE +0 -0
  51. {ophyd_async-0.3a2.dist-info → ophyd_async-0.3a4.dist-info}/WHEEL +0 -0
  52. {ophyd_async-0.3a2.dist-info → ophyd_async-0.3a4.dist-info}/entry_points.txt +0 -0
  53. {ophyd_async-0.3a2.dist-info → ophyd_async-0.3a4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,66 @@
1
+ import asyncio
2
+ from typing import Optional
3
+
4
+ from ophyd_async.core import AsyncStatus, DetectorControl, DetectorTrigger
5
+ from ophyd_async.epics.areadetector.drivers.ad_base import (
6
+ start_acquiring_driver_and_ensure_status,
7
+ )
8
+
9
+ from ..drivers.vimba_driver import (
10
+ VimbaDriver,
11
+ VimbaExposeOutMode,
12
+ VimbaOnOff,
13
+ VimbaTriggerSource,
14
+ )
15
+ from ..utils import ImageMode, stop_busy_record
16
+
17
+ TRIGGER_MODE = {
18
+ DetectorTrigger.internal: VimbaOnOff.off,
19
+ DetectorTrigger.constant_gate: VimbaOnOff.on,
20
+ DetectorTrigger.variable_gate: VimbaOnOff.on,
21
+ DetectorTrigger.edge_trigger: VimbaOnOff.on,
22
+ }
23
+
24
+ EXPOSE_OUT_MODE = {
25
+ DetectorTrigger.internal: VimbaExposeOutMode.timed,
26
+ DetectorTrigger.constant_gate: VimbaExposeOutMode.trigger_width,
27
+ DetectorTrigger.variable_gate: VimbaExposeOutMode.trigger_width,
28
+ DetectorTrigger.edge_trigger: VimbaExposeOutMode.timed,
29
+ }
30
+
31
+
32
+ class VimbaController(DetectorControl):
33
+ def __init__(
34
+ self,
35
+ driver: VimbaDriver,
36
+ ) -> None:
37
+ self._drv = driver
38
+
39
+ def get_deadtime(self, exposure: float) -> float:
40
+ return 0.001
41
+
42
+ async def arm(
43
+ self,
44
+ num: int,
45
+ trigger: DetectorTrigger = DetectorTrigger.internal,
46
+ exposure: Optional[float] = None,
47
+ ) -> AsyncStatus:
48
+ await asyncio.gather(
49
+ self._drv.trigger_mode.set(TRIGGER_MODE[trigger]),
50
+ self._drv.expose_mode.set(EXPOSE_OUT_MODE[trigger]),
51
+ self._drv.num_images.set(num),
52
+ self._drv.image_mode.set(ImageMode.multiple),
53
+ )
54
+ if exposure is not None and trigger not in [
55
+ DetectorTrigger.variable_gate,
56
+ DetectorTrigger.constant_gate,
57
+ ]:
58
+ await self._drv.acquire_time.set(exposure)
59
+ if trigger != DetectorTrigger.internal:
60
+ self._drv.trig_source.set(VimbaTriggerSource.line1)
61
+ else:
62
+ self._drv.trig_source.set(VimbaTriggerSource.freerun)
63
+ return await start_acquiring_driver_and_ensure_status(self._drv)
64
+
65
+ async def disarm(self):
66
+ await stop_busy_record(self._drv.acquire, False, timeout=1)
@@ -4,12 +4,18 @@ from .ad_base import (
4
4
  DetectorState,
5
5
  start_acquiring_driver_and_ensure_status,
6
6
  )
7
+ from .aravis_driver import AravisDriver
8
+ from .kinetix_driver import KinetixDriver
7
9
  from .pilatus_driver import PilatusDriver
10
+ from .vimba_driver import VimbaDriver
8
11
 
9
12
  __all__ = [
10
13
  "ADBase",
11
14
  "ADBaseShapeProvider",
12
15
  "PilatusDriver",
16
+ "AravisDriver",
17
+ "KinetixDriver",
18
+ "VimbaDriver",
13
19
  "start_acquiring_driver_and_ensure_status",
14
20
  "DetectorState",
15
21
  ]
@@ -9,8 +9,8 @@ from ophyd_async.core import (
9
9
  set_and_wait_for_value,
10
10
  )
11
11
 
12
- from ...signal.signal import epics_signal_rw
13
- from ..utils import ImageMode, ad_r, ad_rw
12
+ from ...signal.signal import epics_signal_r, epics_signal_rw, epics_signal_rw_rbv
13
+ from ..utils import ImageMode
14
14
  from ..writers.nd_plugin import NDArrayBase
15
15
 
16
16
 
@@ -43,14 +43,16 @@ DEFAULT_GOOD_STATES: FrozenSet[DetectorState] = frozenset(
43
43
  class ADBase(NDArrayBase):
44
44
  def __init__(self, prefix: str, name: str = "") -> None:
45
45
  # Define some signals
46
- self.acquire = ad_rw(bool, prefix + "Acquire")
47
- self.acquire_time = ad_rw(float, prefix + "AcquireTime")
48
- self.num_images = ad_rw(int, prefix + "NumImages")
49
- self.image_mode = ad_rw(ImageMode, prefix + "ImageMode")
50
- self.array_counter = ad_rw(int, prefix + "ArrayCounter")
51
- self.array_size_x = ad_r(int, prefix + "ArraySizeX")
52
- self.array_size_y = ad_r(int, prefix + "ArraySizeY")
53
- self.detector_state = ad_r(DetectorState, prefix + "DetectorState")
46
+ self.acquire = epics_signal_rw_rbv(bool, prefix + "Acquire")
47
+ self.acquire_time = epics_signal_rw_rbv(float, prefix + "AcquireTime")
48
+ self.num_images = epics_signal_rw_rbv(int, prefix + "NumImages")
49
+ self.image_mode = epics_signal_rw_rbv(ImageMode, prefix + "ImageMode")
50
+ self.array_counter = epics_signal_rw_rbv(int, prefix + "ArrayCounter")
51
+ self.array_size_x = epics_signal_r(int, prefix + "ArraySizeX_RBV")
52
+ self.array_size_y = epics_signal_r(int, prefix + "ArraySizeY_RBV")
53
+ self.detector_state = epics_signal_r(
54
+ DetectorState, prefix + "DetectorState_RBV"
55
+ )
54
56
  # There is no _RBV for this one
55
57
  self.wait_for_plugins = epics_signal_rw(bool, prefix + "WaitForPlugins")
56
58
  super().__init__(prefix, name=name)
@@ -2,7 +2,7 @@ from enum import Enum
2
2
  from typing import Callable, Dict, Literal, Optional, Tuple
3
3
 
4
4
  from ophyd_async.epics.areadetector.drivers import ADBase
5
- from ophyd_async.epics.areadetector.utils import ad_r, ad_rw
5
+ from ophyd_async.epics.signal.signal import epics_signal_r, epics_signal_rw_rbv
6
6
 
7
7
 
8
8
  class AravisTriggerMode(str, Enum):
@@ -138,10 +138,12 @@ class AravisDriver(ADBase):
138
138
  """
139
139
 
140
140
  def __init__(self, prefix: str, name: str = "") -> None:
141
- self.trigger_mode = ad_rw(AravisTriggerMode, prefix + "TriggerMode")
142
- self.trigger_source = ad_rw(str, prefix + "TriggerSource")
143
- self.model = ad_r(str, prefix + "Model")
144
- self.pixel_format = ad_rw(str, prefix + "PixelFormat")
141
+ self.trigger_mode = epics_signal_rw_rbv(
142
+ AravisTriggerMode, prefix + "TriggerMode"
143
+ )
144
+ self.trigger_source = epics_signal_rw_rbv(str, prefix + "TriggerSource")
145
+ self.model = epics_signal_r(str, prefix + "Model_RBV")
146
+ self.pixel_format = epics_signal_rw_rbv(str, prefix + "PixelFormat")
145
147
  self.dead_time: Optional[float] = None
146
148
  super().__init__(prefix, name=name)
147
149
 
@@ -0,0 +1,27 @@
1
+ from enum import Enum
2
+
3
+ from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
4
+
5
+ from .ad_base import ADBase
6
+
7
+
8
+ class KinetixTriggerMode(str, Enum):
9
+ internal = "Internal"
10
+ edge = "Rising Edge"
11
+ gate = "Exp. Gate"
12
+
13
+
14
+ class KinetixReadoutMode(str, Enum):
15
+ sensitivity = 1
16
+ speed = 2
17
+ dynamic_range = 3
18
+
19
+
20
+ class KinetixDriver(ADBase):
21
+ def __init__(self, prefix: str, name: str = "") -> None:
22
+ # self.pixel_format = epics_signal_rw_rbv(PixelFormat, prefix + "PixelFormat")
23
+ self.trigger_mode = epics_signal_rw_rbv(
24
+ KinetixTriggerMode, prefix + "TriggerMode"
25
+ )
26
+ self.mode = epics_signal_rw_rbv(KinetixReadoutMode, prefix + "ReadoutPortIdx")
27
+ super().__init__(prefix, name)
@@ -1,6 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
- from ..utils import ad_rw
3
+ from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
4
+
4
5
  from .ad_base import ADBase
5
6
 
6
7
 
@@ -14,5 +15,7 @@ class PilatusTriggerMode(str, Enum):
14
15
 
15
16
  class PilatusDriver(ADBase):
16
17
  def __init__(self, prefix: str, name: str = "") -> None:
17
- self.trigger_mode = ad_rw(PilatusTriggerMode, prefix + "TriggerMode")
18
+ self.trigger_mode = epics_signal_rw_rbv(
19
+ PilatusTriggerMode, prefix + "TriggerMode"
20
+ )
18
21
  super().__init__(prefix, name)
@@ -0,0 +1,63 @@
1
+ from enum import Enum
2
+
3
+ from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
4
+
5
+ from .ad_base import ADBase
6
+
7
+
8
+ class VimbaPixelFormat(str, Enum):
9
+ internal = "Mono8"
10
+ ext_enable = "Mono12"
11
+ ext_trigger = "Ext. Trigger"
12
+ mult_trigger = "Mult. Trigger"
13
+ alignment = "Alignment"
14
+
15
+
16
+ class VimbaConvertFormat(str, Enum):
17
+ none = "None"
18
+ mono8 = "Mono8"
19
+ mono16 = "Mono16"
20
+ rgb8 = "RGB8"
21
+ rgb16 = "RGB16"
22
+
23
+
24
+ class VimbaTriggerSource(str, Enum):
25
+ freerun = "Freerun"
26
+ line1 = "Line1"
27
+ line2 = "Line2"
28
+ fixed_rate = "FixedRate"
29
+ software = "Software"
30
+ action0 = "Action0"
31
+ action1 = "Action1"
32
+
33
+
34
+ class VimbaOverlap(str, Enum):
35
+ off = "Off"
36
+ prev_frame = "PreviousFrame"
37
+
38
+
39
+ class VimbaOnOff(str, Enum):
40
+ on = "On"
41
+ off = "Off"
42
+
43
+
44
+ class VimbaExposeOutMode(str, Enum):
45
+ timed = "Timed" # Use ExposureTime PV
46
+ trigger_width = "TriggerWidth" # Expose for length of high signal
47
+
48
+
49
+ class VimbaDriver(ADBase):
50
+ def __init__(self, prefix: str, name: str = "") -> None:
51
+ # self.pixel_format = epics_signal_rw_rbv(PixelFormat, prefix + "PixelFormat")
52
+ self.convert_format = epics_signal_rw_rbv(
53
+ VimbaConvertFormat, prefix + "ConvertPixelFormat"
54
+ ) # Pixel format of data outputted to AD
55
+ self.trig_source = epics_signal_rw_rbv(
56
+ VimbaTriggerSource, prefix + "TriggerSource"
57
+ )
58
+ self.trigger_mode = epics_signal_rw_rbv(VimbaOnOff, prefix + "TriggerMode")
59
+ self.overlap = epics_signal_rw_rbv(VimbaOverlap, prefix + "TriggerOverlap")
60
+ self.expose_mode = epics_signal_rw_rbv(
61
+ VimbaExposeOutMode, prefix + "ExposureMode"
62
+ )
63
+ super().__init__(prefix, name)
@@ -0,0 +1,46 @@
1
+ from bluesky.protocols import HasHints, Hints
2
+
3
+ from ophyd_async.core import DirectoryProvider, StandardDetector
4
+ from ophyd_async.epics.areadetector.controllers.kinetix_controller import (
5
+ KinetixController,
6
+ )
7
+ from ophyd_async.epics.areadetector.drivers import ADBaseShapeProvider
8
+ from ophyd_async.epics.areadetector.drivers.kinetix_driver import KinetixDriver
9
+ from ophyd_async.epics.areadetector.writers import HDFWriter, NDFileHDF
10
+
11
+
12
+ class KinetixDetector(StandardDetector, HasHints):
13
+ """
14
+ Ophyd-async implementation of an ADKinetix Detector.
15
+ https://github.com/NSLS-II/ADKinetix
16
+ """
17
+
18
+ _controller: KinetixController
19
+ _writer: HDFWriter
20
+
21
+ def __init__(
22
+ self,
23
+ prefix: str,
24
+ directory_provider: DirectoryProvider,
25
+ drv_suffix="cam1:",
26
+ hdf_suffix="HDF1:",
27
+ name="",
28
+ ):
29
+ self.drv = KinetixDriver(prefix + drv_suffix)
30
+ self.hdf = NDFileHDF(prefix + hdf_suffix)
31
+
32
+ super().__init__(
33
+ KinetixController(self.drv),
34
+ HDFWriter(
35
+ self.hdf,
36
+ directory_provider,
37
+ lambda: self.name,
38
+ ADBaseShapeProvider(self.drv),
39
+ ),
40
+ config_sigs=(self.drv.acquire_time,),
41
+ name=name,
42
+ )
43
+
44
+ @property
45
+ def hints(self) -> Hints:
46
+ return self._writer.hints
@@ -1,10 +1,7 @@
1
- from typing import Optional, Sequence
2
-
3
1
  from bluesky.protocols import Hints
4
2
 
5
3
  from ophyd_async.core import DirectoryProvider
6
4
  from ophyd_async.core.detector import StandardDetector
7
- from ophyd_async.core.signal import SignalR
8
5
  from ophyd_async.epics.areadetector.controllers.pilatus_controller import (
9
6
  PilatusController,
10
7
  )
@@ -22,15 +19,14 @@ class PilatusDetector(StandardDetector):
22
19
 
23
20
  def __init__(
24
21
  self,
25
- name: str,
22
+ prefix: str,
26
23
  directory_provider: DirectoryProvider,
27
- driver: PilatusDriver,
28
- hdf: NDFileHDF,
29
- config_sigs: Optional[Sequence[SignalR]] = None,
30
- **scalar_sigs: str,
24
+ drv_suffix="cam1:",
25
+ hdf_suffix="HDF1:",
26
+ name="",
31
27
  ):
32
- self.drv = driver
33
- self.hdf = hdf
28
+ self.drv = PilatusDriver(prefix + drv_suffix)
29
+ self.hdf = NDFileHDF(prefix + hdf_suffix)
34
30
 
35
31
  super().__init__(
36
32
  PilatusController(self.drv),
@@ -39,9 +35,8 @@ class PilatusDetector(StandardDetector):
39
35
  directory_provider,
40
36
  lambda: self.name,
41
37
  ADBaseShapeProvider(self.drv),
42
- **scalar_sigs,
43
38
  ),
44
- config_sigs=config_sigs or (self.drv.acquire_time,),
39
+ config_sigs=(self.drv.acquire_time,),
45
40
  name=name,
46
41
  )
47
42
 
@@ -3,7 +3,13 @@ from typing import Sequence
3
3
 
4
4
  from bluesky.protocols import Triggerable
5
5
 
6
- from ophyd_async.core import AsyncStatus, SignalR, StandardReadable
6
+ from ophyd_async.core import (
7
+ AsyncStatus,
8
+ ConfigSignal,
9
+ HintedSignal,
10
+ SignalR,
11
+ StandardReadable,
12
+ )
7
13
 
8
14
  from .drivers.ad_base import ADBase
9
15
  from .utils import ImageMode
@@ -20,12 +26,14 @@ class SingleTriggerDet(StandardReadable, Triggerable):
20
26
  ) -> None:
21
27
  self.drv = drv
22
28
  self.__dict__.update(plugins)
23
- self.set_readable_signals(
24
- # Can't subscribe to read signals as race between monitor coming back and
25
- # caput callback on acquire
26
- read_uncached=[self.drv.array_counter] + list(read_uncached),
27
- config=[self.drv.acquire_time],
29
+
30
+ self.add_readables(
31
+ [self.drv.array_counter, *read_uncached],
32
+ wrapper=HintedSignal.uncached,
28
33
  )
34
+
35
+ self.add_readables([self.drv.acquire_time], wrapper=ConfigSignal)
36
+
29
37
  super().__init__(name=name)
30
38
 
31
39
  @AsyncStatus.wrap
@@ -1,18 +1,8 @@
1
1
  from enum import Enum
2
- from typing import Optional, Type
2
+ from typing import Optional
3
3
  from xml.etree import cElementTree as ET
4
4
 
5
- from ophyd_async.core import DEFAULT_TIMEOUT, SignalR, SignalRW, T, wait_for_value
6
-
7
- from ..signal.signal import epics_signal_r, epics_signal_rw
8
-
9
-
10
- def ad_rw(datatype: Type[T], prefix: str) -> SignalRW[T]:
11
- return epics_signal_rw(datatype, prefix + "_RBV", prefix)
12
-
13
-
14
- def ad_r(datatype: Type[T], prefix: str) -> SignalR[T]:
15
- return epics_signal_r(datatype, prefix + "_RBV")
5
+ from ophyd_async.core import DEFAULT_TIMEOUT, SignalRW, T, wait_for_value
16
6
 
17
7
 
18
8
  class FileWriteMode(str, Enum):
@@ -0,0 +1,43 @@
1
+ from bluesky.protocols import HasHints, Hints
2
+
3
+ from ophyd_async.core import DirectoryProvider, StandardDetector
4
+ from ophyd_async.epics.areadetector.controllers.vimba_controller import VimbaController
5
+ from ophyd_async.epics.areadetector.drivers import ADBaseShapeProvider
6
+ from ophyd_async.epics.areadetector.drivers.vimba_driver import VimbaDriver
7
+ from ophyd_async.epics.areadetector.writers import HDFWriter, NDFileHDF
8
+
9
+
10
+ class VimbaDetector(StandardDetector, HasHints):
11
+ """
12
+ Ophyd-async implementation of an ADVimba Detector.
13
+ """
14
+
15
+ _controller: VimbaController
16
+ _writer: HDFWriter
17
+
18
+ def __init__(
19
+ self,
20
+ prefix: str,
21
+ directory_provider: DirectoryProvider,
22
+ drv_suffix="cam1:",
23
+ hdf_suffix="HDF1:",
24
+ name="",
25
+ ):
26
+ self.drv = VimbaDriver(prefix + drv_suffix)
27
+ self.hdf = NDFileHDF(prefix + hdf_suffix)
28
+
29
+ super().__init__(
30
+ VimbaController(self.drv),
31
+ HDFWriter(
32
+ self.hdf,
33
+ directory_provider,
34
+ lambda: self.name,
35
+ ADBaseShapeProvider(self.drv),
36
+ ),
37
+ config_sigs=(self.drv.acquire_time,),
38
+ name=name,
39
+ )
40
+
41
+ @property
42
+ def hints(self) -> Hints:
43
+ return self._writer.hints
@@ -2,7 +2,7 @@ import asyncio
2
2
  from pathlib import Path
3
3
  from typing import AsyncGenerator, AsyncIterator, Dict, List, Optional
4
4
 
5
- from bluesky.protocols import Descriptor, Hints, StreamAsset
5
+ from bluesky.protocols import DataKey, Hints, StreamAsset
6
6
 
7
7
  from ophyd_async.core import (
8
8
  DEFAULT_TIMEOUT,
@@ -40,7 +40,7 @@ class HDFWriter(DetectorWriter):
40
40
  self._file: Optional[_HDFFile] = None
41
41
  self._multiplier = 1
42
42
 
43
- async def open(self, multiplier: int = 1) -> Dict[str, Descriptor]:
43
+ async def open(self, multiplier: int = 1) -> Dict[str, DataKey]:
44
44
  self._file = None
45
45
  info = self._directory_provider()
46
46
  await asyncio.gather(
@@ -52,6 +52,9 @@ class HDFWriter(DetectorWriter):
52
52
  self.hdf.file_name.set(f"{info.prefix}{self.hdf.name}{info.suffix}"),
53
53
  self.hdf.file_template.set("%s/%s.h5"),
54
54
  self.hdf.file_write_mode.set(FileWriteMode.stream),
55
+ # Never use custom xml layout file but use the one defined
56
+ # in the source code file NDFileHDF5LayoutXML.cpp
57
+ self.hdf.xml_file_name.set(""),
55
58
  )
56
59
 
57
60
  assert (
@@ -81,7 +84,7 @@ class HDFWriter(DetectorWriter):
81
84
  )
82
85
  )
83
86
  describe = {
84
- ds.name: Descriptor(
87
+ ds.name: DataKey(
85
88
  source=self.hdf.full_file_name.source,
86
89
  shape=outer_shape + tuple(ds.shape),
87
90
  dtype="array" if ds.shape else "number",
@@ -1,7 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
- from ...signal.signal import epics_signal_rw
4
- from ..utils import FileWriteMode, ad_r, ad_rw
3
+ from ...signal.signal import epics_signal_r, epics_signal_rw, epics_signal_rw_rbv
4
+ from ..utils import FileWriteMode
5
5
  from .nd_plugin import NDPluginBase
6
6
 
7
7
 
@@ -19,21 +19,24 @@ class Compression(str, Enum):
19
19
  class NDFileHDF(NDPluginBase):
20
20
  def __init__(self, prefix: str, name="") -> None:
21
21
  # Define some signals
22
- self.position_mode = ad_rw(bool, prefix + "PositionMode")
23
- self.compression = ad_rw(Compression, prefix + "Compression")
24
- self.num_extra_dims = ad_rw(int, prefix + "NumExtraDims")
25
- self.file_path = ad_rw(str, prefix + "FilePath")
26
- self.file_name = ad_rw(str, prefix + "FileName")
27
- self.file_path_exists = ad_r(bool, prefix + "FilePathExists")
28
- self.file_template = ad_rw(str, prefix + "FileTemplate")
29
- self.full_file_name = ad_r(str, prefix + "FullFileName")
30
- self.file_write_mode = ad_rw(FileWriteMode, prefix + "FileWriteMode")
31
- self.num_capture = ad_rw(int, prefix + "NumCapture")
32
- self.num_captured = ad_r(int, prefix + "NumCaptured")
33
- self.swmr_mode = ad_rw(bool, prefix + "SWMRMode")
34
- self.lazy_open = ad_rw(bool, prefix + "LazyOpen")
35
- self.capture = ad_rw(bool, prefix + "Capture")
22
+ self.position_mode = epics_signal_rw_rbv(bool, prefix + "PositionMode")
23
+ self.compression = epics_signal_rw_rbv(Compression, prefix + "Compression")
24
+ self.num_extra_dims = epics_signal_rw_rbv(int, prefix + "NumExtraDims")
25
+ self.file_path = epics_signal_rw_rbv(str, prefix + "FilePath")
26
+ self.file_name = epics_signal_rw_rbv(str, prefix + "FileName")
27
+ self.file_path_exists = epics_signal_r(bool, prefix + "FilePathExists_RBV")
28
+ self.file_template = epics_signal_rw_rbv(str, prefix + "FileTemplate")
29
+ self.full_file_name = epics_signal_r(str, prefix + "FullFileName_RBV")
30
+ self.file_write_mode = epics_signal_rw_rbv(
31
+ FileWriteMode, prefix + "FileWriteMode"
32
+ )
33
+ self.num_capture = epics_signal_rw_rbv(int, prefix + "NumCapture")
34
+ self.num_captured = epics_signal_r(int, prefix + "NumCaptured_RBV")
35
+ self.swmr_mode = epics_signal_rw_rbv(bool, prefix + "SWMRMode")
36
+ self.lazy_open = epics_signal_rw_rbv(bool, prefix + "LazyOpen")
37
+ self.capture = epics_signal_rw_rbv(bool, prefix + "Capture")
36
38
  self.flush_now = epics_signal_rw(bool, prefix + "FlushNow")
37
- self.array_size0 = ad_r(int, prefix + "ArraySize0")
38
- self.array_size1 = ad_r(int, prefix + "ArraySize1")
39
+ self.array_size0 = epics_signal_r(int, prefix + "ArraySize0_RBV")
40
+ self.array_size1 = epics_signal_r(int, prefix + "ArraySize1_RBV")
41
+ self.xml_file_name = epics_signal_rw_rbv(str, prefix + "XMLFileName")
39
42
  super().__init__(prefix, name)
@@ -2,8 +2,7 @@ from enum import Enum
2
2
 
3
3
  from ophyd_async.core import Device
4
4
  from ophyd_async.epics.signal import epics_signal_rw
5
-
6
- from ..utils import ad_r, ad_rw
5
+ from ophyd_async.epics.signal.signal import epics_signal_r, epics_signal_rw_rbv
7
6
 
8
7
 
9
8
  class Callback(str, Enum):
@@ -13,16 +12,16 @@ class Callback(str, Enum):
13
12
 
14
13
  class NDArrayBase(Device):
15
14
  def __init__(self, prefix: str, name: str = "") -> None:
16
- self.unique_id = ad_r(int, prefix + "UniqueId")
15
+ self.unique_id = epics_signal_r(int, prefix + "UniqueId_RBV")
17
16
  self.nd_attributes_file = epics_signal_rw(str, prefix + "NDAttributesFile")
18
- super().__init__(name)
17
+ super().__init__(name=name)
19
18
 
20
19
 
21
20
  class NDPluginBase(NDArrayBase):
22
21
  def __init__(self, prefix: str, name: str = "") -> None:
23
- self.nd_array_port = ad_rw(str, prefix + "NDArrayPort")
24
- self.enable_callback = ad_rw(Callback, prefix + "EnableCallbacks")
25
- self.nd_array_address = ad_rw(int, prefix + "NDArrayAddress")
22
+ self.nd_array_port = epics_signal_rw_rbv(str, prefix + "NDArrayPort")
23
+ self.enable_callback = epics_signal_rw_rbv(Callback, prefix + "EnableCallbacks")
24
+ self.nd_array_address = epics_signal_rw_rbv(int, prefix + "NDArrayAddress")
26
25
  super().__init__(prefix, name)
27
26
 
28
27
 
@@ -16,8 +16,10 @@ from bluesky.protocols import Movable, Stoppable
16
16
 
17
17
  from ophyd_async.core import (
18
18
  AsyncStatus,
19
+ ConfigSignal,
19
20
  Device,
20
21
  DeviceVector,
22
+ HintedSignal,
21
23
  StandardReadable,
22
24
  observe_value,
23
25
  )
@@ -39,26 +41,21 @@ class Sensor(StandardReadable):
39
41
 
40
42
  def __init__(self, prefix: str, name="") -> None:
41
43
  # Define some signals
42
- self.value = epics_signal_r(float, prefix + "Value")
43
- self.mode = epics_signal_rw(EnergyMode, prefix + "Mode")
44
- # Set name and signals for read() and read_configuration()
45
- self.set_readable_signals(
46
- read=[self.value],
47
- config=[self.mode],
48
- )
44
+ with self.add_children_as_readables(HintedSignal):
45
+ self.value = epics_signal_r(float, prefix + "Value")
46
+ with self.add_children_as_readables(ConfigSignal):
47
+ self.mode = epics_signal_rw(EnergyMode, prefix + "Mode")
48
+
49
49
  super().__init__(name=name)
50
50
 
51
51
 
52
52
  class SensorGroup(StandardReadable):
53
53
  def __init__(self, prefix: str, name: str = "", sensor_count: int = 3) -> None:
54
- self.sensors = DeviceVector(
55
- {i: Sensor(f"{prefix}{i}:") for i in range(1, sensor_count + 1)}
56
- )
54
+ with self.add_children_as_readables():
55
+ self.sensors = DeviceVector(
56
+ {i: Sensor(f"{prefix}{i}:") for i in range(1, sensor_count + 1)}
57
+ )
57
58
 
58
- # Makes read() produce the values of all sensors
59
- self.set_readable_signals(
60
- read=[sensor.value for sensor in self.sensors.values()],
61
- )
62
59
  super().__init__(name)
63
60
 
64
61
 
@@ -67,20 +64,20 @@ class Mover(StandardReadable, Movable, Stoppable):
67
64
 
68
65
  def __init__(self, prefix: str, name="") -> None:
69
66
  # Define some signals
67
+ with self.add_children_as_readables(HintedSignal):
68
+ self.readback = epics_signal_r(float, prefix + "Readback")
69
+
70
+ with self.add_children_as_readables(ConfigSignal):
71
+ self.velocity = epics_signal_rw(float, prefix + "Velocity")
72
+ self.units = epics_signal_r(str, prefix + "Readback.EGU")
73
+
70
74
  self.setpoint = epics_signal_rw(float, prefix + "Setpoint")
71
- self.readback = epics_signal_r(float, prefix + "Readback")
72
- self.velocity = epics_signal_rw(float, prefix + "Velocity")
73
- self.units = epics_signal_r(str, prefix + "Readback.EGU")
74
75
  self.precision = epics_signal_r(int, prefix + "Readback.PREC")
75
76
  # Signals that collide with standard methods should have a trailing underscore
76
77
  self.stop_ = epics_signal_x(prefix + "Stop.PROC")
77
78
  # Whether set() should complete successfully or not
78
79
  self._set_success = True
79
- # Set name and signals for read() and read_configuration()
80
- self.set_readable_signals(
81
- read=[self.readback],
82
- config=[self.velocity, self.units],
83
- )
80
+
84
81
  super().__init__(name=name)
85
82
 
86
83
  def set_name(self, name: str):