Fix capture error handing

The error handling for capture needs to still send the aquired event
or it will lock forever. On getting the errors to work there
were some other minor issues in how the errors were called.
This commit is contained in:
Julian Stirling 2025-04-09 23:52:47 +01:00
parent 70e7a21a29
commit 83d2930d1f

View file

@ -152,14 +152,13 @@ ZipBlob = blob_type("application/zip")
class SmartScanThing(Thing):
def __init__(self, path_to_openflexure_stitch: str):
self._script = path_to_openflexure_stitch
self._stitching_script = path_to_openflexure_stitch
self._preview_stitch_popen = None
self._preview_stitch_popen_lock = threading.Lock()
self._correlate_popen = None
self._correlate_popen_lock = threading.Lock()
self._scan_lock = threading.Lock()
# Variables set by the scan
self._latest_scan_name = None
self._cancel = None
@ -217,9 +216,11 @@ class SmartScanThing(Thing):
# record starting position so we can return there
self._starting_position = self._stage.position
self._run_scan(scan_name, overlap)
except:
except Exception as e:
self._return_to_starting_position()
self._perform_final_stitch(overlap)
# Error must be raised so UI gives correct output
raise e
finally:
# However the scan finnishes unset all variables and release lock
self._cancel = None
@ -550,6 +551,7 @@ class SmartScanThing(Thing):
)
capture_thread.start()
acquired.wait() # wait until the image is acquired
positions.append(loc[:2])
names.append(name)
@ -637,6 +639,7 @@ class SmartScanThing(Thing):
download_zip=False,
)
self._logger.info("Waiting for background processes to finish...")
self.preview_stitch_wait()
self.correlate_wait()
try:
@ -658,9 +661,12 @@ class SmartScanThing(Thing):
This will set the event `acquired` once the image has been acquired, so
that the stage may be moved while it's saved.
"""
capture_start = time.time()
image, metadata = self.capture_image()
acquired.set()
try:
capture_start = time.time()
image, metadata = self.capture_image()
finally:
# Ensure aquired is set even if capture fails or program will hang forever.
acquired.set()
acquisition_time = time.time()
self.save_capture(jpeg_path, image, metadata)
save_time = time.time()
@ -681,9 +687,7 @@ class SmartScanThing(Thing):
metadata = self._metadata_getter()
image = self._cam.capture_array()[..., :3]
except Exception as e:
raise CaptureError(
"An error occurred while capturing: {}".format(e), exc_info=e
)
raise CaptureError("An error occurred while capturing") from e
return image, metadata
def save_capture(
@ -709,10 +713,7 @@ class SmartScanThing(Thing):
except:
self._logger.warning(f"Failed to add metadata to {jpeg_path}")
except Exception as e:
raise IOError(
f"An error occurred while saving {jpeg_path}: {e}",
exc_info=e,
)
raise IOError(f"An error occurred while saving {jpeg_path}") from e
@thing_property
def max_range(self) -> int:
@ -905,12 +906,24 @@ class SmartScanThing(Thing):
return FileResponse(path)
def preview_stitch_start(self, images_folder: str) -> None:
"""Start stitching a preview of the scan in a subprocess"""
"""Start stitching a preview of the scan in a backgroun subprocess
This uses popen and returns immediatly
- self._preview_stitch_popen holds the popen for polling
- self._preview_stitch_popen_lock is a lock aquired while interacting
with Popen
"""
if self.preview_stitch_running():
raise RuntimeError("Only one subprocess is allowed at a time")
with self._preview_stitch_popen_lock:
self._preview_stitch_popen = Popen(
[self._script, "--stitching_mode", "only_stage_stitch", images_folder]
[
self._stitching_script,
"--stitching_mode",
"only_stage_stitch",
images_folder,
]
)
def preview_stitch_running(self) -> bool:
@ -934,7 +947,7 @@ class SmartScanThing(Thing):
with self._correlate_popen_lock:
self._correlate_popen = Popen(
[
self._script,
self._stitching_script,
"--stitching_mode",
"only_correlate",
"--minimum_overlap",
@ -1012,7 +1025,7 @@ class SmartScanThing(Thing):
overlap = 0.1
self.run_subprocess(
[
self._script,
self._stitching_script,
"--stitching_mode",
"all",
f"{tiff_arg}",