Component Framework

Everything under hSI that manages a piece of the acquisition is a component: an object derived from scanimage.interfaces.Component. The components live in the scanimage.components package. Understanding the base class pays off, because it explains behavior you will run into in every component - why some properties can be changed while focusing and others cannot, why numInstances matters, and where the Tiff header values come from.

classdef Component < scanimage.interfaces.Class & most.Model & dabs.resources.SIComponent
  • most.Model provides the property metadata and header machinery.

  • dabs.resources.SIComponent makes the component a named resource, which is how components find hSI and how the resource store finds components.


The component list

scanimage.SI constructs its components in its constructor and exposes each as an immutable handle property.

Handle

Class

Responsibility

hSI.hCoordinateSystems

CoordinateSystems

Owns the coordinate system tree and its persistence.

hSI.hRoiManager

RoiManager

Imaging ROIs, resolution, zoom, frame rates.

hSI.hScan2D

Scan2D subclass

The active imaging system. hSI.hScanners lists all of them.

hSI.hChannels

Channels

Channel display / save selection, offsets, input ranges, averaging.

hSI.hDisplay

Display

Channel windows, frame averaging for display, last acquired frames.

hSI.hBeams

Beams

Beam powers, depth compensation, blanking, power boxes.

hSI.hPmts

Pmts

PMT gain, bandwidth, power and trip state.

hSI.hShutters

Shutters

Shutter transitions.

hSI.hMotors

Motors

Stage control and the sample coordinate systems.

hSI.hFastZ

FastZ

Fast axial actuator: waveform, lag, flyback.

hSI.hStackManager

StackManager

Stack and volume definition, slice / volume counters.

hSI.hWaveformManager

WaveformManager

Computes, caches and optimizes scanner output waveforms.

hSI.hPhotostim

Photostim

Photostimulation sequences, triggering and monitoring.

hSI.hIntegrationRoiManager

IntegrationRoiManager

Online integration ROIs and their output channels.

hSI.hMotionManager

MotionManager

Motion estimation and correction.

hSI.hTileManager

TileManager

Tiles and tiled acquisition.

hSI.hCycleManager

CycleManager

Multi-iteration cycle acquisitions.

hSI.hCameraManager

CameraManager

Camera wrappers and their alignment to reference space.

hSI.hDataManager

DataManager

Distributes acquired ROI data to consumers.

hSI.hUserFunctions

UserFunctions

Event hooks for user code.

hSI.hConfigurationSaver

ConfigurationSaver

CFG / USR configuration files.

% every component is also a resource, so the resource store can enumerate them
hComponents = hSI.hResourceStore.filterByClass('dabs.resources.SIComponent');

numInstances

numInstances reports how many hardware instances the component is backed by. A component with numInstances <= 0 is inert: start returns immediately, property updates are refused, and functions guarded by componentExecuteFunction do nothing.

This is what makes ScanImage tolerate a partial configuration. If no PMT controller is configured, hSI.hPmts still exists and can be queried, it simply does not act.

if hSI.hPhotostim.numInstances > 0
    hSI.hPhotostim.onDemandStimNow(1);
end

Active state and the acquisition state machine

hSI.acqState is one of 'idle', 'focus', 'grab', 'loop', 'loop_wait' and 'point'. hSI.active is true whenever the state is not idle and initialization has completed.

Each component has its own active flag, set by the framework:

  • hComponent.start(...) asserts the component is not already active, calls the subclass hook componentStart, then sets active. If componentStart throws, ScanImage aborts before the error is rethrown.

  • hComponent.abort(...) clears active and calls componentAbort. Errors raised during abort are logged rather than thrown, so an abort always completes.

A component constructed with independentComponent = true is not tied to hSI’s state and may act while an acquisition is running.


Live update rules

Six constants on every component decide what may change during an acquisition. They are declared Constant, Hidden in each component class.

Constant

Meaning

PROP_TRUE_LIVE_UPDATE

Properties that may be set while the component is active, with no interruption at all.

PROP_FOCUS_TRUE_LIVE_UPDATE

Properties that may be set live, but only while focusing.

DENY_PROP_LIVE_UPDATE

Properties that may not be applied during focus even by the abort-and-restart fallback described below.

FUNC_TRUE_LIVE_EXECUTION

Methods callable while the component is active.

FUNC_FOCUS_TRUE_LIVE_EXECUTION

Methods callable live while focusing.

DENY_FUNC_LIVE_EXECUTION

Methods that may not be run through the abort-and-restart fallback.

Property setters call componentUpdateProperty(propName,val) and only proceed if it returns true; methods guard themselves with componentExecuteFunction(fncName,...).

The fallback behavior is worth knowing about, because it is visible to users: when you set a property that is not in the live-update lists while ScanImage is focusing, ScanImage aborts the focus, applies the change, and restarts focus. During a grab or loop the change is refused with a message on the command window and the old value is kept.

% which properties can be changed live on the ROI manager while focusing?
scanimage.components.RoiManager.PROP_FOCUS_TRUE_LIVE_UPDATE

Note

The constructor checks these lists against the class’s actual properties and methods and warns about stale entries, so a typo shows up at startup rather than silently disabling a live update.


Configuration, machine data and class data

Components mix in one or more of the following, which is where their settings live:

Mixin

Purpose

most.HasMachineDataFile

Hardware configuration, persisted to the machine data file (MDF) under a heading named by mdfHeading. loadMdf / saveMdf move values between the file and the object.

most.HasClassDataFile

Bulk data that does not belong in a text configuration file - calibrations, alignment tables, cached waveforms - persisted to a .mat file.

dabs.resources.configuration.HasConfigPage

Gives the component a page in the resource configuration editor. Call hComponent.showConfig() to open it.

CFG and USR files are handled separately by hSI.hConfigurationSaver, which saves the observable model properties of all components rather than the hardware configuration.


Property metadata and the Tiff header

Components are most.Model objects. Each declares mdlPropAttributes (built by a local ziniInitPropAttributes function at the bottom of the class file) describing type, range and dimensionality for its properties; the setters run these through validatePropArg. mdlHeaderExcludeProps lists properties that should not be written into acquisition metadata.

The header written into Tiff files is produced by hSI.getHeaderString(); ROI definitions are serialized separately by hSI.getRoiDataString(). Extra properties can be added with

hSI.mdlCustomProps = {'hRoiManager.scanZoomFactor'};   % model properties
hSI.extCustomProps = {...};                            % properties outside the model

See also

Output Files for the layout of the resulting file.


Writing code against a component

Components are handle objects with observable properties, so the natural way to react to a change is a listener:

hL = most.ErrorHandler.addCatchingListener(hSI.hStackManager,'slicesDone','PostSet', ...
     @(src,evt)fprintf('slice %d\n',hSI.hStackManager.slicesDone));

most.ErrorHandler.addCatchingListener is used throughout ScanImage in preference to addlistener because it logs and contains errors raised in the callback instead of letting them break the acquisition.

For acquisition lifecycle hooks - start, done, abort, per-frame - use user functions rather than listeners; they are designed for it and are saved with the configuration.