234 {
235 int32_t beginRange, endRange, rangeInterval;
236 long dryRun;
237 long PVs, j, i_arg, labeled, quotes, numerical;
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)
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) {
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)");
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 ||
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,
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,
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,
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,
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)
448 break;
449 default:
450 SDDS_Bomb((
char *)
"unknown option (cavget)");
451 break;
452 }
453 } else
455 }
456
457 if (doRepeat && doStats)
458 SDDS_Bomb((
char *)
"-repeat and -statistics are imcompatible.");
459
460
461
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
493 allocPVA(&pva, PVs, repeats);
494
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
519 ConnectPVA(&pva, pendIOTime);
520
521
522
523 repeats0 = 0;
524
525 do {
526
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
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)) {
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);
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);
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);
760 if (List)
761 free(List);
762
763 return EXIT_SUCCESS;
764}
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.
#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.
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.