224 lines
5.6 KiB
C++
224 lines
5.6 KiB
C++
/**
|
|
* 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;
|
|
}
|