States¶
Karabo has a fixed set of provided states, all of which are listed in the tables below. States are classified in base states, which can be seen as set of more general states, and device type states, which map closer to the type of hardware being controlled or to certain types of software devices, but also always map to a base state. Each base state has a assigned color coding, making it easy to view are devices state at first glance.
Base and derived states are defined as follows:
UNKNOWN
should be used if the Karabo device has no connection to hardware,
or it cannot be assured that the correct state of the hardware is reported by
the device. The state can also be set if an unknown software error
occurs in the device code.
The INIT
state in which a Karabo device should transition into upon
initialization. During initialization connection to the hardware should
be established.
After initialization the device state should thus be KNOWN
, and the device
should transition either to DISABLED
, ERROR
or one of the states which
are derived from NORMAL
. If no connection can be established the device
should be placed into the UNKNOWN
state.
The KNOWN
base state is the counterpart to the UNKNOWN
state and should
not usually be set to device. Instead, the device logic should decide which
of the states deriving from KNOWN
should be entered after initialization.
All states listed in the following derive from KNOWN
.
DISABLED
is used if the device will not normally act on commands and reconfigurations.
However, a disabled device is connected to the Karabo system,
i.e. (some) value may be read back, at the very least it is able to notify
Karabo of its disabled status.
The ERROR
state is reserved for hardware errors. It must only be used for an
error pertinent to the hardware component.
The NORMAL
base state should not usually be entered programmatically.
Similar to KNOWN
, device logic should rather transition the device
into one of the derived states. The following states derive from and compare
equal to NORMAL
.
STATIC
is itself a base state to the ACTIVE
and PASSIVE
states.
It is the counterpart to the changing states and rarely used.
PAUSED
Data Acquisition will be paused while the device is in this state.
[TODO: add better (or more complete) description for PAUSED
]
The ACTIVE
state is derived from STATIC
and should usually be used
only for comparison purposes. Rather developers should transition into a device
state derived from it. It is the counterpart to PASSIVE
.
The PASSIVE
state is derived from STATIC
and should usually be used
only for comparison purposes. Rather developers should transition into a
device state derived from it. It is the counterpart to ACTIVE
.
The state RUNNING
is a base state is related to data acquisition devices.
This base state has two children, ACQUIRING
and PROCESSING
and is
colored blueish to indicate that data is flowing.
The ACQUIRING
state is essentially used for detector devices when the data
acquisition is active, while the PROCESSING
state is present in downstream
pipeline devices to show they are receiving and processing the detector data.
The state CHANGING
is a base state to the INCREASING
and
DECREASING
states. It may however also directly be used, e.g. if a device
is changing in a way that a directional indication does not make sense. It is
the counterpart to the STATIC
state. CHANGING
and derived states should
be used when a device is transitioning to a new target condition, e.g. a motor
moving to a new position, a power supply ramping to a given voltage or a pump
spinning up to speed. Once the target value is reached the device should
transition into a STATIC
state.
The state INCREASING
is derived from CHANGING
and should be used if
it makes sense to indicate a directional transition of the hardware.
It is the counterpart to DECREASING
.
The state DECREASING
is derived from CHANGING
and should be used
if it makes sense to indicate a directional transition of the hardware.
It is the counterpart to INCREASING
.
Warning
The ERROR
state is reserved for hardware errors. Errors due to
communication problems or software errors should result in a transition
into the UNKNOWN
state. Generally though, software errors should not
occur and if they do the device should recover into an operational
mode. Composite devices should transition to UNKNOWN
if they are not
able to contact a device they are to control, as they might not have
all the information available to work properly.
Warning
Devices requiring to establish connections to hardware first, e.g. through the
network, or some other interface, do this either in the INIT
state.
Connection functionality must be implemented in the initialization hooks
,
not in the constructor or __init__
methods. It might take time,
and would otherwise yield the device unresponsive.
The following diagram shows how base states and derived states are connected,
and which transitions are allowed. Upon initialization, devices generally
transition from UNKNOWN
into one of the states derived from the KNOWN
base state. This is done by passing through the INIT
state, where the
connection to hardware should be established. Note that a connection error
should not put the device into an ERROR
state but rather back into
UNKNOWN
!
As shown in the diagram a transition to any of the states deriving from
the KNOWN
base state back to UNKNOWN
is possible, this should e.g.
occur if the connection to the hardware is lost. Restablishing a KNOWN
state
should happen by passing through the INIT
state``.
The ERROR
and DISABLED
states may be transitioned into from any of the
states deriving from the NORMAL
base state. Conversely, the device may
implement logic to recover from an ERROR
state into any of the NORMAL
-derived states, or from DISABLED
into these.
Most Significant State¶
Especially for middle-layer devices a recurring scenario is the evaluation of
the most significant state, or composite state of a group of states. This is
where state trumping must be used. In Karabo, state trumping is centralized
in the sense that a set of standard trumping rules are provided, giving the
base states a particular order.
In the flat base-state hierarchy the following graph is being followed
in trump evaluation, where DISABLED
is trumped by all other states and
UNKNOWN
will trump all other states.
Warning
The UNKNOWN
state purposely trumps all other states, as the device is
in a condition in which it does not have all the information necessary
to determine the proper state. Thus the conservative assumption is
that the device is in an error state.
Note
When the input list of states contains two or more states that derive from a common state in the trump list and that common parent is the most significant among all the input states, the most significant state will be the one that comes last in the input list.
To exemplify: if COOLING
and RAMPING_DOWN
, which are derived from
DECREASING
, are in the input list along with other states that are
less significant than DECREASING
, the most significant state will be
COOLING
if it comes after RAMPING_DOWN
in the input list. Otherwise,
the most significant will be RAMPING_DOWN
.
It is important to add in here that a state is considered to derive from itself
(like classes are subclasses of themselves in most OOP languages). So, if in the
example above the classes were COOLING
and DECREASING
, the same rule of the
most significant being the one that comes closest to the end of the input
list would apply.
Device developers should however not implement trumping functionality themselves,
but instead use the StateSignifier().returnMostSignificant
function
provided by Karabo.
from karabo.middlelayer import State, StateSignifier
trumpState = StateSignifier()
listOfStates = [State.ERROR, State.MOVING, State.CHANGING]
definingState = trumpState.returnMostSignificant(listOfStates)
print(definingState)
>>> State.ERROR
Calling returnMostSignificant
from the StateSignifier
without
additional keywords will result in returning evaluation substates
of STATIC
and CHANGING
. A priority can be established between
the two direct descendants of STATIC
(ACTIVE
and PASSIVE
) and
between the two direct descendants of CHANGING
(INCREASING
and
DECREASING
). Those priorities can be controlled by the following
two keywords:
- staticSignificant =
ACTIVE|PASSIVE
- defines whether
ACTIVE
orPASSIVE
should evaluate as more significant. - changingSignificant =
INCREASING|DECREASING
- defines whether
INCREASING
orDECREASING
should evaluate as more significant.
In rare scenarios states might need to be trumped differently. Developers can
provide for a different trumping method in initialization of the StateSignifier
.
A list of base states should be provided as the trump list, the order of which
determines trumping and provides the same returnMostSignificant
method as in the
default trumping implementation.
from karabo.middlelayer import State, StateSignifier
trumpList = []
trumpList.append(State.DISABLED)
trumpList.append(State.STATIC)
trumpList.append(State.CHANGING)
trumpList.append(State.INIT)
trumpList.append(State.UNKNOWN)
trumpList.append(State.ERROR)
myStateSignifier = StateSignifier(trumpList)
sState = myStateSignifier.returnMostSignificant([State.DISABLED,
State.INIT])
Derived States¶
For certain device classes conventions on common state names have historically grown. Karabo supports these existing state names, by providing derived states. The diagrams below list these states, in terms of from the base states they derive.
Interlocked Devices¶
A device which may not be altered because it is in an INTERLOCKED
state is
in a state derived from DISABLED
:
Note
Although the INTERLOCKED
state derives from the DISABLED
state, it
is much more significant and is trumped by State.ERROR
, State.INIT
and
State.UNKNOWN
.
Devices with Binary-like behavior¶
Many hardware devices have states which map to a kind of “binary” behavior,
i.e. two states which are the opposite or counterpart of each other, thus
deriving from ACTIVE
and PASSIVE
. In each of this states the device
is rather STATIC
, which is the base state for both:
Devices with Transitionatory Behavior¶
Frequently, a transition from one hardware state to another will not be immediate,
but rather take some time, e.g. if a stage is instructed to driver to a new
location, a power supply is ramping to a new voltage or a chiller is set to
a lower temperature. During a longer lasting transition such devices should be
placed into a CHANGING
derived state, possibly also indicating if an increase
or decrease of the value is being performed.
Note
While comparisons between different derived states are guaranteed to work
it is good practice to compare to the base state. You can also write
if myState.isDerivedFrom(State.CHANGING)
and not
if myState == State.MOVING
.
Changing States¶
The device state should be queried and set using the getState() and updateState() methods in the bound APIs
current_state = self.getState()
...
self.updateState(State.MOVING)
In the middle-layer API normal property retrieval and assignment will automatically map to these calls
current_state = self.state
self.state = State.MOVING
Warning
While internally states are serialized as strings, states can only be updated by assigning a state enumerator object.