Using Devices ============= The station exposes *devices*, each of which is a remote software object that manages part of the station. Each device has the following properties: - It has a *state*, - Many devices manage and represent hardware in the station, - It exposes *read-only attributes*, that expose values from within the device or from the hardware it represents, - It exposes *read-write attributes*, that allow controlling the functionality of the device, or the hardware it represents, - It exposes *properties*, which are fixed configuration parameters (such as port numbers and timeouts), - It exposes *commands*, that request the execution of a procedure in the device or in the hardware it manages. To access a device, one creates a ``Device`` object. For example:: recv = Device("LTS/RECV/1") See :doc:`../control` on how and where to execute this code. States ------------ The state of a device is then queried with ``device.state()``. Each device can be in one of the following states: - ``DevState.OFF``: The device is not operating, - ``DevState.INIT``: The device is being initialised, - ``DevState.STANDBY``: The device is initialised and ready to be configured further, - ``DevState.ON``: The device is operational. - ``DevState.FAULT``: The device is malfunctioning. Functionality cannot be counted on. - The ``device.state()`` function can throw an error, if the device cannot be reached at all. For example, because it's docker container has not been started. Each device provides the following functions to change state: - ``off()``: Turn the device ``OFF`` from any state. - ``initialise()``: Initialise the device from the ``OFF`` state, to bring it to the ``STANDBY`` state. - ``on()``: Mark the device as operational, from the ``STANDBY`` state, bringing it to ``ON``. Attributes ------------ The device can be operated in ``ON`` state, where it exposes *attributes* and *commands*. The attributes can be accessed as python properties, for example:: recv = Device("LTS/RECV/1") # turn on all LED0s recv.RCU_LED0_RW = [True] * 32 # retrieve the status of all LED0s print(recv.RCU_LED0_R) The attributes with an: - ``_R`` suffix are monitoring points, reflecting the state of the hardware, and are thus read-only. - ``_RW`` suffix are control points, reflecting the desired state of the hardware. They are read-write, where writing requests the hardware to set the specified value. Reading them returns the last requested value. .. _attribute-masks: Attribute masks --------------------- Several devices employ *attribute masks* in order to toggle which elements in their hardware array are actually to be controlled. This construct is necessary as most control points consist of arrays of values that cover all hardware elements. These array control points are always fully sent: it is not possible to update only a single element without uploading the rest. Without a mask, it is impossible to control a subset of the hardware. The masks only affect *writing* to attributes. Reading attributes (monitoring points) always result in data for all elements in the array. For example, the ``RCU_mask_RW`` array is the RCU mask in the ``recv`` device. It behaves as follows, when we interact with the ``RCU_LED0_R(W)`` attributes:: recv = Device("LTS/RECV/1") # set mask to control all RCUs recv.RCU_mask_RW = [True] * 32 # request to turn off LED0 for all RCUs recv.RCU_LED0_RW = [False] * 32 # <--- all LED0s are now off # recv.RCU_LED0_R should show this, # if you have the RCU hardware installed. # set mask to only control RCU 3 mask = [False] * 32 mask[3] = True recv.RCU_mask_RW = mask # request to turn on LED0, for all RCUs # due to the mask, only LED0 on RCU 3 # will be set. recv.RCU_LED0_RW = [True] * 32 # <--- only LED0 on RCU3 is now on # recv.RCU_LED0_R should show this, # if you have the RCU hardware installed.