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

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());
}
}
}
}}