26 #include "dbAccessDefs.h" 28 #include "dbConvertFast.h" 71 static lset lnkCalc_lset;
85 clink = calloc(1,
sizeof(
struct calc_link));
100 static void lnkCalc_free(
jlink *pjlink)
105 for (i = 0; i < clink->
nArgs; i++)
120 static jlif_result lnkCalc_integer(
jlink *pjlink,
long long num)
126 return jlif_continue;
130 errlogPrintf(
"lnkCalc: Unexpected integer %lld\n", num);
135 errlogPrintf(
"lnkCalc: Too many input args, limit is %d\n",
142 return jlif_continue;
145 static jlif_result lnkCalc_double(
jlink *pjlink,
double num)
155 errlogPrintf(
"lnkCalc: Too many input args, limit is %d\n",
162 return jlif_continue;
165 static jlif_result lnkCalc_string(
jlink *pjlink,
const char *
val,
size_t len)
168 char *inbuf, *postbuf;
173 return jlif_continue;
179 if (len != 1 || (tinp = toupper((
int)
val[0])) <
'A' || tinp >
'L') {
180 errlogPrintf(
"lnkCalc: Bad 'time' parameter \"%.*s\"\n", (
int) len, val);
183 clink->
tinp = tinp -
'A';
184 return jlif_continue;
198 inbuf = malloc(len+1);
204 memcpy(inbuf,
val, len);
208 clink->
major = inbuf;
212 clink->
minor = inbuf;
220 if (
postfix(inbuf, postbuf, &err) < 0) {
226 return jlif_continue;
229 static jlif_key_result lnkCalc_start_map(
jlink *pjlink)
234 return jlif_key_child_inlink;
236 return jlif_key_child_outlink;
240 return jlif_key_stop;
243 return jlif_key_continue;
246 static jlif_result lnkCalc_map_key(
jlink *pjlink,
const char *key,
size_t len)
255 if (!strncmp(key,
"out", len) &&
265 if (!strncmp(key,
"expr", len) && !clink->
post_expr)
267 else if (!strncmp(key,
"args", len) && !clink->
nArgs)
269 else if (!strncmp(key,
"prec", len))
271 else if (!strncmp(key,
"time", len))
279 if (!strncmp(key,
"major", len) && !clink->
post_major)
281 else if (!strncmp(key,
"minor", len) && !clink->
post_minor)
283 else if (!strncmp(key,
"units", len) && !clink->
units)
291 errlogPrintf(
"lnkCalc: Unknown key \"%.*s\"\n", (
int) len, key);
295 return jlif_continue;
298 static jlif_result lnkCalc_end_map(
jlink *pjlink)
315 return jlif_continue;
318 static jlif_result lnkCalc_start_array(
jlink *pjlink)
327 return jlif_continue;
330 static jlif_result lnkCalc_end_array(
jlink *pjlink)
337 return jlif_continue;
340 static void lnkCalc_end_child(
jlink *parent,
jlink *child)
347 errlogPrintf(
"lnkCalc: Too many input args, limit is %d\n",
352 plink = &clink->
inp[clink->
nArgs++];
358 errlogPrintf(
"lnkCalc: Unexpected child link, parser state = %d\n",
371 static struct lset* lnkCalc_get_lset(
const jlink *pjlink)
373 return &lnkCalc_lset;
376 static void lnkCalc_report(
const jlink *pjlink,
int level,
int indent)
381 printf(
"%*s'calc': \"%s\" = %.*g %s\n", indent,
"",
387 printf(
"%*s Alarm: %s, %s\n", indent,
"",
392 printf(
"%*s Major expression: \"%s\"\n", indent,
"",
395 printf(
"%*s Minor expression: \"%s\"\n", indent,
"",
398 if (clink->
tinp >= 0) {
402 printf(
"%*s Timestamp input %c: %s\n", indent,
"",
403 clink->
tinp +
'A', timeStr);
406 for (i = 0; i < clink->
nArgs; i++) {
407 struct link *plink = &clink->
inp[
i];
411 printf(
"%*s Input %c: %g\n", indent,
"",
412 i +
'A', clink->
arg[i]);
415 dbJLinkReport(child, level - 1, indent + 4);
419 printf(
"%*s Output:\n", indent,
"");
426 static long lnkCalc_map_children(
jlink *pjlink, jlink_map_fn rtn,
void *ctx)
431 for (i = 0; i < clink->
nArgs; i++) {
432 struct link *child = &clink->
inp[
i];
433 long status = dbJLinkMapChildren(child, rtn, ctx);
440 return dbJLinkMapChildren(&clink->
out, rtn, ctx);
447 static void lnkCalc_open(
struct link *plink)
453 for (i = 0; i < clink->
nArgs; i++) {
454 struct link *child = &clink->
inp[
i];
462 dbJLinkInit(&clink->
out);
466 static void lnkCalc_remove(
struct dbLocker *locker,
struct link *plink)
472 for (i = 0; i < clink->
nArgs; i++) {
473 struct link *child = &clink->
inp[
i];
475 dbRemoveLink(locker, child);
479 dbRemoveLink(locker, &clink->
out);
493 static int lnkCalc_isConn(
const struct link *plink)
500 for (i = 0; i < clink->
nArgs; i++) {
501 struct link *child = &clink->
inp[
i];
503 if (dbLinkIsVolatile(child) &&
504 !dbIsLinkConnected(child))
509 struct link *child = &clink->
out;
511 if (dbLinkIsVolatile(child) &&
512 !dbIsLinkConnected(child))
519 static int lnkCalc_getDBFtype(
const struct link *plink)
524 static long lnkCalc_getElements(
const struct link *plink,
long *nelements)
536 static long readLocked(
struct link *pinp,
void *vvt)
538 struct lcvt *pvt = (
struct lcvt *) vvt;
542 if (!status && pvt->
ptime)
543 dbGetTimeStamp(pinp, pvt->
ptime);
548 static long lnkCalc_getValue(
struct link *plink,
short dbrType,
void *
pbuffer,
559 return S_db_badDbrtype;
561 conv = dbFastPutConvertRoutine[
DBR_DOUBLE][dbrType];
564 for (i = 0; i < clink->
nArgs; i++) {
565 struct link *child = &clink->
inp[
i];
568 if (i == clink->
tinp) {
571 status = dbLinkDoLocked(child, readLocked, &vt);
572 if (status == S_db_noLSET)
573 status = readLocked(child, &vt);
575 if (dbLinkIsConstant(&prec->tsel) &&
577 prec->time = clink->
time;
590 if (!status && pnRequest)
600 double alval = clink->
val;
603 if (!status && alval) {
606 recGblSetSevr(prec, clink->
stat, clink->
sevr);
611 double alval = clink->
val;
614 if (!status && alval) {
617 recGblSetSevr(prec, clink->
stat, clink->
sevr);
624 static long lnkCalc_putValue(
struct link *plink,
short dbrType,
625 const void *
pbuffer,
long nRequest)
635 return S_db_badDbrtype;
637 conv = dbFastGetConvertRoutine[dbrType][
DBR_DOUBLE];
640 for (i = 0; i < clink->
nArgs; i++) {
641 struct link *child = &clink->
inp[
i];
644 if (i == clink->
tinp) {
647 status = dbLinkDoLocked(child, readLocked, &vt);
648 if (status == S_db_noLSET)
649 status = readLocked(child, &vt);
651 if (dbLinkIsConstant(&prec->tsel) &&
653 prec->time = clink->
time;
669 double alval = clink->
val;
672 if (!status && alval) {
675 recGblSetSevr(prec, clink->
stat, clink->
sevr);
680 double alval = clink->
val;
683 if (!status && alval) {
686 recGblSetSevr(prec, clink->
stat, clink->
sevr);
697 static long lnkCalc_getPrecision(
const struct link *plink,
short *precision)
702 *precision = clink->
prec;
706 static long lnkCalc_getUnits(
const struct link *plink,
char *
units,
int len)
729 *severity = clink->
sevr;
739 if (clink->
tinp >= 0) {
740 *pstamp = clink->
time;
747 static long doLocked(
struct link *plink, dbLinkUserCallback rtn,
void *priv)
749 return rtn(plink, priv);
755 static lset lnkCalc_lset = {
757 lnkCalc_open, lnkCalc_remove,
759 lnkCalc_isConn, lnkCalc_getDBFtype, lnkCalc_getElements,
762 lnkCalc_getPrecision, lnkCalc_getUnits,
763 lnkCalc_getAlarm, lnkCalc_getTimestamp,
764 lnkCalc_putValue,
NULL,
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
LIBCOM_API const char * calcErrorStr(short error)
Convert an error code to a string.
An EPICS-specific replacement for ANSI C's assert.
struct dbCommon * precord
#define CONTAINER(ptr, structure, member)
Find parent object from a member pointer.
The API for the EPICS Calculation Engine.
#define INVALID_DB_REQ(x)
struct calc_link calc_link
epicsExportAddress(jlif, lnkCalcIf)
#define CALCPERFORM_NARGS
Number of input arguments to a calc expression (A-L)
Miscellaneous macro definitions.
LIBCOM_API const char * epicsAlarmSeverityStrings[ALARM_NSEV]
How to convert an alarm severity into a string.
LIBCOM_API size_t epicsStdCall epicsTimeToStrftime(char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
Convert epicsTimeStamp to string. See epicsTime::strftime()
#define epicsTimeEventDeviceTime
int errlogPrintf(const char *pFormat,...)
char * epicsStrnDup(const char *s, size_t len)
EPICS time stamp, for use from C code.
struct link inp[CALCPERFORM_NARGS]
double arg[CALCPERFORM_NARGS]
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.
enum calc_link::@9 pstate
LIBCOM_API const char * epicsAlarmConditionStrings[ALARM_NSTATUS]
How to convert an alarm condition/status into a string.
#define INFIX_TO_POSTFIX_SIZE(n)
Calculate required size of postfix buffer from infix.