diff --git a/DeviceAdapters/OpenFlexure/OpenFlexure.cpp b/DeviceAdapters/OpenFlexure/OpenFlexure.cpp index 47936de44..ab36480df 100644 --- a/DeviceAdapters/OpenFlexure/OpenFlexure.cpp +++ b/DeviceAdapters/OpenFlexure/OpenFlexure.cpp @@ -4,11 +4,9 @@ // SUBSYSTEM: DeviceAdapters //----------------------------------------------------------------------------- // DESCRIPTION: Adapter for the OpenFlexure Microscope. This adapter is used on the v5 Sangaboard. +// - Tested with Sangaboard Firmware v1.0.1-dev || Sangaboard v0.5.x // -// AUTHOR: Samdrea Hsu, samdreahsu@gmail.com, 06/22/2024 -// -// Karl Hoover (stuff such as programmable CCD size & the various image processors) -// Arther Edelstein ( equipment error simulation) +// AUTHOR: Samdrea Hsu, samdreahsu@gmail.com, 09/23/2024 // // COPYRIGHT: Samdrea Hsu // diff --git a/DeviceAdapters/OpenFlexure/OpenFlexure.h b/DeviceAdapters/OpenFlexure/OpenFlexure.h index 69090db46..c72e8bd81 100644 --- a/DeviceAdapters/OpenFlexure/OpenFlexure.h +++ b/DeviceAdapters/OpenFlexure/OpenFlexure.h @@ -4,11 +4,9 @@ // SUBSYSTEM: DeviceAdapters //----------------------------------------------------------------------------- // DESCRIPTION: Adapter for the OpenFlexure Microscope. This adapter is used on the v5 Sangaboard. +// - Tested with Sangaboard Firmware v1.0.1-dev || Sangaboard v0.5.x // -// AUTHOR: Samdrea Hsu, samdreahsu@gmail.com, 06/22/2024 -// -// Karl Hoover (stuff such as programmable CCD size & the various image processors) -// Arther Edelstein ( equipment error simulation) +// AUTHOR: Samdrea Hsu, samdreahsu@gmail.com, 09/23/2024 // // COPYRIGHT: Samdrea Hsu // 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..0d47abdf2 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. @@ -6214,6 +6215,350 @@ 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(); +} + +/** +* Gets the pressure of the pump in kPa +*/ +double CMMCore::getPumpPressureKPa(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; +} + +/** +* Sets the pressure of the pump in kPa +*/ +void CMMCore::setPumpPressureKPa(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)); + } +} + +/** +* 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::pumpDispenseDurationSeconds(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::pumpDispenseVolumeUl(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 +7725,6 @@ void CMMCore::updateAllowedChannelGroups() setChannelGroup(""); } - /////////////////////////////////////////////////////////////////////////////// // Automatic device and serial port discovery methods // diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index d06d86013..b9c408841 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 setPumpPressureKPa(const char* pumplabel, double pressure) throw (CMMError); + double getPumpPressureKPa(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 pumpDispenseDurationSeconds(const char* pumpLabel, double seconds) throw (CMMError); + void pumpDispenseVolumeUl(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..2e6fb9bea 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/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 84cef7177..752b76c74 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 {