diff --git a/configure/ExampleRELEASE.local b/configure/ExampleRELEASE.local index dc46b3e..483ab6e 100644 --- a/configure/ExampleRELEASE.local +++ b/configure/ExampleRELEASE.local @@ -2,6 +2,8 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top EPICS_BASE=/home/install/epics/base -PVCOMMON=/home/hg/pvCommonCPP -PVDATA=/home/hg/pvDataCPP -PVACCESS=/home/hg/pvAccessCPP +V4BASE=/home/hg +PVCOMMON=${V4BASE}/pvCommonCPP +PVDATA=${V4BASE}/pvDataCPP +NORMATIVETYPES=${V4BASE}/normativeTypesCPP +PVACCESS=${V4BASE}/pvAccessCPP diff --git a/documentation/easyPVA.html b/documentation/easyPVA.html index 8472bb4..dfb1598 100644 --- a/documentation/easyPVA.html +++ b/documentation/easyPVA.html @@ -94,7 +94,7 @@ There is code for NTMultiChannel that helps with access to more complicated data

EasyPVA is a synchronous API for accessing PVData via PVAccess. It provides an interface to many of the features provided by pvData and pvAccess.

-

This document describes the layout of the source files in this project.

+

This document describes the layout of the source files in this project.

A user overview is available via EasyChannel

This provides methods for connecting to a channel and for creating instances of EasyField, EasyProcess, ..., EasyRPC.

-

Connection must be made before any crete method is called or +

Connection must be made before any create method is called or an exception is raised. The following is a synchronous connection request:

-easyChannel->connect(5.0); // BLOCKS 
+easyChannel->connect(5.0); // BLOCKS AND THROWS IF NO CONNECT
 

This blocks until then connection is made or until timout occurs. An exception is raised if the connection request fails. @@ -134,7 +134,7 @@ An exception is raised if the connection request fails.

 easyChannel->issueConnect(); // DOES NOT BLOCK
 .....
-Status status =easyChannel->waitConnect(5.0);  // BLOCKS
+Status status =easyChannel->waitConnect(5.0);  // BLOCKS DOES NOT THROW
 if(!status.isOK()) {
    // failure do something
 }
@@ -189,36 +189,36 @@ void easyData->putDouble(5.0);
 

This provides methods to connect to channelGet and to issue get request. To connect via a single synchronous call:

-eastGet->connect();  // BLOCKS
+eastGet->connect();  // BLOCKS AND CAN THROW
 

This can also be done in two steps:

 easyGet->issueConnect(); // DOES NOT BLOCK
 ...
-Status status = easyGet->waitConnect(); // BLOCKS
+Status status = easyGet->waitConnect(); // BLOCKS AND DOES NOT HROW
 

Once connected gets are issued via either:

-void easyGet->get();
+void easyGet->get(); // BLOCKS AND CAN THROW
 
or
 easyGet->issueGet(); // DOES NOT BLOCK
 ...
-Status status = easyGet->waitGet(); // BLOCKS
+Status status = easyGet->waitGet(); // BLOCKS AND DOES NOT THROW
 

EasyPut

This is similar to easyGet except that it wraps channelPut instead of channelGet.

Once connected puts are issued via either:

-void easyPut->put();
+void easyPut->put(); // BLOCKS AND CAN THROW
 
or
 easyPut->issuePut(); // DOES NOT BLOCK
 ...
-Status status = easyPut->waitPut(); // BLOCKS
+Status status = easyPut->waitPut(); // BLOCKS AND DOES NOT THROW
 

EasyMonitor

Connecting is similar to easyGet and easyPut. @@ -287,7 +287,26 @@ It has methods:

Look at javaDoc for details.

EasyMultiChannel - Wrapper For Multiple Channels

-

TBD

+

EasyMultiChannel

+

This provides methods for connecting to multiple channels. +For now clients has no reason to use this directly. +Instead they will use it via EasyMultiDouble or EasyNTMultiChannel. +

+

EasyMultiDouble

+

This provides support for gets and puts to the value field of multiple channels. +Each channel must have a value field that is a numeric scalar. +The client always sees that data as a PVDoubleArray. +All channels must connect. +If any problems occur an exception is thrown. +

+

EasyNTMultiChannel

+

This provides support for gets and puts to the value field of multiple channels. +Each channel must have a value field. +The client always sees that data as a NTMultiChannel, which is one +of the types provided by normativeTypesCPP. +All channels must connect. +If any problems occur an exception is thrown. +

diff --git a/example/src/Makefile b/example/src/Makefile index 9acc4f4..ab07940 100644 --- a/example/src/Makefile +++ b/example/src/Makefile @@ -33,6 +33,21 @@ exampleEasyMonitor_LIBS += pvAccess exampleEasyMonitor_LIBS += pvData exampleEasyMonitor_LIBS += Com +PROD_HOST += exampleEasyMultiDouble +exampleEasyMultiDouble_SRCS += exampleEasyMultiDouble.cpp +exampleEasyMultiDouble_LIBS += easyPVA +exampleEasyMultiDouble_LIBS += pvAccess +exampleEasyMultiDouble_LIBS += pvData +exampleEasyMultiDouble_LIBS += Com + +PROD_HOST += exampleEasyNTMultiChannel +exampleEasyNTMultiChannel_SRCS += exampleEasyNTMultiChannel.cpp +exampleEasyNTMultiChannel_LIBS += easyPVA +exampleEasyNTMultiChannel_LIBS += pvAccess +exampleEasyNTMultiChannel_LIBS += nt +exampleEasyNTMultiChannel_LIBS += pvData +exampleEasyNTMultiChannel_LIBS += Com + #=========================== include $(TOP)/configure/RULES diff --git a/example/src/exampleEasyMultiDouble.cpp b/example/src/exampleEasyMultiDouble.cpp new file mode 100644 index 0000000..b310255 --- /dev/null +++ b/example/src/exampleEasyMultiDouble.cpp @@ -0,0 +1,56 @@ +/*exampleEasyMultiDouble.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::easyPVA; + + +static void example(EasyPVAPtr const &easyPVA) +{ + cout << "example multiDouble\n"; + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "exampleDouble04"; + channelNames[4] = "exampleDouble05"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + EasyMultiDoublePtr multiDouble(EasyMultiDouble::create(easyPVA,pvNames)); + try { + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + +} + + +int main(int argc,char *argv[]) +{ + EasyPVAPtr easyPVA = EasyPVA::create(); + example(easyPVA); + return 0; +} diff --git a/example/src/exampleEasyNTMultiChannel.cpp b/example/src/exampleEasyNTMultiChannel.cpp new file mode 100644 index 0000000..7ab90fd --- /dev/null +++ b/example/src/exampleEasyNTMultiChannel.cpp @@ -0,0 +1,65 @@ +/*exampleEasyNTMultiChannel.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::easyPVA; +using namespace epics::nt; + + +static void example(EasyPVAPtr const &easyPVA) +{ + cout << "example ntMultiChannel\n"; + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble"; + channelNames[1] = "exampleDoubleArray"; + channelNames[2] = "exampleString"; + channelNames[3] = "exampleBoolean"; + channelNames[4] = "exampleEnum"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + StructureConstPtr structure = builder-> + addTimeStamp()-> + addSeverity() -> + addStatus() -> + addMessage() -> + addSecondsPastEpoch() -> + addNanoseconds() -> + addUserTag() -> + createStructure(); + EasyNTMultiChannelPtr easy = EasyNTMultiChannel::create( + easyPVA,pvNames,structure); + try { + NTMultiChannelPtr nt = easy->get(); + cout << "initial\n" << nt->getPVStructure() << endl; + + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + } + +} + + +int main(int argc,char *argv[]) +{ + EasyPVAPtr easyPVA = EasyPVA::create(); + example(easyPVA); + return 0; +} diff --git a/example/src/exampleEasyPut.cpp b/example/src/exampleEasyPut.cpp index 81f2d12..6f3d02d 100644 --- a/example/src/exampleEasyPut.cpp +++ b/example/src/exampleEasyPut.cpp @@ -1,4 +1,4 @@ -/*exampleEasyProcess.cpp */ +/*exampleEasyPut.cpp */ /** * Copyright - See the COPYRIGHT that is included with this distribution. * EPICS pvData is distributed subject to a Software License Agreement found @@ -22,7 +22,7 @@ using namespace epics::easyPVA; static void examplePut(EasyPVAPtr const &easyPVA) { - cout << "example process\n"; + cout << "example put\n"; EasyChannelPtr channel = easyPVA->channel("exampleDouble"); EasyPutPtr put = channel->put(); EasyPutDataPtr putData = put->getData(); diff --git a/src/Makefile b/src/Makefile index c403aca..29d25fb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,6 +6,8 @@ include $(TOP)/configure/CONFIG LIBRARY += easyPVA INC += easyPVA.h +INC += easyMultiDouble.h +INC += easyNTMultiChannel.h LIBSRCS += easyPVA.cpp LIBSRCS += easyPutData.cpp @@ -17,9 +19,12 @@ LIBSRCS += easyGet.cpp LIBSRCS += easyPut.cpp LIBSRCS += easyMonitor.cpp LIBSRCS += easyPutGet.cpp +LIBSRCS += easyMultiChannel.cpp +LIBSRCS += easyMultiDouble.cpp +LIBSRCS += easyNTMultiChannel.cpp #LIBSRCS += easyRPC.cpp -easyPVA_LIBS += pvAccess pvData Com +easyPVA_LIBS += pvAccess pvData nt Com easyPVA_LIBS += $(EPICS_BASE_IOC_LIBS) include $(TOP)/configure/RULES diff --git a/src/easyChannel.cpp b/src/easyChannel.cpp index 1bbc431..cadbac8 100644 --- a/src/easyChannel.cpp +++ b/src/easyChannel.cpp @@ -164,12 +164,6 @@ void EasyChannel::channelStateChange( if(waitingForConnect) waitForConnect.signal(); } -tr1::shared_ptr EasyChannel::getChannel() -{ - if(isDestroyed) throw std::runtime_error("easyChannel was destroyed"); - return channel; -} - string EasyChannel::getRequesterName() { EasyPVAPtr yyy = easyPVA.lock(); @@ -206,6 +200,12 @@ string EasyChannel::getChannelName() return channelName; } +Channel::shared_pointer EasyChannel::getChannel() +{ + if(isDestroyed) throw std::runtime_error("easyChannel was destroyed"); + return channel; +} + void EasyChannel::connect(double timeout) { if(isDestroyed) throw std::runtime_error("easyChannel was destroyed"); @@ -225,7 +225,9 @@ void EasyChannel::issueConnect() } channelRequester = ChannelRequester::shared_pointer(new ChannelRequesterImpl(this)); - channelConnectStatus = Status(Status::STATUSTYPE_ERROR,"createChannel failed"); + channelConnectStatus = Status( + Status::STATUSTYPE_ERROR, + getChannelName() + " createChannel failed"); connectState = connectActive; ChannelProviderRegistry::shared_pointer reg = getChannelProviderRegistry(); ChannelProvider::shared_pointer provider = reg->getProvider(providerName); diff --git a/src/easyGetData.cpp b/src/easyGetData.cpp index a88f902..4c72497 100644 --- a/src/easyGetData.cpp +++ b/src/easyGetData.cpp @@ -55,7 +55,7 @@ void EasyGetData::checkValue() void EasyGetData::setMessagePrefix(std::string const & value) { - messagePrefix = value; + messagePrefix = value + " "; } StructureConstPtr EasyGetData::getStructure() @@ -165,7 +165,7 @@ double EasyGetData::getDouble() return pvDouble->get(); } if(!ScalarTypeFunc::isNumeric(scalarType)) { - throw std::runtime_error(notCompatibleScalar); + throw std::runtime_error(messagePrefix + notCompatibleScalar); } return convert->toDouble(pvScalar); } diff --git a/src/easyMonitorData.cpp b/src/easyMonitorData.cpp index cef65c2..7f5d9f0 100644 --- a/src/easyMonitorData.cpp +++ b/src/easyMonitorData.cpp @@ -58,7 +58,7 @@ void EasyMonitorData::checkValue() void EasyMonitorData::setMessagePrefix(std::string const & value) { - messagePrefix = value; + messagePrefix = value + " "; } StructureConstPtr EasyMonitorData::getStructure() @@ -191,7 +191,7 @@ double EasyMonitorData::getDouble() return pvDouble->get(); } if(!ScalarTypeFunc::isNumeric(scalarType)) { - throw std::runtime_error(notCompatibleScalar); + throw std::runtime_error(messagePrefix + notCompatibleScalar); } return convert->toDouble(pvScalar); } diff --git a/src/easyMultiChannel.cpp b/src/easyMultiChannel.cpp new file mode 100644 index 0000000..a1d2f84 --- /dev/null +++ b/src/easyMultiChannel.cpp @@ -0,0 +1,165 @@ +/* easyMultiChannel.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 easyPVA { + + + +EasyMultiChannel::EasyMultiChannel( + EasyPVAPtr const &easyPVA, + PVStringArrayPtr const & channelName, + string const & providerName) +: easyPVA(easyPVA), + channelName(channelName), + providerName(providerName), + numChannel(channelName->getLength()), + isConnected(getPVDataCreate()->createPVScalarArray()), + isDestroyed(false) +{ +} + +EasyMultiChannel::~EasyMultiChannel() +{ + destroy(); +} + +void EasyMultiChannel::destroy() +{ + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + easyChannelArray.reset(); +} + +PVStringArrayPtr EasyMultiChannel::getChannelNames() +{ + if(isDestroyed) throw std::runtime_error("easyMultiChannel was destroyed"); + return channelName; +} + +Status EasyMultiChannel::connect(double timeout,size_t maxNotConnected) +{ + if(isDestroyed) throw std::runtime_error("easyMultiChannel was destroyed"); + if(easyChannelArray) throw std::runtime_error("easyMultiChannel already connected"); + EasyPVAPtr easy = easyPVA.lock(); + if(!easy) return Status(Status::STATUSTYPE_ERROR,"easyPVA is gone"); + shared_vector easyChannel(numChannel,EasyChannelPtr()); + PVStringArray::const_svector channelNames = channelName->view(); + shared_vector isConnected(numChannel,false); + for(size_t i=0; i< numChannel; ++i) { + easyChannel[i] = easy->createChannel(channelNames[i],providerName); + easyChannel[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 = easyChannel[i]->waitConnect(timeout); + } else { + status = easyChannel[i]->waitConnect(.001); + } + if(status.isOK()) { + ++numConnected; + isConnected[i] = true; + continue; + } + if(returnStatus.isOK()) returnStatus = status; + ++numBad; + if(numBad>maxNotConnected) break; + } + easyChannelArray = EasyChannelArrayPtr(new EasyChannelArray(freeze(easyChannel))); + this->isConnected->replace(freeze(isConnected)); + return numBad>maxNotConnected ? returnStatus : Status::Ok; +} + + +bool EasyMultiChannel::allConnected() +{ + if(isDestroyed) throw std::runtime_error("easyMultiChannel was destroyed"); + if(!easyChannelArray) throw std::runtime_error("easyMultiChannel not connected"); + if(numConnected==numChannel) return true; + return (numConnected==numChannel) ? true : false; +} + +bool EasyMultiChannel::connectionChange() +{ + if(isDestroyed) throw std::runtime_error("easyMultiChannel was destroyed"); + if(!easyChannelArray) throw std::runtime_error("easyMultiChannel not connected"); + if(numConnected==numChannel) return true; + PVBooleanArray::const_svector isConnected = this->isConnected->view(); + shared_vector channels = *easyChannelArray.get(); + 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; +} + +PVBooleanArrayPtr EasyMultiChannel::getIsConnected() +{ + if(isDestroyed) throw std::runtime_error("easyMultiChannel was destroyed"); + if(!easyChannelArray) throw std::runtime_error("easyMultiChannel not connected"); + if(!connectionChange()) return isConnected; + shared_vector isConnected(numChannel,false); + shared_vector channels = *easyChannelArray.get(); + for(size_t i=0; igetChannel(); + Channel::ConnectionState stateNow = channel->getConnectionState(); + if(stateNow==Channel::CONNECTED) isConnected[i] = true; + } + this->isConnected->replace(freeze(isConnected)); + return this->isConnected; +} + +EasyChannelArrayWPtr EasyMultiChannel::getEasyChannelArray() +{ + if(isDestroyed) throw std::runtime_error("easyMultiChannel was destroyed"); + if(!easyChannelArray) throw std::runtime_error("easyMultiChannel not connected"); + return easyChannelArray; +} + +EasyPVA::weak_pointer EasyMultiChannel::getEasyPVA() +{ + if(isDestroyed) throw std::runtime_error("easyMultiChannel was destroyed"); + return easyPVA; +} + +EasyMultiChannelPtr EasyMultiChannel::create( + EasyPVAPtr const &easyPVA, + PVStringArrayPtr const & channelNames, + string const & providerName) +{ + EasyMultiChannelPtr channel(new EasyMultiChannel(easyPVA,channelNames,providerName)); + return channel; +} + +}} diff --git a/src/easyMultiDouble.cpp b/src/easyMultiDouble.cpp new file mode 100644 index 0000000..c7f18f3 --- /dev/null +++ b/src/easyMultiDouble.cpp @@ -0,0 +1,138 @@ +/* easyMultiDouble.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 + */ + +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace easyPVA { + +EasyMultiDoublePtr EasyMultiDouble::create( + EasyPVAPtr const & easyPVA, + PVStringArrayPtr const & channelName, + double timeout, + std::string const & providerName) +{ + EasyMultiChannelPtr easyMultiChannel( + EasyMultiChannel::create(easyPVA,channelName,providerName)); + Status status = easyMultiChannel->connect(timeout,0); + if(!status.isOK()) throw std::runtime_error(status.getMessage()); + return EasyMultiDoublePtr(new EasyMultiDouble(easyMultiChannel)); +} + +EasyMultiDouble::EasyMultiDouble(EasyMultiChannelPtr const &easyMultiChannel) +: + easyMultiChannel(easyMultiChannel) +{} + +EasyMultiDouble::~EasyMultiDouble() +{ +} + +void EasyMultiDouble::createGet() +{ + EasyChannelArrayPtr easyChannelArray = easyMultiChannel->getEasyChannelArray().lock(); + if(!easyChannelArray) throw std::runtime_error("easyChannelArray is gone"); + shared_vector easyChannels = *easyChannelArray; + size_t numChannel = easyChannels.size(); + easyGet = std::vector(numChannel,EasyGetPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreateGet("value"); + easyGet[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); +} + +void EasyMultiDouble::createPut() +{ + EasyChannelArrayPtr easyChannelArray = easyMultiChannel->getEasyChannelArray().lock(); + if(!easyChannelArray) throw std::runtime_error("easyChannelArray is gone"); + shared_vector easyChannels = *easyChannelArray; + size_t numChannel = easyChannels.size(); + easyPut = std::vector(numChannel,EasyPutPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreatePut("value"); + easyPut[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); +} + +epics::pvData::shared_vector EasyMultiDouble::get() +{ + if(easyGet.empty()) createGet(); + shared_vector channelNames = easyMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + epics::pvData::shared_vector data(channelNames.size()); + for(size_t i=0; iissueGet(); + } + for(size_t i=0; iwaitGet(); + if(!status.isOK()) { + string message = channelNames[i] + " " + status.getMessage(); + throw std::runtime_error(message); + } + data[i] = easyGet[i]->getData()->getDouble(); + } + return data; +} + +void EasyMultiDouble::put(shared_vector const &value) +{ + if(easyPut.empty()) createPut(); + shared_vector channelNames = easyMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + for(size_t i=0; igetData()->putDouble(value[i]); + easyPut[i]->issuePut(); + } + for(size_t i=0; iwaitPut(); + if(!status.isOK()) { + string message = channelNames[i] + " " + status.getMessage(); + throw std::runtime_error(message); + } + } +} + + +}} diff --git a/src/easyMultiDouble.h b/src/easyMultiDouble.h new file mode 100644 index 0000000..f2f05e9 --- /dev/null +++ b/src/easyMultiDouble.h @@ -0,0 +1,81 @@ +/* easyMultiDouble.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 EASYMULTIDOUBLE_H +#define EASYMULTIDOUBLE_H + +#ifdef epicsExportSharedSymbols +# define easyPVAEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#include + +namespace epics { namespace easyPVA { + +class EasyMultiDouble; +typedef std::tr1::shared_ptr EasyMultiDoublePtr; + +/** + * @brief Support for multiple channels where each channel has a value field that is a scalar double. + * If any problems arise an exception is thrown. + * + * @author mrk + */ +class epicsShareClass EasyMultiDouble +{ +public: + POINTER_DEFINITIONS(EasyMultiDouble); + /** + * @brief Create a EasyMultiDouble. + * @param &easyPVA Interface to EasyPVA + * @param channelName PVStringArray of channelNames. + * @param timeout The timeout in seconds for connecting. + * @param providerName The name of the channelProvider for each channel. + * @return The interface to EasyMultiDouble. + */ + static EasyMultiDoublePtr create( + EasyPVAPtr const & easyPVA, + epics::pvData::PVStringArrayPtr const & channelName, + double timeout = 5.0, + std::string const & providerName = "pva"); + /** + * @brief destructor + */ + ~EasyMultiDouble(); + /** + * @brief destroy any resources used. + */ + void destroy(); + /** + * @brief get the value of all the channels. + * @return The data. + */ + epics::pvData::shared_vector get(); + /** + * @brief put a new value to each channel. + * @param value The data. + */ + void put(epics::pvData::shared_vector const &value); + EasyMultiChannelPtr getEasyMultiChannel(); +private: + EasyMultiDouble( + EasyMultiChannelPtr const & channelName); + void createGet(); + void createPut(); + + EasyMultiChannelPtr easyMultiChannel; + std::vector easyGet; + std::vector easyPut; +}; + +}} + +#endif // EASYMULTIDOUBLE_H diff --git a/src/easyNTMultiChannel.cpp b/src/easyNTMultiChannel.cpp new file mode 100644 index 0000000..b42e0c4 --- /dev/null +++ b/src/easyNTMultiChannel.cpp @@ -0,0 +1,262 @@ +/* easyNTMultiChannel.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 + */ + +#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 easyPVA { + +EasyNTMultiChannelPtr EasyNTMultiChannel::create( + EasyPVAPtr const & easyPVA, + PVStringArrayPtr const & channelName, + StructureConstPtr const &structure, + double timeout, + std::string const & providerName) +{ + EasyMultiChannelPtr easyMultiChannel( + EasyMultiChannel::create(easyPVA,channelName,providerName)); + Status status = easyMultiChannel->connect(timeout,0); + if(!status.isOK()) throw std::runtime_error(status.getMessage()); + if(!NTMultiChannel::is_a(structure)) throw std::runtime_error("structure is not valid"); + PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure); + pvStructure->getSubField("channelName")-> + replace(easyMultiChannel->getChannelNames()->view()); + pvStructure->getSubField("isConnected")-> + replace(easyMultiChannel->getIsConnected()->view()); + NTMultiChannelPtr ntMultiChannel(NTMultiChannel::wrap(pvStructure)); + return EasyNTMultiChannelPtr(new EasyNTMultiChannel(easyMultiChannel,ntMultiChannel)); +} + +EasyNTMultiChannel::EasyNTMultiChannel( + EasyMultiChannelPtr const &easyMultiChannel, + NTMultiChannelPtr const &ntMultiChannel) +: + easyMultiChannel(easyMultiChannel), + ntMultiChannel(ntMultiChannel), + pvUnionArray(ntMultiChannel->getPVStructure()->getSubField("value")), + pvDataCreate(getPVDataCreate()) +{} + +EasyNTMultiChannel::~EasyNTMultiChannel() +{ +} + +void EasyNTMultiChannel::createGet() +{ + PVStructurePtr pvStructure = ntMultiChannel->getPVStructure(); + bool getAlarm = false; + if(pvStructure->getSubField("severity")) getAlarm = true; + if(pvStructure->getSubField("status")) getAlarm = true; + if(pvStructure->getSubField("severity")) getAlarm = true; + bool getTimeStamp = false; + if(pvStructure->getSubField("secondsPastEpoch")) getTimeStamp = true; + if(pvStructure->getSubField("nanoseconds")) getTimeStamp = true; + if(pvStructure->getSubField("userTag")) getTimeStamp = true; + string request = "value"; + if(getAlarm) request += ",alarm"; + if(getTimeStamp) request += ",timeStamp"; + EasyChannelArrayPtr easyChannelArray = easyMultiChannel->getEasyChannelArray().lock(); + if(!easyChannelArray) throw std::runtime_error("easyChannelArray is gone"); + shared_vector easyChannels = *easyChannelArray; + size_t numChannel = easyChannels.size(); + easyGet = std::vector(numChannel,EasyGetPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreateGet(request); + easyGet[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); + +} + +void EasyNTMultiChannel::createPut() +{ + EasyChannelArrayPtr easyChannelArray = easyMultiChannel->getEasyChannelArray().lock(); + if(!easyChannelArray) throw std::runtime_error("easyChannelArray is gone"); + shared_vector easyChannels = *easyChannelArray; + size_t numChannel = easyChannels.size(); + easyPut = std::vector(numChannel,EasyPutPtr()); + bool allOK = true; + string message; + for(size_t i=0; icreatePut("value"); + easyPut[i]->issueConnect(); + } + for(size_t i=0; iwaitConnect(); + if(!status.isOK()) { + message = "connect status " + status.getMessage(); + allOK = false; + break; + } + } + if(!allOK) throw std::runtime_error(message); +} + +NTMultiChannelPtr EasyNTMultiChannel::get() +{ + if(easyGet.empty()) createGet(); + PVStructurePtr pvStructure = ntMultiChannel->getPVStructure(); + shared_vector channelNames = easyMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + bool severityExists = false; + bool statusExists = false; + bool messageExists = false; + bool secondsPastEpochExists = false; + bool nanosecondsExists = false; + bool userTagExists = false; + if(pvStructure->getSubField("severity")) { + severity.resize(numChannel); + severityExists = true; + } + if(pvStructure->getSubField("status")) { + status.resize(numChannel); + statusExists = true; + } + if(pvStructure->getSubField("message")) { + message.resize(numChannel); + messageExists = true; + } + if(pvStructure->getSubField("secondsPastEpoch")) { + secondsPastEpoch.resize(numChannel); + secondsPastEpochExists = true; + } + if(pvStructure->getSubField("nanoseconds")) { + nanoseconds.resize(numChannel); + nanosecondsExists = true; + } + if(pvStructure->getSubField("userTag")) { + userTag.resize(numChannel); + userTagExists = true; + } + valueVector.resize(numChannel); + + for(size_t i=0; iissueGet(); + } + for(size_t i=0; iwaitGet(); + if(!stat.isOK()) { + string message = channelNames[i] + " " + stat.getMessage(); + throw std::runtime_error(message); + } + PVStructurePtr pvStructure = easyGet[i]->getData()->getPVStructure(); + PVFieldPtr pvField = pvStructure->getSubField("value"); + if(!pvField) { + string message = channelNames[i] + " no value field"; + throw std::runtime_error(message); + } + UnionConstPtr u = pvUnionArray->getUnionArray()->getUnion(); + if(u->isVariant()) { + PVUnionPtr pvUnion = pvDataCreate->createPVVariantUnion(); + pvUnion->set(pvField); + valueVector[i] = pvUnion; + } else { + PVUnionPtr pvUnion = pvDataCreate->createPVUnion(u); + pvUnion->set(pvField); + valueVector[i] = pvUnion; + } + pvField = pvStructure->getSubField("alarm"); + if(pvField) { + if(pvAlarm.attach(pvField)) { + pvAlarm.get(alarm); + if(severityExists) severity[i] = alarm.getSeverity(); + if(statusExists) status[i] = alarm.getStatus(); + if(messageExists) message[i] = alarm.getMessage(); + } + } + pvField = pvStructure->getSubField("timeStamp"); + if(pvField) { + if(pvTimeStamp.attach(pvField)) { + pvTimeStamp.get(timeStamp); + if(secondsPastEpochExists) secondsPastEpoch[i] = + timeStamp.getSecondsPastEpoch(); + if(nanosecondsExists) nanoseconds[i] = + timeStamp.getNanoseconds(); + if(userTagExists) userTag[i] = timeStamp.getUserTag(); + } + } + } + pvUnionArray->replace(freeze(valueVector)); + if(severityExists) { + pvStructure->getSubField("severity")->replace( + freeze(severity)); + } + if(statusExists) { + pvStructure->getSubField("status")->replace( + freeze(status)); + } + if(messageExists) { + pvStructure->getSubField("message")->replace(freeze(message)); + } + if(secondsPastEpochExists) { + pvStructure->getSubField("secondsPastEpoch")->replace(freeze(secondsPastEpoch)); + } + if(nanosecondsExists) { + pvStructure->getSubField("nanoseconds")->replace(freeze(nanoseconds)); + } + if(userTagExists) { + pvStructure->getSubField("userTag")->replace(freeze(userTag)); + } + return ntMultiChannel; +} + +void EasyNTMultiChannel::put(NTMultiChannelPtr const &value) +{ + if(easyPut.empty()) createPut(); + shared_vector channelNames = easyMultiChannel->getChannelNames()->view(); + size_t numChannel = channelNames.size(); + PVUnionArrayPtr pvValue = value->getPVStructure()-> + getSubField("value"); + shared_vector valueVector = pvValue->view(); + for(size_t i=0; iget(); + PVFieldPtr pvTo = easyPut[i]->getData()->getValue(); + pvTo->copy(*pvFrom); + easyPut[i]->issuePut(); + } catch (std::exception e) { + string message = channelNames[i] + e.what(); + throw std::runtime_error(message); + } + } + for(size_t i=0; iwaitPut(); + if(!status.isOK()) { + string message = channelNames[i] + " " + status.getMessage(); + throw std::runtime_error(message); + } + } +} + +}} diff --git a/src/easyNTMultiChannel.h b/src/easyNTMultiChannel.h new file mode 100644 index 0000000..f8ff34a --- /dev/null +++ b/src/easyNTMultiChannel.h @@ -0,0 +1,102 @@ +/* easyNTMultiChannel.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 EASYNTMULTIChannel_H +#define EASYNTMULTIChannel_H + +#ifdef epicsExportSharedSymbols +# define easyPVAEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#include + +namespace epics { namespace easyPVA { + +class EasyNTMultiChannel; +typedef std::tr1::shared_ptr EasyNTMultiChannelPtr; + +/** + * @brief Support for multiple channels where each channel has a value field that is a scalar double. + * If any problems arise an exception is thrown. + * + * @author mrk + */ +class epicsShareClass EasyNTMultiChannel +{ +public: + POINTER_DEFINITIONS(EasyNTMultiChannel); + /** + * @brief Create a EasyNTMultiChannel. + * @param &easyPVA Interface to EasyPVA + * @param channelName PVStringArray of channelNames. + * @param structure valid NTMultiChannel structure. + * @param timeout Timeout for connecting. + * @param providerName The provider for each channel. + * @return The interface to EasyNTMultiChannel. + */ + static EasyNTMultiChannelPtr create( + EasyPVAPtr const & easyPVA, + epics::pvData::PVStringArrayPtr const & channelName, + epics::pvData::StructureConstPtr const & structure, + double timeout = 5.0, + std::string const & providerName = "pva"); + /** + * @brief destructor + */ + ~EasyNTMultiChannel(); + /** + * @brief destroy any resources used. + */ + void destroy(); + /** + * @brief get the value of all the channels. + * @return The data. + */ + epics::nt::NTMultiChannelPtr get(); + /** + * @brief put a new value to each channel. + * @param value The data. + */ + void put(epics::nt::NTMultiChannelPtr const &value); + /** + * @brief Get the EasyMultiChannel. + * @return The interface. + */ + EasyMultiChannelPtr getEasyMultiChannel(); +private: + EasyNTMultiChannel( + EasyMultiChannelPtr const & channelName, + epics::nt::NTMultiChannelPtr const &ntMultiChannel); + void createGet(); + void createPut(); + + EasyMultiChannelPtr easyMultiChannel; + epics::nt::NTMultiChannelPtr ntMultiChannel; + epics::pvData::PVUnionArrayPtr pvUnionArray; + epics::pvData::PVDataCreatePtr pvDataCreate; + std::vector easyGet; + std::vector easyPut; + epics::pvData::shared_vector valueVector; + 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; +}; + +}} + +#endif // EASYNTMULTIChannel_H diff --git a/src/easyPVA.cpp b/src/easyPVA.cpp index 640b67c..89a022d 100644 --- a/src/easyPVA.cpp +++ b/src/easyPVA.cpp @@ -174,5 +174,18 @@ EasyChannelPtr EasyPVA::createChannel(string const & channelName, string const & return EasyChannel::create(getPtrSelf(),channelName,providerName); } +EasyMultiChannelPtr EasyPVA::createMultiChannel( + epics::pvData::PVStringArrayPtr const & channelNames) +{ + return createMultiChannel(channelNames,"pva"); +} + +EasyMultiChannelPtr EasyPVA::createMultiChannel( + epics::pvData::PVStringArrayPtr const & channelNames, + std::string const & providerName) +{ + return EasyMultiChannel::create(getPtrSelf(),channelNames,providerName); +} + }} diff --git a/src/easyPVA.h b/src/easyPVA.h index 956e974..4bf25ab 100644 --- a/src/easyPVA.h +++ b/src/easyPVA.h @@ -32,6 +32,7 @@ #include #include #include +#include #ifdef easyPVAEpicsExportSharedSymbols # define epicsExportSharedSymbols @@ -72,16 +73,13 @@ typedef std::tr1::shared_ptr EasyArrayPtr; class EasyRPC; typedef std::tr1::shared_ptr EasyRPCPtr; -class EasyMultiData; -typedef std::tr1::shared_ptr EasyMultiDataPtr; +typedef epics::pvData::shared_vector EasyChannelArray; +typedef std::tr1::shared_ptr EasyChannelArrayPtr; +typedef std::tr1::weak_ptr EasyChannelArrayWPtr; + class EasyMultiChannel; typedef std::tr1::shared_ptr EasyMultiChannelPtr; -class EasyMultiGet; -typedef std::tr1::shared_ptr EasyMultiGetPtr; -class EasyMultiPut; -typedef std::tr1::shared_ptr EasyMultiPutPtr; -class EasyMultiMonitor; -typedef std::tr1::shared_ptr EasyMultiMonitorPtr; +class EasyMultiChannelGet; // following are private to easyPVA class EasyChannelCache; @@ -165,7 +163,8 @@ public: * @param channelName The channelName array. * @return The interface. */ - EasyMultiChannelPtr createMultiChannel(epics::pvData::StringArray const & channelName); + EasyMultiChannelPtr createMultiChannel( + epics::pvData::PVStringArrayPtr const & channelNames); /** * @brief Create an EasyMultiChannel with the specified provider. * @param channelName The channelName array. @@ -173,19 +172,8 @@ public: * @return The interface. */ EasyMultiChannelPtr createMultiChannel( - epics::pvData::StringArray const & channelName, - std::string const & providerName); - /** - * @brief Create an EasyMultiChannel with the specified provider. - * @param channelName The channelName. - * @param providerName The provider. - * @param union The union interface for the value field of each channel. - * @return The interface. - */ - EasyMultiChannelPtr createMultiChannel( - epics::pvData::StringArray const & channelName, - std::string const & providerName, - epics::pvData::UnionConstPtr const & u); + epics::pvData::PVStringArrayPtr const & channelNames, + std::string const & providerName); /** * @brief Set a requester. * The default is for EasyPVA to handle messages by printing to System.out. @@ -235,11 +223,12 @@ public: * @brief Create a EasyChannel. * @param easyPVA Interface to EasyPVA * @param channelName The name of the channel. - * @return The interface to the EasyPVAStructure. + * @return The interface. */ static EasyChannelPtr create( EasyPVAPtr const &easyPVA, - std::string const & channelName) {return create(easyPVA,channelName,"pva");} + std::string const & channelName) + {return create(easyPVA,channelName,"pva");} /** * @brief Create a EasyChannel. * @param channelName The name of the channel. @@ -260,13 +249,18 @@ public: * @return The channel name. */ std::string getChannelName(); + /** + * @brief Get the the channel to which EasyChannel is connected. + * @return The channel interface. + */ + epics::pvAccess::Channel::shared_pointer getChannel(); /** * @brief Connect to the channel. * This calls issueConnect and waitConnect. * An exception is thrown if connect fails. * @param timeout The time to wait for connecting to the channel. */ - void connect(double timeout); + void connect(double timeout=5.0); /** * @brief Issue a connect request and return immediately. */ @@ -479,7 +473,6 @@ private: void channelStateChange( epics::pvAccess::Channel::shared_pointer const & channel, epics::pvAccess::Channel::ConnectionState connectionState); - std::tr1::shared_ptr getChannel(); std::string getRequesterName(); void message( std::string const & message, @@ -916,7 +909,7 @@ private: epics::pvData::PVTimeStamp pvTimeStamp; }; -class ChannelProcessRequesterImpl; // private to ChannelProcess. +class ChannelProcessRequesterImpl; // private to EasyProcess /** * @brief An easy to use alternative to ChannelProcess. * @@ -1016,7 +1009,7 @@ private: friend class ChannelProcessRequesterImpl; }; -class ChannelGetRequesterImpl; // private to ChannelGet. +class ChannelGetRequesterImpl; // private to EasyGet /** * @brief An easy to use alternative to ChannelGet. * @@ -1125,7 +1118,7 @@ private: friend class ChannelGetRequesterImpl; }; -class ChannelPutRequesterImpl; // private to ChannelPut. +class ChannelPutRequesterImpl; // private to EasyPut /** * @brief An easy to use alternative to ChannelPut. * @@ -1251,7 +1244,7 @@ private : friend class ChannelPutRequesterImpl; }; -class ChannelPutGetRequesterImpl; // private to ChannelPutGet. +class ChannelPutGetRequesterImpl; // private to EasyPutGet /** * @brief An easy to use alternative to ChannelPutGet. * @@ -1558,13 +1551,107 @@ private: friend class ChannelMonitorRequester; }; +/** + * @brief Provides access to multiple channels. + * + * @author mrk + */ +class epicsShareClass EasyMultiChannel : + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(EasyMultiChannel); + /** + * @brief Create a EasyMultiChannel. + * @param channelNames The name. of the channel.. + * @param providerName The name of the provider. + * @param u The union interface for each channel. + * @return The interface to the EasyPVAStructure. + */ + static EasyMultiChannelPtr create( + EasyPVAPtr const &easyPVA, + epics::pvData::PVStringArrayPtr const & channelNames, + std::string const & providerName = "pva"); + ~EasyMultiChannel(); + /** + * @brief Destroy the pvAccess connection. + */ + void destroy(); + /** + * @brief Get the channelNames. + * @return The names. + */ + epics::pvData::PVStringArrayPtr getChannelNames(); + /** + * @brief Connect to the channel. + * This calls issueConnect and waitConnect. + * An exception is thrown if connect fails. + * @param timeout The time to wait for connecting to the channel. + * @param maxNotConnected Maximum number of channels that do not connect. + * @return status of request + */ + epics::pvData::Status connect( + double timeout=5, + size_t maxNotConnected=0); + /** + * 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::PVBooleanArrayPtr getIsConnected(); + /** + * Get the easyChannelArray. + * @return The weak shared pointer. + */ + EasyChannelArrayWPtr getEasyChannelArray(); + /** + * Get easyPVA. + * @return The weak shared pointer. + */ + EasyPVA::weak_pointer getEasyPVA(); + /** + * Get the shared pointer to self. + * @return The shared pointer. + */ + EasyMultiChannelPtr getPtrSelf() + { + return shared_from_this(); + } +private: + EasyMultiChannel( + EasyPVAPtr const &pva, + epics::pvData::PVStringArrayPtr const & channelName, + std::string const & providerName); + + EasyPVA::weak_pointer easyPVA; + epics::pvData::PVStringArrayPtr channelName; + std::string providerName; + size_t numChannel; + epics::pvData::Mutex mutex; + + size_t numConnected; + EasyChannelArrayPtr easyChannelArray; + epics::pvData::PVBooleanArrayPtr isConnected; + bool isDestroyed; +}; + + }} #endif /* EASYPVA_H */ /** @page Overview Documentation * - *
easyPVA.html + * overview.html * */ diff --git a/src/easyPutData.cpp b/src/easyPutData.cpp index 1866a91..4df9fe6 100644 --- a/src/easyPutData.cpp +++ b/src/easyPutData.cpp @@ -86,7 +86,7 @@ void EasyPutData::postPut(size_t fieldNumber) void EasyPutData::setMessagePrefix(std::string const & value) { - messagePrefix = value; + messagePrefix = value + " "; } StructureConstPtr EasyPutData::getStructure() @@ -221,7 +221,7 @@ void EasyPutData::putDouble(double value) pvDouble->put(value); } if(!ScalarTypeFunc::isNumeric(scalarType)) { - throw std::runtime_error(notCompatibleScalar); + throw std::runtime_error(messagePrefix + notCompatibleScalar); } convert->fromDouble(pvScalar,value); } diff --git a/test/src/Makefile b/test/src/Makefile index 389b5b4..04dffde 100644 --- a/test/src/Makefile +++ b/test/src/Makefile @@ -28,8 +28,18 @@ testEasyPutGet_SRCS = testEasyPutGet testHarness_SRCS += testEasyPutGet.cpp TESTS += testEasyPutGet +TESTPROD_HOST += testEasyMultiDouble +testEasyMultiDouble_SRCS = testEasyMultiDouble +testHarness_SRCS += testEasyMultiDouble.cpp +TESTS += testEasyMultiDouble -PROD_LIBS += easyPVA pvAccess pvData Com +TESTPROD_HOST += testEasyNTMultiChannel +testEasyNTMultiChannel_SRCS = testEasyNTMultiChannel +testHarness_SRCS += testEasyNTMultiChannel.cpp +TESTS += testEasyNTMultiChannel + + +PROD_LIBS += easyPVA pvAccess pvData nt Com testHarness_SRCS += easyAllTests.c diff --git a/test/src/easyAllTests.c b/test/src/easyAllTests.c index 4a46bf9..810e8d9 100644 --- a/test/src/easyAllTests.c +++ b/test/src/easyAllTests.c @@ -14,6 +14,8 @@ int testEasyPutData(void); int testEasyMonitorData(void); int testEasyPutGetMonitor(void); int testEasyPutGet(void); +int testEasyMultiDouble(void); +int testEasyNTMultiChannel(void); void easyAllTests(void) { @@ -23,5 +25,7 @@ void easyAllTests(void) runTest(testEasyMonitorData); runTest(testEasyPutMonitor); runTest(testEasyPut); + runTest(testEasyMultiDouble); + runTest(testEasyNTMultiChannel); } diff --git a/test/src/testEasyMultiDouble.cpp b/test/src/testEasyMultiDouble.cpp new file mode 100644 index 0000000..e48ecd6 --- /dev/null +++ b/test/src/testEasyMultiDouble.cpp @@ -0,0 +1,156 @@ +/*testEasyMultiDouble.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 +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::easyPVA; + + +static void testGood(EasyPVAPtr const &easyPVA) +{ + bool isOk = true; + cout << "\nstarting testGood\n"; + try { + EasyPVAPtr easyPVA(EasyPVA::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "exampleDouble04"; + channelNames[4] = "exampleDouble05"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + EasyMultiDoublePtr multiDouble(EasyMultiDouble::create(easyPVA,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==true,"all channels double"); +} + +static void testGoodMixed(EasyPVAPtr const &easyPVA) +{ + bool isOk = true; + cout << "\nstarting testGoodMixed\n"; + try { + EasyPVAPtr easyPVA(EasyPVA::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleByte"; + channelNames[1] = "exampleShort"; + channelNames[2] = "exampleInt"; + channelNames[3] = "exampleFloat"; + channelNames[4] = "exampleDouble"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + EasyMultiDoublePtr multiDouble(EasyMultiDouble::create(easyPVA,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==true,"channels mixed type"); +} + +static void testChannelNotExist(EasyPVAPtr const &easyPVA) +{ + bool isOk = true; + cout << "\nstarting testChannelNotExist\n"; + try { + EasyPVAPtr easyPVA(EasyPVA::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "NoneExistChannel"; + channelNames[4] = "exampleDouble05"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + EasyMultiDoublePtr multiDouble(EasyMultiDouble::create(easyPVA,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==false,"channel not exist"); +} + +static void testNonNumeric(EasyPVAPtr const &easyPVA) +{ + bool isOk = true; + cout << "\nstarting testNonNumeric\n"; + try { + EasyPVAPtr easyPVA(EasyPVA::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble01"; + channelNames[1] = "exampleDouble02"; + channelNames[2] = "exampleDouble03"; + channelNames[3] = "exampleDouble04"; + channelNames[4] = "exampleDouble05Array"; + PVStringArrayPtr pvNames = + getPVDataCreate()->createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + EasyMultiDoublePtr multiDouble(EasyMultiDouble::create(easyPVA,pvNames)); + shared_vector data = multiDouble->get(); + cout << "initial " << data << endl; + for(size_t i=0; iput(data); + data = multiDouble->get(); + cout << "final " << data << endl; + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==false,"channel not numeric"); +} + +MAIN(testEasyMultiDouble) +{ + cout << "\nstarting testEasyMultiDouble\n"; + testPlan(4); + EasyPVAPtr easyPVA = EasyPVA::create(); + testGood(easyPVA); + testGoodMixed(easyPVA); + testChannelNotExist(easyPVA); + testNonNumeric(easyPVA); + cout << "done\n"; + return 0; +} diff --git a/test/src/testEasyNTMultiChannel.cpp b/test/src/testEasyNTMultiChannel.cpp new file mode 100644 index 0000000..793d77a --- /dev/null +++ b/test/src/testEasyNTMultiChannel.cpp @@ -0,0 +1,132 @@ +/*testEasyNTMultiChannel.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 +#include + +using namespace std; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::easyPVA; +using namespace epics::nt; +using std::tr1::static_pointer_cast; + + +static void testGood(EasyPVAPtr const &easyPVA) +{ + PVDataCreatePtr pvDataCreate(getPVDataCreate()); + bool isOk = true; + cout << "\nstarting testGood\n"; + try { + EasyPVAPtr easyPVA(EasyPVA::create()); + size_t num = 5; + shared_vector channelNames(num); + channelNames[0] = "exampleDouble"; + channelNames[1] = "exampleDoubleArray"; + channelNames[2] = "exampleString"; + channelNames[3] = "exampleBoolean"; + channelNames[4] = "exampleEnum"; + PVStringArrayPtr pvNames = pvDataCreate-> + createPVScalarArray(); + pvNames->replace(freeze(channelNames)); + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + StructureConstPtr structure = builder-> + addTimeStamp()-> + addSeverity() -> + addStatus() -> + addMessage() -> + addSecondsPastEpoch() -> + addNanoseconds() -> + addUserTag() -> + createStructure(); + EasyNTMultiChannelPtr easy = EasyNTMultiChannel::create( + easyPVA,pvNames,structure); + NTMultiChannelPtr nt = easy->get(); + cout << "initial\n" << nt->getPVStructure() << endl; + for(size_t numtimes=0; numtimes<3; ++numtimes) { + PVUnionArrayPtr pvValue = nt->getPVStructure()-> + getSubField("value"); + shared_vector valueVector = pvValue->reuse(); + for(size_t i=0; iget(); + Type type = pvField->getField()->getType(); + if(type==scalar) { + PVScalarPtr pvScalar = static_pointer_cast(pvField); + ScalarType scalarType = pvScalar->getScalar()->getScalarType(); + if(ScalarTypeFunc::isNumeric(scalarType)) { + double oldValue = pvScalar->getAs(); + oldValue++; + pvScalar->putFrom(oldValue); + } else if(scalarType==pvString) { + PVStringPtr pv = static_pointer_cast(pvField); + string val = pv->get(); + val += " added"; + pv->put(val); + } else if(scalarType==pvBoolean) { + PVBooleanPtr pv = static_pointer_cast(pvField); + bool val = pv->get(); + pv->put(!val); + } + } else if(type==scalarArray) { + PVScalarArrayPtr pv = + static_pointer_cast(pvField); + ScalarType scalarType = pv->getScalarArray()->getElementType(); + if(scalarType==pvDouble) { + PVDoubleArrayPtr pvd = static_pointer_cast(pv); + shared_vector valvec = pvd->reuse(); + if(valvec.capacity()==0) { + valvec.resize(4); + for(size_t i=0; ireplace(freeze(valvec)); + } + } else if(type==epics::pvData::structure) { + PVStructurePtr pvStructure = static_pointer_cast(pvField); + PVIntPtr pv = pvStructure->getSubField("index"); + if(pv) { + PVStringArrayPtr choices = pvStructure->getSubField("choices"); + if(choices) { + int32 nchoices = choices->getLength(); + int32 oldval = pv->get(); + int32 newval = (oldval==nchoices) ? 0 : ++oldval; + pv->put(newval); + } + } + } + } + pvValue->replace(freeze(valueVector)); + easy->put(nt); + nt = easy->get(); + cout << "after put\n" << nt->getPVStructure() << endl; + } + } catch (std::runtime_error e) { + cout << "exception " << e.what() << endl; + isOk = false; + } + testOk(isOk==true,"no problems"); +} + + +MAIN(testEasyNTMultiChannel) +{ + cout << "\nstarting testEasyNTMultiChannel\n"; + testPlan(1); + EasyPVAPtr easyPVA = EasyPVA::create(); + testGood(easyPVA); + cout << "done\n"; + return 0; +} diff --git a/test/src/testEasyPutData.cpp b/test/src/testEasyPutData.cpp index 1bf9e14..aac091e 100644 --- a/test/src/testEasyPutData.cpp +++ b/test/src/testEasyPutData.cpp @@ -1,4 +1,4 @@ -/*testEasyData.cpp */ +/*testEasyPutData.cpp */ /** * Copyright - See the COPYRIGHT that is included with this distribution. * EPICS pvData is distributed subject to a Software License Agreement found diff --git a/test/src/testEasyPutGetMonitor.cpp b/test/src/testEasyPutGetMonitor.cpp index 498efde..f020686 100644 --- a/test/src/testEasyPutGetMonitor.cpp +++ b/test/src/testEasyPutGetMonitor.cpp @@ -1,4 +1,4 @@ -/*exampleEasyPutGetMonitor.cpp */ +/*testEasyPutGetMonitor.cpp */ /** * Copyright - See the COPYRIGHT that is included with this distribution. * EPICS pvData is distributed subject to a Software License Agreement found