Merge changes from 3.16 branch into 7.0
This commit is contained in:
@@ -96,6 +96,17 @@ testHarness_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/analogMonitorTest.dbd ../analogMonitorTest.db
|
||||
TESTS += analogMonitorTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/scanEventTest.dbd
|
||||
DBDDEPENDS_FILES += scanEventTest.dbd$(DEP)
|
||||
scanEventTest_DBD += base.dbd
|
||||
TESTPROD_HOST += scanEventTest
|
||||
scanEventTest_SRCS += scanEventTest.c
|
||||
scanEventTest_SRCS += scanEventTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += scanEventTest.c
|
||||
testHarness_SRCS += scanEventTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/scanEventTest.dbd ../scanEventTest.db
|
||||
TESTS += scanEventTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/regressTest.dbd
|
||||
DBDDEPENDS_FILES += regressTest.dbd$(DEP)
|
||||
regressTest_DBD += base.dbd
|
||||
@@ -118,6 +129,13 @@ testHarness_SRCS += simmTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/simmTest.dbd $(COMMON_DIR)/simmTest.db
|
||||
TESTS += simmTest
|
||||
|
||||
TESTPROD_HOST += mbbioDirectTest
|
||||
mbbioDirectTest_SRCS += mbbioDirectTest.c
|
||||
mbbioDirectTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += mbbioDirectTest.c
|
||||
TESTFILES += ../mbbioDirectTest.db
|
||||
TESTS += mbbioDirectTest
|
||||
|
||||
# epicsRunRecordTests runs all the test programs in a known working order.
|
||||
testHarness_SRCS += epicsRunRecordTests.c
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ int linkRetargetLinkTest(void);
|
||||
int linkInitTest(void);
|
||||
int asyncSoftTest(void);
|
||||
int simmTest(void);
|
||||
int mbbioDirectTest(void);
|
||||
int scanEventTest(void);
|
||||
|
||||
void epicsRunRecordTests(void)
|
||||
{
|
||||
@@ -44,5 +46,9 @@ void epicsRunRecordTests(void)
|
||||
|
||||
runTest(simmTest);
|
||||
|
||||
runTest(mbbioDirectTest);
|
||||
|
||||
runTest(scanEventTest);
|
||||
|
||||
epicsExit(0); /* Trigger test harness */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2017 Dirk Zimoch
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/* Theory of Operation
|
||||
*
|
||||
* For each of the two soft device supports (soft/raw soft/soft),
|
||||
* there is a combination of mbboDirect -> val / sim -> mbbiDirect.
|
||||
*
|
||||
* The intermediate records are of type double (val) and long (sim) to
|
||||
* check conversion from/to double.
|
||||
*
|
||||
* For each device support, the following is done:
|
||||
* 1. The mbboDirect record is set to a specific value through the database.
|
||||
* 2. The initial value is checked on both ends.
|
||||
* 3. Two single bits (5 & 31) are toggled, values checked on both ends.
|
||||
* 4. Sim mode is activated, one bit (0) is toggled, values are checked,
|
||||
* data path (old value in val, new value in sim) is checked.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dbAccess.h"
|
||||
#include "errlog.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbTest.h"
|
||||
#include "dbUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
static
|
||||
void testmbbioFields(const char* rec, unsigned int value)
|
||||
{
|
||||
char field[40];
|
||||
unsigned int i;
|
||||
|
||||
testdbGetFieldEqual(rec, DBF_ULONG, value);
|
||||
for (i=0; i < 32; i++)
|
||||
{
|
||||
sprintf(field,"%s.B%X", rec, i);
|
||||
testdbGetFieldEqual(field, DBF_ULONG, (value>>i)&1);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void testmbbioRecords(unsigned int count, unsigned int value)
|
||||
{
|
||||
char rec[40];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
sprintf(rec, "do%d", i);
|
||||
testDiag(" ### %s ###", rec);
|
||||
testmbbioFields(rec, value);
|
||||
sprintf(rec, "di%d", i);
|
||||
testmbbioFields(rec, value);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void putN(const char* pattern, unsigned int count, unsigned int value)
|
||||
{
|
||||
char field[40];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
sprintf(field, pattern, i);
|
||||
testdbPutFieldOk(field, DBF_ULONG, value);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void testN(const char* pattern, unsigned int count, unsigned int value)
|
||||
{
|
||||
char field[40];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
sprintf(field, pattern, i);
|
||||
testdbGetFieldEqual(field, DBF_ULONG, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(mbbioDirectTest)
|
||||
{
|
||||
unsigned int value = 0xdeadbeef;
|
||||
unsigned int simvalue = 0;
|
||||
char macros [40];
|
||||
const unsigned int N = 2;
|
||||
|
||||
testPlan(N*((32+1)*2*4+4+3));
|
||||
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
|
||||
|
||||
recTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
sprintf(macros, "INIT=%#x", value);
|
||||
testdbReadDatabase("mbbioDirectTest.db", NULL, macros);
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
testDiag("##### check initial value #####");
|
||||
testmbbioRecords(N, value);
|
||||
|
||||
testDiag("##### set bit 5 #####");
|
||||
putN("do%u.B5", N, 1);
|
||||
value |= (1<<5);
|
||||
testN("val%d", N, value);
|
||||
testmbbioRecords(N, value);
|
||||
|
||||
testDiag("##### clear bit 31 (0x1f) #####");
|
||||
putN("do%u.B1F", N, 0);
|
||||
value &= ~(1<<31);
|
||||
testN("val%d", N, value);
|
||||
testmbbioRecords(N, value);
|
||||
|
||||
testDiag("##### simulation mode #####");
|
||||
dbpf("sim", "1");
|
||||
simvalue = value & ~1;
|
||||
putN("do%u.B0", N, 0);
|
||||
/* old value in lo* */
|
||||
testN("val%d", N, value);
|
||||
/* sim value in sim* */
|
||||
testN("sim%d", N, simvalue);
|
||||
testmbbioRecords(N, simvalue);
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
record(bo, "sim") {
|
||||
field(ZNAM, "off")
|
||||
field(ONAM, "simulation")
|
||||
}
|
||||
|
||||
record(mbboDirect, "do1") {
|
||||
field(DOL, "$(INIT=0)")
|
||||
field(DTYP, "Soft Channel")
|
||||
field(OUT, "val1 PP")
|
||||
field(SIOL, "sim1 PP")
|
||||
field(SIML, "sim")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
record(ao, "val1") {
|
||||
field(FLNK, "di1")
|
||||
}
|
||||
record(longout, "sim1") {
|
||||
field(FLNK, "di1")
|
||||
}
|
||||
record(mbbiDirect, "di1") {
|
||||
field(DTYP, "Soft Channel")
|
||||
field(INP, "val1")
|
||||
field(SIOL, "sim1 PP")
|
||||
field(SIML, "sim")
|
||||
}
|
||||
|
||||
|
||||
record(mbboDirect, "do2") {
|
||||
field(DOL, "$(INIT=0)")
|
||||
field(DTYP, "Raw Soft Channel")
|
||||
field(OUT, "val2 PP")
|
||||
field(SIOL, "sim2 PP")
|
||||
field(SIML, "sim")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
record(ao, "val2") {
|
||||
field(FLNK, "di2")
|
||||
}
|
||||
record(longout, "sim2") {
|
||||
field(FLNK, "di2")
|
||||
}
|
||||
record(mbbiDirect, "di2") {
|
||||
field(DTYP, "Raw Soft Channel")
|
||||
field(INP, "val2")
|
||||
field(SIML, "sim")
|
||||
field(SIOL, "sim2")
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2018 Paul Scherrer Institut
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Dirk Zimoch <dirk.zimoch@psi.ch>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
#include "epicsThread.h"
|
||||
#include "dbScan.h"
|
||||
|
||||
void scanEventTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
/* test name to event number:
|
||||
num = 0 is no event,
|
||||
num > 0 is numeric event
|
||||
num < 0 is string event (use same unique number for aliases)
|
||||
*/
|
||||
const struct {char* name; int num;} events[] = {
|
||||
/* No events */
|
||||
{NULL, 0},
|
||||
{"", 0},
|
||||
{" ", 0},
|
||||
{"0", 0},
|
||||
{"0.000000", 0},
|
||||
{"-0.00000", 0},
|
||||
{"0.9", 0},
|
||||
/* Numeric events */
|
||||
{"2", 2},
|
||||
{"2.000000", 2},
|
||||
{"2.5", 2},
|
||||
{" 2.5 ", 2},
|
||||
{"+0x02", 2},
|
||||
{"3", 3},
|
||||
/* Named events */
|
||||
{"info 1", -1},
|
||||
{" info 1 ", -1},
|
||||
{"-0.9", -2},
|
||||
{"-2", -3},
|
||||
{"-2.000000", -4},
|
||||
{"-2.5", -5},
|
||||
{" -2.5 ", -5},
|
||||
{"nan", -6},
|
||||
{"NaN", -7},
|
||||
{"-NAN", -8},
|
||||
{"-inf", -9},
|
||||
{"inf", -10},
|
||||
};
|
||||
|
||||
MAIN(scanEventTest)
|
||||
{
|
||||
int i, e;
|
||||
int aliases[512] ;
|
||||
int expected_count[512];
|
||||
#define INDX(i) 256-events[i].num
|
||||
#define MAXEV 5
|
||||
|
||||
testPlan(NELEMENTS(events)*2+(MAXEV+1)*5);
|
||||
|
||||
testdbPrepare();
|
||||
|
||||
memset(aliases, 0, sizeof(aliases));
|
||||
memset(expected_count, 0, sizeof(expected_count));
|
||||
|
||||
testdbReadDatabase("scanEventTest.dbd", NULL, NULL);
|
||||
|
||||
scanEventTest_registerRecordDeviceDriver(pdbbase);
|
||||
for (i = 0; i < NELEMENTS(events); i++) {
|
||||
char substitutions[256];
|
||||
sprintf(substitutions, "N=%d,EVENT=%s", i, events[i].name);
|
||||
testdbReadDatabase("scanEventTest.db", NULL, substitutions);
|
||||
}
|
||||
testIocInitOk();
|
||||
testDiag("Test if eventNameToHandle() strips spaces and handles numeric events");
|
||||
for (i = 0; i < NELEMENTS(events); i++) {
|
||||
EVENTPVT pev = eventNameToHandle(events[i].name);
|
||||
/* test that some names are not events (num=0) */
|
||||
if (events[i].num == 0)
|
||||
testOk(pev == NULL, "\"%s\" -> no event", events[i].name);
|
||||
else
|
||||
{
|
||||
expected_count[INDX(i)]++; /* +1 for postEvent */
|
||||
if (events[i].num > 0)
|
||||
{
|
||||
testOk(pev != NULL, "\"%s\" -> numeric event %d", events[i].name, events[i].num);
|
||||
expected_count[INDX(i)]++; /* +1 for post_event */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* test that some strings resolve the same event (num!=0) */
|
||||
if (!aliases[INDX(i)])
|
||||
{
|
||||
aliases[INDX(i)] = i;
|
||||
testOk(pev != NULL, "\"%s\" -> new named event", events[i].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
testOk(pev == eventNameToHandle(events[aliases[INDX(i)]].name),
|
||||
"\"%s\" alias for \"%s\"", events[i].name, events[aliases[INDX(i)]].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
post_event(events[i].num); /* triggers numeric events only */
|
||||
postEvent(pev);
|
||||
}
|
||||
|
||||
testDiag("Check calculated numeric events (backward compatibility)");
|
||||
for (e = 0; e <= MAXEV; e++) {
|
||||
testdbPutFieldOk("eventnum", DBR_LONG, e);
|
||||
testdbGetFieldEqual("e1", DBR_LONG, e);
|
||||
testdbGetFieldEqual("e2", DBR_LONG, e);
|
||||
testdbPutFieldOk("e3", DBR_LONG, e);
|
||||
testdbPutFieldOk("e3.PROC", DBR_LONG, 1);
|
||||
for (i = 0; i < NELEMENTS(events); i++)
|
||||
if (e > 0 && e < 256 && events[i].num == e) { /* numeric events */
|
||||
expected_count[INDX(i)]+=3; /* +1 for eventnum->e1, +1 for e2<-eventnum, +1 for e3 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Allow records to finish processing */
|
||||
testSyncCallback();
|
||||
testDiag("Check if events have been processed the expected number of times");
|
||||
for (i = 0; i < NELEMENTS(events); i++) {
|
||||
char pvname[100];
|
||||
sprintf(pvname, "c%d", i);
|
||||
testDiag("Event \"%s\" expected %d times", events[i].name, expected_count[INDX(i)]);
|
||||
testdbGetFieldEqual(pvname, DBR_LONG, expected_count[INDX(i)]);
|
||||
}
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
record(calc, "c$(N)") {
|
||||
field(SCAN, "Event")
|
||||
field(EVNT, "$(EVENT)")
|
||||
field(CALC, "VAL+1")
|
||||
}
|
||||
record(dfanout, "eventnum") {
|
||||
field(OUTA, "e1 PP")
|
||||
field(FLNK, "e2")
|
||||
}
|
||||
record(event, "e1") {
|
||||
}
|
||||
record(event, "e2") {
|
||||
field(INP, "eventnum")
|
||||
}
|
||||
record(event, "e3") {
|
||||
}
|
||||
Reference in New Issue
Block a user