diff --git a/src/nt/ntnameValue.cpp b/src/nt/ntnameValue.cpp index 4c2bb6e..4ba4533 100644 --- a/src/nt/ntnameValue.cpp +++ b/src/nt/ntnameValue.cpp @@ -7,104 +7,157 @@ #include -namespace epics { namespace pvData { +using namespace std; +using namespace epics::pvData; -using std::tr1::static_pointer_cast; +namespace epics { namespace nt { -bool NTNameValue::isNTNameValue(PVStructurePtr const & pvStructure) +namespace detail { + +static NTFieldPtr ntField = NTField::get(); + +NTNameValueBuilder::shared_pointer NTNameValueBuilder::value( + epics::pvData::ScalarType scalarType + ) { - PVFieldPtr pvField = pvStructure->getSubField("names"); - if(pvField.get()==NULL) return false; - FieldConstPtr field = pvField->getField(); - if(field->getType()!=scalarArray) return false; - ScalarArrayConstPtr pscalarArray = - static_pointer_cast(field); - if(pscalarArray->getElementType()!=pvString) return false; - pvField = pvStructure->getSubField("values"); - if(pvField==0) return false; - field = pvField->getField(); - if(field->getType()!=scalarArray) return false; - pscalarArray = static_pointer_cast(field); - if(pscalarArray->getElementType()!=pvString) return false; - return true; + valueType = scalarType; + valueTypeSet = true; + + return shared_from_this(); } -NTNameValuePtr NTNameValue::create( - bool hasFunction,bool hasTimeStamp, bool hasAlarm) +StructureConstPtr NTNameValueBuilder::createStructure() { - StandardFieldPtr standardField = getStandardField(); - size_t nfields = 2; - if(hasFunction) nfields++; - if(hasTimeStamp) nfields++; - if(hasAlarm) nfields++; - FieldCreatePtr fieldCreate = getFieldCreate(); - PVDataCreatePtr pvDataCreate = getPVDataCreate(); - FieldConstPtrArray fields; - StringArray names; - fields.resize(nfields); - names.resize(nfields); - names[0] = "names"; - fields[0] = fieldCreate->createScalarArray(pvString); - names[1] = "values"; - fields[1] = fieldCreate->createScalarArray(pvString); - size_t ind = 2; - if(hasFunction) { - names[ind] = "function"; - fields[ind++] = fieldCreate->createScalar(pvString); - } - if(hasTimeStamp) { - names[ind] = "timeStamp"; - fields[ind++] = standardField->timeStamp(); - } - if(hasAlarm) { - names[ind] = "alarm"; - fields[ind++] = standardField->alarm(); - } - StructureConstPtr st = fieldCreate->createStructure(names,fields); - PVStructurePtr pvStructure = pvDataCreate->createPVStructure(st); - return NTNameValuePtr(new NTNameValue(pvStructure)); + if (!valueTypeSet) + throw std::runtime_error("value type not set"); + + FieldBuilderPtr builder = + getFieldCreate()->createFieldBuilder()-> + setId(NTNameValue::URI)-> + addArray("names", pvString)-> + addArray("values", valueType); + + if (descriptor) + builder->add("descriptor", pvString); + + if (alarm) + builder->add("alarm", ntField->createAlarm()); + + if (timeStamp) + builder->add("timeStamp", ntField->createTimeStamp()); + + StructureConstPtr s = builder->createStructure(); + + reset(); + return s; } -NTNameValuePtr NTNameValue::create( - PVStructurePtr const & pvStructure) +NTNameValueBuilder::shared_pointer NTNameValueBuilder::addDescriptor() { - return NTNameValuePtr(new NTNameValue(pvStructure)); + descriptor = true; + return shared_from_this(); } -NTNameValue::NTNameValue(PVStructure::shared_pointer const & pvStructure) -: pvNTNameValue(pvStructure) +NTNameValueBuilder::shared_pointer NTNameValueBuilder::addAlarm() { - NTFieldPtr ntfield = NTField::get(); - PVScalarArrayPtr pvArray = - pvStructure->getScalarArrayField("names",pvString); - pvNames = static_pointer_cast(pvArray); - pvArray = pvStructure->getScalarArrayField("values",pvString); - pvValues = static_pointer_cast(pvArray); - PVFieldPtr pvField = pvStructure->getSubField("function"); - if(pvField.get()!=NULL) { - pvFunction = pvStructure->getStringField("function"); - } - pvField = pvStructure->getSubField("timeStamp"); - if(pvField.get()!=NULL && ntfield->isTimeStamp(pvField->getField())) { - pvTimeStamp = static_pointer_cast(pvField); - } - pvField = pvStructure->getSubField("alarm"); - if(pvField.get()!=NULL && ntfield->isAlarm(pvField->getField())) { - pvAlarm = static_pointer_cast(pvField); - } + alarm = true; + return shared_from_this(); } - -void NTNameValue::attachTimeStamp(PVTimeStamp &pv) +NTNameValueBuilder::shared_pointer NTNameValueBuilder::addTimeStamp() { - if(pvTimeStamp.get()==NULL) return; - pv.attach(pvTimeStamp); + timeStamp = true; + return shared_from_this(); } -void NTNameValue::attachAlarm(PVAlarm &pv) +PVStructurePtr NTNameValueBuilder::createPVStructure() { - if(pvAlarm.get()==NULL) return; - pv.attach(pvAlarm); + return getPVDataCreate()->createPVStructure(createStructure()); } +NTNameValuePtr NTNameValueBuilder::create() +{ + return NTNameValuePtr(new NTNameValue(createPVStructure())); +} + +NTNameValueBuilder::NTNameValueBuilder() +{ + reset(); +} + +void NTNameValueBuilder::reset() +{ + valueTypeSet = false; + descriptor = false; + alarm = false; + timeStamp = false; +} + +} + +const std::string NTNameValue::URI("uri:ev4:nt/2012/pwd:NTNameValue"); + +bool NTNameValue::is_a(StructureConstPtr const & structure) +{ + return structure->getID() == URI; +} + +NTNameValueBuilderPtr NTNameValue::createBuilder() +{ + return NTNameValueBuilderPtr(new detail::NTNameValueBuilder()); +} + +bool NTNameValue::attachTimeStamp(PVTimeStamp &pvTimeStamp) const +{ + PVStructurePtr ts = getTimeStamp(); + if (ts) + return pvTimeStamp.attach(ts); + else + return false; +} + +bool NTNameValue::attachAlarm(PVAlarm &pvAlarm) const +{ + PVStructurePtr al = getAlarm(); + if (al) + return pvAlarm.attach(al); + else + return false; +} + +PVStructurePtr NTNameValue::getPVStructure() const +{ + return pvNTNameValue; +} + +PVStringPtr NTNameValue::getDescriptor() const +{ + return pvNTNameValue->getSubField("descriptor"); +} + +PVStructurePtr NTNameValue::getTimeStamp() const +{ + return pvNTNameValue->getSubField("timeStamp"); +} + +PVStructurePtr NTNameValue::getAlarm() const +{ + return pvNTNameValue->getSubField("alarm"); +} + +PVStringArrayPtr NTNameValue::getNames() const +{ + return pvNTNameValue->getSubField("names"); +} + +PVFieldPtr NTNameValue::getValues() const +{ + return pvNTNameValue->getSubField("values"); +} + +NTNameValue::NTNameValue(PVStructurePtr const & pvStructure) : + pvNTNameValue(pvStructure) +{} + + }} diff --git a/src/nt/ntnameValue.h b/src/nt/ntnameValue.h index 790292d..107c6d2 100644 --- a/src/nt/ntnameValue.h +++ b/src/nt/ntnameValue.h @@ -9,92 +9,191 @@ #include -namespace epics { namespace pvData { - -/** - * Convenience Class for NTNameValue - * @author mrk - * - */ +namespace epics { namespace nt { class NTNameValue; typedef std::tr1::shared_ptr NTNameValuePtr; -class NTNameValue +namespace detail { + + /** + * Interface for in-line creating of NTNameValue. + * 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 NTNameValueBuilder : + public std::tr1::enable_shared_from_this + { + public: + POINTER_DEFINITIONS(NTNameValueBuilder); + + /** + * Set a value array {@code Scalar} type. + * @param scalarType value array scalar array. + * @return this instance of a {@code NTTableBuilder}. + */ + shared_pointer value(epics::pvData::ScalarType scalarType); + + /** + * Add descriptor field to the NTNameValue. + * @return this instance of a {@code NTNameValueBuilder}. + */ + shared_pointer addDescriptor(); + + /** + * Add alarm structure to the NTNameValue. + * @return this instance of a {@code NTNameValueBuilder}. + */ + shared_pointer addAlarm(); + + /** + * Add timeStamp structure to the NTNameValue. + * @return this instance of a {@code NTNameValueBuilder}. + */ + shared_pointer addTimeStamp(); + + /** + * Create a {@code Structure} that represents NTNameValue. + * 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 NTNameValue. + * 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 NTNameValue} instance. + * This resets this instance state and allows new {@code instance to be created. + * @return a new instance of a {@code NTNameValue} + */ + NTNameValuePtr create(); + + private: + NTNameValueBuilder(); + + void reset(); + + bool valueTypeSet; + epics::pvData::ScalarType valueType; + + bool descriptor; + bool alarm; + bool timeStamp; + + friend class ::epics::nt::NTNameValue; + }; + +} + +typedef std::tr1::shared_ptr NTNameValueBuilderPtr; + + + +/** + * Convenience Class for NTNameValue + * @author mrk + */ +class NTNameValue { public: POINTER_DEFINITIONS(NTNameValue); + + static const std::string URI; + /** - * Is the pvStructure an NTNameValue. - * @param pvStructure The pvStructure to test. + * Is the structure an NTNameValue. + * @param structure The structure to test. * @return (false,true) if (is not, is) an NTNameValue. */ - static bool isNTNameValue(PVStructurePtr const & pvStructure); + static bool is_a(epics::pvData::StructureConstPtr const & structure); + /** - * Create an NTNameValue pvStructure. - * @param hasFunction Create a PVString field named function. - * @param hasTimeStamp Create a timeStamp structure field. - * @param hasAlarm Create an alarm structure field. - * @return NTNameValuePtr + * Create a NTNameValue builder instance. + * @return builder instance. */ - static NTNameValuePtr create( - bool hasFunction,bool hasTimeStamp, bool hasAlarm); - static NTNameValuePtr create( - PVStructurePtr const & pvStructure); + static NTNameValueBuilderPtr createBuilder(); + /** - * Destructor + * Destructor. */ ~NTNameValue() {} - /** - * Get the function field. - * @return The pvString or null if no function field. - */ - PVStringPtr getFunction() {return pvFunction;} - /** - * Attach a pvTimeStamp. - * @param pvTimeStamp The pvTimeStamp that will be attached. - * Does nothing if no timeStamp - */ - void attachTimeStamp(PVTimeStamp &pvTimeStamp); + + /** + * 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 + * Does nothing if no alarm. + * @return true if the operation was successfull (i.e. this instance has a timeStamp field), otherwise false. */ - void attachAlarm(PVAlarm &pvAlarm); + bool attachAlarm(epics::pvData::PVAlarm &pvAlarm) const; + /** * Get the pvStructure. * @return PVStructurePtr. */ - PVStructurePtr getPVStructure(){return pvNTNameValue;} + 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. */ - PVStructurePtr getTimeStamp(){return pvTimeStamp;} + epics::pvData::PVStructurePtr getTimeStamp() const; + /** * Get the alarm. * @return PVStructurePtr which may be null. */ - PVStructurePtr getAlarm() {return pvAlarm;} + epics::pvData::PVStructurePtr getAlarm() const; + /** - * Get the string array on names. - * @return The array of names. + * Get the names array field. + * @return The PVStringArray for the names. */ - PVStringArrayPtr getNames() {return pvNames;} + epics::pvData::PVStringArrayPtr getNames() const; + /** - * Get the string array on values. - * @return The array of values. + * Get the value array field. + * @return The PVField for the values. */ - PVStringArrayPtr getValues() {return pvValues;} + epics::pvData::PVFieldPtr getValues() const; + + /** + * Get the value array field of a specified type (e.g. PVDoubleArray). + * @return The array for the values. + */ + template + std::tr1::shared_ptr getValues() const + { + epics::pvData::PVFieldPtr pvField = getValues(); + if (pvField.get()) + return std::tr1::dynamic_pointer_cast(pvField); + else + return std::tr1::shared_ptr(); + } + private: - NTNameValue(PVStructurePtr const & pvStructure); - PVStructurePtr pvNTNameValue; - PVStringPtr pvFunction; - PVStructurePtr pvTimeStamp; - PVStructurePtr pvAlarm; - PVStringArrayPtr pvNames; - PVStringArrayPtr pvValues; + NTNameValue(epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr pvNTNameValue; + friend class detail::NTNameValueBuilder; }; }} diff --git a/test/nt/ntnameValueTest.cpp b/test/nt/ntnameValueTest.cpp index accad8a..d167d5d 100644 --- a/test/nt/ntnameValueTest.cpp +++ b/test/nt/ntnameValueTest.cpp @@ -3,79 +3,179 @@ * EPICS pvDataCPP is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ -/* - * ntnameValueTest.cpp - * - * Created on: 2011.11 - * Author: Marty Kraimer - */ -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include #include -#include +using namespace epics::nt; using namespace epics::pvData; -using std::string; -using std::cout; -using std::endl; +using std::tr1::dynamic_pointer_cast; -static PVDataCreatePtr pvDataCreate = getPVDataCreate(); -static NTFieldPtr ntField = NTField::get(); -static PVNTFieldPtr pvntField = PVNTField::get(); - -static void test(FILE * fd) +void test_builder() { - NTNameValuePtr ntNameValue = NTNameValue::create(true,true,true); - PVStructurePtr pvStructure = ntNameValue->getPVStructure(); - cout << *pvStructure << endl; - cout << *pvStructure->getStructure() << endl; - PVStringArrayPtr names = ntNameValue->getNames(); - PVStringArrayPtr values = ntNameValue->getValues(); - size_t n = 2; - shared_vector name(n); - shared_vector value(n); - name[0] = "name 0"; - name[1] = "name 1"; - value[0] = "value 0"; - value[1] = "value 1"; - names->replace(freeze(name)); - values->replace(freeze(value)); - PVStringPtr function = ntNameValue->getFunction(); - function->put("test"); - PVAlarm pvAlarm; - ntNameValue->attachAlarm(pvAlarm); - Alarm alarm; - alarm.setMessage("test alarm"); - alarm.setSeverity(majorAlarm); - alarm.setStatus(clientStatus); - pvAlarm.set(alarm); - PVTimeStamp pvTimeStamp; - ntNameValue->attachTimeStamp(pvTimeStamp); - TimeStamp timeStamp(1000,1000,10); - pvTimeStamp.set(timeStamp); - cout << *pvStructure << endl; - assert(NTNameValue::isNTNameValue(pvStructure)); -} + testDiag("test_builder"); + NTNameValueBuilderPtr builder = NTNameValue::createBuilder(); + testOk(builder.get() != 0, "Got builder"); -int main(int argc,char *argv[]) -{ - char *fileName = 0; - if(argc>1) fileName = argv[1]; - FILE * fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); + StructureConstPtr structure = builder-> + value(pvDouble)-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + createStructure(); + testOk1(structure.get() != 0); + if (!structure) + return; + + testOk1(NTNameValue::is_a(structure)); + testOk1(structure->getID() == NTNameValue::URI); + testOk1(structure->getNumberFields() == 5); + testOk1(structure->getField("names").get() != 0); + testOk1(structure->getField("values").get() != 0); + testOk1(structure->getField("descriptor").get() != 0); + testOk1(structure->getField("alarm").get() != 0); + testOk1(structure->getField("timeStamp").get() != 0); + + testOk(dynamic_pointer_cast(structure->getField("values")).get() != 0 && + dynamic_pointer_cast(structure->getField("values"))->getElementType() == pvDouble, "value array element type"); + + std::cout << *structure << std::endl; + + // no value set + try + { + structure = builder-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + createStructure(); + testFail("no value type set"); + } catch (std::runtime_error &) { + testPass("no value type set"); } - test(fd); - return(0); } +void test_ntnameValue() +{ + testDiag("test_ntnameValue"); + + NTNameValueBuilderPtr builder = NTNameValue::createBuilder(); + testOk(builder.get() != 0, "Got builder"); + + NTNameValuePtr ntNameValue = builder-> + value(pvInt)-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + create(); + testOk1(ntNameValue.get() != 0); + + testOk1(ntNameValue->getPVStructure().get() != 0); + testOk1(ntNameValue->getDescriptor().get() != 0); + testOk1(ntNameValue->getAlarm().get() != 0); + testOk1(ntNameValue->getTimeStamp().get() != 0); + testOk1(ntNameValue->getNames().get() != 0); + testOk1(ntNameValue->getValues().get() != 0); + + // + // example how to set names + // + PVStringArray::svector newNames; + newNames.push_back("name1"); + newNames.push_back("name2"); + newNames.push_back("name3"); + + PVStringArrayPtr pvNamesField = ntNameValue->getNames(); + pvNamesField->replace(freeze(newNames)); + + // + // example how to get names + // + PVStringArray::const_svector names(pvNamesField->view()); + + testOk1(names.size() == 3); + testOk1(names[0] == "name1"); + testOk1(names[1] == "name2"); + testOk1(names[2] == "name3"); + + // + // example how to set values + // + PVIntArray::svector newValues; + newValues.push_back(1); + newValues.push_back(2); + newValues.push_back(8); + + PVIntArrayPtr pvValueField = ntNameValue->getValues(); + pvValueField->replace(freeze(newValues)); + + // + // example how to get column 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 (ntNameValue->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 (ntNameValue->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"); + + // + // set descriptor + // + ntNameValue->getDescriptor()->put("This is a test NTNameValue"); + + // dump NTNameValue + std::cout << *ntNameValue->getPVStructure() << std::endl; + +} + +MAIN(testNTNameValue) { + testPlan(31); + test_builder(); + test_ntnameValue(); + return testDone(); +} + + diff --git a/test/nt/nttableTest.cpp b/test/nt/nttableTest.cpp index 3680bd4..c77cce5 100644 --- a/test/nt/nttableTest.cpp +++ b/test/nt/nttableTest.cpp @@ -3,12 +3,6 @@ * EPICS pvDataCPP is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ -/* - * nttableTest.cpp - * - * Created on: 2011.11 - * Author: Marty Kraimer - */ #include #include