SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
cawait.cc File Reference

Detailed Description

Wait for Channel Access (CA) and pvAccess (PVA) Process Variable (PV) values to satisfy specific conditions from the command line.

This program waits for a set of PVs to satisfy specific conditions. It provides logical operations on PV states, supports multiple event triggers, and enables the execution of commands during various event phases. It utilizes both Channel Access (CA) and PV Access (PVA) protocols for PV interaction.

Usage

cawait [-interval=<seconds>]
[-timeLimit=<seconds>]
[-totalTimeLimit=<seconds>]
[-interval=<seconds>]
[-timeLimit=<seconds>]
[-totalTimeLimit=<seconds>]
-waitFor=<PVname>[,lowerLimit=<value>,upperLimit=<value>]
[,equalTo=<value>][,sameAs=<string>][,above=<value>
[,below=<value>][,changed][,monitor]
[{-and | -or | -not}]
[-repeat[=<number>]]
[-emit=event=<string>[,timeout=<string>][,end=<string>]]
[-preEvent=<command>]
[-onEvent=<command>]
[-postEvent=<command>]
[-onEnd=<command>]
[-subprocess=<command>[,event=<string>][,timeout=<string>][,end=<string>]]
[-pendIOTime=<seconds>]
[-noWarnings]
[-provider={ca|pva}]

Options

Required Description
-waitFor Specifies a PV and conditions to monitor.
Optional Description
-interval Interval for PV state checks (default: 0.1 s).
-timeLimit Maximum wait time for a single event (default: infinite).
-totalTimeLimit Maximum runtime for the program (default: infinite).
-repeat Number of times to repeat the monitoring process (default: 1) (0=infinite).
-emit Strings emitted during event or timeout detection.
-preEvent, -postEvent Commands to execute before and after monitoring.
-onEvent, -onEnd Commands executed during event detection or after completion.
-subprocess Subprocess to execute with optional event or timeout messages.
-pendIOTime Time limit for Channel Access (CA) operations.
-provider Protocol provider for PV monitoring (default: CA).
-noWarnings Suppresses warnings during execution.
License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Authors
  • M. Borland
  • R. Soliday

Definition in file cawait.cc.

#include <complex>
#include <iostream>
#include <queue>
#include <cstdlib>
#include <ctime>
#include <cstddef>
#include <unistd.h>
#include <cadef.h>
#include <epicsVersion.h>
#include "mdb.h"
#include "scan.h"
#include "match_string.h"
#include "SDDS.h"

Go to the source code of this file.

Functions

long waitForEvent (double timeLimit, double interval, long invert)
 
long rpn_stack_test (long stack_ptr, long numneeded, char *stackname, char *caller)
 
long rpn_pop_log (long *logical)
 
long rpn_push_log (long logical)
 
void rpn_log_and (void)
 
void rpn_log_or (void)
 
void rpn_log_not (void)
 
void rpn_clear_stack ()
 
void EventHandler (struct event_handler_args event)
 
void StringEventHandler (struct event_handler_args event)
 
void oag_ca_exception_handler (struct exception_handler_args args)
 
int main (int argc, char **argv)
 
void sleep_us (unsigned int nusecs)
 

Function Documentation

◆ EventHandler()

void EventHandler ( struct event_handler_args event)

Definition at line 710 of file cawait.cc.

710 {
711 struct dbr_time_double *dbrValue;
712 long index;
713 index = *((long *)event.usr);
714 dbrValue = (struct dbr_time_double *)event.dbr;
715 waitFor[index].value = (double)dbrValue->value;
716 if (waitFor[index].eventSeen == -1)
717 waitFor[index].eventSeen = 0;
718 else
719 waitFor[index].eventSeen = 1;
720}

◆ main()

int main ( int argc,
char ** argv )

Definition at line 237 of file cawait.cc.

237 {
238 long i_arg, j, terminateLoop;
239 unsigned long flags;
240 SCANNED_ARG *s_arg;
241 double interval, timeLimit, totalTimeLimit, startTime;
242 //long useMonitor;
243 long code = 0, repeats, eventEndPending;
244 char *emitOnEvent, *emitOnTimeout, *emitOnEnd;
245 char **preEvent, **postEvent, **onEvent, **onEnd;
246 SUBPROCESS *subprocess;
247 long preEvents, postEvents, onEvents, onEnds, subprocesses;
248 long noWarnings = 0;
249 long providerMode = 0;
250#if (EPICS_VERSION > 3)
251 PVA_OVERALL pva;
252#endif
253
255 argc = scanargs(&s_arg, argc, argv);
256 if (argc < 2)
257 bomb(NULL, USAGE);
258
259 waitFor = NULL;
260 waitFors = 0;
261 interval = 0.1;
262 timeLimit = totalTimeLimit = -1;
263 //useMonitor = 0;
264 repeats = 1;
265 emitOnEvent = emitOnTimeout = emitOnEnd = NULL;
266 preEvent = postEvent = onEvent = onEnd = NULL;
267 subprocess = NULL;
268 preEvents = postEvents = onEvents = onEnds = subprocesses = 0;
269 pendIOTime = 10;
270
271 for (i_arg = 1; i_arg < argc; i_arg++) {
272 if (s_arg[i_arg].arg_type == OPTION) {
273 delete_chars(s_arg[i_arg].list[0], (char *)"_");
274 switch (code = match_string(s_arg[i_arg].list[0], commandline_option, COMMANDLINE_OPTIONS, 0)) {
275 case CLO_INTERVAL:
276 if (s_arg[i_arg].n_items != 2 ||
277 sscanf(s_arg[i_arg].list[1], "%lf", &interval) != 1 ||
278 interval <= 0)
279 SDDS_Bomb((char *)"invalid -interval syntax/value");
280 break;
281 case CLO_TIMELIMIT:
282 if (s_arg[i_arg].n_items != 2 ||
283 sscanf(s_arg[i_arg].list[1], "%lf", &timeLimit) != 1 ||
284 timeLimit <= 0)
285 SDDS_Bomb((char *)"invalid -timeLimit syntax/value");
286 break;
287 case CLO_WAITFOR:
288 if (s_arg[i_arg].n_items < 3)
289 SDDS_Bomb((char *)"invalid -waitFor syntax");
290 waitFor = (WAITFOR *)trealloc(waitFor, sizeof(*waitFor) * (waitFors + 1));
291 waitFor[waitFors].PVname = s_arg[i_arg].list[1];
292 s_arg[i_arg].n_items -= 2;
293 if (!scanItemList(&waitFor[waitFors].flags, s_arg[i_arg].list + 2, &s_arg[i_arg].n_items, 0,
294 "lowerlimit", SDDS_DOUBLE, &waitFor[waitFors].lowerLimit, 1, LOWERLIMIT_GIVEN,
295 "upperlimit", SDDS_DOUBLE, &waitFor[waitFors].upperLimit, 1, UPPERLIMIT_GIVEN,
296 "above", SDDS_DOUBLE, &waitFor[waitFors].above, 1, ABOVE_GIVEN,
297 "below", SDDS_DOUBLE, &waitFor[waitFors].below, 1, BELOW_GIVEN,
298 "equal", SDDS_DOUBLE, &waitFor[waitFors].equalTo, 1, EQUALTO_GIVEN,
299 "sameas", SDDS_STRING, &waitFor[waitFors].sameAs, 1, SAME_AS_GIVEN,
300 "changed", -1, NULL, 0, CHANGED_GIVEN,
301 "monitor", -1, NULL, 0, MONITOR_GIVEN,
302 NULL) ||
303 !waitFor[waitFors].flags ||
304 (waitFor[waitFors].flags & LOWERLIMIT_GIVEN && !(waitFor[waitFors].flags & UPPERLIMIT_GIVEN)) ||
305 (!(waitFor[waitFors].flags & LOWERLIMIT_GIVEN) && waitFor[waitFors].flags & UPPERLIMIT_GIVEN) ||
306 (waitFor[waitFors].flags & LOWERLIMIT_GIVEN &&
307 waitFor[waitFors].lowerLimit >= waitFor[waitFors].upperLimit) ||
308 (waitFor[waitFors].flags & SAME_AS_GIVEN && waitFor[waitFors].flags & (~SAME_AS_GIVEN)))
309 SDDS_Bomb((char *)"invalid -waitFor syntax/values");
310 waitFor[waitFors].operations = 0;
311 waitFor[waitFors].operation = NULL;
312 waitFor[waitFors].changeReferenceLoaded = 0;
313 waitFors++;
314 s_arg[i_arg].n_items += 2;
315 break;
316 case CLO_EZCATIMING:
317 break;
318 case CLO_USEMONITOR:
319 //useMonitor = 1;
320 break;
321 case CLO_NOWARN:
322 noWarnings = 1;
323 break;
324 case CLO_NOT:
325 case CLO_OR:
326 case CLO_AND:
327 if (waitFors < 1 && code == CLO_NOT)
328 SDDS_Bomb((char *)"invalid syntax---give a -waitFor option before -not");
329 if (waitFors < 2 && code != CLO_NOT)
330 SDDS_Bomb((char *)"invalid syntax---give at least two -waitFor options before -or or -and");
331 waitFor[waitFors - 1].operation = (short *)SDDS_Realloc(waitFor[waitFors - 1].operation,
332 sizeof(*waitFor[waitFors - 1].operation) * (waitFor[waitFors - 1].operations + 1));
333 waitFor[waitFors - 1].operation[waitFor[waitFors - 1].operations] = code;
334 waitFor[waitFors - 1].operations++;
335 break;
336 case CLO_REPEAT:
337 if (s_arg[i_arg].n_items == 1)
338 repeats = 0; /* indefinite number of repeats */
339 else if (s_arg[i_arg].n_items != 2 ||
340 sscanf(s_arg[i_arg].list[1], "%ld", &repeats) != 1 ||
341 repeats < 1)
342 SDDS_Bomb((char *)"invalid -repeats syntax/value");
343 break;
344 case CLO_EMIT:
345 s_arg[i_arg].n_items -= 1;
346 if (!scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
347 "event", SDDS_STRING, &emitOnEvent, 1, EMIT_EVENT_GIVEN,
348 "timeout", SDDS_STRING, &emitOnTimeout, 1, EMIT_TIMEOUT_GIVEN,
349 "end", SDDS_STRING, &emitOnEnd, 1, EMIT_END_GIVEN,
350 NULL) ||
351 !(flags & EMIT_EVENT_GIVEN))
352 SDDS_Bomb((char *)"invalid -emit syntax/values");
353 s_arg[i_arg].n_items += 1;
354 break;
355 case CLO_PREEVENT:
356 if (s_arg[i_arg].n_items != 2)
357 SDDS_Bomb((char *)"invalid -preEvent syntax");
358 if (!(preEvent = (char **)SDDS_Realloc(preEvent, sizeof(*preEvent) * (preEvents + 1))))
359 SDDS_Bomb((char *)"allocation failure");
360 preEvent[preEvents] = s_arg[i_arg].list[1];
361 preEvents++;
362 break;
363 case CLO_POSTEVENT:
364 if (s_arg[i_arg].n_items != 2)
365 SDDS_Bomb((char *)"invalid -postEvent syntax");
366 if (!(postEvent = (char **)SDDS_Realloc(postEvent, sizeof(*postEvent) * (postEvents + 1))))
367 SDDS_Bomb((char *)"allocation failure");
368 postEvent[postEvents] = s_arg[i_arg].list[1];
369 postEvents++;
370 break;
371 case CLO_SUBPROCESS:
372 if (s_arg[i_arg].n_items < 2)
373 SDDS_Bomb((char *)"invalid -subprocess syntax");
374 if (!(subprocess = (SUBPROCESS *)SDDS_Realloc(subprocess, sizeof(*subprocess) * (subprocesses + 1))))
375 SDDS_Bomb((char *)"allocation failure");
376 subprocess[subprocesses].command = s_arg[i_arg].list[1];
377 s_arg[i_arg].n_items -= 2;
378 if (!scanItemList(&flags, s_arg[i_arg].list + 2, &s_arg[i_arg].n_items, 0,
379 "event", SDDS_STRING, &subprocess[subprocesses].emitOnEvent, 1, EMIT_EVENT_GIVEN,
380 "timeout", SDDS_STRING, &subprocess[subprocesses].emitOnTimeout, 1, EMIT_TIMEOUT_GIVEN,
381 "end", SDDS_STRING, &subprocess[subprocesses].emitOnEnd, 1, EMIT_END_GIVEN,
382 NULL) ||
383 !(flags & EMIT_EVENT_GIVEN))
384 SDDS_Bomb((char *)"invalid -subprocess syntax/values");
385 subprocess[subprocesses].fp = NULL;
386 subprocesses++;
387 s_arg[i_arg].n_items += 2;
388 break;
389 case CLO_ONEVENT:
390 if (s_arg[i_arg].n_items != 2)
391 SDDS_Bomb((char *)"invalid -onEvent syntax");
392 if (!(onEvent = (char **)SDDS_Realloc(onEvent, sizeof(*onEvent) * (onEvents + 1))))
393 SDDS_Bomb((char *)"allocation failure");
394 onEvent[onEvents] = s_arg[i_arg].list[1];
395 onEvents++;
396 break;
397 case CLO_ONEND:
398 if (s_arg[i_arg].n_items != 2)
399 SDDS_Bomb((char *)"invalid -onEnd syntax");
400 if (!(onEnd = (char **)SDDS_Realloc(onEnd, sizeof(*onEnd) * (onEnds + 1))))
401 SDDS_Bomb((char *)"allocation failure");
402 onEnd[onEnds] = s_arg[i_arg].list[1];
403 onEnds++;
404 break;
405 case CLO_TOTALTIMELIMIT:
406 if (s_arg[i_arg].n_items != 2 ||
407 sscanf(s_arg[i_arg].list[1], "%lf", &totalTimeLimit) != 1 ||
408 totalTimeLimit <= 0)
409 SDDS_Bomb((char *)"invalid -totalTimeLimit syntax/value");
410 break;
411 case CLO_PENDIOTIME:
412 if (s_arg[i_arg].n_items != 2)
413 bomb((char *)"wrong number of items for -pendIoTime", NULL);
414 if (sscanf(s_arg[i_arg].list[1], "%lf", &pendIOTime) != 1 ||
415 pendIOTime <= 0)
416 bomb((char *)"invalid -pendIoTime value (cawait)", NULL);
417 break;
418 case CLO_PROVIDER:
419 if (s_arg[i_arg].n_items != 2)
420 SDDS_Bomb((char *)"no value given for option -provider");
421 if ((providerMode = match_string(s_arg[i_arg].list[1], providerOption,
422 PROVIDER_COUNT, 0)) < 0)
423 SDDS_Bomb((char *)"invalid -provider");
424 break;
425 default:
426 SDDS_Bomb((char *)"unknown option");
427 break;
428 }
429 } else
430 SDDS_Bomb((char *)"unknown option");
431 }
432
433 if (!waitFors)
434 SDDS_Bomb((char *)"-waitFor option must be given at least once");
435 if (providerMode == PROVIDER_PVA) {
436#if (EPICS_VERSION > 3)
437 //Allocate memory for pva structure
438 allocPVA(&pva, waitFors, 0);
439 //List PV names
440 epics::pvData::shared_vector<std::string> names(pva.numPVs);
441 epics::pvData::shared_vector<std::string> provider(pva.numPVs);
442 for (j = 0; j < pva.numPVs; j++) {
443 if (strncmp(waitFor[j].PVname, "pva://", 6) == 0) {
444 waitFor[j].PVname += 6;
445 names[j] = waitFor[j].PVname;
446 waitFor[j].PVname -= 6;
447 provider[j] = "pva";
448 } else if (strncmp(waitFor[j].PVname, "ca://", 5) == 0) {
449 waitFor[j].PVname += 5;
450 names[j] = waitFor[j].PVname;
451 waitFor[j].PVname -= 5;
452 provider[j] = "ca";
453 } else {
454 names[j] = waitFor[j].PVname;
455 provider[j] = "pva";
456 }
457 }
458 pva.pvaChannelNames = freeze(names);
459 pva.pvaProvider = freeze(provider);
460 //Connect to PVs
461 ConnectPVA(&pva, pendIOTime);
462
463 for (j = 0; j < pva.numPVs; j++) {
464 if (!pva.isConnected[j]) {
465 fprintf(stderr, "Error (cawait): problem doing search for %s\n", waitFor[j].PVname);
466 return (EXIT_FAILURE);
467 }
468 }
469 //Get initial values
470 if (GetPVAValues(&pva) == 1) {
471 return (EXIT_FAILURE);
472 }
473 if (MonitorPVAValues(&pva) == 1) {
474 return (EXIT_FAILURE);
475 }
476 epicsThreadSleep(.1);
477 if (PollMonitoredPVA(&pva)) {
478 //fprintf(stderr, "something changed\n");
479 }
480#else
481 fprintf(stderr, "-provider=pva is only available with newer versions of EPICS\n");
482 return (EXIT_FAILURE);
483#endif
484 } else {
485 if (ca_task_initialize() != ECA_NORMAL) {
486 fprintf(stderr, "Error (cawait): problem initializing channel access\n");
487 return (EXIT_FAILURE);
488 }
489 ca_add_exception_event(oag_ca_exception_handler, NULL);
490
491 /* connect to all PVs */
492 for (j = 0; j < waitFors; j++) {
493 if (ca_search(waitFor[j].PVname, &waitFor[j].channelID) != ECA_NORMAL) {
494 fprintf(stderr, "Error (cawait): problem doing search for %s\n",
495 waitFor[j].PVname);
496 ca_task_exit();
497 return (EXIT_FAILURE);
498 }
499 waitFor[j].usrValue = j;
500 }
501
502 ca_pend_io(pendIOTime);
503
504#ifdef DEBUG
505 fprintf(stderr, "Returned from ca_pend_io after ca_search calls\n");
506#endif
507
508 for (j = 0; j < waitFors; j++) {
509 if (ca_state(waitFor[j].channelID) != cs_conn) {
510 fprintf(stderr, "Error (cawait): no connection in time for %s\n",
511 waitFor[j].PVname);
512 ca_task_exit();
513 return (EXIT_FAILURE);
514 }
515 waitFor[j].eventSeen = -1;
516 if (!(waitFor[j].flags & SAME_AS_GIVEN)) {
517 waitFor[j].channelType = DBF_DOUBLE;
518 if (ca_add_masked_array_event(DBR_TIME_DOUBLE, 1, waitFor[j].channelID,
519 EventHandler, (void *)&waitFor[j].usrValue,
520 (ca_real)0, (ca_real)0, (ca_real)0,
521 NULL, DBE_VALUE) != ECA_NORMAL) {
522 fprintf(stderr, "error: unable to setup callback for PV %s\n", waitFor[j].PVname);
523 ca_task_exit();
524 return (EXIT_FAILURE);
525 }
526 } else {
527 waitFor[j].channelType = DBF_STRING;
528 if (ca_add_masked_array_event(DBR_TIME_STRING, 1, waitFor[j].channelID,
529 StringEventHandler, (void *)&waitFor[j].usrValue,
530 (ca_real)0, (ca_real)0, (ca_real)0,
531 NULL, DBE_VALUE) != ECA_NORMAL) {
532 fprintf(stderr, "error: unable to setup callback for PV %s\n", waitFor[j].PVname);
533 ca_task_exit();
534 return (EXIT_FAILURE);
535 }
536 }
537 }
538 if (ca_pend_io(pendIOTime) != ECA_NORMAL) {
539 fprintf(stderr, "Error (cawait): unable to setup callbacks for PVs\n");
540 ca_task_exit();
541 return (EXIT_FAILURE);
542 }
543#ifdef DEBUG
544 fprintf(stderr, "ca_pend_io called after ca_add_masked_array_event calls\n");
545#endif
546 }
547
548 /* initialize the subprocesses */
549 for (j = 0; j < subprocesses; j++) {
550 if (!(subprocess[j].fp = popen(subprocess[j].command, "w"))) {
551 fprintf(stderr, "Error (cawait): problem starting subprocess with command %s\n", subprocess[j].command);
552 if (providerMode != PROVIDER_PVA)
553 ca_task_exit();
554 return (EXIT_FAILURE);
555 }
556 }
557
558 startTime = getTimeInSecs();
559 if (totalTimeLimit > 0 && totalTimeLimit < timeLimit) {
560 timeLimit = totalTimeLimit;
561 }
562 eventEndPending = 0; /* indicates that the end of the last event is pending. */
563 do {
564#ifdef DEBUG
565 fprintf(stderr, "At top of main loop\n");
566#endif
567 terminateLoop = 0;
568 if (totalTimeLimit > 0 && ((getTimeInSecs() - startTime) > totalTimeLimit)) {
569 terminateLoop = 1;
570 }
571
572 if (!eventEndPending) {
573 if (!terminateLoop) {
574 /* execute pre-event commands */
575 for (j = 0; j < preEvents; j++) {
576 system(preEvent[j]);
577 }
578
579 if (providerMode == PROVIDER_PVA) {
580#if (EPICS_VERSION > 3)
581 /* wait for event to become true */
582 code = waitForEventPVA(&pva, timeLimit, interval, 0);
583#endif
584 } else {
585 code = waitForEvent(timeLimit, interval, 0);
586 }
587
588 if (code == LOGIC_ERROR) {
589 fputs("logic error---probably too few operators (cawait)\n", stderr);
590 if (providerMode != PROVIDER_PVA)
591 ca_task_exit();
592 return (EXIT_FAILURE);
593 }
594
595 /* emit messages to standard output, as requested */
596 if (emitOnEvent) {
597 switch (code) {
598 case EVENT:
599 puts(emitOnEvent);
600 fflush(stdout);
601 break;
602 case TIMEOUT:
603 if (emitOnTimeout) {
604 puts(emitOnTimeout);
605 fflush(stdout);
606 }
607 break;
608 default:
609 break;
610 }
611 }
612
613 /* emit messages to subprocesses, as requested */
614 for (j = 0; j < subprocesses; j++) {
615 switch (code) {
616 case EVENT:
617 fputs(subprocess[j].emitOnEvent, subprocess[j].fp);
618 fputc('\n', subprocess[j].fp);
619 fflush(subprocess[j].fp);
620 break;
621 case TIMEOUT:
622 if (subprocess[j].emitOnTimeout) {
623 fputs(subprocess[j].emitOnTimeout, subprocess[j].fp);
624 fputc('\n', subprocess[j].fp);
625 fflush(subprocess[j].fp);
626 }
627 break;
628 }
629 }
630
631 /* execute on-event commands */
632 if (code == EVENT) {
633 for (j = 0; j < onEvents; j++) {
634 system(onEvent[j]);
635 }
636 }
637 }
638 }
639
640 if (repeats == 1 || terminateLoop) {
641 if (!eventEndPending) {
642 /* last repeat */
643 if (emitOnEnd) {
644 /* emit end-of-run message to stdout */
645 puts(emitOnEnd);
646 fflush(stdout);
647 }
648 /* execute end-of-run commands */
649 for (j = 0; j < onEnds; j++) {
650 system(onEnd[j]);
651 }
652 /* emit end-of-run messages to subprocesses */
653 for (j = 0; j < subprocesses; j++) {
654 if (subprocess[j].emitOnEnd) {
655 fputs(subprocess[j].emitOnEnd, subprocess[j].fp);
656 fputc('\n', subprocess[j].fp);
657 fflush(subprocess[j].fp);
658 }
659 }
660#if (EPICS_VERSION > 3)
661 if (providerMode == PROVIDER_PVA)
662 freePVA(&pva);
663#endif
664 free_scanargs(&s_arg, argc);
665 if (terminateLoop || eventEndPending) {
666 if (providerMode != PROVIDER_PVA)
667 ca_task_exit();
668 return (EXIT_SUCCESS);
669 }
670 /* exit with error if non-event end */
671 return (code == EVENT ? 0 : 1);
672 }
673 }
674
675#ifdef DEBUG
676 fprintf(stderr, "Waiting for event\n");
677#endif
678 if (providerMode == PROVIDER_PVA) {
679#if (EPICS_VERSION > 3)
680 /* wait for event to become false */
681 code = waitForEventPVA(&pva, timeLimit, interval, 1);
682#endif
683 } else {
684 code = waitForEvent(timeLimit, interval, 1);
685 }
686 if (code == TIMEOUT) {
687 eventEndPending = 1;
688 if (!noWarnings) {
689 fprintf(stderr, "warning: timeout error waiting for event to clear (cawait)\n");
690 }
691 } else {
692 eventEndPending = 0;
693 /* execute post-event commands */
694 for (j = 0; j < postEvents; j++) {
695 system(postEvent[j]);
696 }
697 }
698 for (j = 0; j < waitFors; j++) {
699 waitFor[j].changeReferenceLoaded = 0;
700 }
701 } while (--repeats);
702
703 if (providerMode != PROVIDER_PVA)
704 ca_task_exit();
705
706 SDDS_Bomb((char *)"Abnormal exit from repeats loop--this shouldn't happen");
707 return (EXIT_FAILURE);
708}
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#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
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
double getTimeInSecs()
Get the current time in seconds since the Epoch with high resolution.
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.
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.

◆ oag_ca_exception_handler()

void oag_ca_exception_handler ( struct exception_handler_args args)

Definition at line 1017 of file cawait.cc.

1017 {
1018 char *pName;
1019 int severityInt;
1020 static const char *severity[] =
1021 {
1022 "Warning",
1023 "Success",
1024 "Error",
1025 "Info",
1026 "Fatal",
1027 "Fatal",
1028 "Fatal",
1029 "Fatal"};
1030
1031 severityInt = CA_EXTRACT_SEVERITY(args.stat);
1032
1033 if ((severityInt != 1) && (severityInt != 3)) {
1034 fprintf(stderr, "CA.Client.Exception................\n");
1035 fprintf(stderr, " %s: \"%s\"\n",
1036 severity[severityInt],
1037 ca_message(args.stat));
1038
1039 if (args.ctx) {
1040 fprintf(stderr, " Context: \"%s\"\n", args.ctx);
1041 }
1042 if (args.chid) {
1043 pName = (char *)ca_name(args.chid);
1044 fprintf(stderr, " Channel: \"%s\"\n", pName);
1045 fprintf(stderr, " Type: \"%s\"\n", dbr_type_to_text(args.type));
1046 }
1047 fprintf(stderr, "This sometimes indicates an IOC that is hung up.\n");
1048 _exit(EXIT_FAILURE);
1049 } else {
1050 fprintf(stdout, "CA.Client.Exception................\n");
1051 fprintf(stdout, " %s: \"%s\"\n",
1052 severity[severityInt],
1053 ca_message(args.stat));
1054
1055 if (args.ctx) {
1056 fprintf(stdout, " Context: \"%s\"\n", args.ctx);
1057 }
1058 if (args.chid) {
1059 pName = (char *)ca_name(args.chid);
1060 fprintf(stdout, " Channel: \"%s\"\n", pName);
1061 fprintf(stdout, " Type: \"%s\"\n", dbr_type_to_text(args.type));
1062 }
1063 }
1064}

◆ rpn_clear_stack()

void rpn_clear_stack ( )

Definition at line 959 of file cawait.cc.

959 {
960 rpn_lstackptr = 0;
961}

◆ rpn_log_and()

void rpn_log_and ( void )

Definition at line 991 of file cawait.cc.

991 {
992 if (!rpn_stack_test(rpn_lstackptr, 2, (char *)"logical", (char *)"rpn_log_and")) {
993 ca_task_exit();
994 exit(EXIT_FAILURE);
995 }
996 rpn_logicstack[rpn_lstackptr - 2] = (rpn_logicstack[rpn_lstackptr - 1] && rpn_logicstack[rpn_lstackptr - 2]);
997 rpn_lstackptr--;
998}

◆ rpn_log_not()

void rpn_log_not ( void )

Definition at line 1009 of file cawait.cc.

1009 {
1010 if (!rpn_stack_test(rpn_lstackptr, 1, (char *)"logical", (char *)"rpn_log_not")) {
1011 ca_task_exit();
1012 exit(EXIT_FAILURE);
1013 }
1014 rpn_logicstack[rpn_lstackptr - 1] = !rpn_logicstack[rpn_lstackptr - 1];
1015}

◆ rpn_log_or()

void rpn_log_or ( void )

Definition at line 1000 of file cawait.cc.

1000 {
1001 if (!rpn_stack_test(rpn_lstackptr, 2, (char *)"logical", (char *)"rpn_log_or")) {
1002 ca_task_exit();
1003 exit(EXIT_FAILURE);
1004 }
1005 rpn_logicstack[rpn_lstackptr - 2] = (rpn_logicstack[rpn_lstackptr - 1] || rpn_logicstack[rpn_lstackptr - 2]);
1006 rpn_lstackptr--;
1007}

◆ rpn_pop_log()

long rpn_pop_log ( long * logical)

Definition at line 971 of file cawait.cc.

971 {
972 if (rpn_lstackptr < 1) {
973 fputs("too few items on logical stack (rpn_pop_log)\n", stderr);
974 ca_task_exit();
975 exit(EXIT_FAILURE);
976 }
977 *logical = rpn_logicstack[--rpn_lstackptr];
978 return (1);
979}

◆ rpn_push_log()

long rpn_push_log ( long logical)

Definition at line 981 of file cawait.cc.

981 {
982 if (rpn_lstackptr == RPN_LOGICSTACKSIZE) {
983 fputs("stack overflow--logical stack size exceeded (rpn_push_log)\n", stderr);
984 ca_task_exit();
985 exit(EXIT_FAILURE);
986 }
987 rpn_logicstack[rpn_lstackptr++] = logical;
988 return (1);
989}

◆ rpn_stack_test()

long rpn_stack_test ( long stack_ptr,
long numneeded,
char * stackname,
char * caller )

Definition at line 963 of file cawait.cc.

963 {
964 if (stack_ptr < numneeded) {
965 fprintf(stderr, "too few items on %s stack (%s)\n", stackname, caller);
966 return 0;
967 }
968 return (1);
969}

◆ sleep_us()

void sleep_us ( unsigned int nusecs)

Definition at line 734 of file cawait.cc.

734 {
735 struct timeval tval;
736
737 tval.tv_sec = nusecs / 1000000;
738 tval.tv_usec = nusecs % 1000000;
739 select(0, NULL, NULL, NULL, &tval);
740}

◆ StringEventHandler()

void StringEventHandler ( struct event_handler_args event)

Definition at line 722 of file cawait.cc.

722 {
723 struct dbr_time_string *dbrValue;
724 long index;
725 index = *((long *)event.usr);
726 dbrValue = (struct dbr_time_string *)event.dbr;
727 sprintf(waitFor[index].stringValue, "%s", (char *)dbrValue->value);
728 if (waitFor[index].eventSeen == -1)
729 waitFor[index].eventSeen = 0;
730 else
731 waitFor[index].eventSeen = 1;
732}

◆ waitForEvent()

long waitForEvent ( double timeLimit,
double interval,
long invert )

Definition at line 748 of file cawait.cc.

749 {
750 double time0, timeNow;
751 long j, k, result, term;
752
753 time0 = getTimeInSecs();
754 if (timeLimit > 0)
755 timeLimit += time0;
756 timeNow = getTimeInSecs();
757 while (timeLimit < 0 || timeNow < timeLimit) {
758#ifdef DEBUG
759 fprintf(stderr, "At top of while loop in waitForEvent()\n");
760#endif
761 if (!hasStarted) {
762 for (j = 0; j < waitFors; j++) {
763 /* request data for all PVs */
764 if (ca_get(waitFor[j].channelType, waitFor[j].channelID,
765 (waitFor[j].channelType == DBF_DOUBLE ? (void *)&waitFor[j].value : (void *)&waitFor[j].stringValue)) != ECA_NORMAL) {
766 fprintf(stderr, "Error (cawait): problem doing ca_get for %s\n",
767 waitFor[j].PVname);
768 ca_task_exit();
769 exit(EXIT_FAILURE);
770 }
771 }
772 if (ca_pend_io(pendIOTime) != ECA_NORMAL) {
773 fprintf(stderr, "Error (cawait): problem doing ca_get for PVs\n");
774 ca_task_exit();
775 exit(EXIT_FAILURE);
776 }
777 hasStarted = 1;
778#ifdef DEBUG
779 for (j = 0; j < waitFors; j++) {
780 switch (waitFor[j].channelType) {
781 case DBF_DOUBLE:
782 fprintf(stderr, "Initial %s = %e\n", waitFor[j].PVname, waitFor[j].value);
783 break;
784 default:
785 fprintf(stderr, "Initial %s = %s\n", waitFor[j].PVname, waitFor[j].stringValue);
786 break;
787 }
788 }
789#endif
790 }
791 for (j = 0; j < waitFors; j++) {
792 if (waitFor[j].flags & CHANGED_GIVEN && !waitFor[j].changeReferenceLoaded) {
793 waitFor[j].changeReference = waitFor[j].value;
794 waitFor[j].changeReferenceLoaded = 1;
795 }
796 }
797 rpn_clear_stack();
798 for (j = 0; j < waitFors; j++) {
799 term = 1;
800 if (waitFor[j].flags & SAME_AS_GIVEN) {
801 term = !strcmp(waitFor[j].stringValue, waitFor[j].sameAs);
802 } else if (waitFor[j].flags & EQUALTO_GIVEN) {
803 if (waitFor[j].value != waitFor[j].equalTo)
804 term = 0;
805 } else if (waitFor[j].flags & (LOWERLIMIT_GIVEN + UPPERLIMIT_GIVEN)) {
806 if (waitFor[j].value < waitFor[j].lowerLimit ||
807 waitFor[j].value > waitFor[j].upperLimit)
808 term = 0;
809 } else if (waitFor[j].flags & ABOVE_GIVEN) {
810 if (waitFor[j].value <= waitFor[j].above)
811 term = 0;
812 } else if (waitFor[j].flags & BELOW_GIVEN) {
813 if (waitFor[j].value >= waitFor[j].below)
814 term = 0;
815 } else if (waitFor[j].flags & CHANGED_GIVEN) {
816 if (waitFor[j].value == waitFor[j].changeReference)
817 term = 0;
818 else
819 waitFor[j].changeReference = waitFor[j].value;
820 } else if (waitFor[j].flags & MONITOR_GIVEN) {
821 if (waitFor[j].eventSeen == 1) {
822 waitFor[j].eventSeen = 0;
823 } else {
824 term = 0;
825 }
826 } else {
827 fprintf(stderr, "no flags set for PV %s--this shouldn't happen\n",
828 waitFor[j].PVname);
829 ca_task_exit();
830 exit(EXIT_FAILURE);
831 }
832 rpn_push_log(term);
833 for (k = 0; k < waitFor[j].operations; k++) {
834 switch (waitFor[j].operation[k]) {
835 case OP_NOT:
836 rpn_log_not();
837 break;
838 case OP_OR:
839 rpn_log_or();
840 break;
841 case OP_AND:
842 rpn_log_and();
843 break;
844 default:
845 ca_task_exit();
846 SDDS_Bomb((char *)"invalid operation seen---this shouldn't happen");
847 break;
848 }
849 }
850 }
851 rpn_pop_log(&result);
852 if (rpn_lstackptr != 0)
853 return LOGIC_ERROR;
854 if (invert)
855 result = !result;
856 if (result)
857 return EVENT;
858#ifdef DEBUG
859 fprintf(stderr, "At bottom of while loop in waitForEvent(). Calling ca_pend_event().\n");
860#endif
861 ca_pend_event(interval);
862 timeNow = getTimeInSecs();
863 }
864 return TIMEOUT;
865}