From 887b453bac9f2548ca2bec7425bc4ca9a3b1d149 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 25 Aug 2014 08:58:40 +0200 Subject: [PATCH] NTScalarArray added --- documentation/TODO.md | 4 + src/Makefile | 2 + src/nt/nt.h | 2 + src/nt/ntscalar.cpp | 12 -- src/nt/ntscalar.h | 8 -- src/nt/ntscalarArray.cpp | 205 +++++++++++++++++++++++++++++ src/nt/ntscalarArray.h | 235 ++++++++++++++++++++++++++++++++++ test/nt/Makefile | 4 + test/nt/ntscalarArrayTest.cpp | 206 +++++++++++++++++++++++++++++ 9 files changed, 658 insertions(+), 20 deletions(-) create mode 100644 documentation/TODO.md create mode 100644 src/nt/ntscalarArray.cpp create mode 100644 src/nt/ntscalarArray.h create mode 100644 test/nt/ntscalarArrayTest.cpp diff --git a/documentation/TODO.md b/documentation/TODO.md new file mode 100644 index 0000000..e6edb22 --- /dev/null +++ b/documentation/TODO.md @@ -0,0 +1,4 @@ +TODO +=========== + +lots of code is a copy paste, consider inheritance and templates diff --git a/src/Makefile b/src/Makefile index 22d207e..6b96e13 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,6 +8,7 @@ SRC_DIRS += $(SRC)/nt INC += nt.h INC += ntfield.h INC += ntscalar.h +INC += ntscalarArray.h INC += ntnameValue.h INC += nttable.h INC += ntmultiChannel.h @@ -15,6 +16,7 @@ INC += ntndarray.h LIBSRCS += ntfield.cpp LIBSRCS += ntscalar.cpp +LIBSRCS += ntscalarArray.cpp LIBSRCS += ntnameValue.cpp LIBSRCS += nttable.cpp LIBSRCS += ntmultiChannel.cpp diff --git a/src/nt/nt.h b/src/nt/nt.h index 296fe6b..3544cfe 100644 --- a/src/nt/nt.h +++ b/src/nt/nt.h @@ -9,9 +9,11 @@ #include #include +#include #include #include #include +#include #endif /* NT_H */ diff --git a/src/nt/ntscalar.cpp b/src/nt/ntscalar.cpp index 27eaf0e..a69cde2 100644 --- a/src/nt/ntscalar.cpp +++ b/src/nt/ntscalar.cpp @@ -20,18 +20,6 @@ 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; diff --git a/src/nt/ntscalar.h b/src/nt/ntscalar.h index a6b6f12..26145f4 100644 --- a/src/nt/ntscalar.h +++ b/src/nt/ntscalar.h @@ -37,13 +37,6 @@ namespace detail { */ 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}. @@ -100,7 +93,6 @@ namespace detail { void reset(); - bool isArray; bool valueTypeSet; epics::pvData::ScalarType valueType; diff --git a/src/nt/ntscalarArray.cpp b/src/nt/ntscalarArray.cpp new file mode 100644 index 0000000..5ceddf7 --- /dev/null +++ b/src/nt/ntscalarArray.cpp @@ -0,0 +1,205 @@ +/* ntscalarArray.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(); + +NTScalarArrayBuilder::shared_pointer NTScalarArrayBuilder::arrayValue( + epics::pvData::ScalarType elementType + ) +{ + valueType = elementType; + valueTypeSet = true; + + return shared_from_this(); +} + +StructureConstPtr NTScalarArrayBuilder::createStructure() +{ + if (!valueTypeSet) + throw std::runtime_error("value array element type not set"); + + FieldBuilderPtr builder = + getFieldCreate()->createFieldBuilder()-> + setId(NTScalarArray::URI)-> + addArray("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; +} + +NTScalarArrayBuilder::shared_pointer NTScalarArrayBuilder::addDescriptor() +{ + descriptor = true; + return shared_from_this(); +} + +NTScalarArrayBuilder::shared_pointer NTScalarArrayBuilder::addAlarm() +{ + alarm = true; + return shared_from_this(); +} + +NTScalarArrayBuilder::shared_pointer NTScalarArrayBuilder::addTimeStamp() +{ + timeStamp = true; + return shared_from_this(); +} + +NTScalarArrayBuilder::shared_pointer NTScalarArrayBuilder::addDisplay() +{ + display = true; + return shared_from_this(); +} + +NTScalarArrayBuilder::shared_pointer NTScalarArrayBuilder::addControl() +{ + control = true; + return shared_from_this(); +} + +PVStructurePtr NTScalarArrayBuilder::createPVStructure() +{ + return getPVDataCreate()->createPVStructure(createStructure()); +} + +NTScalarArrayPtr NTScalarArrayBuilder::create() +{ + return NTScalarArrayPtr(new NTScalarArray(createPVStructure())); +} + +NTScalarArrayBuilder::NTScalarArrayBuilder() +{ + reset(); +} + +void NTScalarArrayBuilder::reset() +{ + valueTypeSet = false; + descriptor = false; + alarm = false; + timeStamp = false; + display = false; + control = false; +} + +} + +const std::string NTScalarArray::URI("uri:ev4:nt/2012/pwd:NTScalarArray"); + +bool NTScalarArray::is_a(StructureConstPtr const & structure) +{ + return structure->getID() == URI; +} + +NTScalarArrayBuilderPtr NTScalarArray::createBuilder() +{ + return NTScalarArrayBuilderPtr(new detail::NTScalarArrayBuilder()); +} + +bool NTScalarArray::attachTimeStamp(PVTimeStamp &pvTimeStamp) const +{ + PVStructurePtr ts = getTimeStamp(); + if (ts) + return pvTimeStamp.attach(ts); + else + return false; +} + +bool NTScalarArray::attachAlarm(PVAlarm &pvAlarm) const +{ + PVStructurePtr al = getAlarm(); + if (al) + return pvAlarm.attach(al); + else + return false; +} + +bool NTScalarArray::attachDisplay(PVDisplay &pvDisplay) const +{ + PVStructurePtr dp = getDisplay(); + if (dp) + return pvDisplay.attach(dp); + else + return false; +} + +bool NTScalarArray::attachControl(PVControl &pvControl) const +{ + PVStructurePtr ctrl = getControl(); + if (ctrl) + return pvControl.attach(ctrl); + else + return false; +} + +PVStructurePtr NTScalarArray::getPVStructure() const +{ + return pvNTScalarArray; +} + +PVStringPtr NTScalarArray::getDescriptor() const +{ + return pvNTScalarArray->getSubField("descriptor"); +} + +PVStructurePtr NTScalarArray::getTimeStamp() const +{ + return pvNTScalarArray->getSubField("timeStamp"); +} + +PVStructurePtr NTScalarArray::getAlarm() const +{ + return pvNTScalarArray->getSubField("alarm"); +} + +PVStructurePtr NTScalarArray::getDisplay() const +{ + return pvNTScalarArray->getSubField("display"); +} + +PVStructurePtr NTScalarArray::getControl() const +{ + return pvNTScalarArray->getSubField("control"); +} + +PVFieldPtr NTScalarArray::getValue() const +{ + return pvValue; +} + +NTScalarArray::NTScalarArray(PVStructurePtr const & pvStructure) : + pvNTScalarArray(pvStructure), pvValue(pvNTScalarArray->getSubField("value")) +{} + + +}} diff --git a/src/nt/ntscalarArray.h b/src/nt/ntscalarArray.h new file mode 100644 index 0000000..df9ca95 --- /dev/null +++ b/src/nt/ntscalarArray.h @@ -0,0 +1,235 @@ +/* ntscalarArray.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 NTSCALARARRAY_H +#define NTSCALARARRAY_H + +#include +#include +#include + +namespace epics { namespace nt { + +class NTScalarArray; +typedef std::tr1::shared_ptr NTScalarArrayPtr; + +namespace detail { + + /** + * Interface for in-line creating of NTScalarArray. + * 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 NTScalarArrayBuilder : + public std::tr1::enable_shared_from_this + { + public: + POINTER_DEFINITIONS(NTScalarArrayBuilder); + + /** + * Set a value type of a NTScalarArray. + * @param elementType the value array element type. + * @return this instance of a {@code NTTableBuilder}. + */ + shared_pointer arrayValue(epics::pvData::ScalarType elementType); + + /** + * Add descriptor field to the NTScalarArray. + * @return this instance of a {@code NTScalarArrayBuilder}. + */ + shared_pointer addDescriptor(); + + /** + * Add alarm structure to the NTScalarArray. + * @return this instance of a {@code NTScalarArrayBuilder}. + */ + shared_pointer addAlarm(); + + /** + * Add timeStamp structure to the NTScalarArray. + * @return this instance of a {@code NTScalarArrayBuilder}. + */ + shared_pointer addTimeStamp(); + + /** + * Add display structure to the NTScalarArray. + * @return this instance of a {@code NTScalarArrayBuilder}. + */ + shared_pointer addDisplay(); + + /** + * Add control structure to the NTScalarArray. + * @return this instance of a {@code NTScalarArrayBuilder}. + */ + shared_pointer addControl(); + + /** + * Create a {@code Structure} that represents NTScalarArray. + * 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 NTScalarArray. + * 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 NTScalarArray} instance. + * This resets this instance state and allows new {@code instance to be created. + * @return a new instance of a {@code NTScalarArray} + */ + NTScalarArrayPtr create(); + + private: + NTScalarArrayBuilder(); + + void reset(); + + bool valueTypeSet; + epics::pvData::ScalarType valueType; + + bool descriptor; + bool alarm; + bool timeStamp; + bool display; + bool control; + + friend class ::epics::nt::NTScalarArray; + }; + +} + +typedef std::tr1::shared_ptr NTScalarArrayBuilderPtr; + + + +/** + * Convenience Class for NTScalarArray + * @author mrk + */ +class NTScalarArray +{ +public: + POINTER_DEFINITIONS(NTScalarArray); + + static const std::string URI; + + /** + * Is the structure an NTScalarArray. + * @param structure The structure to test. + * @return (false,true) if (is not, is) an NTScalarArray. + */ + static bool is_a(epics::pvData::StructureConstPtr const & structure); + + /** + * Create a NTScalarArray builder instance. + * @return builder instance. + */ + static NTScalarArrayBuilderPtr createBuilder(); + + /** + * Destructor. + */ + ~NTScalarArray() {} + + /** + * 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. PVDoubleArray). + * @return The field for the values. + */ + template + std::tr1::shared_ptr getValue() const + { + return std::tr1::dynamic_pointer_cast(pvValue); + } + +private: + NTScalarArray(epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr pvNTScalarArray; + epics::pvData::PVFieldPtr pvValue; + friend class detail::NTScalarArrayBuilder; +}; + +}} +#endif /* NTScalarArray_H */ diff --git a/test/nt/Makefile b/test/nt/Makefile index fdf08bb..c1f47ea 100644 --- a/test/nt/Makefile +++ b/test/nt/Makefile @@ -12,6 +12,10 @@ TESTPROD_HOST += ntscalarTest ntscalarTest_SRCS += ntscalarTest.cpp TESTS += ntscalarTest +TESTPROD_HOST += ntscalarArrayTest +ntscalarArrayTest_SRCS += ntscalarArrayTest.cpp +TESTS += ntscalarArrayTest + TESTPROD_HOST += ntnameValueTest ntnameValueTest_SRCS += ntnameValueTest.cpp TESTS += ntnameValueTest diff --git a/test/nt/ntscalarArrayTest.cpp b/test/nt/ntscalarArrayTest.cpp new file mode 100644 index 0000000..5903cc0 --- /dev/null +++ b/test/nt/ntscalarArrayTest.cpp @@ -0,0 +1,206 @@ +/** + * 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"); + + NTScalarArrayBuilderPtr builder = NTScalarArray::createBuilder(); + testOk(builder.get() != 0, "Got builder"); + + StructureConstPtr structure = builder-> + arrayValue(pvDouble)-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addDisplay()-> + addControl()-> + createStructure(); + testOk1(structure.get() != 0); + if (!structure) + return; + + testOk1(NTScalarArray::is_a(structure)); + testOk1(structure->getID() == NTScalarArray::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"))->getElementType() == 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_ntscalarArray() +{ + testDiag("test_ntscalarArray"); + + NTScalarArrayBuilderPtr builder = NTScalarArray::createBuilder(); + testOk(builder.get() != 0, "Got builder"); + + NTScalarArrayPtr ntScalarArray = builder-> + arrayValue(pvInt)-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addDisplay()-> + addControl()-> + create(); + testOk1(ntScalarArray.get() != 0); + + testOk1(ntScalarArray->getPVStructure().get() != 0); + testOk1(ntScalarArray->getValue().get() != 0); + testOk1(ntScalarArray->getDescriptor().get() != 0); + testOk1(ntScalarArray->getAlarm().get() != 0); + testOk1(ntScalarArray->getTimeStamp().get() != 0); + testOk1(ntScalarArray->getDisplay().get() != 0); + testOk1(ntScalarArray->getControl().get() != 0); + + // + // example how to set values + // + PVIntArray::svector newValues; + newValues.push_back(1); + newValues.push_back(2); + newValues.push_back(8); + + PVIntArrayPtr pvValueField = ntScalarArray->getValue(); + pvValueField->replace(freeze(newValues)); + + // + // example how to get values + // + PVIntArray::const_svector values(pvValueField->view()); + + testOk1(values.size() == 3); + testOk1(values[0] == 1); + testOk1(values[1] == 2); + testOk1(values[2] == 8); + + // + // timeStamp ops + // + PVTimeStamp pvTimeStamp; + if (ntScalarArray->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 (ntScalarArray->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 (ntScalarArray->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 array"); + display.setFormat("%d"); + display.setUnits("A"); + pvDisplay.set(display); + } + else + testFail("display attach fail"); + + // + // control ops + // + PVControl pvControl; + if (ntScalarArray->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 + // + ntScalarArray->getDescriptor()->put("This is a test NTScalarArray"); + + // dump ntScalarArray + std::cout << *ntScalarArray->getPVStructure() << std::endl; + +} + +MAIN(testNTScalarArray) { + testPlan(31); + test_builder(); + test_ntscalarArray(); + return testDone(); +} + +