ophyd-async 0.3a3__py3-none-any.whl → 0.3a5__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 +1 -1
- ophyd_async/core/__init__.py +26 -11
- ophyd_async/core/async_status.py +96 -33
- ophyd_async/core/detector.py +22 -28
- ophyd_async/core/device.py +50 -14
- ophyd_async/core/mock_signal_backend.py +85 -0
- ophyd_async/core/mock_signal_utils.py +149 -0
- ophyd_async/core/signal.py +93 -53
- ophyd_async/core/{sim_signal_backend.py → soft_signal_backend.py} +23 -33
- ophyd_async/core/utils.py +19 -0
- ophyd_async/epics/_backend/_aioca.py +11 -7
- ophyd_async/epics/_backend/_p4p.py +11 -7
- ophyd_async/epics/_backend/common.py +17 -17
- ophyd_async/epics/areadetector/__init__.py +0 -4
- ophyd_async/epics/areadetector/aravis.py +1 -5
- ophyd_async/epics/areadetector/controllers/aravis_controller.py +6 -1
- ophyd_async/epics/areadetector/drivers/ad_base.py +12 -10
- ophyd_async/epics/areadetector/drivers/aravis_driver.py +6 -122
- ophyd_async/epics/areadetector/drivers/kinetix_driver.py +7 -4
- ophyd_async/epics/areadetector/drivers/pilatus_driver.py +5 -2
- ophyd_async/epics/areadetector/drivers/vimba_driver.py +12 -7
- ophyd_async/epics/areadetector/utils.py +2 -12
- ophyd_async/epics/areadetector/writers/nd_file_hdf.py +21 -19
- ophyd_async/epics/areadetector/writers/nd_plugin.py +6 -7
- ophyd_async/epics/demo/__init__.py +27 -32
- ophyd_async/epics/motion/motor.py +40 -37
- ophyd_async/epics/pvi/pvi.py +13 -13
- ophyd_async/epics/signal/__init__.py +8 -1
- ophyd_async/panda/_hdf_panda.py +3 -3
- ophyd_async/planstubs/__init__.py +5 -1
- ophyd_async/planstubs/ensure_connected.py +22 -0
- ophyd_async/protocols.py +32 -2
- ophyd_async/sim/demo/sim_motor.py +50 -35
- ophyd_async/sim/pattern_generator.py +5 -5
- {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a5.dist-info}/METADATA +2 -2
- {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a5.dist-info}/RECORD +40 -37
- {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a5.dist-info}/LICENSE +0 -0
- {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a5.dist-info}/WHEEL +0 -0
- {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a5.dist-info}/entry_points.txt +0 -0
- {ophyd_async-0.3a3.dist-info → ophyd_async-0.3a5.dist-info}/top_level.txt +0 -0
|
@@ -20,7 +20,7 @@ from ophyd_async.core import (
|
|
|
20
20
|
)
|
|
21
21
|
from ophyd_async.core.utils import DEFAULT_TIMEOUT, NotConnected
|
|
22
22
|
|
|
23
|
-
from .common import
|
|
23
|
+
from .common import get_supported_values
|
|
24
24
|
|
|
25
25
|
# https://mdavidsaver.github.io/p4p/values.html
|
|
26
26
|
specifier_to_dtype: Dict[str, Dtype] = {
|
|
@@ -109,7 +109,8 @@ class PvaNDArrayConverter(PvaConverter):
|
|
|
109
109
|
|
|
110
110
|
@dataclass
|
|
111
111
|
class PvaEnumConverter(PvaConverter):
|
|
112
|
-
|
|
112
|
+
def __init__(self, choices: dict[str, str]):
|
|
113
|
+
self.choices = tuple(choices.values())
|
|
113
114
|
|
|
114
115
|
def write_value(self, value: Union[Enum, str]):
|
|
115
116
|
if isinstance(value, Enum):
|
|
@@ -118,11 +119,15 @@ class PvaEnumConverter(PvaConverter):
|
|
|
118
119
|
return value
|
|
119
120
|
|
|
120
121
|
def value(self, value):
|
|
121
|
-
return
|
|
122
|
+
return self.choices[value["value"]["index"]]
|
|
122
123
|
|
|
123
124
|
def get_datakey(self, source: str, value) -> DataKey:
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
return {
|
|
126
|
+
"source": source,
|
|
127
|
+
"dtype": "string",
|
|
128
|
+
"shape": [],
|
|
129
|
+
"choices": list(self.choices),
|
|
130
|
+
}
|
|
126
131
|
|
|
127
132
|
|
|
128
133
|
class PvaEnumBoolConverter(PvaConverter):
|
|
@@ -214,7 +219,7 @@ def make_converter(datatype: Optional[Type], values: Dict[str, Any]) -> PvaConve
|
|
|
214
219
|
pv_choices = get_unique(
|
|
215
220
|
{k: tuple(v["value"]["choices"]) for k, v in values.items()}, "choices"
|
|
216
221
|
)
|
|
217
|
-
return PvaEnumConverter(
|
|
222
|
+
return PvaEnumConverter(get_supported_values(pv, datatype, pv_choices))
|
|
218
223
|
elif "NTScalar" in typeid:
|
|
219
224
|
if (
|
|
220
225
|
datatype
|
|
@@ -244,7 +249,6 @@ class PvaSignalBackend(SignalBackend[T]):
|
|
|
244
249
|
self.converter: PvaConverter = DisconnectedPvaConverter()
|
|
245
250
|
self.subscription: Optional[Subscription] = None
|
|
246
251
|
|
|
247
|
-
@property
|
|
248
252
|
def source(self, name: str):
|
|
249
253
|
return f"pva://{self.read_pv}"
|
|
250
254
|
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Dict, Optional, Tuple, Type
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def
|
|
5
|
+
def get_supported_values(
|
|
6
6
|
pv: str,
|
|
7
|
-
datatype: Optional[Type[
|
|
8
|
-
pv_choices: Tuple[
|
|
9
|
-
) ->
|
|
7
|
+
datatype: Optional[Type[str]],
|
|
8
|
+
pv_choices: Tuple[str, ...],
|
|
9
|
+
) -> Dict[str, str]:
|
|
10
10
|
if not datatype:
|
|
11
|
-
return
|
|
11
|
+
return {x: x or "_" for x in pv_choices}
|
|
12
12
|
|
|
13
|
-
if not issubclass(datatype, Enum):
|
|
14
|
-
raise TypeError(f"{pv} has type Enum not {datatype.__name__}")
|
|
15
13
|
if not issubclass(datatype, str):
|
|
16
|
-
raise TypeError(f"{pv}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
(
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
raise TypeError(f"{pv} is type Enum but doesn't inherit from String")
|
|
15
|
+
if issubclass(datatype, Enum):
|
|
16
|
+
choices = tuple(v.value for v in datatype)
|
|
17
|
+
if set(choices) != set(pv_choices):
|
|
18
|
+
raise TypeError(
|
|
19
|
+
(
|
|
20
|
+
f"{pv} has choices {pv_choices}, "
|
|
21
|
+
f"which do not match {datatype}, which has {choices}"
|
|
22
|
+
)
|
|
23
23
|
)
|
|
24
|
-
)
|
|
25
|
-
return
|
|
24
|
+
return {x: datatype(x) for x in pv_choices}
|
|
25
|
+
return {x: x for x in pv_choices}
|
|
@@ -7,8 +7,6 @@ from .utils import (
|
|
|
7
7
|
ImageMode,
|
|
8
8
|
NDAttributeDataType,
|
|
9
9
|
NDAttributesXML,
|
|
10
|
-
ad_r,
|
|
11
|
-
ad_rw,
|
|
12
10
|
)
|
|
13
11
|
from .vimba import VimbaDetector
|
|
14
12
|
|
|
@@ -19,8 +17,6 @@ __all__ = [
|
|
|
19
17
|
"SingleTriggerDet",
|
|
20
18
|
"FileWriteMode",
|
|
21
19
|
"ImageMode",
|
|
22
|
-
"ad_r",
|
|
23
|
-
"ad_rw",
|
|
24
20
|
"NDAttributeDataType",
|
|
25
21
|
"NDAttributesXML",
|
|
26
22
|
"PilatusDetector",
|
|
@@ -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 DirectoryProvider, StandardDetector
|
|
6
6
|
from ophyd_async.epics.areadetector.controllers.aravis_controller import (
|
|
7
7
|
AravisController,
|
|
8
8
|
)
|
|
@@ -45,10 +45,6 @@ class AravisDetector(StandardDetector, HasHints):
|
|
|
45
45
|
name=name,
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
-
async def _prepare(self, value: TriggerInfo) -> None:
|
|
49
|
-
await self.drv.fetch_deadtime()
|
|
50
|
-
await super()._prepare(value)
|
|
51
|
-
|
|
52
48
|
def get_external_trigger_gpio(self):
|
|
53
49
|
return self._controller.gpio_number
|
|
54
50
|
|
|
@@ -14,6 +14,11 @@ from ophyd_async.epics.areadetector.drivers.aravis_driver import (
|
|
|
14
14
|
)
|
|
15
15
|
from ophyd_async.epics.areadetector.utils import ImageMode, stop_busy_record
|
|
16
16
|
|
|
17
|
+
# The deadtime of an ADaravis controller varies depending on the exact model of camera.
|
|
18
|
+
# Ideally we would maximize performance by dynamically retrieving the deadtime at
|
|
19
|
+
# runtime. See https://github.com/bluesky/ophyd-async/issues/308
|
|
20
|
+
_HIGHEST_POSSIBLE_DEADTIME = 1961e-6
|
|
21
|
+
|
|
17
22
|
|
|
18
23
|
class AravisController(DetectorControl):
|
|
19
24
|
GPIO_NUMBER = Literal[1, 2, 3, 4]
|
|
@@ -23,7 +28,7 @@ class AravisController(DetectorControl):
|
|
|
23
28
|
self.gpio_number = gpio_number
|
|
24
29
|
|
|
25
30
|
def get_deadtime(self, exposure: float) -> float:
|
|
26
|
-
return
|
|
31
|
+
return _HIGHEST_POSSIBLE_DEADTIME
|
|
27
32
|
|
|
28
33
|
async def arm(
|
|
29
34
|
self,
|
|
@@ -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
|
|
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 =
|
|
47
|
-
self.acquire_time =
|
|
48
|
-
self.num_images =
|
|
49
|
-
self.image_mode =
|
|
50
|
-
self.array_counter =
|
|
51
|
-
self.array_size_x =
|
|
52
|
-
self.array_size_y =
|
|
53
|
-
self.detector_state =
|
|
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)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Literal
|
|
3
3
|
|
|
4
4
|
from ophyd_async.epics.areadetector.drivers import ADBase
|
|
5
|
-
from ophyd_async.epics.
|
|
5
|
+
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class AravisTriggerMode(str, Enum):
|
|
@@ -22,113 +22,6 @@ class AravisTriggerMode(str, Enum):
|
|
|
22
22
|
AravisTriggerSource = Literal["Freerun", "Line1", "Line2", "Line3", "Line4"]
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def _reverse_lookup(
|
|
26
|
-
model_deadtimes: Dict[float, Tuple[str, ...]],
|
|
27
|
-
) -> Callable[[str], float]:
|
|
28
|
-
def inner(pixel_format: str, model_name: str) -> float:
|
|
29
|
-
for deadtime, pixel_formats in model_deadtimes.items():
|
|
30
|
-
if pixel_format in pixel_formats:
|
|
31
|
-
return deadtime
|
|
32
|
-
raise ValueError(
|
|
33
|
-
f"Model {model_name} does not have a defined deadtime "
|
|
34
|
-
f"for pixel format {pixel_format}"
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
return inner
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
_deadtimes: Dict[str, Callable[[str, str], float]] = {
|
|
41
|
-
# cite: https://cdn.alliedvision.com/fileadmin/content/documents/products/cameras/Manta/techman/Manta_TechMan.pdf retrieved 2024-04-05 # noqa: E501
|
|
42
|
-
"Manta G-125": lambda _, __: 63e-6,
|
|
43
|
-
"Manta G-145": lambda _, __: 106e-6,
|
|
44
|
-
"Manta G-235": _reverse_lookup(
|
|
45
|
-
{
|
|
46
|
-
118e-6: (
|
|
47
|
-
"Mono8",
|
|
48
|
-
"Mono12Packed",
|
|
49
|
-
"BayerRG8",
|
|
50
|
-
"BayerRG12",
|
|
51
|
-
"BayerRG12Packed",
|
|
52
|
-
"YUV411Packed",
|
|
53
|
-
),
|
|
54
|
-
256e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
|
|
55
|
-
390e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
|
|
56
|
-
}
|
|
57
|
-
),
|
|
58
|
-
"Manta G-895": _reverse_lookup(
|
|
59
|
-
{
|
|
60
|
-
404e-6: (
|
|
61
|
-
"Mono8",
|
|
62
|
-
"Mono12Packed",
|
|
63
|
-
"BayerRG8",
|
|
64
|
-
"BayerRG12Packed",
|
|
65
|
-
"YUV411Packed",
|
|
66
|
-
),
|
|
67
|
-
542e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
|
|
68
|
-
822e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
|
|
69
|
-
}
|
|
70
|
-
),
|
|
71
|
-
"Manta G-2460": _reverse_lookup(
|
|
72
|
-
{
|
|
73
|
-
979e-6: (
|
|
74
|
-
"Mono8",
|
|
75
|
-
"Mono12Packed",
|
|
76
|
-
"BayerRG8",
|
|
77
|
-
"BayerRG12Packed",
|
|
78
|
-
"YUV411Packed",
|
|
79
|
-
),
|
|
80
|
-
1304e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
|
|
81
|
-
1961e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
|
|
82
|
-
}
|
|
83
|
-
),
|
|
84
|
-
# cite: https://cdn.alliedvision.com/fileadmin/content/documents/products/cameras/various/appnote/GigE/GigE-Cameras_AppNote_PIV-Min-Time-Between-Exposures.pdf retrieved 2024-04-05 # noqa: E501
|
|
85
|
-
"Manta G-609": lambda _, __: 47e-6,
|
|
86
|
-
# cite: https://cdn.alliedvision.com/fileadmin/content/documents/products/cameras/Mako/techman/Mako_TechMan_en.pdf retrieved 2024-04-05 # noqa: E501
|
|
87
|
-
"Mako G-040": _reverse_lookup(
|
|
88
|
-
{
|
|
89
|
-
101e-6: (
|
|
90
|
-
"Mono8",
|
|
91
|
-
"Mono12Packed",
|
|
92
|
-
"BayerRG8",
|
|
93
|
-
"BayerRG12Packed",
|
|
94
|
-
"YUV411Packed",
|
|
95
|
-
),
|
|
96
|
-
140e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
|
|
97
|
-
217e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
|
|
98
|
-
}
|
|
99
|
-
),
|
|
100
|
-
"Mako G-125": lambda _, __: 70e-6,
|
|
101
|
-
# Assume 12 bits: 10 bits = 275e-6
|
|
102
|
-
"Mako G-234": _reverse_lookup(
|
|
103
|
-
{
|
|
104
|
-
356e-6: (
|
|
105
|
-
"Mono8",
|
|
106
|
-
"BayerRG8",
|
|
107
|
-
"BayerRG12",
|
|
108
|
-
"BayerRG12Packed",
|
|
109
|
-
"YUV411Packed",
|
|
110
|
-
"YUV422Packed",
|
|
111
|
-
),
|
|
112
|
-
# Assume 12 bits: 10 bits = 563e-6
|
|
113
|
-
726e-6: ("RGB8Packed", "BRG8Packed", "YUV444Packed"),
|
|
114
|
-
}
|
|
115
|
-
),
|
|
116
|
-
"Mako G-507": _reverse_lookup(
|
|
117
|
-
{
|
|
118
|
-
270e-6: (
|
|
119
|
-
"Mono8",
|
|
120
|
-
"Mono12Packed",
|
|
121
|
-
"BayerRG8",
|
|
122
|
-
"BayerRG12Packed",
|
|
123
|
-
"YUV411Packed",
|
|
124
|
-
),
|
|
125
|
-
363e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
|
|
126
|
-
554e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
|
|
127
|
-
}
|
|
128
|
-
),
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
25
|
class AravisDriver(ADBase):
|
|
133
26
|
# If instantiating a new instance, ensure it is supported in the _deadtimes dict
|
|
134
27
|
"""Generic Driver supporting the Manta and Mako drivers.
|
|
@@ -138,17 +31,8 @@ class AravisDriver(ADBase):
|
|
|
138
31
|
"""
|
|
139
32
|
|
|
140
33
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
141
|
-
self.trigger_mode =
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
self.
|
|
145
|
-
self.dead_time: Optional[float] = None
|
|
34
|
+
self.trigger_mode = epics_signal_rw_rbv(
|
|
35
|
+
AravisTriggerMode, prefix + "TriggerMode"
|
|
36
|
+
)
|
|
37
|
+
self.trigger_source = epics_signal_rw_rbv(str, prefix + "TriggerSource")
|
|
146
38
|
super().__init__(prefix, name=name)
|
|
147
|
-
|
|
148
|
-
async def fetch_deadtime(self) -> None:
|
|
149
|
-
# All known in-use version B/C have same deadtime as non-B/C
|
|
150
|
-
model: str = (await self.model.get_value()).removesuffix("B").removesuffix("C")
|
|
151
|
-
if model not in _deadtimes:
|
|
152
|
-
raise ValueError(f"Model {model} does not have defined deadtimes")
|
|
153
|
-
pixel_format: str = await self.pixel_format.get_value()
|
|
154
|
-
self.dead_time = _deadtimes.get(model)(pixel_format, model)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
|
|
4
|
+
|
|
4
5
|
from .ad_base import ADBase
|
|
5
6
|
|
|
6
7
|
|
|
@@ -18,7 +19,9 @@ class KinetixReadoutMode(str, Enum):
|
|
|
18
19
|
|
|
19
20
|
class KinetixDriver(ADBase):
|
|
20
21
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
21
|
-
# self.pixel_format =
|
|
22
|
-
self.trigger_mode =
|
|
23
|
-
|
|
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")
|
|
24
27
|
super().__init__(prefix, name)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
-
from
|
|
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 =
|
|
18
|
+
self.trigger_mode = epics_signal_rw_rbv(
|
|
19
|
+
PilatusTriggerMode, prefix + "TriggerMode"
|
|
20
|
+
)
|
|
18
21
|
super().__init__(prefix, name)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
|
|
4
|
+
|
|
4
5
|
from .ad_base import ADBase
|
|
5
6
|
|
|
6
7
|
|
|
@@ -47,12 +48,16 @@ class VimbaExposeOutMode(str, Enum):
|
|
|
47
48
|
|
|
48
49
|
class VimbaDriver(ADBase):
|
|
49
50
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
50
|
-
# self.pixel_format =
|
|
51
|
-
self.convert_format =
|
|
51
|
+
# self.pixel_format = epics_signal_rw_rbv(PixelFormat, prefix + "PixelFormat")
|
|
52
|
+
self.convert_format = epics_signal_rw_rbv(
|
|
52
53
|
VimbaConvertFormat, prefix + "ConvertPixelFormat"
|
|
53
54
|
) # Pixel format of data outputted to AD
|
|
54
|
-
self.trig_source =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
self.
|
|
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
|
+
)
|
|
58
63
|
super().__init__(prefix, name)
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Optional
|
|
3
3
|
from xml.etree import cElementTree as ET
|
|
4
4
|
|
|
5
|
-
from ophyd_async.core import DEFAULT_TIMEOUT,
|
|
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):
|
|
@@ -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
|
|
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,22 +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 =
|
|
23
|
-
self.compression =
|
|
24
|
-
self.num_extra_dims =
|
|
25
|
-
self.file_path =
|
|
26
|
-
self.file_name =
|
|
27
|
-
self.file_path_exists =
|
|
28
|
-
self.file_template =
|
|
29
|
-
self.full_file_name =
|
|
30
|
-
self.file_write_mode =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
self.
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
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 =
|
|
38
|
-
self.array_size1 =
|
|
39
|
-
self.xml_file_name =
|
|
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")
|
|
40
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 =
|
|
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 =
|
|
24
|
-
self.enable_callback =
|
|
25
|
-
self.nd_array_address =
|
|
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
|
|
|
@@ -6,23 +6,23 @@ import random
|
|
|
6
6
|
import string
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
|
-
import
|
|
9
|
+
from dataclasses import replace
|
|
10
10
|
from enum import Enum
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Callable, List, Optional
|
|
13
12
|
|
|
14
13
|
import numpy as np
|
|
15
14
|
from bluesky.protocols import Movable, Stoppable
|
|
16
15
|
|
|
17
16
|
from ophyd_async.core import (
|
|
18
|
-
AsyncStatus,
|
|
19
17
|
ConfigSignal,
|
|
20
18
|
Device,
|
|
21
19
|
DeviceVector,
|
|
22
20
|
HintedSignal,
|
|
23
21
|
StandardReadable,
|
|
22
|
+
WatchableAsyncStatus,
|
|
24
23
|
observe_value,
|
|
25
24
|
)
|
|
25
|
+
from ophyd_async.core.utils import WatcherUpdate
|
|
26
26
|
|
|
27
27
|
from ..signal.signal import epics_signal_r, epics_signal_rw, epics_signal_x
|
|
28
28
|
|
|
@@ -85,46 +85,41 @@ class Mover(StandardReadable, Movable, Stoppable):
|
|
|
85
85
|
# Readback should be named the same as its parent in read()
|
|
86
86
|
self.readback.set_name(name)
|
|
87
87
|
|
|
88
|
-
async def _move(self, new_position: float
|
|
88
|
+
async def _move(self, new_position: float):
|
|
89
89
|
self._set_success = True
|
|
90
90
|
# time.monotonic won't go backwards in case of NTP corrections
|
|
91
|
-
start = time.monotonic()
|
|
92
91
|
old_position, units, precision = await asyncio.gather(
|
|
93
92
|
self.setpoint.get_value(),
|
|
94
93
|
self.units.get_value(),
|
|
95
94
|
self.precision.get_value(),
|
|
96
95
|
)
|
|
97
96
|
# Wait for the value to set, but don't wait for put completion callback
|
|
98
|
-
|
|
99
|
-
async for current_position in observe_value(self.readback):
|
|
100
|
-
for watcher in watchers:
|
|
101
|
-
watcher(
|
|
102
|
-
name=self.name,
|
|
103
|
-
current=current_position,
|
|
104
|
-
initial=old_position,
|
|
105
|
-
target=new_position,
|
|
106
|
-
unit=units,
|
|
107
|
-
precision=precision,
|
|
108
|
-
time_elapsed=time.monotonic() - start,
|
|
109
|
-
)
|
|
110
|
-
if np.isclose(current_position, new_position):
|
|
111
|
-
break
|
|
97
|
+
move_status = self.setpoint.set(new_position, wait=True)
|
|
112
98
|
if not self._set_success:
|
|
113
99
|
raise RuntimeError("Motor was stopped")
|
|
100
|
+
# return a template to set() which it can use to yield progress updates
|
|
101
|
+
return (
|
|
102
|
+
WatcherUpdate(
|
|
103
|
+
initial=old_position,
|
|
104
|
+
current=old_position,
|
|
105
|
+
target=new_position,
|
|
106
|
+
unit=units,
|
|
107
|
+
precision=precision,
|
|
108
|
+
),
|
|
109
|
+
move_status,
|
|
110
|
+
)
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
coro = asyncio.wait_for(self._move(new_position, watchers), timeout=timeout)
|
|
127
|
-
return AsyncStatus(coro, watchers)
|
|
112
|
+
@WatchableAsyncStatus.wrap # uses the timeout argument from the function it wraps
|
|
113
|
+
async def set(self, new_position: float, timeout: float | None = None):
|
|
114
|
+
update, _ = await self._move(new_position)
|
|
115
|
+
async for current_position in observe_value(self.readback):
|
|
116
|
+
yield replace(
|
|
117
|
+
update,
|
|
118
|
+
name=self.name,
|
|
119
|
+
current=current_position,
|
|
120
|
+
)
|
|
121
|
+
if np.isclose(current_position, new_position):
|
|
122
|
+
break
|
|
128
123
|
|
|
129
124
|
async def stop(self, success=True):
|
|
130
125
|
self._set_success = success
|