NTMultiChannel support now available.

This commit is contained in:
mrkraimer
2015-08-10 05:16:45 -04:00
parent 2fae1da00a
commit 702652d20f
17 changed files with 1501 additions and 29 deletions

32
README.md Normal file
View File

@@ -0,0 +1,32 @@
Status
===========
* The API should be almost ready for feature freeze for release 4.5
* Everything defined in pvaClient.h should be ready but see below for remaining work.
* Everything defined in pvaClientMultiChannel.h is ready but see below for remaining work.
Examples
------------
The examples require the database in pvaClientTestCPP.
For example:
...
mrk> pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd
...
pvaClientChannel
---------------
Channel::getField and channelArray are not supported for release 4.5.
pvaClientMultiChannel
---------------
For release 4.6 support is available for multiDouble and NTMultiChannel.
In the future additional support should be provided that at least includes NTScalarMultiChannel.
Testing with some channels not connected have not been done.
At least some testing with missing channels should be done before release 4.5

View File

@@ -1,9 +0,0 @@
To build do the following:
cd configure
cp ExampleRELEASE.local RELEASE.local
edit RELEASE.local
cd ..
make
Now read documentation/pvaClientCPP.html

View File

@@ -40,6 +40,13 @@ examplePvaClientMultiDouble_LIBS += pvAccess
examplePvaClientMultiDouble_LIBS += pvData
examplePvaClientMultiDouble_LIBS += Com
PROD_HOST += examplePvaClientNTMulti
examplePvaClientNTMulti_SRCS += examplePvaClientNTMulti.cpp
examplePvaClientNTMulti_LIBS += pvaClient
examplePvaClientNTMulti_LIBS += pvAccess
examplePvaClientNTMulti_LIBS += pvData
examplePvaClientNTMulti_LIBS += Com
PROD_HOST += helloWorldRPC
helloWorldRPC_SRCS += helloWorldRPC.cpp
helloWorldRPC_LIBS += pvaClient

View File

@@ -33,7 +33,7 @@ cout << "num " << num << " names " << channelNames << endl;
PvaClientMultiPutDoublePtr multiPut(multiChannel->createPut());
PvaClientMultiMonitorDoublePtr multiMonitor(multiChannel->createMonitor());
shared_vector<double> data(num,0);
for(double value = 0.0; value< 1.0; value+= .2) {
for(double value = 0.2; value< 2.3; value+= 1.0) {
try {
for(size_t i=0; i<num; ++i) data[i] = value + i;
cout << "put " << data << endl;
@@ -57,7 +57,7 @@ int main(int argc,char *argv[])
size_t num = 5;
shared_vector<string> channelNames(num);
channelNames[0] = "double01";
channelNames[1] = "double02";
channelNames[1] = "int01";
channelNames[2] = "double03";
channelNames[3] = "double04";
channelNames[4] = "double05";
@@ -68,7 +68,7 @@ int main(int argc,char *argv[])
example(pva,"ca",names);
channelNames = shared_vector<string>(num);
channelNames[0] = "exampleDouble01";
channelNames[1] = "exampleDouble02";
channelNames[1] = "exampleInt";
channelNames[2] = "exampleDouble03";
channelNames[3] = "exampleDouble04";
channelNames[4] = "exampleDouble05";

View File

@@ -0,0 +1,141 @@
/*examplePvaClientNTMulti.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
/* Author: Marty Kraimer */
#include <iostream>
#include <pv/pvaClientMultiChannel.h>
#include <pv/convert.h>
using std::tr1::static_pointer_cast;
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static ConvertPtr convert = getConvert();
static void setValue(PVUnionPtr const &pvUnion, double value)
{
UnionConstPtr u = pvUnion->getUnion();
FieldConstPtr field = u->getField(0);
Type type = field->getType();
if(type==scalar) {
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
ScalarType scalarType = scalar->getScalarType();
if(scalarType==pvDouble) {
PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
pvDataCreate->createPVScalar(pvDouble));
pvValue->put(value);
pvUnion->set(0,pvValue);
return;
}
if(scalarType==pvString) {
PVStringPtr pvValue = static_pointer_cast<PVString>(
pvDataCreate->createPVScalar(pvString));
stringstream ss;
ss << "value" << value;
pvValue->put(ss.str());
pvUnion->set(0,pvValue);
return;
}
throw std::runtime_error("only pvDouble and pvString are supported");
}
if(type==scalarArray) {
ScalarArrayConstPtr scalarArray = static_pointer_cast<const ScalarArray>(field);
ScalarType scalarType = scalarArray->getElementType();
if(scalarType==pvDouble) {
size_t num = 5;
PVDoubleArrayPtr pvValue = static_pointer_cast<PVDoubleArray>(
pvDataCreate->createPVScalarArray(pvDouble));
shared_vector<double> data(num);
for(size_t i=0; i<num; ++i) data[i] = value +i;
pvValue->replace(freeze(data));
pvUnion->set(0,pvValue);
return;
}
if(scalarType==pvString) {
size_t num = 5;
PVStringArrayPtr pvValue = static_pointer_cast<PVStringArray>(
pvDataCreate->createPVScalarArray(pvString));
shared_vector<string> data(num);
for(size_t i=0; i<num; ++i) {
stringstream ss;
ss << "value" << value << i;
data[i] = ss.str();
}
pvValue->replace(freeze(data));
pvUnion->set(0,pvValue);
return;
}
throw std::runtime_error("only pvDouble and pvString are supported");
}
throw std::runtime_error("only scalar and scalarArray fields are supported");
}
static void example(
PvaClientPtr const &pva,
string provider,
shared_vector<const string> const &channelNames)
{
size_t num = channelNames.size();
PvaClientMultiChannelPtr multiChannel(
PvaClientMultiChannel::create(pva,channelNames,provider));
PvaClientNTMultiGetPtr multiGet(multiChannel->createNTGet());
PvaClientNTMultiPutPtr multiPut(multiChannel->createNTPut());
PvaClientNTMultiMonitorPtr multiMonitor(multiChannel->createNTMonitor());
shared_vector<epics::pvData::PVUnionPtr> data = multiPut->getValues();
for(double value = 0.0; value< 2.1; value+= 1.0) {
for(size_t i=0; i<num ; ++i) {
PVUnionPtr pvUnion = data[i];
setValue(pvUnion,value);
}
multiPut->put();
multiGet->get();
PvaClientNTMultiDataPtr multiData = multiGet->getData();
PVStructurePtr pvStructure = multiData->getPVTop();
cout << "pvStructure\n" << pvStructure << endl;
bool result = multiMonitor->waitEvent(.1);
while(result) {
multiData = multiMonitor->getData();
pvStructure = multiData->getPVTop();
cout << "monitor pvStructure\n" << pvStructure << endl;
result = multiMonitor->poll();
}
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
size_t num = 4;
shared_vector<string> channelNames(num);
channelNames[0] = "double01";
channelNames[1] = "string01";
channelNames[2] = "doubleArray01";
channelNames[3] = "stringArray01";
cout << "dbRecord pva\n";
shared_vector<const string> names(freeze(channelNames));
example(pva,"pva",names);
cout << "dbRecord ca\n";
example(pva,"ca",names);
channelNames = shared_vector<string>(num);
channelNames[0] = "exampleDouble";
channelNames[1] = "exampleString";
channelNames[2] = "exampleDoubleArray";
channelNames[3] = "exampleStringArray";
names = freeze(channelNames);
cout << "pvRecord pva\n";
example(pva,"pva",names);
return 0;
}

View File

@@ -13,12 +13,16 @@
#include <iostream>
#include <pv/pvaClient.h>
#include <pv/convert.h>
using std::tr1::static_pointer_cast;
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvaClient;
static ConvertPtr convert = getConvert();
static void examplePut(PvaClientPtr const &pva)
{
@@ -45,10 +49,29 @@ static void examplePut(PvaClientPtr const &pva)
}
}
static void examplePVFieldPut(PvaClientPtr const &pva)
{
cout << "example put\n";
PvaClientChannelPtr channel = pva->channel("exampleDouble");
PvaClientPutPtr put = channel->put();
PvaClientPutDataPtr putData = put->getData();
PVFieldPtr pvField = putData->getValue();
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
try {
convert->fromDouble(pvScalar,1.0); put->put();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
convert->fromDouble(pvScalar,2.0); put->put();
cout << channel->get("field()")->getData()->showChanged(cout) << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
int main(int argc,char *argv[])
{
PvaClientPtr pva = PvaClient::create();
examplePut(pva);
examplePVFieldPut(pva);
return 0;
}

View File

@@ -22,6 +22,10 @@ LIBSRCS += pvaClientMultiChannel.cpp
LIBSRCS += pvaClientMultiGetDouble.cpp
LIBSRCS += pvaClientMultiPutDouble.cpp
LIBSRCS += pvaClientMultiMonitorDouble.cpp
LIBSRCS += pvaClientNTMultiPut.cpp
LIBSRCS += pvaClientNTMultiData.cpp
LIBSRCS += pvaClientNTMultiGet.cpp
LIBSRCS += pvaClientNTMultiMonitor.cpp
pvaClient_LIBS += pvAccess pvData nt Com
pvaClient_LIBS += $(EPICS_BASE_IOC_LIBS)

View File

@@ -0,0 +1,203 @@
/* pvaClientNTMultiData.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <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();
PvaClientNTMultiDataPtr PvaClientNTMultiData::create(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest)
{
PvaClientNTMultiDataPtr pvaClientNTMultiData(
new PvaClientNTMultiData(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiData;
}
PvaClientNTMultiData::PvaClientNTMultiData(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
pvRequest(pvRequest),
u(u),
nchannel(pvaClientChannelArray.size()),
gotAlarm(false),
gotTimeStamp(false),
isDestroyed(false)
{
PVFieldPtr pvValue = pvRequest->getSubField("field.value");
if(!pvValue) {
throw std::runtime_error("pvRequest did not specify value");
}
topPVStructure.resize(nchannel);
for(size_t i=0; i< nchannel; ++i) topPVStructure[i] = PVStructurePtr();
NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder();
builder->value(u);
if(pvRequest->getSubField("field.alarm"))
{
gotAlarm = true;
builder->addAlarm();
severity.resize(nchannel);
status.resize(nchannel);
message.resize(nchannel);
}
if(pvRequest->getSubField("field.timeStamp")) {
gotTimeStamp = true;
builder->addTimeStamp();
secondsPastEpoch.resize(nchannel);
nanoseconds.resize(nchannel);
userTag.resize(nchannel);
}
ntMultiChannel = builder->create();
}
PvaClientNTMultiData::~PvaClientNTMultiData()
{
destroy();
}
void PvaClientNTMultiData::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
}
void PvaClientNTMultiData::setStructure(StructureConstPtr const & structure,size_t index)
{
FieldConstPtr field = structure->getField("value");
if(!field) {
string message = "channel "
+ pvaClientChannelArray[index]->getChannel()->getChannelName()
+ " does not have top level value field";
throw std::runtime_error(message);
}
}
void PvaClientNTMultiData::setPVStructure(
PVStructurePtr const &pvStructure,size_t index)
{
topPVStructure[index] = pvStructure;
}
size_t PvaClientNTMultiData::getNumber()
{
return nchannel;
}
void PvaClientNTMultiData::startDeltaTime()
{
for(size_t i=0; i<nchannel; ++i)
{
topPVStructure[i] = PVStructurePtr();
if(gotAlarm)
{
alarm.setSeverity(noAlarm);
alarm.setStatus(noStatus);
alarm.setMessage("");
severity[i] = invalidAlarm;
status[i] = undefinedStatus;
message[i] = "not connected";
}
if(gotTimeStamp)
{
timeStamp.getCurrent();
secondsPastEpoch[i] = 0;
nanoseconds[i] = 0;
userTag[i] = 0;
}
}
}
void PvaClientNTMultiData::endDeltaTime()
{
for(size_t i=0; i<nchannel; ++i)
{
PVStructurePtr pvst = topPVStructure[i];
if(!pvst) {
unionValue[i] = PVUnionPtr();
} else {
unionValue[i]->set(pvst->getSubField("value"));
}
if(gotAlarm)
{
severity[i] = pvst->getSubField<PVInt>("alarm.severity")->get();
status[i] = pvst->getSubField<PVInt>("alarm.status")->get();
message[i] = pvst->getSubField<PVString>("alarm.message")->get();
}
if(gotTimeStamp)
{
secondsPastEpoch[i] = pvst->getSubField<PVLong>("timeStamp.secondsPastEpoch")->get();
nanoseconds[i] = pvst->getSubField<PVInt>("timeStamp.nanoseconds")->get();
userTag[i] = pvst->getSubField<PVInt>("timeStamp.userTag")->get();
}
}
ntMultiChannel->getValue()->replace(freeze(unionValue));
if(gotAlarm)
{
ntMultiChannel->getSeverity()->replace(freeze(severity));
ntMultiChannel->getStatus()->replace(freeze(status));
ntMultiChannel->getMessage()->replace(freeze(message));
}
if(gotTimeStamp)
{
ntMultiChannel->getSecondsPastEpoch()->replace(freeze(secondsPastEpoch));
ntMultiChannel->getNanoseconds()->replace(freeze(nanoseconds));
ntMultiChannel->getUserTag()->replace(freeze(userTag));
}
}
TimeStamp PvaClientNTMultiData::getTimeStamp()
{
pvTimeStamp.get(timeStamp);
return timeStamp;
}
NTMultiChannelPtr PvaClientNTMultiData::getNTMultiChannel()
{
return ntMultiChannel;
}
PVStructurePtr PvaClientNTMultiData::getPVTop()
{
return ntMultiChannel->getPVStructure();
}
}}

View File

@@ -15,7 +15,7 @@
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/pvaClientMultiChannel.h>
#include <pv/createRequest.h>
using std::tr1::static_pointer_cast;
@@ -52,7 +52,8 @@ PvaClientMultiChannel::PvaClientMultiChannel(
numChannel(channelName.size()),
numConnected(0),
pvaClientChannelArray(PvaClientChannelArray(numChannel,PvaClientChannelPtr())),
isConnected(shared_vector<bool>(numChannel,false)),
isConnected(shared_vector<epics::pvData::boolean>(numChannel,false)),
createRequest(CreateRequest::create()),
isDestroyed(false)
{
}
@@ -131,7 +132,7 @@ bool PvaClientMultiChannel::connectionChange()
return false;
}
epics::pvData::shared_vector<bool> PvaClientMultiChannel::getIsConnected()
epics::pvData::shared_vector<epics::pvData::boolean> PvaClientMultiChannel::getIsConnected()
{
if(isDestroyed) throw std::runtime_error("pvaClientMultiChannel was destroyed");
for(size_t i=0; i<numChannel; ++i) {
@@ -181,5 +182,47 @@ PvaClientMultiMonitorDoublePtr PvaClientMultiChannel::createMonitor()
return PvaClientMultiMonitorDouble::create(getPtrSelf(), pvaClientChannelArray);
}
PvaClientNTMultiPutPtr PvaClientMultiChannel::createNTPut()
{
checkConnected();
return PvaClientNTMultiPut::create(getPtrSelf(), pvaClientChannelArray);
}
PvaClientNTMultiGetPtr PvaClientMultiChannel::createNTGet()
{
return createNTGet("value,alarm,timeStamp");
}
PvaClientNTMultiGetPtr PvaClientMultiChannel::createNTGet(std::string const &request)
{
checkConnected();
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
stringstream ss;
ss << " PvaClientMultiChannel::createNTGet invalid pvRequest: " + createRequest->getMessage();
throw std::runtime_error(ss.str());
}
return PvaClientNTMultiGet::create(getPtrSelf(), pvaClientChannelArray,pvRequest);
}
PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor()
{
return createNTMonitor("value,alarm,timeStamp");
}
PvaClientNTMultiMonitorPtr PvaClientMultiChannel::createNTMonitor(std::string const &request)
{
checkConnected();
PVStructurePtr pvRequest = createRequest->createRequest(request);
if(!pvRequest) {
stringstream ss;
ss << " PvaClientMultiChannel::createNTMonitor invalid pvRequest: " + createRequest->getMessage();
throw std::runtime_error(ss.str());
}
return PvaClientNTMultiMonitor::create(getPtrSelf(), pvaClientChannelArray,pvRequest);
}
}}

View File

@@ -1,4 +1,4 @@
/* pvaClient.h */
/* pvaClientMultiChannel.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
@@ -18,6 +18,7 @@
#include <pv/pvaClient.h>
#include <pv/ntmultiChannel.h>
#include <pv/createRequest.h>
namespace epics { namespace pvaClient {
@@ -32,11 +33,20 @@ typedef std::tr1::shared_ptr<PvaClientMultiPutDouble> PvaClientMultiPutDoublePtr
class PvaClientMultiMonitorDouble;
typedef std::tr1::shared_ptr<PvaClientMultiMonitorDouble> PvaClientMultiMonitorDoublePtr;
class PvaClientNTMultiGet;
typedef std::tr1::shared_ptr<PvaClientNTMultiGet> PvaClientNTMultiGetPtr;
class PvaClientNTMultiPut;
typedef std::tr1::shared_ptr<PvaClientNTMultiPut> PvaClientNTMultiPutPtr;
class PvaClientNTMultiMonitor;
typedef std::tr1::shared_ptr<PvaClientNTMultiMonitor> PvaClientNTMultiMonitorPtr;
class PvaClientNTMultiData;
typedef std::tr1::shared_ptr<PvaClientNTMultiData> PvaClientNTMultiDataPtr;
typedef epics::pvData::shared_vector<PvaClientChannelPtr> PvaClientChannelArray;
/**
* Provides access to multiple channels.
* @brief PvaMultiChannel is a synchronous interface for accessing multiple channels.
*
* @author mrk
*/
@@ -58,9 +68,11 @@ public:
std::string const & providerName = "pva",
size_t maxNotConnected=0
);
/**
* Destructor
*/
~PvaClientMultiChannel();
/** Destroy the pvAccess connection.
/** Destroy the pvAccess connections.
*/
void destroy();
/** Get the channelNames.
@@ -85,7 +97,7 @@ public:
/** Get the connection state of each channel.
* @return The state of each channel.
*/
epics::pvData::shared_vector<bool> getIsConnected();
epics::pvData::shared_vector<epics::pvData::boolean> getIsConnected();
/** Get the pvaClientChannelArray.
* @return The shared pointer.
*/
@@ -109,6 +121,35 @@ public:
* @return The interface.
*/
PvaClientMultiMonitorDoublePtr createMonitor();
/**
* Create a pvaClientNTMultiPut.
* @return The interface.
*/
PvaClientNTMultiPutPtr createNTPut();
/**
* Create a pvaClientNTMultiGet.
* This calls the next method with request = "value,alarm,timeStamp"
* @return The interface.
*/
PvaClientNTMultiGetPtr createNTGet();
/**
* Create a pvaClientNTMultiGet;
* @param request The request for each channel.
* @return The interface.
*/
PvaClientNTMultiGetPtr createNTGet(std::string const &request);
/**
* Create a pvaClientNTMultiMonitor.
* This calls the next method with request = "value,alarm,timeStamp"
* @return The interface.
*/
PvaClientNTMultiMonitorPtr createNTMonitor();
/**
* Create a pvaClientNTMultiPut.
* @param request The request for each channel.
* @return The interface.
*/
PvaClientNTMultiMonitorPtr createNTMonitor(std::string const &request);
/** Get the shared pointer to self.
* @return The shared pointer.
*/
@@ -135,8 +176,10 @@ private:
size_t numConnected;
PvaClientChannelArray pvaClientChannelArray;
epics::pvData::shared_vector<bool> isConnected;
epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
epics::pvData::CreateRequest::shared_pointer createRequest;
bool isDestroyed;
};
/**
@@ -319,6 +362,312 @@ private:
bool isDestroyed;
};
/**
* This provides channelGet to multiple channels where the value field of each channel is presented as a union.
*/
class epicsShareClass PvaClientNTMultiGet :
public std::tr1::enable_shared_from_this<PvaClientNTMultiGet>
{
public:
POINTER_DEFINITIONS(PvaClientNTMultiGet);
/**
* Factory method that creates a PvaClientNTMultiGet.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @param pvRequest The pvRequest for each channel.
* @return The interface.
*/
static PvaClientNTMultiGetPtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
~PvaClientNTMultiGet();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Create a channelGet for each channel.
*/
void connect();
/**
* get data for each channel.
*/
void get();
/**
* get the data.
* @return the pvaClientNTMultiData.
*/
PvaClientNTMultiDataPtr getData();
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiGetPtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientNTMultiGet(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
PvaClientMultiChannelPtr pvaClientMultiChannel;
PvaClientChannelArray pvaClientChannelArray;
size_t nchannel;
epics::pvData::Mutex mutex;
epics::pvData::PVStructurePtr pvRequest;
PvaClientNTMultiDataPtr pvaClientNTMultiData;
std::vector<PvaClientGetPtr> pvaClientGet;
bool isConnected;
bool isDestroyed;
};
/**
* This provides channelPut to multiple channels where the value field of each channel is presented as a union.
*/
class epicsShareClass PvaClientNTMultiPut :
public std::tr1::enable_shared_from_this<PvaClientNTMultiPut>
{
public:
POINTER_DEFINITIONS(PvaClientNTMultiPut);
/**
* Factory method that creates a PvaClientNTMultiPut.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @return The interface.
*/
static PvaClientNTMultiPutPtr create(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray);
~PvaClientNTMultiPut();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Create a channelPut for each channel.
*/
void connect();
/**
* get the value field of each channel as a union.
* @return A shared vector of union.
*/
epics::pvData::shared_vector<epics::pvData::PVUnionPtr> getValues();
/**
* put the data to each channel.
' */
void put();
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiPutPtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientNTMultiPut(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray);
PvaClientMultiChannelPtr pvaClientMultiChannel;
PvaClientChannelArray pvaClientChannelArray;
size_t nchannel;
epics::pvData::Mutex mutex;
epics::pvData::shared_vector<epics::pvData::PVUnionPtr> unionValue;
epics::pvData::shared_vector<epics::pvData::PVFieldPtr> value;
std::vector<PvaClientPutPtr> pvaClientPut;
bool isConnected;
bool isDestroyed;
};
/**
* This provides channel monitor to multiple channels where the value field of each channel is presented as a union.
*/
class epicsShareClass PvaClientNTMultiMonitor :
public std::tr1::enable_shared_from_this<PvaClientNTMultiMonitor>
{
public:
POINTER_DEFINITIONS(PvaClientNTMultiMonitor);
/**
* Factory method that creates a PvaClientNTMultiMonitor.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @param pvRequest The pvRequest for each channel.
* @return The interface.
*/
static PvaClientNTMultiMonitorPtr create(
PvaClientMultiChannelPtr const &pvaNTMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
~PvaClientNTMultiMonitor();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Create a channel monitor for each channel.
*/
void connect();
/**
* poll each channel.
* If any has new data it is used to update the double[].
* @return (false,true) if (no, at least one) value was updated.
*/
bool poll();
/**
* Wait until poll returns true.
* @param waitForEvent The time to keep trying.
* A thread sleep of .1 seconds occurs between each call to poll.
* @return (false,true) if (timeOut, poll returned true).
*/
bool waitEvent(double waitForEvent);
/**
* get the data.
* @return the pvaClientNTMultiData.
*/
PvaClientNTMultiDataPtr getData();
/** Monitor the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiMonitorPtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientNTMultiMonitor(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
PvaClientMultiChannelPtr pvaClientMultiChannel;
PvaClientChannelArray pvaClientChannelArray;
size_t nchannel;
epics::pvData::Mutex mutex;
epics::pvData::PVStructurePtr pvRequest;
PvaClientNTMultiDataPtr pvaClientNTMultiData;
std::vector<PvaClientMonitorPtr> pvaClientMonitor;
bool isConnected;
bool isDestroyed;
};
/**
* This provides NTMultiChannel data for both PvaClientNTMultiGet and PvaClientNTMultiMonitor.
*/
class epicsShareClass PvaClientNTMultiData :
public std::tr1::enable_shared_from_this<PvaClientNTMultiData>
{
public:
POINTER_DEFINITIONS(PvaClientNTMultiData);
/**
* Factory method that creates a PvaClientNTMultiData.
* Normally only called by PvaClientNTMultiGet and PvaClientNTMultiMonitor.
* @param u The union interface for the value field of each channel.
* @param pvaClientMultiChannel The interface to PvaClientMultiChannel.
* @param pvaClientChannelArray The PvaClientChannel array.
* @param pvRequest The pvRequest for each channel.
*/
static PvaClientNTMultiDataPtr create(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaNTMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
~PvaClientNTMultiData();
/** Destroy the pvAccess connection.
*/
void destroy();
/**
* Get the number of channels.
* @return The number of channels.
*/
size_t getNumber();
/**
* Set the timeStamp base for computing deltaTimes.
*/
void startDeltaTime();
/**
* Update NTMultiChannel fields.
*/
void endDeltaTime();
/**
* Get the time when the last get was made.
* @return The timeStamp.
*/
epics::pvData::TimeStamp getTimeStamp();
/**
* Get the NTMultiChannel.
* @return The value.
*/
epics::nt::NTMultiChannelPtr getNTMultiChannel();
/**
* Get the top level structure.
* @return The top level structure.
*/
epics::pvData::PVStructurePtr getPVTop();
/** Get the shared pointer to self.
* @return The shared pointer.
*/
PvaClientNTMultiDataPtr getPtrSelf()
{
return shared_from_this();
}
private:
PvaClientNTMultiData(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaNTMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest);
static epics::pvData::PVStructurePtr createRequest(std::string const & request);
void setStructure(epics::pvData::StructureConstPtr const & structure,size_t index);
void setPVStructure(
epics::pvData::PVStructurePtr const &pvStructure,size_t index);
PvaClientMultiChannelPtr pvaClientMultiChannel;
PvaClientChannelArray pvaClientChannelArray;
epics::pvData::PVStructurePtr pvRequest;
epics::pvData::UnionConstPtr u;
size_t nchannel;
epics::pvData::Mutex mutex;
std::vector<epics::pvData::PVStructurePtr> topPVStructure;
bool gotAlarm;
bool gotTimeStamp;
bool isDestroyed;
epics::nt::NTMultiChannelPtr ntMultiChannel;
epics::pvData::PVStructurePtr pvTop;
epics::pvData::shared_vector<epics::pvData::PVUnionPtr> unionValue;
epics::pvData::shared_vector<epics::pvData::int32> severity;
epics::pvData::shared_vector<epics::pvData::int32> status;
epics::pvData::shared_vector<std::string> message;
epics::pvData::shared_vector<epics::pvData::int64> secondsPastEpoch;
epics::pvData::shared_vector<epics::pvData::int32> nanoseconds;
epics::pvData::shared_vector<epics::pvData::int32> userTag;
epics::pvData::Alarm alarm;
epics::pvData::PVAlarm pvAlarm;
epics::pvData::TimeStamp timeStamp;;
epics::pvData::PVTimeStamp pvTimeStamp;
friend class PvaClientNTMultiGet;
friend class PvaClientNTMultiPut;
friend class PvaClientNTMultiMonitor;
};
}}
#endif /* PVACLIENTMULTICHANNEL_H */

View File

@@ -68,7 +68,7 @@ void PvaClientMultiGetDouble::destroy()
void PvaClientMultiGetDouble::connect()
{
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
for(size_t i=0; i<nchannel; ++i)
{
@@ -94,7 +94,7 @@ void PvaClientMultiGetDouble::connect()
epics::pvData::shared_vector<double> PvaClientMultiGetDouble::get()
{
if(!isGetConnected) connect();
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{

View File

@@ -69,7 +69,7 @@ void PvaClientMultiMonitorDouble::destroy()
void PvaClientMultiMonitorDouble::connect()
{
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
for(size_t i=0; i<nchannel; ++i)
{
@@ -103,7 +103,7 @@ bool PvaClientMultiMonitorDouble::poll()
epicsThreadSleep(.01);
}
bool result = false;
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {

View File

@@ -70,7 +70,7 @@ void PvaClientMultiPutDouble::destroy()
void PvaClientMultiPutDouble::connect()
{
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
@@ -98,13 +98,13 @@ void PvaClientMultiPutDouble::put(epics::pvData::shared_vector<double> const &da
if(data.size()!=nchannel) {
throw std::runtime_error("data has wrong size");
}
shared_vector<bool> isConnected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean> 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]);
PVScalarPtr pvValue = pvTop->getSubField<PVScalar>("value");
convert->fromDouble(pvValue,data[i]);
pvaClientPut[i]->issuePut();
}
if(isConnected[i]) {

View File

@@ -0,0 +1,232 @@
/* pvaClientNTMultiData.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <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();
PvaClientNTMultiDataPtr PvaClientNTMultiData::create(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest)
{
PvaClientNTMultiDataPtr pvaClientNTMultiData(
new PvaClientNTMultiData(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiData;
}
PvaClientNTMultiData::PvaClientNTMultiData(
epics::pvData::UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
pvRequest(pvRequest),
u(u),
nchannel(pvaClientChannelArray.size()),
gotAlarm(false),
gotTimeStamp(false),
isDestroyed(false)
{
PVFieldPtr pvValue = pvRequest->getSubField("field.value");
if(!pvValue) {
throw std::runtime_error("pvRequest did not specify value");
}
topPVStructure.resize(nchannel);
unionValue.resize(nchannel);
for(size_t i=0; i< nchannel; ++i) {
topPVStructure[i] = PVStructurePtr();
unionValue[i] = pvDataCreate->createPVUnion(u);
}
NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder();
builder->value(u);
if(pvRequest->getSubField("field.alarm"))
{
gotAlarm = true;
builder->addAlarm();
builder->addSeverity();
builder->addStatus();
builder->addMessage();
severity.resize(nchannel);
status.resize(nchannel);
message.resize(nchannel);
}
if(pvRequest->getSubField("field.timeStamp")) {
gotTimeStamp = true;
builder->addTimeStamp();
builder->addSecondsPastEpoch();
builder->addNanoseconds();
builder->addUserTag();
secondsPastEpoch.resize(nchannel);
nanoseconds.resize(nchannel);
userTag.resize(nchannel);
}
ntMultiChannel = builder->create();
ntMultiChannel->getChannelName()->replace(pvaClientMultiChannel->getChannelNames());
}
PvaClientNTMultiData::~PvaClientNTMultiData()
{
destroy();
}
void PvaClientNTMultiData::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
}
void PvaClientNTMultiData::setStructure(StructureConstPtr const & structure,size_t index)
{
FieldConstPtr field = structure->getField("value");
if(!field) {
string message = "channel "
+ pvaClientChannelArray[index]->getChannel()->getChannelName()
+ " does not have top level value field";
throw std::runtime_error(message);
}
}
void PvaClientNTMultiData::setPVStructure(
PVStructurePtr const &pvStructure,size_t index)
{
topPVStructure[index] = pvStructure;
}
size_t PvaClientNTMultiData::getNumber()
{
return nchannel;
}
void PvaClientNTMultiData::startDeltaTime()
{
for(size_t i=0; i<nchannel; ++i)
{
topPVStructure[i] = PVStructurePtr();
if(gotAlarm)
{
alarm.setSeverity(noAlarm);
alarm.setStatus(noStatus);
alarm.setMessage("");
severity[i] = invalidAlarm;
status[i] = undefinedStatus;
message[i] = "not connected";
}
if(gotTimeStamp)
{
timeStamp.getCurrent();
secondsPastEpoch[i] = 0;
nanoseconds[i] = 0;
userTag[i] = 0;
}
}
}
void PvaClientNTMultiData::endDeltaTime()
{
for(size_t i=0; i<nchannel; ++i)
{
PVStructurePtr pvst = topPVStructure[i];
if(!pvst) {
unionValue[i] = PVUnionPtr();
} else {
unionValue[i]->set(pvst->getSubField("value"));
}
if(gotAlarm)
{
severity[i] = pvst->getSubField<PVInt>("alarm.severity")->get();
status[i] = pvst->getSubField<PVInt>("alarm.status")->get();
message[i] = pvst->getSubField<PVString>("alarm.message")->get();
}
if(gotTimeStamp)
{
secondsPastEpoch[i] = pvst->getSubField<PVLong>("timeStamp.secondsPastEpoch")->get();
nanoseconds[i] = pvst->getSubField<PVInt>("timeStamp.nanoseconds")->get();
userTag[i] = pvst->getSubField<PVInt>("timeStamp.userTag")->get();
}
}
shared_vector<epics::pvData::PVUnionPtr> val(nchannel);
for(size_t i=0; i<nchannel; ++i) val[i] = unionValue[i];
ntMultiChannel->getValue()->replace(freeze(val));
shared_vector<epics::pvData::boolean> connected = pvaClientMultiChannel->getIsConnected();
shared_vector<epics::pvData::boolean> isConnected(nchannel);
for(size_t i=0; i<nchannel; ++i) isConnected[i] = connected[i];
ntMultiChannel->getIsConnected()->replace(freeze(isConnected));
if(gotAlarm)
{
shared_vector<int32> sev(nchannel);
for(size_t i=0; i<nchannel; ++i) sev[i] = severity[i];
ntMultiChannel->getSeverity()->replace(freeze(sev));
shared_vector<int32> sta(nchannel);
for(size_t i=0; i<nchannel; ++i) sta[i] = status[i];
ntMultiChannel->getStatus()->replace(freeze(sta));
shared_vector<string> mes(nchannel);
for(size_t i=0; i<nchannel; ++i) mes[i] = message[i];
ntMultiChannel->getMessage()->replace(freeze(mes));
}
if(gotTimeStamp)
{
shared_vector<int64> sec(nchannel);
for(size_t i=0; i<nchannel; ++i) sec[i] = secondsPastEpoch[i];
ntMultiChannel->getSecondsPastEpoch()->replace(freeze(sec));
shared_vector<int32> nano(nchannel);
for(size_t i=0; i<nchannel; ++i) nano[i] = nanoseconds[i];
ntMultiChannel->getNanoseconds()->replace(freeze(nano));
shared_vector<int32> tag(nchannel);
for(size_t i=0; i<nchannel; ++i) tag[i] = userTag[i];
ntMultiChannel->getUserTag()->replace(freeze(tag));
}
}
TimeStamp PvaClientNTMultiData::getTimeStamp()
{
pvTimeStamp.get(timeStamp);
return timeStamp;
}
NTMultiChannelPtr PvaClientNTMultiData::getNTMultiChannel()
{
return ntMultiChannel;
}
PVStructurePtr PvaClientNTMultiData::getPVTop()
{
return ntMultiChannel->getPVStructure();
}
}}

143
src/pvaClientNTMultiGet.cpp Normal file
View File

@@ -0,0 +1,143 @@
/* pvaClientNTMultiGet.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <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();
PvaClientNTMultiGetPtr PvaClientNTMultiGet::create(
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest)
{
UnionConstPtr u = fieldCreate->createVariantUnion();
PvaClientNTMultiGetPtr pvaClientNTMultiGet(
new PvaClientNTMultiGet(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiGet;
}
PvaClientNTMultiGet::PvaClientNTMultiGet(
UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()),
pvRequest(pvRequest),
pvaClientNTMultiData(
PvaClientNTMultiData::create(
u,
pvaClientMultiChannel,
pvaClientChannelArray,
pvRequest)),
isConnected(false),
isDestroyed(false)
{
}
PvaClientNTMultiGet::~PvaClientNTMultiGet()
{
destroy();
}
void PvaClientNTMultiGet::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
}
void PvaClientNTMultiGet::connect()
{
pvaClientGet.resize(nchannel);
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
if(pvRequest->getSubField("field.alarm")) request += ",alarm";
if(pvRequest->getSubField("field.timeStamp")) request += ",timeStamp";
for(size_t i=0; 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());
}
}
this->isConnected = true;
}
void PvaClientNTMultiGet::get()
{
if(!isConnected) connect();
shared_vector<epics::pvData::boolean> 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());
}
}
pvaClientNTMultiData->startDeltaTime();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
pvaClientNTMultiData->setPVStructure(pvaClientGet[i]->getData()->getPVStructure(),i);
}
}
pvaClientNTMultiData->endDeltaTime();
}
PvaClientNTMultiDataPtr PvaClientNTMultiGet::getData()
{
return pvaClientNTMultiData;
}
}}

View File

@@ -0,0 +1,155 @@
/* pvaClientNTMultiMonitor.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <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();
PvaClientNTMultiMonitorPtr PvaClientNTMultiMonitor::create(
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
epics::pvData::PVStructurePtr const & pvRequest)
{
UnionConstPtr u = fieldCreate->createVariantUnion();
PvaClientNTMultiMonitorPtr pvaClientNTMultiMonitor(
new PvaClientNTMultiMonitor(u,pvaMultiChannel,pvaClientChannelArray,pvRequest));
return pvaClientNTMultiMonitor;
}
PvaClientNTMultiMonitor::PvaClientNTMultiMonitor(
UnionConstPtr const & u,
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray,
PVStructurePtr const & pvRequest)
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()),
pvRequest(pvRequest),
pvaClientNTMultiData(
PvaClientNTMultiData::create(
u,
pvaClientMultiChannel,
pvaClientChannelArray,
pvRequest)),
isConnected(false),
isDestroyed(false)
{
}
PvaClientNTMultiMonitor::~PvaClientNTMultiMonitor()
{
destroy();
}
void PvaClientNTMultiMonitor::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
}
void PvaClientNTMultiMonitor::connect()
{
pvaClientMonitor.resize(nchannel);
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
string request = "value";
if(pvRequest->getSubField("field.alarm")) request += ",alarm";
if(pvRequest->getSubField("field.timeStamp")) request += ",timeStamp";
for(size_t i=0; 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 << " PvaChannelMonitor::waitConnect " << status.getMessage();
throw std::runtime_error(ss.str());
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) pvaClientMonitor[i]->start();
}
this->isConnected = true;
}
bool PvaClientNTMultiMonitor::poll()
{
if(!isConnected) connect();
bool result = false;
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
pvaClientNTMultiData->startDeltaTime();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
if(pvaClientMonitor[i]->poll()) {
pvaClientNTMultiData->setPVStructure(
pvaClientMonitor[i]->getData()->getPVStructure(),i);
pvaClientMonitor[i]->releaseEvent();
result = true;
}
}
}
if(result) pvaClientNTMultiData->endDeltaTime();
return result;
}
bool PvaClientNTMultiMonitor::waitEvent(double waitForEvent)
{
if(poll()) return true;
TimeStamp start;
start.getCurrent();
TimeStamp now;
while(true) {
epicsThreadSleep(.1);
if(poll()) return true;
now.getCurrent();
double diff = TimeStamp::diff(now,start);
if(diff>=waitForEvent) break;
}
return false;
}
PvaClientNTMultiDataPtr PvaClientNTMultiMonitor::getData()
{
return pvaClientNTMultiData;
}
}}

149
src/pvaClientNTMultiPut.cpp Normal file
View File

@@ -0,0 +1,149 @@
/* PvaClientNTMultiPut.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2015.03
*/
#define epicsExportSharedSymbols
#include <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();
PvaClientNTMultiPutPtr PvaClientNTMultiPut::create(
PvaClientMultiChannelPtr const &pvaMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray)
{
PvaClientNTMultiPutPtr pvaClientNTMultiPut(
new PvaClientNTMultiPut(pvaMultiChannel,pvaClientChannelArray));
return pvaClientNTMultiPut;
}
PvaClientNTMultiPut::PvaClientNTMultiPut(
PvaClientMultiChannelPtr const &pvaClientMultiChannel,
PvaClientChannelArray const &pvaClientChannelArray)
: pvaClientMultiChannel(pvaClientMultiChannel),
pvaClientChannelArray(pvaClientChannelArray),
nchannel(pvaClientChannelArray.size()),
unionValue(shared_vector<epics::pvData::PVUnionPtr>(nchannel,PVUnionPtr())),
value(shared_vector<epics::pvData::PVFieldPtr>(nchannel,PVFieldPtr())),
isConnected(false),
isDestroyed(false)
{
}
PvaClientNTMultiPut::~PvaClientNTMultiPut()
{
destroy();
}
void PvaClientNTMultiPut::destroy()
{
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
pvaClientChannelArray.clear();
}
void PvaClientNTMultiPut::connect()
{
pvaClientPut.resize(nchannel);
shared_vector<epics::pvData::boolean> 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());
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
pvaClientPut[i]->issueGet();
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
Status status = pvaClientPut[i]->waitGet();
if(status.isOK()) continue;
stringstream ss;
string channelName = pvaClientChannelArray[i]->getChannelName();
ss << "channel " << channelName << " PvaChannelPut::waitGet " << status.getMessage();
throw std::runtime_error(ss.str());
}
}
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
value[i] = pvaClientPut[i]->getData()->getValue();
FieldBuilderPtr builder = fieldCreate->createFieldBuilder();
builder->add("value",value[i]->getField());
unionValue[i] = pvDataCreate->createPVUnion(builder->createUnion());
}
}
this->isConnected = true;
}
shared_vector<epics::pvData::PVUnionPtr> PvaClientNTMultiPut::getValues()
{
if(!isConnected) connect();
return unionValue;
}
void PvaClientNTMultiPut::put()
{
if(!isConnected) connect();
shared_vector<epics::pvData::boolean> isConnected = pvaClientMultiChannel->getIsConnected();
for(size_t i=0; i<nchannel; ++i)
{
if(isConnected[i]) {
value[i]->copy(*unionValue[i]->get());
pvaClientPut[i]->issuePut();
}
if(isConnected[i]) {
Status status = pvaClientPut[i]->waitPut();
if(status.isOK()) continue;
stringstream ss;
string channelName = pvaClientChannelArray[i]->getChannelName();
ss << "channel " << channelName << " PvaChannelPut::waitConnect " << status.getMessage();
throw std::runtime_error(ss.str());
}
}
}
}}