SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
cavget.cc
Go to the documentation of this file.
1/**
2 * @file cavget.cc
3 * @brief Read Channel Access (CA) and pvAccess (PVA) Process Variable (PV) values from the command line.
4 *
5 * This program allows the user to retrieve values from specified Process Variables (PVs)
6 * from the command line, supporting various formats and filtering options. It processes the inputs, establishes
7 * connections to the EPICS database, retrieves values, and optionally applies statistical analysis or despiking.
8 *
9 * @section Usage
10 * ```
11 * cavget [-list=<string>[=<value>][,<string>[=<value>]...]]
12 * [-range=begin=<integer>,end=<integer>[,format=<string>][,interval=<integer>]]
13 * [-floatformat=<printfString>]
14 * [-charArray]
15 * {
16 * [-delimiter=<string>]
17 * [-labeled]
18 * [-noQuotes]
19 * [-embrace=start=<string>,end=<string>]
20 * | [-cavputForm]
21 * }
22 * [-statistics=number=<value>,pause=<value>[,format=[tagvalue][pretty][SDDS,file=<filename]]]
23 * [-pendIoTime=<seconds>]
24 * [-repeat=number=<integer>,pause=<seconds>[,average[,sigma]]]
25 * [-numerical]
26 * [-errorValue=<string>]
27 * [-excludeErrors]
28 * [-despike[[neighbors=<integer>][,passes=<integer>][,averageOf=<integer>][,threshold=<value>]]]
29 * [-provider={ca|pva}]
30 * [-info]
31 * [-printErrors]
32 * ```
33 *
34 * @section Options
35 * | Option | Description |
36 * |---------------------------------------|---------------------------------------------------------------------------------------|
37 * | `-list` | Specifies PV name components. |
38 * | `-range` | Defines a range of integers for PV name construction. |
39 * | `-pendiotime` | Maximum wait time for connections/returns. Default is 1.0 seconds. |
40 * | `-statistics` | Enables statistical analysis with various formats: tagvalue, pretty, or SDDS. |
41 * | `-despike` | Removes spikes based on specified neighbors, passes, and thresholds. |
42 * | `-repeat` | Repeatedly reads PV values at intervals. |
43 * | `-provider` | Specifies the provider for the PVs (default is `ca`). |
44 * | `-dryrun` | Displays PV names/values without sending to IOCs. |
45 * | `-floatformat` | Custom printf-style format for floating-point values. |
46 * | `-info` | Prints metadata for the specified PVs. |
47 * | `-delimiter` | Sets the delimiter for output values. Default is a newline. |
48 * | `-noquotes` | Suppresses quotes around string values. |
49 * | `-embrace` | Adds custom braces around values. |
50 * | `-errorvalue` | Output for timeouts/errors. Default is `?`. |
51 * | `-excludeerrors` | Suppresses output for errors. |
52 * | `-numerical` | Forces numerical values for enumerated types. |
53 * | `-chararray` | Prints character arrays as strings. |
54 *
55 * @subsection Incompatibilities
56 * - `-statistics` is incompatible with:
57 * - `-repeat`
58 * - `-cavputform`
59 * - For `-despike`:
60 * - Requires either `-repeat` or `-statistics` to be specified.
61 *
62 * @copyright
63 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
64 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
65 *
66 * @license
67 * This file is distributed under the terms of the Software License Agreement
68 * found in the file LICENSE included with this distribution.
69 *
70 * @authors
71 * - M. Borland
72 * - R. Soliday
73 */
74
75#include <complex>
76#include <iostream>
77#include <cstdlib>
78#include <ctime>
79
80#if defined(_WIN32)
81# include <winsock.h>
82#else
83# include <unistd.h>
84#endif
85
86#include <cadef.h>
87#include <epicsVersion.h>
88#if (EPICS_VERSION > 3)
89# include "pvaSDDS.h"
90#endif
91
92#include "mdb.h"
93#include "scan.h"
94#include "match_string.h"
95#include "SDDS.h"
96
97#include "pvMultList.h"
98
99#define CLO_LIST 0
100#define CLO_RANGE 1
101#define CLO_PENDIOTIME 2
102#define CLO_DRYRUN 3
103#define CLO_LABELED 4
104#define CLO_FLOATFORMAT 5
105#define CLO_DELIMITER 6
106#define CLO_NOQUOTES 7
107#define CLO_EMBRACE 8
108#define CLO_REPEAT 9
109#define CLO_ERRORVALUE 10
110#define CLO_NUMERICAL 11
111#define CLO_CAVPUTFORM 12
112#define CLO_EXCLUDEERRORS 13
113#define CLO_STATISTICS 14
114#define CLO_DESPIKE 15
115#define CLO_PRINTERRORS 16
116#define CLO_PROVIDER 17
117#define CLO_INFO 18
118#define CLO_CHARARRAY 19
119#define COMMANDLINE_OPTIONS 20
120char *commandline_option[COMMANDLINE_OPTIONS] = {
121 (char *)"list", (char *)"range", (char *)"pendiotime", (char *)"dryrun", (char *)"labeled",
122 (char *)"floatformat", (char *)"delimiter", (char *)"noquotes", (char *)"embrace", (char *)"repeat",
123 (char *)"errorvalue", (char *)"numerical", (char *)"cavputform", (char *)"excludeerrors",
124 (char *)"statistics", (char *)"despike", (char *)"printErrors", (char *)"provider", (char *)"info",
125 (char *)"chararray"};
126
127#define CLO_STATS_TAGVALUE 0
128#define CLO_STATS_PRETTY 1
129#define CLO_STATS_SDDS 2
130#define STATISTICS_FORMATS 3
131char *statisticsFormat[STATISTICS_FORMATS] = {
132 (char *)"tagvalue",
133 (char *)"pretty",
134 (char *)"SDDS",
135};
136
137#define PROVIDER_CA 0
138#define PROVIDER_PVA 1
139#define PROVIDER_COUNT 2
140char *providerOption[PROVIDER_COUNT] = {
141 (char *)"ca",
142 (char *)"pva",
143};
144
145static char *USAGE = (char *)
146"Usage: cavget \n"
147" [-list=<string>[=<value>][,<string>[=<value>]...]]\n"
148" [-range=begin=<integer>,end=<integer>[,format=<string>][,interval=<integer>]]\n"
149" [-floatformat=<printfString>]\n"
150" [-charArray]\n"
151" { \n"
152" [-delimiter=<string>]\n"
153" [-labeled]\n"
154" [-noQuotes]\n"
155" [-embrace=start=<string>,end=<string>]\n"
156" | [-cavputForm]\n"
157" }\n"
158" [-statistics=number=<value>,pause=<value>[,format=[tagvalue][pretty][SDDS,file=<filename]]]\n"
159" [-pendIoTime=<seconds>]\n"
160" [-repeat=number=<integer>,pause=<seconds>[,average[,sigma]]]\n"
161" [-numerical]\n"
162" [-errorValue=<string>]\n"
163" [-excludeErrors]\n"
164" [-despike[[neighbors=<integer>][,passes=<integer>][,averageOf=<integer>][,threshold=<value>]]]\n"
165" [-provider={ca|pva}]\n"
166" [-info]\n"
167" [-printErrors]\n"
168"\n"
169"Options Description:\n"
170"-list Specifies PV name string components.\n"
171"-range Specifies range of integers and format string.\n"
172"-floatFormat Specifies printf-style format for single/double values. Default is %g.\n"
173"-charArray Prints character array values as strings.\n"
174"-delimiter Specifies string between values. Default is a newline.\n"
175"-labeled Echoes PV name with value, separated by a space.\n"
176"-noQuotes Avoid quotes around string values with whitespace or blank values.\n"
177"-embrace Adds braces around tag-value pairs (typically used with -label).\n"
178"-cavputForm Formats output for direct restoration by cavput.\n"
179"-pendIoTime Sets max wait time for connections/returns. Default is 1.0s.\n"
180"-dryRun Displays PV names/values without sending to IOCs.\n"
181"-errorValue Specifies output string for timeout/errors. Default is '?'.\n"
182"-excludeErrors Suppresses output for PVs with timeout/errors.\n"
183"-numerical Returns numerical values for enumerated types.\n"
184"-repeat Reads PVs repeatedly at intervals. Averages numeric readbacks.\n"
185"-statistics Performs statistical calculations:\n"
186" - Format tagvalue: \"mean <value> median <value> sigma <value> ...\"\n"
187" - Format pretty: Column-aligned output.\n"
188" - Format SDDS: Writes results to specified file.\n"
189"-despike Removes spikes from readings. Requires repeat/statistics:\n"
190" - <neighbors>: Number of neighbors for checking spikes.\n"
191" - <averageOf>: Values around spike for averaging.\n"
192" - <passes>: Number of despiking passes.\n"
193" - <threshold>: Spike threshold.\n"
194"-provider Defaults to ca (channel access) calls.\n"
195"-info Prints meta data for PVs.\n"
196"-printErrors Outputs error messages if channel not found.\n\n"
197"Program by Michael Borland and Robert Soliday, ANL/APS (" EPICS_VERSION_STRING ", " __DATE__ ").\n";
198
199
200void sleep_us(unsigned int nusecs) {
201 struct timeval tval;
202
203 tval.tv_sec = nusecs / 1000000;
204 tval.tv_usec = nusecs % 1000000;
205 select(0, NULL, NULL, NULL, &tval);
206}
207
208#define REPEAT_AVERAGE 0x0001U
209#define REPEAT_SIGMA 0x0002U
210
211long printResult(FILE *fp, char *startBrace, long labeled, long connectedInTime,
212 long channelType, PV_VALUE PVvalue, char *endBrace,
213 char *floatFormat, short charArray, char *errorValue, long quotes,
214 long cavputForm, long excludeErrors,
215 long delimNeeded, char *delimiter, long secondValue, long doRepeats,
216 long doStats, long repeats, double *value, long average, short printErrors);
217void printResultPretty(FILE *fp, long *channelType, PV_VALUE *PVvalue, long PVs, long quotes,
218 short *connectedInTime, char *errorValue, short printErrors);
219long writeStatisticsToSDDSFile(char *outputFile, long *channelType, PV_VALUE *PVvalue, long PVs,
220 short *connectedInTime, char *errorValue, short printErrors);
221void oag_ca_exception_handler(struct exception_handler_args args);
222
223#if (EPICS_VERSION > 3)
224
225void printResultPVA(char *startBrace, long labeled, PVA_OVERALL *pva, PV_VALUE *PVvalue, char *endBrace,
226 char *floatFormat, short charArray, char *errorValue, long quotes, long cavputForm,
227 long excludeErrors, char *delimiter, long secondValue,
228 long doRepeat, long doStats, long repeats, long average, short printErrors);
229void printResultPrettyPVA(PVA_OVERALL *pva, long quotes, char *errorValue, short printErrors);
230void writeStatisticsToSDDSFilePVA(char *outputFile, PVA_OVERALL *pva, long quotes, char *errorValue, short printErrors);
231void GetInfoData(PVA_OVERALL *pva, PV_VALUE *PVvalue);
232#endif
233
234int main(int argc, char **argv) {
235 int32_t beginRange, endRange, rangeInterval;
236 long dryRun;
237 long PVs, j, i_arg, labeled, quotes, numerical;
238 PV_VALUE *PVvalue;
239 TERM_LIST *List;
240 unsigned long flags;
241 SCANNED_ARG *s_arg;
242 char *rangeFormat, *floatFormat, *delimiter;
243 short charArray=0;
244 double pendIOTime, repeatPause, despikeThreshold;
245 chid *channelID;
246 short *connectedInTime = NULL;
247 char *startBrace, *endBrace;
248 long average, sigma, repeats0, cavputForm, excludeErrors, doStats, doRepeat, doDespike;
249 int32_t repeats, despikeNeighbors, despikePasses, despikeAverageOf;
250 char *errorValue = (char *)"?";
251 char *statsFormat, *statsOutput;
252 double **value = NULL;
253 long *channelType = NULL;
254 short printErrors = 0;
255 long providerMode = 0;
256 long infoMode = 0;
257#if (EPICS_VERSION > 3)
258 PVA_OVERALL pva;
259#else
260 long delimNeeded;
261#endif
262
263 argc = scanargs(&s_arg, argc, argv);
264 if (argc < 2) {
265 fprintf(stderr, "%s\n", USAGE);
266 exit(EXIT_FAILURE);
267 }
268 statsFormat = statsOutput = NULL;
269 PVvalue = NULL;
270 List = NULL;
271 PVs = dryRun = labeled = numerical = 0;
272 floatFormat = (char *)"%g";
273 delimiter = (char *)"\n";
274 quotes = 1;
275 pendIOTime = 1.0;
276 startBrace = endBrace = NULL;
277 repeats = average = sigma = 0;
278 doStats = doRepeat = doDespike = 0;
279 repeatPause = 1;
280 cavputForm = excludeErrors = 0;
281 channelID = NULL;
282 despikeNeighbors = 10;
283 despikePasses = 2;
284 despikeAverageOf = 4;
285 despikeThreshold = 0;
286
287 for (i_arg = 1; i_arg < argc; i_arg++) {
288 if (s_arg[i_arg].arg_type == OPTION) {
289 delete_chars(s_arg[i_arg].list[0], (char *)"_");
290 switch (match_string(s_arg[i_arg].list[0], commandline_option, COMMANDLINE_OPTIONS, 0)) {
291 case CLO_LIST:
292 if (s_arg[i_arg].n_items < 2)
293 SDDS_Bomb((char *)"invalid -list syntax (cavget)");
294 List = (TERM_LIST *)trealloc(List, sizeof(*List) * (s_arg[i_arg].n_items - 1));
295 for (j = 1; j < s_arg[i_arg].n_items; j++) {
296 List[j - 1].flags = 0;
297 List[j - 1].string = s_arg[i_arg].list[j];
298 List[j - 1].value = NULL;
299 }
300 multiplyWithList(&PVvalue, &PVs, List, s_arg[i_arg].n_items - 1);
301 break;
302 case CLO_RANGE:
303 s_arg[i_arg].n_items--;
304 rangeFormat = NULL;
305 rangeInterval = 1;
306 if (!scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
307 "begin", SDDS_LONG, &beginRange, 1, BEGIN_GIVEN,
308 "end", SDDS_LONG, &endRange, 1, END_GIVEN,
309 "interval", SDDS_LONG, &rangeInterval, 1, INTERVAL_GIVEN,
310 "format", SDDS_STRING, &rangeFormat, 1, FORMAT_GIVEN,
311 NULL) ||
312 !(flags & BEGIN_GIVEN) || !(flags & END_GIVEN) || beginRange > endRange ||
313 (flags & FORMAT_GIVEN && SDDS_StringIsBlank(rangeFormat)))
314 SDDS_Bomb((char *)"invalid -range syntax/values");
315 if (!rangeFormat)
316 rangeFormat = (char *)"%ld";
317 multiplyWithRange(&PVvalue, &PVs, beginRange, endRange, rangeInterval, rangeFormat);
318 s_arg[i_arg].n_items++;
319 break;
320 case CLO_PENDIOTIME:
321 if (s_arg[i_arg].n_items != 2)
322 SDDS_Bomb((char *)"wrong number of items for -pendIoTime");
323 if (sscanf(s_arg[i_arg].list[1], "%lf", &pendIOTime) != 1 ||
324 pendIOTime <= 0)
325 SDDS_Bomb((char *)"invalid -pendIoTime value (cavget)");
326 break;
327 case CLO_DRYRUN:
328 dryRun = 1;
329 break;
330 case CLO_LABELED:
331 labeled = 1;
332 break;
333 case CLO_PRINTERRORS:
334 printErrors = 1;
335 break;
336 case CLO_INFO:
337 infoMode = 1;
338 break;
339 case CLO_CHARARRAY:
340 charArray = 1;
341 break;
342 case CLO_FLOATFORMAT:
343 if (s_arg[i_arg].n_items != 2)
344 SDDS_Bomb((char *)"wrong number of items for -floatFormat");
345 floatFormat = s_arg[i_arg].list[1];
346 break;
347 case CLO_DELIMITER:
348 if (s_arg[i_arg].n_items != 2)
349 SDDS_Bomb((char *)"wrong number of items for -delimiter");
350 delimiter = s_arg[i_arg].list[1];
351 break;
352 case CLO_NOQUOTES:
353 quotes = 0;
354 break;
355 case CLO_EMBRACE:
356 s_arg[i_arg].n_items--;
357 startBrace = (char *)"{";
358 endBrace = (char *)"}";
359 if (!scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
360 "start", SDDS_STRING, &startBrace, 1, 0,
361 "end", SDDS_STRING, &endBrace, 1, 0,
362 NULL))
363 SDDS_Bomb((char *)"invalid -embrace syntax");
364 s_arg[i_arg].n_items++;
365 break;
366 case CLO_DESPIKE:
367 s_arg[i_arg].n_items--;
368 doDespike = 1;
369 if (!scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
370 "neighbors", SDDS_LONG, &despikeNeighbors, 1, 0,
371 "passes", SDDS_LONG, &despikePasses, 1, 0,
372 "averageOf", SDDS_LONG, &despikeAverageOf, 1, 0,
373 "threshold", SDDS_DOUBLE, &despikeThreshold, 1, 0,
374 NULL) ||
375 despikeNeighbors < 0 ||
376 despikePasses < 0 || despikeAverageOf < 0 || despikeThreshold < 0)
377 SDDS_Bomb((char *)"invalid -despike syntax");
378 s_arg[i_arg].n_items++;
379 break;
380 case CLO_REPEAT:
381 s_arg[i_arg].n_items--;
382 doRepeat = 1;
383 repeats = average = 0;
384 if (!scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
385 "number", SDDS_LONG, &repeats, 1, 0,
386 "pause", SDDS_DOUBLE, &repeatPause, 1, 0,
387 "average", -1, NULL, 0, REPEAT_AVERAGE,
388 "sigma", -1, NULL, 0, REPEAT_SIGMA,
389 NULL) ||
390 repeats < 1)
391 SDDS_Bomb((char *)"invalid -repeat syntax");
392 if (flags & REPEAT_AVERAGE)
393 average = 1;
394 if (flags & REPEAT_SIGMA)
395 sigma = 1;
396 s_arg[i_arg].n_items++;
397 break;
398 case CLO_STATISTICS:
399 s_arg[i_arg].n_items--;
400 doStats = 1;
401 repeats = 0;
402 if (!scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
403 "number", SDDS_LONG, &repeats, 1, 0,
404 "pause", SDDS_DOUBLE, &repeatPause, 1, 0,
405 "format", SDDS_STRING, &statsFormat, 1, 0,
406 "file", SDDS_STRING, &statsOutput, 1, 0,
407 NULL) ||
408 repeats < 1)
409 SDDS_Bomb((char *)"invalid -statistics syntax");
410 if (!statsFormat)
411 SDDS_Bomb((char *)"invalid -statistics syntax, the format is not given.");
412 switch (match_string(statsFormat, statisticsFormat, STATISTICS_FORMATS, 0)) {
413 case CLO_STATS_TAGVALUE:
414 case CLO_STATS_PRETTY:
415 if (statsOutput)
416 SDDS_Bomb((char *)"invalid -statics format syntax");
417 break;
418 case CLO_STATS_SDDS:
419 if (!statsOutput)
420 SDDS_Bomb((char *)"invalid -statics format=SDDS syntax, output filename is not given");
421 break;
422 default:
423 SDDS_Bomb((char *)"unknown format given to -statistics option");
424 break;
425 }
426 s_arg[i_arg].n_items++;
427 break;
428 case CLO_ERRORVALUE:
429 if (s_arg[i_arg].n_items != 2)
430 SDDS_Bomb((char *)"invalid -errorValue syntax");
431 errorValue = s_arg[i_arg].list[1];
432 break;
433 case CLO_NUMERICAL:
434 numerical = 1;
435 break;
436 case CLO_CAVPUTFORM:
437 cavputForm = 1;
438 break;
439 case CLO_EXCLUDEERRORS:
440 excludeErrors = 1;
441 break;
442 case CLO_PROVIDER:
443 if (s_arg[i_arg].n_items != 2)
444 SDDS_Bomb((char *)"no value given for option -provider");
445 if ((providerMode = match_string(s_arg[i_arg].list[1], providerOption,
446 PROVIDER_COUNT, 0)) < 0)
447 SDDS_Bomb((char *)"invalid -provider");
448 break;
449 default:
450 SDDS_Bomb((char *)"unknown option (cavget)");
451 break;
452 }
453 } else
454 SDDS_Bomb((char *)"unknown option");
455 }
456
457 if (doRepeat && doStats)
458 SDDS_Bomb((char *)"-repeat and -statistics are imcompatible.");
459
460 /*if (cavputForm && doStats)
461 SDDS_Bomb((char*)"-cavputForm and -statistics are imcompatible."); */
462 if (doDespike) {
463 if (!doRepeat && !doStats)
464 SDDS_Bomb((char *)"neither repeat or statistics is given, can not do despiking!");
465 if (doRepeat) {
466 sigma = 0;
467 average = 1;
468 }
469 if (despikeNeighbors > repeats)
470 despikeNeighbors = repeats;
471 if (despikeAverageOf > repeats)
472 despikeAverageOf = repeats;
473 }
474 if (cavputForm)
475 delimiter = (char *)",";
476 if (dryRun) {
477 for (j = 0; j < PVs; j++) {
478 if (strncmp(PVvalue[j].name, "pva://", 6) == 0) {
479 PVvalue[j].name += 6;
480 printf("%32s\n", PVvalue[j].name);
481 PVvalue[j].name -= 6;
482 } else if (strncmp(PVvalue[j].name, "ca://", 5) == 0) {
483 PVvalue[j].name += 5;
484 printf("%32s\n", PVvalue[j].name);
485 PVvalue[j].name -= 5;
486 } else {
487 printf("%32s\n", PVvalue[j].name);
488 }
489 }
490 } else {
491#if (EPICS_VERSION > 3)
492 //Allocate memory for pva structure
493 allocPVA(&pva, PVs, repeats);
494 //List PV names
495 epics::pvData::shared_vector<std::string> names(pva.numPVs);
496 epics::pvData::shared_vector<std::string> provider(pva.numPVs);
497 for (j = 0; j < pva.numPVs; j++) {
498 if (strncmp(PVvalue[j].name, "pva://", 6) == 0) {
499 PVvalue[j].name += 6;
500 names[j] = PVvalue[j].name;
501 PVvalue[j].name -= 6;
502 provider[j] = "pva";
503 } else if (strncmp(PVvalue[j].name, "ca://", 5) == 0) {
504 PVvalue[j].name += 5;
505 names[j] = PVvalue[j].name;
506 PVvalue[j].name -= 5;
507 provider[j] = "ca";
508 } else {
509 names[j] = PVvalue[j].name;
510 if (providerMode == PROVIDER_PVA)
511 provider[j] = "pva";
512 else
513 provider[j] = "ca";
514 }
515 }
516 pva.pvaChannelNames = freeze(names);
517 pva.pvaProvider = freeze(provider);
518 //Connect to PVs
519 ConnectPVA(&pva, pendIOTime);
520
521
522
523 repeats0 = 0;
524
525 do {
526 //Get data from PVs and return a PVStructure
527 if (infoMode) {
528 pva.includeAlarmSeverity = true;
529 }
530 if (GetPVAValues(&pva) == 1) {
531 return (EXIT_FAILURE);
532 }
533 if (infoMode) {
534 GetInfoData(&pva, PVvalue);
535 exit(EXIT_SUCCESS);
536 }
537 //Change enumerated PV values to int from string if the numerical option is given
538 if ((repeats0 == 0) && (numerical)) {
539 for (j = 0; j < PVs; j++) {
540 if (pva.isConnected[j] && pva.pvaData[j].pvEnumeratedStructure) {
541 pva.pvaData[j].scalarType = epics::pvData::pvInt;
542 }
543 }
544 }
545
546 if (!repeats) {
547 for (j = 0; j < PVs; j++) {
548 if ((pva.pvaData[j].numGetElements == 1) && (pva.pvaData[j].numeric)) {
549 pva.pvaData[j].mean = pva.pvaData[j].getData[0].values[0];
550 }
551 }
552 }
553 repeats0++;
554 if ((repeats0 < repeats) && (repeatPause > 0)) {
555 usleepSystemIndependent(repeatPause * 1000000);
556 }
557 } while (repeats0 < repeats);
558
559 if (repeats) {
560 for (j = 0; j < PVs; j++) {
561 if ((pva.pvaData[j].numGetElements == 1) && (pva.pvaData[j].numeric)) {
562 double *v;
563 long i;
564 v = (double *)malloc(sizeof(double) * repeats);
565 for (i = 0; i < repeats; i++) {
566 v[i] = pva.pvaData[j].getData[i].values[0];
567 }
568 if (doDespike) {
569 despikeData(v, repeats, despikeNeighbors, despikePasses, despikeAverageOf, despikeThreshold, 0);
570 }
571 find_min_max(&pva.pvaData[j].min, &pva.pvaData[j].max, v, repeats);
572 computeMoments(&pva.pvaData[j].mean, &pva.pvaData[j].rms, &pva.pvaData[j].stDev, &pva.pvaData[j].MAD, v, repeats);
573 pva.pvaData[j].spread = pva.pvaData[j].max - pva.pvaData[j].min;
574 pva.pvaData[j].sigma = pva.pvaData[j].stDev / sqrt(repeats);
575 find_median(&pva.pvaData[j].median, v, repeats);
576 free(v);
577 }
578 }
579 }
580
581 if (!statsFormat ||
582 match_string(statsFormat, statisticsFormat, STATISTICS_FORMATS, 0) == CLO_STATS_TAGVALUE) {
583 printResultPVA(startBrace, labeled, &pva, PVvalue, endBrace,
584 floatFormat, charArray, errorValue, quotes, cavputForm,
585 excludeErrors, delimiter, sigma,
586 doRepeat, doStats, repeats, average, printErrors);
587 }
588 if (statsFormat) {
589 switch (match_string(statsFormat, statisticsFormat, STATISTICS_FORMATS, 0)) {
590 case CLO_STATS_PRETTY:
591 printResultPrettyPVA(&pva, quotes, errorValue, printErrors);
592 break;
593 case CLO_STATS_SDDS:
594 writeStatisticsToSDDSFilePVA(statsOutput, &pva, quotes, errorValue, printErrors);
595 break;
596 default:
597 break;
598 }
599 }
600 if (PVvalue) {
601 for (j = 0; j < PVs; j++) {
602 if (PVvalue[j].name)
603 free(PVvalue[j].name);
604 }
605 free(PVvalue);
606 }
607 freePVA(&pva);
608 if (statsFormat)
609 free(statsFormat);
610 if (statsOutput)
611 free(statsOutput);
612 if (List)
613 free(List);
614 free_scanargs(&s_arg, argc);
615 return (EXIT_SUCCESS);
616#else
617 if (!(value = (double **)malloc(sizeof(double *) * PVs)))
618 SDDS_Bomb((char *)"memory allocation failure (cavget)");
619 for (j = 0; j < PVs; j++) {
620 if (repeats) {
621 if (!(value[j] = (double *)calloc((repeats), sizeof(double))))
622 SDDS_Bomb((char *)"memory allocation failure (cavget)");
623 } else {
624 if (!(value[j] = (double *)calloc(1, sizeof(double))))
625 SDDS_Bomb((char *)"memory allocation failure (cavget)");
626 }
627 }
628 repeats0 = 0;
629
630 ca_task_initialize();
631 ca_add_exception_event(oag_ca_exception_handler, NULL);
632 if (!(channelID = (chid *)malloc(sizeof(*channelID) * PVs)) ||
633 !(channelType = (long *)malloc(sizeof(*channelType) * PVs)) ||
634 !(connectedInTime = (short *)malloc(sizeof(*connectedInTime) * PVs)))
635 SDDS_Bomb((char *)"memory allocation failure (cavget)");
636 for (j = 0; j < PVs; j++)
637 if (ca_search(PVvalue[j].name, channelID + j) != ECA_NORMAL) {
638 fprintf(stderr, "error (cavget): problem doing search for %s\n",
639 PVvalue[j].name);
640 ca_task_exit();
641 exit(EXIT_FAILURE);
642 }
643 ca_pend_io(pendIOTime);
644 if (numerical)
645 for (j = 0; j < PVs; j++) {
646 channelType[j] = ca_field_type(channelID[j]);
647 if ((channelType[j] = ca_field_type(channelID[j])) == DBF_ENUM)
648 channelType[j] = DBF_DOUBLE;
649 }
650 else
651 for (j = 0; j < PVs; j++)
652 channelType[j] = ca_field_type(channelID[j]);
653 do {
654 for (j = 0; j < PVs; j++) {
655 if (!(connectedInTime[j] = ca_state(channelID[j]) == cs_conn))
656 continue;
657 switch (channelType[j]) {
658 case DBF_STRING:
659 case DBF_ENUM:
660 PVvalue[j].value = (char *)malloc(sizeof(char) * 256);
661 if (ca_get(DBR_STRING, channelID[j], PVvalue[j].value) != ECA_NORMAL) {
662 fprintf(stderr, "problem doing get for %s\n",
663 PVvalue[j].name);
664 ca_task_exit();
665 exit(EXIT_FAILURE);
666 }
667 break;
668 case DBF_NO_ACCESS:
669 fprintf(stderr, "Error: No access to PV %s\n", PVvalue[j].name);
670 ca_task_exit();
671 exit(EXIT_FAILURE);
672 break;
673 default:
674 if (ca_get(DBR_DOUBLE, channelID[j],
675 &value[j][repeats0]) != ECA_NORMAL) {
676 fprintf(stderr, "problem doing get for %s\n",
677 PVvalue[j].name);
678 ca_task_exit();
679 exit(EXIT_FAILURE);
680 }
681 break;
682 }
683 }
684 ca_pend_io(pendIOTime);
685 repeats0++;
686 if (!repeats) {
687 for (j = 0; j < PVs; j++)
688 PVvalue[j].mean = value[j][0];
689 }
690 if ((repeats0 < repeats) && (repeatPause > 0)) {
691 ca_pend_event(repeatPause);
692 }
693 } while (repeats0 < repeats);
694
695 if (repeats) {
696 for (j = 0; j < PVs; j++) {
697 if (doDespike) {
698 despikeData(value[j], repeats, despikeNeighbors, despikePasses, despikeAverageOf,
699 despikeThreshold, 0);
700 }
701 find_min_max(&PVvalue[j].min, &PVvalue[j].max, value[j], repeats);
702 computeMoments(&PVvalue[j].mean, &PVvalue[j].rms, &PVvalue[j].stDev, &PVvalue[j].MAD,
703 value[j], repeats);
704 PVvalue[j].spread = PVvalue[j].max - PVvalue[j].min;
705 PVvalue[j].sigma = PVvalue[j].stDev / sqrt(repeats);
706 find_median(&PVvalue[j].median, value[j], repeats);
707 }
708 }
709
710 delimNeeded = 0;
711 if (!statsFormat ||
712 match_string(statsFormat, statisticsFormat, STATISTICS_FORMATS, 0) == CLO_STATS_TAGVALUE) {
713 for (j = 0; j < PVs; j++) {
714 if (printResult(stdout, startBrace, labeled, connectedInTime[j],
715 channelType[j], PVvalue[j], endBrace,
716 floatFormat, charArray, errorValue, quotes, cavputForm,
717 excludeErrors, delimNeeded, delimiter, sigma, doRepeat, doStats, repeats, value[j], average,
718 printErrors))
719 delimNeeded = 1;
720 }
721 if (delimNeeded)
722 fputc('\n', stdout);
723 }
724 if (statsFormat) {
725 switch (match_string(statsFormat, statisticsFormat, STATISTICS_FORMATS, 0)) {
726 case CLO_STATS_PRETTY:
727 printResultPretty(stdout, channelType, PVvalue, PVs, quotes, connectedInTime, errorValue, printErrors);
728 break;
729 case CLO_STATS_SDDS:
730 writeStatisticsToSDDSFile(statsOutput, channelType, PVvalue, PVs, connectedInTime, errorValue, printErrors);
731 break;
732 default:
733 break;
734 }
735 }
736 ca_task_exit();
737#endif
738 }
739 for (j = 0; j < PVs; j++) {
740 if (PVvalue[j].name)
741 free(PVvalue[j].name);
742 if (PVvalue[j].value)
743 free(PVvalue[j].value);
744 PVvalue[j].name = PVvalue[j].value = NULL;
745 }
746 if (value) {
747 for (j = 0; j < PVs; j++)
748 free(value[j]);
749 free(value);
750 }
751 if (PVvalue)
752 free(PVvalue);
753 if (channelID)
754 free(channelID);
755 if (channelType)
756 free(channelType);
757 if (connectedInTime)
758 free(connectedInTime);
759 free_scanargs(&s_arg, argc);
760 if (List)
761 free(List);
762
763 return EXIT_SUCCESS;
764}
765
766long printResult(FILE *fp, char *startBrace, long labeled, long connectedInTime,
767 long channelType, PV_VALUE PVvalue, char *endBrace,
768 char *floatFormat, short charArray, char *errorValue, long quotes,
769 long cavputForm, long excludeErrors,
770 long delimNeeded, char *delimiter, long secondValue,
771 long doRepeat, long doStats, long repeats, double *value, long average, short printErrors) {
772 long i;
773
774 if (excludeErrors && !connectedInTime)
775 return 0;
776 if (delimNeeded && delimiter)
777 fputs(delimiter, fp);
778 if (cavputForm) {
779 fprintf(fp, "%s=", PVvalue.name);
780 quotes = 0;
781 } else {
782 if (startBrace)
783 fputs(startBrace, fp);
784 if (labeled)
785 fprintf(fp, "%s ", PVvalue.name);
786 }
787 if (!connectedInTime) {
788 if (printErrors)
789 fprintf(stderr, "%s is not connected or invalid PV name.\n", PVvalue.name);
790 else
791 fputs(errorValue, fp);
792 } else {
793 switch (channelType) {
794 case DBF_SHORT:
795 case DBF_LONG:
796 case DBF_CHAR:
797 if (cavputForm || (!doRepeat && !doStats)) {
798 fprintf(fp, "%.0f", PVvalue.mean);
799 } else {
800 if (doRepeat) {
801 if (!average) {
802 for (i = 0; i < repeats; i++) {
803 fprintf(fp, "%.0f ", value[i]);
804 }
805 } else {
806 fprintf(fp, "%.0f", PVvalue.mean);
807 if (secondValue) {
808 fprintf(fp, " ");
809 fprintf(fp, "%.0f", PVvalue.sigma);
810 }
811 }
812 }
813 if (doStats) {
814 fprintf(fp, "mean ");
815 fprintf(fp, "%.0f", PVvalue.mean);
816 fprintf(fp, " median ");
817 fprintf(fp, "%.0f", PVvalue.median);
818 fprintf(fp, " sigma ");
819 fprintf(fp, "%.0f", PVvalue.sigma);
820 fprintf(fp, " stDev ");
821 fprintf(fp, "%.0f", PVvalue.stDev);
822 fprintf(fp, " MAD ");
823 fprintf(fp, "%.0f", PVvalue.MAD);
824 fprintf(fp, " min ");
825 fprintf(fp, "%.0f", PVvalue.min);
826 fprintf(fp, " max ");
827 fprintf(fp, "%.0f", PVvalue.max);
828 fprintf(fp, " spread ");
829 fprintf(fp, "%.0f", PVvalue.spread);
830 }
831 }
832 break;
833 case DBF_STRING:
834 case DBF_ENUM:
835 if (!quotes)
836 fputs(PVvalue.value, fp);
837 else {
838 if (SDDS_StringIsBlank(PVvalue.value) ||
839 SDDS_HasWhitespace(PVvalue.value))
840 fprintf(fp, "\"%s\"", PVvalue.value);
841 else
842 fputs(PVvalue.value, fp);
843 }
844 break;
845 case DBF_DOUBLE:
846 case DBF_FLOAT:
847 default:
848 if (cavputForm || (!doRepeat && !doStats)) {
849 fprintf(fp, floatFormat, PVvalue.mean);
850 } else {
851 if (doRepeat) {
852 if (!average) {
853 for (i = 0; i < repeats; i++) {
854 fprintf(fp, floatFormat, value[i]);
855 fprintf(fp, " ");
856 }
857 } else {
858 fprintf(fp, floatFormat, PVvalue.mean);
859 if (secondValue) {
860 fprintf(fp, " ");
861 fprintf(fp, floatFormat, PVvalue.sigma);
862 }
863 }
864 }
865 if (doStats) {
866 fprintf(fp, " mean ");
867 fprintf(fp, floatFormat, PVvalue.mean);
868 fprintf(fp, " median ");
869 fprintf(fp, floatFormat, PVvalue.median);
870 fprintf(fp, " sigma ");
871 fprintf(fp, floatFormat, PVvalue.sigma);
872 fprintf(fp, " stDev ");
873 fprintf(fp, floatFormat, PVvalue.stDev);
874 fprintf(fp, " MAD ");
875 fprintf(fp, floatFormat, PVvalue.MAD);
876 fprintf(fp, " min ");
877 fprintf(fp, floatFormat, PVvalue.min);
878 fprintf(fp, " max ");
879 fprintf(fp, floatFormat, PVvalue.max);
880 fprintf(fp, " spread ");
881 fprintf(fp, floatFormat, PVvalue.spread);
882 }
883 }
884 break;
885 }
886 }
887 if (endBrace && !cavputForm)
888 fputs(endBrace, fp);
889 return 1;
890}
891
892void printResultPretty(FILE *fp, long *channelType, PV_VALUE *PVvalue, long PVs, long quotes,
893 short *connectedInTime, char *errorValue, short printErrors) {
894 long i;
895
896 fprintf(fp, "%20s", "ControlName");
897 fprintf(fp, "%10s", "mean");
898 fprintf(fp, "%10s", "median");
899 fprintf(fp, "%10s", "sigma");
900 fprintf(fp, "%10s", "stDev");
901 fprintf(fp, "%10s", "MAD");
902 fprintf(fp, "%10s", "min");
903 fprintf(fp, "%10s", "max");
904 fprintf(fp, "%10s", "spread");
905 fputc('\n', fp);
906 for (i = 0; i < 100; i++)
907 fputc('-', fp);
908 fputc('\n', fp);
909
910 for (i = 0; i < PVs; i++) {
911 fprintf(fp, "%20s", PVvalue[i].name);
912 if (!connectedInTime[i]) {
913 if (printErrors)
914 fprintf(stderr, "%s is not connected or invalid PV name.\n", PVvalue[i].name);
915 else {
916 fprintf(fp, " ");
917 fputs(errorValue, fp);
918 }
919 } else {
920 switch (channelType[i]) {
921 case DBF_STRING:
922 case DBF_ENUM:
923 if (!quotes)
924 fputs(PVvalue[i].value, fp);
925 else {
926 if (SDDS_StringIsBlank(PVvalue[i].value) ||
927 SDDS_HasWhitespace(PVvalue[i].value))
928 fprintf(fp, "\"%s\"", PVvalue[i].value);
929 else
930 fputs(PVvalue[i].value, fp);
931 }
932 break;
933 default:
934 fprintf(fp, "%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f", PVvalue[i].mean,
935 PVvalue[i].median, PVvalue[i].sigma, PVvalue[i].stDev, PVvalue[i].MAD,
936 PVvalue[i].min, PVvalue[i].max, PVvalue[i].spread);
937 break;
938 }
939 }
940 fputc('\n', fp);
941 }
942}
943
944long writeStatisticsToSDDSFile(char *outputFile, long *channelType, PV_VALUE *PVvalue, long PVs,
945 short *connectedInTime, char *errorValue, short printErrors) {
946 SDDS_DATASET SDDS_out;
947 long i, row;
948
949 for (i = 0; i < PVs; i++) {
950 switch (channelType[i]) {
951 case DBF_STRING:
952 case DBF_ENUM:
953 case DBF_CHAR:
954 fprintf(stderr, "Error, doing statistical analysis for PVs of non-numeric type is meaningless.\n");
955 return 0;
956 default:
957 break;
958 }
959 }
960
961 if (!SDDS_InitializeOutput(&SDDS_out, SDDS_BINARY, 0, NULL, "cavget output", outputFile))
962 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
963 if (SDDS_DefineColumn(&SDDS_out, "ControlName", NULL, NULL, NULL, NULL, SDDS_STRING, 0) < 0 ||
964 SDDS_DefineColumn(&SDDS_out, "Mean", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
965 SDDS_DefineColumn(&SDDS_out, "Median", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
966 SDDS_DefineColumn(&SDDS_out, "Sigma", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
967 SDDS_DefineColumn(&SDDS_out, "StDev", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
968 SDDS_DefineColumn(&SDDS_out, "MAD", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
969 SDDS_DefineColumn(&SDDS_out, "Minimum", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
970 SDDS_DefineColumn(&SDDS_out, "Maximum", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
971 SDDS_DefineColumn(&SDDS_out, "Spread", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0)
972 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
973 if (!SDDS_WriteLayout(&SDDS_out))
974 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
975 if (!SDDS_StartTable(&SDDS_out, PVs))
976 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
977 for (i = row = 0; i < PVs; i++, row++) {
978 if (printErrors && !connectedInTime[i])
979 fprintf(stderr, "%s is not connected or invalid PV name.\n", PVvalue[i].name);
980 if (!connectedInTime[i] ||
981 channelType[i] == DBF_STRING || channelType[i] == DBF_ENUM) {
982 row--;
983 continue;
984 } else {
985 if (!SDDS_SetRowValues(&SDDS_out, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, row,
986 "ControlName", PVvalue[i].name,
987 "Mean", PVvalue[i].mean, "Median", PVvalue[i].median,
988 "Sigma", PVvalue[i].sigma, "StDev", PVvalue[i].stDev,
989 "MAD", PVvalue[i].MAD, "Minimum", PVvalue[i].min,
990 "Maximum", PVvalue[i].max, "Spread", PVvalue[i].spread, NULL)) {
991 SDDS_SetError((char *)"Unable to set statistical values in SDDS data set");
992 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
993 return 0;
994 }
995 }
996 }
997 if (!SDDS_WritePage(&SDDS_out))
998 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
999 if (!SDDS_Terminate(&SDDS_out))
1000 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
1001 return 1;
1002}
1003
1004void oag_ca_exception_handler(struct exception_handler_args args) {
1005 char *pName;
1006 int severityInt;
1007 static const char *severity[] =
1008 {
1009 "Warning",
1010 "Success",
1011 "Error",
1012 "Info",
1013 "Fatal",
1014 "Fatal",
1015 "Fatal",
1016 "Fatal"};
1017
1018 severityInt = CA_EXTRACT_SEVERITY(args.stat);
1019
1020 fprintf(stderr, "CA.Client.Exception................\n");
1021 fprintf(stderr, " %s: \"%s\"\n",
1022 severity[severityInt],
1023 ca_message(args.stat));
1024
1025 if (args.ctx) {
1026 fprintf(stderr, " Context: \"%s\"\n", args.ctx);
1027 }
1028 if (args.chid) {
1029 pName = (char *)ca_name(args.chid);
1030 fprintf(stderr, " Channel: \"%s\"\n", pName);
1031 fprintf(stderr, " Type: \"%s\"\n", dbr_type_to_text(args.type));
1032 }
1033 fprintf(stderr, "This sometimes indicates an IOC that is hung up.\n");
1034 _exit(EXIT_FAILURE);
1035}
1036
1037#if (EPICS_VERSION > 3)
1038
1039void printResultPVA(char *startBrace, long labeled, PVA_OVERALL *pva, PV_VALUE *PVvalue, char *endBrace,
1040 char *floatFormat, short charArray, char *errorValue, long quotes, long cavputForm,
1041 long excludeErrors, char *delimiter, long secondValue,
1042 long doRepeat, long doStats, long repeats, long average, short printErrors) {
1043 long i, j, n, delimNeeded = 0;
1044 char *s;
1045
1046 if (doStats) {
1047 for (i = 0; i < pva->numPVs; i++) {
1048 if (pva->isConnected[i]) {
1049 switch (pva->pvaData[i].scalarType) {
1050 case epics::pvData::pvString:
1051 case epics::pvData::pvBoolean:
1052 fprintf(stderr, "Error, doing statistical analysis for PVs of non-numeric type is meaningless.\n");
1053 exit(EXIT_FAILURE);
1054 default:
1055 break;
1056 }
1057 if (pva->pvaData[i].numGetElements != 1) {
1058 fprintf(stderr, "Error, doing statistical analysis for PVs of array types is not available.\n");
1059 exit(EXIT_FAILURE);
1060 }
1061 }
1062 }
1063 }
1064
1065 for (j = 0; j < pva->numPVs; j++) {
1066 if (excludeErrors && !pva->isConnected[j])
1067 continue;
1068 if (delimNeeded && delimiter)
1069 fputs(delimiter, stdout);
1070 if (cavputForm) {
1071 if (strncmp(PVvalue[j].name, "pva://", 6) == 0) {
1072 PVvalue[j].name += 6;
1073 fprintf(stdout, "pva://%s=", PVvalue[j].name);
1074 PVvalue[j].name -= 6;
1075 } else if (strncmp(PVvalue[j].name, "ca://", 5) == 0) {
1076 PVvalue[j].name += 5;
1077 fprintf(stdout, "ca://%s=", PVvalue[j].name);
1078 PVvalue[j].name -= 5;
1079 } else {
1080 fprintf(stdout, "%s=", PVvalue[j].name);
1081 }
1082 quotes = 0;
1083 } else {
1084 if (startBrace)
1085 fputs(startBrace, stdout);
1086 if (labeled)
1087 fprintf(stdout, "%s ", pva->pvaChannelNames[j].c_str());
1088 }
1089 if (!pva->isConnected[j]) {
1090 if (printErrors)
1091 fprintf(stderr, "%s is not connected or invalid PV name.\n", pva->pvaChannelNames[j].c_str());
1092 else
1093 fputs(errorValue, stdout);
1094 } else if ((pva->pvaData[j].numGetElements == 1) && (pva->pvaData[j].fieldType != epics::pvData::scalarArray)) {
1095 switch (pva->pvaData[j].scalarType) {
1096 case epics::pvData::pvByte:
1097 case epics::pvData::pvUByte:
1098 case epics::pvData::pvShort:
1099 case epics::pvData::pvUShort:
1100 case epics::pvData::pvInt:
1101 case epics::pvData::pvUInt:
1102 case epics::pvData::pvLong:
1103 case epics::pvData::pvULong:
1104 if (cavputForm || (!doRepeat && !doStats)) {
1105 fprintf(stdout, "%.0f", pva->pvaData[j].mean);
1106 } else {
1107 if (doRepeat) {
1108 if (!average) {
1109 for (i = 0; i < repeats; i++) {
1110 fprintf(stdout, "%.0f ", pva->pvaData[j].getData[i].values[0]);
1111 }
1112 } else {
1113 fprintf(stdout, "%.0f", pva->pvaData[j].mean);
1114 if (secondValue) {
1115 fprintf(stdout, " ");
1116 fprintf(stdout, "%.0f", pva->pvaData[j].sigma);
1117 }
1118 }
1119 }
1120 if (doStats) {
1121 fprintf(stdout, "mean ");
1122 fprintf(stdout, "%.0f", pva->pvaData[j].mean);
1123 fprintf(stdout, " median ");
1124 fprintf(stdout, "%.0f", pva->pvaData[j].median);
1125 fprintf(stdout, " sigma ");
1126 fprintf(stdout, "%.0f", pva->pvaData[j].sigma);
1127 fprintf(stdout, " stDev ");
1128 fprintf(stdout, "%.0f", pva->pvaData[j].stDev);
1129 fprintf(stdout, " MAD ");
1130 fprintf(stdout, "%.0f", pva->pvaData[j].MAD);
1131 fprintf(stdout, " min ");
1132 fprintf(stdout, "%.0f", pva->pvaData[j].min);
1133 fprintf(stdout, " max ");
1134 fprintf(stdout, "%.0f", pva->pvaData[j].max);
1135 fprintf(stdout, " spread ");
1136 fprintf(stdout, "%.0f", pva->pvaData[j].spread);
1137 }
1138 }
1139 break;
1140 case epics::pvData::pvString:
1141 case epics::pvData::pvBoolean:
1142 n = 0;
1143 if ((doRepeat) && (average)) {
1144 n = pva->pvaData[j].numGetReadings - 1;
1145 }
1146 while (n < pva->pvaData[j].numGetReadings) {
1147 s = pva->pvaData[j].getData[n].stringValues[0];
1148 if (quotes && (SDDS_StringIsBlank((char *)s) || SDDS_HasWhitespace((char *)s))) {
1149 fprintf(stdout, "\"%s\"", s);
1150 } else {
1151 fputs(s, stdout);
1152 }
1153 if ((doRepeat) && (secondValue)) {
1154 fprintf(stdout, " 0");
1155 }
1156 if (n != pva->pvaData[j].numGetReadings - 1) {
1157 fprintf(stdout, " ");
1158 }
1159 n++;
1160 }
1161 break;
1162 case epics::pvData::pvDouble:
1163 case epics::pvData::pvFloat:
1164 default:
1165 if (cavputForm || (!doRepeat && !doStats)) {
1166 fprintf(stdout, floatFormat, pva->pvaData[j].mean);
1167 } else {
1168 if (doRepeat) {
1169 if (!average) {
1170 for (i = 0; i < repeats; i++) {
1171 fprintf(stdout, floatFormat, pva->pvaData[j].getData[i].values[0]);
1172 fprintf(stdout, " ");
1173 }
1174 } else {
1175 fprintf(stdout, floatFormat, pva->pvaData[j].mean);
1176 if (secondValue) {
1177 fprintf(stdout, " ");
1178 fprintf(stdout, floatFormat, pva->pvaData[j].sigma);
1179 }
1180 }
1181 }
1182 if (doStats) {
1183 fprintf(stdout, " mean ");
1184 fprintf(stdout, floatFormat, pva->pvaData[j].mean);
1185 fprintf(stdout, " median ");
1186 fprintf(stdout, floatFormat, pva->pvaData[j].median);
1187 fprintf(stdout, " sigma ");
1188 fprintf(stdout, floatFormat, pva->pvaData[j].sigma);
1189 fprintf(stdout, " stDev ");
1190 fprintf(stdout, floatFormat, pva->pvaData[j].stDev);
1191 fprintf(stdout, " MAD ");
1192 fprintf(stdout, floatFormat, pva->pvaData[j].MAD);
1193 fprintf(stdout, " min ");
1194 fprintf(stdout, floatFormat, pva->pvaData[j].min);
1195 fprintf(stdout, " max ");
1196 fprintf(stdout, floatFormat, pva->pvaData[j].max);
1197 fprintf(stdout, " spread ");
1198 fprintf(stdout, floatFormat, pva->pvaData[j].spread);
1199 }
1200 }
1201 break;
1202 }
1203 } else {
1204 n = 0;
1205 if ((doRepeat) && (average)) {
1206 n = pva->pvaData[j].numGetReadings - 1;
1207 }
1208 switch (pva->pvaData[j].scalarType) {
1209 case epics::pvData::pvString:
1210 case epics::pvData::pvBoolean: {
1211 while (n < pva->pvaData[j].numGetReadings) {
1212 fprintf(stdout, "%ld", pva->pvaData[j].numGetElements);
1213 for (i = 0; i < pva->pvaData[j].numGetElements; i++) {
1214 if (quotes && (SDDS_StringIsBlank((char *)pva->pvaData[j].getData[n].stringValues[i]) || SDDS_HasWhitespace((char *)pva->pvaData[j].getData[n].stringValues[i]))) {
1215 fprintf(stdout, ",\"%s\"", pva->pvaData[j].getData[n].stringValues[i]);
1216 } else {
1217 fprintf(stdout, ",%s", pva->pvaData[j].getData[n].stringValues[i]);
1218 }
1219 }
1220 if ((doRepeat) && (secondValue)) {
1221 fprintf(stdout, " 0");
1222 }
1223 if (n != pva->pvaData[j].numGetReadings - 1) {
1224 fprintf(stdout, " ");
1225 }
1226 n++;
1227 }
1228 break;
1229 }
1230 case epics::pvData::pvByte:
1231 case epics::pvData::pvUByte: {
1232 while (n < pva->pvaData[j].numGetReadings) {
1233 if (charArray) {
1234 if (quotes) {
1235 fprintf(stdout, "\"");
1236 }
1237 for (i = 0; i < pva->pvaData[j].numGetElements; i++) {
1238 fprintf(stdout, "%c", (char)pva->pvaData[j].getData[n].values[i]);
1239 }
1240 if (quotes) {
1241 fprintf(stdout, "\"");
1242 }
1243 } else {
1244 fprintf(stdout, "%ld", pva->pvaData[j].numGetElements);
1245 for (i = 0; i < pva->pvaData[j].numGetElements; i++) {
1246 fprintf(stdout, ",%.0f", pva->pvaData[j].getData[n].values[i]);
1247 }
1248 if ((doRepeat) && (secondValue)) {
1249 fprintf(stdout, " 0");
1250 }
1251 }
1252 if (n != pva->pvaData[j].numGetReadings - 1) {
1253 fprintf(stdout, " ");
1254 }
1255 n++;
1256 }
1257 break;
1258 }
1259 case epics::pvData::pvShort:
1260 case epics::pvData::pvUShort:
1261 case epics::pvData::pvInt:
1262 case epics::pvData::pvUInt:
1263 case epics::pvData::pvLong:
1264 case epics::pvData::pvULong: {
1265 while (n < pva->pvaData[j].numGetReadings) {
1266 fprintf(stdout, "%ld", pva->pvaData[j].numGetElements);
1267 for (i = 0; i < pva->pvaData[j].numGetElements; i++) {
1268 fprintf(stdout, ",%.0f", pva->pvaData[j].getData[n].values[i]);
1269 }
1270 if ((doRepeat) && (secondValue)) {
1271 fprintf(stdout, " 0");
1272 }
1273 if (n != pva->pvaData[j].numGetReadings - 1) {
1274 fprintf(stdout, " ");
1275 }
1276 n++;
1277 }
1278 break;
1279 }
1280 case epics::pvData::pvDouble:
1281 case epics::pvData::pvFloat:
1282 default: {
1283 while (n < pva->pvaData[j].numGetReadings) {
1284 fprintf(stdout, "%ld", pva->pvaData[j].numGetElements);
1285 for (i = 0; i < pva->pvaData[j].numGetElements; i++) {
1286 fprintf(stdout, ",");
1287 fprintf(stdout, floatFormat, pva->pvaData[j].getData[n].values[i]);
1288 }
1289 if ((doRepeat) && (secondValue)) {
1290 fprintf(stdout, " 0");
1291 }
1292 if (n != pva->pvaData[j].numGetReadings - 1) {
1293 fprintf(stdout, " ");
1294 }
1295 n++;
1296 }
1297 break;
1298 }
1299 }
1300 }
1301 if (endBrace && !cavputForm)
1302 fputs(endBrace, stdout);
1303
1304 delimNeeded = 1;
1305 }
1306 if (delimNeeded)
1307 fputc('\n', stdout);
1308 return;
1309}
1310
1311void printResultPrettyPVA(PVA_OVERALL *pva, long quotes, char *errorValue, short printErrors) {
1312 long i;
1313
1314 fprintf(stdout, "%20s", "ControlName");
1315 fprintf(stdout, "%10s", "mean");
1316 fprintf(stdout, "%10s", "median");
1317 fprintf(stdout, "%10s", "sigma");
1318 fprintf(stdout, "%10s", "stDev");
1319 fprintf(stdout, "%10s", "MAD");
1320 fprintf(stdout, "%10s", "min");
1321 fprintf(stdout, "%10s", "max");
1322 fprintf(stdout, "%10s", "spread");
1323 fputc('\n', stdout);
1324 for (i = 0; i < 100; i++)
1325 fputc('-', stdout);
1326 fputc('\n', stdout);
1327
1328 for (i = 0; i < pva->numPVs; i++) {
1329 if (!pva->isConnected[i]) {
1330 if (printErrors)
1331 fprintf(stderr, "%s is not connected or invalid PV name.\n", pva->pvaChannelNames[i].c_str());
1332 else {
1333 fprintf(stdout, "%20s", pva->pvaChannelNames[i].c_str());
1334 fprintf(stdout, " ");
1335 fputs(errorValue, stdout);
1336 }
1337 } else {
1338 fprintf(stdout, "%20s", pva->pvaChannelNames[i].c_str());
1339 if (pva->pvaData[i].numGetElements == 1) {
1340 switch (pva->pvaData[i].scalarType) {
1341 case epics::pvData::pvString:
1342 case epics::pvData::pvBoolean:
1343 break;
1344 default:
1345 fprintf(stdout, "%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f", pva->pvaData[i].mean,
1346 pva->pvaData[i].median, pva->pvaData[i].sigma, pva->pvaData[i].stDev, pva->pvaData[i].MAD,
1347 pva->pvaData[i].min, pva->pvaData[i].max, pva->pvaData[i].spread);
1348 break;
1349 }
1350 } else {
1351 }
1352 }
1353 fputc('\n', stdout);
1354 }
1355}
1356
1357void writeStatisticsToSDDSFilePVA(char *outputFile, PVA_OVERALL *pva, long quotes, char *errorValue, short printErrors) {
1358 SDDS_DATASET SDDS_out;
1359 long i, row;
1360
1361 for (i = 0; i < pva->numPVs; i++) {
1362 if (pva->isConnected[i]) {
1363 switch (pva->pvaData[i].scalarType) {
1364 case epics::pvData::pvString:
1365 case epics::pvData::pvBoolean:
1366 fprintf(stderr, "Error, doing statistical analysis for PVs of non-numeric type is meaningless.\n");
1367 exit(EXIT_FAILURE);
1368 default:
1369 break;
1370 }
1371 if (pva->pvaData[i].numGetElements != 1) {
1372 fprintf(stderr, "Error, doing statistical analysis for PVs of array types is not available.\n");
1373 exit(EXIT_FAILURE);
1374 }
1375 }
1376 }
1377
1378 if (!SDDS_InitializeOutput(&SDDS_out, SDDS_BINARY, 0, NULL, "cavget output", outputFile))
1379 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
1380 if (SDDS_DefineColumn(&SDDS_out, "ControlName", NULL, NULL, NULL, NULL, SDDS_STRING, 0) < 0 ||
1381 SDDS_DefineColumn(&SDDS_out, "Mean", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
1382 SDDS_DefineColumn(&SDDS_out, "Median", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
1383 SDDS_DefineColumn(&SDDS_out, "Sigma", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
1384 SDDS_DefineColumn(&SDDS_out, "StDev", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
1385 SDDS_DefineColumn(&SDDS_out, "MAD", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
1386 SDDS_DefineColumn(&SDDS_out, "Minimum", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
1387 SDDS_DefineColumn(&SDDS_out, "Maximum", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
1388 SDDS_DefineColumn(&SDDS_out, "Spread", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0)
1389 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
1390 if (!SDDS_WriteLayout(&SDDS_out))
1391 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
1392 if (!SDDS_StartTable(&SDDS_out, pva->numPVs))
1393 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
1394 for (i = row = 0; i < pva->numPVs; i++, row++) {
1395 if (printErrors && !pva->isConnected[i])
1396 fprintf(stderr, "%s is not connected or invalid PV name.\n", pva->pvaChannelNames[i].c_str());
1397 if (!pva->isConnected[i] ||
1398 pva->pvaData[i].scalarType == epics::pvData::pvString ||
1399 pva->pvaData[i].scalarType == epics::pvData::pvBoolean) {
1400 row--;
1401 continue;
1402 } else {
1403 if (!SDDS_SetRowValues(&SDDS_out, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, row,
1404 "ControlName", pva->pvaChannelNames[i].c_str(),
1405 "Mean", pva->pvaData[i].mean, "Median", pva->pvaData[i].median,
1406 "Sigma", pva->pvaData[i].sigma, "StDev", pva->pvaData[i].stDev,
1407 "MAD", pva->pvaData[i].MAD, "Minimum", pva->pvaData[i].min,
1408 "Maximum", pva->pvaData[i].max, "Spread", pva->pvaData[i].spread, NULL)) {
1409 SDDS_SetError((char *)"Unable to set statistical values in SDDS data set");
1410 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
1411 }
1412 }
1413 }
1414 if (!SDDS_WritePage(&SDDS_out))
1415 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
1416 if (!SDDS_Terminate(&SDDS_out))
1417 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
1418 return;
1419}
1420
1421void GetInfoData(PVA_OVERALL *pva, PV_VALUE *PVvalue) {
1422 long n;
1423 uint32_t EnumNumOfChoices;
1424 char **EnumChoices=NULL;
1425 for (n=0; n<pva->numPVs; n++) {
1426 if (n>0)
1427 fprintf(stdout, "\n");
1428 fprintf(stdout, "%s\n", PVvalue[n].name);
1429 if (pva->isConnected[n])
1430 fprintf(stdout, " Active: y\n");
1431 else
1432 fprintf(stdout, " Active: n\n");
1433 fprintf(stdout, " Provider: %s\n", GetProviderName(pva, n).c_str());
1434 fprintf(stdout, " Host: %s\n", GetRemoteAddress(pva,n).c_str());
1435 if (HaveReadAccess(pva, n))
1436 fprintf(stdout, " Read Access: y\n");
1437 else
1438 fprintf(stdout, " Read Access: n\n");
1439 if (HaveWriteAccess(pva, n))
1440 fprintf(stdout, " Write Access: y\n");
1441 else
1442 fprintf(stdout, " Write Access: n\n");
1443 fprintf(stdout, " Alarm Severity: %s\n", GetAlarmSeverity(pva, n).c_str());
1444 fprintf(stdout, " Structure ID: %s\n", GetStructureID(pva, n).c_str());
1445 fprintf(stdout, " Field Type: %s\n", GetFieldType(pva,n).c_str());
1446 fprintf(stdout, " Element Count: %" PRIu32 "\n", GetElementCount(pva,n));
1447 fprintf(stdout, " Native Data Type: %s\n", GetNativeDataType(pva,n).c_str());
1448 if (IsEnumFieldType(pva,n)) {
1449 EnumNumOfChoices = GetEnumChoices(pva, n, &EnumChoices);
1450 fprintf(stdout, " Number of Choices: %" PRIu32 "\n", EnumNumOfChoices);
1451 for (uint32_t m = 0; m < EnumNumOfChoices; m++) {
1452 fprintf(stdout, " Index %" PRIu32 ": %s\n", m, EnumChoices[m]);
1453 free(EnumChoices[m]);
1454 EnumChoices[m]=NULL;
1455 }
1456 if (EnumChoices) {
1457 free(EnumChoices);
1458 EnumChoices=NULL;
1459 }
1460 }
1461 }
1462
1463}
1464
1465#endif
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
int32_t SDDS_HasWhitespace(char *string)
Checks if a string contains any whitespace characters.
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
Definition array.c:181
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
Definition findMinMax.c:33
void usleepSystemIndependent(long usec)
Sleep for a given number of microseconds, system-independently.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
long computeMoments(double *mean, double *rms, double *standDev, double *meanAbsoluteDev, double *x, long n)
Computes the mean, RMS, standard deviation, and mean absolute deviation of an array.
Definition moments.c:108
Helper Functions used by cavget and cavput.
Functions for managing and interacting with Process Variable Array (PVA) structures.
long find_median(double *value, double *x, long n)
Finds the median value of an array of doubles and returns the index of the median.
Definition rowmedian.c:32
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
long despikeData(double *data, long rows, long neighbors, long passes, long averageOf, double threshold, long countLimit)
Remove spikes from a data array by comparing each point to its neighbors.
Definition smooth.c:86