From 67dbe2b87f780bc0a8aa3da0d75a0503c5903453 Mon Sep 17 00:00:00 2001 From: Lars Kool Date: Mon, 24 Jun 2024 10:07:29 +0200 Subject: [PATCH 1/3] Splitting Pump device into PressurePump and VolumetricPump --- MMCore/CoreUtils.h | 2 + MMCore/Devices/DeviceInstances.h | 2 + MMCore/Devices/PressurePumpInstance.cpp | 30 ++ MMCore/Devices/PressurePumpInstance.h | 45 ++ MMCore/Devices/VolumetricPumpInstance.cpp | 39 ++ MMCore/Devices/VolumetricPumpInstance.h | 53 ++ .../LoadableModules/LoadedDeviceAdapter.cpp | 4 + MMCore/MMCore.cpp | 474 +++++++++++++++++- MMCore/MMCore.h | 41 ++ MMCore/MMCore.vcxproj | 6 +- MMCore/MMCore.vcxproj.filters | 20 +- MMCore/Makefile.am | 4 + MMCore/meson.build | 2 + MMDevice/DeviceBase.h | 89 ++++ .../MMDevice-SharedRuntime.vcxproj.filters | 2 +- MMDevice/MMDevice.cpp | 2 + MMDevice/MMDevice.h | 205 ++++++++ MMDevice/MMDeviceConstants.h | 50 +- micromanager.sln | 16 +- 19 files changed, 1057 insertions(+), 29 deletions(-) create mode 100644 MMCore/Devices/PressurePumpInstance.cpp create mode 100644 MMCore/Devices/PressurePumpInstance.h create mode 100644 MMCore/Devices/VolumetricPumpInstance.cpp create mode 100644 MMCore/Devices/VolumetricPumpInstance.h diff --git a/MMCore/CoreUtils.h b/MMCore/CoreUtils.h index d8b6718e5..779930684 100644 --- a/MMCore/CoreUtils.h +++ b/MMCore/CoreUtils.h @@ -72,6 +72,8 @@ inline std::string ToString(const MM::DeviceType d) case MM::SLMDevice: return "SLM"; case MM::HubDevice: return "Hub"; case MM::GalvoDevice: return "Galvo"; + case MM::PressurePumpDevice: return "PressurePump"; + case MM::VolumetricPumpDevice: return "VolumetricPump"; } return "Invalid"; } diff --git a/MMCore/Devices/DeviceInstances.h b/MMCore/Devices/DeviceInstances.h index 8dfacf4d7..e7ccae517 100644 --- a/MMCore/Devices/DeviceInstances.h +++ b/MMCore/Devices/DeviceInstances.h @@ -33,3 +33,5 @@ #include "SLMInstance.h" #include "GalvoInstance.h" #include "HubInstance.h" +#include "PressurePumpInstance.h" +#include "VolumetricPumpInstance.h" diff --git a/MMCore/Devices/PressurePumpInstance.cpp b/MMCore/Devices/PressurePumpInstance.cpp new file mode 100644 index 000000000..8b5e8119b --- /dev/null +++ b/MMCore/Devices/PressurePumpInstance.cpp @@ -0,0 +1,30 @@ +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +// +// DESCRIPTION: PressurePump device instance wrapper +// +// COPYRIGHT: Institut Pierre-Gilles de Gennes, Paris, 2024, +// All Rights reserved +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Lars Kool, Institut Pierre-Gilles de Gennes + +#include "PressurePumpInstance.h" +#include "../../MMDevice/MMDeviceConstants.h" + +// General pump functions +int PressurePumpInstance::Stop() { return GetImpl()->Stop(); } +int PressurePumpInstance::Calibrate() { return GetImpl()->Calibrate(); } +bool PressurePumpInstance::requiresCalibration() { return GetImpl()->RequiresCalibration(); } +int PressurePumpInstance::setPressure(double pressure) { return GetImpl()->SetPressure(pressure); } +int PressurePumpInstance::getPressure(double& pressure) { return GetImpl()->GetPressure(pressure); } \ No newline at end of file diff --git a/MMCore/Devices/PressurePumpInstance.h b/MMCore/Devices/PressurePumpInstance.h new file mode 100644 index 000000000..7e4a189a2 --- /dev/null +++ b/MMCore/Devices/PressurePumpInstance.h @@ -0,0 +1,45 @@ +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +// +// DESCRIPTION: Pump device instance wrapper +// +// COPYRIGHT: Institut Pierre-Gilles de Gennes, Paris, 2024, +// All Rights reserved +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Lars Kool, Institut Pierre-Gilles de Gennes + +#include "DeviceInstanceBase.h" +#include "../../MMDevice/MMDeviceConstants.h" + +class PressurePumpInstance : public DeviceInstanceBase +{ +public: + PressurePumpInstance(CMMCore* core, + std::shared_ptr adapter, + const std::string& name, + MM::Device* pDevice, + DeleteDeviceFunction deleteFunction, + const std::string& label, + mm::logging::Logger deviceLogger, + mm::logging::Logger coreLogger) : + DeviceInstanceBase(core, adapter, name, pDevice, deleteFunction, label, deviceLogger, coreLogger) + {} + + + int Calibrate(); + int Stop(); + bool requiresCalibration(); + int setPressure(double pressure); + int getPressure(double& pressure); +}; diff --git a/MMCore/Devices/VolumetricPumpInstance.cpp b/MMCore/Devices/VolumetricPumpInstance.cpp new file mode 100644 index 000000000..088356085 --- /dev/null +++ b/MMCore/Devices/VolumetricPumpInstance.cpp @@ -0,0 +1,39 @@ +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +// +// DESCRIPTION: Pump device instance wrapper +// +// COPYRIGHT: Institut Pierre-Gilles de Gennes, Paris, 2024, +// All Rights reserved +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Lars Kool, Institut Pierre-Gilles de Gennes + +#include "VolumetricPumpInstance.h" +#include "../../MMDevice/MMDeviceConstants.h" + +// Volume controlled pump functions +int VolumetricPumpInstance::Home() { return GetImpl()->Home(); } +int VolumetricPumpInstance::Stop() { return GetImpl()->Stop(); } +bool VolumetricPumpInstance::requiresHoming() { return GetImpl()->RequiresHoming(); } +int VolumetricPumpInstance::invertDirection(bool state) { return GetImpl()->InvertDirection(state); } +int VolumetricPumpInstance::isDirectionInverted(bool& state) { return GetImpl()->IsDirectionInverted(state); } +int VolumetricPumpInstance::setVolumeUl(double volume) { return GetImpl()->SetVolumeUl(volume); } +int VolumetricPumpInstance::getVolumeUl(double& volume) { return GetImpl()->GetVolumeUl(volume); } +int VolumetricPumpInstance::setMaxVolumeUl(double volume) { return GetImpl()->SetMaxVolumeUl(volume); } +int VolumetricPumpInstance::getMaxVolumeUl(double& volume) { return GetImpl()->GetMaxVolumeUl(volume); } +int VolumetricPumpInstance::setFlowrateUlPerSec(double flowrate) { return GetImpl()->SetFlowrateUlPerSecond(flowrate); } +int VolumetricPumpInstance::getFlowrateUlPerSec(double& flowrate) { return GetImpl()->GetFlowrateUlPerSecond(flowrate); } +int VolumetricPumpInstance::Start() { return GetImpl()->Start(); } +int VolumetricPumpInstance::DispenseDuration(double durSec) { return GetImpl()->DispenseDuration(durSec); } +int VolumetricPumpInstance::DispenseVolume(double volUl) { return GetImpl()->DispenseVolume(volUl); } diff --git a/MMCore/Devices/VolumetricPumpInstance.h b/MMCore/Devices/VolumetricPumpInstance.h new file mode 100644 index 000000000..7e0baf6ea --- /dev/null +++ b/MMCore/Devices/VolumetricPumpInstance.h @@ -0,0 +1,53 @@ +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +// +// DESCRIPTION: Pump device instance wrapper +// +// COPYRIGHT: Institut Pierre-Gilles de Gennes, Paris, 2024, +// All Rights reserved +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Lars Kool, Institut Pierre-Gilles de Gennes + +#include "DeviceInstanceBase.h" +#include "../../MMDevice/MMDeviceConstants.h" + +class VolumetricPumpInstance : public DeviceInstanceBase +{ +public: + VolumetricPumpInstance(CMMCore* core, + std::shared_ptr adapter, + const std::string& name, + MM::Device* pDevice, + DeleteDeviceFunction deleteFunction, + const std::string& label, + mm::logging::Logger deviceLogger, + mm::logging::Logger coreLogger) : + DeviceInstanceBase(core, adapter, name, pDevice, deleteFunction, label, deviceLogger, coreLogger) + {} + + int Home(); + int Stop(); + bool requiresHoming(); + int invertDirection(bool state); + int isDirectionInverted(bool& state); + int setVolumeUl(double volUl); + int getVolumeUl(double& volUl); + int setMaxVolumeUl(double volUl); + int getMaxVolumeUl(double& volUl); + int setFlowrateUlPerSec(double flowrate); + int getFlowrateUlPerSec(double& flowrate); + int Start(); + int DispenseDuration(double durSec); + int DispenseVolume(double volUl); +}; diff --git a/MMCore/LoadableModules/LoadedDeviceAdapter.cpp b/MMCore/LoadableModules/LoadedDeviceAdapter.cpp index caf2a3404..1dd68e363 100644 --- a/MMCore/LoadableModules/LoadedDeviceAdapter.cpp +++ b/MMCore/LoadableModules/LoadedDeviceAdapter.cpp @@ -185,6 +185,10 @@ LoadedDeviceAdapter::LoadDevice(CMMCore* core, const std::string& name, return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); case MM::HubDevice: return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); + case MM::PressurePumpDevice: + return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); + case MM::VolumetricPumpDevice: + return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); default: deleter(pDevice); throw CMMError("Device " + ToQuotedString(name) + diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index 4bef95471..623f53546 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -1903,6 +1903,7 @@ void CMMCore::setAdapterOriginXY(double newXUm, double newYUm) throw (CMMError) * The returned value is determined by the most recent call to * setFocusDirection() for the stage, or defaults to what the stage device * adapter declares (often 0, for unknown). + * adapter declares (often 0, for unknown). * * An exception is thrown if the direction has not been set and the device * encounters an error when determining the default direction. @@ -3228,6 +3229,32 @@ std::string CMMCore::getAutoFocusDevice() return std::string(); } +/** + * Returns the label of the currently selected pressure pump. + */ +std::string CMMCore::getPressurePumpDevice() +{ + std::shared_ptr pump = currentPressurePump_.lock(); + if (pump) + { + return pump->GetLabel(); + } + return std::string(); +} + +/** + * Returns the label of the currently selected volumetric pump. + */ +std::string CMMCore::getVolumetricPumpDevice() +{ + std::shared_ptr pump = currentVolumetricPump_.lock(); + if (pump) + { + return pump->GetLabel(); + } + return std::string(); +} + /** * Sets the current auto-focus device. */ @@ -6214,6 +6241,452 @@ std::string CMMCore::getGalvoChannel(const char* deviceLabel) throw (CMMError) return pGalvo->GetChannel(); } +/////////////////////////////////////////////////////////////////////////////// +// Pressure Pump methods +/////////////////////////////////////////////////////////////////////////////// + +/** + * Sets the current pump device. + * @param pump the shutter device label + */ +void CMMCore::setPressurePumpDevice(const char* deviceLabel) throw (CMMError) +{ + if (!deviceLabel || strlen(deviceLabel) > 0) // Allow empty label + CheckDeviceLabel(deviceLabel); + + // Nothing to do if this is the current shutter device: + if (getPressurePumpDevice().compare(deviceLabel) == 0) + return; + + if (strlen(deviceLabel) > 0) + { + currentPressurePump_ = + deviceManager_->GetDeviceOfType(deviceLabel); + + LOG_INFO(coreLogger_) << "Default shutter set to " << deviceLabel; + } + else + { + currentPressurePump_.reset(); + LOG_INFO(coreLogger_) << "Default pump unset"; + } + properties_->Refresh(); // TODO: more efficient + std::string newPumpLabel = getPressurePumpDevice(); + { + MMThreadGuard scg(stateCacheLock_); + stateCache_.addSetting(PropertySetting(MM::g_Keyword_CoreDevice, MM::g_Keyword_CorePressurePump, newPumpLabel.c_str())); + } +} + +/** + * Sets the current pump device. + * @param pump the shutter device label + */ +void CMMCore::setPressurePumpDevice(const char* deviceLabel) throw (CMMError) +{ + if (!deviceLabel || strlen(deviceLabel) > 0) // Allow empty label + CheckDeviceLabel(deviceLabel); + + // Nothing to do if this is the current shutter device: + if (getPressurePumpDevice().compare(deviceLabel) == 0) + return; + + if (strlen(deviceLabel) > 0) + { + currentPressurePump_ = + deviceManager_->GetDeviceOfType(deviceLabel); + + LOG_INFO(coreLogger_) << "Default shutter set to " << deviceLabel; + } + else + { + currentPressurePump_.reset(); + LOG_INFO(coreLogger_) << "Default pump unset"; + } + properties_->Refresh(); // TODO: more efficient + std::string newPumpLabel = getPressurePumpDevice(); + { + MMThreadGuard scg(stateCacheLock_); + stateCache_.addSetting(PropertySetting(MM::g_Keyword_CoreDevice, MM::g_Keyword_CorePressurePump, newPumpLabel.c_str())); + } +} + +/** +* Stops the pressure pump +*/ +void CMMCore::PressurePumpStop(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->Stop(); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Calibrates the pump +*/ +void CMMCore::PressurePumpCalibrate(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->Calibrate(); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Returns boolean whether the pump is operational before calibration +*/ +bool CMMCore::PressurePumpRequiresCalibration(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + return pPump->requiresCalibration(); +} + +/** +* Sets the pressure of the pump in kPa +*/ +void CMMCore::setPumpPressure(const char* deviceLabel, double pressurekPa) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->setPressure(pressurekPa); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Gets the pressure of the pump in kPa +*/ +double CMMCore::getPumpPressure(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + double pressurekPa = 0; + int ret = pPump->getPressure(pressurekPa); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } + return pressurekPa; +} + +/////////////////////////////////////////////////////////////////////////////// +// Volumetric Pump methods +/////////////////////////////////////////////////////////////////////////////// + +/** + * Sets the current pump device. + * @param pump the shutter device label + */ +void CMMCore::setVolumetricPumpDevice(const char* deviceLabel) throw (CMMError) +{ + if (!deviceLabel || strlen(deviceLabel) > 0) // Allow empty label + CheckDeviceLabel(deviceLabel); + + // Nothing to do if this is the current shutter device: + if (getVolumetricPumpDevice().compare(deviceLabel) == 0) + return; + + if (strlen(deviceLabel) > 0) + { + currentVolumetricPump_ = + deviceManager_->GetDeviceOfType(deviceLabel); + + LOG_INFO(coreLogger_) << "Default shutter set to " << deviceLabel; + } + else + { + currentVolumetricPump_.reset(); + LOG_INFO(coreLogger_) << "Default pump unset"; + } + properties_->Refresh(); // TODO: more efficient + std::string newPumpLabel = getVolumetricPumpDevice(); + { + MMThreadGuard scg(stateCacheLock_); + stateCache_.addSetting(PropertySetting(MM::g_Keyword_CoreDevice, MM::g_Keyword_CoreVolumetricPump, newPumpLabel.c_str())); + } +} + +/** +* Stops the volumetric pump +*/ +void CMMCore::VolumetricPumpStop(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->Stop(); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Homes the pump +*/ +void CMMCore::VolumetricPumpHome(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->Home(); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +bool CMMCore::VolumetricPumpRequiresHoming(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + return pPump->requiresHoming(); +} + +/** +* Sets whether the pump direction needs to be inverted +*/ +void CMMCore::invertPumpDirection(const char* deviceLabel, bool invert) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->invertDirection(invert); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Gets whether the pump direction needs to be inverted +*/ +bool CMMCore::isPumpDirectionInverted(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + bool invert = false; + int ret = pPump->isDirectionInverted(invert); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } + return invert; +} + +/** +* Sets the volume of fluid in the pump in uL. Note it does not withdraw upto +* this amount. It is merely to inform MM of the volume in a prefilled pump. +*/ +void CMMCore::setPumpVolume(const char* deviceLabel, double volUl) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->setVolumeUl(volUl); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Get the fluid volume in the pump in uL +*/ +double CMMCore::getPumpVolume(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + double volUl = 0; + int ret = pPump->getVolumeUl(volUl); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } + return volUl; +} + +/** +* Sets the max volume of the pump in uL +*/ +void CMMCore::setPumpMaxVolume(const char* deviceLabel, double volUl) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->setMaxVolumeUl(volUl); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Gets the max volume of the pump in uL +*/ +double CMMCore::getPumpMaxVolume(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + double volUl = 0; + int ret = pPump->getMaxVolumeUl(volUl); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } + return volUl; +} + +/** +* Sets the flowrate of the pump in uL per second +*/ +void CMMCore::setPumpFlowrate(const char* deviceLabel, double UlperSec) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->setFlowrateUlPerSec(UlperSec); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Gets the flowrate of the pump in uL per second +*/ +double CMMCore::getPumpFlowrate(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + double UlperSec = 0; + int ret = pPump->getFlowrateUlPerSec(UlperSec); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } + return UlperSec; +} + +/** +* Start dispensing at the set flowrate until syringe is empty, or manually +* stopped (whichever occurs first). +*/ +void CMMCore::PumpStart(const char* deviceLabel) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->Start(); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Dispenses for the provided duration (in seconds) at the set flowrate +*/ +void CMMCore::PumpDispenseDuration(const char* deviceLabel, double seconds) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->DispenseDuration(seconds); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + +/** +* Dispenses the provided volume (in uL) at the set flowrate +*/ +void CMMCore::PumpDispenseVolume(const char* deviceLabel, double microLiter) throw (CMMError) +{ + std::shared_ptr pPump = + deviceManager_->GetDeviceOfType(deviceLabel); + mm::DeviceModuleLockGuard guard(pPump); + + int ret = pPump->DispenseVolume(microLiter); + + if (ret != DEVICE_OK) + { + logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); + throw CMMError(getDeviceErrorText(ret, pPump)); + } +} + /* SYSTEM STATE */ @@ -7380,7 +7853,6 @@ void CMMCore::updateAllowedChannelGroups() setChannelGroup(""); } - /////////////////////////////////////////////////////////////////////////////// // Automatic device and serial port discovery methods // diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index d06d86013..759fda0be 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -105,6 +105,8 @@ class SLMInstance; class ShutterInstance; class StageInstance; class XYStageInstance; +class PressurePumpInstance; +class VolumetricPumpInstance; class CMMCore; @@ -277,6 +279,8 @@ class CMMCore std::string getImageProcessorDevice(); std::string getSLMDevice(); std::string getGalvoDevice(); + std::string getPressurePumpDevice(); + std::string getVolumetricPumpDevice(); std::string getChannelGroup(); void setCameraDevice(const char* cameraLabel) throw (CMMError); void setShutterDevice(const char* shutterLabel) throw (CMMError); @@ -286,6 +290,8 @@ class CMMCore void setImageProcessorDevice(const char* procLabel) throw (CMMError); void setSLMDevice(const char* slmLabel) throw (CMMError); void setGalvoDevice(const char* galvoLabel) throw (CMMError); + void setPressurePumpDevice(const char* pumpLabel) throw (CMMError); + void setVolumetricPumpDevice(const char* pumpLabel) throw (CMMError); void setChannelGroup(const char* channelGroup) throw (CMMError); ///@} @@ -607,6 +613,39 @@ class CMMCore std::string getGalvoChannel(const char* galvoLabel) throw (CMMError); ///@} + /** \name PressurePump control + * + * Control of pressure pumps + */ + ///@{ + void PressurePumpStop(const char* pumpLabel) throw (CMMError); + void PressurePumpCalibrate(const char* pumpLabel) throw (CMMError); + bool PressurePumpRequiresCalibration(const char* pumpLabel) throw (CMMError); + void setPumpPressure(const char* pumplabel, double pressure) throw (CMMError); + double getPumpPressure(const char* pumplabel) throw (CMMError); + ///@} + + /** \name VolumetricPump control + * + * Control of volumetric pumps + */ + ///@{ + void VolumetricPumpStop(const char* pumpLabel) throw (CMMError); + void VolumetricPumpHome(const char* pumpLabel) throw (CMMError); + bool VolumetricPumpRequiresHoming(const char* pumpLabel) throw (CMMError); + void invertPumpDirection(const char* pumpLabel, bool invert) throw (CMMError); + bool isPumpDirectionInverted(const char* pumpLabel) throw (CMMError); + void setPumpVolume(const char* pumpLabel, double volume) throw (CMMError); + double getPumpVolume(const char* pumpLabel) throw (CMMError); + void setPumpMaxVolume(const char* pumpLabel, double volume) throw (CMMError); + double getPumpMaxVolume(const char* pumpLabel) throw (CMMError); + void setPumpFlowrate(const char* pumpLabel, double volume) throw (CMMError); + double getPumpFlowrate(const char* pumpLabel) throw (CMMError); + void PumpStart(const char* pumpLabel) throw (CMMError); + void PumpDispenseDuration(const char* pumpLabel, double seconds) throw (CMMError); + void PumpDispenseVolume(const char* pumpLabel, double microLiter) throw (CMMError); + ///@} + /** \name Device discovery. */ ///@{ bool supportsDeviceDetection(const char* deviceLabel); @@ -647,6 +686,8 @@ class CMMCore std::weak_ptr currentSLMDevice_; std::weak_ptr currentGalvoDevice_; std::weak_ptr currentImageProcessor_; + std::weak_ptr currentPressurePump_; + std::weak_ptr currentVolumetricPump_; std::string channelGroup_; long pollingIntervalMs_; diff --git a/MMCore/MMCore.vcxproj b/MMCore/MMCore.vcxproj index ebfdcb9ba..845633a91 100644 --- a/MMCore/MMCore.vcxproj +++ b/MMCore/MMCore.vcxproj @@ -88,12 +88,14 @@ + + @@ -131,12 +133,14 @@ + + @@ -181,4 +185,4 @@ - + \ No newline at end of file diff --git a/MMCore/MMCore.vcxproj.filters b/MMCore/MMCore.vcxproj.filters index 1920583b6..50f2a3f7d 100644 --- a/MMCore/MMCore.vcxproj.filters +++ b/MMCore/MMCore.vcxproj.filters @@ -141,6 +141,18 @@ Source Files + + Source Files\Devices + + + Source Files\Devices + + + Source Files\Devices + + + Source Files\Devices + @@ -305,5 +317,11 @@ Header Files + + Header Files\Devices + + + Header Files\Devices + - + \ No newline at end of file diff --git a/MMCore/Makefile.am b/MMCore/Makefile.am index e5d26a97d..b112987a7 100644 --- a/MMCore/Makefile.am +++ b/MMCore/Makefile.am @@ -41,6 +41,8 @@ libMMCore_la_SOURCES = \ Devices/ImageProcessorInstance.h \ Devices/MagnifierInstance.cpp \ Devices/MagnifierInstance.h \ + Devices/PressurePumpInstance.cpp \ + Devices/PressurePumpInstance.h \ Devices/SLMInstance.cpp \ Devices/SLMInstance.h \ Devices/SerialInstance.cpp \ @@ -53,6 +55,8 @@ libMMCore_la_SOURCES = \ Devices/StageInstance.h \ Devices/StateInstance.cpp \ Devices/StateInstance.h \ + Devices/VolumetricPumpInstance.cpp \ + Devices/VolumetricPumpInstance.h \ Devices/XYStageInstance.cpp \ Devices/XYStageInstance.h \ Error.cpp \ diff --git a/MMCore/meson.build b/MMCore/meson.build index 8b04fafb3..a781b3bc2 100644 --- a/MMCore/meson.build +++ b/MMCore/meson.build @@ -51,12 +51,14 @@ mmcore_sources = files( 'Devices/HubInstance.cpp', 'Devices/ImageProcessorInstance.cpp', 'Devices/MagnifierInstance.cpp', + 'Devices/PressurePumpInstance.cpp', 'Devices/SerialInstance.cpp', 'Devices/ShutterInstance.cpp', 'Devices/SignalIOInstance.cpp', 'Devices/SLMInstance.cpp', 'Devices/StageInstance.cpp', 'Devices/StateInstance.cpp', + 'Devices/VolumetricPumpInstance.cpp', 'Devices/XYStageInstance.cpp', 'Error.cpp', 'FrameBuffer.cpp', diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 883b7e34b..aff685a80 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2480,6 +2480,95 @@ class CStateDeviceBase : public CDeviceBase std::map labels_; }; +/** +* Base class for creating pump device adapters. +*/ +template +class CVolumetricPumpBase : public CDeviceBase +{ + int Home() + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int InvertDirection(bool /*state*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int IsDirectionInverted(bool& /*state*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int SetVolumeUl(double /*volume*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int GetVolumeUl(double& /*volume*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int SetMaxVolumeUl(double /*volume*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int GetMaxVolumeUl(double& /*volume*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int SetFlowrateUlPerSecond(double /*flowrate*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int GetFlowrateUlPerSecond(double& /*flowrate*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int Start() + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int DispenseDuration(double /*durSec*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int DispenseVolume(double /*volUl*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } +}; + +/** +* Base class for creating pump device adapters. +*/ +template +class CPressurePumpBase : public CDeviceBase +{ + int Calibrate() + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int SetPressure(double /*pressure*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + int GetPressure(double& /*pressure*/) + { + return DEVICE_UNSUPPORTED_COMMAND; + } +}; + // _t, a macro for timing single lines. // This macros logs the text of the line, x, measures diff --git a/MMDevice/MMDevice-SharedRuntime.vcxproj.filters b/MMDevice/MMDevice-SharedRuntime.vcxproj.filters index 2f38adf00..1f924c37b 100644 --- a/MMDevice/MMDevice-SharedRuntime.vcxproj.filters +++ b/MMDevice/MMDevice-SharedRuntime.vcxproj.filters @@ -62,4 +62,4 @@ Header Files - + \ No newline at end of file diff --git a/MMDevice/MMDevice.cpp b/MMDevice/MMDevice.cpp index 36c82ef97..2b8d8660c 100644 --- a/MMDevice/MMDevice.cpp +++ b/MMDevice/MMDevice.cpp @@ -47,5 +47,7 @@ const DeviceType Magnifier::Type = MagnifierDevice; const DeviceType SLM::Type = SLMDevice; const DeviceType Galvo::Type = GalvoDevice; const DeviceType Hub::Type = HubDevice; +const DeviceType PressurePump::Type = PressurePumpDevice; +const DeviceType VolumetricPump::Type = VolumetricPumpDevice; } // namespace MM diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index cddfebd00..3615802f1 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1306,6 +1306,211 @@ namespace MM { virtual Device* GetInstalledDevice(int devIdx) = 0; }; + /** + * Pressure Pump API + */ + class PressurePump : public Device + { + public: + PressurePump() {} + virtual ~PressurePump() {} + + // MMDevice API + virtual DeviceType GetType() const { return Type; } + static const DeviceType Type; + + /** +* Stops the pump. The implementation should halt any dispensing/withdrawal, +* and make the pump available again (make Busy() return false). +* +* Required by MMPump API +*/ + virtual int Stop() = 0; + + /** + * Calibrates the pressure controller. If no internal calibration is + * supported, just return DEVICE_OK. + * + * Optional function of MMPump API (only required for pressure controllers) + */ + virtual int Calibrate() = 0; + + /** + * Returns whether the pressure controller is functional before calibration, + * or it needs to undergo internal calibration before any commands can be + * executed. + * + * Required by MMPump API. + */ + virtual bool RequiresCalibration() = 0; + + /** + * Sets the pressure of the pressure controller. The provided value will + * be in kPa. The implementation should convert the unit from kPa to the + * desired unit by the device. + * + * Optional function of MMPump API (only required for pressure controllers) + */ + virtual int SetPressure(double pressure) = 0; + + /** + * Gets the pressure of the pressure controller. The returned value + * has to be in kPa. The implementation, therefore, should convert the + * value provided by the pressure controller to kPa. + * + * Optional function of MMPump API (only required for pressure controllers) + */ + virtual int GetPressure(double& pressure) = 0; + }; + + /** + * Volumetric Pump API + */ + class VolumetricPump : public Device + { + public: + VolumetricPump() {} + virtual ~VolumetricPump() {} + + // MMDevice API + virtual DeviceType GetType() const { return Type; } + static const DeviceType Type; + + /** + * Homes the pump. If no homing is supported, just return DEVICE_OK + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int Home() = 0; + + /** + * Stops the pump. The implementation should halt any dispensing/withdrawal, + * and make the pump available again (make Busy() return false). + * + * Required by MMPump API + */ + virtual int Stop() = 0; + + /** + * Flag to check whether the pump requires homing before being operational + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual bool RequiresHoming() = 0; + + /** + * Sets the direction of the pump. Certain pump + * (e.g. peristaltic and DC pumps) don't have an apriori forward-reverse direction, + * as it depends on how it is connected. This function allows you to switch + * forward and reverse. + * + * The implementation of this function should allow two values, 1 and -1, + * and should ignore all other values, where 1 indicates that the direction + * is left as-is, and -1 indicates that the direction should be reversed. If + * the pump is uni-directional, this function does not need to be + * implemented. + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int InvertDirection(bool inverted) = 0; + + /** + * Sets the direction of the pump. Certain pump + * (e.g. peristaltic and DC pumps) don't have an apriori forward-reverse direction, + * as it depends on how it is connected. This function allows you to switch + * forward and reverse. + * + * The implementation of this function should allow two values, [1] and [-1], + * and should ignore all other values, where [1] indicates that the direction + * is left as-is, and [-1] indicates that the direction should be reversed. + * When the pump is uni-directional, the function should always assign [1] to + * [direction] + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int IsDirectionInverted(bool& inverted) = 0; + + /** + * Sets the current volume of the pump in microliters (uL). + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int SetVolumeUl(double volUl) = 0; + + /** + * Gets the current volume of the pump in microliters (uL). + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int GetVolumeUl(double& volUl) = 0; + + /** + * Sets the maximum volume of the pump in microliters (uL). + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int SetMaxVolumeUl(double volUl) = 0; + + /** + * Gets the maximum volume of the pump in microliters (uL). + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int GetMaxVolumeUl(double& volUl) = 0; + + /** + * Sets the flowrate in microliter (uL) per second. The implementation + * should convert the provided flowrate to whichever unit the pump desires + * (steps/s, mL/h, V). + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int SetFlowrateUlPerSecond(double flowrate) = 0; + + /** + * Gets the flowrate in microliter (uL) per second. + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int GetFlowrateUlPerSecond(double& flowrate) = 0; + + /** + * Dispenses/withdraws until the minimum or maximum volume has been + * reached, or the pumping is manually stopped + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int Start() = 0; + + /** + * Dispenses/withdraws for the provided time, with the flowrate provided + * by GetFlowrate_uLperMin + * Dispensing for an undetermined amount of time can be done with DBL_MAX + * During the dispensing/withdrawal, Busy() should return "true". + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int DispenseDuration(double durSec) = 0; + + /** + * Dispenses/withdraws the provided volume. + * + * The implementation should cause positive volumes to be dispensed, whereas + * negative volumes should be withdrawn. The implementation should prevent + * the volume to go negative (i.e. stop the pump once the syringe is empty), + * or to go over the maximum volume (i.e. stop the pump once it is full). + * This automatically allows for dispensing/withdrawal for an undetermined + * amount of time by providing DBL_MAX for dispense, and DBL_MIN for + * withdraw. + * + * During the dispensing/withdrawal, Busy() should return "true". + * + * Optional function of MMPump API (only required for volumetric pumps) + */ + virtual int DispenseVolume(double volUl) = 0; + }; + + /** * Callback API to the core control module. * Devices use this abstract interface to use Core services diff --git a/MMDevice/MMDeviceConstants.h b/MMDevice/MMDeviceConstants.h index 62aa53ce6..bdb2215b9 100644 --- a/MMDevice/MMDeviceConstants.h +++ b/MMDevice/MMDeviceConstants.h @@ -75,6 +75,7 @@ #define DEVICE_SEQUENCE_TOO_LARGE 39 #define DEVICE_OUT_OF_MEMORY 40 #define DEVICE_NOT_YET_IMPLEMENTED 41 +#define DEVICE_PUMP_IS_RUNNING 42 namespace MM { @@ -130,6 +131,8 @@ namespace MM { const char* const g_Keyword_CoreImageProcessor = "ImageProcessor"; const char* const g_Keyword_CoreSLM = "SLM"; const char* const g_Keyword_CoreGalvo = "Galvo"; + const char* const g_Keyword_CorePressurePump = "PressurePump"; + const char* const g_Keyword_CoreVolumetricPump = "VolumetricPump"; const char* const g_Keyword_CoreTimeoutMs = "TimeoutMs"; const char* const g_Keyword_Channel = "Channel"; const char* const g_Keyword_Version = "Version"; @@ -138,9 +141,14 @@ namespace MM { const char* const g_Keyword_Transpose_MirrorX = "TransposeMirrorX"; const char* const g_Keyword_Transpose_MirrorY = "TransposeMirrorY"; const char* const g_Keyword_Transpose_Correction = "TransposeCorrection"; - const char* const g_Keyword_Closed_Position = "ClosedPosition"; - const char* const g_Keyword_HubID = "HubID"; - + const char* const g_Keyword_Closed_Position = "ClosedPosition"; + const char* const g_Keyword_HubID = "HubID"; + const char* const g_Keyword_Current_Volume = "Volume_uL"; + const char* const g_Keyword_Min_Volume = "Min_Volume_uL"; + const char* const g_Keyword_Max_Volume = "Max_Volume_uL"; + const char* const g_Keyword_Flowrate = "Flowrate_uL_per_sec"; + const char* const g_Keyword_Pressure_Imposed = "Pressure Imposed"; + const char* const g_Keyword_Pressure_Measured = "Pressure Measured"; // image annotations const char* const g_Keyword_Metadata_CameraLabel = "Camera"; @@ -201,23 +209,25 @@ namespace MM { // Type constants // enum DeviceType { - UnknownType=0, - AnyType, - CameraDevice, - ShutterDevice, - StateDevice, - StageDevice, - XYStageDevice, - SerialDevice, - GenericDevice, - AutoFocusDevice, - CoreDevice, - ImageProcessorDevice, - SignalIODevice, - MagnifierDevice, - SLMDevice, - HubDevice, - GalvoDevice + UnknownType = 0, + AnyType, + CameraDevice, + ShutterDevice, + StateDevice, + StageDevice, + XYStageDevice, + SerialDevice, + GenericDevice, + AutoFocusDevice, + CoreDevice, + ImageProcessorDevice, + SignalIODevice, + MagnifierDevice, + SLMDevice, + HubDevice, + GalvoDevice, + PressurePumpDevice, + VolumetricPumpDevice }; enum PropertyType { diff --git a/micromanager.sln b/micromanager.sln index d69eacc52..0d6175b14 100644 --- a/micromanager.sln +++ b/micromanager.sln @@ -492,7 +492,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DahengGalaxy", "DeviceAdapt EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PyDevice", "DeviceAdapters\PyDevice\PyDevice.vcxproj", "{36CF524A-8214-404C-8E6B-B5DEC1FDADF9}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HikRobot", "DeviceAdapters\HikRobot\HikRobot.vcxproj", "{38DCD378-83FE-4C42-8916-1C477A35F65F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hikrobot", "DeviceAdapters\HikRobot\HikRobot.vcxproj", "{38DCD378-83FE-4C42-8916-1C477A35F65F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Fluigent", "DeviceAdapters\Fluigent\Fluigent.vcxproj", "{4F22D447-EDC6-4766-A750-A5781276040A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1476,14 +1478,18 @@ Global {DD3A2820-F54C-42F3-AA0E-DC95D57481B7}.Debug|x64.Build.0 = Debug|x64 {DD3A2820-F54C-42F3-AA0E-DC95D57481B7}.Release|x64.ActiveCfg = Release|x64 {DD3A2820-F54C-42F3-AA0E-DC95D57481B7}.Release|x64.Build.0 = Release|x64 - {38DCD378-83FE-4C42-8916-1C477A35F65F}.Debug|x64.ActiveCfg = Debug|x64 - {38DCD378-83FE-4C42-8916-1C477A35F65F}.Debug|x64.Build.0 = Debug|x64 - {38DCD378-83FE-4C42-8916-1C477A35F65F}.Release|x64.ActiveCfg = Release|x64 - {38DCD378-83FE-4C42-8916-1C477A35F65F}.Release|x64.Build.0 = Release|x64 {36CF524A-8214-404C-8E6B-B5DEC1FDADF9}.Debug|x64.ActiveCfg = Debug|x64 {36CF524A-8214-404C-8E6B-B5DEC1FDADF9}.Debug|x64.Build.0 = Debug|x64 {36CF524A-8214-404C-8E6B-B5DEC1FDADF9}.Release|x64.ActiveCfg = Release|x64 {36CF524A-8214-404C-8E6B-B5DEC1FDADF9}.Release|x64.Build.0 = Release|x64 + {38DCD378-83FE-4C42-8916-1C477A35F65F}.Debug|x64.ActiveCfg = Debug|x64 + {38DCD378-83FE-4C42-8916-1C477A35F65F}.Debug|x64.Build.0 = Debug|x64 + {38DCD378-83FE-4C42-8916-1C477A35F65F}.Release|x64.ActiveCfg = Release|x64 + {38DCD378-83FE-4C42-8916-1C477A35F65F}.Release|x64.Build.0 = Release|x64 + {4F22D447-EDC6-4766-A750-A5781276040A}.Debug|x64.ActiveCfg = Debug|x64 + {4F22D447-EDC6-4766-A750-A5781276040A}.Debug|x64.Build.0 = Debug|x64 + {4F22D447-EDC6-4766-A750-A5781276040A}.Release|x64.ActiveCfg = Release|x64 + {4F22D447-EDC6-4766-A750-A5781276040A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 53110f6f3e8fe0a4062332f46ae71a985ad7c959 Mon Sep 17 00:00:00 2001 From: Lars Kool Date: Fri, 23 Aug 2024 10:55:02 +0200 Subject: [PATCH 2/3] Squashed commits and fixed bug with setPumpPressure --- MMCore/MMCore.cpp | 49 ++++++----------------------------- MMCore/MMCore.h | 2 +- MMCore/MMCore.vcxproj.filters | 6 ----- 3 files changed, 9 insertions(+), 48 deletions(-) diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index 623f53546..09168bc26 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6278,39 +6278,6 @@ void CMMCore::setPressurePumpDevice(const char* deviceLabel) throw (CMMError) } } -/** - * Sets the current pump device. - * @param pump the shutter device label - */ -void CMMCore::setPressurePumpDevice(const char* deviceLabel) throw (CMMError) -{ - if (!deviceLabel || strlen(deviceLabel) > 0) // Allow empty label - CheckDeviceLabel(deviceLabel); - - // Nothing to do if this is the current shutter device: - if (getPressurePumpDevice().compare(deviceLabel) == 0) - return; - - if (strlen(deviceLabel) > 0) - { - currentPressurePump_ = - deviceManager_->GetDeviceOfType(deviceLabel); - - LOG_INFO(coreLogger_) << "Default shutter set to " << deviceLabel; - } - else - { - currentPressurePump_.reset(); - LOG_INFO(coreLogger_) << "Default pump unset"; - } - properties_->Refresh(); // TODO: more efficient - std::string newPumpLabel = getPressurePumpDevice(); - { - MMThreadGuard scg(stateCacheLock_); - stateCache_.addSetting(PropertySetting(MM::g_Keyword_CoreDevice, MM::g_Keyword_CorePressurePump, newPumpLabel.c_str())); - } -} - /** * Stops the pressure pump */ @@ -6360,41 +6327,41 @@ bool CMMCore::PressurePumpRequiresCalibration(const char* deviceLabel) throw (CM } /** -* Sets the pressure of the pump in kPa +* Gets the pressure of the pump in kPa */ -void CMMCore::setPumpPressure(const char* deviceLabel, double pressurekPa) throw (CMMError) +double CMMCore::getPumpPressure(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); mm::DeviceModuleLockGuard guard(pPump); - int ret = pPump->setPressure(pressurekPa); + double pressurekPa = 0; + int ret = pPump->getPressure(pressurekPa); if (ret != DEVICE_OK) { logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); throw CMMError(getDeviceErrorText(ret, pPump)); } + return pressurekPa; } /** -* Gets the pressure of the pump in kPa +* Sets the pressure of the pump in kPa */ -double CMMCore::getPumpPressure(const char* deviceLabel) throw (CMMError) +void CMMCore::setPumpPressure(const char* deviceLabel, double pressurekPa) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); mm::DeviceModuleLockGuard guard(pPump); - double pressurekPa = 0; - int ret = pPump->getPressure(pressurekPa); + int ret = pPump->setPressure(pressurekPa); if (ret != DEVICE_OK) { logError(deviceLabel, getDeviceErrorText(ret, pPump).c_str()); throw CMMError(getDeviceErrorText(ret, pPump)); } - return pressurekPa; } /////////////////////////////////////////////////////////////////////////////// diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index 759fda0be..4f3070f6c 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -685,9 +685,9 @@ class CMMCore std::weak_ptr currentAutofocusDevice_; std::weak_ptr currentSLMDevice_; std::weak_ptr currentGalvoDevice_; - std::weak_ptr currentImageProcessor_; std::weak_ptr currentPressurePump_; std::weak_ptr currentVolumetricPump_; + std::weak_ptr currentImageProcessor_; std::string channelGroup_; long pollingIntervalMs_; diff --git a/MMCore/MMCore.vcxproj.filters b/MMCore/MMCore.vcxproj.filters index 50f2a3f7d..2e6fb9bea 100644 --- a/MMCore/MMCore.vcxproj.filters +++ b/MMCore/MMCore.vcxproj.filters @@ -147,12 +147,6 @@ Source Files\Devices - - Source Files\Devices - - - Source Files\Devices - From 95a18a06fe030782bfea7ccc142b960b08bd8e7f Mon Sep 17 00:00:00 2001 From: Lars Kool Date: Wed, 9 Oct 2024 09:30:03 +0200 Subject: [PATCH 3/3] Removed currentPumpDevices, added units to pump method names, removed spurious change of micromanager.sln --- MMCore/MMCore.cpp | 117 +++++----------------------------------------- MMCore/MMCore.h | 28 +++++------ micromanager.sln | 6 --- 3 files changed, 22 insertions(+), 129 deletions(-) diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index 09168bc26..0d47abdf2 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -3229,32 +3229,6 @@ std::string CMMCore::getAutoFocusDevice() return std::string(); } -/** - * Returns the label of the currently selected pressure pump. - */ -std::string CMMCore::getPressurePumpDevice() -{ - std::shared_ptr pump = currentPressurePump_.lock(); - if (pump) - { - return pump->GetLabel(); - } - return std::string(); -} - -/** - * Returns the label of the currently selected volumetric pump. - */ -std::string CMMCore::getVolumetricPumpDevice() -{ - std::shared_ptr pump = currentVolumetricPump_.lock(); - if (pump) - { - return pump->GetLabel(); - } - return std::string(); -} - /** * Sets the current auto-focus device. */ @@ -6245,43 +6219,11 @@ std::string CMMCore::getGalvoChannel(const char* deviceLabel) throw (CMMError) // Pressure Pump methods /////////////////////////////////////////////////////////////////////////////// -/** - * Sets the current pump device. - * @param pump the shutter device label - */ -void CMMCore::setPressurePumpDevice(const char* deviceLabel) throw (CMMError) -{ - if (!deviceLabel || strlen(deviceLabel) > 0) // Allow empty label - CheckDeviceLabel(deviceLabel); - - // Nothing to do if this is the current shutter device: - if (getPressurePumpDevice().compare(deviceLabel) == 0) - return; - - if (strlen(deviceLabel) > 0) - { - currentPressurePump_ = - deviceManager_->GetDeviceOfType(deviceLabel); - - LOG_INFO(coreLogger_) << "Default shutter set to " << deviceLabel; - } - else - { - currentPressurePump_.reset(); - LOG_INFO(coreLogger_) << "Default pump unset"; - } - properties_->Refresh(); // TODO: more efficient - std::string newPumpLabel = getPressurePumpDevice(); - { - MMThreadGuard scg(stateCacheLock_); - stateCache_.addSetting(PropertySetting(MM::g_Keyword_CoreDevice, MM::g_Keyword_CorePressurePump, newPumpLabel.c_str())); - } -} /** * Stops the pressure pump */ -void CMMCore::PressurePumpStop(const char* deviceLabel) throw (CMMError) +void CMMCore::pressurePumpStop(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6299,7 +6241,7 @@ void CMMCore::PressurePumpStop(const char* deviceLabel) throw (CMMError) /** * Calibrates the pump */ -void CMMCore::PressurePumpCalibrate(const char* deviceLabel) throw (CMMError) +void CMMCore::pressurePumpCalibrate(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6317,7 +6259,7 @@ void CMMCore::PressurePumpCalibrate(const char* deviceLabel) throw (CMMError) /** * Returns boolean whether the pump is operational before calibration */ -bool CMMCore::PressurePumpRequiresCalibration(const char* deviceLabel) throw (CMMError) +bool CMMCore::pressurePumpRequiresCalibration(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6329,7 +6271,7 @@ bool CMMCore::PressurePumpRequiresCalibration(const char* deviceLabel) throw (CM /** * Gets the pressure of the pump in kPa */ -double CMMCore::getPumpPressure(const char* deviceLabel) throw (CMMError) +double CMMCore::getPumpPressureKPa(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6349,7 +6291,7 @@ double CMMCore::getPumpPressure(const char* deviceLabel) throw (CMMError) /** * Sets the pressure of the pump in kPa */ -void CMMCore::setPumpPressure(const char* deviceLabel, double pressurekPa) throw (CMMError) +void CMMCore::setPumpPressureKPa(const char* deviceLabel, double pressurekPa) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6364,47 +6306,10 @@ void CMMCore::setPumpPressure(const char* deviceLabel, double pressurekPa) throw } } -/////////////////////////////////////////////////////////////////////////////// -// Volumetric Pump methods -/////////////////////////////////////////////////////////////////////////////// - -/** - * Sets the current pump device. - * @param pump the shutter device label - */ -void CMMCore::setVolumetricPumpDevice(const char* deviceLabel) throw (CMMError) -{ - if (!deviceLabel || strlen(deviceLabel) > 0) // Allow empty label - CheckDeviceLabel(deviceLabel); - - // Nothing to do if this is the current shutter device: - if (getVolumetricPumpDevice().compare(deviceLabel) == 0) - return; - - if (strlen(deviceLabel) > 0) - { - currentVolumetricPump_ = - deviceManager_->GetDeviceOfType(deviceLabel); - - LOG_INFO(coreLogger_) << "Default shutter set to " << deviceLabel; - } - else - { - currentVolumetricPump_.reset(); - LOG_INFO(coreLogger_) << "Default pump unset"; - } - properties_->Refresh(); // TODO: more efficient - std::string newPumpLabel = getVolumetricPumpDevice(); - { - MMThreadGuard scg(stateCacheLock_); - stateCache_.addSetting(PropertySetting(MM::g_Keyword_CoreDevice, MM::g_Keyword_CoreVolumetricPump, newPumpLabel.c_str())); - } -} - /** * Stops the volumetric pump */ -void CMMCore::VolumetricPumpStop(const char* deviceLabel) throw (CMMError) +void CMMCore::volumetricPumpStop(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6422,7 +6327,7 @@ void CMMCore::VolumetricPumpStop(const char* deviceLabel) throw (CMMError) /** * Homes the pump */ -void CMMCore::VolumetricPumpHome(const char* deviceLabel) throw (CMMError) +void CMMCore::volumetricPumpHome(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6437,7 +6342,7 @@ void CMMCore::VolumetricPumpHome(const char* deviceLabel) throw (CMMError) } } -bool CMMCore::VolumetricPumpRequiresHoming(const char* deviceLabel) throw (CMMError) +bool CMMCore::volumetricPumpRequiresHoming(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6603,7 +6508,7 @@ double CMMCore::getPumpFlowrate(const char* deviceLabel) throw (CMMError) * Start dispensing at the set flowrate until syringe is empty, or manually * stopped (whichever occurs first). */ -void CMMCore::PumpStart(const char* deviceLabel) throw (CMMError) +void CMMCore::pumpStart(const char* deviceLabel) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6621,7 +6526,7 @@ void CMMCore::PumpStart(const char* deviceLabel) throw (CMMError) /** * Dispenses for the provided duration (in seconds) at the set flowrate */ -void CMMCore::PumpDispenseDuration(const char* deviceLabel, double seconds) throw (CMMError) +void CMMCore::pumpDispenseDurationSeconds(const char* deviceLabel, double seconds) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); @@ -6639,7 +6544,7 @@ void CMMCore::PumpDispenseDuration(const char* deviceLabel, double seconds) thro /** * Dispenses the provided volume (in uL) at the set flowrate */ -void CMMCore::PumpDispenseVolume(const char* deviceLabel, double microLiter) throw (CMMError) +void CMMCore::pumpDispenseVolumeUl(const char* deviceLabel, double microLiter) throw (CMMError) { std::shared_ptr pPump = deviceManager_->GetDeviceOfType(deviceLabel); diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index 4f3070f6c..b9c408841 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -279,8 +279,6 @@ class CMMCore std::string getImageProcessorDevice(); std::string getSLMDevice(); std::string getGalvoDevice(); - std::string getPressurePumpDevice(); - std::string getVolumetricPumpDevice(); std::string getChannelGroup(); void setCameraDevice(const char* cameraLabel) throw (CMMError); void setShutterDevice(const char* shutterLabel) throw (CMMError); @@ -290,8 +288,6 @@ class CMMCore void setImageProcessorDevice(const char* procLabel) throw (CMMError); void setSLMDevice(const char* slmLabel) throw (CMMError); void setGalvoDevice(const char* galvoLabel) throw (CMMError); - void setPressurePumpDevice(const char* pumpLabel) throw (CMMError); - void setVolumetricPumpDevice(const char* pumpLabel) throw (CMMError); void setChannelGroup(const char* channelGroup) throw (CMMError); ///@} @@ -618,11 +614,11 @@ class CMMCore * Control of pressure pumps */ ///@{ - void PressurePumpStop(const char* pumpLabel) throw (CMMError); - void PressurePumpCalibrate(const char* pumpLabel) throw (CMMError); - bool PressurePumpRequiresCalibration(const char* pumpLabel) throw (CMMError); - void setPumpPressure(const char* pumplabel, double pressure) throw (CMMError); - double getPumpPressure(const char* pumplabel) throw (CMMError); + void pressurePumpStop(const char* pumpLabel) throw (CMMError); + void pressurePumpCalibrate(const char* pumpLabel) throw (CMMError); + bool pressurePumpRequiresCalibration(const char* pumpLabel) throw (CMMError); + void setPumpPressureKPa(const char* pumplabel, double pressure) throw (CMMError); + double getPumpPressureKPa(const char* pumplabel) throw (CMMError); ///@} /** \name VolumetricPump control @@ -630,9 +626,9 @@ class CMMCore * Control of volumetric pumps */ ///@{ - void VolumetricPumpStop(const char* pumpLabel) throw (CMMError); - void VolumetricPumpHome(const char* pumpLabel) throw (CMMError); - bool VolumetricPumpRequiresHoming(const char* pumpLabel) throw (CMMError); + void volumetricPumpStop(const char* pumpLabel) throw (CMMError); + void volumetricPumpHome(const char* pumpLabel) throw (CMMError); + bool volumetricPumpRequiresHoming(const char* pumpLabel) throw (CMMError); void invertPumpDirection(const char* pumpLabel, bool invert) throw (CMMError); bool isPumpDirectionInverted(const char* pumpLabel) throw (CMMError); void setPumpVolume(const char* pumpLabel, double volume) throw (CMMError); @@ -641,9 +637,9 @@ class CMMCore double getPumpMaxVolume(const char* pumpLabel) throw (CMMError); void setPumpFlowrate(const char* pumpLabel, double volume) throw (CMMError); double getPumpFlowrate(const char* pumpLabel) throw (CMMError); - void PumpStart(const char* pumpLabel) throw (CMMError); - void PumpDispenseDuration(const char* pumpLabel, double seconds) throw (CMMError); - void PumpDispenseVolume(const char* pumpLabel, double microLiter) throw (CMMError); + void pumpStart(const char* pumpLabel) throw (CMMError); + void pumpDispenseDurationSeconds(const char* pumpLabel, double seconds) throw (CMMError); + void pumpDispenseVolumeUl(const char* pumpLabel, double microLiter) throw (CMMError); ///@} /** \name Device discovery. */ @@ -685,8 +681,6 @@ class CMMCore std::weak_ptr currentAutofocusDevice_; std::weak_ptr currentSLMDevice_; std::weak_ptr currentGalvoDevice_; - std::weak_ptr currentPressurePump_; - std::weak_ptr currentVolumetricPump_; std::weak_ptr currentImageProcessor_; std::string channelGroup_; diff --git a/micromanager.sln b/micromanager.sln index 0d6175b14..c1dbad354 100644 --- a/micromanager.sln +++ b/micromanager.sln @@ -494,8 +494,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PyDevice", "DeviceAdapters\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hikrobot", "DeviceAdapters\HikRobot\HikRobot.vcxproj", "{38DCD378-83FE-4C42-8916-1C477A35F65F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Fluigent", "DeviceAdapters\Fluigent\Fluigent.vcxproj", "{4F22D447-EDC6-4766-A750-A5781276040A}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -1486,10 +1484,6 @@ Global {38DCD378-83FE-4C42-8916-1C477A35F65F}.Debug|x64.Build.0 = Debug|x64 {38DCD378-83FE-4C42-8916-1C477A35F65F}.Release|x64.ActiveCfg = Release|x64 {38DCD378-83FE-4C42-8916-1C477A35F65F}.Release|x64.Build.0 = Release|x64 - {4F22D447-EDC6-4766-A750-A5781276040A}.Debug|x64.ActiveCfg = Debug|x64 - {4F22D447-EDC6-4766-A750-A5781276040A}.Debug|x64.Build.0 = Debug|x64 - {4F22D447-EDC6-4766-A750-A5781276040A}.Release|x64.ActiveCfg = Release|x64 - {4F22D447-EDC6-4766-A750-A5781276040A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE