ophyd-async 0.12.2__tar.gz → 0.13.0__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 (307) hide show
  1. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/PKG-INFO +3 -2
  2. ophyd_async-0.13.0/docs/explanations/decisions/0011-buffer-updates-camonitor.md +33 -0
  3. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/pyproject.toml +3 -2
  4. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/_version.py +2 -2
  5. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/__init__.py +11 -0
  6. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_detector.py +6 -9
  7. ophyd_async-0.13.0/src/ophyd_async/core/_enums.py +21 -0
  8. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adaravis/__init__.py +1 -2
  9. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adaravis/_aravis_controller.py +4 -4
  10. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adaravis/_aravis_io.py +2 -12
  11. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/__init__.py +4 -4
  12. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_core_io.py +59 -7
  13. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_core_logic.py +4 -3
  14. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_core_writer.py +4 -5
  15. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_utils.py +36 -11
  16. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/advimba/__init__.py +0 -2
  17. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/advimba/_vimba_controller.py +6 -9
  18. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/advimba/_vimba_io.py +3 -10
  19. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/__init__.py +2 -0
  20. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/_aioca.py +6 -2
  21. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/_util.py +12 -0
  22. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/eiger/_odin_io.py +25 -7
  23. ophyd_async-0.13.0/src/ophyd_async/epics/pmac/__init__.py +8 -0
  24. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/pmac/_pmac_io.py +34 -23
  25. ophyd_async-0.13.0/src/ophyd_async/epics/pmac/_utils.py +231 -0
  26. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/eiger/_eiger.py +1 -1
  27. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/eiger/_eiger_io.py +2 -1
  28. ophyd_async-0.13.0/src/ophyd_async/plan_stubs/_nd_attributes.py +48 -0
  29. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async.egg-info/PKG-INFO +3 -2
  30. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async.egg-info/SOURCES.txt +5 -0
  31. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async.egg-info/requires.txt +2 -1
  32. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_detector.py +0 -17
  33. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_device.py +1 -0
  34. ophyd_async-0.13.0/tests/epics/adcore/test_plugins.py +9 -0
  35. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adcore/test_writers.py +46 -0
  36. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/advimba/test_vimba.py +17 -21
  37. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/eiger/test_odin_io.py +53 -29
  38. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/pmac/test_pmac_io.py +31 -9
  39. ophyd_async-0.13.0/tests/epics/pmac/test_pmac_utils.py +324 -0
  40. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/signal/test_signals.py +45 -2
  41. ophyd_async-0.13.0/tests/epics/test_areadetector_subclass_naming.py +66 -0
  42. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/test_motor.py +1 -0
  43. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/eiger/test_eiger_detector.py +11 -2
  44. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/sim/test_sim_motor.py +1 -0
  45. ophyd_async-0.12.2/src/ophyd_async/epics/pmac/__init__.py +0 -3
  46. ophyd_async-0.12.2/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -74
  47. ophyd_async-0.12.2/tests/epics/test_areadetector_subclass_naming.py +0 -32
  48. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.codecov.yml +0 -0
  49. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.copier-answers.yml +0 -0
  50. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.devcontainer/devcontainer.json +0 -0
  51. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.git-blame-ignore-revs +0 -0
  52. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/CONTRIBUTING.md +0 -0
  53. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  54. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  55. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  56. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/actions/install_requirements/action.yml +0 -0
  57. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/codeql/codeql-config.yml +0 -0
  58. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/dependabot.yml +0 -0
  59. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/pages/index.html +0 -0
  60. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/pages/make_switcher.py +0 -0
  61. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_check.yml +0 -0
  62. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_codeql.yml +0 -0
  63. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_dist.yml +0 -0
  64. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_docs.yml +0 -0
  65. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_import_with_no_extras.yml +0 -0
  66. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_pypi.yml +0 -0
  67. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_release.yml +0 -0
  68. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_test.yml +0 -0
  69. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/_tox.yml +0 -0
  70. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/ci.yml +0 -0
  71. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.github/workflows/periodic.yml +0 -0
  72. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.gitignore +0 -0
  73. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/.pre-commit-config.yaml +0 -0
  74. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/Dockerfile +0 -0
  75. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/LICENSE +0 -0
  76. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/README.md +0 -0
  77. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/_static/custom.css +0 -0
  78. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/conf.py +0 -0
  79. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  80. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  81. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  82. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  83. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  84. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  85. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
  86. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0008-signal-types.md +0 -0
  87. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
  88. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/0010-docstring-format.md +0 -0
  89. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions/COPYME +0 -0
  90. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/decisions.md +0 -0
  91. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/declarative-vs-procedural.md +0 -0
  92. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/design-goals.md +0 -0
  93. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/device-connection-strategies.md +0 -0
  94. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/devices-signals-backends.md +0 -0
  95. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/fly-scanning.md +0 -0
  96. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/plan-stubs.md +0 -0
  97. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations/where-device-logic.md +0 -0
  98. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/explanations.md +0 -0
  99. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/genindex.rst +0 -0
  100. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to/choose-right-baseclass.md +0 -0
  101. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to/contribute.md +0 -0
  102. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to/derive-one-signal-from-others.md +0 -0
  103. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to/implement-ad-detector.md +0 -0
  104. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to/interact-with-signals.md +0 -0
  105. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to/put-device-back.md +0 -0
  106. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to/store-and-retrieve.md +0 -0
  107. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/how-to.md +0 -0
  108. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/images/fly_scan_collection_windows_and_frames.svg +0 -0
  109. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/images/ophyd-async-logo.svg +0 -0
  110. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/images/ophyd-favicon.svg +0 -0
  111. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
  112. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/index.md +0 -0
  113. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/reference.md +0 -0
  114. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/tutorials/implementing-detectors.md +0 -0
  115. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/tutorials/implementing-devices.md +0 -0
  116. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/tutorials/installation.md +0 -0
  117. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/tutorials/using-devices.md +0 -0
  118. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/tutorials/writing-tests-for-devices.md +0 -0
  119. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/docs/tutorials.md +0 -0
  120. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/setup.cfg +0 -0
  121. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/__init__.py +0 -0
  122. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/__main__.py +0 -0
  123. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/_docs_parser.py +0 -0
  124. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_derived_signal.py +0 -0
  125. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_derived_signal_backend.py +0 -0
  126. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_device.py +0 -0
  127. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_device_filler.py +0 -0
  128. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_flyer.py +0 -0
  129. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_hdf_dataset.py +0 -0
  130. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_log.py +0 -0
  131. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
  132. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_protocol.py +0 -0
  133. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_providers.py +0 -0
  134. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_readable.py +0 -0
  135. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_settings.py +0 -0
  136. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_signal.py +0 -0
  137. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_signal_backend.py +0 -0
  138. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
  139. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_status.py +0 -0
  140. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_table.py +0 -0
  141. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_utils.py +0 -0
  142. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/core/_yaml_settings.py +0 -0
  143. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/__init__.py +0 -0
  144. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adandor/__init__.py +0 -0
  145. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adandor/_andor.py +0 -0
  146. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adandor/_andor_controller.py +0 -0
  147. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
  148. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
  149. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
  150. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_hdf_writer.py +6 -6
  151. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
  152. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
  153. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
  154. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
  155. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
  156. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
  157. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
  158. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
  159. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
  160. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
  161. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
  162. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
  163. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
  164. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
  165. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
  166. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
  167. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
  168. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/_epics_device.py +0 -0
  169. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/_p4p.py +0 -0
  170. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
  171. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/core/_signal.py +0 -0
  172. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/__init__.py +0 -0
  173. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/__main__.py +0 -0
  174. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/_ioc.py +0 -0
  175. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/_motor.py +0 -0
  176. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
  177. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
  178. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/_stage.py +0 -0
  179. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/motor.db +0 -0
  180. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/point_detector.db +0 -0
  181. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
  182. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/eiger/__init__.py +0 -0
  183. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/motor.py +0 -0
  184. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/signal.py +0 -0
  185. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/testing/__init__.py +0 -0
  186. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
  187. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/testing/_utils.py +0 -0
  188. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/testing/test_records.db +0 -0
  189. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
  190. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/__init__.py +0 -0
  191. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/core.py +0 -0
  192. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/eiger/__init__.py +0 -0
  193. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +0 -0
  194. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
  195. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
  196. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/panda/_block.py +0 -0
  197. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/panda/_control.py +0 -0
  198. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
  199. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/panda/_table.py +0 -0
  200. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
  201. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
  202. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  203. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
  204. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/plan_stubs/_fly.py +0 -0
  205. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/plan_stubs/_panda.py +0 -0
  206. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/plan_stubs/_settings.py +0 -0
  207. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/plan_stubs/_utils.py +0 -0
  208. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
  209. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/py.typed +0 -0
  210. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/__init__.py +0 -0
  211. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/__main__.py +0 -0
  212. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_blob_detector.py +0 -0
  213. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
  214. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_blob_detector_writer.py +0 -0
  215. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
  216. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
  217. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_motor.py +0 -0
  218. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_pattern_generator.py +0 -0
  219. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_point_detector.py +0 -0
  220. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/sim/_stage.py +0 -0
  221. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/__init__.py +0 -0
  222. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/core/__init__.py +0 -0
  223. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/core/_base_device.py +0 -0
  224. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/core/_converters.py +0 -0
  225. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/core/_signal.py +0 -0
  226. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/core/_tango_readable.py +0 -0
  227. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/core/_tango_transport.py +0 -0
  228. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/core/_utils.py +0 -0
  229. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/demo/__init__.py +0 -0
  230. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/demo/_counter.py +0 -0
  231. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/demo/_detector.py +0 -0
  232. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/demo/_mover.py +0 -0
  233. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
  234. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
  235. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/testing/__init__.py +0 -0
  236. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
  237. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/__init__.py +0 -0
  238. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
  239. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/_assert.py +0 -0
  240. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/_mock_signal_utils.py +0 -0
  241. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/_one_of_everything.py +0 -0
  242. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/_single_derived.py +0 -0
  243. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/_utils.py +0 -0
  244. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
  245. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  246. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/src/ophyd_async.egg-info/top_level.txt +0 -0
  247. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/system_tests/epics/eiger/README.md +0 -0
  248. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
  249. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/system_tests/epics/eiger/test_eiger_system.py +0 -0
  250. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/conftest.py +0 -0
  251. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_auto_init_devices.py +0 -0
  252. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_flyer.py +0 -0
  253. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_log.py +0 -0
  254. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_mock_signal_backend.py +0 -0
  255. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_multi_derived_signal.py +0 -0
  256. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_observe.py +0 -0
  257. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_protocol.py +0 -0
  258. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_providers.py +0 -0
  259. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_readable.py +0 -0
  260. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_signal.py +0 -0
  261. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_single_derived_signal.py +0 -0
  262. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_soft_signal_backend.py +0 -0
  263. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_status.py +0 -0
  264. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_subset_enum.py +0 -0
  265. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_table.py +0 -0
  266. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_utils.py +0 -0
  267. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/core/test_watchable_async_status.py +0 -0
  268. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adandor/test_andor.py +0 -0
  269. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adaravis/test_aravis.py +0 -0
  270. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adcore/test_cont_acq_detector.py +0 -0
  271. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adcore/test_detectors.py +0 -0
  272. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adcore/test_drivers.py +0 -0
  273. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adcore/test_scans.py +0 -0
  274. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adcore/test_single_trigger.py +0 -0
  275. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adkinetix/test_kinetix.py +0 -0
  276. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adpilatus/test_pilatus.py +0 -0
  277. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/adsimdetector/test_sim.py +0 -0
  278. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/conftest.py +0 -0
  279. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/demo/test_epics_demo.py +0 -0
  280. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/pvi/test_pvi.py +0 -0
  281. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/signal/test_common.py +0 -0
  282. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/signal/test_yaml_save_ca.yaml +0 -0
  283. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/epics/signal/test_yaml_save_pva.yaml +0 -0
  284. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/eiger/test_eiger_controller.py +0 -0
  285. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/db/panda.db +0 -0
  286. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/test_hdf_panda.py +0 -0
  287. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/test_panda_connect.py +0 -0
  288. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/test_panda_control.py +0 -0
  289. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/test_panda_utils.py +0 -0
  290. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/test_seq_table.py +0 -0
  291. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/test_trigger.py +0 -0
  292. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/fastcs/panda/test_writer.py +0 -0
  293. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/plan_stubs/test_ensure_connected.py +0 -0
  294. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/plan_stubs/test_fly.py +0 -0
  295. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/plan_stubs/test_settings.py +0 -0
  296. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/plan_stubs/test_setup.py +0 -0
  297. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/sim/__init__.py +0 -0
  298. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/sim/test_sim_blob_detector.py +0 -0
  299. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/tango/conftest.py +0 -0
  300. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/tango/context_subprocess.py +0 -0
  301. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/tango/test_base_device.py +0 -0
  302. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/tango/test_tango_signals.py +0 -0
  303. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/tango/test_tango_transport.py +0 -0
  304. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/test_cli.py +0 -0
  305. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/test_data/test_yaml_config_save.yaml +0 -0
  306. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/test_data/test_yaml_save.yaml +0 -0
  307. {ophyd_async-0.12.2 → ophyd_async-0.13.0}/tests/test_tutorials.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.12.2
3
+ Version: 0.13.0
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,10 +49,11 @@ 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
53
  Provides-Extra: sim
53
54
  Requires-Dist: h5py; extra == "sim"
54
55
  Provides-Extra: ca
55
- Requires-Dist: aioca>=1.6; extra == "ca"
56
+ Requires-Dist: aioca>=2.0a4; extra == "ca"
56
57
  Provides-Extra: pva
57
58
  Requires-Dist: p4p>=4.2.0; extra == "pva"
58
59
  Provides-Extra: tango
@@ -0,0 +1,33 @@
1
+ # 11. Buffer updates when using `camonitor`
2
+
3
+ Date: 2025-07-30
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The ChannelAccess signal backend uses aioca.camonitor to subscribe to changes in PV values. By default it deals with backpressure by dropping excessive updates that it is too slow to handle. It also has a mode whereby it will buffer the updates, lagging behind if there are too many.
12
+
13
+ ```python
14
+ # The following will buffer every update to the PV
15
+ aioca.camonitor(my_pv, all_updates=True)
16
+ ```
17
+
18
+ ## Decision
19
+
20
+ Default `all_updates` to `True` in the ChannelAccess backend, but provide a feature flag via an environment variable so it can be reverted at runtime if necessary.
21
+
22
+ ```bash
23
+ # The following should restore the old behavior
24
+ export OPHYD_ASYNC_EPICS_CA_KEEP_ALL_UPDATES=False
25
+ ```
26
+
27
+ ## Consequences
28
+
29
+ If backpressure is causing a problem, ophyd-async will slow down and lag behind. This is deemed to be an easier problem to spot and debug than updates being silently dropped.
30
+
31
+ It is the responsibility of IOCs to not push updates too quickly (<=10Hz) rather than the responsibility of ophyd-async to handle them. If an IOC is pushing updates too quickly, it should be fixed.
32
+
33
+ There may be unknown bugs and race conditions exposed by this change, they can be temporarily remedied by disabling the feature (see above).
@@ -20,7 +20,8 @@ dependencies = [
20
20
  "colorlog",
21
21
  "pydantic>=2.0",
22
22
  "pydantic-numpy",
23
- "stamina>=23.1.0"
23
+ "stamina>=23.1.0",
24
+ "scanspec>=1.0a1",
24
25
  ]
25
26
  dynamic = ["version"]
26
27
  license.file = "LICENSE"
@@ -29,7 +30,7 @@ requires-python = ">=3.10"
29
30
 
30
31
  [project.optional-dependencies]
31
32
  sim = ["h5py"]
32
- ca = ["aioca>=1.6"]
33
+ ca = ["aioca>=2.0a4"]
33
34
  pva = ["p4p>=4.2.0"]
34
35
  tango = ["pytango==10.0.0"]
35
36
  demo = ["ipython", "matplotlib", "pyqt6"]
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.12.2'
21
- __version_tuple__ = version_tuple = (0, 12, 2)
20
+ __version__ = version = '0.13.0'
21
+ __version_tuple__ = version_tuple = (0, 13, 0)
@@ -16,6 +16,12 @@ from ._detector import (
16
16
  )
17
17
  from ._device import Device, DeviceConnector, DeviceVector, init_devices
18
18
  from ._device_filler import DeviceFiller
19
+ from ._enums import (
20
+ EnabledDisabled,
21
+ EnableDisable,
22
+ InOut,
23
+ OnOff,
24
+ )
19
25
  from ._flyer import FlyerController, FlyMotorInfo, StandardFlyer
20
26
  from ._hdf_dataset import HDFDatasetDescription, HDFDocumentComposer
21
27
  from ._log import config_ophyd_async_logging
@@ -209,4 +215,9 @@ __all__ = [
209
215
  # Back compat - delete before 1.0
210
216
  "ConfigSignal",
211
217
  "HintedSignal",
218
+ # Standard enums
219
+ "EnabledDisabled",
220
+ "EnableDisable",
221
+ "InOut",
222
+ "OnOff",
212
223
  ]
@@ -104,7 +104,11 @@ class DetectorController(ABC):
104
104
 
105
105
  @abstractmethod
106
106
  def get_deadtime(self, exposure: float | None) -> float:
107
- """For a given exposure, how long should the time between exposures be."""
107
+ """Get state-independent deadtime.
108
+
109
+ For a given exposure, what is the safest minimum time between exposures that
110
+ can be determined without reading signals.
111
+ """
108
112
 
109
113
  @abstractmethod
110
114
  async def prepare(self, trigger_info: TriggerInfo) -> None:
@@ -313,14 +317,7 @@ class StandardDetector(
313
317
  if value.trigger != DetectorTrigger.INTERNAL and not value.deadtime:
314
318
  msg = "Deadtime must be supplied when in externally triggered mode"
315
319
  raise ValueError(msg)
316
- required_deadtime = self._controller.get_deadtime(value.livetime)
317
- if value.deadtime and required_deadtime > value.deadtime:
318
- msg = (
319
- f"Detector {self._controller} needs at least {required_deadtime}s "
320
- f"deadtime, but trigger logic provides only {value.deadtime}s"
321
- )
322
- raise ValueError(msg)
323
- elif not value.deadtime:
320
+ if not value.deadtime:
324
321
  value.deadtime = self._controller.get_deadtime(value.livetime)
325
322
  self._trigger_info = value
326
323
  self._number_of_events_iter = iter(
@@ -0,0 +1,21 @@
1
+ from ._utils import StrictEnum
2
+
3
+
4
+ class OnOff(StrictEnum):
5
+ ON = "On"
6
+ OFF = "Off"
7
+
8
+
9
+ class EnableDisable(StrictEnum):
10
+ ENABLE = "Enable"
11
+ DISABLE = "Disable"
12
+
13
+
14
+ class EnabledDisabled(StrictEnum):
15
+ ENABLED = "Enabled"
16
+ DISABLED = "Disabled"
17
+
18
+
19
+ class InOut(StrictEnum):
20
+ IN = "In"
21
+ OUT = "Out"
@@ -5,12 +5,11 @@ https://github.com/areaDetector/ADAravis
5
5
 
6
6
  from ._aravis import AravisDetector
7
7
  from ._aravis_controller import AravisController
8
- from ._aravis_io import AravisDriverIO, AravisTriggerMode, AravisTriggerSource
8
+ from ._aravis_io import AravisDriverIO, AravisTriggerSource
9
9
 
10
10
  __all__ = [
11
11
  "AravisDetector",
12
12
  "AravisController",
13
13
  "AravisDriverIO",
14
- "AravisTriggerMode",
15
14
  "AravisTriggerSource",
16
15
  ]
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
2
 
3
- from ophyd_async.core import DetectorTrigger, TriggerInfo
3
+ from ophyd_async.core import DetectorTrigger, OnOff, TriggerInfo
4
4
  from ophyd_async.epics import adcore
5
5
 
6
- from ._aravis_io import AravisDriverIO, AravisTriggerMode, AravisTriggerSource
6
+ from ._aravis_io import AravisDriverIO, AravisTriggerSource
7
7
 
8
8
  # The deadtime of an ADaravis controller varies depending on the exact model of camera.
9
9
  # Ideally we would maximize performance by dynamically retrieving the deadtime at
@@ -23,14 +23,14 @@ class AravisController(adcore.ADBaseController[AravisDriverIO]):
23
23
 
24
24
  if trigger_info.trigger is DetectorTrigger.INTERNAL:
25
25
  # Set trigger mode off to ignore the trigger source
26
- await self.driver.trigger_mode.set(AravisTriggerMode.OFF)
26
+ await self.driver.trigger_mode.set(OnOff.OFF)
27
27
  elif trigger_info.trigger in {
28
28
  DetectorTrigger.CONSTANT_GATE,
29
29
  DetectorTrigger.EDGE_TRIGGER,
30
30
  }:
31
31
  # Trigger on the rising edge of Line1
32
32
  # trigger mode must be set first and on it's own!
33
- await self.driver.trigger_mode.set(AravisTriggerMode.ON)
33
+ await self.driver.trigger_mode.set(OnOff.ON)
34
34
  await self.driver.trigger_source.set(AravisTriggerSource.LINE1)
35
35
  else:
36
36
  raise ValueError(f"ADAravis does not support {trigger_info.trigger}")
@@ -1,20 +1,10 @@
1
1
  from typing import Annotated as A
2
2
 
3
- from ophyd_async.core import SignalRW, StrictEnum, SubsetEnum
3
+ from ophyd_async.core import OnOff, SignalRW, SubsetEnum
4
4
  from ophyd_async.epics import adcore
5
5
  from ophyd_async.epics.core import PvSuffix
6
6
 
7
7
 
8
- class AravisTriggerMode(StrictEnum):
9
- """GigEVision GenICAM standard TriggerMode."""
10
-
11
- ON = "On"
12
- """Use TriggerSource to trigger each frame"""
13
-
14
- OFF = "Off"
15
- """Just trigger as fast as you can"""
16
-
17
-
18
8
  class AravisTriggerSource(SubsetEnum):
19
9
  """Which trigger source to use when TriggerMode=On."""
20
10
 
@@ -27,5 +17,5 @@ class AravisDriverIO(adcore.ADBaseIO):
27
17
  This mirrors the interface provided by ADAravis/db/aravisCamera.template.
28
18
  """
29
19
 
30
- trigger_mode: A[SignalRW[AravisTriggerMode], PvSuffix.rbv("TriggerMode")]
20
+ trigger_mode: A[SignalRW[OnOff], PvSuffix.rbv("TriggerMode")]
31
21
  trigger_source: A[SignalRW[AravisTriggerSource], PvSuffix.rbv("TriggerSource")]
@@ -7,7 +7,6 @@ from ._core_detector import AreaDetector, ContAcqAreaDetector
7
7
  from ._core_io import (
8
8
  ADBaseDatasetDescriber,
9
9
  ADBaseIO,
10
- ADCallbacks,
11
10
  ADCompression,
12
11
  ADState,
13
12
  NDArrayBaseIO,
@@ -18,6 +17,7 @@ from ._core_io import (
18
17
  NDPluginBaseIO,
19
18
  NDPluginCBIO,
20
19
  NDPluginStatsIO,
20
+ NDROIStatIO,
21
21
  )
22
22
  from ._core_logic import DEFAULT_GOOD_STATES, ADBaseContAcqController, ADBaseController
23
23
  from ._core_writer import ADWriter
@@ -33,12 +33,11 @@ from ._utils import (
33
33
  NDAttributeParam,
34
34
  NDAttributePv,
35
35
  NDAttributePvDbrType,
36
- stop_busy_record,
36
+ ndattributes_to_xml,
37
37
  )
38
38
 
39
39
  __all__ = [
40
40
  "ADBaseIO",
41
- "ADCallbacks",
42
41
  "ADCompression",
43
42
  "ADBaseContAcqController",
44
43
  "AreaDetector",
@@ -50,6 +49,7 @@ __all__ = [
50
49
  "NDFileHDFIO",
51
50
  "NDPluginBaseIO",
52
51
  "NDPluginStatsIO",
52
+ "NDROIStatIO",
53
53
  "DEFAULT_GOOD_STATES",
54
54
  "ADBaseDatasetDescriber",
55
55
  "ADBaseController",
@@ -64,8 +64,8 @@ __all__ = [
64
64
  "NDAttributePv",
65
65
  "NDAttributeParam",
66
66
  "NDAttributeDataType",
67
- "stop_busy_record",
68
67
  "NDAttributePvDbrType",
69
68
  "NDCBFlushOnSoftTrgMode",
70
69
  "NDPluginCBIO",
70
+ "ndattributes_to_xml",
71
71
  ]
@@ -1,17 +1,19 @@
1
1
  import asyncio
2
2
  from typing import Annotated as A
3
3
 
4
- from ophyd_async.core import DatasetDescriber, SignalR, SignalRW, StrictEnum
4
+ from ophyd_async.core import (
5
+ DatasetDescriber,
6
+ DeviceVector,
7
+ EnableDisable,
8
+ SignalR,
9
+ SignalRW,
10
+ StrictEnum,
11
+ )
5
12
  from ophyd_async.epics.core import EpicsDevice, PvSuffix
6
13
 
7
14
  from ._utils import ADBaseDataType, ADFileWriteMode, ADImageMode, convert_ad_dtype_to_np
8
15
 
9
16
 
10
- class ADCallbacks(StrictEnum):
11
- ENABLE = "Enable"
12
- DISABLE = "Disable"
13
-
14
-
15
17
  class NDArrayBaseIO(EpicsDevice):
16
18
  """Class responsible for passing detector data from drivers to pluglins.
17
19
 
@@ -53,7 +55,7 @@ class NDPluginBaseIO(NDArrayBaseIO):
53
55
  """
54
56
 
55
57
  nd_array_port: A[SignalRW[str], PvSuffix.rbv("NDArrayPort")]
56
- enable_callbacks: A[SignalRW[ADCallbacks], PvSuffix.rbv("EnableCallbacks")]
58
+ enable_callbacks: A[SignalRW[EnableDisable], PvSuffix.rbv("EnableCallbacks")]
57
59
  nd_array_address: A[SignalRW[int], PvSuffix.rbv("NDArrayAddress")]
58
60
  array_size0: A[SignalR[int], PvSuffix("ArraySize0_RBV")]
59
61
  array_size1: A[SignalR[int], PvSuffix("ArraySize1_RBV")]
@@ -87,6 +89,56 @@ class NDPluginStatsIO(NDPluginBaseIO):
87
89
  hist_max: A[SignalRW[float], PvSuffix.rbv("HistMax")]
88
90
 
89
91
 
92
+ class NDROIStatIO(NDPluginBaseIO):
93
+ """Plugin for calculating basic statistics for multiple ROIs.
94
+
95
+ Each ROI is implemented as an instance of NDROIStatNIO,
96
+ and the collection of ROIs is held as a DeviceVector.
97
+
98
+ See HTML docs at https://areadetector.github.io/areaDetector/ADCore/NDPluginROIStat.html
99
+ """
100
+
101
+ def __init__(self, prefix, num_channels=8, with_pvi=False, name=""):
102
+ self.channels = DeviceVector(
103
+ {i: NDROIStatNIO(f"{prefix}{i}:") for i in range(1, num_channels + 1)}
104
+ )
105
+ super().__init__(prefix, with_pvi, name)
106
+
107
+
108
+ class NDROIStatNIO(EpicsDevice):
109
+ """Defines the parameters for a single ROI used for statistics calculation.
110
+
111
+ Each instance represents a single ROI, with attributes for its position
112
+ (min_x, min_y) and size (size_x, size_y), as well as a name and use status.
113
+
114
+ See definition in ADApp/pluginSrc/NDPluginROIStat.h in https://github.com/areaDetector/ADCore.
115
+
116
+ Attributes:
117
+ name: The name of the ROI.
118
+ use: Flag indicating whether the ROI is used.
119
+ min_x: The start X-coordinate of the ROI.
120
+ min_y: The start Y-coordinate of the ROI.
121
+ size_x: The width of the ROI.
122
+ size_y: The height of the ROI.
123
+ min_value: Minimum count value in the ROI.
124
+ max_value: Maximum count value in the ROI.
125
+ mean_value: Mean counts value in the ROI.
126
+ total: Total counts in the ROI.
127
+ """
128
+
129
+ name_: A[SignalRW[str], PvSuffix("Name")]
130
+ use: A[SignalRW[bool], PvSuffix.rbv("Use")]
131
+ min_x: A[SignalRW[int], PvSuffix.rbv("MinX")]
132
+ min_y: A[SignalRW[int], PvSuffix.rbv("MinY")]
133
+ size_x: A[SignalRW[int], PvSuffix.rbv("SizeX")]
134
+ size_y: A[SignalRW[int], PvSuffix.rbv("SizeY")]
135
+ # stats
136
+ min_value: A[SignalR[float], PvSuffix("MinValue_RBV")]
137
+ max_value: A[SignalR[float], PvSuffix("MaxValue_RBV")]
138
+ mean_value: A[SignalR[float], PvSuffix("MeanValue_RBV")]
139
+ total: A[SignalR[float], PvSuffix("Total_RBV")]
140
+
141
+
90
142
  class ADState(StrictEnum):
91
143
  """Default set of states of an AreaDetector driver.
92
144
 
@@ -6,19 +6,20 @@ from ophyd_async.core import (
6
6
  AsyncStatus,
7
7
  DetectorController,
8
8
  DetectorTrigger,
9
+ EnableDisable,
9
10
  TriggerInfo,
10
11
  observe_value,
11
12
  set_and_wait_for_value,
12
13
  )
14
+ from ophyd_async.epics.core import stop_busy_record
13
15
 
14
16
  from ._core_io import (
15
17
  ADBaseIO,
16
- ADCallbacks,
17
18
  ADState,
18
19
  NDCBFlushOnSoftTrgMode,
19
20
  NDPluginCBIO,
20
21
  )
21
- from ._utils import ADImageMode, stop_busy_record
22
+ from ._utils import ADImageMode
22
23
 
23
24
  # Default set of states that we should consider "good" i.e. the acquisition
24
25
  # is complete and went well
@@ -198,7 +199,7 @@ class ADBaseContAcqController(ADBaseController[ADBaseIO]):
198
199
 
199
200
  # Configure the CB plugin to collect the correct number of triggers
200
201
  await asyncio.gather(
201
- self.cb_plugin.enable_callbacks.set(ADCallbacks.ENABLE),
202
+ self.cb_plugin.enable_callbacks.set(EnableDisable.ENABLE),
202
203
  self.cb_plugin.pre_count.set(0),
203
204
  self.cb_plugin.post_count.set(trigger_info.total_number_of_exposures),
204
205
  self.cb_plugin.preset_trigger_count.set(1),
@@ -12,19 +12,19 @@ from event_model import ( # type: ignore
12
12
  from pydantic import PositiveInt
13
13
 
14
14
  from ophyd_async.core._detector import DetectorWriter
15
+ from ophyd_async.core._enums import EnableDisable
15
16
  from ophyd_async.core._providers import DatasetDescriber, PathInfo, PathProvider
16
17
  from ophyd_async.core._signal import (
17
18
  observe_value,
18
19
  set_and_wait_for_value,
19
- wait_for_value,
20
20
  )
21
21
  from ophyd_async.core._status import AsyncStatus
22
22
  from ophyd_async.core._utils import DEFAULT_TIMEOUT, error_if_none
23
+ from ophyd_async.epics.core import stop_busy_record
23
24
 
24
25
  # from ophyd_async.epics.adcore._core_logic import ADBaseDatasetDescriber
25
26
  from ._core_io import (
26
27
  ADBaseDatasetDescriber,
27
- ADCallbacks,
28
28
  NDArrayBaseIO,
29
29
  NDFileIO,
30
30
  NDFilePluginIO,
@@ -89,7 +89,7 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
89
89
  )
90
90
 
91
91
  if isinstance(self.fileio, NDFilePluginIO):
92
- await self.fileio.enable_callbacks.set(ADCallbacks.ENABLE)
92
+ await self.fileio.enable_callbacks.set(EnableDisable.ENABLE)
93
93
 
94
94
  # Set the directory creation depth first, since dir creation callback happens
95
95
  # when directory path PV is processed.
@@ -213,8 +213,7 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
213
213
 
214
214
  async def close(self):
215
215
  # Already done a caput callback in _capture_status, so can't do one here
216
- await self.fileio.capture.set(False, wait=False)
217
- await wait_for_value(self.fileio.capture, False, DEFAULT_TIMEOUT)
216
+ await stop_busy_record(self.fileio.capture, False, timeout=DEFAULT_TIMEOUT)
218
217
  if self._capture_status and not self._capture_status.done:
219
218
  # We kicked off an open, so wait for it to return
220
219
  await self._capture_status
@@ -1,14 +1,12 @@
1
+ from collections.abc import Sequence
1
2
  from dataclasses import dataclass
3
+ from xml.etree import ElementTree as ET
2
4
 
3
5
  from ophyd_async.core import (
4
- DEFAULT_TIMEOUT,
5
- SignalDatatypeT,
6
6
  SignalR,
7
- SignalRW,
8
7
  StrictEnum,
9
8
  SubsetEnum,
10
9
  SupersetEnum,
11
- wait_for_value,
12
10
  )
13
11
 
14
12
 
@@ -136,10 +134,37 @@ class NDAttributeParam:
136
134
  description: str = "" # A description that appears in the HDF file as an attribute
137
135
 
138
136
 
139
- async def stop_busy_record(
140
- signal: SignalRW[SignalDatatypeT],
141
- value: SignalDatatypeT,
142
- timeout: float = DEFAULT_TIMEOUT,
143
- ) -> None:
144
- await signal.set(value, wait=False)
145
- await wait_for_value(signal, value, timeout=timeout)
137
+ def ndattributes_to_xml(
138
+ ndattributes: Sequence[NDAttributeParam | NDAttributePv],
139
+ ) -> str:
140
+ """Convert a set of NDAttribute params to XML."""
141
+ root = ET.Element("Attributes")
142
+ for ndattribute in ndattributes:
143
+ if isinstance(ndattribute, NDAttributeParam):
144
+ ET.SubElement(
145
+ root,
146
+ "Attribute",
147
+ name=ndattribute.name,
148
+ type="PARAM",
149
+ source=ndattribute.param,
150
+ addr=str(ndattribute.addr),
151
+ datatype=ndattribute.datatype.value,
152
+ description=ndattribute.description,
153
+ )
154
+ elif isinstance(ndattribute, NDAttributePv):
155
+ ET.SubElement(
156
+ root,
157
+ "Attribute",
158
+ name=ndattribute.name,
159
+ type="EPICS_PV",
160
+ source=ndattribute.signal.source.split("ca://")[-1],
161
+ dbrtype=ndattribute.dbrtype.value,
162
+ description=ndattribute.description,
163
+ )
164
+ else:
165
+ raise ValueError(
166
+ f"Invalid type for ndattributes: {type(ndattribute)}. "
167
+ "Expected NDAttributePv or NDAttributeParam."
168
+ )
169
+ xml_text = ET.tostring(root, encoding="unicode")
170
+ return xml_text
@@ -4,7 +4,6 @@ from ._vimba_io import (
4
4
  VimbaConvertFormat,
5
5
  VimbaDriverIO,
6
6
  VimbaExposeOutMode,
7
- VimbaOnOff,
8
7
  VimbaOverlap,
9
8
  VimbaTriggerSource,
10
9
  )
@@ -14,7 +13,6 @@ __all__ = [
14
13
  "VimbaController",
15
14
  "VimbaDriverIO",
16
15
  "VimbaExposeOutMode",
17
- "VimbaOnOff",
18
16
  "VimbaTriggerSource",
19
17
  "VimbaOverlap",
20
18
  "VimbaConvertFormat",
@@ -1,18 +1,15 @@
1
1
  import asyncio
2
2
 
3
- from ophyd_async.core import (
4
- DetectorTrigger,
5
- TriggerInfo,
6
- )
3
+ from ophyd_async.core import DetectorTrigger, OnOff, TriggerInfo
7
4
  from ophyd_async.epics import adcore
8
5
 
9
- from ._vimba_io import VimbaDriverIO, VimbaExposeOutMode, VimbaOnOff, VimbaTriggerSource
6
+ from ._vimba_io import VimbaDriverIO, VimbaExposeOutMode, VimbaTriggerSource
10
7
 
11
8
  TRIGGER_MODE = {
12
- DetectorTrigger.INTERNAL: VimbaOnOff.OFF,
13
- DetectorTrigger.CONSTANT_GATE: VimbaOnOff.ON,
14
- DetectorTrigger.VARIABLE_GATE: VimbaOnOff.ON,
15
- DetectorTrigger.EDGE_TRIGGER: VimbaOnOff.ON,
9
+ DetectorTrigger.INTERNAL: OnOff.OFF,
10
+ DetectorTrigger.CONSTANT_GATE: OnOff.ON,
11
+ DetectorTrigger.VARIABLE_GATE: OnOff.ON,
12
+ DetectorTrigger.EDGE_TRIGGER: OnOff.ON,
16
13
  }
17
14
 
18
15
  EXPOSE_OUT_MODE = {
@@ -1,6 +1,6 @@
1
1
  from typing import Annotated as A
2
2
 
3
- from ophyd_async.core import SignalRW, StrictEnum
3
+ from ophyd_async.core import OnOff, SignalRW, StrictEnum
4
4
  from ophyd_async.epics import adcore
5
5
  from ophyd_async.epics.core import PvSuffix
6
6
 
@@ -30,17 +30,10 @@ class VimbaTriggerSource(StrictEnum):
30
30
  class VimbaOverlap(StrictEnum):
31
31
  """Overlap modes for the Vimba detector."""
32
32
 
33
- OFF = "Off"
33
+ OFF = OnOff.OFF
34
34
  PREV_FRAME = "PreviousFrame"
35
35
 
36
36
 
37
- class VimbaOnOff(StrictEnum):
38
- """On/Off modes on the Vimba detector."""
39
-
40
- ON = "On"
41
- OFF = "Off"
42
-
43
-
44
37
  class VimbaExposeOutMode(StrictEnum):
45
38
  """Exposure control modes for Vimba detectors."""
46
39
 
@@ -55,6 +48,6 @@ class VimbaDriverIO(adcore.ADBaseIO):
55
48
  SignalRW[VimbaConvertFormat], PvSuffix("ConvertPixelFormat")
56
49
  ]
57
50
  trigger_source: A[SignalRW[VimbaTriggerSource], PvSuffix("TriggerSource")]
58
- trigger_mode: A[SignalRW[VimbaOnOff], PvSuffix("TriggerMode")]
51
+ trigger_mode: A[SignalRW[OnOff], PvSuffix("TriggerMode")]
59
52
  trigger_overlap: A[SignalRW[VimbaOverlap], PvSuffix("TriggerOverlap")]
60
53
  exposure_mode: A[SignalRW[VimbaExposeOutMode], PvSuffix("ExposureMode")]
@@ -10,6 +10,7 @@ from ._signal import (
10
10
  epics_signal_w,
11
11
  epics_signal_x,
12
12
  )
13
+ from ._util import stop_busy_record
13
14
 
14
15
  __all__ = [
15
16
  "PviDeviceConnector",
@@ -23,4 +24,5 @@ __all__ = [
23
24
  "epics_signal_rw_rbv",
24
25
  "epics_signal_w",
25
26
  "epics_signal_x",
27
+ "stop_busy_record",
26
28
  ]
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import os
2
3
  import sys
3
4
  import typing
4
5
  from collections.abc import Mapping, Sequence
@@ -40,6 +41,10 @@ from ._util import EpicsSignalBackend, format_datatype, get_supported_values
40
41
  logger = logging.getLogger("ophyd_async")
41
42
 
42
43
 
44
+ def _all_updates() -> bool:
45
+ return os.environ.get("OPHYD_ASYNC_EPICS_CA_KEEP_ALL_UPDATES", "True") == "True"
46
+
47
+
43
48
  def _limits_from_augmented_value(value: AugmentedValue) -> Limits:
44
49
  def get_limits(limit: str) -> LimitsRange | None:
45
50
  low = getattr(value, f"lower_{limit}_limit", nan)
@@ -250,12 +255,11 @@ class CaSignalBackend(EpicsSignalBackend[SignalDatatypeT]):
250
255
  datatype: type[SignalDatatypeT] | None,
251
256
  read_pv: str = "",
252
257
  write_pv: str = "",
253
- all_updates: bool = True,
254
258
  ):
255
259
  self.converter: CaConverter = DisconnectedCaConverter(float, dbr.DBR_DOUBLE)
256
260
  self.initial_values: dict[str, AugmentedValue] = {}
257
261
  self.subscription: Subscription | None = None
258
- self._all_updates = all_updates
262
+ self._all_updates = _all_updates()
259
263
  super().__init__(datatype, read_pv, write_pv)
260
264
 
261
265
  def source(self, name: str, read: bool):
@@ -4,13 +4,16 @@ from typing import Any, TypeVar, get_args, get_origin
4
4
  import numpy as np
5
5
 
6
6
  from ophyd_async.core import (
7
+ DEFAULT_TIMEOUT,
7
8
  SignalBackend,
8
9
  SignalDatatypeT,
10
+ SignalRW,
9
11
  StrictEnum,
10
12
  SubsetEnum,
11
13
  SupersetEnum,
12
14
  get_dtype,
13
15
  get_enum_cls,
16
+ wait_for_value,
14
17
  )
15
18
 
16
19
  T = TypeVar("T")
@@ -76,3 +79,12 @@ class EpicsSignalBackend(SignalBackend[SignalDatatypeT]):
76
79
  self.read_pv = read_pv
77
80
  self.write_pv = write_pv
78
81
  super().__init__(datatype)
82
+
83
+
84
+ async def stop_busy_record(
85
+ signal: SignalRW[SignalDatatypeT],
86
+ value: SignalDatatypeT,
87
+ timeout: float = DEFAULT_TIMEOUT,
88
+ ) -> None:
89
+ await signal.set(value, wait=False)
90
+ await wait_for_value(signal, value, timeout=timeout)