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
|
||||
|
||||
This example demonstrates a client which issues a Get operation on startup,
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
- Simplest (shortest) possible
|
||||
- @ref examples_miniget
|
||||
- @ref examples_miniput
|
||||
- More complete
|
||||
- @ref examples_getme
|
||||
- @ref examples_putme
|
||||
|
@ -10,6 +10,7 @@ TESTPROD_HOST += monitorme
|
||||
TESTPROD_HOST += spamme
|
||||
|
||||
TESTPROD_HOST += miniget
|
||||
TESTPROD_HOST += miniput
|
||||
|
||||
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;
|
||||
|
||||
namespace {
|
||||
struct GetWait : pvac::ClientChannel::GetCallback
|
||||
struct WaitCommon
|
||||
{
|
||||
epicsMutex mutex;
|
||||
epicsEvent event;
|
||||
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;
|
||||
|
||||
GetWait() :done(false) {}
|
||||
GetWait() {}
|
||||
virtual ~GetWait() {}
|
||||
virtual void getDone(const pvac::GetEvent& evt)
|
||||
{
|
||||
@ -55,16 +72,7 @@ pvac::ClientChannel::get(double timeout,
|
||||
{
|
||||
GetWait waiter;
|
||||
Operation op(get(&waiter, pvRequest));
|
||||
{
|
||||
Guard G(waiter.mutex);
|
||||
while(!waiter.done) {
|
||||
UnGuard U(G);
|
||||
if(!waiter.event.wait(timeout)) {
|
||||
op.cancel();
|
||||
throw Timeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
waiter.wait(timeout);
|
||||
if(waiter.result.event==pvac::GetEvent::Success)
|
||||
return waiter.result.value;
|
||||
else
|
||||
@ -94,4 +102,105 @@ pvac::ClientChannel::rpc(double timeout,
|
||||
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
|
||||
|
@ -135,7 +135,15 @@ struct epicsShareClass Timeout : public std::runtime_error
|
||||
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
|
||||
{
|
||||
struct Impl;
|
||||
@ -233,6 +241,28 @@ public:
|
||||
Operation put(PutCallback* cb,
|
||||
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
|
||||
struct epicsShareClass MonitorCallback {
|
||||
virtual ~MonitorCallback() {}
|
||||
|
Reference in New Issue
Block a user