Experimental Physics and Industrial Control System
mdavidsaver has proposed merging lp:~epics-core/epics-base/server-side-plugins into lp:epics-base.
Requested reviews:
Ralph Lange (ralph-lange)
EPICS Core Developers (epics-core)
For more details, see:
https://code.launchpad.net/~epics-core/epics-base/server-side-plugins/+merge/108028
This branch takes the changes from
lp:~ralph-lange/epics-base/server-side-plugins
And updates them to the current 3.15 branch. So when reviewing the changes please check also for unintentionally reverted changes from the 3.15 branch.
--
The attached diff has been truncated due to its size.
https://code.launchpad.net/~epics-core/epics-base/server-side-plugins/+merge/108028
Your team EPICS Core Developers is requested to review the proposed merge of lp:~epics-core/epics-base/server-side-plugins into lp:epics-base.
=== modified file '.bzrignore'
--- .bzrignore 2009-12-23 21:06:44 +0000
+++ .bzrignore 2012-05-30 18:10:27 +0000
@@ -6,3 +6,6 @@
./include
./templates
**/O.*
+./.cproject
+./.project
+./.settings
=== modified file 'configure/RULES.Db'
--- configure/RULES.Db 2012-05-29 21:44:49 +0000
+++ configure/RULES.Db 2012-05-30 18:10:27 +0000
@@ -397,12 +397,12 @@
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
@$(RM) $@ $*.tmp
- $(REGISTERRECORDDEVICEDRIVER) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
+ $(REGISTERRECORDDEVICEDRIVER) $(DBDFLAGS) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
$(MV) $*.tmp $@
%_registerRecordDeviceDriver.cpp: %.dbd
@$(RM) $@ $*.tmp
- $(REGISTERRECORDDEVICEDRIVER) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
+ $(REGISTERRECORDDEVICEDRIVER) $(DBDFLAGS) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
$(MV) $*.tmp $@
.PRECIOUS: %_registerRecordDeviceDriver.cpp
=== modified file 'src/Makefile'
--- src/Makefile 2012-03-14 20:27:40 +0000
+++ src/Makefile 2012-05-30 18:10:27 +0000
@@ -69,6 +69,10 @@
DIRS += std
std_DEPEND_DIRS = ioc libCom/RTEMS
+DIRS += ioc/db/filters/test
+ioc/db/filters/test_DEPEND_DIRS = ioc std libCom/RTEMS
+
+
include $(TOP)/configure/RULES_DIRS
=== modified file 'src/ioc/as/asDbLib.c'
--- src/ioc/as/asDbLib.c 2012-05-03 17:19:34 +0000
+++ src/ioc/as/asDbLib.c 2012-05-30 18:10:27 +0000
@@ -6,7 +6,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 02-11-94*/
@@ -27,7 +27,7 @@
#include "caeventmask.h"
#include "callback.h"
#include "dbStaticLib.h"
-#include "dbAddr.h"
+#include "dbChannel.h"
#include "dbAccess.h"
#include "db_field_log.h"
#include "dbEvent.h"
@@ -40,7 +40,7 @@
static char *psubstitutions=NULL;
static epicsThreadId asInitTheadId=0;
static int firstTime = TRUE;
-
+
static long asDbAddRecords(void)
{
DBENTRY dbentry;
@@ -98,7 +98,7 @@
}
return(0);
}
-
+
static void asSpcAsCallback(struct dbCommon *precord)
{
asChangeGroup(&precord->asp, precord->asg);
@@ -109,7 +109,7 @@
int *firstTime = (int *)arg;
*firstTime = FALSE;
}
-
+
static long asInitCommon(void)
{
long status;
@@ -117,7 +117,7 @@
int wasFirstTime = firstTime;
static epicsThreadOnceId asInitCommonOnceFlag = EPICS_THREAD_ONCE_INIT;
-
+
epicsThreadOnce(&asInitCommonOnceFlag,asInitCommonOnce,(void *)&firstTime);
if(wasFirstTime) {
if(!pacf) return(0); /*access security will NEVER be turned on*/
@@ -148,7 +148,7 @@
{
return(asInitCommon());
}
-
+
static void wdCallback(void *arg)
{
ASDBCALLBACK *pcallback = (ASDBCALLBACK *)arg;
@@ -195,23 +195,15 @@
}
return(0);
}
-
-int epicsShareAPI asDbGetAsl(void *paddress)
+
+int epicsShareAPI asDbGetAsl(struct dbChannel *chan)
{
- DBADDR *paddr = paddress;
- dbFldDes *pflddes;
-
- pflddes = paddr->pfldDes;
- return((int)pflddes->as_level);
+ return dbChannelFldDes(chan)->as_level;
}
-void * epicsShareAPI asDbGetMemberPvt(void *paddress)
+void * epicsShareAPI asDbGetMemberPvt(struct dbChannel *chan)
{
- DBADDR *paddr = paddress;
- dbCommon *precord;
-
- precord = paddr->precord;
- return((void *)precord->asp);
+ return dbChannelRecord(chan)->asp;
}
static void astacCallback(ASCLIENTPVT clientPvt,asClientStatus status)
@@ -259,7 +251,7 @@
}
return(0);
}
-
+
static void myMemberCallback(ASMEMBERPVT memPvt,FILE *fp)
{
dbCommon *precord;
=== modified file 'src/ioc/as/asDbLib.h'
--- src/ioc/as/asDbLib.h 2010-10-05 19:27:37 +0000
+++ src/ioc/as/asDbLib.h 2012-05-30 18:10:27 +0000
@@ -5,12 +5,12 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* share/epicsH/dbAsLib.h */
/* $Revision-Id$ */
/* Author: Marty Kraimer Date: 02-23-94*/
-
+
#ifndef INCdbAsLibh
#define INCdbAsLibh
@@ -22,6 +22,8 @@
long status;
} ASDBCALLBACK;
+struct dbChannel;
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -30,8 +32,8 @@
epicsShareFunc int epicsShareAPI asSetSubstitutions(const char *substitutions);
epicsShareFunc int epicsShareAPI asInit(void);
epicsShareFunc int epicsShareAPI asInitAsyn(ASDBCALLBACK *pcallback);
-epicsShareFunc int epicsShareAPI asDbGetAsl( void *paddr);
-epicsShareFunc void * epicsShareAPI asDbGetMemberPvt( void *paddr);
+epicsShareFunc int epicsShareAPI asDbGetAsl(struct dbChannel *chan);
+epicsShareFunc void * epicsShareAPI asDbGetMemberPvt(struct dbChannel *chan);
epicsShareFunc int epicsShareAPI asdbdump(void);
epicsShareFunc int epicsShareAPI asdbdumpFP(FILE *fp);
epicsShareFunc int epicsShareAPI aspuag(const char *uagname);
=== modified file 'src/ioc/db/Makefile'
--- src/ioc/db/Makefile 2011-11-14 23:38:36 +0000
+++ src/ioc/db/Makefile 2012-05-30 18:10:27 +0000
@@ -17,9 +17,12 @@
INC += dbCa.h
INC += dbAddr.h
INC += dbBkpt.h
+INC += dbChannel.h
INC += dbConvert.h
INC += dbConvertFast.h
+INC += dbExtractArray.h
INC += dbEvent.h
+INC += dbLink.h
INC += dbLock.h
INC += dbNotify.h
INC += dbScan.h
@@ -30,6 +33,8 @@
INC += initHooks.h
INC += recGbl.h
INC += dbIocRegister.h
+INC += chfPlugin.h
+INC += dbState.h
INC += db_access_routines.h
INC += db_convert.h
@@ -50,11 +55,17 @@
DBDINC += $(basename $(menuGlobal_DBD))
DBDINC += dbCommon
+DBD_INSTALLS += ../db/filters/filters.dbd
+
+
dbCore_SRCS += dbLock.c
dbCore_SRCS += dbAccess.c
dbCore_SRCS += dbBkpt.c
+dbCore_SRCS += dbChannel.c
dbCore_SRCS += dbConvert.c
dbCore_SRCS += dbFastLinkConv.c
+dbCore_SRCS += dbExtractArray.c
+dbCore_SRCS += dbLink.c
dbCore_SRCS += dbNotify.c
dbCore_SRCS += dbScan.c
dbCore_SRCS += dbEvent.c
@@ -74,4 +85,13 @@
dbCore_SRCS += dbContextReadNotifyCache.cpp
dbCore_SRCS += templateInstances.cpp
dbCore_SRCS += dbIocRegister.c
+dbCore_SRCS += chfPlugin.c
+dbCore_SRCS += dbState.c
+
+SRC_DIRS += $(IOCDIR)/db/filters
+
+dbCore_SRCS += ts.c
+dbCore_SRCS += dbnd.c
+dbCore_SRCS += arr.c
+dbCore_SRCS += sync.c
=== added file 'src/ioc/db/chfPlugin.c'
--- src/ioc/db/chfPlugin.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/chfPlugin.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,641 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+
+#include <dbDefs.h>
+#include <dbStaticLib.h>
+#include <epicsTypes.h>
+#include <epicsString.h>
+#include <errlog.h>
+#include <shareLib.h>
+
+#define epicsExportSharedSymbols
+#include "chfPlugin.h"
+
+#ifndef HUGE_VALF
+# define HUGE_VALF HUGE_VAL
+#endif
+#ifndef HUGE_VALL
+# define HUGE_VALL (-(HUGE_VAL))
+#endif
+
+/*
+ * Data for a chfPlugin
+ */
+typedef struct chfPlugin {
+ const chfPluginArgDef *opts;
+ size_t nopts;
+ epicsUInt32 *required;
+ const chfPluginIf *pif;
+} chfPlugin;
+
+/*
+ * Parser state data for a chfFilter (chfPlugin instance)
+ */
+typedef struct chfFilter {
+ const chfPlugin *plugin;
+ epicsUInt32 *found;
+ void *puser;
+ epicsInt16 nextParam;
+} chfFilter;
+
+/* Data types we get from the parser */
+typedef enum chfPluginType {
+ chfPluginTypeBool,
+ chfPluginTypeInt,
+ chfPluginTypeDouble,
+ chfPluginTypeString
+} chfPluginType;
+
+/*
+ * Convert the (long) integer value 'val' to the type named in 'opt->optType'
+ * and store the result at 'user + opt->offset'.
+ */
+static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
+{
+ long *ival;
+ int *eval;
+ const chfPluginEnumType *emap;
+ double *dval;
+ char *sval;
+ char buff[22]; /* 2^64 = 1.8e+19, so 20 digits plus sign max */
+
+/* printf("Got an integer for %s (type %d): %ld\n", opt->name, opt->optType, val); */
+
+ if (!opt->convert && opt->optType != chfPluginArgInt32) {
+ return -1;
+ }
+
+ switch (opt->optType) {
+ case chfPluginArgInt32:
+ ival = (long*) ((char*)user + opt->offset);
+ *ival = val;
+ break;
+ case chfPluginArgBoolean:
+ eval = (int*) ((char*)user + opt->offset);
+ *eval = !!val;
+ break;
+ case chfPluginArgDouble:
+ dval = (double*) ((char*)user + opt->offset);
+ *dval = (double) val;
+ break;
+ case chfPluginArgString:
+ sval = ((char*)user + opt->offset);
+ sprintf(buff, "%ld", val);
+ if (strlen(buff) > opt->size-1) {
+ return -1;
+ }
+ strncpy(sval, buff, opt->size-1);
+ sval[opt->size-1]='\0';
+ break;
+ case chfPluginArgEnum:
+ eval = (int*) ((char*)user + opt->offset);
+ for (emap = opt->enums; emap && emap->name; emap++) {
+ if (val == emap->value) {
+ *eval = val;
+ break;
+ }
+ }
+ if (!emap || !emap->name) {
+ return -1;
+ }
+ break;
+ case chfPluginArgInvalid:
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Convert the (int) boolean value 'val' to the type named in 'opt->optType'
+ * and store the result at 'user + opt->offset'.
+ */
+static int store_boolean_value(const chfPluginArgDef *opt, void *user, int val)
+{
+ long *ival;
+ int *eval;
+ double *dval;
+ char *sval;
+
+/* printf("Got a boolean for %s (type %d): %d\n", opt->name, opt->optType, val); */
+
+ if (!opt->convert && opt->optType != chfPluginArgBoolean) {
+ return -1;
+ }
+
+ switch (opt->optType) {
+ case chfPluginArgInt32:
+ ival = (long*) ((char*)user + opt->offset);
+ *ival = val;
+ break;
+ case chfPluginArgBoolean:
+ eval = (int*) ((char*)user + opt->offset);
+ *eval = val;
+ break;
+ case chfPluginArgDouble:
+ dval = (double*) ((char*)user + opt->offset);
+ *dval = val ? 1. : 0.;
+ break;
+ case chfPluginArgString:
+ sval = ((char*)user + opt->offset);
+ if ((val ? 4 : 5) > opt->size-1) {
+ return -1;
+ }
+ strncpy(sval, (val ? "true" : "false"), opt->size-1);
+ sval[opt->size-1]='\0';
+ break;
+ case chfPluginArgEnum:
+ case chfPluginArgInvalid:
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Convert the double value 'val' to the type named in 'opt->optType'
+ * and store the result at 'user + opt->offset'.
+ */
+static int store_double_value(const chfPluginArgDef *opt, void *user, double val)
+{
+ long *ival;
+ int *eval;
+ double *dval;
+ char *sval;
+ int i;
+
+/*
+ printf("Got a double for %s (type %d, convert: %s): %g\n",
+ opt->name, opt->optType, opt->convert?"yes":"no", val);
+*/
+ if (!opt->convert && opt->optType != chfPluginArgDouble) {
+ return -1;
+ }
+
+ switch (opt->optType) {
+ case chfPluginArgInt32:
+ if (val < LONG_MIN || val > LONG_MAX) {
+ return -1;
+ }
+ ival = (long*) ((char*)user + opt->offset);
+ *ival = (long) val;
+ break;
+ case chfPluginArgBoolean:
+ eval = (int*) ((char*)user + opt->offset);
+ *eval = (val != 0.) ? 1 : 0;
+ break;
+ case chfPluginArgDouble:
+ dval = (double*) ((char*)user + opt->offset);
+ *dval = val;
+ break;
+ case chfPluginArgString:
+ sval = ((char*)user + opt->offset);
+ if (opt->size <= 8) { /* Play it safe: 3 exp + 2 sign + 'e' + '.' */
+ return -1;
+ }
+ i = snprintf(sval, opt->size, "%.*g", opt->size - 7, val);
+ if (i >= opt->size) {
+ return -1;
+ }
+ break;
+ case chfPluginArgEnum:
+ case chfPluginArgInvalid:
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Convert the (char*) string value 'val' to the type named in 'opt->optType'
+ * and store the result at 'user + opt->offset'.
+ */
+static int store_string_value(const chfPluginArgDef *opt, void *user, const char *val, size_t len)
+{
+ long *ival;
+ int *eval;
+ const chfPluginEnumType *emap;
+ double *dval;
+ char *sval;
+ char *end;
+ int i;
+
+/* printf("Got a string for %s (type %d): %.*s\n", opt->name, opt->optType, len, val); */
+
+ if (!opt->convert && opt->optType != chfPluginArgString && opt->optType != chfPluginArgEnum) {
+ return -1;
+ }
+
+ switch (opt->optType) {
+ case chfPluginArgInt32:
+ ival = (long*) ((char*)user + opt->offset);
+ *ival = strtol(val, &end, 0);
+ /* test for the myriad error conditions which strtol may use */
+ if (*ival == LONG_MAX || *ival == LONG_MIN || end == val) {
+ return -1;
+ }
+ break;
+ case chfPluginArgBoolean:
+ eval = (int*) ((char*)user + opt->offset);
+ if (strncasecmp(val, "true", len) == 0) {
+ *eval = 1;
+ } else if (strncasecmp(val, "false", len) == 0) {
+ *eval = 0;
+ } else {
+ i = strtol(val, &end, 0);
+ if (i > INT_MAX || i < INT_MIN || end == val) {
+ return -1;
+ }
+ *eval = !!i;
+ }
+ break;
+ case chfPluginArgDouble:
+ dval = (double*) ((char*)user + opt->offset);
+ *dval = strtod(val, &end);
+ /* Indicates errors in the same manner as strtol */
+ if (*dval==HUGE_VALF||*dval==HUGE_VALL||end==val )
+ {
+ return -1;
+ }
+ break;
+ case chfPluginArgString:
+ i = opt->size-1 < len ? opt->size-1 : len;
+ sval = ((char*)user + opt->offset);
+ strncpy(sval, val, i);
+ sval[i] = '\0';
+ break;
+ case chfPluginArgEnum:
+ eval = (int*) ((char*)user + opt->offset);
+ for (emap = opt->enums; emap && emap->name; emap++) {
+ if (strncmp(emap->name, val, len) == 0) {
+ *eval = emap->value;
+ break;
+ }
+ }
+ if( !emap || !emap->name ) {
+ return -1;
+ }
+ break;
+ case chfPluginArgInvalid:
+ return -1;
+ }
+ return 0;
+}
+
+static void freeInstanceData(chfFilter *f)
+{
+ free(f->found); /* FIXME: Use a free-list */
+ free(f); /* FIXME: Use a free-list */
+}
+
+/*
+ * chFilterIf callbacks
+ */
+
+/* First entry point when a new filter instance is created.
+ * All per-instance allocations happen here.
+ */
+static parse_result parse_start(chFilter *filter)
+{
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f;
+
+ /* Filter context */
+ /* FIXME: Use a free-list */
+ f = calloc(1, sizeof(chfFilter));
+ if (!f) {
+ fprintf(stderr,"chfFilterCtx calloc failed\n");
+ goto errfctx;
+ }
+ f->nextParam = -1;
+
+ /* Bit array to find missing required keys */
+ /* FIXME: Use a free-list */
+ f->found = calloc( (p->nopts/32)+1, sizeof(epicsUInt32) );
+ if (!f->found) {
+ fprintf(stderr,"chfConfigParseStart: bit array calloc failed\n");
+ goto errbitarray;
+ }
+
+ /* Call the plugin to allocate its structure, it returns NULL on error */
+ if (p->pif->allocPvt) {
+ if ((f->puser = p->pif->allocPvt()) == NULL)
+ goto errplugin;
+ }
+
+ filter->puser = (void*) f;
+
+ return parse_continue;
+
+ errplugin:
+ free(f->found); /* FIXME: Use a free-list */
+ errbitarray:
+ free(f); /* FIXME: Use a free-list */
+ errfctx:
+ return parse_stop;
+}
+
+static void parse_abort(chFilter *filter) {
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f = (chfFilter*) filter->puser;
+
+ /* Call the plugin to tell it we're aborting */
+ if (p->pif->parse_error) p->pif->parse_error(f->puser);
+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
+ freeInstanceData(f);
+}
+
+static parse_result parse_end(chFilter *filter)
+{
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f = (chfFilter*) filter->puser;
+ int i;
+
+ /* Check if all required arguments were supplied */
+ for(i = 0; i < (p->nopts/32)+1; i++) {
+ if ((f->found[i] & p->required[i]) != p->required[i]) {
+ if (p->pif->parse_error) p->pif->parse_error(f->puser);
+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
+ freeInstanceData(f);
+ return parse_stop;
+ }
+ }
+
+ /* Call the plugin to tell it we're done */
+ if (p->pif->parse_ok) {
+ if (p->pif->parse_ok(f->puser)) {
+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
+ freeInstanceData(f);
+ return parse_stop;
+ }
+ }
+
+ return parse_continue;
+}
+
+static parse_result parse_boolean(chFilter *filter, int boolVal)
+{
+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
+ chfFilter *f = (chfFilter*)filter->puser;
+
+ if (f->nextParam < 0 || store_boolean_value(&opts[f->nextParam], f->puser, boolVal)) {
+ return parse_stop;
+ } else {
+ return parse_continue;
+ }
+}
+
+static parse_result parse_integer(chFilter *filter, long integerVal)
+{
+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
+ chfFilter *f = (chfFilter*)filter->puser;
+
+ if (f->nextParam < 0 || store_integer_value(&opts[f->nextParam], f->puser, integerVal)) {
+ return parse_stop;
+ } else {
+ return parse_continue;
+ }
+}
+
+static parse_result parse_double(chFilter *filter, double doubleVal)
+{
+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
+ chfFilter *f = (chfFilter*)filter->puser;
+
+ if (f->nextParam < 0 || store_double_value(&opts[f->nextParam], f->puser, doubleVal)) {
+ return parse_stop;
+ } else {
+ return parse_continue;
+ }
+}
+
+static parse_result parse_string(chFilter *filter, const char *stringVal, size_t stringLen)
+{
+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
+ chfFilter *f = (chfFilter*)filter->puser;
+
+ if (f->nextParam < 0 || store_string_value(&opts[f->nextParam], f->puser, stringVal, stringLen)) {
+ return parse_stop;
+ } else {
+ return parse_continue;
+ }
+}
+
+static parse_result parse_start_map(chFilter *filter)
+{
+ return parse_continue;
+}
+
+static parse_result parse_map_key(chFilter *filter, const char *key, size_t stringLen)
+{
+ const chfPluginArgDef *cur;
+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
+ chfFilter *f = (chfFilter*)filter->puser;
+ int i;
+
+ f->nextParam = -1;
+ for(cur = opts, i = 0; cur && cur->name; cur++, i++) {
+ if (strncmp(key, cur->name, stringLen) == 0) {
+ f->nextParam = i;
+ break;
+ }
+ }
+ if (f->nextParam == -1) {
+ return parse_stop;
+ }
+
+ f->found[i/32] |= 1<<(i%32);
+ return parse_continue;
+}
+
+static parse_result parse_end_map(chFilter *filter)
+{
+ return parse_continue;
+}
+
+static long channel_open(chFilter *filter)
+{
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f = (chfFilter*) filter->puser;
+
+ if (p->pif->channel_open) return p->pif->channel_open(filter->chan, f->puser);
+ else return 0;
+}
+
+static void channel_register_pre(chFilter *filter,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f = (chfFilter*) filter->puser;
+
+ if (p->pif->channelRegisterPre)
+ p->pif->channelRegisterPre(filter->chan, f->puser, cb_out, arg_out, probe);
+}
+
+static void channel_register_post(chFilter *filter,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f = (chfFilter*) filter->puser;
+
+ if (p->pif->channelRegisterPost)
+ p->pif->channelRegisterPost(filter->chan, f->puser, cb_out, arg_out, probe);
+}
+
+static void channel_report(chFilter *filter, int level, const unsigned short indent)
+{
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f = (chfFilter*) filter->puser;
+
+ if (p->pif->channel_report)
+ p->pif->channel_report(filter->chan, f->puser, level, indent);
+}
+
+static void channel_close(chFilter *filter)
+{
+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
+ chfFilter *f = (chfFilter*) filter->puser;
+
+ if (p->pif->channel_close) p->pif->channel_close(filter->chan, f->puser);
+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
+ free(f->found); /* FIXME: Use a free-list */
+ free(f); /* FIXME: Use a free-list */
+}
+
+/*
+ * chFilterIf for the wrapper
+ * we just support a simple one-level map, and no arrays
+ */
+static chFilterIf wrapper_fif = {
+ parse_start,
+ parse_abort,
+ parse_end,
+
+ NULL, /* parse_null, */
+ parse_boolean,
+ parse_integer,
+ parse_double,
+ parse_string,
+
+ parse_start_map,
+ parse_map_key,
+ parse_end_map,
+
+ NULL, /* parse_start_array, */
+ NULL, /* parse_end_array, */
+
+ channel_open,
+ channel_register_pre,
+ channel_register_post,
+ channel_report,
+ channel_close
+};
+
+const char* chfPluginEnumString(const chfPluginEnumType *emap, int i, const char* def)
+{
+ for(; emap && emap->name; emap++) {
+ if ( i == emap->value ) {
+ return emap->name;
+ }
+ }
+ return def;
+}
+
+int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginArgDef* opts)
+{
+ chfPlugin *p;
+ size_t i;
+ const chfPluginArgDef *cur;
+ epicsUInt32 *reqd;
+
+ /* Check and count options */
+ for (i = 0, cur = opts; cur && cur->name; i++, cur++) {
+ switch(cur->optType) {
+ case chfPluginArgInt32:
+ if (cur->size < sizeof(long)) {
+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for long (%lu)\n",
+ key, cur->size, cur->name,
+ (unsigned long) sizeof(long));
+ return -1;
+ }
+ break;
+ case chfPluginArgBoolean:
+ if (cur->size < 1) {
+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for boolean (%lu)\n",
+ key, cur->size, cur->name,
+ (unsigned long) sizeof(char));
+ return -1;
+ }
+ break;
+ case chfPluginArgDouble:
+ if (cur->size < sizeof(double)) {
+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for double (%lu)\n",
+ key, cur->size, cur->name,
+ (unsigned long) sizeof(double));
+ return -1;
+ }
+ break;
+ case chfPluginArgString:
+ if (cur->size < sizeof(char*)) {
+ /* Catch if someone has given us a char* instead of a char[]
+ * Also means that char buffers must be >=4.
+ */
+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for string (>= %lu)\n",
+ key, cur->size, cur->name,
+ (unsigned long) sizeof(char*));
+ return -1;
+ }
+ break;
+ case chfPluginArgEnum:
+ if (cur->size < sizeof(int)) {
+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for enum (%lu)\n",
+ key, cur->size, cur->name,
+ (unsigned long) sizeof(int));
+ return -1;
+ }
+ break;
+ case chfPluginArgInvalid:
+ errlogPrintf("Plugin %s: storage type for %s is not defined\n",
+ key, cur->name);
+ return -1;
+ break;
+ }
+ }
+
+ /* Bit array used to find missing required keys */
+ reqd = dbCalloc((i/32)+1, sizeof(epicsUInt32));
+ if (!reqd) {
+ fprintf(stderr,"Plugin %s: bit array calloc failed\n", key);
+ return -1;
+ }
+
+ for (i = 0, cur = opts; cur && cur->name; i++, cur++) {
+ if (cur->required) reqd[i/32] |= 1 << (i%32);
+ }
+
+ /* Plugin data */
+ p = dbCalloc(1, sizeof(chfPlugin));
+ p->pif = pif;
+ p->opts = opts;
+ p->nopts = i;
+ p->required = reqd;
+
+ dbRegisterFilter(key, &wrapper_fif, p);
+
+ return 0;
+}
=== added file 'src/ioc/db/chfPlugin.h'
--- src/ioc/db/chfPlugin.h 1970-01-01 00:00:00 +0000
+++ src/ioc/db/chfPlugin.h 2012-05-30 18:10:27 +0000
@@ -0,0 +1,280 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
+
+#ifndef CHFPLUGIN_H
+#define CHFPLUGIN_H
+
+#include <shareLib.h>
+#include <dbDefs.h>
+#include <epicsTypes.h>
+#include <dbChannel.h>
+
+struct db_field_log;
+
+/** @file chfPlugin.h
+ * @brief Channel filter simplified plugins.
+ *
+ * Utility layer to allow an easier (reduced) interface for
+ * channel filter plugins.
+ *
+ * Parsing the configuration arguments of a channel filter plugin
+ * is done according to an argument description table provided by the plugin.
+ * The parser stores the results directly into a user supplied structure
+ * after appropriate type conversion.
+ *
+ * To specify the arguments, a chfPluginArgDef table must be defined
+ * for the user structure. This table has to be specified when the plugin registers.
+ *
+ * The plugin is responsible to register an init function using
+ * epicsExportRegistrar() and the accompanying registrar() directive in the dbd,
+ * and call chfPluginRegister() from within the init function.
+ *
+ * For example:
+ *
+ * typedef struct myStruct {
+ * ... other stuff
+ * epicsUInt32 ival;
+ * double dval;
+ * epicsUInt32 ival2;
+ * int enumval;
+ * char strval[20];
+ * } myStruct;
+ *
+ * static const
+ * chfPluginEnumType colorEnum[] = { {"Red",1}, {"Green",2}, {"Blue",3}, {NULL,0} };
+ *
+ * static const
+ * chfPluginDef myStructDef[] = {
+ * chfInt32 (myStruct, ival, "Integer" , 0, 0),
+ * chfInt32 (myStruct, ival2, "Second" , 1, 0),
+ * chfDouble(myStruct, dval, "Double" , 1, 0),
+ * chfString(myStruct, strval , "String" , 1, 0),
+ * chfEnum (myStruct, enumval, "Color" , 1, 0, colorEnum),
+ * chfPluginEnd
+ * };
+ *
+ * Note: The 4th argument specifies the parameter to be required (1) or optional (0),
+ * the 5th whether converting to the required type is allowed (1), or
+ * type mismatches are an error (0).
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief Channel filter simplified plugin interface.
+ *
+ * The routines in this structure must be implemented by each filter plugin.
+ */
+typedef struct chfPluginIf {
+
+ /* Memory management */
+ /** @brief Allocate private resources.
+ *
+ * <em>Called before parsing starts.</em>
+ * The plugin should allocate its per-instance structures,
+ * returning a pointer to them or NULL requesting an abort of the operation.
+ *
+ * allocPvt may be set to NULL, if no resource allocation is needed.
+ *
+ * @return Pointer to private structure, NULL if operation is to be aborted.
+ */
+ void * (* allocPvt) (void);
+
+ /** @brief Free private resources.
+ *
+ * <em>Called as part of abort or shutdown.</em>
+ * The plugin should release any resources allocated for this filter;
+ * no further calls through this interface will be made.
+ *
+ * freePvt may be set to NULL, if no resources need to be released.
+ *
+ * @param pvt Pointer to private structure.
+ */
+ void (* freePvt) (void *pvt);
+
+ /* Parameter parsing results */
+ /** @brief A parsing error occurred.
+ *
+ * <em>Called after parsing failed with an error.</em>
+ *
+ * @param pvt Pointer to private structure.
+ */
+ void (* parse_error) (void *pvt);
+
+ /** @brief Configuration has been parsed successfully.
+ *
+ * <em>Called after parsing has finished ok.</em>
+ * The plugin may check the validity of the parsed data,
+ * returning -1 to request an abort of the operation.
+ *
+ * @param pvt Pointer to private structure.
+ * @return 0 for success, -1 if operation is to be aborted.
+ */
+ int (* parse_ok) (void *pvt);
+
+ /* Channel operations */
+ /** @brief Open channel.
+ *
+ * <em>Called as part of the channel connection setup.</em>
+ *
+ * @param chan dbChannel for which the connection is being made.
+ * @param pvt Pointer to private structure.
+ * @return 0 for success, -1 if operation is to be aborted.
+ */
+ long (* channel_open) (dbChannel *chan, void *pvt);
+
+ /** @brief Register callbacks for pre-event-queue operation.
+ *
+ * <em>Called as part of the channel connection setup.</em>
+ *
+ * This function is called to establish the stack of plugins that an event
+ * is passed through between the database and the event queue.
+ *
+ * The plugin must set pe_out to point to its own post-event callback in order
+ * to be called when a data update is sent from the database towards the
+ * event queue.
+ *
+ * The plugin may find out the type of data it will receive by looking at 'probe'.
+ * If the plugin will change the data type and/or size, it must update 'probe'
+ * accordingly.
+ *
+ * @param chan dbChannel for which the connection is being made.
+ * @param pvt Pointer to private structure.
+ * @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
+ * this plugin).
+ * @param arg_out Argument that must be supplied when calling
+ * this plugin's post-event callback.
+ */
+ void (* channelRegisterPre) (dbChannel *chan, void *pvt,
+ chPostEventFunc **cb_out, void **arg_out,
+ db_field_log *probe);
+
+ /** @brief Register callbacks for post-event-queue operation.
+ *
+ * <em>Called as part of the channel connection setup.</em>
+ *
+ * This function is called to establish the stack of plugins that an event
+ * is passed through between the event queue and the final user (CA server or
+ * database access).
+ *
+ * The plugin must set pe_out to point to its own post-event callback in order
+ * to be called when a data update is sent from the event queue towards the
+ * final user.
+ *
+ * The plugin may find out the type of data it will receive by looking at 'probe'.
+ * If the plugin will change the data type and/or size, it must update 'probe'
+ * accordingly.
+ *
+ * @param chan dbChannel for which the connection is being made.
+ * @param pvt Pointer to private structure.
+ * @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
+ * this plugin).
+ * @param arg_out Argument that must be supplied when calling
+ * this plugin's post-event callback.
+ */
+ void (* channelRegisterPost) (dbChannel *chan, void *pvt,
+ chPostEventFunc **cb_out, void **arg_out,
+ db_field_log *probe);
+
+ /** @brief Channel report request.
+ *
+ * <em>Called as part of show... routines.</em>
+ *
+ * @param chan dbChannel for which the report is requested.
+ * @param pvt Pointer to private structure.
+ * @param level Interest level.
+ * @param indent Number of spaces to print before each output line.
+ */
+ void (* channel_report) (dbChannel *chan, void *pvt, int level, const unsigned short indent);
+
+ /* FIXME: More filter routines here ... */
+
+ /** @brief Channel close request.
+ *
+ * <em>Called as part of connection shutdown.</em>
+ * @param chan dbChannel for which the connection is being shut down.
+ * @param pvt Pointer to private structure.
+ */
+ void (* channel_close) (dbChannel *chan, void *pvt);
+
+} chfPluginIf;
+
+typedef enum chfPluginArg {
+ chfPluginArgInvalid=0,
+ chfPluginArgBoolean,
+ chfPluginArgInt32,
+ chfPluginArgDouble,
+ chfPluginArgString,
+ chfPluginArgEnum
+} chfPluginArg;
+
+typedef struct chfPluginEnumType {
+ const char *name;
+ const int value;
+} chfPluginEnumType;
+
+typedef struct chfPluginArgDef {
+ const char * name;
+ chfPluginArg optType;
+ int required:1;
+ int convert:1;
+ epicsUInt32 offset;
+ epicsUInt32 size;
+ const chfPluginEnumType *enums;
+} chfPluginArgDef;
+
+#define chfInt32(Struct, Member, Name, Req, Conv) \
+{Name, chfPluginArgInt32, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
+
+#define chfBoolean(Struct, Member, Name, Req, Conv) \
+{Name, chfPluginArgBoolean, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
+
+#define chfDouble(Struct, Member, Name, Req, Conv) \
+{Name, chfPluginArgDouble, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
+
+#define chfString(Struct, Member, Name, Req, Conv) \
+{Name, chfPluginArgString, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
+
+#define chfEnum(Struct, Member, Name, Req, Conv, Enums) \
+{Name, chfPluginArgEnum, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
+
+#define chfPluginArgEnd {0}
+
+/* Extra output when parsing and converting */
+#define CHFPLUGINDEBUG 1
+
+/** @brief Return the string associated with Enum index 'i'.
+ *
+ * @param Enums A null-terminated array of string/integer pairs.
+ * @param i An Enum index.
+ * @param def String to be returned when 'i' isn't a valid Enum index.
+ * @return The string associated with 'i'.
+ */
+epicsShareFunc const char* chfPluginEnumString(const chfPluginEnumType *Enums, int i, const char* def);
+
+/** @brief Register a plugin.
+ *
+ * @param key The plugin name key that clients will use.
+ * @param pif Pointer to the plugin's interface.
+ * @param opts Pointer to the configuration argument description table.
+ */
+epicsShareFunc int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginArgDef* opts);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CHFPLUGIN_H
=== modified file 'src/ioc/db/dbAccess.c'
--- src/ioc/db/dbAccess.c 2012-02-20 16:01:04 +0000
+++ src/ioc/db/dbAccess.c 2012-05-30 18:10:27 +0000
@@ -1,21 +1,22 @@
/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* dbAccess.c */
-/* $Revision-Id$ */
+
/*
* Original Author: Bob Dalesio
* Current Author: Marty Kraimer
- * Date: 11-7-90
-*/
+ * Andrew Johnson <[email protected]>
+ * Ralph Lange <[email protected]>
+ */
-
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -46,6 +47,7 @@
#include "dbAddr.h"
#include "callback.h"
#include "dbScan.h"
+#include "dbLink.h"
#include "dbLock.h"
#include "dbEvent.h"
#include "dbConvert.h"
@@ -89,17 +91,6 @@
/* The following is to handle SPC_AS */
static SPC_ASCALLBACK spcAsCallback = 0;
-
-static void inherit_severity(const struct pv_link *ppv_link,
- dbCommon *pdest, epicsEnum16 stat, epicsEnum16 sevr)
-{
- switch(ppv_link->pvlMask&pvlOptMsMode) {
- case pvlOptNMS: break;
- case pvlOptMSI: if (sevr < INVALID_ALARM) break;
- case pvlOptMS: recGblSetSevr(pdest,LINK_ALARM,sevr); break;
- case pvlOptMSS: recGblSetSevr(pdest,stat,sevr); break;
- }
-}
void epicsShareAPI dbSpcAsRegisterCallback(SPC_ASCALLBACK func)
{
@@ -113,7 +104,7 @@
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)) {
@@ -139,7 +130,7 @@
}
return(0);
}
-
+
static void get_enum_strs(DBADDR *paddr, char **ppbuffer,
struct rset *prset,long *options)
{
@@ -199,7 +190,7 @@
*ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size;
return;
}
-
+
static void get_graphics(DBADDR *paddr, char **ppbuffer,
struct rset *prset,long *options)
{
@@ -239,7 +230,7 @@
}
return;
}
-
+
static void get_control(DBADDR *paddr, char **ppbuffer,
struct rset *prset,long *options)
{
@@ -279,7 +270,7 @@
}
return;
}
-
+
static void get_alarm(DBADDR *paddr, char **ppbuffer,
struct rset *prset,long *options)
{
@@ -324,35 +315,44 @@
}
return;
}
-
-static void getOptions(DBADDR *paddr,char **poriginal,long *options,void *pflin)
+
+/*
+ * This code relies on *poriginal being aligned and all increments done by the
+ * 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)
{
db_field_log *pfl= (db_field_log *)pflin;
struct rset *prset;
- short field_type=paddr->field_type;
+ 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!=NULL) {
- *pushort++ = pfl->stat;
- *pushort++ = pfl->sevr;
- } else {
- *pushort++ = pcommon->stat;
- *pushort++ = pcommon->sevr;
- }
+ 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 ){
+ if( prset && prset->get_units ){
(*prset->get_units)(paddr, pbuffer);
pbuffer[DB_UNITS_SIZE-1] = '\0';
} else {
@@ -363,7 +363,7 @@
if( (*options) & DBR_PRECISION ) {
memset(pbuffer, '\0', dbr_precision_size);
if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE)
- && prset && prset->get_precision ){
+ && prset && prset->get_precision ){
(*prset->get_precision)(paddr,pbuffer);
} else {
*options ^= DBR_PRECISION; /*Turn off DBR_PRECISION*/
@@ -373,12 +373,12 @@
if( (*options) & DBR_TIME ) {
epicsUInt32 *ptime = (epicsUInt32 *)pbuffer;
- if(pfl!=NULL) {
- *ptime++ = pfl->time.secPastEpoch;
- *ptime++ = pfl->time.nsec;
- } else {
- *ptime++ = pcommon->time.secPastEpoch;
- *ptime++ = pcommon->time.nsec;
+ 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;
}
@@ -392,7 +392,7 @@
get_alarm(paddr, &pbuffer, prset, options);
*poriginal = pbuffer;
}
-
+
struct rset * epicsShareAPI dbGetRset(const struct dbAddr *paddr)
{
struct dbFldDes *pfldDes = paddr->pfldDes;
@@ -419,10 +419,10 @@
int epicsShareAPI dbIsValueField(const struct dbFldDes *pdbFldDes)
{
- if(pdbFldDes->pdbRecordType->indvalFlddes == pdbFldDes->indRecordType)
- return(TRUE);
+ if (pdbFldDes->pdbRecordType->indvalFlddes == pdbFldDes->indRecordType)
+ return TRUE;
else
- return(FALSE);
+ return FALSE;
}
int epicsShareAPI dbGetFieldIndex(const struct dbAddr *paddr)
@@ -430,50 +430,6 @@
return paddr->pfldDes->indRecordType;
}
-long epicsShareAPI dbGetNelements(const struct link *plink,long *nelements)
-{
- switch(plink->type) {
- case CONSTANT:
- *nelements = 0;
- return(0);
- case DB_LINK: {
- DBADDR *paddr = (DBADDR *)plink->value.pv_link.pvt;
- *nelements = paddr->no_elements;
- return(0);
- }
- case CA_LINK:
- return(dbCaGetNelements(plink,nelements));
- default:
- break;
- }
- return(S_db_badField);
-}
-
-int epicsShareAPI dbIsLinkConnected(const struct link *plink)
-{
- switch(plink->type) {
- case DB_LINK: return(TRUE);
- case CA_LINK: return(dbCaIsLinkConnected(plink));
- default: break;
- }
- return(FALSE);
-}
-
-int epicsShareAPI dbGetLinkDBFtype(const struct link *plink)
-{
- switch(plink->type) {
- case DB_LINK:
- {
- DBADDR *paddr = (DBADDR *)plink->value.pv_link.pvt;
-
- return((int)paddr->field_type);
- }
- case CA_LINK: return(dbCaGetLinkDBFtype(plink));
- default: break;
- }
- return(-1);
-}
-
/*
* Process a record if its scan field is passive.
* Will notify if processing is complete by callback.
@@ -481,50 +437,15 @@
*/
long epicsShareAPI dbScanPassive(dbCommon *pfrom, dbCommon *pto)
{
- long status;
-
/* if not passive just return success */
- if(pto->scan != 0) return(0);
-
- if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto);
- status = dbProcess(pto);
- return(status);
-}
-
-/*KLUDGE: Following needed so that dbPutLink to PROC field works correctly*/
-long epicsShareAPI dbScanLink(dbCommon *pfrom, dbCommon *pto)
-{
- long status;
- unsigned char pact;
-
- if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto);
- pact = pfrom->pact;
- pfrom->pact = TRUE;
- status = dbProcess(pto);
- pfrom->pact = pact;
- return(status);
-}
-
-void epicsShareAPI dbScanFwdLink(struct link *plink)
-{
- dbCommon *precord;
- struct pv_link *pvlink;
- short fwdLinkValue;
-
- if(plink->type!=DB_LINK && plink->type!=CA_LINK) return;
- pvlink = &plink->value.pv_link;
- precord = pvlink->precord;
- if(plink->type==DB_LINK) {
- dbAddr *paddr = (dbAddr *)plink->value.pv_link.pvt;
- dbScanPassive(precord,paddr->precord);
- return;
- }
- if(!(pvlink->pvlMask & pvlOptFWD)) return;
- fwdLinkValue = 1;
- dbCaPutLink(plink,DBR_SHORT,&fwdLinkValue,1);
- return;
-}
-
+ if (pto->scan != 0)
+ return 0;
+
+ if (pfrom && pfrom->ppn)
+ dbNotifyAdd(pfrom,pto);
+ return dbProcess(pto);
+}
+
/*
* Process the record.
* 1. Check for breakpoints.
@@ -536,121 +457,127 @@
*/
long epicsShareAPI dbProcess(dbCommon *precord)
{
- struct rset *prset = precord->rset;
- dbRecordType *pdbRecordType = precord->rdes;
- unsigned char tpro=precord->tpro;
- long status = 0;
- int *ptrace;
- int set_trace=FALSE;
- dbFldDes *pdbFldDes;
- int callNotifyCompletion = FALSE;
-
- ptrace = dbLockSetAddrTrace(precord);
+ struct rset *prset = precord->rset;
+ dbRecordType *pdbRecordType = precord->rdes;
+ unsigned char tpro = precord->tpro;
+ long status = 0;
+ int *ptrace;
+ int set_trace = FALSE;
+ dbFldDes *pdbFldDes;
+ int callNotifyCompletion = FALSE;
+
+ ptrace = dbLockSetAddrTrace(precord);
+ /*
+ * Note that it is likely that if any changes are made
+ * to dbProcess() corresponding changes will have to
+ * be made in the breakpoint handler.
+ */
+
+ /* see if there are any stopped records or breakpoints */
+ if (lset_stack_count != 0) {
/*
- * Note that it is likely that if any changes are made
- * to dbProcess() corresponding changes will have to
- * be made in the breakpoint handler.
+ * Check to see if the record should be processed
+ * and activate breakpoint accordingly. If this
+ * function call returns non-zero, skip record
+ * support and fall out of dbProcess(). This is
+ * done so that a dbContTask() can be spawned to
+ * take over record processing for the lock set
+ * containing a breakpoint.
*/
-
- /* see if there are any stopped records or breakpoints */
- if (lset_stack_count != 0) {
- /*
- * Check to see if the record should be processed
- * and activate breakpoint accordingly. If this
- * function call returns non-zero, skip record
- * support and fall out of dbProcess(). This is
- * done so that a dbContTask() can be spawned to
- * take over record processing for the lock set
- * containing a breakpoint.
- */
- if (dbBkpt(precord))
- goto all_done;
- }
-
- /* check for trace processing*/
- if (tpro) {
- if(*ptrace==0) {
- *ptrace = 1;
- set_trace = TRUE;
- }
- }
-
- /* If already active dont process */
- if (precord->pact) {
- unsigned short monitor_mask;
-
- if (*ptrace) printf("%s: Active %s\n",
- epicsThreadGetNameSelf(), precord->name);
- /* raise scan alarm after MAX_LOCK times */
- if (precord->stat==SCAN_ALARM) goto all_done;
- if (precord->lcnt++ !=MAX_LOCK) goto all_done;
- if (precord->sevr>=INVALID_ALARM) goto all_done;
- recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);
- monitor_mask = recGblResetAlarms(precord);
- monitor_mask |= DBE_VALUE|DBE_LOG;
- pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
- db_post_events(precord,
- (void *)(((char *)precord) + pdbFldDes->offset),
- monitor_mask);
- goto all_done;
- }
- else precord->lcnt = 0;
-
- /*
- * Check the record disable link. A record will not be
- * processed if the value retrieved through this link
- * is equal to constant set in the record's disv field.
- */
- status = dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0);
-
- /* if disabled check disable alarm severity and return success */
- if (precord->disa == precord->disv) {
- if(*ptrace) printf("%s: Disabled %s\n",
- epicsThreadGetNameSelf(), precord->name);
- /*take care of caching and notifyCompletion*/
- precord->rpro = FALSE;
- precord->putf = FALSE;
- callNotifyCompletion = TRUE;
- /* raise disable alarm */
- if (precord->stat==DISABLE_ALARM) goto all_done;
- precord->sevr = precord->diss;
- precord->stat = DISABLE_ALARM;
- precord->nsev = 0;
- precord->nsta = 0;
- db_post_events(precord, &precord->stat, DBE_VALUE);
- 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);
- goto all_done;
- }
-
- /* locate record processing routine */
- /* put this in iocInit() !!! */
- if (!(prset=precord->rset) || !(prset->process)) {
- callNotifyCompletion = TRUE;
- precord->pact=1;/*set pact TRUE so error is issued only once*/
- recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess");
- status = S_db_noRSET;
- if (*ptrace) printf("%s: No RSET for %s\n",
- epicsThreadGetNameSelf(), precord->name);
- goto all_done;
- }
- if(*ptrace) printf("%s: Process %s\n",
- epicsThreadGetNameSelf(), precord->name);
- /* process record */
- status = (*prset->process)(precord);
- /* Print record's fields if PRINT_MASK set in breakpoint field */
- if (lset_stack_count != 0) {
- dbPrint(precord);
- }
+ if (dbBkpt(precord))
+ goto all_done;
+ }
+
+ /* check for trace processing*/
+ if (tpro) {
+ if(*ptrace==0) {
+ *ptrace = 1;
+ set_trace = TRUE;
+ }
+ }
+
+ /* If already active dont process */
+ if (precord->pact) {
+ unsigned short monitor_mask;
+
+ if (*ptrace)
+ printf("%s: Active %s\n",
+ epicsThreadGetNameSelf(), precord->name);
+ /* raise scan alarm after MAX_LOCK times */
+ if (precord->stat==SCAN_ALARM) goto all_done;
+ if (precord->lcnt++ !=MAX_LOCK) goto all_done;
+ if (precord->sevr>=INVALID_ALARM) goto all_done;
+ recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);
+ monitor_mask = recGblResetAlarms(precord);
+ monitor_mask |= DBE_VALUE|DBE_LOG;
+ pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
+ db_post_events(precord,
+ (void *)(((char *)precord) + pdbFldDes->offset),
+ monitor_mask);
+ goto all_done;
+ }
+ else precord->lcnt = 0;
+
+ /*
+ * Check the record disable link. A record will not be
+ * processed if the value retrieved through this link
+ * is equal to constant set in the record's disv field.
+ */
+ status = dbGetLink(&precord->sdis, DBR_SHORT, &precord->disa, 0, 0);
+
+ /* if disabled check disable alarm severity and return success */
+ if (precord->disa == precord->disv) {
+ if(*ptrace)
+ printf("%s: Disabled %s\n",
+ epicsThreadGetNameSelf(), precord->name);
+
+ /*take care of caching and notifyCompletion*/
+ precord->rpro = FALSE;
+ precord->putf = FALSE;
+ callNotifyCompletion = TRUE;
+
+ /* raise disable alarm */
+ if (precord->stat==DISABLE_ALARM) goto all_done;
+ precord->sevr = precord->diss;
+ precord->stat = DISABLE_ALARM;
+ precord->nsev = 0;
+ precord->nsta = 0;
+ db_post_events(precord, &precord->stat, DBE_VALUE);
+ 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);
+ goto all_done;
+ }
+
+ /* locate record processing routine */
+ /* FIXME: put this in iocInit() !!! */
+ if (!(prset=precord->rset) || !(prset->process)) {
+ callNotifyCompletion = TRUE;
+ precord->pact=1;/*set pact TRUE so error is issued only once*/
+ recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess");
+ status = S_db_noRSET;
+ if (*ptrace)
+ printf("%s: No RSET for %s\n",
+ epicsThreadGetNameSelf(), precord->name);
+ goto all_done;
+ }
+ if(*ptrace)
+ printf("%s: Process %s\n",
+ epicsThreadGetNameSelf(), precord->name);
+ /* process record */
+ status = (*prset->process)(precord);
+ /* Print record's fields if PRINT_MASK set in breakpoint field */
+ if (lset_stack_count != 0) {
+ dbPrint(precord);
+ }
all_done:
- if (set_trace) *ptrace = 0;
- if(callNotifyCompletion && precord->ppn) dbNotifyCompletion(precord);
- return(status);
+ if (set_trace) *ptrace = 0;
+ if(callNotifyCompletion && precord->ppn) dbNotifyCompletion(precord);
+ return(status);
}
-
+
/*
* Fill out a database structure (*paddr) for
* a record given by the name "pname."
@@ -726,59 +653,7 @@
dbFinishEntry(&dbEntry);
return status;
}
-
-/* JOH 10-19-04 */
-static char * dbCopyInNameComponentOfPV (
- char * pBuf, unsigned bufLen, const char * pComponent )
-{
- unsigned compLen = strlen ( pComponent );
- if ( compLen < bufLen ) {
- strcpy ( pBuf, pComponent );
- return pBuf + compLen;
- }
- else {
- unsigned reducedSize = bufLen - 1u;
- strncpy ( pBuf, pComponent, reducedSize );
- pBuf[reducedSize] = '\0';
- return pBuf + reducedSize;
- }
-}
-/*
- * Copies PV name into pBuf of length bufLen
- *
- * Returns the number of bytes written to pBuf
- * not including null termination.
- * JOH 10-19-04
- */
-unsigned dbNameOfPV (
- const dbAddr * paddr, char * pBuf, unsigned bufLen )
-{
- dbFldDes * pfldDes = paddr->pfldDes;
- char * pBufTmp = pBuf;
- if ( bufLen == 0u ) {
- return 0u;
- }
- pBufTmp = dbCopyInNameComponentOfPV (
- pBufTmp, bufLen, paddr->precord->name );
- pBufTmp = dbCopyInNameComponentOfPV (
- pBufTmp, bufLen - ( pBufTmp - pBuf ), "." );
- pBufTmp = dbCopyInNameComponentOfPV (
- pBufTmp, bufLen - ( pBufTmp - pBuf ), pfldDes->name );
- return pBufTmp - pBuf;
-}
-/*
- * Returns the number of bytes in the PV name
- * not including null termination.
- * JOH 10-19-04
- */
-unsigned dbNameSizeOfPV ( const dbAddr * paddr )
-{
- unsigned recNameLen = strlen ( paddr->precord->name );
- dbFldDes * pfldDes = paddr->pfldDes;
- unsigned fieldNameLen = strlen ( pfldDes->name );
- return recNameLen + fieldNameLen + 1;
-}
-
+
long epicsShareAPI dbValueSize(short dbr_type)
{
/* sizes for value associated with each DBR request type */
@@ -826,222 +701,117 @@
return dbReadDatabase(&pdbbase, file, 0, subs);
}
-
-long epicsShareAPI dbGetLinkValue(struct link *plink, short dbrType,
- void *pbuffer, long *poptions, long *pnRequest)
-{
- long status = 0;
-
- if (plink->type == CONSTANT) {
- if (poptions) *poptions = 0;
- if (pnRequest) *pnRequest = 0;
- } else if (plink->type == DB_LINK) {
- struct pv_link *ppv_link = &(plink->value.pv_link);
- DBADDR *paddr = ppv_link->pvt;
- dbCommon *precord = plink->value.pv_link.precord;
-
- /* scan passive records with links that are process passive */
- if (ppv_link->pvlMask&pvlOptPP) {
- dbCommon *pfrom = paddr->precord;
- unsigned char pact;
-
- pact = precord->pact;
- precord->pact = TRUE;
- status = dbScanPassive(precord,pfrom);
- precord->pact = pact;
- if (status) return status;
- }
- if(precord!= paddr->precord) {
- inherit_severity(ppv_link,precord,paddr->precord->stat,paddr->precord->sevr);
- }
-
- if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
- } else {
- unsigned short dbfType = paddr->field_type;
- long no_elements = paddr->no_elements;
-
- if (dbrType < 0 || dbrType > DBR_ENUM ||
- dbfType > DBF_DEVICE) {
- status = S_db_badDbrtype;
- recGblRecordError(status, precord, "GetLinkValue Failed");
- recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
- return status;
- }
- /* attempt to make a fast link */
- if ((!poptions || *poptions == 0) &&
- no_elements == 1 &&
- (!pnRequest || *pnRequest == 1) &&
- paddr->special != SPC_ATTRIBUTE) {
- ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
- } else {
- ppv_link->getCvt = 0;
- status = dbGet(paddr, dbrType, pbuffer, poptions, pnRequest, NULL);
- }
- }
- ppv_link->lastGetdbrType = dbrType;
- if (status) {
- recGblRecordError(status, precord, "dbGetLinkValue");
- recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
- }
- } else if (plink->type == CA_LINK) {
- struct dbCommon *precord = plink->value.pv_link.precord;
- const struct pv_link *pcalink = &plink->value.pv_link;
- epicsEnum16 sevr, stat;
-
- status=dbCaGetLink(plink,dbrType,pbuffer,&stat,&sevr,pnRequest);
- if (status) {
- recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
- } else {
- inherit_severity(pcalink,precord,stat,sevr);
- }
- if (poptions) *poptions = 0;
- } else {
- cantProceed("dbGetLinkValue: Illegal link type");
- }
- return status;
-}
-
-long epicsShareAPI dbPutLinkValue(struct link *plink, short dbrType,
- const void *pbuffer, long nRequest)
-{
- long status = 0;
-
- if (plink->type == DB_LINK) {
- struct dbCommon *psource = plink->value.pv_link.precord;
- struct pv_link *ppv_link = &plink->value.pv_link;
- DBADDR *paddr = (DBADDR *)ppv_link->pvt;
- dbCommon *pdest = paddr->precord;
-
- status = dbPut(paddr, dbrType, pbuffer, nRequest);
- inherit_severity(ppv_link,pdest,psource->nsta,psource->nsev);
- if (status) return status;
-
- if (paddr->pfield == (void *)&pdest->proc ||
- (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
- /*if dbPutField caused asyn record to process */
- /* ask for reprocessing*/
- if (pdest->putf) {
- pdest->rpro = TRUE;
- } else { /* otherwise ask for the record to be processed*/
- status = dbScanLink(psource, pdest);
- }
- }
- if (status)
- recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM);
- } else if (plink->type == CA_LINK) {
- struct dbCommon *psource = plink->value.pv_link.precord;
-
- status = dbCaPutLink(plink, dbrType, pbuffer, nRequest);
- if (status < 0)
- recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM);
- } else {
- cantProceed("dbPutLinkValue: Illegal link type");
- }
- return status;
-}
-
+
+static long getLinkValue(DBADDR *paddr, short dbrType,
+ char *pbuf, long *nRequest)
+{
+ dbCommon *precord = paddr->precord;
+ dbFldDes *pfldDes = paddr->pfldDes;
+ int maxlen;
+ DBENTRY dbEntry;
+ long status;
+
+ switch (dbrType) {
+ case DBR_STRING:
+ maxlen = MAX_STRING_SIZE - 1;
+ if (nRequest && *nRequest > 1) *nRequest = 1;
+ break;
+
+ case DBR_CHAR:
+ case DBR_UCHAR:
+ if (nRequest && *nRequest > 0) {
+ maxlen = *nRequest - 1;
+ break;
+ }
+ /* else fall through ... */
+ default:
+ return S_db_badDbrtype;
+ }
+
+ dbInitEntry(pdbbase, &dbEntry);
+ status = dbFindRecord(&dbEntry, precord->name);
+ if (!status) status = dbFindField(&dbEntry, pfldDes->name);
+ if (!status) {
+ char *rtnString = dbGetString(&dbEntry);
+
+ strncpy(pbuf, rtnString, --maxlen);
+ pbuf[maxlen] = 0;
+ }
+ dbFinishEntry(&dbEntry);
+ return status;
+}
+
+static long getAttrValue(DBADDR *paddr, short dbrType,
+ char *pbuf, long *nRequest)
+{
+ int maxlen;
+
+ if (!paddr->pfield) return S_db_badField;
+
+ switch (dbrType) {
+ case DBR_STRING:
+ maxlen = MAX_STRING_SIZE - 1;
+ if (nRequest && *nRequest > 1) *nRequest = 1;
+ break;
+
+ case DBR_CHAR:
+ case DBR_UCHAR:
+ if (nRequest && *nRequest > 0) {
+ maxlen = *nRequest - 1;
+ break;
+ }
+ /* else fall through ... */
+ default:
+ return S_db_badDbrtype;
+ }
+
+ strncpy(pbuf, paddr->pfield, --maxlen);
+ pbuf[maxlen] = 0;
+ return 0;
+}
+
long epicsShareAPI dbGetField(DBADDR *paddr,short dbrType,
void *pbuffer, long *options, long *nRequest, void *pflin)
{
- short dbfType = paddr->field_type;
dbCommon *precord = paddr->precord;
long status = 0;
dbScanLock(precord);
- if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
- DBENTRY dbEntry;
- dbFldDes *pfldDes = paddr->pfldDes;
- char *rtnString;
- char *pbuf = (char *)pbuffer;
- int maxlen;
-
- if (options && (*options))
- getOptions(paddr, &pbuf, options, pflin);
- if (nRequest && *nRequest == 0) goto done;
-
- switch (dbrType) {
- case DBR_STRING:
- maxlen = MAX_STRING_SIZE - 1;
- if (nRequest && *nRequest > 1) *nRequest = 1;
- break;
-
- case DBR_CHAR:
- case DBR_UCHAR:
- if (nRequest && *nRequest > 0) {
- maxlen = *nRequest - 1;
- break;
- }
- /* else fall through ... */
- default:
- status = S_db_badDbrtype;
- goto done;
- }
-
- dbInitEntry(pdbbase, &dbEntry);
- status = dbFindRecord(&dbEntry, precord->name);
- if (!status) status = dbFindField(&dbEntry, pfldDes->name);
- if (!status) {
- rtnString = dbGetString(&dbEntry);
- strncpy(pbuf, rtnString, maxlen);
- pbuf[maxlen] = 0;
- }
- dbFinishEntry(&dbEntry);
- } else {
- status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin);
- }
-done:
+ status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin);
dbScanUnlock(precord);
return status;
}
-
+
long epicsShareAPI dbGet(DBADDR *paddr, short dbrType,
void *pbuffer, long *options, long *nRequest, void *pflin)
{
+ char *pbuf = pbuffer;
db_field_log *pfl = (db_field_log *)pflin;
- short field_type = paddr->field_type;
- long no_elements = paddr->no_elements;
+ short field_type;
+ long no_elements;
long offset;
struct rset *prset;
long status = 0;
- if (options && *options) {
- char *pbuf = pbuffer;
-
+ if (options && *options)
getOptions(paddr, &pbuf, options, pflin);
- pbuffer = pbuf;
- }
- if (nRequest && *nRequest == 0) return 0;
-
- if (paddr->special == SPC_ATTRIBUTE) {
- char *pbuf = pbuffer;
- int maxlen;
-
- if (!paddr->pfield) return S_db_badField;
-
- switch (dbrType) {
- case DBR_STRING:
- maxlen = MAX_STRING_SIZE - 1;
- if (nRequest && *nRequest > 1) *nRequest = 1;
- break;
-
- case DBR_CHAR:
- case DBR_UCHAR:
- if (nRequest && *nRequest > 0) {
- maxlen = *nRequest - 1;
- break;
- }
- /* else fall through ... */
- default:
- return S_db_badDbrtype;
- }
-
- strncpy(pbuf, (char *)paddr->pfield, maxlen);
- pbuf[maxlen] = 0;
+ if (nRequest && *nRequest == 0)
return 0;
+
+ if (!pfl || pfl->type == dbfl_type_rec) {
+ field_type = paddr->field_type;
+ no_elements = paddr->no_elements;
+ } else {
+ field_type = pfl->field_type;
+ no_elements = pfl->no_elements;
}
+ if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK)
+ return getLinkValue(paddr, dbrType, pbuf, nRequest);
+
+ if (paddr->special == SPC_ATTRIBUTE)
+ return getAttrValue(paddr, dbrType, pbuf, nRequest);
+
/* Check for valid request */
if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
char message[80];
@@ -1052,7 +822,8 @@
}
/* check for array */
- if (paddr->special == SPC_DBADDR &&
+ if ((!pfl || pfl->type == dbfl_type_rec) &&
+ paddr->special == SPC_DBADDR &&
no_elements > 1 &&
(prset = dbGetRset(paddr)) &&
prset->get_array_info) {
@@ -1062,15 +833,20 @@
if (offset == 0 && (!nRequest || no_elements == 1)) {
if (nRequest) *nRequest = 1;
- if (pfl != NULL) {
+ if (!pfl || pfl->type == dbfl_type_rec) {
+ status = dbFastGetConvertRoutine[field_type][dbrType]
+ (paddr->pfield, pbuffer, paddr);
+ } else {
DBADDR localAddr = *paddr; /* Structure copy */
-
- localAddr.pfield = (char *)&pfl->field;
+ localAddr.field_type = pfl->field_type;
+ localAddr.field_size = pfl->field_size;
+ localAddr.no_elements = pfl->no_elements;
+ if (pfl->type == dbfl_type_val)
+ localAddr.pfield = (char *) &pfl->u.v.field;
+ else
+ localAddr.pfield = (char *) pfl->u.r.field;
status = dbFastGetConvertRoutine[field_type][dbrType]
(localAddr.pfield, pbuffer, &localAddr);
- } else {
- status = dbFastGetConvertRoutine[field_type][dbrType]
- (paddr->pfield, pbuffer, paddr);
}
} else {
long n;
@@ -1094,18 +870,23 @@
/* convert database field and place it in the buffer */
if (n <= 0) {
;/*do nothing*/
- } else if (pfl) {
+ } else if (!pfl || pfl->type == dbfl_type_rec) {
+ status = convert(paddr, pbuffer, n, no_elements, offset);
+ } else {
DBADDR localAddr = *paddr; /* Structure copy */
-
- localAddr.pfield = (char *)&pfl->field;
+ localAddr.field_type = pfl->field_type;
+ localAddr.field_size = pfl->field_size;
+ localAddr.no_elements = pfl->no_elements;
+ if (pfl->type == dbfl_type_val)
+ localAddr.pfield = (char *) &pfl->u.v.field;
+ else
+ localAddr.pfield = (char *) pfl->u.r.field;
status = convert(&localAddr, pbuffer, n, no_elements, offset);
- } else {
- status = convert(paddr, pbuffer, n, no_elements, offset);
}
}
return status;
}
-
+
devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *prdes, int dtyp) {
return (devSup *)ellNth(&prdes->devList, dtyp+1);
}
@@ -1125,10 +906,9 @@
dbCommon *precord = paddr->precord;
dbFldDes *pfldDes = paddr->pfldDes;
long special = paddr->special;
- DBLINK *plink = (DBLINK *)paddr->pfield;
+ struct link *plink = (struct link *)paddr->pfield;
const char *pstring = (const char *)pbuffer;
DBENTRY dbEntry;
- DBADDR dbaddr;
struct dsxt *old_dsxt = NULL;
struct dset *new_dset = NULL;
struct dsxt *new_dsxt = NULL;
@@ -1199,21 +979,8 @@
switch (plink->type) { /* Old link type */
case DB_LINK:
- free(plink->value.pv_link.pvt);
- plink->value.pv_link.pvt = 0;
- plink->type = PV_LINK;
- plink->value.pv_link.getCvt = 0;
- plink->value.pv_link.pvlMask = 0;
- plink->value.pv_link.lastGetdbrType = 0;
- dbLockSetSplit(precord);
- break;
-
case CA_LINK:
- dbCaRemoveLink(plink);
- plink->type = PV_LINK;
- plink->value.pv_link.getCvt = 0;
- plink->value.pv_link.pvlMask = 0;
- plink->value.pv_link.lastGetdbrType = 0;
+ dbRemoveLink(plink);
break;
case CONSTANT:
@@ -1260,35 +1027,7 @@
switch (plink->type) { /* New link type */
case PV_LINK:
- if (plink == &precord->tsel)
- recGblTSELwasModified(plink);
- plink->value.pv_link.precord = precord;
-
- if (!(plink->value.pv_link.pvlMask & (pvlOptCA|pvlOptCP|pvlOptCPP)) &&
- (dbNameToAddr(plink->value.pv_link.pvname, &dbaddr) == 0)) {
- /* It's a DB link */
- DBADDR *pdbAddr;
-
- plink->type = DB_LINK;
- pdbAddr = dbMalloc(sizeof(struct dbAddr));
- *pdbAddr = dbaddr; /* NB: structure copy */;
- plink->value.pv_link.pvt = pdbAddr;
- dbLockSetRecordLock(pdbAddr->precord);
- dbLockSetMerge(precord, pdbAddr->precord);
- } else { /* Make it a CA link */
- char *pperiod;
-
- plink->type = CA_LINK;
- if (pfldDes->field_type == DBF_INLINK) {
- plink->value.pv_link.pvlMask |= pvlOptInpNative;
- }
- dbCaAddLink(plink);
- if (pfldDes->field_type == DBF_FWDLINK) {
- pperiod = strrchr(plink->value.pv_link.pvname, '.');
- if (pperiod && strstr(pperiod, "PROC"))
- plink->value.pv_link.pvlMask |= pvlOptFWD;
- }
- }
+ dbAddLink(precord, plink, pfldDes->field_type);
break;
case CONSTANT:
@@ -1316,7 +1055,7 @@
}
postScanEvent:
if (scan != precord->scan)
- db_post_events(precord, &precord->scan, DBE_VALUE|DBE_LOG);
+ db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
unlock:
dbLockSetGblUnlock();
finish:
@@ -1337,8 +1076,7 @@
return S_db_noMod;
/*check for putField disabled*/
- if (precord->disp &&
- (void *)(&precord->disp) != paddr->pfield)
+ if (precord->disp && paddr->pfield != &precord->disp)
return S_db_putDisabled;
if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK)
@@ -1347,7 +1085,7 @@
dbScanLock(precord);
status = dbPut(paddr, dbrType, pbuffer, nRequest);
if (status == 0) {
- if (paddr->pfield == (void *)&precord->proc ||
+ if (paddr->pfield == &precord->proc ||
(pfldDes->process_passive &&
precord->scan == 0 &&
dbrType < DBR_PUT_ACKT)) {
@@ -1366,16 +1104,18 @@
dbScanUnlock(precord);
return status;
}
-
-static long putAckt(DBADDR *paddr, const unsigned short *pbuffer, long nRequest,
+
+static long putAckt(DBADDR *paddr, const void *pbuffer, long nRequest,
long no_elements, long offset)
{
dbCommon *precord = paddr->precord;
+ const unsigned short *ptrans = pbuffer;
- if (*pbuffer == precord->ackt) return 0;
- precord->ackt = *pbuffer;
+ 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);
}
@@ -1383,19 +1123,20 @@
return 0;
}
-static long putAcks(DBADDR *paddr, const unsigned short *pbuffer, long nRequest,
+static long putAcks(DBADDR *paddr, const void *pbuffer, long nRequest,
long no_elements, long offset)
{
dbCommon *precord = paddr->precord;
+ const unsigned short *psev = pbuffer;
- if (*pbuffer >= precord->acks) {
+ if (*psev >= precord->acks) {
precord->acks = 0;
+ db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);
db_post_events(precord, NULL, DBE_ALARM);
- db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);
}
return 0;
}
-
+
long epicsShareAPI dbPut(DBADDR *paddr, short dbrType,
const void *pbuffer, long nRequest)
{
@@ -1403,17 +1144,17 @@
short field_type = paddr->field_type;
long no_elements = paddr->no_elements;
long special = paddr->special;
- long offset;
long status = 0;
dbFldDes *pfldDes;
int isValueField;
- if (special == SPC_ATTRIBUTE) return S_db_noMod;
+ if (special == SPC_ATTRIBUTE)
+ return S_db_noMod;
if (dbrType == DBR_PUT_ACKT && field_type <= DBF_DEVICE) {
- return putAckt(paddr, (unsigned short *)pbuffer, 1, 1, 0);
+ return putAckt(paddr, pbuffer, 1, 1, 0);
} else if (dbrType == DBR_PUT_ACKS && field_type <= DBF_DEVICE) {
- return putAcks(paddr, (unsigned short *)pbuffer, 1, 1, 0);
+ return putAcks(paddr, pbuffer, 1, 1, 0);
} else if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
char message[80];
@@ -1432,6 +1173,7 @@
paddr->pfield, paddr);
} else {
struct rset *prset = dbGetRset(paddr);
+ long offset = 0;
if (paddr->special == SPC_DBADDR &&
prset && prset->get_array_info) {
@@ -1439,8 +1181,6 @@
status = prset->get_array_info(paddr, &dummy, &offset);
}
- else
- offset = 0;
if (no_elements < nRequest) nRequest = no_elements;
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
nRequest, no_elements, offset);
@@ -1471,140 +1211,4 @@
return status;
}
-
-/* various utility routines */
-long epicsShareAPI dbGetControlLimits(
- const struct link *plink,double *low, double *high)
-{
- struct buffer {
- DBRctrlDouble
- double value;
- } buffer;
- DBADDR *paddr;
- long options = DBR_CTRL_DOUBLE;
- long number_elements = 0;
- long status;
-
- if(plink->type == CA_LINK) return(dbCaGetControlLimits(plink,low,high));
- if(plink->type !=DB_LINK) return(S_db_notFound);
- paddr = (DBADDR *)plink->value.pv_link.pvt;
- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
- if(status) return(status);
- *low = buffer.lower_ctrl_limit;
- *high = buffer.upper_ctrl_limit;
- return(0);
-}
-
-long epicsShareAPI dbGetGraphicLimits(
- const struct link *plink,double *low, double *high)
-{
- struct buffer {
- DBRgrDouble
- double value;
- } buffer;
- DBADDR *paddr;
- long options = DBR_GR_DOUBLE;
- long number_elements = 0;
- long status;
-
- if(plink->type == CA_LINK) return(dbCaGetGraphicLimits(plink,low,high));
- if(plink->type !=DB_LINK) return(S_db_notFound);
- paddr = (DBADDR *)plink->value.pv_link.pvt;
- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
- if(status) return(status);
- *low = buffer.lower_disp_limit;
- *high = buffer.upper_disp_limit;
- return(0);
-}
-
-long epicsShareAPI dbGetAlarmLimits(const struct link *plink,
- double *lolo, double *low, double *high, double *hihi)
-{
- struct buffer {
- DBRalDouble
- double value;
- } buffer;
- DBADDR *paddr;
- long options = DBR_AL_DOUBLE;
- long number_elements = 0;
- long status;
-
- if(plink->type == CA_LINK)
- return(dbCaGetAlarmLimits(plink,lolo,low,high,hihi));
- if(plink->type !=DB_LINK) return(S_db_notFound);
- paddr = (DBADDR *)plink->value.pv_link.pvt;
- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
- if(status) return(status);
- *lolo = buffer.lower_alarm_limit;
- *low = buffer.lower_warning_limit;
- *high = buffer.upper_warning_limit;
- *hihi = buffer.upper_alarm_limit;
- return(0);
-}
-
-long epicsShareAPI dbGetPrecision(const struct link *plink,short *precision)
-{
- struct buffer {
- DBRprecision
- double value;
- } buffer;
- DBADDR *paddr;
- long options = DBR_PRECISION;
- long number_elements = 0;
- long status;
-
- if(plink->type == CA_LINK) return(dbCaGetPrecision(plink,precision));
- if(plink->type !=DB_LINK) return(S_db_notFound);
- paddr = (DBADDR *)plink->value.pv_link.pvt;
- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
- if(status) return(status);
- *precision = buffer.precision.dp;
- return(0);
-}
-
-long epicsShareAPI dbGetUnits(
- const struct link *plink,char *units,int unitsSize)
-{
- struct buffer {
- DBRunits
- double value;
- } buffer;
- DBADDR *paddr;
- long options = DBR_UNITS;
- long number_elements = 0;
- long status;
-
- if(plink->type == CA_LINK) return(dbCaGetUnits(plink,units,unitsSize));
- if(plink->type !=DB_LINK) return(S_db_notFound);
- paddr = (DBADDR *)plink->value.pv_link.pvt;
- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
- if(status) return(status);
- strncpy(units,buffer.units,unitsSize);
- return(0);
-}
-
-long epicsShareAPI dbGetAlarm(const struct link *plink,
- epicsEnum16 *status,epicsEnum16 *severity)
-{
- DBADDR *paddr;
-
- if(plink->type == CA_LINK) return(dbCaGetAlarm(plink,status,severity));
- if(plink->type !=DB_LINK) return(S_db_notFound);
- paddr = (DBADDR *)plink->value.pv_link.pvt;
- if (status) *status = paddr->precord->stat;
- if (severity) *severity = paddr->precord->sevr;
- return(0);
-}
-
-long epicsShareAPI dbGetTimeStamp(const struct link *plink,epicsTimeStamp *pstamp)
-{
- DBADDR *paddr;
-
- if (plink->type == CA_LINK)
- return dbCaGetTimeStamp(plink,pstamp);
- if (plink->type != DB_LINK)
- return S_db_notFound;
- paddr = (DBADDR *)plink->value.pv_link.pvt;
- *pstamp = paddr->precord->time;
- return 0;
-}
+
=== modified file 'src/ioc/db/dbAccess.h'
--- src/ioc/db/dbAccess.h 2002-07-12 21:35:43 +0000
+++ src/ioc/db/dbAccess.h 2012-05-30 18:10:27 +0000
@@ -3,8 +3,7 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
+* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbAccess.h */
@@ -22,6 +21,7 @@
#include "dbAddr.h"
#include "dbLock.h"
#include "dbAccessDefs.h"
+#include "dbLink.h"
#include "dbCa.h"
#include "dbCommon.h"
#include "db_field_log.h"
=== modified file 'src/ioc/db/dbAccessDefs.h'
--- src/ioc/db/dbAccessDefs.h 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbAccessDefs.h 2012-05-30 18:10:27 +0000
@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbAccessDefs.h */
/* $Revision-Id$ */
@@ -20,6 +19,8 @@
#include "epicsTypes.h"
#include "epicsTime.h"
+#include "dbBase.h"
+#include "dbAddr.h"
#ifdef INCLdb_accessh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
@@ -47,7 +48,7 @@
#define DBR_CTRL_DOUBLE 0x00000100
#define DBR_AL_LONG 0x00000200
#define DBR_AL_DOUBLE 0x00000400
-
+
/**********************************************************************
* The next page contains macros for defining requests.
* As an example the following defines a buffer to accept an array
@@ -69,7 +70,7 @@
* options = DBR_STATUS|DBR_TIME;
* number_elements = 10;
* rtnval=dbGetField(paddr,DBR_FLOAT,&buffer,&options,&number_elements);
- *
+ *
* When dbGetField returns:
* rtnval is error status (0 means success)
* options has a bit set for each option that was accepted
@@ -97,7 +98,7 @@
* MYBUFFER *pbuf1;
* MYBUFFER buf;
*************************************************************************/
-
+
/* Macros for defining each option */
#define DBRstatus \
epicsUInt16 status; /* alarm status */\
@@ -143,7 +144,7 @@
epicsFloat64 upper_warning_limit;\
epicsFloat64 lower_warning_limit;\
epicsFloat64 lower_alarm_limit;
-
+
/* structures for each option type */
struct dbr_status {DBRstatus};
struct dbr_units {DBRunits};
@@ -198,25 +199,6 @@
#define S_db_cntSpwn (M_dbAccess|63) /*Cannot spawn dbContTask*/
#define S_db_cntCont (M_dbAccess|65) /*Cannot resume dbContTask*/
#define S_db_noMemory (M_dbAccess|66) /*unable to allocate data structure from pool*/
-
-/* Global Database Access Routines*/
-#define dbGetLink(PLNK, DBRTYPE, PBUFFER, OPTIONS, NREQUEST) \
- ( ( ( (PLNK)->type == CONSTANT ) && \
- ( (NREQUEST) == 0) &&\
- ( (OPTIONS) == 0) ) \
- ? 0 \
- : dbGetLinkValue((PLNK),(DBRTYPE), \
- (void *)(PBUFFER), (OPTIONS), (NREQUEST) ) )
-#define dbPutLink(PLNK, DBRTYPE, PBUFFER, NREQUEST) \
- ( ( (PLNK)->type == CONSTANT) \
- ? 0 \
- : dbPutLinkValue( (PLNK), (DBRTYPE), (void *)(PBUFFER), (NREQUEST) ) )
-#define dbGetPdbAddrFromLink(PLNK) \
- ( ( (PLNK)->type != DB_LINK ) \
- ? 0 \
- : ( ( (struct dbAddr *)( (PLNK)->value.pv_link.pvt) ) ) )
-#define dbGetSevr(PLINK,PSEVERITY) \
- dbGetAlarm((PLINK),NULL,(PSEVERITY))
epicsShareFunc long epicsShareAPI dbPutSpecial(struct dbAddr *paddr,int pass);
epicsShareFunc struct rset * epicsShareAPI dbGetRset(const struct dbAddr *paddr);
@@ -224,51 +206,24 @@
const char *recordTypename,const char *name,const char*value);
epicsShareFunc int epicsShareAPI dbIsValueField(const struct dbFldDes *pdbFldDes);
epicsShareFunc int epicsShareAPI dbGetFieldIndex(const struct dbAddr *paddr);
-epicsShareFunc long epicsShareAPI dbGetNelements(
- const struct link *plink,long *nelements);
-epicsShareFunc int epicsShareAPI dbIsLinkConnected(const struct link *plink);
-epicsShareFunc int epicsShareAPI dbGetLinkDBFtype(const struct link *plink);
-epicsShareFunc long epicsShareAPI dbScanLink(
- struct dbCommon *pfrom, struct dbCommon *pto);
epicsShareFunc long epicsShareAPI dbScanPassive(
struct dbCommon *pfrom,struct dbCommon *pto);
-epicsShareFunc void epicsShareAPI dbScanFwdLink(struct link *plink);
epicsShareFunc long epicsShareAPI dbProcess(struct dbCommon *precord);
epicsShareFunc long epicsShareAPI dbNameToAddr(
const char *pname,struct dbAddr *);
epicsShareFunc devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
epicsShareFunc devSup* epicsShareAPI dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset);
-epicsShareFunc long epicsShareAPI dbGetLinkValue(
- struct link *,short dbrType,void *pbuffer,long *options,long *nRequest);
epicsShareFunc long epicsShareAPI dbGetField(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
long *nRequest,void *pfl);
epicsShareFunc long epicsShareAPI dbGet(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
long *nRequest,void *pfl);
-epicsShareFunc long epicsShareAPI dbPutLinkValue(
- struct link *,short dbrType,const void *pbuffer,long nRequest);
epicsShareFunc long epicsShareAPI dbPutField(
struct dbAddr *,short dbrType,const void *pbuffer,long nRequest);
epicsShareFunc long epicsShareAPI dbPut(
struct dbAddr *,short dbrType,const void *pbuffer,long nRequest);
-/* various utility routines */
-epicsShareFunc long epicsShareAPI dbGetControlLimits(
- const struct link *plink,double *low, double *high);
-epicsShareFunc long epicsShareAPI dbGetGraphicLimits(
- const struct link *plink,double *low, double *high);
-epicsShareFunc long epicsShareAPI dbGetAlarmLimits(
- const struct link *plink,double *lolo, double *low, double *high, double *hihi);
-epicsShareFunc long epicsShareAPI dbGetPrecision(
- const struct link *plink,short *precision);
-epicsShareFunc long epicsShareAPI dbGetUnits(
- const struct link *plink,char *units,int unitsSize);
-epicsShareFunc long epicsShareAPI dbGetAlarm(
- const struct link *plink, epicsEnum16 *status,epicsEnum16 *severity);
-epicsShareFunc long epicsShareAPI dbGetTimeStamp(
- const struct link *plink,epicsTimeStamp *pstamp);
-
typedef void(*SPC_ASCALLBACK)(struct dbCommon *);
/*dbSpcAsRegisterCallback called by access security */
epicsShareFunc void epicsShareAPI dbSpcAsRegisterCallback(SPC_ASCALLBACK func);
=== modified file 'src/ioc/db/dbAddr.h'
--- src/ioc/db/dbAddr.h 2008-08-15 18:58:18 +0000
+++ src/ioc/db/dbAddr.h 2012-05-30 18:10:27 +0000
@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef dbAddrh
@@ -27,7 +27,4 @@
typedef dbAddr DBADDR;
-unsigned dbNameOfPV (const dbAddr * paddr, char * pBuf, unsigned bufLen);
-unsigned dbNameSizeOfPV (const dbAddr * paddr);
-
#endif /* dbAddrh */
=== modified file 'src/ioc/db/dbBkpt.c'
--- src/ioc/db/dbBkpt.c 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbBkpt.c 2012-05-30 18:10:27 +0000
@@ -65,6 +65,7 @@
#include "dbAddr.h"
#include "dbAccessDefs.h"
#include "dbScan.h"
+#include "dbLink.h"
#include "dbLock.h"
#include "recGbl.h"
#include "dbTest.h"
=== modified file 'src/ioc/db/dbCAC.h'
--- src/ioc/db/dbCAC.h 2011-06-01 22:22:12 +0000
+++ src/ioc/db/dbCAC.h 2012-05-30 18:10:27 +0000
@@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* $Revision-Id$
@@ -49,7 +49,7 @@
#include "db_access.h"
#include "dbNotify.h"
#include "dbEvent.h"
-#include "dbAddr.h"
+#include "dbChannel.h"
#include "dbLock.h"
#include "dbCommon.h"
#include "db_convert.h"
@@ -75,25 +75,25 @@
virtual ~dbBaseIO() {}
};
-extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbAddr *paddr,
+extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbChannel *dbch,
int eventsRemaining, struct db_field_log *pfl );
-class dbSubscriptionIO :
- public tsDLNode < dbSubscriptionIO >,
+class dbSubscriptionIO :
+ public tsDLNode < dbSubscriptionIO >,
public dbBaseIO {
public:
- dbSubscriptionIO (
+ dbSubscriptionIO (
epicsGuard < epicsMutex > &, epicsMutex &,
- dbContext &, dbChannelIO &, struct dbAddr &, cacStateNotify &,
+ dbContext &, dbChannelIO &, struct dbChannel *, cacStateNotify &,
unsigned type, unsigned long count, unsigned mask, dbEventCtx );
void destructor ( epicsGuard < epicsMutex > & );
void unsubscribe ( epicsGuard < epicsMutex > & );
void channelDeleteException ( epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
- void * operator new ( size_t size,
+ void * operator new ( size_t size,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & );
- epicsPlacementDeleteOperator (( void *,
+ epicsPlacementDeleteOperator (( void *,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & ))
private:
epicsMutex & mutex;
@@ -104,8 +104,8 @@
unsigned type;
unsigned id;
dbSubscriptionIO * isSubscription ();
- friend void dbSubscriptionEventCallback (
- void * pPrivate, struct dbAddr * paddr,
+ friend void dbSubscriptionEventCallback (
+ void * pPrivate, struct dbChannel * dbch,
int eventsRemaining, struct db_field_log * pfl );
dbSubscriptionIO ( const dbSubscriptionIO & );
dbSubscriptionIO & operator = ( const dbSubscriptionIO & );
@@ -149,8 +149,8 @@
class dbContextReadNotifyCache {
public:
dbContextReadNotifyCache ( epicsMutex & );
- void callReadNotify ( epicsGuard < epicsMutex > &,
- struct dbAddr & addr, unsigned type, unsigned long count,
+ void callReadNotify ( epicsGuard < epicsMutex > &,
+ struct dbChannel * dbch, unsigned type, unsigned long count,
cacReadNotify & notify );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
private:
@@ -162,29 +162,29 @@
class dbContext : public cacContext {
public:
- dbContext ( epicsMutex & cbMutex, epicsMutex & mutex,
+ dbContext ( epicsMutex & cbMutex, epicsMutex & mutex,
cacContextNotify & notify );
virtual ~dbContext ();
void destroyChannel ( epicsGuard < epicsMutex > &, dbChannelIO & );
- void callReadNotify ( epicsGuard < epicsMutex > &,
- struct dbAddr & addr, unsigned type, unsigned long count,
+ void callReadNotify ( epicsGuard < epicsMutex > &,
+ struct dbChannel * dbch, unsigned type, unsigned long count,
cacReadNotify & notify );
- void callStateNotify ( struct dbAddr &addr, unsigned type, unsigned long count,
+ void callStateNotify ( struct dbChannel * dbch, unsigned type, unsigned long count,
const struct db_field_log * pfl, cacStateNotify & notify );
- void subscribe (
+ void subscribe (
epicsGuard < epicsMutex > &,
- struct dbAddr & addr, dbChannelIO & chan,
- unsigned type, unsigned long count, unsigned mask,
+ struct dbChannel * dbch, dbChannelIO & chan,
+ unsigned type, unsigned long count, unsigned mask,
cacStateNotify & notify, cacChannel::ioid * pId );
- void initiatePutNotify (
- epicsGuard < epicsMutex > &, dbChannelIO &, struct dbAddr &,
- unsigned type, unsigned long count, const void * pValue,
- cacWriteNotify & notify, cacChannel::ioid * pId );
+ void initiatePutNotify (
+ epicsGuard < epicsMutex > &, dbChannelIO &, struct dbChannel *,
+ unsigned type, unsigned long count, const void * pValue,
+ cacWriteNotify & notify, cacChannel::ioid * pId );
void show ( unsigned level ) const;
void showAllIO ( const dbChannelIO & chan, unsigned level ) const;
- void destroyAllIO (
+ void destroyAllIO (
epicsGuard < epicsMutex > &, dbChannelIO & chan );
- void ioCancel ( epicsGuard < epicsMutex > &,
+ void ioCancel ( epicsGuard < epicsMutex > &,
dbChannelIO & chan, const cacChannel::ioid &id );
void ioShow ( epicsGuard < epicsMutex > &,
const cacChannel::ioid & id, unsigned level ) const;
@@ -202,11 +202,11 @@
epics_auto_ptr < cacContext > pNetContext;
char * pStateNotifyCache;
- cacChannel & createChannel (
+ cacChannel & createChannel (
epicsGuard < epicsMutex > &,
- const char * pChannelName, cacChannelNotify &,
+ const char * pChannelName, cacChannelNotify &,
cacChannel::priLev );
- void flush (
+ void flush (
epicsGuard < epicsMutex > & );
unsigned circuitCount (
epicsGuard < epicsMutex > & ) const;
@@ -214,7 +214,7 @@
epicsGuard < epicsMutex > & ) const;
unsigned beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const;
- void show (
+ void show (
epicsGuard < epicsMutex > &, unsigned level ) const;
dbContext ( const dbContext & );
@@ -226,17 +226,17 @@
{
}
-inline dbContextPrivateListOfIO::~dbContextPrivateListOfIO ()
+inline dbContextPrivateListOfIO::~dbContextPrivateListOfIO ()
{
assert ( ! this->pBlocker );
}
-inline void dbContext::callReadNotify (
- epicsGuard < epicsMutex > & guard, struct dbAddr &addr,
+inline void dbContext::callReadNotify (
+ epicsGuard < epicsMutex > & guard, struct dbChannel * dbch,
unsigned type, unsigned long count, cacReadNotify & notifyIn )
{
guard.assertIdenticalMutex ( this-> mutex );
- this->readNotifyCache.callReadNotify ( guard, addr, type, count, notifyIn );
+ this->readNotifyCache.callReadNotify ( guard, dbch, type, count, notifyIn );
}
#endif // dbCACh
=== modified file 'src/ioc/db/dbCa.c'
--- src/ioc/db/dbCa.c 2012-05-04 18:38:59 +0000
+++ src/ioc/db/dbCa.c 2012-05-30 18:10:27 +0000
@@ -411,6 +411,13 @@
return pca->isConnected;
}
+void dbCaScanFwdLink(struct link *plink) {
+ short fwdLinkValue = 1;
+
+ if (plink->value.pv_link.pvlMask & pvlOptFWD)
+ dbCaPutLink(plink, DBR_SHORT, &fwdLinkValue, 1);
+}
+
#define pcaGetCheck \
assert(plink); \
if (plink->type != CA_LINK) return -1; \
@@ -639,7 +646,7 @@
static void eventCallback(struct event_handler_args arg)
{
caLink *pca = (caLink *)arg.usr;
- DBLINK *plink;
+ struct link *plink;
size_t size;
dbCommon *precord = 0;
struct dbr_time_double *pdbr_time_double;
=== modified file 'src/ioc/db/dbCa.h'
--- src/ioc/db/dbCa.h 2009-04-29 18:24:25 +0000
+++ src/ioc/db/dbCa.h 2012-05-30 18:10:27 +0000
@@ -40,6 +40,7 @@
#define dbCaPutLink(plink, dbrType, pbuffer, nRequest) \
dbCaPutLinkCallback((plink), (dbrType), (pbuffer), (nRequest), 0, 0)
epicsShareFunc int dbCaIsLinkConnected(const struct link *plink);
+epicsShareFunc void dbCaScanFwdLink(struct link *plink);
/* The following are available after the link is connected*/
epicsShareFunc long dbCaGetNelements(const struct link *plink,
=== added file 'src/ioc/db/dbChannel.c'
--- src/ioc/db/dbChannel.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbChannel.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,864 @@
+/*************************************************************************\
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Andrew Johnson <[email protected]>
+ * Ralph Lange <[email protected]>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "cantProceed.h"
+#include "dbChannel.h"
+#include "dbCommon.h"
+#include "dbBase.h"
+#include "dbEvent.h"
+#include "link.h"
+#include <freeList.h>
+#include "dbAccessDefs.h"
+#include "dbLock.h"
+#include "dbStaticLib.h"
+#include "epicsAssert.h"
+#include "errlog.h"
+#include "gpHash.h"
+#include "recSup.h"
+#include "special.h"
+#include "yajl_parse.h"
+
+/* The following is defined in db_convert.h */
+extern unsigned short dbDBRnewToDBRold[DBR_ENUM+1];
+
+typedef struct parseContext {
+ dbChannel *chan;
+ chFilter *filter;
+ int depth;
+} parseContext;
+
+#define CALLIF(rtn) !rtn ? parse_stop : rtn
+
+static void *dbchStringFreeList;
+
+void dbChannelInit (void)
+{
+ if (!dbchStringFreeList) {
+ freeListInitPvt(&dbchStringFreeList,
+ sizeof(epicsOldString), 128);
+ }
+}
+
+static void chf_value(parseContext *parser, parse_result *presult)
+{
+ chFilter *filter = parser->filter;
+
+ if (*presult == parse_stop || parser->depth > 0)
+ return;
+
+ parser->filter = NULL;
+ if (filter->plug->fif->parse_end(filter) == parse_continue) {
+ ellAdd(&parser->chan->filters, &filter->list_node);
+ } else {
+ free(filter); // FIXME: Use free-list
+ *presult = parse_stop;
+ }
+}
+
+static int chf_null(void * ctx)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ parse_result result;
+
+ assert(filter);
+ result = CALLIF(filter->plug->fif->parse_null)(filter );
+ chf_value(parser, &result);
+ return result;
+}
+
+static int chf_boolean(void * ctx, int boolVal)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ parse_result result;
+
+ assert(filter);
+ result = CALLIF(filter->plug->fif->parse_boolean)(filter , boolVal);
+ chf_value(parser, &result);
+ return result;
+}
+
+static int chf_integer(void * ctx, long integerVal)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ parse_result result;
+
+ assert(filter);
+ result = CALLIF(filter->plug->fif->parse_integer)(filter , integerVal);
+ chf_value(parser, &result);
+ return result;
+}
+
+static int chf_double(void * ctx, double doubleVal)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ parse_result result;
+
+ assert(filter);
+ result = CALLIF(filter->plug->fif->parse_double)(filter , doubleVal);
+ chf_value(parser, &result);
+ return result;
+}
+
+static int chf_string(void * ctx, const unsigned char * stringVal,
+ unsigned int stringLen)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ parse_result result;
+
+ assert(filter);
+ result = CALLIF(filter->plug->fif->parse_string)(filter , (const char *) stringVal, stringLen);
+ chf_value(parser, &result);
+ return result;
+}
+
+static int chf_start_map(void * ctx)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+
+ if (!filter) {
+ assert(parser->depth == 0);
+ return parse_continue; /* Opening '{' */
+ }
+
+ ++parser->depth;
+ return CALLIF(filter->plug->fif->parse_start_map)(filter );
+}
+
+static int chf_map_key(void * ctx, const unsigned char * key,
+ unsigned int stringLen)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ const chFilterPlugin *plug;
+ parse_result result;
+
+ if (filter) {
+ assert(parser->depth > 0);
+ return CALLIF(filter->plug->fif->parse_map_key)(filter , (const char *) key, stringLen);
+ }
+
+ assert(parser->depth == 0);
+ plug = dbFindFilter((const char *) key, stringLen);
+ if (!plug) {
+ printf("dbChannelCreate: Channel filter '%.*s' not found\n", stringLen, key);
+ return parse_stop;
+ }
+
+ /* FIXME: Use a free-list */
+ filter = (chFilter *) callocMustSucceed(1, sizeof(*filter), "Creating dbChannel filter");
+ filter->chan = parser->chan;
+ filter->plug = plug;
+ filter->puser = NULL;
+
+ result = plug->fif->parse_start(filter);
+ if (result == parse_continue) {
+ parser->filter = filter;
+ } else {
+ free(filter); // FIXME: Use free-list
+ }
+ return result;
+}
+
+static int chf_end_map(void * ctx)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ parse_result result;
+
+ if (!filter) {
+ assert(parser->depth == 0);
+ return parse_continue; /* Final closing '}' */
+ }
+
+ assert(parser->depth > 0);
+ result = CALLIF(filter->plug->fif->parse_end_map)(filter );
+
+ --parser->depth;
+ chf_value(parser, &result);
+ return result;
+}
+
+static int chf_start_array(void * ctx)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+
+ assert(filter);
+ ++parser->depth;
+ return CALLIF(filter->plug->fif->parse_start_array)(filter );
+}
+
+static int chf_end_array(void * ctx)
+{
+ parseContext *parser = (parseContext *) ctx;
+ chFilter *filter = parser->filter;
+ parse_result result;
+
+ assert(filter);
+ result = CALLIF(filter->plug->fif->parse_end_array)(filter );
+ --parser->depth;
+ chf_value(parser, &result);
+ return result;
+}
+
+static const yajl_callbacks chf_callbacks =
+ { chf_null, chf_boolean, chf_integer, chf_double, NULL, chf_string,
+ chf_start_map, chf_map_key, chf_end_map, chf_start_array, chf_end_array };
+
+static const yajl_parser_config chf_config =
+ { 0, 1 }; /* allowComments = NO , checkUTF8 = YES */
+
+static void * chf_malloc(void *ctx, unsigned int sz)
+{
+ return malloc(sz); /* FIXME: free-list */
+}
+
+static void * chf_realloc(void *ctx, void *ptr, unsigned int sz)
+{
+ return realloc(ptr, sz); /* FIXME: free-list */
+}
+
+static void chf_free(void *ctx, void *ptr)
+{
+ return free(ptr); /* FIXME: free-list */
+}
+
+static const yajl_alloc_funcs chf_alloc =
+ { chf_malloc, chf_realloc, chf_free };
+
+static long chf_parse(dbChannel *chan, const char **pjson)
+{
+ parseContext parser =
+ { chan, NULL, 0 };
+ yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_config, &chf_alloc, &parser);
+ const char *json = *pjson;
+ size_t jlen = strlen(json);
+ yajl_status ys;
+ long status;
+
+ if (!yh)
+ return S_db_noMemory;
+
+ ys = yajl_parse(yh, (const unsigned char *) json, jlen);
+ if (ys == yajl_status_insufficient_data)
+ ys = yajl_parse_complete(yh);
+
+ switch (ys) {
+ case yajl_status_ok:
+ status = 0;
+ *pjson += yajl_get_bytes_consumed(yh);
+ break;
+
+ case yajl_status_error: {
+ unsigned char *err;
+
+ err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
+ printf("dbChannelCreate: %s\n", err);
+ yajl_free_error(yh, err);
+ } /* fall through */
+ default:
+ status = S_db_notFound;
+ }
+
+ if (parser.filter) {
+ assert(status);
+ parser.filter->plug->fif->parse_abort(parser.filter);
+ free(parser.filter); /* FIXME: free-list */
+ }
+ yajl_free(yh);
+ return status;
+}
+
+static long pvNameLookup(DBENTRY *pdbe, const char **ppname)
+{
+ long status;
+
+ dbInitEntry(pdbbase, pdbe);
+
+ status = dbFindRecordPart(pdbe, ppname);
+ if (status)
+ return status;
+
+ if (**ppname == '.')
+ ++*ppname;
+
+ status = dbFindFieldPart(pdbe, ppname);
+ if (status == S_dbLib_fieldNotFound)
+ status = dbGetAttributePart(pdbe, ppname);
+
+ return status;
+}
+
+long dbChannelTest(const char *name)
+{
+ DBENTRY dbEntry;
+ long status;
+
+ if (!name || !*name || !pdbbase)
+ return S_db_notFound;
+
+ status = pvNameLookup(&dbEntry, &name);
+
+ dbFinishEntry(&dbEntry);
+ return status;
+}
+
+#define TRY(Func, Arg) \
+if (Func) { \
+ result = Func Arg; \
+ if (result != parse_continue) goto failure; \
+}
+
+static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppnext) {
+ epicsInt32 start = 0;
+ epicsInt32 end = -1;
+ epicsInt32 incr = 1;
+ epicsInt32 l;
+ char *pnext;
+ short exist;
+ chFilter *filter;
+ const chFilterPlugin *plug;
+ parse_result result;
+ long status = 0;
+
+ /* If no number is present, strtol() returns 0 and sets pnext=pname,
+ else pnext points to the first char after the number */
+ pname++;
+ l = strtol(pname, &pnext, 0);
+ exist = pnext - pname;
+ if (exist) start = l;
+ pname = pnext;
+ if (*pname == ']' && exist) {
+ end = start;
+ goto insertplug;
+ }
+ if (*pname != ':') {
+ status = S_dbLib_fieldNotFound;
+ goto finish;
+ }
+ pname++;
+ l = strtol(pname, &pnext, 0);
+ exist = pnext - pname;
+ pname = pnext;
+ if (*pname == ']') {
+ if (exist) end = l;
+ goto insertplug;
+ }
+ if (exist) incr = l;
+ if (*pname != ':') {
+ status = S_dbLib_fieldNotFound;
+ goto finish;
+ }
+ pname++;
+ l = strtol(pname, &pnext, 0);
+ exist = pnext - pname;
+ if (exist) end = l;
+ pname = pnext;
+ if (*pname != ']') {
+ status = S_dbLib_fieldNotFound;
+ goto finish;
+ }
+
+ insertplug:
+ pname++;
+ *ppnext = pname;
+
+ plug = dbFindFilter("arr", 3);
+ if (!plug) {
+ status = S_dbLib_fieldNotFound;
+ goto finish;
+ }
+
+ /* FIXME: Use a free-list */
+ filter = (chFilter *) callocMustSucceed(1, sizeof(*filter), "Creating 'arr' dbChannel filter");
+ filter->chan = chan;
+ filter->plug = plug;
+ filter->puser = NULL;
+
+ TRY(filter->plug->fif->parse_start, (filter));
+ TRY(filter->plug->fif->parse_start_map, (filter));
+ if (start != 0) {
+ TRY(filter->plug->fif->parse_map_key, (filter, "s", 1));
+ TRY(filter->plug->fif->parse_integer, (filter, start));
+ }
+ if (incr != 1) {
+ TRY(filter->plug->fif->parse_map_key, (filter, "i", 1));
+ TRY(filter->plug->fif->parse_integer, (filter, incr));
+ }
+ if (end != -1) {
+ TRY(filter->plug->fif->parse_map_key, (filter, "e", 1));
+ TRY(filter->plug->fif->parse_integer, (filter, end));
+ }
+ TRY(filter->plug->fif->parse_end_map, (filter));
+ TRY(filter->plug->fif->parse_end, (filter));
+
+ ellAdd(&chan->filters, &filter->list_node);
+ return 0;
+
+ failure:
+ free(filter); // FIXME: Use free-list
+ status = S_dbLib_fieldNotFound;
+
+ finish:
+ 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_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;
+ DBENTRY dbEntry;
+ dbChannel *chan = NULL;
+ dbAddr *paddr;
+ dbFldDes *pflddes;
+ long status;
+ short dbfType;
+
+ if (!name || !*name || !pdbbase)
+ return NULL;
+
+ status = pvNameLookup(&dbEntry, &pname);
+ if (status)
+ goto finish;
+
+ /* FIXME: Use free-list */
+ chan = (dbChannel *) callocMustSucceed(1, sizeof(*chan), "dbChannelCreate");
+ chan->name = strdup(name); /* FIXME: free-list */
+ ellInit(&chan->filters);
+ ellInit(&chan->pre_chain);
+ ellInit(&chan->post_chain);
+
+ paddr = &chan->addr;
+ pflddes = dbEntry.pflddes;
+ dbfType = pflddes->field_type;
+
+ paddr->precord = dbEntry.precnode->precord;
+ paddr->pfield = dbEntry.pfield;
+ paddr->pfldDes = pflddes;
+ paddr->no_elements = 1;
+ paddr->field_type = dbfType;
+ paddr->field_size = pflddes->size;
+ paddr->special = pflddes->special;
+ paddr->dbr_field_type = mapDBFToDBR[dbfType];
+
+ /* Handle field modifiers */
+ if (*pname) {
+ if (*pname == '$') {
+ /* Some field types can be accessed as char arrays */
+ if (dbfType == DBF_STRING) {
+ paddr->no_elements = pflddes->size;
+ paddr->field_type = DBF_CHAR;
+ paddr->field_size = 1;
+ paddr->dbr_field_type = DBR_CHAR;
+ } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
+ /* Clients see a char array, but keep original dbfType */
+ paddr->no_elements = PVNAME_STRINGSZ + 12;
+ paddr->field_size = 1;
+ paddr->dbr_field_type = DBR_CHAR;
+ } else {
+ status = S_dbLib_fieldNotFound;
+ goto finish;
+ }
+ pname++;
+ }
+
+ if (*pname == '[') {
+ status = parseArrayRange(chan, pname, &pname);
+ if (status) goto finish;
+ }
+
+ /* JSON may follow */
+ if (*pname == '{') {
+ status = chf_parse(chan, &pname);
+ if (status) goto finish;
+ }
+
+ /* Make sure there's nothing else */
+ if (*pname) {
+ status = S_dbLib_fieldNotFound;
+ goto finish;
+ }
+ }
+
+ if (paddr->special == SPC_DBADDR) {
+ struct rset *prset = dbGetRset(paddr);
+
+ /* Let record type modify the dbAddr */
+ if (prset && prset->cvt_dbaddr) {
+ status = prset->cvt_dbaddr(paddr);
+ if (status) goto finish;
+ }
+ }
+
+finish:
+ if (status && chan) {
+ dbChannelDelete(chan);
+ chan = NULL;
+ }
+ dbFinishEntry(&dbEntry);
+ return chan;
+}
+
+db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn) {
+ chFilter *filter;
+ ELLNODE *node;
+ db_field_log *pLog = pLogIn;
+
+ for (node = ellFirst(&chan->pre_chain); node && pLog; node = ellNext(node)) {
+ filter = CONTAINER(node, chFilter, pre_node);
+ pLog = filter->pre_func(filter->pre_arg, chan, pLog);
+ }
+ return pLog;
+}
+
+db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn) {
+ chFilter *filter;
+ ELLNODE *node;
+ db_field_log *pLog = pLogIn;
+
+ for (node = ellFirst(&chan->post_chain); node && pLog; node = ellNext(node)) {
+ filter = CONTAINER(node, chFilter, post_node);
+ pLog = filter->post_func(filter->post_arg, chan, pLog);
+ }
+ return pLog;
+}
+
+long dbChannelOpen(dbChannel *chan)
+{
+ chFilter *filter;
+ chPostEventFunc *func;
+ void *arg;
+ long status;
+ ELLNODE *node;
+
+ for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
+ filter = CONTAINER(node, chFilter, list_node);
+ /* Call channel_open */
+ status = 0;
+ if (filter->plug->fif->channel_open)
+ status = filter->plug->fif->channel_open(filter);
+ if (status) return status;
+ }
+
+ /* Set up type probe */
+ db_field_log probe;
+ db_field_log p;
+ probe.field_type = dbChannelFieldType(chan);
+ probe.no_elements = dbChannelElements(chan);
+ probe.field_size = dbChannelFieldSize(chan);
+ p = probe;
+
+ /*
+ * Build up the pre- and post-event-queue filter chains
+ * Separate loops because the probe must reach the filters in the right order.
+ */
+ for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
+ filter = CONTAINER(node, chFilter, list_node);
+ func = NULL;
+ arg = NULL;
+ if (filter->plug->fif->channel_register_pre) {
+ filter->plug->fif->channel_register_pre(filter, &func, &arg, &p);
+ if (func) {
+ ellAdd(&chan->pre_chain, &filter->pre_node);
+ filter->pre_func = func;
+ filter->pre_arg = arg;
+ probe = p;
+ }
+ }
+ }
+ for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
+ filter = CONTAINER(node, chFilter, list_node);
+ func = NULL;
+ arg = NULL;
+ if (filter->plug->fif->channel_register_post) {
+ filter->plug->fif->channel_register_post(filter, &func, &arg, &p);
+ if (func) {
+ ellAdd(&chan->post_chain, &filter->post_node);
+ filter->post_func = func;
+ filter->post_arg = arg;
+ probe = p;
+ }
+ }
+ }
+
+ /* Save probe results */
+ chan->final_no_elements = probe.no_elements;
+ chan->final_field_size = probe.field_size;
+ chan->final_type = probe.field_type;
+ chan->dbr_final_type = dbDBRnewToDBRold[mapDBFToDBR[probe.field_type]];
+
+ return 0;
+}
+
+/* FIXME: For performance we should make these one-liners into macros,
+ * or try to make them inline if all our compilers can do that.
+ */
+const char * dbChannelName(dbChannel *chan)
+{
+ return chan->name;
+}
+
+struct dbCommon * dbChannelRecord(dbChannel *chan)
+{
+ return chan->addr.precord;
+}
+
+struct dbFldDes * dbChannelFldDes(dbChannel *chan)
+{
+ return chan->addr.pfldDes;
+}
+
+long dbChannelElements(dbChannel *chan)
+{
+ return chan->addr.no_elements;
+}
+
+short dbChannelFieldType(dbChannel *chan)
+{
+ return chan->addr.field_type;
+}
+
+short dbChannelExportType(dbChannel *chan)
+{
+ return chan->addr.dbr_field_type;
+}
+
+short dbChannelFieldSize(dbChannel *chan)
+{
+ return chan->addr.field_size;
+}
+
+long dbChannelFinalElements(dbChannel *chan)
+{
+ return chan->final_no_elements;
+}
+
+short dbChannelFinalFieldType(dbChannel *chan)
+{
+ return chan->final_type;
+}
+
+short dbChannelFinalExportType(dbChannel *chan)
+{
+ return chan->dbr_final_type;
+}
+
+short dbChannelFinalFieldSize(dbChannel *chan)
+{
+ return chan->final_field_size;
+}
+
+short dbChannelSpecial(dbChannel *chan)
+{
+ return chan->addr.special;
+}
+
+void * dbChannelField(dbChannel *chan)
+{
+ /* Channel filters do not get to interpose here since there are many
+ * places where the field pointer is compared with the address of a
+ * specific record field, so they can't modify the pointer value.
+ */
+ return chan->addr.pfield;
+}
+
+/* Only use dbChannelGet() if the record is already locked. */
+long dbChannelGet(dbChannel *chan, short type, void *pbuffer,
+ long *options, long *nRequest, void *pfl)
+{
+ /* FIXME: Vector through chan->get() ? */
+ return dbGet(&chan->addr, type, pbuffer, options, nRequest, pfl);
+}
+
+long dbChannelGetField(dbChannel *chan, short dbrType, void *pbuffer,
+ long *options, long *nRequest, void *pfl)
+{
+ dbCommon *precord = chan->addr.precord;
+ long status = 0;
+
+ dbScanLock(precord);
+ status = dbChannelGet(chan, dbrType, pbuffer, options, nRequest, pfl);
+ dbScanUnlock(precord);
+ return status;
+}
+
+/* Only use dbChannelPut() if the record is already locked.
+ * This routine doesn't work on link fields, ignores DISP, and
+ * doesn't trigger record processing on PROC or pp(TRUE).
+ */
+long dbChannelPut(dbChannel *chan, short type, const void *pbuffer,
+ long nRequest)
+{
+ /* FIXME: Vector through chan->put() ? */
+ return dbPut(&chan->addr, type, pbuffer, nRequest);
+}
+
+long dbChannelPutField(dbChannel *chan, short type, const void *pbuffer,
+ long nRequest)
+{
+ /* FIXME: Vector through chan->putField() ? */
+ return dbPutField(&chan->addr, type, pbuffer, nRequest);
+}
+
+void dbChannelShow(dbChannel *chan, int level, const unsigned short indent)
+{
+ long elems = chan->addr.no_elements;
+ long felems = chan->final_no_elements;
+ int count = ellCount(&chan->filters);
+ int pre = ellCount(&chan->pre_chain);
+ int post = ellCount(&chan->post_chain);
+
+ printf("%*schannel name: %s\n", indent, "", chan->name);
+ /* FIXME: show field_type as text */
+ printf("%*s field_type=%d (%dB), %ld element%s, %d filter%s", indent, "",
+ chan->addr.field_type, chan->addr.field_size, elems, elems == 1 ? "" : "s",
+ count, count == 1 ? "" : "s");
+ if (count)
+ printf(" (%d pre eventq, %d post eventq)\n", pre, post);
+ else
+ printf("\n");
+ if (level > 0)
+ dbChannelFilterShow(chan, level - 1, indent + 2);
+ if (count) {
+ /* FIXME: show field_type as text */
+ printf("%*s final field_type=%d (%dB), %ld element%s\n", indent, "",
+ chan->final_type, chan->final_field_size, felems, felems == 1 ? "" : "s");
+ }
+}
+
+void dbChannelFilterShow(dbChannel *chan, int level, const unsigned short indent)
+{
+ chFilter *filter = (chFilter *) ellFirst(&chan->filters);
+ while (filter) {
+ filter->plug->fif->channel_report(filter, level, indent);
+ filter = (chFilter *) ellNext(&filter->list_node);
+ }
+}
+
+void dbChannelDelete(dbChannel *chan)
+{
+ chFilter *filter;
+
+ /* Close filters in reverse order */
+ while ((filter = (chFilter *) ellPop(&chan->filters))) {
+ filter->plug->fif->channel_close(filter);
+ free(filter);
+ }
+ free((char *) chan->name); // FIXME: Use free-list
+ free(chan); // FIXME: Use free-list
+}
+
+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;
+
+ if (!pfl->type == dbfl_type_rec) return;
+
+ struct dbCommon *prec = dbChannelRecord(chan);
+ 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)
+{
+ GPHENTRY *pgph;
+ chFilterPlugin *pfilt;
+
+ if (!pdbbase) {
+ printf("dbRegisterFilter: pdbbase not set!\n");
+ return;
+ }
+
+ pgph = gphFind(pdbbase->pgpHash, name, &pdbbase->filterList);
+ if (pgph)
+ return;
+
+ pfilt = dbCalloc(1, sizeof(chFilterPlugin));
+ pfilt->name = strdup(name);
+ pfilt->fif = fif;
+ pfilt->puser = puser;
+
+ ellAdd(&pdbbase->filterList, &pfilt->node);
+ pgph = gphAdd(pdbbase->pgpHash, pfilt->name, &pdbbase->filterList);
+ if (!pgph) {
+ free((void *) pfilt->name);
+ free(pfilt);
+ printf("dbRegisterFilter: gphAdd failed\n");
+ return;
+ }
+ pgph->userPvt = pfilt;
+}
+
+const chFilterPlugin * dbFindFilter(const char *name, size_t len)
+{
+ GPHENTRY *pgph = gphFindParse(pdbbase->pgpHash, name, len,
+ &pdbbase->filterList);
+
+ if (!pgph)
+ return NULL;
+ return (chFilterPlugin *) pgph->userPvt;
+}
=== added file 'src/ioc/db/dbChannel.h'
--- src/ioc/db/dbChannel.h 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbChannel.h 2012-05-30 18:10:27 +0000
@@ -0,0 +1,181 @@
+/*************************************************************************\
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Andrew Johnson <[email protected]>
+ * Ralph Lange <[email protected]>
+ */
+
+#ifndef INC_dbChannel_H
+#define INC_dbChannel_H
+
+#include "dbDefs.h"
+#include "dbAddr.h"
+#include "ellLib.h"
+#include "epicsTypes.h"
+#include "errMdef.h"
+#include "shareLib.h"
+#include "db_field_log.h"
+#include "dbEvent.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * event subscription
+ */
+typedef struct evSubscrip {
+ ELLNODE node;
+ struct dbChannel *chan;
+ EVENTFUNC *user_sub;
+ void *user_arg;
+ struct event_que *ev_que;
+ db_field_log **pLastLog;
+ unsigned long npend; /* n times this event is on the queue */
+ unsigned long nreplace; /* n times replacing event on the queue */
+ unsigned char select;
+ char useValque;
+ char callBackInProgress;
+ char enabled;
+} evSubscrip;
+
+typedef struct chFilter chFilter;
+
+/* A dbChannel points to a record field, and can have multiple filters */
+typedef struct dbChannel {
+ const char *name;
+ dbAddr addr; /* address structure for record/field */
+ long final_no_elements; /* final number of elements (arrays) */
+ short final_field_size; /* final size of element */
+ short final_type; /* final type of database field */
+ short dbr_final_type; /* final field type as seen by database request */
+ ELLLIST filters; /* list of filters as created from JSON */
+ ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
+ ELLLIST post_chain; /* list of filters to be called post-event-queue */
+} dbChannel;
+
+/* Prototype for the post event function that is called in filter stacks */
+typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
+
+/* Return values from chFilterIf->parse_* routines: */
+typedef enum {
+ parse_stop, parse_continue
+} parse_result;
+
+/* These routines must be implemented by each filter plug-in */
+typedef struct chFilterIf {
+ /* Parsing event handlers: */
+ parse_result (* parse_start)(chFilter *filter);
+ /* If parse_start() returns parse_continue for a filter, one of
+ * parse_abort() or parse_end() will later be called for that same
+ * filter.
+ */
+ void (* parse_abort)(chFilter *filter);
+ /* If parse_abort() is called it should release any memory allocated
+ * for this filter; no further parse_...() calls will be made;
+ */
+ parse_result (* parse_end)(chFilter *filter);
+ /* If parse_end() returns parse_stop it should have released any
+ * memory allocated for this filter; no further parse_...() calls will
+ * be made in this case.
+ */
+
+ parse_result (* parse_null)(chFilter *filter);
+ parse_result (* parse_boolean)(chFilter *filter, int boolVal);
+ parse_result (* parse_integer)(chFilter *filter, long integerVal);
+ parse_result (* parse_double)(chFilter *filter, double doubleVal);
+ parse_result (* parse_string)(chFilter *filter, const char *stringVal,
+ size_t stringLen); /* NB: stringVal is not zero-terminated: */
+
+ parse_result (* parse_start_map)(chFilter *filter);
+ parse_result (* parse_map_key)(chFilter *filter, const char *key,
+ size_t stringLen); /* NB: key is not zero-terminated: */
+ parse_result (* parse_end_map)(chFilter *filter);
+
+ parse_result (* parse_start_array)(chFilter *filter);
+ parse_result (* parse_end_array)(chFilter *filter);
+
+ /* Channel operations: */
+ long (* channel_open)(chFilter *filter);
+ void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
+ void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
+ void (* channel_report)(chFilter *filter, int level, const unsigned short indent);
+ /* FIXME: More filter routines here ... */
+ void (* channel_close)(chFilter *filter);
+} chFilterIf;
+
+/* A chFilterPlugin holds data for a filter plugin */
+typedef struct chFilterPlugin {
+ ELLNODE node;
+ const char *name;
+ const chFilterIf *fif;
+ void *puser;
+} chFilterPlugin;
+
+/* A chFilter holds data for a single filter instance */
+struct chFilter {
+ ELLNODE list_node;
+ ELLNODE pre_node;
+ ELLNODE post_node;
+ dbChannel *chan;
+ const chFilterPlugin *plug;
+ chPostEventFunc *pre_func;
+ void *pre_arg;
+ chPostEventFunc *post_func;
+ void *post_arg;
+ void *puser;
+};
+
+struct dbCommon;
+struct dbFldDes;
+
+epicsShareFunc void dbChannelInit (void);
+epicsShareFunc long dbChannelTest(const char *name);
+epicsShareFunc dbChannel * dbChannelCreate(const char *name);
+epicsShareFunc long dbChannelOpen(dbChannel *chan);
+epicsShareFunc const char * dbChannelName(dbChannel *chan);
+epicsShareFunc struct dbCommon * dbChannelRecord(dbChannel *chan);
+epicsShareFunc struct dbFldDes * dbChannelFldDes(dbChannel *chan);
+epicsShareFunc long dbChannelElements(dbChannel *chan);
+epicsShareFunc short dbChannelFieldType(dbChannel *chan);
+epicsShareFunc short dbChannelExportType(dbChannel *chan);
+epicsShareFunc short dbChannelFieldSize(dbChannel *chan);
+epicsShareFunc long dbChannelFinalElements(dbChannel *chan);
+epicsShareFunc short dbChannelFinalFieldType(dbChannel *chan);
+epicsShareFunc short dbChannelFinalExportType(dbChannel *chan);
+epicsShareFunc short dbChannelFinalElementSize(dbChannel *chan);
+epicsShareFunc short dbChannelSpecial(dbChannel *chan);
+epicsShareFunc void * dbChannelField(dbChannel *chan);
+epicsShareFunc long dbChannelGet(dbChannel *chan, short type,
+ void *pbuffer, long *options, long *nRequest, void *pfl);
+epicsShareFunc long dbChannelGetField(dbChannel *chan, short type,
+ void *pbuffer, long *options, long *nRequest, void *pfl);
+epicsShareFunc long dbChannelPut(dbChannel *chan, short type,
+ const void *pbuffer, long nRequest);
+epicsShareFunc long dbChannelPutField(dbChannel *chan, short type,
+ const void *pbuffer, long nRequest);
+epicsShareFunc void dbChannelShow(dbChannel *chan, int level,
+ const unsigned short indent);
+epicsShareFunc void dbChannelFilterShow(dbChannel *chan, int level,
+ const unsigned short indent);
+epicsShareFunc void dbChannelDelete(dbChannel *chan);
+
+epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
+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
+}
+#endif
+
+#endif /* INC_dbChannel_H */
=== modified file 'src/ioc/db/dbChannelIO.cpp'
--- src/ioc/db/dbChannelIO.cpp 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbChannelIO.cpp 2012-05-30 18:10:27 +0000
@@ -4,20 +4,20 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/*
+/*
* $Revision-Id$
*
- *
+ *
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
- *
+ *
* Copyright, 1986, The Regents of the University of California.
- *
- *
+ *
+ *
* Author Jeffrey O. Hill
* [email protected]
* 505 665 1831
@@ -40,15 +40,12 @@
#include "dbChannelIO.h"
#include "dbPutNotifyBlocker.h"
-dbChannelIO::dbChannelIO (
- epicsMutex & mutexIn, cacChannelNotify & notify,
- const dbAddr & addrIn, dbContext & serviceIO ) :
- cacChannel ( notify ), mutex ( mutexIn ), serviceIO ( serviceIO ),
- addr ( addrIn )
+dbChannelIO::dbChannelIO (
+ epicsMutex & mutexIn, cacChannelNotify & notify,
+ dbChannel * dbchIn, dbContext & serviceIO ) :
+ cacChannel ( notify ), mutex ( mutexIn ), serviceIO ( serviceIO ),
+ dbch ( dbchIn )
{
- unsigned bufLen = dbNameSizeOfPV ( & this->addr ) + 1;
- this->pNameStr.reset ( new char [ bufLen ] );
- dbNameOfPV ( & this->addr, this->pNameStr.get (), bufLen );
}
void dbChannelIO::initiateConnect ( epicsGuard < epicsMutex > & guard )
@@ -57,7 +54,7 @@
this->notify().connectNotify ( guard );
}
-dbChannelIO::~dbChannelIO ()
+dbChannelIO::~dbChannelIO ()
{
}
@@ -65,48 +62,49 @@
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.destroyAllIO ( guard, *this );
+ dbChannelDelete ( this->dbch );
this->~dbChannelIO ();
}
-void dbChannelIO::destroy (
+void dbChannelIO::destroy (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.destroyChannel ( guard, *this );
- // dont access this pointer after above call because
- // object nolonger exists
+ // don't access this pointer after above call because
+ // object no longer exists
}
-cacChannel::ioStatus dbChannelIO::read (
- epicsGuard < epicsMutex > & guard, unsigned type,
- unsigned long count, cacReadNotify & notify, ioid * )
+cacChannel::ioStatus dbChannelIO::read (
+ epicsGuard < epicsMutex > & guard, unsigned type,
+ unsigned long count, cacReadNotify & notify, ioid * )
{
guard.assertIdenticalMutex ( this->mutex );
- this->serviceIO.callReadNotify ( guard, this->addr,
+ this->serviceIO.callReadNotify ( guard, this->dbch,
type, count, notify );
return iosSynch;
}
-void dbChannelIO::write (
- epicsGuard < epicsMutex > & guard, unsigned type,
+void dbChannelIO::write (
+ epicsGuard < epicsMutex > & guard, unsigned type,
unsigned long count, const void *pValue )
{
epicsGuardRelease < epicsMutex > unguard ( guard );
if ( count > LONG_MAX ) {
throw outOfBounds();
}
- int status = db_put_field ( &this->addr, type, pValue,
+ int status = dbChannel_put ( this->dbch, type, pValue,
static_cast <long> (count) );
if ( status ) {
- throw std::logic_error (
+ throw std::logic_error (
"db_put_field() completed unsuccessfully" );
}
}
-cacChannel::ioStatus dbChannelIO::write (
- epicsGuard < epicsMutex > & guard, unsigned type,
- unsigned long count, const void * pValue,
- cacWriteNotify & notify, ioid * pId )
+cacChannel::ioStatus dbChannelIO::write (
+ epicsGuard < epicsMutex > & guard, unsigned type,
+ unsigned long count, const void * pValue,
+ cacWriteNotify & notify, ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -114,24 +112,24 @@
throw outOfBounds();
}
- this->serviceIO.initiatePutNotify (
- guard, *this, this->addr,
+ this->serviceIO.initiatePutNotify (
+ guard, *this, this->dbch,
type, count, pValue, notify, pId );
return iosAsynch;
}
-void dbChannelIO::subscribe (
- epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
- unsigned mask, cacStateNotify & notify, ioid * pId )
-{
+void dbChannelIO::subscribe (
+ epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
+ unsigned mask, cacStateNotify & notify, ioid * pId )
+{
guard.assertIdenticalMutex ( this->mutex );
- this->serviceIO.subscribe (
- guard, this->addr, *this,
+ this->serviceIO.subscribe (
+ guard, this->dbch, *this,
type, count, mask, notify, pId );
}
-void dbChannelIO::ioCancel (
+void dbChannelIO::ioCancel (
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & id )
{
@@ -139,7 +137,7 @@
this->serviceIO.ioCancel ( mutualExclusionGuard, *this, id );
}
-void dbChannelIO::ioShow (
+void dbChannelIO::ioShow (
epicsGuard < epicsMutex > & guard,
const ioid & id, unsigned level ) const
{
@@ -147,31 +145,35 @@
this->serviceIO.ioShow ( guard, id, level );
}
-void dbChannelIO::show (
+void dbChannelIO::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
- printf ("channel at %p attached to local database record %s\n",
- static_cast <const void *> ( this ), this->addr.precord->name );
+ printf ("channel at %p attached to local database record %s\n",
+ static_cast <const void *> ( this ),
+ dbChannelRecord ( this->dbch ) -> name );
if ( level > 0u ) {
- printf ( "\ttype %s, element count %li, field at %p\n",
- dbf_type_to_text ( this->addr.dbr_field_type ), this->addr.no_elements,
- this->addr.pfield );
- }
- if ( level > 1u ) {
- this->serviceIO.show ( level - 2u );
- this->serviceIO.showAllIO ( *this, level - 2u );
+ printf ( " type %s, element count %li, field at %p\n",
+ dbf_type_to_text ( dbChannelExportType ( this->dbch ) ),
+ dbChannelElements ( this->dbch ),
+ dbChannelField ( this->dbch ) );
+ if ( level > 1u ) {
+ dbChannelFilterShow ( this->dbch, level - 2u, 8 );
+ this->serviceIO.show ( level - 2u );
+ this->serviceIO.showAllIO ( *this, level - 2u );
+ }
}
}
unsigned long dbChannelIO::nativeElementCount (
- epicsGuard < epicsMutex > & guard ) const
+ epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
- if ( this->addr.no_elements >= 0u ) {
- return static_cast < unsigned long > ( this->addr.no_elements );
+ long elements = dbChannelElements ( this->dbch );
+ if ( elements >= 0u ) {
+ return static_cast < unsigned long > ( elements );
}
return 0u;
}
@@ -181,24 +183,30 @@
epicsGuard < epicsMutex > & guard ) const throw ()
{
guard.assertIdenticalMutex ( this->mutex );
- return this->pNameStr.get ();
+ return dbChannelName ( this->dbch );
}
unsigned dbChannelIO::getName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLen ) const throw ()
{
- return dbNameOfPV ( & this->addr, pBuf, bufLen );
+ const char *name = dbChannelName ( this->dbch );
+ size_t len = strlen ( name );
+ strncpy ( pBuf, name, bufLen );
+ if (len < bufLen)
+ return len;
+ pBuf[--bufLen] = '\0';
+ return bufLen;
}
short dbChannelIO::nativeType (
- epicsGuard < epicsMutex > & guard ) const
+ epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
- return this->addr.dbr_field_type;
+ return dbChannelExportType( this->dbch );
}
-void * dbChannelIO::operator new ( size_t size,
+void * dbChannelIO::operator new ( size_t size,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
@@ -212,7 +220,7 @@
}
#ifdef CXX_PLACEMENT_DELETE
-void dbChannelIO::operator delete ( void *pCadaver,
+void dbChannelIO::operator delete ( void *pCadaver,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
=== modified file 'src/ioc/db/dbChannelIO.h'
--- src/ioc/db/dbChannelIO.h 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbChannelIO.h 2012-05-30 18:10:27 +0000
@@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -44,65 +44,64 @@
class dbChannelIO : public cacChannel, public dbContextPrivateListOfIO {
public:
- dbChannelIO (
- epicsMutex &, cacChannelNotify &,
- const dbAddr &, dbContext & );
- void destructor (
+ dbChannelIO (
+ epicsMutex &, cacChannelNotify &,
+ dbChannel *, dbContext & );
+ void destructor (
epicsGuard < epicsMutex > & );
void destroy (
epicsGuard < epicsMutex > & mutualExclusionGuard );
- void callReadNotify (
- epicsGuard < epicsMutex > &,
- unsigned type, unsigned long count,
+ void callReadNotify (
+ epicsGuard < epicsMutex > &,
+ unsigned type, unsigned long count,
cacReadNotify & notify );
- void callStateNotify (
- unsigned type, unsigned long count,
+ void callStateNotify (
+ unsigned type, unsigned long count,
const struct db_field_log * pfl, cacStateNotify & notify );
- void show (
+ void show (
epicsGuard < epicsMutex > &, unsigned level ) const;
unsigned getName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLen ) const throw ();
const char * pName (
epicsGuard < epicsMutex > & ) const throw ();
- void * operator new ( size_t size,
+ void * operator new ( size_t size,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & );
- epicsPlacementDeleteOperator (( void *,
+ epicsPlacementDeleteOperator (( void *,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & ))
protected:
~dbChannelIO ();
private:
epicsMutex & mutex;
dbContext & serviceIO;
- dbAddr addr;
- epics_auto_ptr < char, eapt_array > pNameStr;
+ dbChannel * dbch;
void initiateConnect (
epicsGuard < epicsMutex > & );
- unsigned requestMessageBytesPending (
- epicsGuard < epicsMutex > & );
- void flush (
- epicsGuard < epicsMutex > & );
- ioStatus read (
+ unsigned requestMessageBytesPending (
+ epicsGuard < epicsMutex > & );
+ void flush (
+ epicsGuard < epicsMutex > & );
+ ioStatus read (
epicsGuard < epicsMutex > &,
- unsigned type, unsigned long count,
+ unsigned type, unsigned long count,
cacReadNotify &, ioid * );
- void write (
+ void write (
epicsGuard < epicsMutex > &,
- unsigned type, unsigned long count,
+ unsigned type, unsigned long count,
const void * pvalue );
- ioStatus write (
+ ioStatus write (
epicsGuard < epicsMutex > &,
- unsigned type, unsigned long count,
+ unsigned type, unsigned long count,
const void * pvalue, cacWriteNotify &, ioid * );
- void subscribe (
+ void subscribe (
epicsGuard < epicsMutex > &,
- unsigned type, unsigned long count,
+ unsigned type, unsigned long count,
unsigned mask, cacStateNotify ¬ify, ioid * );
- void ioCancel (
+ void ioCancel (
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & );
- void ioShow (
+ void ioShow (
epicsGuard < epicsMutex > &,
const ioid &, unsigned level ) const;
short nativeType (
@@ -115,18 +114,18 @@
void operator delete ( void * );
};
-inline void dbChannelIO::callReadNotify (
- epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
+inline void dbChannelIO::callReadNotify (
+ epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
cacReadNotify & notify )
{
guard.assertIdenticalMutex ( this->mutex );
- this->serviceIO.callReadNotify ( guard, this->addr, type, count, notify );
+ this->serviceIO.callReadNotify ( guard, this->dbch, type, count, notify );
}
-inline void dbChannelIO::callStateNotify ( unsigned type, unsigned long count,
+inline void dbChannelIO::callStateNotify ( unsigned type, unsigned long count,
const struct db_field_log *pfl, cacStateNotify ¬ify )
{
- this->serviceIO.callStateNotify ( this->addr, type, count, pfl, notify );
+ this->serviceIO.callStateNotify ( this->dbch, type, count, pfl, notify );
}
=== modified file 'src/ioc/db/dbContext.cpp'
--- src/ioc/db/dbContext.cpp 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbContext.cpp 2012-05-30 18:10:27 +0000
@@ -4,19 +4,19 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/*
+/*
* $Revision-Id$
*
- *
+ *
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
- *
+ *
* Copyright, 1986, The Regents of the University of California.
- *
- *
+ *
+ *
* Author Jeffrey O. Hill
* [email protected]
* 505 665 1831
@@ -33,6 +33,7 @@
#include "epicsEvent.h"
#include "epicsThread.h"
#include "errlog.h"
+#include "dbChannel.h"
#define epicsExportSharedSymbols
#include "db_access_routines.h"
@@ -43,20 +44,20 @@
class dbService : public cacService {
public:
~dbService () {}
- cacContext & contextCreate (
- epicsMutex & mutualExclusion,
- epicsMutex & callbackControl,
+ cacContext & contextCreate (
+ epicsMutex & mutualExclusion,
+ epicsMutex & callbackControl,
cacContextNotify & );
};
static dbService dbs;
-cacContext & dbService::contextCreate (
- epicsMutex & mutualExclusion,
- epicsMutex & callbackControl,
+cacContext & dbService::contextCreate (
+ epicsMutex & mutualExclusion,
+ epicsMutex & callbackControl,
cacContextNotify & notify )
{
- return * new dbContext ( callbackControl,
+ return * new dbContext ( callbackControl,
mutualExclusion, notify );
}
@@ -67,9 +68,9 @@
dbBaseIO::dbBaseIO () {}
-dbContext::dbContext ( epicsMutex & cbMutexIn,
+dbContext::dbContext ( epicsMutex & cbMutexIn,
epicsMutex & mutexIn, cacContextNotify & notifyIn ) :
- readNotifyCache ( mutexIn ), ctx ( 0 ),
+ readNotifyCache ( mutexIn ), ctx ( 0 ),
stateNotifyCacheSize ( 0 ), mutex ( mutexIn ), cbMutex ( cbMutexIn ),
notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 )
{
@@ -84,41 +85,41 @@
}
cacChannel & dbContext::createChannel ( // X aCC 361
- epicsGuard < epicsMutex > & guard, const char * pName,
+ epicsGuard < epicsMutex > & guard, const char * pName,
cacChannelNotify & notifyIn, cacChannel::priLev priority )
{
guard.assertIdenticalMutex ( this->mutex );
- struct dbAddr addr;
- int status;
- {
- // dont know if the database might call a put callback
- // while holding its lock ...
- epicsGuardRelease < epicsMutex > unguard ( guard );
- status = db_name_to_addr ( pName, & addr );
- }
- if ( status ) {
+ dbChannel *dbch = dbChannel_create ( pName );
+ if ( ! dbch ) {
if ( ! this->pNetContext.get() ) {
this->pNetContext.reset (
- & this->notify.createNetworkContext (
+ & this->notify.createNetworkContext (
this->mutex, this->cbMutex ) );
}
return this->pNetContext->createChannel (
guard, pName, notifyIn, priority );
}
- else if ( ca_preemtive_callback_is_enabled () ) {
- return * new ( this->dbChannelIOFreeList )
- dbChannelIO ( this->mutex, notifyIn, addr, *this );
- }
- else {
- errlogPrintf (
+
+ if ( ! ca_preemtive_callback_is_enabled () ) {
+ dbChannelDelete ( dbch );
+ errlogPrintf (
"dbContext: preemptive callback required for direct in\n"
"memory interfacing of CA channels to the DB.\n" );
throw cacChannel::unsupportedByService ();
}
+
+ try {
+ return * new ( this->dbChannelIOFreeList )
+ dbChannelIO ( this->mutex, notifyIn, dbch, *this );
+ }
+ catch (...) {
+ dbChannelDelete ( dbch );
+ throw;
+ }
}
-void dbContext::destroyChannel (
+void dbContext::destroyChannel (
epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -134,30 +135,30 @@
this->dbChannelIOFreeList.release ( & chan );
}
-void dbContext::callStateNotify ( struct dbAddr & addr,
- unsigned type, unsigned long count,
- const struct db_field_log * pfl,
+void dbContext::callStateNotify ( struct dbChannel * dbch,
+ unsigned type, unsigned long count,
+ const struct db_field_log * pfl,
cacStateNotify & notifyIn )
{
unsigned long size = dbr_size_n ( type, count );
if ( type > INT_MAX ) {
epicsGuard < epicsMutex > guard ( this->mutex );
- notifyIn.exception ( guard, ECA_BADTYPE,
- "type code out of range (high side)",
+ notifyIn.exception ( guard, ECA_BADTYPE,
+ "type code out of range (high side)",
type, count );
return;
}
if ( count > INT_MAX ) {
epicsGuard < epicsMutex > guard ( this->mutex );
- notifyIn.exception ( guard, ECA_BADCOUNT,
+ notifyIn.exception ( guard, ECA_BADCOUNT,
"element count out of range (high side)",
type, count);
return;
}
- // no need to lock this because state notify is
+ // no need to lock this because state notify is
// called from only one event queue consumer thread
if ( this->stateNotifyCacheSize < size) {
char * pTmp = new char [size];
@@ -166,14 +167,14 @@
this->stateNotifyCacheSize = size;
}
void *pvfl = (void *) pfl;
- int status = db_get_field ( &addr, static_cast <int> ( type ),
+ int status = dbChannel_get ( dbch, static_cast <int> ( type ),
this->pStateNotifyCache, static_cast <int> ( count ), pvfl );
if ( status ) {
epicsGuard < epicsMutex > guard ( this->mutex );
- notifyIn.exception ( guard, ECA_GETFAIL,
- "db_get_field() completed unsuccessfuly", type, count );
+ notifyIn.exception ( guard, ECA_GETFAIL,
+ "dbChannel_get() completed unsuccessfully", type, count );
}
- else {
+ else {
epicsGuard < epicsMutex > guard ( this->mutex );
notifyIn.current ( guard, type, count, this->pStateNotifyCache );
}
@@ -185,10 +186,10 @@
assert ( status == ECA_NORMAL );
}
-void dbContext::subscribe (
+void dbContext::subscribe (
epicsGuard < epicsMutex > & guard,
- struct dbAddr & addr, dbChannelIO & chan,
- unsigned type, unsigned long count, unsigned mask,
+ struct dbChannel * dbch, dbChannelIO & chan,
+ unsigned type, unsigned long count, unsigned mask,
cacStateNotify & notifyIn, cacChannel::ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -214,12 +215,12 @@
unsigned selfPriority = epicsThreadGetPrioritySelf ();
unsigned above;
- epicsThreadBooleanStatus tbs =
+ epicsThreadBooleanStatus tbs =
epicsThreadLowestPriorityLevelAbove ( selfPriority, &above );
if ( tbs != epicsThreadBooleanStatusSuccess ) {
above = selfPriority;
}
- int status = db_start_events ( tmpctx, "CAC-event",
+ int status = db_start_events ( tmpctx, "CAC-event",
cacAttachClientCtx, ca_current_context (), above );
if ( status ) {
db_close_events ( tmpctx );
@@ -227,7 +228,7 @@
}
}
if ( this->ctx ) {
- // another thread tried to simultaneously setup
+ // another thread tried to simultaneously setup
// the event system
db_close_events ( tmpctx );
}
@@ -237,9 +238,9 @@
}
dbSubscriptionIO & subscr =
- * new ( this->dbSubscriptionIOFreeList )
- dbSubscriptionIO ( guard, this->mutex, *this, chan,
- addr, notifyIn, type, count, mask, this->ctx );
+ * new ( this->dbSubscriptionIOFreeList )
+ dbSubscriptionIO ( guard, this->mutex, *this, chan,
+ dbch, notifyIn, type, count, mask, this->ctx );
chan.dbContextPrivateListOfIO::eventq.add ( subscr );
this->ioTable.idAssignAdd ( subscr );
@@ -248,27 +249,27 @@
}
}
-void dbContext::initiatePutNotify (
+void dbContext::initiatePutNotify (
epicsGuard < epicsMutex > & guard,
- dbChannelIO & chan, struct dbAddr & addr,
- unsigned type, unsigned long count, const void * pValue,
+ dbChannelIO & chan, struct dbChannel * dbch,
+ unsigned type, unsigned long count, const void * pValue,
cacWriteNotify & notifyIn, cacChannel::ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
if ( ! chan.dbContextPrivateListOfIO::pBlocker ) {
- chan.dbContextPrivateListOfIO::pBlocker =
- new ( this->dbPutNotifyBlockerFreeList )
+ chan.dbContextPrivateListOfIO::pBlocker =
+ new ( this->dbPutNotifyBlockerFreeList )
dbPutNotifyBlocker ( this->mutex );
this->ioTable.idAssignAdd ( *chan.dbContextPrivateListOfIO::pBlocker );
}
- chan.dbContextPrivateListOfIO::pBlocker->initiatePutNotify (
- guard, notifyIn, addr, type, count, pValue );
+ chan.dbContextPrivateListOfIO::pBlocker->initiatePutNotify (
+ guard, notifyIn, dbch, type, count, pValue );
if ( pId ) {
*pId = chan.dbContextPrivateListOfIO::pBlocker->getId ();
}
}
-void dbContext::destroyAllIO (
+void dbContext::destroyAllIO (
epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -284,7 +285,7 @@
}
while ( ( pIO = tmp.get() ) ) {
- // This prevents a db event callback from coming
+ // This prevents a db event callback from coming
// through after the notify IO is deleted
pIO->unsubscribe ( guard );
// If they call ioCancel() here it will be ignored
@@ -301,8 +302,8 @@
}
}
-void dbContext::ioCancel (
- epicsGuard < epicsMutex > & guard, dbChannelIO & chan,
+void dbContext::ioCancel (
+ epicsGuard < epicsMutex > & guard, dbChannelIO & chan,
const cacChannel::ioid &id )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -325,8 +326,8 @@
}
}
-void dbContext::ioShow (
- epicsGuard < epicsMutex > & guard, const cacChannel::ioid &id,
+void dbContext::ioShow (
+ epicsGuard < epicsMutex > & guard, const cacChannel::ioid &id,
unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
@@ -339,7 +340,7 @@
void dbContext::showAllIO ( const dbChannelIO & chan, unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
- tsDLIterConst < dbSubscriptionIO > pItem =
+ tsDLIterConst < dbSubscriptionIO > pItem =
chan.dbContextPrivateListOfIO::eventq.firstIter ();
while ( pItem.valid () ) {
pItem->show ( guard, level );
@@ -356,14 +357,14 @@
this->show ( guard, level );
}
-void dbContext::show (
+void dbContext::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
- printf ( "dbContext at %p\n",
+ printf ( "dbContext at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {
- printf ( "\tevent call back cache location %p, and its size %lu\n",
+ printf ( "\tevent call back cache location %p, and its size %lu\n",
static_cast <void *> ( this->pStateNotifyCache ), this->stateNotifyCacheSize );
this->readNotifyCache.show ( guard, level - 1 );
}
@@ -375,7 +376,7 @@
}
}
-void dbContext::flush (
+void dbContext::flush (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
=== modified file 'src/ioc/db/dbContextReadNotifyCache.cpp'
--- src/ioc/db/dbContextReadNotifyCache.cpp 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbContextReadNotifyCache.cpp 2012-05-30 18:10:27 +0000
@@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -30,11 +30,11 @@
class privateAutoDestroyPtr {
public:
- privateAutoDestroyPtr (
+ privateAutoDestroyPtr (
dbContextReadNotifyCacheAllocator & allocator, unsigned long size ) :
_allocator ( allocator ), _p ( allocator.alloc ( size ) ) {}
~privateAutoDestroyPtr () { _allocator.free ( _p ); }
- char * get () const { return _p; }
+ char * get () const { return _p; }
private:
dbContextReadNotifyCacheAllocator & _allocator;
char * _p;
@@ -43,28 +43,28 @@
};
// extra effort taken here to not hold the lock when calling the callback
-void dbContextReadNotifyCache::callReadNotify (
- epicsGuard < epicsMutex > & guard, struct dbAddr & addr,
+void dbContextReadNotifyCache::callReadNotify (
+ epicsGuard < epicsMutex > & guard, struct dbChannel * dbch,
unsigned type, unsigned long count, cacReadNotify & notify )
{
guard.assertIdenticalMutex ( _mutex );
if ( type > INT_MAX ) {
- notify.exception ( guard, ECA_BADTYPE,
- "type code out of range (high side)",
+ notify.exception ( guard, ECA_BADTYPE,
+ "type code out of range (high side)",
type, count );
return;
}
- if ( addr.no_elements < 0 ) {
- notify.exception ( guard, ECA_BADCOUNT,
+ if ( dbChannelElements(dbch) < 0 ) {
+ notify.exception ( guard, ECA_BADCOUNT,
"database has negetive element count",
type, count);
return;
}
- if ( count > static_cast < unsigned > ( addr.no_elements ) ) {
- notify.exception ( guard, ECA_BADCOUNT,
+ if ( count > static_cast < unsigned long > ( dbChannelElements(dbch) ) ) {
+ notify.exception ( guard, ECA_BADCOUNT,
"element count out of range (high side)",
type, count);
return;
@@ -75,21 +75,21 @@
int status;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
- status = db_get_field ( &addr, static_cast <int> ( type ),
- ptr.get (), static_cast <int> ( count ), 0 );
+ status = dbChannel_get ( dbch, static_cast <int> ( type ),
+ ptr.get (), static_cast <long> ( count ), 0 );
}
if ( status ) {
- notify.exception ( guard, ECA_GETFAIL,
+ notify.exception ( guard, ECA_GETFAIL,
"db_get_field() completed unsuccessfuly",
type, count );
}
- else {
- notify.completion (
+ else {
+ notify.completion (
guard, type, count, ptr.get () );
}
}
-void dbContextReadNotifyCache::show (
+void dbContextReadNotifyCache::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( _mutex );
@@ -155,8 +155,8 @@
pNext = _pReadNotifyCache->pNext;
count++;
}
- printf ( "\tcount %lu and size %lu\n",
- static_cast < unsigned long > ( count ),
+ printf ( "\tcount %lu and size %lu\n",
+ static_cast < unsigned long > ( count ),
_readNotifyCacheSize );
}
}
=== modified file 'src/ioc/db/dbEvent.c'
--- src/ioc/db/dbEvent.c 2011-10-19 18:07:00 +0000
+++ src/ioc/db/dbEvent.c 2012-05-30 18:10:27 +0000
@@ -1,19 +1,20 @@
/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* dbEvent.c */
-/* $Revision-Id$ */
-/* routines for scheduling events to lower priority tasks via the RT kernel */
+
/*
- * Author: Jeffrey O. Hill
- * Date: 4-1-89
-*/
+ * Author: Jeffrey O. Hill <[email protected]>
+ *
+ * Ralph Lange <[email protected]>
+ */
#include <stddef.h>
#include <stdlib.h>
@@ -39,6 +40,7 @@
#include "db_field_log.h"
#define epicsExportSharedSymbols
#include "dbAddr.h"
+#include "dbChannel.h"
#include "dbLock.h"
#include "dbAccessDefs.h"
#include "dbEvent.h"
@@ -49,51 +51,33 @@
#define EVENTQEMPTY ((struct evSubscrip *)NULL)
/*
- * event subscruiption
- */
-struct evSubscrip {
- ELLNODE node;
- struct dbAddr *paddr;
- EVENTFUNC *user_sub;
- void *user_arg;
- struct event_que *ev_que;
- db_field_log *pLastLog;
- unsigned long npend; /* n times this event is on the queue */
- unsigned long nreplace; /* n times replacing event on the queue */
- unsigned char select;
- char valque;
- char callBackInProgress;
- char enabled;
-};
-
-/*
* really a ring buffer
*/
struct event_que {
/* lock writers to the ring buffer only */
/* readers must never slow up writers */
epicsMutexId writelock;
- db_field_log valque[EVENTQUESIZE];
+ db_field_log *valque[EVENTQUESIZE];
struct evSubscrip *evque[EVENTQUESIZE];
struct event_que *nextque; /* in case que quota exceeded */
struct event_user *evUser; /* event user parent struct */
unsigned short putix;
unsigned short getix;
unsigned short quota; /* the number of assigned entries*/
- unsigned short nDuplicates; /* N events duplicated on this q */
+ unsigned short nDuplicates; /* N events duplicated on this q */
unsigned short nCanceled; /* the number of canceled entries */
};
struct event_user {
struct event_que firstque; /* the first event que */
-
+
epicsMutexId lock;
epicsEventId ppendsem; /* Wait while empty */
epicsEventId pflush_sem; /* wait for flush */
-
+
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
void *extralabor_arg;/* parameter to above */
-
+
epicsThreadId taskid; /* event handler task id */
struct evSubscrip *pSuicideEvent; /* event that is deleteing itself */
unsigned queovr; /* event que overflow count */
@@ -114,34 +98,28 @@
#define RNGINC(OLD)\
( (unsigned short) ( (OLD) >= (EVENTQUESIZE-1) ? 0 : (OLD)+1 ) )
-#define LOCKEVQUE(EV_QUE)\
-epicsMutexMustLock((EV_QUE)->writelock);
-
-#define UNLOCKEVQUE(EV_QUE)\
-epicsMutexUnlock((EV_QUE)->writelock);
-
-#define LOCKREC(RECPTR)\
-epicsMutexMustLock((RECPTR)->mlok);
-
-#define UNLOCKREC(RECPTR)\
-epicsMutexUnlock((RECPTR)->mlok);
+#define LOCKEVQUE(EV_QUE) epicsMutexMustLock((EV_QUE)->writelock)
+#define UNLOCKEVQUE(EV_QUE) epicsMutexUnlock((EV_QUE)->writelock)
+#define LOCKREC(RECPTR) epicsMutexMustLock((RECPTR)->mlok)
+#define UNLOCKREC(RECPTR) epicsMutexUnlock((RECPTR)->mlok)
static void *dbevEventUserFreeList;
static void *dbevEventQueueFreeList;
-static void *dbevEventBlockFreeList;
+static void *dbevEventSubscriptionFreeList;
+static void *dbevFieldLogFreeList;
static char *EVENT_PEND_NAME = "eventTask";
static struct evSubscrip canceledEvent;
-static unsigned short ringSpace ( const struct event_que *pevq )
+static unsigned short ringSpace ( const struct event_que *pevq )
{
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
if ( pevq->getix > pevq->putix ) {
return ( unsigned short ) ( pevq->getix - pevq->putix );
}
else {
- return ( unsigned short ) ( ( EVENTQUESIZE + pevq->getix ) - pevq->putix );
+ return ( unsigned short ) ( ( EVENTQUESIZE + pevq->getix ) - pevq->putix );
}
}
return 0;
@@ -163,7 +141,7 @@
DBADDR addr;
long status;
struct evSubscrip *pevent;
- dbFldDes *pdbFldDes;
+ dbFldDes *pdbFldDes;
if ( ! pname ) return DB_EVENT_OK;
status = dbNameToAddr ( pname, &addr );
@@ -172,7 +150,7 @@
return DB_EVENT_ERROR;
}
- LOCKREC ( addr.precord );
+ LOCKREC (addr.precord);
pevent = (struct evSubscrip *) ellFirst ( &addr.precord->mlis );
@@ -186,16 +164,16 @@
ellCount ( &addr.precord->mlis ) );
while ( pevent ) {
- pdbFldDes = pevent->paddr->pfldDes;
+ pdbFldDes = dbChannelFldDes(pevent->chan);
if ( level > 0 ) {
printf ( "%4.4s", pdbFldDes->name );
printf ( " { " );
- if ( pevent->select & DBE_VALUE ) printf( "VALUE " );
- if ( pevent->select & DBE_LOG ) printf( "LOG " );
- if ( pevent->select & DBE_ALARM ) printf( "ALARM " );
- if ( pevent->select & DBE_PROPERTY ) printf( "PROPERTY " );
+ if ( pevent->select & DBE_VALUE ) printf( "VALUE " );
+ if ( pevent->select & DBE_LOG ) printf( "LOG " );
+ if ( pevent->select & DBE_ALARM ) printf( "ALARM " );
+ if ( pevent->select & DBE_PROPERTY ) printf( "PROPERTY " );
printf ( "}" );
if ( pevent->npend ) {
@@ -210,15 +188,15 @@
taskId = ( void * ) pevent->ev_que->evUser->taskid;
UNLOCKEVQUE(pevent->ev_que);
if ( nEntriesFree == 0u ) {
- printf ( ", thread=%p, queue full",
+ printf ( ", thread=%p, queue full",
(void *) taskId );
}
else if ( nEntriesFree == EVENTQUESIZE ) {
- printf ( ", thread=%p, queue empty",
+ printf ( ", thread=%p, queue empty",
(void *) taskId );
}
else {
- printf ( ", thread=%p, unused entries=%u",
+ printf ( ", thread=%p, unused entries=%u",
(void *) taskId, nEntriesFree );
}
}
@@ -229,7 +207,7 @@
if ( pevent->nreplace ) {
printf (", discarded by replacement=%ld", pevent->nreplace);
}
- if ( ! pevent->valque ) {
+ if ( ! pevent->useValque ) {
printf (", queueing disabled" );
}
LOCKEVQUE(pevent->ev_que);
@@ -245,19 +223,19 @@
}
if ( level > 3 ) {
- printf ( ", ev %p, ev que %p, ev user %p",
- ( void * ) pevent,
- ( void * ) pevent->ev_que,
+ printf ( ", ev %p, ev que %p, ev user %p",
+ ( void * ) pevent,
+ ( void * ) pevent->ev_que,
( void * ) pevent->ev_que->evUser );
}
printf( "\n" );
}
- pevent = (struct evSubscrip *) ellNext ( &pevent->node );
+ pevent = (struct evSubscrip *) ellNext ( &pevent->node );
}
- UNLOCKREC ( addr.precord );
+ UNLOCKREC (addr.precord);
return DB_EVENT_OK;
}
@@ -268,32 +246,36 @@
*
* 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 epicsShareAPI db_init_events (void)
{
struct event_user * evUser;
-
+
if (!dbevEventUserFreeList) {
- freeListInitPvt(&dbevEventUserFreeList,
+ freeListInitPvt(&dbevEventUserFreeList,
sizeof(struct event_user),8);
}
if (!dbevEventQueueFreeList) {
- freeListInitPvt(&dbevEventQueueFreeList,
+ freeListInitPvt(&dbevEventQueueFreeList,
sizeof(struct event_que),8);
}
- if (!dbevEventBlockFreeList) {
- freeListInitPvt(&dbevEventBlockFreeList,
+ if (!dbevEventSubscriptionFreeList) {
+ freeListInitPvt(&dbevEventSubscriptionFreeList,
sizeof(struct evSubscrip),256);
}
-
- evUser = (struct event_user *)
+ if (!dbevFieldLogFreeList) {
+ freeListInitPvt(&dbevFieldLogFreeList,
+ sizeof(struct db_field_log),2048);
+ }
+
+ evUser = (struct event_user *)
freeListCalloc(dbevEventUserFreeList);
if (!evUser) {
return NULL;
}
-
+
evUser->firstque.evUser = evUser;
evUser->firstque.writelock = epicsMutexCreate();
if (!evUser->firstque.writelock) {
@@ -304,7 +286,7 @@
if (!evUser->ppendsem) {
epicsMutexDestroy (evUser->firstque.writelock);
return NULL;
- }
+ }
evUser->pflush_sem = epicsEventCreate(epicsEventEmpty);
if (!evUser->pflush_sem) {
epicsMutexDestroy (evUser->firstque.writelock);
@@ -327,7 +309,7 @@
/*
* DB_CLOSE_EVENTS()
- *
+ *
* evUser block and additional event queues
* deallocated when the event thread terminates
* itself
@@ -341,7 +323,7 @@
* Exit not forced on event blocks for now - this is left to channel
* access and any other tasks using this facility which can find them
* more efficiently.
- *
+ *
* NOTE: not deleting events before calling this routine could be
* hazardous to the system's health.
*/
@@ -375,7 +357,7 @@
* DB_ADD_EVENT()
*/
dbEventSubscription epicsShareAPI db_add_event (
- dbEventCtx ctx, struct dbAddr *paddr,
+ dbEventCtx ctx, struct dbChannel *chan,
EVENTFUNC *user_sub, void *user_arg, unsigned select)
{
struct event_user * const evUser = (struct event_user *) ctx;
@@ -389,7 +371,7 @@
return NULL;
}
- pevent = freeListCalloc ( dbevEventBlockFreeList );
+ pevent = freeListCalloc (dbevEventSubscriptionFreeList);
if ( ! pevent ) {
return NULL;
}
@@ -422,7 +404,7 @@
epicsMutexUnlock ( evUser->lock );
if ( ! ev_que ) {
- freeListFree ( dbevEventBlockFreeList, pevent );
+ freeListFree ( dbevEventSubscriptionFreeList, pevent );
return NULL;
}
@@ -430,7 +412,7 @@
pevent->nreplace = 0ul;
pevent->user_sub = user_sub;
pevent->user_arg = user_arg;
- pevent->paddr = paddr;
+ pevent->chan = chan;
pevent->select = (unsigned char) select;
pevent->pLastLog = NULL; /* not yet in the queue */
pevent->callBackInProgress = FALSE;
@@ -442,12 +424,12 @@
* communication (for other types they get whatever happens to be
* there upon wakeup)
*/
- if( paddr->no_elements == 1 &&
- paddr->field_size <= sizeof(union native_value)) {
- pevent->valque = TRUE;
+ if( dbChannelElements(chan) == 1 &&
+ dbChannelFieldSize(chan) <= sizeof(union native_value)) {
+ pevent->useValque = TRUE;
}
else {
- pevent->valque = FALSE;
+ pevent->useValque = FALSE;
}
return pevent;
@@ -456,93 +438,93 @@
/*
* db_event_enable()
*/
-void epicsShareAPI db_event_enable (dbEventSubscription es)
+void epicsShareAPI db_event_enable (dbEventSubscription event)
{
- struct evSubscrip * const pevent = (struct evSubscrip *) es;
- struct dbCommon * const precord =
- (struct dbCommon *) pevent->paddr->precord;
+ struct evSubscrip * const pevent = (struct evSubscrip *) event;
+ struct dbCommon * const precord = dbChannelRecord(pevent->chan);
- LOCKREC(precord);
+ LOCKREC (precord);
if ( ! pevent->enabled ) {
ellAdd (&precord->mlis, &pevent->node);
pevent->enabled = TRUE;
}
- UNLOCKREC(precord);
+ UNLOCKREC (precord);
}
/*
* db_event_disable()
*/
-void epicsShareAPI db_event_disable (dbEventSubscription es)
+void epicsShareAPI db_event_disable (dbEventSubscription event)
{
- struct evSubscrip * const pevent = (struct evSubscrip *) es;
- struct dbCommon * const precord =
- (struct dbCommon *) pevent->paddr->precord;
+ struct evSubscrip * const pevent = (struct evSubscrip *) event;
+ struct dbCommon * const precord = dbChannelRecord(pevent->chan);
- LOCKREC(precord);
+ LOCKREC (precord);
if ( pevent->enabled ) {
ellDelete(&precord->mlis, &pevent->node);
pevent->enabled = FALSE;
}
- UNLOCKREC(precord);
+ UNLOCKREC (precord);
}
/*
* event_remove()
* event queue lock _must_ be applied
+ * this nulls the entry in the queue, but doesn't delete the db_field_log chunk
*/
-static void event_remove ( struct event_que *ev_que,
+static void event_remove ( struct event_que *ev_que,
unsigned short index, struct evSubscrip *placeHolder )
{
- struct evSubscrip * const pEvent = ev_que->evque[index];
+ struct evSubscrip * const pevent = ev_que->evque[index];
ev_que->evque[index] = placeHolder;
- if ( pEvent->npend == 1u ) {
- pEvent->pLastLog = NULL;
+ ev_que->valque[index] = NULL;
+ if ( pevent->npend == 1u ) {
+ pevent->pLastLog = NULL;
}
else {
- assert ( pEvent->npend > 1u );
+ assert ( pevent->npend > 1u );
assert ( ev_que->nDuplicates >= 1u );
ev_que->nDuplicates--;
}
- pEvent->npend--;
+ pevent->npend--;
}
/*
* DB_CANCEL_EVENT()
*
- * This routine does not prevent two threads from deleting
+ * This routine does not prevent two threads from deleting
* the same block at the same time.
- *
+ *
*/
-void epicsShareAPI db_cancel_event (dbEventSubscription es)
+void epicsShareAPI db_cancel_event (dbEventSubscription event)
{
- struct evSubscrip * const pevent = ( struct evSubscrip * ) es;
+ struct evSubscrip * const pevent = (struct evSubscrip *) event;
unsigned short getix;
- db_event_disable ( es );
+ db_event_disable ( event );
/*
- * flag the event as canceled by NULLing out the callback handler
+ * flag the event as canceled by NULLing out the callback handler
*
* make certain that the event isnt being accessed while
* its call back changes
*/
- LOCKEVQUE ( pevent->ev_que )
+ LOCKEVQUE (pevent->ev_que);
pevent->user_sub = NULL;
/*
* purge this event from the queue
*
- * Its better to take this approach rather than waiting
+ * Its better to take this approach rather than waiting
* for the event thread to finish removing this event
* from the queue because the event thread will not
- * process if we are in flow control mode. Since blocking
+ * process if we are in flow control mode. Since blocking
* here will block CA's TCP input queue then a dead lock
* would be possible.
*/
- for ( getix = pevent->ev_que->getix;
+ for ( getix = pevent->ev_que->getix;
pevent->ev_que->evque[getix] != EVENTQEMPTY; ) {
if ( pevent->ev_que->evque[getix] == pevent ) {
assert ( pevent->ev_que->nCanceled < USHRT_MAX );
@@ -561,17 +543,17 @@
}
else {
while ( pevent->callBackInProgress ) {
- UNLOCKEVQUE ( pevent->ev_que )
+ UNLOCKEVQUE (pevent->ev_que);
epicsEventMustWait ( pevent->ev_que->evUser->pflush_sem );
- LOCKEVQUE ( pevent->ev_que )
+ LOCKEVQUE (pevent->ev_que);
}
}
pevent->ev_que->quota -= EVENTENTRIES;
- UNLOCKEVQUE ( pevent->ev_que )
-
- freeListFree ( dbevEventBlockFreeList, pevent );
+ UNLOCKEVQUE (pevent->ev_que);
+
+ freeListFree ( dbevEventSubscriptionFreeList, pevent );
return;
}
@@ -585,7 +567,7 @@
{
struct event_user * const evUser = (struct event_user *) ctx;
- epicsMutexMustLock ( evUser->lock );
+ epicsMutexMustLock ( evUser->lock );
while ( evUser->extraLaborBusy ) {
epicsMutexUnlock ( evUser->lock );
epicsThreadSleep(0.1);
@@ -640,38 +622,90 @@
}
/*
- * DB_POST_SINGLE_EVENT_PRIVATE()
+ * DB_CREATE_EVENT_LOG()
*
* NOTE: This assumes that the db scan lock is already applied
- */
-static void db_post_single_event_private (struct evSubscrip *event)
-{
- struct event_que * const ev_que = event->ev_que;
- db_field_log * pLog;
+ * (as it copies data from the record)
+ */
+db_field_log* epicsShareAPI db_create_event_log (struct evSubscrip *pevent)
+{
+ 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->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
+ * address
+ */
+ memcpy(&pLog->u.v.field,
+ dbChannelField(chan),
+ dbChannelFieldSize(chan));
+ } else {
+ pLog->type = dbfl_type_rec;
+ }
+ }
+ return pLog;
+}
+
+/*
+ * DB_CREATE_READ_LOG()
+ *
+ */
+db_field_log* epicsShareAPI db_create_read_log (struct dbChannel *chan)
+{
+ db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
+
+ if (pLog) {
+ pLog->ctx = dbfl_context_read;
+ pLog->type = dbfl_type_rec;
+ }
+ return pLog;
+}
+
+/*
+ * DB_QUEUE_EVENT_LOG()
+ *
+ */
+static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
+{
+ struct event_que *ev_que;
int firstEventFlag;
unsigned rngSpace;
+ ev_que = pevent->ev_que;
/*
* evUser ring buffer must be locked for the multiple
* threads writing/reading it
*/
- LOCKEVQUE(ev_que)
+ LOCKEVQUE (ev_que);
/*
- * if we have an event on the queue and we are
- * not saving the current value (because this is a
- * string or an array) then ignore duplicate
- * events (saving them without the current valuye
- * serves no purpose)
+ * 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 (!event->valque && event->npend>0u) {
- UNLOCKEVQUE(ev_que)
+ 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
+ /*
+ * add to task local event que
*/
/*
@@ -680,34 +714,38 @@
* then replace the last event on the queue (for this monitor)
*/
rngSpace = ringSpace ( ev_que );
- if ( event->npend>0u &&
+ if ( pevent->npend>0u &&
(ev_que->evUser->flowCtrlMode || rngSpace<=EVENTSPERQUE) ) {
/*
* replace last event if no space is left
*/
- pLog = event->pLastLog;
- event->nreplace++;
+ if (*pevent->pLastLog) {
+ db_delete_field_log(*pevent->pLastLog);
+ *pevent->pLastLog = pLog;
+ }
+ pevent->nreplace++;
/*
- * the event task has already been notified about
+ * the event task has already been notified about
* this so we dont need to post the semaphore
*/
firstEventFlag = 0;
}
/*
- * Otherwise, the current entry must be available.
+ * Otherwise, the current entry must be available.
* Fill it in and advance the ring buffer.
*/
else {
assert ( ev_que->evque[ev_que->putix] == EVENTQEMPTY );
- pLog = &ev_que->valque[ev_que->putix];
- ev_que->evque[ev_que->putix] = event;
- if (event->npend>0u) {
+ ev_que->evque[ev_que->putix] = pevent;
+ ev_que->valque[ev_que->putix] = pLog;
+ pevent->pLastLog = &ev_que->valque[ev_que->putix];
+ if (pevent->npend>0u) {
ev_que->nDuplicates++;
}
- event->npend++;
- /*
- * if the ring buffer was empty before
- * adding this event
+ pevent->npend++;
+ /*
+ * if the ring buffer was empty before
+ * adding this event
*/
if (rngSpace==EVENTQUESIZE) {
firstEventFlag = 1;
@@ -718,39 +756,21 @@
ev_que->putix = RNGINC ( ev_que->putix );
}
- if (pLog && event->valque) {
- struct dbCommon *precord = event->paddr->precord;
- pLog->stat = precord->stat;
- pLog->sevr = precord->sevr;
- pLog->time = precord->time;
-
- /*
- * use memcpy to avoid a bus error on
- * union copy of char in the db at an odd
- * address
- */
- memcpy( (char *)&pLog->field,
- (char *)event->paddr->pfield,
- event->paddr->field_size);
-
- event->pLastLog = pLog;
- }
-
- UNLOCKEVQUE(ev_que)
-
- /*
- * its more efficent to notify the event handler
+ UNLOCKEVQUE (ev_que);
+
+ /*
+ * its more efficent to notify the event handler
* only after the event is ready and the lock
* is off in case it runs at a higher priority
* than the caller here.
*/
if (firstEventFlag) {
- /*
- * notify the event handler
+ /*
+ * notify the event handler
*/
epicsEventSignal(ev_que->evUser->ppendsem);
}
-}
+}
/*
* DB_POST_EVENTS()
@@ -763,28 +783,30 @@
void *pField,
unsigned int caEventMask
)
-{
- struct dbCommon * const pdbc = (struct dbCommon *)pRecord;
- struct evSubscrip * event;
-
- if (pdbc->mlis.count == 0) return DB_EVENT_OK; /* no monitors set */
-
- LOCKREC(pdbc);
-
- for (event = (struct evSubscrip *) pdbc->mlis.node.next;
- event; event = (struct evSubscrip *) event->node.next){
-
+{
+ struct dbCommon * const prec = (struct dbCommon *) pRecord;
+ struct evSubscrip *pevent;
+
+ if (prec->mlis.count == 0) return DB_EVENT_OK; /* no monitors set */
+
+ LOCKREC (prec);
+
+ for (pevent = (struct evSubscrip *) prec->mlis.node.next;
+ pevent; pevent = (struct evSubscrip *) pevent->node.next){
+
/*
* Only send event msg if they are waiting on the field which
* changed or pval==NULL and waiting on alarms and alarms changed
*/
- if ( (event->paddr->pfield == (void *)pField || pField==NULL) &&
- (caEventMask & event->select) ) {
- db_post_single_event_private (event);
+ if ( (dbChannelField(pevent->chan) == (void *)pField || pField==NULL) &&
+ (caEventMask & pevent->select)) {
+ db_field_log *pLog = db_create_event_log(pevent);
+ pLog = dbChannelRunPreChain(pevent->chan, pLog);
+ if (pLog) db_queue_event_log(pevent, pLog);
}
}
- UNLOCKREC(pdbc);
+ UNLOCKREC (prec);
return DB_EVENT_OK;
}
@@ -792,14 +814,18 @@
/*
* DB_POST_SINGLE_EVENT()
*/
-void epicsShareAPI db_post_single_event (dbEventSubscription es)
-{
- struct evSubscrip * const event = (struct evSubscrip *) es;
- struct dbCommon * const precord = event->paddr->precord;
-
- dbScanLock (precord);
- db_post_single_event_private (event);
- dbScanUnlock (precord);
+void epicsShareAPI db_post_single_event (dbEventSubscription event)
+{
+ struct evSubscrip * const pevent = (struct evSubscrip *) event;
+ struct dbCommon * const prec = dbChannelRecord(pevent->chan);
+
+ dbScanLock (prec);
+
+ db_field_log *pLog = db_create_event_log(pevent);
+ pLog = dbChannelRunPreChain(pevent->chan, pLog);
+ db_queue_event_log(pevent, pLog);
+
+ dbScanUnlock (prec);
}
/*
@@ -808,31 +834,35 @@
static int event_read ( struct event_que *ev_que )
{
db_field_log *pfl;
- void ( *user_sub ) ( void *user_arg, struct dbAddr *paddr,
+ void ( *user_sub ) ( void *user_arg, struct dbChannel *chan,
int eventsRemaining, db_field_log *pfl );
-
+
/*
* evUser ring buffer must be locked for the multiple
* threads writing/reading it
*/
- LOCKEVQUE ( ev_que )
-
+ LOCKEVQUE (ev_que);
+
/*
* if in flow control mode drain duplicates and then
* suspend processing events until flow control
* mode is over
*/
if ( ev_que->evUser->flowCtrlMode && ev_que->nDuplicates == 0u ) {
- UNLOCKEVQUE(ev_que);
+ UNLOCKEVQUE (ev_que);
return DB_EVENT_OK;
}
-
+
while ( ev_que->evque[ev_que->getix] != EVENTQEMPTY ) {
- db_field_log fl = ev_que->valque[ev_que->getix];
- struct evSubscrip *event = ev_que->evque[ev_que->getix];
+ pfl = ev_que->valque[ev_que->getix];
+ struct evSubscrip *pevent = ev_que->evque[ev_que->getix];
- if ( event == &canceledEvent ) {
+ if ( pevent == &canceledEvent ) {
ev_que->evque[ev_que->getix] = EVENTQEMPTY;
+ if (ev_que->valque[ev_que->getix]) {
+ db_delete_field_log(ev_que->valque[ev_que->getix]);
+ ev_que->valque[ev_que->getix] = NULL;
+ }
ev_que->getix = RNGINC ( ev_que->getix );
assert ( ev_que->nCanceled > 0 );
ev_que->nCanceled--;
@@ -844,12 +874,6 @@
* communication. (for other types they get whatever happens
* to be there upon wakeup)
*/
- if ( event->valque ) {
- pfl = &fl;
- }
- else {
- pfl = NULL;
- }
event_remove ( ev_que, ev_que->getix, EVENTQEMPTY );
ev_que->getix = RNGINC ( ev_que->getix );
@@ -858,29 +882,34 @@
* create a local copy of the call back parameters while
* we still have the lock
*/
- user_sub = event->user_sub;
+ user_sub = pevent->user_sub;
/*
* Next event pointer can be used by event tasks to determine
* if more events are waiting in the queue
*
* Must remove the lock here so that we dont deadlock if
- * this calls dbGetField() and blocks on the record lock,
- * dbPutField() is in progress in another task, it has the
- * record lock, and it is calling db_post_events() waiting
+ * this calls dbGetField() and blocks on the record lock,
+ * dbPutField() is in progress in another task, it has the
+ * record lock, and it is calling db_post_events() waiting
* for the event queue lock (which this thread now has).
*/
if ( user_sub ) {
/*
* This provides a way to test to see if an event is in use
- * despite the fact that the event queue does not point to
- * it.
+ * despite the fact that the event queue does not point to
+ * it.
*/
- event->callBackInProgress = TRUE;
- UNLOCKEVQUE ( ev_que )
- ( *user_sub ) ( event->user_arg, event->paddr,
+ pevent->callBackInProgress = TRUE;
+ UNLOCKEVQUE (ev_que);
+ /* Run post-event-queue filter chain */
+ if (ellCount(&pevent->chan->post_chain)) {
+ dbChannelRunPostChain(pevent->chan, pfl);
+ }
+ /* Issue user callback */
+ ( *user_sub ) ( pevent->user_arg, pevent->chan,
ev_que->evque[ev_que->getix] != EVENTQEMPTY, pfl );
- LOCKEVQUE ( ev_que )
+ LOCKEVQUE (ev_que);
/*
* check to see if this event has been canceled each
@@ -889,22 +918,23 @@
* complete sem if there are no longer any events on the
* queue
*/
- if ( ev_que->evUser->pSuicideEvent == event ) {
+ if ( ev_que->evUser->pSuicideEvent == pevent ) {
ev_que->evUser->pSuicideEvent = NULL;
}
else {
- if ( event->user_sub==NULL && event->npend==0u ) {
- event->callBackInProgress = FALSE;
+ if ( pevent->user_sub==NULL && pevent->npend==0u ) {
+ pevent->callBackInProgress = FALSE;
epicsEventSignal ( ev_que->evUser->pflush_sem );
}
else {
- event->callBackInProgress = FALSE;
+ pevent->callBackInProgress = FALSE;
}
}
}
+ db_delete_field_log(pfl);
}
- UNLOCKEVQUE ( ev_que )
+ UNLOCKEVQUE (ev_que);
return DB_EVENT_OK;
}
@@ -924,7 +954,7 @@
taskwdInsert ( epicsThreadGetIdSelf(), NULL, NULL );
- do{
+ do {
void (*pExtraLaborSub) (void *);
void *pExtraLaborArg;
epicsEventMustWait(evUser->ppendsem);
@@ -951,7 +981,7 @@
}
evUser->extraLaborBusy = FALSE;
- for ( ev_que = &evUser->firstque; ev_que;
+ for ( ev_que = &evUser->firstque; ev_que;
ev_que = ev_que->nextque ) {
epicsMutexUnlock ( evUser->lock );
event_read (ev_que);
@@ -959,7 +989,7 @@
}
epicsMutexUnlock ( evUser->lock );
- } while( ! evUser->pendexit );
+ } while ( ! evUser->pendexit );
epicsMutexDestroy(evUser->firstque.writelock);
@@ -967,7 +997,7 @@
struct event_que *nextque;
ev_que = evUser->firstque.nextque;
- while(ev_que){
+ while (ev_que) {
nextque = ev_que->nextque;
epicsMutexDestroy(ev_que->writelock);
freeListFree(dbevEventQueueFreeList, ev_que);
@@ -990,15 +1020,15 @@
* DB_START_EVENTS()
*/
int epicsShareAPI db_start_events (
- dbEventCtx ctx,const char *taskname, void (*init_func)(void *),
+ dbEventCtx ctx,const char *taskname, void (*init_func)(void *),
void *init_func_arg, unsigned osiPriority )
{
struct event_user * const evUser = (struct event_user *) ctx;
-
+
epicsMutexMustLock ( evUser->lock );
- /*
- * only one ca_pend_event thread may be
+ /*
+ * only one ca_pend_event thread may be
* started for each evUser
*/
if (evUser->taskid) {
@@ -1044,7 +1074,7 @@
epicsMutexMustLock ( evUser->lock );
evUser->flowCtrlMode = TRUE;
epicsMutexUnlock ( evUser->lock );
- /*
+ /*
* notify the event handler task
*/
epicsEventSignal(evUser->ppendsem);
@@ -1063,13 +1093,24 @@
epicsMutexMustLock ( evUser->lock );
evUser->flowCtrlMode = FALSE;
epicsMutexUnlock ( evUser->lock );
- /*
+ /*
* notify the event handler task
*/
epicsEventSignal (evUser->ppendsem);
#ifdef DEBUG
printf("fc off %lu\n", tickGet());
#endif
-}
-
-
+}
+
+/*
+ * db_delete_field_log()
+ */
+void epicsShareAPI db_delete_field_log (db_field_log *pfl)
+{
+ if (pfl) {
+ /* Free field if reference type field log and dtor is set */
+ if (pfl->type == dbfl_type_ref && pfl->u.r.dtor) pfl->u.r.dtor(pfl);
+ /* Free the field log chunk */
+ freeListFree(dbevFieldLogFreeList, pfl);
+ }
+}
=== modified file 'src/ioc/db/dbEvent.h'
--- src/ioc/db/dbEvent.h 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbEvent.h 2012-05-30 18:10:27 +0000
@@ -1,17 +1,19 @@
/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/*
- * $Revision-Id$
+
+/*
+ * Author: Jeffrey O. Hill <[email protected]>
*
- * Author: Jeff Hill
- * Date: 030393
+ * Ralph Lange <[email protected]>
*/
#ifndef INCLdbEventh
@@ -34,8 +36,9 @@
extern "C" {
#endif
-struct dbAddr;
+struct dbChannel;
struct db_field_log;
+struct evSubscrip;
epicsShareFunc int epicsShareAPI db_event_list (
const char *name, unsigned level);
@@ -49,7 +52,7 @@
typedef void EXTRALABORFUNC (void *extralabor_arg);
epicsShareFunc dbEventCtx epicsShareAPI db_init_events (void);
epicsShareFunc int epicsShareAPI db_start_events (
- dbEventCtx ctx, const char *taskname, void (*init_func)(void *),
+ dbEventCtx ctx, const char *taskname, void (*init_func)(void *),
void *init_func_arg, unsigned osiPriority );
epicsShareFunc void epicsShareAPI db_close_events (dbEventCtx ctx);
epicsShareFunc void epicsShareAPI db_event_flow_ctrl_mode_on (dbEventCtx ctx);
@@ -60,18 +63,22 @@
epicsShareFunc int epicsShareAPI db_post_extra_labor (dbEventCtx ctx);
epicsShareFunc void epicsShareAPI db_event_change_priority ( dbEventCtx ctx, unsigned epicsPriority );
-typedef void EVENTFUNC (void *user_arg, struct dbAddr *paddr,
+typedef void EVENTFUNC (void *user_arg, struct dbChannel *chan,
int eventsRemaining, struct db_field_log *pfl);
typedef void * dbEventSubscription;
epicsShareFunc dbEventSubscription epicsShareAPI db_add_event (
- dbEventCtx ctx, struct dbAddr *paddr,
+ dbEventCtx ctx, struct dbChannel *chan,
EVENTFUNC *user_sub, void *user_arg, unsigned select);
epicsShareFunc void epicsShareAPI db_cancel_event (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_post_single_event (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_event_enable (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_event_disable (dbEventSubscription es);
+epicsShareFunc struct db_field_log* epicsShareAPI db_create_event_log (struct evSubscrip *pevent);
+epicsShareFunc struct db_field_log* epicsShareAPI db_create_read_log (struct dbChannel *chan);
+epicsShareFunc void epicsShareAPI db_delete_field_log (struct db_field_log *pfl);
+
#define DB_EVENT_OK 0
#define DB_EVENT_ERROR (-1)
=== added file 'src/ioc/db/dbExtractArray.c'
--- src/ioc/db/dbExtractArray.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbExtractArray.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,84 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2002 The Regents of the University of California, as
+* Operator of Los Alamos National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ *
+ * based on dbConvert.c
+ * written by: Bob Dalesio, Marty Kraimer
+ */
+
+#include <string.h>
+
+#include "epicsTypes.h"
+#include "dbAddr.h"
+#define epicsExportSharedSymbols
+#include "dbExtractArray.h"
+
+void dbExtractArrayFromRec(const dbAddr *paddr, void *pto,
+ 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);
+
+ if (nRequest > no_elements) nRequest = no_elements;
+ if (isString && srcSize > MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE;
+
+ if (increment == 1 && dstSize == srcSize) {
+ nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset;
+ memcpy(pdst, &psrc[offset * srcSize], dstSize * 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';
+ } else {
+ for (; nRequest > 0; nRequest--, pdst += dstSize, 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';
+ }
+ }
+}
=== added file 'src/ioc/db/dbExtractArray.h'
--- src/ioc/db/dbExtractArray.h 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbExtractArray.h 2012-05-30 18:10:27 +0000
@@ -0,0 +1,34 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2002 The Regents of the University of California, as
+* Operator of Los Alamos National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+#ifndef INC_dbExtractArray_H
+#define INC_dbExtractArray_H
+
+#include "dbFldTypes.h"
+#include "dbAddr.h"
+#include "shareLib.h"
+
+#ifdef __cplusplus
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // INC_dbExtractArray_H
=== modified file 'src/ioc/db/dbIocRegister.c'
--- src/ioc/db/dbIocRegister.c 2012-04-10 22:10:50 +0000
+++ src/ioc/db/dbIocRegister.c 2012-05-30 18:10:27 +0000
@@ -21,6 +21,7 @@
#include "dbNotify.h"
#include "callback.h"
#include "dbIocRegister.h"
+#include "dbState.h"
/* dbLoadDatabase */
static const iocshArg dbLoadDatabaseArg0 = { "file name",iocshArgString};
@@ -297,6 +298,51 @@
callbackSetQueueSize(args[0].ival);
}
+/* dbStateCreate */
+static const iocshArg dbStateCreateArg0 = { "name", iocshArgString };
+static const iocshArg * const dbStateCreateArgs[] = { &dbStateCreateArg0 };
+static const iocshFuncDef dbStateCreateFuncDef = { "dbStateCreate", 1, dbStateCreateArgs };
+static void dbStateCreateCallFunc (const iocshArgBuf *args)
+{
+ dbStateCreate(args[0].sval);
+}
+
+/* dbStateSet */
+static const iocshArg dbStateSetArg0 = { "id", iocshArgInt };
+static const iocshArg * const dbStateSetArgs[] = { &dbStateSetArg0 };
+static const iocshFuncDef dbStateSetFuncDef = { "dbStateSet", 1, dbStateSetArgs };
+static void dbStateSetCallFunc (const iocshArgBuf *args)
+{
+ dbStateSet((dbStateId) args[0].ival);
+}
+
+/* dbStateClear */
+static const iocshArg dbStateClearArg0 = { "id", iocshArgInt };
+static const iocshArg * const dbStateClearArgs[] = { &dbStateClearArg0 };
+static const iocshFuncDef dbStateClearFuncDef = { "dbStateClear", 1, dbStateClearArgs };
+static void dbStateClearCallFunc (const iocshArgBuf *args)
+{
+ dbStateClear((dbStateId) args[0].ival);
+}
+
+/* dbStateShow */
+static const iocshArg dbStateShowArg0 = { "id", iocshArgInt };
+static const iocshArg dbStateShowArg1 = { "level", iocshArgInt };
+static const iocshArg * const dbStateShowArgs[] = { &dbStateShowArg0, &dbStateShowArg1 };
+static const iocshFuncDef dbStateShowFuncDef = { "dbStateShow", 2, dbStateShowArgs };
+static void dbStateShowCallFunc (const iocshArgBuf *args)
+{
+ dbStateShow((dbStateId) args[0].ival, args[1].ival);
+}
+
+/* dbStateShowAll */
+static const iocshArg dbStateShowAllArg0 = { "level", iocshArgInt };
+static const iocshArg * const dbStateShowAllArgs[] = { &dbStateShowAllArg0 };
+static const iocshFuncDef dbStateShowAllFuncDef = { "dbStateShowAll", 1, dbStateShowAllArgs };
+static void dbStateShowAllCallFunc (const iocshArgBuf *args)
+{
+ dbStateShowAll(args[0].ival);
+}
void epicsShareAPI dbIocRegister(void)
{
@@ -342,4 +388,10 @@
iocshRegister(&scanpiolFuncDef,scanpiolCallFunc);
iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc);
+
+ iocshRegister(&dbStateCreateFuncDef, dbStateCreateCallFunc);
+ iocshRegister(&dbStateSetFuncDef, dbStateSetCallFunc);
+ iocshRegister(&dbStateClearFuncDef, dbStateClearCallFunc);
+ iocshRegister(&dbStateShowFuncDef, dbStateShowCallFunc);
+ iocshRegister(&dbStateShowAllFuncDef, dbStateShowAllCallFunc);
}
=== added file 'src/ioc/db/dbLink.c'
--- src/ioc/db/dbLink.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbLink.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,648 @@
+/*************************************************************************\
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
+ * National Laboratory.
+ * Copyright (c) 2002 The Regents of the University of California, as
+ * Operator of Los Alamos National Laboratory.
+ * EPICS BASE is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+/* dbLink.c */
+/* $Id$ */
+/*
+ * Original Authors: Bob Dalesio, Marty Kraimer
+ * Current Author: Andrew Johnson
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "dbDefs.h"
+#include "epicsThread.h"
+#include "errlog.h"
+#include "cantProceed.h"
+#include "cvtFast.h"
+#include "epicsTime.h"
+#include "alarm.h"
+#include "ellLib.h"
+#include "dbStaticLib.h"
+#include "dbBase.h"
+#include "link.h"
+#include "dbFldTypes.h"
+#include "recSup.h"
+#include "devSup.h"
+#include "caeventmask.h"
+#include "db_field_log.h"
+#include "dbCommon.h"
+#include "dbFldTypes.h"
+#include "special.h"
+#include "errMdef.h"
+#define epicsExportSharedSymbols
+#include "dbAddr.h"
+#include "dbLink.h"
+#include "callback.h"
+#include "dbScan.h"
+#include "dbLock.h"
+#include "dbEvent.h"
+#include "dbConvert.h"
+#include "dbConvertFast.h"
+#include "epicsEvent.h"
+#include "dbCa.h"
+#include "dbBkpt.h"
+#include "dbNotify.h"
+#include "dbAccessDefs.h"
+#include "recGbl.h"
+
+static void inherit_severity(const struct pv_link *ppv_link, dbCommon *pdest,
+ epicsEnum16 stat, epicsEnum16 sevr)
+{
+ switch (ppv_link->pvlMask & pvlOptMsMode) {
+ case pvlOptNMS:
+ break;
+ case pvlOptMSI:
+ if (sevr < INVALID_ALARM)
+ break;
+ /* Fall through */
+ case pvlOptMS:
+ recGblSetSevr(pdest, LINK_ALARM, sevr);
+ break;
+ case pvlOptMSS:
+ recGblSetSevr(pdest, stat, sevr);
+ break;
+ }
+}
+
+/***************************** Constant Links *****************************/
+
+static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
+{
+ if (!plink->value.constantStr)
+ return S_db_badField;
+
+ /* Constant strings are always numeric */
+ if (dbrType== DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
+ dbrType = DBF_USHORT;
+
+ return dbFastPutConvertRoutine[DBR_STRING][dbrType]
+ (plink->value.constantStr, pbuffer, NULL);
+}
+
+static long dbConstGetNelements(const struct link *plink, long *nelements)
+{
+ *nelements = 0;
+ return 0;
+}
+
+static long dbConstGetLink(struct link *plink, short dbrType, void *pbuffer,
+ epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+{
+ if (pnRequest)
+ *pnRequest = 0;
+ return 0;
+}
+
+/***************************** Database Links *****************************/
+
+static long dbDbInitLink(struct link *plink, short dbfType)
+{
+ DBADDR dbaddr;
+ long status;
+ DBADDR *pdbAddr;
+
+ status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
+ if (status)
+ return status;
+
+ plink->type = DB_LINK;
+ pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
+ *pdbAddr = dbaddr; /* structure copy */
+ plink->value.pv_link.pvt = pdbAddr;
+ return 0;
+}
+
+static long dbDbAddLink(struct link *plink, short dbfType)
+{
+ long status = dbDbInitLink(plink, dbfType);
+
+ if (!status) {
+ DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbCommon *precord = plink->value.pv_link.precord;
+
+ dbLockSetRecordLock(pdbAddr->precord);
+ dbLockSetMerge(precord, pdbAddr->precord);
+ }
+ return status;
+}
+
+static void dbDbRemoveLink(struct link *plink)
+{
+ free(plink->value.pv_link.pvt);
+ plink->value.pv_link.pvt = 0;
+ plink->value.pv_link.getCvt = 0;
+ plink->value.pv_link.lastGetdbrType = 0;
+ plink->type = PV_LINK;
+ dbLockSetSplit(plink->value.pv_link.precord);
+}
+
+static int dbDbIsLinkConnected(const struct link *plink)
+{
+ return TRUE;
+}
+
+static int dbDbGetDBFtype(const struct link *plink)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ return paddr->field_type;
+}
+
+static long dbDbGetElements(const struct link *plink, long *nelements)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ *nelements = paddr->no_elements;
+ return 0;
+}
+
+static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
+ epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
+{
+ struct pv_link *ppv_link = &plink->value.pv_link;
+ DBADDR *paddr = ppv_link->pvt;
+ dbCommon *precord = plink->value.pv_link.precord;
+ long status;
+
+ /* scan passive records if link is process passive */
+ if (ppv_link->pvlMask & pvlOptPP) {
+ unsigned char pact = precord->pact;
+
+ precord->pact = TRUE;
+ status = dbScanPassive(precord, paddr->precord);
+ precord->pact = pact;
+ if (status)
+ return status;
+ }
+ *pstat = paddr->precord->stat;
+ *psevr = paddr->precord->sevr;
+
+ if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
+ status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ } else {
+ unsigned short dbfType = paddr->field_type;
+
+ if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
+ return S_db_badDbrtype;
+
+ if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
+ && paddr->special != SPC_ATTRIBUTE) {
+ ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
+ status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ } else {
+ ppv_link->getCvt = NULL;
+ status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
+ }
+ ppv_link->lastGetdbrType = dbrType;
+ }
+ return status;
+}
+
+static long dbDbGetControlLimits(const struct link *plink, double *low,
+ double *high)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRctrlDouble
+ double value;
+ } buffer;
+ long options = DBR_CTRL_DOUBLE;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ NULL);
+
+ if (status)
+ return status;
+
+ *low = buffer.lower_ctrl_limit;
+ *high = buffer.upper_ctrl_limit;
+ return 0;
+}
+
+static long dbDbGetGraphicLimits(const struct link *plink, double *low,
+ double *high)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRgrDouble
+ double value;
+ } buffer;
+ long options = DBR_GR_DOUBLE;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ NULL);
+
+ if (status)
+ return status;
+
+ *low = buffer.lower_disp_limit;
+ *high = buffer.upper_disp_limit;
+ return 0;
+}
+
+static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
+ double *low, double *high, double *hihi)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRalDouble
+ double value;
+ } buffer;
+ long options = DBR_AL_DOUBLE;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ 0);
+
+ if (status)
+ return status;
+
+ *lolo = buffer.lower_alarm_limit;
+ *low = buffer.lower_warning_limit;
+ *high = buffer.upper_warning_limit;
+ *hihi = buffer.upper_alarm_limit;
+ return 0;
+}
+
+static long dbDbGetPrecision(const struct link *plink, short *precision)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRprecision
+ double value;
+ } buffer;
+ long options = DBR_PRECISION;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ 0);
+
+ if (status)
+ return status;
+
+ *precision = buffer.precision.dp;
+ return 0;
+}
+
+static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ struct buffer {
+ DBRunits
+ double value;
+ } buffer;
+ long options = DBR_UNITS;
+ long number_elements = 0;
+ long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
+ 0);
+
+ if (status)
+ return status;
+
+ strncpy(units, buffer.units, unitsSize);
+ return 0;
+}
+
+static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
+ epicsEnum16 *severity)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ if (status)
+ *status = paddr->precord->stat;
+ if (severity)
+ *severity = paddr->precord->sevr;
+ return 0;
+}
+
+static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
+{
+ DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+
+ *pstamp = paddr->precord->time;
+ return 0;
+}
+
+static long dbDbPutValue(struct link *plink, short dbrType,
+ const void *pbuffer, long nRequest)
+{
+ struct pv_link *ppv_link = &plink->value.pv_link;
+ struct dbCommon *psrce = ppv_link->precord;
+ DBADDR *paddr = (DBADDR *) ppv_link->pvt;
+ dbCommon *pdest = paddr->precord;
+ long status = dbPut(paddr, dbrType, pbuffer, nRequest);
+
+ inherit_severity(ppv_link, pdest, psrce->nsta, psrce->nsev);
+ if (status)
+ return status;
+
+ if (paddr->pfield == (void *) &pdest->proc ||
+ (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
+ /* if dbPutField caused asyn record to process */
+ /* ask for reprocessing*/
+ if (pdest->putf) {
+ pdest->rpro = TRUE;
+ } else { /* process dest record with source's PACT true */
+ unsigned char pact;
+
+ if (psrce && psrce->ppn)
+ dbNotifyAdd(psrce, pdest);
+ pact = psrce->pact;
+ psrce->pact = TRUE;
+ status = dbProcess(pdest);
+ psrce->pact = pact;
+ }
+ }
+ return status;
+}
+
+static void dbDbScanFwdLink(struct link *plink)
+{
+ dbCommon *precord = plink->value.pv_link.precord;
+ dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
+
+ dbScanPassive(precord, paddr->precord);
+}
+
+lset dbDb_lset = { dbDbInitLink, dbDbAddLink, NULL, dbDbRemoveLink,
+ dbDbIsLinkConnected, dbDbGetDBFtype, dbDbGetElements, dbDbGetValue,
+ dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
+ dbDbGetPrecision, dbDbGetUnits, dbDbGetAlarm, dbDbGetTimeStamp,
+ dbDbPutValue, dbDbScanFwdLink };
+
+/***************************** Generic Link API *****************************/
+
+void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType)
+{
+ plink->value.pv_link.precord = precord;
+
+ if (plink == &precord->tsel)
+ recGblTSELwasModified(plink);
+
+ if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) {
+ /* Make it a DB link if possible */
+ if (!dbDbInitLink(plink, dbfType))
+ return;
+ }
+
+ /* Make it a CA link */
+ if (dbfType == DBF_INLINK)
+ plink->value.pv_link.pvlMask |= pvlOptInpNative;
+
+ dbCaAddLink(plink);
+ if (dbfType == DBF_FWDLINK) {
+ char *pperiod = strrchr(plink->value.pv_link.pvname, '.');
+
+ if (pperiod && strstr(pperiod, "PROC")) {
+ plink->value.pv_link.pvlMask |= pvlOptFWD;
+ } else {
+ errlogPrintf("%s.FLNK is a Channel Access Link "
+ " but does not link to a PROC field\n", precord->name);
+ }
+ }
+}
+
+void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType)
+{
+ plink->value.pv_link.precord = precord;
+
+ if (plink == &precord->tsel)
+ recGblTSELwasModified(plink);
+
+ if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) {
+ /* Can we make it a DB link? */
+ if (!dbDbAddLink(plink, dbfType))
+ return;
+ }
+
+ /* Make it a CA link */
+ if (dbfType == DBF_INLINK)
+ plink->value.pv_link.pvlMask |= pvlOptInpNative;
+
+ dbCaAddLink(plink);
+ if (dbfType == DBF_FWDLINK) {
+ char *pperiod = strrchr(plink->value.pv_link.pvname, '.');
+
+ if (pperiod && strstr(pperiod, "PROC"))
+ plink->value.pv_link.pvlMask |= pvlOptFWD;
+ }
+}
+
+long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
+{
+ switch (plink->type) {
+ case CONSTANT:
+ return dbConstLoadLink(plink, dbrType, pbuffer);
+ }
+ return S_db_notFound;
+}
+
+void dbRemoveLink(struct link *plink)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ dbDbRemoveLink(plink);
+ break;
+ case CA_LINK:
+ dbCaRemoveLink(plink);
+ break;
+ default:
+ cantProceed("dbRemoveLink: Unexpected link type %d\n", plink->type);
+ }
+ plink->type = PV_LINK;
+ plink->value.pv_link.pvlMask = 0;
+}
+
+int dbIsLinkConnected(const struct link *plink)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbIsLinkConnected(plink);
+ case CA_LINK:
+ return dbCaIsLinkConnected(plink);
+ }
+ return FALSE;
+}
+
+int dbGetLinkDBFtype(const struct link *plink)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetDBFtype(plink);
+ case CA_LINK:
+ return dbCaGetLinkDBFtype(plink);
+ }
+ return -1;
+}
+
+long dbGetNelements(const struct link *plink, long *nelements)
+{
+ switch (plink->type) {
+ case CONSTANT:
+ return dbConstGetNelements(plink, nelements);
+ case DB_LINK:
+ return dbDbGetElements(plink, nelements);
+ case CA_LINK:
+ return dbCaGetNelements(plink, nelements);
+ }
+ return S_db_badField;
+}
+
+long dbGetLinkValue(struct link *plink, short dbrType, void *pbuffer,
+ long *poptions, long *pnRequest)
+{
+ struct dbCommon *precord = plink->value.pv_link.precord;
+ epicsEnum16 sevr = 0, stat = 0;
+ long status;
+
+ if (poptions && *poptions) {
+ printf("dbGetLinkValue: Use of poptions no longer supported\n");
+ *poptions = 0;
+ }
+
+ switch (plink->type) {
+ case CONSTANT:
+ status = dbConstGetLink(plink, dbrType, pbuffer, &stat, &sevr,
+ pnRequest);
+ break;
+ case DB_LINK:
+ status = dbDbGetValue(plink, dbrType, pbuffer, &stat, &sevr, pnRequest);
+ break;
+ case CA_LINK:
+ status = dbCaGetLink(plink, dbrType, pbuffer, &stat, &sevr, pnRequest);
+ break;
+ default:
+ cantProceed("dbGetLinkValue: Illegal link type %d\n", plink->type);
+ status = -1;
+ }
+ if (status) {
+ recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
+ } else {
+ inherit_severity(&plink->value.pv_link, precord, stat, sevr);
+ }
+ return status;
+}
+
+long dbGetControlLimits(const struct link *plink, double *low, double *high)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetControlLimits(plink, low, high);
+ case CA_LINK:
+ return dbCaGetControlLimits(plink, low, high);
+ }
+ return S_db_notFound;
+}
+
+long dbGetGraphicLimits(const struct link *plink, double *low, double *high)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetGraphicLimits(plink, low, high);
+ case CA_LINK:
+ return dbCaGetGraphicLimits(plink, low, high);
+ }
+ return S_db_notFound;
+}
+
+long dbGetAlarmLimits(const struct link *plink, double *lolo, double *low,
+ double *high, double *hihi)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetAlarmLimits(plink, lolo, low, high, hihi);
+ case CA_LINK:
+ return dbCaGetAlarmLimits(plink, lolo, low, high, hihi);
+ }
+ return S_db_notFound;
+}
+
+long dbGetPrecision(const struct link *plink, short *precision)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetPrecision(plink, precision);
+ case CA_LINK:
+ return dbCaGetPrecision(plink, precision);
+ }
+ return S_db_notFound;
+}
+
+long dbGetUnits(const struct link *plink, char *units, int unitsSize)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetUnits(plink, units, unitsSize);
+ case CA_LINK:
+ return dbCaGetUnits(plink, units, unitsSize);
+ }
+ return S_db_notFound;
+}
+
+long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
+ epicsEnum16 *severity)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetAlarm(plink, status, severity);
+ case CA_LINK:
+ return dbCaGetAlarm(plink, status, severity);
+ }
+ return S_db_notFound;
+}
+
+long dbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ return dbDbGetTimeStamp(plink, pstamp);
+ case CA_LINK:
+ return dbCaGetTimeStamp(plink, pstamp);
+ }
+ return S_db_notFound;
+}
+
+long dbPutLinkValue(struct link *plink, short dbrType, const void *pbuffer,
+ long nRequest)
+{
+ long status;
+
+ switch (plink->type) {
+ case DB_LINK:
+ status = dbDbPutValue(plink, dbrType, pbuffer, nRequest);
+ break;
+ case CA_LINK:
+ status = dbCaPutLink(plink, dbrType, pbuffer, nRequest);
+ break;
+ default:
+ cantProceed("dbPutLinkValue: Illegal link type %d\n", plink->type);
+ status = -1;
+ }
+ if (status) {
+ struct dbCommon *precord = plink->value.pv_link.precord;
+
+ recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
+ }
+ return status;
+}
+
+void dbScanFwdLink(struct link *plink)
+{
+ switch (plink->type) {
+ case DB_LINK:
+ dbDbScanFwdLink(plink);
+ break;
+ case CA_LINK:
+ dbCaScanFwdLink(plink);
+ break;
+ }
+}
+
=== added file 'src/ioc/db/dbLink.h'
--- src/ioc/db/dbLink.h 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbLink.h 2012-05-30 18:10:27 +0000
@@ -0,0 +1,94 @@
+/*************************************************************************\
+* Copyright (c) 2010 The UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2002 The Regents of the University of California, as
+* Operator of Los Alamos National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+/*
+ * dbLink.h
+ *
+ * Created on: Mar 21, 2010
+ * Author: Andrew Johnson
+ */
+
+#ifndef INC_dbLink_H
+#define INC_dbLink_H
+
+#include "link.h"
+#include "shareLib.h"
+#include "epicsTypes.h"
+#include "epicsTime.h"
+
+typedef struct lset {
+ long (*initLink)(struct link *plink, short dbfType);
+ long (*addLink)(struct link *plink, short dbfType);
+ long (*loadLink)(struct link *plink, short dbrType, void *pbuffer);
+ void (*removeLink)(struct link *plink);
+ int (*isLinkConnected)(const struct link *plink);
+ int (*getDBFtype)(const struct link *plink);
+ long (*getElements)(const struct link *plink, long *nelements);
+ long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
+ epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest);
+ long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
+ long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
+ long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
+ double *hi, double *hihi);
+ long (*getPrecision)(const struct link *plink, short *precision);
+ long (*getUnits)(const struct link *plink, char *units, int unitsSize);
+ long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
+ epicsEnum16 *severity);
+ long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
+ long (*putValue)(struct link *plink, short dbrType,
+ const void *pbuffer, long nRequest);
+ void (*scanFwdLink)(struct link *plink);
+} lset;
+
+#define dbGetLink(PLNK, DBRTYPE, PBUFFER, OPTIONS, NREQUEST) \
+ ( ( ( (PLNK)->type == CONSTANT ) && \
+ ( (NREQUEST) == 0) && \
+ ( (OPTIONS) == 0) ) \
+ ? 0 \
+ : dbGetLinkValue((PLNK),(DBRTYPE), \
+ (void *)(PBUFFER), (OPTIONS), (NREQUEST) ) )
+
+#define dbPutLink(PLNK, DBRTYPE, PBUFFER, NREQUEST) \
+ ( ( (PLNK)->type == CONSTANT) \
+ ? 0 \
+ : dbPutLinkValue( (PLNK), (DBRTYPE), (void *)(PBUFFER), (NREQUEST) ) )
+
+#define dbGetSevr(PLINK, PSEVERITY) \
+ dbGetAlarm((PLINK), NULL, (PSEVERITY));
+
+epicsShareFunc void dbInitLink(struct dbCommon *precord, struct link *plink,
+ short dbfType);
+epicsShareFunc void dbAddLink(struct dbCommon *precord, struct link *plink,
+ short dbfType);
+epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
+ void *pbuffer);
+epicsShareFunc void dbRemoveLink(struct link *plink);
+epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
+epicsShareFunc int dbIsLinkConnected(const struct link *plink);
+epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
+epicsShareFunc long dbGetLinkValue(struct link *, short dbrType, void *pbuffer,
+ long *options, long *nRequest);
+epicsShareFunc long dbGetControlLimits(const struct link *plink, double *low,
+ double *high);
+epicsShareFunc long dbGetGraphicLimits(const struct link *plink, double *low,
+ double *high);
+epicsShareFunc long dbGetAlarmLimits(const struct link *plink, double *lolo,
+ double *low, double *high, double *hihi);
+epicsShareFunc long dbGetPrecision(const struct link *plink, short *precision);
+epicsShareFunc long dbGetUnits(const struct link *plink, char *units,
+ int unitsSize);
+epicsShareFunc long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
+ epicsEnum16 *severity);
+epicsShareFunc long dbGetTimeStamp(const struct link *plink,
+ epicsTimeStamp *pstamp);
+epicsShareFunc long dbPutLinkValue(struct link *, short dbrType,
+ const void *pbuffer, long nRequest);
+epicsShareFunc void dbScanFwdLink(struct link *plink);
+
+
+#endif /* INC_dbLink_H */
=== modified file 'src/ioc/db/dbNotify.c'
--- src/ioc/db/dbNotify.c 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbNotify.c 2012-05-30 18:10:27 +0000
@@ -5,15 +5,15 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* dbNotify.c */
-/* base/src/db $Revision-Id$ */
+
/*
* Author: Marty Kraimer
- * Date: 03-30-95
+ * Andrew Johnson <[email protected]>
+ *
* Extracted from dbLink.c
-*/
+ */
#include <stdlib.h>
#include <stdarg.h>
@@ -36,7 +36,7 @@
#include "dbCommon.h"
#define epicsExportSharedSymbols
#include "callback.h"
-#include "dbAddr.h"
+#include "dbChannel.h"
#include "dbScan.h"
#include "dbLock.h"
#include "callback.h"
@@ -45,7 +45,7 @@
#include "dbNotify.h"
#include "epicsTime.h"
#include "cantProceed.h"
-
+
/*putNotify.state values */
typedef enum {
putNotifyNotActive,
@@ -55,44 +55,44 @@
putNotifyPutInProgress,
putNotifyUserCallbackRequested,
putNotifyUserCallbackActive
-}putNotifyState;
+} putNotifyState;
/*structure attached to ppnr field of each record*/
typedef struct putNotifyRecord {
- ellCheckNode waitNode;
- ELLLIST restartList; /*list of putNotifys to restart*/
+ ellCheckNode waitNode;
+ ELLLIST restartList; /*list of putNotifys to restart*/
dbCommon *precord;
-}putNotifyRecord;
+} putNotifyRecord;
#define MAGIC 0xfedc0123
typedef struct putNotifyPvt {
- ELLNODE node; /*For free list*/
- long magic;
- short state;
- CALLBACK callback;
- ELLLIST waitList; /*list of records for current putNotify*/
- short cancelWait;
- short userCallbackWait;
+ ELLNODE node; /*For free list*/
+ long magic;
+ short state;
+ CALLBACK callback;
+ ELLLIST waitList; /*list of records for current putNotify*/
+ short cancelWait;
+ short userCallbackWait;
epicsEventId cancelEvent;
epicsEventId userCallbackEvent;
-}putNotifyPvt;
+} putNotifyPvt;
/* putNotify groups can span locksets if links are dynamically modified*/
/* Thus a global lock is taken while putNotify fields are accessed */
typedef struct notifyGlobal {
epicsMutexId lock;
ELLLIST freeList;
-}notifyGlobal;
+} notifyGlobal;
static notifyGlobal *pnotifyGlobal = 0;
-
+
/*Local routines*/
static void putNotifyInit(putNotify *ppn);
static void putNotifyCleanup(putNotify *ppn);
static void restartCheck(putNotifyRecord *ppnr);
-static void callUser(dbCommon *precord,putNotify *ppn);
+static void callUser(dbCommon *precord, putNotify *ppn);
static void notifyCallback(CALLBACK *pcallback);
-static void putNotifyCommon(putNotify *ppn,dbCommon *precord);
+static void putNotifyCommon(putNotify *ppn, dbCommon *precord);
#define ellSafeAdd(list,listnode) \
{ \
@@ -112,9 +112,9 @@
{
putNotifyPvt *pputNotifyPvt;
- pputNotifyPvt = (putNotifyPvt *)ellFirst(&pnotifyGlobal->freeList);
- if(pputNotifyPvt) {
- ellDelete(&pnotifyGlobal->freeList,&pputNotifyPvt->node);
+ pputNotifyPvt = (putNotifyPvt *) ellFirst(&pnotifyGlobal->freeList);
+ if (pputNotifyPvt) {
+ ellDelete(&pnotifyGlobal->freeList, &pputNotifyPvt->node);
} else {
pputNotifyPvt = dbCalloc(1,sizeof(putNotifyPvt));
pputNotifyPvt->cancelEvent = epicsEventCreate(epicsEventEmpty);
@@ -135,26 +135,26 @@
static void putNotifyCleanup(putNotify *ppn)
{
- putNotifyPvt *pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
+ putNotifyPvt *pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
pputNotifyPvt->state = putNotifyNotActive;
- ellAdd(&pnotifyGlobal->freeList,&pputNotifyPvt->node);
+ ellAdd(&pnotifyGlobal->freeList, &pputNotifyPvt->node);
ppn->pputNotifyPvt = 0;
}
-
+
static void restartCheck(putNotifyRecord *ppnr)
{
dbCommon *precord = ppnr->precord;
putNotify *pfirst;
putNotifyPvt *pputNotifyPvt;
-
+
assert(precord->ppn);
- pfirst = (putNotify *)ellFirst(&ppnr->restartList);
- if(!pfirst) {
+ pfirst = (putNotify *) ellFirst(&ppnr->restartList);
+ if (!pfirst) {
precord->ppn = 0;
return;
}
- pputNotifyPvt = (putNotifyPvt *)pfirst->pputNotifyPvt;
+ pputNotifyPvt = (putNotifyPvt *) pfirst->pputNotifyPvt;
assert(pputNotifyPvt->state==putNotifyWaitForRestart);
/* remove pfirst from restartList */
ellSafeDelete(&ppnr->restartList,&pfirst->restartNode);
@@ -165,25 +165,25 @@
callbackRequest(&pputNotifyPvt->callback);
}
-static void callUser(dbCommon *precord,putNotify *ppn)
+static void callUser(dbCommon *precord, putNotify *ppn)
{
- putNotifyPvt *pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
+ putNotifyPvt *pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
(*ppn->userCallback)(ppn);
epicsMutexMustLock(pnotifyGlobal->lock);
- if(pputNotifyPvt->cancelWait && pputNotifyPvt->userCallbackWait) {
+ if (pputNotifyPvt->cancelWait && pputNotifyPvt->userCallbackWait) {
errlogPrintf("%s putNotify: both cancelWait and userCallbackWait true."
- "This is illegal\n",precord->name);
+ "This is illegal\n", precord->name);
pputNotifyPvt->cancelWait = pputNotifyPvt->userCallbackWait = 0;
}
- if(!pputNotifyPvt->cancelWait && !pputNotifyPvt->userCallbackWait) {
+ if (!pputNotifyPvt->cancelWait && !pputNotifyPvt->userCallbackWait) {
putNotifyCleanup(ppn);
- epicsMutexUnlock(pnotifyGlobal->lock);
+ epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
- if(pputNotifyPvt->cancelWait) {
+ if (pputNotifyPvt->cancelWait) {
pputNotifyPvt->cancelWait = 0;
epicsEventSignal(pputNotifyPvt->cancelEvent);
epicsMutexUnlock(pnotifyGlobal->lock);
@@ -195,38 +195,37 @@
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
-
-static void putNotifyCommon(putNotify *ppn,dbCommon *precord)
+
+static void putNotifyCommon(putNotify *ppn, dbCommon *precord)
{
- long status=0;
- dbFldDes *pfldDes = ppn->paddr->pfldDes;
- putNotifyPvt *pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
+ long status;
+ putNotifyPvt *pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
- if(precord->ppn && pputNotifyPvt->state!=putNotifyRestartCallbackRequested)
- { /*another putNotify owns the record */
- pputNotifyPvt->state = putNotifyWaitForRestart;
+ if (precord->ppn &&
+ pputNotifyPvt->state != putNotifyRestartCallbackRequested) { /*another putNotify owns the record */
+ pputNotifyPvt->state = putNotifyWaitForRestart;
ellSafeAdd(&precord->ppnr->restartList,&ppn->restartNode);
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
return;
- } else if(precord->ppn){
- assert(precord->ppn==ppn);
+ } else if (precord->ppn) {
+ assert(precord->ppn == ppn);
assert(pputNotifyPvt->state==putNotifyRestartCallbackRequested);
}
- if(precord->pact) {
+ if (precord->pact) {
precord->ppn = ppn;
ellSafeAdd(&pputNotifyPvt->waitList,&precord->ppnr->waitNode);
- pputNotifyPvt->state = putNotifyRestartInProgress;
+ pputNotifyPvt->state = putNotifyRestartInProgress;
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
return;
}
- status=dbPut(ppn->paddr,ppn->dbrType,ppn->pbuffer,ppn->nRequest);
- ppn->status = (status==0) ? putNotifyOK : putNotifyError;
+ status = dbChannelPut(ppn->chan, ppn->dbrType, ppn->pbuffer, ppn->nRequest);
+ ppn->status = (status == 0) ? putNotifyOK : putNotifyError;
/* Check to see if dbProcess should not be called */
- if(!status /*dont process if dbPut returned error */
- &&((ppn->paddr->pfield==(void *)&precord->proc) /*If PROC call dbProcess*/
- || (pfldDes->process_passive && precord->scan==0))) {
+ if (!status /*dont process if dbPut returned error */
+ && ((dbChannelField(ppn->chan) == (void *) & precord->proc) /*If PROC call dbProcess*/
+ || (dbChannelFldDes(ppn->chan)->process_passive && precord->scan == 0))) {
precord->ppn = ppn;
ellSafeAdd(&pputNotifyPvt->waitList,&precord->ppnr->waitNode);
pputNotifyPvt->state = putNotifyPutInProgress;
@@ -235,31 +234,31 @@
dbScanUnlock(precord);
return;
}
- if(pputNotifyPvt->state==putNotifyRestartCallbackRequested) {
+ if (pputNotifyPvt->state == putNotifyRestartCallbackRequested) {
restartCheck(precord->ppnr);
}
pputNotifyPvt->state = putNotifyUserCallbackActive;
assert(precord->ppn!=ppn);
- callUser(precord,ppn);
+ callUser(precord, ppn);
}
-
+
static void notifyCallback(CALLBACK *pcallback)
{
- putNotify *ppn=NULL;
- dbCommon *precord;
+ putNotify *ppn = NULL;
+ dbCommon *precord;
putNotifyPvt *pputNotifyPvt;
callbackGetUser(ppn,pcallback);
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
- precord = ppn->paddr->precord;
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
+ precord = dbChannelRecord(ppn->chan);
dbScanLock(precord);
epicsMutexMustLock(pnotifyGlobal->lock);
assert(precord->ppnr);
assert(pputNotifyPvt->state==putNotifyRestartCallbackRequested
- || pputNotifyPvt->state==putNotifyUserCallbackRequested);
+ || pputNotifyPvt->state==putNotifyUserCallbackRequested);
assert(ellCount(&pputNotifyPvt->waitList)==0);
- if(pputNotifyPvt->cancelWait) {
- if(pputNotifyPvt->state==putNotifyRestartCallbackRequested) {
+ if (pputNotifyPvt->cancelWait) {
+ if (pputNotifyPvt->state == putNotifyRestartCallbackRequested) {
restartCheck(precord->ppnr);
}
epicsEventSignal(pputNotifyPvt->cancelEvent);
@@ -267,58 +266,61 @@
dbScanUnlock(precord);
return;
}
- if(pputNotifyPvt->state==putNotifyRestartCallbackRequested) {
- putNotifyCommon(ppn,precord);
+ if (pputNotifyPvt->state == putNotifyRestartCallbackRequested) {
+ putNotifyCommon(ppn, precord);
return;
}
/* All done. Clean up and call userCallback */
pputNotifyPvt->state = putNotifyUserCallbackActive;
assert(precord->ppn!=ppn);
- callUser(precord,ppn);
+ callUser(precord, ppn);
}
void epicsShareAPI dbPutNotifyInit(void)
{
- if(pnotifyGlobal) return;
+ if (pnotifyGlobal)
+ return;
pnotifyGlobal = dbCalloc(1,sizeof(notifyGlobal));
pnotifyGlobal->lock = epicsMutexMustCreate();
ellInit(&pnotifyGlobal->freeList);
}
-
+
void epicsShareAPI dbPutNotify(putNotify *ppn)
{
- dbCommon *precord = ppn->paddr->precord;
- short dbfType = ppn->paddr->field_type;
- long status=0;
+ struct dbChannel *chan = ppn->chan;
+ dbCommon *precord = dbChannelRecord(chan);
+ short dbfType = dbChannelFieldType(chan);
+ long status = 0;
putNotifyPvt *pputNotifyPvt;
assert(precord);
/*check for putField disabled*/
- if(precord->disp) {
- if((void *)(&precord->disp) != ppn->paddr->pfield) {
- ppn->status = putNotifyPutDisabled;
- (*ppn->userCallback)(ppn);
- return;
+ if (precord->disp) {
+ if (dbChannelField(chan) != (void *) & precord->disp) {
+ ppn->status = putNotifyPutDisabled;
+ (*ppn->userCallback)(ppn);
+ return;
}
}
/* Must handle DBF_XXXLINKs as special case.
- * Only dbPutField will change link fields.
+ * Only dbPutField will change link fields.
* Also the record is not processed as a result
- */
- if(dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) {
- status=dbPutField(ppn->paddr,ppn->dbrType,ppn->pbuffer,ppn->nRequest);
- ppn->status = (status==0) ? putNotifyOK : putNotifyError;
+ */
+ if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
+ status = dbChannelPutField(ppn->chan, ppn->dbrType, ppn->pbuffer,
+ ppn->nRequest);
+ ppn->status = (status == 0) ? putNotifyOK : putNotifyError;
(*ppn->userCallback)(ppn);
return;
}
dbScanLock(precord);
epicsMutexMustLock(pnotifyGlobal->lock);
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
- if(pputNotifyPvt && (pputNotifyPvt->magic!=MAGIC)) {
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
+ if (pputNotifyPvt && (pputNotifyPvt->magic != MAGIC)) {
printf("dbPutNotify:pputNotifyPvt was not initialized\n");
pputNotifyPvt = 0;
}
- if(pputNotifyPvt) {
+ if (pputNotifyPvt) {
assert(pputNotifyPvt->state==putNotifyUserCallbackActive);
pputNotifyPvt->userCallbackWait = 1;
epicsMutexUnlock(pnotifyGlobal->lock);
@@ -328,38 +330,38 @@
epicsMutexMustLock(pnotifyGlobal->lock);
putNotifyCleanup(ppn);
}
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
assert(!pputNotifyPvt);
putNotifyInit(ppn);
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
- if(!precord->ppnr) {/* make sure record has a putNotifyRecord*/
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
+ if (!precord->ppnr) {/* make sure record has a putNotifyRecord*/
precord->ppnr = dbCalloc(1,sizeof(putNotifyRecord));
precord->ppnr->precord = precord;
ellInit(&precord->ppnr->restartList);
}
- putNotifyCommon(ppn,precord);
+ putNotifyCommon(ppn, precord);
}
-
+
void epicsShareAPI dbNotifyCancel(putNotify *ppn)
{
- dbCommon *precord = ppn->paddr->precord;
+ dbCommon *precord = dbChannelRecord(ppn->chan);
putNotifyState state;
putNotifyPvt *pputNotifyPvt;
assert(precord);
dbScanLock(precord);
epicsMutexMustLock(pnotifyGlobal->lock);
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
- if(!pputNotifyPvt || pputNotifyPvt->state==putNotifyNotActive) {
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
+ if (!pputNotifyPvt || pputNotifyPvt->state == putNotifyNotActive) {
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
return;
}
state = pputNotifyPvt->state;
/*If callback is scheduled or active wait for it to complete*/
- if(state==putNotifyUserCallbackRequested
- || state==putNotifyRestartCallbackRequested
- || state==putNotifyUserCallbackActive) {
+ if (state == putNotifyUserCallbackRequested || state
+ == putNotifyRestartCallbackRequested || state
+ == putNotifyUserCallbackActive) {
pputNotifyPvt->cancelWait = 1;
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
@@ -369,24 +371,26 @@
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
- switch(state) {
- case putNotifyNotActive: break;
+ switch (state) {
+ case putNotifyNotActive:
+ break;
case putNotifyWaitForRestart:
assert(precord->ppn);
assert(precord->ppn!=ppn);
- ellSafeDelete(&precord->ppnr->restartList,&ppn->restartNode);
+ ellSafeDelete(&precord->ppnr->restartList,&ppn->restartNode)
+ ;
break;
case putNotifyRestartInProgress:
- case putNotifyPutInProgress:
- { /*Take all records out of wait list */
- putNotifyRecord *ppnrWait;
+ case putNotifyPutInProgress: { /*Take all records out of wait list */
+ putNotifyRecord *ppnrWait;
- while((ppnrWait = (putNotifyRecord *)ellFirst(&pputNotifyPvt->waitList))){
- ellSafeDelete(&pputNotifyPvt->waitList,&ppnrWait->waitNode);
- restartCheck(ppnrWait);
- }
+ while ((ppnrWait = (putNotifyRecord *) ellFirst(&pputNotifyPvt->waitList))) {
+ ellSafeDelete(&pputNotifyPvt->waitList,&ppnrWait->waitNode);
+ restartCheck(ppnrWait);
}
- if(precord->ppn==ppn) restartCheck(precord->ppnr);
+ }
+ if (precord->ppn == ppn)
+ restartCheck(precord->ppnr);
break;
default:
printf("dbNotify: illegal state for notifyCallback\n");
@@ -396,29 +400,29 @@
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
}
-
+
void epicsShareAPI dbNotifyCompletion(dbCommon *precord)
{
- putNotify *ppn = precord->ppn;
+ putNotify *ppn = precord->ppn;
putNotifyPvt *pputNotifyPvt;
epicsMutexMustLock(pnotifyGlobal->lock);
assert(ppn);
assert(precord->ppnr);
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
- if(pputNotifyPvt->state!=putNotifyRestartInProgress
- && pputNotifyPvt->state!=putNotifyPutInProgress) {
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
+ if (pputNotifyPvt->state != putNotifyRestartInProgress
+ && pputNotifyPvt->state != putNotifyPutInProgress) {
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
ellSafeDelete(&pputNotifyPvt->waitList,&precord->ppnr->waitNode);
- if((ellCount(&pputNotifyPvt->waitList)!=0)) {
+ if ((ellCount(&pputNotifyPvt->waitList)!=0)) {
restartCheck(precord->ppnr);
- } else if(pputNotifyPvt->state == putNotifyPutInProgress) {
+ } else if (pputNotifyPvt->state == putNotifyPutInProgress) {
pputNotifyPvt->state = putNotifyUserCallbackRequested;
restartCheck(precord->ppnr);
callbackRequest(&pputNotifyPvt->callback);
- } else if(pputNotifyPvt->state == putNotifyRestartInProgress) {
+ } else if (pputNotifyPvt->state == putNotifyRestartInProgress) {
pputNotifyPvt->state = putNotifyRestartCallbackRequested;
callbackRequest(&pputNotifyPvt->callback);
} else {
@@ -432,142 +436,140 @@
putNotify *ppn = pfrom->ppn;
putNotifyPvt *pputNotifyPvt;
- if(pto->pact) return; /*if active it will not be processed*/
+ if (pto->pact)
+ return; /*if active it will not be processed*/
epicsMutexMustLock(pnotifyGlobal->lock);
- if(!pto->ppnr) {/* make sure record has a putNotifyRecord*/
+ if (!pto->ppnr) {/* make sure record has a putNotifyRecord*/
pto->ppnr = dbCalloc(1,sizeof(putNotifyRecord));
pto->ppnr->precord = pto;
ellInit(&pto->ppnr->restartList);
}
assert(ppn);
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
- if(!(pto->ppn)
- && (pputNotifyPvt->state==putNotifyPutInProgress)
- && (pto!=ppn->paddr->precord)) {
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
+ if (!pto->ppn &&
+ (pputNotifyPvt->state == putNotifyPutInProgress) &&
+ (pto != dbChannelRecord(ppn->chan))) {
putNotifyPvt *pputNotifyPvt;
pto->ppn = pfrom->ppn;
- pputNotifyPvt = (putNotifyPvt *)pfrom->ppn->pputNotifyPvt;
+ pputNotifyPvt = (putNotifyPvt *) pfrom->ppn->pputNotifyPvt;
ellSafeAdd(&pputNotifyPvt->waitList,&pto->ppnr->waitNode);
}
epicsMutexUnlock(pnotifyGlobal->lock);
}
-
+
typedef struct tpnInfo {
epicsEventId callbackDone;
- putNotify *ppn;
-}tpnInfo;
+ putNotify *ppn;
+} tpnInfo;
static void dbtpnCallback(putNotify *ppn)
{
putNotifyStatus status = ppn->status;
- tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt;
+ tpnInfo *ptpnInfo = (tpnInfo *) ppn->usrPvt;
+ const char *pname = dbChannelRecord(ppn->chan)->name;
- if(status==0)
- printf("dbtpnCallback: success record=%s\n",ppn->paddr->precord->name);
+ if (status == 0)
+ printf("dbtpnCallback: success record=%s\n", pname);
else
- printf("%s dbtpnCallback putNotify.status %d\n",ppn->paddr->precord->name,(int)status);
+ printf("%s dbtpnCallback putNotify.status %d\n",
+ pname, (int) status);
epicsEventSignal(ptpnInfo->callbackDone);
}
static void tpnThread(void *pvt)
{
- tpnInfo *ptpnInfo = (tpnInfo *)pvt;
- putNotify *ppn = (putNotify *)ptpnInfo->ppn;
+ tpnInfo *ptpnInfo = (tpnInfo *) pvt;
+ putNotify *ppn = (putNotify *) ptpnInfo->ppn;
dbPutNotify(ppn);
epicsEventWait(ptpnInfo->callbackDone);
dbNotifyCancel(ppn);
epicsEventDestroy(ptpnInfo->callbackDone);
- free((void *)ppn->paddr);
+ free(ppn->pbuffer);
+ dbChannelDelete(ppn->chan);
free(ppn);
free(ptpnInfo);
}
-long epicsShareAPI dbtpn(char *pname,char *pvalue)
+long epicsShareAPI dbtpn(char *pname, char *pvalue)
{
- long status;
- tpnInfo *ptpnInfo;
- DBADDR *pdbaddr=NULL;
- putNotify *ppn=NULL;
- char *psavevalue;
- int len;
+ struct dbChannel *chan;
+ tpnInfo *ptpnInfo;
+ putNotify *ppn;
+ char *pbuffer;
- len = strlen(pvalue);
- /*allocate space for value immediately following DBADDR*/
- pdbaddr = dbCalloc(1,sizeof(DBADDR) + len+1);
- psavevalue = (char *)(pdbaddr + 1);
- strcpy(psavevalue,pvalue);
- status = dbNameToAddr(pname,pdbaddr);
- if(status) {
- errMessage(status, "dbtpn: dbNameToAddr");
- free((void *)pdbaddr);
- return(-1);
+ pbuffer = strdup(pvalue);
+ chan = dbChannelCreate(pname);
+ if (!chan) {
+ printf("dbtpn: No such channel");
+ return -1;
}
- ppn = dbCalloc(1,sizeof(putNotify));
- ppn->paddr = pdbaddr;
- ppn->pbuffer = psavevalue;
+
+ ppn = dbCalloc(1, sizeof(putNotify));
+ ppn->chan = chan;
+ ppn->pbuffer = pbuffer;
ppn->nRequest = 1;
ppn->dbrType = DBR_STRING;
ppn->userCallback = dbtpnCallback;
- ptpnInfo = dbCalloc(1,sizeof(tpnInfo));
+ ptpnInfo = dbCalloc(1, sizeof(tpnInfo));
ptpnInfo->ppn = ppn;
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
ppn->usrPvt = ptpnInfo;
- epicsThreadCreate("dbtpn",epicsThreadPriorityHigh,
- epicsThreadGetStackSize(epicsThreadStackMedium),
- tpnThread,ptpnInfo);
- return(0);
+ epicsThreadCreate("dbtpn", epicsThreadPriorityHigh,
+ epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
+ return 0;
}
-
+
int epicsShareAPI dbNotifyDump(void)
{
epicsMutexLockStatus lockStatus;
dbRecordType *pdbRecordType;
dbRecordNode *pdbRecordNode;
- dbCommon *precord;
- putNotify *ppn;
- putNotify *ppnRestart;
+ dbCommon *precord;
+ putNotify *ppn;
+ putNotify *ppnRestart;
putNotifyRecord *ppnrWait;
int itry;
-
-
- for(itry=0; itry<100; itry++) {
+
+ for (itry = 0; itry < 100; itry++) {
lockStatus = epicsMutexTryLock(pnotifyGlobal->lock);
- if(lockStatus==epicsMutexLockOK) break;
+ if (lockStatus == epicsMutexLockOK)
+ break;
epicsThreadSleep(.05);
}
- for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
- pdbRecordType;
- pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
- for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
- pdbRecordNode;
- pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
+ for (pdbRecordType = (dbRecordType *) ellFirst(&pdbbase->recordTypeList); pdbRecordType; pdbRecordType
+ = (dbRecordType *) ellNext(&pdbRecordType->node)) {
+ for (pdbRecordNode = (dbRecordNode *) ellFirst(&pdbRecordType->recList); pdbRecordNode; pdbRecordNode
+ = (dbRecordNode *) ellNext(&pdbRecordNode->node)) {
putNotifyPvt *pputNotifyPvt;
precord = pdbRecordNode->precord;
- if (!precord->name[0] ||
- pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
- continue;
- if(!precord->ppn) continue;
- if(!precord->ppnr) continue;
- if(precord->ppn->paddr->precord != precord) continue;
+ if (!precord->name[0] || pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
+ continue;
+ if (!precord->ppn)
+ continue;
+ if (!precord->ppnr)
+ continue;
+ if (dbChannelRecord(precord->ppn->chan) != precord)
+ continue;
ppn = precord->ppn;
- pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
- printf("%s state %d ppn %p\n waitList\n",
- precord->name,pputNotifyPvt->state,(void*)ppn);
- ppnrWait = (putNotifyRecord *)ellFirst(&pputNotifyPvt->waitList);
- while(ppnrWait) {
- printf(" %s pact %d\n",
- ppnrWait->precord->name,ppnrWait->precord->pact);
- ppnrWait = (putNotifyRecord *)ellNext(&ppnrWait->waitNode.node);
+ pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
+ printf("%s state %d ppn %p\n waitList\n", precord->name,
+ pputNotifyPvt->state, (void*) ppn);
+ ppnrWait = (putNotifyRecord *) ellFirst(&pputNotifyPvt->waitList);
+ while (ppnrWait) {
+ printf(" %s pact %d\n", ppnrWait->precord->name,
+ ppnrWait->precord->pact);
+ ppnrWait = (putNotifyRecord *) ellNext(&ppnrWait->waitNode.node);
}
printf(" restartList\n");
- ppnRestart = (putNotify *)ellFirst(&precord->ppnr->restartList);
- while(ppnRestart) {
- printf(" %p\n", (void *)ppnRestart);
- ppnRestart = (putNotify *)ellNext(&ppnRestart->restartNode.node);
+ ppnRestart = (putNotify *) ellFirst(&precord->ppnr->restartList);
+ while (ppnRestart) {
+ printf(" %p\n", (void *) ppnRestart);
+ ppnRestart = (putNotify *) ellNext(&ppnRestart->restartNode.node);
}
}
}
- if(lockStatus==epicsMutexLockOK) epicsMutexUnlock(pnotifyGlobal->lock);
- return(0);
+ if (lockStatus == epicsMutexLockOK)
+ epicsMutexUnlock(pnotifyGlobal->lock);
+ return (0);
}
=== modified file 'src/ioc/db/dbNotify.h'
--- src/ioc/db/dbNotify.h 2006-11-18 00:09:27 +0000
+++ src/ioc/db/dbNotify.h 2012-05-30 18:10:27 +0000
@@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbNotify.h */
@@ -18,12 +18,12 @@
#include "callback.h"
#ifdef __cplusplus
- /* for brain dead C++ compilers */
- struct dbCommon;
- struct putNotify;
extern "C" {
#endif
-
+
+struct dbCommon;
+struct putNotify;
+
typedef struct ellCheckNode{
ELLNODE node;
int isOnList;
@@ -40,7 +40,7 @@
ellCheckNode restartNode;
/*The following members MUST be set by user*/
void (*userCallback)(struct putNotify *);
- struct dbAddr *paddr; /*dbAddr set by dbNameToAddr*/
+ struct dbChannel *chan; /*dbChannel*/
void *pbuffer; /*address of data*/
long nRequest; /*number of elements to be written*/
short dbrType; /*database request type*/
@@ -55,7 +55,7 @@
epicsShareFunc void epicsShareAPI dbPutNotify(putNotify *pputNotify);
epicsShareFunc void epicsShareAPI dbNotifyCancel(putNotify *pputNotify);
-/*dbPutNotifyMapType convience function for old database access*/
+/*dbPutNotifyMapType convenience function for old database access*/
epicsShareFunc int epicsShareAPI dbPutNotifyMapType (putNotify *ppn, short oldtype);
/* dbPutNotifyInit called by iocInit */
@@ -70,9 +70,9 @@
/* dbtpn is test routine for put notify */
epicsShareFunc long epicsShareAPI dbtpn(char *recordname,char *value);
-/* dbNotifyDump is an INVASIVE debug utility. Dont use this needlessly*/
+/* dbNotifyDump is an INVASIVE debug utility. Don't use this needlessly*/
epicsShareFunc int epicsShareAPI dbNotifyDump(void);
-
+
/* This module provides code to handle put notify. If a put causes a record to
* be processed, then a user supplied callback is called when that record
* and all records processed because of that record complete processing.
@@ -87,8 +87,8 @@
*
* After dbPutNotify is called it may not called for the same putNotify
* until the putCallback is complete. The use can call dbNotifyCancel
- * to cancel the operation.
- *
+ * to cancel the operation.
+ *
* The user callback is called when the operation is completed.
*
* The other global routines (dbNotifyAdd and dbNotifyCompletion) are called by:
=== modified file 'src/ioc/db/dbPutNotifyBlocker.cpp'
--- src/ioc/db/dbPutNotifyBlocker.cpp 2011-10-19 18:07:00 +0000
+++ src/ioc/db/dbPutNotifyBlocker.cpp 2012-05-30 18:10:27 +0000
@@ -5,21 +5,21 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/*
+/*
* $Revision-Id$
*
- *
+ *
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
- *
+ *
* Copyright, 1986, The Regents of the University of California.
- *
- *
- * Author:
+ *
+ *
+ * Author:
* Jeffrey O. Hill
* [email protected]
* 505 665 1831
@@ -47,7 +47,7 @@
#include "dbPutNotifyBlocker.h"
dbPutNotifyBlocker::dbPutNotifyBlocker ( epicsMutex & mutexIn ) :
- mutex ( mutexIn ), pNotify ( 0 ),
+ mutex ( mutexIn ), pNotify ( 0 ),
maxValueSize ( sizeof ( this->dbrScalarValue ) )
{
memset ( & this->pn, '\0', sizeof ( this->pn ) );
@@ -55,7 +55,7 @@
this->pn.pbuffer = & this->dbrScalarValue;
}
-dbPutNotifyBlocker::~dbPutNotifyBlocker ()
+dbPutNotifyBlocker::~dbPutNotifyBlocker ()
{
}
@@ -70,7 +70,7 @@
this->~dbPutNotifyBlocker ();
}
-void dbPutNotifyBlocker::cancel (
+void dbPutNotifyBlocker::cancel (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -82,7 +82,7 @@
this->block.signal ();
}
-void dbPutNotifyBlocker::expandValueBuf (
+void dbPutNotifyBlocker::expandValueBuf (
epicsGuard < epicsMutex > & guard, unsigned long newSize )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -127,9 +127,9 @@
}
}
-void dbPutNotifyBlocker::initiatePutNotify (
- epicsGuard < epicsMutex > & guard, cacWriteNotify & notify,
- struct dbAddr & addr, unsigned type, unsigned long count,
+void dbPutNotifyBlocker::initiatePutNotify (
+ epicsGuard < epicsMutex > & guard, cacWriteNotify & notify,
+ struct dbChannel * dbch, unsigned type, unsigned long count,
const void * pValue )
{
guard. assertIdenticalMutex ( this->mutex );
@@ -163,7 +163,7 @@
throw cacChannel::badType();
}
- int status = dbPutNotifyMapType (
+ int status = dbPutNotifyMapType (
&this->pn, static_cast <short> ( type ) );
if ( status ) {
this->pNotify = 0;
@@ -171,7 +171,7 @@
}
this->pn.nRequest = static_cast < unsigned > ( count );
- this->pn.paddr = &addr;
+ this->pn.chan = dbch;
this->pn.userCallback = putNotifyCompletion;
this->pn.usrPvt = this;
@@ -191,22 +191,22 @@
this->show ( guard, level );
}
-void dbPutNotifyBlocker::show (
+void dbPutNotifyBlocker::show (
epicsGuard < epicsMutex > &, unsigned level ) const
{
- printf ( "put notify blocker at %p\n",
+ printf ( "put notify blocker at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {
this->block.show ( level - 1u );
}
}
-dbSubscriptionIO * dbPutNotifyBlocker::isSubscription ()
+dbSubscriptionIO * dbPutNotifyBlocker::isSubscription ()
{
return 0;
}
-void * dbPutNotifyBlocker::operator new ( size_t size,
+void * dbPutNotifyBlocker::operator new ( size_t size,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
@@ -220,7 +220,7 @@
}
#ifdef CXX_PLACEMENT_DELETE
-void dbPutNotifyBlocker::operator delete ( void *pCadaver,
+void dbPutNotifyBlocker::operator delete ( void *pCadaver,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
=== modified file 'src/ioc/db/dbPutNotifyBlocker.h'
--- src/ioc/db/dbPutNotifyBlocker.h 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbPutNotifyBlocker.h 2012-05-30 18:10:27 +0000
@@ -5,20 +5,20 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/*
+/*
* $Revision-Id$
*
- *
+ *
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
- *
+ *
* Copyright, 1986, The Regents of the University of California.
- *
- *
+ *
+ *
* Author Jeffrey O. Hill
* [email protected]
* 505 665 1831
@@ -43,24 +43,24 @@
public:
dbPutNotifyBlocker ( epicsMutex & );
void destructor ( epicsGuard < epicsMutex > & );
- void initiatePutNotify ( epicsGuard < epicsMutex > &,
- cacWriteNotify &, struct dbAddr &,
+ void initiatePutNotify ( epicsGuard < epicsMutex > &,
+ cacWriteNotify &, struct dbChannel *,
unsigned type, unsigned long count, const void * pValue );
void cancel ( epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
- void * operator new ( size_t size,
+ void * operator new ( size_t size,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & );
- epicsPlacementDeleteOperator (( void *,
+ epicsPlacementDeleteOperator (( void *,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & ))
private:
putNotify pn;
//
- // Include a union of all scalar types
+ // Include a union of all scalar types
// including fixed length strings so
- // that in many cases we can avoid
+ // that in many cases we can avoid
// allocating another buffer
- //
+ //
union {
dbr_string_t strval;
dbr_short_t shrtval;
@@ -76,7 +76,7 @@
cacWriteNotify * pNotify;
unsigned long maxValueSize;
dbSubscriptionIO * isSubscription ();
- void expandValueBuf (
+ void expandValueBuf (
epicsGuard < epicsMutex > &, unsigned long newSize );
friend void putNotifyCompletion ( putNotify * ppn );
dbPutNotifyBlocker ( const dbPutNotifyBlocker & );
=== added file 'src/ioc/db/dbState.c'
--- src/ioc/db/dbState.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbState.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,107 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "iocsh.h"
+#include "epicsMutex.h"
+#include "ellLib.h"
+#include "dbStaticLib.h"
+#include "dbDefs.h"
+
+#include "dbState.h"
+
+static ELLLIST states = ELLLIST_INIT;
+
+typedef struct dbState {
+ ELLNODE node;
+ int status;
+ char *name;
+ epicsMutexId lock; /* FIXME: Use atomic operations instead */
+} dbState;
+
+dbStateId dbStateFind(const char *name)
+{
+ ELLNODE *node;
+ dbStateId id;
+
+ for (node = ellFirst(&states); node; node = ellNext(node)) {
+ id = CONTAINER(node, dbState, node);
+ if (strcmp(id->name, name) == 0)
+ return id;
+ }
+ return NULL;
+}
+
+dbStateId dbStateCreate(const char *name)
+{
+ dbStateId id;
+
+ if ((id = dbStateFind(name)))
+ return id;
+
+ id = callocMustSucceed(1, sizeof(dbState), "createDbState");
+ id->name = strdup(name);
+ id->lock = epicsMutexMustCreate();
+ ellAdd(&states, &id->node);
+
+ return id;
+}
+
+void dbStateSet(dbStateId id)
+{
+ if (!id)
+ return;
+ epicsMutexMustLock(id->lock);
+ id->status = 1;
+ epicsMutexUnlock(id->lock);
+}
+
+void dbStateClear(dbStateId id)
+{
+ if (!id)
+ return;
+ epicsMutexMustLock(id->lock);
+ id->status = 0;
+ epicsMutexUnlock(id->lock);
+}
+
+int dbStateGet(dbStateId id)
+{
+ int status;
+
+ if (!id)
+ return 0;
+ epicsMutexMustLock(id->lock);
+ status = id->status;
+ epicsMutexUnlock(id->lock);
+ return status;
+}
+
+void dbStateShow(dbStateId id, unsigned int level)
+{
+ if (level >=1)
+ printf("id %#x '%s' : ", (unsigned int) id, id->name);
+ printf("%s\n", dbStateGet(id) ? "TRUE" : "FALSE");
+}
+
+void dbStateShowAll(unsigned int level)
+{
+ ELLNODE *node;
+ dbStateId id;
+
+ for (node = ellFirst(&states); node; node = ellNext(node)) {
+ id = CONTAINER(node, dbState, node);
+ dbStateShow(id, level+1);
+ }
+}
=== added file 'src/ioc/db/dbState.h'
--- src/ioc/db/dbState.h 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbState.h 2012-05-30 18:10:27 +0000
@@ -0,0 +1,92 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#ifndef INCdbStateH
+#define INCdbStateH
+
+#include "shareLib.h"
+
+/** @file dbState.h
+ * @brief Generic IOC state facility
+ *
+ * This library provides a simple global flag facility that can be used to
+ * synchronize e.g. plugins with IOC-wide states, that may be derived from
+ * events (either soft events or hard events coming from specialized timing
+ * and event hardware).
+ *
+ * A subset of this API is provided as IOC Shell commands to allow
+ * command line debugging.
+ *
+ */
+
+typedef struct dbState *dbStateId;
+
+/** @brief Create db state.
+ *
+ * Creates a new db state with the specified 'name', returning the new id.
+ * If state with that name already exists, the existing state's id is returned.
+ *
+ * <em>Also provided as an IOC Shell command.</em>
+ *
+ * @param name Db state name.
+ * @return Id of db state, NULL for failure.
+ */
+epicsShareFunc dbStateId dbStateCreate(const char *name);
+
+/** @brief Find db state.
+ *
+ * @param name Db state name.
+ * @return Id of db state, NULL if not found.
+ */
+epicsShareFunc dbStateId dbStateFind(const char *name);
+
+/** @brief Set db state to TRUE.
+ *
+ * <em>Also provided as an IOC Shell command.</em>
+ *
+ * @param id Db state id.
+ */
+epicsShareFunc void dbStateSet(dbStateId id);
+
+/** @brief Set db state to FALSE.
+ *
+ * <em>Also provided as an IOC Shell command.</em>
+ *
+ * @param id Db state id.
+ */
+epicsShareFunc void dbStateClear(dbStateId id);
+
+/** @brief Get db state.
+ *
+ * @param id Db state id.
+ * @return Current db state (0|1).
+ */
+epicsShareFunc int dbStateGet(dbStateId id);
+
+/** @brief Print info about db state.
+ *
+ * <em>Also provided as an IOC Shell command.</em>
+ *
+ * @param id Db state id.
+ * @param level Interest level.
+ */
+epicsShareFunc void dbStateShow(dbStateId id, unsigned int level);
+
+/** @brief Print info about all db states.
+ *
+ * <em>Also provided as an IOC Shell command.</em>
+ *
+ * @param level Interest level.
+ */
+epicsShareFunc void dbStateShowAll(unsigned int level);
+
+#endif // INCdbStateH
=== modified file 'src/ioc/db/dbSubscriptionIO.cpp'
--- src/ioc/db/dbSubscriptionIO.cpp 2010-10-05 19:27:37 +0000
+++ src/ioc/db/dbSubscriptionIO.cpp 2012-05-30 18:10:27 +0000
@@ -4,20 +4,20 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/*
+/*
* $Revision-Id$
*
- *
+ *
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
- *
+ *
* Copyright, 1986, The Regents of the University of California.
- *
- *
+ *
+ *
* Author Jeffrey O. Hill
* [email protected]
* 505 665 1831
@@ -41,18 +41,18 @@
#include "dbChannelIO.h"
#include "db_access_routines.h"
-dbSubscriptionIO::dbSubscriptionIO (
+dbSubscriptionIO::dbSubscriptionIO (
epicsGuard < epicsMutex > & guard, epicsMutex & mutexIn,
- dbContext &, dbChannelIO & chanIO,
- dbAddr & addr, cacStateNotify & notifyIn, unsigned typeIn,
+ dbContext &, dbChannelIO & chanIO,
+ dbChannel * dbch, cacStateNotify & notifyIn, unsigned typeIn,
unsigned long countIn, unsigned maskIn, dbEventCtx ctx ) :
- mutex ( mutexIn ), count ( countIn ), notify ( notifyIn ),
+ mutex ( mutexIn ), count ( countIn ), notify ( notifyIn ),
chan ( chanIO ), es ( 0 ), type ( typeIn ), id ( 0u )
{
guard.assertIdenticalMutex ( this->mutex );
{
epicsGuardRelease < epicsMutex > unguard ( guard );
- this->es = db_add_event ( ctx, & addr,
+ this->es = db_add_event ( ctx, dbch,
dbSubscriptionEventCallback, (void *) this, maskIn );
if ( this->es == 0 ) {
throw std::bad_alloc();
@@ -62,7 +62,7 @@
}
}
-dbSubscriptionIO::~dbSubscriptionIO ()
+dbSubscriptionIO::~dbSubscriptionIO ()
{
}
@@ -72,7 +72,7 @@
this->~dbSubscriptionIO ();
}
-void dbSubscriptionIO::unsubscribe (
+void dbSubscriptionIO::unsubscribe (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -86,11 +86,11 @@
}
}
-void dbSubscriptionIO::channelDeleteException (
+void dbSubscriptionIO::channelDeleteException (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
- this->notify.exception ( guard, ECA_CHANDESTROY,
+ this->notify.exception ( guard, ECA_CHANDESTROY,
this->chan.pName(guard), this->type, this->count );
}
@@ -112,21 +112,21 @@
__FILE__, __LINE__ );
}
-void * dbSubscriptionIO::operator new ( size_t size,
+void * dbSubscriptionIO::operator new ( size_t size,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
-void dbSubscriptionIO::operator delete ( void * pCadaver,
+void dbSubscriptionIO::operator delete ( void * pCadaver,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
-extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbAddr * /* paddr */,
+extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbChannel * /* dbch */,
int /* eventsRemaining */, struct db_field_log *pfl )
{
dbSubscriptionIO * pIO = static_cast < dbSubscriptionIO * > ( pPrivate );
@@ -139,19 +139,19 @@
this->show ( guard, level );
}
-void dbSubscriptionIO::show (
+void dbSubscriptionIO::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
- printf ( "Data base subscription IO at %p\n",
+ printf ( "Data base subscription IO at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {
short tmpType;
if ( this->type < SHRT_MAX ) {
tmpType = static_cast < short > ( this->type );
printf ( "\ttype %s, count %lu, channel at %p\n",
- dbf_type_to_text ( tmpType ), this->count,
+ dbf_type_to_text ( tmpType ), this->count,
static_cast <void *> ( &this->chan ) );
}
else {
@@ -161,7 +161,7 @@
}
}
-dbSubscriptionIO * dbSubscriptionIO::isSubscription ()
+dbSubscriptionIO * dbSubscriptionIO::isSubscription ()
{
return this;
}
=== modified file 'src/ioc/db/db_access.c'
--- src/ioc/db/db_access.c 2011-08-30 23:09:11 +0000
+++ src/ioc/db/db_access.c 2012-05-30 18:10:27 +0000
@@ -4,15 +4,13 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* $Revision-Id$ */
-
/* Interface between old database access and new
*
* Author: Marty Kraimer
- * Date: 6-1-90
+ * Andrew Johnson <[email protected]>
*/
#include <stddef.h>
@@ -24,6 +22,7 @@
#include "epicsConvert.h"
#include "dbDefs.h"
+#include "dbChannel.h"
#include "errlog.h"
#include "ellLib.h"
#include "epicsTime.h"
@@ -42,10 +41,6 @@
#include "dbEvent.h"
#include "db_access_routines.h"
-#ifndef NULL
-#define NULL 0
-#endif
-
#define oldDBF_STRING 0
#define oldDBF_INT 1
@@ -108,50 +103,36 @@
typedef char DBSTRING[MAX_STRING_SIZE];
-#ifndef MAX_STRING_SIZE
-#define MAX_STRING_SIZE 40
-#endif
-
-/*
- * DB_PROCESS
- *
- * process database records
- */
-void db_process(struct dbAddr *paddr)
-{
- long status = dbProcess(paddr->precord);
-
- if (status) errMessage(status, "db_process failed");
-}
-
-/*
- * DB_NAME_TO_ADDR
- */
-int epicsShareAPI db_name_to_addr(const char *pname, struct dbAddr *paddr)
-{
- long status;
+struct dbChannel * dbChannel_create(const char *pname)
+{
+ dbChannel *chan = dbChannelCreate(pname);
short ftype;
- status = dbNameToAddr(pname, paddr);
- if (!status) {
- ftype = paddr->dbr_field_type;
- if (INVALID_DB_REQ(ftype)) {
- errlogPrintf("%s dbNameToAddr failed\n", pname);
- return -2;
- }
- paddr->dbr_field_type = dbDBRnewToDBRold[ftype];
- return 0;
- }
- else
- return -1;
+ if (!chan)
+ return NULL;
+
+ ftype = chan->addr.dbr_field_type;
+ if (INVALID_DB_REQ(ftype)) {
+ dbChannelDelete(chan);
+ return NULL;
+ }
+
+ chan->addr.dbr_field_type = dbDBRnewToDBRold[ftype];
+
+ if (dbChannelOpen(chan)) {
+ dbChannelDelete(chan);
+ return NULL;
+ }
+
+ return chan;
}
-
-int epicsShareAPI db_get_field(struct dbAddr *paddr,
- int buffer_type, void *pbuffer, int no_elements, void *pfl)
+
+int dbChannel_get(struct dbChannel *chan,
+ int buffer_type, void *pbuffer, long no_elements, void *pfl)
{
long nRequest = no_elements;
- int result = db_get_field_and_count(
- paddr, buffer_type, pbuffer, &nRequest, pfl);
+ int result = dbChannel_get_count(
+ chan, buffer_type, pbuffer, &nRequest, pfl);
if (nRequest < no_elements) {
/* The database request returned fewer elements than requested, so
* fill the remainder of the buffer with zeros.
@@ -168,10 +149,11 @@
/* Performs the work of the public db_get_field API, but also returns the number
* of elements actually copied to the buffer. The caller is responsible for
* zeroing the remaining part of the buffer. */
-int epicsShareAPI db_get_field_and_count(
- struct dbAddr *paddr, int buffer_type,
+int epicsShareAPI dbChannel_get_count(
+ struct dbChannel *chan, int buffer_type,
void *pbuffer, long *nRequest, void *pfl)
{
+ dbAddr *paddr=&chan->addr;
long status;
long options;
long i;
@@ -184,26 +166,26 @@
switch(buffer_type) {
case(oldDBR_STRING):
- status = dbGetField(paddr, DBR_STRING, pbuffer, &zero, nRequest, pfl);
+ status = dbChannelGetField(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
break;
/* case(oldDBR_INT): */
case(oldDBR_SHORT):
- status = dbGetField(paddr, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
+ status = dbChannelGetField(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_FLOAT):
- status = dbGetField(paddr, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
+ status = dbChannelGetField(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_ENUM):
- status = dbGetField(paddr, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
+ status = dbChannelGetField(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_CHAR):
- status = dbGetField(paddr, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
+ status = dbChannelGetField(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_LONG):
- status = dbGetField(paddr, DBR_LONG, pbuffer, &zero, nRequest, pfl);
+ status = dbChannelGetField(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_DOUBLE):
- status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
+ status = dbChannelGetField(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_STS_STRING):
@@ -216,10 +198,10 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
- status = dbGetField(paddr, DBR_STRING, pold->value, &zero,
+ status = dbChannelGetField(chan, DBR_STRING, pold->value, &zero,
nRequest, pfl);
}
break;
@@ -232,10 +214,10 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
- status = dbGetField(paddr, DBR_SHORT, &pold->value, &zero,
+ status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -247,10 +229,10 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
- status = dbGetField(paddr, DBR_FLOAT, &pold->value, &zero,
+ status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -262,10 +244,10 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
- status = dbGetField(paddr, DBR_ENUM, &pold->value, &zero,
+ status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -277,10 +259,10 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
- status = dbGetField(paddr, DBR_UCHAR, &pold->value, &zero,
+ status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -292,10 +274,10 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
- status = dbGetField(paddr, DBR_LONG, &pold->value, &zero,
+ status = dbChannelGetField(chan, DBR_LONG, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -307,11 +289,11 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
- status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -325,12 +307,12 @@
} newSt;
options = DBR_STATUS | DBR_TIME;
- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
- status = dbGetField(paddr, DBR_STRING, pold->value, &options,
+ status = dbChannelGetField(chan, DBR_STRING, pold->value, &options,
nRequest, pfl);
}
break;
@@ -344,12 +326,12 @@
} newSt;
options = DBR_STATUS | DBR_TIME;
- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
- status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -362,12 +344,12 @@
} newSt;
options = DBR_STATUS | DBR_TIME;
- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
- status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -380,12 +362,12 @@
} newSt;
options = DBR_STATUS | DBR_TIME;
- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
- status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -398,12 +380,12 @@
} newSt;
options = DBR_STATUS | DBR_TIME;
- status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_CHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
- status = dbGetField(paddr, DBR_CHAR, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_CHAR, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -416,12 +398,12 @@
} newSt;
options = DBR_STATUS | DBR_TIME;
- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
- status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -434,12 +416,12 @@
} newSt;
options = DBR_STATUS | DBR_TIME;
- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
- status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -457,7 +439,7 @@
} newSt;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -469,7 +451,7 @@
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
- status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -486,7 +468,7 @@
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_AL_DOUBLE;
- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -499,7 +481,7 @@
pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit);
options = 0;
- status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -515,7 +497,7 @@
} newSt;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -527,7 +509,7 @@
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
- status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -542,7 +524,7 @@
} newSt;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -554,7 +536,7 @@
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
- status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -571,7 +553,7 @@
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_AL_DOUBLE;
- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -584,7 +566,7 @@
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
- status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -603,7 +585,7 @@
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -617,7 +599,7 @@
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
- status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -635,7 +617,7 @@
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -650,7 +632,7 @@
pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit);
pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit);
options = 0;
- status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -667,7 +649,7 @@
memset(pold, '\0', sizeof(struct dbr_ctrl_enum));
/* first get status and severity */
options = DBR_STATUS | DBR_ENUM_STRS;
- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
no_str = newSt.no_str;
@@ -677,7 +659,7 @@
strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i]));
/*now get values*/
options = 0;
- status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -694,7 +676,7 @@
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -708,7 +690,7 @@
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
- status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -725,7 +707,7 @@
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -739,7 +721,7 @@
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
- status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -757,7 +739,7 @@
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -772,7 +754,7 @@
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
- status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
+ status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -785,13 +767,13 @@
} newSt;
options = DBR_STATUS;
- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
+ status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->ackt = newSt.ackt;
pold->acks = newSt.acks;
options = 0;
- status = dbGetField(paddr, DBR_STRING, pold->value,
+ status = dbChannelGetField(chan, DBR_STRING, pold->value,
&options, nRequest, pfl);
}
break;
@@ -807,7 +789,7 @@
break;
}
dbInitEntry(pdbbase, &dbEntry);
- status = dbFindRecord(&dbEntry, paddr->precord->name);
+ status = dbFindRecord(&dbEntry, dbChannelRecord(chan)->name);
if (!status) name = dbGetRecordTypeName(&dbEntry);
dbFinishEntry(&dbEntry);
if (status) break;
@@ -825,165 +807,163 @@
if (status) return -1;
return 0;
}
-
-/* DB_PUT_FIELD put a field and convert it to the desired type */
-int epicsShareAPI db_put_field(struct dbAddr *paddr, int src_type,
- const void *psrc, int no_elements)
+int dbChannel_put(struct dbChannel *chan, int src_type,
+ const void *psrc, long no_elements)
{
long status;
- switch(src_type) {
+ switch (src_type) {
case(oldDBR_STRING):
- status = dbPutField(paddr, DBR_STRING, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_STRING, psrc, no_elements);
break;
/* case(oldDBR_INT): */
case(oldDBR_SHORT):
- status = dbPutField(paddr, DBR_SHORT, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_SHORT, psrc, no_elements);
break;
case(oldDBR_FLOAT):
- status = dbPutField(paddr, DBR_FLOAT, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_FLOAT, psrc, no_elements);
break;
case(oldDBR_ENUM):
- status = dbPutField(paddr, DBR_ENUM, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_ENUM, psrc, no_elements);
break;
case(oldDBR_CHAR):
- status = dbPutField(paddr, DBR_UCHAR, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_UCHAR, psrc, no_elements);
break;
case(oldDBR_LONG):
- status = dbPutField(paddr, DBR_LONG, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_LONG, psrc, no_elements);
break;
case(oldDBR_DOUBLE):
- status = dbPutField(paddr, DBR_DOUBLE, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_DOUBLE, psrc, no_elements);
break;
case(oldDBR_STS_STRING):
- status = dbPutField(paddr, DBR_STRING,
+ status = dbChannelPutField(chan, DBR_STRING,
((const struct dbr_sts_string *)psrc)->value, no_elements);
break;
/* case(oldDBR_STS_INT): */
case(oldDBR_STS_SHORT):
- status = dbPutField(paddr, DBR_SHORT,
+ status = dbChannelPutField(chan, DBR_SHORT,
&((const struct dbr_sts_short *)psrc)->value, no_elements);
break;
case(oldDBR_STS_FLOAT):
- status = dbPutField(paddr, DBR_FLOAT,
+ status = dbChannelPutField(chan, DBR_FLOAT,
&((const struct dbr_sts_float *)psrc)->value, no_elements);
break;
case(oldDBR_STS_ENUM):
- status = dbPutField(paddr, DBR_ENUM,
+ status = dbChannelPutField(chan, DBR_ENUM,
&((const struct dbr_sts_enum *)psrc)->value, no_elements);
break;
case(oldDBR_STS_CHAR):
- status = dbPutField(paddr, DBR_UCHAR,
+ status = dbChannelPutField(chan, DBR_UCHAR,
&((const struct dbr_sts_char *)psrc)->value, no_elements);
break;
case(oldDBR_STS_LONG):
- status = dbPutField(paddr, DBR_LONG,
+ status = dbChannelPutField(chan, DBR_LONG,
&((const struct dbr_sts_long *)psrc)->value, no_elements);
break;
case(oldDBR_STS_DOUBLE):
- status = dbPutField(paddr, DBR_DOUBLE,
+ status = dbChannelPutField(chan, DBR_DOUBLE,
&((const struct dbr_sts_double *)psrc)->value, no_elements);
break;
case(oldDBR_TIME_STRING):
- status = dbPutField(paddr, DBR_TIME,
+ status = dbChannelPutField(chan, DBR_TIME,
((const struct dbr_time_string *)psrc)->value, no_elements);
break;
/* case(oldDBR_TIME_INT): */
case(oldDBR_TIME_SHORT):
- status = dbPutField(paddr, DBR_SHORT,
+ status = dbChannelPutField(chan, DBR_SHORT,
&((const struct dbr_time_short *)psrc)->value, no_elements);
break;
case(oldDBR_TIME_FLOAT):
- status = dbPutField(paddr, DBR_FLOAT,
+ status = dbChannelPutField(chan, DBR_FLOAT,
&((const struct dbr_time_float *)psrc)->value, no_elements);
break;
case(oldDBR_TIME_ENUM):
- status = dbPutField(paddr, DBR_ENUM,
+ status = dbChannelPutField(chan, DBR_ENUM,
&((const struct dbr_time_enum *)psrc)->value, no_elements);
break;
case(oldDBR_TIME_CHAR):
- status = dbPutField(paddr, DBR_UCHAR,
+ status = dbChannelPutField(chan, DBR_UCHAR,
&((const struct dbr_time_char *)psrc)->value, no_elements);
break;
case(oldDBR_TIME_LONG):
- status = dbPutField(paddr, DBR_LONG,
+ status = dbChannelPutField(chan, DBR_LONG,
&((const struct dbr_time_long *)psrc)->value, no_elements);
break;
case(oldDBR_TIME_DOUBLE):
- status = dbPutField(paddr, DBR_DOUBLE,
+ status = dbChannelPutField(chan, DBR_DOUBLE,
&((const struct dbr_time_double *)psrc)->value, no_elements);
break;
case(oldDBR_GR_STRING):
/* no struct dbr_gr_string - use dbr_sts_string instead */
- status = dbPutField(paddr, DBR_STRING,
+ status = dbChannelPutField(chan, DBR_STRING,
((const struct dbr_sts_string *)psrc)->value, no_elements);
break;
/* case(oldDBR_GR_INT): */
case(oldDBR_GR_SHORT):
- status = dbPutField(paddr, DBR_SHORT,
+ status = dbChannelPutField(chan, DBR_SHORT,
&((const struct dbr_gr_short *)psrc)->value, no_elements);
break;
case(oldDBR_GR_FLOAT):
- status = dbPutField(paddr, DBR_FLOAT,
+ status = dbChannelPutField(chan, DBR_FLOAT,
&((const struct dbr_gr_float *)psrc)->value, no_elements);
break;
case(oldDBR_GR_ENUM):
- status = dbPutField(paddr, DBR_ENUM,
+ status = dbChannelPutField(chan, DBR_ENUM,
&((const struct dbr_gr_enum *)psrc)->value, no_elements);
break;
case(oldDBR_GR_CHAR):
- status = dbPutField(paddr, DBR_UCHAR,
+ status = dbChannelPutField(chan, DBR_UCHAR,
&((const struct dbr_gr_char *)psrc)->value, no_elements);
break;
case(oldDBR_GR_LONG):
- status = dbPutField(paddr, DBR_LONG,
+ status = dbChannelPutField(chan, DBR_LONG,
&((const struct dbr_gr_long *)psrc)->value, no_elements);
break;
case(oldDBR_GR_DOUBLE):
- status = dbPutField(paddr, DBR_DOUBLE,
+ status = dbChannelPutField(chan, DBR_DOUBLE,
&((const struct dbr_gr_double *)psrc)->value, no_elements);
break;
case(oldDBR_CTRL_STRING):
/* no struct dbr_ctrl_string - use dbr_sts_string instead */
- status = dbPutField(paddr, DBR_STRING,
+ status = dbChannelPutField(chan, DBR_STRING,
((const struct dbr_sts_string *)psrc)->value, no_elements);
break;
/* case(oldDBR_CTRL_INT): */
case(oldDBR_CTRL_SHORT):
- status = dbPutField(paddr, DBR_SHORT,
+ status = dbChannelPutField(chan, DBR_SHORT,
&((const struct dbr_ctrl_short *)psrc)->value, no_elements);
break;
case(oldDBR_CTRL_FLOAT):
- status = dbPutField(paddr, DBR_FLOAT,
+ status = dbChannelPutField(chan, DBR_FLOAT,
&((const struct dbr_ctrl_float *)psrc)->value, no_elements);
break;
case(oldDBR_CTRL_ENUM):
- status = dbPutField(paddr, DBR_ENUM,
+ status = dbChannelPutField(chan, DBR_ENUM,
&((const struct dbr_ctrl_enum *)psrc)->value, no_elements);
break;
case(oldDBR_CTRL_CHAR):
- status = dbPutField(paddr, DBR_UCHAR,
+ status = dbChannelPutField(chan, DBR_UCHAR,
&((const struct dbr_ctrl_char *)psrc)->value, no_elements);
break;
case(oldDBR_CTRL_LONG):
- status = dbPutField(paddr, DBR_LONG,
+ status = dbChannelPutField(chan, DBR_LONG,
&((const struct dbr_ctrl_long *)psrc)->value, no_elements);
break;
case(oldDBR_CTRL_DOUBLE):
- status = dbPutField(paddr, DBR_DOUBLE,
+ status = dbChannelPutField(chan, DBR_DOUBLE,
&((const struct dbr_ctrl_double *)psrc)->value, no_elements);
break;
case(oldDBR_PUT_ACKT):
- status = dbPutField(paddr, DBR_PUT_ACKT, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_PUT_ACKT, psrc, no_elements);
break;
case(oldDBR_PUT_ACKS):
- status = dbPutField(paddr, DBR_PUT_ACKS, psrc, no_elements);
+ status = dbChannelPutField(chan, DBR_PUT_ACKS, psrc, no_elements);
break;
default:
@@ -993,7 +973,7 @@
return 0;
}
-
+
epicsShareFunc int epicsShareAPI dbPutNotifyMapType (putNotify *ppn, short oldtype)
{
switch(oldtype) {
=== modified file 'src/ioc/db/db_access_routines.h'
--- src/ioc/db/db_access_routines.h 2010-09-27 16:41:53 +0000
+++ src/ioc/db/db_access_routines.h 2012-05-30 18:10:27 +0000
@@ -1,11 +1,10 @@
/*************************************************************************\
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* base/include/db_access_routines.h */
@@ -22,26 +21,21 @@
#endif
#include "shareLib.h"
-#include "dbAddr.h"
epicsShareExtern struct dbBase *pdbbase;
epicsShareExtern volatile int interruptAccept;
/*
- * old db access API
- * (included here because these routines use dbAccess.h and their
- * prototypes must also be included in db_access.h)
+ * Adaptors for db_access users
*/
-epicsShareFunc int epicsShareAPI db_name_to_addr(
- const char *pname, DBADDR *paddr);
-epicsShareFunc int epicsShareAPI db_put_field(
- DBADDR *paddr, int src_type,const void *psrc, int no_elements);
-epicsShareFunc int epicsShareAPI db_get_field(
- DBADDR *paddr, int dest_type,void *pdest, int no_elements, void *pfl);
-epicsShareFunc int epicsShareAPI db_get_field_and_count(
- struct dbAddr *paddr, int buffer_type,
- void *pbuffer, long *nRequest, void *pfl);
+epicsShareFunc struct dbChannel * dbChannel_create(const char *pname);
+epicsShareFunc int dbChannel_get(struct dbChannel *chan,
+ int buffer_type, void *pbuffer, long no_elements, void *pfl);
+epicsShareFunc int dbChannel_put(struct dbChannel *chan, int src_type,
+ const void *psrc, long no_elements);
+epicsShareFunc int epicsShareAPI dbChannel_get_count(struct dbChannel *chan,
+ int buffer_type, void *pbuffer, long *nRequest, void *pfl);
#ifdef __cplusplus
=== modified file 'src/ioc/db/db_field_log.h'
--- src/ioc/db/db_field_log.h 2010-10-05 19:27:37 +0000
+++ src/ioc/db/db_field_log.h 2012-05-30 18:10:27 +0000
@@ -1,19 +1,26 @@
/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* $Revision-Id$
- * Author: Jeffrey O. Hill
- * Date: 4-1-89
+
+/*
+ * Author: Jeffrey O. Hill <[email protected]>
+ *
+ * Ralph Lange <[email protected]>
*/
+
#ifndef INCLdb_field_logh
#define INCLdb_field_logh
+#include "epicsTime.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -27,7 +34,7 @@
* will most likely change infrequently.
*
*/
-union native_value{
+union native_value {
short dbf_int;
short dbf_short;
float dbf_float;
@@ -36,7 +43,7 @@
long dbf_long;
double dbf_double;
#ifdef DB_EVENT_LOG_STRINGS
- char dbf_string[MAXSTRINGSIZE];
+ char dbf_string[MAX_STRING_SIZE];
#endif
};
@@ -44,12 +51,48 @@
* structure to log the state of a data base field at the time
* an event is triggered.
*/
+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 */
+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_event
+} dbfl_context;
+
+#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref")
+
+struct dbfl_val {
+ union native_value field; /* Field value */
+};
+
+struct dbfl_ref {
+ dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
+ void *pvt; /* Private pointer */
+ void *field; /* Field value */
+};
+
typedef struct db_field_log {
- unsigned short stat; /* Alarm Status */
- unsigned short sevr; /* Alarm Severity */
- epicsTimeStamp time; /* time stamp */
- union native_value field; /* field value */
-}db_field_log;
+ enum dbfl_type type:2; /* type (union) selector */
+ enum dbfl_context ctx:1; /* context (operation type) */
+ epicsTimeStamp time; /* Time stamp */
+ 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 */
+ union {
+ struct dbfl_val v;
+ struct dbfl_ref r;
+ } u;
+} db_field_log;
#ifdef __cplusplus
}
=== modified file 'src/ioc/db/db_test.c'
--- src/ioc/db/db_test.c 2012-05-03 17:19:34 +0000
+++ src/ioc/db/db_test.c 2012-05-30 18:10:27 +0000
@@ -5,13 +5,13 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* share/src/db @(#)db_test.c 1.10 2/3/94 */
+
/* database access subroutines */
/*
* Author: Bob Dalesio
- * Date: 4/15/88
+ * Andrew Johnson <[email protected]>
*/
#include <stddef.h>
#include <epicsStdlib.h>
@@ -23,706 +23,230 @@
#include "cadef.h"
#include "epicsStdio.h"
#define epicsExportSharedSymbols
+#include "dbChannel.h"
#include "db_access_routines.h"
#include "dbNotify.h"
#include "db_test.h"
#include "dbCommon.h"
-
#define MAX_ELEMS 10
-int epicsShareAPI gft(char *pname)
+
+int gft(char *pname)
{
- char tgf_buffer[MAX_ELEMS*MAX_STRING_SIZE+sizeof(struct dbr_ctrl_double)];
- struct dbAddr addr;
- struct dbAddr *paddr = &addr;
- short number_elements;
- int i;
- int status;
-
- if (pname==0 || ((*pname < ' ') || (*pname > 'z'))) {
- printf("\nusage \"pv name\"\n");
- return(1);
- }
- /* convert name to database address */
- status=db_name_to_addr(pname,&addr);
- if(status) {
- printf("db_name_to_addr failed\n");
- return(1);
- }
- printf(" Record Name: %s\n",pname);
- printf("Record Address: 0x%p\n",(void *)addr.precord);
- printf(" Field Type: %d\n",addr.dbr_field_type);
- printf(" Field Address: 0x%p\n",addr.pfield);
- printf(" Field Size: %d\n",addr.field_size);
- printf(" No Elements: %ld\n",addr.no_elements);
- number_elements =
- ((addr.no_elements > MAX_ELEMS)?MAX_ELEMS:addr.no_elements);
-
- for(i=0; i<=LAST_BUFFER_TYPE; i++) {
- if(addr.dbr_field_type==0) {
- if( (i!=DBR_STRING)
- && (i!=DBR_STS_STRING)
- && (i!=DBR_TIME_STRING)
- && (i!=DBR_GR_STRING)
- && (i!=DBR_CTRL_STRING)) continue;
- }
- if(db_get_field(paddr,i,tgf_buffer,number_elements,NULL)<0)
- printf("\t%s Failed\n",dbr_text[i]);
- else
- ca_dump_dbr (i,number_elements,tgf_buffer);
- }
- return(0);
+ char tgf_buffer[MAX_ELEMS*MAX_STRING_SIZE + sizeof(struct dbr_ctrl_double)];
+ struct dbChannel *chan;
+ struct dbCommon *precord;
+ long elements;
+ short type;
+ int i;
+
+ chan = dbChannel_create(pname);
+ if (!chan) {
+ printf("Channel couldn't be created\n");
+ return 1;
+ }
+
+ precord = dbChannelRecord(chan);
+ elements = dbChannelElements(chan);
+ type = dbChannelExportType(chan);
+
+ printf(" Record Name: %s\n", precord->name);
+ printf("Record Address: 0x%p\n", precord);
+ printf(" Export Type: %d\n", type);
+ printf(" Field Address: 0x%p\n", dbChannelField(chan));
+ printf(" Field Size: %d\n", dbChannelFieldSize(chan));
+ printf(" No Elements: %ld\n", elements);
+
+ if (elements > MAX_ELEMS)
+ elements = MAX_ELEMS;
+
+ for (i = 0; i <= LAST_BUFFER_TYPE; i++) {
+ if (type == 0) {
+ if ((i != DBR_STRING) && (i != DBR_STS_STRING) &&
+ (i != DBR_TIME_STRING) && (i != DBR_GR_STRING) &&
+ (i != DBR_CTRL_STRING))
+ continue;
+ }
+ if (dbChannel_get(chan, i, tgf_buffer, elements, NULL) < 0)
+ printf("\t%s Failed\n", dbr_text[i]);
+ else
+ ca_dump_dbr(i, elements, tgf_buffer);
+ }
+
+ dbChannelDelete(chan);
+ return 0;
}
-
+
/*
* TPF
* Test put field
*/
-int epicsShareAPI pft(char *pname,char *pvalue)
-{
- struct dbAddr addr;
- struct dbAddr *paddr = &addr;
- char buffer[500];
- short shortvalue;
- long longvalue;
- float floatvalue;
- unsigned char charvalue;
- double doublevalue;
- int status;
-
- if (pname==0 || pvalue==0
- || ((*pname < ' ') || (*pname > 'z'))
- || ((*pvalue < ' ') || (*pvalue > 'z'))){
- printf("\nusage \"pv name\",\"value\"\n");
- return(1);
- }
-
- /* convert name to database address */
-
- /* convert name to database address */
- status=db_name_to_addr(pname,&addr);
- if(status) {
- printf("db_name_to_addr failed\n");
- return(1);
- }
- printf(" Record Name: %s\n",pname);
- printf("Record Address: 0x%p\n",(void *)addr.precord);
- printf(" Field Type: %d\n",addr.dbr_field_type);
- printf(" Field Address: 0x%p\n",addr.pfield);
- printf(" Field Size: %d\n",addr.field_size);
- printf(" No Elements: %ld\n",addr.no_elements);
- if (db_put_field(paddr,DBR_STRING,pvalue,1) < 0) printf("\n\t failed ");
- if (db_get_field(paddr,DBR_STRING,buffer,1,NULL) < 0) printf("\n\tfailed");
- else ca_dump_dbr(DBR_STRING,1,buffer);
- if(addr.dbr_field_type<=DBF_STRING || addr.dbr_field_type==DBF_ENUM)
- return(0);
- if(sscanf(pvalue,"%hd",&shortvalue)==1) {
- if (db_put_field(paddr,DBR_SHORT,&shortvalue,1) < 0)
- printf("\n\t SHORT failed ");
- if (db_get_field(paddr,DBR_SHORT,buffer,1,NULL) < 0)
- printf("\n\t SHORT GET failed");
- else ca_dump_dbr(DBR_SHORT,1,buffer);
- }
- if(sscanf(pvalue,"%ld",&longvalue)==1) {
- if (db_put_field(paddr,DBR_LONG,&longvalue,1) < 0)
- printf("\n\t LONG failed ");
- if (db_get_field(paddr,DBR_LONG,buffer,1,NULL) < 0)
- printf("\n\t LONG GET failed");
- else ca_dump_dbr(DBR_LONG,1,buffer);
- }
- if(epicsScanFloat(pvalue, &floatvalue)==1) {
- if (db_put_field(paddr,DBR_FLOAT,&floatvalue,1) < 0)
- printf("\n\t FLOAT failed ");
- if (db_get_field(paddr,DBR_FLOAT,buffer,1,NULL) < 0)
- printf("\n\t FLOAT GET failed");
- else ca_dump_dbr(DBR_FLOAT,1,buffer);
- }
- if(epicsScanFloat(pvalue, &floatvalue)==1) {
- doublevalue=floatvalue;
- if (db_put_field(paddr,DBR_DOUBLE,&doublevalue,1) < 0)
- printf("\n\t DOUBLE failed ");
- if (db_get_field(paddr,DBR_DOUBLE,buffer,1,NULL) < 0)
- printf("\n\t DOUBLE GET failed");
- else ca_dump_dbr(DBR_DOUBLE,1,buffer);
- }
- if(sscanf(pvalue,"%hd",&shortvalue)==1) {
- charvalue=(unsigned char)shortvalue;
- if (db_put_field(paddr,DBR_CHAR,&charvalue,1) < 0)
- printf("\n\t CHAR failed ");
- if (db_get_field(paddr,DBR_CHAR,buffer,1,NULL) < 0)
- printf("\n\t CHAR GET failed");
- else ca_dump_dbr(DBR_CHAR,1,buffer);
- }
- if(sscanf(pvalue,"%hd",&shortvalue)==1) {
- if (db_put_field(paddr,DBR_ENUM,&shortvalue,1) < 0)
- printf("\n\t ENUM failed ");
- if (db_get_field(paddr,DBR_ENUM,buffer,1,NULL) < 0)
- printf("\n\t ENUM GET failed");
- else ca_dump_dbr(DBR_ENUM,1,buffer);
- }
- printf("\n");
- return(0);
-}
-
-#if 0
-/*
- * PRINT_RETURNED
- *
- * print out the values in a database access interface structure
- */
-static void print_returned(type,count,pbuffer)
- short type;
- char *pbuffer;
- short count;
-{
- short i;
-
- printf("%s\t",dbr_text[type]);
- switch(type){
- case (DBR_STRING):
- for(i=0; i<count && *pbuffer!=0; i++) {
- if(count!=1 && (i%5 == 0)) printf("\n");
- printf("%s ",pbuffer);
- pbuffer += MAX_STRING_SIZE;
- }
- break;
- case (DBR_SHORT):
- case (DBR_ENUM):
- {
- short *pvalue = (short *)pbuffer;
- for (i = 0; i < count; i++,pvalue++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*(short *)pvalue);
- }
- break;
- }
- case (DBR_FLOAT):
- {
- float *pvalue = (float *)pbuffer;
- for (i = 0; i < count; i++,pvalue++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",*(float *)pvalue);
- }
- break;
- }
- case (DBR_CHAR):
- {
- int value;
-
- for (i = 0; i < count; i++,pbuffer++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- value = *(unsigned char *)pbuffer;
- printf("%d ",value);
- }
- break;
- }
- case (DBR_LONG):
- {
- long *pvalue = (long *)pbuffer;
- for (i = 0; i < count; i++,pvalue++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%ld ", (unsigned long)*pvalue);
- }
- break;
- }
- case (DBR_DOUBLE):
- {
- double *pvalue = (double *)pbuffer;
- for (i = 0; i < count; i++,pvalue++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",(float)(*pvalue));
- }
- break;
- }
- case (DBR_STS_STRING):
- case (DBR_GR_STRING):
- case (DBR_CTRL_STRING):
- {
- struct dbr_sts_string *pvalue
- = (struct dbr_sts_string *) pbuffer;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf("\tValue: %s",pvalue->value);
- break;
- }
- case (DBR_STS_ENUM):
- case (DBR_STS_SHORT):
- {
- struct dbr_sts_short *pvalue
- = (struct dbr_sts_short *)pbuffer;
- short *pshort = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pshort++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*pshort);
- }
- break;
- }
- case (DBR_STS_FLOAT):
- {
- struct dbr_sts_float *pvalue
- = (struct dbr_sts_float *)pbuffer;
- float *pfloat = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pfloat++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",*pfloat);
- }
- break;
- }
- case (DBR_STS_CHAR):
- {
- struct dbr_sts_char *pvalue
- = (struct dbr_sts_char *)pbuffer;
- unsigned char *pchar = &pvalue->value;
- short value;
-
- printf("%2d %2d",pvalue->status,pvalue->severity);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pchar++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- value=*pchar;
- printf("%d ",value);
- }
- break;
- }
- case (DBR_STS_LONG):
- {
- struct dbr_sts_long *pvalue
- = (struct dbr_sts_long *)pbuffer;
- dbr_long_t *plong = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,plong++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*plong);
- }
- break;
- }
- case (DBR_STS_DOUBLE):
- {
- struct dbr_sts_double *pvalue
- = (struct dbr_sts_double *)pbuffer;
- double *pdouble = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pdouble++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",(float)(*pdouble));
- }
- break;
- }
- case (DBR_TIME_STRING):
- {
- struct dbr_time_string *pvalue
- = (struct dbr_time_string *) pbuffer;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf("\tTimeStamp: %u %u",
- pvalue->stamp.secPastEpoch, pvalue->stamp.nsec);
- printf("\tValue: ");
- printf("%s",pvalue->value);
- break;
- }
- case (DBR_TIME_SHORT):
- case (DBR_TIME_ENUM):
- {
- struct dbr_time_short *pvalue
- = (struct dbr_time_short *)pbuffer;
- short *pshort = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf("\tTimeStamp: %u %u",
- pvalue->stamp.secPastEpoch, pvalue->stamp.nsec);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pshort++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*pshort);
- }
- break;
- }
- case (DBR_TIME_FLOAT):
- {
- struct dbr_time_float *pvalue
- = (struct dbr_time_float *)pbuffer;
- float *pfloat = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf("\tTimeStamp: %u %u",
- pvalue->stamp.secPastEpoch, pvalue->stamp.nsec);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pfloat++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",*pfloat);
- }
- break;
- }
- case (DBR_TIME_CHAR):
- {
- struct dbr_time_char *pvalue
- = (struct dbr_time_char *)pbuffer;
- unsigned char *pchar = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf("\tTimeStamp: %u %u",
- pvalue->stamp.secPastEpoch, pvalue->stamp.nsec);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pchar++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",(short)(*pchar));
- }
- break;
- }
- case (DBR_TIME_LONG):
- {
- struct dbr_time_long *pvalue
- = (struct dbr_time_long *)pbuffer;
- dbr_long_t *plong = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf("\tTimeStamp: %u %u",
- pvalue->stamp.secPastEpoch, pvalue->stamp.nsec);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,plong++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*plong);
- }
- break;
- }
- case (DBR_TIME_DOUBLE):
- {
- struct dbr_time_double *pvalue
- = (struct dbr_time_double *)pbuffer;
- double *pdouble = &pvalue->value;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf("\tTimeStamp: %u %u",
- pvalue->stamp.secPastEpoch, pvalue->stamp.nsec);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pdouble++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",(float)(*pdouble));
- }
- break;
- }
- case (DBR_GR_SHORT):
- {
- struct dbr_gr_short *pvalue
- = (struct dbr_gr_short *)pbuffer;
- short *pshort = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf("\n\t%8d %8d %8d %8d %8d %8d",
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pshort++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*pshort);
- }
- break;
- }
- case (DBR_GR_FLOAT):
- {
- struct dbr_gr_float *pvalue
- = (struct dbr_gr_float *)pbuffer;
- float *pfloat = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf(" %3d\n\t%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f",
- pvalue->precision,
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pfloat++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",*pfloat);
- }
- break;
- }
- case (DBR_GR_ENUM):
- case (DBR_CTRL_ENUM):
- {
- struct dbr_gr_enum *pvalue
- = (struct dbr_gr_enum *)pbuffer;
- printf("%2d %2d",pvalue->status,
- pvalue->severity);
- printf("\tValue: %d",pvalue->value);
- if(pvalue->no_str>0) {
- printf("\n\t%3d",pvalue->no_str);
- for (i = 0; i < pvalue->no_str; i++)
- printf("\n\t%.26s",pvalue->strs[i]);
- }
- break;
- }
- case (DBR_GR_CHAR):
- {
- struct dbr_gr_char *pvalue
- = (struct dbr_gr_char *)pbuffer;
- unsigned char *pchar = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf("\n\t%8d %8d %8d %8d %8d %8d",
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pchar++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",(short)(*pchar));
- }
- break;
- }
- case (DBR_GR_LONG):
- {
- struct dbr_gr_long *pvalue
- = (struct dbr_gr_long *)pbuffer;
- dbr_long_t *plong = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf("\n\t%8d %8d %8d %8d %8d %8d",
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,plong++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*plong);
- }
- break;
- }
- case (DBR_GR_DOUBLE):
- {
- struct dbr_gr_double *pvalue
- = (struct dbr_gr_double *)pbuffer;
- double *pdouble = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf(" %3d\n\t%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f",
- pvalue->precision,
- (float)(pvalue->upper_disp_limit),
- (float)(pvalue->lower_disp_limit),
- (float)(pvalue->upper_alarm_limit),
- (float)(pvalue->upper_warning_limit),
- (float)(pvalue->lower_warning_limit),
- (float)(pvalue->lower_alarm_limit));
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pdouble++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",(float)(*pdouble));
- }
- break;
- }
- case (DBR_CTRL_SHORT):
- {
- struct dbr_ctrl_short *pvalue
- = (struct dbr_ctrl_short *)pbuffer;
- short *pshort = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf("\n\t%8d %8d %8d %8d %8d %8d",
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- printf(" %8d %8d",
- pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pshort++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*pshort);
- }
- break;
- }
- case (DBR_CTRL_FLOAT):
- {
- struct dbr_ctrl_float *pvalue
- = (struct dbr_ctrl_float *)pbuffer;
- float *pfloat = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf(" %3d\n\t%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f",
- pvalue->precision,
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- printf(" %8.3f %8.3f",
- pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pfloat++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",*pfloat);
- }
- break;
- }
- case (DBR_CTRL_CHAR):
- {
- struct dbr_ctrl_char *pvalue
- = (struct dbr_ctrl_char *)pbuffer;
- unsigned char *pchar = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf("\n\t%8d %8d %8d %8d %8d %8d",
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- printf(" %8d %8d",
- pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pchar++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%4d ",(short)(*pchar));
- }
- break;
- }
- case (DBR_CTRL_LONG):
- {
- struct dbr_ctrl_long *pvalue
- = (struct dbr_ctrl_long *)pbuffer;
- dbr_long_t *plong = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf("\n\t%8d %8d %8d %8d %8d %8d",
- pvalue->upper_disp_limit,pvalue->lower_disp_limit,
- pvalue->upper_alarm_limit,pvalue->upper_warning_limit,
- pvalue->lower_warning_limit,pvalue->lower_alarm_limit);
- printf(" %8d %8d",
- pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit);
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,plong++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",*plong);
- }
- break;
- }
- case (DBR_CTRL_DOUBLE):
- {
- struct dbr_ctrl_double *pvalue
- = (struct dbr_ctrl_double *)pbuffer;
- double *pdouble = &pvalue->value;
- printf("%2d %2d %.8s",pvalue->status,pvalue->severity,
- pvalue->units);
- printf(" %3d\n\t%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f",
- pvalue->precision,
- (float)(pvalue->upper_disp_limit),
- (float)(pvalue->lower_disp_limit),
- (float)(pvalue->upper_alarm_limit),
- (float)(pvalue->upper_warning_limit),
- (float)(pvalue->lower_warning_limit),
- (float)(pvalue->lower_alarm_limit));
- printf(" %8.3f %8.3f",
- (float)(pvalue->upper_ctrl_limit),
- (float)(pvalue->lower_ctrl_limit));
- if(count==1) printf("\tValue: ");
- for (i = 0; i < count; i++,pdouble++){
- if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.6f ",(float)(*pdouble));
- }
- break;
- }
- case (DBR_STSACK_STRING):
- {
- struct dbr_stsack_string *pvalue
- = (struct dbr_stsack_string *)pbuffer;
- printf("%2d %2d",pvalue->status,pvalue->severity);
- printf(" %2d %2d",pvalue->ackt,pvalue->acks);
- printf(" %s",pvalue->value);
- break;
- }
- case (DBR_CLASS_NAME):
- {
- printf(" %s",(char *)pbuffer);
- break;
- }
+int epicsShareAPI pft(char *pname, char *pvalue)
+{
+ struct dbChannel *chan;
+ struct dbCommon *precord;
+ long elements;
+ short type;
+ char buffer[500];
+ short shortvalue;
+ long longvalue;
+ float floatvalue;
+ unsigned char charvalue;
+ double doublevalue;
+
+ chan = dbChannel_create(pname);
+ if (!chan) {
+ printf("Channel couldn't be created\n");
+ return 1;
+ }
+
+ precord = dbChannelRecord(chan);
+ elements = dbChannelElements(chan);
+ type = dbChannelExportType(chan);
+
+ printf(" Record Name: %s\n", precord->name);
+ printf("Record Address: 0x%p\n", precord);
+ printf(" Export Type: %d\n", type);
+ printf(" Field Address: 0x%p\n", dbChannelField(chan));
+ printf(" Field Size: %d\n", dbChannelFieldSize(chan));
+ printf(" No Elements: %ld\n", elements);
+
+ if (dbChannel_put(chan, DBR_STRING,pvalue, 1) < 0)
+ printf("\n\t failed ");
+ if (dbChannel_get(chan, DBR_STRING,buffer, 1, NULL) < 0)
+ printf("\n\tfailed");
+ else
+ ca_dump_dbr(DBR_STRING,1, buffer);
+
+ if (type <= DBF_STRING || type == DBF_ENUM)
+ return 0;
+
+ if (sscanf(pvalue, "%hd", &shortvalue) == 1) {
+ if (dbChannel_put(chan, DBR_SHORT,&shortvalue, 1) < 0)
+ printf("\n\t SHORT failed ");
+ if (dbChannel_get(chan, DBR_SHORT,buffer, 1, NULL) < 0)
+ printf("\n\t SHORT GET failed");
+ else
+ ca_dump_dbr(DBR_SHORT,1, buffer);
+ }
+ if (sscanf(pvalue, "%ld", &longvalue) == 1) {
+ if (dbChannel_put(chan, DBR_LONG,&longvalue, 1) < 0)
+ printf("\n\t LONG failed ");
+ if (dbChannel_get(chan, DBR_LONG,buffer, 1, NULL) < 0)
+ printf("\n\t LONG GET failed");
+ else
+ ca_dump_dbr(DBR_LONG,1, buffer);
+ }
+ if (epicsScanFloat(pvalue, &floatvalue) == 1) {
+ if (dbChannel_put(chan, DBR_FLOAT,&floatvalue, 1) < 0)
+ printf("\n\t FLOAT failed ");
+ if (dbChannel_get(chan, DBR_FLOAT,buffer, 1, NULL) < 0)
+ printf("\n\t FLOAT GET failed");
+ else
+ ca_dump_dbr(DBR_FLOAT,1, buffer);
+ }
+ if (epicsScanFloat(pvalue, &floatvalue) == 1) {
+ doublevalue = floatvalue;
+ if (dbChannel_put(chan, DBR_DOUBLE,&doublevalue, 1) < 0)
+ printf("\n\t DOUBLE failed ");
+ if (dbChannel_get(chan, DBR_DOUBLE,buffer, 1, NULL) < 0)
+ printf("\n\t DOUBLE GET failed");
+ else
+ ca_dump_dbr(DBR_DOUBLE,1, buffer);
+ }
+ if (sscanf(pvalue, "%hd", &shortvalue) == 1) {
+ charvalue = (unsigned char) shortvalue;
+ if (dbChannel_put(chan, DBR_CHAR,&charvalue, 1) < 0)
+ printf("\n\t CHAR failed ");
+ if (dbChannel_get(chan, DBR_CHAR,buffer, 1, NULL) < 0)
+ printf("\n\t CHAR GET failed");
+ else
+ ca_dump_dbr(DBR_CHAR,1, buffer);
+ }
+ if (sscanf(pvalue, "%hd", &shortvalue) == 1) {
+ if (dbChannel_put(chan, DBR_ENUM,&shortvalue, 1) < 0)
+ printf("\n\t ENUM failed ");
+ if (dbChannel_get(chan, DBR_ENUM,buffer, 1, NULL) < 0)
+ printf("\n\t ENUM GET failed");
+ else
+ ca_dump_dbr(DBR_ENUM,1, buffer);
}
printf("\n");
+ return (0);
}
-#endif
-
+
+
typedef struct tpnInfo {
epicsEventId callbackDone;
- putNotify *ppn;
-}tpnInfo;
+ putNotify *ppn;
+ struct dbChannel *chan;
+} tpnInfo;
static void tpnCallback(putNotify *ppn)
{
- struct dbAddr *pdbaddr = (struct dbAddr *)ppn->paddr;
- tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt;
+ tpnInfo *ptpnInfo = (tpnInfo *) ppn->usrPvt;
putNotifyStatus status = ppn->status;
- char *pname = pdbaddr->precord->name;
+ const char *pname = dbChannelRecord(ppn->chan)->name;
- if(status==0)
- printf("tpnCallback: success record=%s\n",pname);
+ if (status == 0)
+ printf("tpnCallback: success record=%s\n", pname);
else
- printf("%s tpnCallback status = %d\n",pname,status);
+ printf("%s tpnCallback status = %d\n", pname, status);
epicsEventSignal(ptpnInfo->callbackDone);
}
static void tpnThread(void *pvt)
{
- tpnInfo *ptpnInfo = (tpnInfo *)pvt;
- putNotify *ppn = (putNotify *)ptpnInfo->ppn;
+ tpnInfo *ptpnInfo = (tpnInfo *) pvt;
+ putNotify *ppn = (putNotify *) ptpnInfo->ppn;
dbPutNotify(ppn);
epicsEventWait(ptpnInfo->callbackDone);
dbNotifyCancel(ppn);
epicsEventDestroy(ptpnInfo->callbackDone);
- free((void *)ppn->paddr);
+ free(ppn->pbuffer);
+ dbChannelDelete(ppn->chan);
free(ppn);
free(ptpnInfo);
}
-
-int epicsShareAPI tpn(char *pname,char *pvalue)
+int epicsShareAPI tpn(char *pname, char *pvalue)
{
- long status;
- tpnInfo *ptpnInfo;
- struct dbAddr *pdbaddr=NULL;
- putNotify *ppn=NULL;
- char *psavevalue;
- int len;
-
- if (pname==0 || pvalue==0
- || ((*pname < ' ') || (*pname > 'z'))
- || ((*pvalue < ' ') || (*pvalue > 'z'))){
- printf("\nusage \"pv name\",\"value\"\n");
- return(1);
- }
- len = strlen(pvalue);
- /*allocate space for value immediately following DBADDR*/
- pdbaddr = calloc(1,sizeof(struct dbAddr) + len+1);
- if(!pdbaddr) {
- printf("calloc failed\n");
- return(-1);
- }
- psavevalue = (char *)(pdbaddr + 1);
- strcpy(psavevalue,pvalue);
- status = db_name_to_addr(pname,pdbaddr);
- if(status) {
- printf("db_name_to_addr failed\n");
- free((void *)pdbaddr);
- return(-1);
- }
- ppn = calloc(1,sizeof(putNotify));
- if(!pdbaddr) {
- printf("calloc failed\n");
- return(-1);
- }
- ppn->paddr = pdbaddr;
- ppn->pbuffer = psavevalue;
+ struct dbChannel *chan;
+ tpnInfo *ptpnInfo;
+ putNotify *ppn;
+ char *pbuffer;
+
+ chan = dbChannel_create(pname);
+ if (!chan) {
+ printf("Channel couldn't be created\n");
+ return 1;
+ }
+
+ pbuffer = strdup(pvalue);
+ ppn = calloc(1, sizeof(putNotify));
+ if (!ppn) {
+ printf("calloc failed\n");
+ return -1;
+ }
+ ppn->chan = chan;
+ ppn->pbuffer = pbuffer;
ppn->nRequest = 1;
- if(dbPutNotifyMapType(ppn,DBR_STRING)) {
- printf("dbPutNotifyMapType failed\n");
- printf("calloc failed\n");
- return(-1);
+ if (dbPutNotifyMapType(ppn, DBR_STRING)) {
+ printf("dbPutNotifyMapType failed\n");
+ printf("calloc failed\n");
+ return -1;
}
ppn->userCallback = tpnCallback;
- ptpnInfo = calloc(1,sizeof(tpnInfo));
- if(!ptpnInfo) {
- printf("calloc failed\n");
- return(-1);
+ ptpnInfo = calloc(1, sizeof(tpnInfo));
+ if (!ptpnInfo) {
+ printf("calloc failed\n");
+ return -1;
}
ptpnInfo->ppn = ppn;
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
ppn->usrPvt = ptpnInfo;
- epicsThreadCreate("tpn",epicsThreadPriorityHigh,
- epicsThreadGetStackSize(epicsThreadStackMedium),
- tpnThread,ptpnInfo);
- return(0);
+ epicsThreadCreate("tpn", epicsThreadPriorityHigh,
+ epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
+ return 0;
}
=== added directory 'src/ioc/db/filters'
=== added file 'src/ioc/db/filters/arr.c'
--- src/ioc/db/filters/arr.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/arr.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,205 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <stdio.h>
+
+#include <epicsExport.h>
+#include <freeList.h>
+#include <dbAccess.h>
+#include <dbExtractArray.h>
+#include <db_field_log.h>
+#include <recSup.h>
+#include <special.h>
+#include <chfPlugin.h>
+
+typedef struct myStruct {
+ epicsInt32 start;
+ epicsInt32 incr;
+ epicsInt32 end;
+ void *arrayFreeList;
+ long no_elements;
+} myStruct;
+
+static void *myStructFreeList;
+
+static const
+chfPluginArgDef opts[] = {
+ chfInt32 (myStruct, start, "s", 0, 1),
+ chfInt32 (myStruct, incr, "i", 0, 1),
+ chfInt32 (myStruct, end, "e", 0, 1),
+ chfPluginArgEnd
+};
+
+static void * allocPvt(void)
+{
+ myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
+ my->incr = 1;
+ my->end = -1;
+ return (void *) my;
+}
+
+static void freePvt(void *pvt)
+{
+ myStruct *my = (myStruct*) pvt;
+
+ if (my->arrayFreeList) freeListCleanup(my->arrayFreeList);
+ freeListFree(myStructFreeList, pvt);
+}
+
+static int parse_ok(void *pvt)
+{
+ myStruct *my = (myStruct*) pvt;
+
+ if (my->incr <= 0) my->incr = 1;
+ return 0;
+}
+
+static void freeArray(db_field_log *pfl) {
+ if (pfl->type == dbfl_type_ref) {
+ freeListFree(pfl->u.r.pvt, pfl->u.r.field);
+ }
+}
+
+static long wrapArrayIndices(long *start, const long increment, long *end, const long no_elements) {
+ long len = 0;
+
+ if (*start < 0) *start = no_elements + *start;
+ if (*start < 0) *start = 0;
+ if (*start > no_elements) *start = no_elements;
+
+ if (*end < 0) *end = no_elements + *end;
+ if (*end < 0) *end = 0;
+ if (*end >= no_elements) *end = no_elements - 1;
+
+ if (*end - *start >= 0) len = 1 + (*end - *start) / increment;
+ return len;
+}
+
+static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
+ myStruct *my = (myStruct*) pvt;
+ struct dbCommon *prec;
+ struct rset *prset;
+ long start = my->start;
+ long end = my->end;
+ long nTarget = 0;
+ long offset = 0;
+ long status;
+ long nSource = chan->addr.no_elements;
+
+ /* Only array data */
+ if (pfl->type == dbfl_type_val) {
+ return pfl;
+
+ /* Extract from record */
+ } else if (pfl->type == dbfl_type_rec) {
+ if (chan->addr.special == SPC_DBADDR &&
+ nSource > 1 &&
+ (prset = dbGetRset(&chan->addr)) &&
+ prset->get_array_info) {
+ status = prset->get_array_info(&chan->addr, &nSource, &offset);
+ nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
+ prec = dbChannelRecord(chan);
+ 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->field_size = chan->addr.field_size;
+ pfl->no_elements = nTarget;
+ if (nTarget) {
+ pfl->u.r.dtor = freeArray;
+ pfl->u.r.pvt = my->arrayFreeList;
+ void *pdst = freeListCalloc(my->arrayFreeList);
+ offset = (offset + start) % chan->addr.no_elements;
+ dbExtractArrayFromRec(&chan->addr, pdst, nTarget, nSource, offset, my->incr);
+ pfl->u.r.field = pdst;
+ }
+ }
+
+ /* Extract from buffer */
+ } else if (pfl->type == dbfl_type_ref) {
+ nSource = pfl->no_elements;
+ nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
+ pfl->no_elements = nTarget;
+ void *psrc = pfl->u.r.field;
+ void *pdst = NULL;
+ if (nTarget) { /* Copy the data out */
+ pdst = freeListCalloc(my->arrayFreeList);
+ 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) {
+ pfl->u.r.dtor = freeArray;
+ pfl->u.r.pvt = my->arrayFreeList;
+ pfl->u.r.field = pdst;
+ }
+ }
+ return pfl;
+}
+
+static void channelRegisterPost(dbChannel *chan, void *pvt,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ myStruct *my = (myStruct*) pvt;
+ long start = my->start;
+ long end = my->end;
+ long max = 0;
+
+ if (probe->no_elements <= 1) return; /* array data only */
+
+ max = wrapArrayIndices(&start, my->incr, &end, probe->no_elements); /* wrap indices into array */
+ if (max) {
+ if (!my->arrayFreeList)
+ freeListInitPvt(&my->arrayFreeList, max * probe->field_size, 2);
+ if (!my->arrayFreeList) return;
+ }
+ probe->no_elements = my->no_elements = max;
+ *cb_out = filter;
+ *arg_out = pvt;
+}
+
+static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent)
+{
+ myStruct *my = (myStruct*) pvt;
+ printf("%*s plugin arr, start=%d, incr=%d, end=%d\n", indent, "",
+ my->start, my->incr, my->end);
+}
+
+static chfPluginIf pif = {
+ allocPvt,
+ freePvt,
+
+ NULL, /* parse_error, */
+ parse_ok,
+
+ NULL, /* channel_open, */
+ NULL, /* channelRegisterPre, */
+ channelRegisterPost,
+ channel_report,
+ NULL /* channel_close */
+};
+
+static void arrInitialize(void)
+{
+ static int firstTime = 1;
+
+ if (!firstTime) return;
+ firstTime = 0;
+
+ if (!myStructFreeList)
+ freeListInitPvt(&myStructFreeList, sizeof(myStruct), 64);
+
+ chfPluginRegister("arr", &pif, opts);
+}
+
+epicsExportRegistrar(arrInitialize);
=== added file 'src/ioc/db/filters/dbnd.c'
--- src/ioc/db/filters/dbnd.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/dbnd.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,142 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <stdio.h>
+
+#include <epicsExport.h>
+#include <epicsMath.h>
+#include <freeList.h>
+#include <dbConvertFast.h>
+#include <chfPlugin.h>
+#include <db_field_log.h>
+
+typedef struct myStruct {
+ int mode;
+ double cval;
+ double hyst;
+ double last;
+} myStruct;
+
+static void *myStructFreeList;
+
+static const
+chfPluginEnumType modeEnum[] = { {"abs", 0}, {"rel", 1}, {NULL,0} };
+
+static const
+chfPluginArgDef opts[] = {
+ chfDouble (myStruct, cval, "d", 0, 1),
+ chfEnum (myStruct, mode, "m", 0, 1, modeEnum),
+ chfPluginArgEnd
+};
+
+static void * allocPvt(void)
+{
+ return freeListCalloc(myStructFreeList);
+}
+
+static void freePvt(void *pvt)
+{
+ freeListFree(myStructFreeList, pvt);
+}
+
+static int parse_ok(void *pvt)
+{
+ myStruct *my = (myStruct*) pvt;
+ my->hyst = my->cval;
+ my->last = epicsNAN;
+ return 0;
+}
+
+static void shiftval (myStruct *my, double val) {
+ my->last = val;
+ if (my->mode == 1)
+ my->hyst = val * my->cval/100.;
+}
+
+static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
+ myStruct *my = (myStruct*) pvt;
+ long status;
+ double val, delta;
+ short drop = 0;
+
+ /*
+ * Only scalar values supported - strings, arrays, and conversion errors
+ * are just passed on
+ */
+ if (pfl->type == dbfl_type_val) {
+ DBADDR localAddr = chan->addr; /* Structure copy */
+ localAddr.field_type = pfl->field_type;
+ localAddr.field_size = pfl->field_size;
+ localAddr.no_elements = pfl->no_elements;
+ localAddr.pfield = (char *) &pfl->u.v.field;
+ status = dbFastGetConvertRoutine[pfl->field_type][DBR_DOUBLE]
+ (localAddr.pfield, (void*) &val, &localAddr);
+ if (!status) {
+ if (isnan(my->last)) {
+ shiftval(my, val);
+ } else {
+ delta = fabs(my->last - val);
+ if (delta <= my->hyst) {
+ drop = 1;
+ } else {
+ shiftval(my, val);
+ }
+ }
+ }
+ }
+ if (drop) return NULL;
+ else return pfl;
+}
+
+static void channelRegisterPre(dbChannel *chan, void *pvt,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ *cb_out = filter;
+ *arg_out = pvt;
+}
+
+static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent)
+{
+ myStruct *my = (myStruct*) pvt;
+ printf("%*s plugin dbnd, mode=%s, delta=%g%s\n", indent, "",
+ chfPluginEnumString(modeEnum, my->mode, "n/a"), my->cval,
+ my->mode == 1 ? "%" : "");
+}
+
+static chfPluginIf pif = {
+ allocPvt,
+ freePvt,
+
+ NULL, /* parse_error, */
+ parse_ok,
+
+ NULL, /* channel_open, */
+ channelRegisterPre,
+ NULL, /* channelRegisterPost, */
+ channel_report,
+ NULL /* channel_close */
+};
+
+static void dbndInitialize(void)
+{
+ static int firstTime = 1;
+
+ if (!firstTime) return;
+ firstTime = 0;
+
+ if (!myStructFreeList)
+ freeListInitPvt(&myStructFreeList, sizeof(myStruct), 64);
+
+ chfPluginRegister("dbnd", &pif, opts);
+}
+
+epicsExportRegistrar(dbndInitialize);
=== added file 'src/ioc/db/filters/filters.dbd'
--- src/ioc/db/filters/filters.dbd 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/filters.dbd 2012-05-30 18:10:27 +0000
@@ -0,0 +1,4 @@
+registrar(tsInitialize)
+registrar(dbndInitialize)
+registrar(arrInitialize)
+registrar(syncInitialize)
=== added file 'src/ioc/db/filters/sync.c'
--- src/ioc/db/filters/sync.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/sync.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,170 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <stdio.h>
+
+#include "epicsExport.h"
+#include "freeList.h"
+#include "db_field_log.h"
+#include "chfPlugin.h"
+#include "dbState.h"
+
+#define STATE_NAME_LENGTH 20
+
+static const
+chfPluginEnumType modeEnum[] = { {"before", 0}, {"first", 1},
+ {"last", 2}, {"after", 3},
+ {"while", 4}, {"unless", 5},
+ {NULL,0} };
+typedef enum syncMode {
+ syncModeBefore=0,
+ syncModeFirst=1,
+ syncModeLast=2,
+ syncModeAfter=3,
+ syncModeWhile=4,
+ syncModeUnless=5
+} syncMode;
+
+typedef struct myStruct {
+ syncMode mode;
+ char state[STATE_NAME_LENGTH];
+ dbStateId id;
+ db_field_log *lastfl;
+ int laststate:1;
+} myStruct;
+
+static void *myStructFreeList;
+
+static const
+chfPluginArgDef opts[] = {
+ chfEnum (myStruct, mode, "m", 1, 1, modeEnum),
+ chfString (myStruct, state, "s", 1, 0),
+ chfPluginArgEnd
+};
+
+static void * allocPvt(void)
+{
+ myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
+ return (void *) my;
+}
+
+static void freePvt(void *pvt)
+{
+ freeListFree(myStructFreeList, pvt);
+}
+
+static int parse_ok(void *pvt)
+{
+ myStruct *my = (myStruct*) pvt;
+
+ if (!(my->id = dbStateFind(my->state)))
+ return -1;
+
+ return 0;
+}
+
+static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
+ if (pfl->ctx == dbfl_context_read)
+ return pfl;
+
+ db_field_log *passfl = NULL;
+ myStruct *my = (myStruct*) pvt;
+ int actstate = dbStateGet(my->id);
+
+ switch (my->mode) {
+ case syncModeBefore:
+ if (actstate && !my->laststate) {
+ passfl = my->lastfl;
+ my->lastfl = NULL;
+ }
+ break;
+ case syncModeFirst:
+ if (actstate && !my->laststate) {
+ passfl = pfl;
+ pfl = NULL;
+ }
+ break;
+ case syncModeLast:
+ if (!actstate && my->laststate) {
+ passfl = my->lastfl;
+ my->lastfl = NULL;
+ }
+ break;
+ case syncModeAfter:
+ if (!actstate && my->laststate) {
+ passfl = pfl;
+ pfl = NULL;
+ }
+ break;
+ case syncModeWhile:
+ if (actstate) {
+ passfl = pfl;
+ }
+ goto no_shift;
+ case syncModeUnless:
+ if (!actstate) {
+ passfl = pfl;
+ }
+ goto no_shift;
+ }
+
+ if (my->lastfl)
+ db_delete_field_log(my->lastfl);
+ my->lastfl = pfl;
+ my->laststate = actstate;
+
+ no_shift:
+ return passfl;
+}
+
+static void channelRegisterPre(dbChannel *chan, void *pvt,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ *cb_out = filter;
+ *arg_out = pvt;
+}
+
+static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent)
+{
+ myStruct *my = (myStruct*) pvt;
+ printf("%*s plugin sync, mode=%s, state=%s\n", indent, "",
+ chfPluginEnumString(modeEnum, my->mode, "n/a"), my->state);
+}
+
+static chfPluginIf pif = {
+ allocPvt,
+ freePvt,
+
+ NULL, /* parse_error, */
+ parse_ok,
+
+ NULL, /* channel_open, */
+ channelRegisterPre,
+ NULL, /* channelRegisterPost, */
+ channel_report,
+ NULL /* channel_close */
+};
+
+static void syncInitialize(void)
+{
+ static int firstTime = 1;
+
+ if (!firstTime) return;
+ firstTime = 0;
+
+ if (!myStructFreeList)
+ freeListInitPvt(&myStructFreeList, sizeof(myStruct), 64);
+
+ chfPluginRegister("sync", &pif, opts);
+}
+
+epicsExportRegistrar(syncInitialize);
=== added directory 'src/ioc/db/filters/test'
=== added file 'src/ioc/db/filters/test/Makefile'
--- src/ioc/db/filters/test/Makefile 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/Makefile 2012-05-30 18:10:27 +0000
@@ -0,0 +1,47 @@
+#*************************************************************************
+# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
+# National Laboratory.
+# Copyright (c) 2002 The Regents of the University of California, as
+# Operator of Los Alamos National Laboratory.
+# EPICS BASE is distributed subject to a Software License Agreement found
+# in the file LICENSE that is included with this distribution.
+#*************************************************************************
+TOP=../../../../..
+
+include $(TOP)/configure/CONFIG
+
+PROD_LIBS += dbCore ca Com
+
+TESTPROD_HOST += tsTest
+tsTest_SRCS += tsTest.c xRecord_registerRecordDeviceDriver.cpp
+OBJS_IOC_vxWorks += tsTest
+TESTS += tsTest
+
+TESTPROD_HOST += dbndTest
+dbndTest_SRCS += dbndTest.c xRecord_registerRecordDeviceDriver.cpp
+OBJS_IOC_vxWorks += dbndTest
+TESTS += dbndTest
+
+TARGETS += $(COMMON_DIR)/arrTest.dbd
+arrTest_DBD += arrRecord.dbd
+TESTPROD_HOST += arrTest
+arrTest_SRCS += arrTest.cpp arrRecord.c arrRecord_registerRecordDeviceDriver.cpp
+OBJS_IOC_vxWorks += arrTest
+TESTS += arrTest
+
+TESTPROD_HOST += syncTest
+syncTest_SRCS += syncTest.c xRecord_registerRecordDeviceDriver.cpp
+OBJS_IOC_vxWorks += syncTest
+TESTS += syncTest
+
+TESTSCRIPTS_HOST += $(TESTS:%=%.t)
+
+include $(TOP)/configure/RULES
+
+$(COMMON_DIR)/xRecord.dbd: ../../../test/xRecord.dbd
+ $(INSTALL) -d $< $(@D)
+
+tsTest$(OBJ): $(COMMON_DIR)/xRecord.h
+dbndTest$(OBJ): $(COMMON_DIR)/xRecord.h
+syncTest$(OBJ): $(COMMON_DIR)/xRecord.h
+arrTest$(OBJ): $(COMMON_DIR)/arrRecord.h
=== added file 'src/ioc/db/filters/test/arrRecord.c'
--- src/ioc/db/filters/test/arrRecord.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/arrRecord.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,135 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2002 The Regents of the University of California, as
+* Operator of Los Alamos National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/* arrRecord.c - minimal array record for test purposes: no processing */
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ *
+ * vaguely implemented like parts of recWaveform.c by Bob Dalesio
+ *
+ */
+
+#include <stdio.h>
+
+#include "dbDefs.h"
+#include "epicsPrint.h"
+#include "dbAccess.h"
+#include "dbEvent.h"
+#include "dbFldTypes.h"
+#include "recSup.h"
+#include "recGbl.h"
+#include "cantProceed.h"
+#define GEN_SIZE_OFFSET
+#include "arrRecord.h"
+#undef GEN_SIZE_OFFSET
+#include "epicsExport.h"
+
+/* Create RSET - Record Support Entry Table*/
+#define report NULL
+#define initialize NULL
+static long init_record(arrRecord *, int);
+static long process(arrRecord *);
+#define special NULL
+#define get_value NULL
+static long cvt_dbaddr(DBADDR *);
+static long get_array_info(DBADDR *, long *, long *);
+static long put_array_info(DBADDR *, long);
+#define get_units NULL
+#define get_precision NULL
+#define get_enum_str NULL
+#define get_enum_strs NULL
+#define put_enum_str NULL
+#define get_graphic_double NULL
+#define get_control_double NULL
+#define get_alarm_double NULL
+
+rset arrRSET = {
+ RSETNUMBER,
+ report,
+ initialize,
+ init_record,
+ process,
+ special,
+ get_value,
+ cvt_dbaddr,
+ get_array_info,
+ put_array_info,
+ get_units,
+ get_precision,
+ get_enum_str,
+ get_enum_strs,
+ put_enum_str,
+ get_graphic_double,
+ get_control_double,
+ get_alarm_double
+};
+epicsExportAddress(rset, arrRSET);
+
+static long init_record(arrRecord *prec, int pass)
+{
+ if (pass == 0) {
+ if (prec->nelm <= 0)
+ prec->nelm = 1;
+ if (prec->ftvl > DBF_ENUM)
+ prec->ftvl = DBF_UCHAR;
+ prec->bptr = callocMustSucceed(prec->nelm, dbValueSize(prec->ftvl),
+ "arr calloc failed");
+
+ if (prec->nelm == 1) {
+ prec->nord = 1;
+ } else {
+ prec->nord = 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static long process(arrRecord *prec)
+{
+ return 0;
+}
+
+static long cvt_dbaddr(DBADDR *paddr)
+{
+ arrRecord *prec = (arrRecord *) paddr->precord;
+
+ paddr->pfield = prec->bptr;
+ paddr->no_elements = prec->nelm;
+ paddr->field_type = prec->ftvl;
+ paddr->field_size = dbValueSize(prec->ftvl);
+ paddr->dbr_field_type = prec->ftvl;
+
+ return 0;
+}
+
+static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
+{
+ arrRecord *prec = (arrRecord *) paddr->precord;
+
+ *no_elements = prec->nord;
+ *offset = prec->off;
+
+ return 0;
+}
+
+static long put_array_info(DBADDR *paddr, long nNew)
+{
+ arrRecord *prec = (arrRecord *) paddr->precord;
+
+ prec->nord = nNew;
+ if (prec->nord > prec->nelm)
+ prec->nord = prec->nelm;
+
+ return 0;
+}
=== added file 'src/ioc/db/filters/test/arrRecord.dbd'
--- src/ioc/db/filters/test/arrRecord.dbd 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/arrRecord.dbd 2012-05-30 18:10:27 +0000
@@ -0,0 +1,33 @@
+include "menuGlobal.dbd"
+include "menuConvert.dbd"
+recordtype(arr) {
+ include "dbCommon.dbd"
+ field(VAL, DBF_NOACCESS) {
+ prompt("Value")
+ special(SPC_DBADDR)
+ pp(TRUE)
+ extra("void *val")
+ }
+ field(NELM, DBF_ULONG) {
+ prompt("Number of Elements")
+ special(SPC_NOMOD)
+ initial("1")
+ }
+ field(FTVL, DBF_MENU) {
+ prompt("Field Type of Value")
+ special(SPC_NOMOD)
+ menu(menuFtype)
+ }
+ field(NORD, DBF_ULONG) {
+ prompt("Number elements read")
+ special(SPC_NOMOD)
+ }
+ field(OFF, DBF_ULONG) {
+ prompt("Offset into array")
+ }
+ field(BPTR, DBF_NOACCESS) {
+ prompt("Buffer Pointer")
+ special(SPC_NOMOD)
+ extra("void *bptr")
+ }
+}
=== added file 'src/ioc/db/filters/test/arrTest.cpp'
--- src/ioc/db/filters/test/arrTest.cpp 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/arrTest.cpp 2012-05-30 18:10:27 +0000
@@ -0,0 +1,337 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2003 The Regents of the University of California, as
+* Operator of Los Alamos National Laboratory.
+* EPICS BASE is distributed subject to the Software License Agreement
+* found in the file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+/* using stuff from softIoc.cpp by Andrew Johnson */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "registryFunction.h"
+#include "epicsThread.h"
+#include "epicsExit.h"
+#include "epicsStdio.h"
+#include "envDefs.h"
+#include "dbStaticLib.h"
+#include "subRecord.h"
+#include "dbAddr.h"
+#include "dbAccess.h"
+#include "asDbLib.h"
+#include "iocInit.h"
+#include "iocsh.h"
+#include "dbChannel.h"
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+#include "arrRecord.h"
+
+extern "C" int arrRecord_registerRecordDeviceDriver(struct dbBase *pdbbase);
+extern "C" void (*pvar_func_arrInitialize)(void);
+
+#define CA_SERVER_PORT "65535"
+
+#define PATTERN 0x55
+
+const char *server_port = CA_SERVER_PORT;
+
+static void exitSubroutine(subRecord *precord) {
+ epicsExit((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static int fl_equals_array(short type, const db_field_log *pfl1, void *p2) {
+ for (int i = 0; i < pfl1->no_elements; i++) {
+ switch (type) {
+ case DBR_DOUBLE:
+ if (((epicsFloat64*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {
+ testDiag("at index=%d: field log has %g, should be %d",
+ i, ((epicsFloat64*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]);
+ return 0;
+ }
+ break;
+ case DBR_LONG:
+ if (((epicsInt32*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {
+ testDiag("at index=%d: field log has %d, should be %d",
+ i, ((epicsInt32*)pfl1->u.r.field)[i], ((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]) {
+ 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]);
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void createAndOpen(const char *chan, const char *json, const char *type, dbChannel**pch, short no) {
+ ELLNODE *node;
+ chFilter *filter;
+ char name[80];
+
+ strncpy(name, chan, sizeof(name)-1);
+ strncat(name, json, sizeof(name)-strlen(name)-1);
+
+ testOk(!!(*pch = dbChannelCreate(name)), "dbChannel with plugin arr %s created", type);
+ testOk((ellCount(&(*pch)->filters) == no), "channel has %d filter(s) in filter list", no);
+
+ testOk(!(dbChannelOpen(*pch)), "dbChannel with plugin arr opened");
+
+ node = ellFirst(&(*pch)->pre_chain);
+ filter = CONTAINER(node, chFilter, pre_node);
+ testOk((ellCount(&(*pch)->pre_chain) == 0), "arr has no filter in pre chain");
+
+ node = ellFirst(&(*pch)->post_chain);
+ filter = CONTAINER(node, chFilter, post_node);
+ testOk((ellCount(&(*pch)->post_chain) == no),
+ "arr has %d filter(s) in post chain", no);
+}
+
+static void testHead (const char *title, const char *typ = "") {
+ const char *line = "------------------------------------------------------------------------------";
+ testDiag(line);
+ testDiag(title, typ);
+ testDiag(line);
+}
+
+#define TEST1(Size, Offset, Incr, Text) \
+ testDiag("Offset: %d (%s)", Offset, Text); \
+ off = Offset; \
+ status = dbPutField(&offaddr, DBR_LONG, &off, 1); \
+ pfl = db_create_read_log(pch); \
+ testOk(pfl->type == dbfl_type_rec, "original field log has type rec"); \
+ 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"); \
+ testOk(fl_equals_array(dbr_type, pfl2, ar##Size##_##Offset##_##Incr), "array data correct"); \
+ db_delete_field_log(pfl);
+
+static void check(short dbr_type) {
+ dbChannel *pch;
+ db_field_log *pfl, *pfl2;
+ int status;
+ dbAddr valaddr;
+ dbAddr offaddr;
+ const char *offname = NULL, *valname = NULL, *typname = NULL;
+ long ar[10] = {10,11,12,13,14,15,16,17,18,19};
+ long *ar10_0_1 = ar;
+ long ar10_4_1[10] = {14,15,16,17,18,19,10,11,12,13};
+ long ar5_0_1[10] = {12,13,14,15,16};
+ long ar5_3_1[10] = {15,16,17,18,19};
+ long ar5_5_1[10] = {17,18,19,10,11};
+ long ar5_9_1[10] = {11,12,13,14,15};
+ long ar5_0_2[10] = {12,14,16};
+ long ar5_3_2[10] = {15,17,19};
+ long ar5_5_2[10] = {17,19,11};
+ long ar5_9_2[10] = {11,13,15};
+ long ar5_0_3[10] = {12,15};
+ long ar5_3_3[10] = {15,18};
+ long ar5_5_3[10] = {17,10};
+ long ar5_9_3[10] = {11,14};
+ long off = 0;
+
+ switch (dbr_type) {
+ case DBR_LONG:
+ offname = "x.OFF";
+ valname = "x.VAL";
+ typname = "long";
+ break;
+ case DBR_DOUBLE:
+ offname = "y.OFF";
+ valname = "y.VAL";
+ typname = "double";
+ break;
+ case DBR_STRING:
+ offname = "z.OFF";
+ valname = "z.VAL";
+ typname = "string";
+ break;
+ default:
+ testDiag("Invalid data type %d", dbr_type);
+ }
+
+ status = dbNameToAddr(offname, &offaddr);
+
+ status = dbNameToAddr(valname, &valaddr);
+ status = dbPutField(&valaddr, DBR_LONG, ar, 10);
+
+ /* Default: should not change anything */
+
+ testHead("Ten %s elements from rec, increment 1, full size (default)", typname);
+ createAndOpen(valname, "{\"arr\":{}}", "(default)", &pch, 1);
+ testOk(pch->final_type == valaddr.field_type,
+ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
+ testOk(pch->final_no_elements == valaddr.no_elements,
+ "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
+ TEST1(10, 0, 1, "no offset");
+ TEST1(10, 4, 1, "wrapped");
+ dbChannelDelete(pch);
+
+ testHead("Ten %s elements from rec, increment 1, out-of-bound start parameter", typname);
+ createAndOpen(valname, "{\"arr\":{\"s\":-500}}", "out-of-bound start", &pch, 1);
+ testOk(pch->final_type == valaddr.field_type,
+ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
+ testOk(pch->final_no_elements == valaddr.no_elements,
+ "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
+ TEST1(10, 4, 1, "wrapped");
+ dbChannelDelete(pch);
+
+ testHead("Ten %s elements from rec, increment 1, out-of-bound end parameter", typname);
+ createAndOpen(valname, "{\"arr\":{\"e\":500}}", "out-of-bound end", &pch, 1);
+ testOk(pch->final_type == valaddr.field_type,
+ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
+ testOk(pch->final_no_elements == valaddr.no_elements,
+ "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
+ TEST1(10, 4, 1, "wrapped");
+ dbChannelDelete(pch);
+
+ testHead("Ten %s elements from rec, increment 1, zero increment parameter", typname);
+ createAndOpen(valname, "{\"arr\":{\"i\":0}}", "zero increment", &pch, 1);
+ testOk(pch->final_type == valaddr.field_type,
+ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
+ testOk(pch->final_no_elements == valaddr.no_elements,
+ "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
+ TEST1(10, 4, 1, "wrapped");
+ dbChannelDelete(pch);
+
+ testHead("Ten %s elements from rec, increment 1, invalid increment parameter", typname);
+ createAndOpen(valname, "{\"arr\":{\"i\":-30}}", "invalid increment", &pch, 1);
+ testOk(pch->final_type == valaddr.field_type,
+ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
+ testOk(pch->final_no_elements == valaddr.no_elements,
+ "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
+ TEST1(10, 4, 1, "wrapped");
+ dbChannelDelete(pch);
+
+#define TEST5(Incr, Left, Right, Type) \
+ testHead("Five %s elements from rec, increment " #Incr ", " Type " addressing", typname); \
+ createAndOpen(valname, "{\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \
+ "(" #Left ":" #Incr ":" #Right ")", &pch, 1); \
+ testOk(pch->final_type == valaddr.field_type, \
+ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \
+ testOk(pch->final_no_elements == 4 / Incr + 1, \
+ "final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \
+ TEST1(5, 0, Incr, "no offset"); \
+ TEST1(5, 3, Incr, "from upper block"); \
+ TEST1(5, 5, Incr, "wrapped"); \
+ TEST1(5, 9, Incr, "from lower block"); \
+ dbChannelDelete(pch);
+
+ /* Contiguous block of 5 */
+
+ TEST5(1, 2, 6, "regular");
+ TEST5(1, -8, 6, "left side from-end");
+ TEST5(1, 2, -4, "right side from-end");
+ TEST5(1, -8, -4, "both sides from-end");
+
+ /* 5 elements with increment 2 */
+
+ TEST5(2, 2, 6, "regular");
+ TEST5(2, -8, 6, "left side from-end");
+ TEST5(2, 2, -4, "right side from-end");
+ TEST5(2, -8, -4, "both sides from-end");
+
+ /* 5 elements with increment 3 */
+
+ TEST5(3, 2, 6, "regular");
+ TEST5(3, -8, 6, "left side from-end");
+ TEST5(3, 2, -4, "right side from-end");
+ TEST5(3, -8, -4, "both sides from-end");
+
+ /* From buffer (plugin chain) */
+
+#define TEST5B(Incr, Left, Right, Type) \
+ testHead("Five %s elements from buffer, increment " #Incr ", " Type " addressing", typname); \
+ createAndOpen(valname, "{\"arr\":{},\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \
+ "(" #Left ":" #Incr ":" #Right ")", &pch, 2); \
+ testOk(pch->final_type == valaddr.field_type, \
+ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \
+ testOk(pch->final_no_elements == 4 / Incr + 1, \
+ "final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \
+ TEST1(5, 0, Incr, "no offset"); \
+ dbChannelDelete(pch);
+
+ /* Contiguous block of 5 */
+
+ TEST5B(1, 2, 6, "regular");
+ TEST5B(1, -8, 6, "left side from-end");
+ TEST5B(1, 2, -4, "right side from-end");
+ TEST5B(1, -8, -4, "both sides from-end");
+
+ /* 5 elements with increment 2 */
+
+ TEST5B(2, 2, 6, "regular");
+ TEST5B(2, -8, 6, "left side from-end");
+ TEST5B(2, 2, -4, "right side from-end");
+ TEST5B(2, -8, -4, "both sides from-end");
+
+ /* 5 elements with increment 3 */
+
+ TEST5B(3, 2, 6, "regular");
+ TEST5B(3, -8, 6, "left side from-end");
+ TEST5B(3, 2, -4, "right side from-end");
+ TEST5B(3, -8, -4, "both sides from-end");
+}
+
+MAIN(arrTest)
+{
+ const chFilterPlugin *plug;
+ char arr[] = "arr";
+ int status;
+
+ testPlan(1404);
+
+ /* Prepare the IOC */
+
+ epicsEnvSet("EPICS_CA_SERVER_PORT", server_port);
+
+ testOk1(!(status=dbReadDatabase(&pdbbase, "arrRecord.dbd", ".:..:../../../../../../dbd", NULL)));
+ if (status) epicsExit(EXIT_FAILURE);
+
+ (*pvar_func_arrInitialize)();
+ arrRecord_registerRecordDeviceDriver(pdbbase);
+ registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
+
+ testOk1(!(status=dbReadDatabase(&pdbbase, "arrTest.db", ".:..", NULL)));
+ if (status) epicsExit(EXIT_FAILURE);
+
+ /* Start the IOC */
+
+ iocInit();
+ db_init_events();
+ epicsThreadSleep(0.2);
+
+ testOk(!!(plug = dbFindFilter(arr, strlen(arr))), "plugin arr registered correctly");
+
+ check(DBR_LONG);
+ check(DBR_DOUBLE);
+ check(DBR_STRING);
+
+ dbFreeBase(pdbbase);
+
+ return testDone();
+
+ epicsExit(EXIT_SUCCESS);
+ /*Note that the following statement will never be executed*/
+ return 0;
+}
=== added file 'src/ioc/db/filters/test/arrTest.db'
--- src/ioc/db/filters/test/arrTest.db 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/arrTest.db 2012-05-30 18:10:27 +0000
@@ -0,0 +1,15 @@
+record(arr, "x") {
+ field(DESC, "test array record")
+ field(NELM, "10")
+ field(FTVL, "LONG")
+}
+record(arr, "y") {
+ field(DESC, "test array record")
+ field(NELM, "10")
+ field(FTVL, "DOUBLE")
+}
+record(arr, "z") {
+ field(DESC, "test array record")
+ field(NELM, "10")
+ field(FTVL, "STRING")
+}
=== added file 'src/ioc/db/filters/test/dbndTest.c'
--- src/ioc/db/filters/test/dbndTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/dbndTest.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,228 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+
+#include "dbStaticLib.h"
+#include "dbAccessDefs.h"
+#include "db_field_log.h"
+#include "dbCommon.h"
+#include "chfPlugin.h"
+#include "epicsUnitTest.h"
+#include "epicsTime.h"
+#include "testMain.h"
+
+#define PATTERN 0x55
+
+epicsShareExtern void (*pvar_func_dbndInitialize)(void);
+
+static db_field_log fl;
+
+static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
+ return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
+}
+
+static void fl_setup(dbChannel *chan, db_field_log *pfl) {
+ struct dbCommon *prec = dbChannelRecord(chan);
+
+ pfl->ctx = dbfl_context_read;
+ pfl->type = dbfl_type_val;
+ pfl->stat = prec->stat;
+ pfl->sevr = prec->sevr;
+ pfl->time = prec->time;
+ pfl->field_type = dbChannelFieldType(chan);
+ pfl->no_elements = dbChannelElements(chan);
+ /*
+ * use memcpy to avoid a bus error on
+ * union copy of char in the db at an odd
+ * address
+ */
+ memcpy(&pfl->u.v.field,
+ dbChannelField(chan),
+ dbChannelFieldSize(chan));
+}
+
+static void changeValue(db_field_log *pfl2, long val) {
+ pfl2->u.v.field.dbf_long = val;
+ testDiag("new value: %ld", val);
+}
+
+static void mustPassOnce(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
+ changeValue(pfl2, val);
+ testDiag("mode=%s delta=%g filter must pass once", m, d);
+ db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
+ testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data");
+ pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(NULL == pfl, "call 2 drops field_log");
+}
+
+static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
+ changeValue(pfl2, val);
+ testDiag("mode=%s delta=%g filter must drop", m, d);
+ db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(NULL == pfl, "call 1 drops field_log");
+}
+
+static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
+ changeValue(pfl2, val);
+ testDiag("mode=%s delta=%g filter must pass twice", m, d);
+ db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
+ testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data");
+ pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(pfl2 == pfl, "call 2 does not drop or replace field_log");
+ testOk(fl_equal(pfl, pfl2), "call 2 does not change field_log data");
+}
+
+static void testHead (char* title) {
+ testDiag("--------------------------------------------------------");
+ testDiag(title);
+ testDiag("--------------------------------------------------------");
+}
+
+void xRecord_registerRecordDeviceDriver(struct dbBase *);
+
+MAIN(dbndTest)
+{
+ dbChannel *pch;
+ chFilter *filter;
+ const chFilterPlugin *plug;
+ char dbnd[] = "dbnd";
+ ELLNODE *node;
+ chPostEventFunc *cb_out = NULL;
+ void *arg_out = NULL;
+ db_field_log *pfl2;
+ db_field_log fl1;
+
+ testPlan(62);
+
+ db_init_events();
+
+ testOk1(!dbReadDatabase(&pdbbase, "xRecord.dbd", ".:../../../test", NULL));
+ testOk(!!pdbbase, "pdbbase was set");
+
+ (*pvar_func_dbndInitialize)(); /* manually initialize plugin */
+
+ xRecord_registerRecordDeviceDriver(pdbbase);
+ testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.db", ".:../../../test", NULL));
+
+ testOk(!!(plug = dbFindFilter(dbnd, strlen(dbnd))), "plugin dbnd registered correctly");
+
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{}}")), "dbChannel with plugin dbnd (delta=0) created");
+ testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
+
+ memset(&fl, PATTERN, sizeof(fl));
+ fl1 = fl;
+ node = ellFirst(&pch->filters);
+ filter = CONTAINER(node, chFilter, list_node);
+ plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
+ testOk(!!(cb_out) && !!(arg_out), "register_pre registers one filter with argument");
+ testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
+
+ testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
+ node = ellFirst(&pch->pre_chain);
+ filter = CONTAINER(node, chFilter, pre_node);
+ testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg != NULL),
+ "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);
+
+ fl1.type = dbfl_type_ref;
+ mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0);
+
+ /* Delta = 0: pass any change */
+
+ testHead("Delta = 0: pass any change");
+ pfl2 = db_create_read_log(pch);
+ testDiag("new field_log from record");
+ fl_setup(pch, pfl2);
+
+ mustPassOnce(pch, pfl2, "abs", 0., 0);
+ mustPassOnce(pch, pfl2, "abs", 0., 1);
+
+ db_delete_field_log(pfl2);
+ dbChannelDelete(pch);
+
+ /* Delta = -1: pass any update */
+
+ testHead("Delta = -1: pass any update");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"d\":-1.0}}")), "dbChannel with plugin dbnd (delta=-1) created");
+ testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
+
+ pfl2 = db_create_read_log(pch);
+ testDiag("new field_log from record");
+ fl_setup(pch, pfl2);
+
+ mustPassTwice(pch, pfl2, "abs", -1., 0);
+ mustPassTwice(pch, pfl2, "abs", -1., 1);
+
+ db_delete_field_log(pfl2);
+ dbChannelDelete(pch);
+
+ /* Delta = absolute */
+
+ testHead("Delta = absolute");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"d\":3}}")), "dbChannel with plugin dbnd (delta=3) created");
+ testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
+
+ pfl2 = db_create_read_log(pch);
+ testDiag("new field_log from record");
+ fl_setup(pch, pfl2);
+
+ mustPassOnce(pch, pfl2, "abs", 3., 1);
+ mustDrop(pch, pfl2, "abs", 3., 3);
+ mustDrop(pch, pfl2, "abs", 3., 4);
+ mustPassOnce(pch, pfl2, "abs", 3., 5);
+
+ db_delete_field_log(pfl2);
+ dbChannelDelete(pch);
+
+ /* Delta = relative */
+
+ testHead("Delta = relative");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"m\":\"rel\",\"d\":50}}")),
+ "dbChannel with plugin dbnd (mode=rel, delta=50) created");
+ testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
+
+ pfl2 = db_create_read_log(pch);
+ testDiag("new field_log from record");
+ fl_setup(pch, pfl2);
+
+ mustPassOnce(pch, pfl2, "rel", 50., 1);
+ mustPassOnce(pch, pfl2, "rel", 50., 2);
+ mustDrop(pch, pfl2, "rel", 50., 3);
+ mustPassOnce(pch, pfl2, "rel", 50., 4);
+ mustDrop(pch, pfl2, "rel", 50., 5);
+ mustDrop(pch, pfl2, "rel", 50., 6);
+ mustPassOnce(pch, pfl2, "rel", 50., 7);
+
+ db_delete_field_log(pfl2);
+ dbChannelDelete(pch);
+ dbFreeBase(pdbbase);
+
+ return testDone();
+}
+
+#define GEN_SIZE_OFFSET
+#include "xRecord.h"
+
+#include <recSup.h>
+#include <epicsExport.h>
+
+static rset xRSET;
+epicsExportAddress(rset,xRSET);
=== added file 'src/ioc/db/filters/test/syncTest.c'
--- src/ioc/db/filters/test/syncTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/syncTest.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,371 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+
+#include "dbStaticLib.h"
+#include "dbAccessDefs.h"
+#include "db_field_log.h"
+#include "dbCommon.h"
+#include "dbChannel.h"
+#include "chfPlugin.h"
+#include "epicsUnitTest.h"
+#include "epicsTime.h"
+#include "dbState.h"
+#include "testMain.h"
+
+#define PATTERN 0x55
+
+epicsShareExtern void (*pvar_func_syncInitialize)(void);
+
+static db_field_log fl;
+static dbStateId red;
+
+static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
+ return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
+}
+
+static void fl_setup(dbChannel *chan, db_field_log *pfl, long val) {
+ struct dbCommon *prec = dbChannelRecord(chan);
+
+ pfl->ctx = dbfl_context_event;
+ pfl->type = dbfl_type_val;
+ pfl->stat = prec->stat;
+ pfl->sevr = prec->sevr;
+ pfl->time = prec->time;
+ pfl->field_type = DBF_LONG;
+ pfl->no_elements = 1;
+ /*
+ * use memcpy to avoid a bus error on
+ * union copy of char in the db at an odd
+ * address
+ */
+ memcpy(&pfl->u.v.field,
+ dbChannelField(chan),
+ dbChannelFieldSize(chan));
+ pfl->u.v.field.dbf_long = val;
+}
+
+static void changeValue(db_field_log *pfl2, long val) {
+ pfl2->u.v.field.dbf_long = val;
+}
+
+static void testHead (char* title) {
+ testDiag("--------------------------------------------------------");
+ testDiag(title);
+ testDiag("--------------------------------------------------------");
+}
+
+static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m) {
+ db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(NULL == pfl, "filter drops field_log (%s)", m);
+}
+
+static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m) {
+ testDiag("%s: filter must pass twice", m);
+ db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
+ pfl = dbChannelRunPreChain(pch, pfl2);
+ testOk(pfl2 == pfl, "call 2 does not drop or replace field_log");
+}
+
+static void mustPassOld(dbChannel *pch, db_field_log *old, db_field_log *cur, char* m) {
+ db_field_log *pfl = dbChannelRunPreChain(pch, cur);
+ testOk(old == pfl, "filter passes previous field log (%s)", m);
+}
+
+static void mustPass(dbChannel *pch, db_field_log *cur, char* m) {
+ db_field_log *pfl = dbChannelRunPreChain(pch, cur);
+ testOk(cur == pfl, "filter passes field_log (%s)", m);
+}
+
+static void checkCtxRead(dbChannel *pch, dbStateId id) {
+ fl.ctx = dbfl_context_read;
+ dbStateClear(id);
+ mustPassTwice(pch, &fl, "ctx='read', state=FALSE");
+ dbStateSet(id);
+ mustPassTwice(pch, &fl, "ctx='read', state=TRUE");
+ dbStateClear(id);
+ mustPassTwice(pch, &fl, "ctx='read', state=FALSE");
+ fl.ctx = dbfl_context_event;
+}
+
+static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) {
+ ELLNODE *node;
+ chFilter *filter;
+ chPostEventFunc *cb_out = NULL;
+ void *arg_out = NULL;
+
+ testDiag("Test filter structure and open channel");
+
+ testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
+
+ db_field_log fl1 = fl;
+ node = ellFirst(&pch->filters);
+ filter = CONTAINER(node, chFilter, list_node);
+ plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
+ testOk(!!(cb_out) && !!(arg_out), "register_pre registers one filter with argument");
+ testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
+
+ testOk(!(dbChannelOpen(pch)), "dbChannel with plugin sync opened");
+ node = ellFirst(&pch->pre_chain);
+ filter = CONTAINER(node, chFilter, pre_node);
+ testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg != NULL),
+ "sync has one filter with argument in pre chain");
+ testOk((ellCount(&pch->post_chain) == 0), "sync has no filter in post chain");
+
+ checkCtxRead(pch, red);
+}
+
+void xRecord_registerRecordDeviceDriver(struct dbBase *);
+
+//MAIN(syncTest)
+int main()
+{
+ dbChannel *pch;
+ chFilter *filter;
+ const chFilterPlugin *plug;
+ char myname[] = "sync";
+ ELLNODE *node;
+ chPostEventFunc *cb_out = NULL;
+ void *arg_out = NULL;
+ db_field_log *pfl[10];
+ db_field_log fl1;
+ int i;
+
+ testPlan(0);
+
+ db_init_events();
+
+ testOk1(!dbReadDatabase(&pdbbase, "xRecord.dbd", ".:../../../test", NULL));
+ testOk(!!pdbbase, "pdbbase was set");
+
+ (*pvar_func_syncInitialize)(); /* manually initialize plugin */
+
+ xRecord_registerRecordDeviceDriver(pdbbase);
+ testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.db", ".:../../../test", NULL));
+
+ testOk(!!(plug = dbFindFilter(myname, strlen(myname))), "plugin %s registered correctly", myname);
+ testOk(!!(red = dbStateCreate("red")), "state 'red' created successfully");
+
+ /* nonexisting state */
+ testOk(!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\",\"s\":\"blue\"}}")),
+ "dbChannel with sync (m='while' s='blue') (nonex state) failed");
+ /* missing state */
+ testOk(!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\"}}")),
+ "dbChannel with sync (m='while') (no state) failed");
+ /* missing mode */
+ testOk(!(pch = dbChannelCreate("x.VAL{\"sync\":{\"s\":\"red\"}}")),
+ "dbChannel with sync (s='red') (no mode) failed");
+
+ /* mode WHILE */
+
+ testHead("Mode WHILE (m='while', s='red')");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\",\"s\":\"red\"}}")),
+ "dbChannel with plugin sync (m='while' s='red') created");
+
+ checkAndOpenChannel(pch, plug);
+
+ for (i = 0; i < 10; i++) {
+ pfl[i] = db_create_read_log(pch);
+ fl_setup(pch, pfl[i], 120 + i);
+ }
+
+ testDiag("Test event stream");
+
+ dbStateClear(red);
+ mustDrop(pch, pfl[0], "state=FALSE, log0");
+ mustDrop(pch, pfl[1], "state=FALSE, log1");
+ mustDrop(pch, pfl[2], "state=FALSE, log2");
+ dbStateSet(red);
+ mustPass(pch, pfl[3], "state=TRUE, log3");
+ mustPass(pch, pfl[4], "state=TRUE, log4");
+ mustPass(pch, pfl[5], "state=TRUE, log5");
+ dbStateClear(red);
+ mustDrop(pch, pfl[6], "state=FALSE, log6");
+ mustDrop(pch, pfl[7], "state=FALSE, log7");
+ mustDrop(pch, pfl[8], "state=FALSE, log8");
+
+ for (i = 0; i < 10; i++)
+ db_delete_field_log(pfl[i]);
+
+ /* mode UNLESS */
+
+ testHead("Mode UNLESS (m='unless', s='red')");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"unless\",\"s\":\"red\"}}")),
+ "dbChannel with plugin sync (m='unless' s='red') created");
+
+ checkAndOpenChannel(pch, plug);
+
+ for (i = 0; i < 10; i++) {
+ pfl[i] = db_create_read_log(pch);
+ fl_setup(pch, pfl[i], 120 + i);
+ }
+
+ testDiag("Test event stream");
+
+ dbStateClear(red);
+ mustPass(pch, pfl[0], "state=FALSE, log0");
+ mustPass(pch, pfl[1], "state=FALSE, log1");
+ mustPass(pch, pfl[2], "state=FALSE, log2");
+ dbStateSet(red);
+ mustDrop(pch, pfl[3], "state=TRUE, log3");
+ mustDrop(pch, pfl[4], "state=TRUE, log4");
+ mustDrop(pch, pfl[5], "state=TRUE, log5");
+ dbStateClear(red);
+ mustPass(pch, pfl[6], "state=FALSE, log6");
+ mustPass(pch, pfl[7], "state=FALSE, log7");
+ mustPass(pch, pfl[8], "state=FALSE, log8");
+
+ for (i = 0; i < 10; i++)
+ db_delete_field_log(pfl[i]);
+
+ /* mode BEFORE */
+
+ testHead("Mode BEFORE (m='before', s='red')");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"before\",\"s\":\"red\"}}")),
+ "dbChannel with plugin sync (m='before' s='red') created");
+
+ checkAndOpenChannel(pch, plug);
+
+ for (i = 0; i < 10; i++) {
+ pfl[i] = db_create_read_log(pch);
+ fl_setup(pch, pfl[i], 120 + i);
+ }
+
+ testDiag("Test event stream");
+
+ dbStateClear(red);
+ mustDrop(pch, pfl[0], "state=FALSE, log0");
+ mustDrop(pch, pfl[1], "state=FALSE, log1");
+ mustDrop(pch, pfl[2], "state=FALSE, log2");
+ dbStateSet(red);
+ mustPassOld(pch, pfl[2], pfl[3], "state=TRUE, log3, pass=log2");
+ mustDrop(pch, pfl[4], "state=TRUE, log4");
+ mustDrop(pch, pfl[5], "state=TRUE, log5");
+ mustDrop(pch, pfl[6], "state=TRUE, log6");
+ dbStateClear(red);
+ mustDrop(pch, pfl[7], "state=FALSE, log7");
+ mustDrop(pch, pfl[8], "state=FALSE, log8");
+ mustDrop(pch, pfl[9], "state=FALSE, log9");
+
+ for (i = 0; i < 10; i++)
+ db_delete_field_log(pfl[i]);
+
+ /* mode FIRST */
+
+ testHead("Mode FIRST (m='first', s='red')");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"first\",\"s\":\"red\"}}")),
+ "dbChannel with plugin sync (m='first' s='red') created");
+
+ checkAndOpenChannel(pch, plug);
+
+ for (i = 0; i < 10; i++) {
+ pfl[i] = db_create_read_log(pch);
+ fl_setup(pch, pfl[i], 120 + i);
+ }
+
+ testDiag("Test event stream");
+
+ dbStateClear(red);
+ mustDrop(pch, pfl[0], "state=FALSE, log0");
+ mustDrop(pch, pfl[1], "state=FALSE, log1");
+ mustDrop(pch, pfl[2], "state=FALSE, log2");
+ dbStateSet(red);
+ mustPass(pch, pfl[3], "state=TRUE, log3");
+ mustDrop(pch, pfl[4], "state=TRUE, log4");
+ mustDrop(pch, pfl[5], "state=TRUE, log5");
+ dbStateClear(red);
+ mustDrop(pch, pfl[6], "state=FALSE, log6");
+ mustDrop(pch, pfl[7], "state=FALSE, log7");
+ mustDrop(pch, pfl[8], "state=FALSE, log8");
+
+ for (i = 0; i < 10; i++)
+ db_delete_field_log(pfl[i]);
+
+ /* mode LAST */
+
+ testHead("Mode LAST (m='last', s='red')");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"last\",\"s\":\"red\"}}")),
+ "dbChannel with plugin sync (m='last' s='red') created");
+
+ checkAndOpenChannel(pch, plug);
+
+ for (i = 0; i < 10; i++) {
+ pfl[i] = db_create_read_log(pch);
+ fl_setup(pch, pfl[i], 120 + i);
+ }
+
+ testDiag("Test event stream");
+
+ dbStateClear(red);
+ mustDrop(pch, pfl[0], "state=FALSE, log0");
+ mustDrop(pch, pfl[1], "state=FALSE, log1");
+ mustDrop(pch, pfl[2], "state=FALSE, log2");
+ dbStateSet(red);
+ mustDrop(pch, pfl[3], "state=TRUE, log3");
+ mustDrop(pch, pfl[4], "state=TRUE, log4");
+ mustDrop(pch, pfl[5], "state=TRUE, log5");
+ dbStateClear(red);
+ mustPassOld(pch, pfl[5], pfl[6], "state=TRUE, log6, pass=log5");
+ mustDrop(pch, pfl[7], "state=FALSE, log7");
+ mustDrop(pch, pfl[8], "state=FALSE, log8");
+ mustDrop(pch, pfl[9], "state=FALSE, log9");
+
+ for (i = 0; i < 10; i++)
+ db_delete_field_log(pfl[i]);
+
+ /* mode AFTER */
+
+ testHead("Mode AFTER (m='after', s='red')");
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"after\",\"s\":\"red\"}}")),
+ "dbChannel with plugin sync (m='after' s='red') created");
+
+ checkAndOpenChannel(pch, plug);
+
+ for (i = 0; i < 10; i++) {
+ pfl[i] = db_create_read_log(pch);
+ fl_setup(pch, pfl[i], 120 + i);
+ }
+
+ testDiag("Test event stream");
+
+ dbStateClear(red);
+ mustDrop(pch, pfl[0], "state=FALSE, log0");
+ mustDrop(pch, pfl[1], "state=FALSE, log1");
+ mustDrop(pch, pfl[2], "state=FALSE, log2");
+ dbStateSet(red);
+ mustDrop(pch, pfl[3], "state=TRUE, log3");
+ mustDrop(pch, pfl[4], "state=TRUE, log4");
+ mustDrop(pch, pfl[5], "state=TRUE, log5");
+ dbStateClear(red);
+ mustPass(pch, pfl[6], "state=FALSE, log6");
+ mustDrop(pch, pfl[7], "state=FALSE, log7");
+ mustDrop(pch, pfl[8], "state=FALSE, log8");
+
+ for (i = 0; i < 10; i++)
+ db_delete_field_log(pfl[i]);
+
+ dbChannelDelete(pch);
+ dbFreeBase(pdbbase);
+
+ return testDone();
+}
+
+#define GEN_SIZE_OFFSET
+#include "xRecord.h"
+
+#include <recSup.h>
+#include <epicsExport.h>
+
+static rset xRSET;
+epicsExportAddress(rset,xRSET);
=== added file 'src/ioc/db/filters/test/tsTest.c'
--- src/ioc/db/filters/test/tsTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/test/tsTest.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,111 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+
+#include "dbStaticLib.h"
+#include "dbAccessDefs.h"
+#include "chfPlugin.h"
+#include "epicsUnitTest.h"
+#include "epicsTime.h"
+#include "testMain.h"
+
+#define PATTERN 0x55
+
+epicsShareExtern void (*pvar_func_tsInitialize)(void);
+
+static db_field_log fl;
+
+static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
+ return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
+}
+
+static int fl_equal_ex_ts(const db_field_log *pfl1, const db_field_log *pfl2) {
+ db_field_log fl1 = *pfl1;
+
+ fl1.time = pfl2->time;
+ return fl_equal(&fl1, pfl2);
+}
+
+void xRecord_registerRecordDeviceDriver(struct dbBase *);
+
+MAIN(tsTest)
+{
+ dbChannel *pch;
+ chFilter *filter;
+ const chFilterPlugin *plug;
+ char ts[] = "ts";
+ ELLNODE *node;
+ chPostEventFunc *cb_out = NULL;
+ void *arg_out = NULL;
+ db_field_log fl1;
+ db_field_log *pfl2;
+
+ testPlan(15);
+
+ db_init_events();
+
+ testOk1(!dbReadDatabase(&pdbbase, "xRecord.dbd", ".:../../../test", NULL));
+ testOk(!!pdbbase, "pdbbase was set");
+
+ (*pvar_func_tsInitialize)(); /* manually initialize plugin */
+
+ xRecord_registerRecordDeviceDriver(pdbbase);
+ testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.db", ".:../../../test", NULL));
+
+ testOk(!!(plug = dbFindFilter(ts, strlen(ts))), "plugin ts registered correctly");
+
+ testOk(!!(pch = dbChannelCreate("x.VAL{\"ts\":{}}")), "dbChannel with plugin ts created");
+ testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
+
+ memset(&fl, PATTERN, sizeof(fl));
+ fl1 = fl;
+ node = ellFirst(&pch->filters);
+ filter = CONTAINER(node, chFilter, list_node);
+ plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
+ testOk(!!(cb_out) && !(arg_out), "register_pre registers one filter w/o argument");
+ testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
+
+ testOk(!(dbChannelOpen(pch)), "dbChannel with plugin ts opened");
+ node = ellFirst(&pch->pre_chain);
+ filter = CONTAINER(node, chFilter, pre_node);
+ testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg == NULL),
+ "ts has one filter w/o argument in pre chain");
+ testOk((ellCount(&pch->post_chain) == 0), "ts has no filter in post chain");
+
+ memset(&fl, PATTERN, sizeof(fl));
+ fl1 = fl;
+ pfl2 = dbChannelRunPreChain(pch, &fl1);
+ testOk(pfl2 == &fl1, "ts filter does not drop or replace field_log");
+ testOk(fl_equal_ex_ts(&fl1, pfl2), "ts filter does not change field_log data");
+
+ testOk(!!(pfl2 = db_create_read_log(pch)), "create field log from channel");
+ epicsTimeStamp stamp = pfl2->time;
+ pfl2 = dbChannelRunPreChain(pch, &fl1);
+ epicsTimeStamp now; epicsTimeGetCurrent(&now);
+ testOk(epicsTimeDiffInSeconds(&pfl2->time, &stamp) > 0. &&
+ epicsTimeDiffInSeconds(&now, &pfl2->time) > 0., "ts filter sets time stamp to \"now\"");
+
+ dbChannelDelete(pch);
+ dbFreeBase(pdbbase);
+
+ return testDone();
+}
+
+#define GEN_SIZE_OFFSET
+#include "xRecord.h"
+
+#include <recSup.h>
+#include <epicsExport.h>
+
+static rset xRSET;
+epicsExportAddress(rset,xRSET);
=== added file 'src/ioc/db/filters/ts.c'
--- src/ioc/db/filters/ts.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/filters/ts.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,67 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <stdio.h>
+
+#include <epicsExport.h>
+#include <chfPlugin.h>
+#include <db_field_log.h>
+
+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) {
+ dbChannelMakeArrayCopy(pvt, pfl, chan);
+ }
+
+ pfl->time = now;
+ return pfl;
+}
+
+static void channelRegisterPre(dbChannel *chan, void *pvt,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ *cb_out = filter;
+}
+
+static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent)
+{
+ printf("%*s plugin ts\n", indent, "");
+}
+
+static chfPluginIf pif = {
+ NULL, /* allocPvt, */
+ NULL, /* freePvt, */
+
+ NULL, /* parse_error, */
+ NULL, /* parse_ok, */
+
+ NULL, /* channel_open, */
+ channelRegisterPre,
+ NULL, /* channelRegisterPost, */
+ channel_report,
+ NULL /* channel_close */
+};
+
+static void tsInitialize(void)
+{
+ static int firstTime = 1;
+
+ if(!firstTime) return;
+ firstTime = 0;
+
+ chfPluginRegister("ts", &pif, NULL);
+}
+
+epicsExportRegistrar(tsInitialize);
=== modified file 'src/ioc/db/recGbl.c'
--- src/ioc/db/recGbl.c 2010-10-05 19:27:37 +0000
+++ src/ioc/db/recGbl.c 2012-05-30 18:10:27 +0000
@@ -6,12 +6,10 @@
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* recGbl.c */
-/* $Revision-Id$ */
/*
* Author: Marty Kraimer
- * Date: 11-7-90
+ * Andrew Johnson <[email protected]>
*/
#include <stddef.h>
@@ -34,6 +32,7 @@
#include "caeventmask.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
+#include "dbLink.h"
#include "dbNotify.h"
#include "dbCa.h"
#include "dbEvent.h"
@@ -166,60 +165,17 @@
return;
}
-
+
int epicsShareAPI recGblInitConstantLink(
struct link *plink,short dbftype,void *pdest)
{
- if(plink->type != CONSTANT) return(FALSE);
- if(!plink->value.constantStr) return(FALSE);
- switch(dbftype) {
- case DBF_STRING:
- strcpy((char *)pdest,plink->value.constantStr);
- break;
- case DBF_CHAR : {
- epicsInt16 value;
- epicsInt8 *pvalue = (epicsInt8 *)pdest;
-
- sscanf(plink->value.constantStr,"%hi",&value);
- *pvalue = value;
- }
- break;
- case DBF_UCHAR : {
- epicsUInt16 value;
- epicsUInt8 *pvalue = (epicsUInt8 *)pdest;
-
- sscanf(plink->value.constantStr,"%hu",&value);
- *pvalue = value;
- }
- break;
- case DBF_SHORT :
- sscanf(plink->value.constantStr,"%hi",(epicsInt16 *)pdest);
- break;
- case DBF_USHORT :
- case DBF_ENUM :
- case DBF_MENU :
- case DBF_DEVICE :
- sscanf(plink->value.constantStr,"%hu",(epicsUInt16 *)pdest);
- break;
- case DBF_LONG :
- *(epicsInt32 *)pdest = strtol(plink->value.constantStr, NULL, 0);
- break;
- case DBF_ULONG :
- *(epicsUInt32 *)pdest = strtoul(plink->value.constantStr, NULL, 10);
- break;
- case DBF_FLOAT :
- epicsScanFloat(plink->value.constantStr, (epicsFloat32 *)pdest);
- break;
- case DBF_DOUBLE :
- epicsScanDouble(plink->value.constantStr, (epicsFloat64 *)pdest);
- break;
- default:
- epicsPrintf("Error in recGblInitConstantLink: Illegal DBF type\n");
- return(FALSE);
- }
- return(TRUE);
+ long status = dbLoadLink(plink, dbftype, pdest);
+
+ if (status)
+ return FALSE;
+ return TRUE;
}
-
+
unsigned short epicsShareAPI recGblResetAlarms(void *precord)
{
dbCommon *pdbc = precord;
=== modified file 'src/ioc/db/test/Makefile'
--- src/ioc/db/test/Makefile 2012-05-29 21:20:17 +0000
+++ src/ioc/db/test/Makefile 2012-05-30 18:10:27 +0000
@@ -27,7 +27,31 @@
TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
+TESTPROD_HOST += dbChannelTest
+dbChannelTest_SRCS += dbChannelTest.c xRecord_registerRecordDeviceDriver.cpp
+OBJS_IOC_vxWorks += dbChannelTest
+TESTS += dbChannelTest
+
+TESTPROD_HOST += chfPluginTest
+chfPluginTest_SRCS += chfPluginTest.c xRecord_registerRecordDeviceDriver.cpp
+OBJS_IOC_vxWorks += chfPluginTest
+TESTS += chfPluginTest
+
+TESTPROD_HOST += arrShorthandTest
+arrShorthandTest_SRCS += arrShorthandTest.c xRecord_registerRecordDeviceDriver.cpp
+OBJS_IOC_vxWorks += arrShorthandTest
+TESTS += arrShorthandTest
+
+TESTPROD_HOST += dbStateTest
+dbStateTest_SRCS += dbStateTest.c
+OBJS_IOC_vxWorks += dbStateTest
+TESTS += dbStateTest
+
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
+dbChannelTest$(OBJ): $(COMMON_DIR)/xRecord.h
+chfPluginTest$(OBJ): $(COMMON_DIR)/xRecord.h
+arrShorthandTest$(OBJ): $(COMMON_DIR)/xRecord.h
+dbStateTest$(OBJ): $(COMMON_DIR)/xRecord.h
=== added file 'src/ioc/db/test/arrShorthandTest.c'
--- src/ioc/db/test/arrShorthandTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/arrShorthandTest.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,139 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+ /*
+ * Test the shorthand array notation [ start : incr : end ]
+ * by registering a thin fake arr plugin
+ * and checking if values are forwarded correctly
+ */
+
+#include <string.h>
+
+#include "chfPlugin.h"
+#include "dbStaticLib.h"
+#include "dbAccessDefs.h"
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+typedef struct myStruct {
+ epicsInt32 start;
+ epicsInt32 incr;
+ epicsInt32 end;
+} myStruct;
+
+static const
+chfPluginArgDef opts[] = {
+ chfInt32 (myStruct, start, "s", 0, 1),
+ chfInt32 (myStruct, incr, "i", 0, 1),
+ chfInt32 (myStruct, end, "e", 0, 1),
+ chfPluginArgEnd
+};
+
+static myStruct my;
+
+static void * allocPvt(void)
+{
+ my.start = 0;
+ my.incr = 1;
+ my.end = -1;
+ return &my;
+}
+
+static chfPluginIf myPif = {
+ allocPvt,
+ NULL, /* freePvt, */
+
+ NULL, /* parse_error, */
+ NULL, /* parse_ok, */
+
+ NULL, /* channel_open, */
+ NULL, /* channelRegisterPre, */
+ NULL, /* channelRegisterPost, */
+ NULL, /* channel_report, */
+ NULL /* channel_close */
+};
+
+static int checkValues(epicsUInt32 s, epicsUInt32 i, epicsUInt32 e) {
+ if (s == my.start && i == my.incr && e == my.end)
+ return 1;
+ else
+ return 0;
+}
+
+static void testHead (char* title) {
+ testDiag("--------------------------------------------------------");
+ testDiag(title);
+ testDiag("--------------------------------------------------------");
+}
+
+void xRecord_registerRecordDeviceDriver(struct dbBase *);
+
+MAIN(chfPluginTest)
+{
+ dbChannel *pch;
+
+ testPlan(29);
+
+ db_init_events();
+
+ testHead("Set up database");
+ testOk1(!dbReadDatabase(&pdbbase, "xRecord.dbd", ".:..", NULL));
+
+ xRecord_registerRecordDeviceDriver(pdbbase);
+ testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.db", ".:..", NULL));
+ testOk(!!pdbbase, "pdbbase was set");
+
+ testHead("Register plugin");
+ testOk(!chfPluginRegister("arr", &myPif, opts), "register fake arr plugin");
+
+#define TESTBAD(Title, Expr) \
+ testDiag(Title); \
+ testOk(!(pch = dbChannelCreate("x." Expr)), "dbChannelCreate (" Expr ") fails"); \
+ if (pch) dbChannelDelete(pch);
+
+#define TESTGOOD(Title, Expr, Start, Incr, End) \
+ testDiag(Title); \
+ testOk(!!(pch = dbChannelCreate("x." Expr)), "dbChannelCreate (" Expr ")"); \
+ testOk(checkValues(Start, Incr, End), "parameters set correctly: s=%d i=%d e=%d", Start, Incr, End); \
+ if (pch) dbChannelDelete(pch);
+
+ TESTBAD("no parameters []", "[]");
+ TESTBAD("invalid char at beginning [x", "[x");
+ TESTBAD("invalid char after 1st arg [2x", "[2x");
+ TESTBAD("invalid char after 2nd arg [2:3x", "[2:3x");
+ TESTBAD("invalid char after 3rd arg [2:3:4x", "[2:3:4x");
+
+ TESTGOOD("one element [index]", "[2]", 2, 1, 2);
+ TESTGOOD("to end [s:]", "[2:]", 2, 1, -1);
+ TESTGOOD("to end [s::]", "[2::]", 2, 1, -1);
+ TESTGOOD("to end with incr [s:i:]", "[2:3:]", 2, 3, -1);
+ TESTGOOD("from beginning [:e]", "[:2]", 0, 1, 2);
+ TESTGOOD("from beginning [::e]", "[::2]", 0, 1, 2);
+ TESTGOOD("from begin with incr [:i:e]", "[:3:2]", 0, 3, 2);
+ TESTGOOD("range [s:e]", "[2:4]", 2, 1, 4);
+ TESTGOOD("range [s::e]", "[2::4]", 2, 1, 4);
+ TESTGOOD("range with incr [s:i:e]", "[2:3:4]", 2, 3, 4);
+
+ dbFreeBase(pdbbase);
+
+ return testDone();
+}
+
+
+#define GEN_SIZE_OFFSET
+#include "xRecord.h"
+
+#include <recSup.h>
+#include <epicsExport.h>
+
+static rset xRSET;
+epicsExportAddress(rset,xRSET);
=== added file 'src/ioc/db/test/chfPluginTest.c'
--- src/ioc/db/test/chfPluginTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/chfPluginTest.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,746 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+
+#include "chfPlugin.h"
+#include "dbStaticLib.h"
+#include "dbAccessDefs.h"
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+#define PATTERN 0x55555555
+#define TYPE_START 0xAAA
+#define R_LEVEL 42
+
+/* Expected / actually run callback bit definitions */
+#define e_alloc 0x00000001
+#define e_free 0x00000002
+#define e_error 0x00000004
+#define e_ok 0x00000008
+#define e_open 0x00000010
+#define e_reg_pre 0x00000020
+#define e_reg_post 0x00000040
+#define e_report 0x00000080
+#define e_close 0x00000100
+#define e_pre 0x00000200
+#define e_post 0x00000400
+#define e_dtor 0x00000800
+
+unsigned int e1, e2, c1, c2;
+unsigned int offset;
+int drop = -1;
+db_field_log *dtorpfl;
+
+#define e_any (e_alloc | e_free | e_error | e_ok | e_open \
+| e_reg_pre | e_reg_post | e_pre | e_post | e_dtor | e_report | e_close)
+
+typedef struct myStruct {
+ int sent1;
+ char flag;
+ int sent2;
+ epicsUInt32 ival;
+ int sent3;
+ double dval;
+ int sent4;
+ int enumval;
+ int sent5;
+ char str[20];
+ int sent6;
+ char c;
+ char c1[2];
+ int offpre;
+ int offpost;
+} myStruct;
+
+static const
+chfPluginEnumType colorEnum[] = { {"R", 1}, {"G", 2}, {"B", 4}, {NULL,0} };
+
+static const
+chfPluginArgDef strictOpts[] = {
+ chfInt32 (myStruct, ival, "i" , 1, 0),
+ chfBoolean(myStruct, flag, "f" , 1, 0),
+ chfDouble (myStruct, dval, "d" , 1, 0),
+ chfString (myStruct, str, "s" , 1, 0),
+ chfEnum (myStruct, enumval, "c" , 1, 0, colorEnum),
+ chfPluginArgEnd
+};
+
+static const
+chfPluginArgDef noconvOpts[] = {
+ chfInt32 (myStruct, ival, "i" , 0, 0),
+ chfBoolean(myStruct, flag, "f" , 0, 0),
+ chfDouble (myStruct, dval, "d" , 0, 0),
+ chfString (myStruct, str, "s" , 0, 0),
+ chfEnum (myStruct, enumval, "c" , 0, 0, colorEnum),
+ chfPluginArgEnd
+};
+
+static const
+chfPluginArgDef sloppyOpts[] = {
+ chfInt32 (myStruct, ival, "i" , 0, 1),
+ chfBoolean(myStruct, flag, "f" , 0, 1),
+ chfDouble (myStruct, dval, "d" , 0, 1),
+ chfString (myStruct, str, "s" , 0, 1),
+ chfEnum (myStruct, enumval, "c" , 0, 1, colorEnum),
+ chfPluginArgEnd
+};
+
+/* Options defs with not enough room provided */
+static const
+chfPluginArgDef brokenOpts1[] = {
+ chfInt32 (myStruct, c1, "i" , 0, 1),
+ chfPluginArgEnd
+};
+
+static const
+chfPluginArgDef brokenOpts2[] = {
+ chfDouble(myStruct, c1, "d" , 0, 1),
+ chfPluginArgEnd
+};
+
+static const
+chfPluginArgDef brokenOpts3[] = {
+ chfString(myStruct, c1, "s" , 0, 1),
+ chfPluginArgEnd
+};
+
+static const
+chfPluginArgDef brokenOpts4[] = {
+ chfEnum (myStruct, c1, "c" , 0, 1, colorEnum),
+ chfPluginArgEnd
+};
+
+int p_ok_return = 0;
+int c_open_return = 0;
+void *puser1, *puser2;
+
+static void clearStruct(void *p) {
+ myStruct *my = (myStruct*) p;
+
+ if (!my) return;
+ memset(my, 0, sizeof(myStruct));
+ my->sent1 = my->sent2 = my->sent3 = my->sent4 = my->sent5 = my->sent6 = PATTERN;
+ my->ival = 12;
+ my->flag = 1;
+ my->dval = 1.234e5;
+ strcpy(my->str, "hello");
+ my->enumval = 4;
+}
+
+static char inst(void* user) {
+ return user == puser1 ? '1' : user == puser2 ? '2' : 'x';
+}
+
+static void * allocPvt(void)
+{
+ myStruct *my = (myStruct*) calloc(1, sizeof(myStruct));
+
+ if (!puser1) {
+ puser1 = my;
+ testOk(e1 & e_alloc, "allocPvt (1) called");
+ c1 |= e_alloc;
+ } else if (!puser2) {
+ puser2 = my;
+ testOk(e2 & e_alloc, "allocPvt (2) called");
+ c2 |= e_alloc;
+ }
+ clearStruct (my);
+ return my;
+}
+
+static void freePvt(void *user)
+{
+ testOk(user == puser1 || user == puser2, "freePvt: user pointer valid");
+ if (user == puser1) {
+ testOk(e1 & e_free, "freePvt (1) called");
+ c1 |= e_free;
+ free(user);
+ puser1 = NULL;
+ } else if (user == puser2) {
+ testOk(e2 & e_free, "freePvt (2) called");
+ c2 |= e_free;
+ free(user);
+ puser2 = NULL;
+ }
+}
+
+static void parse_error(void *user)
+{
+ testOk(user == puser1 || user == puser2, "parse_error: user pointer valid");
+ if (user == puser1) {
+ testOk(e1 & e_error, "parse_error (1) called");
+ c1 |= e_error;
+ } else if (user == puser2) {
+ testOk(e2 & e_error, "parse_error (2) called");
+ c2 |= e_error;
+ }
+}
+
+static int parse_ok(void *user)
+{
+ testOk(user == puser1 || user == puser2, "parse_ok: user pointer valid");
+ if (user == puser1) {
+ testOk(e1 & e_ok, "parse_ok (1) called");
+ c1 |= e_ok;
+ } else if (user == puser2) {
+ testOk(e2 & e_ok, "parse_ok (2) called");
+ c2 |= e_ok;
+
+ }
+
+ return p_ok_return;
+}
+
+static long channel_open(dbChannel *chan, void *user)
+{
+ testOk(user == puser1 || user == puser2, "channel_open: user pointer valid");
+ if (user == puser1) {
+ testOk(e1 & e_open, "channel_open (1) called");
+ c1 |= e_open;
+ } else if (user == puser2) {
+ testOk(e2 & e_open, "channel_open (2) called");
+ c2 |= e_open;
+ }
+
+ return c_open_return;
+}
+
+static void dbfl_free1(db_field_log *pfl) {
+ testOk(e1 & e_dtor, "dbfl_free (1) called");
+ testOk(dtorpfl == pfl, "dbfl_free (1): db_field_log pointer correct");
+ dtorpfl = NULL;
+ c1 |= e_dtor;
+}
+
+static void dbfl_free2(db_field_log *pfl) {
+ testOk(e2 & e_dtor, "dbfl_free (2) called");
+ testOk(dtorpfl == pfl, "dbfl_free (2): db_field_log pointer correct");
+ dtorpfl = NULL;
+ c2 |= e_dtor;
+}
+
+static db_field_log * pre(void *user, dbChannel *chan, db_field_log *pLog) {
+ myStruct *my = (myStruct*)user;
+ dbfl_freeFunc *dtor = NULL;
+
+ testOk(user == puser1 || user == puser2, "pre: user pointer valid");
+ if (my == puser1) {
+ testOk(e1 & e_pre, "pre (1) called");
+ testOk(!(c2 & e_pre), "pre (2) has not been called before pre (1)");
+ c1 |= e_pre;
+ dtor = dbfl_free1;
+ } else if (my == puser2) {
+ testOk(e2 & e_pre, "pre (2) called");
+ testOk(!(e1 & e_pre) || c1 & e_pre, "pre (1) has been called before pre (2)");
+ c2 |= e_pre;
+ dtor = dbfl_free2;
+ }
+ testOk(!(c1 & e_post), "post (1) has not been called before pre (%c)", inst(user));
+ testOk(!(c2 & e_post), "post (2) has not been called before pre (%c)", inst(user));
+
+ if (!testOk(pLog->field_type == TYPE_START + my->offpre, "pre (%c) got field log of expected type", inst(user)))
+ testDiag("expected: %d, got %d", TYPE_START + my->offpre, pLog->field_type);
+ pLog->field_type++;
+
+ if (my->offpre == 0) { /* The first one registers a dtor and saves pfl */
+ pLog->u.r.dtor = dtor;
+ dtorpfl = pLog;
+ }
+
+ if (my->offpre == drop) {
+ testDiag("pre (%c) is dropping the field log", inst(user));
+ return NULL;
+ }
+ return pLog;
+}
+
+static db_field_log * post(void *user, dbChannel *chan, db_field_log *pLog) {
+ myStruct *my = (myStruct*)user;
+ dbfl_freeFunc *dtor = NULL;
+
+ testOk(user == puser1 || user == puser2, "post: user pointer valid");
+ if (my == puser1) {
+ testOk(e1 & e_post, "post (1) called");
+ testOk(!(c2 & e_post), "post (2) has not been called before post (1)");
+ c1 |= e_post;
+ dtor = dbfl_free1;
+ } else if (my == puser2) {
+ testOk(e2 & e_post, "post (2) called");
+ testOk(!(e1 & e_post) || c1 & e_post, "post (1) has been called before post (2)");
+ c2 |= e_post;
+ dtor = dbfl_free2;
+ }
+ testOk(!(e1 & e_pre) || c1 & e_pre, "pre (1) has been called before post (%c)", inst(user));
+ testOk(!(e2 & e_pre) || c2 & e_pre, "pre (2) has been called before post (%c)", inst(user));
+
+ if (!testOk(pLog->field_type == TYPE_START + my->offpost, "post (%c) got field log of expected type", inst(user)))
+ testDiag("expected: %d, got %d", TYPE_START + my->offpost, pLog->field_type);
+ pLog->field_type++;
+
+ if (my->offpost == 0) { /* The first one registers a dtor and remembers pfl */
+ pLog->u.r.dtor = dtor;
+ dtorpfl = pLog;
+ }
+
+ if (my->offpost == drop) {
+ testDiag("post (%c) is dropping the field log", inst(user));
+ return NULL;
+ }
+ return pLog;
+}
+
+static void channelRegisterPre(dbChannel *chan, void *user,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ myStruct *my = (myStruct*)user;
+
+ testOk(user == puser1 || user == puser2, "register_pre: user pointer valid");
+ if (my == puser1) {
+ testOk(e1 & e_reg_pre, "register_pre (1) called");
+ testOk(!(c2 & e_reg_pre), "register_pre (2) has not been called before register_pre (1)");
+ c1 |= e_reg_pre;
+ } else if (my == puser2) {
+ testOk(e2 & e_reg_pre, "register_pre (2) called");
+ testOk(!(e1 & e_reg_pre) || c1 & e_reg_pre, "register_pre (1) has been called before register_pre (2)");
+ c2 |= e_reg_pre;
+ }
+ testOk(!(c1 & e_reg_post), "register_post (1) has not been called before register_pre (%c)", inst(user));
+ testOk(!(c2 & e_reg_post), "register_post (2) has not been called before register_pre (%c)", inst(user));
+
+ my->offpre = offset++;
+ probe->field_type++;
+ *cb_out = pre;
+ *arg_out = user;
+}
+
+static void channelRegisterPost(dbChannel *chan, void *user,
+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ myStruct *my = (myStruct*)user;
+
+ testOk(user == puser1 || user == puser2, "register_post: user pointer valid");
+ if (my == puser1) {
+ testOk(e1 & e_reg_post, "register_post (1) called");
+ testOk(!(c2 & e_reg_post), "register_post (2) has not been called before register_post (1)");
+ c1 |= e_reg_post;
+ } else if (my == puser2) {
+ testOk(e2 & e_reg_post, "register_post (2) called");
+ testOk(!(e1 & e_reg_post) || c1 & e_reg_post, "register_post (1) has been called before register_post (2)");
+ c2 |= e_reg_post;
+ }
+ testOk(!(e1 & e_reg_pre) || c1 & e_reg_pre, "register_pre (1) has been called before register_post (%c)", inst(user));
+ testOk(!(e2 & e_reg_pre) || c2 & e_reg_pre, "register_pre (2) has been called before register_post (%c)", inst(user));
+
+ my->offpost = offset++;
+ probe->field_type++;
+ *cb_out = post;
+ *arg_out = user;
+}
+
+static void channel_report(dbChannel *chan, void *user, int level, const unsigned short indent)
+{
+ testOk(user == puser1 || user == puser2, "channel_report: user pointer valid");
+ testOk(level == R_LEVEL - 1, "channel_report: level correct");
+ if (user == puser1) {
+ testOk(e1 & e_report, "channel_report (1) called");
+ c1 |= e_report;
+ } else if (user == puser2) {
+ testOk(e2 & e_report, "channel_report (2) called");
+ c2 |= e_report;
+ }
+}
+
+static void channel_close(dbChannel *chan, void *user)
+{
+ testOk(user == puser1 || user == puser2, "channel_close: user pointer valid");
+ if (user == puser1) {
+ testOk(e1 & e_close, "channel_close (1) called");
+ c1 |= e_close;
+ } else if (user == puser2) {
+ testOk(e2 & e_close, "channel_close (2) called");
+ c2 |= e_close;
+ }
+}
+
+static chfPluginIf myPif = {
+ allocPvt,
+ freePvt,
+
+ parse_error,
+ parse_ok,
+
+ channel_open,
+ channelRegisterPre,
+ channelRegisterPost,
+ channel_report,
+ channel_close
+};
+
+static chfPluginIf prePif = {
+ allocPvt,
+ freePvt,
+
+ parse_error,
+ parse_ok,
+
+ channel_open,
+ channelRegisterPre,
+ NULL,
+ channel_report,
+ channel_close
+};
+
+static chfPluginIf postPif = {
+ allocPvt,
+ freePvt,
+
+ parse_error,
+ parse_ok,
+
+ channel_open,
+ NULL,
+ channelRegisterPost,
+ channel_report,
+ channel_close
+};
+
+static int checkValues(myStruct *my, epicsUInt32 i, int f, double d, char *s, int c) {
+ if (!my) return 0;
+ if (my->sent1 == PATTERN && my->sent2 == PATTERN && my->sent3 == PATTERN
+ && my->sent4 == PATTERN && my->sent5 == PATTERN && my->sent6 == PATTERN
+ && my->ival == i && my->flag == f && my->dval == d && my->enumval == c
+ && (strcmp(s, my->str) == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void testHead (char* title) {
+ testDiag("--------------------------------------------------------");
+ testDiag(title);
+ testDiag("--------------------------------------------------------");
+}
+
+void xRecord_registerRecordDeviceDriver(struct dbBase *);
+
+MAIN(chfPluginTest)
+{
+ dbChannel *pch;
+ db_field_log *pfl;
+
+ testPlan(1755);
+
+ db_init_events();
+
+ /* Enum to string conversion */
+ testHead("Enum to string conversion");
+ testOk(strcmp(chfPluginEnumString(colorEnum, 1, "-"), "R") == 0, "Enum to string: R");
+ testOk(strcmp(chfPluginEnumString(colorEnum, 2, "-"), "G") == 0, "Enum to string: G");
+ testOk(strcmp(chfPluginEnumString(colorEnum, 4, "-"), "B") == 0, "Enum to string: B");
+ testOk(strcmp(chfPluginEnumString(colorEnum, 3, "-"), "-") == 0, "Enum to string: invalid index");
+
+ testHead("Set up database");
+ testOk1(!dbReadDatabase(&pdbbase, "xRecord.dbd", ".:..", NULL));
+
+ xRecord_registerRecordDeviceDriver(pdbbase);
+ testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.db", ".:..", NULL));
+ testOk(!!pdbbase, "pdbbase was set");
+
+ testHead("Try to register buggy plugins");
+ testOk(!!chfPluginRegister("buggy", &myPif, brokenOpts1), "not enough storage for integer");
+ testOk(!!chfPluginRegister("buggy", &myPif, brokenOpts2), "not enough storage for double");
+ testOk(!!chfPluginRegister("buggy", &myPif, brokenOpts3), "not enough storage for string");
+ testOk(!!chfPluginRegister("buggy", &myPif, brokenOpts4), "not enough storage for enum");
+
+ testHead("Register plugins");
+ testOk(!chfPluginRegister("strict", &myPif, strictOpts), "register plugin strict");
+ testOk(!chfPluginRegister("noconv", &myPif, noconvOpts), "register plugin noconv");
+ testOk(!chfPluginRegister("sloppy", &myPif, sloppyOpts), "register plugin sloppy");
+ testOk(!chfPluginRegister("pre", &prePif, sloppyOpts), "register plugin pre");
+ testOk(!chfPluginRegister("post", &postPif, sloppyOpts), "register plugin post");
+
+ /* STRICT parsing: mandatory, no conversion */
+
+ /* All perfect */
+ testHead("STRICT parsing: all ok");
+ e1 = e_alloc | e_ok; c1 = 0;
+ testOk(!!(pch = dbChannelCreate("x.{\"strict\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")), "strict parsing: JSON correct");
+ testOk(checkValues(puser1, 1, 0, 1.2e15, "bar", 1), "guards intact, values correct");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+ e1 = e_close | e_free; c1 = 0;
+ if (pch) dbChannelDelete(pch);
+ testOk(!puser1, "user part cleaned up");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+
+ /* Any one missing must fail */
+ testHead("STRICT parsing: any missing parameter must fail");
+ e1 = e_alloc | e_error | e_free; c1 = 0;
+ testOk(!(pch = dbChannelCreate("x.{\"strict\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\"}}")), "strict parsing: c missing");
+ testOk(!puser1, "user part cleaned up");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+ e1 = e_alloc | e_error | e_free; c1 = 0;
+ testOk(!(pch = dbChannelCreate("x.{\"strict\":{\"f\":false,\"i\":1,\"d\":1.2e15,\"c\":\"R\"}}")), "strict parsing: s missing");
+ testOk(!puser1, "user part cleaned up");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+ e1 = e_alloc | e_error | e_free; c1 = 0;
+ testOk(!(pch = dbChannelCreate("x.{\"strict\":{\"i\":1,\"c\":\"R\",\"f\":false,\"s\":\"bar\"}}")), "strict parsing: d missing");
+ testOk(!puser1, "user part cleaned up");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+ e1 = e_alloc | e_error | e_free; c1 = 0;
+ testOk(!(pch = dbChannelCreate("x.{\"strict\":{\"d\":1.2e15,\"c\":\"R\",\"i\":1,\"s\":\"bar\"}}")), "strict parsing: f missing");
+ testOk(!puser1, "user part cleaned up");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+ e1 = e_alloc | e_error | e_free; c1 = 0;
+ testOk(!(pch = dbChannelCreate("x.{\"strict\":{\"c\":\"R\",\"s\":\"bar\",\"f\":false,\"d\":1.2e15}}")), "strict parsing: i missing");
+ testOk(!puser1, "user part cleaned up");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+
+ /* NOCONV parsing: optional, no conversion */
+
+ /* Any one missing must leave the default intact */
+ testHead("NOCONV parsing: any missing parameter must fall back to default value");
+ e1 = e_alloc | e_ok; c1 = 0;
+ testOk(!!(pch = dbChannelCreate("x.{\"noconv\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\"}}")), "noconv parsing: c missing");
+ testOk(checkValues(puser1, 1, 0, 1.2e15, "bar", 4), "guards intact, values correct");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+ e1 = e_close | e_free; c1 = 0;
+ if (pch) dbChannelDelete(pch);
+ testOk(!puser1, "user part cleaned up");
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+
+ e1 = e_any;
+ testOk(!!(pch = dbChannelCreate("x.{\"noconv\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"c\":\"R\"}}")), "noconv parsing: s missing");
+ testOk(checkValues(puser1, 1, 0, 1.2e15, "hello", 1), "guards intact, values correct");
+ if (pch) dbChannelDelete(pch);
+
+ testOk(!!(pch = dbChannelCreate("x.{\"noconv\":{\"i\":1,\"f\":false,\"s\":\"bar\",\"c\":\"R\"}}")), "noconv parsing: d missing");
+ testOk(checkValues(puser1, 1, 0, 1.234e5, "bar", 1), "guards intact, values correct");
+ if (pch) dbChannelDelete(pch);
+
+ testOk(!!(pch = dbChannelCreate("x.{\"noconv\":{\"i\":1,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")), "noconv parsing: f missing");
+ testOk(checkValues(puser1, 1, 1, 1.2e15, "bar", 1), "guards intact, values correct");
+ if (pch) dbChannelDelete(pch);
+
+ testOk(!!(pch = dbChannelCreate("x.{\"noconv\":{\"f\":false,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")), "noconv parsing: i missing");
+ testOk(checkValues(puser1, 12, 0, 1.2e15, "bar", 1), "guards intact, values correct");
+ if (pch) dbChannelDelete(pch);
+
+ /* Reject wrong types */
+#define WRONGTYPETEST(Var, Val, Typ) \
+ e1 = e_alloc | e_error | e_free; c1 = 0; \
+ testOk(!(pch = dbChannelCreate("x.{\"noconv\":{\""#Var"\":"#Val"}}")), "noconv parsing: wrong type "#Typ" for "#Var); \
+ testOk(!puser1, "user part cleaned up"); \
+ if (!testOk(c1 == e1, "all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+
+ testHead("NOCONV parsing: rejection of wrong parameter types");
+
+ WRONGTYPETEST(i, 123.0, double);
+ WRONGTYPETEST(i, true, boolean);
+ WRONGTYPETEST(i, "1", string);
+ WRONGTYPETEST(f, "false", string);
+ WRONGTYPETEST(f, 0.0, double);
+ WRONGTYPETEST(f, 1, integer);
+ WRONGTYPETEST(d, "1.2", string);
+ WRONGTYPETEST(d, true, boolean);
+ WRONGTYPETEST(d, 123, integer);
+ WRONGTYPETEST(s, 1.23, double);
+ WRONGTYPETEST(s, true, boolean);
+ WRONGTYPETEST(s, 123, integer);
+ WRONGTYPETEST(c, 1.23, double);
+ WRONGTYPETEST(c, true, boolean);
+ WRONGTYPETEST(c, 2, integer);
+
+ /* SLOPPY parsing: optional, with conversion */
+
+#define CONVTESTGOOD(Var, Val, Typ, Ival, Fval, Dval, Sval, Cval) \
+ e1 = e_alloc | e_ok; c1 = 0; \
+ testOk(!!(pch = dbChannelCreate("x.{\"sloppy\":{\""#Var"\":"#Val"}}")), "sloppy parsing: "#Typ" (good) for "#Var); \
+ testOk(checkValues(puser1, Ival, Fval, Dval, Sval, Cval), "guards intact, values correct"); \
+ if (!testOk(c1 == e1, "create channel: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ e1 = e_close | e_free; c1 = 0; \
+ if (pch) dbChannelDelete(pch); \
+ testOk(!puser1, "user part cleaned up"); \
+ if (!testOk(c1 == e1, "delete channel: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+
+#define CONVTESTBAD(Var, Val, Typ) \
+ e1 = e_alloc | e_error | e_free; c1 = 0; \
+ testOk(!(pch = dbChannelCreate("x.{\"sloppy\":{\""#Var"\":"#Val"}}")), "sloppy parsing: "#Typ" (bad) for "#Var); \
+ testOk(!puser1, "user part cleaned up"); \
+ if (!testOk(c1 == e1, "create channel: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+
+ /* To integer */
+ testHead("SLOPPY parsing: conversion to integer");
+ CONVTESTGOOD(i, "123e4", positive string, 123, 1, 1.234e5, "hello", 4);
+ CONVTESTGOOD(i, "-12345", negative string, -12345, 1, 1.234e5, "hello", 4);
+ CONVTESTBAD(i, "9234567890", out-of-range string);
+ CONVTESTBAD(i, ".4", invalid string);
+ CONVTESTGOOD(i, false, valid boolean, 0, 1, 1.234e5, "hello", 4);
+ CONVTESTGOOD(i, 3456.789, valid double, 3456, 1, 1.234e5, "hello", 4);
+ CONVTESTBAD(i, 34.7e14, out-of-range double);
+
+ /* To boolean */
+ testHead("SLOPPY parsing: conversion to boolean");
+ CONVTESTGOOD(f, "false", valid string, 12, 0, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, "False", capital valid string, 12, 0, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, "0", 0 string, 12, 0, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, "15", 15 string, 12, 1, 1.234e5, "hello", 4); /* Any one missing must leave the default intact */
+ CONVTESTBAD(f, ".4", invalid .4 string);
+ CONVTESTBAD(f, "Flase", misspelled invalid string);
+ CONVTESTGOOD(f, 0, zero integer, 12, 0, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, 12, positive integer, 12, 1, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, -1234, negative integer, 12, 1, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, 0.4, positive non-zero double, 12, 1, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, 0.0, zero double, 12, 0, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, -0.0, minus-zero double, 12, 0, 1.234e5, "hello", 4);
+ CONVTESTGOOD(f, -1.24e14, negative double, 12, 1, 1.234e5, "hello", 4);
+
+ /* To double */
+ testHead("SLOPPY parsing: conversion to double");
+ CONVTESTGOOD(d, "123e4", positive double string, 12, 1, 1.23e6, "hello", 4);
+ CONVTESTGOOD(d, "-7.89e-14", negative double string, 12, 1, -7.89e-14, "hello", 4);
+ CONVTESTGOOD(d, "123", positive integer string, 12, 1, 123.0, "hello", 4);
+ CONVTESTGOOD(d, "-1234567", negative integer string, 12, 1, -1.234567e6, "hello", 4);
+ CONVTESTBAD(d, "1.67e407", out-of-range double string);
+ CONVTESTBAD(d, "blubb", invalid blubb string);
+ CONVTESTGOOD(d, 123, positive integer, 12, 1, 123.0, "hello", 4);
+ CONVTESTGOOD(d, -12345, negative integer, 12, 1, -1.2345e4, "hello", 4);
+ CONVTESTGOOD(d, true, true boolean, 12, 1, 1.0, "hello", 4);
+ CONVTESTGOOD(d, false, false boolean, 12, 1, 0.0, "hello", 4);
+
+ /* To string */
+ testHead("SLOPPY parsing: conversion to string");
+ CONVTESTGOOD(s, 12345, positive integer, 12, 1, 1.234e5, "12345", 4);
+ CONVTESTGOOD(s, -1234567891, negative integer, 12, 1, 1.234e5, "-1234567891", 4);
+ CONVTESTGOOD(s, true, true boolean, 12, 1, 1.234e5, "true", 4);
+ CONVTESTGOOD(s, false, false boolean, 12, 1, 1.234e5, "false", 4);
+ CONVTESTGOOD(s, 123e4, small positive double, 12, 1, 1.234e5, "1230000", 4);
+ CONVTESTGOOD(s, -123e24, negative double, 12, 1, 1.234e5, "-1.23e+26", 4);
+ CONVTESTGOOD(s, -1.23456789123456789e26, large rounded negative double, 12, 1, 1.234e5, "-1.234567891235e+26", 4);
+
+ /* To Enum */
+ testHead("SLOPPY parsing: conversion to enum");
+ CONVTESTGOOD(c, 2, valid integer choice, 12, 1, 1.234e5, "hello", 2);
+ CONVTESTBAD(c, 3, invalid integer choice);
+ CONVTESTBAD(c, 3.2, double);
+ CONVTESTGOOD(c, "R", valid string choice, 12, 1, 1.234e5, "hello", 1);
+ CONVTESTBAD(c, "blubb", invalid string choice);
+
+ /* Registering and running filter callbacks */
+
+#define CHAINTEST1(Type, Json, ExpReg, ExpRun, DType) \
+ testHead("Filter chain test, "Type" filter"); \
+ offset = 0; \
+ e1 = e_alloc | e_ok; c1 = 0; \
+ testOk(!!(pch = dbChannelCreate("x."Json)), "filter chains: create channel with "Type" filter"); \
+ if (!testOk(c1 == e1, "create channel: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ e1 = e_open | ExpReg; c1 = 0; \
+ testOk(!dbChannelOpen(pch), "dbChannelOpen returned channel"); \
+ if (!testOk(c1 == e1, "open channel: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ e1 = ExpRun; c1 = 0; \
+ testOk(!!(pfl = db_create_read_log(pch)), "create db_field_log"); \
+ pfl->type = dbfl_type_ref; \
+ pfl->field_type = TYPE_START; \
+ testOk(!!(pfl = dbChannelRunPreChain(pch, pfl)), "run pre eventq chain"); \
+ testOk(!!(pfl = dbChannelRunPostChain(pch, pfl)), "run post eventq chain"); \
+ testOk(pfl->field_type == TYPE_START + DType, "final data type is correct"); \
+ db_delete_field_log(pfl); \
+ if (!testOk(c1 == e1, "run filter chains: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ e1 = e_report; c1 = 0; \
+ dbChannelShow(pch, R_LEVEL, 0); \
+ if (!testOk(c1 == e1, "report: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ e1 = e_close | e_free; c1 = 0; \
+ if (pch) dbChannelDelete(pch); \
+ if (!testOk(c1 == e1, "delete channel: all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1);
+
+#define CHAINTEST2(Type, Json, ExpReg1, ExpRun1, ExpReg2, ExpRun2, DType) \
+ testHead("Filter chain test, "Type" filters"); \
+ offset = 0; \
+ e1 = e_alloc | e_ok; c1 = 0; \
+ e2 = e_alloc | e_ok; c2 = 0; \
+ testOk(!!(pch = dbChannelCreate("x."Json)), "filter chains: create channel with "Type" filters"); \
+ if (!testOk(c1 == e1, "create channel (1): all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ if (!testOk(c2 == e2, "create channel (2): all expected calls happened")) testDiag("expected %#x - called %#x", e2, c2); \
+ e1 = e_open | ExpReg1; c1 = 0; \
+ e2 = e_open | ExpReg2; c2 = 0; \
+ if (pch) testOk(!dbChannelOpen(pch), "dbChannelOpen returned channel"); \
+ if (!testOk(c1 == e1, "open channel (1): all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ if (!testOk(c2 == e2, "open channel (2): all expected calls happened")) testDiag("expected %#x - called %#x", e2, c2); \
+ e1 = ExpRun1; c1 = 0; \
+ e2 = ExpRun2; c2 = 0; \
+ if (pch) testOk(!!(pfl = db_create_read_log(pch)), "create db_field_log"); \
+ pfl->type = dbfl_type_ref; \
+ pfl->field_type = TYPE_START; \
+ if (pch) testOk(!!(pfl = dbChannelRunPreChain(pch, pfl)) || (drop >=0 && drop <= 1), "run pre eventq chain"); \
+ if (pch && (drop < 0 || drop >= 2)) testOk(!!(pfl = dbChannelRunPostChain(pch, pfl)) || drop >=2, "run post eventq chain"); \
+ if (pfl) testOk(pfl->field_type == TYPE_START + DType, "final data type is correct"); \
+ if (pfl) db_delete_field_log(pfl); \
+ if (!testOk(c1 == e1, "run filter chains (1): all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ if (!testOk(c2 == e2, "run filter chains (2): all expected calls happened")) testDiag("expected %#x - called %#x", e2, c2); \
+ e1 = e_report; c1 = 0; \
+ e2 = e_report; c2 = 0; \
+ dbChannelShow(pch, R_LEVEL, 0); \
+ if (!testOk(c1 == e1, "report (1): all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ if (!testOk(c2 == e2, "report (2): all expected calls happened")) testDiag("expected %#x - called %#x", e2, c2); \
+ e1 = e_close | e_free; c1 = 0; \
+ e2 = e_close | e_free; c2 = 0; \
+ if (pch) dbChannelDelete(pch); \
+ if (!testOk(c1 == e1, "delete channel (1): all expected calls happened")) testDiag("expected %#x - called %#x", e1, c1); \
+ if (!testOk(c2 == e2, "delete channel (2): all expected calls happened")) testDiag("expected %#x - called %#x", e2, c2);
+
+ CHAINTEST1("1 pre", "{\"pre\":{}}", e_reg_pre, e_pre | e_dtor, 1); /* One filter, pre chain */
+ CHAINTEST1("1 post", "{\"post\":{}}", e_reg_post, e_post | e_dtor, 1); /* One filter, post chain */
+ CHAINTEST1("1 both", "{\"sloppy\":{}}", e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, 2); /* One, both chains */
+ CHAINTEST2("2 pre", "{\"pre\":{},\"pre\":{}}", e_reg_pre, e_pre | e_dtor, e_reg_pre, e_pre, 2); /* Two filters, pre chain */
+ CHAINTEST2("2 post", "{\"post\":{},\"post\":{}}", e_reg_post, e_post | e_dtor, e_reg_post, e_post, 2); /* Two filters, post chain */
+ CHAINTEST2("2 both", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains */
+ e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, e_reg_pre | e_reg_post, e_pre | e_post, 4);
+ CHAINTEST2("1 pre, 1 post", "{\"pre\":{},\"post\":{}}", e_reg_pre, e_pre | e_dtor, e_reg_post, e_post, 2); /* Two, pre then post */
+ CHAINTEST2("1 post, 1 pre", "{\"post\":{},\"pre\":{}}", e_reg_post, e_post, e_reg_pre, e_pre | e_dtor, 2); /* Two, post then pre */
+ CHAINTEST2("1 pre, 1 both", "{\"pre\":{},\"sloppy\":{}}", /* Two, pre then both */
+ e_reg_pre, e_pre | e_dtor, e_reg_pre | e_reg_post, e_pre | e_post, 3);
+ CHAINTEST2("1 both, 1 pre", "{\"sloppy\":{},\"pre\":{}}", /* Two, both then pre */
+ e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, e_reg_pre, e_pre, 3);
+ CHAINTEST2("1 post, 1 both", "{\"post\":{},\"sloppy\":{}}", /* Two, post then both */
+ e_reg_post, e_post, e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, 3);
+ CHAINTEST2("1 both, 1 post", "{\"sloppy\":{},\"post\":{}}", /* Two, both then post */
+ e_reg_pre | e_reg_post, e_pre | e_post | e_dtor, e_reg_post, e_post, 3);
+
+ /* Plugins dropping updates */
+ drop = 0;
+ CHAINTEST2("2 both (drop at 0)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 0 */
+ e_reg_pre | e_reg_post, e_pre, e_reg_pre | e_reg_post, 0, -1);
+ drop = 1;
+ CHAINTEST2("2 both (drop at 1)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 1 */
+ e_reg_pre | e_reg_post, e_pre, e_reg_pre | e_reg_post, e_pre, -1);
+ drop = 2;
+ CHAINTEST2("2 both (drop at 2)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 2 */
+ e_reg_pre | e_reg_post, e_pre | e_post, e_reg_pre | e_reg_post, e_pre, -1);
+ drop = 3;
+ CHAINTEST2("2 both (drop at 3)", "{\"sloppy\":{},\"sloppy\":{}}", /* Two, both chains, drop at filter 3 */
+ e_reg_pre | e_reg_post, e_pre | e_post, e_reg_pre | e_reg_post, e_pre | e_post, -1);
+ drop = -1;
+
+ dbFreeBase(pdbbase);
+
+ return testDone();
+}
+
+#define GEN_SIZE_OFFSET
+#include "xRecord.h"
+
+#include <recSup.h>
+#include <epicsExport.h>
+
+static rset xRSET;
+epicsExportAddress(rset,xRSET);
=== added file 'src/ioc/db/test/dbChannelTest.c'
--- src/ioc/db/test/dbChannelTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/dbChannelTest.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,260 @@
+/*************************************************************************\
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+
+/*
+ * Author: Andrew Johnson <[email protected]>
+ * Ralph Lange <[email protected]>
+ */
+
+#include "dbChannel.h"
+#include "dbStaticLib.h"
+#include "dbAccessDefs.h"
+#include "recSup.h"
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+/* Expected call bit definitions */
+#define e_start 0x00000001
+#define e_abort 0x00000002
+#define e_end 0x00000004
+#define e_null 0x00000008
+#define e_boolean 0x00000010
+#define e_integer 0x00000020
+#define e_double 0x00000040
+#define e_string 0x00000080
+#define e_start_map 0x00000100
+#define e_map_key 0x00000200
+#define e_end_map 0x00000400
+#define e_start_array 0x00000800
+#define e_end_array 0x00001000
+#define e_open 0x00002000
+#define e_reg_pre 0x00004000
+#define e_reg_post 0x00008000
+#define e_report 0x00010000
+#define e_close 0x00020000
+
+#define r_any (e_start | e_abort | e_end | \
+ e_null | e_boolean | e_integer | e_double | e_string | \
+ e_start_map | e_map_key | e_end_map | e_start_array | e_end_array)
+#define r_scalar (e_start | e_abort | e_end | \
+ e_null | e_boolean | e_integer | e_double | e_string)
+
+unsigned int e, r;
+#define p_ret(x) return r & x ? parse_continue : parse_stop
+
+parse_result p_start(chFilter *filter)
+{
+ testOk(e & e_start, "parse_start called");
+ p_ret(e_start);
+}
+
+void p_abort(chFilter *filter)
+{
+ testOk(e & e_abort, "parse_abort called");
+}
+
+parse_result p_end(chFilter *filter)
+{
+ testOk(e & e_end, "parse_end called");
+ p_ret(e_end);
+}
+
+parse_result p_null(chFilter *filter)
+{
+ testOk(e & e_null, "parse_null called");
+ p_ret(e_null);
+}
+parse_result p_boolean(chFilter *filter, int boolVal)
+{
+ testOk(e & e_boolean, "parse_boolean called, val = %d", boolVal);
+ p_ret(e_boolean);
+}
+parse_result p_integer(chFilter *filter, long integerVal)
+{
+ testOk(e & e_integer, "parse_integer called, val = %ld", integerVal);
+ p_ret(e_integer);
+}
+parse_result p_double(chFilter *filter, double doubleVal)
+{
+ testOk(e & e_double, "parse_double called, val = %g", doubleVal);
+ p_ret(e_double);
+}
+parse_result p_string(chFilter *filter, const char *stringVal, size_t stringLen)
+{
+ testOk(e & e_string, "parse_string called, val = '%.*s'", (int) stringLen,
+ stringVal);
+ p_ret(e_string);
+}
+
+parse_result p_start_map(chFilter *filter)
+{
+ testOk(e & e_start_map, "parse_start_map called");
+ p_ret(e_start_map);
+}
+parse_result p_map_key(chFilter *filter, const char *key, size_t stringLen)
+{
+ testOk(e & e_map_key, "parse_map_key called, key = '%.*s'", (int) stringLen, key);
+ p_ret(e_map_key);
+}
+parse_result p_end_map(chFilter *filter)
+{
+ testOk(e & e_end_map, "parse_end_map called");
+ p_ret(e_end_map);
+}
+
+parse_result p_start_array(chFilter *filter)
+{
+ testOk(e & e_start_array, "parse_start_array called");
+ p_ret(e_start_array);
+}
+parse_result p_end_array(chFilter *filter)
+{
+ testOk(e & e_end_array, "parse_end_array called");
+ p_ret(e_end_array);
+}
+
+long c_open(chFilter *filter)
+{
+ testOk(e & e_open, "channel_open called");
+ return 0;
+}
+void c_reg_pre(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ testOk(e & e_reg_pre, "channel_register_pre called");
+}
+void c_reg_post(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
+{
+ testOk(e & e_reg_post, "channel_register_post called");
+}
+void c_report(chFilter *filter, int level, const unsigned short indent)
+{
+ testOk(e & e_report, "channel_report called, level = %d", level);
+}
+void c_close(chFilter *filter)
+{
+ testOk(e & e_close, "channel_close called");
+}
+
+chFilterIf testIf =
+ { p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
+ p_string, p_start_map, p_map_key, p_end_map, p_start_array, p_end_array,
+ c_open, c_reg_pre, c_reg_post, c_report, c_close };
+
+void xRecord_registerRecordDeviceDriver(struct dbBase *);
+
+MAIN(dbChannelTest)
+{
+ dbChannel *pch;
+
+ testPlan(69);
+
+ testOk1(!dbReadDatabase(&pdbbase, "xRecord.dbd", ".:..", NULL));
+
+ xRecord_registerRecordDeviceDriver(pdbbase);
+ testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.db", ".:..", NULL));
+ testOk(!!pdbbase, "pdbbase was set");
+
+ r = e = 0;
+ /* dbChannelTest() checks record and field names */
+ testOk1(!dbChannelTest("x.NAME"));
+ testOk1(!dbChannelTest("x.VAL"));
+ testOk1(!dbChannelTest("x."));
+ testOk1(!dbChannelTest("x"));
+ testOk(dbChannelTest("y"), "Test, nonexistent record");
+ testOk(dbChannelTest("x.NOFIELD"), "Test, nonexistent field");
+
+ /* dbChannelTest() allows but ignores field modifiers */
+ testOk1(!dbChannelTest("x.NAME$"));
+ testOk1(!dbChannelTest("x.{}"));
+ testOk1(!dbChannelTest("x.VAL{\"json\":true}"));
+
+ /* dbChannelCreate() accepts field modifiers */
+ testOk1(!!(pch = dbChannelCreate("x.{}")));
+ if (pch) dbChannelDelete(pch);
+ testOk1(!!(pch = dbChannelCreate("x.VAL{}")));
+ if (pch) dbChannelDelete(pch);
+ testOk1(!!(pch = dbChannelCreate("x.NAME$")));
+ testOk1(pch && pch->addr.no_elements > 1);
+ if (pch) dbChannelDelete(pch);
+ testOk1(!!(pch = dbChannelCreate("x.NAME${}")));
+ testOk1(pch && pch->addr.no_elements > 1);
+ if (pch) dbChannelDelete(pch);
+
+ /* dbChannelCreate() rejects bad PVs */
+ testOk(!dbChannelCreate("y"), "Create, bad record");
+ testOk(!dbChannelCreate("x.NOFIELD"), "Create, bad field");
+ testOk(!dbChannelCreate("x.{not-json}"), "Create, bad JSON");
+ testOk(!dbChannelCreate("x.{\"none\":null}"), "Create, bad filter");
+
+ dbRegisterFilter("any", &testIf, NULL);
+
+ /* Parser event rejection by filter */
+ e = e_start;
+ testOk1(!dbChannelCreate("x.{\"any\":null}"));
+
+ r = e_start;
+ e = e_start | e_null | e_abort;
+ testOk1(!dbChannelCreate("x.{\"any\":null}"));
+
+ r = e_start | e_null;
+ e = e_start | e_null | e_end;
+ testOk1(!dbChannelCreate("x.{\"any\":null}"));
+
+ /* Successful parsing... */
+ r = r_any;
+ e = e_start | e_null | e_end;
+ testOk1(!!(pch = dbChannelCreate("x.{\"any\":null}")));
+ e = e_close;
+ if (pch) dbChannelDelete(pch);
+
+ dbRegisterFilter("scalar", &testIf, NULL);
+
+ e = e_start | e_null | e_end;
+ testOk1(!!(pch = dbChannelCreate("x.{\"scalar\":null}")));
+
+ e = e_report;
+ dbChannelShow(pch, 1, 2);
+
+ e = e_close;
+ if (pch) dbChannelDelete(pch);
+
+ e = e_start | e_start_array | e_boolean | e_integer | e_end_array
+ | e_end;
+ testOk1(!!(pch = dbChannelCreate("x.{\"any\":[true,1]}")));
+ e = e_close;
+ if (pch) dbChannelDelete(pch);
+
+ e = e_start | e_start_map | e_map_key | e_double | e_string | e_end_map
+ | e_end;
+ testOk1(!!(pch = dbChannelCreate("x.{\"any\":{\"a\":2.7183,\"b\":\"c\"}}")));
+ e = e_close;
+ if (pch) dbChannelDelete(pch);
+
+ /* More event rejection */
+ r = r_scalar;
+ e = e_start | e_start_array | e_abort;
+ testOk1(!dbChannelCreate("x.{\"scalar\":[null]}"));
+
+ e = e_start | e_start_map | e_abort;
+ testOk1(!dbChannelCreate("x.{\"scalar\":{}}"));
+
+ dbFreeBase(pdbbase);
+
+ return testDone();
+}
+
+#define GEN_SIZE_OFFSET
+#include "xRecord.h"
+
+#include <recSup.h>
+#include <epicsExport.h>
+
+static rset xRSET;
+epicsExportAddress(rset,xRSET);
=== added file 'src/ioc/db/test/dbChannelTest.db'
--- src/ioc/db/test/dbChannelTest.db 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/dbChannelTest.db 2012-05-30 18:10:27 +0000
@@ -0,0 +1,2 @@
+record(x, x) {}
+
=== added file 'src/ioc/db/test/dbStateTest.c'
--- src/ioc/db/test/dbStateTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/dbStateTest.c 2012-05-30 18:10:27 +0000
@@ -0,0 +1,56 @@
+/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/*
+ * Author: Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+
+#include "dbState.h"
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+MAIN(dbStateTest)
+{
+ dbStateId red, red2, blue, blue2;
+ int i;
+
+ testPlan(20);
+
+ testOk(!dbStateFind("y"), "Finding nonexisting state fails");
+
+ testOk(!!(red = dbStateCreate("red")), "Create state 'red'");
+ testOk((red2 = dbStateFind("red")) == red, "Find 'red' returns correct id");
+ testOk((red2 = dbStateCreate("red")) == red, "Create existing 'red' returns correct id");
+ testOk(!dbStateFind("y"), "Finding nonexisting state still fails");
+
+ testOk(!!(blue = dbStateCreate("blue")), "Create state 'blue'");
+ testOk((blue2 = dbStateFind("blue")) == blue, "Find 'blue' returns correct id");
+ testOk((blue2 = dbStateCreate("blue")) == blue, "Create existing 'blue' returns correct id");
+ testOk(!dbStateFind("y"), "Finding nonexisting state still fails");
+
+ testOk((i = dbStateGet(red)) == 0, "Default 'red' state is 0");
+ testOk((i = dbStateGet(blue)) == 0, "Default 'blue' state is 0");
+ dbStateSet(red);
+ testOk((i = dbStateGet(red)) == 1, "After setting, 'red' state is 1");
+ testOk((i = dbStateGet(blue)) == 0, "'blue' state is 0");
+ dbStateSet(blue);
+ testOk((i = dbStateGet(blue)) == 1, "After setting, 'blue' state is 1");
+ testOk((i = dbStateGet(red)) == 1, "'red' state is 1");
+ dbStateClear(blue);
+ testOk((i = dbStateGet(blue)) == 0, "After clearing, 'blue' state is 0");
+ testOk((i = dbStateGet(red)) == 1, "'red' state is 1");
+ dbStateClear(red);
+ testOk((i = dbStateGet(red)) == 0, "After clearing, 'red' state is 0");
+ testOk((i = dbStateGet(blue)) == 0, "'red' state is 0");
+
+ testOk(!dbStateFind("y"), "Finding nonexisting state still fails");
+
+ return testDone();
+}
=== added file 'src/ioc/db/test/xRecord.dbd'
--- src/ioc/db/test/xRecord.dbd 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/xRecord.dbd 2012-05-30 18:10:27 +0000
@@ -0,0 +1,12 @@
+# This is a combined minimal DBD and DB file
+
+recordtype(x) {
+ field(NAME, DBF_STRING) {
+ prompt("Record Name")
+ special(SPC_NOMOD)
+ size(61)
+ }
+ field(VAL, DBF_LONG) {
+ prompt("Value")
+ }
+}
=== modified file 'src/ioc/dbStatic/dbBase.h'
--- src/ioc/dbStatic/dbBase.h 2010-10-05 19:27:37 +0000
+++ src/ioc/dbStatic/dbBase.h 2012-05-30 18:10:27 +0000
@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* $Revision-Id$
*
@@ -19,7 +19,7 @@
#include "dbFldTypes.h"
#include "ellLib.h"
#include "dbDefs.h"
-
+
typedef struct dbMenu {
ELLNODE node;
char *name;
@@ -67,7 +67,7 @@
long number; /*number of brkInt in this table*/
struct brkInt *paBrkInt; /* ptr to array of brkInts */
}brkTable;
-
+
typedef struct dbFldDes{ /* field description */
char *prompt; /*Prompt string for DCT*/
char *name; /*Field name*/
@@ -128,7 +128,7 @@
ELLNODE node;
char *name;
char *type;
-
+
}dbVariableDef;
typedef struct dbRecordType {
@@ -164,6 +164,7 @@
ELLLIST functionList;
ELLLIST variableList;
ELLLIST bptList;
+ ELLLIST filterList;
void *pathPvt;
struct dbPvd *ppvd;
struct gphPvt *pgpHash;
=== modified file 'src/ioc/dbStatic/dbPvdLib.c'
--- src/ioc/dbStatic/dbPvdLib.c 2009-04-09 17:28:59 +0000
+++ src/ioc/dbStatic/dbPvdLib.c 2012-05-30 18:10:27 +0000
@@ -181,6 +181,7 @@
ellDelete(&pbucket->list, (ELLNODE *)ppvdNode);
free(ppvdNode);
}
+ epicsMutexUnlock(pbucket->lock);
epicsMutexDestroy(pbucket->lock);
free(pbucket);
}
=== modified file 'src/ioc/dbStatic/dbStaticLib.c'
--- src/ioc/dbStatic/dbStaticLib.c 2012-05-29 21:44:49 +0000
+++ src/ioc/dbStatic/dbStaticLib.c 2012-05-30 18:10:27 +0000
@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* $Revision-Id$ */
@@ -41,7 +41,7 @@
#include "guigroup.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
-
+
int dbStaticDebug = 0;
static char *pNullString = "";
#define messagesize 100
@@ -191,7 +191,7 @@
sizeof(promptBBGPIB_IO)/sizeof(char *),
sizeof(promptRF_IO)/sizeof(char *),
sizeof(promptVXI_IO)/sizeof(char *)};
-
+
/*forward references for private routines*/
static FILE *openOutstream(const char *filename);
static void finishOutstream(FILE *stream);
@@ -203,7 +203,7 @@
static char *getpMessage(DBENTRY *pdbentry);
static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname);
static long epicsShareAPI dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length);
-
+
/* internal routines*/
static FILE *openOutstream(const char *filename)
{
@@ -347,7 +347,7 @@
if(plink->text) free(plink->text);
memset((char *)plink,0,sizeof(struct link));
}
-
+
void dbFreePath(DBBASE *pdbbase)
{
ELLLIST *ppathList;
@@ -366,7 +366,7 @@
return;
}
-
+
static long mapLINKTtoFORMT(DBLINK *plink,dbFldDes *pflddes,int *ind)
{
switch(plink->type) {
@@ -407,7 +407,7 @@
}
return(S_dbLib_badLink);
}
-
+
static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess)
{
char message[200];
@@ -439,7 +439,7 @@
strcat(pmessage,mess);
errMessage(status,pmessage);
}
-
+
static void zeroDbentry(DBENTRY *pdbentry)
{
/*NOTE that pdbbase, message, and formpvt MUST NOT be set to NULL*/
@@ -466,7 +466,7 @@
dbFldDes *pflddes;
DBLINK *plink;
char *pname;
-
+
dbGetFieldAddress(pdbentry);
pflddes = pdbentry->pflddes;
if(!pflddes) return(-1);
@@ -489,7 +489,7 @@
}
return(S_dbLib_badLink);
}
-
+
/*Public only for dbStaticNoRun*/
dbDeviceMenu *dbGetDeviceMenu(DBENTRY *pdbentry)
{
@@ -526,7 +526,7 @@
pflddes->ftPvt = pdbDeviceMenu;
return(pdbDeviceMenu);
}
-
+
/* Beginning of Public Routines */
#define INC_SIZE 256
@@ -555,7 +555,7 @@
strcat(*string,src);
*stringLength += strlen(src);
}
-
+
dbBase * epicsShareAPI dbAllocBase(void)
{
dbBase *pdbbase;
@@ -568,6 +568,7 @@
ellInit(&pdbbase->functionList);
ellInit(&pdbbase->variableList);
ellInit(&pdbbase->bptList);
+ ellInit(&pdbbase->filterList);
gphInitPvt(&pdbbase->pgpHash,256);
dbPvdInitPvt(pdbbase);
return (pdbbase);
@@ -595,7 +596,7 @@
brkTable *pbrkTableNext;
int i;
DBENTRY dbentry;
-
+
dbInitEntry(pdbbase,&dbentry);
pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
@@ -620,7 +621,7 @@
free((void *)pdbFldDes->initial);
if(pdbFldDes->field_type==DBF_DEVICE && pdbFldDes->ftPvt) {
dbDeviceMenu *pdbDeviceMenu;
-
+
pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt;
free((void *)pdbDeviceMenu->papChoice);
free((void *)pdbDeviceMenu);
@@ -729,12 +730,12 @@
free((void *)pdbbase);
return;
}
-
+
DBENTRY * epicsShareAPI dbAllocEntry(dbBase *pdbbase)
{
DBENTRY *pdbentry;
- pdbentry = dbmfMalloc(sizeof(DBENTRY));
+ pdbentry = dbmfMalloc(sizeof(DBENTRY));
memset(pdbentry,'\0',sizeof(DBENTRY));
pdbentry->pdbbase = pdbbase;
return(pdbentry);
@@ -780,7 +781,7 @@
pto->formpvt = NULL;
}
-
+
long epicsShareAPI dbPath(DBBASE *pdbbase,const char *path)
{
if(!pdbbase) return(-1);
@@ -796,7 +797,7 @@
const char *plast;
unsigned expectingPath;
unsigned sawMissingPath;
-
+
if(!pdbbase) return(-1);
ppathList = (ELLLIST *)pdbbase->pathPvt;
if(!ppathList) {
@@ -865,7 +866,7 @@
{
ELLLIST *ppathList;
dbPathNode *pdbPathNode;
-
+
if(!pdbbase) return(-1);
ppathList = (ELLLIST *)pdbbase->pathPvt;
@@ -877,7 +878,7 @@
return 0;
}
-
+
long epicsShareAPI dbWriteRecord(DBBASE *ppdbbase,const char *filename,
const char *precordTypename,int level)
{
@@ -974,7 +975,7 @@
dbFinishEntry(pdbentry);
return(0);
}
-
+
long epicsShareAPI dbWriteMenu(
DBBASE *ppdbbase,const char *filename,const char *menuName)
{
@@ -1017,7 +1018,7 @@
}
return(0);
}
-
+
long epicsShareAPI dbWriteRecordType(
DBBASE *pdbbase,const char *filename,const char *recordTypeName)
{
@@ -1114,7 +1115,7 @@
}
return(0);
}
-
+
long epicsShareAPI dbWriteDevice(DBBASE *pdbbase,const char *filename)
{
FILE *stream;
@@ -1156,7 +1157,7 @@
}
return(0);
}
-
+
long epicsShareAPI dbWriteDriver(DBBASE *pdbbase,const char *filename)
{
FILE *stream;
@@ -1227,7 +1228,7 @@
}
return(0);
}
-
+
long epicsShareAPI dbWriteBreaktable(DBBASE *pdbbase,const char *filename)
{
FILE *stream;
@@ -1262,7 +1263,7 @@
}
return(0);
}
-
+
long epicsShareAPI dbFindRecordType(DBENTRY *pdbentry,const char *recordType)
{
dbBase *pdbbase = pdbentry->pdbbase;
@@ -1306,7 +1307,7 @@
{
return(ellCount(&pdbentry->pdbbase->recordTypeList));
}
-
+
long epicsShareAPI dbPutRecordAttribute(
DBENTRY *pdbentry, const char *name, const char*value)
{
@@ -1382,7 +1383,7 @@
{
return dbGetAttributePart(pdbentry, &pname);
}
-
+
long epicsShareAPI dbFirstField(DBENTRY *pdbentry,int dctonly)
{
@@ -1426,7 +1427,7 @@
indfield++;
}
}
-
+
int epicsShareAPI dbGetFieldType(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -1450,7 +1451,7 @@
n = 0;
for(indfield=0; indfield<precordType->no_fields; indfield++) {
pflddes = precordType->papFldDes[indfield];
- if(dctonly && (pflddes->field_type==DBF_DEVICE)
+ if(dctonly && (pflddes->field_type==DBF_DEVICE)
&& (ellCount(&precordType->devList)==0) ) continue;
if(!dctonly || pflddes->promptgroup) n++;
}
@@ -1488,7 +1489,7 @@
if(!pflddes) return(0);
return(pflddes->promptgroup);
}
-
+
long epicsShareAPI dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1535,7 +1536,7 @@
if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);}
return(0);
}
-
+
long epicsShareAPI dbDeleteAliases(DBENTRY *pdbentry)
{
dbBase *pdbbase = pdbentry->pdbbase;
@@ -1653,7 +1654,7 @@
return dbFindField(pdbentry, ++pname);
return 0;
}
-
+
long epicsShareAPI dbFirstRecord(DBENTRY *pdbentry)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1706,7 +1707,7 @@
if(!precnode) return NULL;
return precnode->recordname;
}
-
+
long epicsShareAPI dbRenameRecord(DBENTRY *pdbentry,const char *newName)
{
dbBase *pdbbase = pdbentry->pdbbase;
@@ -1752,7 +1753,7 @@
/*Leave pdbentry pointing to newly renamed record*/
return(dbFindRecord(pdbentry,newName));
}
-
+
long epicsShareAPI dbVisibleRecord(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
@@ -1778,7 +1779,7 @@
if(!precnode) return 0;
return precnode->flags & DBRN_FLAGS_VISIBLE ? 1 : 0;
}
-
+
long epicsShareAPI dbCreateAlias(DBENTRY *pdbentry, const char *alias)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1828,7 +1829,7 @@
if(!precnode) return 0;
return precnode->flags & DBRN_FLAGS_ISALIAS ? 1 : 0;
}
-
+
long epicsShareAPI dbCopyRecord(DBENTRY *pdbentry,const char *newRecordName,int overWriteOK)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1882,7 +1883,7 @@
/*Leave pdbentry pointing to newRecordName*/
return(dbFindRecord(pdbentry,newRecordName));
}
-
+
long epicsShareAPI dbFindFieldPart(DBENTRY *pdbentry,const char **ppname)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -1967,7 +1968,7 @@
int epicsShareAPI dbFoundField(DBENTRY *pdbentry)
{ return((pdbentry->pfield) ? TRUE : FALSE); }
-
+
char * epicsShareAPI dbGetString(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -1997,7 +1998,7 @@
case DBF_DEVICE:
return(dbGetStringNum(pdbentry));
case DBF_INLINK:
- case DBF_OUTLINK:
+ case DBF_OUTLINK:
if(!pfield) {strcpy(message,"Field not found"); return(message);}
plink = (DBLINK *)pfield;
switch(plink->type) {
@@ -2138,7 +2139,7 @@
}
return (message);
}
-
+
static void cvtDecimalOrHexToShort(char *from,short *value)
{
if(strspn(from,"0x")==2 || strspn(from,"0X")==2) {
@@ -2264,7 +2265,7 @@
goto done;
}
switch (plink->type) {
- case CONSTANT:
+ case CONSTANT:
case PV_LINK: {
short ppOpt = 0;
short msOpt = 0;
@@ -2428,7 +2429,7 @@
}
break;
case GPIB_IO: {
- char *end;
+ char *end;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
@@ -2545,7 +2546,7 @@
}
return(status);
}
-
+
char * epicsShareAPI dbVerify(DBENTRY *pdbentry,const char *pstring)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -2591,13 +2592,13 @@
return(message);
}
switch (pflddes->field_type) {
- case DBF_CHAR :
+ case DBF_CHAR :
if(value<-128 || value>127) {
strcpy(message,"must have -128<=value<=127");
return(message);
}
return(NULL);
- case DBF_SHORT :
+ case DBF_SHORT :
if(value<-32768 || value>32767) {
strcpy(message,"must have -32768<=value<=32767");
return(message);
@@ -2626,14 +2627,14 @@
return(message);
}
switch (pflddes->field_type) {
- case DBF_UCHAR :
+ case DBF_UCHAR :
if(value>255) {
strcpy(message,"must have 0<=value<=255");
return(message);
}
return(NULL);
case DBF_ENUM:
- case DBF_USHORT :
+ case DBF_USHORT :
if(value>65535) {
strcpy(message,"must have 0<=value<=65535");
return(message);
@@ -2646,7 +2647,7 @@
}
}
case DBF_FLOAT:
- case DBF_DOUBLE: {
+ case DBF_DOUBLE: {
double value;
char *endp;
@@ -2661,7 +2662,7 @@
dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
char *pchoice;
int i;
-
+
if(!pdbMenu) return(NULL);
for (i = 0; i < pdbMenu->nChoice; i++) {
if(!(pchoice = pdbMenu->papChoiceValue[i])) continue;
@@ -2699,7 +2700,7 @@
strcpy(message,"Not a valid field type");
return (message);
}
-
+
char *epicsShareAPI dbGetRange(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -2729,14 +2730,14 @@
strcpy(message,"Not a valid field type");
return (message);
}
-
+
long epicsShareAPI dbFirstInfo(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
-
+
pdbentry->pinfonode = NULL;
if (!precnode) return (S_dbLib_recNotFound);
-
+
pdbentry->pinfonode = (dbInfoNode *)ellFirst(&precnode->infoList);
return (pdbentry->pinfonode ? 0 : S_dbLib_infoNotFound);
}
@@ -2745,11 +2746,11 @@
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo;
-
+
if (!precnode) return (S_dbLib_recNotFound);
pinfo = pdbentry->pinfonode;
if (!pinfo) return (S_dbLib_infoNotFound);
-
+
pinfo = (dbInfoNode *)ellNext(&pinfo->node);
pdbentry->pinfonode = pinfo;
return (pinfo ? 0 : S_dbLib_infoNotFound);
@@ -2759,10 +2760,10 @@
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo;
-
+
pdbentry->pinfonode = NULL;
if (!precnode) return(S_dbLib_recNotFound);
-
+
pinfo = (dbInfoNode *)ellFirst(&precnode->infoList);
while (pinfo) {
if (!strcmp(pinfo->name, name)) {
@@ -2778,7 +2779,7 @@
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo = pdbentry->pinfonode;
-
+
if (!precnode) return (S_dbLib_recNotFound);
if (!pinfo) return (S_dbLib_infoNotFound);
ellDelete(&precnode->infoList,&pinfo->node);
@@ -2841,11 +2842,11 @@
dbInfoNode *pinfo;
dbRecordNode *precnode = pdbentry->precnode;
if (!precnode) return (S_dbLib_recNotFound);
-
+
dbFindInfo(pdbentry, name);
pinfo = pdbentry->pinfonode;
if (pinfo) return (dbPutInfoString(pdbentry, string));
-
+
/*Create new info node*/
pinfo = calloc(1,sizeof(dbInfoNode));
if (!pinfo) return (S_dbLib_outMem);
@@ -2875,7 +2876,7 @@
if(!pgph) return(NULL);
return((brkTable *)pgph->userPvt);
}
-
+
dbMenu * epicsShareAPI dbFindMenu(dbBase *pdbbase,const char *name)
{
GPHENTRY *pgph;
@@ -2933,7 +2934,7 @@
}
return (-1);
}
-
+
char * epicsShareAPI dbGetMenuStringFromIndex(DBENTRY *pdbentry, int index)
{
dbFldDes *pflddes = pdbentry->pflddes;
@@ -2996,13 +2997,13 @@
}
return (-1);
}
-
+
drvSup * epicsShareAPI dbFindDriver(dbBase *pdbbase, const char *name) {
GPHENTRY *pgph = gphFind(pdbbase->pgpHash,name,&pdbbase->drvList);
if (!pgph) return NULL;
return (drvSup *) pgph->userPvt;
}
-
+
int epicsShareAPI dbAllocForm(DBENTRY *psave)
{
DBENTRY dbEntry;
@@ -3076,7 +3077,7 @@
dbFinishEntry(pdbentry);
return(nlines);
}
-
+
long epicsShareAPI dbFreeForm(DBENTRY *pdbentry)
{
if(pdbentry->formpvt) {
@@ -3093,7 +3094,7 @@
if(!pform) return(NULL);
return(pform->prompt);
}
-
+
char ** epicsShareAPI dbGetFormValue(DBENTRY *pdbentry)
{
struct form *pform = pdbentry->formpvt;
@@ -3105,7 +3106,7 @@
if(!plink) return(NULL);
value = pform->value;
switch(pform->linkType) {
- case FORM_CONSTANT:
+ case FORM_CONSTANT:
if(plink->value.constantStr) {
strcpy(*value,plink->value.constantStr);
} else {
@@ -3263,7 +3264,7 @@
}
return(pform->value);
}
-
+
long epicsShareAPI dbPutForm(DBENTRY *pdbentry,char **value)
{
struct form *pform = pdbentry->formpvt;
@@ -3279,7 +3280,7 @@
if(!plink) return(S_dbLib_badLink);
verify = pform->verify;
switch(pform->linkType) {
- case FORM_CONSTANT:
+ case FORM_CONSTANT:
**verify = 0; /*Initialize to no error*/
if(**value == '\0') break;
dvalue = epicsStrtod(*value,&endp);
@@ -3580,7 +3581,7 @@
**verify = 0;
break;
case FORM_VXI_IO:
- plink->value.vxiio.flag =
+ plink->value.vxiio.flag =
((strchr(*value,'Y')||strchr(*value,'y') ? VXIDYNAMIC : VXISTATIC));
value++; verify++;
lvalue = strtol(*value,&endp,0);
@@ -3619,7 +3620,7 @@
}
return(status);
}
-
+
char ** epicsShareAPI dbVerifyForm(DBENTRY *pdbentry,char **value)
{
struct form *pform = pdbentry->formpvt;
@@ -3664,7 +3665,7 @@
dbFinishEntry(pdbentry);
return(rtnval);
}
-
+
int epicsShareAPI dbGetNLinks(DBENTRY *pdbentry)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -3715,7 +3716,7 @@
}
return(-1);
}
-
+
long epicsShareAPI dbCvtLinkToConstant(DBENTRY *pdbentry)
{
dbFldDes *pflddes;
@@ -3779,7 +3780,7 @@
}
return(S_dbLib_badLink);
}
-
+
void epicsShareAPI dbDumpPath(DBBASE *pdbbase)
{
ELLLIST *ppathList;
@@ -3821,7 +3822,7 @@
}
dbWriteMenuFP(pdbbase,stdout,menuName);
}
-
+
void epicsShareAPI dbDumpRecordType(DBBASE *pdbbase,const char *recordTypeName)
{
dbRecordType *pdbRecordType;
@@ -3863,7 +3864,7 @@
if(recordTypeName) break;
}
}
-
+
void epicsShareAPI dbDumpField(
DBBASE *pdbbase,const char *recordTypeName,const char *fname)
{
@@ -3955,7 +3956,7 @@
if(recordTypeName) break;
}
}
-
+
void epicsShareAPI dbDumpDevice(DBBASE *pdbbase,const char *recordTypeName)
{
dbRecordType *pdbRecordType;
@@ -4051,7 +4052,7 @@
}
return;
}
-
+
static char *bus[VXI_IO+1] = {"","","VME","CAMAC","AB",
"GPIB","BITBUS","","","","","","INST","BBGPIB","VXI"};
void epicsShareAPI dbReportDeviceConfig(dbBase *pdbbase,FILE *report)
=== modified file 'src/ioc/dbStatic/link.h'
--- src/ioc/dbStatic/link.h 2010-10-05 19:27:37 +0000
+++ src/ioc/dbStatic/link.h 2012-05-30 18:10:27 +0000
@@ -1,27 +1,24 @@
/*************************************************************************\
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
+* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* link.h */
-/* base/include $Revision-Id$ */
+/* $Id$ */
/*
- * Original Author: Bob Dalesio
- * Current Author: Marty Kraimer
- * Date: 6-1-90
+ * Original Authors: Bob Dalesio, Marty Kraimer
*/
+#ifndef INC_link_H
+#define INC_link_H
+
#include "dbDefs.h"
#include "shareLib.h"
-#ifndef INClinkh
-#define INClinkh 1
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -55,8 +52,8 @@
/* structure of a PV_LINK DB_LINK and a CA_LINK */
/*Options defined by pvlMask */
#define pvlOptMsMode 0x3 /*Maximize Severity mode selection*/
-#define pvlOptNMS 0 /*Dont Maximize Severity*/
-#define pvlOptMS 1 /*Maximize Severity allways*/
+#define pvlOptNMS 0 /*Don't Maximize Severity*/
+#define pvlOptMS 1 /*Maximize Severity always*/
#define pvlOptMSI 2 /*Maximize Severity if INVALID*/
#define pvlOptMSS 3 /*Maximize Severity and copy Status*/
#define pvlOptPP 0x4 /*Process Passive*/
@@ -77,14 +74,15 @@
};
struct dbCommon;
+struct pvlet;
struct pv_link {
- char *pvname; /*pvname to link to*/
- struct dbCommon *precord; /*Address of record containing link*/
- void *pvt; /*CA or DB private*/
- LINKCVT getCvt; /*input conversion function*/
- short pvlMask; /*Options mask*/
- short lastGetdbrType; /*last dbrType for DB or CA get*/
+ char *pvname; /* pvname link points to */
+ struct dbCommon *precord; /* Address of record owning link */
+ void *pvt; /* CA or DB private */
+ LINKCVT getCvt; /* input conversion function */
+ short pvlMask; /* Options mask */
+ short lastGetdbrType; /* last dbrType for DB or CA get */
};
/* structure of a VME io channel */
@@ -150,13 +148,12 @@
/* structure of an instrument io link */
struct instio {
- char *string; /* the cat of location.
- signal.parameter */
+ char *string;
};
/* structure of a vxi link */
struct vxiio{
- short flag; /* 0 = frame/slot, 1 = SA */
+ short flag; /* 0 = frame/slot, 1 = SA */
short frame;
short slot;
short la; /* logical address if flag =1 */
@@ -165,7 +162,7 @@
};
/* union of possible address structures */
-union value{
+union value {
char *constantStr; /*constant string*/
struct macro_link macro_link; /* link containing macro substitution*/
struct pv_link pv_link; /* link to process variable*/
@@ -180,9 +177,9 @@
struct vxiio vxiio; /* vxi io */
};
-struct link{
- union value value;
- short type;
+struct link {
+ union value value;
+ short type;
char *text; /* original INP/OUT link text */
};
@@ -191,4 +188,4 @@
#ifdef __cplusplus
}
#endif
-#endif /*INClinkh*/
+#endif /* INC_link_H */
=== modified file 'src/ioc/misc/iocInit.c'
--- src/ioc/misc/iocInit.c 2011-09-26 21:42:15 +0000
+++ src/ioc/misc/iocInit.c 2012-05-30 18:10:27 +0000
@@ -41,7 +41,6 @@
#include "taskwd.h"
#include "callback.h"
#include "dbCommon.h"
-#include "dbLock.h"
#include "devSup.h"
#include "drvSup.h"
#include "menuConvert.h"
@@ -59,6 +58,7 @@
#include "initHooks.h"
#include "epicsExit.h"
#include "epicsSignal.h"
+#include "dbChannel.h"
#define epicsExportSharedSymbols
#include "epicsRelease.h"
@@ -426,48 +426,18 @@
static void doResolveLinks(dbRecordType *pdbRecordType, dbCommon *precord,
void *user)
{
+ dbFldDes **papFldDes = pdbRecordType->papFldDes;
+ short *link_ind = pdbRecordType->link_ind;
devSup *pdevSup;
int j;
- /* Convert all PV_LINKs to DB_LINKs or CA_LINKs */
/* For all the links in the record type... */
for (j = 0; j < pdbRecordType->no_links; j++) {
- dbFldDes *pdbFldDes =
- pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
+ dbFldDes *pdbFldDes = papFldDes[link_ind[j]];
DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
- if (plink->type == PV_LINK) {
- DBADDR dbaddr;
-
- if (plink == &precord->tsel) recGblTSELwasModified(plink);
- if (!(plink->value.pv_link.pvlMask&(pvlOptCA|pvlOptCP|pvlOptCPP))
- && (dbNameToAddr(plink->value.pv_link.pvname,&dbaddr)==0)) {
- DBADDR *pdbAddr;
-
- plink->type = DB_LINK;
- pdbAddr = dbCalloc(1,sizeof(struct dbAddr));
- *pdbAddr = dbaddr; /*structure copy*/;
- plink->value.pv_link.pvt = pdbAddr;
- } else {/*It is a CA link*/
-
- if (pdbFldDes->field_type == DBF_INLINK) {
- plink->value.pv_link.pvlMask |= pvlOptInpNative;
- }
- dbCaAddLink(plink);
- if (pdbFldDes->field_type == DBF_FWDLINK) {
- char *pperiod =
- strrchr(plink->value.pv_link.pvname,'.');
-
- if (pperiod && strstr(pperiod,"PROC")) {
- plink->value.pv_link.pvlMask |= pvlOptFWD;
- } else {
- errlogPrintf("%s.FLNK is a Channel Access Link "
- " but does not link to a PROC field\n",
- precord->name);
- }
- }
- }
- }
+ if (plink->type == PV_LINK)
+ dbInitLink(precord, plink, pdbFldDes->field_type);
}
pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
if (pdevSup) {
@@ -491,6 +461,7 @@
static void initDatabase(void)
{
+ dbChannelInit();
iterateRecords(doInitRecord0, NULL);
iterateRecords(doResolveLinks, NULL);
iterateRecords(doInitRecord1, NULL);
=== modified file 'src/ioc/registry/registerRecordDeviceDriver.pl'
--- src/ioc/registry/registerRecordDeviceDriver.pl 2012-03-27 15:47:59 +0000
+++ src/ioc/registry/registerRecordDeviceDriver.pl 2012-05-30 18:10:27 +0000
@@ -18,12 +18,18 @@
use DBD::Parser;
use EPICS::Readfile;
use EPICS::Path;
+use EPICS::Getopts;
use Text::Wrap;
+getopts('I@') or
+ die "Usage: registerRecordDeviceDriver [-I dir] in.dbd subroutinename [TOP]";
+
+my @path = map { split /[:;]/ } @EPICS::Getopts::opt_I; # FIXME: Broken on Win32?
+
my ($file, $subname, $bldTop) = @ARGV;
my $dbd = DBD->new();
-&ParseDBD($dbd, &Readfile($file));
+&ParseDBD($dbd, &Readfile($file, "", \@path));
$Text::Wrap::columns = 75;
=== modified file 'src/ioc/rsrv/camessage.c'
--- src/ioc/rsrv/camessage.c 2010-11-01 21:01:04 +0000
+++ src/ioc/rsrv/camessage.c 2012-05-30 18:10:27 +0000
@@ -1,15 +1,19 @@
/*************************************************************************\
+* Copyright (c) 2010 Brookhaven National Laboratory.
+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
+* fuer Materialien und Energie GmbH.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
- * Author: Jeffrey O. Hill
+ * Author: Jeffrey O. Hill <[email protected]>
*
+ * Ralph Lange <[email protected]>
*/
#include <stddef.h>
@@ -45,7 +49,7 @@
#include "rsrv.h"
#include "server.h"
-#define RECORD_NAME(PADDR) ((PADDR)->precord->name)
+#define RECORD_NAME(CHAN) (dbChannelRecord(CHAN)->name)
static EVENTFUNC read_reply;
@@ -60,9 +64,9 @@
putNotify dbPutNotify;
caHdrLargeArray msg;
/*
- * Include a union of all scalar types
+ * Include a union of all scalar types
* including fixed length strings so
- * that in many cases we can avoid
+ * that in many cases we can avoid
* allocating another buffer and only
* use an rsrv_put_notify from its
* free list.
@@ -173,8 +177,8 @@
/*
* allocate plenty of space for a sprintf() buffer
*/
- localStatus = cas_copy_in_header ( client,
- CA_PROTO_ERROR, maxDiagLen, 0, 0, cid, status,
+ localStatus = cas_copy_in_header ( client,
+ CA_PROTO_ERROR, maxDiagLen, 0, 0, cid, status,
( void * ) &pReqOut );
if ( localStatus != ECA_NORMAL ) {
errlogPrintf ( "caserver: Unable to deliver err msg \"%s\" to client because \"%s\"\n",
@@ -187,7 +191,7 @@
* copy back the request protocol
* (in network byte order)
*/
- if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
+ if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
CA_V49( client->minor_version_number ) ) {
ca_uint32_t *pLW = ( ca_uint32_t * ) ( pReqOut + 1 );
pReqOut->m_cmmd = htons ( curp->m_cmmd );
@@ -222,7 +226,7 @@
size += (ca_uint32_t) (diagLen + 1u);
}
else {
- errlogPrintf (
+ errlogPrintf (
"caserver: vsend_err: epicsVsnprintf detected "
"error message truncation, pFormat = \"%s\"\n",
pformat );
@@ -282,9 +286,9 @@
"CAS: Request from %s => cmmd=%d cid=0x%x type=%d count=%d postsize=%u\n",
hostName, mp->m_cmmd, mp->m_cid, mp->m_dataType, mp->m_count, mp->m_postsize);
- epicsPrintf (
-"CAS: Request from %s => available=0x%x \tN=%u paddr=%p\n",
- hostName, mp->m_available, mnum, (pciu?(void *)&pciu->addr:NULL));
+ epicsPrintf (
+"CAS: Request from %s => available=0x%x \tN=%u dbch=%p\n",
+ hostName, mp->m_available, mnum, (pciu?(void *)&pciu->dbch:NULL));
if (mp->m_cmmd==CA_PROTO_WRITE && mp->m_dataType==DBF_STRING && pPayLoad ) {
epicsPrintf (
@@ -297,7 +301,7 @@
* logBadIdWithFileAndLineno()
*/
static void logBadIdWithFileAndLineno(
-struct client *client,
+struct client *client,
caHdrLargeArray *mp,
const void *pPayload,
char *pFileName,
@@ -314,10 +318,10 @@
/*
* bad_udp_cmd_action()
*/
-static int bad_udp_cmd_action ( caHdrLargeArray *mp,
+static int bad_udp_cmd_action ( caHdrLargeArray *mp,
void *pPayload, struct client *pClient )
{
- log_header ("invalid (damaged?) request code from UDP",
+ log_header ("invalid (damaged?) request code from UDP",
pClient, mp, pPayload, 0);
return RSRV_ERROR;
}
@@ -325,13 +329,13 @@
/*
* udp_echo_action()
*/
-static int udp_echo_action ( caHdrLargeArray *mp,
+static int udp_echo_action ( caHdrLargeArray *mp,
void *pPayload, struct client *pClient )
{
char *pPayloadOut;
int status;
SEND_LOCK ( pClient );
- status = cas_copy_in_header ( pClient, mp->m_cmmd, mp->m_postsize,
+ status = cas_copy_in_header ( pClient, mp->m_cmmd, mp->m_postsize,
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available,
( void * ) &pPayloadOut );
if ( status == ECA_NORMAL ) {
@@ -345,13 +349,13 @@
/*
* bad_tcp_cmd_action()
*/
-static int bad_tcp_cmd_action ( caHdrLargeArray *mp, void *pPayload,
+static int bad_tcp_cmd_action ( caHdrLargeArray *mp, void *pPayload,
struct client *client )
{
const char *pCtx = "invalid (damaged?) request code from TCP";
log_header ( pCtx, client, mp, pPayload, 0 );
- /*
+ /*
* by default, clients dont recover
* from this
*/
@@ -365,7 +369,7 @@
/*
* tcp_version_action()
*/
-static int tcp_version_action ( caHdrLargeArray *mp, void *pPayload,
+static int tcp_version_action ( caHdrLargeArray *mp, void *pPayload,
struct client *client )
{
double tmp;
@@ -406,13 +410,13 @@
/*
* tcp_echo_action()
*/
-static int tcp_echo_action ( caHdrLargeArray *mp,
+static int tcp_echo_action ( caHdrLargeArray *mp,
void *pPayload, struct client *pClient )
{
char *pPayloadOut;
int status;
SEND_LOCK ( pClient );
- status = cas_copy_in_header ( pClient, mp->m_cmmd, mp->m_postsize,
+ status = cas_copy_in_header ( pClient, mp->m_cmmd, mp->m_postsize,
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available,
( void * ) &pPayloadOut );
if ( status == ECA_NORMAL ) {
@@ -426,7 +430,7 @@
/*
* events_on_action ()
*/
-static int events_on_action ( caHdrLargeArray *mp,
+static int events_on_action ( caHdrLargeArray *mp,
void *pPayload, struct client *pClient )
{
db_event_flow_ctrl_mode_off ( pClient->evuser );
@@ -436,7 +440,7 @@
/*
* events_off_action ()
*/
-static int events_off_action ( caHdrLargeArray *mp,
+static int events_off_action ( caHdrLargeArray *mp,
void *pPayload, struct client *pClient )
{
db_event_flow_ctrl_mode_on ( pClient->evuser );
@@ -462,8 +466,8 @@
* on failure to pre v41 clients
*/
if ( ! CA_V41 ( pClient->minor_version_number ) ) {
- send_err ( &pevext->msg, ECA_GETFAIL, pClient,
- RECORD_NAME ( &pevext->pciu->addr ) );
+ send_err ( &pevext->msg, ECA_GETFAIL, pClient,
+ RECORD_NAME ( pevext->pciu->dbch ) );
return;
}
@@ -473,30 +477,30 @@
* event/put/get callback.
*
* Fetched value is zerod in case they
- * use it even when the status indicates
+ * use it even when the status indicates
* failure.
*
* The m_cid field in the protocol
* header is abused to carry the status
*/
- status = cas_copy_in_header ( pClient, pevext->msg.m_cmmd, pevext->size,
- pevext->msg.m_dataType, pevext->msg.m_count, ECA_NORDACCESS,
+ status = cas_copy_in_header ( pClient, pevext->msg.m_cmmd, pevext->size,
+ pevext->msg.m_dataType, pevext->msg.m_count, ECA_NORDACCESS,
pevext->msg.m_available, ( void * ) &pPayloadOut );
if ( status == ECA_NORMAL ) {
memset ( pPayloadOut, 0, pevext->size );
cas_commit_msg ( pClient, pevext->size );
}
else {
- send_err ( &pevext->msg, status, pClient,
+ send_err ( &pevext->msg, status, pClient,
"server unable to load read access denied response into protocol buffer PV=\"%s max bytes=%u\"",
- RECORD_NAME ( &pevext->pciu->addr ), rsrvSizeofLargeBufTCP );
+ RECORD_NAME ( pevext->pciu->dbch ), rsrvSizeofLargeBufTCP );
}
}
/*
* read_reply()
*/
-static void read_reply ( void *pArg, struct dbAddr *paddr,
+static void read_reply ( void *pArg, struct dbChannel *dbch,
int eventsRemaining, db_field_log *pfl )
{
ca_uint32_t cid;
@@ -508,12 +512,14 @@
int status;
int v41;
int autosize;
+ int local_fl = 0;
long item_count;
ca_uint32_t payload_size;
+ dbAddr *paddr=&dbch->addr;
SEND_LOCK ( pClient );
- /*
+ /*
* New clients recv the status of the
* operation directly to the
* event/put/get callback.
@@ -543,10 +549,10 @@
pevext->msg.m_dataType, item_count, cid, pevext->msg.m_available,
&pPayload );
if ( status != ECA_NORMAL ) {
- send_err ( &pevext->msg, status, pClient,
+ send_err ( &pevext->msg, status, pClient,
"server unable to load read (or subscription update) response "
"into protocol buffer PV=\"%s\" max bytes=%u",
- RECORD_NAME ( paddr ), rsrvSizeofLargeBufTCP );
+ RECORD_NAME ( dbch ), rsrvSizeofLargeBufTCP );
if ( ! eventsRemaining )
cas_send_bs_msg ( pClient, FALSE );
SEND_UNLOCK ( pClient );
@@ -564,19 +570,32 @@
return;
}
- status = db_get_field_and_count(
- paddr, pevext->msg.m_dataType, pPayload, &item_count, pfl);
+ /* If filters are involved in a read, create field log and run filters */
+ if (!pfl && (ellCount(&dbch->pre_chain) || ellCount(&dbch->post_chain))) {
+ pfl = db_create_read_log(dbch);
+ if (pfl) {
+ local_fl = 1;
+ pfl = dbChannelRunPreChain(dbch, pfl);
+ pfl = dbChannelRunPostChain(dbch, pfl);
+ }
+ }
+
+ status = dbChannel_get_count ( dbch, pevext->msg.m_dataType,
+ pPayload, &item_count, pfl);
+
+ if (local_fl) db_delete_field_log(pfl);
+
if ( status < 0 ) {
/*
* I cant wait to redesign this protocol from scratch!
*/
if ( ! v41 ) {
/*
- * old client & plain get
+ * old client & plain get
* continue to return an exception
* on failure
*/
- send_err ( &pevext->msg, ECA_GETFAIL, pClient, RECORD_NAME ( paddr ) );
+ send_err ( &pevext->msg, ECA_GETFAIL, pClient, RECORD_NAME ( dbch ) );
}
else {
/* New clients recv the status of the operation directly to the
@@ -598,8 +617,8 @@
}
}
else {
- int cacStatus = caNetConvert (
- pevext->msg.m_dataType, pPayload, pPayload,
+ int cacStatus = caNetConvert (
+ pevext->msg.m_dataType, pPayload, pPayload,
TRUE /* host -> net format */, item_count );
if ( cacStatus == ECA_NORMAL ) {
ca_uint32_t data_size =
@@ -646,6 +665,8 @@
void *pPayload;
int status;
int v41;
+ int local_fl = 0;
+ db_field_log *pfl = NULL;
if ( ! pciu ) {
logBadId ( pClient, mp, 0 );
@@ -655,18 +676,18 @@
SEND_LOCK ( pClient );
if ( INVALID_DB_REQ ( mp->m_dataType ) ) {
- send_err ( mp, ECA_BADTYPE, pClient, RECORD_NAME ( &pciu->addr ) );
+ send_err ( mp, ECA_BADTYPE, pClient, RECORD_NAME ( pciu->dbch ) );
SEND_UNLOCK ( pClient );
return RSRV_ERROR;
}
payloadSize = dbr_size_n ( mp->m_dataType, mp->m_count );
- status = cas_copy_in_header ( pClient, mp->m_cmmd, payloadSize,
+ status = cas_copy_in_header ( pClient, mp->m_cmmd, payloadSize,
mp->m_dataType, mp->m_count, pciu->cid, mp->m_available, &pPayload );
if ( status != ECA_NORMAL ) {
- send_err ( mp, status, pClient,
+ send_err ( mp, status, pClient,
"server unable to load read response into protocol buffer PV=\"%s\" max bytes=%u",
- RECORD_NAME ( &pciu->addr ), rsrvSizeofLargeBufTCP );
+ RECORD_NAME ( pciu->dbch ), rsrvSizeofLargeBufTCP );
SEND_UNLOCK ( pClient );
return RSRV_OK;
}
@@ -682,25 +703,38 @@
else{
status = ECA_GETFAIL;
}
- send_err ( mp, status,
- pClient, RECORD_NAME ( &pciu->addr ) );
+ send_err ( mp, status,
+ pClient, RECORD_NAME ( pciu->dbch ) );
SEND_UNLOCK ( pClient );
return RSRV_OK;
}
- status = db_get_field ( &pciu->addr, mp->m_dataType,
- pPayload, mp->m_count, 0 );
+ /* If filters are involved in a read, create field log and run filters */
+ if (ellCount(&pciu->dbch->pre_chain) || ellCount(&pciu->dbch->post_chain)) {
+ pfl = db_create_read_log(pciu->dbch);
+ if (pfl) {
+ local_fl = 1;
+ pfl = dbChannelRunPreChain(pciu->dbch, pfl);
+ pfl = dbChannelRunPostChain(pciu->dbch, pfl);
+ }
+ }
+
+ status = dbChannel_get ( pciu->dbch, mp->m_dataType,
+ pPayload, mp->m_count, pfl );
+
+ if (local_fl) db_delete_field_log(pfl);
+
if ( status < 0 ) {
- send_err ( mp, ECA_GETFAIL, pClient, RECORD_NAME ( &pciu->addr ) );
+ send_err ( mp, ECA_GETFAIL, pClient, RECORD_NAME ( pciu->dbch ) );
SEND_UNLOCK ( pClient );
return RSRV_OK;
}
- status = caNetConvert (
- mp->m_dataType, pPayload, pPayload,
+ status = caNetConvert (
+ mp->m_dataType, pPayload, pPayload,
TRUE /* host -> net format */, mp->m_count );
if ( status != ECA_NORMAL ) {
- send_err ( mp, status, pClient, RECORD_NAME ( &pciu->addr ) );
+ send_err ( mp, status, pClient, RECORD_NAME ( pciu->dbch ) );
SEND_UNLOCK ( pClient );
return RSRV_OK;
}
@@ -717,7 +751,7 @@
}
else {
pStr[payloadSize-1] = '\0';
- errlogPrintf (
+ errlogPrintf (
"caserver: read_action: detected DBR_STRING w/o nill termination "
"in response from db_get_field, pPayload = \"%s\"\n",
pStr );
@@ -754,11 +788,11 @@
* favor of the standard db event calling
* mechanism- routine(userarg, paddr). See
* events added above.
- *
+ *
* Hold argument set true so the send message
* buffer is not flushed once each call.
*/
- read_reply ( &evext, &pciu->addr, TRUE, NULL );
+ read_reply ( &evext, pciu->dbch, TRUE, NULL );
return RSRV_OK;
}
@@ -766,7 +800,7 @@
/*
* write_action()
*/
-static int write_action ( caHdrLargeArray *mp,
+static int write_action ( caHdrLargeArray *mp,
void *pPayload, struct client *client )
{
struct channel_in_use *pciu;
@@ -791,25 +825,25 @@
}
SEND_LOCK(client);
send_err(
- mp,
- status,
- client,
- RECORD_NAME(&pciu->addr));
+ mp,
+ status,
+ client,
+ RECORD_NAME ( pciu->dbch ));
SEND_UNLOCK(client);
return RSRV_OK;
}
- status = caNetConvert (
- mp->m_dataType, pPayload, pPayload,
+ status = caNetConvert (
+ mp->m_dataType, pPayload, pPayload,
FALSE /* net -> host format */, mp->m_count );
if ( status != ECA_NORMAL ) {
log_header ("invalid data type", client, mp, pPayload, 0);
SEND_LOCK(client);
send_err(
- mp,
- status,
- client,
- RECORD_NAME(&pciu->addr));
+ mp,
+ status,
+ client,
+ RECORD_NAME ( pciu->dbch ));
SEND_UNLOCK(client);
return RSRV_ERROR;
}
@@ -817,10 +851,10 @@
asWritePvt = asTrapWriteBefore ( pciu->asClientPVT,
pciu->client->pUserName ? pciu->client->pUserName : "",
pciu->client->pHostName ? pciu->client->pHostName : "",
- (void *) &pciu->addr );
+ pciu->dbch );
- dbStatus = db_put_field(
- &pciu->addr,
+ dbStatus = dbChannel_put(
+ pciu->dbch,
mp->m_dataType,
pPayload,
mp->m_count);
@@ -830,10 +864,10 @@
if (dbStatus < 0) {
SEND_LOCK(client);
send_err(
- mp,
- ECA_PUTFAIL,
- client,
- RECORD_NAME(&pciu->addr));
+ mp,
+ ECA_PUTFAIL,
+ client,
+ RECORD_NAME ( pciu->dbch ));
SEND_UNLOCK(client);
}
@@ -852,8 +886,8 @@
int chanCount;
epicsMutexMustLock ( client->chanListLock );
- chanCount =
- ellCount ( &client->chanList ) +
+ chanCount =
+ ellCount ( &client->chanList ) +
ellCount ( &client->chanPendingUpdateARList );
epicsMutexUnlock( client->chanListLock );
@@ -872,13 +906,13 @@
pName = (char *) pPayload;
size = strlen(pName)+1;
if (size > 512) {
- log_header ( "bad (very long) host name",
+ log_header ( "bad (very long) host name",
client, mp, pPayload, 0 );
SEND_LOCK(client);
send_err(
- mp,
- ECA_INTERNAL,
- client,
+ mp,
+ ECA_INTERNAL,
+ client,
"bad (very long) host name");
SEND_UNLOCK(client);
return RSRV_ERROR;
@@ -889,7 +923,7 @@
*/
pMalloc = malloc(size);
if(!pMalloc){
- log_header ( "no space in pool for new host name",
+ log_header ( "no space in pool for new host name",
client, mp, pPayload, 0 );
SEND_LOCK(client);
send_err(
@@ -901,8 +935,8 @@
return RSRV_ERROR;
}
strncpy(
- pMalloc,
- pName,
+ pMalloc,
+ pName,
size-1);
pMalloc[size-1]='\0';
@@ -912,13 +946,13 @@
free ( pName );
}
- DLOG (2, ( "CAS: host_name_action for \"%s\"\n",
+ DLOG (2, ( "CAS: host_name_action for \"%s\"\n",
client->pHostName ? client->pHostName : "" ) );
return RSRV_OK;
}
-
+
/*
* client_name_action()
*/
@@ -931,8 +965,8 @@
int chanCount;
epicsMutexMustLock ( client->chanListLock );
- chanCount =
- ellCount ( &client->chanList ) +
+ chanCount =
+ ellCount ( &client->chanList ) +
ellCount ( &client->chanPendingUpdateARList );
epicsMutexUnlock( client->chanListLock );
@@ -951,13 +985,13 @@
pName = (char *) pPayload;
size = strlen(pName)+1;
if (size > 512) {
- log_header ("a very long user name was specified",
+ log_header ("a very long user name was specified",
client, mp, pPayload, 0);
SEND_LOCK(client);
send_err(
- mp,
- ECA_INTERNAL,
- client,
+ mp,
+ ECA_INTERNAL,
+ client,
"a very long user name was specified");
SEND_UNLOCK(client);
return RSRV_ERROR;
@@ -968,7 +1002,7 @@
*/
pMalloc = malloc(size);
if(!pMalloc){
- log_header ("no memory for new user name",
+ log_header ("no memory for new user name",
client, mp, pPayload, 0);
SEND_LOCK(client);
send_err(
@@ -980,8 +1014,8 @@
return RSRV_ERROR;
}
strncpy(
- pMalloc,
- pName,
+ pMalloc,
+ pName,
size-1);
pMalloc[size-1]='\0';
@@ -999,7 +1033,7 @@
*/
static struct channel_in_use *casCreateChannel (
struct client *client,
-struct dbAddr *pAddr,
+struct dbChannel *dbch,
unsigned cid
)
{
@@ -1009,14 +1043,14 @@
int status;
/* get block off free list if possible */
- pchannel = (struct channel_in_use *)
+ pchannel = (struct channel_in_use *)
freeListCalloc(rsrvChanFreeList);
if (!pchannel) {
return NULL;
}
ellInit(&pchannel->eventq);
epicsTimeGetCurrent(&pchannel->time_at_creation);
- pchannel->addr = *pAddr;
+ pchannel->dbch = dbch;
pchannel->client = client;
/*
* bypass read only warning
@@ -1046,8 +1080,8 @@
* Verify that this id is not in use
*/
status = bucketAddItemUnsignedId (
- pCaBucket,
- &pchannel->sid,
+ pCaBucket,
+ &pchannel->sid,
pchannel);
} while (status == S_bucket_idInUse);
@@ -1116,7 +1150,7 @@
epicsMutexUnlock ( pclient->chanListLock );
/*
- * Update all event call backs
+ * Update all event call backs
*/
epicsMutexMustLock(pclient->eventqLock);
for (pevext = (struct event_ext *) ellFirst(&pciu->eventq);
@@ -1175,8 +1209,8 @@
}
SEND_LOCK ( pciu->client );
- status = cas_copy_in_header (
- pciu->client, CA_PROTO_ACCESS_RIGHTS, 0,
+ status = cas_copy_in_header (
+ pciu->client, CA_PROTO_ACCESS_RIGHTS, 0,
0, 0, pciu->cid, ar, 0 );
/*
* OK to just ignore the request if the connection drops
@@ -1197,26 +1231,28 @@
if ( v42 ) {
int status;
ca_uint32_t nElem;
+ long dbElem;
SEND_LOCK ( pciu->client );
- if ( pciu->addr.no_elements < 0 ) {
+ dbElem = dbChannelFinalElements(pciu->dbch);
+ if ( dbElem < 0 ) {
nElem = 0;
}
else {
if ( ! CA_V49 ( pciu->client->minor_version_number ) ) {
- if ( pciu->addr.no_elements >= 0xffff ) {
+ if ( dbElem >= 0xffff ) {
nElem = 0xfffe;
}
else {
- nElem = (ca_uint32_t) pciu->addr.no_elements;
+ nElem = (ca_uint32_t) dbElem;
}
}
else {
- nElem = (ca_uint32_t) pciu->addr.no_elements;
+ nElem = (ca_uint32_t) dbElem;
}
}
- status = cas_copy_in_header (
+ status = cas_copy_in_header (
pciu->client, CA_PROTO_CREATE_CHAN, 0u,
- pciu->addr.dbr_field_type, nElem, pciu->cid,
+ dbChannelFinalExportType(pciu->dbch), nElem, pciu->cid,
pciu->sid, NULL );
if ( status == ECA_NORMAL ) {
cas_commit_msg ( pciu->client, 0u );
@@ -1228,7 +1264,7 @@
/*
* claim_ciu_action()
*/
-static int claim_ciu_action ( caHdrLargeArray *mp,
+static int claim_ciu_action ( caHdrLargeArray *mp,
void *pPayload, client *client )
{
int status;
@@ -1243,47 +1279,48 @@
client->minor_version_number = mp->m_available;
if (CA_V44(client->minor_version_number)) {
- struct dbAddr tmp_addr;
+ struct dbChannel *dbch;
char *pName = (char *) pPayload;
/*
* check the sanity of the message
*/
if (mp->m_postsize<=1) {
- log_header ( "empty PV name in UDP search request?",
+ log_header ( "empty PV name in UDP search request?",
client, mp, pPayload, 0 );
return RSRV_OK;
}
pName[mp->m_postsize-1] = '\0';
- status = db_name_to_addr (pName, &tmp_addr);
- if (status) {
+ dbch = dbChannel_create (pName);
+ if (!dbch) {
return RSRV_OK;
}
- DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %d\n",
- pName, tmp_addr.dbr_field_type, tmp_addr.no_elements) );
-
+ DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %d\n",
+ pName, dbChannelExportType(dbch), dbChannelElements(dbch)) );
+
pciu = casCreateChannel (
- client,
- &tmp_addr,
+ client,
+ dbch,
mp->m_cid);
if (!pciu) {
- log_header ("no memory to create new channel",
+ log_header ("no memory to create new channel",
client, mp, pPayload, 0);
SEND_LOCK(client);
- send_err(mp,
- ECA_ALLOCMEM,
- client,
- RECORD_NAME(&tmp_addr));
+ send_err(mp,
+ ECA_ALLOCMEM,
+ client,
+ RECORD_NAME(dbch));
SEND_UNLOCK(client);
+ dbChannelDelete(dbch);
return RSRV_ERROR;
}
}
else {
epicsMutexMustLock(prsrv_cast_client->chanListLock);
/*
- * clients which dont claim their
+ * clients which dont claim their
* channel in use block prior to
* timeout must reconnect
*/
@@ -1302,8 +1339,8 @@
return RSRV_ERROR;
}
- /*
- * duplicate claim message are unacceptable
+ /*
+ * duplicate claim message are unacceptable
* (so we disconnect the client)
*/
if (pciu->client!=prsrv_cast_client) {
@@ -1327,7 +1364,7 @@
* who is claiming it
*/
ellDelete(
- &prsrv_cast_client->chanList,
+ &prsrv_cast_client->chanList,
&pciu->node);
epicsMutexUnlock(prsrv_cast_client->chanListLock);
@@ -1343,12 +1380,12 @@
*/
status = asAddClient(
&pciu->asClientPVT,
- asDbGetMemberPvt(&pciu->addr),
- asDbGetAsl(&pciu->addr),
+ asDbGetMemberPvt(pciu->dbch),
+ asDbGetAsl(pciu->dbch),
client->pUserName ? client->pUserName : "",
- client->pHostName ? client->pHostName : "");
+ client->pHostName ? client->pHostName : "");
if(status != 0 && status != S_asLib_asNotActive){
- log_header ("No room for security table",
+ log_header ("No room for security table",
client, mp, pPayload, 0);
SEND_LOCK(client);
send_err(mp, ECA_ALLOCMEM, client, "No room for security table");
@@ -1357,7 +1394,7 @@
}
/*
- * store ptr to channel in use block
+ * store ptr to channel in use block
* in access security private
*/
asPutClientPvt(pciu->asClientPVT, pciu);
@@ -1366,7 +1403,7 @@
* register for asynch updates of access rights changes
*/
status = asRegisterClientCallback(
- pciu->asClientPVT,
+ pciu->asClientPVT,
casAccessRightsCB);
if ( status == S_asLib_asNotActive ) {
epicsMutexMustLock ( client->chanListLock );
@@ -1378,10 +1415,10 @@
claim_ciu_reply ( pciu );
}
else if (status!=0) {
- log_header ("No room for access security state change subscription",
+ log_header ("No room for access security state change subscription",
client, mp, pPayload, 0);
SEND_LOCK(client);
- send_err(mp, ECA_ALLOCMEM, client,
+ send_err(mp, ECA_ALLOCMEM, client,
"No room for access security state change subscription");
SEND_UNLOCK(client);
return RSRV_ERROR;
@@ -1429,7 +1466,7 @@
db_post_extra_labor(pClient->evuser);
}
-/*
+/*
* write_notify_reply()
* (called by the CA server event task via the extra labor interface)
*/
@@ -1477,18 +1514,18 @@
asTrapWriteAfter ( asWritePvtTmp );
/*
- * the channel id field is being abused to carry
+ * the channel id field is being abused to carry
* status here
*/
SEND_LOCK(pClient);
- localStatus = cas_copy_in_header (
- pClient, CA_PROTO_WRITE_NOTIFY,
- 0u, msgtmp.m_dataType, msgtmp.m_count, status,
+ localStatus = cas_copy_in_header (
+ pClient, CA_PROTO_WRITE_NOTIFY,
+ 0u, msgtmp.m_dataType, msgtmp.m_count, status,
msgtmp.m_available, 0 );
if ( localStatus != ECA_NORMAL ) {
/*
* inability to aquire buffer space
- * Indicates corruption
+ * Indicates corruption
*/
errlogPrintf("CA server corrupted - put call back(s) discarded\n");
SEND_UNLOCK ( pClient );
@@ -1511,11 +1548,11 @@
*/
static void sendAllUpdateAS ( struct client *client )
{
- struct channel_in_use *pciu;
+ struct channel_in_use *pciu;
epicsMutexMustLock ( client->chanListLock );
- pciu = ( struct channel_in_use * )
+ pciu = ( struct channel_in_use * )
ellGet ( & client->chanPendingUpdateARList );
while ( pciu ) {
if ( pciu->state == rsrvCS_pendConnectRespUpdatePendAR ) {
@@ -1531,14 +1568,14 @@
}
pciu->state = rsrvCS_inService;
ellAdd ( & client->chanList, & pciu->node );
- pciu = ( struct channel_in_use * )
+ pciu = ( struct channel_in_use * )
ellGet ( & client->chanPendingUpdateARList );
}
epicsMutexUnlock( client->chanListLock );
}
-/*
+/*
* rsrv_extra_labor()
* (called by the CA server event task via the extra labor interface)
*/
@@ -1562,8 +1599,8 @@
* the cid field abused to contain status
* during put cb replies
*/
- status = cas_copy_in_header ( client, CA_PROTO_WRITE_NOTIFY,
- 0u, mp->m_dataType, mp->m_count, statusCA,
+ status = cas_copy_in_header ( client, CA_PROTO_WRITE_NOTIFY,
+ 0u, mp->m_dataType, mp->m_count, statusCA,
mp->m_available, 0 );
if ( status != ECA_NORMAL ) {
SEND_UNLOCK ( client );
@@ -1578,28 +1615,28 @@
void initializePutNotifyFreeList (void)
{
if ( ! rsrvPutNotifyFreeList ) {
- freeListInitPvt ( &rsrvPutNotifyFreeList,
+ freeListInitPvt ( &rsrvPutNotifyFreeList,
sizeof(struct rsrv_put_notify), 512 );
assert ( rsrvPutNotifyFreeList );
}
}
-static struct rsrv_put_notify *
+static struct rsrv_put_notify *
rsrvAllocPutNotify ( struct channel_in_use * pciu )
{
struct rsrv_put_notify *pNotify;
-
+
if ( rsrvPutNotifyFreeList ) {
pNotify = (RSRVPUTNOTIFY *)
freeListCalloc ( rsrvPutNotifyFreeList );
if ( pNotify ) {
- pNotify->dbPutNotify.pbuffer =
+ pNotify->dbPutNotify.pbuffer =
&pNotify->dbrScalarValue;
- pNotify->valueSize =
+ pNotify->valueSize =
sizeof (pNotify->dbrScalarValue);
pNotify->dbPutNotify.usrPvt = pciu;
- pNotify->dbPutNotify.paddr = &pciu->addr;
- pNotify->dbPutNotify.userCallback =
+ pNotify->dbPutNotify.chan = pciu->dbch;
+ pNotify->dbPutNotify.userCallback =
write_notify_call_back;
}
}
@@ -1609,18 +1646,18 @@
return pNotify;
}
-static int rsrvExpandPutNotify (
+static int rsrvExpandPutNotify (
struct rsrv_put_notify * pNotify, unsigned sizeNeeded )
{
int booleanStatus;
-
+
if ( sizeNeeded > pNotify->valueSize ) {
/*
- * try to use the union embeded in the free list
- * item, but allocate a random sized block if they
+ * try to use the union embeded in the free list
+ * item, but allocate a random sized block if they
* writing a vector.
*/
- if ( pNotify->valueSize >
+ if ( pNotify->valueSize >
sizeof (pNotify->dbrScalarValue) ) {
free ( pNotify->dbPutNotify.pbuffer );
}
@@ -1633,9 +1670,9 @@
/*
* revert back to the embedded union
*/
- pNotify->dbPutNotify.pbuffer =
+ pNotify->dbPutNotify.pbuffer =
&pNotify->dbrScalarValue;
- pNotify->valueSize =
+ pNotify->valueSize =
sizeof (pNotify->dbrScalarValue);
booleanStatus = FALSE;
}
@@ -1643,7 +1680,7 @@
else {
booleanStatus = TRUE;
}
-
+
return booleanStatus;
}
@@ -1651,7 +1688,7 @@
{
unsigned size = sizeof ( *pNotify );
if ( pNotify ) {
- if ( pNotify->valueSize >
+ if ( pNotify->valueSize >
sizeof ( pNotify->dbrScalarValue ) ) {
size += pNotify->valueSize;
}
@@ -1659,7 +1696,7 @@
return size;
}
-void rsrvFreePutNotify ( client *pClient,
+void rsrvFreePutNotify ( client *pClient,
struct rsrv_put_notify *pNotify )
{
if ( pNotify ) {
@@ -1671,16 +1708,16 @@
epicsMutexUnlock ( pClient->putNotifyLock );
/*
- * if any possiblity that the put notify is
+ * if any possiblity that the put notify is
* outstanding then cancel it
*/
if ( busyTmp ) {
dbNotifyCancel ( &pNotify->dbPutNotify );
- }
+ }
epicsMutexMustLock ( pClient->putNotifyLock );
if ( pNotify->onExtraLaborQueue ) {
- ellDelete ( &pClient->putNotifyQue,
+ ellDelete ( &pClient->putNotifyQue,
&pNotify->node );
}
busyTmp = pNotify->busy;
@@ -1692,7 +1729,7 @@
asTrapWriteAfter ( asWritePvtTmp );
}
- if ( pNotify->valueSize >
+ if ( pNotify->valueSize >
sizeof(pNotify->dbrScalarValue) ) {
free ( pNotify->dbPutNotify.pbuffer );
}
@@ -1703,7 +1740,7 @@
/*
* write_notify_action()
*/
-static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
+static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
struct client *client )
{
unsigned size;
@@ -1732,7 +1769,7 @@
if ( pciu->pPutNotify ) {
/*
- * serialize concurrent put notifies
+ * serialize concurrent put notifies
*/
epicsMutexMustLock(client->putNotifyLock);
while(pciu->pPutNotify->busy){
@@ -1757,7 +1794,7 @@
busyTmp = pciu->pPutNotify->busy;
if ( busyTmp ) {
if ( pciu->pPutNotify->onExtraLaborQueue ) {
- ellDelete ( &client->putNotifyQue,
+ ellDelete ( &client->putNotifyQue,
&pciu->pPutNotify->node );
}
pciu->pPutNotify->busy = FALSE;
@@ -1765,9 +1802,9 @@
pciu->pPutNotify->asWritePvt = 0;
}
epicsMutexUnlock(client->putNotifyLock);
-
+
if ( busyTmp ) {
- log_header("put call back time out", client,
+ log_header("put call back time out", client,
&pciu->pPutNotify->msg, pciu->pPutNotify->dbPutNotify.pbuffer, 0);
asTrapWriteAfter ( asWritePvtTmp );
putNotifyErrorReply (client, &pciu->pPutNotify->msg, ECA_PUTCBINPROG);
@@ -1784,15 +1821,15 @@
* send error and go to next request
* if there isnt enough memory left
*/
- log_header ( "no memory to initiate put notify",
+ log_header ( "no memory to initiate put notify",
client, mp, pPayload, 0 );
putNotifyErrorReply (client, mp, ECA_ALLOCMEM);
return RSRV_ERROR;
}
}
-
+
if ( ! rsrvExpandPutNotify ( pciu->pPutNotify, size ) ) {
- log_header ( "no memory to initiate vector put notify",
+ log_header ( "no memory to initiate vector put notify",
client, mp, pPayload, 0 );
putNotifyErrorReply ( client, mp, ECA_ALLOCMEM );
return RSRV_ERROR;
@@ -1803,8 +1840,8 @@
pciu->pPutNotify->msg = *mp;
pciu->pPutNotify->dbPutNotify.nRequest = mp->m_count;
- status = caNetConvert (
- mp->m_dataType, pPayload, pciu->pPutNotify->dbPutNotify.pbuffer,
+ status = caNetConvert (
+ mp->m_dataType, pPayload, pciu->pPutNotify->dbPutNotify.pbuffer,
FALSE /* net -> host format */, mp->m_count );
if ( status != ECA_NORMAL ) {
log_header ("invalid data type", client, mp, pPayload, 0);
@@ -1819,11 +1856,11 @@
return RSRV_OK;
}
- pciu->pPutNotify->asWritePvt = asTrapWriteBefore (
+ pciu->pPutNotify->asWritePvt = asTrapWriteBefore (
pciu->asClientPVT,
pciu->client->pUserName ? pciu->client->pUserName : "",
pciu->client->pHostName ? pciu->client->pHostName : "",
- (void *) &pciu->addr );
+ pciu->dbch );
dbPutNotify(&pciu->pPutNotify->dbPutNotify);
@@ -1849,10 +1886,10 @@
}
/*
- * stop further use of server if memory becomes scarse
+ * stop further use of server if memory becomes scarce
*/
spaceAvailOnFreeList = freeListItemsAvail ( rsrvEventFreeList ) > 0;
- if ( osiSufficentSpaceInPool(sizeof(*pevext)) || spaceAvailOnFreeList ) {
+ if ( osiSufficentSpaceInPool(sizeof(*pevext)) || spaceAvailOnFreeList ) {
pevext = (struct event_ext *) freeListCalloc (rsrvEventFreeList);
}
else {
@@ -1860,14 +1897,14 @@
}
if (!pevext) {
- log_header ("no memory to add subscription",
+ log_header ("no memory to add subscription",
client, mp, pPayload, 0);
SEND_LOCK(client);
send_err(
mp,
- ECA_ALLOCMEM,
- client,
- RECORD_NAME(&pciu->addr));
+ ECA_ALLOCMEM,
+ client,
+ RECORD_NAME(pciu->dbch));
SEND_UNLOCK(client);
return RSRV_ERROR;
}
@@ -1881,15 +1918,15 @@
ellAdd( &pciu->eventq, &pevext->node);
epicsMutexUnlock(client->eventqLock);
- pevext->pdbev = db_add_event (client->evuser, &pciu->addr,
+ pevext->pdbev = db_add_event (client->evuser, pciu->dbch,
read_reply, pevext, pevext->mask);
if (pevext->pdbev == NULL) {
- log_header ("no memory to add subscription to db",
+ log_header ("no memory to add subscription to db",
client, mp, pPayload, 0);
SEND_LOCK(client);
- send_err (mp, ECA_ALLOCMEM, client,
- "subscription install into record %s failed",
- RECORD_NAME(&pciu->addr));
+ send_err (mp, ECA_ALLOCMEM, client,
+ "subscription install into record %s failed",
+ RECORD_NAME(pciu->dbch));
SEND_UNLOCK(client);
return RSRV_ERROR;
}
@@ -1903,7 +1940,7 @@
* of the socket would block. This prevents
* a application program initiated deadlock.
*
- * However when I am reconnecting I reissue
+ * However when I am reconnecting I reissue
* the monitors and I could get deadlocked.
* The client is blocked sending and the server
* task for the client is blocked sending in
@@ -1914,7 +1951,7 @@
* post_single_event() below instead of calling
* read_reply() in this module. This is a complete
* fix since a monitor setup is the only request
- * soliciting a reply in the client which is
+ * soliciting a reply in the client which is
* issued from inside of service.c (from inside
* of the part of the ca client which services
* messages sent by the server).
@@ -1940,13 +1977,13 @@
/*
* clear_channel_reply()
*/
-static int clear_channel_reply ( caHdrLargeArray *mp,
+static int clear_channel_reply ( caHdrLargeArray *mp,
void *pPayload, struct client *client )
{
struct event_ext *pevext;
struct channel_in_use *pciu;
int status;
-
+
/*
*
* Verify the channel
@@ -1957,43 +1994,43 @@
logBadId ( client, mp, pPayload );
return RSRV_ERROR;
}
-
+
rsrvFreePutNotify ( client, pciu->pPutNotify );
-
+
while (TRUE){
epicsMutexMustLock(client->eventqLock);
pevext = (struct event_ext *) ellGet(&pciu->eventq);
epicsMutexUnlock(client->eventqLock);
-
+
if(!pevext){
break;
}
-
+
if (pevext->pdbev) {
db_cancel_event (pevext->pdbev);
}
freeListFree(rsrvEventFreeList, pevext);
}
-
+
db_flush_extra_labor_event ( client->evuser );
-
+
/*
* send delete confirmed message
*/
SEND_LOCK(client);
- status = cas_copy_in_header ( client, CA_PROTO_CLEAR_CHANNEL,
- 0u, mp->m_dataType, mp->m_count, mp->m_cid,
+ status = cas_copy_in_header ( client, CA_PROTO_CLEAR_CHANNEL,
+ 0u, mp->m_dataType, mp->m_count, mp->m_cid,
mp->m_available, NULL );
if ( status != ECA_NORMAL ) {
SEND_UNLOCK(client);
return RSRV_ERROR;
}
-
+
cas_commit_msg ( client, 0u );
SEND_UNLOCK(client);
-
+
epicsMutexMustLock ( client->chanListLock );
- if ( pciu->state == rsrvCS_inService ||
+ if ( pciu->state == rsrvCS_inService ||
pciu->state == rsrvCS_pendConnectResp ) {
ellDelete ( &client->chanList, &pciu->node );
}
@@ -2004,22 +2041,22 @@
else {
epicsMutexUnlock( client->chanListLock );
SEND_LOCK(client);
- send_err(mp, ECA_INTERNAL, client,
+ send_err(mp, ECA_INTERNAL, client,
"channel was in strange state or corrupted during cleanup");
SEND_UNLOCK(client);
return RSRV_ERROR;
}
epicsMutexUnlock( client->chanListLock );
-
+
/*
* remove from access control list
*/
status = asRemoveClient(&pciu->asClientPVT);
if(status != 0 && status != S_asLib_asNotActive){
- errMessage(status, RECORD_NAME(&pciu->addr));
+ errMessage(status, RECORD_NAME(pciu->dbch));
return RSRV_ERROR;
}
-
+
LOCK_CLIENTQ;
status = bucketRemoveItemUnsignedId (pCaBucket, &pciu->sid);
if(status != S_bucket_success){
@@ -2031,11 +2068,12 @@
rsrvChannelCount--;
UNLOCK_CLIENTQ;
+ dbChannelDelete(pciu->dbch);
freeListFree(rsrvChanFreeList, pciu);
-
+
return RSRV_OK;
}
-
+
/*
*
* event_cancel_reply()
@@ -2049,7 +2087,7 @@
struct channel_in_use *pciu;
struct event_ext *pevext;
int status;
-
+
/*
*
* Verify the channel
@@ -2060,7 +2098,7 @@
logBadId ( client, mp, pPayload );
return RSRV_ERROR;
}
-
+
/*
* search events on this channel for a match
* (there are usually very few monitors per channel)
@@ -2068,38 +2106,38 @@
epicsMutexMustLock(client->eventqLock);
for (pevext = (struct event_ext *) ellFirst(&pciu->eventq);
pevext; pevext = (struct event_ext *) ellNext(&pevext->node)){
-
+
if (pevext->msg.m_available == mp->m_available) {
ellDelete(&pciu->eventq, &pevext->node);
break;
}
}
epicsMutexUnlock(client->eventqLock);
-
+
/*
- * Not Found- return an exception event
+ * Not Found- return an exception event
*/
if(!pevext){
SEND_LOCK(client);
- send_err(mp, ECA_BADMONID, client, RECORD_NAME(&pciu->addr));
+ send_err(mp, ECA_BADMONID, client, RECORD_NAME(pciu->dbch));
SEND_UNLOCK(client);
return RSRV_ERROR;
}
-
+
/*
* cancel monitor activity in progress
*/
if (pevext->pdbev) {
db_cancel_event (pevext->pdbev);
}
-
+
/*
* send delete confirmed message
*/
SEND_LOCK(client);
- status = cas_copy_in_header ( client, pevext->msg.m_cmmd,
- 0u, pevext->msg.m_dataType, pevext->msg.m_count, pevext->msg.m_cid,
+ status = cas_copy_in_header ( client, pevext->msg.m_cmmd,
+ 0u, pevext->msg.m_dataType, pevext->msg.m_count, pevext->msg.m_cid,
pevext->msg.m_available, NULL );
if ( status != ECA_NORMAL ) {
SEND_UNLOCK(client);
@@ -2107,7 +2145,7 @@
}
cas_commit_msg ( client, 0 );
SEND_UNLOCK(client);
-
+
freeListFree (rsrvEventFreeList, pevext);
return RSRV_OK;
@@ -2120,8 +2158,8 @@
{
int status;
SEND_LOCK(client);
- status = cas_copy_in_header ( client, mp->m_cmmd,
- 0u, mp->m_dataType, mp->m_count, mp->m_cid,
+ status = cas_copy_in_header ( client, mp->m_cmmd,
+ 0u, mp->m_dataType, mp->m_count, mp->m_cid,
mp->m_available, NULL );
if ( status != ECA_NORMAL ) {
SEND_UNLOCK(client);
@@ -2132,17 +2170,17 @@
return RSRV_OK;
}
-/*
+/*
* search_fail_reply()
*
- * Only when requested by the client
+ * Only when requested by the client
* send search failed reply
*/
static void search_fail_reply ( caHdrLargeArray *mp, void *pPayload, struct client *client)
{
int status;
SEND_LOCK ( client );
- status = cas_copy_in_header ( client, CA_PROTO_NOT_FOUND,
+ status = cas_copy_in_header ( client, CA_PROTO_NOT_FOUND,
0u, mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available, NULL );
if ( status != ECA_NORMAL ) {
SEND_UNLOCK ( client );
@@ -2180,16 +2218,16 @@
SEND_LOCK ( client );
/*
* sequence number is specified zero when we copy in the
- * header because we dont know it until we receive a datagram
+ * header because we dont know it until we receive a datagram
* from the client
*/
- status = cas_copy_in_header ( client, CA_PROTO_VERSION,
- 0, 0, CA_MINOR_PROTOCOL_REVISION,
+ status = cas_copy_in_header ( client, CA_PROTO_VERSION,
+ 0, 0, CA_MINOR_PROTOCOL_REVISION,
0, 0, 0 );
if ( status != ECA_NORMAL ) {
SEND_UNLOCK ( client );
return RSRV_ERROR;
- }
+ }
cas_commit_msg ( client, 0 );
SEND_UNLOCK ( client );
return RSRV_OK;
@@ -2200,7 +2238,6 @@
*/
static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client *client )
{
- struct dbAddr tmp_addr;
ca_uint16_t *pMinorVersion;
char *pName = (char *) pPayload;
int status;
@@ -2215,41 +2252,41 @@
* check the sanity of the message
*/
if (mp->m_postsize<=1) {
- log_header ("empty PV name in UDP search request?",
+ log_header ("empty PV name in UDP search request?",
client, mp, pPayload, 0);
return RSRV_OK;
}
pName[mp->m_postsize-1] = '\0';
-
+
/* Exit quickly if channel not on this node */
- status = db_name_to_addr (pName, &tmp_addr);
- if (status) {
+ if (dbChannelTest(pName)) {
DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pPayLoad ) );
if (mp->m_dataType == DOREPLY)
search_fail_reply ( mp, pPayload, client );
return RSRV_OK;
}
-
+
/*
- * stop further use of server if memory becomes scarse
+ * stop further use of server if memory becomes scarce
*/
spaceAvailOnFreeList = freeListItemsAvail ( rsrvChanFreeList ) > 0
&& freeListItemsAvail ( rsrvEventFreeList ) > reasonableMonitorSpace;
- spaceNeeded = sizeof (struct channel_in_use) +
+ spaceNeeded = sizeof (struct channel_in_use) +
reasonableMonitorSpace * sizeof (struct event_ext);
- if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
+ if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
SEND_LOCK(client);
send_err ( mp, ECA_ALLOCMEM, client, "Server memory exhausted" );
SEND_UNLOCK(client);
return RSRV_OK;
}
-
+
/*
* starting with V4.4 the count field is used (abused)
* to store the minor version number of the client.
*
* New versions dont alloc the channel in response
* to a search request.
+ * For these, allocation has been moved to claim_ciu_action().
*
* m_count, m_cid are already in host format...
*/
@@ -2259,49 +2296,58 @@
type = ca_server_port;
}
else {
+ struct dbChannel *dbch;
struct channel_in_use *pchannel;
-
- pchannel = casCreateChannel ( client, &tmp_addr, mp->m_cid );
+
+ dbch = dbChannel_create(pName);
+ if (!dbch) {
+ DLOG ( 2, ( "CAS: dbChannel Test of \"%s\" OK but Create failed\n", pName ) );
+ if (mp->m_dataType == DOREPLY)
+ search_fail_reply ( mp, pPayload, client );
+ return RSRV_OK;
+ }
+ pchannel = casCreateChannel ( client, dbch, mp->m_cid );
if (!pchannel) {
SEND_LOCK(client);
- send_err ( mp, ECA_ALLOCMEM, client,
- RECORD_NAME ( &tmp_addr ) );
+ send_err ( mp, ECA_ALLOCMEM, client,
+ RECORD_NAME ( dbch ) );
SEND_UNLOCK ( client );
+ dbChannelDelete(dbch);
return RSRV_OK;
}
sid = pchannel->sid;
- if ( tmp_addr.no_elements < 0 ) {
+ if ( dbChannelFinalElements(dbch) < 0 ) {
count = 0;
}
- else if ( tmp_addr.no_elements > 0xffff ) {
+ else if ( dbChannelFinalElements(dbch) > 0xffff ) {
count = 0xfffe;
}
else {
- count = (ca_uint16_t) tmp_addr.no_elements;
+ count = (ca_uint16_t) dbChannelFinalElements(dbch);
}
- type = (ca_uint16_t) tmp_addr.dbr_field_type;
+ type = (ca_uint16_t) dbChannelFinalExportType(dbch);
}
-
+
SEND_LOCK ( client );
- status = cas_copy_in_header ( client, CA_PROTO_SEARCH,
- sizeof(*pMinorVersion), type, count,
- sid, mp->m_available,
+ status = cas_copy_in_header ( client, CA_PROTO_SEARCH,
+ sizeof(*pMinorVersion), type, count,
+ sid, mp->m_available,
( void * ) &pMinorVersion );
if ( status != ECA_NORMAL ) {
SEND_UNLOCK ( client );
return RSRV_ERROR;
}
-
+
/*
* Starting with CA V4.1 the minor version number
* is appended to the end of each search reply.
- * This value is ignored by earlier clients.
+ * This value is ignored by earlier clients.
*/
*pMinorVersion = htons ( CA_MINOR_PROTOCOL_REVISION );
-
+
cas_commit_msg ( client, sizeof ( *pMinorVersion ) );
SEND_UNLOCK ( client );
-
+
return RSRV_OK;
}
@@ -2311,7 +2357,6 @@
static int search_reply_tcp (
caHdrLargeArray *mp, void *pPayload, struct client *client )
{
- struct dbAddr tmp_addr;
char *pName = (char *) pPayload;
int status;
int spaceAvailOnFreeList;
@@ -2329,8 +2374,7 @@
pName[mp->m_postsize-1] = '\0';
/* Exit quickly if channel not on this node */
- status = db_name_to_addr (pName, &tmp_addr);
- if (status) {
+ if (dbChannelTest(pName)) {
DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pPayLoad ) );
- Replies:
- Re: [Merge] lp:~epics-core/epics-base/server-side-plugins into lp:epics-base Andrew Johnson
- [Merge] lp:~epics-core/epics-base/server-side-plugins into lp:epics-base noreply
- Navigate by Date:
- Prev:
Re: R3.15.0 deadline approaching Michael Davidsaver
- Next:
[Merge] lp:~epics-core/epics-base/thread-pool into lp:epics-base mdavidsaver
- 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:
Re: R3.15.0 deadline approaching Michael Davidsaver
- Next:
Re: [Merge] lp:~epics-core/epics-base/server-side-plugins into lp:epics-base Andrew Johnson
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
<2012>
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024