79#include <epicsVersion.h>
80#if (EPICS_VERSION > 3)
82# include "pv/thread.h"
87#include "match_string.h"
92#define CLO_EZCATIMING 2
93#define CLO_TIMELIMIT 3
94#define CLO_USEMONITOR 4
100#define CLO_PREEVENT 10
101#define CLO_POSTEVENT 11
102#define CLO_SUBPROCESS 12
103#define CLO_ONEVENT 13
105#define CLO_TOTALTIMELIMIT 15
106#define CLO_PENDIOTIME 16
108#define CLO_PROVIDER 18
109#define COMMANDLINE_OPTIONS 19
110char *commandline_option[COMMANDLINE_OPTIONS] = {
111 (
char *)
"interval", (
char *)
"waitfor", (
char *)
"ezcatiming",
112 (
char *)
"timelimit", (
char *)
"usemonitor", (
char *)
"not",
113 (
char *)
"or", (
char *)
"and", (
char *)
"repeat", (
char *)
"emit",
114 (
char *)
"preevent", (
char *)
"postevent", (
char *)
"subprocess",
115 (
char *)
"onevent", (
char *)
"onend", (
char *)
"totaltimelimit",
116 (
char *)
"pendiotime", (
char *)
"nowarnings", (
char *)
"provider"};
119#define PROVIDER_PVA 1
120#define PROVIDER_COUNT 2
121char *providerOption[PROVIDER_COUNT] = {
126static char *USAGE = (
char *)
128 " [-interval=<seconds>]\n"
129 " [-timeLimit=<seconds>]\n"
130 " [-totalTimeLimit=<seconds>]\n"
131 " -waitFor=<PVname>[,lowerLimit=<value>,upperLimit=<value>]\n"
132 " [,equalTo=<value>][,sameAs=<string>][,above=<value>]\n"
133 " [,below=<value>][,changed][,monitor]\n"
134 " [{-and | -or | -not}]\n"
135 " [-repeat[=<number>]]\n"
136 " [-emit=event=<string>[,timeout=<string>][,end=<string>]]\n"
137 " [-preEvent=<command>]\n"
138 " [-onEvent=<command>]\n"
139 " [-postEvent=<command>]\n"
140 " [-onEnd=<command>]\n"
141 " [-subprocess=<command>[,event=<string>][,timeout=<string>][,end=<string>]]\n"
142 " [-pendIOTime=<seconds>]\n"
144 " [-provider={ca|pva}]\n"
146 "Description of options:\n"
147 " -interval Specifies interval between checking PVs (default: 0.1 s).\n"
148 " Uses monitors, so it doesn’t load the IOCs.\n"
149 " -timeLimit Specifies maximum time to wait (default: infinite).\n"
150 " -totalTimeLimit Specifies the maximum runtime of cawait (default: infinite).\n"
151 " -waitFor Specifies PV name and criteria for ending wait.\n"
152 " Each occurrence pushes a result on the logic stack.\n"
153 " -and, -or, -not Performs operations on the logic stack.\n"
154 " -repeat Specifies the number of times to wait for the event (default: 1).\n"
155 " If no qualifiers, defaults to infinite. Event condition must\n"
156 " become false to start a new event.\n"
157 " -emit Specifies strings to emit to stdout when the event condition,\n"
158 " a timeout, or the specified number of events is detected.\n"
159 " -preEvent Command executed before waiting for the event.\n"
160 " -onEvent Command executed when the event occurs.\n"
161 " -postEvent Command executed after waiting for the event.\n"
162 " -onEnd Command executed after the final event is detected.\n"
163 " -subprocess Command executed on a pipe; optionally specifies messages for\n"
164 " events, timeouts, and end-of-run.\n"
165 " -pendIOTime Sets time (in seconds) allowed for CA operations.\n"
166 " -provider Specifies the provider (default: ca - channel access).\n"
168 "Program by Michael Borland and Robert Soliday, ANL/APS (" EPICS_VERSION_STRING
", " __DATE__
")";
170#define LOWERLIMIT_GIVEN 0x00001U
171#define UPPERLIMIT_GIVEN 0x00002U
172#define EQUALTO_GIVEN 0x00004U
173#define ABOVE_GIVEN 0x00008U
174#define BELOW_GIVEN 0x00010U
175#define SAME_AS_GIVEN 0x00020U
176#define CHANGED_GIVEN 0x00040U
177#define MONITOR_GIVEN 0x00080U
179#define OP_NOT CLO_NOT
181#define OP_AND CLO_AND
188 double lowerLimit, upperLimit, equalTo;
189 double above, below, changeReference;
196 char stringValue[256];
198 short changeReferenceLoaded;
204 char *emitOnEvent, *emitOnTimeout, *emitOnEnd;
208#define EMIT_EVENT_GIVEN 0x0001U
209#define EMIT_TIMEOUT_GIVEN 0x0002U
210#define EMIT_END_GIVEN 0x0004U
215long waitForEvent(
double timeLimit,
double interval,
217long rpn_stack_test(
long stack_ptr,
long numneeded,
char *stackname,
char *caller);
218long rpn_pop_log(
long *logical);
219long rpn_push_log(
long logical);
220void rpn_log_and(
void);
221void rpn_log_or(
void);
222void rpn_log_not(
void);
223void rpn_clear_stack();
224void EventHandler(
struct event_handler_args event);
225void StringEventHandler(
struct event_handler_args event);
226void oag_ca_exception_handler(
struct exception_handler_args args);
233#if (EPICS_VERSION > 3)
234long waitForEventPVA(
PVA_OVERALL *pva,
double timeLimit,
double interval,
long invert);
237int main(
int argc,
char **argv) {
238 long i_arg, j, terminateLoop;
241 double interval, timeLimit, totalTimeLimit, startTime;
243 long code = 0, repeats, eventEndPending;
244 char *emitOnEvent, *emitOnTimeout, *emitOnEnd;
245 char **preEvent, **postEvent, **onEvent, **onEnd;
247 long preEvents, postEvents, onEvents, onEnds, subprocesses;
249 long providerMode = 0;
250#if (EPICS_VERSION > 3)
255 argc =
scanargs(&s_arg, argc, argv);
262 timeLimit = totalTimeLimit = -1;
265 emitOnEvent = emitOnTimeout = emitOnEnd = NULL;
266 preEvent = postEvent = onEvent = onEnd = NULL;
268 preEvents = postEvents = onEvents = onEnds = subprocesses = 0;
271 for (i_arg = 1; i_arg < argc; i_arg++) {
272 if (s_arg[i_arg].arg_type == OPTION) {
274 switch (code =
match_string(s_arg[i_arg].list[0], commandline_option, COMMANDLINE_OPTIONS, 0)) {
276 if (s_arg[i_arg].n_items != 2 ||
277 sscanf(s_arg[i_arg].list[1],
"%lf", &interval) != 1 ||
279 SDDS_Bomb((
char *)
"invalid -interval syntax/value");
282 if (s_arg[i_arg].n_items != 2 ||
283 sscanf(s_arg[i_arg].list[1],
"%lf", &timeLimit) != 1 ||
285 SDDS_Bomb((
char *)
"invalid -timeLimit syntax/value");
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,
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;
314 s_arg[i_arg].n_items += 2;
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++;
337 if (s_arg[i_arg].n_items == 1)
339 else if (s_arg[i_arg].n_items != 2 ||
340 sscanf(s_arg[i_arg].list[1],
"%ld", &repeats) != 1 ||
342 SDDS_Bomb((
char *)
"invalid -repeats syntax/value");
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,
351 !(flags & EMIT_EVENT_GIVEN))
352 SDDS_Bomb((
char *)
"invalid -emit syntax/values");
353 s_arg[i_arg].n_items += 1;
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))))
360 preEvent[preEvents] = s_arg[i_arg].list[1];
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))))
368 postEvent[postEvents] = s_arg[i_arg].list[1];
372 if (s_arg[i_arg].n_items < 2)
373 SDDS_Bomb((
char *)
"invalid -subprocess syntax");
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,
383 !(flags & EMIT_EVENT_GIVEN))
384 SDDS_Bomb((
char *)
"invalid -subprocess syntax/values");
385 subprocess[subprocesses].fp = NULL;
387 s_arg[i_arg].n_items += 2;
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))))
394 onEvent[onEvents] = s_arg[i_arg].list[1];
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))))
402 onEnd[onEnds] = s_arg[i_arg].list[1];
405 case CLO_TOTALTIMELIMIT:
406 if (s_arg[i_arg].n_items != 2 ||
407 sscanf(s_arg[i_arg].list[1],
"%lf", &totalTimeLimit) != 1 ||
409 SDDS_Bomb((
char *)
"invalid -totalTimeLimit syntax/value");
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 ||
416 bomb((
char *)
"invalid -pendIoTime value (cawait)", NULL);
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)
434 SDDS_Bomb((
char *)
"-waitFor option must be given at least once");
435 if (providerMode == PROVIDER_PVA) {
436#if (EPICS_VERSION > 3)
438 allocPVA(&pva, waitFors, 0);
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;
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;
454 names[j] = waitFor[j].PVname;
458 pva.pvaChannelNames = freeze(names);
459 pva.pvaProvider = freeze(provider);
461 ConnectPVA(&pva, pendIOTime);
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);
470 if (GetPVAValues(&pva) == 1) {
471 return (EXIT_FAILURE);
473 if (MonitorPVAValues(&pva) == 1) {
474 return (EXIT_FAILURE);
476 epicsThreadSleep(.1);
477 if (PollMonitoredPVA(&pva)) {
481 fprintf(stderr,
"-provider=pva is only available with newer versions of EPICS\n");
482 return (EXIT_FAILURE);
485 if (ca_task_initialize() != ECA_NORMAL) {
486 fprintf(stderr,
"Error (cawait): problem initializing channel access\n");
487 return (EXIT_FAILURE);
489 ca_add_exception_event(oag_ca_exception_handler, NULL);
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",
497 return (EXIT_FAILURE);
499 waitFor[j].usrValue = j;
502 ca_pend_io(pendIOTime);
505 fprintf(stderr,
"Returned from ca_pend_io after ca_search calls\n");
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",
513 return (EXIT_FAILURE);
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);
524 return (EXIT_FAILURE);
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);
534 return (EXIT_FAILURE);
538 if (ca_pend_io(pendIOTime) != ECA_NORMAL) {
539 fprintf(stderr,
"Error (cawait): unable to setup callbacks for PVs\n");
541 return (EXIT_FAILURE);
544 fprintf(stderr,
"ca_pend_io called after ca_add_masked_array_event calls\n");
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)
554 return (EXIT_FAILURE);
559 if (totalTimeLimit > 0 && totalTimeLimit < timeLimit) {
560 timeLimit = totalTimeLimit;
565 fprintf(stderr,
"At top of main loop\n");
568 if (totalTimeLimit > 0 && ((
getTimeInSecs() - startTime) > totalTimeLimit)) {
572 if (!eventEndPending) {
573 if (!terminateLoop) {
575 for (j = 0; j < preEvents; j++) {
579 if (providerMode == PROVIDER_PVA) {
580#if (EPICS_VERSION > 3)
582 code = waitForEventPVA(&pva, timeLimit, interval, 0);
585 code = waitForEvent(timeLimit, interval, 0);
588 if (code == LOGIC_ERROR) {
589 fputs(
"logic error---probably too few operators (cawait)\n", stderr);
590 if (providerMode != PROVIDER_PVA)
592 return (EXIT_FAILURE);
614 for (j = 0; j < subprocesses; j++) {
617 fputs(subprocess[j].emitOnEvent, subprocess[j].fp);
618 fputc(
'\n', subprocess[j].fp);
619 fflush(subprocess[j].fp);
622 if (subprocess[j].emitOnTimeout) {
623 fputs(subprocess[j].emitOnTimeout, subprocess[j].fp);
624 fputc(
'\n', subprocess[j].fp);
625 fflush(subprocess[j].fp);
633 for (j = 0; j < onEvents; j++) {
640 if (repeats == 1 || terminateLoop) {
641 if (!eventEndPending) {
649 for (j = 0; j < onEnds; j++) {
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);
660#if (EPICS_VERSION > 3)
661 if (providerMode == PROVIDER_PVA)
665 if (terminateLoop || eventEndPending) {
666 if (providerMode != PROVIDER_PVA)
668 return (EXIT_SUCCESS);
671 return (code == EVENT ? 0 : 1);
676 fprintf(stderr,
"Waiting for event\n");
678 if (providerMode == PROVIDER_PVA) {
679#if (EPICS_VERSION > 3)
681 code = waitForEventPVA(&pva, timeLimit, interval, 1);
684 code = waitForEvent(timeLimit, interval, 1);
686 if (code == TIMEOUT) {
689 fprintf(stderr,
"warning: timeout error waiting for event to clear (cawait)\n");
694 for (j = 0; j < postEvents; j++) {
695 system(postEvent[j]);
698 for (j = 0; j < waitFors; j++) {
699 waitFor[j].changeReferenceLoaded = 0;
703 if (providerMode != PROVIDER_PVA)
706 SDDS_Bomb((
char *)
"Abnormal exit from repeats loop--this shouldn't happen");
707 return (EXIT_FAILURE);
710void EventHandler(
struct event_handler_args event) {
711 struct dbr_time_double *dbrValue;
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;
719 waitFor[index].eventSeen = 1;
722void StringEventHandler(
struct event_handler_args event) {
723 struct dbr_time_string *dbrValue;
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;
731 waitFor[index].eventSeen = 1;
734void sleep_us(
unsigned int nusecs) {
737 tval.tv_sec = nusecs / 1000000;
738 tval.tv_usec = nusecs % 1000000;
739 select(0, NULL, NULL, NULL, &tval);
742#define RPN_LOGICSTACKSIZE 500
745short rpn_logicstack[RPN_LOGICSTACKSIZE];
746long rpn_lstackptr = 0;
748long waitForEvent(
double timeLimit,
double interval,
750 double time0, timeNow;
751 long j, k, result, term;
757 while (timeLimit < 0 || timeNow < timeLimit) {
759 fprintf(stderr,
"At top of while loop in waitForEvent()\n");
762 for (j = 0; j < waitFors; j++) {
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",
772 if (ca_pend_io(pendIOTime) != ECA_NORMAL) {
773 fprintf(stderr,
"Error (cawait): problem doing ca_get for PVs\n");
779 for (j = 0; j < waitFors; j++) {
780 switch (waitFor[j].channelType) {
782 fprintf(stderr,
"Initial %s = %e\n", waitFor[j].PVname, waitFor[j].value);
785 fprintf(stderr,
"Initial %s = %s\n", waitFor[j].PVname, waitFor[j].stringValue);
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;
798 for (j = 0; j < waitFors; j++) {
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)
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)
809 }
else if (waitFor[j].flags & ABOVE_GIVEN) {
810 if (waitFor[j].value <= waitFor[j].above)
812 }
else if (waitFor[j].flags & BELOW_GIVEN) {
813 if (waitFor[j].value >= waitFor[j].below)
815 }
else if (waitFor[j].flags & CHANGED_GIVEN) {
816 if (waitFor[j].value == waitFor[j].changeReference)
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;
827 fprintf(stderr,
"no flags set for PV %s--this shouldn't happen\n",
833 for (k = 0; k < waitFor[j].operations; k++) {
834 switch (waitFor[j].operation[k]) {
846 SDDS_Bomb((
char *)
"invalid operation seen---this shouldn't happen");
851 rpn_pop_log(&result);
852 if (rpn_lstackptr != 0)
859 fprintf(stderr,
"At bottom of while loop in waitForEvent(). Calling ca_pend_event().\n");
861 ca_pend_event(interval);
867#if (EPICS_VERSION > 3)
868long waitForEventPVA(
PVA_OVERALL *pva,
double timeLimit,
double interval,
long invert) {
869 double time0, timeNow;
870 long j, k, result, term;
875 while (timeLimit < 0 || timeNow < timeLimit) {
879 for (j = 0; j < waitFors; j++) {
880 if ((pva->isConnected[j]) && (pva->pvaData[j].fieldType == epics::pvData::scalar)) {
881 if (waitFor[j].flags & CHANGED_GIVEN && !waitFor[j].changeReferenceLoaded) {
882 waitFor[j].changeReference = pva->pvaData[j].getData[0].values[0];
883 waitFor[j].changeReferenceLoaded = 1;
889 for (j = 0; j < waitFors; j++) {
890 if ((pva->isConnected[j]) && (pva->pvaData[j].numMonitorReadings > 0)) {
891 if ((pva->pvaData[j].fieldType == epics::pvData::scalar)) {
893 if (waitFor[j].flags & SAME_AS_GIVEN) {
894 term = !strcmp(pva->pvaData[j].monitorData[0].stringValues[0], waitFor[j].sameAs);
895 }
else if (waitFor[j].flags & EQUALTO_GIVEN) {
896 if (pva->pvaData[j].monitorData[0].values[0] != waitFor[j].equalTo)
898 }
else if (waitFor[j].flags & (LOWERLIMIT_GIVEN + UPPERLIMIT_GIVEN)) {
899 if (pva->pvaData[j].monitorData[0].values[0] < waitFor[j].lowerLimit ||
900 pva->pvaData[j].monitorData[0].values[0] > waitFor[j].upperLimit)
902 }
else if (waitFor[j].flags & ABOVE_GIVEN) {
903 if (pva->pvaData[j].monitorData[0].values[0] <= waitFor[j].above)
905 }
else if (waitFor[j].flags & BELOW_GIVEN) {
906 if (pva->pvaData[j].monitorData[0].values[0] >= waitFor[j].below)
908 }
else if (waitFor[j].flags & CHANGED_GIVEN) {
909 if (pva->pvaData[j].monitorData[0].values[0] == waitFor[j].changeReference)
912 waitFor[j].changeReference = pva->pvaData[j].monitorData[0].values[0];
914 fprintf(stderr,
"no flags set for PV %s--this shouldn't happen\n", waitFor[j].PVname);
918 fprintf(stderr,
"error: cawait only works with scalar values.\n");
922 for (k = 0; k < waitFor[j].operations; k++) {
923 switch (waitFor[j].operation[k]) {
934 SDDS_Bomb((
char *)
"invalid operation seen---this shouldn't happen");
941 rpn_pop_log(&result);
942 if (rpn_lstackptr != 0)
949 epicsThreadSleep(interval);
950 if (PollMonitoredPVA(pva)) {
959void rpn_clear_stack() {
963long rpn_stack_test(
long stack_ptr,
long numneeded,
char *stackname,
char *caller) {
964 if (stack_ptr < numneeded) {
965 fprintf(stderr,
"too few items on %s stack (%s)\n", stackname, caller);
971long rpn_pop_log(
long *logical) {
972 if (rpn_lstackptr < 1) {
973 fputs(
"too few items on logical stack (rpn_pop_log)\n", stderr);
977 *logical = rpn_logicstack[--rpn_lstackptr];
981long rpn_push_log(
long logical) {
982 if (rpn_lstackptr == RPN_LOGICSTACKSIZE) {
983 fputs(
"stack overflow--logical stack size exceeded (rpn_push_log)\n", stderr);
987 rpn_logicstack[rpn_lstackptr++] = logical;
991void rpn_log_and(
void) {
992 if (!rpn_stack_test(rpn_lstackptr, 2, (
char *)
"logical", (
char *)
"rpn_log_and")) {
996 rpn_logicstack[rpn_lstackptr - 2] = (rpn_logicstack[rpn_lstackptr - 1] && rpn_logicstack[rpn_lstackptr - 2]);
1000void rpn_log_or(
void) {
1001 if (!rpn_stack_test(rpn_lstackptr, 2, (
char *)
"logical", (
char *)
"rpn_log_or")) {
1005 rpn_logicstack[rpn_lstackptr - 2] = (rpn_logicstack[rpn_lstackptr - 1] || rpn_logicstack[rpn_lstackptr - 2]);
1009void rpn_log_not(
void) {
1010 if (!rpn_stack_test(rpn_lstackptr, 1, (
char *)
"logical", (
char *)
"rpn_log_not")) {
1014 rpn_logicstack[rpn_lstackptr - 1] = !rpn_logicstack[rpn_lstackptr - 1];
1017void oag_ca_exception_handler(
struct exception_handler_args args) {
1020 static const char *severity[] =
1031 severityInt = CA_EXTRACT_SEVERITY(args.stat);
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));
1040 fprintf(stderr,
" Context: \"%s\"\n", args.ctx);
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));
1047 fprintf(stderr,
"This sometimes indicates an IOC that is hung up.\n");
1048 _exit(EXIT_FAILURE);
1050 fprintf(stdout,
"CA.Client.Exception................\n");
1051 fprintf(stdout,
" %s: \"%s\"\n",
1052 severity[severityInt],
1053 ca_message(args.stat));
1056 fprintf(stdout,
" Context: \"%s\"\n", args.ctx);
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));
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
#define SDDS_STRING
Identifier for the string 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.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
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.
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.