ophyd-async 0.13.2__tar.gz → 0.13.4__tar.gz

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 (329) hide show
  1. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/PKG-INFO +3 -2
  2. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/pyproject.toml +2 -1
  3. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/_version.py +3 -3
  4. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/__init__.py +2 -1
  5. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_table.py +8 -0
  6. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_core_logic.py +3 -1
  7. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/motor.py +11 -2
  8. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/pmac/_pmac_io.py +8 -4
  9. ophyd_async-0.13.4/src/ophyd_async/epics/pmac/_pmac_trajectory.py +217 -0
  10. ophyd_async-0.13.4/src/ophyd_async/epics/pmac/_pmac_trajectory_generation.py +692 -0
  11. ophyd_async-0.13.4/src/ophyd_async/epics/pmac/_utils.py +167 -0
  12. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/jungfrau/__init__.py +2 -1
  13. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/jungfrau/_controller.py +29 -11
  14. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/jungfrau/_utils.py +10 -2
  15. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/panda/__init__.py +10 -0
  16. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/panda/_block.py +14 -0
  17. ophyd_async-0.13.4/src/ophyd_async/fastcs/panda/_trigger.py +223 -0
  18. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async.egg-info/PKG-INFO +3 -2
  19. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async.egg-info/SOURCES.txt +3 -0
  20. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async.egg-info/requires.txt +2 -1
  21. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_log.py +0 -1
  22. ophyd_async-0.13.4/tests/epics/pmac/conftest.py +34 -0
  23. ophyd_async-0.13.4/tests/epics/pmac/test_pmac_trajectory.py +211 -0
  24. ophyd_async-0.13.2/tests/epics/pmac/test_pmac_utils.py → ophyd_async-0.13.4/tests/epics/pmac/test_pmac_trajectory_generation.py +535 -300
  25. ophyd_async-0.13.4/tests/epics/pmac/test_pmac_utils.py +119 -0
  26. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/test_motor.py +11 -1
  27. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/jungfrau/test_controller.py +49 -2
  28. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/jungfrau/test_utils.py +4 -2
  29. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/panda/db/panda.db +12 -1
  30. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/panda/test_panda_utils.py +4 -1
  31. ophyd_async-0.13.4/tests/fastcs/panda/test_trigger.py +351 -0
  32. ophyd_async-0.13.2/src/ophyd_async/epics/pmac/_pmac_trajectory.py +0 -116
  33. ophyd_async-0.13.2/src/ophyd_async/epics/pmac/_utils.py +0 -847
  34. ophyd_async-0.13.2/src/ophyd_async/fastcs/panda/_trigger.py +0 -103
  35. ophyd_async-0.13.2/tests/epics/pmac/test_pmac_trajectory.py +0 -170
  36. ophyd_async-0.13.2/tests/fastcs/panda/test_trigger.py +0 -156
  37. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.codecov.yml +0 -0
  38. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.copier-answers.yml +0 -0
  39. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.devcontainer/devcontainer.json +0 -0
  40. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.git-blame-ignore-revs +0 -0
  41. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/CONTRIBUTING.md +0 -0
  42. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  43. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  44. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  45. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/actions/install_requirements/action.yml +0 -0
  46. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/codeql/codeql-config.yml +0 -0
  47. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/dependabot.yml +0 -0
  48. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/pages/index.html +0 -0
  49. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/pages/make_switcher.py +0 -0
  50. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_codeql.yml +0 -0
  51. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_dist.yml +0 -0
  52. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_docs.yml +0 -0
  53. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_import_with_no_extras.yml +0 -0
  54. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_pypi.yml +0 -0
  55. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_release.yml +0 -0
  56. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_system_test.yml +0 -0
  57. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_test.yml +0 -0
  58. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/_tox.yml +0 -0
  59. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/ci.yml +0 -0
  60. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.github/workflows/periodic.yml +0 -0
  61. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.gitignore +0 -0
  62. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.gitmodules +0 -0
  63. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/.pre-commit-config.yaml +0 -0
  64. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/Dockerfile +0 -0
  65. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/LICENSE +0 -0
  66. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/README.md +0 -0
  67. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/_static/custom.css +0 -0
  68. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/conf.py +0 -0
  69. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  70. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  71. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  72. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  73. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  74. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  75. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
  76. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0008-signal-types.md +0 -0
  77. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
  78. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0010-docstring-format.md +0 -0
  79. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/0011-buffer-updates-camonitor.md +0 -0
  80. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions/COPYME +0 -0
  81. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/decisions.md +0 -0
  82. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/declarative-vs-procedural.md +0 -0
  83. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/design-goals.md +0 -0
  84. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/device-connection-strategies.md +0 -0
  85. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/devices-signals-backends.md +0 -0
  86. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/fly-scanning.md +0 -0
  87. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/plan-stubs.md +0 -0
  88. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/when-to-extend-movable.md +0 -0
  89. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations/where-device-logic.md +0 -0
  90. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/explanations.md +0 -0
  91. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/genindex.rst +0 -0
  92. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to/choose-right-baseclass.md +0 -0
  93. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to/contribute.md +0 -0
  94. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to/derive-one-signal-from-others.md +0 -0
  95. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to/implement-ad-detector.md +0 -0
  96. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to/interact-with-signals.md +0 -0
  97. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to/put-device-back.md +0 -0
  98. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to/store-and-retrieve.md +0 -0
  99. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/how-to.md +0 -0
  100. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/images/fly_scan_collection_windows_and_frames.svg +0 -0
  101. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/images/ophyd-async-logo.svg +0 -0
  102. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/images/ophyd-favicon.svg +0 -0
  103. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
  104. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/index.md +0 -0
  105. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/reference.md +0 -0
  106. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/tutorials/implementing-detectors.md +0 -0
  107. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/tutorials/implementing-devices.md +0 -0
  108. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/tutorials/installation.md +0 -0
  109. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/tutorials/using-devices.md +0 -0
  110. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/tutorials/writing-tests-for-devices.md +0 -0
  111. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/docs/tutorials.md +0 -0
  112. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/setup.cfg +0 -0
  113. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/__init__.py +0 -0
  114. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/__main__.py +0 -0
  115. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/_docs_parser.py +0 -0
  116. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_derived_signal.py +0 -0
  117. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_derived_signal_backend.py +0 -0
  118. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_detector.py +0 -0
  119. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_device.py +0 -0
  120. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_device_filler.py +0 -0
  121. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_enums.py +0 -0
  122. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_flyer.py +0 -0
  123. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_hdf_dataset.py +0 -0
  124. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_log.py +0 -0
  125. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
  126. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_protocol.py +0 -0
  127. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_providers.py +0 -0
  128. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_readable.py +0 -0
  129. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_settings.py +0 -0
  130. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_signal.py +0 -0
  131. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_signal_backend.py +0 -0
  132. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
  133. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_status.py +0 -0
  134. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_utils.py +0 -0
  135. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/core/_yaml_settings.py +0 -0
  136. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/__init__.py +0 -0
  137. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adandor/__init__.py +0 -0
  138. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adandor/_andor.py +0 -0
  139. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adandor/_andor_controller.py +0 -0
  140. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
  141. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
  142. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
  143. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
  144. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
  145. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/__init__.py +0 -0
  146. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
  147. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
  148. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_core_writer.py +0 -0
  149. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_hdf_writer.py +0 -0
  150. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
  151. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
  152. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
  153. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adcore/_utils.py +0 -0
  154. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
  155. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
  156. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
  157. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
  158. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
  159. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
  160. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
  161. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
  162. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
  163. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
  164. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
  165. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
  166. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/advimba/__init__.py +0 -0
  167. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
  168. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
  169. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
  170. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/__init__.py +0 -0
  171. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/_aioca.py +0 -0
  172. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
  173. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/_epics_device.py +0 -0
  174. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/_p4p.py +0 -0
  175. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
  176. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/_signal.py +0 -0
  177. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/core/_util.py +0 -0
  178. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/__init__.py +0 -0
  179. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/__main__.py +0 -0
  180. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/_ioc.py +0 -0
  181. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/_motor.py +0 -0
  182. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
  183. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
  184. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/_stage.py +0 -0
  185. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/motor.db +0 -0
  186. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/point_detector.db +0 -0
  187. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
  188. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/odin/__init__.py +0 -0
  189. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/odin/_odin_io.py +0 -0
  190. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/pmac/__init__.py +0 -0
  191. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/signal.py +0 -0
  192. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/testing/__init__.py +0 -0
  193. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
  194. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/testing/_utils.py +0 -0
  195. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/testing/test_records.db +0 -0
  196. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
  197. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/__init__.py +0 -0
  198. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/core.py +0 -0
  199. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/eiger/__init__.py +0 -0
  200. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/eiger/_eiger.py +0 -0
  201. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +0 -0
  202. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/eiger/_eiger_io.py +0 -0
  203. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/jungfrau/_jungfrau.py +0 -0
  204. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/jungfrau/_signals.py +0 -0
  205. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
  206. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/panda/_control.py +0 -0
  207. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
  208. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/panda/_table.py +0 -0
  209. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
  210. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  211. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
  212. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/_fly.py +0 -0
  213. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
  214. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/_panda.py +0 -0
  215. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/_settings.py +0 -0
  216. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/_utils.py +0 -0
  217. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
  218. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/py.typed +0 -0
  219. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/__init__.py +0 -0
  220. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/__main__.py +0 -0
  221. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_blob_detector.py +0 -0
  222. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
  223. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_blob_detector_writer.py +0 -0
  224. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
  225. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
  226. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_motor.py +0 -0
  227. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_pattern_generator.py +0 -0
  228. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_point_detector.py +0 -0
  229. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/sim/_stage.py +0 -0
  230. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/__init__.py +0 -0
  231. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/core/__init__.py +0 -0
  232. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/core/_base_device.py +0 -0
  233. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/core/_converters.py +0 -0
  234. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/core/_signal.py +0 -0
  235. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/core/_tango_readable.py +0 -0
  236. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/core/_tango_transport.py +0 -0
  237. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/core/_utils.py +0 -0
  238. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/demo/__init__.py +0 -0
  239. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/demo/_counter.py +0 -0
  240. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/demo/_detector.py +0 -0
  241. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/demo/_mover.py +0 -0
  242. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
  243. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
  244. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/testing/__init__.py +0 -0
  245. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
  246. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/__init__.py +0 -0
  247. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
  248. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/_assert.py +0 -0
  249. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/_mock_signal_utils.py +0 -0
  250. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/_one_of_everything.py +0 -0
  251. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/_single_derived.py +0 -0
  252. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/_utils.py +0 -0
  253. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
  254. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  255. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/src/ophyd_async.egg-info/top_level.txt +0 -0
  256. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/conftest.py +0 -0
  257. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/epics/adsim/baseline.yaml +0 -0
  258. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/epics/adsim/start_iocs.sh +0 -0
  259. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/epics/adsim/stop_iocs.sh +0 -0
  260. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/epics/adsim/test_adsim_system.py +0 -0
  261. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/epics/eiger/README.md +0 -0
  262. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
  263. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/system_tests/epics/eiger/test_eiger_system.py +0 -0
  264. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/conftest.py +0 -0
  265. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_auto_init_devices.py +0 -0
  266. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_detector.py +0 -0
  267. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_device.py +0 -0
  268. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_flyer.py +0 -0
  269. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_mock_signal_backend.py +0 -0
  270. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_multi_derived_signal.py +0 -0
  271. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_observe.py +0 -0
  272. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_protocol.py +0 -0
  273. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_providers.py +0 -0
  274. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_readable.py +0 -0
  275. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_signal.py +0 -0
  276. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_single_derived_signal.py +0 -0
  277. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_soft_signal_backend.py +0 -0
  278. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_status.py +0 -0
  279. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_subset_enum.py +0 -0
  280. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_table.py +0 -0
  281. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_utils.py +0 -0
  282. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/core/test_watchable_async_status.py +0 -0
  283. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adandor/test_andor.py +0 -0
  284. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adaravis/test_aravis.py +0 -0
  285. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adcore/test_cont_acq_detector.py +0 -0
  286. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adcore/test_detectors.py +0 -0
  287. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adcore/test_drivers.py +0 -0
  288. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adcore/test_plugins.py +0 -0
  289. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adcore/test_scans.py +0 -0
  290. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adcore/test_single_trigger.py +0 -0
  291. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adcore/test_writers.py +0 -0
  292. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adkinetix/test_kinetix.py +0 -0
  293. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adpilatus/test_pilatus.py +0 -0
  294. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/adsimdetector/test_sim.py +0 -0
  295. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/advimba/test_vimba.py +0 -0
  296. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/conftest.py +0 -0
  297. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/demo/test_epics_demo.py +0 -0
  298. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/eiger/test_odin_io.py +0 -0
  299. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/pmac/test_pmac_io.py +0 -0
  300. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/pvi/test_pvi.py +0 -0
  301. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/signal/test_common.py +0 -0
  302. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/signal/test_signals.py +0 -0
  303. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/signal/test_yaml_save_ca.yaml +0 -0
  304. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/signal/test_yaml_save_pva.yaml +0 -0
  305. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/epics/test_areadetector_subclass_naming.py +0 -0
  306. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/eiger/test_eiger_controller.py +0 -0
  307. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/eiger/test_eiger_detector.py +0 -0
  308. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/jungfrau/__init__.py +0 -0
  309. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/panda/test_hdf_panda.py +0 -0
  310. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/panda/test_panda_connect.py +0 -0
  311. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/panda/test_panda_control.py +0 -0
  312. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/panda/test_seq_table.py +0 -0
  313. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/fastcs/panda/test_writer.py +0 -0
  314. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/plan_stubs/test_ensure_connected.py +0 -0
  315. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/plan_stubs/test_fly.py +0 -0
  316. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/plan_stubs/test_settings.py +0 -0
  317. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/plan_stubs/test_setup.py +0 -0
  318. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/sim/__init__.py +0 -0
  319. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/sim/test_sim_blob_detector.py +0 -0
  320. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/sim/test_sim_motor.py +0 -0
  321. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/tango/conftest.py +0 -0
  322. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/tango/context_subprocess.py +0 -0
  323. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/tango/test_base_device.py +0 -0
  324. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/tango/test_tango_signals.py +0 -0
  325. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/tango/test_tango_transport.py +0 -0
  326. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/test_cli.py +0 -0
  327. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/test_data/test_yaml_config_save.yaml +0 -0
  328. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/test_data/test_yaml_save.yaml +0 -0
  329. {ophyd_async-0.13.2 → ophyd_async-0.13.4}/tests/test_tutorials.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.13.2
3
+ Version: 0.13.4
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
@@ -49,7 +49,7 @@ Requires-Dist: colorlog
49
49
  Requires-Dist: pydantic>=2.0
50
50
  Requires-Dist: pydantic-numpy
51
51
  Requires-Dist: stamina>=23.1.0
52
- Requires-Dist: scanspec>=1.0a1
52
+ Requires-Dist: scanspec>=0.8
53
53
  Requires-Dist: velocity-profile
54
54
  Provides-Extra: sim
55
55
  Requires-Dist: h5py; extra == "sim"
@@ -88,6 +88,7 @@ Requires-Dist: pytest-forked; extra == "dev"
88
88
  Requires-Dist: pytest-rerunfailures; extra == "dev"
89
89
  Requires-Dist: pytest-timeout; extra == "dev"
90
90
  Requires-Dist: ruff; extra == "dev"
91
+ Requires-Dist: scanspec>=1.0a1; extra == "dev"
91
92
  Requires-Dist: sphinx-autobuild; extra == "dev"
92
93
  Requires-Dist: sphinx-autodoc2; extra == "dev"
93
94
  Requires-Dist: sphinxcontrib-mermaid; extra == "dev"
@@ -21,7 +21,7 @@ dependencies = [
21
21
  "pydantic>=2.0",
22
22
  "pydantic-numpy",
23
23
  "stamina>=23.1.0",
24
- "scanspec>=1.0a1",
24
+ "scanspec>=0.8",
25
25
  "velocity-profile",
26
26
  ]
27
27
  dynamic = ["version"]
@@ -60,6 +60,7 @@ dev = [
60
60
  "pytest-rerunfailures",
61
61
  "pytest-timeout",
62
62
  "ruff",
63
+ "scanspec>=1.0a1",
63
64
  "sphinx-autobuild",
64
65
  "sphinx-autodoc2",
65
66
  "sphinxcontrib-mermaid",
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.13.2'
32
- __version_tuple__ = version_tuple = (0, 13, 2)
31
+ __version__ = version = '0.13.4'
32
+ __version_tuple__ = version_tuple = (0, 13, 4)
33
33
 
34
- __commit_id__ = commit_id = 'gc5aa76fc4'
34
+ __commit_id__ = commit_id = 'gb42c37bf9'
@@ -78,7 +78,7 @@ from ._signal_backend import (
78
78
  )
79
79
  from ._soft_signal_backend import SoftSignalBackend
80
80
  from ._status import AsyncStatus, WatchableAsyncStatus, completed_status
81
- from ._table import Table
81
+ from ._table import Table, TableSubclass
82
82
  from ._utils import (
83
83
  CALCULATE_TIMEOUT,
84
84
  DEFAULT_TIMEOUT,
@@ -221,4 +221,5 @@ __all__ = [
221
221
  "EnableDisable",
222
222
  "InOut",
223
223
  "OnOff",
224
+ "TableSubclass",
224
225
  ]
@@ -13,6 +13,7 @@ TableSubclass = TypeVar("TableSubclass", bound="Table")
13
13
 
14
14
 
15
15
  def _concat(value1, value2):
16
+ """Concatenate two values, supports both NumPy arrays and generic types."""
16
17
  if isinstance(value1, np.ndarray):
17
18
  return np.concatenate((value1, value2))
18
19
  else:
@@ -20,6 +21,8 @@ def _concat(value1, value2):
20
21
 
21
22
 
22
23
  def _make_default_factory(dtype: np.dtype) -> Callable[[], np.ndarray]:
24
+ """Creates a default factory, returns an empty Numpy array of a specified dtype."""
25
+
23
26
  def numpy_array_default_factory() -> np.ndarray:
24
27
  return np.array([], dtype)
25
28
 
@@ -91,6 +94,11 @@ class Table(ConfinedModel):
91
94
  raise TypeError(f"Cannot use annotation {anno} in a Table")
92
95
  cls.__annotations__[k] = new_anno
93
96
 
97
+ @classmethod
98
+ def empty(cls: type[TableSubclass]) -> TableSubclass:
99
+ """Makes an empty table with zero length columns."""
100
+ return cls() # type: ignore
101
+
94
102
  def __add__(self, right: TableSubclass) -> TableSubclass:
95
103
  """Concatenate the arrays in field values."""
96
104
  cls = type(right)
@@ -34,9 +34,11 @@ class ADBaseController(DetectorController, Generic[ADBaseIOT]):
34
34
  self,
35
35
  driver: ADBaseIOT,
36
36
  good_states: frozenset[ADState] = DEFAULT_GOOD_STATES,
37
+ image_mode: ADImageMode = ADImageMode.MULTIPLE,
37
38
  ) -> None:
38
39
  self.driver: ADBaseIOT = driver
39
40
  self.good_states = good_states
41
+ self.image_mode = image_mode
40
42
  self.frame_timeout = DEFAULT_TIMEOUT
41
43
  self._arm_status: AsyncStatus | None = None
42
44
 
@@ -52,7 +54,7 @@ class ADBaseController(DetectorController, Generic[ADBaseIOT]):
52
54
  )
53
55
  await asyncio.gather(
54
56
  self.driver.num_images.set(trigger_info.total_number_of_exposures),
55
- self.driver.image_mode.set(ADImageMode.MULTIPLE),
57
+ self.driver.image_mode.set(self.image_mode),
56
58
  )
57
59
 
58
60
  async def arm(self):
@@ -107,18 +107,27 @@ class Motor(
107
107
  self.user_readback.set_name(name)
108
108
 
109
109
  async def check_motor_limit(self, abs_start_pos: float, abs_end_pos: float):
110
- """Check the motor limit with the absolute positions."""
110
+ """Check the positions are within limits.
111
+
112
+ Will raise a MotorLimitsException if the given absolute positions will be
113
+ outside the motor soft limits.
114
+ """
111
115
  motor_lower_limit, motor_upper_limit, egu = await asyncio.gather(
112
116
  self.low_limit_travel.get_value(),
113
117
  self.high_limit_travel.get_value(),
114
118
  self.motor_egu.get_value(),
115
119
  )
120
+
121
+ # EPICS motor record treats limits of 0, 0 as no limit
122
+ if motor_lower_limit == 0 and motor_upper_limit == 0:
123
+ return
124
+
116
125
  if (
117
126
  not motor_upper_limit >= abs_start_pos >= motor_lower_limit
118
127
  or not motor_upper_limit >= abs_end_pos >= motor_lower_limit
119
128
  ):
120
129
  raise MotorLimitsException(
121
- f"Motor trajectory for requested fly/move is from "
130
+ f"{self.name} motor trajectory for requested fly/move is from "
122
131
  f"{abs_start_pos}{egu} to "
123
132
  f"{abs_end_pos}{egu} but motor limits are "
124
133
  f"{motor_lower_limit}{egu} <= x <= {motor_upper_limit}{egu} "
@@ -4,7 +4,7 @@ import numpy as np
4
4
 
5
5
  from ophyd_async.core import Array1D, Device, DeviceVector, StandardReadable
6
6
  from ophyd_async.epics import motor
7
- from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
7
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x
8
8
 
9
9
  CS_LETTERS = "ABCUVWXYZ"
10
10
 
@@ -40,11 +40,15 @@ class PmacTrajectoryIO(StandardReadable):
40
40
  for i, letter in enumerate(CS_LETTERS)
41
41
  }
42
42
  )
43
+ self.total_points = epics_signal_r(int, f"{prefix}TotalPoints_RBV")
43
44
  self.points_to_build = epics_signal_rw(int, prefix + "ProfilePointsToBuild")
44
- self.build_profile = epics_signal_rw(bool, prefix + "ProfileBuild")
45
+ self.build_profile = epics_signal_x(prefix + "ProfileBuild")
46
+ self.append_profile = epics_signal_x(prefix + "ProfileAppend")
47
+ # This should be a SignalX, but because it is a Busy record, must
48
+ # be a SignalRW to be waited on in PmacTrajectoryTriggerLogic.
49
+ # TODO: Change record type to bo from busy (https://github.com/DiamondLightSource/pmac/issues/154)
45
50
  self.execute_profile = epics_signal_rw(bool, prefix + "ProfileExecute")
46
- self.scan_percent = epics_signal_r(float, prefix + "TscanPercent_RBV")
47
- self.abort_profile = epics_signal_rw(bool, prefix + "ProfileAbort")
51
+ self.abort_profile = epics_signal_x(prefix + "ProfileAbort")
48
52
  self.profile_cs_name = epics_signal_rw(str, prefix + "ProfileCsName")
49
53
  self.calculate_velocities = epics_signal_rw(bool, prefix + "ProfileCalcVel")
50
54
 
@@ -0,0 +1,217 @@
1
+ import asyncio
2
+ from dataclasses import dataclass
3
+
4
+ import numpy as np
5
+ from scanspec.core import Path, Slice
6
+ from scanspec.specs import Spec
7
+
8
+ from ophyd_async.core import (
9
+ DEFAULT_TIMEOUT,
10
+ AsyncStatus,
11
+ FlyerController,
12
+ error_if_none,
13
+ observe_value,
14
+ set_and_wait_for_value,
15
+ wait_for_value,
16
+ )
17
+ from ophyd_async.epics.motor import Motor
18
+ from ophyd_async.epics.pmac import PmacIO
19
+ from ophyd_async.epics.pmac._pmac_io import CS_LETTERS
20
+ from ophyd_async.epics.pmac._pmac_trajectory_generation import PVT, Trajectory
21
+ from ophyd_async.epics.pmac._utils import (
22
+ _PmacMotorInfo,
23
+ calculate_ramp_position_and_duration,
24
+ )
25
+
26
+ # PMAC durations are in milliseconds
27
+ # We must convert from scanspec durations (seconds) to milliseconds
28
+ # PMAC motion program multiples durations by 0.001
29
+ # (see https://github.com/DiamondLightSource/pmac/blob/afe81f8bb9179c3a20eff351f30bc6cfd1539ad9/pmacApp/pmc/trajectory_scan_code_ppmac.pmc#L241)
30
+ # Therefore, we must divide scanspec durations by 10e-6
31
+ TICK_S = 0.000001
32
+ SLICE_SIZE = 4000
33
+
34
+
35
+ @dataclass
36
+ class PmacPrepareContext:
37
+ path: Path
38
+ motor_info: _PmacMotorInfo
39
+ ramp_up_time: float
40
+
41
+
42
+ class PmacTrajectoryTriggerLogic(FlyerController):
43
+ def __init__(self, pmac: PmacIO) -> None:
44
+ self.pmac = pmac
45
+ self._next_pvt: PVT | None
46
+ self._loaded: int = 0
47
+ self._trajectory_status: AsyncStatus | None = None
48
+ self._prepare_context: PmacPrepareContext | None = None
49
+
50
+ async def prepare(self, value: Spec[Motor]):
51
+ path = Path(value.calculate())
52
+ slice = path.consume(SLICE_SIZE)
53
+ path_length = len(path)
54
+ motors = slice.axes()
55
+ motor_info = await _PmacMotorInfo.from_motors(self.pmac, motors)
56
+ ramp_up_pos, ramp_up_time = calculate_ramp_position_and_duration(
57
+ slice, motor_info, True
58
+ )
59
+ self._prepare_context = PmacPrepareContext(
60
+ path=path, motor_info=motor_info, ramp_up_time=ramp_up_time
61
+ )
62
+ await asyncio.gather(
63
+ self._build_trajectory(motor_info, slice, path_length, ramp_up_time),
64
+ self._move_to_start(motor_info, ramp_up_pos),
65
+ )
66
+
67
+ async def kickoff(self):
68
+ prepare_context = error_if_none(
69
+ self._prepare_context, "Cannot kickoff. Must call prepare first."
70
+ )
71
+ self._prepare_context = None
72
+ self._trajectory_status = self._execute_trajectory(
73
+ prepare_context.path, prepare_context.motor_info
74
+ )
75
+ # Wait for the ramp up to happen
76
+ await wait_for_value(
77
+ self.pmac.trajectory.total_points,
78
+ lambda v: v >= 1,
79
+ prepare_context.ramp_up_time + DEFAULT_TIMEOUT,
80
+ )
81
+
82
+ async def complete(self):
83
+ trajectory_status = error_if_none(
84
+ self._trajectory_status, "Cannot complete. Must call kickoff first."
85
+ )
86
+ await trajectory_status
87
+ # Reset trajectory status and number of loaded points
88
+ self._trajectory_status = None
89
+ self._loaded = 0
90
+
91
+ async def stop(self):
92
+ await self.pmac.trajectory.abort_profile.trigger()
93
+
94
+ @AsyncStatus.wrap
95
+ async def _execute_trajectory(self, path: Path, motor_info: _PmacMotorInfo):
96
+ execute_status = self.pmac.trajectory.execute_profile.set(
97
+ True, wait=True, timeout=None
98
+ )
99
+ # We consume SLICE_SIZE from self.path and parse a trajectory
100
+ # containing at least 2 * SLICE_SIZE, as a gapless trajectory
101
+ # will contain 2 points per slice frame. If gaps are present,
102
+ # additional points are inserted, overfilling the buffer.
103
+ min_buffer_size = SLICE_SIZE * 2
104
+ async for current_point in observe_value(
105
+ self.pmac.trajectory.total_points,
106
+ done_status=execute_status,
107
+ timeout=DEFAULT_TIMEOUT,
108
+ ):
109
+ # Ensure we maintain a minimum buffer size, if we have more points to append
110
+ if len(path) != 0 and self._loaded - current_point < min_buffer_size:
111
+ # We have less than SLICE_SIZE * 2 points in the buffer, so refill
112
+ next_slice = path.consume(SLICE_SIZE)
113
+ path_length = len(path)
114
+ await self._append_trajectory(next_slice, path_length, motor_info)
115
+
116
+ async def _append_trajectory(
117
+ self, slice: Slice, path_length: int, motor_info: _PmacMotorInfo
118
+ ):
119
+ trajectory = await self._parse_trajectory(slice, path_length, motor_info)
120
+ await self._set_trajectory_arrays(trajectory, motor_info)
121
+ await self.pmac.trajectory.append_profile.trigger()
122
+
123
+ async def _build_trajectory(
124
+ self,
125
+ motor_info: _PmacMotorInfo,
126
+ slice: Slice,
127
+ path_length: int,
128
+ ramp_up_time: float,
129
+ ):
130
+ trajectory = await self._parse_trajectory(
131
+ slice, path_length, motor_info, ramp_up_time
132
+ )
133
+ use_axis = {
134
+ axis + 1: (axis in motor_info.motor_cs_index.values())
135
+ for axis in range(len(CS_LETTERS))
136
+ }
137
+
138
+ coros = [
139
+ self.pmac.trajectory.profile_cs_name.set(motor_info.cs_port),
140
+ self.pmac.trajectory.calculate_velocities.set(False),
141
+ self._set_trajectory_arrays(trajectory, motor_info),
142
+ ] + [
143
+ self.pmac.trajectory.use_axis[number].set(use)
144
+ for number, use in use_axis.items()
145
+ ]
146
+
147
+ await asyncio.gather(*coros)
148
+ await self.pmac.trajectory.build_profile.trigger()
149
+
150
+ async def _parse_trajectory(
151
+ self,
152
+ slice: Slice,
153
+ path_length: int,
154
+ motor_info: _PmacMotorInfo,
155
+ ramp_up_time: float | None = None,
156
+ ) -> Trajectory:
157
+ trajectory, exit_pvt = Trajectory.from_slice(
158
+ slice,
159
+ motor_info,
160
+ None if ramp_up_time else self._next_pvt,
161
+ ramp_up_time=ramp_up_time,
162
+ )
163
+
164
+ if path_length == 0:
165
+ ramp_down_pos, ramp_down_time = calculate_ramp_position_and_duration(
166
+ slice, motor_info, False
167
+ )
168
+ trajectory = trajectory.with_ramp_down(
169
+ exit_pvt, ramp_down_pos, ramp_down_time, 0
170
+ )
171
+ self._next_pvt = exit_pvt
172
+ self._loaded += len(trajectory)
173
+
174
+ return trajectory
175
+
176
+ async def _set_trajectory_arrays(
177
+ self, trajectory: Trajectory, motor_info: _PmacMotorInfo
178
+ ):
179
+ coros = []
180
+ for motor, number in motor_info.motor_cs_index.items():
181
+ coros.append(
182
+ self.pmac.trajectory.positions[number + 1].set(
183
+ trajectory.positions[motor]
184
+ )
185
+ )
186
+ coros.append(
187
+ self.pmac.trajectory.velocities[number + 1].set(
188
+ trajectory.velocities[motor]
189
+ )
190
+ )
191
+ coros.extend(
192
+ [
193
+ self.pmac.trajectory.time_array.set(trajectory.durations / TICK_S),
194
+ self.pmac.trajectory.user_array.set(trajectory.user_programs),
195
+ self.pmac.trajectory.points_to_build.set(len(trajectory.durations)),
196
+ ]
197
+ )
198
+ await asyncio.gather(*coros)
199
+
200
+ async def _move_to_start(
201
+ self, motor_info: _PmacMotorInfo, ramp_up_position: dict[Motor, np.float64]
202
+ ):
203
+ coord = self.pmac.coord[motor_info.cs_number]
204
+ coros = []
205
+ await coord.defer_moves.set(True)
206
+ for motor, position in ramp_up_position.items():
207
+ coros.append(
208
+ set_and_wait_for_value(
209
+ coord.cs_axis_setpoint[motor_info.motor_cs_index[motor] + 1],
210
+ position,
211
+ set_timeout=10,
212
+ wait_for_set_completion=False,
213
+ )
214
+ )
215
+ statuses = await asyncio.gather(*coros)
216
+ await coord.defer_moves.set(False)
217
+ await asyncio.gather(*statuses)