diff --git a/DeviceAdapters/ASITiger/ASIZStage.cpp b/DeviceAdapters/ASITiger/ASIZStage.cpp index ad09aa0afb..c89917fa95 100644 --- a/DeviceAdapters/ASITiger/ASIZStage.cpp +++ b/DeviceAdapters/ASITiger/ASIZStage.cpp @@ -46,7 +46,11 @@ CZStage::CZStage(const char* name) : unitMult_(g_StageDefaultUnitMult), // later will try to read actual setting stepSizeUm_(g_StageMinStepSize), // we'll use 1 nm as our smallest possible step size, this is somewhat arbitrary and doesn't change during the program axisLetter_(g_EmptyAxisLetterStr), // value determined by extended name - advancedPropsEnabled_(false) + advancedPropsEnabled_(false), + ring_buffer_supported_(false), + ring_buffer_capacity_(0), + ttl_trigger_supported_(false), + ttl_trigger_enabled_(false) { if (IsExtendedName(name)) // only set up these properties if we have the required information in the name { @@ -243,6 +247,102 @@ int CZStage::Initialize() AddAllowedValue(g_AxisPolarity, g_FocusPolarityMicroManagerDefault); UpdateProperty(g_AxisPolarity); + // get build info so we can add optional properties + build_info_type build; + RETURN_ON_MM_ERROR( hub_->GetBuildInfo(addressChar_, build) ); + + // add single-axis properties if supported + // (single-axis support existed prior pre-2.8 firmware, but now we have easier way to tell if it's present using axis properties + // and it wasn't used very much before SPIM) + if(build.vAxesProps[0] & BIT5)// if(hub_->IsDefinePresent(build, g_Define_SINGLEAXIS_FUNCTION)) + { + // copied from ASIMMirror.cpp + pAct = new CPropertyAction (this, &CZStage::OnSAAmplitude); + CreateProperty(g_SAAmplitudePropertyName, "0", MM::Float, false, pAct); + UpdateProperty(g_SAAmplitudePropertyName); + pAct = new CPropertyAction (this, &CZStage::OnSAOffset); + CreateProperty(g_SAOffsetPropertyName, "0", MM::Float, false, pAct); + UpdateProperty(g_SAOffsetPropertyName); + pAct = new CPropertyAction (this, &CZStage::OnSAPeriod); + CreateProperty(g_SAPeriodPropertyName, "0", MM::Integer, false, pAct); + UpdateProperty(g_SAPeriodPropertyName); + pAct = new CPropertyAction (this, &CZStage::OnSAMode); + CreateProperty(g_SAModePropertyName, g_SAMode_0, MM::String, false, pAct); + AddAllowedValue(g_SAModePropertyName, g_SAMode_0); + AddAllowedValue(g_SAModePropertyName, g_SAMode_1); + AddAllowedValue(g_SAModePropertyName, g_SAMode_2); + AddAllowedValue(g_SAModePropertyName, g_SAMode_3); + UpdateProperty(g_SAModePropertyName); + pAct = new CPropertyAction (this, &CZStage::OnSAPattern); + CreateProperty(g_SAPatternPropertyName, g_SAPattern_0, MM::String, false, pAct); + AddAllowedValue(g_SAPatternPropertyName, g_SAPattern_0); + AddAllowedValue(g_SAPatternPropertyName, g_SAPattern_1); + AddAllowedValue(g_SAPatternPropertyName, g_SAPattern_2); + UpdateProperty(g_SAPatternPropertyName); + // generates a set of additional advanced properties that are rarely used + pAct = new CPropertyAction (this, &CZStage::OnSAAdvanced); + CreateProperty(g_AdvancedSAPropertiesPropertyName, g_NoState, MM::String, false, pAct); + AddAllowedValue(g_AdvancedSAPropertiesPropertyName, g_NoState); + AddAllowedValue(g_AdvancedSAPropertiesPropertyName, g_YesState); + UpdateProperty(g_AdvancedSAPropertiesPropertyName); + } + + // add ring buffer properties if supported (starting version 2.81) + if (FirmwareVersionAtLeast(2.81) && (build.vAxesProps[0] & BIT1)) + { + // get the number of ring buffer positions from the BU X output + string rb_define = hub_->GetDefineString(build, "RING BUFFER"); + + ring_buffer_capacity_ = 0; + if (rb_define.size() > 12) + { + ring_buffer_capacity_ = atol(rb_define.substr(11).c_str()); + } + + if (ring_buffer_capacity_ != 0) + { + ring_buffer_supported_ = true; + + pAct = new CPropertyAction (this, &CZStage::OnRBMode); + CreateProperty(g_RB_ModePropertyName, g_RB_OnePoint_1, MM::String, false, pAct); + AddAllowedValue(g_RB_ModePropertyName, g_RB_OnePoint_1); + AddAllowedValue(g_RB_ModePropertyName, g_RB_PlayOnce_2); + AddAllowedValue(g_RB_ModePropertyName, g_RB_PlayRepeat_3); + UpdateProperty(g_RB_ModePropertyName); + + pAct = new CPropertyAction (this, &CZStage::OnRBDelayBetweenPoints); + CreateProperty(g_RB_DelayPropertyName, "0", MM::Integer, false, pAct); + UpdateProperty(g_RB_DelayPropertyName); + + // "do it" property to do TTL trigger via serial + pAct = new CPropertyAction (this, &CZStage::OnRBTrigger); + CreateProperty(g_RB_TriggerPropertyName, g_IdleState, MM::String, false, pAct); + AddAllowedValue(g_RB_TriggerPropertyName, g_IdleState, 0); + AddAllowedValue(g_RB_TriggerPropertyName, g_DoItState, 1); + AddAllowedValue(g_RB_TriggerPropertyName, g_DoneState, 2); + UpdateProperty(g_RB_TriggerPropertyName); + + pAct = new CPropertyAction (this, &CZStage::OnRBRunning); + CreateProperty(g_RB_AutoplayRunningPropertyName, g_NoState, MM::String, false, pAct); + AddAllowedValue(g_RB_AutoplayRunningPropertyName, g_NoState); + AddAllowedValue(g_RB_AutoplayRunningPropertyName, g_YesState); + UpdateProperty(g_RB_AutoplayRunningPropertyName); + + pAct = new CPropertyAction (this, &CZStage::OnUseSequence); + CreateProperty(g_UseSequencePropertyName, g_NoState, MM::String, false, pAct); + AddAllowedValue(g_UseSequencePropertyName, g_NoState); + AddAllowedValue(g_UseSequencePropertyName, g_YesState); + ttl_trigger_enabled_ = false; + } + + } + + if (FirmwareVersionAtLeast(3.09) && (hub_->IsDefinePresent(build, "IN0_INT")) + && ring_buffer_supported_) + { + ttl_trigger_supported_ = true; + } + initialized_ = true; return DEVICE_OK; } @@ -357,6 +457,80 @@ int CZStage::SetOrigin() return hub_->QueryCommandVerify(command.str(),":A"); } +int CZStage::StopStageSequence() +// disables TTL triggering; doesn't actually stop anything already happening on controller +{ + ostringstream command; command.str(""); + if (!ttl_trigger_supported_) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + command << addressChar_ << "TTL X=0"; // switch off TTL triggering + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(),":A") ); + return DEVICE_OK; +} + +int CZStage::StartStageSequence() +// enables TTL triggering; doesn't actually start anything going on controller +{ + ostringstream command; command.str(""); + if (!ttl_trigger_supported_) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + // ensure that ringbuffer pointer points to first entry and + // that we only trigger the first axis (assume only 1 axis on piezo card) + command << addressChar_ << "RM Y=1 Z=0"; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(),":A") ); + + command.str(""); + command << addressChar_ << "TTL X=1"; // switch on TTL triggering + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(),":A") ); + return DEVICE_OK; +} + +int CZStage::SendStageSequence() +{ + ostringstream command; command.str(""); + if (!ttl_trigger_supported_) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + command << addressChar_ << "RM X=0"; // clear ring buffer + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(),":A") ); + for (unsigned i=0; i< sequence_.size(); i++) // send new points + { + command.str(""); + command << "LD " << axisLetter_ << "=" << sequence_[i]*unitMult_; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(),":A") ); + } + + return DEVICE_OK; +} + +int CZStage::ClearStageSequence() +{ + ostringstream command; command.str(""); + if (!ttl_trigger_supported_) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + sequence_.clear(); + command << addressChar_ << "RM X=0"; // clear ring buffer + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(),":A") ); + return DEVICE_OK; +} + +int CZStage::AddToStageSequence(double position) +{ + if (!ttl_trigger_supported_) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + sequence_.push_back(position); + return DEVICE_OK; +} + //////////////// // action handlers @@ -1166,4 +1340,582 @@ int CZStage::OnAxisPolarity(MM::PropertyBase* pProp, MM::ActionType eAct) return DEVICE_OK; } +int CZStage::OnSAAdvanced(MM::PropertyBase* pProp, MM::ActionType eAct) +// special property, when set to "yes" it creates a set of little-used properties that can be manipulated thereafter +{ + if (eAct == MM::BeforeGet) + { + return DEVICE_OK; // do nothing + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_YesState) == 0) + { + CPropertyAction* pAct; + + pAct = new CPropertyAction (this, &CZStage::OnSAClkSrc); + CreateProperty(g_SAClkSrcPropertyName, g_SAClkSrc_0, MM::String, false, pAct); + AddAllowedValue(g_SAClkSrcPropertyName, g_SAClkSrc_0); + AddAllowedValue(g_SAClkSrcPropertyName, g_SAClkSrc_1); + UpdateProperty(g_SAClkSrcPropertyName); + + pAct = new CPropertyAction (this, &CZStage::OnSAClkPol); + CreateProperty(g_SAClkPolPropertyName, g_SAClkPol_0, MM::String, false, pAct); + AddAllowedValue(g_SAClkPolPropertyName, g_SAClkPol_0); + AddAllowedValue(g_SAClkPolPropertyName, g_SAClkPol_1); + UpdateProperty(g_SAClkPolPropertyName); + + pAct = new CPropertyAction (this, &CZStage::OnSATTLOut); + CreateProperty(g_SATTLOutPropertyName, g_SATTLOut_0, MM::String, false, pAct); + AddAllowedValue(g_SATTLOutPropertyName, g_SATTLOut_0); + AddAllowedValue(g_SATTLOutPropertyName, g_SATTLOut_1); + UpdateProperty(g_SATTLOutPropertyName); + + pAct = new CPropertyAction (this, &CZStage::OnSATTLPol); + CreateProperty(g_SATTLPolPropertyName, g_SATTLPol_0, MM::String, false, pAct); + AddAllowedValue(g_SATTLPolPropertyName, g_SATTLPol_0); + AddAllowedValue(g_SATTLPolPropertyName, g_SATTLPol_1); + UpdateProperty(g_SATTLPolPropertyName); + + pAct = new CPropertyAction (this, &CZStage::OnSAPatternByte); + CreateProperty(g_SAPatternModePropertyName, "0", MM::Integer, false, pAct); + SetPropertyLimits(g_SAPatternModePropertyName, 0, 255); + UpdateProperty(g_SAPatternModePropertyName); + } + } + return DEVICE_OK; +} + +int CZStage::OnSAAmplitude(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + double tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAA " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR( hub_->ParseAnswerAfterEquals(tmp) ); + tmp = tmp/unitMult_; + if (!pProp->Set(tmp)) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + pProp->Get(tmp); + command << "SAA " << axisLetter_ << "=" << tmp*unitMult_; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSAOffset(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + double tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAO " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR( hub_->ParseAnswerAfterEquals(tmp) ); + tmp = tmp/unitMult_; + if (!pProp->Set(tmp)) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + pProp->Get(tmp); + command << "SAO " << axisLetter_ << "=" << tmp*unitMult_; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSAPeriod(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAF " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + if (!pProp->Set(tmp)) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + pProp->Get(tmp); + command << "SAF " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSAMode(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + static bool justSet = false; + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_ && !justSet) + return DEVICE_OK; + command << "SAM " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + bool success; + switch (tmp) + { + case 0: success = pProp->Set(g_SAMode_0); break; + case 1: success = pProp->Set(g_SAMode_1); break; + case 2: success = pProp->Set(g_SAMode_2); break; + case 3: success = pProp->Set(g_SAMode_3); break; + default:success = 0; break; + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + justSet = false; + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_SAMode_0) == 0) + tmp = 0; + else if (tmpstr.compare(g_SAMode_1) == 0) + tmp = 1; + else if (tmpstr.compare(g_SAMode_2) == 0) + tmp = 2; + else if (tmpstr.compare(g_SAMode_3) == 0) + tmp = 3; + else + return DEVICE_INVALID_PROPERTY_VALUE; + command << "SAM " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + // get the updated value right away + justSet = true; + return OnSAMode(pProp, MM::BeforeGet); + } + return DEVICE_OK; +} + +int CZStage::OnSAPattern(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + bool success; + tmp = tmp & ((long)(BIT2|BIT1|BIT0)); // zero all but the lowest 3 bits + switch (tmp) + { + case 0: success = pProp->Set(g_SAPattern_0); break; + case 1: success = pProp->Set(g_SAPattern_1); break; + case 2: success = pProp->Set(g_SAPattern_2); break; + default:success = 0; break; + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_SAPattern_0) == 0) + tmp = 0; + else if (tmpstr.compare(g_SAPattern_1) == 0) + tmp = 1; + else if (tmpstr.compare(g_SAPattern_2) == 0) + tmp = 2; + else + return DEVICE_INVALID_PROPERTY_VALUE; + // have to get current settings and then modify bits 0-2 from there + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + long current; + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(current) ); + current = current & (~(long)(BIT2|BIT1|BIT0)); // set lowest 3 bits to zero + tmp += current; + command.str(""); + command << "SAP " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSAPatternByte(MM::PropertyBase* pProp, MM::ActionType eAct) +// get every single time +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + if (!pProp->Set(tmp)) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + pProp->Get(tmp); + command << "SAP " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSAClkSrc(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + bool success; + tmp = tmp & ((long)(BIT7)); // zero all but bit 7 + switch (tmp) + { + case 0: success = pProp->Set(g_SAClkSrc_0); break; + case BIT7: success = pProp->Set(g_SAClkSrc_1); break; + default:success = 0; break; + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_SAClkSrc_0) == 0) + tmp = 0; + else if (tmpstr.compare(g_SAClkSrc_1) == 0) + tmp = BIT7; + else + return DEVICE_INVALID_PROPERTY_VALUE; + // have to get current settings and then modify bit 7 from there + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + long current; + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(current) ); + current = current & (~(long)(BIT7)); // clear bit 7 + tmp += current; + command.str(""); + command << "SAP " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSAClkPol(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + bool success; + tmp = tmp & ((long)(BIT6)); // zero all but bit 6 + switch (tmp) + { + case 0: success = pProp->Set(g_SAClkPol_0); break; + case BIT6: success = pProp->Set(g_SAClkPol_1); break; + default:success = 0; break; + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_SAClkPol_0) == 0) + tmp = 0; + else if (tmpstr.compare(g_SAClkPol_1) == 0) + tmp = BIT6; + else + return DEVICE_INVALID_PROPERTY_VALUE; + // have to get current settings and then modify bit 6 from there + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + long current; + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(current) ); + current = current & (~(long)(BIT6)); // clear bit 6 + tmp += current; + command.str(""); + command << "SAP " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSATTLOut(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + bool success; + tmp = tmp & ((long)(BIT5)); // zero all but bit 5 + switch (tmp) + { + case 0: success = pProp->Set(g_SATTLOut_0); break; + case BIT5: success = pProp->Set(g_SATTLOut_1); break; + default:success = 0; break; + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_SATTLOut_0) == 0) + tmp = 0; + else if (tmpstr.compare(g_SATTLOut_1) == 0) + tmp = BIT5; + else + return DEVICE_INVALID_PROPERTY_VALUE; + // have to get current settings and then modify bit 5 from there + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + long current; + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(current) ); + current = current & (~(long)(BIT5)); // clear bit 5 + tmp += current; + command.str(""); + command << "SAP " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnSATTLPol(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(tmp) ); + bool success; + tmp = tmp & ((long)(BIT4)); // zero all but bit 4 + switch (tmp) + { + case 0: success = pProp->Set(g_SATTLPol_0); break; + case BIT4: success = pProp->Set(g_SATTLPol_1); break; + default:success = 0; break; + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_SATTLPol_0) == 0) + tmp = 0; + else if (tmpstr.compare(g_SATTLPol_1) == 0) + tmp = BIT4; + else + return DEVICE_INVALID_PROPERTY_VALUE; + // have to get current settings and then modify bit 4 from there + command << "SAP " << axisLetter_ << "?"; + response << ":A " << axisLetter_ << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str())); + long current; + RETURN_ON_MM_ERROR ( hub_->ParseAnswerAfterEquals(current) ); + current = current & (~(long)(BIT4)); // clear bit 4 + tmp += current; + command.str(""); + command << "SAP " << axisLetter_ << "=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnRBMode(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + string pseudoAxisChar = FirmwareVersionAtLeast(2.89) ? "F" : "X"; + long tmp; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << addressChar_ << "RM " << pseudoAxisChar << "?"; + response << ":A " << pseudoAxisChar << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str()) ); + RETURN_ON_MM_ERROR( hub_->ParseAnswerAfterEquals(tmp) ); + if (tmp >= 128) + { + tmp -= 128; // remove the "running now" code if present + } + bool success; + switch ( tmp ) + { + case 1: success = pProp->Set(g_RB_OnePoint_1); break; + case 2: success = pProp->Set(g_RB_PlayOnce_2); break; + case 3: success = pProp->Set(g_RB_PlayRepeat_3); break; + default: success = false; + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_RB_OnePoint_1) == 0) + tmp = 1; + else if (tmpstr.compare(g_RB_PlayOnce_2) == 0) + tmp = 2; + else if (tmpstr.compare(g_RB_PlayRepeat_3) == 0) + tmp = 3; + else + return DEVICE_INVALID_PROPERTY_VALUE; + command << addressChar_ << "RM " << pseudoAxisChar << "=" << tmp; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), ":A")); + } + return DEVICE_OK; +} + +int CZStage::OnRBTrigger(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + if (eAct == MM::BeforeGet) { + pProp->Set(g_IdleState); + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + if (tmpstr.compare(g_DoItState) == 0) + { + command << addressChar_ << "RM"; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + pProp->Set(g_DoneState); + } + } + return DEVICE_OK; +} + +int CZStage::OnRBRunning(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + ostringstream response; response.str(""); + string pseudoAxisChar = FirmwareVersionAtLeast(2.89) ? "F" : "X"; + long tmp = 0; + static bool justSet; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_ && !justSet) + return DEVICE_OK; + command << addressChar_ << "RM " << pseudoAxisChar << "?"; + response << ":A " << pseudoAxisChar << "="; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), response.str()) ); + RETURN_ON_MM_ERROR( hub_->ParseAnswerAfterEquals(tmp) ); + bool success; + if (tmp >= 128) + { + success = pProp->Set(g_YesState); + } + else + { + success = pProp->Set(g_NoState); + } + if (!success) + return DEVICE_INVALID_PROPERTY_VALUE; + justSet = false; + } + else if (eAct == MM::AfterSet) + { + justSet = true; + return OnRBRunning(pProp, MM::BeforeGet); + } + return DEVICE_OK; +} + +int CZStage::OnRBDelayBetweenPoints(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + long tmp = 0; + if (eAct == MM::BeforeGet) + { + if (!refreshProps_ && initialized_) + return DEVICE_OK; + command << addressChar_ << "RT Z?"; + RETURN_ON_MM_ERROR( hub_->QueryCommandVerify(command.str(), ":A Z=")); + RETURN_ON_MM_ERROR( hub_->ParseAnswerAfterEquals(tmp) ); + if (!pProp->Set(tmp)) + return DEVICE_INVALID_PROPERTY_VALUE; + } + else if (eAct == MM::AfterSet) { + pProp->Get(tmp); + command << addressChar_ << "RT Z=" << tmp; + RETURN_ON_MM_ERROR ( hub_->QueryCommandVerify(command.str(), ":A") ); + } + return DEVICE_OK; +} + +int CZStage::OnUseSequence(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + ostringstream command; command.str(""); + if (eAct == MM::BeforeGet) + { + if (ttl_trigger_enabled_) + pProp->Set(g_YesState); + else + pProp->Set(g_NoState); + } + else if (eAct == MM::AfterSet) { + string tmpstr; + pProp->Get(tmpstr); + ttl_trigger_enabled_ = (ttl_trigger_supported_ && (tmpstr.compare(g_YesState) == 0)); + return OnUseSequence(pProp, MM::BeforeGet); // refresh value + } + return DEVICE_OK; +} diff --git a/DeviceAdapters/ASITiger/ASIZStage.h b/DeviceAdapters/ASITiger/ASIZStage.h index 2230004801..98edb3ed63 100644 --- a/DeviceAdapters/ASITiger/ASIZStage.h +++ b/DeviceAdapters/ASITiger/ASIZStage.h @@ -57,15 +57,15 @@ class CZStage : public ASIPeripheralBase int SetOrigin(); bool IsContinuousFocusDrive() const {return false;} // todo figure out what this means and if it's accurate - int IsStageSequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; } - int GetStageSequenceMaxLength(long& nrEvents) const { nrEvents = 0; return DEVICE_OK; } - // below aren't implemented yet - int StartStageSequence() { return DEVICE_UNSUPPORTED_COMMAND; } - int StopStageSequence() { return DEVICE_UNSUPPORTED_COMMAND; } - int ClearStageSequence() { return DEVICE_UNSUPPORTED_COMMAND; } - int AddToStageSequence(double /*position*/) { return DEVICE_UNSUPPORTED_COMMAND; } - int SendStageSequence() { return DEVICE_UNSUPPORTED_COMMAND; } + int IsStageSequenceable(bool& isSequenceable) const { isSequenceable = ttl_trigger_enabled_; return DEVICE_OK; } + int GetStageSequenceMaxLength(long& nrEvents) const { nrEvents = ring_buffer_capacity_; return DEVICE_OK; } + + int StartStageSequence(); + int StopStageSequence(); + int ClearStageSequence(); + int AddToStageSequence(double position); + int SendStageSequence(); // action interface // ---------------- @@ -97,12 +97,35 @@ class CZStage : public ASIPeripheralBase int OnWheelSlowSpeed (MM::PropertyBase* pProp, MM::ActionType eAct); int OnWheelMirror (MM::PropertyBase* pProp, MM::ActionType eAct); int OnAxisPolarity (MM::PropertyBase* pProp, MM::ActionType eAct); + // single axis properties + int OnSAAmplitude (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAOffset (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAPeriod (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAMode (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAPattern (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAAdvanced (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAClkSrc (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAClkPol (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSATTLOut (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSATTLPol (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSAPatternByte (MM::PropertyBase* pProp, MM::ActionType eAct); + // ring buffer properties + int OnRBDelayBetweenPoints (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnRBMode (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnRBTrigger (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnRBRunning (MM::PropertyBase* pProp, MM::ActionType eAct); + int OnUseSequence (MM::PropertyBase* pProp, MM::ActionType eAct); private: double unitMult_; double stepSizeUm_; string axisLetter_; bool advancedPropsEnabled_; + bool ring_buffer_supported_; + long ring_buffer_capacity_; + bool ttl_trigger_supported_; + bool ttl_trigger_enabled_; + std::vector sequence_; // private helper functions int OnSaveJoystickSettings(); diff --git a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive.h b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive.h index d19bce4630..d491b51278 100644 --- a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive.h +++ b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive.h @@ -24,5 +24,7 @@ static const char* g_Keyword_SetPosZUm = "Set position Z (um)"; static const char* g_Keyword_SetPosXUm = "Set position X (um)"; static const char* g_Keyword_SetPosYUm = "Set position Y (um)"; static const char* g_Keyword_SetOrigin = "Set origin here"; +static const char* g_Keyword_SetSequence = "Use Sequence"; +static const char* g_Keyword_ShiftSequence = "Shift sequence by 1"; #endif //_MCL_NANODRIVE_H_ diff --git a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.cpp b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.cpp index e1bd984f31..ee8cca74db 100644 --- a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.cpp +++ b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.cpp @@ -15,6 +15,8 @@ MCL_NanoDrive_XYStage::MCL_NanoDrive_XYStage(): settlingTimeY_ms_(100), curXpos_(0), curYpos_(0), + commandedX_(0), + commandedY_(0), firstWriteX_(true), firstWriteY_(true), MCLhandle_(0) @@ -51,8 +53,8 @@ void MCL_NanoDrive_XYStage::GetName(char* name) const int MCL_NanoDrive_XYStage::Initialize() { -// BEGIN LOCKING -HandleListLock(); + // BEGIN LOCKING + HandleListLock(); int err = DEVICE_OK; int possHandle = 0; @@ -89,6 +91,7 @@ HandleListLock(); device->Initialize(possHandle, XY_TYPE); for (int i = 0; i < numHandles; i++) { + possHandle = handlesToUseOrRelease[i]; device->setHandle(possHandle); @@ -357,6 +360,17 @@ int MCL_NanoDrive_XYStage::SetDeviceProperties() if (err != DEVICE_OK) return err; + + //Current Commanded Position + sprintf(iToChar, "%f", commandedX_); + pAct = new CPropertyAction(this, &MCL_NanoDrive_XYStage::OnCommandChangedX); + err = CreateProperty("CommandedX",iToChar, MM::Float, true, pAct); + + //Current Commanded Position + sprintf(iToChar, "%f", commandedY_); + pAct = new CPropertyAction(this, &MCL_NanoDrive_XYStage::OnCommandChangedY); + err = CreateProperty("CommandedY",iToChar, MM::Float, true, pAct); + return DEVICE_OK; } @@ -727,3 +741,31 @@ int MCL_NanoDrive_XYStage::OnSetOrigin(MM::PropertyBase* pProp, MM::ActionType e return err; } + +int MCL_NanoDrive_XYStage::OnCommandChangedX(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + int err = DEVICE_OK; + + if (eAct == MM::BeforeGet) + { + double ignoreZ; + MCL_GetCommandedPosition(&commandedX_, &commandedY_, &ignoreZ, MCLhandle_); + pProp->Set(commandedX_); + } + + return err; +} + +int MCL_NanoDrive_XYStage::OnCommandChangedY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + int err = DEVICE_OK; + + if (eAct == MM::BeforeGet) + { + double ignoreZ; + MCL_GetCommandedPosition(&commandedX_, &commandedY_, &ignoreZ, MCLhandle_); + pProp->Set(commandedY_); + } + + return err; +} diff --git a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.h b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.h index 215ff19d42..dea81dc60e 100644 --- a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.h +++ b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_XYStage.h @@ -59,6 +59,8 @@ class MCL_NanoDrive_XYStage : public CXYStageBase int OnSettlingTimeXMs(MM::PropertyBase* pProp, MM::ActionType eAct); int OnSettlingTimeYMs(MM::PropertyBase* pProp, MM::ActionType eAct); int OnSetOrigin(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnCommandChangedX(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnCommandChangedY(MM::PropertyBase* pProp, MM::ActionType eAct); private: int SetDeviceProperties(); @@ -91,6 +93,9 @@ class MCL_NanoDrive_XYStage : public CXYStageBase bool firstWriteX_; bool firstWriteY_; + + double commandedX_; + double commandedY_; }; #endif // _MCL_NANODRIVE_XYSTAGE_H_ \ No newline at end of file diff --git a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.cpp b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.cpp index d58e5dcf61..afb8e753ac 100644 --- a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.cpp +++ b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.cpp @@ -13,7 +13,12 @@ MCL_NanoDrive_ZStage::MCL_NanoDrive_ZStage() : initialized_(false), settlingTimeZ_ms_(100), curZpos_(0), + commandedZ_(0), firstWrite_(true), + canSupportSeq_(false), + supportsSeq_(false), + seqMaxSize_(0), + shiftSequence_(false), MCLhandle_(0) { // Basically only construct error messages in the constructor @@ -47,8 +52,8 @@ bool MCL_NanoDrive_ZStage::Busy() int MCL_NanoDrive_ZStage::Initialize() { -// BEGIN LOCKING -> make sure to unlock before any return call -HandleListLock(); + // BEGIN LOCKING -> make sure to unlock before any return call + HandleListLock(); int err = DEVICE_OK; int possHandle = 0; @@ -179,6 +184,15 @@ HandleListLock(); goto ZSTAGE_INIT_EXIT; } + if((pi.FirmwareProfile & 0x0100) != 0) + { + canSupportSeq_ = true; + supportsSeq_ = true; + err = MCL_SequenceGetMax(&seqMaxSize_, MCLhandle_); + if(err != MCL_SUCCESS) + goto ZSTAGE_INIT_EXIT; + } + err = CreateZStageProperties(); if (err != DEVICE_OK) { @@ -329,6 +343,29 @@ int MCL_NanoDrive_ZStage::CreateZStageProperties() yesNoList.push_back("Yes"); SetAllowedValues(g_Keyword_SetOrigin, yesNoList); + if(canSupportSeq_) + { + // Set the origin at the current position + pAct = new CPropertyAction(this, &MCL_NanoDrive_ZStage::OnSetSequence); + err = CreateProperty(g_Keyword_SetSequence, "No", MM::String, false, pAct); + if (err != DEVICE_OK) + return err; + SetAllowedValues(g_Keyword_SetSequence, yesNoList); + + + pAct = new CPropertyAction(this, &MCL_NanoDrive_ZStage::OnSetShiftSequence); + err = CreateProperty(g_Keyword_ShiftSequence, "No", MM::String, false, pAct); + if(err != DEVICE_OK) + return err; + SetAllowedValues(g_Keyword_ShiftSequence, yesNoList); + } + + + //Current Commanded Position + sprintf(iToChar, "%f", commandedZ_); + pAct = new CPropertyAction(this, &MCL_NanoDrive_ZStage::OnCommandChanged); + err = CreateProperty("CommandedZ",iToChar, MM::Float, true, pAct); + return DEVICE_OK; } @@ -437,39 +474,95 @@ int MCL_NanoDrive_ZStage::GetLimits(double& lower, double& upper) int MCL_NanoDrive_ZStage::IsStageSequenceable(bool& isSequenceable) const { - isSequenceable = false; + isSequenceable = supportsSeq_; return DEVICE_OK; } -int MCL_NanoDrive_ZStage::GetStageSequenceMaxLength(long& /*nrEvents*/)const + +int MCL_NanoDrive_ZStage::GetStageSequenceMaxLength(long& nrEvents)const { - return DEVICE_UNSUPPORTED_COMMAND; + if(!supportsSeq_) + return DEVICE_UNSUPPORTED_COMMAND; + + nrEvents = seqMaxSize_; + + return DEVICE_OK; } + int MCL_NanoDrive_ZStage::StartStageSequence() { - return DEVICE_UNSUPPORTED_COMMAND; + if(!supportsSeq_) + return DEVICE_UNSUPPORTED_COMMAND; + + int err = MCL_SequenceStart(MCLhandle_); + if(err != MCL_SUCCESS) + return err; + + return DEVICE_OK; } + int MCL_NanoDrive_ZStage::StopStageSequence() { - return DEVICE_UNSUPPORTED_COMMAND; -} -int MCL_NanoDrive_ZStage::LoadStageSequence(std::vector /*positions*/) const -{ - return DEVICE_UNSUPPORTED_COMMAND; + if(!supportsSeq_) + return DEVICE_UNSUPPORTED_COMMAND; + + int err = MCL_SequenceStop(MCLhandle_); + if(err != MCL_SUCCESS) + return err; + + return DEVICE_OK; } int MCL_NanoDrive_ZStage::ClearStageSequence() { - return DEVICE_UNSUPPORTED_COMMAND; + if(!supportsSeq_) + return DEVICE_UNSUPPORTED_COMMAND; + + sequence_.clear(); + int err = MCL_SequenceClear(MCLhandle_); + if(err != MCL_SUCCESS) + return err; + + return DEVICE_OK; } -int MCL_NanoDrive_ZStage::AddToStageSequence(double /*position*/) +int MCL_NanoDrive_ZStage::AddToStageSequence(double position) { - return DEVICE_UNSUPPORTED_COMMAND; + if(!supportsSeq_) + return DEVICE_UNSUPPORTED_COMMAND; + + sequence_.push_back(position); + + return DEVICE_OK; } -int MCL_NanoDrive_ZStage::SendStageSequence() +int MCL_NanoDrive_ZStage::SendStageSequence() { - return DEVICE_UNSUPPORTED_COMMAND; + if(!supportsSeq_) + return DEVICE_UNSUPPORTED_COMMAND; + + if(sequence_.size() < 0) + return MCL_SEQ_NOT_VALID; + + double *seqCopy = new double[sequence_.size()]; + if(shiftSequence_) + { + if(sequence_.size() == 1) + seqCopy[0] = sequence_[0]; + else + { + memcpy(seqCopy, &sequence_[1], (sequence_.size() - 1) * sizeof(double)); + seqCopy[sequence_.size() - 1] = sequence_[0]; + } + } + else + { + memcpy(seqCopy, &sequence_[0], sequence_.size() * sizeof(double)); + } + + int err = MCL_SequenceLoad(axis_, seqCopy, sequence_.size(), MCLhandle_); + delete [] seqCopy; + + return err; } bool MCL_NanoDrive_ZStage::IsContinuousFocusDrive() const @@ -548,3 +641,63 @@ int MCL_NanoDrive_ZStage::OnSetOrigin(MM::PropertyBase* pProp, MM::ActionType eA return err; } + +int MCL_NanoDrive_ZStage::OnCommandChanged(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + int err = DEVICE_OK; + + if (eAct == MM::BeforeGet) + { + double ignoreX, ignoreY; + MCL_GetCommandedPosition(&ignoreX, &ignoreY, &commandedZ_, MCLhandle_); + pProp->Set(commandedZ_); + } + + return err; +} + +int MCL_NanoDrive_ZStage::OnSetSequence(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + if(supportsSeq_) + pProp->Set("Yes"); + else + pProp->Set("No"); + } + else if (eAct == MM::AfterSet) + { + std::string message; + pProp->Get(message); + + if (message.compare("Yes") == 0) + supportsSeq_ = true; + else + supportsSeq_ = false; + } + + return DEVICE_OK; +} + +int MCL_NanoDrive_ZStage::OnSetShiftSequence(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + if(shiftSequence_) + pProp->Set("Yes"); + else + pProp->Set("No"); + } + else if (eAct == MM::AfterSet) + { + std::string message; + pProp->Get(message); + + if (message.compare("Yes") == 0) + shiftSequence_ = true; + else + shiftSequence_ = false; + } + + return DEVICE_OK; +} \ No newline at end of file diff --git a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.h b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.h index 387e19221c..726cf0a465 100644 --- a/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.h +++ b/DeviceAdapters/MCL_NanoDrive/MCL_NanoDrive_ZStage.h @@ -21,9 +21,12 @@ License: Distributed under the BSD license. #include "HandleListType.h" #include "heap.h" +#include + class MCL_NanoDrive_ZStage : public CStageBase { public: + MCL_NanoDrive_ZStage(); ~MCL_NanoDrive_ZStage(); @@ -36,7 +39,7 @@ class MCL_NanoDrive_ZStage : public CStageBase // Stage API virtual int SetPositionUm(double pos); virtual int GetPositionUm(double& pos); - virtual int SetRelativePositionUm(double d); + virtual int SetRelativePositionUm(double d); virtual double GetStepSize(); virtual int SetPositionSteps(long steps); virtual int GetPositionSteps(long& steps); @@ -46,11 +49,10 @@ class MCL_NanoDrive_ZStage : public CStageBase virtual int GetStageSequenceMaxLength(long& nrEvents) const; virtual int StartStageSequence(); virtual int StopStageSequence(); - virtual int LoadStageSequence(std::vector positions) const; - virtual bool IsContinuousFocusDrive() const; virtual int ClearStageSequence(); virtual int AddToStageSequence(double position); - virtual int SendStageSequence(); + virtual int SendStageSequence(); + virtual bool IsContinuousFocusDrive() const; int getHandle(){ return MCLhandle_;} @@ -58,6 +60,9 @@ class MCL_NanoDrive_ZStage : public CStageBase int OnPositionUm(MM::PropertyBase* pProp, MM::ActionType eAct); int OnSettlingTimeZMs(MM::PropertyBase* pProp, MM::ActionType eAct); int OnSetOrigin(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnCommandChanged(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSetSequence(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSetShiftSequence(MM::PropertyBase* pProp, MM::ActionType eAct); private: int CreateZStageProperties(); @@ -71,10 +76,16 @@ class MCL_NanoDrive_ZStage : public CStageBase double calibration_; int serialNumber_; int settlingTimeZ_ms_; + double commandedZ_; double curZpos_; - bool firstWrite_; + + bool canSupportSeq_; + bool supportsSeq_; + int seqMaxSize_; + bool shiftSequence_; + std::vector sequence_; int axis_; }; diff --git a/DeviceAdapters/MCL_NanoDrive/Madlib.h b/DeviceAdapters/MCL_NanoDrive/Madlib.h index cab3895e2f..33a8d7b09c 100644 --- a/DeviceAdapters/MCL_NanoDrive/Madlib.h +++ b/DeviceAdapters/MCL_NanoDrive/Madlib.h @@ -16,6 +16,7 @@ License: Distributed under the BSD license. #define MCL_INVALID_AXIS -7 #define MCL_INVALID_HANDLE -8 #define MCL_INVALID_DRIVER -9 +#define MCL_SEQ_NOT_VALID -10 #pragma pack(push, 1) struct ProductInformation { @@ -48,6 +49,13 @@ MADLIB_API double MCL_GetCalibration(unsigned int axis, int handle); MADLIB_API int MCL_GetSerialNumber(int handle); MADLIB_API int MCL_GetProductInfo(struct ProductInformation *pi, int handle); MADLIB_API bool MCL_DeviceAttached(int milliseconds, int handle); +MADLIB_API int MCL_GetCommandedPosition(double *xCom, double *yCom, double *zCom, int handle); + +MADLIB_API int MCL_SequenceLoad(int axis, double* sequence, int seqSize, int handle); +MADLIB_API int MCL_SequenceClear(int handle); +MADLIB_API int MCL_SequenceStart(int handle); +MADLIB_API int MCL_SequenceStop(int handle); +MADLIB_API int MCL_SequenceGetMax(int* max, int handle); MADLIB_API bool MCL_CorrectDriverVersion(); diff --git a/DeviceAdapters/MCL_NanoDrive/Madlib.lib b/DeviceAdapters/MCL_NanoDrive/Madlib.lib index b1244e3106..62963b873b 100644 Binary files a/DeviceAdapters/MCL_NanoDrive/Madlib.lib and b/DeviceAdapters/MCL_NanoDrive/Madlib.lib differ diff --git a/DeviceAdapters/MCL_NanoDrive/Madlib64.lib b/DeviceAdapters/MCL_NanoDrive/Madlib64.lib index 79e76a024d..405c8ebadd 100644 Binary files a/DeviceAdapters/MCL_NanoDrive/Madlib64.lib and b/DeviceAdapters/MCL_NanoDrive/Madlib64.lib differ diff --git a/MMCore/FrameBuffer.cpp b/MMCore/FrameBuffer.cpp index 8d8e1aab2f..80cb0c6394 100644 --- a/MMCore/FrameBuffer.cpp +++ b/MMCore/FrameBuffer.cpp @@ -18,7 +18,8 @@ #include "FrameBuffer.h" -#include +#include +#include namespace mm { diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index edb358495b..f5a4db8342 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -106,7 +106,7 @@ using namespace std; * (Keep the 3 numbers on one line to make it easier to look at diffs when * merging/rebasing.) */ -const int MMCore_versionMajor = 8, MMCore_versionMinor = 4, MMCore_versionPatch = 1; +const int MMCore_versionMajor = 8, MMCore_versionMinor = 5, MMCore_versionPatch = 0; /////////////////////////////////////////////////////////////////////////////// @@ -4176,6 +4176,54 @@ void CMMCore::getROI(int& x, int& y, int& xSize, int& ySize) throw (CMMError) ySize = (int) uYSize; } +/** +* Set the hardware region of interest for a specified camera. +* +* A successful call to this method will clear any images in the sequence +* buffer, even if the ROI does not change. +* +* Warning: the clearing of the sequence buffer will interfere with any sequence +* acquisitions currently being performed on other cameras. +* +* If multiple ROIs are set prior to this call, they will be replaced by the +* new single ROI. +* +* The coordinates are in units of binned pixels. That is, conceptually, +* binning is applied before the ROI. +* +* @param label camera label +* @param x coordinate of the top left corner +* @param y coordinate of the top left corner +* @param xSize number of horizontal pixels +* @param ySize number of horizontal pixels +*/ +void CMMCore::setROI(const char* label, int x, int y, int xSize, int ySize) throw (CMMError) +{ + boost::shared_ptr camera = deviceManager_->GetDeviceOfType(label); + if (camera) + { + mm::DeviceModuleLockGuard guard(camera); + LOG_DEBUG(coreLogger_) << "Will set ROI of camera " << label << + " to (left = " << x << ", top = " << y << + ", width = " << xSize << ", height = " << ySize << ")"; + int nRet = camera->SetROI(x, y, xSize, ySize); + if (nRet != DEVICE_OK) + throw CMMError(getDeviceErrorText(nRet, camera).c_str(), MMERR_DEVICE_GENERIC); + + // Any images left over in the sequence buffer may have sizes + // inconsistent with the current image size. There is no way to "fix" + // popNextImage() to handle this correctly, so we need to make sure we + // discard such images. + cbuf_->Clear(); + } + else + throw CMMError(getCoreErrorText(MMERR_CameraNotAvailable).c_str(), MMERR_CameraNotAvailable); + + LOG_DEBUG(coreLogger_) << "Did set ROI of camera " << label << + " to (left = " << x << ", top = " << y << + ", width = " << xSize << ", height = " << ySize << ")"; +} + /** * Return the current hardware region of interest for a camera. If multiple * ROIs are set, this method instead returns a rectangle that describes the diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index c2ead10db6..cf67d40b0f 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -349,7 +349,8 @@ class CMMCore /** \name Image acquisition. */ ///@{ - void setROI(int x, int y, int xSize, int ySize) throw (CMMError); + void setROI(int x, int y, int xSize, int ySize) throw (CMMError); + void setROI(const char* label, int x, int y, int xSize, int ySize) throw (CMMError); void getROI(int& x, int& y, int& xSize, int& ySize) throw (CMMError); void getROI(const char* label, int& x, int& y, int& xSize, int& ySize) throw (CMMError); void clearROI() throw (CMMError);