diff --git a/DeviceAdapters/MCL_MicroDrive/MicroDriveZStage.cpp b/DeviceAdapters/MCL_MicroDrive/MicroDriveZStage.cpp index 893109d66..85434d76e 100644 --- a/DeviceAdapters/MCL_MicroDrive/MicroDriveZStage.cpp +++ b/DeviceAdapters/MCL_MicroDrive/MicroDriveZStage.cpp @@ -370,7 +370,7 @@ int MCL_MicroDrive_ZStage::OnPositionMm(MM::PropertyBase* pProp, MM::ActionType err = GetPositionMm(z); if(err != MCL_SUCCESS) return err; - err = BeginMovementThread(STANDARD_MOVE_TYPE, z); + err = BeginMovementThread(STANDARD_MOVE_TYPE, pos); if (err != DEVICE_OK) return err; } diff --git a/DeviceAdapters/NIDAQ/NIDigitalOutputPort.cpp b/DeviceAdapters/NIDAQ/NIDigitalOutputPort.cpp index 06f52de3c..4f8e74379 100644 --- a/DeviceAdapters/NIDAQ/NIDigitalOutputPort.cpp +++ b/DeviceAdapters/NIDAQ/NIDigitalOutputPort.cpp @@ -98,6 +98,22 @@ int DigitalOutputPort::Initialize() supportsBlankingAndSequencing_ = true; GetHub()->StopDOBlankingAndSequence(portWidth_); + // Some cards lie about their portwidth, if blanking does not work, try 32 bits + // Workaround for possible DAQmx bug on USB-6341; see + // https://forums.ni.com/t5/Multifunction-DAQ/problem-with-correlated-DIO-on-USB-6341/td-p/3344066 + if (!supportsBlankingAndSequencing_) + { + uInt32 oldPortWidth = portWidth_; + portWidth_ = 32; + if (GetHub()->StartDOBlankingAndOrSequence(tmpNiPort, portWidth_, true, false, 0, false, tmpTriggerTerminal) == DEVICE_OK) + supportsBlankingAndSequencing_ = true; + GetHub()->StopDOBlankingAndSequence(portWidth_); + if (!supportsBlankingAndSequencing_) + { + portWidth_ = oldPortWidth; + } + } + CPropertyAction* pAct; if (supportsBlankingAndSequencing_) { diff --git a/DeviceAdapters/Zaber/ConnectionManager.cpp b/DeviceAdapters/Zaber/ConnectionManager.cpp index b99add048..df9824fc6 100644 --- a/DeviceAdapters/Zaber/ConnectionManager.cpp +++ b/DeviceAdapters/Zaber/ConnectionManager.cpp @@ -1,7 +1,10 @@ #include "ConnectionManager.h" +#include +#include + std::shared_ptr ConnectionManager::getConnection(std::string port) -{ +{ std::lock_guard lockGuard(lock_); if (connections_.count(port) > 0) { if (auto connectionPtr = connections_.at(port).lock()) { @@ -9,9 +12,32 @@ std::shared_ptr ConnectionManager::getConnection(std::string po } } - auto connection = std::make_shared(zml::Connection::openSerialPort(port)); + std::shared_ptr connection; + if (port.find("share://") == 0) { + // share://:/ + std::regex parser("^share:\\/\\/([^:\\/]+)(:\\d+)?(\\/.*)?$", std::regex_constants::ECMAScript); + std::smatch partMatch; + if (!std::regex_match(port, partMatch, parser)) { + throw zmlbase::InvalidArgumentException("Invalid network share connection string: " + port); + } + + std::string host = partMatch[1].str(); + int sharePort = 11421; + std::string connectionName; + if (partMatch[2].matched) { + sharePort = std::stoi(partMatch[2].str().substr(1)); + } + if (partMatch[3].matched) { + connectionName = partMatch[3].str().substr(1); + } + + connection = std::make_shared(zml::Connection::openNetworkShare(host, sharePort, connectionName)); + } else { + connection = std::make_shared(zml::Connection::openSerialPort(port)); + } + auto id = connection->getInterfaceId(); - connection->getDisconnected().subscribe([=](std::shared_ptr) { + connection->getDisconnected().subscribe([=, this](std::shared_ptr) { removeConnection(port, id); }); connections_[port] = connection; @@ -22,18 +48,19 @@ std::shared_ptr ConnectionManager::getConnection(std::string po bool ConnectionManager::removeConnection(std::string port, int interfaceId) { std::lock_guard lockGuard(lock_); - if (connections_.count(port) == 0) { + auto it = connections_.find(port); + if (it == connections_.end()) { return false; - } + } if (interfaceId != -1) { - if (auto connection = connections_.at(port).lock()) { + if (auto connection = it->second.lock()) { if (connection->getInterfaceId() != interfaceId) { return false; } } } - connections_.erase(port); + connections_.erase(it); return true; -} \ No newline at end of file +} diff --git a/DeviceAdapters/Zaber/FilterCubeTurret.cpp b/DeviceAdapters/Zaber/FilterCubeTurret.cpp index 3044c6fc8..4fb837c8f 100644 --- a/DeviceAdapters/Zaber/FilterCubeTurret.cpp +++ b/DeviceAdapters/Zaber/FilterCubeTurret.cpp @@ -222,9 +222,7 @@ int FilterCubeTurret::PortGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) { if (initialized_) { - // revert - pProp->Set(port_.c_str()); - return ERR_PORT_CHANGE_FORBIDDEN; + resetConnection(); } pProp->Get(port_); diff --git a/DeviceAdapters/Zaber/FilterCubeTurret.h b/DeviceAdapters/Zaber/FilterCubeTurret.h index 07988a00e..8cdaf53fb 100644 --- a/DeviceAdapters/Zaber/FilterCubeTurret.h +++ b/DeviceAdapters/Zaber/FilterCubeTurret.h @@ -38,21 +38,21 @@ class FilterCubeTurret : public CStateDeviceBase, public Zaber // Device API // ---------- - int Initialize(); - int Shutdown(); - void GetName(char* name) const; - bool Busy(); + int Initialize() override; + int Shutdown() override; + void GetName(char* name) const override; + bool Busy() override; // Stage API // --------- - unsigned long GetNumberOfPositions() const + unsigned long GetNumberOfPositions() const override { return numPositions_; } // Base class overrides // ---------------- - virtual int GetPositionLabel(long pos, char* label) const; + int GetPositionLabel(long pos, char* label) const override; // Properties // ---------------- diff --git a/DeviceAdapters/Zaber/FilterWheel.cpp b/DeviceAdapters/Zaber/FilterWheel.cpp index 2466cdf0a..4fbcccfbb 100644 --- a/DeviceAdapters/Zaber/FilterWheel.cpp +++ b/DeviceAdapters/Zaber/FilterWheel.cpp @@ -217,9 +217,7 @@ int FilterWheel::PortGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) { if (initialized_) { - // revert - pProp->Set(port_.c_str()); - return ERR_PORT_CHANGE_FORBIDDEN; + resetConnection(); } pProp->Get(port_); diff --git a/DeviceAdapters/Zaber/FilterWheel.h b/DeviceAdapters/Zaber/FilterWheel.h index 31e2cd2bc..3f2587ec5 100644 --- a/DeviceAdapters/Zaber/FilterWheel.h +++ b/DeviceAdapters/Zaber/FilterWheel.h @@ -37,21 +37,21 @@ class FilterWheel : public CStateDeviceBase, public ZaberBase // Device API // ---------- - int Initialize(); - int Shutdown(); - void GetName(char* name) const; - bool Busy(); + int Initialize() override; + int Shutdown() override; + void GetName(char* name) const override; + bool Busy() override; // Stage API // --------- - unsigned long GetNumberOfPositions() const + unsigned long GetNumberOfPositions() const override { return numPositions_; } // Base class overrides // ---------------- - virtual int GetPositionLabel(long pos, char* label) const; + int GetPositionLabel(long pos, char* label) const override; // Properties // ---------------- diff --git a/DeviceAdapters/Zaber/Illuminator.cpp b/DeviceAdapters/Zaber/Illuminator.cpp index cbf4fbce2..1a340072a 100644 --- a/DeviceAdapters/Zaber/Illuminator.cpp +++ b/DeviceAdapters/Zaber/Illuminator.cpp @@ -373,9 +373,7 @@ int Illuminator::PortGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) { if (initialized_) { - // revert - pProp->Set(port_.c_str()); - return ERR_PORT_CHANGE_FORBIDDEN; + resetConnection(); } pProp->Get(port_); diff --git a/DeviceAdapters/Zaber/Illuminator.h b/DeviceAdapters/Zaber/Illuminator.h index a95d198c2..5ff54e64e 100644 --- a/DeviceAdapters/Zaber/Illuminator.h +++ b/DeviceAdapters/Zaber/Illuminator.h @@ -37,15 +37,15 @@ class Illuminator : public CShutterBase, public ZaberBase // Device API // ---------- - int Initialize(); - int Shutdown(); + int Initialize() override; + int Shutdown() override; - void GetName(char* pszName) const; - bool Busy(); + void GetName(char* pszName) const override; + bool Busy() override; - int SetOpen(bool open = true); - int GetOpen(bool& open); - int Fire(double deltaT); + int SetOpen(bool open = true) override; + int GetOpen(bool& open) override; + int Fire(double deltaT) override; // Properties // ---------------- @@ -66,7 +66,7 @@ class Illuminator : public CShutterBase, public ZaberBase bool *lampExists_; // Enables the optimization of using the device-scope lamp on command. - bool canUseDeviceLampOnCommand_; + bool canUseDeviceLampOnCommand_; // Enables the optimization of only turning on individual axes that // have nonzero flux when the shutter opens. @@ -76,9 +76,9 @@ class Illuminator : public CShutterBase, public ZaberBase double* maxFlux_; // These variables exist only to enable good UX in the absence of - // a device-scope lamp on command. The specific behavior these are + // a device-scope lamp on command. The specific behavior these are // for is when you are tuning presets, you leave the shutter open - // and adjust intensities. If you change a zero intensity to + // and adjust intensities. If you change a zero intensity to // nonzero, it must turn that axis on, only if the shutter is open. bool *lampIsOn_; bool isOpen_; diff --git a/DeviceAdapters/Zaber/Makefile.am b/DeviceAdapters/Zaber/Makefile.am index 4941c2be6..7a5d659ee 100644 --- a/DeviceAdapters/Zaber/Makefile.am +++ b/DeviceAdapters/Zaber/Makefile.am @@ -2,6 +2,8 @@ AM_CXXFLAGS = $(MMDEVAPI_CXXFLAGS) $(ZML_CPPFLAGS) deviceadapter_LTLIBRARIES = libmmgr_dal_Zaber.la libmmgr_dal_Zaber_la_SOURCES = \ + WdiAutofocus.cpp \ + WdiAutofocus.h \ ObjectiveChanger.cpp \ ObjectiveChanger.h \ Illuminator.cpp \ diff --git a/DeviceAdapters/Zaber/ObjectiveChanger.cpp b/DeviceAdapters/Zaber/ObjectiveChanger.cpp index 92e13cb82..ea5a59438 100644 --- a/DeviceAdapters/Zaber/ObjectiveChanger.cpp +++ b/DeviceAdapters/Zaber/ObjectiveChanger.cpp @@ -93,7 +93,7 @@ int ObjectiveChanger::Initialize() this->LogMessage("ObjectiveChanger::Initialize\n", true); - auto ret = handleException([=]() { + auto ret = handleException([&]() { ensureConnected(); if (!this->changer_.getFocusAxis().isHomed()) { this->changer_.change(1); @@ -232,9 +232,7 @@ int ObjectiveChanger::PortGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) { if (initialized_) { - // revert - pProp->Set(port_.c_str()); - return ERR_PORT_CHANGE_FORBIDDEN; + resetConnection(); } pProp->Get(port_); @@ -350,7 +348,7 @@ int ObjectiveChanger::FocusOffsetGetSet(MM::PropertyBase* pProp, MM::ActionType } int ObjectiveChanger::setObjective(long objective, bool applyOffset) { - return handleException([=]() { + return handleException([&]() { ensureConnected(); zmlbase::Measurement offset; if (applyOffset) { diff --git a/DeviceAdapters/Zaber/ObjectiveChanger.h b/DeviceAdapters/Zaber/ObjectiveChanger.h index 05c8b15f8..cce17d40e 100644 --- a/DeviceAdapters/Zaber/ObjectiveChanger.h +++ b/DeviceAdapters/Zaber/ObjectiveChanger.h @@ -38,25 +38,25 @@ class ObjectiveChanger : public CStateDeviceBase, public Zaber // Device API // ---------- - int Initialize(); - int Shutdown(); - void GetName(char* name) const; - bool Busy(); + int Initialize() override; + int Shutdown() override; + void GetName(char* name) const override; + bool Busy() override; // Stage API // --------- - unsigned long GetNumberOfPositions() const + unsigned long GetNumberOfPositions() const override { return numPositions_; } // Base class overrides // ---------------- - virtual int GetPositionLabel(long pos, char* label) const; + int GetPositionLabel(long pos, char* label) const override; // ZaverBase class overrides // ---------------- - virtual void onNewConnection(); + void onNewConnection() override; // Properties // ---------------- @@ -66,9 +66,9 @@ class ObjectiveChanger : public CStateDeviceBase, public Zaber int XLdaAddressGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); int PositionGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); int FocusOffsetGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); - - int setObjective(long objective, bool applyOffset); private: + int setObjective(long objective, bool applyOffset); + long xMorAddress_; long xLdaAddress_; long numPositions_; diff --git a/DeviceAdapters/Zaber/Stage.cpp b/DeviceAdapters/Zaber/Stage.cpp index 8dfe20b97..158b9c2c3 100644 --- a/DeviceAdapters/Zaber/Stage.cpp +++ b/DeviceAdapters/Zaber/Stage.cpp @@ -294,9 +294,7 @@ int Stage::OnPort (MM::PropertyBase* pProp, MM::ActionType eAct) { if (initialized_) { - // revert - pProp->Set(port_.c_str()); - return ERR_PORT_CHANGE_FORBIDDEN; + resetConnection(); } pProp->Get(port_); diff --git a/DeviceAdapters/Zaber/Stage.h b/DeviceAdapters/Zaber/Stage.h index ca9b7f06c..6f9be2722 100644 --- a/DeviceAdapters/Zaber/Stage.h +++ b/DeviceAdapters/Zaber/Stage.h @@ -36,28 +36,28 @@ class Stage : public CStageBase, public ZaberBase // Device API // ---------- - int Initialize(); - int Shutdown(); - void GetName(char* name) const; - bool Busy(); + int Initialize() override; + int Shutdown() override; + void GetName(char* name) const override; + bool Busy() override; // Stage API // --------- - int GetPositionUm(double& pos); - int GetPositionSteps(long& steps); - int SetPositionUm(double pos); - int SetRelativePositionUm(double d); - int SetPositionSteps(long steps); - int SetRelativePositionSteps(long steps); - int Move(double velocity); - int Stop(); - int Home(); - int SetAdapterOriginUm(double d); - int SetOrigin(); - int GetLimits(double& lower, double& upper); + int GetPositionUm(double& pos) override; + int GetPositionSteps(long& steps) override; + int SetPositionUm(double pos) override; + int SetRelativePositionUm(double d) override; + int SetPositionSteps(long steps) override; + int SetRelativePositionSteps(long steps); // not in the base class + int Move(double velocity) override; + int Stop() override; + int Home() override; + int SetAdapterOriginUm(double d) override; + int SetOrigin() override; + int GetLimits(double& lower, double& upper) override; - int IsStageSequenceable(bool& isSequenceable) const {isSequenceable = false; return DEVICE_OK;} - bool IsContinuousFocusDrive() const {return false;} + int IsStageSequenceable(bool& isSequenceable) const override { isSequenceable = false; return DEVICE_OK; } + bool IsContinuousFocusDrive() const override { return false; } // action interface // ---------------- diff --git a/DeviceAdapters/Zaber/WdiAutofocus.cpp b/DeviceAdapters/Zaber/WdiAutofocus.cpp new file mode 100644 index 000000000..50fde9275 --- /dev/null +++ b/DeviceAdapters/Zaber/WdiAutofocus.cpp @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: WdiAutofocus.cpp +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Device adapter for WDI autofocus. +// +// AUTHOR: Martin Zak (contact@zaber.com) + +// COPYRIGHT: Zaber Technologies, 2024 + +// LICENSE: This file is distributed under the BSD 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. + +#ifdef WIN32 +#pragma warning(disable: 4355) +#endif + +#include "WdiAutofocus.h" + +const char* g_WdiAutofocusName = "WdiAutofocus"; +const char* g_WdiAutofocusDescription = "Zaber WDI Autofocus device adapter"; +const char* g_Msg_AF_MOVEMENT_FAILED = "The movement has failed. Ensure that the autofocus is in range and the focus axis is within the limits."; + +using namespace std; + +WdiAutofocus::WdiAutofocus() : + ZaberBase(this), + focusAddress_(1), + focusAxis_(1), + limitMin_(0.0), + limitMax_(0.0) +{ + this->LogMessage("WdiAutofocus::WdiAutofocus\n", true); + + InitializeDefaultErrorMessages(); + ZaberBase::setErrorMessages([&](auto code, auto message) { this->SetErrorText(code, message); }); + this->SetErrorText(ERR_MOVEMENT_FAILED, g_Msg_AF_MOVEMENT_FAILED); + + CreateProperty(MM::g_Keyword_Name, g_WdiAutofocusName, MM::String, true); + CreateProperty(MM::g_Keyword_Description, g_WdiAutofocusDescription, MM::String, true); + + CPropertyAction* pAct = new CPropertyAction(this, &WdiAutofocus::PortGetSet); + CreateProperty("Zaber Serial Port", port_.c_str(), MM::String, false, pAct, true); + + pAct = new CPropertyAction(this, &WdiAutofocus::FocusAddressGetSet); + CreateIntegerProperty("Focus Stage Device Number", focusAddress_, false, pAct, true); + SetPropertyLimits("Focus Stage Device Number", 1, 99); + + pAct = new CPropertyAction(this, &WdiAutofocus::FocusAxisGetSet); + CreateIntegerProperty("Focus Stage Axis Number", focusAxis_, false, pAct, true); + SetPropertyLimits("Focus Stage Axis Number", 1, 99); +} + +WdiAutofocus::~WdiAutofocus() +{ + this->LogMessage("WdiAutofocus::~WdiAutofocus\n", true); + Shutdown(); +} + +void WdiAutofocus::GetName(char* name) const +{ + CDeviceUtils::CopyLimitedString(name, g_WdiAutofocusDescription); +} + +int WdiAutofocus::Initialize() +{ + if (initialized_) + { + return DEVICE_OK; + } + + core_ = GetCoreCallback(); + + this->LogMessage("WdiAutofocus::Initialize\n", true); + + auto pAct = new CPropertyAction(this, &WdiAutofocus::LimitMinGetSet); + CreateFloatProperty("Limit Min [mm]", limitMin_, false, pAct); + pAct = new CPropertyAction(this, &WdiAutofocus::LimitMaxGetSet); + CreateFloatProperty("Limit Max [mm]", limitMax_, false, pAct); + + auto ret = UpdateStatus(); + if (ret == DEVICE_OK) + { + initialized_ = true; + } + + return ret; +} + +int WdiAutofocus::Shutdown() +{ + this->LogMessage("WdiAutofocus::Shutdown\n", true); + + if (initialized_) + { + initialized_ = false; + } + + return DEVICE_OK; +} + +bool WdiAutofocus::Busy() +{ + this->LogMessage("WdiAutofocus::Busy\n", true); + + bool busy = false; + auto ret = handleException([&]() { + ensureConnected(); + busy = axis_.isBusy(); + }); + return ret == DEVICE_OK && busy; +} + +int WdiAutofocus::PortGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream os; + os << "WdiAutofocus::PortGetSet(" << pProp << ", " << eAct << ")\n"; + this->LogMessage(os.str().c_str(), false); + + if (eAct == MM::BeforeGet) + { + pProp->Set(port_.c_str()); + } + else if (eAct == MM::AfterSet) + { + if (initialized_) + { + resetConnection(); + } + + pProp->Get(port_); + } + + return DEVICE_OK; +} + +int WdiAutofocus::FocusAddressGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + this->LogMessage("WdiAutofocus::FocusAddressGetSet\n", true); + + if (eAct == MM::AfterSet) + { + if (initialized_) + { + resetConnection(); + } + + pProp->Get(focusAddress_); + } + else if (eAct == MM::BeforeGet) + { + pProp->Set(focusAddress_); + } + + return DEVICE_OK; +} + +int WdiAutofocus::FocusAxisGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + this->LogMessage("WdiAutofocus::FocusAxisGetSet\n", true); + + if (eAct == MM::AfterSet) + { + if (initialized_) + { + resetConnection(); + } + + pProp->Get(focusAxis_); + } + else if (eAct == MM::BeforeGet) + { + pProp->Set(focusAxis_); + } + + return DEVICE_OK; +} + +int WdiAutofocus::LimitMinGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + this->LogMessage("ObjectiveChanger::LimitMinGetSet\n", true); + return LimitGetSet(pProp, eAct, limitMin_, "motion.tracking.limit.min"); +} + +int WdiAutofocus::LimitMaxGetSet(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + this->LogMessage("ObjectiveChanger::LimitMaxGetSet\n", true); + return LimitGetSet(pProp, eAct, limitMax_, "motion.tracking.limit.max"); +} + +int WdiAutofocus::LimitGetSet(MM::PropertyBase* pProp, MM::ActionType eAct, double& limit, const char* setting) +{ + if (eAct == MM::AfterSet) + { + double newLimit; + pProp->Get(newLimit); + bool update = limit != newLimit; + limit = newLimit; + + if (update) { + return handleException([&]() { + ensureConnected(); + axis_.getSettings().set(setting, limit * WdiAutofocus_::xLdaNativePerMm); + }); + } + } + else if (eAct == MM::BeforeGet) + { + if (initialized_) + { + int ret = handleException([&]() { + ensureConnected(); + limit = axis_.getSettings().get(setting) / WdiAutofocus_::xLdaNativePerMm; + }); + if (ret != DEVICE_OK) + { + return ret; + } + } + + pProp->Set(limit); + } + + return DEVICE_OK; +} + +int WdiAutofocus::FullFocus() { + this->LogMessage("WdiAutofocus::FullFocus\n", true); + + return handleException([&]() { + ensureConnected(); + + axis_.genericCommand("move track once"); + axis_.waitUntilIdle(); + }); +} + +int WdiAutofocus::IncrementalFocus() { + this->LogMessage("WdiAutofocus::IncrementalFocus\n", true); + + return FullFocus(); +} + +int WdiAutofocus::GetLastFocusScore(double& score) { + this->LogMessage("WdiAutofocus::GetLastFocusScore\n", true); + + return GetCurrentFocusScore(score); +} + +int WdiAutofocus::GetCurrentFocusScore(double& score) { + this->LogMessage("WdiAutofocus::GetCurrentFocusScore\n", true); + + score = 0.0; + return handleException([&]() { + ensureConnected(); + + auto reply = axis_.getDevice().genericCommand("io get ai 1"); + score = stod(reply.getData()); + }); +} + +int WdiAutofocus::GetOffset(double& offset) { + this->LogMessage("WdiAutofocus::GetOffset\n", true); + offset = 0.0; + return DEVICE_OK; +} +int WdiAutofocus::SetOffset(double offset) { + this->LogMessage("WdiAutofocus::SetOffset\n", true); + if (offset != 0.0) { + return DEVICE_UNSUPPORTED_COMMAND; + } + return DEVICE_OK; +} + +int WdiAutofocus::SetContinuousFocusing(bool state) { + this->LogMessage("WdiAutofocus::SetContinuousFocusing\n", true); + + return handleException([&]() { + ensureConnected(); + + if (state) { + axis_.genericCommand("move track"); + } else { + axis_.stop(); + } + }); +} + +int WdiAutofocus::GetContinuousFocusing(bool& state) { + this->LogMessage("WdiAutofocus::GetContinuousFocusing\n", true); + return handleException([&]() { + ensureConnected(); + state = axis_.isBusy(); + }); +} + +bool WdiAutofocus::IsContinuousFocusLocked() { + this->LogMessage("WdiAutofocus::IsContinuousFocusLocked\n", true); + + bool locked; + auto ret = handleException([&]() { + ensureConnected(); + locked = axis_.getSettings().get("motion.tracking.settle.tolerance.met") > 0; + }); + return ret == DEVICE_OK && locked; +} + +void WdiAutofocus::onNewConnection() { + ZaberBase::onNewConnection(); + axis_ = connection_->getDevice(focusAddress_).getAxis(focusAxis_); +} diff --git a/DeviceAdapters/Zaber/WdiAutofocus.h b/DeviceAdapters/Zaber/WdiAutofocus.h new file mode 100644 index 000000000..3e32ac9ca --- /dev/null +++ b/DeviceAdapters/Zaber/WdiAutofocus.h @@ -0,0 +1,78 @@ +#pragma once +/////////////////////////////////////////////////////////////////////////////// +// FILE: WdiAutofocus.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Device adapter for WDI autofocus. +// +// AUTHOR: Martin Zak (contact@zaber.com) + +// COPYRIGHT: Zaber Technologies, 2024 + +// LICENSE: This file is distributed under the BSD 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. + +#include "Zaber.h" + +extern const char* g_WdiAutofocusName; +extern const char* g_WdiAutofocusDescription; + +namespace WdiAutofocus_ { + const double xLdaNativePerMm = 1000000.0; +} + +class WdiAutofocus : public CAutoFocusBase, public ZaberBase +{ +public: + WdiAutofocus(); + ~WdiAutofocus(); + + // Device API + // ---------- + int Initialize() override; + int Shutdown() override; + void GetName(char* name) const override; + bool Busy() override; + + // AutoFocus API + // ---------- + bool IsContinuousFocusLocked() override; + int FullFocus() override; + int IncrementalFocus() override; + int GetLastFocusScore(double& score) override; + int GetCurrentFocusScore(double& score) override; + int GetOffset(double& offset) override; + int SetOffset(double offset) override; + int SetContinuousFocusing(bool state) override; + int GetContinuousFocusing(bool& state) override; + + // ZaberBase class overrides + // ---------------- + void onNewConnection() override; + + // Properties + // ---------------- + int PortGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); + int FocusAddressGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); + int FocusAxisGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); + int LimitMinGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); + int LimitMaxGetSet(MM::PropertyBase* pProp, MM::ActionType eAct); + int LimitGetSet(MM::PropertyBase* pProp, MM::ActionType eAct, double& limit, const char* setting); + +private: + long focusAddress_; + long focusAxis_; + zml::Axis axis_; + + double limitMin_; + double limitMax_; +}; diff --git a/DeviceAdapters/Zaber/XYStage.cpp b/DeviceAdapters/Zaber/XYStage.cpp index b16a2ffe9..117e7f211 100644 --- a/DeviceAdapters/Zaber/XYStage.cpp +++ b/DeviceAdapters/Zaber/XYStage.cpp @@ -607,9 +607,7 @@ int XYStage::OnPort(MM::PropertyBase* pProp, MM::ActionType eAct) { if (initialized_) { - // revert - pProp->Set(port_.c_str()); - return ERR_PORT_CHANGE_FORBIDDEN; + resetConnection(); } pProp->Get(port_); } diff --git a/DeviceAdapters/Zaber/XYStage.h b/DeviceAdapters/Zaber/XYStage.h index b4048b958..6c6000833 100644 --- a/DeviceAdapters/Zaber/XYStage.h +++ b/DeviceAdapters/Zaber/XYStage.h @@ -4,9 +4,9 @@ // SUBSYSTEM: DeviceAdapters //----------------------------------------------------------------------------- // DESCRIPTION: XYStage Device Adapter -// +// // AUTHOR: David Goosen & Athabasca Witschi (contact@zaber.com) -// +// // COPYRIGHT: Zaber Technologies Inc., 2017 // // LICENSE: This file is distributed under the BSD license. @@ -36,27 +36,26 @@ class XYStage : public CXYStageBase, public ZaberBase // Device API // ---------- - int Initialize(); - int Shutdown(); - void GetName(char* name) const; - bool Busy(); + int Initialize() override; + int Shutdown() override; + void GetName(char* name) const override; + bool Busy() override; // XYStage API // ----------- - int GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax); - int Move(double vx, double vy); - int SetPositionSteps(long x, long y); - int GetPositionSteps(long& x, long& y); - int SetRelativePositionSteps(long x, long y); - int Home(); - int Stop(); - int SetOrigin(); - int SetAdapterOrigin(); - int GetStepLimits(long& xMin, long& xMax, long& yMin, long& yMax); - double GetStepSizeXUm() {return stepSizeXUm_;} - double GetStepSizeYUm() {return stepSizeYUm_;} + int GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax) override; + int Move(double vx, double vy) override; + int SetPositionSteps(long x, long y) override; + int GetPositionSteps(long& x, long& y) override; + int SetRelativePositionSteps(long x, long y) override; + int Home() override; + int Stop() override; + int SetOrigin() override; + int GetStepLimits(long& xMin, long& xMax, long& yMin, long& yMax) override; + double GetStepSizeXUm() override { return stepSizeXUm_; } + double GetStepSizeYUm() override { return stepSizeYUm_; } - int IsXYStageSequenceable(bool& isSequenceable) const {isSequenceable = false; return DEVICE_OK;} + int IsXYStageSequenceable(bool& isSequenceable) const override { isSequenceable = false; return DEVICE_OK; } // action interface // ---------------- diff --git a/DeviceAdapters/Zaber/Zaber.cpp b/DeviceAdapters/Zaber/Zaber.cpp index b242ffb1e..4cf5183ce 100644 --- a/DeviceAdapters/Zaber/Zaber.cpp +++ b/DeviceAdapters/Zaber/Zaber.cpp @@ -32,6 +32,7 @@ #include "FilterCubeTurret.h" #include "Illuminator.h" #include "ObjectiveChanger.h" +#include "WdiAutofocus.h" #include @@ -48,6 +49,7 @@ const char* g_Msg_LAMP_OVERHEATED = "Some of the illuminator lamps are overheate const char* g_Msg_PERIPHERAL_DISCONNECTED = "A peripheral has been disconnected; please reconnect it or set its peripheral ID to zero and then restart the driver."; const char* g_Msg_PERIPHERAL_UNSUPPORTED = "Controller firmware does not support one of the connected peripherals; please update the firmware."; const char* g_Msg_FIRMWARE_UNSUPPORTED = "Firmware is not suported; please update the firmware."; +const char* g_Msg_ERR_INVALID_OPERATION = "Operation cannot be performed at this time."; ////////////////////////////////////////////////////////////////////////////////// @@ -61,6 +63,7 @@ MODULE_API void InitializeModuleData() RegisterDevice(g_FilterTurretName, MM::StateDevice, g_FilterTurretDescription); RegisterDevice(g_IlluminatorName, MM::ShutterDevice, g_IlluminatorDescription); RegisterDevice(g_ObjectiveChangerName, MM::StateDevice, g_ObjectiveChangerDescription); + RegisterDevice(g_WdiAutofocusName, MM::AutoFocusDevice, g_WdiAutofocusDescription); } @@ -90,6 +93,10 @@ MODULE_API MM::Device* CreateDevice(const char* deviceName) { return new ObjectiveChanger(); } + else if (strcmp(deviceName, g_WdiAutofocusName) == 0) + { + return new WdiAutofocus(); + } else { return 0; @@ -153,7 +160,7 @@ void ZaberBase::resetConnection() { // the connection destructor can throw in the rarest occasions connection_ = nullptr; } - catch (const zmlbase::MotionLibException e) + catch (const zmlbase::MotionLibException e) { } } @@ -228,13 +235,13 @@ int ZaberBase::SetSetting(long device, long axis, string setting, double data, i } -bool ZaberBase::IsBusy(long device) +bool ZaberBase::IsBusy(long device, long axis) { core_->LogMessage(device_, "ZaberBase::IsBusy\n", true); zml::Response resp; - int ret = Command(device, 0, "", resp); + int ret = Command(device, axis, "", resp); if (ret != DEVICE_OK) { ostringstream os; @@ -453,6 +460,10 @@ int ZaberBase::handleException(std::function wrapped) { core_->LogMessage(device_, e.what(), true); return ERR_MOVEMENT_FAILED; } + catch (const zmlbase::InvalidOperationException e) { + core_->LogMessage(device_, e.what(), true); + return ERR_INVALID_OPERATION; + } catch (const zmlbase::MotionLibException e) { core_->LogMessage(device_, e.what(), true); return DEVICE_ERR; @@ -472,4 +483,5 @@ void ZaberBase::setErrorMessages(std::function setter) { setter(ERR_LAMP_DISCONNECTED, g_Msg_LAMP_DISCONNECTED); setter(ERR_LAMP_OVERHEATED, g_Msg_LAMP_OVERHEATED); setter(ERR_FIRMWARE_UNSUPPORTED, g_Msg_FIRMWARE_UNSUPPORTED); + setter(ERR_INVALID_OPERATION, g_Msg_ERR_INVALID_OPERATION); } diff --git a/DeviceAdapters/Zaber/Zaber.h b/DeviceAdapters/Zaber/Zaber.h index 1fba41aa8..d1c5e59d4 100644 --- a/DeviceAdapters/Zaber/Zaber.h +++ b/DeviceAdapters/Zaber/Zaber.h @@ -44,6 +44,7 @@ namespace zmlmi = zaber::motion::microscopy; #define ERR_PORT_CHANGE_FORBIDDEN 10002 #define ERR_DRIVER_DISABLED 10004 +#define ERR_INVALID_OPERATION 10008 #define ERR_MOVEMENT_FAILED 10016 #define ERR_COMMAND_REJECTED 10032 #define ERR_NO_REFERENCE_POS 10064 @@ -70,7 +71,7 @@ class ZaberBase template int GetSetting(long device, long axis, std::string setting, TReturn& data); int GetSettings(long device, long axis, std::string setting, std::vector& data); int SetSetting(long device, long axis, std::string setting, double data, int decimalPlaces = -1); - bool IsBusy(long device); + bool IsBusy(long device, long axis = 0); int Stop(long device, long lockstepGroup = 0); int GetLimits(long device, long axis, long& min, long& max); int SendMoveCommand(long device, long axis, std::string type, long data, bool lockstep = false); diff --git a/DeviceAdapters/Zaber/Zaber.vcxproj b/DeviceAdapters/Zaber/Zaber.vcxproj index a25dd995a..b485aec5c 100644 --- a/DeviceAdapters/Zaber/Zaber.vcxproj +++ b/DeviceAdapters/Zaber/Zaber.vcxproj @@ -59,13 +59,13 @@ true true WIN32;_USRDLL;_WINDOWS;%(PreprocessorDefinitions) - $(MM_3RDPARTYPUBLIC)\Zaber\zaber-motion\include;%(AdditionalIncludeDirectories) + $(MM_3RDPARTYPUBLIC)\Zaber\zaber-motion-3.4.4\include;%(AdditionalIncludeDirectories) true true zml.lib;%(AdditionalDependencies) - $(MM_3RDPARTYPUBLIC)\Zaber\zaber-motion\win64\lib;%(AdditionalLibraryDirectories) + $(MM_3RDPARTYPUBLIC)\Zaber\zaber-motion-3.4.4\win64\lib;%(AdditionalLibraryDirectories) @@ -75,6 +75,7 @@ + @@ -85,6 +86,7 @@ + diff --git a/DeviceAdapters/Zaber/Zaber.vcxproj.filters b/DeviceAdapters/Zaber/Zaber.vcxproj.filters index 192f91275..884105b05 100644 --- a/DeviceAdapters/Zaber/Zaber.vcxproj.filters +++ b/DeviceAdapters/Zaber/Zaber.vcxproj.filters @@ -39,6 +39,9 @@ Source Files + + Source Files + @@ -65,5 +68,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/DeviceAdapters/configure.ac b/DeviceAdapters/configure.ac index 5e898c7e4..af0e239db 100644 --- a/DeviceAdapters/configure.ac +++ b/DeviceAdapters/configure.ac @@ -431,24 +431,26 @@ AS_IF([test "x$want_vimba_x" != xno], AM_CONDITIONAL([BUILD_ALLIED_VISION_CAMERA], [test "x$use_vimba_x" = xyes]) # Zaber Motion Library (hack: only support 3rdpartypublic copy currently) +zml_version="3.4.4" +zml_so_version="3.4" AC_MSG_CHECKING([for Zaber Motion Library in 3rdpartypublic]) -zml_header_to_check="${thirdpartypublic}/Zaber/zaber-motion/include/zaber/motion/library.h" +zml_header_to_check="${thirdpartypublic}/Zaber/zaber-motion-${zml_version}/include/zaber/motion/library.h" AM_CONDITIONAL([BUILD_ZABER], [test -f $zml_header_to_check]) if test -f "$zml_header_to_check"; then AC_MSG_RESULT([found]) - ZML_CPPFLAGS="-I${thirdpartypublic}/Zaber/zaber-motion/include" + ZML_CPPFLAGS="-I${thirdpartypublic}/Zaber/zaber-motion-${zml_version}/include" ZML_LIBS="-lzml" case $host in *linux*) # Linux builds by users should install ZML libs - zml_linux_libdir="${thirdpartypublic}/Zaber/zaber-motion/linux-amd64/lib" + zml_linux_libdir="${thirdpartypublic}/Zaber/zaber-motion-${zml_version}/linux-amd64/lib" ZML_LDFLAGS="-L${zml_linux_libdir} -Wl,-rpath,"'\$$ORIGIN' - ZML_LIBS_TO_COPY="${zml_linux_libdir}/libzml.so.3.4 ${zml_linux_libdir}/libzaber-motion-lib-linux-amd64.so.3.4.3" + ZML_LIBS_TO_COPY="${zml_linux_libdir}/libzml.so.${zml_so_version} ${zml_linux_libdir}/libzaber-motion-lib-linux-amd64.so.${zml_version}" ;; *apple-darwin*) # macOS build for packaging does not ship ZML - ZML_LDFLAGS="-L${thirdpartypublic}/Zaber/zaber-motion/darwin/lib" + ZML_LDFLAGS="-L${thirdpartypublic}/Zaber/zaber-motion-${zml_version}/darwin/lib" ZML_LIBS_TO_COPY="" ;; esac diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 883b7e34b..84cef7177 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -1562,7 +1562,7 @@ class CCameraBase : public CDeviceBase virtual long GetNumberOfImages() {return thd_->GetNumberOfImages();} // called from the thread function before exit - virtual void OnThreadExiting() throw() + virtual void OnThreadExiting() { try { @@ -1668,7 +1668,7 @@ class CCameraBase : public CDeviceBase void UpdateActualDuration() {actualDuration_ = camera_->GetCurrentMMTime() - startTime_;} private: - virtual int svc(void) throw() + virtual int svc() { int ret=DEVICE_ERR; try diff --git a/MMDevice/ImageMetadata.h b/MMDevice/ImageMetadata.h index 98f5c8a64..212d7b084 100644 --- a/MMDevice/ImageMetadata.h +++ b/MMDevice/ImageMetadata.h @@ -22,17 +22,6 @@ #pragma once -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4290) // 'C++ exception specification ignored' -#endif - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -// 'dynamic exception specifications are deprecated in C++11 [-Wdeprecated]' -#pragma GCC diagnostic ignored "-Wdeprecated" -#endif - #include "MMDeviceConstants.h" #include @@ -42,6 +31,12 @@ #include #include +#ifdef SWIG +#define MMDEVICE_LEGACY_THROW(ex) throw (ex) +#else +#define MMDEVICE_LEGACY_THROW(ex) +#endif + /////////////////////////////////////////////////////////////////////////////// // MetadataError // ------------- @@ -326,14 +321,14 @@ class Metadata return false; } - MetadataSingleTag GetSingleTag(const char* key) const throw (MetadataKeyError) + MetadataSingleTag GetSingleTag(const char* key) const MMDEVICE_LEGACY_THROW(MetadataKeyError) { MetadataTag* tag = FindTag(key); const MetadataSingleTag* stag = tag->ToSingleTag(); return *stag; } - MetadataArrayTag GetArrayTag(const char* key) const throw (MetadataKeyError) + MetadataArrayTag GetArrayTag(const char* key) const MMDEVICE_LEGACY_THROW(MetadataKeyError) { MetadataTag* tag = FindTag(key); const MetadataArrayTag* atag = tag->ToArrayTag(); @@ -499,11 +494,3 @@ class Metadata typedef std::map::iterator TagIter; typedef std::map::const_iterator TagConstIter; }; - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#ifdef _MSC_VER -#pragma warning(pop) -#endif