ophyd-async 0.8.0a6__py3-none-any.whl → 0.9.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.
- ophyd_async/_version.py +2 -2
- ophyd_async/core/__init__.py +15 -46
- ophyd_async/core/_detector.py +68 -44
- ophyd_async/core/_device.py +120 -79
- ophyd_async/core/_device_filler.py +17 -8
- ophyd_async/core/_flyer.py +2 -2
- ophyd_async/core/_protocol.py +0 -28
- ophyd_async/core/_readable.py +30 -23
- ophyd_async/core/_settings.py +104 -0
- ophyd_async/core/_signal.py +91 -151
- ophyd_async/core/_signal_backend.py +4 -1
- ophyd_async/core/_soft_signal_backend.py +2 -1
- ophyd_async/core/_table.py +18 -10
- ophyd_async/core/_utils.py +30 -5
- ophyd_async/core/_yaml_settings.py +64 -0
- ophyd_async/epics/adandor/__init__.py +9 -0
- ophyd_async/epics/adandor/_andor.py +45 -0
- ophyd_async/epics/adandor/_andor_controller.py +49 -0
- ophyd_async/epics/adandor/_andor_io.py +36 -0
- ophyd_async/epics/adaravis/__init__.py +3 -1
- ophyd_async/epics/adaravis/_aravis.py +23 -37
- ophyd_async/epics/adaravis/_aravis_controller.py +21 -30
- ophyd_async/epics/adaravis/_aravis_io.py +4 -4
- ophyd_async/epics/adcore/__init__.py +15 -8
- ophyd_async/epics/adcore/_core_detector.py +41 -0
- ophyd_async/epics/adcore/_core_io.py +56 -31
- ophyd_async/epics/adcore/_core_logic.py +99 -86
- ophyd_async/epics/adcore/_core_writer.py +219 -0
- ophyd_async/epics/adcore/_hdf_writer.py +33 -59
- ophyd_async/epics/adcore/_jpeg_writer.py +26 -0
- ophyd_async/epics/adcore/_single_trigger.py +5 -4
- ophyd_async/epics/adcore/_tiff_writer.py +26 -0
- ophyd_async/epics/adcore/_utils.py +37 -36
- ophyd_async/epics/adkinetix/_kinetix.py +29 -24
- ophyd_async/epics/adkinetix/_kinetix_controller.py +15 -27
- ophyd_async/epics/adkinetix/_kinetix_io.py +7 -7
- ophyd_async/epics/adpilatus/__init__.py +2 -2
- ophyd_async/epics/adpilatus/_pilatus.py +28 -40
- ophyd_async/epics/adpilatus/_pilatus_controller.py +47 -25
- ophyd_async/epics/adpilatus/_pilatus_io.py +5 -5
- ophyd_async/epics/adsimdetector/__init__.py +3 -3
- ophyd_async/epics/adsimdetector/_sim.py +33 -17
- ophyd_async/epics/advimba/_vimba.py +23 -23
- ophyd_async/epics/advimba/_vimba_controller.py +21 -35
- ophyd_async/epics/advimba/_vimba_io.py +23 -23
- ophyd_async/epics/core/_aioca.py +52 -21
- ophyd_async/epics/core/_p4p.py +59 -16
- ophyd_async/epics/core/_pvi_connector.py +4 -2
- ophyd_async/epics/core/_signal.py +9 -2
- ophyd_async/epics/core/_util.py +10 -1
- ophyd_async/epics/eiger/_eiger_controller.py +4 -4
- ophyd_async/epics/eiger/_eiger_io.py +3 -3
- ophyd_async/epics/motor.py +26 -15
- ophyd_async/epics/sim/_ioc.py +29 -0
- ophyd_async/epics/{demo → sim}/_mover.py +12 -6
- ophyd_async/epics/{demo → sim}/_sensor.py +2 -2
- ophyd_async/epics/testing/__init__.py +14 -14
- ophyd_async/epics/testing/_example_ioc.py +53 -67
- ophyd_async/epics/testing/_utils.py +17 -45
- ophyd_async/epics/testing/test_records.db +22 -0
- ophyd_async/fastcs/core.py +2 -2
- ophyd_async/fastcs/panda/__init__.py +0 -2
- ophyd_async/fastcs/panda/_block.py +9 -9
- ophyd_async/fastcs/panda/_control.py +9 -4
- ophyd_async/fastcs/panda/_hdf_panda.py +7 -2
- ophyd_async/fastcs/panda/_table.py +4 -1
- ophyd_async/fastcs/panda/_trigger.py +7 -7
- ophyd_async/plan_stubs/__init__.py +14 -0
- ophyd_async/plan_stubs/_ensure_connected.py +11 -17
- ophyd_async/plan_stubs/_fly.py +2 -2
- ophyd_async/plan_stubs/_nd_attributes.py +7 -5
- ophyd_async/plan_stubs/_panda.py +13 -0
- ophyd_async/plan_stubs/_settings.py +125 -0
- ophyd_async/plan_stubs/_wait_for_awaitable.py +13 -0
- ophyd_async/sim/__init__.py +19 -0
- ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_detector_controller.py +9 -2
- ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_generator.py +13 -6
- ophyd_async/sim/{demo/_sim_motor.py → _sim_motor.py} +34 -32
- ophyd_async/tango/core/_signal.py +3 -1
- ophyd_async/tango/core/_tango_transport.py +13 -15
- ophyd_async/tango/{demo → sim}/_mover.py +5 -2
- ophyd_async/testing/__init__.py +52 -0
- ophyd_async/testing/__pytest_assert_rewrite.py +4 -0
- ophyd_async/testing/_assert.py +176 -0
- ophyd_async/{core → testing}/_mock_signal_utils.py +15 -11
- ophyd_async/testing/_one_of_everything.py +126 -0
- ophyd_async/testing/_wait_for_pending.py +22 -0
- {ophyd_async-0.8.0a6.dist-info → ophyd_async-0.9.0.dist-info}/METADATA +4 -2
- ophyd_async-0.9.0.dist-info/RECORD +129 -0
- {ophyd_async-0.8.0a6.dist-info → ophyd_async-0.9.0.dist-info}/WHEEL +1 -1
- ophyd_async/core/_device_save_loader.py +0 -274
- ophyd_async/epics/adsimdetector/_sim_controller.py +0 -51
- ophyd_async/fastcs/panda/_utils.py +0 -16
- ophyd_async/sim/demo/__init__.py +0 -19
- ophyd_async/sim/testing/__init__.py +0 -0
- ophyd_async-0.8.0a6.dist-info/RECORD +0 -116
- ophyd_async-0.8.0a6.dist-info/entry_points.txt +0 -2
- /ophyd_async/epics/{demo → sim}/__init__.py +0 -0
- /ophyd_async/epics/{demo → sim}/mover.db +0 -0
- /ophyd_async/epics/{demo → sim}/sensor.db +0 -0
- /ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/__init__.py +0 -0
- /ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_detector.py +0 -0
- /ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_detector_writer.py +0 -0
- /ophyd_async/tango/{demo → sim}/__init__.py +0 -0
- /ophyd_async/tango/{demo → sim}/_counter.py +0 -0
- /ophyd_async/tango/{demo → sim}/_detector.py +0 -0
- /ophyd_async/tango/{demo → sim}/_tango/__init__.py +0 -0
- /ophyd_async/tango/{demo → sim}/_tango/_servers.py +0 -0
- {ophyd_async-0.8.0a6.dist-info → ophyd_async-0.9.0.dist-info}/LICENSE +0 -0
- {ophyd_async-0.8.0a6.dist-info → ophyd_async-0.9.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from ophyd_async.core import StrictEnum, SubsetEnum
|
|
2
|
+
from ophyd_async.epics.adcore import ADBaseIO
|
|
3
|
+
from ophyd_async.epics.core import (
|
|
4
|
+
epics_signal_r,
|
|
5
|
+
epics_signal_rw,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Andor2TriggerMode(StrictEnum):
|
|
10
|
+
INTERNAL = "Internal"
|
|
11
|
+
EXT_TRIGGER = "External"
|
|
12
|
+
EXT_START = "External Start"
|
|
13
|
+
EXT_EXPOSURE = "External Exposure"
|
|
14
|
+
EXT_FVP = "External FVP"
|
|
15
|
+
SOFTWARE = "Software"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Andor2DataType(SubsetEnum):
|
|
19
|
+
UINT16 = "UInt16"
|
|
20
|
+
UINT32 = "UInt32"
|
|
21
|
+
FLOAT32 = "Float32"
|
|
22
|
+
FLOAT64 = "Float64"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Andor2DriverIO(ADBaseIO):
|
|
26
|
+
"""
|
|
27
|
+
Epics pv for andor model:DU897_BV as deployed on p99
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
31
|
+
super().__init__(prefix, name=name)
|
|
32
|
+
self.trigger_mode = epics_signal_rw(Andor2TriggerMode, prefix + "TriggerMode")
|
|
33
|
+
self.data_type = epics_signal_r(Andor2DataType, prefix + "DataType_RBV")
|
|
34
|
+
self.andor_accumulate_period = epics_signal_r(
|
|
35
|
+
float, prefix + "AndorAccumulatePeriod_RBV"
|
|
36
|
+
)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from ._aravis import AravisDetector
|
|
2
2
|
from ._aravis_controller import AravisController
|
|
3
|
-
from ._aravis_io import AravisDriverIO
|
|
3
|
+
from ._aravis_io import AravisDriverIO, AravisTriggerMode, AravisTriggerSource
|
|
4
4
|
|
|
5
5
|
__all__ = [
|
|
6
6
|
"AravisDetector",
|
|
7
7
|
"AravisController",
|
|
8
8
|
"AravisDriverIO",
|
|
9
|
+
"AravisTriggerMode",
|
|
10
|
+
"AravisTriggerSource",
|
|
9
11
|
]
|
|
@@ -1,61 +1,47 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Sequence
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from ophyd_async.core import PathProvider, StandardDetector
|
|
3
|
+
from ophyd_async.core import PathProvider
|
|
4
|
+
from ophyd_async.core._signal import SignalR
|
|
6
5
|
from ophyd_async.epics import adcore
|
|
7
6
|
|
|
8
7
|
from ._aravis_controller import AravisController
|
|
9
8
|
from ._aravis_io import AravisDriverIO
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class AravisDetector(
|
|
11
|
+
class AravisDetector(adcore.AreaDetector[AravisController]):
|
|
13
12
|
"""
|
|
14
13
|
Ophyd-async implementation of an ADAravis Detector.
|
|
15
14
|
The detector may be configured for an external trigger on a GPIO port,
|
|
16
15
|
which must be done prior to preparing the detector
|
|
17
16
|
"""
|
|
18
17
|
|
|
19
|
-
_controller: AravisController
|
|
20
|
-
_writer: adcore.ADHDFWriter
|
|
21
|
-
|
|
22
18
|
def __init__(
|
|
23
19
|
self,
|
|
24
20
|
prefix: str,
|
|
25
21
|
path_provider: PathProvider,
|
|
26
22
|
drv_suffix="cam1:",
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
writer_cls: type[adcore.ADWriter] = adcore.ADHDFWriter,
|
|
24
|
+
fileio_suffix: str | None = None,
|
|
25
|
+
name: str = "",
|
|
29
26
|
gpio_number: AravisController.GPIO_NUMBER = 1,
|
|
27
|
+
config_sigs: Sequence[SignalR] = (),
|
|
28
|
+
plugins: dict[str, adcore.NDPluginBaseIO] | None = None,
|
|
30
29
|
):
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
driver = AravisDriverIO(prefix + drv_suffix)
|
|
31
|
+
controller = AravisController(driver, gpio_number=gpio_number)
|
|
32
|
+
|
|
33
|
+
writer = writer_cls.with_io(
|
|
34
|
+
prefix,
|
|
35
|
+
path_provider,
|
|
36
|
+
dataset_source=driver,
|
|
37
|
+
fileio_suffix=fileio_suffix,
|
|
38
|
+
plugins=plugins,
|
|
39
|
+
)
|
|
33
40
|
|
|
34
41
|
super().__init__(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
path_provider,
|
|
39
|
-
lambda: self.name,
|
|
40
|
-
adcore.ADBaseDatasetDescriber(self.drv),
|
|
41
|
-
),
|
|
42
|
-
config_sigs=(self.drv.acquire_time,),
|
|
42
|
+
controller=controller,
|
|
43
|
+
writer=writer,
|
|
44
|
+
plugins=plugins,
|
|
43
45
|
name=name,
|
|
46
|
+
config_sigs=config_sigs,
|
|
44
47
|
)
|
|
45
|
-
|
|
46
|
-
def get_external_trigger_gpio(self):
|
|
47
|
-
return self._controller.gpio_number
|
|
48
|
-
|
|
49
|
-
def set_external_trigger_gpio(self, gpio_number: AravisController.GPIO_NUMBER):
|
|
50
|
-
supported_gpio_numbers = get_args(AravisController.GPIO_NUMBER)
|
|
51
|
-
if gpio_number not in supported_gpio_numbers:
|
|
52
|
-
raise ValueError(
|
|
53
|
-
f"{self.__class__.__name__} only supports the following GPIO "
|
|
54
|
-
f"indices: {supported_gpio_numbers} but was asked to "
|
|
55
|
-
f"use {gpio_number}"
|
|
56
|
-
)
|
|
57
|
-
self._controller.gpio_number = gpio_number
|
|
58
|
-
|
|
59
|
-
@property
|
|
60
|
-
def hints(self) -> Hints:
|
|
61
|
-
return self._writer.hints
|
|
@@ -2,11 +2,8 @@ import asyncio
|
|
|
2
2
|
from typing import Literal
|
|
3
3
|
|
|
4
4
|
from ophyd_async.core import (
|
|
5
|
-
AsyncStatus,
|
|
6
|
-
DetectorController,
|
|
7
5
|
DetectorTrigger,
|
|
8
6
|
TriggerInfo,
|
|
9
|
-
set_and_wait_for_value,
|
|
10
7
|
)
|
|
11
8
|
from ophyd_async.epics import adcore
|
|
12
9
|
|
|
@@ -18,49 +15,46 @@ from ._aravis_io import AravisDriverIO, AravisTriggerMode, AravisTriggerSource
|
|
|
18
15
|
_HIGHEST_POSSIBLE_DEADTIME = 1961e-6
|
|
19
16
|
|
|
20
17
|
|
|
21
|
-
class AravisController(
|
|
18
|
+
class AravisController(adcore.ADBaseController[AravisDriverIO]):
|
|
22
19
|
GPIO_NUMBER = Literal[1, 2, 3, 4]
|
|
23
20
|
|
|
24
|
-
def __init__(
|
|
25
|
-
self
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
driver: AravisDriverIO,
|
|
24
|
+
good_states: frozenset[adcore.DetectorState] = adcore.DEFAULT_GOOD_STATES,
|
|
25
|
+
gpio_number: GPIO_NUMBER = 1,
|
|
26
|
+
) -> None:
|
|
27
|
+
super().__init__(driver, good_states=good_states)
|
|
26
28
|
self.gpio_number = gpio_number
|
|
27
|
-
self._arm_status: AsyncStatus | None = None
|
|
28
29
|
|
|
29
30
|
def get_deadtime(self, exposure: float | None) -> float:
|
|
30
31
|
return _HIGHEST_POSSIBLE_DEADTIME
|
|
31
32
|
|
|
32
33
|
async def prepare(self, trigger_info: TriggerInfo):
|
|
33
34
|
if trigger_info.total_number_of_triggers == 0:
|
|
34
|
-
image_mode = adcore.ImageMode.
|
|
35
|
+
image_mode = adcore.ImageMode.CONTINUOUS
|
|
35
36
|
else:
|
|
36
|
-
image_mode = adcore.ImageMode.
|
|
37
|
+
image_mode = adcore.ImageMode.MULTIPLE
|
|
37
38
|
if (exposure := trigger_info.livetime) is not None:
|
|
38
|
-
await self.
|
|
39
|
+
await self.driver.acquire_time.set(exposure)
|
|
39
40
|
|
|
40
41
|
trigger_mode, trigger_source = self._get_trigger_info(trigger_info.trigger)
|
|
41
42
|
# trigger mode must be set first and on it's own!
|
|
42
|
-
await self.
|
|
43
|
+
await self.driver.trigger_mode.set(trigger_mode)
|
|
43
44
|
|
|
44
45
|
await asyncio.gather(
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
46
|
+
self.driver.trigger_source.set(trigger_source),
|
|
47
|
+
self.driver.num_images.set(trigger_info.total_number_of_triggers),
|
|
48
|
+
self.driver.image_mode.set(image_mode),
|
|
48
49
|
)
|
|
49
50
|
|
|
50
|
-
async def arm(self):
|
|
51
|
-
self._arm_status = await set_and_wait_for_value(self._drv.acquire, True)
|
|
52
|
-
|
|
53
|
-
async def wait_for_idle(self):
|
|
54
|
-
if self._arm_status:
|
|
55
|
-
await self._arm_status
|
|
56
|
-
|
|
57
51
|
def _get_trigger_info(
|
|
58
52
|
self, trigger: DetectorTrigger
|
|
59
53
|
) -> tuple[AravisTriggerMode, AravisTriggerSource]:
|
|
60
54
|
supported_trigger_types = (
|
|
61
|
-
DetectorTrigger.
|
|
62
|
-
DetectorTrigger.
|
|
63
|
-
DetectorTrigger.
|
|
55
|
+
DetectorTrigger.CONSTANT_GATE,
|
|
56
|
+
DetectorTrigger.EDGE_TRIGGER,
|
|
57
|
+
DetectorTrigger.INTERNAL,
|
|
64
58
|
)
|
|
65
59
|
if trigger not in supported_trigger_types:
|
|
66
60
|
raise ValueError(
|
|
@@ -68,10 +62,7 @@ class AravisController(DetectorController):
|
|
|
68
62
|
f"types: {supported_trigger_types} but was asked to "
|
|
69
63
|
f"use {trigger}"
|
|
70
64
|
)
|
|
71
|
-
if trigger == DetectorTrigger.
|
|
72
|
-
return AravisTriggerMode.
|
|
65
|
+
if trigger == DetectorTrigger.INTERNAL:
|
|
66
|
+
return AravisTriggerMode.OFF, AravisTriggerSource.FREERUN
|
|
73
67
|
else:
|
|
74
|
-
return (AravisTriggerMode.
|
|
75
|
-
|
|
76
|
-
async def disarm(self):
|
|
77
|
-
await adcore.stop_busy_record(self._drv.acquire, False, timeout=1)
|
|
68
|
+
return (AravisTriggerMode.ON, f"Line{self.gpio_number}") # type: ignore
|
|
@@ -6,8 +6,8 @@ from ophyd_async.epics.core import epics_signal_rw_rbv
|
|
|
6
6
|
class AravisTriggerMode(StrictEnum):
|
|
7
7
|
"""GigEVision GenICAM standard: on=externally triggered"""
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
ON = "On"
|
|
10
|
+
OFF = "Off"
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
"""A minimal set of TriggerSources that must be supported by the underlying record.
|
|
@@ -20,8 +20,8 @@ class AravisTriggerMode(StrictEnum):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class AravisTriggerSource(SubsetEnum):
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
FREERUN = "Freerun"
|
|
24
|
+
LINE1 = "Line1"
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class AravisDriverIO(adcore.ADBaseIO):
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
from ._core_detector import AreaDetector
|
|
1
2
|
from ._core_io import (
|
|
3
|
+
ADBaseDatasetDescriber,
|
|
2
4
|
ADBaseIO,
|
|
3
5
|
DetectorState,
|
|
4
6
|
NDArrayBaseIO,
|
|
5
7
|
NDFileHDFIO,
|
|
8
|
+
NDFileIO,
|
|
9
|
+
NDPluginBaseIO,
|
|
6
10
|
NDPluginStatsIO,
|
|
7
11
|
)
|
|
8
|
-
from ._core_logic import
|
|
9
|
-
|
|
10
|
-
ADBaseDatasetDescriber,
|
|
11
|
-
set_exposure_time_and_acquire_period_if_supplied,
|
|
12
|
-
start_acquiring_driver_and_ensure_status,
|
|
13
|
-
)
|
|
12
|
+
from ._core_logic import DEFAULT_GOOD_STATES, ADBaseController
|
|
13
|
+
from ._core_writer import ADWriter
|
|
14
14
|
from ._hdf_writer import ADHDFWriter
|
|
15
|
+
from ._jpeg_writer import ADJPEGWriter
|
|
15
16
|
from ._single_trigger import SingleTriggerDetector
|
|
17
|
+
from ._tiff_writer import ADTIFFWriter
|
|
16
18
|
from ._utils import (
|
|
17
19
|
ADBaseDataType,
|
|
18
20
|
FileWriteMode,
|
|
@@ -26,15 +28,20 @@ from ._utils import (
|
|
|
26
28
|
|
|
27
29
|
__all__ = [
|
|
28
30
|
"ADBaseIO",
|
|
31
|
+
"AreaDetector",
|
|
29
32
|
"DetectorState",
|
|
30
33
|
"NDArrayBaseIO",
|
|
34
|
+
"NDFileIO",
|
|
31
35
|
"NDFileHDFIO",
|
|
36
|
+
"NDPluginBaseIO",
|
|
32
37
|
"NDPluginStatsIO",
|
|
33
38
|
"DEFAULT_GOOD_STATES",
|
|
34
39
|
"ADBaseDatasetDescriber",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
40
|
+
"ADBaseController",
|
|
41
|
+
"ADWriter",
|
|
37
42
|
"ADHDFWriter",
|
|
43
|
+
"ADTIFFWriter",
|
|
44
|
+
"ADJPEGWriter",
|
|
38
45
|
"SingleTriggerDetector",
|
|
39
46
|
"ADBaseDataType",
|
|
40
47
|
"FileWriteMode",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import SignalR, StandardDetector
|
|
4
|
+
|
|
5
|
+
from ._core_io import NDPluginBaseIO
|
|
6
|
+
from ._core_logic import ADBaseControllerT
|
|
7
|
+
from ._core_writer import ADWriter
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AreaDetector(StandardDetector[ADBaseControllerT, ADWriter]):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
controller: ADBaseControllerT,
|
|
14
|
+
writer: ADWriter,
|
|
15
|
+
plugins: dict[str, NDPluginBaseIO] | None = None,
|
|
16
|
+
config_sigs: Sequence[SignalR] = (),
|
|
17
|
+
name: str = "",
|
|
18
|
+
):
|
|
19
|
+
self.driver = controller.driver
|
|
20
|
+
self.fileio = writer.fileio
|
|
21
|
+
|
|
22
|
+
if plugins is not None:
|
|
23
|
+
for name, plugin in plugins.items():
|
|
24
|
+
setattr(self, name, plugin)
|
|
25
|
+
|
|
26
|
+
super().__init__(
|
|
27
|
+
controller,
|
|
28
|
+
writer,
|
|
29
|
+
(self.driver.acquire_period, self.driver.acquire_time, *config_sigs),
|
|
30
|
+
name=name,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def get_plugin(
|
|
34
|
+
self, name: str, plugin_type: type[NDPluginBaseIO] = NDPluginBaseIO
|
|
35
|
+
) -> NDPluginBaseIO:
|
|
36
|
+
plugin = getattr(self, name, None)
|
|
37
|
+
if not isinstance(plugin, plugin_type):
|
|
38
|
+
raise TypeError(
|
|
39
|
+
f"Expected {self.name}.{name} to be a {plugin_type}, got {plugin}"
|
|
40
|
+
)
|
|
41
|
+
return plugin
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
1
3
|
from ophyd_async.core import Device, StrictEnum
|
|
4
|
+
from ophyd_async.core._providers import DatasetDescriber
|
|
2
5
|
from ophyd_async.epics.core import (
|
|
3
6
|
epics_signal_r,
|
|
4
7
|
epics_signal_rw,
|
|
5
8
|
epics_signal_rw_rbv,
|
|
6
9
|
)
|
|
7
10
|
|
|
8
|
-
from ._utils import ADBaseDataType, FileWriteMode, ImageMode
|
|
11
|
+
from ._utils import ADBaseDataType, FileWriteMode, ImageMode, convert_ad_dtype_to_np
|
|
9
12
|
|
|
10
13
|
|
|
11
14
|
class Callback(StrictEnum):
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
ENABLE = "Enable"
|
|
16
|
+
DISABLE = "Disable"
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
class NDArrayBaseIO(Device):
|
|
@@ -27,6 +30,21 @@ class NDArrayBaseIO(Device):
|
|
|
27
30
|
super().__init__(name=name)
|
|
28
31
|
|
|
29
32
|
|
|
33
|
+
class ADBaseDatasetDescriber(DatasetDescriber):
|
|
34
|
+
def __init__(self, driver: NDArrayBaseIO) -> None:
|
|
35
|
+
self._driver = driver
|
|
36
|
+
|
|
37
|
+
async def np_datatype(self) -> str:
|
|
38
|
+
return convert_ad_dtype_to_np(await self._driver.data_type.get_value())
|
|
39
|
+
|
|
40
|
+
async def shape(self) -> tuple[int, int]:
|
|
41
|
+
shape = await asyncio.gather(
|
|
42
|
+
self._driver.array_size_y.get_value(),
|
|
43
|
+
self._driver.array_size_x.get_value(),
|
|
44
|
+
)
|
|
45
|
+
return shape
|
|
46
|
+
|
|
47
|
+
|
|
30
48
|
class NDPluginBaseIO(NDArrayBaseIO):
|
|
31
49
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
32
50
|
self.nd_array_port = epics_signal_rw_rbv(str, prefix + "NDArrayPort")
|
|
@@ -36,6 +54,7 @@ class NDPluginBaseIO(NDArrayBaseIO):
|
|
|
36
54
|
self.nd_array_address = epics_signal_rw_rbv(int, prefix + "NDArrayAddress")
|
|
37
55
|
self.array_size0 = epics_signal_r(int, prefix + "ArraySize0_RBV")
|
|
38
56
|
self.array_size1 = epics_signal_r(int, prefix + "ArraySize1_RBV")
|
|
57
|
+
self.queue_size = epics_signal_rw(int, prefix + "QueueSize")
|
|
39
58
|
super().__init__(prefix, name)
|
|
40
59
|
|
|
41
60
|
|
|
@@ -72,17 +91,17 @@ class DetectorState(StrictEnum):
|
|
|
72
91
|
See definition in ADApp/ADSrc/ADDriver.h in https://github.com/areaDetector/ADCore
|
|
73
92
|
"""
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
94
|
+
IDLE = "Idle"
|
|
95
|
+
ACQUIRE = "Acquire"
|
|
96
|
+
READOUT = "Readout"
|
|
97
|
+
CORRECT = "Correct"
|
|
98
|
+
SAVING = "Saving"
|
|
99
|
+
ABORTING = "Aborting"
|
|
100
|
+
ERROR = "Error"
|
|
101
|
+
WAITING = "Waiting"
|
|
102
|
+
INITIALIZING = "Initializing"
|
|
103
|
+
DISCONNECTED = "Disconnected"
|
|
104
|
+
ABORTED = "Aborted"
|
|
86
105
|
|
|
87
106
|
|
|
88
107
|
class ADBaseIO(NDArrayBaseIO):
|
|
@@ -99,40 +118,46 @@ class ADBaseIO(NDArrayBaseIO):
|
|
|
99
118
|
|
|
100
119
|
|
|
101
120
|
class Compression(StrictEnum):
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
121
|
+
NONE = "None"
|
|
122
|
+
NBIT = "N-bit"
|
|
123
|
+
SZIP = "szip"
|
|
124
|
+
ZLIB = "zlib"
|
|
125
|
+
BLOSC = "Blosc"
|
|
126
|
+
BSLZ4 = "BSLZ4"
|
|
127
|
+
LZ4 = "LZ4"
|
|
128
|
+
JPEG = "JPEG"
|
|
110
129
|
|
|
111
130
|
|
|
112
|
-
class
|
|
131
|
+
class NDFileIO(NDPluginBaseIO):
|
|
113
132
|
def __init__(self, prefix: str, name="") -> None:
|
|
114
|
-
# Define some signals
|
|
115
|
-
self.position_mode = epics_signal_rw_rbv(bool, prefix + "PositionMode")
|
|
116
|
-
self.compression = epics_signal_rw_rbv(Compression, prefix + "Compression")
|
|
117
|
-
self.num_extra_dims = epics_signal_rw_rbv(int, prefix + "NumExtraDims")
|
|
118
133
|
self.file_path = epics_signal_rw_rbv(str, prefix + "FilePath")
|
|
119
134
|
self.file_name = epics_signal_rw_rbv(str, prefix + "FileName")
|
|
120
135
|
self.file_path_exists = epics_signal_r(bool, prefix + "FilePathExists_RBV")
|
|
121
136
|
self.file_template = epics_signal_rw_rbv(str, prefix + "FileTemplate")
|
|
122
137
|
self.full_file_name = epics_signal_r(str, prefix + "FullFileName_RBV")
|
|
138
|
+
self.file_number = epics_signal_rw(int, prefix + "FileNumber")
|
|
139
|
+
self.auto_increment = epics_signal_rw(bool, prefix + "AutoIncrement")
|
|
123
140
|
self.file_write_mode = epics_signal_rw_rbv(
|
|
124
141
|
FileWriteMode, prefix + "FileWriteMode"
|
|
125
142
|
)
|
|
126
143
|
self.num_capture = epics_signal_rw_rbv(int, prefix + "NumCapture")
|
|
127
144
|
self.num_captured = epics_signal_r(int, prefix + "NumCaptured_RBV")
|
|
128
|
-
self.swmr_mode = epics_signal_rw_rbv(bool, prefix + "SWMRMode")
|
|
129
|
-
self.lazy_open = epics_signal_rw_rbv(bool, prefix + "LazyOpen")
|
|
130
145
|
self.capture = epics_signal_rw_rbv(bool, prefix + "Capture")
|
|
131
|
-
self.flush_now = epics_signal_rw(bool, prefix + "FlushNow")
|
|
132
|
-
self.xml_file_name = epics_signal_rw_rbv(str, prefix + "XMLFileName")
|
|
133
146
|
self.array_size0 = epics_signal_r(int, prefix + "ArraySize0")
|
|
134
147
|
self.array_size1 = epics_signal_r(int, prefix + "ArraySize1")
|
|
135
148
|
self.create_directory = epics_signal_rw(int, prefix + "CreateDirectory")
|
|
149
|
+
super().__init__(prefix, name)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class NDFileHDFIO(NDFileIO):
|
|
153
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
154
|
+
self.position_mode = epics_signal_rw_rbv(bool, prefix + "PositionMode")
|
|
155
|
+
self.compression = epics_signal_rw_rbv(Compression, prefix + "Compression")
|
|
156
|
+
self.num_extra_dims = epics_signal_rw_rbv(int, prefix + "NumExtraDims")
|
|
157
|
+
self.swmr_mode = epics_signal_rw_rbv(bool, prefix + "SWMRMode")
|
|
158
|
+
self.flush_now = epics_signal_rw(bool, prefix + "FlushNow")
|
|
159
|
+
self.xml_file_name = epics_signal_rw_rbv(str, prefix + "XMLFileName")
|
|
136
160
|
self.num_frames_chunks = epics_signal_r(int, prefix + "NumFramesChunks_RBV")
|
|
137
161
|
self.chunk_size_auto = epics_signal_rw_rbv(bool, prefix + "ChunkSizeAuto")
|
|
162
|
+
self.lazy_open = epics_signal_rw_rbv(bool, prefix + "LazyOpen")
|
|
138
163
|
super().__init__(prefix, name)
|