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:
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,6 +1,7 @@
|
||||
record(waveform, "wfrec") {
|
||||
field(NELM, "10")
|
||||
field(FTVL, "LONG")
|
||||
field(INP, [1, 2, 3])
|
||||
}
|
||||
record(waveform, "wfrec1") {
|
||||
field(NELM, "1")
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,6 +14,9 @@ include "stdRecords.dbd"
|
||||
# Channel filters & plugins
|
||||
include "filters.dbd"
|
||||
|
||||
# Link types
|
||||
include "links.dbd"
|
||||
|
||||
# Standard device support
|
||||
include "devSoft.dbd"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user