ophyd-async 0.3a1__py3-none-any.whl → 0.3a3__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/__init__.py +1 -4
- ophyd_async/_version.py +1 -1
- ophyd_async/core/__init__.py +23 -3
- ophyd_async/core/_providers.py +3 -1
- ophyd_async/core/detector.py +72 -46
- ophyd_async/core/device.py +8 -0
- ophyd_async/core/flyer.py +12 -21
- ophyd_async/core/signal.py +134 -20
- ophyd_async/core/signal_backend.py +6 -3
- ophyd_async/core/sim_signal_backend.py +32 -20
- ophyd_async/core/standard_readable.py +212 -23
- ophyd_async/core/utils.py +18 -1
- ophyd_async/epics/_backend/_aioca.py +17 -15
- ophyd_async/epics/_backend/_p4p.py +34 -25
- ophyd_async/epics/_backend/common.py +16 -11
- ophyd_async/epics/areadetector/__init__.py +8 -0
- ophyd_async/epics/areadetector/aravis.py +67 -0
- ophyd_async/epics/areadetector/controllers/__init__.py +2 -1
- ophyd_async/epics/areadetector/controllers/aravis_controller.py +73 -0
- ophyd_async/epics/areadetector/controllers/kinetix_controller.py +49 -0
- ophyd_async/epics/areadetector/controllers/pilatus_controller.py +36 -24
- ophyd_async/epics/areadetector/controllers/vimba_controller.py +66 -0
- ophyd_async/epics/areadetector/drivers/__init__.py +6 -0
- ophyd_async/epics/areadetector/drivers/aravis_driver.py +154 -0
- ophyd_async/epics/areadetector/drivers/kinetix_driver.py +24 -0
- ophyd_async/epics/areadetector/drivers/pilatus_driver.py +4 -4
- ophyd_async/epics/areadetector/drivers/vimba_driver.py +58 -0
- ophyd_async/epics/areadetector/kinetix.py +46 -0
- ophyd_async/epics/areadetector/pilatus.py +45 -0
- ophyd_async/epics/areadetector/single_trigger_det.py +14 -6
- ophyd_async/epics/areadetector/vimba.py +43 -0
- ophyd_async/epics/areadetector/writers/_hdffile.py +4 -4
- ophyd_async/epics/areadetector/writers/hdf_writer.py +12 -4
- ophyd_async/epics/areadetector/writers/nd_file_hdf.py +1 -0
- ophyd_async/epics/demo/__init__.py +45 -18
- ophyd_async/epics/motion/motor.py +24 -19
- ophyd_async/epics/pvi/__init__.py +3 -0
- ophyd_async/epics/pvi/pvi.py +318 -0
- ophyd_async/epics/signal/signal.py +26 -9
- ophyd_async/log.py +130 -0
- ophyd_async/panda/__init__.py +17 -6
- ophyd_async/panda/_common_blocks.py +49 -0
- ophyd_async/panda/_hdf_panda.py +48 -0
- ophyd_async/panda/{panda_controller.py → _panda_controller.py} +3 -7
- ophyd_async/panda/_trigger.py +39 -0
- ophyd_async/panda/writers/__init__.py +3 -0
- ophyd_async/panda/writers/_hdf_writer.py +220 -0
- ophyd_async/panda/writers/_panda_hdf_file.py +58 -0
- ophyd_async/planstubs/__init__.py +5 -0
- ophyd_async/planstubs/prepare_trigger_and_dets.py +57 -0
- ophyd_async/protocols.py +96 -0
- ophyd_async/sim/__init__.py +11 -0
- ophyd_async/sim/demo/__init__.py +3 -0
- ophyd_async/sim/demo/sim_motor.py +118 -0
- ophyd_async/sim/pattern_generator.py +318 -0
- ophyd_async/sim/sim_pattern_detector_control.py +55 -0
- ophyd_async/sim/sim_pattern_detector_writer.py +34 -0
- ophyd_async/sim/sim_pattern_generator.py +37 -0
- {ophyd_async-0.3a1.dist-info → ophyd_async-0.3a3.dist-info}/METADATA +30 -69
- ophyd_async-0.3a3.dist-info/RECORD +83 -0
- ophyd_async/epics/pvi.py +0 -70
- ophyd_async/panda/panda.py +0 -241
- ophyd_async-0.3a1.dist-info/RECORD +0 -56
- /ophyd_async/panda/{table.py → _table.py} +0 -0
- /ophyd_async/panda/{utils.py → _utils.py} +0 -0
- {ophyd_async-0.3a1.dist-info → ophyd_async-0.3a3.dist-info}/LICENSE +0 -0
- {ophyd_async-0.3a1.dist-info → ophyd_async-0.3a3.dist-info}/WHEEL +0 -0
- {ophyd_async-0.3a1.dist-info → ophyd_async-0.3a3.dist-info}/entry_points.txt +0 -0
- {ophyd_async-0.3a1.dist-info → ophyd_async-0.3a3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from ..utils import ad_rw
|
|
4
|
+
from .ad_base import ADBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class VimbaPixelFormat(str, Enum):
|
|
8
|
+
internal = "Mono8"
|
|
9
|
+
ext_enable = "Mono12"
|
|
10
|
+
ext_trigger = "Ext. Trigger"
|
|
11
|
+
mult_trigger = "Mult. Trigger"
|
|
12
|
+
alignment = "Alignment"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class VimbaConvertFormat(str, Enum):
|
|
16
|
+
none = "None"
|
|
17
|
+
mono8 = "Mono8"
|
|
18
|
+
mono16 = "Mono16"
|
|
19
|
+
rgb8 = "RGB8"
|
|
20
|
+
rgb16 = "RGB16"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class VimbaTriggerSource(str, Enum):
|
|
24
|
+
freerun = "Freerun"
|
|
25
|
+
line1 = "Line1"
|
|
26
|
+
line2 = "Line2"
|
|
27
|
+
fixed_rate = "FixedRate"
|
|
28
|
+
software = "Software"
|
|
29
|
+
action0 = "Action0"
|
|
30
|
+
action1 = "Action1"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class VimbaOverlap(str, Enum):
|
|
34
|
+
off = "Off"
|
|
35
|
+
prev_frame = "PreviousFrame"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class VimbaOnOff(str, Enum):
|
|
39
|
+
on = "On"
|
|
40
|
+
off = "Off"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class VimbaExposeOutMode(str, Enum):
|
|
44
|
+
timed = "Timed" # Use ExposureTime PV
|
|
45
|
+
trigger_width = "TriggerWidth" # Expose for length of high signal
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class VimbaDriver(ADBase):
|
|
49
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
50
|
+
# self.pixel_format = ad_rw(PixelFormat, prefix + "PixelFormat")
|
|
51
|
+
self.convert_format = ad_rw(
|
|
52
|
+
VimbaConvertFormat, prefix + "ConvertPixelFormat"
|
|
53
|
+
) # Pixel format of data outputted to AD
|
|
54
|
+
self.trig_source = ad_rw(VimbaTriggerSource, prefix + "TriggerSource")
|
|
55
|
+
self.trigger_mode = ad_rw(VimbaOnOff, prefix + "TriggerMode")
|
|
56
|
+
self.overlap = ad_rw(VimbaOverlap, prefix + "TriggerOverlap")
|
|
57
|
+
self.expose_mode = ad_rw(VimbaExposeOutMode, prefix + "ExposureMode")
|
|
58
|
+
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
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from bluesky.protocols import Hints
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import DirectoryProvider
|
|
4
|
+
from ophyd_async.core.detector import StandardDetector
|
|
5
|
+
from ophyd_async.epics.areadetector.controllers.pilatus_controller import (
|
|
6
|
+
PilatusController,
|
|
7
|
+
)
|
|
8
|
+
from ophyd_async.epics.areadetector.drivers.ad_base import ADBaseShapeProvider
|
|
9
|
+
from ophyd_async.epics.areadetector.drivers.pilatus_driver import PilatusDriver
|
|
10
|
+
from ophyd_async.epics.areadetector.writers.hdf_writer import HDFWriter
|
|
11
|
+
from ophyd_async.epics.areadetector.writers.nd_file_hdf import NDFileHDF
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PilatusDetector(StandardDetector):
|
|
15
|
+
"""A Pilatus StandardDetector writing HDF files"""
|
|
16
|
+
|
|
17
|
+
_controller: PilatusController
|
|
18
|
+
_writer: HDFWriter
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
prefix: str,
|
|
23
|
+
directory_provider: DirectoryProvider,
|
|
24
|
+
drv_suffix="cam1:",
|
|
25
|
+
hdf_suffix="HDF1:",
|
|
26
|
+
name="",
|
|
27
|
+
):
|
|
28
|
+
self.drv = PilatusDriver(prefix + drv_suffix)
|
|
29
|
+
self.hdf = NDFileHDF(prefix + hdf_suffix)
|
|
30
|
+
|
|
31
|
+
super().__init__(
|
|
32
|
+
PilatusController(self.drv),
|
|
33
|
+
HDFWriter(
|
|
34
|
+
self.hdf,
|
|
35
|
+
directory_provider,
|
|
36
|
+
lambda: self.name,
|
|
37
|
+
ADBaseShapeProvider(self.drv),
|
|
38
|
+
),
|
|
39
|
+
config_sigs=(self.drv.acquire_time,),
|
|
40
|
+
name=name,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def hints(self) -> Hints:
|
|
45
|
+
return self._writer.hints
|
|
@@ -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
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
@@ -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
|
|
@@ -44,10 +44,10 @@ class _HDFFile:
|
|
|
44
44
|
def stream_data(self, indices_written: int) -> Iterator[StreamDatum]:
|
|
45
45
|
# Indices are relative to resource
|
|
46
46
|
if indices_written > self._last_emitted:
|
|
47
|
-
indices =
|
|
48
|
-
start
|
|
49
|
-
stop
|
|
50
|
-
|
|
47
|
+
indices = {
|
|
48
|
+
"start": self._last_emitted,
|
|
49
|
+
"stop": indices_written,
|
|
50
|
+
}
|
|
51
51
|
self._last_emitted = indices_written
|
|
52
52
|
for bundle in self._bundles:
|
|
53
53
|
yield bundle.compose_stream_datum(indices)
|
|
@@ -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
|
|
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,
|
|
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:
|
|
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",
|
|
@@ -109,12 +112,17 @@ class HDFWriter(DetectorWriter):
|
|
|
109
112
|
await self.hdf.flush_now.set(True)
|
|
110
113
|
if indices_written:
|
|
111
114
|
if not self._file:
|
|
115
|
+
path = Path(await self.hdf.full_file_name.get_value())
|
|
112
116
|
self._file = _HDFFile(
|
|
113
117
|
self._directory_provider(),
|
|
114
118
|
# See https://github.com/bluesky/ophyd-async/issues/122
|
|
115
|
-
|
|
119
|
+
path,
|
|
116
120
|
self._datasets,
|
|
117
121
|
)
|
|
122
|
+
# stream resource says "here is a dataset",
|
|
123
|
+
# stream datum says "here are N frames in that stream resource",
|
|
124
|
+
# you get one stream resource and many stream datums per scan
|
|
125
|
+
|
|
118
126
|
for doc in self._file.stream_resources():
|
|
119
127
|
yield "stream_resource", doc
|
|
120
128
|
for doc in self._file.stream_data(indices_written):
|
|
@@ -36,4 +36,5 @@ class NDFileHDF(NDPluginBase):
|
|
|
36
36
|
self.flush_now = epics_signal_rw(bool, prefix + "FlushNow")
|
|
37
37
|
self.array_size0 = ad_r(int, prefix + "ArraySize0")
|
|
38
38
|
self.array_size1 = ad_r(int, prefix + "ArraySize1")
|
|
39
|
+
self.xml_file_name = ad_rw(str, prefix + "XMLFileName")
|
|
39
40
|
super().__init__(prefix, name)
|
|
@@ -14,7 +14,15 @@ from typing import Callable, List, Optional
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
from bluesky.protocols import Movable, Stoppable
|
|
16
16
|
|
|
17
|
-
from ophyd_async.core import
|
|
17
|
+
from ophyd_async.core import (
|
|
18
|
+
AsyncStatus,
|
|
19
|
+
ConfigSignal,
|
|
20
|
+
Device,
|
|
21
|
+
DeviceVector,
|
|
22
|
+
HintedSignal,
|
|
23
|
+
StandardReadable,
|
|
24
|
+
observe_value,
|
|
25
|
+
)
|
|
18
26
|
|
|
19
27
|
from ..signal.signal import epics_signal_r, epics_signal_rw, epics_signal_x
|
|
20
28
|
|
|
@@ -33,35 +41,43 @@ class Sensor(StandardReadable):
|
|
|
33
41
|
|
|
34
42
|
def __init__(self, prefix: str, name="") -> None:
|
|
35
43
|
# Define some signals
|
|
36
|
-
self.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
config=[self.mode],
|
|
42
|
-
)
|
|
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
|
+
|
|
43
49
|
super().__init__(name=name)
|
|
44
50
|
|
|
45
51
|
|
|
52
|
+
class SensorGroup(StandardReadable):
|
|
53
|
+
def __init__(self, prefix: str, name: str = "", sensor_count: int = 3) -> None:
|
|
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
|
+
)
|
|
58
|
+
|
|
59
|
+
super().__init__(name)
|
|
60
|
+
|
|
61
|
+
|
|
46
62
|
class Mover(StandardReadable, Movable, Stoppable):
|
|
47
63
|
"""A demo movable that moves based on velocity"""
|
|
48
64
|
|
|
49
65
|
def __init__(self, prefix: str, name="") -> None:
|
|
50
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
|
+
|
|
51
74
|
self.setpoint = epics_signal_rw(float, prefix + "Setpoint")
|
|
52
|
-
self.readback = epics_signal_r(float, prefix + "Readback")
|
|
53
|
-
self.velocity = epics_signal_rw(float, prefix + "Velocity")
|
|
54
|
-
self.units = epics_signal_r(str, prefix + "Readback.EGU")
|
|
55
75
|
self.precision = epics_signal_r(int, prefix + "Readback.PREC")
|
|
56
76
|
# Signals that collide with standard methods should have a trailing underscore
|
|
57
77
|
self.stop_ = epics_signal_x(prefix + "Stop.PROC")
|
|
58
78
|
# Whether set() should complete successfully or not
|
|
59
79
|
self._set_success = True
|
|
60
|
-
|
|
61
|
-
self.set_readable_signals(
|
|
62
|
-
read=[self.readback],
|
|
63
|
-
config=[self.velocity, self.units],
|
|
64
|
-
)
|
|
80
|
+
|
|
65
81
|
super().__init__(name=name)
|
|
66
82
|
|
|
67
83
|
def set_name(self, name: str):
|
|
@@ -135,11 +151,22 @@ def start_ioc_subprocess() -> str:
|
|
|
135
151
|
pv_prefix = "".join(random.choice(string.ascii_uppercase) for _ in range(12)) + ":"
|
|
136
152
|
here = Path(__file__).absolute().parent
|
|
137
153
|
args = [sys.executable, "-m", "epicscorelibs.ioc"]
|
|
154
|
+
|
|
155
|
+
# Create standalone sensor
|
|
138
156
|
args += ["-m", f"P={pv_prefix}"]
|
|
139
157
|
args += ["-d", str(here / "sensor.db")]
|
|
140
|
-
|
|
141
|
-
|
|
158
|
+
|
|
159
|
+
# Create sensor group
|
|
160
|
+
for suffix in ["1", "2", "3"]:
|
|
161
|
+
args += ["-m", f"P={pv_prefix}{suffix}:"]
|
|
162
|
+
args += ["-d", str(here / "sensor.db")]
|
|
163
|
+
|
|
164
|
+
# Create X and Y motors
|
|
165
|
+
for suffix in ["X", "Y"]:
|
|
166
|
+
args += ["-m", f"P={pv_prefix}{suffix}:"]
|
|
142
167
|
args += ["-d", str(here / "mover.db")]
|
|
168
|
+
|
|
169
|
+
# Start IOC
|
|
143
170
|
process = subprocess.Popen(
|
|
144
171
|
args,
|
|
145
172
|
stdin=subprocess.PIPE,
|
|
@@ -4,7 +4,7 @@ from typing import Callable, List, Optional
|
|
|
4
4
|
|
|
5
5
|
from bluesky.protocols import Movable, Stoppable
|
|
6
6
|
|
|
7
|
-
from ophyd_async.core import AsyncStatus, StandardReadable
|
|
7
|
+
from ophyd_async.core import AsyncStatus, ConfigSignal, HintedSignal, StandardReadable
|
|
8
8
|
|
|
9
9
|
from ..signal.signal import epics_signal_r, epics_signal_rw, epics_signal_x
|
|
10
10
|
|
|
@@ -14,33 +14,38 @@ class Motor(StandardReadable, Movable, Stoppable):
|
|
|
14
14
|
|
|
15
15
|
def __init__(self, prefix: str, name="") -> None:
|
|
16
16
|
# Define some signals
|
|
17
|
-
self.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
with self.add_children_as_readables(ConfigSignal):
|
|
18
|
+
self.motor_egu = epics_signal_r(str, prefix + ".EGU")
|
|
19
|
+
self.velocity = epics_signal_rw(float, prefix + ".VELO")
|
|
20
|
+
|
|
21
|
+
with self.add_children_as_readables(HintedSignal):
|
|
22
|
+
self.user_readback = epics_signal_r(float, prefix + ".RBV")
|
|
23
|
+
|
|
24
|
+
self.user_setpoint = epics_signal_rw(float, prefix + ".VAL")
|
|
25
|
+
self.max_velocity = epics_signal_r(float, prefix + ".VMAX")
|
|
26
|
+
self.acceleration_time = epics_signal_rw(float, prefix + ".ACCL")
|
|
21
27
|
self.precision = epics_signal_r(int, prefix + ".PREC")
|
|
22
|
-
|
|
23
|
-
self.
|
|
28
|
+
self.deadband = epics_signal_r(float, prefix + ".RDBD")
|
|
29
|
+
self.motor_done_move = epics_signal_r(int, prefix + ".DMOV")
|
|
30
|
+
self.low_limit_travel = epics_signal_rw(float, prefix + ".LLM")
|
|
31
|
+
self.high_limit_travel = epics_signal_rw(float, prefix + ".HLM")
|
|
32
|
+
|
|
33
|
+
self.motor_stop = epics_signal_x(prefix + ".STOP")
|
|
24
34
|
# Whether set() should complete successfully or not
|
|
25
35
|
self._set_success = True
|
|
26
|
-
# Set name and signals for read() and read_configuration()
|
|
27
|
-
self.set_readable_signals(
|
|
28
|
-
read=[self.readback],
|
|
29
|
-
config=[self.velocity, self.units],
|
|
30
|
-
)
|
|
31
36
|
super().__init__(name=name)
|
|
32
37
|
|
|
33
38
|
def set_name(self, name: str):
|
|
34
39
|
super().set_name(name)
|
|
35
40
|
# Readback should be named the same as its parent in read()
|
|
36
|
-
self.
|
|
41
|
+
self.user_readback.set_name(name)
|
|
37
42
|
|
|
38
43
|
async def _move(self, new_position: float, watchers: List[Callable] = []):
|
|
39
44
|
self._set_success = True
|
|
40
45
|
start = time.monotonic()
|
|
41
46
|
old_position, units, precision = await asyncio.gather(
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
47
|
+
self.user_setpoint.get_value(),
|
|
48
|
+
self.motor_egu.get_value(),
|
|
44
49
|
self.precision.get_value(),
|
|
45
50
|
)
|
|
46
51
|
|
|
@@ -56,11 +61,11 @@ class Motor(StandardReadable, Movable, Stoppable):
|
|
|
56
61
|
time_elapsed=time.monotonic() - start,
|
|
57
62
|
)
|
|
58
63
|
|
|
59
|
-
self.
|
|
64
|
+
self.user_readback.subscribe_value(update_watchers)
|
|
60
65
|
try:
|
|
61
|
-
await self.
|
|
66
|
+
await self.user_setpoint.set(new_position)
|
|
62
67
|
finally:
|
|
63
|
-
self.
|
|
68
|
+
self.user_readback.clear_sub(update_watchers)
|
|
64
69
|
if not self._set_success:
|
|
65
70
|
raise RuntimeError("Motor was stopped")
|
|
66
71
|
|
|
@@ -81,5 +86,5 @@ class Motor(StandardReadable, Movable, Stoppable):
|
|
|
81
86
|
self._set_success = success
|
|
82
87
|
# Put with completion will never complete as we are waiting for completion on
|
|
83
88
|
# the move above, so need to pass wait=False
|
|
84
|
-
status = self.
|
|
89
|
+
status = self.motor_stop.trigger(wait=False)
|
|
85
90
|
await status
|