From 587b16cadbf1d3029fa51cdfb2e561f5038d2259 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 28 Jul 2026 10:50:13 -0700 Subject: [PATCH 1/6] fix stage scan speed restore --- .../model/acquisitions/AcquisitionEngineScape.java | 3 +++ 1 file changed, 3 insertions(+) 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 9656bde..4525dc7 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java @@ -179,6 +179,9 @@ boolean run() { "stage scanning previously. Do you want to set it to 1 mm/s now?"); if (result) { xyStage.setSpeedX(1.0); + // origSpeedX_ is the value finish() restores, so it has to track the change we + // just made; otherwise we put the small speed straight back at the end of the run + origSpeedX_ = 1.0; } } // TODO: add more checks from original plugin here... Z speed? From 3fd76f93726f916263866b1f6846c8666aa97f5e Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 28 Jul 2026 12:36:51 -0700 Subject: [PATCH 2/6] restore camera library switch for pseudo-overlap; both engines --- .../acquisitions/AcquisitionEngineDispim.java | 18 +++++++++++++++--- .../acquisitions/AcquisitionEngineScape.java | 14 +++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java index 01c43d0..8b38258 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java @@ -15,6 +15,7 @@ import org.micromanager.data.internal.DefaultSummaryMetadata; import org.micromanager.data.internal.ndtiff.NDTiffAdapter; import org.micromanager.internal.MMStudio; +import org.micromanager.lightsheetmanager.api.data.CameraLibrary; import org.micromanager.lightsheetmanager.api.data.CameraMode; import org.micromanager.lightsheetmanager.api.data.GeometryType; import org.micromanager.lightsheetmanager.api.data.ChannelMode; @@ -849,9 +850,20 @@ public DefaultTimingSettings.Builder getTimingFromPeriodAndLightExposure() { break; case PSEUDO_OVERLAP:// PCO or Photometrics, enforce 0.25ms between end exposure and start of next exposure by triggering camera 0.25ms into the slice cameraDuration = 1; // doesn't really matter, 1ms should be plenty fast yet easy to see for debugging - // TODO: not dealing with PVCAM (maybe throw error on unknown cam lib) - sliceDuration = getSliceDuration(delayBeforeScan, scanDuration, scansPerSlice, delayBeforeLaser, laserDuration, delayBeforeCamera, cameraDuration); - cameraExposure = sliceDuration - delayBeforeCamera; // s.cameraDelay should be 0.25ms for PCO + switch (CameraLibrary.fromString(camera.getDeviceLibrary())) { + case PVCAM: + // leave cameraExposure alone + break; + case PCOCAMERA: + sliceDuration = getSliceDuration(delayBeforeScan, scanDuration, scansPerSlice, + delayBeforeLaser, laserDuration, delayBeforeCamera, cameraDuration); + cameraExposure = sliceDuration - delayBeforeCamera; // delayBeforeCamera should be 0.25ms for PCO + break; + default: + studio_.logs().showError("Unknown camera library for pseudo-overlap " + + "calculations: " + camera.getDeviceLibrary()); + break; + } if (cameraReadoutMax < 0.24) { studio_.logs().showError("Camera delay should be at least 0.25ms for pseudo-overlap mode."); } 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 4525dc7..09a45d6 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java @@ -1352,9 +1352,17 @@ public DefaultTimingSettings.Builder getTimingFromPeriodAndLightExposure() { break; case PSEUDO_OVERLAP:// PCO or Photometrics, enforce 0.25ms between end exposure and start of next exposure by triggering camera 0.25ms into the slice // cameraTriggerDuration: doesn't really matter, 1ms should be plenty fast yet easy to see for debugging - // leave cameraExposure alone if using PVCAM device library - if (!camera.getDeviceLibrary().equals("PVCAM")) { - cameraExposure = tsb.sliceDuration() - delayBeforeCamera; // delayBeforeCamera should be 0.25ms for PCO + switch (CameraLibrary.fromString(camera.getDeviceLibrary())) { + case PVCAM: + // leave cameraExposure alone + break; + case PCOCAMERA: + cameraExposure = tsb.sliceDuration() - delayBeforeCamera; // delayBeforeCamera should be 0.25ms for PCO + break; + default: + studio_.logs().showError("Unknown camera library for pseudo-overlap " + + "calculations: " + camera.getDeviceLibrary()); + break; } if (cameraReadoutMax < 0.24) { studio_.logs().showError("Camera delay should be at least 0.25ms for pseudo-overlap mode."); From 1212c27ea954c5e9c677ebb41982b85a362acd5d Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 28 Jul 2026 13:54:00 -0700 Subject: [PATCH 3/6] remove redundant implements LightSheetCamera from camera subclasses --- .../lightsheetmanager/model/devices/cameras/AndorCamera.java | 3 +-- .../lightsheetmanager/model/devices/cameras/DemoCamera.java | 3 +-- .../model/devices/cameras/HamamatsuCamera.java | 3 +-- .../lightsheetmanager/model/devices/cameras/PcoCamera.java | 3 +-- .../lightsheetmanager/model/devices/cameras/PvCamera.java | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/AndorCamera.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/AndorCamera.java index cde8069..a5a5702 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/AndorCamera.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/AndorCamera.java @@ -1,7 +1,6 @@ package org.micromanager.lightsheetmanager.model.devices.cameras; import org.micromanager.Studio; -import org.micromanager.lightsheetmanager.api.LightSheetCamera; import org.micromanager.lightsheetmanager.api.data.CameraMode; import java.awt.Rectangle; @@ -11,7 +10,7 @@ *

Device Adapter: AndorSDK3 *

Camera Support: Andor Zyla 4.2, Andor Zyla 5.5 */ -public class AndorCamera extends CameraBase implements LightSheetCamera { +public class AndorCamera extends CameraBase { public static class Models { public static final String ZYLA55 = "Zyla 5.5"; diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/DemoCamera.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/DemoCamera.java index 74046a0..ac899b1 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/DemoCamera.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/DemoCamera.java @@ -1,7 +1,6 @@ package org.micromanager.lightsheetmanager.model.devices.cameras; import org.micromanager.Studio; -import org.micromanager.lightsheetmanager.api.LightSheetCamera; import org.micromanager.lightsheetmanager.api.data.CameraMode; import java.awt.Rectangle; @@ -12,7 +11,7 @@ *

Device Adapter: DHub *

Camera Support: DemoCamera */ -public class DemoCamera extends CameraBase implements LightSheetCamera { +public class DemoCamera extends CameraBase { public static class Properties { public static final String BINNING = "Binning"; diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/HamamatsuCamera.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/HamamatsuCamera.java index fca3367..8a7104b 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/HamamatsuCamera.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/HamamatsuCamera.java @@ -1,7 +1,6 @@ package org.micromanager.lightsheetmanager.model.devices.cameras; import org.micromanager.Studio; -import org.micromanager.lightsheetmanager.api.LightSheetCamera; import org.micromanager.lightsheetmanager.api.data.CameraMode; import java.awt.Rectangle; @@ -11,7 +10,7 @@ *

Device Adapter: HamamatsuHam *

Camera Support: ORCA-Flash4, ORCA-Fusion, ORCA-Fusion BT */ -public class HamamatsuCamera extends CameraBase implements LightSheetCamera { +public class HamamatsuCamera extends CameraBase { public static class Models { public static final String FUSION_BT = "C15440"; public static final String FUSION = "C14440"; diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PcoCamera.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PcoCamera.java index 3ac7243..1e45c41 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PcoCamera.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PcoCamera.java @@ -1,7 +1,6 @@ package org.micromanager.lightsheetmanager.model.devices.cameras; import org.micromanager.Studio; -import org.micromanager.lightsheetmanager.api.LightSheetCamera; import org.micromanager.lightsheetmanager.api.data.CameraMode; import java.awt.Rectangle; @@ -12,7 +11,7 @@ *

Device Adapter: PCO_Camera *

Camera Support: Edge 5.5, Panda */ -public class PcoCamera extends CameraBase implements LightSheetCamera { +public class PcoCamera extends CameraBase { public static class Models { public static final String EDGE55 =" 5.5"; diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PvCamera.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PvCamera.java index 5370c09..bfac4b4 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PvCamera.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/PvCamera.java @@ -1,7 +1,6 @@ package org.micromanager.lightsheetmanager.model.devices.cameras; import org.micromanager.Studio; -import org.micromanager.lightsheetmanager.api.LightSheetCamera; import org.micromanager.lightsheetmanager.api.data.CameraMode; import java.awt.Rectangle; @@ -11,7 +10,7 @@ *

Device Adapter: PVCAM *

Camera Support: Kinetix, Prime 95B, Prime */ -public class PvCamera extends CameraBase implements LightSheetCamera { +public class PvCamera extends CameraBase { public static class Models { public static final String PRIME = "CIS2020F"; From 21fbea5a569c38765fcc04811f012e94032c723c Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 28 Jul 2026 14:58:05 -0700 Subject: [PATCH 4/6] make vendor camera methods abstract; add UnknownCamera --- .../model/DeviceManager.java | 7 ++-- .../model/devices/cameras/CameraBase.java | 32 +++++++------------ 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java b/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java index a0f72b2..f88ccc7 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/DeviceManager.java @@ -21,6 +21,7 @@ import org.micromanager.lightsheetmanager.model.devices.cameras.HamamatsuCamera; import org.micromanager.lightsheetmanager.model.devices.cameras.PcoCamera; import org.micromanager.lightsheetmanager.model.devices.cameras.PvCamera; +import org.micromanager.lightsheetmanager.model.devices.cameras.UnknownCamera; import org.micromanager.lightsheetmanager.model.devices.vendor.ASIPLogic; import org.micromanager.lightsheetmanager.model.devices.vendor.ASIPiezo; import org.micromanager.lightsheetmanager.model.devices.vendor.ASIScanner; @@ -222,10 +223,10 @@ private void createCameraDevice(final String propertyName, final String deviceNa addDevice(propertyName, deviceName, demoCamera); break; default: - CameraBase camera = new CameraBase(studio_, deviceName); + UnknownCamera camera = new UnknownCamera(studio_, deviceName); addDevice(propertyName, deviceName, camera); - studio_.logs().logError( - "Camera device library \"" + cameraLibrary + "\" not supported, using basic camera."); + studio_.logs().logError("Camera device library \"" + cameraLibrary + + "\" not supported; exposure and ROI will work but timing values are unknown."); break; } } diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/CameraBase.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/CameraBase.java index 5be8c5e..5945637 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/CameraBase.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/CameraBase.java @@ -7,12 +7,14 @@ import java.awt.Rectangle; -// TODO: consider removing implements LightSheetCamera so no default methods for subclasses - /** * This is the base camera class. + * + *

Methods that need per-vendor knowledge are abstract on purpose: a camera class that + * forgets one fails to compile. Cameras whose device library resolves to + * {@code CameraLibrary.UNKNOWN} use {@link UnknownCamera}. */ -public class CameraBase extends DeviceBase implements LightSheetCamera { +public abstract class CameraBase extends DeviceBase implements LightSheetCamera { protected CameraMode mode_; @@ -96,32 +98,20 @@ public CameraMode getTriggerMode() { } @Override - public void setBinning() { - - } + public abstract void setBinning(); @Override - public int getBinning() { - return 0; - } + public abstract int getBinning(); @Override - public Rectangle getResolution() { - return new Rectangle(); - } + public abstract Rectangle getResolution(); @Override - public double getRowReadoutTime() { - return 0; - } + public abstract double getRowReadoutTime(); @Override - public double getReadoutTime(CameraMode cameraMode) { - return 0; - } + public abstract double getReadoutTime(CameraMode cameraMode); @Override - public double getResetTime(CameraMode cameraMode) { - return 0; - } + public abstract double getResetTime(CameraMode cameraMode); } From c747ff102cccd8960770fb9843d49a1a1390a9ef Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 28 Jul 2026 15:09:36 -0700 Subject: [PATCH 5/6] read camera mode from settings, not camera readback; both engines. --- .../model/acquisitions/AcquisitionEngineDispim.java | 8 ++++---- .../model/acquisitions/AcquisitionEngineScape.java | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java index 8b38258..5562165 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineDispim.java @@ -641,7 +641,8 @@ private boolean doHardwareCalculations(PLogicDispim plc) { // TODO: code that doubles nrSlicesSoftware if (twoSided && acqBothCameras) missing CameraBase camera = model_.devices().device("Imaging1Camera"); - CameraMode camMode = camera.getTriggerMode(); + // settings are the source of truth for camera mode + CameraMode camMode = acqSettings_.cameraMode(); final double cameraReadoutTime = camera.getReadoutTime(camMode); final double exposureTime = acqSettings_.timing().cameraExposure(); @@ -767,9 +768,8 @@ public DefaultTimingSettings.Builder getTimingFromPeriodAndLightExposure() { // TODO: do this in ui? camera.setTriggerMode(acqSettings_.cameraMode()); - //System.out.println(camera.getDeviceName()); - CameraMode camMode = camera.getTriggerMode(); - //System.out.println(camMode); + // settings are the source of truth for camera mode + CameraMode camMode = acqSettings_.cameraMode(); DefaultTimingSettings.Builder tsb = DefaultTimingSettings.builder(); 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 09a45d6..8259b04 100644 --- a/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java +++ b/src/main/java/org/micromanager/lightsheetmanager/model/acquisitions/AcquisitionEngineScape.java @@ -1247,10 +1247,8 @@ public DefaultTimingSettings.Builder getTimingFromPeriodAndLightExposure() { cam.setTriggerMode(acqSettings_.cameraMode()); } - // TODO: camera.getTriggerMode(); does not match up with actual selected trigger mode for PVCAM (pseudo overlap reads as edge trigger) - //System.out.println(camera.getDeviceName()); - CameraMode camMode = acqSettings_.cameraMode(); // camera.getTriggerMode(); - //System.out.println(camMode); + // settings are the source of truth for camera mode + CameraMode camMode = acqSettings_.cameraMode(); final double scanLaserBufferTime = NumberUtils.roundToQuarterMs(0.25); // below assumed to be multiple of 0.25ms From 2eb5f774fe0c2796030184793bb915e527b3dfc0 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 28 Jul 2026 15:39:02 -0700 Subject: [PATCH 6/6] add UnknownCamera --- .../model/devices/cameras/UnknownCamera.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/UnknownCamera.java diff --git a/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/UnknownCamera.java b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/UnknownCamera.java new file mode 100644 index 0000000..90c32f8 --- /dev/null +++ b/src/main/java/org/micromanager/lightsheetmanager/model/devices/cameras/UnknownCamera.java @@ -0,0 +1,58 @@ +package org.micromanager.lightsheetmanager.model.devices.cameras; + +import org.micromanager.Studio; +import org.micromanager.lightsheetmanager.api.data.CameraMode; + +import java.awt.Rectangle; + +/** + * Stand-in for a camera whose device adapter the plugin does not have a class for. + * + *

Device setup still completes so the plugin opens and the rest of the configuration stays + * usable, and the generic operations inherited from {@link CameraBase} (exposure, ROI) work + * through the Core for any camera. Only the values that need vendor knowledge fail, and they + * fail loudly: returning a zero for readout or reset time would flow straight into the + * slice-timing math and produce a plausible-looking but wrong acquisition. + */ +public class UnknownCamera extends CameraBase { + + public UnknownCamera(final Studio studio, final String deviceName) { + super(studio, deviceName); + } + + private UnsupportedOperationException unsupported(final String what) { + return new UnsupportedOperationException("Camera \"" + deviceName_ + + "\" uses a device adapter the plugin does not support, so " + what + + " is unknown. Supported: AndorSDK3, HamamatsuHam, PCO_Camera, PVCAM, DemoCamera."); + } + + @Override + public void setBinning() { + throw unsupported("binning"); + } + + @Override + public int getBinning() { + throw unsupported("binning"); + } + + @Override + public Rectangle getResolution() { + throw unsupported("sensor resolution"); + } + + @Override + public double getRowReadoutTime() { + throw unsupported("row readout time"); + } + + @Override + public double getReadoutTime(final CameraMode cameraMode) { + throw unsupported("readout time"); + } + + @Override + public double getResetTime(final CameraMode cameraMode) { + throw unsupported("reset time"); + } +}