Merge remote-tracking branch 'linksup/master'

* linksup/master: (112 commits)
  ioc/dbStatic: rename link debugging info tags
  jlif future proof for 64-bit json parser
  Demonstrate and use numeric literals in calc args
  separate jlink and lset debug flags
  std/link: runtime conditional debugging in calc/const
  std/rec/test: extend linkRetargetLink w/ jlink
  ioc/db: dbUnitTest add testdbPutArrFieldOk()
  ioc/db: cleanup dbEvent freeLists
  ioc/db: dbUnitTest testMonitor leaks dbChannel
  std/link: all calc example
  jlink conditional debug print
  ioc/as: dbCore needs ca
  Additional linkInitTest checks
  Minimize work done in readLocked routine
  Minimize work done in readLocked() routine
  Cosmetic changes to various soft device supports
  Enhancements to subArray record & soft device support
  Fix bug in eventRecord::init_record
  Updates to Release Notes and links.html
  Make dbLinkIs{Constant|Volatile}() return only true/false
  ...

Conflicts:
	documentation/RELEASE_NOTES.html
	src/ioc/db/dbAccess.c
This commit is contained in:
Michael Davidsaver
2017-05-04 20:14:30 -04:00
142 changed files with 5921 additions and 1622 deletions
+1
View File
@@ -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
+41 -24
View File
@@ -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,36 +53,52 @@ 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:
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);
if (prec->inp.type == CONSTANT) {
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;
}
static long readLocked(struct link *pinp, void *dummy)
{
aaiRecord *prec = (aaiRecord *) pinp->precord;
long nRequest = prec->nelm;
long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
if (!status && nRequest > 0) {
prec->nord = nRequest;
prec->udf = FALSE;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
}
return status;
}
static long read_aai(aaiRecord *prec)
{
long nRequest = prec->nelm;
struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp;
long status = dbLinkDoLocked(pinp, readLocked, NULL);
dbGetLink(prec->simm == menuYesNoYES ? &prec->siol : &prec->inp,
prec->ftvl, prec->bptr, 0, &nRequest);
if (nRequest > 0) {
prec->nord = nRequest;
prec->udf=FALSE;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
if (status == S_db_noLSET)
status = readLocked(pinp, NULL);
return 0;
return status;
}
+1 -12
View File
@@ -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 (dbLinkIsConstant(&prec->out)) {
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;
}
+34 -26
View File
@@ -50,47 +50,55 @@ 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 (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;
}
if (recGblInitConstantLink(&prec->inp, DBF_DOUBLE, &prec->val))
prec->udf = FALSE;
return 0;
}
struct aivt {
double val;
epicsTimeStamp *ptime;
};
static long readLocked(struct link *pinp, void *vvt)
{
struct aivt *pvt = (struct aivt *) vvt;
long status = dbGetLink(pinp, DBR_DOUBLE, &pvt->val, 0, 0);
if (!status && pvt->ptime)
dbGetTimeStamp(pinp, pvt->ptime);
return status;
}
static long read_ai(aiRecord *prec)
{
double val;
long status;
struct aivt vt;
if (prec->inp.type == CONSTANT)
if (dbLinkIsConstant(&prec->inp))
return 2;
if (!dbGetLink(&prec->inp, DBR_DOUBLE, &val, 0, 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, &vt);
if (!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);
prec->val = vt.val * (1.0 - prec->smoo) + (prec->val * prec->smoo);
else
prec->val = val;
prec->val = vt.val;
prec->udf = FALSE;
prec->dpvt = &devAiSoft; /* Any non-zero value */
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
} else {
prec->dpvt = NULL;
}
else
prec->dpvt = NULL;
return 2;
}
+21 -19
View File
@@ -49,29 +49,31 @@ 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:
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;
}
recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->rval);
return 0;
}
static long readLocked(struct link *pinp, void *dummy)
{
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(pinp, &prec->time);
return status;
}
static long read_ai(aiRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0) &&
prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
return 0;
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
return status;
}
+11 -13
View File
@@ -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;
}
-4
View File
@@ -66,10 +66,6 @@ static long read_bi(biRecord *prec)
prec->udf = FALSE;
}
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
return 2;
}
+23 -23
View File
@@ -47,32 +47,32 @@ 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 (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;
}
if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
prec->udf = FALSE;
return 0;
}
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);
return 2;
}
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->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
return 2;
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
return status;
}
+21 -19
View File
@@ -47,29 +47,31 @@ 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:
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;
}
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 (status) return status;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
return status;
}
static long read_bi(biRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_ULONG, &prec->rval, 0, 0) &&
prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
return 0;
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
return status;
}
+13 -16
View File
@@ -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;
}
+9 -11
View File
@@ -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;
}
+36 -26
View File
@@ -47,40 +47,50 @@ 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 (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;
}
if (recGblInitConstantLink(&prec->inp, DBF_STRING, prec->val))
prec->udf = FALSE;
return 0;
}
struct eventvt {
char newEvent[MAX_STRING_SIZE];
epicsTimeStamp *ptime;
};
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;
char newEvent[MAX_STRING_SIZE];
struct eventvt vt;
if (prec->inp.type != CONSTANT) {
status = dbGetLink(&prec->inp, DBR_STRING, newEvent, 0, 0);
if (status) return status;
if (strcmp(newEvent, prec->val) != 0) {
strcpy(prec->val, newEvent);
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, &vt);
if (!status) {
if (strcmp(vt.newEvent, prec->val) != 0) {
strcpy(prec->val, vt.newEvent);
prec->epvt = eventNameToHandle(prec->val);
}
prec->udf = FALSE;
}
prec->udf = FALSE;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
return 0;
return status;
}
+3 -15
View File
@@ -51,21 +51,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(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);
}
if (recGblInitConstantLink(&prec->svl,DBF_DOUBLE,&prec->sgnl))
prec->udf = FALSE;
return 0;
}
+21 -21
View File
@@ -47,32 +47,32 @@ 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 (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;
}
if (recGblInitConstantLink(&prec->inp, DBF_LONG, &prec->val))
prec->udf = FALSE;
return 0;
}
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) return status;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
return status;
}
static long read_longin(longinRecord *prec)
{
long status;
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
status = dbGetLink(&prec->inp, DBR_LONG, &prec->val, 0, 0);
if (!status &&
prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
return status;
}
+14 -16
View File
@@ -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;
}
+17 -5
View File
@@ -24,14 +24,26 @@ static long init_record(lsiRecord *prec)
return 0;
}
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) return status;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
return status;
}
static long read_string(lsiRecord *prec)
{
long status = dbGetLinkLS(&prec->inp, prec->val, prec->sizv, &prec->len);
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
if (!status &&
prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
return status;
}
+7 -11
View File
@@ -30,21 +30,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);
+24 -23
View File
@@ -47,32 +47,33 @@ 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 (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;
}
if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
prec->udf = FALSE;
return 0;
}
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);
return 2;
}
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->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
return 2;
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
return status;
}
+7 -17
View File
@@ -47,22 +47,12 @@ 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:
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;
recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
/* Preserve old functionality */
if (prec->nobt == 0)
prec->mask = 0xffffffff;
prec->mask <<= prec->shft;
return 0;
}
@@ -71,7 +61,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);
}
+24 -23
View File
@@ -47,32 +47,33 @@ 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 (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;
}
if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
prec->udf = FALSE;
return 0;
}
static long readLocked(struct link *pinp, void *dummy)
{
mbbiRecord *prec = (mbbiRecord *) 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);
return 2;
}
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->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
return 2;
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
return status;
}
+28 -22
View File
@@ -47,33 +47,39 @@ 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:
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;
recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->rval);
/* Preserve old functionality*/
if (prec->nobt == 0)
prec->mask = 0xffffffff;
prec->mask <<= prec->shft;
return 0;
}
static long readLocked(struct link *pinp, void *dummy)
{
mbbiRecord *prec = (mbbiRecord *) pinp->precord;
long status = dbGetLink(pinp, DBR_LONG, &prec->rval, 0, 0);
if (status) return status;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
return status;
}
static long read_mbbi(mbbiRecord *prec)
{
if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0)) {
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
if (!status)
prec->rval &= prec->mask;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
return 0;
return status;
}
+5 -12
View File
@@ -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 */
+14 -16
View File
@@ -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;
}
+6 -11
View File
@@ -30,18 +30,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 = {
+67 -36
View File
@@ -45,55 +45,86 @@ struct {
};
epicsExportAddress(dset, devSASoft);
static long init_record(subArrayRecord *prec)
static void subset(subArrayRecord *prec, long nRequest)
{
/* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/
switch (prec->inp.type) {
case 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;
}
long ecount = nRequest - prec->indx;
static long read_sa(subArrayRecord *prec)
{
long nRequest = prec->indx + prec->nelm;
long ecount;
if (nRequest > prec->malm)
nRequest = prec->malm;
if (prec->inp.type == CONSTANT)
nRequest = prec->nord;
else
dbGetLink(&prec->inp, 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 &&
prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &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;
struct sart rt;
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;
}
+24 -24
View File
@@ -49,35 +49,35 @@ 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 (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;
}
if (recGblInitConstantLink(&prec->inp, DBF_STRING, prec->val))
prec->udf = FALSE;
return 0;
}
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) return status;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(pinp, &prec->time);
return status;
}
static long read_stringin(stringinRecord *prec)
{
long status;
long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
if (status == S_db_noLSET)
status = readLocked(&prec->inp, NULL);
if (!status && !dbLinkIsConstant(&prec->inp))
prec->udf = FALSE;
status = dbGetLink(&prec->inp, DBR_STRING, prec->val, 0, 0);
if (!status) {
if (prec->inp.type != CONSTANT)
prec->udf = FALSE;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
}
return status;
}
+12 -16
View File
@@ -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.
\*************************************************************************/
/*
* Author: Marty Kraimer
* Date: 04NOV2003
@@ -49,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;
}
+41 -22
View File
@@ -48,33 +48,52 @@ 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:
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);
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;
}
struct wfrt {
long nRequest;
epicsTimeStamp *ptime;
};
static long readLocked(struct link *pinp, void *vrt)
{
waveformRecord *prec = (waveformRecord *) pinp->precord;
struct wfrt *prt = (struct wfrt *) 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_wf(waveformRecord *prec)
{
long nRequest = prec->nelm;
long status;
struct wfrt rt;
dbGetLink(&prec->inp, prec->ftvl, prec->bptr, 0, &nRequest);
if (nRequest > 0) {
prec->nord = nRequest;
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
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, &rt);
if (!status && rt.nRequest > 0) {
prec->nord = rt.nRequest;
prec->udf = FALSE;
}
return 0;
return status;
}
+18
View File
@@ -0,0 +1,18 @@
#*************************************************************************
# 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 += lnkConst.c
dbRecStd_SRCS += lnkCalc.c
HTMLS += links.html
+123
View File
@@ -0,0 +1,123 @@
=head1 Extensible Links
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
=item * L<Constant|/"Constant Link const">
=item * L<Calc|/"Calculation Link calc">
=back
=head2 Using JSON Links
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<JavaScript
Object Notation|http://www.json.org/>) 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
=cut
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<getValue()> routine is called. Most record types
support the use of constant links by calling C<recGblInitConstantLink()> 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<printf> and C<calcout> 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
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
{const: 3.14159265358979}
{const: "Pi"}
{const: [1, 2.718281828459, 3.14159265358979]}
{const: ["One", "e", "Pi"]}
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:
field(INP, {const:"Inf"})
=cut
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 inputs can be provided.
=head4 Parameters
The link address is a JSON map with the following keys:
=over
=item expr
The primary expression to be evaluated, given 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<A>, C<B>, C<C>, ... C<L>. Each input argument may be either a
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
An optional string specifying the engineering units for the result of the
expression. Equivalent to the C<EGU> field of a record.
=item prec
An optional integer specifying the numeric precision with which the calculation
result should be displayed. Equivalent to the C<PREC> field of a record.
=back
=head4 Example
{calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5], prec:3}}
=cut
+642
View File
@@ -0,0 +1,642 @@
/*************************************************************************\
* 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 */
/* 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:{...}}}
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "alarm.h"
#include "dbDefs.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)();
#define IFDEBUG(n) if(clink->jlink.debug)
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 *expr;
char *major;
char *minor;
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", clink);
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);
free(clink->units);
free(clink);
}
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, %lld)\n", clink, num);
if (clink->pstate == ps_prec) {
clink->prec = num;
return jlif_continue;
}
if (clink->pstate != ps_args) {
return jlif_stop;
errlogPrintf("lnkCalc: Unexpected integer %lld\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", clink, 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+1));
if (!postbuf) {
errlogPrintf("lnkCalc: Out of memory\n");
return jlif_stop;
}
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;
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));
return jlif_stop;
}
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_map(calc@%p)\n", clink);
if (clink->pstate == ps_args)
return jlif_key_child_link;
if (clink->pstate != ps_init) {
errlogPrintf("lnkCalc: Unexpected map\n");
return jlif_key_stop;
}
return jlif_key_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_map(calc@%p)\n", clink);
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;
}
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", clink);
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", clink);
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)
{
calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink);
IFDEBUG(10)
printf("lnkCalc_get_lset(calc@%p)\n", pjlink);
return &lnkCalc_lset;
}
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);
printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "",
clink->expr, clink->prec, clink->val,
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 expression: \"%s\"\n", indent, "",
clink->major);
if (clink->post_minor)
printf("%*s Minor expression: \"%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 **************************/
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);
dbLoadLink(child, DBR_DOUBLE, &clink->arg[i]);
}
}
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->expr);
free(clink->major);
free(clink->minor);
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) &&
!dbIsLinkConnected(child))
connected = 0;
}
return connected;
}
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);
printf("lnkCalc_getDBFtype(calc@%p)\n", clink);
}
return DBF_DOUBLE;
}
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);
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);
/* Any errors have already triggered a LINK/INVALID alarm */
}
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;
}
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
{
return rtn(plink, priv);
}
/************************* 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, doLocked
};
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, lnkCalc_map_children
};
epicsExportAddress(jlif, lnkCalcIf);
+585
View File
@@ -0,0 +1,585 @@
/*************************************************************************\
* 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 <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "dbDefs.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 "epicsExport.h"
#define IFDEBUG(n) if(clink->jlink.debug)
typedef long (*FASTCONVERT)();
typedef struct const_link {
jlink jlink; /* embedded object */
int nElems;
enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type;
union {
epicsInt32 scalar_integer; /* si32 */
epicsFloat64 scalar_double; /* sf64 */
char *scalar_string; /* sc40 */
void *pmem;
epicsInt32 *pintegers; /* ai32 */
epicsFloat64 *pdoubles; /* af64 */
char **pstrings; /* ac40 */
} value;
} const_link;
static lset lnkConst_lset;
/*************************** jlif Routines **************************/
static jlink* lnkConst_alloc(short dbfType)
{
const_link *clink = calloc(1, sizeof(*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)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_free(const@%p) type=%d\n", pjlink, clink->type);
switch (clink->type) {
int i;
case ac40:
for (i=0; i<clink->nElems; i++)
free(clink->value.pstrings[i]);
/* fall through */
case sc40:
case ai32:
case af64:
free(clink->value.pmem);
break;
case s0:
case a0:
case si32:
case sf64:
break;
}
free(clink);
}
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, %lld)\n", pjlink, num);
switch (clink->type) {
void *buf;
case s0:
clink->type = si32;
clink->value.scalar_integer = num;
break;
case a0:
clink->type = ai32;
/* fall through */
case ai32:
buf = realloc(clink->value.pmem, newElems * sizeof(epicsInt32));
if (!buf)
return jlif_stop;
clink->value.pmem = buf;
clink->value.pintegers[clink->nElems] = num;
break;
case af64:
buf = realloc(clink->value.pmem, newElems * sizeof(epicsFloat64));
if (!buf)
return jlif_stop;
clink->value.pmem = buf;
clink->value.pdoubles[clink->nElems] = num;
break;
case ac40:
errlogPrintf("lnkConst: Mixed data types in array\n");
/* fall through */
default:
return jlif_stop;
}
clink->nElems = newElems;
return jlif_continue;
}
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);
return lnkConst_integer(pjlink, 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 i;
case s0:
clink->type = sf64;
clink->value.scalar_double = num;
break;
case a0:
clink->type = af64;
/* fall through */
case af64:
f64buf = realloc(clink->value.pmem, newElems * sizeof(epicsFloat64));
if (!f64buf)
return jlif_stop;
f64buf[clink->nElems] = num;
clink->value.pdoubles = f64buf;
break;
case ai32: /* promote earlier ai32 values to af64 */
f64buf = calloc(newElems, sizeof(epicsFloat64));
if (!f64buf)
return jlif_stop;
for (i = 0; i < clink->nElems; i++) {
f64buf[i] = clink->value.pintegers[i];
}
free(clink->value.pmem);
f64buf[clink->nElems] = num;
clink->type = af64;
clink->value.pdoubles = f64buf;
break;
case ac40:
errlogPrintf("lnkConst: Mixed data types in array\n");
/* fall through */
default:
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, *str;
case s0:
str = malloc(len+1);
if (!str)
return jlif_stop;
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:
vec = realloc(clink->value.pmem, newElems * sizeof(char *));
if (!vec)
return jlif_stop;
str = malloc(len+1);
if (!str)
return jlif_stop;
strncpy(str, val, len);
str[len] = '\0';
vec[clink->nElems] = str;
clink->value.pstrings = vec;
break;
case af64:
case ai32:
errlogPrintf("lnkConst: Mixed data types in array\n");
/* fall thorough */
default:
return jlif_stop;
}
clink->nElems = newElems;
return jlif_continue;
}
static jlif_result lnkConst_start_array(jlink *pjlink)
{
const_link *clink = CONTAINER(pjlink, const_link, 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)
{
const_link *clink = CONTAINER(pjlink, const_link, jlink);
IFDEBUG(10)
printf("lnkConst_end_array(const@%p)\n", pjlink);
return jlif_continue;
}
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);
return &lnkConst_lset;
}
/* 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)
{
const_link *clink = CONTAINER(pjlink, const_link, 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);
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 **************************/
static void lnkConst_remove(struct dbLocker *locker, struct link *plink)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, 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)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, 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;
case ac40:
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.pstrings[0], pbuffer, NULL);
break;
default:
status = S_db_badField;
break;
}
return status;
}
static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink);
const char *pstr;
IFDEBUG(10)
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;
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)
{
const_link *clink = CONTAINER(plink->value.json.jlink, const_link, 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;
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;
}
*pnReq = nElems;
return status;
}
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);
*nelements = 0;
return 0;
}
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);
if (pnRequest)
*pnRequest = 0;
return 0;
}
/************************* Interface Tables *************************/
static lset lnkConst_lset = {
1, 0, /* Constant, not Volatile */
NULL, lnkConst_remove,
lnkConst_loadScalar, lnkConst_loadLS, lnkConst_loadArray, NULL,
NULL, lnkConst_getNelements, lnkConst_getValue,
NULL, NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL
};
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
};
epicsExportAddress(jlif, lnkConstIf);
+6 -54
View File
@@ -109,10 +109,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
struct aSubRecord *prec = (struct aSubRecord *)pcommon;
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,19 @@ static long init_record(struct dbCommon *pcommon, int pass)
}
/* Initialize the Subroutine Name Link */
switch (prec->subl.type) {
case 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;
}
recGblInitConstantLink(&prec->subl, DBF_STRING, prec->snam);
/* Initialize Input Links */
for (i = 0; i < NUM_ARGS; i++) {
struct link *plink = &(&prec->inpa)[i];
switch (plink->type) {
case CONSTANT:
if ((&prec->noa)[i] < 2)
recGblInitConstantLink(plink, (&prec->fta)[i], (&prec->a)[i]);
break;
short dbr = (&prec->fta)[i];
long n = (&prec->noa)[i];
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;
}
dbLoadLinkArray(plink, dbr, (&prec->a)[i], &n);
if (n > 0)
(&prec->nea)[i] = n;
}
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);
+1 -4
View File
@@ -141,10 +141,7 @@ static long init_record(struct dbCommon *pcommon, 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);
}
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
/* must have read_aai function defined */
if (pdset->number < 5 || pdset->read_aai == NULL) {
+1 -4
View File
@@ -141,10 +141,7 @@ static long init_record(struct dbCommon *pcommon, 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);
}
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
/* must have write_aao function defined */
if (pdset->number < 5 || pdset->write_aao == NULL) {
+2 -9
View File
@@ -110,15 +110,8 @@ static long init_record(struct dbCommon *pcommon, 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);
}
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");
+5 -10
View File
@@ -110,20 +110,15 @@ static long init_record(struct dbCommon *pcommon, 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);
}
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)) {
@@ -191,8 +186,8 @@ static long process(struct dbCommon *pcommon)
/* 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 {
+25 -28
View File
@@ -131,44 +131,40 @@ static void myCallbackFunc(CALLBACK *arg)
static long init_record(struct dbCommon *pcommon,int pass)
{
struct boRecord *prec = (struct boRecord *)pcommon;
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;
/* 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);
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;
@@ -203,7 +199,8 @@ static long process(struct dbCommon *pcommon)
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;
+1 -3
View File
@@ -99,9 +99,7 @@ static long init_record(struct dbCommon *pcommon, 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,
+66 -39
View File
@@ -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"
@@ -99,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.
*
*/
@@ -142,42 +143,57 @@ static long init_record(struct dbCommon *pcommon, 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');
}
}
}
@@ -300,8 +316,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;
@@ -349,23 +363,36 @@ 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);
@@ -708,9 +735,9 @@ static void checkLinks(calcoutRecord *prec)
plinkValid = &prec->inav;
for (i = 0; i<CALCPERFORM_NARGS+1; i++, plink++, plinkValid++) {
if (plink->type == CA_LINK) {
if (dbLinkIsVolatile(plink)) {
caLink = 1;
stat = dbCaIsLinkConnected(plink);
stat = dbIsLinkConnected(plink);
if (!stat && (*plinkValid == calcoutINAV_EXT_NC)) {
caLinkNc = 1;
}
+13 -10
View File
@@ -94,13 +94,16 @@ static void push_values(dfanoutRecord *);
static long init_record(struct dbCommon *pcommon, int pass)
{
struct dfanoutRecord *prec = (struct dfanoutRecord *)pcommon;
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(struct dbCommon *pcommon)
@@ -108,11 +111,11 @@ static long process(struct dbCommon *pcommon)
struct dfanoutRecord *prec = (struct dfanoutRecord *)pcommon;
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;
+5 -9
View File
@@ -99,18 +99,14 @@ static long init_record(struct dbCommon *pcommon, 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);
}
prec->epvt = eventNameToHandle(prec->val);
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
recGblInitConstantLink(&prec->siol, DBF_STRING, &prec->sval);
if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) )
status=(*pdset->init_record)(prec);
prec->epvt = eventNameToHandle(prec->val);
return(status);
}
+2 -3
View File
@@ -106,8 +106,7 @@ static long process(struct dbCommon *pcommon)
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(struct dbCommon *pcommon)
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;
+2 -7
View File
@@ -182,13 +182,8 @@ static long init_record(struct dbCommon *pcommon, 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;
+20 -21
View File
@@ -97,37 +97,36 @@ static long readValue(longinRecord *prec);
static long init_record(struct dbCommon *pcommon, int pass)
{
struct longinRecord *prec = (struct longinRecord *)pcommon;
struct longindset *pdset;
long status;
struct longindset *pdset = (struct longindset *) prec->dset;
if (pass==0) return(0);
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);
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;
}
/* 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);
}
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(struct dbCommon *pcommon)
+28 -24
View File
@@ -94,33 +94,38 @@ static void convert(longoutRecord *prec, epicsInt32 value);
static long init_record(struct dbCommon *pcommon, int pass)
{
struct longoutRecord *prec = (struct longoutRecord *)pcommon;
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(struct dbCommon *pcommon)
@@ -137,11 +142,10 @@ static long process(struct dbCommon *pcommon)
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 {
+2 -5
View File
@@ -113,11 +113,8 @@ static long init_record(struct dbCommon *pcommon, 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)
+2 -5
View File
@@ -131,11 +131,8 @@ static long init_record(struct dbCommon *pcommon, 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)
+4 -7
View File
@@ -115,12 +115,9 @@ static long init_record(struct dbCommon *pcommon, 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(struct dbCommon *pcommon)
}
if (!pact) {
if (prec->dol.type != CONSTANT &&
if (!dbLinkIsConstant(&prec->dol) &&
prec->omsl == menuOmslclosed_loop) {
epicsUInt16 val;
+4 -7
View File
@@ -135,12 +135,9 @@ static long init_record(struct dbCommon *pcommon, 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(struct dbCommon *pcommon)
}
if (!pact) {
if (prec->dol.type != CONSTANT &&
if (!dbLinkIsConstant(&prec->dol) &&
prec->omsl == menuOmslclosed_loop) {
epicsUInt16 val;
+13 -5
View File
@@ -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);
@@ -204,8 +204,9 @@ static void doPrintf(printfRecord *prec)
break;
case 's':
if (flags & F_LONG && plink->type != CONSTANT) {
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;
@@ -252,7 +260,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);
+7 -10
View File
@@ -91,22 +91,19 @@ static long init_record(struct dbCommon *pcommon, 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; i<SEL_MAX; i++, plink++, pvalue++) {
*pvalue = epicsNAN;
if (plink->type==CONSTANT) {
recGblInitConstantLink(plink,DBF_DOUBLE,pvalue);
}
for (i=0; i<SEL_MAX; i++, plink++, pvalue++) {
*pvalue = epicsNAN;
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
return(0);
return 0;
}
static long process(struct dbCommon *pcommon)
+5 -7
View File
@@ -117,13 +117,11 @@ static long init_record(struct dbCommon *pcommon, int pass)
callbackSetUser(pseqRecPvt, &pseqRecPvt->callback);
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(struct dbCommon *pcommon)
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(struct dbCommon *pcommon)
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++;
+20 -21
View File
@@ -94,34 +94,33 @@ static long init_record(struct dbCommon *pcommon, int pass)
{
struct stringinRecord *prec = (struct stringinRecord *)pcommon;
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;
}
/* 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);
}
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;
}
/*
+30 -27
View File
@@ -96,34 +96,37 @@ static long init_record(struct dbCommon *pcommon, int pass)
{
struct stringoutRecord *prec = (struct stringoutRecord *)pcommon;
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(struct dbCommon *pcommon)
@@ -138,13 +141,13 @@ static long process(struct dbCommon *pcommon)
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);
+2
View File
@@ -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;
}
+1 -3
View File
@@ -100,9 +100,7 @@ static long init_record(struct dbCommon *pcommon, 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]) {
+7
View File
@@ -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
+12 -9
View File
@@ -8,6 +8,7 @@
#include <string.h>
#include "dbAccess.h"
#include "dbTest.h"
#include "dbUnitTest.h"
#include "errlog.h"
@@ -20,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;
@@ -45,16 +46,18 @@ 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))
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL)) {
testFail("dbGet fails");
else {
testOk(nreq==0, "nreq==0 (got %ld)", nreq);
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);
@@ -101,10 +104,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))
@@ -157,7 +160,7 @@ static void testGetPutArray(void)
MAIN(arrayOpTest)
{
testPlan(20);
testPlan(21);
testGetPutArray();
return testDone();
}
+1
View File
@@ -1,6 +1,7 @@
record(waveform, "wfrec") {
field(NELM, "10")
field(FTVL, "LONG")
field(INP, [1, 2, 3])
}
record(waveform, "wfrec1") {
field(NELM, "1")
+3
View File
@@ -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 */
}
+212
View File
@@ -0,0 +1,212 @@
/*************************************************************************\
* 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.
\*************************************************************************/
#include <string.h>
#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 startTestIoc(const char *dbfile)
{
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase(dbfile, NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
}
static void testLongStringInit()
{
testDiag("testLongStringInit");
startTestIoc("linkInitTest.db");
{
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, "!--------------------------------------");
}
testdbGetFieldEqual("longstr4.VAL", DBR_STRING, "One");
testIocShutdownOk();
testdbCleanup();
}
static void testCalcInit()
{
testDiag("testCalcInit");
startTestIoc("linkInitTest.db");
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();
}
static void testPrintfStrings()
{
testDiag("testPrintfStrings");
startTestIoc("linkInitTest.db");
{
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();
}
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(62);
testLongStringInit();
testCalcInit();
testPrintfStrings();
testArrayInputs();
testEventRecord();
return testDone();
}
+67
View File
@@ -0,0 +1,67 @@
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(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"}})
}
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"])
}
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")
}
+8
View File
@@ -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:5
}})
field(PINI, "YES")
}
+49 -21
View File
@@ -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,60 @@ 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);
/* 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);
testdbGetFieldEqual("rec:j1", DBF_DOUBLE, 12.0);
testLongStrEq("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[{\"const\":7}]}}");
}
MAIN(linkRetargetLinkTest)
{
testPlan(10);
testPlan(18);
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();
}
+4 -7
View File
@@ -110,10 +110,7 @@ static long init_record(struct dbCommon *pcommon, 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);
}
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
/* must have dset defined */
if (!(pdset = (struct wfdset *)(prec->dset))) {
@@ -314,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;
@@ -330,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)
+2
View File
@@ -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
+3
View File
@@ -14,6 +14,9 @@ include "stdRecords.dbd"
# Channel filters & plugins
include "filters.dbd"
# Link types
include "links.dbd"
# Standard device support
include "devSoft.dbd"