From 29c3746ddd6557ef571c9fdeccd136a0e9324425 Mon Sep 17 00:00:00 2001 From: Ian O'Hara Date: Mon, 20 Jan 2025 16:07:10 -0800 Subject: [PATCH] fix(acquisition abort): Aborting acquisitions midway left the ui in an invalid state (#76) `34713ec14805b441a1cee7dbeb2c13c337035d31` added the `self.is_current_acquisition_widget` concept on our acquisition widgets. This was set to `= False` in two places for each - one in the `toggle_acquisition` and another in `acquisition_finished`. The `toggle_acquisition` always ran first (it sent the signal that eventually resulted in `acquisition_finished` getting called), which means that the code in `acquisition_finished` was always skipped via the `if` guard checking for `is_current_acquisition_widget`. It's not clear if we need `is_current_acquisition_widget` since it's new-ish, but for now leave it and just make it so `acquisition_finished` is the only `= False` setter of that flag. Tested by: running local acquisitions. Before this, the stage control + acquisition widgets would get wedged in disabled state if you aborted an acquisition midway. Now, they don't and you can continue using the UI. --- software/control/core/core.py | 8 +++++++- software/control/gui_hcs.py | 1 + software/control/widgets.py | 22 ++++++++++++++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/software/control/core/core.py b/software/control/core/core.py index b200bf90..1a32a38f 100644 --- a/software/control/core/core.py +++ b/software/control/core/core.py @@ -4,6 +4,7 @@ from control.microcontroller import Microcontroller from squid.abc import AbstractStage +import squid.logging # qt libraries os.environ["QT_API"] = "pyqt5" @@ -1468,6 +1469,7 @@ def run(self): while self.time_point < self.Nt: # check if abort acquisition has been requested if self.multiPointController.abort_acqusition_requested: + self._log.debug("In run, abort_acquisition_requested=True") break self.run_single_time_point() @@ -1489,6 +1491,7 @@ def run(self): # wait until it's time to do the next acquisition while time.time() < self.timestamp_acquisition_started + self.time_point * self.dt: if self.multiPointController.abort_acqusition_requested: + self._log.debug("In run wait loop, abort_acquisition_requested=True") break time.sleep(0.05) @@ -2179,7 +2182,7 @@ def __init__( parent=None, ): QObject.__init__(self) - + self._log = squid.logging.get_logger(self.__class__.__name__) self.camera = camera if DO_FLUORESCENCE_RTP: self.processingHandler = ProcessingHandler() @@ -2533,6 +2536,7 @@ def run_acquisition(self): self.thread.start() def _on_acquisition_completed(self): + self._log.debug("MultiPointController._on_acquisition_completed called") # restore the previous selected mode if self.gen_focus_map: self.autofocusController.clear_focus_map() @@ -3218,6 +3222,7 @@ class NavigationViewer(QFrame): def __init__(self, objectivestore, sample="glass slide", invertX=False, *args, **kwargs): super().__init__(*args, **kwargs) + self._log = squid.logging.get_logger(self.__class__.__name__) self.setFrameStyle(QFrame.Panel | QFrame.Raised) self.sample = sample self.objectiveStore = objectivestore @@ -3493,6 +3498,7 @@ def handle_mouse_click(self, evt): x_mm = (mouse_point.x() - self.origin_x_pixel) * self.mm_per_pixel y_mm = (mouse_point.y() - self.origin_y_pixel) * self.mm_per_pixel + self._log.debug(f"Got double click at (x_mm, y_mm) = {x_mm, y_mm}") self.signal_coordinates_clicked.emit(x_mm, y_mm) except Exception as e: diff --git a/software/control/gui_hcs.py b/software/control/gui_hcs.py index 9453f5ae..35f37dcf 100644 --- a/software/control/gui_hcs.py +++ b/software/control/gui_hcs.py @@ -1251,6 +1251,7 @@ def toggleWellSelector(self, show): self.wellSelectionWidget.setVisible(show) def toggleAcquisitionStart(self, acquisition_started): + self.log.debug(f"toggleAcquisitionStarted({acquisition_started=})") if acquisition_started: self.log.info("STARTING ACQUISITION") if self.is_live_scan_grid_on: # disconnect live scan grid during acquisition diff --git a/software/control/widgets.py b/software/control/widgets.py index ab77350b..47f11539 100644 --- a/software/control/widgets.py +++ b/software/control/widgets.py @@ -1875,6 +1875,7 @@ def __init__( ): super().__init__(*args, **kwargs) self._log = squid.logging.get_logger(self.__class__.__name__) + self.acquisition_start_time = None self.last_used_locations = None self.last_used_location_ids = None self.stage = stage @@ -2397,6 +2398,7 @@ def update_Nz(self): self.entry_NZ.setValue(nz) def update_region_progress(self, current_fov, num_fovs): + self._log.debug(f"Updating region progress for {current_fov=}, {num_fovs=}") self.progress_bar.setMaximum(num_fovs) self.progress_bar.setValue(current_fov) @@ -2425,6 +2427,9 @@ def update_region_progress(self, current_fov, num_fovs): self.eta_timer.start(1000) # Update every 1000 ms (1 second) def update_acquisition_progress(self, current_region, num_regions, current_time_point): + self._log.debug( + f"updating acquisition progress for {current_region=}, {num_regions=}, {current_time_point=}..." + ) self.current_region = current_region self.current_time_point = current_time_point @@ -2524,6 +2529,7 @@ def display_stitcher_widget(self, checked): self.signal_stitcher_widget.emit(checked) def toggle_acquisition(self, pressed): + self._log.debug(f"FlexibleMultiPointWidget.toggle_acquisition, {pressed=}") if self.base_path_is_set == False: self.btn_startAcquisition.setChecked(False) msg = QMessageBox() @@ -2585,9 +2591,8 @@ def toggle_acquisition(self, pressed): # Start coordinate-based acquisition self.multipointController.run_acquisition() else: + # This must eventually propagate through and call out acquisition_finished. self.multipointController.request_abort_aquisition() - self.is_current_acquisition_widget = False - self.setEnabled_all(True) def load_last_used_locations(self): if self.last_used_locations is None or len(self.last_used_locations) == 0: @@ -2984,6 +2989,10 @@ def import_location_list(self): self._log.debug(self.location_list) def acquisition_is_finished(self): + self._log.debug( + f"In FlexibleMultiPointWidget, got acquisition_is_finished with {self.is_current_acquisition_widget=}" + ) + if not self.is_current_acquisition_widget: return # Skip if this wasn't the widget that started acquisition @@ -3055,6 +3064,7 @@ def __init__( **kwargs, ): super().__init__(*args, **kwargs) + self._log = squid.logging.get_logger(self.__class__.__name__) self.stage = stage self.navigationViewer = navigationViewer self.multipointController = multipointController @@ -3665,6 +3675,7 @@ def update_live_coordinates(self, pos: squid.abc.Pos): self._last_y_mm = y_mm def toggle_acquisition(self, pressed): + self._log.debug(f"WellplateMultiPointWidget.toggle_acquisition, {pressed=}") if not self.base_path_is_set: self.btn_startAcquisition.setChecked(False) QMessageBox.warning(self, "Warning", "Please choose base saving directory first") @@ -3744,11 +3755,14 @@ def toggle_acquisition(self, pressed): self.multipointController.run_acquisition() else: + # This must eventually propagate through and call our aquisition_is_finished, or else we'll be left + # in an odd state. self.multipointController.request_abort_aquisition() - self.is_current_acquisition_widget = False - self.setEnabled_all(True) def acquisition_is_finished(self): + self._log.debug( + f"In WellMultiPointWidget, got acquisition_is_finished with {self.is_current_acquisition_widget=}" + ) if not self.is_current_acquisition_widget: return # Skip if this wasn't the widget that started acquisition