From 45a531b167488e23ced350b8af04e4153b237926 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Apr 2012 13:25:07 -0400 Subject: [PATCH] Add arr plugin for array subsets (+ testcode) --- src/ioc/db/Makefile | 1 + src/ioc/db/filters/arr.c | 201 +++++++++++++++++ src/ioc/db/filters/filters.dbd | 1 + src/ioc/db/filters/test/Makefile | 13 +- src/ioc/db/filters/test/arrRecord.c | 135 +++++++++++ src/ioc/db/filters/test/arrRecord.dbd | 32 +++ src/ioc/db/filters/test/arrTest.cpp | 307 ++++++++++++++++++++++++++ src/ioc/db/filters/test/arrTest.db | 15 ++ src/ioc/db/filters/test/dbndTest.c | 2 +- src/ioc/db/filters/test/tsTest.c | 2 +- 10 files changed, 706 insertions(+), 3 deletions(-) create mode 100644 src/ioc/db/filters/arr.c create mode 100644 src/ioc/db/filters/test/arrRecord.c create mode 100644 src/ioc/db/filters/test/arrRecord.dbd create mode 100644 src/ioc/db/filters/test/arrTest.cpp create mode 100644 src/ioc/db/filters/test/arrTest.db diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile index 27a26915e..7e3c2526b 100644 --- a/src/ioc/db/Makefile +++ b/src/ioc/db/Makefile @@ -88,4 +88,5 @@ dbCore_SRCS += chfPlugin.c LIB_SRCS += ts.c LIB_SRCS += dbnd.c +LIB_SRCS += arr.c diff --git a/src/ioc/db/filters/arr.c b/src/ioc/db/filters/arr.c new file mode 100644 index 000000000..07e1309a5 --- /dev/null +++ b/src/ioc/db/filters/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 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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); diff --git a/src/ioc/db/filters/filters.dbd b/src/ioc/db/filters/filters.dbd index c859f0f40..48cd94cd3 100644 --- a/src/ioc/db/filters/filters.dbd +++ b/src/ioc/db/filters/filters.dbd @@ -1,2 +1,3 @@ registrar(tsInitialize) registrar(dbndInitialize) +registrar(arrInitialize) diff --git a/src/ioc/db/filters/test/Makefile b/src/ioc/db/filters/test/Makefile index 1e32b3056..23ebe705e 100644 --- a/src/ioc/db/filters/test/Makefile +++ b/src/ioc/db/filters/test/Makefile @@ -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 diff --git a/src/ioc/db/filters/test/arrRecord.c b/src/ioc/db/filters/test/arrRecord.c new file mode 100644 index 000000000..5e9b2f02c --- /dev/null +++ b/src/ioc/db/filters/test/arrRecord.c @@ -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 + * + * vaguely implemented like parts of recWaveform.c by Bob Dalesio + * + */ + +#include + +#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; +} diff --git a/src/ioc/db/filters/test/arrRecord.dbd b/src/ioc/db/filters/test/arrRecord.dbd new file mode 100644 index 000000000..25a45351d --- /dev/null +++ b/src/ioc/db/filters/test/arrRecord.dbd @@ -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") + } +} diff --git a/src/ioc/db/filters/test/arrTest.cpp b/src/ioc/db/filters/test/arrTest.cpp new file mode 100644 index 000000000..690bd555c --- /dev/null +++ b/src/ioc/db/filters/test/arrTest.cpp @@ -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 + */ + +/* using stuff from softIoc.cpp by Andrew Johnson */ + +#include +#include +#include +#include +#include + +#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(base_dbd); + char *db_file = const_cast(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; +} diff --git a/src/ioc/db/filters/test/arrTest.db b/src/ioc/db/filters/test/arrTest.db new file mode 100644 index 000000000..467cf0d08 --- /dev/null +++ b/src/ioc/db/filters/test/arrTest.db @@ -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") +} diff --git a/src/ioc/db/filters/test/dbndTest.c b/src/ioc/db/filters/test/dbndTest.c index 727b02906..1d3f543c5 100644 --- a/src/ioc/db/filters/test/dbndTest.c +++ b/src/ioc/db/filters/test/dbndTest.c @@ -102,7 +102,7 @@ MAIN(dbndTest) db_field_log *pfl, *pfl2; db_field_log fl1; - testPlan(0); + testPlan(61); db_init_events(); diff --git a/src/ioc/db/filters/test/tsTest.c b/src/ioc/db/filters/test/tsTest.c index 6dda76a21..f02c5d441 100644 --- a/src/ioc/db/filters/test/tsTest.c +++ b/src/ioc/db/filters/test/tsTest.c @@ -48,7 +48,7 @@ MAIN(tsTest) db_field_log fl1; db_field_log *pfl2; - testPlan(0); + testPlan(14); db_init_events();