diff --git a/src/Makefile b/src/Makefile index 85fdbf8..8b6b64b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -21,6 +21,7 @@ INC += ntunion.h INC += ntaggregate.h INC += ntattribute.h INC += ntcontinuum.h +INC += nthistogram.h LIBSRCS += ntutils.cpp LIBSRCS += ntfield.cpp @@ -37,6 +38,7 @@ LIBSRCS += ntunion.cpp LIBSRCS += ntaggregate.cpp LIBSRCS += ntattribute.cpp LIBSRCS += ntcontinuum.cpp +LIBSRCS += nthistogram.cpp LIBRARY = nt diff --git a/src/nt/nt.h b/src/nt/nt.h index 143292d..b70ee27 100644 --- a/src/nt/nt.h +++ b/src/nt/nt.h @@ -24,6 +24,7 @@ #include #include #include +#include #endif /* NT_H */ diff --git a/src/nt/nthistogram.cpp b/src/nt/nthistogram.cpp new file mode 100644 index 0000000..549c2a9 --- /dev/null +++ b/src/nt/nthistogram.cpp @@ -0,0 +1,206 @@ +/* ntcontinuum.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 { + +NTHistogramBuilder::shared_pointer NTHistogramBuilder::value( + epics::pvData::ScalarType scalarType + ) +{ + valueType = scalarType; + valueTypeSet = true; + + return shared_from_this(); +} + +StructureConstPtr NTHistogramBuilder::createStructure() +{ + if (!valueTypeSet) + throw std::runtime_error("value array element type not set"); + + FieldBuilderPtr builder = + getFieldCreate()->createFieldBuilder()-> + setId(NTHistogram::URI)-> + addArray("ranges", pvDouble)-> + addArray("value", valueType); + + 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; +} + +NTHistogramBuilder::shared_pointer NTHistogramBuilder::addDescriptor() +{ + descriptor = true; + return shared_from_this(); +} + +NTHistogramBuilder::shared_pointer NTHistogramBuilder::addAlarm() +{ + alarm = true; + return shared_from_this(); +} + +NTHistogramBuilder::shared_pointer NTHistogramBuilder::addTimeStamp() +{ + timeStamp = true; + return shared_from_this(); +} + + +PVStructurePtr NTHistogramBuilder::createPVStructure() +{ + return getPVDataCreate()->createPVStructure(createStructure()); +} + +NTHistogramPtr NTHistogramBuilder::create() +{ + return NTHistogramPtr(new NTHistogram(createPVStructure())); +} + +NTHistogramBuilder::NTHistogramBuilder() +{ + reset(); +} + +void NTHistogramBuilder::reset() +{ + valueTypeSet = false; + descriptor = false; + alarm = false; + timeStamp = false; + extraFieldNames.clear(); + extraFields.clear(); +} + +NTHistogramBuilder::shared_pointer NTHistogramBuilder::add(string const & name, FieldConstPtr const & field) +{ + extraFields.push_back(field); extraFieldNames.push_back(name); + return shared_from_this(); +} + +} + +const std::string NTHistogram::URI("epics:nt/NTHistogram:1.0"); + +NTHistogram::shared_pointer NTHistogram::wrap(PVStructurePtr const & structure) +{ + if(!isCompatible(structure)) return shared_pointer(); + return wrapUnsafe(structure); +} + +NTHistogram::shared_pointer NTHistogram::wrapUnsafe(PVStructurePtr const & structure) +{ + return shared_pointer(new NTHistogram(structure)); +} + +bool NTHistogram::is_a(StructureConstPtr const & structure) +{ + return NTUtils::is_a(structure->getID(), URI); +} + +bool NTHistogram::isCompatible(PVStructurePtr const & pvStructure) +{ + if(!pvStructure) return false; + PVScalarArrayPtr 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; +} + + +NTHistogramBuilderPtr NTHistogram::createBuilder() +{ + return NTHistogramBuilderPtr(new detail::NTHistogramBuilder()); +} + +bool NTHistogram::attachTimeStamp(PVTimeStamp &pvTimeStamp) const +{ + PVStructurePtr ts = getTimeStamp(); + if (ts) + return pvTimeStamp.attach(ts); + else + return false; +} + +bool NTHistogram::attachAlarm(PVAlarm &pvAlarm) const +{ + PVStructurePtr al = getAlarm(); + if (al) + return pvAlarm.attach(al); + else + return false; +} + +PVStructurePtr NTHistogram::getPVStructure() const +{ + return pvNTHistogram; +} + +PVStringPtr NTHistogram::getDescriptor() const +{ + return pvNTHistogram->getSubField("descriptor"); +} + +PVStructurePtr NTHistogram::getTimeStamp() const +{ + return pvNTHistogram->getSubField("timeStamp"); +} + +PVStructurePtr NTHistogram::getAlarm() const +{ + return pvNTHistogram->getSubField("alarm"); +} + +PVDoubleArrayPtr NTHistogram::getRanges() const +{ + return pvNTHistogram->getSubField("ranges"); +} + +PVScalarArrayPtr NTHistogram::getValue() const +{ + return pvValue; +} + +NTHistogram::NTHistogram(PVStructurePtr const & pvStructure) : + pvNTHistogram(pvStructure), + pvValue(pvNTHistogram->getSubField("value")) +{} + + +}} diff --git a/src/nt/nthistogram.h b/src/nt/nthistogram.h new file mode 100644 index 0000000..db67ad9 --- /dev/null +++ b/src/nt/nthistogram.h @@ -0,0 +1,277 @@ +/* nthistogram.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 NTHISTOGRAM_H +#define NTHISTOGRAM_H + +#ifdef epicsExportSharedSymbols +# define nthistogramEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#ifdef nthistogramEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef nthistogramEpicsExportSharedSymbols +#endif + +#include + +#include + + +namespace epics { namespace nt { + +class NTHistogram; +typedef std::tr1::shared_ptr NTHistogramPtr; + +namespace detail { + + /** + * @brief Interface for in-line creating of NTHistogram. + * + * 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 NTHistogramBuilder : + public std::tr1::enable_shared_from_this + { + public: + POINTER_DEFINITIONS(NTHistogramBuilder); + + /** + * Set a scalar type of value field array. + * @param scalarType the value type. + * @return this instance of NTHistogramBuilder. + */ + shared_pointer value(epics::pvData::ScalarType scalarType); + + /** + * Add descriptor field to the NTHistogram. + * @return this instance of NTHistogramBuilder. + */ + shared_pointer addDescriptor(); + + /** + * Add alarm structure to the NTHistogram. + * @return this instance of NTHistogramBuilder. + */ + shared_pointer addAlarm(); + + /** + * Add timeStamp structure to the NTHistogram. + * @return this instance of NTHistogramBuilder. + */ + shared_pointer addTimeStamp(); + + /** + * Create a Structure that represents NTHistogram. + * This resets this instance state and allows new instance to be created. + * @return a new instance of Structure. + */ + epics::pvData::StructureConstPtr createStructure(); + + /** + * Create a PVStructure that represents NTHistogram. + * This resets this instance state and allows new instance to be created. + * @return a new instance of PVStructure. + */ + epics::pvData::PVStructurePtr createPVStructure(); + + /** + * Create a NTHistogram instance. + * This resets this instance state and allows new instance to be created. + * @return a new instance of NTHistogram. + */ + NTHistogramPtr create(); + /** + * Add extra Field to the type. + * @param name name of the field. + * @param field a field to add. + * @return this instance of NTHistogramBuilder. + */ + shared_pointer add(std::string const & name, epics::pvData::FieldConstPtr const & field); + + private: + NTHistogramBuilder(); + + void reset(); + + bool valueTypeSet; + epics::pvData::ScalarType valueType; + + bool dim; + 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::NTHistogram; + }; + +} + +typedef std::tr1::shared_ptr NTHistogramBuilderPtr; + + + +/** + * @brief Convenience Class for NTHistogram + * + * @author dgh + */ +class epicsShareClass NTHistogram +{ +public: + POINTER_DEFINITIONS(NTHistogram); + + static const std::string URI; + + /** + * Wrap (aka dynamic cast, or wrap) the structure to NTHistogram. + * 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 NTHistogram. + * @return NTHistogram instance on success, nullptr otherwise. + */ + static shared_pointer wrap(epics::pvData::PVStructurePtr const & structure); + + /** + * Wrap (aka dynamic cast, or wrap) the structure to NTHistogram without checking for isCompatible + * @param structure The structure to wrap-ed (dynamic cast, wrapped) to NTHistogram. + * @return NTHistogram instance. + */ + static shared_pointer wrapUnsafe(epics::pvData::PVStructurePtr const & structure); + + /** + * Is the structure an NTHistogram. + * @param structure The structure to test. + * @return (false,true) if (is not, is) an NTHistogram. + */ + static bool is_a(epics::pvData::StructureConstPtr const & structure); + + /** + * Is the structure an NTHistogram. + * @param pvStructure The PVStructure to test. + * @return (false,true) if (is not, is) an NTHistogram. + */ + static bool is_a(epics::pvData::PVStructurePtr const & pvStructure); + + /** + * Is the Structure compatible with NTHistogram. + * This method introspects the fields to see if they are compatible. + * @param structure The Structure to test. + * @return (false,true) if (is not, is) an NTHistogram. + */ + static bool isCompatible( + epics::pvData::StructureConstPtr const &structure); + + /** + * Is the PVStructure compatible with NTHistogram. + * 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 NTHistogram. + */ + static bool isCompatible( + epics::pvData::PVStructurePtr const &pvStructure); + + /** + * Checks if the specified structure is a valid NTHistogram. + * + * Checks whether the wrapped structure is valid with respect to this + * version of NTHistogram + * @return (false,true) if (is not, is) a valid NTHistogram. + */ + bool isValid(); + + /** + * Create a NTHistogram builder instance. + * @return builder instance. + */ + static NTHistogramBuilderPtr createBuilder(); + + /** + * Destructor. + */ + ~NTHistogram() {} + + /** + * 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 base field. + * @return The PVDoubleArray for the base. + */ + epics::pvData::PVDoubleArrayPtr getRanges() const; + + /** + * Get the value field. + * @return The PVScalarArray for the values. + */ + epics::pvData::PVScalarArrayPtr getValue() const; + + /** + * Get the value field of a specified type (e.g. PVIntArray). + * @return The field for the values. + */ + template + std::tr1::shared_ptr getValue() const + { + return std::tr1::dynamic_pointer_cast(pvValue); + } + + +private: + NTHistogram(epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr pvNTHistogram; + epics::pvData::PVScalarArrayPtr pvValue; + + friend class detail::NTHistogramBuilder; +}; + +}} +#endif /* NTHISTOGRAM_H */