87#include <epicsVersion.h>
88#if (EPICS_VERSION > 3)
94#include "match_string.h"
101#define CLO_PENDIOTIME 2
104#define CLO_FLOATFORMAT 5
105#define CLO_DELIMITER 6
106#define CLO_NOQUOTES 7
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
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"};
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] = {
138#define PROVIDER_PVA 1
139#define PROVIDER_COUNT 2
140char *providerOption[PROVIDER_COUNT] = {
145static char *USAGE = (
char *)
147" [-list=<string>[=<value>][,<string>[=<value>]...]]\n"
148" [-range=begin=<integer>,end=<integer>[,format=<string>][,interval=<integer>]]\n"
149" [-floatformat=<printfString>]\n"
152" [-delimiter=<string>]\n"
155" [-embrace=start=<string>,end=<string>]\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"
162" [-errorValue=<string>]\n"
164" [-despike[[neighbors=<integer>][,passes=<integer>][,averageOf=<integer>][,threshold=<value>]]]\n"
165" [-provider={ca|pva}]\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";
200void sleep_us(
unsigned int nusecs) {
203 tval.tv_sec = nusecs / 1000000;
204 tval.tv_usec = nusecs % 1000000;
205 select(0, NULL, NULL, NULL, &tval);
208#define REPEAT_AVERAGE 0x0001U
209#define REPEAT_SIGMA 0x0002U
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);
223#if (EPICS_VERSION > 3)
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);
234int main(
int argc,
char **argv) {
235 int32_t beginRange, endRange, rangeInterval;
237 long PVs, j, i_arg, labeled, quotes, numerical;
242 char *rangeFormat, *floatFormat, *delimiter;
244 double pendIOTime, repeatPause, despikeThreshold;
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;
257#if (EPICS_VERSION > 3)
263 argc =
scanargs(&s_arg, argc, argv);
265 fprintf(stderr,
"%s\n", USAGE);
268 statsFormat = statsOutput = NULL;
271 PVs = dryRun = labeled = numerical = 0;
272 floatFormat = (
char *)
"%g";
273 delimiter = (
char *)
"\n";
276 startBrace = endBrace = NULL;
277 repeats = average = sigma = 0;
278 doStats = doRepeat = doDespike = 0;
280 cavputForm = excludeErrors = 0;
282 despikeNeighbors = 10;
284 despikeAverageOf = 4;
285 despikeThreshold = 0;
287 for (i_arg = 1; i_arg < argc; i_arg++) {
288 if (s_arg[i_arg].arg_type == OPTION) {
290 switch (
match_string(s_arg[i_arg].list[0], commandline_option, COMMANDLINE_OPTIONS, 0)) {
292 if (s_arg[i_arg].n_items < 2)
293 SDDS_Bomb((
char *)
"invalid -list syntax (cavget)");
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;
300 multiplyWithList(&PVvalue, &PVs, List, s_arg[i_arg].n_items - 1);
303 s_arg[i_arg].n_items--;
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,
312 !(flags & BEGIN_GIVEN) || !(flags & END_GIVEN) || beginRange > endRange ||
314 SDDS_Bomb((
char *)
"invalid -range syntax/values");
316 rangeFormat = (
char *)
"%ld";
317 multiplyWithRange(&PVvalue, &PVs, beginRange, endRange, rangeInterval, rangeFormat);
318 s_arg[i_arg].n_items++;
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 ||
325 SDDS_Bomb((
char *)
"invalid -pendIoTime value (cavget)");
333 case CLO_PRINTERRORS:
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];
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];
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,
363 SDDS_Bomb((
char *)
"invalid -embrace syntax");
364 s_arg[i_arg].n_items++;
367 s_arg[i_arg].n_items--;
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,
375 despikeNeighbors < 0 ||
376 despikePasses < 0 || despikeAverageOf < 0 || despikeThreshold < 0)
377 SDDS_Bomb((
char *)
"invalid -despike syntax");
378 s_arg[i_arg].n_items++;
381 s_arg[i_arg].n_items--;
383 repeats = average = 0;
384 if (!
scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
387 "average", -1, NULL, 0, REPEAT_AVERAGE,
388 "sigma", -1, NULL, 0, REPEAT_SIGMA,
391 SDDS_Bomb((
char *)
"invalid -repeat syntax");
392 if (flags & REPEAT_AVERAGE)
394 if (flags & REPEAT_SIGMA)
396 s_arg[i_arg].n_items++;
399 s_arg[i_arg].n_items--;
402 if (!
scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
409 SDDS_Bomb((
char *)
"invalid -statistics syntax");
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:
416 SDDS_Bomb((
char *)
"invalid -statics format syntax");
420 SDDS_Bomb((
char *)
"invalid -statics format=SDDS syntax, output filename is not given");
423 SDDS_Bomb((
char *)
"unknown format given to -statistics option");
426 s_arg[i_arg].n_items++;
429 if (s_arg[i_arg].n_items != 2)
430 SDDS_Bomb((
char *)
"invalid -errorValue syntax");
431 errorValue = s_arg[i_arg].list[1];
439 case CLO_EXCLUDEERRORS:
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)
450 SDDS_Bomb((
char *)
"unknown option (cavget)");
457 if (doRepeat && doStats)
458 SDDS_Bomb((
char *)
"-repeat and -statistics are imcompatible.");
463 if (!doRepeat && !doStats)
464 SDDS_Bomb((
char *)
"neither repeat or statistics is given, can not do despiking!");
469 if (despikeNeighbors > repeats)
470 despikeNeighbors = repeats;
471 if (despikeAverageOf > repeats)
472 despikeAverageOf = repeats;
475 delimiter = (
char *)
",";
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;
487 printf(
"%32s\n", PVvalue[j].name);
491#if (EPICS_VERSION > 3)
493 allocPVA(&pva, PVs, repeats);
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;
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;
509 names[j] = PVvalue[j].name;
510 if (providerMode == PROVIDER_PVA)
516 pva.pvaChannelNames = freeze(names);
517 pva.pvaProvider = freeze(provider);
519 ConnectPVA(&pva, pendIOTime);
528 pva.includeAlarmSeverity =
true;
530 if (GetPVAValues(&pva) == 1) {
531 return (EXIT_FAILURE);
534 GetInfoData(&pva, PVvalue);
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;
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];
554 if ((repeats0 < repeats) && (repeatPause > 0)) {
557 }
while (repeats0 < repeats);
560 for (j = 0; j < PVs; j++) {
561 if ((pva.pvaData[j].numGetElements == 1) && (pva.pvaData[j].numeric)) {
564 v = (
double *)malloc(
sizeof(
double) * repeats);
565 for (i = 0; i < repeats; i++) {
566 v[i] = pva.pvaData[j].getData[i].values[0];
569 despikeData(v, repeats, despikeNeighbors, despikePasses, despikeAverageOf, despikeThreshold, 0);
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);
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);
589 switch (
match_string(statsFormat, statisticsFormat, STATISTICS_FORMATS, 0)) {
590 case CLO_STATS_PRETTY:
591 printResultPrettyPVA(&pva, quotes, errorValue, printErrors);
594 writeStatisticsToSDDSFilePVA(statsOutput, &pva, quotes, errorValue, printErrors);
601 for (j = 0; j < PVs; j++) {
603 free(PVvalue[j].name);
615 return (EXIT_SUCCESS);
617 if (!(value = (
double **)malloc(
sizeof(
double *) * PVs)))
618 SDDS_Bomb((
char *)
"memory allocation failure (cavget)");
619 for (j = 0; j < PVs; j++) {
621 if (!(value[j] = (
double *)calloc((repeats),
sizeof(
double))))
622 SDDS_Bomb((
char *)
"memory allocation failure (cavget)");
624 if (!(value[j] = (
double *)calloc(1,
sizeof(
double))))
625 SDDS_Bomb((
char *)
"memory allocation failure (cavget)");
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",
643 ca_pend_io(pendIOTime);
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;
651 for (j = 0; j < PVs; j++)
652 channelType[j] = ca_field_type(channelID[j]);
654 for (j = 0; j < PVs; j++) {
655 if (!(connectedInTime[j] = ca_state(channelID[j]) == cs_conn))
657 switch (channelType[j]) {
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",
669 fprintf(stderr,
"Error: No access to PV %s\n", PVvalue[j].name);
674 if (ca_get(DBR_DOUBLE, channelID[j],
675 &value[j][repeats0]) != ECA_NORMAL) {
676 fprintf(stderr,
"problem doing get for %s\n",
684 ca_pend_io(pendIOTime);
687 for (j = 0; j < PVs; j++)
688 PVvalue[j].mean = value[j][0];
690 if ((repeats0 < repeats) && (repeatPause > 0)) {
691 ca_pend_event(repeatPause);
693 }
while (repeats0 < repeats);
696 for (j = 0; j < PVs; j++) {
698 despikeData(value[j], repeats, despikeNeighbors, despikePasses, despikeAverageOf,
699 despikeThreshold, 0);
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,
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);
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,
725 switch (
match_string(statsFormat, statisticsFormat, STATISTICS_FORMATS, 0)) {
726 case CLO_STATS_PRETTY:
727 printResultPretty(stdout, channelType, PVvalue, PVs, quotes, connectedInTime, errorValue, printErrors);
730 writeStatisticsToSDDSFile(statsOutput, channelType, PVvalue, PVs, connectedInTime, errorValue, printErrors);
739 for (j = 0; j < PVs; j++) {
741 free(PVvalue[j].name);
742 if (PVvalue[j].value)
743 free(PVvalue[j].value);
744 PVvalue[j].name = PVvalue[j].value = NULL;
747 for (j = 0; j < PVs; j++)
758 free(connectedInTime);
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) {
774 if (excludeErrors && !connectedInTime)
776 if (delimNeeded && delimiter)
777 fputs(delimiter, fp);
779 fprintf(fp,
"%s=", PVvalue.name);
783 fputs(startBrace, fp);
785 fprintf(fp,
"%s ", PVvalue.name);
787 if (!connectedInTime) {
789 fprintf(stderr,
"%s is not connected or invalid PV name.\n", PVvalue.name);
791 fputs(errorValue, fp);
793 switch (channelType) {
797 if (cavputForm || (!doRepeat && !doStats)) {
798 fprintf(fp,
"%.0f", PVvalue.mean);
802 for (i = 0; i < repeats; i++) {
803 fprintf(fp,
"%.0f ", value[i]);
806 fprintf(fp,
"%.0f", PVvalue.mean);
809 fprintf(fp,
"%.0f", PVvalue.sigma);
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);
836 fputs(PVvalue.value, fp);
840 fprintf(fp,
"\"%s\"", PVvalue.value);
842 fputs(PVvalue.value, fp);
848 if (cavputForm || (!doRepeat && !doStats)) {
849 fprintf(fp, floatFormat, PVvalue.mean);
853 for (i = 0; i < repeats; i++) {
854 fprintf(fp, floatFormat, value[i]);
858 fprintf(fp, floatFormat, PVvalue.mean);
861 fprintf(fp, floatFormat, PVvalue.sigma);
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);
887 if (endBrace && !cavputForm)
892void printResultPretty(FILE *fp,
long *channelType,
PV_VALUE *PVvalue,
long PVs,
long quotes,
893 short *connectedInTime,
char *errorValue,
short printErrors) {
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");
906 for (i = 0; i < 100; i++)
910 for (i = 0; i < PVs; i++) {
911 fprintf(fp,
"%20s", PVvalue[i].name);
912 if (!connectedInTime[i]) {
914 fprintf(stderr,
"%s is not connected or invalid PV name.\n", PVvalue[i].name);
917 fputs(errorValue, fp);
920 switch (channelType[i]) {
924 fputs(PVvalue[i].value, fp);
928 fprintf(fp,
"\"%s\"", PVvalue[i].value);
930 fputs(PVvalue[i].value, fp);
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);
944long writeStatisticsToSDDSFile(
char *outputFile,
long *channelType,
PV_VALUE *PVvalue,
long PVs,
945 short *connectedInTime,
char *errorValue,
short printErrors) {
949 for (i = 0; i < PVs; i++) {
950 switch (channelType[i]) {
954 fprintf(stderr,
"Error, doing statistical analysis for PVs of non-numeric type is meaningless.\n");
975 if (!SDDS_StartTable(&SDDS_out, PVs))
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) {
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");
1000 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
1004void oag_ca_exception_handler(
struct exception_handler_args args) {
1007 static const char *severity[] =
1018 severityInt = CA_EXTRACT_SEVERITY(args.stat);
1020 fprintf(stderr,
"CA.Client.Exception................\n");
1021 fprintf(stderr,
" %s: \"%s\"\n",
1022 severity[severityInt],
1023 ca_message(args.stat));
1026 fprintf(stderr,
" Context: \"%s\"\n", args.ctx);
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));
1033 fprintf(stderr,
"This sometimes indicates an IOC that is hung up.\n");
1034 _exit(EXIT_FAILURE);
1037#if (EPICS_VERSION > 3)
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;
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");
1057 if (pva->pvaData[i].numGetElements != 1) {
1058 fprintf(stderr,
"Error, doing statistical analysis for PVs of array types is not available.\n");
1065 for (j = 0; j < pva->numPVs; j++) {
1066 if (excludeErrors && !pva->isConnected[j])
1068 if (delimNeeded && delimiter)
1069 fputs(delimiter, stdout);
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;
1080 fprintf(stdout,
"%s=", PVvalue[j].name);
1085 fputs(startBrace, stdout);
1087 fprintf(stdout,
"%s ", pva->pvaChannelNames[j].c_str());
1089 if (!pva->isConnected[j]) {
1091 fprintf(stderr,
"%s is not connected or invalid PV name.\n", pva->pvaChannelNames[j].c_str());
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);
1109 for (i = 0; i < repeats; i++) {
1110 fprintf(stdout,
"%.0f ", pva->pvaData[j].getData[i].values[0]);
1113 fprintf(stdout,
"%.0f", pva->pvaData[j].mean);
1115 fprintf(stdout,
" ");
1116 fprintf(stdout,
"%.0f", pva->pvaData[j].sigma);
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);
1140 case epics::pvData::pvString:
1141 case epics::pvData::pvBoolean:
1143 if ((doRepeat) && (average)) {
1144 n = pva->pvaData[j].numGetReadings - 1;
1146 while (n < pva->pvaData[j].numGetReadings) {
1147 s = pva->pvaData[j].getData[n].stringValues[0];
1149 fprintf(stdout,
"\"%s\"", s);
1153 if ((doRepeat) && (secondValue)) {
1154 fprintf(stdout,
" 0");
1156 if (n != pva->pvaData[j].numGetReadings - 1) {
1157 fprintf(stdout,
" ");
1162 case epics::pvData::pvDouble:
1163 case epics::pvData::pvFloat:
1165 if (cavputForm || (!doRepeat && !doStats)) {
1166 fprintf(stdout, floatFormat, pva->pvaData[j].mean);
1170 for (i = 0; i < repeats; i++) {
1171 fprintf(stdout, floatFormat, pva->pvaData[j].getData[i].values[0]);
1172 fprintf(stdout,
" ");
1175 fprintf(stdout, floatFormat, pva->pvaData[j].mean);
1177 fprintf(stdout,
" ");
1178 fprintf(stdout, floatFormat, pva->pvaData[j].sigma);
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);
1205 if ((doRepeat) && (average)) {
1206 n = pva->pvaData[j].numGetReadings - 1;
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++) {
1215 fprintf(stdout,
",\"%s\"", pva->pvaData[j].getData[n].stringValues[i]);
1217 fprintf(stdout,
",%s", pva->pvaData[j].getData[n].stringValues[i]);
1220 if ((doRepeat) && (secondValue)) {
1221 fprintf(stdout,
" 0");
1223 if (n != pva->pvaData[j].numGetReadings - 1) {
1224 fprintf(stdout,
" ");
1230 case epics::pvData::pvByte:
1231 case epics::pvData::pvUByte: {
1232 while (n < pva->pvaData[j].numGetReadings) {
1235 fprintf(stdout,
"\"");
1237 for (i = 0; i < pva->pvaData[j].numGetElements; i++) {
1238 fprintf(stdout,
"%c", (
char)pva->pvaData[j].getData[n].values[i]);
1241 fprintf(stdout,
"\"");
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]);
1248 if ((doRepeat) && (secondValue)) {
1249 fprintf(stdout,
" 0");
1252 if (n != pva->pvaData[j].numGetReadings - 1) {
1253 fprintf(stdout,
" ");
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]);
1270 if ((doRepeat) && (secondValue)) {
1271 fprintf(stdout,
" 0");
1273 if (n != pva->pvaData[j].numGetReadings - 1) {
1274 fprintf(stdout,
" ");
1280 case epics::pvData::pvDouble:
1281 case epics::pvData::pvFloat:
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]);
1289 if ((doRepeat) && (secondValue)) {
1290 fprintf(stdout,
" 0");
1292 if (n != pva->pvaData[j].numGetReadings - 1) {
1293 fprintf(stdout,
" ");
1301 if (endBrace && !cavputForm)
1302 fputs(endBrace, stdout);
1307 fputc(
'\n', stdout);
1311void printResultPrettyPVA(
PVA_OVERALL *pva,
long quotes,
char *errorValue,
short printErrors) {
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++)
1326 fputc(
'\n', stdout);
1328 for (i = 0; i < pva->numPVs; i++) {
1329 if (!pva->isConnected[i]) {
1331 fprintf(stderr,
"%s is not connected or invalid PV name.\n", pva->pvaChannelNames[i].c_str());
1333 fprintf(stdout,
"%20s", pva->pvaChannelNames[i].c_str());
1334 fprintf(stdout,
" ");
1335 fputs(errorValue, stdout);
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:
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);
1353 fputc(
'\n', stdout);
1357void writeStatisticsToSDDSFilePVA(
char *outputFile,
PVA_OVERALL *pva,
long quotes,
char *errorValue,
short printErrors) {
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");
1371 if (pva->pvaData[i].numGetElements != 1) {
1372 fprintf(stderr,
"Error, doing statistical analysis for PVs of array types is not available.\n");
1379 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
1389 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
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) {
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);
1415 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
1417 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
1423 uint32_t EnumNumOfChoices;
1424 char **EnumChoices=NULL;
1425 for (n=0; n<pva->numPVs; n++) {
1427 fprintf(stdout,
"\n");
1428 fprintf(stdout,
"%s\n", PVvalue[n].name);
1429 if (pva->isConnected[n])
1430 fprintf(stdout,
" Active: y\n");
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");
1438 fprintf(stdout,
" Read Access: n\n");
1439 if (HaveWriteAccess(pva, n))
1440 fprintf(stdout,
" Write Access: y\n");
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;
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_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.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
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.
int32_t SDDS_HasWhitespace(char *string)
Checks if a string contains any whitespace characters.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_DOUBLE
Identifier for the double data type.
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
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.
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.
Helper Functions used by cavget and cavput.
Functions for managing and interacting with Process Variable Array (PVA) structures.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
void free_scanargs(SCANNED_ARG **scanned, int argc)
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.