From 0d30f1f0df83f7ae4c6f9f20c8c8a57a938af333 Mon Sep 17 00:00:00 2001 From: Lars Kool Date: Mon, 24 Jun 2024 10:07:29 +0200 Subject: [PATCH] Added PressurePump and VolumetricPump to MM --- MMCore/CoreUtils.h | 2 + MMCore/Devices/DeviceInstances.h | 2 + MMCore/Devices/PressurePumpInstance.cpp | 30 ++ MMCore/Devices/PressurePumpInstance.h | 47 +++ MMCore/Devices/VolumetricPumpInstance.cpp | 39 +++ MMCore/Devices/VolumetricPumpInstance.h | 56 ++++ MMCore/MMCore.cpp | 348 +++++++++++++++++++++- MMCore/MMCore.h | 35 +++ MMCore/MMCore.vcxproj | 6 +- MMCore/MMCore.vcxproj.filters | 14 +- MMCore/Makefile.am | 4 + MMDevice/MMDevice.cpp | 2 + MMDevice/MMDevice.h | 205 +++++++++++++ MMDevice/MMDeviceConstants.h | 43 +-- 14 files changed, 813 insertions(+), 20 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..716ded85c --- /dev/null +++ b/MMCore/Devices/PressurePumpInstance.h @@ -0,0 +1,47 @@ +// 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 + +#pragma once +#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..85c978759 --- /dev/null +++ b/MMCore/Devices/VolumetricPumpInstance.h @@ -0,0 +1,56 @@ +// 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 + +#pragma once + +#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/MMCore.cpp b/MMCore/MMCore.cpp index 4bef95471..ebf90822c 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6214,6 +6214,353 @@ std::string CMMCore::getGalvoChannel(const char* deviceLabel) throw (CMMError) return pGalvo->GetChannel(); } +/////////////////////////////////////////////////////////////////////////////// +// Pressure Pump methods +/////////////////////////////////////////////////////////////////////////////// + +/** +* 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 +/////////////////////////////////////////////////////////////////////////////// + +/** +* 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 +7727,6 @@ void CMMCore::updateAllowedChannelGroups() setChannelGroup(""); } - /////////////////////////////////////////////////////////////////////////////// // Automatic device and serial port discovery methods // diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index d06d86013..bb0ee5978 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; @@ -607,6 +609,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); 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..4f2fdc544 100644 --- a/MMCore/MMCore.vcxproj.filters +++ b/MMCore/MMCore.vcxproj.filters @@ -141,6 +141,12 @@ Source Files + + Source Files\Devices + + + Source Files\Devices + @@ -305,5 +311,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/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..bffe7203b 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_RUNNING 42 namespace MM { @@ -140,6 +141,12 @@ namespace MM { 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_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 @@ -201,23 +208,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 {