From 8486ec64c4c0db1464ea81195e5614403dc2945b Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 20 Jul 2020 15:56:38 -0500 Subject: [PATCH 1/5] Add original version of Teledyne Dalsa GigE driver Author: Robert Frazee --- .../TeledyneDalsaGigE/GigENano.vcxproj | 165 ++++ .../GigENano.vcxproj.filters | 30 + .../TeledyneDalsaGigE/TestCamera.cpp | 859 ++++++++++++++++++ DeviceAdapters/TeledyneDalsaGigE/TestCamera.h | 154 ++++ 4 files changed, 1208 insertions(+) create mode 100644 DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj create mode 100644 DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj.filters create mode 100644 DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp create mode 100644 DeviceAdapters/TeledyneDalsaGigE/TestCamera.h diff --git a/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj b/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj new file mode 100644 index 0000000000..b9293c17ad --- /dev/null +++ b/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj @@ -0,0 +1,165 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {DE209272-1DA7-4551-9D34-3ECE99DDE827} + Win32Proj + GigENano + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + true + Unicode + Windows7.1SDK + + + DynamicLibrary + false + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;GIGENANO_EXPORTS;%(PreprocessorDefinitions) + $(SAPERADIR)\Include;$(SAPERADIR)\Classes\Basic;%(AdditionalIncludeDirectories) + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;GIGENANO_EXPORTS;%(PreprocessorDefinitions) + $(SAPERADIR)\Include;$(SAPERADIR)\Classes\Basic;%(AdditionalIncludeDirectories) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;GIGENANO_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;GIGENANO_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + + + + + + + + + {b8c95f39-54bf-40a9-807b-598df2821d55} + + + + + + \ No newline at end of file diff --git a/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj.filters b/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj.filters new file mode 100644 index 0000000000..65fa98af31 --- /dev/null +++ b/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;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 + + + + + Header Files + + + + + Source Files + + + + + + \ No newline at end of file diff --git a/DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp b/DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp new file mode 100644 index 0000000000..a8282e4fec --- /dev/null +++ b/DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp @@ -0,0 +1,859 @@ +///////////////////////////////////////////////////////// +// FILE: TestCamera.cpp +// PROJECT: Teledyne DALSA Micro-Manager Glue Library +//------------------------------------------------------- +// AUTHOR: Robert Frazee, rfraze1@lsu.edu + +#include "TestCamera.h" +#include "../MMDevice/ModuleInterface.h" +#include "stdio.h" +#include "conio.h" +#include "math.h" +#include "sapclassbasic.h" +#include + +using namespace std; + +const char* g_CameraName = "GigE Nano"; +const char* g_PixelType_8bit = "8bit"; +const char* g_PixelType_10bit = "10bit"; +const char* g_PixelType_12bit = "12bit"; + +const char* g_CameraModelProperty = "Model"; +const char* g_CameraModel_A = "Nano-M1930-NIR"; + +// g_CameraAcqDeviceNumberProperty +// g_CameraServerNameProperty +// g_CameraConfigFilenameProperty +const char* g_CameraAcqDeviceNumberProperty = "Acquisition Device Number"; +const char* g_CameraAcqDeviceNumber_Def = "0"; +const char* g_CameraServerNameProperty = "Server Name"; +const char* g_CameraServerName_Def = "Nano-M1930-NIR_1"; +const char* g_CameraConfigFilenameProperty = "Config Filename"; +const char* g_CameraConfigFilename_Def = "NoFile"; + + +/////////////////////////////////////////////////////////////////////////////// +// Exported MMDevice API +/////////////////////////////////////////////////////////////////////////////// + +/** + * List all supported hardware devices here + */ +MODULE_API void InitializeModuleData() +{ + RegisterDevice(g_CameraName, MM::CameraDevice, "GigE Nano Camera Device"); +} + +MODULE_API MM::Device* CreateDevice(const char* deviceName) +{ + if (deviceName == 0) + return 0; + + // decide which device class to create based on the deviceName parameter + if (strcmp(deviceName, g_CameraName) == 0) + { + // create camera + return new TestCamera(); + } + + // ...supplied name not recognized + // to heck with it, return a device anyway + return new TestCamera(); +} + +MODULE_API void DeleteDevice(MM::Device* pDevice) +{ + delete pDevice; +} + +/////////////////////////////////////////////////////////////////////////////// +// TestCamera implementation +// ~~~~~~~~~~~~~~~~~~~~~~~ + +/** +* TestCamera 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. +*/ +TestCamera::TestCamera() : + binning_ (1), + gain_(1), + bytesPerPixel_(1), + bitsPerPixel_(8), + initialized_(false), + roiX_(0), + roiY_(0), + thd_(0), + sequenceRunning_(false), + SapFormatBytes_(1) +{ + // call the base class method to set-up default error codes/messages + InitializeDefaultErrorMessages(); + + // Description property + int ret = CreateProperty(MM::g_Keyword_Description, "GigE Nano Camera Adapter", MM::String, true); + assert(ret == DEVICE_OK); + + // camera type pre-initialization property + ret = CreateProperty(g_CameraModelProperty, g_CameraModel_A, MM::String, false, 0, true); + assert(ret == DEVICE_OK); + + vector modelValues; + modelValues.push_back(g_CameraModel_A); + modelValues.push_back(g_CameraModel_A); + + ret = SetAllowedValues(g_CameraModelProperty, modelValues); + assert(ret == DEVICE_OK); + + // Sapera++ library stuff + + int serverCount = SapManager::GetServerCount(); + if(serverCount == 0) + { + ErrorBox((LPCWSTR)L"Initialization Error", (LPCWSTR)L"No servers!"); + } + + acqServerName_ = new char[CORSERVER_MAX_STRLEN]; + configFilename_ = new char[MAX_PATH]; + + ret = CreateProperty(g_CameraAcqDeviceNumberProperty, g_CameraAcqDeviceNumber_Def, MM::Integer, false, 0, true); + assert(ret == DEVICE_OK); + + ret = CreateProperty(g_CameraServerNameProperty, g_CameraServerName_Def, MM::String, false, 0, true); + assert(ret == DEVICE_OK); + + ret = CreateProperty(g_CameraConfigFilenameProperty, g_CameraConfigFilename_Def, MM::String, false, 0, true); + assert(ret == DEVICE_OK); + + // create live video thread + thd_ = new SequenceThread(this); +} + +/** +* TestCamera destructor. +* If this device used as intended within the Micro-Manager system, +* Shutdown() will be always called before the destructor. But in any case +* we need to make sure that all resources are properly released even if +* Shutdown() was not called. +*/ +TestCamera::~TestCamera() +{ + if (initialized_) + Shutdown(); +} + +/** +* Obtains device name. +* Required by the MM::Device API. +*/ +void TestCamera::GetName(char* name) const +{ + // We just return the name we use for referring to this + // device adapter. + CDeviceUtils::CopyLimitedString(name, g_CameraName); +} + +/** +* Intializes the hardware. +* Typically we access and initialize hardware at this point. +* Device properties are typically created here as well. +* Required by the MM::Device API. +*/ +int TestCamera::Initialize() +{ + if (initialized_) + return DEVICE_OK; + + //SapManager::DisplayMessage("This plugin logs debug messages. Press no so they don't all pop up like this."); + // set property list + // ----------------- + + // binning + CPropertyAction *pAct = new CPropertyAction (this, &TestCamera::OnBinning); + //@TODO: Check what the actual binning value is and set that + // For now, set binning to 1 for MM and set that on the camera later + int ret = CreateProperty(MM::g_Keyword_Binning, "1", MM::Integer, false, pAct); + assert(ret == DEVICE_OK); + + vector binningValues; + binningValues.push_back("1"); + binningValues.push_back("2"); + binningValues.push_back("4"); + + ret = SetAllowedValues(MM::g_Keyword_Binning, binningValues); + assert(ret == DEVICE_OK); + + //Sapera stuff + // g_CameraAcqDeviceNumberProperty + // g_CameraServerNameProperty + // g_CameraConfigFilenameProperty + long tmpDeviceNumber; + if(GetProperty(g_CameraAcqDeviceNumberProperty, tmpDeviceNumber) != DEVICE_OK) + { + //SapManager::DisplayMessage("Failed to retrieve AcqDeviceNumberProperty"); + return DEVICE_ERR; + } + acqDeviceNumber_ = (UINT32)tmpDeviceNumber; + + if(false)//GetProperty(g_CameraServerNameProperty, acqServerName_) != DEVICE_OK) + { + //SapManager::DisplayMessage("Failed to retrieve ServerNameProperty"); + return DEVICE_ERR; + } + acqServerName_ = (char *)g_CameraServerName_Def; + + if(false)//GetProperty(g_CameraConfigFilenameProperty, configFilename_) != DEVICE_OK) + { + //SapManager::DisplayMessage("Failed to retrieve ConfigFilenameProperty"); + return DEVICE_ERR; + } + configFilename_ = "NoFile"; + + //SapManager::DisplayMessage("(Sapera app)Creating loc_ object"); + SapLocation loc_(acqServerName_, acqDeviceNumber_); + //SapManager::DisplayMessage("(Sapera app)Created loc_ object"); + //SapManager::DisplayMessage("(Sapera app)GetResourceCount for ResourceAcqDevice starting"); + if(SapManager::GetResourceCount(acqServerName_, SapManager::ResourceAcqDevice) > 0) + { + //SapManager::DisplayMessage("(Sapera app)GetResourceCount for ResourceAcqDevice found something"); + if(strcmp(configFilename_, "NoFile") == 0) + AcqDevice_ = SapAcqDevice(loc_, false); + else + AcqDevice_ = SapAcqDevice(loc_, configFilename_); + + Buffers_ = SapBufferWithTrash(2, &AcqDevice_); + AcqDeviceToBuf_ = SapAcqDeviceToBuf(&AcqDevice_, &Buffers_); + Xfer_ = &AcqDeviceToBuf_; + + if(!AcqDevice_.Create()) + { + ret = FreeHandles(); + if (ret != DEVICE_OK) + { + //SapManager::DisplayMessage("Failed to FreeHandles during Acq_.Create() for ResourceAcqDevice"); + return ret; + } + //SapManager::DisplayMessage("Failed to create Acq_ for ResourceAcqDevice"); + return DEVICE_INVALID_INPUT_PARAM; + } + } + //SapManager::DisplayMessage("(Sapera app)GetResourceCount for ResourceAcqDevice done"); + //SapManager::DisplayMessage("(Sapera app)Creating Buffers_"); + if(!Buffers_.Create()) + { + ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_NATIVE_MODULE_FAILED; + } + //SapManager::DisplayMessage("(Sapera app)Creating Xfer_"); + if(Xfer_ && !Xfer_->Create()) + { + //SapManager::DisplayMessage("Xfer_ creation failed"); + ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_NATIVE_MODULE_FAILED; + } + //SapManager::DisplayMessage("(Sapera app)Starting Xfer"); + //Start continuous grab + //Xfer_->Grab(); + //SapManager::DisplayMessage("(Sapera app)Sapera Initialization for TestCamera complete"); + + if(!AcqDevice_.GetFeatureValue("ExposureTime", &exposureMs_)) + return DEVICE_ERR; + exposureMs_ = exposureMs_ / 1000; + + // synchronize bit depth with camera + + char acqFormat[10]; + AcqDevice_.GetFeatureValue("PixelFormat", acqFormat, 10); + if(strcmp(acqFormat, "Mono8") == 0) + { + // Setup Micro-Manager for 8bit pixels + SapFormatBytes_ = 1; + bitsPerPixel_ = 8; + bytesPerPixel_ = 1; + //resize the SapBuffer + int ret = SapBufferReformat(SapFormatMono8, "Mono8"); + if(ret != DEVICE_OK) + { + return ret; + } + ResizeImageBuffer(); + pAct = new CPropertyAction (this, &TestCamera::OnPixelType); + ret = CreateProperty(MM::g_Keyword_PixelType, g_PixelType_8bit, MM::String, false, pAct); + assert(ret == DEVICE_OK); + } + if(strcmp(acqFormat, "Mono10") == 0) + { + // Setup Micro-Manager for 8bit pixels + SapFormatBytes_ = 2; + bitsPerPixel_ = 10; + bytesPerPixel_ = 2; + //resize the SapBuffer + int ret = SapBufferReformat(SapFormatMono10, "Mono10"); + if(ret != DEVICE_OK) + { + return ret; + } + ResizeImageBuffer(); + pAct = new CPropertyAction (this, &TestCamera::OnPixelType); + ret = CreateProperty(MM::g_Keyword_PixelType, g_PixelType_10bit, MM::String, false, pAct); + assert(ret == DEVICE_OK); + } + + + // pixel type + + + vector pixelTypeValues; + pixelTypeValues.push_back(g_PixelType_8bit); + pixelTypeValues.push_back(g_PixelType_10bit); + + + ret = SetAllowedValues(MM::g_Keyword_PixelType, pixelTypeValues); + assert(ret == DEVICE_OK); + + // Set Binning to 1 + if(!AcqDevice_.SetFeatureValue("BinningVertical", 1)) + return DEVICE_ERR; + if(!AcqDevice_.SetFeatureValue("BinningHorizontal", 1)) + return DEVICE_ERR; + + + // Setup gain + pAct = new CPropertyAction(this, &TestCamera::OnGain); + ret = CreateProperty(MM::g_Keyword_Gain, "1.0", MM::Float, false, pAct); + assert(ret == DEVICE_OK); + if(!AcqDevice_.SetFeatureValue("Gain", 1.0)) + return DEVICE_ERR; + SapFeature SapGain_(loc_); + if(!SapGain_.Create()) + return DEVICE_ERR; + AcqDevice_.GetFeatureInfo("Gain", &SapGain_); + double g_low = 0.0; + double g_high = 0.0; + SapGain_.GetMax(&g_high); + SapGain_.GetMin(&g_low); + SetPropertyLimits(MM::g_Keyword_Gain, g_low, g_high); + + + + // 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. +* Ideally this method will completely unload the device and release all resources. +* Shutdown() may be called multiple times in a row. +* Required by the MM::Device API. +*/ +int TestCamera::Shutdown() +{ + if(!initialized_) + return DEVICE_OK; + initialized_ = false; + Xfer_->Freeze(); + if(!Xfer_->Wait(5000)) + return DEVICE_NATIVE_MODULE_FAILED; + int ret; + ret = FreeHandles(); + if(ret != DEVICE_OK) + return ret; + return DEVICE_OK; +} + +/** +* Frees Sapera buffers and such +*/ +int TestCamera::FreeHandles() +{ + if(Xfer_ && *Xfer_ && !Xfer_->Destroy()) return DEVICE_ERR; + if(!Buffers_.Destroy()) return DEVICE_ERR; + if(!Acq_.Destroy()) return DEVICE_ERR; + if(!AcqDevice_.Destroy()) return DEVICE_ERR; + return DEVICE_OK; +} + +int TestCamera::ErrorBox(LPCWSTR text, LPCWSTR caption) +{ + return MessageBox(NULL, caption, text, (MB_ICONERROR | MB_OK)); +} + +/** +* Performs exposure and grabs a single image. +* This function blocks during the actual exposure and returns immediately afterwards +* Required by the MM::Camera API. +*/ +int TestCamera::SnapImage() +{ + // This will always be false, as no sequences will ever run + if(sequenceRunning_) + return DEVICE_CAMERA_BUSY_ACQUIRING; + // Start image capture + if(!Xfer_->Snap(1)) + { + return DEVICE_ERR; + } + // Wait for either the capture to finish or 2.5 seconds, whichever is first + if(!Xfer_->Wait(2500)) + { + return DEVICE_ERR; + } + return DEVICE_OK; +} + +/** +* Returns pixel data. +* Required by the MM::Camera API. +* 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.) +*/ +const unsigned char* TestCamera::GetImageBuffer() +{ + // Put Sapera buffer into Micro-Manager Buffer + Buffers_.ReadRect(roiX_, roiY_, img_.Width(), img_.Height(), const_cast(img_.GetPixels())); + // Return location of the Micro-Manager Buffer + return const_cast(img_.GetPixels()); +} + +/** +* Returns image buffer X-size in pixels. +* Required by the MM::Camera API. +*/ +unsigned TestCamera::GetImageWidth() const +{ + return img_.Width(); +} + +/** +* Returns image buffer Y-size in pixels. +* Required by the MM::Camera API. +*/ +unsigned TestCamera::GetImageHeight() const +{ + return img_.Height(); +} + +/** +* Returns image buffer pixel depth in bytes. +* Required by the MM::Camera API. +*/ +unsigned TestCamera::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 TestCamera::GetBitDepth() const +{ + return bitsPerPixel_; +} + +/** +* Returns the size in bytes of the image buffer. +* Required by the MM::Camera API. +*/ +long TestCamera::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 TestCamera::SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) +{ + if (xSize == 0 && ySize == 0) + { + // effectively clear ROI + ResizeImageBuffer(); + roiX_ = 0; + roiY_ = 0; + } + else + { + // apply ROI + img_.Resize(xSize, ySize); + roiX_ = x; + roiY_ = y; + } + return DEVICE_OK; +} + +/** +* Returns the actual dimensions of the current ROI. +* Required by the MM::Camera API. +*/ +int TestCamera::GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize) +{ + x = roiX_; + y = roiY_; + + xSize = img_.Width(); + ySize = img_.Height(); + + return DEVICE_OK; +} + +/** +* Resets the Region of Interest to full frame. +* Required by the MM::Camera API. +*/ +int TestCamera::ClearROI() +{ + ResizeImageBuffer(); + roiX_ = 0; + roiY_ = 0; + + return DEVICE_OK; +} + +/** +* Returns the current exposure setting in milliseconds. +* Required by the MM::Camera API. +*/ +double TestCamera::GetExposure() const +{ + return exposureMs_; +} + +/** +* Sets exposure in milliseconds. +* Required by the MM::Camera API. +*/ +void TestCamera::SetExposure(double exp) +{ + exposureMs_ = exp; + // Micromanager deals with exposure time in ms + // Sapera deals with exposure time in us + // As such, we convert between the two + AcqDevice_.SetFeatureValue("ExposureTime", (exposureMs_ * 1000)); +} + +/** +* Returns the current binning factor. +* Required by the MM::Camera API. +*/ +int TestCamera::GetBinning() const +{ + return binning_; +} + +/** +* Sets binning factor. +* Required by the MM::Camera API. +*/ +int TestCamera::SetBinning(int binF) +{ + return SetProperty(MM::g_Keyword_Binning, CDeviceUtils::ConvertToString(binF)); +} + +int TestCamera::PrepareSequenceAcqusition() +{ + return DEVICE_ERR; +} + + +/** + * 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 TestCamera::StartSequenceAcquisition(double interval_ms) +{ + //@TODO: Implement Sequence Acquisition + return DEVICE_ERR; + //int ret = StartSequenceAcquisition((long)(interval_ms/exposureMs_), interval_ms, true); + //return ret; +} + +/** +* Stop and wait for the Sequence thread finished +*/ +int TestCamera::StopSequenceAcquisition() +{ + //@TODO: Implement Sequence Acquisition + return DEVICE_ERR; + /*thd_->Stop(); + thd_->wait(); + sequenceRunning_ = false; + 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 TestCamera::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) +{ + //@TODO: Implement Sequence Acquisition + return DEVICE_ERR; + /*if (sequenceRunning_) + { + return DEVICE_CAMERA_BUSY_ACQUIRING; + } + int ret = GetCoreCallback()->PrepareForAcq(this); + if (ret != DEVICE_OK) + { + return ret; + } + sequenceRunning_ = true; + thd_->SetLength(10); + thd_->Start(); + return DEVICE_OK; */ +} + +/* + * Inserts Image and MetaData into MMCore circular Buffer + */ +int TestCamera::InsertImage() +{ + //@TODO: Implement Sequence Acquisition + return GetCoreCallback()->InsertImage(this, const_cast(img_.GetPixels()), GetImageWidth(), GetImageHeight(), GetImageBytesPerPixel()); +} + + +bool TestCamera::IsCapturing() { + //@TODO: Implement Sequence Acquisition + return sequenceRunning_; +} + + +/////////////////////////////////////////////////////////////////////////////// +// TestCamera Action handlers +/////////////////////////////////////////////////////////////////////////////// + +/** +* Handles "Binning" property. +*/ +int TestCamera::OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + long binSize; + pProp->Get(binSize); + binning_ = (int)binSize; + if(!AcqDevice_.SetFeatureValue("BinningVertical", binning_)) + return DEVICE_ERR; + if(!AcqDevice_.SetFeatureValue("BinningHorizontal", binning_)) + return DEVICE_ERR; + return ResizeImageBuffer(); + } + else if (eAct == MM::BeforeGet) + { + pProp->Set((long)binning_); + } + + return DEVICE_OK; +} + +/** +* Handles "PixelType" property. +*/ +int TestCamera::OnPixelType(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + //bytesPerPixel_ = 1; + //ResizeImageBuffer(); + //return DEVICE_OK; + if (eAct == MM::AfterSet) + { + //SapManager::DisplayMessage("(Sapera app)OnPixelType MM:AfterSet"); + string val; + pProp->Get(val); + if (val.compare(g_PixelType_8bit) == 0) + { + if(SapFormatBytes_ != 1) + { + SapFormatBytes_ = 1; + bitsPerPixel_ = 8; + //resize the SapBuffer + int ret = SapBufferReformat(SapFormatMono8, "Mono8"); + if(ret != DEVICE_OK) + { + return ret; + } + } + bytesPerPixel_ = 1; + } + else if (val.compare(g_PixelType_10bit) == 0) + { + if(SapFormatBytes_ != 2) + { + SapFormatBytes_ = 2; + bitsPerPixel_ = 10; + //resize the SapBuffer + int ret = SapBufferReformat(SapFormatMono16, "Mono10"); + if(ret != DEVICE_OK) + { + return ret; + } + } + bytesPerPixel_ = 2; + } + else + assert(false); + + ResizeImageBuffer(); + } + else if (eAct == MM::BeforeGet) + { + if (bytesPerPixel_ == 1) + pProp->Set(g_PixelType_8bit); + else if (bytesPerPixel_ == 2) + pProp->Set(g_PixelType_10bit); + else + assert(false); // this should never happen + } + + return DEVICE_OK; +} + +/** +* Handles "Gain" property. +*/ +int TestCamera::OnGain(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + //SapManager::DisplayMessage("(Sapera app)OnGain MM:AfterSet"); + pProp->Get(gain_); + AcqDevice_.SetFeatureValue("Gain", gain_); + } + else if (eAct == MM::BeforeGet) + { + pProp->Set(gain_); + } + + return DEVICE_OK; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Private TestCamera methods +/////////////////////////////////////////////////////////////////////////////// + +/** +* Sync internal image buffer size to the chosen property values. +*/ +int TestCamera::ResizeImageBuffer() +{ + img_.Resize(IMAGE_WIDTH/binning_, IMAGE_HEIGHT/binning_, bytesPerPixel_); + + return DEVICE_OK; +} + +/** + * Generate an image with fixed value for all pixels + */ +void TestCamera::GenerateImage() +{ + const int maxValue = (1 << MAX_BIT_DEPTH) - 1; // max for the 12 bit camera + const double maxExp = 1000; + double step = maxValue/maxExp; + unsigned char* pBuf = const_cast(img_.GetPixels()); + memset(pBuf, (int) (step * max(exposureMs_, maxExp)), img_.Height()*img_.Width()*img_.Depth()); +} + +/* + * Reformat Sapera Buffer Object + */ +int TestCamera::SapBufferReformat(SapFormat format, const char * acqFormat) +{ + Xfer_->Destroy(); + AcqDevice_.SetFeatureValue("PixelFormat", acqFormat); + Buffers_.Destroy(); + Buffers_ = SapBufferWithTrash(2, &AcqDevice_); + Buffers_.SetFormat(format); + AcqDeviceToBuf_ = SapAcqDeviceToBuf(&AcqDevice_, &Buffers_); + Xfer_ = &AcqDeviceToBuf_; + if(!Buffers_.Create()) + { + //SapManager::DisplayMessage("Failed to recreate Buffer - SapBufferReformat"); + int ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_NATIVE_MODULE_FAILED; + } + if(Xfer_ && !Xfer_->Create()) + { + //SapManager::DisplayMessage("Xfer_ recreation failed - SapBufferReformat"); + int ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_NATIVE_MODULE_FAILED; + } + return DEVICE_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// Threading methods +/////////////////////////////////////////////////////////////////////////////// + +int SequenceThread::svc() +{ + //SapManager::DisplayMessage("SequenceThread Start"); + long count(0); + while (!stop_ )//&& count < numImages_) + { + /*int ret = camera_->SnapImage(); + if (ret != DEVICE_OK) + { + //SapManager::DisplayMessage("SequenceThread Snap failed"); + camera_->StopSequenceAcquisition(); + return 1; + }*/ + + int ret = camera_->InsertImage(); + if (ret != DEVICE_OK) + { + //SapManager::DisplayMessage("SequenceThread InsertFailed"); + camera_->StopSequenceAcquisition(); + return 1; + } + //count++; + } + //SapManager::DisplayMessage("SequenceThread End"); + return 0; +} \ No newline at end of file diff --git a/DeviceAdapters/TeledyneDalsaGigE/TestCamera.h b/DeviceAdapters/TeledyneDalsaGigE/TestCamera.h new file mode 100644 index 0000000000..b3808676e6 --- /dev/null +++ b/DeviceAdapters/TeledyneDalsaGigE/TestCamera.h @@ -0,0 +1,154 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: TestCamera.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Skeleton code for the micro-manager camera adapter. Use it as +// starting point for writing custom device adapters +// +// AUTHOR: Nenad Amodaj, http://nenad.amodaj.com +// +// COPYRIGHT: University of California, San Francisco, 2011 +// +// LICENSE: This file is distributed under the BSD license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// + +#ifndef _TestCamera_H_ +#define _TestCamera_H_ + +#include "DeviceBase.h" +#include "ImgBuffer.h" +#include "DeviceThreads.h" +#include "ImgBuffer.h" +#include "stdio.h" +#include "conio.h" +#include "math.h" +#include "sapclassbasic.h" +#include + +////////////////////////////////////////////////////////////////////////////// +// Error codes +// +#define ERR_UNKNOWN_MODE 102 + +class SequenceThread; + +class TestCamera : public CCameraBase +{ +public: + TestCamera(); + ~TestCamera(); + + // MMDevice API + // ------------ + int Initialize(); + int Shutdown(); + + void GetName(char* name) const; + + // TestCamera API + // ------------ + int SnapImage(); + const unsigned char* GetImageBuffer(); + unsigned GetImageWidth() const; + unsigned GetImageHeight() const; + unsigned GetImageBytesPerPixel() const; + unsigned GetBitDepth() const; + long GetImageBufferSize() const; + double GetExposure() const; + void SetExposure(double exp); + int SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize); + int GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize); + int ClearROI(); + int PrepareSequenceAcqusition(); + int StartSequenceAcquisition(double interval); + int StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow); + int StopSequenceAcquisition(); + bool IsCapturing(); + int GetBinning() const; + int SetBinning(int binSize); + int IsExposureSequenceable(bool& seq) const {seq = false; return DEVICE_OK;} + + // action interface + // ---------------- + int OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnPixelType(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnGain(MM::PropertyBase* pProp, MM::ActionType eAct); + +private: + friend class SequenceThread; + static const int IMAGE_WIDTH = 1920; + static const int IMAGE_HEIGHT = 1200; + static const int MAX_BIT_DEPTH = 12; + + SequenceThread* thd_; + int binning_; + int bytesPerPixel_; + int bitsPerPixel_; + double gain_; + double exposureMs_; + bool initialized_; + ImgBuffer img_; + int roiX_, roiY_; + bool sequenceRunning_; + + int ResizeImageBuffer(); + void GenerateImage(); + int InsertImage(); + + UINT32 acqDeviceNumber_; + char* acqServerName_; + char* configFilename_; + SapAcquisition Acq_; + SapAcqDevice AcqDevice_; + SapBufferWithTrash Buffers_; + SapTransfer AcqToBuf_; + SapTransfer AcqDeviceToBuf_; + SapTransfer* Xfer_; + SapLocation loc_; + SapFeature SapGain_; + int SapFormatBytes_; + + int FreeHandles(); + int ErrorBox(LPCWSTR text, LPCWSTR caption); + LPCWSTR TestCamera::string2winstring(const std::string& s); + int SapBufferReformat(SapFormat format, const char * acqFormat); +}; + + +//threading stuff. Tread lightly +class SequenceThread : public MMDeviceThreadBase +{ + public: + SequenceThread(TestCamera* pCam) : stop_(false), numImages_(0) {camera_ = pCam;} + ~SequenceThread() {} + + int svc (void); + + void Stop() {stop_ = true;} + + void Start() + { + stop_ = false; + activate(); + } + + void SetLength(long images) {numImages_ = images;} + long GetLength(void) {return numImages_;}; + + private: + TestCamera* camera_; + bool stop_; + long numImages_; +}; + +#endif //_TestCamera_H_ From fd22175ce3d256c9f3ec79dc6b8a3a52ea76bc47 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 20 Jul 2020 16:10:09 -0500 Subject: [PATCH 2/5] Updated driver - squashed commit - Update paths - Driver compiles - Minor changes in imports - Add temperature and device info - Rename TestCamera to SaperaGigE internally - Rename files and folders to SaperaGigE - Rename/add features - Remove hard-coded model description - Implement scanning for available cameralink servers - Add access to additional features - Add camera gain as property - Fix indents / reformat code - Update/fix binning property - Some reshuffling of content - Start working on image/roi shapes - Clean up pixel format selection - Update resizing of buffers - Simplify creation of properties based on device features - Improve driver handling/logging - Enable TurboDrive - Avoid crashes when hardware binning is not available - Update SaperaGigE specific tool chain elements --- DeviceAdapters/SaperaGigE/SaperaGigE.cpp | 1033 +++++++++++++++++ DeviceAdapters/SaperaGigE/SaperaGigE.h | 225 ++++ .../SaperaGigE.vcxproj} | 31 +- .../SaperaGigE.vcxproj.filters} | 14 +- .../TeledyneDalsaGigE/TestCamera.cpp | 859 -------------- DeviceAdapters/TeledyneDalsaGigE/TestCamera.h | 154 --- 6 files changed, 1281 insertions(+), 1035 deletions(-) create mode 100644 DeviceAdapters/SaperaGigE/SaperaGigE.cpp create mode 100644 DeviceAdapters/SaperaGigE/SaperaGigE.h rename DeviceAdapters/{TeledyneDalsaGigE/GigENano.vcxproj => SaperaGigE/SaperaGigE.vcxproj} (85%) rename DeviceAdapters/{TeledyneDalsaGigE/GigENano.vcxproj.filters => SaperaGigE/SaperaGigE.vcxproj.filters} (63%) delete mode 100644 DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp delete mode 100644 DeviceAdapters/TeledyneDalsaGigE/TestCamera.h diff --git a/DeviceAdapters/SaperaGigE/SaperaGigE.cpp b/DeviceAdapters/SaperaGigE/SaperaGigE.cpp new file mode 100644 index 0000000000..41f5852d32 --- /dev/null +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.cpp @@ -0,0 +1,1033 @@ +///////////////////////////////////////////////////////// +// FILE: SaperaGigE.cpp +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//------------------------------------------------------- +// DESCRIPTION: An adapter for Gigbit-Ethernet cameras using an +// SDK from JAI, Inc. Users and developers will +// need to download and install the JAI SDK and control tool. +// +// AUTHOR: Robert Frazee, rfraze1@lsu.edu +// Ingmar Schoegl, ischoegl@lsu.edu +// +// LICENSE: This file is distributed under the BSD license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. + +#include "SaperaGigE.h" + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////// +// Exported MMDevice API +/////////////////////////////////////////////////////////////////////////////// + +/** + * List all supported hardware devices here + */ +MODULE_API void InitializeModuleData() +{ + RegisterDevice(g_CameraDeviceName, MM::CameraDevice, "Sapera GigE camera device adapter"); +} + +MODULE_API MM::Device* CreateDevice(const char* deviceName) +{ + if (deviceName == 0) + return 0; + + // decide which device class to create based on the deviceName parameter + if (strcmp(deviceName, g_CameraDeviceName) == 0) + { + // create camera + return new SaperaGigE(); + } + + // ...supplied name not recognized + // to heck with it, return a device anyway + return new SaperaGigE(); +} + +MODULE_API void DeleteDevice(MM::Device* pDevice) +{ + delete pDevice; +} + +std::wstring s2ws(const std::string& s) +{ + int len; + int slength = (int)s.length() + 1; + len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); + wchar_t* buf = new wchar_t[len]; + MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); + std::wstring r(buf); + delete[] buf; + return r; +} + +int ErrorBox(std::string text, std::string caption) +{ + return MessageBox(NULL, s2ws(caption).c_str(), s2ws(text).c_str(), (MB_ICONERROR | MB_OK)); +} + +/////////////////////////////////////////////////////////////////////////////// +// SaperaGigE implementation +// ~~~~~~~~~~~~~~~~~~~~~~~ + +/** +* SaperaGigE 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. +*/ +SaperaGigE::SaperaGigE() : + bytesPerPixel_(1), + bitsPerPixel_(8), + initialized_(false), + thd_(0), + sequenceRunning_(false), + Roi_(NULL) +{ + // call the base class method to set-up default error codes/messages + InitializeDefaultErrorMessages(); + + CreateProperty(MM::g_Keyword_Name, g_CameraDeviceName, MM::String, true); + + // Sapera++ library stuff + if (!(SapManager::DetectAllServers(SapManager::DetectServerAll))) + { + LogMessage("No CameraLink camera servers detected", false); + activeDevice_ = ""; + return; + } + + int serverCount = SapManager::GetServerCount(); + char serverName[CORSERVER_MAX_STRLEN]; + for (int serverIndex = 0; serverIndex < serverCount; serverIndex++) + { + if (SapManager::GetResourceCount(serverIndex, SapManager::ResourceAcqDevice) != 0) + { + // Get Server Name Value + SapManager::GetServerName(serverIndex, serverName, sizeof(serverName)); + acqDeviceList_.push_back(serverName); + } + } + + if (acqDeviceList_.size() == 0) + { + activeDevice_ = ""; + return; + } + + // add available servers to property and set active device to first server in the list + CreateProperty(g_CameraServer, acqDeviceList_[0].c_str(), MM::String, false, 0, false); + SetAllowedValues(g_CameraServer, acqDeviceList_); + activeDevice_ = acqDeviceList_[0]; +} + +/** +* SaperaGigE destructor. +* If this device used as intended within the Micro-Manager system, +* Shutdown() will be always called before the destructor. But in any case +* we need to make sure that all resources are properly released even if +* Shutdown() was not called. +*/ +SaperaGigE::~SaperaGigE() +{ + if (initialized_) + Shutdown(); +} + +/** +* Obtains device name. +* Required by the MM::Device API. +*/ +void SaperaGigE::GetName(char* name) const +{ + // We just return the name we use for referring to this + // device adapter. + CDeviceUtils::CopyLimitedString(name, g_CameraDeviceName); +} + +/** +* Intializes the hardware. +* Typically we access and initialize hardware at this point. +* Device properties are typically created here as well. +* Required by the MM::Device API. +*/ +int SaperaGigE::Initialize() +{ + if (initialized_) + return DEVICE_OK; + if (activeDevice_.size() == 0) + return DEVICE_NOT_CONNECTED; + + int ret; + + // create live video thread + thd_ = new SequenceThread(this); + + LogMessage((std::string) "Initialize device '" + activeDevice_ + "'"); + SapLocation loc_(activeDevice_.c_str()); + AcqDevice_ = SapAcqDevice(loc_, false); + if (!AcqDevice_.Create()) + { + ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_INVALID_INPUT_PARAM; + } + AcqFeature_ = SapFeature(loc_); + if (!AcqFeature_.Create()) + { + ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_NATIVE_MODULE_FAILED; + } + + // binning + ret = SetUpBinningProperties(); + if (ret != DEVICE_OK) + return ret; + + // set up Sapera / Micro-Manager buffers + LogMessage((std::string) "Setting up buffers"); + ret = SynchronizeBuffers(); + if (ret != DEVICE_OK) + return ret; + + // set property list + // ----------------- + + // device features + for (auto const& x : deviceFeatures) + { + feature f = x.second; + BOOL isAvailable; + AcqDevice_.IsFeatureAvailable(f.name, &isAvailable); + if (!isAvailable) + { + LogMessage((std::string) "Feature '" + f.name + + "' is not supported"); + continue; + } + + LogMessage((std::string) "Adding feature '" + f.name + + "' as property '" + x.first + "'"); + char value[MM::MaxStrLength]; + if (!AcqDevice_.GetFeatureValue(f.name, value, sizeof(value))) + return DEVICE_ERR; + + AcqDevice_.GetFeatureInfo(f.name, &AcqFeature_); + SapFeature::Type sapType; + AcqFeature_.GetType(&sapType); + std::map< SapFeature::Type, MM::PropertyType>::iterator it; + it = featureType.find(sapType); + MM::PropertyType eType; + if (it == featureType.end()) + eType = MM::String; + else + eType = it->second; + + if (f.action == NULL) + ret = CreateProperty(x.first, value, eType, f.readOnly); + else + ret = CreateProperty(x.first, value, eType, f.readOnly, f.action); + assert(ret == DEVICE_OK); + + if (sapType == SapFeature::TypeEnum) + { + vector allowed; + int count; + AcqFeature_.GetEnumCount(&count); + for (int i = 0; i < count; i++) + { + AcqFeature_.GetEnumString(i, value, sizeof(value)); + allowed.push_back(value); + } + ret = SetAllowedValues(x.first, allowed); + assert(ret == DEVICE_OK); + } + } + + double low = 0.0; + double high = 0.0; + + // Set up gain + AcqDevice_.GetFeatureInfo("Gain", &AcqFeature_); + AcqFeature_.GetMax(&high); + AcqFeature_.GetMin(&low); + SetPropertyLimits(MM::g_Keyword_Gain, low, high); + + // Set up exposure + AcqDevice_.GetFeatureInfo("ExposureTime", &AcqFeature_); + AcqFeature_.GetMin(&low); // us + AcqFeature_.GetMax(&high); // us + SetPropertyLimits(MM::g_Keyword_Exposure, low / 1000., high / 1000.); + + // synchronize all properties + // -------------------------- + ret = UpdateStatus(); + if (ret != DEVICE_OK) + return ret; + + initialized_ = true; + return DEVICE_OK; +} + +/** +* Shuts down (unloads) the device. +* Ideally this method will completely unload the device and release all resources. +* Shutdown() may be called multiple times in a row. +* Required by the MM::Device API. +*/ +int SaperaGigE::Shutdown() +{ + if (!initialized_) + return DEVICE_OK; + LogMessage((std::string) "Shutting down device '" + loc_.GetServerName() + "'"); + + initialized_ = false; + Xfer_->Freeze(); + if (!Xfer_->Wait(5000)) + return DEVICE_NATIVE_MODULE_FAILED; + int ret; + ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_OK; +} + +/** +* Frees Sapera buffers and such +*/ +int SaperaGigE::FreeHandles() +{ + LogMessage((std::string) "Destroy Sapera buffers and devices"); + if (Xfer_ && *Xfer_ && !Xfer_->Destroy()) return DEVICE_ERR; + if (!Buffers_.Destroy()) return DEVICE_ERR; + if (!AcqFeature_.Destroy()) return DEVICE_ERR; + if (!AcqDevice_.Destroy()) return DEVICE_ERR; + return DEVICE_OK; +} + +/** +* Performs exposure and grabs a single image. +* This function blocks during the actual exposure and returns immediately afterwards +* Required by the MM::Camera API. +*/ +int SaperaGigE::SnapImage() +{ + // This will always be false, as no sequences will ever run + if (sequenceRunning_) + return DEVICE_CAMERA_BUSY_ACQUIRING; + // Start image capture + Xfer_->SetCommandTimeout(1000); + if (!Xfer_->Snap(1)) + { + return DEVICE_ERR; + } + // Wait for either the capture to finish or 2.5 seconds, whichever is first + if (!Xfer_->Wait(2500)) + { + return DEVICE_ERR; + } + return DEVICE_OK; +} + +/** +* Returns pixel data. +* Required by the MM::Camera API. +* 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(), GetImageHeight() 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.) +*/ +const unsigned char* SaperaGigE::GetImageBuffer() +{ + // Put Sapera buffer into Micro-Manager Buffer + Buffers_.ReadRect(Roi_->GetXMin(), Roi_->GetYMin(), img_.Width(), img_.Height(), + const_cast(img_.GetPixels())); + // Return location of the Micro-Manager Buffer + return const_cast(img_.GetPixels()); +} + +/** +* Returns image buffer X-size in pixels. +* Required by the MM::Camera API. +*/ +unsigned SaperaGigE::GetImageWidth() const +{ + return img_.Width(); +} + +/** +* Returns image buffer Y-size in pixels. +* Required by the MM::Camera API. +*/ +unsigned SaperaGigE::GetImageHeight() const +{ + return img_.Height(); +} + +/** +* Returns image buffer pixel depth in bytes. +* Required by the MM::Camera API. +*/ +unsigned SaperaGigE::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 SaperaGigE::GetBitDepth() const +{ + return bitsPerPixel_; +} + +/** +* Returns the size in bytes of the image buffer. +* Required by the MM::Camera API. +*/ +long SaperaGigE::GetImageBufferSize() const +{ + return img_.Width() * img_.Height() * img_.Depth(); +} + +/** +* 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 SaperaGigE::SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) +{ + LogMessage((std::string) "Setting Region of Interest"); + if (xSize == 0 && ySize == 0) + return ClearROI(); + else + { + // apply ROI + Roi_->SetRoi(x, y, xSize, ySize); + img_.Resize(xSize, ySize); + } + return DEVICE_OK; +} + +/** +* Returns the actual dimensions of the current ROI +* Required by the MM::Camera API. +*/ +int SaperaGigE::GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize) +{ + x = Roi_->GetXMin(); + y = Roi_->GetYMin(); + xSize = Roi_->GetWidth(); + ySize = Roi_->GetHeight(); + + return DEVICE_OK; +} + +/** +* Resets the Region of Interest to full frame. +* Required by the MM::Camera API. +*/ +int SaperaGigE::ClearROI() +{ + Roi_->ResetRoi(); + ResizeImageBuffer(); + return DEVICE_OK; +} + +/** +* Returns the current exposure setting in milliseconds. +* Required by the MM::Camera API. +*/ +double SaperaGigE::GetExposure() const +{ + char buf[MM::MaxStrLength]; + int ret = GetProperty(MM::g_Keyword_Exposure, buf); + if (ret != DEVICE_OK) + return 0.0; + return atof(buf); +} + +/** +* Sets exposure in milliseconds. +* Required by the MM::Camera API. +*/ +void SaperaGigE::SetExposure(double exp) +{ + int ret = SetProperty(MM::g_Keyword_Exposure, CDeviceUtils::ConvertToString(exp)); +} + +/** +* Returns the current binning factor. +* Required by the MM::Camera API. +*/ +int SaperaGigE::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. +* Required by the MM::Camera API. +*/ +int SaperaGigE::SetBinning(int binF) +{ + return SetProperty(MM::g_Keyword_Binning, CDeviceUtils::ConvertToString(binF)); +} + +//i/** +// * 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 SaperaGigE::StartSequenceAcquisition(double interval_ms) +//int SaperaGigE::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow); +//{ +// //@TODO: Implement Sequence Acquisition +// return DEVICE_ERR; +// //int ret = StartSequenceAcquisition((long)(interval_ms/exposureMs_), interval_ms, true); +// //return ret; +//} + +/** +* Stop and wait for the Sequence thread finished +*/ +int SaperaGigE::StopSequenceAcquisition() +{ + //@TODO: Implement Sequence Acquisition + return DEVICE_ERR; + /*thd_->Stop(); + thd_->wait(); + sequenceRunning_ = false; + 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 SaperaGigE::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) +{ + //@TODO: Implement Sequence Acquisition + return DEVICE_ERR; + /*if (sequenceRunning_) + { + return DEVICE_CAMERA_BUSY_ACQUIRING; + } + int ret = GetCoreCallback()->PrepareForAcq(this); + if (ret != DEVICE_OK) + { + return ret; + } + sequenceRunning_ = true; + thd_->SetLength(10); + thd_->Start(); + return DEVICE_OK; */ +} + +/* + * Inserts Image and MetaData into MMCore circular Buffer + */ +int SaperaGigE::InsertImage() +{ + //@TODO: Implement Sequence Acquisition + return GetCoreCallback()->InsertImage(this, const_cast(img_.GetPixels()), GetImageWidth(), GetImageHeight(), GetImageBytesPerPixel()); +} + +bool SaperaGigE::IsCapturing() { + //@TODO: Implement Sequence Acquisition + return sequenceRunning_; +} + +/////////////////////////////////////////////////////////////////////////////// +// SaperaGigE Action handlers +/////////////////////////////////////////////////////////////////////////////// + +/** +* Handles "Binning" property. +*/ +int SaperaGigE::OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + long binSize; + pProp->Get(binSize); + if (!AcqDevice_.SetFeatureValue("BinningVertical", int(binSize))) + return DEVICE_ERR; + if (!AcqDevice_.SetFeatureValue("BinningHorizontal", int(binSize))) + return DEVICE_ERR; + return SynchronizeBuffers(); + } + // MM::BeforeGet returns the value cached in the property. + return DEVICE_OK; +} + +int SaperaGigE::OnBinningMode(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + std::string value; + pProp->Get(value); + AcqDevice_.SetFeatureValue("binningMode", value.c_str()); + } + // MM::BeforeGet returns the value cached in the property. + return DEVICE_OK; +} + +int SaperaGigE::OnPixelSize(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + return DEVICE_CAN_NOT_SET_PROPERTY; + } + else if (eAct == MM::BeforeGet) + { + UINT32 value; + if (!AcqDevice_.GetFeatureValue("PixelSize", &value)) + return DEVICE_ERR; + pProp->Set((long)value); + } + return DEVICE_OK; +} + +long SaperaGigE::CheckValue(const char* key, long value) +{ + int64_t min, max, inc; + AcqDevice_.GetFeatureInfo(key, &AcqFeature_); + AcqFeature_.GetInc(&inc); + AcqFeature_.GetMin(&min); + AcqFeature_.GetMax(&max); + + long out = (value / (long)inc) * (long)inc; + out = max((long)min, min((long)max, out)); + + if (value != out) + LogMessage((std::string) "Encountered invalid value for '" + key + + "': corrected " + std::to_string(value) + " to " + std::to_string(out)); + return out; +} + +int SaperaGigE::OnOffsetX(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + long value; + pProp->Get(value); + + value = CheckValue("OffsetX", value); + if (!AcqDevice_.SetFeatureValue("OffsetX", value)) + return DEVICE_ERR; + } + else if (eAct == MM::BeforeGet) + { + UINT32 value; + if (!AcqDevice_.GetFeatureValue("OffsetX", &value)) + return DEVICE_ERR; + pProp->Set((long)value); + } + return DEVICE_OK; +} + +int SaperaGigE::OnOffsetY(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + long value; + pProp->Get(value); + + value = CheckValue("OffsetY", value); + if (!AcqDevice_.SetFeatureValue("OffsetY", value)) + return DEVICE_ERR; + } + else if (eAct == MM::BeforeGet) + { + UINT32 value; + if (!AcqDevice_.GetFeatureValue("OffsetY", &value)) + return DEVICE_ERR; + pProp->Set((long)value); + } + return DEVICE_OK; +} + +int SaperaGigE::OnWidth(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + long value; + pProp->Get(value); + + value = CheckValue("Width", value); + int ret = SynchronizeBuffers("", value, -1); + if (ret != DEVICE_OK) + return ret; + } + else if (eAct == MM::BeforeGet) + { + UINT32 value; + if (!AcqDevice_.GetFeatureValue("Width", &value)) + return DEVICE_ERR; + pProp->Set((long)value); + } + return DEVICE_OK; +} + +int SaperaGigE::OnHeight(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + long value; + pProp->Get(value); + + value = CheckValue("Height", value); + int ret = SynchronizeBuffers("", -1, value); + if (ret != DEVICE_OK) + return ret; + } + else if (eAct == MM::BeforeGet) + { + UINT32 value; + if (!AcqDevice_.GetFeatureValue("Height", &value)) + return DEVICE_ERR; + pProp->Set((long)value); + } + return DEVICE_OK; +} + +int SaperaGigE::OnImageTimeout(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + double value; + pProp->Get(value); + int ret = SynchronizeBuffers("", -1, -1, value); + if (ret != DEVICE_OK) + return ret; + } + else if (eAct == MM::BeforeGet) + { + double value; + if (!AcqDevice_.GetFeatureValue("ImageTimeout", &value)) + return DEVICE_ERR; + pProp->Set(value); + } + return DEVICE_OK; +} + +int SaperaGigE::OnTemperature(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::AfterSet) + { + return DEVICE_CAN_NOT_SET_PROPERTY; + } + else if (eAct == MM::BeforeGet) + { + double value; + if (!AcqDevice_.GetFeatureValue("DeviceTemperature", &value)) + return DEVICE_ERR; + pProp->Set(value); + } + return DEVICE_OK; +} + +/** +* Handles "PixelType" property. +*/ +int SaperaGigE::OnPixelType(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + char pixelFormat[10]; + AcqDevice_.GetFeatureValue("PixelFormat", pixelFormat, sizeof(pixelFormat)); + if (eAct == MM::AfterSet) + { + std::string value; + pProp->Get(value); + + if (!(value.compare(pixelFormat) == 0)) + { + //resize the SapBuffer + int ret = SynchronizeBuffers(value); + if (ret != DEVICE_OK) + return ret; + } + } + else if (eAct == MM::BeforeGet) + { + pProp->Set(pixelFormat); + } + + return DEVICE_OK; +} + +/** +* Handles "Gain" property. +*/ +int SaperaGigE::OnGain(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + double gain = 1.; + if (eAct == MM::AfterSet) + { + pProp->Get(gain); + AcqDevice_.SetFeatureValue("Gain", gain); + } + else if (eAct == MM::BeforeGet) + { + AcqDevice_.GetFeatureValue("Gain", &gain); + pProp->Set(gain); + } + + return DEVICE_OK; +} + +int SaperaGigE::OnExposure(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + // note that GigE units of exposure are us; umanager uses ms + if (eAct == MM::AfterSet) + { + double oldd = 0, newd = 0; + AcqDevice_.GetFeatureValue("ExposureTime", &oldd); // us + pProp->Get(newd); // ms + if (!AcqDevice_.SetFeatureValue("ExposureTime", newd * 1000.0)) // ms to us + { + pProp->Set(oldd / 1000.0); // us to ms + return DEVICE_INVALID_PROPERTY_VALUE; + } + } + else if (eAct == MM::BeforeGet) + { + double d = 0; + if (AcqDevice_.GetFeatureValue("ExposureTime", &d)) // us + pProp->Set(d / 1000.0); + } + return DEVICE_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// Private SaperaGigE methods +/////////////////////////////////////////////////////////////////////////////// + +/** +* Sync internal image buffer size to the chosen property values. +*/ +int SaperaGigE::ResizeImageBuffer() +{ + UINT32 width, height; + if (!AcqDevice_.GetFeatureValue("Height", &height)) + return DEVICE_INVALID_PROPERTY; + if (!AcqDevice_.GetFeatureValue("Width", &width)) + return DEVICE_INVALID_PROPERTY; + + img_.Resize(width, height, bytesPerPixel_); + + return DEVICE_OK; +} + +/** + * Generate an image with fixed value for all pixels + */ +void SaperaGigE::GenerateImage() +{ + const int maxValue = (1 << MAX_BIT_DEPTH) - 1; // max for the 12 bit camera + const double maxExp = 1000; + double step = maxValue / maxExp; + unsigned char* pBuf = const_cast(img_.GetPixels()); + double exposureMs = GetExposure(); + memset(pBuf, (int)(step * max(exposureMs, maxExp)), GetImageBufferSize()); +} + +/* + * Reformat Sapera Buffer Object + */ +int SaperaGigE::SynchronizeBuffers(std::string pixelFormat, int width, int height, double timeout) +{ + // destroy transfer and buffer + if (Roi_ != NULL) + { + delete Roi_; + Xfer_->Destroy(); + Buffers_.Destroy(); + } + + // default value + if (pixelFormat.size()) + AcqDevice_.SetFeatureValue("PixelFormat", pixelFormat.c_str()); + if (width > 0) + AcqDevice_.SetFeatureValue("Width", width); + if (height > 0) + AcqDevice_.SetFeatureValue("Height", height); + if (timeout > 0) + AcqDevice_.SetFeatureValue("ImageTimeout", timeout); + + // synchronize bit depth with camera + AcqDevice_.GetFeatureValue("PixelSize", &bitsPerPixel_); + bytesPerPixel_ = (bitsPerPixel_ + 7) / 8; + + // re-create transfer and buffer + Buffers_ = SapBufferWithTrash(3, &AcqDevice_); + Roi_ = new SapBufferRoi(&Buffers_); + AcqDeviceToBuf_ = SapAcqDeviceToBuf(&AcqDevice_, &Buffers_, XferCallback, this); + Xfer_ = &AcqDeviceToBuf_; + if (!Buffers_.Create()) + { + int ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_NATIVE_MODULE_FAILED; + } + if (Xfer_ && !Xfer_->Create()) + { + int ret = FreeHandles(); + if (ret != DEVICE_OK) + return ret; + return DEVICE_NATIVE_MODULE_FAILED; + } + ResizeImageBuffer(); + + return DEVICE_OK; +} + +void SaperaGigE::XferCallback(SapXferCallbackInfo* pInfo) +{ + // If grabbing in trash buffer, log a message + if (pInfo->IsTrash()) + { + ErrorBox((std::string) "Frames acquired in trash buffer: " + + std::to_string(pInfo->GetEventCount()), "Xfer"); + } +} + + +int SaperaGigE::SetUpBinningProperties() +{ + BOOL hasHorzBinning; + BOOL hasVertBinning; + AcqDevice_.IsFeatureAvailable("BinningHorizontal", &hasHorzBinning); + AcqDevice_.IsFeatureAvailable("BinningVertical", &hasVertBinning); + if (!hasHorzBinning || !hasVertBinning) + { + if (!hasHorzBinning) + LogMessage((std::string) "Feature 'BinningHorizontal' is not supported"); + if (!hasVertBinning) + LogMessage((std::string) "Feature 'BinningVertical' is not supported"); + return DEVICE_OK; + } + + // note that the GenICam spec separates vertical and horizontal binning and does + // not provide a single, unified binning property. + LogMessage((std::string) "Set up binning properties"); + CPropertyAction* pAct = new CPropertyAction(this, &SaperaGigE::OnBinning); + int ret = CreateProperty(MM::g_Keyword_Binning, "1", MM::Integer, false, pAct); + if (DEVICE_OK != ret) + return ret; + + int64_t bin, min, max, inc; + std::vector vValues, hValues, binValues; + + // vertical binning + if (!AcqDevice_.SetFeatureValue("BinningVertical", 1)) + { + LogMessage((std::string) "Failed to set 'BinningVertical'"); + return DEVICE_INVALID_PROPERTY; + } + AcqDevice_.GetFeatureValue("BinningVertical", &bin); + AcqDevice_.GetFeatureInfo("BinningVertical", &AcqFeature_); + AcqFeature_.GetMin(&min); + AcqFeature_.GetMax(&max); + AcqFeature_.GetInc(&inc); + for (int64_t i = min; i <= max; i += inc) + vValues.push_back(std::to_string(i)); + + // horizontal binning + if (!AcqDevice_.SetFeatureValue("BinningHorizontal", 1)) + { + LogMessage((std::string) "Failed to set 'BinningHorizontal'"); + return DEVICE_INVALID_PROPERTY; + } + AcqDevice_.GetFeatureValue("BinningHorizontal", &bin); + AcqDevice_.GetFeatureInfo("BinningHorizontal", &AcqFeature_); + AcqFeature_.GetMin(&min); + AcqFeature_.GetMax(&max); + AcqFeature_.GetInc(&inc); + for (int64_t i = min; i <= max; i += inc) + hValues.push_back(std::to_string(i)); + + // possible uniform binning values. + if (vValues.empty() && hValues.empty()) + binValues.push_back("1"); + else if (vValues.empty()) + binValues = hValues; + else if (hValues.empty()) + binValues = vValues; + else { + binValues.reserve(vValues.size() + hValues.size()); + std::set_union(vValues.begin(), vValues.end(), + hValues.begin(), hValues.end(), + std::back_inserter(binValues)); + } + + return SetAllowedValues(MM::g_Keyword_Binning, binValues); +} + +/////////////////////////////////////////////////////////////////////////////// +// Threading methods +/////////////////////////////////////////////////////////////////////////////// + +int SequenceThread::svc() +{ + //SapManager::DisplayMessage("SequenceThread Start"); + long count(0); + while (!stop_)//&& count < numImages_) + { + /*int ret = camera_->SnapImage(); + if (ret != DEVICE_OK) + { + //SapManager::DisplayMessage("SequenceThread Snap failed"); + camera_->StopSequenceAcquisition(); + return 1; + }*/ + + int ret = camera_->InsertImage(); + if (ret != DEVICE_OK) + { + //SapManager::DisplayMessage("SequenceThread InsertFailed"); + camera_->StopSequenceAcquisition(); + return 1; + } + //count++; + } + //SapManager::DisplayMessage("SequenceThread End"); + return 0; +} \ No newline at end of file diff --git a/DeviceAdapters/SaperaGigE/SaperaGigE.h b/DeviceAdapters/SaperaGigE/SaperaGigE.h new file mode 100644 index 0000000000..8548530878 --- /dev/null +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.h @@ -0,0 +1,225 @@ +///////////////////////////////////////////////////////// +// FILE: SaperaGigE.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//------------------------------------------------------- +// DESCRIPTION: An adapter for Gigbit-Ethernet cameras using an +// SDK from JAI, Inc. Users and developers will +// need to download and install the JAI SDK and control tool. +// +// AUTHOR: Robert Frazee, rfraze1@lsu.edu +// Ingmar Schoegl, ischoegl@lsu.edu +// +// LICENSE: This file is distributed under the BSD license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. + +#ifndef _SaperaGigE_H_ +#define _SaperaGigE_H_ + +#include "DeviceBase.h" +#include "DeviceThreads.h" +#include "ImgBuffer.h" +#include "stdio.h" +#include "conio.h" +#include "math.h" +#include "SapClassBasic.h" +#include "../MMDevice/ModuleInterface.h" +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// Error codes +// +#define ERR_UNKNOWN_MODE 102 + +class SequenceThread; + +const char* g_CameraDeviceName = "Sapera GigE camera adapter"; +const char* g_CameraServer = "AcquisitionDevice"; + +std::map< SapFeature::Type, MM::PropertyType > featureType = { + {SapFeature::TypeString, MM::String}, + {SapFeature::TypeEnum, MM::String}, + {SapFeature::TypeInt32, MM::Integer}, + {SapFeature::TypeFloat, MM::Float}, + {SapFeature::TypeDouble, MM::Float}, + {SapFeature::TypeUndefined, MM::String} +}; + +std::wstring s2ws(const std::string&); +int ErrorBox(std::string text, std::string caption); + +class SaperaGigE : public CCameraBase +{ +private: + struct feature + { + char* name; + bool readOnly; + CPropertyAction* action; + }; + + const std::map< const char*, feature > deviceFeatures = { + // information on device - use names shown in Sapera CamExpert + {MM::g_Keyword_PixelType, {"PixelFormat", false, new CPropertyAction(this, &SaperaGigE::OnPixelType)}}, + {MM::g_Keyword_Exposure, {"ExposureTime", false, new CPropertyAction(this, &SaperaGigE::OnExposure)}}, + {MM::g_Keyword_Gain, {"Gain", false, new CPropertyAction(this, &SaperaGigE::OnGain)}}, + {"CameraVendor", {"DeviceVendorName", true, NULL}}, + {"CameraFamily", {"DeviceFamilyName", true, NULL}}, + {MM::g_Keyword_CameraName, {"DeviceModelName", true, NULL}}, + {"CameraVersion", {"DeviceVersion", true, NULL}}, + {"CameraInfo", {"DeviceManufacturerInfo", true, NULL}}, + {"CameraPartNumber", {"deviceManufacturerPartNumber", true, NULL}}, + {"CameraFirmwareVersion", {"DeviceFirmwareVersion", true, NULL}}, + {"CameraSerialNumber", {"DeviceSerialNumber", true, NULL}}, + {MM::g_Keyword_CameraID, {"DeviceUserID", true, NULL}}, + {"CameraMacAddress", {"deviceMacAddress", true, NULL}}, + {"SensorColorType", {"sensorColorType", true, NULL}}, + {"SensorPixelCoding", {"PixelCoding", true, NULL}}, + {"SensorBlackLevel", {"BlackLevel", true, NULL}}, + {"SensorPixelInput", {"pixelSizeInput", true, NULL}}, + {"SensorShutterMode", {"SensorShutterMode", false, NULL}}, + {"SensorBinningMode", {"binningMode", false, new CPropertyAction(this, &SaperaGigE::OnBinningMode)}}, + {"SensorWidth", {"SensorWidth", true, NULL}}, + {"SensorHeight", {"SensorHeight", true, NULL}}, + {"ImagePixelSize", {"PixelSize", true, new CPropertyAction(this, &SaperaGigE::OnPixelSize)}}, + {"ImageHorizontalOffset", {"OffsetX", false, new CPropertyAction(this, &SaperaGigE::OnOffsetX)}}, + {"ImageVerticalOffset", {"OffsetY", false, new CPropertyAction(this, &SaperaGigE::OnOffsetY)}}, + {"ImageWidth", {"Width", false, new CPropertyAction(this, &SaperaGigE::OnWidth)}}, + {"ImageHeight", {"Height", false, new CPropertyAction(this, &SaperaGigE::OnHeight)}}, + {"ImageTimeout", {"ImageTimeout", false, new CPropertyAction(this, &SaperaGigE::OnImageTimeout)}}, + {"TurboTransferEnable", {"turboTransferEnable", true, NULL}}, + {"SensorTemperature", {"DeviceTemperature", true, new CPropertyAction(this, &SaperaGigE::OnTemperature)}}, + //{"ReverseX", {"ReverseX", true, NULL}}, + //{MM::g_Keyword_Transpose_MirrorY, {"ReverseY", true, NULL}}, + }; + +public: + SaperaGigE(); + ~SaperaGigE(); + + // MMDevice API + // ------------ + int Initialize(); + int Shutdown(); + + void GetName(char* name) const; + + // SaperaGigE API + // ------------ + int SnapImage(); + const unsigned char* GetImageBuffer(); + unsigned GetImageWidth() const; + unsigned GetImageHeight() const; + unsigned GetImageBytesPerPixel() const; + unsigned GetBitDepth() const; + long GetImageBufferSize() const; + double GetExposure() const; + void SetExposure(double exp); + + // ROI-related functions + int SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize); + int GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize); + int ClearROI(); + + // sequence-acquisition-related functions + int PrepareSequenceAcqusition() { return DEVICE_OK; } + //int StartSequenceAcquisition(double interval); + int StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow); + int StopSequenceAcquisition(); + bool IsCapturing(); + + // pixel-size-related functions + // the GenICam spec and the JAI sdk have no way to query sensor pixel size. + double GetNominalPixelSizeUm() const { return 1.0; } + double GetPixelSizeUm() const { return 1.0 * GetBinning(); } + + int GetBinning() const; + int SetBinning(int binSize); + int IsExposureSequenceable(bool& seq) const { seq = false; return DEVICE_OK; } + + // action interface + // ---------------- + int OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnBinningMode(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnPixelSize(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnOffsetX(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnOffsetY(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnWidth(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnHeight(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnImageTimeout(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnTemperature(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnPixelType(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnGain(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnExposure(MM::PropertyBase* pProp, MM::ActionType eAct); + +private: + + friend class SequenceThread; + static const int MAX_BIT_DEPTH = 12; + + ImgBuffer img_; + SequenceThread* thd_; + int bytesPerPixel_; + int bitsPerPixel_; + bool initialized_; + bool sequenceRunning_; + + int ResizeImageBuffer(); + void GenerateImage(); + int InsertImage(); + + std::vector acqDeviceList_; + std::string activeDevice_; + + SapAcqDevice AcqDevice_; + SapBufferWithTrash Buffers_; + SapBufferRoi* Roi_; + SapTransfer AcqToBuf_; + SapTransfer AcqDeviceToBuf_; + SapTransfer* Xfer_; + SapLocation loc_; + SapFeature AcqFeature_; + + int FreeHandles(); + int SetUpBinningProperties(); + int SynchronizeBuffers(std::string pixelFormat = "", int width = -1, int height = -1, double timeout = -1.); + long CheckValue(const char*, long); + static void XferCallback(SapXferCallbackInfo*); +}; + +//threading stuff. Tread lightly +class SequenceThread : public MMDeviceThreadBase +{ +public: + SequenceThread(SaperaGigE* pCam) : stop_(false), numImages_(0) { camera_ = pCam; } + ~SequenceThread() {} + + int svc(void); + + void Stop() { stop_ = true; } + + void Start() + { + stop_ = false; + activate(); + } + + void SetLength(long images) { numImages_ = images; } + long GetLength(void) { return numImages_; }; + +private: + SaperaGigE* camera_; + bool stop_; + long numImages_; +}; + +#endif //_SaperaGigE_H_ diff --git a/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj b/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj similarity index 85% rename from DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj rename to DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj index b9293c17ad..00b23dbef0 100644 --- a/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj @@ -22,18 +22,21 @@ {DE209272-1DA7-4551-9D34-3ECE99DDE827} Win32Proj GigENano + SaperaGigE + 10.0 DynamicLibrary true Unicode + v142 DynamicLibrary true Unicode - Windows7.1SDK + v142 DynamicLibrary @@ -46,29 +49,30 @@ false true Unicode + v142 - - + + - - + + - - + + - - + + @@ -137,6 +141,7 @@ true true WIN32;NDEBUG;_WINDOWS;_USRDLL;GIGENANO_EXPORTS;%(PreprocessorDefinitions) + $(SAPERADIR)\Include;$(SAPERADIR)\Classes\Basic;%(AdditionalIncludeDirectories) Windows @@ -146,16 +151,16 @@ - + - + - + - + {b8c95f39-54bf-40a9-807b-598df2821d55} diff --git a/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj.filters b/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj.filters similarity index 63% rename from DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj.filters rename to DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj.filters index 65fa98af31..cc74925644 100644 --- a/DeviceAdapters/TeledyneDalsaGigE/GigENano.vcxproj.filters +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj.filters @@ -9,22 +9,18 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;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 - - + + + + Header Files - + Source Files - - - \ No newline at end of file diff --git a/DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp b/DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp deleted file mode 100644 index a8282e4fec..0000000000 --- a/DeviceAdapters/TeledyneDalsaGigE/TestCamera.cpp +++ /dev/null @@ -1,859 +0,0 @@ -///////////////////////////////////////////////////////// -// FILE: TestCamera.cpp -// PROJECT: Teledyne DALSA Micro-Manager Glue Library -//------------------------------------------------------- -// AUTHOR: Robert Frazee, rfraze1@lsu.edu - -#include "TestCamera.h" -#include "../MMDevice/ModuleInterface.h" -#include "stdio.h" -#include "conio.h" -#include "math.h" -#include "sapclassbasic.h" -#include - -using namespace std; - -const char* g_CameraName = "GigE Nano"; -const char* g_PixelType_8bit = "8bit"; -const char* g_PixelType_10bit = "10bit"; -const char* g_PixelType_12bit = "12bit"; - -const char* g_CameraModelProperty = "Model"; -const char* g_CameraModel_A = "Nano-M1930-NIR"; - -// g_CameraAcqDeviceNumberProperty -// g_CameraServerNameProperty -// g_CameraConfigFilenameProperty -const char* g_CameraAcqDeviceNumberProperty = "Acquisition Device Number"; -const char* g_CameraAcqDeviceNumber_Def = "0"; -const char* g_CameraServerNameProperty = "Server Name"; -const char* g_CameraServerName_Def = "Nano-M1930-NIR_1"; -const char* g_CameraConfigFilenameProperty = "Config Filename"; -const char* g_CameraConfigFilename_Def = "NoFile"; - - -/////////////////////////////////////////////////////////////////////////////// -// Exported MMDevice API -/////////////////////////////////////////////////////////////////////////////// - -/** - * List all supported hardware devices here - */ -MODULE_API void InitializeModuleData() -{ - RegisterDevice(g_CameraName, MM::CameraDevice, "GigE Nano Camera Device"); -} - -MODULE_API MM::Device* CreateDevice(const char* deviceName) -{ - if (deviceName == 0) - return 0; - - // decide which device class to create based on the deviceName parameter - if (strcmp(deviceName, g_CameraName) == 0) - { - // create camera - return new TestCamera(); - } - - // ...supplied name not recognized - // to heck with it, return a device anyway - return new TestCamera(); -} - -MODULE_API void DeleteDevice(MM::Device* pDevice) -{ - delete pDevice; -} - -/////////////////////////////////////////////////////////////////////////////// -// TestCamera implementation -// ~~~~~~~~~~~~~~~~~~~~~~~ - -/** -* TestCamera 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. -*/ -TestCamera::TestCamera() : - binning_ (1), - gain_(1), - bytesPerPixel_(1), - bitsPerPixel_(8), - initialized_(false), - roiX_(0), - roiY_(0), - thd_(0), - sequenceRunning_(false), - SapFormatBytes_(1) -{ - // call the base class method to set-up default error codes/messages - InitializeDefaultErrorMessages(); - - // Description property - int ret = CreateProperty(MM::g_Keyword_Description, "GigE Nano Camera Adapter", MM::String, true); - assert(ret == DEVICE_OK); - - // camera type pre-initialization property - ret = CreateProperty(g_CameraModelProperty, g_CameraModel_A, MM::String, false, 0, true); - assert(ret == DEVICE_OK); - - vector modelValues; - modelValues.push_back(g_CameraModel_A); - modelValues.push_back(g_CameraModel_A); - - ret = SetAllowedValues(g_CameraModelProperty, modelValues); - assert(ret == DEVICE_OK); - - // Sapera++ library stuff - - int serverCount = SapManager::GetServerCount(); - if(serverCount == 0) - { - ErrorBox((LPCWSTR)L"Initialization Error", (LPCWSTR)L"No servers!"); - } - - acqServerName_ = new char[CORSERVER_MAX_STRLEN]; - configFilename_ = new char[MAX_PATH]; - - ret = CreateProperty(g_CameraAcqDeviceNumberProperty, g_CameraAcqDeviceNumber_Def, MM::Integer, false, 0, true); - assert(ret == DEVICE_OK); - - ret = CreateProperty(g_CameraServerNameProperty, g_CameraServerName_Def, MM::String, false, 0, true); - assert(ret == DEVICE_OK); - - ret = CreateProperty(g_CameraConfigFilenameProperty, g_CameraConfigFilename_Def, MM::String, false, 0, true); - assert(ret == DEVICE_OK); - - // create live video thread - thd_ = new SequenceThread(this); -} - -/** -* TestCamera destructor. -* If this device used as intended within the Micro-Manager system, -* Shutdown() will be always called before the destructor. But in any case -* we need to make sure that all resources are properly released even if -* Shutdown() was not called. -*/ -TestCamera::~TestCamera() -{ - if (initialized_) - Shutdown(); -} - -/** -* Obtains device name. -* Required by the MM::Device API. -*/ -void TestCamera::GetName(char* name) const -{ - // We just return the name we use for referring to this - // device adapter. - CDeviceUtils::CopyLimitedString(name, g_CameraName); -} - -/** -* Intializes the hardware. -* Typically we access and initialize hardware at this point. -* Device properties are typically created here as well. -* Required by the MM::Device API. -*/ -int TestCamera::Initialize() -{ - if (initialized_) - return DEVICE_OK; - - //SapManager::DisplayMessage("This plugin logs debug messages. Press no so they don't all pop up like this."); - // set property list - // ----------------- - - // binning - CPropertyAction *pAct = new CPropertyAction (this, &TestCamera::OnBinning); - //@TODO: Check what the actual binning value is and set that - // For now, set binning to 1 for MM and set that on the camera later - int ret = CreateProperty(MM::g_Keyword_Binning, "1", MM::Integer, false, pAct); - assert(ret == DEVICE_OK); - - vector binningValues; - binningValues.push_back("1"); - binningValues.push_back("2"); - binningValues.push_back("4"); - - ret = SetAllowedValues(MM::g_Keyword_Binning, binningValues); - assert(ret == DEVICE_OK); - - //Sapera stuff - // g_CameraAcqDeviceNumberProperty - // g_CameraServerNameProperty - // g_CameraConfigFilenameProperty - long tmpDeviceNumber; - if(GetProperty(g_CameraAcqDeviceNumberProperty, tmpDeviceNumber) != DEVICE_OK) - { - //SapManager::DisplayMessage("Failed to retrieve AcqDeviceNumberProperty"); - return DEVICE_ERR; - } - acqDeviceNumber_ = (UINT32)tmpDeviceNumber; - - if(false)//GetProperty(g_CameraServerNameProperty, acqServerName_) != DEVICE_OK) - { - //SapManager::DisplayMessage("Failed to retrieve ServerNameProperty"); - return DEVICE_ERR; - } - acqServerName_ = (char *)g_CameraServerName_Def; - - if(false)//GetProperty(g_CameraConfigFilenameProperty, configFilename_) != DEVICE_OK) - { - //SapManager::DisplayMessage("Failed to retrieve ConfigFilenameProperty"); - return DEVICE_ERR; - } - configFilename_ = "NoFile"; - - //SapManager::DisplayMessage("(Sapera app)Creating loc_ object"); - SapLocation loc_(acqServerName_, acqDeviceNumber_); - //SapManager::DisplayMessage("(Sapera app)Created loc_ object"); - //SapManager::DisplayMessage("(Sapera app)GetResourceCount for ResourceAcqDevice starting"); - if(SapManager::GetResourceCount(acqServerName_, SapManager::ResourceAcqDevice) > 0) - { - //SapManager::DisplayMessage("(Sapera app)GetResourceCount for ResourceAcqDevice found something"); - if(strcmp(configFilename_, "NoFile") == 0) - AcqDevice_ = SapAcqDevice(loc_, false); - else - AcqDevice_ = SapAcqDevice(loc_, configFilename_); - - Buffers_ = SapBufferWithTrash(2, &AcqDevice_); - AcqDeviceToBuf_ = SapAcqDeviceToBuf(&AcqDevice_, &Buffers_); - Xfer_ = &AcqDeviceToBuf_; - - if(!AcqDevice_.Create()) - { - ret = FreeHandles(); - if (ret != DEVICE_OK) - { - //SapManager::DisplayMessage("Failed to FreeHandles during Acq_.Create() for ResourceAcqDevice"); - return ret; - } - //SapManager::DisplayMessage("Failed to create Acq_ for ResourceAcqDevice"); - return DEVICE_INVALID_INPUT_PARAM; - } - } - //SapManager::DisplayMessage("(Sapera app)GetResourceCount for ResourceAcqDevice done"); - //SapManager::DisplayMessage("(Sapera app)Creating Buffers_"); - if(!Buffers_.Create()) - { - ret = FreeHandles(); - if (ret != DEVICE_OK) - return ret; - return DEVICE_NATIVE_MODULE_FAILED; - } - //SapManager::DisplayMessage("(Sapera app)Creating Xfer_"); - if(Xfer_ && !Xfer_->Create()) - { - //SapManager::DisplayMessage("Xfer_ creation failed"); - ret = FreeHandles(); - if (ret != DEVICE_OK) - return ret; - return DEVICE_NATIVE_MODULE_FAILED; - } - //SapManager::DisplayMessage("(Sapera app)Starting Xfer"); - //Start continuous grab - //Xfer_->Grab(); - //SapManager::DisplayMessage("(Sapera app)Sapera Initialization for TestCamera complete"); - - if(!AcqDevice_.GetFeatureValue("ExposureTime", &exposureMs_)) - return DEVICE_ERR; - exposureMs_ = exposureMs_ / 1000; - - // synchronize bit depth with camera - - char acqFormat[10]; - AcqDevice_.GetFeatureValue("PixelFormat", acqFormat, 10); - if(strcmp(acqFormat, "Mono8") == 0) - { - // Setup Micro-Manager for 8bit pixels - SapFormatBytes_ = 1; - bitsPerPixel_ = 8; - bytesPerPixel_ = 1; - //resize the SapBuffer - int ret = SapBufferReformat(SapFormatMono8, "Mono8"); - if(ret != DEVICE_OK) - { - return ret; - } - ResizeImageBuffer(); - pAct = new CPropertyAction (this, &TestCamera::OnPixelType); - ret = CreateProperty(MM::g_Keyword_PixelType, g_PixelType_8bit, MM::String, false, pAct); - assert(ret == DEVICE_OK); - } - if(strcmp(acqFormat, "Mono10") == 0) - { - // Setup Micro-Manager for 8bit pixels - SapFormatBytes_ = 2; - bitsPerPixel_ = 10; - bytesPerPixel_ = 2; - //resize the SapBuffer - int ret = SapBufferReformat(SapFormatMono10, "Mono10"); - if(ret != DEVICE_OK) - { - return ret; - } - ResizeImageBuffer(); - pAct = new CPropertyAction (this, &TestCamera::OnPixelType); - ret = CreateProperty(MM::g_Keyword_PixelType, g_PixelType_10bit, MM::String, false, pAct); - assert(ret == DEVICE_OK); - } - - - // pixel type - - - vector pixelTypeValues; - pixelTypeValues.push_back(g_PixelType_8bit); - pixelTypeValues.push_back(g_PixelType_10bit); - - - ret = SetAllowedValues(MM::g_Keyword_PixelType, pixelTypeValues); - assert(ret == DEVICE_OK); - - // Set Binning to 1 - if(!AcqDevice_.SetFeatureValue("BinningVertical", 1)) - return DEVICE_ERR; - if(!AcqDevice_.SetFeatureValue("BinningHorizontal", 1)) - return DEVICE_ERR; - - - // Setup gain - pAct = new CPropertyAction(this, &TestCamera::OnGain); - ret = CreateProperty(MM::g_Keyword_Gain, "1.0", MM::Float, false, pAct); - assert(ret == DEVICE_OK); - if(!AcqDevice_.SetFeatureValue("Gain", 1.0)) - return DEVICE_ERR; - SapFeature SapGain_(loc_); - if(!SapGain_.Create()) - return DEVICE_ERR; - AcqDevice_.GetFeatureInfo("Gain", &SapGain_); - double g_low = 0.0; - double g_high = 0.0; - SapGain_.GetMax(&g_high); - SapGain_.GetMin(&g_low); - SetPropertyLimits(MM::g_Keyword_Gain, g_low, g_high); - - - - // 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. -* Ideally this method will completely unload the device and release all resources. -* Shutdown() may be called multiple times in a row. -* Required by the MM::Device API. -*/ -int TestCamera::Shutdown() -{ - if(!initialized_) - return DEVICE_OK; - initialized_ = false; - Xfer_->Freeze(); - if(!Xfer_->Wait(5000)) - return DEVICE_NATIVE_MODULE_FAILED; - int ret; - ret = FreeHandles(); - if(ret != DEVICE_OK) - return ret; - return DEVICE_OK; -} - -/** -* Frees Sapera buffers and such -*/ -int TestCamera::FreeHandles() -{ - if(Xfer_ && *Xfer_ && !Xfer_->Destroy()) return DEVICE_ERR; - if(!Buffers_.Destroy()) return DEVICE_ERR; - if(!Acq_.Destroy()) return DEVICE_ERR; - if(!AcqDevice_.Destroy()) return DEVICE_ERR; - return DEVICE_OK; -} - -int TestCamera::ErrorBox(LPCWSTR text, LPCWSTR caption) -{ - return MessageBox(NULL, caption, text, (MB_ICONERROR | MB_OK)); -} - -/** -* Performs exposure and grabs a single image. -* This function blocks during the actual exposure and returns immediately afterwards -* Required by the MM::Camera API. -*/ -int TestCamera::SnapImage() -{ - // This will always be false, as no sequences will ever run - if(sequenceRunning_) - return DEVICE_CAMERA_BUSY_ACQUIRING; - // Start image capture - if(!Xfer_->Snap(1)) - { - return DEVICE_ERR; - } - // Wait for either the capture to finish or 2.5 seconds, whichever is first - if(!Xfer_->Wait(2500)) - { - return DEVICE_ERR; - } - return DEVICE_OK; -} - -/** -* Returns pixel data. -* Required by the MM::Camera API. -* 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.) -*/ -const unsigned char* TestCamera::GetImageBuffer() -{ - // Put Sapera buffer into Micro-Manager Buffer - Buffers_.ReadRect(roiX_, roiY_, img_.Width(), img_.Height(), const_cast(img_.GetPixels())); - // Return location of the Micro-Manager Buffer - return const_cast(img_.GetPixels()); -} - -/** -* Returns image buffer X-size in pixels. -* Required by the MM::Camera API. -*/ -unsigned TestCamera::GetImageWidth() const -{ - return img_.Width(); -} - -/** -* Returns image buffer Y-size in pixels. -* Required by the MM::Camera API. -*/ -unsigned TestCamera::GetImageHeight() const -{ - return img_.Height(); -} - -/** -* Returns image buffer pixel depth in bytes. -* Required by the MM::Camera API. -*/ -unsigned TestCamera::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 TestCamera::GetBitDepth() const -{ - return bitsPerPixel_; -} - -/** -* Returns the size in bytes of the image buffer. -* Required by the MM::Camera API. -*/ -long TestCamera::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 TestCamera::SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) -{ - if (xSize == 0 && ySize == 0) - { - // effectively clear ROI - ResizeImageBuffer(); - roiX_ = 0; - roiY_ = 0; - } - else - { - // apply ROI - img_.Resize(xSize, ySize); - roiX_ = x; - roiY_ = y; - } - return DEVICE_OK; -} - -/** -* Returns the actual dimensions of the current ROI. -* Required by the MM::Camera API. -*/ -int TestCamera::GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize) -{ - x = roiX_; - y = roiY_; - - xSize = img_.Width(); - ySize = img_.Height(); - - return DEVICE_OK; -} - -/** -* Resets the Region of Interest to full frame. -* Required by the MM::Camera API. -*/ -int TestCamera::ClearROI() -{ - ResizeImageBuffer(); - roiX_ = 0; - roiY_ = 0; - - return DEVICE_OK; -} - -/** -* Returns the current exposure setting in milliseconds. -* Required by the MM::Camera API. -*/ -double TestCamera::GetExposure() const -{ - return exposureMs_; -} - -/** -* Sets exposure in milliseconds. -* Required by the MM::Camera API. -*/ -void TestCamera::SetExposure(double exp) -{ - exposureMs_ = exp; - // Micromanager deals with exposure time in ms - // Sapera deals with exposure time in us - // As such, we convert between the two - AcqDevice_.SetFeatureValue("ExposureTime", (exposureMs_ * 1000)); -} - -/** -* Returns the current binning factor. -* Required by the MM::Camera API. -*/ -int TestCamera::GetBinning() const -{ - return binning_; -} - -/** -* Sets binning factor. -* Required by the MM::Camera API. -*/ -int TestCamera::SetBinning(int binF) -{ - return SetProperty(MM::g_Keyword_Binning, CDeviceUtils::ConvertToString(binF)); -} - -int TestCamera::PrepareSequenceAcqusition() -{ - return DEVICE_ERR; -} - - -/** - * 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 TestCamera::StartSequenceAcquisition(double interval_ms) -{ - //@TODO: Implement Sequence Acquisition - return DEVICE_ERR; - //int ret = StartSequenceAcquisition((long)(interval_ms/exposureMs_), interval_ms, true); - //return ret; -} - -/** -* Stop and wait for the Sequence thread finished -*/ -int TestCamera::StopSequenceAcquisition() -{ - //@TODO: Implement Sequence Acquisition - return DEVICE_ERR; - /*thd_->Stop(); - thd_->wait(); - sequenceRunning_ = false; - 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 TestCamera::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) -{ - //@TODO: Implement Sequence Acquisition - return DEVICE_ERR; - /*if (sequenceRunning_) - { - return DEVICE_CAMERA_BUSY_ACQUIRING; - } - int ret = GetCoreCallback()->PrepareForAcq(this); - if (ret != DEVICE_OK) - { - return ret; - } - sequenceRunning_ = true; - thd_->SetLength(10); - thd_->Start(); - return DEVICE_OK; */ -} - -/* - * Inserts Image and MetaData into MMCore circular Buffer - */ -int TestCamera::InsertImage() -{ - //@TODO: Implement Sequence Acquisition - return GetCoreCallback()->InsertImage(this, const_cast(img_.GetPixels()), GetImageWidth(), GetImageHeight(), GetImageBytesPerPixel()); -} - - -bool TestCamera::IsCapturing() { - //@TODO: Implement Sequence Acquisition - return sequenceRunning_; -} - - -/////////////////////////////////////////////////////////////////////////////// -// TestCamera Action handlers -/////////////////////////////////////////////////////////////////////////////// - -/** -* Handles "Binning" property. -*/ -int TestCamera::OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct) -{ - if (eAct == MM::AfterSet) - { - long binSize; - pProp->Get(binSize); - binning_ = (int)binSize; - if(!AcqDevice_.SetFeatureValue("BinningVertical", binning_)) - return DEVICE_ERR; - if(!AcqDevice_.SetFeatureValue("BinningHorizontal", binning_)) - return DEVICE_ERR; - return ResizeImageBuffer(); - } - else if (eAct == MM::BeforeGet) - { - pProp->Set((long)binning_); - } - - return DEVICE_OK; -} - -/** -* Handles "PixelType" property. -*/ -int TestCamera::OnPixelType(MM::PropertyBase* pProp, MM::ActionType eAct) -{ - //bytesPerPixel_ = 1; - //ResizeImageBuffer(); - //return DEVICE_OK; - if (eAct == MM::AfterSet) - { - //SapManager::DisplayMessage("(Sapera app)OnPixelType MM:AfterSet"); - string val; - pProp->Get(val); - if (val.compare(g_PixelType_8bit) == 0) - { - if(SapFormatBytes_ != 1) - { - SapFormatBytes_ = 1; - bitsPerPixel_ = 8; - //resize the SapBuffer - int ret = SapBufferReformat(SapFormatMono8, "Mono8"); - if(ret != DEVICE_OK) - { - return ret; - } - } - bytesPerPixel_ = 1; - } - else if (val.compare(g_PixelType_10bit) == 0) - { - if(SapFormatBytes_ != 2) - { - SapFormatBytes_ = 2; - bitsPerPixel_ = 10; - //resize the SapBuffer - int ret = SapBufferReformat(SapFormatMono16, "Mono10"); - if(ret != DEVICE_OK) - { - return ret; - } - } - bytesPerPixel_ = 2; - } - else - assert(false); - - ResizeImageBuffer(); - } - else if (eAct == MM::BeforeGet) - { - if (bytesPerPixel_ == 1) - pProp->Set(g_PixelType_8bit); - else if (bytesPerPixel_ == 2) - pProp->Set(g_PixelType_10bit); - else - assert(false); // this should never happen - } - - return DEVICE_OK; -} - -/** -* Handles "Gain" property. -*/ -int TestCamera::OnGain(MM::PropertyBase* pProp, MM::ActionType eAct) -{ - if (eAct == MM::AfterSet) - { - //SapManager::DisplayMessage("(Sapera app)OnGain MM:AfterSet"); - pProp->Get(gain_); - AcqDevice_.SetFeatureValue("Gain", gain_); - } - else if (eAct == MM::BeforeGet) - { - pProp->Set(gain_); - } - - return DEVICE_OK; -} - - -/////////////////////////////////////////////////////////////////////////////// -// Private TestCamera methods -/////////////////////////////////////////////////////////////////////////////// - -/** -* Sync internal image buffer size to the chosen property values. -*/ -int TestCamera::ResizeImageBuffer() -{ - img_.Resize(IMAGE_WIDTH/binning_, IMAGE_HEIGHT/binning_, bytesPerPixel_); - - return DEVICE_OK; -} - -/** - * Generate an image with fixed value for all pixels - */ -void TestCamera::GenerateImage() -{ - const int maxValue = (1 << MAX_BIT_DEPTH) - 1; // max for the 12 bit camera - const double maxExp = 1000; - double step = maxValue/maxExp; - unsigned char* pBuf = const_cast(img_.GetPixels()); - memset(pBuf, (int) (step * max(exposureMs_, maxExp)), img_.Height()*img_.Width()*img_.Depth()); -} - -/* - * Reformat Sapera Buffer Object - */ -int TestCamera::SapBufferReformat(SapFormat format, const char * acqFormat) -{ - Xfer_->Destroy(); - AcqDevice_.SetFeatureValue("PixelFormat", acqFormat); - Buffers_.Destroy(); - Buffers_ = SapBufferWithTrash(2, &AcqDevice_); - Buffers_.SetFormat(format); - AcqDeviceToBuf_ = SapAcqDeviceToBuf(&AcqDevice_, &Buffers_); - Xfer_ = &AcqDeviceToBuf_; - if(!Buffers_.Create()) - { - //SapManager::DisplayMessage("Failed to recreate Buffer - SapBufferReformat"); - int ret = FreeHandles(); - if (ret != DEVICE_OK) - return ret; - return DEVICE_NATIVE_MODULE_FAILED; - } - if(Xfer_ && !Xfer_->Create()) - { - //SapManager::DisplayMessage("Xfer_ recreation failed - SapBufferReformat"); - int ret = FreeHandles(); - if (ret != DEVICE_OK) - return ret; - return DEVICE_NATIVE_MODULE_FAILED; - } - return DEVICE_OK; -} - -/////////////////////////////////////////////////////////////////////////////// -// Threading methods -/////////////////////////////////////////////////////////////////////////////// - -int SequenceThread::svc() -{ - //SapManager::DisplayMessage("SequenceThread Start"); - long count(0); - while (!stop_ )//&& count < numImages_) - { - /*int ret = camera_->SnapImage(); - if (ret != DEVICE_OK) - { - //SapManager::DisplayMessage("SequenceThread Snap failed"); - camera_->StopSequenceAcquisition(); - return 1; - }*/ - - int ret = camera_->InsertImage(); - if (ret != DEVICE_OK) - { - //SapManager::DisplayMessage("SequenceThread InsertFailed"); - camera_->StopSequenceAcquisition(); - return 1; - } - //count++; - } - //SapManager::DisplayMessage("SequenceThread End"); - return 0; -} \ No newline at end of file diff --git a/DeviceAdapters/TeledyneDalsaGigE/TestCamera.h b/DeviceAdapters/TeledyneDalsaGigE/TestCamera.h deleted file mode 100644 index b3808676e6..0000000000 --- a/DeviceAdapters/TeledyneDalsaGigE/TestCamera.h +++ /dev/null @@ -1,154 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// FILE: TestCamera.h -// PROJECT: Micro-Manager -// SUBSYSTEM: DeviceAdapters -//----------------------------------------------------------------------------- -// DESCRIPTION: Skeleton code for the micro-manager camera adapter. Use it as -// starting point for writing custom device adapters -// -// AUTHOR: Nenad Amodaj, http://nenad.amodaj.com -// -// COPYRIGHT: University of California, San Francisco, 2011 -// -// LICENSE: This file is distributed under the BSD license. -// License text is included with the source distribution. -// -// This file is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. -// - -#ifndef _TestCamera_H_ -#define _TestCamera_H_ - -#include "DeviceBase.h" -#include "ImgBuffer.h" -#include "DeviceThreads.h" -#include "ImgBuffer.h" -#include "stdio.h" -#include "conio.h" -#include "math.h" -#include "sapclassbasic.h" -#include - -////////////////////////////////////////////////////////////////////////////// -// Error codes -// -#define ERR_UNKNOWN_MODE 102 - -class SequenceThread; - -class TestCamera : public CCameraBase -{ -public: - TestCamera(); - ~TestCamera(); - - // MMDevice API - // ------------ - int Initialize(); - int Shutdown(); - - void GetName(char* name) const; - - // TestCamera API - // ------------ - int SnapImage(); - const unsigned char* GetImageBuffer(); - unsigned GetImageWidth() const; - unsigned GetImageHeight() const; - unsigned GetImageBytesPerPixel() const; - unsigned GetBitDepth() const; - long GetImageBufferSize() const; - double GetExposure() const; - void SetExposure(double exp); - int SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize); - int GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize); - int ClearROI(); - int PrepareSequenceAcqusition(); - int StartSequenceAcquisition(double interval); - int StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow); - int StopSequenceAcquisition(); - bool IsCapturing(); - int GetBinning() const; - int SetBinning(int binSize); - int IsExposureSequenceable(bool& seq) const {seq = false; return DEVICE_OK;} - - // action interface - // ---------------- - int OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct); - int OnPixelType(MM::PropertyBase* pProp, MM::ActionType eAct); - int OnGain(MM::PropertyBase* pProp, MM::ActionType eAct); - -private: - friend class SequenceThread; - static const int IMAGE_WIDTH = 1920; - static const int IMAGE_HEIGHT = 1200; - static const int MAX_BIT_DEPTH = 12; - - SequenceThread* thd_; - int binning_; - int bytesPerPixel_; - int bitsPerPixel_; - double gain_; - double exposureMs_; - bool initialized_; - ImgBuffer img_; - int roiX_, roiY_; - bool sequenceRunning_; - - int ResizeImageBuffer(); - void GenerateImage(); - int InsertImage(); - - UINT32 acqDeviceNumber_; - char* acqServerName_; - char* configFilename_; - SapAcquisition Acq_; - SapAcqDevice AcqDevice_; - SapBufferWithTrash Buffers_; - SapTransfer AcqToBuf_; - SapTransfer AcqDeviceToBuf_; - SapTransfer* Xfer_; - SapLocation loc_; - SapFeature SapGain_; - int SapFormatBytes_; - - int FreeHandles(); - int ErrorBox(LPCWSTR text, LPCWSTR caption); - LPCWSTR TestCamera::string2winstring(const std::string& s); - int SapBufferReformat(SapFormat format, const char * acqFormat); -}; - - -//threading stuff. Tread lightly -class SequenceThread : public MMDeviceThreadBase -{ - public: - SequenceThread(TestCamera* pCam) : stop_(false), numImages_(0) {camera_ = pCam;} - ~SequenceThread() {} - - int svc (void); - - void Stop() {stop_ = true;} - - void Start() - { - stop_ = false; - activate(); - } - - void SetLength(long images) {numImages_ = images;} - long GetLength(void) {return numImages_;}; - - private: - TestCamera* camera_; - bool stop_; - long numImages_; -}; - -#endif //_TestCamera_H_ From 3c0150c3f7ccfa4abdb7c7283666048d0158263a Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 18 Sep 2020 13:20:18 -0500 Subject: [PATCH 3/5] Add SaperaGigE.sln --- DeviceAdapters/SaperaGigE/SaperaGigE.sln | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 DeviceAdapters/SaperaGigE/SaperaGigE.sln diff --git a/DeviceAdapters/SaperaGigE/SaperaGigE.sln b/DeviceAdapters/SaperaGigE/SaperaGigE.sln new file mode 100644 index 0000000000..f644df37b0 --- /dev/null +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30309.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SaperaGigE", "SaperaGigE.vcxproj", "{DE209272-1DA7-4551-9D34-3ECE99DDE827}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMDevice-SharedRuntime", "..\..\MMDevice\MMDevice-SharedRuntime.vcxproj", "{B8C95F39-54BF-40A9-807B-598DF2821D55}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Debug|x64.ActiveCfg = Debug|x64 + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Debug|x64.Build.0 = Debug|x64 + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Debug|x86.ActiveCfg = Debug|Win32 + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Debug|x86.Build.0 = Debug|Win32 + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Release|x64.ActiveCfg = Release|x64 + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Release|x64.Build.0 = Release|x64 + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Release|x86.ActiveCfg = Release|Win32 + {DE209272-1DA7-4551-9D34-3ECE99DDE827}.Release|x86.Build.0 = Release|Win32 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Debug|x64.ActiveCfg = Debug|x64 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Debug|x64.Build.0 = Debug|x64 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Debug|x86.ActiveCfg = Debug|Win32 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Debug|x86.Build.0 = Debug|Win32 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Release|x64.ActiveCfg = Release|x64 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Release|x64.Build.0 = Release|x64 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Release|x86.ActiveCfg = Release|Win32 + {B8C95F39-54BF-40A9-807B-598DF2821D55}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {27BEF3A4-9D38-46E3-BAA7-EE3F618BEEC2} + EndGlobalSection +EndGlobal From f4c395a03869dc984548dc78fbf20b33b244c591 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 20 Sep 2020 09:53:46 -0500 Subject: [PATCH 4/5] Backport C++11 to WindowsSDK7.1 --- DeviceAdapters/SaperaGigE/SaperaGigE.cpp | 83 ++++++++++++++++---- DeviceAdapters/SaperaGigE/SaperaGigE.h | 50 ++---------- DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj | 4 +- 3 files changed, 77 insertions(+), 60 deletions(-) diff --git a/DeviceAdapters/SaperaGigE/SaperaGigE.cpp b/DeviceAdapters/SaperaGigE/SaperaGigE.cpp index 41f5852d32..c44e6e0fb2 100644 --- a/DeviceAdapters/SaperaGigE/SaperaGigE.cpp +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.cpp @@ -207,13 +207,68 @@ int SaperaGigE::Initialize() if (ret != DEVICE_OK) return ret; + // set up feature type correspondence + std::map featureTypes; + + featureTypes[SapFeature::TypeString] = MM::String; + featureTypes[SapFeature::TypeEnum] = MM::String; + featureTypes[SapFeature::TypeInt32] = MM::Integer; + featureTypes[SapFeature::TypeFloat] = MM::Float; + featureTypes[SapFeature::TypeDouble] = MM::Float; + featureTypes[SapFeature::TypeUndefined] = MM::String; + // set property list // ----------------- + std::map< const char*, feature > deviceFeatures; + + deviceFeatures[MM::g_Keyword_PixelType] = define_feature( "PixelFormat", false, + new CPropertyAction(this, &SaperaGigE::OnPixelType) ); + deviceFeatures[MM::g_Keyword_Exposure] = define_feature( "ExposureTime", false, + new CPropertyAction(this, &SaperaGigE::OnExposure) ); + deviceFeatures[MM::g_Keyword_Gain] = define_feature( "Gain", false, + new CPropertyAction(this, &SaperaGigE::OnGain) ); + deviceFeatures["CameraVendor"] = define_feature( "DeviceVendorName", true, NULL ); + deviceFeatures["CameraFamily"] = define_feature( "DeviceFamilyName", true, NULL ); + deviceFeatures[MM::g_Keyword_CameraName] = define_feature( "DeviceModelName", true, NULL ); + deviceFeatures["CameraVersion"] = define_feature( "DeviceVersion", true, NULL ); + deviceFeatures["CameraInfo"] = define_feature( "DeviceManufacturerInfo", true, NULL ); + deviceFeatures["CameraPartNumber"] = define_feature( "deviceManufacturerPartNumber", true, NULL ); + deviceFeatures["CameraFirmwareVersion"] = define_feature( "DeviceFirmwareVersion", true, NULL ); + deviceFeatures["CameraSerialNumber"] = define_feature( "DeviceSerialNumber", true, NULL ); + deviceFeatures[MM::g_Keyword_CameraID] = define_feature( "DeviceUserID", true, NULL ); + deviceFeatures["CameraMacAddress"] = define_feature( "deviceMacAddress", true, NULL ); + deviceFeatures["SensorColorType"] = define_feature( "sensorColorType", true, NULL ); + deviceFeatures["SensorPixelCoding"] = define_feature( "PixelCoding", true, NULL ); + deviceFeatures["SensorBlackLevel"] = define_feature( "BlackLevel", true, NULL ); + deviceFeatures["SensorPixelInput"] = define_feature( "pixelSizeInput", true, NULL ); + deviceFeatures["SensorShutterMode"] = define_feature( "SensorShutterMode", false, NULL ); + deviceFeatures["SensorBinningMode"] = define_feature( "binningMode", false, + new CPropertyAction(this, &SaperaGigE::OnBinningMode) ); + deviceFeatures["SensorWidth"] = define_feature( "SensorWidth", true, NULL ); + deviceFeatures["SensorHeight"] = define_feature( "SensorHeight", true, NULL ); + deviceFeatures["ImagePixelSize"] = define_feature( "PixelSize", true, + new CPropertyAction(this, &SaperaGigE::OnPixelSize) ); + deviceFeatures["ImageHorizontalOffset"] = define_feature( "OffsetX", false, + new CPropertyAction(this, &SaperaGigE::OnOffsetX) ); + deviceFeatures["ImageVerticalOffset"] = define_feature( "OffsetY", false, + new CPropertyAction(this, &SaperaGigE::OnOffsetY) ); + deviceFeatures["ImageWidth"] = define_feature( "Width", false, + new CPropertyAction(this, &SaperaGigE::OnWidth) ); + deviceFeatures["ImageHeight"] = define_feature( "Height", false, + new CPropertyAction(this, &SaperaGigE::OnHeight) ); + deviceFeatures["ImageTimeout"] = define_feature( "ImageTimeout", false, + new CPropertyAction(this, &SaperaGigE::OnImageTimeout) ); + deviceFeatures["TurboTransferEnable"] = define_feature( "turboTransferEnable", true, NULL ); + deviceFeatures["SensorTemperature"] = define_feature( "DeviceTemperature", true, + new CPropertyAction(this, &SaperaGigE::OnTemperature) ); + // device features - for (auto const& x : deviceFeatures) + //for (auto const& x : deviceFeatures) + std::map< const char*, feature >::iterator x; + for (x = deviceFeatures.begin(); x != deviceFeatures.end(); x++) { - feature f = x.second; + feature f = x->second; BOOL isAvailable; AcqDevice_.IsFeatureAvailable(f.name, &isAvailable); if (!isAvailable) @@ -224,7 +279,7 @@ int SaperaGigE::Initialize() } LogMessage((std::string) "Adding feature '" + f.name - + "' as property '" + x.first + "'"); + + "' as property '" + x->first + "'"); char value[MM::MaxStrLength]; if (!AcqDevice_.GetFeatureValue(f.name, value, sizeof(value))) return DEVICE_ERR; @@ -233,17 +288,17 @@ int SaperaGigE::Initialize() SapFeature::Type sapType; AcqFeature_.GetType(&sapType); std::map< SapFeature::Type, MM::PropertyType>::iterator it; - it = featureType.find(sapType); + it = featureTypes.find(sapType); MM::PropertyType eType; - if (it == featureType.end()) + if (it == featureTypes.end()) eType = MM::String; else eType = it->second; if (f.action == NULL) - ret = CreateProperty(x.first, value, eType, f.readOnly); + ret = CreateProperty(x->first, value, eType, f.readOnly); else - ret = CreateProperty(x.first, value, eType, f.readOnly, f.action); + ret = CreateProperty(x->first, value, eType, f.readOnly, f.action); assert(ret == DEVICE_OK); if (sapType == SapFeature::TypeEnum) @@ -256,7 +311,7 @@ int SaperaGigE::Initialize() AcqFeature_.GetEnumString(i, value, sizeof(value)); allowed.push_back(value); } - ret = SetAllowedValues(x.first, allowed); + ret = SetAllowedValues(x->first, allowed); assert(ret == DEVICE_OK); } } @@ -627,7 +682,7 @@ int SaperaGigE::OnPixelSize(MM::PropertyBase* pProp, MM::ActionType eAct) long SaperaGigE::CheckValue(const char* key, long value) { - int64_t min, max, inc; + INT64 min, max, inc; AcqDevice_.GetFeatureInfo(key, &AcqFeature_); AcqFeature_.GetInc(&inc); AcqFeature_.GetMin(&min); @@ -638,7 +693,7 @@ long SaperaGigE::CheckValue(const char* key, long value) if (value != out) LogMessage((std::string) "Encountered invalid value for '" + key - + "': corrected " + std::to_string(value) + " to " + std::to_string(out)); + + "': corrected " + std::to_string((INT64) value) + " to " + std::to_string((INT64) out)); return out; } @@ -925,7 +980,7 @@ void SaperaGigE::XferCallback(SapXferCallbackInfo* pInfo) if (pInfo->IsTrash()) { ErrorBox((std::string) "Frames acquired in trash buffer: " - + std::to_string(pInfo->GetEventCount()), "Xfer"); + + std::to_string((INT64) pInfo->GetEventCount()), "Xfer"); } } @@ -953,7 +1008,7 @@ int SaperaGigE::SetUpBinningProperties() if (DEVICE_OK != ret) return ret; - int64_t bin, min, max, inc; + INT64 bin, min, max, inc; std::vector vValues, hValues, binValues; // vertical binning @@ -967,7 +1022,7 @@ int SaperaGigE::SetUpBinningProperties() AcqFeature_.GetMin(&min); AcqFeature_.GetMax(&max); AcqFeature_.GetInc(&inc); - for (int64_t i = min; i <= max; i += inc) + for (INT64 i = min; i <= max; i += inc) vValues.push_back(std::to_string(i)); // horizontal binning @@ -981,7 +1036,7 @@ int SaperaGigE::SetUpBinningProperties() AcqFeature_.GetMin(&min); AcqFeature_.GetMax(&max); AcqFeature_.GetInc(&inc); - for (int64_t i = min; i <= max; i += inc) + for (INT64 i = min; i <= max; i += inc) hValues.push_back(std::to_string(i)); // possible uniform binning values. diff --git a/DeviceAdapters/SaperaGigE/SaperaGigE.h b/DeviceAdapters/SaperaGigE/SaperaGigE.h index 8548530878..8dc166081c 100644 --- a/DeviceAdapters/SaperaGigE/SaperaGigE.h +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.h @@ -33,7 +33,7 @@ #include "SapClassBasic.h" #include "../MMDevice/ModuleInterface.h" #include -#include +#include ////////////////////////////////////////////////////////////////////////////// // Error codes @@ -45,21 +45,13 @@ class SequenceThread; const char* g_CameraDeviceName = "Sapera GigE camera adapter"; const char* g_CameraServer = "AcquisitionDevice"; -std::map< SapFeature::Type, MM::PropertyType > featureType = { - {SapFeature::TypeString, MM::String}, - {SapFeature::TypeEnum, MM::String}, - {SapFeature::TypeInt32, MM::Integer}, - {SapFeature::TypeFloat, MM::Float}, - {SapFeature::TypeDouble, MM::Float}, - {SapFeature::TypeUndefined, MM::String} -}; - std::wstring s2ws(const std::string&); int ErrorBox(std::string text, std::string caption); class SaperaGigE : public CCameraBase { private: + struct feature { char* name; @@ -67,40 +59,10 @@ class SaperaGigE : public CCameraBase CPropertyAction* action; }; - const std::map< const char*, feature > deviceFeatures = { - // information on device - use names shown in Sapera CamExpert - {MM::g_Keyword_PixelType, {"PixelFormat", false, new CPropertyAction(this, &SaperaGigE::OnPixelType)}}, - {MM::g_Keyword_Exposure, {"ExposureTime", false, new CPropertyAction(this, &SaperaGigE::OnExposure)}}, - {MM::g_Keyword_Gain, {"Gain", false, new CPropertyAction(this, &SaperaGigE::OnGain)}}, - {"CameraVendor", {"DeviceVendorName", true, NULL}}, - {"CameraFamily", {"DeviceFamilyName", true, NULL}}, - {MM::g_Keyword_CameraName, {"DeviceModelName", true, NULL}}, - {"CameraVersion", {"DeviceVersion", true, NULL}}, - {"CameraInfo", {"DeviceManufacturerInfo", true, NULL}}, - {"CameraPartNumber", {"deviceManufacturerPartNumber", true, NULL}}, - {"CameraFirmwareVersion", {"DeviceFirmwareVersion", true, NULL}}, - {"CameraSerialNumber", {"DeviceSerialNumber", true, NULL}}, - {MM::g_Keyword_CameraID, {"DeviceUserID", true, NULL}}, - {"CameraMacAddress", {"deviceMacAddress", true, NULL}}, - {"SensorColorType", {"sensorColorType", true, NULL}}, - {"SensorPixelCoding", {"PixelCoding", true, NULL}}, - {"SensorBlackLevel", {"BlackLevel", true, NULL}}, - {"SensorPixelInput", {"pixelSizeInput", true, NULL}}, - {"SensorShutterMode", {"SensorShutterMode", false, NULL}}, - {"SensorBinningMode", {"binningMode", false, new CPropertyAction(this, &SaperaGigE::OnBinningMode)}}, - {"SensorWidth", {"SensorWidth", true, NULL}}, - {"SensorHeight", {"SensorHeight", true, NULL}}, - {"ImagePixelSize", {"PixelSize", true, new CPropertyAction(this, &SaperaGigE::OnPixelSize)}}, - {"ImageHorizontalOffset", {"OffsetX", false, new CPropertyAction(this, &SaperaGigE::OnOffsetX)}}, - {"ImageVerticalOffset", {"OffsetY", false, new CPropertyAction(this, &SaperaGigE::OnOffsetY)}}, - {"ImageWidth", {"Width", false, new CPropertyAction(this, &SaperaGigE::OnWidth)}}, - {"ImageHeight", {"Height", false, new CPropertyAction(this, &SaperaGigE::OnHeight)}}, - {"ImageTimeout", {"ImageTimeout", false, new CPropertyAction(this, &SaperaGigE::OnImageTimeout)}}, - {"TurboTransferEnable", {"turboTransferEnable", true, NULL}}, - {"SensorTemperature", {"DeviceTemperature", true, new CPropertyAction(this, &SaperaGigE::OnTemperature)}}, - //{"ReverseX", {"ReverseX", true, NULL}}, - //{MM::g_Keyword_Transpose_MirrorY, {"ReverseY", true, NULL}}, - }; + feature define_feature(char* name, bool readOnly, CPropertyAction* action) { + feature out = { name, readOnly, action }; + return out; + } public: SaperaGigE(); diff --git a/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj b/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj index 00b23dbef0..794a5c5290 100644 --- a/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.vcxproj @@ -36,7 +36,7 @@ DynamicLibrary true Unicode - v142 + Windows7.1SDK DynamicLibrary @@ -49,7 +49,7 @@ false true Unicode - v142 + Windows7.1SDK From f997eba093e001b86f9909bed467c451ffe6439e Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 1 Oct 2020 08:47:11 -0500 Subject: [PATCH 5/5] Add some logging messages --- DeviceAdapters/SaperaGigE/SaperaGigE.cpp | 40 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/DeviceAdapters/SaperaGigE/SaperaGigE.cpp b/DeviceAdapters/SaperaGigE/SaperaGigE.cpp index c44e6e0fb2..1783ac3c46 100644 --- a/DeviceAdapters/SaperaGigE/SaperaGigE.cpp +++ b/DeviceAdapters/SaperaGigE/SaperaGigE.cpp @@ -391,6 +391,7 @@ int SaperaGigE::SnapImage() Xfer_->SetCommandTimeout(1000); if (!Xfer_->Snap(1)) { + LogMessage("Failure occurred while capturing a single image"); return DEVICE_ERR; } // Wait for either the capture to finish or 2.5 seconds, whichever is first @@ -584,7 +585,7 @@ int SaperaGigE::SetBinning(int binF) int SaperaGigE::StopSequenceAcquisition() { //@TODO: Implement Sequence Acquisition - return DEVICE_ERR; + return DEVICE_NOT_YET_IMPLEMENTED; /*thd_->Stop(); thd_->wait(); sequenceRunning_ = false; @@ -599,7 +600,7 @@ int SaperaGigE::StopSequenceAcquisition() int SaperaGigE::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) { //@TODO: Implement Sequence Acquisition - return DEVICE_ERR; + return DEVICE_NOT_YET_IMPLEMENTED; /*if (sequenceRunning_) { return DEVICE_CAMERA_BUSY_ACQUIRING; @@ -813,7 +814,10 @@ int SaperaGigE::OnTemperature(MM::PropertyBase* pProp, MM::ActionType eAct) { double value; if (!AcqDevice_.GetFeatureValue("DeviceTemperature", &value)) + { + LogMessage("Failed to get feature value for 'DeviceTemperature'"); return DEVICE_ERR; + } pProp->Set(value); } return DEVICE_OK; @@ -856,11 +860,19 @@ int SaperaGigE::OnGain(MM::PropertyBase* pProp, MM::ActionType eAct) if (eAct == MM::AfterSet) { pProp->Get(gain); - AcqDevice_.SetFeatureValue("Gain", gain); + if (!AcqDevice_.SetFeatureValue("Gain", gain)) + { + LogMessage("Failed to set feature value for 'Gain'"); + return DEVICE_ERR; + } } else if (eAct == MM::BeforeGet) { - AcqDevice_.GetFeatureValue("Gain", &gain); + if (!AcqDevice_.GetFeatureValue("Gain", &gain)) + { + LogMessage("Failed to get feature value for 'Gain'"); + return DEVICE_ERR; + } pProp->Set(gain); } @@ -870,22 +882,24 @@ int SaperaGigE::OnGain(MM::PropertyBase* pProp, MM::ActionType eAct) int SaperaGigE::OnExposure(MM::PropertyBase* pProp, MM::ActionType eAct) { // note that GigE units of exposure are us; umanager uses ms + double exposure; if (eAct == MM::AfterSet) { - double oldd = 0, newd = 0; - AcqDevice_.GetFeatureValue("ExposureTime", &oldd); // us - pProp->Get(newd); // ms - if (!AcqDevice_.SetFeatureValue("ExposureTime", newd * 1000.0)) // ms to us + pProp->Get(exposure); // ms + if (!AcqDevice_.SetFeatureValue("ExposureTime", exposure * 1000.0)) // ms to us { - pProp->Set(oldd / 1000.0); // us to ms - return DEVICE_INVALID_PROPERTY_VALUE; + LogMessage("Failed to set feature value for 'ExposureTime'"); + return DEVICE_ERR; } } else if (eAct == MM::BeforeGet) { - double d = 0; - if (AcqDevice_.GetFeatureValue("ExposureTime", &d)) // us - pProp->Set(d / 1000.0); + if (!AcqDevice_.GetFeatureValue("ExposureTime", &exposure)) // us + { + LogMessage("Failed to get feature value for 'ExposureTime'"); + return DEVICE_ERR; + } + pProp->Set(exposure / 1000.0); } return DEVICE_OK; }