Merge fix-tsel branch into 3.16
This commit is contained in:
@@ -66,6 +66,26 @@ static const char * link_field_name(const struct link *plink)
|
||||
return "????";
|
||||
}
|
||||
|
||||
/* Special TSEL handler for PV links */
|
||||
/* FIXME: Generalize for new link types... */
|
||||
static void TSEL_modified(struct link *plink)
|
||||
{
|
||||
struct pv_link *ppv_link;
|
||||
char *pfieldname;
|
||||
|
||||
if (plink->type != PV_LINK) {
|
||||
errlogPrintf("dbLink::TSEL_modified called for non PV_LINK\n");
|
||||
return;
|
||||
}
|
||||
/* If pvname contains .TIME truncate it to point to VAL instead */
|
||||
ppv_link = &plink->value.pv_link;
|
||||
pfieldname = strstr(ppv_link->pvname, ".TIME");
|
||||
if (pfieldname) {
|
||||
*pfieldname = 0;
|
||||
plink->flags |= DBLINK_FLAG_TSELisTIME;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************** Generic Link API *****************************/
|
||||
|
||||
@@ -93,7 +113,7 @@ void dbInitLink(struct link *plink, short dbfType)
|
||||
return;
|
||||
|
||||
if (plink == &precord->tsel)
|
||||
recGblTSELwasModified(plink);
|
||||
TSEL_modified(plink);
|
||||
|
||||
if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) {
|
||||
/* Make it a DB link if possible */
|
||||
@@ -127,6 +147,9 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
|
||||
{
|
||||
struct dbCommon *precord = plink->precord;
|
||||
|
||||
/* Clear old TSELisTIME flag */
|
||||
plink->flags &= ~DBLINK_FLAG_TSELisTIME;
|
||||
|
||||
if (plink->type == CONSTANT) {
|
||||
dbConstAddLink(plink);
|
||||
return;
|
||||
@@ -145,7 +168,7 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
|
||||
return;
|
||||
|
||||
if (plink == &precord->tsel)
|
||||
recGblTSELwasModified(plink);
|
||||
TSEL_modified(plink);
|
||||
|
||||
if (ptarget) {
|
||||
/* It's a DB link */
|
||||
@@ -470,4 +493,3 @@ long dbPutLinkLS(struct link *plink, char *pbuffer, epicsUInt32 len)
|
||||
|
||||
return dbPutLink(plink, DBR_STRING, pbuffer, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos 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.
|
||||
\*************************************************************************/
|
||||
/* recGbl.c */
|
||||
/*
|
||||
@@ -259,15 +259,13 @@ void recGblGetTimeStamp(void *pvoid)
|
||||
struct link *plink = &prec->tsel;
|
||||
|
||||
if (!dbLinkIsConstant(plink)) {
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
|
||||
if (ppv_link->pvlMask & pvlOptTSELisTime) {
|
||||
if (plink->flags & DBLINK_FLAG_TSELisTIME) {
|
||||
if (dbGetTimeStamp(plink, &prec->time))
|
||||
errlogPrintf("recGblGetTimeStamp: dbGetTimeStamp failed, %s.TSEL = %s\n",
|
||||
prec->name, ppv_link->pvname);
|
||||
errlogPrintf("recGblGetTimeStamp: dbGetTimeStamp failed for %s.TSEL",
|
||||
prec->name);
|
||||
return;
|
||||
}
|
||||
dbGetLink(&prec->tsel, DBR_SHORT, &prec->tse, 0, 0);
|
||||
dbGetLink(plink, DBR_SHORT, &prec->tse, 0, 0);
|
||||
}
|
||||
if (prec->tse != epicsTimeEventDeviceTime) {
|
||||
if (epicsTimeGetEvent(&prec->time, prec->tse))
|
||||
@@ -276,24 +274,6 @@ void recGblGetTimeStamp(void *pvoid)
|
||||
}
|
||||
}
|
||||
|
||||
void recGblTSELwasModified(struct link *plink)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
char *pfieldname;
|
||||
|
||||
if (plink->type != PV_LINK) {
|
||||
errlogPrintf("recGblTSELwasModified called for non PV_LINK\n");
|
||||
return;
|
||||
}
|
||||
/*If pvname ends in .TIME then just ask for VAL*/
|
||||
/*Note that the VAL value will not be used*/
|
||||
pfieldname = strstr(ppv_link->pvname, ".TIME");
|
||||
if (pfieldname) {
|
||||
*pfieldname = 0;
|
||||
ppv_link->pvlMask |= pvlOptTSELisTime;
|
||||
}
|
||||
}
|
||||
|
||||
void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval,
|
||||
const epicsFloat64 deadband, unsigned *monitor_mask, const unsigned add_mask)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos 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.
|
||||
\*************************************************************************/
|
||||
/* recGbl.h */
|
||||
/* Record Global
|
||||
@@ -63,7 +63,6 @@ epicsShareFunc void recGblInheritSevr(int msMode, void *precord, epicsEnum16 sta
|
||||
epicsEnum16 sevr);
|
||||
epicsShareFunc void recGblFwdLink(void *precord);
|
||||
epicsShareFunc void recGblGetTimeStamp(void *precord);
|
||||
epicsShareFunc void recGblTSELwasModified(struct link *plink);
|
||||
epicsShareFunc void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval,
|
||||
const epicsFloat64 deadband, unsigned *monitor_mask, const unsigned add_mask);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "epicsThread.h"
|
||||
#include "iocInit.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbDefs.h"
|
||||
#include "link.h"
|
||||
#include "dbAccess.h"
|
||||
#include "registry.h"
|
||||
@@ -565,7 +566,7 @@ void testJLink(void)
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
testNumZ(3);
|
||||
testNumZ(6);
|
||||
|
||||
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
|
||||
testdbPutFieldOk("j2.PROC", DBF_LONG, 1);
|
||||
@@ -576,13 +577,16 @@ void testJLink(void)
|
||||
testdbGetFieldEqual("j2.VAL", DBF_LONG, 2);
|
||||
testdbGetFieldEqual("j3.VAL", DBF_LONG, 3);
|
||||
|
||||
testNumZ(3);
|
||||
testNumZ(6);
|
||||
|
||||
testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}");
|
||||
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
|
||||
testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
|
||||
|
||||
testNumZ(3);
|
||||
testdbPutFieldOk("j2.TSEL", DBF_STRING, "{\"z\":{\"good\":0}}");
|
||||
testdbPutFieldOk("j2.PROC", DBF_LONG, 1);
|
||||
|
||||
testNumZ(7);
|
||||
|
||||
testdbPutFieldFail(S_dbLib_badField, "j1.INP", DBF_STRING, "{\"z\":{\"fail\":5}}");
|
||||
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
|
||||
@@ -590,7 +594,13 @@ void testJLink(void)
|
||||
/* put failure in parsing stage doesn't modify link */
|
||||
testdbGetFieldEqual("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}");
|
||||
|
||||
testNumZ(3);
|
||||
testNumZ(7);
|
||||
|
||||
/* Check SDIS using a JSON link prevents processing */
|
||||
testdbPutFieldOk("j1.SDIS", DBF_STRING, "{\"z\":{\"good\":1}}");
|
||||
testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":1}}");
|
||||
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
|
||||
testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
@@ -599,9 +609,81 @@ void testJLink(void)
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
static
|
||||
void testTSEL(void)
|
||||
{
|
||||
dbCommon *rec[2];
|
||||
dbLocker *locker;
|
||||
|
||||
testDiag("Test TSEL link to .TIME");
|
||||
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
|
||||
|
||||
dbTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
testdbReadDatabase("dbPutLinkTest.db", NULL, NULL);
|
||||
|
||||
rec[0] = testdbRecordPtr("time:one");
|
||||
rec[1] = testdbRecordPtr("time:two");
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
locker = dbLockerAlloc(rec, NELEMENTS(rec), 0);
|
||||
if(!locker)
|
||||
testAbort("dbLockerAlloc() fails");
|
||||
|
||||
testdbPutFieldOk("time:one.PROC", DBF_LONG, 1);
|
||||
|
||||
/* wait a bit so that we would get different timestamps */
|
||||
epicsThreadSleep(0.001);
|
||||
|
||||
testdbPutFieldOk("time:two.PROC", DBF_LONG, 1);
|
||||
|
||||
#define COMPARE(MSG, C, TS1, TS2) testOk((C)^((TS1)->secPastEpoch == (TS2)->secPastEpoch && (TS1)->nsec == (TS2)->nsec), \
|
||||
MSG " %u:%u == %u:%u", (unsigned)(TS1)->secPastEpoch, (unsigned)(TS1)->nsec, \
|
||||
(unsigned)(TS2)->secPastEpoch, (unsigned)(TS2)->nsec)
|
||||
|
||||
testDiag("Check initially connected TSEL link");
|
||||
dbScanLockMany(locker);
|
||||
COMPARE("first", 0, &rec[0]->time, &rec[1]->time);
|
||||
testOk1(rec[1]->tsel.flags & DBLINK_FLAG_TSELisTIME);
|
||||
dbScanUnlockMany(locker);
|
||||
|
||||
testdbPutFieldOk("time:two.TSEL", DBF_STRING, "");
|
||||
|
||||
testdbPutFieldOk("time:two.PROC", DBF_LONG, 1);
|
||||
|
||||
testDiag("Check no TSEL link");
|
||||
dbScanLockMany(locker);
|
||||
COMPARE("second", 1, &rec[0]->time, &rec[1]->time);
|
||||
testOk1(!(rec[1]->tsel.flags & DBLINK_FLAG_TSELisTIME));
|
||||
dbScanUnlockMany(locker);
|
||||
|
||||
testdbPutFieldOk("time:two.TSEL", DBF_STRING, "time:one.TIME");
|
||||
|
||||
testdbPutFieldOk("time:two.PROC", DBF_LONG, 1);
|
||||
|
||||
testDiag("Check re-connected TSEL link");
|
||||
dbScanLockMany(locker);
|
||||
COMPARE("third", 0, &rec[0]->time, &rec[1]->time);
|
||||
testOk1(rec[1]->tsel.flags & DBLINK_FLAG_TSELisTIME);
|
||||
dbScanUnlockMany(locker);
|
||||
|
||||
dbLockerFree(locker);
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
#undef COMPARE
|
||||
}
|
||||
|
||||
MAIN(dbPutLinkTest)
|
||||
{
|
||||
testPlan(301);
|
||||
testPlan(319);
|
||||
testLinkParse();
|
||||
testLinkFailParse();
|
||||
testCADBSet();
|
||||
@@ -610,5 +692,6 @@ MAIN(dbPutLinkTest)
|
||||
testLinkInitFail();
|
||||
testLinkFail();
|
||||
testJLink();
|
||||
testTSEL();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -47,3 +47,8 @@ record(x, "rVXI_IO2") {
|
||||
field(DTYP, "Unit Test VXI_IO")
|
||||
field(INP, "#V81 S82 @parm2 VXI_IO")
|
||||
}
|
||||
|
||||
record(x, "time:one") {}
|
||||
record(x, "time:two") {
|
||||
field(TSEL, "time:one.TIME")
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
|
||||
record(x, "j1") {
|
||||
field(INP, {z:{good:1}})
|
||||
field(TSEL, {z:{good:0}})
|
||||
field(SDIS, {z:{good:0}})
|
||||
field(FLNK, {z:{good:0}})
|
||||
}
|
||||
|
||||
record(x, "j2") {
|
||||
field(INP, {z:{good:2}})
|
||||
field(TSEL, "j1.TIME")
|
||||
}
|
||||
|
||||
record(x, "j3") {
|
||||
|
||||
@@ -1940,7 +1940,7 @@ char * dbGetString(DBENTRY *pdbentry)
|
||||
else ppind=0;
|
||||
dbMsgPrint(pdbentry, "%s%s%s%s",
|
||||
plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
|
||||
(pvlMask & pvlOptTSELisTime) ? ".TIME" : "",
|
||||
(plink->flags & DBLINK_FLAG_TSELisTIME) ? ".TIME" : "",
|
||||
ppstring[ppind],
|
||||
msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
|
||||
break;
|
||||
|
||||
@@ -67,10 +67,10 @@ epicsShareExtern maplinkType pamaplinkType[];
|
||||
#define pvlOptInpString 0x100 /*Input as string*/
|
||||
#define pvlOptOutNative 0x200 /*Output native*/
|
||||
#define pvlOptOutString 0x400 /*Output as string*/
|
||||
#define pvlOptTSELisTime 0x800 /*Field TSEL is getting timeStamp*/
|
||||
|
||||
/* DBLINK Flag bits */
|
||||
#define DBLINK_FLAG_INITIALIZED 1 /* dbInitLink() called */
|
||||
#define DBLINK_FLAG_TSELisTIME 2 /* Use TSEL to get timeStamp */
|
||||
|
||||
struct macro_link {
|
||||
char *macroStr;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ record(ai, "emptylink" ) {
|
||||
field(INP, {calc: {expr:"0"}})
|
||||
}
|
||||
record(ai, "emptylink1" ) {
|
||||
field(INP, {calc: {expr:"1"}})
|
||||
field(INP, {calc: {expr:"A", args:[1], time:"a"}})
|
||||
field(TSEL, -2)
|
||||
}
|
||||
|
||||
record(printf, "printf1") {
|
||||
|
||||
Reference in New Issue
Block a user