The most Framework
most is the foundation layer that both scanimage and dabs are built on. It is not
something you would normally program against directly, but its idioms appear in every example
in this section - most.ErrorHandler.addCatchingListener, most.idioms.isValidObj,
mdlPropAttributes, makeEntry - so it is worth knowing what they do and why ScanImage®
prefers them over the plain MATLAB equivalents.
most.Model
most.Model is the model half of ScanImage’s model-view-controller split. Every
component is a most.Model. It provides three things.
Property attributes and validation
A subclass declares an mdlPropAttributes struct whose fields name properties and describe
their constraints:
Field |
Meaning |
|---|---|
|
Valid classes for the property. |
|
Valid attributes, in the sense of |
|
Other properties whose value this one depends on. |
By convention the struct is built by a local ziniInitPropAttributes() function at the
bottom of the class file. Setters run values through obj.validatePropArg(propname,val),
which is why setting a component property to a nonsense value produces a message naming the
property rather than a failure deeper in.
DependsOn is what makes dependent properties observable: ScanImage binds listeners so
that a change to prop1 fires a notification on the dependent property. Dependencies can
reach across objects:
s.DependentProp = struct('DependsOn',{'prop1' 'hSibling.prop2' 'hParent.prop3'});
The order of fields in mdlPropAttributes is honored during initialization and when
applying a property set - a property with no constraints can be listed with an empty struct
purely to pin its position.
Property sets
Property sets are serialized snapshots of object state. They are what CFG and USR files are made of.
Method |
Description |
|---|---|
|
Write a property set to file. |
|
Write only the listed properties. |
|
Load and apply. |
|
Load without applying. |
|
Apply a set, returning the previous values. |
|
Apply a subset. |
hSI.hConfigurationSaver sits on top of these.
Headers
Method |
Description |
|---|---|
|
Readout of all gettable properties as text. |
|
The same as a struct, which is what the JSON header format serializes. |
mdlHeaderExcludeProps on each class lists properties to leave out - device handles,
transient state, anything that would be noise in a file header. See
Acquisition Metadata.
Submodels
A model may own submodels one level deep. Declaring a property’s Classes as
'most.Model' nests that submodel’s mdlPropAttributes into the parent’s during
initialization, so the parent’s property sets and headers cover the child too.
most.HasMachineDataFile
The machine data file (MDF) holds hardware configuration as readable text, grouped into
headings. A class that mixes in most.HasMachineDataFile declares:
properties (Constant, Hidden)
mdfClassName = mfilename('class');
mdfHeading = 'Shutter';
mdfDependsOnClasses;
mdfDirectProp;
mdfPropPrefix;
mdfDefault = defaultMdfSection();
end
and implements loadMdf and saveMdf. Entries are built with a static helper:
most.HasMachineDataFile.makeEntry(name,value,comment,liveUpdate)
The comment becomes the inline comment in the MDF, so it is the user-facing description of the setting - worth writing properly.
Member |
Description |
|---|---|
|
Read one variable into a property, returning success rather than throwing. |
|
Write one property back. |
|
Remove the object’s heading from the file. |
|
Migrate an MDF to the current format. |
See also
Writing a Device Driver for the full pattern in context.
most.HasClassDataFile
Class data files are .mat files holding data that does not belong in a text configuration
file: calibrations, alignment tables, cached waveforms. most.HasMachineDataFile derives
from this class, so a device with an MDF heading also has class data available.
Method |
Description |
|---|---|
|
Create the file with defaults if it does not exist. |
|
Read one variable. |
|
Write one variable. |
|
Back the file up before overwriting. |
Static equivalents - getClassDataVarStatic, setClassDataVarStatic,
ensureClassDataFileStatic, deleteClassDataFile, backupClassDataFileStatic - work
without an instance, and can optionally search superclasses.
hSI.hCoordinateSystems is the most visible user of this mechanism: the whole coordinate system tree is serialized into one class data file.
See also
Reset Class Data Files for recovering from a corrupted file.
most.ErrorHandler
most.ErrorHandler is why ScanImage stays up when one device misbehaves. It logs errors
centrally, keeps a history, and - most importantly for user code - provides listeners that
contain their own exceptions.
Method |
Description |
|---|---|
|
Drop-in replacement for |
|
Log an error and report it to the user. |
|
Log without reporting. |
|
Report or print an error. |
|
Assertion that routes through the handler. |
|
Handler-aware equivalents of the built-ins. |
|
Run a function, containing any error. |
|
The recorded error history. |
|
Log errors to a file - useful when chasing an intermittent fault. |
|
Configure the handler. |
% contained listener - an error in the callback will not break the acquisition
hL = most.ErrorHandler.addCatchingListener(hSI.hStackManager,'slicesDone','PostSet', ...
@(src,evt)myCallback());
% capture a session's errors to a file
most.ErrorHandler.startLogging('C:\logs\si_errors.txt');
Warning
A contained error is still an error. If a callback silently stops doing anything
useful, check most.ErrorHandler.errorHistory() before assuming the event stopped
firing.
most.idioms
A grab-bag of small helpers. The ones that appear constantly in ScanImage source:
Function |
Purpose |
|---|---|
|
True for a handle that is both non-empty and not deleted. Guards two failure modes in
one call, which is why it is used in place of |
|
Delete a handle if it is valid; no-op otherwise. |
|
Warning and error output that matches ScanImage’s console style. |
|
Figure and axes creation with ScanImage’s defaults applied. |
|
Convert a string to an enumeration member - how enum-valued properties accept text. |
|
Inline conditional. |
Other subpackages worth knowing about: most.json (used for the JSON Tiff header),
most.util (Singleton, Uuid, DelayedEventListener, findAllClasses),
most.math, most.fileutil and most.gui.
most.util.DelayedEventListener deserves a mention: it is the debounce used where a
property changes far more often than consumers need to react - hSI.hScan2D’s
scannersetChanged event and hSI.hMotors’s samplePositionChanged event are both
built on it.
% fire at most once every 100 ms, no matter how often the property changes
hL = most.util.DelayedEventListener(0.1,hObj,'someProp','PostSet',@(varargin)myCallback());