pvAccessCPP  7.1.7
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Client Put Example

This example demonstrates a client which issues a Put operation on startup, waits for acknowledgement that the put has been handled, then exits.

#include <set>
#include <queue>
#include <vector>
#include <string>
#include <exception>
#if !defined(_WIN32)
#include <signal.h>
#define USE_SIGNAL
#endif
#include <epicsEvent.h>
#include <epicsMutex.h>
#include <epicsGuard.h>
#include <epicsGetopt.h>
#include <pv/configuration.h>
#include <pv/caProvider.h>
#include <pva/client.h>
#include <pv/epicsException.h>
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
namespace {
typedef epicsGuard<epicsMutex> Guard;
typedef epicsGuardRelease<epicsMutex> UnGuard;
epicsMutex mutex;
epicsEvent done;
size_t waitingFor;
#ifdef USE_SIGNAL
void alldone(int num)
{
(void)num;
done.signal();
}
#endif
struct PutTracker : public pvac::ClientChannel::PutCallback
{
POINTER_DEFINITIONS(PutTracker);
const std::string value;
PutTracker(pvac::ClientChannel& channel,
const pvd::PVStructure::const_shared_pointer& pvReq,
const std::string& value)
:op(channel.put(this, pvReq)) // put() starts here
,value(value)
{}
virtual ~PutTracker()
{
op.cancel();
}
virtual void putBuild(const epics::pvData::StructureConstPtr &build, pvac::ClientChannel::PutCallback::Args& args) OVERRIDE FINAL
{
// At this point we have the user provided value string 'value'
// and the server provided structure (with types).
// note: an exception thrown here will result in putDone() w/ Fail
// allocate a new structure instance.
// we are one-shot so don't bother to re-use
pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(build));
// we only know about writes to scalar 'value' field
pvd::PVScalarPtr valfld(root->getSubFieldT<pvd::PVScalar>("value"));
// attempt convert string to actual field type
valfld->putFrom(value);
args.root = root; // non-const -> const
// mark only 'value' field to be sent.
// other fields w/ default values won't be sent.
args.tosend.set(valfld->getFieldOffset());
std::cout<<"Put value "<<valfld<<" sending="<<args.tosend<<"\n";
}
virtual void putDone(const pvac::PutEvent &evt) OVERRIDE FINAL
{
switch(evt.event) {
std::cerr<<op.name()<<" Error: "<<evt.message<<"\n";
break;
std::cerr<<op.name()<<" Cancelled\n";
break;
std::cout<<op.name()<<" Done\n";
}
{
Guard G(mutex);
waitingFor--;
}
done.signal();
}
};
void usage()
{
std::cout<<"Usage: putme [-h] [-P <provider>] [-w <timeout>] [-r <request>] pvname=value ...\n";
}
std::string strip(const std::string& inp)
{
size_t f=inp.find_first_not_of(" \t\n\r"),
l=inp.find_last_not_of (" \t\n\r");
if(f==inp.npos || f>l)
throw std::invalid_argument("Empty string");
return inp.substr(f, l-f+1);
}
} // namespace
int main(int argc, char *argv[]) {
try {
double waitTime = 5.0;
std::string providerName("pva"), request("field()");
int opt;
while( (opt=getopt(argc, argv, "hP:w:r:"))!=-1)
{
switch(opt) {
case 'P':
providerName = optarg;
break;
case 'w':
waitTime = pvd::castUnsafe<double, std::string>(optarg);
break;
case 'r':
request = optarg;
break;
default:
std::cerr<<"Unknown argument "<<opt<<"\n";
/* fall through */
case 'h':
usage();
return 1;
}
}
args_t args;
for(int i=optind; i<argc; i++)
{
std::string arg(argv[i]);
size_t eq = arg.find('=');
if(eq==arg.npos) {
std::cerr<<"Missing '=' in \""<<arg<<"\"\n";
usage();
return 1;
}
std::string pv (strip(arg.substr(0, eq))),
val(strip(arg.substr(eq+1)));
args.push_back(std::make_pair(pv, val));
}
// build "pvRequest" which asks for all fields
pvd::PVStructure::const_shared_pointer pvReq(pvd::createRequest(request));
// explicitly select configuration from process environment
pva::Configuration::shared_pointer conf(pva::ConfigurationBuilder()
.push_env()
.build());
// "pva" provider automatically in registry
// add "ca" provider to registry
std::cout<<"Use provider: "<<providerName<<"\n";
pvac::ClientProvider provider(providerName, conf);
{
Guard G(mutex);
waitingFor = args.size();
}
for(size_t i=0; i<args.size(); i++)
{
args_t::const_reference arg = args[i];
pvac::ClientChannel chan(provider.connect(arg.first));
PutTracker::shared_pointer op(new PutTracker(chan, pvReq, arg.second));
ops.push_back(op);
}
#ifdef USE_SIGNAL
signal(SIGINT, alldone);
signal(SIGTERM, alldone);
signal(SIGQUIT, alldone);
#endif
int ret = 0;
{
Guard G(mutex);
while(waitingFor) {
UnGuard U(G);
if(waitTime<0.0) {
done.wait();
} else if(!done.wait(waitTime)) {
std::cerr<<"Timeout\n";
ret = 1;
break; // timeout
}
}
}
return ret;
} catch(std::exception& e){
PRINT_EXCEPTION(e);
std::cerr<<"Error: "<<e.what()<<"\n";
return 2;
}
}