From d86723d62a68b1bfa27f5bb134c3cd5cadaa0e39 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 29 Jul 2014 15:13:10 +0200 Subject: [PATCH 01/14] std/rec/test: add test for deadband mechanism of analog record types --- src/Makefile | 2 + src/std/rec/test/Makefile | 40 +++++ src/std/rec/test/analogMonitorTest.c | 236 ++++++++++++++++++++++++++ src/std/rec/test/analogMonitorTest.db | 13 ++ src/std/rec/test/epicsRunTests.c | 24 +++ src/std/rec/test/myTestSub.dbd | 1 + src/std/rec/test/rtemsTestHarness.c | 14 ++ 7 files changed, 330 insertions(+) create mode 100644 src/std/rec/test/Makefile create mode 100644 src/std/rec/test/analogMonitorTest.c create mode 100644 src/std/rec/test/analogMonitorTest.db create mode 100644 src/std/rec/test/epicsRunTests.c create mode 100644 src/std/rec/test/myTestSub.dbd create mode 100644 src/std/rec/test/rtemsTestHarness.c diff --git a/src/Makefile b/src/Makefile index 3307b8786..0cbd1c138 100644 --- a/src/Makefile +++ b/src/Makefile @@ -75,6 +75,8 @@ std_DEPEND_DIRS = ioc libCom/RTEMS DIRS += std/filters/test std/filters/test_DEPEND_DIRS = std +DIRS += std/rec/test +std/filters/test_DEPEND_DIRS = std include $(TOP)/configure/RULES_DIRS diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile new file mode 100644 index 000000000..bfb8740d5 --- /dev/null +++ b/src/std/rec/test/Makefile @@ -0,0 +1,40 @@ +#************************************************************************* +# Copyright (c) 2012 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 the file LICENSE that is included with this distribution. +#************************************************************************* +TOP=../../../.. + +include $(TOP)/configure/CONFIG + +PROD_LIBS = dbRecStd dbCore ca Com + +TARGETS += $(COMMON_DIR)/analogMonitorTest.dbd +analogMonitorTest_DBD += base.dbd +analogMonitorTest_DBD += myTestSub.dbd +TESTPROD_HOST += analogMonitorTest +analogMonitorTest_SRCS += analogMonitorTest.c +analogMonitorTest_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp +testHarness_SRCS += analogMonitorTest.c +testHarness_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp +TESTFILES += $(COMMON_DIR)/analogMonitorTest.dbd ../analogMonitorTest.db +TESTS += analogMonitorTest + +# epicsRunTests runs all the test programs in a known working order. +testHarness_SRCS += epicsRunTests.c + +recordTestHarness_SRCS += $(testHarness_SRCS) +recordTestHarness_SRCS_RTEMS += rtemsTestHarness.c + +PROD_vxWorks = recordTestHarness +PROD_RTEMS = recordTestHarness + +TESTSPEC_vxWorks = recordTestHarness.munch; epicsRunTests +TESTSPEC_RTEMS = recordTestHarness.boot; epicsRunTests + +TESTSCRIPTS_HOST += $(TESTS:%=%.t) + +include $(TOP)/configure/RULES diff --git a/src/std/rec/test/analogMonitorTest.c b/src/std/rec/test/analogMonitorTest.c new file mode 100644 index 000000000..4d7ad0869 --- /dev/null +++ b/src/std/rec/test/analogMonitorTest.c @@ -0,0 +1,236 @@ +/*************************************************************************\ +* Copyright (c) 2014 ITER Organization. +* 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 "registryFunction.h" +#include "osiFileName.h" +#include "epicsThread.h" +#include "epicsMath.h" +#include "epicsUnitTest.h" +#include "dbAccessDefs.h" +#include "dbStaticLib.h" +#include "dbEvent.h" +#include "caeventmask.h" +#include "db_field_log.h" +#include "chfPlugin.h" +#include "iocInit.h" +#include "testMain.h" +#include "epicsExport.h" + +/* Test parameters */ + +#define NO_OF_RECORD_TYPES 7 +#define NO_OF_DEADBANDS 3 +#define NO_OF_PATTERNS 16 +#define NO_OF_VALUES_PER_SEQUENCE 2 + +void analogMonitorTest_registerRecordDeviceDriver(struct dbBase *); + +/* Indices for record type, deadband type, deadband value, test number, val in sequence */ +static int irec, ityp, idbnd, itest, iseq; + +/* Records to test with */ +static const char t_Record[NO_OF_RECORD_TYPES][10] = { + {"ai"}, {"ao"}, {"calc"}, {"calcout"}, {"dfanout"}, {"sel"}, {"sub"}, +}; +/* Deadband types to test */ +static const char t_DbndType[2][5] = { {".MDEL"}, {".ADEL"} }; +/* Different deadbands to test with */ +static double t_Deadband[NO_OF_DEADBANDS] = { -1, 0, 1.5 }; +/* Value sequences for each of the 16 tests */ +static double t_SetValues[NO_OF_PATTERNS][NO_OF_VALUES_PER_SEQUENCE]; +/* Expected updates (1=yes) for each sequence of each test of each deadband */ +static int t_ExpectedUpdates[NO_OF_DEADBANDS][NO_OF_PATTERNS][NO_OF_VALUES_PER_SEQUENCE] = { + { /* deadband = -1 */ + {1, 1}, {1, 1}, {1, 1}, {1, 1}, + {1, 1}, {1, 1}, {1, 1}, {1, 1}, + {1, 1}, {1, 1}, {1, 1}, {1, 1}, + {1, 1}, {1, 1}, {1, 1}, {1, 1}, + }, + { /* deadband = 0 */ + {1, 1}, {0, 1}, {0, 0}, {0, 0}, + {1, 1}, {1, 0}, {1, 1}, {1, 1}, + {1, 1}, {1, 1}, {1, 0}, {1, 1}, + {1, 1}, {1, 1}, {1, 1}, {1, 0}, + }, + { /* deadband = 1.5 */ + {0, 1}, {0, 1}, {0, 0}, {0, 0}, + {1, 1}, {1, 0}, {1, 1}, {1, 1}, + {1, 1}, {1, 1}, {1, 0}, {1, 1}, + {1, 1}, {1, 1}, {1, 1}, {1, 0}, + }, +}; +static int t_ReceivedUpdates[NO_OF_PATTERNS][NO_OF_VALUES_PER_SEQUENCE]; + +/* Dummy subroutine needed for sub record */ + +static long myTestSub(void *p) { + return 0; +} +epicsRegisterFunction(myTestSub); + + +/* Minimal pre-chain plugin to divert all monitors back into the test (before they hit the queue) */ + +static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { + double val = *((double*)chan->addr.pfield); + + /* iseq == -1 is the value reset before the test pattern -> do not count */ + if (iseq >= 0) { + t_ReceivedUpdates[itest][iseq] = 1; + testOk((val == t_SetValues[itest][iseq]) || (isnan(val) && isnan(t_SetValues[itest][iseq])), + "update %d of test pattern %2d with %s = %2.1f (expected %f, got %f)", + iseq, itest, (ityp==0?"MDEL":"ADEL"), t_Deadband[idbnd], t_SetValues[itest][iseq], val); + } + db_delete_field_log(pfl); + return NULL; +} + +static void channelRegisterPre(dbChannel *chan, void *pvt, + chPostEventFunc **cb_out, void **arg_out, db_field_log *probe) +{ + *cb_out = filter; +} + +static chfPluginIf pif = { + NULL, /* allocPvt, */ + NULL, /* freePvt, */ + NULL, /* parse_error, */ + NULL, /* parse_ok, */ + NULL, /* channel_open, */ + channelRegisterPre, + NULL, /* channelRegisterPost, */ + NULL, /* channel_report, */ + NULL /* channel_close */ +}; + + +MAIN(analogMonitorTest) +{ + dbChannel *pch; + const chFilterPlugin *plug; + const char test[] = "test"; + dbEventCtx evtctx; + dbEventSubscription subscr; + unsigned mask; + struct dbAddr vaddr, daddr; + double val; + char chan[50]; /* Channel name */ + char cval[50]; /* Name for test values */ + char cdel[50]; /* Name for deadband values */ + + /* Test patterns: + * 0: step less than deadband (of 1.5) + * 1: step larger than deadband (of 1.5) + * 2: no change + * 3: -0.0 -> +0.0 + * ... all possible combinations of steps + * between: finite / NaN / -inf / +inf + */ + t_SetValues[ 0][0] = 1.0; t_SetValues[ 0][1] = 2.0; + t_SetValues[ 1][0] = 0.0; t_SetValues[ 1][1] = 2.0; + t_SetValues[ 2][0] = 0.0; t_SetValues[ 2][1] = 0.0; + t_SetValues[ 3][0] = -0.0; t_SetValues[ 3][1] = 0.0; + t_SetValues[ 4][0] = epicsNAN; t_SetValues[ 4][1] = 1.0; + t_SetValues[ 5][0] = epicsNAN; t_SetValues[ 5][1] = epicsNAN; + t_SetValues[ 6][0] = epicsNAN; t_SetValues[ 6][1] = epicsINF; + t_SetValues[ 7][0] = epicsNAN; t_SetValues[ 7][1] = -epicsINF; + t_SetValues[ 8][0] = epicsINF; t_SetValues[ 8][1] = 1.0; + t_SetValues[ 9][0] = epicsINF; t_SetValues[ 9][1] = epicsNAN; + t_SetValues[10][0] = epicsINF; t_SetValues[10][1] = epicsINF; + t_SetValues[11][0] = epicsINF; t_SetValues[11][1] = -epicsINF; + t_SetValues[12][0] = -epicsINF; t_SetValues[12][1] = 1.0; + t_SetValues[13][0] = -epicsINF; t_SetValues[13][1] = epicsNAN; + t_SetValues[14][0] = -epicsINF; t_SetValues[14][1] = epicsINF; + t_SetValues[15][0] = -epicsINF; t_SetValues[15][1] = -epicsINF; + + testPlan(1793); + + if (dbReadDatabase(&pdbbase, "analogMonitorTest.dbd", + "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR + "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL)) + testAbort("Error reading database description 'analogMonitorTest.dbd'"); + + analogMonitorTest_registerRecordDeviceDriver(pdbbase); + + if (dbReadDatabase(&pdbbase, "analogMonitorTest.db", + "." OSI_PATH_LIST_SEPARATOR "..", NULL)) + testAbort("Error reading test database 'analogMonitorTest.db'"); + + /* Start the core IOC (no CA) */ + iocBuildIsolated(); + + evtctx = db_init_events(); + chfPluginRegister(test, &pif, NULL); + + testOk(!!(plug = dbFindFilter(test, strlen(test))), "interceptor plugin registered correctly"); + + /* Loop over all analog record types (one instance each) */ + for (irec = 0; irec < NO_OF_RECORD_TYPES; irec++) { + strcpy(cval, t_Record[irec]); + strcpy(chan, cval); + strcat(chan, ".VAL{\"test\":{}}"); + if ((strcmp(t_Record[irec], "sel") == 0) + || (strcmp(t_Record[irec], "calc") == 0) + || (strcmp(t_Record[irec], "calcout") == 0)) { + strcat(cval, ".A"); + } else { + strcat(cval, ".VAL"); + } + + testDiag("--------------------------------------------------------"); + testDiag("Testing the %s record", t_Record[irec]); + testDiag("--------------------------------------------------------"); + + testOk(!!(pch = dbChannelCreate(chan)), "dbChannel with test plugin created"); + testOk(!dbChannelOpen(pch), "dbChannel opened"); + + dbNameToAddr(cval, &vaddr); + + /* Loop over both tested deadband types */ + for (ityp = 0; ityp < 2; ityp++) { + strcpy(cdel, t_Record[irec]); + strcat(cdel, t_DbndType[ityp]); + dbNameToAddr(cdel, &daddr); + mask = (ityp==0?DBE_VALUE:DBE_ARCHIVE); + subscr = db_add_event(evtctx, pch, NULL, NULL, mask); + db_event_enable(subscr); + + /* Loop over all tested deadband values */ + for (idbnd = 0; idbnd < NO_OF_DEADBANDS; idbnd++) { + dbPutField(&daddr, DBR_DOUBLE, (void*) &t_Deadband[idbnd], 1); + memset(t_ReceivedUpdates, 0, sizeof(t_ReceivedUpdates)); + + /* Loop over all test patterns */ + for (itest = 0; itest < NO_OF_PATTERNS; itest++) { + iseq = -1; + val = 0.0; + dbPutField(&vaddr, DBR_DOUBLE, (void*) &val, 1); + + /* Loop over the test sequence */ + for (iseq = 0; iseq < NO_OF_VALUES_PER_SEQUENCE; iseq++) { + dbPutField(&vaddr, DBR_DOUBLE, (void*) &t_SetValues[itest][iseq], 1); + } + /* Check expected vs. actual monitors */ + testOk( (t_ExpectedUpdates[idbnd][itest][0] == t_ReceivedUpdates[itest][0]) && + (t_ExpectedUpdates[idbnd][itest][1] == t_ReceivedUpdates[itest][1]), + "received updates for test pattern %2d with %s = %2.1f (expected %d-%d, got %d-%d)", + itest, (ityp==0?"MDEL":"ADEL"), t_Deadband[idbnd], + t_ExpectedUpdates[idbnd][itest][0], t_ExpectedUpdates[idbnd][itest][1], + t_ReceivedUpdates[itest][0], t_ReceivedUpdates[itest][1]); + } + } + db_cancel_event(subscr); + } + } + iocShutdown(); + return testDone(); +} diff --git a/src/std/rec/test/analogMonitorTest.db b/src/std/rec/test/analogMonitorTest.db new file mode 100644 index 000000000..5b3f4a2d7 --- /dev/null +++ b/src/std/rec/test/analogMonitorTest.db @@ -0,0 +1,13 @@ +record(ai, "ai") {} +record(ao, "ao") {} +record(calc, "calc") { + field(CALC, "A") +} +record(calcout, "calcout") { + field(CALC, "A") +} +record(dfanout, "dfanout") {} +record(sel, "sel") {} +record(sub, "sub") { + field(SNAM, "myTestSub") +} diff --git a/src/std/rec/test/epicsRunTests.c b/src/std/rec/test/epicsRunTests.c new file mode 100644 index 000000000..610ee8364 --- /dev/null +++ b/src/std/rec/test/epicsRunTests.c @@ -0,0 +1,24 @@ +/*************************************************************************\ +* Copyright (c) 2012 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. +\*************************************************************************/ + +/* + * Run tests as a batch. + */ + +#include "epicsUnitTest.h" +#include "epicsExit.h" + +int analogMonitorTest(void); + +void epicsRunTests(void) +{ + testHarness(); + + runTest(analogMonitorTest); + + epicsExit(0); /* Trigger test harness */ +} diff --git a/src/std/rec/test/myTestSub.dbd b/src/std/rec/test/myTestSub.dbd new file mode 100644 index 000000000..eb0943b54 --- /dev/null +++ b/src/std/rec/test/myTestSub.dbd @@ -0,0 +1 @@ +function(myTestSub) diff --git a/src/std/rec/test/rtemsTestHarness.c b/src/std/rec/test/rtemsTestHarness.c new file mode 100644 index 000000000..dd25941ef --- /dev/null +++ b/src/std/rec/test/rtemsTestHarness.c @@ -0,0 +1,14 @@ +/*************************************************************************\ +* Copyright (c) 2012 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. +\*************************************************************************/ + +extern void epicsRunTests(void); + +int main(int argc, char **argv) +{ + epicsRunTests(); /* calls epicsExit(0) */ + return 0; +} From 633ef60514fd0abfa6c468a5474564d29b1a2688 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 29 Jul 2014 15:16:37 +0200 Subject: [PATCH 02/14] std/rec: fix NaN/inf bug in deadband algorithm of analog records --- src/std/rec/aiRecord.c | 53 ++++++++++++-------- src/std/rec/aoRecord.c | 58 ++++++++++++++-------- src/std/rec/calcRecord.c | 45 +++++++++++------ src/std/rec/calcoutRecord.c | 97 ++++++++++++++++++++++--------------- src/std/rec/dfanoutRecord.c | 68 ++++++++++++++++---------- src/std/rec/selRecord.c | 28 ++++++++--- src/std/rec/subRecord.c | 30 +++++++++--- 7 files changed, 247 insertions(+), 132 deletions(-) diff --git a/src/std/rec/aiRecord.c b/src/std/rec/aiRecord.c index c7f4d7977..2b919b1c5 100644 --- a/src/std/rec/aiRecord.c +++ b/src/std/rec/aiRecord.c @@ -459,26 +459,41 @@ static void monitor(aiRecord *prec) unsigned short monitor_mask; double delta; - monitor_mask = recGblResetAlarms(prec); - /* check for value change */ - delta = prec->mlst - prec->val; - if(delta<0.0) delta = -delta; - if (!(delta <= prec->mdel)) { /* Handles MDEL == NAN */ - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + monitor_mask = recGblResetAlarms(prec); - /* check for archive change */ - delta = prec->alst - prec->val; - if(delta<0.0) delta = -delta; - if (!(delta <= prec->adel)) { /* Handles ADEL == NAN */ - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + /* check for value change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->mlst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->mlst)) { + delta = epicsINF; + } + if (delta > prec->mdel) { + /* post events for value change */ + monitor_mask |= DBE_VALUE; + /* update last value monitored */ + prec->mlst = prec->val; + } + + /* check for archive change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->alst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->alst)) { + delta = epicsINF; + } + if (delta > prec->adel) { + /* post events on value field for archive change */ + monitor_mask |= DBE_LOG; + /* update last archive value monitored */ + prec->alst = prec->val; + } /* send out monitors connected to the value field */ if (monitor_mask){ diff --git a/src/std/rec/aoRecord.c b/src/std/rec/aoRecord.c index 78febffe5..71f095231 100644 --- a/src/std/rec/aoRecord.c +++ b/src/std/rec/aoRecord.c @@ -510,31 +510,47 @@ static void monitor(aoRecord *prec) unsigned short monitor_mask; double delta; - monitor_mask = recGblResetAlarms(prec); - /* check for value change */ + monitor_mask = recGblResetAlarms(prec); + + /* check for value change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { delta = prec->mlst - prec->val; - if(delta<0.0) delta = -delta; - if (!(delta <= prec->mdel)) { /* Handles MDEL == NAN */ - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } - /* check for archive change */ + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->mlst)) { + delta = epicsINF; + } + if (delta > prec->mdel) { + /* post events for value change */ + monitor_mask |= DBE_VALUE; + /* update last value monitored */ + prec->mlst = prec->val; + } + + /* check for archive change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { delta = prec->alst - prec->val; - if(delta<0.0) delta = -delta; - if (!(delta <= prec->adel)) { /* Handles ADEL == NAN */ - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->alst)) { + delta = epicsINF; + } + if (delta > prec->adel) { + /* post events on value field for archive change */ + monitor_mask |= DBE_LOG; + /* update last archive value monitored */ + prec->alst = prec->val; + } + /* send out monitors connected to the value field */ + if (monitor_mask){ + db_post_events(prec,&prec->val,monitor_mask); + } - /* send out monitors connected to the value field */ - if (monitor_mask){ - db_post_events(prec,&prec->val,monitor_mask); - } if(prec->omod) monitor_mask |= (DBE_VALUE|DBE_LOG); if(monitor_mask) { prec->omod = FALSE; diff --git a/src/std/rec/calcRecord.c b/src/std/rec/calcRecord.c index 9a7a56e96..ef1560a25 100644 --- a/src/std/rec/calcRecord.c +++ b/src/std/rec/calcRecord.c @@ -400,29 +400,46 @@ static void monitor(calcRecord *prec) int i; monitor_mask = recGblResetAlarms(prec); + /* check for value change */ - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - if (!(delta <= prec->mdel)) { /* Handles MDEL == NAN */ - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; + delta = 0; + if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->mlst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->mlst)) { + delta = epicsINF; } + if (delta > prec->mdel) { + /* post events for value change */ + monitor_mask |= DBE_VALUE; + /* update last value monitored */ + prec->mlst = prec->val; + } + /* check for archive change */ - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - if (!(delta <= prec->adel)) { /* Handles ADEL == NAN */ - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; + delta = 0; + if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->alst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->alst)) { + delta = epicsINF; + } + if (delta > prec->adel) { + /* post events on value field for archive change */ + monitor_mask |= DBE_LOG; + /* update last archive value monitored */ + prec->alst = prec->val; } /* send out monitors connected to the value field */ if (monitor_mask){ db_post_events(prec, &prec->val, monitor_mask); } + /* check all input fields for changes*/ pnew = &prec->a; pprev = &prec->la; diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c index 190c94c96..55ba11167 100644 --- a/src/std/rec/calcoutRecord.c +++ b/src/std/rec/calcoutRecord.c @@ -622,50 +622,67 @@ static void execOutput(calcoutRecord *prec) static void monitor(calcoutRecord *prec) { - unsigned monitor_mask; - double delta; - double *pnew; - double *pprev; - int i; + unsigned monitor_mask; + double delta; + double *pnew; + double *pprev; + int i; - monitor_mask = recGblResetAlarms(prec); - /* check for value change */ + monitor_mask = recGblResetAlarms(prec); + + /* check for value change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { delta = prec->mlst - prec->val; - if (delta<0.0) delta = -delta; - if (!(delta <= prec->mdel)) { /* Handles MDEL == NAN */ - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } - /* check for archive change */ - delta = prec->alst - prec->val; - if (delta<0.0) delta = -delta; - if (!(delta <= prec->adel)) { /* Handles ADEL == NAN */ - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->mlst)) { + delta = epicsINF; + } + if (delta > prec->mdel) { + /* post events for value change */ + monitor_mask |= DBE_VALUE; + /* update last value monitored */ + prec->mlst = prec->val; + } - /* send out monitors connected to the value field */ - if (monitor_mask){ - db_post_events(prec, &prec->val, monitor_mask); + /* check for archive change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->alst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->alst)) { + delta = epicsINF; + } + if (delta > prec->adel) { + /* post events on value field for archive change */ + monitor_mask |= DBE_LOG; + /* update last archive value monitored */ + prec->alst = prec->val; + } + + /* send out monitors connected to the value field */ + if (monitor_mask){ + db_post_events(prec, &prec->val, monitor_mask); + } + + /* check all input fields for changes*/ + for (i = 0, pnew = &prec->a, pprev = &prec->la; ia, pprev = &prec->la; ipovl != prec->oval) { - db_post_events(prec, &prec->oval, monitor_mask|DBE_VALUE|DBE_LOG); - prec->povl = prec->oval; - } - return; + } + /* Check OVAL field */ + if (prec->povl != prec->oval) { + db_post_events(prec, &prec->oval, monitor_mask|DBE_VALUE|DBE_LOG); + prec->povl = prec->oval; + } + return; } static int fetch_values(calcoutRecord *prec) diff --git a/src/std/rec/dfanoutRecord.c b/src/std/rec/dfanoutRecord.c index cccc91ab4..904003edb 100644 --- a/src/std/rec/dfanoutRecord.c +++ b/src/std/rec/dfanoutRecord.c @@ -259,37 +259,53 @@ static void checkAlarms(dfanoutRecord *prec) static void monitor(dfanoutRecord *prec) { - unsigned short monitor_mask; + unsigned short monitor_mask; + double delta; - double delta; + monitor_mask = recGblResetAlarms(prec); - monitor_mask = recGblResetAlarms(prec); - /* check for value change */ + /* check for value change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { delta = prec->mlst - prec->val; - if(delta<0) delta = -delta; - if (!(delta <= prec->mdel)) { /* Handles MDEL == NAN */ - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } - /* check for archive change */ - delta = prec->alst - prec->val; - if(delta<0) delta = -delta; - if (!(delta <= prec->adel)) { /* Handles ADEL == NAN */ - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->mlst)) { + delta = epicsINF; + } + if (delta > prec->mdel) { + /* post events for value change */ + monitor_mask |= DBE_VALUE; + /* update last value monitored */ + prec->mlst = prec->val; + } - /* send out monitors connected to the value field */ - if (monitor_mask){ - db_post_events(prec,&prec->val,monitor_mask); - } - return; + /* check for archive change */ + delta = 0; + if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->alst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->alst)) { + delta = epicsINF; + } + if (delta > prec->adel) { + /* post events on value field for archive change */ + monitor_mask |= DBE_LOG; + /* update last archive value monitored */ + prec->alst = prec->val; + } + + /* send out monitors connected to the value field */ + if (monitor_mask){ + db_post_events(prec,&prec->val,monitor_mask); + } + + return; } - + static void push_values(dfanoutRecord *prec) { struct link *plink; /* structure of the link field */ diff --git a/src/std/rec/selRecord.c b/src/std/rec/selRecord.c index eb9a04af8..f8524fd97 100644 --- a/src/std/rec/selRecord.c +++ b/src/std/rec/selRecord.c @@ -314,19 +314,35 @@ static void monitor(selRecord *prec) int i; monitor_mask = recGblResetAlarms(prec); + /* check for value change */ - delta = prec->mlst - prec->val; - if(delta<0.0) delta = -delta; - if (!(delta <= prec->mdel)) { /* Handles MDEL == NAN */ + delta = 0; + if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->mlst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->mlst)) { + delta = epicsINF; + } + if (delta > prec->mdel) { /* post events for value change */ monitor_mask |= DBE_VALUE; /* update last value monitored */ prec->mlst = prec->val; } + /* check for archive change */ - delta = prec->alst - prec->val; - if(delta<0.0) delta = -delta; - if (!(delta <= prec->adel)) { /* Handles ADEL == NAN */ + delta = 0; + if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->alst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->alst)) { + delta = epicsINF; + } + if (delta > prec->adel) { /* post events on value field for archive change */ monitor_mask |= DBE_LOG; /* update last archive value monitored */ diff --git a/src/std/rec/subRecord.c b/src/std/rec/subRecord.c index 9e4c1875f..ddbef9c19 100644 --- a/src/std/rec/subRecord.c +++ b/src/std/rec/subRecord.c @@ -380,28 +380,46 @@ static void monitor(subRecord *prec) /* get alarm mask */ monitor_mask = recGblResetAlarms(prec); + /* check for value change */ - delta = prec->val - prec->mlst; - if (delta < 0.0) delta = -delta; - if (!(delta <= prec->mdel)) { /* Handles MDEL == NAN */ + delta = 0; + if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->mlst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->mlst)) { + delta = epicsINF; + } + if (delta > prec->mdel) { /* post events for value change */ monitor_mask |= DBE_VALUE; /* update last value monitored */ prec->mlst = prec->val; } + /* check for archive change */ - delta = prec->val - prec->alst; - if (delta < 0.0) delta = -delta; - if (!(delta <= prec->adel)) { /* Handles ADEL == NAN */ + delta = 0; + if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { + delta = epicsINF; + } else if (!isinf(prec->val) && !isnan(prec->val)) { + delta = prec->alst - prec->val; + if (delta < 0.0) delta = -delta; + } else if (signbit(prec->val) != signbit(prec->alst)) { + delta = epicsINF; + } + if (delta > prec->adel) { /* post events on value field for archive change */ monitor_mask |= DBE_LOG; /* update last archive value monitored */ prec->alst = prec->val; } + /* send out monitors connected to the value field */ if (monitor_mask) { db_post_events(prec, &prec->val, monitor_mask); } + /* check all input fields for changes */ for (i = 0, pnew = &prec->a, pold = &prec->la; i < INP_ARG_MAX; i++, pnew++, pold++) { From c8946b4fc29622fe0167a94e43359b8b14e2026f Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 29 Jul 2014 15:19:12 +0200 Subject: [PATCH 03/14] std/rec: fix inf handling in select record --- src/std/rec/selRecord.c | 93 +++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/src/std/rec/selRecord.c b/src/std/rec/selRecord.c index f8524fd97..34f9e44d5 100644 --- a/src/std/rec/selRecord.c +++ b/src/std/rec/selRecord.c @@ -383,62 +383,57 @@ static void do_sel(selRecord *prec) pvalue = &prec->a; switch (prec->selm){ case (selSELM_Specified): - if (prec->seln >= SEL_MAX) { - recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM); - return; - } - val = *(pvalue+prec->seln); - break; + if (prec->seln >= SEL_MAX) { + recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM); + return; + } + val = *(pvalue+prec->seln); + break; case (selSELM_High_Signal): - val = -epicsINF; - for (i = 0; i < SEL_MAX; i++,pvalue++){ - if (!isnan(*pvalue) && val < *pvalue) { - val = *pvalue; - prec->seln = i; - } - } - break; + val = -epicsINF; + for (i = 0; i < SEL_MAX; i++,pvalue++){ + if (!isnan(*pvalue) && val < *pvalue) { + val = *pvalue; + prec->seln = i; + } + } + break; case (selSELM_Low_Signal): - val = epicsINF; - for (i = 0; i < SEL_MAX; i++,pvalue++){ - if (!isnan(*pvalue) && val > *pvalue) { - val = *pvalue; - prec->seln = i; - } - } - break; + val = epicsINF; + for (i = 0; i < SEL_MAX; i++,pvalue++){ + if (!isnan(*pvalue) && val > *pvalue) { + val = *pvalue; + prec->seln = i; + } + } + break; case (selSELM_Median_Signal): - count = 0; - order[0] = epicsNAN; - for (i = 0; i < SEL_MAX; i++,pvalue++){ - if (!isnan(*pvalue)){ - /* Insertion sort */ - j = count; - while ((j > 0) && (order[j-1] > *pvalue)){ - order[j] = order[j-1]; - j--; - } - order[j] = *pvalue; - count++; - } - } - prec->seln = count; - val = order[count / 2]; - break; + count = 0; + order[0] = epicsNAN; + for (i = 0; i < SEL_MAX; i++,pvalue++){ + if (!isnan(*pvalue)){ + /* Insertion sort */ + j = count; + while ((j > 0) && (order[j-1] > *pvalue)){ + order[j] = order[j-1]; + j--; + } + order[j] = *pvalue; + count++; + } + } + prec->seln = count; + val = order[count / 2]; + break; default: - recGblSetSevr(prec,CALC_ALARM,INVALID_ALARM); - return; - } - if (!isinf(val)){ - prec->val=val; - prec->udf=isnan(prec->val); - } else { - recGblSetSevr(prec,UDF_ALARM,MAJOR_ALARM); - /* If UDF is TRUE this alarm will be overwritten by checkAlarms*/ + recGblSetSevr(prec,CALC_ALARM,INVALID_ALARM); + return; } + prec->val = val; + prec->udf = isnan(prec->val); return; } - + /* * FETCH_VALUES * From 6f41e11804ffb3b84bb7e16a2b649137430414f4 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 30 Jul 2014 10:35:03 +0200 Subject: [PATCH 04/14] ioc/db: add recGblCheckDeadband() to recGbl library --- src/ioc/db/recGbl.c | 26 +++++++++++++++++++++++++- src/ioc/db/recGbl.h | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index 7388d6e29..2aeddf436 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -274,7 +274,31 @@ void recGblTSELwasModified(struct link *plink) ppv_link->pvlMask |= pvlOptTSELisTime; } } - + +void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval, + const epicsFloat64 deadband, unsigned *monitor_mask, const unsigned add_mask) +{ + double delta = 0; + + if (isnan(newval) != isnan(*poldval) || isinf(newval) != isinf(*poldval)) { + /* one is NaN or +-inf, the other finite -> send update */ + delta = epicsINF; + } else if (!isinf(newval) && !isnan(newval)) { + /* both are finite -> compare delta with deadband */ + delta = *poldval - newval; + if (delta < 0.0) delta = -delta; + } else if (signbit(newval) != signbit(*poldval)) { + /* one is +inf, the other -inf -> send update */ + delta = epicsINF; + } + if (delta > deadband) { + /* add bits to monitor mask */ + *monitor_mask |= add_mask; + /* update last value monitored */ + *poldval = newval; + } +} + static void getMaxRangeValues(short field_type, double *pupper_limit, double *plower_limit) { diff --git a/src/ioc/db/recGbl.h b/src/ioc/db/recGbl.h index 64db229ed..04a0ee4d1 100644 --- a/src/ioc/db/recGbl.h +++ b/src/ioc/db/recGbl.h @@ -62,6 +62,8 @@ epicsShareFunc int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsShareFunc void recGblFwdLink(void *precord); epicsShareFunc void recGblGetTimeStamp(void *precord); epicsShareFunc void recGblTSELwasModified(struct link *plink); +epicsShareFunc void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval, + const epicsFloat64 deadband, unsigned *monitor_mask, const unsigned add_mask); #ifdef __cplusplus } From f354f880ccc09389dd5acd36ead863d584305107 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 30 Jul 2014 10:36:24 +0200 Subject: [PATCH 05/14] std/rec: make all analog type records use new recGblCheckDeadband() --- src/std/rec/aiRecord.c | 37 +++---------------------------------- src/std/rec/aoRecord.c | 37 +++---------------------------------- src/std/rec/calcRecord.c | 36 ++++-------------------------------- src/std/rec/calcoutRecord.c | 33 ++------------------------------- src/std/rec/dfanoutRecord.c | 37 +++---------------------------------- src/std/rec/selRecord.c | 35 +++-------------------------------- src/std/rec/subRecord.c | 33 ++------------------------------- 7 files changed, 20 insertions(+), 228 deletions(-) diff --git a/src/std/rec/aiRecord.c b/src/std/rec/aiRecord.c index 2b919b1c5..b624fde87 100644 --- a/src/std/rec/aiRecord.c +++ b/src/std/rec/aiRecord.c @@ -456,44 +456,13 @@ static void convert(aiRecord *prec) static void monitor(aiRecord *prec) { - unsigned short monitor_mask; - double delta; - - monitor_mask = recGblResetAlarms(prec); + unsigned monitor_mask = recGblResetAlarms(prec); /* check for value change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->mlst)) { - delta = epicsINF; - } - if (delta > prec->mdel) { - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE); /* check for archive change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->alst)) { - delta = epicsINF; - } - if (delta > prec->adel) { - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE); /* send out monitors connected to the value field */ if (monitor_mask){ diff --git a/src/std/rec/aoRecord.c b/src/std/rec/aoRecord.c index 71f095231..a3def5607 100644 --- a/src/std/rec/aoRecord.c +++ b/src/std/rec/aoRecord.c @@ -507,44 +507,13 @@ static void convert(aoRecord *prec, double value) static void monitor(aoRecord *prec) { - unsigned short monitor_mask; - double delta; - - monitor_mask = recGblResetAlarms(prec); + unsigned monitor_mask = recGblResetAlarms(prec); /* check for value change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->mlst)) { - delta = epicsINF; - } - if (delta > prec->mdel) { - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE); /* check for archive change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->alst)) { - delta = epicsINF; - } - if (delta > prec->adel) { - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE); /* send out monitors connected to the value field */ if (monitor_mask){ diff --git a/src/std/rec/calcRecord.c b/src/std/rec/calcRecord.c index ef1560a25..a83ee073a 100644 --- a/src/std/rec/calcRecord.c +++ b/src/std/rec/calcRecord.c @@ -395,45 +395,17 @@ static void checkAlarms(calcRecord *prec, epicsTimeStamp *timeLast) static void monitor(calcRecord *prec) { - unsigned short monitor_mask; - double delta, *pnew, *pprev; + unsigned monitor_mask; + double *pnew, *pprev; int i; monitor_mask = recGblResetAlarms(prec); /* check for value change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->mlst)) { - delta = epicsINF; - } - if (delta > prec->mdel) { - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE); /* check for archive change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->alst)) { - delta = epicsINF; - } - if (delta > prec->adel) { - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE); /* send out monitors connected to the value field */ if (monitor_mask){ diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c index 55ba11167..c62b3f446 100644 --- a/src/std/rec/calcoutRecord.c +++ b/src/std/rec/calcoutRecord.c @@ -623,7 +623,6 @@ static void execOutput(calcoutRecord *prec) static void monitor(calcoutRecord *prec) { unsigned monitor_mask; - double delta; double *pnew; double *pprev; int i; @@ -631,38 +630,10 @@ static void monitor(calcoutRecord *prec) monitor_mask = recGblResetAlarms(prec); /* check for value change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->mlst)) { - delta = epicsINF; - } - if (delta > prec->mdel) { - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE); /* check for archive change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->alst)) { - delta = epicsINF; - } - if (delta > prec->adel) { - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE); /* send out monitors connected to the value field */ if (monitor_mask){ diff --git a/src/std/rec/dfanoutRecord.c b/src/std/rec/dfanoutRecord.c index 904003edb..15d06fb3c 100644 --- a/src/std/rec/dfanoutRecord.c +++ b/src/std/rec/dfanoutRecord.c @@ -259,44 +259,13 @@ static void checkAlarms(dfanoutRecord *prec) static void monitor(dfanoutRecord *prec) { - unsigned short monitor_mask; - double delta; - - monitor_mask = recGblResetAlarms(prec); + unsigned monitor_mask = recGblResetAlarms(prec); /* check for value change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->mlst)) { - delta = epicsINF; - } - if (delta > prec->mdel) { - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE); /* check for archive change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->alst)) { - delta = epicsINF; - } - if (delta > prec->adel) { - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE); /* send out monitors connected to the value field */ if (monitor_mask){ diff --git a/src/std/rec/selRecord.c b/src/std/rec/selRecord.c index 34f9e44d5..b9f385173 100644 --- a/src/std/rec/selRecord.c +++ b/src/std/rec/selRecord.c @@ -307,8 +307,7 @@ static void checkAlarms(selRecord *prec) static void monitor(selRecord *prec) { - unsigned short monitor_mask; - double delta; + unsigned monitor_mask; double *pnew; double *pprev; int i; @@ -316,38 +315,10 @@ static void monitor(selRecord *prec) monitor_mask = recGblResetAlarms(prec); /* check for value change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->mlst)) { - delta = epicsINF; - } - if (delta > prec->mdel) { - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE); /* check for archive change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->alst)) { - delta = epicsINF; - } - if (delta > prec->adel) { - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE); /* send out monitors connected to the value field */ if (monitor_mask) diff --git a/src/std/rec/subRecord.c b/src/std/rec/subRecord.c index ddbef9c19..f8808a849 100644 --- a/src/std/rec/subRecord.c +++ b/src/std/rec/subRecord.c @@ -373,7 +373,6 @@ static void checkAlarms(subRecord *prec) static void monitor(subRecord *prec) { unsigned monitor_mask; - double delta; double *pnew; double *pold; int i; @@ -382,38 +381,10 @@ static void monitor(subRecord *prec) monitor_mask = recGblResetAlarms(prec); /* check for value change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->mlst) || isinf(prec->val) != isinf(prec->mlst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->mlst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->mlst)) { - delta = epicsINF; - } - if (delta > prec->mdel) { - /* post events for value change */ - monitor_mask |= DBE_VALUE; - /* update last value monitored */ - prec->mlst = prec->val; - } + recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE); /* check for archive change */ - delta = 0; - if (isnan(prec->val) != isnan(prec->alst) || isinf(prec->val) != isinf(prec->alst)) { - delta = epicsINF; - } else if (!isinf(prec->val) && !isnan(prec->val)) { - delta = prec->alst - prec->val; - if (delta < 0.0) delta = -delta; - } else if (signbit(prec->val) != signbit(prec->alst)) { - delta = epicsINF; - } - if (delta > prec->adel) { - /* post events on value field for archive change */ - monitor_mask |= DBE_LOG; - /* update last archive value monitored */ - prec->alst = prec->val; - } + recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE); /* send out monitors connected to the value field */ if (monitor_mask) { From edafb56273d4eb9fc6f49ae240fb36a714046cb6 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 30 Jul 2014 10:37:10 +0200 Subject: [PATCH 06/14] std/filters: make dbnd filter use recGblCheckDeadband() --- src/std/filters/dbnd.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/std/filters/dbnd.c b/src/std/filters/dbnd.c index 3147c088f..36c852b2b 100644 --- a/src/std/filters/dbnd.c +++ b/src/std/filters/dbnd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -56,17 +57,11 @@ static int parse_ok(void *pvt) return 0; } -static void shiftval (myStruct *my, double val) { - my->last = val; - if (my->mode == 1) - my->hyst = val * my->cval/100.; -} - static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { myStruct *my = (myStruct*) pvt; long status; - double val, delta; - short drop = 0; + double val; + unsigned send = 1; /* * Only scalar values supported - strings, arrays, and conversion errors @@ -81,19 +76,14 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { status = dbFastGetConvertRoutine[pfl->field_type][DBR_DOUBLE] (localAddr.pfield, (void*) &val, &localAddr); if (!status) { - if (isnan(my->last)) { - shiftval(my, val); - } else { - delta = fabs(my->last - val); - if (delta <= my->hyst) { - drop = 1; - } else { - shiftval(my, val); - } + send = 0; + recGblCheckDeadband(&my->last, val, my->hyst, &send, 1); + if (send && my->mode == 1) { + my->hyst = val * my->cval/100.; } } } - if (drop) { + if (!send) { db_delete_field_log(pfl); return NULL; } else return pfl; From 01dcbed948898d4295357cfe854b3d5d88cbbae1 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 30 Jul 2014 13:36:26 +0200 Subject: [PATCH 07/14] ioc/db/test: add test for recGblCheckDeadband() --- src/ioc/db/test/Makefile | 6 ++ src/ioc/db/test/epicsRunDbTests.c | 2 + src/ioc/db/test/recGblCheckDeadbandTest.c | 118 ++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 src/ioc/db/test/recGblCheckDeadbandTest.c diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 84514ddbd..7032292b2 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -79,6 +79,12 @@ TESTS += arrShorthandTest TESTPROD_HOST += benchdbConvert benchdbConvert_SRCS += benchdbConvert.c +TESTPROD_HOST += recGblCheckDeadbandTest +recGblCheckDeadbandTest_SRCS += recGblCheckDeadbandTest.c +recGblCheckDeadbandTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp +testHarness_SRCS += recGblCheckDeadbandTest.c +TESTS += recGblCheckDeadbandTest + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunDbTests.c diff --git a/src/ioc/db/test/epicsRunDbTests.c b/src/ioc/db/test/epicsRunDbTests.c index ed6fd3c2a..ae150b55a 100644 --- a/src/ioc/db/test/epicsRunDbTests.c +++ b/src/ioc/db/test/epicsRunDbTests.c @@ -25,6 +25,7 @@ int dbPutLinkTest(void); int testDbChannel(void); int chfPluginTest(void); int arrShorthandTest(void); +int recGblCheckDeadbandTest(void); void epicsRunDbTests(void) { @@ -38,6 +39,7 @@ void epicsRunDbTests(void) runTest(dbPutLinkTest); runTest(testDbChannel); runTest(arrShorthandTest); + runTest(recGblCheckDeadbandTest); runTest(chfPluginTest); dbmfFreeChunks(); diff --git a/src/ioc/db/test/recGblCheckDeadbandTest.c b/src/ioc/db/test/recGblCheckDeadbandTest.c new file mode 100644 index 000000000..2df4c26ee --- /dev/null +++ b/src/ioc/db/test/recGblCheckDeadbandTest.c @@ -0,0 +1,118 @@ +/*************************************************************************\ +* Copyright (c) 2014 ITER Organization. +* 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 "recGbl.h" +#include "epicsMath.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +/* Test parameters */ + +#define NO_OF_DEADBANDS 3 +#define NO_OF_PATTERNS 19 + +void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); + +/* Indices for deadband value, test number, val in sequence */ +static int idbnd, itest, iseq; + +/* Different deadbands to test with */ +static double t_Deadband[NO_OF_DEADBANDS] = { -1, 0, 1.5 }; +/* Value sequences for each of the 16 tests */ +static double t_SetValues[NO_OF_PATTERNS][2]; +/* Expected updates (1=yes) for each sequence of each test of each deadband */ +static int t_ExpectedUpdates[NO_OF_DEADBANDS][NO_OF_PATTERNS] = { + { /* deadband = -1 */ + 1, 1, 1, 1, + 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + }, + { /* deadband = 0 */ + 1, 1, 0, 0, + 1, 1, 1, + 1, 0, 1, 1, + 1, 1, 0, 1, + 1, 1, 1, 0, + }, + { /* deadband = 1.5 */ + 0, 1, 0, 0, + 1, 1, 1, + 1, 0, 1, 1, + 1, 1, 0, 1, + 1, 1, 1, 0, + }, +}; + +MAIN(recGblCheckDeadbandTest) +{ + unsigned mask; + double oldval, newval; + + /* Test patterns: + * 0: step less than deadband (of 1.5) + * 1: step larger than deadband (of 1.5) + * 2: no change + * 3: -0.0 -> +0.0 + * ... all possible combinations of steps + * between: finite / NaN / -inf / +inf + */ + t_SetValues[ 0][0] = 1.0; t_SetValues[ 0][1] = 2.0; + t_SetValues[ 1][0] = 0.0; t_SetValues[ 1][1] = 2.0; + t_SetValues[ 2][0] = 0.0; t_SetValues[ 2][1] = 0.0; + t_SetValues[ 3][0] = -0.0; t_SetValues[ 3][1] = 0.0; + t_SetValues[ 4][0] = 1.0; t_SetValues[ 4][1] = epicsNAN; + t_SetValues[ 5][0] = 1.0; t_SetValues[ 5][1] = epicsINF; + t_SetValues[ 6][0] = 1.0; t_SetValues[ 6][1] = -epicsINF; + t_SetValues[ 7][0] = epicsNAN; t_SetValues[ 7][1] = 1.0; + t_SetValues[ 8][0] = epicsNAN; t_SetValues[ 8][1] = epicsNAN; + t_SetValues[ 9][0] = epicsNAN; t_SetValues[ 9][1] = epicsINF; + t_SetValues[10][0] = epicsNAN; t_SetValues[10][1] = -epicsINF; + t_SetValues[11][0] = epicsINF; t_SetValues[11][1] = 1.0; + t_SetValues[12][0] = epicsINF; t_SetValues[12][1] = epicsNAN; + t_SetValues[13][0] = epicsINF; t_SetValues[13][1] = epicsINF; + t_SetValues[14][0] = epicsINF; t_SetValues[14][1] = -epicsINF; + t_SetValues[15][0] = -epicsINF; t_SetValues[15][1] = 1.0; + t_SetValues[16][0] = -epicsINF; t_SetValues[16][1] = epicsNAN; + t_SetValues[17][0] = -epicsINF; t_SetValues[17][1] = epicsINF; + t_SetValues[18][0] = -epicsINF; t_SetValues[18][1] = -epicsINF; + + testPlan(114); + + /* Loop over all tested deadband values */ + for (idbnd = 0; idbnd < NO_OF_DEADBANDS; idbnd++) { + + /* Loop over all test patterns */ + for (itest = 0; itest < NO_OF_PATTERNS; itest++) { + oldval = t_SetValues[itest][0]; + newval = t_SetValues[itest][1]; + mask = 0; + + recGblCheckDeadband(&oldval, newval, t_Deadband[idbnd], &mask, 1); + + /* Check expected vs. actual test result */ + testOk(t_ExpectedUpdates[idbnd][itest] == mask, + "deadband=%2.1f: check for oldvalue=%f newvalue=%f (expected %d, got %d)", + t_Deadband[idbnd], t_SetValues[itest][0], t_SetValues[itest][1], + t_ExpectedUpdates[idbnd][itest], mask); + + if (mask) { + testOk((oldval == newval) || (isnan(oldval) && isnan(newval)), "mask set, oldval equals newval"); + } else { + testOk((oldval == t_SetValues[itest][0]) || (isnan(oldval) && isnan(t_SetValues[itest][0])), + "mask not set, oldval unchanged"); + } + } + } + return testDone(); +} From 96b082d3e4081ffcad21d7e9a76ab66edff3ae9f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 4 Aug 2014 12:26:31 -0400 Subject: [PATCH 08/14] fix makefile typo --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 0cbd1c138..74dfc172a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -76,7 +76,7 @@ DIRS += std/filters/test std/filters/test_DEPEND_DIRS = std DIRS += std/rec/test -std/filters/test_DEPEND_DIRS = std +std/rec/test_DEPEND_DIRS = std include $(TOP)/configure/RULES_DIRS From 73a64bc89f5d917e4f456d97bdd2aacf3bf1329a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 4 Aug 2014 13:28:47 -0400 Subject: [PATCH 09/14] quiet some warnings unused variable iseq undefined struct dbBase --- src/ioc/db/test/recGblCheckDeadbandTest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/test/recGblCheckDeadbandTest.c b/src/ioc/db/test/recGblCheckDeadbandTest.c index 2df4c26ee..d3cac3a45 100644 --- a/src/ioc/db/test/recGblCheckDeadbandTest.c +++ b/src/ioc/db/test/recGblCheckDeadbandTest.c @@ -11,6 +11,7 @@ #include #include "recGbl.h" +#include "dbBase.h" #include "epicsMath.h" #include "epicsUnitTest.h" #include "testMain.h" @@ -23,7 +24,7 @@ void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); /* Indices for deadband value, test number, val in sequence */ -static int idbnd, itest, iseq; +static int idbnd, itest; /* Different deadbands to test with */ static double t_Deadband[NO_OF_DEADBANDS] = { -1, 0, 1.5 }; From fb3314ea454d7f15cef10688a26b8c1f9bedd687 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 4 Aug 2014 13:43:37 -0400 Subject: [PATCH 10/14] analogMonitorTest: char array too small --- src/std/rec/test/analogMonitorTest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/std/rec/test/analogMonitorTest.c b/src/std/rec/test/analogMonitorTest.c index 4d7ad0869..f0c1950c1 100644 --- a/src/std/rec/test/analogMonitorTest.c +++ b/src/std/rec/test/analogMonitorTest.c @@ -42,7 +42,7 @@ static const char t_Record[NO_OF_RECORD_TYPES][10] = { {"ai"}, {"ao"}, {"calc"}, {"calcout"}, {"dfanout"}, {"sel"}, {"sub"}, }; /* Deadband types to test */ -static const char t_DbndType[2][5] = { {".MDEL"}, {".ADEL"} }; +static const char t_DbndType[2][6] = { {".MDEL"}, {".ADEL"} }; /* Different deadbands to test with */ static double t_Deadband[NO_OF_DEADBANDS] = { -1, 0, 1.5 }; /* Value sequences for each of the 16 tests */ @@ -206,6 +206,7 @@ MAIN(analogMonitorTest) /* Loop over all tested deadband values */ for (idbnd = 0; idbnd < NO_OF_DEADBANDS; idbnd++) { + testDiag("Test %s%s = %g", t_Record[irec], t_DbndType[ityp], t_Deadband[idbnd]); dbPutField(&daddr, DBR_DOUBLE, (void*) &t_Deadband[idbnd], 1); memset(t_ReceivedUpdates, 0, sizeof(t_ReceivedUpdates)); From ded1f3572d98a8e5753695238f02ff51f57e1a09 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 5 Aug 2014 10:42:25 +0200 Subject: [PATCH 11/14] ioc/db: force isnan()/isinf() to be 1 (instead of non-zero) --- src/ioc/db/recGbl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index 2aeddf436..6466fa6cd 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -280,7 +280,7 @@ void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval, { double delta = 0; - if (isnan(newval) != isnan(*poldval) || isinf(newval) != isinf(*poldval)) { + if (!!isnan(newval) != !!isnan(*poldval) || !!isinf(newval) != !!isinf(*poldval)) { /* one is NaN or +-inf, the other finite -> send update */ delta = epicsINF; } else if (!isinf(newval) && !isnan(newval)) { From 130d98463c48bce2f51809419335f14b0041b10e Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 5 Aug 2014 11:17:29 +0200 Subject: [PATCH 12/14] ioc/db (recGblCheckDeadband): pull most common case to front --- src/ioc/db/recGbl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index 6466fa6cd..f7dfee333 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -280,13 +280,13 @@ void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval, { double delta = 0; - if (!!isnan(newval) != !!isnan(*poldval) || !!isinf(newval) != !!isinf(*poldval)) { - /* one is NaN or +-inf, the other finite -> send update */ - delta = epicsINF; - } else if (!isinf(newval) && !isnan(newval)) { + if (finite(newval) && finite(*poldval)) { /* both are finite -> compare delta with deadband */ delta = *poldval - newval; if (delta < 0.0) delta = -delta; + } else if (!!isnan(newval) != !!isnan(*poldval) || !!isinf(newval) != !!isinf(*poldval)) { + /* one is NaN or +-inf, the other not -> send update */ + delta = epicsINF; } else if (signbit(newval) != signbit(*poldval)) { /* one is +inf, the other -inf -> send update */ delta = epicsINF; From fdb21252b090c98754640faa2892c22d8e03a89e Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 5 Aug 2014 11:20:23 +0200 Subject: [PATCH 13/14] ioc/db (recGblCheckDeadband): avoid signbit() which does not exist on older MSVC installations --- src/ioc/db/recGbl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index f7dfee333..26799386d 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -287,7 +287,7 @@ void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval, } else if (!!isnan(newval) != !!isnan(*poldval) || !!isinf(newval) != !!isinf(*poldval)) { /* one is NaN or +-inf, the other not -> send update */ delta = epicsINF; - } else if (signbit(newval) != signbit(*poldval)) { + } else if (isinf(newval) && newval != *poldval) { /* one is +inf, the other -inf -> send update */ delta = epicsINF; } From e6a883bc5f2676d782ab1e292f06bef74b5d795a Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 5 Aug 2014 14:29:14 +0200 Subject: [PATCH 14/14] std/rec/test: explicitly register test subroutine for subroutine record (fix build on MinGW) --- src/std/rec/test/Makefile | 1 - src/std/rec/test/analogMonitorTest.c | 3 ++- src/std/rec/test/myTestSub.dbd | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 src/std/rec/test/myTestSub.dbd diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index bfb8740d5..b8657ce83 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -14,7 +14,6 @@ PROD_LIBS = dbRecStd dbCore ca Com TARGETS += $(COMMON_DIR)/analogMonitorTest.dbd analogMonitorTest_DBD += base.dbd -analogMonitorTest_DBD += myTestSub.dbd TESTPROD_HOST += analogMonitorTest analogMonitorTest_SRCS += analogMonitorTest.c analogMonitorTest_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp diff --git a/src/std/rec/test/analogMonitorTest.c b/src/std/rec/test/analogMonitorTest.c index f0c1950c1..56f3cf475 100644 --- a/src/std/rec/test/analogMonitorTest.c +++ b/src/std/rec/test/analogMonitorTest.c @@ -75,7 +75,6 @@ static int t_ReceivedUpdates[NO_OF_PATTERNS][NO_OF_VALUES_PER_SEQUENCE]; static long myTestSub(void *p) { return 0; } -epicsRegisterFunction(myTestSub); /* Minimal pre-chain plugin to divert all monitors back into the test (before they hit the queue) */ @@ -152,6 +151,8 @@ MAIN(analogMonitorTest) t_SetValues[14][0] = -epicsINF; t_SetValues[14][1] = epicsINF; t_SetValues[15][0] = -epicsINF; t_SetValues[15][1] = -epicsINF; + registryFunctionAdd("myTestSub", (REGISTRYFUNCTION) myTestSub); + testPlan(1793); if (dbReadDatabase(&pdbbase, "analogMonitorTest.dbd", diff --git a/src/std/rec/test/myTestSub.dbd b/src/std/rec/test/myTestSub.dbd deleted file mode 100644 index eb0943b54..000000000 --- a/src/std/rec/test/myTestSub.dbd +++ /dev/null @@ -1 +0,0 @@ -function(myTestSub)