diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index 7e50f0ddf..f200e54e6 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in the file LICENSE that is included with this distribution. +# in the file LICENSE that is included with this distribution. #************************************************************************* TOP=../../../.. @@ -60,6 +60,13 @@ testHarness_SRCS += compressTest.c TESTFILES += ../compressTest.db TESTS += compressTest +TESTPROD_HOST += asyncSoftTest +asyncSoftTest_SRCS += asyncSoftTest.c +asyncSoftTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp +testHarness_SRCS += asyncSoftTest.c +TESTFILES += ../asyncSoftTest.db +TESTS += asyncSoftTest + TARGETS += $(COMMON_DIR)/asTestIoc.dbd DBDDEPENDS_FILES += asTestIoc.dbd$(DEP) asTestIoc_DBD += base.dbd diff --git a/src/std/rec/test/asyncSoftTest.c b/src/std/rec/test/asyncSoftTest.c new file mode 100644 index 000000000..1ac9f41ef --- /dev/null +++ b/src/std/rec/test/asyncSoftTest.c @@ -0,0 +1,189 @@ +/*************************************************************************\ +* Copyright (c) 2017 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. +\*************************************************************************/ + +#include + +#include "dbAccess.h" +#include "dbStaticLib.h" +#include "dbTest.h" +#include "dbUnitTest.h" +#include "epicsEvent.h" +#include "errlog.h" +#include "registryFunction.h" +#include "subRecord.h" +#include "testMain.h" + +static int startCounter, doneCounter; +static epicsEventId asyncEvent, doneEvent; + +static +long asyncSubr(subRecord *prec) +{ + testDiag("Processing %s, pact=%d", prec->name, prec->pact); + + if (!prec->pact) { + epicsEventTrigger(asyncEvent); + prec->pact = 1; /* Make asynchronous */ + } + + return 0; +} + +static +long doneSubr(subRecord *prec) +{ + epicsEventTrigger(doneEvent); + return 0; +} + +static +void checkAsyncInput(const char *rec, int init, dbCommon *async) +{ + char inp[16], proc[16]; + + testDiag("Checking record '%s'", rec); + + strcpy(inp, rec); + strcat(inp, ".INP"); + strcpy(proc, rec); + strcat(proc, ".PROC"); + + if (init) { + testdbGetFieldEqual(rec, DBF_LONG, init); + + testdbPutFieldOk(inp, DBF_STRING, "async"); + } + + testdbPutFieldOk(proc, DBF_CHAR, 1); + + epicsEventWait(asyncEvent); + testdbGetFieldEqual("startCounter", DBF_LONG, ++startCounter); + testdbGetFieldEqual("doneCounter", DBF_LONG, doneCounter); + + dbScanLock(async); + async->rset->process(async); + dbScanUnlock(async); + + epicsEventWait(doneEvent); + testdbGetFieldEqual("startCounter", DBF_LONG, startCounter); + testdbGetFieldEqual("doneCounter", DBF_LONG, ++doneCounter); +} + +static +void testAsynInputs(dbCommon *async) +{ + const char * records[] = { + "ai0", "bi0", "di0", "ii0", "li0", "mi0", "si0", NULL, + "bi1", /* bi1 must be first in this group */ + "ai1", "di1", "ii1", "li1", "mi1", "si1", NULL, + }; + const char ** rec = &records[0]; + int init = 1; /* bi1 initializes to 1 */ + + testDiag("============ Starting %s ============", EPICS_FUNCTION); + + startCounter = doneCounter = 0; + testdbPutFieldOk("startCounter", DBF_LONG, startCounter); + testdbPutFieldOk("doneCounter", DBF_LONG, doneCounter); + + epicsEventTryWait(asyncEvent); + epicsEventTryWait(doneEvent); + + while (*rec) { /* 1st group don't need initializing */ + checkAsyncInput(*rec++, 0, async); + } + rec++; + while (*rec) { + checkAsyncInput(*rec++, init, async); + init = 9; /* remainder initialize to 9 */ + } + + testDiag("============= Ending %s =============", EPICS_FUNCTION); +} + +static +void checkAsyncOutput(const char *rec, dbCommon *async) +{ + char proc[16]; + + testDiag("Checking record '%s'", rec); + + strcpy(proc, rec); + strcat(proc, ".PROC"); + + testdbPutFieldOk(proc, DBF_CHAR, 1); + + epicsEventWait(asyncEvent); + testdbGetFieldEqual("startCounter", DBF_LONG, ++startCounter); + testdbGetFieldEqual("doneCounter", DBF_LONG, doneCounter); + + dbScanLock(async); + async->rset->process(async); + dbScanUnlock(async); + + epicsEventWait(doneEvent); + testdbGetFieldEqual("startCounter", DBF_LONG, startCounter); + testdbGetFieldEqual("doneCounter", DBF_LONG, ++doneCounter); +} + +static +void testAsyncOutputs(dbCommon *async) +{ + const char * records[] = { + "ao1", "bo1", "do1", "io1", "lo1", "lso1", "mo1", "so1", NULL, + }; + const char ** rec = &records[0]; + + testDiag("============ Starting %s ============", EPICS_FUNCTION); + + startCounter = doneCounter = 0; + testdbPutFieldOk("startCounter", DBF_LONG, startCounter); + testdbPutFieldOk("doneCounter", DBF_LONG, doneCounter); + + epicsEventTryWait(asyncEvent); + epicsEventTryWait(doneEvent); + + while (*rec) { + checkAsyncOutput(*rec++, async); + } + + testDiag("============= Ending %s =============", EPICS_FUNCTION); +} + +void recTestIoc_registerRecordDeviceDriver(struct dbBase *); + +MAIN(recMiscTest) +{ + dbCommon *async; + + testPlan(0); + + testdbPrepare(); + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); + + recTestIoc_registerRecordDeviceDriver(pdbbase); + registryFunctionAdd("asyncSubr", (REGISTRYFUNCTION) asyncSubr); + registryFunctionAdd("doneSubr", (REGISTRYFUNCTION) doneSubr); + + testdbReadDatabase("asyncSoftTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + async = testdbRecordPtr("async"); + asyncEvent = epicsEventCreate(epicsEventEmpty); + doneEvent = epicsEventCreate(epicsEventEmpty); + + testAsynInputs(async); + testAsyncOutputs(async); + + testIocShutdownOk(); + testdbCleanup(); + + return testDone(); +} diff --git a/src/std/rec/test/asyncSoftTest.db b/src/std/rec/test/asyncSoftTest.db new file mode 100644 index 000000000..6cb51422b --- /dev/null +++ b/src/std/rec/test/asyncSoftTest.db @@ -0,0 +1,188 @@ +record(ai, "ai0") { + field(DTYP, "Async Soft Channel") + field(INP, "async") + field(FLNK, "done") +} +record(bi, "bi0") { + field(DTYP, "Async Soft Channel") + field(INP, "async") + field(FLNK, "done") + field(ZNAM, "Zero") + field(ONAM, "One") +} +record(int64in, "ii0") { + field(DTYP, "Async Soft Channel") + field(INP, "async") + field(FLNK, "done") +} +record(longin, "li0") { + field(DTYP, "Async Soft Channel") + field(INP, "async") + field(FLNK, "done") +} +record(mbbiDirect, "di0") { + field(DTYP, "Async Soft Channel") + field(NOBT, 4) + field(INP, "async") + field(FLNK, "done") +} +record(mbbi, "mi0") { + field(DTYP, "Async Soft Channel") + field(NOBT, 4) + field(INP, "async") + field(FLNK, "done") + field(ZRST, "Zero") + field(ONST, "One") + field(TWST, "Two") + field(THST, "Three") + field(FRST, "Four") + field(FVST, "Five") + field(SXST, "Six") + field(SVST, "Seven") + field(EIST, "Eight") + field(NIST, "Nine") + field(TEST, "Ten") + field(ELST, "Eleven") + field(TWST, "Twelve") + field(TTST, "Thirteen") + field(FTST, "Fourteen") + field(FFST, "Fifteen") +} +record(stringin, "si0") { + field(DTYP, "Async Soft Channel") + field(INP, "async") + field(FLNK, "done") +} + +record(ai, "ai1") { + field(DTYP, "Async Soft Channel") + field(INP, {const:9}) + field(FLNK, "done") +} +record(bi, "bi1") { + field(DTYP, "Async Soft Channel") + field(INP, {const:1}) + field(FLNK, "done") + field(ZNAM, "Zero") + field(ONAM, "One") +} +record(int64in, "ii1") { + field(DTYP, "Async Soft Channel") + field(INP, {const:9}) + field(FLNK, "done") +} +record(longin, "li1") { + field(DTYP, "Async Soft Channel") + field(INP, {const:9}) + field(FLNK, "done") +} +record(mbbiDirect, "di1") { + field(DTYP, "Async Soft Channel") + field(NOBT, 4) + field(INP, {const:9}) + field(FLNK, "done") +} +record(mbbi, "mi1") { + field(DTYP, "Async Soft Channel") + field(NOBT, 4) + field(INP, {const:9}) + field(FLNK, "done") + field(ZRST, "Zero") + field(ONST, "One") + field(TWST, "Two") + field(THST, "Three") + field(FRST, "Four") + field(FVST, "Five") + field(SXST, "Six") + field(SVST, "Seven") + field(EIST, "Eight") + field(NIST, "Nine") + field(TEST, "Ten") + field(ELST, "Eleven") + field(TWST, "Twelve") + field(TTST, "Thirteen") + field(FTST, "Fourteen") + field(FFST, "Fifteen") +} +record(stringin, "si1") { + field(DTYP, "Async Soft Channel") + field(INP, {const:"9"}) + field(FLNK, "done") +} + +record(sub, "async") { + field(INPA, "startCounter PP") + field(SNAM, "asyncSubr") +} +record(calc, "startCounter") { + field(CALC, "VAL+1") +} +record(sub, "done") { + field(INPA, "doneCounter PP") + field(SNAM, "doneSubr") +} +record(calc, "doneCounter") { + field(CALC, "VAL+1") +} + +record(ao, "ao1") { + field(DTYP, "Async Soft Channel") + field(OUT, "async.PROC CA") + field(FLNK, "done") +} +record(bo, "bo1") { + field(DTYP, "Async Soft Channel") + field(OUT, "async.PROC CA") + field(FLNK, "done") + field(ZNAM, "Zero") + field(ONAM, "One") +} +record(int64out, "io1") { + field(DTYP, "Async Soft Channel") + field(OUT, "async.PROC CA") + field(FLNK, "done") +} +record(longout, "lo1") { + field(DTYP, "Async Soft Channel") + field(OUT, "async.PROC CA") + field(FLNK, "done") +} +record(mbboDirect, "do1") { + field(DTYP, "Async Soft Channel") + field(NOBT, 4) + field(OUT, "async.PROC CA") + field(FLNK, "done") +} +record(mbbo, "mo1") { + field(DTYP, "Async Soft Channel") + field(NOBT, 4) + field(OUT, "async.PROC CA") + field(FLNK, "done") + field(ZRST, "Zero") + field(ONST, "One") + field(TWST, "Two") + field(THST, "Three") + field(FRST, "Four") + field(FVST, "Five") + field(SXST, "Six") + field(SVST, "Seven") + field(EIST, "Eight") + field(NIST, "Nine") + field(TEST, "Ten") + field(ELST, "Eleven") + field(TWST, "Twelve") + field(TTST, "Thirteen") + field(FTST, "Fourteen") + field(FFST, "Fifteen") +} +record(lso, "lso1") { + field(DTYP, "Async Soft Channel") + field(OUT, "async.PROC CA") + field(FLNK, "done") + field(SIZV, 40) +} +record(stringout, "so1") { + field(DTYP, "Async Soft Channel") + field(OUT, "async.PROC CA") + field(FLNK, "done") +}