Add arr plugin for array subsets (+ testcode)
This commit is contained in:
@@ -88,4 +88,5 @@ dbCore_SRCS += chfPlugin.c
|
||||
|
||||
LIB_SRCS += ts.c
|
||||
LIB_SRCS += dbnd.c
|
||||
LIB_SRCS += arr.c
|
||||
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*************************************************************************\
|
||||
* 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 <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#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;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (*end - *start >= 1) len = 1 + (*end - *start - 1 ) / 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);
|
||||
@@ -1,2 +1,3 @@
|
||||
registrar(tsInitialize)
|
||||
registrar(dbndInitialize)
|
||||
registrar(arrInitialize)
|
||||
|
||||
@@ -10,18 +10,29 @@ TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_LIBS += dbIoc registryIoc dbStaticHost ca Com
|
||||
PROD_LIBS += dbIoc miscIoc registryIoc ca Com
|
||||
|
||||
TESTPROD_HOST += tsTest
|
||||
tsTest_SRCS += tsTest.c
|
||||
tsTest_LIBS += dbStaticHost
|
||||
OBJS_IOC_vxWorks += tsTest
|
||||
TESTS += tsTest
|
||||
|
||||
TESTPROD_HOST += dbndTest
|
||||
dbndTest_SRCS += dbndTest.c
|
||||
dbndTest_LIBS += dbStaticHost
|
||||
OBJS_IOC_vxWorks += dbndTest
|
||||
TESTS += dbndTest
|
||||
|
||||
DBDINC += arrRecord
|
||||
TARGETS += $(COMMON_DIR)/arrTest.dbd
|
||||
arrTest_DBD += arrRecord.dbd
|
||||
TESTPROD_HOST += arrTest
|
||||
arrTest_SRCS += arrTest.cpp arrRecord.c arrRecord_registerRecordDeviceDriver.cpp
|
||||
arrTest_LIBS += dbStaticIoc
|
||||
OBJS_IOC_vxWorks += arrTest
|
||||
TESTS += arrTest
|
||||
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -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 <Ralph.Lange@bessy.de>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
include "menuGlobal.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")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
/*************************************************************************\
|
||||
* 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 <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
/* 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 "epicsInstallDir.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 DBD_FILE EPICS_BASE "/src/db/filters/test/O.Common/arrTest.dbd"
|
||||
#define DB_FILE EPICS_BASE "/src/db/filters/test/arrTest.db"
|
||||
#define EXIT_FILE EPICS_BASE "/db/softIocExit.db"
|
||||
#define CA_SERVER_PORT "65535"
|
||||
|
||||
#define PATTERN 0x55
|
||||
|
||||
const char *base_dbd = DBD_FILE;
|
||||
const char *arr_db = DB_FILE;
|
||||
const char *exit_db = EXIT_FILE;
|
||||
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);
|
||||
}
|
||||
|
||||
static void check(short dbr_type) {
|
||||
dbChannel *pch;
|
||||
db_field_log *pfl, *pfl2;
|
||||
int status;
|
||||
dbAddr valaddr;
|
||||
dbAddr offaddr;
|
||||
char *offname, *valname, *typname;
|
||||
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);
|
||||
|
||||
#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);
|
||||
|
||||
/* 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)", valaddr.field_type);
|
||||
testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld)", valaddr.no_elements);
|
||||
|
||||
TEST1(10, 0, 1, "no offset");
|
||||
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)", valaddr.field_type); \
|
||||
testOk(pch->final_no_elements == 4 / Incr + 1, "final no_elements correct (%d)", 4 / Incr + 1); \
|
||||
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, 7, "regular");
|
||||
TEST5(1, -8, 7, "left side from-end");
|
||||
TEST5(1, 2, -3, "right side from-end");
|
||||
TEST5(1, -8, -3, "both sides from-end");
|
||||
|
||||
/* 5 elements with increment 2 */
|
||||
|
||||
TEST5(2, 2, 7, "regular");
|
||||
TEST5(2, -8, 7, "left side from-end");
|
||||
TEST5(2, 2, -3, "right side from-end");
|
||||
TEST5(2, -8, -3, "both sides from-end");
|
||||
|
||||
/* 5 elements with increment 3 */
|
||||
|
||||
TEST5(3, 2, 7, "regular");
|
||||
TEST5(3, -8, 7, "left side from-end");
|
||||
TEST5(3, 2, -3, "right side from-end");
|
||||
TEST5(3, -8, -3, "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)", valaddr.field_type); \
|
||||
testOk(pch->final_no_elements == 4 / Incr + 1, "final no_elements correct (%d)", 4 / Incr + 1); \
|
||||
TEST1(5, 0, Incr, "no offset"); \
|
||||
dbChannelDelete(pch);
|
||||
|
||||
/* Contiguous block of 5 */
|
||||
|
||||
TEST5B(1, 2, 7, "regular");
|
||||
TEST5B(1, -8, 7, "left side from-end");
|
||||
TEST5B(1, 2, -3, "right side from-end");
|
||||
TEST5B(1, -8, -3, "both sides from-end");
|
||||
|
||||
/* 5 elements with increment 2 */
|
||||
|
||||
TEST5B(2, 2, 7, "regular");
|
||||
TEST5B(2, -8, 7, "left side from-end");
|
||||
TEST5B(2, 2, -3, "right side from-end");
|
||||
TEST5B(2, -8, -3, "both sides from-end");
|
||||
|
||||
/* 5 elements with increment 3 */
|
||||
|
||||
TEST5B(3, 2, 7, "regular");
|
||||
TEST5B(3, -8, 7, "left side from-end");
|
||||
TEST5B(3, 2, -3, "right side from-end");
|
||||
TEST5B(3, -8, -3, "both sides from-end");
|
||||
}
|
||||
|
||||
MAIN(arrTest)
|
||||
{
|
||||
char *dbd_file = const_cast<char*>(base_dbd);
|
||||
char *db_file = const_cast<char*>(arr_db);
|
||||
const chFilterPlugin *plug;
|
||||
char arr[] = "arr";
|
||||
int status;
|
||||
|
||||
testPlan(1272);
|
||||
|
||||
/* Prepare the IOC */
|
||||
|
||||
epicsEnvSet("EPICS_CA_SERVER_PORT", server_port);
|
||||
|
||||
testOk1(!(status = dbLoadDatabase(dbd_file, NULL, NULL)));
|
||||
if (status) epicsExit(EXIT_FAILURE);
|
||||
|
||||
(*pvar_func_arrInitialize)();
|
||||
arrRecord_registerRecordDeviceDriver(pdbbase);
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
|
||||
testOk1(!(status = dbLoadRecords(db_file, 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;
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -102,7 +102,7 @@ MAIN(dbndTest)
|
||||
db_field_log *pfl, *pfl2;
|
||||
db_field_log fl1;
|
||||
|
||||
testPlan(0);
|
||||
testPlan(61);
|
||||
|
||||
db_init_events();
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ MAIN(tsTest)
|
||||
db_field_log fl1;
|
||||
db_field_log *pfl2;
|
||||
|
||||
testPlan(0);
|
||||
testPlan(14);
|
||||
|
||||
db_init_events();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user