From 9371adc614a595bb65cec4c43972c6ab0f6a1ab8 Mon Sep 17 00:00:00 2001 From: ToufikABED Date: Fri, 10 Feb 2023 08:50:35 +0900 Subject: [PATCH 1/4] add SigmaKoki Adapter --- DeviceAdapters/SigmaKoki/Camera.cpp | 1959 +++++++++++++++++ DeviceAdapters/SigmaKoki/Camera.h | 213 ++ DeviceAdapters/SigmaKoki/Shutter.cpp | 861 ++++++++ DeviceAdapters/SigmaKoki/Shutter.h | 77 + DeviceAdapters/SigmaKoki/SigmaBase.cpp | 230 ++ DeviceAdapters/SigmaKoki/SigmaBase.h | 71 + DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj | 197 ++ .../SigmaKoki/SigmaKoki.vcxproj.filters | 54 + DeviceAdapters/SigmaKoki/XYStage.cpp | 1494 +++++++++++++ DeviceAdapters/SigmaKoki/XYStage.h | 114 + DeviceAdapters/SigmaKoki/ZStage.cpp | 1063 +++++++++ DeviceAdapters/SigmaKoki/ZStage.h | 88 + DeviceAdapters/SigmaKoki/license.txt | 28 + 13 files changed, 6449 insertions(+) create mode 100644 DeviceAdapters/SigmaKoki/Camera.cpp create mode 100644 DeviceAdapters/SigmaKoki/Camera.h create mode 100644 DeviceAdapters/SigmaKoki/Shutter.cpp create mode 100644 DeviceAdapters/SigmaKoki/Shutter.h create mode 100644 DeviceAdapters/SigmaKoki/SigmaBase.cpp create mode 100644 DeviceAdapters/SigmaKoki/SigmaBase.h create mode 100644 DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj create mode 100644 DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters create mode 100644 DeviceAdapters/SigmaKoki/XYStage.cpp create mode 100644 DeviceAdapters/SigmaKoki/XYStage.h create mode 100644 DeviceAdapters/SigmaKoki/ZStage.cpp create mode 100644 DeviceAdapters/SigmaKoki/ZStage.h create mode 100644 DeviceAdapters/SigmaKoki/license.txt diff --git a/DeviceAdapters/SigmaKoki/Camera.cpp b/DeviceAdapters/SigmaKoki/Camera.cpp new file mode 100644 index 000000000..bfdc1375c --- /dev/null +++ b/DeviceAdapters/SigmaKoki/Camera.cpp @@ -0,0 +1,1959 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: Camera2.cpp +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#pragma once + +#include +#include +#include +#include +#include +#include +#include "StCamD.h" +#include "Camera.h" +using namespace std; + +// Constants +// +// Property name + +const char* g_CameraDeviceName = "SKCam"; +const char* g_CameraProductName = "ProductName"; +const char* g_CameraALCMode = "ALC_Mode"; +const char* g_CameraShutterGain = "Shutter Gain"; +const char* g_CameraShutterGainMode = "Shutter Gain Mode"; +const char* g_CameraShutterGainAutoMax = "Shutter Gain Auto Max"; +const char* g_CameraShutterGainAutoMin = "Shutter Gain Auto Min"; +const char* g_CameraExposure = "Exposure (msec)"; +const char* g_CameraClockSpeed = "ClockSpeed"; +const char* g_CameraFPS = "FPS"; +const char* g_CameraImageDeviceSizeH = "ImageDeviceSize_H(pixel)"; +const char* g_CameraImageDeviceSizeV = "ImageDeviceSize_V(pixel)"; +const char* g_CameraWBMode = "WhiteBalance_Mode"; +const char* g_CameraWBGainR = "WhiteBalance_GainR"; +const char* g_CameraWBGainGr = "WhiteBalance_GainGr"; +const char* g_CameraWBGainGb = "WhiteBalance_GainGb"; +const char* g_CameraWBGainB = "WhiteBalance_GainB"; +const char* g_CameraDelaySnap = "SnapDelay (msec)"; + +// scan mode +const char* g_ScanMode = "Binning Scan Mode"; + + +// ALC(Auto Luminance Control) mode +const char* g_ALCMode_FS_MG = "Fixed Shutter/Manual Gain"; +const char* g_ALCMode_AS_AGC = "Auto Shutter/AGC"; +const char* g_ALCMode_AS_MG = "Auto Shutter/Manual Gain"; +const char* g_ALCMode_FS_AGC = "Fixed Shutter/AGC"; + +// clock-speed types +const char* g_ClockSpeed_Reference = "Reference clock"; +const char* g_ClockSpeed_Div2 = "1/2 clock"; +const char* g_ClockSpeed_Div4 = "1/4 clock"; + +//Mirror orienation +const char* g_Mirror_Mode = "Mirror Mode"; + + +// pixel type +const char* g_PixelType_8bitMONO = "8bit_MONO"; +const char* g_PixelType_32bitBGR = "32bit_BGR"; + +// white balance mode +const char* g_WB_Mode_Off = "Off"; +const char* g_WB_Mode_Auto = "Auto"; +const char* g_WB_Mode_Manual = "Manual"; +const char* g_WB_Mode_OneShot = "OneShot"; + +/////////////////////////////////////////////////////////////////////////////// +// Exported MMDevice API +/////////////////////////////////////////////////////////////////////////////// + +// General utility function: +int ClearPort(MM::Device& device, MM::Core& core, std::string port) +{ + //Clear contents of serial port + const int bufSize = 255; + unsigned char clear[bufSize]; + unsigned long read = bufSize; + int ret; + while (read == (unsigned)bufSize) + { + ret = core.ReadFromSerial(&device, port.c_str(), clear, bufSize, read); + if (ret != DEVICE_OK) + return ret; + } + return DEVICE_OK; +} + +#pragma region Camera +///////////////////////////////////////////////////////////////////////////////// +//// Camera +//// +////Supported models �c [STC-MC202USB, STC-STC-MCA5MUSB3, SK-TC202USB-AT](old model) +////Added Cameras USB 3 [STC-MCS122BU3V, STC-MCCM401U3V, STC-MBCM200U3V/NIR, other USB3 cameras were not tested yet ] + +/** +* Camera constructor. +* Setup default all variables and create device properties required to exist +* before intialization. In this case, no such properties were required. All +* properties will be created in the Initialize() method. +* +* As a general guideline Micro-Manager devices do not access hardware in the +* the constructor. We should do as little as possible in the constructor and +* perform most of the initialization in the Initialize() method. +*/ +Camera::Camera() : + // initialization of parameters + SigmaBase(this), + CCameraBase(), + initialized_(false), + isMonochrome_(false), + enabledROI_(false), + readoutUs_(0.0), + bitDepth_(8), + roiX_(0), + roiY_(0), + dwSize_(0), + dwLinePitch_(0), + dwPreviewPixelFormat_(0), + gain_(0), + gainMode_("Digital All"), + autoGainMax_(0), + autoGainMin_(0), + exposureMsec_(0.0), + exposureMaxMsec_(0.0), + exposureMinMsec_(0.0), + exposureClock_(0), + exposureMaxClock_(0), + clockFreq_(0), + fps_(0.0), + wbGainR_(0), + wbGainGr_(0), + wbGainGb_(0), + wbGainB_(0), + delayMsec_(0), + sequenceStartTime_(0), + isSequenceable_(false), + binFac_(1), + imageSizeH_(0), + imageSizeV_(0), + mirrorMode_("MIRROR OFF"), + stopOnOverflow_(false), + nComponents_(1) +{ + // Error Msgs + InitializeDefaultErrorMessages(); + SetErrorText(ERR_CAMERA_OPEN_FAILED, "Failed to open."); + SetErrorText(ERR_CAMERA_GET_PREVIEWDATASIZE_FAILED, "Failed to get the preview data size."); + SetErrorText(ERR_CAMERA_SET_PIXELFORMAT_FAILED, "Failed to set the pixel format."); + SetErrorText(ERR_CAMERA_SET_TARGET_BRIGHTNESS_FAILED, "Failed to set the target brightness."); + SetErrorText(ERR_CAMERA_GET_SHUTTER_GAIN_CONTROL_RANGE_FAILED, "Failed to get the auto gain control range."); + SetErrorText(ERR_CAMERA_SET_ALCMODE_FAILED, "Failed to set the ALC-mode."); + SetErrorText(ERR_CAMERA_GET_ALCMODE_FAILED, "Failed to get the ALC-mode."); + SetErrorText(ERR_CAMERA_SET_SHUTTER_GAIN_FAILED, "Failed to set the shutter gain value."); + SetErrorText(ERR_CAMERA_GET_SHUTTER_GAIN_FAILED, "Failed to get the shutter gain value."); + SetErrorText(ERR_CAMERA_SET_EXPOSURE_TIME_FAILED, "Failed to set the exposure time."); + SetErrorText(ERR_CAMERA_GET_EXPOSURE_TIME_FAILED, "Failed to get the exposure time."); + SetErrorText(ERR_CAMERA_GET_CLOCK_FAILED, "Failed to get the clock mode."); + SetErrorText(ERR_CAMERA_SET_CLOCK_FAILED, "Failed to set the clock mode."); + SetErrorText(ERR_CAMERA_GET_FPS_FAILED, "Failed to get the FPS."); + SetErrorText(ERR_CAMERA_START_TRANSFER_FAILED, "Failed to transfer the start of the image data."); + SetErrorText(ERR_CAMERA_STOP_TRANSFER_FAILED, "Failed to transfer the stop of the image data."); + SetErrorText(ERR_CAMERA_SNAPSHOT_FAILED, "Failed to snapshot."); + SetErrorText(ERR_CAMERA_LIVE_STOP_UNKNOWN, "Live has been stopped with an unknown error."); + SetErrorText(ERR_CAMERA_GET_PRODUCT_NAME_FAILED, "Failed to get the product name."); + SetErrorText(ERR_CAMERA_SET_BINNING_SCAN_MODE_FAILED, "Failed to set binning scan mode."); + SetErrorText(ERR_CAMERA_GET_BINNING_SCAN_MODE_FAILED, "Failed to get binning scan mode."); + SetErrorText(ERR_CAMERA_SET_WB_MODE_FAILED, "Failed to set white balance mode."); + SetErrorText(ERR_CAMERA_GET_WB_MODE_FAILED, "Failed to get white balance mode."); + SetErrorText(ERR_CAMERA_SET_WB_GAIN_FAILED, "Failed to set white balance gain."); + SetErrorText(ERR_CAMERA_GET_WB_GAIN_FAILED, "Failed to get white balance gain."); + SetErrorText(ERR_CAMERA_GET_COLOR_ARRAY_FAILED, "Failed to get color array."); + SetErrorText(ERR_CAMERA_SET_ROI_FAILED, "Failed to set ROI."); + SetErrorText(ERR_CAMERA_GET_ROI_COUNT_FAILED, "Failed to get ROI count."); + SetErrorText(ERR_CAMERA_ALCMODE_UNAVAILABLE_FUNCTION, "It can not be set in the current ALC mode."); + SetErrorText(ERR_CAMERA_WBMODE_UNAVAILABLE_FUNCTION, "It can not be set in the current White Balance mode."); + SetErrorText(ERR_CAMERA_SCAN_MODE_FAILED_SETTING, "Failed to set scan mode"); + SetErrorText(ERR_CAMERA_SCAN_MODE_PROHIBTED, "Cannot Set Data in Actual Normal Scan Mode"); + readoutStartTime_ = GetCurrentMMTime(); + thd_ = new MySequenceThread(this); + + // Name + CreateStringProperty(MM::g_Keyword_Name, g_CameraDeviceName, true); + + // Description + CreateStringProperty(MM::g_Keyword_Description, "SIGMA-KOKI Camera Device Adapter", true); +} + +Camera::~Camera() +{ + StopSequenceAcquisition(); + delete thd_; +} + +#pragma endregion Camera + +void Camera::GetName(char* Name) const +{ + CDeviceUtils::CopyLimitedString(Name, g_CameraDeviceName); +} + +int Camera::Initialize() +{ + if (initialized_) + return DEVICE_OK; + + // Create a system object for device scan and connection. + // Here we use CIStSystemPtr instead of IStSystemReleasable for automatically managing the IStSystemReleasable class with auto initial/deinitial. + //CIStSystemPtr pIStSystem(CreateIStSystem()); + // Create a camera device object and connect to first detected device by using the function of system object. + // We use CIStDevicePtr instead of IStDeviceReleasable for automatically managing the IStDeviceReleasable class with auto initial/deinitial. + //CIStDevicePtr pIStDevice(pIStSystem->CreateFirstIStDevice()); + + // Open and product name + handle_ = StCam_Open(0); + if (handle_ == 0) { return ERR_CAMERA_OPEN_FAILED; } + + BOOL ans = TRUE; + + // Product name(read only) + ans = StCam_GetProductNameA(handle_, &name_, 255); + if (!ans) { return ERR_CAMERA_GET_PRODUCT_NAME_FAILED; } + + int ret = CreateStringProperty(g_CameraProductName, &name_, true); + if (ret != DEVICE_OK) + return ret; + + productName_ = productName_.append(&name_); + cout << "Name product " << productName_ << endl; + + // ROI Check Changed in MM 2.0 + /*Check of ROI function + DWORD count = 0; + ans = StCam_GetMaxROICount(handle_, &count); + if (!ans) { return ERR_CAMERA_GET_ROI_COUNT_FAILED; } + if (count == 1) + { + enabledROI_ = false; // USB2.0 type + } + else + { + enabledROI_ = true; // USB3.0 type + }*/ + + // ColorArray (color or monochrome) + WORD colorArray; + ans = StCam_GetColorArray(handle_, &colorArray); + if (!ans) { return ERR_CAMERA_GET_COLOR_ARRAY_FAILED; } + + if (colorArray == STCAM_COLOR_ARRAY_MONO) + { + isMonochrome_ = true; //mono + } + else + { + isMonochrome_ = false; //color + } + + // Pixel format (read only.) + const char* pixelType; + DWORD pixelFormat; + if (isMonochrome_) + { + pixelFormat = STCAM_PIXEL_FORMAT_08_MONO_OR_RAW; + pixelType = g_PixelType_8bitMONO; + } + else + { + pixelFormat = STCAM_PIXEL_FORMAT_32_BGR; + pixelType = g_PixelType_32bitBGR; + } + ans = StCam_SetPreviewPixelFormat(handle_, pixelFormat); + if (!ans) { return ERR_CAMERA_SET_PIXELFORMAT_FAILED; } + + ret = CreateStringProperty(MM::g_Keyword_PixelType, pixelType, true); + if (ret != DEVICE_OK) + return ret; + + // scan mode + ans = StCam_GetEnableImageSize(handle_, 0, &scanMode_); + if (!ans) {return ERR_CAMERA_SCAN_MODE_FAILED_SETTING;} + CPropertyAction* pAct = new CPropertyAction(this, &Camera::OnScanMode); + ret = CreateProperty(g_ScanMode, scanModeType_.c_str(), MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + + + vector ScanMode; + ScanMode.push_back("SCAN MODE NORMAL"); + + if ((scanMode_ & STCAM_SCAN_MODE_ROI) != 0) + { + ScanMode.push_back("SCAN MODE ROI"); + SetProperty(g_ScanMode, "SCAN MODE ROI"); + ClearROI(); + } + SetAllowedValues(g_ScanMode, ScanMode); + + + // Image device Size + DWORD imageSizeHorizontal_, imageSizeVertical_; + ans = StCam_GetMaximumImageSize(handle_, &imageSizeHorizontal_, &imageSizeVertical_); + if (!ans) { return ERR_CAMERA_GET_PREVIEWDATASIZE_FAILED; } + ans = StCam_GetPreviewDataSize(handle_, &dwSize_, &imageSizeH_, &imageSizeV_, &dwLinePitch_); + if (!ans) { return ERR_CAMERA_GET_PREVIEWDATASIZE_FAILED; } + + //img_.Resize((unsigned int)imageSizeHorizontal_ / binFac_, (unsigned int)imageSizeVertical_ / binFac_); + + pAct = new CPropertyAction(this, &Camera::OnImageH); + ret = CreateProperty(g_CameraImageDeviceSizeH, to_string(imageSizeH_).c_str(), MM::Float, false, pAct); + if (ret != DEVICE_OK) + return ret; + SetPropertyLimits(g_CameraImageDeviceSizeH, 0, (long)imageSizeHorizontal_); + + pAct = new CPropertyAction(this, &Camera::OnImageV); + ret = CreateProperty(g_CameraImageDeviceSizeV, to_string(imageSizeV_).c_str(), MM::Float, false, pAct); + if (ret != DEVICE_OK) + return ret; + SetPropertyLimits(g_CameraImageDeviceSizeV, 0, (long)imageSizeVertical_); + img_.Resize((unsigned int)imageSizeH_ / binFac_, (unsigned int)imageSizeV_ / binFac_); + + // Before sizing MM 1.4 + /*ans = StCam_GetPreviewDataSize(handle_, &dwSize_, &imageSizeH_, &imageSizeV_, &dwLinePitch_); + if (!ans) { return ERR_CAMERA_GET_PREVIEWDATASIZE_FAILED; } + img_.Resize((unsigned int)imageSizeH_ / binFac_, (unsigned int)imageSizeV_ / binFac_); + + ret = CreateIntegerProperty(g_CameraImageDeviceSizeH, (long)imageSizeH_, true); + if (ret != DEVICE_OK) + return ret; + ret = CreateIntegerProperty(g_CameraImageDeviceSizeV, (long)imageSizeV_, true); + if (ret != DEVICE_OK) + return ret;*/ + + + // Binning chnaged in MM 2.0 + // NOTE: USB2.0 type is valid only full scan ("1"), binning scan can not be used. + // NOTE: Monochrome type or USB3.0 type is available. + vector binValues; + if (productName_ == "STC-MC202USB" || productName_ == "STC-MCCM401U3V") + { + binValues.push_back("1"); + ret = CreateIntegerProperty(MM::g_Keyword_Binning, binFac_, true); + } + else + { + binValues.push_back("1"); + binValues.push_back("2"); + pAct = new CPropertyAction(this, &Camera::OnBinning); + ret = CreateIntegerProperty(MM::g_Keyword_Binning, binFac_, false, pAct); + if (ret != DEVICE_OK) + return ret; + ret = SetAllowedValues(MM::g_Keyword_Binning, binValues); + if (ret != DEVICE_OK) + return ret; + } + + // Target brightness + ans = StCam_SetTargetBrightness(handle_, 128, 0, 0); + if (!ans) { return ERR_CAMERA_SET_TARGET_BRIGHTNESS_FAILED; } + + // ALC�iAuto Luminance Control�j mode + pAct = new CPropertyAction(this, &Camera::OnALCMode); + ret = CreateStringProperty(g_CameraALCMode, alcMode_.c_str(), false, pAct); + if (ret != DEVICE_OK) + return ret; + + // Mirror Orientation + pAct = new CPropertyAction(this, &Camera::OnMirrorRotation); + ret = CreateProperty(g_Mirror_Mode, mirrorMode_.c_str(), MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + AddAllowedValue(g_Mirror_Mode, "MIRROR OFF"); + AddAllowedValue(g_Mirror_Mode, "MIRROR HORIZONTAL"); + AddAllowedValue(g_Mirror_Mode, "MIRROR VERTICAL"); + AddAllowedValue(g_Mirror_Mode, "MIRROR HORIZONTAL VERTICAL"); + + vector alcmode; + alcmode.push_back(g_ALCMode_FS_MG); + alcmode.push_back(g_ALCMode_AS_AGC); + alcmode.push_back(g_ALCMode_AS_MG); + alcmode.push_back(g_ALCMode_FS_AGC); + + ret = SetAllowedValues(g_CameraALCMode, alcmode); + if (ret != DEVICE_OK) + return ret; + + // Gain Mode (Added in MM 2.0) + pAct = new CPropertyAction(this, &Camera::OnGainMode); + ret = CreateProperty(g_CameraShutterGainMode, gainMode_.c_str(), MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + AddAllowedValue(g_CameraShutterGainMode, "Digital All"); + ans = StCam_GetMaxDigitalGain(handle_, &digitalGainMax_); + ans = StCam_GetDigitalGainSettingValueFromGainTimes(handle_, 1.0F, &digitalGainMin_); + BOOL analogFlag = false; + ans = StCam_HasFunction(handle_, STCAM_CAMERA_FUNCTION_DISABLED_ANALOG_GAIN, &analogFlag); + if (analogFlag == FALSE) + { + AddAllowedValue(g_CameraShutterGainMode, "Analog All"); + ans = StCam_GetMaxGain(handle_, &analogGainMax_); + } + + // Shutter gain + pAct = new CPropertyAction(this, &Camera::OnShutterGain); + ret = CreateProperty(g_CameraShutterGain, to_string(gain_).c_str(),MM::Integer , false, pAct); + if (ret != DEVICE_OK) + return ret; + SetPropertyLimits(g_CameraShutterGain, digitalGainMin_, digitalGainMax_); + + //AutoGain Max and Min + ans = StCam_GetGainControlRange(handle_, &autoGainMin_, &autoGainMax_); + if (!ans) { return ERR_CAMERA_GET_SHUTTER_GAIN_CONTROL_RANGE_FAILED; } + + pAct = new CPropertyAction(this, &Camera::OnAutoGainMax); + ret = CreateProperty(g_CameraShutterGainAutoMax, to_string(autoGainMax_).c_str(),MM::Integer, false, pAct); + if (ret != DEVICE_OK) + return ret; + SetPropertyLimits(g_CameraShutterGainAutoMax, 0, 255); + + pAct = new CPropertyAction(this, &Camera::OnAutoGainMin); + ret = CreateProperty(g_CameraShutterGainAutoMin, to_string(autoGainMin_).c_str(),MM::Integer, false, pAct); + if (ret != DEVICE_OK) + return ret; + SetPropertyLimits(g_CameraShutterGainAutoMin, 0, 255); + + if (productName_ == "STC-MC202USB") + { + // Clock speed (USB2.0 only) + pAct = new CPropertyAction(this, &Camera::OnClockSpeed); + ret = CreateStringProperty(g_CameraClockSpeed, g_ClockSpeed_Reference, false, pAct); + if (ret != DEVICE_OK) + return ret; + + vector clockType; + clockType.push_back(g_ClockSpeed_Reference); + clockType.push_back(g_ClockSpeed_Div2); + clockType.push_back(g_ClockSpeed_Div4); + + ret = SetAllowedValues(g_CameraClockSpeed, clockType); + if (ret != DEVICE_OK) + return ret; + } + + // FPS + ans = StCam_GetOutputFPS(handle_, &fps_); + if (!ans) { return ERR_CAMERA_GET_FPS_FAILED; } + + char s[256] = { '\0' }; + sprintf(s, "%.*f", 2, fps_); + + ret = CreateStringProperty(g_CameraFPS, s, false); + if (ret != DEVICE_OK) + return ret; + + AddAllowedValue(g_CameraFPS, s); + + // Exposure time (msec) + ans = StCam_GetMaxShortExposureClock(handle_, &exposureMaxClock_); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + FLOAT value = 0.0; + ans = StCam_GetExposureTimeFromClock(handle_, exposureMaxClock_, &value); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + exposureMaxMsec_ = (double)value * 1000; + + if (enabledROI_) + { + // USB3.0 type + exposureMinMsec_ = 0.032; + } + else + { + // USB2.0 type + if (clockMode_ == g_ClockSpeed_Reference) + { + exposureMinMsec_ = 0.000027; + } + else if (clockMode_ == g_ClockSpeed_Div2 || clockMode_ == g_ClockSpeed_Div4) + { + exposureMinMsec_ = 0.0; + } + } + + pAct = new CPropertyAction(this, &Camera::OnExposure); + ret = CreateFloatProperty(g_CameraExposure, exposureMaxMsec_, false, pAct); + if (ret != DEVICE_OK) + return ret; + + SetPropertyLimits(g_CameraExposure, exposureMinMsec_, exposureMaxMsec_); + + // White Balance + if (!isMonochrome_) + { + // White balance mode�icolor type only�j + pAct = new CPropertyAction(this, &Camera::OnWhiteBalanceMode); + ret = CreateStringProperty(g_CameraWBMode, wbMode_.c_str(), false, pAct); + if (ret != DEVICE_OK) + return ret; + + vector mode; + mode.push_back(g_WB_Mode_Off); + mode.push_back(g_WB_Mode_Auto); + mode.push_back(g_WB_Mode_Manual); + mode.push_back(g_WB_Mode_OneShot); + + ret = SetAllowedValues(g_CameraWBMode, mode); + if (ret != DEVICE_OK) + return ret; + + // Get white balance gain + ans = StCam_GetWhiteBalanceGain(handle_, &wbGainR_, &wbGainGr_, &wbGainGb_, &wbGainB_); + if (!ans) { return ERR_CAMERA_GET_WB_GAIN_FAILED; } + + // White Balance Gain R + pAct = new CPropertyAction(this, &Camera::OnWBGainR); + ret = CreateIntegerProperty(g_CameraWBGainR, wbGainR_, false, pAct); + if (ret != DEVICE_OK) + return ret; + + SetPropertyLimits(g_CameraWBGainR, 128, 640); + + // White Balance Gain Gr + pAct = new CPropertyAction(this, &Camera::OnWBGainGr); + ret = CreateIntegerProperty(g_CameraWBGainGr, wbGainGr_, false, pAct); + if (ret != DEVICE_OK) + return ret; + + SetPropertyLimits(g_CameraWBGainGr, 128, 640); + + // White Balance Gain Gb + pAct = new CPropertyAction(this, &Camera::OnWBGainGb); + ret = CreateIntegerProperty(g_CameraWBGainGb, wbGainGb_, false, pAct); + if (ret != DEVICE_OK) + return ret; + + SetPropertyLimits(g_CameraWBGainGb, 128, 640); + + // White Balance Gain B + pAct = new CPropertyAction(this, &Camera::OnWBGainB); + ret = CreateIntegerProperty(g_CameraWBGainB, wbGainB_, false, pAct); + if (ret != DEVICE_OK) + return ret; + + SetPropertyLimits(g_CameraWBGainB, 128, 640); + } + + // readout time + pAct = new CPropertyAction(this, &Camera::OnReadoutTime); + ret = CreateFloatProperty(MM::g_Keyword_ReadoutTime, 0, false, pAct); + if (ret != DEVICE_OK) + return ret; + + + // {synchronize all properties + ret = UpdateStatus(); + if (ret != DEVICE_OK) + return ret; + + // setup the buffer + ret = ResizeImageBuffer(); + if (ret != DEVICE_OK) + return ret; + + + initialized_ = true; + + return DEVICE_OK; +} + +/** +* Shuts down (unloads) the device. +* Required by the MM::Device API. +* Ideally this method will completely unload the device and release all resources. +* Shutdown() may be called multiple times in a row. +* After Shutdown() we should be allowed to call Initialize() again to load the device +* without causing problems. +*/ +int Camera::Shutdown() +{ + StCam_Close(handle_); + + initialized_ = false; + + return DEVICE_OK; +} + +/** +* Performs exposure and grabs a single image. +* +* SnapImage should start the image exposure in the camera and block until +* the exposure is finished. It should not wait for read-out and transfer of data. +* Return DEVICE_OK on succes, error code otherwise. +* +* This function should block during the actual exposure and return immediately afterwards +* (i.e., before readout). This behavior is needed for proper synchronization with the shutter. +* +* Required by the MM::Camera API. +*/ +int Camera::SnapImage() +{ + //Delay + MMThreadGuard g(imgPixelsLock_); + MM::MMTime start = GetCurrentMMTime(); + MM::TimeoutMs tout(start, delayMsec_); + while (!tout.expired(GetCurrentMMTime())) {} + + ResizeImageBuffer(); + //Allocate Memory + PBYTE imgBuff = (PBYTE) new BYTE[GetImageBufferSize()]; + + cout << "Before StCam_TakePreviewSnapShot " << img_.Height() << "X" << img_.Width() << endl; + //Take Snap Shot + BOOL ans = TRUE; + DWORD dwNumberOfByteTrans, dwFrameNo; + DWORD dwMilliseconds = 1000; + ans = StCam_TakePreviewSnapShot(handle_, imgBuff, GetImageBufferSize(), &dwNumberOfByteTrans, &dwFrameNo, dwMilliseconds); + cout << "last error " << ans << endl; + if (!ans) { return ERR_CAMERA_SNAPSHOT_FAILED; } + cout << "Before memcpy imageSizeH_ X imageSizeV_ " << imageSizeH_ << "X" << imageSizeV_ << endl; + cout << "Before memcpy img_.Width() X img_.Height() " << img_.Width() << "X" << img_.Height() << endl; + memcpy(img_.GetPixelsRW(), imgBuff, GetImageBufferSize()); + cout << "after memcpy img_.Width() X img_.Height() " << img_.Width() << "X" << img_.Height() << endl; + + delete[] imgBuff; + + return DEVICE_OK; +} + +/** +* Returns pixel data. +* Required by the MM::Camera API. +* GetImageBuffer will be called shortly after SnapImage returns. +* Use it to wait for camera read-out and transfer of data into memory +* Return a pointer to a buffer containing the image data +* The calling program will assume the size of the buffer based on the values +* obtained from GetImageBufferSize(), which in turn should be consistent with +* values returned by GetImageWidth(), GetImageHight() and GetImageBytesPerPixel(). +* The calling program allso assumes that camera never changes the size of +* the pixel buffer on its own. In other words, the buffer can change only if +* appropriate properties are set (such as binning, pixel type, etc.) +* Multi-Channel cameras should return the content of the first channel in this call. +*/ +const unsigned char* Camera::GetImageBuffer() +{ + MMThreadGuard g(imgPixelsLock_); + MM::MMTime readoutTime(readoutUs_); + while (readoutTime > (GetCurrentMMTime() - readoutStartTime_)) {} + unsigned char *pB = (unsigned char*)(img_.GetPixels()); + + return pB; +} + +//* Returns image buffer X-size in pixels. +//* Required by the MM::Camera API. +//*/ +unsigned Camera::GetImageWidth() const +{ + return img_.Width(); +} + +//* Returns image buffer Y-size in pixels. +//* Required by the MM::Camera API. +//*/ +unsigned Camera::GetImageHeight() const +{ + return img_.Height(); +} + +//* Returns image buffer pixel depth in bytes. +//* Required by the MM::Camera API. +//*/ +unsigned Camera::GetImageBytesPerPixel() const +{ + return img_.Depth(); +} + +//* Returns the bit depth (dynamic range) of the pixel. +//* This does not affect the buffer size, it just gives the client application +//* a guideline on how to interpret pixel values. +//* Required by the MM::Camera API. +//*/ +unsigned Camera::GetBitDepth() const +{ + return bitDepth_; +} + +///** +//* Returns the size in bytes of the image buffer. +//* Required by the MM::Camera API. +//*/ +long Camera::GetImageBufferSize() const +{ + return img_.Width() * img_.Height() * GetImageBytesPerPixel(); +} + +///** +//* Sets the camera Region Of Interest. +//* Required by the MM::Camera API. +//* This command will change the dimensions of the image. +//* Depending on the hardware capabilities the camera may not be able to configure the +//* exact dimensions requested - but should try do as close as possible. +//* If the hardware does not have this capability the software should simulate the ROI by +//* appropriately cropping each frame. +//* This demo implementation ignores the position coordinates and just crops the buffer. +//* @param x - top-left corner coordinate +//* @param y - top-left corner coordinate +//* @param xSize - width +//* @param ySize - height +//*/ +int Camera::SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) +{ + BOOL ans = TRUE; + + + if (scanModeType_ == "SCAN MODE NORMAL") + { + DWORD imageSizeHorizontal_, imageSizeVertical_; + ans = StCam_GetMaximumImageSize(handle_, &imageSizeHorizontal_, &imageSizeVertical_); + imageSizeH_ = imageSizeHorizontal_ / binFac_; + imageSizeV_ = imageSizeVertical_ / binFac_; + ResizeImageBuffer(); + return DEVICE_OK; + } + + ans = StCam_StopTransfer(handle_); + if (!ans) { return ERR_CAMERA_STOP_TRANSFER_FAILED; } + + + + if (xSize == 0 && ySize == 0) + { + + cout << "Effectivelly Clear ROI =" << imageSizeH_ << " X " << imageSizeV_ << endl; + // effectively clear ROI + ResizeImageBuffer(); + roiX_ = 0; + roiY_ = 0; + } + else + { + cout << "apply ROI xoffset and yoffset beofre =" << x << "X" << y << endl; + cout << "apply ROI RoiX_ and RoiY_ =" << roiX_ << "X" << roiY_ << endl; + + unsigned x1= x; unsigned y1=y; + + if (binFac_ == 2) + { + x1 = x* binFac_; + y1 = y *binFac_; + } + DWORD /*size_x, size_y, */offset_x, offset_y; WORD mode = 0; + ans = StCam_SetImageSize(handle_, 0, STCAM_SCAN_MODE_ROI, x1, y1 , xSize , ySize); + if (!ans) { return ERR_CAMERA_SET_ROI_FAILED; } + + ans = StCam_GetImageSize(handle_, nullptr, &mode, &offset_x, &offset_y, &/*size_x*/imageSizeH_, &/*size_y*/imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + + // apply ROI + img_.Resize(imageSizeH_ , imageSizeV_); + roiX_ = x; + roiY_ = y; + cout << "apply ROI imageSizeH_ imageSizeV_ =" << imageSizeH_ << "X" << imageSizeV_ << endl; + + } + ans = StCam_StartTransfer(handle_); + if (!ans) { return ERR_CAMERA_START_TRANSFER_FAILED; } + + return DEVICE_OK; +} + +///** +//* Returns the actual dimensions of the current ROI. +//* Required by the MM::Camera API. +//*/ +int Camera::GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize) +{ + x = roiX_; + y = roiY_; + + xSize = img_.Width(); + ySize = img_.Height(); + + cout << "Get ROI =" << img_.Width() << "X" << img_.Height() << endl; + cout << "Get ROI offset =" << roiX_ << "X" << roiY_ << endl; + + return DEVICE_OK; +} + +///** +//* Resets the Region of Interest to full frame. +//* Required by the MM::Camera API. +//*/ +int Camera::ClearROI() +{ + if (scanModeType_ == "SCAN MODE NORMAL") + return ERR_CAMERA_SCAN_MODE_PROHIBTED; // error for cameras that not support Roi settings + + BOOL ans = TRUE; + ans = StCam_StopTransfer(handle_); + if (!ans) { return ERR_CAMERA_STOP_TRANSFER_FAILED; } + DWORD imageSizeHorizontal_, imageSizeVertical_; + ans = StCam_GetMaximumImageSize(handle_, &imageSizeHorizontal_, &imageSizeVertical_); // Size of Camera with binning = 1 + if (!ans) { return ERR_CAMERA_GET_PREVIEWDATASIZE_FAILED; } + + ans = StCam_SetImageSize(handle_, STCAM_IMAGE_SIZE_MODE_UXGA, STCAM_SCAN_MODE_ROI, 0, 0, imageSizeHorizontal_/binFac_, imageSizeVertical_/binFac_); + if (!ans) { return ERR_CAMERA_SET_ROI_FAILED; } + + imageSizeH_ = imageSizeHorizontal_/ binFac_; + imageSizeV_ = imageSizeVertical_/binFac_; + + cout << "BinFac_ check =" << binFac_ << endl; + cout << "Clear ROI max size =" << imageSizeHorizontal_ << "X" << imageSizeVertical_ << endl; + cout << "Clear ROI img_ size =" << imageSizeH_ << "X" << imageSizeV_ << endl; + ResizeImageBuffer(); + roiX_ = 0; + roiY_ = 0; + + ans = StCam_StartTransfer(handle_); + if (!ans) { return ERR_CAMERA_START_TRANSFER_FAILED; } + return DEVICE_OK; +} + +/** +* Sets exposure in milliseconds through presetting +* Required by the MM::Camera API. +*/ +void Camera::SetExposure(double exp) +{ + SetProperty(g_CameraExposure, CDeviceUtils::ConvertToString(exp)); + GetCoreCallback()->OnExposureChanged(this, exp);; +} + +/** +* Returns the current exposure setting in milliseconds through presetting. +* Required by the MM::Camera API. +*/ +double Camera::GetExposure() const +{ + char buf[MM::MaxStrLength]; + int ret = GetProperty(g_CameraExposure, buf); + if (ret != DEVICE_OK) + return 0.0; + return atof(buf); +} + +/** +* Returns the current binning factor through presetting. +* Required by the MM::Camera API. +*/ +int Camera::GetBinning() const +{ + char buf[MM::MaxStrLength]; + int ret = GetProperty(MM::g_Keyword_Binning, buf); + if (ret != DEVICE_OK) + return 1; + return atoi(buf); +} + +/** +* Sets binning factor through presetting. +* Required by the MM::Camera API. +*/ +int Camera::SetBinning(int binF) +{ + return SetProperty(MM::g_Keyword_Binning, CDeviceUtils::ConvertToString(binF)); +} + +int Camera::IsExposureSequenceable(bool& isSequenceable) const +{ + isSequenceable = isSequenceable_; + return DEVICE_OK; +} + +/** +* Required by the MM::Camera API +* Please implement this yourself and do not rely on the base class implementation +* The Base class implementation is deprecated and will be removed shortly +*/ +int Camera::StartSequenceAcquisition(double interval) +{ + return StartSequenceAcquisition(LONG_MAX, interval, false); +} + +/** +* Stop and wait for the Sequence thread finished +*/ +int Camera::StopSequenceAcquisition() +{ + + BOOL ans = TRUE; + ans = StCam_StopTransfer(handle_); + if (!ans) { return ERR_CAMERA_STOP_TRANSFER_FAILED; } + + cout << "Stop Transfer = " << ans << endl; + if (!thd_->IsStopped()) { + cout << "Thd entred = " << ans << endl; + thd_->Stop(); + thd_->wait(); + } + + return DEVICE_OK; +} + +/** +* Simple implementation of Sequence Acquisition +* A sequence acquisition should run on its own thread and transport new images +* coming of the camera into the MMCore circular buffer. +*/ +int Camera::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) +{ + if (IsCapturing()) + return DEVICE_CAMERA_BUSY_ACQUIRING; + + int ret = GetCoreCallback()->PrepareForAcq(this); + if (ret != DEVICE_OK) + return ret; + sequenceStartTime_ = GetCurrentMMTime(); + imageCounter_ = 0; + + BOOL ans = TRUE; + ans = StCam_StartTransfer(handle_); + if (!ans) { return ERR_CAMERA_START_TRANSFER_FAILED; } + + + cout << "interval = " << interval_ms << endl; + thd_->Start(numImages, interval_ms); + stopOnOverflow_ = stopOnOverflow; + + return DEVICE_OK; +} + +/* +* Inserts Image and MetaData into MMCore circular Buffer +*/ +int Camera::InsertImage() +{ + MM::MMTime timeStamp = this->GetCurrentMMTime(); + char label[MM::MaxStrLength]; + this->GetLabel(label); + + // Important: metadata about the image are generated here: + Metadata md; + md.put("Camera", label); + md.put(MM::g_Keyword_Metadata_StartTime, CDeviceUtils::ConvertToString(sequenceStartTime_.getMsec())); + md.put(MM::g_Keyword_Elapsed_Time_ms, CDeviceUtils::ConvertToString((timeStamp - sequenceStartTime_).getMsec())); + md.put(MM::g_Keyword_Metadata_ImageNumber, CDeviceUtils::ConvertToString(imageCounter_)); + + imageCounter_++; + + MMThreadGuard g(imgPixelsLock_); + + const unsigned char* pI; + pI = GetImageBuffer(); // img.pixels + + unsigned int w = GetImageWidth(); + unsigned int h = GetImageHeight(); + unsigned int b = GetImageBytesPerPixel(); + cout << "bytes per pixel = " << b << endl; + int ret = GetCoreCallback()->InsertImage(this, pI, w, h, b, md.Serialize().c_str()); + + if (!stopOnOverflow_ && ret == DEVICE_BUFFER_OVERFLOW) + { + // do not stop on overflow - just reset the buffer + GetCoreCallback()->ClearImageBuffer(this); + // don't process this same image again... + cout << "Stop On overflow = " << stopOnOverflow_ << endl; + return GetCoreCallback()->InsertImage(this, pI, w, h, b, md.Serialize().c_str()); + } + else + { + return ret; + } +} + +/* +* Do actual capturing +* Called from inside the thread +*/ +int Camera::ThreadRun(void) +{ + int ret = SnapImage(); + if (ret != DEVICE_OK) + return ERR_CAMERA_LIVE_STOP_UNKNOWN; + + /*ResizeImageBuffer(); + PBYTE imgBuff = (PBYTE) new BYTE[GetImageBufferSize()]; + BOOL ans = TRUE; + DWORD dwNumberOfByteTrans, dwFrameNo; + DWORD dwMilliseconds = 1000; + ans = StCam_TakePreviewSnapShot(handle_, imgBuff, GetImageBufferSize(), &dwNumberOfByteTrans, &dwFrameNo, dwMilliseconds); + if (!ans) { return ERR_CAMERA_SNAPSHOT_FAILED; } + + memcpy(img_.GetPixelsRW(), imgBuff, GetImageBufferSize()); + + delete[] imgBuff;*/ + cout << " inserting " << imageCounter_ << endl; + ret = InsertImage(); + cout << " inserting finish " << imageCounter_ << endl; + if (ret != DEVICE_OK) + return ERR_CAMERA_LIVE_STOP_UNKNOWN; + + + + return ret; +} + +bool Camera::IsCapturing() { + return !thd_->IsStopped(); +} + +/* +* called from the thread function before exit +*/ +void Camera::OnThreadExiting() throw() +{ + try + { + LogMessage(g_Msg_SEQUENCE_ACQUISITION_THREAD_EXITING); + GetCoreCallback() ? GetCoreCallback()->AcqFinished(this, 0) : DEVICE_OK; + } + catch (...) + { + LogMessage(g_Msg_EXCEPTION_IN_ON_THREAD_EXITING, false); + } +} + +MySequenceThread::MySequenceThread(Camera* pCam) + :intervalMs_(default_intervalMS) + , numImages_(default_numImages) + , imageCounter_(0) + , stop_(true) + , suspend_(false) + , camera_(pCam) + , startTime_(0) + , actualDuration_(0) + , lastFrameTime_(0) +{}; + +MySequenceThread::~MySequenceThread() {}; + +void MySequenceThread::Stop() { + MMThreadGuard(this->stopLock_); + stop_ = true; +} + +void MySequenceThread::Start(long numImages, double intervalMs) +{ + MMThreadGuard(this->stopLock_); + MMThreadGuard(this->suspendLock_); + numImages_ = numImages; + intervalMs_ = intervalMs; + imageCounter_ = 0; + stop_ = false; + suspend_ = false; + activate(); + actualDuration_ = 0; + startTime_ = camera_->GetCurrentMMTime(); + lastFrameTime_ = 0; +} + +bool MySequenceThread::IsStopped() { + MMThreadGuard(this->stopLock_); + return stop_; +} + +void MySequenceThread::Suspend() { + MMThreadGuard(this->suspendLock_); + suspend_ = true; +} + +bool MySequenceThread::IsSuspended() { + MMThreadGuard(this->suspendLock_); + return suspend_; +} + +void MySequenceThread::Resume() { + MMThreadGuard(this->suspendLock_); + suspend_ = false; +} + +int MySequenceThread::svc(void) throw() +{ + int ret = DEVICE_ERR; + try + { + do + { + ret = camera_->ThreadRun(); + + camera_->LogMessage("Inside try, the result is = " + to_string(ret), false); + camera_->LogMessage(" numImages is = " + to_string(numImages_), false); + camera_->LogMessage(" numCounter is = " + to_string(imageCounter_++), false); + } while (DEVICE_OK == ret && !IsStopped() && imageCounter_++ < numImages_ - 1); + if (IsStopped()) + camera_->LogMessage("SeqAcquisition interrupted by the user\n"); + } + catch (...) { + camera_->LogMessage(g_Msg_EXCEPTION_IN_THREAD, false); + } + stop_ = true; + actualDuration_ = camera_->GetCurrentMMTime() - startTime_; + camera_->OnThreadExiting(); + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +// Private Camera methods +/////////////////////////////////////////////////////////////////////////////// +/** +* Sync internal image buffer size to the chosen property values. +*/ +int Camera::ResizeImageBuffer() +{ + char buf[MM::MaxStrLength]; + + int ret = GetProperty(MM::g_Keyword_PixelType, buf); + if (ret != DEVICE_OK) + return ret; + + std::string pixelType(buf); + + if (pixelType.compare(g_PixelType_8bitMONO) == 0) + { + nComponents_ = 1; + } + else if (pixelType.compare(g_PixelType_32bitBGR) == 0) + { + nComponents_ = 4; + } + + img_.Resize((unsigned int)imageSizeH_ , (unsigned int)imageSizeV_ , nComponents_); + + return DEVICE_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// Action handlers +/////////////////////////////////////////////////////////////////////////////// + +/** +* Handles "Binning" property. +*/ +int Camera::OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + BOOL ans = TRUE; + WORD mode = 0; + byte skippH, skippV, hBin, vBin; + + cout << "Product is " << productName_ << endl; + + if (eAct == MM::BeforeGet) + { + ans = StCam_GetSkippingAndBinning(handle_, &skippH, &skippV, &hBin, &vBin); + if (!ans) { return ERR_CAMERA_GET_BINNING_SCAN_MODE_FAILED; } + binFac_ = long(skippH); + + + if (productName_ == "STC-MCA5MUSB3") // Set and get binning for this camera is different than the others (ご注意) + binFac_ += 1; + // + cout << "Get Skipp and Bin = " << (long)skippH << " / " << (long)skippV << " / " << (long)hBin << " / " << (long)vBin << endl; + pProp->Set(binFac_); + } + else if (eAct == MM::AfterSet) + { + if (IsCapturing()) + return DEVICE_CAMERA_BUSY_ACQUIRING; + + if (scanModeType_ == "SCAN MODE NORMAL") + return ERR_CAMERA_SCAN_MODE_PROHIBTED; + pProp->Get(binFac_); + if (productName_ == "STC-MCA5MUSB3") // Set and get binning for this camera is different than the others (ご注意) [カメラ CSマウント] + { + if (binFac_ == 1) + {ans = StCam_SetSkippingAndBinning(handle_, 0, 0, 0, 0);} + else + ans = StCam_SetSkippingAndBinning(handle_, 1, 1, 0, 0); + } + else + { + if (binFac_ == 1) + {ans = StCam_SetSkippingAndBinning(handle_, 1, 1, 1, 1);} + else + ans = StCam_SetSkippingAndBinning(handle_, 2, 2, 1, 1); + } + + + if (!ans) { return ERR_CAMERA_SET_BINNING_SCAN_MODE_FAILED; } + + + } + if (scanModeType_ == "SCAN MODE NORMAL") + { + mode = STCAM_SCAN_MODE_NORMAL; + } + else + mode = STCAM_SCAN_MODE_ROI; + + DWORD /*size_x, size_y, */offset_x, offset_y; + ans = StCam_GetImageSize(handle_, nullptr, &mode, &offset_x, &offset_y, &/*size_x*/imageSizeH_, &/*size_y*/imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + ResizeImageBuffer(); + cout << "After Set Binning offsetx and y " << offset_x << "X" << offset_y << endl; + cout << "After Set Binning img_ size " << img_.Height() << "X" << img_.Width() << endl; + return DEVICE_OK; +} + +/** +* Handles "ReadoutTime" property. +*/ +int Camera::OnReadoutTime(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + double readoutMs; + pProp->Get(readoutMs); + + readoutUs_ = readoutMs * 1000.0; + } + else if (eAct == MM::BeforeGet) + { + pProp->Set(readoutUs_ / 1000.0); + } + + return DEVICE_OK; +} + +/** +* Handles "ALC_Mode" property. ALC = Auto Luminance Control +*/ +int Camera::OnALCMode(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + BOOL ans = TRUE; + BYTE mode = 0; + if (eAct == MM::BeforeGet) + { + ans = StCam_GetALCMode(handle_, &mode); + if (!ans) { return ERR_CAMERA_GET_ALCMODE_FAILED; } + + switch (mode) + { + case STCAM_ALCMODE_FIXED_SHUTTER_AGC_OFF: + alcMode_ = g_ALCMode_FS_MG; + break; + case STCAM_ALCMODE_AUTO_SHUTTER_ON_AGC_ON: + alcMode_ = g_ALCMode_AS_AGC; + break; + case STCAM_ALCMODE_AUTO_SHUTTER_ON_AGC_OFF: + alcMode_ = g_ALCMode_AS_MG; + break; + case STCAM_ALCMODE_FIXED_SHUTTER_AGC_ON: + alcMode_ = g_ALCMode_FS_AGC; + break; + default: + ans = StCam_SetALCMode(handle_, STCAM_ALCMODE_FIXED_SHUTTER_AGC_OFF); + if (!ans) { return ERR_CAMERA_SET_ALCMODE_FAILED; } + alcMode_ = g_ALCMode_FS_MG; + break; + } + + pProp->Set(alcMode_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(alcMode_); + + if (alcMode_ == g_ALCMode_FS_MG) + { + mode = STCAM_ALCMODE_FIXED_SHUTTER_AGC_OFF; + } + else if (alcMode_ == g_ALCMode_AS_AGC) + { + mode = STCAM_ALCMODE_AUTO_SHUTTER_ON_AGC_ON; + } + else if (alcMode_ == g_ALCMode_AS_MG) + { + mode = STCAM_ALCMODE_AUTO_SHUTTER_ON_AGC_OFF; + } + else if (alcMode_ == g_ALCMode_FS_AGC) + { + mode = STCAM_ALCMODE_FIXED_SHUTTER_AGC_ON; + } + ans = StCam_SetALCMode(handle_, mode); + if (!ans) { return ERR_CAMERA_SET_ALCMODE_FAILED; } + + // Re-acquisition of the shutter gain + if (alcMode_ == g_ALCMode_FS_MG || alcMode_ == g_ALCMode_AS_MG) + { + if (gainMode_ == "Analog All") + { + ans = StCam_GetGain(handle_, &gain_); + if (!ans) { return ERR_CAMERA_GET_SHUTTER_GAIN_FAILED; } + } + else + { + ans = StCam_GetDigitalGain(handle_, &gain_); + if (!ans) { return ERR_CAMERA_GET_SHUTTER_GAIN_FAILED; } + } + + SetProperty(g_CameraShutterGain, CDeviceUtils::ConvertToString(gain_)); + } + + // Re-acquisition of the exposure time + if (alcMode_ == g_ALCMode_FS_MG || alcMode_ == g_ALCMode_FS_AGC) + { + ans = StCam_GetExposureClock(handle_, &exposureClock_); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + FLOAT value; + ans = StCam_GetExposureTimeFromClock(handle_, (DWORD)exposureClock_, &value); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + exposureMsec_ = value * 1000; + + SetProperty(g_CameraExposure, CDeviceUtils::ConvertToString(exposureMsec_)); + } + } + return DEVICE_OK; +} + +// Gain mode added in MM2.0 +int Camera::OnGainMode(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(gainMode_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(gainMode_); + } + + return DEVICE_OK; +} + +/* +* Handles "ShutterGain" property. different from 1.4 [can set both Gain (Digital and Analog)] +*/ +int Camera::OnShutterGain(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + BOOL ans = TRUE; + if (eAct == MM::BeforeGet) + { + if (gainMode_ == "Digital All") + { + ans = StCam_GetDigitalGain(handle_, &gain_);//-->> for USB3, USB2? + SetPropertyLimits(g_CameraShutterGain, digitalGainMin_, digitalGainMax_); + } + else + { + ans = StCam_GetGain(handle_, &gain_);//-->>for USB2 + SetPropertyLimits(g_CameraShutterGain, 0, analogGainMax_); + } + if (!ans) { return ERR_CAMERA_GET_SHUTTER_GAIN_FAILED; } + + pProp->Set((long)gain_); + } + else if (eAct == MM::AfterSet) + { + long value; + pProp->Get(value); + gain_ = (WORD)value; + + if (gainMode_ == "Analog All") + { + if (alcMode_ == g_ALCMode_AS_AGC || alcMode_ == g_ALCMode_FS_AGC) + { + return ERR_CAMERA_ALCMODE_UNAVAILABLE_FUNCTION; + } + ans = StCam_SetGain(handle_, gain_); + SetPropertyLimits(g_CameraShutterGain, 0, analogGainMax_); + } + else if (gainMode_ == "Digital All") + { + ans = StCam_SetDigitalGain(handle_, gain_); + SetPropertyLimits(g_CameraShutterGain, digitalGainMin_, digitalGainMax_); + } + + if (!ans) { return ERR_CAMERA_SET_SHUTTER_GAIN_FAILED; } + } + return DEVICE_OK; +} + +// Auto Gain Max Ana Min added in MM 2.0 +int Camera::OnAutoGainMax(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((double)autoGainMax_); + } + else if (eAct == MM::AfterSet) + { + if (alcMode_ == g_ALCMode_FS_MG || alcMode_ == g_ALCMode_AS_MG) + { + return ERR_CAMERA_ALCMODE_UNAVAILABLE_FUNCTION; + } + + double t; + pProp->Get(t); + + autoGainMax_ = t; + if (autoGainMax_ < autoGainMin_) + { + autoGainMax_ = autoGainMin_; + } + + StCam_SetGainControlRange(handle_, autoGainMin_, autoGainMax_); + } + return DEVICE_OK; +} + +// Auto Gain Max Ana Min added in MM 2.0 +int Camera::OnAutoGainMin(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((double)autoGainMin_); + } + else if (eAct == MM::AfterSet) + { + if (alcMode_ == g_ALCMode_FS_MG || alcMode_ == g_ALCMode_AS_MG) + { + return ERR_CAMERA_ALCMODE_UNAVAILABLE_FUNCTION; + } + double t; + pProp->Get(t); + + autoGainMin_ = t; + if (autoGainMin_ > autoGainMax_) + { + autoGainMin_ = autoGainMax_; + } + + StCam_SetGainControlRange(handle_, autoGainMin_, autoGainMax_); + } + + + return DEVICE_OK; +} + +/** +* Handles "Exposure(msec)" time property. +*/ +int Camera::OnExposure(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + BOOL ans = TRUE; + if (eAct == MM::BeforeGet) + { + ans = StCam_GetExposureClock(handle_, &exposureClock_); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + FLOAT value; + ans = StCam_GetExposureTimeFromClock(handle_, (DWORD)exposureClock_, &value); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + exposureMsec_ = value * 1000; + + pProp->Set(exposureMsec_); + } + else if (eAct == MM::AfterSet) + { + if (alcMode_ == g_ALCMode_AS_AGC || alcMode_ == g_ALCMode_AS_MG) + { + return ERR_CAMERA_ALCMODE_UNAVAILABLE_FUNCTION; + } + + pProp->Get(exposureMsec_); + + FLOAT expTime = (FLOAT)(exposureMsec_ / 1000); + ans = StCam_GetExposureClockFromTime(handle_, expTime, &exposureClock_); + if (!ans) { return ERR_CAMERA_SET_EXPOSURE_TIME_FAILED; } + + ans = StCam_SetExposureClock(handle_, (DWORD)exposureClock_); + if (!ans) { return ERR_CAMERA_SET_EXPOSURE_TIME_FAILED; } + } + return DEVICE_OK; +} + +/** +* Handles "ClockSpeed" property. +*/ +int Camera::OnClockSpeed(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + BOOL ans = TRUE; + DWORD mode = 0; + if (eAct == MM::BeforeGet) + { + ans = StCam_GetClock(handle_, &mode, &clockFreq_); + if (!ans) { return ERR_CAMERA_GET_CLOCK_FAILED; } + + switch (mode) + { + case STCAM_CLOCK_MODE_NORMAL: + clockMode_ = g_ClockSpeed_Reference; + break; + case STCAM_CLOCK_MODE_DIV_2: + clockMode_ = g_ClockSpeed_Div2; + break; + case STCAM_CLOCK_MODE_DIV_4: + clockMode_ = g_ClockSpeed_Div4; + break; + default: + clockMode_ = g_ClockSpeed_Reference; + mode = STCAM_CLOCK_MODE_NORMAL; + ans = StCam_SetClock(handle_, mode, clockFreq_); + if (!ans) { return ERR_CAMERA_SET_CLOCK_FAILED; } + break; + } + pProp->Set(clockMode_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(clockMode_); + + if (clockMode_ == g_ClockSpeed_Reference) + { + mode = STCAM_CLOCK_MODE_NORMAL; + } + else if (clockMode_ == g_ClockSpeed_Div2) + { + mode = STCAM_CLOCK_MODE_DIV_2; + } + else if (clockMode_ == g_ClockSpeed_Div4) + { + mode = STCAM_CLOCK_MODE_DIV_4; + } + + ans = StCam_SetClock(handle_, mode, clockFreq_); + if (!ans) { return ERR_CAMERA_SET_CLOCK_FAILED; } + + // Re-acquisition of FPS + ans = StCam_GetOutputFPS(handle_, &fps_); + if (!ans) { return ERR_CAMERA_GET_FPS_FAILED; } + + ClearAllowedValues(g_CameraFPS); + char s[256] = { '\0' }; + sprintf(s, "%.*f", 2, fps_); + AddAllowedValue(g_CameraFPS, s); + + // Re-setting of the exposure time range. + ans = StCam_GetMaxShortExposureClock(handle_, &exposureMaxClock_); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + FLOAT expSec = 0.0; + ans = StCam_GetExposureTimeFromClock(handle_, exposureMaxClock_, &expSec); + if (!ans) { return ERR_CAMERA_GET_EXPOSURE_TIME_FAILED; } + + exposureMaxMsec_ = (double)expSec * 1000; + + if (enabledROI_) + { + // USB3.0 type + exposureMinMsec_ = 0.032; + } + else + { + // USB2.0 type + if (clockMode_ == g_ClockSpeed_Reference) + { + exposureMinMsec_ = 0.000027; + } + else if (clockMode_ == g_ClockSpeed_Div2 || clockMode_ == g_ClockSpeed_Div4) + { + exposureMinMsec_ = 0.0; + } + } + + SetPropertyLimits(g_CameraExposure, exposureMinMsec_, exposureMaxMsec_); + } + return DEVICE_OK; +} + +/** +* Handles "WhiteBalance_Mode" property. +*/ +int Camera::OnWhiteBalanceMode(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + BOOL ans = TRUE; + BYTE mode = 0; + if (eAct == MM::BeforeGet) + { + ans = StCam_GetWhiteBalanceMode(handle_, &mode); + if (!ans) { return ERR_CAMERA_GET_WB_MODE_FAILED; } + + switch (mode) + { + case STCAM_WB_OFF: + wbMode_ = g_WB_Mode_Off; + break; + case STCAM_WB_MANUAL: + wbMode_ = g_WB_Mode_Manual; + break; + case STCAM_WB_FULLAUTO: + wbMode_ = g_WB_Mode_Auto; + break; + case STCAM_WB_ONESHOT: + wbMode_ = g_WB_Mode_OneShot; + break; + } + + pProp->Set(wbMode_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(wbMode_); + + if (wbMode_ == g_WB_Mode_Off) + { + mode = STCAM_WB_OFF; + } + else if (wbMode_ == g_WB_Mode_Manual) + { + mode = STCAM_WB_MANUAL; + } + else if (wbMode_ == g_WB_Mode_Auto) + { + mode = STCAM_WB_FULLAUTO; + } + else if (wbMode_ == g_WB_Mode_OneShot) + { + mode = STCAM_WB_ONESHOT; + } + ans = StCam_SetWhiteBalanceMode(handle_, mode); + if (!ans) { return ERR_CAMERA_SET_WB_MODE_FAILED; } + + CDeviceUtils::SleepMs(1); + + ans = StCam_GetWhiteBalanceGain(handle_, &wbGainR_, &wbGainGr_, &wbGainGb_, &wbGainB_); + if (!ans) { return ERR_CAMERA_GET_WB_GAIN_FAILED; } + + SetProperty(g_CameraWBGainR, CDeviceUtils::ConvertToString(wbGainR_)); + SetProperty(g_CameraWBGainGr, CDeviceUtils::ConvertToString(wbGainGr_)); + SetProperty(g_CameraWBGainGb, CDeviceUtils::ConvertToString(wbGainGb_)); + SetProperty(g_CameraWBGainB, CDeviceUtils::ConvertToString(wbGainB_)); + } + return DEVICE_OK; +} + +/** +* Handles "WhiteBalance_GainR" property. +*/ +int Camera::OnWBGainR(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((long)wbGainR_); + } + else if (eAct == MM::AfterSet) + { + if (wbMode_ == g_WB_Mode_Off || wbMode_ == g_WB_Mode_OneShot || wbMode_ == g_WB_Mode_Auto) + { + return ERR_CAMERA_WBMODE_UNAVAILABLE_FUNCTION; + } + + long value; + pProp->Get(value); + + wbGainR_ = (WORD)value; + + BOOL ans = TRUE; + ans = StCam_SetWhiteBalanceGain(handle_, wbGainR_, wbGainGr_, wbGainGb_, wbGainB_); + if (!ans) { return ERR_CAMERA_SET_WB_GAIN_FAILED; } + } + return DEVICE_OK; +} + +/** +* Handles "WhiteBalance_GainGr" property. +*/ +int Camera::OnWBGainGr(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((long)wbGainGr_); + } + else if (eAct == MM::AfterSet) + { + if (wbMode_ == g_WB_Mode_Off) + { + return ERR_CAMERA_WBMODE_UNAVAILABLE_FUNCTION; + } + + long value; + pProp->Get(value); + + wbGainGr_ = (WORD)value; + + BOOL ans = TRUE; + ans = StCam_SetWhiteBalanceGain(handle_, wbGainR_, wbGainGr_, wbGainGb_, wbGainB_); + if (!ans) { return ERR_CAMERA_SET_WB_GAIN_FAILED; } + } + return DEVICE_OK; +} + +/** +* Handles "WhiteBalance_GainGb" property. +*/ +int Camera::OnWBGainGb(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((long)wbGainGb_); + } + else if (eAct == MM::AfterSet) + { + if (wbMode_ == g_WB_Mode_Off) + { + return ERR_CAMERA_WBMODE_UNAVAILABLE_FUNCTION; + } + + long value; + pProp->Get(value); + + wbGainGb_ = (WORD)value; + + BOOL ans = TRUE; + ans = StCam_SetWhiteBalanceGain(handle_, wbGainR_, wbGainGr_, wbGainGb_, wbGainB_); + if (!ans) { return ERR_CAMERA_SET_WB_GAIN_FAILED; } + } + return DEVICE_OK; +} +/** +* Handles "WhiteBalance_GainB" property. +*/ +int Camera::OnWBGainB(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((long)wbGainB_); + } + else if (eAct == MM::AfterSet) + { + if (wbMode_ == g_WB_Mode_Off || wbMode_ == g_WB_Mode_OneShot || wbMode_ == g_WB_Mode_Auto) + { + return ERR_CAMERA_WBMODE_UNAVAILABLE_FUNCTION; + } + + long value; + pProp->Get(value); + + wbGainB_ = (WORD)value; + + BOOL ans = TRUE; + ans = StCam_SetWhiteBalanceGain(handle_, wbGainR_, wbGainGr_, wbGainGb_, wbGainB_); + if (!ans) { return ERR_CAMERA_SET_WB_GAIN_FAILED; } + } + return DEVICE_OK; +} + +int Camera::OnIsSequenceable(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + std::string val = "Yes"; + if (eAct == MM::BeforeGet) + { + if (!isSequenceable_) + { + val = "No"; + } + pProp->Set(val.c_str()); + } + else if (eAct == MM::AfterSet) + { + isSequenceable_ = false; + pProp->Get(val); + if (val == "Yes") + { + isSequenceable_ = true; + } + } + + return DEVICE_OK; +} + +// Mirror flip, Added in MM 2.0 +int Camera::OnMirrorRotation(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + BYTE mirrorH; + if (eAct == MM::BeforeGet) + { + StCam_GetMirrorMode(handle_, &mirrorH); + + if (int(mirrorH) == 0) + { + mirrorMode_ = "MIRROR OFF"; + } + else if (int(mirrorH) == 1) + { + mirrorMode_ = "MIRROR HORIZONTAL"; + } + else if (int(mirrorH) == 2) + { + mirrorMode_ = "MIRROR VERTICAL"; + } + else if (int(mirrorH) == 3) + { + mirrorMode_ = "MIRROR HORIZONTAL VERTICAL"; + } + + pProp->Set(mirrorMode_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(mirrorMode_); + + if (mirrorMode_ == "MIRROR OFF") + { + StCam_SetMirrorMode(handle_, 0); + } + else if (mirrorMode_ == "MIRROR HORIZONTAL") + { + StCam_SetMirrorMode(handle_, 1); + } + else if (mirrorMode_ == "MIRROR VERTICAL") + { + StCam_SetMirrorMode(handle_, 2); + } + else if (mirrorMode_ == "MIRROR HORIZONTAL VERTICAL") + { + StCam_SetMirrorMode(handle_, 3); + } + } + + + return DEVICE_OK; +} + +// Scan Mode, added in MM 2.0 {Normal Mode and Roi Mode} +int Camera::OnScanMode(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + bool ans = false; + WORD mode = 0; + if (eAct == MM::BeforeGet) + { + DWORD /*size_x, size_y, */offset_x, offset_y; + ans = StCam_GetImageSize(handle_, nullptr, &mode, &offset_x, &offset_y, &/*size_x*/imageSizeH_, &/*size_y*/imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + + cout << "mode type Before Get " << /*size_x*/imageSizeH_ <<" X "<< /*size_y*/imageSizeV_ << endl; + cout << "mode type Before Get " << mode << endl; + if (mode == STCAM_SCAN_MODE_NORMAL) + { + scanModeType_ = "SCAN MODE NORMAL"; + enabledROI_ = false; + } + else if (mode == STCAM_SCAN_MODE_ROI) + { + scanModeType_ = "SCAN MODE ROI"; + enabledROI_ = true; + } + else + { + scanModeType_ = "SCAN MODE NORMAL"; + enabledROI_ = false; + ans = StCam_SetImageSize(handle_, STCAM_IMAGE_SIZE_MODE_UXGA, STCAM_SCAN_MODE_NORMAL, 0, 0, imageSizeH_, imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + } + + pProp->Set(scanModeType_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(scanModeType_); + cout << "mode type After set " << scanModeType_ << endl; + if (scanModeType_ == "SCAN MODE NORMAL") + { + enabledROI_ = false; + mode = STCAM_SCAN_MODE_NORMAL; + ans = StCam_SetImageSize(handle_, STCAM_IMAGE_SIZE_MODE_UXGA, mode, 0, 0, imageSizeH_, imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + cout << "mode type After set " << mode << endl; + } + if (scanModeType_ == "SCAN MODE ROI") + { + enabledROI_ = true; + mode = STCAM_SCAN_MODE_ROI; + ans = StCam_SetImageSize(handle_, STCAM_IMAGE_SIZE_MODE_UXGA, mode, 0, 0, imageSizeH_, imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + cout << "mode type After set " << mode << endl; + + } + } + + + + return DEVICE_OK; +} + +// OnImage H and OnImage V, Added in MM 2.0, allows camera sizing (works only in Roi Mode) +int Camera::OnImageH(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + bool ans = false; + WORD mode = 0; + if (eAct == MM::BeforeGet) + { + + DWORD size_x, size_y, offset_x, offset_y; + mode = STCAM_SCAN_MODE_ROI; + ans = StCam_GetImageSize(handle_, nullptr, &mode, &offset_x, &offset_y, &size_x, &size_y); + + imageSizeH_ = size_x; + pProp->Set((long)imageSizeH_); + } + else if (eAct == MM::AfterSet) + { + if (IsCapturing()) + return DEVICE_CAMERA_BUSY_ACQUIRING; + if (scanModeType_ == "SCAN MODE NORMAL") + return ERR_CAMERA_SCAN_MODE_PROHIBTED; + double x = 0; + pProp->Get(x); + imageSizeH_ = x; + mode = STCAM_SCAN_MODE_ROI; + ans = StCam_SetImageSize(handle_, 0, mode, 0, 0, imageSizeH_, imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + + + } + return DEVICE_OK; +} + +// OnImage H and OnImage V, Added in MM 2.0, allows camera sizing (works only in Roi Mode) +int Camera::OnImageV(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + bool ans = false; + WORD mode = 0; + if (eAct == MM::BeforeGet) + { + + DWORD size_x, size_y, offset_x, offset_y; + mode = STCAM_SCAN_MODE_ROI; + ans = StCam_GetImageSize(handle_, nullptr, &mode, &offset_x, &offset_y, &size_x, &size_y); + + imageSizeV_ = size_y; + pProp->Set((long)imageSizeV_); + } + else if (eAct == MM::AfterSet) + { + if (IsCapturing()) + return DEVICE_CAMERA_BUSY_ACQUIRING; + if (scanModeType_ == "SCAN MODE NORMAL") + return ERR_CAMERA_SCAN_MODE_PROHIBTED; + double y = 0; + pProp->Get(y); + imageSizeV_ = y; + mode = STCAM_SCAN_MODE_ROI; + ans = StCam_SetImageSize(handle_, 0, mode, 0, 0, imageSizeH_, imageSizeV_); + if (!ans) { return ERR_CAMERA_SCAN_MODE_FAILED_SETTING; } + } + return DEVICE_OK; +} diff --git a/DeviceAdapters/SigmaKoki/Camera.h b/DeviceAdapters/SigmaKoki/Camera.h new file mode 100644 index 000000000..cc40a655a --- /dev/null +++ b/DeviceAdapters/SigmaKoki/Camera.h @@ -0,0 +1,213 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: Camera2.h +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#pragma once +#pragma region Prehead_Inclus +#include "SigmaBase.h" +#include +#include +#include +#include +using namespace std; +extern const char* g_CameraDeviceName; +#pragma endregion Prehead_Inclus + +#pragma region Camera_Err_MSG +#define ERR_CAMERA_OPEN_FAILED 10401 +#define ERR_CAMERA_GET_PREVIEWDATASIZE_FAILED 10402 +#define ERR_CAMERA_SET_PIXELFORMAT_FAILED 10403 +#define ERR_CAMERA_SET_TARGET_BRIGHTNESS_FAILED 10404 +#define ERR_CAMERA_GET_SHUTTER_GAIN_CONTROL_RANGE_FAILED 10405 +#define ERR_CAMERA_SET_ALCMODE_FAILED 10406 +#define ERR_CAMERA_GET_ALCMODE_FAILED 10407 +#define ERR_CAMERA_SET_SHUTTER_GAIN_FAILED 10408 +#define ERR_CAMERA_GET_SHUTTER_GAIN_FAILED 10409 +#define ERR_CAMERA_GET_EXPOSURE_TIME_FAILED 10410 +#define ERR_CAMERA_SET_EXPOSURE_TIME_FAILED 10411 +#define ERR_CAMERA_GET_CLOCK_FAILED 10412 +#define ERR_CAMERA_SET_CLOCK_FAILED 10413 +#define ERR_CAMERA_GET_FPS_FAILED 10414 +#define ERR_CAMERA_START_TRANSFER_FAILED 10415 +#define ERR_CAMERA_STOP_TRANSFER_FAILED 10416 +#define ERR_CAMERA_SNAPSHOT_FAILED 10417 +#define ERR_CAMERA_LIVE_STOP_UNKNOWN 10418 +#define ERR_CAMERA_GET_PRODUCT_NAME_FAILED 10419 +#define ERR_CAMERA_SET_BINNING_SCAN_MODE_FAILED 10420 +#define ERR_CAMERA_GET_BINNING_SCAN_MODE_FAILED 10421 +#define ERR_CAMERA_SET_WB_MODE_FAILED 10422 +#define ERR_CAMERA_GET_WB_MODE_FAILED 10423 +#define ERR_CAMERA_SET_WB_GAIN_FAILED 10424 +#define ERR_CAMERA_GET_WB_GAIN_FAILED 10425 +#define ERR_CAMERA_GET_COLOR_ARRAY_FAILED 10426 +#define ERR_CAMERA_SET_ROI_FAILED 10427 +#define ERR_CAMERA_GET_ROI_COUNT_FAILED 10428 +#define ERR_CAMERA_ALCMODE_UNAVAILABLE_FUNCTION 10429 +#define ERR_CAMERA_WBMODE_UNAVAILABLE_FUNCTION 10430 +#define ERR_CAMERA_SCAN_MODE_FAILED_SETTING 10431 +#define ERR_CAMERA_SCAN_MODE_PROHIBTED 10432 + +#pragma endregion Camera_Err_MSG + +class Camera : public CCameraBase, public SigmaBase +{ +#pragma region Constructor_Des +public: + Camera(); + ~Camera(); +#pragma endregion Constructor_Des + +#pragma region Device_Api + void GetName(char* pszName) const; + int Initialize(); + int Shutdown(); +#pragma endregion Device_Api + +#pragma region Camera_Api + int SnapImage(); + const unsigned char* GetImageBuffer(); + long GetImageBufferSize() const; + unsigned GetImageWidth() const; + unsigned GetImageHeight() const; + unsigned GetImageBytesPerPixel() const; + unsigned GetBitDepth() const; + int GetBinning() const; + int SetBinning(int binSize); + double GetExposure() const; + void SetExposure(double exp_ms); + int GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize); + int SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize); + int ClearROI(); + int PrepareSequenceAcqusition() { return DEVICE_OK; }; + int StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow); + int StartSequenceAcquisition(double interval_ms); + int StopSequenceAcquisition(); + int InsertImage(); + int ThreadRun(); + bool IsCapturing(); + void OnThreadExiting() throw(); + int IsExposureSequenceable(bool& isSequenceable) const; + unsigned GetNumberOfComponents() const { return nComponents_; }; +#pragma endregion Camera_Api + +#pragma region Action_interface + + int OnALCMode(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnGainMode(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnShutterGain(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnAutoGainMax(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnAutoGainMin(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnExposure(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnClockSpeed(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnWhiteBalanceMode(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnWBGainR(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnWBGainGr(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnWBGainGb(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnWBGainB(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnReadoutTime(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnIsSequenceable(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnMirrorRotation(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnScanMode(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnImageH(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnImageV(MM::PropertyBase* pProp, MM::ActionType eAct); +#pragma endregion Action_interface + +#pragma region Declaration_Variable +private: + int ResizeImageBuffer(); + HANDLE handle_; + char name_; + bool isMonochrome_; + bool enabledROI_; + std::string alcMode_, scanModeType_, productName_; + DWORD dwSize_; + + DWORD dwLinePitch_; + unsigned int dwPreviewPixelFormat_; + WORD gain_, scanMode_; + double exposureMsec_; + DWORD exposureClock_; + WORD autoGainMax_, analogGainMax_, digitalGainMax_, digitalGainMin_; + WORD autoGainMin_; + double exposureMaxMsec_; + double exposureMinMsec_; + DWORD exposureMaxClock_; + std::string clockMode_, mirrorMode_, gainMode_; // mirror command + Gain Mode added.(8/3/22) + DWORD clockFreq_; + FLOAT fps_; + std::string wbMode_; + WORD wbGainR_; + WORD wbGainGr_; + WORD wbGainGb_; + WORD wbGainB_; + unsigned int delayMsec_; + ImgBuffer img_; + bool busy_; + bool stopOnOverFlow_; + bool initialized_; + double readoutUs_; + MM::MMTime readoutStartTime_; + MM::MMTime sequenceStartTime_; + int bitDepth_; + unsigned roiX_; + unsigned roiY_; + bool isSequenceable_; + long imageCounter_; + long binFac_; + DWORD imageSizeH_; + DWORD imageSizeV_; + bool stopOnOverflow_; + MMThreadLock imgPixelsLock_; + friend class MySequenceThread; + int nComponents_; + MySequenceThread* thd_; +#pragma endregion Declaration_Variable + +}; + +class MySequenceThread : public MMDeviceThreadBase +{ +#pragma region Live_Api + friend class Camera; + enum { default_numImages = 1, default_intervalMS = 100 }; +public: + MySequenceThread(Camera* pCam); + ~MySequenceThread(); + void Stop(); + void Start(long numImages, double intervalMs); + bool IsStopped(); + void Suspend(); + bool IsSuspended(); + void Resume(); + double GetIntervalMs() { return intervalMs_; } + void SetLength(long images) { numImages_ = images; } + long GetLength() const { return numImages_; } + long GetImageCounter() { return imageCounter_; } + MM::MMTime GetStartTime() { return startTime_; } + MM::MMTime GetActualDuration() { return actualDuration_; } +#pragma endregion Live_Api + +#pragma region Live_Declaration +private: + int svc(void) throw(); + double intervalMs_; + long numImages_; + long imageCounter_; + bool stop_; + bool suspend_; + Camera* camera_; + MM::MMTime startTime_; + MM::MMTime actualDuration_; + MM::MMTime lastFrameTime_; + MMThreadLock stopLock_; + MMThreadLock suspendLock_; +#pragma endregion Live_Declaration +}; diff --git a/DeviceAdapters/SigmaKoki/Shutter.cpp b/DeviceAdapters/SigmaKoki/Shutter.cpp new file mode 100644 index 000000000..47f0ab63a --- /dev/null +++ b/DeviceAdapters/SigmaKoki/Shutter.cpp @@ -0,0 +1,861 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: Shutter.cpp +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#include "Shutter.h" +#include + +const char* g_ShutterDeviceName_C2B1 = "C2B-1"; +const char* g_ShutterDeviceName_C2B2 = "C2B-2"; +const char* g_ShutterDeviceName_C4B1 = "C4B-1"; +const char* g_ShutterDeviceName_C4B2 = "C4B-2"; +const char* g_ShutterDeviceName_C4B3 = "C4B-3"; +const char* g_ShutterDeviceName_C4B4 = "C4B-4"; + +const char* g_ShutterModel = "ShutterModel"; +const char* g_ShutterModel_BSH = "BSH/SSH-R"; +const char* g_ShutterModel_BSH2 = "BSH2/SSH-25RA"; +const char* g_ShutterModel_SSHS = "SSH-S"; +const char* g_ShutterModel_SHPS = "SHPS"; + + +Shutter::Shutter(const char* name, int channel) : + SigmaBase(this), + name_(name), + channel_(channel), + defUser1_("USER1"), + defUser2_("USER2"), + defUser3_("USER3"), + changedTime_(0.0), + model_(C2B) +{ + InitializeDefaultErrorMessages(); + + // create pre-initialization properties + // ------------------------------------ + + // Name + CreateProperty(MM::g_Keyword_Name, name_.c_str(), MM::String, true); // should be fixed "name_" + + // Description + CreateProperty(MM::g_Keyword_Description, "SIGMA-KOKI Shutter adapter", MM::String, true); + + // Port + CPropertyAction* pAct = new CPropertyAction(this, &Shutter::OnPort); + CreateProperty(MM::g_Keyword_Port, "Undefined", MM::String, false, pAct, true); + EnableDelay(); + + UpdateStatus(); +} + +Shutter::~Shutter() +{ + Shutdown(); +} +/// +/// Busy +/// +/// +bool Shutter::Busy() +{ + MM::MMTime interval = GetCurrentMMTime() - changedTime_; + MM::MMTime delay(GetDelayMs() * 1000.0); + double tt = GetDelayMs(); + cout << "On busy" << endl; + cout << "Get Delay (MS) = " << tt << endl; + cout << "Get Delay value = " << tt*1000 << endl; + + + if (interval < delay) + return true; + else + return false; +} + +/// +/// Get Name +/// +/// +void Shutter::GetName(char* pszName) const +{ + CDeviceUtils::CopyLimitedString(pszName, name_.c_str()); +} + +/// +/// Initialization +/// +/// +int Shutter::Initialize() +{ + + if (initialized_) + return DEVICE_OK; + + core_ = GetCoreCallback(); + + // Set the device ID + int ret = SetDeviceID(model_); + if (ret != DEVICE_OK) + return ERR_SHUTTER_DEVICE_UNRECOGNIZABLE; + + + // Set the proprietes command system of controller + switch (model_) + { + case Shutter::C2B:// Set the command system of controller. 'SSH-C2B' controller only. + ret = SetCommandSystem(); + if (ret != DEVICE_OK) + return ERR_SHUTTER_COMMANDSYSTEM_FAILED; + break; + case Shutter::C4B:// Set the interrupt packet state. 'SSH-C4B' controller only + ret = SetInterruptPacketState(); + if (ret != DEVICE_OK) + return ERR_SHUTTER_INTERRUPT_FAILED; + break; + default: + break; + } + + // state propriety + CPropertyAction* pAct = new CPropertyAction(this, &Shutter::OnState); + ret = CreateProperty(MM::g_Keyword_State, "0", MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + AddAllowedValue(MM::g_Keyword_State, "0"); + AddAllowedValue(MM::g_Keyword_State, "1"); + + // Delay propriety + pAct = new CPropertyAction(this, &Shutter::OnDelay); + ret = CreateProperty(MM::g_Keyword_Delay, "0.0", MM::Float, false, pAct); + if (ret != DEVICE_OK) + return ret; + + + // Set the delay time of controller side. Delay time is 0.0 seconds. + if (model_ == C2B) + { + ret = SetControllerDelay(0.0); + if (ret != DEVICE_OK) + return ERR_SHUTTER_DELAY_FAILED; + } + + + + // Model propriety + pAct = new CPropertyAction(this, &Shutter::OnModel); + string s = ""; + switch (model_) + { + case Shutter::C2B: + modelType_ = g_ShutterModel_BSH2; + ret = CreateProperty(g_ShutterModel, g_ShutterModel_BSH2, MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + AddAllowedValue(g_ShutterModel, g_ShutterModel_BSH); + AddAllowedValue(g_ShutterModel, g_ShutterModel_SSHS); + AddAllowedValue(g_ShutterModel, g_ShutterModel_SHPS); + AddAllowedValue(g_ShutterModel, g_ShutterModel_BSH2); + for (int i = 1; i <= 3; i++) + { // assign shutter name to s (propriety) + ret = GetShutterName(s, 4 + i); + if (ret != DEVICE_OK) + return ERR_SHUTTER_MODELNAME_FAILED; + switch (i) + { + case 1: + defUser1_ = s; + break; + case 2: + defUser2_ = s; + break; + case 3: + defUser3_ = s; + break; + } + AddAllowedValue(g_ShutterModel, s.c_str()); + } + break; + case Shutter::C4B: + modelType_ = g_ShutterModel_BSH; + ret = CreateProperty(g_ShutterModel, g_ShutterModel_BSH, MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + AddAllowedValue(g_ShutterModel, g_ShutterModel_BSH); + AddAllowedValue(g_ShutterModel, g_ShutterModel_SSHS); + break; + default: + break; + } + + // Set the action mode. + ret = SetShutterActionMode(); + if (ret != DEVICE_OK) + return ERR_SHUTTER_ACTIONMODE_FAILED; + + ret = UpdateStatus(); + if (ret != DEVICE_OK) + return ret; + + // Set timer for the Busy signal + changedTime_ = GetCurrentMMTime(); + initialized_ = true; + + return DEVICE_OK; +} + +/// +/// ShutDown +/// +/// +int Shutter::Shutdown() +{ + if (initialized_) + { + initialized_ = false; + } + return DEVICE_OK; +} +/// +/// Open Set +/// +/// +/// + +int Shutter::SetOpen(bool open) +{ + long pos; + if (open) + { + pos = 1; //open + } + else + { + pos = 0; //close + } + return SetProperty(MM::g_Keyword_State, CDeviceUtils::ConvertToString(pos)); +} + +/// +/// Get Open +/// +/// +/// +int Shutter::GetOpen(bool& open) +{ + char buf[MM::MaxStrLength]; + int ret = GetProperty(MM::g_Keyword_State, buf); + if (ret != DEVICE_OK) + return ret; + long pos = atol(buf); + pos == 1 ? open = true : open = false; + + return DEVICE_OK; +} + +/// +/// Fire Command Not supported +/// +/// +/// +int Shutter::Fire(double deltaT) +{ + return DEVICE_UNSUPPORTED_COMMAND; +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////// Action handlers ////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +/// +/// Action Handler On State +/// +/// +/// +/// +int Shutter::OnState(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + bool open; + int ret; + // Set timer for the Busy signal + + double tt = GetDelayMs(); + cout << "On state" << endl; + cout << "Get Delay (MS) = " << tt << endl; + if (eAct == MM::BeforeGet) + { + ret = GetShutterPosition(open); + if (ret != DEVICE_OK) + return ret; + if (open) + { + pProp->Set("1"); + } + else + { + pProp->Set("0"); + } + } + else if (eAct == MM::AfterSet) + { + changedTime_ = GetCurrentMMTime(); + string state = ""; + pProp->Get(state); + + if (state == "1") + { + ret = GetShutterPosition(open); //Check the status(Open?) of the shutter before run. + if (ret != DEVICE_OK) + return ret; + if (!open) + { + return SetShutterPosition(true); //open + + } + } + else if (state == "0") + { + ret = GetShutterPosition(open); //Check the status(Close?) of the shutter before run. + if (ret != DEVICE_OK) + return ret; + if (open) + { + return SetShutterPosition(false); //close + } + } + else + { + return ERR_SHUTTER_STATE_FAILED; + } + } + + return DEVICE_OK; +} +/// +/// Action On POrt +/// +/// +/// +/// +int Shutter::OnPort(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(port_.c_str()); + } + else if (eAct == MM::AfterSet) + { + if (initialized_) + { + // revert + pProp->Set(port_.c_str()); + return ERR_PORT_CHANGE_FORBIDDEN; + } + + pProp->Get(port_); + } + + return DEVICE_OK; +} + +/// +/// On Delay +/// +/// +/// +/// +int Shutter::OnDelay(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(this->GetDelayMs()); + } + else if (eAct == MM::AfterSet) + { + double delay; + pProp->Get(delay); + this->SetDelayMs(delay); + } + + return DEVICE_OK; +} + +/// +/// On Model +/// +/// +/// +/// +int Shutter::OnModel(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + bool open; + int ret = GetShutterPosition(open); + if (ret != DEVICE_OK) + return ERR_SHUTTER_STATE_FAILED; + + if (eAct == MM::BeforeGet) + { + if (!open) + { + pProp->Set(modelType_.c_str()); + ret = SetShutterModel(modelType_); + if (ret != DEVICE_OK) + return ERR_SHUTTER_MODEL_FAILED; + } + } + else if (eAct == MM::AfterSet) + { + if (!open) + { + pProp->Get(modelType_); + ret = SetShutterModel(modelType_); + if (ret != DEVICE_OK) + return ERR_SHUTTER_MODEL_FAILED; + } + } + + return DEVICE_OK; +} + +/// +/// Send an open/close +/// +/// +/// +int Shutter::SetShutterPosition(bool state) +{ + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Create command + string cmd; + switch (model_) + { + case Shutter::C4B: + if (state) + { + cmd = "SH " + to_string(channel_) + ",1"; //open + } + else + { + cmd = "SH " + to_string(channel_) + ",0"; //close + } + break; + case Shutter::C2B: + if (state) + { + cmd = "OPEN:" + to_string(channel_); //open + } + else + { + cmd = "CLOSE:" + to_string(channel_); //close + } + break; + } + + // Send command and Recieve data + string answer = ""; + ret = SendRecieve(cmd, answer); + if (ret != DEVICE_OK) + return ret; + + if (answer == "A" || answer == "S") + { + return DEVICE_OK; + } + else + { + return ERR_SHUTTER_CONTROL_FAILED; + } +} + +/// +/// Check the state of the shutter. +/// +/// +/// +int Shutter::GetShutterPosition(bool& state) +{ + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Create command + string cmd; + switch (model_) + { + case Shutter::C4B: + cmd = "GH " + to_string(channel_); + break; + case Shutter::C2B: + cmd = "OPEN?" + to_string(channel_); + break; + } + + // Send command Recieve data + string answer = ""; + + ret = SendRecieve(cmd, answer); + if (ret != DEVICE_OK) + return ret; + + string buf = ""; + switch (model_) + { + case Shutter::C4B: + if (answer == "B") + { + return ERR_SHUTTER_STATE_FAILED; + } + buf = answer.substr(2, 1); + if (buf == "1") //open + { + state = true; + } + else if (buf == "0") //close + { + state = false; + } + break; + case Shutter::C2B: + if (answer == "C" || answer == "P") + { + return ERR_SHUTTER_STATE_FAILED; + } + buf = answer.substr(4, 1); + if (buf == "O") //open + { + state = true; + } + else if (buf == "C") //close + { + state = false; + } + break; + } + + return DEVICE_OK; +} + +/// +/// Setting the Model_ of device model +/// +/// +/// +int Shutter::SetDeviceID(ShutterModel& model) +{ + + if (name_ == g_ShutterDeviceName_C4B1) + { + model = Shutter::C4B; + } + else if (name_ == g_ShutterDeviceName_C4B2) + { + model = Shutter::C4B; + } + else if (name_ == g_ShutterDeviceName_C4B3) + { + model = Shutter::C4B; + } + else if (name_ == g_ShutterDeviceName_C4B4) + { + model = Shutter::C4B; + } + else if (name_ == g_ShutterDeviceName_C2B1) + { + model = Shutter::C2B; + } + else if (name_ == g_ShutterDeviceName_C2B2) + { + model = Shutter::C2B; + } + else + { + return false; + } + + return DEVICE_OK; +} + +/// +/// Setting the command system of controller. +// NOTE: 'SSH-C2B' controller only is valid. +// NOTE: It is controlled by the 'SSH-C2B command-system'. 'SSH-C4B command-system' is not used. +/// +/// +int Shutter::SetCommandSystem() +{ + if (model_ != C2B) + { + return false; + } + + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Send command// Recieve data + string answer = ""; + ret = SendRecieve("SC 1", answer); + if (ret != DEVICE_OK) + return ret; + + if (answer == "S") + { + return DEVICE_OK; + } + else + { + return ERR_SHUTTER_COMMANDSYSTEM_FAILED; + } +} + +/// +/// Setting the shutter action mode. +/// NOTE: It is controlled by the 'BULB' mode. 'TIMER' mode is not used. +/// +/// +int Shutter::SetShutterActionMode() +{ + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Create command + string cmd; + switch (model_) + { + case Shutter::C2B: + cmd = "MODE:" + to_string(channel_) + ",B"; + break; + case Shutter::C4B: + cmd = "SM " + to_string(channel_) + ",0"; + break; + default: + break; + } + + // Send command// Recieve data + string answer = ""; + ret = SendRecieve(cmd, answer); + if (ret != DEVICE_OK) + return ret; + + if (answer == "A" || answer == "S") + { + return DEVICE_OK; + } + else + { + return ERR_SHUTTER_ACTIONMODE_FAILED; + } +} + +/// +/// Setting the shutter models. +/// +/// +/// +int Shutter::SetShutterModel(const std::string model) +{ + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Create command + string cmd; + if (model == g_ShutterModel_BSH) // BSH/SSH-R + { + switch (model_) + { + case Shutter::C4B: + cmd = "PC " + to_string(channel_) + ",100"; + break; + case Shutter::C2B: + cmd = "SEL:" + to_string(channel_) + ",1"; + break; + } + } + else if (model == g_ShutterModel_SSHS) // SSH-S + { + switch (model_) + { + case Shutter::C4B: + cmd = "PC " + to_string(channel_) + ",002"; + break; + case Shutter::C2B: + cmd = "SEL:" + to_string(channel_) + ",2"; + break; + } + } + else if (model == g_ShutterModel_SHPS) // SHPS + { + cmd = "SEL:" + to_string(channel_) + ",3"; + } + else if (model == g_ShutterModel_BSH2) // BSH2/SSH-25RA + { + cmd = "SEL:" + to_string(channel_) + ",4"; + } + else if (model == defUser1_) // User-defined model 1 + { + cmd = "SEL:" + to_string(channel_) + ",5"; + } + else if (model == defUser2_) // User-defined model 2 + { + cmd = "SEL:" + to_string(channel_) + ",6"; + } + else if (model == defUser3_) // User-defined model 3 + { + cmd = "SEL:" + to_string(channel_) + ",7"; + } + + // Send command // Recieve data + string answer = ""; + ret = SendRecieve(cmd, answer); + if (ret != DEVICE_OK) + return ret; + + if (answer == "A" || answer == "S") + { + return DEVICE_OK; + } + else + { + return ERR_SHUTTER_MODEL_FAILED; + } +} + +/// +/// Get the shutter model name. +/// NOTE: 'SSH-C2B' controller only is valid. +/// +int Shutter::GetShutterName(std::string& name, int index) +{ + if (model_ != Shutter::C2B) + { + return false; + } + + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Create command + string cmd; + cmd = "NAME?" + to_string(index); + + // Send command // Recieve data + string answer = ""; + ret = SendRecieve(cmd, answer); + if (ret != DEVICE_OK) + return ret; + + if (answer == "C" || answer == "P") + { + return ERR_SHUTTER_MODELNAME_FAILED; + } + else + { + name = answer.substr(5, 7); + while (*name.rbegin() == ' ') + { + name.erase(name.size() - 1); + } + + return DEVICE_OK; + } +} + +/// +/// Setting the interrupt packet state. +/// NOTE: 'SSH-C4B' controller only is valid. +/// NOTE: Interrupt packet is not used. +/// +int Shutter::SetInterruptPacketState() +{ + if (model_ != Shutter::C4B) + { + return false; + } + + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Send command ---> 'SP 0' is the non-use mode. 'SP 1' is the use mode. + // Recieve data + string answer = ""; + ret = SendRecieve("SP 0", answer); + if (ret != DEVICE_OK) + return ret; + + if (answer == "A") + { + return DEVICE_OK; + } + else + { + return ERR_SHUTTER_INTERRUPT_FAILED; + } +} + +/// +/// Setting the delay time of the controller side. +/// NOTE: 'SSH-C2B' controller only is valid. +/// NOTE: In the case of 0.0 seconds is no delay time. +/// +int Shutter::SetControllerDelay(double val) +{ + if (model_ !=Shutter::C2B) + { + return false; + } + + if (val < 0.0 || val > 999.9) + { + return ERR_SHUTTER_DELAY_FAILED; + } + + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Create command + ostringstream c_val; + c_val << val; + string cmd = "DLY:" + to_string(channel_) + "," + c_val.str(); + + // Send command// Recieve data + string answer = ""; + ret = SendRecieve(cmd, answer); + if (ret != DEVICE_OK) + return ret; + + if (answer == "S") + { + return DEVICE_OK; + } + else + { + return ERR_SHUTTER_DELAY_FAILED; + } +} diff --git a/DeviceAdapters/SigmaKoki/Shutter.h b/DeviceAdapters/SigmaKoki/Shutter.h new file mode 100644 index 000000000..8d6b73188 --- /dev/null +++ b/DeviceAdapters/SigmaKoki/Shutter.h @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: Shutter.h +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#pragma once + +#include "SigmaBase.h" +using namespace std; + +extern const char* g_ShutterDeviceName_C2B1; +extern const char* g_ShutterDeviceName_C2B2; +extern const char* g_ShutterDeviceName_C4B1; +extern const char* g_ShutterDeviceName_C4B2; +extern const char* g_ShutterDeviceName_C4B3; +extern const char* g_ShutterDeviceName_C4B4; + + +class Shutter : public CShutterBase, public SigmaBase +{ +public: + Shutter(const char* name, int channel); + ~Shutter(); + + bool Busy(); + void GetName(char* pszName) const; + int Initialize(); + int Shutdown(); + + // Shutter API + int SetOpen(bool open = true); + int GetOpen(bool& open); + int Fire(double deltaT); + + // Action Interface + // ---------------- + int OnState(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnPort(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnDelay(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnModel(MM::PropertyBase* pProp, MM::ActionType eAct); + +private: + /// + /// Controller model + /// + enum ShutterModel + { + C2B, // SSH-C2B + C4B // SSH-C4B + }; + + int SetShutterPosition(bool state); + int GetShutterPosition(bool& state); + int SetDeviceID(ShutterModel& model); + int SetCommandSystem(); + int SetShutterActionMode(); + int SetShutterModel(const std::string model); + int GetShutterName(std::string& name, int index); + int SetInterruptPacketState(); + int SetControllerDelay(double val); + + // bool initialized_; + std::string name_; + std::string modelType_; + std::string defUser1_; + std::string defUser2_; + std::string defUser3_; + ShutterModel model_; + int channel_; + MM::MMTime changedTime_; +}; diff --git a/DeviceAdapters/SigmaKoki/SigmaBase.cpp b/DeviceAdapters/SigmaKoki/SigmaBase.cpp new file mode 100644 index 000000000..28386a741 --- /dev/null +++ b/DeviceAdapters/SigmaKoki/SigmaBase.cpp @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: SigmaBase.cpp +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#include "XYStage.h" +#include "ZStage.h" +#include "Shutter.h" +#include "SigmaBase.h" +#include "Camera.h" + +/// +/// Constructor +/// +SigmaBase::SigmaBase(MM::Device *device): + initialized_(false), + port_("Undefined"), + device_(device), + core_(0) +{ +} + +/// +/// Destructor +/// +SigmaBase::~SigmaBase() +{ +} + + + +/////////////////////////////////////////////////////////////////////////////// +// Exported MMDevice API +/////////////////////////////////////////////////////////////////////////////// + +MODULE_API void InitializeModuleData() +{ + RegisterDevice(g_XYStageDeviceName, MM::XYStageDevice, "XYStage (Advanced System)"); + RegisterDevice(g_ZStageDeviceName, MM::StageDevice, "ZStage (focusing actuator)"); + RegisterDevice(g_ShutterDeviceName_C2B1, MM::ShutterDevice, "SSH-C2B CH1"); + RegisterDevice(g_ShutterDeviceName_C2B2, MM::ShutterDevice, "SSH-C2B CH2"); + RegisterDevice(g_ShutterDeviceName_C4B1, MM::ShutterDevice, "SSH-C4B CH1"); + RegisterDevice(g_ShutterDeviceName_C4B2, MM::ShutterDevice, "SSH-C4B CH2"); + RegisterDevice(g_ShutterDeviceName_C4B3, MM::ShutterDevice, "SSH-C4B CH3"); + RegisterDevice(g_ShutterDeviceName_C4B4, MM::ShutterDevice, "SSH-C4B CH4"); + RegisterDevice(g_CameraDeviceName, MM::CameraDevice, "Camera"); +} + +/// +/// Device Creation +/// +/// +/// +MODULE_API MM::Device* CreateDevice(const char* deviceName) +{ + if (deviceName == 0) + { + return 0; + } + + if (strcmp(deviceName, g_XYStageDeviceName) == 0) + { + XYStage* s = new XYStage(); + return s; + } + else if (strcmp(deviceName, g_ZStageDeviceName) == 0) + { + ZStage* s = new ZStage(); + return s; + //return 0; + } + else if (strcmp(deviceName, g_ShutterDeviceName_C2B1) == 0) + { + Shutter* s = new Shutter(g_ShutterDeviceName_C2B1, 1); + return s; + } + else if (strcmp(deviceName, g_ShutterDeviceName_C2B2) == 0) + { + Shutter* s = new Shutter(g_ShutterDeviceName_C2B2, 2); + return s; + } + else if (strcmp(deviceName, g_ShutterDeviceName_C4B1) == 0) + { + Shutter* s = new Shutter(g_ShutterDeviceName_C4B1, 1); + return s; + } + else if (strcmp(deviceName, g_ShutterDeviceName_C4B2) == 0) + { + Shutter* s = new Shutter(g_ShutterDeviceName_C4B2, 2); + return s; + } + else if (strcmp(deviceName, g_ShutterDeviceName_C4B3) == 0) + { + Shutter* s = new Shutter(g_ShutterDeviceName_C4B3, 3); + return s; + } + else if (strcmp(deviceName, g_ShutterDeviceName_C4B4) == 0) + { + Shutter* s = new Shutter(g_ShutterDeviceName_C4B4, 4); + return s; + } + else if (strcmp(deviceName, g_CameraDeviceName) == 0) + { + Camera* s = new Camera(); + return s; + } + else + { + return 0; + } +} + +MODULE_API void DeleteDevice(MM::Device* pDevice) +{ + delete pDevice; +} + +/////////////////////////////////////////////////////////////////////////////// +// Common API +/////////////////////////////////////////////////////////////////////////////// + +/// +/// Clear port +/// +/// +int SigmaBase::ClearPort() const +{ + core_->LogMessage(device_, "SigmaBase::ClearPort\n", true); + //Clear contents of serial port + const int bufSize = 255; + unsigned char clear[bufSize]; + unsigned long read = bufSize; + int ret; + while (read == (unsigned)bufSize) + { + ret = core_->ReadFromSerial(device_, port_.c_str(), clear, bufSize, read); + if (ret != DEVICE_OK) + return ret; + } + return DEVICE_OK; +} + +/// +/// Send command string +/// +/// +/// +int SigmaBase::SendCommand(const std::string command) +{ + core_->LogMessage(device_, ("SigmaBase::Send:" + command + "\n").c_str(), true); + int ret = core_->SetSerialCommand(device_, port_.c_str(), command.c_str(), "\r\n"); + if (ret != DEVICE_OK) { return ret; } + return DEVICE_OK; +} + +/// +/// Recieve data +/// +/// +/// +int SigmaBase::RecieveData(std::string& data) +{ + const size_t BUFSIZE = 2048; + char buf[BUFSIZE] = { '\0' }; + int ret = core_->GetSerialAnswer(device_, port_.c_str(), BUFSIZE, buf, "\r\n"); + if (ret != DEVICE_OK) { return ret; } + data = buf; + core_->LogMessage(device_, ("SigmaBase::Receive:" + data + "\n").c_str(), true); + return DEVICE_OK; +} + +/// +/// Send command and recieve data +/// +/// +/// +/// +int SigmaBase::SendRecieve(const std::string command, std::string& data) +{ + int ret = SendCommand(command); + if (ret != DEVICE_OK) { return ret; } + + ret = RecieveData(data); + if (ret != DEVICE_OK){ return ret; } + + return DEVICE_OK; +} + +/// +/// Send command and check recieve data 'OK' +/// +/// +/// +int SigmaBase::SendCheckRecievedOK(const std::string command) +{ + std::string data = ""; + int ret = SendRecieve(command, data); + if (ret != DEVICE_OK){ return ret; } + + if (strcmp(data.c_str(), "OK") != 0) + { + return DEVICE_SERIAL_INVALID_RESPONSE; + } + return DEVICE_OK; +} + +/// +/// Split by specified delimiter +/// +/// source string +/// delimiter +/// +std::vector SigmaBase::split(std::string src, char del) +{ + std::stringstream ss(src); + vector result; + while (ss.good()) + { + string substr; + getline(ss, substr, del); + result.push_back(substr); + } + return result; +} diff --git a/DeviceAdapters/SigmaKoki/SigmaBase.h b/DeviceAdapters/SigmaKoki/SigmaBase.h new file mode 100644 index 000000000..6c1d28482 --- /dev/null +++ b/DeviceAdapters/SigmaKoki/SigmaBase.h @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: SigmaBase.h +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#ifndef _SIGMABASE_H_ +#define _SIGMABASE_H_ + +#include +#include +#include +#include +////////////////////////////////////////////////////////////////////////////// +// Error codes +//General +#define ERR_PORT_CHANGE_FORBIDDEN 10001 +//ZStage +#define ERR_ZSTEGE_DEVICE_UNRECOGNIZABLE 10201 +#define ERR_ZSTAGE_STEPSIZE_FAILED 10202 +#define ERR_ZSTAGE_SPEED_FAILED 10203 +#define ERR_ZSTAGE_SET_RESOLUTION_CLOSE_CONTROL_FAILED 10204 +//XYStage +#define ERR_XYSTEGE_DEVICE_UNRECOGNIZABLE 10101 +#define ERR_XYSTAGE_STEPSIZE_FAILED 10102 +#define ERR_XYSTAGE_SPEED_FAILED 10103 +//Shutter +#define ERR_SHUTTER_DEVICE_UNRECOGNIZABLE 10301 +#define ERR_SHUTTER_INTERRUPT_FAILED 10302 +#define ERR_SHUTTER_CONTROL_FAILED 10303 +#define ERR_SHUTTER_STATE_FAILED 10304 +#define ERR_SHUTTER_COMMANDSYSTEM_FAILED 10305 +#define ERR_SHUTTER_ACTIONMODE_FAILED 10306 +#define ERR_SHUTTER_MODEL_FAILED 10307 +#define ERR_SHUTTER_MODELNAME_FAILED 10308 +#define ERR_SHUTTER_DELAY_FAILED 10309 + +////////////////////////////////////////////////////////////////////////////// + + +class SigmaBase +{ +public: + SigmaBase(MM::Device *device); + virtual ~SigmaBase(); + +protected: + int ClearPort() const; + + int SendCommand(const std::string command); + int RecieveData(std::string& data); + int SendRecieve(const std::string command, std::string& data); + int SendCheckRecievedOK(const std::string command); + + /* + * [Added] - 2022-03-02, h.kibata@sigma-koki.com + */ + std::vector split(std::string src, char del); + + bool initialized_; + std::string port_; + MM::Device* device_; + MM::Core* core_; +}; + +#endif //_TEST_SIGMAKOKI_H_ diff --git a/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj new file mode 100644 index 000000000..1efcd562e --- /dev/null +++ b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {39655236-2634-4ed3-aacd-0c9b032f805c} + TestSigmaKoki + SigmaKoki + 10.0 + + + + DynamicLibrary + true + v142 + <different options> + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + <different options> + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + $(MM_BUILDDIR)\$(Configuration)\$(Platform)\ + $(MM_BUILDDIR)\intermediates\$(Configuration)\$(Platform)\$(ProjectName)\ + mmgr_dal_$(ProjectName) + + + false + $(MM_BUILDDIR)\$(Configuration)\$(Platform)\ + $(MM_BUILDDIR)\intermediates\$(Configuration)\$(Platform)\$(ProjectName)\ + mmgr_dal_$(ProjectName) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + %(AdditionalIncludeDirectories) + + + Console + true + %(AdditionalLibraryDirectories) + + + + + Level4 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)MMDevice + + + Console + true + true + true + %(AdditionalLibraryDirectories);$(ProjectDir)\Camera_Lib\x86 + StCamD.lib;%(AdditionalDependencies) + + + + + Level4 + WIN32;_DEBUG;_WINDOWS;_USRDLL;MODULE_EXPORTS;%(PreprocessorDefinitions) + true + 4127;4290;%(DisableSpecificWarnings) + Default + %(AdditionalIncludeDirectories) + + + Console + true + C:\Users\t.abed\Desktop\Micromanger test part 1\build\Release\x64;%(AdditionalLibraryDirectories) + $(OutDir)StCamD.lib;StCamD.lib + + + + + Level4 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + 4127;4290;%(DisableSpecificWarnings) + $(SolutionDir)MMDevice + true + + + Console + true + true + true + %(AdditionalLibraryDirectories);$(ProjectDir)\Camera_Lib\x64 + StCamD.lib;%(AdditionalDependencies) + + + + xcopy/y "$(OutputPath)mmgr_dal_$(ProjectName)$(TargetExt)" "C:\Program Files\Micro-Manager-2.0" + + + + + + + + + + + + + + + + + + + + {b8c95f39-54bf-40a9-807b-598df2821d55} + + + + + + \ No newline at end of file diff --git a/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters new file mode 100644 index 000000000..e8418be7c --- /dev/null +++ b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + ソース ファイル + + + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + ヘッダー ファイル + + + \ No newline at end of file diff --git a/DeviceAdapters/SigmaKoki/XYStage.cpp b/DeviceAdapters/SigmaKoki/XYStage.cpp new file mode 100644 index 000000000..5601c49fe --- /dev/null +++ b/DeviceAdapters/SigmaKoki/XYStage.cpp @@ -0,0 +1,1494 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: XYStage.cpp +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#include "XYStage.h" +#include +#include +#include +#include + +using namespace std; +// XY_Device Adapter (Registartion from SigmaBase) +const char* g_XYStageDeviceName = "XYStage"; +// cont variable to be used proprietes +const char* g_ChannelX = "Channel_X"; +const char* g_ChannelY = "Channel_Y"; +const char* g_XYStageSpeed = "Speed (micron/sec)"; +const char* g_XStepSize = "StepSize_X (micron)"; +const char* g_YStepSize = "StepSize_Y (micron)"; +const char* g_FullStepStageX = "Full Step Stage X (micron)"; +const char* g_FullStepStageY = "Full Step Stage Y (micron)"; +const char* g_DivisionX = "Division Stage X"; +const char* g_DivisionY = "Division Stage Y"; +const char* g_DivisionInfo = "Division Information"; +const char* g_XYStageController = "Name of Controller"; +const char* g_FCModel = "Controller Model"; +const char* g_FCModelSet = "FC-types"; +const char* g_FCResolution = "Controller Resolution (micron)"; +const char* g_PulseRateInfo = "Please set the correct PULSE_RATE for each axis in memory switches"; + +const int MaxSpeedum = 5000; // micromter unit +const int MinSpeedum = 10; // micromter unit + +/// +/// Constructor +/// +XYStage::XYStage() : + SigmaBase(this), + model_(SHOT2), + channelX_(1), + channelY_(2), + channelA_(3), + channelB_(4), + speedXYum_(3000), + fullStepSizeXum_(2.0), + fullStepSizeYum_(2.0), + stepSizeXum_(0.1), + stepSizeYum_(0.1), + divisionX_(20), + divisionY_(20), + answerTimeoutMs_(500), + positionXpulse_(0), + positionYpulse_(0), + positionApulse_(0), + positionBpulse_(0), + isBusyHomeShot4_(false), + fcModel_("FC-***"), + slow_pulse (0), + fast_pulse(0), + PlsRate1(0), + PlsRate2(0) +{ + InitializeDefaultErrorMessages(); + + // Create pre-initialization properties + SetErrorText(ERR_XYSTEGE_DEVICE_UNRECOGNIZABLE, "Connected device can not recognized."); + SetErrorText(ERR_XYSTAGE_STEPSIZE_FAILED, "Failed to resolution setting."); + SetErrorText(ERR_XYSTAGE_SPEED_FAILED, "Failed to speed setting."); + + // Name + CreateProperty(MM::g_Keyword_Name, g_XYStageDeviceName, MM::String, true); + + // Description + CreateProperty(MM::g_Keyword_Description, "SIGMA-KOKI XYStage adapter", MM::String, true); + + // Port + CPropertyAction* pAct = new CPropertyAction(this, &XYStage::OnPort); + CreateProperty(MM::g_Keyword_Port, "Undefined", MM::String, false, pAct, true); +} + +/// +/// Destructor +/// +XYStage::~XYStage() +{ + Shutdown(); +} + +/// +/// get name +/// +void XYStage::GetName(char* Name) const +{ + CDeviceUtils::CopyLimitedString(Name, g_XYStageDeviceName); +} + +/// +/// Shutdown +/// +int XYStage::Shutdown() +{ + if (initialized_) + { + initialized_ = false; + } + return DEVICE_OK; +} + +/// +/// busy status +/// +bool XYStage::Busy() +{ + // Home command on Y channel when using SHOT-304 + if (model_ == SHOT4) + { + if (isBusyHomeShot4_) + { + int ret = SendCheckRecievedOK("H:" + to_string(channelY_)); + if (ret != DEVICE_OK) return ret; + isBusyHomeShot4_ = false; + Busy(); + } + } + + //First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return false; + + // Send command + string answer = ""; + ret = SendRecieve("!:", answer); + if (ret != DEVICE_OK) + return false; + + // Receive check (busy or ready) + if (model_ == XYStage::HSC3||model_==SHRC3) + { + string::size_type index = answer.find("1"); + if (index == string::npos) + { + return false; //ready + } + else + { + return true; //busy + } + } + else if (answer.substr(0, 1).compare("B") == 0) + { + return true; //busy + } + + return false; //ready +} + +/// +/// Set device model +/// +int XYStage::SetDeviceModel() +{ + //First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + + // Send status command and recieve data + string data = ""; + ret = SendRecieve("Q:", data); + if (ret != DEVICE_OK) + return ret; + + const int SHOT2_STATUS_STRING_LENGTH = 27; + const int SHOT4_STATUS_STRING_LENGTH = 49; + const int FC2_STATUS_STRING_LENGTH = 32; + + // setting + if (data.length() == SHOT2_STATUS_STRING_LENGTH) + { + model_ = XYStageModel::SHOT2; // SHOT-302GS, SHOT-702 + g_DivisionInfo = "Set Division Of Shot-2Axis"; + g_XYStageController = "SHOT-302GS/SHOT-702"; + } + else if (data.length() == SHOT4_STATUS_STRING_LENGTH) + { + model_ = XYStageModel::SHOT4; // SHOT-304GS + g_DivisionInfo = "Set Division Of Shot-304"; + g_XYStageController = "SHOT-304GS"; + } + else if (data.length() == FC2_STATUS_STRING_LENGTH) + { + model_ = XYStageModel::FC2; + g_DivisionInfo = "No Division Setting For FC Series"; + g_XYStageController = "FC Series Controller"; + + // Get product name + string name = "unknown"; + ret = SendRecieve("*IDN?", name); + if (ret != DEVICE_OK) { return ret; } + + // ','-separated array + vector product_info = split(name, ','); + + string resolution_axis1; + string resolution_axis2; + + const int FC_MODEL_INDEX = 0; + const int FC_AXIS_COUNT = 1; + + fcModel_ = product_info[FC_MODEL_INDEX] + " " + product_info[FC_AXIS_COUNT]; + + // Get resolution + // Key words are extracted to determine old and current models. + // "0" :old model ...FC/SC-101G, FC-401G, FC-501G + // "1" :current model ...FC-111, 411, 511, 611, 911, 114, 414, 514 + string key_word = product_info[FC_AXIS_COUNT].substr(4, 1); + if (key_word == "1") + { + /* + * return unit :nanometer + */ + ret = SendRecieve("RESO:"+ to_string(channelX_), resolution_axis1); + if (ret != DEVICE_OK) { return ret; } + ret = SendRecieve("RESO:"+ to_string(channelY_), resolution_axis2); + if (ret != DEVICE_OK) { return ret; } + + stepSizeXum_ = stod(resolution_axis1)/double(1000); + stepSizeYum_ = stod(resolution_axis2)/double(1000); + } + else + { + /* + * return unit :micrometer + */ + ret = SendRecieve("RES:"+ to_string(channelX_), resolution_axis1); + if (ret != DEVICE_OK) { return ret; } + ret = SendRecieve("RES:"+ to_string(channelY_), resolution_axis2); + if (ret != DEVICE_OK) { return ret; } + + stepSizeXum_ = stod(resolution_axis1); + stepSizeYum_ = stod(resolution_axis2); + } + // Freeing up memory for vectors + vector().swap(product_info); + } + else + { + //Get product name + + string name = "unknown"; + ret = SendRecieve("?:N", name); + if (ret != DEVICE_OK) { return ret; } + + // remove white spaces + name.erase(std::remove_if(name.begin(), name.end(), isspace), name.end()); + + if (strcmp(name.c_str(), "HSC-103" ) == 0) + { + model_ = XYStageModel::HSC3; // HSC-103 + g_DivisionInfo = "No division setting for HSC controller | fixed to 40"; + g_XYStageController = "HSC-103 Controller"; + } + else if (strcmp(name.c_str(), "SHRC-203") == 0) + { + model_ = XYStageModel::SHRC3; // SHRC-203 + g_DivisionInfo = "Set Division Of SHRC-203"; + g_XYStageController = "SHRC-203"; + string mode = ""; + //MODE:HOST (to be confirmed) + //FMT:HIT + ret = SendRecieve("?:FMT",mode); + if (ret != DEVICE_OK) { return ret; } + + if (mode != "HIT") + { + SendCheckRecievedOK("FMT:HIT"); + if (ret != DEVICE_OK) { return ret; } + } + + } + } + + return DEVICE_OK; +} + +/// +/// Initialize +/// +int XYStage::Initialize() +{ + if (initialized_){ return DEVICE_OK; } + core_ = GetCoreCallback(); + + this->LogMessage("XYStage::Initialize\n", true); + + //Set device model + int ret = SetDeviceModel(); + if (ret != DEVICE_OK) { return ERR_XYSTEGE_DEVICE_UNRECOGNIZABLE; } + + // Create propiretes XY-Channel + CPropertyAction* pAct = new CPropertyAction(this, &XYStage::OnChannelX); + ret = CreateProperty(g_ChannelX, "1", MM::Integer, false, pAct); + if (ret != DEVICE_OK) + return ret; + pAct = new CPropertyAction(this, &XYStage::OnChannelY); + ret = CreateProperty(g_ChannelY, "2", MM::Integer, false, pAct); + if (ret != DEVICE_OK) + return ret; + + if (model_ != FC2) + { + // stages full step X Y + // Valid for all controllers except FC Series + pAct = new CPropertyAction(this, &XYStage::OnFullStepSizeX); + ret = CreateProperty(g_FullStepStageX, "2", MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + pAct = new CPropertyAction(this, &XYStage::OnFullStepSizeY); + ret = CreateProperty(g_FullStepStageY, "2", MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + } + + bool ifdisabled = true; // enable/disable Division Setting in proprietes Available on (SHOT Series) not available on (HSC & FC Series) + + // Channels and full step creation + switch (model_) + { + case XYStage::SHOT2: + for (int i = 1; i <= 2; i++) + { + AddAllowedValue(g_ChannelX, to_string(i).c_str()); + AddAllowedValue(g_ChannelY, to_string(i).c_str()); + } + CreateFullStepPropXY(); + ifdisabled = false; + break; + case XYStage::FC2: + for (int i = 1; i <= 2; i++) + { + AddAllowedValue(g_ChannelX, to_string(i).c_str()); + AddAllowedValue(g_ChannelY, to_string(i).c_str()); + } + // Read Only Prop {{ controller model, Resolution, stepsizeX and stepsizeY }} + CreateProperty(g_FCModel, fcModel_.c_str(), MM::String, true); + CreateProperty(g_FCResolution, to_string(stepSizeXum_).c_str(), MM::String, true); + break; + case XYStage::SHOT4: + for (int i = 1; i <= 4; i++) + { + AddAllowedValue(g_ChannelX, to_string(i).c_str()); + AddAllowedValue(g_ChannelY, to_string(i).c_str()); + } + CreateFullStepPropXY(); + ifdisabled = false; + break; + case XYStage::HSC3: + for (int i = 1; i <= 3; i++) + { + AddAllowedValue(g_ChannelX, to_string(i).c_str()); + AddAllowedValue(g_ChannelY, to_string(i).c_str()); + } + CreateFullStepPropXY(); + ifdisabled = true; + + + // Pulse Rate Information + CreateProperty("Stage Pulse Rate Info", g_PulseRateInfo, MM::String, true); + // Set pulse rate 1 + pAct = new CPropertyAction(this, &XYStage::onPulseRateX); + ret = CreateProperty("StageX Pulse Rate", to_string(PlsRate1).c_str(), MM::String, true, pAct); + if (ret != DEVICE_OK) + return ret; + // Set pulse rate 2 + pAct = new CPropertyAction(this, &XYStage::onPulseRateY); + ret = CreateProperty("StageY Pulse Rate", to_string(PlsRate2).c_str(), MM::String, true, pAct); + if (ret != DEVICE_OK) + return ret; + + break; + case XYStage::SHRC3: + + for (int i = 1; i <= 3; i++) + { + AddAllowedValue(g_ChannelX, to_string(i).c_str()); + AddAllowedValue(g_ChannelY, to_string(i).c_str()); + } + CreateFullStepPropXY(); + ifdisabled = false; + /* + * TODO: To be implemented once specifications are finalised. + */ + break; + default: + break; + } + + + // Axis Division X and Y for all controllers except FC Serie. + // No division for FC Series + // No step Size for FC Series + if (model_ != FC2) + { + pAct = new CPropertyAction(this, &XYStage::OnDivisionX); + ret = CreateProperty(g_DivisionX, "20", MM::String, ifdisabled, pAct); + if (ret != DEVICE_OK) + return ret; + + pAct = new CPropertyAction(this, &XYStage::OnDivisionY); + ret = CreateProperty(g_DivisionY, "20", MM::String, ifdisabled, pAct); + if (ret != DEVICE_OK) + return ret; + CreateDivisionPropXY(); + } + // Step Size X proprietes (Read only ) + pAct = new CPropertyAction(this, &XYStage::OnStepSizeX); + ret = CreateProperty(g_XStepSize, to_string(stepSizeXum_).c_str(), MM::String, true, pAct); + if (ret != DEVICE_OK) + return ret; + // Step Size y proprietes (Read only ) + pAct = new CPropertyAction(this, &XYStage::OnStepSizeY); + ret = CreateProperty(g_YStepSize, to_string(stepSizeYum_).c_str(), MM::String, true, pAct); + if (ret != DEVICE_OK) + return ret; + + + // Division Information read only + CreateProperty("XY Division Information", g_DivisionInfo, MM::String, true); + + // controller name + CreateProperty("Name of Controller(XY)", g_XYStageController, MM::String, true); + + // XY-Speed (micron/sec) + pAct = new CPropertyAction(this, &XYStage::OnSpeedXY); + ret = CreateProperty(g_XYStageSpeed, "3000", MM::Integer, false, pAct); + if (ret != DEVICE_OK) + return ret; + SetPropertyLimits(g_XYStageSpeed, MinSpeedum, MaxSpeedum); + + ret = UpdateStatus(); + if (ret != DEVICE_OK) + return ret; + initialized_ = true; + + return DEVICE_OK; +} + +/// +/// Mechanical origin return +/// +int XYStage::Home() +{ + int ret = GenericCommandProcess("H:"); + if (ret != DEVICE_OK) return ret; + + return DEVICE_OK; +} + +/// Setting the XY-stage resolution(move per step [micron]). Deleted, no needed +/// NOTE: to be confirmed . +//int XYStage::SetResolution() +//{ +// // Set division of X stage with corresponding division X +// int ret = SetDivision(channelX_, divisionX_); +// if (ret != DEVICE_OK) +// return ret; +// // Set division of Y stage with corresponding division Y +// ret = SetDivision(channelY_, divisionY_); +// if (ret != DEVICE_OK) +// return ret; +// +// return DEVICE_OK; +//} + +// Setting the XY-stage division by axis(channel). +/// NOTE: Shot controllers only. (+ SHRC Controller ) +int XYStage::SetDivision(int channel, int division) +{ + //First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Send command �c the division number + if (model_ == SHRC3) // hit mode SHRC controller + { + if (channel == 1) { ret = SendCheckRecievedOK("S:" + to_string(division) + ",,"); } + else if (channel == 2 ) { ret = SendCheckRecievedOK("S:," + to_string(division) + ","); } + else if (channel == 3) { ret = SendCheckRecievedOK("S:,," + to_string(division) ); } + if (ret != DEVICE_OK) + return ret; + } + else {/// Other Shot controller + ret = SendCheckRecievedOK("S:" + to_string(channel) + to_string(division)); + if (ret != DEVICE_OK) + return ret; + } + return DEVICE_OK; +} + +/// +/// Update position all controller except FC Series +/// +/// +int XYStage::UpdatePosition() +{ + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Send status command 'Q:' & Recieve position data + string data = ""; + ret = SendRecieve("Q:", data); + if (ret != DEVICE_OK) + return ret; + + // Remove spaces in data strings + data.erase(std::remove_if(data.begin(), data.end(), isspace), data.end()); + + // ','-separated array + vector status = split(data, ','); + + // Set the position status for each axis + switch (model_) + { + case XYStage::SHOT2: + case XYStage::FC2: + positionXpulse_ = atol(status[channelX_ - 1].c_str()); + positionYpulse_ = atol(status[channelY_ - 1].c_str()); + positionApulse_ = 0; + positionBpulse_ = 0; + break; + case XYStage::SHOT4: + positionXpulse_ = atol(status[channelX_ - 1].c_str()); + positionYpulse_ = atol(status[channelY_ - 1].c_str()); + positionApulse_ = atol(status[channelA_ - 1].c_str()); + positionBpulse_ = atol(status[channelB_ - 1].c_str()); + break; + case XYStage::HSC3: + case XYStage::SHRC3: + positionXpulse_ = atol(status[channelX_ - 1].c_str()); + positionYpulse_ = atol(status[channelY_ - 1].c_str()); + positionApulse_ = atol(status[channelA_ - 1].c_str()); + positionBpulse_ = 0; + break; + default: + positionXpulse_ = 0; + positionYpulse_ = 0; + positionApulse_ = 0; + positionBpulse_ = 0; + break; + } + + // Freeing up memory for vectors + vector().swap(status); + + return DEVICE_OK; +} + +/// +/// Update position only fc controllers +/// Unit -> true is micromter, otherwise is pulse +/// +/// + + + +/// +/// Assignment of other channels 'A' and 'B' +/// +void XYStage::AssignmentOtherChannels() +{ + switch (model_) + { + case XYStage::SHOT2: + case XYStage::FC2: + channelA_ = 3; + channelB_ = 4; + break; + case XYStage::SHOT4: + for (int i = 1; i <= 4; i++) + { + if (i != channelX_) + { + if (i != channelY_) + { + channelA_ = i; + break; + } + } + } + for (int j = 1; j <= 4; j++) + { + if (j != channelX_) + { + if (j != channelY_) + { + if (j != channelA_) + { + channelB_ = j; + break; + } + } + } + } + break; + case XYStage::HSC3: + case XYStage::SHRC3: + for (int i = 1; i <= 3; i++) + { + if (i != channelX_) + { + if (i != channelY_) + { + channelA_ = i; + break; + } + } + } + channelB_ = 4; + break; + default: + channelA_ = 3; + channelB_ = 4; + break; + } + core_->LogMessage(device_, ("X:" + to_string(channelX_) + + ",Y:" + to_string(channelY_) + + ",A:" + to_string(channelA_) + + ",B:" + to_string(channelB_) + "\n").c_str(), false); +} + +/// +/// Create drive command; @Test added, 2022-03-03, h.kibata@sigma-koki.com +/// +/// X-position[pulse] // X-position [Micrometer] fc series +/// Y-position[pulse] // Y-position [Micrometer] fc series +/// drive mode, true->absolue/false->relative +/// command string +string XYStage::ToDriveCommand(long x, long y, bool is_abs) +{ + // Update status + if (UpdatePosition() != DEVICE_OK) + { + return ""; + } + + int axis_count = 2; // Axis count + string pos_header; // Number of Pulses + string comma; // Comma in case of Hit mode + string command; // Commands + long* src_pos = new long[4]; + src_pos[0] = x; + src_pos[1] = y; + + // Drive mode + if (is_abs) + { + //Absolue + command = "A:"; + src_pos[2] = positionApulse_; + src_pos[3] = positionBpulse_; + } + else + { + //Relative + command = "M:"; + src_pos[2] = 0; + src_pos[3] = 0; + } + + switch (model_) + { + case XYStage::SHOT2:case XYStage::FC2: + axis_count = 2; + pos_header = "P"; + comma = ""; + command += "W"; + break; + case XYStage::SHOT4: + axis_count = 4; + pos_header = "P"; + comma = ""; + command += "W"; + break; + case XYStage::HSC3:case XYStage::SHRC3: + axis_count = 3; + pos_header = ""; + comma = ","; + break; + default: + axis_count = 2; + pos_header = "P"; + comma = ""; + command += "W"; + break; + } + + string* sign = new string[axis_count]; // Sign array + string* buffer_command = new string[axis_count]; // Buffer command array + long dst_pos[4] = {0, 0, 0, 0}; // Destination position array + int channel[4] = {channelX_, channelY_, channelA_, channelB_}; // Channel array + + // combined + for (int i = 0; i < axis_count; i++) + { + for (int j = 0; j < axis_count; j++) + { + if (i == channel[j] - 1) // Get Amount Sign in all axis + { + if (src_pos[j] >= 0) + { + sign[i] = "+"; + } + else + { + sign[i] = "-"; + } + dst_pos[i] = src_pos[j]; + } + } + if (i == axis_count - 1) + { + buffer_command[i] = sign[i] + pos_header + to_string(abs(dst_pos[i])); // Build and create command SHOT mode + } + else + { + buffer_command[i] = sign[i] + pos_header + to_string(abs(dst_pos[i])) + comma; // Build and create command HIT mode + } + command += buffer_command[i]; + } + + // retrieve + delete[] src_pos; + delete[] sign; + delete[] buffer_command; + + return command; +} + +/// +/// Drive command processing (generic) +/// +/// X-position[pulse] +/// Y-position[pulse] +/// drive mode, true->absolue/false->relative +/// +int XYStage::DriveCommandProcess(long x, long y, bool is_abs) +{ + // First Clear serial port + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // create drive command + string command = ToDriveCommand(x, y, is_abs); + if (command.empty()) + { + return DEVICE_UNSUPPORTED_COMMAND; + } + + // Send command + switch (model_) + { + case XYStage::SHOT2: + case XYStage::SHOT4: + ret = SendCheckRecievedOK(command); + if (ret != DEVICE_OK) return ret; + ret = SendCheckRecievedOK("G:"); + if (ret != DEVICE_OK) return ret; + break; + case XYStage::FC2: + ret = SendCommand(command); + if (ret != DEVICE_OK) return ret; + ret = SendCommand("G"); + if (ret != DEVICE_OK) return ret; + break; + case XYStage::HSC3:case XYStage::SHRC3: + ret = SendCheckRecievedOK(command); + if (ret != DEVICE_OK) return ret; + break; + + /* + * TODO: To be implemented once specifications are finalised. + */ + default: + return DEVICE_UNSUPPORTED_COMMAND; + } + + return DEVICE_OK; +} + +/// +/// Generic command 'H:', 'L:', 'R:' processing +/// +/// command header string +/// +int XYStage::GenericCommandProcess(string command_header) +{ + // First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + string retour; + // Send Stop Command + switch (model_) + { + case XYStage::SHOT2: + ret = SendCheckRecievedOK(command_header + "W"); + if (ret != DEVICE_OK) return ret; + break; + case XYStage::SHOT4: + if (command_header == "H:") + { + ret = SendCheckRecievedOK(command_header + to_string(channelX_)); + if (ret != DEVICE_OK) return ret; + isBusyHomeShot4_= true; + } + else + { + ret = SendCheckRecievedOK(command_header + to_string(channelX_)); + if (ret != DEVICE_OK) return ret; + + ret = SendCheckRecievedOK(command_header + to_string(channelY_)); + if (ret != DEVICE_OK) return ret; + } + break; + case XYStage::FC2: + ret = SendCommand(command_header + "W"); + if (ret != DEVICE_OK) return ret; + break; + case XYStage::HSC3:case XYStage::SHRC3: + for (int i = 1; i <= 3; i++) + { + if (i == channelX_) + { + command_header += "1"; + } + else if (i == channelY_) + { + command_header += "1"; + } + else + { + command_header += "0"; + } + if (i != 3) + { + command_header += ","; + } + } + + // Send Recieve data check OK + ret = SendCheckRecievedOK(command_header); + if (ret != DEVICE_OK) return ret; + break; + default: + return DEVICE_UNSUPPORTED_COMMAND; + } + return DEVICE_OK; +} + +/// +/// Pulse Speed setting +/// +/// +/// +int XYStage::PulseSpeedSetting(int val) +{ + // Setting the XY-speed pulse + fast_pulse = (long)(val / stepSizeXum_); + slow_pulse = 0; + switch (model_) + { + case XYStage::SHOT2:case XYStage::SHOT4:case XYStage::HSC3:case XYStage::SHRC3: + //Speed(F) [PPS] + if (fast_pulse < 1 || fast_pulse > (long)(MaxSpeedum/stepSizeXum_)) { return ERR_XYSTAGE_SPEED_FAILED; } + //Speed(S) [PPS] + slow_pulse = GetSlowSpeedPulse(fast_pulse); + break; + case XYStage::FC2: + if (fast_pulse < 1 || fast_pulse > (long)(MaxSpeedum / stepSizeXum_)) { return ERR_XYSTAGE_SPEED_FAILED; } + break; + + default: + break; + } + + return DEVICE_OK; +} + +/// +/// Stop stage +/// +int XYStage::Stop() +{ + int ret = GenericCommandProcess("L:"); + if (ret != DEVICE_OK) + return ret; + return DEVICE_OK; +} + +/// +/// Logical origin +/// +int XYStage::SetOrigin() +{ + int ret = GenericCommandProcess("R:"); + if (ret != DEVICE_OK) + return ret; + + return DEVICE_OK; +} + +/// +/// Positioning by steps || Absolute Move (pulse) +/// +int XYStage::SetPositionSteps(long x, long y) +{ + int ret = DriveCommandProcess(x, y, true); + if (ret != DEVICE_OK) + return ret; + + return DEVICE_OK; +} + +/// +/// Positioning by steps || Relative Move (pulse) +/// +int XYStage::SetRelativePositionSteps(long x, long y) +{ + int ret = DriveCommandProcess(x, y, false); + if (ret != DEVICE_OK) + return ret; + + return DEVICE_OK; +} + +/// +/// Get position per micrometer +/// +/// X-position[um] +/// Y-position[um] +/// +int XYStage::GetPositionUm(double& x, double& y) +{ + + int ret = UpdatePosition(); + if (ret != DEVICE_OK) + return ret; + + // retrieve x and y in Um + x = (double)(positionXpulse_ * stepSizeXum_); + y = (double)(positionYpulse_ * stepSizeYum_); + + return DEVICE_OK; +} + +/// +/// Get position steps +/// +/// X-position[pulse] +/// Y-position[pulse] +/// +int XYStage::GetPositionSteps(long& x, long& y) +{ + + int ret = UpdatePosition(); + if (ret != DEVICE_OK) + return ret; + + x = positionXpulse_; + y = positionYpulse_; + + return DEVICE_OK; +} + +/// +/// Set speed +/// +/// speed value +/// +int XYStage::SetSpeedXY(int val) +{ + //First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Set slow_pulse and fast_pulse + ret = PulseSpeedSetting(val); + if (ret != DEVICE_OK) + return ret; + + // Create command and send + // NOTE: Acceleration and Deceleration time fixed to 100 msec. + string cmd; string cmd_x; string cmd_y; + switch (model_) + { + case XYStage::SHOT2: + cmd = "D:WS" + to_string(slow_pulse) + "F" + to_string(fast_pulse) + "R100S" + to_string(slow_pulse) + "F" + to_string(fast_pulse) + "R100"; + SendCheckRecievedOK(cmd); + break; + case XYStage::SHOT4: + cmd_x = "D:" + to_string(channelX_) + "S" + to_string(slow_pulse) + "F" + to_string(fast_pulse) + "R100"; + SendCheckRecievedOK(cmd_x); + cmd_y = "D:" + to_string(channelY_) + "S" + to_string(slow_pulse) + "F" + to_string(fast_pulse) + "R100"; + SendCheckRecievedOK(cmd_y); + break; + case XYStage::FC2: + cmd = "D:WF" + to_string(fast_pulse) + "F" + to_string(fast_pulse); + SendCommand(cmd); + break; + case XYStage::HSC3:case XYStage::SHRC3: + cmd = "D:" + to_string(channelX_) + "," + to_string(slow_pulse) + "," + to_string(fast_pulse) + ",100"; + SendCheckRecievedOK(cmd); + cmd = "D:" + to_string(channelY_) + "," + to_string(slow_pulse) + "," + to_string(fast_pulse) + ",100"; + SendCheckRecievedOK(cmd); + break; + default: + break; + } + + // Send command (Setting of acc and dec time of FC series.) + if (model_== FC2) + { + // X-axis + string acc_x; + acc_x = "ACC:" + to_string(channelX_) + " 100"; + ret = SendCommand(acc_x); + if (ret != DEVICE_OK) + return ret; + // Y-axis + string acc_y; + acc_y = "ACC:" + to_string(channelY_) + " 100"; + ret = SendCommand(acc_y); + if (ret != DEVICE_OK) + return ret; + } + return DEVICE_OK; +} + +/// +/// Get slow speed +/// +/// 'Fast'-speed[pulse] +/// +long XYStage::GetSlowSpeedPulse(long fast) +{ + long slow = 0; + if (fast <= 50000) { slow = fast / 2; } + else { slow = 15000; } + return slow; +} + +/// +/// Get Limit +/// +int XYStage::GetLimitsUm(double& /*xMin*/, double& /*xMax*/, double& /*yMin*/, double& /*yMax*/) +{ + return DEVICE_UNSUPPORTED_COMMAND; +} + +/// +/// Get Limit step +/// +int XYStage::GetStepLimits(long& /*xMin*/, long& /*xMax*/, long& /*yMin*/, long& /*yMax*/) +{ + return DEVICE_UNSUPPORTED_COMMAND; +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Action handlers +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int XYStage::OnPort(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(port_.c_str()); + } + else if (eAct == MM::AfterSet) + { + if (initialized_) + { + // revert + pProp->Set(port_.c_str()); + return ERR_PORT_CHANGE_FORBIDDEN; + } + pProp->Get(port_); + } + + return DEVICE_OK; +} + + +int XYStage::OnChannelX(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((long)channelX_); + } + else if (eAct == MM::AfterSet) + { + long n; + pProp->Get(n); + channelX_ = int(n); + AssignmentOtherChannels(); + } + + return DEVICE_OK; +} + +int XYStage::OnChannelY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((long)channelY_); + } + else if (eAct == MM::AfterSet) + { + long n; + pProp->Get(n); + channelY_ = int(n); + AssignmentOtherChannels(); + } + + return DEVICE_OK; +} + +// NOTE: Step size is calculated depends full step stage and division. +int XYStage::OnStepSizeX(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + if (model_ == SHOT2 ||model_== SHOT4||model_ == SHRC3) + { + int ret = SetDivision(channelX_, divisionX_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_STEPSIZE_FAILED; + } + + pProp->Set(stepSizeXum_); + } + + return DEVICE_OK; +} + +// NOTE: Because the resolution is fixed (0.1 micron), Action-interface does not create now. +int XYStage::OnStepSizeY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + if (model_ == SHOT2 ||model_ == SHOT4 || model_ == SHRC3) + { + int ret = SetDivision(channelY_, divisionY_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_STEPSIZE_FAILED; + } + + pProp->Set(stepSizeYum_); + } + + return DEVICE_OK; +} + + +// Set speed for all controllers +int XYStage::OnSpeedXY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set((long)speedXYum_); + + int ret = SetSpeedXY(speedXYum_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_SPEED_FAILED; + } + else if (eAct == MM::AfterSet) + { + long n; + pProp->Get(n); + speedXYum_ = (int)n; + + int ret = SetSpeedXY(speedXYum_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_SPEED_FAILED; + } + + return DEVICE_OK; +} + +// Get Set proprietes full step X (depend on stages categories) +int XYStage::OnFullStepSizeX(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(fullStepSizeXum_); + } + else if (eAct == MM::AfterSet) + { + long n; + pProp->Get(n); + fullStepSizeXum_ = n; + } + + return DEVICE_OK; +} +// Get Set proprietes full step Y (depend on stages categories) +int XYStage::OnFullStepSizeY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(fullStepSizeYum_); + } + else if (eAct == MM::AfterSet) + { + long n; + pProp->Get(n); + fullStepSizeYum_ = n; + } + + return DEVICE_OK; +} + +// Get Set proprietes Division X +int XYStage::OnDivisionX(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + string x = "00"; + if (model_ == SHOT2 || model_ == SHOT4||model_==SHRC3) + { + x = to_string(divisionX_); + int ret = SetDivision(channelX_, divisionX_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_STEPSIZE_FAILED; + stepSizeXum_ = fullStepSizeXum_ / double(divisionX_); + } + if (model_ == HSC3) + { + divisionX_ = 40; + x = "40"; + //stepSizeXum_ = fullStepSizeXum_ / double(divisionX_); + stepSizeXum_ = 0.01; + } + pProp->Set(x.c_str()); + } + else if (eAct == MM::AfterSet) + { + string n; + pProp->Get(n); + if (model_ == SHOT2 || model_ == SHOT4 || model_ == SHRC3) + { + divisionX_ = stoi(n); + int ret = SetDivision(channelX_, divisionX_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_STEPSIZE_FAILED; + stepSizeXum_ = fullStepSizeXum_ / double(divisionX_); + } + if (model_ == HSC3) + { + divisionX_ = 40; + //stepSizeXum_ = fullStepSizeXum_ / double(divisionX_); + stepSizeXum_ = 0.01; + } + } + + return DEVICE_OK; +} + +// Get Set proprietes Division y +int XYStage::OnDivisionY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + string y = "00"; + if (model_ == SHOT2 || model_ == SHOT4 || model_ == SHRC3) + { + y = to_string(divisionY_); + + int ret = SetDivision(channelY_, divisionY_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_STEPSIZE_FAILED; + + stepSizeYum_ = fullStepSizeYum_ / double(divisionY_); + } + if (model_ == HSC3) + { + divisionY_ = 40; + y = "40"; + //stepSizeYum_ = fullStepSizeYum_ / double(divisionY_); + stepSizeYum_ = 0.01; + } + pProp->Set(y.c_str()); + + } + else if (eAct == MM::AfterSet) + { + string n; + pProp->Get(n); + if (model_ == SHOT2 || model_ == SHOT4 || model_ == SHRC3) + { + divisionY_ = stoi(n); + int ret = SetDivision(channelY_, divisionY_); + if (ret != DEVICE_OK) + return ERR_XYSTAGE_STEPSIZE_FAILED; + + stepSizeYum_ = fullStepSizeYum_ / double(divisionY_); + } + if (model_ == HSC3) + { + divisionY_ = 40; + //stepSizeYum_ = fullStepSizeYum_ / double(divisionY_); + stepSizeYum_ = 0.01; + } + } + + return DEVICE_OK; +} + + +// Pulse Rate Setting for HSC-103 only +int XYStage::onPulseRateX(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + /*Pulse Rate Calculclation in HSC-103 controller + PULSE RATE = (FULL_STEP / DIVISION)* 1000 /0.1*/ + const int UM_TO_NM_RATE = 1000; + const double NM_TO_PULSERATE_RATE = 0.1; + if (model_ == HSC3) + { + PlsRate1 = ((fullStepSizeXum_/40) * UM_TO_NM_RATE) / NM_TO_PULSERATE_RATE; + } + pProp->Set(long(PlsRate1)); + } + + return DEVICE_OK; +} + +int XYStage::onPulseRateY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + /* Pulse Rate Calculclation in HSC-103 controller + PULSE RATE = (FULL_STEP / DIVISION)* 1000 /0.1*/ + const int UM_TO_NM_RATE = 1000; + const double NM_TO_PULSERATE_RATE = 0.1; + if (model_ == HSC3) + { + PlsRate2 = ((fullStepSizeYum_ / 40) * UM_TO_NM_RATE) / NM_TO_PULSERATE_RATE; + } + pProp->Set(long(PlsRate2)); + } + return DEVICE_OK; +} + +/// +/// Create Division proprietes values +/// +void XYStage::CreateDivisionPropXY() +{ + ClearAllowedValues(g_DivisionX); + ClearAllowedValues(g_DivisionY); + + switch (model_) + { + case XYStage::SHOT2:case XYStage::SHOT4:case XYStage::SHRC3:case XYStage::HSC3: + /* + * HACK: Where possible, we would like to make the code a bit smarter. + */ + // Division X + AddAllowedDivisionPropXY(g_DivisionX); + // Division Y + AddAllowedDivisionPropXY(g_DivisionY); + break; + case XYStage::FC2: + /* + * NOTE: Fixed for each FC series model. + */ + break; + default: + break; + } +} + +/// +/// Creation of full step proprietes values. +/// +void XYStage::CreateFullStepPropXY() +{ + // Full Steps X + AddAllowedValue(g_FullStepStageX, "2"); + AddAllowedValue(g_FullStepStageX, "4"); + AddAllowedValue(g_FullStepStageX, "20"); + // Full Steps Y + AddAllowedValue(g_FullStepStageY, "2"); + AddAllowedValue(g_FullStepStageY, "4"); + AddAllowedValue(g_FullStepStageY, "20"); +} + +/// +/// Add division prop for X and Y (reduce size and avoid writing for x and y proprietes one by one) +/// +/// +void XYStage::AddAllowedDivisionPropXY(const char* div) +{ + + switch (model_) + { + case XYStage::SHOT2:case XYStage::SHOT4: + // Division X and Y + AddAllowedValue(div, "1"); + AddAllowedValue(div, "2"); + AddAllowedValue(div, "4"); + AddAllowedValue(div, "5"); + AddAllowedValue(div, "8"); + AddAllowedValue(div, "10"); + AddAllowedValue(div, "20"); + AddAllowedValue(div, "25"); + AddAllowedValue(div, "40"); + AddAllowedValue(div, "50"); + AddAllowedValue(div, "80"); + AddAllowedValue(div, "100"); + AddAllowedValue(div, "125"); + AddAllowedValue(div, "200"); + AddAllowedValue(div, "250"); + break; + case XYStage::FC2: + break; + case XYStage::HSC3: + /* + * NOTE: Fixed in 40 divisions. + */ + AddAllowedValue(div, "40"); + + break; + case XYStage::SHRC3: + for (int i = 1; i <= 6; i++) // Add from 1 to 6 + { + AddAllowedValue(div, to_string(i).c_str()); + } + AddAllowedValue(div, "8"); + AddAllowedValue(div, "12"); + AddAllowedValue(div, "25"); + for (int i = 1; i < 60; i++) // Add from 10 to 60 + { + i += 9; + AddAllowedValue(div, to_string(i).c_str()); + } + AddAllowedValue(div, "80"); + AddAllowedValue(div, "120"); + AddAllowedValue(div, "125"); + AddAllowedValue(div, "250"); + for (int i = 1; i < 400; i++) // add from 100 to 400 + { + i += 99; + AddAllowedValue(div, to_string(i).c_str()); + } + for (int i = 600; i <= 1000; i++) // add from 600 to 1000 + { + int k = i; + AddAllowedValue(div, to_string(k).c_str()); + i = i + 199; + } + for (int i = 1000; i <= 8000; i++) // add from 1000 to 8000 + { + int l = i; + AddAllowedValue(div, to_string(l).c_str()); + i = i + i - 1; + } + + break; + default: + break; + } + + +} diff --git a/DeviceAdapters/SigmaKoki/XYStage.h b/DeviceAdapters/SigmaKoki/XYStage.h new file mode 100644 index 000000000..a25e3dd2c --- /dev/null +++ b/DeviceAdapters/SigmaKoki/XYStage.h @@ -0,0 +1,114 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: XYStage.h +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#pragma once + +#include "SigmaBase.h" +using namespace std; +extern const char* g_XYStageDeviceName; + + +class XYStage : public CXYStageBase, public SigmaBase +{ +public: + XYStage(); + ~XYStage(); + + //Device API + //---------- + bool Busy(); + void GetName(char* pszName) const; + int Initialize(); + int Shutdown(); + + // XYStage API + //------------ + int GetPositionUm(double& x, double& y); + int GetPositionSteps(long& x, long& y); + int SetPositionSteps(long x, long y); + int SetRelativePositionSteps(long x, long y); + int Home(); + int Stop(); + int SetOrigin(); + int GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax); + int GetStepLimits(long& xMin, long& xMax, long& yMin, long& yMax); + double GetStepSizeXUm() { return stepSizeXum_; } + double GetStepSizeYUm() { return stepSizeYum_; } + int IsXYStageSequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; } + + // Action Interface + // ---------------- + int OnPort(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnChannelX(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnChannelY(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnStepSizeX(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnStepSizeY(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSpeedXY(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnFullStepSizeX(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnFullStepSizeY(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnDivisionX(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnDivisionY(MM::PropertyBase* pProp, MM::ActionType eAct); + // test + int onPulseRateX(MM::PropertyBase* pProp, MM::ActionType eAct); + int onPulseRateY(MM::PropertyBase* pProp, MM::ActionType eAct); + +private: + /// + /// Controller model + /// + enum XYStageModel + { + SHOT2, //SHOT-702, 302GS + SHOT4, //SHOT-304GS + FC2, //FC-Series + HSC3, //HSC-103 + SHRC3 //HRSC-203 SHRC changed + }; + + void CreateDivisionPropXY(); + void CreateFullStepPropXY(); + void AddAllowedDivisionPropXY(const char* div); // Added 5��12��2022 t.abed + int SetDeviceModel(); // change from [ SetDeviceModel(XYStageModel& model)] no needed + int SetDivision(int channel, int division); + int SetSpeedXY(int vxy); + long GetSlowSpeedPulse(long fast); + int UpdatePosition(); + void AssignmentOtherChannels(); + string ToDriveCommand(long x, long y, bool is_abs); + int DriveCommandProcess(long x, long y, bool is_abs); + int GenericCommandProcess(string command_header); + int PulseSpeedSetting(int val); // Added 12/4/2022 t.abed + + XYStageModel model_; + int channelX_; + int channelY_; + int channelA_; + int channelB_; + long positionXpulse_; + long positionYpulse_; + long positionApulse_; + long positionBpulse_; + long slow_pulse;// for speed setting + long fast_pulse;// for speed setting + int speedXYum_; + double fullStepSizeXum_; + double fullStepSizeYum_; + double stepSizeXum_; + double stepSizeYum_; + int divisionX_; + int divisionY_; + double answerTimeoutMs_; + bool isBusyHomeShot4_;//Busy flag for Home in case of Shot4 + string fcModel_; + int PlsRate1; // pulse rate StageX for HSC controller + int PlsRate2; // pulse rate STageY for HSC controller + +}; diff --git a/DeviceAdapters/SigmaKoki/ZStage.cpp b/DeviceAdapters/SigmaKoki/ZStage.cpp new file mode 100644 index 000000000..36be97756 --- /dev/null +++ b/DeviceAdapters/SigmaKoki/ZStage.cpp @@ -0,0 +1,1063 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ZStage.cpp +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#include "ZStage.h" + +using namespace std; +// cont variable to be used proprietes +const char* g_ZStageDeviceName = "ZStage"; +const char* g_ZStageChannel = "Channel"; +const char* g_ZStageControlMode = "Control Mode"; +const char* g_ZStageOpenControl = "OPEN"; +const char* g_ZStageCloseControl = "CLOSE"; +const char* g_ZStageStepSizeUm = "StepSize (micron)"; +const char* g_ZStageFullStepSize = "FullStepSize (micron)"; +const char* g_ZStageDivision = "Division of Controller"; +const char* g_ZStageSpeed = "Speed (micron/sec)"; +const char* g_ZinfoDivision = "Division Information"; +const char* g_ZStageController = "Name of Controller"; +const char* g_ZfineMode = "[CLOSE/OPEN] Setting, Please set to CLOSE mode in Memory Switch"; +const char* g_PulseRateInfoZ = "Please set the correct PULSE_RATE for each axis in memory switches"; + +/// +/// Constructor +/// +ZStage::ZStage() : + SigmaBase(this), + model_(SHOT2), + channel_("1"), + controlMode_("OPEN"), + fullstepSizeZum_(2.0), + stepSizeZum_(0.1), + divisionZ_("20"), + speed_(1000), + answerTimeoutMs_(500), + stepsZ_(0.0), + PlsRateZ(1) +{ + InitializeDefaultErrorMessages(); + + // Create pre-initialization properties + // Name + CreateProperty(MM::g_Keyword_Name, g_ZStageDeviceName, MM::String, true); + // Description + CreateProperty(MM::g_Keyword_Description, "SIGMA-KOKI ZStage adapter", MM::String, true); + // Port + CPropertyAction* pAct = new CPropertyAction(this, &ZStage::OnPort); + CreateProperty(MM::g_Keyword_Port, "Undefined", MM::String, false, pAct, true); +} + +/// +/// Destructor +/// +ZStage::~ZStage() +{ + Shutdown(); +} + +/// +/// Busy status +/// +/// +bool ZStage::Busy() +{ + // First Clear serial port from previous stuff------------------------------------------------------------------------------------------------ + int ret = ClearPort(); + if (ret != DEVICE_OK) + return false; + // Send command // Recieve Busy/Ready data---------------------------------------------------------------------------------------------------- + string answer = ""; + ret = SendRecieve("!:",answer); + if (ret != DEVICE_OK) + return false; + // Receive check (busy or ready)-------------------------------------------------------------------------------------------------------------- + if (model_ == HSC3|| model_== SHRC3) + { + string::size_type index = answer.find("1"); + if (index == string::npos) + { + return false; /*ready*/ + } + else + { + return true; /*busy*/ + } + } + else if (answer.substr(0, 1).compare("B") == 0) + { + return true; /*busy*/ + } + return false; /*ready*/ +} + +/// +/// Get Name +/// +/// +void ZStage::GetName(char* pszName) const +{ + CDeviceUtils::CopyLimitedString(pszName, g_ZStageDeviceName); +} + +/// +/// Initialize +/// +/// +int ZStage::Initialize() +{ + if (initialized_) { return DEVICE_OK; } + core_ = GetCoreCallback(); + + int ret = SetDeviceModel(); + if (ret != DEVICE_OK) { return ERR_XYSTEGE_DEVICE_UNRECOGNIZABLE; } + + // Channel + CPropertyAction* pAct = new CPropertyAction(this, &ZStage::OnChannel); + ret = CreateProperty(g_ZStageChannel, "1", MM::String, false, pAct); + // Assign Chanels number + CreateChanelProp(); + + + // stages full step Z + // NOTE: In the case of the piezo-controller (FINE-01, FINE-503), No Step stages. + if (model_ == SHOT1 || model_ == SHOT2 || model_ == SHOT4 || model_ == HSC3 || model_ == SHRC3) + { + pAct = new CPropertyAction(this, &ZStage::OnFullStepSize); + ret = CreateProperty(g_ZStageFullStepSize, "2", MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + AddAllowedValue(g_ZStageFullStepSize, "0.2"); + AddAllowedValue(g_ZStageFullStepSize, "1"); + AddAllowedValue(g_ZStageFullStepSize, "2"); + AddAllowedValue(g_ZStageFullStepSize, "4"); + AddAllowedValue(g_ZStageFullStepSize, "20"); + } + + bool ifdisabled = true; // enable/disable Division Setting in proprietes Available on (SHOT Series) / disable the others + + switch (model_) + { + case ZStage::SHOT1: + ifdisabled = false; + + break; + case ZStage::SHOT2:case ZStage::SHOT4: + // control mode prop + pAct = new CPropertyAction(this, &ZStage::OnControlModel); + ret = CreateProperty(g_ZStageControlMode, controlMode_.c_str(), MM::String, false, pAct); + if (ret != DEVICE_OK) + return ret; + AddAllowedValue(g_ZStageControlMode, g_ZStageOpenControl); + AddAllowedValue(g_ZStageControlMode, g_ZStageCloseControl); + ifdisabled = false; + break; + + case ZStage::FINE1:case ZStage::FINE3: + ifdisabled = true; + stepSizeZum_ = 0.010; + CreateProperty("Control Mode Info", g_ZfineMode, MM::String, true); + break; + + case ZStage::HSC3: + ifdisabled = true; + + // Pulse Rate Information + CreateProperty("Stage Pulse Rate Info", g_PulseRateInfoZ, MM::String, true); + // Pulse rate + pAct = new CPropertyAction(this, &ZStage::OnPulseRateZ); + ret = CreateProperty("StageZ Pulse Rate", to_string(PlsRateZ).c_str() , MM::String, true, pAct); + if (ret != DEVICE_OK) + return ret; + break; + + case ZStage::SHRC3: + + + ifdisabled = false; + break; + + default: + break; + } + + // Axis Division Z + // NOTE: In the case of the piezo-controller (FINE-01, FINE-503), No division setting. + if (model_ == SHOT1 || model_ == SHOT2 || model_ == SHOT4 || model_ == HSC3 || model_ == SHRC3) + { + pAct = new CPropertyAction(this, &ZStage::OnDivision); + ret = CreateProperty(g_ZStageDivision, "20", MM::String, ifdisabled, pAct); + if (ret != DEVICE_OK) + return ret; + CreateDivisionProp(); + } + + // Read only step Size + pAct = new CPropertyAction(this, &ZStage::OnStepSizeZ); + ret = CreateProperty(g_ZStageStepSizeUm, to_string(stepSizeZum_).c_str(), MM::String, true, pAct); + if (ret != DEVICE_OK) + return ret; + + // Speed (micron/sec) + // NOTE: In the case of the piezo-controller (FINE-01, FINE-503), speed can not be set. + if (model_ == SHOT1 || model_ == SHOT2 || model_ == SHOT4 || model_ == HSC3 || model_ == SHRC3) + { + pAct = new CPropertyAction(this, &ZStage::OnSpeed); + ret = CreateProperty(g_ZStageSpeed, to_string(speed_).c_str(), MM::Integer, false, pAct); + if (ret != DEVICE_OK) + return ret; + SetPropertyLimits(g_ZStageSpeed, 1, 2000); + } + + // Division Information + CreateProperty("Z Division Information", g_ZinfoDivision, MM::String, true); + + // controller name + CreateProperty("Name of Controller(Z)", g_ZStageController, MM::String, true); + + ret = UpdateStatus(); + if (ret != DEVICE_OK) + return ret; + + initialized_ = true; + return DEVICE_OK; +} + +/// +/// Shut down +/// +/// +int ZStage::Shutdown() +{ + if (initialized_) + { + initialized_ = false; + } + return DEVICE_OK; +} + +/// +/// Get position in Um +/// +/// +/// +int ZStage::GetPositionUm(double& pos) +{ + // get position of Z in steps + int ret = UpdatePositionZ(); + + if (ret != DEVICE_OK) + return ret; + + // Extract position to um + if (model_ == FINE1 || model_ == FINE3) + { + pos = (stepsZ_ / 1000); //nano -> micron + } + else if (model_ == HSC3) + { + pos =(stepsZ_ * 0.01); + } + else + { + if (controlMode_ == g_ZStageOpenControl) + { + pos = (double)(stepsZ_ * stepSizeZum_); //pulse -> micron + } + else if (controlMode_ == g_ZStageCloseControl) + { + pos = (double)(stepsZ_ * 0.01); //pulse -> micron + } + } + + return DEVICE_OK; +} + +/// +/// Get the position in steps +/// +/// +/// +int ZStage::GetPositionSteps(long& steps) +{ + // get position of Z in steps + int ret = UpdatePositionZ(); + if (ret != DEVICE_OK) + return ret; + + steps = stepsZ_; + + return DEVICE_OK; +} + +/// +/// Set Position in um unit +/// +/// +/// +int ZStage::SetPositionUm(double pos) +{ + // Set position Um (Absolue drive ) + int ret = DriveCommadProcessZ(pos); + if (ret != DEVICE_OK) + return ret; + + return DEVICE_OK; + +} + +/// +/// Home set +/// +/// +int ZStage::SetOrigin() +{ + // First Clear serial port from previous stuff------------------------------------------------------- + int ret = ClearPort(); + if (ret != DEVICE_OK) + {return ret;} + + + // Create command------------------------------------------------------- + string cmd = "R:"; + + if (model_ == HSC3) + { + for (int i = 1; i <= 3; i++) + { + if (i == stoi(channel_)) { cmd += "1"; } + else { cmd += "0"; } + if (i != 3) { cmd += ","; } + } + } + else + { + cmd += channel_; + } + + // Send command ------------------------------------------------------- + ret = SendCheckRecievedOK(cmd); + if (ret != DEVICE_OK) + return ret; + + return DEVICE_OK; +} + +/// +/// Not supported command +/// +int ZStage::GetLimits(double& min, double& max) +{ + return DEVICE_UNSUPPORTED_COMMAND; +} + +/// Action Handlers ////////////////////////////////////////////////////////////////// +/// +/// On Port +/// All acctions of proprietes handlers +/// +int ZStage::OnPort(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(port_.c_str()); + } + else if (eAct == MM::AfterSet) + { + if (initialized_) + { + // revert + pProp->Set(port_.c_str()); + return ERR_PORT_CHANGE_FORBIDDEN; + } + + pProp->Get(port_); + } + + return DEVICE_OK; +} + +/// +/// Set Channels for all controller +/// +/// +int ZStage::OnChannel(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(channel_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(channel_); + } + + return DEVICE_OK; +} + +/// +/// set/get full step size for all controller +/// +/// +/// +int ZStage::OnFullStepSize(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(fullstepSizeZum_); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(fullstepSizeZum_); + } + + if (model_ == SHOT2 || model_ == SHOT4) + { + if (controlMode_ == g_ZStageOpenControl) + { + //CreateResolutionList(fullstepSizeZum_); + } + else if (controlMode_ == g_ZStageCloseControl) + { + ClearAllowedValues(g_ZStageStepSizeUm); + AddAllowedValue(g_ZStageStepSizeUm, "0.100"); + AddAllowedValue(g_ZStageStepSizeUm, "0.500"); + } + } + return DEVICE_OK; +} + + +/// +/// REad only step size of Z +/// +/// +/// +/// +int ZStage::OnStepSizeZ(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + if (model_==SHOT2 || model_ == SHOT4 || model_ == SHRC3) + { + pProp->Set(stepSizeZum_); + + } + } + return DEVICE_OK; +} + + + +/// +/// Get Set Step Size (division) +/// +/// +/// +/// +int ZStage::OnDivision(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + int ret; + if (eAct == MM::BeforeGet) + { + + if (model_ == HSC3) + { + divisionZ_ = "40"; + stepSizeZum_ = fullstepSizeZum_ / stod(divisionZ_); + stepSizeZum_ = 0.01; + } + + pProp->Set(divisionZ_.c_str()); + + if (model_ == SHOT2 || model_ == SHOT4 || model_ == SHRC3 ) + { + ret = SetDivision(stoi(divisionZ_)); + if (ret != DEVICE_OK) + return ERR_ZSTAGE_STEPSIZE_FAILED; + double d = fullstepSizeZum_ / stod(divisionZ_); + stepSizeZum_ = d; + } + if (model_ == SHOT1) + { + stepSizeZum_ = fullstepSizeZum_ / stod(divisionZ_); + } + + } + else if (eAct == MM::AfterSet) + { + if (model_ == SHOT2 || model_ == SHOT4) + { + if (controlMode_ == g_ZStageCloseControl) + { + double pos; + GetPositionUm(pos); + if (pos != 0.0) + { + return ERR_ZSTAGE_SET_RESOLUTION_CLOSE_CONTROL_FAILED; + } + } + } + + pProp->Get(divisionZ_); + + if (model_ == SHOT2 || model_ == SHOT4 || model_ == SHRC3) + { + + ret = SetDivision(stoi(divisionZ_)); + if (ret != DEVICE_OK) + return ERR_ZSTAGE_STEPSIZE_FAILED; + double d = fullstepSizeZum_ / stod(divisionZ_); + stepSizeZum_ = d; + } + if (model_ == SHOT1) + { + stepSizeZum_ = fullstepSizeZum_ / stod(divisionZ_); + } + } + + return DEVICE_OK; +} + +/// +/// Set get speed +/// +/// +/// +/// +int ZStage::OnSpeed(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + int ret; + if (eAct == MM::BeforeGet) + { + pProp->Set((long)speed_); + + ret = SetSpeed(speed_); + if (ret != DEVICE_OK) + return ERR_ZSTAGE_SPEED_FAILED; + } + else if (eAct == MM::AfterSet) + { + long n; + pProp->Get(n); + speed_ = (int)n; + + ret = SetSpeed(speed_); + if (ret != DEVICE_OK) + return ERR_ZSTAGE_SPEED_FAILED; + } + + return DEVICE_OK; +} +/// +/// +/// +/// +/// +/// +int ZStage::OnControlModel(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(controlMode_.c_str()); + } + else if (eAct == MM::AfterSet) + { + pProp->Get(controlMode_); + + if (controlMode_ == g_ZStageOpenControl) + { + CreateDivisionProp(); + } + else if (controlMode_ == g_ZStageCloseControl) + { + ClearAllowedValues(g_ZStageStepSizeUm); + AddAllowedValue(g_ZStageStepSizeUm, "0.100"); + AddAllowedValue(g_ZStageStepSizeUm, "0.500"); + } + } + + return DEVICE_OK; +} +int ZStage::OnPulseRateZ(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + // Pulse Rate Calculclation in HSC-103 controller + // PULSE RATE = (FULL_STEP / DIVISION)* 1000 /0.1 + const int UM_TO_NM_RATE = 1000; + const double NM_TO_PULSERATE_RATE = 0.1; + if (model_ == HSC3) + { + PlsRateZ = ((fullstepSizeZum_/40) * UM_TO_NM_RATE) / NM_TO_PULSERATE_RATE; + } + pProp->Set(long(PlsRateZ)); + } + + return DEVICE_OK; +} +/// +/// Set device model +/// +/// +/// +int ZStage::SetDeviceModel() +{ + //First Clear serial port from previous stuff---------------------------------------------------------------------------------------------------- + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Send status command and recieve data---------------------------------------------------------------------------------------------------------- + string data = ""; + ret = SendRecieve("Q:", data); + if (ret != DEVICE_OK) + return ret; + + const int SHOT1_STATUS_STRING_LENGTH = 16; + const int SHOT2_STATUS_STRING_LENGTH = 27; + const int FINE3_STATUS_STRING_LENGTH = 38; + const int SHOT4_STATUS_STRING_LENGTH = 49; + + + + if (data.length() == SHOT1_STATUS_STRING_LENGTH) + { + //Read the controller model + string answer = ""; + ret = SendRecieve("?:N", answer); + if (ret != DEVICE_OK) + return ret; + + if (answer== "FINE-01r ") + { + model_ = FINE1; // FINE-01 + g_ZinfoDivision = "No division for fine controllers"; + g_ZStageController = "Fine-01"; + } + else + { + model_ = SHOT1; // GIP-101, TAF-C01 + g_ZinfoDivision = "Please set the division from dip switch"; + g_ZStageController = "GIP-101/TAF-C01"; + } + } + else if (data.length() == FINE3_STATUS_STRING_LENGTH) + { + model_ = FINE3; // FINE-503 + g_ZinfoDivision = "No division for fine controllers"; + g_ZStageController = "Fine-503"; + } + else if (data.length() == SHOT2_STATUS_STRING_LENGTH) + { + model_ = SHOT2; // SHOT-302GS, SHOT-702 + g_ZinfoDivision = "Set Division Of Shot-2Axis"; + g_ZStageController = "SHOT-302GS/SHOT-702"; + } + else if (data.length() == SHOT4_STATUS_STRING_LENGTH) + { + model_ = SHOT4; // SHOT-304GS + g_ZinfoDivision = "Set Division Of Shot-304"; + g_ZStageController = "SHOT-304GS"; + channel_ = "3"; + } + else + { + //Get product name + string name = "unknown"; + ret = SendRecieve("?:N", name); + if (ret != DEVICE_OK) { return ret; } + + // remove white spaces + name.erase(std::remove_if(name.begin(), name.end(), isspace), name.end()); + + if (strcmp(name.c_str(), "HSC-103") == 0) + { + model_ = HSC3; // HSC-103 + g_ZinfoDivision = "No division setting for HSC controller|fixed to 40"; + g_ZStageController = "HSC-103"; + channel_ = "3"; + } + else if (strcmp(name.c_str(), "SHRC-203") == 0) + { + model_ = SHRC3; // SHRC-203 + g_ZinfoDivision = "Set Division Of SHRC-203"; + g_ZStageController = "SHRC-203"; + channel_ = "3"; + string mode = ""; + //MODE:HOST (to be confirmed) + //FMT:HIT + ret = SendRecieve("?:FMT", mode); + if (ret != DEVICE_OK) { return ret; } + + if (mode != "HIT") + { + SendCheckRecievedOK("FMT:HIT"); + if (ret != DEVICE_OK) { return ret; } + } + } + + } + + return DEVICE_OK; +} + +/// +/// Creating a Division list in prop. +/// +/// +void ZStage::CreateDivisionProp() +{ + // Clear all allowed value declared before.-------------------------------------------------------------------------------------------- + ClearAllowedValues(g_ZStageDivision); + AddAllowedDivisionPropXY(g_ZStageDivision); // Added 9��12��2022 t.abed +} + +/// +/// Add division prop for Z (reduce size) +/// +/// +void ZStage::AddAllowedDivisionPropXY(const char* div) +{ + switch (model_) + { + case ZStage::SHOT1:case ZStage::SHOT2:case ZStage::SHOT4: + // Division Z + AddAllowedValue(div, "1"); + AddAllowedValue(div, "2"); + AddAllowedValue(div, "4"); + AddAllowedValue(div, "5"); + AddAllowedValue(div, "8"); + AddAllowedValue(div, "10"); + AddAllowedValue(div, "20"); + AddAllowedValue(div, "25"); + AddAllowedValue(div, "40"); + AddAllowedValue(div, "50"); + AddAllowedValue(div, "80"); + AddAllowedValue(div, "100"); + AddAllowedValue(div, "125"); + AddAllowedValue(div, "200"); + AddAllowedValue(div, "250"); + break; + case ZStage::FINE1:case ZStage::FINE3: + AddAllowedValue(div, "200"); + break; + case ZStage::HSC3: + AddAllowedValue(div, "40"); + break; + case ZStage::SHRC3: + for (int i = 1; i <= 6; i++) // Add from 1 to 6 + { + AddAllowedValue(div, to_string(i).c_str()); + } + AddAllowedValue(div, "8"); + AddAllowedValue(div, "12"); + AddAllowedValue(div, "25"); + for (int i = 1; i < 60; i++) // Add from 10 to 60 + { + i += 9; + AddAllowedValue(div, to_string(i).c_str()); + } + AddAllowedValue(div, "80"); + AddAllowedValue(div, "120"); + AddAllowedValue(div, "125"); + AddAllowedValue(div, "250"); + for (int i = 1; i < 400; i++) // add from 100 to 400 + { + i += 99; + AddAllowedValue(div, to_string(i).c_str()); + } + for (int i = 600; i <= 1000; i++) // add from 600 to 1000 + { + int k = i; + AddAllowedValue(div, to_string(k).c_str()); + i = i + 199; + } + for (int i = 1000; i <= 8000; i++) // add from 1000 to 8000 + { + int l = i; + AddAllowedValue(div, to_string(l).c_str()); + i = i + i - 1; + } + break; + default: + break; + } + +} + +/// +/// Create allowed channel in prop +/// +void ZStage::CreateChanelProp() +{ + if (model_ == SHOT1 || model_ == FINE1) + { + AddAllowedValue(g_ZStageChannel, "1"); + } + else if (model_ == FINE3 || model_ == HSC3 || model_ == SHRC3) + { + for (int i = 1; i <= 3; i++) + { + AddAllowedValue(g_ZStageChannel, to_string(i).c_str()); + } + } + else if (model_ == SHOT2) + { + for (int i = 1; i <= 2; i++) + { + AddAllowedValue(g_ZStageChannel, to_string(i).c_str()); + } + } + else + { + for (int i = 1; i <= 4; i++) + { + AddAllowedValue(g_ZStageChannel, to_string(i).c_str()); + } + } +} + +/// +/// Set Speed +/// +/// +/// +int ZStage::SetSpeed(int val) +{ + //First Clear serial port from previous stuff + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + long pulse_fast; + long pulse_slow = 0; + + // Setting the speed pulse. + pulse_fast = (long)(val / stepSizeZum_); + + //Speed(F) [PPS] + if (pulse_fast < 1 || pulse_fast > 500000) { return ERR_ZSTAGE_SPEED_FAILED; } + + //Speed(S) [PPS] + pulse_slow = GetSlowSpeedPulse(pulse_fast); + + // Create command + // NOTE: Acceleration and Deceleration time fixed to 100 msec. + string cmd; + if (model_ == HSC3|| model_==SHRC3) + { + cmd = "D:" + channel_ + "," + to_string(pulse_slow) + "," + to_string(pulse_fast) + ",100"; + } + else + { + cmd = "D:" +channel_ + "S" + to_string(pulse_slow) + "F" + to_string(pulse_fast) + "R100"; + } + + // Send command + ret = SendCheckRecievedOK(cmd); + if (ret != DEVICE_OK) + return ret; + return DEVICE_OK; +} + +int ZStage::UpdatePositionZ() +{ + //First Clear serial port from previous stuff-------------------------------------------------------------------------------------------------------- + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + // Send command & Recieve position data-------------------------------------------------------------------------------------------------------------- + string status = ""; + ret = SendRecieve("Q:", status); + if (ret != DEVICE_OK) + return ret; + // delete spaces + status.erase(std::remove_if(status.begin(), status.end(), ::isspace), status.end()); + + // split status by comma ---------------------------------------------------------------------------------------------------------------------------- + // ','-separated array + vector result = split(status, ','); + + int AxisZ = stoi(channel_) - 1; + // get position in steps depends controller --------------------------------------------------------------------------------------------------------- + switch (model_) + { + case ZStage::SHOT1: + stepsZ_ = atol(result[AxisZ].c_str()); + break; + case ZStage::SHOT2: + stepsZ_ = atol(result[AxisZ].c_str()); + break; + case ZStage::SHOT4: + stepsZ_ = atol(result[AxisZ].c_str()); + break; + case ZStage::FINE1: + stepsZ_ = atol(result[AxisZ].c_str()); + break; + case ZStage::FINE3: + stepsZ_ = atol(result[AxisZ].c_str()); + break; + case ZStage::HSC3: + stepsZ_ = atol(result[AxisZ].c_str()); + break; + case ZStage::SHRC3: + stepsZ_ = atol(result[AxisZ].c_str()); + break; + default: + stepsZ_ = 0.0; + break; + } + return DEVICE_OK; +} + +/// +/// Drive Command (Absolue Drive only) +/// +/// +/// +int ZStage::DriveCommadProcessZ(double position) +{ + // First Clear serial port from previous stuff------------------------------------------------------------------------------------------------------- + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + + // Setting the driving direction---------------------------------------------------------------------------------------------------- + string sign; + if (position >= 0) { sign = '+'; } + else { sign = '-'; } + + // Create command parameters---------------------------------------------------------------------------------------------------- + string cmd = ""; + long pos_pulse = 0; + long pos_nano = 0; + + // Create command depends controller------------------------------------------------------------------------------------------------ + switch (model_) + { + case ZStage::SHOT1: + pos_pulse = (long)(position / stepSizeZum_); //micron -> pulse + cmd = "A:" + channel_ + sign + "P" + to_string(abs(pos_pulse)); + break; + case ZStage::SHOT2:case ZStage::SHOT4: + if (controlMode_ == g_ZStageOpenControl) + { + pos_pulse = (long)(position / stepSizeZum_); //micron -> pulse + cmd = "A:" + channel_ + sign + "P" + to_string(abs(pos_pulse)); + } + else if (controlMode_ == g_ZStageCloseControl) + { + double d = abs(position); + char pos_micro[256] = { '\0' }; + sprintf(pos_micro, "%.*f", 2, d); //micron -> micron + cmd = "A:" + channel_ + sign + "P" + pos_micro; + } + break; + case ZStage::FINE1:case ZStage::FINE3: + pos_nano = (long)(position * 1000); //micron -> nano + cmd = "A:" + channel_ + sign + "P" + to_string(abs(pos_nano)); + break; + case ZStage::HSC3:case ZStage::SHRC3: + + if (model_ == HSC3) { + pos_pulse = (long)(position / 0.01); //micron -> pulse + } + else { + pos_pulse = (long)(position / stepSizeZum_); //micron -> pulse + } + + cmd = "A:"; + for (int i = 1; i <= 3; i++) + { + if (i == stoi(channel_)) + { + cmd += sign + to_string(abs(pos_pulse)); + } + + if (i != 3) + { + cmd += ","; + } + } + //cmd = "A:,," + to_string(abs(pos_pulse)); + break; + default: + break; + } + // Send command parameters// Recieve data--------------------------------------------------------------- + + ret = SendCheckRecievedOK(cmd); + if (ret != DEVICE_OK) + return ret; + switch (model_) + { + case ZStage::SHOT1:case ZStage::SHOT2:case ZStage::SHOT4:case ZStage::FINE1:case ZStage::FINE3: + ret = SendCheckRecievedOK("G:"); + if (ret != DEVICE_OK) + return ret; + break; + case ZStage::HSC3:case ZStage::SHRC3: + break; + default: + break; + } + + + return DEVICE_OK; +} + +/// +/// Set division for Z stage +/// +/// +/// +int ZStage::SetDivision(int division) +{ + //First Clear serial port from previous stuff----------------------------------------------------------------------------------------------------- + int ret = ClearPort(); + if (ret != DEVICE_OK) + return ret; + // Create divsion set command--------------------------------------------------------------------------------------------------------------------- + + if (model_ == SHRC3) + { + if (channel_ == "1") { ret = SendCheckRecievedOK("S:" + to_string(division) + ",,"); } + else if (channel_ == "2") { ret = SendCheckRecievedOK("S:," + to_string(division) + ","); } + else if (channel_ == "3") { ret = SendCheckRecievedOK("S:,," + to_string(division)); } + if (ret != DEVICE_OK) + return ret; + } + else + { + ret = SendCheckRecievedOK("S:" + channel_ + to_string(division)); + if (ret != DEVICE_OK) + return ret; + } + + return DEVICE_OK; +} + + +/// +/// Getting the value of a slow-speed pulse +/// +/// +/// +long ZStage::GetSlowSpeedPulse(long pls_vxy) +{ + long pls_slow; + + if (pls_vxy <= 50000) { pls_slow = pls_vxy / 2; } + else { pls_slow = 30000; } + + return pls_slow; +} + diff --git a/DeviceAdapters/SigmaKoki/ZStage.h b/DeviceAdapters/SigmaKoki/ZStage.h new file mode 100644 index 000000000..544763649 --- /dev/null +++ b/DeviceAdapters/SigmaKoki/ZStage.h @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ZStage.h +// PROJECT: Micro-Manager 2.0 +// SUBSYSTEM: DeviceAdapters +// +//----------------------------------------------------------------------------- +// DESCRIPTION: SIGMA-KOKI device adapter 2.0 +// +// AUTHOR : Hiroki Kibata, Abed Toufik Release Date : 05/02/2023 +// +// COPYRIGHT: SIGMA KOKI CO.,LTD, Tokyo, 2023 +#pragma once + +#include "SigmaBase.h" +extern const char* g_ZStageDeviceName; + +class ZStage : public CStageBase, public SigmaBase +{ +public: + ZStage(); + ~ZStage(); + + // Device API + // ---------- + bool Busy(); + void GetName(char* pszName) const; + int Initialize(); + int Shutdown(); + + // Stage API + // --------- + int GetPositionUm(double& pos); + int GetPositionSteps(long& steps); + int SetPositionUm(double pos); + int SetPositionSteps(long steps) { return DEVICE_OK; }; + int SetOrigin(); + int GetLimits(double& min, double& max); + + int IsStageSequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; } + bool IsContinuousFocusDrive() const { return false; } + + // Action Interface + // ---------------- + int OnPort(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnChannel(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnFullStepSize(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnStepSizeZ(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnDivision(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnSpeed(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnControlModel(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnPulseRateZ(MM::PropertyBase* pProp, MM::ActionType eAct); +private: + /// + /// Controller Model + /// + enum ZStageModel + { + SHOT1, //GIP-101, TAF-C01 + SHOT2, //SHOT-702, 302GS + SHOT4, //SHOT-304GS + FINE1, //FINE-01 + FINE3, //FINE-503 + HSC3, //HSC-103 + SHRC3 //HRSC-203 change to SHRC + }; + + int SetDeviceModel(); // change from [ SetDeviceModel(XYStageModel& model)] no needed + void CreateDivisionProp(); + void AddAllowedDivisionPropXY(const char* div); // Added 5��12��2022 t.abed + void CreateChanelProp(); + int SetDivision(int division); + int SetSpeed(int val); + int UpdatePositionZ(); // Added 4��7��2022�@�@�@t.abed + int DriveCommadProcessZ(double position);// Added 4��7��2022 t.abed + long GetSlowSpeedPulse(long pls); + + ZStageModel model_; + std::string controlMode_; + std::string channel_; + int speed_; + double stepsZ_; // Z stage current position Added 4��7��2022 t.abed + double fullstepSizeZum_; + double stepSizeZum_; + std::string divisionZ_; + double answerTimeoutMs_; + int PlsRateZ; +}; + diff --git a/DeviceAdapters/SigmaKoki/license.txt b/DeviceAdapters/SigmaKoki/license.txt new file mode 100644 index 000000000..8156247a9 --- /dev/null +++ b/DeviceAdapters/SigmaKoki/license.txt @@ -0,0 +1,28 @@ +COPYRIGHT(c) 2023, SIGMA KOKI CO.,LTD, Tokyo, +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and +the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. The names 'SIGMA KOKI' may not be used to endorse or promote +products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 007059f38014fcf0a1c222773ac6c6ffc4e6f13d Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Fri, 10 Feb 2023 16:57:18 -0600 Subject: [PATCH 2/4] SigmaKoki: Fixes for current MMDevice MMTime API --- DeviceAdapters/SigmaKoki/Camera.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/DeviceAdapters/SigmaKoki/Camera.cpp b/DeviceAdapters/SigmaKoki/Camera.cpp index bfdc1375c..2b24cd315 100644 --- a/DeviceAdapters/SigmaKoki/Camera.cpp +++ b/DeviceAdapters/SigmaKoki/Camera.cpp @@ -950,7 +950,6 @@ int Camera::InsertImage() // Important: metadata about the image are generated here: Metadata md; md.put("Camera", label); - md.put(MM::g_Keyword_Metadata_StartTime, CDeviceUtils::ConvertToString(sequenceStartTime_.getMsec())); md.put(MM::g_Keyword_Elapsed_Time_ms, CDeviceUtils::ConvertToString((timeStamp - sequenceStartTime_).getMsec())); md.put(MM::g_Keyword_Metadata_ImageNumber, CDeviceUtils::ConvertToString(imageCounter_)); @@ -1062,9 +1061,9 @@ void MySequenceThread::Start(long numImages, double intervalMs) stop_ = false; suspend_ = false; activate(); - actualDuration_ = 0; + actualDuration_ = MM::MMTime{}; startTime_ = camera_->GetCurrentMMTime(); - lastFrameTime_ = 0; + lastFrameTime_ = MM::MMTime{}; } bool MySequenceThread::IsStopped() { From 4467769be35a05699637790167874869ba8d0911 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Fri, 10 Feb 2023 16:58:48 -0600 Subject: [PATCH 3/4] SigmaKoki: Standardize project settings --- DeviceAdapters/SigmaKoki/Camera.cpp | 6 +- DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj | 106 ++---------------- .../SigmaKoki/SigmaKoki.vcxproj.filters | 31 ++--- 3 files changed, 26 insertions(+), 117 deletions(-) diff --git a/DeviceAdapters/SigmaKoki/Camera.cpp b/DeviceAdapters/SigmaKoki/Camera.cpp index 2b24cd315..f2ba1c37b 100644 --- a/DeviceAdapters/SigmaKoki/Camera.cpp +++ b/DeviceAdapters/SigmaKoki/Camera.cpp @@ -17,8 +17,12 @@ #include #include #include -#include "StCamD.h" #include "Camera.h" + +#define NOMINMAX +#include // Needed by StCamD.h +#include "StCamD.h" + using namespace std; // Constants diff --git a/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj index 1efcd562e..17c64ee25 100644 --- a/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj +++ b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj @@ -1,14 +1,6 @@ - - Debug - Win32 - - - Release - Win32 - Debug x64 @@ -27,24 +19,11 @@ 10.0 - - DynamicLibrary - true - v142 - <different options> - - - DynamicLibrary - false - v142 - true - Unicode - DynamicLibrary true v142 - <different options> + Unicode DynamicLibrary @@ -58,16 +37,6 @@ - - - - - - - - - - @@ -79,97 +48,41 @@ - - true - - - false - true - $(MM_BUILDDIR)\$(Configuration)\$(Platform)\ - $(MM_BUILDDIR)\intermediates\$(Configuration)\$(Platform)\$(ProjectName)\ - mmgr_dal_$(ProjectName) false - $(MM_BUILDDIR)\$(Configuration)\$(Platform)\ - $(MM_BUILDDIR)\intermediates\$(Configuration)\$(Platform)\$(ProjectName)\ - mmgr_dal_$(ProjectName) - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - %(AdditionalIncludeDirectories) - - - Console - true - %(AdditionalLibraryDirectories) - - - - - Level4 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(SolutionDir)MMDevice - - - Console - true - true - true - %(AdditionalLibraryDirectories);$(ProjectDir)\Camera_Lib\x86 - StCamD.lib;%(AdditionalDependencies) - - - Level4 WIN32;_DEBUG;_WINDOWS;_USRDLL;MODULE_EXPORTS;%(PreprocessorDefinitions) - true 4127;4290;%(DisableSpecificWarnings) - Default - %(AdditionalIncludeDirectories) + $(MM_3RDPARTYPRIVATE)\Sentech\StCamUSBPack_EN_220919\2_SDK\StandardSDK(v3.17)\StandardSDK(v3.17)\include;%(AdditionalIncludeDirectories) - Console - true - C:\Users\t.abed\Desktop\Micromanger test part 1\build\Release\x64;%(AdditionalLibraryDirectories) - $(OutDir)StCamD.lib;StCamD.lib + Windows + $(MM_3RDPARTYPRIVATE)\Sentech\StCamUSBPack_EN_220919\2_SDK\StandardSDK(v3.17)\StandardSDK(v3.17)\Lib\x64;%(AdditionalLibraryDirectories) + StCamD.lib;%(AdditionalDependencies) - Level4 true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MODULE_EXPORTS;%(PreprocessorDefinitions) 4127;4290;%(DisableSpecificWarnings) - $(SolutionDir)MMDevice - true + $(MM_3RDPARTYPRIVATE)\Sentech\StCamUSBPack_EN_220919\2_SDK\StandardSDK(v3.17)\StandardSDK(v3.17)\include;%(AdditionalIncludeDirectories) - Console + Windows true true - true - %(AdditionalLibraryDirectories);$(ProjectDir)\Camera_Lib\x64 + $(MM_3RDPARTYPRIVATE)\Sentech\StCamUSBPack_EN_220919\2_SDK\StandardSDK(v3.17)\StandardSDK(v3.17)\Lib\x64;%(AdditionalLibraryDirectories) StCamD.lib;%(AdditionalDependencies) - - xcopy/y "$(OutputPath)mmgr_dal_$(ProjectName)$(TargetExt)" "C:\Program Files\Micro-Manager-2.0" - @@ -182,7 +95,6 @@ - diff --git a/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters index e8418be7c..64c23467f 100644 --- a/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters +++ b/DeviceAdapters/SigmaKoki/SigmaKoki.vcxproj.filters @@ -1,54 +1,47 @@  - + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - + {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - ソース ファイル + Source Files - ソース ファイル + Source Files - ソース ファイル + Source Files - ソース ファイル + Source Files - ソース ファイル + Source Files - ヘッダー ファイル + Header Files - ヘッダー ファイル + Header Files - ヘッダー ファイル + Header Files - ヘッダー ファイル - - - ヘッダー ファイル + Header Files - ヘッダー ファイル + Header Files \ No newline at end of file From fa9cf378a09a73e9ddecdbacb3cf1210474b8e1e Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Fri, 10 Feb 2023 17:36:15 -0600 Subject: [PATCH 4/4] SigmaKoki: Add to build; remove old secret version --- micromanager.sln | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/micromanager.sln b/micromanager.sln index 035df83da..3a0e4856a 100644 --- a/micromanager.sln +++ b/micromanager.sln @@ -232,8 +232,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Toptica_iChrome_MLE_TCP", " EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AxioCam", "SecretDeviceAdapters\AxioCam\AxioCam.vcxproj", "{91CCB72B-852D-47D8-82FA-0E19A300A125}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SigmaKoki", "SecretDeviceAdapters\SigmaKoki\SigmaKoki.vcxproj", "{AC1AF894-E294-4A99-B8D1-1D7F5073B758}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Standa", "DeviceAdapters\Standa\Standa.vcxproj", "{1995D553-BABB-4987-A0AC-84496297DDE5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FLICamera", "DeviceAdapters\FLICamera\FLICamera.vcxproj", "{4FFC5AC3-7A59-40C2-B155-AA3EA5D391AE}" @@ -456,6 +454,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MicroFPGA", "DeviceAdapters EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SequenceTester", "DeviceAdapters\SequenceTester\SequenceTester.vcxproj", "{7ECDC9D5-626B-4F5B-AD3D-E6EF249BAA6E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SigmaKoki", "DeviceAdapters\SigmaKoki\SigmaKoki.vcxproj", "{39655236-2634-4ED3-AACD-0C9B032F805C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -922,10 +922,6 @@ Global {91CCB72B-852D-47D8-82FA-0E19A300A125}.Debug|x64.Build.0 = Debug|x64 {91CCB72B-852D-47D8-82FA-0E19A300A125}.Release|x64.ActiveCfg = Release|x64 {91CCB72B-852D-47D8-82FA-0E19A300A125}.Release|x64.Build.0 = Release|x64 - {AC1AF894-E294-4A99-B8D1-1D7F5073B758}.Debug|x64.ActiveCfg = Debug|x64 - {AC1AF894-E294-4A99-B8D1-1D7F5073B758}.Debug|x64.Build.0 = Debug|x64 - {AC1AF894-E294-4A99-B8D1-1D7F5073B758}.Release|x64.ActiveCfg = Release|x64 - {AC1AF894-E294-4A99-B8D1-1D7F5073B758}.Release|x64.Build.0 = Release|x64 {1995D553-BABB-4987-A0AC-84496297DDE5}.Debug|x64.ActiveCfg = Debug|x64 {1995D553-BABB-4987-A0AC-84496297DDE5}.Debug|x64.Build.0 = Debug|x64 {1995D553-BABB-4987-A0AC-84496297DDE5}.Release|x64.ActiveCfg = Release|x64 @@ -1370,6 +1366,10 @@ Global {7ECDC9D5-626B-4F5B-AD3D-E6EF249BAA6E}.Debug|x64.Build.0 = Debug|x64 {7ECDC9D5-626B-4F5B-AD3D-E6EF249BAA6E}.Release|x64.ActiveCfg = Release|x64 {7ECDC9D5-626B-4F5B-AD3D-E6EF249BAA6E}.Release|x64.Build.0 = Release|x64 + {39655236-2634-4ED3-AACD-0C9B032F805C}.Debug|x64.ActiveCfg = Debug|x64 + {39655236-2634-4ED3-AACD-0C9B032F805C}.Debug|x64.Build.0 = Debug|x64 + {39655236-2634-4ED3-AACD-0C9B032F805C}.Release|x64.ActiveCfg = Release|x64 + {39655236-2634-4ED3-AACD-0C9B032F805C}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE