From 1e028d68d885cea30978b0069d6cd6442651bda3 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 3 Apr 2016 00:49:36 -0500
Subject: [PATCH 001/112] Move DBLINK support code into its own source file
---
src/ioc/db/Makefile | 4 +-
src/ioc/db/dbDbLink.c | 344 ++++++++++++++++++++++++++++++++++++++++++
src/ioc/db/dbDbLink.h | 35 +++++
src/ioc/db/dbLink.c | 315 +-------------------------------------
src/ioc/db/recGbl.c | 23 ++-
src/ioc/db/recGbl.h | 2 +
6 files changed, 409 insertions(+), 314 deletions(-)
create mode 100644 src/ioc/db/dbDbLink.c
create mode 100644 src/ioc/db/dbDbLink.h
diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile
index 83cd2ce4a..1b83eeaf9 100644
--- a/src/ioc/db/Makefile
+++ b/src/ioc/db/Makefile
@@ -14,12 +14,13 @@ SRC_DIRS += $(IOCDIR)/db
INC += callback.h
INC += dbAccess.h
INC += dbAccessDefs.h
-INC += dbCa.h
INC += dbAddr.h
INC += dbBkpt.h
+INC += dbCa.h
INC += dbChannel.h
INC += dbConvert.h
INC += dbConvertFast.h
+INC += dbDbLink.h
INC += dbExtractArray.h
INC += dbEvent.h
INC += dbLink.h
@@ -65,6 +66,7 @@ dbCore_SRCS += dbAccess.c
dbCore_SRCS += dbBkpt.c
dbCore_SRCS += dbChannel.c
dbCore_SRCS += dbConvert.c
+dbCore_SRCS += dbDbLink.c
dbCore_SRCS += dbFastLinkConv.c
dbCore_SRCS += dbExtractArray.c
dbCore_SRCS += dbLink.c
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
new file mode 100644
index 000000000..ab106f77d
--- /dev/null
+++ b/src/ioc/db/dbDbLink.c
@@ -0,0 +1,344 @@
+/*************************************************************************\
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* 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.
+\*************************************************************************/
+/* dbDbLink.c
+ *
+ * Original Authors: Bob Dalesio, Marty Kraimer
+ * Current Author: Andrew Johnson
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "alarm.h"
+#include "cantProceed.h"
+#include "cvtFast.h"
+#include "dbDefs.h"
+#include "ellLib.h"
+#include "epicsTime.h"
+#include "errlog.h"
+
+#include "caeventmask.h"
+
+#define epicsExportSharedSymbols
+#include "dbAccessDefs.h"
+#include "dbAddr.h"
+#include "dbBase.h"
+#include "dbBkpt.h"
+#include "dbCommon.h"
+#include "dbConvertFast.h"
+#include "dbConvert.h"
+#include "db_field_log.h"
+#include "dbFldTypes.h"
+#include "dbLink.h"
+#include "dbLockPvt.h"
+#include "dbNotify.h"
+#include "dbScan.h"
+#include "dbStaticLib.h"
+#include "devSup.h"
+#include "link.h"
+#include "recGbl.h"
+#include "recSup.h"
+#include "special.h"
+
+/***************************** Database Links *****************************/
+
+/* Forward definition */
+static lset dbDb_lset;
+
+long dbDbInitLink(struct link *plink, short dbfType)
+{
+ DBADDR dbaddr;
+ long status;
+ DBADDR *pdbAddr;
+
+ status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
+ if (status)
+ return status;
+
+ plink->lset = &dbDb_lset;
+ plink->type = DB_LINK;
+ pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
+ *pdbAddr = dbaddr; /* structure copy */
+ plink->value.pv_link.pvt = pdbAddr;
+ ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
+ /* merging into the same lockset is deferred to the caller.
+ * cf. initPVLinks()
+ */
+ dbLockSetMerge(NULL, plink->precord, dbaddr.precord);
+ assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);
+ return 0;
+}
+
+void dbDbAddLink(dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptarget)
+{
+ plink->lset = &dbDb_lset;
+ plink->type = DB_LINK;
+ plink->value.pv_link.pvt = ptarget;
+ ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);
+
+ /* target record is already locked in dbPutFieldLink() */
+ dbLockSetMerge(locker, plink->precord, ptarget->precord);
+}
+
+static void dbDbRemoveLink(dbLocker *locker, struct link *plink)
+{
+ DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
+ plink->value.pv_link.pvt = 0;
+ plink->value.pv_link.getCvt = 0;
+ plink->value.pv_link.pvlMask = 0;
+ plink->value.pv_link.lastGetdbrType = 0;
+ plink->type = PV_LINK;
+ plink->lset = NULL;
+ ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
+ dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
+ free(pdbAddr);
+}
+
+static int dbDbIsConnected(const struct link *plink)
+{
+ return TRUE;
+}
+
+static int dbDbGetDBFtype(const struct link *plink)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ return paddr->field_type;
+}
+
+static long dbDbGetElements(const struct link *plink, long *nelements)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ *nelements = paddr->no_elements;
+ return 0;
+}
+
+static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
+ epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+{
+ struct pv_link *ppv_link = &plink->value.pv_link;
+ DBADDR *paddr = ppv_link->pvt;
+ dbCommon *precord = plink->precord;
+ long status;
+
+ /* scan passive records if link is process passive */
+ if (ppv_link->pvlMask & pvlOptPP) {
+ unsigned char pact = precord->pact;
+
+ precord->pact = TRUE;
+ status = dbScanPassive(precord, paddr->precord);
+ precord->pact = pact;
+ if (status)
+ return status;
+ }
+ *pstat = paddr->precord->stat;
+ *psevr = paddr->precord->sevr;
+
+ if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
+ status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ } else {
+ unsigned short dbfType = paddr->field_type;
+
+ if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
+ return S_db_badDbrtype;
+
+ if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
+ && paddr->special != SPC_ATTRIBUTE) {
+ ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
+ status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ } else {
+ ppv_link->getCvt = NULL;
+ status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
+ }
+ ppv_link->lastGetdbrType = dbrType;
+ }
+ return status;
+}
+
+static long dbDbGetControlLimits(const struct link *plink, double *low,
+ double *high)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRctrlDouble
+ double value;
+ } buffer;
+ long options = DBR_CTRL_DOUBLE;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ NULL);
+
+ if (status)
+ return status;
+
+ *low = buffer.lower_ctrl_limit;
+ *high = buffer.upper_ctrl_limit;
+ return 0;
+}
+
+static long dbDbGetGraphicLimits(const struct link *plink, double *low,
+ double *high)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRgrDouble
+ double value;
+ } buffer;
+ long options = DBR_GR_DOUBLE;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ NULL);
+
+ if (status)
+ return status;
+
+ *low = buffer.lower_disp_limit;
+ *high = buffer.upper_disp_limit;
+ return 0;
+}
+
+static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
+ double *low, double *high, double *hihi)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRalDouble
+ double value;
+ } buffer;
+ long options = DBR_AL_DOUBLE;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ 0);
+
+ if (status)
+ return status;
+
+ *lolo = buffer.lower_alarm_limit;
+ *low = buffer.lower_warning_limit;
+ *high = buffer.upper_warning_limit;
+ *hihi = buffer.upper_alarm_limit;
+ return 0;
+}
+
+static long dbDbGetPrecision(const struct link *plink, short *precision)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRprecision
+ double value;
+ } buffer;
+ long options = DBR_PRECISION;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ 0);
+
+ if (status)
+ return status;
+
+ *precision = (short) buffer.precision.dp;
+ return 0;
+}
+
+static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRunits
+ double value;
+ } buffer;
+ long options = DBR_UNITS;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ 0);
+
+ if (status)
+ return status;
+
+ strncpy(units, buffer.units, unitsSize);
+ return 0;
+}
+
+static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
+ epicsEnum16 *severity)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ if (status)
+ *status = paddr->precord->stat;
+ if (severity)
+ *severity = paddr->precord->sevr;
+ return 0;
+}
+
+static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ *pstamp = paddr->precord->time;
+ return 0;
+}
+
+static long dbDbPutValue(struct link *plink, short dbrType,
+ const void *pbuffer, long nRequest)
+{
+ struct pv_link *ppv_link = &plink->value.pv_link;
+ struct dbCommon *psrce = plink->precord;
+ DBADDR *paddr = (DBADDR *) ppv_link->pvt;
+ dbCommon *pdest = paddr->precord;
+ long status = dbPut(paddr, dbrType, pbuffer, nRequest);
+
+ recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,
+ psrce->nsev);
+ if (status)
+ return status;
+
+ if (paddr->pfield == (void *) &pdest->proc ||
+ (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
+ /* if dbPutField caused asyn record to process */
+ /* ask for reprocessing*/
+ if (pdest->putf) {
+ pdest->rpro = TRUE;
+ } else { /* process dest record with source's PACT true */
+ unsigned char pact;
+
+ if (psrce && psrce->ppn)
+ dbNotifyAdd(psrce, pdest);
+ pact = psrce->pact;
+ psrce->pact = TRUE;
+ status = dbProcess(pdest);
+ psrce->pact = pact;
+ }
+ }
+ return status;
+}
+
+static void dbDbScanFwdLink(struct link *plink)
+{
+ dbCommon *precord = plink->precord;
+ dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
+
+ dbScanPassive(precord, paddr->precord);
+}
+
+static lset dbDb_lset = {
+ dbDbRemoveLink,
+ dbDbIsConnected,
+ dbDbGetDBFtype, dbDbGetElements,
+ dbDbGetValue,
+ dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
+ dbDbGetPrecision, dbDbGetUnits,
+ dbDbGetAlarm, dbDbGetTimeStamp,
+ dbDbPutValue,
+ dbDbScanFwdLink
+};
+
diff --git a/src/ioc/db/dbDbLink.h b/src/ioc/db/dbDbLink.h
new file mode 100644
index 000000000..c36772004
--- /dev/null
+++ b/src/ioc/db/dbDbLink.h
@@ -0,0 +1,35 @@
+/*************************************************************************\
+* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* 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.
+\*************************************************************************/
+/* dbDbLink.h
+ *
+ * Created on: April 3rd, 2016
+ * Author: Andrew Johnson
+ */
+
+#ifndef INC_dbDbLink_H
+#define INC_dbDbLink_H
+
+#include "shareLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct link;
+struct dbLocker;
+
+epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);
+epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,
+ short dbfType, DBADDR *ptarget);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_dbDbLink_H */
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index a224eac0f..5faa437bb 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -39,6 +39,7 @@
#include "dbCommon.h"
#include "dbConvertFast.h"
#include "dbConvert.h"
+#include "dbDbLink.h"
#include "dbEvent.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
@@ -56,25 +57,6 @@
#include "recSup.h"
#include "special.h"
-static void inherit_severity(const struct pv_link *ppv_link, dbCommon *pdest,
- epicsEnum16 stat, epicsEnum16 sevr)
-{
- switch (ppv_link->pvlMask & pvlOptMsMode) {
- case pvlOptNMS:
- break;
- case pvlOptMSI:
- if (sevr < INVALID_ALARM)
- break;
- /* Fall through */
- case pvlOptMS:
- recGblSetSevr(pdest, LINK_ALARM, sevr);
- break;
- case pvlOptMSS:
- recGblSetSevr(pdest, stat, sevr);
- break;
- }
-}
-
/* How to identify links in error messages */
static const char * link_field_name(const struct link *plink)
{
@@ -150,298 +132,6 @@ static lset dbConst_lset = {
NULL
};
-/***************************** Database Links *****************************/
-
-/* Forward definition */
-static lset dbDb_lset;
-
-static long dbDbInitLink(struct link *plink, short dbfType)
-{
- DBADDR dbaddr;
- long status;
- DBADDR *pdbAddr;
-
- status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
- if (status)
- return status;
-
- plink->lset = &dbDb_lset;
- plink->type = DB_LINK;
- pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
- *pdbAddr = dbaddr; /* structure copy */
- plink->value.pv_link.pvt = pdbAddr;
- ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
- /* merging into the same lockset is deferred to the caller.
- * cf. initPVLinks()
- */
- dbLockSetMerge(NULL, plink->precord, dbaddr.precord);
- assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);
- return 0;
-}
-
-static void dbDbAddLink(dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptarget)
-{
- plink->lset = &dbDb_lset;
- plink->type = DB_LINK;
- plink->value.pv_link.pvt = ptarget;
- ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);
-
- /* target record is already locked in dbPutFieldLink() */
- dbLockSetMerge(locker, plink->precord, ptarget->precord);
-}
-
-static void dbDbRemoveLink(dbLocker *locker, struct link *plink)
-{
- DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
- plink->value.pv_link.pvt = 0;
- plink->value.pv_link.getCvt = 0;
- plink->value.pv_link.pvlMask = 0;
- plink->value.pv_link.lastGetdbrType = 0;
- plink->type = PV_LINK;
- plink->lset = NULL;
- ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
- dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
- free(pdbAddr);
-}
-
-static int dbDbIsConnected(const struct link *plink)
-{
- return TRUE;
-}
-
-static int dbDbGetDBFtype(const struct link *plink)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- return paddr->field_type;
-}
-
-static long dbDbGetElements(const struct link *plink, long *nelements)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- *nelements = paddr->no_elements;
- return 0;
-}
-
-static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
- epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
-{
- struct pv_link *ppv_link = &plink->value.pv_link;
- DBADDR *paddr = ppv_link->pvt;
- dbCommon *precord = plink->precord;
- long status;
-
- /* scan passive records if link is process passive */
- if (ppv_link->pvlMask & pvlOptPP) {
- unsigned char pact = precord->pact;
-
- precord->pact = TRUE;
- status = dbScanPassive(precord, paddr->precord);
- precord->pact = pact;
- if (status)
- return status;
- }
- *pstat = paddr->precord->stat;
- *psevr = paddr->precord->sevr;
-
- if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
- } else {
- unsigned short dbfType = paddr->field_type;
-
- if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
- return S_db_badDbrtype;
-
- if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
- && paddr->special != SPC_ATTRIBUTE) {
- ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
- } else {
- ppv_link->getCvt = NULL;
- status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
- }
- ppv_link->lastGetdbrType = dbrType;
- }
- return status;
-}
-
-static long dbDbGetControlLimits(const struct link *plink, double *low,
- double *high)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
- struct buffer {
- DBRctrlDouble
- double value;
- } buffer;
- long options = DBR_CTRL_DOUBLE;
- long number_elements = 0;
- long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
- NULL);
-
- if (status)
- return status;
-
- *low = buffer.lower_ctrl_limit;
- *high = buffer.upper_ctrl_limit;
- return 0;
-}
-
-static long dbDbGetGraphicLimits(const struct link *plink, double *low,
- double *high)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
- struct buffer {
- DBRgrDouble
- double value;
- } buffer;
- long options = DBR_GR_DOUBLE;
- long number_elements = 0;
- long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
- NULL);
-
- if (status)
- return status;
-
- *low = buffer.lower_disp_limit;
- *high = buffer.upper_disp_limit;
- return 0;
-}
-
-static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
- double *low, double *high, double *hihi)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
- struct buffer {
- DBRalDouble
- double value;
- } buffer;
- long options = DBR_AL_DOUBLE;
- long number_elements = 0;
- long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
- 0);
-
- if (status)
- return status;
-
- *lolo = buffer.lower_alarm_limit;
- *low = buffer.lower_warning_limit;
- *high = buffer.upper_warning_limit;
- *hihi = buffer.upper_alarm_limit;
- return 0;
-}
-
-static long dbDbGetPrecision(const struct link *plink, short *precision)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
- struct buffer {
- DBRprecision
- double value;
- } buffer;
- long options = DBR_PRECISION;
- long number_elements = 0;
- long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
- 0);
-
- if (status)
- return status;
-
- *precision = (short) buffer.precision.dp;
- return 0;
-}
-
-static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
- struct buffer {
- DBRunits
- double value;
- } buffer;
- long options = DBR_UNITS;
- long number_elements = 0;
- long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
- 0);
-
- if (status)
- return status;
-
- strncpy(units, buffer.units, unitsSize);
- return 0;
-}
-
-static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
- epicsEnum16 *severity)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- if (status)
- *status = paddr->precord->stat;
- if (severity)
- *severity = paddr->precord->sevr;
- return 0;
-}
-
-static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
-{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- *pstamp = paddr->precord->time;
- return 0;
-}
-
-static long dbDbPutValue(struct link *plink, short dbrType,
- const void *pbuffer, long nRequest)
-{
- struct pv_link *ppv_link = &plink->value.pv_link;
- struct dbCommon *psrce = plink->precord;
- DBADDR *paddr = (DBADDR *) ppv_link->pvt;
- dbCommon *pdest = paddr->precord;
- long status = dbPut(paddr, dbrType, pbuffer, nRequest);
-
- inherit_severity(ppv_link, pdest, psrce->nsta, psrce->nsev);
- if (status)
- return status;
-
- if (paddr->pfield == (void *) &pdest->proc ||
- (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
- /* if dbPutField caused asyn record to process */
- /* ask for reprocessing*/
- if (pdest->putf) {
- pdest->rpro = TRUE;
- } else { /* process dest record with source's PACT true */
- unsigned char pact;
-
- if (psrce && psrce->ppn)
- dbNotifyAdd(psrce, pdest);
- pact = psrce->pact;
- psrce->pact = TRUE;
- status = dbProcess(pdest);
- psrce->pact = pact;
- }
- }
- return status;
-}
-
-static void dbDbScanFwdLink(struct link *plink)
-{
- dbCommon *precord = plink->precord;
- dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
-
- dbScanPassive(precord, paddr->precord);
-}
-
-static lset dbDb_lset = {
- dbDbRemoveLink,
- dbDbIsConnected,
- dbDbGetDBFtype, dbDbGetElements,
- dbDbGetValue,
- dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
- dbDbGetPrecision, dbDbGetUnits,
- dbDbGetAlarm, dbDbGetTimeStamp,
- dbDbPutValue,
- dbDbScanFwdLink
-};
-
/***************************** Generic Link API *****************************/
void dbInitLink(struct link *plink, short dbfType)
@@ -587,7 +277,8 @@ long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
if (status) {
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
} else {
- inherit_severity(&plink->value.pv_link, precord, stat, sevr);
+ recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode, precord,
+ stat, sevr);
}
return status;
}
diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c
index 7b7affd97..7ed1293f9 100644
--- a/src/ioc/db/recGbl.c
+++ b/src/ioc/db/recGbl.c
@@ -17,6 +17,7 @@
#include
#include
+#include "alarm.h"
#include "dbDefs.h"
#include "epicsMath.h"
#include "epicsPrint.h"
@@ -214,7 +215,27 @@ int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr)
}
return FALSE;
}
-
+
+void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
+ epicsEnum16 sevr)
+{
+ switch (msMode) {
+ case pvlOptNMS:
+ break;
+ case pvlOptMSI:
+ if (sevr < INVALID_ALARM)
+ break;
+ /* Fall through */
+ case pvlOptMS:
+ recGblSetSevr(precord, LINK_ALARM, sevr);
+ break;
+ case pvlOptMSS:
+ recGblSetSevr(precord, stat, sevr);
+ break;
+ }
+}
+
+
void recGblFwdLink(void *precord)
{
dbCommon *pdbc = precord;
diff --git a/src/ioc/db/recGbl.h b/src/ioc/db/recGbl.h
index e81749a54..8eb589450 100644
--- a/src/ioc/db/recGbl.h
+++ b/src/ioc/db/recGbl.h
@@ -59,6 +59,8 @@ epicsShareFunc int recGblInitConstantLink(struct link *plink,
epicsShareFunc unsigned short recGblResetAlarms(void *precord);
epicsShareFunc int recGblSetSevr(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr);
+epicsShareFunc void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
+ epicsEnum16 sevr);
epicsShareFunc void recGblFwdLink(void *precord);
epicsShareFunc void recGblGetTimeStamp(void *precord);
epicsShareFunc void recGblTSELwasModified(struct link *plink);
From 8a5d1a08adde5bdaa6140baba7e81f12d3903c9b Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 3 Apr 2016 01:29:28 -0500
Subject: [PATCH 002/112] Restore loadLink to lset, move CONSTANT link code
into its own source file
---
src/ioc/db/Makefile | 2 +
src/ioc/db/dbCa.c | 1 +
src/ioc/db/dbConstLink.c | 112 +++++++++++++++++++++++++++++++++++++++
src/ioc/db/dbConstLink.h | 34 ++++++++++++
src/ioc/db/dbDbLink.c | 1 +
src/ioc/db/dbLink.c | 75 ++------------------------
src/ioc/db/dbLink.h | 1 +
7 files changed, 156 insertions(+), 70 deletions(-)
create mode 100644 src/ioc/db/dbConstLink.c
create mode 100644 src/ioc/db/dbConstLink.h
diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile
index 1b83eeaf9..3f08bbe83 100644
--- a/src/ioc/db/Makefile
+++ b/src/ioc/db/Makefile
@@ -18,6 +18,7 @@ INC += dbAddr.h
INC += dbBkpt.h
INC += dbCa.h
INC += dbChannel.h
+INC += dbConstLink.h
INC += dbConvert.h
INC += dbConvertFast.h
INC += dbDbLink.h
@@ -65,6 +66,7 @@ dbCore_SRCS += dbLock.c
dbCore_SRCS += dbAccess.c
dbCore_SRCS += dbBkpt.c
dbCore_SRCS += dbChannel.c
+dbCore_SRCS += dbConstLink.c
dbCore_SRCS += dbConvert.c
dbCore_SRCS += dbDbLink.c
dbCore_SRCS += dbFastLinkConv.c
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index d05b8c7e5..de37682b6 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -709,6 +709,7 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) {
}
static lset dbCa_lset = {
+ NULL,
dbCaRemoveLink,
isConnected,
getDBFtype, getElements,
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
new file mode 100644
index 000000000..4666d6138
--- /dev/null
+++ b/src/ioc/db/dbConstLink.c
@@ -0,0 +1,112 @@
+/*************************************************************************\
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* 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.
+\*************************************************************************/
+/* dbConstLink.c
+ *
+ * Original Authors: Bob Dalesio, Marty Kraimer
+ * Current Author: Andrew Johnson
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "alarm.h"
+#include "cvtFast.h"
+#include "dbDefs.h"
+#include "ellLib.h"
+#include "epicsTime.h"
+#include "errlog.h"
+
+#define epicsExportSharedSymbols
+#include "callback.h"
+#include "dbAccessDefs.h"
+#include "dbAddr.h"
+#include "dbBase.h"
+#include "dbBkpt.h"
+#include "dbCa.h"
+#include "dbCommon.h"
+#include "dbConvertFast.h"
+#include "dbConvert.h"
+#include "dbDbLink.h"
+#include "dbEvent.h"
+#include "db_field_log.h"
+#include "dbFldTypes.h"
+#include "dbFldTypes.h"
+#include "dbLink.h"
+#include "dbLockPvt.h"
+#include "dbNotify.h"
+#include "dbScan.h"
+#include "dbStaticLib.h"
+#include "devSup.h"
+#include "epicsEvent.h"
+#include "errMdef.h"
+#include "link.h"
+#include "recGbl.h"
+#include "recSup.h"
+#include "special.h"
+
+/***************************** Constant Links *****************************/
+
+/* Forward definition */
+static lset dbConst_lset;
+
+void dbConstInitLink(struct link *plink)
+{
+ plink->lset = &dbConst_lset;
+}
+
+void dbConstAddLink(struct link *plink)
+{
+ plink->lset = &dbConst_lset;
+}
+
+static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
+{
+ if (!plink->value.constantStr)
+ return S_db_badField;
+
+ plink->lset = &dbConst_lset;
+
+ /* Constant strings are always numeric */
+ if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
+ dbrType = DBF_USHORT;
+
+ return dbFastPutConvertRoutine[DBR_STRING][dbrType]
+ (plink->value.constantStr, pbuffer, NULL);
+}
+
+static long dbConstGetNelements(const struct link *plink, long *nelements)
+{
+ *nelements = 0;
+ return 0;
+}
+
+static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
+ epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+{
+ if (pnRequest)
+ *pnRequest = 0;
+ return 0;
+}
+
+static lset dbConst_lset = {
+ dbConstLoadLink,
+ NULL,
+ NULL,
+ NULL, dbConstGetNelements,
+ dbConstGetValue,
+ NULL, NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL,
+ NULL
+};
+
diff --git a/src/ioc/db/dbConstLink.h b/src/ioc/db/dbConstLink.h
new file mode 100644
index 000000000..fb598ab9f
--- /dev/null
+++ b/src/ioc/db/dbConstLink.h
@@ -0,0 +1,34 @@
+/*************************************************************************\
+* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* 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.
+\*************************************************************************/
+/* dbConstLink.h
+ *
+ * Created on: April 3rd, 2016
+ * Author: Andrew Johnson
+ */
+
+#ifndef INC_dbConstLink_H
+#define INC_dbConstLink_H
+
+#include "shareLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct link;
+
+epicsShareFunc long dbConstInitLink(struct link *plink);
+epicsShareFunc void dbConstAddLink(struct link *plink);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_dbConstLink_H */
+
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index ab106f77d..f35791f7d 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -331,6 +331,7 @@ static void dbDbScanFwdLink(struct link *plink)
}
static lset dbDb_lset = {
+ NULL,
dbDbRemoveLink,
dbDbIsConnected,
dbDbGetDBFtype, dbDbGetElements,
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index 5faa437bb..c14fecc73 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -19,39 +19,29 @@
#include
#include "alarm.h"
-#include "cantProceed.h"
#include "cvtFast.h"
#include "dbDefs.h"
#include "ellLib.h"
-#include "epicsThread.h"
#include "epicsTime.h"
#include "errlog.h"
#include "caeventmask.h"
#define epicsExportSharedSymbols
-#include "callback.h"
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
-#include "dbBkpt.h"
#include "dbCa.h"
#include "dbCommon.h"
-#include "dbConvertFast.h"
-#include "dbConvert.h"
+#include "dbConstLink.h"
#include "dbDbLink.h"
-#include "dbEvent.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
-#include "dbFldTypes.h"
#include "dbLink.h"
#include "dbLockPvt.h"
-#include "dbNotify.h"
#include "dbScan.h"
#include "dbStaticLib.h"
#include "devSup.h"
-#include "epicsEvent.h"
-#include "errMdef.h"
#include "link.h"
#include "recGbl.h"
#include "recSup.h"
@@ -76,62 +66,6 @@ static const char * link_field_name(const struct link *plink)
}
-/***************************** Constant Links *****************************/
-
-/* Forward definition */
-static lset dbConst_lset;
-
-static void dbConstInitLink(struct link *plink)
-{
- plink->lset = &dbConst_lset;
-}
-
-static void dbConstAddLink(struct link *plink)
-{
- plink->lset = &dbConst_lset;
-}
-
-static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
-{
- if (!plink->value.constantStr)
- return S_db_badField;
-
- plink->lset = &dbConst_lset;
-
- /* Constant strings are always numeric */
- if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
- dbrType = DBF_USHORT;
-
- return dbFastPutConvertRoutine[DBR_STRING][dbrType]
- (plink->value.constantStr, pbuffer, NULL);
-}
-
-static long dbConstGetNelements(const struct link *plink, long *nelements)
-{
- *nelements = 0;
- return 0;
-}
-
-static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
- epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
-{
- if (pnRequest)
- *pnRequest = 0;
- return 0;
-}
-
-static lset dbConst_lset = {
- NULL,
- NULL,
- NULL, dbConstGetNelements,
- dbConstGetValue,
- NULL, NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- NULL,
- NULL
-};
-
/***************************** Generic Link API *****************************/
void dbInitLink(struct link *plink, short dbfType)
@@ -209,10 +143,11 @@ void dbAddLink(dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptar
long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
{
- if (plink->type == CONSTANT)
- return dbConstLoadLink(plink, dbrType, pbuffer);
+ lset *plset = plink->lset;
+
+ if (plset->loadLink)
+ return plset->loadLink(plink, dbrType, pbuffer);
- /* Could pass a type hint to the other link types here */
return S_db_notFound;
}
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index a2e9175df..f33f6aee3 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -28,6 +28,7 @@ extern "C" {
struct dbLocker;
typedef struct lset {
+ long (*loadLink)(struct link *plink, short dbrType, void *pbuffer);
void (*removeLink)(struct dbLocker *locker, struct link *plink);
int (*isConnected)(const struct link *plink);
int (*getDBFtype)(const struct link *plink);
From 0348c2295bb2b5f8cc3f7f7127c4b7e35f3664d7 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 26 Apr 2016 22:13:12 -0500
Subject: [PATCH 003/112] Cleanup
---
src/ioc/db/dbConstLink.c | 22 ----------------------
src/ioc/db/dbDbLink.c | 5 +++--
src/ioc/db/dbLink.c | 6 +++---
3 files changed, 6 insertions(+), 27 deletions(-)
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 4666d6138..022ba7fe9 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -13,45 +13,23 @@
*/
#include
-#include
-#include
#include
-#include
-#include "alarm.h"
#include "cvtFast.h"
#include "dbDefs.h"
-#include "ellLib.h"
-#include "epicsTime.h"
#include "errlog.h"
#define epicsExportSharedSymbols
-#include "callback.h"
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
-#include "dbBkpt.h"
-#include "dbCa.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
#include "dbConvert.h"
-#include "dbDbLink.h"
-#include "dbEvent.h"
-#include "db_field_log.h"
-#include "dbFldTypes.h"
#include "dbFldTypes.h"
#include "dbLink.h"
-#include "dbLockPvt.h"
-#include "dbNotify.h"
-#include "dbScan.h"
-#include "dbStaticLib.h"
-#include "devSup.h"
-#include "epicsEvent.h"
-#include "errMdef.h"
#include "link.h"
#include "recGbl.h"
-#include "recSup.h"
-#include "special.h"
/***************************** Constant Links *****************************/
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index f35791f7d..46c4b7ef6 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -78,7 +78,8 @@ long dbDbInitLink(struct link *plink, short dbfType)
return 0;
}
-void dbDbAddLink(dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptarget)
+void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
+ DBADDR *ptarget)
{
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
@@ -89,7 +90,7 @@ void dbDbAddLink(dbLocker *locker, struct link *plink, short dbfType, DBADDR *pt
dbLockSetMerge(locker, plink->precord, ptarget->precord);
}
-static void dbDbRemoveLink(dbLocker *locker, struct link *plink)
+static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
{
DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
plink->value.pv_link.pvt = 0;
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index c14fecc73..2f8195cc8 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -38,7 +38,6 @@
#include "db_field_log.h"
#include "dbFldTypes.h"
#include "dbLink.h"
-#include "dbLockPvt.h"
#include "dbScan.h"
#include "dbStaticLib.h"
#include "devSup.h"
@@ -110,7 +109,8 @@ void dbInitLink(struct link *plink, short dbfType)
}
}
-void dbAddLink(dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptarget)
+void dbAddLink(dbLocker *locker, struct link *plink, short dbfType,
+ DBADDR *ptarget)
{
struct dbCommon *precord = plink->precord;
@@ -201,7 +201,7 @@ long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
long status;
if (poptions && *poptions) {
- printf("dbGetLinkValue: Use of poptions no longer supported\n");
+ printf("dbGetLink: Use of poptions no longer supported\n");
*poptions = 0;
}
From 778aa18c009480d62b1eb214b34532d631131edd Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 27 Apr 2016 20:29:16 -0500
Subject: [PATCH 004/112] More cleanup
---
src/ioc/db/dbLink.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index 2f8195cc8..dfc02f4fe 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -109,7 +109,7 @@ void dbInitLink(struct link *plink, short dbfType)
}
}
-void dbAddLink(dbLocker *locker, struct link *plink, short dbfType,
+void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
DBADDR *ptarget)
{
struct dbCommon *precord = plink->precord;
@@ -151,7 +151,7 @@ long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
return S_db_notFound;
}
-void dbRemoveLink(dbLocker *locker, struct link *plink)
+void dbRemoveLink(struct dbLocker *locker, struct link *plink)
{
lset *plset = plink->lset;
From 13294f80cc171cb5d1db1f8a653e18f0c68e7b6d Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 27 Apr 2016 20:47:17 -0500
Subject: [PATCH 005/112] Add basic support and tests for a JSON link address
type
---
src/ioc/db/test/dbLinkdset.c | 1 +
src/ioc/db/test/dbLinkdset.dbd | 1 +
src/ioc/db/test/dbPutLinkTest.c | 16 +++++++--
src/ioc/db/test/dbPutLinkTest.db | 4 +++
src/ioc/dbStatic/dbStaticLib.c | 61 ++++++++++++++++++++++++--------
src/ioc/dbStatic/link.h | 10 ++++--
src/tools/DBD/Device.pm | 1 +
7 files changed, 75 insertions(+), 19 deletions(-)
diff --git a/src/ioc/db/test/dbLinkdset.c b/src/ioc/db/test/dbLinkdset.c
index 6e775df7b..c10cdd3bf 100644
--- a/src/ioc/db/test/dbLinkdset.c
+++ b/src/ioc/db/test/dbLinkdset.c
@@ -29,6 +29,7 @@ long link_test_noop(void *junk)
static dset devxLTest ## LTYPE = {4, NULL, &link_test_init, &link_test_noop, &link_test_noop}; \
epicsExportAddress(dset, devxLTest ## LTYPE);
+DEFDSET(JSON_STR)
DEFDSET(VME_IO)
DEFDSET(CAMAC_IO)
DEFDSET(AB_IO)
diff --git a/src/ioc/db/test/dbLinkdset.dbd b/src/ioc/db/test/dbLinkdset.dbd
index 84d5eefe9..14ecaaadf 100644
--- a/src/ioc/db/test/dbLinkdset.dbd
+++ b/src/ioc/db/test/dbLinkdset.dbd
@@ -1,3 +1,4 @@
+device(x, JSON_STR, devxLTestJSON_STR, "Unit Test JSON_STR")
device(x, VME_IO, devxLTestVME_IO, "Unit Test VME_IO")
device(x, CAMAC_IO, devxLTestCAMAC_IO, "Unit Test CAMAC_IO")
device(x, AB_IO, devxLTestAB_IO, "Unit Test AB_IO")
diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c
index 5fcab16b8..1423b6fe4 100644
--- a/src/ioc/db/test/dbPutLinkTest.c
+++ b/src/ioc/db/test/dbPutLinkTest.c
@@ -60,6 +60,7 @@ static const struct testParseDataT {
{"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}},
{" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}},
{" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}},
+ {" {\"x\":{}} ", {JSON_STR, "{\"x\":{}}", 0, "", /*{}*/}},
{NULL}
};
@@ -239,6 +240,7 @@ typedef struct {
} testHWDataT;
static const testHWDataT testHWData[] = {
+ {"rJSON_STR", JSON_STR, "{\"JSON\":{}}", {0}, "{\"JSON\":{}}"},
{"rVME_IO", VME_IO, "#C100 S101 @parm VME_IO", {100, 101}, "parm VME_IO"},
{"rCAMAC_IO", CAMAC_IO, "#B11 C12 N13 A14 F15 @parm CAMAC_IO", {11, 12, 13, 14, 15}, "parm CAMAC_IO"},
{"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"},
@@ -255,6 +257,9 @@ static const testHWDataT testHWData[] = {
static void testLink(DBLINK *plink, const testHWDataT *td)
{
switch(td->ltype) {
+ case JSON_STR:
+ testOk1(strcmp(plink->value.json.string, td->parm)==0);
+ break;
case VME_IO:
testOk1(plink->value.vmeio.card==td->vals[0]);
testOk1(plink->value.vmeio.signal==td->vals[1]);
@@ -360,6 +365,7 @@ static void testHWInitSet(void)
}
static const testHWDataT testHWData2[] = {
+ {"rJSON_STR", JSON_STR, "{\"json\":{}}", {0}, "{\"json\":{}}"},
{"rVME_IO", VME_IO, "#C200 S201 @another VME_IO", {200, 201}, "another VME_IO"},
{"rCAMAC_IO", CAMAC_IO, "#B111 C112 N113 A114 F115 @CAMAC_IO", {111, 112, 113, 114, 115}, "CAMAC_IO"},
{"rAB_IO", AB_IO, "#L121 A122 C123 S124 @another AB_IO", {121, 122, 123, 124}, "another AB_IO"},
@@ -482,9 +488,15 @@ static void testLinkFail(void)
/* INST_IO doesn't accept empty string */
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "");
- /* INST_IO doesn't accept empty string */
+ /* INST_IO doesn't accept string without @ */
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc");
+ /* JSON_STR doesn't accept empty string */
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_STR.INP", DBR_STRING, "");
+
+ /* JSON_STR doesn't accept string without braces */
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_STR.INP", DBR_STRING, "abc");
+
/* syntax errors */
testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO");
testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "C200 #S201");
@@ -504,7 +516,7 @@ static void testLinkFail(void)
MAIN(dbPutLinkTest)
{
- testPlan(251);
+ testPlan(263);
testLinkParse();
testLinkFailParse();
testCADBSet();
diff --git a/src/ioc/db/test/dbPutLinkTest.db b/src/ioc/db/test/dbPutLinkTest.db
index 7753b5b08..421d98f52 100644
--- a/src/ioc/db/test/dbPutLinkTest.db
+++ b/src/ioc/db/test/dbPutLinkTest.db
@@ -3,6 +3,10 @@ record(x, "x2") {}
record(x, "x3") {}
record(x, "x4") {}
+record(x, "rJSON_STR") {
+ field(DTYP, "Unit Test JSON_STR")
+ field(INP, "{\"JSON\":{}}")
+}
record(x, "rVME_IO") {
field(DTYP, "Unit Test VME_IO")
field(INP, "#C100 S101 @parm VME_IO")
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index e0b514c81..6039266ed 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -67,6 +67,7 @@ epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = {
{"GPIB_IO",GPIB_IO},
{"BITBUS_IO",BITBUS_IO},
{"MACRO_LINK",MACRO_LINK},
+ {"JSON_STR",JSON_STR},
{"PN_LINK",PN_LINK},
{"DB_LINK",DB_LINK},
{"CA_LINK",CA_LINK},
@@ -121,6 +122,7 @@ void dbFreeLinkContents(struct link *plink)
case CONSTANT: free((void *)plink->value.constantStr); break;
case MACRO_LINK: free((void *)plink->value.macro_link.macroStr); break;
case PV_LINK: free((void *)plink->value.pv_link.pvname); break;
+ case JSON_STR: parm = plink->value.json.string; break;
case VME_IO: parm = plink->value.vmeio.parm; break;
case CAMAC_IO: parm = plink->value.camacio.parm; break;
case AB_IO: parm = plink->value.abio.parm; break;
@@ -1918,6 +1920,9 @@ char * dbGetString(DBENTRY *pdbentry)
dbMsgCpy(pdbentry, "");
}
break;
+ case JSON_STR:
+ dbMsgCpy(pdbentry, plink->value.json.string);
+ break;
case PN_LINK:
dbMsgPrint(pdbentry, "%s%s",
plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "",
@@ -2169,6 +2174,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
*/
case CONSTANT: plink->value.constantStr = NULL; break;
case PV_LINK: plink->value.pv_link.pvname = callocMustSucceed(1, 1, "init PV_LINK"); break;
+ case JSON_STR: plink->value.json.string = pNullString; break;
case VME_IO: plink->value.vmeio.parm = pNullString; break;
case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
case AB_IO: plink->value.abio.parm = pNullString; break;
@@ -2235,6 +2241,12 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
memcpy(pstr, str, len);
pstr[len] = '\0';
+ /* Check for braces => JSON */
+ if (*str == '{' && str[len-1] == '}') {
+ pinfo->ltype = JSON_STR;
+ return 0;
+ }
+
/* Check for other HW link types */
if (*pstr == '#') {
int ret;
@@ -2336,16 +2348,18 @@ fail:
long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
{
/* consume allocated string pinfo->target on failure */
-
int link_type = CONSTANT;
- if(devsup)
+
+ if (devsup)
link_type = devsup->link_type;
- if(link_type==pinfo->ltype)
+ if (link_type == pinfo->ltype)
return 0;
- switch(pinfo->ltype) {
+
+ switch (pinfo->ltype) {
case CONSTANT:
+ case JSON_STR:
case PV_LINK:
- if(link_type==CONSTANT || link_type==PV_LINK)
+ if (link_type == CONSTANT || link_type == PV_LINK)
return 0;
default:
free(pinfo->target);
@@ -2373,11 +2387,22 @@ void dbSetLinkPV(DBLINK *plink, dbLinkInfo *pinfo)
pinfo->target = NULL;
}
+static
+void dbSetLinkJSON(DBLINK *plink, dbLinkInfo *pinfo)
+{
+ plink->type = JSON_STR;
+ plink->value.json.string = pinfo->target;
+
+ pinfo->target = NULL;
+}
+
static
void dbSetLinkHW(DBLINK *plink, dbLinkInfo *pinfo)
{
-
switch(pinfo->ltype) {
+ case JSON_STR:
+ plink->value.json.string = pinfo->target;
+ break;
case INST_IO:
plink->value.instio.string = pinfo->target;
break;
@@ -2456,27 +2481,33 @@ long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
int ret = 0;
int link_type = CONSTANT;
- if(devsup)
+ if (devsup)
link_type = devsup->link_type;
- if(link_type==CONSTANT || link_type==PV_LINK) {
- switch(pinfo->ltype) {
+ if (link_type == CONSTANT || link_type == PV_LINK) {
+ switch (pinfo->ltype) {
case CONSTANT:
dbFreeLinkContents(plink);
- dbSetLinkConst(plink, pinfo); break;
+ dbSetLinkConst(plink, pinfo);
+ break;
case PV_LINK:
dbFreeLinkContents(plink);
- dbSetLinkPV(plink, pinfo); break;
+ dbSetLinkPV(plink, pinfo);
+ break;
+ case JSON_STR:
+ dbFreeLinkContents(plink);
+ dbSetLinkJSON(plink, pinfo);
+ break;
default:
errlogMessage("Warning: dbSetLink: forgot to test with dbCanSetLink() or logic error");
goto fail; /* can't assign HW link */
}
-
- } else if(link_type==pinfo->ltype) {
+ }
+ else if (link_type == pinfo->ltype) {
dbFreeLinkContents(plink);
dbSetLinkHW(plink, pinfo);
-
- } else
+ }
+ else
goto fail;
return ret;
diff --git a/src/ioc/dbStatic/link.h b/src/ioc/dbStatic/link.h
index e0063a68b..19ab68081 100644
--- a/src/ioc/dbStatic/link.h
+++ b/src/ioc/dbStatic/link.h
@@ -33,7 +33,7 @@ extern "C" {
#define GPIB_IO 5
#define BITBUS_IO 6
#define MACRO_LINK 7
-
+#define JSON_STR 8
#define PN_LINK 9
#define DB_LINK 10
#define CA_LINK 11
@@ -41,7 +41,7 @@ extern "C" {
#define BBGPIB_IO 13 /* bitbus -> gpib */
#define RF_IO 14
#define VXI_IO 15
-#define LINK_NTYPES 15
+#define LINK_NTYPES 16
typedef struct maplinkType {
char *strvalue;
int value;
@@ -87,6 +87,11 @@ struct pv_link {
short lastGetdbrType; /* last dbrType for DB or CA get */
};
+struct json_link {
+ char *string;
+ /* ... */
+};
+
/* structure of a VME io channel */
struct vmeio {
short card;
@@ -167,6 +172,7 @@ struct vxiio {
union value {
char *constantStr; /*constant string*/
struct macro_link macro_link; /* link containing macro substitution*/
+ struct json_link json; /* JSON-encoded link */
struct pv_link pv_link; /* link to process variable*/
struct vmeio vmeio; /* vme io point */
struct camacio camacio; /* camac io point */
diff --git a/src/tools/DBD/Device.pm b/src/tools/DBD/Device.pm
index 5d13a9655..62ee45e28 100644
--- a/src/tools/DBD/Device.pm
+++ b/src/tools/DBD/Device.pm
@@ -5,6 +5,7 @@ use DBD::Base;
my %link_types = (
CONSTANT => qr/$RXnum/o,
PV_LINK => qr/$RXname \s+ [.NPCAMS ]*/ox,
+ JSON_STR => qr/\{ .* \}/ox,
VME_IO => qr/\# (?: \s* [CS] \s* $RXintx)* \s* (?: @ .*)?/ox,
CAMAC_IO => qr/\# (?: \s* [BCNAF] \s* $RXintx)* \s* (?: @ .*)?/ox,
RF_IO => qr/\# (?: \s* [RMDE] \s* $RXintx)*/ox,
From 6a592dc2c00c29c1127e44e45914addd5e97b63f Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 8 May 2016 22:57:42 -0500
Subject: [PATCH 006/112] Support "link(name, lset)" syntax in DBD files
Both Perl and dbStaticLib support included.
Also added a new std/link directory for link types.
Nothing looks up the registered link support tables yet.
---
src/ioc/dbStatic/dbBase.h | 8 +++
src/ioc/dbStatic/dbLex.l | 1 +
src/ioc/dbStatic/dbLexRoutines.c | 21 ++++++
src/ioc/dbStatic/dbStaticIocRegister.c | 9 +++
src/ioc/dbStatic/dbStaticLib.c | 36 ++++++++++
src/ioc/dbStatic/dbStaticLib.h | 5 ++
src/ioc/dbStatic/dbYacc.y | 10 ++-
src/std/Makefile | 1 +
src/std/link/Makefile | 17 +++++
src/std/link/links.dbd.pod | 92 ++++++++++++++++++++++++++
src/std/softIoc/RULES | 2 +
src/std/softIoc/base.dbd | 3 +
src/tools/DBD.pm | 6 ++
src/tools/DBD/Link.pm | 22 ++++++
src/tools/DBD/Output.pm | 9 +++
src/tools/DBD/Parser.pm | 6 ++
src/tools/Makefile | 1 +
17 files changed, 248 insertions(+), 1 deletion(-)
create mode 100644 src/std/link/Makefile
create mode 100644 src/std/link/links.dbd.pod
create mode 100644 src/tools/DBD/Link.pm
diff --git a/src/ioc/dbStatic/dbBase.h b/src/ioc/dbStatic/dbBase.h
index adf5f1d60..de543a1e7 100644
--- a/src/ioc/dbStatic/dbBase.h
+++ b/src/ioc/dbStatic/dbBase.h
@@ -44,6 +44,13 @@ typedef struct devSup {
struct dsxt *pdsxt; /* Extended device support */
}devSup;
+typedef struct linkSup {
+ ELLNODE node;
+ char *name;
+ char *lset_name;
+ struct lset *lset;
+} linkSup;
+
typedef struct dbDeviceMenu {
int nChoice;
char **papChoice;
@@ -162,6 +169,7 @@ typedef struct dbBase {
ELLLIST menuList;
ELLLIST recordTypeList;
ELLLIST drvList;
+ ELLLIST linkList;
ELLLIST registrarList;
ELLLIST functionList;
ELLLIST variableList;
diff --git a/src/ioc/dbStatic/dbLex.l b/src/ioc/dbStatic/dbLex.l
index 681cb1f24..37de82647 100644
--- a/src/ioc/dbStatic/dbLex.l
+++ b/src/ioc/dbStatic/dbLex.l
@@ -38,6 +38,7 @@ static int yyreset(void)
"field" return(tokenFIELD);
"device" return(tokenDEVICE);
"driver" return(tokenDRIVER);
+"link" return(tokenLINK);
"breaktable" return(tokenBREAKTABLE);
"record" return(tokenRECORD);
"grecord" return(tokenGRECORD);
diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c
index 2bbf272c1..6046c91a6 100644
--- a/src/ioc/dbStatic/dbLexRoutines.c
+++ b/src/ioc/dbStatic/dbLexRoutines.c
@@ -75,6 +75,7 @@ static void dbRecordtypeFieldItem(char *name,char *value);
static void dbDevice(char *recordtype,char *linktype,
char *dsetname,char *choicestring);
static void dbDriver(char *name);
+static void dbLinkType(char *name, char *lset_name);
static void dbRegistrar(char *name);
static void dbFunction(char *name);
static void dbVariable(char *name, char *type);
@@ -785,6 +786,26 @@ static void dbDriver(char *name)
ellAdd(&pdbbase->drvList,&pdrvSup->node);
}
+static void dbLinkType(char *name, char *lset_name)
+{
+ linkSup *pLinkSup;
+ GPHENTRY *pgphentry;
+
+ pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->linkList);
+ if (pgphentry) {
+ return;
+ }
+ pLinkSup = dbCalloc(1,sizeof(linkSup));
+ pLinkSup->name = epicsStrDup(name);
+ pLinkSup->lset_name = epicsStrDup(lset_name);
+ pgphentry = gphAdd(pdbbase->pgpHash, pLinkSup->name, &pdbbase->linkList);
+ if (!pgphentry) {
+ yyerrorAbort("gphAdd failed");
+ }
+ pgphentry->userPvt = pLinkSup;
+ ellAdd(&pdbbase->linkList, &pLinkSup->node);
+}
+
static void dbRegistrar(char *name)
{
dbText *ptext;
diff --git a/src/ioc/dbStatic/dbStaticIocRegister.c b/src/ioc/dbStatic/dbStaticIocRegister.c
index 18d346c70..65acc198d 100644
--- a/src/ioc/dbStatic/dbStaticIocRegister.c
+++ b/src/ioc/dbStatic/dbStaticIocRegister.c
@@ -86,6 +86,14 @@ static void dbDumpDriverCallFunc(const iocshArgBuf *args)
dbDumpDriver(*iocshPpdbbase);
}
+/* dbDumpLink */
+static const iocshArg * const dbDumpLinkArgs[] = { &argPdbbase};
+static const iocshFuncDef dbDumpLinkFuncDef = {"dbDumpLink",1,dbDumpLinkArgs};
+static void dbDumpLinkCallFunc(const iocshArgBuf *args)
+{
+ dbDumpLink(*iocshPpdbbase);
+}
+
/* dbDumpRegistrar */
static const iocshArg * const dbDumpRegistrarArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs};
@@ -160,6 +168,7 @@ void dbStaticIocRegister(void)
iocshRegister(&dbDumpFieldFuncDef, dbDumpFieldCallFunc);
iocshRegister(&dbDumpDeviceFuncDef, dbDumpDeviceCallFunc);
iocshRegister(&dbDumpDriverFuncDef, dbDumpDriverCallFunc);
+ iocshRegister(&dbDumpLinkFuncDef, dbDumpLinkCallFunc);
iocshRegister(&dbDumpRegistrarFuncDef,dbDumpRegistrarCallFunc);
iocshRegister(&dbDumpFunctionFuncDef, dbDumpFunctionCallFunc);
iocshRegister(&dbDumpVariableFuncDef, dbDumpVariableCallFunc);
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index 6039266ed..c5774dec8 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -458,6 +458,7 @@ void dbFreeBase(dbBase *pdbbase)
dbVariableDef *pvarNext;
drvSup *pdrvSup;
drvSup *pdrvSupNext;
+ linkSup *plinkSup;
brkTable *pbrkTable;
brkTable *pbrkTableNext;
chFilterPlugin *pfilt;
@@ -558,6 +559,11 @@ void dbFreeBase(dbBase *pdbbase)
free((void *)pdrvSup);
pdrvSup = pdrvSupNext;
}
+ while ((plinkSup = (linkSup *) ellGet(&pdbbase->linkList))) {
+ free(plinkSup->lset_name);
+ free(plinkSup->name);
+ free(plinkSup);
+ }
ptext = (dbText *)ellFirst(&pdbbase->registrarList);
while(ptext) {
ptextNext = (dbText *)ellNext(&ptext->node);
@@ -1070,6 +1076,21 @@ long dbWriteDriverFP(DBBASE *pdbbase,FILE *fp)
return(0);
}
+long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp)
+{
+ linkSup *plinkSup;
+
+ if (!pdbbase) {
+ fprintf(stderr, "pdbbase not specified\n");
+ return -1;
+ }
+ for (plinkSup = (linkSup *) ellFirst(&pdbbase->linkList);
+ plinkSup; plinkSup = (linkSup *) ellNext(&plinkSup->node)) {
+ fprintf(fp, "link(%s,%s)\n", plinkSup->name, plinkSup->lset_name);
+ }
+ return 0;
+}
+
long dbWriteRegistrarFP(DBBASE *pdbbase,FILE *fp)
{
dbText *ptext;
@@ -3107,6 +3128,12 @@ char * dbGetRelatedField(DBENTRY *psave)
return(rtnval);
}
+linkSup* dbFindLinkSup(dbBase *pdbbase, const char *name) {
+ GPHENTRY *pgph = gphFind(pdbbase->pgpHash,name,&pdbbase->linkList);
+ if (!pgph) return NULL;
+ return (linkSup *) pgph->userPvt;
+}
+
int dbGetNLinks(DBENTRY *pdbentry)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -3460,6 +3487,15 @@ void dbDumpDriver(DBBASE *pdbbase)
dbWriteDriverFP(pdbbase,stdout);
}
+void dbDumpLink(DBBASE *pdbbase)
+{
+ if(!pdbbase) {
+ fprintf(stderr,"pdbbase not specified\n");
+ return;
+ }
+ dbWriteLinkFP(pdbbase,stdout);
+}
+
void dbDumpRegistrar(DBBASE *pdbbase)
{
if(!pdbbase) {
diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h
index 93f7f27d2..e01bec25d 100644
--- a/src/ioc/dbStatic/dbStaticLib.h
+++ b/src/ioc/dbStatic/dbStaticLib.h
@@ -99,6 +99,7 @@ epicsShareFunc long dbWriteDeviceFP(DBBASE *pdbbase, FILE *fp);
epicsShareFunc long dbWriteDriver(DBBASE *pdbbase,
const char *filename);
epicsShareFunc long dbWriteDriverFP(DBBASE *pdbbase, FILE *fp);
+epicsShareFunc long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp);
epicsShareFunc long dbWriteRegistrarFP(DBBASE *pdbbase, FILE *fp);
epicsShareFunc long dbWriteFunctionFP(DBBASE *pdbbase, FILE *fp);
epicsShareFunc long dbWriteVariableFP(DBBASE *pdbbase, FILE *fp);
@@ -208,6 +209,9 @@ epicsShareFunc drvSup * dbFindDriver(dbBase *pdbbase,
const char *name);
epicsShareFunc char * dbGetRelatedField(DBENTRY *pdbentry);
+epicsShareFunc linkSup * dbFindLinkSup(dbBase *pdbbase,
+ const char *name);
+
epicsShareFunc int dbGetNLinks(DBENTRY *pdbentry);
epicsShareFunc long dbGetLinkField(DBENTRY *pdbentry, int index);
epicsShareFunc int dbGetLinkType(DBENTRY *pdbentry);
@@ -227,6 +231,7 @@ epicsShareFunc void dbDumpField(DBBASE *pdbbase,
epicsShareFunc void dbDumpDevice(DBBASE *pdbbase,
const char *recordTypeName);
epicsShareFunc void dbDumpDriver(DBBASE *pdbbase);
+epicsShareFunc void dbDumpLink(DBBASE *pdbbase);
epicsShareFunc void dbDumpRegistrar(DBBASE *pdbbase);
epicsShareFunc void dbDumpFunction(DBBASE *pdbbase);
epicsShareFunc void dbDumpVariable(DBBASE *pdbbase);
diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y
index 272f509c4..c5f64eef3 100644
--- a/src/ioc/dbStatic/dbYacc.y
+++ b/src/ioc/dbStatic/dbYacc.y
@@ -20,7 +20,7 @@ static int yyAbort = 0;
%token tokenINCLUDE tokenPATH tokenADDPATH
%token tokenALIAS tokenMENU tokenCHOICE tokenRECORDTYPE
%token tokenFIELD tokenINFO tokenREGISTRAR
-%token tokenDEVICE tokenDRIVER tokenBREAKTABLE
+%token tokenDEVICE tokenDRIVER tokenLINK tokenBREAKTABLE
%token tokenRECORD tokenGRECORD tokenVARIABLE tokenFUNCTION
%token tokenSTRING tokenCDEFS
@@ -46,6 +46,7 @@ database_item: include
| tokenRECORDTYPE recordtype_head recordtype_body
| device
| driver
+ | link
| registrar
| function
| variable
@@ -162,6 +163,13 @@ driver: tokenDRIVER '(' tokenSTRING ')'
dbDriver($3); dbmfFree($3);
};
+link: tokenLINK '(' tokenSTRING ',' tokenSTRING ')'
+{
+ if(dbStaticDebug>2) printf("link %s %s\n",$3,$5);
+ dbLinkType($3,$5);
+ dbmfFree($3); dbmfFree($5);
+};
+
registrar: tokenREGISTRAR '(' tokenSTRING ')'
{
if(dbStaticDebug>2) printf("registrar %s\n",$3);
diff --git a/src/std/Makefile b/src/std/Makefile
index 2065f1f4e..dcfcb6a22 100644
--- a/src/std/Makefile
+++ b/src/std/Makefile
@@ -20,6 +20,7 @@ dbRecStd_RCS += dbRecStd.rc
include $(STDDIR)/rec/Makefile
include $(STDDIR)/dev/Makefile
include $(STDDIR)/filters/Makefile
+include $(STDDIR)/link/Makefile
include $(STDDIR)/softIoc/Makefile
include $(TOP)/configure/RULES
diff --git a/src/std/link/Makefile b/src/std/link/Makefile
new file mode 100644
index 000000000..d2e158475
--- /dev/null
+++ b/src/std/link/Makefile
@@ -0,0 +1,17 @@
+#*************************************************************************
+# 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.
+#*************************************************************************
+
+# This is a Makefile fragment, see src/std/Makefile.
+
+SRC_DIRS += $(STDDIR)/link
+
+DBD += links.dbd
+
+# dbRecStd_SRCS += ...
+
+HTMLS += links.html
+
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
new file mode 100644
index 000000000..c4a5a45cd
--- /dev/null
+++ b/src/std/link/links.dbd.pod
@@ -0,0 +1,92 @@
+=head1 Link Types
+
+Links are an extensible mechanism for adding new kinds of database link,
+using JSON for link addresses.
+The following link types are available in this release:
+
+=over
+
+=item * L
+
+=item * L
+
+=item * L
+
+=back
+
+=head2 Using Links
+
+...
+must appear inside a pair of braces C< {} > expressed as a JSON
+(L) object, which allows link
+parameters to be defined as needed.
+
+Note that due to the required presence of the double-quote characters in the
+JSON strings in a link field value string in a database file, it will usually
+be necessary to escape all double-quote characters in the JSON object by
+preceding them with a backslash C< \ > character.
+Database configuration tools that support this link mechanism must be careful
+to handle these escapes correctly on reading and writing string values from/to
+a .db file.
+
+=head2 Filter Reference
+
+=cut
+
+link(const,lsetConst)
+
+=head3 Constant Link C<"const">
+
+...
+
+=head4 Parameters
+
+...
+
+=head4 Example
+
+ ...
+
+=cut
+
+link(db,lsetDatabase)
+
+=head3 Database Link C<"db">
+
+...
+
+=head4 Parameters
+
+...
+
+=head4 Example
+
+ ...
+
+=cut
+
+link(ca,lsetChannelAccess)
+
+=head3 Channel Access Link C<"ca">
+
+...
+
+=head4 Parameters
+
+...
+
+=over
+
+=item ...
+
+...
+
+=back
+
+...
+
+=head4 Example
+
+ ...
+
+=cut
diff --git a/src/std/softIoc/RULES b/src/std/softIoc/RULES
index cb540ad3c..fc1c6236e 100644
--- a/src/std/softIoc/RULES
+++ b/src/std/softIoc/RULES
@@ -9,8 +9,10 @@
softIoc.dbd$(DEP): $(COMMON_DIR)/stdRecords.dbd
softIoc.dbd$(DEP): $(COMMON_DIR)/filters.dbd
+softIoc.dbd$(DEP): $(COMMON_DIR)/links.dbd
$(COMMON_DIR)/softIoc.dbd: $(COMMON_DIR)/stdRecords.dbd
$(COMMON_DIR)/softIoc.dbd: $(COMMON_DIR)/filters.dbd
+$(COMMON_DIR)/softIoc.dbd: $(COMMON_DIR)/links.dbd
$(COMMON_DIR)/softIoc.dbd: $(STDDIR)/softIoc/Makefile
softMain$(DEP): epicsInstallDir.h
diff --git a/src/std/softIoc/base.dbd b/src/std/softIoc/base.dbd
index 5c5632550..644d8bbaa 100644
--- a/src/std/softIoc/base.dbd
+++ b/src/std/softIoc/base.dbd
@@ -16,6 +16,9 @@ include "stdRecords.dbd"
# Channel filters & plugins
include "filters.dbd"
+# Link types
+include "links.dbd"
+
# Standard device support
include "devSoft.dbd"
diff --git a/src/tools/DBD.pm b/src/tools/DBD.pm
index 3a2a85ee4..aabe26d26 100644
--- a/src/tools/DBD.pm
+++ b/src/tools/DBD.pm
@@ -6,6 +6,7 @@ use warnings;
use DBD::Base;
use DBD::Breaktable;
use DBD::Driver;
+use DBD::Link;
use DBD::Menu;
use DBD::Recordtype;
use DBD::Recfield;
@@ -21,6 +22,7 @@ sub new {
my $this = {
'DBD::Breaktable' => {},
'DBD::Driver' => {},
+ 'DBD::Link' => {},
'DBD::Function' => {},
'DBD::Menu' => {},
'DBD::Recordtype' => {},
@@ -80,6 +82,10 @@ sub drivers {
return shift->{'DBD::Driver'};
}
+sub links {
+ return shift->{'DBD::Link'};
+}
+
sub functions {
return shift->{'DBD::Function'};
}
diff --git a/src/tools/DBD/Link.pm b/src/tools/DBD/Link.pm
new file mode 100644
index 000000000..ac1a14452
--- /dev/null
+++ b/src/tools/DBD/Link.pm
@@ -0,0 +1,22 @@
+package DBD::Link;
+use DBD::Base;
+@ISA = qw(DBD::Base);
+
+sub init {
+ my ($this, $name, $lset) = @_;
+ $this->SUPER::init($lset, "link support (lset)");
+ $this->{KEY} = $name;
+ return $this;
+}
+
+sub key {
+ return shift->{KEY};
+}
+
+sub equals {
+ my ($a, $b) = @_;
+ return $a->SUPER::equals($b)
+ && $a->{KEY} eq $b->{KEY};
+}
+
+1;
diff --git a/src/tools/DBD/Output.pm b/src/tools/DBD/Output.pm
index 6e9d67b3c..cfe5bb196 100644
--- a/src/tools/DBD/Output.pm
+++ b/src/tools/DBD/Output.pm
@@ -13,6 +13,7 @@ use DBD::Base;
use DBD::Breaktable;
use DBD::Device;
use DBD::Driver;
+use DBD::Link;
use DBD::Menu;
use DBD::Recordtype;
use DBD::Recfield;
@@ -26,6 +27,7 @@ sub OutputDBD {
OutputMenus($out, $dbd->menus);
OutputRecordtypes($out, $dbd->recordtypes);
OutputDrivers($out, $dbd->drivers);
+ OutputLinks($out, $dbd->links);
OutputRegistrars($out, $dbd->registrars);
OutputFunctions($out, $dbd->functions);
OutputVariables($out, $dbd->variables);
@@ -78,6 +80,13 @@ sub OutputDrivers {
foreach keys %{$drivers};
}
+sub OutputLinks {
+ my ($out, $links) = @_;
+ while (my ($name, $link) = each %{$links}) {
+ printf $out "link(%s, %s)\n", $link->key, $name;
+ }
+}
+
sub OutputRegistrars {
my ($out, $registrars) = @_;
printf $out "registrar(%s)\n", $_
diff --git a/src/tools/DBD/Parser.pm b/src/tools/DBD/Parser.pm
index fa33bf26e..d36fca555 100644
--- a/src/tools/DBD/Parser.pm
+++ b/src/tools/DBD/Parser.pm
@@ -13,6 +13,7 @@ use DBD::Base;
use DBD::Breaktable;
use DBD::Device;
use DBD::Driver;
+use DBD::Link;
use DBD::Menu;
use DBD::Recordtype;
use DBD::Recfield;
@@ -37,6 +38,11 @@ sub ParseDBD {
my ($driver_name) = unquote($1);
$dbd->add(DBD::Driver->new($driver_name));
}
+ elsif (m/\G link \s* \( \s* $RXstr \s*, \s* $RXstr \s* \)/oxgc) {
+ print "Link $1, $2\n" if $debug;
+ my ($key, $lset) = unquote($1, $2);
+ $dbd->add(DBD::Link->new($key, $lset));
+ }
elsif (m/\G registrar \s* \( \s* $RXstr \s* \)/oxgc) {
print "Registrar: $1\n" if $debug;
my ($registrar_name) = unquote($1);
diff --git a/src/tools/Makefile b/src/tools/Makefile
index 99820d567..8f5aacbed 100644
--- a/src/tools/Makefile
+++ b/src/tools/Makefile
@@ -23,6 +23,7 @@ PERL_MODULES += DBD/Base.pm
PERL_MODULES += DBD/Breaktable.pm
PERL_MODULES += DBD/Device.pm
PERL_MODULES += DBD/Driver.pm
+PERL_MODULES += DBD/Link.pm
PERL_MODULES += DBD/Function.pm
PERL_MODULES += DBD/Menu.pm
PERL_MODULES += DBD/Output.pm
From 574db5674044944ebe729297f556a276be298691 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 19 May 2016 00:51:23 -0500
Subject: [PATCH 007/112] Make antelope's error messages slightly nicer
---
src/libCom/yacc/antelope.c | 6 +++-
src/libCom/yacc/error.c | 62 +++++++++++++++++++-------------------
2 files changed, 36 insertions(+), 32 deletions(-)
diff --git a/src/libCom/yacc/antelope.c b/src/libCom/yacc/antelope.c
index 65d360a58..7143b38ff 100644
--- a/src/libCom/yacc/antelope.c
+++ b/src/libCom/yacc/antelope.c
@@ -115,7 +115,11 @@ getargs(int argc, char *argv[])
int i;
char *s;
- if (argc > 0) myname = argv[0];
+ if (argc > 0) {
+ myname = strrchr(argv[0], '/');
+ if (myname) myname++;
+ else myname = argv[0];
+ }
for (i = 1; i < argc; ++i)
{
s = argv[i];
diff --git a/src/libCom/yacc/error.c b/src/libCom/yacc/error.c
index 2c72241a5..d95c92a3a 100644
--- a/src/libCom/yacc/error.c
+++ b/src/libCom/yacc/error.c
@@ -14,7 +14,7 @@
void
fatal(char *msg)
{
- fprintf(stderr, "%s: f - %s\n", myname, msg);
+ fprintf(stderr, "%s: fatal - %s\n", myname, msg);
done(2);
}
@@ -22,7 +22,7 @@ fatal(char *msg)
void
no_space(void)
{
- fprintf(stderr, "%s: f - out of space\n", myname);
+ fprintf(stderr, "%s: fatal - out of space\n", myname);
done(2);
}
@@ -30,7 +30,7 @@ no_space(void)
void
open_error(char *filename)
{
- fprintf(stderr, "%s: f - cannot open \"%s\"\n", myname, filename);
+ fprintf(stderr, "%s: fatal - cannot open \"%s\"\n", myname, filename);
done(2);
}
@@ -38,7 +38,7 @@ open_error(char *filename)
void
unexpected_EOF(void)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", unexpected end-of-file\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", unexpected end-of-file\n",
myname, lineno, input_file_name);
done(1);
}
@@ -74,7 +74,7 @@ print_pos(char *st_line, char *st_cptr)
void
syntax_error(int st_lineno, char *st_line, char *st_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", syntax error\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", syntax error\n",
myname, st_lineno, input_file_name);
print_pos(st_line, st_cptr);
done(1);
@@ -84,7 +84,7 @@ syntax_error(int st_lineno, char *st_line, char *st_cptr)
void
unterminated_comment(int c_lineno, char *c_line, char *c_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", unmatched /*\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", unmatched /*\n",
myname, c_lineno, input_file_name);
print_pos(c_line, c_cptr);
done(1);
@@ -94,7 +94,7 @@ unterminated_comment(int c_lineno, char *c_line, char *c_cptr)
void
unterminated_string(int s_lineno, char *s_line, char *s_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", unterminated string\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", unterminated string\n",
myname, s_lineno, input_file_name);
print_pos(s_line, s_cptr);
done(1);
@@ -104,7 +104,7 @@ unterminated_string(int s_lineno, char *s_line, char *s_cptr)
void
unterminated_text(int t_lineno, char *t_line, char *t_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", unmatched %%{\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", unmatched %%{\n",
myname, t_lineno, input_file_name);
print_pos(t_line, t_cptr);
done(1);
@@ -114,7 +114,7 @@ unterminated_text(int t_lineno, char *t_line, char *t_cptr)
void
unterminated_union(int u_lineno, char *u_line, char *u_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", unterminated %%union \
+ fprintf(stderr, "%s: error - line %d of \"%s\", unterminated %%union \
declaration\n", myname, u_lineno, input_file_name);
print_pos(u_line, u_cptr);
done(1);
@@ -124,7 +124,7 @@ declaration\n", myname, u_lineno, input_file_name);
void
over_unionized(char *u_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", too many %%union \
+ fprintf(stderr, "%s: error - line %d of \"%s\", too many %%union \
declarations\n", myname, lineno, input_file_name);
print_pos(line, u_cptr);
done(1);
@@ -134,7 +134,7 @@ declarations\n", myname, lineno, input_file_name);
void
illegal_tag(int t_lineno, char *t_line, char *t_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", illegal tag\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", illegal tag\n",
myname, t_lineno, input_file_name);
print_pos(t_line, t_cptr);
done(1);
@@ -144,7 +144,7 @@ illegal_tag(int t_lineno, char *t_line, char *t_cptr)
void
illegal_character(char *c_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", illegal character\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", illegal character\n",
myname, lineno, input_file_name);
print_pos(line, c_cptr);
done(1);
@@ -154,7 +154,7 @@ illegal_character(char *c_cptr)
void
used_reserved(char *s)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", illegal use of reserved symbol \
+ fprintf(stderr, "%s: error - line %d of \"%s\", illegal use of reserved symbol \
%s\n", myname, lineno, input_file_name, s);
done(1);
}
@@ -163,7 +163,7 @@ used_reserved(char *s)
void
tokenized_start(char *s)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", the start symbol %s cannot be \
+ fprintf(stderr, "%s: error - line %d of \"%s\", the start symbol %s cannot be \
declared to be a token\n", myname, lineno, input_file_name, s);
done(1);
}
@@ -172,7 +172,7 @@ declared to be a token\n", myname, lineno, input_file_name, s);
void
retyped_warning(char *s)
{
- fprintf(stderr, "%s: w - line %d of \"%s\", the type of %s has been \
+ fprintf(stderr, "%s: warning - line %d of \"%s\", the type of %s has been \
redeclared\n", myname, lineno, input_file_name, s);
}
@@ -180,7 +180,7 @@ redeclared\n", myname, lineno, input_file_name, s);
void
reprec_warning(char *s)
{
- fprintf(stderr, "%s: w - line %d of \"%s\", the precedence of %s has been \
+ fprintf(stderr, "%s: warning - line %d of \"%s\", the precedence of %s has been \
redeclared\n", myname, lineno, input_file_name, s);
}
@@ -188,7 +188,7 @@ redeclared\n", myname, lineno, input_file_name, s);
void
revalued_warning(char *s)
{
- fprintf(stderr, "%s: w - line %d of \"%s\", the value of %s has been \
+ fprintf(stderr, "%s: warning - line %d of \"%s\", the value of %s has been \
redeclared\n", myname, lineno, input_file_name, s);
}
@@ -196,7 +196,7 @@ redeclared\n", myname, lineno, input_file_name, s);
void
terminal_start(char *s)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", the start symbol %s is a \
+ fprintf(stderr, "%s: error - line %d of \"%s\", the start symbol %s is a \
token\n", myname, lineno, input_file_name, s);
done(1);
}
@@ -205,7 +205,7 @@ token\n", myname, lineno, input_file_name, s);
void
restarted_warning(void)
{
- fprintf(stderr, "%s: w - line %d of \"%s\", the start symbol has been \
+ fprintf(stderr, "%s: warning - line %d of \"%s\", the start symbol has been \
redeclared\n", myname, lineno, input_file_name);
}
@@ -213,7 +213,7 @@ redeclared\n", myname, lineno, input_file_name);
void
no_grammar(void)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", no grammar has been \
+ fprintf(stderr, "%s: error - line %d of \"%s\", no grammar has been \
specified\n", myname, lineno, input_file_name);
done(1);
}
@@ -222,7 +222,7 @@ specified\n", myname, lineno, input_file_name);
void
terminal_lhs(int s_lineno)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", a token appears on the lhs \
+ fprintf(stderr, "%s: error - line %d of \"%s\", a token appears on the lhs \
of a production\n", myname, s_lineno, input_file_name);
done(1);
}
@@ -231,7 +231,7 @@ of a production\n", myname, s_lineno, input_file_name);
void
prec_redeclared(void)
{
- fprintf(stderr, "%s: w - line %d of \"%s\", conflicting %%prec \
+ fprintf(stderr, "%s: warning - line %d of \"%s\", conflicting %%prec \
specifiers\n", myname, lineno, input_file_name);
}
@@ -239,7 +239,7 @@ specifiers\n", myname, lineno, input_file_name);
void
unterminated_action(int a_lineno, char *a_line, char *a_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", unterminated action\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", unterminated action\n",
myname, a_lineno, input_file_name);
print_pos(a_line, a_cptr);
done(1);
@@ -249,7 +249,7 @@ unterminated_action(int a_lineno, char *a_line, char *a_cptr)
void
dollar_warning(int a_lineno, int i)
{
- fprintf(stderr, "%s: w - line %d of \"%s\", $%d references beyond the \
+ fprintf(stderr, "%s: warning - line %d of \"%s\", $%d references beyond the \
end of the current rule\n", myname, a_lineno, input_file_name, i);
}
@@ -257,7 +257,7 @@ end of the current rule\n", myname, a_lineno, input_file_name, i);
void
dollar_error(int a_lineno, char *a_line, char *a_cptr)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", illegal $-name\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", illegal $-name\n",
myname, a_lineno, input_file_name);
print_pos(a_line, a_cptr);
done(1);
@@ -267,7 +267,7 @@ dollar_error(int a_lineno, char *a_line, char *a_cptr)
void
untyped_lhs(void)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", $$ is untyped\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", $$ is untyped\n",
myname, lineno, input_file_name);
done(1);
}
@@ -276,7 +276,7 @@ untyped_lhs(void)
void
untyped_rhs(int i, char *s)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", $%d (%s) is untyped\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", $%d (%s) is untyped\n",
myname, lineno, input_file_name, i, s);
done(1);
}
@@ -285,7 +285,7 @@ untyped_rhs(int i, char *s)
void
unknown_rhs(int i)
{
- fprintf(stderr, "%s: e - line %d of \"%s\", $%d is untyped\n",
+ fprintf(stderr, "%s: error - line %d of \"%s\", $%d is untyped\n",
myname, lineno, input_file_name, i);
done(1);
}
@@ -294,7 +294,7 @@ unknown_rhs(int i)
void
default_action_warning(void)
{
- fprintf(stderr, "%s: w - line %d of \"%s\", the default action assigns an \
+ fprintf(stderr, "%s: warning - line %d of \"%s\", the default action assigns an \
undefined value to $$\n", myname, lineno, input_file_name);
}
@@ -302,7 +302,7 @@ undefined value to $$\n", myname, lineno, input_file_name);
void
undefined_goal(char *s)
{
- fprintf(stderr, "%s: e - the start symbol %s is undefined\n", myname, s);
+ fprintf(stderr, "%s: error - the start symbol %s is undefined\n", myname, s);
done(1);
}
@@ -310,5 +310,5 @@ undefined_goal(char *s)
void
undefined_symbol_warning(char *s)
{
- fprintf(stderr, "%s: w - the symbol %s is undefined\n", myname, s);
+ fprintf(stderr, "%s: warning - the symbol %s is undefined\n", myname, s);
}
From efb5ba27ae23b370c8e45a18ffba6ef06eaecf84 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 19 May 2016 00:58:45 -0500
Subject: [PATCH 008/112] libCom/dbmf: Add dbmfStrcat3() for JSON parsing
Also removed all epicsShareAPI attributes
Made string arguments const char *
---
src/libCom/dbmf/dbmf.c | 39 +++++++++++++++++++++++++--------------
src/libCom/dbmf/dbmf.h | 14 ++++++++------
2 files changed, 33 insertions(+), 20 deletions(-)
diff --git a/src/libCom/dbmf/dbmf.c b/src/libCom/dbmf/dbmf.c
index f5545cb88..03be8ea32 100644
--- a/src/libCom/dbmf/dbmf.c
+++ b/src/libCom/dbmf/dbmf.c
@@ -68,7 +68,7 @@ dbmfPrivate dbmfPvt;
static dbmfPrivate *pdbmfPvt = NULL;
int dbmfDebug=0;
-int epicsShareAPI dbmfInit(size_t size, int chunkItems)
+int dbmfInit(size_t size, int chunkItems)
{
if(pdbmfPvt) {
printf("dbmfInit: Already initialized\n");
@@ -94,7 +94,7 @@ int epicsShareAPI dbmfInit(size_t size, int chunkItems)
}
-void* epicsShareAPI dbmfMalloc(size_t size)
+void* dbmfMalloc(size_t size)
{
void **pnextFree;
void **pfreeList;
@@ -156,15 +156,15 @@ void* epicsShareAPI dbmfMalloc(size_t size)
return((void *)pmem);
}
-char * epicsShareAPI dbmfStrdup(unsigned char *str)
+char * dbmfStrdup(const char *str)
{
- size_t len = strlen((char *) str);
+ size_t len = strlen(str);
char *buf = dbmfMalloc(len + 1);
- strcpy(buf, (char *) str);
+ strcpy(buf, str);
return buf;
}
-void epicsShareAPI dbmfFree(void* mem)
+void dbmfFree(void* mem)
{
char *pmem = (char *)mem;
chunkNode *pchunkNode;
@@ -194,7 +194,7 @@ void epicsShareAPI dbmfFree(void* mem)
epicsMutexUnlock(pdbmfPvt->lock);
}
-int epicsShareAPI dbmfShow(int level)
+int dbmfShow(int level)
{
if(pdbmfPvt==NULL) {
printf("Never initialized\n");
@@ -230,7 +230,7 @@ int epicsShareAPI dbmfShow(int level)
return(0);
}
-void epicsShareAPI dbmfFreeChunks(void)
+void dbmfFreeChunks(void)
{
chunkNode *pchunkNode;
chunkNode *pnext;;
@@ -259,21 +259,32 @@ void epicsShareAPI dbmfFreeChunks(void)
#else /* DBMF_FREELIST_DEBUG */
-int epicsShareAPI dbmfInit(size_t size, int chunkItems)
+int dbmfInit(size_t size, int chunkItems)
{ return 0; }
-void* epicsShareAPI dbmfMalloc(size_t size)
+void* dbmfMalloc(size_t size)
{ return malloc(size); }
-char * epicsShareAPI dbmfStrdup(unsigned char *str)
+char * dbmfStrdup(const char *str)
{ return strdup((char*)str); }
-void epicsShareAPI dbmfFree(void* mem)
+void dbmfFree(void* mem)
{ free(mem); }
-int epicsShareAPI dbmfShow(int level)
+int dbmfShow(int level)
{ return 0; }
-void epicsShareAPI dbmfFreeChunks(void) {}
+void dbmfFreeChunks(void) {}
#endif /* DBMF_FREELIST_DEBUG */
+
+char * dbmfStrcat3(const char *lhs, const char *mid, const char *rhs)
+{
+ size_t len = strlen(lhs) + strlen(mid) + strlen(rhs) + 1;
+ char *buf = dbmfMalloc(len);
+ strcpy(buf, lhs);
+ strcat(buf, mid);
+ strcat(buf, rhs);
+ return buf;
+}
+
diff --git a/src/libCom/dbmf/dbmf.h b/src/libCom/dbmf/dbmf.h
index 3740e532e..a641d66c7 100644
--- a/src/libCom/dbmf/dbmf.h
+++ b/src/libCom/dbmf/dbmf.h
@@ -23,12 +23,14 @@
extern "C" {
#endif
-epicsShareFunc int epicsShareAPI dbmfInit(size_t size, int chunkItems);
-epicsShareFunc void * epicsShareAPI dbmfMalloc(size_t bytes);
-epicsShareFunc char * epicsShareAPI dbmfStrdup(unsigned char *str);
-epicsShareFunc void epicsShareAPI dbmfFree(void* bytes);
-epicsShareFunc void epicsShareAPI dbmfFreeChunks(void);
-epicsShareFunc int epicsShareAPI dbmfShow(int level);
+epicsShareFunc int dbmfInit(size_t size, int chunkItems);
+epicsShareFunc void * dbmfMalloc(size_t bytes);
+epicsShareFunc char * dbmfStrdup(const char *str);
+epicsShareFunc char * dbmfStrcat3(const char *lhs, const char *mid,
+ const char *rhs);
+epicsShareFunc void dbmfFree(void *bytes);
+epicsShareFunc void dbmfFreeChunks(void);
+epicsShareFunc int dbmfShow(int level);
/* Rules:
* 1) Size is always made a multiple of 8.
From 28b3b1678c38be419a750ac1816a1ae9fa9763ba Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 19 May 2016 01:15:33 -0500
Subject: [PATCH 009/112] ioc/dbStatic: Add JSON parsing of field values
The parsing removes all white-space outside of quotes from the JSON.
dbRecordField() now strips quotes from simple string values itself.
---
src/ioc/dbStatic/dbLex.l | 44 ++++++++++++++++---
src/ioc/dbStatic/dbLexRoutines.c | 5 +++
src/ioc/dbStatic/dbYacc.y | 75 +++++++++++++++++++++++++++++---
3 files changed, 111 insertions(+), 13 deletions(-)
diff --git a/src/ioc/dbStatic/dbLex.l b/src/ioc/dbStatic/dbLex.l
index 37de82647..e79120a0e 100644
--- a/src/ioc/dbStatic/dbLex.l
+++ b/src/ioc/dbStatic/dbLex.l
@@ -1,11 +1,12 @@
/*************************************************************************\
-* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
+* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* 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.
\*************************************************************************/
+
newline "\n"
backslash "\\"
doublequote "\""
@@ -15,6 +16,18 @@ escape {backslash}.
stringchar [^"\n\\]
bareword [a-zA-Z0-9_\-+:.\[\]<>;]
+punctuation [:,\[\]{}]
+normalchar [^"\\\0-\x1f]
+escapedchar ({backslash}["\\/bfnrt])
+hexdigit [0-9a-fA-F]
+unicodechar ({backslash}"u"{hexdigit}{4})
+jsonchar ({normalchar}|{escapedchar}|{unicodechar})
+jsondqstr ({doublequote}{jsonchar}*{doublequote})
+int ("-"?([0-9]|[1-9][0-9]+))
+frac ("."[0-9]+)
+exp ([eE][+-]?[0-9]+)
+number ({int}{frac}?{exp}?)
+
%{
#undef YY_INPUT
#define YY_INPUT(b,r,ms) (r=(*db_yyinput)((char *)b,ms))
@@ -27,6 +40,8 @@ static int yyreset(void)
%}
+%x JSON
+
%%
"include" return(tokenINCLUDE);
@@ -49,18 +64,18 @@ static int yyreset(void)
"variable" return(tokenVARIABLE);
{bareword}+ { /* unquoted string or number */
- yylval.Str = dbmfStrdup(yytext);
+ yylval.Str = dbmfStrdup((char *) yytext);
return(tokenSTRING);
}
{doublequote}({stringchar}|{escape})*{doublequote} { /* quoted string */
- yylval.Str = dbmfStrdup(yytext+1);
+ yylval.Str = dbmfStrdup((char *) yytext+1);
yylval.Str[strlen(yylval.Str)-1] = '\0';
return(tokenSTRING);
}
%.* { /*C definition in recordtype*/
- yylval.Str = dbmfStrdup(yytext+1);
+ yylval.Str = dbmfStrdup((char *) yytext+1);
return(tokenCDEFS);
}
@@ -71,13 +86,30 @@ static int yyreset(void)
"," return(yytext[0]);
{comment}.* ;
-{whitespace} ;
{doublequote}({stringchar}|{escape})*{newline} { /* bad string */
yyerrorAbort("Newline in string, closing quote missing");
}
-. {
+"null" return jsonNULL;
+"true" return jsonTRUE;
+"false" return jsonFALSE;
+
+{punctuation} return yytext[0];
+
+{jsondqstr} {
+ yylval.Str = dbmfStrdup((char *) yytext);
+ return jsonSTRING;
+}
+
+{number} {
+ yylval.Str = dbmfStrdup((char *) yytext);
+ return jsonNUMBER;
+}
+
+{whitespace} ;
+
+. {
char message[40];
YY_BUFFER_STATE *dummy=0;
diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c
index 6046c91a6..ff9f04db1 100644
--- a/src/ioc/dbStatic/dbLexRoutines.c
+++ b/src/ioc/dbStatic/dbLexRoutines.c
@@ -1048,6 +1048,11 @@ static void dbRecordField(char *name,char *value)
yyerror(NULL);
return;
}
+ if (*value == '"') {
+ /* jsonSTRING values still have their quotes */
+ value++;
+ value[strlen(value) - 1] = 0;
+ }
dbTranslateEscape(value, value); /* yuck: in-place, but safe */
status = dbPutString(pdbentry,value);
if(status) {
diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y
index c5f64eef3..abcc11981 100644
--- a/src/ioc/dbStatic/dbYacc.y
+++ b/src/ioc/dbStatic/dbYacc.y
@@ -17,6 +17,11 @@ static int yyAbort = 0;
%start database
+%union
+{
+ char *Str;
+}
+
%token tokenINCLUDE tokenPATH tokenADDPATH
%token tokenALIAS tokenMENU tokenCHOICE tokenRECORDTYPE
%token tokenFIELD tokenINFO tokenREGISTRAR
@@ -24,10 +29,10 @@ static int yyAbort = 0;
%token tokenRECORD tokenGRECORD tokenVARIABLE tokenFUNCTION
%token tokenSTRING tokenCDEFS
-%union
-{
- char *Str;
-}
+%token jsonNULL jsonTRUE jsonFALSE
+%token jsonNUMBER jsonSTRING
+%type json_value json_object json_array
+%type json_members json_pair json_elements
%%
@@ -247,10 +252,11 @@ record_body: /* empty */
record_field_list: record_field_list record_field
| record_field;
-record_field: tokenFIELD '(' tokenSTRING ',' tokenSTRING ')'
+record_field: tokenFIELD '(' tokenSTRING ','
+ { BEGIN JSON; } json_value { BEGIN INITIAL; } ')'
{
- if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$5);
- dbRecordField($3,$5); dbmfFree($3); dbmfFree($5);
+ if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$6);
+ dbRecordField($3,$6); dbmfFree($3); dbmfFree($6);
}
| tokenINFO '(' tokenSTRING ',' tokenSTRING ')'
{
@@ -270,6 +276,61 @@ alias: tokenALIAS '(' tokenSTRING ',' tokenSTRING ')'
dbAlias($3,$5); dbmfFree($3); dbmfFree($5);
};
+json_object: '{' '}'
+{
+ $$ = "{}";
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+}
+ | '{' json_members '}'
+{
+ $$ = dbmfStrcat3("{", $2, "}");
+ dbmfFree($2);
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+};
+
+json_members: json_pair
+ | json_pair ',' json_members
+{
+ $$ = dbmfStrcat3($1, ",", $3);
+ dbmfFree($1); dbmfFree($3);
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+};
+
+json_pair: jsonSTRING ':' json_value
+{
+ $$ = dbmfStrcat3($1, ":", $3);
+ dbmfFree($1); dbmfFree($3);
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+};
+
+json_array: '[' ']'
+{
+ $$ = "[]";
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+}
+ | '[' json_elements ']'
+{
+ $$ = dbmfStrcat3("[", $2, "]");
+ dbmfFree($2);
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+};
+
+json_elements: json_value
+ | json_value ',' json_elements
+{
+ $$ = dbmfStrcat3($1, ",", $3);
+ dbmfFree($1); dbmfFree($3);
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+};
+
+json_value: jsonNULL { $$ = "null"; }
+ | jsonTRUE { $$ = "true"; }
+ | jsonFALSE { $$ = "false"; }
+ | jsonNUMBER
+ | jsonSTRING
+ | json_array
+ | json_object ;
+
%%
From 61e82ee1ae7c01c8c4eab46d6f81533a8fa63046 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 19 May 2016 01:32:12 -0500
Subject: [PATCH 010/112] Fix memory allocation bugs
---
src/ioc/dbStatic/dbYacc.y | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y
index abcc11981..870ff01b0 100644
--- a/src/ioc/dbStatic/dbYacc.y
+++ b/src/ioc/dbStatic/dbYacc.y
@@ -278,7 +278,7 @@ alias: tokenALIAS '(' tokenSTRING ',' tokenSTRING ')'
json_object: '{' '}'
{
- $$ = "{}";
+ $$ = dbmfStrdup("{}");
if (dbStaticDebug>2) printf("json %s\n", $$);
}
| '{' json_members '}'
@@ -305,7 +305,7 @@ json_pair: jsonSTRING ':' json_value
json_array: '[' ']'
{
- $$ = "[]";
+ $$ = dbmfStrdup("[]");
if (dbStaticDebug>2) printf("json %s\n", $$);
}
| '[' json_elements ']'
@@ -323,9 +323,9 @@ json_elements: json_value
if (dbStaticDebug>2) printf("json %s\n", $$);
};
-json_value: jsonNULL { $$ = "null"; }
- | jsonTRUE { $$ = "true"; }
- | jsonFALSE { $$ = "false"; }
+json_value: jsonNULL { $$ = dbmfStrdup("null"); }
+ | jsonTRUE { $$ = dbmfStrdup("true"); }
+ | jsonFALSE { $$ = dbmfStrdup("false"); }
| jsonNUMBER
| jsonSTRING
| json_array
From 6e6ae4354b1c30d3bc6de191fa3d2c11ffd69ad2 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 19 May 2016 14:01:05 -0500
Subject: [PATCH 011/112] Fix warnings from dbmfStrdup() change
---
src/ioc/dbtemplate/dbLoadTemplate_lex.l | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/ioc/dbtemplate/dbLoadTemplate_lex.l b/src/ioc/dbtemplate/dbLoadTemplate_lex.l
index afb729517..c6a99a8a1 100644
--- a/src/ioc/dbtemplate/dbLoadTemplate_lex.l
+++ b/src/ioc/dbtemplate/dbLoadTemplate_lex.l
@@ -24,13 +24,13 @@ bareword [a-zA-Z0-9_\-+:./\\\[\]<>;]
{doublequote}({dstringchar}|{escape})*{doublequote} |
{singlequote}({sstringchar}|{escape})*{singlequote} {
- yylval.Str = dbmfStrdup(yytext+1);
+ yylval.Str = dbmfStrdup((char *) yytext+1);
yylval.Str[strlen(yylval.Str)-1] = '\0';
return(QUOTE);
}
{bareword}+ {
- yylval.Str = dbmfStrdup(yytext);
+ yylval.Str = dbmfStrdup((char *) yytext);
return(WORD);
}
From 7ea544673a628e2367916e2eb5c1b1c1f5e449b1 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 20 May 2016 00:02:45 -0500
Subject: [PATCH 012/112] Accept bareword JSON strings, quote them
---
src/ioc/dbStatic/dbLex.l | 6 ++++++
src/ioc/dbStatic/dbYacc.y | 16 ++++++++++++----
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/ioc/dbStatic/dbLex.l b/src/ioc/dbStatic/dbLex.l
index e79120a0e..d4f232518 100644
--- a/src/ioc/dbStatic/dbLex.l
+++ b/src/ioc/dbStatic/dbLex.l
@@ -18,6 +18,7 @@ bareword [a-zA-Z0-9_\-+:.\[\]<>;]
punctuation [:,\[\]{}]
normalchar [^"\\\0-\x1f]
+barechar [a-zA-Z0-9_\-+.]
escapedchar ({backslash}["\\/bfnrt])
hexdigit [0-9a-fA-F]
unicodechar ({backslash}"u"{hexdigit}{4})
@@ -102,6 +103,11 @@ static int yyreset(void)
return jsonSTRING;
}
+{barechar}+ {
+ yylval.Str = dbmfStrdup((char *) yytext);
+ return jsonBARE;
+}
+
{number} {
yylval.Str = dbmfStrdup((char *) yytext);
return jsonNUMBER;
diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y
index 870ff01b0..25df127ed 100644
--- a/src/ioc/dbStatic/dbYacc.y
+++ b/src/ioc/dbStatic/dbYacc.y
@@ -30,9 +30,9 @@ static int yyAbort = 0;
%token tokenSTRING tokenCDEFS
%token jsonNULL jsonTRUE jsonFALSE
-%token jsonNUMBER jsonSTRING
+%token jsonNUMBER jsonSTRING jsonBARE
%type json_value json_object json_array
-%type json_members json_pair json_elements
+%type json_members json_pair json_elements json_string
%%
@@ -296,13 +296,21 @@ json_members: json_pair
if (dbStaticDebug>2) printf("json %s\n", $$);
};
-json_pair: jsonSTRING ':' json_value
+json_pair: json_string ':' json_value
{
$$ = dbmfStrcat3($1, ":", $3);
dbmfFree($1); dbmfFree($3);
if (dbStaticDebug>2) printf("json %s\n", $$);
};
+json_string: jsonSTRING
+ | jsonBARE
+{
+ $$ = dbmfStrcat3("\"", $1, "\"");
+ dbmfFree($1);
+ if (dbStaticDebug>2) printf("json %s\n", $$);
+};
+
json_array: '[' ']'
{
$$ = dbmfStrdup("[]");
@@ -327,7 +335,7 @@ json_value: jsonNULL { $$ = dbmfStrdup("null"); }
| jsonTRUE { $$ = dbmfStrdup("true"); }
| jsonFALSE { $$ = dbmfStrdup("false"); }
| jsonNUMBER
- | jsonSTRING
+ | json_string
| json_array
| json_object ;
From c76041b14c73bccf440861f87c1378fb675f1cc6 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 20 May 2016 20:32:39 -0500
Subject: [PATCH 013/112] Rename JSON_STR to JSON_LINK
---
src/ioc/db/test/dbLinkdset.c | 2 +-
src/ioc/db/test/dbLinkdset.dbd | 2 +-
src/ioc/db/test/dbPutLinkTest.c | 16 ++++++++--------
src/ioc/db/test/dbPutLinkTest.db | 4 ++--
src/ioc/dbStatic/dbStaticLib.c | 18 +++++++++---------
src/ioc/dbStatic/link.h | 2 +-
src/tools/DBD/Device.pm | 2 +-
7 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/src/ioc/db/test/dbLinkdset.c b/src/ioc/db/test/dbLinkdset.c
index c10cdd3bf..d7b8230f0 100644
--- a/src/ioc/db/test/dbLinkdset.c
+++ b/src/ioc/db/test/dbLinkdset.c
@@ -29,7 +29,7 @@ long link_test_noop(void *junk)
static dset devxLTest ## LTYPE = {4, NULL, &link_test_init, &link_test_noop, &link_test_noop}; \
epicsExportAddress(dset, devxLTest ## LTYPE);
-DEFDSET(JSON_STR)
+DEFDSET(JSON_LINK)
DEFDSET(VME_IO)
DEFDSET(CAMAC_IO)
DEFDSET(AB_IO)
diff --git a/src/ioc/db/test/dbLinkdset.dbd b/src/ioc/db/test/dbLinkdset.dbd
index 14ecaaadf..da2d4d946 100644
--- a/src/ioc/db/test/dbLinkdset.dbd
+++ b/src/ioc/db/test/dbLinkdset.dbd
@@ -1,4 +1,4 @@
-device(x, JSON_STR, devxLTestJSON_STR, "Unit Test JSON_STR")
+device(x, JSON_LINK, devxLTestJSON_LINK, "Unit Test JSON_LINK")
device(x, VME_IO, devxLTestVME_IO, "Unit Test VME_IO")
device(x, CAMAC_IO, devxLTestCAMAC_IO, "Unit Test CAMAC_IO")
device(x, AB_IO, devxLTestAB_IO, "Unit Test AB_IO")
diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c
index 1423b6fe4..76813c2fd 100644
--- a/src/ioc/db/test/dbPutLinkTest.c
+++ b/src/ioc/db/test/dbPutLinkTest.c
@@ -60,7 +60,7 @@ static const struct testParseDataT {
{"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}},
{" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}},
{" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}},
- {" {\"x\":{}} ", {JSON_STR, "{\"x\":{}}", 0, "", /*{}*/}},
+ {" {\"x\":{}} ", {JSON_LINK, "{\"x\":{}}", 0, "", /*{}*/}},
{NULL}
};
@@ -240,7 +240,7 @@ typedef struct {
} testHWDataT;
static const testHWDataT testHWData[] = {
- {"rJSON_STR", JSON_STR, "{\"JSON\":{}}", {0}, "{\"JSON\":{}}"},
+ {"rJSON_LINK", JSON_LINK, "{\"JSON\":{}}", {0}, "{\"JSON\":{}}"},
{"rVME_IO", VME_IO, "#C100 S101 @parm VME_IO", {100, 101}, "parm VME_IO"},
{"rCAMAC_IO", CAMAC_IO, "#B11 C12 N13 A14 F15 @parm CAMAC_IO", {11, 12, 13, 14, 15}, "parm CAMAC_IO"},
{"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"},
@@ -257,7 +257,7 @@ static const testHWDataT testHWData[] = {
static void testLink(DBLINK *plink, const testHWDataT *td)
{
switch(td->ltype) {
- case JSON_STR:
+ case JSON_LINK:
testOk1(strcmp(plink->value.json.string, td->parm)==0);
break;
case VME_IO:
@@ -365,7 +365,7 @@ static void testHWInitSet(void)
}
static const testHWDataT testHWData2[] = {
- {"rJSON_STR", JSON_STR, "{\"json\":{}}", {0}, "{\"json\":{}}"},
+ {"rJSON_LINK", JSON_LINK, "{\"json\":{}}", {0}, "{\"json\":{}}"},
{"rVME_IO", VME_IO, "#C200 S201 @another VME_IO", {200, 201}, "another VME_IO"},
{"rCAMAC_IO", CAMAC_IO, "#B111 C112 N113 A114 F115 @CAMAC_IO", {111, 112, 113, 114, 115}, "CAMAC_IO"},
{"rAB_IO", AB_IO, "#L121 A122 C123 S124 @another AB_IO", {121, 122, 123, 124}, "another AB_IO"},
@@ -491,11 +491,11 @@ static void testLinkFail(void)
/* INST_IO doesn't accept string without @ */
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc");
- /* JSON_STR doesn't accept empty string */
- testdbPutFieldFail(S_dbLib_badField, "rJSON_STR.INP", DBR_STRING, "");
+ /* JSON_LINK doesn't accept empty string */
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "");
- /* JSON_STR doesn't accept string without braces */
- testdbPutFieldFail(S_dbLib_badField, "rJSON_STR.INP", DBR_STRING, "abc");
+ /* JSON_LINK doesn't accept bareword string */
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "abc");
/* syntax errors */
testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO");
diff --git a/src/ioc/db/test/dbPutLinkTest.db b/src/ioc/db/test/dbPutLinkTest.db
index 421d98f52..747666052 100644
--- a/src/ioc/db/test/dbPutLinkTest.db
+++ b/src/ioc/db/test/dbPutLinkTest.db
@@ -3,8 +3,8 @@ record(x, "x2") {}
record(x, "x3") {}
record(x, "x4") {}
-record(x, "rJSON_STR") {
- field(DTYP, "Unit Test JSON_STR")
+record(x, "rJSON_LINK") {
+ field(DTYP, "Unit Test JSON_LINK")
field(INP, "{\"JSON\":{}}")
}
record(x, "rVME_IO") {
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index c5774dec8..db7a6a3f5 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -67,7 +67,7 @@ epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = {
{"GPIB_IO",GPIB_IO},
{"BITBUS_IO",BITBUS_IO},
{"MACRO_LINK",MACRO_LINK},
- {"JSON_STR",JSON_STR},
+ {"JSON_LINK",JSON_LINK},
{"PN_LINK",PN_LINK},
{"DB_LINK",DB_LINK},
{"CA_LINK",CA_LINK},
@@ -122,7 +122,7 @@ void dbFreeLinkContents(struct link *plink)
case CONSTANT: free((void *)plink->value.constantStr); break;
case MACRO_LINK: free((void *)plink->value.macro_link.macroStr); break;
case PV_LINK: free((void *)plink->value.pv_link.pvname); break;
- case JSON_STR: parm = plink->value.json.string; break;
+ case JSON_LINK: parm = plink->value.json.string; break;
case VME_IO: parm = plink->value.vmeio.parm; break;
case CAMAC_IO: parm = plink->value.camacio.parm; break;
case AB_IO: parm = plink->value.abio.parm; break;
@@ -1941,7 +1941,7 @@ char * dbGetString(DBENTRY *pdbentry)
dbMsgCpy(pdbentry, "");
}
break;
- case JSON_STR:
+ case JSON_LINK:
dbMsgCpy(pdbentry, plink->value.json.string);
break;
case PN_LINK:
@@ -2195,7 +2195,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
*/
case CONSTANT: plink->value.constantStr = NULL; break;
case PV_LINK: plink->value.pv_link.pvname = callocMustSucceed(1, 1, "init PV_LINK"); break;
- case JSON_STR: plink->value.json.string = pNullString; break;
+ case JSON_LINK: plink->value.json.string = pNullString; break;
case VME_IO: plink->value.vmeio.parm = pNullString; break;
case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
case AB_IO: plink->value.abio.parm = pNullString; break;
@@ -2264,7 +2264,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
- pinfo->ltype = JSON_STR;
+ pinfo->ltype = JSON_LINK;
return 0;
}
@@ -2378,7 +2378,7 @@ long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
switch (pinfo->ltype) {
case CONSTANT:
- case JSON_STR:
+ case JSON_LINK:
case PV_LINK:
if (link_type == CONSTANT || link_type == PV_LINK)
return 0;
@@ -2411,7 +2411,7 @@ void dbSetLinkPV(DBLINK *plink, dbLinkInfo *pinfo)
static
void dbSetLinkJSON(DBLINK *plink, dbLinkInfo *pinfo)
{
- plink->type = JSON_STR;
+ plink->type = JSON_LINK;
plink->value.json.string = pinfo->target;
pinfo->target = NULL;
@@ -2421,7 +2421,7 @@ static
void dbSetLinkHW(DBLINK *plink, dbLinkInfo *pinfo)
{
switch(pinfo->ltype) {
- case JSON_STR:
+ case JSON_LINK:
plink->value.json.string = pinfo->target;
break;
case INST_IO:
@@ -2515,7 +2515,7 @@ long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
dbFreeLinkContents(plink);
dbSetLinkPV(plink, pinfo);
break;
- case JSON_STR:
+ case JSON_LINK:
dbFreeLinkContents(plink);
dbSetLinkJSON(plink, pinfo);
break;
diff --git a/src/ioc/dbStatic/link.h b/src/ioc/dbStatic/link.h
index 19ab68081..dc9ccacbc 100644
--- a/src/ioc/dbStatic/link.h
+++ b/src/ioc/dbStatic/link.h
@@ -33,7 +33,7 @@ extern "C" {
#define GPIB_IO 5
#define BITBUS_IO 6
#define MACRO_LINK 7
-#define JSON_STR 8
+#define JSON_LINK 8
#define PN_LINK 9
#define DB_LINK 10
#define CA_LINK 11
diff --git a/src/tools/DBD/Device.pm b/src/tools/DBD/Device.pm
index 62ee45e28..2fa1777d9 100644
--- a/src/tools/DBD/Device.pm
+++ b/src/tools/DBD/Device.pm
@@ -5,7 +5,7 @@ use DBD::Base;
my %link_types = (
CONSTANT => qr/$RXnum/o,
PV_LINK => qr/$RXname \s+ [.NPCAMS ]*/ox,
- JSON_STR => qr/\{ .* \}/ox,
+ JSON_LINK => qr/\{ .* \}/ox,
VME_IO => qr/\# (?: \s* [CS] \s* $RXintx)* \s* (?: @ .*)?/ox,
CAMAC_IO => qr/\# (?: \s* [BCNAF] \s* $RXintx)* \s* (?: @ .*)?/ox,
RF_IO => qr/\# (?: \s* [RMDE] \s* $RXintx)*/ox,
From f6c4099634a314ba5d695202ed99758aa151c5d3 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 23 May 2016 12:00:11 +0200
Subject: [PATCH 014/112] Make info tags also JSON objects
---
src/ioc/dbStatic/dbLexRoutines.c | 6 ++++++
src/ioc/dbStatic/dbYacc.y | 7 ++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c
index ff9f04db1..380844dec 100644
--- a/src/ioc/dbStatic/dbLexRoutines.c
+++ b/src/ioc/dbStatic/dbLexRoutines.c
@@ -1072,6 +1072,12 @@ static void dbRecordInfo(char *name, char *value)
if(duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
+ if (*value == '"') {
+ /* jsonSTRING values still have their quotes */
+ value++;
+ value[strlen(value) - 1] = 0;
+ }
+ dbTranslateEscape(value, value); /* yuck: in-place, but safe */
status = dbPutInfo(pdbentry,name,value);
if(status) {
epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y
index 25df127ed..e61ce58b0 100644
--- a/src/ioc/dbStatic/dbYacc.y
+++ b/src/ioc/dbStatic/dbYacc.y
@@ -258,10 +258,11 @@ record_field: tokenFIELD '(' tokenSTRING ','
if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$6);
dbRecordField($3,$6); dbmfFree($3); dbmfFree($6);
}
- | tokenINFO '(' tokenSTRING ',' tokenSTRING ')'
+ | tokenINFO '(' tokenSTRING ','
+ { BEGIN JSON; } json_value { BEGIN INITIAL; } ')'
{
- if(dbStaticDebug>2) printf("record_info %s %s\n",$3,$5);
- dbRecordInfo($3,$5); dbmfFree($3); dbmfFree($5);
+ if(dbStaticDebug>2) printf("record_info %s %s\n",$3,$6);
+ dbRecordInfo($3,$6); dbmfFree($3); dbmfFree($6);
}
| tokenALIAS '(' tokenSTRING ')'
{
From 08b7802009d200416a81b567768d8b5fbff7f511 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 24 May 2016 11:59:08 +0200
Subject: [PATCH 015/112] Recognize numbers before barewords
---
src/ioc/dbStatic/dbLex.l | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/ioc/dbStatic/dbLex.l b/src/ioc/dbStatic/dbLex.l
index d4f232518..99a3b85cf 100644
--- a/src/ioc/dbStatic/dbLex.l
+++ b/src/ioc/dbStatic/dbLex.l
@@ -103,16 +103,16 @@ static int yyreset(void)
return jsonSTRING;
}
-{barechar}+ {
- yylval.Str = dbmfStrdup((char *) yytext);
- return jsonBARE;
-}
-
{number} {
yylval.Str = dbmfStrdup((char *) yytext);
return jsonNUMBER;
}
+{barechar}+ {
+ yylval.Str = dbmfStrdup((char *) yytext);
+ return jsonBARE;
+}
+
{whitespace} ;
. {
From 1f726c876027894c78c1a18fe2f2de9eb04c288c Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 24 May 2016 12:01:38 +0200
Subject: [PATCH 016/112] Recognize arrays as constant links
---
src/ioc/dbStatic/dbStaticLib.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index db7a6a3f5..c718dacab 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2330,6 +2330,12 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
return 0;
}
+ /* Link may be an array constant */
+ if (pstr[0] == '[' && pstr[len-1] == ']' && strchr(pstr, ',')) {
+ pinfo->ltype = CONSTANT;
+ return 0;
+ }
+
pinfo->ltype = PV_LINK;
pstr = strchr(pstr, ' '); /* find start of link modifiers (can't be seperated by tabs) */
if (pstr) {
From 667f74759db5298a3da8ac9a5c21a9ec159821c9 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 1 Jun 2016 15:46:24 -0500
Subject: [PATCH 017/112] Allow (discard) comments inside JSON
---
src/ioc/dbStatic/dbLex.l | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/ioc/dbStatic/dbLex.l b/src/ioc/dbStatic/dbLex.l
index 99a3b85cf..cfbb5bda4 100644
--- a/src/ioc/dbStatic/dbLex.l
+++ b/src/ioc/dbStatic/dbLex.l
@@ -86,8 +86,6 @@ static int yyreset(void)
")" return(yytext[0]);
"," return(yytext[0]);
-{comment}.* ;
-
{doublequote}({stringchar}|{escape})*{newline} { /* bad string */
yyerrorAbort("Newline in string, closing quote missing");
}
@@ -113,6 +111,8 @@ static int yyreset(void)
return jsonBARE;
}
+{comment}.* ;
+
{whitespace} ;
. {
From 7627454f6301de5879a33ef3942afc37d86533e9 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 2 Jun 2016 22:02:54 -0500
Subject: [PATCH 018/112] Simplify link-type checks in soft device supports
---
src/std/dev/devAaiSoft.c | 13 +------------
src/std/dev/devAaoSoft.c | 13 +------------
src/std/dev/devAiSoft.c | 13 +------------
src/std/dev/devAiSoftRaw.c | 13 +------------
src/std/dev/devBiSoft.c | 13 +------------
src/std/dev/devBiSoftRaw.c | 13 +------------
src/std/dev/devEventSoft.c | 13 +------------
src/std/dev/devHistogramSoft.c | 13 +------------
src/std/dev/devLiSoft.c | 13 +------------
src/std/dev/devMbbiDirectSoft.c | 13 +------------
src/std/dev/devMbbiDirectSoftRaw.c | 13 +------------
src/std/dev/devMbbiSoft.c | 13 +------------
src/std/dev/devMbbiSoftRaw.c | 13 +------------
src/std/dev/devSASoft.c | 13 +------------
src/std/dev/devSiSoft.c | 13 +------------
src/std/dev/devWfSoft.c | 13 +------------
16 files changed, 16 insertions(+), 192 deletions(-)
diff --git a/src/std/dev/devAaiSoft.c b/src/std/dev/devAaiSoft.c
index caaaa50ff..ff985b088 100644
--- a/src/std/dev/devAaiSoft.c
+++ b/src/std/dev/devAaiSoft.c
@@ -52,19 +52,8 @@ epicsExportAddress(dset,devAaiSoft);
static long init_record(aaiRecord *prec)
{
- /* INP must be a CONSTANT or a PV_LINK or a DB_LINK or a CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
prec->nord = 0;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default :
- recGblRecordError(S_db_badField, (void *)prec,
- "devAaiSoft (init_record) Illegal INP field");
- return(S_db_badField);
}
return 0;
}
diff --git a/src/std/dev/devAaoSoft.c b/src/std/dev/devAaoSoft.c
index 61eeb9cdd..a88d61140 100644
--- a/src/std/dev/devAaoSoft.c
+++ b/src/std/dev/devAaoSoft.c
@@ -52,19 +52,8 @@ epicsExportAddress(dset,devAaoSoft);
static long init_record(aaoRecord *prec)
{
- /* OUT must be a CONSTANT or a PV_LINK or a DB_LINK or a CA_LINK*/
- switch (prec->out.type) {
- case CONSTANT:
+ if (prec->out.type == CONSTANT) {
prec->nord = 0;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default :
- recGblRecordError(S_db_badField, prec,
- "devAaoSoft (init_record) Illegal OUT field");
- return(S_db_badField);
}
return 0;
}
diff --git a/src/std/dev/devAiSoft.c b/src/std/dev/devAiSoft.c
index 77ee6dbed..ccd713d75 100644
--- a/src/std/dev/devAiSoft.c
+++ b/src/std/dev/devAiSoft.c
@@ -51,20 +51,9 @@ epicsExportAddress(dset, devAiSoft);
static long init_record(aiRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
if (recGblInitConstantLink(&prec->inp, DBF_DOUBLE, &prec->val))
prec->udf = FALSE;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devAiSoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devAiSoftRaw.c b/src/std/dev/devAiSoftRaw.c
index 0cf5e40f0..fa9d869ed 100644
--- a/src/std/dev/devAiSoftRaw.c
+++ b/src/std/dev/devAiSoftRaw.c
@@ -50,19 +50,8 @@ epicsExportAddress(dset, devAiSoftRaw);
static long init_record(aiRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->rval);
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devAiSoftRaw (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devBiSoft.c b/src/std/dev/devBiSoft.c
index 6c2740693..4b0ee854a 100644
--- a/src/std/dev/devBiSoft.c
+++ b/src/std/dev/devBiSoft.c
@@ -48,20 +48,9 @@ epicsExportAddress(dset, devBiSoft);
static long init_record(biRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
prec->udf = FALSE;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devBiSoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devBiSoftRaw.c b/src/std/dev/devBiSoftRaw.c
index 2afef6356..3f40bade8 100644
--- a/src/std/dev/devBiSoftRaw.c
+++ b/src/std/dev/devBiSoftRaw.c
@@ -48,19 +48,8 @@ epicsExportAddress(dset, devBiSoftRaw);
static long init_record(biRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devBiSoftRaw (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devEventSoft.c b/src/std/dev/devEventSoft.c
index 418da5658..09987cb5b 100644
--- a/src/std/dev/devEventSoft.c
+++ b/src/std/dev/devEventSoft.c
@@ -48,20 +48,9 @@ epicsExportAddress(dset, devEventSoft);
static long init_record(eventRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
if (recGblInitConstantLink(&prec->inp, DBF_STRING, &prec->val))
prec->udf = FALSE;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devEventSoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devHistogramSoft.c b/src/std/dev/devHistogramSoft.c
index cdb4add1e..21a09b52e 100644
--- a/src/std/dev/devHistogramSoft.c
+++ b/src/std/dev/devHistogramSoft.c
@@ -52,20 +52,9 @@ epicsExportAddress(dset,devHistogramSoft);
static long init_record(histogramRecord *prec)
{
- /* histogram.svl must be a CONSTANT or a PV_LINK or a DB_LINK or a CA_LINK*/
- switch (prec->svl.type) {
- case (CONSTANT) :
+ if (prec->svl.type == CONSTANT) {
if(recGblInitConstantLink(&prec->svl,DBF_DOUBLE,&prec->sgnl))
prec->udf = FALSE;
- break;
- case (PV_LINK) :
- case (DB_LINK) :
- case (CA_LINK) :
- break;
- default :
- recGblRecordError(S_db_badField,(void *)prec,
- "devHistogramSoft (init_record) Illegal SVL field");
- return(S_db_badField);
}
return 0;
}
diff --git a/src/std/dev/devLiSoft.c b/src/std/dev/devLiSoft.c
index 11dbedc3f..3deea8493 100644
--- a/src/std/dev/devLiSoft.c
+++ b/src/std/dev/devLiSoft.c
@@ -48,20 +48,9 @@ epicsExportAddress(dset, devLiSoft);
static long init_record(longinRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
if (recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->val))
prec->udf = FALSE;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devLiSoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devMbbiDirectSoft.c b/src/std/dev/devMbbiDirectSoft.c
index 8b7816b65..ccbc7efe7 100644
--- a/src/std/dev/devMbbiDirectSoft.c
+++ b/src/std/dev/devMbbiDirectSoft.c
@@ -48,20 +48,9 @@ epicsExportAddress(dset, devMbbiDirectSoft);
static long init_record(mbbiDirectRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
prec->udf = FALSE;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devMbbiDirectSoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devMbbiDirectSoftRaw.c b/src/std/dev/devMbbiDirectSoftRaw.c
index df8c08f52..3824cdc14 100644
--- a/src/std/dev/devMbbiDirectSoftRaw.c
+++ b/src/std/dev/devMbbiDirectSoftRaw.c
@@ -48,19 +48,8 @@ epicsExportAddress(dset, devMbbiDirectSoftRaw);
static long init_record(mbbiDirectRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devMbbiDirectSoftRaw (init_record) Illegal INP field");
- return S_db_badField;
}
/*to preserve old functionality*/
if (prec->nobt == 0) prec->mask = 0xffffffff;
diff --git a/src/std/dev/devMbbiSoft.c b/src/std/dev/devMbbiSoft.c
index c3b0d28f1..210699fa6 100644
--- a/src/std/dev/devMbbiSoft.c
+++ b/src/std/dev/devMbbiSoft.c
@@ -48,20 +48,9 @@ epicsExportAddress(dset, devMbbiSoft);
static long init_record(mbbiRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
prec->udf = FALSE;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devMbbiSoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devMbbiSoftRaw.c b/src/std/dev/devMbbiSoftRaw.c
index 997201cdb..4d5b57cb9 100644
--- a/src/std/dev/devMbbiSoftRaw.c
+++ b/src/std/dev/devMbbiSoftRaw.c
@@ -48,19 +48,8 @@ epicsExportAddress(dset, devMbbiSoftRaw);
static long init_record(mbbiRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devMbbiSoftRaw (init_record) Illegal INP field");
- return S_db_badField;
}
/*to preserve old functionality*/
if (prec->nobt == 0) prec->mask = 0xffffffff;
diff --git a/src/std/dev/devSASoft.c b/src/std/dev/devSASoft.c
index 6178b6ce7..049fa644e 100644
--- a/src/std/dev/devSASoft.c
+++ b/src/std/dev/devSASoft.c
@@ -48,19 +48,8 @@ epicsExportAddress(dset, devSASoft);
static long init_record(subArrayRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
prec->nord = 0;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devSASoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devSiSoft.c b/src/std/dev/devSiSoft.c
index 1a64674cf..044a41afb 100644
--- a/src/std/dev/devSiSoft.c
+++ b/src/std/dev/devSiSoft.c
@@ -50,20 +50,9 @@ epicsExportAddress(dset, devSiSoft);
static long init_record(stringinRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
if (recGblInitConstantLink(&prec->inp, DBF_STRING, prec->val))
prec->udf = FALSE;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devSiSoft (init_record) Illegal INP field");
- return S_db_badField;
}
return 0;
}
diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c
index 0ea0ce771..c18b9007c 100644
--- a/src/std/dev/devWfSoft.c
+++ b/src/std/dev/devWfSoft.c
@@ -49,19 +49,8 @@ epicsExportAddress(dset, devWfSoft);
static long init_record(waveformRecord *prec)
{
- /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
- switch (prec->inp.type) {
- case CONSTANT:
+ if (prec->inp.type == CONSTANT) {
prec->nord = 0;
- break;
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "devWfSoft (init_record) Illegal INP field");
- return(S_db_badField);
}
return 0;
}
From d1986edd9e0c9bc60caebb160909cb467de3a70b Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 2 Jun 2016 22:22:11 -0500
Subject: [PATCH 019/112] Simplify link-type checks in record supports
---
src/std/rec/aSubRecord.c | 53 ++----------------------------------
src/std/rec/aaiRecord.c | 1 -
src/std/rec/aaoRecord.c | 1 -
src/std/rec/aiRecord.c | 2 --
src/std/rec/aoRecord.c | 1 -
src/std/rec/boRecord.c | 1 -
src/std/rec/longinRecord.c | 2 --
src/std/rec/stringinRecord.c | 1 -
src/std/rec/waveformRecord.c | 1 -
9 files changed, 3 insertions(+), 60 deletions(-)
diff --git a/src/std/rec/aSubRecord.c b/src/std/rec/aSubRecord.c
index 0bb33dac3..0df5d5cad 100644
--- a/src/std/rec/aSubRecord.c
+++ b/src/std/rec/aSubRecord.c
@@ -109,10 +109,8 @@ static long init_record(aSubRecord *prec, int pass)
{
STATIC_ASSERT(sizeof(prec->onam)==sizeof(prec->snam));
GENFUNCPTR pfunc;
- long status;
int i;
- status = 0;
if (pass == 0) {
/* Allocate memory for arrays */
initFields(&prec->fta, &prec->noa, &prec->nea, NULL,
@@ -123,65 +121,20 @@ static long init_record(aSubRecord *prec, int pass)
}
/* Initialize the Subroutine Name Link */
- switch (prec->subl.type) {
- case CONSTANT:
+ if (prec->subl.type == CONSTANT) {
recGblInitConstantLink(&prec->subl, DBF_STRING, prec->snam);
- break;
-
- case PV_LINK:
- case DB_LINK:
- case CA_LINK:
- break;
-
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "aSubRecord(init_record) Bad SUBL link type");
- return S_db_badField;
}
/* Initialize Input Links */
for (i = 0; i < NUM_ARGS; i++) {
struct link *plink = &(&prec->inpa)[i];
- switch (plink->type) {
- case CONSTANT:
+
+ if (plink->type == CONSTANT) {
if ((&prec->noa)[i] < 2)
recGblInitConstantLink(plink, (&prec->fta)[i], (&prec->a)[i]);
- break;
-
- case PV_LINK:
- case CA_LINK:
- case DB_LINK:
- break;
-
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "aSubRecord(init_record) Illegal INPUT LINK");
- status = S_db_badField;
- break;
}
}
- if (status)
- return status;
-
- /* Initialize Output Links */
- for (i = 0; i < NUM_ARGS; i++) {
- switch ((&prec->outa)[i].type) {
- case CONSTANT:
- case PV_LINK:
- case CA_LINK:
- case DB_LINK:
- break;
-
- default:
- recGblRecordError(S_db_badField, (void *)prec,
- "aSubRecord(init_record) Illegal OUTPUT LINK");
- status = S_db_badField;
- }
- }
- if (status)
- return status;
-
/* Call the user initialization routine if there is one */
if (prec->inam[0] != 0) {
pfunc = (GENFUNCPTR)registryFunctionFind(prec->inam);
diff --git a/src/std/rec/aaiRecord.c b/src/std/rec/aaiRecord.c
index 5b370fe4c..9e1286704 100644
--- a/src/std/rec/aaiRecord.c
+++ b/src/std/rec/aaiRecord.c
@@ -140,7 +140,6 @@ static long init_record(aaiRecord *prec, int pass)
return 0;
}
- /* SIML must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
diff --git a/src/std/rec/aaoRecord.c b/src/std/rec/aaoRecord.c
index 565fd2886..83a73328e 100644
--- a/src/std/rec/aaoRecord.c
+++ b/src/std/rec/aaoRecord.c
@@ -140,7 +140,6 @@ static long init_record(aaoRecord *prec, int pass)
return 0;
}
- /* SIML must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
diff --git a/src/std/rec/aiRecord.c b/src/std/rec/aiRecord.c
index fb1218b16..b13c856f8 100644
--- a/src/std/rec/aiRecord.c
+++ b/src/std/rec/aiRecord.c
@@ -111,12 +111,10 @@ static long init_record(void *precord,int pass)
if (pass==0) return(0);
- /* ai.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
- /* ai.siol must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siol.type == CONSTANT) {
recGblInitConstantLink(&prec->siol,DBF_DOUBLE,&prec->sval);
}
diff --git a/src/std/rec/aoRecord.c b/src/std/rec/aoRecord.c
index 63125593e..28b0c3c0c 100644
--- a/src/std/rec/aoRecord.c
+++ b/src/std/rec/aoRecord.c
@@ -110,7 +110,6 @@ static long init_record(aoRecord *prec, int pass)
if (pass==0) return(0);
- /* ao.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
diff --git a/src/std/rec/boRecord.c b/src/std/rec/boRecord.c
index 55e198220..d0ed38146 100644
--- a/src/std/rec/boRecord.c
+++ b/src/std/rec/boRecord.c
@@ -138,7 +138,6 @@ static long init_record(boRecord *prec,int pass)
if (pass==0) return(0);
- /* bo.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
diff --git a/src/std/rec/longinRecord.c b/src/std/rec/longinRecord.c
index b4b50ebd5..bd224ac1d 100644
--- a/src/std/rec/longinRecord.c
+++ b/src/std/rec/longinRecord.c
@@ -103,12 +103,10 @@ static long init_record(longinRecord *prec, int pass)
if (pass==0) return(0);
- /* longin.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
- /* longin.siol must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siol.type == CONSTANT) {
recGblInitConstantLink(&prec->siol,DBF_LONG,&prec->sval);
}
diff --git a/src/std/rec/stringinRecord.c b/src/std/rec/stringinRecord.c
index 02f454788..00988223c 100644
--- a/src/std/rec/stringinRecord.c
+++ b/src/std/rec/stringinRecord.c
@@ -104,7 +104,6 @@ static long init_record(stringinRecord *prec, int pass)
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
- /* stringin.siol must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siol.type == CONSTANT) {
recGblInitConstantLink(&prec->siol,DBF_STRING,prec->sval);
}
diff --git a/src/std/rec/waveformRecord.c b/src/std/rec/waveformRecord.c
index 293be79af..c6ca2a04a 100644
--- a/src/std/rec/waveformRecord.c
+++ b/src/std/rec/waveformRecord.c
@@ -111,7 +111,6 @@ static long init_record(waveformRecord *prec, int pass)
return 0;
}
- /* wf.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
From c01967d64f6565c04bcb867e2f8788c184277644 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 2 Jun 2016 22:29:45 -0500
Subject: [PATCH 020/112] Remove spurious include dbCa.h
---
src/ioc/db/dbAccess.c | 1 -
src/ioc/db/recGbl.c | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c
index bdfe86eab..1f8b68ba6 100644
--- a/src/ioc/db/dbAccess.c
+++ b/src/ioc/db/dbAccess.c
@@ -41,7 +41,6 @@
#include "dbAddr.h"
#include "dbBase.h"
#include "dbBkpt.h"
-#include "dbCa.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
#include "dbConvert.h"
diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c
index 7ed1293f9..19bc425ba 100644
--- a/src/ioc/db/recGbl.c
+++ b/src/ioc/db/recGbl.c
@@ -31,7 +31,6 @@
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
-#include "dbCa.h"
#include "dbCommon.h"
#include "dbEvent.h"
#include "db_field_log.h"
From dafe2a83a33dab7073e35e0246b41d63c79b52fe Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 10 Aug 2016 12:19:53 -0500
Subject: [PATCH 021/112] libCom: Make yajl_alloc.h usable
---
src/libCom/yajl/Makefile | 1 +
src/libCom/yajl/yajl_alloc.h | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/libCom/yajl/Makefile b/src/libCom/yajl/Makefile
index 579848555..39146ca79 100644
--- a/src/libCom/yajl/Makefile
+++ b/src/libCom/yajl/Makefile
@@ -13,6 +13,7 @@ SRC_DIRS += $(LIBCOM)/yacc
# Yet Another JSON Library
SRC_DIRS += $(LIBCOM)/yajl
+INC += yajl_alloc.h
INC += yajl_common.h
INC += yajl_gen.h
INC += yajl_parse.h
diff --git a/src/libCom/yajl/yajl_alloc.h b/src/libCom/yajl/yajl_alloc.h
index cc1e5cf43..3935eef58 100644
--- a/src/libCom/yajl/yajl_alloc.h
+++ b/src/libCom/yajl/yajl_alloc.h
@@ -45,6 +45,6 @@
#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr))
#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz))
-void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf);
+YAJL_API void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf);
#endif
From ae2180f5b5676833733a7a3ff12d579982142880 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 10 Aug 2016 12:21:03 -0500
Subject: [PATCH 022/112] Comments in Makefile
---
src/ioc/db/test/Makefile | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile
index 67ef688e0..b268b57a1 100644
--- a/src/ioc/db/test/Makefile
+++ b/src/ioc/db/test/Makefile
@@ -26,7 +26,6 @@ DBDDEPENDS_FILES += dbTestIoc.dbd$(DEP)
dbTestIoc_DBD += menuGlobal.dbd
dbTestIoc_DBD += menuConvert.dbd
dbTestIoc_DBD += menuScan.dbd
-#dbTestIoc_DBD += arrRecord.dbd
dbTestIoc_DBD += xRecord.dbd
dbTestIoc_DBD += arrRecord.dbd
dbTestIoc_DBD += devx.dbd
@@ -152,7 +151,7 @@ recGblCheckDeadbandTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += recGblCheckDeadbandTest.c
TESTS += recGblCheckDeadbandTest
-# The testHarness runs all the test programs in a known working order.
+# This runs all the test programs in a known working order:
testHarness_SRCS += epicsRunDbTests.c
dbTestHarness_SRCS += $(testHarness_SRCS)
From 519208833fc9edd0a5475d8a8aa7a1ad28bc882a Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 10 Aug 2016 12:49:49 -0500
Subject: [PATCH 023/112] Add lset::loadArray and JSON parsing
Replace lset::loadLink with lset::loadScalar, add lset::loadArray
Add dbLoadLinkArray() routine to dbLink.h API
New dbConvertJSON.h API for use by dbConstLoadArray()
---
src/ioc/db/Makefile | 2 +
src/ioc/db/dbCa.c | 2 +-
src/ioc/db/dbConstLink.c | 31 ++++---
src/ioc/db/dbConvertJSON.c | 164 +++++++++++++++++++++++++++++++++++++
src/ioc/db/dbConvertJSON.h | 27 ++++++
src/ioc/db/dbDbLink.c | 3 +-
src/ioc/db/dbLink.c | 16 +++-
src/ioc/db/dbLink.h | 12 ++-
8 files changed, 237 insertions(+), 20 deletions(-)
create mode 100644 src/ioc/db/dbConvertJSON.c
create mode 100644 src/ioc/db/dbConvertJSON.h
diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile
index 3f08bbe83..0c874ccff 100644
--- a/src/ioc/db/Makefile
+++ b/src/ioc/db/Makefile
@@ -21,6 +21,7 @@ INC += dbChannel.h
INC += dbConstLink.h
INC += dbConvert.h
INC += dbConvertFast.h
+INC += dbConvertJSON.h
INC += dbDbLink.h
INC += dbExtractArray.h
INC += dbEvent.h
@@ -68,6 +69,7 @@ dbCore_SRCS += dbBkpt.c
dbCore_SRCS += dbChannel.c
dbCore_SRCS += dbConstLink.c
dbCore_SRCS += dbConvert.c
+dbCore_SRCS += dbConvertJSON.c
dbCore_SRCS += dbDbLink.c
dbCore_SRCS += dbFastLinkConv.c
dbCore_SRCS += dbExtractArray.c
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index de37682b6..5f532ad5d 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -709,8 +709,8 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) {
}
static lset dbCa_lset = {
- NULL,
dbCaRemoveLink,
+ NULL, NULL,
isConnected,
getDBFtype, getElements,
dbCaGetLink,
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 022ba7fe9..1c1f89c3a 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -12,24 +12,19 @@
* Current Author: Andrew Johnson
*/
-#include
#include
-#include "cvtFast.h"
#include "dbDefs.h"
-#include "errlog.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbAddr.h"
-#include "dbBase.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
-#include "dbConvert.h"
+#include "dbConvertJSON.h"
#include "dbFldTypes.h"
#include "dbLink.h"
#include "link.h"
-#include "recGbl.h"
/***************************** Constant Links *****************************/
@@ -46,14 +41,14 @@ void dbConstAddLink(struct link *plink)
plink->lset = &dbConst_lset;
}
-static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
+/**************************** Member functions ****************************/
+
+static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
{
if (!plink->value.constantStr)
return S_db_badField;
- plink->lset = &dbConst_lset;
-
- /* Constant strings are always numeric */
+ /* Constant scalars are always numeric */
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
dbrType = DBF_USHORT;
@@ -61,6 +56,19 @@ static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
(plink->value.constantStr, pbuffer, NULL);
}
+static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
+ long *pnReq)
+{
+ if (!plink->value.constantStr)
+ return S_db_badField;
+
+ /* No support for arrays of choice types */
+ if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
+ return S_db_badField;
+
+ return dbPutConvertJSON(plink->value.constantStr, dbrType, pbuffer, pnReq);
+}
+
static long dbConstGetNelements(const struct link *plink, long *nelements)
{
*nelements = 0;
@@ -76,8 +84,9 @@ static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
}
static lset dbConst_lset = {
- dbConstLoadLink,
NULL,
+ dbConstLoadScalar,
+ dbConstLoadArray,
NULL,
NULL, dbConstGetNelements,
dbConstGetValue,
diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c
new file mode 100644
index 000000000..d877fe043
--- /dev/null
+++ b/src/ioc/db/dbConvertJSON.c
@@ -0,0 +1,164 @@
+/*************************************************************************\
+* 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.
+\*************************************************************************/
+/* dbConvertJSON.c */
+
+#include
+#include
+
+#include "dbDefs.h"
+#include "yajl_alloc.h"
+#include "yajl_parse.h"
+
+#define epicsExportSharedSybols
+#include "dbAccessDefs.h"
+#include "dbConvertFast.h"
+
+typedef long (*FASTCONVERT)();
+
+typedef struct parseContext {
+ int depth;
+ short dbrType;
+ short dbrSize;
+ void *pdest;
+ int elems;
+} parseContext;
+
+static int dbcj_null(void *ctx) {
+ return 0; /* Illegal */
+}
+
+static int dbcj_boolean(void *ctx, int val) {
+ return 0; /* Illegal */
+}
+
+static int dbcj_integer(void *ctx, long num) {
+ parseContext *parser = (parseContext *) ctx;
+ epicsInt32 val32 = num;
+ FASTCONVERT conv = dbFastPutConvertRoutine[DBF_LONG][parser->dbrType];
+
+ if (parser->elems > 0) {
+ conv(&val32, parser->pdest, NULL);
+ parser->pdest += parser->dbrSize;
+ parser->elems--;
+ }
+ return 1;
+}
+
+static int dbcj_double(void *ctx, double num) {
+ parseContext *parser = (parseContext *) ctx;
+ FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
+
+ if (parser->elems > 0) {
+ conv(&num, parser->pdest, NULL);
+ parser->pdest += parser->dbrSize;
+ parser->elems--;
+ }
+ return 1;
+}
+
+static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
+ parseContext *parser = (parseContext *) ctx;
+ char *pdest = parser->pdest;
+
+ /* Not attempting to handle char-array fields here, they need more
+ * metadata about the field than we have available at the moment.
+ */
+ if (parser->dbrType != DBF_STRING)
+ return 0; /* Illegal */
+
+ if (parser->elems > 0) {
+ if (len > MAX_STRING_SIZE - 1)
+ len = MAX_STRING_SIZE - 1;
+ strncpy(pdest, (const char *) val, len);
+ pdest[len] = 0;
+ }
+ return 1;
+}
+
+static int dbcj_start_map(void *ctx) {
+ return 0; /* Illegal */
+}
+
+static int dbcj_map_key(void *ctx, const unsigned char *key, unsigned int len) {
+ return 0; /* Illegal */
+}
+
+static int dbcj_end_map(void *ctx) {
+ return 0; /* Illegal */
+}
+
+static int dbcj_start_array(void *ctx) {
+ parseContext *parser = (parseContext *) ctx;
+
+ parser->depth++;
+ return (parser->depth == 1);
+}
+
+static int dbcj_end_array(void *ctx) {
+ parseContext *parser = (parseContext *) ctx;
+
+ parser->depth--;
+ return (parser->depth == 0);
+}
+
+
+static yajl_callbacks dbcj_callbacks = {
+ dbcj_null, dbcj_boolean, dbcj_integer, dbcj_double, NULL, dbcj_string,
+ dbcj_start_map, dbcj_map_key, dbcj_end_map,
+ dbcj_start_array, dbcj_end_array
+};
+
+static const yajl_parser_config dbcj_config =
+ { 0, 0 }; /* allowComments = NO, checkUTF8 = NO */
+
+long dbPutConvertJSON(const char *json, short dbrType,
+ void *pdest, long *pnRequest)
+{
+ parseContext context, *parser = &context;
+ yajl_alloc_funcs dbcj_alloc;
+ yajl_handle yh;
+ yajl_status ys;
+ size_t jlen = strlen(json);
+ long status;
+
+ parser->depth = 0;
+ parser->dbrType = dbrType;
+ parser->dbrSize = dbValueSize(dbrType);
+ parser->pdest = pdest;
+ parser->elems = *pnRequest;
+
+ yajl_set_default_alloc_funcs(&dbcj_alloc);
+ yh = yajl_alloc(&dbcj_callbacks, &dbcj_config, &dbcj_alloc, parser);
+ if (!yh)
+ return S_db_noMemory;
+
+ ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen);
+ if (ys == yajl_status_insufficient_data)
+ ys = yajl_parse_complete(yh);
+
+ switch (ys) {
+ case yajl_status_ok:
+ *pnRequest -= parser->elems;
+ status = 0;
+ break;
+
+ case yajl_status_error: {
+ unsigned char *err = yajl_get_error(yh, 1,
+ (const unsigned char *) json, (unsigned int) jlen);
+ fprintf(stderr, "dbPutConvertJSON: %s\n", err);
+ yajl_free_error(yh, err);
+ }
+ /* fall through */
+ default:
+ status = S_db_badField;
+ }
+
+ yajl_free(yh);
+ return status;
+}
+
+
diff --git a/src/ioc/db/dbConvertJSON.h b/src/ioc/db/dbConvertJSON.h
new file mode 100644
index 000000000..11546d9ab
--- /dev/null
+++ b/src/ioc/db/dbConvertJSON.h
@@ -0,0 +1,27 @@
+/*************************************************************************\
+* 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.
+\*************************************************************************/
+/* dbConvertJSON.h */
+
+#ifndef INC_dbConvertJSON_H
+#define INC_dbConvertJSON_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This name should probably be changed to inclue "array" */
+epicsShareFunc long dbPutConvertJSON(const char *json, short dbrType,
+ void *pdest, long *psize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_dbConvertJSON_H */
+
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index 46c4b7ef6..0013d1b34 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -98,7 +98,6 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
plink->value.pv_link.pvlMask = 0;
plink->value.pv_link.lastGetdbrType = 0;
plink->type = PV_LINK;
- plink->lset = NULL;
ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
free(pdbAddr);
@@ -332,8 +331,8 @@ static void dbDbScanFwdLink(struct link *plink)
}
static lset dbDb_lset = {
- NULL,
dbDbRemoveLink,
+ NULL, NULL,
dbDbIsConnected,
dbDbGetDBFtype, dbDbGetElements,
dbDbGetValue,
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index dfc02f4fe..111175276 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -145,8 +145,20 @@ long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
{
lset *plset = plink->lset;
- if (plset->loadLink)
- return plset->loadLink(plink, dbrType, pbuffer);
+
+ if (plset->loadScalar)
+ return plset->loadScalar(plink, dbrType, pbuffer);
+
+ return S_db_notFound;
+}
+
+long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
+ long *pnRequest)
+{
+ lset *plset = plink->lset;
+
+ if (plset->loadArray)
+ return plset->loadArray(plink, dbrType, pbuffer, pnRequest);
return S_db_notFound;
}
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index f33f6aee3..628483119 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -28,8 +28,10 @@ extern "C" {
struct dbLocker;
typedef struct lset {
- long (*loadLink)(struct link *plink, short dbrType, void *pbuffer);
void (*removeLink)(struct dbLocker *locker, struct link *plink);
+ long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
+ long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
+ long *pnRequest);
int (*isConnected)(const struct link *plink);
int (*getDBFtype)(const struct link *plink);
long (*getElements)(const struct link *plink, long *nelements);
@@ -53,11 +55,13 @@ typedef struct lset {
dbGetAlarm(link, NULL, sevr)
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
-epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
- DBADDR *ptarget);
+epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
+ short dbfType, DBADDR *ptarget);
+epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
void *pbuffer);
-epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
+epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
+ long *pnRequest);
epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
epicsShareFunc int dbIsLinkConnected(const struct link *plink);
From fb785e45c7e865c69fbe659820b6037e2e581a47 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 10 Aug 2016 12:53:39 -0500
Subject: [PATCH 024/112] Adjust record and device support for array constants
---
src/std/dev/devAaiSoft.c | 5 ++++-
src/std/dev/devWfSoft.c | 15 ++++++++-------
src/std/rec/aSubRecord.c | 8 ++++++--
src/std/rec/test/arrayOpTest.c | 11 ++++++-----
src/std/rec/test/arrayOpTest.db | 1 +
5 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/src/std/dev/devAaiSoft.c b/src/std/dev/devAaiSoft.c
index ff985b088..768ddb00e 100644
--- a/src/std/dev/devAaiSoft.c
+++ b/src/std/dev/devAaiSoft.c
@@ -52,8 +52,11 @@ epicsExportAddress(dset,devAaiSoft);
static long init_record(aaiRecord *prec)
{
+ long nRequest = prec->nelm;
+
if (prec->inp.type == CONSTANT) {
- prec->nord = 0;
+ dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nRequest);
+ prec->nord = (nRequest > 0) ? nRequest : 0;
}
return 0;
}
diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c
index c18b9007c..4128ed47a 100644
--- a/src/std/dev/devWfSoft.c
+++ b/src/std/dev/devWfSoft.c
@@ -49,22 +49,23 @@ epicsExportAddress(dset, devWfSoft);
static long init_record(waveformRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- prec->nord = 0;
- }
- return 0;
+ long nelm = prec->nelm;
+ long status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nelm);
+
+ prec->nord = !status && (nelm > 0) ? nelm : 0;
+ return status;
}
static long read_wf(waveformRecord *prec)
{
long nRequest = prec->nelm;
+ long status = dbGetLink(&prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
- dbGetLink(&prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
- if (nRequest > 0) {
+ if (!status && nRequest > 0) {
prec->nord = nRequest;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
- return 0;
+ return status;
}
diff --git a/src/std/rec/aSubRecord.c b/src/std/rec/aSubRecord.c
index 0df5d5cad..2e0785087 100644
--- a/src/std/rec/aSubRecord.c
+++ b/src/std/rec/aSubRecord.c
@@ -130,8 +130,12 @@ static long init_record(aSubRecord *prec, int pass)
struct link *plink = &(&prec->inpa)[i];
if (plink->type == CONSTANT) {
- if ((&prec->noa)[i] < 2)
- recGblInitConstantLink(plink, (&prec->fta)[i], (&prec->a)[i]);
+ short dbr = (&prec->fta)[i];
+ long n = (&prec->noa)[i];
+
+ dbLoadLinkArray(plink, dbr, (&prec->a)[i], &n);
+ if (n > 0)
+ (&prec->nea)[i] = n;
}
}
diff --git a/src/std/rec/test/arrayOpTest.c b/src/std/rec/test/arrayOpTest.c
index 27c0becdd..d77921081 100644
--- a/src/std/rec/test/arrayOpTest.c
+++ b/src/std/rec/test/arrayOpTest.c
@@ -8,6 +8,7 @@
#include
#include "dbAccess.h"
+#include "dbTest.h"
#include "dbUnitTest.h"
#include "errlog.h"
@@ -45,16 +46,16 @@ static void testGetPutArray(void)
testAbort("Failed to find record wfrec");
memcpy(&save, &addr, sizeof(save));
- testDiag("Fetch initial value");
+ testDiag("Fetch initial value of %s", prec->name);
dbScanLock(addr.precord);
- testOk1(prec->nord==0);
+ testOk(prec->nord==3, "prec->nord==3 (got %d)", prec->nord);
nreq = NELEMENTS(data);
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
testFail("dbGet fails");
else {
- testOk(nreq==0, "nreq==0 (got %ld)", nreq);
+ testOk(nreq==3, "nreq==3 (got %ld)", nreq);
}
dbScanUnlock(addr.precord);
@@ -101,10 +102,10 @@ static void testGetPutArray(void)
testAbort("Failed to find record wfrec1");
memcpy(&save, &addr, sizeof(save));
- testDiag("Fetch initial value");
+ testDiag("Fetch initial value of %s", prec->name);
dbScanLock(addr.precord);
- testOk1(prec->nord==0);
+ testOk(prec->nord==0, "prec->nord==0 (got %d)", prec->nord);
nreq = NELEMENTS(data);
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
diff --git a/src/std/rec/test/arrayOpTest.db b/src/std/rec/test/arrayOpTest.db
index fc809fbe9..1c011e755 100644
--- a/src/std/rec/test/arrayOpTest.db
+++ b/src/std/rec/test/arrayOpTest.db
@@ -1,6 +1,7 @@
record(waveform, "wfrec") {
field(NELM, "10")
field(FTVL, "LONG")
+ field(INP, [1, 2, 3])
}
record(waveform, "wfrec1") {
field(NELM, "1")
From 899feb24b2ee53dbf416818e323541e5db465017 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 12 Aug 2016 19:50:17 -0400
Subject: [PATCH 025/112] iocInit: close CA_LINKs through lset
---
src/ioc/misc/iocInit.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c
index ba0ea345d..2bcccf35d 100644
--- a/src/ioc/misc/iocInit.c
+++ b/src/ioc/misc/iocInit.c
@@ -641,7 +641,8 @@ static void doCloseLinks(dbRecordType *pdbRecordType, dbCommon *precord,
dbScanLock(precord);
locked = 1;
}
- dbCaRemoveLink(NULL, plink);
+ if(plink->lset)
+ (*plink->lset->removeLink)(NULL, plink);
} else if (iocBuildMode==buildIsolated && plink->type == DB_LINK) {
/* free link, but don't split lockset like dbDbRemoveLink() */
From bb58598eba171b56b73353247f1264feedf08a91 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 12 Aug 2016 23:20:24 -0500
Subject: [PATCH 026/112] A cleaner way to close CA & DB links
---
src/ioc/db/dbDbLink.c | 17 +++++++++++------
src/ioc/misc/iocInit.c | 13 +++++--------
2 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index 0013d1b34..e4e86316c 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -93,13 +93,18 @@ void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
{
DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
- plink->value.pv_link.pvt = 0;
- plink->value.pv_link.getCvt = 0;
- plink->value.pv_link.pvlMask = 0;
- plink->value.pv_link.lastGetdbrType = 0;
+
plink->type = PV_LINK;
- ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
- dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
+
+ /* locker is NULL when an isolated IOC is closing its links */
+ if (locker) {
+ plink->value.pv_link.pvt = 0;
+ plink->value.pv_link.getCvt = 0;
+ plink->value.pv_link.pvlMask = 0;
+ plink->value.pv_link.lastGetdbrType = 0;
+ ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
+ dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
+ }
free(pdbAddr);
}
diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c
index 2bcccf35d..d0483e55a 100644
--- a/src/ioc/misc/iocInit.c
+++ b/src/ioc/misc/iocInit.c
@@ -641,14 +641,11 @@ static void doCloseLinks(dbRecordType *pdbRecordType, dbCommon *precord,
dbScanLock(precord);
locked = 1;
}
- if(plink->lset)
- (*plink->lset->removeLink)(NULL, plink);
-
- } else if (iocBuildMode==buildIsolated && plink->type == DB_LINK) {
- /* free link, but don't split lockset like dbDbRemoveLink() */
- free(plink->value.pv_link.pvt);
- plink->type = PV_LINK;
- plink->lset = NULL;
+ dbRemoveLink(NULL, plink);
+ }
+ else if (iocBuildMode==buildIsolated && plink->type == DB_LINK) {
+ /* free link, but don't split lockset */
+ dbRemoveLink(NULL, plink);
}
}
From d3a9ba7701e45d520e540930df4d8fa23c030f5e Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 12 Aug 2016 23:21:26 -0500
Subject: [PATCH 027/112] Fix issues related to const array initialization
---
src/ioc/db/dbConstLink.c | 1 +
src/ioc/db/dbConstLink.h | 2 +-
src/ioc/db/dbConvertJSON.c | 18 ++++++++++--------
src/ioc/db/dbLink.c | 4 ++--
src/ioc/dbStatic/dbStaticLib.c | 3 ++-
src/std/dev/devAaiSoft.c | 22 ++++++++++++++++++----
src/std/dev/devWfSoft.c | 5 ++++-
7 files changed, 38 insertions(+), 17 deletions(-)
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 1c1f89c3a..90f5d8d6b 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -20,6 +20,7 @@
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbCommon.h"
+#include "dbConstLink.h"
#include "dbConvertFast.h"
#include "dbConvertJSON.h"
#include "dbFldTypes.h"
diff --git a/src/ioc/db/dbConstLink.h b/src/ioc/db/dbConstLink.h
index fb598ab9f..c187f9fc5 100644
--- a/src/ioc/db/dbConstLink.h
+++ b/src/ioc/db/dbConstLink.h
@@ -23,7 +23,7 @@ extern "C" {
struct link;
-epicsShareFunc long dbConstInitLink(struct link *plink);
+epicsShareFunc void dbConstInitLink(struct link *plink);
epicsShareFunc void dbConstAddLink(struct link *plink);
#ifdef __cplusplus
diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c
index d877fe043..cd7b7ca44 100644
--- a/src/ioc/db/dbConvertJSON.c
+++ b/src/ioc/db/dbConvertJSON.c
@@ -42,8 +42,8 @@ static int dbcj_integer(void *ctx, long num) {
if (parser->elems > 0) {
conv(&val32, parser->pdest, NULL);
- parser->pdest += parser->dbrSize;
- parser->elems--;
+ parser->pdest += parser->dbrSize;
+ parser->elems--;
}
return 1;
}
@@ -54,8 +54,8 @@ static int dbcj_double(void *ctx, double num) {
if (parser->elems > 0) {
conv(&num, parser->pdest, NULL);
- parser->pdest += parser->dbrSize;
- parser->elems--;
+ parser->pdest += parser->dbrSize;
+ parser->elems--;
}
return 1;
}
@@ -71,10 +71,12 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
return 0; /* Illegal */
if (parser->elems > 0) {
- if (len > MAX_STRING_SIZE - 1)
- len = MAX_STRING_SIZE - 1;
+ if (len > parser->dbrSize - 1)
+ len = parser->dbrSize - 1;
strncpy(pdest, (const char *) val, len);
- pdest[len] = 0;
+ pdest[len] = 0;
+ parser->pdest += parser->dbrSize;
+ parser->elems--;
}
return 1;
}
@@ -147,7 +149,7 @@ long dbPutConvertJSON(const char *json, short dbrType,
break;
case yajl_status_error: {
- unsigned char *err = yajl_get_error(yh, 1,
+ unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, (unsigned int) jlen);
fprintf(stderr, "dbPutConvertJSON: %s\n", err);
yajl_free_error(yh, err);
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index 111175276..a07d35caf 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -146,7 +146,7 @@ long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
lset *plset = plink->lset;
- if (plset->loadScalar)
+ if (plset && plset->loadScalar)
return plset->loadScalar(plink, dbrType, pbuffer);
return S_db_notFound;
@@ -157,7 +157,7 @@ long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
{
lset *plset = plink->lset;
- if (plset->loadArray)
+ if (plset && plset->loadArray)
return plset->loadArray(plink, dbrType, pbuffer, pnRequest);
return S_db_notFound;
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index c718dacab..9ef89e802 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2331,7 +2331,8 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
}
/* Link may be an array constant */
- if (pstr[0] == '[' && pstr[len-1] == ']' && strchr(pstr, ',')) {
+ if (pstr[0] == '[' && pstr[len-1] == ']' &&
+ (strchr(pstr, ',') || strchr(pstr, '"'))) {
pinfo->ltype = CONSTANT;
return 0;
}
diff --git a/src/std/dev/devAaiSoft.c b/src/std/dev/devAaiSoft.c
index 768ddb00e..31626bacb 100644
--- a/src/std/dev/devAaiSoft.c
+++ b/src/std/dev/devAaiSoft.c
@@ -22,6 +22,7 @@
#include "alarm.h"
#include "dbDefs.h"
#include "dbAccess.h"
+#include "dbConstLink.h"
#include "recGbl.h"
#include "devSup.h"
#include "cantProceed.h"
@@ -52,11 +53,24 @@ epicsExportAddress(dset,devAaiSoft);
static long init_record(aaiRecord *prec)
{
- long nRequest = prec->nelm;
-
if (prec->inp.type == CONSTANT) {
- dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nRequest);
- prec->nord = (nRequest > 0) ? nRequest : 0;
+ long nRequest = prec->nelm;
+ long status;
+
+ /* Allocate a buffer, record support hasn't done that yet */
+ if (!prec->bptr) {
+ prec->bptr = callocMustSucceed(nRequest, dbValueSize(prec->ftvl),
+ "devAaiSoft: buffer calloc failed");
+ }
+
+ /* This is pass 0 so link hasn't been initialized either */
+ dbConstInitLink(&prec->inp);
+
+ status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nRequest);
+ if (!status && nRequest > 0) {
+ prec->nord = nRequest;
+ prec->udf = FALSE;
+ }
}
return 0;
}
diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c
index 4128ed47a..e5aef8195 100644
--- a/src/std/dev/devWfSoft.c
+++ b/src/std/dev/devWfSoft.c
@@ -52,7 +52,10 @@ static long init_record(waveformRecord *prec)
long nelm = prec->nelm;
long status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nelm);
- prec->nord = !status && (nelm > 0) ? nelm : 0;
+ if (!status && nelm > 0) {
+ prec->nord = nelm;
+ prec->udf = FALSE;
+ }
return status;
}
From fe71fc98b86099249bbdee75ee6e23257c166ff2 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 12 Aug 2016 23:53:42 -0500
Subject: [PATCH 028/112] Undo a small & unnecessary behaviour change
---
src/std/dev/devWfSoft.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c
index e5aef8195..9093344d7 100644
--- a/src/std/dev/devWfSoft.c
+++ b/src/std/dev/devWfSoft.c
@@ -56,6 +56,8 @@ static long init_record(waveformRecord *prec)
prec->nord = nelm;
prec->udf = FALSE;
}
+ else
+ prec->nord = 0;
return status;
}
From 7df97f074e0f18636dd32a3b0ce9aa747da45c3f Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 13 Aug 2016 21:42:23 -0500
Subject: [PATCH 029/112] Add lset::dbPutLinkAsync and S_db_noLSET
---
src/ioc/db/dbAccessDefs.h | 1 +
src/ioc/db/dbCa.c | 14 +++++++----
src/ioc/db/dbConstLink.c | 2 +-
src/ioc/db/dbDbLink.c | 2 +-
src/ioc/db/dbLink.c | 52 ++++++++++++++++++++++++++++++---------
src/ioc/db/dbLink.h | 5 ++++
6 files changed, 57 insertions(+), 19 deletions(-)
diff --git a/src/ioc/db/dbAccessDefs.h b/src/ioc/db/dbAccessDefs.h
index e0e8f4484..67b529d39 100644
--- a/src/ioc/db/dbAccessDefs.h
+++ b/src/ioc/db/dbAccessDefs.h
@@ -182,6 +182,7 @@ struct dbr_alDouble {DBRalDouble};
#define S_db_badChoice (M_dbAccess|13) /*Illegal choice*/
#define S_db_badField (M_dbAccess|15) /*Illegal field value*/
#define S_db_lsetLogic (M_dbAccess|17) /*Logic error generating lock sets*/
+#define S_db_noLSET (M_dbAccess|21) /*No link support table or entry*/
#define S_db_noRSET (M_dbAccess|31) /*missing record support entry table*/
#define S_db_noSupport (M_dbAccess|33) /*RSET or DSXT routine not defined*/
#define S_db_BadSub (M_dbAccess|35) /*Subroutine not found*/
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index 5f532ad5d..1763fe3e7 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -232,11 +232,8 @@ void dbCaSync(void)
void dbCaCallbackProcess(void *userPvt)
{
struct link *plink = (struct link *)userPvt;
- dbCommon *pdbCommon = plink->precord;
- dbScanLock(pdbCommon);
- pdbCommon->rset->process(pdbCommon);
- dbScanUnlock(pdbCommon);
+ dbLinkAsyncComplete(plink);
}
void dbCaShutdown(void)
@@ -420,6 +417,13 @@ done:
return status;
}
+static long dbCaPutAsync(struct link *plink,short dbrType,
+ const void *pbuffer,long nRequest)
+{
+ return dbCaPutLinkCallback(plink, dbrType, pbuffer, nRequest,
+ dbCaCallbackProcess, plink);
+}
+
long dbCaPutLinkCallback(struct link *plink,short dbrType,
const void *pbuffer,long nRequest,dbCaCallback callback,void *userPvt)
{
@@ -717,7 +721,7 @@ static lset dbCa_lset = {
getControlLimits, getGraphicLimits, getAlarmLimits,
getPrecision, getUnits,
getAlarm, getTimeStamp,
- dbCaPutLink,
+ dbCaPutLink, dbCaPutAsync,
scanForward
};
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 90f5d8d6b..38f5d448c 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -94,7 +94,7 @@ static lset dbConst_lset = {
NULL, NULL, NULL,
NULL, NULL,
NULL, NULL,
- NULL,
+ NULL, NULL,
NULL
};
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index e4e86316c..58f089126 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -344,7 +344,7 @@ static lset dbDb_lset = {
dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
dbDbGetPrecision, dbDbGetUnits,
dbDbGetAlarm, dbDbGetTimeStamp,
- dbDbPutValue,
+ dbDbPutValue, NULL,
dbDbScanFwdLink
};
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index a07d35caf..a877eec6e 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -38,6 +38,7 @@
#include "db_field_log.h"
#include "dbFldTypes.h"
#include "dbLink.h"
+#include "dbLock.h"
#include "dbScan.h"
#include "dbStaticLib.h"
#include "devSup.h"
@@ -149,7 +150,7 @@ long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
if (plset && plset->loadScalar)
return plset->loadScalar(plink, dbrType, pbuffer);
- return S_db_notFound;
+ return S_db_noLSET;
}
long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
@@ -160,7 +161,7 @@ long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
if (plset && plset->loadArray)
return plset->loadArray(plink, dbrType, pbuffer, pnRequest);
- return S_db_notFound;
+ return S_db_noLSET;
}
void dbRemoveLink(struct dbLocker *locker, struct link *plink)
@@ -199,7 +200,7 @@ long dbGetNelements(const struct link *plink, long *nelements)
lset *plset = plink->lset;
if (!plset || !plset->getElements)
- return S_db_badField;
+ return S_db_noLSET;
return plset->getElements(plink, nelements);
}
@@ -235,7 +236,7 @@ long dbGetControlLimits(const struct link *plink, double *low, double *high)
lset *plset = plink->lset;
if (!plset || !plset->getControlLimits)
- return S_db_notFound;
+ return S_db_noLSET;
return plset->getControlLimits(plink, low, high);
}
@@ -245,7 +246,7 @@ long dbGetGraphicLimits(const struct link *plink, double *low, double *high)
lset *plset = plink->lset;
if (!plset || !plset->getGraphicLimits)
- return S_db_notFound;
+ return S_db_noLSET;
return plset->getGraphicLimits(plink, low, high);
}
@@ -256,7 +257,7 @@ long dbGetAlarmLimits(const struct link *plink, double *lolo, double *low,
lset *plset = plink->lset;
if (!plset || !plset->getAlarmLimits)
- return S_db_notFound;
+ return S_db_noLSET;
return plset->getAlarmLimits(plink, lolo, low, high, hihi);
}
@@ -266,7 +267,7 @@ long dbGetPrecision(const struct link *plink, short *precision)
lset *plset = plink->lset;
if (!plset || !plset->getPrecision)
- return S_db_notFound;
+ return S_db_noLSET;
return plset->getPrecision(plink, precision);
}
@@ -276,7 +277,7 @@ long dbGetUnits(const struct link *plink, char *units, int unitsSize)
lset *plset = plink->lset;
if (!plset || !plset->getUnits)
- return S_db_notFound;
+ return S_db_noLSET;
return plset->getUnits(plink, units, unitsSize);
}
@@ -287,7 +288,7 @@ long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
lset *plset = plink->lset;
if (!plset || !plset->getAlarm)
- return S_db_notFound;
+ return S_db_noLSET;
return plset->getAlarm(plink, status, severity);
}
@@ -297,7 +298,7 @@ long dbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
lset *plset = plink->lset;
if (!plset || !plset->getTimeStamp)
- return S_db_notFound;
+ return S_db_noLSET;
return plset->getTimeStamp(plink, pstamp);
}
@@ -309,7 +310,7 @@ long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
long status;
if (!plset || !plset->putValue)
- return S_db_notFound;
+ return S_db_noLSET;
status = plset->putValue(plink, dbrType, pbuffer, nRequest);
if (status) {
@@ -320,6 +321,33 @@ long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
return status;
}
+void dbLinkAsyncComplete(struct link *plink)
+{
+ dbCommon *pdbCommon = plink->precord;
+
+ dbScanLock(pdbCommon);
+ pdbCommon->rset->process(pdbCommon);
+ dbScanUnlock(pdbCommon);
+}
+
+long dbPutLinkAsync(struct link *plink, short dbrType, const void *pbuffer,
+ long nRequest)
+{
+ lset *plset = plink->lset;
+ long status;
+
+ if (!plset || !plset->putAsync)
+ return S_db_noLSET;
+
+ status = plset->putAsync(plink, dbrType, pbuffer, nRequest);
+ if (status) {
+ struct dbCommon *precord = plink->precord;
+
+ recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
+ }
+ return status;
+}
+
void dbScanFwdLink(struct link *plink)
{
lset *plset = plink->lset;
@@ -341,7 +369,7 @@ long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
return 0;
}
- return S_db_notFound;
+ return S_db_noLSET;
}
long dbGetLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index 628483119..834400c73 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -48,6 +48,8 @@ typedef struct lset {
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
long (*putValue)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
+ long (*putAsync)(struct link *plink, short dbrType,
+ const void *pbuffer, long nRequest);
void (*scanForward)(struct link *plink);
} lset;
@@ -83,6 +85,9 @@ epicsShareFunc long dbGetTimeStamp(const struct link *plink,
epicsTimeStamp *pstamp);
epicsShareFunc long dbPutLink(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
+epicsShareFunc void dbLinkAsyncComplete(struct link *plink);
+epicsShareFunc long dbPutLinkAsync(struct link *plink, short dbrType,
+ const void *pbuffer, long nRequest);
epicsShareFunc void dbScanFwdLink(struct link *plink);
epicsShareFunc long dbLoadLinkLS(struct link *plink, char *pbuffer,
From bed1c618a8891c94909fb9cb2f2e7338c67d988a Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 13 Aug 2016 21:53:31 -0500
Subject: [PATCH 030/112] Use dbPutLinkAsync() in all output SoftCallback dev's
---
src/std/dev/devAoSoftCallback.c | 24 +++++++++-----------
src/std/dev/devBoSoftCallback.c | 29 +++++++++++-------------
src/std/dev/devCalcoutSoftCallback.c | 20 ++++++++---------
src/std/dev/devLoSoftCallback.c | 30 ++++++++++++-------------
src/std/dev/devLsoSoftCallback.c | 18 ++++++---------
src/std/dev/devMbboDirectSoftCallback.c | 17 +++++---------
src/std/dev/devMbboSoftCallback.c | 30 ++++++++++++-------------
src/std/dev/devPrintfSoftCallback.c | 17 +++++---------
src/std/dev/devSoSoftCallback.c | 29 ++++++++++--------------
9 files changed, 91 insertions(+), 123 deletions(-)
diff --git a/src/std/dev/devAoSoftCallback.c b/src/std/dev/devAoSoftCallback.c
index 35c3f6fe2..c1fb72f13 100644
--- a/src/std/dev/devAoSoftCallback.c
+++ b/src/std/dev/devAoSoftCallback.c
@@ -54,17 +54,15 @@ static long write_ao(aoRecord *prec)
struct link *plink = &prec->out;
long status;
- if(prec->pact) return(0);
- if(plink->type!=CA_LINK) {
- status = dbPutLink(plink,DBR_DOUBLE,&prec->oval,1);
- return(status);
- }
- status = dbCaPutLinkCallback(plink,DBR_DOUBLE,&prec->oval,1,
- dbCaCallbackProcess,plink);
- if(status) {
- recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
- return(status);
- }
- prec->pact = TRUE;
- return(0);
+ if (prec->pact)
+ return 0;
+
+ status = dbPutLinkAsync(plink, DBR_DOUBLE, &prec->oval, 1);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
+ status = dbPutLink(plink, DBR_DOUBLE, &prec->oval, 1);
+
+ return status;
}
+
diff --git a/src/std/dev/devBoSoftCallback.c b/src/std/dev/devBoSoftCallback.c
index 4cdb51a29..ffb68e525 100644
--- a/src/std/dev/devBoSoftCallback.c
+++ b/src/std/dev/devBoSoftCallback.c
@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* devBoCallbackSoft.c */
@@ -54,17 +53,15 @@ static long write_bo(boRecord *prec)
struct link *plink = &prec->out;
long status;
- if(prec->pact) return(0);
- if(plink->type!=CA_LINK) {
- status = dbPutLink(plink,DBR_USHORT,&prec->val,1);
- return(status);
- }
- status = dbCaPutLinkCallback(plink,DBR_USHORT,&prec->val,1,
- dbCaCallbackProcess,plink);
- if(status) {
- recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
- return(status);
- }
- prec->pact = TRUE;
- return(0);
+ if (prec->pact)
+ return 0;
+
+ status = dbPutLinkAsync(plink, DBR_USHORT, &prec->val, 1);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
+ status = dbPutLink(plink, DBR_USHORT, &prec->val, 1);
+
+ return status;
}
+
diff --git a/src/std/dev/devCalcoutSoftCallback.c b/src/std/dev/devCalcoutSoftCallback.c
index 0552df826..94f9d4f99 100644
--- a/src/std/dev/devCalcoutSoftCallback.c
+++ b/src/std/dev/devCalcoutSoftCallback.c
@@ -48,17 +48,15 @@ static long write_calcout(calcoutRecord *prec)
struct link *plink = &prec->out;
long status;
- if (prec->pact) return 0;
- if (plink->type != CA_LINK) {
+ if (prec->pact)
+ return 0;
+
+ status = dbPutLinkAsync(plink, DBR_DOUBLE, &prec->oval, 1);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
status = dbPutLink(plink, DBR_DOUBLE, &prec->oval, 1);
- return status;
- }
- status = dbCaPutLinkCallback(plink, DBR_DOUBLE, &prec->oval, 1,
- dbCaCallbackProcess, plink);
- if (status) {
- recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
- return status;
- }
- prec->pact = TRUE;
+
return 0;
}
+
diff --git a/src/std/dev/devLoSoftCallback.c b/src/std/dev/devLoSoftCallback.c
index 2bc4a7e46..f211957b5 100644
--- a/src/std/dev/devLoSoftCallback.c
+++ b/src/std/dev/devLoSoftCallback.c
@@ -3,10 +3,10 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
+
/* devLoSoftCallback.c */
/*
* Author: Marty Kraimer
@@ -51,17 +51,15 @@ static long write_longout(longoutRecord *prec)
struct link *plink = &prec->out;
long status;
- if(prec->pact) return(0);
- if(plink->type!=CA_LINK) {
- status = dbPutLink(plink,DBR_LONG,&prec->val,1);
- return(status);
- }
- status = dbCaPutLinkCallback(plink,DBR_LONG,&prec->val,1,
- dbCaCallbackProcess,plink);
- if(status) {
- recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
- return(status);
- }
- prec->pact = TRUE;
- return(0);
+ if (prec->pact)
+ return 0;
+
+ status = dbPutLinkAsync(plink, DBR_LONG, &prec->val, 1);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
+ status = dbPutLink(plink, DBR_LONG, &prec->val, 1);
+
+ return status;
}
+
diff --git a/src/std/dev/devLsoSoftCallback.c b/src/std/dev/devLsoSoftCallback.c
index 4ab7ead9d..616b27692 100644
--- a/src/std/dev/devLsoSoftCallback.c
+++ b/src/std/dev/devLsoSoftCallback.c
@@ -31,21 +31,17 @@ static long write_string(lsoRecord *prec)
len = 1;
}
- if (plink->type != CA_LINK)
- return dbPutLink(plink, dtyp, prec->val, len);
+ status = dbPutLinkAsync(plink, dtyp, prec->val, len);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
+ status = dbPutLink(plink, dtyp, prec->val, len);
- status = dbCaPutLinkCallback(plink, dtyp, prec->val, len,
- dbCaCallbackProcess, plink);
- if (status) {
- recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
- return status;
- }
-
- prec->pact = TRUE;
- return 0;
+ return status;
}
lsodset devLsoSoftCallback = {
5, NULL, NULL, NULL, NULL, write_string
};
epicsExportAddress(dset, devLsoSoftCallback);
+
diff --git a/src/std/dev/devMbboDirectSoftCallback.c b/src/std/dev/devMbboDirectSoftCallback.c
index 8c71ef77e..e64c3d41c 100644
--- a/src/std/dev/devMbboDirectSoftCallback.c
+++ b/src/std/dev/devMbboDirectSoftCallback.c
@@ -29,20 +29,13 @@ static long write_mbbo(mbboDirectRecord *prec)
if (prec->pact)
return 0;
- if (plink->type != CA_LINK) {
+ status = dbPutLinkAsync(plink, DBR_USHORT, &prec->val, 1);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
status = dbPutLink(plink, DBR_USHORT, &prec->val, 1);
- return status;
- }
- status = dbCaPutLinkCallback(plink, DBR_USHORT, &prec->val, 1,
- dbCaCallbackProcess, plink);
- if (status) {
- recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
- return status;
- }
-
- prec->pact = TRUE;
- return 0;
+ return status;
}
/* Create the dset for devMbboSoft */
diff --git a/src/std/dev/devMbboSoftCallback.c b/src/std/dev/devMbboSoftCallback.c
index 705308163..fd5fe405a 100644
--- a/src/std/dev/devMbboSoftCallback.c
+++ b/src/std/dev/devMbboSoftCallback.c
@@ -3,10 +3,10 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
+
/* devMbboSoftCallback.c */
/*
* Author: Marty Kraimer
@@ -50,17 +50,15 @@ static long write_mbbo(mbboRecord *prec)
struct link *plink = &prec->out;
long status;
- if(prec->pact) return(0);
- if(plink->type!=CA_LINK) {
- status = dbPutLink(plink,DBR_USHORT,&prec->val,1);
- return(status);
- }
- status = dbCaPutLinkCallback(plink,DBR_USHORT,&prec->val,1,
- dbCaCallbackProcess,plink);
- if(status) {
- recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
- return(status);
- }
- prec->pact = TRUE;
- return(0);
+ if (prec->pact)
+ return 0;
+
+ status = dbPutLinkAsync(plink, DBR_USHORT, &prec->val, 1);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
+ status = dbPutLink(plink, DBR_USHORT, &prec->val, 1);
+
+ return status;
}
+
diff --git a/src/std/dev/devPrintfSoftCallback.c b/src/std/dev/devPrintfSoftCallback.c
index 7f9314d9e..51fde605d 100644
--- a/src/std/dev/devPrintfSoftCallback.c
+++ b/src/std/dev/devPrintfSoftCallback.c
@@ -31,18 +31,13 @@ static long write_string(printfRecord *prec)
len = 1;
}
- if (plink->type != CA_LINK)
- return dbPutLink(plink, dtyp, prec->val, len);
+ status = dbPutLinkAsync(plink, dtyp, prec->val, len);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
+ status = dbPutLink(plink, dtyp, prec->val, len);
- status = dbCaPutLinkCallback(plink, dtyp, prec->val, len,
- dbCaCallbackProcess, plink);
- if (status) {
- recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
- return status;
- }
-
- prec->pact = TRUE;
- return 0;
+ return status;
}
printfdset devPrintfSoftCallback = {
diff --git a/src/std/dev/devSoSoftCallback.c b/src/std/dev/devSoSoftCallback.c
index a39e14b4d..df8c5d819 100644
--- a/src/std/dev/devSoSoftCallback.c
+++ b/src/std/dev/devSoSoftCallback.c
@@ -3,11 +3,10 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* $Revision-Id$ */
+
/*
* Author: Marty Kraimer
* Date: 04NOV2003
@@ -50,19 +49,15 @@ static long write_stringout(stringoutRecord *prec)
struct link *plink = &prec->out;
long status;
- if (prec->pact) return 0;
+ if (prec->pact)
+ return 0;
- if (plink->type != CA_LINK) {
- return dbPutLink(plink, DBR_STRING, &prec->val, 1);
- }
+ status = dbPutLinkAsync(plink, DBR_STRING, &prec->val, 1);
+ if (!status)
+ prec->pact = TRUE;
+ else if (status == S_db_noLSET)
+ status = dbPutLink(plink, DBR_STRING, &prec->val, 1);
- status = dbCaPutLinkCallback(plink, DBR_STRING, &prec->val, 1,
- dbCaCallbackProcess, plink);
- if (status) {
- recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
- return status;
- }
-
- prec->pact = TRUE;
- return 0;
+ return status;
}
+
From cbc7af0ef8fb25a27b1d08a5af8bbee5f64883d9 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 15 Aug 2016 20:19:19 -0500
Subject: [PATCH 031/112] Remove 2 obsolete dbStatic routines (forms)
---
src/ioc/dbStatic/dbStaticLib.c | 61 ----------------------------------
src/ioc/dbStatic/dbStaticLib.h | 2 --
2 files changed, 63 deletions(-)
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index 9ef89e802..a09b999aa 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -3193,67 +3193,6 @@ int dbGetLinkType(DBENTRY *pdbentry)
return(-1);
}
-long dbCvtLinkToConstant(DBENTRY *pdbentry)
-{
- dbFldDes *pflddes;
- DBLINK *plink;
-
- dbGetFieldAddress(pdbentry);
- pflddes = pdbentry->pflddes;
- if(!pflddes) return(-1);
- plink = (DBLINK *)pdbentry->pfield;
- if(!plink) return(-1);
- switch (pflddes->field_type) {
- case DBF_INLINK:
- case DBF_OUTLINK:
- case DBF_FWDLINK:
- if(plink->type == CONSTANT) return(0);
- if(plink->type != PV_LINK) return(S_dbLib_badLink);
- free((void *)plink->value.pv_link.pvname);
- plink->value.pv_link.pvname = NULL;
- plink->type = CONSTANT;
- if(pflddes->initial) {
- plink->value.constantStr =
- dbCalloc(strlen(pflddes->initial)+1,sizeof(char));
- strcpy(plink->value.constantStr,pflddes->initial);
- } else {
- plink->value.constantStr = NULL;
- }
- return(0);
- default:
- epicsPrintf("dbCvtLinkToConstant called for non link field\n");
- }
- return(S_dbLib_badLink);
-}
-
-long dbCvtLinkToPvlink(DBENTRY *pdbentry)
-{
- dbFldDes *pflddes;
- DBLINK *plink;
-
- dbGetFieldAddress(pdbentry);
- pflddes = pdbentry->pflddes;
- if(!pflddes) return(-1);
- if(!pdbentry->precnode || !pdbentry->precnode->precord) return(-1);
- plink = (DBLINK *)pdbentry->pfield;
- if(!plink) return(-1);
- switch (pflddes->field_type) {
- case DBF_INLINK:
- case DBF_OUTLINK:
- case DBF_FWDLINK:
- if(plink->type == PV_LINK) return(0);
- if(plink->type != CONSTANT) return(S_dbLib_badLink);
- free(plink->value.constantStr);
- plink->type = PV_LINK;
- plink->value.pv_link.pvlMask = 0;
- plink->value.pv_link.pvname = 0;
- return(0);
- default:
- epicsPrintf("dbCvtLinkToPvlink called for non link field\n");
- }
- return(S_dbLib_badLink);
-}
-
void dbDumpPath(DBBASE *pdbbase)
{
ELLLIST *ppathList;
diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h
index e01bec25d..1015301b4 100644
--- a/src/ioc/dbStatic/dbStaticLib.h
+++ b/src/ioc/dbStatic/dbStaticLib.h
@@ -215,8 +215,6 @@ epicsShareFunc linkSup * dbFindLinkSup(dbBase *pdbbase,
epicsShareFunc int dbGetNLinks(DBENTRY *pdbentry);
epicsShareFunc long dbGetLinkField(DBENTRY *pdbentry, int index);
epicsShareFunc int dbGetLinkType(DBENTRY *pdbentry);
-epicsShareFunc long dbCvtLinkToConstant(DBENTRY *pdbentry);
-epicsShareFunc long dbCvtLinkToPvlink(DBENTRY *pdbentry);
/* Dump routines */
epicsShareFunc void dbDumpPath(DBBASE *pdbbase);
From 82385c9f1b1bab5f02243587bfc36fff775d5c38 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 18 Aug 2016 00:18:41 -0500
Subject: [PATCH 032/112] Missed a spot handling JSON_LINK field values
---
src/ioc/dbStatic/dbStaticLib.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index a09b999aa..e147374e5 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2039,6 +2039,9 @@ char * dbGetString(DBENTRY *pdbentry)
dbMsgCpy(pdbentry, "");
}
break;
+ case JSON_LINK:
+ dbMsgCpy(pdbentry, plink->value.json.string);
+ break;
case PV_LINK:
case CA_LINK:
case DB_LINK: {
@@ -2264,6 +2267,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
+ /* FIXME Parse JSON object here */
pinfo->ltype = JSON_LINK;
return 0;
}
@@ -2333,6 +2337,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Link may be an array constant */
if (pstr[0] == '[' && pstr[len-1] == ']' &&
(strchr(pstr, ',') || strchr(pstr, '"'))) {
+ /* FIXME Parse JSON array here */
pinfo->ltype = CONSTANT;
return 0;
}
From cca6a5d05a5b733a4dedd135c44e21861dfeb1ad Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 27 Aug 2016 16:26:55 -0500
Subject: [PATCH 033/112] Add isConstant and isVolatile to LSET
---
src/ioc/db/dbAccess.c | 24 ++++++-------------
src/ioc/db/dbCa.c | 1 +
src/ioc/db/dbConstLink.c | 1 +
src/ioc/db/dbDbLink.c | 1 +
src/ioc/db/dbLink.c | 51 ++++++++++++++++++++++++++++++----------
src/ioc/db/dbLink.h | 20 ++++++++++++++++
src/ioc/db/recGbl.c | 2 +-
7 files changed, 70 insertions(+), 30 deletions(-)
diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c
index 1f8b68ba6..ff94a5b53 100644
--- a/src/ioc/db/dbAccess.c
+++ b/src/ioc/db/dbAccess.c
@@ -1048,23 +1048,12 @@ static long dbPutFieldLink(DBADDR *paddr,
}
}
- switch (plink->type) { /* Old link type */
- case DB_LINK:
- case CA_LINK:
- case CONSTANT:
- dbRemoveLink(&locker, plink); /* link type becomes PV_LINK */
- break;
-
- case PV_LINK:
- case MACRO_LINK:
- break; /* should never get here */
-
- default: /* Hardware address */
- if (!isDevLink) {
- status = S_db_badHWaddr;
- goto restoreScan;
- }
- break;
+ if (dbLinkIsDefined(plink)) {
+ dbRemoveLink(&locker, plink); /* Clear out old link */
+ }
+ else if (!isDevLink) {
+ status = S_db_badHWaddr;
+ goto restoreScan;
}
if (special) status = dbPutSpecial(paddr, 0);
@@ -1097,6 +1086,7 @@ static long dbPutFieldLink(DBADDR *paddr,
switch (plink->type) { /* New link type */
case PV_LINK:
case CONSTANT:
+ case JSON_LINK:
dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr);
break;
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index 1763fe3e7..99dcd75bb 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -713,6 +713,7 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) {
}
static lset dbCa_lset = {
+ 0, 1, /* not Constant, Volatile */
dbCaRemoveLink,
NULL, NULL,
isConnected,
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 38f5d448c..a969addf3 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -85,6 +85,7 @@ static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
}
static lset dbConst_lset = {
+ 1, 0, /* Constant, not Volatile */
NULL,
dbConstLoadScalar,
dbConstLoadArray,
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index 58f089126..cdecd0ea6 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -336,6 +336,7 @@ static void dbDbScanFwdLink(struct link *plink)
}
static lset dbDb_lset = {
+ 0, 0, /* not Constant, not Volatile */
dbDbRemoveLink,
NULL, NULL,
dbDbIsConnected,
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index a877eec6e..c2ae385d0 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -120,6 +120,9 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
return;
}
+ if (plink->type != PV_LINK)
+ return;
+
if (plink == &precord->tsel)
recGblTSELwasModified(plink);
@@ -142,10 +145,45 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
}
}
-long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
+void dbRemoveLink(struct dbLocker *locker, struct link *plink)
{
lset *plset = plink->lset;
+ if (plset) {
+ if (plset->removeLink)
+ plset->removeLink(locker, plink);
+ plink->lset = NULL;
+ }
+}
+
+int dbLinkIsDefined(const struct link *plink)
+{
+ return (plink->lset != 0);
+}
+
+int dbLinkIsConstant(const struct link *plink)
+{
+ lset *plset = plink->lset;
+
+ if (plset)
+ return plset->isConstant;
+
+ return -1;
+}
+
+int dbLinkIsVolatile(const struct link *plink)
+{
+ lset *plset = plink->lset;
+
+ if (plset)
+ return plset->isVolatile;
+
+ return -1;
+}
+
+long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
+{
+ lset *plset = plink->lset;
if (plset && plset->loadScalar)
return plset->loadScalar(plink, dbrType, pbuffer);
@@ -164,17 +202,6 @@ long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
return S_db_noLSET;
}
-void dbRemoveLink(struct dbLocker *locker, struct link *plink)
-{
- lset *plset = plink->lset;
-
- if (plset) {
- if (plset->removeLink)
- plset->removeLink(locker, plink);
- plink->lset = NULL;
- }
-}
-
int dbIsLinkConnected(const struct link *plink)
{
lset *plset = plink->lset;
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index 834400c73..2903528c1 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -28,13 +28,24 @@ extern "C" {
struct dbLocker;
typedef struct lset {
+ /* Characteristics of the link type */
+ const unsigned isConstant:1;
+ const unsigned isVolatile:1;
+
+ /* Destructor */
void (*removeLink)(struct dbLocker *locker, struct link *plink);
+
+ /* Const init, data type hinting */
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest);
+
+ /* Metadata */
int (*isConnected)(const struct link *plink);
int (*getDBFtype)(const struct link *plink);
long (*getElements)(const struct link *plink, long *nelements);
+
+ /* Get data */
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest);
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
@@ -46,10 +57,14 @@ typedef struct lset {
long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity);
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
+
+ /* Put data */
long (*putValue)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
long (*putAsync)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
+
+ /* Process */
void (*scanForward)(struct link *plink);
} lset;
@@ -60,6 +75,11 @@ epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
short dbfType, DBADDR *ptarget);
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
+
+epicsShareFunc int dbLinkIsDefined(const struct link *plink); /* 0 or 1 */
+epicsShareFunc int dbLinkIsConstant(const struct link *plink); /* -1, 0 or 1 */
+epicsShareFunc int dbLinkIsVolatile(const struct link *plink); /* -1, 0 or 1 */
+
epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
void *pbuffer);
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c
index 19bc425ba..0d835b9a4 100644
--- a/src/ioc/db/recGbl.c
+++ b/src/ioc/db/recGbl.c
@@ -256,7 +256,7 @@ void recGblGetTimeStamp(void *pvoid)
dbCommon* prec = (dbCommon*)pvoid;
struct link *plink = &prec->tsel;
- if (plink->type != CONSTANT) {
+ if (!dbLinkIsConstant(plink)) {
struct pv_link *ppv_link = &plink->value.pv_link;
if (ppv_link->pvlMask & pvlOptTSELisTime) {
From 37b6cbb50cb8f1fddec779766282c71459754147 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 27 Aug 2016 16:30:48 -0500
Subject: [PATCH 034/112] Use new dbLink APIs instead of checking link.type
---
src/std/dev/devAaiSoft.c | 14 ++---
src/std/dev/devAaoSoft.c | 2 +-
src/std/dev/devAiSoft.c | 12 ++--
src/std/dev/devAiSoftRaw.c | 7 +--
src/std/dev/devBiDbState.c | 2 +-
src/std/dev/devBiSoft.c | 11 ++--
src/std/dev/devBiSoftRaw.c | 6 +-
src/std/dev/devEventSoft.c | 10 ++--
src/std/dev/devHistogramSoft.c | 7 +--
src/std/dev/devLiSoft.c | 9 ++-
src/std/dev/devLsiSoft.c | 2 +-
src/std/dev/devMbbiDirectSoft.c | 12 ++--
src/std/dev/devMbbiDirectSoftRaw.c | 13 +++--
src/std/dev/devMbbiSoft.c | 13 ++---
src/std/dev/devMbbiSoftRaw.c | 13 +++--
src/std/dev/devSASoft.c | 16 ++++--
src/std/dev/devSiSoft.c | 10 ++--
src/std/dev/devWfSoft.c | 4 +-
src/std/rec/aSubRecord.c | 17 ++----
src/std/rec/aaiRecord.c | 4 +-
src/std/rec/aaoRecord.c | 4 +-
src/std/rec/aiRecord.c | 9 +--
src/std/rec/aoRecord.c | 14 ++---
src/std/rec/boRecord.c | 52 ++++++++---------
src/std/rec/calcRecord.c | 4 +-
src/std/rec/calcoutRecord.c | 92 +++++++++++++++++++-----------
src/std/rec/dfanoutRecord.c | 23 ++++----
src/std/rec/eventRecord.c | 9 +--
src/std/rec/fanoutRecord.c | 5 +-
src/std/rec/histogramRecord.c | 9 +--
src/std/rec/longinRecord.c | 39 +++++++------
src/std/rec/longoutRecord.c | 52 +++++++++--------
src/std/rec/mbbiDirectRecord.c | 7 +--
src/std/rec/mbbiRecord.c | 7 +--
src/std/rec/mbboDirectRecord.c | 11 ++--
src/std/rec/mbboRecord.c | 11 ++--
src/std/rec/printfRecord.c | 10 ++--
src/std/rec/selRecord.c | 17 +++---
src/std/rec/seqRecord.c | 12 ++--
src/std/rec/stringinRecord.c | 40 ++++++-------
src/std/rec/stringoutRecord.c | 57 +++++++++---------
src/std/rec/subRecord.c | 4 +-
src/std/rec/waveformRecord.c | 10 ++--
43 files changed, 328 insertions(+), 354 deletions(-)
diff --git a/src/std/dev/devAaiSoft.c b/src/std/dev/devAaiSoft.c
index 31626bacb..ab6476ea9 100644
--- a/src/std/dev/devAaiSoft.c
+++ b/src/std/dev/devAaiSoft.c
@@ -78,16 +78,16 @@ static long init_record(aaiRecord *prec)
static long read_aai(aaiRecord *prec)
{
long nRequest = prec->nelm;
+ long status = dbGetLink(prec->simm == menuYesNoYES ? &prec->siol :
+ &prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
- dbGetLink(prec->simm == menuYesNoYES ? &prec->siol : &prec->inp,
- prec->ftvl, prec->bptr, 0, &nRequest);
- if (nRequest > 0) {
+ if (!status && nRequest > 0) {
prec->nord = nRequest;
- prec->udf=FALSE;
- if (prec->tsel.type == CONSTANT &&
+ prec->udf = FALSE;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
-
- return 0;
+ return status;
}
diff --git a/src/std/dev/devAaoSoft.c b/src/std/dev/devAaoSoft.c
index a88d61140..dd96d10c0 100644
--- a/src/std/dev/devAaoSoft.c
+++ b/src/std/dev/devAaoSoft.c
@@ -52,7 +52,7 @@ epicsExportAddress(dset,devAaoSoft);
static long init_record(aaoRecord *prec)
{
- if (prec->out.type == CONSTANT) {
+ if (dbLinkIsConstant(&prec->out)) {
prec->nord = 0;
}
return 0;
diff --git a/src/std/dev/devAiSoft.c b/src/std/dev/devAiSoft.c
index ccd713d75..ba669f4c9 100644
--- a/src/std/dev/devAiSoft.c
+++ b/src/std/dev/devAiSoft.c
@@ -51,10 +51,9 @@ epicsExportAddress(dset, devAiSoft);
static long init_record(aiRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- if (recGblInitConstantLink(&prec->inp, DBF_DOUBLE, &prec->val))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->inp, DBF_DOUBLE, &prec->val))
+ prec->udf = FALSE;
+
return 0;
}
@@ -62,9 +61,6 @@ static long read_ai(aiRecord *prec)
{
double val;
- if (prec->inp.type == CONSTANT)
- return 2;
-
if (!dbGetLink(&prec->inp, DBR_DOUBLE, &val, 0, 0)) {
/* Apply smoothing algorithm */
@@ -76,7 +72,7 @@ static long read_ai(aiRecord *prec)
prec->udf = FALSE;
prec->dpvt = &devAiSoft; /* Any non-zero value */
- if (prec->tsel.type == CONSTANT &&
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
} else {
diff --git a/src/std/dev/devAiSoftRaw.c b/src/std/dev/devAiSoftRaw.c
index fa9d869ed..1ec289b38 100644
--- a/src/std/dev/devAiSoftRaw.c
+++ b/src/std/dev/devAiSoftRaw.c
@@ -50,16 +50,15 @@ epicsExportAddress(dset, devAiSoftRaw);
static long init_record(aiRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->rval);
- }
+ recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->rval);
+
return 0;
}
static long read_ai(aiRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0) &&
- prec->tsel.type == CONSTANT &&
+ dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
diff --git a/src/std/dev/devBiDbState.c b/src/std/dev/devBiDbState.c
index c0d7120b2..b0670c6db 100644
--- a/src/std/dev/devBiDbState.c
+++ b/src/std/dev/devBiDbState.c
@@ -66,7 +66,7 @@ static long read_bi(biRecord *prec)
prec->udf = FALSE;
}
- if (prec->tsel.type == CONSTANT &&
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
diff --git a/src/std/dev/devBiSoft.c b/src/std/dev/devBiSoft.c
index 4b0ee854a..a9364debc 100644
--- a/src/std/dev/devBiSoft.c
+++ b/src/std/dev/devBiSoft.c
@@ -48,19 +48,16 @@ epicsExportAddress(dset, devBiSoft);
static long init_record(biRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
+ prec->udf = FALSE;
return 0;
}
static long read_bi(biRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_USHORT, &prec->val, 0, 0)) {
- if (prec->inp.type != CONSTANT)
- prec->udf = FALSE;
- if (prec->tsel.type == CONSTANT &&
+ prec->udf = FALSE;
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
diff --git a/src/std/dev/devBiSoftRaw.c b/src/std/dev/devBiSoftRaw.c
index 3f40bade8..2d8dc25e5 100644
--- a/src/std/dev/devBiSoftRaw.c
+++ b/src/std/dev/devBiSoftRaw.c
@@ -48,16 +48,14 @@ epicsExportAddress(dset, devBiSoftRaw);
static long init_record(biRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
- }
+ recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
return 0;
}
static long read_bi(biRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_ULONG, &prec->rval, 0, 0) &&
- prec->tsel.type == CONSTANT &&
+ dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
diff --git a/src/std/dev/devEventSoft.c b/src/std/dev/devEventSoft.c
index 09987cb5b..c9a5f273e 100644
--- a/src/std/dev/devEventSoft.c
+++ b/src/std/dev/devEventSoft.c
@@ -48,10 +48,8 @@ epicsExportAddress(dset, devEventSoft);
static long init_record(eventRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- if (recGblInitConstantLink(&prec->inp, DBF_STRING, &prec->val))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->inp, DBF_STRING, &prec->val))
+ prec->udf = FALSE;
return 0;
}
@@ -60,7 +58,7 @@ static long read_event(eventRecord *prec)
long status;
char newEvent[MAX_STRING_SIZE];
- if (prec->inp.type != CONSTANT) {
+ if (!dbLinkIsConstant(&prec->inp)) {
status = dbGetLink(&prec->inp, DBR_STRING, newEvent, 0, 0);
if (status) return status;
if (strcmp(newEvent, prec->val) != 0) {
@@ -69,7 +67,7 @@ static long read_event(eventRecord *prec)
}
}
prec->udf = FALSE;
- if (prec->tsel.type == CONSTANT &&
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
return 0;
diff --git a/src/std/dev/devHistogramSoft.c b/src/std/dev/devHistogramSoft.c
index 21a09b52e..60e6e3ddd 100644
--- a/src/std/dev/devHistogramSoft.c
+++ b/src/std/dev/devHistogramSoft.c
@@ -52,10 +52,9 @@ epicsExportAddress(dset,devHistogramSoft);
static long init_record(histogramRecord *prec)
{
- if (prec->svl.type == CONSTANT) {
- if(recGblInitConstantLink(&prec->svl,DBF_DOUBLE,&prec->sgnl))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->svl,DBF_DOUBLE,&prec->sgnl))
+ prec->udf = FALSE;
+
return 0;
}
diff --git a/src/std/dev/devLiSoft.c b/src/std/dev/devLiSoft.c
index 3deea8493..0752b4f30 100644
--- a/src/std/dev/devLiSoft.c
+++ b/src/std/dev/devLiSoft.c
@@ -48,10 +48,9 @@ epicsExportAddress(dset, devLiSoft);
static long init_record(longinRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- if (recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->val))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->val))
+ prec->udf = FALSE;
+
return 0;
}
@@ -61,7 +60,7 @@ static long read_longin(longinRecord *prec)
status = dbGetLink(&prec->inp, DBR_LONG, &prec->val, 0, 0);
if (!status &&
- prec->tsel.type == CONSTANT &&
+ dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
return status;
diff --git a/src/std/dev/devLsiSoft.c b/src/std/dev/devLsiSoft.c
index a5547cba8..aadd48f0d 100644
--- a/src/std/dev/devLsiSoft.c
+++ b/src/std/dev/devLsiSoft.c
@@ -29,7 +29,7 @@ static long read_string(lsiRecord *prec)
long status = dbGetLinkLS(&prec->inp, prec->val, prec->sizv, &prec->len);
if (!status &&
- prec->tsel.type == CONSTANT &&
+ dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
diff --git a/src/std/dev/devMbbiDirectSoft.c b/src/std/dev/devMbbiDirectSoft.c
index ccbc7efe7..27dd2eb1f 100644
--- a/src/std/dev/devMbbiDirectSoft.c
+++ b/src/std/dev/devMbbiDirectSoft.c
@@ -48,19 +48,17 @@ epicsExportAddress(dset, devMbbiDirectSoft);
static long init_record(mbbiDirectRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
+ prec->udf = FALSE;
+
return 0;
}
static long read_mbbi(mbbiDirectRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_USHORT, &prec->val, 0, 0)) {
- if (prec->inp.type != CONSTANT)
- prec->udf = FALSE;
- if (prec->tsel.type == CONSTANT &&
+ prec->udf = FALSE;
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
diff --git a/src/std/dev/devMbbiDirectSoftRaw.c b/src/std/dev/devMbbiDirectSoftRaw.c
index 3824cdc14..2509ed392 100644
--- a/src/std/dev/devMbbiDirectSoftRaw.c
+++ b/src/std/dev/devMbbiDirectSoftRaw.c
@@ -48,11 +48,12 @@ epicsExportAddress(dset, devMbbiDirectSoftRaw);
static long init_record(mbbiDirectRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
- }
- /*to preserve old functionality*/
- if (prec->nobt == 0) prec->mask = 0xffffffff;
+ recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
+
+ /* Preserve old functionality */
+ if (prec->nobt == 0)
+ prec->mask = 0xffffffff;
+
prec->mask <<= prec->shft;
return 0;
}
@@ -61,7 +62,7 @@ static long read_mbbi(mbbiDirectRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0)) {
prec->rval &= prec->mask;
- if (prec->tsel.type == CONSTANT &&
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
diff --git a/src/std/dev/devMbbiSoft.c b/src/std/dev/devMbbiSoft.c
index 210699fa6..406e8b6ec 100644
--- a/src/std/dev/devMbbiSoft.c
+++ b/src/std/dev/devMbbiSoft.c
@@ -48,19 +48,18 @@ epicsExportAddress(dset, devMbbiSoft);
static long init_record(mbbiRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
+ prec->udf = FALSE;
+
return 0;
}
static long read_mbbi(mbbiRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_USHORT, &prec->val, 0, 0)) {
- if (prec->inp.type != CONSTANT)
- prec->udf = FALSE;
- if (prec->tsel.type == CONSTANT &&
+ prec->udf = FALSE;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
diff --git a/src/std/dev/devMbbiSoftRaw.c b/src/std/dev/devMbbiSoftRaw.c
index 4d5b57cb9..ffe0b00f7 100644
--- a/src/std/dev/devMbbiSoftRaw.c
+++ b/src/std/dev/devMbbiSoftRaw.c
@@ -48,11 +48,12 @@ epicsExportAddress(dset, devMbbiSoftRaw);
static long init_record(mbbiRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
- }
- /*to preserve old functionality*/
- if (prec->nobt == 0) prec->mask = 0xffffffff;
+ recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
+
+ /* Preserve old functionality*/
+ if (prec->nobt == 0)
+ prec->mask = 0xffffffff;
+
prec->mask <<= prec->shft;
return 0;
}
@@ -61,7 +62,7 @@ static long read_mbbi(mbbiRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0)) {
prec->rval &= prec->mask;
- if (prec->tsel.type == CONSTANT &&
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
diff --git a/src/std/dev/devSASoft.c b/src/std/dev/devSASoft.c
index 049fa644e..84c31c5a6 100644
--- a/src/std/dev/devSASoft.c
+++ b/src/std/dev/devSASoft.c
@@ -48,10 +48,16 @@ epicsExportAddress(dset, devSASoft);
static long init_record(subArrayRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- prec->nord = 0;
+ long nelm = prec->nelm;
+ long status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nelm);
+
+ if (!status && nelm > 0) {
+ prec->nord = nelm;
+ prec->udf = FALSE;
}
- return 0;
+ else
+ prec->nord = 0;
+ return status;
}
static long read_sa(subArrayRecord *prec)
@@ -62,7 +68,7 @@ static long read_sa(subArrayRecord *prec)
if (nRequest > prec->malm)
nRequest = prec->malm;
- if (prec->inp.type == CONSTANT)
+ if (dbLinkIsConstant(&prec->inp))
nRequest = prec->nord;
else
dbGetLink(&prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
@@ -81,7 +87,7 @@ static long read_sa(subArrayRecord *prec)
prec->nord = ecount;
if (nRequest > 0 &&
- prec->tsel.type == CONSTANT &&
+ dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
diff --git a/src/std/dev/devSiSoft.c b/src/std/dev/devSiSoft.c
index 044a41afb..a969185b7 100644
--- a/src/std/dev/devSiSoft.c
+++ b/src/std/dev/devSiSoft.c
@@ -50,10 +50,8 @@ epicsExportAddress(dset, devSiSoft);
static long init_record(stringinRecord *prec)
{
- if (prec->inp.type == CONSTANT) {
- if (recGblInitConstantLink(&prec->inp, DBF_STRING, prec->val))
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->inp, DBF_STRING, prec->val))
+ prec->udf = FALSE;
return 0;
}
@@ -63,9 +61,9 @@ static long read_stringin(stringinRecord *prec)
status = dbGetLink(&prec->inp, DBR_STRING, prec->val, 0, 0);
if (!status) {
- if (prec->inp.type != CONSTANT)
+ if (!dbLinkIsConstant(&prec->inp))
prec->udf = FALSE;
- if (prec->tsel.type == CONSTANT &&
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c
index 9093344d7..35ddf73b6 100644
--- a/src/std/dev/devWfSoft.c
+++ b/src/std/dev/devWfSoft.c
@@ -68,7 +68,9 @@ static long read_wf(waveformRecord *prec)
if (!status && nRequest > 0) {
prec->nord = nRequest;
- if (prec->tsel.type == CONSTANT &&
+ prec->udf = FALSE;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
diff --git a/src/std/rec/aSubRecord.c b/src/std/rec/aSubRecord.c
index 2e0785087..02461c135 100644
--- a/src/std/rec/aSubRecord.c
+++ b/src/std/rec/aSubRecord.c
@@ -121,22 +121,17 @@ static long init_record(aSubRecord *prec, int pass)
}
/* Initialize the Subroutine Name Link */
- if (prec->subl.type == CONSTANT) {
- recGblInitConstantLink(&prec->subl, DBF_STRING, prec->snam);
- }
+ recGblInitConstantLink(&prec->subl, DBF_STRING, prec->snam);
/* Initialize Input Links */
for (i = 0; i < NUM_ARGS; i++) {
struct link *plink = &(&prec->inpa)[i];
+ short dbr = (&prec->fta)[i];
+ long n = (&prec->noa)[i];
- if (plink->type == CONSTANT) {
- short dbr = (&prec->fta)[i];
- long n = (&prec->noa)[i];
-
- dbLoadLinkArray(plink, dbr, (&prec->a)[i], &n);
- if (n > 0)
- (&prec->nea)[i] = n;
- }
+ dbLoadLinkArray(plink, dbr, (&prec->a)[i], &n);
+ if (n > 0)
+ (&prec->nea)[i] = n;
}
/* Call the user initialization routine if there is one */
diff --git a/src/std/rec/aaiRecord.c b/src/std/rec/aaiRecord.c
index 9e1286704..612b2d8c5 100644
--- a/src/std/rec/aaiRecord.c
+++ b/src/std/rec/aaiRecord.c
@@ -140,9 +140,7 @@ static long init_record(aaiRecord *prec, int pass)
return 0;
}
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
+ recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
/* must have read_aai function defined */
if (pdset->number < 5 || pdset->read_aai == NULL) {
diff --git a/src/std/rec/aaoRecord.c b/src/std/rec/aaoRecord.c
index 83a73328e..b547a4c00 100644
--- a/src/std/rec/aaoRecord.c
+++ b/src/std/rec/aaoRecord.c
@@ -140,9 +140,7 @@ static long init_record(aaoRecord *prec, int pass)
return 0;
}
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
+ recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
/* must have write_aao function defined */
if (pdset->number < 5 || pdset->write_aao == NULL) {
diff --git a/src/std/rec/aiRecord.c b/src/std/rec/aiRecord.c
index b13c856f8..9d20cab0d 100644
--- a/src/std/rec/aiRecord.c
+++ b/src/std/rec/aiRecord.c
@@ -111,13 +111,8 @@ static long init_record(void *precord,int pass)
if (pass==0) return(0);
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
-
- if (prec->siol.type == CONSTANT) {
- recGblInitConstantLink(&prec->siol,DBF_DOUBLE,&prec->sval);
- }
+ recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
+ recGblInitConstantLink(&prec->siol,DBF_DOUBLE,&prec->sval);
if(!(pdset = (aidset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"ai: init_record");
diff --git a/src/std/rec/aoRecord.c b/src/std/rec/aoRecord.c
index 28b0c3c0c..a32c5bb55 100644
--- a/src/std/rec/aoRecord.c
+++ b/src/std/rec/aoRecord.c
@@ -110,19 +110,15 @@ static long init_record(aoRecord *prec, int pass)
if (pass==0) return(0);
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
+ recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
if(!(pdset = (struct aodset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"ao: init_record");
return(S_dev_noDSET);
}
/* get the initial value if dol is a constant*/
- if (prec->dol.type == CONSTANT) {
- if(recGblInitConstantLink(&prec->dol,DBF_DOUBLE,&prec->val))
- prec->udf = isnan(prec->val);
- }
+ if (recGblInitConstantLink(&prec->dol,DBF_DOUBLE,&prec->val))
+ prec->udf = isnan(prec->val);
/* must have write_ao function defined */
if ((pdset->number < 6) || (pdset->write_ao ==NULL)) {
@@ -189,8 +185,8 @@ static long process(aoRecord *prec)
/* fetch value and convert*/
if (prec->pact == FALSE) {
- if ((prec->dol.type != CONSTANT)
- && (prec->omsl == menuOmslclosed_loop)) {
+ if (!dbLinkIsConstant(&prec->dol) &&
+ prec->omsl == menuOmslclosed_loop) {
status = fetch_value(prec, &value);
}
else {
diff --git a/src/std/rec/boRecord.c b/src/std/rec/boRecord.c
index d0ed38146..24b842d87 100644
--- a/src/std/rec/boRecord.c
+++ b/src/std/rec/boRecord.c
@@ -132,43 +132,40 @@ static void myCallbackFunc(CALLBACK *arg)
static long init_record(boRecord *prec,int pass)
{
- struct bodset *pdset;
- long status=0;
+ struct bodset *pdset = (struct bodset *) prec->dset;
+ unsigned short ival = 0;
+ long status = 0;
myCallback *pcallback;
- if (pass==0) return(0);
+ if (pass == 0)
+ return 0;
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+
+ if (!pdset) {
+ recGblRecordError(S_dev_noDSET, prec, "bo: init_record");
+ return S_dev_noDSET;
}
- if(!(pdset = (struct bodset *)(prec->dset))) {
- recGblRecordError(S_dev_noDSET,(void *)prec,"bo: init_record");
- return(S_dev_noDSET);
- }
/* must have write_bo functions defined */
- if( (pdset->number < 5) || (pdset->write_bo == NULL) ) {
- recGblRecordError(S_dev_missingSup,(void *)prec,"bo: init_record");
- return(S_dev_missingSup);
+ if ((pdset->number < 5) || (pdset->write_bo == NULL)) {
+ recGblRecordError(S_dev_missingSup, prec, "bo: init_record");
+ return S_dev_missingSup;
}
+
/* get the initial value */
- if (prec->dol.type == CONSTANT) {
- unsigned short ival = 0;
-
- if(recGblInitConstantLink(&prec->dol,DBF_USHORT,&ival)) {
- if (ival == 0) prec->val = 0;
- else prec->val = 1;
- prec->udf = FALSE;
- }
+ if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &ival)) {
+ prec->val = !!ival;
+ prec->udf = FALSE;
}
- pcallback = (myCallback *)(calloc(1,sizeof(myCallback)));
- prec->rpvt = (void *)pcallback;
- callbackSetCallback(myCallbackFunc,&pcallback->callback);
- callbackSetUser(pcallback,&pcallback->callback);
- pcallback->precord = (struct dbCommon *)prec;
+ pcallback = (myCallback *) calloc(1, sizeof(myCallback));
+ prec->rpvt = pcallback;
+ callbackSetCallback(myCallbackFunc, &pcallback->callback);
+ callbackSetUser(pcallback, &pcallback->callback);
+ pcallback->precord = (struct dbCommon *) prec;
- if( pdset->init_record ) {
+ if (pdset->init_record) {
status=(*pdset->init_record)(prec);
if(status==0) {
if(prec->rval==0) prec->val = 0;
@@ -202,7 +199,8 @@ static long process(boRecord *prec)
return(S_dev_missingSup);
}
if (!prec->pact) {
- if ((prec->dol.type != CONSTANT) && (prec->omsl == menuOmslclosed_loop)){
+ if (!dbLinkIsConstant(&prec->dol) &&
+ prec->omsl == menuOmslclosed_loop) {
unsigned short val;
prec->pact = TRUE;
diff --git a/src/std/rec/calcRecord.c b/src/std/rec/calcRecord.c
index a83ee073a..b479b779b 100644
--- a/src/std/rec/calcRecord.c
+++ b/src/std/rec/calcRecord.c
@@ -100,9 +100,7 @@ static long init_record(calcRecord *prec, int pass)
plink = &prec->inpa;
pvalue = &prec->a;
for (i = 0; i < CALCPERFORM_NARGS; i++, plink++, pvalue++) {
- if (plink->type == CONSTANT) {
- recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
- }
+ recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
if (postfix(prec->calc, prec->rpcl, &error_number)) {
recGblRecordError(S_db_badField, (void *)prec,
diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c
index c62b3f446..217c2abf0 100644
--- a/src/std/rec/calcoutRecord.c
+++ b/src/std/rec/calcoutRecord.c
@@ -25,6 +25,7 @@
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbEvent.h"
+#include "dbLink.h"
#include "dbScan.h"
#include "cantProceed.h"
#include "epicsMath.h"
@@ -141,42 +142,57 @@ static long init_record(calcoutRecord *prec, int pass)
epicsEnum16 *plinkValid;
short error_number;
calcoutDSET *pcalcoutDSET;
-
- DBADDR dbaddr;
- DBADDR *pAddr = &dbaddr;
rpvtStruct *prpvt;
if (pass == 0) {
prec->rpvt = (rpvtStruct *) callocMustSucceed(1, sizeof(rpvtStruct), "calcoutRecord");
return 0;
}
+
if (!(pcalcoutDSET = (calcoutDSET *)prec->dset)) {
recGblRecordError(S_dev_noDSET, (void *)prec, "calcout:init_record");
return S_dev_noDSET;
}
+
/* must have write defined */
if ((pcalcoutDSET->number < 5) || (pcalcoutDSET->write ==NULL)) {
recGblRecordError(S_dev_missingSup, (void *)prec, "calcout:init_record");
return S_dev_missingSup;
}
+
prpvt = prec->rpvt;
plink = &prec->inpa;
pvalue = &prec->a;
plinkValid = &prec->inav;
+
for (i = 0; i <= CALCPERFORM_NARGS; i++, plink++, pvalue++, plinkValid++) {
- if (plink->type == CONSTANT) {
- /* Don't InitConstantLink the .OUT link */
- if (i < CALCPERFORM_NARGS) {
- recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
- }
+ /* Don't InitConstantLink the .OUT link */
+ if (i < CALCPERFORM_NARGS) {
+ recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
+ }
+
+ if (dbLinkIsConstant(plink)) {
*plinkValid = calcoutINAV_CON;
- } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) {
- /* PV resides on this ioc */
+ }
+ else if (dbLinkIsVolatile(plink)) {
+ int conn = dbIsLinkConnected(plink);
+
+ if (conn)
+ *plinkValid = calcoutINAV_EXT;
+ else {
+ /* Monitor for connection */
+ *plinkValid = calcoutINAV_EXT_NC;
+ prpvt->caLinkStat = CA_LINKS_NOT_OK;
+ }
+ }
+ else {
+ /* PV must reside on this ioc */
*plinkValid = calcoutINAV_LOC;
- } else {
- /* pv is not on this ioc. Callback later for connection stat */
- *plinkValid = calcoutINAV_EXT_NC;
- prpvt->caLinkStat = CA_LINKS_NOT_OK;
+
+ if (!dbIsLinkConnected(plink)) {
+ errlogPrintf("calcout: %s.INP%c in no-vo disco state\n",
+ prec->name, i+'A');
+ }
}
}
@@ -298,8 +314,6 @@ static long special(DBADDR *paddr, int after)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
rpvtStruct *prpvt = prec->rpvt;
- DBADDR dbaddr;
- DBADDR *pAddr = &dbaddr;
short error_number;
int fieldIndex = dbGetFieldIndex(paddr);
int lnkIndex;
@@ -347,23 +361,35 @@ static long special(DBADDR *paddr, int after)
plink = &prec->inpa + lnkIndex;
pvalue = &prec->a + lnkIndex;
plinkValid = &prec->inav + lnkIndex;
- if (plink->type == CONSTANT) {
- if (fieldIndex != calcoutRecordOUT) {
- recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
- db_post_events(prec, pvalue, DBE_VALUE);
- }
+
+ if (fieldIndex != calcoutRecordOUT)
+ recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
+ if (dbLinkIsConstant(plink)) {
+ db_post_events(prec, pvalue, DBE_VALUE);
*plinkValid = calcoutINAV_CON;
- } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) {
- /* if the PV resides on this ioc */
+ } else if (dbLinkIsVolatile(plink)) {
+ int conn = dbIsLinkConnected(plink);
+
+ if (conn)
+ *plinkValid = calcoutINAV_EXT;
+ else {
+ /* Monitor for connection */
+ *plinkValid = calcoutINAV_EXT_NC;
+ /* DO_CALLBACK, if not already scheduled */
+ if (!prpvt->cbScheduled) {
+ callbackRequestDelayed(&prpvt->checkLinkCb, .5);
+ prpvt->cbScheduled = 1;
+ prpvt->caLinkStat = CA_LINKS_NOT_OK;
+ }
+ }
+ }
+ else {
+ /* PV must reside on this ioc */
*plinkValid = calcoutINAV_LOC;
- } else {
- /* pv is not on this ioc. Callback later for connection stat */
- *plinkValid = calcoutINAV_EXT_NC;
- /* DO_CALLBACK, if not already scheduled */
- if (!prpvt->cbScheduled) {
- callbackRequestDelayed(&prpvt->checkLinkCb, .5);
- prpvt->cbScheduled = 1;
- prpvt->caLinkStat = CA_LINKS_NOT_OK;
+
+ if (!dbIsLinkConnected(plink)) {
+ errlogPrintf("calcout: %s.INP%c in no-vo diso state\n",
+ prec->name, lnkIndex);
}
}
db_post_events(prec, plinkValid, DBE_VALUE);
@@ -706,9 +732,9 @@ static void checkLinks(calcoutRecord *prec)
plinkValid = &prec->inav;
for (i = 0; itype == CA_LINK) {
+ if (dbLinkIsVolatile(plink) == 1) {
caLink = 1;
- stat = dbCaIsLinkConnected(plink);
+ stat = dbIsLinkConnected(plink);
if (!stat && (*plinkValid == calcoutINAV_EXT_NC)) {
caLinkNc = 1;
}
diff --git a/src/std/rec/dfanoutRecord.c b/src/std/rec/dfanoutRecord.c
index 15d06fb3c..d25093d4f 100644
--- a/src/std/rec/dfanoutRecord.c
+++ b/src/std/rec/dfanoutRecord.c
@@ -95,24 +95,27 @@ static void push_values(dfanoutRecord *);
static long init_record(dfanoutRecord *prec, int pass)
{
- if (pass==0) return(0);
+ if (pass==0)
+ return 0;
+
+ recGblInitConstantLink(&prec->sell, DBF_USHORT, &prec->seln);
- recGblInitConstantLink(&prec->sell,DBF_USHORT,&prec->seln);
/* get the initial value dol is a constant*/
- if(recGblInitConstantLink(&prec->dol,DBF_DOUBLE,&prec->val))
- prec->udf = isnan(prec->val);
- return(0);
+ if (recGblInitConstantLink(&prec->dol, DBF_DOUBLE, &prec->val))
+ prec->udf = isnan(prec->val);
+
+ return 0;
}
static long process(dfanoutRecord *prec)
{
long status=0;
- if (!prec->pact
- && (prec->dol.type != CONSTANT)
- && (prec->omsl == menuOmslclosed_loop)){
- status = dbGetLink(&(prec->dol),DBR_DOUBLE,&(prec->val),0,0);
- if(prec->dol.type!=CONSTANT && RTN_SUCCESS(status))
+ if (!prec->pact &&
+ !dbLinkIsConstant(&prec->dol) &&
+ prec->omsl == menuOmslclosed_loop) {
+ status = dbGetLink(&prec->dol, DBR_DOUBLE, &prec->val, 0, 0);
+ if (!dbLinkIsConstant(&prec->dol) && !status)
prec->udf = isnan(prec->val);
}
prec->pact = TRUE;
diff --git a/src/std/rec/eventRecord.c b/src/std/rec/eventRecord.c
index a7f9c82a9..35fd32192 100644
--- a/src/std/rec/eventRecord.c
+++ b/src/std/rec/eventRecord.c
@@ -100,13 +100,8 @@ static long init_record(eventRecord *prec, int pass)
if (pass==0) return(0);
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
-
- if (prec->siol.type == CONSTANT) {
- recGblInitConstantLink(&prec->siol,DBF_STRING,&prec->sval);
- }
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitConstantLink(&prec->siol, DBF_STRING, &prec->sval);
prec->epvt = eventNameToHandle(prec->val);
diff --git a/src/std/rec/fanoutRecord.c b/src/std/rec/fanoutRecord.c
index e2bec291c..7897fbc6f 100644
--- a/src/std/rec/fanoutRecord.c
+++ b/src/std/rec/fanoutRecord.c
@@ -106,8 +106,7 @@ static long process(fanoutRecord *prec)
case fanoutSELM_All:
plink = &prec->lnk0;
for (i = 0; i < NLINKS; i++, plink++) {
- if (plink->type != CONSTANT)
- dbScanFwdLink(plink);
+ dbScanFwdLink(plink);
}
break;
@@ -134,7 +133,7 @@ static long process(fanoutRecord *prec)
break;
plink = &prec->lnk0;
for (i = 0; i < NLINKS; i++, seln >>= 1, plink++) {
- if (seln & 1 && plink->type != CONSTANT)
+ if (seln & 1)
dbScanFwdLink(plink);
}
break;
diff --git a/src/std/rec/histogramRecord.c b/src/std/rec/histogramRecord.c
index 74b2fcd17..643c4fa68 100644
--- a/src/std/rec/histogramRecord.c
+++ b/src/std/rec/histogramRecord.c
@@ -183,13 +183,8 @@ static long init_record(histogramRecord *prec, int pass)
wdogInit(prec);
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
- }
-
- if (prec->siol.type == CONSTANT) {
- recGblInitConstantLink(&prec->siol, DBF_DOUBLE, &prec->sval);
- }
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitConstantLink(&prec->siol, DBF_DOUBLE, &prec->sval);
/* must have device support defined */
pdset = (struct histogramdset *) prec->dset;
diff --git a/src/std/rec/longinRecord.c b/src/std/rec/longinRecord.c
index bd224ac1d..91d7e2193 100644
--- a/src/std/rec/longinRecord.c
+++ b/src/std/rec/longinRecord.c
@@ -98,35 +98,36 @@ static long readValue(longinRecord *prec);
static long init_record(longinRecord *prec, int pass)
{
- struct longindset *pdset;
- long status;
+ struct longindset *pdset = (struct longindset *) prec->dset;
- if (pass==0) return(0);
+ if (pass==0)
+ return(0);
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitConstantLink(&prec->siol, DBF_LONG, &prec->sval);
+
+ if (!pdset) {
+ recGblRecordError(S_dev_noDSET, prec, "longin: init_record");
+ return S_dev_noDSET;
}
- if (prec->siol.type == CONSTANT) {
- recGblInitConstantLink(&prec->siol,DBF_LONG,&prec->sval);
- }
-
- if(!(pdset = (struct longindset *)(prec->dset))) {
- recGblRecordError(S_dev_noDSET,(void *)prec,"longin: init_record");
- return(S_dev_noDSET);
- }
/* must have read_longin function defined */
- if( (pdset->number < 5) || (pdset->read_longin == NULL) ) {
- recGblRecordError(S_dev_missingSup,(void *)prec,"longin: init_record");
- return(S_dev_missingSup);
+ if ((pdset->number < 5) || (pdset->read_longin == NULL)) {
+ recGblRecordError(S_dev_missingSup, prec, "longin: init_record");
+ return S_dev_missingSup;
}
- if( pdset->init_record ) {
- if((status=(*pdset->init_record)(prec))) return(status);
+
+ if (pdset->init_record) {
+ long status = pdset->init_record(prec);
+
+ if (status)
+ return status;
}
+
prec->mlst = prec->val;
prec->alst = prec->val;
prec->lalm = prec->val;
- return(0);
+ return 0;
}
static long process(longinRecord *prec)
diff --git a/src/std/rec/longoutRecord.c b/src/std/rec/longoutRecord.c
index afdf90ea8..5d35df634 100644
--- a/src/std/rec/longoutRecord.c
+++ b/src/std/rec/longoutRecord.c
@@ -95,33 +95,38 @@ static void convert(longoutRecord *prec, epicsInt32 value);
static long init_record(longoutRecord *prec, int pass)
{
- struct longoutdset *pdset;
- long status=0;
+ struct longoutdset *pdset = (struct longoutdset *) prec->dset;
- if (pass==0) return(0);
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
- if(!(pdset = (struct longoutdset *)(prec->dset))) {
- recGblRecordError(S_dev_noDSET,(void *)prec,"longout: init_record");
- return(S_dev_noDSET);
+ if (pass==0)
+ return 0;
+
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+
+ if (!pdset) {
+ recGblRecordError(S_dev_noDSET, prec, "longout: init_record");
+ return S_dev_noDSET;
}
+
/* must have write_longout functions defined */
- if( (pdset->number < 5) || (pdset->write_longout == NULL) ) {
- recGblRecordError(S_dev_missingSup,(void *)prec,"longout: init_record");
- return(S_dev_missingSup);
+ if ((pdset->number < 5) || (pdset->write_longout == NULL)) {
+ recGblRecordError(S_dev_missingSup, prec, "longout: init_record");
+ return S_dev_missingSup;
}
- if (prec->dol.type == CONSTANT) {
- if(recGblInitConstantLink(&prec->dol,DBF_LONG,&prec->val))
- prec->udf=FALSE;
- }
- if( pdset->init_record ) {
- if((status=(*pdset->init_record)(prec))) return(status);
+
+ if (recGblInitConstantLink(&prec->dol, DBF_LONG, &prec->val))
+ prec->udf=FALSE;
+
+ if (pdset->init_record) {
+ long status = pdset->init_record(prec);
+
+ if (status)
+ return status;
}
+
prec->mlst = prec->val;
prec->alst = prec->val;
prec->lalm = prec->val;
- return(0);
+ return 0;
}
static long process(longoutRecord *prec)
@@ -137,11 +142,10 @@ static long process(longoutRecord *prec)
return(S_dev_missingSup);
}
if (!prec->pact) {
- if((prec->dol.type != CONSTANT)
- && (prec->omsl == menuOmslclosed_loop)) {
- status = dbGetLink(&(prec->dol),DBR_LONG,
- &value,0,0);
- if (prec->dol.type!=CONSTANT && RTN_SUCCESS(status))
+ if (!dbLinkIsConstant(&prec->dol) &&
+ prec->omsl == menuOmslclosed_loop) {
+ status = dbGetLink(&prec->dol, DBR_LONG, &value, 0, 0);
+ if (!dbLinkIsConstant(&prec->dol) && !status)
prec->udf=FALSE;
}
else {
diff --git a/src/std/rec/mbbiDirectRecord.c b/src/std/rec/mbbiDirectRecord.c
index 1d603ab5a..cc1170b7e 100644
--- a/src/std/rec/mbbiDirectRecord.c
+++ b/src/std/rec/mbbiDirectRecord.c
@@ -114,11 +114,8 @@ static long init_record(mbbiDirectRecord *prec, int pass)
return S_dev_missingSup;
}
- if (prec->siml.type == CONSTANT)
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
-
- if (prec->siol.type == CONSTANT)
- recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
/* Initialize MASK if the user set NOBT instead */
if (prec->mask == 0 && prec->nobt <= 32)
diff --git a/src/std/rec/mbbiRecord.c b/src/std/rec/mbbiRecord.c
index bfc4fdba6..bd344f307 100644
--- a/src/std/rec/mbbiRecord.c
+++ b/src/std/rec/mbbiRecord.c
@@ -131,11 +131,8 @@ static long init_record(mbbiRecord *prec, int pass)
return S_dev_missingSup;
}
- if (prec->siml.type == CONSTANT)
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
-
- if (prec->siol.type == CONSTANT)
- recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
/* Initialize MASK if the user set NOBT instead */
if (prec->mask == 0 && prec->nobt <= 32)
diff --git a/src/std/rec/mbboDirectRecord.c b/src/std/rec/mbboDirectRecord.c
index ae43bdcf2..fb36a0a3b 100644
--- a/src/std/rec/mbboDirectRecord.c
+++ b/src/std/rec/mbboDirectRecord.c
@@ -116,12 +116,9 @@ static long init_record(mbboDirectRecord *prec, int pass)
return S_dev_missingSup;
}
- if (prec->siml.type == CONSTANT)
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
-
- if (prec->dol.type == CONSTANT)
- if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
- prec->udf = FALSE;
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
+ prec->udf = FALSE;
/* Initialize MASK if the user set NOBT instead */
if (prec->mask == 0 && prec->nobt <= 32)
@@ -175,7 +172,7 @@ static long process(mbboDirectRecord *prec)
}
if (!pact) {
- if (prec->dol.type != CONSTANT &&
+ if (!dbLinkIsConstant(&prec->dol) &&
prec->omsl == menuOmslclosed_loop) {
epicsUInt16 val;
diff --git a/src/std/rec/mbboRecord.c b/src/std/rec/mbboRecord.c
index ffb6f1eed..9d00a6d5e 100644
--- a/src/std/rec/mbboRecord.c
+++ b/src/std/rec/mbboRecord.c
@@ -136,12 +136,9 @@ static long init_record(mbboRecord *prec, int pass)
return S_dev_missingSup;
}
- if (prec->siml.type == CONSTANT)
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
-
- if (prec->dol.type == CONSTANT)
- if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
- prec->udf = FALSE;
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
+ prec->udf = FALSE;
/* Initialize MASK if the user set NOBT instead */
if (prec->mask == 0 && prec->nobt <= 32)
@@ -206,7 +203,7 @@ static long process(mbboRecord *prec)
}
if (!pact) {
- if (prec->dol.type != CONSTANT &&
+ if (!dbLinkIsConstant(&prec->dol) &&
prec->omsl == menuOmslclosed_loop) {
epicsUInt16 val;
diff --git a/src/std/rec/printfRecord.c b/src/std/rec/printfRecord.c
index 977349ae8..f8419e4ad 100644
--- a/src/std/rec/printfRecord.c
+++ b/src/std/rec/printfRecord.c
@@ -46,7 +46,7 @@
VALTYPE val; \
int ok; \
\
- if (plink->type == CONSTANT) \
+ if (dbLinkIsConstant(plink)) \
ok = recGblInitConstantLink(plink++, DBRTYPE, &val); \
else \
ok = ! dbGetLink(plink++, DBRTYPE, &val, 0, 0); \
@@ -113,7 +113,7 @@ static void doPrintf(printfRecord *prec)
epicsInt16 i;
int ok;
- if (plink->type == CONSTANT)
+ if (dbLinkIsConstant(plink))
ok = recGblInitConstantLink(plink++, DBR_SHORT, &i);
else
ok = ! dbGetLink(plink++, DBR_SHORT, &i, 0, 0);
@@ -203,8 +203,8 @@ static void doPrintf(printfRecord *prec)
}
break;
- case 's':
- if (flags & F_LONG && plink->type != CONSTANT) {
+ case 's': /* FIXME: const strings are now supported */
+ if (flags & F_LONG && !dbLinkIsConstant(plink)) {
long n = vspace + 1;
if (precision && n > precision)
@@ -252,7 +252,7 @@ static void doPrintf(printfRecord *prec)
char val[MAX_STRING_SIZE];
int ok;
- if (plink->type == CONSTANT)
+ if (dbLinkIsConstant(plink))
ok = recGblInitConstantLink(plink++, DBR_STRING, val);
else
ok = ! dbGetLink(plink++, DBR_STRING, val, 0, 0);
diff --git a/src/std/rec/selRecord.c b/src/std/rec/selRecord.c
index b9f385173..37456feff 100644
--- a/src/std/rec/selRecord.c
+++ b/src/std/rec/selRecord.c
@@ -92,22 +92,19 @@ static long init_record(selRecord *prec, int pass)
int i;
double *pvalue;
- if (pass==0) return(0);
+ if (pass==0)
+ return 0;
/* get seln initial value if nvl is a constant*/
- if (prec->nvl.type == CONSTANT ) {
- recGblInitConstantLink(&prec->nvl,DBF_USHORT,&prec->seln);
- }
+ recGblInitConstantLink(&prec->nvl, DBF_USHORT, &prec->seln);
plink = &prec->inpa;
pvalue = &prec->a;
- for(i=0; itype==CONSTANT) {
- recGblInitConstantLink(plink,DBF_DOUBLE,pvalue);
- }
+ for (i=0; icallback);
prec->dpvt = pseqRecPvt;
- if (prec->sell.type == CONSTANT)
- recGblInitConstantLink(&prec->sell, DBF_USHORT, &prec->seln);
+ recGblInitConstantLink(&prec->sell, DBF_USHORT, &prec->seln);
grp = (linkGrp *) &prec->dly0;
for (index = 0; index < NUM_LINKS; index++, grp++) {
- if (grp->dol.type == CONSTANT)
- recGblInitConstantLink(&grp->dol, DBF_DOUBLE, &grp->dov);
+ recGblInitConstantLink(&grp->dol, DBF_DOUBLE, &grp->dov);
}
prec->oldn = prec->seln;
@@ -150,8 +148,7 @@ static long process(seqRecord *prec)
lmask = (1 << NUM_LINKS) - 1;
else {
/* Get SELN value */
- if (prec->sell.type != CONSTANT)
- dbGetLink(&prec->sell, DBR_USHORT, &prec->seln, 0, 0);
+ dbGetLink(&prec->sell, DBR_USHORT, &prec->seln, 0, 0);
if (prec->selm == seqSELM_Specified) {
int grpn = prec->seln + prec->offs;
@@ -185,7 +182,8 @@ static long process(seqRecord *prec)
pgrp = (linkGrp *) &prec->dly0;
for (i = 0; lmask; lmask >>= 1) {
if ((lmask & 1) &&
- (pgrp->lnk.type != CONSTANT || pgrp->dol.type != CONSTANT)) {
+ (!dbLinkIsConstant(&pgrp->lnk) ||
+ !dbLinkIsConstant(&pgrp->dol))) {
pcb->grps[i++] = pgrp;
}
pgrp++;
diff --git a/src/std/rec/stringinRecord.c b/src/std/rec/stringinRecord.c
index 00988223c..474b24324 100644
--- a/src/std/rec/stringinRecord.c
+++ b/src/std/rec/stringinRecord.c
@@ -95,33 +95,33 @@ static long readValue(stringinRecord *);
static long init_record(stringinRecord *prec, int pass)
{
STATIC_ASSERT(sizeof(prec->oval)==sizeof(prec->val));
- struct stringindset *pdset;
- long status;
+ struct stringindset *pdset = (struct stringindset *) prec->dset;
- if (pass==0) return(0);
+ if (pass==0)
+ return 0;
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ recGblInitConstantLink(&prec->siol, DBF_STRING, prec->sval);
+
+ if (!pdset) {
+ recGblRecordError(S_dev_noDSET, prec, "stringin: init_record");
+ return S_dev_noDSET;
}
- if (prec->siol.type == CONSTANT) {
- recGblInitConstantLink(&prec->siol,DBF_STRING,prec->sval);
- }
-
- if(!(pdset = (struct stringindset *)(prec->dset))) {
- recGblRecordError(S_dev_noDSET,(void *)prec,"stringin: init_record");
- return(S_dev_noDSET);
- }
/* must have read_stringin function defined */
- if( (pdset->number < 5) || (pdset->read_stringin == NULL) ) {
- recGblRecordError(S_dev_missingSup,(void *)prec,"stringin: init_record");
- return(S_dev_missingSup);
+ if ((pdset->number < 5) || (pdset->read_stringin == NULL)) {
+ recGblRecordError(S_dev_missingSup, prec, "stringin: init_record");
+ return S_dev_missingSup;
}
- if( pdset->init_record ) {
- if((status=(*pdset->init_record)(prec))) return(status);
+
+ if (pdset->init_record) {
+ long status = pdset->init_record(prec);
+
+ if (status)
+ return status;
}
- strcpy(prec->oval,prec->val);
- return(0);
+ strcpy(prec->oval, prec->val);
+ return 0;
}
/*
diff --git a/src/std/rec/stringoutRecord.c b/src/std/rec/stringoutRecord.c
index 1bd376176..dbb368a59 100644
--- a/src/std/rec/stringoutRecord.c
+++ b/src/std/rec/stringoutRecord.c
@@ -97,34 +97,37 @@ static long writeValue(stringoutRecord *);
static long init_record(stringoutRecord *prec, int pass)
{
STATIC_ASSERT(sizeof(prec->oval)==sizeof(prec->val));
- struct stringoutdset *pdset;
- long status=0;
+ struct stringoutdset *pdset = (struct stringoutdset *) prec->dset;
- if (pass==0) return(0);
+ if (pass==0)
+ return 0;
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+
+ if (!pdset) {
+ recGblRecordError(S_dev_noDSET, prec, "stringout: init_record");
+ return S_dev_noDSET;
}
- if(!(pdset = (struct stringoutdset *)(prec->dset))) {
- recGblRecordError(S_dev_noDSET,(void *)prec,"stringout: init_record");
- return(S_dev_noDSET);
- }
/* must have write_stringout functions defined */
- if( (pdset->number < 5) || (pdset->write_stringout == NULL) ) {
- recGblRecordError(S_dev_missingSup,(void *)prec,"stringout: init_record");
- return(S_dev_missingSup);
+ if ((pdset->number < 5) || (pdset->write_stringout == NULL)) {
+ recGblRecordError(S_dev_missingSup, prec, "stringout: init_record");
+ return S_dev_missingSup;
}
+
/* get the initial value dol is a constant*/
- if (prec->dol.type == CONSTANT){
- if(recGblInitConstantLink(&prec->dol,DBF_STRING,prec->val))
- prec->udf=FALSE;
+ if (recGblInitConstantLink(&prec->dol, DBF_STRING, prec->val))
+ prec->udf = FALSE;
+
+ if (pdset->init_record) {
+ long status = pdset->init_record(prec);
+
+ if(status)
+ return status;
}
- if( pdset->init_record ) {
- if((status=(*pdset->init_record)(prec))) return(status);
- }
- strcpy(prec->oval,prec->val);
- return(0);
+
+ strcpy(prec->oval, prec->val);
+ return 0;
}
static long process(stringoutRecord *prec)
@@ -138,13 +141,13 @@ static long process(stringoutRecord *prec)
recGblRecordError(S_dev_missingSup,(void *)prec,"write_stringout");
return(S_dev_missingSup);
}
- if (!prec->pact
- && (prec->dol.type != CONSTANT)
- && (prec->omsl == menuOmslclosed_loop)) {
- status = dbGetLink(&(prec->dol),
- DBR_STRING,prec->val,0,0);
- if(prec->dol.type!=CONSTANT && RTN_SUCCESS(status)) prec->udf=FALSE;
- }
+ if (!prec->pact &&
+ !dbLinkIsConstant(&prec->dol) &&
+ prec->omsl == menuOmslclosed_loop) {
+ status = dbGetLink(&prec->dol, DBR_STRING, prec->val, 0, 0);
+ if (!dbLinkIsConstant(&prec->dol) && !status)
+ prec->udf=FALSE;
+ }
if(prec->udf == TRUE ){
recGblSetSevr(prec,UDF_ALARM,prec->udfs);
diff --git a/src/std/rec/subRecord.c b/src/std/rec/subRecord.c
index f8808a849..9cb3ae683 100644
--- a/src/std/rec/subRecord.c
+++ b/src/std/rec/subRecord.c
@@ -101,9 +101,7 @@ static long init_record(subRecord *prec, int pass)
plink = &prec->inpa;
pvalue = &prec->a;
for (i = 0; i < INP_ARG_MAX; i++, plink++, pvalue++) {
- if (plink->type == CONSTANT) {
- recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
- }
+ recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
if (prec->inam[0]) {
diff --git a/src/std/rec/waveformRecord.c b/src/std/rec/waveformRecord.c
index c6ca2a04a..71e19014a 100644
--- a/src/std/rec/waveformRecord.c
+++ b/src/std/rec/waveformRecord.c
@@ -111,9 +111,7 @@ static long init_record(waveformRecord *prec, int pass)
return 0;
}
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
- }
+ recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
/* must have dset defined */
if (!(pdset = (struct wfdset *)(prec->dset))) {
@@ -313,7 +311,7 @@ static long readValue(waveformRecord *prec)
return (*pdset->read_wf)(prec);
}
- status = dbGetLink(&(prec->siml), DBR_ENUM, &(prec->simm),0,0);
+ status = dbGetLink(&prec->siml, DBR_ENUM, &prec->simm, 0, 0);
if (status)
return status;
@@ -329,9 +327,9 @@ static long readValue(waveformRecord *prec)
if (prec->simm == menuYesNoYES){
long nRequest = prec->nelm;
- status = dbGetLink(&(prec->siol), prec->ftvl, prec->bptr, 0, &nRequest);
+ status = dbGetLink(&prec->siol, prec->ftvl, prec->bptr, 0, &nRequest);
/* nord set only for db links: needed for old db_access */
- if (prec->siol.type != CONSTANT) {
+ if (!dbLinkIsConstant(&prec->siol)) {
prec->nord = nRequest;
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
if (status == 0)
From fc66793ee27ea62d109efbbdaa12d5e01edea1c5 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 27 Aug 2016 16:31:49 -0500
Subject: [PATCH 035/112] Start documenting changes
---
documentation/RELEASE_NOTES.html | 146 +++++++++++++++++++++++++++++++
1 file changed, 146 insertions(+)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 635198704..3b0189205 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -20,6 +20,152 @@
-->
+Device Support Address Type JSON_LINK
+
+Device support may be written to expect hardware addresses in the new
+JSON_LINK address type. Addresses loaded from a database file will be
+checked against the JSON rules, and a strict JSON representation of the result
+is provided as a C string pointed to by link.value.json.string.
+
+Currently the device support is responsible for parsing the JSON text itself.
+An event-driven JSON parser library has been included in libCom since Base-3.15,
+YAJL (Yet Another JSON Library)
+Version 1.012, documented
+here.
+
+
+JSON Link Addressing
+
+
+
+FIXME text missing here...
+
+Support routine changes
+
+For link fields in external record types and soft device support to be able
+to use the new JSON link types properly, the following changes are
+necessary:
+
+
+
+- Make all calls to recGblInitConstantLink() unconditional on the
+link type, i.e. change this code:
+
+
+ if (prec->siml.type == CONSTANT) {
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ }
+
+
+into this:
+
+
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+
+
+Note that recGblInitConstantLink() still returns true if the field was
+successfully initialized from the link.
+
+- Code like this:
+
+
+ if ((prec->dol.type != CONSTANT) &&
+
+
+should usually become:
+
+
+ if (!dbLinkIsConstant(&prec->dol) &&
+
+
+
+- Other code that compares a link type with CONSTANT should be modified to
+use the new routine dbLinkIsConstant(plink) instead.
+
+- Any code that calls dbCa routines directly or that explicitly checks if a
+link has been resolved as a CA link using code such as
+
+
+ if (plink->type == CA_LINK)
+
+
+should be modified to use the new generic routines defined in dbLink.h. As an
+example, the calcout record has been modified to use the new dbLink API.
+
+- ...
+
+
+
+FIXME text missing here...
+
+
+
+
+Constant Link Values
+
+Previously a constant link (i.e. a link that does not point to another PV,
+either local or over Channel Access) has only been able to provide a numeric
+value; any string found in a link field that was not recognized as a number was
+treated as a PV name. In this release, constant links may contain string values,
+arrays, or even arrays of strings. These are indicated by ...
+
+FIXME text missing here...
+
+
+Database Parsing of "Relaxed JSON" Values
+
+A database file can now provide a "relaxed JSON" value for a database field
+value or an info tag. Only a few field types can currently accept such values,
+but the capability is now available for use in other places in the future. If a
+JSON-capable field is written to at run-time though only strictly compliant JSON
+may be used (the dbStaticLib parser rewrites relaxed JSON values into strict
+JSON before passing them to the datase for interpretation, where the strict
+rules must be followed).
+
+"Relaxed JSON" was developed to maximize compatibility with the previous
+database parser rules and reduce the number of double-quotes that would be
+needed using strict JSON syntax. The parser will also accept strict JSON, which
+should be used when machine-generating database files. The differences are:
+
+
+
+- Strings containing only the characters a-z A-Z 0-9 _ - + .
+do not have to be enclosed in double-quote characters.
+
+- The above rule applies to map keys as well as to regular string values.
+
+- The JSON keywords null, true and false (all
+lower-case) will be recognized as keywords, so must be quoted to use any of
+these single words as a string.
+
+- Comments may be used, introduced as usual by the #
+character and extending to the end of the line.
+
+
+
+A JSON field or info value is only enclosed in quotes when the value being
+provided is a single string, and even here the quotes can be omitted in some
+cases as described above. The following shows both correct and incorrect
+excerpts from a database file:
+
+
+ record(ai, math:pi) {
+ field(INP, {const: 3.14159265358979}) # Correct
+ field(SIOL, "{const: 3.142857}") # Wrong
+
+ info(autosave, { # White-space and comments are allowed
+ fields:[DESC, SIMM],
+ pass0:[VAL]
+ }) # Correct
+ }
+
+
+Note that the record, field and info-tag names do not accept JSON
+values, so they follows the older bareword rules for quoting where the colon
+: and several additional characters are legal in a bareword
+string.
+
+
Echoless comments in iocsh
The way comments are parsed by the iocsh interpreter has changed. The
From 056edc0d8a0820259c0494d822d2ad881e0cabb2 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 28 Aug 2016 23:41:35 -0500
Subject: [PATCH 036/112] Undo buggy change
---
src/std/dev/devAiSoft.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/std/dev/devAiSoft.c b/src/std/dev/devAiSoft.c
index ba669f4c9..74a2a759a 100644
--- a/src/std/dev/devAiSoft.c
+++ b/src/std/dev/devAiSoft.c
@@ -61,6 +61,9 @@ static long read_ai(aiRecord *prec)
{
double val;
+ if (dbLinkIsConstant(&prec->inp))
+ return 2;
+
if (!dbGetLink(&prec->inp, DBR_DOUBLE, &val, 0, 0)) {
/* Apply smoothing algorithm */
From 7edc0c67ca84331a3b49b0f53cef219bd9315658 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 29 Aug 2016 01:12:09 -0500
Subject: [PATCH 037/112] JSON Links implementation
The lnkConst.c implementation is not yet complete, no support for arrays of
strings (JMOP).
Link error messages should display their record & field name, which is not yet
possible.
The ability to embed links as parameters to other link types is not complete
yet; this will be required for the calc link type.
This code currently passes all existing tests, but additional tests are needed
for the new functionality.
---
src/ioc/db/Makefile | 2 +
src/ioc/db/dbConstLink.c | 30 +-
src/ioc/db/dbConvertJSON.c | 12 +-
src/ioc/db/dbJLink.c | 370 +++++++++++++++++++++
src/ioc/db/dbJLink.h | 70 ++++
src/ioc/db/dbLink.c | 15 +
src/ioc/db/dbTest.c | 4 +-
src/ioc/dbStatic/dbBase.h | 4 +-
src/ioc/dbStatic/dbLexRoutines.c | 8 +-
src/ioc/dbStatic/dbStaticLib.c | 15 +-
src/ioc/dbStatic/link.h | 3 +-
src/ioc/misc/iocInit.c | 19 ++
src/ioc/registry/Makefile | 2 +
src/ioc/registry/registryCommon.c | 14 +
src/ioc/registry/registryCommon.h | 3 +
src/ioc/registry/registryJLinks.c | 27 ++
src/ioc/registry/registryJLinks.h | 28 ++
src/std/link/Makefile | 2 +-
src/std/link/links.dbd.pod | 55 ++--
src/std/link/lnkConst.c | 412 ++++++++++++++++++++++++
src/tools/DBD/Link.pm | 4 +-
src/tools/registerRecordDeviceDriver.pl | 18 ++
22 files changed, 1071 insertions(+), 46 deletions(-)
create mode 100644 src/ioc/db/dbJLink.c
create mode 100644 src/ioc/db/dbJLink.h
create mode 100644 src/ioc/registry/registryJLinks.c
create mode 100644 src/ioc/registry/registryJLinks.h
create mode 100644 src/std/link/lnkConst.c
diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile
index 0c874ccff..e758b6a5a 100644
--- a/src/ioc/db/Makefile
+++ b/src/ioc/db/Makefile
@@ -25,6 +25,7 @@ INC += dbConvertJSON.h
INC += dbDbLink.h
INC += dbExtractArray.h
INC += dbEvent.h
+INC += dbJLink.h
INC += dbLink.h
INC += dbLock.h
INC += dbNotify.h
@@ -73,6 +74,7 @@ dbCore_SRCS += dbConvertJSON.c
dbCore_SRCS += dbDbLink.c
dbCore_SRCS += dbFastLinkConv.c
dbCore_SRCS += dbExtractArray.c
+dbCore_SRCS += dbJLink.c
dbCore_SRCS += dbLink.c
dbCore_SRCS += dbNotify.c
dbCore_SRCS += dbScan.c
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index a969addf3..821fc58da 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -13,6 +13,7 @@
*/
#include
+#include
#include "dbDefs.h"
@@ -46,28 +47,41 @@ void dbConstAddLink(struct link *plink)
static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
{
- if (!plink->value.constantStr)
- return S_db_badField;
+ const char *pstr = plink->value.constantStr;
+ size_t len;
- /* Constant scalars are always numeric */
+ if (!pstr)
+ return S_db_badField;
+ len = strlen(pstr);
+
+ /* Choice values must be numeric */
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
dbrType = DBF_USHORT;
+ if (*pstr == '[' && pstr[len-1] == ']') {
+ /* Convert from JSON array */
+ long nReq = 1;
+
+ return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq);
+ }
+
return dbFastPutConvertRoutine[DBR_STRING][dbrType]
- (plink->value.constantStr, pbuffer, NULL);
+ (pstr, pbuffer, NULL);
}
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
long *pnReq)
{
- if (!plink->value.constantStr)
+ const char *pstr = plink->value.constantStr;
+
+ if (!pstr)
return S_db_badField;
- /* No support for arrays of choice types */
+ /* Choice values must be numeric */
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
- return S_db_badField;
+ dbrType = DBF_USHORT;
- return dbPutConvertJSON(plink->value.constantStr, dbrType, pbuffer, pnReq);
+ return dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
}
static long dbConstGetNelements(const struct link *plink, long *nelements)
diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c
index cd7b7ca44..14a48866f 100644
--- a/src/ioc/db/dbConvertJSON.c
+++ b/src/ioc/db/dbConvertJSON.c
@@ -10,6 +10,7 @@
#include
#include "dbDefs.h"
+#include "errlog.h"
#include "yajl_alloc.h"
#include "yajl_parse.h"
@@ -23,7 +24,7 @@ typedef struct parseContext {
int depth;
short dbrType;
short dbrSize;
- void *pdest;
+ char *pdest;
int elems;
} parseContext;
@@ -67,8 +68,10 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
/* Not attempting to handle char-array fields here, they need more
* metadata about the field than we have available at the moment.
*/
- if (parser->dbrType != DBF_STRING)
+ if (parser->dbrType != DBF_STRING) {
+ errlogPrintf("dbPutConvertJSON: String provided, numeric value(s) expected\n");
return 0; /* Illegal */
+ }
if (parser->elems > 0) {
if (len > parser->dbrSize - 1)
@@ -82,6 +85,7 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
}
static int dbcj_start_map(void *ctx) {
+ errlogPrintf("dbPutConvertJSON: Map type not supported\n");
return 0; /* Illegal */
}
@@ -96,7 +100,9 @@ static int dbcj_end_map(void *ctx) {
static int dbcj_start_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
- parser->depth++;
+ if (++parser->depth > 1)
+ errlogPrintf("dbPutConvertJSON: Embedded arrays not supported\n");
+
return (parser->depth == 1);
}
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
new file mode 100644
index 000000000..ed18a2894
--- /dev/null
+++ b/src/ioc/db/dbJLink.c
@@ -0,0 +1,370 @@
+/*************************************************************************\
+* 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.
+\*************************************************************************/
+/* dbJLink.c */
+
+#include
+#include
+
+#include "epicsAssert.h"
+#include "errlog.h"
+#include "yajl_alloc.h"
+#include "yajl_parse.h"
+
+#define epicsExportSharedSybols
+#include "dbAccessDefs.h"
+#include "dbCommon.h"
+#include "dbJLink.h"
+#include "dbStaticLib.h"
+#include "link.h"
+
+/* Change 'undef' to 'define' to turn on debug statements: */
+#undef DEBUG_JLINK
+
+#ifdef DEBUG_JLINK
+ int jlinkDebug = 10;
+# define IFDEBUG(n) \
+ if (jlinkDebug >= n) /* block or statement */
+#else
+# define IFDEBUG(n) \
+ if(0) /* Compiler will elide the block or statement */
+#endif
+
+
+typedef struct parseContext {
+ jlink *pjlink;
+ jlink *product;
+ struct link *plink;
+ short dbfType;
+ short jsonDepth;
+ short linkDepth;
+ unsigned key_is_link:1;
+} parseContext;
+
+#define CALLIF(routine) !routine ? jlif_stop : routine
+
+
+static int dbjl_value(parseContext *parser, jlif_result result) {
+ jlink *pjlink = parser->pjlink;
+
+ IFDEBUG(10) {
+ printf("dbjl_value(%s@%p, %d)\n", pjlink->pif->name, pjlink, result);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ if (result == jlif_stop || parser->linkDepth > 0)
+ return result;
+
+ parser->product = pjlink;
+ parser->key_is_link = 0;
+ parser->pjlink = pjlink->parent;
+
+ IFDEBUG(8)
+ printf("dbjl_value: product = %p\n", pjlink);
+
+ return pjlink->pif->end_parse ? pjlink->pif->end_parse(pjlink)
+ : jlif_continue;
+}
+
+static int dbjl_null(void *ctx) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+
+ IFDEBUG(10)
+ printf("dbjl_null(%s@%p)\n", pjlink->pif->name, pjlink);
+
+ assert(pjlink);
+ return dbjl_value(parser, CALLIF(pjlink->pif->parse_null)(pjlink));
+}
+
+static int dbjl_boolean(void *ctx, int val) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+
+ assert(pjlink);
+ return dbjl_value(parser, CALLIF(pjlink->pif->parse_boolean)(pjlink, val));
+}
+
+static int dbjl_integer(void *ctx, long num) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+
+ IFDEBUG(10)
+ printf("dbjl_integer(%s@%p, %ld)\n", pjlink->pif->name, pjlink, num);
+
+ assert(pjlink);
+ return dbjl_value(parser, CALLIF(pjlink->pif->parse_integer)(pjlink, num));
+}
+
+static int dbjl_double(void *ctx, double num) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+
+ IFDEBUG(10)
+ printf("dbjl_double(%s@%p, %g)\n", pjlink->pif->name, pjlink, num);
+
+ assert(pjlink);
+ return dbjl_value(parser, CALLIF(pjlink->pif->parse_double)(pjlink, num));
+}
+
+static int dbjl_string(void *ctx, const unsigned char *val, unsigned len) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+
+ IFDEBUG(10)
+ printf("dbjl_string(%s@%p, \"%.*s\")\n", pjlink->pif->name, pjlink, len, val);
+
+ assert(pjlink);
+ return dbjl_value(parser,
+ CALLIF(pjlink->pif->parse_string)(pjlink, (const char *) val, len));
+}
+
+static int dbjl_start_map(void *ctx) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+ jlif_key_result result;
+
+ if (!pjlink) {
+ IFDEBUG(10) {
+ printf("dbjl_start_map(NULL)\n");
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ assert(parser->jsonDepth == 0);
+ parser->jsonDepth++;
+ parser->key_is_link = 1;
+ return jlif_continue; /* Opening '{' */
+ }
+
+ IFDEBUG(10) {
+ printf("dbjl_start_map(%s@%p)\n", pjlink->pif->name, pjlink);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ parser->linkDepth++;
+ parser->jsonDepth++;
+ result = CALLIF(pjlink->pif->parse_start_map)(pjlink);
+ if (result == jlif_key_embed_link) {
+ parser->key_is_link = 1;
+ result = jlif_continue;
+ }
+
+ IFDEBUG(10)
+ printf("dbjl_start_map -> %d\n", result);
+
+ return result;
+}
+
+static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+ char link_name[MAX_LINK_NAME + 1];
+ size_t lnlen = len;
+ linkSup *linkSup;
+ jlif *pjlif;
+ jlif_result result;
+
+ if (!parser->key_is_link) {
+ if (!pjlink) {
+ errlogPrintf("dbJLinkInit: Illegal second link key '%.*s' seen for %s\n",
+ len, key, parser->plink->precord->name);
+ return jlif_stop;
+ }
+
+ IFDEBUG(10) {
+ printf("dbjl_map_key(%s@%p, \"%.*s\")\n",
+ pjlink->pif->name, pjlink, len, key);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ assert(parser->linkDepth > 0);
+ return CALLIF(pjlink->pif->parse_map_key)(pjlink, (const char *) key, len);
+ }
+
+ IFDEBUG(10) {
+ printf("dbjl_map_key(NULL, \"%.*s\")\n", len, key);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ if (lnlen > MAX_LINK_NAME)
+ lnlen = MAX_LINK_NAME;
+ strncpy(link_name, (const char *) key, lnlen);
+ link_name[lnlen] = '\0';
+
+ linkSup = dbFindLinkSup(pdbbase, link_name);
+ if (!linkSup) {
+ errlogPrintf("dbJLinkInit: Link type '%s' not found for %s\n",
+ link_name, parser->plink->precord->name);
+ return jlif_stop;
+ }
+
+ pjlif = linkSup->pjlif;
+ if (!pjlif) {
+ errlogPrintf("dbJLinkInit: Support for Link type '%s' not loaded\n",
+ link_name);
+ return jlif_stop;
+ }
+
+ pjlink = pjlif->alloc_jlink(parser->plink);
+ if (!pjlink) {
+ errlogPrintf("dbJLinkInit: Out of memory\n");
+ return jlif_stop;
+ }
+ pjlink->pif = pjlif;
+
+ if (parser->pjlink) {
+ /* This is an embedded link */
+ pjlink->parent = parser->pjlink;
+ }
+
+ result = pjlif->start_parse ? pjlif->start_parse(pjlink) : jlif_continue;
+ if (result == jlif_continue) {
+ parser->pjlink = pjlink;
+
+ IFDEBUG(8)
+ printf("dbjl_map_key: New %s@%p\n", pjlink->pif->name, pjlink);
+ }
+ else {
+ pjlif->free_jlink(pjlink);
+ }
+ // FIXME Ensure link map has only one link key...
+
+ IFDEBUG(10)
+ printf("dbjl_map_key -> %d\n", result);
+
+ return result;
+}
+
+static int dbjl_end_map(void *ctx) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+ jlif_result result;
+
+ IFDEBUG(10) {
+ printf("dbjl_end_map(%s@%p)\n",
+ pjlink ? pjlink->pif->name : "NULL", pjlink);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ parser->jsonDepth--;
+ if (parser->linkDepth > 0) {
+ parser->linkDepth--;
+
+ result = dbjl_value(parser, CALLIF(pjlink->pif->parse_end_map)(pjlink));
+ }
+ else {
+ result = jlif_continue;
+ }
+ return result;
+}
+
+static int dbjl_start_array(void *ctx) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+
+ IFDEBUG(10) {
+ printf("dbjl_start_array(%s@%p)\n", pjlink->pif->name, pjlink);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ assert(pjlink);
+ parser->linkDepth++;
+ parser->jsonDepth++;
+ return CALLIF(pjlink->pif->parse_start_array)(pjlink);
+}
+
+static int dbjl_end_array(void *ctx) {
+ parseContext *parser = (parseContext *) ctx;
+ jlink *pjlink = parser->pjlink;
+
+ IFDEBUG(10) {
+ printf("dbjl_end_array(%s@%p)\n", pjlink->pif->name, pjlink);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ assert(pjlink);
+ parser->linkDepth--;
+ parser->jsonDepth--;
+ return dbjl_value(parser, CALLIF(pjlink->pif->parse_end_array)(pjlink));
+}
+
+static yajl_callbacks dbjl_callbacks = {
+ dbjl_null, dbjl_boolean, dbjl_integer, dbjl_double, NULL, dbjl_string,
+ dbjl_start_map, dbjl_map_key, dbjl_end_map, dbjl_start_array, dbjl_end_array
+};
+
+static const yajl_parser_config dbjl_config =
+ { 0, 0 }; /* allowComments = NO, checkUTF8 = NO */
+
+long dbJLinkInit(struct link *plink, short dbfType)
+{
+ parseContext context, *parser = &context;
+ yajl_alloc_funcs dbjl_allocs;
+ yajl_handle yh;
+ yajl_status ys;
+ const char *json = plink->value.json.string;
+ size_t jlen = strlen(json);
+ long status;
+
+ IFDEBUG(10)
+ printf("dbJLinkInit(\"%s.????\", %d)\n", plink->precord->name, dbfType);
+
+ parser->pjlink = NULL;
+ parser->product = NULL;
+ parser->plink = plink;
+ parser->dbfType = dbfType;
+ parser->jsonDepth = 0;
+ parser->linkDepth = 0;
+ parser->key_is_link = 0;
+
+ IFDEBUG(10)
+ printf("dbJLinkInit: jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+
+ yajl_set_default_alloc_funcs(&dbjl_allocs);
+ yh = yajl_alloc(&dbjl_callbacks, &dbjl_config, &dbjl_allocs, parser);
+ if (!yh)
+ return S_db_noMemory;
+
+ ys = yajl_parse(yh, (const unsigned char *) json, (unsigned) jlen);
+ if (ys == yajl_status_insufficient_data)
+ ys = yajl_parse_complete(yh);
+
+ switch (ys) {
+ unsigned char *err;
+ jlink *pjlink;
+
+ case yajl_status_ok:
+ assert(parser->jsonDepth == 0);
+ pjlink = parser->product;
+ assert(pjlink);
+ plink->value.json.jlink = pjlink;
+ plink->lset = pjlink->pif->get_lset(pjlink);
+ status = 0;
+ break;
+
+ case yajl_status_error:
+ err = yajl_get_error(yh, 1, (const unsigned char *) json, (unsigned) jlen);
+ errlogPrintf("dbJLinkInit: %s\n", err);
+ yajl_free_error(yh, err);
+ /* fall through */
+ default:
+ status = S_db_badField;
+ }
+
+ yajl_free(yh);
+ return status;
+}
+
+
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
new file mode 100644
index 000000000..42d5e362c
--- /dev/null
+++ b/src/ioc/db/dbJLink.h
@@ -0,0 +1,70 @@
+/*************************************************************************\
+* 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.
+\*************************************************************************/
+/* dbJLink.h */
+
+#ifndef INC_dbJLink_H
+#define INC_dbJLink_H
+
+#include
+#include
+
+/* Limit for link name key length */
+#define MAX_LINK_NAME 15
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ jlif_stop = 0,
+ jlif_continue = 1
+} jlif_result;
+
+typedef enum {
+ jlif_key_stop = jlif_stop,
+ jlif_key_continue = jlif_continue,
+ jlif_key_embed_link
+} jlif_key_result;
+
+struct link;
+struct lset;
+typedef struct jlink jlink;
+
+typedef struct jlif {
+ const char *name;
+ jlink* (*alloc_jlink)(struct link *);
+ void (*free_jlink)(jlink *);
+ jlif_result (*start_parse)(jlink *);
+ jlif_result (*parse_null)(jlink *);
+ jlif_result (*parse_boolean)(jlink *, int val);
+ jlif_result (*parse_integer)(jlink *, long num);
+ jlif_result (*parse_double)(jlink *, double num);
+ jlif_result (*parse_string)(jlink *, const char *val, size_t len);
+ jlif_key_result (*parse_start_map)(jlink *);
+ jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
+ jlif_result (*parse_end_map)(jlink *);
+ jlif_result (*parse_start_array)(jlink *);
+ jlif_result (*parse_end_array)(jlink *);
+ jlif_result (*end_parse)(jlink *);
+ struct lset* (*get_lset)(const jlink *);
+ void (*report)(const jlink *);
+} jlif;
+
+typedef struct jlink {
+ jlif *pif;
+ jlink *parent;
+ /* Link types extend or embed this structure for private storage */
+} jlink;
+
+epicsShareFunc long dbJLinkInit(struct link *plink, short dbfType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_dbJLink_H */
+
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index c2ae385d0..7e1cceb03 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -37,6 +37,7 @@
#include "dbDbLink.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
+#include "dbJLink.h"
#include "dbLink.h"
#include "dbLock.h"
#include "dbScan.h"
@@ -77,6 +78,11 @@ void dbInitLink(struct link *plink, short dbfType)
return;
}
+ if (plink->type == JSON_LINK) {
+ dbJLinkInit(plink, dbfType);
+ return;
+ }
+
if (plink->type != PV_LINK)
return;
@@ -120,6 +126,15 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
return;
}
+ if (plink->type == JSON_LINK) {
+ /*
+ * FIXME: Can't create DB links as dbJLink types yet,
+ * dbLock.c doesn't have any way to find/track them.
+ */
+ dbJLinkInit(plink, dbfType);
+ return;
+ }
+
if (plink->type != PV_LINK)
return;
diff --git a/src/ioc/db/dbTest.c b/src/ioc/db/dbTest.c
index d7d778d7f..69628cd5d 100644
--- a/src/ioc/db/dbTest.c
+++ b/src/ioc/db/dbTest.c
@@ -941,7 +941,9 @@ static void printBuffer(
}
else {
for (i = 0; i < no_elements; i+= MAXLINE - 5) {
- sprintf(pmsg, " \"%.*s\"", MAXLINE - 5, (char *)pbuffer + i);
+ int width = no_elements - i;
+ if (width > MAXLINE - 5) width = MAXLINE - 5;
+ sprintf(pmsg, " \"%.*s\"", width, (char *)pbuffer + i);
if (i + MAXLINE - 5 < no_elements) strcat(pmsg, " +");
dbpr_msgOut(pMsgBuff, tab_size);
}
diff --git a/src/ioc/dbStatic/dbBase.h b/src/ioc/dbStatic/dbBase.h
index de543a1e7..84d41c2fe 100644
--- a/src/ioc/dbStatic/dbBase.h
+++ b/src/ioc/dbStatic/dbBase.h
@@ -47,8 +47,8 @@ typedef struct devSup {
typedef struct linkSup {
ELLNODE node;
char *name;
- char *lset_name;
- struct lset *lset;
+ char *jlif_name;
+ struct jlif *pjlif;
} linkSup;
typedef struct dbDeviceMenu {
diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c
index 380844dec..660c02669 100644
--- a/src/ioc/dbStatic/dbLexRoutines.c
+++ b/src/ioc/dbStatic/dbLexRoutines.c
@@ -75,7 +75,7 @@ static void dbRecordtypeFieldItem(char *name,char *value);
static void dbDevice(char *recordtype,char *linktype,
char *dsetname,char *choicestring);
static void dbDriver(char *name);
-static void dbLinkType(char *name, char *lset_name);
+static void dbLinkType(char *name, char *jlif_name);
static void dbRegistrar(char *name);
static void dbFunction(char *name);
static void dbVariable(char *name, char *type);
@@ -786,7 +786,7 @@ static void dbDriver(char *name)
ellAdd(&pdbbase->drvList,&pdrvSup->node);
}
-static void dbLinkType(char *name, char *lset_name)
+static void dbLinkType(char *name, char *jlif_name)
{
linkSup *pLinkSup;
GPHENTRY *pgphentry;
@@ -797,7 +797,7 @@ static void dbLinkType(char *name, char *lset_name)
}
pLinkSup = dbCalloc(1,sizeof(linkSup));
pLinkSup->name = epicsStrDup(name);
- pLinkSup->lset_name = epicsStrDup(lset_name);
+ pLinkSup->jlif_name = epicsStrDup(jlif_name);
pgphentry = gphAdd(pdbbase->pgpHash, pLinkSup->name, &pdbbase->linkList);
if (!pgphentry) {
yyerrorAbort("gphAdd failed");
@@ -1053,7 +1053,7 @@ static void dbRecordField(char *name,char *value)
value++;
value[strlen(value) - 1] = 0;
}
- dbTranslateEscape(value, value); /* yuck: in-place, but safe */
+ dbTranslateEscape(value, value); /* in-place; safe & legal */
status = dbPutString(pdbentry,value);
if(status) {
epicsPrintf("Can't set \"%s.%s\" to \"%s\"\n",
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index e147374e5..b9532516b 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -46,6 +46,7 @@
#include "special.h"
#include "dbCommon.h"
+#include "dbJLink.h"
int dbStaticDebug = 0;
static char *pNullString = "";
@@ -122,7 +123,11 @@ void dbFreeLinkContents(struct link *plink)
case CONSTANT: free((void *)plink->value.constantStr); break;
case MACRO_LINK: free((void *)plink->value.macro_link.macroStr); break;
case PV_LINK: free((void *)plink->value.pv_link.pvname); break;
- case JSON_LINK: parm = plink->value.json.string; break;
+ case JSON_LINK:
+ if (plink->value.json.jlink)
+ plink->value.json.jlink->pif->free_jlink(plink->value.json.jlink);
+ parm = plink->value.json.string;
+ break;
case VME_IO: parm = plink->value.vmeio.parm; break;
case CAMAC_IO: parm = plink->value.camacio.parm; break;
case AB_IO: parm = plink->value.abio.parm; break;
@@ -560,7 +565,7 @@ void dbFreeBase(dbBase *pdbbase)
pdrvSup = pdrvSupNext;
}
while ((plinkSup = (linkSup *) ellGet(&pdbbase->linkList))) {
- free(plinkSup->lset_name);
+ free(plinkSup->jlif_name);
free(plinkSup->name);
free(plinkSup);
}
@@ -1086,7 +1091,7 @@ long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp)
}
for (plinkSup = (linkSup *) ellFirst(&pdbbase->linkList);
plinkSup; plinkSup = (linkSup *) ellNext(&plinkSup->node)) {
- fprintf(fp, "link(%s,%s)\n", plinkSup->name, plinkSup->lset_name);
+ fprintf(fp, "link(%s,%s)\n", plinkSup->name, plinkSup->jlif_name);
}
return 0;
}
@@ -2267,9 +2272,8 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
- /* FIXME Parse JSON object here */
pinfo->ltype = JSON_LINK;
- return 0;
+ return 0;
}
/* Check for other HW link types */
@@ -2337,7 +2341,6 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Link may be an array constant */
if (pstr[0] == '[' && pstr[len-1] == ']' &&
(strchr(pstr, ',') || strchr(pstr, '"'))) {
- /* FIXME Parse JSON array here */
pinfo->ltype = CONSTANT;
return 0;
}
diff --git a/src/ioc/dbStatic/link.h b/src/ioc/dbStatic/link.h
index dc9ccacbc..ab1d7a54d 100644
--- a/src/ioc/dbStatic/link.h
+++ b/src/ioc/dbStatic/link.h
@@ -87,9 +87,10 @@ struct pv_link {
short lastGetdbrType; /* last dbrType for DB or CA get */
};
+struct jlink;
struct json_link {
char *string;
- /* ... */
+ struct jlink *jlink;
};
/* structure of a VME io channel */
diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c
index d0483e55a..09558c1fb 100644
--- a/src/ioc/misc/iocInit.c
+++ b/src/ioc/misc/iocInit.c
@@ -66,6 +66,7 @@
#include "recSup.h"
#include "registryDeviceSupport.h"
#include "registryDriverSupport.h"
+#include "registryJLinks.h"
#include "registryRecordType.h"
#include "rsrv.h"
@@ -79,6 +80,7 @@ static enum {
/* define forward references*/
static int checkDatabase(dbBase *pdbbase);
static void initDrvSup(void);
+static void initJLinks(void);
static void initRecSup(void);
static void initDevSup(void);
static void finishDevSup(void);
@@ -145,6 +147,7 @@ static int iocBuild_2(void)
{
initHookAnnounce(initHookAfterCaLinkInit);
+ initJLinks();
initDrvSup();
initHookAnnounce(initHookAfterInitDrvSup);
@@ -374,6 +377,22 @@ static void initDrvSup(void) /* Locate all driver support entry tables */
}
}
+static void initJLinks(void)
+{
+ linkSup *plinkSup;
+
+ for (plinkSup = (linkSup *)ellFirst(&pdbbase->linkList); plinkSup;
+ plinkSup = (linkSup *)ellNext(&plinkSup->node)) {
+ jlif *pjlif = registryJLinkFind(plinkSup->name);
+
+ if (!pjlif) {
+ errlogPrintf("iocInit: JLink %s not found\n", plinkSup->name);
+ continue;
+ }
+ plinkSup->pjlif = pjlif;
+ }
+}
+
static void initRecSup(void)
{
dbRecordType *pdbRecordType;
diff --git a/src/ioc/registry/Makefile b/src/ioc/registry/Makefile
index ce285a0c6..a85320a9d 100644
--- a/src/ioc/registry/Makefile
+++ b/src/ioc/registry/Makefile
@@ -14,6 +14,7 @@ SRC_DIRS += $(IOCDIR)/registry
INC += registryRecordType.h
INC += registryDeviceSupport.h
INC += registryDriverSupport.h
+INC += registryJLinks.h
INC += registryFunction.h
INC += registryCommon.h
INC += registryIocRegister.h
@@ -21,6 +22,7 @@ INC += registryIocRegister.h
dbCore_SRCS += registryRecordType.c
dbCore_SRCS += registryDeviceSupport.c
dbCore_SRCS += registryDriverSupport.c
+dbCore_SRCS += registryJLinks.c
dbCore_SRCS += registryFunction.c
dbCore_SRCS += registryCommon.c
dbCore_SRCS += registryIocRegister.c
diff --git a/src/ioc/registry/registryCommon.c b/src/ioc/registry/registryCommon.c
index e5d5768af..f4ec4af55 100644
--- a/src/ioc/registry/registryCommon.c
+++ b/src/ioc/registry/registryCommon.c
@@ -19,6 +19,7 @@
#include "registryCommon.h"
#include "registryDeviceSupport.h"
#include "registryDriverSupport.h"
+#include "registryJLinks.h"
void registerRecordTypes(DBBASE *pbase, int nRecordTypes,
@@ -76,3 +77,16 @@ void registerDrivers(DBBASE *pbase, int nDrivers,
}
}
+void registerJLinks(DBBASE *pbase, int nLinks, jlif * const *jlifsl)
+{
+ int i;
+ for (i = 0; i < nLinks; i++) {
+ if (registryJLinkFind(jlifsl[i]->name)) continue;
+ if (!registryJLinkAdd(jlifsl[i])) {
+ errlogPrintf("registryJLinkAdd failed %s\n",
+ jlifsl[i]->name);
+ continue;
+ }
+ }
+}
+
diff --git a/src/ioc/registry/registryCommon.h b/src/ioc/registry/registryCommon.h
index c4b601665..51b32dee3 100644
--- a/src/ioc/registry/registryCommon.h
+++ b/src/ioc/registry/registryCommon.h
@@ -12,6 +12,7 @@
#include "dbStaticLib.h"
#include "devSup.h"
+#include "dbJLink.h"
#include "registryRecordType.h"
#include "shareLib.h"
@@ -28,6 +29,8 @@ epicsShareFunc void registerDevices(
epicsShareFunc void registerDrivers(
DBBASE *pbase, int nDrivers,
const char * const *driverSupportNames, struct drvet * const *drvsl);
+epicsShareFunc void registerJLinks(
+ DBBASE *pbase, int nDrivers, jlif * const *jlifsl);
#ifdef __cplusplus
}
diff --git a/src/ioc/registry/registryJLinks.c b/src/ioc/registry/registryJLinks.c
new file mode 100644
index 000000000..04c827098
--- /dev/null
+++ b/src/ioc/registry/registryJLinks.c
@@ -0,0 +1,27 @@
+/*************************************************************************\
+* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* 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.
+\*************************************************************************/
+/* registryJLinks.c */
+
+#define epicsExportSharedSymbols
+#include "registry.h"
+#include "registryJLinks.h"
+#include "dbJLink.h"
+
+static void *registryID = "JSON link types";
+
+
+epicsShareFunc int registryJLinkAdd(struct jlif *pjlif)
+{
+ return registryAdd(registryID, pjlif->name, pjlif);
+}
+
+epicsShareFunc jlif * registryJLinkFind(const char *name)
+{
+ return registryFind(registryID, name);
+}
diff --git a/src/ioc/registry/registryJLinks.h b/src/ioc/registry/registryJLinks.h
new file mode 100644
index 000000000..3f304c6d5
--- /dev/null
+++ b/src/ioc/registry/registryJLinks.h
@@ -0,0 +1,28 @@
+/*************************************************************************\
+* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* 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.
+\*************************************************************************/
+
+#ifndef INC_registryJLinks_H
+#define INC_registryJLinks_H
+
+#include "dbJLink.h"
+#include "shareLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+epicsShareFunc int registryJLinkAdd(jlif *pjlif);
+epicsShareFunc jlif * registryJLinkFind(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* INC_registryDriverSupport_H */
diff --git a/src/std/link/Makefile b/src/std/link/Makefile
index d2e158475..56b56b8be 100644
--- a/src/std/link/Makefile
+++ b/src/std/link/Makefile
@@ -11,7 +11,7 @@ SRC_DIRS += $(STDDIR)/link
DBD += links.dbd
-# dbRecStd_SRCS += ...
+dbRecStd_SRCS += lnkConst.c
HTMLS += links.html
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
index c4a5a45cd..335808097 100644
--- a/src/std/link/links.dbd.pod
+++ b/src/std/link/links.dbd.pod
@@ -1,7 +1,7 @@
-=head1 Link Types
+=head1 JSON Links
-Links are an extensible mechanism for adding new kinds of database link,
-using JSON for link addresses.
+JSON Links are an extensible mechanism for adding new kinds of database link,
+using JSON for the link address.
The following link types are available in this release:
=over
@@ -12,6 +12,8 @@ The following link types are available in this release:
=item * L
+=item * L
+
=back
=head2 Using Links
@@ -21,35 +23,36 @@ must appear inside a pair of braces C< {} > expressed as a JSON
(L) object, which allows link
parameters to be defined as needed.
-Note that due to the required presence of the double-quote characters in the
-JSON strings in a link field value string in a database file, it will usually
-be necessary to escape all double-quote characters in the JSON object by
-preceding them with a backslash C< \ > character.
-Database configuration tools that support this link mechanism must be careful
-to handle these escapes correctly on reading and writing string values from/to
-a .db file.
-=head2 Filter Reference
+=head2 Link Type Reference
=cut
-link(const,lsetConst)
+link(const, lnkConstIf)
=head3 Constant Link C<"const">
-...
+Constant links provide one or more values at link initalization time, but do not return
+any data when their C routine is called. Most record types support the use of
+constant links by calling C at initialization, which results in
+the constant value being loaded into the target field at that time.
=head4 Parameters
-...
+A const link takes a parameter which may be an integer, double or string, or an array of
+those types. If an array contains both integers and double values the integers will be
+promoted to doubles. Mixing strings and numbers in an array will result in an error.
-=head4 Example
+=head4 Examples
- ...
+ {const: 3.14159265358979}
+ {const: "Pi"}
+ {const: [1, 2.718281828459, 3.14159265358979]}
+ {const: ["One", "e", "Pi"]}
=cut
-link(db,lsetDatabase)
+#link(db, lnkDbIf)
=head3 Database Link C<"db">
@@ -65,7 +68,7 @@ link(db,lsetDatabase)
=cut
-link(ca,lsetChannelAccess)
+#link(ca, lnkCaIf)
=head3 Channel Access Link C<"ca">
@@ -90,3 +93,19 @@ link(ca,lsetChannelAccess)
...
=cut
+
+#link(calc, lnkCalcIf)
+
+=head3 Calculation Link C<"calc">
+
+...
+
+=head4 Parameters
+
+...
+
+=head4 Example
+
+ ...
+
+=cut
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
new file mode 100644
index 000000000..6ed4e5e9a
--- /dev/null
+++ b/src/std/link/lnkConst.c
@@ -0,0 +1,412 @@
+/*************************************************************************\
+* 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.
+\*************************************************************************/
+/* lnkConst.c */
+
+#include
+#include
+#include
+
+#include "dbDefs.h"
+#include "errlog.h"
+#include "epicsAssert.h"
+#include "epicsTypes.h"
+#include "dbAccessDefs.h"
+#include "dbConvertFast.h"
+#include "dbLink.h"
+#include "dbJLink.h"
+#include "epicsExport.h"
+
+
+/* Change 'undef' to 'define' to turn on debug statements: */
+#undef DEBUG_LINK
+
+#ifdef DEBUG_LINK
+ int lnkConstDebug = 10;
+# define IFDEBUG(n) \
+ if (lnkConstDebug >= n) /* block or statement */
+#else
+# define IFDEBUG(n) \
+ if(0) /* Compiler will elide the block or statement */
+#endif
+
+typedef long (*FASTCONVERT)();
+
+typedef struct clink {
+ struct jlink jlink; /* embedded */
+ int nElems;
+ enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type;
+ union {
+ epicsInt32 scalar_integer;
+ epicsFloat64 scalar_double;
+ char * scalar_string;
+ void *pmem;
+ epicsInt32 *pintegers;
+ epicsFloat64 *pdoubles;
+ char **pstrings;
+ } value;
+} clink;
+
+static lset lnkConst_lset;
+
+
+/*************************** jlif Routines **************************/
+
+static jlink* lnkConst_alloc(struct link *plink) {
+ clink *clink = calloc(1, sizeof(struct clink));
+
+ IFDEBUG(10)
+ printf("lnkConst_alloc()\n");
+
+ clink->type = s0;
+ clink->nElems = 0;
+ clink->value.pmem = NULL;
+
+ IFDEBUG(10)
+ printf("lnkConst_alloc -> const@%p\n", clink);
+
+ return &clink->jlink;
+}
+
+static void lnkConst_free(jlink *pjlink) {
+ clink *clink = CONTAINER(pjlink, struct clink, jlink);
+
+ IFDEBUG(10)
+ printf("lnkConst_free(const@%p)\n", pjlink);
+
+ switch (clink->type) {
+ int i;
+ case ac40:
+ for (i=0; inElems; i++)
+ free(clink->value.pstrings[i]);
+ /* fall through */
+ case ai32:
+ case af64:
+ free(clink->value.pmem);
+ default:
+ break;
+ }
+ free(clink);
+}
+
+static jlif_result lnkConst_integer(jlink *pjlink, long num) {
+ clink *clink = CONTAINER(pjlink, struct clink, jlink);
+
+ IFDEBUG(10)
+ printf("lnkConst_integer(const@%p, %ld)\n", pjlink, num);
+
+ switch (clink->type) {
+ void *buf;
+ int nElems;
+
+ case s0:
+ clink->nElems = 1;
+ clink->type = si32;
+ clink->value.scalar_integer = num;
+ break;
+
+ case a0:
+ clink->type = ai32;
+ /* fall thorough */
+ case ai32:
+ nElems = clink->nElems + 1;
+ buf = realloc(clink->value.pmem, nElems * sizeof(epicsInt32));
+ if (!buf) break;
+ clink->value.pmem = buf;
+ clink->value.pintegers[clink->nElems] = num;
+ clink->nElems = nElems;
+ break;
+
+ case af64:
+ nElems = clink->nElems + 1;
+ buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
+ if (!buf) break;
+ clink->value.pmem = buf;
+ clink->value.pdoubles[clink->nElems++] = num;
+ break;
+
+ case ac40:
+ errlogPrintf("lnkConst: Mixed data types in array\n");
+ /* FIXME ??? */
+ default:
+ return jlif_stop;
+ }
+ return jlif_continue;
+}
+
+static jlif_result lnkConst_boolean(jlink *pjlink, int val) {
+ IFDEBUG(10)
+ printf("lnkConst_boolean(const@%p, %d)\n", pjlink, val);
+
+ return lnkConst_integer(pjlink, val);
+}
+
+static jlif_result lnkConst_double(jlink *pjlink, double num) {
+ clink *clink = CONTAINER(pjlink, struct clink, jlink);
+
+ IFDEBUG(10)
+ printf("lnkConst_double(const@%p, %g)\n", pjlink, num);
+
+ switch (clink->type) {
+ epicsFloat64 *f64buf;
+ int nElems, i;
+
+ case s0:
+ clink->nElems = 1;
+ clink->type = sf64;
+ clink->value.scalar_double = num;
+ break;
+
+ case a0:
+ clink->type = af64;
+ /* fall thorough */
+ case af64:
+ nElems = clink->nElems + 1;
+ f64buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
+ if (!f64buf) break;
+ clink->value.pdoubles = f64buf;
+ clink->value.pdoubles[clink->nElems++] = num;
+ break;
+
+ case ai32: /* promote earlier ai32 values to af64 */
+ f64buf = calloc(clink->nElems + 1, sizeof(epicsFloat64));
+ if (!f64buf) break;
+ for (i = 0; i < clink->nElems; i++) {
+ f64buf[i] = clink->value.pintegers[i];
+ }
+ f64buf[clink->nElems++] = num;
+ free(clink->value.pmem);
+ clink->value.pdoubles = f64buf;
+ clink->type = af64;
+ break;
+
+ case ac40:
+ errlogPrintf("lnkConst: Mixed data types in array\n");
+ /* FIXME ??? */
+ default:
+ return jlif_stop;
+ }
+
+ return jlif_continue;
+}
+
+static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) {
+ clink *clink = CONTAINER(pjlink, struct clink, jlink);
+
+ IFDEBUG(10)
+ printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
+
+ if (len > MAX_STRING_SIZE)
+ len = MAX_STRING_SIZE;
+
+ if (clink->type == s0) {
+ char *buf = malloc(len + 1);
+
+ if (!buf)
+ return jlif_stop;
+
+ strncpy(buf, val, len);
+ buf[len] = '\0';
+
+ clink->nElems = 1;
+ clink->type = sc40;
+ clink->value.scalar_string = buf;
+ return jlif_continue;
+ }
+ /* FIXME Implement a0 and ac40 */
+ /* FIXME How to handle ai32 and af64? */
+ errlogPrintf("lnkConst: Mixed data types in array\n");
+
+ return jlif_stop;
+}
+
+static jlif_result lnkConst_start_array(jlink *pjlink) {
+ clink *clink = CONTAINER(pjlink, struct clink, jlink);
+
+ IFDEBUG(10)
+ printf("lnkConst_start_array(const@%p)\n", pjlink);
+
+ if (clink->type != s0) {
+ errlogPrintf("lnkConst: Embedded array value\n");
+ return jlif_stop;
+ }
+
+ clink->type = a0;
+ return jlif_continue;
+}
+
+static jlif_result lnkConst_end_array(jlink *pjlink) {
+ IFDEBUG(10)
+ printf("lnkConst_end_array(const@%p)\n", pjlink);
+
+ return jlif_continue;
+}
+
+static struct lset* lnkConst_get_lset(const jlink *pjlink) {
+ IFDEBUG(10)
+ printf("lnkConst_get_lset(const@%p)\n", pjlink);
+
+ return &lnkConst_lset;
+}
+
+static void lnkConst_report(const jlink *pjlink) {
+ clink *clink = CONTAINER(pjlink, struct clink, jlink);
+
+ IFDEBUG(10)
+ printf("lnkConst_report(const@%p)\n", clink);
+
+ /* FIXME Implement! */
+}
+
+/*************************** lset Routines **************************/
+
+static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer)
+{
+ clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+ long status;
+
+ IFDEBUG(10)
+ printf("lnkConst_loadScalar(const@%p, %d, %p)\n",
+ clink, dbrType, pbuffer);
+
+ switch (clink->type) {
+ case si32:
+ status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
+ (&clink->value.scalar_integer, pbuffer, NULL);
+ break;
+
+ case sf64:
+ status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
+ (&clink->value.scalar_double, pbuffer, NULL);
+ break;
+
+ case sc40:
+ status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
+ (clink->value.scalar_string, pbuffer, NULL);
+ break;
+
+ case ai32:
+ status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
+ (clink->value.pintegers, pbuffer, NULL);
+ break;
+
+ case af64:
+ status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
+ (clink->value.pdoubles, pbuffer, NULL);
+ break;
+
+ default:
+ status = S_db_badField;
+ break;
+ }
+
+ return status;
+}
+
+static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
+ long *pnReq)
+{
+ clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+ short dbrSize = dbValueSize(dbrType);
+ char *pdest = pbuffer;
+ int nElems = clink->nElems;
+ FASTCONVERT conv;
+ long status;
+
+ IFDEBUG(10)
+ printf("lnkConst_loadArray(const@%p, %d, %p, (%ld))\n",
+ clink, dbrType, pbuffer, *pnReq);
+
+ if (nElems > *pnReq)
+ nElems = *pnReq;
+
+ switch (clink->type) {
+ int i;
+
+ case si32:
+ status = dbFastPutConvertRoutine[DBF_LONG][dbrType]
+ (&clink->value.scalar_integer, pdest, NULL);
+ break;
+
+ case sf64:
+ status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]
+ (&clink->value.scalar_double, pdest, NULL);
+ break;
+
+ case sc40:
+ status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
+ (clink->value.scalar_string, pbuffer, NULL);
+ break;
+
+ case ai32:
+ conv = dbFastPutConvertRoutine[DBF_LONG][dbrType];
+ for (i = 0; i < nElems; i++) {
+ conv(&clink->value.pintegers[i], pdest, NULL);
+ pdest += dbrSize;
+ }
+ status = 0;
+ break;
+
+ case af64:
+ conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType];
+ for (i = 0; i < nElems; i++) {
+ conv(&clink->value.pdoubles[i], pdest, NULL);
+ pdest += dbrSize;
+ }
+ status = 0;
+ break;
+
+ default:
+ status = S_db_badField;
+ }
+ *pnReq = nElems;
+ return status;
+}
+
+static long lnkConst_getNelements(const struct link *plink, long *nelements)
+{
+ IFDEBUG(10)
+ printf("lnkConst_getNelements(const@%p, (%ld))\n",
+ plink->value.json.jlink, *nelements);
+
+ *nelements = 0;
+ return 0;
+}
+
+static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
+ epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+{
+ IFDEBUG(10)
+ printf("lnkConst_loadScalar(const@%p, %d, %p, ... (%ld))\n",
+ plink->value.json.jlink, dbrType, pbuffer, *pnRequest);
+
+ if (pnRequest)
+ *pnRequest = 0;
+ return 0;
+}
+
+
+/************************* Interface Tables *************************/
+
+static lset lnkConst_lset = {
+ 1, 0, /* Constant, not Volatile */
+ NULL, lnkConst_loadScalar, lnkConst_loadArray, NULL,
+ NULL, lnkConst_getNelements, lnkConst_getValue,
+ NULL, NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL
+};
+
+static jlif lnkConstIf = {
+ "const", lnkConst_alloc, lnkConst_free, NULL,
+ NULL, lnkConst_boolean, lnkConst_integer, lnkConst_double, lnkConst_string,
+ NULL, NULL, NULL, lnkConst_start_array, lnkConst_end_array,
+ NULL, lnkConst_get_lset, lnkConst_report
+};
+epicsExportAddress(jlif, lnkConstIf);
+
diff --git a/src/tools/DBD/Link.pm b/src/tools/DBD/Link.pm
index ac1a14452..4a4568e82 100644
--- a/src/tools/DBD/Link.pm
+++ b/src/tools/DBD/Link.pm
@@ -3,8 +3,8 @@ use DBD::Base;
@ISA = qw(DBD::Base);
sub init {
- my ($this, $name, $lset) = @_;
- $this->SUPER::init($lset, "link support (lset)");
+ my ($this, $name, $jlif) = @_;
+ $this->SUPER::init($jlif, "link support (jlif)");
$this->{KEY} = $name;
return $this;
}
diff --git a/src/tools/registerRecordDeviceDriver.pl b/src/tools/registerRecordDeviceDriver.pl
index 34f1b59cb..18b522772 100644
--- a/src/tools/registerRecordDeviceDriver.pl
+++ b/src/tools/registerRecordDeviceDriver.pl
@@ -159,6 +159,20 @@ if (%drivers) {
print $out "};\n\n";
}
+my %links = %{$dbd->links};
+if (%links) {
+ my @links = sort keys %links;
+
+ # Declare the link interfaces
+ print $out wrap('epicsShareExtern jlif ', ' ',
+ join(', ', map {"*pvar_jlif_$_"} @links)), ";\n\n";
+
+ # List of pointers to each link interface
+ print $out "static struct jlif *jlifsl[] = {\n";
+ print $out join(",\n", map {" pvar_jlif_$_"} @links);
+ print $out "};\n\n";
+}
+
my @registrars = sort keys %{$dbd->registrars};
my @functions = sort keys %{$dbd->functions};
push @registrars, map {"register_func_$_"} @functions;
@@ -234,6 +248,10 @@ print $out (<< 'END') if %drivers;
registerDrivers(pbase, NELEMENTS(drvsl), driverSupportNames, drvsl);
END
+print $out (<< 'END') if %links;
+ registerJLinks(pbase, NELEMENTS(jlifsl), jlifsl);
+END
+
print $out (<< "END") for @registrars;
pvar_func_$_();
END
From 33e565b67deadf0f114e51dd4af0860542afd6eb Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 29 Aug 2016 10:41:51 -0500
Subject: [PATCH 038/112] Fix build warning from clang
---
src/ioc/db/dbJLink.h | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index 42d5e362c..3f52a6877 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -32,7 +32,13 @@ typedef enum {
struct link;
struct lset;
-typedef struct jlink jlink;
+struct jlif;
+
+typedef struct jlink {
+ struct jlif *pif;
+ struct jlink *parent;
+ /* Link types extend or embed this structure for private storage */
+} jlink;
typedef struct jlif {
const char *name;
@@ -54,12 +60,6 @@ typedef struct jlif {
void (*report)(const jlink *);
} jlif;
-typedef struct jlink {
- jlif *pif;
- jlink *parent;
- /* Link types extend or embed this structure for private storage */
-} jlink;
-
epicsShareFunc long dbJLinkInit(struct link *plink, short dbfType);
#ifdef __cplusplus
From 5ec0633282b0b852c7468919c61e75c457f11310 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 30 Aug 2016 01:13:15 -0500
Subject: [PATCH 039/112] Pass link dbfType to jlif allocator; needed!
---
src/ioc/db/dbJLink.c | 2 +-
src/ioc/db/dbJLink.h | 2 +-
src/std/link/lnkConst.c | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index ed18a2894..40797e9d8 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -213,7 +213,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
return jlif_stop;
}
- pjlink = pjlif->alloc_jlink(parser->plink);
+ pjlink = pjlif->alloc_jlink(parser->plink, parser->dbfType);
if (!pjlink) {
errlogPrintf("dbJLinkInit: Out of memory\n");
return jlif_stop;
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index 3f52a6877..503b64af8 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -42,7 +42,7 @@ typedef struct jlink {
typedef struct jlif {
const char *name;
- jlink* (*alloc_jlink)(struct link *);
+ jlink* (*alloc_jlink)(struct link *, short dbfType);
void (*free_jlink)(jlink *);
jlif_result (*start_parse)(jlink *);
jlif_result (*parse_null)(jlink *);
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 6ed4e5e9a..d655a8078 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -36,7 +36,7 @@
typedef long (*FASTCONVERT)();
typedef struct clink {
- struct jlink jlink; /* embedded */
+ jlink jlink; /* embedded object */
int nElems;
enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type;
union {
@@ -55,7 +55,7 @@ static lset lnkConst_lset;
/*************************** jlif Routines **************************/
-static jlink* lnkConst_alloc(struct link *plink) {
+static jlink* lnkConst_alloc(struct link *plink, short dbfType) {
clink *clink = calloc(1, sizeof(struct clink));
IFDEBUG(10)
From d0dcd61b237ea44e7fd2e4226855f7801c17502c Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 30 Aug 2016 23:03:08 -0500
Subject: [PATCH 040/112] Add code for arrays of strings
---
src/std/link/lnkConst.c | 66 ++++++++++++++++++++++++++++++++++-------
1 file changed, 55 insertions(+), 11 deletions(-)
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index d655a8078..bf956215e 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -199,12 +199,12 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) {
IFDEBUG(10)
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
- if (len > MAX_STRING_SIZE)
- len = MAX_STRING_SIZE;
-
- if (clink->type == s0) {
- char *buf = malloc(len + 1);
+ switch (clink->type) {
+ char *buf, **vec;
+ int nElems;
+ case s0:
+ buf = malloc(len + 1);
if (!buf)
return jlif_stop;
@@ -214,13 +214,43 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) {
clink->nElems = 1;
clink->type = sc40;
clink->value.scalar_string = buf;
- return jlif_continue;
- }
- /* FIXME Implement a0 and ac40 */
- /* FIXME How to handle ai32 and af64? */
- errlogPrintf("lnkConst: Mixed data types in array\n");
+ break;
- return jlif_stop;
+ case a0:
+ clink->type = ac40;
+ /* fall thorough */
+ case ac40:
+ if (len > MAX_STRING_SIZE)
+ len = MAX_STRING_SIZE;
+
+ buf = malloc(len + 1);
+ if (!buf)
+ return jlif_stop;
+
+ strncpy(buf, val, len);
+ buf[len] = '\0';
+
+ nElems = clink->nElems + 1;
+
+ vec = realloc(clink->value.pmem, nElems * sizeof(char *));
+ if (!vec) {
+ free(buf);
+ break;
+ }
+
+ vec[clink->nElems++] = buf;
+ clink->value.pstrings = vec;
+ break;
+
+ case af64:
+ case ai32:
+ errlogPrintf("lnkConst: Mixed data types in array\n");
+ /* fall thorough */
+ default:
+ return jlif_stop;
+ }
+
+ return jlif_continue;
}
static jlif_result lnkConst_start_array(jlink *pjlink) {
@@ -298,6 +328,11 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer
(clink->value.pdoubles, pbuffer, NULL);
break;
+ case ac40:
+ status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
+ (clink->value.pstrings[0], pbuffer, NULL);
+ break;
+
default:
status = S_db_badField;
break;
@@ -359,6 +394,15 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
status = 0;
break;
+ case ac40:
+ conv = dbFastPutConvertRoutine[DBF_STRING][dbrType];
+ for (i = 0; i < nElems; i++) {
+ conv(clink->value.pstrings[i], pdest, NULL);
+ pdest += dbrSize;
+ }
+ status = 0;
+ break;
+
default:
status = S_db_badField;
}
From 40a3a6674530a824ab9065c4ed8cfb5356fd6502 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 31 Aug 2016 00:36:23 -0500
Subject: [PATCH 041/112] Added loadLS routine to lset
The long string in/out records use a different initializer
for constant links. The new loadLS method allows a constant
link type to initialize such a long string field.
NB: This routine was added in the middle of the lset table.
Any external link support implementations must be adjusted.
---
src/ioc/db/dbCa.c | 2 +-
src/ioc/db/dbConstLink.c | 25 +++++++++++++++++++++++++
src/ioc/db/dbDbLink.c | 2 +-
src/ioc/db/dbLink.c | 25 +++++++++++--------------
src/ioc/db/dbLink.h | 2 ++
src/std/link/lnkConst.c | 31 ++++++++++++++++++++++++++++++-
6 files changed, 70 insertions(+), 17 deletions(-)
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index 99dcd75bb..88d4468f4 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -715,7 +715,7 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) {
static lset dbCa_lset = {
0, 1, /* not Constant, Volatile */
dbCaRemoveLink,
- NULL, NULL,
+ NULL, NULL, NULL,
isConnected,
getDBFtype, getElements,
dbCaGetLink,
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 821fc58da..5f3aa1ac0 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -69,6 +69,30 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
(pstr, pbuffer, NULL);
}
+static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
+ epicsUInt32 *plen)
+{
+ const char *pstr = plink->value.constantStr;
+ size_t len;
+
+ if (!pstr)
+ return S_db_badField;
+ len = strlen(pstr);
+
+ /* FIXME This handles the common case, but not the general one... */
+ if (pstr[0] == '[' && pstr[1] == '"' &&
+ pstr[len-2] == '"' && pstr[len-1] == ']') {
+ pstr += 2;
+ len -= 4;
+ }
+ if (--size > len) size = len;
+
+ strncpy(pbuffer, pstr, size);
+ pbuffer[size] = 0;
+ *plen = (epicsUInt32) strlen(pbuffer) + 1;
+ return 0;
+}
+
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
long *pnReq)
{
@@ -102,6 +126,7 @@ static lset dbConst_lset = {
1, 0, /* Constant, not Volatile */
NULL,
dbConstLoadScalar,
+ dbConstLoadLS,
dbConstLoadArray,
NULL,
NULL, dbConstGetNelements,
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index cdecd0ea6..2fc21c5bc 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -338,7 +338,7 @@ static void dbDbScanFwdLink(struct link *plink)
static lset dbDb_lset = {
0, 0, /* not Constant, not Volatile */
dbDbRemoveLink,
- NULL, NULL,
+ NULL, NULL, NULL,
dbDbIsConnected,
dbDbGetDBFtype, dbDbGetElements,
dbDbGetValue,
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index 7e1cceb03..78df46941 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -206,6 +206,17 @@ long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
return S_db_noLSET;
}
+long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
+ epicsUInt32 *plen)
+{
+ lset *plset = plink->lset;
+
+ if (plset && plset->loadLS)
+ return plset->loadLS(plink, pbuffer, size, plen);
+
+ return S_db_noLSET;
+}
+
long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
@@ -400,20 +411,6 @@ void dbScanFwdLink(struct link *plink)
/* Helper functions for long string support */
-long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
- epicsUInt32 *plen)
-{
- if (plink->type == CONSTANT &&
- plink->value.constantStr) {
- strncpy(pbuffer, plink->value.constantStr, --size);
- pbuffer[size] = 0;
- *plen = (epicsUInt32) strlen(pbuffer) + 1;
- return 0;
- }
-
- return S_db_noLSET;
-}
-
long dbGetLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index 2903528c1..ebdf24307 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -37,6 +37,8 @@ typedef struct lset {
/* Const init, data type hinting */
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
+ long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
+ epicsUInt32 *plen);
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest);
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index bf956215e..842867b6d 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -341,6 +341,35 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer
return status;
}
+static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
+ epicsUInt32 *plen)
+{
+ clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+ const char *pstr;
+
+ IFDEBUG(10)
+ printf("lnkConst_loadLS(const@%p, %p, %d, %d)\n",
+ clink, pbuffer, size, *plen);
+
+ switch (clink->type) {
+ case sc40:
+ pstr = clink->value.scalar_string;
+ break;
+
+ case ac40:
+ pstr = clink->value.pstrings[0];
+ break;
+
+ default:
+ return S_db_badField;
+ }
+
+ strncpy(pbuffer, pstr, --size);
+ pbuffer[size] = 0;
+ *plen = (epicsUInt32) strlen(pbuffer) + 1;
+ return 0;
+}
+
static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
long *pnReq)
{
@@ -437,7 +466,7 @@ static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
static lset lnkConst_lset = {
1, 0, /* Constant, not Volatile */
- NULL, lnkConst_loadScalar, lnkConst_loadArray, NULL,
+ NULL, lnkConst_loadScalar, lnkConst_loadLS, lnkConst_loadArray, NULL,
NULL, lnkConst_getNelements, lnkConst_getValue,
NULL, NULL, NULL,
NULL, NULL,
From 3992d4b92ad6ee0493af6e7ba1609cde980d3fc3 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 1 Sep 2016 00:56:26 -0500
Subject: [PATCH 042/112] Split dbJLinkInit, JLinks are now parsed at load-time
---
src/ioc/db/dbJLink.c | 50 ++++++++++++++++++++-----------
src/ioc/db/dbJLink.h | 8 +++--
src/ioc/db/dbLink.c | 4 +--
src/ioc/dbStatic/dbStaticLib.c | 10 +++++--
src/ioc/dbStatic/dbStaticPvt.h | 10 +++++--
src/ioc/misc/iocInit.c | 18 -----------
src/ioc/registry/registryCommon.c | 3 +-
src/ioc/registry/registryJLinks.c | 20 +++++--------
src/ioc/registry/registryJLinks.h | 4 +--
src/std/link/lnkConst.c | 6 ++--
10 files changed, 70 insertions(+), 63 deletions(-)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index 40797e9d8..f94a90e17 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -37,7 +37,6 @@
typedef struct parseContext {
jlink *pjlink;
jlink *product;
- struct link *plink;
short dbfType;
short jsonDepth;
short linkDepth;
@@ -56,12 +55,23 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
parser->jsonDepth, parser->linkDepth, parser->key_is_link);
}
+ if (result == jlif_stop && pjlink) {
+ jlink *parent;
+
+ while ((parent = pjlink->parent)) {
+ pjlink->pif->free_jlink(pjlink);
+ pjlink = parent;
+ }
+ pjlink->pif->free_jlink(pjlink);
+ }
+
if (result == jlif_stop || parser->linkDepth > 0)
return result;
parser->product = pjlink;
parser->key_is_link = 0;
- parser->pjlink = pjlink->parent;
+ if (pjlink)
+ parser->pjlink = pjlink->parent;
IFDEBUG(8)
printf("dbjl_value: product = %p\n", pjlink);
@@ -172,8 +182,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
if (!parser->key_is_link) {
if (!pjlink) {
- errlogPrintf("dbJLinkInit: Illegal second link key '%.*s' seen for %s\n",
- len, key, parser->plink->precord->name);
+ errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
+ len, key);
return jlif_stop;
}
@@ -201,8 +211,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
linkSup = dbFindLinkSup(pdbbase, link_name);
if (!linkSup) {
- errlogPrintf("dbJLinkInit: Link type '%s' not found for %s\n",
- link_name, parser->plink->precord->name);
+ errlogPrintf("dbJLinkInit: Link type '%s' not found\n",
+ link_name);
return jlif_stop;
}
@@ -213,7 +223,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
return jlif_stop;
}
- pjlink = pjlif->alloc_jlink(parser->plink, parser->dbfType);
+ pjlink = pjlif->alloc_jlink(parser->dbfType);
if (!pjlink) {
errlogPrintf("dbJLinkInit: Out of memory\n");
return jlif_stop;
@@ -307,22 +317,21 @@ static yajl_callbacks dbjl_callbacks = {
static const yajl_parser_config dbjl_config =
{ 0, 0 }; /* allowComments = NO, checkUTF8 = NO */
-long dbJLinkInit(struct link *plink, short dbfType)
+long dbJLinkParse(const char *json, size_t jlen, short dbfType,
+ jlink **ppjlink)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbjl_allocs;
yajl_handle yh;
yajl_status ys;
- const char *json = plink->value.json.string;
- size_t jlen = strlen(json);
long status;
IFDEBUG(10)
- printf("dbJLinkInit(\"%s.????\", %d)\n", plink->precord->name, dbfType);
+ printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
+ (int) jlen, json, dbfType, ppjlink);
parser->pjlink = NULL;
parser->product = NULL;
- parser->plink = plink;
parser->dbfType = dbfType;
parser->jsonDepth = 0;
parser->linkDepth = 0;
@@ -343,14 +352,10 @@ long dbJLinkInit(struct link *plink, short dbfType)
switch (ys) {
unsigned char *err;
- jlink *pjlink;
case yajl_status_ok:
assert(parser->jsonDepth == 0);
- pjlink = parser->product;
- assert(pjlink);
- plink->value.json.jlink = pjlink;
- plink->lset = pjlink->pif->get_lset(pjlink);
+ *ppjlink = parser->product;
status = 0;
break;
@@ -367,4 +372,15 @@ long dbJLinkInit(struct link *plink, short dbfType)
return status;
}
+long dbJLinkInit(struct link *plink)
+{
+ jlink *pjlink;
+ assert(plink);
+ pjlink = plink->value.json.jlink;
+
+ if (pjlink)
+ plink->lset = pjlink->pif->get_lset(pjlink, plink);
+
+ return 0;
+}
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index 503b64af8..fc3d86005 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -42,7 +42,7 @@ typedef struct jlink {
typedef struct jlif {
const char *name;
- jlink* (*alloc_jlink)(struct link *, short dbfType);
+ jlink* (*alloc_jlink)(short dbfType);
void (*free_jlink)(jlink *);
jlif_result (*start_parse)(jlink *);
jlif_result (*parse_null)(jlink *);
@@ -56,11 +56,13 @@ typedef struct jlif {
jlif_result (*parse_start_array)(jlink *);
jlif_result (*parse_end_array)(jlink *);
jlif_result (*end_parse)(jlink *);
- struct lset* (*get_lset)(const jlink *);
+ struct lset* (*get_lset)(const jlink *, struct link *);
void (*report)(const jlink *);
} jlif;
-epicsShareFunc long dbJLinkInit(struct link *plink, short dbfType);
+epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
+ jlink **ppjlink);
+epicsShareFunc long dbJLinkInit(struct link *plink);
#ifdef __cplusplus
}
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index 78df46941..2f2bd461a 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -79,7 +79,7 @@ void dbInitLink(struct link *plink, short dbfType)
}
if (plink->type == JSON_LINK) {
- dbJLinkInit(plink, dbfType);
+ dbJLinkInit(plink);
return;
}
@@ -131,7 +131,7 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
* FIXME: Can't create DB links as dbJLink types yet,
* dbLock.c doesn't have any way to find/track them.
*/
- dbJLinkInit(plink, dbfType);
+ dbJLinkInit(plink);
return;
}
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index b9532516b..a1a62e652 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2272,8 +2272,12 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
- pinfo->ltype = JSON_LINK;
- return 0;
+ long status = dbJLinkParse(str, len, ftype, &pinfo->jlink);
+
+ if (!status)
+ pinfo->ltype = JSON_LINK;
+
+ return status;
}
/* Check for other HW link types */
@@ -2428,8 +2432,10 @@ void dbSetLinkJSON(DBLINK *plink, dbLinkInfo *pinfo)
{
plink->type = JSON_LINK;
plink->value.json.string = pinfo->target;
+ plink->value.json.jlink = pinfo->jlink;
pinfo->target = NULL;
+ pinfo->jlink = NULL;
}
static
diff --git a/src/ioc/dbStatic/dbStaticPvt.h b/src/ioc/dbStatic/dbStaticPvt.h
index 8e58e9535..3e2435e79 100644
--- a/src/ioc/dbStatic/dbStaticPvt.h
+++ b/src/ioc/dbStatic/dbStaticPvt.h
@@ -16,6 +16,8 @@
#ifndef INCdbStaticPvth
#define INCdbStaticPvth 1
+#include "dbJLink.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -40,15 +42,19 @@ typedef struct dbLinkInfo {
short ltype;
/* full link string for CONSTANT and PV_LINK,
- * parm string for HW links*/
+ * parm string for HW links, JSON for JSON_LINK
+ */
char *target;
/* for PV_LINK */
short modifiers;
- /* HW links */
+ /* for HW links */
char hwid[6]; /* one extra element for a nil */
int hwnums[5];
+
+ /* for JSON_LINK */
+ jlink *jlink;
} dbLinkInfo;
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c
index 09558c1fb..f863e3fe9 100644
--- a/src/ioc/misc/iocInit.c
+++ b/src/ioc/misc/iocInit.c
@@ -80,7 +80,6 @@ static enum {
/* define forward references*/
static int checkDatabase(dbBase *pdbbase);
static void initDrvSup(void);
-static void initJLinks(void);
static void initRecSup(void);
static void initDevSup(void);
static void finishDevSup(void);
@@ -147,7 +146,6 @@ static int iocBuild_2(void)
{
initHookAnnounce(initHookAfterCaLinkInit);
- initJLinks();
initDrvSup();
initHookAnnounce(initHookAfterInitDrvSup);
@@ -377,22 +375,6 @@ static void initDrvSup(void) /* Locate all driver support entry tables */
}
}
-static void initJLinks(void)
-{
- linkSup *plinkSup;
-
- for (plinkSup = (linkSup *)ellFirst(&pdbbase->linkList); plinkSup;
- plinkSup = (linkSup *)ellNext(&plinkSup->node)) {
- jlif *pjlif = registryJLinkFind(plinkSup->name);
-
- if (!pjlif) {
- errlogPrintf("iocInit: JLink %s not found\n", plinkSup->name);
- continue;
- }
- plinkSup->pjlif = pjlif;
- }
-}
-
static void initRecSup(void)
{
dbRecordType *pdbRecordType;
diff --git a/src/ioc/registry/registryCommon.c b/src/ioc/registry/registryCommon.c
index f4ec4af55..56664c5bb 100644
--- a/src/ioc/registry/registryCommon.c
+++ b/src/ioc/registry/registryCommon.c
@@ -81,8 +81,7 @@ void registerJLinks(DBBASE *pbase, int nLinks, jlif * const *jlifsl)
{
int i;
for (i = 0; i < nLinks; i++) {
- if (registryJLinkFind(jlifsl[i]->name)) continue;
- if (!registryJLinkAdd(jlifsl[i])) {
+ if (!registryJLinkAdd(pbase, jlifsl[i])) {
errlogPrintf("registryJLinkAdd failed %s\n",
jlifsl[i]->name);
continue;
diff --git a/src/ioc/registry/registryJLinks.c b/src/ioc/registry/registryJLinks.c
index 04c827098..921a2cbcc 100644
--- a/src/ioc/registry/registryJLinks.c
+++ b/src/ioc/registry/registryJLinks.c
@@ -1,27 +1,23 @@
/*************************************************************************\
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
-* 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.
\*************************************************************************/
/* registryJLinks.c */
-#define epicsExportSharedSymbols
#include "registry.h"
+#define epicsExportSharedSymbols
+#include "dbBase.h"
+#include "dbStaticLib.h"
#include "registryJLinks.h"
#include "dbJLink.h"
-static void *registryID = "JSON link types";
-
-
-epicsShareFunc int registryJLinkAdd(struct jlif *pjlif)
+epicsShareFunc int registryJLinkAdd(DBBASE *pbase, struct jlif *pjlif)
{
- return registryAdd(registryID, pjlif->name, pjlif);
-}
+ linkSup *plinkSup = dbFindLinkSup(pbase, pjlif->name);
-epicsShareFunc jlif * registryJLinkFind(const char *name)
-{
- return registryFind(registryID, name);
+ if (plinkSup)
+ plinkSup->pjlif = pjlif;
+ return !!plinkSup;
}
diff --git a/src/ioc/registry/registryJLinks.h b/src/ioc/registry/registryJLinks.h
index 3f304c6d5..7e6a8933e 100644
--- a/src/ioc/registry/registryJLinks.h
+++ b/src/ioc/registry/registryJLinks.h
@@ -10,6 +10,7 @@
#ifndef INC_registryJLinks_H
#define INC_registryJLinks_H
+#include "dbBase.h"
#include "dbJLink.h"
#include "shareLib.h"
@@ -17,8 +18,7 @@
extern "C" {
#endif
-epicsShareFunc int registryJLinkAdd(jlif *pjlif);
-epicsShareFunc jlif * registryJLinkFind(const char *name);
+epicsShareFunc int registryJLinkAdd(DBBASE *pbase, jlif *pjlif);
#ifdef __cplusplus
}
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 842867b6d..14d8a5b59 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -55,7 +55,7 @@ static lset lnkConst_lset;
/*************************** jlif Routines **************************/
-static jlink* lnkConst_alloc(struct link *plink, short dbfType) {
+static jlink* lnkConst_alloc(short dbfType) {
clink *clink = calloc(1, sizeof(struct clink));
IFDEBUG(10)
@@ -275,9 +275,9 @@ static jlif_result lnkConst_end_array(jlink *pjlink) {
return jlif_continue;
}
-static struct lset* lnkConst_get_lset(const jlink *pjlink) {
+static struct lset* lnkConst_get_lset(const jlink *pjlink, struct link *plink) {
IFDEBUG(10)
- printf("lnkConst_get_lset(const@%p)\n", pjlink);
+ printf("lnkConst_get_lset(const@%p, %p)\n", pjlink, plink);
return &lnkConst_lset;
}
From 23c71e9965106cffbeae523f4dd17d20e4fe1aaa Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 1 Sep 2016 23:21:23 -0500
Subject: [PATCH 043/112] Various improvements
* Added new lset::openLink() method, called on JSON_LINKs only
* Cleanup in dbJLink.c to prevent memory leaks.
* Removed jlif::start_parse() method.
* Renamed jlif::end_parse() to end_child, which will be called on
the parent link when a child link has succesfully finished parsing.
---
src/ioc/db/dbCa.c | 2 +-
src/ioc/db/dbConstLink.c | 2 +-
src/ioc/db/dbDbLink.c | 2 +-
src/ioc/db/dbJLink.c | 121 ++++++++++++++++++++++-----------------
src/ioc/db/dbJLink.h | 7 +--
src/ioc/db/dbLink.c | 8 +++
src/ioc/db/dbLink.h | 5 ++
src/std/link/lnkConst.c | 9 +--
8 files changed, 94 insertions(+), 62 deletions(-)
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index 88d4468f4..d680dc4a7 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -714,7 +714,7 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) {
static lset dbCa_lset = {
0, 1, /* not Constant, Volatile */
- dbCaRemoveLink,
+ NULL, dbCaRemoveLink,
NULL, NULL, NULL,
isConnected,
getDBFtype, getElements,
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 5f3aa1ac0..32e0c88c1 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -124,7 +124,7 @@ static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
static lset dbConst_lset = {
1, 0, /* Constant, not Volatile */
- NULL,
+ NULL, NULL,
dbConstLoadScalar,
dbConstLoadLS,
dbConstLoadArray,
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index 2fc21c5bc..294a13fe0 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -337,7 +337,7 @@ static void dbDbScanFwdLink(struct link *plink)
static lset dbDb_lset = {
0, 0, /* not Constant, not Volatile */
- dbDbRemoveLink,
+ NULL, dbDbRemoveLink,
NULL, NULL, NULL,
dbDbIsConnected,
dbDbGetDBFtype, dbDbGetElements,
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index f94a90e17..11f364e5e 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -43,17 +43,13 @@ typedef struct parseContext {
unsigned key_is_link:1;
} parseContext;
-#define CALLIF(routine) !routine ? jlif_stop : routine
+#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
-
-static int dbjl_value(parseContext *parser, jlif_result result) {
+static int dbjl_return(parseContext *parser, jlif_result result) {
jlink *pjlink = parser->pjlink;
- IFDEBUG(10) {
- printf("dbjl_value(%s@%p, %d)\n", pjlink->pif->name, pjlink, result);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
- }
+ IFDEBUG(10)
+ printf("dbjl_return(%s@%p, %d)\n", pjlink->pif->name, pjlink, result);
if (result == jlif_stop && pjlink) {
jlink *parent;
@@ -65,19 +61,35 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
pjlink->pif->free_jlink(pjlink);
}
- if (result == jlif_stop || parser->linkDepth > 0)
- return result;
+ return result;
+}
+
+static int dbjl_value(parseContext *parser, jlif_result result) {
+ jlink *pjlink = parser->pjlink;
+ jlink *parent;
+
+ IFDEBUG(10) {
+ printf("dbjl_value(%s@%p, %d)\n", pjlink->pif->name, pjlink, result);
+ printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ }
+
+ if (result == jlif_stop || parser->linkDepth > 0)
+ return dbjl_return(parser, result);
+
+ parent = pjlink->parent;
+ if (!parent)
+ parser->product = pjlink;
+ else if (parent->pif->end_child)
+ parent->pif->end_child(parent, pjlink);
- parser->product = pjlink;
parser->key_is_link = 0;
- if (pjlink)
- parser->pjlink = pjlink->parent;
+ parser->pjlink = parent;
IFDEBUG(8)
printf("dbjl_value: product = %p\n", pjlink);
- return pjlink->pif->end_parse ? pjlink->pif->end_parse(pjlink)
- : jlif_continue;
+ return jlif_continue;
}
static int dbjl_null(void *ctx) {
@@ -88,7 +100,8 @@ static int dbjl_null(void *ctx) {
printf("dbjl_null(%s@%p)\n", pjlink->pif->name, pjlink);
assert(pjlink);
- return dbjl_value(parser, CALLIF(pjlink->pif->parse_null)(pjlink));
+ return dbjl_value(parser,
+ CALL_OR_STOP(pjlink->pif->parse_null)(pjlink));
}
static int dbjl_boolean(void *ctx, int val) {
@@ -96,7 +109,8 @@ static int dbjl_boolean(void *ctx, int val) {
jlink *pjlink = parser->pjlink;
assert(pjlink);
- return dbjl_value(parser, CALLIF(pjlink->pif->parse_boolean)(pjlink, val));
+ return dbjl_value(parser,
+ CALL_OR_STOP(pjlink->pif->parse_boolean)(pjlink, val));
}
static int dbjl_integer(void *ctx, long num) {
@@ -104,10 +118,12 @@ static int dbjl_integer(void *ctx, long num) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
- printf("dbjl_integer(%s@%p, %ld)\n", pjlink->pif->name, pjlink, num);
+ printf("dbjl_integer(%s@%p, %ld)\n",
+ pjlink->pif->name, pjlink, num);
assert(pjlink);
- return dbjl_value(parser, CALLIF(pjlink->pif->parse_integer)(pjlink, num));
+ return dbjl_value(parser,
+ CALL_OR_STOP(pjlink->pif->parse_integer)(pjlink, num));
}
static int dbjl_double(void *ctx, double num) {
@@ -115,10 +131,12 @@ static int dbjl_double(void *ctx, double num) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
- printf("dbjl_double(%s@%p, %g)\n", pjlink->pif->name, pjlink, num);
+ printf("dbjl_double(%s@%p, %g)\n",
+ pjlink->pif->name, pjlink, num);
assert(pjlink);
- return dbjl_value(parser, CALLIF(pjlink->pif->parse_double)(pjlink, num));
+ return dbjl_value(parser,
+ CALL_OR_STOP(pjlink->pif->parse_double)(pjlink, num));
}
static int dbjl_string(void *ctx, const unsigned char *val, unsigned len) {
@@ -126,11 +144,12 @@ static int dbjl_string(void *ctx, const unsigned char *val, unsigned len) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
- printf("dbjl_string(%s@%p, \"%.*s\")\n", pjlink->pif->name, pjlink, len, val);
+ printf("dbjl_string(%s@%p, \"%.*s\")\n",
+ pjlink->pif->name, pjlink, len, val);
assert(pjlink);
return dbjl_value(parser,
- CALLIF(pjlink->pif->parse_string)(pjlink, (const char *) val, len));
+ CALL_OR_STOP(pjlink->pif->parse_string)(pjlink, (const char *) val, len));
}
static int dbjl_start_map(void *ctx) {
@@ -159,8 +178,9 @@ static int dbjl_start_map(void *ctx) {
parser->linkDepth++;
parser->jsonDepth++;
- result = CALLIF(pjlink->pif->parse_start_map)(pjlink);
- if (result == jlif_key_embed_link) {
+
+ result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
+ if (result == jlif_key_child_link) {
parser->key_is_link = 1;
result = jlif_continue;
}
@@ -168,7 +188,7 @@ static int dbjl_start_map(void *ctx) {
IFDEBUG(10)
printf("dbjl_start_map -> %d\n", result);
- return result;
+ return dbjl_return(parser, result);
}
static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
@@ -178,13 +198,12 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
size_t lnlen = len;
linkSup *linkSup;
jlif *pjlif;
- jlif_result result;
if (!parser->key_is_link) {
if (!pjlink) {
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
len, key);
- return jlif_stop;
+ return dbjl_return(parser, jlif_stop);
}
IFDEBUG(10) {
@@ -195,7 +214,9 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
}
assert(parser->linkDepth > 0);
- return CALLIF(pjlink->pif->parse_map_key)(pjlink, (const char *) key, len);
+ return dbjl_return(parser,
+ CALL_OR_STOP(pjlink->pif->parse_map_key)(pjlink,
+ (const char *) key, len));
}
IFDEBUG(10) {
@@ -213,44 +234,35 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
if (!linkSup) {
errlogPrintf("dbJLinkInit: Link type '%s' not found\n",
link_name);
- return jlif_stop;
+ return dbjl_return(parser, jlif_stop);
}
pjlif = linkSup->pjlif;
if (!pjlif) {
errlogPrintf("dbJLinkInit: Support for Link type '%s' not loaded\n",
link_name);
- return jlif_stop;
+ return dbjl_return(parser, jlif_stop);
}
pjlink = pjlif->alloc_jlink(parser->dbfType);
if (!pjlink) {
errlogPrintf("dbJLinkInit: Out of memory\n");
- return jlif_stop;
+ return dbjl_return(parser, jlif_stop);
}
pjlink->pif = pjlif;
if (parser->pjlink) {
- /* This is an embedded link */
+ /* We're starting a child link, save its parent */
pjlink->parent = parser->pjlink;
}
+ parser->pjlink = pjlink;
- result = pjlif->start_parse ? pjlif->start_parse(pjlink) : jlif_continue;
- if (result == jlif_continue) {
- parser->pjlink = pjlink;
+ IFDEBUG(8)
+ printf("dbjl_map_key: New %s@%p\n", pjlink->pif->name, pjlink);
- IFDEBUG(8)
- printf("dbjl_map_key: New %s@%p\n", pjlink->pif->name, pjlink);
- }
- else {
- pjlif->free_jlink(pjlink);
- }
- // FIXME Ensure link map has only one link key...
+ // FIXME How to ensure a link map has only one key/value pair?
- IFDEBUG(10)
- printf("dbjl_map_key -> %d\n", result);
-
- return result;
+ return jlif_continue;
}
static int dbjl_end_map(void *ctx) {
@@ -269,7 +281,8 @@ static int dbjl_end_map(void *ctx) {
if (parser->linkDepth > 0) {
parser->linkDepth--;
- result = dbjl_value(parser, CALLIF(pjlink->pif->parse_end_map)(pjlink));
+ result = dbjl_value(parser,
+ CALL_OR_STOP(pjlink->pif->parse_end_map)(pjlink));
}
else {
result = jlif_continue;
@@ -290,7 +303,9 @@ static int dbjl_start_array(void *ctx) {
assert(pjlink);
parser->linkDepth++;
parser->jsonDepth++;
- return CALLIF(pjlink->pif->parse_start_array)(pjlink);
+
+ return dbjl_return(parser,
+ CALL_OR_STOP(pjlink->pif->parse_start_array)(pjlink));
}
static int dbjl_end_array(void *ctx) {
@@ -306,9 +321,12 @@ static int dbjl_end_array(void *ctx) {
assert(pjlink);
parser->linkDepth--;
parser->jsonDepth--;
- return dbjl_value(parser, CALLIF(pjlink->pif->parse_end_array)(pjlink));
+
+ return dbjl_value(parser,
+ CALL_OR_STOP(pjlink->pif->parse_end_array)(pjlink));
}
+
static yajl_callbacks dbjl_callbacks = {
dbjl_null, dbjl_boolean, dbjl_integer, dbjl_double, NULL, dbjl_string,
dbjl_start_map, dbjl_map_key, dbjl_end_map, dbjl_start_array, dbjl_end_array
@@ -380,7 +398,8 @@ long dbJLinkInit(struct link *plink)
pjlink = plink->value.json.jlink;
if (pjlink)
- plink->lset = pjlink->pif->get_lset(pjlink, plink);
+ plink->lset = pjlink->pif->get_lset(pjlink);
+ dbLinkOpen(plink);
return 0;
}
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index fc3d86005..7b32fb130 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -27,7 +27,7 @@ typedef enum {
typedef enum {
jlif_key_stop = jlif_stop,
jlif_key_continue = jlif_continue,
- jlif_key_embed_link
+ jlif_key_child_link
} jlif_key_result;
struct link;
@@ -44,7 +44,6 @@ typedef struct jlif {
const char *name;
jlink* (*alloc_jlink)(short dbfType);
void (*free_jlink)(jlink *);
- jlif_result (*start_parse)(jlink *);
jlif_result (*parse_null)(jlink *);
jlif_result (*parse_boolean)(jlink *, int val);
jlif_result (*parse_integer)(jlink *, long num);
@@ -55,8 +54,8 @@ typedef struct jlif {
jlif_result (*parse_end_map)(jlink *);
jlif_result (*parse_start_array)(jlink *);
jlif_result (*parse_end_array)(jlink *);
- jlif_result (*end_parse)(jlink *);
- struct lset* (*get_lset)(const jlink *, struct link *);
+ void (*end_child)(jlink *parent, jlink *child);
+ struct lset* (*get_lset)(const jlink *);
void (*report)(const jlink *);
} jlif;
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index 2f2bd461a..f58944222 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -160,6 +160,14 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
}
}
+void dbLinkOpen(struct link *plink)
+{
+ lset *plset = plink->lset;
+
+ if (plset && plset->openLink)
+ plset->openLink(plink);
+}
+
void dbRemoveLink(struct dbLocker *locker, struct link *plink)
{
lset *plset = plink->lset;
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index ebdf24307..3cf676af9 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -32,6 +32,9 @@ typedef struct lset {
const unsigned isConstant:1;
const unsigned isVolatile:1;
+ /* Activation */
+ void (*openLink)(struct link *plink);
+
/* Destructor */
void (*removeLink)(struct dbLocker *locker, struct link *plink);
@@ -76,6 +79,8 @@ typedef struct lset {
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
short dbfType, DBADDR *ptarget);
+
+epicsShareFunc void dbLinkOpen(struct link *plink);
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
epicsShareFunc int dbLinkIsDefined(const struct link *plink); /* 0 or 1 */
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 14d8a5b59..1059521d3 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -275,9 +275,9 @@ static jlif_result lnkConst_end_array(jlink *pjlink) {
return jlif_continue;
}
-static struct lset* lnkConst_get_lset(const jlink *pjlink, struct link *plink) {
+static struct lset* lnkConst_get_lset(const jlink *pjlink) {
IFDEBUG(10)
- printf("lnkConst_get_lset(const@%p, %p)\n", pjlink, plink);
+ printf("lnkConst_get_lset(const@%p)\n", pjlink);
return &lnkConst_lset;
}
@@ -466,7 +466,8 @@ static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
static lset lnkConst_lset = {
1, 0, /* Constant, not Volatile */
- NULL, lnkConst_loadScalar, lnkConst_loadLS, lnkConst_loadArray, NULL,
+ NULL, NULL,
+ lnkConst_loadScalar, lnkConst_loadLS, lnkConst_loadArray, NULL,
NULL, lnkConst_getNelements, lnkConst_getValue,
NULL, NULL, NULL,
NULL, NULL,
@@ -476,7 +477,7 @@ static lset lnkConst_lset = {
};
static jlif lnkConstIf = {
- "const", lnkConst_alloc, lnkConst_free, NULL,
+ "const", lnkConst_alloc, lnkConst_free,
NULL, lnkConst_boolean, lnkConst_integer, lnkConst_double, lnkConst_string,
NULL, NULL, NULL, lnkConst_start_array, lnkConst_end_array,
NULL, lnkConst_get_lset, lnkConst_report
From 6e88d486157364329ca58a7f013c606235102c0c Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 13:25:19 -0500
Subject: [PATCH 044/112] Added epicsStrnDup() and dbmfStrndup() routines
The JSON parser passes string arguments with a length
instead or nil-terminating them. These routines make it
simple to copy such strings into either permanent or
temporary storage.
---
src/libCom/dbmf/dbmf.c | 16 ++++++++++++----
src/libCom/dbmf/dbmf.h | 1 +
src/libCom/misc/epicsString.c | 9 +++++++++
src/libCom/misc/epicsString.h | 1 +
4 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/src/libCom/dbmf/dbmf.c b/src/libCom/dbmf/dbmf.c
index 03be8ea32..423027b11 100644
--- a/src/libCom/dbmf/dbmf.c
+++ b/src/libCom/dbmf/dbmf.c
@@ -158,10 +158,18 @@ void* dbmfMalloc(size_t size)
char * dbmfStrdup(const char *str)
{
- size_t len = strlen(str);
- char *buf = dbmfMalloc(len + 1);
- strcpy(buf, str);
- return buf;
+ size_t len = strlen(str);
+ char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
+
+ return strcpy(buf, str);
+}
+
+char * dbmfStrndup(const char *str, size_t len)
+{
+ char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
+
+ buf[len] = '\0';
+ return strncpy(buf, str, len);
}
void dbmfFree(void* mem)
diff --git a/src/libCom/dbmf/dbmf.h b/src/libCom/dbmf/dbmf.h
index a641d66c7..2c8a28f2c 100644
--- a/src/libCom/dbmf/dbmf.h
+++ b/src/libCom/dbmf/dbmf.h
@@ -26,6 +26,7 @@ extern "C" {
epicsShareFunc int dbmfInit(size_t size, int chunkItems);
epicsShareFunc void * dbmfMalloc(size_t bytes);
epicsShareFunc char * dbmfStrdup(const char *str);
+epicsShareFunc char * dbmfStrndup(const char *str, size_t len);
epicsShareFunc char * dbmfStrcat3(const char *lhs, const char *mid,
const char *rhs);
epicsShareFunc void dbmfFree(void *bytes);
diff --git a/src/libCom/misc/epicsString.c b/src/libCom/misc/epicsString.c
index 7a63580a2..996c669aa 100644
--- a/src/libCom/misc/epicsString.c
+++ b/src/libCom/misc/epicsString.c
@@ -223,6 +223,15 @@ int epicsStrnCaseCmp(const char *s1, const char *s2, size_t len)
return 0;
}
+char * epicsStrnDup(const char *s, size_t len)
+{
+ char *buf = mallocMustSucceed(len + 1, "epicsStrnDup");
+
+ strncpy(buf, s, len);
+ buf[len] = '\0';
+ return buf;
+}
+
char * epicsStrDup(const char *s)
{
return strcpy(mallocMustSucceed(strlen(s)+1, "epicsStrDup"), s);
diff --git a/src/libCom/misc/epicsString.h b/src/libCom/misc/epicsString.h
index c264ebb27..e4bc3804f 100644
--- a/src/libCom/misc/epicsString.h
+++ b/src/libCom/misc/epicsString.h
@@ -32,6 +32,7 @@ epicsShareFunc size_t epicsStrnEscapedFromRawSize(const char *buf, size_t len);
epicsShareFunc int epicsStrCaseCmp(const char *s1, const char *s2);
epicsShareFunc int epicsStrnCaseCmp(const char *s1, const char *s2, size_t len);
epicsShareFunc char * epicsStrDup(const char *s);
+epicsShareFunc char * epicsStrnDup(const char *s, size_t len);
epicsShareFunc int epicsStrPrintEscaped(FILE *fp, const char *s, size_t n);
#define epicsStrSnPrintEscaped epicsStrnEscapedFromRaw
epicsShareFunc int epicsStrGlobMatch(const char *str, const char *pattern);
From 1e1c52cb691b25a69d9409fedd1fe399922fd75a Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 13:27:30 -0500
Subject: [PATCH 045/112] Use new epicsStrnDup() API
---
src/std/link/lnkConst.c | 31 ++++++++-----------------------
1 file changed, 8 insertions(+), 23 deletions(-)
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 1059521d3..0b5c58937 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -13,6 +13,7 @@
#include "dbDefs.h"
#include "errlog.h"
#include "epicsAssert.h"
+#include "epicsString.h"
#include "epicsTypes.h"
#include "dbAccessDefs.h"
#include "dbConvertFast.h"
@@ -200,45 +201,29 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) {
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
switch (clink->type) {
- char *buf, **vec;
+ char **vec;
int nElems;
case s0:
- buf = malloc(len + 1);
- if (!buf)
- return jlif_stop;
-
- strncpy(buf, val, len);
- buf[len] = '\0';
-
clink->nElems = 1;
clink->type = sc40;
- clink->value.scalar_string = buf;
+ clink->value.scalar_string = epicsStrnDup(val, len);
break;
case a0:
clink->type = ac40;
/* fall thorough */
case ac40:
- if (len > MAX_STRING_SIZE)
- len = MAX_STRING_SIZE;
-
- buf = malloc(len + 1);
- if (!buf)
- return jlif_stop;
-
- strncpy(buf, val, len);
- buf[len] = '\0';
-
nElems = clink->nElems + 1;
vec = realloc(clink->value.pmem, nElems * sizeof(char *));
- if (!vec) {
- free(buf);
+ if (!vec)
break;
- }
- vec[clink->nElems++] = buf;
+ if (len >= MAX_STRING_SIZE)
+ len = MAX_STRING_SIZE - 1;
+
+ vec[clink->nElems++] = epicsStrnDup(val, len);
clink->value.pstrings = vec;
break;
From 07b09eed1f27a0cd0665fd25f5a10211f9803b66 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 13:36:17 -0500
Subject: [PATCH 046/112] Fixes to dbJLink, added dbJLinkFree()
Moved the clearing of key_is_link to the right place,
embedded links now parse correctly.
---
src/ioc/db/dbJLink.c | 10 +++++++---
src/ioc/db/dbJLink.h | 2 ++
src/ioc/dbStatic/dbStaticLib.c | 3 +--
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index 11f364e5e..ec98fbccb 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -17,6 +17,7 @@
#define epicsExportSharedSybols
#include "dbAccessDefs.h"
#include "dbCommon.h"
+#include "dbLink.h"
#include "dbJLink.h"
#include "dbStaticLib.h"
#include "link.h"
@@ -45,6 +46,11 @@ typedef struct parseContext {
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
+void dbJLinkFree(jlink *pjlink) {
+ if (pjlink)
+ pjlink->pif->free_jlink(pjlink);
+}
+
static int dbjl_return(parseContext *parser, jlif_result result) {
jlink *pjlink = parser->pjlink;
@@ -83,7 +89,6 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
else if (parent->pif->end_child)
parent->pif->end_child(parent, pjlink);
- parser->key_is_link = 0;
parser->pjlink = parent;
IFDEBUG(8)
@@ -256,12 +261,11 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
pjlink->parent = parser->pjlink;
}
parser->pjlink = pjlink;
+ parser->key_is_link = 0;
IFDEBUG(8)
printf("dbjl_map_key: New %s@%p\n", pjlink->pif->name, pjlink);
- // FIXME How to ensure a link map has only one key/value pair?
-
return jlif_continue;
}
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index 7b32fb130..fff8b7fe1 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -63,6 +63,8 @@ epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
jlink **ppjlink);
epicsShareFunc long dbJLinkInit(struct link *plink);
+epicsShareFunc void dbJLinkFree(jlink *);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index a1a62e652..62527c693 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -124,8 +124,7 @@ void dbFreeLinkContents(struct link *plink)
case MACRO_LINK: free((void *)plink->value.macro_link.macroStr); break;
case PV_LINK: free((void *)plink->value.pv_link.pvname); break;
case JSON_LINK:
- if (plink->value.json.jlink)
- plink->value.json.jlink->pif->free_jlink(plink->value.json.jlink);
+ dbJLinkFree(plink->value.json.jlink);
parm = plink->value.json.string;
break;
case VME_IO: parm = plink->value.vmeio.parm; break;
From 8d1c4165515202e94dcaf61b2e1cc1da48aae8d6 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 19:21:11 -0500
Subject: [PATCH 047/112] Moved PV_LINK-specific code out of dbLink.c into link
types
This required a change to the lset::getValue arguments, removing
the pstat and psevr pointers. Links can still return a non-zero
value from getValue and trigger a LINK:INVALID alarm, but for any
other alarm settings they must manipulate the record themselves.
---
src/ioc/db/dbCa.c | 14 +++++++++-----
src/ioc/db/dbCa.h | 3 +--
src/ioc/db/dbConstLink.c | 2 +-
src/ioc/db/dbDbLink.c | 8 +++++---
src/ioc/db/dbLink.c | 9 ++-------
src/ioc/db/dbLink.h | 2 +-
src/std/link/lnkConst.c | 2 +-
7 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index d680dc4a7..3b223be89 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -50,6 +50,7 @@
#include "dbLock.h"
#include "dbScan.h"
#include "link.h"
+#include "recGbl.h"
#include "recSup.h"
/* defined in dbContext.cpp
@@ -337,8 +338,8 @@ void dbCaRemoveLink(struct dbLocker *locker, struct link *plink)
addAction(pca, CA_CLEAR_CHANNEL);
}
-long dbCaGetLink(struct link *plink,short dbrType, void *pdest,
- epicsEnum16 *pstat, epicsEnum16 *psevr, long *nelements)
+long dbCaGetLink(struct link *plink, short dbrType, void *pdest,
+ long *nelements)
{
caLink *pca = (caLink *)plink->value.pv_link.pvt;
long status = 0;
@@ -410,10 +411,13 @@ long dbCaGetLink(struct link *plink,short dbrType, void *pdest,
aConvert(&dbAddr, pdest, ntoget, ntoget, 0);
}
done:
- if (pstat) *pstat = pca->stat;
- if (psevr) *psevr = pca->sevr;
- if (link_action) addAction(pca, link_action);
+ if (link_action)
+ addAction(pca, link_action);
+ if (!status)
+ recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
+ plink->precord, pca->stat, pca->sevr);
epicsMutexUnlock(pca->lock);
+
return status;
}
diff --git a/src/ioc/db/dbCa.h b/src/ioc/db/dbCa.h
index f1cfada40..4b9e9d9ba 100644
--- a/src/ioc/db/dbCa.h
+++ b/src/ioc/db/dbCa.h
@@ -33,8 +33,7 @@ epicsShareFunc long dbCaAddLink(struct dbLocker *locker, struct link *plink, sho
epicsShareFunc void dbCaRemoveLink(struct dbLocker *locker, struct link *plink);
epicsShareFunc long dbCaGetLink(struct link *plink,
- short dbrType, void *pbuffer, epicsEnum16 *pstat, epicsEnum16 *psevr,
- long *nRequest);
+ short dbrType, void *pbuffer, long *nRequest);
epicsShareFunc long dbCaGetAttributes(const struct link *plink,
dbCaCallback callback, void *userPvt);
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 32e0c88c1..7d196ec88 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -115,7 +115,7 @@ static long dbConstGetNelements(const struct link *plink, long *nelements)
}
static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
- epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+ long *pnRequest)
{
if (pnRequest)
*pnRequest = 0;
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index 294a13fe0..87e78b1b0 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -129,7 +129,7 @@ static long dbDbGetElements(const struct link *plink, long *nelements)
}
static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
- epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+ long *pnRequest)
{
struct pv_link *ppv_link = &plink->value.pv_link;
DBADDR *paddr = ppv_link->pvt;
@@ -146,8 +146,6 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
if (status)
return status;
}
- *pstat = paddr->precord->stat;
- *psevr = paddr->precord->sevr;
if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
@@ -167,6 +165,10 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
}
ppv_link->lastGetdbrType = dbrType;
}
+
+ if (!status)
+ recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
+ plink->precord, paddr->precord->stat, paddr->precord->sevr);
return status;
}
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index f58944222..054df88c9 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -270,7 +270,6 @@ long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
long *poptions, long *pnRequest)
{
struct dbCommon *precord = plink->precord;
- epicsEnum16 sevr = 0, stat = 0;
lset *plset = plink->lset;
long status;
@@ -282,13 +281,9 @@ long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
if (!plset || !plset->getValue)
return -1;
- status = plset->getValue(plink, dbrType, pbuffer, &stat, &sevr, pnRequest);
- if (status) {
+ status = plset->getValue(plink, dbrType, pbuffer, pnRequest);
+ if (status)
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
- } else {
- recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode, precord,
- stat, sevr);
- }
return status;
}
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index 3cf676af9..cf7ff0433 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -52,7 +52,7 @@ typedef struct lset {
/* Get data */
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
- epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest);
+ long *pnRequest);
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 0b5c58937..4ff3ed2bc 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -435,7 +435,7 @@ static long lnkConst_getNelements(const struct link *plink, long *nelements)
}
static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
- epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+ long *pnRequest)
{
IFDEBUG(10)
printf("lnkConst_loadScalar(const@%p, %d, %p, ... (%ld))\n",
From 5fe3e8bfb5002d664a34e7c89664223958182649 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 19:22:55 -0500
Subject: [PATCH 048/112] Added calc link-type
---
src/std/link/Makefile | 1 +
src/std/link/links.dbd.pod | 43 ++-
src/std/link/lnkCalc.c | 545 +++++++++++++++++++++++++++++++++++++
3 files changed, 585 insertions(+), 4 deletions(-)
create mode 100644 src/std/link/lnkCalc.c
diff --git a/src/std/link/Makefile b/src/std/link/Makefile
index 56b56b8be..31d14b825 100644
--- a/src/std/link/Makefile
+++ b/src/std/link/Makefile
@@ -12,6 +12,7 @@ SRC_DIRS += $(STDDIR)/link
DBD += links.dbd
dbRecStd_SRCS += lnkConst.c
+dbRecStd_SRCS += lnkCalc.c
HTMLS += links.html
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
index 335808097..9cff283d0 100644
--- a/src/std/link/links.dbd.pod
+++ b/src/std/link/links.dbd.pod
@@ -94,18 +94,53 @@ promoted to doubles. Mixing strings and numbers in an array will result in an er
=cut
-#link(calc, lnkCalcIf)
+link(calc, lnkCalcIf)
=head3 Calculation Link C<"calc">
-...
+Calculation links can perform simple mathematical expressions on scalar
+(double-precision floating-point) values obtained from other link types and
+return a single double-precision floating-point result. The expressions are
+evaluated by the EPICS Calc engine, and up to 12 input links can be used.
=head4 Parameters
-...
+The link value is a map with the following keys:
+
+=over
+
+=item expr
+
+The expression to be evaluated, provided as a string.
+
+=item major
+
+An optional expression that returns non-zero to raise a major alarm.
+
+=item minor
+
+An optional expression that returns non-zero to raise a minor alarm.
+
+=item args
+
+A JSON list of up to 12 input arguments for the expression, which are assigned
+to the inputs C, C, C, ... C. Each input argument may be either a
+numeric literal or an embedded link inside C<{}> braces.
+
+=item units
+
+An optional string specifying the engineering units for the result of the
+expression. Equivalent to the C field of a record.
+
+item prec
+
+An optional integer specifying the numeric precision with which the calculation
+result should be displayed. Equivalent to the E field of a record.
+
+=back
=head4 Example
- ...
+ {calc: {expr:"A+B", args:[1, 2]}}
=cut
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
new file mode 100644
index 000000000..015dd0311
--- /dev/null
+++ b/src/std/link/lnkCalc.c
@@ -0,0 +1,545 @@
+/*************************************************************************\
+* 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.
+\*************************************************************************/
+/* lnkCalc.c */
+
+#include
+#include
+#include
+
+#include "alarm.h"
+#include "dbDefs.h"
+#include "dbmf.h"
+#include "errlog.h"
+#include "epicsAssert.h"
+#include "epicsString.h"
+#include "epicsTypes.h"
+#include "dbAccessDefs.h"
+#include "dbConvertFast.h"
+#include "dbLink.h"
+#include "dbJLink.h"
+#include "dbStaticLib.h"
+#include "dbStaticPvt.h"
+#include "postfix.h"
+#include "recGbl.h"
+#include "epicsExport.h"
+
+
+typedef long (*FASTCONVERT)();
+
+/* Change 'undef' to 'define' to turn on debug statements: */
+#define DEBUG_LINK
+
+#ifdef DEBUG_LINK
+ int lnkCalcDebug = 10;
+# define IFDEBUG(n) \
+ if (lnkCalcDebug >= n) /* block or statement */
+#else
+# define IFDEBUG(n) \
+ if(0) /* Compiler will elide the block or statement */
+#endif
+
+typedef struct calc_link {
+ jlink jlink; /* embedded object */
+ int nArgs;
+ enum {ps_init,
+ ps_expr, ps_major, ps_minor,
+ ps_args,
+ ps_prec,
+ ps_units,
+ ps_error}
+ pstate;
+ epicsEnum16 stat;
+ epicsEnum16 sevr;
+ short prec;
+ char *post_expr;
+ char *post_major;
+ char *post_minor;
+ char *units;
+ struct link inp[CALCPERFORM_NARGS];
+ double arg[CALCPERFORM_NARGS];
+ double val;
+} calc_link;
+
+static lset lnkCalc_lset;
+
+
+/*************************** jlif Routines **************************/
+
+static jlink* lnkCalc_alloc(short dbfType) {
+ calc_link *clink = calloc(1, sizeof(struct calc_link));
+
+ IFDEBUG(10)
+ printf("lnkCalc_alloc()\n");
+
+ clink->nArgs = 0;
+ clink->pstate = ps_init;
+ clink->prec = 15; /* standard value for a double */
+
+ IFDEBUG(10)
+ printf("lnkCalc_alloc -> calc@%p\n", clink);
+
+ return &clink->jlink;
+}
+
+static void lnkCalc_free(jlink *pjlink) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+ int i;
+
+ IFDEBUG(10)
+ printf("lnkCalc_free(calc@%p)\n", pjlink);
+
+ for (i = 0; i < clink->nArgs; i++)
+ dbJLinkFree(clink->inp[i].value.json.jlink);
+
+ free(clink->post_expr);
+ free(clink->post_major);
+ free(clink->post_minor);
+ free(clink->units);
+ free(clink);
+}
+
+static jlif_result lnkCalc_integer(jlink *pjlink, long num) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_integer(calc@%p, %ld)\n", pjlink, num);
+
+ if (clink->pstate == ps_prec) {
+ clink->prec = num;
+ return jlif_continue;
+ }
+
+ if (clink->pstate != ps_args) {
+ return jlif_stop;
+ errlogPrintf("lnkCalc: Unexpected integer %ld\n", num);
+ }
+
+ if (clink->nArgs == CALCPERFORM_NARGS) {
+ errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
+ CALCPERFORM_NARGS);
+ return jlif_stop;
+ }
+
+ clink->arg[clink->nArgs++] = num;
+
+ return jlif_continue;
+}
+
+static jlif_result lnkCalc_double(jlink *pjlink, double num) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_double(calc@%p, %g)\n", pjlink, num);
+
+ if (clink->pstate != ps_args) {
+ return jlif_stop;
+ errlogPrintf("lnkCalc: Unexpected double %g\n", num);
+ }
+
+ if (clink->nArgs == CALCPERFORM_NARGS) {
+ errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
+ CALCPERFORM_NARGS);
+ return jlif_stop;
+ }
+
+ clink->arg[clink->nArgs++] = num;
+
+ return jlif_continue;
+}
+
+static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+ char *inbuf, *postbuf;
+ short err;
+
+ IFDEBUG(10)
+ printf("lnkCalc_string(calc@%p, \"%.*s\")\n", clink, (int) len, val);
+
+ if (clink->pstate == ps_units) {
+ clink->units = epicsStrnDup(val, len);
+ return jlif_continue;
+ }
+
+ if (clink->pstate < ps_expr || clink->pstate > ps_minor) {
+ errlogPrintf("lnkCalc: Unexpected string \"%.*s\"\n", (int) len, val);
+ return jlif_stop;
+ }
+
+ postbuf = malloc(INFIX_TO_POSTFIX_SIZE(len));
+ if (!postbuf) {
+ errlogPrintf("lnkCalc: Out of memory\n");
+ return jlif_stop;
+ }
+
+ if (clink->pstate == ps_major)
+ clink->post_major = postbuf;
+ else if (clink->pstate == ps_minor)
+ clink->post_minor = postbuf;
+ else
+ clink->post_expr = postbuf;
+
+ inbuf = dbmfStrndup(val, len);
+
+ if (postfix(inbuf, postbuf, &err) < 0) {
+ errlogPrintf("lnkCalc: Error in calc expression, %s\n",
+ calcErrorStr(err));
+ dbmfFree(inbuf);
+ return jlif_stop;
+ }
+
+ dbmfFree(inbuf);
+ return jlif_continue;
+}
+
+static jlif_key_result lnkCalc_start_map(jlink *pjlink) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_start_array(calc@%p)\n", pjlink);
+
+ if (clink->pstate == ps_args)
+ return jlif_key_child_link;
+
+ if (clink->pstate != ps_init) {
+ errlogPrintf("lnkCalc: Unexpected map\n");
+ return jlif_stop;
+ }
+
+ return jlif_continue;
+}
+
+static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n",
+ pjlink, (int) len, key);
+
+ if (len == 4) {
+ if (!strncmp(key, "expr", len) && !clink->post_expr)
+ clink->pstate = ps_expr;
+ else if (!strncmp(key, "args", len) && !clink->nArgs)
+ clink->pstate = ps_args;
+ else if (!strncmp(key, "prec", len))
+ clink->pstate = ps_prec;
+ else {
+ errlogPrintf("lnkCalc: Unknown key \"%.4s\"\n", key);
+ return jlif_stop;
+ }
+ }
+ else if (len == 5) {
+ if (!strncmp(key, "major", len) && !clink->post_major)
+ clink->pstate = ps_major;
+ else if (!strncmp(key, "minor", len) && !clink->post_minor)
+ clink->pstate = ps_minor;
+ else if (!strncmp(key, "units", len) && !clink->units)
+ clink->pstate = ps_units;
+ else {
+ errlogPrintf("lnkCalc: Unknown key \"%.5s\"\n", key);
+ return jlif_stop;
+ }
+ }
+ else {
+ errlogPrintf("lnkCalc: Unknown key \"%.*s\"\n", (int) len, key);
+ return jlif_stop;
+ }
+
+ return jlif_continue;
+}
+
+static jlif_result lnkCalc_end_map(jlink *pjlink) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_end_array(calc@%p)\n", pjlink);
+
+ if (clink->pstate == ps_error)
+ return jlif_stop;
+
+ return jlif_continue;
+}
+
+static jlif_result lnkCalc_start_array(jlink *pjlink) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_start_array(calc@%p)\n", pjlink);
+
+ if (clink->pstate != ps_args) {
+ errlogPrintf("lnkCalc: Unexpected array\n");
+ return jlif_stop;
+ }
+
+ return jlif_continue;
+}
+
+static jlif_result lnkCalc_end_array(jlink *pjlink) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_end_array(calc@%p)\n", pjlink);
+
+ if (clink->pstate == ps_error)
+ return jlif_stop;
+
+ return jlif_continue;
+}
+
+static void lnkCalc_end_child(jlink *parent, jlink *child) {
+ calc_link *clink = CONTAINER(parent, struct calc_link, jlink);
+ struct link *plink;
+
+ if (clink->nArgs == CALCPERFORM_NARGS) {
+ dbJLinkFree(child);
+ errlogPrintf("lnkCalc: Too many input args, limit is %d\n",
+ CALCPERFORM_NARGS);
+ clink->pstate = ps_error;
+ return;
+ }
+
+ plink = &clink->inp[clink->nArgs++];
+ plink->type = JSON_LINK;
+ plink->value.json.string = NULL;
+ plink->value.json.jlink = child;
+}
+
+static struct lset* lnkCalc_get_lset(const jlink *pjlink) {
+ IFDEBUG(10)
+ printf("lnkCalc_get_lset(calc@%p)\n", pjlink);
+
+ return &lnkCalc_lset;
+}
+
+static void lnkCalc_report(const jlink *pjlink) {
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_report(calc@%p)\n", clink);
+
+ /* FIXME Implement! */
+}
+
+/*************************** lset Routines **************************/
+
+static void lnkCalc_open(struct link *plink)
+{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+ int i;
+
+ IFDEBUG(10)
+ printf("lnkCalc_open(calc@%p)\n", clink);
+
+ for (i = 0; i < clink->nArgs; i++) {
+ struct link *child = &clink->inp[i];
+
+ child->precord = plink->precord;
+ dbJLinkInit(child);
+ }
+}
+
+static void lnkCalc_remove(struct dbLocker *locker, struct link *plink)
+{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+ int i;
+
+ IFDEBUG(10)
+ printf("lnkCalc_remove(calc@%p)\n", clink);
+
+ for (i = 0; i < clink->nArgs; i++) {
+ struct link *child = &clink->inp[i];
+
+ dbRemoveLink(locker, child);
+ }
+
+ free(clink->post_expr);
+ free(clink->post_major);
+ free(clink->post_minor);
+ free(clink->units);
+ free(clink);
+ plink->value.json.jlink = NULL;
+}
+
+static int lnkCalc_isConn(const struct link *plink)
+{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+ int connected = 1;
+ int i;
+
+ IFDEBUG(10)
+ printf("lnkCalc_isConn(calc@%p)\n", clink);
+
+ for (i = 0; i < clink->nArgs; i++) {
+ struct link *child = &clink->inp[i];
+
+ if (dbLinkIsVolatile(child) > 0 &&
+ !dbIsLinkConnected(child))
+ connected = 0;
+ }
+
+ return connected;
+}
+
+static int lnkCalc_getDBFtype(const struct link *plink)
+{
+ IFDEBUG(10) {
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+
+ printf("lnkCalc_getDBFtype(calc@%p)\n", clink);
+ }
+
+ return DBF_DOUBLE;
+}
+
+static long lnkCalc_getElements(const struct link *plink, long *nelements)
+{
+ IFDEBUG(10) {
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+
+ printf("lnkCalc_getElements(calc@%p, (%ld))\n",
+ clink, *nelements);
+ }
+
+ *nelements = 1;
+ return 0;
+}
+
+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);
+ int i;
+ long status;
+ FASTCONVERT conv = dbFastPutConvertRoutine[DBR_DOUBLE][dbrType];
+
+ IFDEBUG(10)
+ printf("lnkCalc_getValue(calc@%p, %d, ...)\n",
+ clink, dbrType);
+
+ 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);
+ }
+ clink->stat = 0;
+ clink->sevr = 0;
+
+ if (clink->post_expr) {
+ status = calcPerform(clink->arg, &clink->val, clink->post_expr);
+ if (!status)
+ status = conv(&clink->val, pbuffer, NULL);
+ if (!status && pnRequest)
+ *pnRequest = 1;
+ }
+ else {
+ status = 0;
+ if (pnRequest)
+ *pnRequest = 0;
+ }
+
+ if (!status && clink->post_major) {
+ double alval = clink->val;
+
+ status = calcPerform(clink->arg, &alval, clink->post_major);
+ if (!status && alval) {
+ clink->stat = LINK_ALARM;
+ clink->sevr = MAJOR_ALARM;
+ recGblSetSevr(plink->precord, clink->stat, clink->sevr);
+ }
+ }
+
+ if (!status && clink->post_minor) {
+ double alval = clink->val;
+
+ status = calcPerform(clink->arg, &alval, clink->post_minor);
+ if (!status && alval) {
+ clink->stat = LINK_ALARM;
+ clink->sevr = MINOR_ALARM;
+ recGblSetSevr(plink->precord, clink->stat, clink->sevr);
+ }
+ }
+
+ return status;
+}
+
+static long lnkCalc_getPrecision(const struct link *plink, short *precision)
+{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_getPrecision(calc@%p)\n", clink);
+
+ *precision = clink->prec;
+ return 0;
+}
+
+static long lnkCalc_getUnits(const struct link *plink, char *units, int len)
+{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_getUnits(calc@%p)\n", clink);
+
+ if (clink->units) {
+ strncpy(units, clink->units, --len);
+ units[len] = '\0';
+ }
+ else
+ units[0] = '\0';
+ return 0;
+}
+
+static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
+ epicsEnum16 *severity)
+{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+
+ IFDEBUG(10)
+ printf("lnkCalc_getAlarm(calc@%p)\n", clink);
+
+ if (status)
+ *status = clink->stat;
+ if (severity)
+ *severity = clink->sevr;
+
+ return 0;
+}
+
+
+/************************* Interface Tables *************************/
+
+static lset lnkCalc_lset = {
+ 0, 1, /* not Constant, Volatile */
+ lnkCalc_open, lnkCalc_remove,
+ NULL, NULL, NULL,
+ lnkCalc_isConn, lnkCalc_getDBFtype, lnkCalc_getElements,
+ lnkCalc_getValue,
+ NULL, NULL, NULL,
+ lnkCalc_getPrecision, lnkCalc_getUnits,
+ lnkCalc_getAlarm, NULL,
+ NULL, NULL,
+ NULL
+};
+
+static jlif lnkCalcIf = {
+ "calc", lnkCalc_alloc, lnkCalc_free,
+ NULL, NULL, lnkCalc_integer, lnkCalc_double, lnkCalc_string,
+ lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map,
+ lnkCalc_start_array, lnkCalc_end_array,
+ lnkCalc_end_child, lnkCalc_get_lset, lnkCalc_report
+};
+epicsExportAddress(jlif, lnkCalcIf);
+
From f8d6cd98a0bda174906c677d68e70f930ce821dc Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 19:44:49 -0500
Subject: [PATCH 049/112] Minor cleanups
---
src/std/link/links.dbd.pod | 6 +++---
src/std/link/lnkCalc.c | 7 ++++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
index 9cff283d0..facfb9106 100644
--- a/src/std/link/links.dbd.pod
+++ b/src/std/link/links.dbd.pod
@@ -132,15 +132,15 @@ numeric literal or an embedded link inside C<{}> braces.
An optional string specifying the engineering units for the result of the
expression. Equivalent to the C field of a record.
-item prec
+=item prec
An optional integer specifying the numeric precision with which the calculation
-result should be displayed. Equivalent to the E field of a record.
+result should be displayed. Equivalent to the C field of a record.
=back
=head4 Example
- {calc: {expr:"A+B", args:[1, 2]}}
+ {calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5]}}
=cut
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 015dd0311..6544898e4 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -45,13 +45,14 @@ typedef long (*FASTCONVERT)();
typedef struct calc_link {
jlink jlink; /* embedded object */
int nArgs;
- enum {ps_init,
+ enum {
+ ps_init,
ps_expr, ps_major, ps_minor,
ps_args,
ps_prec,
ps_units,
- ps_error}
- pstate;
+ ps_error
+ } pstate;
epicsEnum16 stat;
epicsEnum16 sevr;
short prec;
From 25315882ec006b3ad652737c1afa5ed5fc5b443e Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 22:22:12 -0500
Subject: [PATCH 050/112] Clean up JSON_LINKs in doCloseLinks
---
src/ioc/misc/iocInit.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c
index f863e3fe9..30854c3bf 100644
--- a/src/ioc/misc/iocInit.c
+++ b/src/ioc/misc/iocInit.c
@@ -637,17 +637,15 @@ static void doCloseLinks(dbRecordType *pdbRecordType, dbCommon *precord,
pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
- if (plink->type == CA_LINK) {
+ if (plink->type == CA_LINK ||
+ plink->type == JSON_LINK ||
+ (plink->type == DB_LINK && iocBuildMode == buildIsolated)) {
if (!locked) {
dbScanLock(precord);
locked = 1;
}
dbRemoveLink(NULL, plink);
}
- else if (iocBuildMode==buildIsolated && plink->type == DB_LINK) {
- /* free link, but don't split lockset */
- dbRemoveLink(NULL, plink);
- }
}
if (precord->dset &&
From 4302da36281ecac0a01c8175ead4401eea65493e Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 3 Sep 2016 22:24:55 -0500
Subject: [PATCH 051/112] Minor fixes to the calc link-type
---
src/std/link/links.dbd.pod | 7 ++++---
src/std/link/lnkCalc.c | 8 +++++---
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
index facfb9106..8ae5c3f56 100644
--- a/src/std/link/links.dbd.pod
+++ b/src/std/link/links.dbd.pod
@@ -101,7 +101,7 @@ link(calc, lnkCalcIf)
Calculation links can perform simple mathematical expressions on scalar
(double-precision floating-point) values obtained from other link types and
return a single double-precision floating-point result. The expressions are
-evaluated by the EPICS Calc engine, and up to 12 input links can be used.
+evaluated by the EPICS Calc engine, and up to 12 inputs can be provided.
=head4 Parameters
@@ -111,7 +111,7 @@ The link value is a map with the following keys:
=item expr
-The expression to be evaluated, provided as a string.
+The primary expression to be evaluated, provided as a string.
=item major
@@ -125,7 +125,8 @@ An optional expression that returns non-zero to raise a minor alarm.
A JSON list of up to 12 input arguments for the expression, which are assigned
to the inputs C, C, C, ... C. Each input argument may be either a
-numeric literal or an embedded link inside C<{}> braces.
+numeric literal or an embedded JSON link inside C<{}> braces. The same input
+values are provided to the two alarm expressions as to the primary expression.
=item units
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 6544898e4..b596471aa 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -31,7 +31,7 @@
typedef long (*FASTCONVERT)();
/* Change 'undef' to 'define' to turn on debug statements: */
-#define DEBUG_LINK
+#undef DEBUG_LINK
#ifdef DEBUG_LINK
int lnkCalcDebug = 10;
@@ -200,7 +200,7 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_start_array(calc@%p)\n", pjlink);
+ printf("lnkCalc_start_map(calc@%p)\n", pjlink);
if (clink->pstate == ps_args)
return jlif_key_child_link;
@@ -256,7 +256,7 @@ static jlif_result lnkCalc_end_map(jlink *pjlink) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_end_array(calc@%p)\n", pjlink);
+ printf("lnkCalc_end_map(calc@%p)\n", pjlink);
if (clink->pstate == ps_error)
return jlif_stop;
@@ -340,6 +340,7 @@ static void lnkCalc_open(struct link *plink)
child->precord = plink->precord;
dbJLinkInit(child);
+ dbLoadLink(child, DBR_DOUBLE, &clink->arg[i]);
}
}
@@ -431,6 +432,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
long nReq = 1;
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
+ /* FIXME Should we look at the return status from dbGetLink? */
}
clink->stat = 0;
clink->sevr = 0;
From ec6d86c91c7e6bf32f7326dbe394709a0fadb384 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 4 Sep 2016 15:56:39 -0500
Subject: [PATCH 052/112] Fix jlink memory leak in dbStaticLib
Added dbFreeLinkInfo(), use everywhere to release dbLinkInfo resources.
Renamed link_type => expected_type in db[Can]SetLink(),
my brain understands this name faster.
---
src/ioc/dbStatic/dbStaticLib.c | 54 ++++++++++++++++++----------------
1 file changed, 29 insertions(+), 25 deletions(-)
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index 62527c693..89ab96d36 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2235,6 +2235,17 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
return 0;
}
+static
+void dbFreeLinkInfo(dbLinkInfo *pinfo)
+{
+ if (pinfo->ltype == JSON_LINK) {
+ dbJLinkFree(pinfo->jlink);
+ pinfo->jlink = NULL;
+ }
+ free(pinfo->target);
+ pinfo->target = NULL;
+}
+
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
{
char *pstr;
@@ -2326,12 +2337,9 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* RF_IO, the string isn't needed at all */
free(pinfo->target);
pinfo->target = NULL;
- } else {
- /* missing parm when required, or found parm when not expected */
- free(pinfo->target);
- pinfo->target = NULL;
- return S_dbLib_badField;
}
+ else goto fail;
+
return 0;
}
@@ -2380,29 +2388,28 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
return 0;
fail:
- free(pinfo->target);
+ dbFreeLinkInfo(pinfo);
return S_dbLib_badField;
}
long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
{
- /* consume allocated string pinfo->target on failure */
- int link_type = CONSTANT;
+ /* Release pinfo resources on failure */
+ int expected_type = devsup ? devsup->link_type : CONSTANT;
- if (devsup)
- link_type = devsup->link_type;
- if (link_type == pinfo->ltype)
+ if (pinfo->ltype == expected_type)
return 0;
switch (pinfo->ltype) {
case CONSTANT:
case JSON_LINK:
case PV_LINK:
- if (link_type == CONSTANT || link_type == PV_LINK)
+ if (expected_type == CONSTANT ||
+ expected_type == JSON_LINK ||
+ expected_type == PV_LINK)
return 0;
default:
- free(pinfo->target);
- pinfo->target = NULL;
+ dbFreeLinkInfo(pinfo);
return 1;
}
}
@@ -2519,13 +2526,11 @@ void dbSetLinkHW(DBLINK *plink, dbLinkInfo *pinfo)
long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
{
- int ret = 0;
- int link_type = CONSTANT;
+ int expected_type = devsup ? devsup->link_type : CONSTANT;
- if (devsup)
- link_type = devsup->link_type;
-
- if (link_type == CONSTANT || link_type == PV_LINK) {
+ if (expected_type == CONSTANT ||
+ expected_type == JSON_LINK ||
+ expected_type == PV_LINK) {
switch (pinfo->ltype) {
case CONSTANT:
dbFreeLinkContents(plink);
@@ -2544,17 +2549,16 @@ long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
goto fail; /* can't assign HW link */
}
}
- else if (link_type == pinfo->ltype) {
+ else if (expected_type == pinfo->ltype) {
dbFreeLinkContents(plink);
dbSetLinkHW(plink, pinfo);
}
else
goto fail;
- return ret;
+ return 0;
fail:
- free(pinfo->target);
- pinfo->target = NULL;
+ dbFreeLinkInfo(pinfo);
return S_dbLib_badField;
}
@@ -2620,7 +2624,7 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
/* links not yet initialized by dbInitRecordLinks() */
free(plink->text);
plink->text = epicsStrDup(pstring);
- free(link_info.target);
+ dbFreeLinkInfo(&link_info);
} else {
/* assignment after init (eg. autosave restore) */
struct dbCommon *prec = pdbentry->precnode->precord;
From 4448317d739af22cb5a83ab5f4734621de1733e6 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 4 Sep 2016 16:02:59 -0500
Subject: [PATCH 053/112] Add lnkConst_remove, fix debug messages
---
src/std/link/lnkCalc.c | 17 ++++++++---------
src/std/link/lnkConst.c | 14 ++++++++++++--
2 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index b596471aa..58f10a20d 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -91,7 +91,7 @@ static void lnkCalc_free(jlink *pjlink) {
int i;
IFDEBUG(10)
- printf("lnkCalc_free(calc@%p)\n", pjlink);
+ printf("lnkCalc_free(calc@%p)\n", clink);
for (i = 0; i < clink->nArgs; i++)
dbJLinkFree(clink->inp[i].value.json.jlink);
@@ -107,7 +107,7 @@ static jlif_result lnkCalc_integer(jlink *pjlink, long num) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_integer(calc@%p, %ld)\n", pjlink, num);
+ printf("lnkCalc_integer(calc@%p, %ld)\n", clink, num);
if (clink->pstate == ps_prec) {
clink->prec = num;
@@ -134,7 +134,7 @@ static jlif_result lnkCalc_double(jlink *pjlink, double num) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_double(calc@%p, %g)\n", pjlink, num);
+ printf("lnkCalc_double(calc@%p, %g)\n", clink, num);
if (clink->pstate != ps_args) {
return jlif_stop;
@@ -200,7 +200,7 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_start_map(calc@%p)\n", pjlink);
+ printf("lnkCalc_start_map(calc@%p)\n", clink);
if (clink->pstate == ps_args)
return jlif_key_child_link;
@@ -217,8 +217,7 @@ static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n",
- pjlink, (int) len, key);
+ printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n", pjlink, (int) len, key);
if (len == 4) {
if (!strncmp(key, "expr", len) && !clink->post_expr)
@@ -256,7 +255,7 @@ static jlif_result lnkCalc_end_map(jlink *pjlink) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_end_map(calc@%p)\n", pjlink);
+ printf("lnkCalc_end_map(calc@%p)\n", clink);
if (clink->pstate == ps_error)
return jlif_stop;
@@ -268,7 +267,7 @@ static jlif_result lnkCalc_start_array(jlink *pjlink) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_start_array(calc@%p)\n", pjlink);
+ printf("lnkCalc_start_array(calc@%p)\n", clink);
if (clink->pstate != ps_args) {
errlogPrintf("lnkCalc: Unexpected array\n");
@@ -282,7 +281,7 @@ static jlif_result lnkCalc_end_array(jlink *pjlink) {
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_end_array(calc@%p)\n", pjlink);
+ printf("lnkCalc_end_array(calc@%p)\n", clink);
if (clink->pstate == ps_error)
return jlif_stop;
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 4ff3ed2bc..3dc08051f 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -278,6 +278,16 @@ static void lnkConst_report(const jlink *pjlink) {
/*************************** lset Routines **************************/
+static void lnkConst_remove(struct dbLocker *locker, struct link *plink)
+{
+ clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+
+ IFDEBUG(10)
+ printf("lnkConst_remove(const@%p)\n", clink);
+
+ lnkConst_free(plink->value.json.jlink);
+}
+
static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer)
{
clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
@@ -438,7 +448,7 @@ static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
IFDEBUG(10)
- printf("lnkConst_loadScalar(const@%p, %d, %p, ... (%ld))\n",
+ printf("lnkConst_getValue(const@%p, %d, %p, ... (%ld))\n",
plink->value.json.jlink, dbrType, pbuffer, *pnRequest);
if (pnRequest)
@@ -451,7 +461,7 @@ static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
static lset lnkConst_lset = {
1, 0, /* Constant, not Volatile */
- NULL, NULL,
+ NULL, lnkConst_remove,
lnkConst_loadScalar, lnkConst_loadLS, lnkConst_loadArray, NULL,
NULL, lnkConst_getNelements, lnkConst_getValue,
NULL, NULL, NULL,
From dd311be3192992b4a4bbc226b335420442b1c667 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 4 Sep 2016 16:33:10 -0500
Subject: [PATCH 054/112] JLink: Convert parser->linkDepth into
jlink->parseDepth
This counter is indicates when we've finished parsing a link,
and needs to be stored with link rather than the parser so it
keeps its value while parsing embedded links. This fixes the
embedded links bug.
Also removed the limit on a link name's length.
---
src/ioc/db/dbJLink.c | 99 +++++++++++++++++++++++---------------------
src/ioc/db/dbJLink.h | 4 +-
2 files changed, 52 insertions(+), 51 deletions(-)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index ec98fbccb..dc0048964 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -10,6 +10,7 @@
#include
#include "epicsAssert.h"
+#include "dbmf.h"
#include "errlog.h"
#include "yajl_alloc.h"
#include "yajl_parse.h"
@@ -40,22 +41,19 @@ typedef struct parseContext {
jlink *product;
short dbfType;
short jsonDepth;
- short linkDepth;
unsigned key_is_link:1;
} parseContext;
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
-void dbJLinkFree(jlink *pjlink) {
- if (pjlink)
- pjlink->pif->free_jlink(pjlink);
-}
-
static int dbjl_return(parseContext *parser, jlif_result result) {
jlink *pjlink = parser->pjlink;
- IFDEBUG(10)
- printf("dbjl_return(%s@%p, %d)\n", pjlink->pif->name, pjlink, result);
+ IFDEBUG(10) {
+ printf("dbjl_return(%s@%p, %d)\t", pjlink->pif->name, pjlink, result);
+ printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
+ }
if (result == jlif_stop && pjlink) {
jlink *parent;
@@ -75,12 +73,12 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
jlink *parent;
IFDEBUG(10) {
- printf("dbjl_value(%s@%p, %d)\n", pjlink->pif->name, pjlink, result);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf("dbjl_value(%s@%p, %d)\t", pjlink->pif->name, pjlink, result);
+ printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
}
- if (result == jlif_stop || parser->linkDepth > 0)
+ if (result == jlif_stop || pjlink->parseDepth > 0)
return dbjl_return(parser, result);
parent = pjlink->parent;
@@ -164,9 +162,9 @@ static int dbjl_start_map(void *ctx) {
if (!pjlink) {
IFDEBUG(10) {
- printf("dbjl_start_map(NULL)\n");
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf("dbjl_start_map(NULL)\t");
+ printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
+ parser->jsonDepth, parser->key_is_link);
}
assert(parser->jsonDepth == 0);
@@ -176,12 +174,12 @@ static int dbjl_start_map(void *ctx) {
}
IFDEBUG(10) {
- printf("dbjl_start_map(%s@%p)\n", pjlink->pif->name, pjlink);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf("dbjl_start_map(%s@%p)\t", pjlink->pif->name, pjlink);
+ printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
}
- parser->linkDepth++;
+ pjlink->parseDepth++;
parser->jsonDepth++;
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
@@ -199,8 +197,7 @@ static int dbjl_start_map(void *ctx) {
static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
- char link_name[MAX_LINK_NAME + 1];
- size_t lnlen = len;
+ char *link_name;
linkSup *linkSup;
jlif *pjlif;
@@ -212,33 +209,31 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
}
IFDEBUG(10) {
- printf("dbjl_map_key(%s@%p, \"%.*s\")\n",
+ printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
pjlink->pif->name, pjlink, len, key);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
}
- assert(parser->linkDepth > 0);
+ assert(pjlink->parseDepth > 0);
return dbjl_return(parser,
CALL_OR_STOP(pjlink->pif->parse_map_key)(pjlink,
(const char *) key, len));
}
IFDEBUG(10) {
- printf("dbjl_map_key(NULL, \"%.*s\")\n", len, key);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf("dbjl_map_key(NULL, \"%.*s\")\t", len, key);
+ printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
+ parser->jsonDepth, parser->key_is_link);
}
- if (lnlen > MAX_LINK_NAME)
- lnlen = MAX_LINK_NAME;
- strncpy(link_name, (const char *) key, lnlen);
- link_name[lnlen] = '\0';
+ link_name = dbmfStrndup((const char *) key, len);
linkSup = dbFindLinkSup(pdbbase, link_name);
if (!linkSup) {
errlogPrintf("dbJLinkInit: Link type '%s' not found\n",
link_name);
+ dbmfFree(link_name);
return dbjl_return(parser, jlif_stop);
}
@@ -246,9 +241,12 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
if (!pjlif) {
errlogPrintf("dbJLinkInit: Support for Link type '%s' not loaded\n",
link_name);
+ dbmfFree(link_name);
return dbjl_return(parser, jlif_stop);
}
+ dbmfFree(link_name);
+
pjlink = pjlif->alloc_jlink(parser->dbfType);
if (!pjlink) {
errlogPrintf("dbJLinkInit: Out of memory\n");
@@ -275,15 +273,16 @@ static int dbjl_end_map(void *ctx) {
jlif_result result;
IFDEBUG(10) {
- printf("dbjl_end_map(%s@%p)\n",
+ printf("dbjl_end_map(%s@%p)\t",
pjlink ? pjlink->pif->name : "NULL", pjlink);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, pjlink ? pjlink->parseDepth : 0,
+ parser->key_is_link);
}
parser->jsonDepth--;
- if (parser->linkDepth > 0) {
- parser->linkDepth--;
+ if (pjlink) {
+ pjlink->parseDepth--;
result = dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_end_map)(pjlink));
@@ -299,13 +298,13 @@ static int dbjl_start_array(void *ctx) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
- printf("dbjl_start_array(%s@%p)\n", pjlink->pif->name, pjlink);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf("dbjl_start_array(%s@%p)\t", pjlink->pif->name, pjlink);
+ printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
}
assert(pjlink);
- parser->linkDepth++;
+ pjlink->parseDepth++;
parser->jsonDepth++;
return dbjl_return(parser,
@@ -317,13 +316,13 @@ static int dbjl_end_array(void *ctx) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
- printf("dbjl_end_array(%s@%p)\n", pjlink->pif->name, pjlink);
- printf(" jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf("dbjl_end_array(%s@%p)\t", pjlink->pif->name, pjlink);
+ printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
}
assert(pjlink);
- parser->linkDepth--;
+ pjlink->parseDepth--;
parser->jsonDepth--;
return dbjl_value(parser,
@@ -356,12 +355,11 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
parser->product = NULL;
parser->dbfType = dbfType;
parser->jsonDepth = 0;
- parser->linkDepth = 0;
parser->key_is_link = 0;
IFDEBUG(10)
- printf("dbJLinkInit: jsonDepth=%d, linkDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, parser->linkDepth, parser->key_is_link);
+ printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n",
+ parser->jsonDepth, parser->key_is_link);
yajl_set_default_alloc_funcs(&dbjl_allocs);
yh = yajl_alloc(&dbjl_callbacks, &dbjl_config, &dbjl_allocs, parser);
@@ -407,3 +405,8 @@ long dbJLinkInit(struct link *plink)
dbLinkOpen(plink);
return 0;
}
+
+void dbJLinkFree(jlink *pjlink) {
+ if (pjlink)
+ pjlink->pif->free_jlink(pjlink);
+}
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index fff8b7fe1..07c07bcd4 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -12,9 +12,6 @@
#include
#include
-/* Limit for link name key length */
-#define MAX_LINK_NAME 15
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -37,6 +34,7 @@ struct jlif;
typedef struct jlink {
struct jlif *pif;
struct jlink *parent;
+ int parseDepth;
/* Link types extend or embed this structure for private storage */
} jlink;
From 19447dc7ffc598f72f74a329b5ee13f81eabdc29 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 4 Sep 2016 16:56:15 -0500
Subject: [PATCH 055/112] Make the long-string buffer for link fields bigger
When representing a link field as a long string (.INP$)
we have to pick some size limit for the buffer.
Previously this was the max length of a PV name + 12 chars,
but with JSON links that's not big enough.
This commit sets it to 1KB and defines a macro so it will be
easier to change in the future if necessary.
---
src/ioc/db/dbAccess.c | 2 +-
src/ioc/db/dbChannel.c | 2 +-
src/libCom/misc/dbDefs.h | 4 ++++
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c
index ff94a5b53..a4ba42b89 100644
--- a/src/ioc/db/dbAccess.c
+++ b/src/ioc/db/dbAccess.c
@@ -657,7 +657,7 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
- paddr->no_elements = PVNAME_STRINGSZ + 12;
+ paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
diff --git a/src/ioc/db/dbChannel.c b/src/ioc/db/dbChannel.c
index 6e08f3c19..bf2b3d438 100644
--- a/src/ioc/db/dbChannel.c
+++ b/src/ioc/db/dbChannel.c
@@ -531,7 +531,7 @@ dbChannel * dbChannelCreate(const char *name)
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
- paddr->no_elements = PVNAME_STRINGSZ + 12;
+ paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
diff --git a/src/libCom/misc/dbDefs.h b/src/libCom/misc/dbDefs.h
index 069d55c1a..e8c2bb265 100644
--- a/src/libCom/misc/dbDefs.h
+++ b/src/libCom/misc/dbDefs.h
@@ -60,6 +60,10 @@
#define PVNAME_STRINGSZ 61
#define PVNAME_SZ (PVNAME_STRINGSZ - 1)
+/* Buffer size for the string representation of a DBF_*LINK field */
+#define PVLINK_STRINGSZ 1024
+
+/* dbAccess enums/menus can have up to this many choices */
#define DB_MAX_CHOICES 30
#endif /* INC_dbDefs_H */
From cd49e245c23d7fe06aeb5a5b5fa7900436c88313 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 5 Sep 2016 14:25:33 -0500
Subject: [PATCH 056/112] Added JLink reporting infrastructure
Command 'dbjlr ' calls the report method for
all JSON links in all records, or in one named record.
Added level and indent arguments to the jlif::report() method.
Added jlif::map_children() method for recursing through all
JSON links, plus dbJLinkMapChildren() and dbJLinkMapAll() APIs.
Implemented the report and map_children methods in the const
and calc link types.
---
src/ioc/db/dbIocRegister.c | 12 ++++
src/ioc/db/dbJLink.c | 130 ++++++++++++++++++++++++++++++++++++-
src/ioc/db/dbJLink.h | 69 ++++++++++++++++++--
src/std/link/lnkCalc.c | 117 +++++++++++++++++++++++++--------
src/std/link/lnkConst.c | 109 +++++++++++++++++++++++++++----
5 files changed, 394 insertions(+), 43 deletions(-)
diff --git a/src/ioc/db/dbIocRegister.c b/src/ioc/db/dbIocRegister.c
index 1a1aafb9a..07c9836c2 100644
--- a/src/ioc/db/dbIocRegister.c
+++ b/src/ioc/db/dbIocRegister.c
@@ -16,6 +16,7 @@
#include "dbCaTest.h"
#include "dbEvent.h"
#include "dbIocRegister.h"
+#include "dbJLink.h"
#include "dbLock.h"
#include "dbNotify.h"
#include "dbScan.h"
@@ -109,6 +110,16 @@ static void dbcarCallFunc(const iocshArgBuf *args)
dbcar(args[0].sval,args[1].ival);
}
+/* dbjlr */
+static const iocshArg dbjlrArg0 = { "record name",iocshArgString};
+static const iocshArg dbjlrArg1 = { "level",iocshArgInt};
+static const iocshArg * const dbjlrArgs[2] = {&dbjlrArg0,&dbjlrArg1};
+static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs};
+static void dbjlrCallFunc(const iocshArgBuf *args)
+{
+ dbjlr(args[0].sval,args[1].ival);
+}
+
/* dbel */
static const iocshArg dbelArg0 = { "record name",iocshArgString};
static const iocshArg dbelArg1 = { "level",iocshArgInt};
@@ -395,6 +406,7 @@ void dbIocRegister(void)
iocshRegister(&dbsrFuncDef,dbsrCallFunc);
iocshRegister(&dbcarFuncDef,dbcarCallFunc);
iocshRegister(&dbelFuncDef,dbelCallFunc);
+ iocshRegister(&dbjlrFuncDef,dbjlrCallFunc);
iocshRegister(&dbLoadDatabaseFuncDef,dbLoadDatabaseCallFunc);
iocshRegister(&dbLoadRecordsFuncDef,dbLoadRecordsCallFunc);
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index dc0048964..7e84bda2a 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -11,6 +11,7 @@
#include "epicsAssert.h"
#include "dbmf.h"
+#include "dbStaticLib.h"
#include "errlog.h"
#include "yajl_alloc.h"
#include "yajl_parse.h"
@@ -20,6 +21,7 @@
#include "dbCommon.h"
#include "dbLink.h"
#include "dbJLink.h"
+#include "dbLock.h"
#include "dbStaticLib.h"
#include "link.h"
@@ -406,7 +408,133 @@ long dbJLinkInit(struct link *plink)
return 0;
}
-void dbJLinkFree(jlink *pjlink) {
+void dbJLinkFree(jlink *pjlink)
+{
if (pjlink)
pjlink->pif->free_jlink(pjlink);
}
+
+void dbJLinkReport(jlink *pjlink, int level, int indent) {
+ if (pjlink && pjlink->pif->report)
+ pjlink->pif->report(pjlink, level, indent);
+}
+
+long dbJLinkMapChildren(struct link *plink, jlink_map_fn rtn, void *ctx)
+{
+ jlink *pjlink;
+ long status;
+
+ if (!plink || plink->type != JSON_LINK)
+ return 0;
+
+ pjlink = plink->value.json.jlink;
+ if (!pjlink)
+ return 0;
+
+ status = rtn(pjlink, ctx);
+ if (!status && pjlink->pif->map_children)
+ status = pjlink->pif->map_children(pjlink, rtn, ctx);
+
+ return status;
+}
+
+long dbjlr(const char *recname, int level)
+{
+ DBENTRY dbentry;
+ DBENTRY * const pdbentry = &dbentry;
+ long status;
+
+ if (!recname || recname[0] == '\0' || !strcmp(recname, "*")) {
+ recname = NULL;
+ printf("JSON links in all records\n\n");
+ }
+ else
+ printf("JSON links in record '%s'\n\n", recname);
+
+ dbInitEntry(pdbbase, pdbentry);
+ for (status = dbFirstRecordType(pdbentry);
+ status == 0;
+ status = dbNextRecordType(pdbentry)) {
+ for (status = dbFirstRecord(pdbentry);
+ status == 0;
+ status = dbNextRecord(pdbentry)) {
+ dbRecordType *pdbRecordType = pdbentry->precordType;
+ dbCommon *precord = pdbentry->precnode->precord;
+ char *prec = (char *) precord;
+ int i;
+
+ if (recname && strcmp(recname, dbGetRecordName(pdbentry)))
+ continue;
+ if (dbIsAlias(pdbentry))
+ continue;
+
+ printf(" %s record '%s':\n", pdbRecordType->name, precord->name);
+
+ dbScanLock(precord);
+ for (i = 0; i < pdbRecordType->no_links; i++) {
+ int idx = pdbRecordType->link_ind[i];
+ dbFldDes *pdbFldDes = pdbRecordType->papFldDes[idx];
+ DBLINK *plink = (DBLINK *) (prec + pdbFldDes->offset);
+
+ if (plink->type != JSON_LINK)
+ continue;
+ if (!dbLinkIsDefined(plink))
+ continue;
+
+ printf(" Link field '%s':\n", pdbFldDes->name);
+ dbJLinkReport(plink->value.json.jlink, level, 6);
+ }
+ dbScanUnlock(precord);
+ if (recname)
+ goto done;
+ }
+ }
+done:
+ return 0;
+}
+
+long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx)
+{
+ DBENTRY dbentry;
+ DBENTRY * const pdbentry = &dbentry;
+ long status;
+
+ if (recname && (recname[0] = '\0' || !strcmp(recname, "*")))
+ recname = NULL;
+
+ dbInitEntry(pdbbase, pdbentry);
+ for (status = dbFirstRecordType(pdbentry);
+ status == 0;
+ status = dbNextRecordType(pdbentry)) {
+ for (status = dbFirstRecord(pdbentry);
+ status == 0;
+ status = dbNextRecord(pdbentry)) {
+ dbRecordType *pdbRecordType = pdbentry->precordType;
+ dbCommon *precord = pdbentry->precnode->precord;
+ char *prec = (char *) precord;
+ int i;
+
+ if (recname && strcmp(recname, dbGetRecordName(pdbentry)))
+ continue;
+ if (dbIsAlias(pdbentry))
+ continue;
+
+ dbScanLock(precord);
+ for (i = 0; i < pdbRecordType->no_links; i++) {
+ int idx = pdbRecordType->link_ind[i];
+ dbFldDes *pdbFldDes = pdbRecordType->papFldDes[idx];
+ DBLINK *plink = (DBLINK *) (prec + pdbFldDes->offset);
+
+ status = dbJLinkMapChildren(plink, rtn, ctx);
+ if (status)
+ goto unlock;
+ }
+unlock:
+ dbScanUnlock(precord);
+ if (status || recname)
+ goto done;
+ }
+ }
+done:
+ return status;
+}
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index 07c07bcd4..38476b1fd 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -32,29 +32,83 @@ struct lset;
struct jlif;
typedef struct jlink {
- struct jlif *pif;
- struct jlink *parent;
- int parseDepth;
+ struct jlif *pif; /* Link methods */
+ struct jlink *parent; /* NULL for top-level links */
+ int parseDepth; /* Used by parser, unused afterwards */
/* Link types extend or embed this structure for private storage */
} jlink;
+typedef long (*jlink_map_fn)(jlink *, void *ctx);
+
typedef struct jlif {
+ /* Optional parser methods below given as NULL are equivalent to
+ * providing a routine that always returns jlif_stop, meaning that
+ * this JSON construct is not allowed at this point in the parse.
+ */
+
const char *name;
+ /* Name for the link type, used in link value */
+
jlink* (*alloc_jlink)(short dbfType);
+ /* Required, allocate new link structure */
+
void (*free_jlink)(jlink *);
+ /* Required, release all resources allocated for link */
+
jlif_result (*parse_null)(jlink *);
+ /* Optional, parser saw a null value */
+
jlif_result (*parse_boolean)(jlink *, int val);
+ /* Optional, parser saw a boolean value */
+
jlif_result (*parse_integer)(jlink *, long num);
+ /* Optional, parser saw an integer value */
+
jlif_result (*parse_double)(jlink *, double num);
+ /* Optional, parser saw a double value */
+
jlif_result (*parse_string)(jlink *, const char *val, size_t len);
+ /* Optional, parser saw a string value */
+
jlif_key_result (*parse_start_map)(jlink *);
+ /* Optional, parser saw an open-brace '{'. Return jlif_key_child_link
+ * to expect a child link next (extra key/value pairs may follow).
+ */
+
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
+ /* Optional, parser saw a map key */
+
jlif_result (*parse_end_map)(jlink *);
+ /* Optional, parser saw a close-brace '}' */
+
jlif_result (*parse_start_array)(jlink *);
+ /* Optional, parser saw an open-bracket */
+
jlif_result (*parse_end_array)(jlink *);
+ /* Optional, parser saw a close-bracket */
+
void (*end_child)(jlink *parent, jlink *child);
+ /* Optional, called with pointer to the new child link after
+ * parse_start_map() returned jlif_key_child_link */
+
struct lset* (*get_lset)(const jlink *);
- void (*report)(const jlink *);
+ /* Required, return lset for this link instance */
+
+ void (*report)(const jlink *, int level, int indent);
+ /* Optional, print status information about this link instance, then
+ * if (level > 0) print a link identifier (at indent+2) and call
+ * dbJLinkReport(child, level-1, indent+4)
+ * for each child.
+ */
+
+ long (*map_children)(jlink *, jlink_map_fn rtn, void *ctx);
+ /* Optional, call dbJLinkMapChildren() on all embedded links.
+ * Stop immediately and return status if non-zero.
+ */
+
+ /* Link types must NOT extend this table with their own routines,
+ * this space is reserved for extensions to the jlink interface.
+ */
} jlif;
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
@@ -62,6 +116,13 @@ epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
epicsShareFunc long dbJLinkInit(struct link *plink);
epicsShareFunc void dbJLinkFree(jlink *);
+epicsShareFunc void dbJLinkReport(jlink *, int level, int indent);
+
+epicsShareFunc long dbJLinkMapChildren(struct link *,
+ jlink_map_fn rtn, void *ctx);
+
+epicsShareFunc long dbjlr(const char *recname, int level);
+epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx);
#ifdef __cplusplus
}
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 58f10a20d..545be430b 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -12,7 +12,6 @@
#include "alarm.h"
#include "dbDefs.h"
-#include "dbmf.h"
#include "errlog.h"
#include "epicsAssert.h"
#include "epicsString.h"
@@ -56,6 +55,9 @@ typedef struct calc_link {
epicsEnum16 stat;
epicsEnum16 sevr;
short prec;
+ char *expr;
+ char *major;
+ char *minor;
char *post_expr;
char *post_major;
char *post_minor;
@@ -70,7 +72,8 @@ static lset lnkCalc_lset;
/*************************** jlif Routines **************************/
-static jlink* lnkCalc_alloc(short dbfType) {
+static jlink* lnkCalc_alloc(short dbfType)
+{
calc_link *clink = calloc(1, sizeof(struct calc_link));
IFDEBUG(10)
@@ -86,7 +89,8 @@ static jlink* lnkCalc_alloc(short dbfType) {
return &clink->jlink;
}
-static void lnkCalc_free(jlink *pjlink) {
+static void lnkCalc_free(jlink *pjlink)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
int i;
@@ -96,6 +100,9 @@ static void lnkCalc_free(jlink *pjlink) {
for (i = 0; i < clink->nArgs; i++)
dbJLinkFree(clink->inp[i].value.json.jlink);
+ free(clink->expr);
+ free(clink->major);
+ free(clink->minor);
free(clink->post_expr);
free(clink->post_major);
free(clink->post_minor);
@@ -103,7 +110,8 @@ static void lnkCalc_free(jlink *pjlink) {
free(clink);
}
-static jlif_result lnkCalc_integer(jlink *pjlink, long num) {
+static jlif_result lnkCalc_integer(jlink *pjlink, long num)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
@@ -130,7 +138,8 @@ static jlif_result lnkCalc_integer(jlink *pjlink, long num) {
return jlif_continue;
}
-static jlif_result lnkCalc_double(jlink *pjlink, double num) {
+static jlif_result lnkCalc_double(jlink *pjlink, double num)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
@@ -152,7 +161,8 @@ static jlif_result lnkCalc_double(jlink *pjlink, double num) {
return jlif_continue;
}
-static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len) {
+static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
char *inbuf, *postbuf;
short err;
@@ -176,27 +186,32 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len) {
return jlif_stop;
}
- if (clink->pstate == ps_major)
- clink->post_major = postbuf;
- else if (clink->pstate == ps_minor)
- clink->post_minor = postbuf;
- else
- clink->post_expr = postbuf;
+ inbuf = epicsStrnDup(val, len);
- inbuf = dbmfStrndup(val, len);
+ if (clink->pstate == ps_major) {
+ clink->major = inbuf;
+ clink->post_major = postbuf;
+ }
+ else if (clink->pstate == ps_minor) {
+ clink->minor = inbuf;
+ clink->post_minor = postbuf;
+ }
+ else {
+ clink->expr = inbuf;
+ clink->post_expr = postbuf;
+ }
if (postfix(inbuf, postbuf, &err) < 0) {
errlogPrintf("lnkCalc: Error in calc expression, %s\n",
calcErrorStr(err));
- dbmfFree(inbuf);
return jlif_stop;
}
- dbmfFree(inbuf);
return jlif_continue;
}
-static jlif_key_result lnkCalc_start_map(jlink *pjlink) {
+static jlif_key_result lnkCalc_start_map(jlink *pjlink)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
@@ -213,7 +228,8 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink) {
return jlif_continue;
}
-static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len) {
+static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
@@ -251,7 +267,8 @@ static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len) {
return jlif_continue;
}
-static jlif_result lnkCalc_end_map(jlink *pjlink) {
+static jlif_result lnkCalc_end_map(jlink *pjlink)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
@@ -263,7 +280,8 @@ static jlif_result lnkCalc_end_map(jlink *pjlink) {
return jlif_continue;
}
-static jlif_result lnkCalc_start_array(jlink *pjlink) {
+static jlif_result lnkCalc_start_array(jlink *pjlink)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
@@ -277,7 +295,8 @@ static jlif_result lnkCalc_start_array(jlink *pjlink) {
return jlif_continue;
}
-static jlif_result lnkCalc_end_array(jlink *pjlink) {
+static jlif_result lnkCalc_end_array(jlink *pjlink)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
@@ -289,7 +308,8 @@ static jlif_result lnkCalc_end_array(jlink *pjlink) {
return jlif_continue;
}
-static void lnkCalc_end_child(jlink *parent, jlink *child) {
+static void lnkCalc_end_child(jlink *parent, jlink *child)
+{
calc_link *clink = CONTAINER(parent, struct calc_link, jlink);
struct link *plink;
@@ -307,20 +327,64 @@ static void lnkCalc_end_child(jlink *parent, jlink *child) {
plink->value.json.jlink = child;
}
-static struct lset* lnkCalc_get_lset(const jlink *pjlink) {
+static struct lset* lnkCalc_get_lset(const jlink *pjlink)
+{
IFDEBUG(10)
printf("lnkCalc_get_lset(calc@%p)\n", pjlink);
return &lnkCalc_lset;
}
-static void lnkCalc_report(const jlink *pjlink) {
+static void lnkCalc_report(const jlink *pjlink, int level, int indent)
+{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+ int i;
IFDEBUG(10)
printf("lnkCalc_report(calc@%p)\n", clink);
- /* FIXME Implement! */
+ printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "",
+ clink->expr, clink->prec, clink->val,
+ clink->units ? clink->units : "");
+
+ if (level > 0) {
+ if (clink->post_major)
+ printf("%*s Major alarm: \"%s\"\n", indent, "",
+ clink->major);
+ if (clink->post_minor)
+ printf("%*s Minor alarm: \"%s\"\n", indent, "",
+ clink->minor);
+
+ for (i = 0; i < clink->nArgs; i++) {
+ struct link *plink = &clink->inp[i];
+ jlink *child = plink->type == JSON_LINK ?
+ plink->value.json.jlink : NULL;
+
+ printf("%*s Input %c: %g\n", indent, "",
+ i + 'A', clink->arg[i]);
+
+ if (child)
+ dbJLinkReport(child, level - 1, indent + 4);
+ }
+ }
+}
+
+long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx)
+{
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+ int i;
+
+ IFDEBUG(10)
+ printf("lnkCalc_map_children(calc@%p)\n", clink);
+
+ for (i = 0; i < clink->nArgs; i++) {
+ struct link *child = &clink->inp[i];
+ long status = dbJLinkMapChildren(child, rtn, ctx);
+
+ if (status)
+ return status;
+ }
+ return 0;
}
/*************************** lset Routines **************************/
@@ -431,7 +495,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
long nReq = 1;
dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq);
- /* FIXME Should we look at the return status from dbGetLink? */
+ /* Any errors have already triggered a LINK/INVALID alarm */
}
clink->stat = 0;
clink->sevr = 0;
@@ -541,7 +605,8 @@ static jlif lnkCalcIf = {
NULL, NULL, lnkCalc_integer, lnkCalc_double, lnkCalc_string,
lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map,
lnkCalc_start_array, lnkCalc_end_array,
- lnkCalc_end_child, lnkCalc_get_lset, lnkCalc_report
+ lnkCalc_end_child, lnkCalc_get_lset,
+ lnkCalc_report, lnkCalc_map_children
};
epicsExportAddress(jlif, lnkCalcIf);
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 3dc08051f..7062ff1f9 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -56,7 +56,8 @@ static lset lnkConst_lset;
/*************************** jlif Routines **************************/
-static jlink* lnkConst_alloc(short dbfType) {
+static jlink* lnkConst_alloc(short dbfType)
+{
clink *clink = calloc(1, sizeof(struct clink));
IFDEBUG(10)
@@ -72,7 +73,8 @@ static jlink* lnkConst_alloc(short dbfType) {
return &clink->jlink;
}
-static void lnkConst_free(jlink *pjlink) {
+static void lnkConst_free(jlink *pjlink)
+{
clink *clink = CONTAINER(pjlink, struct clink, jlink);
IFDEBUG(10)
@@ -93,7 +95,8 @@ static void lnkConst_free(jlink *pjlink) {
free(clink);
}
-static jlif_result lnkConst_integer(jlink *pjlink, long num) {
+static jlif_result lnkConst_integer(jlink *pjlink, long num)
+{
clink *clink = CONTAINER(pjlink, struct clink, jlink);
IFDEBUG(10)
@@ -145,7 +148,8 @@ static jlif_result lnkConst_boolean(jlink *pjlink, int val) {
return lnkConst_integer(pjlink, val);
}
-static jlif_result lnkConst_double(jlink *pjlink, double num) {
+static jlif_result lnkConst_double(jlink *pjlink, double num)
+{
clink *clink = CONTAINER(pjlink, struct clink, jlink);
IFDEBUG(10)
@@ -194,7 +198,8 @@ static jlif_result lnkConst_double(jlink *pjlink, double num) {
return jlif_continue;
}
-static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) {
+static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
+{
clink *clink = CONTAINER(pjlink, struct clink, jlink);
IFDEBUG(10)
@@ -238,7 +243,8 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) {
return jlif_continue;
}
-static jlif_result lnkConst_start_array(jlink *pjlink) {
+static jlif_result lnkConst_start_array(jlink *pjlink)
+{
clink *clink = CONTAINER(pjlink, struct clink, jlink);
IFDEBUG(10)
@@ -253,27 +259,104 @@ static jlif_result lnkConst_start_array(jlink *pjlink) {
return jlif_continue;
}
-static jlif_result lnkConst_end_array(jlink *pjlink) {
+static jlif_result lnkConst_end_array(jlink *pjlink)
+{
IFDEBUG(10)
printf("lnkConst_end_array(const@%p)\n", pjlink);
return jlif_continue;
}
-static struct lset* lnkConst_get_lset(const jlink *pjlink) {
+static struct lset* lnkConst_get_lset(const jlink *pjlink)
+{
IFDEBUG(10)
printf("lnkConst_get_lset(const@%p)\n", pjlink);
return &lnkConst_lset;
}
-static void lnkConst_report(const jlink *pjlink) {
+
+/* Report outputs:
+ * 'const': integer 21
+ * 'const': double 5.23
+ * 'const': string "something"
+ * 'const': array of 999 integers
+ * [1, 2, 3]
+ * 'const': array of 1 double
+ * [1.2345]
+ * 'const': array of 2 strings
+ * ["hello", "world"]
+ *
+ * Array values are only printed at level 2
+ * because there might be quite a few of them.
+ */
+
+static void lnkConst_report(const jlink *pjlink, int level, int indent)
+{
clink *clink = CONTAINER(pjlink, struct clink, jlink);
+ const char * const type_names[4] = {
+ "bug", "integer", "double", "string"
+ };
+ const char * const dtype = type_names[clink->type & 3];
IFDEBUG(10)
printf("lnkConst_report(const@%p)\n", clink);
- /* FIXME Implement! */
+ if (clink->type > a0) {
+ const char * const plural = clink->nElems > 1 ? "s" : "";
+
+ printf("%*s'const': array of %d %s%s", indent, "",
+ clink->nElems, dtype, plural);
+
+ if (level < 2) {
+ putchar('\n');
+ }
+ else {
+ int i;
+
+ switch (clink->type) {
+ case ai32:
+ printf("\n%*s[%d", indent+2, "", clink->value.pintegers[0]);
+ for (i = 1; i < clink->nElems; i++) {
+ printf(", %d", clink->value.pintegers[i]);
+ }
+ break;
+ case af64:
+ printf("\n%*s[%g", indent+2, "", clink->value.pdoubles[0]);
+ for (i = 1; i < clink->nElems; i++) {
+ printf(", %g", clink->value.pdoubles[i]);
+ }
+ break;
+ case ac40:
+ printf("\n%*s[\"%s\"", indent+2, "", clink->value.pstrings[0]);
+ for (i = 1; i < clink->nElems; i++) {
+ printf(", \"%s\"", clink->value.pstrings[i]);
+ }
+ break;
+ default:
+ break;
+ }
+ printf("]\n");
+ }
+ return;
+ }
+
+ printf("%*s'const': %s", indent, "", dtype);
+
+ switch (clink->type) {
+ case si32:
+ printf(" %d\n", clink->value.scalar_integer);
+ return;
+ case sf64:
+ printf(" %g\n", clink->value.scalar_double);
+ return;
+ case sc40:
+ printf(" \"%s\"\n", clink->value.scalar_string);
+ return;
+ default:
+ printf(" -- type=%d\n", clink->type);
+ return;
+ }
}
/*************************** lset Routines **************************/
@@ -474,8 +557,10 @@ static lset lnkConst_lset = {
static jlif lnkConstIf = {
"const", lnkConst_alloc, lnkConst_free,
NULL, lnkConst_boolean, lnkConst_integer, lnkConst_double, lnkConst_string,
- NULL, NULL, NULL, lnkConst_start_array, lnkConst_end_array,
- NULL, lnkConst_get_lset, lnkConst_report
+ NULL, NULL, NULL,
+ lnkConst_start_array, lnkConst_end_array,
+ NULL, lnkConst_get_lset,
+ lnkConst_report, NULL
};
epicsExportAddress(jlif, lnkConstIf);
From 5b747996056ec906d14ae62d6fa4d0e4ce4d6edf Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 5 Sep 2016 15:12:09 -0500
Subject: [PATCH 057/112] Some documentation updates
---
src/std/link/links.dbd.pod | 77 ++++++++++++--------------------------
src/std/link/lnkCalc.c | 5 +++
2 files changed, 28 insertions(+), 54 deletions(-)
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
index 8ae5c3f56..3e9199947 100644
--- a/src/std/link/links.dbd.pod
+++ b/src/std/link/links.dbd.pod
@@ -8,10 +8,6 @@ The following link types are available in this release:
=item * L
-=item * L
-
-=item * L
-
=item * L
=back
@@ -19,9 +15,11 @@ The following link types are available in this release:
=head2 Using Links
...
-must appear inside a pair of braces C< {} > expressed as a JSON
-(L) object, which allows link
-parameters to be defined as needed.
+
+When setting a record link field to a JSON link, the link specification must
+appear inside a pair of braces C< {} > expressed as a JSON (L) object, which allows link parameters to be
+defined as needed by the particular link type.
=head2 Link Type Reference
@@ -32,16 +30,23 @@ link(const, lnkConstIf)
=head3 Constant Link C<"const">
-Constant links provide one or more values at link initalization time, but do not return
-any data when their C routine is called. Most record types support the use of
-constant links by calling C at initialization, which results in
-the constant value being loaded into the target field at that time.
+Constant links provide one or more values at link initalization time, but do not
+return any data when their C routine is called. Most record types
+support the use of constant links by calling C at
+record initialization, which results in the constant value being loaded into the
+target field at that time.
+
+Note that for most record types (the C and C records are
+exceptions) it is pointless to set an input link to a constant link at runtime
+since the link initialization that loads the field value usually only happens
+when a record is initialized.
=head4 Parameters
-A const link takes a parameter which may be an integer, double or string, or an array of
-those types. If an array contains both integers and double values the integers will be
-promoted to doubles. Mixing strings and numbers in an array will result in an error.
+A const link takes a parameter which may be an integer, double or string, or an
+array of those types. If an array contains both integers and double values the
+integers will be promoted to doubles. Mixing strings and numbers in an array
+results in an error.
=head4 Examples
@@ -50,47 +55,11 @@ promoted to doubles. Mixing strings and numbers in an array will result in an er
{const: [1, 2.718281828459, 3.14159265358979]}
{const: ["One", "e", "Pi"]}
-=cut
+The JSON syntax does not support Infinity or NaN values when parsing numbers,
+but (for scalars) it is possible to provide these in a string which will be
+converted to the desired double value at initialization, for example:
-#link(db, lnkDbIf)
-
-=head3 Database Link C<"db">
-
-...
-
-=head4 Parameters
-
-...
-
-=head4 Example
-
- ...
-
-=cut
-
-#link(ca, lnkCaIf)
-
-=head3 Channel Access Link C<"ca">
-
-...
-
-=head4 Parameters
-
-...
-
-=over
-
-=item ...
-
-...
-
-=back
-
-...
-
-=head4 Example
-
- ...
+ field(INP, {const:"Inf"})
=cut
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 545be430b..0f5f205c3 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -6,6 +6,11 @@
\*************************************************************************/
/* lnkCalc.c */
+/* TODO:
+ * Support setting individual input links instead of the args list.
+ * {calc:{expr:"K", K:{...}}}
+ */
+
#include
#include
#include
From 268e59b052e41fc71144ee73f1b285bd28ae6a33 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 5 Sep 2016 15:38:16 -0500
Subject: [PATCH 058/112] Minor updates
---
src/std/link/links.dbd.pod | 4 +++-
src/std/link/lnkCalc.c | 9 +++++++--
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
index 3e9199947..a7ddeb553 100644
--- a/src/std/link/links.dbd.pod
+++ b/src/std/link/links.dbd.pod
@@ -39,7 +39,9 @@ target field at that time.
Note that for most record types (the C and C records are
exceptions) it is pointless to set an input link to a constant link at runtime
since the link initialization that loads the field value usually only happens
-when a record is initialized.
+when a record is initialized. A constant link that is embedded inside another
+input link type such as a calculation link should be OK though since the link
+initialization will take place when the record's field gets set.
=head4 Parameters
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 0f5f205c3..7021e40b4 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -353,11 +353,16 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent)
clink->units ? clink->units : "");
if (level > 0) {
+ if (clink->sevr)
+ printf("%*s Alarm: %s, %s\n", indent, "",
+ epicsAlarmSeverityStrings[clink->sevr],
+ epicsAlarmConditionStrings[clink->stat]);
+
if (clink->post_major)
- printf("%*s Major alarm: \"%s\"\n", indent, "",
+ printf("%*s Major expression: \"%s\"\n", indent, "",
clink->major);
if (clink->post_minor)
- printf("%*s Minor alarm: \"%s\"\n", indent, "",
+ printf("%*s Minor expression: \"%s\"\n", indent, "",
clink->minor);
for (i = 0; i < clink->nArgs; i++) {
From 2d4301f0bbe75c331f2c8b3f4f8936b1217b11c9 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 5 Sep 2016 22:36:45 -0500
Subject: [PATCH 059/112] Fix warnings from clang
---
src/ioc/db/dbJLink.c | 2 +-
src/std/link/lnkCalc.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index 7e84bda2a..8b2778511 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -160,7 +160,7 @@ static int dbjl_string(void *ctx, const unsigned char *val, unsigned len) {
static int dbjl_start_map(void *ctx) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
- jlif_key_result result;
+ int result;
if (!pjlink) {
IFDEBUG(10) {
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 7021e40b4..2acbe0666 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -227,10 +227,10 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink)
if (clink->pstate != ps_init) {
errlogPrintf("lnkCalc: Unexpected map\n");
- return jlif_stop;
+ return jlif_key_stop;
}
- return jlif_continue;
+ return jlif_key_continue;
}
static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len)
From 8a9707e74fd5dd578efcd078295083c35ea8995e Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 6 Sep 2016 22:28:36 -0500
Subject: [PATCH 060/112] Fixed a small memory leak in lnkCalc
---
src/std/link/lnkCalc.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 2acbe0666..1b3222a34 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -432,6 +432,9 @@ static void lnkCalc_remove(struct dbLocker *locker, struct link *plink)
dbRemoveLink(locker, child);
}
+ free(clink->expr);
+ free(clink->major);
+ free(clink->minor);
free(clink->post_expr);
free(clink->post_major);
free(clink->post_minor);
From c12a35e388f5ed04a0f294089658e5f8e70c41eb Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 7 Sep 2016 00:47:51 -0500
Subject: [PATCH 061/112] Clean up memory leaks
---
src/ioc/db/dbJLink.c | 1 +
src/ioc/db/dbLink.c | 2 ++
src/ioc/dbStatic/dbStaticLib.c | 10 ++++------
src/ioc/dbStatic/dbStaticPvt.h | 2 ++
4 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index 8b2778511..a5939a6d5 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -385,6 +385,7 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
err = yajl_get_error(yh, 1, (const unsigned char *) json, (unsigned) jlen);
errlogPrintf("dbJLinkInit: %s\n", err);
yajl_free_error(yh, err);
+ dbJLinkFree(parser->pjlink);
/* fall through */
default:
status = S_db_badField;
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index 054df88c9..bb74f91c6 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -177,6 +177,8 @@ void dbRemoveLink(struct dbLocker *locker, struct link *plink)
plset->removeLink(locker, plink);
plink->lset = NULL;
}
+ if (plink->type == JSON_LINK)
+ plink->value.json.jlink = NULL;
}
int dbLinkIsDefined(const struct link *plink)
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index 89ab96d36..566f3cf74 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2235,7 +2235,6 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
return 0;
}
-static
void dbFreeLinkInfo(dbLinkInfo *pinfo)
{
if (pinfo->ltype == JSON_LINK) {
@@ -2282,12 +2281,11 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
- long status = dbJLinkParse(str, len, ftype, &pinfo->jlink);
+ if (dbJLinkParse(str, len, ftype, &pinfo->jlink))
+ goto fail;
- if (!status)
- pinfo->ltype = JSON_LINK;
-
- return status;
+ pinfo->ltype = JSON_LINK;
+ return 0;
}
/* Check for other HW link types */
diff --git a/src/ioc/dbStatic/dbStaticPvt.h b/src/ioc/dbStatic/dbStaticPvt.h
index 3e2435e79..41a37429a 100644
--- a/src/ioc/dbStatic/dbStaticPvt.h
+++ b/src/ioc/dbStatic/dbStaticPvt.h
@@ -74,6 +74,8 @@ long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup);
* Unconditionally takes ownership of pinfo->target
*/
long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *dset);
+/* Free dbLinkInfo storage */
+epicsShareFunc void dbFreeLinkInfo(dbLinkInfo *pinfo);
/* The following is for path */
typedef struct dbPathNode {
From b2012fdfb5be89b9af4fe1415a58b00c46980780 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 7 Sep 2016 00:50:40 -0500
Subject: [PATCH 062/112] Added test link type, fix dbPutLinkTest for
JSON_LINKs
---
src/ioc/db/test/Makefile | 2 +
src/ioc/db/test/dbPutLinkTest.c | 24 +++++----
src/ioc/db/test/dbPutLinkTest.db | 2 +-
src/ioc/db/test/xLink.c | 88 ++++++++++++++++++++++++++++++++
src/ioc/db/test/xLink.dbd | 1 +
5 files changed, 107 insertions(+), 10 deletions(-)
create mode 100644 src/ioc/db/test/xLink.c
create mode 100644 src/ioc/db/test/xLink.dbd
diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile
index b268b57a1..66567d318 100644
--- a/src/ioc/db/test/Makefile
+++ b/src/ioc/db/test/Makefile
@@ -18,6 +18,7 @@ TESTLIBRARY = dbTestIoc
dbTestIoc_SRCS += arrRecord.c
dbTestIoc_SRCS += xRecord.c
dbTestIoc_SRCS += dbLinkdset.c
+dbTestIoc_SRCS += xLink.c
dbTestIoc_SRCS += devx.c
dbTestIoc_LIBS = dbCore ca Com
@@ -28,6 +29,7 @@ dbTestIoc_DBD += menuConvert.dbd
dbTestIoc_DBD += menuScan.dbd
dbTestIoc_DBD += xRecord.dbd
dbTestIoc_DBD += arrRecord.dbd
+dbTestIoc_DBD += xLink.dbd
dbTestIoc_DBD += devx.dbd
dbTestIoc_DBD += dbLinkdset.dbd
TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db
diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c
index 76813c2fd..a0a4d66ba 100644
--- a/src/ioc/db/test/dbPutLinkTest.c
+++ b/src/ioc/db/test/dbPutLinkTest.c
@@ -60,7 +60,7 @@ static const struct testParseDataT {
{"#B11 C12 N13 A14 F15 @cparam", {CAMAC_IO, "cparam", 0, "BCNAF", {11, 12, 13, 14, 15}}},
{" #B111 C112 N113 @cparam", {CAMAC_IO, "cparam", 0, "BCN", {111, 112, 113}}},
{" @hello world ", {INST_IO, "hello world", 0, "", /*{}*/}},
- {" {\"x\":{}} ", {JSON_LINK, "{\"x\":{}}", 0, "", /*{}*/}},
+ {" {\"x\":true} ", {JSON_LINK, "{\"x\":true}", 0, "", /*{}*/}},
{NULL}
};
@@ -101,7 +101,7 @@ static void testLinkParse(void)
info.hwnums[i], td->info.hwnums[i]);
}
}
- free(info.target);
+ dbFreeLinkInfo(&info);
}
testIocShutdownOk();
@@ -240,7 +240,7 @@ typedef struct {
} testHWDataT;
static const testHWDataT testHWData[] = {
- {"rJSON_LINK", JSON_LINK, "{\"JSON\":{}}", {0}, "{\"JSON\":{}}"},
+ {"rJSON_LINK", JSON_LINK, "{\"x\":true}", {0}, "{\"x\":true}"},
{"rVME_IO", VME_IO, "#C100 S101 @parm VME_IO", {100, 101}, "parm VME_IO"},
{"rCAMAC_IO", CAMAC_IO, "#B11 C12 N13 A14 F15 @parm CAMAC_IO", {11, 12, 13, 14, 15}, "parm CAMAC_IO"},
{"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"},
@@ -365,7 +365,7 @@ static void testHWInitSet(void)
}
static const testHWDataT testHWData2[] = {
- {"rJSON_LINK", JSON_LINK, "{\"json\":{}}", {0}, "{\"json\":{}}"},
+ {"rJSON_LINK", JSON_LINK, "{\"x\":true}", {0}, "{\"x\":true}"},
{"rVME_IO", VME_IO, "#C200 S201 @another VME_IO", {200, 201}, "another VME_IO"},
{"rCAMAC_IO", CAMAC_IO, "#B111 C112 N113 A114 F115 @CAMAC_IO", {111, 112, 113, 114, 115}, "CAMAC_IO"},
{"rAB_IO", AB_IO, "#L121 A122 C123 S124 @another AB_IO", {121, 122, 123, 124}, "another AB_IO"},
@@ -491,11 +491,17 @@ static void testLinkFail(void)
/* INST_IO doesn't accept string without @ */
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc");
- /* JSON_LINK doesn't accept empty string */
- testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "");
+ /* JSON_LINK dies properly */
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":false}");
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":null}");
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":1}");
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":1.1}");
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":\"x\"}");
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":[]}");
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":{}}");
- /* JSON_LINK doesn't accept bareword string */
- testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "abc");
+ /* JSON_LINK syntax errors */
+ testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":bbbb}");
/* syntax errors */
testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO");
@@ -516,7 +522,7 @@ static void testLinkFail(void)
MAIN(dbPutLinkTest)
{
- testPlan(263);
+ testPlan(269);
testLinkParse();
testLinkFailParse();
testCADBSet();
diff --git a/src/ioc/db/test/dbPutLinkTest.db b/src/ioc/db/test/dbPutLinkTest.db
index 747666052..6742fcb39 100644
--- a/src/ioc/db/test/dbPutLinkTest.db
+++ b/src/ioc/db/test/dbPutLinkTest.db
@@ -5,7 +5,7 @@ record(x, "x4") {}
record(x, "rJSON_LINK") {
field(DTYP, "Unit Test JSON_LINK")
- field(INP, "{\"JSON\":{}}")
+ field(INP, {x:true})
}
record(x, "rVME_IO") {
field(DTYP, "Unit Test VME_IO")
diff --git a/src/ioc/db/test/xLink.c b/src/ioc/db/test/xLink.c
new file mode 100644
index 000000000..f6dfab95c
--- /dev/null
+++ b/src/ioc/db/test/xLink.c
@@ -0,0 +1,88 @@
+/*************************************************************************\
+* 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.
+\*************************************************************************/
+/* xLink.c */
+
+#include "dbDefs.h"
+#include "dbLink.h"
+#include "dbJLink.h"
+#include "epicsExport.h"
+
+
+typedef struct xlink {
+ jlink jlink; /* embedded object */
+ /* ... */
+} xlink;
+
+static lset xlink_lset;
+
+static jlink* xlink_alloc(short dbfType)
+{
+ xlink *xlink = calloc(1, sizeof(struct xlink));
+
+ return &xlink->jlink;
+}
+
+static void xlink_free(jlink *pjlink)
+{
+ xlink *xlink = CONTAINER(pjlink, struct xlink, jlink);
+
+ free(xlink);
+}
+
+static jlif_result xlink_boolean(jlink *pjlink, int val)
+{
+ return val; /* False triggers a parse failure */
+}
+
+static struct lset* xlink_get_lset(const jlink *pjlink)
+{
+ return &xlink_lset;
+}
+
+
+static void xlink_remove(struct dbLocker *locker, struct link *plink)
+{
+ xlink_free(plink->value.json.jlink);
+}
+
+static long xlink_getNelements(const struct link *plink, long *nelements)
+{
+ *nelements = 0;
+ return 0;
+}
+
+static long xlink_getValue(struct link *plink, short dbrType, void *pbuffer,
+ long *pnRequest)
+{
+ if (pnRequest)
+ *pnRequest = 0;
+ return 0;
+}
+
+
+static lset xlink_lset = {
+ 1, 0, /* Constant, not Volatile */
+ NULL, xlink_remove,
+ NULL, NULL, NULL, NULL,
+ NULL, xlink_getNelements, xlink_getValue,
+ NULL, NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL
+};
+
+static jlif xlinkIf = {
+ "x", xlink_alloc, xlink_free,
+ NULL, xlink_boolean, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL,
+ NULL, xlink_get_lset,
+ NULL, NULL
+};
+epicsExportAddress(jlif, xlinkIf);
+
diff --git a/src/ioc/db/test/xLink.dbd b/src/ioc/db/test/xLink.dbd
new file mode 100644
index 000000000..290b0ba02
--- /dev/null
+++ b/src/ioc/db/test/xLink.dbd
@@ -0,0 +1 @@
+link(x, xlinkIf)
From 58c78af4f940d188ccb6a9d26d3ff754135f4cf5 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 7 Sep 2016 23:35:39 -0500
Subject: [PATCH 063/112] Initialize all fields of jlink, link types may not
use calloc
---
src/ioc/db/dbJLink.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index a5939a6d5..c350a5155 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -255,6 +255,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
return dbjl_return(parser, jlif_stop);
}
pjlink->pif = pjlif;
+ pjlink->parent = NULL;
+ pjlink->parseDepth = 0;
if (parser->pjlink) {
/* We're starting a child link, save its parent */
From da5455ed222ddee097dc9b994898e74d9b10ddd6 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 9 Sep 2016 11:14:59 -0500
Subject: [PATCH 064/112] Fixes for Windows builds
---
src/ioc/db/dbConvertJSON.c | 2 +-
src/ioc/db/dbJLink.c | 3 +--
src/ioc/dbStatic/dbStaticPvt.h | 6 +++---
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c
index 14a48866f..c0e1e2c8e 100644
--- a/src/ioc/db/dbConvertJSON.c
+++ b/src/ioc/db/dbConvertJSON.c
@@ -14,7 +14,7 @@
#include "yajl_alloc.h"
#include "yajl_parse.h"
-#define epicsExportSharedSybols
+#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbConvertFast.h"
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index c350a5155..5638e73ee 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -11,12 +11,11 @@
#include "epicsAssert.h"
#include "dbmf.h"
-#include "dbStaticLib.h"
#include "errlog.h"
#include "yajl_alloc.h"
#include "yajl_parse.h"
-#define epicsExportSharedSybols
+#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbCommon.h"
#include "dbLink.h"
diff --git a/src/ioc/dbStatic/dbStaticPvt.h b/src/ioc/dbStatic/dbStaticPvt.h
index 41a37429a..372fd54bf 100644
--- a/src/ioc/dbStatic/dbStaticPvt.h
+++ b/src/ioc/dbStatic/dbStaticPvt.h
@@ -16,8 +16,6 @@
#ifndef INCdbStaticPvth
#define INCdbStaticPvth 1
-#include "dbJLink.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -38,6 +36,8 @@ char *dbRecordName(DBENTRY *pdbentry);
char *dbGetStringNum(DBENTRY *pdbentry);
long dbPutStringNum(DBENTRY *pdbentry,const char *pstring);
+struct jlink;
+
typedef struct dbLinkInfo {
short ltype;
@@ -54,7 +54,7 @@ typedef struct dbLinkInfo {
int hwnums[5];
/* for JSON_LINK */
- jlink *jlink;
+ struct jlink *jlink;
} dbLinkInfo;
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
From fab5ce675f71f0754fd1eb986d330509742a24e3 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 12 Dec 2016 17:44:01 -0600
Subject: [PATCH 065/112] Update comments in calcoutRecord
---
src/std/rec/calcoutRecord.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c
index 217c2abf0..ab1f53fac 100644
--- a/src/std/rec/calcoutRecord.c
+++ b/src/std/rec/calcoutRecord.c
@@ -100,15 +100,15 @@ typedef struct calcoutDSET {
}calcoutDSET;
-/* To provide feedback to the user as to the connection status of the
+/* To provide feedback to the user as to the connection status of the
* links (.INxV and .OUTV), the following algorithm has been implemented ...
*
- * A new PV_LINK [either in init() or special()] is searched for using
- * dbNameToAddr. If local, it is so indicated. If not, a checkLinkCb
- * callback is scheduled to check the connectivity later using
- * dbCaIsLinkConnected(). Anytime there are unconnected CA_LINKs, another
+ * A new PV_LINK is checked [in both init() and special()] to see if the
+ * target is local -- if so it is marked as such. If not, a checkLinkCb
+ * callback is scheduled to check the connection status later by calling
+ * dbIsLinkConnected(). Anytime there are unconnected CA_LINKs, another
* callback is scheduled. Once all connections are established, the CA_LINKs
- * are checked whenever the record processes.
+ * are checked whenever the record processes.
*
*/
From c52088205e82d022bbb2649cec5de31e585f8cf3 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 17 Feb 2017 14:15:31 -0600
Subject: [PATCH 066/112] Remove constant link checks from test device
---
src/ioc/db/test/devx.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/ioc/db/test/devx.c b/src/ioc/db/test/devx.c
index 104c64001..6cd01202a 100644
--- a/src/ioc/db/test/devx.c
+++ b/src/ioc/db/test/devx.c
@@ -141,15 +141,12 @@ epicsExportAddress(dset, devxScanIO);
/* basic DTYP="Soft Channel" */
static long xsoft_init_record(xRecord *prec)
{
- if(prec->inp.type==CONSTANT)
- recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->val);
+ recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->val);
return 0;
}
static long xsoft_read(xRecord *prec)
{
- if(prec->inp.type==CONSTANT)
- return 0;
dbGetLink(&prec->inp, DBR_DOUBLE, &prec->val, NULL, NULL);
return 0;
}
From 00549c832a9bd941b8a6d6e127dcbe1946b73c47 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 17 Feb 2017 14:16:57 -0600
Subject: [PATCH 067/112] Fix HTML entities
---
documentation/RELEASE_NOTES.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 3b0189205..17b5946c6 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -69,13 +69,13 @@ successfully initialized from the link.
Code like this:
- if ((prec->dol.type != CONSTANT) &&
+ if ((prec->dol.type != CONSTANT) &&
should usually become:
- if (!dbLinkIsConstant(&prec->dol) &&
+ if (!dbLinkIsConstant(&prec->dol) &&
From 428dfe7a5c91708ff92fdb916ce3b54a55263752 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Tue, 28 Feb 2017 18:00:51 -0600
Subject: [PATCH 068/112] add testing lset
---
src/ioc/db/test/Makefile | 2 +
src/ioc/db/test/dbPutLinkTest.c | 187 +++++++++++++------------
src/ioc/db/test/jlinkz.c | 232 ++++++++++++++++++++++++++++++++
src/ioc/db/test/jlinkz.dbd | 1 +
4 files changed, 335 insertions(+), 87 deletions(-)
create mode 100644 src/ioc/db/test/jlinkz.c
create mode 100644 src/ioc/db/test/jlinkz.dbd
diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile
index 66567d318..4fe389cbf 100644
--- a/src/ioc/db/test/Makefile
+++ b/src/ioc/db/test/Makefile
@@ -20,6 +20,7 @@ dbTestIoc_SRCS += xRecord.c
dbTestIoc_SRCS += dbLinkdset.c
dbTestIoc_SRCS += xLink.c
dbTestIoc_SRCS += devx.c
+dbTestIoc_SRCS += jlinkz.c
dbTestIoc_LIBS = dbCore ca Com
TARGETS += $(COMMON_DIR)/dbTestIoc.dbd
@@ -31,6 +32,7 @@ dbTestIoc_DBD += xRecord.dbd
dbTestIoc_DBD += arrRecord.dbd
dbTestIoc_DBD += xLink.dbd
dbTestIoc_DBD += devx.dbd
+dbTestIoc_DBD += jlinkz.dbd
dbTestIoc_DBD += dbLinkdset.dbd
TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db
diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c
index a0a4d66ba..e46d2c4d9 100644
--- a/src/ioc/db/test/dbPutLinkTest.c
+++ b/src/ioc/db/test/dbPutLinkTest.c
@@ -68,7 +68,7 @@ static void testLinkParse(void)
{
const struct testParseDataT *td = testParseData;
dbLinkInfo info;
- testDiag("link parsing");
+ testDiag("\n# Checking link parsing\n#");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
@@ -81,22 +81,27 @@ static void testLinkParse(void)
testIocInitOk();
eltc(1);
- for(;td->str; td++) {
+ for (;td->str; td++) {
int i, N;
- testDiag("Parse \"%s\"", td->str);
- testOk1(dbParseLink(td->str, DBF_INLINK, &info)==0);
- testOk1(info.ltype==td->info.ltype);
- if(td->info.target)
+ testDiag("Parsing \"%s\"", td->str);
+ testOk(dbParseLink(td->str, DBF_INLINK, &info) == 0, "Parser returned OK");
+ if (!testOk(info.ltype == td->info.ltype, "Link type value"))
+ testDiag("Expected %d, got %d", td->info.ltype, info.ltype);
+ if (td->info.target)
testStrcmp(0, info.target, td->info.target);
- if(info.ltype==td->info.ltype) {
- switch(info.ltype) {
+ if (info.ltype == td->info.ltype) {
+ switch (info.ltype) {
case PV_LINK:
- testOk1(info.modifiers==td->info.modifiers);
+ if (!testOk(info.modifiers == td->info.modifiers,
+ "PV Link modifier flags"))
+ testDiag("Expected %d, got %d", td->info.modifiers,
+ info.modifiers);
break;
case VME_IO:
+ case CAMAC_IO:
testStrcmp(0, info.hwid, td->info.hwid);
N = strlen(td->info.hwid);
- for(i=0; iinfo.hwnums[i], "%d == %d",
info.hwnums[i], td->info.hwnums[i]);
}
@@ -125,7 +130,7 @@ static void testLinkFailParse(void)
{
const char * const *td = testParseFailData;
dbLinkInfo info;
- testDiag("link parsing of invalid input");
+ testDiag("\n# Check parsing of invalid inputs\n#");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
@@ -139,8 +144,8 @@ static void testLinkFailParse(void)
eltc(1);
for(;*td; td++) {
- testDiag("Expect failure \"%s\"", *td);
- testOk1(dbParseLink(*td, DBF_INLINK, &info)==S_dbLib_badField);
+ testOk(dbParseLink(*td, DBF_INLINK, &info) == S_dbLib_badField,
+ "dbParseLink correctly rejected \"%s\"", *td);
}
testIocShutdownOk();
@@ -180,7 +185,7 @@ static void testCADBSet(void)
const struct testDataT *td = testSetData;
xRecord *prec;
DBLINK *plink;
- testDiag("DB/CA link retargeting");
+ testDiag("\n# Checking DB/CA link retargeting\n#");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
@@ -197,21 +202,22 @@ static void testCADBSet(void)
plink = &prec->lnk;
for (;td->linkstring;td++) {
- testDiag("x1.LNK <- \"%s\"", td->linkstring);
+ testDiag("Trying field value \"%s\"", td->linkstring);
testdbPutFieldOk("x1.LNK", DBF_STRING, td->linkstring);
if (td->linkback)
testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkback);
else
testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkstring);
- testOk1(plink->type==td->linkType);
+ if (!testOk(plink->type == td->linkType, "Link type"))
+ testDiag("Expected %d, got %d", td->linkType, plink->type);
- if (plink->type==td->linkType) {
- switch(td->linkType) {
+ if (plink->type == td->linkType) {
+ switch (td->linkType) {
case CONSTANT:
- if(plink->value.constantStr)
- testOk1(strcmp(plink->value.constantStr,td->linkstring)==0);
- else if(td->linkstring[0]=='\0')
+ if (plink->value.constantStr)
+ testOk1(strcmp(plink->value.constantStr, td->linkstring) == 0);
+ else if (td->linkstring[0]=='\0')
testPass("Empty String");
else
testFail("oops");
@@ -219,7 +225,7 @@ static void testCADBSet(void)
case DB_LINK:
case CA_LINK:
- testOk(plink->value.pv_link.pvlMask==td->pvlMask,
+ testOk(plink->value.pv_link.pvlMask == td->pvlMask,
"pvlMask %x == %x", plink->value.pv_link.pvlMask, td->pvlMask);
break;
}
@@ -258,65 +264,65 @@ static void testLink(DBLINK *plink, const testHWDataT *td)
{
switch(td->ltype) {
case JSON_LINK:
- testOk1(strcmp(plink->value.json.string, td->parm)==0);
+ testOk1(strcmp(plink->value.json.string, td->parm) == 0);
break;
case VME_IO:
- testOk1(plink->value.vmeio.card==td->vals[0]);
- testOk1(plink->value.vmeio.signal==td->vals[1]);
- testOk1(strcmp(plink->value.vmeio.parm, td->parm)==0);
+ testOk1(plink->value.vmeio.card == td->vals[0]);
+ testOk1(plink->value.vmeio.signal == td->vals[1]);
+ testOk1(strcmp(plink->value.vmeio.parm, td->parm) == 0);
break;
case CAMAC_IO:
- testOk1(plink->value.camacio.b==td->vals[0]);
- testOk1(plink->value.camacio.c==td->vals[1]);
- testOk1(plink->value.camacio.n==td->vals[2]);
- testOk1(plink->value.camacio.a==td->vals[3]);
- testOk1(plink->value.camacio.f==td->vals[4]);
- testOk1(strcmp(plink->value.camacio.parm, td->parm)==0);
+ testOk1(plink->value.camacio.b == td->vals[0]);
+ testOk1(plink->value.camacio.c == td->vals[1]);
+ testOk1(plink->value.camacio.n == td->vals[2]);
+ testOk1(plink->value.camacio.a == td->vals[3]);
+ testOk1(plink->value.camacio.f == td->vals[4]);
+ testOk1(strcmp(plink->value.camacio.parm, td->parm) == 0);
break;
case AB_IO:
- testOk1(plink->value.abio.link==td->vals[0]);
- testOk1(plink->value.abio.adapter==td->vals[1]);
- testOk1(plink->value.abio.card==td->vals[2]);
- testOk1(plink->value.abio.signal==td->vals[3]);
- testOk1(strcmp(plink->value.abio.parm, td->parm)==0);
+ testOk1(plink->value.abio.link == td->vals[0]);
+ testOk1(plink->value.abio.adapter == td->vals[1]);
+ testOk1(plink->value.abio.card == td->vals[2]);
+ testOk1(plink->value.abio.signal == td->vals[3]);
+ testOk1(strcmp(plink->value.abio.parm, td->parm) == 0);
break;
case GPIB_IO:
- testOk1(plink->value.gpibio.link==td->vals[0]);
- testOk1(plink->value.gpibio.addr==td->vals[1]);
- testOk1(strcmp(plink->value.gpibio.parm, td->parm)==0);
+ testOk1(plink->value.gpibio.link == td->vals[0]);
+ testOk1(plink->value.gpibio.addr == td->vals[1]);
+ testOk1(strcmp(plink->value.gpibio.parm, td->parm) == 0);
break;
case BITBUS_IO:
- testOk1(plink->value.bitbusio.link==td->vals[0]);
- testOk1(plink->value.bitbusio.node==td->vals[1]);
- testOk1(plink->value.bitbusio.port==td->vals[2]);
- testOk1(plink->value.bitbusio.signal==td->vals[3]);
- testOk1(strcmp(plink->value.bitbusio.parm, td->parm)==0);
+ testOk1(plink->value.bitbusio.link == td->vals[0]);
+ testOk1(plink->value.bitbusio.node == td->vals[1]);
+ testOk1(plink->value.bitbusio.port == td->vals[2]);
+ testOk1(plink->value.bitbusio.signal == td->vals[3]);
+ testOk1(strcmp(plink->value.bitbusio.parm, td->parm) == 0);
break;
case INST_IO:
- testOk1(strcmp(plink->value.instio.string, td->parm)==0);
+ testOk1(strcmp(plink->value.instio.string, td->parm) == 0);
break;
case BBGPIB_IO:
- testOk1(plink->value.bbgpibio.link==td->vals[0]);
- testOk1(plink->value.bbgpibio.bbaddr==td->vals[1]);
- testOk1(plink->value.bbgpibio.gpibaddr==td->vals[2]);
- testOk1(strcmp(plink->value.bbgpibio.parm, td->parm)==0);
+ testOk1(plink->value.bbgpibio.link == td->vals[0]);
+ testOk1(plink->value.bbgpibio.bbaddr == td->vals[1]);
+ testOk1(plink->value.bbgpibio.gpibaddr == td->vals[2]);
+ testOk1(strcmp(plink->value.bbgpibio.parm, td->parm) == 0);
break;
case RF_IO:
- testOk1(plink->value.rfio.cryo==td->vals[0]);
- testOk1(plink->value.rfio.micro==td->vals[1]);
- testOk1(plink->value.rfio.dataset==td->vals[2]);
- testOk1(plink->value.rfio.element==td->vals[3]);
+ testOk1(plink->value.rfio.cryo == td->vals[0]);
+ testOk1(plink->value.rfio.micro == td->vals[1]);
+ testOk1(plink->value.rfio.dataset == td->vals[2]);
+ testOk1(plink->value.rfio.element == td->vals[3]);
break;
case VXI_IO:
- if(plink->value.vxiio.flag==VXIDYNAMIC) {
- testOk1(plink->value.vxiio.frame==td->vals[0]);
- testOk1(plink->value.vxiio.slot==td->vals[1]);
- testOk1(plink->value.vxiio.signal==td->vals[2]);
+ if(plink->value.vxiio.flag == VXIDYNAMIC) {
+ testOk1(plink->value.vxiio.frame == td->vals[0]);
+ testOk1(plink->value.vxiio.slot == td->vals[1]);
+ testOk1(plink->value.vxiio.signal == td->vals[2]);
} else {
- testOk1(plink->value.vxiio.la==td->vals[0]);
- testOk1(plink->value.vxiio.signal==td->vals[1]);
+ testOk1(plink->value.vxiio.la == td->vals[0]);
+ testOk1(plink->value.vxiio.signal == td->vals[1]);
}
- testOk1(strcmp(plink->value.vxiio.parm, td->parm)==0);
+ testOk1(strcmp(plink->value.vxiio.parm, td->parm) == 0);
break;
}
}
@@ -324,7 +330,7 @@ static void testLink(DBLINK *plink, const testHWDataT *td)
static void testHWInitSet(void)
{
const testHWDataT *td = testHWData;
- testDiag("HW link parsing during initialization");
+ testDiag("\n# Checking HW link parsing during initialization\n#");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
@@ -337,13 +343,14 @@ static void testHWInitSet(void)
testIocInitOk();
eltc(1);
- for(;td->recname;td++) {
+ for (;td->recname; td++) {
char buf[MAX_STRING_SIZE];
xRecord *prec;
DBLINK *plink;
+
testDiag("%s == \"%s\"", td->recname, td->wval);
- prec = (xRecord*)testdbRecordPtr(td->recname);
+ prec = (xRecord *) testdbRecordPtr(td->recname);
plink = &prec->inp;
strcpy(buf, td->recname);
@@ -351,9 +358,11 @@ static void testHWInitSet(void)
testdbGetFieldEqual(buf, DBR_STRING, td->wval);
- testOk(plink->type==td->ltype, "link type %d == %d",
- plink->type, td->ltype);
- if(plink->type==td->ltype) {
+ if (!testOk(plink->type == td->ltype, "Link type")) {
+ testDiag("Expected %d, got %d",
+ td->ltype, plink->type);
+ }
+ else {
testLink(plink, td);
}
@@ -382,7 +391,8 @@ static const testHWDataT testHWData2[] = {
static void testHWMod(void)
{
const testHWDataT *td = testHWData2;
- testDiag("HW link parsing during retarget");
+
+ testDiag("\n# Checking HW link parsing during retarget\n#");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
@@ -411,9 +421,11 @@ static void testHWMod(void)
testdbGetFieldEqual(buf, DBR_STRING, td->wval);
- testOk(plink->type==td->ltype, "link type %d == %d",
- plink->type, td->ltype);
- if(plink->type==td->ltype) {
+ if (!testOk(plink->type == td->ltype, "Link type")) {
+ testDiag("Expected %d, got %d",
+ td->ltype, plink->type);
+ }
+ else {
testLink(plink, td);
}
@@ -428,42 +440,42 @@ static void testLinkInitFail(void)
{
xRecord *prec;
DBLINK *plink;
- testDiag("Link parsing failures during initialization");
+ testDiag("\n# Checking link parse failures at iocInit\n#");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
dbTestIoc_registerRecordDeviceDriver(pdbbase);
-
/* this load will fail */
eltc(0);
- testOk1(dbReadDatabase(&pdbbase, "dbBadLink.db", "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
- "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL)!=0);
+ testOk(dbReadDatabase(&pdbbase, "dbBadLink.db", "." OSI_PATH_LIST_SEPARATOR
+ ".." OSI_PATH_LIST_SEPARATOR "../O.Common" OSI_PATH_LIST_SEPARATOR
+ "O.Common", NULL) != 0, "dbReadDatabase returned error (expected)");
testIocInitOk();
eltc(1);
testdbGetFieldEqual("eVME_IO1.INP", DBR_STRING, "#C0 S0 @");
- prec = (xRecord*)testdbRecordPtr("eVME_IO1");
+ prec = (xRecord *) testdbRecordPtr("eVME_IO1");
plink = &prec->inp;
- testOk1(plink->type==VME_IO);
- testOk1(plink->value.vmeio.parm!=NULL);
+ testOk1(plink->type == VME_IO);
+ testOk1(plink->value.vmeio.parm != NULL);
testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C0 S0 @");
- prec = (xRecord*)testdbRecordPtr("eVME_IO2");
+ prec = (xRecord *) testdbRecordPtr("eVME_IO2");
plink = &prec->inp;
- testOk1(plink->type==VME_IO);
- testOk1(plink->value.vmeio.parm!=NULL);
+ testOk1(plink->type == VME_IO);
+ testOk1(plink->value.vmeio.parm != NULL);
testdbGetFieldEqual("eINST_IO.INP", DBR_STRING, "@");
- prec = (xRecord*)testdbRecordPtr("eINST_IO");
+ prec = (xRecord *) testdbRecordPtr("eINST_IO");
plink = &prec->inp;
- testOk1(plink->type==INST_IO);
- testOk1(plink->value.instio.string!=NULL);
+ testOk1(plink->type == INST_IO);
+ testOk1(plink->value.instio.string != NULL);
testIocShutdownOk();
@@ -472,7 +484,7 @@ static void testLinkInitFail(void)
static void testLinkFail(void)
{
- testDiag("Link parsing failures");
+ testDiag("\n# Checking runtime link parse failures\n#");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
@@ -491,7 +503,8 @@ static void testLinkFail(void)
/* INST_IO doesn't accept string without @ */
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc");
- /* JSON_LINK dies properly */
+ /* JSON_LINK dies when expected */
+ testdbPutFieldOk("rJSON_LINK.INP", DBR_STRING, "{\"x\":true}");
testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":false}");
testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":null}");
testdbPutFieldFail(S_dbLib_badField, "rJSON_LINK.INP", DBR_STRING, "{\"x\":1}");
@@ -522,7 +535,7 @@ static void testLinkFail(void)
MAIN(dbPutLinkTest)
{
- testPlan(269);
+ testPlan(280);
testLinkParse();
testLinkFailParse();
testCADBSet();
diff --git a/src/ioc/db/test/jlinkz.c b/src/ioc/db/test/jlinkz.c
new file mode 100644
index 000000000..79b642ebd
--- /dev/null
+++ b/src/ioc/db/test/jlinkz.c
@@ -0,0 +1,232 @@
+/*************************************************************************\
+* Copyright (c) 2016 Michael Davidsaver
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+int numzalloc;
+
+typedef struct {
+ jlink base;
+ epicsMutexId lock;
+ unsigned isset:1;
+ unsigned isopen:1;
+ epicsInt32 value;
+} zpriv;
+
+
+static
+void z_open(struct link *plink)
+{
+ zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
+
+ if(priv->isopen)
+ testDiag("lsetZ re-open");
+ priv->isopen = 1;
+}
+
+static
+void z_remove(struct dbLocker *locker, struct link *plink)
+{
+ zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
+
+ epicsMutexLock(priv->lock);
+
+ if(!priv->isopen)
+ testDiag("lsetZ remove without open");
+
+ epicsMutexUnlock(priv->lock);
+
+ epicsAtomicDecrIntT(&numzalloc);
+
+ free(priv);
+ plink->value.json.jlink = NULL; /* paranoia */
+}
+
+static
+int z_connected(const struct link *plink)
+{
+ return 1; /* TODO: not provided should be connected */
+}
+
+static
+int z_dbftype(const struct link *plink)
+{
+ return DBF_LONG;
+}
+
+static
+long z_elements(const struct link *plink, long *nelements)
+{
+ *nelements = 1;
+ return 0;
+}
+
+static
+long z_getval(struct link *plink, short dbrType, void *pbuffer,
+ long *pnRequest)
+{
+ long ret;
+ long (*pconv)(const epicsInt32 *, void *, const dbAddr *) = dbFastGetConvertRoutine[DBF_LONG][dbrType];
+ zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
+
+ if(pnRequest && *pnRequest==0) return 0;
+
+ epicsMutexLock(priv->lock);
+ ret = (*pconv)(&priv->value, pbuffer, NULL);
+ epicsMutexUnlock(priv->lock);
+ if(ret==0 && pnRequest) *pnRequest = 1;
+ return ret;
+}
+
+/* TODO: atomicly get value and alarm */
+static
+long z_getalarm(const struct link *plink, epicsEnum16 *status,
+ epicsEnum16 *severity)
+{
+ zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
+ epicsEnum16 sevr, stat;
+
+ epicsMutexLock(priv->lock);
+ sevr = priv->isset ? 0 : INVALID_ALARM;
+ stat = priv->isset ? 0 : LINK_ALARM;
+ epicsMutexUnlock(priv->lock);
+
+ if(status) *status = stat;
+ if(severity) *severity = sevr;
+ return 0;
+}
+
+static
+long z_putval(struct link *plink, short dbrType,
+ const void *pbuffer, long nRequest)
+{
+ long ret;
+ long (*pconv)(epicsInt32 *, const void *, const dbAddr *) = dbFastPutConvertRoutine[DBF_LONG][dbrType];
+ zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
+
+ if(nRequest==0) return 0;
+
+ epicsMutexLock(priv->lock);
+ ret = (*pconv)(&priv->value, pbuffer, NULL);
+ epicsMutexUnlock(priv->lock);
+ return ret;
+}
+
+static lset lsetZ = {
+ 0, 0, /* non-const, non-volatile */
+ &z_open,
+ &z_remove,
+ NULL, NULL, NULL, /* load */
+ &z_connected,
+ &z_dbftype,
+ &z_elements,
+ &z_getval,
+ NULL, /* control limits */
+ NULL, /* display limits */
+ NULL, /* alarm limits */
+ NULL, /* prec */
+ NULL, /* units */
+ &z_getalarm,
+ NULL, /* time */
+ &z_putval,
+ NULL, /* putasync */
+ NULL, /* forward */
+};
+
+static
+jlink* z_alloc(short dbfType)
+{
+ zpriv *priv;
+ priv = calloc(1, sizeof(*priv));
+ if(!priv) return NULL;
+
+ epicsAtomicIncrIntT(&numzalloc);
+
+ return &priv->base;
+}
+
+static
+void z_free(jlink *pj)
+{
+ zpriv *priv = CONTAINER(pj, zpriv, base);
+
+ if(priv->isopen)
+ testDiag("lsetZ jlink free after open()\n");
+
+ epicsAtomicDecrIntT(&numzalloc);
+
+ free(priv);
+}
+
+static
+jlif_result z_int(jlink *pj, long num)
+{
+ zpriv *priv = CONTAINER(pj, zpriv, base);
+
+ priv->value = num;
+ priv->isset = 1;
+
+ return jlif_continue;
+}
+
+static
+jlif_key_result z_start(jlink *pj)
+{
+ return jlif_continue;
+}
+
+static
+jlif_result z_key(jlink *pj, const char *key, size_t len)
+{
+ if(strcmp(key,"fail")==0) return jlif_stop;
+ else return jlif_continue;
+}
+
+static
+jlif_result z_end(jlink *pj)
+{
+ return jlif_continue;
+}
+
+static
+struct lset* z_lset(const jlink *pj)
+{
+ return &lsetZ;
+}
+
+static jlif jlifZ = {
+ "z",
+ &z_alloc,
+ &z_free,
+ NULL, /* null */
+ NULL, /* bool */
+ &z_int,
+ NULL, /* double */
+ NULL, /* string */
+ &z_start,
+ &z_key,
+ &z_end,
+ NULL, /* start array */
+ NULL, /* end array */
+ NULL, /* end child */
+ &z_lset,
+ NULL, /* report */
+ NULL /* map child */
+};
+
+epicsExportAddress(jlif, jlifZ);
diff --git a/src/ioc/db/test/jlinkz.dbd b/src/ioc/db/test/jlinkz.dbd
new file mode 100644
index 000000000..5408a88b6
--- /dev/null
+++ b/src/ioc/db/test/jlinkz.dbd
@@ -0,0 +1 @@
+link("z", "jlifZ")
From 2bb02e732aa0131f5661a06c9babe00e3466d79d Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Tue, 28 Feb 2017 20:06:42 -0600
Subject: [PATCH 069/112] libCom: add errSymMsg() error message lookup
Like errSymLookup() but always returns a static string.
---
src/libCom/error/errMdef.h | 1 +
src/libCom/error/errSymLib.c | 38 ++++++++++++++++++++++++------------
2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/src/libCom/error/errMdef.h b/src/libCom/error/errMdef.h
index e511d912b..163b063f2 100644
--- a/src/libCom/error/errMdef.h
+++ b/src/libCom/error/errMdef.h
@@ -53,6 +53,7 @@ extern "C" {
#define M_time (529 <<16) /*epicsTime*/
epicsShareFunc void epicsShareAPI errSymLookup(long status, char *pBuf, unsigned bufLength);
+epicsShareFunc const char* errSymMsg(long status);
epicsShareFunc void epicsShareAPI errSymTest(unsigned short modnum, unsigned short begErrNum, unsigned short endErrNum);
epicsShareFunc void epicsShareAPI errSymTestPrint(long errNum);
epicsShareFunc int epicsShareAPI errSymBld(void);
diff --git a/src/libCom/error/errSymLib.c b/src/libCom/error/errSymLib.c
index f75577b23..74d766810 100644
--- a/src/libCom/error/errSymLib.c
+++ b/src/libCom/error/errSymLib.c
@@ -192,11 +192,9 @@ static void errRawCopy ( long statusToDecode, char *pBuf, unsigned bufLength )
assert ( nChar < bufLength );
}
}
-
-/****************************************************************
- * errSymLookup
- ***************************************************************/
-void epicsShareAPI errSymLookup (long status, char * pBuf, unsigned bufLength)
+
+static
+const char* errSymLookupInternal(long status)
{
unsigned modNum;
unsigned hashInd;
@@ -211,9 +209,7 @@ void epicsShareAPI errSymLookup (long status, char * pBuf, unsigned bufLength)
if ( modNum <= 500 ) {
const char * pStr = strerror ((int) status);
if ( pStr ) {
- strncpy(pBuf, pStr,bufLength);
- pBuf[bufLength-1] = '\0';
- return;
+ return pStr;
}
}
else {
@@ -222,17 +218,35 @@ void epicsShareAPI errSymLookup (long status, char * pBuf, unsigned bufLength)
pNextNode = *phashnode;
while(pNextNode) {
if(pNextNode->errNum==status){
- strncpy(pBuf, pNextNode->message, bufLength);
- pBuf[bufLength-1] = '\0';
- return;
+ return pNextNode->message;
}
phashnode = &pNextNode->hashnode;
pNextNode = *phashnode;
}
}
+ return NULL;
+}
+
+const char* errSymMsg(long status)
+{
+ const char* msg = errSymLookupInternal(status);
+ return msg ? msg : "";
+}
+
+/****************************************************************
+ * errSymLookup
+ ***************************************************************/
+void epicsShareAPI errSymLookup (long status, char * pBuf, unsigned bufLength)
+{
+ const char* msg = errSymLookupInternal(status);
+ if(msg) {
+ strncpy(pBuf, msg, bufLength);
+ pBuf[bufLength-1] = '\0';
+ return;
+ }
errRawCopy(status, pBuf, bufLength);
}
-
+
/****************************************************************
* errSymDump
***************************************************************/
From 46993a5e381bc6324603aada8afd5b3ec80fca7d Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Tue, 28 Feb 2017 20:09:21 -0600
Subject: [PATCH 070/112] dbUnitTest: more informative dbPutField*()
---
src/ioc/db/dbUnitTest.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/ioc/db/dbUnitTest.c b/src/ioc/db/dbUnitTest.c
index d0d5906c8..f4994c854 100644
--- a/src/ioc/db/dbUnitTest.c
+++ b/src/ioc/db/dbUnitTest.c
@@ -152,7 +152,7 @@ void testdbPutFieldOk(const char* pv, short dbrType, ...)
ret = testdbVPutField(pv, dbrType, ap);
va_end(ap);
- testOk(ret==0, "dbPutField(%s, %d, ...) == %ld", pv, dbrType, ret);
+ testOk(ret==0, "dbPutField(%s, %d, ...) -> %ld (%s)", pv, dbrType, ret, errSymMsg(ret));
}
void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
@@ -164,10 +164,8 @@ void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
ret = testdbVPutField(pv, dbrType, ap);
va_end(ap);
- if(ret==status)
- testPass("dbPutField(\"%s\", %d, ...) == %ld", pv, dbrType, status);
- else
- testFail("dbPutField(\"%s\", %d, ...) != %ld (%ld)", pv, dbrType, status, ret);
+ testOk(ret==status, "dbPutField(\"%s\", %d, ...) -> %ld (%s) == %ld (%s)",
+ pv, dbrType, status, errSymMsg(status), ret, errSymMsg(ret));
}
void testdbGetFieldEqual(const char* pv, short dbrType, ...)
From 8069d9d80b87313bd334d5a1f392eac3d09b1796 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 28 Feb 2017 20:55:05 -0600
Subject: [PATCH 071/112] dbUnitTest: Improve output slightly
---
src/ioc/db/dbUnitTest.c | 18 +++++++++---------
src/libCom/error/makeStatTbl.pl | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/ioc/db/dbUnitTest.c b/src/ioc/db/dbUnitTest.c
index f4994c854..35264abdd 100644
--- a/src/ioc/db/dbUnitTest.c
+++ b/src/ioc/db/dbUnitTest.c
@@ -106,8 +106,8 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap)
DBADDR addr;
union anybuf pod;
- if(dbNameToAddr(pv, &addr)) {
- testFail("Missing PV %s", pv);
+ if (dbNameToAddr(pv, &addr)) {
+ testFail("Missing PV \"%s\"", pv);
return S_dbLib_recNotFound;
}
@@ -152,7 +152,7 @@ void testdbPutFieldOk(const char* pv, short dbrType, ...)
ret = testdbVPutField(pv, dbrType, ap);
va_end(ap);
- testOk(ret==0, "dbPutField(%s, %d, ...) -> %ld (%s)", pv, dbrType, ret, errSymMsg(ret));
+ testOk(ret==0, "dbPutField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, ret, errSymMsg(ret));
}
void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
@@ -164,7 +164,7 @@ void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
ret = testdbVPutField(pv, dbrType, ap);
va_end(ap);
- testOk(ret==status, "dbPutField(\"%s\", %d, ...) -> %ld (%s) == %ld (%s)",
+ testOk(ret==status, "dbPutField(\"%s\", %d, ...) -> %#lx (%s) == %#lx (%s)",
pv, dbrType, status, errSymMsg(status), ret, errSymMsg(ret));
}
@@ -185,13 +185,13 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
long status;
if(dbNameToAddr(pv, &addr)) {
- testFail("Missing PV %s", pv);
+ testFail("Missing PV \"%s\"", pv);
return;
}
status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL);
- if(status) {
- testFail("dbGetField(\"%s\",%d,...) returns %ld", pv, dbrType, status);
+ if (status) {
+ testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));
return;
}
@@ -224,8 +224,8 @@ dbCommon* testdbRecordPtr(const char* pv)
{
DBADDR addr;
- if(dbNameToAddr(pv, &addr))
- testAbort("Missing record %s", pv);
+ if (dbNameToAddr(pv, &addr))
+ testAbort("Missing record \"%s\"", pv);
return addr.precord;
}
diff --git a/src/libCom/error/makeStatTbl.pl b/src/libCom/error/makeStatTbl.pl
index 8bc63e23c..4f53901f3 100644
--- a/src/libCom/error/makeStatTbl.pl
+++ b/src/libCom/error/makeStatTbl.pl
@@ -86,7 +86,7 @@ foreach $line ( @err_sym_line )
{
print OUT "$line\n";
# define S_symbol /* comment */
- if ($line =~ m'[ \t#]define[ \t]*(S_[A-Za-z0-9_]+).*\/\*(.+)\*\/')
+ if ($line =~ m'[ \t#]define[ \t]*(S_[A-Za-z0-9_]+).*\/\* ?(.+?) ?\*\/')
{
$symbol[$count] = $1;
$comment[$count]= $2;
From 6377c2e1e4babdefe5b3a98401a85a8d693c1fec Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Tue, 28 Feb 2017 20:58:11 -0600
Subject: [PATCH 072/112] db/test: dbPutLinkTest include json links and more
---
src/ioc/db/test/Makefile | 2 +-
src/ioc/db/test/dbPutLinkTest.c | 69 ++++++++++++++++++++++++++++++-
src/ioc/db/test/dbPutLinkTestJ.db | 12 ++++++
src/ioc/db/test/devx.c | 3 +-
src/ioc/db/test/jlinkz.c | 44 ++++++++++++++------
src/ioc/db/test/jlinkz.h | 27 ++++++++++++
6 files changed, 140 insertions(+), 17 deletions(-)
create mode 100644 src/ioc/db/test/dbPutLinkTestJ.db
create mode 100644 src/ioc/db/test/jlinkz.h
diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile
index 4fe389cbf..6c9f3e9c1 100644
--- a/src/ioc/db/test/Makefile
+++ b/src/ioc/db/test/Makefile
@@ -57,7 +57,7 @@ dbPutLinkTest_SRCS += dbPutLinkTest.c
dbPutLinkTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbPutLinkTest.c
TESTS += dbPutLinkTest
-TESTFILES += ../dbPutLinkTest.db ../dbBadLink.db
+TESTFILES += ../dbPutLinkTest.db ../dbPutLinkTestJ.db ../dbBadLink.db
TESTPROD_HOST += dbLockTest
dbLockTest_SRCS += dbLockTest.c
diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c
index e46d2c4d9..d8024c82a 100644
--- a/src/ioc/db/test/dbPutLinkTest.c
+++ b/src/ioc/db/test/dbPutLinkTest.c
@@ -24,8 +24,10 @@
#include "osiFileName.h"
#include "dbmf.h"
#include "errlog.h"
+#include
#include "xRecord.h"
+#include "jlinkz.h"
#include "testMain.h"
@@ -533,9 +535,73 @@ static void testLinkFail(void)
testdbCleanup();
}
+static
+void testNumZ(int expect)
+{
+ int numz = epicsAtomicGetIntT(&numzalloc);
+ testOk(numz==expect, "numzalloc==%d (%d)", expect, numz);
+}
+
+static
+void testJLink(void)
+{
+ testDiag("Test json link setup/retarget");
+
+ testNumZ(0);
+
+ testDiag("Link parsing failures");
+ testdbPrepare();
+
+ testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
+
+ dbTestIoc_registerRecordDeviceDriver(pdbbase);
+
+ testdbReadDatabase("dbPutLinkTest.db", NULL, NULL);
+ testdbReadDatabase("dbPutLinkTestJ.db", NULL, NULL);
+
+ testNumZ(0);
+
+ eltc(0);
+ testIocInitOk();
+ eltc(1);
+
+ testNumZ(3);
+
+ testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
+ testdbPutFieldOk("j2.PROC", DBF_LONG, 1);
+ testdbPutFieldOk("j3.PROC", DBF_LONG, 1);
+
+ testdbGetFieldEqual("j1.INP", DBF_STRING, "{\"z\":{\"good\":1}}");
+ testdbGetFieldEqual("j1.VAL", DBF_LONG, 1);
+ testdbGetFieldEqual("j2.VAL", DBF_LONG, 2);
+ testdbGetFieldEqual("j3.VAL", DBF_LONG, 3);
+
+ testNumZ(3);
+
+ testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}");
+ testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
+ testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
+
+ testNumZ(3);
+
+ testdbPutFieldFail(S_dbLib_badField, "j1.INP", DBF_STRING, "{\"z\":{\"fail\":5}}");
+ testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
+ testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
+ /* put failure in parsing stage doesn't modify link */
+ testdbGetFieldEqual("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}");
+
+ testNumZ(3);
+
+ testIocShutdownOk();
+
+ testNumZ(0);
+
+ testdbCleanup();
+}
+
MAIN(dbPutLinkTest)
{
- testPlan(280);
+ testPlan(301);
testLinkParse();
testLinkFailParse();
testCADBSet();
@@ -543,5 +609,6 @@ MAIN(dbPutLinkTest)
testHWMod();
testLinkInitFail();
testLinkFail();
+ testJLink();
return testDone();
}
diff --git a/src/ioc/db/test/dbPutLinkTestJ.db b/src/ioc/db/test/dbPutLinkTestJ.db
new file mode 100644
index 000000000..25cf4c822
--- /dev/null
+++ b/src/ioc/db/test/dbPutLinkTestJ.db
@@ -0,0 +1,12 @@
+
+record(x, "j1") {
+ field(INP, {z:{good:1}})
+}
+
+record(x, "j2") {
+ field(INP, {z:{good:2}})
+}
+
+record(x, "j3") {
+ field(INP, {z:{good:3}})
+}
diff --git a/src/ioc/db/test/devx.c b/src/ioc/db/test/devx.c
index 6cd01202a..c5527f14e 100644
--- a/src/ioc/db/test/devx.c
+++ b/src/ioc/db/test/devx.c
@@ -147,8 +147,7 @@ static long xsoft_init_record(xRecord *prec)
static long xsoft_read(xRecord *prec)
{
- dbGetLink(&prec->inp, DBR_DOUBLE, &prec->val, NULL, NULL);
- return 0;
+ return dbGetLink(&prec->inp, DBR_LONG, &prec->val, NULL, NULL);
}
static struct xdset devxSoft = {
diff --git a/src/ioc/db/test/jlinkz.c b/src/ioc/db/test/jlinkz.c
index 79b642ebd..6602a22b0 100644
--- a/src/ioc/db/test/jlinkz.c
+++ b/src/ioc/db/test/jlinkz.c
@@ -14,19 +14,15 @@
#include
#include
#include
-#include
#include
+#include
#include
-int numzalloc;
+#define epicsExportSharedSymbols
-typedef struct {
- jlink base;
- epicsMutexId lock;
- unsigned isset:1;
- unsigned isopen:1;
- epicsInt32 value;
-} zpriv;
+#include "jlinkz.h"
+
+int numzalloc;
static
@@ -37,6 +33,7 @@ void z_open(struct link *plink)
if(priv->isopen)
testDiag("lsetZ re-open");
priv->isopen = 1;
+ testDiag("Open jlinkz %p", priv);
}
static
@@ -51,8 +48,11 @@ void z_remove(struct dbLocker *locker, struct link *plink)
epicsMutexUnlock(priv->lock);
+ testDiag("Remove/free jlinkz %p", priv);
+
epicsAtomicDecrIntT(&numzalloc);
+ epicsMutexDestroy(priv->lock);
free(priv);
plink->value.json.jlink = NULL; /* paranoia */
}
@@ -153,11 +153,20 @@ jlink* z_alloc(short dbfType)
{
zpriv *priv;
priv = calloc(1, sizeof(*priv));
- if(!priv) return NULL;
+ if(!priv) goto fail;
+
+ priv->lock = epicsMutexCreate();
+ if(!priv->lock) goto fail;
epicsAtomicIncrIntT(&numzalloc);
+ testDiag("Alloc jlinkz %p", priv);
+
return &priv->base;
+fail:
+ if(priv && priv->lock) epicsMutexDestroy(priv->lock);
+ free(priv);
+ return NULL;
}
static
@@ -166,10 +175,13 @@ void z_free(jlink *pj)
zpriv *priv = CONTAINER(pj, zpriv, base);
if(priv->isopen)
- testDiag("lsetZ jlink free after open()\n");
+ testDiag("lsetZ jlink free after open()");
+
+ testDiag("Free jlinkz %p", priv);
epicsAtomicDecrIntT(&numzalloc);
+ epicsMutexDestroy(priv->lock);
free(priv);
}
@@ -193,8 +205,14 @@ jlif_key_result z_start(jlink *pj)
static
jlif_result z_key(jlink *pj, const char *key, size_t len)
{
- if(strcmp(key,"fail")==0) return jlif_stop;
- else return jlif_continue;
+ zpriv *priv = CONTAINER(pj, zpriv, base);
+
+ if(len==4 && strncmp(key,"fail", len)==0) {
+ testDiag("Found fail key jlinkz %p", priv);
+ return jlif_stop;
+ } else {
+ return jlif_continue;
+ }
}
static
diff --git a/src/ioc/db/test/jlinkz.h b/src/ioc/db/test/jlinkz.h
new file mode 100644
index 000000000..5c34d2eec
--- /dev/null
+++ b/src/ioc/db/test/jlinkz.h
@@ -0,0 +1,27 @@
+/*************************************************************************\
+* Copyright (c) 2016 Michael Davidsaver
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+
+#ifndef JLINKZ_H
+#define JLINKZ_H
+
+#include
+#include
+#include
+
+#include
+
+epicsShareExtern
+int numzalloc;
+
+typedef struct {
+ jlink base;
+ epicsMutexId lock;
+ unsigned isset:1;
+ unsigned isopen:1;
+ epicsInt32 value;
+} zpriv;
+
+#endif /* JLINKZ_H */
From 1d749ac7e7d3c1ac826865eddeb1d410dde037ec Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Tue, 28 Feb 2017 21:00:57 -0600
Subject: [PATCH 073/112] dbLock: add assert in dbScanLock
catch locking attempts before iocInit()
---
src/ioc/db/dbLock.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/ioc/db/dbLock.c b/src/ioc/db/dbLock.c
index d0f266795..7b04daa4e 100644
--- a/src/ioc/db/dbLock.c
+++ b/src/ioc/db/dbLock.c
@@ -190,6 +190,8 @@ void dbScanLock(dbCommon *precord)
lockRecord * const lr = precord->lset;
lockSet *ls;
+ assert(lr);
+
ls = dbLockGetRef(lr);
assert(epicsAtomicGetIntT(&ls->refcount)>0);
From 17bd1ae6d03c31c0b4703b7c99354dccf6b0924e Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 3 Mar 2017 12:23:36 -0600
Subject: [PATCH 074/112] db/test: Fix warning from clang
---
src/ioc/db/test/jlinkz.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ioc/db/test/jlinkz.c b/src/ioc/db/test/jlinkz.c
index 6602a22b0..f283f814e 100644
--- a/src/ioc/db/test/jlinkz.c
+++ b/src/ioc/db/test/jlinkz.c
@@ -199,7 +199,7 @@ jlif_result z_int(jlink *pj, long num)
static
jlif_key_result z_start(jlink *pj)
{
- return jlif_continue;
+ return jlif_key_continue;
}
static
From d2db634ed2de7c20063e5a19282e099bbe060cb6 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 19 Apr 2017 16:44:11 -0500
Subject: [PATCH 075/112] Add dbLinkDoLocked() support
New lset method, implemented in all link types.
Includes a test for the dbCa implementation.
---
src/ioc/db/dbCa.c | 13 +++++++-
src/ioc/db/dbConstLink.c | 3 +-
src/ioc/db/dbDbLink.c | 8 +++--
src/ioc/db/dbLink.c | 12 ++++++++
src/ioc/db/dbLink.h | 8 +++++
src/ioc/db/test/dbCaLinkTest.c | 56 +++++++++++++++++++++++++++++++++-
src/ioc/db/test/jlinkz.c | 1 +
src/ioc/db/test/xLink.c | 2 +-
src/std/link/lnkCalc.c | 7 ++++-
src/std/link/lnkConst.c | 2 +-
10 files changed, 103 insertions(+), 9 deletions(-)
diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c
index 3b223be89..be954be12 100644
--- a/src/ioc/db/dbCa.c
+++ b/src/ioc/db/dbCa.c
@@ -684,6 +684,17 @@ static long getUnits(const struct link *plink,
return gotAttributes ? 0 : -1;
}
+static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
+{
+ caLink *pca;
+ long status;
+
+ pcaGetCheck
+ status = rtn(plink, priv);
+ epicsMutexUnlock(pca->lock);
+ return status;
+}
+
static void scanComplete(void *raw, dbCommon *prec)
{
caLink *pca = raw;
@@ -727,7 +738,7 @@ static lset dbCa_lset = {
getPrecision, getUnits,
getAlarm, getTimeStamp,
dbCaPutLink, dbCaPutAsync,
- scanForward
+ scanForward, doLocked
};
static void connectionCallback(struct connection_handler_args arg)
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 7d196ec88..00eeb8e17 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -135,6 +135,5 @@ static lset dbConst_lset = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
- NULL
+ NULL, NULL
};
-
diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c
index 87e78b1b0..8263293e9 100644
--- a/src/ioc/db/dbDbLink.c
+++ b/src/ioc/db/dbDbLink.c
@@ -337,6 +337,11 @@ static void dbDbScanFwdLink(struct link *plink)
dbScanPassive(precord, paddr->precord);
}
+static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
+{
+ return rtn(plink, priv);
+}
+
static lset dbDb_lset = {
0, 0, /* not Constant, not Volatile */
NULL, dbDbRemoveLink,
@@ -348,6 +353,5 @@ static lset dbDb_lset = {
dbDbGetPrecision, dbDbGetUnits,
dbDbGetAlarm, dbDbGetTimeStamp,
dbDbPutValue, NULL,
- dbDbScanFwdLink
+ dbDbScanFwdLink, doLocked
};
-
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index bb74f91c6..d383a3cbe 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -414,6 +414,18 @@ void dbScanFwdLink(struct link *plink)
plset->scanForward(plink);
}
+long dbLinkDoLocked(struct link *plink, dbLinkUserCallback rtn,
+ void *priv)
+{
+ lset *plset = plink->lset;
+
+ if (!rtn || !plset || !plset->doLocked)
+ return S_db_noLSET;
+
+ return plset->doLocked(plink, rtn, priv);
+}
+
+
/* Helper functions for long string support */
long dbGetLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index cf7ff0433..6f5858b65 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -27,6 +27,8 @@ extern "C" {
struct dbLocker;
+typedef long (*dbLinkUserCallback)(struct link *plink, void *priv);
+
typedef struct lset {
/* Characteristics of the link type */
const unsigned isConstant:1;
@@ -71,6 +73,9 @@ typedef struct lset {
/* Process */
void (*scanForward)(struct link *plink);
+
+ /* Atomicity */
+ long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
} lset;
#define dbGetSevr(link, sevr) \
@@ -117,6 +122,9 @@ epicsShareFunc long dbPutLinkAsync(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
epicsShareFunc void dbScanFwdLink(struct link *plink);
+epicsShareFunc long dbLinkDoLocked(struct link *plink, dbLinkUserCallback rtn,
+ void *priv);
+
epicsShareFunc long dbLoadLinkLS(struct link *plink, char *pbuffer,
epicsUInt32 size, epicsUInt32 *plen);
epicsShareFunc long dbGetLinkLS(struct link *plink, char *pbuffer,
diff --git a/src/ioc/db/test/dbCaLinkTest.c b/src/ioc/db/test/dbCaLinkTest.c
index e1955a5ad..8d563a076 100644
--- a/src/ioc/db/test/dbCaLinkTest.c
+++ b/src/ioc/db/test/dbCaLinkTest.c
@@ -107,6 +107,39 @@ void putLink(DBLINK *plink, short dbr, const void*buf, long nReq)
waitEvent = NULL;
}
+static long getTwice(struct link *psrclnk, void *dummy)
+{
+ epicsInt32 val1, val2;
+ long status = dbGetLink(psrclnk, DBR_LONG, &val1, 0, 0);
+
+ if (status) return status;
+
+ epicsThreadSleep(0.5);
+ status = dbGetLink(psrclnk, DBR_LONG, &val2, 0, 0);
+ if (status) return status;
+
+ testDiag("val1 = %d, val2 = %d", val1, val2);
+ return (val1 == val2) ? 0 : -1;
+}
+
+static void countUp(void *parm)
+{
+ xRecord *ptarg = (xRecord *)parm;
+ epicsInt32 val;
+
+ for (val = 1; val < 10; val++) {
+ dbScanLock((dbCommon*)ptarg);
+ ptarg->val = val;
+ db_post_events(ptarg, &ptarg->val, DBE_VALUE|DBE_ALARM|DBE_ARCHIVE);
+ dbScanUnlock((dbCommon*)ptarg);
+
+ epicsThreadSleep(0.1);
+ }
+
+ if (waitEvent)
+ epicsEventMustTrigger(waitEvent);
+}
+
static void testNativeLink(void)
{
xRecord *psrc, *ptarg;
@@ -166,6 +199,27 @@ static void testNativeLink(void)
testOk1(ptarg->val==1010);
dbScanUnlock((dbCommon*)ptarg);
+ assert(!waitEvent);
+ waitEvent = epicsEventMustCreate(epicsEventEmpty);
+
+ /* Start counter */
+ epicsThreadCreate("countUp", epicsThreadPriorityHigh,
+ epicsThreadGetStackSize(epicsThreadStackSmall), countUp, ptarg);
+
+ dbScanLock((dbCommon*)psrc);
+ /* Check that unlocked gets change */
+ temp = getTwice(psrclnk, NULL);
+ testOk(temp == -1, "unlocked, getTwice returned %d (-1)", temp);
+
+ /* Check locked gets are atomic */
+ temp = dbLinkDoLocked(psrclnk, getTwice, NULL);
+ testOk(temp == 0, "locked, getTwice returned %d (0)", temp);
+ dbScanUnlock((dbCommon*)psrc);
+
+ epicsEventMustWait(waitEvent);
+ epicsEventDestroy(waitEvent);
+ waitEvent = NULL;
+
testIocShutdownOk();
testdbCleanup();
@@ -598,7 +652,7 @@ static void testCAC(void)
MAIN(dbCaLinkTest)
{
- testPlan(99);
+ testPlan(101);
testNativeLink();
testStringLink();
testCP();
diff --git a/src/ioc/db/test/jlinkz.c b/src/ioc/db/test/jlinkz.c
index f283f814e..7bb8b831e 100644
--- a/src/ioc/db/test/jlinkz.c
+++ b/src/ioc/db/test/jlinkz.c
@@ -146,6 +146,7 @@ static lset lsetZ = {
&z_putval,
NULL, /* putasync */
NULL, /* forward */
+ NULL, /* doLocked */
};
static
diff --git a/src/ioc/db/test/xLink.c b/src/ioc/db/test/xLink.c
index f6dfab95c..12175f44e 100644
--- a/src/ioc/db/test/xLink.c
+++ b/src/ioc/db/test/xLink.c
@@ -73,7 +73,7 @@ static lset xlink_lset = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
- NULL
+ NULL, NULL
};
static jlif xlinkIf = {
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 1b3222a34..a7ec9126a 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -597,6 +597,11 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status,
return 0;
}
+static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
+{
+ return rtn(plink, priv);
+}
+
/************************* Interface Tables *************************/
@@ -610,7 +615,7 @@ static lset lnkCalc_lset = {
lnkCalc_getPrecision, lnkCalc_getUnits,
lnkCalc_getAlarm, NULL,
NULL, NULL,
- NULL
+ NULL, doLocked
};
static jlif lnkCalcIf = {
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 7062ff1f9..f3ff5d004 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -551,7 +551,7 @@ static lset lnkConst_lset = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
- NULL
+ NULL, NULL
};
static jlif lnkConstIf = {
From 89f13aa51bac2a945a94590ea6b9cf165c7bcada Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 19 Apr 2017 16:50:38 -0500
Subject: [PATCH 076/112] Modify soft devices to synchronize TSEL=-2 timestamps
Use dbLinkDoLocked() to ensure a timestamp set by TSEL=-2
comes from the same update as the value.
---
documentation/RELEASE_NOTES.html | 11 ++++++++
src/std/dev/devAaiSoft.c | 19 ++++++++++---
src/std/dev/devAiSoft.c | 46 +++++++++++++++++++++-----------
src/std/dev/devAiSoftRaw.c | 22 ++++++++++++---
src/std/dev/devBiSoft.c | 18 ++++++++++---
src/std/dev/devBiSoftRaw.c | 18 ++++++++++---
src/std/dev/devEventSoft.c | 19 ++++++++++---
src/std/dev/devLiSoft.c | 18 ++++++++++---
src/std/dev/devLsiSoft.c | 17 +++++++++---
src/std/dev/devMbbiDirectSoft.c | 18 ++++++++++---
src/std/dev/devMbbiSoft.c | 18 ++++++++++---
src/std/dev/devMbbiSoftRaw.c | 18 ++++++++++---
src/std/dev/devSASoft.c | 19 ++++++++++---
src/std/dev/devSiSoft.c | 20 ++++++++++----
src/std/dev/devWfSoft.c | 17 +++++++++---
15 files changed, 236 insertions(+), 62 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 17b5946c6..4da494f4a 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -20,6 +20,17 @@
-->
+Synchronized Timestamps with TSEL=-2
+
+Most Soft Channel input device support routines have supported fetching the
+timestamp through the INP link along with the input data. However before now
+there was no guarantee that the timestamp provided by a CA link came from the
+same update as the data, since the two were read at separate times without
+maintaining a lock on the CA input buffer. This shortcoming has been fixed as
+part of the new link support code, which allows code using a link to pass a
+subroutine to the link type to be run with the link locked. The subroutine may
+make multiple requests for metadata from the link, but must not block.
+
Device Support Address Type JSON_LINK
Device support may be written to expect hardware addresses in the new
diff --git a/src/std/dev/devAaiSoft.c b/src/std/dev/devAaiSoft.c
index ab6476ea9..a9d1c7615 100644
--- a/src/std/dev/devAaiSoft.c
+++ b/src/std/dev/devAaiSoft.c
@@ -75,11 +75,11 @@ static long init_record(aaiRecord *prec)
return 0;
}
-static long read_aai(aaiRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
+ aaiRecord *prec = (aaiRecord *) pinp->precord;
long nRequest = prec->nelm;
- long status = dbGetLink(prec->simm == menuYesNoYES ? &prec->siol :
- &prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
+ long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
if (!status && nRequest > 0) {
prec->nord = nRequest;
@@ -87,7 +87,18 @@ static long read_aai(aaiRecord *prec)
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
}
return status;
}
+
+static long read_aai(aaiRecord *prec)
+{
+ struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp;
+ long status = dbLinkDoLocked(pinp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(pinp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devAiSoft.c b/src/std/dev/devAiSoft.c
index 74a2a759a..85c78c242 100644
--- a/src/std/dev/devAiSoft.c
+++ b/src/std/dev/devAiSoft.c
@@ -57,29 +57,43 @@ static long init_record(aiRecord *prec)
return 0;
}
+static long readLocked(struct link *pinp, void *dummy)
+{
+ aiRecord *prec = (aiRecord *) pinp->precord;
+ double val;
+ long status = dbGetLink(pinp, DBR_DOUBLE, &val, 0, 0);
+
+ if (status) return status;
+
+ /* Apply smoothing algorithm */
+ if (prec->smoo != 0.0 && prec->dpvt && finite(prec->val))
+ prec->val = val * (1.00 - prec->smoo) + (prec->val * prec->smoo);
+ else
+ prec->val = val;
+
+ prec->udf = FALSE;
+ prec->dpvt = &devAiSoft; /* Any non-zero value */
+
+ if (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime)
+ dbGetTimeStamp(pinp, &prec->time);
+
+ return 0;
+}
+
static long read_ai(aiRecord *prec)
{
- double val;
+ long status;
if (dbLinkIsConstant(&prec->inp))
return 2;
- if (!dbGetLink(&prec->inp, DBR_DOUBLE, &val, 0, 0)) {
+ status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
- /* Apply smoothing algorithm */
- if (prec->smoo != 0.0 && prec->dpvt && finite(prec->val))
- prec->val = val * (1.00 - prec->smoo) + (prec->val * prec->smoo);
- else
- prec->val = val;
-
- prec->udf = FALSE;
- prec->dpvt = &devAiSoft; /* Any non-zero value */
-
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
- } else {
+ if (status)
prec->dpvt = NULL;
- }
+
return 2;
}
diff --git a/src/std/dev/devAiSoftRaw.c b/src/std/dev/devAiSoftRaw.c
index 1ec289b38..b06e245d2 100644
--- a/src/std/dev/devAiSoftRaw.c
+++ b/src/std/dev/devAiSoftRaw.c
@@ -55,12 +55,26 @@ static long init_record(aiRecord *prec)
return 0;
}
-static long read_ai(aiRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0) &&
- dbLinkIsConstant(&prec->tsel) &&
+ aiRecord *prec = (aiRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_LONG, &prec->rval, 0, 0);
+
+ if (status) return status;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
return 0;
}
+
+static long read_ai(aiRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devBiSoft.c b/src/std/dev/devBiSoft.c
index a9364debc..b1b3c17a3 100644
--- a/src/std/dev/devBiSoft.c
+++ b/src/std/dev/devBiSoft.c
@@ -53,13 +53,25 @@ static long init_record(biRecord *prec)
return 0;
}
-static long read_bi(biRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- if (!dbGetLink(&prec->inp, DBR_USHORT, &prec->val, 0, 0)) {
+ biRecord *prec = (biRecord *) pinp->precord;
+
+ if (!dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0)) {
prec->udf = FALSE;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
}
return 2;
}
+
+static long read_bi(biRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devBiSoftRaw.c b/src/std/dev/devBiSoftRaw.c
index 2d8dc25e5..afddd4712 100644
--- a/src/std/dev/devBiSoftRaw.c
+++ b/src/std/dev/devBiSoftRaw.c
@@ -52,12 +52,24 @@ static long init_record(biRecord *prec)
return 0;
}
-static long read_bi(biRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- if (!dbGetLink(&prec->inp, DBR_ULONG, &prec->rval, 0, 0) &&
+ biRecord *prec = (biRecord *) pinp->precord;
+
+ if (!dbGetLink(pinp, DBR_ULONG, &prec->rval, 0, 0) &&
dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
return 0;
}
+
+static long read_bi(biRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devEventSoft.c b/src/std/dev/devEventSoft.c
index c9a5f273e..b5cc02f5c 100644
--- a/src/std/dev/devEventSoft.c
+++ b/src/std/dev/devEventSoft.c
@@ -53,13 +53,14 @@ static long init_record(eventRecord *prec)
return 0;
}
-static long read_event(eventRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
+ eventRecord *prec = (eventRecord *) pinp->precord;
long status;
char newEvent[MAX_STRING_SIZE];
- if (!dbLinkIsConstant(&prec->inp)) {
- status = dbGetLink(&prec->inp, DBR_STRING, newEvent, 0, 0);
+ if (!dbLinkIsConstant(pinp)) {
+ status = dbGetLink(pinp, DBR_STRING, newEvent, 0, 0);
if (status) return status;
if (strcmp(newEvent, prec->val) != 0) {
strcpy(prec->val, newEvent);
@@ -69,6 +70,16 @@ static long read_event(eventRecord *prec)
prec->udf = FALSE;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
return 0;
}
+
+static long read_event(eventRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devLiSoft.c b/src/std/dev/devLiSoft.c
index 0752b4f30..b48baccf9 100644
--- a/src/std/dev/devLiSoft.c
+++ b/src/std/dev/devLiSoft.c
@@ -54,14 +54,24 @@ static long init_record(longinRecord *prec)
return 0;
}
-static long read_longin(longinRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- long status;
+ longinRecord *prec = (longinRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_LONG, &prec->val, 0, 0);
- status = dbGetLink(&prec->inp, DBR_LONG, &prec->val, 0, 0);
if (!status &&
dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
+ return status;
+}
+
+static long read_longin(longinRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
return status;
}
diff --git a/src/std/dev/devLsiSoft.c b/src/std/dev/devLsiSoft.c
index aadd48f0d..8ec5ea2fa 100644
--- a/src/std/dev/devLsiSoft.c
+++ b/src/std/dev/devLsiSoft.c
@@ -24,14 +24,25 @@ static long init_record(lsiRecord *prec)
return 0;
}
-static long read_string(lsiRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- long status = dbGetLinkLS(&prec->inp, prec->val, prec->sizv, &prec->len);
+ lsiRecord *prec = (lsiRecord *) pinp->precord;
+ long status = dbGetLinkLS(pinp, prec->val, prec->sizv, &prec->len);
if (!status &&
dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
+
+ return status;
+}
+
+static long read_string(lsiRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
return status;
}
diff --git a/src/std/dev/devMbbiDirectSoft.c b/src/std/dev/devMbbiDirectSoft.c
index 27dd2eb1f..8160bdfad 100644
--- a/src/std/dev/devMbbiDirectSoft.c
+++ b/src/std/dev/devMbbiDirectSoft.c
@@ -54,13 +54,25 @@ static long init_record(mbbiDirectRecord *prec)
return 0;
}
-static long read_mbbi(mbbiDirectRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- if (!dbGetLink(&prec->inp, DBR_USHORT, &prec->val, 0, 0)) {
+ mbbiDirectRecord *prec = (mbbiDirectRecord *) pinp->precord;
+
+ if (!dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0)) {
prec->udf = FALSE;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
}
return 2;
}
+
+static long read_mbbi(mbbiDirectRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devMbbiSoft.c b/src/std/dev/devMbbiSoft.c
index 406e8b6ec..b7411aea4 100644
--- a/src/std/dev/devMbbiSoft.c
+++ b/src/std/dev/devMbbiSoft.c
@@ -54,14 +54,26 @@ static long init_record(mbbiRecord *prec)
return 0;
}
-static long read_mbbi(mbbiRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- if (!dbGetLink(&prec->inp, DBR_USHORT, &prec->val, 0, 0)) {
+ mbbiRecord *prec = (mbbiRecord *) pinp->precord;
+
+ if (!dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0)) {
prec->udf = FALSE;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
}
return 2;
}
+
+static long read_mbbi(mbbiRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devMbbiSoftRaw.c b/src/std/dev/devMbbiSoftRaw.c
index ffe0b00f7..ddaecfc29 100644
--- a/src/std/dev/devMbbiSoftRaw.c
+++ b/src/std/dev/devMbbiSoftRaw.c
@@ -58,13 +58,25 @@ static long init_record(mbbiRecord *prec)
return 0;
}
-static long read_mbbi(mbbiRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0)) {
+ mbbiRecord *prec = (mbbiRecord *) pinp->precord;
+
+ if (!dbGetLink(pinp, DBR_LONG, &prec->rval, 0, 0)) {
prec->rval &= prec->mask;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
}
return 0;
}
+
+static long read_mbbi(mbbiRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devSASoft.c b/src/std/dev/devSASoft.c
index 84c31c5a6..b197f7eff 100644
--- a/src/std/dev/devSASoft.c
+++ b/src/std/dev/devSASoft.c
@@ -60,18 +60,19 @@ static long init_record(subArrayRecord *prec)
return status;
}
-static long read_sa(subArrayRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
+ subArrayRecord *prec = (subArrayRecord *) pinp->precord;
long nRequest = prec->indx + prec->nelm;
long ecount;
if (nRequest > prec->malm)
nRequest = prec->malm;
- if (dbLinkIsConstant(&prec->inp))
+ if (dbLinkIsConstant(pinp))
nRequest = prec->nord;
else
- dbGetLink(&prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
+ dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
ecount = nRequest - prec->indx;
if (ecount > 0) {
@@ -89,7 +90,17 @@ static long read_sa(subArrayRecord *prec)
if (nRequest > 0 &&
dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
return 0;
}
+
+static long read_sa(subArrayRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devSiSoft.c b/src/std/dev/devSiSoft.c
index a969185b7..b1f3255f4 100644
--- a/src/std/dev/devSiSoft.c
+++ b/src/std/dev/devSiSoft.c
@@ -55,17 +55,27 @@ static long init_record(stringinRecord *prec)
return 0;
}
-static long read_stringin(stringinRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
- long status;
+ stringinRecord *prec = (stringinRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_STRING, prec->val, 0, 0);
- status = dbGetLink(&prec->inp, DBR_STRING, prec->val, 0, 0);
if (!status) {
- if (!dbLinkIsConstant(&prec->inp))
+ if (!dbLinkIsConstant(pinp))
prec->udf = FALSE;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
}
return status;
}
+
+static long read_stringin(stringinRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c
index 35ddf73b6..124f615c9 100644
--- a/src/std/dev/devWfSoft.c
+++ b/src/std/dev/devWfSoft.c
@@ -61,10 +61,11 @@ static long init_record(waveformRecord *prec)
return status;
}
-static long read_wf(waveformRecord *prec)
+static long readLocked(struct link *pinp, void *dummy)
{
+ waveformRecord *prec = (waveformRecord *) pinp->precord;
long nRequest = prec->nelm;
- long status = dbGetLink(&prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
+ long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
if (!status && nRequest > 0) {
prec->nord = nRequest;
@@ -72,7 +73,17 @@ static long read_wf(waveformRecord *prec)
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
+ dbGetTimeStamp(pinp, &prec->time);
}
return status;
}
+
+static long read_wf(waveformRecord *prec)
+{
+ long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, NULL);
+
+ return status;
+}
From dcb1f75b4db23d0ccac83857c69329cb76aa423d Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 19 Apr 2017 16:53:12 -0500
Subject: [PATCH 077/112] Cosmetic cleanups
---
src/ioc/db/test/dbCaLinkTest.c | 4 ++--
src/std/dev/devBiDbState.c | 4 ----
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/ioc/db/test/dbCaLinkTest.c b/src/ioc/db/test/dbCaLinkTest.c
index 8d563a076..0940e153e 100644
--- a/src/ioc/db/test/dbCaLinkTest.c
+++ b/src/ioc/db/test/dbCaLinkTest.c
@@ -98,10 +98,10 @@ void putLink(DBLINK *plink, short dbr, const void*buf, long nReq)
ret = dbCaPutLinkCallback(plink, dbr, buf, nReq,
&waitCB, NULL);
if(ret) {
- testFail("putLink fails %ld\n", ret);
+ testFail("putLink fails %ld", ret);
} else {
epicsEventMustWait(waitEvent);
- testPass("putLink ok\n");
+ testPass("putLink ok");
}
epicsEventDestroy(waitEvent);
waitEvent = NULL;
diff --git a/src/std/dev/devBiDbState.c b/src/std/dev/devBiDbState.c
index b0670c6db..fcb6c8f63 100644
--- a/src/std/dev/devBiDbState.c
+++ b/src/std/dev/devBiDbState.c
@@ -66,10 +66,6 @@ static long read_bi(biRecord *prec)
prec->udf = FALSE;
}
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(&prec->inp, &prec->time);
-
return 2;
}
From 7e60faae10dfc9ff6913c30ebd48ced9f0a08ba6 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 21 Apr 2017 13:04:53 -0500
Subject: [PATCH 078/112] No need to truncate const string array elements
---
src/std/link/lnkConst.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index f3ff5d004..02532243b 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -225,9 +225,6 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
if (!vec)
break;
- if (len >= MAX_STRING_SIZE)
- len = MAX_STRING_SIZE - 1;
-
vec[clink->nElems++] = epicsStrnDup(val, len);
clink->value.pstrings = vec;
break;
From 611cb3f52e0fce37f3c189d22db6087626c85c28 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 21 Apr 2017 13:55:59 -0500
Subject: [PATCH 079/112] Fix typos, remove FIXMEs from lnkConst.c
---
src/std/link/lnkConst.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 02532243b..899f0cc68 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -114,7 +114,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long num)
case a0:
clink->type = ai32;
- /* fall thorough */
+ /* fall through */
case ai32:
nElems = clink->nElems + 1;
buf = realloc(clink->value.pmem, nElems * sizeof(epicsInt32));
@@ -134,7 +134,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long num)
case ac40:
errlogPrintf("lnkConst: Mixed data types in array\n");
- /* FIXME ??? */
+ /* fall through */
default:
return jlif_stop;
}
@@ -167,7 +167,7 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
case a0:
clink->type = af64;
- /* fall thorough */
+ /* fall through */
case af64:
nElems = clink->nElems + 1;
f64buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
@@ -190,7 +190,7 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
case ac40:
errlogPrintf("lnkConst: Mixed data types in array\n");
- /* FIXME ??? */
+ /* fall through */
default:
return jlif_stop;
}
From 23cef0339e56607992137de79781ef45fcdf1d85 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 21 Apr 2017 13:56:49 -0500
Subject: [PATCH 080/112] Fix buffer allocation bug in lnkCalc.c
---
src/std/link/lnkCalc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index a7ec9126a..c36174aa6 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -185,7 +185,7 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
return jlif_stop;
}
- postbuf = malloc(INFIX_TO_POSTFIX_SIZE(len));
+ postbuf = malloc(INFIX_TO_POSTFIX_SIZE(len+1));
if (!postbuf) {
errlogPrintf("lnkCalc: Out of memory\n");
return jlif_stop;
From e99fe61e07cc6aea83bfe0d987f5fb5ddd682e0d Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 21 Apr 2017 14:18:05 -0500
Subject: [PATCH 081/112] Fix postfix.h macro arg and document
---
src/libCom/calc/postfix.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/libCom/calc/postfix.h b/src/libCom/calc/postfix.h
index a7a2a3cbe..b90492012 100644
--- a/src/libCom/calc/postfix.h
+++ b/src/libCom/calc/postfix.h
@@ -19,9 +19,10 @@
#define CALCPERFORM_NARGS 12
#define CALCPERFORM_STACK 80
-#define INFIX_TO_POSTFIX_SIZE(n) (n*21/6)
+#define INFIX_TO_POSTFIX_SIZE(n) ((n)*21/6)
/* The above expression is an estimate of the maximum postfix buffer
- * size needed for a given infix expression buffer. The actual size
+ * size needed for a given infix expression buffer (the argument must count
+ * the trailing nil byte in the input expression string). The actual size
* needed is never larger than this value, although it is actually a
* few bytes smaller for some sizes.
*
From 8b24383e9ee430e8b5fc4e4eea3d7bbb1aefbc98 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Thu, 20 Apr 2017 19:48:19 -0400
Subject: [PATCH 082/112] arrayOpTest: check initial dbGet value
---
src/std/rec/test/arrayOpTest.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/std/rec/test/arrayOpTest.c b/src/std/rec/test/arrayOpTest.c
index d77921081..b37c725e2 100644
--- a/src/std/rec/test/arrayOpTest.c
+++ b/src/std/rec/test/arrayOpTest.c
@@ -21,7 +21,7 @@ void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void testGetPutArray(void)
{
- double data[4] = {1, 2, 3, 4};
+ double data[4] = {11, 12, 13, 14};
DBADDR addr, save;
long nreq;
epicsInt32 *pbtr;
@@ -52,10 +52,12 @@ static void testGetPutArray(void)
testOk(prec->nord==3, "prec->nord==3 (got %d)", prec->nord);
nreq = NELEMENTS(data);
- if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
+ if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL)) {
testFail("dbGet fails");
- else {
+ testSkip(1, "failed get");
+ } else {
testOk(nreq==3, "nreq==3 (got %ld)", nreq);
+ testOk1(data[0]==1.0 && data[1]==2.0 && data[2]==3.0);
}
dbScanUnlock(addr.precord);
@@ -158,7 +160,7 @@ static void testGetPutArray(void)
MAIN(arrayOpTest)
{
- testPlan(20);
+ testPlan(21);
testGetPutArray();
return testDone();
}
From 7121b016d55dfd23c4e1de461a1fb8ffdc0e97b9 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Thu, 20 Apr 2017 21:13:50 -0400
Subject: [PATCH 083/112] ioc/db: dbConstLoadLS handle size=0
handle size=0 and clarify
---
src/ioc/db/dbConstLink.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 00eeb8e17..928f7cf94 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -77,6 +77,8 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
if (!pstr)
return S_db_badField;
+ if (!size)
+ return 0;
len = strlen(pstr);
/* FIXME This handles the common case, but not the general one... */
@@ -85,11 +87,11 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
pstr += 2;
len -= 4;
}
- if (--size > len) size = len;
+ if (len+1 > size) len = size-1;
- strncpy(pbuffer, pstr, size);
- pbuffer[size] = 0;
- *plen = (epicsUInt32) strlen(pbuffer) + 1;
+ memcpy(pbuffer, pstr, len);
+ pbuffer[len] = 0;
+ *plen = len+1;
return 0;
}
From 43f6a06bcd272affdb99e8f40a6a8a11c5f97b24 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 21 Apr 2017 11:29:22 -0400
Subject: [PATCH 084/112] std/link: lnkConst avoid cantProceed()
---
src/std/link/lnkCalc.c | 8 +++++++-
src/std/link/lnkConst.c | 13 +++++++++++--
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index c36174aa6..b8cab4021 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -191,7 +191,13 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len)
return jlif_stop;
}
- inbuf = epicsStrnDup(val, len);
+ inbuf = malloc(len+1);
+ if(!inbuf) {
+ errlogPrintf("lnkCalc: Out of memory\n");
+ return jlif_stop;
+ }
+ memcpy(inbuf, val, len);
+ inbuf[len] = '\0';
if (clink->pstate == ps_major) {
clink->major = inbuf;
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 899f0cc68..4c9232a2b 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -212,7 +212,11 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
case s0:
clink->nElems = 1;
clink->type = sc40;
- clink->value.scalar_string = epicsStrnDup(val, len);
+ clink->value.scalar_string = malloc(len+1);
+ if(!clink->value.scalar_string)
+ return jlif_stop;
+ strncpy(clink->value.scalar_string, val, len);
+ clink->value.scalar_string[len] = '\0';
break;
case a0:
@@ -225,8 +229,13 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
if (!vec)
break;
- vec[clink->nElems++] = epicsStrnDup(val, len);
+ vec[clink->nElems] = malloc(len+1);
+ if(!vec[clink->nElems])
+ return jlif_stop;
+ strncpy(vec[clink->nElems], val, len);
+ vec[clink->nElems][len] = '\0';
clink->value.pstrings = vec;
+ clink->nElems++;
break;
case af64:
From b99a7b9252bdd08c4be55aeeeefc441b512206a7 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 21 Apr 2017 12:18:18 -0400
Subject: [PATCH 085/112] std/link: lnkConst fix mem leak and hard fail on no
mem
---
src/std/link/lnkConst.c | 34 +++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 4c9232a2b..999945e27 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -41,13 +41,13 @@ typedef struct clink {
int nElems;
enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type;
union {
- epicsInt32 scalar_integer;
- epicsFloat64 scalar_double;
- char * scalar_string;
+ epicsInt32 scalar_integer; /* si32 */
+ epicsFloat64 scalar_double; /* sf64 */
+ char * scalar_string; /* s0 and sc40 */
void *pmem;
- epicsInt32 *pintegers;
- epicsFloat64 *pdoubles;
- char **pstrings;
+ epicsInt32 *pintegers; /* ai32 */
+ epicsFloat64 *pdoubles; /* af64 */
+ char **pstrings; /* ac40 */
} value;
} clink;
@@ -78,7 +78,7 @@ static void lnkConst_free(jlink *pjlink)
clink *clink = CONTAINER(pjlink, struct clink, jlink);
IFDEBUG(10)
- printf("lnkConst_free(const@%p)\n", pjlink);
+ printf("lnkConst_free(const@%p) type=%d\n", pjlink, pvt->type);
switch (clink->type) {
int i;
@@ -86,10 +86,15 @@ static void lnkConst_free(jlink *pjlink)
for (i=0; inElems; i++)
free(clink->value.pstrings[i]);
/* fall through */
+ case s0:
+ case sc40:
case ai32:
case af64:
free(clink->value.pmem);
- default:
+ break;
+ case a0:
+ case si32:
+ case sf64:
break;
}
free(clink);
@@ -118,7 +123,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long num)
case ai32:
nElems = clink->nElems + 1;
buf = realloc(clink->value.pmem, nElems * sizeof(epicsInt32));
- if (!buf) break;
+ if (!buf) return jlif_stop;
clink->value.pmem = buf;
clink->value.pintegers[clink->nElems] = num;
clink->nElems = nElems;
@@ -127,7 +132,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long num)
case af64:
nElems = clink->nElems + 1;
buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
- if (!buf) break;
+ if (!buf) return jlif_stop;
clink->value.pmem = buf;
clink->value.pdoubles[clink->nElems++] = num;
break;
@@ -171,14 +176,14 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
case af64:
nElems = clink->nElems + 1;
f64buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
- if (!f64buf) break;
+ if (!f64buf) return jlif_stop;
clink->value.pdoubles = f64buf;
clink->value.pdoubles[clink->nElems++] = num;
break;
case ai32: /* promote earlier ai32 values to af64 */
f64buf = calloc(clink->nElems + 1, sizeof(epicsFloat64));
- if (!f64buf) break;
+ if (!f64buf) return jlif_stop;
for (i = 0; i < clink->nElems; i++) {
f64buf[i] = clink->value.pintegers[i];
}
@@ -212,6 +217,7 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
case s0:
clink->nElems = 1;
clink->type = sc40;
+ free(clink->value.scalar_string);
clink->value.scalar_string = malloc(len+1);
if(!clink->value.scalar_string)
return jlif_stop;
@@ -227,7 +233,7 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
vec = realloc(clink->value.pmem, nElems * sizeof(char *));
if (!vec)
- break;
+ return jlif_stop;
vec[clink->nElems] = malloc(len+1);
if(!vec[clink->nElems])
@@ -435,6 +441,8 @@ static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
printf("lnkConst_loadLS(const@%p, %p, %d, %d)\n",
clink, pbuffer, size, *plen);
+ if(!size) return 0;
+
switch (clink->type) {
case sc40:
pstr = clink->value.scalar_string;
From 414e5b82b8b8ce64fd3bfe003ffc2e42d1a502c6 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 21 Apr 2017 14:54:46 -0400
Subject: [PATCH 086/112] std/link: lnkCalc require expression
error if 'expr' key isn't provided.
---
src/std/link/lnkCalc.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index b8cab4021..ea02ad039 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -287,6 +287,10 @@ static jlif_result lnkCalc_end_map(jlink *pjlink)
if (clink->pstate == ps_error)
return jlif_stop;
+ else if (!clink->post_expr) {
+ errlogPrintf("lnkCalc: no expression ('expr' key)\n");
+ return jlif_stop;
+ }
return jlif_continue;
}
From 54e94a1e12bad6d3a271c3d1c5a6a55c41dd47e0 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 21 Apr 2017 15:30:44 -0400
Subject: [PATCH 087/112] std/link: lnkConst refactor
Avoid variable with same name as typedef.
Confuses qtcreator.
---
src/std/link/lnkConst.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 999945e27..11f1476d8 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -36,7 +36,7 @@
typedef long (*FASTCONVERT)();
-typedef struct clink {
+typedef struct const_link {
jlink jlink; /* embedded object */
int nElems;
enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type;
@@ -49,7 +49,7 @@ typedef struct clink {
epicsFloat64 *pdoubles; /* af64 */
char **pstrings; /* ac40 */
} value;
-} clink;
+} const_link;
static lset lnkConst_lset;
@@ -58,7 +58,7 @@ static lset lnkConst_lset;
static jlink* lnkConst_alloc(short dbfType)
{
- clink *clink = calloc(1, sizeof(struct clink));
+ const_link *clink = calloc(1, sizeof(*clink));
IFDEBUG(10)
printf("lnkConst_alloc()\n");
@@ -75,10 +75,10 @@ static jlink* lnkConst_alloc(short dbfType)
static void lnkConst_free(jlink *pjlink)
{
- clink *clink = CONTAINER(pjlink, struct clink, jlink);
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
- printf("lnkConst_free(const@%p) type=%d\n", pjlink, pvt->type);
+ printf("lnkConst_free(const@%p) type=%d\n", pjlink, clink->type);
switch (clink->type) {
int i;
@@ -102,7 +102,7 @@ static void lnkConst_free(jlink *pjlink)
static jlif_result lnkConst_integer(jlink *pjlink, long num)
{
- clink *clink = CONTAINER(pjlink, struct clink, jlink);
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_integer(const@%p, %ld)\n", pjlink, num);
@@ -155,7 +155,7 @@ static jlif_result lnkConst_boolean(jlink *pjlink, int val) {
static jlif_result lnkConst_double(jlink *pjlink, double num)
{
- clink *clink = CONTAINER(pjlink, struct clink, jlink);
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_double(const@%p, %g)\n", pjlink, num);
@@ -205,7 +205,7 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
{
- clink *clink = CONTAINER(pjlink, struct clink, jlink);
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
@@ -257,7 +257,7 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
static jlif_result lnkConst_start_array(jlink *pjlink)
{
- clink *clink = CONTAINER(pjlink, struct clink, jlink);
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_start_array(const@%p)\n", pjlink);
@@ -305,7 +305,7 @@ static struct lset* lnkConst_get_lset(const jlink *pjlink)
static void lnkConst_report(const jlink *pjlink, int level, int indent)
{
- clink *clink = CONTAINER(pjlink, struct clink, jlink);
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
const char * const type_names[4] = {
"bug", "integer", "double", "string"
};
@@ -375,7 +375,7 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent)
static void lnkConst_remove(struct dbLocker *locker, struct link *plink)
{
- clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+ const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_remove(const@%p)\n", clink);
@@ -385,7 +385,7 @@ static void lnkConst_remove(struct dbLocker *locker, struct link *plink)
static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer)
{
- clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+ const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
long status;
IFDEBUG(10)
@@ -434,7 +434,7 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer
static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
- clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+ const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
const char *pstr;
IFDEBUG(10)
@@ -465,7 +465,7 @@ static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
long *pnReq)
{
- clink *clink = CONTAINER(plink->value.json.jlink, struct clink, jlink);
+ const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
short dbrSize = dbValueSize(dbrType);
char *pdest = pbuffer;
int nElems = clink->nElems;
From cfe9a51c5de8376301b50b867fafb079194ad4bc Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 21 Apr 2017 11:22:26 -0400
Subject: [PATCH 088/112] std/rec/test: start linkInitTest
---
src/std/rec/test/Makefile | 7 ++
src/std/rec/test/epicsRunRecordTests.c | 3 +
src/std/rec/test/linkInitTest.c | 104 +++++++++++++++++++++++++
src/std/rec/test/linkInitTest.db | 23 ++++++
4 files changed, 137 insertions(+)
create mode 100644 src/std/rec/test/linkInitTest.c
create mode 100644 src/std/rec/test/linkInitTest.db
diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile
index 793312f9a..90c7bab16 100644
--- a/src/std/rec/test/Makefile
+++ b/src/std/rec/test/Makefile
@@ -39,6 +39,13 @@ testHarness_SRCS += linkRetargetLinkTest.c
TESTFILES += ../linkRetargetLink.db
TESTS += linkRetargetLinkTest
+TESTPROD_HOST += linkInitTest
+linkInitTest_SRCS += linkInitTest.c
+linkInitTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
+testHarness_SRCS += linkInitTest.c
+TESTFILES += ../linkInitTest.db
+TESTS += linkInitTest
+
TESTPROD_HOST += compressTest
compressTest_SRCS += compressTest.c
compressTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
diff --git a/src/std/rec/test/epicsRunRecordTests.c b/src/std/rec/test/epicsRunRecordTests.c
index 5612917cc..8b1d30d59 100644
--- a/src/std/rec/test/epicsRunRecordTests.c
+++ b/src/std/rec/test/epicsRunRecordTests.c
@@ -17,6 +17,7 @@ int compressTest(void);
int arrayOpTest(void);
int asTest(void);
int linkRetargetLinkTest(void);
+int linkInitTest(void);
void epicsRunRecordTests(void)
{
@@ -32,5 +33,7 @@ void epicsRunRecordTests(void)
runTest(linkRetargetLinkTest);
+ runTest(linkInitTest);
+
epicsExit(0); /* Trigger test harness */
}
diff --git a/src/std/rec/test/linkInitTest.c b/src/std/rec/test/linkInitTest.c
new file mode 100644
index 000000000..f904ffa67
--- /dev/null
+++ b/src/std/rec/test/linkInitTest.c
@@ -0,0 +1,104 @@
+/*************************************************************************\
+* Copyright (c) 2015 Michael Davidsaver
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+
+#define EPICS_DBCA_PRIVATE_API
+
+#include
+
+#include "dbAccess.h"
+#include "alarm.h"
+#include "dbUnitTest.h"
+#include "errlog.h"
+#include "epicsThread.h"
+
+#include "testMain.h"
+
+void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
+
+static void testLongStringInit()
+{
+ testDiag("testLongStringInit");
+
+ testdbPrepare();
+
+ testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
+
+ recTestIoc_registerRecordDeviceDriver(pdbbase);
+
+ testdbReadDatabase("linkInitTest.db", NULL, NULL);
+
+ eltc(0);
+ testIocInitOk();
+ eltc(1);
+
+ {
+ const char buf[] = "!----------------------------------------------!";
+ testdbGetArrFieldEqual("longstr1.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf);
+ testdbGetFieldEqual("longstr1.VAL", DBR_STRING, "!--------------------------------------");
+ }
+
+ {
+ const char buf[] = "!----------------------------------------------!";
+ testdbGetArrFieldEqual("longstr2.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf);
+ testdbGetFieldEqual("longstr2.VAL", DBR_STRING, "!--------------------------------------");
+ }
+
+ {
+ const char buf[] = "!----------------------------------------------!";
+ testdbGetArrFieldEqual("longstr3.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf);
+ testdbGetFieldEqual("longstr3.VAL", DBR_STRING, "!--------------------------------------");
+ }
+
+ testIocShutdownOk();
+
+ testdbCleanup();
+}
+
+static void testCalcInit()
+{
+ testDiag("testCalcInit");
+
+ testdbPrepare();
+
+ testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
+
+ recTestIoc_registerRecordDeviceDriver(pdbbase);
+
+ testdbReadDatabase("linkInitTest.db", NULL, NULL);
+
+ eltc(0);
+ testIocInitOk();
+ eltc(1);
+
+ testdbGetFieldEqual("emptylink.VAL", DBR_DOUBLE, 0.0);
+ testdbGetFieldEqual("emptylink.SEVR", DBR_LONG, INVALID_ALARM);
+
+ testdbPutFieldOk("emptylink.PROC", DBF_LONG, 1);
+
+ testdbGetFieldEqual("emptylink.VAL", DBR_DOUBLE, 0.0);
+ testdbGetFieldEqual("emptylink.SEVR", DBR_LONG, 0);
+
+ testdbGetFieldEqual("emptylink1.VAL", DBR_DOUBLE, 0.0);
+ testdbGetFieldEqual("emptylink1.SEVR", DBR_LONG, INVALID_ALARM);
+
+ testdbPutFieldOk("emptylink1.PROC", DBF_LONG, 1);
+
+ testdbGetFieldEqual("emptylink1.VAL", DBR_DOUBLE, 1.0);
+ testdbGetFieldEqual("emptylink1.SEVR", DBR_LONG, 0);
+
+ testIocShutdownOk();
+
+ testdbCleanup();
+}
+
+MAIN(linkInitTest)
+{
+ testPlan(16);
+ testLongStringInit();
+ testCalcInit();
+ return testDone();
+}
diff --git a/src/std/rec/test/linkInitTest.db b/src/std/rec/test/linkInitTest.db
new file mode 100644
index 000000000..15230c30a
--- /dev/null
+++ b/src/std/rec/test/linkInitTest.db
@@ -0,0 +1,23 @@
+
+record(lsi, "longstr1") {
+ field(SIZV, "100")
+ field(INP, ["!----------------------------------------------!"])
+}
+
+record(lsi, "longstr2") {
+ field(SIZV, "100")
+ field(INP, {const: ["!----------------------------------------------!"]})
+}
+
+record(lsi, "longstr3") {
+ field(SIZV, "100")
+ field(INP, {const: "!----------------------------------------------!"})
+}
+
+record(ai, "emptylink" ) {
+ field(INP, {calc: {expr:"0"}})
+}
+
+record(ai, "emptylink1" ) {
+ field(INP, {calc: {expr:"1"}})
+}
From 421a2c8eb9d7e9d3ac88a8b30eed506dc718a0f7 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 23 Apr 2017 00:11:22 -0500
Subject: [PATCH 089/112] Tidy up lnkConst.c after Michael's bug-fix changes
Should make the code easier to follow.
---
src/std/link/lnkConst.c | 85 ++++++++++++++++++++++-------------------
1 file changed, 45 insertions(+), 40 deletions(-)
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 11f1476d8..5fcf84bc4 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -43,7 +43,7 @@ typedef struct const_link {
union {
epicsInt32 scalar_integer; /* si32 */
epicsFloat64 scalar_double; /* sf64 */
- char * scalar_string; /* s0 and sc40 */
+ char *scalar_string; /* sc40 */
void *pmem;
epicsInt32 *pintegers; /* ai32 */
epicsFloat64 *pdoubles; /* af64 */
@@ -86,12 +86,12 @@ static void lnkConst_free(jlink *pjlink)
for (i=0; inElems; i++)
free(clink->value.pstrings[i]);
/* fall through */
- case s0:
case sc40:
case ai32:
case af64:
free(clink->value.pmem);
break;
+ case s0:
case a0:
case si32:
case sf64:
@@ -103,16 +103,15 @@ static void lnkConst_free(jlink *pjlink)
static jlif_result lnkConst_integer(jlink *pjlink, long num)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
+ int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_integer(const@%p, %ld)\n", pjlink, num);
switch (clink->type) {
void *buf;
- int nElems;
case s0:
- clink->nElems = 1;
clink->type = si32;
clink->value.scalar_integer = num;
break;
@@ -121,20 +120,21 @@ static jlif_result lnkConst_integer(jlink *pjlink, long num)
clink->type = ai32;
/* fall through */
case ai32:
- nElems = clink->nElems + 1;
- buf = realloc(clink->value.pmem, nElems * sizeof(epicsInt32));
- if (!buf) return jlif_stop;
+ buf = realloc(clink->value.pmem, newElems * sizeof(epicsInt32));
+ if (!buf)
+ return jlif_stop;
+
clink->value.pmem = buf;
clink->value.pintegers[clink->nElems] = num;
- clink->nElems = nElems;
break;
case af64:
- nElems = clink->nElems + 1;
- buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
- if (!buf) return jlif_stop;
+ buf = realloc(clink->value.pmem, newElems * sizeof(epicsFloat64));
+ if (!buf)
+ return jlif_stop;
+
clink->value.pmem = buf;
- clink->value.pdoubles[clink->nElems++] = num;
+ clink->value.pdoubles[clink->nElems] = num;
break;
case ac40:
@@ -143,6 +143,8 @@ static jlif_result lnkConst_integer(jlink *pjlink, long num)
default:
return jlif_stop;
}
+
+ clink->nElems = newElems;
return jlif_continue;
}
@@ -156,16 +158,16 @@ static jlif_result lnkConst_boolean(jlink *pjlink, int val) {
static jlif_result lnkConst_double(jlink *pjlink, double num)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
+ int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_double(const@%p, %g)\n", pjlink, num);
switch (clink->type) {
epicsFloat64 *f64buf;
- int nElems, i;
+ int i;
case s0:
- clink->nElems = 1;
clink->type = sf64;
clink->value.scalar_double = num;
break;
@@ -174,23 +176,26 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
clink->type = af64;
/* fall through */
case af64:
- nElems = clink->nElems + 1;
- f64buf = realloc(clink->value.pmem, nElems * sizeof(epicsFloat64));
- if (!f64buf) return jlif_stop;
+ f64buf = realloc(clink->value.pmem, newElems * sizeof(epicsFloat64));
+ if (!f64buf)
+ return jlif_stop;
+
+ f64buf[clink->nElems] = num;
clink->value.pdoubles = f64buf;
- clink->value.pdoubles[clink->nElems++] = num;
break;
case ai32: /* promote earlier ai32 values to af64 */
- f64buf = calloc(clink->nElems + 1, sizeof(epicsFloat64));
- if (!f64buf) return jlif_stop;
+ f64buf = calloc(newElems, sizeof(epicsFloat64));
+ if (!f64buf)
+ return jlif_stop;
+
for (i = 0; i < clink->nElems; i++) {
f64buf[i] = clink->value.pintegers[i];
}
- f64buf[clink->nElems++] = num;
free(clink->value.pmem);
- clink->value.pdoubles = f64buf;
+ f64buf[clink->nElems] = num;
clink->type = af64;
+ clink->value.pdoubles = f64buf;
break;
case ac40:
@@ -200,48 +205,47 @@ static jlif_result lnkConst_double(jlink *pjlink, double num)
return jlif_stop;
}
+ clink->nElems = newElems;
return jlif_continue;
}
static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
+ int newElems = clink->nElems + 1;
IFDEBUG(10)
printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val);
switch (clink->type) {
- char **vec;
- int nElems;
+ char **vec, *str;
case s0:
- clink->nElems = 1;
- clink->type = sc40;
- free(clink->value.scalar_string);
- clink->value.scalar_string = malloc(len+1);
- if(!clink->value.scalar_string)
+ str = malloc(len+1);
+ if (!str)
return jlif_stop;
- strncpy(clink->value.scalar_string, val, len);
- clink->value.scalar_string[len] = '\0';
+
+ strncpy(str, val, len);
+ str[len] = '\0';
+ clink->type = sc40;
+ clink->value.scalar_string = str;
break;
case a0:
clink->type = ac40;
/* fall thorough */
case ac40:
- nElems = clink->nElems + 1;
-
- vec = realloc(clink->value.pmem, nElems * sizeof(char *));
+ vec = realloc(clink->value.pmem, newElems * sizeof(char *));
if (!vec)
return jlif_stop;
-
- vec[clink->nElems] = malloc(len+1);
- if(!vec[clink->nElems])
+ str = malloc(len+1);
+ if (!str)
return jlif_stop;
- strncpy(vec[clink->nElems], val, len);
- vec[clink->nElems][len] = '\0';
+
+ strncpy(str, val, len);
+ str[len] = '\0';
+ vec[clink->nElems] = str;
clink->value.pstrings = vec;
- clink->nElems++;
break;
case af64:
@@ -252,6 +256,7 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len)
return jlif_stop;
}
+ clink->nElems = newElems;
return jlif_continue;
}
From 30e634b97b40f1c30bce0cd1550f0a348da63114 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sun, 23 Apr 2017 23:32:15 -0500
Subject: [PATCH 090/112] Adjust calcout's handling of undefined links
---
src/std/rec/calcoutRecord.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c
index e1020938e..92a292140 100644
--- a/src/std/rec/calcoutRecord.c
+++ b/src/std/rec/calcoutRecord.c
@@ -172,10 +172,10 @@ static long init_record(struct dbCommon *pcommon, int pass)
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
- if (dbLinkIsConstant(plink)) {
+ if (dbLinkIsConstant(plink) > 0) {
*plinkValid = calcoutINAV_CON;
}
- else if (dbLinkIsVolatile(plink)) {
+ else if (dbLinkIsVolatile(plink) > 0) {
int conn = dbIsLinkConnected(plink);
if (conn)
@@ -366,10 +366,10 @@ static long special(DBADDR *paddr, int after)
if (fieldIndex != calcoutRecordOUT)
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
- if (dbLinkIsConstant(plink)) {
+ if (dbLinkIsConstant(plink) > 0) {
db_post_events(prec, pvalue, DBE_VALUE);
*plinkValid = calcoutINAV_CON;
- } else if (dbLinkIsVolatile(plink)) {
+ } else if (dbLinkIsVolatile(plink) > 0) {
int conn = dbIsLinkConnected(plink);
if (conn)
From 311ad57e9340629ffec17953a11be2b144c23fa9 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 24 Apr 2017 15:18:52 -0500
Subject: [PATCH 091/112] printfRecord: Handle const long-strings in "%ls"
Adds some tests for printfRecord.
---
src/std/rec/printfRecord.c | 14 ++++++--
src/std/rec/test/linkInitTest.c | 55 +++++++++++++++++++++++++++++++-
src/std/rec/test/linkInitTest.db | 10 ++++++
3 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/src/std/rec/printfRecord.c b/src/std/rec/printfRecord.c
index 17114712e..7011453d4 100644
--- a/src/std/rec/printfRecord.c
+++ b/src/std/rec/printfRecord.c
@@ -203,9 +203,10 @@ static void doPrintf(printfRecord *prec)
}
break;
- case 's': /* FIXME: const strings are now supported */
- if (flags & F_LONG && !dbLinkIsConstant(plink)) {
+ case 's':
+ if (flags & F_LONG) {
long n = vspace + 1;
+ long status;
if (precision && n > precision)
n = precision + 1;
@@ -213,7 +214,14 @@ static void doPrintf(printfRecord *prec)
* characters to be printed from the string.
* It does not limit the field width however.
*/
- if (dbGetLink(plink++, DBR_CHAR, pval, 0, &n))
+ if (dbLinkIsConstant(plink)) {
+ epicsUInt32 len = n;
+ status = dbLoadLinkLS(plink++, pval, n, &len);
+ n = len;
+ }
+ else
+ status = dbGetLink(plink++, DBR_CHAR, pval, 0, &n);
+ if (status)
flags |= F_BADLNK;
else {
int padding;
diff --git a/src/std/rec/test/linkInitTest.c b/src/std/rec/test/linkInitTest.c
index f904ffa67..ac849ba4a 100644
--- a/src/std/rec/test/linkInitTest.c
+++ b/src/std/rec/test/linkInitTest.c
@@ -95,10 +95,63 @@ static void testCalcInit()
testdbCleanup();
}
+static void testPrintfInit()
+{
+ testDiag("testPrintfInit");
+
+ testdbPrepare();
+
+ testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
+
+ recTestIoc_registerRecordDeviceDriver(pdbbase);
+
+ testdbReadDatabase("linkInitTest.db", NULL, NULL);
+
+ eltc(0);
+ testIocInitOk();
+ eltc(1);
+
+ {
+ const char buf1[] = "Test string, exactly 40 characters long";
+ const char buf2[] = "Longer test string, more that 40 characters long";
+ const char buf2t[] = "Longer test string, more that 40 charac";
+
+ /* The FMT field is pp(TRUE), so this put triggers processing */
+ testdbPutFieldOk("printf1.FMT", DBF_STRING, "%s");
+ testdbGetArrFieldEqual("printf1.VAL$", DBF_CHAR, NELEMENTS(buf1)+2,
+ NELEMENTS(buf1), buf1);
+ testdbGetFieldEqual("printf1.VAL", DBR_STRING, buf1);
+
+ testdbPutFieldOk("printf1.FMT", DBF_STRING, "%ls");
+ testdbGetArrFieldEqual("printf1.VAL$", DBF_CHAR, NELEMENTS(buf1)+2,
+ NELEMENTS(buf1), buf1);
+ testdbGetFieldEqual("printf1.VAL", DBR_STRING, buf1);
+
+ testdbPutFieldOk("printf2.FMT", DBF_STRING, "%s");
+ testdbGetArrFieldEqual("printf2.VAL$", DBF_CHAR, NELEMENTS(buf2)+2,
+ NELEMENTS(buf2t), buf2t);
+ testdbGetFieldEqual("printf2.VAL", DBR_STRING, buf2t);
+
+ testdbPutFieldOk("printf2.FMT", DBF_STRING, "%ls");
+ testdbGetArrFieldEqual("printf2.VAL$", DBF_CHAR, NELEMENTS(buf2)+2,
+ NELEMENTS(buf2), buf2);
+ testdbGetFieldEqual("printf2.VAL", DBR_STRING, buf2t);
+
+ testdbPutFieldOk("printf2.FMT", DBF_STRING, "%.39ls");
+ testdbGetArrFieldEqual("printf2.VAL$", DBF_CHAR, NELEMENTS(buf2)+2,
+ NELEMENTS(buf2t), buf2t);
+ }
+
+ testIocShutdownOk();
+
+ testdbCleanup();
+}
+
MAIN(linkInitTest)
{
- testPlan(16);
+ testPlan(30);
testLongStringInit();
testCalcInit();
+ testPrintfInit();
return testDone();
}
diff --git a/src/std/rec/test/linkInitTest.db b/src/std/rec/test/linkInitTest.db
index 15230c30a..a8063a899 100644
--- a/src/std/rec/test/linkInitTest.db
+++ b/src/std/rec/test/linkInitTest.db
@@ -21,3 +21,13 @@ record(ai, "emptylink" ) {
record(ai, "emptylink1" ) {
field(INP, {calc: {expr:"1"}})
}
+
+record(printf, "printf1") {
+ field(SIZV, "100")
+ field(INP0, ["Test string, exactly 40 characters long"])
+}
+record(printf, "printf2") {
+ field(SIZV, "100")
+ field(INP0, ["Longer test string, more that 40 characters long"])
+}
+
From da94b7a2e4acb9d9bf3436cc30448ce1b322c6ef Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 24 Apr 2017 17:09:01 -0500
Subject: [PATCH 092/112] Fix dbConstLink to handle a long-string array
properly
Added a new parser dbLSConvertJSON for long-string arrays.
New test checks that only the first string element is used.
---
src/ioc/db/dbConstLink.c | 17 +-----
src/ioc/db/dbConvertJSON.c | 93 ++++++++++++++++++++++++++++++--
src/ioc/db/dbConvertJSON.h | 3 +-
src/std/rec/test/linkInitTest.c | 4 +-
src/std/rec/test/linkInitTest.db | 5 +-
5 files changed, 99 insertions(+), 23 deletions(-)
diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c
index 928f7cf94..0bdc70f92 100644
--- a/src/ioc/db/dbConstLink.c
+++ b/src/ioc/db/dbConstLink.c
@@ -73,26 +73,11 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
const char *pstr = plink->value.constantStr;
- size_t len;
if (!pstr)
return S_db_badField;
- if (!size)
- return 0;
- len = strlen(pstr);
- /* FIXME This handles the common case, but not the general one... */
- if (pstr[0] == '[' && pstr[1] == '"' &&
- pstr[len-2] == '"' && pstr[len-1] == ']') {
- pstr += 2;
- len -= 4;
- }
- if (len+1 > size) len = size-1;
-
- memcpy(pbuffer, pstr, len);
- pbuffer[len] = 0;
- *plen = len+1;
- return 0;
+ return dbLSConvertJSON(pstr, pbuffer, size, plen);
}
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c
index c0e1e2c8e..e2a453549 100644
--- a/src/ioc/db/dbConvertJSON.c
+++ b/src/ioc/db/dbConvertJSON.c
@@ -17,6 +17,7 @@
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbConvertFast.h"
+#include "dbConvertJSON.h"
typedef long (*FASTCONVERT)();
@@ -49,6 +50,10 @@ static int dbcj_integer(void *ctx, long num) {
return 1;
}
+static int dblsj_integer(void *ctx, long num) {
+ return 0; /* Illegal */
+}
+
static int dbcj_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
@@ -61,6 +66,10 @@ static int dbcj_double(void *ctx, double num) {
return 1;
}
+static int dblsj_double(void *ctx, double num) {
+ return 0; /* Illegal */
+}
+
static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
parseContext *parser = (parseContext *) ctx;
char *pdest = parser->pdest;
@@ -69,7 +78,7 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
* metadata about the field than we have available at the moment.
*/
if (parser->dbrType != DBF_STRING) {
- errlogPrintf("dbPutConvertJSON: String provided, numeric value(s) expected\n");
+ errlogPrintf("dbConvertJSON: String provided, numeric value(s) expected\n");
return 0; /* Illegal */
}
@@ -84,8 +93,28 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
return 1;
}
+static int dblsj_string(void *ctx, const unsigned char *val, unsigned int len) {
+ parseContext *parser = (parseContext *) ctx;
+ char *pdest = parser->pdest;
+
+ if (parser->dbrType != DBF_STRING) {
+ errlogPrintf("dbConvertJSON: dblsj_string dbrType error\n");
+ return 0; /* Illegal */
+ }
+
+ if (parser->elems > 0) {
+ if (len > parser->dbrSize - 1)
+ len = parser->dbrSize - 1;
+ strncpy(pdest, (const char *) val, len);
+ pdest[len] = 0;
+ parser->pdest = pdest + len;
+ parser->elems = 0;
+ }
+ return 1;
+}
+
static int dbcj_start_map(void *ctx) {
- errlogPrintf("dbPutConvertJSON: Map type not supported\n");
+ errlogPrintf("dbConvertJSON: Map type not supported\n");
return 0; /* Illegal */
}
@@ -101,7 +130,7 @@ static int dbcj_start_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
if (++parser->depth > 1)
- errlogPrintf("dbPutConvertJSON: Embedded arrays not supported\n");
+ errlogPrintf("dbConvertJSON: Embedded arrays not supported\n");
return (parser->depth == 1);
}
@@ -157,7 +186,7 @@ long dbPutConvertJSON(const char *json, short dbrType,
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, (unsigned int) jlen);
- fprintf(stderr, "dbPutConvertJSON: %s\n", err);
+ fprintf(stderr, "dbConvertJSON: %s\n", err);
yajl_free_error(yh, err);
}
/* fall through */
@@ -170,3 +199,59 @@ long dbPutConvertJSON(const char *json, short dbrType,
}
+static yajl_callbacks dblsj_callbacks = {
+ dbcj_null, dbcj_boolean, dblsj_integer, dblsj_double, NULL, dblsj_string,
+ dbcj_start_map, dbcj_map_key, dbcj_end_map,
+ dbcj_start_array, dbcj_end_array
+};
+
+long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
+ epicsUInt32 *plen)
+{
+ parseContext context, *parser = &context;
+ yajl_alloc_funcs dbcj_alloc;
+ yajl_handle yh;
+ yajl_status ys;
+ size_t jlen = strlen(json);
+ long status;
+
+ if (!size) {
+ *plen = 0;
+ return 0;
+ }
+
+ parser->depth = 0;
+ parser->dbrType = DBF_STRING;
+ parser->dbrSize = size;
+ parser->pdest = pdest;
+ parser->elems = 1;
+
+ yajl_set_default_alloc_funcs(&dbcj_alloc);
+ yh = yajl_alloc(&dblsj_callbacks, &dbcj_config, &dbcj_alloc, parser);
+ if (!yh)
+ return S_db_noMemory;
+
+ ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen);
+ if (ys == yajl_status_insufficient_data)
+ ys = yajl_parse_complete(yh);
+
+ switch (ys) {
+ case yajl_status_ok:
+ *plen = (char *) parser->pdest - pdest + 1;
+ status = 0;
+ break;
+
+ case yajl_status_error: {
+ unsigned char *err = yajl_get_error(yh, 1,
+ (const unsigned char *) json, (unsigned int) jlen);
+ fprintf(stderr, "dbLoadLS_JSON: %s\n", err);
+ yajl_free_error(yh, err);
+ }
+ /* fall through */
+ default:
+ status = S_db_badField;
+ }
+
+ yajl_free(yh);
+ return status;
+}
diff --git a/src/ioc/db/dbConvertJSON.h b/src/ioc/db/dbConvertJSON.h
index 11546d9ab..7dd8e4aed 100644
--- a/src/ioc/db/dbConvertJSON.h
+++ b/src/ioc/db/dbConvertJSON.h
@@ -18,7 +18,8 @@ extern "C" {
/* This name should probably be changed to inclue "array" */
epicsShareFunc long dbPutConvertJSON(const char *json, short dbrType,
void *pdest, long *psize);
-
+epicsShareFunc long dbLSConvertJSON(const char *json, char *pdest,
+ epicsUInt32 size, epicsUInt32 *plen);
#ifdef __cplusplus
}
#endif
diff --git a/src/std/rec/test/linkInitTest.c b/src/std/rec/test/linkInitTest.c
index ac849ba4a..b99b98c69 100644
--- a/src/std/rec/test/linkInitTest.c
+++ b/src/std/rec/test/linkInitTest.c
@@ -53,6 +53,8 @@ static void testLongStringInit()
testdbGetFieldEqual("longstr3.VAL", DBR_STRING, "!--------------------------------------");
}
+ testdbGetFieldEqual("longstr4.VAL", DBR_STRING, "One");
+
testIocShutdownOk();
testdbCleanup();
@@ -149,7 +151,7 @@ static void testPrintfInit()
MAIN(linkInitTest)
{
- testPlan(30);
+ testPlan(31);
testLongStringInit();
testCalcInit();
testPrintfInit();
diff --git a/src/std/rec/test/linkInitTest.db b/src/std/rec/test/linkInitTest.db
index a8063a899..0e9bbf55e 100644
--- a/src/std/rec/test/linkInitTest.db
+++ b/src/std/rec/test/linkInitTest.db
@@ -1,4 +1,3 @@
-
record(lsi, "longstr1") {
field(SIZV, "100")
field(INP, ["!----------------------------------------------!"])
@@ -14,6 +13,10 @@ record(lsi, "longstr3") {
field(INP, {const: "!----------------------------------------------!"})
}
+record(stringin, "longstr4") {
+ field(INP, ["One","Two","Three","Four"])
+}
+
record(ai, "emptylink" ) {
field(INP, {calc: {expr:"0"}})
}
From c71afb631cffbd60b8f94cea4f67bb82fb9b339b Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 25 Apr 2017 20:37:09 -0500
Subject: [PATCH 093/112] Make dbLinkIs{Constant|Volatile}() return only
true/false
---
src/ioc/db/dbLink.c | 10 ++--------
src/ioc/db/dbLink.h | 6 +++---
src/std/link/lnkCalc.c | 2 +-
src/std/rec/calcoutRecord.c | 11 ++++++-----
4 files changed, 12 insertions(+), 17 deletions(-)
diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c
index a8b7f62ad..6fb936ae4 100644
--- a/src/ioc/db/dbLink.c
+++ b/src/ioc/db/dbLink.c
@@ -190,20 +190,14 @@ int dbLinkIsConstant(const struct link *plink)
{
lset *plset = plink->lset;
- if (plset)
- return plset->isConstant;
-
- return -1;
+ return !plset || plset->isConstant;
}
int dbLinkIsVolatile(const struct link *plink)
{
lset *plset = plink->lset;
- if (plset)
- return plset->isVolatile;
-
- return -1;
+ return plset && plset->isVolatile;
}
long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h
index 6f5858b65..ad4ac2f45 100644
--- a/src/ioc/db/dbLink.h
+++ b/src/ioc/db/dbLink.h
@@ -89,8 +89,8 @@ epicsShareFunc void dbLinkOpen(struct link *plink);
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
epicsShareFunc int dbLinkIsDefined(const struct link *plink); /* 0 or 1 */
-epicsShareFunc int dbLinkIsConstant(const struct link *plink); /* -1, 0 or 1 */
-epicsShareFunc int dbLinkIsVolatile(const struct link *plink); /* -1, 0 or 1 */
+epicsShareFunc int dbLinkIsConstant(const struct link *plink); /* 0 or 1 */
+epicsShareFunc int dbLinkIsVolatile(const struct link *plink); /* 0 or 1 */
epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
void *pbuffer);
@@ -98,7 +98,7 @@ epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
long *pnRequest);
epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
-epicsShareFunc int dbIsLinkConnected(const struct link *plink);
+epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
epicsShareFunc long dbGetLink(struct link *, short dbrType, void *pbuffer,
long *options, long *nRequest);
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index ea02ad039..70d47426e 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -466,7 +466,7 @@ static int lnkCalc_isConn(const struct link *plink)
for (i = 0; i < clink->nArgs; i++) {
struct link *child = &clink->inp[i];
- if (dbLinkIsVolatile(child) > 0 &&
+ if (dbLinkIsVolatile(child) &&
!dbIsLinkConnected(child))
connected = 0;
}
diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c
index 92a292140..8b5525527 100644
--- a/src/std/rec/calcoutRecord.c
+++ b/src/std/rec/calcoutRecord.c
@@ -172,10 +172,10 @@ static long init_record(struct dbCommon *pcommon, int pass)
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
- if (dbLinkIsConstant(plink) > 0) {
+ if (dbLinkIsConstant(plink)) {
*plinkValid = calcoutINAV_CON;
}
- else if (dbLinkIsVolatile(plink) > 0) {
+ else if (dbLinkIsVolatile(plink)) {
int conn = dbIsLinkConnected(plink);
if (conn)
@@ -366,10 +366,11 @@ static long special(DBADDR *paddr, int after)
if (fieldIndex != calcoutRecordOUT)
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
- if (dbLinkIsConstant(plink) > 0) {
+
+ if (dbLinkIsConstant(plink)) {
db_post_events(prec, pvalue, DBE_VALUE);
*plinkValid = calcoutINAV_CON;
- } else if (dbLinkIsVolatile(plink) > 0) {
+ } else if (dbLinkIsVolatile(plink)) {
int conn = dbIsLinkConnected(plink);
if (conn)
@@ -734,7 +735,7 @@ static void checkLinks(calcoutRecord *prec)
plinkValid = &prec->inav;
for (i = 0; i
Date: Tue, 25 Apr 2017 22:52:08 -0500
Subject: [PATCH 094/112] Updates to Release Notes and links.html
---
documentation/RELEASE_NOTES.html | 223 +++++++++++++++++++++++--------
src/std/link/links.dbd.pod | 45 ++++---
2 files changed, 194 insertions(+), 74 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 0da4a7b4f..8e5509782 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -26,37 +26,70 @@
Most Soft Channel input device support routines have supported fetching the
timestamp through the INP link along with the input data. However before now
there was no guarantee that the timestamp provided by a CA link came from the
-same update as the data, since the two were read at separate times without
-maintaining a lock on the CA input buffer. This shortcoming has been fixed as
-part of the new link support code, which allows code using a link to pass a
-subroutine to the link type to be run with the link locked. The subroutine may
-make multiple requests for metadata from the link, but must not block.
-
-Device Support Address Type JSON_LINK
-
-Device support may be written to expect hardware addresses in the new
-JSON_LINK address type. Addresses loaded from a database file will be
-checked against the JSON rules, and a strict JSON representation of the result
-is provided as a C string pointed to by link.value.json.string.
-
-Currently the device support is responsible for parsing the JSON text itself.
-An event-driven JSON parser library has been included in libCom since Base-3.15,
-YAJL (Yet Another JSON Library)
-Version 1.012, documented
-here.
+same update as the data, since the two were read from the CA input buffer at
+separate times without maintaining a lock on that buffer in between. This
+shortcoming could be fixed as a result of the new link support code, which
+allows code using a link to pass a subroutine to the link type which will be run
+with the link locked. The subroutine may make multiple requests for metadata
+from the link, but must not block.
-JSON Link Addressing
+Extensible Link Types
-FIXME text missing here...
+A major new feature introduced with this release of EPICS Base is an
+Extensible Link Type mechanism, also known as Link Support or JSON Link Types.
+This addition permits new kinds of link I/O to be added to an IOC in a similar
+manner to the other extension points already supported (e.g. record, device and
+driver support).
-Support routine changes
+A new link type must implement two related APIs, one for parsing the JSON
+string which provides the link address and the other which implements the link
+operations that get called at run-time to perform I/O. The link type is built
+into the IOC by providing a new link entry in a DBD file.
+
+
+New Link Types Added
+
+This release contains two new JSON link types, const and
+calc:
+
+
+
+- The const link type is almost equivalent to the old CONSTANT link
+type with the updates described below to accept arrays and strings, except that
+there is no need to wrap a scalar string constant inside array brackets since a
+constant string will never be confused with a PV name.
+
+- The calc link type allows CALC expressions to be used to combine
+values from other JSON links to produce its value. Until additional JSON link
+types are created though, the calc link type has little practical
+utility as it can currently only fetch inputs from other calc links or
+from const links.
+
+
+
+The new link types are documented in a
+separate
+document
+.
+
+
+Device Support Addressing using JSON_LINK
+
+
The API to allow device support to use JSON addresses is currently
+incomplete; developers are advised not to try creating device support that
+specifies a JSON_LINK address type.
+
+
+Support Routine Modifications for Extensible Link Types
For link fields in external record types and soft device support to be able
-to use the new JSON link types properly, the following changes are
-necessary:
+to use the new link types properly, various changes are required to utilize the
+new Link Support API as defined in the dbLink.h header file and outlined below.
+The existing built-in Database and Channel Access link types have been altered
+to implement the link APIs, so will work properly after these conversions:
@@ -75,69 +108,149 @@ into this:
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
-Note that recGblInitConstantLink() still returns true if the field was
-successfully initialized from the link.
+Note that recGblInitConstantLink() still returns TRUE if the field was
+successfully initialized from the link (implying the link is constant).
+This change will work properly with all Base releases currently in use.
-- Code like this:
+
- Code that needs to identify a constant link should be modified to use the
+new routine dbLinkIsConstant() instead, which returns TRUE for constant
+or undefined links, FALSE for links whose dbGetLink() routine may
+return different values on different calls. For example this:
- if ((prec->dol.type != CONSTANT) &&
+ if (prec->dol.type != CONSTANT)
-should usually become:
+should become this:
- if (!dbLinkIsConstant(&prec->dol) &&
+ if (!dbLinkIsConstant(&prec->dol))
+
+
+When the converted software is also required to build against older versions of
+Base, this macro definition may be useful:
+
+
+#define dbLinkIsConstant(lnk) ((lnk)->type == CONSTANT)
-- Other code that compares a link type with CONSTANT should be modified to
-use the new routine dbLinkIsConstant(plink) instead.
-
-- Any code that calls dbCa routines directly or that explicitly checks if a
+
- Any code that calls dbCa routines directly, or that explicitly checks if a
link has been resolved as a CA link using code such as
- if (plink->type == CA_LINK)
+ if (prec->inp.type == CA_LINK)
-should be modified to use the new generic routines defined in dbLink.h. As an
-example, the calcout record has been modified to use the new dbLink API.
+will still compile and run, but will only work properly with the old CA link
+type. To operate with the new extensible link types such code must be modified
+to use the new generic routines defined in dbLink.h and should never attempt to
+examine or modify data inside the link. After conversion the above line would
+probably become:
-- ...
+
+ if (dbLinkIsVolatile(&prec->inp))
+
+
+A volatile link is one like a Channel Access link which may disconnect and
+reconnect without notice at runtime. Database links and constant links are not
+volatile; unless their link address is changed they will always remain in the
+same state they started in. For compatibility when building against older
+versions of Base, this macro definition may be useful:
+
+
+#define dbLinkIsVolatile(lnk) ((lnk)->type == CA_LINK)
+
+
+
+The current connection state of a volatile link can be found using the
+routine dbIsLinkConnected() which will only return TRUE for a volatile
+link that is currently connected. Code using the older dbCa API returning this
+information used to look like this:
+
+
+ stat = dbCaIsLinkConnected(plink);
+
+
+which should become:
+
+ stat = dbIsLinkConnected(plink);
+
+
+Similar changes should be made for calls to the other dbCa routines.
+
+
+A full example can be found by looking at the changes to the calcout record
+type, which has been modified in this release to use the new dbLink generic
+API.
-FIXME text missing here...
-
Constant Link Values
-Previously a constant link (i.e. a link that does not point to another PV,
-either local or over Channel Access) has only been able to provide a numeric
-value; any string found in a link field that was not recognized as a number was
-treated as a PV name. In this release, constant links may contain string values,
-arrays, or even arrays of strings. These are indicated by ...
+Previously a constant link (i.e. a link that did not point to another PV,
+either locally or over Channel Access) was only able to provide a single numeric
+value to a record initialization; any string given in a link field that was not
+recognized as a number was treated as a PV name. In this release, constant links
+can be expressed using JSON array syntax and may provide array initialization of
+values containing integers, doubles or strings. An array containing a single
+string value can also be used to initialize scalar strings, so the stringin,
+stringout, lsi (long string input), lso (long string output), printf, waveform,
+subArray and aai (analog array input) record types and/or their soft device
+supports have been modified to support this.
-FIXME text missing here...
+Some examples of constant array and string initialized records are:
+
+
+ record(stringin, "const:string") {
+ field(INP, ["Not-a-PV-name"])
+ }
+ record(waveform, "const:longs") {
+ field(FTVL, LONG)
+ field(NELM, 10)
+ field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ }
+ record(aai, "const:doubles") {
+ field(FTVL, DOUBLE)
+ field(NELM, 10)
+ field(INP, [0, 1, 1.6e-19, 2.718, 3.141593])
+ }
+ record(aSub, "select") {
+ field(FTA, STRING)
+ field(NOA, 4)
+ field(INPA, ["Zero", "One", "Two", "Three"])
+ field(FTB, SHORT)
+ field(NOB, 1)
+ field(FTVA, STRING)
+ field(NOVA, 1)
+ field(SNAM, "select_asub")
+ }
+
+
+Reminder: Link initialization with constant values normally only occurs at
+record initialization time. The calcout and printf record types are the only
+exceptions in the Base record types to this rule, so it is generally not useful
+to change a const link value after iocInit.
Database Parsing of "Relaxed JSON" Values
A database file can now provide a "relaxed JSON" value for a database field
value or an info tag. Only a few field types can currently accept such values,
-but the capability is now available for use in other places in the future. If a
-JSON-capable field is written to at run-time though only strictly compliant JSON
-may be used (the dbStaticLib parser rewrites relaxed JSON values into strict
-JSON before passing them to the datase for interpretation, where the strict
-rules must be followed).
+but the capability is now available for use in other places in the future. When
+writing to a JSON-capable field at run-time however, only strictly compliant
+JSON may be used (the dbStaticLib parser rewrites relaxed JSON values into
+strict JSON before passing them to the datase for interpretation, where the
+strict rules must be followed).
"Relaxed JSON" was developed to maximize compatibility with the previous
database parser rules and reduce the number of double-quotes that would be
-needed using strict JSON syntax. The parser will also accept strict JSON, which
-should be used when machine-generating database files. The differences are:
+needed for strict JSON syntax. The parser does accept strict JSON too though,
+which should be used when machine-generating database files. The differences
+are:
@@ -147,7 +260,7 @@ do not have to be enclosed in double-quote characters.
- The above rule applies to map keys as well as to regular string values.
- The JSON keywords null, true and false (all
-lower-case) will be recognized as keywords, so must be quoted to use any of
+lower-case) will be recognized as keywords, so they must be quoted to use any of
these single words as a string.
- Comments may be used, introduced as usual by the #
@@ -175,7 +288,9 @@ excerpts from a database file:
Note that the record, field and info-tag names do not accept JSON
values, so they follows the older bareword rules for quoting where the colon
: and several additional characters are legal in a bareword
-string.
+string. Only the value (after the comma) is parsed as JSON. The autosave module
+has not been modified to accept JSON syntax, the above is only an example of
+how JSON might be used.
Echoless comments in iocsh
diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod
index a7ddeb553..ceb6ced77 100644
--- a/src/std/link/links.dbd.pod
+++ b/src/std/link/links.dbd.pod
@@ -1,8 +1,11 @@
-=head1 JSON Links
+=head1 Extensible Links
-JSON Links are an extensible mechanism for adding new kinds of database link,
-using JSON for the link address.
-The following link types are available in this release:
+The extensible link mechanism allows new kinds of record links to be created,
+using JSON for the link address syntax.
+The IOC continues to support the older link types that do not use JSON to
+specify their link addresses.
+
+The following additional link types are available in this release:
=over
@@ -12,14 +15,16 @@ The following link types are available in this release:
=back
-=head2 Using Links
+=head2 Using JSON Links
-...
-
-When setting a record link field to a JSON link, the link specification must
-appear inside a pair of braces C< {} > expressed as a JSON (L) object, which allows link parameters to be
-defined as needed by the particular link type.
+When setting a record link field to a JSON link address, the link specification
+must appear inside a pair of braces C< {} > expressed as a JSON (L) object, which allows link parameters to
+be defined as needed by the particular link type. When link fields are set from
+an IOC database file at initialization time, the field definitions may take
+advantage of a "relaxed JSON" syntax that reduces the number of double-quote
+characters required and maintains backwards compatibility with the older
+database file syntax.
=head2 Link Type Reference
@@ -36,12 +41,12 @@ support the use of constant links by calling C at
record initialization, which results in the constant value being loaded into the
target field at that time.
-Note that for most record types (the C and C records are
-exceptions) it is pointless to set an input link to a constant link at runtime
-since the link initialization that loads the field value usually only happens
-when a record is initialized. A constant link that is embedded inside another
-input link type such as a calculation link should be OK though since the link
-initialization will take place when the record's field gets set.
+Note that for most record types (the C and C records are the
+main exceptions) it is pointless to set an input link to a constant link at
+runtime since the link initialization that loads the field value usually only
+happens when a record is initialized. A constant link that is embedded inside
+another input link type such as a calculation link should be OK though since the
+link initialization will take place when the record's field gets set.
=head4 Parameters
@@ -76,13 +81,13 @@ evaluated by the EPICS Calc engine, and up to 12 inputs can be provided.
=head4 Parameters
-The link value is a map with the following keys:
+The link address is a JSON map with the following keys:
=over
=item expr
-The primary expression to be evaluated, provided as a string.
+The primary expression to be evaluated, given as a string.
=item major
@@ -113,6 +118,6 @@ result should be displayed. Equivalent to the C field of a record.
=head4 Example
- {calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5]}}
+ {calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5], prec:3}}
=cut
From 4eafb6fd8e2ca0af37b46df2c7a7b485f1fb9469 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 26 Apr 2017 15:03:43 -0500
Subject: [PATCH 095/112] Fix bug in eventRecord::init_record
Look up event handle /after/ the device init routine has been run,
in case it modified the event name in VAL. That didn't used to
be possible because constant links couldn't return strings.
---
src/std/rec/eventRecord.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/std/rec/eventRecord.c b/src/std/rec/eventRecord.c
index 5c4a65743..38a4ad62f 100644
--- a/src/std/rec/eventRecord.c
+++ b/src/std/rec/eventRecord.c
@@ -102,10 +102,11 @@ static long init_record(struct dbCommon *pcommon, int pass)
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
recGblInitConstantLink(&prec->siol, DBF_STRING, &prec->sval);
- prec->epvt = eventNameToHandle(prec->val);
-
if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) )
status=(*pdset->init_record)(prec);
+
+ prec->epvt = eventNameToHandle(prec->val);
+
return(status);
}
From d1af663705793af67669ba35ad1a8ba6a3eaa12f Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 26 Apr 2017 15:52:08 -0500
Subject: [PATCH 096/112] Enhancements to subArray record & soft device support
Permit record's use as a look-up-table by reading constant
input array data in dset::read_sa() routine.
Move sub-array operation into a separate function.
Extract subarray from constant INP value at device init.
Reduce the work done inside readLocked() to a minimum.
Limit NELM value to at most MALM in record init routine.
---
documentation/RELEASE_NOTES.html | 20 +++++++
src/std/dev/devSASoft.c | 95 ++++++++++++++++++++------------
src/std/rec/subArrayRecord.c | 2 +
3 files changed, 82 insertions(+), 35 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 8e5509782..ce6a00896 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -21,6 +21,26 @@
-->
+Lookup-tables using the subArrray record
+
+The subArray record can now be used as a lookup-table from a constant array
+specified in its INP field. For example:
+
+
+record(subArray, "powers-of-2") {
+ field(FTVL, "LONG")
+ field(MALM, 12)
+ field(INP, [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048])
+ field(INDX, 0)
+ field(NELM, 1)
+}
+
+
+The INDX field selects which power of 2 to set the VAL field to. In previous
+releases the INP field would have to have been pointed to a separate waveform
+record that was initialized with the array values somehow at initialization
+time.
+
Synchronized Timestamps with TSEL=-2
Most Soft Channel input device support routines have supported fetching the
diff --git a/src/std/dev/devSASoft.c b/src/std/dev/devSASoft.c
index 56ffdd796..01a076e6d 100644
--- a/src/std/dev/devSASoft.c
+++ b/src/std/dev/devSASoft.c
@@ -45,61 +45,86 @@ struct {
};
epicsExportAddress(dset, devSASoft);
-static long init_record(subArrayRecord *prec)
+static void subset(subArrayRecord *prec, long nRequest)
{
- long nelm = prec->nelm;
- long status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nelm);
+ long ecount = nRequest - prec->indx;
- if (!status && nelm > 0) {
- prec->nord = nelm;
- prec->udf = FALSE;
- }
- else
- prec->nord = 0;
- return status;
-}
-
-static long readLocked(struct link *pinp, void *dummy)
-{
- subArrayRecord *prec = (subArrayRecord *) pinp->precord;
- long nRequest = prec->indx + prec->nelm;
- long ecount;
-
- if (nRequest > prec->malm)
- nRequest = prec->malm;
-
- if (dbLinkIsConstant(pinp))
- nRequest = prec->nord;
- else
- dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
-
- ecount = nRequest - prec->indx;
if (ecount > 0) {
int esize = dbValueSize(prec->ftvl);
if (ecount > prec->nelm)
ecount = prec->nelm;
+
memmove(prec->bptr, (char *)prec->bptr + prec->indx * esize,
ecount * esize);
} else
ecount = 0;
prec->nord = ecount;
+ prec->udf = FALSE;
+}
- if (nRequest > 0 &&
- dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
+static long init_record(subArrayRecord *prec)
+{
+ long nRequest = prec->indx + prec->nelm;
+ long status;
- return 0;
+ if (nRequest > prec->malm)
+ nRequest = prec->malm;
+
+ status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nRequest);
+
+ if (!status && nRequest > 0)
+ subset(prec, nRequest);
+
+ return status;
+}
+
+struct sart {
+ long nRequest;
+ epicsTimeStamp *ptime;
+};
+
+static long readLocked(struct link *pinp, void *vrt)
+{
+ subArrayRecord *prec = (subArrayRecord *) pinp->precord;
+ struct sart *prt = (struct sart *) vrt;
+ long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &prt->nRequest);
+
+ if (!status && prt->ptime)
+ dbGetTimeStamp(pinp, prt->ptime);
+
+ return status;
}
static long read_sa(subArrayRecord *prec)
{
- long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+ long status;
+ struct sart rt;
- if (status == S_db_noLSET)
- status = readLocked(&prec->inp, NULL);
+ rt.nRequest = prec->indx + prec->nelm;
+ if (rt.nRequest > prec->malm)
+ rt.nRequest = prec->malm;
+
+ rt.ptime = (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime) ? &prec->time : NULL;
+
+ if (dbLinkIsConstant(&prec->inp)) {
+ status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &rt.nRequest);
+ if (status == S_db_badField) { /* INP was empty */
+ rt.nRequest = prec->nord;
+ status = 0;
+ }
+ }
+ else {
+ status = dbLinkDoLocked(&prec->inp, readLocked, &rt);
+
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, &rt);
+ }
+
+ if (!status && rt.nRequest > 0)
+ subset(prec, rt.nRequest);
return status;
}
diff --git a/src/std/rec/subArrayRecord.c b/src/std/rec/subArrayRecord.c
index 3de610c26..d9d1c33e1 100644
--- a/src/std/rec/subArrayRecord.c
+++ b/src/std/rec/subArrayRecord.c
@@ -108,6 +108,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
prec->bptr = callocMustSucceed(prec->malm, dbValueSize(prec->ftvl),
"subArrayRecord calloc failed");
prec->nord = 0;
+ if (prec->nelm > prec->malm)
+ prec->nelm = prec->malm;
return 0;
}
From c13a4f24ceb9241ce4d5bc6172f002dee228149e Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 26 Apr 2017 15:55:03 -0500
Subject: [PATCH 097/112] Cosmetic changes to various soft device supports
---
src/std/dev/devAiSoftRaw.c | 2 +-
src/std/dev/devBiSoft.c | 14 ++++++++------
src/std/dev/devBiSoftRaw.c | 9 ++++++---
src/std/dev/devLiSoft.c | 6 ++++--
src/std/dev/devLsiSoft.c | 5 +++--
src/std/dev/devMbbiDirectSoft.c | 14 ++++++++------
src/std/dev/devMbbiSoft.c | 13 +++++++------
7 files changed, 37 insertions(+), 26 deletions(-)
diff --git a/src/std/dev/devAiSoftRaw.c b/src/std/dev/devAiSoftRaw.c
index e7b767e50..f2cfd5df5 100644
--- a/src/std/dev/devAiSoftRaw.c
+++ b/src/std/dev/devAiSoftRaw.c
@@ -65,7 +65,7 @@ static long readLocked(struct link *pinp, void *dummy)
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
- return 0;
+ return status;
}
static long read_ai(aiRecord *prec)
diff --git a/src/std/dev/devBiSoft.c b/src/std/dev/devBiSoft.c
index f0f305b8c..12640ad0c 100644
--- a/src/std/dev/devBiSoft.c
+++ b/src/std/dev/devBiSoft.c
@@ -55,13 +55,15 @@ static long init_record(biRecord *prec)
static long readLocked(struct link *pinp, void *dummy)
{
biRecord *prec = (biRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0);
+
+ if (status) return status;
+
+ prec->udf = FALSE;
+ if (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime)
+ dbGetTimeStamp(pinp, &prec->time);
- if (!dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0)) {
- prec->udf = FALSE;
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
- }
return 2;
}
diff --git a/src/std/dev/devBiSoftRaw.c b/src/std/dev/devBiSoftRaw.c
index 3cb6b6ffe..a71bf89cb 100644
--- a/src/std/dev/devBiSoftRaw.c
+++ b/src/std/dev/devBiSoftRaw.c
@@ -48,19 +48,22 @@ epicsExportAddress(dset, devBiSoftRaw);
static long init_record(biRecord *prec)
{
recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
+
return 0;
}
static long readLocked(struct link *pinp, void *dummy)
{
biRecord *prec = (biRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_ULONG, &prec->rval, 0, 0);
- if (!dbGetLink(pinp, DBR_ULONG, &prec->rval, 0, 0) &&
- dbLinkIsConstant(&prec->tsel) &&
+ if (status) return status;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
- return 0;
+ return status;
}
static long read_bi(biRecord *prec)
diff --git a/src/std/dev/devLiSoft.c b/src/std/dev/devLiSoft.c
index 30f981b59..6d7b7fda1 100644
--- a/src/std/dev/devLiSoft.c
+++ b/src/std/dev/devLiSoft.c
@@ -58,10 +58,12 @@ static long readLocked(struct link *pinp, void *dummy)
longinRecord *prec = (longinRecord *) pinp->precord;
long status = dbGetLink(pinp, DBR_LONG, &prec->val, 0, 0);
- if (!status &&
- dbLinkIsConstant(&prec->tsel) &&
+ if (status) return status;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
+
return status;
}
diff --git a/src/std/dev/devLsiSoft.c b/src/std/dev/devLsiSoft.c
index 8ec5ea2fa..3076c9900 100644
--- a/src/std/dev/devLsiSoft.c
+++ b/src/std/dev/devLsiSoft.c
@@ -29,8 +29,9 @@ static long readLocked(struct link *pinp, void *dummy)
lsiRecord *prec = (lsiRecord *) pinp->precord;
long status = dbGetLinkLS(pinp, prec->val, prec->sizv, &prec->len);
- if (!status &&
- dbLinkIsConstant(&prec->tsel) &&
+ if (status) return status;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
diff --git a/src/std/dev/devMbbiDirectSoft.c b/src/std/dev/devMbbiDirectSoft.c
index c63d0de1a..9c929b2b6 100644
--- a/src/std/dev/devMbbiDirectSoft.c
+++ b/src/std/dev/devMbbiDirectSoft.c
@@ -56,13 +56,15 @@ static long init_record(mbbiDirectRecord *prec)
static long readLocked(struct link *pinp, void *dummy)
{
mbbiDirectRecord *prec = (mbbiDirectRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0);
+
+ if (status) return status;
+
+ prec->udf = FALSE;
+ if (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime)
+ dbGetTimeStamp(pinp, &prec->time);
- if (!dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0)) {
- prec->udf = FALSE;
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
- }
return 2;
}
diff --git a/src/std/dev/devMbbiSoft.c b/src/std/dev/devMbbiSoft.c
index 670e2f615..b0b57144f 100644
--- a/src/std/dev/devMbbiSoft.c
+++ b/src/std/dev/devMbbiSoft.c
@@ -56,14 +56,15 @@ static long init_record(mbbiRecord *prec)
static long readLocked(struct link *pinp, void *dummy)
{
mbbiRecord *prec = (mbbiRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0);
- if (!dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0)) {
- prec->udf = FALSE;
+ if (status) return status;
+
+ prec->udf = FALSE;
+ if (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime)
+ dbGetTimeStamp(pinp, &prec->time);
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
- }
return 2;
}
From bbd94928bbed65959b1b2ed72cea14cd3c2d4806 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 26 Apr 2017 15:59:03 -0500
Subject: [PATCH 098/112] Minimize work done in readLocked() routine
Move post-I/O work back to the read_xx routines.
---
src/std/dev/devAiSoft.c | 50 ++++++++++++++++++++----------------
src/std/dev/devMbbiSoftRaw.c | 18 ++++++++-----
src/std/dev/devSiSoft.c | 17 +++++++-----
src/std/dev/devWfSoft.c | 35 ++++++++++++++++---------
4 files changed, 72 insertions(+), 48 deletions(-)
diff --git a/src/std/dev/devAiSoft.c b/src/std/dev/devAiSoft.c
index 69afff3ee..0ecc1b13f 100644
--- a/src/std/dev/devAiSoft.c
+++ b/src/std/dev/devAiSoft.c
@@ -56,42 +56,48 @@ static long init_record(aiRecord *prec)
return 0;
}
-static long readLocked(struct link *pinp, void *dummy)
-{
- aiRecord *prec = (aiRecord *) pinp->precord;
+struct aivt {
double val;
- long status = dbGetLink(pinp, DBR_DOUBLE, &val, 0, 0);
+ epicsTimeStamp *ptime;
+};
- if (status) return status;
+static long readLocked(struct link *pinp, void *vvt)
+{
+ struct aivt *pvt = (struct aivt *) vvt;
+ long status = dbGetLink(pinp, DBR_DOUBLE, &pvt->val, 0, 0);
- /* Apply smoothing algorithm */
- if (prec->smoo != 0.0 && prec->dpvt && finite(prec->val))
- prec->val = val * (1.00 - prec->smoo) + (prec->val * prec->smoo);
- else
- prec->val = val;
+ if (!status && pvt->ptime)
+ dbGetTimeStamp(pinp, pvt->ptime);
- prec->udf = FALSE;
- prec->dpvt = &devAiSoft; /* Any non-zero value */
-
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
-
- return 0;
+ return status;
}
static long read_ai(aiRecord *prec)
{
long status;
+ struct aivt vt;
if (dbLinkIsConstant(&prec->inp))
return 2;
- status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
- if (status == S_db_noLSET)
- status = readLocked(&prec->inp, NULL);
+ vt.ptime = (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime) ? &prec->time : NULL;
- if (status)
+ status = dbLinkDoLocked(&prec->inp, readLocked, &vt);
+ if (status == S_db_noLSET)
+ status = readLocked(&prec->inp, &vt);
+
+ if (!status) {
+ /* Apply smoothing algorithm */
+ if (prec->smoo != 0.0 && prec->dpvt && finite(prec->val))
+ prec->val = vt.val * (1.0 - prec->smoo) + (prec->val * prec->smoo);
+ else
+ prec->val = vt.val;
+
+ prec->udf = FALSE;
+ prec->dpvt = &devAiSoft; /* Any non-zero value */
+ }
+ else
prec->dpvt = NULL;
return 2;
diff --git a/src/std/dev/devMbbiSoftRaw.c b/src/std/dev/devMbbiSoftRaw.c
index fde76513a..3bd6b21da 100644
--- a/src/std/dev/devMbbiSoftRaw.c
+++ b/src/std/dev/devMbbiSoftRaw.c
@@ -60,14 +60,15 @@ static long init_record(mbbiRecord *prec)
static long readLocked(struct link *pinp, void *dummy)
{
mbbiRecord *prec = (mbbiRecord *) pinp->precord;
+ long status = dbGetLink(pinp, DBR_LONG, &prec->rval, 0, 0);
- if (!dbGetLink(pinp, DBR_LONG, &prec->rval, 0, 0)) {
- prec->rval &= prec->mask;
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
- }
- return 0;
+ if (status) return status;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime)
+ dbGetTimeStamp(pinp, &prec->time);
+
+ return status;
}
static long read_mbbi(mbbiRecord *prec)
@@ -77,5 +78,8 @@ static long read_mbbi(mbbiRecord *prec)
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
+ if (!status)
+ prec->rval &= prec->mask;
+
return status;
}
diff --git a/src/std/dev/devSiSoft.c b/src/std/dev/devSiSoft.c
index 9b1fcfe4b..5141c1038 100644
--- a/src/std/dev/devSiSoft.c
+++ b/src/std/dev/devSiSoft.c
@@ -51,6 +51,7 @@ static long init_record(stringinRecord *prec)
{
if (recGblInitConstantLink(&prec->inp, DBF_STRING, prec->val))
prec->udf = FALSE;
+
return 0;
}
@@ -59,13 +60,12 @@ static long readLocked(struct link *pinp, void *dummy)
stringinRecord *prec = (stringinRecord *) pinp->precord;
long status = dbGetLink(pinp, DBR_STRING, prec->val, 0, 0);
- if (!status) {
- if (!dbLinkIsConstant(pinp))
- prec->udf = FALSE;
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
- }
+ if (status) return status;
+
+ if (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime)
+ dbGetTimeStamp(pinp, &prec->time);
+
return status;
}
@@ -76,5 +76,8 @@ static long read_stringin(stringinRecord *prec)
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
+ if (!status && !dbLinkIsConstant(&prec->inp))
+ prec->udf = FALSE;
+
return status;
}
diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c
index d1daefd7b..8d8295696 100644
--- a/src/std/dev/devWfSoft.c
+++ b/src/std/dev/devWfSoft.c
@@ -60,29 +60,40 @@ static long init_record(waveformRecord *prec)
return status;
}
-static long readLocked(struct link *pinp, void *dummy)
+struct wfrt {
+ long nRequest;
+ epicsTimeStamp *ptime;
+};
+
+static long readLocked(struct link *pinp, void *vrt)
{
waveformRecord *prec = (waveformRecord *) pinp->precord;
- long nRequest = prec->nelm;
- long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
+ struct wfrt *prt = (struct wfrt *) vrt;
+ long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &prt->nRequest);
- if (!status && nRequest > 0) {
- prec->nord = nRequest;
- prec->udf = FALSE;
+ if (!status && prt->ptime)
+ dbGetTimeStamp(pinp, prt->ptime);
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
- }
return status;
}
static long read_wf(waveformRecord *prec)
{
- long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+ long status;
+ struct wfrt rt;
+ rt.nRequest = prec->nelm;
+ rt.ptime = (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime) ? &prec->time : NULL;
+
+ status = dbLinkDoLocked(&prec->inp, readLocked, &rt);
if (status == S_db_noLSET)
- status = readLocked(&prec->inp, NULL);
+ status = readLocked(&prec->inp, &rt);
+
+ if (!status && rt.nRequest > 0) {
+ prec->nord = rt.nRequest;
+ prec->udf = FALSE;
+ }
return status;
}
From 4813b3753843eb374adfbdf0bb7709b8214e60f0 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 26 Apr 2017 16:01:09 -0500
Subject: [PATCH 099/112] Minimize work done in readLocked routine
Move post-I/O back to read_event.
Fix initialization bug.
---
src/std/dev/devEventSoft.c | 52 +++++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 20 deletions(-)
diff --git a/src/std/dev/devEventSoft.c b/src/std/dev/devEventSoft.c
index ae5c9d01b..a748dda66 100644
--- a/src/std/dev/devEventSoft.c
+++ b/src/std/dev/devEventSoft.c
@@ -47,38 +47,50 @@ epicsExportAddress(dset, devEventSoft);
static long init_record(eventRecord *prec)
{
- if (recGblInitConstantLink(&prec->inp, DBF_STRING, &prec->val))
+ if (recGblInitConstantLink(&prec->inp, DBF_STRING, prec->val))
prec->udf = FALSE;
+
return 0;
}
-static long readLocked(struct link *pinp, void *dummy)
-{
- eventRecord *prec = (eventRecord *) pinp->precord;
- long status;
+struct eventvt {
char newEvent[MAX_STRING_SIZE];
+ epicsTimeStamp *ptime;
+};
- if (!dbLinkIsConstant(pinp)) {
- status = dbGetLink(pinp, DBR_STRING, newEvent, 0, 0);
- if (status) return status;
- if (strcmp(newEvent, prec->val) != 0) {
- strcpy(prec->val, newEvent);
- prec->epvt = eventNameToHandle(prec->val);
- }
- }
- prec->udf = FALSE;
- if (dbLinkIsConstant(&prec->tsel) &&
- prec->tse == epicsTimeEventDeviceTime)
- dbGetTimeStamp(pinp, &prec->time);
- return 0;
+static long readLocked(struct link *pinp, void *vvt)
+{
+ struct eventvt *pvt = (struct eventvt *) vvt;
+ long status = dbGetLink(pinp, DBR_STRING, pvt->newEvent, 0, 0);
+
+ if (!status && pvt->ptime)
+ dbGetTimeStamp(pinp, pvt->ptime);
+
+ return status;
}
static long read_event(eventRecord *prec)
{
- long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
+ long status;
+ struct eventvt vt;
+ if (dbLinkIsConstant(&prec->inp))
+ return 0;
+
+ vt.ptime = (dbLinkIsConstant(&prec->tsel) &&
+ prec->tse == epicsTimeEventDeviceTime) ? &prec->time : NULL;
+
+ status = dbLinkDoLocked(&prec->inp, readLocked, &vt);
if (status == S_db_noLSET)
- status = readLocked(&prec->inp, NULL);
+ status = readLocked(&prec->inp, &vt);
+
+ if (!status) {
+ if (strcmp(vt.newEvent, prec->val) != 0) {
+ strcpy(prec->val, vt.newEvent);
+ prec->epvt = eventNameToHandle(prec->val);
+ }
+ prec->udf = FALSE;
+ }
return status;
}
From 0748adfb9aca298cbcac4ad278711a02732d5c5b Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 26 Apr 2017 16:04:13 -0500
Subject: [PATCH 100/112] Additional linkInitTest checks
Now tests array record types and the eventRecord.
Also moved repeated IOC startup code into separate function.
---
src/std/rec/test/linkInitTest.c | 125 ++++++++++++++++++++++---------
src/std/rec/test/linkInitTest.db | 41 ++++++++--
2 files changed, 125 insertions(+), 41 deletions(-)
diff --git a/src/std/rec/test/linkInitTest.c b/src/std/rec/test/linkInitTest.c
index b99b98c69..cc17c07c5 100644
--- a/src/std/rec/test/linkInitTest.c
+++ b/src/std/rec/test/linkInitTest.c
@@ -4,9 +4,6 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
-
-#define EPICS_DBCA_PRIVATE_API
-
#include
#include "dbAccess.h"
@@ -19,21 +16,23 @@
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
-static void testLongStringInit()
+static void startTestIoc(const char *dbfile)
{
- testDiag("testLongStringInit");
-
testdbPrepare();
-
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
-
recTestIoc_registerRecordDeviceDriver(pdbbase);
-
- testdbReadDatabase("linkInitTest.db", NULL, NULL);
+ testdbReadDatabase(dbfile, NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
+}
+
+static void testLongStringInit()
+{
+ testDiag("testLongStringInit");
+
+ startTestIoc("linkInitTest.db");
{
const char buf[] = "!----------------------------------------------!";
@@ -64,17 +63,7 @@ static void testCalcInit()
{
testDiag("testCalcInit");
- testdbPrepare();
-
- testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
-
- recTestIoc_registerRecordDeviceDriver(pdbbase);
-
- testdbReadDatabase("linkInitTest.db", NULL, NULL);
-
- eltc(0);
- testIocInitOk();
- eltc(1);
+ startTestIoc("linkInitTest.db");
testdbGetFieldEqual("emptylink.VAL", DBR_DOUBLE, 0.0);
testdbGetFieldEqual("emptylink.SEVR", DBR_LONG, INVALID_ALARM);
@@ -97,21 +86,11 @@ static void testCalcInit()
testdbCleanup();
}
-static void testPrintfInit()
+static void testPrintfStrings()
{
- testDiag("testPrintfInit");
+ testDiag("testPrintfStrings");
- testdbPrepare();
-
- testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
-
- recTestIoc_registerRecordDeviceDriver(pdbbase);
-
- testdbReadDatabase("linkInitTest.db", NULL, NULL);
-
- eltc(0);
- testIocInitOk();
- eltc(1);
+ startTestIoc("linkInitTest.db");
{
const char buf1[] = "Test string, exactly 40 characters long";
@@ -149,11 +128,85 @@ static void testPrintfInit()
testdbCleanup();
}
+static void testArrayInputs()
+{
+ epicsInt32 oneToTwelve[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+
+ testDiag("testArrayInputs");
+
+ startTestIoc("linkInitTest.db");
+
+ testdbGetFieldEqual("aai1.NORD", DBR_LONG, 10);
+ testdbGetFieldEqual("aai1.UDF", DBR_UCHAR, 0);
+ testdbGetFieldEqual("sa1.NORD", DBR_LONG, 10);
+ testdbGetFieldEqual("sa1.UDF", DBR_UCHAR, 0);
+ testdbGetFieldEqual("sa2.NORD", DBR_LONG, 0);
+ testdbGetFieldEqual("sa2.UDF", DBR_UCHAR, 1);
+ testdbGetFieldEqual("wf1.NORD", DBR_LONG, 10);
+ testdbGetFieldEqual("wf1.UDF", DBR_UCHAR, 0);
+
+ testdbGetArrFieldEqual("aai1.VAL", DBF_LONG, 12, 10, &oneToTwelve[0]);
+ testdbGetArrFieldEqual("sa1.VAL", DBF_LONG, 12, 10, &oneToTwelve[2]);
+ testdbGetArrFieldEqual("sa2.VAL", DBF_LONG, 10, 0, NULL);
+ testdbGetArrFieldEqual("wf1.VAL", DBF_LONG, 12, 10, &oneToTwelve[0]);
+
+ testdbPutFieldOk("sa1.INDX", DBF_LONG, 3);
+ testdbGetArrFieldEqual("sa1.VAL", DBF_LONG, 12, 9, &oneToTwelve[3]);
+
+ testdbPutFieldOk("sa1.NELM", DBF_LONG, 3);
+ testdbGetArrFieldEqual("sa1.VAL", DBF_LONG, 12, 3, &oneToTwelve[3]);
+
+ testdbPutFieldOk("sa2.VAL", DBF_LONG, 1);
+ testdbGetArrFieldEqual("sa2.VAL", DBF_LONG, 10, 1, &oneToTwelve[0]);
+
+ testIocShutdownOk();
+ testdbCleanup();
+}
+
+static void testEventRecord()
+{
+ testMonitor *countmon;
+
+ testDiag("testEventRecord");
+
+ startTestIoc("linkInitTest.db");
+ countmon = testMonitorCreate("count1.VAL", DBR_LONG, 0);
+
+ testdbGetFieldEqual("ev1.VAL", DBR_STRING, "soft event 1");
+ testdbGetFieldEqual("ev1.UDF", DBR_UCHAR, 0);
+ testdbGetFieldEqual("ev2.VAL", DBR_STRING, "");
+ testdbGetFieldEqual("ev2.UDF", DBR_UCHAR, 1);
+ testdbGetFieldEqual("count1.VAL", DBR_LONG, 0);
+
+ testdbPutFieldOk("ev1.PROC", DBF_UCHAR, 1);
+ testMonitorWait(countmon);
+ testdbGetFieldEqual("count1.VAL", DBR_LONG, 1);
+
+ testdbPutFieldOk("ev2.PROC", DBF_UCHAR, 1);
+ testMonitorWait(countmon);
+ testdbGetFieldEqual("ev2.UDF", DBR_UCHAR, 0);
+ testdbGetFieldEqual("count1.VAL", DBR_LONG, 2);
+
+ testdbPutFieldOk("count1.EVNT", DBF_STRING, "Tock");
+ testdbPutFieldOk("ev2.PROC", DBF_UCHAR, 1);
+ testMonitorWait(countmon);
+ testdbGetFieldEqual("count1.VAL", DBR_LONG, 3);
+
+ testMonitorDestroy(countmon);
+ testIocShutdownOk();
+ testdbCleanup();
+}
+
+
MAIN(linkInitTest)
{
- testPlan(31);
+ testPlan(62);
+
testLongStringInit();
testCalcInit();
- testPrintfInit();
+ testPrintfStrings();
+ testArrayInputs();
+ testEventRecord();
+
return testDone();
}
diff --git a/src/std/rec/test/linkInitTest.db b/src/std/rec/test/linkInitTest.db
index 0e9bbf55e..6887b56ba 100644
--- a/src/std/rec/test/linkInitTest.db
+++ b/src/std/rec/test/linkInitTest.db
@@ -2,25 +2,22 @@ record(lsi, "longstr1") {
field(SIZV, "100")
field(INP, ["!----------------------------------------------!"])
}
-
record(lsi, "longstr2") {
field(SIZV, "100")
field(INP, {const: ["!----------------------------------------------!"]})
}
-
record(lsi, "longstr3") {
field(SIZV, "100")
field(INP, {const: "!----------------------------------------------!"})
}
-
-record(stringin, "longstr4") {
+record(lsi, "longstr4") {
+ field(SIZV, "100")
field(INP, ["One","Two","Three","Four"])
}
record(ai, "emptylink" ) {
field(INP, {calc: {expr:"0"}})
}
-
record(ai, "emptylink1" ) {
field(INP, {calc: {expr:"1"}})
}
@@ -34,3 +31,37 @@ record(printf, "printf2") {
field(INP0, ["Longer test string, more that 40 characters long"])
}
+record(waveform, "aai1") {
+ field(NELM, 10)
+ field(FTVL, "LONG")
+ field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
+}
+record(subArray, "sa1") {
+ field(FTVL, "LONG")
+ field(MALM, 12)
+ field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
+ field(INDX, 2)
+ field(NELM, 10)
+}
+record(subArray, "sa2") {
+ field(FTVL, "LONG")
+ field(MALM, 10)
+ field(NELM, 1)
+}
+record(waveform, "wf1") {
+ field(NELM, 10)
+ field(FTVL, "LONG")
+ field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
+}
+
+record(longin, "count1" ) {
+ field(INP, {calc: {expr:"VAL+1"}})
+ field(SCAN, "Event")
+ field(EVNT, "soft event 1")
+}
+record(event, "ev1") {
+ field(INP, ["soft event 1"])
+}
+record(event, "ev2") {
+ field(INP, "count1.EVNT")
+}
From e51cc39b0c485c2e6d2a98752516f9c8ffcb5a4d Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Thu, 27 Apr 2017 17:24:23 -0400
Subject: [PATCH 101/112] ioc/as: dbCore needs ca
---
src/ioc/as/Makefile | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/ioc/as/Makefile b/src/ioc/as/Makefile
index 971e6a594..25237c26c 100644
--- a/src/ioc/as/Makefile
+++ b/src/ioc/as/Makefile
@@ -23,5 +23,4 @@ dbCore_SRCS += asIocRegister.c
PROD_HOST += ascheck
ascheck_SRCS = ascheck.c
-ascheck_LIBS = dbCore
-
+ascheck_LIBS = dbCore ca
From 579a0791ea271b77d36f088537fcc49d9c94b609 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Thu, 27 Apr 2017 19:46:33 -0400
Subject: [PATCH 102/112] jlink conditional debug print
Enable magic info("linkDebug","YES") to enable
debug prints during parsing.
---
src/ioc/db/dbAccess.c | 2 +-
src/ioc/db/dbJLink.c | 60 +++++++++++++++------------------
src/ioc/db/dbJLink.h | 3 +-
src/ioc/db/test/dbPutLinkTest.c | 4 +--
src/ioc/dbStatic/dbStaticLib.c | 19 ++++++++---
src/ioc/dbStatic/dbStaticPvt.h | 4 ++-
6 files changed, 51 insertions(+), 41 deletions(-)
diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c
index 46b47fb04..5331b30ac 100644
--- a/src/ioc/db/dbAccess.c
+++ b/src/ioc/db/dbAccess.c
@@ -1006,7 +1006,7 @@ static long dbPutFieldLink(DBADDR *paddr,
return S_db_badDbrtype;
}
- status = dbParseLink(pstring, pfldDes->field_type, &link_info);
+ status = dbParseLink(pstring, pfldDes->field_type, &link_info, 0);
if (status)
return status;
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index 5638e73ee..f634e6d3c 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -18,24 +18,15 @@
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbCommon.h"
+#include "dbStaticLib.h"
+#include "dbStaticPvt.h"
#include "dbLink.h"
#include "dbJLink.h"
#include "dbLock.h"
#include "dbStaticLib.h"
#include "link.h"
-/* Change 'undef' to 'define' to turn on debug statements: */
-#undef DEBUG_JLINK
-
-#ifdef DEBUG_JLINK
- int jlinkDebug = 10;
-# define IFDEBUG(n) \
- if (jlinkDebug >= n) /* block or statement */
-#else
-# define IFDEBUG(n) \
- if(0) /* Compiler will elide the block or statement */
-#endif
-
+#define IFDEBUG(n) if(parser->debug)
typedef struct parseContext {
jlink *pjlink;
@@ -43,6 +34,7 @@ typedef struct parseContext {
short dbfType;
short jsonDepth;
unsigned key_is_link:1;
+ unsigned debug:1;
} parseContext;
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
@@ -51,9 +43,9 @@ static int dbjl_return(parseContext *parser, jlif_result result) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
- printf("dbjl_return(%s@%p, %d)\t", pjlink->pif->name, pjlink, result);
+ printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
+ parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
if (result == jlif_stop && pjlink) {
@@ -74,19 +66,21 @@ static int dbjl_value(parseContext *parser, jlif_result result) {
jlink *parent;
IFDEBUG(10) {
- printf("dbjl_value(%s@%p, %d)\t", pjlink->pif->name, pjlink, result);
+ printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
+ parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
if (result == jlif_stop || pjlink->parseDepth > 0)
return dbjl_return(parser, result);
parent = pjlink->parent;
- if (!parent)
+ if (!parent) {
parser->product = pjlink;
- else if (parent->pif->end_child)
+ } else if (parent->pif->end_child) {
parent->pif->end_child(parent, pjlink);
+ }
+ pjlink->debug = 0;
parser->pjlink = parent;
@@ -101,7 +95,7 @@ static int dbjl_null(void *ctx) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
- printf("dbjl_null(%s@%p)\n", pjlink->pif->name, pjlink);
+ printf("dbjl_null(%s@%p)\n", pjlink ? pjlink->pif->name : "", pjlink);
assert(pjlink);
return dbjl_value(parser,
@@ -175,9 +169,9 @@ static int dbjl_start_map(void *ctx) {
}
IFDEBUG(10) {
- printf("dbjl_start_map(%s@%p)\t", pjlink->pif->name, pjlink);
+ printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
+ parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
pjlink->parseDepth++;
@@ -213,7 +207,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
pjlink->pif->name, pjlink, len, key);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
+ parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
assert(pjlink->parseDepth > 0);
@@ -256,6 +250,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
pjlink->pif = pjlif;
pjlink->parent = NULL;
pjlink->parseDepth = 0;
+ pjlink->debug = !!parser->debug;
if (parser->pjlink) {
/* We're starting a child link, save its parent */
@@ -265,7 +260,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
parser->key_is_link = 0;
IFDEBUG(8)
- printf("dbjl_map_key: New %s@%p\n", pjlink->pif->name, pjlink);
+ printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink);
return jlif_continue;
}
@@ -301,9 +296,9 @@ static int dbjl_start_array(void *ctx) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
- printf("dbjl_start_array(%s@%p)\t", pjlink->pif->name, pjlink);
+ printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
+ parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
assert(pjlink);
@@ -319,9 +314,9 @@ static int dbjl_end_array(void *ctx) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
- printf("dbjl_end_array(%s@%p)\t", pjlink->pif->name, pjlink);
+ printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
- parser->jsonDepth, pjlink->parseDepth, parser->key_is_link);
+ parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
assert(pjlink);
@@ -342,7 +337,7 @@ static const yajl_parser_config dbjl_config =
{ 0, 0 }; /* allowComments = NO, checkUTF8 = NO */
long dbJLinkParse(const char *json, size_t jlen, short dbfType,
- jlink **ppjlink)
+ jlink **ppjlink, unsigned opts)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbjl_allocs;
@@ -350,15 +345,16 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
yajl_status ys;
long status;
- IFDEBUG(10)
- printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
- (int) jlen, json, dbfType, ppjlink);
-
parser->pjlink = NULL;
parser->product = NULL;
parser->dbfType = dbfType;
parser->jsonDepth = 0;
parser->key_is_link = 0;
+ parser->debug = !!(opts&LINK_DEBUG);
+
+ IFDEBUG(10)
+ printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
+ (int) jlen, json, dbfType, ppjlink);
IFDEBUG(10)
printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n",
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index 38476b1fd..8924c5d4a 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -35,6 +35,7 @@ typedef struct jlink {
struct jlif *pif; /* Link methods */
struct jlink *parent; /* NULL for top-level links */
int parseDepth; /* Used by parser, unused afterwards */
+ unsigned debug:1; /* set by caller of jlif operations to request debug output to console */
/* Link types extend or embed this structure for private storage */
} jlink;
@@ -112,7 +113,7 @@ typedef struct jlif {
} jlif;
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
- jlink **ppjlink);
+ jlink **ppjlink, unsigned opts);
epicsShareFunc long dbJLinkInit(struct link *plink);
epicsShareFunc void dbJLinkFree(jlink *);
diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c
index d8024c82a..b39b98db2 100644
--- a/src/ioc/db/test/dbPutLinkTest.c
+++ b/src/ioc/db/test/dbPutLinkTest.c
@@ -86,7 +86,7 @@ static void testLinkParse(void)
for (;td->str; td++) {
int i, N;
testDiag("Parsing \"%s\"", td->str);
- testOk(dbParseLink(td->str, DBF_INLINK, &info) == 0, "Parser returned OK");
+ testOk(dbParseLink(td->str, DBF_INLINK, &info, 0) == 0, "Parser returned OK");
if (!testOk(info.ltype == td->info.ltype, "Link type value"))
testDiag("Expected %d, got %d", td->info.ltype, info.ltype);
if (td->info.target)
@@ -146,7 +146,7 @@ static void testLinkFailParse(void)
eltc(1);
for(;*td; td++) {
- testOk(dbParseLink(*td, DBF_INLINK, &info) == S_dbLib_badField,
+ testOk(dbParseLink(*td, DBF_INLINK, &info, 0) == S_dbLib_badField,
"dbParseLink correctly rejected \"%s\"", *td);
}
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index a9de8ea3c..82f300c64 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2175,7 +2175,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
if(!plink->text)
continue;
- if(dbParseLink(plink->text, pflddes->field_type, &link_info)!=0) {
+ if(dbParseLink(plink->text, pflddes->field_type, &link_info, 0)!=0) {
/* This was already parsed once when ->text was set.
* Any syntax error messages were printed at that time.
*/
@@ -2204,7 +2204,7 @@ void dbFreeLinkInfo(dbLinkInfo *pinfo)
pinfo->target = NULL;
}
-long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
+long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts)
{
char *pstr;
size_t len;
@@ -2240,7 +2240,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
/* Check for braces => JSON */
if (*str == '{' && str[len-1] == '}') {
- if (dbJLinkParse(str, len, ftype, &pinfo->jlink))
+ if (dbJLinkParse(str, len, ftype, &pinfo->jlink, opts))
goto fail;
pinfo->ltype = JSON_LINK;
@@ -2573,8 +2573,19 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
case DBF_FWDLINK: {
dbLinkInfo link_info;
DBLINK *plink = (DBLINK *)pfield;
+ DBENTRY infoentry;
+ unsigned opts = 0;
- status = dbParseLink(pstring, pflddes->field_type, &link_info);
+ if(pdbentry->precnode && ellCount(&pdbentry->precnode->infoList)) {
+ dbCopyEntryContents(pdbentry, &infoentry);
+
+ if(dbFindInfo(&infoentry, "linkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
+ opts |= LINK_DEBUG;
+
+ dbFinishEntry(&infoentry);
+ }
+
+ status = dbParseLink(pstring, pflddes->field_type, &link_info, opts);
if (status) break;
if (plink->type==CONSTANT && plink->value.constantStr==NULL) {
diff --git a/src/ioc/dbStatic/dbStaticPvt.h b/src/ioc/dbStatic/dbStaticPvt.h
index 4e7d2d6f1..3af74459b 100644
--- a/src/ioc/dbStatic/dbStaticPvt.h
+++ b/src/ioc/dbStatic/dbStaticPvt.h
@@ -59,10 +59,12 @@ typedef struct dbLinkInfo {
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
+#define LINK_DEBUG 1
+
/* Parse link string. no record locks needed.
* on success caller must free pinfo->target
*/
-epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo);
+epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts);
/* Check if link type allow the parsed link value pinfo
* to be assigned to the given link.
* Record containing plink must be locked.
From be8de34130e9cdb877deb5f35b01ef77c5c5ec8a Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Thu, 27 Apr 2017 19:50:46 -0400
Subject: [PATCH 103/112] std/link: all calc example
---
documentation/RELEASE_NOTES.html | 7 +++++++
src/std/link/lnkCalc.c | 6 +++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index ce6a00896..48f48c64e 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -90,6 +90,13 @@ from const links.
+
+ field(INP, {calc:{expr:"A+B+1",
+ args:[{const:5}, # A
+ {const:6}] # B
+ }})
+
+
The new link types are documented in a
separate
document
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 70d47426e..7f311d017 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -6,7 +6,11 @@
\*************************************************************************/
/* lnkCalc.c */
-/* TODO:
+/* Current usage
+ * {calc:{expr:"A", args:[{...}, ...]}}
+ * First link in 'args' is 'A', second is 'B', and so forth.
+ *
+ * TODO:
* Support setting individual input links instead of the args list.
* {calc:{expr:"K", K:{...}}}
*/
From d397f0fd924f70b75a4d50f29b2f53e3f5b7429a Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 28 Apr 2017 15:43:17 -0400
Subject: [PATCH 104/112] ioc/db: dbUnitTest testMonitor leaks dbChannel
---
src/ioc/db/dbUnitTest.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/ioc/db/dbUnitTest.c b/src/ioc/db/dbUnitTest.c
index 6926595c2..c259e1234 100644
--- a/src/ioc/db/dbUnitTest.c
+++ b/src/ioc/db/dbUnitTest.c
@@ -36,6 +36,7 @@ static ELLLIST testEvtList; /* holds testMonitor::node */
struct testMonitor {
ELLNODE node;
dbEventSubscription sub;
+ dbChannel *chan;
epicsEventId event;
unsigned count;
};
@@ -322,7 +323,7 @@ testMonitor* testMonitorCreate(const char* pvname, unsigned mask, unsigned opt)
mon->event = epicsEventMustCreate(epicsEventEmpty);
- chan = dbChannelCreate(pvname);
+ chan = mon->chan = dbChannelCreate(pvname);
if(!chan)
testAbort("testMonitorCreate - dbChannelCreate(\"%s\") fails", pvname);
if(!!(status=dbChannelOpen(chan)))
@@ -353,6 +354,8 @@ void testMonitorDestroy(testMonitor *mon)
db_cancel_event(mon->sub);
+ dbChannelDelete(mon->chan);
+
epicsEventDestroy(mon->event);
free(mon);
From b4db176e489f67af5e9f8bad53d2b9141327fddb Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Sat, 15 Apr 2017 20:27:50 -0400
Subject: [PATCH 105/112] ioc/db: cleanup dbEvent freeLists
---
src/ioc/db/dbEvent.c | 16 ++++++++++++++++
src/ioc/db/dbEvent.h | 4 ++++
src/ioc/db/dbUnitTest.c | 3 +++
3 files changed, 23 insertions(+)
diff --git a/src/ioc/db/dbEvent.c b/src/ioc/db/dbEvent.c
index 5e386dd5c..a5830881f 100644
--- a/src/ioc/db/dbEvent.c
+++ b/src/ioc/db/dbEvent.c
@@ -321,6 +321,22 @@ fail:
return NULL;
}
+
+epicsShareFunc void db_cleanup_events(void)
+{
+ freeListCleanup(dbevEventUserFreeList);
+ dbevEventUserFreeList = NULL;
+
+ freeListCleanup(dbevEventQueueFreeList);
+ dbevEventQueueFreeList = NULL;
+
+ freeListCleanup(dbevEventSubscriptionFreeList);
+ dbevEventSubscriptionFreeList = NULL;
+
+ freeListCleanup(dbevFieldLogFreeList);
+ dbevFieldLogFreeList = NULL;
+}
+
/*
* DB_CLOSE_EVENTS()
*
diff --git a/src/ioc/db/dbEvent.h b/src/ioc/db/dbEvent.h
index fe0e52f90..8ee109373 100644
--- a/src/ioc/db/dbEvent.h
+++ b/src/ioc/db/dbEvent.h
@@ -63,6 +63,10 @@ epicsShareFunc void db_flush_extra_labor_event (dbEventCtx);
epicsShareFunc int db_post_extra_labor (dbEventCtx ctx);
epicsShareFunc void db_event_change_priority ( dbEventCtx ctx, unsigned epicsPriority );
+#ifdef EPICS_PRIVATE_API
+epicsShareFunc void db_cleanup_events(void);
+#endif
+
typedef void EVENTFUNC (void *user_arg, struct dbChannel *chan,
int eventsRemaining, struct db_field_log *pfl);
diff --git a/src/ioc/db/dbUnitTest.c b/src/ioc/db/dbUnitTest.c
index c259e1234..48ad0f0c6 100644
--- a/src/ioc/db/dbUnitTest.c
+++ b/src/ioc/db/dbUnitTest.c
@@ -12,6 +12,8 @@
#include
+#define EPICS_PRIVATE_API
+
#include "dbmf.h"
#include "epicsUnitTest.h"
#include "osiFileName.h"
@@ -90,6 +92,7 @@ void testIocShutdownOk(void)
void testdbCleanup(void)
{
dbFreeBase(pdbbase);
+ db_cleanup_events();
initHookFree();
registryFree();
pdbbase = NULL;
From d752b962d54b43531a8a2aa589d9a09f227b174c Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 28 Apr 2017 16:44:18 -0400
Subject: [PATCH 106/112] ioc/db: dbUnitTest add testdbPutArrFieldOk()
---
src/ioc/db/dbUnitTest.c | 15 +++++++++++++++
src/ioc/db/dbUnitTest.h | 2 ++
2 files changed, 17 insertions(+)
diff --git a/src/ioc/db/dbUnitTest.c b/src/ioc/db/dbUnitTest.c
index 48ad0f0c6..644741e5e 100644
--- a/src/ioc/db/dbUnitTest.c
+++ b/src/ioc/db/dbUnitTest.c
@@ -227,6 +227,21 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
}
}
+void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf)
+{
+ DBADDR addr;
+ long status;
+
+ if (dbNameToAddr(pv, &addr)) {
+ testFail("Missing PV \"%s\"", pv);
+ return;
+ }
+
+ status = dbPutField(&addr, dbrType, pbuf, count);
+
+ testOk(status==0, "dbPutField(\"%s\", dbr=%d, count=%lu, ...) -> %ld", pv, dbrType, count, status);
+}
+
void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long cnt, const void *pbufraw)
{
DBADDR addr;
diff --git a/src/ioc/db/dbUnitTest.h b/src/ioc/db/dbUnitTest.h
index 82954c277..31d068350 100644
--- a/src/ioc/db/dbUnitTest.h
+++ b/src/ioc/db/dbUnitTest.h
@@ -55,6 +55,8 @@ epicsShareFunc long testdbVPutField(const char* pv, short dbrType, va_list ap);
epicsShareFunc void testdbGetFieldEqual(const char* pv, short dbrType, ...);
epicsShareFunc void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap);
+epicsShareFunc void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf);
+
/**
* @param pv PV name string
* @param dbfType One of the DBF_* macros from dbAccess.h
From 2a1f7909093a1b6e87dfceea7a00aa8fdca5107a Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 28 Apr 2017 16:44:55 -0400
Subject: [PATCH 107/112] std/rec/test: extend linkRetargetLink w/ jlink
---
src/std/rec/test/linkRetargetLink.db | 8 +++
src/std/rec/test/linkRetargetLinkTest.c | 66 +++++++++++++++++--------
2 files changed, 53 insertions(+), 21 deletions(-)
diff --git a/src/std/rec/test/linkRetargetLink.db b/src/std/rec/test/linkRetargetLink.db
index 3306e43ea..16d033e44 100644
--- a/src/std/rec/test/linkRetargetLink.db
+++ b/src/std/rec/test/linkRetargetLink.db
@@ -15,3 +15,11 @@ record(stringout, "rec:link2") {
field(VAL, "rec:src2 CP")
field(OUT, "rec:ai.INP CA")
}
+
+record(ai, "rec:j1") {
+ field(INP, {calc:{
+ expr:"A+5",
+ args:{const:5}
+ }})
+ field(PINI, "YES")
+}
diff --git a/src/std/rec/test/linkRetargetLinkTest.c b/src/std/rec/test/linkRetargetLinkTest.c
index 894c94587..8000419d6 100644
--- a/src/std/rec/test/linkRetargetLinkTest.c
+++ b/src/std/rec/test/linkRetargetLinkTest.c
@@ -27,24 +27,7 @@ static void testRetarget(void)
{
testMonitor *lnkmon, *valmon;
- testdbPrepare();
-
- testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
-
- recTestIoc_registerRecordDeviceDriver(pdbbase);
-
- testdbReadDatabase("linkRetargetLink.db", NULL, NULL);
-
- eltc(0);
- testIocInitOk();
- eltc(1);
- /* wait for local CA links to be connected or dbPutField() will fail */
- /* wait for initial CA_CONNECT actions to be processed.
- * Assume that local CA links deliver callbacks synchronously
- * eg. that ca_create_channel() will invoke the connection callback
- * before returning.
- */
- dbCaSync();
+ testDiag("In testRetarget");
lnkmon = testMonitorCreate("rec:ai.INP", DBE_VALUE, 0);
valmon = testMonitorCreate("rec:ai", DBE_VALUE, 0);
@@ -80,15 +63,56 @@ static void testRetarget(void)
testMonitorDestroy(lnkmon);
testMonitorDestroy(valmon);
+}
- testIocShutdownOk();
+#define testLongStrEq(PV, VAL) testdbGetArrFieldEqual(PV, DBF_CHAR, sizeof(VAL)+2, sizeof(VAL), VAL)
+#define testPutLongStr(PV, VAL) testdbPutArrFieldOk(PV, DBF_CHAR, sizeof(VAL), VAL);
- testdbCleanup();
+static void testRetargetJLink(void)
+{
+ testDiag("In testRetargetJLink");
+
+ testdbGetFieldEqual("rec:j1", DBF_DOUBLE, 10.0);
+ /* without [] */
+ testLongStrEq("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":{\"const\":5}}}");
+
+ /* with [] */
+ testPutLongStr("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[{\"const\":7}]}}");
+ testdbPutFieldOk("rec:j1.PROC", DBF_LONG, 1);
+
+ testdbGetFieldEqual("rec:j1", DBF_DOUBLE, 12.0);
+ testLongStrEq("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[{\"const\":7}]}}");
}
MAIN(linkRetargetLinkTest)
{
- testPlan(10);
+ testPlan(16);
+
+ testdbPrepare();
+
+ testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
+
+ recTestIoc_registerRecordDeviceDriver(pdbbase);
+
+ testdbReadDatabase("linkRetargetLink.db", NULL, NULL);
+
+ eltc(0);
+ testIocInitOk();
+ eltc(1);
+ /* wait for local CA links to be connected or dbPutField() will fail */
+ /* wait for initial CA_CONNECT actions to be processed.
+ * Assume that local CA links deliver callbacks synchronously
+ * eg. that ca_create_channel() will invoke the connection callback
+ * before returning.
+ */
+ dbCaSync();
+
testRetarget();
+ testRetargetJLink();
+
+ testIocShutdownOk();
+
+ testdbCleanup();
+
return testDone();
}
From 4a9fe82575c46418d705ca665327db51c11bbd30 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 28 Apr 2017 16:57:07 -0400
Subject: [PATCH 108/112] std/link: runtime conditional debugging in calc/const
---
src/std/link/lnkCalc.c | 20 +++++++++-----------
src/std/link/lnkConst.c | 24 ++++++++++++------------
2 files changed, 21 insertions(+), 23 deletions(-)
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 7f311d017..05acf3350 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -38,17 +38,7 @@
typedef long (*FASTCONVERT)();
-/* Change 'undef' to 'define' to turn on debug statements: */
-#undef DEBUG_LINK
-
-#ifdef DEBUG_LINK
- int lnkCalcDebug = 10;
-# define IFDEBUG(n) \
- if (lnkCalcDebug >= n) /* block or statement */
-#else
-# define IFDEBUG(n) \
- if(0) /* Compiler will elide the block or statement */
-#endif
+#define IFDEBUG(n) if(clink->jlink.debug)
typedef struct calc_link {
jlink jlink; /* embedded object */
@@ -348,6 +338,8 @@ static void lnkCalc_end_child(jlink *parent, jlink *child)
static struct lset* lnkCalc_get_lset(const jlink *pjlink)
{
+ calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
+
IFDEBUG(10)
printf("lnkCalc_get_lset(calc@%p)\n", pjlink);
@@ -480,6 +472,9 @@ static int lnkCalc_isConn(const struct link *plink)
static int lnkCalc_getDBFtype(const struct link *plink)
{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+
IFDEBUG(10) {
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
@@ -492,6 +487,9 @@ static int lnkCalc_getDBFtype(const struct link *plink)
static long lnkCalc_getElements(const struct link *plink, long *nelements)
{
+ calc_link *clink = CONTAINER(plink->value.json.jlink,
+ struct calc_link, jlink);
+
IFDEBUG(10) {
calc_link *clink = CONTAINER(plink->value.json.jlink,
struct calc_link, jlink);
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index 5fcf84bc4..a647e6a60 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -22,17 +22,7 @@
#include "epicsExport.h"
-/* Change 'undef' to 'define' to turn on debug statements: */
-#undef DEBUG_LINK
-
-#ifdef DEBUG_LINK
- int lnkConstDebug = 10;
-# define IFDEBUG(n) \
- if (lnkConstDebug >= n) /* block or statement */
-#else
-# define IFDEBUG(n) \
- if(0) /* Compiler will elide the block or statement */
-#endif
+#define IFDEBUG(n) if(clink->jlink.debug)
typedef long (*FASTCONVERT)();
@@ -148,7 +138,9 @@ static jlif_result lnkConst_integer(jlink *pjlink, long num)
return jlif_continue;
}
-static jlif_result lnkConst_boolean(jlink *pjlink, int val) {
+static jlif_result lnkConst_boolean(jlink *pjlink, int val)
+{
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_boolean(const@%p, %d)\n", pjlink, val);
@@ -278,6 +270,8 @@ static jlif_result lnkConst_start_array(jlink *pjlink)
static jlif_result lnkConst_end_array(jlink *pjlink)
{
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
+
IFDEBUG(10)
printf("lnkConst_end_array(const@%p)\n", pjlink);
@@ -286,6 +280,8 @@ static jlif_result lnkConst_end_array(jlink *pjlink)
static struct lset* lnkConst_get_lset(const jlink *pjlink)
{
+ const_link *clink = CONTAINER(pjlink, const_link, jlink);
+
IFDEBUG(10)
printf("lnkConst_get_lset(const@%p)\n", pjlink);
@@ -538,6 +534,8 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
static long lnkConst_getNelements(const struct link *plink, long *nelements)
{
+ const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
+
IFDEBUG(10)
printf("lnkConst_getNelements(const@%p, (%ld))\n",
plink->value.json.jlink, *nelements);
@@ -549,6 +547,8 @@ static long lnkConst_getNelements(const struct link *plink, long *nelements)
static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
+ const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
+
IFDEBUG(10)
printf("lnkConst_getValue(const@%p, %d, %p, ... (%ld))\n",
plink->value.json.jlink, dbrType, pbuffer, *pnRequest);
From f65b2119ade2a961e8551c940eaf8ba863501376 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Fri, 28 Apr 2017 17:11:47 -0400
Subject: [PATCH 109/112] separate jlink and lset debug flags
"lsetDebug" for lset callbacks and "jlinkDebug" for jlink parsing.
---
src/ioc/db/dbJLink.c | 10 ++++++----
src/ioc/dbStatic/dbStaticLib.c | 6 ++++--
src/ioc/dbStatic/dbStaticPvt.h | 3 ++-
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c
index f634e6d3c..b68432f6e 100644
--- a/src/ioc/db/dbJLink.c
+++ b/src/ioc/db/dbJLink.c
@@ -26,7 +26,7 @@
#include "dbStaticLib.h"
#include "link.h"
-#define IFDEBUG(n) if(parser->debug)
+#define IFDEBUG(n) if(parser->parse_debug)
typedef struct parseContext {
jlink *pjlink;
@@ -34,7 +34,8 @@ typedef struct parseContext {
short dbfType;
short jsonDepth;
unsigned key_is_link:1;
- unsigned debug:1;
+ unsigned parse_debug:1;
+ unsigned lset_debug:1;
} parseContext;
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
@@ -250,7 +251,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
pjlink->pif = pjlif;
pjlink->parent = NULL;
pjlink->parseDepth = 0;
- pjlink->debug = !!parser->debug;
+ pjlink->debug = !!parser->lset_debug;
if (parser->pjlink) {
/* We're starting a child link, save its parent */
@@ -350,7 +351,8 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType,
parser->dbfType = dbfType;
parser->jsonDepth = 0;
parser->key_is_link = 0;
- parser->debug = !!(opts&LINK_DEBUG);
+ parser->parse_debug = !!(opts&LINK_DEBUG_JPARSE);
+ parser->lset_debug = !!(opts&LINK_DEBUG_LSET);
IFDEBUG(10)
printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index 82f300c64..d54b37b87 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2579,8 +2579,10 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
if(pdbentry->precnode && ellCount(&pdbentry->precnode->infoList)) {
dbCopyEntryContents(pdbentry, &infoentry);
- if(dbFindInfo(&infoentry, "linkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
- opts |= LINK_DEBUG;
+ if(dbFindInfo(&infoentry, "lsetDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
+ opts |= LINK_DEBUG_LSET;
+ if(dbFindInfo(&infoentry, "jlinkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
+ opts |= LINK_DEBUG_JPARSE;
dbFinishEntry(&infoentry);
}
diff --git a/src/ioc/dbStatic/dbStaticPvt.h b/src/ioc/dbStatic/dbStaticPvt.h
index 3af74459b..58d32c28c 100644
--- a/src/ioc/dbStatic/dbStaticPvt.h
+++ b/src/ioc/dbStatic/dbStaticPvt.h
@@ -59,7 +59,8 @@ typedef struct dbLinkInfo {
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
-#define LINK_DEBUG 1
+#define LINK_DEBUG_LSET 1
+#define LINK_DEBUG_JPARSE 2
/* Parse link string. no record locks needed.
* on success caller must free pinfo->target
From 1cad1c5ba6b91bd172d2b9b36ea03cc60a25643b Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Sat, 29 Apr 2017 20:43:54 -0500
Subject: [PATCH 110/112] Demonstrate and use numeric literals in calc args
---
documentation/RELEASE_NOTES.html | 2 +-
src/std/rec/test/linkRetargetLink.db | 2 +-
src/std/rec/test/linkRetargetLinkTest.c | 10 +++++++---
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 48f48c64e..20287ed4f 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -92,7 +92,7 @@ from const links.
field(INP, {calc:{expr:"A+B+1",
- args:[{const:5}, # A
+ args:[5, # A
{const:6}] # B
}})
diff --git a/src/std/rec/test/linkRetargetLink.db b/src/std/rec/test/linkRetargetLink.db
index 16d033e44..148e2d50b 100644
--- a/src/std/rec/test/linkRetargetLink.db
+++ b/src/std/rec/test/linkRetargetLink.db
@@ -19,7 +19,7 @@ record(stringout, "rec:link2") {
record(ai, "rec:j1") {
field(INP, {calc:{
expr:"A+5",
- args:{const:5}
+ args:5
}})
field(PINI, "YES")
}
diff --git a/src/std/rec/test/linkRetargetLinkTest.c b/src/std/rec/test/linkRetargetLinkTest.c
index 8000419d6..2a37696aa 100644
--- a/src/std/rec/test/linkRetargetLinkTest.c
+++ b/src/std/rec/test/linkRetargetLinkTest.c
@@ -73,10 +73,14 @@ static void testRetargetJLink(void)
testDiag("In testRetargetJLink");
testdbGetFieldEqual("rec:j1", DBF_DOUBLE, 10.0);
- /* without [] */
- testLongStrEq("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":{\"const\":5}}}");
+ /* minimal args */
+ testLongStrEq("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":5}}");
/* with [] */
+ testPutLongStr("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[7]}}");
+ testdbPutFieldOk("rec:j1.PROC", DBF_LONG, 1);
+
+ /* with const */
testPutLongStr("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[{\"const\":7}]}}");
testdbPutFieldOk("rec:j1.PROC", DBF_LONG, 1);
@@ -86,7 +90,7 @@ static void testRetargetJLink(void)
MAIN(linkRetargetLinkTest)
{
- testPlan(16);
+ testPlan(18);
testdbPrepare();
From b4c625d8d12749e163fd2bfe2a07d216437f915e Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Wed, 3 May 2017 17:27:57 -0400
Subject: [PATCH 111/112] jlif future proof for 64-bit json parser
---
src/ioc/db/dbJLink.h | 2 +-
src/ioc/db/test/jlinkz.c | 2 +-
src/std/link/lnkCalc.c | 6 +++---
src/std/link/lnkConst.c | 4 ++--
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h
index 8924c5d4a..61b59670b 100644
--- a/src/ioc/db/dbJLink.h
+++ b/src/ioc/db/dbJLink.h
@@ -62,7 +62,7 @@ typedef struct jlif {
jlif_result (*parse_boolean)(jlink *, int val);
/* Optional, parser saw a boolean value */
- jlif_result (*parse_integer)(jlink *, long num);
+ jlif_result (*parse_integer)(jlink *, long long num);
/* Optional, parser saw an integer value */
jlif_result (*parse_double)(jlink *, double num);
diff --git a/src/ioc/db/test/jlinkz.c b/src/ioc/db/test/jlinkz.c
index 7bb8b831e..6683c6779 100644
--- a/src/ioc/db/test/jlinkz.c
+++ b/src/ioc/db/test/jlinkz.c
@@ -187,7 +187,7 @@ void z_free(jlink *pj)
}
static
-jlif_result z_int(jlink *pj, long num)
+jlif_result z_int(jlink *pj, long long num)
{
zpriv *priv = CONTAINER(pj, zpriv, base);
diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c
index 05acf3350..286b61702 100644
--- a/src/std/link/lnkCalc.c
+++ b/src/std/link/lnkCalc.c
@@ -109,12 +109,12 @@ static void lnkCalc_free(jlink *pjlink)
free(clink);
}
-static jlif_result lnkCalc_integer(jlink *pjlink, long num)
+static jlif_result lnkCalc_integer(jlink *pjlink, long long num)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
- printf("lnkCalc_integer(calc@%p, %ld)\n", clink, num);
+ printf("lnkCalc_integer(calc@%p, %lld)\n", clink, num);
if (clink->pstate == ps_prec) {
clink->prec = num;
@@ -123,7 +123,7 @@ static jlif_result lnkCalc_integer(jlink *pjlink, long num)
if (clink->pstate != ps_args) {
return jlif_stop;
- errlogPrintf("lnkCalc: Unexpected integer %ld\n", num);
+ errlogPrintf("lnkCalc: Unexpected integer %lld\n", num);
}
if (clink->nArgs == CALCPERFORM_NARGS) {
diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c
index a647e6a60..db824abbc 100644
--- a/src/std/link/lnkConst.c
+++ b/src/std/link/lnkConst.c
@@ -90,13 +90,13 @@ static void lnkConst_free(jlink *pjlink)
free(clink);
}
-static jlif_result lnkConst_integer(jlink *pjlink, long num)
+static jlif_result lnkConst_integer(jlink *pjlink, long long num)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
int newElems = clink->nElems + 1;
IFDEBUG(10)
- printf("lnkConst_integer(const@%p, %ld)\n", pjlink, num);
+ printf("lnkConst_integer(const@%p, %lld)\n", pjlink, num);
switch (clink->type) {
void *buf;
From 8ae7930375a7afd203f837045682dc2e8711cf99 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver
Date: Thu, 4 May 2017 20:12:02 -0400
Subject: [PATCH 112/112] ioc/dbStatic: rename link debugging info tags
---
src/ioc/dbStatic/dbStaticLib.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index d54b37b87..a3058dfe1 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -2579,9 +2579,9 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
if(pdbentry->precnode && ellCount(&pdbentry->precnode->infoList)) {
dbCopyEntryContents(pdbentry, &infoentry);
- if(dbFindInfo(&infoentry, "lsetDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
+ if(dbFindInfo(&infoentry, "base:lsetDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
opts |= LINK_DEBUG_LSET;
- if(dbFindInfo(&infoentry, "jlinkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
+ if(dbFindInfo(&infoentry, "base:jlinkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0)
opts |= LINK_DEBUG_JPARSE;
dbFinishEntry(&infoentry);