From f4d94b9725278f21bcfb0d6a38f7ab670330992c Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Tue, 9 Mar 2021 16:26:53 +0100 Subject: [PATCH] Longout OOPT field refactoring and updated documentation; Release notes additions --- documentation/RELEASE_NOTES.md | 7 + modules/database/src/std/rec/longoutRecord.c | 37 +++--- .../src/std/rec/longoutRecord.dbd.pod | 62 +++++++-- modules/database/test/std/rec/longoutTest.c | 124 ++++++++++++------ modules/database/test/std/rec/longoutTest.db | 10 +- 5 files changed, 169 insertions(+), 71 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 587b52448..213370363 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -16,6 +16,13 @@ should also be read to understand what has changed since earlier releases. ## Changes made on the 7.0 branch since 7.0.5 +### Extend longout conditions to write the OUT link (OOPT field) + +The longout record has now the capacity to condition its output write operation to +different options, using the OOPT field (similar to calcout record). This is +the first output record to have such feature as a result of the +[Make output records only write on change](https://bugs.launchpad.net/epics-base/+bug/1398215) +issue on Launchpad. ----- diff --git a/modules/database/src/std/rec/longoutRecord.c b/modules/database/src/std/rec/longoutRecord.c index f5bb4a292..e60e01c79 100644 --- a/modules/database/src/std/rec/longoutRecord.c +++ b/modules/database/src/std/rec/longoutRecord.c @@ -81,6 +81,9 @@ rset longoutRSET={ }; epicsExportAddress(rset,longoutRSET); +#define OUT_LINK_UNCHANGED 0 +#define OUT_LINK_CHANGED 1 + static void checkAlarms(longoutRecord *prec); static void monitor(longoutRecord *prec); static long writeValue(longoutRecord *prec); @@ -120,7 +123,8 @@ static long init_record(struct dbCommon *pcommon, int pass) prec->mlst = prec->val; prec->alst = prec->val; prec->lalm = prec->val; - prec->oval = prec->val; + prec->pval = prec->val; + prec->outpvt = OUT_LINK_UNCHANGED; return 0; } @@ -213,14 +217,13 @@ static long special(DBADDR *paddr, int after) return(0); } - /* If OOPT is "on change" we force a write operation */ + /* Detect an output link re-direction (change)*/ if (dbGetFieldIndex(paddr) == longoutRecordOUT) { - if ((!after) && (prec->oopt == longoutOOPT_On_Change)) - prec->oopt = longoutOOPT_Write_Once_Then_On_Change; - return 0; + if (!after) + prec->outpvt = OUT_LINK_CHANGED; + return(0); } - default: recGblDbaddrError(S_db_badChoice, paddr, "longout: special"); return(S_db_badChoice); @@ -392,10 +395,7 @@ static void monitor(longoutRecord *prec) static long writeValue(longoutRecord *prec) { -<<<<<<< HEAD longoutdset *pdset = (longoutdset *) prec->dset; -======= ->>>>>>> 2b7ca9598 (Added OOPT to longout record) long status = 0; if (!prec->pact) { @@ -435,7 +435,7 @@ static long writeValue(longoutRecord *prec) static void convert(longoutRecord *prec, epicsInt32 value) { - /* check drive limits */ + /* check drive limits */ if(prec->drvh > prec->drvl) { if (value > prec->drvh) value = prec->drvh; else if (value < prec->drvl) value = prec->drvl; @@ -453,11 +453,15 @@ static long conditional_write(longoutRecord *prec) switch (prec->oopt) { case longoutOOPT_On_Change: - doDevSupWrite = (prec->val != prec->oval); + /* Forces a write op if a change in the OUT field is detected */ + if ((prec->ooch == menuYesNoYES) && (prec->outpvt == OUT_LINK_CHANGED)) { + doDevSupWrite = 1; + } else { + /* Only write if value is different from the previous one */ + doDevSupWrite = (prec->val != prec->pval); + } break; - case longoutOOPT_Write_Once_Then_On_Change: - prec->oopt = longoutOOPT_On_Change; case longoutOOPT_Every_Time: doDevSupWrite = 1; break; @@ -471,11 +475,11 @@ static long conditional_write(longoutRecord *prec) break; case longoutOOPT_Transition_To_Zero: - doDevSupWrite = ((prec->val == 0)&&(prec->oval != 0)); + doDevSupWrite = ((prec->val == 0)&&(prec->pval != 0)); break; case longoutOOPT_Transition_To_Non_zero: - doDevSupWrite = ((prec->val != 0)&&(prec->oval == 0)); + doDevSupWrite = ((prec->val != 0)&&(prec->pval == 0)); break; default: @@ -485,6 +489,7 @@ static long conditional_write(longoutRecord *prec) if (doDevSupWrite) status = pdset->write_longout(prec); - prec->oval = prec->val; + prec->pval = prec->val; + prec->outpvt = OUT_LINK_UNCHANGED; /* reset status of OUT link */ return status; } \ No newline at end of file diff --git a/modules/database/src/std/rec/longoutRecord.dbd.pod b/modules/database/src/std/rec/longoutRecord.dbd.pod index 3f11769ba..fe596c118 100644 --- a/modules/database/src/std/rec/longoutRecord.dbd.pod +++ b/modules/database/src/std/rec/longoutRecord.dbd.pod @@ -27,10 +27,8 @@ menu(longoutOOPT) { choice(longoutOOPT_When_Non_zero,"When Non-zero") choice(longoutOOPT_Transition_To_Zero,"Transition To Zero") choice(longoutOOPT_Transition_To_Non_zero,"Transition To Non-zero") - choice(longoutOOPT_Write_Once_Then_On_Change, "Write Once Then On Change") } - recordtype(longout) { =head2 Parameter Fields @@ -82,7 +80,45 @@ DTYP field must then specify the C<<< Soft Channel >>> device support routine. See L
for information on the format of hardware addresses and database links. -=fields OUT, DTYP +=fields OUT, DTYP, OOPT, OOCH + +=head4 Menu longoutOOPT + +The OOPT field determines the condition that causes the output link to be +written to. It's a menu field that has six choices: + +=menu longoutOOPT + +=over + +=item * +C -- write output every time record is processed. (DEFAULT) + +=item * +C -- write output every time VAL changes, i.e., every time the +result of the expression changes. + +=item * +C -- when record is processed, write output if VAL is zero. + +=item * +C -- when record is processed, write output if VAL is +non-zero. + +=item * +C -- when record is processed, write output only if VAL +is zero and the last value was non-zero. + +=item * +C -- when record is processed, write output only if +VAL is non-zero and last value was zero. + +=back + +=head4 Changes in OUT field when OOPT = On Change + +The OOCH field determines if a change in OUT field should cause a write operation +even when the value is the same and OOPT = On Change. By default, OOCH is set to YES. =cut @@ -372,7 +408,7 @@ for more information on simulation mode and its fields. prompt("Sim. Mode Private") special(SPC_NOMOD) interest(4) - extra("epicsCallback *simpvt") + extra("epicsCallback *simpvt") } field(IVOA,DBF_MENU) { prompt("INVALID output action") @@ -385,11 +421,21 @@ for more information on simulation mode and its fields. promptgroup("50 - Output") interest(2) } - field(OVAL,DBF_LONG) { - prompt("Last Value Written") - promptgroup("50 - Output") - asl(ASL1) + field(PVAL,DBF_LONG) { + prompt("Previous Value") + } + field(OUTPVT,DBF_NOACCESS) { + prompt("Output Link Changed Private") special(SPC_NOMOD) + interest(4) + extra("epicsEnum16 outpvt") + } + field(OOCH,DBF_MENU) { + prompt("Output Execute On Change") + promptgroup("50 - Output") + interest(1) + menu(menuYesNo) + initial("1") } field(OOPT,DBF_MENU) { prompt("Output Execute Opt") diff --git a/modules/database/test/std/rec/longoutTest.c b/modules/database/test/std/rec/longoutTest.c index 60da091b2..c69a6b386 100644 --- a/modules/database/test/std/rec/longoutTest.c +++ b/modules/database/test/std/rec/longoutTest.c @@ -10,14 +10,15 @@ #include "errlog.h" #include "dbAccess.h" #include "epicsMath.h" +#include "menuYesNo.h" #include "longoutRecord.h" void recTestIoc_registerRecordDeviceDriver(struct dbBase *); static void test_oopt_everytime(void){ - /* reset rec processing counter */ - testdbPutFieldOk("counter.VAL", DBF_DOUBLE, 0.0); + /* reset rec processing counter_a */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); /* write the same value two times */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); @@ -27,8 +28,8 @@ static void test_oopt_everytime(void){ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 18); - /* Test if the counter was processed 4 times */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 4.0); + /* Test if the counter_a was processed 4 times */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 4.0); // number of tests = 6 } @@ -37,22 +38,22 @@ static void test_oopt_onchange(void){ /* change OOPT to On Change */ testdbPutFieldOk("longout_rec.OOPT", DBF_ENUM, longoutOOPT_On_Change); - /* reset rec processing counter */ - testdbPutFieldOk("counter.VAL", DBF_DOUBLE, 0.0); + /* reset rec processing counter_a */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); /* write the same value two times */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); - /* Test if the counter was processed only once */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 1.0); + /* Test if the counter_a was processed only once */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 1.0); /* write two times with different values*/ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 18); - /* Test if the counter was processed 1 + 2 times */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 3.0); + /* Test if the counter_a was processed 1 + 2 times */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 3.0); //number of tests 8 } @@ -60,22 +61,22 @@ static void test_oopt_onchange(void){ static void test_oopt_whenzero(void){ testdbPutFieldOk("longout_rec.OOPT", DBF_ENUM, longoutOOPT_When_Zero); - /* reset rec processing counter */ - testdbPutFieldOk("counter.VAL", DBF_DOUBLE, 0.0); + /* reset rec processing counter_a */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); /* write zero two times */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 0); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 0); - /* Test if the counter was processed twice */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 2.0); + /* Test if the counter_a was processed twice */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 2.0); /* write two times with non-zero values*/ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 18); - /* Test if the counter was still processed 2 times */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 2.0); + /* Test if the counter_a was still processed 2 times */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 2.0); //number of tests 8 } @@ -83,22 +84,22 @@ static void test_oopt_whenzero(void){ static void test_oopt_whennonzero(void){ testdbPutFieldOk("longout_rec.OOPT", DBF_ENUM, longoutOOPT_When_Non_zero); - /* reset rec processing counter */ - testdbPutFieldOk("counter.VAL", DBF_DOUBLE, 0.0); + /* reset rec processing counter_a */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); /* write zero two times */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 0); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 0); - /* Test if the counter was never processed */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 0.0); + /* Test if the counter_a was never processed */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 0.0); /* write two times with non-zero values*/ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 18); - /* Test if the counter was still processed 2 times */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 2.0); + /* Test if the counter_a was still processed 2 times */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 2.0); //number of tests 8 } @@ -106,23 +107,23 @@ static void test_oopt_whennonzero(void){ static void test_oopt_when_transition_zero(void){ testdbPutFieldOk("longout_rec.OOPT", DBF_ENUM, longoutOOPT_Transition_To_Zero); - /* reset rec processing counter */ - testdbPutFieldOk("counter.VAL", DBF_DOUBLE, 0.0); + /* reset rec processing counter_a */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); /* write non-zero then zero */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 0); - /* Test if the counter was processed */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 1.0); + /* Test if the counter_a was processed */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 1.0); /* write another transition to zero */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 0); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); - /* Test if the counter was processed once more */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 2.0); + /* Test if the counter_a was processed once more */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 2.0); //number of tests 9 } @@ -133,21 +134,21 @@ static void test_oopt_when_transition_nonzero(void){ /* write non-zero to start fresh */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); - /* reset rec processing counter */ - testdbPutFieldOk("counter.VAL", DBF_DOUBLE, 0.0); + /* reset rec processing counter_a */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); /* write non-zero then zero */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 0); - /* Test if the counter was never processed */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 0.0); + /* Test if the counter_a was never processed */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 0.0); /* write a transition to non-zero */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 18); - /* Test if the counter was processed */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 1.0); + /* Test if the counter_a was processed */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 1.0); //number of tests 8 } @@ -159,35 +160,74 @@ static void test_changing_out_field(void){ /* write an initial value */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); - /* reset rec processing counter */ - testdbPutFieldOk("counter.VAL", DBF_DOUBLE, 0.0); - testdbPutFieldOk("counter2.VAL", DBF_DOUBLE, 0.0); + /* reset rec processing counters */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); + testdbPutFieldOk("counter_b.VAL", DBF_DOUBLE, 0.0); /* write the same value */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); /* Test if the counter was never processed */ - testdbGetFieldEqual("counter", DBF_DOUBLE, 0.0); + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 0.0); /* change the OUT link to another counter */ - testdbPutFieldOk("longout_rec.OUT", DBF_STRING, "counter2.B PP"); + testdbPutFieldOk("longout_rec.OUT", DBF_STRING, "counter_b.B PP"); /* write the same value */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); /* Test if the counter was processed once */ - testdbGetFieldEqual("counter2", DBF_DOUBLE, 1.0); + testdbGetFieldEqual("counter_b", DBF_DOUBLE, 1.0); /* write the same value */ testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); /* Test if the counter was not processed again */ - testdbGetFieldEqual("counter2", DBF_DOUBLE, 1.0); + testdbGetFieldEqual("counter_b", DBF_DOUBLE, 1.0); + + /* Set option to write ON CHANGE even when the OUT link was changed */ + testdbPutFieldOk("longout_rec.OOCH", DBF_ENUM, menuYesNoNO); + + /* write an initial value */ + testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); + + /* reset rec processing counters */ + testdbPutFieldOk("counter_a.VAL", DBF_DOUBLE, 0.0); + testdbPutFieldOk("counter_b.VAL", DBF_DOUBLE, 0.0); + + /* write the same value */ + testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); + + /* Test if the counter_b was never processed */ + testdbGetFieldEqual("counter_b", DBF_DOUBLE, 0.0); + + /* change back the OUT link to counter_a */ + testdbPutFieldOk("longout_rec.OUT", DBF_STRING, "counter_a.B PP"); + + /* write the same value */ + testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); + + /* Test if the counter was never processed */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 0.0); + + /* write the same value */ + testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 16); + + /* Test if the counter was not processed again */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 0.0); + + /* write new value */ + testdbPutFieldOk("longout_rec.VAL", DBF_LONG, 17); + + /* Test if the counter was processed once */ + testdbGetFieldEqual("counter_a", DBF_DOUBLE, 1.0); + + //number of tests 24 } MAIN(longoutTest) { - testPlan(6+8+8+8+9+8+11); + testPlan(6+8+8+8+9+8+24); testdbPrepare(); testdbReadDatabase("recTestIoc.dbd", NULL, NULL); diff --git a/modules/database/test/std/rec/longoutTest.db b/modules/database/test/std/rec/longoutTest.db index 93428a070..b988792cd 100644 --- a/modules/database/test/std/rec/longoutTest.db +++ b/modules/database/test/std/rec/longoutTest.db @@ -1,17 +1,17 @@ -record(calc, "counter") { - field(INPA, "counter") +record(calc, "counter_a") { + field(INPA, "counter_a") field(CALC, "A+1") field(SCAN, "Passive") } -record(calc, "counter2") { - field(INPA, "counter2") +record(calc, "counter_b") { + field(INPA, "counter_b") field(CALC, "A+1") field(SCAN, "Passive") } record(longout, "longout_rec") { field(VAL, "0") - field(OUT, "counter.B PP") + field(OUT, "counter_a.B PP") field(PINI, "YES") }