NDAttribute源码解析及测试代码

NDAttribute源码解析:

#include 
#include 
#include 

#include "NDAttribute.h"

/** 对应以上枚举的字符串 */
static const char *NDAttrSourceStrings[] = {
    "DRIVER",
    "PARAM",
    "EPICS_PV",
    "FUNCTION"
};

const char *NDAttribute::attrSourceString(NDAttrSource_t type)
{
  return NDAttrSourceStrings[type];
}

/** NDAttribute构造器
  * [in] pName:         要被创建的属性的名称.
  * [in] sourceType:    要被创建的来源类型(NDAttrSource_t).
  * [in] pSource:       表示对应这个属性的来源字符串.
  * [in] pDescription:  这个属性的描述.
  * [in] dataType:      这个属性的数据类型 (NDAttrDataType_t).
  * [in] pValue:        这个属性值的指针.
  */
  NDAttribute::NDAttribute(const char *pName, const char *pDescription,
                           NDAttrSource_t sourceType, const char *pSource,
                           NDAttrDataType_t dataType, void *pValue)

  : dataType_(NDAttrUndefined)

{

  this->name_ = pName ? pName : "";
  this->description_ = pDescription ? pDescription : "";
  this->sourceType_ = sourceType;
  switch (sourceType) {
    case NDAttrSourceDriver:
      this->sourceTypeString_ = "NDAttrSourceDriver";
      break;
    case NDAttrSourceEPICSPV:
      this->sourceTypeString_ = "NDAttrSourceEPICSPV";
      break;
    case NDAttrSourceParam:
      this->sourceTypeString_ = "NDAttrSourceParam";
      break;
    case NDAttrSourceFunct:
      this->sourceTypeString_ = "NDAttrSourceFunct";
      break;
    default:
      this->sourceType_ = NDAttrSourceUndefined;
      this->sourceTypeString_ = "Undefined";
  }
  this->source_ = pSource ? pSource : "";
  this->string_ = "";
  if (pValue) {
    this->setDataType(dataType);
    this->setValue(pValue);
  }
  
  this->listNode_.pNDAttribute = this;
}

/** NDAttribute拷贝构造器
  * [in] attribute:从其拷贝属性
   NDAttribute类的成员变量:
   std::string name_;std::string description_; NDAttrDataType_t dataType_;  NDAttrValue value_;        
   std::string string_; std::string source_;  NDAttrSource_t sourceType_; std::string sourceTypeString_; 
  */
NDAttribute::NDAttribute(NDAttribute& attribute)
{
  void *pValue;
  this->name_ = attribute.name_;                    //复制属性名
  this->description_ = attribute.description_;      // 复制描述字符串
  this->source_ = attribute.source_;                // 复制来源字符串
  this->sourceType_ = attribute.sourceType_;        // 复制来源类型的枚举
  this->sourceTypeString_ = attribute.sourceTypeString_;  // 复制来源类型字符串
  this->string_ = "";                                     // 复制字符串类型属性的字符串
  this->dataType_ = attribute.dataType_;                  // 复制数据类型枚举
  if (attribute.dataType_ == NDAttrString) pValue = (void *)attribute.string_.c_str(); // 如果是字符串类型的属性,c_str()生成一个const char *指针,指向字符串的首地址
  else pValue = &attribute.value_; // 除字符串属性外,pValue指向需要被复制值的首地址
  this->setValue(pValue);
  this->listNode_.pNDAttribute = this;
}


/** NDAttribute析构函数 */
NDAttribute::~NDAttribute()
{
}

/** 从this复制属性到pOut。
  * pOut:指向这个输出属性的指针。如果NULL,将使用拷贝构造器创建输出属性。仅拷贝这个值,
  * 认为所有其它字段在pOut中已经相同。
  * 返回:指向这个副本的指针
  */
NDAttribute* NDAttribute::copy(NDAttribute *pOut)
{
  void *pValue;

  if (!pOut)
    pOut = new NDAttribute(*this);
  else {// 用一个指针指向要被复制的值
    if (this->dataType_ == NDAttrString) pValue = (void *)this->string_.c_str();
    else pValue = &this->value_;
    pOut->setValue(pValue);
  }
  return pOut;
}

/** 返回这个属性的名称,const char * 类型
  */
const char *NDAttribute::getName()
{
  return name_.c_str();
}

/** 设置这个属性的数据类型。这个仅能被调用一次 */
int NDAttribute::setDataType(NDAttrDataType_t type)
{
  // 设置数据类型为与已有类型相同类型是可以的。
  // 在通道访问重连时这将发生,并且如果驱动创建一个参数并且每次调用这个函数。
  if (type == this->dataType_) return ND_SUCCESS;
  if (this->dataType_ != NDAttrUndefined) { // 如果NDAttribute对象的数据类型不为DAttrUndefined,则报错。
    fprintf(stderr, "NDAttribute::setDataType, data type already defined = %d\n", this->dataType_);
    return ND_ERROR;
  }
  // 传入类型必须为合法的属性类型
  if ((type < NDAttrInt8) || (type > NDAttrString)) {
    fprintf(stderr, "NDAttribute::setDataType, invalid data type = %d\n", type);
    return ND_ERROR;
  }
  this->dataType_ = type;
  return ND_SUCCESS;
}

/**  返回这个属性的数据类型
  */
NDAttrDataType_t NDAttribute::getDataType()
{
  return dataType_;
}

/**  返回这个属性的描述,const char *
  */
const char *NDAttribute::getDescription()
{
  return description_.c_str();
}

/** 返回这个属性的来源字符串,const char *
  */
const char *NDAttribute::getSource()
{
  return source_.c_str();
}

/**  返回这个属性的来源信息
  * [out] pSourceType:这个属性的来源类型 (NDAttrSource_t). 
  * 返回: 这个属性的表示来源类型字符串
  */
const char *NDAttribute::getSourceInfo(NDAttrSource_t *pSourceType)
{
  *pSourceType = sourceType_;
  return sourceTypeString_.c_str();
}

/** 为这个属性设置值
  * [in] pValue :指向这个值的指针. */
int NDAttribute::setValue(const void *pValue)
{
  /* 如果任何数据类型,但未被定义,则指针必须有效 */
  if ((dataType_ != NDAttrUndefined) && !pValue) return ND_ERROR;

  /* 特殊处理字符串 */
  if (dataType_ == NDAttrString) {
     // 如果先前值是相同字符串,不做任何事情,节省释放和分配内存。
     // 如果不相同,释放老字符串,并且复制新字符串
    if (this->string_ == (char *)pValue) return ND_SUCCESS;
    this->string_ = (char *)pValue;
    return ND_SUCCESS;
  }
  switch (dataType_) { // 根据数据类型进行复制值
    case NDAttrInt8:
      this->value_.i8 = *(epicsInt8 *)pValue;
      break;
    case NDAttrUInt8:
      this->value_.ui8 = *(epicsUInt8 *)pValue;
      break;
    case NDAttrInt16:
      this->value_.i16 = *(epicsInt16 *)pValue;
      break;
    case NDAttrUInt16:
      this->value_.ui16 = *(epicsUInt16 *)pValue;
      break;
    case NDAttrInt32:
      this->value_.i32 = *(epicsInt32*)pValue;
      break;
    case NDAttrUInt32:
      this->value_.ui32 = *(epicsUInt32 *)pValue;
      break;
    case NDAttrInt64:
      this->value_.i64 = *(epicsInt64*)pValue;
      break;
    case NDAttrUInt64:
      this->value_.ui64 = *(epicsUInt64 *)pValue;
      break;
    case NDAttrFloat32:
      this->value_.f32 = *(epicsFloat32 *)pValue;
      break;
    case NDAttrFloat64:
      this->value_.f64 = *(epicsFloat64 *)pValue;
      break;
    case NDAttrUndefined:
      break;
    default:
      return ND_ERROR;
      break;
  }
  return ND_SUCCESS;
}

/** 为这个属性设置值
  * [in] value:这个属性的值  */
int NDAttribute::setValue(const std::string& value)
{
  /* 这个属性的值类型必须是字符串NDAttrString */
  if (dataType_ == NDAttrString) {
    this->string_ = value;
    return ND_SUCCESS;
  }
  return ND_ERROR;
}

/** 返回这个属性的数据类型和大小。
  * [out] pDataType:指向返回数据类型存储位置的指针 .
  * [out] pSize:指向存储返回数据大小的位置的指针; 这是用于除NDAttrString外的所有数据类型的大小 this is the
  * 在NDAttrString情况下,它是包含0终止符的字符串的长度。
  */
int NDAttribute::getValueInfo(NDAttrDataType_t *pDataType, size_t *pSize)
{
  *pDataType = this->dataType_;
  switch (this->dataType_) {
    case NDAttrInt8:
      *pSize = sizeof(this->value_.i8);
      break;
    case NDAttrUInt8:
      *pSize = sizeof(this->value_.ui8);
      break;
    case NDAttrInt16:
      *pSize = sizeof(this->value_.i16);
      break;
    case NDAttrUInt16:
      *pSize = sizeof(this->value_.ui16);
      break;
    case NDAttrInt32:
      *pSize = sizeof(this->value_.i32);
      break;
    case NDAttrUInt32:
      *pSize = sizeof(this->value_.ui32);
      break;
    case NDAttrInt64:
      *pSize = sizeof(this->value_.i64);
      break;
    case NDAttrUInt64:
      *pSize = sizeof(this->value_.ui64);
      break;
    case NDAttrFloat32:
      *pSize = sizeof(this->value_.f32);
      break;
    case NDAttrFloat64:
      *pSize = sizeof(this->value_.f64);
      break;
    case NDAttrString:// NDAttrString情况下,是字符串字符长度+1
      *pSize = this->string_.size()+1;
      break;// NDAttrUndefined情况下,尺寸为0
    case NDAttrUndefined:
      *pSize = 0;
      break;
    default: // 非法属性值类型
      return ND_ERROR;
      break;
  }
  return ND_SUCCESS;
}

/* 模板函数:模板类型名epicsType */
template 
int NDAttribute::getValueT(void *pValueIn, size_t dataSize)
{
  epicsType *pValue = (epicsType *)pValueIn;

  switch (this->dataType_) {// 根据NDAttribute对象的数据类型,获取除字符串类型外的所有类型的值
    case NDAttrInt8:
      *pValue = (epicsType) this->value_.i8;
      break;
    case NDAttrUInt8:
       *pValue = (epicsType) this->value_.ui8;
      break;
    case NDAttrInt16:
      *pValue = (epicsType) this->value_.i16;
      break;
    case NDAttrUInt16:
      *pValue = (epicsType) this->value_.ui16;
      break;
    case NDAttrInt32:
      *pValue = (epicsType) this->value_.i32;
      break;
    case NDAttrUInt32:
      *pValue = (epicsType) this->value_.ui32;
      break;
    case NDAttrInt64:
      *pValue = (epicsType) this->value_.i64;
      break;
    case NDAttrUInt64:
      *pValue = (epicsType) this->value_.ui64;
      break;
    case NDAttrFloat32:
      *pValue = (epicsType) this->value_.f32;
      break;
    case NDAttrFloat64:
      *pValue = (epicsType) this->value_.f64;
      break;
    default:
      return ND_ERROR;
  }
  return ND_SUCCESS ;
}


/** Returns the value of this attribute. 返回这个属性的值。
  * [in] dataType:这个值的数据类型.
  * [out] pValue:存储返回值的位置的指针.
  * [in] dataSize :输入数据位置的大小; 仅在dataType是NDAttrString,才使用.
  *
  * 在数值数据类型之间进行数据类型转换 */
int NDAttribute::getValue(NDAttrDataType_t dataType, void *pValue, size_t dataSize)
{
  switch (this->dataType_) {
    case NDAttrString: // NDAttribute对象是值是字符串类型
      if (dataType != NDAttrString) return ND_ERROR;
      if (dataSize == 0) dataSize = this->string_.size()+1;
      strncpy((char *)pValue, this->string_.c_str(), dataSize);
      return ND_SUCCESS;
    case NDAttrUndefined:
      return ND_ERROR;
    default:
      break;
  }

  switch (dataType) {
    case NDAttrInt8:
      return getValueT(pValue, dataSize);
    case NDAttrUInt8:
      return getValueT(pValue, dataSize);
    case NDAttrInt16:
      return getValueT(pValue, dataSize);
      break;
    case NDAttrUInt16:
      return getValueT(pValue, dataSize);
    case NDAttrInt32:
      return getValueT(pValue, dataSize);
    case NDAttrUInt32:
      return getValueT(pValue, dataSize);
    case NDAttrInt64:
      return getValueT(pValue, dataSize);
    case NDAttrUInt64:
      return getValueT(pValue, dataSize);
    case NDAttrFloat32:
      return getValueT(pValue, dataSize);
    case NDAttrFloat64:
      return getValueT(pValue, dataSize);
    default:
      return ND_ERROR;
  }
  return ND_SUCCESS ;
}

/** 以一个std::string返回一个NDAttrString的值。
  * [out] value: 存储这个返回值的位置.
  *
  *   在数值数据类型之间进行数据类型转换*/
int NDAttribute::getValue(std::string& value)
{
  switch (this->dataType_) {// 这个NDAttribute对象的值类型是NDAttrString,获取这个字符串,其余情况都返回出错
    case NDAttrString: 
      value = this->string_;
      return ND_SUCCESS;
    default:
      return ND_ERROR;
  }
}

/** 更新这个属性的当前值。
  * 这个基类什么也没做,但派生类可以获取这个属性的当前值,例如,从一个EPICS PV或者驱动参数库
 */
int NDAttribute::updateValue()
{
  return ND_SUCCESS;
}

/** 报告这个属性(attribute)的性质(properties)。
  * [in] fp : 报告输出的文件指针.
  * [in] details:所需报告的详细程度;当前什么也不做
  */
int NDAttribute::report(FILE *fp, int details)
{

  fprintf(fp, "\n");
  fprintf(fp, "NDAttribute, address=%p:\n", this); // 这个对象的地址
  fprintf(fp, "  name=%s\n", this->name_.c_str());  // 这个对象的属性名
  fprintf(fp, "  description=%s\n", this->description_.c_str()); //这个对象的描述
  fprintf(fp, "  source type=%d\n", this->sourceType_);  // 这个属性来源类型枚举值
  fprintf(fp, "  source type string=%s\n", this->sourceTypeString_.c_str()); // 这个属性来源类型字符串
  fprintf(fp, "  source=%s\n", this->source_.c_str());  //说明这个对象的值的来源的字符串
  switch (this->dataType_) {// 根据对象的值的类型,输出对应的值
    case NDAttrInt8:
      fprintf(fp, "  dataType=NDAttrInt8\n");
      fprintf(fp, "  value=%d\n", this->value_.i8);
      break;
    case NDAttrUInt8:
      fprintf(fp, "  dataType=NDAttrUInt8\n");
      fprintf(fp, "  value=%u\n", this->value_.ui8);
      break;
    case NDAttrInt16:
      fprintf(fp, "  dataType=NDAttrInt16\n");
      fprintf(fp, "  value=%d\n", this->value_.i16);
      break;
    case NDAttrUInt16:
      fprintf(fp, "  dataType=NDAttrUInt16\n");
      fprintf(fp, "  value=%d\n", this->value_.ui16);
      break;
    case NDAttrInt32:
      fprintf(fp, "  dataType=NDAttrInt32\n");
      fprintf(fp, "  value=%d\n", this->value_.i32);
      break;
    case NDAttrUInt32:
      fprintf(fp, "  dataType=NDAttrUInt32\n");
      fprintf(fp, "  value=%d\n", this->value_.ui32);
      break;
    case NDAttrInt64:
      fprintf(fp, "  dataType=NDAttrInt64\n");
      fprintf(fp, "  value=%lld\n", this->value_.i64);
      break;
    case NDAttrUInt64:
      fprintf(fp, "  dataType=NDAttrUInt64\n");
      fprintf(fp, "  value=%llu\n", this->value_.ui64);
      break;
    case NDAttrFloat32:
      fprintf(fp, "  dataType=NDAttrFloat32\n");
      fprintf(fp, "  value=%f\n", this->value_.f32);
      break;
    case NDAttrFloat64:
      fprintf(fp, "  dataType=NDAttrFloat64\n");
      fprintf(fp, "  value=%f\n", this->value_.f64);
      break;
    case NDAttrString: // 特殊处理值类型为NDAttrString的对象,这种对象的值存储在std::string_成员变量中
      fprintf(fp, "  dataType=NDAttrString\n");
      fprintf(fp, "  value=%s\n", this->string_.c_str());
      break;
    case NDAttrUndefined:
      fprintf(fp, "  dataType=NDAttrUndefined\n");
      break;
    default:
      fprintf(fp, "  dataType=UNKNOWN\n");
      return ND_ERROR;
      break;
  }
  return ND_SUCCESS;
}

1)以下代码是测试了 NDAttribute对象的源代码:

#include 
#include 
#include 

#include "NDAttribute.h"

int main()
{
        epicsInt8 i8 = -1;
        epicsInt8 i8_c;
        NDAttrSource_t sourceType;

        /* 测试构造函数:属性名,描述字符串, 属性值来源类型,说明属性值来源的字符串,属性值的类型,属性值*/
        NDAttribute * pAttribute = new NDAttribute("i8Attribute", "Test An attribute", NDAttrSourceDriver, "from driver", NDAttrInt8, &i8);

        /* 显示属性名*/
        printf("Name: %s\n", pAttribute->getName());
        /* 显示这个属性的描述 */
        printf("Description: %s\n", pAttribute->getDescription());
        /* 显示说明属性来源的字符串 */
        printf("Source: %s\n", pAttribute->getSource());
        /* 获取属性来源说明,以及属性值来源类型的枚举值 */
        printf("SourceInfo:%s\n", pAttribute->getSourceInfo(&sourceType));
        printf("SourceAttrSourceString:%d\n", sourceType);

        /* 获取这个属性的值 */
        pAttribute->getValue(NDAttrInt8, &i8_c);
        printf("The value from NDAttribute: %d\n", i8_c);

        pAttribute->report(stdout, 10);

        /* 测试拷贝构造函数 */
        NDAttribute * pAttribute_c = new NDAttribute(*pAttribute);
        pAttribute_c->report(stdout, 10);

        /* 设置NDAttribute对象的值*/
        i8 = 100;
        pAttribute->setValue(&i8);
        pAttribute->report(stdout, 10);

        return 0;
}

2)编译以上代码的Makefile文件:

TOP=..

include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE
#============================
PROD_HOST +=  testndattribute
testndattribute_SRCS += testndattribute.cpp
testndattribute_LIBS += asyn
testndattribute_LIBS += ADBase
testndattribute_LIBS += $(EPICS_BASE_IOC_LIBS)
testndattribute_LIBS += $(EPICS_BASE_HOST_LIBS)

include $(TOP)/configure/RULES

3)执行编译后的程序进行测试:

orangepi@orangepi4-lts:~/host_program/host/hostApp$ O.linux-aarch64/testndattribute
Name: i8Attribute
Description: Test An attribute
Source: from driver
SourceInfo:NDAttrSourceDriver
SourceAttrSourceString:0
The value from NDAttribute: -1

NDAttribute, address=0xaaaaf4b27b40:
  name=i8Attribute
  description=Test An attribute
  source type=0
  source type string=NDAttrSourceDriver
  source=from driver
  dataType=NDAttrInt8
  value=-1

NDAttribute, address=0xaaaaf4b280f0:
  name=i8Attribute
  description=Test An attribute
  source type=0
  source type string=NDAttrSourceDriver
  source=from driver
  dataType=NDAttrInt8
  value=-1

NDAttribute, address=0xaaaaf4b27b40:
  name=i8Attribute
  description=Test An attribute
  source type=0
  source type string=NDAttrSourceDriver
  source=from driver
  dataType=NDAttrInt8
  value=100

你可能感兴趣的:(EPICS教程,Linux,C,EPICS,C语言)