From 9dc9fe0d362550b72eb6b2589832dc0875858797 Mon Sep 17 00:00:00 2001 From: Bryan T Date: Wed, 20 May 2020 15:37:13 +0100 Subject: [PATCH 01/12] added argument to quantise seek + added odin uid offset PV --- .../modules/ADOdin/blocks/odin_runnable_block.yaml | 7 ++++++- malcolm/modules/ADOdin/blocks/odin_writer_block.yaml | 6 ++++++ malcolm/modules/ADOdin/parts/odinwriterpart.py | 2 ++ .../scanning/controllers/runnablecontroller.py | 11 +++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml index 24b3b6fdf..87af71197 100644 --- a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml +++ b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml @@ -45,6 +45,10 @@ description: Name of secondary dataset to link in nxs file default: sum +- builtin.parameters.int32: + name: num_frame_receivers + description: Number of FR processes (seek to integer multiples of this when pausing) + default: 1 - builtin.defines.docstring: value: | @@ -54,6 +58,7 @@ mri: $(mri_prefix) config_dir: $(config_dir) initial_design: $(initial_design) + seek_multiples_of: $(num_frame_receivers) description: | Odin is a set of libraries for capturing data from high speed detectors @@ -91,4 +96,4 @@ name: DSET - builtin.parts.IconPart: - svg: $(yamldir)/../icons/odin_logo.svg \ No newline at end of file + svg: $(yamldir)/../icons/odin_logo.svg diff --git a/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml b/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml index 453d639c0..ecabaedb6 100644 --- a/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml +++ b/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml @@ -85,6 +85,12 @@ # pv: $(prefix):N# umFramesFlush # rbv_suffix: _RB# V +- ca.parts.CALongPart: + name: uidOffset + description: value to offset UID by + pv: $(prefix):PARAM:UID:Adjustment + rbv_suffix: _RBV + # Filename - ca.parts.CACharArrayPart: name: filePath diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index ca94cc634..0ecb54218 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -351,6 +351,8 @@ def on_seek(self, self.unique_id_offset = completed_steps - self.done_when_reaches self.done_when_reaches += steps_to_do child = context.block_view(self.mri) + # set UID offset for file writing + child.uidOffset.put_value(self.unique_id_offset) # Just reset the array counter_block child.arrayCounter.put_value(0) # Start a future waiting for the first array diff --git a/malcolm/modules/scanning/controllers/runnablecontroller.py b/malcolm/modules/scanning/controllers/runnablecontroller.py index 98e652357..a84975e80 100644 --- a/malcolm/modules/scanning/controllers/runnablecontroller.py +++ b/malcolm/modules/scanning/controllers/runnablecontroller.py @@ -26,6 +26,8 @@ AConfigureParams = ConfigureParams with Anno("Step to mark as the last completed step, -1 for current"): ALastGoodStep = int +with Anno("Quantise seek to integer multiples of"): + ASeekMultiple = int # Pull re-used annotypes into our namespace in case we are subclassed AConfigDir = builtin.controllers.AConfigDir @@ -149,6 +151,7 @@ def __init__(self, initial_design="", # type: AInitialDesign use_git=True, # type: AUseGit description="", # type: ADescription + seek_multiples_of=1, # type: ASeekMultiple ): # type: (...) -> None super(RunnableController, self).__init__( @@ -176,6 +179,8 @@ def __init__(self, self.steps_per_run = 0 # type: int # Create sometimes writeable attribute for the current completed scan # step + self.seek_multiples_of = seek_multiples_of + # Quantise seek to integer multiples of this value self.completed_steps = NumberMeta( "int32", "Readback of number of scan steps", tags=[Widget.METER.tag()] # Widget.TEXTINPUT.tag()] @@ -565,6 +570,8 @@ def pause(self, lastGoodStep=-1): elif lastGoodStep >= total_steps: lastGoodStep = total_steps - 1 + lastGoodStep -= (lastGoodStep % self.seek_multiple_of) + if self.state.value in [ss.ARMED, ss.FINISHED]: # We don't have a run process, free to go anywhere we want next_state = ss.ARMED @@ -581,10 +588,14 @@ def do_pause(self, completed_steps): # type: (int) -> None self.run_hooks( PauseHook(p, c) for p, c in self.create_part_contexts().items()) + + completed_steps -= (completed_steps % self.seek_multiple_of) + in_run_steps = completed_steps % self.steps_per_run steps_to_do = self.steps_per_run - in_run_steps part_info = self.run_hooks( ReportStatusHook(p, c) for p, c in self.part_contexts.items()) + self.completed_steps.set_value(completed_steps) self.run_hooks( SeekHook(p, c, completed_steps, steps_to_do, part_info, **kwargs) From 949cf263b87a8849dedc37bb39a7cb2a37ab7080 Mon Sep 17 00:00:00 2001 From: Bryan T Date: Wed, 17 Jun 2020 10:28:59 +0100 Subject: [PATCH 02/12] removed seek_multiples_of from odin_runnable_block (should be defined on scan controller) --- malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml index 87af71197..eeeac14ec 100644 --- a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml +++ b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml @@ -45,11 +45,6 @@ description: Name of secondary dataset to link in nxs file default: sum -- builtin.parameters.int32: - name: num_frame_receivers - description: Number of FR processes (seek to integer multiples of this when pausing) - default: 1 - - builtin.defines.docstring: value: | Device block corresponding to ADOdin + Odin file writer plugin . @@ -58,7 +53,6 @@ mri: $(mri_prefix) config_dir: $(config_dir) initial_design: $(initial_design) - seek_multiples_of: $(num_frame_receivers) description: | Odin is a set of libraries for capturing data from high speed detectors From 0e0209ab4703a798c6a8dc1e2363f6a8f93a4eb8 Mon Sep 17 00:00:00 2001 From: Bryan T Date: Wed, 17 Jun 2020 10:57:12 +0100 Subject: [PATCH 03/12] fix typo --- malcolm/modules/scanning/controllers/runnablecontroller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/malcolm/modules/scanning/controllers/runnablecontroller.py b/malcolm/modules/scanning/controllers/runnablecontroller.py index a84975e80..3536495f9 100644 --- a/malcolm/modules/scanning/controllers/runnablecontroller.py +++ b/malcolm/modules/scanning/controllers/runnablecontroller.py @@ -151,7 +151,7 @@ def __init__(self, initial_design="", # type: AInitialDesign use_git=True, # type: AUseGit description="", # type: ADescription - seek_multiples_of=1, # type: ASeekMultiple + seek_multiple_of=1, # type: ASeekMultiple ): # type: (...) -> None super(RunnableController, self).__init__( @@ -179,7 +179,7 @@ def __init__(self, self.steps_per_run = 0 # type: int # Create sometimes writeable attribute for the current completed scan # step - self.seek_multiples_of = seek_multiples_of + self.seek_multiple_of = seek_multiple_of # Quantise seek to integer multiples of this value self.completed_steps = NumberMeta( "int32", "Readback of number of scan steps", From dd6a02508b73d0f7c4b3ee1b436910f8c17db913 Mon Sep 17 00:00:00 2001 From: Bryan T Date: Wed, 15 Jul 2020 14:52:44 +0100 Subject: [PATCH 04/12] remove pause hook for writerpart and fix uid offset in seek --- malcolm/modules/ADOdin/parts/odinwriterpart.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index 0ecb54218..9b12dc3e6 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -276,7 +276,7 @@ def setup(self, registrar): registrar.hook(scanning.hooks.RunHook, self.on_run) registrar.hook(scanning.hooks.PostRunReadyHook, self.on_post_run_ready) registrar.hook(scanning.hooks.AbortHook, self.on_abort) - registrar.hook(scanning.hooks.PauseHook, self.on_pause) + # registrar.hook(scanning.hooks.PauseHook, self.on_pause) @add_call_types def on_pause(self, context): @@ -347,9 +347,9 @@ def on_seek(self, ): # type: (...) -> None # This is rewinding or setting up for another batch, so the detector - # will skip to a uniqueID that has not been produced yet - self.unique_id_offset = completed_steps - self.done_when_reaches - self.done_when_reaches += steps_to_do + # will reset count to zero and set UID offset appropriately + self.unique_id_offset = completed_steps # - self.done_when_reaches + self.done_when_reaches = steps_to_do child = context.block_view(self.mri) # set UID offset for file writing child.uidOffset.put_value(self.unique_id_offset) From 083afa7661484737ecda6b55550d7b05025e9247 Mon Sep 17 00:00:00 2001 From: Bryan Robert Tester Date: Fri, 17 Jul 2020 10:39:09 +0100 Subject: [PATCH 05/12] add frameOffset setting --- .../ADOdin/blocks/odin_runnable_block.yaml | 1 + .../ADOdin/blocks/odin_writer_block.yaml | 17 +++++--- .../modules/ADOdin/parts/odinwriterpart.py | 41 ++++++++++++++----- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml index eeeac14ec..d2bb15d38 100644 --- a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml +++ b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml @@ -82,6 +82,7 @@ - ADOdin.parts.OdinWriterPart: name: WRITER mri: $(mri_prefix):$(writer_suffix) + driver_mri: $(mri_prefix):DRV sum_name: $(sum_name) uid_name: $(uid_name) secondary_set: $(secondary_set) diff --git a/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml b/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml index ecabaedb6..913ea3b73 100644 --- a/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml +++ b/malcolm/modules/ADOdin/blocks/odin_writer_block.yaml @@ -79,11 +79,11 @@ description: type of the pixel data rbv: $(prefix):DataType -#- ca.parts.CALongPa#-rt: -# name: flushData# PerNFrames -# description: Nu# mber of frames to capture between HDF dataset flushes -# pv: $(prefix):N# umFramesFlush -# rbv_suffix: _RB# V +#- ca.parts.CALongPart: +# name: flushDataPerNFrames +# description: Number of frames to capture between HDF dataset flushes +# pv: $(prefix):NumFramesFlush +# rbv_suffix: _RBV - ca.parts.CALongPart: name: uidOffset @@ -91,6 +91,13 @@ pv: $(prefix):PARAM:UID:Adjustment rbv_suffix: _RBV +- ca.parts.CALongPart: + name: frameOffset + description: value to offset frame index by + pv: $(prefix):OFF:Adjustment + rbv_suffix: _RBV + + # Filename - ca.parts.CACharArrayPart: name: filePath diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index 9b12dc3e6..52d216558 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -5,7 +5,7 @@ from vdsgen import InterleaveVDSGenerator, ReshapeVDSGenerator from scanpointgenerator import CompoundGenerator -from malcolm.core import APartName, Future, Info, PartRegistrar, BadValueError +from malcolm.core import APartName, Future, Info, PartRegistrar, BadValueError, errors from malcolm.modules import builtin, scanning if TYPE_CHECKING: @@ -230,7 +230,7 @@ def add_nexus_nodes(generator, vds_file_path): # We will set these attributes on the child block, so don't save them -@builtin.util.no_save("fileName", "filePath", "numCapture") +@builtin.util.no_save("fileName", "filePath", "numCapture", "uidOffset") class OdinWriterPart(builtin.parts.ChildPart): """Part for controlling an `hdf_writer_block` in a Device""" @@ -239,6 +239,7 @@ class OdinWriterPart(builtin.parts.ChildPart): array_future = None # type: Future done_when_reaches = None # type: int unique_id_offset = None # type: int + frame_offset = None # type: int # The HDF5 layout file we write to say where the datasets go layout_filename = None # type: str exposure_time = None # type: float @@ -249,12 +250,14 @@ def __init__(self, initial_visibility=True, # type: AInitialVisibility uid_name="uid", # type: AUidName sum_name="sum", # type: ASumName - secondary_set="sum" # type: ASecondaryDataset + secondary_set="sum", # type: ASecondaryDataset + driver_mri=None # type: AMri ): # type: (...) -> None self.uid_name = uid_name self.sum_name = sum_name self.secondary_set = secondary_set + self.drv_mri = driver_mri super(OdinWriterPart, self).__init__(name, mri, initial_visibility) @add_call_types @@ -301,8 +304,13 @@ def on_configure(self, # On initial configure, expect to get the demanded number of frames self.done_when_reaches = completed_steps + steps_to_do - self.unique_id_offset = 0 + if self.unique_id_offset is None: + self.unique_id_offset = 1 + if self.frame_offset is None: + self.frame_offset = 0 child = context.block_view(self.mri) + child.uidOffset.put_value(self.unique_id_offset) + child.frameOffset.put_value(self.frame_offset) file_dir = fileDir.rstrip(os.sep) # derive file path from template as AreaDetector would normally do @@ -318,7 +326,7 @@ def on_configure(self, assert "." in vds_full_filename, \ "File extension for %r should be supplied" % vds_full_filename futures = child.put_attribute_values_async(dict( - numCapture=steps_to_do, + numCapture=self.done_when_reaches, filePath=file_dir + os.sep, fileName=raw_file_basename)) context.wait_all_futures(futures) @@ -348,13 +356,22 @@ def on_seek(self, # type: (...) -> None # This is rewinding or setting up for another batch, so the detector # will reset count to zero and set UID offset appropriately - self.unique_id_offset = completed_steps # - self.done_when_reaches - self.done_when_reaches = steps_to_do + child = context.block_view(self.mri) - # set UID offset for file writing - child.uidOffset.put_value(self.unique_id_offset) + # Wait until Odin stops receiving frames + try: + child.when_value_matches( + "numCaptured", self.done_when_reaches, + event_timeout=self.exposure_time + 5) + except errors.TimeoutError: + pass + current_count = child.numCaptured.value + self.unique_id_offset = self.done_when_reaches + self.frame_offset = (completed_steps - self.done_when_reaches) + 1 + self.done_when_reaches = steps_to_do + current_count + #drv = context.block_view(self.drv_mri) # Just reset the array counter_block - child.arrayCounter.put_value(0) + #drv.arrayCounter.put_value(0) # Start a future waiting for the first array self.array_future = child.when_value_matches_async( "numCaptured", greater_than_zero) @@ -374,7 +391,9 @@ def on_run(self, context): def on_post_run_ready(self, context): # type: (scanning.hooks.AContext) -> None # If this is the last one, wait until the file is closed - context.wait_all_futures(self.start_future) + context.wait_all_futures(self.start_future) + self.unique_id_offset = None + self.frame_offset = None @add_call_types def on_abort(self, context): From 084f5a756c84f8f7a8de646a45171b50be5955ea Mon Sep 17 00:00:00 2001 From: Bryan T Date: Fri, 17 Jul 2020 10:44:51 +0100 Subject: [PATCH 06/12] attempt to fix setting of offsets on seek --- malcolm/modules/ADOdin/parts/odinwriterpart.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index 52d216558..ec7dbd59d 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -304,9 +304,8 @@ def on_configure(self, # On initial configure, expect to get the demanded number of frames self.done_when_reaches = completed_steps + steps_to_do - if self.unique_id_offset is None: + if completed_steps == 0: self.unique_id_offset = 1 - if self.frame_offset is None: self.frame_offset = 0 child = context.block_view(self.mri) child.uidOffset.put_value(self.unique_id_offset) @@ -391,9 +390,7 @@ def on_run(self, context): def on_post_run_ready(self, context): # type: (scanning.hooks.AContext) -> None # If this is the last one, wait until the file is closed - context.wait_all_futures(self.start_future) - self.unique_id_offset = None - self.frame_offset = None + context.wait_all_futures(self.start_future) @add_call_types def on_abort(self, context): From 4d6b53b521f7dd872f063338b895eabb497c2f28 Mon Sep 17 00:00:00 2001 From: Bryan Robert Tester Date: Fri, 17 Jul 2020 14:11:39 +0100 Subject: [PATCH 07/12] fix done_when_reaches and add offset value setting in seek --- malcolm/modules/ADOdin/parts/odinwriterpart.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index ec7dbd59d..0d78b08a5 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -230,7 +230,7 @@ def add_nexus_nodes(generator, vds_file_path): # We will set these attributes on the child block, so don't save them -@builtin.util.no_save("fileName", "filePath", "numCapture", "uidOffset") +@builtin.util.no_save("fileName", "filePath", "numCapture", "uidOffset", "frameOffset") class OdinWriterPart(builtin.parts.ChildPart): """Part for controlling an `hdf_writer_block` in a Device""" @@ -367,7 +367,11 @@ def on_seek(self, current_count = child.numCaptured.value self.unique_id_offset = self.done_when_reaches self.frame_offset = (completed_steps - self.done_when_reaches) + 1 - self.done_when_reaches = steps_to_do + current_count + + child.uidOffset.put_value(self.unique_id_offset) + child.frameOffset.put_value(self.frame_offset) + + self.done_when_reaches = steps_to_do + current_count - 1 #drv = context.block_view(self.drv_mri) # Just reset the array counter_block #drv.arrayCounter.put_value(0) From cded431b1b19b3e9eb62f6961e2de9d00b7a853d Mon Sep 17 00:00:00 2001 From: Bryan T Date: Thu, 20 Aug 2020 13:39:57 +0100 Subject: [PATCH 08/12] add odindriverpart to ensure arraycounter is zeroed at start on each configure --- .../ADOdin/blocks/odin_runnable_block.yaml | 2 +- malcolm/modules/ADOdin/parts/__init__.py | 1 + malcolm/modules/ADOdin/parts/odindriverpart.py | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 malcolm/modules/ADOdin/parts/odindriverpart.py diff --git a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml index d2bb15d38..f811c9330 100644 --- a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml +++ b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml @@ -64,7 +64,7 @@ mri: $(mri_prefix):DRV prefix: $(pv_prefix):$(drv_suffix) -- ADCore.parts.DetectorDriverPart: +- ADOdin.parts.OdinDriverPart: name: DRV mri: $(mri_prefix):DRV soft_trigger_modes: diff --git a/malcolm/modules/ADOdin/parts/__init__.py b/malcolm/modules/ADOdin/parts/__init__.py index 1bc9dbd8e..3b7950eab 100644 --- a/malcolm/modules/ADOdin/parts/__init__.py +++ b/malcolm/modules/ADOdin/parts/__init__.py @@ -1,4 +1,5 @@ from .odinwriterpart import OdinWriterPart, AMri, APartName +from .odindriverpart import OdinDriverPart # Expose a nice namespace from malcolm.core import submodule_all diff --git a/malcolm/modules/ADOdin/parts/odindriverpart.py b/malcolm/modules/ADOdin/parts/odindriverpart.py new file mode 100644 index 000000000..4010ad548 --- /dev/null +++ b/malcolm/modules/ADOdin/parts/odindriverpart.py @@ -0,0 +1,16 @@ +from malcolm.core import Context +from malcolm.modules import scanning +from malcolm.modules.ADCore.parts import DetectorDriverPart + + +class OdinDriverPart(DetectorDriverPart): + def setup_detector(self, + context, # type: Context + completed_steps, # type: scanning.hooks.ACompletedSteps + steps_to_do, # type: scanning.hooks.AStepsToDo + duration, # type: float + part_info, # type: scanning.hooks.APartInfo + **kwargs # type: Any + ): + # type: (...) -> None + super(OdinDriverPart, self).setup_detector(context, 0, steps_to_do, duration, part_info) From 4df1239a177c6bf56500485572684020b9f25fdd Mon Sep 17 00:00:00 2001 From: Bryan T Date: Tue, 25 Aug 2020 11:36:43 +0100 Subject: [PATCH 09/12] copy all annotated methods into OdinDriverPart and super --- .../modules/ADOdin/parts/odindriverpart.py | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/malcolm/modules/ADOdin/parts/odindriverpart.py b/malcolm/modules/ADOdin/parts/odindriverpart.py index 4010ad548..6a86aff6a 100644 --- a/malcolm/modules/ADOdin/parts/odindriverpart.py +++ b/malcolm/modules/ADOdin/parts/odindriverpart.py @@ -1,8 +1,10 @@ from malcolm.core import Context -from malcolm.modules import scanning +from malcolm.modules import builtin, scanning from malcolm.modules.ADCore.parts import DetectorDriverPart - +# We will set these attributes on the child block, so don't save them +@builtin.util.no_save('arrayCounter', 'imageMode', 'numImages', + 'arrayCallbacks', 'exposure', 'acquirePeriod') class OdinDriverPart(DetectorDriverPart): def setup_detector(self, context, # type: Context @@ -14,3 +16,38 @@ def setup_detector(self, ): # type: (...) -> None super(OdinDriverPart, self).setup_detector(context, 0, steps_to_do, duration, part_info) + + @add_call_types + def on_reset(self, context): + # type: (scanning.hooks.AContext) -> None + super(OdinDriverPart, self).on_reset(context) + + @add_call_types + def on_report_status(self): + # type: () -> scanning.hooks.UInfos + super(OdinDriverPart, self).on_report_status() + + # Allow CamelCase as fileDir parameter will be serialized + # noinspection PyPep8Naming + @add_call_types + def on_configure(self, + context, # type: scanning.hooks.AContext + completed_steps, # type: scanning.hooks.ACompletedSteps + steps_to_do, # type: scanning.hooks.AStepsToDo + part_info, # type: scanning.hooks.APartInfo + generator, # type: scanning.hooks.AGenerator + fileDir, # type: scanning.hooks.AFileDir + **kwargs # type: Any + ): + # type: (...) -> None + super(OdinDriverPart, self).on_configure(context, completed_steps, steps_to_do, part_info, generator, fileDir, **kwargs) + + @add_call_types + def on_run(self, context): + # type: (scanning.hooks.AContext) -> None + super(OdinDriverPart, self).on_run(context) + + @add_call_types + def on_abort(self, context): + # type: (scanning.hooks.AContext) -> None + self.abort_detector(context) From 6ef1c6c82f4ae8ee8e93074678d89fdad80088b5 Mon Sep 17 00:00:00 2001 From: Bryan Robert Tester Date: Thu, 27 Aug 2020 14:47:04 +0100 Subject: [PATCH 10/12] add check for squashingexcluder + fix indent --- .../modules/ADOdin/parts/odindriverpart.py | 20 ++++++++++--------- .../modules/ADOdin/parts/odinwriterpart.py | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/malcolm/modules/ADOdin/parts/odindriverpart.py b/malcolm/modules/ADOdin/parts/odindriverpart.py index 6a86aff6a..a85dfc655 100644 --- a/malcolm/modules/ADOdin/parts/odindriverpart.py +++ b/malcolm/modules/ADOdin/parts/odindriverpart.py @@ -2,22 +2,24 @@ from malcolm.modules import builtin, scanning from malcolm.modules.ADCore.parts import DetectorDriverPart +from annotypes import add_call_types, Any + # We will set these attributes on the child block, so don't save them @builtin.util.no_save('arrayCounter', 'imageMode', 'numImages', 'arrayCallbacks', 'exposure', 'acquirePeriod') class OdinDriverPart(DetectorDriverPart): - def setup_detector(self, - context, # type: Context - completed_steps, # type: scanning.hooks.ACompletedSteps - steps_to_do, # type: scanning.hooks.AStepsToDo - duration, # type: float - part_info, # type: scanning.hooks.APartInfo - **kwargs # type: Any - ): + def setup_detector(self, + context, # type: Context + completed_steps, # type: scanning.hooks.ACompletedSteps + steps_to_do, # type: scanning.hooks.AStepsToDo + duration, # type: float + part_info, # type: scanning.hooks.APartInfo + **kwargs # type: Any + ): # type: (...) -> None super(OdinDriverPart, self).setup_detector(context, 0, steps_to_do, duration, part_info) - @add_call_types + @add_call_types def on_reset(self, context): # type: (scanning.hooks.AContext) -> None super(OdinDriverPart, self).on_reset(context) diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index 0d78b08a5..8c70a6105 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -3,7 +3,7 @@ import h5py from annotypes import Anno, add_call_types, TYPE_CHECKING from vdsgen import InterleaveVDSGenerator, ReshapeVDSGenerator -from scanpointgenerator import CompoundGenerator +from scanpointgenerator import CompoundGenerator, SquashingExcluder from malcolm.core import APartName, Future, Info, PartRegistrar, BadValueError, errors from malcolm.modules import builtin, scanning @@ -134,7 +134,7 @@ def create_vds(generator, raw_name, vds_path, child, uid_name, sum_name): # The first dimension alternating has no meaning. If any subsequent ones # alternate then it will radically slow down the VDS creation and reading. # We rely on a scanning.parts.UnrollingPart to - if any(dim.alternate for dim in generator.dimensions[1:]): + if any(dim.alternate for dim in generator.dimensions[1:]) and not any(isinstance(excl, SquashingExcluder) for excl in generator.excluders) : raise BadValueError( "Snake scans are not supported as the VDS is not performant. You " "can add a scanning.parts.UnrollingPart to the top level scan " From 86aebd6efd6b8a25c8dca73cfdc1e5231d49d504 Mon Sep 17 00:00:00 2001 From: Bryan Robert Tester Date: Fri, 9 Oct 2020 10:49:43 +0100 Subject: [PATCH 11/12] fix frame offset for new odindriverpart --- malcolm/modules/ADOdin/parts/odinwriterpart.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index 8c70a6105..88b16504e 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -134,7 +134,7 @@ def create_vds(generator, raw_name, vds_path, child, uid_name, sum_name): # The first dimension alternating has no meaning. If any subsequent ones # alternate then it will radically slow down the VDS creation and reading. # We rely on a scanning.parts.UnrollingPart to - if any(dim.alternate for dim in generator.dimensions[1:]) and not any(isinstance(excl, SquashingExcluder) for excl in generator.excluders) : + if any(dim.alternate for dim in generator.dimensions[1:]): raise BadValueError( "Snake scans are not supported as the VDS is not performant. You " "can add a scanning.parts.UnrollingPart to the top level scan " @@ -366,15 +366,17 @@ def on_seek(self, pass current_count = child.numCaptured.value self.unique_id_offset = self.done_when_reaches - self.frame_offset = (completed_steps - self.done_when_reaches) + 1 + # worked with vanilla detectordriverpart + # self.frame_offset = (completed_steps - self.done_when_reaches) + 1 + self.frame_offset = completed_steps child.uidOffset.put_value(self.unique_id_offset) child.frameOffset.put_value(self.frame_offset) - - self.done_when_reaches = steps_to_do + current_count - 1 + + self.done_when_reaches = steps_to_do + current_count #drv = context.block_view(self.drv_mri) # Just reset the array counter_block - #drv.arrayCounter.put_value(0) + #drv.arrayCounter.put_value(0) # Start a future waiting for the first array self.array_future = child.when_value_matches_async( "numCaptured", greater_than_zero) From b3656e2f7bd399d693868e293249e54d4a6853a8 Mon Sep 17 00:00:00 2001 From: Bryan T Date: Thu, 15 Oct 2020 10:02:23 +0100 Subject: [PATCH 12/12] removed redundant code --- .../ADOdin/blocks/odin_runnable_block.yaml | 1 - .../modules/ADOdin/parts/odindriverpart.py | 39 +------------------ .../modules/ADOdin/parts/odinwriterpart.py | 30 ++++++-------- 3 files changed, 13 insertions(+), 57 deletions(-) diff --git a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml index f811c9330..3469654fc 100644 --- a/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml +++ b/malcolm/modules/ADOdin/blocks/odin_runnable_block.yaml @@ -82,7 +82,6 @@ - ADOdin.parts.OdinWriterPart: name: WRITER mri: $(mri_prefix):$(writer_suffix) - driver_mri: $(mri_prefix):DRV sum_name: $(sum_name) uid_name: $(uid_name) secondary_set: $(secondary_set) diff --git a/malcolm/modules/ADOdin/parts/odindriverpart.py b/malcolm/modules/ADOdin/parts/odindriverpart.py index a85dfc655..43638b0fe 100644 --- a/malcolm/modules/ADOdin/parts/odindriverpart.py +++ b/malcolm/modules/ADOdin/parts/odindriverpart.py @@ -4,9 +4,6 @@ from annotypes import add_call_types, Any -# We will set these attributes on the child block, so don't save them -@builtin.util.no_save('arrayCounter', 'imageMode', 'numImages', - 'arrayCallbacks', 'exposure', 'acquirePeriod') class OdinDriverPart(DetectorDriverPart): def setup_detector(self, context, # type: Context @@ -17,39 +14,5 @@ def setup_detector(self, **kwargs # type: Any ): # type: (...) -> None - super(OdinDriverPart, self).setup_detector(context, 0, steps_to_do, duration, part_info) + super(OdinDriverPart, self).setup_detector(context, 0, steps_to_do, duration, part_info) - @add_call_types - def on_reset(self, context): - # type: (scanning.hooks.AContext) -> None - super(OdinDriverPart, self).on_reset(context) - - @add_call_types - def on_report_status(self): - # type: () -> scanning.hooks.UInfos - super(OdinDriverPart, self).on_report_status() - - # Allow CamelCase as fileDir parameter will be serialized - # noinspection PyPep8Naming - @add_call_types - def on_configure(self, - context, # type: scanning.hooks.AContext - completed_steps, # type: scanning.hooks.ACompletedSteps - steps_to_do, # type: scanning.hooks.AStepsToDo - part_info, # type: scanning.hooks.APartInfo - generator, # type: scanning.hooks.AGenerator - fileDir, # type: scanning.hooks.AFileDir - **kwargs # type: Any - ): - # type: (...) -> None - super(OdinDriverPart, self).on_configure(context, completed_steps, steps_to_do, part_info, generator, fileDir, **kwargs) - - @add_call_types - def on_run(self, context): - # type: (scanning.hooks.AContext) -> None - super(OdinDriverPart, self).on_run(context) - - @add_call_types - def on_abort(self, context): - # type: (scanning.hooks.AContext) -> None - self.abort_detector(context) diff --git a/malcolm/modules/ADOdin/parts/odinwriterpart.py b/malcolm/modules/ADOdin/parts/odinwriterpart.py index 88b16504e..708d7da3c 100644 --- a/malcolm/modules/ADOdin/parts/odinwriterpart.py +++ b/malcolm/modules/ADOdin/parts/odinwriterpart.py @@ -3,7 +3,7 @@ import h5py from annotypes import Anno, add_call_types, TYPE_CHECKING from vdsgen import InterleaveVDSGenerator, ReshapeVDSGenerator -from scanpointgenerator import CompoundGenerator, SquashingExcluder +from scanpointgenerator import CompoundGenerator from malcolm.core import APartName, Future, Info, PartRegistrar, BadValueError, errors from malcolm.modules import builtin, scanning @@ -251,13 +251,10 @@ def __init__(self, uid_name="uid", # type: AUidName sum_name="sum", # type: ASumName secondary_set="sum", # type: ASecondaryDataset - driver_mri=None # type: AMri ): - # type: (...) -> None self.uid_name = uid_name self.sum_name = sum_name self.secondary_set = secondary_set - self.drv_mri = driver_mri super(OdinWriterPart, self).__init__(name, mri, initial_visibility) @add_call_types @@ -358,26 +355,23 @@ def on_seek(self, child = context.block_view(self.mri) # Wait until Odin stops receiving frames - try: - child.when_value_matches( - "numCaptured", self.done_when_reaches, - event_timeout=self.exposure_time + 5) - except errors.TimeoutError: - pass - current_count = child.numCaptured.value + # try: + # child.when_value_matches( + # "numCaptured", self.done_when_reaches, + # event_timeout=self.exposure_time + 5) + # except errors.TimeoutError: + # pass + #current_count = child.numCaptured.value + self.unique_id_offset = self.done_when_reaches - # worked with vanilla detectordriverpart - # self.frame_offset = (completed_steps - self.done_when_reaches) + 1 self.frame_offset = completed_steps child.uidOffset.put_value(self.unique_id_offset) child.frameOffset.put_value(self.frame_offset) - self.done_when_reaches = steps_to_do + current_count - #drv = context.block_view(self.drv_mri) - # Just reset the array counter_block - #drv.arrayCounter.put_value(0) - # Start a future waiting for the first array + # TODO: point this to check written UID instead + # self.done_when_reaches = steps_to_do + current_count + self.array_future = child.when_value_matches_async( "numCaptured", greater_than_zero)