From 29490f24c7bbc00e4802c0331ee0d4f06070d47b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 31 Jul 2014 16:22:01 -0400 Subject: [PATCH 1/6] dbFreeLinkContents: missing case for RF_IO --- src/ioc/dbStatic/dbStaticLib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 636fc59fa..3d3a6ecbd 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -226,6 +226,7 @@ void dbFreeLinkContents(struct link *plink) case BITBUS_IO: parm = plink->value.bitbusio.parm;break; case INST_IO: parm = plink->value.instio.string; break; case BBGPIB_IO: parm = plink->value.bbgpibio.parm;break; + case RF_IO: break; case VXI_IO: parm = plink->value.vxiio.parm; break; default: epicsPrintf("dbFreeLink called but link type unknown\n"); From 9f53417a8d05d765ad5e090e72dabb22d650ed59 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 31 Jul 2014 16:22:01 -0400 Subject: [PATCH 2/6] add dbCaLinkInitIsolated() Initialize dbCa workList lock so that CA_LINK creation in test code doesn't crash. Once created links will never connect. clean up workList for unittest when dbCaShutdown is called state is already exit. --- src/ioc/db/dbCa.c | 85 +++++++++++++++++++++++++++--------------- src/ioc/db/dbCa.h | 3 +- src/ioc/misc/iocInit.c | 2 + 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c index c64f5713f..924e308e0 100644 --- a/src/ioc/db/dbCa.c +++ b/src/ioc/db/dbCa.c @@ -73,6 +73,7 @@ static void dbCaTask(void *); errlogPrintf("%s has DB CA link to %s\n",\ pcaLink->plink->value.pv_link.precord->name, pcaLink->pvname) +static int dbca_chan_count; /* caLink locking * @@ -163,6 +164,32 @@ static void addAction(caLink *pca, short link_action) epicsEventSignal(workListEvent); } +static void dbCaLinkFree(caLink *pca) +{ + dbCaCallback callback; + struct link *plinkPutCallback = 0; + + if (pca->chid) { + ca_clear_channel(pca->chid); + --dbca_chan_count; + } + callback = pca->putCallback; + if (callback) { + plinkPutCallback = pca->plinkPutCallback; + pca->plinkPutCallback = 0; + pca->putCallback = 0; + pca->putType = 0; + } + free(pca->pgetNative); + free(pca->pputNative); + free(pca->pgetString); + free(pca->pputString); + free(pca->pvname); + epicsMutexDestroy(pca->lock); + free(pca); + if (callback) callback(plinkPutCallback); +} + void dbCaCallbackProcess(void *usrPvt) { struct link *plink = (struct link *)usrPvt; @@ -180,7 +207,18 @@ void dbCaShutdown(void) epicsEventSignal(workListEvent); epicsEventMustWait(startStopEvent); epicsEventDestroy(startStopEvent); - epicsEventDestroy(workListEvent); + } else { + /* manually cleanup queue since dbCa thread isn't running + * which only happens in unit tests + */ + caLink *pca; + epicsMutexMustLock(workListLock); + while((pca=(caLink*)ellGet(&workList))!=NULL) { + if(pca->link_action&CA_CLEAR_CHANNEL) { + dbCaLinkFree(pca); + } + } + epicsMutexUnlock(workListLock); } } @@ -189,11 +227,20 @@ static void dbCaExit(void *arg) dbCaShutdown(); } +void dbCaLinkInitIsolated(void) +{ + if (!workListLock) + workListLock = epicsMutexMustCreate(); + if (!workListEvent) + workListEvent = epicsEventMustCreate(epicsEventEmpty); + dbCaCtl = ctlExit; + epicsAtExit(dbCaExit, NULL); +} + void dbCaLinkInit(void) { dbServiceIOInit(); - workListLock = epicsMutexMustCreate(); - workListEvent = epicsEventMustCreate(epicsEventEmpty); + dbCaLinkInitIsolated(); startStopEvent = epicsEventMustCreate(epicsEventEmpty); dbCaCtl = ctlPause; @@ -201,7 +248,6 @@ void dbCaLinkInit(void) epicsThreadGetStackSize(epicsThreadStackBig), dbCaTask, NULL); epicsEventMustWait(startStopEvent); - epicsAtExit(dbCaExit, NULL); } void dbCaRun(void) @@ -846,8 +892,6 @@ static void getAttribEventCallback(struct event_handler_args arg) static void dbCaTask(void *arg) { - int chan_count = 0; - taskwdInsert(0, NULL, NULL); SEVCHK(ca_context_create(ca_enable_preemptive_callback), "dbCaTask calling ca_context_create"); @@ -877,29 +921,8 @@ static void dbCaTask(void *arg) if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding; epicsMutexUnlock(workListLock); /* Give back immediately */ if (link_action & CA_CLEAR_CHANNEL) { /* This must be first */ - dbCaCallback callback; - struct link *plinkPutCallback = 0; - - if (pca->chid) { - ca_clear_channel(pca->chid); - --chan_count; - } - callback = pca->putCallback; - if (callback) { - plinkPutCallback = pca->plinkPutCallback; - pca->plinkPutCallback = 0; - pca->putCallback = 0; - pca->putType = 0; - } - free(pca->pgetNative); - free(pca->pputNative); - free(pca->pgetString); - free(pca->pputString); - free(pca->pvname); - epicsMutexDestroy(pca->lock); - free(pca); + dbCaLinkFree(pca); /* No alarm is raised. Since link is changing so what? */ - if (callback) callback(plinkPutCallback); continue; /* No other link_action makes sense */ } if (link_action & CA_CONNECT) { @@ -912,7 +935,7 @@ static void dbCaTask(void *arg) printLinks(pca); continue; } - chan_count++; + dbca_chan_count++; status = ca_replace_access_rights_event(pca->chid, accessRightsCallback); if (status != ECA_NORMAL) { @@ -1014,9 +1037,9 @@ static void dbCaTask(void *arg) } shutdown: taskwdRemove(0); - if (chan_count == 0) + if (dbca_chan_count == 0) ca_context_destroy(); else - fprintf(stderr, "dbCa: chan_count = %d at shutdown\n", chan_count); + fprintf(stderr, "dbCa: chan_count = %d at shutdown\n", dbca_chan_count); epicsEventSignal(startStopEvent); } diff --git a/src/ioc/db/dbCa.h b/src/ioc/db/dbCa.h index a147307bf..cfdf7321f 100644 --- a/src/ioc/db/dbCa.h +++ b/src/ioc/db/dbCa.h @@ -23,7 +23,8 @@ extern "C" { typedef void (*dbCaCallback)(void *userPvt); epicsShareFunc void dbCaCallbackProcess(void *usrPvt); -epicsShareFunc void dbCaLinkInit(void); +epicsShareFunc void dbCaLinkInit(void); /* internal initialization for iocBuild() */ +epicsShareFunc void dbCaLinkInitIsolated(void); /* internal initialization for iocBuildIsolated() */ epicsShareFunc void dbCaRun(void); epicsShareFunc void dbCaPause(void); epicsShareFunc void dbCaShutdown(void); diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c index 5e950af47..77bcb32a0 100644 --- a/src/ioc/misc/iocInit.c +++ b/src/ioc/misc/iocInit.c @@ -192,6 +192,8 @@ int iocBuildIsolated(void) status = iocBuild_1(); if (status) return status; + dbCaLinkInitIsolated(); + status = iocBuild_2(); if (status) return status; From 40838579af4b91d8adcb921227be648971a186fa Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 31 Jul 2014 16:22:01 -0400 Subject: [PATCH 3/6] iocShutdown: cleanup links --- src/ioc/dbStatic/dbStaticLib.c | 2 +- src/ioc/misc/iocInit.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 3d3a6ecbd..43a371b7a 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -229,7 +229,7 @@ void dbFreeLinkContents(struct link *plink) case RF_IO: break; case VXI_IO: parm = plink->value.vxiio.parm; break; default: - epicsPrintf("dbFreeLink called but link type unknown\n"); + epicsPrintf("dbFreeLink called but link type %d unknown\n", plink->type); } if(parm && (parm != pNullString)) free((void *)parm); if(plink->text) free(plink->text); diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c index 77bcb32a0..73f8ebd00 100644 --- a/src/ioc/misc/iocInit.c +++ b/src/ioc/misc/iocInit.c @@ -623,6 +623,11 @@ static void doCloseLinks(dbRecordType *pdbRecordType, dbCommon *precord, } dbCaRemoveLink(plink); plink->type = CONSTANT; + + } else if (plink->type == DB_LINK) { + /* free link, but don't split lockset like dbDbRemoveLink() */ + free(plink->value.pv_link.pvt); + plink->type = CONSTANT; } } @@ -646,11 +651,20 @@ static void doCloseLinks(dbRecordType *pdbRecordType, dbCommon *precord, static void doFreeRecord(dbRecordType *pdbRecordType, dbCommon *precord, void *user) { + int j; struct rset *prset = pdbRecordType->prset; if (!prset) return; /* unlikely */ epicsMutexDestroy(precord->mlok); + + for (j = 0; j < pdbRecordType->no_links; j++) { + dbFldDes *pdbFldDes = + pdbRecordType->papFldDes[pdbRecordType->link_ind[j]]; + DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset); + + dbFreeLinkContents(plink); + } } int iocShutdown(void) From e09066cfabb427240ac78af1219fb6fb4ff35b3e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 31 Jul 2014 16:22:01 -0400 Subject: [PATCH 4/6] dbPutLinkTest: check parsing of CA_LINK --- src/ioc/db/test/dbPutLinkTest.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index a5a4e8084..c6f6adb77 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -39,6 +39,7 @@ static const struct testDataT { {"", CONSTANT, 0}, {"0", CONSTANT, 0}, {"42", CONSTANT, 0}, + {"x1", DB_LINK, 0, "x1 NPP NMS"}, {"x1.VAL", DB_LINK, 0, "x1.VAL NPP NMS"}, {"x1.TIME", DB_LINK, 0, "x1.TIME NPP NMS"}, @@ -46,7 +47,12 @@ static const struct testDataT { {"x1 PP MSS", DB_LINK, pvlOptPP|pvlOptMSS, "x1 PP MSS"}, {"x1 PPMSS", DB_LINK, pvlOptPP|pvlOptMSS, "x1 PP MSS"}, {"x1 PPMSI", DB_LINK, pvlOptPP|pvlOptMSI, "x1 PP MSI"}, - /*TODO: testing doesn't support CA_LINK yet */ + + {"qq", CA_LINK, pvlOptInpNative, "qq NPP NMS"}, + {"qq MSI", CA_LINK, pvlOptInpNative|pvlOptMSI, "qq NPP MSI"}, + {"qq MSICA", CA_LINK, pvlOptInpNative|pvlOptCA|pvlOptMSI, "qq CA MSI"}, + + {"x1 CA", CA_LINK, pvlOptInpNative|pvlOptCA, "x1 CA NMS"}, {NULL} }; @@ -71,6 +77,7 @@ static void testSet(void) plink = &prec->lnk; for(;td->linkstring;td++) { + testDiag("x1.LNK <- \"%s\"", td->linkstring); testdbPutFieldOk("x1.LNK", DBF_STRING, td->linkstring); if(td->linkback) @@ -91,7 +98,9 @@ static void testSet(void) break; case DB_LINK: - testOk1(plink->value.pv_link.pvlMask==td->pvlMask); + case CA_LINK: + testOk(plink->value.pv_link.pvlMask==td->pvlMask, + "pvlMask %x == %x", plink->value.pv_link.pvlMask, td->pvlMask); break; } } @@ -104,7 +113,7 @@ static void testSet(void) MAIN(dbPutLinkTest) { - testPlan(40); + testPlan(56); testSet(); return testDone(); } From d05f2e6062bcbab8b40e674a8ee5838462fce663 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 31 Jul 2014 16:22:02 -0400 Subject: [PATCH 5/6] dbPutLinkTest: check HW link parsing --- src/ioc/db/test/Makefile | 4 +- src/ioc/db/test/dbBadLink.db | 16 ++ src/ioc/db/test/dbLinkdset.c | 40 +++++ src/ioc/db/test/dbLinkdset.dbd | 11 ++ src/ioc/db/test/dbPutLinkTest.c | 288 ++++++++++++++++++++++++++++++- src/ioc/db/test/dbPutLinkTest.db | 41 +++++ src/ioc/db/test/xRecord.dbd | 3 + 7 files changed, 397 insertions(+), 6 deletions(-) create mode 100644 src/ioc/db/test/dbBadLink.db create mode 100644 src/ioc/db/test/dbLinkdset.c create mode 100644 src/ioc/db/test/dbLinkdset.dbd diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 2c374985b..f85f62f8c 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -12,13 +12,15 @@ include $(TOP)/configure/CONFIG TESTLIBRARY = dbTestIoc -dbTestIoc_SRCS = xRecord.c +dbTestIoc_SRCS += xRecord.c +dbTestIoc_SRCS += dbLinkdset.c dbTestIoc_LIBS = dbCore TARGETS += $(COMMON_DIR)/dbTestIoc.dbd dbTestIoc_DBD += menuGlobal.dbd dbTestIoc_DBD += menuConvert.dbd dbTestIoc_DBD += xRecord.dbd +dbTestIoc_DBD += dbLinkdset.dbd TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db testHarness_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp diff --git a/src/ioc/db/test/dbBadLink.db b/src/ioc/db/test/dbBadLink.db new file mode 100644 index 000000000..6c41e854b --- /dev/null +++ b/src/ioc/db/test/dbBadLink.db @@ -0,0 +1,16 @@ +# The records in this file have intentional +# syntax error in their input links + +record(x, "eVME_IO1") { + field(DTYP, "Unit Test VME_IO") + field(INP, "C100 S101 @parm VME_IO") +} +record(x, "eVME_IO2") { + field(DTYP, "Unit Test VME_IO") + field(INP, "#C200 201 @parm VME_IO") +} + +record(x, "eINST_IO") { + field(DTYP, "Unit Test INST_IO") + field(INP, "hello") +} diff --git a/src/ioc/db/test/dbLinkdset.c b/src/ioc/db/test/dbLinkdset.c new file mode 100644 index 000000000..dce258a3f --- /dev/null +++ b/src/ioc/db/test/dbLinkdset.c @@ -0,0 +1,40 @@ + +#include + +#include + +#include + +static +long link_test_extend(struct dbCommon *junk) +{ return 0; } + +static dsxt xrecextend = {&link_test_extend, &link_test_extend}; + +static +long link_test_init(int junk) +{ + devExtend(&xrecextend); + return 0; +} + +static +long link_test_noop(void *junk) +{ return 0; } + + + +#define DEFDSET(LTYPE) \ + static dset devxLTest ## LTYPE = {4, NULL, &link_test_init, &link_test_noop, &link_test_noop}; \ + epicsExportAddress(dset, devxLTest ## LTYPE); + +DEFDSET(Soft) +DEFDSET(VME_IO) +DEFDSET(CAMAC_IO) +DEFDSET(AB_IO) +DEFDSET(GPIB_IO) +DEFDSET(BITBUS_IO) +DEFDSET(INST_IO) +DEFDSET(BBGPIB_IO) +DEFDSET(RF_IO) +DEFDSET(VXI_IO) diff --git a/src/ioc/db/test/dbLinkdset.dbd b/src/ioc/db/test/dbLinkdset.dbd new file mode 100644 index 000000000..b1e070c66 --- /dev/null +++ b/src/ioc/db/test/dbLinkdset.dbd @@ -0,0 +1,11 @@ +device(x, CONSTANT,devxLTestSoft,"Soft Channel") + +device(x, VME_IO, devxLTestVME_IO, "Unit Test VME_IO") +device(x, CAMAC_IO, devxLTestCAMAC_IO, "Unit Test CAMAC_IO") +device(x, AB_IO, devxLTestAB_IO, "Unit Test AB_IO") +device(x, GPIB_IO, devxLTestGPIB_IO, "Unit Test GPIB_IO") +device(x, BITBUS_IO, devxLTestBITBUS_IO, "Unit Test BITBUS_IO") +device(x, INST_IO, devxLTestINST_IO, "Unit Test INST_IO") +device(x, BBGPIB_IO, devxLTestBBGPIB_IO, "Unit Test BBGPIB_IO") +device(x, RF_IO, devxLTestRF_IO, "Unit Test RF_IO") +device(x, VXI_IO, devxLTestVXI_IO, "Unit Test VXI_IO") diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index c6f6adb77..75e01b2d7 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -31,10 +31,10 @@ void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); static const struct testDataT { - const char *linkstring; + const char * const linkstring; short linkType; unsigned int pvlMask; - const char *linkback; + const char * const linkback; } testSetData[] = { {"", CONSTANT, 0}, {"0", CONSTANT, 0}, @@ -56,11 +56,12 @@ static const struct testDataT { {NULL} }; -static void testSet(void) +static void testCADBSet(void) { const struct testDataT *td = testSetData; xRecord *prec; DBLINK *plink; + testDiag("DB/CA link retargeting"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -111,9 +112,286 @@ static void testSet(void) testdbCleanup(); } +typedef struct { + const char * const recname; + short ltype; + const char * const wval; + short vals[5]; + const char * const parm; +} testHWDataT; + +static const testHWDataT testHWData[] = { + {"rVME_IO", VME_IO, "#C100 S101 @parm VME_IO", {100, 101}, "parm VME_IO"}, + {"rCAMAC_IO", CAMAC_IO, "#B11 C12 N13 A14 F15 @parm CAMAC_IO", {11, 12, 13, 14, 15}, "parm CAMAC_IO"}, + {"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"}, + {"rGPIB_IO", GPIB_IO, "#L31 A32 @parm GPIB_IO", {31, 32}, "parm GPIB_IO"}, + {"rBITBUS_IO", BITBUS_IO, "#L41 N42 P43 S44 @parm BITBUS_IO", {41, 42, 43, 44}, "parm BITBUS_IO"}, + {"rINST_IO", INST_IO, "@parm INST_IO", {}, "parm INST_IO"}, + {"rBBGPIB_IO", BBGPIB_IO, "#L51 B52 G53 @parm BBGPIB_IO", {51, 52, 53}, "parm BBGPIB_IO"}, + {"rRF_IO", RF_IO, "#R61 M62 D63 E64", {61, 62, 63, 64}, NULL}, + {"rVXI_IO1", VXI_IO, "#V71 C72 S73 @parm1 VXI_IO", {71, 72, 73}, "parm1 VXI_IO"}, + {"rVXI_IO2", VXI_IO, "#V81 S82 @parm2 VXI_IO", {81, 82}, "parm2 VXI_IO"}, + {NULL} +}; + +static void testLink(DBLINK *plink, const testHWDataT *td) +{ + switch(td->ltype) { + case VME_IO: + testOk1(plink->value.vmeio.card==td->vals[0]); + testOk1(plink->value.vmeio.signal==td->vals[1]); + testOk1(strcmp(plink->value.vmeio.parm, td->parm)==0); + break; + case CAMAC_IO: + testOk1(plink->value.camacio.b==td->vals[0]); + testOk1(plink->value.camacio.c==td->vals[1]); + testOk1(plink->value.camacio.n==td->vals[2]); + testOk1(plink->value.camacio.a==td->vals[3]); + testOk1(plink->value.camacio.f==td->vals[4]); + testOk1(strcmp(plink->value.camacio.parm, td->parm)==0); + break; + case AB_IO: + testOk1(plink->value.abio.link==td->vals[0]); + testOk1(plink->value.abio.adapter==td->vals[1]); + testOk1(plink->value.abio.card==td->vals[2]); + testOk1(plink->value.abio.signal==td->vals[3]); + testOk1(strcmp(plink->value.abio.parm, td->parm)==0); + break; + case GPIB_IO: + testOk1(plink->value.gpibio.link==td->vals[0]); + testOk1(plink->value.gpibio.addr==td->vals[1]); + testOk1(strcmp(plink->value.gpibio.parm, td->parm)==0); + break; + case BITBUS_IO: + testOk1(plink->value.bitbusio.link==td->vals[0]); + testOk1(plink->value.bitbusio.node==td->vals[1]); + testOk1(plink->value.bitbusio.port==td->vals[2]); + testOk1(plink->value.bitbusio.signal==td->vals[3]); + testOk1(strcmp(plink->value.bitbusio.parm, td->parm)==0); + break; + case INST_IO: + testOk1(strcmp(plink->value.instio.string, td->parm)==0); + break; + case BBGPIB_IO: + testOk1(plink->value.bbgpibio.link==td->vals[0]); + testOk1(plink->value.bbgpibio.bbaddr==td->vals[1]); + testOk1(plink->value.bbgpibio.gpibaddr==td->vals[2]); + testOk1(strcmp(plink->value.bbgpibio.parm, td->parm)==0); + break; + case RF_IO: + testOk1(plink->value.rfio.cryo==td->vals[0]); + testOk1(plink->value.rfio.micro==td->vals[1]); + testOk1(plink->value.rfio.dataset==td->vals[2]); + testOk1(plink->value.rfio.element==td->vals[3]); + break; + case VXI_IO: + if(plink->value.vxiio.flag==VXIDYNAMIC) { + testOk1(plink->value.vxiio.frame==td->vals[0]); + testOk1(plink->value.vxiio.slot==td->vals[1]); + testOk1(plink->value.vxiio.signal==td->vals[2]); + } else { + testOk1(plink->value.vxiio.la==td->vals[0]); + testOk1(plink->value.vxiio.signal==td->vals[1]); + } + testOk1(strcmp(plink->value.vxiio.parm, td->parm)==0); + break; + } +} + +static void testHWInitSet(void) +{ + const testHWDataT *td = testHWData; + testDiag("HW link parsing during initialization"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("dbPutLinkTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + for(;td->recname;td++) { + char buf[MAX_STRING_SIZE]; + xRecord *prec; + DBLINK *plink; + testDiag("%s == \"%s\"", td->recname, td->wval); + + prec = (xRecord*)testdbRecordPtr(td->recname); + plink = &prec->inp; + + strcpy(buf, td->recname); + strcat(buf, ".INP"); + + testdbGetFieldEqual(buf, DBR_STRING, td->wval); + + testOk(plink->type==td->ltype, "link type %d == %d", + plink->type, td->ltype); + if(plink->type==td->ltype) { + testLink(plink, td); + } + + } + + testIocShutdownOk(); + + testdbCleanup(); +} + +static const testHWDataT testHWData2[] = { + {"rVME_IO", VME_IO, "#C200 S201 @another VME_IO", {200, 201}, "another VME_IO"}, + {"rCAMAC_IO", CAMAC_IO, "#B111 C112 N113 A114 F115 @CAMAC_IO", {111, 112, 113, 114, 115}, "CAMAC_IO"}, + {"rAB_IO", AB_IO, "#L121 A122 C123 S124 @another AB_IO", {121, 122, 123, 124}, "another AB_IO"}, + {"rGPIB_IO", GPIB_IO, "#L131 A132 @another GPIB_IO", {131, 132}, "another GPIB_IO"}, + {"rBITBUS_IO", BITBUS_IO, "#L141 N142 P143 S144 @BITBUS_IO", {141, 142, 143, 144}, "BITBUS_IO"}, + {"rINST_IO", INST_IO, "@another INST_IO", {}, "another INST_IO"}, + {"rBBGPIB_IO", BBGPIB_IO, "#L151 B152 G153 @another BBGPIB_IO", {151, 152, 153}, "another BBGPIB_IO"}, + {"rRF_IO", RF_IO, "#R161 M162 D163 E164", {161, 162, 163, 164}, NULL}, + {"rVXI_IO1", VXI_IO, "#V171 C172 S173 @another1 VXI_IO", {171, 172, 173}, "another1 VXI_IO"}, + {"rVXI_IO2", VXI_IO, "#V181 S182 @another2 VXI_IO", {181, 182}, "another2 VXI_IO"}, + {NULL} +}; + +static void testHWMod(void) +{ + const testHWDataT *td = testHWData2; + testDiag("HW link parsing during retarget"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("dbPutLinkTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + for(;td->recname;td++) { + char buf[MAX_STRING_SIZE]; + xRecord *prec; + DBLINK *plink; + testDiag("%s -> \"%s\"", td->recname, td->wval); + + prec = (xRecord*)testdbRecordPtr(td->recname); + plink = &prec->inp; + + strcpy(buf, td->recname); + strcat(buf, ".INP"); + + testdbPutFieldOk(buf, DBR_STRING, td->wval); + + testdbGetFieldEqual(buf, DBR_STRING, td->wval); + + testOk(plink->type==td->ltype, "link type %d == %d", + plink->type, td->ltype); + if(plink->type==td->ltype) { + testLink(plink, td); + } + + } + + testIocShutdownOk(); + + testdbCleanup(); +} + +static void testLinkInitFail(void) +{ + xRecord *prec; + DBLINK *plink; + testDiag("Link parsing failures during initialization"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + + /* this load will fail */ + eltc(0); + testOk1(dbReadDatabase(&pdbbase, "dbBadLink.db", "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR + "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL)!=0); + + testIocInitOk(); + eltc(1); + + testdbGetFieldEqual("eVME_IO1.INP", DBR_STRING, "#C0 S0 @"); + + prec = (xRecord*)testdbRecordPtr("eVME_IO1"); + plink = &prec->inp; + testOk1(plink->type==VME_IO); + testOk1(plink->value.vmeio.parm!=NULL); + + testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C200 S0 @"); + + prec = (xRecord*)testdbRecordPtr("eVME_IO2"); + plink = &prec->inp; + testOk1(plink->type==VME_IO); + testOk1(plink->value.vmeio.parm!=NULL); + + testdbGetFieldEqual("eINST_IO.INP", DBR_STRING, "@"); + + prec = (xRecord*)testdbRecordPtr("eINST_IO"); + plink = &prec->inp; + testOk1(plink->type==INST_IO); + testOk1(plink->value.instio.string!=NULL); + + testIocShutdownOk(); + + testdbCleanup(); +} + +static void testLinkFail(void) +{ + testDiag("Link parsing failures"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("dbPutLinkTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + /* INST_IO doesn't accept empty string */ + testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, ""); + + /* INST_IO accepts invalid input as empty string */ + testdbPutFieldOk("rINST_IO.INP", DBR_STRING, "abc"); + testdbGetFieldEqual("rINST_IO.INP", DBR_STRING, "@"); + + /* syntax errors */ + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO"); + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "C200 #S201"); + + /* VME_IO doesn't accept empty string */ + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, ""); + + testdbPutFieldOk("rVME_IO.INP", DBR_STRING, "#C1 S2 @hello"); + + /* VME_IO fails invalid input */ + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "abc"); + + testIocShutdownOk(); + + testdbCleanup(); +} + MAIN(dbPutLinkTest) { - testPlan(56); - testSet(); + testPlan(200); + testCADBSet(); + testHWInitSet(); + testHWMod(); + testLinkInitFail(); + testLinkFail(); return testDone(); } diff --git a/src/ioc/db/test/dbPutLinkTest.db b/src/ioc/db/test/dbPutLinkTest.db index 940ea2e7f..7753b5b08 100644 --- a/src/ioc/db/test/dbPutLinkTest.db +++ b/src/ioc/db/test/dbPutLinkTest.db @@ -2,3 +2,44 @@ record(x, "x1") {} record(x, "x2") {} record(x, "x3") {} record(x, "x4") {} + +record(x, "rVME_IO") { + field(DTYP, "Unit Test VME_IO") + field(INP, "#C100 S101 @parm VME_IO") +} +record(x, "rCAMAC_IO") { + field(DTYP, "Unit Test CAMAC_IO") + field(INP, "#B11 C12 N13 A14 F15 @parm CAMAC_IO") +} +record(x, "rAB_IO") { + field(DTYP, "Unit Test AB_IO") + field(INP, "#L21 A22 C23 S24 @parm AB_IO") +} +record(x, "rGPIB_IO") { + field(DTYP, "Unit Test GPIB_IO") + field(INP, "#L31 A32 @parm GPIB_IO") +} +record(x, "rBITBUS_IO") { + field(DTYP, "Unit Test BITBUS_IO") + field(INP, "#L41 N42 P43 S44 @parm BITBUS_IO") +} +record(x, "rINST_IO") { + field(DTYP, "Unit Test INST_IO") + field(INP, "@parm INST_IO") +} +record(x, "rBBGPIB_IO") { + field(DTYP, "Unit Test BBGPIB_IO") + field(INP, "#L51 B52 G53 @parm BBGPIB_IO") +} +record(x, "rRF_IO") { + field(DTYP, "Unit Test RF_IO") + field(INP, "#R61 M62 D63 E64") +} +record(x, "rVXI_IO1") { + field(DTYP, "Unit Test VXI_IO") + field(INP, "#V71 C72 S73 @parm1 VXI_IO") +} +record(x, "rVXI_IO2") { + field(DTYP, "Unit Test VXI_IO") + field(INP, "#V81 S82 @parm2 VXI_IO") +} diff --git a/src/ioc/db/test/xRecord.dbd b/src/ioc/db/test/xRecord.dbd index 8f4b2156c..fb230f563 100644 --- a/src/ioc/db/test/xRecord.dbd +++ b/src/ioc/db/test/xRecord.dbd @@ -8,4 +8,7 @@ recordtype(x) { field(LNK, DBF_INLINK) { prompt("Link") } + field(INP, DBF_INLINK) { + prompt("Input Link") + } } From 6225602777a36f7bed19fc2dd877fdc95a14a586 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 18 Sep 2014 10:51:09 +0200 Subject: [PATCH 6/6] ioc/db/test: fix dbPutLinkTest.c to compile on Windows --- src/ioc/db/test/dbPutLinkTest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index 75e01b2d7..001b28c35 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -126,7 +126,7 @@ static const testHWDataT testHWData[] = { {"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"}, {"rGPIB_IO", GPIB_IO, "#L31 A32 @parm GPIB_IO", {31, 32}, "parm GPIB_IO"}, {"rBITBUS_IO", BITBUS_IO, "#L41 N42 P43 S44 @parm BITBUS_IO", {41, 42, 43, 44}, "parm BITBUS_IO"}, - {"rINST_IO", INST_IO, "@parm INST_IO", {}, "parm INST_IO"}, + {"rINST_IO", INST_IO, "@parm INST_IO", {0}, "parm INST_IO"}, {"rBBGPIB_IO", BBGPIB_IO, "#L51 B52 G53 @parm BBGPIB_IO", {51, 52, 53}, "parm BBGPIB_IO"}, {"rRF_IO", RF_IO, "#R61 M62 D63 E64", {61, 62, 63, 64}, NULL}, {"rVXI_IO1", VXI_IO, "#V71 C72 S73 @parm1 VXI_IO", {71, 72, 73}, "parm1 VXI_IO"}, @@ -247,7 +247,7 @@ static const testHWDataT testHWData2[] = { {"rAB_IO", AB_IO, "#L121 A122 C123 S124 @another AB_IO", {121, 122, 123, 124}, "another AB_IO"}, {"rGPIB_IO", GPIB_IO, "#L131 A132 @another GPIB_IO", {131, 132}, "another GPIB_IO"}, {"rBITBUS_IO", BITBUS_IO, "#L141 N142 P143 S144 @BITBUS_IO", {141, 142, 143, 144}, "BITBUS_IO"}, - {"rINST_IO", INST_IO, "@another INST_IO", {}, "another INST_IO"}, + {"rINST_IO", INST_IO, "@another INST_IO", {0}, "another INST_IO"}, {"rBBGPIB_IO", BBGPIB_IO, "#L151 B152 G153 @another BBGPIB_IO", {151, 152, 153}, "another BBGPIB_IO"}, {"rRF_IO", RF_IO, "#R161 M162 D163 E164", {161, 162, 163, 164}, NULL}, {"rVXI_IO1", VXI_IO, "#V171 C172 S173 @another1 VXI_IO", {171, 172, 173}, "another1 VXI_IO"},