ophyd-async 0.3.4a1__py3-none-any.whl → 0.4.0__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 (44) hide show
  1. ophyd_async/_version.py +2 -2
  2. ophyd_async/core/__init__.py +20 -8
  3. ophyd_async/core/_providers.py +186 -24
  4. ophyd_async/core/detector.py +14 -15
  5. ophyd_async/core/device.py +18 -6
  6. ophyd_async/core/signal.py +32 -8
  7. ophyd_async/core/soft_signal_backend.py +21 -6
  8. ophyd_async/epics/_backend/_aioca.py +3 -0
  9. ophyd_async/epics/_backend/_p4p.py +50 -2
  10. ophyd_async/epics/_backend/common.py +3 -1
  11. ophyd_async/epics/areadetector/aravis.py +3 -3
  12. ophyd_async/epics/areadetector/controllers/aravis_controller.py +1 -0
  13. ophyd_async/epics/areadetector/drivers/ad_base.py +3 -2
  14. ophyd_async/epics/areadetector/kinetix.py +3 -3
  15. ophyd_async/epics/areadetector/pilatus.py +3 -3
  16. ophyd_async/epics/areadetector/vimba.py +3 -3
  17. ophyd_async/epics/areadetector/writers/__init__.py +2 -2
  18. ophyd_async/epics/areadetector/writers/general_hdffile.py +97 -0
  19. ophyd_async/epics/areadetector/writers/hdf_writer.py +27 -10
  20. ophyd_async/epics/areadetector/writers/nd_file_hdf.py +3 -0
  21. ophyd_async/epics/areadetector/writers/nd_plugin.py +30 -0
  22. ophyd_async/epics/demo/demo_ad_sim_detector.py +3 -3
  23. ophyd_async/epics/motion/motor.py +132 -2
  24. ophyd_async/panda/__init__.py +15 -1
  25. ophyd_async/panda/_common_blocks.py +22 -1
  26. ophyd_async/panda/_hdf_panda.py +5 -3
  27. ophyd_async/panda/_table.py +20 -18
  28. ophyd_async/panda/_trigger.py +62 -7
  29. ophyd_async/panda/writers/_hdf_writer.py +17 -8
  30. ophyd_async/plan_stubs/ensure_connected.py +7 -2
  31. ophyd_async/plan_stubs/fly.py +58 -7
  32. ophyd_async/sim/pattern_generator.py +71 -182
  33. ophyd_async/sim/sim_pattern_detector_control.py +3 -3
  34. ophyd_async/sim/sim_pattern_detector_writer.py +9 -5
  35. ophyd_async/sim/sim_pattern_generator.py +12 -5
  36. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/METADATA +7 -2
  37. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/RECORD +41 -43
  38. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/WHEEL +1 -1
  39. ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -10
  40. ophyd_async/epics/areadetector/writers/_hdffile.py +0 -54
  41. ophyd_async/panda/writers/_panda_hdf_file.py +0 -54
  42. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/LICENSE +0 -0
  43. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/entry_points.txt +0 -0
  44. {ophyd_async-0.3.4a1.dist-info → ophyd_async-0.4.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import atexit
3
+ import inspect
3
4
  import logging
4
5
  import time
5
6
  from dataclasses import dataclass
@@ -19,6 +20,7 @@ from ophyd_async.core import (
19
20
  get_unique,
20
21
  wait_for_connection,
21
22
  )
23
+ from ophyd_async.core.signal_backend import RuntimeSubsetEnum
22
24
  from ophyd_async.core.utils import DEFAULT_TIMEOUT, NotConnected
23
25
 
24
26
  from .common import LimitPair, Limits, common_meta, get_supported_values
@@ -39,6 +41,21 @@ specifier_to_dtype: Dict[str, Dtype] = {
39
41
  "s": "string",
40
42
  }
41
43
 
44
+ specifier_to_np_dtype: Dict[str, str] = {
45
+ "?": "<i2", # bool
46
+ "b": "|i1", # int8
47
+ "B": "|u1", # uint8
48
+ "h": "<i2", # int16
49
+ "H": "<u2", # uint16
50
+ "i": "<i4", # int32
51
+ "I": "<u4", # uint32
52
+ "l": "<i8", # int64
53
+ "L": "<u8", # uint64
54
+ "f": "<f4", # float32
55
+ "d": "<f8", # float64
56
+ "s": "|S40",
57
+ }
58
+
42
59
 
43
60
  def _data_key_from_value(
44
61
  source: str,
@@ -59,12 +76,35 @@ def _data_key_from_value(
59
76
  DataKey: A rich DataKey describing the DB record
60
77
  """
61
78
  shape = shape or []
62
- dtype = dtype or specifier_to_dtype[value.type().aspy("value")]
79
+ type_code = value.type().aspy("value")
80
+
81
+ dtype = dtype or specifier_to_dtype[type_code]
82
+
83
+ try:
84
+ if isinstance(type_code, tuple):
85
+ dtype_numpy = ""
86
+ if type_code[1] == "enum_t":
87
+ if dtype == "bool":
88
+ dtype_numpy = "<i2"
89
+ else:
90
+ for item in type_code[2]:
91
+ if item[0] == "choices":
92
+ dtype_numpy = specifier_to_np_dtype[item[1][1]]
93
+ elif not type_code.startswith("a"):
94
+ dtype_numpy = specifier_to_np_dtype[type_code]
95
+ else:
96
+ # Array type, use typecode of internal element
97
+ dtype_numpy = specifier_to_np_dtype[type_code[1]]
98
+ except KeyError:
99
+ # Case where we can't determine dtype string from value
100
+ dtype_numpy = ""
101
+
63
102
  display_data = getattr(value, "display", None)
64
103
 
65
104
  d = DataKey(
66
105
  source=source,
67
106
  dtype=dtype,
107
+ dtype_numpy=dtype_numpy,
68
108
  shape=shape,
69
109
  )
70
110
  if display_data is not None:
@@ -249,7 +289,7 @@ def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConve
249
289
  typ = get_unique(
250
290
  {k: type(v.get("value")) for k, v in values.items()}, "value types"
251
291
  )
252
- if "NTScalarArray" in typeid and typ == list:
292
+ if "NTScalarArray" in typeid and typ is list:
253
293
  # Waveform of strings, check we wanted this
254
294
  if datatype and datatype != Sequence[str]:
255
295
  raise TypeError(f"{pv} has type [str] not {datatype.__name__}")
@@ -287,6 +327,14 @@ def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConve
287
327
  return PvaEnumConverter(get_supported_values(pv, datatype, pv_choices))
288
328
  elif "NTScalar" in typeid:
289
329
  if (
330
+ typ is str
331
+ and inspect.isclass(datatype)
332
+ and issubclass(datatype, RuntimeSubsetEnum)
333
+ ):
334
+ return PvaEnumConverter(
335
+ get_supported_values(pv, datatype, datatype.choices)
336
+ )
337
+ elif (
290
338
  datatype
291
339
  and not issubclass(typ, datatype)
292
340
  and not (
@@ -1,6 +1,8 @@
1
1
  import inspect
2
2
  from enum import Enum
3
- from typing import Dict, Optional, Tuple, Type, TypedDict
3
+ from typing import Dict, Optional, Tuple, Type
4
+
5
+ from typing_extensions import TypedDict
4
6
 
5
7
  from ophyd_async.core.signal_backend import RuntimeSubsetEnum
6
8
 
@@ -2,7 +2,7 @@ from typing import get_args
2
2
 
3
3
  from bluesky.protocols import HasHints, Hints
4
4
 
5
- from ophyd_async.core import DirectoryProvider, StandardDetector
5
+ from ophyd_async.core import PathProvider, StandardDetector
6
6
  from ophyd_async.epics.areadetector.controllers.aravis_controller import (
7
7
  AravisController,
8
8
  )
@@ -24,7 +24,7 @@ class AravisDetector(StandardDetector, HasHints):
24
24
  def __init__(
25
25
  self,
26
26
  prefix: str,
27
- directory_provider: DirectoryProvider,
27
+ path_provider: PathProvider,
28
28
  drv_suffix="cam1:",
29
29
  hdf_suffix="HDF1:",
30
30
  name="",
@@ -37,7 +37,7 @@ class AravisDetector(StandardDetector, HasHints):
37
37
  AravisController(self.drv, gpio_number=gpio_number),
38
38
  HDFWriter(
39
39
  self.hdf,
40
- directory_provider,
40
+ path_provider,
41
41
  lambda: self.name,
42
42
  ADBaseShapeProvider(self.drv),
43
43
  ),
@@ -62,6 +62,7 @@ class AravisController(DetectorControl):
62
62
  supported_trigger_types = (
63
63
  DetectorTrigger.constant_gate,
64
64
  DetectorTrigger.edge_trigger,
65
+ DetectorTrigger.internal,
65
66
  )
66
67
  if trigger not in supported_trigger_types:
67
68
  raise ValueError(
@@ -1,6 +1,6 @@
1
1
  import asyncio
2
2
  from enum import Enum
3
- from typing import FrozenSet, Sequence, Set
3
+ from typing import FrozenSet, Set
4
4
 
5
5
  from ophyd_async.core import (
6
6
  DEFAULT_TIMEOUT,
@@ -131,9 +131,10 @@ class ADBaseShapeProvider(ShapeProvider):
131
131
  def __init__(self, driver: ADBase) -> None:
132
132
  self._driver = driver
133
133
 
134
- async def __call__(self) -> Sequence[int]:
134
+ async def __call__(self) -> tuple:
135
135
  shape = await asyncio.gather(
136
136
  self._driver.array_size_y.get_value(),
137
137
  self._driver.array_size_x.get_value(),
138
+ self._driver.data_type.get_value(),
138
139
  )
139
140
  return shape
@@ -1,6 +1,6 @@
1
1
  from bluesky.protocols import HasHints, Hints
2
2
 
3
- from ophyd_async.core import DirectoryProvider, StandardDetector
3
+ from ophyd_async.core import PathProvider, StandardDetector
4
4
  from ophyd_async.epics.areadetector.controllers.kinetix_controller import (
5
5
  KinetixController,
6
6
  )
@@ -21,7 +21,7 @@ class KinetixDetector(StandardDetector, HasHints):
21
21
  def __init__(
22
22
  self,
23
23
  prefix: str,
24
- directory_provider: DirectoryProvider,
24
+ path_provider: PathProvider,
25
25
  drv_suffix="cam1:",
26
26
  hdf_suffix="HDF1:",
27
27
  name="",
@@ -33,7 +33,7 @@ class KinetixDetector(StandardDetector, HasHints):
33
33
  KinetixController(self.drv),
34
34
  HDFWriter(
35
35
  self.hdf,
36
- directory_provider,
36
+ path_provider,
37
37
  lambda: self.name,
38
38
  ADBaseShapeProvider(self.drv),
39
39
  ),
@@ -2,7 +2,7 @@ from enum import Enum
2
2
 
3
3
  from bluesky.protocols import Hints
4
4
 
5
- from ophyd_async.core import DirectoryProvider
5
+ from ophyd_async.core import PathProvider
6
6
  from ophyd_async.core.detector import StandardDetector
7
7
  from ophyd_async.epics.areadetector.controllers.pilatus_controller import (
8
8
  PilatusController,
@@ -36,7 +36,7 @@ class PilatusDetector(StandardDetector):
36
36
  def __init__(
37
37
  self,
38
38
  prefix: str,
39
- directory_provider: DirectoryProvider,
39
+ path_provider: PathProvider,
40
40
  readout_time: PilatusReadoutTime = PilatusReadoutTime.pilatus3,
41
41
  drv_suffix: str = "cam1:",
42
42
  hdf_suffix: str = "HDF1:",
@@ -49,7 +49,7 @@ class PilatusDetector(StandardDetector):
49
49
  PilatusController(self.drv, readout_time=readout_time.value),
50
50
  HDFWriter(
51
51
  self.hdf,
52
- directory_provider,
52
+ path_provider,
53
53
  lambda: self.name,
54
54
  ADBaseShapeProvider(self.drv),
55
55
  ),
@@ -1,6 +1,6 @@
1
1
  from bluesky.protocols import HasHints, Hints
2
2
 
3
- from ophyd_async.core import DirectoryProvider, StandardDetector
3
+ from ophyd_async.core import PathProvider, StandardDetector
4
4
  from ophyd_async.epics.areadetector.controllers.vimba_controller import VimbaController
5
5
  from ophyd_async.epics.areadetector.drivers import ADBaseShapeProvider
6
6
  from ophyd_async.epics.areadetector.drivers.vimba_driver import VimbaDriver
@@ -18,7 +18,7 @@ class VimbaDetector(StandardDetector, HasHints):
18
18
  def __init__(
19
19
  self,
20
20
  prefix: str,
21
- directory_provider: DirectoryProvider,
21
+ path_provider: PathProvider,
22
22
  drv_suffix="cam1:",
23
23
  hdf_suffix="HDF1:",
24
24
  name="",
@@ -30,7 +30,7 @@ class VimbaDetector(StandardDetector, HasHints):
30
30
  VimbaController(self.drv),
31
31
  HDFWriter(
32
32
  self.hdf,
33
- directory_provider,
33
+ path_provider,
34
34
  lambda: self.name,
35
35
  ADBaseShapeProvider(self.drv),
36
36
  ),
@@ -1,5 +1,5 @@
1
1
  from .hdf_writer import HDFWriter
2
2
  from .nd_file_hdf import NDFileHDF
3
- from .nd_plugin import NDPluginBase, NDPluginStats
3
+ from .nd_plugin import ADBaseDataType, NDPluginBase, NDPluginStats
4
4
 
5
- __all__ = ["HDFWriter", "NDFileHDF", "NDPluginBase", "NDPluginStats"]
5
+ __all__ = ["HDFWriter", "NDFileHDF", "NDPluginBase", "NDPluginStats", "ADBaseDataType"]
@@ -0,0 +1,97 @@
1
+ from dataclasses import dataclass, field
2
+ from pathlib import Path
3
+ from typing import Iterator, List, Sequence
4
+ from urllib.parse import urlunparse
5
+
6
+ from event_model import (
7
+ ComposeStreamResource,
8
+ ComposeStreamResourceBundle,
9
+ StreamDatum,
10
+ StreamResource,
11
+ )
12
+
13
+ from ophyd_async.core import PathInfo
14
+
15
+
16
+ @dataclass
17
+ class _HDFDataset:
18
+ data_key: str
19
+ dataset: str
20
+ shape: Sequence[int] = field(default_factory=tuple)
21
+ dtype_numpy: str = ""
22
+ multiplier: int = 1
23
+ swmr: bool = False
24
+
25
+
26
+ SLICE_NAME = "AD_HDF5_SWMR_SLICE"
27
+
28
+
29
+ class _HDFFile:
30
+ """
31
+ :param directory_info: Contains information about how to construct a StreamResource
32
+ :param full_file_name: Absolute path to the file to be written
33
+ :param datasets: Datasets to write into the file
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ path_info: PathInfo,
39
+ full_file_name: Path,
40
+ datasets: List[_HDFDataset],
41
+ hostname: str = "localhost",
42
+ ) -> None:
43
+ self._last_emitted = 0
44
+ self._hostname = hostname
45
+
46
+ if len(datasets) == 0:
47
+ self._bundles = []
48
+ return None
49
+
50
+ bundler_composer = ComposeStreamResource()
51
+
52
+ uri = urlunparse(
53
+ (
54
+ "file",
55
+ self._hostname,
56
+ str((path_info.root / full_file_name).absolute()),
57
+ "",
58
+ "",
59
+ None,
60
+ )
61
+ )
62
+
63
+ self._bundles: List[ComposeStreamResourceBundle] = [
64
+ bundler_composer(
65
+ mimetype="application/x-hdf5",
66
+ uri=uri,
67
+ data_key=ds.data_key,
68
+ parameters={
69
+ "dataset": ds.dataset,
70
+ "swmr": ds.swmr,
71
+ "multiplier": ds.multiplier,
72
+ },
73
+ uid=None,
74
+ validate=True,
75
+ )
76
+ for ds in datasets
77
+ ]
78
+
79
+ def stream_resources(self) -> Iterator[StreamResource]:
80
+ for bundle in self._bundles:
81
+ yield bundle.stream_resource_doc
82
+
83
+ def stream_data(self, indices_written: int) -> Iterator[StreamDatum]:
84
+ # Indices are relative to resource
85
+ if indices_written > self._last_emitted:
86
+ indices = {
87
+ "start": self._last_emitted,
88
+ "stop": indices_written,
89
+ }
90
+ self._last_emitted = indices_written
91
+ for bundle in self._bundles:
92
+ yield bundle.compose_stream_datum(indices)
93
+ return None
94
+
95
+ def close(self) -> None:
96
+ for bundle in self._bundles:
97
+ bundle.close()
@@ -8,30 +8,30 @@ from ophyd_async.core import (
8
8
  DEFAULT_TIMEOUT,
9
9
  AsyncStatus,
10
10
  DetectorWriter,
11
- DirectoryProvider,
12
11
  NameProvider,
12
+ PathProvider,
13
13
  ShapeProvider,
14
14
  set_and_wait_for_value,
15
15
  wait_for_value,
16
16
  )
17
17
  from ophyd_async.core.signal import observe_value
18
18
 
19
- from ._hdfdataset import _HDFDataset
20
- from ._hdffile import _HDFFile
19
+ from .general_hdffile import _HDFDataset, _HDFFile
21
20
  from .nd_file_hdf import FileWriteMode, NDFileHDF
21
+ from .nd_plugin import convert_ad_dtype_to_np
22
22
 
23
23
 
24
24
  class HDFWriter(DetectorWriter):
25
25
  def __init__(
26
26
  self,
27
27
  hdf: NDFileHDF,
28
- directory_provider: DirectoryProvider,
28
+ path_provider: PathProvider,
29
29
  name_provider: NameProvider,
30
30
  shape_provider: ShapeProvider,
31
31
  **scalar_datasets_paths: str,
32
32
  ) -> None:
33
33
  self.hdf = hdf
34
- self._directory_provider = directory_provider
34
+ self._path_provider = path_provider
35
35
  self._name_provider = name_provider
36
36
  self._shape_provider = shape_provider
37
37
  self._scalar_datasets_paths = scalar_datasets_paths
@@ -42,7 +42,7 @@ class HDFWriter(DetectorWriter):
42
42
 
43
43
  async def open(self, multiplier: int = 1) -> Dict[str, DataKey]:
44
44
  self._file = None
45
- info = self._directory_provider()
45
+ info = self._path_provider(device_name=self.hdf.name)
46
46
  file_path = str(info.root / info.resource_dir)
47
47
  await asyncio.gather(
48
48
  self.hdf.num_extra_dims.set(0),
@@ -50,8 +50,9 @@ class HDFWriter(DetectorWriter):
50
50
  self.hdf.swmr_mode.set(True),
51
51
  # See https://github.com/bluesky/ophyd-async/issues/122
52
52
  self.hdf.file_path.set(file_path),
53
- self.hdf.file_name.set(f"{info.prefix}{self.hdf.name}{info.suffix}"),
53
+ self.hdf.file_name.set(info.filename),
54
54
  self.hdf.file_template.set("%s/%s.h5"),
55
+ self.hdf.create_dir_depth.set(info.create_dir_depth),
55
56
  self.hdf.file_write_mode.set(FileWriteMode.stream),
56
57
  # Never use custom xml layout file but use the one defined
57
58
  # in the source code file NDFileHDF5LayoutXML.cpp
@@ -70,9 +71,22 @@ class HDFWriter(DetectorWriter):
70
71
  detector_shape = tuple(await self._shape_provider())
71
72
  self._multiplier = multiplier
72
73
  outer_shape = (multiplier,) if multiplier > 1 else ()
74
+ frame_shape = detector_shape[:-1] if len(detector_shape) > 0 else []
75
+ dtype_numpy = (
76
+ convert_ad_dtype_to_np(detector_shape[-1])
77
+ if len(detector_shape) > 0
78
+ else ""
79
+ )
80
+
73
81
  # Add the main data
74
82
  self._datasets = [
75
- _HDFDataset(name, "/entry/data/data", detector_shape, multiplier)
83
+ _HDFDataset(
84
+ data_key=name,
85
+ dataset="/entry/data/data",
86
+ shape=frame_shape,
87
+ dtype_numpy=dtype_numpy,
88
+ multiplier=multiplier,
89
+ )
76
90
  ]
77
91
  # And all the scalar datasets
78
92
  for ds_name, ds_path in self._scalar_datasets_paths.items():
@@ -81,14 +95,17 @@ class HDFWriter(DetectorWriter):
81
95
  f"{name}-{ds_name}",
82
96
  f"/entry/instrument/NDAttributes/{ds_path}",
83
97
  (),
98
+ "",
84
99
  multiplier,
85
100
  )
86
101
  )
102
+
87
103
  describe = {
88
- ds.name: DataKey(
104
+ ds.data_key: DataKey(
89
105
  source=self.hdf.full_file_name.source,
90
106
  shape=outer_shape + tuple(ds.shape),
91
107
  dtype="array" if ds.shape else "number",
108
+ dtype_numpy=ds.dtype_numpy,
92
109
  external="STREAM:",
93
110
  )
94
111
  for ds in self._datasets
@@ -115,7 +132,7 @@ class HDFWriter(DetectorWriter):
115
132
  if not self._file:
116
133
  path = Path(await self.hdf.full_file_name.get_value())
117
134
  self._file = _HDFFile(
118
- self._directory_provider(),
135
+ self._path_provider(),
119
136
  # See https://github.com/bluesky/ophyd-async/issues/122
120
137
  path,
121
138
  self._datasets,
@@ -37,4 +37,7 @@ class NDFileHDF(NDPluginBase):
37
37
  self.capture = epics_signal_rw_rbv(bool, prefix + "Capture")
38
38
  self.flush_now = epics_signal_rw(bool, prefix + "FlushNow")
39
39
  self.xml_file_name = epics_signal_rw_rbv(str, prefix + "XMLFileName")
40
+ self.array_size0 = epics_signal_r(int, prefix + "ArraySize0")
41
+ self.array_size1 = epics_signal_r(int, prefix + "ArraySize1")
42
+ self.create_dir_depth = epics_signal_rw(int, prefix + "CreateDirectory")
40
43
  super().__init__(prefix, name)
@@ -10,6 +10,35 @@ class Callback(str, Enum):
10
10
  Disable = "Disable"
11
11
 
12
12
 
13
+ class ADBaseDataType(str, Enum):
14
+ Int8 = "Int8"
15
+ UInt8 = "UInt8"
16
+ Int16 = "Int16"
17
+ UInt16 = "UInt16"
18
+ Int32 = "Int32"
19
+ UInt32 = "UInt32"
20
+ Int64 = "Int64"
21
+ UInt64 = "UInt64"
22
+ Float32 = "Float32"
23
+ Float64 = "Float64"
24
+
25
+
26
+ def convert_ad_dtype_to_np(ad_dtype: ADBaseDataType) -> str:
27
+ ad_dtype_to_np_dtype = {
28
+ ADBaseDataType.Int8: "|i1",
29
+ ADBaseDataType.UInt8: "|u1",
30
+ ADBaseDataType.Int16: "<i2",
31
+ ADBaseDataType.UInt16: "<u2",
32
+ ADBaseDataType.Int32: "<i4",
33
+ ADBaseDataType.UInt32: "<u4",
34
+ ADBaseDataType.Int64: "<i8",
35
+ ADBaseDataType.UInt64: "<u8",
36
+ ADBaseDataType.Float32: "<f4",
37
+ ADBaseDataType.Float64: "<f8",
38
+ }
39
+ return ad_dtype_to_np_dtype[ad_dtype]
40
+
41
+
13
42
  class NDArrayBase(Device):
14
43
  def __init__(self, prefix: str, name: str = "") -> None:
15
44
  self.unique_id = epics_signal_r(int, prefix + "UniqueId_RBV")
@@ -17,6 +46,7 @@ class NDArrayBase(Device):
17
46
  self.acquire = epics_signal_rw_rbv(bool, prefix + "Acquire")
18
47
  self.array_size_x = epics_signal_r(int, prefix + "ArraySizeX_RBV")
19
48
  self.array_size_y = epics_signal_r(int, prefix + "ArraySizeY_RBV")
49
+ self.data_type = epics_signal_r(ADBaseDataType, prefix + "NDDataType_RBV")
20
50
  self.array_counter = epics_signal_rw_rbv(int, prefix + "ArrayCounter")
21
51
  # There is no _RBV for this one
22
52
  self.wait_for_plugins = epics_signal_rw(bool, prefix + "WaitForPlugins")
@@ -1,6 +1,6 @@
1
1
  from typing import Sequence
2
2
 
3
- from ophyd_async.core import DirectoryProvider, SignalR, StandardDetector
3
+ from ophyd_async.core import PathProvider, SignalR, StandardDetector
4
4
 
5
5
  from ..areadetector.controllers import ADSimController
6
6
  from ..areadetector.drivers import ADBase, ADBaseShapeProvider
@@ -15,7 +15,7 @@ class DemoADSimDetector(StandardDetector):
15
15
  self,
16
16
  drv: ADBase,
17
17
  hdf: NDFileHDF,
18
- directory_provider: DirectoryProvider,
18
+ path_provider: PathProvider,
19
19
  name: str = "",
20
20
  config_sigs: Sequence[SignalR] = (),
21
21
  ):
@@ -26,7 +26,7 @@ class DemoADSimDetector(StandardDetector):
26
26
  ADSimController(self.drv),
27
27
  HDFWriter(
28
28
  self.hdf,
29
- directory_provider,
29
+ path_provider,
30
30
  lambda: self.name,
31
31
  ADBaseShapeProvider(self.drv),
32
32
  ),