pvaTestClient: put example

This commit is contained in:
Michael Davidsaver
2017-07-10 13:40:36 +02:00
parent 6436ceb04d
commit 8f4fafd668
5 changed files with 238 additions and 1 deletions

View File

@ -10,6 +10,17 @@ and again each time a channel becomes Connected.
*/ */
/** /**
@page examples_putme 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 putme.cpp
*/
/**
@page examples_monitorme Client Monitor Example @page examples_monitorme Client Monitor Example
This example demonstrates a client which sets up a persistent Monitor operation. This example demonstrates a client which sets up a persistent Monitor operation.

View File

@ -29,6 +29,7 @@ See the @ref providers page.
@section main_examples Examples @section main_examples Examples
- @ref examples_getme - @ref examples_getme
- @ref examples_putme
- @ref examples_monitorme - @ref examples_monitorme
*/ */

View File

@ -5,6 +5,7 @@ include $(TOP)/configure/CONFIG
PROD_LIBS += pvAccess pvData ca Com PROD_LIBS += pvAccess pvData ca Com
TESTPROD_HOST += getme TESTPROD_HOST += getme
TESTPROD_HOST += putme
TESTPROD_HOST += monitorme TESTPROD_HOST += monitorme
TESTPROD_HOST += spamme TESTPROD_HOST += spamme

223
examples/putme.cpp Normal file
View File

@ -0,0 +1,223 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvAccessCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#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>
//! [Headers]
#include <pv/configuration.h>
#include <pv/clientFactory.h>
#include <pv/caProvider.h>
#include <pv/pvaTestClient.h>
//! [Headers]
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 TestClientChannel::PutCallback
{
POINTER_DEFINITIONS(PutTracker);
TestOperation op;
const std::string value;
PutTracker(TestClientChannel& 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 pvd::PVStructure::const_shared_pointer putBuild(const epics::pvData::StructureConstPtr &build)
{
pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(build));
pvd::PVScalarPtr valfld(root->getSubFieldT<pvd::PVScalar>("value"));
valfld->putFrom(value);
std::cout<<"Put value "<<valfld<<"\n";
return root;
}
virtual void putDone(const TestPutEvent &evt)
{
switch(evt.event) {
case TestPutEvent::Fail:
std::cerr<<op.name()<<" Error: "<<evt.message<<"\n";
break;
case TestPutEvent::Cancel:
std::cerr<<op.name()<<" Cancelled\n";
break;
case TestPutEvent::Success:
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;
}
}
typedef std::vector<std::pair<std::string, std::string> > args_t;
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("field()"));
// explicitly select configuration from process environment
pva::Configuration::shared_pointer conf(pva::ConfigurationBuilder()
.push_env()
.build());
// add "pva" provider to registry
pva::ClientFactory::start();
// add "ca" provider to registry
pva::ca::CAClientFactory::start();
std::cout<<"Use provider: "<<providerName<<"\n";
TestClientProvider provider(providerName, conf);
std::vector<PutTracker::shared_pointer> ops(args.size());
{
Guard G(mutex);
waitingFor = args.size();
}
for(size_t i=0; i<args.size(); i++)
{
args_t::const_reference arg = args[i];
TestClientChannel 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
{
Guard G(mutex);
while(waitingFor) {
UnGuard U(G);
if(waitTime<0.0) {
done.wait();
} else if(!done.wait(waitTime)) {
std::cerr<<"Timeout\n";
break; // timeout
}
}
}
} catch(std::exception& e){
PRINT_EXCEPTION(e);
std::cerr<<"Error: "<<e.what()<<"\n";
return 1;
}
return 0;
}

View File

@ -109,6 +109,7 @@ struct GetPutter : public pva::ChannelPutRequester,
LOG(pva::logLevelInfo, "Lost exception in %s: %s", CURRENT_FUNCTION, e.what()); LOG(pva::logLevelInfo, "Lost exception in %s: %s", CURRENT_FUNCTION, e.what());
} }
} }
// check putcb again after UnGuard
if(putcb) { if(putcb) {
pvd::BitSet::shared_pointer all(new pvd::BitSet); pvd::BitSet::shared_pointer all(new pvd::BitSet);
all->set(0); all->set(0);
@ -132,7 +133,7 @@ struct GetPutter : public pva::ChannelPutRequester,
pva::ChannelPut::shared_pointer const & channelPut) OVERRIDE FINAL pva::ChannelPut::shared_pointer const & channelPut) OVERRIDE FINAL
{ {
Guard G(mutex); Guard G(mutex);
if(!getcb) return; if(!putcb) return;
if(!status.isOK()) { if(!status.isOK()) {
event.message = status.getMessage(); event.message = status.getMessage();