Building Micro-Manager Device Adapters



Building Micro-Manager Device Adapters

Nenad Amodaj, nenad@

Oleksiy Danikhno, Oleksiy.Danikhno@ucsf.edu

Nico Sturman, nico@cmp.ucsf.edu

Karl Hoover, karl.hoover@ucsf.edu

Created on: August 17, 2006

Updated on: November 7, 2006 for API version 14

Updated on: January 17, 2007 for API version 14

Updated on: October 1, 2007 for API version 20

Updated on: May 08, 2008 for API version 25

Updated on: May 30, 2008 for API version 26

Updated on: December 22, 2008 for API version 30

Updated on: December 22, 2008 for API version 30

Updated on: January 28, 2009 for API version 31

January 7, 2010 – API version 33

Tested with For Micro-Manager Version 1.3.4318

Introduction 2

Plugin interface 2

Utility classes and files 2

DemoCamera 3

Sensicam 3

Nikon 3

DemoStreamingCamera 4

DemoRGBCamera 4

Project settings for MSDEV 4

Testing and debugging device adapters 4

C++ environment 4

Scripting environment 5

Changes from the previous releases 5

API version 33 (1.3.43 release) 5

API version 31 (1.3.17 release) 6

API version 26 to 30 (1.3.15 release) 6

API version 24 to 26 (1.2.15 release) 7

API version 20 to 24 (1.2 release) 7

New methods for the base MMDevice class 7

New device types 8

API version 14 to 20 (1.1 release) 8

New device type 8

Continuous (burst) acquisition mode 8

MMTime utility class 8

API version 12 to 14 8

DLL naming convention 8

Additional methods required in all adapter modules 9

Introduction

To create a device adapter you don't need access to the entire Micro-Manager source code. All files required to build new device adapters for Micro-Manager on the Windows platform are included in the MMDeviceKit-win installer. For devices with special drivers and hardware boards, e.g. cameras, you will need to also install manufacturer's SDK and all required low-level drivers and libraries.

Once you build a device adapter DLL you can just copy it in the Micro-Manager root application directory and load it either from the script (program) or from the configuration file (see Configuration Guide).

Plugin interface

A device adapter is a software plugin for a specific device, e.g. stage, camera, shutter, etc. Each device adapter must implement one of the abstract interfaces defined in the MMDevice.h. Device library (DLL file) can contain one or more device adapters. The library DLL must also implement plugin management functions defined in the ModuleInterface.h. In theory, these two files plus MMDeviceConstants.h (for error codes and other constants) are all you need to create device adapters: if you implement the required API with the correct behavior, the Micro-Manager application will be able to make use of it.

MMDevice.h, ModuleInterface.h and MMDeviceConstants.h essentially define the plugin interface and are also used by the MMCore module. Do not modify these files – any discrepancy between your version and the one used to build the main application will likely result in the system crash or severe malfunction.

Utility classes and files

To make building device adapters easier, we provide a couple of additional files to use as building blocks. First, DeviceBase.h contains base class partial API implementations for all device classes. The idea is to derive your particular device adapter class from the appropriate class defined in the DeviceBase.h. This header file contains method implementations as well, so there is no corresponding cpp file.

Since DeviceBase.h and other utility files are not used by the main application, you can modify them if you wish. However, the best strategy is to avoid changing any of the supplied utility files since they implement some of the essential device behavior that the main application is relying on. Also, you should avoid overriding methods in the supplied base classes, even if they are declared as virtual – the class is not really designed for that purpose. The idea is to derive your class from one of the base classes and implement only abstract methods.

The BaseSequenceThread class defined in DeviceBase.h as an inner class of the CCameraBase template implements a thread for sequence acquisition session. Examples of using this BaseThread can be found in the implementations of DemoCamera, DemoStreamingCamera, DemoRGBCamera, QICamera and PVCAM adapters. You can either use this BaseSequenceThread class or provide your own when implementing continuous (sequence acquisition in your camera adapter).

Property.h and Property.cpp provide the implementation of the Micro-Manager "Property" mechanism, but again, only on the device side – they are not used in the rest of the application. Property class is used by the DeviceBase classes and most of the time you won't have to deal with it directly.

DeviceUtils.h and DeviceUtils.cpp contain a couple of relatively simple helper functions you may or may not want to use.

ImgBuffer.h and ImgBuffer.cpp provide a simple implementation of the generic image buffer, which you may or may not find useful for building camera adapters. By all means disregard this class if you have a better one or your device does not need to deal with images.

DemoCamera

DemoCamera project included in the installer is a simple example on how to create a working device adapter. You can use it as a starting point for building your own device adapter. DemoCamera DLL contains a simple camera simulator and a number of demo devices: objective turret, filter changer, stage, etc. Most of these devices don't really perform any actions, they just respond to commands and their main purpose is to enable testing of the main application without connecting to the hardware.

DemoCamera.cpp includes relatively extensive comments to help you understand how the API methods should work.

Sensicam

Sensicam project is also included in the installer as an example of the 'real' camera driver. However, in order to build it you need to obtain Sensicam SDK (header files and libraries) from the camera manufacturer. This driver is relatively limited in functionality; code has very few comments, and should be used only as an example, mainly of how the external camera libraries are used to build the device adapter for Micro-Manager.

Nikon

Nikon project is an example of the device adapter using serial interface. Micro-Manager adapters should not use serial ports directly, but rather by using system calls provided by the Micro-Manager device API.

DemoStreamingCamera

The DemoStreamingCamera provides an example of how to implement continuous (sequence) acquisition, and uses the circular buffer implemented in CMMCore. Also, it provides an example of how a RGB color camera can be implemented as a multiple-channel camera.

DemoRGBCamera

DemoRGBCamera provides examples of implementing continuous sequence acquisition mode and using the circular buffer implemented in CMMCore for both monochrome and color images.

Project settings for MSDEV

All Micro-Manager C++ code is built with MSDEV 8.0 (Visual Studio 20085). Some preliminary testing has been done with Visual Studio 2010 also.You should use the same project settings as in the DemoCamera.vcproj or Sensicam.vcproj, unless you have some really strong reason to do otherwise.

All the project are configured to support asynchronous exceptions (/EHa)

Testing and debugging device adapters

1 C++ environment

Using the included project Test_MMCore_devkit, you can test and debug your device adapter completely within your C++ build environment, without the need to use Java API or even having any reference to the existing Micro-Manager installation. Test_MMCore_devkit is also an example how you can build C++ applications with MMCore automated microscope API.

Test_MMCore_devkit.cpp is a command line program which takes a configuration file and performs a simple exercise of the API functionality. It links to two pre-built libraries (included in the installation) mmcorer.lib (MMCore API module as static library) and ace.lib (ACE dynamic library).

2 Scripting environment

To test devices from Micro-Manager scripting environment you can use the "Scrip Panel" (Tools menu). The scripting environment has a built-in reference to the main API module as "mmc" and reference to the UI "gui". Here is an example of a simple test script:

mmc.unloadAllDevices();

mmc.loadDevice("Camera", "DemoCamera", "DCam");

mmc.initializeDevice("Camera");

mmc.setExposure(50);

mmc.snapImage();

if (core.getBytesPerPixel() == 1) {

// 8-bit grayscale pixels

byte[] img = (byte[])mmc.getImage();

gui.message("Image snapped, " + img.length + " pixels total, 8 bits each.");

guimessage("Pixel [0,0] value = " + img[0]);

} else if (mmc.getBytesPerPixel() == 2){

// 16-bit grayscale pixels

short[] img = (short[])mmc.getImage();

gui.message("Image snapped, " + img.length + " pixels total, 16 bits each.");

gui.message("Pixel [0,0] value = " + img[0]);

} else {

gui.message("Dont' know how to handle images with " + mmc.getBytesPerPixel() +

" byte pixels.");

}

If you plan to actively use scripting you may want to look at the "Micro-Manager Programming Manual":



as well as at the Scripting Wiki:



The guide was written for standalone Java programming, but the BeanShell syntax is the same and in principle the examples are more or less applicable to the scripting environment. The main thing to keep in mind is that in Micro-Manager scripting console there is no need to instantiate the "core" module. The reference to the core API is already available as "mmc" object.

Changes from the previous releases

1 API version 33 (1.3.43 release)

New Device categories:

ProgrammableIO()

SLM() ( Projector, Spatial Light Modulator, or Anti-Camera)

CommandDispatch()

MMDevice.h changes terminology, Channels (in the context of color cameras) become Components, hence:

GetNumberOfChannels -> GetNumberOfComponents.

GetChannelName → GetComponentName

New method signature for devices: PrepareSequenceAcqusition()

Autofocus devices add methods:

GetOffset(double &offset)

SetOffset(double offset)

Core (in MMDevice.h) new method signatures:

OnCoordinateUpdate(const Device* caller)

GetChannelConfigs(std::vector& groups)

CMMCore (in MMCore.h) new signatures:

void setAutoFocusOffset(double offset) throw (CMMError);

double getAutoFocusOffset() throw (CMMError);

std::string getSLMDevice();

std::string getChannelGroup();

void setSLMDevice(const char* slmLabel) throw (CMMError);

void setChannelGroup(const char* channelGroup) throw (CMMError);

CMMCore support for pixel size calibration and configuration group management.

2 API version 31 (1.3.17 release)

BaseSequenceThread. Implemented basic sequence acquisition functionality in svc() method like calculating number of frames, capturing with the specified interval and etc.

CCameraBase.

Implemented virtual function IsCapturing returning true if the acquisition thread is run. If you do not use the BaseSequence thread to implement Sequence acquisition, then you will need to provide your own implementation of this function.

Added virtual ThreadRun() method. This method is called from inside the acquisition thread and implements receiving image data from the camera.

Added virtual OnThreadExiting() method called from inside the acquisition thread and implements actions necessary to finalize the sequence capturing.

CMMCore. Added isSequenceRunning() method which should be used instead of “Busy()” method of the camera to determine if the camera adapter is executing a sequence of image capturing. Note: normally, camera adapters should not return Busy status while the sequence acquisition thread is running.

Circuilar buffer now supports 32 bits images.

3 API version 26 to 30 (1.3.15 release)

XYStageDevices. Default implementations for the functions SetRelativePositionUm(double, double), SetPositionUm(double, double), and GetPositionUm(double) are now provided in DeviceBase.h. You are encouraged not to override these functions but rather implement the Get and SetPostionSteps. This allows Micro-Manager to provide a general mechanism to let the use mirror the axis and change axis orientation so that a generalized coordinate system can be used. Although these implementations are not yet provided for single axis stages we anticipate this to happen soon and encourage you to use the 'PositionSteps' functions as the main entry point in communicating with the actual device

CameraDevice – Added Properties 'TransposeMirrorX', 'TransposeMirrorY', 'TransposeXY', 'TranposeCorrection', that can be used to inform Micro-Manager of the camera orientation. See for information on how coordinates and directionality are handled in Micro-Manager

CameraDevice – Changes in Sequence mode: There is now a default implementation for SequenceAcquisition. You should override this with a better implementation if you can. Two more overloaded forms of StartSequenceAcquistion have been added with default implementations that should b e implemented where possible (one form does not request a number of images, another adds the parameter bool stopOnOverflow).

SignalIODevice – Added the functions SetGateOpen and GetGateOpen that are used to configure IO devices as shutters.

4 API version 24 to 26 (1.2.15 release)

1. CameraDevice - Made the functions 'int GetBinning()' and 'int SetBinning(int binSize)' mandatory. GetBinning is used in the Core to adjust pixelSize based on binning. The function 'GetNominalPixelSize' was removed.

2. StageDevice - Added the function 'int SetRelativePositionUm(double d)'. A default implementation is provided, however, you are encouraged to override this function (which will be madated some time in the future).

3. XYStageDevice - Added function 'int SetRelativePositionUm (double dx, double dy)'. A default implementation is provided, however, you are encouraged to override this function (which will be madated some time in the future).

4. MagnifierDevice - This is a new device that should be used by devices that effect the magnification in a predictable way. A single method needs to be implemented for such a device: 'double GetMagnification()'

5 API version 20 to 24 (1.2 release)

1 New methods for the base MMDevice class

HasProperty() – for finding out if device supports a property before using it. This will avoid generating and handling exceptions if the desired property does not exist. Default implementation is in the DeviceBase.h, automatic and requires no overriding.

GetPropertyType() – returns property type. Default implementation is in the DeviceBase.h, automatic and requires no overriding.

UsesDelay() – Default implementation returns “false”, i.e. declaring that the device does not use “Delay” setting. If the particular adapter does use delay settings, it must override this method by returning “true”. Very few devices use this feature.

HasPropertyLimits(), GetPropertyLowerLimit(), GetPropertyUpperLimit() – This set of methods allows the device to specify value limits for “continuous” settings. The default implementation of these methods is automatic, but the limits (if any) must be specified in the code when particular property is declared using SetPropertyLimits(). For an example see DemoStreamingCamera.cpp.

2 New device types

ImageStreamer, ImageProcessor and SignalIO device types were added. Instances of these devices are still under development and the API is likely to change. We do not recommend writing adapters for these device types just as yet.

6 API version 14 to 20 (1.1 release)

1 New device type

Processor virtual device is added to the MMDevice API to enable real-time processing and closed loop control.

2 Continuous (burst) acquisition mode

Camera API was extended to optionally support continuous acquisition mode. This mode allows cameras to run at full speed, under their own timing. Additional extensions were also made in the CoreCallback API to provide access to the circular buffer service.

3 MMTime utility class

A new utility class MMTime was added to simplify cross-platform high-resolution timer functionality, for time-out loops, time stamps, etc.

7 API version 12 to 14

This section is very important if you already have custom adapters for the previous API revision. Your existing adapters won't work with the newer Micro-Manager releases if you don't make changes listed below.

1 DLL naming convention

All adapter DLL file names now have prefix "mmgr_dal_", e.g. mmgr_dal_hamamatsu.dll. However, there are no changes required for the configuration files. The prefix is internally appended by the MMCore when looking for the device adapter and it does not appear in any external naming convention.

Example project files in this package are all updated with the new convention. The linker will add prefix to the output file name. You need to modify your existing projects to conform to the new file naming convention.

2 Additional methods required in all adapter modules

All adapter modules (DLL libraries) now support additional methods (see ModuleInterface.h):

extern "C" {

MODULE_API MM::Device* CreateDevice(const char* name);

MODULE_API void DeleteDevice(MM::Device* pDevice);

MODULE_API long GetModuleVersion();

MODULE_API long GetDeviceInterfaceVersion();

MODULE_API unsigned GetNumberOfDevices();

MODULE_API bool GetDeviceName(unsigned deviceIndex, char* name, unsigned bufferLength);

MODULE_API bool GetDeviceDescription(unsigned deviceIndex, char* name, unsigned bufferLength);

MODULE_API void InitializeModuleData();

}

The only thing you need to add to your existing modules is the implementation of the method "InitializeModuleData()" (see example projects). This method will be called each time MMCore loads the adapter library. In this method we create a list of adapters available in the DLL library. For example, DemoCamera library (DemoCamera.cpp) has the following InitializeModuleData() method implementation:

MODULE_API void InitializeModuleData()

{

AddAvailableDeviceName(g_CameraDeviceName, "Demo camera");

AddAvailableDeviceName(g_WheelDeviceName, "Demo filter wheel");

AddAvailableDeviceName(g_ObjectiveDeviceName, "Demo objective turret");

AddAvailableDeviceName(g_StageDeviceName, "Demo stage");

AddAvailableDeviceName(g_LightPathDeviceName, "Demo light path");

}

The first parameter in "AddAvailableDeviceName", is the adapter name and the second one is a short description.

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download