Skip to content
Snippets Groups Projects
Commit 4975e485 authored by Taya Snijder's avatar Taya Snijder
Browse files

Merge branch 'L2SS-545_12_jan_2022-attribute_wrapper_documentation' into 'master'

final version of the attr wrapper readme

Closes L2SS-545

See merge request !221
parents 2016b808 8ebc7993
No related branches found
No related tags found
1 merge request!221final version of the attr wrapper readme
this folder contains all the comms_client implementations for organisation
#Attribute wrapper use guide
### How to add a new client
soon™
The attribute wrapper is an abstraction layer around tango attributes. This abstraction layer provides an easier and more consistent way of creating and using attributes and allows for easy reuse of code.
You can find example uses of the attribute wrapper inside the devices folder: https://git.astron.nl/lofar2.0/tango/-/tree/master/tangostationcontrol/tangostationcontrol/devices
Inside lofar/tango/tangostationcontrol/tangostationcontrol/devices/lofar_device.py we import the attribute wrapper. Here we also create a dictionary containing all attribute values in the devices with the setup_value_dict method. This dictionary is set up when the device is initialized. This file, together with the opcua_client.py may be of interest as they are created as generic base classes.
##Functions/methods
`__init__`:
Comms_id: user-supplied identifier that is attached to this object, to identify which communication class will need to be attached
Comms_annotation: : data passed along to the attribute. can be given any form of data. handling is up to client implementation
Datatype: The numpy type of the attribute
Dims: Tuple of the dimensions (x,) or (x,y)
Access: AttrWriteType.READ or AttrWriteType.READWRITE , determines whether this is a read or read/write function.
Init_value: Initialisation value. If none is presents, fills the attribute with zero data of the correct type and dimension
**kwargs: any other non attribute_wrapper arguments.
NOTE: the `__init__` function contains wrappers for the unassigned read/write functions. In previous versions the read function of an RW attribute used to return the last value it had written *to* the client instead of the value from the client. This has since been changed.
`initial_value`:
This function fills the attribute with a default value of all zero's with the proper dimensions and type if None is specified.
`Set_comm_client`:
This function can be called to assign a read and write function to the attribute using the data accessor or client given to this function. The attribute wrapper assumes the client is running and has a function called ‘setup_attribute’ which will provide it with a valid read/write function.
`async_set_comm_client`:
Aynchronous version of the set_comm_client function.
`set_pass_func`:
Can be called to assign a 'fake' read/write function. This is useful as a fallback option while development is still ongoing.
`_decorate_read_function`:
Wrap an attribute read function to annotate its exceptions with our comms_annotation to be able to identify which attribute triggered the error.
`_decorate_write_function`:
Wrap an attribute write function to annotate its exceptions with our comms_annotation to be able to identify which attribute triggered the error.
##Example Device / usage
Here an example of a Tango Device that uses the attribute wrapper is presented.
The device class is a sub-class of opcua_device, which is, in turn, a sub-class of lofar_device class which implements the attribute initialisation methods (attr_list and setup_value_dict ) as stated above.
```python
class RECV(opcua_device):
# ----------
# Attributes
# ----------
# Scalar attribute
RECVTR_translator_busy_R = attribute_wrapper(comms_annotation=["RECVTR_translator_busy_R"],datatype=numpy.bool_ )
# Array attribute
RCU_TEMP_R = attribute_wrapper(comms_annotation=["RCU_TEMP_R"], datatype=numpy.float64, dims=(32,))
# Image (2D array) attribute
HBAT_BF_delays_R = attribute_wrapper(comms_annotation=["HBAT_BF_delays_R" ],datatype=numpy.int64 , dims=(32,96))
```
Once the Tango device is up and running, one can interact with the device attributes just as it would be with the standard Tango attribute classes. For example:
> d = DeviceProxy(‘fqdn_name’)
>
> attr_names = d.get_attribute_list()
>
> d.RCU_TEMP_R # read attribute value
>
> d.HBAT_BF_delays_RW = [....] # write attribute value
##How clients work:
Clients work by providing a communication interface or data accessor for the attribute. The implementation of this is largely up to the user, but must contain a `setup_attribute` function that returns a valid read and write function.
Once a client has been initialized, the attributes can be assigned their read/write functions.
To couple a client to an attribute the set_comm_client or async_set_comm_client of the attribute_wrapper can be called. This function then calls the `setup_attribute` function of the client.
Attributes can be given any custom data in the `Comms_annotation` argument during their creation. This data as well as the attribute_wrapper object itself can be accessed by the `setup_attribute` function in order to correctly configure the read/write functions. The read function should return a numpy array of the correct type and shape, while the write function has to take an input value, which will be of the type and shape of the attribute.
Clients can be set up in the device, during the initialization and then can be assigned to the attributes by looping through the list of attributes and calling the `set_comm_client` function.
`tangostationcontrol/tangostationcontrol/clients/comms_client.py` provides a generic client class for us and may be of interest.
##Dependencies
Attribute wrappers wraps around tango attributes. As such, Tango needs to be installed.
The attribute wrapper relies on 1 internal file. tango/tangostationcontrol/devices/device_decorators.py, which is imported by the attribute_wrapper.py. This file is used for ensuring the read/write functions are only called in the correct device state.
##Closing
The advantages of using attribute_wrapper class instead of the standard Tango Attribute class can be noted in the following example where, in the first part, an implementation of the standard class is presented, while in the second part the analogous implementation using an attribute_wrapper is shown.
##From official Tango documentation #
```python
class PowerSupply(Device):
current = attribute(label="Current", dtype=float,
display_level=DispLevel.EXPERT,
access=AttrWriteType.READ_WRITE,
unit="A", format="8.4f",
min_value=0.0, max_value=8.5,
min_alarm=0.1, max_alarm=8.4,
min_warning=0.5, max_warning=8.0,
fget="get_current", fset="set_current",
doc="the power supply current")
def get_current(self):
return 2.3456, time(), AttrQuality.ATTR_WARNING
def set_current(self, current):
print("Current set to %f" % current)
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment