Merged the db-test branch.
Also made additional changes: * Simplified xRecord.c so it can run on vxWorks. * Standard way to load DBD and DB files in tests All test harnesses now run on vxWorks (but some tests still fail).
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include <dbStaticLib.h>
|
||||
#include <epicsTypes.h>
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsStdlib.h>
|
||||
#include <epicsString.h>
|
||||
#include <errlog.h>
|
||||
#include <shareLib.h>
|
||||
@@ -29,13 +30,6 @@
|
||||
#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
|
||||
*/
|
||||
@@ -65,10 +59,11 @@ typedef enum chfPluginType {
|
||||
} chfPluginType;
|
||||
|
||||
/*
|
||||
* Convert the (long) integer value 'val' to the type named in 'opt->optType'
|
||||
* and store the result at 'user + opt->offset'.
|
||||
* Convert the (epicsInt32) 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)
|
||||
static int
|
||||
store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
|
||||
{
|
||||
epicsInt32 *ival;
|
||||
int *eval;
|
||||
@@ -77,7 +72,10 @@ static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
|
||||
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); */
|
||||
#ifdef DEBUG_CHF
|
||||
printf("Got an integer for %s (type %d): %ld\n",
|
||||
opt->name, opt->optType, (long) val);
|
||||
#endif
|
||||
|
||||
if (!opt->convert && opt->optType != chfPluginArgInt32) {
|
||||
return -1;
|
||||
@@ -89,24 +87,23 @@ static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
|
||||
*ival = val;
|
||||
break;
|
||||
case chfPluginArgBoolean:
|
||||
eval = (int*) ((char*)user + opt->offset);
|
||||
*eval = !!val;
|
||||
sval = user + opt->offset;
|
||||
*sval = !!val;
|
||||
break;
|
||||
case chfPluginArgDouble:
|
||||
dval = (double*) ((char*)user + opt->offset);
|
||||
*dval = (double) val;
|
||||
dval = (double*) (user + opt->offset);
|
||||
*dval = val;
|
||||
break;
|
||||
case chfPluginArgString:
|
||||
sval = ((char*)user + opt->offset);
|
||||
sprintf(buff, "%ld", val);
|
||||
if (strlen(buff) > opt->size-1) {
|
||||
sval = user + opt->offset;
|
||||
if (sprintf(buff, "%ld", (long)val) > 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);
|
||||
eval = (int*) (user + opt->offset);
|
||||
for (emap = opt->enums; emap && emap->name; emap++) {
|
||||
if (val == emap->value) {
|
||||
*eval = val;
|
||||
@@ -127,14 +124,16 @@ static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
|
||||
* 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)
|
||||
static int store_boolean_value(const chfPluginArgDef *opt, char *user, int val)
|
||||
{
|
||||
epicsInt32 *ival;
|
||||
int *eval;
|
||||
double *dval;
|
||||
char *sval;
|
||||
|
||||
/* printf("Got a boolean for %s (type %d): %d\n", opt->name, opt->optType, val); */
|
||||
#ifdef DEBUG_CHF
|
||||
printf("Got a boolean for %s (type %d): %d\n",
|
||||
opt->name, opt->optType, val);
|
||||
#endif
|
||||
|
||||
if (!opt->convert && opt->optType != chfPluginArgBoolean) {
|
||||
return -1;
|
||||
@@ -142,24 +141,24 @@ static int store_boolean_value(const chfPluginArgDef *opt, void *user, int val)
|
||||
|
||||
switch (opt->optType) {
|
||||
case chfPluginArgInt32:
|
||||
ival = (epicsInt32 *) ((char*)user + opt->offset);
|
||||
ival = (epicsInt32 *) (user + opt->offset);
|
||||
*ival = val;
|
||||
break;
|
||||
case chfPluginArgBoolean:
|
||||
eval = (int*) ((char*)user + opt->offset);
|
||||
*eval = val;
|
||||
sval = user + opt->offset;
|
||||
*sval = val;
|
||||
break;
|
||||
case chfPluginArgDouble:
|
||||
dval = (double*) ((char*)user + opt->offset);
|
||||
*dval = val ? 1. : 0.;
|
||||
dval = (double*) (user + opt->offset);
|
||||
*dval = !!val;
|
||||
break;
|
||||
case chfPluginArgString:
|
||||
sval = ((char*)user + opt->offset);
|
||||
if ((val ? 4 : 5) > opt->size-1) {
|
||||
sval = 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';
|
||||
strncpy(sval, val ? "true" : "false", opt->size - 1);
|
||||
sval[opt->size - 1] = '\0';
|
||||
break;
|
||||
case chfPluginArgEnum:
|
||||
case chfPluginArgInvalid:
|
||||
@@ -172,43 +171,42 @@ static int store_boolean_value(const chfPluginArgDef *opt, void *user, int val)
|
||||
* 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)
|
||||
static int
|
||||
store_double_value(const chfPluginArgDef *opt, void *user, double val)
|
||||
{
|
||||
epicsInt32 *ival;
|
||||
int *eval;
|
||||
double *dval;
|
||||
char *sval;
|
||||
int i;
|
||||
|
||||
/*
|
||||
#ifdef DEBUG_CHF
|
||||
printf("Got a double for %s (type %d, convert: %s): %g\n",
|
||||
opt->name, opt->optType, opt->convert?"yes":"no", val);
|
||||
*/
|
||||
opt->name, opt->optType, opt->convert ? "yes" : "no", val);
|
||||
#endif
|
||||
|
||||
if (!opt->convert && opt->optType != chfPluginArgDouble) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (opt->optType) {
|
||||
case chfPluginArgInt32:
|
||||
#if (LONG_MAX > 0x7fffffff)
|
||||
if (val < -0x80000000L || val > 0x7fffffff) {
|
||||
if (val < INT_MIN || val > INT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
ival = (epicsInt32 *) ((char*)user + opt->offset);
|
||||
*ival = val;
|
||||
ival = (epicsInt32 *) (user + opt->offset);
|
||||
*ival = (epicsInt32) val;
|
||||
break;
|
||||
case chfPluginArgBoolean:
|
||||
eval = (int*) ((char*)user + opt->offset);
|
||||
*eval = (val != 0.) ? 1 : 0;
|
||||
sval = user + opt->offset;
|
||||
*sval = !!val;
|
||||
break;
|
||||
case chfPluginArgDouble:
|
||||
dval = (double*) ((char*)user + opt->offset);
|
||||
dval = (double*) (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' + '.' */
|
||||
sval = user + opt->offset;
|
||||
if (opt->size <= 8) { /* Play it safe: 3 exp + 2 sign + 'e' + '.' */
|
||||
return -1;
|
||||
}
|
||||
i = epicsSnprintf(sval, opt->size, "%.*g", (int) opt->size - 7, val);
|
||||
@@ -227,10 +225,11 @@ static int store_double_value(const chfPluginArgDef *opt, void *user, double val
|
||||
* 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)
|
||||
static int
|
||||
store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
|
||||
size_t len)
|
||||
{
|
||||
epicsInt32 *ival;
|
||||
long lval;
|
||||
int *eval;
|
||||
const chfPluginEnumType *emap;
|
||||
double *dval;
|
||||
@@ -238,57 +237,47 @@ static int store_string_value(const chfPluginArgDef *opt, void *user, const char
|
||||
char *end;
|
||||
int i;
|
||||
|
||||
/* printf("Got a string for %s (type %d): %.*s\n", opt->name, opt->optType, len, val); */
|
||||
#ifdef DEBUG_CHF
|
||||
printf("Got a string for %s (type %d): %.*s\n",
|
||||
opt->name, opt->optType, (int) len, val);
|
||||
#endif
|
||||
|
||||
if (!opt->convert && opt->optType != chfPluginArgString && opt->optType != chfPluginArgEnum) {
|
||||
if (!opt->convert && opt->optType != chfPluginArgString &&
|
||||
opt->optType != chfPluginArgEnum) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (opt->optType) {
|
||||
case chfPluginArgInt32:
|
||||
lval = strtol(val, &end, 0);
|
||||
/* test for the myriad error conditions which strtol may use */
|
||||
if (lval == LONG_MAX || lval == LONG_MIN
|
||||
#if (LONG_MAX > 0x7fffffff)
|
||||
|| lval < -0x80000000L || lval > 0x7fffffff
|
||||
#endif
|
||||
|| end == val) {
|
||||
return -1;
|
||||
}
|
||||
ival = (epicsInt32 *) ((char*)user + opt->offset);
|
||||
*ival = lval;
|
||||
break;
|
||||
ival = (epicsInt32 *) (user + opt->offset);
|
||||
return epicsParseInt32(val, ival, 0, &end);
|
||||
|
||||
case chfPluginArgBoolean:
|
||||
eval = (int*) ((char*)user + opt->offset);
|
||||
sval = user + opt->offset;
|
||||
if (epicsStrnCaseCmp(val, "true", len) == 0) {
|
||||
*eval = 1;
|
||||
*sval = 1;
|
||||
} else if (epicsStrnCaseCmp(val, "false", len) == 0) {
|
||||
*eval = 0;
|
||||
*sval = 0;
|
||||
} else {
|
||||
i = strtol(val, &end, 0);
|
||||
if (i > INT_MAX || i < INT_MIN || end == val) {
|
||||
epicsInt8 i8;
|
||||
|
||||
if (epicsParseInt8(val, &i8, 0, &end))
|
||||
return -1;
|
||||
}
|
||||
*eval = !!i;
|
||||
*sval = !!i8;
|
||||
}
|
||||
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;
|
||||
dval = (double*) (user + opt->offset);
|
||||
return epicsParseDouble(val, dval, &end);
|
||||
|
||||
case chfPluginArgString:
|
||||
i = opt->size-1 < len ? opt->size-1 : len;
|
||||
sval = ((char*)user + opt->offset);
|
||||
sval = user + opt->offset;
|
||||
strncpy(sval, val, i);
|
||||
sval[i] = '\0';
|
||||
break;
|
||||
case chfPluginArgEnum:
|
||||
eval = (int*) ((char*)user + opt->offset);
|
||||
eval = (int*) (user + opt->offset);
|
||||
for (emap = opt->enums; emap && emap->name; emap++) {
|
||||
if (strncmp(emap->name, val, len) == 0) {
|
||||
*eval = emap->value;
|
||||
@@ -327,7 +316,7 @@ static parse_result parse_start(chFilter *filter)
|
||||
/* FIXME: Use a free-list */
|
||||
f = calloc(1, sizeof(chfFilter));
|
||||
if (!f) {
|
||||
fprintf(stderr,"chfFilterCtx calloc failed\n");
|
||||
errlogPrintf("chfFilterCtx calloc failed\n");
|
||||
goto errfctx;
|
||||
}
|
||||
f->nextParam = -1;
|
||||
@@ -336,7 +325,7 @@ static parse_result parse_start(chFilter *filter)
|
||||
/* 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");
|
||||
errlogPrintf("chfConfigParseStart: bit array calloc failed\n");
|
||||
goto errbitarray;
|
||||
}
|
||||
|
||||
@@ -401,7 +390,8 @@ 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)) {
|
||||
if (f->nextParam < 0 ||
|
||||
store_boolean_value(&opts[f->nextParam], f->puser, boolVal)) {
|
||||
return parse_stop;
|
||||
} else {
|
||||
return parse_continue;
|
||||
@@ -413,7 +403,13 @@ 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)) {
|
||||
if(sizeof(long)>sizeof(epicsInt32)) {
|
||||
epicsInt32 temp=integerVal;
|
||||
if(integerVal !=temp)
|
||||
return parse_stop;
|
||||
}
|
||||
if (f->nextParam < 0 ||
|
||||
store_integer_value(&opts[f->nextParam], f->puser, integerVal)) {
|
||||
return parse_stop;
|
||||
} else {
|
||||
return parse_continue;
|
||||
@@ -425,19 +421,22 @@ 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)) {
|
||||
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)
|
||||
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)) {
|
||||
if (f->nextParam < 0 ||
|
||||
store_string_value(&opts[f->nextParam], f->puser, stringVal, stringLen)) {
|
||||
return parse_stop;
|
||||
} else {
|
||||
return parse_continue;
|
||||
@@ -449,7 +448,8 @@ 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)
|
||||
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;
|
||||
@@ -481,31 +481,38 @@ 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;
|
||||
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)
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
p->pif->channelRegisterPost(filter->chan, f->puser, cb_out, arg_out,
|
||||
probe);
|
||||
}
|
||||
|
||||
static void channel_report(chFilter *filter, int level, const unsigned short indent)
|
||||
static void channel_report(chFilter *filter, int level,
|
||||
const unsigned short indent)
|
||||
{
|
||||
chfPlugin *p = (chfPlugin*) filter->plug->puser;
|
||||
chfFilter *f = (chfFilter*) filter->puser;
|
||||
@@ -525,11 +532,20 @@ static void channel_close(chFilter *filter)
|
||||
free(f); /* FIXME: Use a free-list */
|
||||
}
|
||||
|
||||
static void plugin_free(void* puser)
|
||||
{
|
||||
chfPlugin *p=puser;
|
||||
free(p->required);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* chFilterIf for the wrapper
|
||||
* we just support a simple one-level map, and no arrays
|
||||
*/
|
||||
static chFilterIf wrapper_fif = {
|
||||
plugin_free,
|
||||
|
||||
parse_start,
|
||||
parse_abort,
|
||||
parse_end,
|
||||
@@ -554,7 +570,8 @@ static chFilterIf wrapper_fif = {
|
||||
channel_close
|
||||
};
|
||||
|
||||
const char* chfPluginEnumString(const chfPluginEnumType *emap, int i, const char* def)
|
||||
const char*
|
||||
chfPluginEnumString(const chfPluginEnumType *emap, int i, const char* def)
|
||||
{
|
||||
for(; emap && emap->name; emap++) {
|
||||
if ( i == emap->value ) {
|
||||
@@ -564,7 +581,9 @@ const char* chfPluginEnumString(const chfPluginEnumType *emap, int i, const char
|
||||
return def;
|
||||
}
|
||||
|
||||
int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginArgDef* opts)
|
||||
int
|
||||
chfPluginRegister(const char* key, const chfPluginIf *pif,
|
||||
const chfPluginArgDef* opts)
|
||||
{
|
||||
chfPlugin *p;
|
||||
size_t i;
|
||||
@@ -576,25 +595,22 @@ int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginAr
|
||||
switch(cur->optType) {
|
||||
case chfPluginArgInt32:
|
||||
if (cur->size < sizeof(epicsInt32)) {
|
||||
errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for epicsInt32 (%lu)\n",
|
||||
key, cur->size, cur->name,
|
||||
(unsigned long) sizeof(epicsInt32));
|
||||
errlogPrintf("Plugin %s: %d bytes too small for epicsInt32 %s\n",
|
||||
key, cur->size, cur->name);
|
||||
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));
|
||||
errlogPrintf("Plugin %s: %d bytes too small for boolean %s\n",
|
||||
key, cur->size, cur->name);
|
||||
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));
|
||||
errlogPrintf("Plugin %s: %d bytes too small for double %s\n",
|
||||
key, cur->size, cur->name);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -603,17 +619,15 @@ int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginAr
|
||||
/* 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*));
|
||||
errlogPrintf("Plugin %s: %d bytes too small for string %s\n",
|
||||
key, cur->size, cur->name);
|
||||
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));
|
||||
errlogPrintf("Plugin %s: %d bytes too small for enum %s\n",
|
||||
key, cur->size, cur->name);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -628,7 +642,7 @@ int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginAr
|
||||
/* 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);
|
||||
errlogPrintf("Plugin %s: bit array calloc failed\n", key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,11 +44,12 @@ struct db_field_log;
|
||||
*
|
||||
* typedef struct myStruct {
|
||||
* ... other stuff
|
||||
* epicsUInt32 ival;
|
||||
* epicsInt32 ival;
|
||||
* double dval;
|
||||
* epicsUInt32 ival2;
|
||||
* epicsInt32 ival2;
|
||||
* int enumval;
|
||||
* char strval[20];
|
||||
* char boolval;
|
||||
* } myStruct;
|
||||
*
|
||||
* static const
|
||||
@@ -61,6 +62,7 @@ struct db_field_log;
|
||||
* chfDouble(myStruct, dval, "Double" , 1, 0),
|
||||
* chfString(myStruct, strval , "String" , 1, 0),
|
||||
* chfEnum (myStruct, enumval, "Color" , 1, 0, colorEnum),
|
||||
* chfBoolean(myStruct, boolval, "Bool" , 1, 0),
|
||||
* chfPluginEnd
|
||||
* };
|
||||
*
|
||||
|
||||
@@ -584,6 +584,8 @@ long dbChannelOpen(dbChannel *chan)
|
||||
}
|
||||
|
||||
/* Set up type probe */
|
||||
probe.type = dbfl_type_val;
|
||||
probe.ctx = dbfl_context_read;
|
||||
probe.field_type = dbChannelFieldType(chan);
|
||||
probe.no_elements = dbChannelElements(chan);
|
||||
probe.field_size = dbChannelFieldSize(chan);
|
||||
|
||||
@@ -72,6 +72,10 @@ typedef enum {
|
||||
|
||||
/* These routines must be implemented by each filter plug-in */
|
||||
typedef struct chFilterIf {
|
||||
/* cleanup pointer passed to dbRegisterFilter().
|
||||
* Called during DB shutdown
|
||||
*/
|
||||
void (* priv_free)(void *puser);
|
||||
/* Parsing event handlers: */
|
||||
parse_result (* parse_start)(chFilter *filter);
|
||||
/* If parse_start() returns parse_continue for a filter, one of
|
||||
|
||||
@@ -74,6 +74,7 @@ struct event_user {
|
||||
epicsMutexId lock;
|
||||
epicsEventId ppendsem; /* Wait while empty */
|
||||
epicsEventId pflush_sem; /* wait for flush */
|
||||
epicsEventId pexitsem; /* wait for event task to join */
|
||||
|
||||
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
|
||||
void *extralabor_arg;/* parameter to above */
|
||||
@@ -276,35 +277,44 @@ dbEventCtx epicsShareAPI db_init_events (void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Flag will be cleared when event task starts */
|
||||
evUser->pendexit = TRUE;
|
||||
|
||||
evUser->firstque.evUser = evUser;
|
||||
evUser->firstque.writelock = epicsMutexCreate();
|
||||
if (!evUser->firstque.writelock) {
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->firstque.writelock)
|
||||
goto fail;
|
||||
|
||||
evUser->ppendsem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->ppendsem) {
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->ppendsem)
|
||||
goto fail;
|
||||
evUser->pflush_sem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->pflush_sem) {
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->pflush_sem)
|
||||
goto fail;
|
||||
evUser->lock = epicsMutexCreate();
|
||||
if (!evUser->lock) {
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
epicsEventDestroy (evUser->pflush_sem);
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->lock)
|
||||
goto fail;
|
||||
evUser->pexitsem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->pexitsem)
|
||||
goto fail;
|
||||
|
||||
evUser->flowCtrlMode = FALSE;
|
||||
evUser->extraLaborBusy = FALSE;
|
||||
evUser->pSuicideEvent = NULL;
|
||||
return (dbEventCtx) evUser;
|
||||
fail:
|
||||
if(evUser->lock)
|
||||
epicsMutexDestroy (evUser->lock);
|
||||
if(evUser->firstque.writelock)
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
if(evUser->ppendsem)
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
if(evUser->pflush_sem)
|
||||
epicsEventDestroy (evUser->pflush_sem);
|
||||
if(evUser->pexitsem)
|
||||
epicsEventDestroy (evUser->pexitsem);
|
||||
freeListFree(dbevEventUserFreeList,evUser);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -328,10 +338,26 @@ void epicsShareAPI db_close_events (dbEventCtx ctx)
|
||||
* hazardous to the system's health.
|
||||
*/
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
evUser->pendexit = TRUE;
|
||||
if(!evUser->pendexit) { /* event task running */
|
||||
evUser->pendexit = TRUE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
/* notify the waiting task */
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
/* wait for task to exit */
|
||||
epicsEventMustWait(evUser->pexitsem);
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
}
|
||||
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
/* notify the waiting task */
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
|
||||
epicsEventDestroy(evUser->pexitsem);
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -824,7 +850,7 @@ void epicsShareAPI db_post_single_event (dbEventSubscription event)
|
||||
|
||||
pLog = db_create_event_log(pevent);
|
||||
pLog = dbChannelRunPreChain(pevent->chan, pLog);
|
||||
db_queue_event_log(pevent, pLog);
|
||||
if(pLog) db_queue_event_log(pevent, pLog);
|
||||
|
||||
dbScanUnlock (prec);
|
||||
}
|
||||
@@ -1006,14 +1032,10 @@ static void event_task (void *pParm)
|
||||
}
|
||||
}
|
||||
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
|
||||
taskwdRemove(epicsThreadGetIdSelf());
|
||||
|
||||
epicsEventSignal(evUser->pexitsem);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1037,7 +1059,6 @@ int epicsShareAPI db_start_events (
|
||||
return DB_EVENT_OK;
|
||||
}
|
||||
|
||||
evUser->pendexit = FALSE;
|
||||
evUser->init_func = init_func;
|
||||
evUser->init_func_arg = init_func_arg;
|
||||
if (!taskname) {
|
||||
@@ -1051,6 +1072,7 @@ int epicsShareAPI db_start_events (
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
return DB_EVENT_ERROR;
|
||||
}
|
||||
evUser->pendexit = FALSE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
return DB_EVENT_OK;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,13 @@ struct dbfl_val {
|
||||
union native_value field; /* Field value */
|
||||
};
|
||||
|
||||
/* External data reference.
|
||||
* If dtor is provided then it should be called when the referenced
|
||||
* data is no longer needed. This is done automatically by
|
||||
* db_delete_field_log(). Any code which changes a dbfl_type_ref
|
||||
* field log to another type, or to reference different data,
|
||||
* must explicitly call the dtor function.
|
||||
*/
|
||||
struct dbfl_ref {
|
||||
dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
|
||||
void *pvt; /* Private pointer */
|
||||
@@ -81,7 +88,9 @@ struct dbfl_ref {
|
||||
|
||||
typedef struct db_field_log {
|
||||
enum dbfl_type type:2; /* type (union) selector */
|
||||
/* ctx is used for all types */
|
||||
enum dbfl_context ctx:1; /* context (operation type) */
|
||||
/* the following are used for value and reference types */
|
||||
epicsTimeStamp time; /* Time stamp */
|
||||
unsigned short stat; /* Alarm Status */
|
||||
unsigned short sevr; /* Alarm Severity */
|
||||
@@ -94,6 +103,29 @@ typedef struct db_field_log {
|
||||
} u;
|
||||
} db_field_log;
|
||||
|
||||
/*
|
||||
* A db_field_log will in one of three types:
|
||||
*
|
||||
* dbfl_type_rec - Reference to record
|
||||
* The field log stores no data itself. Data must instead be taken
|
||||
* via the dbChannel* which must always be provided when along
|
||||
* with the field log.
|
||||
* For this type only the 'type' and 'ctx' members are used.
|
||||
*
|
||||
* dbfl_type_ref - Reference to outside value
|
||||
* Used for variable size (array) data types. Meta-data
|
||||
* is stored in the field log, but value data is stored externally
|
||||
* (see struct dbfl_ref).
|
||||
* For this type all meta-data members are used. The dbfl_ref side of the
|
||||
* data union is used.
|
||||
*
|
||||
* dbfl_type_val - Internal value
|
||||
* Used to store small scalar data. Meta-data and value are
|
||||
* present in this structure and no external references are used.
|
||||
* For this type all meta-data members are used. The dbfl_val side of the
|
||||
* data union is used.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# Copyright (c) 2012 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.
|
||||
@@ -10,48 +10,63 @@ TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_vxWorks += dbTestHarness
|
||||
PROD_RTEMS += dbTestHarness
|
||||
|
||||
PROD_LIBS = dbCore ca Com
|
||||
|
||||
TESTPROD_HOST += callbackTest
|
||||
callbackTest_SRCS += callbackTest.c
|
||||
dbTestHarness_SRCS += callbackTest.c
|
||||
testHarness_SRCS += callbackTest.c
|
||||
TESTS += callbackTest
|
||||
|
||||
|
||||
dbTestHarness_SRCS += epicsRunDbTests.c
|
||||
dbTestHarness_SRCS_RTEMS = rtemsTestHarness.c
|
||||
|
||||
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
|
||||
testHarness_SRCS += dbStateTest.c
|
||||
TESTS += dbStateTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/dbChannelTest.dbd
|
||||
dbChannelTest_DBD += xRecord.dbd
|
||||
TESTPROD_HOST += dbChannelTest
|
||||
dbChannelTest_SRCS += xRecord.c
|
||||
dbChannelTest_SRCS += dbChannelTest.c
|
||||
dbChannelTest_SRCS += dbChannelTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbChannelTest.c
|
||||
testHarness_SRCS += dbChannelTest_registerRecordDeviceDriver.cpp
|
||||
TESTS += dbChannelTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/chfPluginTest.dbd
|
||||
chfPluginTest_DBD += xRecord.dbd
|
||||
TESTPROD_HOST += chfPluginTest
|
||||
chfPluginTest_SRCS += xRecord.c
|
||||
chfPluginTest_SRCS += chfPluginTest.c
|
||||
chfPluginTest_SRCS += chfPluginTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += chfPluginTest.c
|
||||
testHarness_SRCS += chfPluginTest_registerRecordDeviceDriver.cpp
|
||||
TESTS += chfPluginTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/arrShorthandTest.dbd
|
||||
arrShorthandTest_DBD += xRecord.dbd
|
||||
TESTPROD_HOST += arrShorthandTest
|
||||
arrShorthandTest_SRCS += xRecord.c
|
||||
arrShorthandTest_SRCS += arrShorthandTest.c
|
||||
arrShorthandTest_SRCS += arrShorthandTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += arrShorthandTest.c
|
||||
testHarness_SRCS += arrShorthandTest_registerRecordDeviceDriver.cpp
|
||||
TESTS += arrShorthandTest
|
||||
|
||||
# The testHarness runs all the test programs in a known working order.
|
||||
testHarness_SRCS += epicsRunDbTests.c
|
||||
testHarness_SRCS += xRecord.c
|
||||
|
||||
dbTestHarness_SRCS += $(testHarness_SRCS)
|
||||
dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
|
||||
|
||||
PROD_vxWorks = dbTestHarness
|
||||
PROD_RTEMS = dbTestHarness
|
||||
|
||||
TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests
|
||||
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
|
||||
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
dbChannelTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
chfPluginTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
arrShorthandTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
dbStateTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
#include "chfPlugin.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "registry.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
typedef struct myStruct {
|
||||
epicsInt32 start;
|
||||
@@ -75,9 +77,9 @@ static void testHead (char* title) {
|
||||
testDiag("--------------------------------------------------------");
|
||||
}
|
||||
|
||||
void xRecord_registerRecordDeviceDriver(struct dbBase *);
|
||||
void arrShorthandTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(chfPluginTest)
|
||||
MAIN(arrShorthandTest)
|
||||
{
|
||||
dbChannel *pch;
|
||||
|
||||
@@ -85,11 +87,14 @@ MAIN(chfPluginTest)
|
||||
|
||||
db_init_events();
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "arrShorthandTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
xRecord_registerRecordDeviceDriver(pdbbase);
|
||||
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
|
||||
arrShorthandTest_registerRecordDeviceDriver(pdbbase);
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
testHead("Register plugin");
|
||||
@@ -124,16 +129,8 @@ MAIN(chfPluginTest)
|
||||
TESTGOOD("range with incr [s:i:e]", "[2:3:4]", 2, 3, 4);
|
||||
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase = NULL;
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <recSup.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
#include "chfPlugin.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "registry.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
#define PATTERN 0x55555555
|
||||
#define TYPE_START 0xAAA
|
||||
@@ -445,15 +447,22 @@ static chfPluginIf postPif = {
|
||||
|
||||
static int checkValues(myStruct *my,
|
||||
epicsUInt32 i, int f, double d, char *s, int c) {
|
||||
int ret = 1;
|
||||
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;
|
||||
}
|
||||
#define CHK(A,B,FMT) if((A)!=(B)) {testDiag("Fail: " #A " (" FMT ") != " #B " (" FMT")", A, B); ret=0;}
|
||||
CHK(my->sent1, PATTERN, "%08x")
|
||||
CHK(my->sent2, PATTERN, "%08x")
|
||||
CHK(my->sent3, PATTERN, "%08x")
|
||||
CHK(my->sent4, PATTERN, "%08x")
|
||||
CHK(my->sent5, PATTERN, "%08x")
|
||||
CHK(my->sent6, PATTERN, "%08x")
|
||||
CHK(my->ival, i, "%08x")
|
||||
CHK(my->flag, f, "%02x")
|
||||
CHK(my->dval, d, "%f")
|
||||
CHK(my->enumval, c, "%d")
|
||||
#undef CHK
|
||||
if(strcmp(s, my->str) != 0) {testDiag("Fail: my->str (%s) != s (%s)", my->str, s); ret=0;}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void testHead (char* title) {
|
||||
@@ -462,7 +471,7 @@ static void testHead (char* title) {
|
||||
testDiag("--------------------------------------------------------");
|
||||
}
|
||||
|
||||
void xRecord_registerRecordDeviceDriver(struct dbBase *);
|
||||
void chfPluginTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(chfPluginTest)
|
||||
{
|
||||
@@ -484,11 +493,14 @@ MAIN(chfPluginTest)
|
||||
testOk(strcmp(chfPluginEnumString(colorEnum, 3, "-"), "-") == 0,
|
||||
"Enum to string: invalid index");
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "chfPluginTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
xRecord_registerRecordDeviceDriver(pdbbase);
|
||||
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
|
||||
chfPluginTest_registerRecordDeviceDriver(pdbbase);
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
testHead("Try to register buggy plugins");
|
||||
@@ -818,15 +830,8 @@ MAIN(chfPluginTest)
|
||||
drop = -1;
|
||||
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase = NULL;
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <recSup.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
#include "dbChannel.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "registry.h"
|
||||
#include "recSup.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
/* Expected call bit definitions */
|
||||
#define e_start 0x00000001
|
||||
@@ -143,11 +145,11 @@ void c_close(chFilter *filter)
|
||||
}
|
||||
|
||||
chFilterIf testIf =
|
||||
{ p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
|
||||
{ NULL, 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 *);
|
||||
void dbChannelTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(testDbChannel) /* dbChannelTest is an API routine... */
|
||||
{
|
||||
@@ -155,11 +157,14 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
|
||||
|
||||
testPlan(66);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "dbChannelTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
xRecord_registerRecordDeviceDriver(pdbbase);
|
||||
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
|
||||
dbChannelTest_registerRecordDeviceDriver(pdbbase);
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
r = e = 0;
|
||||
@@ -247,15 +252,8 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
|
||||
testOk1(!dbChannelCreate("x.{\"scalar\":{}}"));
|
||||
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase = NULL;
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <recSup.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
|
||||
@@ -14,14 +14,25 @@
|
||||
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsExit.h"
|
||||
#include "dbmf.h"
|
||||
|
||||
int callbackTest(void);
|
||||
int dbStateTest(void);
|
||||
int testDbChannel(void);
|
||||
int chfPluginTest(void);
|
||||
int arrShorthandTest(void);
|
||||
|
||||
void epicsRunDbTests(void)
|
||||
{
|
||||
testHarness();
|
||||
|
||||
runTest(callbackTest);
|
||||
runTest(dbStateTest);
|
||||
runTest(testDbChannel);
|
||||
runTest(chfPluginTest);
|
||||
runTest(arrShorthandTest);
|
||||
|
||||
dbmfFreeChunks();
|
||||
|
||||
epicsExit(0); /* Trigger test harness */
|
||||
}
|
||||
|
||||
@@ -5,10 +5,40 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
#ifdef __rtems__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <envDefs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif /* __rtems__ */
|
||||
|
||||
extern void epicsRunDbTests(void);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef __rtems__
|
||||
struct stat s;
|
||||
printf("Try to create /tmp\n");
|
||||
umask(0);
|
||||
if(mkdir("/tmp", 0777)!=0)
|
||||
perror("Can't create /tmp");
|
||||
if(stat("/tmp", &s)==0) {
|
||||
printf("Stat /tmp: %o %u,%u\n", s.st_mode, s.st_uid, s.st_gid);
|
||||
}
|
||||
epicsEnvSet("TMPDIR","/tmp");
|
||||
{
|
||||
char name[40];
|
||||
if(getcwd(name,40))
|
||||
printf("Running from %s\n", name);
|
||||
else
|
||||
printf("Can't determine PWD");
|
||||
}
|
||||
#endif
|
||||
|
||||
epicsRunDbTests(); /* calls epicsExit(0) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
25
src/ioc/db/test/xRecord.c
Normal file
25
src/ioc/db/test/xRecord.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*************************************************************************\
|
||||
* 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 <anj@aps.anl.gov>
|
||||
* Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#include "dbAccessDefs.h"
|
||||
#include <recSup.h>
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "epicsStdlib.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "dbChannel.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "link.h"
|
||||
@@ -592,6 +593,8 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
|
||||
drvSup *pdrvSupNext;
|
||||
brkTable *pbrkTable;
|
||||
brkTable *pbrkTableNext;
|
||||
chFilterPlugin *pfilt;
|
||||
chFilterPlugin *pfiltNext;
|
||||
int i;
|
||||
DBENTRY dbentry;
|
||||
|
||||
@@ -651,6 +654,7 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
|
||||
ellDelete(&pdbRecordType->attributeList,&pAttribute->node);
|
||||
free((void *)pAttribute->name);
|
||||
free((void *)pAttribute->pdbFldDes);
|
||||
free(pAttribute);
|
||||
pAttribute = pAttributeNext;
|
||||
}
|
||||
pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node);
|
||||
@@ -722,6 +726,15 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
|
||||
free((void *)pbrkTable);
|
||||
pbrkTable = pbrkTableNext;
|
||||
}
|
||||
pfilt = (chFilterPlugin *)ellFirst(&pdbbase->filterList);
|
||||
while(pfilt) {
|
||||
pfiltNext = (chFilterPlugin *)ellNext(&pfilt->node);
|
||||
free((char*)pfilt->name);
|
||||
if(pfilt->fif->priv_free)
|
||||
(*pfilt->fif->priv_free)(pfilt->puser);
|
||||
free(pfilt);
|
||||
pfilt = pfiltNext;
|
||||
}
|
||||
gphFreeMem(pdbbase->pgpHash);
|
||||
dbPvdFreeMem(pdbbase);
|
||||
dbFreePath(pdbbase);
|
||||
|
||||
@@ -186,8 +186,7 @@ print << 'END';
|
||||
}
|
||||
|
||||
if (executed) {
|
||||
printf("Registration already done.\n");
|
||||
return 0;
|
||||
printf("Warning: Registration already done.\n");
|
||||
}
|
||||
executed = 1;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifndef DBMF_H
|
||||
#define DBMF_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -81,6 +81,7 @@ epicsShareFunc void epicsShareAPI registryFree(void)
|
||||
{
|
||||
if(!gphPvt) return;
|
||||
gphFreeMem(gphPvt);
|
||||
gphPvt = 0;
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI registryDump(void)
|
||||
|
||||
@@ -93,8 +93,10 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (drop) return NULL;
|
||||
else return pfl;
|
||||
if (drop) {
|
||||
db_delete_field_log(pfl);
|
||||
return NULL;
|
||||
} else return pfl;
|
||||
}
|
||||
|
||||
static void channelRegisterPre(dbChannel *chan, void *pvt,
|
||||
|
||||
@@ -59,6 +59,8 @@ static void * allocPvt(void)
|
||||
|
||||
static void freePvt(void *pvt)
|
||||
{
|
||||
myStruct *my = (myStruct*) pvt;
|
||||
db_delete_field_log(my->lastfl);
|
||||
freeListFree(myStructFreeList, pvt);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
|
||||
# Copyright (c) 2012 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.
|
||||
@@ -10,30 +10,62 @@ TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_LIBS += dbRecStd dbCore ca Com
|
||||
PROD_LIBS = dbRecStd dbCore ca Com
|
||||
|
||||
TARGETS += $(COMMON_DIR)/tsTest.dbd
|
||||
tsTest_DBD += xRecord.dbd
|
||||
TESTPROD_HOST += tsTest
|
||||
tsTest_SRCS += tsTest.c xRecord_registerRecordDeviceDriver.cpp
|
||||
OBJS_IOC_vxWorks += tsTest
|
||||
tsTest_SRCS += xRecord.c
|
||||
tsTest_SRCS += tsTest.c
|
||||
tsTest_SRCS += tsTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += tsTest.c
|
||||
testHarness_SRCS += tsTest_registerRecordDeviceDriver.cpp
|
||||
TESTS += tsTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/dbndTest.dbd
|
||||
dbndTest_DBD += xRecord.dbd
|
||||
TESTPROD_HOST += dbndTest
|
||||
dbndTest_SRCS += dbndTest.c xRecord_registerRecordDeviceDriver.cpp
|
||||
OBJS_IOC_vxWorks += dbndTest
|
||||
dbndTest_SRCS += xRecord.c
|
||||
dbndTest_SRCS += dbndTest.c
|
||||
dbndTest_SRCS += dbndTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbndTest.c
|
||||
testHarness_SRCS += dbndTest_registerRecordDeviceDriver.cpp
|
||||
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
|
||||
arrTest_SRCS += arrRecord.c
|
||||
arrTest_SRCS += arrTest.cpp
|
||||
arrTest_SRCS += arrTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += arrRecord.c
|
||||
testHarness_SRCS += arrTest.cpp
|
||||
testHarness_SRCS += arrTest_registerRecordDeviceDriver.cpp
|
||||
TESTS += arrTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/syncTest.dbd
|
||||
syncTest_DBD += xRecord.dbd
|
||||
TESTPROD_HOST += syncTest
|
||||
syncTest_SRCS += syncTest.c xRecord_registerRecordDeviceDriver.cpp
|
||||
OBJS_IOC_vxWorks += syncTest
|
||||
syncTest_SRCS += xRecord.c
|
||||
syncTest_SRCS += syncTest.c
|
||||
syncTest_SRCS += syncTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += syncTest.c
|
||||
testHarness_SRCS += syncTest_registerRecordDeviceDriver.cpp
|
||||
TESTS += syncTest
|
||||
|
||||
# epicsRunFilterTests runs all the test programs in a known working order.
|
||||
testHarness_SRCS += epicsRunFilterTests.c
|
||||
testHarness_SRCS += xRecord.c
|
||||
|
||||
filterTestHarness_SRCS += $(testHarness_SRCS)
|
||||
filterTestHarness_SRCS_RTEMS += rtemsTestHarness.c
|
||||
|
||||
PROD_vxWorks = filterTestHarness
|
||||
PROD_RTEMS = filterTestHarness
|
||||
|
||||
TESTSPEC_vxWorks = filterTestHarness.munch; epicsRunFilterTests
|
||||
TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests
|
||||
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "epicsStdio.h"
|
||||
#include "envDefs.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbmf.h"
|
||||
#include "registry.h"
|
||||
#include "subRecord.h"
|
||||
#include "dbAddr.h"
|
||||
#include "dbAccess.h"
|
||||
@@ -37,10 +39,11 @@
|
||||
#include "dbChannel.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
#include "arrRecord.h"
|
||||
|
||||
extern "C" int arrRecord_registerRecordDeviceDriver(struct dbBase *pdbbase);
|
||||
extern "C" int arrTest_registerRecordDeviceDriver(struct dbBase *pdbbase);
|
||||
extern "C" void (*pvar_func_arrInitialize)(void);
|
||||
|
||||
#define CA_SERVER_PORT "65535"
|
||||
@@ -293,6 +296,19 @@ static void check(short dbr_type) {
|
||||
TEST5B(3, -8, -4, "both sides from-end");
|
||||
}
|
||||
|
||||
static dbEventCtx evtctx;
|
||||
|
||||
static void arrTestCleanup(void* junk)
|
||||
{
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase=0;
|
||||
|
||||
db_close_events(evtctx);
|
||||
|
||||
dbmfFreeChunks();
|
||||
}
|
||||
|
||||
MAIN(arrTest)
|
||||
{
|
||||
const chFilterPlugin *plug;
|
||||
@@ -304,21 +320,25 @@ MAIN(arrTest)
|
||||
|
||||
epicsEnvSet("EPICS_CA_SERVER_PORT", server_port);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "arrRecord.dbd",
|
||||
"..:../../../../../dbd", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "arrTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
(*pvar_func_arrInitialize)();
|
||||
arrRecord_registerRecordDeviceDriver(pdbbase);
|
||||
arrTest_registerRecordDeviceDriver(pdbbase);
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "arrTest.db", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "arrTest.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
epicsAtExit(&arrTestCleanup,NULL);
|
||||
|
||||
/* Start the IOC */
|
||||
|
||||
iocInit();
|
||||
db_init_events();
|
||||
evtctx = db_init_events();
|
||||
epicsThreadSleep(0.2);
|
||||
|
||||
testOk(!!(plug = dbFindFilter(arr, strlen(arr))), "plugin arr registered correctly");
|
||||
@@ -327,11 +347,5 @@ MAIN(arrTest)
|
||||
check(DBR_DOUBLE);
|
||||
check(DBR_STRING);
|
||||
|
||||
dbFreeBase(pdbbase);
|
||||
|
||||
return testDone();
|
||||
|
||||
epicsExit(EXIT_SUCCESS);
|
||||
/*Note that the following statement will never be executed*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
#include "dbAccessDefs.h"
|
||||
#include "db_field_log.h"
|
||||
#include "dbCommon.h"
|
||||
#include "registry.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsTime.h"
|
||||
#include "dbmf.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
#define PATTERN 0x55
|
||||
|
||||
@@ -96,7 +99,7 @@ static void testHead (char* title) {
|
||||
testDiag("--------------------------------------------------------");
|
||||
}
|
||||
|
||||
void xRecord_registerRecordDeviceDriver(struct dbBase *);
|
||||
void dbndTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(dbndTest)
|
||||
{
|
||||
@@ -109,18 +112,22 @@ MAIN(dbndTest)
|
||||
void *arg_out = NULL;
|
||||
db_field_log *pfl2;
|
||||
db_field_log fl1;
|
||||
dbEventCtx evtctx;
|
||||
|
||||
testPlan(59);
|
||||
|
||||
db_init_events();
|
||||
evtctx = db_init_events();
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "dbndTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
(*pvar_func_dbndInitialize)(); /* manually initialize plugin */
|
||||
xRecord_registerRecordDeviceDriver(pdbbase);
|
||||
dbndTest_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
testOk(!!(plug = dbFindFilter(dbnd, strlen(dbnd))), "plugin dbnd registered correctly");
|
||||
@@ -160,9 +167,13 @@ MAIN(dbndTest)
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "abs", 0., 0);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "abs", 0., 1);
|
||||
|
||||
db_delete_field_log(pfl2);
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* Delta = -1: pass any update */
|
||||
@@ -192,11 +203,25 @@ MAIN(dbndTest)
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "abs", 3., 1);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustDrop(pch, pfl2, "abs", 3., 3);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustDrop(pch, pfl2, "abs", 3., 4);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "abs", 3., 5);
|
||||
|
||||
db_delete_field_log(pfl2);
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* Delta = relative */
|
||||
@@ -211,25 +236,51 @@ MAIN(dbndTest)
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 1);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 2);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustDrop(pch, pfl2, "rel", 50., 3);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 4);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustDrop(pch, pfl2, "rel", 50., 5);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustDrop(pch, pfl2, "rel", 50., 6);
|
||||
|
||||
pfl2 = db_create_read_log(pch);
|
||||
testDiag("new field_log from record");
|
||||
fl_setup(pch, pfl2);
|
||||
|
||||
mustPassOnce(pch, pfl2, "rel", 50., 7);
|
||||
|
||||
db_delete_field_log(pfl2);
|
||||
dbChannelDelete(pch);
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase=0;
|
||||
|
||||
db_close_events(evtctx);
|
||||
|
||||
dbmfFreeChunks();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <recSup.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
|
||||
33
src/std/filters/test/epicsRunFilterTests.c
Normal file
33
src/std/filters/test/epicsRunFilterTests.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Run filter tests as a batch.
|
||||
*/
|
||||
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsExit.h"
|
||||
#include "dbmf.h"
|
||||
|
||||
int tsTest(void);
|
||||
int dbndTest(void);
|
||||
int syncTest(void);
|
||||
int arrTest(void);
|
||||
|
||||
void epicsRunFilterTests(void)
|
||||
{
|
||||
testHarness();
|
||||
|
||||
runTest(tsTest);
|
||||
runTest(dbndTest);
|
||||
runTest(syncTest);
|
||||
runTest(arrTest);
|
||||
|
||||
dbmfFreeChunks();
|
||||
|
||||
epicsExit(0); /* Trigger test harness */
|
||||
}
|
||||
@@ -17,11 +17,14 @@
|
||||
#include "db_field_log.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbChannel.h"
|
||||
#include "registry.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "dbmf.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsTime.h"
|
||||
#include "dbState.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
#define PATTERN 0x55
|
||||
|
||||
@@ -127,7 +130,7 @@ static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) {
|
||||
checkCtxRead(pch, red);
|
||||
}
|
||||
|
||||
void xRecord_registerRecordDeviceDriver(struct dbBase *);
|
||||
void syncTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(syncTest)
|
||||
{
|
||||
@@ -136,18 +139,22 @@ MAIN(syncTest)
|
||||
char myname[] = "sync";
|
||||
db_field_log *pfl[10];
|
||||
int i;
|
||||
dbEventCtx evtctx;
|
||||
|
||||
testPlan(0);
|
||||
|
||||
db_init_events();
|
||||
evtctx = db_init_events();
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "syncTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
(*pvar_func_syncInitialize)(); /* manually initialize plugin */
|
||||
xRecord_registerRecordDeviceDriver(pdbbase);
|
||||
syncTest_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
testOk(!!(plug = dbFindFilter(myname, strlen(myname))), "plugin %s registered correctly", myname);
|
||||
@@ -194,6 +201,8 @@ MAIN(syncTest)
|
||||
for (i = 0; i < 10; i++)
|
||||
db_delete_field_log(pfl[i]);
|
||||
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* mode UNLESS */
|
||||
|
||||
testHead("Mode UNLESS (m='unless', s='red')");
|
||||
@@ -225,6 +234,8 @@ MAIN(syncTest)
|
||||
for (i = 0; i < 10; i++)
|
||||
db_delete_field_log(pfl[i]);
|
||||
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* mode BEFORE */
|
||||
|
||||
testHead("Mode BEFORE (m='before', s='red')");
|
||||
@@ -254,8 +265,9 @@ MAIN(syncTest)
|
||||
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]);
|
||||
db_delete_field_log(pfl[2]);
|
||||
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* mode FIRST */
|
||||
|
||||
@@ -285,8 +297,10 @@ MAIN(syncTest)
|
||||
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]);
|
||||
db_delete_field_log(pfl[3]);
|
||||
db_delete_field_log(pfl[9]);
|
||||
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* mode LAST */
|
||||
|
||||
@@ -317,8 +331,9 @@ MAIN(syncTest)
|
||||
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]);
|
||||
db_delete_field_log(pfl[5]);
|
||||
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* mode AFTER */
|
||||
|
||||
@@ -348,20 +363,17 @@ MAIN(syncTest)
|
||||
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]);
|
||||
db_delete_field_log(pfl[6]);
|
||||
db_delete_field_log(pfl[9]);
|
||||
|
||||
dbChannelDelete(pch);
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase=0;
|
||||
|
||||
db_close_events(evtctx);
|
||||
|
||||
dbmfFreeChunks();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <recSup.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
#include "dbAccessDefs.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "registry.h"
|
||||
#include "dbmf.h"
|
||||
#include "epicsTime.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
#define PATTERN 0x55
|
||||
|
||||
@@ -36,7 +39,7 @@ static int fl_equal_ex_ts(const db_field_log *pfl1, const db_field_log *pfl2) {
|
||||
return fl_equal(&fl1, pfl2);
|
||||
}
|
||||
|
||||
void xRecord_registerRecordDeviceDriver(struct dbBase *);
|
||||
void tsTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(tsTest)
|
||||
{
|
||||
@@ -50,18 +53,22 @@ MAIN(tsTest)
|
||||
db_field_log fl1;
|
||||
db_field_log *pfl2;
|
||||
epicsTimeStamp stamp, now;
|
||||
dbEventCtx evtctx;
|
||||
|
||||
testPlan(12);
|
||||
|
||||
db_init_events();
|
||||
evtctx = db_init_events();
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "tsTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
(*pvar_func_tsInitialize)(); /* manually initialize plugin */
|
||||
xRecord_registerRecordDeviceDriver(pdbbase);
|
||||
tsTest_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
|
||||
if (dbReadDatabase(&pdbbase, "xRecord.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
testOk(!!(plug = dbFindFilter(ts, strlen(ts))), "plugin ts registered correctly");
|
||||
@@ -92,6 +99,8 @@ MAIN(tsTest)
|
||||
|
||||
testOk(!!(pfl2 = db_create_read_log(pch)), "create field log from channel");
|
||||
stamp = pfl2->time;
|
||||
db_delete_field_log(pfl2);
|
||||
|
||||
pfl2 = dbChannelRunPreChain(pch, &fl1);
|
||||
epicsTimeGetCurrent(&now);
|
||||
testOk(epicsTimeDiffInSeconds(&pfl2->time, &stamp) > 0. &&
|
||||
@@ -99,15 +108,12 @@ MAIN(tsTest)
|
||||
|
||||
dbChannelDelete(pch);
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase=0;
|
||||
|
||||
db_close_events(evtctx);
|
||||
|
||||
dbmfFreeChunks();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <recSup.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
|
||||
25
src/std/filters/test/xRecord.c
Normal file
25
src/std/filters/test/xRecord.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*************************************************************************\
|
||||
* 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 <anj@aps.anl.gov>
|
||||
* Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#include "dbAccessDefs.h"
|
||||
#include <recSup.h>
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "xRecord.h"
|
||||
|
||||
#include <epicsExport.h>
|
||||
|
||||
static rset xRSET;
|
||||
epicsExportAddress(rset,xRSET);
|
||||
Reference in New Issue
Block a user