This is Unofficial EPICS BASE Doxygen Site
pvput.cpp
Go to the documentation of this file.
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 #include <iostream>
6 #include <vector>
7 #include <string>
8 #include <istream>
9 #include <fstream>
10 #include <sstream>
11 
12 #include <stdio.h>
13 #include <epicsExit.h>
14 
15 #include <epicsStdlib.h>
16 #include <epicsGetopt.h>
17 #include <epicsThread.h>
18 
19 #include <pv/logger.h>
20 #include <pv/lock.h>
21 #include <pv/convert.h>
22 #include <pv/pvdVersion.h>
23 #include <pv/json.h>
24 
25 #include <pva/client.h>
26 
27 #include <pv/pvaDefs.h>
28 #include <pv/event.h>
29 
30 #include <pv/caProvider.h>
31 
32 #include "pvutils.h"
33 
34 namespace {
35 
36 void usage (bool details=false)
37 {
38  fprintf (stderr,
39  "Usage: pvput [options] <PV name> <value>\n"
40  " pvput [options] <PV name> <size/ignored> <value> [<value> ...]\n"
41  " pvput [options] <PV name> <field>=<value> ...\n"
42  " pvput [options] <PV name> <json_array>\n"
43  " pvput [options] <PV name> <json_map>\n"
44  "\n"
46  " Deprecated options:\n"
47  " default: Auto - try value as enum string, then as index number\n"
48  " -n, -s, -F, -t: ignored\n"
49  " -f <input file>: error"
50  , request.c_str(), timeout, defaultProvider.c_str());
51  if(details) {
52  fprintf (stderr,
53  "\n JSON support is present\n"
54  "\nExamples:\n"
55  "\n"
56  " pvput double01 1.234 # shorthand\n"
57  " pvput double01 value=1.234\n"
58  "\n"
59  " pvput arr:pv X 1.0 2.0 # shorthand (X is arbitrary and ignored)\n"
60  " pvput arr:pv \"[1.0, 2.0]\" # shorthand\n"
61  " pvput arr:pv value=\"[1.0, 2.0]\"\n"
62  "\n"
63  "Field values may be given with JSON syntax.\n"
64  "\n"
65  "Complete structure\n"
66  "\n"
67  " pvput double01 '{\"value\":1.234}'\n"
68  "\n"
69  "Sub-structure(s)\n"
70  "\n"
71  " pvput group:pv some='{\"value\":1.234}' other='{\"value\":\"a string\"}'\n"
72  "\n"
73  );
74  }
75 }
76 
77 void printValue(std::string const & channelName, pvd::PVStructure::const_shared_pointer const & pv)
78 {
79  std::cout<<pv->stream().format(outmode);
80  std::cout.flush();
81 }
82 
83 struct Putter : public pvac::ClientChannel::PutCallback
84 {
85  epicsEvent wait;
87  bool done;
89  std::string message;
90 
91  Putter() :done(false) {}
92 
93  typedef pvd::shared_vector<std::string> bare_t;
94  bare_t bare;
95 
96  typedef std::pair<std::string, std::string> KV_t;
97  typedef std::vector<KV_t> pairs_t;
98  pairs_t pairs;
99 
101 
102  virtual void putBuild(const epics::pvData::StructureConstPtr& build, Args& args)
103  {
104  if(debugFlag) std::cerr<<"Server defined structure\n"<<build;
105  pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(build));
106 
107  if(bare.size()==1 && bare[0][0]=='{') {
108  if(debugFlag) fprintf(stderr, "In JSON top mode\n");
109  std::istringstream strm(bare[0]);
110  parseJSON(strm, root, &args.tosend);
111 
112  } else if(pairs.empty()) {
113  if(debugFlag) fprintf(stderr, "In plain value mode\n");
114 
115  pvd::PVFieldPtr fld(root->getSubField("value"));
116  if(!fld)
117  throw std::runtime_error("Structure has no .value");
118  pvd::Type ftype = fld->getField()->getType();
119 
120  if(ftype==pvd::scalar) {
121  if(bare.size()!=1) {
122  throw std::runtime_error("Can't assign multiple values to scalar");
123  }
124  pvd::PVScalar* sfld(static_cast<pvd::PVScalar*>(fld.get()));
125  sfld->putFrom(bare[0]);
126  args.tosend.set(sfld->getFieldOffset());
127 
128  } else if(ftype==pvd::scalarArray) {
129  pvd::PVScalarArray* sfld(static_cast<pvd::PVScalarArray*>(fld.get()));
130 
131  // first element is "length" which we ignore for compatibility
132  bare.slice(1);
133 
134  sfld->putFrom(freeze(bare));
135  args.tosend.set(sfld->getFieldOffset());
136 
137  } else if(ftype==pvd::structure && fld->getField()->getID()=="enum_t") {
138  if(bare.size()!=1) {
139  throw std::runtime_error("Can't assign multiple values to enum");
140  }
141  pvd::PVStructure* sfld(static_cast<pvd::PVStructure*>(fld.get()));
142 
143  assert(!!args.previous); // ensure by calling put(..., true) below
144  pvd::PVScalar* idxfld(sfld->getSubFieldT<pvd::PVScalar>("index").get());
145  pvd::PVStringArray::const_svector choices(args.previous->getSubFieldT<pvd::PVStringArray>("value.choices")->view());
146 
147  bool found=false;
148  for(size_t i=0; i<choices.size(); i++) {
149  if(bare[0]==choices[i]) {
150  idxfld->putFrom<pvd::int64>(i);
151  found=true;
152  break;
153  }
154  }
155 
156  if(!found) {
157  // try to parse as integer
158  idxfld->putFrom(bare[0]);
159  }
160 
161  args.tosend.set(idxfld->getFieldOffset());
162  } else {
163  throw std::runtime_error("Don't know how to set field .value");
164  }
165 
166  } else {
167  if(debugFlag) fprintf(stderr, "In field=value mode\n");
168 
169  for(pairs_t::const_iterator it=pairs.begin(), end=pairs.end(); it!=end; ++it)
170  {
171  pvd::PVFieldPtr fld(root->getSubField(it->first));
172  if(!fld) {
173  fprintf(stderr, "%s : Warning: no such field\n", it->first.c_str());
174  // ignore
175 
176  } else if(it->second[0]=='[') {
178  jarray(arr, it->second.c_str());
179 
180  pvd::PVScalarArray* afld(dynamic_cast<pvd::PVScalarArray*>(fld.get()));
181  if(!afld) {
182  fprintf(stderr, "%s : Error not a scalar array field\n", it->first.c_str());
183  throw std::runtime_error("Not a scalar array field");
184  }
185  afld->putFrom(freeze(arr));
186  args.tosend.set(afld->getFieldOffset());
187 
188  } else if(it->second[0]=='{' || it->second[0]=='[') {
189  std::istringstream strm(it->second);
190  parseJSON(strm, fld, &args.tosend);
191 
192  } else {
193  pvd::PVScalarPtr sfld(std::tr1::dynamic_pointer_cast<pvd::PVScalar>(fld));
194  if(!sfld) {
195  fprintf(stderr, "%s : Error: need a scalar field\n", it->first.c_str());
196  } else {
197  sfld->putFrom(it->second);
198  args.tosend.set(sfld->getFieldOffset());
199  }
200  }
201  }
202  }
203 
204  args.root = root;
205  if(debugFlag)
206  std::cout<<"To be sent: "<<args.tosend<<"\n"<<args.root;
207  }
208 
209  virtual void putDone(const pvac::PutEvent& evt)
210  {
211  {
212  epicsGuard<epicsMutex> G(lock);
213  result = evt.event;
214  message = evt.message;
215  done = true;
216  }
217 
218  wait.signal();
219  }
220 };
221 
222 } // namespace
223 
224 int main (int argc, char *argv[])
225 {
226  try {
227  int opt; /* getopt() current option */
228  bool quiet = false;
229 
230  setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */
231  putenv(const_cast<char*>("POSIXLY_CORRECT=")); /* Behave correct on GNU getopt systems; e.g. handle negative numbers */
232 
233  while ((opt = getopt(argc, argv, ":hvVM:r:w:tp:qdF:f:ns")) != -1) {
234  switch (opt) {
235  case 'h': /* Print usage */
236  usage(true);
237  return 0;
238  case 'v':
239  outmode = pvd::PVStructure::Formatter::Raw;
240  break;
241  case 'V': /* Print version */
242  {
243  fprintf(stdout, "pvAccess %u.%u.%u%s\n",
244  EPICS_PVA_MAJOR_VERSION,
245  EPICS_PVA_MINOR_VERSION,
246  EPICS_PVA_MAINTENANCE_VERSION,
247  (EPICS_PVA_DEVELOPMENT_FLAG)?"-SNAPSHOT":"");
248  fprintf(stdout, "pvData %u.%u.%u%s\n",
249  EPICS_PVD_MAJOR_VERSION,
250  EPICS_PVD_MINOR_VERSION,
251  EPICS_PVD_MAINTENANCE_VERSION,
252  (EPICS_PVD_DEVELOPMENT_FLAG)?"-SNAPSHOT":"");
253  fprintf(stdout, "Base %s\n", EPICS_VERSION_FULL);
254  return 0;
255  }
256  case 'M':
257  if(strcmp(optarg, "raw")==0) {
258  outmode = pvd::PVStructure::Formatter::Raw;
259  } else if(strcmp(optarg, "nt")==0) {
260  outmode = pvd::PVStructure::Formatter::NT;
261  } else if(strcmp(optarg, "json")==0) {
262  outmode = pvd::PVStructure::Formatter::JSON;
263  } else {
264  fprintf(stderr, "Unknown output mode '%s'\n", optarg);
265  outmode = pvd::PVStructure::Formatter::Raw;
266  }
267  break;
268  case 'w': /* Set PVA timeout value */
269  {
270  double temp;
271  if((epicsScanDouble(optarg, &temp)) != 1)
272  {
273  fprintf(stderr, "'%s' is not a valid timeout value "
274  "- ignored. ('pvput -h' for help.)\n", optarg);
275  } else {
276  timeout = temp;
277  }
278  }
279  break;
280  case 'r': /* Set PVA timeout value */
281  request = optarg;
282  break;
283  case 't': /* Terse mode */
284  // deprecated
285  break;
286  case 'd': /* Debug log level */
287  debugFlag = true;
288  break;
289  case 'p': /* Set default provider */
291  break;
292  case 'q': /* Quiet mode */
293  quiet = true;
294  break;
295  case 'F': /* Store this for output formatting */
296  break;
297  case 'f': /* Use input stream as input */
298  fprintf(stderr, "Unsupported option -f\n");
299  return 1;
300  case 'n':
301  break;
302  case 's':
303  break;
304  case '?':
305  fprintf(stderr,
306  "Unrecognized option: '-%c'. ('pvput -h' for help.)\n",
307  optopt);
308  return 1;
309  case ':':
310  fprintf(stderr,
311  "Option '-%c' requires an argument. ('pvput -h' for help.)\n",
312  optopt);
313  return 1;
314  default :
315  usage();
316  return 1;
317  }
318  }
319 
320  if (argc <= optind)
321  {
322  fprintf(stderr, "No pv name specified. ('pvput -h' for help.)\n");
323  return 1;
324  }
325  std::string pv = argv[optind++];
326 
327  std::string providerName(defaultProvider);
328  std::string pvName(pv);
329 
330  int nVals = argc - optind; /* Remaining arg list are PV names */
331  if (nVals < 1)
332  {
333  fprintf(stderr, "No value(s) specified. ('pvput -h' for help.)\n");
334  return 1;
335  }
336 
337  std::vector<std::string> values;
338  // copy values from command line
339  for (int n = 0; optind < argc; n++, optind++)
340  values.push_back(argv[optind]);
341 
342  Putter thework;
343 
344  for(size_t i=0, N=values.size(); i<N; i++)
345  {
346  size_t sep = values[i].find_first_of('=');
347  if(sep==std::string::npos) {
348  thework.bare.push_back(values[i]);
349  } else {
350  thework.pairs.push_back(std::make_pair(values[i].substr(0, sep),
351  values[i].substr(sep+1)));
352  }
353  }
354 
355  if(!thework.bare.empty() && !thework.pairs.empty()) {
356  usage();
357  fprintf(stderr, "\nCan't mix bare values and field=value pairs\n");
358  return 1;
359 
360  } else if(thework.bare.size()==1 && thework.bare[0][0]=='[') {
361  // treat plain "[...]" as "value=[...]"
362  thework.pairs.push_back(std::make_pair("value", thework.bare[0]));
363  thework.bare.clear();
364  }
365 
366  pvd::PVStructure::shared_pointer pvRequest;
367  try {
368  pvRequest = pvd::createRequest(request);
369  } catch(std::exception& e){
370  fprintf(stderr, "failed to parse request string: %s\n", e.what());
371  return 1;
372  }
373 
375 
376  std::cout << std::boolalpha;
377 
379 
380  pvac::ClientProvider ctxt(providerName);
381 
382  pvac::ClientChannel chan(ctxt.connect(pvName));
383 
384  if (!quiet) {
385  std::cout << "Old : ";
386  printValue(pvName, chan.get(timeout, pvRequest));
387  }
388 
389  {
390  pvac::Operation op(chan.put(&thework, pvRequest, true));
391 
392  epicsGuard<epicsMutex> G(thework.lock);
393  while(!thework.done) {
395  if(!thework.wait.wait(timeout)) {
396  fprintf(stderr, "Put timeout\n");
397  return 1;
398  }
399  }
400  }
401 
402  if(thework.result==pvac::PutEvent::Fail) {
403  fprintf(stderr, "Error: %s\n", thework.message.c_str());
404  }
405 
406  if (!quiet) {
407  std::cout << "New : ";
408  }
409  printValue(pvName, chan.get(timeout, pvRequest));
410 
411  return thework.result!=pvac::PutEvent::Success;
412  } catch(std::exception& e) {
413  std::cerr<<"Error: "<<e.what()<<"\n";
414  return 1;
415  }
416 }
double timeout
Definition: pvutils.cpp:25
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: epicsGetopt.c:65
virtual const_svector view() const OVERRIDE FINAL
Fetch a read-only view of the current array data.
Definition: pvData.h:1209
PVScalar is the base class for each scalar field.
Definition: pvData.h:272
pvac::PutEvent result
Definition: clientSync.cpp:117
std::string request
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
epicsMutexId lock
Definition: osiClockTime.c:37
int i
Definition: scan.c:967
int optind
Definition: epicsGetopt.c:50
Definition: tool_lib.h:67
#define SET_LOG_LEVEL(level)
Definition: logger.h:50
callbacks for put()
Definition: client.h:358
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
#define NULL
Definition: catime.c:38
#define epicsScanDouble(str, to)
Definition: epicsStdlib.h:78
PVStructure::shared_pointer createRequest(std::string const &request)
Handle for in-progress get/put/rpc operation.
Definition: client.h:50
std::string message
Check when event==Fail.
Definition: client.h:95
int optopt
Definition: epicsGetopt.c:50
int main(int argc, char *argv[])
Definition: pvput.cpp:224
Information on put completion.
Definition: client.h:88
void jarray(pvd::shared_vector< std::string > &out, const char *inp)
Definition: pvutils.cpp:68
template class for all extensions of PVArray.
Definition: pvData.h:55
enum pvac::PutEvent::event_t event
Base class for a scalarArray.
Definition: pvData.h:618
std::tr1::shared_ptr< PVScalar > PVScalarPtr
Definition: pvData.h:77
Extended replacement for the Posix exit and atexit routines.
epics::pvData::PVStructure::shared_pointer parseJSON(std::istream &strm)
Definition: parseany.cpp:255
Data interface for a structure,.
Definition: pvData.h:712
int putenv(char *)
#define stdout
Definition: epicsStdio.h:30
Central client context.
Definition: client.h:517
#define COMMON_OPTIONS
Definition: pvutils.h:25
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
int64_t int64
Definition: pvType.h:87
ClientChannel connect(const std::string &name, const ClientChannel::Options &conf=ClientChannel::Options())
Definition: client.cpp:295
request ends in failure. Check message
Definition: client.h:91
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition: pvData.h:66
void done(int k)
Definition: antelope.c:77
#define stderr
Definition: epicsStdio.h:32
ChannelPut::shared_pointer op
Definition: pvAccess.cpp:132
bool debugFlag
Definition: pvutils.cpp:26
C++ and C descriptions for a thread.
static void start()
start provider ca
Definition: caProvider.cpp:201
std::string defaultProvider
char * optarg
Definition: epicsGetopt.c:55
void usage(void)
Definition: cainfo.c:36
pvd::PVStructure::Formatter::format_t outmode
Definition: pvutils.cpp:28
#define false
Definition: flexdef.h:85
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
It worked!
Definition: client.h:93
::epics::pvData::shared_vector< const T > const_svector
Definition: pvData.h:1185