Enumerated attribute

Intended audience: developers, Programming language: c++

Since Tango release 9, enumerated attribute is supported using the new data type DevEnum. This data type is not a real C++ enumeration because:

  1. The enumerated value allways start with 0
  2. Values are consecutive
  3. It is transferred on the network as DevShort data type

One enumeration label is associated to each enumeration value. For the Tango kernel, it is this list of enumeration labels which will define the possible enumeration values. For instance if the enumeration has 3 labels, its value must be between 0 and 2. There are two ways to define the enumeration labels:

  1. At attribute creation time. This is the most common case when the list of possible enumeration values and labels are known at compile time. The Tango code generator Pogo generates for you the code needed to pass the enumeration labels to the Tango kernel.
  2. In the user code when the enumeration values and labels are not known at compile time but retrieved during device startup phase. The user gives the possible enumeration values to the Tango kernel using the Attribute class set_properties() method.

A Tango client is able to retrieve the enumeration labels in the attribute configuration returned by instance by a call to the DeviceProxy::get_attribute_config() method. Using the DeviceProxy::set_attribute_config() call, a user may change the enumeration labels but not their number.

Usage in a Tango class

Within a Tango class, you set the attribute value with a C++ enum or a DevShort variable. In case a DevShort variable is used, its value will be checked according to the enumeration labels list given to Tango kernel.

Setting the labels with enumeration compile time knowledge

In such a case, the enumeration labels are given to Tango at the attribute creation time in the attribute_factory method of the XXXClass class. Let us take one example

 1   enum class Card: short
 2   {
 3       NORTH = 0,
 4       SOUTH,
 5       EAST,
 6       WEST
 7   };
 8 
 9   void XXXClass::attribute_factory(vector<Tango::Attr *> &att_list)
10   {
11       .....
12       TheEnumAttrib   *theenum = new TheEnumAttrib();
13       Tango::UserDefaultAttrProp theenum_prop;
14       vector<string> labels = {"North","South","East","West"};
15       theenum_prop.set_enum_labels(labels);
16       theenum->set_default_properties(theenum_prop);
17       att_list.push_back(theenum);
18       .....
19    }

line 1-7 : The definition of the enumeration (C++11 in this example)

line 14 : A vector of strings with the enumeration labels is created. Because there is no way to get the labels from the enumeration definition, they are re-defined here.

line 15 : This vector is given to the theenum_prop object which contains the user default properties

line 16 : The user default properties are associated to the attribute
In most cases, all this code will be automatically generated by the Tango code generator Pogo. It is given here for completness.

Setting the labels without enumeration compile time knowledge

In such a case, the enumeration labels are retrieved by the user in a way specific to the device and passed to Tango using the Attribute class set_properties() method. Let us take one example

 1   void MyDev::init_device()
 2   {
 3       ...
 4 
 5       Attribute &att = get_device_attr()->get_attr_by_name("TheEnumAtt");
 6       MultiAttrProp<DevEnum> multi_prop;
 7       att.get_properties(multi_prop);
 8 
 9       multi_prop.enum_labels = {....};
10       att.set_properties(multi_prop);
11       ....
12    }

line 5 : Get a reference to the attribute object

line 7 : Retrieve the attribute properties

line 9 : Initialise the attribute labels in the set of attribute properties

line 10 : Set the attribute properties

Setting the attribute value

It is possible to set the attribute value using either a classical DevShort variable or using a variable of the C++ enumeration. The following example is when you have compile time knowledge of the enumeration definition. We assume that the enumeration is the same than the one defined above (Card enumeration)

1   enum Card points;
2 
3   void MyDev::read_TheEnum(Attribute &att)
4   {
5       ...
6       points = SOUTH;
7       att.set_value(&points);
8   }

line 1 : One instance of the Card enum is created (named points)

line 6 : The enumeration is initialized

line 7 : The value of the attribute object is set using the enumeration (by pointer)
To get the same result using a classical DevShort variable, the code looks like
1   DevShort sh;
2 
3   void MyDev::read_TheEnum(Attribute &att)
4   {
5       ...
6       sh = 1;
7       att.set_value(&sh);
8   }

line 1 : A DevShort variable is created (named sh)

line 6 : The variable is initialized

line 7 : The value of the attribute object is set using the DevShort variable (by pointer)

Usage in a Tango client

Within a Tango client, you insert/extract enumerated attribute value in/from DeviceAttribute object with a C++ enum or a DevShort variable. The later case is for generic client which do not have compile time knowledge of the enumeration. The code looks like

1   DeviceAttribute da = the_dev.read_attribute("TheEnumAtt");
2   Card ca;
3   da >> ca;
4 
5   DeviceAttribute db = the_dev.read_attribute("TheEnumAtt");
6   DevShort sh;
7   da >> sh;

line 2-3 : The attribute value is extracted in a C++ enumeration variable

line 6-7 : The attribute value is extracted in a DevShort variable