pvac: add synchronous put to 'value' field
This commit is contained in:
@ -9,6 +9,15 @@ The shortest possible PVA get() example.
|
|||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
|
|
||||||
|
@page examples_miniput Simple Client Put Example
|
||||||
|
|
||||||
|
The shortest possible PVA put() example.
|
||||||
|
|
||||||
|
@include miniput.cpp
|
||||||
|
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
|
||||||
@page examples_getme Client Get Example
|
@page examples_getme Client Get Example
|
||||||
|
|
||||||
This example demonstrates a client which issues a Get operation on startup,
|
This example demonstrates a client which issues a Get operation on startup,
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
- Simplest (shortest) possible
|
- Simplest (shortest) possible
|
||||||
- @ref examples_miniget
|
- @ref examples_miniget
|
||||||
|
- @ref examples_miniput
|
||||||
- More complete
|
- More complete
|
||||||
- @ref examples_getme
|
- @ref examples_getme
|
||||||
- @ref examples_putme
|
- @ref examples_putme
|
||||||
|
@ -10,6 +10,7 @@ TESTPROD_HOST += monitorme
|
|||||||
TESTPROD_HOST += spamme
|
TESTPROD_HOST += spamme
|
||||||
|
|
||||||
TESTPROD_HOST += miniget
|
TESTPROD_HOST += miniget
|
||||||
|
TESTPROD_HOST += miniput
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
||||||
#----------------------------------------
|
#----------------------------------------
|
||||||
|
33
examples/miniput.cpp
Normal file
33
examples/miniput.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
// The simplest possible PVA put
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "pva/client.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if(argc<=2) {
|
||||||
|
std::cerr<<"Usage: "<<argv[0]<<" <pvname> <value>\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pvac::ClientProvider provider("pva");
|
||||||
|
|
||||||
|
pvac::ClientChannel channel(provider.connect(argv[1]));
|
||||||
|
|
||||||
|
std::cout<<"Before "<<channel.name()<<" : "<<channel.get()<<"\n";
|
||||||
|
|
||||||
|
channel.putValue<epics::pvData::pvString>(argv[2]);
|
||||||
|
|
||||||
|
std::cout<<"After "<<channel.name()<<" : "<<channel.get()<<"\n";
|
||||||
|
|
||||||
|
}catch(std::exception& e){
|
||||||
|
std::cerr<<"Error: "<<e.what()<<"\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
@ -22,14 +22,31 @@ typedef epicsGuard<epicsMutex> Guard;
|
|||||||
typedef epicsGuardRelease<epicsMutex> UnGuard;
|
typedef epicsGuardRelease<epicsMutex> UnGuard;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct GetWait : pvac::ClientChannel::GetCallback
|
struct WaitCommon
|
||||||
{
|
{
|
||||||
epicsMutex mutex;
|
epicsMutex mutex;
|
||||||
epicsEvent event;
|
epicsEvent event;
|
||||||
bool done;
|
bool done;
|
||||||
|
|
||||||
|
WaitCommon() :done(false) {}
|
||||||
|
void wait(double timeout)
|
||||||
|
{
|
||||||
|
Guard G(mutex);
|
||||||
|
while(!done) {
|
||||||
|
UnGuard U(G);
|
||||||
|
if(!event.wait(timeout)) {
|
||||||
|
throw pvac::Timeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GetWait : public pvac::ClientChannel::GetCallback,
|
||||||
|
public WaitCommon
|
||||||
|
{
|
||||||
pvac::GetEvent result;
|
pvac::GetEvent result;
|
||||||
|
|
||||||
GetWait() :done(false) {}
|
GetWait() {}
|
||||||
virtual ~GetWait() {}
|
virtual ~GetWait() {}
|
||||||
virtual void getDone(const pvac::GetEvent& evt)
|
virtual void getDone(const pvac::GetEvent& evt)
|
||||||
{
|
{
|
||||||
@ -55,16 +72,7 @@ pvac::ClientChannel::get(double timeout,
|
|||||||
{
|
{
|
||||||
GetWait waiter;
|
GetWait waiter;
|
||||||
Operation op(get(&waiter, pvRequest));
|
Operation op(get(&waiter, pvRequest));
|
||||||
{
|
waiter.wait(timeout);
|
||||||
Guard G(waiter.mutex);
|
|
||||||
while(!waiter.done) {
|
|
||||||
UnGuard U(G);
|
|
||||||
if(!waiter.event.wait(timeout)) {
|
|
||||||
op.cancel();
|
|
||||||
throw Timeout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(waiter.result.event==pvac::GetEvent::Success)
|
if(waiter.result.event==pvac::GetEvent::Success)
|
||||||
return waiter.result.value;
|
return waiter.result.value;
|
||||||
else
|
else
|
||||||
@ -94,4 +102,105 @@ pvac::ClientChannel::rpc(double timeout,
|
|||||||
throw std::runtime_error(waiter.result.message);
|
throw std::runtime_error(waiter.result.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct PutValCommon : public pvac::ClientChannel::PutCallback,
|
||||||
|
public WaitCommon
|
||||||
|
{
|
||||||
|
pvac::PutEvent result;
|
||||||
|
|
||||||
|
PutValCommon() {}
|
||||||
|
virtual ~PutValCommon() {}
|
||||||
|
|
||||||
|
virtual void putDone(const PutEvent& evt)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Guard G(mutex);
|
||||||
|
if(done) {
|
||||||
|
LOG(pva::logLevelWarn, "oops, double event to PutCallback");
|
||||||
|
} else {
|
||||||
|
result = evt;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.signal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PutValScalar : public PutValCommon
|
||||||
|
{
|
||||||
|
const void* value;
|
||||||
|
pvd::ScalarType vtype;
|
||||||
|
|
||||||
|
PutValScalar(const void* value, pvd::ScalarType vtype) :value(value), vtype(vtype) {}
|
||||||
|
virtual ~PutValScalar() {}
|
||||||
|
|
||||||
|
virtual void putBuild(const epics::pvData::StructureConstPtr& build, Args& args)
|
||||||
|
{
|
||||||
|
pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(build));
|
||||||
|
pvd::PVScalarPtr value(root->getSubField<pvd::PVScalar>("value"));
|
||||||
|
if(value) {
|
||||||
|
value->putFrom(this->value, vtype);
|
||||||
|
args.tosend.set(value->getFieldOffset());
|
||||||
|
} else {
|
||||||
|
// TODO: handle enum
|
||||||
|
throw std::runtime_error("PV has no scalar 'value' sub-field");
|
||||||
|
}
|
||||||
|
args.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PutValArray : public PutValCommon
|
||||||
|
{
|
||||||
|
pvd::shared_vector<const void> arr;
|
||||||
|
|
||||||
|
PutValArray(const pvd::shared_vector<const void>& arr) :arr(arr) {}
|
||||||
|
virtual ~PutValArray() {}
|
||||||
|
|
||||||
|
virtual void putBuild(const epics::pvData::StructureConstPtr& build, Args& args)
|
||||||
|
{
|
||||||
|
pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(build));
|
||||||
|
pvd::PVScalarArrayPtr value(root->getSubField<pvd::PVScalarArray>("value"));
|
||||||
|
if(value) {
|
||||||
|
value->putFrom(arr);
|
||||||
|
args.tosend.set(value->getFieldOffset());
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("PV has no scalar array 'value' sub-field");
|
||||||
|
}
|
||||||
|
args.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
} //namespace
|
||||||
|
|
||||||
|
void
|
||||||
|
ClientChannel::putValue(const void* value,
|
||||||
|
pvd::ScalarType vtype,
|
||||||
|
double timeout,
|
||||||
|
pvd::PVStructure::const_shared_pointer pvRequest)
|
||||||
|
{
|
||||||
|
PutValScalar waiter(value, vtype);
|
||||||
|
Operation op(put(&waiter, pvRequest));
|
||||||
|
waiter.wait(timeout);
|
||||||
|
if(waiter.result.event==PutEvent::Success)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
throw std::runtime_error(waiter.result.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClientChannel::putValue(const epics::pvData::shared_vector<const void>& value,
|
||||||
|
double timeout,
|
||||||
|
epics::pvData::PVStructure::const_shared_pointer pvRequest)
|
||||||
|
{
|
||||||
|
PutValArray waiter(value);
|
||||||
|
Operation op(put(&waiter, pvRequest));
|
||||||
|
waiter.wait(timeout);
|
||||||
|
if(waiter.result.event==PutEvent::Success)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
throw std::runtime_error(waiter.result.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}//namespace pvac
|
}//namespace pvac
|
||||||
|
@ -135,7 +135,15 @@ struct epicsShareClass Timeout : public std::runtime_error
|
|||||||
Timeout();
|
Timeout();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Represents a single channel
|
/** Represents a single channel
|
||||||
|
*
|
||||||
|
* This class has two sets of methods, those which block for completion, and
|
||||||
|
* those which use callbacks to signal completion.
|
||||||
|
*
|
||||||
|
* Those which block accept a 'timeout' argument (in seconds).
|
||||||
|
*
|
||||||
|
* Those which use callbacks accept a 'cb' argument and return an Operation or Monitor handle object.
|
||||||
|
*/
|
||||||
class epicsShareClass ClientChannel
|
class epicsShareClass ClientChannel
|
||||||
{
|
{
|
||||||
struct Impl;
|
struct Impl;
|
||||||
@ -233,6 +241,28 @@ public:
|
|||||||
Operation put(PutCallback* cb,
|
Operation put(PutCallback* cb,
|
||||||
epics::pvData::PVStructure::const_shared_pointer pvRequest = epics::pvData::PVStructure::const_shared_pointer());
|
epics::pvData::PVStructure::const_shared_pointer pvRequest = epics::pvData::PVStructure::const_shared_pointer());
|
||||||
|
|
||||||
|
//! Put to the 'value' field and block until complete.
|
||||||
|
//! Accepts a scalar value
|
||||||
|
template<epics::pvData::ScalarType ID>
|
||||||
|
inline void putValue(typename epics::pvData::meta::arg_type<typename epics::pvData::ScalarTypeTraits<ID>::type>::type value,
|
||||||
|
double timeout = 3.0,
|
||||||
|
epics::pvData::PVStructure::const_shared_pointer pvRequest = epics::pvData::PVStructure::const_shared_pointer())
|
||||||
|
{
|
||||||
|
putValue(&value, ID, timeout, pvRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Put to the 'value' field and block until complete.
|
||||||
|
//! Accepts untyped scalar value
|
||||||
|
void putValue(const void* value, epics::pvData::ScalarType vtype,
|
||||||
|
double timeout,
|
||||||
|
epics::pvData::PVStructure::const_shared_pointer pvRequest);
|
||||||
|
|
||||||
|
//! Put to the 'value' field and block until complete.
|
||||||
|
//! Accepts scalar array
|
||||||
|
void putValue(const epics::pvData::shared_vector<const void>& value,
|
||||||
|
double timeout,
|
||||||
|
epics::pvData::PVStructure::const_shared_pointer pvRequest);
|
||||||
|
|
||||||
//! Monitor event notification
|
//! Monitor event notification
|
||||||
struct epicsShareClass MonitorCallback {
|
struct epicsShareClass MonitorCallback {
|
||||||
virtual ~MonitorCallback() {}
|
virtual ~MonitorCallback() {}
|
||||||
|
Reference in New Issue
Block a user