This is Unofficial EPICS BASE Doxygen Site
lnkCalc.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * EPICS BASE is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 /* lnkCalc.c */
8 
9 /* Usage
10  * {calc:{expr:"A*B", args:[{...}, ...], units:"mm"}}
11  * First link in 'args' is 'A', second is 'B', and so forth.
12  */
13 
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 
19 #include "alarm.h"
20 #include "dbDefs.h"
21 #include "errlog.h"
22 #include "epicsAssert.h"
23 #include "epicsString.h"
24 #include "epicsTypes.h"
25 #include "epicsTime.h"
26 #include "dbAccessDefs.h"
27 #include "dbCommon.h"
28 #include "dbConvertFast.h"
29 #include "dbLink.h"
30 #include "dbJLink.h"
31 #include "dbStaticLib.h"
32 #include "dbStaticPvt.h"
33 #include "postfix.h"
34 #include "recGbl.h"
35 #include "epicsExport.h"
36 
37 
38 typedef long (*FASTCONVERT)();
39 
40 typedef struct calc_link {
41  jlink jlink; /* embedded object */
42  int nArgs;
43  short dbfType;
44  enum {
52  } pstate;
55  short prec;
56  char *expr;
57  char *major;
58  char *minor;
59  char *post_expr;
60  char *post_major;
61  char *post_minor;
62  char *units;
63  short tinp;
65  struct link out;
68  double val;
69 } calc_link;
70 
71 static lset lnkCalc_lset;
72 
73 
74 /*************************** jlif Routines **************************/
75 
76 static jlink* lnkCalc_alloc(short dbfType)
77 {
78  calc_link *clink;
79 
80  if (dbfType == DBF_FWDLINK) {
81  errlogPrintf("lnkCalc: No support for forward links\n");
82  return NULL;
83  }
84 
85  clink = calloc(1, sizeof(struct calc_link));
86  if (!clink) {
87  errlogPrintf("lnkCalc: calloc() failed.\n");
88  return NULL;
89  }
90 
91  clink->nArgs = 0;
92  clink->dbfType = dbfType;
93  clink->pstate = ps_init;
94  clink->prec = 15; /* standard value for a double */
95  clink->tinp = -1;
96 
97  return &clink->jlink;
98 }
99 
100 static void lnkCalc_free(jlink *pjlink)
101 {
102  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
103  int i;
104 
105  for (i = 0; i < clink->nArgs; i++)
106  dbJLinkFree(clink->inp[i].value.json.jlink);
107 
108  dbJLinkFree(clink->out.value.json.jlink);
109 
110  free(clink->expr);
111  free(clink->major);
112  free(clink->minor);
113  free(clink->post_expr);
114  free(clink->post_major);
115  free(clink->post_minor);
116  free(clink->units);
117  free(clink);
118 }
119 
120 static jlif_result lnkCalc_integer(jlink *pjlink, long long num)
121 {
122  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
123 
124  if (clink->pstate == ps_prec) {
125  clink->prec = num;
126  return jlif_continue;
127  }
128 
129  if (clink->pstate != ps_args) {
130  errlogPrintf("lnkCalc: Unexpected integer %lld\n", num);
131  return jlif_stop;
132  }
133 
134  if (clink->nArgs == CALCPERFORM_NARGS) {
135  errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
137  return jlif_stop;
138  }
139 
140  clink->arg[clink->nArgs++] = num;
141 
142  return jlif_continue;
143 }
144 
145 static jlif_result lnkCalc_double(jlink *pjlink, double num)
146 {
147  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
148 
149  if (clink->pstate != ps_args) {
150  errlogPrintf("lnkCalc: Unexpected double %g\n", num);
151  return jlif_stop;
152  }
153 
154  if (clink->nArgs == CALCPERFORM_NARGS) {
155  errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
157  return jlif_stop;
158  }
159 
160  clink->arg[clink->nArgs++] = num;
161 
162  return jlif_continue;
163 }
164 
165 static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
166 {
167  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
168  char *inbuf, *postbuf;
169  short err;
170 
171  if (clink->pstate == ps_units) {
172  clink->units = epicsStrnDup(val, len);
173  return jlif_continue;
174  }
175 
176  if (clink->pstate == ps_time) {
177  char tinp;
178 
179  if (len != 1 || (tinp = toupper((int) val[0])) < 'A' || tinp > 'L') {
180  errlogPrintf("lnkCalc: Bad 'time' parameter \"%.*s\"\n", (int) len, val);
181  return jlif_stop;
182  }
183  clink->tinp = tinp - 'A';
184  return jlif_continue;
185  }
186 
187  if (clink->pstate < ps_expr || clink->pstate > ps_minor) {
188  errlogPrintf("lnkCalc: Unexpected string \"%.*s\"\n", (int) len, val);
189  return jlif_stop;
190  }
191 
192  postbuf = malloc(INFIX_TO_POSTFIX_SIZE(len+1));
193  if (!postbuf) {
194  errlogPrintf("lnkCalc: Out of memory\n");
195  return jlif_stop;
196  }
197 
198  inbuf = malloc(len+1);
199  if(!inbuf) {
200  errlogPrintf("lnkCalc: Out of memory\n");
201  free(postbuf);
202  return jlif_stop;
203  }
204  memcpy(inbuf, val, len);
205  inbuf[len] = '\0';
206 
207  if (clink->pstate == ps_major) {
208  clink->major = inbuf;
209  clink->post_major = postbuf;
210  }
211  else if (clink->pstate == ps_minor) {
212  clink->minor = inbuf;
213  clink->post_minor = postbuf;
214  }
215  else {
216  clink->expr = inbuf;
217  clink->post_expr = postbuf;
218  }
219 
220  if (postfix(inbuf, postbuf, &err) < 0) {
221  errlogPrintf("lnkCalc: Error in calc expression, %s\n",
222  calcErrorStr(err));
223  return jlif_stop;
224  }
225 
226  return jlif_continue;
227 }
228 
229 static jlif_key_result lnkCalc_start_map(jlink *pjlink)
230 {
231  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
232 
233  if (clink->pstate == ps_args)
234  return jlif_key_child_inlink;
235  if (clink->pstate == ps_out)
236  return jlif_key_child_outlink;
237 
238  if (clink->pstate != ps_init) {
239  errlogPrintf("lnkCalc: Unexpected map\n");
240  return jlif_key_stop;
241  }
242 
243  return jlif_key_continue;
244 }
245 
246 static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len)
247 {
248  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
249 
250  /* FIXME: These errors messages are wrong when a key is duplicated.
251  * The key is known, we just don't allow it more than once.
252  */
253 
254  if (len == 3) {
255  if (!strncmp(key, "out", len) &&
256  clink->dbfType == DBF_OUTLINK &&
257  clink->out.type == 0)
258  clink->pstate = ps_out;
259  else {
260  errlogPrintf("lnkCalc: Unknown key \"%.3s\"\n", key);
261  return jlif_stop;
262  }
263  }
264  else if (len == 4) {
265  if (!strncmp(key, "expr", len) && !clink->post_expr)
266  clink->pstate = ps_expr;
267  else if (!strncmp(key, "args", len) && !clink->nArgs)
268  clink->pstate = ps_args;
269  else if (!strncmp(key, "prec", len))
270  clink->pstate = ps_prec;
271  else if (!strncmp(key, "time", len))
272  clink->pstate = ps_time;
273  else {
274  errlogPrintf("lnkCalc: Unknown key \"%.4s\"\n", key);
275  return jlif_stop;
276  }
277  }
278  else if (len == 5) {
279  if (!strncmp(key, "major", len) && !clink->post_major)
280  clink->pstate = ps_major;
281  else if (!strncmp(key, "minor", len) && !clink->post_minor)
282  clink->pstate = ps_minor;
283  else if (!strncmp(key, "units", len) && !clink->units)
284  clink->pstate = ps_units;
285  else {
286  errlogPrintf("lnkCalc: Unknown key \"%.5s\"\n", key);
287  return jlif_stop;
288  }
289  }
290  else {
291  errlogPrintf("lnkCalc: Unknown key \"%.*s\"\n", (int) len, key);
292  return jlif_stop;
293  }
294 
295  return jlif_continue;
296 }
297 
298 static jlif_result lnkCalc_end_map(jlink *pjlink)
299 {
300  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
301 
302  if (clink->pstate == ps_error)
303  return jlif_stop;
304  else if (clink->dbfType == DBF_INLINK &&
305  !clink->post_expr) {
306  errlogPrintf("lnkCalc: No expression ('expr' key)\n");
307  return jlif_stop;
308  }
309  else if (clink->dbfType == DBF_OUTLINK &&
310  clink->out.type != JSON_LINK) {
311  errlogPrintf("lnkCalc: No output link ('out' key)\n");
312  return jlif_stop;
313  }
314 
315  return jlif_continue;
316 }
317 
318 static jlif_result lnkCalc_start_array(jlink *pjlink)
319 {
320  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
321 
322  if (clink->pstate != ps_args) {
323  errlogPrintf("lnkCalc: Unexpected array\n");
324  return jlif_stop;
325  }
326 
327  return jlif_continue;
328 }
329 
330 static jlif_result lnkCalc_end_array(jlink *pjlink)
331 {
332  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
333 
334  if (clink->pstate == ps_error)
335  return jlif_stop;
336 
337  return jlif_continue;
338 }
339 
340 static void lnkCalc_end_child(jlink *parent, jlink *child)
341 {
342  calc_link *clink = CONTAINER(parent, struct calc_link, jlink);
343  struct link *plink;
344 
345  if (clink->pstate == ps_args) {
346  if (clink->nArgs == CALCPERFORM_NARGS) {
347  errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
349  goto errOut;
350  }
351 
352  plink = &clink->inp[clink->nArgs++];
353  }
354  else if (clink->pstate == ps_out) {
355  plink = &clink->out;
356  }
357  else {
358  errlogPrintf("lnkCalc: Unexpected child link, parser state = %d\n",
359  clink->pstate);
360 errOut:
361  clink->pstate = ps_error;
362  dbJLinkFree(child);
363  return;
364  }
365 
366  plink->type = JSON_LINK;
367  plink->value.json.string = NULL;
368  plink->value.json.jlink = child;
369 }
370 
371 static struct lset* lnkCalc_get_lset(const jlink *pjlink)
372 {
373  return &lnkCalc_lset;
374 }
375 
376 static void lnkCalc_report(const jlink *pjlink, int level, int indent)
377 {
378  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
379  int i;
380 
381  printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "",
382  clink->expr, clink->prec, clink->val,
383  clink->units ? clink->units : "");
384 
385  if (level > 0) {
386  if (clink->sevr)
387  printf("%*s Alarm: %s, %s\n", indent, "",
390 
391  if (clink->post_major)
392  printf("%*s Major expression: \"%s\"\n", indent, "",
393  clink->major);
394  if (clink->post_minor)
395  printf("%*s Minor expression: \"%s\"\n", indent, "",
396  clink->minor);
397 
398  if (clink->tinp >= 0) {
399  char timeStr[40];
400  epicsTimeToStrftime(timeStr, 40, "%Y-%m-%d %H:%M:%S.%09f",
401  &clink->time);
402  printf("%*s Timestamp input %c: %s\n", indent, "",
403  clink->tinp + 'A', timeStr);
404  }
405 
406  for (i = 0; i < clink->nArgs; i++) {
407  struct link *plink = &clink->inp[i];
408  jlink *child = plink->type == JSON_LINK ?
409  plink->value.json.jlink : NULL;
410 
411  printf("%*s Input %c: %g\n", indent, "",
412  i + 'A', clink->arg[i]);
413 
414  if (child)
415  dbJLinkReport(child, level - 1, indent + 4);
416  }
417 
418  if (clink->out.type == JSON_LINK) {
419  printf("%*s Output:\n", indent, "");
420 
421  dbJLinkReport(clink->out.value.json.jlink, level - 1, indent + 4);
422  }
423  }
424 }
425 
426 static long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
427 {
428  calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
429  int i;
430 
431  for (i = 0; i < clink->nArgs; i++) {
432  struct link *child = &clink->inp[i];
433  long status = dbJLinkMapChildren(child, rtn, ctx);
434 
435  if (status)
436  return status;
437  }
438 
439  if (clink->out.type == JSON_LINK) {
440  return dbJLinkMapChildren(&clink->out, rtn, ctx);
441  }
442  return 0;
443 }
444 
445 /*************************** lset Routines **************************/
446 
447 static void lnkCalc_open(struct link *plink)
448 {
449  calc_link *clink = CONTAINER(plink->value.json.jlink,
450  struct calc_link, jlink);
451  int i;
452 
453  for (i = 0; i < clink->nArgs; i++) {
454  struct link *child = &clink->inp[i];
455 
456  child->precord = plink->precord;
457  dbJLinkInit(child);
458  dbLoadLink(child, DBR_DOUBLE, &clink->arg[i]);
459  }
460 
461  if (clink->out.type == JSON_LINK) {
462  dbJLinkInit(&clink->out);
463  }
464 }
465 
466 static void lnkCalc_remove(struct dbLocker *locker, struct link *plink)
467 {
468  calc_link *clink = CONTAINER(plink->value.json.jlink,
469  struct calc_link, jlink);
470  int i;
471 
472  for (i = 0; i < clink->nArgs; i++) {
473  struct link *child = &clink->inp[i];
474 
475  dbRemoveLink(locker, child);
476  }
477 
478  if (clink->out.type == JSON_LINK) {
479  dbRemoveLink(locker, &clink->out);
480  }
481 
482  free(clink->expr);
483  free(clink->major);
484  free(clink->minor);
485  free(clink->post_expr);
486  free(clink->post_major);
487  free(clink->post_minor);
488  free(clink->units);
489  free(clink);
490  plink->value.json.jlink = NULL;
491 }
492 
493 static int lnkCalc_isConn(const struct link *plink)
494 {
495  calc_link *clink = CONTAINER(plink->value.json.jlink,
496  struct calc_link, jlink);
497  int connected = 1;
498  int i;
499 
500  for (i = 0; i < clink->nArgs; i++) {
501  struct link *child = &clink->inp[i];
502 
503  if (dbLinkIsVolatile(child) &&
504  !dbIsLinkConnected(child))
505  connected = 0;
506  }
507 
508  if (clink->out.type == JSON_LINK) {
509  struct link *child = &clink->out;
510 
511  if (dbLinkIsVolatile(child) &&
512  !dbIsLinkConnected(child))
513  connected = 0;
514  }
515 
516  return connected;
517 }
518 
519 static int lnkCalc_getDBFtype(const struct link *plink)
520 {
521  return DBF_DOUBLE;
522 }
523 
524 static long lnkCalc_getElements(const struct link *plink, long *nelements)
525 {
526  *nelements = 1;
527  return 0;
528 }
529 
530 /* Get value and timestamp atomically for link indicated by time */
531 struct lcvt {
532  double *pval;
534 };
535 
536 static long readLocked(struct link *pinp, void *vvt)
537 {
538  struct lcvt *pvt = (struct lcvt *) vvt;
539  long nReq = 1;
540  long status = dbGetLink(pinp, DBR_DOUBLE, pvt->pval, NULL, &nReq);
541 
542  if (!status && pvt->ptime)
543  dbGetTimeStamp(pinp, pvt->ptime);
544 
545  return status;
546 }
547 
548 static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
549  long *pnRequest)
550 {
551  calc_link *clink = CONTAINER(plink->value.json.jlink,
552  struct calc_link, jlink);
553  dbCommon *prec = plink->precord;
554  int i;
555  long status;
556  FASTCONVERT conv;
557 
558  if(INVALID_DB_REQ(dbrType))
559  return S_db_badDbrtype;
560 
561  conv = dbFastPutConvertRoutine[DBR_DOUBLE][dbrType];
562 
563  /* Any link errors will trigger a LINK/INVALID alarm in the child link */
564  for (i = 0; i < clink->nArgs; i++) {
565  struct link *child = &clink->inp[i];
566  long nReq = 1;
567 
568  if (i == clink->tinp) {
569  struct lcvt vt = {&clink->arg[i], &clink->time};
570 
571  status = dbLinkDoLocked(child, readLocked, &vt);
572  if (status == S_db_noLSET)
573  status = readLocked(child, &vt);
574 
575  if (dbLinkIsConstant(&prec->tsel) &&
576  prec->tse == epicsTimeEventDeviceTime) {
577  prec->time = clink->time;
578  }
579  }
580  else
581  dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
582  }
583  clink->stat = 0;
584  clink->sevr = 0;
585 
586  if (clink->post_expr) {
587  status = calcPerform(clink->arg, &clink->val, clink->post_expr);
588  if (!status)
589  status = conv(&clink->val, pbuffer, NULL);
590  if (!status && pnRequest)
591  *pnRequest = 1;
592  }
593  else {
594  status = 0;
595  if (pnRequest)
596  *pnRequest = 0;
597  }
598 
599  if (!status && clink->post_major) {
600  double alval = clink->val;
601 
602  status = calcPerform(clink->arg, &alval, clink->post_major);
603  if (!status && alval) {
604  clink->stat = LINK_ALARM;
605  clink->sevr = MAJOR_ALARM;
606  recGblSetSevr(prec, clink->stat, clink->sevr);
607  }
608  }
609 
610  if (!status && !clink->sevr && clink->post_minor) {
611  double alval = clink->val;
612 
613  status = calcPerform(clink->arg, &alval, clink->post_minor);
614  if (!status && alval) {
615  clink->stat = LINK_ALARM;
616  clink->sevr = MINOR_ALARM;
617  recGblSetSevr(prec, clink->stat, clink->sevr);
618  }
619  }
620 
621  return status;
622 }
623 
624 static long lnkCalc_putValue(struct link *plink, short dbrType,
625  const void *pbuffer, long nRequest)
626 {
627  calc_link *clink = CONTAINER(plink->value.json.jlink,
628  struct calc_link, jlink);
629  dbCommon *prec = plink->precord;
630  int i;
631  long status;
632  FASTCONVERT conv;
633 
634  if(INVALID_DB_REQ(dbrType))
635  return S_db_badDbrtype;
636 
637  conv = dbFastGetConvertRoutine[dbrType][DBR_DOUBLE];
638 
639  /* Any link errors will trigger a LINK/INVALID alarm in the child link */
640  for (i = 0; i < clink->nArgs; i++) {
641  struct link *child = &clink->inp[i];
642  long nReq = 1;
643 
644  if (i == clink->tinp) {
645  struct lcvt vt = {&clink->arg[i], &clink->time};
646 
647  status = dbLinkDoLocked(child, readLocked, &vt);
648  if (status == S_db_noLSET)
649  status = readLocked(child, &vt);
650 
651  if (dbLinkIsConstant(&prec->tsel) &&
652  prec->tse == epicsTimeEventDeviceTime) {
653  prec->time = clink->time;
654  }
655  }
656  else
657  dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
658  }
659  clink->stat = 0;
660  clink->sevr = 0;
661 
662  /* Get the value being output as VAL */
663  status = conv(pbuffer, &clink->val, NULL);
664 
665  if (!status && clink->post_expr)
666  status = calcPerform(clink->arg, &clink->val, clink->post_expr);
667 
668  if (!status && clink->post_major) {
669  double alval = clink->val;
670 
671  status = calcPerform(clink->arg, &alval, clink->post_major);
672  if (!status && alval) {
673  clink->stat = LINK_ALARM;
674  clink->sevr = MAJOR_ALARM;
675  recGblSetSevr(prec, clink->stat, clink->sevr);
676  }
677  }
678 
679  if (!status && !clink->sevr && clink->post_minor) {
680  double alval = clink->val;
681 
682  status = calcPerform(clink->arg, &alval, clink->post_minor);
683  if (!status && alval) {
684  clink->stat = LINK_ALARM;
685  clink->sevr = MINOR_ALARM;
686  recGblSetSevr(prec, clink->stat, clink->sevr);
687  }
688  }
689 
690  if (!status) {
691  status = dbPutLink(&clink->out, DBR_DOUBLE, &clink->val, 1);
692  }
693 
694  return status;
695 }
696 
697 static long lnkCalc_getPrecision(const struct link *plink, short *precision)
698 {
699  calc_link *clink = CONTAINER(plink->value.json.jlink,
700  struct calc_link, jlink);
701 
702  *precision = clink->prec;
703  return 0;
704 }
705 
706 static long lnkCalc_getUnits(const struct link *plink, char *units, int len)
707 {
708  calc_link *clink = CONTAINER(plink->value.json.jlink,
709  struct calc_link, jlink);
710 
711  if (clink->units) {
712  strncpy(units, clink->units, --len);
713  units[len] = '\0';
714  }
715  else
716  units[0] = '\0';
717  return 0;
718 }
719 
720 static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
721  epicsEnum16 *severity)
722 {
723  calc_link *clink = CONTAINER(plink->value.json.jlink,
724  struct calc_link, jlink);
725 
726  if (status)
727  *status = clink->stat;
728  if (severity)
729  *severity = clink->sevr;
730 
731  return 0;
732 }
733 
734 static long lnkCalc_getTimestamp(const struct link *plink, epicsTimeStamp *pstamp)
735 {
736  calc_link *clink = CONTAINER(plink->value.json.jlink,
737  struct calc_link, jlink);
738 
739  if (clink->tinp >= 0) {
740  *pstamp = clink->time;
741  return 0;
742  }
743 
744  return -1;
745 }
746 
747 static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
748 {
749  return rtn(plink, priv);
750 }
751 
752 
753 /************************* Interface Tables *************************/
754 
755 static lset lnkCalc_lset = {
756  0, 1, /* not Constant, Volatile */
757  lnkCalc_open, lnkCalc_remove,
758  NULL, NULL, NULL,
759  lnkCalc_isConn, lnkCalc_getDBFtype, lnkCalc_getElements,
760  lnkCalc_getValue,
761  NULL, NULL, NULL,
762  lnkCalc_getPrecision, lnkCalc_getUnits,
763  lnkCalc_getAlarm, lnkCalc_getTimestamp,
764  lnkCalc_putValue, NULL,
765  NULL, doLocked
766 };
767 
768 static jlif lnkCalcIf = {
769  "calc", lnkCalc_alloc, lnkCalc_free,
770  NULL, NULL, lnkCalc_integer, lnkCalc_double, lnkCalc_string,
771  lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map,
772  lnkCalc_start_array, lnkCalc_end_array,
773  lnkCalc_end_child, lnkCalc_get_lset,
774  lnkCalc_report, lnkCalc_map_children, NULL
775 };
776 epicsExportAddress(jlif, lnkCalcIf);
LIBCOM_API const char * calcErrorStr(short error)
Convert an error code to a string.
Definition: postfix.c:493
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
#define MAJOR_ALARM
Definition: alarm.h:52
#define CONTAINER(ptr, structure, member)
Find parent object from a member pointer.
Definition: dbDefs.h:66
int i
Definition: scan.c:967
The API for the EPICS Calculation Engine.
#define printf
Definition: epicsStdio.h:41
#define INVALID_DB_REQ(x)
Definition: db_access.h:115
Definition: lnkCalc.c:531
#define NULL
Definition: catime.c:38
struct calc_link calc_link
dbfType
Definition: dbFldTypes.h:24
epicsExportAddress(jlif, lnkCalcIf)
#define CALCPERFORM_NARGS
Number of input arguments to a calc expression (A-L)
Definition: postfix.h:25
Miscellaneous macro definitions.
LIBCOM_API const char * epicsAlarmSeverityStrings[ALARM_NSEV]
How to convert an alarm severity into a string.
Definition: alarmString.c:16
LIBCOM_API long calcPerform(double *parg, double *presult, const char *pinst)
Run the calculation engine.
Definition: calcPerform.c:45
LIBCOM_API size_t epicsStdCall epicsTimeToStrftime(char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
Convert epicsTimeStamp to string. See epicsTime::strftime()
Definition: epicsTime.cpp:1120
epicsTimeStamp * ptime
Definition: lnkCalc.c:533
#define epicsTimeEventDeviceTime
Definition: epicsTime.h:362
double * pval
Definition: lnkCalc.c:532
#define DBR_DOUBLE
Definition: db_access.h:76
long(* FASTCONVERT)()
Definition: lnkCalc.c:38
#define LINK_ALARM
Definition: alarm.h:105
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
char * epicsStrnDup(const char *s, size_t len)
Definition: epicsString.c:224
char * pbuffer
Definition: errlog.c:85
epicsUInt16 epicsEnum16
Definition: epicsTypes.h:47
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
#define MINOR_ALARM
Definition: alarm.h:51
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
LIBCOM_API long postfix(const char *psrc, char *pout, short *perror)
Compile an infix expression into postfix byte-code.
Definition: postfix.c:209
struct json_link json
Definition: link.h:177
LIBCOM_API const char * epicsAlarmConditionStrings[ALARM_NSTATUS]
How to convert an alarm condition/status into a string.
Definition: alarmString.c:26
#define INFIX_TO_POSTFIX_SIZE(n)
Calculate required size of postfix buffer from infix.
Definition: postfix.h:58
Exporting IOC objects.