This is Unofficial EPICS BASE Doxygen Site
camonitor.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2009 Helmholtz-Zentrum Berlin fuer Materialien und Energie.
3 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
4 * National Laboratory.
5 * Copyright (c) 2002 The Regents of the University of California, as
6 * Operator of Los Alamos National Laboratory.
7 * Copyright (c) 2002 Berliner Elektronenspeicherringgesellschaft fuer
8 * Synchrotronstrahlung.
9 * EPICS BASE is distributed subject to a Software License Agreement found
10 * in file LICENSE that is included with this distribution.
11 \*************************************************************************/
12 
13 /*
14  * Author: Ralph Lange (BESSY)
15  *
16  * Modification History
17  * 2008/04/16 Ralph Lange (BESSY)
18  * Updated usage info
19  * 2009/03/31 Larry Hoff (BNL)
20  * Added field separators
21  * 2009/04/01 Ralph Lange (HZB/BESSY)
22  * Added support for long strings (array of char) and quoting of nonprintable characters
23  *
24  */
25 
26 #include <stdio.h>
27 #include <epicsStdlib.h>
28 #include <string.h>
29 #include "epicsVersion.h"
30 
31 #include <cadef.h>
32 #include <epicsGetopt.h>
33 
34 #include "tool_lib.h"
35 
36 #define VALID_DOUBLE_DIGITS 18 /* Max usable precision for a double */
37 
38 static unsigned long reqElems = 0;
39 static unsigned long eventMask = DBE_VALUE | DBE_ALARM; /* Event mask used */
40 static int floatAsString = 0; /* Flag: fetch floats as string */
41 static int nConn = 0; /* Number of connected PVs */
42 
43 
44 void usage (void)
45 {
46  fprintf (stderr, "\nUsage: camonitor [options] <PV name> ...\n"
47  "\n"
48  " -h: Help: Print this message\n"
49  " -V: Version: Show EPICS and CA versions\n"
50  "Channel Access options:\n"
51  " -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
52  " -m <msk>: Specify CA event mask to use. <msk> is any combination of\n"
53  " 'v' (value), 'a' (alarm), 'l' (log/archive), 'p' (property).\n"
54  " Default event mask is 'va'\n"
55  " -p <pri>: CA priority (0-%u, default 0=lowest)\n"
56  "Timestamps:\n"
57  " Default: Print absolute timestamps (as reported by CA server)\n"
58  " -t <key>: Specify timestamp source(s) and type, with <key> containing\n"
59  " 's' = CA server (remote) timestamps\n"
60  " 'c' = CA client (local) timestamps (shown in '()'s)\n"
61  " 'n' = no timestamps\n"
62  " 'r' = relative timestamps (time elapsed since start of program)\n"
63  " 'i' = incremental timestamps (time elapsed since last update)\n"
64  " 'I' = incremental timestamps (time since last update, by channel)\n"
65  " 'r', 'i' or 'I' require 's' or 'c' to select the time source\n"
66  "Enum format:\n"
67  " -n: Print DBF_ENUM values as number (default is enum string)\n"
68  "Array values: Print number of elements, then list of values\n"
69  " Default: Request and print all elements (dynamic arrays supported)\n"
70  " -# <num>: Request and print up to <num> elements\n"
71  " -S: Print arrays of char as a string (long string)\n"
72  "Floating point format:\n"
73  " Default: Use %%g format\n"
74  " -e <num>: Use %%e format, with a precision of <num> digits\n"
75  " -f <num>: Use %%f format, with a precision of <num> digits\n"
76  " -g <num>: Use %%g format, with a precision of <num> digits\n"
77  " -s: Get value as string (honors server-side precision)\n"
78  " -lx: Round to long integer and print as hex number\n"
79  " -lo: Round to long integer and print as octal number\n"
80  " -lb: Round to long integer and print as binary number\n"
81  "Integer number format:\n"
82  " Default: Print as decimal number\n"
83  " -0x: Print as hex number\n"
84  " -0o: Print as octal number\n"
85  " -0b: Print as binary number\n"
86  "Alternate output field separator:\n"
87  " -F <ofs>: Use <ofs> to separate fields in output\n"
88  "\n"
89  "Example: camonitor -f8 my_channel another_channel\n"
90  " (doubles are printed as %%f with precision of 8)\n\n"
92 }
93 
94 
95 
96 /*+**************************************************************************
97  *
98  * Function: event_handler
99  *
100  * Description: CA event_handler for request type callback
101  * Prints the event data
102  *
103  * Arg(s) In: args - event handler args (see CA manual)
104  *
105  **************************************************************************-*/
106 
107 static void event_handler (evargs args)
108 {
109  pv* pv = args.usr;
110 
111  pv->status = args.status;
112  if (args.status == ECA_NORMAL)
113  {
114  pv->dbrType = args.type;
115  pv->nElems = args.count;
116  pv->value = (void *) args.dbr; /* casting away const */
117 
118  print_time_val_sts(pv, reqElems);
119  fflush(stdout);
120 
121  pv->value = NULL;
122  }
123 }
124 
125 
126 /*+**************************************************************************
127  *
128  * Function: connection_handler
129  *
130  * Description: CA connection_handler
131  *
132  * Arg(s) In: args - connection_handler_args (see CA manual)
133  *
134  **************************************************************************-*/
135 
136 static void connection_handler ( struct connection_handler_args args )
137 {
138  pv *ppv = ( pv * ) ca_puser ( args.chid );
139  if ( args.op == CA_OP_CONN_UP ) {
140  nConn++;
141 
142  if (ppv->onceConnected && ppv->dbfType != ca_field_type(ppv->chid)) {
143  /* Data type has changed. Rebuild connection with new type. */
145  ppv->evid = NULL;
146  }
147 
148  if (!ppv->evid) {
149  ppv->onceConnected = 1;
150  /* Set up pv structure */
151  /* ------------------- */
152 
153  /* Get natural type and array count */
154  ppv->dbfType = ca_field_type(ppv->chid);
155  ppv->dbrType = dbf_type_to_DBR_TIME(ppv->dbfType); /* Use native type */
156  if (dbr_type_is_ENUM(ppv->dbrType)) /* Enums honour -n option */
157  {
158  if (enumAsNr) ppv->dbrType = DBR_TIME_INT;
159  else ppv->dbrType = DBR_TIME_STRING;
160  }
161  else if (floatAsString &&
163  {
164  ppv->dbrType = DBR_TIME_STRING;
165  }
166  /* Set request count */
167  ppv->nElems = ca_element_count(ppv->chid);
168  ppv->reqElems = reqElems > ppv->nElems ? ppv->nElems : reqElems;
169 
170  /* Issue CA request */
171  /* ---------------- */
172  /* install monitor once with first connect */
174  ppv->reqElems,
175  ppv->chid,
176  eventMask,
178  (void*)ppv,
179  &ppv->evid);
180  }
181  }
182  else if ( args.op == CA_OP_CONN_DOWN ) {
183  nConn--;
184  ppv->status = ECA_DISCONN;
185  print_time_val_sts(ppv, reqElems);
186  }
187 }
188 
189 
190 /*+**************************************************************************
191  *
192  * Function: main
193  *
194  * Description: camonitor main()
195  * Evaluate command line options, set up CA, connect the
196  * channels, collect and print the data as requested
197  *
198  * Arg(s) In: [options] <pv-name> ...
199  *
200  * Arg(s) Out: none
201  *
202  * Return(s): Standard return code (0=success, 1=error)
203  *
204  **************************************************************************-*/
205 
206 int main (int argc, char *argv[])
207 {
208  int returncode = 0;
209  int n;
210  int result; /* CA result */
211  IntFormatT outType; /* Output type */
212 
213  int opt; /* getopt() current option */
214  int digits = 0; /* getopt() no. of float digits */
215 
216  int nPvs; /* Number of PVs */
217  pv* pvs; /* Array of PV structures */
218 
219  LINE_BUFFER(stdout); /* Configure stdout buffering */
220 
221  while ((opt = getopt(argc, argv, ":nhVm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
222  switch (opt) {
223  case 'h': /* Print usage */
224  usage();
225  return 0;
226  case 'V':
227  printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
228  return 0;
229  case 'n': /* Print ENUM as index numbers */
230  enumAsNr=1;
231  break;
232  case 't': /* Select timestamp source(s) and type */
233  tsSrcServer = 0;
234  tsSrcClient = 0;
235  {
236  int i = 0;
237  char c;
238  while ((c = optarg[i++]))
239  switch (c) {
240  case 's': tsSrcServer = 1; break;
241  case 'c': tsSrcClient = 1; break;
242  case 'n': break;
243  case 'r': tsType = relative; break;
244  case 'i': tsType = incremental; break;
245  case 'I': tsType = incrementalByChan; break;
246  default :
247  fprintf(stderr, "Invalid argument '%c' "
248  "for option '-t' - ignored.\n", c);
249  }
250  }
251  break;
252  case 'w': /* Set CA timeout value */
253  if(epicsScanDouble(optarg, &caTimeout) != 1)
254  {
255  fprintf(stderr, "'%s' is not a valid timeout value "
256  "- ignored. ('camonitor -h' for help.)\n", optarg);
258  }
259  break;
260  case '#': /* Array count */
261  if (sscanf(optarg,"%ld", &reqElems) != 1)
262  {
263  fprintf(stderr, "'%s' is not a valid array element count "
264  "- ignored. ('camonitor -h' for help.)\n", optarg);
265  reqElems = 0;
266  }
267  break;
268  case 'p': /* CA priority */
269  if (sscanf(optarg,"%u", &caPriority) != 1)
270  {
271  fprintf(stderr, "'%s' is not a valid CA priority "
272  "- ignored. ('camonitor -h' for help.)\n", optarg);
274  }
276  break;
277  case 'm': /* Select CA event mask */
278  eventMask = 0;
279  {
280  int i = 0;
281  char c, err = 0;
282  while ((c = optarg[i++]) && !err)
283  switch (c) {
284  case 'v': eventMask |= DBE_VALUE; break;
285  case 'a': eventMask |= DBE_ALARM; break;
286  case 'l': eventMask |= DBE_LOG; break;
287  case 'p': eventMask |= DBE_PROPERTY; break;
288  default :
289  fprintf(stderr, "Invalid argument '%s' "
290  "for option '-m' - ignored.\n", optarg);
291  eventMask = DBE_VALUE | DBE_ALARM;
292  err = 1;
293  }
294  }
295  break;
296  case 's': /* Select string dbr for floating type data */
297  floatAsString = 1;
298  break;
299  case 'S': /* Treat char array as (long) string */
300  charArrAsStr = 1;
301  break;
302  case 'e': /* Select %e/%f/%g format, using <arg> digits */
303  case 'f':
304  case 'g':
305  if (sscanf(optarg, "%d", &digits) != 1)
306  fprintf(stderr,
307  "Invalid precision argument '%s' "
308  "for option '-%c' - ignored.\n", optarg, opt);
309  else
310  {
311  if (digits>=0 && digits<=VALID_DOUBLE_DIGITS)
312  sprintf(dblFormatStr, "%%-.%d%c", digits, opt);
313  else
314  fprintf(stderr, "Precision %d for option '-%c' "
315  "out of range - ignored.\n", digits, opt);
316  }
317  break;
318  case 'l': /* Convert to long and use integer format */
319  case '0': /* Select integer format */
320  switch ((char) *optarg) {
321  case 'x': outType = hex; break; /* x print Hex */
322  case 'b': outType = bin; break; /* b print Binary */
323  case 'o': outType = oct; break; /* o print Octal */
324  default :
325  outType = dec;
326  fprintf(stderr, "Invalid argument '%s' "
327  "for option '-%c' - ignored.\n", optarg, opt);
328  }
329  if (outType != dec) {
330  if (opt == '0') outTypeI = outType;
331  else outTypeF = outType;
332  }
333  break;
334  case 'F': /* Store this for output and tool_lib formatting */
335  fieldSeparator = (char) *optarg;
336  break;
337  case '?':
338  fprintf(stderr,
339  "Unrecognized option: '-%c'. ('camonitor -h' for help.)\n",
340  optopt);
341  return 1;
342  case ':':
343  fprintf(stderr,
344  "Option '-%c' requires an argument. ('camonitor -h' for help.)\n",
345  optopt);
346  return 1;
347  default :
348  usage();
349  return 1;
350  }
351  }
352 
353  nPvs = argc - optind; /* Remaining arg list are PV names */
354 
355  if (nPvs < 1)
356  {
357  fprintf(stderr, "No pv name specified. ('camonitor -h' for help.)\n");
358  return 1;
359  }
360  /* Start up Channel Access */
361 
363  if (result != ECA_NORMAL) {
364  fprintf(stderr, "CA error %s occurred while trying "
365  "to start channel access.\n", ca_message(result));
366  return 1;
367  }
368  /* Allocate PV structure array */
369 
370  pvs = calloc (nPvs, sizeof(pv));
371  if (!pvs)
372  {
373  fprintf(stderr, "Memory allocation for channel structures failed.\n");
374  return 1;
375  }
376  /* Connect channels */
377 
378  /* Copy PV names from command line */
379  for (n = 0; optind < argc; n++, optind++)
380  {
381  pvs[n].name = argv[optind];
382  }
383  /* Create CA connections */
384  returncode = create_pvs(pvs, nPvs, connection_handler);
385  if ( returncode ) {
386  return returncode;
387  }
388  /* Check for channels that didn't connect */
390  for (n = 0; n < nPvs; n++)
391  {
392  if (!pvs[n].onceConnected)
393  print_time_val_sts(&pvs[n], reqElems);
394  }
395 
396  /* Read and print data forever */
397  ca_pend_event(0);
398 
399  /* Shut down Channel Access */
401 
402  return result;
403 }
int tsSrcServer
Definition: tool_lib.c:44
IntFormatT
Definition: tool_lib.h:64
#define CA_OP_CONN_UP
Definition: cadef.h:128
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: epicsGetopt.c:65
void print_time_val_sts(pv *pv, unsigned long reqElems)
Definition: tool_lib.c:503
#define dbr_type_is_ENUM(type)
Definition: db_access.h:664
pvac::PutEvent result
Definition: clientSync.cpp:117
IntFormatT outTypeI
Definition: tool_lib.c:46
capri caPriority
Definition: tool_lib.c:56
const void * dbr
Definition: cadef.h:89
long dbfType
Definition: tool_lib.h:71
char dblFormatStr[30]
Definition: tool_lib.c:49
char fieldSeparator
Definition: tool_lib.c:51
int i
Definition: scan.c:967
#define DEFAULT_TIMEOUT
Definition: tool_lib.h:50
int optind
Definition: epicsGetopt.c:50
LIBCA_API unsigned long epicsStdCall ca_element_count(chid chan)
#define CA_PRIORITY_MAX
Definition: cadef.h:190
Definition: tool_lib.h:67
#define printf
Definition: epicsStdio.h:41
LIBCA_API void *epicsStdCall ca_puser(chid chan)
void * value
Definition: tool_lib.h:76
#define VALID_DOUBLE_DIGITS
Definition: camonitor.c:36
#define NULL
Definition: catime.c:38
#define DBE_ALARM
Definition: caeventmask.h:41
chid chid
Definition: tool_lib.h:70
#define DBR_TIME_INT
Definition: db_access.h:86
int status
Definition: tool_lib.h:75
int charArrAsStr
Definition: tool_lib.c:54
#define LINE_BUFFER(stream)
Definition: tool_lib.h:53
#define epicsScanDouble(str, to)
Definition: epicsStdlib.h:78
LIBCA_API short epicsStdCall ca_field_type(chid chan)
#define ECA_DISCONN
Definition: caerr.h:101
int create_pvs(pv *pvs, int nPvs, caCh *pCB)
Definition: tool_lib.c:574
int main(int argc, char *argv[])
Definition: camonitor.c:206
int optopt
Definition: epicsGetopt.c:50
#define DBE_VALUE
Definition: caeventmask.h:38
int epicsStdCall ca_context_create(ca_preemptive_callback_select premptiveCallbackSelect)
Definition: access.cpp:172
int epicsStdCall ca_pend_event(ca_real timeout)
Definition: access.cpp:457
#define ECA_NORMAL
Definition: caerr.h:77
#define DEFAULT_CA_PRIORITY
Definition: tool_lib.h:49
#define DBE_LOG
Definition: caeventmask.h:40
#define DBR_TIME_STRING
Definition: db_access.h:85
long dbrType
Definition: tool_lib.h:72
LIBCA_API int epicsStdCall ca_clear_subscription(evid pMon)
TimeT tsType
Definition: tool_lib.c:43
char onceConnected
Definition: tool_lib.h:80
void event_handler(struct event_handler_args args)
Definition: evtime.c:73
void usage(void)
Definition: camonitor.c:44
#define stdout
Definition: epicsStdio.h:30
unsigned long nElems
Definition: tool_lib.h:73
int tsSrcClient
Definition: tool_lib.c:45
#define CA_OP_CONN_DOWN
Definition: cadef.h:129
#define DBE_PROPERTY
Definition: caeventmask.h:42
const char *epicsStdCall ca_message(long ca_status)
Definition: access.cpp:561
const char *epicsStdCall ca_version()
Definition: access.cpp:641
evid evid
Definition: tool_lib.h:81
Definition: tool_lib.h:64
unsigned long reqElems
Definition: tool_lib.h:74
#define dbr_type_is_FLOAT(type)
Definition: db_access.h:661
Definition: tool_lib.h:64
Definition: tool_lib.h:64
#define stderr
Definition: epicsStdio.h:32
char * name
Definition: tool_lib.h:69
#define dbr_type_is_DOUBLE(type)
Definition: db_access.h:673
Definition: tool_lib.h:64
void epicsStdCall ca_context_destroy()
Definition: access.cpp:232
int enumAsNr
Definition: tool_lib.c:53
IntFormatT outTypeF
Definition: tool_lib.c:47
char * optarg
Definition: epicsGetopt.c:55
void * usr
Definition: cadef.h:85
LIBCA_API int epicsStdCall ca_create_subscription(chtype type, unsigned long count, chid chanId, long mask, caEventCallBackFunc *pFunc, void *pArg, evid *pEventID)
double caTimeout
Definition: tool_lib.c:55
#define dbf_type_to_DBR_TIME(type)
Definition: db_access.h:705