Merge changes from 3.16 branch and below into database/master
Also removes some extraneous template files
This commit is contained in:
@@ -114,6 +114,14 @@ expression. Equivalent to the C<EGU> field of a record.
|
||||
An optional integer specifying the numeric precision with which the calculation
|
||||
result should be displayed. Equivalent to the C<PREC> field of a record.
|
||||
|
||||
=item time
|
||||
|
||||
An optional string containing a single upper or lower-case letter C<A> ... C<L>
|
||||
which must correspond to an input provided in the c<args> parameter. When the
|
||||
record containing such a link has C<TSEL> set to -2 (epicsTimeEventDeviceTime)
|
||||
the record's timestamp field C<TIME> will be read from the indicated input link
|
||||
atomically with the value of the input argument.
|
||||
|
||||
=back
|
||||
|
||||
=head4 Example
|
||||
|
||||
+55
-6
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* lnkCalc.c */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "alarm.h"
|
||||
#include "dbDefs.h"
|
||||
@@ -26,6 +27,7 @@
|
||||
#include "epicsString.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbJLink.h"
|
||||
@@ -49,6 +51,7 @@ typedef struct calc_link {
|
||||
ps_args,
|
||||
ps_prec,
|
||||
ps_units,
|
||||
ps_time,
|
||||
ps_error
|
||||
} pstate;
|
||||
epicsEnum16 stat;
|
||||
@@ -61,6 +64,7 @@ typedef struct calc_link {
|
||||
char *post_major;
|
||||
char *post_minor;
|
||||
char *units;
|
||||
short tinp;
|
||||
struct link inp[CALCPERFORM_NARGS];
|
||||
double arg[CALCPERFORM_NARGS];
|
||||
double val;
|
||||
@@ -81,6 +85,7 @@ static jlink* lnkCalc_alloc(short dbfType)
|
||||
clink->nArgs = 0;
|
||||
clink->pstate = ps_init;
|
||||
clink->prec = 15; /* standard value for a double */
|
||||
clink->tinp = -1;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkCalc_alloc -> calc@%p\n", clink);
|
||||
@@ -174,6 +179,16 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
if (clink->pstate == ps_time) {
|
||||
char tinp;
|
||||
if (len != 1 || (tinp = toupper(val[0])) < 'A' || tinp > 'L') {
|
||||
errlogPrintf("lnkCalc: Bad 'time' parameter \"%.*s\"\n", (int) len, val);
|
||||
return jlif_stop;
|
||||
}
|
||||
clink->tinp = tinp - 'A';
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
if (clink->pstate < ps_expr || clink->pstate > ps_minor) {
|
||||
errlogPrintf("lnkCalc: Unexpected string \"%.*s\"\n", (int) len, val);
|
||||
return jlif_stop;
|
||||
@@ -247,6 +262,8 @@ static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len)
|
||||
clink->pstate = ps_args;
|
||||
else if (!strncmp(key, "prec", len))
|
||||
clink->pstate = ps_prec;
|
||||
else if (!strncmp(key, "time", len))
|
||||
clink->pstate = ps_time;
|
||||
else {
|
||||
errlogPrintf("lnkCalc: Unknown key \"%.4s\"\n", key);
|
||||
return jlif_stop;
|
||||
@@ -371,6 +388,10 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
|
||||
printf("%*s Minor expression: \"%s\"\n", indent, "",
|
||||
clink->minor);
|
||||
|
||||
if (clink->tinp >= 0 && clink->tinp < clink->nArgs)
|
||||
printf("%*s Timestamp input \"%c\"\n", indent, "",
|
||||
clink->tinp + 'A');
|
||||
|
||||
for (i = 0; i < clink->nArgs; i++) {
|
||||
struct link *plink = &clink->inp[i];
|
||||
jlink *child = plink->type == JSON_LINK ?
|
||||
@@ -502,11 +523,30 @@ static long lnkCalc_getElements(const struct link *plink, long *nelements)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get value and timestamp atomically for link indicated by time */
|
||||
struct lcvt {
|
||||
double *pval;
|
||||
epicsTimeStamp *ptime;
|
||||
};
|
||||
|
||||
static long readLocked(struct link *pinp, void *vvt)
|
||||
{
|
||||
struct lcvt *pvt = (struct lcvt *) vvt;
|
||||
long nReq = 1;
|
||||
long status = dbGetLink(pinp, DBR_DOUBLE, pvt->pval, NULL, &nReq);
|
||||
|
||||
if (!status && pvt->ptime)
|
||||
dbGetTimeStamp(pinp, pvt->ptime);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest)
|
||||
{
|
||||
calc_link *clink = CONTAINER(plink->value.json.jlink,
|
||||
struct calc_link, jlink);
|
||||
dbCommon *prec = plink->precord;
|
||||
int i;
|
||||
long status;
|
||||
FASTCONVERT conv = dbFastPutConvertRoutine[DBR_DOUBLE][dbrType];
|
||||
@@ -515,12 +555,22 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
printf("lnkCalc_getValue(calc@%p, %d, ...)\n",
|
||||
clink, dbrType);
|
||||
|
||||
/* Any link errors will trigger a LINK/INVALID alarm in the child link */
|
||||
for (i = 0; i < clink->nArgs; i++) {
|
||||
struct link *child = &clink->inp[i];
|
||||
long nReq = 1;
|
||||
|
||||
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
|
||||
/* Any errors have already triggered a LINK/INVALID alarm */
|
||||
if (i == clink->tinp &&
|
||||
dbLinkIsConstant(&prec->tsel) &&
|
||||
prec->tse == epicsTimeEventDeviceTime) {
|
||||
struct lcvt vt = {&clink->arg[i], &prec->time};
|
||||
|
||||
status = dbLinkDoLocked(child, readLocked, &vt);
|
||||
if (status == S_db_noLSET)
|
||||
status = readLocked(child, &vt);
|
||||
}
|
||||
else
|
||||
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
|
||||
}
|
||||
clink->stat = 0;
|
||||
clink->sevr = 0;
|
||||
@@ -545,7 +595,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
if (!status && alval) {
|
||||
clink->stat = LINK_ALARM;
|
||||
clink->sevr = MAJOR_ALARM;
|
||||
recGblSetSevr(plink->precord, clink->stat, clink->sevr);
|
||||
recGblSetSevr(prec, clink->stat, clink->sevr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +606,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
if (!status && alval) {
|
||||
clink->stat = LINK_ALARM;
|
||||
clink->sevr = MINOR_ALARM;
|
||||
recGblSetSevr(plink->precord, clink->stat, clink->sevr);
|
||||
recGblSetSevr(prec, clink->stat, clink->sevr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,4 +689,3 @@ static jlif lnkCalcIf = {
|
||||
lnkCalc_report, lnkCalc_map_children
|
||||
};
|
||||
epicsExportAddress(jlif, lnkCalcIf);
|
||||
|
||||
|
||||
+67
-26
@@ -22,20 +22,20 @@
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
#define IFDEBUG(n) if(clink->jlink.debug)
|
||||
#define IFDEBUG(n) if (clink->jlink.debug)
|
||||
|
||||
typedef long (*FASTCONVERT)();
|
||||
|
||||
typedef struct const_link {
|
||||
jlink jlink; /* embedded object */
|
||||
int nElems;
|
||||
enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type;
|
||||
enum {s0, si64, sf64, sc40, a0, ai64, af64, ac40} type;
|
||||
union {
|
||||
epicsInt32 scalar_integer; /* si32 */
|
||||
epicsInt64 scalar_integer; /* si64 */
|
||||
epicsFloat64 scalar_double; /* sf64 */
|
||||
char *scalar_string; /* sc40 */
|
||||
void *pmem;
|
||||
epicsInt32 *pintegers; /* ai32 */
|
||||
epicsInt64 *pintegers; /* ai64 */
|
||||
epicsFloat64 *pdoubles; /* af64 */
|
||||
char **pstrings; /* ac40 */
|
||||
} value;
|
||||
@@ -77,13 +77,13 @@ static void lnkConst_free(jlink *pjlink)
|
||||
free(clink->value.pstrings[i]);
|
||||
/* fall through */
|
||||
case sc40:
|
||||
case ai32:
|
||||
case ai64:
|
||||
case af64:
|
||||
free(clink->value.pmem);
|
||||
break;
|
||||
case s0:
|
||||
case a0:
|
||||
case si32:
|
||||
case si64:
|
||||
case sf64:
|
||||
break;
|
||||
}
|
||||
@@ -102,20 +102,24 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
|
||||
void *buf;
|
||||
|
||||
case s0:
|
||||
clink->type = si32;
|
||||
clink->type = si64;
|
||||
clink->value.scalar_integer = num;
|
||||
IFDEBUG(12)
|
||||
printf(" si64 := %lld\n", num);
|
||||
break;
|
||||
|
||||
case a0:
|
||||
clink->type = ai32;
|
||||
clink->type = ai64;
|
||||
/* fall through */
|
||||
case ai32:
|
||||
buf = realloc(clink->value.pmem, newElems * sizeof(epicsInt32));
|
||||
case ai64:
|
||||
buf = realloc(clink->value.pmem, newElems * sizeof(epicsInt64));
|
||||
if (!buf)
|
||||
return jlif_stop;
|
||||
|
||||
clink->value.pmem = buf;
|
||||
clink->value.pintegers[clink->nElems] = num;
|
||||
IFDEBUG(12)
|
||||
printf(" ai64 += %lld\n", num);
|
||||
break;
|
||||
|
||||
case af64:
|
||||
@@ -125,6 +129,8 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num)
|
||||
|
||||
clink->value.pmem = buf;
|
||||
clink->value.pdoubles[clink->nElems] = num;
|
||||
IFDEBUG(12)
|
||||
printf(" af64 += %lld\n", num);
|
||||
break;
|
||||
|
||||
case ac40:
|
||||
@@ -176,7 +182,7 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
|
||||
clink->value.pdoubles = f64buf;
|
||||
break;
|
||||
|
||||
case ai32: /* promote earlier ai32 values to af64 */
|
||||
case ai64: /* promote earlier ai64 values to af64 */
|
||||
f64buf = calloc(newElems, sizeof(epicsFloat64));
|
||||
if (!f64buf)
|
||||
return jlif_stop;
|
||||
@@ -241,7 +247,7 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
|
||||
break;
|
||||
|
||||
case af64:
|
||||
case ai32:
|
||||
case ai64:
|
||||
errlogPrintf("lnkConst: Mixed data types in array\n");
|
||||
/* fall thorough */
|
||||
default:
|
||||
@@ -328,10 +334,10 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent)
|
||||
int i;
|
||||
|
||||
switch (clink->type) {
|
||||
case ai32:
|
||||
printf("\n%*s[%d", indent+2, "", clink->value.pintegers[0]);
|
||||
case ai64:
|
||||
printf("\n%*s[%lld", indent+2, "", clink->value.pintegers[0]);
|
||||
for (i = 1; i < clink->nElems; i++) {
|
||||
printf(", %d", clink->value.pintegers[i]);
|
||||
printf(", %lld", clink->value.pintegers[i]);
|
||||
}
|
||||
break;
|
||||
case af64:
|
||||
@@ -357,8 +363,8 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent)
|
||||
printf("%*s'const': %s", indent, "", dtype);
|
||||
|
||||
switch (clink->type) {
|
||||
case si32:
|
||||
printf(" %d\n", clink->value.scalar_integer);
|
||||
case si64:
|
||||
printf(" %lld\n", clink->value.scalar_integer);
|
||||
return;
|
||||
case sf64:
|
||||
printf(" %g\n", clink->value.scalar_double);
|
||||
@@ -394,37 +400,51 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer
|
||||
clink, dbrType, pbuffer);
|
||||
|
||||
switch (clink->type) {
|
||||
case si32:
|
||||
status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
|
||||
case si64:
|
||||
IFDEBUG(12)
|
||||
printf(" si64 %lld\n", clink->value.scalar_integer);
|
||||
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
|
||||
(&clink->value.scalar_integer, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case sf64:
|
||||
IFDEBUG(12)
|
||||
printf(" sf64 %g\n", clink->value.scalar_double);
|
||||
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
|
||||
(&clink->value.scalar_double, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case sc40:
|
||||
IFDEBUG(12)
|
||||
printf(" sc40 '%s'\n", clink->value.scalar_string);
|
||||
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
|
||||
(clink->value.scalar_string, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case ai32:
|
||||
status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
|
||||
case ai64:
|
||||
IFDEBUG(12)
|
||||
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
|
||||
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
|
||||
(clink->value.pintegers, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case af64:
|
||||
IFDEBUG(12)
|
||||
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
|
||||
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
|
||||
(clink->value.pdoubles, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case ac40:
|
||||
IFDEBUG(12)
|
||||
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
|
||||
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
|
||||
(clink->value.pstrings[0], pbuffer, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
IFDEBUG(12)
|
||||
printf(" Bad type %d\n", clink->type);
|
||||
status = S_db_badField;
|
||||
break;
|
||||
}
|
||||
@@ -446,14 +466,20 @@ static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
|
||||
switch (clink->type) {
|
||||
case sc40:
|
||||
IFDEBUG(12)
|
||||
printf(" sc40 '%s'\n", clink->value.scalar_string);
|
||||
pstr = clink->value.scalar_string;
|
||||
break;
|
||||
|
||||
case ac40:
|
||||
IFDEBUG(12)
|
||||
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
|
||||
pstr = clink->value.pstrings[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
IFDEBUG(12)
|
||||
printf(" Bad type %d\n", clink->type);
|
||||
return S_db_badField;
|
||||
}
|
||||
|
||||
@@ -483,23 +509,31 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
switch (clink->type) {
|
||||
int i;
|
||||
|
||||
case si32:
|
||||
status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
|
||||
case si64:
|
||||
IFDEBUG(12)
|
||||
printf(" si64 %lld\n", clink->value.scalar_integer);
|
||||
status = dbFastPutConvertRoutine[DBF_INT64][dbrType]
|
||||
(&clink->value.scalar_integer, pdest, NULL);
|
||||
break;
|
||||
|
||||
case sf64:
|
||||
IFDEBUG(12)
|
||||
printf(" sf64 %g\n", clink->value.scalar_double);
|
||||
status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
|
||||
(&clink->value.scalar_double, pdest, NULL);
|
||||
break;
|
||||
|
||||
case sc40:
|
||||
IFDEBUG(12)
|
||||
printf(" sc40 '%s'\n", clink->value.scalar_string);
|
||||
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
|
||||
(clink->value.scalar_string, pbuffer, NULL);
|
||||
break;
|
||||
|
||||
case ai32:
|
||||
conv = dbFastPutConvertRoutine[DBF_LONG][dbrType];
|
||||
case ai64:
|
||||
IFDEBUG(12)
|
||||
printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]);
|
||||
conv = dbFastPutConvertRoutine[DBF_INT64][dbrType];
|
||||
for (i = 0; i < nElems; i++) {
|
||||
conv(&clink->value.pintegers[i], pdest, NULL);
|
||||
pdest += dbrSize;
|
||||
@@ -508,6 +542,8 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
break;
|
||||
|
||||
case af64:
|
||||
IFDEBUG(12)
|
||||
printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]);
|
||||
conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType];
|
||||
for (i = 0; i < nElems; i++) {
|
||||
conv(&clink->value.pdoubles[i], pdest, NULL);
|
||||
@@ -517,6 +553,8 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
break;
|
||||
|
||||
case ac40:
|
||||
IFDEBUG(12)
|
||||
printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]);
|
||||
conv = dbFastPutConvertRoutine[DBF_STRING][dbrType];
|
||||
for (i = 0; i < nElems; i++) {
|
||||
conv(clink->value.pstrings[i], pdest, NULL);
|
||||
@@ -526,6 +564,8 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
break;
|
||||
|
||||
default:
|
||||
IFDEBUG(12)
|
||||
printf(" Bad type %d\n", clink->type);
|
||||
status = S_db_badField;
|
||||
}
|
||||
*pnReq = nElems;
|
||||
@@ -551,7 +591,8 @@ static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("lnkConst_getValue(const@%p, %d, %p, ... (%ld))\n",
|
||||
plink->value.json.jlink, dbrType, pbuffer, *pnRequest);
|
||||
plink->value.json.jlink, dbrType, pbuffer,
|
||||
pnRequest ? *pnRequest : 0);
|
||||
|
||||
if (pnRequest)
|
||||
*pnRequest = 0;
|
||||
|
||||
Reference in New Issue
Block a user