pvac: add synchronous put to 'value' field

This commit is contained in:
Michael Davidsaver
2017-07-18 14:02:14 +02:00
parent 43019344d2
commit 1a47e5fb0a
6 changed files with 196 additions and 13 deletions

View File

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