From 702652d20faac3beeb8e0108b8dbeba9be514812 Mon Sep 17 00:00:00 2001 From: mrkraimer Date: Mon, 10 Aug 2015 05:16:45 -0400 Subject: [PATCH] NTMultiChannel support now available. --- README.md | 32 ++ README.txt | 9 - example/src/Makefile | 7 + example/src/examplePvaClientMultiDouble.cpp | 6 +- example/src/examplePvaClientNTMulti.cpp | 141 ++++++++ example/src/examplePvaClientPut.cpp | 23 ++ src/Makefile | 4 + src/PvaClientNTMultiData.cpp | 203 +++++++++++ src/pvaClientMultiChannel.cpp | 49 ++- src/pvaClientMultiChannel.h | 361 +++++++++++++++++++- src/pvaClientMultiGetDouble.cpp | 4 +- src/pvaClientMultiMonitorDouble.cpp | 4 +- src/pvaClientMultiPutDouble.cpp | 8 +- src/pvaClientNTMultiData.cpp | 232 +++++++++++++ src/pvaClientNTMultiGet.cpp | 143 ++++++++ src/pvaClientNTMultiMonitor.cpp | 155 +++++++++ src/pvaClientNTMultiPut.cpp | 149 ++++++++ 17 files changed, 1501 insertions(+), 29 deletions(-) create mode 100644 README.md delete mode 100644 README.txt create mode 100644 example/src/examplePvaClientNTMulti.cpp create mode 100644 src/PvaClientNTMultiData.cpp create mode 100644 src/pvaClientNTMultiData.cpp create mode 100644 src/pvaClientNTMultiGet.cpp create mode 100644 src/pvaClientNTMultiMonitor.cpp create mode 100644 src/pvaClientNTMultiPut.cpp diff --git a/README.md b/README.md new file mode 100644 index 0000000..12c9ff5 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +Status +=========== + +* The API should be almost ready for feature freeze for release 4.5 +* Everything defined in pvaClient.h should be ready but see below for remaining work. +* Everything defined in pvaClientMultiChannel.h is ready but see below for remaining work. + +Examples +------------ + +The examples require the database in pvaClientTestCPP. +For example: + +... +mrk> pwd +/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase +mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd +... + +pvaClientChannel +--------------- + +Channel::getField and channelArray are not supported for release 4.5. + +pvaClientMultiChannel +--------------- + +For release 4.6 support is available for multiDouble and NTMultiChannel. +In the future additional support should be provided that at least includes NTScalarMultiChannel. + +Testing with some channels not connected have not been done. +At least some testing with missing channels should be done before release 4.5 diff --git a/README.txt b/README.txt deleted file mode 100644 index 123cdc6..0000000 --- a/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -To build do the following: - -cd configure -cp ExampleRELEASE.local RELEASE.local -edit RELEASE.local -cd .. -make - -Now read documentation/pvaClientCPP.html diff --git a/example/src/Makefile b/example/src/Makefile index 4f48aaf..6654b6e 100644 --- a/example/src/Makefile +++ b/example/src/Makefile @@ -40,6 +40,13 @@ examplePvaClientMultiDouble_LIBS += pvAccess examplePvaClientMultiDouble_LIBS += pvData examplePvaClientMultiDouble_LIBS += Com +PROD_HOST += examplePvaClientNTMulti +examplePvaClientNTMulti_SRCS += examplePvaClientNTMulti.cpp +examplePvaClientNTMulti_LIBS += pvaClient +examplePvaClientNTMulti_LIBS += pvAccess +examplePvaClientNTMulti_LIBS += pvData +examplePvaClientNTMulti_LIBS += Com + PROD_HOST += helloWorldRPC helloWorldRPC_SRCS += helloWorldRPC.cpp helloWorldRPC_LIBS += pvaClient diff --git a/example/src/examplePvaClientMultiDouble.cpp b/example/src/examplePvaClientMultiDouble.cpp index 2c5b986..054024c 100644 --- a/example/src/examplePvaClientMultiDouble.cpp +++ b/example/src/examplePvaClientMultiDouble.cpp @@ -33,7 +33,7 @@ cout << "num " << num << " names " << channelNames << endl; PvaClientMultiPutDoublePtr multiPut(multiChannel->createPut()); PvaClientMultiMonitorDoublePtr multiMonitor(multiChannel->createMonitor()); shared_vector data(num,0); - for(double value = 0.0; value< 1.0; value+= .2) { + for(double value = 0.2; value< 2.3; value+= 1.0) { try { for(size_t i=0; i channelNames(num); channelNames[0] = "double01"; - channelNames[1] = "double02"; + channelNames[1] = "int01"; channelNames[2] = "double03"; channelNames[3] = "double04"; channelNames[4] = "double05"; @@ -68,7 +68,7 @@ int main(int argc,char *argv[]) example(pva,"ca",names); channelNames = shared_vector(num); channelNames[0] = "exampleDouble01"; - channelNames[1] = "exampleDouble02"; + channelNames[1] = "exampleInt"; channelNames[2] = "exampleDouble03"; channelNames[3] = "exampleDouble04"; channelNames[4] = "exampleDouble05"; diff --git a/example/src/examplePvaClientNTMulti.cpp b/example/src/examplePvaClientNTMulti.cpp new file mode 100644 index 0000000..be72505 --- /dev/null +++ b/example/src/examplePvaClientNTMulti.cpp @@ -0,0 +1,141 @@ +/*examplePvaClientNTMulti.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include + +#include +#include + +using std::tr1::static_pointer_cast; +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvaClient; + +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static ConvertPtr convert = getConvert(); + +static void setValue(PVUnionPtr const &pvUnion, double value) +{ + UnionConstPtr u = pvUnion->getUnion(); + FieldConstPtr field = u->getField(0); + Type type = field->getType(); + if(type==scalar) { + ScalarConstPtr scalar = static_pointer_cast(field); + ScalarType scalarType = scalar->getScalarType(); + if(scalarType==pvDouble) { + PVDoublePtr pvValue = static_pointer_cast( + pvDataCreate->createPVScalar(pvDouble)); + pvValue->put(value); + pvUnion->set(0,pvValue); + return; + } + if(scalarType==pvString) { + PVStringPtr pvValue = static_pointer_cast( + pvDataCreate->createPVScalar(pvString)); + stringstream ss; + ss << "value" << value; + pvValue->put(ss.str()); + pvUnion->set(0,pvValue); + return; + } + throw std::runtime_error("only pvDouble and pvString are supported"); + } + if(type==scalarArray) { + ScalarArrayConstPtr scalarArray = static_pointer_cast(field); + ScalarType scalarType = scalarArray->getElementType(); + if(scalarType==pvDouble) { + size_t num = 5; + PVDoubleArrayPtr pvValue = static_pointer_cast( + pvDataCreate->createPVScalarArray(pvDouble)); + shared_vector data(num); + for(size_t i=0; ireplace(freeze(data)); + pvUnion->set(0,pvValue); + return; + } + if(scalarType==pvString) { + size_t num = 5; + PVStringArrayPtr pvValue = static_pointer_cast( + pvDataCreate->createPVScalarArray(pvString)); + shared_vector data(num); + for(size_t i=0; ireplace(freeze(data)); + pvUnion->set(0,pvValue); + return; + } + throw std::runtime_error("only pvDouble and pvString are supported"); + } + throw std::runtime_error("only scalar and scalarArray fields are supported"); +} + +static void example( + PvaClientPtr const &pva, + string provider, + shared_vector const &channelNames) +{ + + size_t num = channelNames.size(); + PvaClientMultiChannelPtr multiChannel( + PvaClientMultiChannel::create(pva,channelNames,provider)); + PvaClientNTMultiGetPtr multiGet(multiChannel->createNTGet()); + PvaClientNTMultiPutPtr multiPut(multiChannel->createNTPut()); + PvaClientNTMultiMonitorPtr multiMonitor(multiChannel->createNTMonitor()); + shared_vector data = multiPut->getValues(); + for(double value = 0.0; value< 2.1; value+= 1.0) { + for(size_t i=0; iput(); + multiGet->get(); + PvaClientNTMultiDataPtr multiData = multiGet->getData(); + PVStructurePtr pvStructure = multiData->getPVTop(); + cout << "pvStructure\n" << pvStructure << endl; + bool result = multiMonitor->waitEvent(.1); + while(result) { + multiData = multiMonitor->getData(); + pvStructure = multiData->getPVTop(); + cout << "monitor pvStructure\n" << pvStructure << endl; + result = multiMonitor->poll(); + } + } +} + +int main(int argc,char *argv[]) +{ + PvaClientPtr pva = PvaClient::create(); + size_t num = 4; + shared_vector channelNames(num); + channelNames[0] = "double01"; + channelNames[1] = "string01"; + channelNames[2] = "doubleArray01"; + channelNames[3] = "stringArray01"; + cout << "dbRecord pva\n"; + shared_vector names(freeze(channelNames)); + example(pva,"pva",names); + cout << "dbRecord ca\n"; + example(pva,"ca",names); + channelNames = shared_vector(num); + channelNames[0] = "exampleDouble"; + channelNames[1] = "exampleString"; + channelNames[2] = "exampleDoubleArray"; + channelNames[3] = "exampleStringArray"; + names = freeze(channelNames); + cout << "pvRecord pva\n"; + example(pva,"pva",names); + return 0; +} diff --git a/example/src/examplePvaClientPut.cpp b/example/src/examplePvaClientPut.cpp index c6202be..dfa3559 100644 --- a/example/src/examplePvaClientPut.cpp +++ b/example/src/examplePvaClientPut.cpp @@ -13,12 +13,16 @@ #include #include +#include +using std::tr1::static_pointer_cast; using namespace std; using namespace epics::pvData; using namespace epics::pvAccess; using namespace epics::pvaClient; +static ConvertPtr convert = getConvert(); + static void examplePut(PvaClientPtr const &pva) { @@ -45,10 +49,29 @@ static void examplePut(PvaClientPtr const &pva) } } +static void examplePVFieldPut(PvaClientPtr const &pva) +{ + cout << "example put\n"; + PvaClientChannelPtr channel = pva->channel("exampleDouble"); + PvaClientPutPtr put = channel->put(); + PvaClientPutDataPtr putData = put->getData(); + PVFieldPtr pvField = putData->getValue(); + PVScalarPtr pvScalar = static_pointer_cast(pvField); + try { + convert->fromDouble(pvScalar,1.0); put->put(); + cout << channel->get("field()")->getData()->showChanged(cout) << endl; + convert->fromDouble(pvScalar,2.0); put->put(); + cout << channel->get("field()")->getData()->showChanged(cout) << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } +} + int main(int argc,char *argv[]) { PvaClientPtr pva = PvaClient::create(); examplePut(pva); + examplePVFieldPut(pva); return 0; } diff --git a/src/Makefile b/src/Makefile index 8a23f7a..5a278f5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -22,6 +22,10 @@ LIBSRCS += pvaClientMultiChannel.cpp LIBSRCS += pvaClientMultiGetDouble.cpp LIBSRCS += pvaClientMultiPutDouble.cpp LIBSRCS += pvaClientMultiMonitorDouble.cpp +LIBSRCS += pvaClientNTMultiPut.cpp +LIBSRCS += pvaClientNTMultiData.cpp +LIBSRCS += pvaClientNTMultiGet.cpp +LIBSRCS += pvaClientNTMultiMonitor.cpp pvaClient_LIBS += pvAccess pvData nt Com pvaClient_LIBS += $(EPICS_BASE_IOC_LIBS) diff --git a/src/PvaClientNTMultiData.cpp b/src/PvaClientNTMultiData.cpp new file mode 100644 index 0000000..9f3fbd8 --- /dev/null +++ b/src/PvaClientNTMultiData.cpp @@ -0,0 +1,203 @@ +/* pvaClientNTMultiData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ + +#define epicsExportSharedSymbols +#include +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::nt; +using namespace std; + +namespace epics { namespace pvaClient { + +static ConvertPtr convert = getConvert(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static StandardFieldPtr standardField = getStandardField(); + + +PvaClientNTMultiDataPtr PvaClientNTMultiData::create( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + PVStructurePtr const & pvRequest) +{ + PvaClientNTMultiDataPtr pvaClientNTMultiData( + new PvaClientNTMultiData(u,pvaMultiChannel,pvaClientChannelArray,pvRequest)); + return pvaClientNTMultiData; +} + +PvaClientNTMultiData::PvaClientNTMultiData( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + pvRequest(pvRequest), + u(u), + nchannel(pvaClientChannelArray.size()), + gotAlarm(false), + gotTimeStamp(false), + isDestroyed(false) +{ + PVFieldPtr pvValue = pvRequest->getSubField("field.value"); + if(!pvValue) { + throw std::runtime_error("pvRequest did not specify value"); + } + topPVStructure.resize(nchannel); + for(size_t i=0; i< nchannel; ++i) topPVStructure[i] = PVStructurePtr(); + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + builder->value(u); + if(pvRequest->getSubField("field.alarm")) + { + gotAlarm = true; + builder->addAlarm(); + severity.resize(nchannel); + status.resize(nchannel); + message.resize(nchannel); + + } + if(pvRequest->getSubField("field.timeStamp")) { + gotTimeStamp = true; + builder->addTimeStamp(); + secondsPastEpoch.resize(nchannel); + nanoseconds.resize(nchannel); + userTag.resize(nchannel); + } + ntMultiChannel = builder->create(); +} + + +PvaClientNTMultiData::~PvaClientNTMultiData() +{ + destroy(); +} + +void PvaClientNTMultiData::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientNTMultiData::setStructure(StructureConstPtr const & structure,size_t index) +{ + FieldConstPtr field = structure->getField("value"); + if(!field) { + string message = "channel " + + pvaClientChannelArray[index]->getChannel()->getChannelName() + + " does not have top level value field"; + throw std::runtime_error(message); + } +} + +void PvaClientNTMultiData::setPVStructure( + PVStructurePtr const &pvStructure,size_t index) +{ + topPVStructure[index] = pvStructure; +} + + +size_t PvaClientNTMultiData::getNumber() +{ + return nchannel; +} + +void PvaClientNTMultiData::startDeltaTime() +{ + for(size_t i=0; iset(pvst->getSubField("value")); + } + if(gotAlarm) + { + severity[i] = pvst->getSubField("alarm.severity")->get(); + status[i] = pvst->getSubField("alarm.status")->get(); + message[i] = pvst->getSubField("alarm.message")->get(); + } + if(gotTimeStamp) + { + secondsPastEpoch[i] = pvst->getSubField("timeStamp.secondsPastEpoch")->get(); + nanoseconds[i] = pvst->getSubField("timeStamp.nanoseconds")->get(); + userTag[i] = pvst->getSubField("timeStamp.userTag")->get(); + } + + } + ntMultiChannel->getValue()->replace(freeze(unionValue)); + if(gotAlarm) + { + ntMultiChannel->getSeverity()->replace(freeze(severity)); + ntMultiChannel->getStatus()->replace(freeze(status)); + ntMultiChannel->getMessage()->replace(freeze(message)); + } + if(gotTimeStamp) + { + ntMultiChannel->getSecondsPastEpoch()->replace(freeze(secondsPastEpoch)); + ntMultiChannel->getNanoseconds()->replace(freeze(nanoseconds)); + ntMultiChannel->getUserTag()->replace(freeze(userTag)); + } +} + +TimeStamp PvaClientNTMultiData::getTimeStamp() +{ + pvTimeStamp.get(timeStamp); + return timeStamp; +} + +NTMultiChannelPtr PvaClientNTMultiData::getNTMultiChannel() +{ + return ntMultiChannel; +} + +PVStructurePtr PvaClientNTMultiData::getPVTop() +{ + return ntMultiChannel->getPVStructure(); +} + +}} diff --git a/src/pvaClientMultiChannel.cpp b/src/pvaClientMultiChannel.cpp index 3e3f2e7..228dc37 100644 --- a/src/pvaClientMultiChannel.cpp +++ b/src/pvaClientMultiChannel.cpp @@ -15,7 +15,7 @@ #include #include #include -#include + using std::tr1::static_pointer_cast; @@ -52,7 +52,8 @@ PvaClientMultiChannel::PvaClientMultiChannel( numChannel(channelName.size()), numConnected(0), pvaClientChannelArray(PvaClientChannelArray(numChannel,PvaClientChannelPtr())), - isConnected(shared_vector(numChannel,false)), + isConnected(shared_vector(numChannel,false)), + createRequest(CreateRequest::create()), isDestroyed(false) { } @@ -131,7 +132,7 @@ bool PvaClientMultiChannel::connectionChange() return false; } -epics::pvData::shared_vector PvaClientMultiChannel::getIsConnected() +epics::pvData::shared_vector PvaClientMultiChannel::getIsConnected() { if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); for(size_t i=0; icreateRequest(request); + if(!pvRequest) { + stringstream ss; + ss << " PvaClientMultiChannel::createNTGet invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return PvaClientNTMultiGet::create(getPtrSelf(), pvaClientChannelArray,pvRequest); +} + + +PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor() +{ + return createNTMonitor("value,alarm,timeStamp"); +} + +PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor(std::string const &request) +{ + checkConnected(); + PVStructurePtr pvRequest = createRequest->createRequest(request); + if(!pvRequest) { + stringstream ss; + ss << " PvaClientMultiChannel::createNTMonitor invalid pvRequest: " + createRequest->getMessage(); + throw std::runtime_error(ss.str()); + } + return PvaClientNTMultiMonitor::create(getPtrSelf(), pvaClientChannelArray,pvRequest); +} + }} diff --git a/src/pvaClientMultiChannel.h b/src/pvaClientMultiChannel.h index ff6c167..86ae925 100644 --- a/src/pvaClientMultiChannel.h +++ b/src/pvaClientMultiChannel.h @@ -1,4 +1,4 @@ -/* pvaClient.h */ +/* pvaClientMultiChannel.h */ /** * Copyright - See the COPYRIGHT that is included with this distribution. * EPICS pvData is distributed subject to a Software License Agreement found @@ -18,6 +18,7 @@ #include #include +#include namespace epics { namespace pvaClient { @@ -32,11 +33,20 @@ typedef std::tr1::shared_ptr PvaClientMultiPutDoublePtr class PvaClientMultiMonitorDouble; typedef std::tr1::shared_ptr PvaClientMultiMonitorDoublePtr; +class PvaClientNTMultiGet; +typedef std::tr1::shared_ptr PvaClientNTMultiGetPtr; +class PvaClientNTMultiPut; +typedef std::tr1::shared_ptr PvaClientNTMultiPutPtr; +class PvaClientNTMultiMonitor; +typedef std::tr1::shared_ptr PvaClientNTMultiMonitorPtr; +class PvaClientNTMultiData; +typedef std::tr1::shared_ptr PvaClientNTMultiDataPtr; + typedef epics::pvData::shared_vector PvaClientChannelArray; /** - * Provides access to multiple channels. + * @brief PvaMultiChannel is a synchronous interface for accessing multiple channels. * * @author mrk */ @@ -58,9 +68,11 @@ public: std::string const & providerName = "pva", size_t maxNotConnected=0 ); - + /** + * Destructor + */ ~PvaClientMultiChannel(); - /** Destroy the pvAccess connection. + /** Destroy the pvAccess connections. */ void destroy(); /** Get the channelNames. @@ -85,7 +97,7 @@ public: /** Get the connection state of each channel. * @return The state of each channel. */ - epics::pvData::shared_vector getIsConnected(); + epics::pvData::shared_vector getIsConnected(); /** Get the pvaClientChannelArray. * @return The shared pointer. */ @@ -109,6 +121,35 @@ public: * @return The interface. */ PvaClientMultiMonitorDoublePtr createMonitor(); + /** + * Create a pvaClientNTMultiPut. + * @return The interface. + */ + PvaClientNTMultiPutPtr createNTPut(); + /** + * Create a pvaClientNTMultiGet. + * This calls the next method with request = "value,alarm,timeStamp" + * @return The interface. + */ + PvaClientNTMultiGetPtr createNTGet(); + /** + * Create a pvaClientNTMultiGet; + * @param request The request for each channel. + * @return The interface. + */ + PvaClientNTMultiGetPtr createNTGet(std::string const &request); + /** + * Create a pvaClientNTMultiMonitor. + * This calls the next method with request = "value,alarm,timeStamp" + * @return The interface. + */ + PvaClientNTMultiMonitorPtr createNTMonitor(); + /** + * Create a pvaClientNTMultiPut. + * @param request The request for each channel. + * @return The interface. + */ + PvaClientNTMultiMonitorPtr createNTMonitor(std::string const &request); /** Get the shared pointer to self. * @return The shared pointer. */ @@ -135,8 +176,10 @@ private: size_t numConnected; PvaClientChannelArray pvaClientChannelArray; - epics::pvData::shared_vector isConnected; + epics::pvData::shared_vector isConnected; + epics::pvData::CreateRequest::shared_pointer createRequest; bool isDestroyed; + }; /** @@ -319,6 +362,312 @@ private: bool isDestroyed; }; +/** + * This provides channelGet to multiple channels where the value field of each channel is presented as a union. + */ +class epicsShareClass PvaClientNTMultiGet : + public std::tr1::enable_shared_from_this +{ + +public: + POINTER_DEFINITIONS(PvaClientNTMultiGet); + /** + * Factory method that creates a PvaClientNTMultiGet. + * @param pvaClientMultiChannel The interface to PvaClientMultiChannel. + * @param pvaClientChannelArray The PvaClientChannel array. + * @param pvRequest The pvRequest for each channel. + * @return The interface. + */ + static PvaClientNTMultiGetPtr create( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest); + + ~PvaClientNTMultiGet(); + + /** Destroy the pvAccess connection. + */ + void destroy(); + /** + * Create a channelGet for each channel. + */ + void connect(); + /** + * get data for each channel. + */ + void get(); + /** + * get the data. + * @return the pvaClientNTMultiData. + */ + PvaClientNTMultiDataPtr getData(); + /** Get the shared pointer to self. + * @return The shared pointer. + */ + PvaClientNTMultiGetPtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaClientNTMultiGet( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest); + + PvaClientMultiChannelPtr pvaClientMultiChannel; + PvaClientChannelArray pvaClientChannelArray; + size_t nchannel; + epics::pvData::Mutex mutex; + + epics::pvData::PVStructurePtr pvRequest; + PvaClientNTMultiDataPtr pvaClientNTMultiData; + std::vector pvaClientGet; + bool isConnected; + bool isDestroyed; +}; + +/** + * This provides channelPut to multiple channels where the value field of each channel is presented as a union. + */ +class epicsShareClass PvaClientNTMultiPut : + public std::tr1::enable_shared_from_this +{ + +public: + POINTER_DEFINITIONS(PvaClientNTMultiPut); + /** + * Factory method that creates a PvaClientNTMultiPut. + * @param pvaClientMultiChannel The interface to PvaClientMultiChannel. + * @param pvaClientChannelArray The PvaClientChannel array. + * @return The interface. + */ + static PvaClientNTMultiPutPtr create( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + ~PvaClientNTMultiPut(); + + /** Destroy the pvAccess connection. + */ + void destroy(); + /** + * Create a channelPut for each channel. + */ + void connect(); + /** + * get the value field of each channel as a union. + * @return A shared vector of union. + */ + epics::pvData::shared_vector getValues(); + /** + * put the data to each channel. +' */ + void put(); + /** Get the shared pointer to self. + * @return The shared pointer. + */ + PvaClientNTMultiPutPtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaClientNTMultiPut( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + + PvaClientMultiChannelPtr pvaClientMultiChannel; + PvaClientChannelArray pvaClientChannelArray; + size_t nchannel; + epics::pvData::Mutex mutex; + + epics::pvData::shared_vector unionValue; + epics::pvData::shared_vector value; + std::vector pvaClientPut; + bool isConnected; + bool isDestroyed; +}; + +/** + * This provides channel monitor to multiple channels where the value field of each channel is presented as a union. + */ +class epicsShareClass PvaClientNTMultiMonitor : + public std::tr1::enable_shared_from_this +{ + +public: + POINTER_DEFINITIONS(PvaClientNTMultiMonitor); + /** + * Factory method that creates a PvaClientNTMultiMonitor. + * @param pvaClientMultiChannel The interface to PvaClientMultiChannel. + * @param pvaClientChannelArray The PvaClientChannel array. + * @param pvRequest The pvRequest for each channel. + * @return The interface. + */ + static PvaClientNTMultiMonitorPtr create( + PvaClientMultiChannelPtr const &pvaNTMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest); + ~PvaClientNTMultiMonitor(); + + /** Destroy the pvAccess connection. + */ + void destroy(); + /** + * Create a channel monitor for each channel. + */ + void connect(); + /** + * poll each channel. + * If any has new data it is used to update the double[]. + * @return (false,true) if (no, at least one) value was updated. + */ + bool poll(); + /** + * Wait until poll returns true. + * @param waitForEvent The time to keep trying. + * A thread sleep of .1 seconds occurs between each call to poll. + * @return (false,true) if (timeOut, poll returned true). + */ + bool waitEvent(double waitForEvent); + /** + * get the data. + * @return the pvaClientNTMultiData. + */ + PvaClientNTMultiDataPtr getData(); + /** Monitor the shared pointer to self. + * @return The shared pointer. + */ + PvaClientNTMultiMonitorPtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaClientNTMultiMonitor( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest); + + PvaClientMultiChannelPtr pvaClientMultiChannel; + PvaClientChannelArray pvaClientChannelArray; + size_t nchannel; + epics::pvData::Mutex mutex; + + epics::pvData::PVStructurePtr pvRequest; + PvaClientNTMultiDataPtr pvaClientNTMultiData; + std::vector pvaClientMonitor; + bool isConnected; + bool isDestroyed; +}; + +/** + * This provides NTMultiChannel data for both PvaClientNTMultiGet and PvaClientNTMultiMonitor. + */ +class epicsShareClass PvaClientNTMultiData : + public std::tr1::enable_shared_from_this +{ + +public: + POINTER_DEFINITIONS(PvaClientNTMultiData); + /** + * Factory method that creates a PvaClientNTMultiData. + * Normally only called by PvaClientNTMultiGet and PvaClientNTMultiMonitor. + * @param u The union interface for the value field of each channel. + * @param pvaClientMultiChannel The interface to PvaClientMultiChannel. + * @param pvaClientChannelArray The PvaClientChannel array. + * @param pvRequest The pvRequest for each channel. + */ + static PvaClientNTMultiDataPtr create( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaNTMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest); + ~PvaClientNTMultiData(); + /** Destroy the pvAccess connection. + */ + void destroy(); + + /** + * Get the number of channels. + * @return The number of channels. + */ + size_t getNumber(); + + /** + * Set the timeStamp base for computing deltaTimes. + */ + void startDeltaTime(); + + /** + * Update NTMultiChannel fields. + */ + void endDeltaTime(); + /** + * Get the time when the last get was made. + * @return The timeStamp. + */ + epics::pvData::TimeStamp getTimeStamp(); + /** + * Get the NTMultiChannel. + * @return The value. + */ + epics::nt::NTMultiChannelPtr getNTMultiChannel(); + + /** + * Get the top level structure. + * @return The top level structure. + */ + epics::pvData::PVStructurePtr getPVTop(); + /** Get the shared pointer to self. + * @return The shared pointer. + */ + PvaClientNTMultiDataPtr getPtrSelf() + { + return shared_from_this(); + } + +private: + PvaClientNTMultiData( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaNTMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest); + static epics::pvData::PVStructurePtr createRequest(std::string const & request); + void setStructure(epics::pvData::StructureConstPtr const & structure,size_t index); + void setPVStructure( + epics::pvData::PVStructurePtr const &pvStructure,size_t index); + + PvaClientMultiChannelPtr pvaClientMultiChannel; + PvaClientChannelArray pvaClientChannelArray; + epics::pvData::PVStructurePtr pvRequest; + epics::pvData::UnionConstPtr u; + size_t nchannel; + epics::pvData::Mutex mutex; + + std::vector topPVStructure; + bool gotAlarm; + bool gotTimeStamp; + bool isDestroyed; + + epics::nt::NTMultiChannelPtr ntMultiChannel; + epics::pvData::PVStructurePtr pvTop; + epics::pvData::shared_vector unionValue; + epics::pvData::shared_vector severity; + epics::pvData::shared_vector status; + epics::pvData::shared_vector message; + epics::pvData::shared_vector secondsPastEpoch; + epics::pvData::shared_vector nanoseconds; + epics::pvData::shared_vector userTag; + epics::pvData::Alarm alarm; + epics::pvData::PVAlarm pvAlarm; + epics::pvData::TimeStamp timeStamp;; + epics::pvData::PVTimeStamp pvTimeStamp; + friend class PvaClientNTMultiGet; + friend class PvaClientNTMultiPut; + friend class PvaClientNTMultiMonitor; +}; + + }} #endif /* PVACLIENTMULTICHANNEL_H */ diff --git a/src/pvaClientMultiGetDouble.cpp b/src/pvaClientMultiGetDouble.cpp index be975dc..3697337 100644 --- a/src/pvaClientMultiGetDouble.cpp +++ b/src/pvaClientMultiGetDouble.cpp @@ -68,7 +68,7 @@ void PvaClientMultiGetDouble::destroy() void PvaClientMultiGetDouble::connect() { - shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); string request = "value"; for(size_t i=0; i PvaClientMultiGetDouble::get() { if(!isGetConnected) connect(); - shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); for(size_t i=0; i isConnected = pvaClientMultiChannel->getIsConnected(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); string request = "value"; for(size_t i=0; i isConnected = pvaClientMultiChannel->getIsConnected(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); for(size_t i=0; i isConnected = pvaClientMultiChannel->getIsConnected(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); for(size_t i=0; i const &da if(data.size()!=nchannel) { throw std::runtime_error("data has wrong size"); } - shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); for(size_t i=0; igetData()->getPVStructure(); - PVDoublePtr pvValue = pvTop->getSubField("value"); - pvValue->put(data[i]); + PVScalarPtr pvValue = pvTop->getSubField("value"); + convert->fromDouble(pvValue,data[i]); pvaClientPut[i]->issuePut(); } if(isConnected[i]) { diff --git a/src/pvaClientNTMultiData.cpp b/src/pvaClientNTMultiData.cpp new file mode 100644 index 0000000..57c571b --- /dev/null +++ b/src/pvaClientNTMultiData.cpp @@ -0,0 +1,232 @@ +/* pvaClientNTMultiData.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ + +#define epicsExportSharedSymbols +#include +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::nt; +using namespace std; + +namespace epics { namespace pvaClient { + +static ConvertPtr convert = getConvert(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static StandardFieldPtr standardField = getStandardField(); + + +PvaClientNTMultiDataPtr PvaClientNTMultiData::create( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + PVStructurePtr const & pvRequest) +{ + PvaClientNTMultiDataPtr pvaClientNTMultiData( + new PvaClientNTMultiData(u,pvaMultiChannel,pvaClientChannelArray,pvRequest)); + return pvaClientNTMultiData; +} + +PvaClientNTMultiData::PvaClientNTMultiData( + epics::pvData::UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + pvRequest(pvRequest), + u(u), + nchannel(pvaClientChannelArray.size()), + gotAlarm(false), + gotTimeStamp(false), + isDestroyed(false) +{ + PVFieldPtr pvValue = pvRequest->getSubField("field.value"); + if(!pvValue) { + throw std::runtime_error("pvRequest did not specify value"); + } + topPVStructure.resize(nchannel); + unionValue.resize(nchannel); + for(size_t i=0; i< nchannel; ++i) { + topPVStructure[i] = PVStructurePtr(); + unionValue[i] = pvDataCreate->createPVUnion(u); + } + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + builder->value(u); + if(pvRequest->getSubField("field.alarm")) + { + gotAlarm = true; + builder->addAlarm(); + builder->addSeverity(); + builder->addStatus(); + builder->addMessage(); + severity.resize(nchannel); + status.resize(nchannel); + message.resize(nchannel); + + } + if(pvRequest->getSubField("field.timeStamp")) { + gotTimeStamp = true; + builder->addTimeStamp(); + builder->addSecondsPastEpoch(); + builder->addNanoseconds(); + builder->addUserTag(); + secondsPastEpoch.resize(nchannel); + nanoseconds.resize(nchannel); + userTag.resize(nchannel); + } + ntMultiChannel = builder->create(); + ntMultiChannel->getChannelName()->replace(pvaClientMultiChannel->getChannelNames()); +} + + +PvaClientNTMultiData::~PvaClientNTMultiData() +{ + destroy(); +} + +void PvaClientNTMultiData::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientNTMultiData::setStructure(StructureConstPtr const & structure,size_t index) +{ + FieldConstPtr field = structure->getField("value"); + if(!field) { + string message = "channel " + + pvaClientChannelArray[index]->getChannel()->getChannelName() + + " does not have top level value field"; + throw std::runtime_error(message); + } +} + +void PvaClientNTMultiData::setPVStructure( + PVStructurePtr const &pvStructure,size_t index) +{ + topPVStructure[index] = pvStructure; +} + + +size_t PvaClientNTMultiData::getNumber() +{ + return nchannel; +} + +void PvaClientNTMultiData::startDeltaTime() +{ + for(size_t i=0; iset(pvst->getSubField("value")); + } + if(gotAlarm) + { + severity[i] = pvst->getSubField("alarm.severity")->get(); + status[i] = pvst->getSubField("alarm.status")->get(); + message[i] = pvst->getSubField("alarm.message")->get(); + } + if(gotTimeStamp) + { + secondsPastEpoch[i] = pvst->getSubField("timeStamp.secondsPastEpoch")->get(); + nanoseconds[i] = pvst->getSubField("timeStamp.nanoseconds")->get(); + userTag[i] = pvst->getSubField("timeStamp.userTag")->get(); + } + + } + shared_vector val(nchannel); + for(size_t i=0; igetValue()->replace(freeze(val)); + shared_vector connected = pvaClientMultiChannel->getIsConnected(); + shared_vector isConnected(nchannel); + for(size_t i=0; igetIsConnected()->replace(freeze(isConnected)); + if(gotAlarm) + { + shared_vector sev(nchannel); + for(size_t i=0; igetSeverity()->replace(freeze(sev)); + shared_vector sta(nchannel); + for(size_t i=0; igetStatus()->replace(freeze(sta)); + shared_vector mes(nchannel); + for(size_t i=0; igetMessage()->replace(freeze(mes)); + } + if(gotTimeStamp) + { + shared_vector sec(nchannel); + for(size_t i=0; igetSecondsPastEpoch()->replace(freeze(sec)); + shared_vector nano(nchannel); + for(size_t i=0; igetNanoseconds()->replace(freeze(nano)); + shared_vector tag(nchannel); + for(size_t i=0; igetUserTag()->replace(freeze(tag)); + } +} + +TimeStamp PvaClientNTMultiData::getTimeStamp() +{ + pvTimeStamp.get(timeStamp); + return timeStamp; +} + +NTMultiChannelPtr PvaClientNTMultiData::getNTMultiChannel() +{ + return ntMultiChannel; +} + +PVStructurePtr PvaClientNTMultiData::getPVTop() +{ + return ntMultiChannel->getPVStructure(); +} + +}} diff --git a/src/pvaClientNTMultiGet.cpp b/src/pvaClientNTMultiGet.cpp new file mode 100644 index 0000000..c541096 --- /dev/null +++ b/src/pvaClientNTMultiGet.cpp @@ -0,0 +1,143 @@ +/* pvaClientNTMultiGet.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ + +#define epicsExportSharedSymbols +#include +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::nt; +using namespace std; + +namespace epics { namespace pvaClient { + +static ConvertPtr convert = getConvert(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static StandardFieldPtr standardField = getStandardField(); + + +PvaClientNTMultiGetPtr PvaClientNTMultiGet::create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + PVStructurePtr const & pvRequest) +{ + UnionConstPtr u = fieldCreate->createVariantUnion(); + PvaClientNTMultiGetPtr pvaClientNTMultiGet( + new PvaClientNTMultiGet(u,pvaMultiChannel,pvaClientChannelArray,pvRequest)); + return pvaClientNTMultiGet; +} + +PvaClientNTMultiGet::PvaClientNTMultiGet( + UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + nchannel(pvaClientChannelArray.size()), + pvRequest(pvRequest), + pvaClientNTMultiData( + PvaClientNTMultiData::create( + u, + pvaClientMultiChannel, + pvaClientChannelArray, + pvRequest)), + isConnected(false), + isDestroyed(false) +{ +} + +PvaClientNTMultiGet::~PvaClientNTMultiGet() +{ + destroy(); +} + +void PvaClientNTMultiGet::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientNTMultiGet::connect() +{ + pvaClientGet.resize(nchannel); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + string request = "value"; + if(pvRequest->getSubField("field.alarm")) request += ",alarm"; + if(pvRequest->getSubField("field.timeStamp")) request += ",timeStamp"; + for(size_t i=0; icreateGet(request); + pvaClientGet[i]->issueConnect(); + } + } + for(size_t i=0; iwaitConnect(); + if(status.isOK()) continue; + stringstream ss; + string channelName = pvaClientChannelArray[i]->getChannelName(); + ss << "channel " << channelName << " PvaChannelGet::waitConnect " << status.getMessage(); + throw std::runtime_error(ss.str()); + } + } + this->isConnected = true; +} + +void PvaClientNTMultiGet::get() +{ + if(!isConnected) connect(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + + for(size_t i=0; iissueGet(); + } + } + for(size_t i=0; iwaitGet(); + if(status.isOK()) continue; + stringstream ss; + string channelName = pvaClientChannelArray[i]->getChannelName(); + ss << "channel " << channelName << " PvaChannelGet::waitConnect " << status.getMessage(); + throw std::runtime_error(ss.str()); + } + } + pvaClientNTMultiData->startDeltaTime(); + for(size_t i=0; isetPVStructure(pvaClientGet[i]->getData()->getPVStructure(),i); + } + } + pvaClientNTMultiData->endDeltaTime(); +} + +PvaClientNTMultiDataPtr PvaClientNTMultiGet::getData() +{ + return pvaClientNTMultiData; +} + +}} diff --git a/src/pvaClientNTMultiMonitor.cpp b/src/pvaClientNTMultiMonitor.cpp new file mode 100644 index 0000000..5fd1709 --- /dev/null +++ b/src/pvaClientNTMultiMonitor.cpp @@ -0,0 +1,155 @@ +/* pvaClientNTMultiMonitor.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ + +#define epicsExportSharedSymbols +#include +#include +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::nt; +using namespace std; + +namespace epics { namespace pvaClient { + +static ConvertPtr convert = getConvert(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static StandardFieldPtr standardField = getStandardField(); + + +PvaClientNTMultiMonitorPtr PvaClientNTMultiMonitor::create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + epics::pvData::PVStructurePtr const & pvRequest) +{ + UnionConstPtr u = fieldCreate->createVariantUnion(); + PvaClientNTMultiMonitorPtr pvaClientNTMultiMonitor( + new PvaClientNTMultiMonitor(u,pvaMultiChannel,pvaClientChannelArray,pvRequest)); + return pvaClientNTMultiMonitor; +} + +PvaClientNTMultiMonitor::PvaClientNTMultiMonitor( + UnionConstPtr const & u, + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray, + PVStructurePtr const & pvRequest) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + nchannel(pvaClientChannelArray.size()), + pvRequest(pvRequest), + pvaClientNTMultiData( + PvaClientNTMultiData::create( + u, + pvaClientMultiChannel, + pvaClientChannelArray, + pvRequest)), + isConnected(false), + isDestroyed(false) +{ +} + + +PvaClientNTMultiMonitor::~PvaClientNTMultiMonitor() +{ + destroy(); +} + +void PvaClientNTMultiMonitor::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + + +void PvaClientNTMultiMonitor::connect() +{ + pvaClientMonitor.resize(nchannel); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + string request = "value"; + if(pvRequest->getSubField("field.alarm")) request += ",alarm"; + if(pvRequest->getSubField("field.timeStamp")) request += ",timeStamp"; + for(size_t i=0; icreateMonitor(request); + pvaClientMonitor[i]->issueConnect(); + } + } + for(size_t i=0; iwaitConnect(); + if(status.isOK()) continue; + stringstream ss; + string channelName = pvaClientChannelArray[i]->getChannelName(); + ss << "channel " << channelName << " PvaChannelMonitor::waitConnect " << status.getMessage(); + throw std::runtime_error(ss.str()); + } + } + for(size_t i=0; istart(); + } + this->isConnected = true; +} + +bool PvaClientNTMultiMonitor::poll() +{ + if(!isConnected) connect(); + bool result = false; + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + pvaClientNTMultiData->startDeltaTime(); + for(size_t i=0; ipoll()) { + pvaClientNTMultiData->setPVStructure( + pvaClientMonitor[i]->getData()->getPVStructure(),i); + pvaClientMonitor[i]->releaseEvent(); + result = true; + } + } + } + if(result) pvaClientNTMultiData->endDeltaTime(); + return result; +} + +bool PvaClientNTMultiMonitor::waitEvent(double waitForEvent) +{ + if(poll()) return true; + TimeStamp start; + start.getCurrent(); + TimeStamp now; + while(true) { + epicsThreadSleep(.1); + if(poll()) return true; + now.getCurrent(); + double diff = TimeStamp::diff(now,start); + if(diff>=waitForEvent) break; + } + return false; +} + +PvaClientNTMultiDataPtr PvaClientNTMultiMonitor::getData() +{ + return pvaClientNTMultiData; +} + +}} diff --git a/src/pvaClientNTMultiPut.cpp b/src/pvaClientNTMultiPut.cpp new file mode 100644 index 0000000..d947d34 --- /dev/null +++ b/src/pvaClientNTMultiPut.cpp @@ -0,0 +1,149 @@ +/* PvaClientNTMultiPut.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2015.03 + */ + +#define epicsExportSharedSymbols +#include +#include +#include +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::nt; +using namespace std; + +namespace epics { namespace pvaClient { + +static ConvertPtr convert = getConvert(); +static FieldCreatePtr fieldCreate = getFieldCreate(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static StandardFieldPtr standardField = getStandardField(); +static CreateRequest::shared_pointer createRequest = CreateRequest::create(); + +PvaClientNTMultiPutPtr PvaClientNTMultiPut::create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +{ + PvaClientNTMultiPutPtr pvaClientNTMultiPut( + new PvaClientNTMultiPut(pvaMultiChannel,pvaClientChannelArray)); + return pvaClientNTMultiPut; +} + +PvaClientNTMultiPut::PvaClientNTMultiPut( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + nchannel(pvaClientChannelArray.size()), + unionValue(shared_vector(nchannel,PVUnionPtr())), + value(shared_vector(nchannel,PVFieldPtr())), + isConnected(false), + isDestroyed(false) +{ +} + + +PvaClientNTMultiPut::~PvaClientNTMultiPut() +{ + destroy(); +} + +void PvaClientNTMultiPut::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientNTMultiPut::connect() +{ + pvaClientPut.resize(nchannel); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + for(size_t i=0; icreatePut(); + pvaClientPut[i]->issueConnect(); + } + } + for(size_t i=0; iwaitConnect(); + if(status.isOK()) continue; + stringstream ss; + string channelName = pvaClientChannelArray[i]->getChannelName(); + ss << "channel " << channelName << " PvaChannelPut::waitConnect " << status.getMessage(); + throw std::runtime_error(ss.str()); + } + } + for(size_t i=0; iissueGet(); + } + } + for(size_t i=0; iwaitGet(); + if(status.isOK()) continue; + stringstream ss; + string channelName = pvaClientChannelArray[i]->getChannelName(); + ss << "channel " << channelName << " PvaChannelPut::waitGet " << status.getMessage(); + throw std::runtime_error(ss.str()); + } + } + for(size_t i=0; igetData()->getValue(); + FieldBuilderPtr builder = fieldCreate->createFieldBuilder(); + builder->add("value",value[i]->getField()); + unionValue[i] = pvDataCreate->createPVUnion(builder->createUnion()); + } + } + this->isConnected = true; +} + +shared_vector PvaClientNTMultiPut::getValues() +{ + if(!isConnected) connect(); + return unionValue; +} + +void PvaClientNTMultiPut::put() +{ + if(!isConnected) connect(); + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + for(size_t i=0; icopy(*unionValue[i]->get()); + pvaClientPut[i]->issuePut(); + } + if(isConnected[i]) { + Status status = pvaClientPut[i]->waitPut(); + if(status.isOK()) continue; + stringstream ss; + string channelName = pvaClientChannelArray[i]->getChannelName(); + ss << "channel " << channelName << " PvaChannelPut::waitConnect " << status.getMessage(); + throw std::runtime_error(ss.str()); + } + } +} + + +}}