(how-to-enumerated-attribute)=
# How to use an enumerated attribute

```{tags} audience:developers, lang:c++
```

{term}`Enumerated attribute`s are supported using the 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 a 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 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 the 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 that instance by a call to the
`DeviceProxy::get_attribute_config()` method. A user may also change the
enumeration labels using the `DeviceProxy::set_attribute_config()` call
but not cannot change 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 the case that a DevShort variable is used, its value will
be checked according to the enumeration labels list passed to the Tango
kernel.

### Setting the labels with enumeration compile time knowledge

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

```{code} cpp
:number-lines: 1

  enum class Card: short
  {
      NORTH = 0,
      SOUTH,
      EAST,
      WEST
  };

  struct TheEnumAttrib : Tango::Attr
  {
      ...

      // Required for enum attributes
      virtual bool same_type(const type_info& in_type) override { return typeid(Card) == in_type; }
      virtual std::string get_enum_type() override { return "Card"; }
  }

  void XXXClass::attribute_factory(vector<Tango::Attr *> &att_list)
  {
      .....
      TheEnumAttrib   *theenum = new TheEnumAttrib();
      Tango::UserDefaultAttrProp theenum_prop;
      vector<string> labels = {"North","South","East","West"};
      theenum_prop.set_enum_labels(labels);
      theenum->set_default_properties(theenum_prop);
      att_list.push_back(theenum);
      .....
   }
```

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

line 9-16 : The definition of the enumerated attribute

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

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

line 26 : The user default properties are associated to the attribute

In most cases this code will be automatically generated by the
Tango code generator Pogo. It is given here for completeness.

### Setting the labels without enumeration compile time knowledge

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

```{code} cpp
:number-lines: 1

  void MyDev::init_device()
  {
      ...

      Attribute &att = get_device_attr()->get_attr_by_name("TheEnumAtt");
      MultiAttrProp<DevEnum> multi_prop;
      att.get_properties(multi_prop);

      multi_prop.enum_labels = {....};
      att.set_properties(multi_prop);
      ....
   }
```

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 as
the one defined above (i.e. the Card enumeration)

```{code} cpp
:number-lines: 1

  enum Card points;

  void MyDev::read_TheEnum(Attribute &att)
  {
      ...
      points = SOUTH;
      att.set_value(&points);
  }
```

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 (using a pointer)

To get the same result using a classical DevShort variable, the code
would look like

```{code} cpp
:number-lines: 1

  DevShort sh;

  void MyDev::read_TheEnum(Attribute &att)
  {
      ...
      sh = 1;
      att.set_value(&sh);
  }
```

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 (using a pointer)

## Usage in a Tango client

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

```{code} cpp
:number-lines: 1

  DeviceAttribute da = the_dev.read_attribute("TheEnumAtt");
  Card ca;
  da >> ca;

  DeviceAttribute db = the_dev.read_attribute("TheEnumAtt");
  DevShort sh;
  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
