diff --git a/DeviceAdapters/QSI/QSI.vcxproj b/DeviceAdapters/QSI/QSI.vcxproj
new file mode 100644
index 000000000..4bcadef65
--- /dev/null
+++ b/DeviceAdapters/QSI/QSI.vcxproj
@@ -0,0 +1,112 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+ {b8c95f39-54bf-40a9-807b-598df2821d55}
+
+
+
+ 16.0
+ Win32Proj
+ {320af64e-c4fc-4a97-a7d1-f8233a8a44c7}
+ QSI
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ _DEBUG;QSI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+ $(MM_3RDPARTYPRIVATE)\QSI\QSISDK_2022_07_19\include;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ false
+ QSICameraCLib.lib;%(AdditionalDependencies)
+ $(MM_3RDPARTYPRIVATE)\QSI\QSISDK_2022_07_19\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;QSI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+ $(MM_3RDPARTYPRIVATE)\QSI\QSISDK_20200917\QSICameraCLib\include;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ true
+ true
+ false
+ QSICameraCLib.lib;%(AdditionalDependencies)
+ $(MM_3RDPARTYPRIVATE)\QSI\QSISDK_20200917\QSICameraCLib\lib\x64;%(AdditionalLibraryDirectories)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DeviceAdapters/QSI/QSI.vcxproj.filters b/DeviceAdapters/QSI/QSI.vcxproj.filters
new file mode 100644
index 000000000..9b679b903
--- /dev/null
+++ b/DeviceAdapters/QSI/QSI.vcxproj.filters
@@ -0,0 +1,33 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/DeviceAdapters/QSI/QSICameraAdapter.cpp b/DeviceAdapters/QSI/QSICameraAdapter.cpp
new file mode 100644
index 000000000..c52873ff5
--- /dev/null
+++ b/DeviceAdapters/QSI/QSICameraAdapter.cpp
@@ -0,0 +1,1869 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FILE: QSICameraAdapter.cpp
+// PROJECT: Micro-Manager
+// SUBSYSTEM: DeviceAdapters
+//-----------------------------------------------------------------------------
+// DESCRIPTION: QSI camera adapter for use with Micro-Manager
+//
+// COPYRIGHT: Quantum Scientific Imaging, Inc. 2024
+//
+
+#include "QSICameraAdapter.h"
+#include "QSIToolkit.h"
+#include
+
+using namespace std;
+
+#pragma region [ Local Constants ]
+
+namespace QSIString
+{
+ // A namespace is being used so there's no chance of name collisions
+
+ const char * const ANTI_BLOOMING = "AntiBlooming";
+ const char * const ANTI_BLOOMING_HIGH = "High";
+ const char * const ANTI_BLOOMING_NORMAL = "Normal";
+ const char * const BINNING_MAX_X = "BinningMaxX";
+ const char * const BINNING_MAX_Y = "BinningMaxY";
+ const char * const BODY_TEMPERATURE = "BodyTemperature";
+ const char * const CONNECT_TO_SERIAL_NUMBER = "ConnectToSerialNumber";
+ const char * const CONNECT_TO_SERIAL_NUMBER_ANY = "Any";
+ const char * const COOLER_STATE = "CoolerState";
+ const char * const COOLER_STATE_ON = "On";
+ const char * const COOLER_STATE_OFF = "Off";
+ const char * const COOLER_POWER = "CoolerPower";
+ const char * const DEVICE_NAME = "QSI Camera";
+ const char * const DEVICE_DESCRIPTION = "QSI camera adapter";
+ const char * const DRIVER_INFO = "DriverInfo";
+ const char * const ELECTRONS_PER_ADU = "ElectronsPerADU";
+ const char * const EXPOSURE_MAX = "ExposureDurationMax";
+ const char * const EXPOSURE_MIN = "ExposureDurationMin";
+ const char * const FAN_MODE = "FanMode";
+ const char * const FAN_MODE_OFF = "Off";
+ const char * const FAN_MODE_QUIET = "Quiet";
+ const char * const FAN_MODE_FULL = "Full";
+ const char * const FILTER_WHEEL_POSITION = "FilterWheelPosition";
+ const char * const FILTER_WHEEL_POSITIONS = "FilterWheelPositions";
+ const char * const FULL_WELL_CAPACITY = "FullWellCapacity";
+ const char * const GAIN_MODE = "GainMode";
+ const char * const GAIN_MODE_HIGH = "High";
+ const char * const GAIN_MODE_LOW = "Low";
+ const char * const HAS_FILTER_WHEEL = "HasFilterWheel";
+ const char * const HAS_FILTER_WHEEL_NO = "No";
+ const char * const HAS_FILTER_WHEEL_YES = "Yes";
+ const char * const HAS_SHUTTER = "HasShutter";
+ const char * const HAS_SHUTTER_NO = "No";
+ const char * const HAS_SHUTTER_YES = "Yes";
+ const char * const LED_SETTING = "LEDSetting";
+ const char * const LED_SETTING_ENABLED = "Enabled";
+ const char * const LED_SETTING_DISABLED = "Disabled";
+ const char * const MAX_ADU = "MaxADU";
+ const char * const MODEL_NAME = "ModelName";
+ const char * const MODEL_NUMBER = "ModelNumber";
+ const char * const OPEN_SHUTTER = "OpenShutterDuringExposure";
+ const char * const OPEN_SHUTTER_NO = "No";
+ const char * const OPEN_SHUTTER_YES = "Yes";
+ const char * const PCB_TEMPERATURE = "PCBTemperature";
+ const char * const PIXEL_SIZE_X = "PixelSizeX";
+ const char * const PIXEL_SIZE_Y = "PixelSizeY";
+ const char * const PRE_EXPOSURE_FLUSH = "PreExposureFlush";
+ const char * const PRE_EXPOSURE_FLUSH_NONE = "None";
+ const char * const PRE_EXPOSURE_FLUSH_MODEST = "Modest";
+ const char * const PRE_EXPOSURE_FLUSH_NORMAL = "Normal";
+ const char * const PRE_EXPOSURE_FLUSH_AGGRESSIVE = "Aggressive";
+ const char * const PRE_EXPOSURE_FLUSH_VERY_AGGRESSIVE = "Very Aggressive";
+ const char * const READOUT_MODE_FAST_READOUT = "Fast Readout";
+ const char * const READOUT_MODE_HIGH_QUALITY = "High Quality";
+ const char * const SERIAL_NUMBER = "SerialNumber";
+ const char * const SHUTTER_PRIORITY = "ShutterPriority";
+ const char * const SHUTTER_PRIORITY_ELECTRONIC = "Electronic";
+ const char * const SHUTTER_PRIORITY_MECHANICAL = "Mechanical";
+ const char * const SOUND_SETTING = "SoundSetting";
+ const char * const SOUND_SETTING_ENABLED = "Enabled";
+ const char * const SOUND_SETTING_DISABLED = "Disabled";
+}
+
+#pragma endregion
+
+#pragma region [ Windows DLL Entry Code ]
+
+// Windows DLL entry code
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/ )
+{
+ switch( ul_reason_for_call )
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+#pragma endregion
+
+#pragma region [ Exported MMDevice API ]
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// List all supported hardware devices here
+//
+MODULE_API void InitializeModuleData()
+{
+ /// Register a device class provided by the device adapter library.
+ /**
+ * To be called in the device adapter module's implementation of
+ * InitializeModuleData().
+ *
+ * Calling this function indicates that the module provides a device with the
+ * given name and type, and provides a user-visible description string.
+ */
+ RegisterDevice(QSIString::DEVICE_NAME, MM::CameraDevice, QSIString::DEVICE_DESCRIPTION);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+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, QSIString::DEVICE_NAME ) == 0 )
+ {
+ // Create camera
+ return new QSICameraAdapter();
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+MODULE_API void DeleteDevice( MM::Device * pDevice )
+{
+ delete pDevice;
+}
+
+#pragma endregion
+
+#pragma region [ QSICameraAdapter - Constructor / Desctructor ]
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// QSICameraAdapter 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.
+//
+QSICameraAdapter::QSICameraAdapter() :
+ m_handle( QSI_HANDLE_INVALID ),
+ m_imageBinning( 1 ),
+ m_imageMaxX( 1 ),
+ m_imageMaxY( 1 ),
+ m_imageNumX( 1 ),
+ m_imageNumY( 1 ),
+ m_imageStartX( 0 ),
+ m_imageStartY( 0 ),
+ m_initialized( false ),
+ m_exposureDuration( 10 ),
+ m_exposureDurationMax( 1000 ),
+ m_exposureDurationMin( 10 ),
+ m_exposureOpenShutter( true ),
+ m_pImageBuffer( 0 ),
+ m_pixelSizeX( 0 ),
+ m_pixelSizeY( 0 ),
+ m_status( QSI_OK )
+{
+ int response;
+
+ // Call the base class method to set-up default error codes/messages
+ InitializeDefaultErrorMessages();
+
+ // Serial number pre-initialization property
+ response = CreateProperty( QSIString::CONNECT_TO_SERIAL_NUMBER, QSIString::CONNECT_TO_SERIAL_NUMBER_ANY, MM::String, false, 0, true );
+ assert( response == DEVICE_OK );
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// QSICameraAdapter 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.
+//
+QSICameraAdapter::~QSICameraAdapter()
+{
+ Shutdown();
+}
+
+#pragma endregion
+
+#pragma region [ QSICameraAdapter - MM::Device Methods ]
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Obtains device name.
+//
+void QSICameraAdapter::GetName( char * name ) const
+{
+ // We just return the name we use for referring to this device adapter.
+ CDeviceUtils::CopyLimitedString( name, QSIString::DEVICE_NAME );
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Intializes the hardware.
+//
+// Typically we access and initialize hardware at this point.
+// Device properties are typically created here as well.
+//
+int QSICameraAdapter::Initialize()
+{
+ char serialNumber[MM::MaxStrLength];
+ int imageBufferSize, response;
+
+
+ // Don't continue if we've already initialized
+ if( m_initialized )
+ return DEVICE_OK;
+
+
+ // Assign meaningful descriptions to error codes
+ SetErrorText( QSI_NOTSUPPORTED, "Not supported." );
+ SetErrorText( QSI_UNRECOVERABLE, "An unrecoverable internal or device error occurred." );
+ SetErrorText( QSI_NOFILTER, "No filterwheel available." );
+ SetErrorText( QSI_NOMEMORY, "Out of memory." );
+ SetErrorText( QSI_BADROWSIZE, "Invalid row size specified." );
+ SetErrorText( QSI_BADCOLSIZE, "Invalid column size specified." );
+ SetErrorText( QSI_INVALIDBIN, "Invalid bin factor specified." );
+ SetErrorText( QSI_NOASYMBIN, "Cannot asymmetric bin." );
+ SetErrorText( QSI_BADEXPOSURE, "Invalid exposure duration specified." );
+ SetErrorText( QSI_BADBINSIZE, "Invalid bin factor specified." );
+ SetErrorText( QSI_NOEXPOSURE, "No prior exposure taken." );
+ SetErrorText( QSI_BADRELAYSTATUS, "An error occurred while getting relay status." );
+ SetErrorText( QSI_BADABORTRELAYS, "An error occurred while aborting active relays." );
+ SetErrorText( QSI_RELAYERROR, "An error occurred while activating relays." );
+ SetErrorText( QSI_INVALIDIMAGEPARAMETER, "One or more image parameters are invalid." );
+ SetErrorText( QSI_NOIMAGEAVAILABLE, "There is no image available for download." );
+ SetErrorText( QSI_NOTCONNECTED, "The camera has not been connected to." );
+ SetErrorText( QSI_INVALIDFILTERNUMBER, "Filter position is invalid." );
+ SetErrorText( QSI_RECOVERABLE, "A recoverable internal error occurred." );
+ SetErrorText( QSI_CONNECTED, "Camera cannot be connected when making this call." );
+ SetErrorText( QSI_INVALIDTEMP, "Invalid temperature specified." );
+ SetErrorText( QSI_TRIGGERTIMEOUT , "Trigger timed out." );
+ SetErrorText( QSI_ERROR_NO_CAMERA, "No camera available." );
+ SetErrorText( QSI_ERROR_NO_SHUTTER, "No shutter available." );
+ SetErrorText( QSI_ERROR_DOWNLOADING, "Camera is busy downloading an image." );
+ SetErrorText( QSI_ERROR_INVALID_HANDLE, "The specified handle is not valid." );
+ SetErrorText( QSI_ERROR_BAD_ARGUMENT, "One of the arguments specified is not valid." );
+ SetErrorText( QSI_ERROR_NULL_POINTER, "A null pointer was passed as an argument." );
+ SetErrorText( QSI_ERROR_INTERNAL_ERROR, "An undefined error occurred." );
+ SetErrorText( QSI_ERROR_NOT_IMPLEMENTED, "Not yet implemented." );
+ SetErrorText( QSI_ERROR_BUFFER_TOO_SMALL, "The specified buffer is too small." );
+ SetErrorText( QSI_ERROR_BUFFER_TOO_LARGE, "The specified buffer is too small." );
+ SetErrorText( QSI_ERROR_NOT_ENABLED, "The requested mode is not enabled." );
+ SetErrorText( QSI_ERROR_CREATE_HANDLE, "C API failed to create handle." );
+ SetErrorText( QSI_ERROR_COMMAND_FAILED, "The command failed." );
+
+ // Grab the serial number from the pre-initialization property created in the constructor
+ GetProperty( QSIString::CONNECT_TO_SERIAL_NUMBER, serialNumber );
+
+ // Connect to the camera
+ QSI_CreateHandle( &m_handle );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( strcmp( QSIString::CONNECT_TO_SERIAL_NUMBER_ANY, serialNumber ) == 0 )
+ {
+ m_status = QSI_Connect( m_handle );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else
+ {
+ m_status = QSI_SetSerialNumber( m_handle, serialNumber, MM::MaxStrLength );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_Connect( m_handle );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+
+ // Get image size info
+ m_status = QSI_GetImageSizeX( m_handle, &m_imageMaxX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetImageSizeY( m_handle, &m_imageMaxY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetImageStartX( m_handle, &m_imageStartX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetImageStartY( m_handle, &m_imageStartY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetImageNumX( m_handle, &m_imageNumX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetImageNumY( m_handle, &m_imageNumY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ // Allocate image buffer and clear it for good measure
+ imageBufferSize = m_imageMaxX * m_imageMaxY * QSI_IMAGE_BYTES_PER_PIXEL;
+
+ m_pImageBuffer = static_cast( malloc( imageBufferSize ) );
+
+ if( m_pImageBuffer == 0 )
+ HANDLE_MM_ERROR( this, DEVICE_OUT_OF_MEMORY, "Out of memory." );
+
+ memset( m_pImageBuffer, 0, imageBufferSize );
+
+ // Setup device properties
+ response = AntiBloomingPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the AntiBlooming property." );
+
+ response = BinningPropertiesSetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the Binning property." );
+
+ response = BodyTemperaturePropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the BodyTemperature property." );
+
+ response = CCDTemperaturePropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the CCDTemperature property." );
+
+ response = CCDTemperatureSetpointPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the CCDTemperatureSetpoint property." );
+
+ response = CoolerPowerPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the CoolerPower property." );
+
+ response = CoolerStatePropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the CoolerState property." );
+
+ response = DescriptionPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the Description property." );
+
+ response = DriverInfoPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the DriverInfo property." );
+
+ response = ExposurePropertiesSetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the Exposure properties." );
+
+ response = FanModePropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the FanMode property." );
+
+ response = FilterWheelPropertiesSetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the FilterWheel properties." );
+
+ response = FullWellCapacityPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the FullWellCapacity property." );
+
+ response = GainPropertiesSetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the Gain properties." );
+
+ response = LEDEnabledPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the LEDEnabled property." );
+
+ response = MaxADUPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the MaxADU property." );
+
+ response = ModelNamePropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the ModelName property." );
+
+ response = ModelNumberPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the ModelNumber property." );
+
+ response = OpenShutterPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the OpenShutter property." );
+
+ response = PCBTemperaturePropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the PCBTemperature property." );
+
+ response = PixelSizePropertiesSetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the PixelSize properties." );
+
+ response = PreExposureFlushPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the PreExposureFlush property." );
+
+ response = ReadoutModePropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the ReadoutMode property." );
+
+ response = SerialNumberPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the SerialNumber property." );
+
+ response = ShutterPropertiesSetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the Shutter properties." );
+
+ response = SoundEnabledPropertySetup();
+ HANDLE_MM_ERROR( this, response, "An error occurred while setting up the SoundEnabled property." );
+
+ // Synchronize all properties
+ response = UpdateStatus();
+ HANDLE_MM_ERROR( this, response, "An error occured while synchronizing properties." );
+
+ // Set a flag so we know that we've been properly initialized
+ m_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.
+//
+int QSICameraAdapter::Shutdown()
+{
+ // Disconnect from camera and release handle
+ if( m_handle != QSI_HANDLE_INVALID )
+ {
+ QSI_Disconnect( m_handle );
+ QSI_ReleaseHandle( m_handle );
+ m_handle = QSI_HANDLE_INVALID;
+ }
+
+ // Free image buffer
+ if( m_pImageBuffer != 0 )
+ {
+ free( m_pImageBuffer );
+ m_pImageBuffer = 0;
+ }
+
+ m_initialized = false;
+
+ return DEVICE_OK;
+}
+
+#pragma endregion
+
+#pragma region [ QSICameraAdapter - MM::Camera Methods ]
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Resets the Region of Interest to full frame.
+//
+int QSICameraAdapter::ClearROI()
+{
+ m_imageNumX = m_imageMaxX / m_imageBinning;
+ m_status = QSI_SetImageNumX( m_handle, m_imageNumX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_imageNumY = m_imageMaxY / m_imageBinning;
+ m_status = QSI_SetImageNumY( m_handle, m_imageNumY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_imageStartX = 0;
+ m_status = QSI_SetImageStartX( m_handle, m_imageStartX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_imageStartY = 0;
+ m_status = QSI_SetImageStartY( m_handle, m_imageStartY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Acquires and inserts an image and it's metadata into MMCore's circular buffer
+//
+int QSICameraAdapter::InsertImage()
+{
+ char label[MM::MaxStrLength];
+ Metadata metadata;
+ const unsigned char * pImageBuffer;
+ int response;
+ const char * pSerializedMetadata;
+
+ // Assemble metadata
+ this->GetLabel( label );
+
+ metadata.put( "Camera", label );
+
+ pSerializedMetadata = metadata.Serialize().c_str();
+
+ // Download image
+ pImageBuffer = GetImageBuffer();
+
+ // Insert received image into MMCore's circular buffer
+ response = GetCoreCallback()->InsertImage( this, pImageBuffer, m_imageNumX, m_imageNumY, QSI_IMAGE_BYTES_PER_PIXEL, pSerializedMetadata );
+
+ if( !isStopOnOverflow() && response == DEVICE_BUFFER_OVERFLOW )
+ {
+ GetCoreCallback()->ClearImageBuffer( this );
+ return GetCoreCallback()->InsertImage( this, pImageBuffer, m_imageNumX, m_imageNumY, QSI_IMAGE_BYTES_PER_PIXEL, pSerializedMetadata, false );
+ }
+ else
+ return response;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::IsExposureSequenceable( bool & seq ) const
+{
+ seq = false;
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns the current binning factor.
+//
+int QSICameraAdapter::GetBinning() const
+{
+ return m_imageBinning;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.
+//
+unsigned int QSICameraAdapter::GetBitDepth() const
+{
+ return QSI_IMAGE_BIT_DEPTH;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns the current exposure setting in milliseconds.
+//
+double QSICameraAdapter::GetExposure() const
+{
+ return m_exposureDuration;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns pixel data.
+//
+// The calling program will assume the size of the buffer based on the values
+// obtained from GetImageBufferSize(), which in turn should be consistent with
+// values returned by GetImageWidth(), GetImageHight() and GetImageBytesPerPixel().
+// The calling program allso assumes that camera never changes the size of
+// the pixel buffer on its own. In other words, the buffer can change only if
+// appropriate properties are set (such as binning, pixel type, etc.)
+//
+const unsigned char * QSICameraAdapter::GetImageBuffer()
+{
+ int imageSize;
+
+ imageSize = m_imageNumX * m_imageNumY;
+
+ m_status = QSI_ReadImage( m_handle, m_pImageBuffer, imageSize );
+
+ if( m_status )
+ {
+ LogMessage( GetLastQSIError( m_handle ), false );
+
+ // Set all image values to 0x0101 (257) to denote an error occurred
+ memset( m_pImageBuffer, 1, m_imageMaxX * m_imageMaxY * QSI_IMAGE_BYTES_PER_PIXEL );
+ }
+
+ return reinterpret_cast( m_pImageBuffer );
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns the size in bytes of the image buffer.
+//
+long QSICameraAdapter::GetImageBufferSize() const
+{
+ return m_imageNumX * m_imageNumY * QSI_IMAGE_BYTES_PER_PIXEL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns image buffer pixel depth in bytes.
+//
+unsigned int QSICameraAdapter::GetImageBytesPerPixel() const
+{
+ return QSI_IMAGE_BYTES_PER_PIXEL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns image buffer Y-size in pixels.
+//
+unsigned int QSICameraAdapter::GetImageHeight() const
+{
+ return m_imageNumY;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns image buffer X-size in pixels.
+//
+unsigned int QSICameraAdapter::GetImageWidth() const
+{
+ return m_imageNumX;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+double QSICameraAdapter::GetPixelSizeUm() const
+{
+ if( m_pixelSizeX == m_pixelSizeY )
+ return m_pixelSizeX;
+ else
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Returns the actual dimensions of the current ROI.
+//
+int QSICameraAdapter::GetROI( unsigned int & x, unsigned int & y, unsigned int & xSize, unsigned int & ySize )
+{
+ x = m_imageStartX;
+ y = m_imageStartY;
+
+ xSize = m_imageNumX;
+ ySize = m_imageNumY;
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sets binning factor.
+//
+int QSICameraAdapter::SetBinning( int binF )
+{
+ return SetProperty( MM::g_Keyword_Binning, CDeviceUtils::ConvertToString( binF ) );
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sets exposure in milliseconds.
+//
+void QSICameraAdapter::SetExposure( double exp )
+{
+ SetProperty( MM::g_Keyword_Exposure, CDeviceUtils::ConvertToString( exp ) );
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sets the camera Region Of Interest.
+// 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.
+//
+// @param x - top-left corner coordinate
+// @param y - top-left corner coordinate
+// @param xSize - width
+// @param ySize - height
+//
+int QSICameraAdapter::SetROI( unsigned x, unsigned y, unsigned xSize, unsigned ySize )
+{
+ if( xSize == 0 && ySize == 0 )
+ {
+ // According to the sample code, this condition is supposed to clear the ROI
+ return ClearROI();
+ }
+ else
+ {
+ m_status = QSI_SetImageNumX( m_handle, xSize );
+ HANDLE_QSI_ERROR( this, m_status );
+ m_imageNumX = xSize;
+
+ m_status = QSI_SetImageNumY( m_handle, ySize );
+ HANDLE_QSI_ERROR( this, m_status );
+ m_imageNumY = ySize;
+
+ m_status = QSI_SetImageStartX( m_handle, x );
+ HANDLE_QSI_ERROR( this, m_status );
+ m_imageStartX = x;
+
+ m_status = QSI_SetImageStartY( m_handle, y );
+ HANDLE_QSI_ERROR( this, m_status );
+ m_imageStartY = y;
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Performs exposure.
+//
+// This function should block during the actual exposure and return immediately afterwards
+// (i.e., before readout). This behavior is needed for proper synchronization with the shutter.
+//
+int QSICameraAdapter::SnapImage()
+{
+ qsi_bool imageReady;
+
+ m_status = QSI_StartExposure( m_handle, m_exposureDuration / 1000.0, m_exposureOpenShutter );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ imageReady = false;
+
+ if( m_exposureDuration > 2 )
+ CDeviceUtils::SleepMs( static_cast( m_exposureDuration ) - 1 );
+
+ while( !imageReady )
+ {
+ m_status = QSI_GetImageReady( m_handle, &imageReady );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// 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 QSICameraAdapter::StartSequenceAcquisition( double interval )
+{
+ return base::StartSequenceAcquisition( LONG_MAX, interval, false );
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Called by BaseSequenceThread during sequence acquisition.
+//
+int QSICameraAdapter::ThreadRun()
+{
+ int response;
+
+ response = SnapImage();
+ if( response ) return response;
+
+ response = InsertImage();
+ if( response ) return response;
+
+ return response;
+}
+
+#pragma endregion
+
+#pragma region [ QSICameraAdapter - Property Methods ]
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::AntiBloomingPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_anti_bloom antiBloom;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::ANTI_BLOOMING_HIGH ) == 0 )
+ m_status = QSI_SetAntiBlooming( m_handle, QSI_ANTI_BLOOM_HIGH );
+ else
+ m_status = QSI_SetAntiBlooming( m_handle, QSI_ANTI_BLOOM_NORMAL );
+
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetAntiBlooming( m_handle, &antiBloom );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( antiBloom == QSI_ANTI_BLOOM_HIGH )
+ pProp->Set( QSIString::ANTI_BLOOMING_HIGH );
+ else
+ pProp->Set( QSIString::ANTI_BLOOMING_NORMAL );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::AntiBloomingPropertySetup()
+{
+ qsi_bool canSetAntiBlooming;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetCanSetAntiBlooming( m_handle, &canSetAntiBlooming );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( canSetAntiBlooming )
+ {
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::AntiBloomingPropertyHandler );
+ response = CreateProperty( QSIString::ANTI_BLOOMING, QSIString::ANTI_BLOOMING_NORMAL, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::ANTI_BLOOMING_NORMAL );
+ values.push_back( QSIString::ANTI_BLOOMING_HIGH );
+
+ response = SetAllowedValues( QSIString::ANTI_BLOOMING, values );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::BinningPropertiesSetup()
+{
+ int maxBinX, maxBinY, maxBin, binX, binY;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetMaxBinX( m_handle, &maxBinX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetMaxBinY( m_handle, &maxBinY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ maxBin = std::min( maxBinX, maxBinY );
+
+ m_status = QSI_GetBinX( m_handle, &binX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetBinY( m_handle, &binY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ // Force symmetric binning
+ if( binX != binY )
+ {
+ m_status = QSI_SetBinY( m_handle, binX );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+
+ m_imageBinning = binX;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::BinningPropertyHandler );
+ response = CreateProperty( MM::g_Keyword_Binning, CDeviceUtils::ConvertToString( m_imageBinning ), MM::Integer, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.reserve( maxBin );
+
+ for( int i = 0; i < maxBin; i++ )
+ values.push_back( CDeviceUtils::ConvertToString( i + 1 ) );
+
+ response = SetAllowedValues( MM::g_Keyword_Binning, values );
+ assert( response == DEVICE_OK );
+
+ response = CreateProperty( QSIString::BINNING_MAX_X, CDeviceUtils::ConvertToString( maxBinX ), MM::Integer, true );
+ assert( response == DEVICE_OK );
+
+ response = CreateProperty( QSIString::BINNING_MAX_Y, CDeviceUtils::ConvertToString( maxBinY ), MM::Integer, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::BinningPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ long binSize;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( binSize );
+
+ m_imageBinning = (int) binSize;
+
+ m_status = QSI_SetBinX( m_handle, (short) binSize );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_SetBinY( m_handle, (short) binSize );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ ClearROI();
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ pProp->Set( (long) m_imageBinning );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::BodyTemperaturePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ double value;
+
+ if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetHeatSinkTemperature( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ pProp->Set( value );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::BodyTemperaturePropertySetup()
+{
+ double value;
+ CPropertyAction * propertyAction;
+ int response;
+
+ m_status = QSI_GetHeatSinkTemperature( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::BodyTemperaturePropertyHandler );
+ response = CreateProperty( QSIString::BODY_TEMPERATURE, CDeviceUtils::ConvertToString( 0.0 ), MM::Float, true, propertyAction );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CCDTemperaturePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ double value;
+
+ if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetCCDTemperature( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ pProp->Set( value );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CCDTemperaturePropertySetup()
+{
+ double value;
+ CPropertyAction * propertyAction;
+ int response;
+
+ m_status = QSI_GetCCDTemperature( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::CCDTemperaturePropertyHandler );
+ response = CreateProperty( MM::g_Keyword_CCDTemperature, CDeviceUtils::ConvertToString( value ), MM::Float, true, propertyAction );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CCDTemperatureSetpointPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ double value;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ m_status = QSI_SetCCDTemperatureSetpoint( m_handle, value );
+ HANDLE_QSI_ERROR( this, m_status );;
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetCCDTemperatureSetpoint( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ pProp->Set( value );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CCDTemperatureSetpointPropertySetup()
+{
+ double value;
+ CPropertyAction * propertyAction;
+ int response;
+
+ m_status = QSI_GetCCDTemperatureSetpoint( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::CCDTemperatureSetpointPropertyHandler );
+ response = CreateProperty( MM::g_Keyword_CCDTemperatureSetPoint, CDeviceUtils::ConvertToString( value ), MM::Float, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CoolerPowerPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ double value;
+
+ if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetCoolerPower( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ pProp->Set( value );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CoolerPowerPropertySetup()
+{
+ double value;
+ CPropertyAction * propertyAction;
+ int response;
+
+ m_status = QSI_GetCoolerPower( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::CoolerPowerPropertyHandler );
+ response = CreateProperty( QSIString::COOLER_POWER, CDeviceUtils::ConvertToString( value ), MM::Float, true, propertyAction );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CoolerStatePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ std::string value;
+ qsi_bool coolerOn;
+ const char * newValue;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::COOLER_STATE_ON ) == 0 )
+ coolerOn = 1;
+ else
+ coolerOn = 0;
+
+ m_status = QSI_SetCoolerOn( m_handle, coolerOn );
+ HANDLE_QSI_ERROR( this, m_status );;
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetCoolerOn( m_handle, &coolerOn );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ if( coolerOn )
+ newValue = QSIString::COOLER_STATE_ON;
+ else
+ newValue = QSIString::COOLER_STATE_OFF;
+
+ pProp->Set( newValue );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::CoolerStatePropertySetup()
+{
+ qsi_bool value;
+ const char * valueString;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetCoolerOn( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ if( value )
+ valueString = QSIString::COOLER_STATE_ON;
+ else
+ valueString = QSIString::COOLER_STATE_OFF;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::CoolerStatePropertyHandler );
+ response = CreateProperty( QSIString::COOLER_STATE, valueString, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::COOLER_STATE_OFF );
+ values.push_back( QSIString::COOLER_STATE_ON );
+
+ response = SetAllowedValues( QSIString::COOLER_STATE, values );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::DescriptionPropertySetup()
+{
+ char value[QSI_LENGTH_DESCRIPTION];
+ int response;
+
+ m_status = QSI_GetDescription( m_handle, value, QSI_LENGTH_DESCRIPTION );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = CreateProperty( MM::g_Keyword_Description, value, MM::String, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::DriverInfoPropertySetup()
+{
+ char value[QSI_LENGTH_DRIVER_INFO];
+ int response;
+
+ m_status = QSI_GetDriverInfo( m_handle, value, QSI_LENGTH_DRIVER_INFO );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = CreateProperty( QSIString::DRIVER_INFO, value, MM::String, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ExposurePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ double value;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+ m_exposureDuration = value;
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ pProp->Set( m_exposureDuration );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ExposurePropertiesSetup()
+{
+ CPropertyAction * propertyAction;
+ int response;
+
+ m_status = QSI_GetMaxExposureTime( m_handle, &m_exposureDurationMax );
+ HANDLE_QSI_ERROR( this, m_status );
+ m_exposureDurationMax *= 1000; // Convert to milliseconds
+
+ m_status = QSI_GetMinExposureTime( m_handle, &m_exposureDurationMin );
+ HANDLE_QSI_ERROR( this, m_status );
+ m_exposureDurationMin *= 1000; // Convert to milliseconds
+
+ if( m_exposureDuration < m_exposureDurationMin )
+ m_exposureDuration = m_exposureDurationMin;
+ else if( m_exposureDuration > m_exposureDurationMax )
+ m_exposureDuration = m_exposureDurationMax;
+
+ response = CreateProperty( QSIString::EXPOSURE_MAX, CDeviceUtils::ConvertToString( m_exposureDurationMax ), MM::String, true );
+ assert( response == DEVICE_OK );
+
+ response = CreateProperty( QSIString::EXPOSURE_MIN, CDeviceUtils::ConvertToString( m_exposureDurationMin ), MM::String, true );
+ assert( response == DEVICE_OK );
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::ExposurePropertyHandler );
+ response = CreateProperty( MM::g_Keyword_Exposure, CDeviceUtils::ConvertToString( m_exposureDuration ), MM::Float, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ response = SetPropertyLimits( MM::g_Keyword_Exposure, m_exposureDurationMin, m_exposureDurationMax );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::FanModePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_fan_mode fanMode;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::FAN_MODE_OFF ) == 0 )
+ m_status = QSI_SetFanMode( m_handle, QSI_FAN_OFF );
+ else if( value.compare( QSIString::FAN_MODE_QUIET ) == 0 )
+ m_status = QSI_SetFanMode( m_handle, QSI_FAN_QUIET );
+ else
+ m_status = QSI_SetFanMode( m_handle, QSI_FAN_FULL );
+
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetFanMode( m_handle, &fanMode );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( fanMode == QSI_FAN_OFF )
+ pProp->Set( QSIString::FAN_MODE_OFF );
+ else if( fanMode == QSI_FAN_QUIET )
+ pProp->Set( QSIString::FAN_MODE_QUIET );
+ else
+ pProp->Set( QSIString::FAN_MODE_FULL );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::FanModePropertySetup()
+{
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::FanModePropertyHandler );
+ response = CreateProperty( QSIString::FAN_MODE, QSIString::FAN_MODE_QUIET, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::FAN_MODE_OFF );
+ values.push_back( QSIString::FAN_MODE_QUIET );
+ values.push_back( QSIString::FAN_MODE_FULL );
+
+ response = SetAllowedValues( QSIString::FAN_MODE, values );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::FilterWheelPositionPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ long value;
+ int position;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+ position = static_cast( value );
+
+ m_status = QSI_SetFilterWheelPosition( m_handle, position - 1 );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetFilterWheelPosition( m_handle, &position );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ pProp->Set( CDeviceUtils::ConvertToString( position + 1 ) );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::FilterWheelPropertiesSetup()
+{
+ qsi_bool hasFilterWheel;
+ const char * hasFilterWheelString;
+ int filterWheelPositionCount;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetHasFilterWheel( m_handle, &hasFilterWheel );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( hasFilterWheel )
+ hasFilterWheelString = QSIString::HAS_FILTER_WHEEL_YES;
+ else
+ hasFilterWheelString = QSIString::HAS_FILTER_WHEEL_NO;
+
+ response = CreateProperty( QSIString::HAS_FILTER_WHEEL, hasFilterWheelString , MM::String, true );
+ assert( response == DEVICE_OK );
+
+ if( hasFilterWheel )
+ {
+ m_status = QSI_GetFilterWheelPositionCount( m_handle, &filterWheelPositionCount );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = CreateProperty( QSIString::FILTER_WHEEL_POSITIONS, CDeviceUtils::ConvertToString( filterWheelPositionCount ), MM::Integer, true );
+ assert( response == DEVICE_OK );
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::FilterWheelPositionPropertyHandler );
+ response = CreateProperty( QSIString::FILTER_WHEEL_POSITION, CDeviceUtils::ConvertToString( 1 ), MM::Integer, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ for( int i = 0; i < filterWheelPositionCount; i++ )
+ values.push_back( CDeviceUtils::ConvertToString( i + 1 ) );
+
+ response = SetAllowedValues( QSIString::FILTER_WHEEL_POSITION, values );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::FullWellCapacityPropertySetup()
+{
+ double value;
+ int response;
+
+ m_status = QSI_GetFullWellCapacity( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = CreateProperty( QSIString::FULL_WELL_CAPACITY, CDeviceUtils::ConvertToString( value ), MM::Float, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::GainPropertiesSetup()
+{
+ qsi_bool canSetGain;
+ double gain;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetCanSetGainMode( m_handle, &canSetGain );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetElectronsPerADU( m_handle, &gain );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( canSetGain )
+ {
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::GainModePropertyHandler );
+ response = CreateProperty( QSIString::GAIN_MODE, QSIString::GAIN_MODE_HIGH, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::GAIN_MODE_HIGH );
+ values.push_back( QSIString::GAIN_MODE_LOW );
+
+ response = SetAllowedValues( QSIString::GAIN_MODE, values );
+ assert( response == DEVICE_OK );
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::GainPropertyHandler );
+ response = CreateProperty( MM::g_Keyword_Gain, CDeviceUtils::ConvertToString( gain ), MM::Float, true, propertyAction );
+ assert( response == DEVICE_OK );
+ }
+ else
+ {
+ response = CreateProperty( MM::g_Keyword_Gain, CDeviceUtils::ConvertToString( gain ), MM::Float, true );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::GainPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ double value;
+
+ if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetElectronsPerADU( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ pProp->Set( value );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::GainModePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_gain_mode gain;
+ int response;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::GAIN_MODE_HIGH ) == 0 )
+ m_status = QSI_SetGainMode( m_handle, QSI_GAIN_MODE_HIGH );
+ else
+ m_status = QSI_SetGainMode( m_handle, QSI_GAIN_MODE_LOW );
+
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = UpdateProperty( MM::g_Keyword_Gain );
+ HANDLE_MM_ERROR( this, response, "An error occurred while updating the Gain property." );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetGainMode( m_handle, &gain );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( gain == QSI_GAIN_MODE_HIGH )
+ pProp->Set( QSIString::GAIN_MODE_HIGH );
+ else
+ pProp->Set( QSIString::GAIN_MODE_LOW );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::LEDEnabledPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_bool enabled;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::LED_SETTING_ENABLED ) == 0 )
+ enabled = 1;
+ else
+ enabled = 0;
+
+ m_status = QSI_SetLEDEnabled( m_handle, enabled );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetLEDEnabled( m_handle, &enabled );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( enabled )
+ pProp->Set( QSIString::LED_SETTING_ENABLED );
+ else
+ pProp->Set( QSIString::LED_SETTING_DISABLED );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::LEDEnabledPropertySetup()
+{
+ qsi_bool canSetLEDEnabled;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetCanSetLEDEnabled( m_handle, &canSetLEDEnabled );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( canSetLEDEnabled )
+ {
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::LEDEnabledPropertyHandler );
+ response = CreateProperty( QSIString::LED_SETTING, QSIString::LED_SETTING_ENABLED, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::LED_SETTING_ENABLED );
+ values.push_back( QSIString::LED_SETTING_DISABLED );
+
+ response = SetAllowedValues( QSIString::LED_SETTING, values );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::MaxADUPropertySetup()
+{
+ int value;
+ int response;
+
+ m_status = QSI_GetMaxADU( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = CreateProperty( QSIString::MAX_ADU, CDeviceUtils::ConvertToString( value ), MM::Float, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ModelNamePropertySetup()
+{
+ char value[QSI_LENGTH_MODEL_NAME];
+ int response;
+
+ m_status = QSI_GetModelName( m_handle, value, QSI_LENGTH_MODEL_NAME );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ response = CreateProperty( QSIString::MODEL_NAME, value, MM::String, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ModelNumberPropertySetup()
+{
+ char value[QSI_LENGTH_MODEL_NUMBER];
+ int response;
+
+ m_status = QSI_GetModelNumber( m_handle, value, QSI_LENGTH_MODEL_NUMBER );
+ HANDLE_QSI_ERROR( this, m_status );;
+
+ response = CreateProperty( QSIString::MODEL_NUMBER, value, MM::String, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::OpenShutterPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::OPEN_SHUTTER_YES ) == 0 )
+ m_exposureOpenShutter = true;
+ else
+ m_exposureOpenShutter = false;
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ if( m_exposureOpenShutter )
+ pProp->Set( QSIString::OPEN_SHUTTER_YES );
+ else
+ pProp->Set( QSIString::OPEN_SHUTTER_NO );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::OpenShutterPropertySetup()
+{
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::OpenShutterPropertyHandler );
+ response = CreateProperty( QSIString::OPEN_SHUTTER, QSIString::OPEN_SHUTTER_YES, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::OPEN_SHUTTER_NO );
+ values.push_back( QSIString::OPEN_SHUTTER_YES );
+
+ response = SetAllowedValues( QSIString::OPEN_SHUTTER, values );
+ assert( response == DEVICE_OK );
+
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::PCBTemperaturePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ double value;
+
+ if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetPCBTemperature( m_handle, &value );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ pProp->Set( CDeviceUtils::ConvertToString( value ) );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::PCBTemperaturePropertySetup()
+{
+ qsi_bool canGetPCBTemperature;
+ CPropertyAction * propertyAction;
+ int response;
+
+ m_status = QSI_GetCanGetPCBTemperature( m_handle, &canGetPCBTemperature );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( canGetPCBTemperature )
+ {
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::PCBTemperaturePropertyHandler );
+ response = CreateProperty( QSIString::PCB_TEMPERATURE, CDeviceUtils::ConvertToString( 0 ), MM::Float, true, propertyAction );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::PixelSizePropertiesSetup()
+{
+ int response;
+
+ m_status = QSI_GetPixelSizeX( m_handle, &m_pixelSizeX );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ m_status = QSI_GetPixelSizeY( m_handle, &m_pixelSizeY );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = CreateProperty( QSIString::PIXEL_SIZE_X, CDeviceUtils::ConvertToString( m_pixelSizeX ), MM::Float, true );
+ assert( response == DEVICE_OK );
+
+ response = CreateProperty( QSIString::PIXEL_SIZE_Y, CDeviceUtils::ConvertToString( m_pixelSizeY ), MM::Float, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::PreExposureFlushPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_pre_exposure_flush preExposureFlush;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::PRE_EXPOSURE_FLUSH_NONE ) == 0 )
+ preExposureFlush = QSI_FLUSH_NONE;
+ else if( value.compare( QSIString::PRE_EXPOSURE_FLUSH_MODEST ) == 0 )
+ preExposureFlush = QSI_FLUSH_MODEST;
+ else if( value.compare( QSIString::PRE_EXPOSURE_FLUSH_AGGRESSIVE ) == 0 )
+ preExposureFlush = QSI_FLUSH_AGGRESSIVE;
+ else if( value.compare( QSIString::PRE_EXPOSURE_FLUSH_VERY_AGGRESSIVE ) == 0 )
+ preExposureFlush = QSI_FLUSH_VERY_AGGRESSIVE;
+ else
+ preExposureFlush = QSI_FLUSH_NORMAL;
+
+ m_status = QSI_SetPreExposureFlush( m_handle, preExposureFlush );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetPreExposureFlush( m_handle, &preExposureFlush );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( preExposureFlush == QSI_FLUSH_NONE )
+ pProp->Set( QSIString::PRE_EXPOSURE_FLUSH_NONE );
+ else if( preExposureFlush == QSI_FLUSH_MODEST )
+ pProp->Set( QSIString::PRE_EXPOSURE_FLUSH_MODEST );
+ else if( preExposureFlush == QSI_FLUSH_AGGRESSIVE )
+ pProp->Set( QSIString::PRE_EXPOSURE_FLUSH_AGGRESSIVE );
+ else if( preExposureFlush == QSI_FLUSH_VERY_AGGRESSIVE )
+ pProp->Set( QSIString::PRE_EXPOSURE_FLUSH_VERY_AGGRESSIVE );
+ else
+ pProp->Set( QSIString::PRE_EXPOSURE_FLUSH_NORMAL );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::PreExposureFlushPropertySetup()
+{
+ qsi_bool canSetPreExposureFlush;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetCanSetPreExposureFlush( m_handle, &canSetPreExposureFlush );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( canSetPreExposureFlush )
+ {
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::PreExposureFlushPropertyHandler );
+ response = CreateProperty( QSIString::PRE_EXPOSURE_FLUSH, QSIString::PRE_EXPOSURE_FLUSH_NORMAL, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::PRE_EXPOSURE_FLUSH_NONE );
+ values.push_back( QSIString::PRE_EXPOSURE_FLUSH_MODEST );
+ values.push_back( QSIString::PRE_EXPOSURE_FLUSH_NORMAL );
+ values.push_back( QSIString::PRE_EXPOSURE_FLUSH_AGGRESSIVE );
+ values.push_back( QSIString::PRE_EXPOSURE_FLUSH_VERY_AGGRESSIVE );
+
+ response = SetAllowedValues( QSIString::PRE_EXPOSURE_FLUSH, values );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ReadoutModePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_readout_speed readoutSpeed;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::READOUT_MODE_FAST_READOUT ) == 0 )
+ m_status = QSI_SetReadoutSpeed( m_handle, QSI_READOUT_FAST );
+ else
+ m_status = QSI_SetReadoutSpeed( m_handle, QSI_READOUT_HIGH_QUALITY );
+
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetReadoutSpeed( m_handle, &readoutSpeed );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( readoutSpeed == QSI_READOUT_FAST )
+ pProp->Set( QSIString::READOUT_MODE_FAST_READOUT );
+ else
+ pProp->Set( QSIString::READOUT_MODE_HIGH_QUALITY );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ReadoutModePropertySetup()
+{
+ qsi_bool canSetReadoutSpeed;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetCanSetReadoutSpeed( m_handle, &canSetReadoutSpeed );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::ReadoutModePropertyHandler );
+ response = CreateProperty( MM::g_Keyword_ReadoutMode, QSIString::READOUT_MODE_HIGH_QUALITY, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::READOUT_MODE_HIGH_QUALITY );
+
+ if( canSetReadoutSpeed )
+ values.push_back( QSIString::READOUT_MODE_FAST_READOUT );
+
+ response = SetAllowedValues( MM::g_Keyword_ReadoutMode, values );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ShutterPropertiesSetup()
+{
+ qsi_bool hasShutter, canSetShutterPriority;
+ const char * hasShutterString;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetHasShutter( m_handle, &hasShutter );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( hasShutter )
+ hasShutterString = QSIString::HAS_SHUTTER_YES;
+ else
+ hasShutterString = QSIString::HAS_SHUTTER_NO;
+
+ response = CreateProperty( QSIString::HAS_SHUTTER, hasShutterString, MM::String, true );
+ assert( response == DEVICE_OK );
+
+ m_status = QSI_GetCanSetShutterPriority( m_handle, &canSetShutterPriority );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( hasShutter && canSetShutterPriority )
+ {
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::ShutterPriorityPropertyHandler );
+ response = CreateProperty( QSIString::SHUTTER_PRIORITY, QSIString::SHUTTER_PRIORITY_ELECTRONIC, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::SHUTTER_PRIORITY_ELECTRONIC );
+ values.push_back( QSIString::SHUTTER_PRIORITY_MECHANICAL );
+
+ response = SetAllowedValues( QSIString::SHUTTER_PRIORITY, values );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::ShutterPriorityPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_shutter_priority shutterPriority;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::SHUTTER_PRIORITY_ELECTRONIC ) == 0 )
+ shutterPriority = QSI_SHUTTER_PRIORITY_ELECTRONIC;
+ else
+ shutterPriority = QSI_SHUTTER_PRIORITY_MECHANICAL;
+
+ m_status = QSI_SetShutterPriority( m_handle, shutterPriority );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetShutterPriority( m_handle, &shutterPriority );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( shutterPriority == QSI_SHUTTER_PRIORITY_ELECTRONIC )
+ pProp->Set( QSIString::SHUTTER_PRIORITY_ELECTRONIC );
+ else
+ pProp->Set( QSIString::SHUTTER_PRIORITY_MECHANICAL );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::SerialNumberPropertySetup()
+{
+ char serialNumber[QSI_LENGTH_SERIAL_NUMBER];
+ int response;
+
+ m_status = QSI_GetSerialNumber( m_handle, serialNumber, QSI_LENGTH_SERIAL_NUMBER );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ response = CreateProperty( QSIString::SERIAL_NUMBER, serialNumber, MM::String, true );
+ assert( response == DEVICE_OK );
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::SoundEnabledPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct )
+{
+ string value;
+ qsi_bool enabled;
+
+ if( eAct == MM::AfterSet )
+ {
+ pProp->Get( value );
+
+ if( value.compare( QSIString::SOUND_SETTING_ENABLED ) == 0 )
+ enabled = 1;
+ else
+ enabled = 0;
+
+ m_status = QSI_SetSoundEnabled( m_handle, enabled );
+ HANDLE_QSI_ERROR( this, m_status );
+ }
+ else if( eAct == MM::BeforeGet )
+ {
+ m_status = QSI_GetSoundEnabled( m_handle, &enabled );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( enabled )
+ pProp->Set( QSIString::SOUND_SETTING_ENABLED );
+ else
+ pProp->Set( QSIString::SOUND_SETTING_DISABLED );
+ }
+
+ return DEVICE_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+int QSICameraAdapter::SoundEnabledPropertySetup()
+{
+ qsi_bool canSetSoundEnabled;
+ CPropertyAction * propertyAction;
+ int response;
+ vector values;
+
+ m_status = QSI_GetCanSetSoundEnabled( m_handle, &canSetSoundEnabled );
+ HANDLE_QSI_ERROR( this, m_status );
+
+ if( canSetSoundEnabled )
+ {
+ propertyAction = new CPropertyAction( this, &QSICameraAdapter::SoundEnabledPropertyHandler );
+ response = CreateProperty( QSIString::SOUND_SETTING, QSIString::SOUND_SETTING_ENABLED, MM::String, false, propertyAction );
+ assert( response == DEVICE_OK );
+
+ values.push_back( QSIString::SOUND_SETTING_ENABLED );
+ values.push_back( QSIString::SOUND_SETTING_DISABLED );
+
+ response = SetAllowedValues( QSIString::SOUND_SETTING, values );
+ assert( response == DEVICE_OK );
+ }
+
+ return DEVICE_OK;
+}
+
+#pragma endregion
diff --git a/DeviceAdapters/QSI/QSICameraAdapter.h b/DeviceAdapters/QSI/QSICameraAdapter.h
new file mode 100644
index 000000000..435d9bd25
--- /dev/null
+++ b/DeviceAdapters/QSI/QSICameraAdapter.h
@@ -0,0 +1,147 @@
+///////////////////////////////////////////////////////////////////////////////
+// FILE: QSICameraAdapter.h
+// PROJECT: Micro-Manager
+// SUBSYSTEM: DeviceAdapters
+//-----------------------------------------------------------------------------
+// DESCRIPTION: QSI camera adapter for use with Micro-Manager
+//
+// COPYRIGHT: Quantum Scientific Imaging, Inc. 2024
+//
+
+#ifndef _QSICAMERAADAPTER_H_
+#define _QSICAMERAADAPTER_H_
+
+#include "DeviceBase.h"
+#include "ImgBuffer.h"
+#include "ModuleInterface.h"
+
+#include "QSICameraCLib.h"
+#include "QSIError.h"
+
+class QSICameraAdapter : public CCameraBase
+{
+private:
+
+ typedef CCameraBase base;
+
+public:
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Constructor / Destructor
+ //
+ QSICameraAdapter();
+ ~QSICameraAdapter();
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MMDevice API
+ //
+ int Initialize();
+ int Shutdown();
+ void GetName( char * name ) const;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Camera API
+ //
+ int ClearROI();
+ unsigned int GetBitDepth() const;
+ const unsigned char * GetImageBuffer();
+ long GetImageBufferSize() const;
+ int GetBinning() const;
+ double GetExposure() const;
+ unsigned int GetImageBytesPerPixel() const;
+ unsigned int GetImageHeight() const;
+ unsigned int GetImageWidth() const;
+ double GetPixelSizeUm() const;
+ int GetROI( unsigned int & x, unsigned int & y, unsigned int & xSize, unsigned int & ySize );
+ int InsertImage();
+ int IsExposureSequenceable( bool & seq ) const;
+ int SetBinning( int binSize );
+ void SetExposure( double exp );
+ int SetROI( unsigned int x, unsigned int y, unsigned int xSize, unsigned int ySize );
+ int SnapImage();
+ int StartSequenceAcquisition( double interval );
+ int ThreadRun();
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Property setup and handling
+ //
+ int AntiBloomingPropertySetup();
+ int AntiBloomingPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int BinningPropertiesSetup();
+ int BinningPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int BodyTemperaturePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int BodyTemperaturePropertySetup();
+ int CCDTemperaturePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int CCDTemperaturePropertySetup();
+ int CCDTemperatureSetpointPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int CCDTemperatureSetpointPropertySetup();
+ int DescriptionPropertySetup();
+ int DriverInfoPropertySetup();
+ int CoolerStatePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int CoolerStatePropertySetup();
+ int CoolerPowerPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int CoolerPowerPropertySetup();
+ int ExposurePropertiesSetup();
+ int ExposurePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int FanModePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int FanModePropertySetup();
+ int FilterWheelPositionPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int FilterWheelPropertiesSetup();
+ int FullWellCapacityPropertySetup();
+ int GainPropertiesSetup();
+ int GainPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int GainModePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int LEDEnabledPropertySetup();
+ int LEDEnabledPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int MaxADUPropertySetup();
+ int ModelNamePropertySetup();
+ int ModelNumberPropertySetup();
+ int OpenShutterPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int OpenShutterPropertySetup();
+ int PCBTemperaturePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int PCBTemperaturePropertySetup();
+ int PixelSizePropertiesSetup();
+ int PreExposureFlushPropertySetup();
+ int PreExposureFlushPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int ReadoutModePropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int ReadoutModePropertySetup();
+ int SerialNumberPropertySetup();
+ int ShutterPropertiesSetup();
+ int ShutterPriorityPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+ int SoundEnabledPropertySetup();
+ int SoundEnabledPropertyHandler( MM::PropertyBase * pProp, MM::ActionType eAct );
+
+private:
+
+#pragma region [ Private Members ]
+
+ static const int QSI_IMAGE_BYTES_PER_PIXEL = 2;
+ static const int QSI_IMAGE_BIT_DEPTH = QSI_IMAGE_BYTES_PER_PIXEL * 8;
+
+ bool m_initialized;
+
+ qsi_handle m_handle;
+ qsi_status m_status;
+
+ bool m_exposureOpenShutter;
+ double m_exposureDuration;
+ double m_exposureDurationMax;
+ double m_exposureDurationMin;
+
+ int m_imageBinning;
+ int m_imageMaxX;
+ int m_imageMaxY;
+ int m_imageNumX;
+ int m_imageNumY;
+ int m_imageStartX;
+ int m_imageStartY;
+ unsigned short * m_pImageBuffer;
+
+ double m_pixelSizeX;
+ double m_pixelSizeY;
+
+#pragma endregion
+
+};
+
+#endif //_QSICAMERAADAPTER_H_
diff --git a/DeviceAdapters/QSI/QSIImage.h b/DeviceAdapters/QSI/QSIImage.h
new file mode 100644
index 000000000..c969b4461
--- /dev/null
+++ b/DeviceAdapters/QSI/QSIImage.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include
+#include
+
+class QSIImage
+{
+public:
+
+ QSIImage( unsigned int maxX, unsigned int maxY ) :
+ m_buffer( 0 ),
+ m_maxX( 0 ),
+ m_maxY( 0 ),
+ m_maxSize( 0 )
+ {
+ m_maxX = maxX;
+ m_maxY = maxY;
+ m_maxSize = maxX * maxY;
+
+ m_buffer = (unsigned short *) malloc( m_maxSize * 2 );
+ memset( m_buffer, 0, m_maxSize * 2 );
+ }
+
+ ~QSIImage( void )
+ {
+ free( m_buffer );
+ }
+
+ unsigned short * GetBuffer()
+ {
+ return m_buffer;
+ }
+
+
+
+private:
+
+ unsigned short * m_buffer;
+ unsigned int m_maxX;
+ unsigned int m_maxY;
+ unsigned int m_maxSize;
+
+};
+
diff --git a/DeviceAdapters/QSI/QSIToolkit.h b/DeviceAdapters/QSI/QSIToolkit.h
new file mode 100644
index 000000000..e23a918bd
--- /dev/null
+++ b/DeviceAdapters/QSI/QSIToolkit.h
@@ -0,0 +1,61 @@
+#pragma once
+#ifndef _QSITOOLKIT_H_
+#define _QSITOOLKIT_H_
+
+#include
+
+#include "QSICameraAdapter.h"
+#include "QSICameraCLib.h"
+
+#pragma region [ Macros ]
+
+///////////////////////////////////////////////////////////////////////////////
+//
+#define HANDLE_QSI_ERROR(cameraAdapterReference,errorCode) \
+ do \
+ { \
+ if( (errorCode) ) \
+ { \
+ (cameraAdapterReference)->LogMessage( GetLastQSIError( m_handle ), false ); \
+ return (errorCode); \
+ } \
+ } \
+ while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+//
+#define HANDLE_MM_ERROR(cameraAdapterReference,errorCode,errorMessage) \
+ do \
+ { \
+ if( (errorCode) ) \
+ { \
+ (cameraAdapterReference)->LogMessage( (errorMessage), false ); \
+ return (errorCode); \
+ } \
+ } \
+ while( false )
+
+#pragma endregion
+
+#pragma region [ Global Methods ]
+
+///////////////////////////////////////////////////////////////////////////////
+//
+std::string GetLastQSIError( qsi_handle handle )
+{
+ char errorStringArray[QSI_LENGTH_ERROR_STRING];
+ qsi_status response;
+
+ memset( errorStringArray, 0, QSI_LENGTH_ERROR_STRING ); // Not really necessary but it never hurts
+
+ response = QSI_GetLastError( handle, errorStringArray, QSI_LENGTH_ERROR_STRING );
+
+ if( response == QSI_ERROR_INVALID_HANDLE )
+ return std::string( "Unable to get last error due to bad handle" );
+
+ return std::string( errorStringArray, QSI_LENGTH_ERROR_STRING );
+}
+
+#pragma endregion
+
+#endif //_QSITOOLKIT_H_
\ No newline at end of file
diff --git a/DeviceAdapters/QSI/license.txt b/DeviceAdapters/QSI/license.txt
new file mode 100644
index 000000000..4571b1712
--- /dev/null
+++ b/DeviceAdapters/QSI/license.txt
@@ -0,0 +1,28 @@
+BSD 3-Clause License
+
+Copyright (c) 2024, QSI
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/micromanager.sln b/micromanager.sln
index a803822d7..60a6adb1f 100644
--- a/micromanager.sln
+++ b/micromanager.sln
@@ -479,6 +479,7 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WOSM", "DeviceAdapters\WOSM\WOSM.vcxproj", "{64E94A9E-B3AE-47EF-8F5A-0356B0E6B9DA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IDSPeak", "DeviceAdapters\IDSPeak\IDSPeak.vcxproj", "{823CF77E-8120-41B1-9B25-823A79C93198}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QSI", "DeviceAdapters\QSI\QSI.vcxproj", "{320AF64E-C4FC-4A97-A7D1-F8233A8A44C7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1442,6 +1443,10 @@ Global
{823CF77E-8120-41B1-9B25-823A79C93198}.Debug|x64.Build.0 = Debug|x64
{823CF77E-8120-41B1-9B25-823A79C93198}.Release|x64.ActiveCfg = Release|x64
{823CF77E-8120-41B1-9B25-823A79C93198}.Release|x64.Build.0 = Release|x64
+ {320AF64E-C4FC-4A97-A7D1-F8233A8A44C7}.Debug|x64.ActiveCfg = Debug|x64
+ {320AF64E-C4FC-4A97-A7D1-F8233A8A44C7}.Debug|x64.Build.0 = Debug|x64
+ {320AF64E-C4FC-4A97-A7D1-F8233A8A44C7}.Release|x64.ActiveCfg = Release|x64
+ {320AF64E-C4FC-4A97-A7D1-F8233A8A44C7}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE