From 494c809ca2730cb138b5bc2221ff89a12482d95b Mon Sep 17 00:00:00 2001 From: Brandon Date: Thu, 11 Apr 2024 17:31:41 -0700 Subject: [PATCH] add setup and cleanup code for stage scanning --- .../lightsheetmanager/model/PLogicSCAPE.java | 19 ++++++ .../acquisitions/AcquisitionEngineSCAPE.java | 63 +++++++++++++++---- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/PLogicSCAPE.java b/src/main/java/org/micromanager/lightsheetmanager/model/PLogicSCAPE.java index 770d72d..b769dac 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/PLogicSCAPE.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/PLogicSCAPE.java @@ -1120,6 +1120,25 @@ public void setPathPreset(int side) { public void stopSPIMStateMachines() { scanner_.setSPIMState(ASIScanner.SPIMState.IDLE); + if (acqSettings_.isUsingStageScanning()) { + // give the stage scan 5 seconds to clean itself up, after which we stop it + // once all images come in there is still a time when stage is moving back to its start/center position + final int timeoutStageScanCleanupMs = 5000; + final long deadline = System.currentTimeMillis() + timeoutStageScanCleanupMs; + while (xyStage_.getScanState() == ASIXYStage.ScanState.IDLE) { + if (System.currentTimeMillis() > deadline) { + xyStage_.setScanState(ASIXYStage.ScanState.IDLE); // force-set to idle + studio_.logs().logError("Force-set XY stage scan to IDLE state with stage speed " + + xyStage_.getSpeedX() + "."); + } else { + try { + Thread.sleep(25); // still waiting... + } catch (InterruptedException e) { + // ignore => only need to busy wait + } + } + } + } } // private void stopSPIMStateMachines(DefaultAcquisitionSettingsDISPIM acqSettings) { diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java index 7c9ad77..b21193a 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineSCAPE.java @@ -36,6 +36,7 @@ import org.micromanager.lightsheetmanager.model.utils.FileUtils; import org.micromanager.lightsheetmanager.model.utils.NumberUtils; +import java.awt.geom.Point2D; import java.io.IOException; import java.util.ArrayList; @@ -79,25 +80,38 @@ boolean run() { final boolean isUsingPLC = model_.devices().isUsingPLogic(); + // initialize stage scanning so we can restore state + Point2D.Double xyPosUm = new Point2D.Double(); + double xSupPosUm = 0.0; + double origXSpeed = 1.0; // don't want 0 in case something goes wrong + double origXAccel = 1.0; // don't want 0 in case something goes wrong + // make sure stage scan is supported if selected - if (isUsingPLC) { - if (acqSettings_.isUsingStageScanning()) { - final ASIXYStage xyStage = model_.devices().getDevice("SampleXY"); - if (xyStage != null) { - if (!xyStage.hasProperty(ASIXYStage.Properties.SCAN_NUM_LINES)) { - studio_.logs().showError("Must have stage with scan-enabled firmware for stage scanning."); - return false; - } - if (acqSettings_.acquisitionMode() == AcquisitionMode.STAGE_SCAN_INTERLEAVED) { - if (acqSettings_.volumeSettings().numViews() < 2) { - studio_.logs().showError("Interleaved stage scan requires two sides."); - } - return false; + if (acqSettings_.isUsingStageScanning()) { + final ASIXYStage xyStage = model_.devices().getDevice("SampleXY"); + if (xyStage != null) { + if (!xyStage.hasProperty(ASIXYStage.Properties.SCAN_NUM_LINES)) { + studio_.logs().showError("Must have stage with scan-enabled firmware for stage scanning."); + return false; + } + if (acqSettings_.acquisitionMode() == AcquisitionMode.STAGE_SCAN_INTERLEAVED) { + if (acqSettings_.volumeSettings().numViews() < 2) { + studio_.logs().showError("Interleaved stage scan requires two sides."); } + return false; } + + // second part: initialize stage scanning so we can restore state + xyPosUm = xyStage.getXYPosition(); + origXSpeed = xyStage.getSpeedX(); + origXAccel = xyStage.getAccelerationX(); + + // TODO: add more checks from orignal plugin here... + // if (origXSpeed < 0.2 && resetXaxisSpeed_) { etc... } } + PLogicSCAPE controller = null; // Assume demo mode if default camera is DemoCamera @@ -557,6 +571,23 @@ public void close() { controller.stopSPIMStateMachines(); } + // if we did stage scanning restore the original position and speed + if (acqSettings_.isUsingStageScanning()) { + final ASIXYStage xyStage = model_.devices().getDevice("SampleXY"); + final boolean returnToOriginalPosition = + acqSettings_.scanSettings().scanReturnToOriginalPosition(); + + // make sure stage scanning state machine is stopped, + // otherwise setting speed/position won't take + xyStage.setScanState(ASIXYStage.ScanState.IDLE); + xyStage.setSpeedX(origXSpeed); + xyStage.setAccelerationX(origXAccel); + + if (returnToOriginalPosition) { + xyStage.setXYPosition(xyPosUm.x, xyPosUm.y); + } + } + // Restore shutter/autoshutter to original state try { core_.setShutterOpen(isShutterOpen); @@ -775,6 +806,12 @@ private boolean doHardwareCalculations(PLogicSCAPE plc) { "with software channels (need to use PLogic channel switching)."); return false; } + if (acqSettings_.isUsingStageScanning()) { + // stage scanning needs to be triggered for each time point + studio_.logs().showError("Cannot use hardware time points (small time point interval) " + + "with stage scanning."); + return false; + } } double extraChannelOffset = 0.0;