From 379a132cd742e87f5a72407a9e77bcfa99eb6d5b Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 22 Aug 2014 09:12:24 +0200 Subject: [PATCH] NTScalar added --- src/Makefile | 2 + src/nt/nt.h | 1 + src/nt/ntscalar.cpp | 217 ++++++++++++++++++++++++++++++++++ src/nt/ntscalar.h | 246 +++++++++++++++++++++++++++++++++++++++ test/nt/Makefile | 20 ++-- test/nt/ntscalarTest.cpp | 196 +++++++++++++++++++++++++++++++ 6 files changed, 672 insertions(+), 10 deletions(-) create mode 100644 src/nt/ntscalar.cpp create mode 100644 src/nt/ntscalar.h create mode 100644 test/nt/ntscalarTest.cpp diff --git a/src/Makefile b/src/Makefile index c81926a..abd4732 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,11 +7,13 @@ SRC_DIRS += $(SRC)/nt INC += nt.h INC += ntfield.h +INC += ntscalar.h INC += ntnameValue.h INC += nttable.h INC += ntmultiChannel.h LIBSRCS += ntfield.cpp +LIBSRCS += ntscalar.cpp LIBSRCS += ntnameValue.cpp LIBSRCS += nttable.cpp LIBSRCS += ntmultiChannel.cpp diff --git a/src/nt/nt.h b/src/nt/nt.h index 747a303..187b90e 100644 --- a/src/nt/nt.h +++ b/src/nt/nt.h @@ -8,6 +8,7 @@ #define NT_H #include +#include #include #include diff --git a/src/nt/ntscalar.cpp b/src/nt/ntscalar.cpp new file mode 100644 index 0000000..9bd935b --- /dev/null +++ b/src/nt/ntscalar.cpp @@ -0,0 +1,217 @@ +/* ntscalar.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. + */ + +#include + +using namespace std; +using namespace epics::pvData; + +namespace epics { namespace nt { + +namespace detail { + +static NTFieldPtr ntField = NTField::get(); + +NTScalarBuilder::shared_pointer NTScalarBuilder::value( + epics::pvData::ScalarType scalarType + ) +{ + isArray = false; + valueType = scalarType; + valueTypeSet = true; + + return shared_from_this(); +} + +NTScalarBuilder::shared_pointer NTScalarBuilder::arrayValue( + epics::pvData::ScalarType scalarType + ) +{ + isArray = true; + valueType = scalarType; + valueTypeSet = true; + + return shared_from_this(); +} + +StructureConstPtr NTScalarBuilder::createStructure() +{ + if (!valueTypeSet) + throw std::runtime_error("value type not set"); + + FieldBuilderPtr builder = + getFieldCreate()->createFieldBuilder()-> + setId(NTScalar::URI)-> + add("value", valueType); + + if (descriptor) + builder->add("descriptor", pvString); + + if (alarm) + builder->add("alarm", ntField->createAlarm()); + + if (timeStamp) + builder->add("timeStamp", ntField->createTimeStamp()); + + if (display) + builder->add("display", ntField->createDisplay()); + + if (control) + builder->add("control", ntField->createControl()); + + StructureConstPtr s = builder->createStructure(); + + reset(); + return s; +} + +NTScalarBuilder::shared_pointer NTScalarBuilder::addDescriptor() +{ + descriptor = true; + return shared_from_this(); +} + +NTScalarBuilder::shared_pointer NTScalarBuilder::addAlarm() +{ + alarm = true; + return shared_from_this(); +} + +NTScalarBuilder::shared_pointer NTScalarBuilder::addTimeStamp() +{ + timeStamp = true; + return shared_from_this(); +} + +NTScalarBuilder::shared_pointer NTScalarBuilder::addDisplay() +{ + display = true; + return shared_from_this(); +} + +NTScalarBuilder::shared_pointer NTScalarBuilder::addControl() +{ + control = true; + return shared_from_this(); +} + +PVStructurePtr NTScalarBuilder::createPVStructure() +{ + return getPVDataCreate()->createPVStructure(createStructure()); +} + +NTScalarPtr NTScalarBuilder::create() +{ + return NTScalarPtr(new NTScalar(createPVStructure())); +} + +NTScalarBuilder::NTScalarBuilder() +{ + reset(); +} + +void NTScalarBuilder::reset() +{ + valueTypeSet = false; + descriptor = false; + alarm = false; + timeStamp = false; + display = false; + control = false; +} + +} + +const std::string NTScalar::URI("uri:ev4:nt/2012/pwd:NTScalar"); + +bool NTScalar::is_a(StructureConstPtr const & structure) +{ + return structure->getID() == URI; +} + +NTScalarBuilderPtr NTScalar::createBuilder() +{ + return NTScalarBuilderPtr(new detail::NTScalarBuilder()); +} + +bool NTScalar::attachTimeStamp(PVTimeStamp &pvTimeStamp) const +{ + PVStructurePtr ts = getTimeStamp(); + if (ts) + return pvTimeStamp.attach(ts); + else + return false; +} + +bool NTScalar::attachAlarm(PVAlarm &pvAlarm) const +{ + PVStructurePtr al = getAlarm(); + if (al) + return pvAlarm.attach(al); + else + return false; +} + +bool NTScalar::attachDisplay(PVDisplay &pvDisplay) const +{ + PVStructurePtr dp = getDisplay(); + if (dp) + return pvDisplay.attach(dp); + else + return false; +} + +bool NTScalar::attachControl(PVControl &pvControl) const +{ + PVStructurePtr ctrl = getControl(); + if (ctrl) + return pvControl.attach(ctrl); + else + return false; +} + +PVStructurePtr NTScalar::getPVStructure() const +{ + return pvNTScalar; +} + +PVStringPtr NTScalar::getDescriptor() const +{ + return pvNTScalar->getSubField("descriptor"); +} + +PVStructurePtr NTScalar::getTimeStamp() const +{ + return pvNTScalar->getSubField("timeStamp"); +} + +PVStructurePtr NTScalar::getAlarm() const +{ + return pvNTScalar->getSubField("alarm"); +} + +PVStructurePtr NTScalar::getDisplay() const +{ + return pvNTScalar->getSubField("display"); +} + +PVStructurePtr NTScalar::getControl() const +{ + return pvNTScalar->getSubField("control"); +} + +PVFieldPtr NTScalar::getValue() const +{ + return pvNTScalar->getSubField("value"); +} + +NTScalar::NTScalar(PVStructurePtr const & pvStructure) : + pvNTScalar(pvStructure) +{} + + +}} diff --git a/src/nt/ntscalar.h b/src/nt/ntscalar.h new file mode 100644 index 0000000..cab4d7c --- /dev/null +++ b/src/nt/ntscalar.h @@ -0,0 +1,246 @@ +/* ntscalar.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 NTSCALAR_H +#define NTSCALAR_H + +#include +#include +#include + +namespace epics { namespace nt { + +class NTScalar; +typedef std::tr1::shared_ptr NTScalarPtr; + +namespace detail { + + /** + * Interface for in-line creating of NTScalar. + * 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 mse + */ + class epicsShareClass NTScalarBuilder : + public std::tr1::enable_shared_from_this + { + public: + POINTER_DEFINITIONS(NTScalarBuilder); + + /** + * Set a value type of a NTScalar. + * @param scalarType the value type. + * @return this instance of a {@code NTTableBuilder}. + */ + shared_pointer value(epics::pvData::ScalarType scalarType); + + /** + * Set a value array type of a NTScalar, i.e. it creates an NTScalarArray. + * @param scalarType the value array element type. + * @return this instance of a {@code NTTableBuilder}. + */ + shared_pointer arrayValue(epics::pvData::ScalarType scalarType); + + /** + * Add descriptor field to the NTScalar. + * @return this instance of a {@code NTScalarBuilder}. + */ + shared_pointer addDescriptor(); + + /** + * Add alarm structure to the NTScalar. + * @return this instance of a {@code NTScalarBuilder}. + */ + shared_pointer addAlarm(); + + /** + * Add timeStamp structure to the NTScalar. + * @return this instance of a {@code NTScalarBuilder}. + */ + shared_pointer addTimeStamp(); + + /** + * Add display structure to the NTScalar. + * @return this instance of a {@code NTScalarBuilder}. + */ + shared_pointer addDisplay(); + + /** + * Add control structure to the NTScalar. + * @return this instance of a {@code NTScalarBuilder}. + */ + shared_pointer addControl(); + + /** + * Create a {@code Structure} that represents NTScalar. + * This resets this instance state and allows new instance to be created. + * @return a new instance of a {@code Structure}. + */ + epics::pvData::StructureConstPtr createStructure(); + + /** + * Create a {@code PVStructure} that represents NTScalar. + * This resets this instance state and allows new {@code instance to be created. + * @return a new instance of a {@code PVStructure} + */ + epics::pvData::PVStructurePtr createPVStructure(); + + /** + * Create a {@code NTScalar} instance. + * This resets this instance state and allows new {@code instance to be created. + * @return a new instance of a {@code NTScalar} + */ + NTScalarPtr create(); + + private: + NTScalarBuilder(); + + void reset(); + + bool isArray; + bool valueTypeSet; + epics::pvData::ScalarType valueType; + + bool descriptor; + bool alarm; + bool timeStamp; + bool display; + bool control; + + friend class ::epics::nt::NTScalar; + }; + +} + +typedef std::tr1::shared_ptr NTScalarBuilderPtr; + + + +/** + * Convenience Class for NTScalar + * @author mrk + */ +class NTScalar +{ +public: + POINTER_DEFINITIONS(NTScalar); + + static const std::string URI; + + /** + * Is the structure an NTScalar. + * @param structure The structure to test. + * @return (false,true) if (is not, is) an NTScalar. + */ + static bool is_a(epics::pvData::StructureConstPtr const & structure); + + /** + * Create a NTScalar builder instance. + * @return builder instance. + */ + static NTScalarBuilderPtr createBuilder(); + + /** + * Destructor. + */ + ~NTScalar() {} + + /** + * 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; + + /** + * Attach an pvDisplay. + * @param pvDisplay The pvDisplay that will be attached. + * Does nothing if no display. + * @return true if the operation was successfull (i.e. this instance has a display field), otherwise false. + */ + bool attachDisplay(epics::pvData::PVDisplay &pvDisplay) const; + + /** + * Attach an pvControl. + * @param pvControl The pvControl that will be attached. + * Does nothing if no control. + * @return true if the operation was successfull (i.e. this instance has a control field), otherwise false. + */ + bool attachControl(epics::pvData::PVControl &pvControl) 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 display. + * @return PVStructurePtr which may be null. + */ + epics::pvData::PVStructurePtr getDisplay() const; + + /** + * Get the control. + * @return PVStructurePtr which may be null. + */ + epics::pvData::PVStructurePtr getControl() const; + + /** + * Get the value field. + * @return The PVField for the values. + */ + epics::pvData::PVFieldPtr getValue() const; + + /** + * Get the value field of a specified type (e.g. PVDouble). + * @return The field for the values. + */ + template + std::tr1::shared_ptr getValue() const + { + epics::pvData::PVFieldPtr pvField = getValue(); + if (pvField.get()) + return std::tr1::dynamic_pointer_cast(pvField); + else + return std::tr1::shared_ptr(); + } + +private: + NTScalar(epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr pvNTScalar; + friend class detail::NTScalarBuilder; +}; + +}} +#endif /* NTScalar_H */ diff --git a/test/nt/Makefile b/test/nt/Makefile index 86da46d..7cab6d4 100644 --- a/test/nt/Makefile +++ b/test/nt/Makefile @@ -4,26 +4,26 @@ include $(TOP)/configure/CONFIG PROD_LIBS += nt pvData Com -PROD_HOST += ntfieldTest +TESTPROD_HOST += ntfieldTest ntfieldTest_SRCS += ntfieldTest.cpp -ntfieldTest_LIBS += nt pvData Com +TESTS += ntfieldTest -PROD_HOST += ntnameValueTest +TESTPROD_HOST += ntscalarTest +ntscalarTest_SRCS += ntscalarTest.cpp +TESTS += ntscalarTest + +TESTPROD_HOST += ntnameValueTest ntnameValueTest_SRCS += ntnameValueTest.cpp -ntnameValueTest_LIBS += nt pvData Com +TESTS += ntnameValueTest -PROD_HOST += ntmultiChannelTest +TESTPROD_HOST += ntmultiChannelTest ntmultiChannelTest_SRCS += ntmultiChannelTest.cpp -ntmultiChannelTest_LIBS += nt pvData Com +TESTS += ntmultiChannelTest TESTPROD_HOST += nttableTest nttableTest_SRCS = nttableTest.cpp TESTS += nttableTest -TESTPROD_HOST += ntmultiChannelTest -ntmultiChannelTest_SRCS = ntmultiChannelTest.cpp -TESTS += ntmultiChannelTest - TESTSCRIPTS_HOST += $(TESTS:%=%.t) include $(TOP)/configure/RULES diff --git a/test/nt/ntscalarTest.cpp b/test/nt/ntscalarTest.cpp new file mode 100644 index 0000000..ad88f14 --- /dev/null +++ b/test/nt/ntscalarTest.cpp @@ -0,0 +1,196 @@ +/** + * 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. + */ + +#include +#include + +#include + +using namespace epics::nt; +using namespace epics::pvData; +using std::tr1::dynamic_pointer_cast; + +void test_builder() +{ + testDiag("test_builder"); + + NTScalarBuilderPtr builder = NTScalar::createBuilder(); + testOk(builder.get() != 0, "Got builder"); + + StructureConstPtr structure = builder-> + value(pvDouble)-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addDisplay()-> + addControl()-> + createStructure(); + testOk1(structure.get() != 0); + if (!structure) + return; + + testOk1(NTScalar::is_a(structure)); + testOk1(structure->getID() == NTScalar::URI); + testOk1(structure->getNumberFields() == 6); + testOk1(structure->getField("value").get() != 0); + testOk1(structure->getField("descriptor").get() != 0); + testOk1(structure->getField("alarm").get() != 0); + testOk1(structure->getField("timeStamp").get() != 0); + testOk1(structure->getField("display").get() != 0); + testOk1(structure->getField("control").get() != 0); + + testOk(dynamic_pointer_cast(structure->getField("value")).get() != 0 && + dynamic_pointer_cast(structure->getField("value"))->getScalarType() == pvDouble, "value type"); + + std::cout << *structure << std::endl; + + // no value set + try + { + structure = builder-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addDisplay()-> + addControl()-> + createStructure(); + testFail("no value type set"); + } catch (std::runtime_error &) { + testPass("no value type set"); + } +} + +void test_ntscalar() +{ + testDiag("test_ntscalar"); + + NTScalarBuilderPtr builder = NTScalar::createBuilder(); + testOk(builder.get() != 0, "Got builder"); + + NTScalarPtr ntScalar = builder-> + value(pvInt)-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addDisplay()-> + addControl()-> + create(); + testOk1(ntScalar.get() != 0); + + testOk1(ntScalar->getPVStructure().get() != 0); + testOk1(ntScalar->getValue().get() != 0); + testOk1(ntScalar->getDescriptor().get() != 0); + testOk1(ntScalar->getAlarm().get() != 0); + testOk1(ntScalar->getTimeStamp().get() != 0); + testOk1(ntScalar->getDisplay().get() != 0); + testOk1(ntScalar->getControl().get() != 0); + + // + // example how to set a value + // + ntScalar->getValue()->put(12); + + // + // example how to get a value + // + int32 value = ntScalar->getValue()->get(); + testOk1(value == 12); + + // + // timeStamp ops + // + PVTimeStamp pvTimeStamp; + if (ntScalar->attachTimeStamp(pvTimeStamp)) + { + testPass("timeStamp attach"); + + // example how to set current time + TimeStamp ts; + ts.getCurrent(); + pvTimeStamp.set(ts); + + // example how to get EPICS time + TimeStamp ts2; + pvTimeStamp.get(ts2); + testOk1(ts2.getEpicsSecondsPastEpoch() != 0); + } + else + testFail("timeStamp attach fail"); + + // + // alarm ops + // + PVAlarm pvAlarm; + if (ntScalar->attachAlarm(pvAlarm)) + { + testPass("alarm attach"); + + // example how to set an alarm + Alarm alarm; + alarm.setStatus(deviceStatus); + alarm.setSeverity(minorAlarm); + alarm.setMessage("simulation alarm"); + pvAlarm.set(alarm); + } + else + testFail("alarm attach fail"); + + // + // display ops + // + PVDisplay pvDisplay; + if (ntScalar->attachDisplay(pvDisplay)) + { + testPass("display attach"); + + // example how to set an display + Display display; + display.setLow(-15); + display.setHigh(15); + display.setDescription("This is a test scalar"); + display.setFormat("%d"); + display.setUnits("A"); + pvDisplay.set(display); + } + else + testFail("display attach fail"); + + // + // control ops + // + PVControl pvControl; + if (ntScalar->attachControl(pvControl)) + { + testPass("control attach"); + + // example how to set an control + Control control; + control.setLow(-10); + control.setHigh(10); + control.setMinStep(1); + pvControl.set(control); + } + else + testFail("control attach fail"); + + // + // set descriptor + // + ntScalar->getDescriptor()->put("This is a test NTScalar"); + + // dump ntScalar + std::cout << *ntScalar->getPVStructure() << std::endl; + +} + +MAIN(testNTScalar) { + testPlan(28); + test_builder(); + test_ntscalar(); + return testDone(); +} + +