Resource Framework
dabs.resources.Resource is the base class of everything dabs knows about. A resource
has a unique name, a lifecycle, an error state, and a record of who is using it. The class
hierarchy underneath it is small:
Class |
Represents |
|---|---|
|
Anything nameable and shareable. |
|
A piece of hardware. Every driver in |
|
A data acquisition board. Owns its IO channels. |
|
A single channel on a DAQ - AO, AI, DO, DI, PFI, CLK. |
|
Communication endpoints. |
|
A ScanImage component. Components are resources so that they can find each other and be enumerated the same way devices are. |
|
Groups the resources belonging to one microscope. |
|
Placeholder returned when a name does not resolve, so that configuration code can report a missing device instead of crashing. |
Identity and state
Property |
Description |
|---|---|
|
Immutable char array, unique within the resource store. Assigned in the constructor. |
|
Non-empty when the resource is unusable. A resource in an error state refuses to be reserved. |
|
Non-empty when the resource is usable but something is off. |
|
The store the resource registered itself with. |
Both message properties are SetObservable and AbortSet, so a widget or script can
listen for hardware going into and out of an error state:
hMotor = dabs.resources.ResourceStore.filterByNameStatic('Stage');
hL = most.ErrorHandler.addCatchingListener(hMotor,'errorMsg','PostSet', ...
@(varargin)fprintf('%s: %s\n',hMotor.name,hMotor.errorMsg));
assertNoError() throws if errorMsg is set - use it at the top of a script that
depends on the device.
Lifecycle
Method |
Description |
|---|---|
|
Reserve the resources this one needs and initialize the hardware. |
|
Release resources and deinitialize the hardware. |
|
Remove the resource from the store. |
Important
reinit and deinit must not throw. A driver that hits a problem
during initialization sets errorMsg instead. This is what lets ScanImage start on a
partially working system and tell you which device failed, rather than aborting startup.
Users and reservations
Resources are shared, and dabs tracks that sharing explicitly in two layers.
Users are the long-lived relationships: a scanner declaring that it uses a particular analog output. Registration carries a human-readable description that shows up in the configuration editor when two devices claim the same channel.
Method |
Description |
|---|---|
|
Declare that |
|
Withdraw the declaration. |
|
Whether a given object is registered. |
|
The description that was registered. |
|
Whether two users that do not allow sharing have both claimed this resource, and who they are. |
|
Read-only summary of the registered users. |
Reservations are the short-lived exclusive claims taken while a resource is actually being driven.
Method |
Description |
|---|---|
|
Take the reservation. Throws when the resource is in an error state, when |
|
Release it. |
|
Release someone else’s reservation. A recovery path, not a normal one. |
|
Read-only summary of the current reservation. |
[tf,conflicts] = hAO.hasUserConflict();
if tf
cellfun(@(h)fprintf('conflicting user: %s\n',h.name),conflicts);
end
Warning
forceUnreserve takes a resource away from whatever is currently driving it.
Use it only to recover from a driver that failed to release its reservation.
Configuration
Most drivers additionally mix in:
Mixin |
Purpose |
|---|---|
|
Persist settings to a heading in the machine data file. |
|
Provide a page in the resource configuration editor. Requires a |
|
Provide a widget for the widget bar. Requires a |
Resources are instantiated from the machine data file:
hResources = dabs.resources.Resource.instantiateFromMdf(mdfPath);
and the mapping from an MDF heading to a class and instance name is available as
[classname,name,isResource,isConstructable] = ...
dabs.resources.Resource.mdfHeadingToClassAndName(heading);
Getting a handle in the base workspace
assigninBase() drops the resource into the base workspace as hResource, which is handy
while exploring from the command window:
hRS = dabs.resources.ResourceStore();
hRS.filterByName('vDAQ0').assigninBase();