ophyd-async 0.3a5__py3-none-any.whl → 0.3rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. ophyd_async/_version.py +1 -1
  2. ophyd_async/core/__init__.py +7 -5
  3. ophyd_async/core/async_status.py +11 -28
  4. ophyd_async/core/detector.py +1 -1
  5. ophyd_async/core/device.py +2 -4
  6. ophyd_async/core/flyer.py +1 -1
  7. ophyd_async/core/mock_signal_backend.py +5 -8
  8. ophyd_async/core/mock_signal_utils.py +10 -14
  9. ophyd_async/core/signal.py +23 -17
  10. ophyd_async/core/signal_backend.py +1 -1
  11. ophyd_async/core/utils.py +11 -0
  12. ophyd_async/epics/areadetector/drivers/ad_base.py +1 -7
  13. ophyd_async/epics/areadetector/writers/hdf_writer.py +3 -2
  14. ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -2
  15. ophyd_async/epics/areadetector/writers/nd_plugin.py +9 -0
  16. ophyd_async/epics/demo/__init__.py +30 -26
  17. ophyd_async/epics/motion/motor.py +35 -29
  18. ophyd_async/panda/__init__.py +2 -0
  19. ophyd_async/panda/writers/_hdf_writer.py +4 -4
  20. ophyd_async/{planstubs → plan_stubs}/__init__.py +5 -1
  21. ophyd_async/plan_stubs/fly.py +149 -0
  22. ophyd_async/sim/demo/sim_motor.py +56 -86
  23. {ophyd_async-0.3a5.dist-info → ophyd_async-0.3rc2.dist-info}/METADATA +1 -1
  24. {ophyd_async-0.3a5.dist-info → ophyd_async-0.3rc2.dist-info}/RECORD +29 -29
  25. ophyd_async/planstubs/prepare_trigger_and_dets.py +0 -57
  26. /ophyd_async/{planstubs → plan_stubs}/ensure_connected.py +0 -0
  27. {ophyd_async-0.3a5.dist-info → ophyd_async-0.3rc2.dist-info}/LICENSE +0 -0
  28. {ophyd_async-0.3a5.dist-info → ophyd_async-0.3rc2.dist-info}/WHEEL +0 -0
  29. {ophyd_async-0.3a5.dist-info → ophyd_async-0.3rc2.dist-info}/entry_points.txt +0 -0
  30. {ophyd_async-0.3a5.dist-info → ophyd_async-0.3rc2.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,20 @@
1
1
  import asyncio
2
- from dataclasses import replace
3
2
 
4
3
  from bluesky.protocols import Movable, Stoppable
5
4
 
6
5
  from ophyd_async.core import (
7
- AsyncStatus,
8
6
  ConfigSignal,
9
7
  HintedSignal,
10
8
  StandardReadable,
11
9
  WatchableAsyncStatus,
12
10
  )
13
11
  from ophyd_async.core.signal import observe_value
14
- from ophyd_async.core.utils import WatcherUpdate
12
+ from ophyd_async.core.utils import (
13
+ DEFAULT_TIMEOUT,
14
+ CalculatableTimeout,
15
+ CalculateTimeout,
16
+ WatcherUpdate,
17
+ )
15
18
 
16
19
  from ..signal.signal import epics_signal_r, epics_signal_rw, epics_signal_x
17
20
 
@@ -47,42 +50,45 @@ class Motor(StandardReadable, Movable, Stoppable):
47
50
  # Readback should be named the same as its parent in read()
48
51
  self.user_readback.set_name(name)
49
52
 
50
- async def _move(
51
- self, new_position: float
52
- ) -> tuple[WatcherUpdate[float], AsyncStatus]:
53
+ @WatchableAsyncStatus.wrap
54
+ async def set(
55
+ self, new_position: float, timeout: CalculatableTimeout = CalculateTimeout
56
+ ):
53
57
  self._set_success = True
54
- old_position, units, precision = await asyncio.gather(
58
+ (
59
+ old_position,
60
+ units,
61
+ precision,
62
+ velocity,
63
+ acceleration_time,
64
+ ) = await asyncio.gather(
55
65
  self.user_setpoint.get_value(),
56
66
  self.motor_egu.get_value(),
57
67
  self.precision.get_value(),
68
+ self.velocity.get_value(),
69
+ self.acceleration_time.get_value(),
58
70
  )
59
- move_status = self.user_setpoint.set(new_position, wait=True)
60
- if not self._set_success:
61
- raise RuntimeError("Motor was stopped")
62
- return (
63
- WatcherUpdate(
64
- initial=old_position,
65
- current=old_position,
66
- target=new_position,
67
- unit=units,
68
- precision=precision,
69
- ),
70
- move_status,
71
- )
72
-
73
- @WatchableAsyncStatus.wrap
74
- async def set(self, new_position: float, timeout: float | None = None):
75
- update, move_status = await self._move(new_position)
71
+ if timeout is CalculateTimeout:
72
+ assert velocity > 0, "Motor has zero velocity"
73
+ timeout = (
74
+ abs(new_position - old_position) / velocity
75
+ + 2 * acceleration_time
76
+ + DEFAULT_TIMEOUT
77
+ )
78
+ move_status = self.user_setpoint.set(new_position, wait=True, timeout=timeout)
76
79
  async for current_position in observe_value(
77
80
  self.user_readback, done_status=move_status
78
81
  ):
79
- if not self._set_success:
80
- raise RuntimeError("Motor was stopped")
81
- yield replace(
82
- update,
83
- name=self.name,
82
+ yield WatcherUpdate(
84
83
  current=current_position,
84
+ initial=old_position,
85
+ target=new_position,
86
+ name=self.name,
87
+ unit=units,
88
+ precision=precision,
85
89
  )
90
+ if not self._set_success:
91
+ raise RuntimeError("Motor was stopped")
86
92
 
87
93
  async def stop(self, success=False):
88
94
  self._set_success = success
@@ -15,6 +15,7 @@ from ._table import (
15
15
  seq_table_from_arrays,
16
16
  seq_table_from_rows,
17
17
  )
18
+ from ._trigger import StaticSeqTableTriggerLogic
18
19
  from ._utils import phase_sorter
19
20
 
20
21
  __all__ = [
@@ -33,4 +34,5 @@ __all__ = [
33
34
  "TimeUnits",
34
35
  "DataBlock",
35
36
  "CommonPandABlocks",
37
+ "StaticSeqTableTriggerLogic",
36
38
  ]
@@ -79,10 +79,10 @@ async def get_signals_marked_for_capture(
79
79
  capture_signals.keys(), capture_signals.values(), signal_values
80
80
  ):
81
81
  signal_path = signal_path.replace("_capture", "")
82
- if (signal_value.value in iter(Capture)) and (signal_value.value != Capture.No):
82
+ if (signal_value in iter(Capture)) and (signal_value != Capture.No):
83
83
  signals_to_capture[signal_path] = CaptureSignalWrapper(
84
84
  signal_object,
85
- signal_value.value,
85
+ signal_value,
86
86
  )
87
87
 
88
88
  return signals_to_capture
@@ -126,7 +126,7 @@ class PandaHDFWriter(DetectorWriter):
126
126
  str(info.root / info.resource_dir)
127
127
  ),
128
128
  self.panda_device.data.hdf_file_name.set(
129
- f"{info.prefix}{self.panda_device.name}{info.suffix}",
129
+ f"{info.prefix}{self.panda_device.name}{info.suffix}.h5",
130
130
  ),
131
131
  self.panda_device.data.num_capture.set(0),
132
132
  )
@@ -149,7 +149,7 @@ class PandaHDFWriter(DetectorWriter):
149
149
  else split_path[-2]
150
150
  )
151
151
 
152
- for suffix in str(capture_signal.capture_type).split(" "):
152
+ for suffix in capture_signal.capture_type.split(" "):
153
153
  self._datasets.append(
154
154
  _HDFDataset(
155
155
  name,
@@ -1,9 +1,13 @@
1
1
  from .ensure_connected import ensure_connected
2
- from .prepare_trigger_and_dets import (
2
+ from .fly import (
3
+ fly_and_collect,
3
4
  prepare_static_seq_table_flyer_and_detectors_with_same_trigger,
5
+ time_resolved_fly_and_collect_with_static_seq_table,
4
6
  )
5
7
 
6
8
  __all__ = [
9
+ "fly_and_collect",
7
10
  "prepare_static_seq_table_flyer_and_detectors_with_same_trigger",
11
+ "time_resolved_fly_and_collect_with_static_seq_table",
8
12
  "ensure_connected",
9
13
  ]
@@ -0,0 +1,149 @@
1
+ from typing import List
2
+
3
+ import bluesky.plan_stubs as bps
4
+ from bluesky.utils import short_uid
5
+
6
+ from ophyd_async.core.detector import DetectorTrigger, StandardDetector, TriggerInfo
7
+ from ophyd_async.core.flyer import HardwareTriggeredFlyable
8
+ from ophyd_async.core.utils import in_micros
9
+ from ophyd_async.panda._table import SeqTable, SeqTableRow, seq_table_from_rows
10
+ from ophyd_async.panda._trigger import SeqTableInfo
11
+
12
+
13
+ def prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
14
+ flyer: HardwareTriggeredFlyable[SeqTableInfo],
15
+ detectors: List[StandardDetector],
16
+ number_of_frames: int,
17
+ exposure: float,
18
+ shutter_time: float,
19
+ repeats: int = 1,
20
+ period: float = 0.0,
21
+ ):
22
+ """Prepare a hardware triggered flyable and one or more detectors.
23
+
24
+ Prepare a hardware triggered flyable and one or more detectors with the
25
+ same trigger. This method constructs TriggerInfo and a static sequence
26
+ table from required parameters. The table is required to prepare the flyer,
27
+ and the TriggerInfo is required to prepare the detector(s).
28
+
29
+ This prepares all supplied detectors with the same trigger.
30
+
31
+ """
32
+ if not detectors:
33
+ raise ValueError("No detectors provided. There must be at least one.")
34
+
35
+ deadtime = max(det.controller.get_deadtime(exposure) for det in detectors)
36
+
37
+ trigger_info = TriggerInfo(
38
+ num=number_of_frames * repeats,
39
+ trigger=DetectorTrigger.constant_gate,
40
+ deadtime=deadtime,
41
+ livetime=exposure,
42
+ )
43
+ trigger_time = number_of_frames * (exposure + deadtime)
44
+ pre_delay = max(period - 2 * shutter_time - trigger_time, 0)
45
+
46
+ table: SeqTable = seq_table_from_rows(
47
+ # Wait for pre-delay then open shutter
48
+ SeqTableRow(
49
+ time1=in_micros(pre_delay),
50
+ time2=in_micros(shutter_time),
51
+ outa2=True,
52
+ ),
53
+ # Keeping shutter open, do N triggers
54
+ SeqTableRow(
55
+ repeats=number_of_frames,
56
+ time1=in_micros(exposure),
57
+ outa1=True,
58
+ outb1=True,
59
+ time2=in_micros(deadtime),
60
+ outa2=True,
61
+ ),
62
+ # Add the shutter close
63
+ SeqTableRow(time2=in_micros(shutter_time)),
64
+ )
65
+
66
+ table_info = SeqTableInfo(table, repeats)
67
+
68
+ for det in detectors:
69
+ yield from bps.prepare(det, trigger_info, wait=False, group="prep")
70
+ yield from bps.prepare(flyer, table_info, wait=False, group="prep")
71
+ yield from bps.wait(group="prep")
72
+
73
+
74
+ def fly_and_collect(
75
+ stream_name: str,
76
+ flyer: HardwareTriggeredFlyable[SeqTableInfo],
77
+ detectors: List[StandardDetector],
78
+ ):
79
+ """Kickoff, complete and collect with a flyer and multiple detectors.
80
+
81
+ This stub takes a flyer and one or more detectors that have been prepared. It
82
+ declares a stream for the detectors, then kicks off the detectors and the flyer.
83
+ The detectors are collected until the flyer and detectors have completed.
84
+
85
+ """
86
+ yield from bps.declare_stream(*detectors, name=stream_name, collect=True)
87
+ yield from bps.kickoff(flyer, wait=True)
88
+ for detector in detectors:
89
+ yield from bps.kickoff(detector)
90
+
91
+ # collect_while_completing
92
+ group = short_uid(label="complete")
93
+
94
+ yield from bps.complete(flyer, wait=False, group=group)
95
+ for detector in detectors:
96
+ yield from bps.complete(detector, wait=False, group=group)
97
+
98
+ done = False
99
+ while not done:
100
+ try:
101
+ yield from bps.wait(group=group, timeout=0.5)
102
+ except TimeoutError:
103
+ pass
104
+ else:
105
+ done = True
106
+ yield from bps.collect(
107
+ *detectors,
108
+ return_payload=False,
109
+ name=stream_name,
110
+ )
111
+ yield from bps.wait(group=group)
112
+
113
+
114
+ def time_resolved_fly_and_collect_with_static_seq_table(
115
+ stream_name: str,
116
+ flyer: HardwareTriggeredFlyable[SeqTableInfo],
117
+ detectors: List[StandardDetector],
118
+ number_of_frames: int,
119
+ exposure: float,
120
+ shutter_time: float,
121
+ repeats: int = 1,
122
+ period: float = 0.0,
123
+ ):
124
+ """Run a scan wth a flyer and multiple detectors.
125
+
126
+ The stub demonstrates the standard basic flow for a flyscan:
127
+
128
+ - Prepare the flyer and detectors with a trigger
129
+ - Fly and collect:
130
+ - Declare the stream and kickoff the scan
131
+ - Collect while completing
132
+
133
+ This needs to be used in a plan that instantates detectors and a flyer,
134
+ stages/unstages the devices, and opens and closes the run.
135
+
136
+ """
137
+
138
+ # Set up scan and prepare trigger
139
+ yield from prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
140
+ flyer,
141
+ detectors,
142
+ number_of_frames=number_of_frames,
143
+ exposure=exposure,
144
+ shutter_time=shutter_time,
145
+ repeats=repeats,
146
+ period=period,
147
+ )
148
+ # Run the fly scan
149
+ yield from fly_and_collect(stream_name, flyer, detectors)
@@ -1,6 +1,6 @@
1
1
  import asyncio
2
+ import contextlib
2
3
  import time
3
- from dataclasses import replace
4
4
 
5
5
  from bluesky.protocols import Movable, Stoppable
6
6
 
@@ -25,109 +25,79 @@ class SimMotor(StandardReadable, Movable, Stoppable):
25
25
  - name: str: name of device
26
26
  - instant: bool: whether to move instantly, or with a delay
27
27
  """
28
+ # Define some signals
28
29
  with self.add_children_as_readables(HintedSignal):
29
30
  self.user_readback, self._user_readback_set = soft_signal_r_and_setter(
30
31
  float, 0
31
32
  )
32
-
33
33
  with self.add_children_as_readables(ConfigSignal):
34
- self.velocity = soft_signal_rw(float, 1.0)
35
- self.egu = soft_signal_rw(str, "mm")
36
-
37
- self._instant = instant
38
- self._move_status: AsyncStatus | None = None
39
-
40
- # Define some signals
34
+ self.velocity = soft_signal_rw(float, 0 if instant else 1.0)
35
+ self.units = soft_signal_rw(str, "mm")
41
36
  self.user_setpoint = soft_signal_rw(float, 0)
42
37
 
43
- super().__init__(name=name)
44
-
45
38
  # Whether set() should complete successfully or not
46
39
  self._set_success = True
40
+ self._move_status: AsyncStatus | None = None
47
41
 
48
- def stop(self, success=False):
49
- """
50
- Stop the motor if it is moving
51
- """
52
- if self._move_status:
53
- self._move_status.task.cancel()
54
- self._move_status = None
42
+ super().__init__(name=name)
55
43
 
56
- async def trigger_callbacks():
57
- await self.user_readback._backend.put(
58
- await self.user_readback._backend.get_value()
59
- )
44
+ async def _move(self, old_position: float, new_position: float, move_time: float):
45
+ start = time.monotonic()
46
+ distance = abs(new_position - old_position)
47
+ while True:
48
+ time_elapsed = round(time.monotonic() - start, 2)
60
49
 
61
- asyncio.create_task(trigger_callbacks())
50
+ # update position based on time elapsed
51
+ if time_elapsed >= move_time:
52
+ # successfully reached our target position
53
+ self._user_readback_set(new_position)
54
+ break
55
+ else:
56
+ current_position = old_position + distance * time_elapsed / move_time
62
57
 
63
- self._set_success = success
58
+ self._user_readback_set(current_position)
59
+
60
+ # 10hz update loop
61
+ await asyncio.sleep(0.1)
64
62
 
65
63
  @WatchableAsyncStatus.wrap
66
- async def set(self, new_position: float, timeout: float | None = None):
64
+ async def set(self, new_position: float):
67
65
  """
68
66
  Asynchronously move the motor to a new position.
69
67
  """
70
- update, move_status = await self._move(new_position, timeout)
71
- async for current_position in observe_value(
72
- self.user_readback, done_status=move_status
73
- ):
74
- if not self._set_success:
75
- raise RuntimeError("Motor was stopped")
76
- yield replace(
77
- update,
78
- name=self.name,
79
- current=current_position,
80
- )
81
-
82
- async def _move(self, new_position: float, timeout: float | None = None):
83
- """
84
- Start the motor moving to a new position.
85
-
86
- If the motor is already moving, it will stop first.
87
- If this is an instant motor the move will be instantaneous.
88
- """
89
- self.stop()
90
- start = time.monotonic()
91
- self._set_success = True
92
-
93
- current_position = await self.user_readback.get_value()
94
- distance = abs(new_position - current_position)
95
- travel_time = 0 if self._instant else distance / await self.velocity.get_value()
96
-
97
- old_position, units = await asyncio.gather(
68
+ # Make sure any existing move tasks are stopped
69
+ await self.stop()
70
+ old_position, units, velocity = await asyncio.gather(
98
71
  self.user_setpoint.get_value(),
99
- self.egu.get_value(),
72
+ self.units.get_value(),
73
+ self.velocity.get_value(),
100
74
  )
101
-
102
- async def update_position():
103
- while True:
104
- time_elapsed = round(time.monotonic() - start, 2)
105
-
106
- # update position based on time elapsed
107
- if time_elapsed >= travel_time:
108
- # successfully reached our target position
109
- self._user_readback_set(new_position)
110
- self._set_success = True
111
- break
112
- else:
113
- current_position = (
114
- old_position + distance * time_elapsed / travel_time
115
- )
116
-
117
- self._user_readback_set(current_position)
118
-
119
- # 10hz update loop
120
- await asyncio.sleep(0.1)
121
-
122
- # set up a task that updates the motor position at ~10hz
123
- self._move_status = AsyncStatus(asyncio.wait_for(update_position(), timeout))
124
-
125
- return (
126
- WatcherUpdate(
127
- initial=old_position,
128
- current=old_position,
129
- target=new_position,
130
- unit=units,
131
- ),
132
- self._move_status,
75
+ # If zero velocity, do instant move
76
+ move_time = abs(new_position - old_position) / velocity if velocity else 0
77
+ self._move_status = AsyncStatus(
78
+ self._move(old_position, new_position, move_time)
133
79
  )
80
+ # If stop is called then this will raise a CancelledError, ignore it
81
+ with contextlib.suppress(asyncio.CancelledError):
82
+ async for current_position in observe_value(
83
+ self.user_readback, done_status=self._move_status
84
+ ):
85
+ yield WatcherUpdate(
86
+ current=current_position,
87
+ initial=old_position,
88
+ target=new_position,
89
+ name=self.name,
90
+ unit=units,
91
+ )
92
+ if not self._set_success:
93
+ raise RuntimeError("Motor was stopped")
94
+
95
+ async def stop(self, success=True):
96
+ """
97
+ Stop the motor if it is moving
98
+ """
99
+ self._set_success = success
100
+ if self._move_status:
101
+ self._move_status.task.cancel()
102
+ self._move_status = None
103
+ await self.user_setpoint.set(await self.user_readback.get_value())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.3a5
3
+ Version: 0.3rc2
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
@@ -1,22 +1,22 @@
1
1
  ophyd_async/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
2
2
  ophyd_async/__main__.py,sha256=G-Zcv_G9zK7Nhx6o5L5w-wyhMxdl_WgyMELu8IMFqAE,328
3
- ophyd_async/_version.py,sha256=U12czQTgzf6ojb0_kN2Mdxwd3eohytfYDRR6gcj6mEw,408
3
+ ophyd_async/_version.py,sha256=Q6NCoABIZDCaoLXsuU8odM9VJngCLNAvP46RIhMvPN0,409
4
4
  ophyd_async/log.py,sha256=DbMjt0bkfUOLHIinZYt0Q0FHZmCXXi5x8y0uFiEmqoQ,3587
5
5
  ophyd_async/protocols.py,sha256=EF2W9nfElV-0QNMYrX1zusL1PqDJR3kNsjlalR29j0I,3412
6
- ophyd_async/core/__init__.py,sha256=YMFc7rJhfq6waLMmHTCD6BVqUM_jM7joPGEoxUued7g,2893
6
+ ophyd_async/core/__init__.py,sha256=znjVeRfrDVJbGLEkUczeKMW46kV6HDrlE4lV0SqvZt4,2952
7
7
  ophyd_async/core/_providers.py,sha256=LrlTMPHKXWOPVkpAOw-pqBq0kip-c3C9ZZPoFfiaV4M,2212
8
- ophyd_async/core/async_status.py,sha256=h6IZUoSeGfuiMT_CAIR-nzHeTJH0srvSpiqOQtxHMnw,5229
9
- ophyd_async/core/detector.py,sha256=j4MRENoe3En4a-3gNpfQXvBgFC4besfcczoP98QOclc,11003
10
- ophyd_async/core/device.py,sha256=_0COEm9x35hmnBb-X5z_q8xnGwfzOgunAovtPWR5yik,7118
8
+ ophyd_async/core/async_status.py,sha256=9TOgOXIAuH62RDo5t-Y5GdjrJ76d_6TFlBxYv-5_a88,4367
9
+ ophyd_async/core/detector.py,sha256=8mdLKphirgit5CVCklJI9eHqKKiCz4CYs9BElo10-lc,11007
10
+ ophyd_async/core/device.py,sha256=280zFnLCoiMZAA-Dh1_AjUSnhxUfKYGgj4H_2S1njOA,7086
11
11
  ophyd_async/core/device_save_loader.py,sha256=RXA3dPUPihAR2ZGDStlGiA-TAsr_xqL0snsCjMsMnfA,9138
12
- ophyd_async/core/flyer.py,sha256=LfO3EQTW2zMeNqZh8TLXvE92E30Duds2RXskRYAdJ_4,2299
13
- ophyd_async/core/mock_signal_backend.py,sha256=13BAbQG1OPC3o_fOFFQH4x1mPYLQ8Zf53WviRPXWDTM,2938
14
- ophyd_async/core/mock_signal_utils.py,sha256=umWf42HHWyUCYLVYnj5weh4pNBMpN1ElRTsxKsc4q_k,4287
15
- ophyd_async/core/signal.py,sha256=57z_-B9BDTCX0BwL63VnyBsBlBqWb6ltFLP9bPiYISE,16081
16
- ophyd_async/core/signal_backend.py,sha256=qDdWz8X4CWStuYknxcj4G76BLq4TzrAIyZO1NOEq9ao,1519
12
+ ophyd_async/core/flyer.py,sha256=bIjzBkrl8HVAlKgsZ_FF0WL69Qvksyzp9ZWmTLl8Yrw,2304
13
+ ophyd_async/core/mock_signal_backend.py,sha256=Ug6jK72wm9vM6EueoUrYgcXtiFzdPUEISRe86LdyYKc,2844
14
+ ophyd_async/core/mock_signal_utils.py,sha256=bF8MVZA1j9zCmS2tBbgUdfwNmcHniHixnmotjd0g7hs,4083
15
+ ophyd_async/core/signal.py,sha256=FbTb5qDPLhVxEbh6gimqXfkZwcqB4ymHTEYVXZVZYrk,16456
16
+ ophyd_async/core/signal_backend.py,sha256=fT3q0WED3JHmNKYCs7PzDLCK4cUPVin3wQjDNPdHqAY,1525
17
17
  ophyd_async/core/soft_signal_backend.py,sha256=56zvcEi4c8n1yYbafTbp7X0VhSkhoehm3L8RBhu2fik,5596
18
18
  ophyd_async/core/standard_readable.py,sha256=uVG3vs3s7-Kzg5dRCtT4I2mhZPqwVGYy2dxNmaOpDVU,8980
19
- ophyd_async/core/utils.py,sha256=OMOpa-5QMAGQbbb0tFD4lRnyk0Fykq4aD2EOQbPt39c,5516
19
+ ophyd_async/core/utils.py,sha256=3oZcXNqAUHX4ZWMBH5gSuK6cFWEhSkZ9GSDYv0pf8jc,5783
20
20
  ophyd_async/epics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  ophyd_async/epics/_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  ophyd_async/epics/_backend/_aioca.py,sha256=cpPNZmRMi7FnAh2-3ec5uklLVFOqsmEmpI1nh5Ud1Ls,8794
@@ -36,7 +36,7 @@ ophyd_async/epics/areadetector/controllers/kinetix_controller.py,sha256=9QmydX85
36
36
  ophyd_async/epics/areadetector/controllers/pilatus_controller.py,sha256=cd1CKkaXlwkpQ0I1VL7nN0U8R4VweTsa08WhvHYI4nY,2243
37
37
  ophyd_async/epics/areadetector/controllers/vimba_controller.py,sha256=Eh4Hr9rWgq1mKvE93JzgixntjPHxF3_07GTFqiOdZqE,2123
38
38
  ophyd_async/epics/areadetector/drivers/__init__.py,sha256=-Ib0Lz4fFQQmB7K0uFxMDvAerkLxadMQERH7lNAvrs4,495
39
- ophyd_async/epics/areadetector/drivers/ad_base.py,sha256=cE7I-IsfQz3UR9yqghy4czAxHeHERTTKe080GB9sCFQ,3847
39
+ ophyd_async/epics/areadetector/drivers/ad_base.py,sha256=18WFAiWEUg0H2LcvTQHrKYj2wThGafQzDpiyAWki6vo,3411
40
40
  ophyd_async/epics/areadetector/drivers/aravis_driver.py,sha256=PmIygsVNoxxYHvZZzFAbAm2DXmXFc13nAzL_DJB6YSU,1464
41
41
  ophyd_async/epics/areadetector/drivers/kinetix_driver.py,sha256=yIV23BkGBJ4i0VskLiLL7AFbadCCR6Ch1UwUDJ9r2YM,743
42
42
  ophyd_async/epics/areadetector/drivers/pilatus_driver.py,sha256=0DsUu9vAPXDa2v8_V0f_kPjBtLu3y4_EkmFfFjYO4Gk,553
@@ -44,21 +44,21 @@ ophyd_async/epics/areadetector/drivers/vimba_driver.py,sha256=J54VtWkOklfbSqZYxG
44
44
  ophyd_async/epics/areadetector/writers/__init__.py,sha256=tpPcrYd1hs8WS7C0gmCnR2EBwjE5RzCljI7WwZ2V_LM,191
45
45
  ophyd_async/epics/areadetector/writers/_hdfdataset.py,sha256=E0C9VgsPyY35h7k0mvcIhjsIVNavApLxizqNWlM388w,167
46
46
  ophyd_async/epics/areadetector/writers/_hdffile.py,sha256=YtUgOKX53m0TaFEGBW671qXqNuuEKxEyLV5Ein1fjvo,1799
47
- ophyd_async/epics/areadetector/writers/hdf_writer.py,sha256=e7EbusP3Ell-2npdLtDWcZ_kDIRidUwHeqcbeMx4mlU,5427
48
- ophyd_async/epics/areadetector/writers/nd_file_hdf.py,sha256=whKDkvKnU1qiDym4xQq4Fd1jHEhtDu552xhhGSnB--w,1910
49
- ophyd_async/epics/areadetector/writers/nd_plugin.py,sha256=sG4XZAS_k065g88n9U3IJGtYI4PPHfyJMcVqh9hVAa4,979
50
- ophyd_async/epics/demo/__init__.py,sha256=8NetaM610KGlVa5QeM47c9KoWkG7GvXoepd8txf6MGU,5598
47
+ ophyd_async/epics/areadetector/writers/hdf_writer.py,sha256=ZpbVilNVv81OpbCrqaeZUoHLarrjzRWEGe-zI1Wxyyw,5436
48
+ ophyd_async/epics/areadetector/writers/nd_file_hdf.py,sha256=EkiaEh_0U6Iz17jFi2IIsRPsVQTQIJRG8EPNCiAHkkU,1762
49
+ ophyd_async/epics/areadetector/writers/nd_plugin.py,sha256=GUzaeTMdG07Rb1x0WzBBxMEltBhr10jb5dL29tEWXEQ,1547
50
+ ophyd_async/epics/demo/__init__.py,sha256=ZcuZ66aIQ58WSydLOSKnk-h_W-aWjhDRZkWQA6f3sig,5790
51
51
  ophyd_async/epics/demo/demo_ad_sim_detector.py,sha256=06y65yvaqXvL2rDocjYyLz9kTVzuwV-LeuPhEfExdOA,944
52
52
  ophyd_async/epics/demo/mover.db,sha256=RFz0rxZue689Wh1sWTZwWeFMUrH04ttPq2u5xJH_Fp4,998
53
53
  ophyd_async/epics/demo/sensor.db,sha256=AVtiydrdtwAz2EFurO2Ult9SSRtre3r0akOBbL98LT0,554
54
54
  ophyd_async/epics/motion/__init__.py,sha256=tnmVRIwKa9PdN_xonJdAUD04UpEceh-hoD7XI62yDB0,46
55
- ophyd_async/epics/motion/motor.py,sha256=ZiyC0WvO9AAsv_FmYBaCmOYQ86yZIS3QnSxfyPUg5jE,3504
55
+ ophyd_async/epics/motion/motor.py,sha256=G8cc-okSXJ6s2fGxRO155xm7PrBbVImBmBMRWts895k,3630
56
56
  ophyd_async/epics/pvi/__init__.py,sha256=TbOQNY4enQWgtr1T7x129vpo2p7FIFlr8cyZqqv5Lk4,158
57
57
  ophyd_async/epics/pvi/pvi.py,sha256=PJdY3rCRyIQbsbHDru-TJ-IVOItyaQwCQKAC0Widu6A,11363
58
58
  ophyd_async/epics/signal/__init__.py,sha256=JXKBSGpRL9y3auh27JRxsqDn_rBOXpJjtd4nCuDOX2g,261
59
59
  ophyd_async/epics/signal/_epics_transport.py,sha256=DEIL0iYUAWssysVEgWGu1fHSM1l-ATV2kjUgPtDN9LY,858
60
60
  ophyd_async/epics/signal/signal.py,sha256=M8ZVG_zLdYJfroCRX-u_w8c3yIhswSRw8e3RkW2szio,3166
61
- ophyd_async/panda/__init__.py,sha256=ZaD1nRgGKAGFGdpP1WWF-FnX3wcGuYqqq0QRZbaSBYQ,692
61
+ ophyd_async/panda/__init__.py,sha256=FuSnvp-RtdA0X4RcHEF0nTiXymRts2MNdFmF_1_i41w,775
62
62
  ophyd_async/panda/_common_blocks.py,sha256=n0PPc1rar43oDSIA-yNubTc8fR5YCW1tyjQU58whsg0,1038
63
63
  ophyd_async/panda/_hdf_panda.py,sha256=QjfZyYos0ZBlIqBiZ5UbyEd_wuh_cGzwV8QE9jvLiIY,1419
64
64
  ophyd_async/panda/_panda_controller.py,sha256=dIqcjmaIHVrki8UXSoDx46kk6I2Lhpe2o3sXNg5f-RQ,1238
@@ -66,21 +66,21 @@ ophyd_async/panda/_table.py,sha256=dLoRP4zYNOkD_s0Vkp2wVYAwkjVG8nNdf8-FaXOTfPo,5
66
66
  ophyd_async/panda/_trigger.py,sha256=tBH8uq_4o1ASG9yofVxq3tjf5v8LPzniDTRL4yjramI,1195
67
67
  ophyd_async/panda/_utils.py,sha256=VHW5kPVISyEkmse_qQcyisBkkEwMO6GG2Ago-CH1AFA,487
68
68
  ophyd_async/panda/writers/__init__.py,sha256=xy7BguVQG4HNIDBfKPjMj0KQo1tptC9LbCpEuMcVGaM,70
69
- ophyd_async/panda/writers/_hdf_writer.py,sha256=_KlawqQHuWXLCvhGg1N6S4dQ8LhM88NbHsbXryxPvPA,7617
69
+ ophyd_async/panda/writers/_hdf_writer.py,sha256=vnyIg3JmlzMIIq75o0IDMfGzBm_GJAhOUisAZE_0cyg,7597
70
70
  ophyd_async/panda/writers/_panda_hdf_file.py,sha256=42iHaTax4JjOBpNC7d4nkNL9SM14OTnFPTIcXv2jg-4,1759
71
- ophyd_async/planstubs/__init__.py,sha256=T2ICLREJv0uUgGRQbxk2w57TZ7jf7wYWB6TBY22cqnc,266
72
- ophyd_async/planstubs/ensure_connected.py,sha256=1MkDu8UqVRPHLnW9IXRn-QvKiG8-rCV8T4KDbjf9K6w,557
73
- ophyd_async/planstubs/prepare_trigger_and_dets.py,sha256=0c4XDAxVkSanyDKtaMda0VgPEbk2jM0geVzAx707DhI,1772
71
+ ophyd_async/plan_stubs/__init__.py,sha256=nO9ELG9J7fYwfVTVRWVorz4kffeszYpwk1ROh6Ha--w,405
72
+ ophyd_async/plan_stubs/ensure_connected.py,sha256=1MkDu8UqVRPHLnW9IXRn-QvKiG8-rCV8T4KDbjf9K6w,557
73
+ ophyd_async/plan_stubs/fly.py,sha256=nl8XLoY7hvlam6H3zl4NcPRUiEJ3xIjopHEfA0ehTDg,4845
74
74
  ophyd_async/sim/__init__.py,sha256=ScjH1g7FMo5yPACfJRZE6xGBWCHU4bKDzNQk1tqObnA,366
75
75
  ophyd_async/sim/pattern_generator.py,sha256=pvSk2zb82D08j2jiKAMqMAfRohGnYd_rpjUraLrCD6c,10640
76
76
  ophyd_async/sim/sim_pattern_detector_control.py,sha256=Ypz8IuRYAY2J243IhVbNyGr_Z-XtpJZ1qxma6NR3TgM,1838
77
77
  ophyd_async/sim/sim_pattern_detector_writer.py,sha256=ESpcVyHd1TP7Cojznv2hJAwLinu3XbgAiVKfX12FCII,1237
78
78
  ophyd_async/sim/sim_pattern_generator.py,sha256=fbcwWxTPYKLK33OzIY15vGylnonOO8HIudz1y_56GZU,1336
79
79
  ophyd_async/sim/demo/__init__.py,sha256=9mxKpslrL89cfSj4g3og8Br3O--pMj3hhWZS-Xu6kyA,56
80
- ophyd_async/sim/demo/sim_motor.py,sha256=gtWYn_zs43XahpzNey0or2PDhoB78fZIVl767HnE-kU,4352
81
- ophyd_async-0.3a5.dist-info/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
82
- ophyd_async-0.3a5.dist-info/METADATA,sha256=39ilqICk5TpmGcGnsJcpXzJjl0NV87VvpOPf2vUez80,6284
83
- ophyd_async-0.3a5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
84
- ophyd_async-0.3a5.dist-info/entry_points.txt,sha256=O0YNJTEufO0w9BozXi-JurTy2U1_o0ypeCgJLQ727Jk,58
85
- ophyd_async-0.3a5.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
86
- ophyd_async-0.3a5.dist-info/RECORD,,
80
+ ophyd_async/sim/demo/sim_motor.py,sha256=a2p5wnHXjF-V5zOFai7jnszk4kbGmrZRnUqBtkOgEfQ,3733
81
+ ophyd_async-0.3rc2.dist-info/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
82
+ ophyd_async-0.3rc2.dist-info/METADATA,sha256=TRb7FrOHb4YrISGe-fkGY_W3kkrnBvioFJsgErNLmo8,6285
83
+ ophyd_async-0.3rc2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
84
+ ophyd_async-0.3rc2.dist-info/entry_points.txt,sha256=O0YNJTEufO0w9BozXi-JurTy2U1_o0ypeCgJLQ727Jk,58
85
+ ophyd_async-0.3rc2.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
86
+ ophyd_async-0.3rc2.dist-info/RECORD,,
@@ -1,57 +0,0 @@
1
- from typing import List
2
-
3
- import bluesky.plan_stubs as bps
4
-
5
- from ophyd_async.core.detector import DetectorTrigger, StandardDetector, TriggerInfo
6
- from ophyd_async.core.flyer import HardwareTriggeredFlyable
7
- from ophyd_async.core.utils import in_micros
8
- from ophyd_async.panda._table import SeqTable, SeqTableRow, seq_table_from_rows
9
- from ophyd_async.panda._trigger import SeqTableInfo
10
-
11
-
12
- def prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
13
- flyer: HardwareTriggeredFlyable[SeqTableInfo],
14
- detectors: List[StandardDetector],
15
- num: int,
16
- width: float,
17
- deadtime: float,
18
- shutter_time: float,
19
- repeats: int = 1,
20
- period: float = 0.0,
21
- ):
22
- trigger_info = TriggerInfo(
23
- num=num * repeats,
24
- trigger=DetectorTrigger.constant_gate,
25
- deadtime=deadtime,
26
- livetime=width,
27
- )
28
-
29
- trigger_time = num * (width + deadtime)
30
- pre_delay = max(period - 2 * shutter_time - trigger_time, 0)
31
-
32
- table: SeqTable = seq_table_from_rows(
33
- # Wait for pre-delay then open shutter
34
- SeqTableRow(
35
- time1=in_micros(pre_delay),
36
- time2=in_micros(shutter_time),
37
- outa2=True,
38
- ),
39
- # Keeping shutter open, do N triggers
40
- SeqTableRow(
41
- repeats=num,
42
- time1=in_micros(width),
43
- outa1=True,
44
- outb1=True,
45
- time2=in_micros(deadtime),
46
- outa2=True,
47
- ),
48
- # Add the shutter close
49
- SeqTableRow(time2=in_micros(shutter_time)),
50
- )
51
-
52
- table_info = SeqTableInfo(table, repeats)
53
-
54
- for det in detectors:
55
- yield from bps.prepare(det, trigger_info, wait=False, group="prep")
56
- yield from bps.prepare(flyer, table_info, wait=False, group="prep")
57
- yield from bps.wait(group="prep")