OpenScanDeviceLib
OpenScan Device Programming Interface
Data Fields
OScDev_DeviceImpl Struct Reference

Data Fields

OScDev_Error(* Arm )(OScDev_Device *device, OScDev_Acquisition *acq)
 Prepare the clock, scanner, and/or detector for an acquisition. More...
 
OScDev_Error(* Close )(OScDev_Device *device)
 
OScDev_Error(* EnumerateInstances )(OScDev_PtrArray **devices)
 Create instances for each physically available device. More...
 
OScDev_Error(* GetActualPixelRate )(OScDev_Device *device, double nominalRateHz, double *actualRateHz)
 Return the actual pixel rate with best known accuracy. More...
 
OScDev_Error(* GetBytesPerSample )(OScDev_Device *device, uint32_t *bytesPerSample)
 Return the bytes per sample given current settings. More...
 
OScDev_Error(* GetModelName )(const char **name)
 
OScDev_Error(* GetName )(OScDev_Device *device, char *name)
 
OScDev_Error(* GetNumberOfChannels )(OScDev_Device *device, uint32_t *nChannels)
 Return the number of channels given current settings. More...
 
OScDev_Error(* GetPixelRates )(OScDev_Device *device, OScDev_NumRange **pixelRatesHz)
 Return the allowed pixel rates. More...
 
OScDev_Error(* GetRasterHeights )(OScDev_Device *device, OScDev_NumRange **heights)
 Return the allowed heights of the raster ROI. More...
 
OScDev_Error(* GetRasterWidths )(OScDev_Device *device, OScDev_NumRange **widths)
 Return the allowed widths of the raster ROI. More...
 
OScDev_Error(* GetResolutions )(OScDev_Device *device, OScDev_NumRange **resolutions)
 Return the allowed scanner resolutions. More...
 
OScDev_Error(* GetZoomFactors )(OScDev_Device *device, OScDev_NumRange **zooms)
 Return the allowed zoom factors. More...
 
OScDev_Error(* HasClock )(OScDev_Device *device, bool *hasClock)
 
OScDev_Error(* HasDetector )(OScDev_Device *device, bool *hasDetector)
 Return true if this device can perform detection.
 
OScDev_Error(* HasScanner )(OScDev_Device *device, bool *hasScanner)
 Return true if this device can perform scanning.
 
OScDev_Error(* IsROIScanSupported )(OScDev_Device *device, bool *supported)
 Return whether the scanner can perform subregion scans. More...
 
OScDev_Error(* IsRunning )(OScDev_Device *device, bool *isRunning)
 Return true if this device is armed or running an acquisition. More...
 
OScDev_Error(* MakeSettings )(OScDev_Device *device, OScDev_PtrArray **settings)
 Create the settings for a device.
 
OScDev_Error(* Open )(OScDev_Device *device)
 Establish a connection to the device. More...
 
OScDev_Error(* ReleaseInstance )(OScDev_Device *device)
 Free the private data for a device. More...
 
OScDev_Error(* Start )(OScDev_Device *device)
 Start the clock from software. More...
 
OScDev_Error(* Stop )(OScDev_Device *device)
 Stop the current acquisition and disarm. More...
 
OScDev_Error(* Wait )(OScDev_Device *device)
 Wait for any current acquisition to finish. More...
 

Detailed Description

Definition at line 507 of file OpenScanDeviceLib.h.

Field Documentation

◆ EnumerateInstances

OScDev_Error(* EnumerateInstances) (OScDev_PtrArray **devices)

Create instances for each physically available device.

Implement this function if it is possible to automatically detect the available devices on the computer. It is also acceptable to implement this function when the device driver supports a small and fixed number of devices that can be easily listed.

Required

Todo:
Provide an alternative mechanism to instantiate devices that cannot be enumerated. Rather than imitating Micro-Manager's leaky "pre-init property" mechanism, we should use dedicated "device loader" objects, which can have settings such as port numbers.

devices must be an array of OScDev_Device objects. OpenScanLib takes ownership of the array (unless the array is statically defined) as well as the device instances. Therefore, the device instances must be created newly every time this function is called, and ReleaseInstance must be correctly implemented.

It is OpenScanLib's responsibility to ensure that no more than 1 instance of the same device (as identified by GetName) is ever opened at the same time.

Definition at line 534 of file OpenScanDeviceLib.h.

◆ ReleaseInstance

OScDev_Error(* ReleaseInstance) (OScDev_Device *device)

Free the private data for a device.

If this device implementation passes non-NULL data to OScDev_Device_Create(), it must also implement this function to free the private data and any resources referenced from it.

OpenScanLib ensures that the device is closed (if it was ever opened) before this function is called.

Conditionally required

Definition at line 547 of file OpenScanDeviceLib.h.

◆ Open

OScDev_Error(* Open) (OScDev_Device *device)

Establish a connection to the device.

Importantly, a device instance must not connect to the physical device until this function is called. This is because multiple instances may be created (but not opened) for the same device.

Definition at line 557 of file OpenScanDeviceLib.h.

◆ HasClock

OScDev_Error(* HasClock) (OScDev_Device *device, bool *hasClock)

Return true if this device can provide the clock for scanning and detection. The clock can be any reference against which the scanning and detection are synchronized. When the scanner and detector belong to the same device, the clock can be entirely internal. When the scanner and detector belong to separate devices, typically one or the other device also provides the clock, and the other device receives the clock through a hardware connection (most commonly a TTL line clock, but this need not be the case).

Definition at line 572 of file OpenScanDeviceLib.h.

◆ GetPixelRates

OScDev_Error(* GetPixelRates) (OScDev_Device *device, OScDev_NumRange **pixelRatesHz)

Return the allowed pixel rates.

The range returned in pixelRatesHz must be stateless, i.e., must not change over the lifetime of the device.

Pixel rate applies to the clock, scanner, and detector.

Required

Definition at line 593 of file OpenScanDeviceLib.h.

◆ GetActualPixelRate

OScDev_Error(* GetActualPixelRate) (OScDev_Device *device, double nominalRateHz, double *actualRateHz)

Return the actual pixel rate with best known accuracy.

If the device supports a range (rather than discrete values) of pixel rates but is known to modify the requested pixel rate (for example, because the pixel rate is generated by frequency division), this function should be implemented to compute the actual pixel rate at the best available precision.

This information is used to match pixel rates between the scanner and detector devices and/or warn the user of unmatched pixel rates.

Optional; if not implemented, it is assumed that the device can operate at the exact requested pixel rate, up to a reasonable precision, or that matching of pixel rate is not critical because a hardware (internal or external) pixel clock signal (or equivalent) is used.

Todo:
It is not clear if this is the best method of matching pixel rates. At the very least, this does allow OpenScanLib to quantify the error, so that the user might establish a discrete set of usable rates. That's probably better than any sort of poorly thought-through automagical matching.

Definition at line 618 of file OpenScanDeviceLib.h.

◆ GetResolutions

OScDev_Error(* GetResolutions) (OScDev_Device *device, OScDev_NumRange **resolutions)

Return the allowed scanner resolutions.

The range returned in resolutions must be stateless, i.e., must not change over the lifetime of the device.

Resolution only applies to the scanner. (The clock and detector operate based on raster size, not resolution.)

Required if the device has a scanner.

Definition at line 632 of file OpenScanDeviceLib.h.

◆ GetZoomFactors

OScDev_Error(* GetZoomFactors) (OScDev_Device *device, OScDev_NumRange **zooms)

Return the allowed zoom factors.

The range returned in zooms must be stateless, i.e., must not change over the lifetime of the device. The range should include the zoom factor of 1.0.

Zoom factor only applies to the scanner.

Optional; the default implementation will allow only a zoom of 1.0.

Definition at line 645 of file OpenScanDeviceLib.h.

◆ IsROIScanSupported

OScDev_Error(* IsROIScanSupported) (OScDev_Device *device, bool *supported)

Return whether the scanner can perform subregion scans.

The value returned in supported must be stateless, i.e., must not change over the lifetime of the device.

The scanner must always support a full-frame scan (width and height equal to resolution). If, in addition, it supports scanning (nonempty) rectangular subregions, this function should be implemented and return true.

A scanner that supports ROI scans must allow the ROI to start at an arbitrary offset (0 to (resolution - 1) in both X and Y). The size (width and height) of the ROI conforms to ranges returned by GetRasterWidths() and GetRasterHeights(), limited by the resolution.

Optional; the default implementation will return false.

Definition at line 665 of file OpenScanDeviceLib.h.

◆ GetRasterWidths

OScDev_Error(* GetRasterWidths) (OScDev_Device *device, OScDev_NumRange **widths)

Return the allowed widths of the raster ROI.

The range returned in widths must be stateless, i.e., must not change over the lifetime of the device.

Raster size applies to the clock, scanner, and detector.

Optional; the default implementation will allow all positive integer widths. If the device only works with an internal scanner, the range will be limited by the scanner resolution.

Definition at line 678 of file OpenScanDeviceLib.h.

◆ GetRasterHeights

OScDev_Error(* GetRasterHeights) (OScDev_Device *device, OScDev_NumRange **heights)

Return the allowed heights of the raster ROI.

The range returned in heights must be stateless, i.e., must not change over the lifetime of the device.

Raster size applies to the clock, scanner, and detector.

Optional; the default implementation will allow all positive integer widths. If the device only works with an internal scanner, the range will be limited by the scanner resolution.

Definition at line 692 of file OpenScanDeviceLib.h.

◆ GetNumberOfChannels

OScDev_Error(* GetNumberOfChannels) (OScDev_Device *device, uint32_t *nChannels)

Return the number of channels given current settings.

Currently, only simultaneous multi-channel imaging is supported, so this function is only called for the device providing the detector.

Required if this device has a detector.

Definition at line 702 of file OpenScanDeviceLib.h.

◆ GetBytesPerSample

OScDev_Error(* GetBytesPerSample) (OScDev_Device *device, uint32_t *bytesPerSample)

Return the bytes per sample given current settings.

Values other than 2 (16-bit) are not currently supported.

Required if this device has a detector.

Definition at line 711 of file OpenScanDeviceLib.h.

◆ Arm

OScDev_Error(* Arm) (OScDev_Device *device, OScDev_Acquisition *acq)

Prepare the clock, scanner, and/or detector for an acquisition.

An implementation of this function should first query the acquisition object acq to learn whether the device should provide the clock, scanner, and/or detector for the acquisition.

If providing the clock, the clock should be set up to immediately start upon receiving the start trigger. The start trigger may be external (hardware input) or software (a call to the Start function); call OScDev_Acquisition_GetClockStartTriggerSource() to determine which.

If providing the scanner, the scanner should be set up to scan according to clock signals. The clock may be internal (i.e. provided by this same device) or external (hardware input); call OScDev_Acquisition_GetClockSource() to determine which.

If providing the detector, the detector should be set up to acquire according to clock signals. The clock may be internal (i.e. provided by this same device) or external (hardware input); call OScDev_Acquisition_GetClockSource() to determine which.

In some integrated devices, the separation between the clock, scanner, and detector may not be clear. The implementation should behave as if the three components were separate and behaved as specified above.

Todo:
Currently, state change after the device is armed is handled in a variable way depending on what triggers the state change (especially stop of acquisition). We should replace this with a simpler interface where the device calls new functions OScDev_Acquisition_NotifyStart() and OScDev_Acquisition_NotifyStop(). The start notification will be purely informational, used e.g. so that the GUI can show "waiting for start trigger" vs "acquisition running". The stop trigger will indicate that all action has finished and the device is ready to be disarmed. (Disarm() should be a mandatory function distinct from Stop(), which should behave as a software trigger for cancellation.) There should also be a way for a device to declare that it is not capable of issuing a start notification (in which case arrival of data can be used as a proxy for display purposes). Stop(), unlike Disarm(), need not be called when OpenScanLib has already received a stop notification.

Definition at line 754 of file OpenScanDeviceLib.h.

◆ Start

OScDev_Error(* Start) (OScDev_Device *device)

Start the clock from software.

A call to this function is how a software start trigger to the clock is implemented.

Before this function is called, Arm() would have been called with the clock source set to OScDev_ClockSource_Internal and the start trigger source set to OScDev_TriggerSource_Software.

It should be noted that a device that is not providing the clock will not receive a call to this function.

Todo:
Better to rename to SoftwareTriggerStart()?

Definition at line 770 of file OpenScanDeviceLib.h.

◆ Stop

OScDev_Error(* Stop) (OScDev_Device *device)

Stop the current acquisition and disarm.

Unlike Start, this function is called for all devices participating in an acquisition, not just the device providing the clock. In this sense, Stop is the counterpart of Arm, not Start.

If there is no acquisition running and the device is not armed, then this function must succeed with no effect.

Currently, this function must wait for the stopping process to complete and return only when the device is ready to be armed again with a new acquisition.

Todo:

This function should be split into two separate functions, SoftwareTriggerStop() and Disarm(), with very different roles. The former should merely be an asynchronous signal that the device should ignore any subsequent start triggers and stop as soon as possible. Actual completion of stopping should be notified via a callback (see Todo at Arm). The latter (Disarm()) should mainly handle cleanup, and should be guaranteed to be called exactly once per armed acquisition, after all processes have stopped.

SoftwareTriggerStop() can be optional to implement; we should additionally provide bool OScDev_Acquisition_SoftwareStopTriggered() which can be called any time between Arm() and Disarm(); this will supersede the bool return value of OScDev_Acquisition_CallFrameCalback().

Definition at line 799 of file OpenScanDeviceLib.h.

◆ IsRunning

OScDev_Error(* IsRunning) (OScDev_Device *device, bool *isRunning)

Return true if this device is armed or running an acquisition.

Note that the device may exit the "running" state on its own (e.g. after completing a specified number of frames), or as the result of a call to StopAcquisition().

In all cases, this function should not return false until all aspects of the acquisition have completed and the device is ready to arm for a new acquisition.

Todo:
This function should be replaced with a callback-based interface to avoid polling and simplify device module implementation.

Definition at line 814 of file OpenScanDeviceLib.h.

◆ Wait

OScDev_Error(* Wait) (OScDev_Device *device)

Wait for any current acquisition to finish.

As soon as this function returns, IsRunning() must return false until Arm() is called again.

This function should return immediately if IsRunning() is already false.

Todo:
This function should be removed, because it leads to reinvention of condition variable code in each device module. Better to report state changes using a callback interface.

Definition at line 828 of file OpenScanDeviceLib.h.


The documentation for this struct was generated from the following file: