ophyd-async 0.8.0a2__py3-none-any.whl → 0.8.0a3__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 +7 -1
- ophyd_async/core/_device.py +1 -0
- ophyd_async/core/_device_filler.py +208 -130
- ophyd_async/core/_readable.py +128 -129
- ophyd_async/core/_utils.py +9 -1
- ophyd_async/epics/adaravis/_aravis_io.py +1 -1
- ophyd_async/epics/adcore/_core_io.py +1 -1
- ophyd_async/epics/adcore/_single_trigger.py +4 -9
- ophyd_async/epics/adkinetix/_kinetix_io.py +1 -1
- ophyd_async/epics/adpilatus/_pilatus_io.py +1 -1
- ophyd_async/epics/advimba/_vimba_io.py +1 -1
- ophyd_async/epics/core/__init__.py +26 -0
- ophyd_async/epics/{signal → core}/_aioca.py +3 -6
- ophyd_async/epics/core/_epics_connector.py +53 -0
- ophyd_async/epics/core/_epics_device.py +13 -0
- ophyd_async/epics/{signal → core}/_p4p.py +3 -6
- ophyd_async/epics/core/_pvi_connector.py +92 -0
- ophyd_async/epics/{signal → core}/_signal.py +31 -16
- ophyd_async/epics/{signal/_common.py → core/_util.py} +19 -1
- ophyd_async/epics/demo/_mover.py +4 -5
- ophyd_async/epics/demo/_sensor.py +9 -12
- ophyd_async/epics/eiger/_eiger_io.py +1 -1
- ophyd_async/epics/eiger/_odin_io.py +1 -1
- ophyd_async/epics/motor.py +4 -5
- ophyd_async/epics/signal.py +11 -0
- ophyd_async/fastcs/core.py +2 -2
- ophyd_async/sim/demo/_sim_motor.py +3 -4
- ophyd_async/tango/base_devices/_base_device.py +15 -16
- ophyd_async/tango/demo/_counter.py +6 -16
- ophyd_async/tango/demo/_mover.py +3 -4
- {ophyd_async-0.8.0a2.dist-info → ophyd_async-0.8.0a3.dist-info}/METADATA +1 -1
- {ophyd_async-0.8.0a2.dist-info → ophyd_async-0.8.0a3.dist-info}/RECORD +37 -35
- ophyd_async/epics/pvi/__init__.py +0 -3
- ophyd_async/epics/pvi/_pvi.py +0 -73
- ophyd_async/epics/signal/__init__.py +0 -20
- {ophyd_async-0.8.0a2.dist-info → ophyd_async-0.8.0a3.dist-info}/LICENSE +0 -0
- {ophyd_async-0.8.0a2.dist-info → ophyd_async-0.8.0a3.dist-info}/WHEEL +0 -0
- {ophyd_async-0.8.0a2.dist-info → ophyd_async-0.8.0a3.dist-info}/entry_points.txt +0 -0
- {ophyd_async-0.8.0a2.dist-info → ophyd_async-0.8.0a3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import Mock
|
|
4
|
+
|
|
5
|
+
from ophyd_async.core import (
|
|
6
|
+
Device,
|
|
7
|
+
DeviceConnector,
|
|
8
|
+
DeviceFiller,
|
|
9
|
+
Signal,
|
|
10
|
+
SignalR,
|
|
11
|
+
SignalRW,
|
|
12
|
+
SignalX,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from ._epics_connector import fill_backend_with_prefix
|
|
16
|
+
from ._signal import PvaSignalBackend, pvget_with_timeout
|
|
17
|
+
|
|
18
|
+
Entry = dict[str, str]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_signal_details(entry: Entry) -> tuple[type[Signal], str, str]:
|
|
22
|
+
match entry:
|
|
23
|
+
case {"r": read_pv}:
|
|
24
|
+
return SignalR, read_pv, read_pv
|
|
25
|
+
case {"r": read_pv, "w": write_pv}:
|
|
26
|
+
return SignalRW, read_pv, write_pv
|
|
27
|
+
case {"rw": read_write_pv}:
|
|
28
|
+
return SignalRW, read_write_pv, read_write_pv
|
|
29
|
+
case {"x": execute_pv}:
|
|
30
|
+
return SignalX, execute_pv, execute_pv
|
|
31
|
+
case _:
|
|
32
|
+
raise TypeError(f"Can't process entry {entry}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PviDeviceConnector(DeviceConnector):
|
|
36
|
+
def __init__(self, prefix: str = "") -> None:
|
|
37
|
+
# TODO: what happens if we get a leading "pva://" here?
|
|
38
|
+
self.prefix = prefix
|
|
39
|
+
self.pvi_pv = prefix + "PVI"
|
|
40
|
+
|
|
41
|
+
def create_children_from_annotations(self, device: Device):
|
|
42
|
+
if not hasattr(self, "filler"):
|
|
43
|
+
self.filler = DeviceFiller(
|
|
44
|
+
device=device,
|
|
45
|
+
signal_backend_factory=PvaSignalBackend,
|
|
46
|
+
device_connector_factory=PviDeviceConnector,
|
|
47
|
+
)
|
|
48
|
+
# Devices will be created with unfilled PviDeviceConnectors
|
|
49
|
+
list(self.filler.create_devices_from_annotations(filled=False))
|
|
50
|
+
# Signals can be filled in with EpicsSignalSuffix and checked at runtime
|
|
51
|
+
for backend, annotations in self.filler.create_signals_from_annotations(
|
|
52
|
+
filled=False
|
|
53
|
+
):
|
|
54
|
+
fill_backend_with_prefix(self.prefix, backend, annotations)
|
|
55
|
+
self.filler.check_created()
|
|
56
|
+
|
|
57
|
+
def _fill_child(self, name: str, entry: Entry, vector_index: int | None = None):
|
|
58
|
+
if set(entry) == {"d"}:
|
|
59
|
+
connector = self.filler.fill_child_device(name, vector_index=vector_index)
|
|
60
|
+
connector.pvi_pv = entry["d"]
|
|
61
|
+
else:
|
|
62
|
+
signal_type, read_pv, write_pv = _get_signal_details(entry)
|
|
63
|
+
backend = self.filler.fill_child_signal(name, signal_type, vector_index)
|
|
64
|
+
backend.read_pv = read_pv
|
|
65
|
+
backend.write_pv = write_pv
|
|
66
|
+
|
|
67
|
+
async def connect(
|
|
68
|
+
self, device: Device, mock: bool | Mock, timeout: float, force_reconnect: bool
|
|
69
|
+
) -> None:
|
|
70
|
+
if mock:
|
|
71
|
+
# Make 2 entries for each DeviceVector
|
|
72
|
+
self.filler.create_device_vector_entries_to_mock(2)
|
|
73
|
+
else:
|
|
74
|
+
pvi_structure = await pvget_with_timeout(self.pvi_pv, timeout)
|
|
75
|
+
entries: dict[str, Entry | list[Entry | None]] = pvi_structure[
|
|
76
|
+
"value"
|
|
77
|
+
].todict()
|
|
78
|
+
# Fill based on what PVI gives us
|
|
79
|
+
for name, entry in entries.items():
|
|
80
|
+
if isinstance(entry, dict):
|
|
81
|
+
# This is a child
|
|
82
|
+
self._fill_child(name, entry)
|
|
83
|
+
else:
|
|
84
|
+
# This is a DeviceVector of children
|
|
85
|
+
for i, e in enumerate(entry):
|
|
86
|
+
if e:
|
|
87
|
+
self._fill_child(name, e, i)
|
|
88
|
+
# Check that all the requested children have been filled
|
|
89
|
+
self.filler.check_filled(f"{self.pvi_pv}: {entries}")
|
|
90
|
+
# Set the name of the device to name all children
|
|
91
|
+
device.set_name(device.name)
|
|
92
|
+
return await super().connect(device, mock, timeout, force_reconnect)
|
|
@@ -14,13 +14,7 @@ from ophyd_async.core import (
|
|
|
14
14
|
get_unique,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
def _make_unavailable_class(error: Exception) -> type:
|
|
19
|
-
class TransportNotAvailable:
|
|
20
|
-
def __init__(*args, **kwargs):
|
|
21
|
-
raise NotImplementedError("Transport not available") from error
|
|
22
|
-
|
|
23
|
-
return TransportNotAvailable
|
|
17
|
+
from ._util import EpicsSignalBackend
|
|
24
18
|
|
|
25
19
|
|
|
26
20
|
class EpicsProtocol(Enum):
|
|
@@ -30,10 +24,26 @@ class EpicsProtocol(Enum):
|
|
|
30
24
|
|
|
31
25
|
_default_epics_protocol = EpicsProtocol.CA
|
|
32
26
|
|
|
27
|
+
|
|
28
|
+
def _make_unavailable_function(error: Exception):
|
|
29
|
+
def transport_not_available(*args, **kwargs):
|
|
30
|
+
raise NotImplementedError("Transport not available") from error
|
|
31
|
+
|
|
32
|
+
return transport_not_available
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _make_unavailable_class(error: Exception) -> type[EpicsSignalBackend]:
|
|
36
|
+
class TransportNotAvailable(EpicsSignalBackend):
|
|
37
|
+
__init__ = _make_unavailable_function(error)
|
|
38
|
+
|
|
39
|
+
return TransportNotAvailable
|
|
40
|
+
|
|
41
|
+
|
|
33
42
|
try:
|
|
34
|
-
from ._p4p import PvaSignalBackend
|
|
43
|
+
from ._p4p import PvaSignalBackend, pvget_with_timeout
|
|
35
44
|
except ImportError as pva_error:
|
|
36
45
|
PvaSignalBackend = _make_unavailable_class(pva_error)
|
|
46
|
+
pvget_with_timeout = _make_unavailable_function(pva_error)
|
|
37
47
|
else:
|
|
38
48
|
_default_epics_protocol = EpicsProtocol.PVA
|
|
39
49
|
|
|
@@ -45,7 +55,7 @@ else:
|
|
|
45
55
|
_default_epics_protocol = EpicsProtocol.CA
|
|
46
56
|
|
|
47
57
|
|
|
48
|
-
def
|
|
58
|
+
def split_protocol_from_pv(pv: str) -> tuple[EpicsProtocol, str]:
|
|
49
59
|
split = pv.split("://", 1)
|
|
50
60
|
if len(split) > 1:
|
|
51
61
|
# We got something like pva://mydevice, so use specified comms mode
|
|
@@ -57,18 +67,23 @@ def _protocol_pv(pv: str) -> tuple[EpicsProtocol, str]:
|
|
|
57
67
|
return protocol, pv
|
|
58
68
|
|
|
59
69
|
|
|
70
|
+
def get_signal_backend_type(protocol: EpicsProtocol) -> type[EpicsSignalBackend]:
|
|
71
|
+
match protocol:
|
|
72
|
+
case EpicsProtocol.CA:
|
|
73
|
+
return CaSignalBackend
|
|
74
|
+
case EpicsProtocol.PVA:
|
|
75
|
+
return PvaSignalBackend
|
|
76
|
+
|
|
77
|
+
|
|
60
78
|
def _epics_signal_backend(
|
|
61
79
|
datatype: type[SignalDatatypeT] | None, read_pv: str, write_pv: str
|
|
62
80
|
) -> SignalBackend[SignalDatatypeT]:
|
|
63
81
|
"""Create an epics signal backend."""
|
|
64
|
-
r_protocol, r_pv =
|
|
65
|
-
w_protocol, w_pv =
|
|
82
|
+
r_protocol, r_pv = split_protocol_from_pv(read_pv)
|
|
83
|
+
w_protocol, w_pv = split_protocol_from_pv(write_pv)
|
|
66
84
|
protocol = get_unique({read_pv: r_protocol, write_pv: w_protocol}, "protocols")
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return CaSignalBackend(datatype, r_pv, w_pv)
|
|
70
|
-
case EpicsProtocol.PVA:
|
|
71
|
-
return PvaSignalBackend(datatype, r_pv, w_pv)
|
|
85
|
+
signal_backend_type = get_signal_backend_type(protocol)
|
|
86
|
+
return signal_backend_type(datatype, r_pv, w_pv)
|
|
72
87
|
|
|
73
88
|
|
|
74
89
|
def epics_signal_rw(
|
|
@@ -3,7 +3,13 @@ from typing import Any, get_args, get_origin
|
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
6
|
-
from ophyd_async.core import
|
|
6
|
+
from ophyd_async.core import (
|
|
7
|
+
SignalBackend,
|
|
8
|
+
SignalDatatypeT,
|
|
9
|
+
SubsetEnum,
|
|
10
|
+
get_dtype,
|
|
11
|
+
get_enum_cls,
|
|
12
|
+
)
|
|
7
13
|
|
|
8
14
|
|
|
9
15
|
def get_supported_values(
|
|
@@ -41,3 +47,15 @@ def format_datatype(datatype: Any) -> str:
|
|
|
41
47
|
return datatype.__name__
|
|
42
48
|
else:
|
|
43
49
|
return str(datatype)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class EpicsSignalBackend(SignalBackend[SignalDatatypeT]):
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
datatype: type[SignalDatatypeT] | None,
|
|
56
|
+
read_pv: str = "",
|
|
57
|
+
write_pv: str = "",
|
|
58
|
+
):
|
|
59
|
+
self.read_pv = read_pv
|
|
60
|
+
self.write_pv = write_pv
|
|
61
|
+
super().__init__(datatype)
|
ophyd_async/epics/demo/_mover.py
CHANGED
|
@@ -8,15 +8,14 @@ from ophyd_async.core import (
|
|
|
8
8
|
DEFAULT_TIMEOUT,
|
|
9
9
|
AsyncStatus,
|
|
10
10
|
CalculatableTimeout,
|
|
11
|
-
ConfigSignal,
|
|
12
11
|
Device,
|
|
13
|
-
HintedSignal,
|
|
14
12
|
StandardReadable,
|
|
15
13
|
WatchableAsyncStatus,
|
|
16
14
|
WatcherUpdate,
|
|
17
15
|
observe_value,
|
|
18
16
|
)
|
|
19
|
-
from ophyd_async.
|
|
17
|
+
from ophyd_async.core import StandardReadableFormat as Format
|
|
18
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
class Mover(StandardReadable, Movable, Stoppable):
|
|
@@ -24,9 +23,9 @@ class Mover(StandardReadable, Movable, Stoppable):
|
|
|
24
23
|
|
|
25
24
|
def __init__(self, prefix: str, name="") -> None:
|
|
26
25
|
# Define some signals
|
|
27
|
-
with self.add_children_as_readables(
|
|
26
|
+
with self.add_children_as_readables(Format.HINTED_SIGNAL):
|
|
28
27
|
self.readback = epics_signal_r(float, prefix + "Readback")
|
|
29
|
-
with self.add_children_as_readables(
|
|
28
|
+
with self.add_children_as_readables(Format.CONFIG_SIGNAL):
|
|
30
29
|
self.velocity = epics_signal_rw(float, prefix + "Velocity")
|
|
31
30
|
self.units = epics_signal_r(str, prefix + "Readback.EGU")
|
|
32
31
|
self.setpoint = epics_signal_rw(float, prefix + "Setpoint")
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
from typing import Annotated as A
|
|
2
|
+
|
|
1
3
|
from ophyd_async.core import (
|
|
2
|
-
ConfigSignal,
|
|
3
4
|
DeviceVector,
|
|
4
|
-
|
|
5
|
+
SignalR,
|
|
6
|
+
SignalRW,
|
|
5
7
|
StandardReadable,
|
|
6
8
|
StrictEnum,
|
|
7
9
|
)
|
|
8
|
-
from ophyd_async.
|
|
10
|
+
from ophyd_async.core import StandardReadableFormat as Format
|
|
11
|
+
from ophyd_async.epics.core import EpicsDevice, PvSuffix
|
|
9
12
|
|
|
10
13
|
|
|
11
14
|
class EnergyMode(StrictEnum):
|
|
@@ -17,17 +20,11 @@ class EnergyMode(StrictEnum):
|
|
|
17
20
|
high = "High Energy"
|
|
18
21
|
|
|
19
22
|
|
|
20
|
-
class Sensor(StandardReadable):
|
|
23
|
+
class Sensor(StandardReadable, EpicsDevice):
|
|
21
24
|
"""A demo sensor that produces a scalar value based on X and Y Movers"""
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
with self.add_children_as_readables(HintedSignal):
|
|
26
|
-
self.value = epics_signal_r(float, prefix + "Value")
|
|
27
|
-
with self.add_children_as_readables(ConfigSignal):
|
|
28
|
-
self.mode = epics_signal_rw(EnergyMode, prefix + "Mode")
|
|
29
|
-
|
|
30
|
-
super().__init__(name=name)
|
|
26
|
+
value: A[SignalR[float], PvSuffix("Value"), Format.HINTED_SIGNAL]
|
|
27
|
+
mode: A[SignalRW[EnergyMode], PvSuffix("Mode"), Format.CONFIG_SIGNAL]
|
|
31
28
|
|
|
32
29
|
|
|
33
30
|
class SensorGroup(StandardReadable):
|
ophyd_async/epics/motor.py
CHANGED
|
@@ -14,14 +14,13 @@ from ophyd_async.core import (
|
|
|
14
14
|
DEFAULT_TIMEOUT,
|
|
15
15
|
AsyncStatus,
|
|
16
16
|
CalculatableTimeout,
|
|
17
|
-
ConfigSignal,
|
|
18
|
-
HintedSignal,
|
|
19
17
|
StandardReadable,
|
|
20
18
|
WatchableAsyncStatus,
|
|
21
19
|
WatcherUpdate,
|
|
22
20
|
observe_value,
|
|
23
21
|
)
|
|
24
|
-
from ophyd_async.
|
|
22
|
+
from ophyd_async.core import StandardReadableFormat as Format
|
|
23
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
class MotorLimitsException(Exception):
|
|
@@ -61,11 +60,11 @@ class Motor(StandardReadable, Locatable, Stoppable, Flyable, Preparable):
|
|
|
61
60
|
|
|
62
61
|
def __init__(self, prefix: str, name="") -> None:
|
|
63
62
|
# Define some signals
|
|
64
|
-
with self.add_children_as_readables(
|
|
63
|
+
with self.add_children_as_readables(Format.CONFIG_SIGNAL):
|
|
65
64
|
self.motor_egu = epics_signal_r(str, prefix + ".EGU")
|
|
66
65
|
self.velocity = epics_signal_rw(float, prefix + ".VELO")
|
|
67
66
|
|
|
68
|
-
with self.add_children_as_readables(
|
|
67
|
+
with self.add_children_as_readables(Format.HINTED_SIGNAL):
|
|
69
68
|
self.user_readback = epics_signal_r(float, prefix + ".RBV")
|
|
70
69
|
|
|
71
70
|
self.user_setpoint = epics_signal_rw(float, prefix + ".VAL")
|
ophyd_async/fastcs/core.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from ophyd_async.core import Device, DeviceConnector
|
|
2
|
-
from ophyd_async.epics.
|
|
2
|
+
from ophyd_async.epics.core import PviDeviceConnector
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def fastcs_connector(device: Device, uri: str) -> DeviceConnector:
|
|
6
6
|
# TODO: add Tango support based on uri scheme
|
|
7
|
-
connector = PviDeviceConnector(uri
|
|
7
|
+
connector = PviDeviceConnector(uri)
|
|
8
8
|
connector.create_children_from_annotations(device)
|
|
9
9
|
return connector
|
|
@@ -6,8 +6,6 @@ from bluesky.protocols import Movable, Stoppable
|
|
|
6
6
|
|
|
7
7
|
from ophyd_async.core import (
|
|
8
8
|
AsyncStatus,
|
|
9
|
-
ConfigSignal,
|
|
10
|
-
HintedSignal,
|
|
11
9
|
StandardReadable,
|
|
12
10
|
WatchableAsyncStatus,
|
|
13
11
|
WatcherUpdate,
|
|
@@ -15,6 +13,7 @@ from ophyd_async.core import (
|
|
|
15
13
|
soft_signal_r_and_setter,
|
|
16
14
|
soft_signal_rw,
|
|
17
15
|
)
|
|
16
|
+
from ophyd_async.core import StandardReadableFormat as Format
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class SimMotor(StandardReadable, Movable, Stoppable):
|
|
@@ -28,11 +27,11 @@ class SimMotor(StandardReadable, Movable, Stoppable):
|
|
|
28
27
|
- instant: bool: whether to move instantly, or with a delay
|
|
29
28
|
"""
|
|
30
29
|
# Define some signals
|
|
31
|
-
with self.add_children_as_readables(
|
|
30
|
+
with self.add_children_as_readables(Format.HINTED_SIGNAL):
|
|
32
31
|
self.user_readback, self._user_readback_set = soft_signal_r_and_setter(
|
|
33
32
|
float, 0
|
|
34
33
|
)
|
|
35
|
-
with self.add_children_as_readables(
|
|
34
|
+
with self.add_children_as_readables(Format.CONFIG_SIGNAL):
|
|
36
35
|
self.velocity = soft_signal_rw(float, 0 if instant else 1.0)
|
|
37
36
|
self.units = soft_signal_rw(str, "mm")
|
|
38
37
|
self.user_setpoint = soft_signal_rw(float, 0)
|
|
@@ -48,7 +48,6 @@ class TangoDevice(Device):
|
|
|
48
48
|
polling=self._polling,
|
|
49
49
|
signal_polling=self._signal_polling,
|
|
50
50
|
)
|
|
51
|
-
connector.create_children_from_annotations(self)
|
|
52
51
|
super().__init__(name=name, connector=connector)
|
|
53
52
|
|
|
54
53
|
|
|
@@ -106,20 +105,24 @@ class TangoDeviceConnector(DeviceConnector):
|
|
|
106
105
|
self._signal_polling = signal_polling
|
|
107
106
|
|
|
108
107
|
def create_children_from_annotations(self, device: Device):
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
if not hasattr(self, "filler"):
|
|
109
|
+
self.filler = DeviceFiller(
|
|
110
|
+
device=device,
|
|
111
|
+
signal_backend_factory=TangoSignalBackend,
|
|
112
|
+
device_connector_factory=lambda: TangoDeviceConnector(
|
|
113
|
+
None, None, (False, 0.1, None, None), {}
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
list(self.filler.create_devices_from_annotations(filled=False))
|
|
117
|
+
list(self.filler.create_signals_from_annotations(filled=False))
|
|
118
|
+
self.filler.check_created()
|
|
116
119
|
|
|
117
120
|
async def connect(
|
|
118
121
|
self, device: Device, mock: bool | Mock, timeout: float, force_reconnect: bool
|
|
119
122
|
) -> None:
|
|
120
123
|
if mock:
|
|
121
124
|
# Make 2 entries for each DeviceVector
|
|
122
|
-
self.
|
|
125
|
+
self.filler.create_device_vector_entries_to_mock(2)
|
|
123
126
|
else:
|
|
124
127
|
if self.trl and self.proxy is None:
|
|
125
128
|
self.proxy = await AsyncDeviceProxy(self.trl)
|
|
@@ -138,7 +141,7 @@ class TangoDeviceConnector(DeviceConnector):
|
|
|
138
141
|
full_trl = f"{self.trl}/{name}"
|
|
139
142
|
signal_type = await infer_signal_type(full_trl, self.proxy)
|
|
140
143
|
if signal_type:
|
|
141
|
-
backend = self.
|
|
144
|
+
backend = self.filler.fill_child_signal(name, signal_type)
|
|
142
145
|
backend.datatype = await infer_python_type(full_trl, self.proxy)
|
|
143
146
|
backend.set_trl(full_trl)
|
|
144
147
|
if polling := self._signal_polling.get(name, ()):
|
|
@@ -147,12 +150,8 @@ class TangoDeviceConnector(DeviceConnector):
|
|
|
147
150
|
elif self._polling[0]:
|
|
148
151
|
backend.set_polling(*self._polling)
|
|
149
152
|
backend.allow_events(False)
|
|
150
|
-
# Check that all the requested children have been
|
|
151
|
-
|
|
152
|
-
raise RuntimeError(
|
|
153
|
-
f"{device.name}: cannot provision {unfilled} from "
|
|
154
|
-
f"{self.trl}: {children}"
|
|
155
|
-
)
|
|
153
|
+
# Check that all the requested children have been filled
|
|
154
|
+
self.filler.check_filled(f"{self.trl}: {children}")
|
|
156
155
|
# Set the name of the device to name all children
|
|
157
156
|
device.set_name(device.name)
|
|
158
157
|
return await super().connect(device, mock, timeout, force_reconnect)
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
HintedSignal,
|
|
6
|
-
SignalR,
|
|
7
|
-
SignalRW,
|
|
8
|
-
SignalX,
|
|
9
|
-
)
|
|
1
|
+
from typing import Annotated as A
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import DEFAULT_TIMEOUT, AsyncStatus, SignalR, SignalRW, SignalX
|
|
4
|
+
from ophyd_async.core import StandardReadableFormat as Format
|
|
10
5
|
from ophyd_async.tango import TangoReadable, tango_polling
|
|
11
6
|
|
|
12
7
|
|
|
@@ -16,16 +11,11 @@ from ophyd_async.tango import TangoReadable, tango_polling
|
|
|
16
11
|
class TangoCounter(TangoReadable):
|
|
17
12
|
# Enter the name and type of the signals you want to use
|
|
18
13
|
# If type is None or Signal, the type will be inferred from the Tango device
|
|
19
|
-
counts: SignalR[int]
|
|
20
|
-
sample_time: SignalRW[float]
|
|
14
|
+
counts: A[SignalR[int], Format.HINTED_SIGNAL]
|
|
15
|
+
sample_time: A[SignalRW[float], Format.CONFIG_SIGNAL]
|
|
21
16
|
start: SignalX
|
|
22
17
|
reset_: SignalX
|
|
23
18
|
|
|
24
|
-
def __init__(self, trl: str | None = "", name=""):
|
|
25
|
-
super().__init__(trl, name=name)
|
|
26
|
-
self.add_readables([self.counts], HintedSignal)
|
|
27
|
-
self.add_readables([self.sample_time], ConfigSignal)
|
|
28
|
-
|
|
29
19
|
@AsyncStatus.wrap
|
|
30
20
|
async def trigger(self) -> None:
|
|
31
21
|
sample_time = await self.sample_time.get_value()
|
ophyd_async/tango/demo/_mover.py
CHANGED
|
@@ -7,8 +7,6 @@ from ophyd_async.core import (
|
|
|
7
7
|
DEFAULT_TIMEOUT,
|
|
8
8
|
AsyncStatus,
|
|
9
9
|
CalculatableTimeout,
|
|
10
|
-
ConfigSignal,
|
|
11
|
-
HintedSignal,
|
|
12
10
|
SignalR,
|
|
13
11
|
SignalRW,
|
|
14
12
|
SignalX,
|
|
@@ -17,6 +15,7 @@ from ophyd_async.core import (
|
|
|
17
15
|
observe_value,
|
|
18
16
|
wait_for_value,
|
|
19
17
|
)
|
|
18
|
+
from ophyd_async.core import StandardReadableFormat as Format
|
|
20
19
|
from ophyd_async.tango import TangoReadable, tango_polling
|
|
21
20
|
from tango import DevState
|
|
22
21
|
|
|
@@ -33,8 +32,8 @@ class TangoMover(TangoReadable, Movable, Stoppable):
|
|
|
33
32
|
|
|
34
33
|
def __init__(self, trl: str | None = "", name=""):
|
|
35
34
|
super().__init__(trl, name=name)
|
|
36
|
-
self.add_readables([self.position],
|
|
37
|
-
self.add_readables([self.velocity],
|
|
35
|
+
self.add_readables([self.position], Format.HINTED_SIGNAL)
|
|
36
|
+
self.add_readables([self.velocity], Format.CONFIG_SIGNAL)
|
|
38
37
|
self._set_success = True
|
|
39
38
|
|
|
40
39
|
@WatchableAsyncStatus.wrap
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.0a3
|
|
4
4
|
Summary: Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
|
|
5
5
|
Author-email: Tom Cobb <tom.cobb@diamond.ac.uk>
|
|
6
6
|
License: BSD 3-Clause License
|