Merge pull request #6 from mrkraimer/master

add pvaClientMultiChannel and pvaClientMultiDouble
This commit is contained in:
Marty Kraimer
2015-08-04 06:48:30 -04:00
12 changed files with 1051 additions and 60 deletions

View File

@@ -28,7 +28,7 @@
<h1>EPICS pvaClientCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS V4 Working Group, Working Draft,
26-June-2015</h2>
03-August-2015</h2>
<dl>
<dt>This version:</dt>
<dd><a
@@ -36,12 +36,12 @@
</a> </dd>
<dt>Latest version:</dt>
<dd><a
href="pvaClientCPP_20150626.html">pvaClientCPP_20150626.html
href="pvaClientCPP_20150803.html">pvaClientCPP_20150803.html
</a> </dd>
<dt>Previous version:</dt>
<dd><a
href="easyPVA_20150609.html">easyPVA_20150609.html</a>
</dd>
href="pvaClientCPP_20150626.html">pvaClientCPP_20150626.html
</a> </dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
@@ -58,6 +58,7 @@ software support for high speed controls network communications used in EPICS ve
pvAccess provides a callback based interface, which can be hard to use.
pvaClient provides an interface that does not require callbacks even for monitors.
</p>
<p>
pvaClientChannel provides many "convenience" methods to directly get and put
scalar and scalarArray data types.
Additional methods provide access to the full features of pvAccess.
@@ -111,26 +112,13 @@ href="./html/index.html">doxygenDoc
</a>
</p>
<h2>Example Database</h2>
<p>The examples require that an example pvAccess server is runnimg.
To get the test database go to:</p>
<a
href="https://github.com/epics_base/pvaClientTestCPP/blob/master/database.zip">pvaClientTestCPP/database.zip
</a>
Then select "raw file" and You will be able to download the zip file.
<p>
When unzipped this is used to create an example IOC database.
</p>
<p>
After unzipping the file:
</p>
<p>The examples require that the database provided by project pvaClientTestCPP
is running.
For example:</p>
<pre>
cd database/configure
cp ExampleRELEASE.local RELEASE.local
edit RELEASE.local
cd ..
make
cd iocBoot/exampleDatabase
../../bin/&lt;arch:&gt;/exampleDatabase st.cmd
mrk&gt; pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk&gt; ../../bin/linux-x86_64/exampleDatabase st.cmd
</pre>
<h2>Examples</h2>
<p>Examples are in directory <b>example/src</b>.
@@ -172,24 +160,19 @@ helps to also look at the source for the example.</p>
</dl>
<h2>examplePvaClientMonitor</h2>
<p>This is an example of creating a monitor on a channel.
It monitors a channel that models a powerSupply, i. e. it is not a "standard" record.
It does not have a value field.
It monitors a scalar double field.
It also issues puts to the same channel so that it can make the monitors occur.
</p>
<p>After starting the example a change can be made to the powerSupply by issuing:</p>
<pre>
pvput -r "power.value,voltage.value" examplePowerSupply 6 6
</pre>
<h2>examplePvaClientPut</h2>
<p>This example gets and puts to channel exampleDouble.</p>
<p>This example gets and puts to channels exampleDouble
and exampleDoubleArray.</p>
<h2>examplePvaClientProcess</h2>
<p>This example makes a process request to channel exampleDouble.</p>
<h2>helloWorldPutGet</h2>
<p>This is an example of issuing a channelPutGet.</p>
<h2>examplePvaClientMultiDouble</h2>
<p>This is an example of issuing gets and puts to multiple channels where each
channel has a numeric scalar value field.</p>
<h2>examplePvaClientNTMultiChannel</h2>
<p>This is an example of using NDMultiChannel to obtain data from multiple channels.
<p>This is an example of using pvaClientMultiChannel,
pvaClientMultiGetDouble, pvaClientMultiPutDouble, and pvaClientMultiMonitorDouble.
</p>
<h2>helloWorldRPC</h2>
<p>This is an example of issuing a channelRPC request.

View File

@@ -297,23 +297,15 @@ It has methods:</p>
<h2>PvaClientMultiChannel - Wrapper For Multiple Channels</h2>
<h3>PvaClientMultiChannel</h3>
<p>This provides methods for connecting to multiple channels.
A client can either use PvaClientMultiChannel directly or use PvaClientMultiDouble or PvaClientNTMultiChannel.
But both impose restrictions on what can be accessed.
</p>
<h3>PvaClientMultiDouble</h3>
<p>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 the data as a PVDoubleArray.
All channels must connect.
If any problems occur an exception is thrown.
<h3>PvaClientMultiGetDouble</h3>
<p>This provides support for channelGet to multiple channels.
</p>
<h3>PvaClientNTMultiChannel</h3>
<p>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 the 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.
<h3>PvaClientMultiPutDouble</h3>
<p>This provides support for channelPut to multiple channels.
</p>
<h3>PvaClientMultiMonitorDouble</h3>
<p>This provides support for monitoring changes to multiple channels.
</p>
</div> <!-- class="contents" -->

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 <iostream>
#include <pv/pvaClientMultiChannel.h>
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 string> 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<double> data(num,0);
for(double value = 0.0; value< 1.0; value+= .2) {
try {
for(size_t i=0; i<num; ++i) data[i] = value + i;
cout << "put " << data << endl;
multiPut->put(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<string> channelNames(num);
channelNames[0] = "double01";
channelNames[1] = "double02";
channelNames[2] = "double03";
channelNames[3] = "double04";
channelNames[4] = "double05";
cout << "double pva\n";
shared_vector<const string> names(freeze(channelNames));
example(pva,"pva",names);
cout << "double ca\n";
example(pva,"ca",names);
channelNames = shared_vector<string>(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;
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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 <map>
#include <sstream>
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/pvaClientMultiChannel.h>
#include <pv/createRequest.h>
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 string> 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 string> 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<bool>(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<const string> 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; i<numChannel; ++i) {
PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i];
Channel::shared_pointer channel = pvaClientChannel->getChannel();
Channel::ConnectionState stateNow = channel->getConnectionState();
bool connectedNow = stateNow==Channel::CONNECTED ? true : false;
if(connectedNow!=isConnected[i]) return true;
}
return false;
}
epics::pvData::shared_vector<bool> PvaClientMultiChannel::getIsConnected()
{
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
for(size_t i=0; i<numChannel; ++i) {
PvaClientChannelPtr pvaClientChannel = pvaClientChannelArray[i];
if(!pvaClientChannel) {
isConnected[i] = false;
continue;
}
Channel::shared_pointer channel = pvaClientChannel->getChannel();
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);
}
}}

331
src/pvaClientMultiChannel.h Normal file
View File

@@ -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 <pv/pvaClient.h>
#include <pv/ntmultiChannel.h>
namespace epics { namespace pvaClient {
class PvaClientMultiChannel;
typedef std::tr1::shared_ptr<PvaClientMultiChannel> PvaClientMultiChannelPtr;
class PvaClientMultiGetDouble;
typedef std::tr1::shared_ptr<PvaClientMultiGetDouble> PvaClientMultiGetDoublePtr;
class PvaClientMultiPutDouble;
typedef std::tr1::shared_ptr<PvaClientMultiPutDouble> PvaClientMultiPutDoublePtr;
class PvaClientMultiMonitorDouble;
typedef std::tr1::shared_ptr<PvaClientMultiMonitorDouble> PvaClientMultiMonitorDoublePtr;
typedef epics::pvData::shared_vector<PvaClientChannelPtr> PvaClientChannelArray;
/**
* Provides access to multiple channels.
*
* @author mrk
*/
class epicsShareClass PvaClientMultiChannel :
public std::tr1::enable_shared_from_this<PvaClientMultiChannel>
{
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 std::string> 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<const std::string> 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<bool> 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 std::string> const & channelName,
std::string const & providerName,
size_t maxNotConnected);
void checkConnected();
PvaClientPtr pvaClient;
epics::pvData::shared_vector<const std::string> channelName;
std::string providerName;
size_t maxNotConnected;
size_t numChannel;
epics::pvData::Mutex mutex;
size_t numConnected;
PvaClientChannelArray pvaClientChannelArray;
epics::pvData::shared_vector<bool> 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<PvaClientMultiGetDouble>
{
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<double> 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<double> doubleValue;
std::vector<PvaClientGetPtr> 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<PvaClientMultiPutDouble>
{
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<double> 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<PvaClientPutPtr> 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<PvaClientMultiMonitorDouble>
{
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<double> 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<double> doubleValue;
std::vector<PvaClientMonitorPtr> pvaClientMonitor;
bool isMonitorConnected;
bool isDestroyed;
};
}}
#endif /* PVACLIENTMULTICHANNEL_H */
/** @page Overview Documentation
*
* <a href = "../pvaClientOverview.html">pvaClientOverview.html</a>
*
*/

View File

@@ -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 <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
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<double>(nchannel)),
pvaClientGet(std::vector<PvaClientGetPtr>(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<bool> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
pvaClientGet[i] = pvaClientChannelArray[i]->createGet(request);
pvaClientGet[i]->issueConnect();
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
Status status = pvaClientGet[i]->waitConnect();
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<double> PvaClientMultiGetDouble::get()
{
if(!isGetConnected) connect();
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
pvaClientGet[i]->issueGet();
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
Status status = pvaClientGet[i]->waitGet();
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; i<nchannel; ++i)
{
if(isConnected[i])
{
PVStructurePtr pvStructure = pvaClientGet[i]->getData()->getPVStructure();
doubleValue[i] = convert->toDouble(pvStructure->getSubField<PVScalar>("value"));
} else {
doubleValue[i] = nan("");
}
}
return doubleValue;
}
}}

View File

@@ -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 <epicsThread.h>
#include <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
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<double>(nchannel,nan(""))),
pvaClientMonitor(std::vector<PvaClientMonitorPtr>(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<bool> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
pvaClientMonitor[i] = pvaClientChannelArray[i]->createMonitor(request);
pvaClientMonitor[i]->issueConnect();
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
Status status = pvaClientMonitor[i]->waitConnect();
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; i<nchannel; ++i)
{
if(isConnected[i]) pvaClientMonitor[i]->start();
}
isMonitorConnected = true;
}
bool PvaClientMultiMonitorDouble::poll()
{
if(!isMonitorConnected){
connect();
epicsThreadSleep(.01);
}
bool result = false;
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
if(pvaClientMonitor[i]->poll()) {
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<double> PvaClientMultiMonitorDouble::get()
{
return doubleValue;
}
}}

View File

@@ -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 <pv/pvaClientMultiChannel.h>
#include <pv/standardField.h>
#include <pv/convert.h>
#include <epicsMath.h>
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<PvaClientPutPtr>(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<bool> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
pvaClientPut[i] = pvaClientChannelArray[i]->createPut();
pvaClientPut[i]->issueConnect();
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
Status status = pvaClientPut[i]->waitConnect();
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<double> const &data)
{
if(!isPutConnected) connect();
if(data.size()!=nchannel) {
throw std::runtime_error("data has wrong size");
}
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
PVStructurePtr pvTop = pvaClientPut[i]->getData()->getPVStructure();
PVDoublePtr pvValue = pvTop->getSubField<PVDouble>("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());
}
}
}
}}