diff --git a/src/Makefile b/src/Makefile index 3e8c1e6..f9cca3e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,6 +19,7 @@ INC += ntmatrix.h INC += ntenum.h INC += ntunion.h INC += ntaggregate.h +INC += ntattribute.h LIBSRCS += ntutils.cpp LIBSRCS += ntfield.cpp @@ -33,6 +34,7 @@ LIBSRCS += ntmatrix.cpp LIBSRCS += ntenum.cpp LIBSRCS += ntunion.cpp LIBSRCS += ntaggregate.cpp +LIBSRCS += ntattribute.cpp LIBRARY = nt diff --git a/src/nt/nt.h b/src/nt/nt.h index f4ef74a..909c612 100644 --- a/src/nt/nt.h +++ b/src/nt/nt.h @@ -22,6 +22,7 @@ #include #include #include +#include #endif /* NT_H */ diff --git a/src/nt/ntattribute.cpp b/src/nt/ntattribute.cpp new file mode 100644 index 0000000..f9a6d81 --- /dev/null +++ b/src/nt/ntattribute.cpp @@ -0,0 +1,202 @@ +/* ntattribute.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#define epicsExportSharedSymbols +#include +#include + +using namespace std; +using namespace epics::pvData; + +namespace epics { namespace nt { + +static NTFieldPtr ntField = NTField::get(); + +namespace detail { + +static NTFieldPtr ntField = NTField::get(); + + +StructureConstPtr NTAttributeBuilder::createStructure() +{ + FieldBuilderPtr builder = + getFieldCreate()->createFieldBuilder()-> + setId(NTAttribute::URI)-> + add("name", pvString)-> + add("value", getFieldCreate()->createVariantUnion()); + + if (tags) + builder->addArray("tags", pvString); + + if (descriptor) + builder->add("descriptor", pvString); + + if (alarm) + builder->add("alarm", ntField->createAlarm()); + + if (timeStamp) + builder->add("timeStamp", ntField->createTimeStamp()); + + size_t extraCount = extraFieldNames.size(); + for (size_t i = 0; i< extraCount; i++) + builder->add(extraFieldNames[i], extraFields[i]); + + + StructureConstPtr s = builder->createStructure(); + + reset(); + return s; +} + +NTAttributeBuilder::shared_pointer NTAttributeBuilder::addTags() +{ + tags = true; + return shared_from_this(); +} + +NTAttributeBuilder::shared_pointer NTAttributeBuilder::addDescriptor() +{ + descriptor = true; + return shared_from_this(); +} + +NTAttributeBuilder::shared_pointer NTAttributeBuilder::addAlarm() +{ + alarm = true; + return shared_from_this(); +} + +NTAttributeBuilder::shared_pointer NTAttributeBuilder::addTimeStamp() +{ + timeStamp = true; + return shared_from_this(); +} + +PVStructurePtr NTAttributeBuilder::createPVStructure() +{ + return getPVDataCreate()->createPVStructure(createStructure()); +} + +NTAttributePtr NTAttributeBuilder::create() +{ + return NTAttributePtr(new NTAttribute(createPVStructure())); +} + +NTAttributeBuilder::NTAttributeBuilder() +{ + reset(); +} + +void NTAttributeBuilder::reset() +{ + descriptor = false; + alarm = false; + timeStamp = false; + extraFieldNames.clear(); + extraFields.clear(); +} + +NTAttributeBuilder::shared_pointer NTAttributeBuilder::add(string const & name, FieldConstPtr const & field) +{ + extraFields.push_back(field); extraFieldNames.push_back(name); + return shared_from_this(); +} + +} + +const std::string NTAttribute::URI("epics:nt/NTAttribute:1.0"); + +NTAttribute::shared_pointer NTAttribute::wrap(PVStructurePtr const & structure) +{ + if(!isCompatible(structure)) return shared_pointer(); + return wrapUnsafe(structure); +} + +NTAttribute::shared_pointer NTAttribute::wrapUnsafe(PVStructurePtr const & structure) +{ + return shared_pointer(new NTAttribute(structure)); +} + +bool NTAttribute::is_a(StructureConstPtr const & structure) +{ + return NTUtils::is_a(structure->getID(), URI); +} + +bool NTAttribute::isCompatible(PVStructurePtr const & pvStructure) +{ + if(!pvStructure) return false; + + PVUnionPtr pvValue = pvStructure->getSubField("value"); + if(!pvValue) return false; + + PVFieldPtr pvField = pvStructure->getSubField("descriptor"); + if(pvField && !pvStructure->getSubField("descriptor")) return false; + + pvField = pvStructure->getSubField("alarm"); + if(pvField && !ntField->isAlarm(pvField->getField())) return false; + + pvField = pvStructure->getSubField("timeStamp"); + if(pvField && !ntField->isTimeStamp(pvField->getField())) return false; + + return true; +} + +NTAttributeBuilderPtr NTAttribute::createBuilder() +{ + return NTAttributeBuilderPtr(new detail::NTAttributeBuilder()); +} + +bool NTAttribute::attachTimeStamp(PVTimeStamp &pvTimeStamp) const +{ + PVStructurePtr ts = getTimeStamp(); + if (ts) + return pvTimeStamp.attach(ts); + else + return false; +} + +bool NTAttribute::attachAlarm(PVAlarm &pvAlarm) const +{ + PVStructurePtr al = getAlarm(); + if (al) + return pvAlarm.attach(al); + else + return false; +} + +PVStructurePtr NTAttribute::getPVStructure() const +{ + return pvNTAttribute; +} + +PVStringPtr NTAttribute::getDescriptor() const +{ + return pvNTAttribute->getSubField("descriptor"); +} + +PVStructurePtr NTAttribute::getTimeStamp() const +{ + return pvNTAttribute->getSubField("timeStamp"); +} + +PVStructurePtr NTAttribute::getAlarm() const +{ + return pvNTAttribute->getSubField("alarm"); +} + +PVUnionPtr NTAttribute::getValue() const +{ + return pvValue; +} + +NTAttribute::NTAttribute(PVStructurePtr const & pvStructure) : + pvNTAttribute(pvStructure), pvValue(pvNTAttribute->getSubField("value")) +{ +} + + +}} diff --git a/src/nt/ntattribute.h b/src/nt/ntattribute.h new file mode 100644 index 0000000..8d5bab7 --- /dev/null +++ b/src/nt/ntattribute.h @@ -0,0 +1,228 @@ +/* ntattribute.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#ifndef NTATTRIBUTE_H +#define NTATTRIBUTE_H + +#ifdef epicsExportSharedSymbols +# define ntattributeEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#ifdef ntattributeEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef ntattributeEpicsExportSharedSymbols +#endif + +#include + +#include + +namespace epics { namespace nt { + +class NTAttribute; +typedef std::tr1::shared_ptr NTAttributePtr; + +namespace detail { + + /** + * @brief Interface for in-line creating of NTAttribute. + * + * One instance can be used to create multiple instances. + * An instance of this object must not be used concurrently (an object has a state). + * @author dgh + */ + class epicsShareClass NTAttributeBuilder : + public std::tr1::enable_shared_from_this + { + public: + POINTER_DEFINITIONS(NTAttributeBuilder); + + /** + * Add tags field to the NTAttribute. + * @return this instance of NTAttributeBuilder. + */ + virtual shared_pointer addTags(); + + /** + * Add descriptor field to the NTAttribute. + * @return this instance of NTAttributeBuilder. + */ + shared_pointer addDescriptor(); + + /** + * Add alarm structure to the NTAttribute. + * @return this instance of NTAttributeBuilder. + */ + shared_pointer addAlarm(); + + /** + * Add timeStamp structure to the NTAttribute. + * @return this instance of NTAttributeBuilder. + */ + shared_pointer addTimeStamp(); + + /** + * Create a Structure that represents NTAttribute. + * This resets this instance state and allows new instance to be created. + * @return a new instance of a Structure. + */ + epics::pvData::StructureConstPtr createStructure(); + + /** + * Create a PVStructure that represents NTAttribute. + * This resets this instance state and allows new instance to be created. + * @return a new instance of a PVStructure. + */ + epics::pvData::PVStructurePtr createPVStructure(); + + /** + * Create a NTAttribute instance. + * This resets this instance state and allows new instance to be created. + * @return a new instance of a NTAttribute. + */ + NTAttributePtr create(); + /** + * Add extra Field to the type. + * @param name name of the field. + * @param field a field to add. + * @return this instance of NTAttributeBuilder. + */ + shared_pointer add(std::string const & name, epics::pvData::FieldConstPtr const & field); + + protected://private: + NTAttributeBuilder(); + + void reset(); + + bool tags; + bool descriptor; + bool alarm; + bool timeStamp; + + // NOTE: this preserves order, however it does not handle duplicates + epics::pvData::StringArray extraFieldNames; + epics::pvData::FieldConstPtrArray extraFields; + + friend class ::epics::nt::NTAttribute; + }; + +} + +typedef std::tr1::shared_ptr NTAttributeBuilderPtr; + + + +/** + * @brief Convenience Class for NTAttribute + * + * @author dgh + */ +class epicsShareClass NTAttribute +{ +public: + POINTER_DEFINITIONS(NTAttribute); + + static const std::string URI; + + /** + * Wrap (aka dynamic cast, or wrap) the structure to NTAttribute. + * First isCompatible is called. + * This method will nullptr if the structure is is not compatible. + * This method will nullptr if the structure is nullptr. + * @param structure The structure to wrap-ed (dynamic cast, wrapped) to NTAttribute. + * @return NTAttribute instance on success, nullptr otherwise. + */ + static shared_pointer wrap(epics::pvData::PVStructurePtr const & structure); + + /** + * Wrap (aka dynamic cast, or wrap) the structure to NTMultiChannel without checking for isCompatible + * @param structure The structure to wrap-ed (dynamic cast, wrapped) to NTAttribute. + * @return NTAttribute instance. + */ + static shared_pointer wrapUnsafe(epics::pvData::PVStructurePtr const & structure); + + /** + * Is the structure an NTAttribute. + * @param structure The structure to test. + * @return (false,true) if (is not, is) an NTAttribute. + */ + static bool is_a(epics::pvData::StructureConstPtr const & structure); + /** + * Is the pvStructure compatible with NTAttribute. + * This method introspects the fields to see if they are compatible. + * @param pvStructure The pvStructure to test. + * @return (false,true) if (is not, is) an NTMultiChannel. + */ + static bool isCompatible( + epics::pvData::PVStructurePtr const &pvStructure); + /** + * Create a NTAttribute builder instance. + * @return builder instance. + */ + static NTAttributeBuilderPtr createBuilder(); + + /** + * Destructor. + */ + ~NTAttribute() {} + + /** + * Attach a pvTimeStamp. + * @param pvTimeStamp The pvTimeStamp that will be attached. + * Does nothing if no timeStamp. + * @return true if the operation was successfull (i.e. this instance has a timeStamp field), otherwise false. + */ + bool attachTimeStamp(epics::pvData::PVTimeStamp &pvTimeStamp) const; + + /** + * Attach an pvAlarm. + * @param pvAlarm The pvAlarm that will be attached. + * Does nothing if no alarm. + * @return true if the operation was successfull (i.e. this instance has a timeStamp field), otherwise false. + */ + bool attachAlarm(epics::pvData::PVAlarm &pvAlarm) const; + + /** + * Get the pvStructure. + * @return PVStructurePtr. + */ + epics::pvData::PVStructurePtr getPVStructure() const; + + /** + * Get the descriptor field. + * @return The pvString or null if no function field. + */ + epics::pvData::PVStringPtr getDescriptor() const; + + /** + * Get the timeStamp. + * @return PVStructurePtr which may be null. + */ + epics::pvData::PVStructurePtr getTimeStamp() const; + + /** + * Get the alarm. + * @return PVStructurePtr which may be null. + */ + epics::pvData::PVStructurePtr getAlarm() const; + + /** + * Get the value field. + * @return The PVUnion for the values. + */ + epics::pvData::PVUnionPtr getValue() const; + +private: + NTAttribute(epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr pvNTAttribute; + epics::pvData::PVUnionPtr pvValue; + + friend class detail::NTAttributeBuilder; +}; + +}} +#endif /* NTATTRIBUTE_H */