packages feed

hs-tango-1.0.0: c_tango/src/c_tango_attribute.cpp

/******************************************************************************
 *
 * File:        c_tango_attribute.c
 * Project:     C/Rust client interface to Tango
 * Description:	Interface functions to access Tango attributes
 * Original:    November 2007
 * Author:      jensmeyer
 *
 * Adapted for tango-rs by Georg Brandl, 2015.
 *
 ******************************************************************************/

#include "c_tango.h"
#include <iostream>

ErrorStack *tango_translate_exception(Tango::DevFailed &tango_exception);
static void convert_attribute_reading(Tango::DeviceAttribute &devattr, AttributeData *argout);
static void convert_attribute_writing(AttributeData *argin, Tango::DeviceAttribute &devattr);
static void convert_attr_query(Tango::AttributeInfoEx &tango_attr_info, AttributeInfo *attr_info);

ErrorStack *
tango_read_attributes(void *proxy, VarStringArray *attr_names, AttributeDataList *argout)
{
  Tango::DeviceProxy *dev = (Tango::DeviceProxy *)proxy;
  std::vector<Tango::DeviceAttribute> *devattr_list = 0;

  // copy the attribute names to a vector of string
  std::vector<std::string> names;
  for (uint32_t i = 0; i < attr_names->length; i++)
  {
    names.push_back(attr_names->sequence[i]);
  }

  try
  {
    devattr_list = dev->read_attributes(names);

    // allocate the AttributeDataList for the number of attributes returned
    INIT_SEQ(*argout, AttributeData, devattr_list->size());

    // loop over all returned attributes and convert the data
    for (uint32_t i = 0; i < devattr_list->size(); i++)
    {
      if ((*devattr_list)[i].has_failed())
        throw Tango::DevFailed((*devattr_list)[i].get_err_stack());
      convert_attribute_reading((*devattr_list)[i], &argout->sequence[i]);
    }

    // the memory is copied, we can now free the returned data
    delete devattr_list;
  }
  catch (Tango::DevFailed &tango_exception)
  {
    if (devattr_list)
      delete devattr_list;
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

ErrorStack *tango_read_attribute(void *proxy, char *attr_name, AttributeData *argout)
{
  Tango::DeviceProxy *dev = (Tango::DeviceProxy *)proxy;
  Tango::DeviceAttribute devattr;

  try
  {
    devattr = dev->read_attribute(attr_name);
    if (devattr.has_failed())
      throw Tango::DevFailed(devattr.get_err_stack());
    convert_attribute_reading(devattr, argout);
  }
  catch (Tango::DevFailed &tango_exception)
  {
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

ErrorStack *tango_write_attributes(void *proxy, AttributeDataList *argin)
{
  Tango::DeviceProxy *dev = (Tango::DeviceProxy *)proxy;
  std::vector<Tango::DeviceAttribute> devattr_list(argin->length);

  try
  {
    for (uint32_t i = 0; i < argin->length; i++)
    {
      convert_attribute_writing(&argin->sequence[i], devattr_list[i]);
    }
    dev->write_attributes(devattr_list);
  }
  catch (Tango::DevFailed &tango_exception)
  {
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

ErrorStack *tango_write_attribute(void *proxy, AttributeData *argin)
{
  Tango::DeviceProxy *dev = (Tango::DeviceProxy *)proxy;
  Tango::DeviceAttribute devattr;

  try
  {
    convert_attribute_writing(argin, devattr);
    dev->write_attribute(devattr);
  }
  catch (Tango::DevFailed &tango_exception)
  {
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

void tango_free_AttributeData(AttributeData *attribute_data)
{
  free(attribute_data->name); // from strdup

#define DELETE_SEQ(member) \
  if (attribute_data->attr_data.member.sequence) \
    delete[] attribute_data->attr_data.member.sequence; \
  break

  switch (attribute_data->data_type)
  {
  case DEV_BOOLEAN:
    DELETE_SEQ(bool_arr);
  case DEV_UCHAR:
    DELETE_SEQ(char_arr);
  case DEV_SHORT:
    DELETE_SEQ(short_arr);
  case DEV_USHORT:
    DELETE_SEQ(ushort_arr);
  case DEV_LONG:
    DELETE_SEQ(long_arr);
  case DEV_ULONG:
    DELETE_SEQ(ulong_arr);
  case DEV_LONG64:
    DELETE_SEQ(long64_arr);
  case DEV_ULONG64:
    DELETE_SEQ(ulong64_arr);
  case DEV_FLOAT:
    DELETE_SEQ(float_arr);
  case DEV_DOUBLE:
    DELETE_SEQ(double_arr);
  case DEV_STATE:
    DELETE_SEQ(state_arr);

  case DEV_STRING:
    for (uint32_t i = 0; i < attribute_data->attr_data.string_arr.length; i++)
    {
      free(attribute_data->attr_data.string_arr.sequence[i]); // from strdup
    }
    DELETE_SEQ(string_arr);

  case DEV_ENCODED:
    for (uint32_t i = 0; i < attribute_data->attr_data.encoded_arr.length; i++)
    {
      free(attribute_data->attr_data.encoded_arr.sequence[i].encoded_format); // from strdup
      delete[] attribute_data->attr_data.encoded_arr.sequence[i].encoded_data;
    }
    DELETE_SEQ(encoded_arr);

  default:
    break;
  }
}

void tango_free_AttributeDataList(AttributeDataList *attribute_data_list)
{
  for (uint32_t i = 0; i < attribute_data_list->length; i++)
  {
    tango_free_AttributeData(&attribute_data_list->sequence[i]);
  }
  delete[] attribute_data_list->sequence;
}

ErrorStack *tango_get_attribute_list(void *proxy, VarStringArray *attr_names)
{
  Tango::DeviceProxy *dev = (Tango::DeviceProxy *)proxy;
  std::vector<std::string> *attr_list = 0;

  try
  {
    attr_list = dev->get_attribute_list();
    int nb_data = attr_list->size();

    // allocate sequence
    INIT_SEQ(*attr_names, char *, nb_data);

    // allocate strings and copy data
    for (int i = 0; i < nb_data; i++)
    {
      attr_names->sequence[i] = strdup((*attr_list)[i].c_str());
    }
    delete attr_list;
  }
  catch (Tango::DevFailed &tango_exception)
  {
    if (attr_list)
      delete attr_list;
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

ErrorStack *tango_get_attribute_config(
    void *proxy, VarStringArray *attr_names, AttributeInfoList *attr_info_list)
{
  Tango::DeviceProxy *dev = (Tango::DeviceProxy *)proxy;
  std::vector<Tango::AttributeInfoEx> *tango_attr_info_list = 0;

  // copy the attribute names to a vector of string
  std::vector<std::string> names;
  for (uint32_t i = 0; i < attr_names->length; i++)
  {
    names.push_back(attr_names->sequence[i]);
  }

  try
  {
    tango_attr_info_list = dev->get_attribute_config_ex(names);

    // allocate the AttributeInfoList for the number of attributes returned
    INIT_SEQ(*attr_info_list, AttributeInfo, tango_attr_info_list->size());

    // loop over all returned attributes and convert the data
    for (uint32_t i = 0; i < tango_attr_info_list->size(); i++)
    {
      convert_attr_query((*tango_attr_info_list)[i], &attr_info_list->sequence[i]);
    }
    delete tango_attr_info_list;
  }
  catch (Tango::DevFailed &tango_exception)
  {
    if (tango_attr_info_list)
      delete tango_attr_info_list;
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

ErrorStack *tango_attribute_list_query(void *proxy, AttributeInfoList *attr_info_list)
{
  Tango::DeviceProxy *dev = (Tango::DeviceProxy *)proxy;
  std::vector<Tango::AttributeInfoEx> *tango_attr_info_list = 0;

  try
  {
    tango_attr_info_list = dev->attribute_list_query_ex();

    // allocate the AttributeInfoList for the number of attributes returned
    INIT_SEQ(*attr_info_list, AttributeInfo, tango_attr_info_list->size());

    // loop over all returned attributes and convert the data
    for (uint32_t i = 0; i < tango_attr_info_list->size(); i++)
    {
      convert_attr_query((*tango_attr_info_list)[i], &attr_info_list->sequence[i]);
    }
    delete tango_attr_info_list;
  }
  catch (Tango::DevFailed &tango_exception)
  {
    if (tango_attr_info_list)
      delete tango_attr_info_list;
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

void tango_free_VarStringArray(VarStringArray *string_arr)
{
  for (uint32_t i = 0; i < string_arr->length; i++)
  {
    free(string_arr->sequence[i]); // from strdup
  }
  delete[] string_arr->sequence;
}

void tango_free_AttributeInfoList(AttributeInfoList *attribute_info_list)
{
  for (uint32_t i = 0; i < attribute_info_list->length; i++)
  {
    free(attribute_info_list->sequence[i].name); // from strdup
    free(attribute_info_list->sequence[i].description);
    free(attribute_info_list->sequence[i].label);
    free(attribute_info_list->sequence[i].unit);
    free(attribute_info_list->sequence[i].standard_unit);
    free(attribute_info_list->sequence[i].display_unit);
    free(attribute_info_list->sequence[i].format);
    free(attribute_info_list->sequence[i].min_value);
    free(attribute_info_list->sequence[i].max_value);
    free(attribute_info_list->sequence[i].min_alarm);
    free(attribute_info_list->sequence[i].max_alarm);
    free(attribute_info_list->sequence[i].writable_attr_name);
    free(attribute_info_list->sequence[i].root_attr_name);
    for (uint16_t j = 0; j < attribute_info_list->sequence[i].enum_labels_count; ++j)
      free(attribute_info_list->sequence[i].enum_labels[j]);
    if (attribute_info_list->sequence[i].enum_labels_count > 0)
      delete[] attribute_info_list->sequence[i].enum_labels;
  }
  delete[] attribute_info_list->sequence;
}

void convert_attribute_reading(Tango::DeviceAttribute &devattr, AttributeData *argout)
{
  // treat INVALID data quality
  if (devattr.get_quality() == Tango::ATTR_INVALID)
  {
    // just initialise the first datatype - this should be valid for
    // all data types in the union!
    argout->attr_data.bool_arr.length = 0;
    argout->attr_data.bool_arr.sequence = NULL;
  }
  else
  {
    int nb_data;

    // get data type
    argout->data_type = (TangoDataType)devattr.get_type();
    argout->data_format = (AttrDataFormat)devattr.data_format;
    argout->nb_read = devattr.get_nb_read();

#define EXTRACT_ARRAY(member, tgtype, type) \
  { \
    Tango::tgtype *seq; \
    devattr >> seq; \
    nb_data = seq->length(); \
    argout->attr_data.member.length = seq->length(); \
    argout->attr_data.member.sequence = seq->get_buffer(true); \
    delete seq; \
    break; \
  }

    switch (argout->data_type)
    {
    case DEV_BOOLEAN:
      EXTRACT_ARRAY(bool_arr, DevVarBooleanArray, bool);
    case DEV_UCHAR:
      EXTRACT_ARRAY(char_arr, DevVarCharArray, uint8_t);
    case DEV_SHORT:
      EXTRACT_ARRAY(short_arr, DevVarShortArray, int16_t);
    case DEV_ENUM:
      EXTRACT_ARRAY(short_arr, DevVarShortArray, int16_t);
    case DEV_USHORT:
      EXTRACT_ARRAY(ushort_arr, DevVarUShortArray, uint16_t);
    case DEV_LONG:
      EXTRACT_ARRAY(long_arr, DevVarLongArray, Tango::DevLong);
    case DEV_ULONG:
      EXTRACT_ARRAY(ulong_arr, DevVarULongArray, Tango::DevULong);
    case DEV_LONG64:
      EXTRACT_ARRAY(long64_arr, DevVarLong64Array, Tango::DevLong64);
    case DEV_ULONG64:
      EXTRACT_ARRAY(ulong64_arr, DevVarULong64Array, Tango::DevULong64);
    case DEV_FLOAT:
      EXTRACT_ARRAY(float_arr, DevVarFloatArray, float);
    case DEV_DOUBLE:
      EXTRACT_ARRAY(double_arr, DevVarDoubleArray, double);

    case DEV_STRING:
    {
      std::vector<std::string> string_vect;
      devattr >> string_vect;
      nb_data = string_vect.size();
      INIT_SEQ(argout->attr_data.string_arr, char *, nb_data);
      for (int i = 0; i < nb_data; i++)
      {
        argout->attr_data.string_arr.sequence[i] = strdup(string_vect[i].c_str());
      }
      break;
    }

    case DEV_STATE:
    {
      std::vector<Tango::DevState> state_vect;

      // the State attribute is not returning a sequence -
      // check whether the attribute name is State!
      if (devattr.name == "State")
      {
        state_vect.resize(1);
        devattr >> state_vect[0];
      }
      else
      {
        devattr >> state_vect;
      }
      nb_data = state_vect.size();
      INIT_SEQ(argout->attr_data.state_arr, TangoDevState, nb_data);
      for (int i = 0; i < nb_data; i++)
      {
        argout->attr_data.state_arr.sequence[i] = (TangoDevState)state_vect[i];
      }
      break;
    }

    case DEV_ENCODED:
    {
      Tango::DevVarEncodedArray *encoded_vect;
      uint32_t nb_data;

      devattr >> encoded_vect;
      nb_data = encoded_vect->length();
      INIT_SEQ(argout->attr_data.encoded_arr, TangoDevEncoded, nb_data);

      // allocate the encoded structues and copy data
      for (uint32_t i = 0; i < nb_data; i++)
      {
        argout->attr_data.encoded_arr.sequence[i].encoded_format =
            strdup((*encoded_vect)[i].encoded_format);
        argout->attr_data.encoded_arr.sequence[i].encoded_length =
            (*encoded_vect)[i].encoded_data.length();
        // get the pointer to the buffer and take over the memory ("true" param)
        argout->attr_data.encoded_arr.sequence[i].encoded_data =
            (uint8_t *)(*encoded_vect)[i].encoded_data.get_buffer(true);
      }
      break;
    }

    default:
      Tango::Except::throw_exception(
          "Data type error",
          "The requested data type is not implemented for attribute reading!",
          "c_tango_attribute.c::convert_attribute_reading()");
      break;
    }
  }

  // get quality factor
  argout->quality = (AttrQuality)devattr.get_quality();

  // copy timestamp
  argout->time_stamp.tv_sec = devattr.time.tv_sec;
  argout->time_stamp.tv_usec = devattr.time.tv_usec;

  // allocate attribute name
  argout->name = strdup(devattr.name.c_str());

  // get data dimension
  argout->dim_x = devattr.dim_x;
  argout->dim_y = devattr.dim_y;
}

void convert_attribute_writing(AttributeData *argin, Tango::DeviceAttribute &devattr)
{
  // allocate a vector and copy the data

#define INSERT_ARRAY(member, type) \
  { \
    std::vector<type> arr(argin->attr_data.member.length); \
    memcpy( \
        arr.data(), \
        argin->attr_data.member.sequence, \
        sizeof(type) * argin->attr_data.member.length); \
    devattr.insert(arr, argin->dim_x, argin->dim_y); \
    break; \
  }

  switch (argin->data_type)
  {
  case DEV_BOOLEAN:
  {
    std::vector<bool> arr(argin->attr_data.bool_arr.length);
    for (uint32_t i = 0; i < argin->attr_data.bool_arr.length; i++)
    {
      arr[i] = argin->attr_data.bool_arr.sequence[i];
    }
    devattr.insert(arr, argin->dim_x, argin->dim_y);
    break;
  }

  case DEV_UCHAR:
    INSERT_ARRAY(char_arr, uint8_t);
  case DEV_SHORT:
    INSERT_ARRAY(short_arr, int16_t);
  case DEV_USHORT:
    INSERT_ARRAY(ushort_arr, uint16_t);
  case DEV_LONG:
    INSERT_ARRAY(long_arr, Tango::DevLong);
  case DEV_ULONG:
    INSERT_ARRAY(ulong_arr, Tango::DevULong);
  case DEV_LONG64:
    INSERT_ARRAY(long64_arr, Tango::DevLong64);
  case DEV_ULONG64:
    INSERT_ARRAY(ulong64_arr, Tango::DevULong64);
  case DEV_FLOAT:
    INSERT_ARRAY(float_arr, float);
  case DEV_DOUBLE:
    INSERT_ARRAY(double_arr, double);

  case DEV_STRING:
  {
    std::vector<std::string> string_arr(argin->attr_data.string_arr.length);
    for (uint32_t i = 0; i < argin->attr_data.string_arr.length; i++)
    {
      string_arr[i] = argin->attr_data.string_arr.sequence[i];
    }
    devattr.insert(string_arr, argin->dim_x, argin->dim_y);
    break;
  }

  case DEV_STATE:
  {
    std::vector<Tango::DevState> state_arr(argin->attr_data.state_arr.length);
    for (uint32_t i = 0; i < argin->attr_data.state_arr.length; i++)
    {
      state_arr[i] = (Tango::DevState)argin->attr_data.state_arr.sequence[i];
    }
    devattr.insert(state_arr, argin->dim_x, argin->dim_y);
    break;
  }

  case DEV_ENCODED:
  {
    // today encoded type is only available as SCALAR data type
    devattr.insert(
        argin->attr_data.encoded_arr.sequence[0].encoded_format,
        argin->attr_data.encoded_arr.sequence[0].encoded_data,
        argin->attr_data.encoded_arr.sequence[0].encoded_length);
    break;
  }

  default:
    Tango::Except::throw_exception(
        "Data type error",
        "The requested data type is not implemented for attribute writing!",
        "c_tango_attribute.c::convert_attribute_writing()");
    break;
  }

  // set attribute name
  devattr.set_name(argin->name);
}

static void convert_attr_query(Tango::AttributeInfoEx &tango_attr_info, AttributeInfo *attr_info)
{
  attr_info->name = strdup(tango_attr_info.name.c_str());
  attr_info->description = strdup(tango_attr_info.description.c_str());
  attr_info->label = strdup(tango_attr_info.label.c_str());
  attr_info->unit = strdup(tango_attr_info.unit.c_str());
  attr_info->standard_unit = strdup(tango_attr_info.standard_unit.c_str());
  attr_info->display_unit = strdup(tango_attr_info.display_unit.c_str());
  attr_info->format = strdup(tango_attr_info.format.c_str());
  attr_info->min_value = strdup(tango_attr_info.min_value.c_str());
  attr_info->max_value = strdup(tango_attr_info.max_value.c_str());
  attr_info->min_alarm = strdup(tango_attr_info.min_alarm.c_str());
  attr_info->max_alarm = strdup(tango_attr_info.max_alarm.c_str());
  attr_info->writable_attr_name = strdup(tango_attr_info.writable_attr_name.c_str());

  attr_info->writable = (AttrWriteType)tango_attr_info.writable;
  attr_info->data_format = (AttrDataFormat)tango_attr_info.data_format;
  attr_info->data_type = (TangoDataType)tango_attr_info.data_type;
  attr_info->max_dim_x = tango_attr_info.max_dim_x;
  attr_info->max_dim_y = tango_attr_info.max_dim_y;
  attr_info->disp_level = (DispLevel)tango_attr_info.disp_level;
  std::size_t const enum_label_count = tango_attr_info.enum_labels.size();
  if (enum_label_count > 0)
  {
    char **enum_labels = new char *[enum_label_count];
    for (std::size_t i = 0; i < enum_label_count; ++i)
      enum_labels[i] = strdup(tango_attr_info.enum_labels[i].c_str());
    attr_info->enum_labels = enum_labels;
  }
  else
  {
    attr_info->enum_labels = nullptr;
  }
  attr_info->enum_labels_count = static_cast<uint16_t>(enum_label_count);

  attr_info->root_attr_name = strdup(tango_attr_info.root_attr_name.c_str());
  attr_info->memorized = (TangoAttrMemorizedType)tango_attr_info.memorized;
}

ErrorStack *tango_poll_attribute(void *db_proxy, char const *cmd_name, int polling_period)
{
  try
  {
    static_cast<Tango::DeviceProxy *>(db_proxy)->poll_attribute(cmd_name, polling_period);
  }
  catch (Tango::DevFailed &tango_exception)
  {
    return tango_translate_exception(tango_exception);
  }
  return 0;
}

ErrorStack *tango_stop_poll_attribute(void *db_proxy, char const *cmd_name)
{
  try
  {
    static_cast<Tango::DeviceProxy *>(db_proxy)->stop_poll_attribute(cmd_name);
  }
  catch (Tango::DevFailed &tango_exception)
  {
    return tango_translate_exception(tango_exception);
  }
  return 0;
}