diff --git a/example/src/Makefile b/example/src/Makefile index d80136b..4f48aaf 100644 --- a/example/src/Makefile +++ b/example/src/Makefile @@ -33,6 +33,13 @@ examplePvaClientMonitor_LIBS += pvAccess examplePvaClientMonitor_LIBS += pvData examplePvaClientMonitor_LIBS += Com +PROD_HOST += examplePvaClientMultiDouble +examplePvaClientMultiDouble_SRCS += examplePvaClientMultiDouble.cpp +examplePvaClientMultiDouble_LIBS += pvaClient +examplePvaClientMultiDouble_LIBS += pvAccess +examplePvaClientMultiDouble_LIBS += pvData +examplePvaClientMultiDouble_LIBS += Com + PROD_HOST += helloWorldRPC helloWorldRPC_SRCS += helloWorldRPC.cpp helloWorldRPC_LIBS += pvaClient diff --git a/example/src/examplePvaClientMonitor.cpp b/example/src/examplePvaClientMonitor.cpp index 1d60295..5e996c3 100644 --- a/example/src/examplePvaClientMonitor.cpp +++ b/example/src/examplePvaClientMonitor.cpp @@ -22,25 +22,29 @@ using namespace epics::pvAccess; using namespace epics::pvaClient; -static void exampleMonitor(PvaClientPtr const &pva) +static void exampleMonitor(PvaClientPtr const &pva,string provider) { - PvaClientMonitorPtr monitor = pva->channel("exampleDouble")->monitor(""); - PvaClientMonitorDataPtr pvaData = monitor->getData(); - PvaClientPutPtr put = pva->channel("exampleDouble")->put(""); + PvaClientMonitorPtr monitor = pva->channel("double00",provider,2.0)->monitor(""); + PvaClientMonitorDataPtr monitorData = monitor->getData(); + PvaClientPutPtr put = pva->channel("double00",provider,2.0)->put(""); PvaClientPutDataPtr putData = put->getData(); for(size_t ntimes=0; ntimes<5; ++ntimes) { double value = ntimes; + cout << "put " << value << endl; putData->putDouble(value); put->put(); - if(!monitor->waitEvent()) { + if(!monitor->waitEvent(.1)) { cout << "waitEvent returned false. Why???"; continue; + } else while(true) { + cout << "monitor " << monitorData->getDouble() << endl; + cout << "changed\n"; + monitorData->showChanged(cout); + cout << "overrun\n"; + monitorData->showOverrun(cout); + monitor->releaseEvent(); + if(!monitor->poll()) break; } - cout << "changed\n"; - pvaData->showChanged(cout); - cout << "overrun\n"; - pvaData->showOverrun(cout); - monitor->releaseEvent(); } } @@ -48,7 +52,10 @@ static void exampleMonitor(PvaClientPtr const &pva) int main(int argc,char *argv[]) { PvaClientPtr pva = PvaClient::create(); - exampleMonitor(pva); + cout << "exampleMonitor pva\n"; + exampleMonitor(pva,"pva"); + cout << "exampleMonitor ca\n"; + exampleMonitor(pva,"ca"); cout << "done\n"; return 0; } diff --git a/example/src/examplePvaClientMultiDouble.cpp b/example/src/examplePvaClientMultiDouble.cpp new file mode 100644 index 0000000..2c5b986 --- /dev/null +++ b/example/src/examplePvaClientMultiDouble.cpp @@ -0,0 +1,79 @@ +/*examplePvaClientMultiDouble.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 + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvaClient; + +static void example( + PvaClientPtr const &pva, + string provider, + shared_vector const &channelNames) +{ + + size_t num = channelNames.size(); +cout << "num " << num << " names " << channelNames << endl; + PvaClientMultiChannelPtr multiChannel( + PvaClientMultiChannel::create(pva,channelNames,provider)); + PvaClientMultiGetDoublePtr multiGet(multiChannel->createGet()); + PvaClientMultiPutDoublePtr multiPut(multiChannel->createPut()); + PvaClientMultiMonitorDoublePtr multiMonitor(multiChannel->createMonitor()); + shared_vector data(num,0); + for(double value = 0.0; value< 1.0; value+= .2) { + try { + for(size_t i=0; iput(data); + data = multiGet->get(); + cout << "get " << data << endl; + bool result = multiMonitor->waitEvent(.1); + while(result) { + cout << "monitor data " << multiMonitor->get() << endl; + result = multiMonitor->poll(); + } + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + } +} + +int main(int argc,char *argv[]) +{ + PvaClientPtr pva = PvaClient::create(); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "double01"; + channelNames[1] = "double02"; + channelNames[2] = "double03"; + channelNames[3] = "double04"; + channelNames[4] = "double05"; + cout << "double pva\n"; + shared_vector names(freeze(channelNames)); + example(pva,"pva",names); + cout << "double ca\n"; + example(pva,"ca",names); + channelNames = shared_vector(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "exampleDouble04"; + channelNames[4] = "exampleDouble05"; + names = freeze(channelNames); + cout << "exampleDouble pva\n"; + example(pva,"pva",names); + return 0; +} diff --git a/example/src/examplePvaClientPut.cpp b/example/src/examplePvaClientPut.cpp index a7f87e1..c6202be 100644 --- a/example/src/examplePvaClientPut.cpp +++ b/example/src/examplePvaClientPut.cpp @@ -26,11 +26,20 @@ static void examplePut(PvaClientPtr const &pva) PvaClientChannelPtr channel = pva->channel("exampleDouble"); PvaClientPutPtr put = channel->put(); PvaClientPutDataPtr putData = put->getData(); + PvaClientMonitorPtr monitor = pva->channel("exampleDouble")->monitor(""); + PvaClientMonitorDataPtr monitorData = monitor->getData(); try { putData->putDouble(3.0); put->put(); cout << channel->get("field()")->getData()->showChanged(cout) << endl; putData->putDouble(4.0); put->put(); cout << channel->get("field()")->getData()->showChanged(cout) << endl; + if(!monitor->waitEvent()) { + cout << "waitEvent returned false. Why???"; + } else while(true) { + cout << "monitor changed\n" << monitorData->showChanged(cout); + monitor->releaseEvent(); + if(!monitor->poll()) break; + } } catch (std::runtime_error e) { cout << "exception " << e.what() << endl; } diff --git a/src/Makefile b/src/Makefile index 8249b7d..8a23f7a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,6 +6,7 @@ include $(TOP)/configure/CONFIG LIBRARY += pvaClient INC += pvaClient.h +INC += pvaClientMultiChannel.h LIBSRCS += pvaClient.cpp LIBSRCS += pvaClientPutData.cpp @@ -17,6 +18,10 @@ LIBSRCS += pvaClientGet.cpp LIBSRCS += pvaClientPut.cpp LIBSRCS += pvaClientMonitor.cpp LIBSRCS += pvaClientPutGet.cpp +LIBSRCS += pvaClientMultiChannel.cpp +LIBSRCS += pvaClientMultiGetDouble.cpp +LIBSRCS += pvaClientMultiPutDouble.cpp +LIBSRCS += pvaClientMultiMonitorDouble.cpp pvaClient_LIBS += pvAccess pvData nt Com pvaClient_LIBS += $(EPICS_BASE_IOC_LIBS) diff --git a/src/pvaClientMultiChannel.cpp b/src/pvaClientMultiChannel.cpp new file mode 100644 index 0000000..3e3f2e7 --- /dev/null +++ b/src/pvaClientMultiChannel.cpp @@ -0,0 +1,185 @@ +/* pvaClientMultiChannel.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.02 + */ +#define epicsExportSharedSymbols + +#include +#include +#include +#include +#include +#include + + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pvaClient { + +static FieldCreatePtr fieldCreate = getFieldCreate(); +static CreateRequest::shared_pointer createRequestPvt = CreateRequest::create(); + +PvaClientMultiChannelPtr PvaClientMultiChannel::create( + PvaClientPtr const &pvaClient, + epics::pvData::shared_vector const & channelNames, + string const & providerName, + size_t maxNotConnected) +{ + PvaClientMultiChannelPtr channel( + new PvaClientMultiChannel(pvaClient,channelNames,providerName,maxNotConnected)); + return channel; +} + + +PvaClientMultiChannel::PvaClientMultiChannel( + PvaClientPtr const &pvaClient, + epics::pvData::shared_vector const & channelName, + string const & providerName, + size_t maxNotConnected) +: pvaClient(pvaClient), + channelName(channelName), + providerName(providerName), + maxNotConnected(maxNotConnected), + numChannel(channelName.size()), + numConnected(0), + pvaClientChannelArray(PvaClientChannelArray(numChannel,PvaClientChannelPtr())), + isConnected(shared_vector(numChannel,false)), + isDestroyed(false) +{ +} + +PvaClientMultiChannel::~PvaClientMultiChannel() +{ + destroy(); +} + +void PvaClientMultiChannel::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientMultiChannel::checkConnected() +{ + if(numConnected==0) connect(3.0); +} + +epics::pvData::shared_vector PvaClientMultiChannel::getChannelNames() +{ + if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); + return channelName; +} + +Status PvaClientMultiChannel::connect(double timeout) +{ + if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); + for(size_t i=0; i< numChannel; ++i) { + pvaClientChannelArray[i] = pvaClient->createChannel(channelName[i],providerName); + pvaClientChannelArray[i]->issueConnect(); + } + Status returnStatus = Status::Ok; + Status status = Status::Ok; + size_t numBad = 0; + for(size_t i=0; i< numChannel; ++i) { + if(numBad==0) { + status = pvaClientChannelArray[i]->waitConnect(timeout); + } else { + status = pvaClientChannelArray[i]->waitConnect(.001); + } + if(status.isOK()) { + ++numConnected; + isConnected[i] = true; + continue; + } + if(returnStatus.isOK()) returnStatus = status; + ++numBad; + if(numBad>maxNotConnected) break; + } + return numBad>maxNotConnected ? returnStatus : Status::Ok; +} + + +bool PvaClientMultiChannel::allConnected() +{ + if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); + return (numConnected==numChannel) ? true : false; +} + +bool PvaClientMultiChannel::connectionChange() +{ + if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); + for(size_t i=0; igetChannel(); + Channel::ConnectionState stateNow = channel->getConnectionState(); + bool connectedNow = stateNow==Channel::CONNECTED ? true : false; + if(connectedNow!=isConnected[i]) return true; + } + return false; +} + +epics::pvData::shared_vector PvaClientMultiChannel::getIsConnected() +{ + if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); + for(size_t i=0; igetChannel(); + Channel::ConnectionState stateNow = channel->getConnectionState(); + isConnected[i] = (stateNow==Channel::CONNECTED) ? true : false; + } + return isConnected; +} + +PvaClientChannelArray PvaClientMultiChannel::getPvaClientChannelArray() +{ + if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); + return pvaClientChannelArray; +} + +PvaClientPtr PvaClientMultiChannel::getPvaClient() +{ + if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed"); + return pvaClient; +} + + + +PvaClientMultiGetDoublePtr PvaClientMultiChannel::createGet() +{ + checkConnected(); + return PvaClientMultiGetDouble::create(getPtrSelf(),pvaClientChannelArray); +} + + +PvaClientMultiPutDoublePtr PvaClientMultiChannel::createPut() +{ + checkConnected(); + return PvaClientMultiPutDouble::create(getPtrSelf(),pvaClientChannelArray); +} + + +PvaClientMultiMonitorDoublePtr PvaClientMultiChannel::createMonitor() +{ + checkConnected(); + return PvaClientMultiMonitorDouble::create(getPtrSelf(), pvaClientChannelArray); +} + + +}} diff --git a/src/pvaClientMultiChannel.h b/src/pvaClientMultiChannel.h new file mode 100644 index 0000000..ff6c167 --- /dev/null +++ b/src/pvaClientMultiChannel.h @@ -0,0 +1,331 @@ +/* pvaClient.h */ +/** + * 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.02 + */ +#ifndef PVACLIENTMULTICHANNEL_H +#define PVACLIENTMULTICHANNEL_H + +#ifdef epicsExportSharedSymbols +# define pvaClientEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#include +#include + + +namespace epics { namespace pvaClient { + + +class PvaClientMultiChannel; +typedef std::tr1::shared_ptr PvaClientMultiChannelPtr; +class PvaClientMultiGetDouble; +typedef std::tr1::shared_ptr PvaClientMultiGetDoublePtr; +class PvaClientMultiPutDouble; +typedef std::tr1::shared_ptr PvaClientMultiPutDoublePtr; +class PvaClientMultiMonitorDouble; +typedef std::tr1::shared_ptr PvaClientMultiMonitorDoublePtr; + + +typedef epics::pvData::shared_vector PvaClientChannelArray; + +/** + * Provides access to multiple channels. + * + * @author mrk + */ +class epicsShareClass PvaClientMultiChannel : + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(PvaClientMultiChannel); + /** Create a PvaClientMultiChannel. + * @param pvaClient The interface to pvaClient. + * @param channelNames The names of the channel.. + * @param providerName The name of the provider. + * @param maxNotConnected The maximum number of channels that can be disconnected. + * @return The interface to the PvaClientMultiChannel + */ + static PvaClientMultiChannelPtr create( + PvaClientPtr const &pvaClient, + epics::pvData::shared_vector const & channelNames, + std::string const & providerName = "pva", + size_t maxNotConnected=0 + ); + + ~PvaClientMultiChannel(); + /** Destroy the pvAccess connection. + */ + void destroy(); + /** Get the channelNames. + * @return The names. + */ + epics::pvData::shared_vector getChannelNames(); + /** Connect to the channels. + * This calls issueConnect and waitConnect. + * An exception is thrown if connect fails. + * @param timeout The time to wait for connecting to the channel. + * @return status of request + */ + epics::pvData::Status connect(double timeout=5); + /** Are all channels connected? + * @return if all are connected. + */ + bool allConnected(); + /** Has a connection state change occured? + * @return (true, false) if (at least one, no) channel has changed state. + */ + bool connectionChange(); + /** Get the connection state of each channel. + * @return The state of each channel. + */ + epics::pvData::shared_vector getIsConnected(); + /** Get the pvaClientChannelArray. + * @return The shared pointer. + */ + PvaClientChannelArray getPvaClientChannelArray(); + /** Get pvaClient. + * @return The shared pointer. + */ + PvaClientPtr getPvaClient(); + /** + * create a pvaClientMultiGetDouble + * @return The interface. + */ + PvaClientMultiGetDoublePtr createGet(); + /** + * create a pvaClientMultiPutDouble + * @return The interface. + */ + PvaClientMultiPutDoublePtr createPut(); + /** + * Create a pvaClientMultiMonitorDouble. + * @return The interface. + */ + PvaClientMultiMonitorDoublePtr createMonitor(); + /** Get the shared pointer to self. + * @return The shared pointer. + */ + PvaClientMultiChannelPtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaClientMultiChannel( + PvaClientPtr const &pvaClient, + epics::pvData::shared_vector const & channelName, + std::string const & providerName, + size_t maxNotConnected); + + void checkConnected(); + + PvaClientPtr pvaClient; + epics::pvData::shared_vector channelName; + std::string providerName; + size_t maxNotConnected; + + size_t numChannel; + epics::pvData::Mutex mutex; + + size_t numConnected; + PvaClientChannelArray pvaClientChannelArray; + epics::pvData::shared_vector isConnected; + bool isDestroyed; +}; + +/** + * This provides channelGet to multiple channels where each channel has a numeric scalar value field. + */ +class epicsShareClass PvaClientMultiGetDouble : + public std::tr1::enable_shared_from_this +{ + +public: + POINTER_DEFINITIONS(PvaClientMultiGetDouble); + + /** + * Factory method that creates a PvaClientMultiGetDouble. + * @param pvaClientMultiChannel The interface to PvaClientMultiChannel. + * @param pvaClientChannelArray The PvaClientChannel array. + * @return The interface. + */ + static PvaClientMultiGetDoublePtr create( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + + ~PvaClientMultiGetDouble(); + + /** Destroy the pvAccess connection. + */ + void destroy(); + /** + * Create a channelGet for each channel. + */ + void connect(); + /** + * get the data. + * @return The double[] where each element is the value field of the corresponding channel. + */ + epics::pvData::shared_vector get(); + /** Get the shared pointer to self. + * @return The shared pointer. + */ + PvaClientMultiGetDoublePtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaClientMultiGetDouble( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + + PvaClientMultiChannelPtr pvaClientMultiChannel; + PvaClientChannelArray pvaClientChannelArray; + size_t nchannel; + epics::pvData::Mutex mutex; + + epics::pvData::shared_vector doubleValue; + std::vector pvaClientGet; + bool isGetConnected; + bool isDestroyed; +}; + +/** + * This provides channelPut to multiple channels where each channel has a numeric scalar value field. + */ +class epicsShareClass PvaClientMultiPutDouble : + public std::tr1::enable_shared_from_this +{ + +public: + POINTER_DEFINITIONS(PvaClientMultiPutDouble); + + /** + * Factory method that creates a PvaClientMultiPutDouble. + * @param pvaClientMultiChannel The interface to PvaClientMultiChannel. + * @param pvaClientChannelArray The PvaClientChannel array. + * @return The interface. + */ + static PvaClientMultiPutDoublePtr create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + ~PvaClientMultiPutDouble(); + + /** Destroy the pvAccess connection. + */ + void destroy(); + /** + * Create a channelPut for each channel. + */ + void connect(); + /** put data to each channel as a double + * @param data The array of data for each channel. + */ + void put(epics::pvData::shared_vector const &data); + /** Get the shared pointer to self. + * @return The shared pointer. + */ + PvaClientMultiPutDoublePtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaClientMultiPutDouble( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + + PvaClientMultiChannelPtr pvaClientMultiChannel; + PvaClientChannelArray pvaClientChannelArray; + size_t nchannel; + epics::pvData::Mutex mutex; + + std::vector pvaClientPut; + bool isPutConnected; + bool isDestroyed; +}; + +/** + * This provides a monitor to multiple channels where each channel has a numeric scalar value field. + */ +class epicsShareClass PvaClientMultiMonitorDouble : + public std::tr1::enable_shared_from_this +{ + +public: + POINTER_DEFINITIONS(PvaClientMultiMonitorDouble); + + /** + * Factory method that creates a PvaClientMultiMonitorDouble. + * @param pvaClientMultiChannel The interface to PvaClientMultiChannel. + * @param pvaClientChannelArray The PvaClientChannel array. + * @return The interface. + */ + static PvaClientMultiMonitorDoublePtr create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + ~PvaClientMultiMonitorDouble(); + + /** 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 double[] where each element is the value field of the corresponding channel. + */ + epics::pvData::shared_vector get(); + /** Monitor the shared pointer to self. + * @return The shared pointer. + */ + PvaClientMultiMonitorDoublePtr getPtrSelf() + { + return shared_from_this(); + } +private: + PvaClientMultiMonitorDouble( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray); + + PvaClientMultiChannelPtr pvaClientMultiChannel; + PvaClientChannelArray pvaClientChannelArray; + size_t nchannel; + epics::pvData::Mutex mutex; + + epics::pvData::shared_vector doubleValue; + std::vector pvaClientMonitor; + bool isMonitorConnected; + bool isDestroyed; +}; + +}} + +#endif /* PVACLIENTMULTICHANNEL_H */ + +/** @page Overview Documentation + * + * pvaClientOverview.html + * + */ + diff --git a/src/pvaClientMultiGetDouble.cpp b/src/pvaClientMultiGetDouble.cpp new file mode 100644 index 0000000..be975dc --- /dev/null +++ b/src/pvaClientMultiGetDouble.cpp @@ -0,0 +1,130 @@ +/* pvaClientMultiGetDouble.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(); + + +PvaClientMultiGetDoublePtr PvaClientMultiGetDouble::create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +{ + PvaClientMultiGetDoublePtr pvaClientMultiGetDouble( + new PvaClientMultiGetDouble(pvaMultiChannel,pvaClientChannelArray)); + return pvaClientMultiGetDouble; +} + +PvaClientMultiGetDouble::PvaClientMultiGetDouble( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + nchannel(pvaClientChannelArray.size()), + doubleValue(shared_vector(nchannel)), + pvaClientGet(std::vector(nchannel,PvaClientGetPtr())), + isGetConnected(false), + isDestroyed(false) +{ +} + +PvaClientMultiGetDouble::~PvaClientMultiGetDouble() +{ + destroy(); +} + +void PvaClientMultiGetDouble::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientMultiGetDouble::connect() +{ + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + string request = "value"; + 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()); + } + } + isGetConnected = true; +} + +epics::pvData::shared_vector PvaClientMultiGetDouble::get() +{ + if(!isGetConnected) 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()); + } + } + + for(size_t i=0; igetData()->getPVStructure(); + doubleValue[i] = convert->toDouble(pvStructure->getSubField("value")); + } else { + doubleValue[i] = nan(""); + } + } + return doubleValue; +} + +}} diff --git a/src/pvaClientMultiMonitorDouble.cpp b/src/pvaClientMultiMonitorDouble.cpp new file mode 100644 index 0000000..f4faa57 --- /dev/null +++ b/src/pvaClientMultiMonitorDouble.cpp @@ -0,0 +1,142 @@ +/* pvaClientMultiMonitorDouble.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(); + + +PvaClientMultiMonitorDoublePtr PvaClientMultiMonitorDouble::create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +{ + PvaClientMultiMonitorDoublePtr pvaClientMultiMonitorDouble( + new PvaClientMultiMonitorDouble(pvaMultiChannel,pvaClientChannelArray)); + return pvaClientMultiMonitorDouble; +} + +PvaClientMultiMonitorDouble::PvaClientMultiMonitorDouble( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + nchannel(pvaClientChannelArray.size()), + doubleValue(shared_vector(nchannel,nan(""))), + pvaClientMonitor(std::vector(nchannel,PvaClientMonitorPtr())), + isMonitorConnected(false), + isDestroyed(false) +{ +} + +PvaClientMultiMonitorDouble::~PvaClientMultiMonitorDouble() +{ + destroy(); +} + +void PvaClientMultiMonitorDouble::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientMultiMonitorDouble::connect() +{ + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + string request = "value"; + 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 << " PvaChannelGet::waitConnect " << status.getMessage(); + throw std::runtime_error(ss.str()); + } + } + for(size_t i=0; istart(); + } + isMonitorConnected = true; +} + +bool PvaClientMultiMonitorDouble::poll() +{ + if(!isMonitorConnected){ + connect(); + epicsThreadSleep(.01); + } + bool result = false; + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + for(size_t i=0; ipoll()) { + doubleValue[i] = pvaClientMonitor[i]->getData()->getDouble(); + pvaClientMonitor[i]->releaseEvent(); + result = true; + } + } + } + return result; +} + +bool PvaClientMultiMonitorDouble::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; +} + +epics::pvData::shared_vector PvaClientMultiMonitorDouble::get() +{ + return doubleValue; +} + + +}} diff --git a/src/pvaClientMultiPutDouble.cpp b/src/pvaClientMultiPutDouble.cpp new file mode 100644 index 0000000..d2dbcd9 --- /dev/null +++ b/src/pvaClientMultiPutDouble.cpp @@ -0,0 +1,121 @@ +/* pvaClientMultiPutDouble.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(); + + +PvaClientMultiPutDoublePtr PvaClientMultiPutDouble::create( + PvaClientMultiChannelPtr const &pvaMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +{ + PvaClientMultiPutDoublePtr pvaClientMultiPutDouble( + new PvaClientMultiPutDouble(pvaMultiChannel,pvaClientChannelArray)); + return pvaClientMultiPutDouble; +} + +PvaClientMultiPutDouble::PvaClientMultiPutDouble( + PvaClientMultiChannelPtr const &pvaClientMultiChannel, + PvaClientChannelArray const &pvaClientChannelArray) +: pvaClientMultiChannel(pvaClientMultiChannel), + pvaClientChannelArray(pvaClientChannelArray), + nchannel(pvaClientChannelArray.size()), + pvaClientPut(std::vector(nchannel,PvaClientPutPtr())), + isPutConnected(false), + isDestroyed(false) +{ +} + + + +PvaClientMultiPutDouble::~PvaClientMultiPutDouble() +{ + destroy(); +} + +void PvaClientMultiPutDouble::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + pvaClientChannelArray.clear(); +} + +void PvaClientMultiPutDouble::connect() +{ + 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()); + } + } + isPutConnected = true; +} + +void PvaClientMultiPutDouble::put(epics::pvData::shared_vector const &data) +{ + if(!isPutConnected) connect(); + if(data.size()!=nchannel) { + throw std::runtime_error("data has wrong size"); + } + shared_vector isConnected = pvaClientMultiChannel->getIsConnected(); + for(size_t i=0; igetData()->getPVStructure(); + PVDoublePtr pvValue = pvTop->getSubField("value"); + pvValue->put(data[i]); + 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()); + } + } +} + +}}