Experimental Physics and Industrial Control System
Ben Franksen has proposed merging ~bfrk/epics-base:write-filters into epics-base:7.0.
Requested reviews:
EPICS Core Developers (epics-core)
For more details, see:
https://code.launchpad.net/~bfrk/epics-base/+git/epics-base/+merge/381125
This is just the initial refactor, no new features yet.
--
Your team EPICS Core Developers is requested to review the proposed merge of ~bfrk/epics-base:write-filters into epics-base:7.0.
diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md
index bdd2468..681495e 100644
--- a/documentation/RELEASE_NOTES.md
+++ b/documentation/RELEASE_NOTES.md
@@ -36,6 +36,15 @@ As long as all support modules and IOCs are rebuilt from source after updating
them to use this release of EPICS Base, these changes should not have any
affect.
+### Filters in database links
+
+Input links can now use filters, most importantly array element and sub array
+access, even if they are not channel access links.
+
+### ai Soft Channel support
+
+The Soft Channel device support for ai records now returns failure when
+fetching the INP link fails.
### logClient reliability
diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c
index 19f6038..a6c31f2 100644
--- a/modules/database/src/ioc/db/dbAccess.c
+++ b/modules/database/src/ioc/db/dbAccess.c
@@ -34,7 +34,7 @@
#include "errlog.h"
#include "errMdef.h"
-#include "epicsExport.h" /* #define epicsExportSharedSymbols */
+#include "epicsExport.h" /* #define epicsExportSharedSymbols */
#include "caeventmask.h"
#include "callback.h"
#include "dbAccessDefs.h"
@@ -63,7 +63,7 @@
#include "special.h"
epicsShareDef struct dbBase *pdbbase = 0;
-epicsShareDef volatile int interruptAccept=FALSE;
+epicsShareDef volatile int interruptAccept = FALSE;
epicsShareDef int dbAccessDebugPUTF = 0;
epicsExportAddress(int, dbAccessDebugPUTF);
@@ -73,24 +73,24 @@ epicsExportAddress(int, dbAccessDebugPUTF);
epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
static short mapDBFToDBR[DBF_NTYPES] = {
- /* DBF_STRING => */ DBR_STRING,
- /* DBF_CHAR => */ DBR_CHAR,
- /* DBF_UCHAR => */ DBR_UCHAR,
- /* DBF_SHORT => */ DBR_SHORT,
- /* DBF_USHORT => */ DBR_USHORT,
- /* DBF_LONG => */ DBR_LONG,
- /* DBF_ULONG => */ DBR_ULONG,
- /* DBF_INT64 => */ DBR_INT64,
- /* DBF_UINT64 => */ DBR_UINT64,
- /* DBF_FLOAT => */ DBR_FLOAT,
- /* DBF_DOUBLE => */ DBR_DOUBLE,
- /* DBF_ENUM, => */ DBR_ENUM,
- /* DBF_MENU, => */ DBR_ENUM,
- /* DBF_DEVICE => */ DBR_ENUM,
- /* DBF_INLINK => */ DBR_STRING,
- /* DBF_OUTLINK => */ DBR_STRING,
- /* DBF_FWDLINK => */ DBR_STRING,
- /* DBF_NOACCESS => */ DBR_NOACCESS
+ /* DBF_STRING => */ DBR_STRING,
+ /* DBF_CHAR => */ DBR_CHAR,
+ /* DBF_UCHAR => */ DBR_UCHAR,
+ /* DBF_SHORT => */ DBR_SHORT,
+ /* DBF_USHORT => */ DBR_USHORT,
+ /* DBF_LONG => */ DBR_LONG,
+ /* DBF_ULONG => */ DBR_ULONG,
+ /* DBF_INT64 => */ DBR_INT64,
+ /* DBF_UINT64 => */ DBR_UINT64,
+ /* DBF_FLOAT => */ DBR_FLOAT,
+ /* DBF_DOUBLE => */ DBR_DOUBLE,
+ /* DBF_ENUM, => */ DBR_ENUM,
+ /* DBF_MENU, => */ DBR_ENUM,
+ /* DBF_DEVICE => */ DBR_ENUM,
+ /* DBF_INLINK => */ DBR_STRING,
+ /* DBF_OUTLINK => */ DBR_STRING,
+ /* DBF_FWDLINK => */ DBR_STRING,
+ /* DBF_NOACCESS => */ DBR_NOACCESS
};
/*
@@ -109,217 +109,219 @@ void dbSpcAsRegisterCallback(SPC_ASCALLBACK func)
spcAsCallback = func;
}
-long dbPutSpecial(DBADDR *paddr,int pass)
+long dbPutSpecial(DBADDR *paddr, int pass)
{
- long int (*pspecial)()=NULL;
- rset *prset;
- dbCommon *precord = paddr->precord;
- long status=0;
- long special=paddr->special;
+ long int (*pspecial) () = NULL;
+ rset *prset;
+ dbCommon *precord = paddr->precord;
+ long status = 0;
+ long special = paddr->special;
prset = dbGetRset(paddr);
- if(special<100) { /*global processing*/
- if((special==SPC_NOMOD) && (pass==0)) {
- status = S_db_noMod;
- recGblDbaddrError(status,paddr,"dbPut");
- return(status);
- }else if(special==SPC_SCAN){
- if(pass==0)
- scanDelete(precord);
- else
- scanAdd(precord);
- }else if((special==SPC_AS) && (pass==1)) {
- if(spcAsCallback) (*spcAsCallback)(precord);
- }
- }else {
- if( prset && (pspecial = (prset->special))) {
- status=(*pspecial)(paddr,pass);
- if(status) return(status);
- } else if(pass==0){
- recGblRecSupError(S_db_noSupport,paddr,"dbPut", "special");
- return(S_db_noSupport);
- }
+ if (special < 100) { /*global processing */
+ if ((special == SPC_NOMOD) && (pass == 0)) {
+ status = S_db_noMod;
+ recGblDbaddrError(status, paddr, "dbPut");
+ return (status);
+ } else if (special == SPC_SCAN) {
+ if (pass == 0)
+ scanDelete(precord);
+ else
+ scanAdd(precord);
+ } else if ((special == SPC_AS) && (pass == 1)) {
+ if (spcAsCallback)
+ (*spcAsCallback) (precord);
+ }
+ } else {
+ if (prset && (pspecial = (prset->special))) {
+ status = (*pspecial) (paddr, pass);
+ if (status)
+ return (status);
+ } else if (pass == 0) {
+ recGblRecSupError(S_db_noSupport, paddr, "dbPut", "special");
+ return (S_db_noSupport);
+ }
}
- return(0);
+ return (0);
}
static void get_enum_strs(DBADDR *paddr, char **ppbuffer,
- rset *prset,long *options)
+ rset * prset, long *options)
{
- short field_type=paddr->field_type;
- dbFldDes *pdbFldDes = paddr->pfldDes;
- dbMenu *pdbMenu;
- dbDeviceMenu *pdbDeviceMenu;
- char **papChoice;
- unsigned long no_str;
- char *ptemp;
- struct dbr_enumStrs *pdbr_enumStrs=(struct dbr_enumStrs*)(*ppbuffer);
+ short field_type = paddr->field_type;
+ dbFldDes *pdbFldDes = paddr->pfldDes;
+ dbMenu *pdbMenu;
+ dbDeviceMenu *pdbDeviceMenu;
+ char **papChoice;
+ unsigned long no_str;
+ char *ptemp;
+ struct dbr_enumStrs *pdbr_enumStrs = (struct dbr_enumStrs *)(*ppbuffer);
unsigned int i;
- memset(pdbr_enumStrs,'\0',dbr_enumStrs_size);
- switch(field_type) {
- case DBF_ENUM:
- if( prset && prset->get_enum_strs ) {
- (*prset->get_enum_strs)(paddr,pdbr_enumStrs);
- } else {
- *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/
- }
- break;
- case DBF_MENU:
- pdbMenu = (dbMenu *)pdbFldDes->ftPvt;
- no_str = pdbMenu->nChoice;
- papChoice= pdbMenu->papChoiceValue;
- goto choice_common;
- case DBF_DEVICE:
- pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt;
- if(!pdbDeviceMenu) {
- *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/
- break;
- }
- no_str = pdbDeviceMenu->nChoice;
- papChoice = pdbDeviceMenu->papChoice;
- goto choice_common;
-choice_common:
- i = sizeof(pdbr_enumStrs->strs)/
- sizeof(pdbr_enumStrs->strs[0]);
- if(i<no_str) no_str = i;
- pdbr_enumStrs->no_str = no_str;
- ptemp = &(pdbr_enumStrs->strs[0][0]);
- for (i=0; i<no_str; i++) {
- if(papChoice[i]==NULL) *ptemp=0;
- else {
- strncpy(ptemp,papChoice[i],
- sizeof(pdbr_enumStrs->strs[0]));
- *(ptemp+sizeof(pdbr_enumStrs->strs[0])-1) = 0;
- }
- ptemp += sizeof(pdbr_enumStrs->strs[0]);
- }
- break;
- default:
- *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/
- break;
- }
- *ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size;
- return;
+ memset(pdbr_enumStrs, '\0', dbr_enumStrs_size);
+ switch (field_type) {
+ case DBF_ENUM:
+ if (prset && prset->get_enum_strs) {
+ (*prset->get_enum_strs) (paddr, pdbr_enumStrs);
+ } else {
+ *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */
+ }
+ break;
+ case DBF_MENU:
+ pdbMenu = (dbMenu *) pdbFldDes->ftPvt;
+ no_str = pdbMenu->nChoice;
+ papChoice = pdbMenu->papChoiceValue;
+ goto choice_common;
+ case DBF_DEVICE:
+ pdbDeviceMenu = (dbDeviceMenu *) pdbFldDes->ftPvt;
+ if (!pdbDeviceMenu) {
+ *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */
+ break;
+ }
+ no_str = pdbDeviceMenu->nChoice;
+ papChoice = pdbDeviceMenu->papChoice;
+ goto choice_common;
+ choice_common:
+ i = sizeof(pdbr_enumStrs->strs) / sizeof(pdbr_enumStrs->strs[0]);
+ if (i < no_str)
+ no_str = i;
+ pdbr_enumStrs->no_str = no_str;
+ ptemp = &(pdbr_enumStrs->strs[0][0]);
+ for (i = 0; i < no_str; i++) {
+ if (papChoice[i] == NULL)
+ *ptemp = 0;
+ else {
+ strncpy(ptemp, papChoice[i], sizeof(pdbr_enumStrs->strs[0]));
+ *(ptemp + sizeof(pdbr_enumStrs->strs[0]) - 1) = 0;
+ }
+ ptemp += sizeof(pdbr_enumStrs->strs[0]);
+ }
+ break;
+ default:
+ *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */
+ break;
+ }
+ *ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size;
+ return;
}
static void get_graphics(DBADDR *paddr, char **ppbuffer,
- rset *prset,long *options)
+ rset * prset, long *options)
{
- struct dbr_grDouble grd;
- int got_data=FALSE;
-
- grd.upper_disp_limit = grd.lower_disp_limit = 0.0;
- if( prset && prset->get_graphic_double ) {
- (*prset->get_graphic_double)(paddr,&grd);
- got_data=TRUE;
- }
- if( (*options) & (DBR_GR_LONG) ) {
- char *pbuffer=*ppbuffer;
-
- if(got_data) {
- struct dbr_grLong *pgr=(struct dbr_grLong*)pbuffer;
- pgr->upper_disp_limit = (epicsInt32)grd.upper_disp_limit;
- pgr->lower_disp_limit = (epicsInt32)grd.lower_disp_limit;
- } else {
- memset(pbuffer,'\0',dbr_grLong_size);
- *options = (*options) ^ DBR_GR_LONG; /*Turn off option*/
- }
- *ppbuffer = ((char *)*ppbuffer) + dbr_grLong_size;
- }
- if( (*options) & (DBR_GR_DOUBLE) ) {
- char *pbuffer=*ppbuffer;
-
- if(got_data) {
- struct dbr_grDouble *pgr=(struct dbr_grDouble*)pbuffer;
- pgr->upper_disp_limit = grd.upper_disp_limit;
- pgr->lower_disp_limit = grd.lower_disp_limit;
- } else {
- memset(pbuffer,'\0',dbr_grDouble_size);
- *options = (*options) ^ DBR_GR_DOUBLE; /*Turn off option*/
- }
- *ppbuffer = ((char *)*ppbuffer) + dbr_grDouble_size;
- }
- return;
+ struct dbr_grDouble grd;
+ int got_data = FALSE;
+
+ grd.upper_disp_limit = grd.lower_disp_limit = 0.0;
+ if (prset && prset->get_graphic_double) {
+ (*prset->get_graphic_double) (paddr, &grd);
+ got_data = TRUE;
+ }
+ if ((*options) & (DBR_GR_LONG)) {
+ char *pbuffer = *ppbuffer;
+
+ if (got_data) {
+ struct dbr_grLong *pgr = (struct dbr_grLong *)pbuffer;
+ pgr->upper_disp_limit = (epicsInt32) grd.upper_disp_limit;
+ pgr->lower_disp_limit = (epicsInt32) grd.lower_disp_limit;
+ } else {
+ memset(pbuffer, '\0', dbr_grLong_size);
+ *options = (*options) ^ DBR_GR_LONG; /*Turn off option */
+ }
+ *ppbuffer = ((char *)*ppbuffer) + dbr_grLong_size;
+ }
+ if ((*options) & (DBR_GR_DOUBLE)) {
+ char *pbuffer = *ppbuffer;
+
+ if (got_data) {
+ struct dbr_grDouble *pgr = (struct dbr_grDouble *)pbuffer;
+ pgr->upper_disp_limit = grd.upper_disp_limit;
+ pgr->lower_disp_limit = grd.lower_disp_limit;
+ } else {
+ memset(pbuffer, '\0', dbr_grDouble_size);
+ *options = (*options) ^ DBR_GR_DOUBLE; /*Turn off option */
+ }
+ *ppbuffer = ((char *)*ppbuffer) + dbr_grDouble_size;
+ }
+ return;
}
static void get_control(DBADDR *paddr, char **ppbuffer,
- rset *prset,long *options)
+ rset * prset, long *options)
{
- struct dbr_ctrlDouble ctrld;
- int got_data=FALSE;
-
- ctrld.upper_ctrl_limit = ctrld.lower_ctrl_limit = 0.0;
- if( prset && prset->get_control_double ) {
- (*prset->get_control_double)(paddr,&ctrld);
- got_data=TRUE;
- }
- if( (*options) & (DBR_CTRL_LONG) ) {
- char *pbuffer=*ppbuffer;
-
- if(got_data) {
- struct dbr_ctrlLong *pctrl=(struct dbr_ctrlLong*)pbuffer;
- pctrl->upper_ctrl_limit = (epicsInt32)ctrld.upper_ctrl_limit;
- pctrl->lower_ctrl_limit = (epicsInt32)ctrld.lower_ctrl_limit;
- } else {
- memset(pbuffer,'\0',dbr_ctrlLong_size);
- *options = (*options) ^ DBR_CTRL_LONG; /*Turn off option*/
- }
- *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlLong_size;
- }
- if( (*options) & (DBR_CTRL_DOUBLE) ) {
- char *pbuffer=*ppbuffer;
-
- if(got_data) {
- struct dbr_ctrlDouble *pctrl=(struct dbr_ctrlDouble*)pbuffer;
- pctrl->upper_ctrl_limit = ctrld.upper_ctrl_limit;
- pctrl->lower_ctrl_limit = ctrld.lower_ctrl_limit;
- } else {
- memset(pbuffer,'\0',dbr_ctrlDouble_size);
- *options = (*options) ^ DBR_CTRL_DOUBLE; /*Turn off option*/
- }
- *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlDouble_size;
- }
- return;
+ struct dbr_ctrlDouble ctrld;
+ int got_data = FALSE;
+
+ ctrld.upper_ctrl_limit = ctrld.lower_ctrl_limit = 0.0;
+ if (prset && prset->get_control_double) {
+ (*prset->get_control_double) (paddr, &ctrld);
+ got_data = TRUE;
+ }
+ if ((*options) & (DBR_CTRL_LONG)) {
+ char *pbuffer = *ppbuffer;
+
+ if (got_data) {
+ struct dbr_ctrlLong *pctrl = (struct dbr_ctrlLong *)pbuffer;
+ pctrl->upper_ctrl_limit = (epicsInt32) ctrld.upper_ctrl_limit;
+ pctrl->lower_ctrl_limit = (epicsInt32) ctrld.lower_ctrl_limit;
+ } else {
+ memset(pbuffer, '\0', dbr_ctrlLong_size);
+ *options = (*options) ^ DBR_CTRL_LONG; /*Turn off option */
+ }
+ *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlLong_size;
+ }
+ if ((*options) & (DBR_CTRL_DOUBLE)) {
+ char *pbuffer = *ppbuffer;
+
+ if (got_data) {
+ struct dbr_ctrlDouble *pctrl = (struct dbr_ctrlDouble *)pbuffer;
+ pctrl->upper_ctrl_limit = ctrld.upper_ctrl_limit;
+ pctrl->lower_ctrl_limit = ctrld.lower_ctrl_limit;
+ } else {
+ memset(pbuffer, '\0', dbr_ctrlDouble_size);
+ *options = (*options) ^ DBR_CTRL_DOUBLE; /*Turn off option */
+ }
+ *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlDouble_size;
+ }
+ return;
}
static void get_alarm(DBADDR *paddr, char **ppbuffer,
- rset *prset, long *options)
+ rset * prset, long *options)
{
char *pbuffer = *ppbuffer;
- struct dbr_alDouble ald = {epicsNAN, epicsNAN, epicsNAN, epicsNAN};
+ struct dbr_alDouble ald = { epicsNAN, epicsNAN, epicsNAN, epicsNAN };
long no_data = TRUE;
if (prset && prset->get_alarm_double)
no_data = prset->get_alarm_double(paddr, &ald);
if (*options & DBR_AL_LONG) {
- struct dbr_alLong *pal = (struct dbr_alLong*) pbuffer;
+ struct dbr_alLong *pal = (struct dbr_alLong *)pbuffer;
- pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ?
+ pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ?
(epicsInt32) ald.upper_alarm_limit : 0;
pal->upper_warning_limit = finite(ald.upper_warning_limit) ?
(epicsInt32) ald.upper_warning_limit : 0;
pal->lower_warning_limit = finite(ald.lower_warning_limit) ?
(epicsInt32) ald.lower_warning_limit : 0;
- pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ?
+ pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ?
(epicsInt32) ald.lower_alarm_limit : 0;
if (no_data)
- *options ^= DBR_AL_LONG; /*Turn off option*/
+ *options ^= DBR_AL_LONG; /*Turn off option */
*ppbuffer += dbr_alLong_size;
}
if (*options & DBR_AL_DOUBLE) {
- struct dbr_alDouble *pal = (struct dbr_alDouble*) pbuffer;
+ struct dbr_alDouble *pal = (struct dbr_alDouble *)pbuffer;
- pal->upper_alarm_limit = ald.upper_alarm_limit;
+ pal->upper_alarm_limit = ald.upper_alarm_limit;
pal->upper_warning_limit = ald.upper_warning_limit;
pal->lower_warning_limit = ald.lower_warning_limit;
- pal->lower_alarm_limit = ald.lower_alarm_limit;
+ pal->lower_alarm_limit = ald.lower_alarm_limit;
if (no_data)
- *options ^= DBR_AL_DOUBLE; /*Turn off option*/
+ *options ^= DBR_AL_DOUBLE; /*Turn off option */
*ppbuffer += dbr_alDouble_size;
}
@@ -330,88 +332,89 @@ static void get_alarm(DBADDR *paddr, char **ppbuffer,
* blocks only changing the buffer pointer in a way that does not break alignment.
*/
static void getOptions(DBADDR *paddr, char **poriginal, long *options,
- void *pflin)
+ void *pflin)
{
- db_field_log *pfl= (db_field_log *)pflin;
- rset *prset;
- short field_type;
- dbCommon *pcommon;
- char *pbuffer = *poriginal;
-
- if (!pfl || pfl->type == dbfl_type_rec)
- field_type = paddr->field_type;
- else
- field_type = pfl->field_type;
- prset=dbGetRset(paddr);
- /* Process options */
- pcommon = paddr->precord;
- if( (*options) & DBR_STATUS ) {
- unsigned short *pushort = (unsigned short *)pbuffer;
-
- if (!pfl || pfl->type == dbfl_type_rec) {
- *pushort++ = pcommon->stat;
- *pushort++ = pcommon->sevr;
- } else {
- *pushort++ = pfl->stat;
- *pushort++ = pfl->sevr;
- }
- *pushort++ = pcommon->acks;
- *pushort++ = pcommon->ackt;
- pbuffer = (char *)pushort;
- }
- if( (*options) & DBR_UNITS ) {
- memset(pbuffer,'\0',dbr_units_size);
- if( prset && prset->get_units ){
- (*prset->get_units)(paddr, pbuffer);
- pbuffer[DB_UNITS_SIZE-1] = '\0';
- } else {
- *options ^= DBR_UNITS; /*Turn off DBR_UNITS*/
- }
- pbuffer += dbr_units_size;
- }
- if( (*options) & DBR_PRECISION ) {
- memset(pbuffer, '\0', dbr_precision_size);
- if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE)
- && prset && prset->get_precision ){
- (*prset->get_precision)(paddr,(long *)pbuffer);
- } else {
- *options ^= DBR_PRECISION; /*Turn off DBR_PRECISION*/
- }
- pbuffer += dbr_precision_size;
- }
- if( (*options) & DBR_TIME ) {
- epicsUInt32 *ptime = (epicsUInt32 *)pbuffer;
-
- if (!pfl || pfl->type == dbfl_type_rec) {
- *ptime++ = pcommon->time.secPastEpoch;
- *ptime++ = pcommon->time.nsec;
- } else {
- *ptime++ = pfl->time.secPastEpoch;
- *ptime++ = pfl->time.nsec;
- }
- pbuffer = (char *)ptime;
- }
- if( (*options) & DBR_ENUM_STRS )
- get_enum_strs(paddr, &pbuffer, prset, options);
- if( (*options) & (DBR_GR_LONG|DBR_GR_DOUBLE ))
- get_graphics(paddr, &pbuffer, prset, options);
- if((*options) & (DBR_CTRL_LONG | DBR_CTRL_DOUBLE ))
- get_control(paddr, &pbuffer, prset, options);
- if((*options) & (DBR_AL_LONG | DBR_AL_DOUBLE ))
- get_alarm(paddr, &pbuffer, prset, options);
- *poriginal = pbuffer;
+ db_field_log *pfl = (db_field_log *) pflin;
+ rset *prset;
+ short field_type;
+ dbCommon *pcommon;
+ char *pbuffer = *poriginal;
+
+ if (!pfl)
+ field_type = paddr->field_type;
+ else
+ field_type = pfl->field_type;
+ prset = dbGetRset(paddr);
+ /* Process options */
+ pcommon = paddr->precord;
+ if ((*options) & DBR_STATUS) {
+ unsigned short *pushort = (unsigned short *)pbuffer;
+
+ if (!pfl) {
+ *pushort++ = pcommon->stat;
+ *pushort++ = pcommon->sevr;
+ } else {
+ *pushort++ = pfl->stat;
+ *pushort++ = pfl->sevr;
+ }
+ *pushort++ = pcommon->acks;
+ *pushort++ = pcommon->ackt;
+ pbuffer = (char *)pushort;
+ }
+ if ((*options) & DBR_UNITS) {
+ memset(pbuffer, '\0', dbr_units_size);
+ if (prset && prset->get_units) {
+ (*prset->get_units) (paddr, pbuffer);
+ pbuffer[DB_UNITS_SIZE - 1] = '\0';
+ } else {
+ *options ^= DBR_UNITS; /*Turn off DBR_UNITS */
+ }
+ pbuffer += dbr_units_size;
+ }
+ if ((*options) & DBR_PRECISION) {
+ memset(pbuffer, '\0', dbr_precision_size);
+ if ((field_type == DBF_FLOAT || field_type == DBF_DOUBLE)
+ && prset && prset->get_precision) {
+ (*prset->get_precision) (paddr, (long *)pbuffer);
+ } else {
+ *options ^= DBR_PRECISION; /*Turn off DBR_PRECISION */
+ }
+ pbuffer += dbr_precision_size;
+ }
+ if ((*options) & DBR_TIME) {
+ epicsUInt32 *ptime = (epicsUInt32 *) pbuffer;
+
+ if (!pfl) {
+ *ptime++ = pcommon->time.secPastEpoch;
+ *ptime++ = pcommon->time.nsec;
+ } else {
+ *ptime++ = pfl->time.secPastEpoch;
+ *ptime++ = pfl->time.nsec;
+ }
+ pbuffer = (char *)ptime;
+ }
+ if ((*options) & DBR_ENUM_STRS)
+ get_enum_strs(paddr, &pbuffer, prset, options);
+ if ((*options) & (DBR_GR_LONG | DBR_GR_DOUBLE))
+ get_graphics(paddr, &pbuffer, prset, options);
+ if ((*options) & (DBR_CTRL_LONG | DBR_CTRL_DOUBLE))
+ get_control(paddr, &pbuffer, prset, options);
+ if ((*options) & (DBR_AL_LONG | DBR_AL_DOUBLE))
+ get_alarm(paddr, &pbuffer, prset, options);
+ *poriginal = pbuffer;
}
-rset * dbGetRset(const struct dbAddr *paddr)
+rset *dbGetRset(const struct dbAddr *paddr)
{
- struct dbFldDes *pfldDes = paddr->pfldDes;
+ struct dbFldDes *pfldDes = paddr->pfldDes;
- if(!pfldDes) return(0);
- return(pfldDes->pdbRecordType->prset);
+ if (!pfldDes)
+ return (0);
+ return (pfldDes->pdbRecordType->prset);
}
-long dbPutAttribute(
- const char *recordTypename, const char *name, const char *value)
+long dbPutAttribute(const char *recordTypename, const char *name,
+ const char *value)
{
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
@@ -430,7 +433,7 @@ long dbPutAttribute(
if (!status)
status = dbPutRecordAttribute(pdbEntry, name, value);
dbFinishEntry(pdbEntry);
-done:
+ done:
if (status)
errMessage(status, "dbPutAttribute failure");
return status;
@@ -458,7 +461,7 @@ int dbGetFieldIndex(const struct dbAddr *paddr)
* 5. Run the process routine specific to the record type.
* 6. Check to see if record contents should be automatically printed.
*/
-long dbProcess(dbCommon *precord)
+long dbProcess(dbCommon * precord)
{
rset *prset = precord->rset;
dbRecordType *pdbRecordType = precord->rdes;
@@ -466,7 +469,7 @@ long dbProcess(dbCommon *precord)
char context[40] = "";
long status = 0;
int *ptrace;
- int set_trace = FALSE;
+ int set_trace = FALSE;
dbFldDes *pdbFldDes;
int callNotifyCompletion = FALSE;
@@ -492,7 +495,7 @@ long dbProcess(dbCommon *precord)
goto all_done;
}
- /* check for trace processing*/
+ /* check for trace processing */
if (tpro) {
if (!*ptrace) {
*ptrace = 1;
@@ -519,19 +522,17 @@ long dbProcess(dbCommon *precord)
/* raise scan alarm after MAX_LOCK times */
if ((precord->stat == SCAN_ALARM) ||
- (precord->lcnt++ < MAX_LOCK) ||
- (precord->sevr >= INVALID_ALARM)) goto all_done;
+ (precord->lcnt++ < MAX_LOCK) || (precord->sevr >= INVALID_ALARM))
+ goto all_done;
recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);
monitor_mask = recGblResetAlarms(precord);
- monitor_mask |= DBE_VALUE|DBE_LOG;
+ monitor_mask |= DBE_VALUE | DBE_LOG;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
db_post_events(precord,
- (void *)(((char *)precord) + pdbFldDes->offset),
- monitor_mask);
+ (void *)(((char *)precord) + pdbFldDes->offset), monitor_mask);
goto all_done;
- }
- else
+ } else
precord->lcnt = 0;
/*
@@ -547,7 +548,7 @@ long dbProcess(dbCommon *precord)
printf("%s: dbProcess of Disabled '%s'\n",
context, precord->name);
- /*take care of caching and notifyCompletion*/
+ /*take care of caching and notifyCompletion */
precord->rpro = FALSE;
precord->putf = FALSE;
callNotifyCompletion = TRUE;
@@ -564,8 +565,8 @@ long dbProcess(dbCommon *precord)
db_post_events(precord, &precord->sevr, DBE_VALUE);
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
db_post_events(precord,
- (void *)(((char *)precord) + pdbFldDes->offset),
- DBE_VALUE|DBE_ALARM);
+ (void *)(((char *)precord) + pdbFldDes->offset),
+ DBE_VALUE | DBE_ALARM);
goto all_done;
}
@@ -573,7 +574,7 @@ long dbProcess(dbCommon *precord)
/* FIXME: put this in iocInit() !!! */
if (!prset || !prset->process) {
callNotifyCompletion = TRUE;
- precord->pact = 1;/*set pact so error is issued only once*/
+ precord->pact = 1; /*set pact so error is issued only once */
recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess");
status = S_db_noRSET;
if (*ptrace)
@@ -592,7 +593,7 @@ long dbProcess(dbCommon *precord)
dbPrint(precord);
}
-all_done:
+ all_done:
if (set_trace)
*ptrace = 0;
if (callNotifyCompletion && precord->ppn)
@@ -601,7 +602,7 @@ all_done:
return status;
}
-long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr)
+long dbEntryToAddr(const DBENTRY * pdbentry, DBADDR *paddr)
{
dbFldDes *pflddes = pdbentry->pflddes;
short dbfType = pflddes->field_type;
@@ -610,9 +611,9 @@ long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr)
paddr->pfield = pdbentry->pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
- paddr->field_type = dbfType;
- paddr->field_size = pflddes->size;
- paddr->special = pflddes->special;
+ paddr->field_type = dbfType;
+ paddr->field_size = pflddes->size;
+ paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
@@ -643,16 +644,20 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
dbInitEntry(pdbbase, &dbEntry);
status = dbFindRecordPart(&dbEntry, &pname);
- if (status) goto finish;
+ if (status)
+ goto finish;
- if (*pname == '.') ++pname;
+ if (*pname == '.')
+ ++pname;
status = dbFindFieldPart(&dbEntry, &pname);
if (status == S_dbLib_fieldNotFound)
status = dbGetAttributePart(&dbEntry, &pname);
- if (status) goto finish;
+ if (status)
+ goto finish;
status = dbEntryToAddr(&dbEntry, paddr);
- if (status) goto finish;
+ if (status)
+ goto finish;
/* Handle field modifiers */
if (*pname++ == '$') {
@@ -664,29 +669,27 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
paddr->field_type = DBF_CHAR;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
- }
- else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
+ } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
- }
- else {
+ } else {
status = S_dbLib_fieldNotFound;
}
}
-finish:
+ finish:
dbFinishEntry(&dbEntry);
return status;
}
-void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)
+void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY * pdbentry)
{
struct dbCommon *prec = paddr->precord;
dbCommonPvt *ppvt = dbRec2Pvt(prec);
- memset((char *)pdbentry,'\0',sizeof(DBENTRY));
+ memset((char *)pdbentry, '\0', sizeof(DBENTRY));
pdbentry->pdbbase = pdbbase;
pdbentry->precordType = prec->rdes;
@@ -696,24 +699,24 @@ void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)
pdbentry->indfield = paddr->pfldDes->indRecordType;
}
-void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
+void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY * pdbentry)
{
dbCommonPvt *ppvt = dbRec2Pvt(prec);
- memset((char *)pdbentry,'\0',sizeof(DBENTRY));
+ memset((char *)pdbentry, '\0', sizeof(DBENTRY));
pdbentry->pdbbase = pdbbase;
pdbentry->precordType = prec->rdes;
pdbentry->precnode = ppvt->recnode;
}
-struct link* dbGetDevLink(struct dbCommon* prec)
+struct link *dbGetDevLink(struct dbCommon *prec)
{
DBLINK *plink = 0;
DBENTRY entry;
dbInitEntryFromRecord(prec, &entry);
- if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) {
- plink = (DBLINK*)entry.pfield;
+ if (dbFindField(&entry, "INP") == 0 || dbFindField(&entry, "OUT") == 0) {
+ plink = (DBLINK *) entry.pfield;
}
dbFinishEntry(&entry);
return plink;
@@ -723,41 +726,53 @@ long dbValueSize(short dbr_type)
{
/* sizes for value associated with each DBR request type */
static long size[] = {
- MAX_STRING_SIZE, /* STRING */
- sizeof(epicsInt8), /* CHAR */
- sizeof(epicsUInt8), /* UCHAR */
- sizeof(epicsInt16), /* SHORT */
- sizeof(epicsUInt16), /* USHORT */
- sizeof(epicsInt32), /* LONG */
- sizeof(epicsUInt32), /* ULONG */
- sizeof(epicsInt64), /* INT64 */
- sizeof(epicsUInt64), /* UINT64 */
- sizeof(epicsFloat32), /* FLOAT */
- sizeof(epicsFloat64), /* DOUBLE */
- sizeof(epicsEnum16)}; /* ENUM */
-
- return(size[dbr_type]);
+ MAX_STRING_SIZE, /* STRING */
+ sizeof(epicsInt8), /* CHAR */
+ sizeof(epicsUInt8), /* UCHAR */
+ sizeof(epicsInt16), /* SHORT */
+ sizeof(epicsUInt16), /* USHORT */
+ sizeof(epicsInt32), /* LONG */
+ sizeof(epicsUInt32), /* ULONG */
+ sizeof(epicsInt64), /* INT64 */
+ sizeof(epicsUInt64), /* UINT64 */
+ sizeof(epicsFloat32), /* FLOAT */
+ sizeof(epicsFloat64), /* DOUBLE */
+ sizeof(epicsEnum16)
+ }; /* ENUM */
+
+ return (size[dbr_type]);
}
-
long dbBufferSize(short dbr_type, long options, long no_elements)
{
- long nbytes=0;
+ long nbytes = 0;
nbytes += dbValueSize(dbr_type) * no_elements;
- if (options & DBR_STATUS) nbytes += dbr_status_size;
- if (options & DBR_UNITS) nbytes += dbr_units_size;
- if (options & DBR_PRECISION) nbytes += dbr_precision_size;
- if (options & DBR_TIME) nbytes += dbr_time_size;
- if (options & DBR_ENUM_STRS) nbytes += dbr_enumStrs_size;
- if (options & DBR_GR_LONG) nbytes += dbr_grLong_size;
- if (options & DBR_GR_DOUBLE) nbytes += dbr_grDouble_size;
- if (options & DBR_CTRL_LONG) nbytes += dbr_ctrlLong_size;
- if (options & DBR_CTRL_DOUBLE) nbytes += dbr_ctrlDouble_size;
- if (options & DBR_AL_LONG) nbytes += dbr_alLong_size;
- if (options & DBR_AL_DOUBLE) nbytes += dbr_alDouble_size;
- return(nbytes);
+ if (options & DBR_STATUS)
+ nbytes += dbr_status_size;
+ if (options & DBR_UNITS)
+ nbytes += dbr_units_size;
+ if (options & DBR_PRECISION)
+ nbytes += dbr_precision_size;
+ if (options & DBR_TIME)
+ nbytes += dbr_time_size;
+ if (options & DBR_ENUM_STRS)
+ nbytes += dbr_enumStrs_size;
+ if (options & DBR_GR_LONG)
+ nbytes += dbr_grLong_size;
+ if (options & DBR_GR_DOUBLE)
+ nbytes += dbr_grDouble_size;
+ if (options & DBR_CTRL_LONG)
+ nbytes += dbr_ctrlLong_size;
+ if (options & DBR_CTRL_DOUBLE)
+ nbytes += dbr_ctrlDouble_size;
+ if (options & DBR_AL_LONG)
+ nbytes += dbr_alLong_size;
+ if (options & DBR_AL_DOUBLE)
+ nbytes += dbr_alDouble_size;
+ return (nbytes);
}
+
int dbLoadDatabase(const char *file, const char *path, const char *subs)
{
if (!file) {
@@ -767,7 +782,7 @@ int dbLoadDatabase(const char *file, const char *path, const char *subs)
return dbReadDatabase(&pdbbase, file, path, subs);
}
-int dbLoadRecords(const char* file, const char* subs)
+int dbLoadRecords(const char *file, const char *subs)
{
int status;
@@ -781,7 +796,6 @@ int dbLoadRecords(const char* file, const char* subs)
return status;
}
-
static long getLinkValue(DBADDR *paddr, short dbrType,
char *pbuf, long *nRequest)
{
@@ -797,7 +811,7 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
* valid DBADDR, so no point to check again.
* Request for zero elements always succeeds
*/
- if(!nReq)
+ if (!nReq)
return 0;
switch (dbrType) {
@@ -806,8 +820,9 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
nReq = 1;
break;
- case DBR_DOUBLE: /* Needed for dbCa links */
- if (nRequest) *nRequest = 1;
+ case DBR_DOUBLE: /* Needed for dbCa links */
+ if (nRequest)
+ *nRequest = 1;
*(double *)pbuf = epicsNAN;
return 0;
@@ -821,27 +836,30 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
dbInitEntry(pdbbase, &dbEntry);
status = dbFindRecord(&dbEntry, precord->name);
- if (!status) status = dbFindField(&dbEntry, pfldDes->name);
+ if (!status)
+ status = dbFindField(&dbEntry, pfldDes->name);
if (!status) {
const char *rtnString = dbGetString(&dbEntry);
- strncpy(pbuf, rtnString, maxlen-1);
- pbuf[maxlen-1] = 0;
- if(dbrType!=DBR_STRING)
- nReq = strlen(pbuf)+1;
- if(nRequest) *nRequest = nReq;
+ strncpy(pbuf, rtnString, maxlen - 1);
+ pbuf[maxlen - 1] = 0;
+ if (dbrType != DBR_STRING)
+ nReq = strlen(pbuf) + 1;
+ if (nRequest)
+ *nRequest = nReq;
}
dbFinishEntry(&dbEntry);
return status;
}
static long getAttrValue(DBADDR *paddr, short dbrType,
- char *pbuf, long *nRequest)
+ char *pbuf, long *nRequest)
{
int maxlen;
long nReq = nRequest ? *nRequest : 1;
- if (!paddr->pfield) return S_db_badField;
+ if (!paddr->pfield)
+ return S_db_badField;
switch (dbrType) {
case DBR_STRING:
@@ -859,22 +877,23 @@ static long getAttrValue(DBADDR *paddr, short dbrType,
return S_db_badDbrtype;
}
- strncpy(pbuf, paddr->pfield, maxlen-1);
- pbuf[maxlen-1] = 0;
- if(dbrType!=DBR_STRING)
- nReq = strlen(pbuf)+1;
- if(nRequest) *nRequest = nReq;
+ strncpy(pbuf, paddr->pfield, maxlen - 1);
+ pbuf[maxlen - 1] = 0;
+ if (dbrType != DBR_STRING)
+ nReq = strlen(pbuf) + 1;
+ if (nRequest)
+ *nRequest = nReq;
return 0;
}
-long dbGetField(DBADDR *paddr,short dbrType,
- void *pbuffer, long *options, long *nRequest, void *pflin)
+long dbGetField(DBADDR *paddr, short dbrType,
+ void *pbuffer, long *options, long *nRequest)
{
dbCommon *precord = paddr->precord;
long status = 0;
dbScanLock(precord);
- status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin);
+ status = dbGet(paddr, dbrType, pbuffer, options, nRequest, NULL);
dbScanUnlock(precord);
return status;
}
@@ -884,7 +903,7 @@ long dbGet(DBADDR *paddr, short dbrType,
{
char *pbuf = pbuffer;
void *pfieldsave = paddr->pfield;
- db_field_log *pfl = (db_field_log *)pflin;
+ db_field_log *pfl = (db_field_log *) pflin;
short field_type;
long capacity, no_elements, offset;
rset *prset;
@@ -895,7 +914,7 @@ long dbGet(DBADDR *paddr, short dbrType,
if (nRequest && *nRequest == 0)
return 0;
- if (!pfl || pfl->type == dbfl_type_rec) {
+ if (!pfl) {
field_type = paddr->field_type;
no_elements = capacity = paddr->no_elements;
@@ -903,15 +922,14 @@ long dbGet(DBADDR *paddr, short dbrType,
* may modify paddr->pfield
*/
if (paddr->pfldDes->special == SPC_DBADDR &&
- (prset = dbGetRset(paddr)) &&
- prset->get_array_info) {
+ (prset = dbGetRset(paddr)) && prset->get_array_info) {
status = prset->get_array_info(paddr, &no_elements, &offset);
} else
offset = 0;
} else {
field_type = pfl->field_type;
no_elements = capacity = pfl->no_elements;
- offset = 0;
+ offset = pfl->offset;
}
if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) {
@@ -937,19 +955,25 @@ long dbGet(DBADDR *paddr, short dbrType,
if (offset == 0 && (!nRequest || no_elements == 1)) {
if (nRequest)
*nRequest = 1;
- if (!pfl || pfl->type == dbfl_type_rec) {
+ if (!pfl) {
status = dbFastGetConvertRoutine[field_type][dbrType]
(paddr->pfield, pbuf, paddr);
} else {
- DBADDR localAddr = *paddr; /* Structure copy */
+ DBADDR localAddr = *paddr; /* Structure copy */
+
+ if (pfl->no_elements < 1) {
+ status = S_db_badField;
+ goto done;
+ }
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
+ /* not used by dbFastConvert: */
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
- localAddr.pfield = (char *) &pfl->u.v.field;
+ localAddr.pfield = (char *)&pfl->u.v.field;
else
- localAddr.pfield = (char *) pfl->u.r.field;
+ localAddr.pfield = (char *)pfl->u.r.field;
status = dbFastGetConvertRoutine[field_type][dbrType]
(localAddr.pfield, pbuf, &localAddr);
}
@@ -969,52 +993,55 @@ long dbGet(DBADDR *paddr, short dbrType,
char message[80];
sprintf(message, "dbGet: Missing conversion for [%d][%d]\n",
- field_type, dbrType);
+ field_type, dbrType);
recGblDbaddrError(S_db_badDbrtype, paddr, message);
status = S_db_badDbrtype;
goto done;
}
/* convert data into the caller's buffer */
if (n <= 0) {
- ;/*do nothing*/
- } else if (!pfl || pfl->type == dbfl_type_rec) {
+ ; /*do nothing */
+ } else if (!pfl) {
status = convert(paddr, pbuf, n, capacity, offset);
} else {
- DBADDR localAddr = *paddr; /* Structure copy */
+ DBADDR localAddr = *paddr; /* Structure copy */
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
+ /* not used by dbConvert, it uses the passed capacity instead: */
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
- localAddr.pfield = (char *) &pfl->u.v.field;
+ localAddr.pfield = (char *)&pfl->u.v.field;
else
- localAddr.pfield = (char *) pfl->u.r.field;
+ localAddr.pfield = (char *)pfl->u.r.field;
status = convert(&localAddr, pbuf, n, capacity, offset);
}
- if(!status && dbrType==DBF_CHAR && nRequest &&
- paddr->pfldDes && paddr->pfldDes->field_type==DBF_STRING)
- {
+ if (!status && dbrType == DBF_CHAR && nRequest &&
+ paddr->pfldDes && paddr->pfldDes->field_type == DBF_STRING) {
/* long string ensure nil and truncate to actual length */
long nReq = *nRequest;
- pbuf[nReq-1] = '\0';
- *nRequest = strlen(pbuf)+1;
+ pbuf[nReq - 1] = '\0';
+ *nRequest = strlen(pbuf) + 1;
}
}
-done:
+ done:
paddr->pfield = pfieldsave;
return status;
}
-devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp) {
- return (devSup *)ellNth(&prdes->devList, dtyp+1);
+devSup *dbDTYPtoDevSup(dbRecordType * prdes, int dtyp)
+{
+ return (devSup *) ellNth(&prdes->devList, dtyp + 1);
}
-devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) {
- devSup *pdevSup = (devSup *)ellFirst(&prdes->devList);
+devSup *dbDSETtoDevSup(dbRecordType * prdes, dset * pdset)
+{
+ devSup *pdevSup = (devSup *) ellFirst(&prdes->devList);
while (pdevSup) {
- if (pdset == pdevSup->pdset) return pdevSup;
- pdevSup = (devSup *)ellNext(&pdevSup->node);
+ if (pdset == pdevSup->pdset)
+ return pdevSup;
+ pdevSup = (devSup *) ellNext(&pdevSup->node);
}
return NULL;
}
@@ -1022,24 +1049,24 @@ devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) {
static long dbPutFieldLink(DBADDR *paddr,
short dbrType, const void *pbuffer, long nRequest)
{
- dbLinkInfo link_info;
- DBADDR *pdbaddr = NULL;
- dbCommon *precord = paddr->precord;
- dbCommon *lockrecs[2];
- dbLocker locker;
- dbFldDes *pfldDes = paddr->pfldDes;
- long special = paddr->special;
+ dbLinkInfo link_info;
+ dbChannel *chan = NULL;
+ dbCommon *precord = paddr->precord;
+ dbCommon *lockrecs[2];
+ dbLocker locker;
+ dbFldDes *pfldDes = paddr->pfldDes;
+ long special = paddr->special;
struct link *plink = (struct link *)paddr->pfield;
- const char *pstring = (const char *)pbuffer;
+ const char *pstring = (const char *)pbuffer;
struct dsxt *old_dsxt = NULL;
dset *new_dset = NULL;
struct dsxt *new_dsxt = NULL;
- devSup *new_devsup = NULL;
- long status;
- int isDevLink;
- short scan;
+ devSup *new_devsup = NULL;
+ long status;
+ int isDevLink;
+ short scan;
- STATIC_ASSERT(DBLOCKER_NALLOC>=2);
+ STATIC_ASSERT(DBLOCKER_NALLOC >= 2);
switch (dbrType) {
case DBR_CHAR:
@@ -1061,25 +1088,20 @@ static long dbPutFieldLink(DBADDR *paddr,
if (link_info.ltype == PV_LINK &&
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
- DBADDR tempaddr;
-
- if (dbNameToAddr(link_info.target, &tempaddr)==0) {
- /* This will become a DB link. */
- pdbaddr = malloc(sizeof(*pdbaddr));
- if (!pdbaddr) {
- status = S_db_noMemory;
- goto cleanup;
- }
- *pdbaddr = tempaddr; /* struct copy */
+ chan = dbChannelCreate(link_info.target);
+ if (chan && dbChannelOpen(chan) != 0) {
+ errlogPrintf
+ ("ERROR: dbPutFieldLink %s.%s=%s: dbChannelOpen() failed\n",
+ precord->name, pfldDes->name, link_info.target);
+ goto cleanup;
}
}
- isDevLink = ellCount(&precord->rdes->devList) > 0 &&
- pfldDes->isDevLink;
+ isDevLink = ellCount(&precord->rdes->devList) > 0 && pfldDes->isDevLink;
memset(&locker, 0, sizeof(locker));
lockrecs[0] = precord;
- lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL;
+ lockrecs[1] = chan ? dbChannelRecord(chan) : NULL;
dbLockerPrepare(&locker, lockrecs, 2);
dbScanLockMany(&locker);
@@ -1130,17 +1152,19 @@ static long dbPutFieldLink(DBADDR *paddr,
if (dbLinkIsDefined(plink)) {
dbRemoveLink(&locker, plink); /* Clear out old link */
- }
- else if (!isDevLink) {
+ } else if (!isDevLink) {
status = S_db_badHWaddr;
goto restoreScan;
}
- if (special) status = dbPutSpecial(paddr, 0);
+ if (special)
+ status = dbPutSpecial(paddr, 0);
- if (!status) status = dbSetLink(plink, &link_info, new_devsup);
+ if (!status)
+ status = dbSetLink(plink, &link_info, new_devsup);
- if (!status && special) status = dbPutSpecial(paddr, 1);
+ if (!status && special)
+ status = dbPutSpecial(paddr, 1);
if (status) {
if (isDevLink) {
@@ -1163,19 +1187,20 @@ static long dbPutFieldLink(DBADDR *paddr,
}
}
- switch (plink->type) { /* New link type */
+ switch (plink->type) { /* New link type */
case PV_LINK:
case CONSTANT:
case JSON_LINK:
- dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr);
+ dbAddLink(&locker, plink, pfldDes->field_type, chan);
+ chan = NULL; /* don't clean it up */
break;
case DB_LINK:
case CA_LINK:
case MACRO_LINK:
- break; /* should never get here */
+ break; /* should never get here */
- default: /* Hardware address */
+ default: /* Hardware address */
if (!isDevLink) {
status = S_db_badHWaddr;
goto postScanEvent;
@@ -1184,19 +1209,20 @@ static long dbPutFieldLink(DBADDR *paddr,
}
db_post_events(precord, plink, DBE_VALUE | DBE_LOG);
-restoreScan:
- if (isDevLink &&
- scan == menuScanI_O_Intr) { /* undo scanDelete() */
+ restoreScan:
+ if (isDevLink && scan == menuScanI_O_Intr) { /* undo scanDelete() */
precord->scan = scan;
scanAdd(precord);
}
-postScanEvent:
+ postScanEvent:
if (scan != precord->scan)
db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
-unlock:
+ unlock:
dbScanUnlockMany(&locker);
dbLockerFinalize(&locker);
-cleanup:
+ cleanup:
+ if (chan)
+ dbChannelDelete(chan);
free(link_info.target);
return status;
}
@@ -1204,16 +1230,16 @@ cleanup:
long dbPutField(DBADDR *paddr, short dbrType,
const void *pbuffer, long nRequest)
{
- long status = 0;
- long special = paddr->special;
- dbFldDes *pfldDes = paddr->pfldDes;
- dbCommon *precord = paddr->precord;
- short dbfType = paddr->field_type;
+ long status = 0;
+ long special = paddr->special;
+ dbFldDes *pfldDes = paddr->pfldDes;
+ dbCommon *precord = paddr->precord;
+ short dbfType = paddr->field_type;
if (special == SPC_ATTRIBUTE)
return S_db_noMod;
- /*check for putField disabled*/
+ /*check for putField disabled */
if (precord->disp && paddr->pfield != &precord->disp)
return S_db_putDisabled;
@@ -1225,8 +1251,7 @@ long dbPutField(DBADDR *paddr, short dbrType,
if (status == 0) {
if (paddr->pfield == &precord->proc ||
(pfldDes->process_passive &&
- precord->scan == 0 &&
- dbrType < DBR_PUT_ACKT)) {
+ precord->scan == 0 && dbrType < DBR_PUT_ACKT)) {
if (precord->pact) {
if (dbAccessDebugPUTF && precord->tpro)
printf("%s: dbPutField to Active '%s', setting RPRO=1\n",
@@ -1249,11 +1274,11 @@ static long putAckt(DBADDR *paddr, const void *pbuffer, long nRequest,
dbCommon *precord = paddr->precord;
const unsigned short *ptrans = pbuffer;
- if (*ptrans == precord->ackt) return 0;
+ if (*ptrans == precord->ackt)
+ return 0;
precord->ackt = *ptrans;
db_post_events(precord, &precord->ackt, DBE_VALUE | DBE_ALARM);
- if (!precord->ackt &&
- precord->acks > precord->sevr) {
+ if (!precord->ackt && precord->acks > precord->sevr) {
precord->acks = precord->sevr;
db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);
}
@@ -1275,14 +1300,13 @@ static long putAcks(DBADDR *paddr, const void *pbuffer, long nRequest,
return 0;
}
-long dbPut(DBADDR *paddr, short dbrType,
- const void *pbuffer, long nRequest)
+long dbPut(DBADDR *paddr, short dbrType, const void *pbuffer, long nRequest)
{
dbCommon *precord = paddr->precord;
- short field_type = paddr->field_type;
- long no_elements = paddr->no_elements;
- long special = paddr->special;
- void *pfieldsave = paddr->pfield;
+ short field_type = paddr->field_type;
+ long no_elements = paddr->no_elements;
+ long special = paddr->special;
+ void *pfieldsave = paddr->pfield;
rset *prset = dbGetRset(paddr);
long status = 0;
long offset;
@@ -1306,7 +1330,8 @@ long dbPut(DBADDR *paddr, short dbrType,
if (special) {
status = dbPutSpecial(paddr, 0);
- if (status) return status;
+ if (status)
+ return status;
}
if (paddr->pfldDes->special == SPC_DBADDR &&
@@ -1315,18 +1340,19 @@ long dbPut(DBADDR *paddr, short dbrType,
status = prset->get_array_info(paddr, &dummy, &offset);
/* paddr->pfield may be modified */
- if (status) goto done;
+ if (status)
+ goto done;
} else
offset = 0;
if (no_elements <= 1) {
- status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
+ status = dbFastPutConvertRoutine[dbrType][field_type] (pbuffer,
paddr->pfield, paddr);
nRequest = 1;
} else {
if (no_elements < nRequest)
nRequest = no_elements;
- status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
+ status = dbPutConvertRoutine[dbrType][field_type] (paddr, pbuffer,
nRequest, no_elements, offset);
}
@@ -1340,17 +1366,19 @@ long dbPut(DBADDR *paddr, short dbrType,
/* Always do special processing if needed */
if (special) {
long status2 = dbPutSpecial(paddr, 1);
- if (status2) goto done;
+ if (status2)
+ goto done;
}
- if (status) goto done;
+ if (status)
+ goto done;
/* Propagate monitor events for this field, */
/* unless the field is VAL and PP is true. */
pfldDes = paddr->pfldDes;
isValueField = dbIsValueField(pfldDes);
- if (isValueField) precord->udf = FALSE;
- if (precord->mlis.count &&
- !(isValueField && pfldDes->process_passive))
+ if (isValueField)
+ precord->udf = FALSE;
+ if (precord->mlis.count && !(isValueField && pfldDes->process_passive))
db_post_events(precord, pfieldsave, DBE_VALUE | DBE_LOG);
/* If this field is a property (metadata) field,
* then post a property change event (even if the field
@@ -1358,7 +1386,7 @@ long dbPut(DBADDR *paddr, short dbrType,
*/
if (precord->mlis.count && pfldDes->prop)
db_post_events(precord, NULL, DBE_PROPERTY);
-done:
+ done:
paddr->pfield = pfieldsave;
return status;
}
diff --git a/modules/database/src/ioc/db/dbAccessDefs.h b/modules/database/src/ioc/db/dbAccessDefs.h
index 805dfd4..4a95989 100644
--- a/modules/database/src/ioc/db/dbAccessDefs.h
+++ b/modules/database/src/ioc/db/dbAccessDefs.h
@@ -243,7 +243,7 @@ epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset);
epicsShareFunc long dbGetField(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
- long *nRequest,void *pfl);
+ long *nRequest);
epicsShareFunc long dbGet(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
long *nRequest,void *pfl);
diff --git a/modules/database/src/ioc/db/dbChannel.c b/modules/database/src/ioc/db/dbChannel.c
index bc3c8e4..e361f3b 100644
--- a/modules/database/src/ioc/db/dbChannel.c
+++ b/modules/database/src/ioc/db/dbChannel.c
@@ -49,14 +49,12 @@ typedef struct parseContext {
static void *dbChannelFreeList;
static void *chFilterFreeList;
-static void *dbchStringFreeList;
void dbChannelExit(void)
{
freeListCleanup(dbChannelFreeList);
freeListCleanup(chFilterFreeList);
- freeListCleanup(dbchStringFreeList);
- dbChannelFreeList = chFilterFreeList = dbchStringFreeList = NULL;
+ dbChannelFreeList = chFilterFreeList = NULL;
}
void dbChannelInit (void)
@@ -66,7 +64,7 @@ void dbChannelInit (void)
freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
- freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
+ db_init_event_freelists();
}
static void chf_value(parseContext *parser, parse_result *presult)
@@ -445,28 +443,6 @@ static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppn
return status;
}
-/* Stolen from dbAccess.c: */
-static short mapDBFToDBR[DBF_NTYPES] =
- {
- /* DBF_STRING => */DBR_STRING,
- /* DBF_CHAR => */DBR_CHAR,
- /* DBF_UCHAR => */DBR_UCHAR,
- /* DBF_SHORT => */DBR_SHORT,
- /* DBF_USHORT => */DBR_USHORT,
- /* DBF_LONG => */DBR_LONG,
- /* DBF_ULONG => */DBR_ULONG,
- /* DBF_INT64 => */DBR_INT64,
- /* DBF_UINT64 => */DBR_UINT64,
- /* DBF_FLOAT => */DBR_FLOAT,
- /* DBF_DOUBLE => */DBR_DOUBLE,
- /* DBF_ENUM, => */DBR_ENUM,
- /* DBF_MENU, => */DBR_ENUM,
- /* DBF_DEVICE => */DBR_ENUM,
- /* DBF_INLINK => */DBR_STRING,
- /* DBF_OUTLINK => */DBR_STRING,
- /* DBF_FWDLINK => */DBR_STRING,
- /* DBF_NOACCESS => */DBR_NOACCESS };
-
dbChannel * dbChannelCreate(const char *name)
{
const char *pname = name;
@@ -735,39 +711,6 @@ void dbChannelDelete(dbChannel *chan)
freeListFree(dbChannelFreeList, chan);
}
-static void freeArray(db_field_log *pfl) {
- if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
- freeListFree(dbchStringFreeList, pfl->u.r.field);
- } else {
- free(pfl->u.r.field);
- }
-}
-
-void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan)
-{
- void *p;
- struct dbCommon *prec = dbChannelRecord(chan);
-
- if (pfl->type != dbfl_type_rec) return;
-
- pfl->type = dbfl_type_ref;
- pfl->stat = prec->stat;
- pfl->sevr = prec->sevr;
- pfl->time = prec->time;
- pfl->field_type = chan->addr.field_type;
- pfl->no_elements = chan->addr.no_elements;
- pfl->field_size = chan->addr.field_size;
- pfl->u.r.dtor = freeArray;
- pfl->u.r.pvt = pvt;
- if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
- p = freeListCalloc(dbchStringFreeList);
- } else {
- p = calloc(pfl->no_elements, pfl->field_size);
- }
- if (p) dbGet(&chan->addr, mapDBFToDBR[pfl->field_type], p, NULL, &pfl->no_elements, NULL);
- pfl->u.r.field = p;
-}
-
/* FIXME: Do these belong in a different file? */
void dbRegisterFilter(const char *name, const chFilterIf *fif, void *puser)
diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h
index fab9c66..6e98dee 100644
--- a/modules/database/src/ioc/db/dbChannel.h
+++ b/modules/database/src/ioc/db/dbChannel.h
@@ -64,8 +64,9 @@ typedef struct dbChannel {
/* Prototype for the channel event function that is called in filter stacks
*
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
- * If pLog->type==dbfl_type_rec then dbScanLock() must be called before copying
- * data out of the associated record.
+ * If pLog->type==dbfl_type_ref and pLog->u.r.dtor is NULL, then dbScanLock() must
+ * be called before accessing the data, as this indicates the data is owned by the
+ * record.
*
* This function has ownership of the field log pLog, if it wishes to discard
* this update it should free the field log with db_delete_field_log() and
@@ -224,7 +225,6 @@ epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, voi
epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len);
-epicsShareFunc void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan);
#ifdef __cplusplus
}
diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c
index f2cb0c5..8677add 100644
--- a/modules/database/src/ioc/db/dbDbLink.c
+++ b/modules/database/src/ioc/db/dbDbLink.c
@@ -60,6 +60,7 @@
#include "dbConvertFast.h"
#include "dbConvert.h"
#include "db_field_log.h"
+#include "db_access_routines.h"
#include "dbFldTypes.h"
#include "dbLink.h"
#include "dbLockPvt.h"
@@ -73,7 +74,7 @@
#include "recSup.h"
#include "special.h"
#include "dbDbLink.h"
-
+#include "dbChannel.h"
/***************************** Database Links *****************************/
@@ -82,45 +83,51 @@ static lset dbDb_lset;
static long processTarget(dbCommon *psrc, dbCommon *pdst);
+#define linkChannel(plink) ((dbChannel *) (plink)->value.pv_link.pvt)
+
long dbDbInitLink(struct link *plink, short dbfType)
{
- DBADDR dbaddr;
long status;
- DBADDR *pdbAddr;
+ dbChannel *chan;
+ dbCommon *precord;
- status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
+ chan = dbChannelCreate(plink->value.pv_link.pvname);
+ if (!chan)
+ return S_db_notFound;
+ status = dbChannelOpen(chan);
if (status)
return status;
+ precord = dbChannelRecord(chan);
+
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
- pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
- *pdbAddr = dbaddr; /* structure copy */
- plink->value.pv_link.pvt = pdbAddr;
- ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
+ plink->value.pv_link.pvt = chan;
+ ellAdd(&precord->bklnk, &plink->value.pv_link.backlinknode);
/* merging into the same lockset is deferred to the caller.
* cf. initPVLinks()
*/
- dbLockSetMerge(NULL, plink->precord, dbaddr.precord);
- assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);
+ dbLockSetMerge(NULL, plink->precord, precord);
+ assert(plink->precord->lset->plockSet == precord->lset->plockSet);
return 0;
}
void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
- DBADDR *ptarget)
+ dbChannel *chan)
{
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
- plink->value.pv_link.pvt = ptarget;
- ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);
+ plink->value.pv_link.pvt = chan;
+ ellAdd(&dbChannelRecord(chan)->bklnk, &plink->value.pv_link.backlinknode);
/* target record is already locked in dbPutFieldLink() */
- dbLockSetMerge(locker, plink->precord, ptarget->precord);
+ dbLockSetMerge(locker, plink->precord, dbChannelRecord(chan));
}
static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
{
- DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ dbCommon *precord = dbChannelRecord(chan);
plink->type = PV_LINK;
@@ -130,10 +137,10 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
plink->value.pv_link.getCvt = 0;
plink->value.pv_link.pvlMask = 0;
plink->value.pv_link.lastGetdbrType = 0;
- ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
- dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
+ ellDelete(&precord->bklnk, &plink->value.pv_link.backlinknode);
+ dbLockSetSplit(locker, plink->precord, precord);
}
- free(pdbAddr);
+ dbChannelDelete(chan);
}
static int dbDbIsConnected(const struct link *plink)
@@ -143,16 +150,14 @@ static int dbDbIsConnected(const struct link *plink)
static int dbDbGetDBFtype(const struct link *plink)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- return paddr->field_type;
+ dbChannel *chan = linkChannel(plink);
+ return dbChannelFinalFieldType(chan);
}
static long dbDbGetElements(const struct link *plink, long *nelements)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- *nelements = paddr->no_elements;
+ dbChannel *chan = linkChannel(plink);
+ *nelements = dbChannelFinalElements(chan);
return 0;
}
@@ -160,30 +165,52 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
struct pv_link *ppv_link = &plink->value.pv_link;
- DBADDR *paddr = ppv_link->pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
dbCommon *precord = plink->precord;
long status;
/* scan passive records if link is process passive */
if (ppv_link->pvlMask & pvlOptPP) {
- status = dbScanPassive(precord, paddr->precord);
+ status = dbScanPassive(precord, dbChannelRecord(chan));
if (status)
return status;
}
- if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ /* If filters are involved in a read, create field log and run filters */
+ if (ellCount(&chan->filters)) {
+ db_field_log *pfl;
+
+ /*
+ * For the moment, empty arrays are not supported by EPICS.
+ * See the remark in src/std/filters/arr.c for details.
+ */
+ if (dbChannelFinalElements(chan) <= 0) /* empty array request */
+ return S_db_badField;
+ pfl = db_create_read_log(chan);
+ if (!pfl)
+ return S_db_noMemory;
+ pfl = dbChannelRunPreChain(chan, pfl);
+ pfl = dbChannelRunPostChain(chan, pfl);
+ status = dbChannelGet(chan, dbrType, pbuffer, NULL, pnRequest, pfl);
+ db_delete_field_log(pfl);
+ if (status)
+ return status;
+ if (pnRequest && *pnRequest <= 0) /* empty array result */
+ return S_db_badField;
+ } else if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
+ status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
} else {
- unsigned short dbfType = paddr->field_type;
+ unsigned short dbfType = dbChannelFinalFieldType(chan);
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
return S_db_badDbrtype;
- if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
- && paddr->special != SPC_DBADDR
- && paddr->special != SPC_ATTRIBUTE) {
+ if (dbChannelFinalElements(chan) == 1 && (!pnRequest || *pnRequest == 1)
+ && dbChannelSpecial(chan) != SPC_DBADDR
+ && dbChannelSpecial(chan) != SPC_ATTRIBUTE) {
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
} else {
ppv_link->getCvt = NULL;
status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
@@ -191,16 +218,18 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
ppv_link->lastGetdbrType = dbrType;
}
- if (!status && precord != paddr->precord)
+ if (!status && precord != dbChannelRecord(chan))
recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
- plink->precord, paddr->precord->stat, paddr->precord->sevr);
+ plink->precord,
+ dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr);
return status;
}
static long dbDbGetControlLimits(const struct link *plink, double *low,
double *high)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRctrlDouble
double value;
@@ -221,7 +250,8 @@ static long dbDbGetControlLimits(const struct link *plink, double *low,
static long dbDbGetGraphicLimits(const struct link *plink, double *low,
double *high)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRgrDouble
double value;
@@ -242,7 +272,8 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low,
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
double *low, double *high, double *hihi)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRalDouble
double value;
@@ -264,7 +295,8 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
static long dbDbGetPrecision(const struct link *plink, short *precision)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRprecision
double value;
@@ -283,7 +315,8 @@ static long dbDbGetPrecision(const struct link *plink, short *precision)
static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRunits
double value;
@@ -303,20 +336,20 @@ static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
+ dbChannel *chan = linkChannel(plink);
+ dbCommon *precord = dbChannelRecord(chan);
if (status)
- *status = paddr->precord->stat;
+ *status = precord->stat;
if (severity)
- *severity = paddr->precord->sevr;
+ *severity = precord->sevr;
return 0;
}
static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- *pstamp = paddr->precord->time;
+ dbChannel *chan = linkChannel(plink);
+ dbCommon *precord = dbChannelRecord(chan);
+ *pstamp = precord->time;
return 0;
}
@@ -324,9 +357,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
struct pv_link *ppv_link = &plink->value.pv_link;
+ dbChannel *chan = linkChannel(plink);
struct dbCommon *psrce = plink->precord;
- DBADDR *paddr = (DBADDR *) ppv_link->pvt;
- dbCommon *pdest = paddr->precord;
+ DBADDR *paddr = &chan->addr;
+ dbCommon *pdest = dbChannelRecord(chan);
long status = dbPut(paddr, dbrType, pbuffer, nRequest);
recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,
@@ -334,7 +368,7 @@ static long dbDbPutValue(struct link *plink, short dbrType,
if (status)
return status;
- if (paddr->pfield == (void *) &pdest->proc ||
+ if (dbChannelField(chan) == (void *) &pdest->proc ||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
status = processTarget(psrce, pdest);
}
@@ -345,9 +379,8 @@ static long dbDbPutValue(struct link *plink, short dbrType,
static void dbDbScanFwdLink(struct link *plink)
{
dbCommon *precord = plink->precord;
- dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
-
- dbScanPassive(precord, paddr->precord);
+ dbChannel *chan = linkChannel(plink);
+ dbScanPassive(precord, dbChannelRecord(chan));
}
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
diff --git a/modules/database/src/ioc/db/dbDbLink.h b/modules/database/src/ioc/db/dbDbLink.h
index c367720..27972d8 100644
--- a/modules/database/src/ioc/db/dbDbLink.h
+++ b/modules/database/src/ioc/db/dbDbLink.h
@@ -26,7 +26,7 @@ struct dbLocker;
epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,
- short dbfType, DBADDR *ptarget);
+ short dbfType, dbChannel *ptarget);
#ifdef __cplusplus
}
diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c
index 0d96e12..532c2ba 100644
--- a/modules/database/src/ioc/db/dbEvent.c
+++ b/modules/database/src/ioc/db/dbEvent.c
@@ -251,18 +251,15 @@ int dbel ( const char *pname, unsigned level )
}
/*
- * DB_INIT_EVENTS()
+ * DB_INIT_EVENT_FREELISTS()
*
*
- * Initialize the event facility for this task. Must be called at least once
- * by each task which uses the db event facility
+ * Initialize the free lists used by the event facility.
+ * Safe to be called multiple times.
*
- * returns: ptr to event user block or NULL if memory can't be allocated
*/
-dbEventCtx db_init_events (void)
+void db_init_event_freelists (void)
{
- struct event_user * evUser;
-
if (!dbevEventUserFreeList) {
freeListInitPvt(&dbevEventUserFreeList,
sizeof(struct event_user),8);
@@ -279,6 +276,22 @@ dbEventCtx db_init_events (void)
freeListInitPvt(&dbevFieldLogFreeList,
sizeof(struct db_field_log),2048);
}
+}
+
+/*
+ * DB_INIT_EVENTS()
+ *
+ *
+ * Initialize the event facility for this task. Must be called at least once
+ * by each task which uses the db event facility
+ *
+ * returns: ptr to event user block or NULL if memory can't be allocated
+ */
+dbEventCtx db_init_events (void)
+{
+ struct event_user * evUser;
+
+ db_init_event_freelists();
evUser = (struct event_user *)
freeListCalloc(dbevEventUserFreeList);
@@ -654,27 +667,22 @@ int db_post_extra_labor (dbEventCtx ctx)
return DB_EVENT_OK;
}
-/*
- * DB_CREATE_EVENT_LOG()
- *
- * NOTE: This assumes that the db scan lock is already applied
- * (as it copies data from the record)
- */
-db_field_log* db_create_event_log (struct evSubscrip *pevent)
+static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
{
db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
if (pLog) {
- struct dbChannel *chan = pevent->chan;
struct dbCommon *prec = dbChannelRecord(chan);
- pLog->ctx = dbfl_context_event;
- if (pevent->useValque) {
+ pLog->stat = prec->stat;
+ pLog->sevr = prec->sevr;
+ pLog->time = prec->time;
+ pLog->field_type = dbChannelFieldType(chan);
+ pLog->field_size = dbChannelFieldSize(chan);
+ pLog->no_elements = dbChannelElements(chan);
+ pLog->offset = 0;
+
+ if (use_val) {
pLog->type = dbfl_type_val;
- pLog->stat = prec->stat;
- pLog->sevr = prec->sevr;
- pLog->time = prec->time;
- pLog->field_type = dbChannelFieldType(chan);
- pLog->no_elements = dbChannelElements(chan);
/*
* use memcpy to avoid a bus error on
* union copy of char in the db at an odd
@@ -684,23 +692,62 @@ db_field_log* db_create_event_log (struct evSubscrip *pevent)
dbChannelField(chan),
dbChannelFieldSize(chan));
} else {
- pLog->type = dbfl_type_rec;
+ rset *prset;
+
+ pLog->type = dbfl_type_ref;
+
+ if (dbChannelSpecial(chan) == SPC_DBADDR &&
+ (prset = dbGetRset(&chan->addr)) &&
+ prset->get_array_info)
+ /* This condition implies !use_val, see db_add_event */
+ {
+ void *pfieldsave = dbChannelField(chan);
+ prec = dbChannelRecord(chan);
+ prset->get_array_info(&chan->addr, &pLog->no_elements, &pLog->offset);
+ /* don't make a copy yet, just reference the field value */
+ pLog->u.r.field = dbChannelField(chan);
+ dbChannelField(chan) = pfieldsave;
+ }
+ else {
+ /* don't make a copy yet, just reference the field value */
+ pLog->u.r.field = dbChannelField(chan);
+ }
+ /* indicate field value still owned by record */
+ pLog->u.r.dtor = NULL;
+ /* no private data yet, may be set by a filter */
+ pLog->u.r.pvt = NULL;
}
}
return pLog;
}
/*
+ * DB_CREATE_EVENT_LOG()
+ *
+ * NOTE: This assumes that the db scan lock is already applied
+ * (as it calls rset->get_array_info)
+ */
+db_field_log* db_create_event_log (struct evSubscrip *pevent)
+{
+ db_field_log *pLog = db_create_field_log(pevent->chan, pevent->useValque);
+ if (pLog) {
+ pLog->ctx = dbfl_context_event;
+ }
+ return pLog;
+}
+
+/*
* DB_CREATE_READ_LOG()
*
*/
db_field_log* db_create_read_log (struct dbChannel *chan)
{
- db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
-
+ db_field_log *pLog = db_create_field_log(chan,
+ dbChannelElements(chan) == 1 &&
+ dbChannelSpecial(chan) != SPC_DBADDR &&
+ dbChannelFieldSize(chan) <= sizeof(union native_value));
if (pLog) {
pLog->ctx = dbfl_context_read;
- pLog->type = dbfl_type_rec;
}
return pLog;
}
@@ -724,20 +771,6 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
LOCKEVQUE (ev_que);
/*
- * if we have an event on the queue and both the last
- * event on the queue and the current event are emtpy
- * (i.e. of type dbfl_type_rec), simply ignore duplicate
- * events (saving empty events serves no purpose)
- */
- if (pevent->npend > 0u &&
- (*pevent->pLastLog)->type == dbfl_type_rec &&
- pLog->type == dbfl_type_rec) {
- db_delete_field_log(pLog);
- UNLOCKEVQUE (ev_que);
- return;
- }
-
- /*
* add to task local event que
*/
diff --git a/modules/database/src/ioc/db/dbEvent.h b/modules/database/src/ioc/db/dbEvent.h
index 374e849..175b0e4 100644
--- a/modules/database/src/ioc/db/dbEvent.h
+++ b/modules/database/src/ioc/db/dbEvent.h
@@ -50,6 +50,7 @@ epicsShareFunc int db_post_events (
typedef void * dbEventCtx;
typedef void EXTRALABORFUNC (void *extralabor_arg);
+void db_init_event_freelists (void);
epicsShareFunc dbEventCtx db_init_events (void);
epicsShareFunc int db_start_events (
dbEventCtx ctx, const char *taskname, void (*init_func)(void *),
diff --git a/modules/database/src/ioc/db/dbExtractArray.c b/modules/database/src/ioc/db/dbExtractArray.c
index e16ab4c..f0ab281 100644
--- a/modules/database/src/ioc/db/dbExtractArray.c
+++ b/modules/database/src/ioc/db/dbExtractArray.c
@@ -13,11 +13,12 @@
/*
* Author: Ralph Lange <Ralph.Lange at bessy.de>
*
- * based on dbConvert.c
+ * based on dbConvert.c, see copyNoConvert
* written by: Bob Dalesio, Marty Kraimer
*/
#include <string.h>
+#include <assert.h>
#include "epicsTypes.h"
@@ -25,61 +26,31 @@
#include "dbAddr.h"
#include "dbExtractArray.h"
-void dbExtractArrayFromRec(const dbAddr *paddr, void *pto,
- long nRequest, long no_elements, long offset, long increment)
+void dbExtractArray(const void *pfrom, void *pto,
+ short field_size, short field_type,
+ long nRequest, long no_elements, long offset, long increment)
{
char *pdst = (char *) pto;
- char *psrc = (char *) paddr->pfield;
- long nUpperPart;
- int i;
- short srcSize = paddr->field_size;
- short dstSize = srcSize;
- char isString = (paddr->field_type == DBF_STRING);
+ const char *psrc = (char *) pfrom;
- if (nRequest > no_elements) nRequest = no_elements;
- if (isString && srcSize > MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE;
+ /* assert preconditions */
+ assert(nRequest >= 0);
+ assert(no_elements >= 0);
+ assert(increment > 0);
+ assert(0 <= offset);
+ assert(offset < no_elements);
- if (increment == 1 && dstSize == srcSize) {
- nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset;
- memcpy(pdst, &psrc[offset * srcSize], dstSize * nUpperPart);
+ if (increment == 1) {
+ long nUpperPart =
+ nRequest < no_elements - offset ? nRequest : no_elements - offset;
+ memcpy(pdst, psrc + (offset * field_size), field_size * nUpperPart);
if (nRequest > nUpperPart)
- memcpy(&pdst[dstSize * nUpperPart], psrc, dstSize * (nRequest - nUpperPart));
- if (isString)
- for (i = 1; i <= nRequest; i++)
- pdst[dstSize*i-1] = '\0';
+ memcpy(pdst + (field_size * nUpperPart), psrc,
+ field_size * (nRequest - nUpperPart));
} else {
- for (; nRequest > 0; nRequest--, pdst += dstSize, offset += increment) {
+ for (; nRequest > 0; nRequest--, pdst += field_size, offset += increment) {
offset %= no_elements;
- memcpy(pdst, &psrc[offset*srcSize], dstSize);
- if (isString) pdst[dstSize-1] = '\0';
- }
- }
-}
-
-void dbExtractArrayFromBuf(const void *pfrom, void *pto,
- short field_size, short field_type,
- long nRequest, long no_elements, long offset, long increment)
-{
- char *pdst = (char *) pto;
- char *psrc = (char *) pfrom;
- int i;
- short srcSize = field_size;
- short dstSize = srcSize;
- char isString = (field_type == DBF_STRING);
-
- if (nRequest > no_elements) nRequest = no_elements;
- if (offset > no_elements - 1) offset = no_elements - 1;
- if (isString && dstSize >= MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE - 1;
-
- if (increment == 1) {
- memcpy(pdst, &psrc[offset * srcSize], dstSize * nRequest);
- if (isString)
- for (i = 1; i <= nRequest; i++)
- pdst[dstSize*i] = '\0';
- } else {
- for (; nRequest > 0; nRequest--, pdst += srcSize, offset += increment) {
- memcpy(pdst, &psrc[offset*srcSize], dstSize);
- if (isString) pdst[dstSize] = '\0';
+ memcpy(pdst, psrc + (offset * field_size), field_size);
}
}
}
diff --git a/modules/database/src/ioc/db/dbExtractArray.h b/modules/database/src/ioc/db/dbExtractArray.h
index 7ed3584..9680660 100644
--- a/modules/database/src/ioc/db/dbExtractArray.h
+++ b/modules/database/src/ioc/db/dbExtractArray.h
@@ -21,11 +21,22 @@
extern "C" {
#endif
-epicsShareFunc void dbExtractArrayFromRec(const DBADDR *paddr, void *pto,
- long nRequest, long no_elements, long offset, long increment);
-epicsShareFunc void dbExtractArrayFromBuf(const void *pfrom, void *pto,
- short field_size, short field_type,
- long nRequest, long no_elements, long offset, long increment);
+/*
+ * This function does not do any conversion. This means we don't have to
+ * truncate the field_size to MAX_STRING_SIZE or add extra null terminators
+ * for string values. All of this is done by the dbConvert routines which
+ * will be called whether or not a filter is active.
+ *
+ * Checked preconditions:
+ * - nRequest >= 0, no_elements >= 0, increment > 0
+ * - 0 <= offset < no_elements
+ * Unchecked preconditions:
+ * - pto points to a buffer with at least field_size*nRequest bytes
+ * - pfrom points to a buffer with at least field_size*no_elements bytes
+ */
+epicsShareFunc void dbExtractArray(const void *pfrom, void *pto,
+ short field_size, short field_type,
+ long nRequest, long no_elements, long offset, long increment);
#ifdef __cplusplus
}
diff --git a/modules/database/src/ioc/db/dbLink.c b/modules/database/src/ioc/db/dbLink.c
index 7c37058..aa72dc8 100644
--- a/modules/database/src/ioc/db/dbLink.c
+++ b/modules/database/src/ioc/db/dbLink.c
@@ -143,7 +143,7 @@ void dbInitLink(struct link *plink, short dbfType)
}
void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
- DBADDR *ptarget)
+ dbChannel *ptarget)
{
struct dbCommon *precord = plink->precord;
diff --git a/modules/database/src/ioc/db/dbLink.h b/modules/database/src/ioc/db/dbLink.h
index 94e1f32..4255a56 100644
--- a/modules/database/src/ioc/db/dbLink.h
+++ b/modules/database/src/ioc/db/dbLink.h
@@ -20,6 +20,7 @@
#include "epicsTypes.h"
#include "epicsTime.h"
#include "dbAddr.h"
+#include "dbChannel.h"
#ifdef __cplusplus
extern "C" {
@@ -368,7 +369,7 @@ epicsShareFunc const char * dbLinkFieldName(const struct link *plink);
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
- short dbfType, DBADDR *ptarget);
+ short dbfType, dbChannel *ptarget);
epicsShareFunc void dbLinkOpen(struct link *plink);
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
diff --git a/modules/database/src/ioc/db/dbLock.c b/modules/database/src/ioc/db/dbLock.c
index 8df755b..19cb1c0 100644
--- a/modules/database/src/ioc/db/dbLock.c
+++ b/modules/database/src/ioc/db/dbLock.c
@@ -743,14 +743,14 @@ void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
for(i=0; i<rtype->no_links; i++) {
dbFldDes *pdesc = rtype->papFldDes[rtype->link_ind[i]];
DBLINK *plink = (DBLINK*)((char*)prec + pdesc->offset);
- DBADDR *ptarget;
+ dbChannel *chan;
lockRecord *lr;
if(plink->type!=DB_LINK)
continue;
- ptarget = plink->value.pv_link.pvt;
- lr = ptarget->precord->lset;
+ chan = plink->value.pv_link.pvt;
+ lr = dbChannelRecord(chan)->lset;
assert(lr);
if(lr->precord==pfirst) {
diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c
index 1193954..206d6c9 100644
--- a/modules/database/src/ioc/db/dbTest.c
+++ b/modules/database/src/ioc/db/dbTest.c
@@ -341,14 +341,14 @@ long dbgf(const char *pname)
no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size);
if (addr.dbr_field_type == DBR_ENUM) {
long status = dbGetField(&addr, DBR_STRING, pbuffer,
- &options, &no_elements, NULL);
+ &options, &no_elements);
printBuffer(status, DBR_STRING, pbuffer, 0L, 0L,
no_elements, &msg_Buff, 10);
}
else {
long status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
- &options, &no_elements, NULL);
+ &options, &no_elements);
printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
no_elements, &msg_Buff, 10);
@@ -487,7 +487,7 @@ long dbtgf(const char *pname)
ret_options = req_options;
no_elements = 0;
status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
- &ret_options, &no_elements, NULL);
+ &ret_options, &no_elements);
printBuffer(status, addr.dbr_field_type, pbuffer,
req_options, ret_options, no_elements, pMsgBuff, tab_size);
@@ -496,62 +496,62 @@ long dbtgf(const char *pname)
dbr_type = DBR_STRING;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_CHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UCHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_SHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_USHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_LONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ULONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_INT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UINT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_FLOAT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_DOUBLE;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ENUM;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
pmsg[0] = '\0';
@@ -651,7 +651,7 @@ long dbtpf(const char *pname, const char *pvalue)
printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]);
status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
- &options, &no_elements, NULL);
+ &options, &no_elements);
printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
no_elements, pMsgBuff, tab_size);
}
diff --git a/modules/database/src/ioc/db/dbUnitTest.c b/modules/database/src/ioc/db/dbUnitTest.c
index 6846ef5..458a28b 100644
--- a/modules/database/src/ioc/db/dbUnitTest.c
+++ b/modules/database/src/ioc/db/dbUnitTest.c
@@ -197,7 +197,7 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
return;
}
- status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL);
+ status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));
return;
@@ -270,7 +270,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
return;
}
- status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL);
+ status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status);
diff --git a/modules/database/src/ioc/db/db_field_log.h b/modules/database/src/ioc/db/db_field_log.h
index 1534517..4b3b82d 100644
--- a/modules/database/src/ioc/db/db_field_log.h
+++ b/modules/database/src/ioc/db/db_field_log.h
@@ -56,20 +56,31 @@ union native_value {
struct db_field_log;
typedef void (dbfl_freeFunc)(struct db_field_log *pfl);
-/* Types of db_field_log: rec = use record, val = val inside, ref = reference inside */
+/*
+ * A db_field_log has one of two types:
+ *
+ * dbfl_type_ref - Reference to value
+ * Used for variable size (array) data types. Meta-data
+ * is stored in the field log, but value data is stored externally.
+ * Only the dbfl_ref side of the data union is valid.
+ *
+ * dbfl_type_val - Internal value
+ * Used to store small scalar data. Meta-data and value are
+ * present in this structure and no external references are used.
+ * Only the dbfl_val side of the data union is valid.
+ */
typedef enum dbfl_type {
- dbfl_type_rec = 0,
dbfl_type_val,
dbfl_type_ref
} dbfl_type;
/* Context of db_field_log: event = subscription update, read = read reply */
typedef enum dbfl_context {
- dbfl_context_read = 0,
+ dbfl_context_read,
dbfl_context_event
} dbfl_context;
-#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref")
+#define dbflTypeStr(t) (t==dbfl_type_val?"val":"ref")
struct dbfl_val {
union native_value field; /* Field value */
@@ -81,6 +92,8 @@ struct dbfl_val {
* db_delete_field_log(). Any code which changes a dbfl_type_ref
* field log to another type, or to reference different data,
* must explicitly call the dtor function.
+ * If the dtor is NULL, then this means the array data is still owned
+ * by a record.
*/
struct dbfl_ref {
dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
@@ -88,8 +101,17 @@ struct dbfl_ref {
void *field; /* Field value */
};
+/*
+ * Note: The offset member is understood to apply an implicit index mapping
+ *
+ * i' = (i + offset) % no_elements
+ *
+ * of request index i. The resulting i' is used to to index into u.r.field.
+ *
+ * Also note that field_size may be larger than MAX_STRING_SIZE.
+ */
typedef struct db_field_log {
- unsigned int type:2; /* type (union) selector */
+ unsigned int type:1; /* type (union) selector */
/* ctx is used for all types */
unsigned int ctx:1; /* context (operation type) */
/* the following are used for value and reference types */
@@ -97,37 +119,15 @@ typedef struct db_field_log {
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
short field_type; /* DBF type of data */
- short field_size; /* Data size */
- long no_elements; /* No of array elements */
+ short field_size; /* Size of a single element */
+ long no_elements; /* No of valid array elements */
+ long offset; /* See above */
union {
struct dbfl_val v;
struct dbfl_ref r;
} u;
} db_field_log;
-/*
- * A db_field_log will in one of three types:
- *
- * dbfl_type_rec - Reference to record
- * The field log stores no data itself. Data must instead be taken
- * via the dbChannel* which must always be provided when along
- * with the field log.
- * For this type only the 'type' and 'ctx' members are used.
- *
- * dbfl_type_ref - Reference to outside value
- * Used for variable size (array) data types. Meta-data
- * is stored in the field log, but value data is stored externally
- * (see struct dbfl_ref).
- * For this type all meta-data members are used. The dbfl_ref side of the
- * data union is used.
- *
- * dbfl_type_val - Internal value
- * Used to store small scalar data. Meta-data and value are
- * present in this structure and no external references are used.
- * For this type all meta-data members are used. The dbfl_val side of the
- * data union is used.
- */
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/database/src/std/dev/devAiSoft.c b/modules/database/src/std/dev/devAiSoft.c
index 0ecc1b1..5f9923e 100644
--- a/modules/database/src/std/dev/devAiSoft.c
+++ b/modules/database/src/std/dev/devAiSoft.c
@@ -96,9 +96,10 @@ static long read_ai(aiRecord *prec)
prec->udf = FALSE;
prec->dpvt = &devAiSoft; /* Any non-zero value */
+ return 2;
}
else
prec->dpvt = NULL;
- return 2;
+ return status;
}
diff --git a/modules/database/src/std/filters/arr.c b/modules/database/src/std/filters/arr.c
index f91708a..b90335e 100644
--- a/modules/database/src/std/filters/arr.c
+++ b/modules/database/src/std/filters/arr.c
@@ -12,16 +12,13 @@
#include <stdio.h>
-#include <freeList.h>
-#include <dbAccess.h>
-#include <dbExtractArray.h>
-#include <db_field_log.h>
-#include <dbLock.h>
-#include <recSup.h>
-#include <epicsExit.h>
-#include <special.h>
-#include <chfPlugin.h>
-#include <epicsExport.h>
+#include "chfPlugin.h"
+#include "dbExtractArray.h"
+#include "db_field_log.h"
+#include "dbLock.h"
+#include "epicsExit.h"
+#include "freeList.h"
+#include "epicsExport.h"
typedef struct myStruct {
epicsInt32 start;
@@ -45,6 +42,8 @@ static void * allocPvt(void)
myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
if (!my) return NULL;
+ /* defaults */
+ my->start = 0;
my->incr = 1;
my->end = -1;
return (void *) my;
@@ -93,78 +92,61 @@ static long wrapArrayIndices(long *start, const long increment, long *end,
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
{
myStruct *my = (myStruct*) pvt;
- struct dbCommon *prec;
- rset *prset;
+ int must_lock;
long start = my->start;
long end = my->end;
- long nTarget = 0;
- long offset = 0;
- long nSource = dbChannelElements(chan);
- long capacity = nSource;
- void *pdst;
+ long nTarget;
+ void *pTarget;
+ /* initial values for the source array */
+ long offset = pfl->offset;
+ long nSource = pfl->no_elements;
switch (pfl->type) {
case dbfl_type_val:
- /* Only filter arrays */
+ /* TODO Treat scalars as arrays with 1 element */
break;
- case dbfl_type_rec:
- /* Extract from record */
- if (dbChannelSpecial(chan) == SPC_DBADDR &&
- nSource > 1 &&
- (prset = dbGetRset(&chan->addr)) &&
- prset->get_array_info)
- {
- void *pfieldsave = dbChannelField(chan);
- prec = dbChannelRecord(chan);
- dbScanLock(prec);
- prset->get_array_info(&chan->addr, &nSource, &offset);
- nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
- pfl->type = dbfl_type_ref;
- pfl->stat = prec->stat;
- pfl->sevr = prec->sevr;
- pfl->time = prec->time;
- pfl->field_type = dbChannelFieldType(chan);
- pfl->field_size = dbChannelFieldSize(chan);
- pfl->no_elements = nTarget;
- if (nTarget) {
- pdst = freeListCalloc(my->arrayFreeList);
- if (pdst) {
- pfl->u.r.dtor = freeArray;
- pfl->u.r.pvt = my->arrayFreeList;
- offset = (offset + start) % dbChannelElements(chan);
- dbExtractArrayFromRec(&chan->addr, pdst, nTarget, capacity,
- offset, my->incr);
- pfl->u.r.field = pdst;
- }
- }
- dbScanUnlock(prec);
- dbChannelField(chan) = pfieldsave;
- }
- break;
-
- /* Extract from buffer */
case dbfl_type_ref:
- pdst = NULL;
- nSource = pfl->no_elements;
+ must_lock = !pfl->u.r.dtor;
+ if (must_lock)
+ dbScanLock(dbChannelRecord(chan));
nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
- pfl->no_elements = nTarget;
- if (nTarget) {
- /* Copy the data out */
- void *psrc = pfl->u.r.field;
-
- pdst = freeListCalloc(my->arrayFreeList);
- if (!pdst) break;
- offset = start;
- dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type,
- nTarget, nSource, offset, my->incr);
- }
- if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
- if (nTarget) {
+ /*
+ * Side note: it would be nice if we could avoid the copying in
+ * the case of my->incr==1. This is currently not possible due to
+ * the way the offset member is interpreted (namely as shifting the
+ * array in a ring-buffer style).
+ */
+ if (nTarget > 0) {
+ /* copy the data */
+ void *pSource = pfl->u.r.field;
+ pTarget = freeListCalloc(my->arrayFreeList);
+ if (!pTarget) break;
+ offset = (offset + start) % nSource;
+ dbExtractArray(pSource, pTarget, pfl->field_size,
+ pfl->field_type, nTarget, nSource, offset, my->incr);
+ if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
+ pfl->u.r.field = pTarget;
pfl->u.r.dtor = freeArray;
pfl->u.r.pvt = my->arrayFreeList;
- pfl->u.r.field = pdst;
}
+ /* adjust offset and no_elements to refer to the new pTarget */
+ pfl->offset = 0;
+ /*
+ * Setting pfl->no_elements outside of the "if" clause above is
+ * done to make requests fail if nTarget is zero, that is, if all
+ * elements selected by the filter are outside the array bounds.
+ * TODO:
+ * It would be possible to lift this restriction by interpreting
+ * a request with *no* number of elements (NULL pointer) as scalar
+ * (meaning: fail if we get less than one element); in contrast,
+ * a request that explicitly specifies one element would be
+ * interpreted as an array request, for which zero elements would
+ * be a normal expected result.
+ */
+ pfl->no_elements = nTarget;
+ if (must_lock)
+ dbScanUnlock(dbChannelRecord(chan));
break;
}
return pfl;
diff --git a/modules/database/src/std/filters/ts.c b/modules/database/src/std/filters/ts.c
index 5925b0b..56c9f5b 100644
--- a/modules/database/src/std/filters/ts.c
+++ b/modules/database/src/std/filters/ts.c
@@ -11,21 +11,39 @@
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-#include <chfPlugin.h>
-#include <dbLock.h>
-#include <db_field_log.h>
-#include <epicsExport.h>
+#include "chfPlugin.h"
+#include "db_field_log.h"
+#include "dbLock.h"
+#include "epicsExport.h"
+
+/*
+ * The size of the data is different for each channel, and can even
+ * change at runtime, so a freeList doesn't make much sense here.
+ */
+static void freeArray(db_field_log *pfl) {
+ free(pfl->u.r.field);
+}
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
epicsTimeStamp now;
epicsTimeGetCurrent(&now);
- /* If string or array, must make a copy (to ensure coherence between time and data) */
- if (pfl->type == dbfl_type_rec) {
- dbScanLock(dbChannelRecord(chan));
- dbChannelMakeArrayCopy(pvt, pfl, chan);
- dbScanUnlock(dbChannelRecord(chan));
+ /* If reference and not already copied,
+ must make a copy (to ensure coherence between time and data) */
+ if (pfl->type == dbfl_type_ref && !pfl->u.r.dtor) {
+ void *pTarget = calloc(pfl->no_elements, pfl->field_size);
+ void *pSource = pfl->u.r.field;
+ if (pTarget) {
+ dbScanLock(dbChannelRecord(chan));
+ memcpy(pTarget, pSource, pfl->field_size * pfl->no_elements);
+ pfl->u.r.field = pTarget;
+ pfl->u.r.dtor = freeArray;
+ pfl->u.r.pvt = pvt;
+ dbScanUnlock(dbChannelRecord(chan));
+ }
}
pfl->time = now;
diff --git a/modules/database/test/ioc/db/dbChArrTest.cpp b/modules/database/test/ioc/db/dbChArrTest.cpp
index 8255fdc..ff74e01 100644
--- a/modules/database/test/ioc/db/dbChArrTest.cpp
+++ b/modules/database/test/ioc/db/dbChArrTest.cpp
@@ -130,7 +130,7 @@ static void check(short dbr_type) {
memset(buf, 0, sizeof(buf)); \
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
pfl = db_create_read_log(pch); \
- testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \
+ testOk(pfl && pfl->type == dbfl_type_ref, "Valid pfl, type = ref"); \
testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
@@ -178,6 +178,7 @@ static void check(short dbr_type) {
pfl->field_type = DBF_CHAR; \
pfl->field_size = 1; \
pfl->no_elements = 26; \
+ pfl->offset = 0; \
pfl->u.r.dtor = freeArray; \
pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \
testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
diff --git a/modules/database/test/std/filters/arrTest.cpp b/modules/database/test/std/filters/arrTest.cpp
index 1ec16b3..08ba07b 100644
--- a/modules/database/test/std/filters/arrTest.cpp
+++ b/modules/database/test/std/filters/arrTest.cpp
@@ -56,25 +56,26 @@ const char *server_port = CA_SERVER_PORT;
static int fl_equals_array(short type, const db_field_log *pfl1, void *p2) {
for (int i = 0; i < pfl1->no_elements; i++) {
+ int j = (i + pfl1->offset) % pfl1->no_elements;
switch (type) {
case DBR_DOUBLE:
- if (((epicsFloat64*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {
+ if (((epicsFloat64*)pfl1->u.r.field)[j] != ((epicsInt32*)p2)[i]) {
testDiag("at index=%d: field log has %g, should be %d",
- i, ((epicsFloat64*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]);
+ i, ((epicsFloat64*)pfl1->u.r.field)[j], ((epicsInt32*)p2)[i]);
return 0;
}
break;
case DBR_LONG:
- if (((epicsInt32*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {
+ if (((epicsInt32*)pfl1->u.r.field)[j] != ((epicsInt32*)p2)[i]) {
testDiag("at index=%d: field log has %d, should be %d",
- i, ((epicsInt32*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]);
+ i, ((epicsInt32*)pfl1->u.r.field)[j], ((epicsInt32*)p2)[i]);
return 0;
}
break;
case DBR_STRING:
- if (strtol(&((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], NULL, 0) != ((epicsInt32*)p2)[i]) {
+ if (strtol(&((const char*)pfl1->u.r.field)[j*pfl1->field_size], NULL, 0) != ((epicsInt32*)p2)[i]) {
testDiag("at index=%d: field log has '%s', should be '%d'",
- i, &((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], ((epicsInt32*)p2)[i]);
+ i, &((const char*)pfl1->u.r.field)[j*pfl1->field_size], ((epicsInt32*)p2)[i]);
return 0;
}
break;
@@ -119,7 +120,7 @@ static void testHead (const char *title, const char *typ = "") {
off = Offset; \
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
pfl = db_create_read_log(pch); \
- testOk(pfl->type == dbfl_type_rec, "original field log has type rec"); \
+ testOk(pfl->type == dbfl_type_ref, "original field log has type ref"); \
pfl2 = dbChannelRunPostChain(pch, pfl); \
testOk(pfl2 == pfl, "call does not drop or replace field_log"); \
testOk(pfl->type == dbfl_type_ref, "filtered field log has type ref"); \
diff --git a/modules/database/test/std/filters/dbndTest.c b/modules/database/test/std/filters/dbndTest.c
index 4d70f83..fd4a472 100644
--- a/modules/database/test/std/filters/dbndTest.c
+++ b/modules/database/test/std/filters/dbndTest.c
@@ -129,7 +129,7 @@ MAIN(dbndTest)
dbEventCtx evtctx;
int logsFree, logsFinal;
- testPlan(77);
+ testPlan(72);
testdbPrepare();
@@ -170,12 +170,9 @@ MAIN(dbndTest)
"dbnd has one filter with argument in pre chain");
testOk((ellCount(&pch->post_chain) == 0), "dbnd has no filter in post chain");
- /* Field logs of type ref and rec: pass any update */
-
- testHead("Field logs of type ref and rec");
- fl1.type = dbfl_type_rec;
- mustPassTwice(pch, &fl1, "abs field_log=rec", 0., 0);
+ /* Field logs of type ref: pass any update */
+ testHead("Field logs of type ref");
fl1.type = dbfl_type_ref;
mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0);
diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile
index 8c087b3..3d7cff9 100644
--- a/modules/database/test/std/rec/Makefile
+++ b/modules/database/test/std/rec/Makefile
@@ -156,6 +156,13 @@ asyncproctest_SRCS += asyncproctest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db
TESTS += asyncproctest
+TESTPROD_HOST += linkFilterTest
+linkFilterTest_SRCS += linkFilterTest.c
+linkFilterTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
+testHarness_SRCS += linkFilterTest.c
+TESTFILES += ../linkFilterTest.db
+TESTS += linkFilterTest
+
# dbHeader* is only a compile test
# no need to actually run
TESTPROD += dbHeaderTest
diff --git a/modules/database/test/std/rec/linkFilterTest.c b/modules/database/test/std/rec/linkFilterTest.c
new file mode 100644
index 0000000..6f38d24
--- /dev/null
+++ b/modules/database/test/std/rec/linkFilterTest.c
@@ -0,0 +1,157 @@
+/*************************************************************************\
+* Copyright (c) 2020 Dirk Zimoch
+* 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 "devSup.h"
+#include "alarm.h"
+#include "dbUnitTest.h"
+#include "errlog.h"
+#include "epicsThread.h"
+
+#include "longinRecord.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 expectProcSuccess(const char *rec)
+{
+ char fieldname[20];
+ testDiag("expecting success from %s", rec);
+ sprintf(fieldname, "%s.PROC", rec);
+ testdbPutFieldOk(fieldname, DBF_LONG, 1);
+ sprintf(fieldname, "%s.SEVR", rec);
+ testdbGetFieldEqual(fieldname, DBF_LONG, NO_ALARM);
+ sprintf(fieldname, "%s.STAT", rec);
+ testdbGetFieldEqual(fieldname, DBF_LONG, NO_ALARM);
+}
+
+static void expectProcFailure(const char *rec)
+{
+ char fieldname[20];
+ testDiag("expecting failure S_db_badField %#x from %s", S_db_badField, rec);
+ sprintf(fieldname, "%s.PROC", rec);
+ testdbPutFieldFail(S_db_badField, fieldname, DBF_LONG, 1);
+ sprintf(fieldname, "%s.SEVR", rec);
+ testdbGetFieldEqual(fieldname, DBF_LONG, INVALID_ALARM);
+ sprintf(fieldname, "%s.STAT", rec);
+ testdbGetFieldEqual(fieldname, DBF_LONG, LINK_ALARM);
+}
+
+static void changeRange(long start, long stop, long step)
+{
+ char linkstring[60];
+ if (step)
+ sprintf(linkstring, "src.[%ld:%ld:%ld]", start, step, stop);
+ else if (stop)
+ sprintf(linkstring, "src.[%ld:%ld]", start, stop);
+ else
+ sprintf(linkstring, "src.[%ld]", start);
+ testDiag("modifying link: %s", linkstring);
+ testdbPutFieldOk("ai.INP", DBF_STRING, linkstring);
+ testdbPutFieldOk("wf.INP", DBF_STRING, linkstring);
+}
+
+static double buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 2, 4, 6};
+
+static void expectRange(long start, long end)
+{
+ long n = end-start+1;
+ testdbGetFieldEqual("ai.VAL", DBF_DOUBLE, buf[start]);
+ testdbGetFieldEqual("wf.NORD", DBF_LONG, n);
+ testdbGetArrFieldEqual("wf.VAL", DBF_DOUBLE, n+2, n, buf+start);
+}
+
+#if 0
+static void expectEmptyArray(void)
+{
+ /* empty arrays are now allowed at the moment */
+ testDiag("expecting empty array");
+ testdbGetFieldEqual("wf.NORD", DBF_LONG, 0);
+}
+#endif
+
+MAIN(linkFilterTest)
+{
+ testPlan(98);
+ startTestIoc("linkFilterTest.db");
+
+ testDiag("PINI");
+ expectRange(2,4);
+
+ testDiag("modify range");
+ changeRange(3,6,0);
+ expectProcSuccess("ai");
+ expectProcSuccess("wf");
+ expectRange(3,6);
+
+ testDiag("backward range");
+ changeRange(5,3,0);
+ expectProcFailure("ai");
+ expectProcFailure("wf");
+
+ testDiag("step 2");
+ changeRange(1,6,2);
+ expectProcSuccess("ai");
+ expectProcSuccess("wf");
+ expectRange(10,12);
+
+ testDiag("range start beyond src.NORD");
+ changeRange(8,9,0);
+ expectProcFailure("ai");
+ expectProcFailure("wf");
+
+ testDiag("range end beyond src.NORD");
+ changeRange(3,9,0);
+ expectProcSuccess("ai");
+ expectProcSuccess("wf");
+ expectRange(3,7); /* clipped range */
+
+ testDiag("range start beyond src.NELM");
+ changeRange(11,12,0);
+ expectProcFailure("ai");
+ expectProcFailure("wf");
+
+ testDiag("range end beyond src.NELM");
+ changeRange(4,12,0);
+ expectProcSuccess("ai");
+ expectProcSuccess("wf");
+ expectRange(4,7); /* clipped range */
+
+ testDiag("single value beyond src.NORD");
+ changeRange(8,0,0);
+ expectProcFailure("ai");
+ expectProcFailure("wf");
+
+ testDiag("single value");
+ changeRange(5,0,0);
+ expectProcSuccess("ai");
+ expectProcSuccess("wf");
+ expectRange(5,5);
+
+ testDiag("single beyond rec.NELM");
+ changeRange(12,0,0);
+ expectProcFailure("ai");
+ expectProcFailure("wf");
+
+ testIocShutdownOk();
+ testdbCleanup();
+ return testDone();
+}
diff --git a/modules/database/test/std/rec/linkFilterTest.db b/modules/database/test/std/rec/linkFilterTest.db
new file mode 100644
index 0000000..5ee371e
--- /dev/null
+++ b/modules/database/test/std/rec/linkFilterTest.db
@@ -0,0 +1,16 @@
+record(waveform, "src") {
+ field(NELM, "10")
+ field(FTVL, "SHORT")
+ field(INP, [1, 2, 3, 4, 5, 6, 7, 8])
+}
+record(ai, "ai") {
+ field(INP, "src.[2]") # expect 3
+ field(PINI, "YES")
+}
+record(waveform, "wf") {
+ field(NELM, "5")
+ field(FTVL, "DOUBLE")
+ field(INP, "src.[2:4]") # expect 3,4,5
+ field(PINI, "YES")
+}
+
diff --git a/modules/database/test/std/rec/regressTest.c b/modules/database/test/std/rec/regressTest.c
index 6614639..fd4f0a8 100644
--- a/modules/database/test/std/rec/regressTest.c
+++ b/modules/database/test/std/rec/regressTest.c
@@ -132,7 +132,7 @@ void testCADisconn(void)
startRegressTestIoc("badCaLink.db");
- testdbPutFieldOk("ai:disconn.PROC", DBF_LONG, 1);
+ testdbPutFieldFail(-1, "ai:disconn.PROC", DBF_LONG, 1);
testdbGetFieldEqual("ai:disconn.SEVR", DBF_LONG, INVALID_ALARM);
testdbGetFieldEqual("ai:disconn.STAT", DBF_LONG, LINK_ALARM);
}
- Replies:
- Re: [Merge] ~bfrk/epics-base:write-filters into epics-base:7.0 Ben Franksen via Core-talk
- [Merge] ~bfrk/epics-base:write-filters into epics-base:7.0 Ben Franksen via Core-talk
- Navigate by Date:
- Prev:
Re: write to a single element of an array field Johnson, Andrew N. via Core-talk
- Next:
Re: [Merge] ~bfrk/epics-base:write-filters into epics-base:7.0 Ben Franksen via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
[Bug 1868680] Re: Access Security file reload (asInit) fails Andrew Johnson via Core-talk
- Next:
Re: [Merge] ~bfrk/epics-base:write-filters into epics-base:7.0 Ben Franksen via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024