Files
pvAccess/pvtoolsSrc/pvinfo.cpp
2020-01-16 16:25:51 -08:00

207 lines
5.8 KiB
C++

/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <iostream>
#include <pva/client.h>
#include <pv/caProvider.h>
#include <stdio.h>
#include <epicsStdlib.h>
#include <epicsGetopt.h>
#include <epicsThread.h>
#include <pv/logger.h>
#include <pv/lock.h>
#include <vector>
#include <string>
#include <sstream>
#include <pv/event.h>
#include <epicsExit.h>
#include "pvutils.h"
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
namespace {
void usage (void)
{
fprintf (stderr, "\nUsage: pvinfo [options] <PV name>...\n\n"
"\noptions:\n"
" -h: Help: Print this message\n"
" -V: Print version and exit\n"
" -w <sec>: Wait time, specifies timeout, default is %f second(s)\n"
" -p <provider>: Set default provider name, default is '%s'\n"
" -d: Enable debug output\n"
" -c: Wait for clean shutdown and report used instance count (for expert users)"
"\nExample: pvinfo double01\n\n"
, timeout, defaultProvider.c_str());
}
int haderror;
struct GetInfo : public pvac::ClientChannel::InfoCallback,
public pvac::ClientChannel::ConnectCallback,
public Tracker
{
pvac::ClientChannel chan;
pvac::Operation op;
std::string peerName;
explicit GetInfo(pvac::ClientChannel& chan)
:chan(chan)
{
chan.addConnectListener(this);
}
virtual ~GetInfo()
{
chan.removeConnectListener(this);
}
virtual void connectEvent(const pvac::ConnectEvent& evt) OVERRIDE FINAL
{
if(evt.connected) {
Guard G(doneLock);
peerName = evt.peerName;
}
}
virtual void infoDone(const pvac::InfoEvent& evt) OVERRIDE FINAL
{
std::string pname;
{
Guard G(doneLock);
pname = peerName;
}
switch(evt.event) {
case pvac::InfoEvent::Cancel: break;
case pvac::InfoEvent::Fail:
std::cerr<<op.name()<<" Error: "<<evt.message<<"\n";
haderror = 1;
break;
case pvac::InfoEvent::Success: {
std::cout<<op.name()<<"\n"
"Server: "<<pname<<"\n"
"Type:\n";
pvd::format::indent_scope I(std::cout);
std::cout<<evt.type<<"\n";
}
}
done();
std::cout.flush();
}
};
} // namespace
int main (int argc, char *argv[])
{
int opt; /* getopt() current option */
bool debug = false;
setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */
while ((opt = getopt(argc, argv, ":hVw:p:dc")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage();
return 0;
case 'V': /* Print version */
{
fprintf(stdout, "pvAccess %u.%u.%u%s\n",
EPICS_PVA_MAJOR_VERSION,
EPICS_PVA_MINOR_VERSION,
EPICS_PVA_MAINTENANCE_VERSION,
(EPICS_PVA_DEVELOPMENT_FLAG)?"-SNAPSHOT":"");
fprintf(stdout, "pvData %u.%u.%u%s\n",
EPICS_PVD_MAJOR_VERSION,
EPICS_PVD_MINOR_VERSION,
EPICS_PVD_MAINTENANCE_VERSION,
(EPICS_PVD_DEVELOPMENT_FLAG)?"-SNAPSHOT":"");
fprintf(stdout, "Base %s\n", EPICS_VERSION_FULL);
return 0;
}
case 'w': /* Set PVA timeout value */
{
double temp;
if((epicsScanDouble(optarg, &temp)) != 1 || timeout <= 0.0)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('pvget -h' for help.)\n", optarg);
} else {
timeout = temp;
}
}
break;
case 'p': /* Set default provider */
defaultProvider = optarg;
break;
case 'd': /* Debug log level */
debug = true;
break;
case 'c': /* Clean-up and report used instance count */
break;
case '?':
fprintf(stderr,
"Unrecognized option: '-%c'. ('pvinfo -h' for help.)\n",
optopt);
return 1;
case ':':
fprintf(stderr,
"Option '-%c' requires an argument. ('pvinfo -h' for help.)\n",
optopt);
return 1;
default :
usage();
return 1;
}
}
if (argc == optind)
{
fprintf(stderr, "No pv name(s) specified. ('pvinfo -h' for help.)\n");
return 1;
}
SET_LOG_LEVEL(debug ? pva::logLevelDebug : pva::logLevelError);
std::vector<std::tr1::shared_ptr<GetInfo> > infos;
pva::ca::CAClientFactory::start();
{
pvac::ClientProvider prov(defaultProvider);
for(int i = optind; i<argc; i++) {
pvac::ClientChannel chan(prov.connect(argv[i]));
std::tr1::shared_ptr<GetInfo> info(new GetInfo(chan));
info->op = chan.info(info.get());
infos.push_back(info);
}
Tracker::prepare(); // install signal handler
{
Guard G(Tracker::doneLock);
while(Tracker::inprog.size() && !Tracker::abort) {
UnGuard U(G);
if(timeout<=0)
Tracker::doneEvt.wait();
else if(!Tracker::doneEvt.wait(timeout)) {
haderror = 1;
std::cerr<<"Timeout\n";
break;
}
}
}
}
return haderror ? 1 : 0;
}