#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