From e5b354708e5060674eec89c2aabb7cb906335ea9 Mon Sep 17 00:00:00 2001 From: Kukhee Kim Date: Thu, 28 Aug 2014 12:11:51 -0700 Subject: [PATCH 1/8] Implement LIFO behavior in compress record --- src/std/rec/compressRecord.c | 52 ++++++++++++++++++++++++++---- src/std/rec/compressRecord.dbd.pod | 11 +++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/std/rec/compressRecord.c b/src/std/rec/compressRecord.c index 0ecfbd4e5..84a93f82f 100644 --- a/src/std/rec/compressRecord.c +++ b/src/std/rec/compressRecord.c @@ -106,7 +106,7 @@ static void monitor(compressRecord *prec) db_post_events(prec, prec->bptr, monitor_mask); } -static void put_value(compressRecord *prec, double *psource, int n) +static void put_value_FIFO(compressRecord *prec, double *psource, int n) { epicsInt32 offset = prec->off; epicsInt32 nuse = prec->nuse; @@ -130,6 +130,42 @@ static void put_value(compressRecord *prec, double *psource, int n) prec->nuse = nuse; return; } + +static void put_value_LIFO(compressRecord *prec, double *psource, int n) +{ + epicsInt32 offset = prec->off; + epicsInt32 nuse = prec->nuse; + epicsInt32 nsam = prec->nsam; + epicsInt32 start = offset - nuse; + double *pdest; + int i; + if(start<0) start += nsam; + + for(i = 0; i < n; i++) { + if(--start < 0) start += nsam; + pdest = prec->bptr + start; + *pdest = *psource++; + } + nuse += n; + if(nuse > nsam) nuse = nsam; + offset = start + nuse; + if(offset>=nsam) offset -= nsam; + + prec->off = offset; + prec->nuse = nuse; + + return; +} + +static void put_value(compressRecord *prec, double *psource, int n) +{ + switch(prec->balg) { + case bufferingALG_FIFO: put_value_FIFO(prec, psource, n); break; + case bufferingALG_LIFO: put_value_LIFO(prec, psource, n); break; + } + return; +} + /* qsort comparison function (for median calculation) */ static int compare(const void *arg1, const void *arg2) @@ -305,6 +341,7 @@ static long init_record(compressRecord *prec, int pass) prec->bptr = calloc(prec->nsam, sizeof(double)); reset(prec); } + return 0; } @@ -388,18 +425,21 @@ static long cvt_dbaddr(DBADDR *paddr) paddr->field_type = DBF_DOUBLE; paddr->field_size = sizeof(double); paddr->dbr_field_type = DBF_DOUBLE; + + if(prec->balg == bufferingALG_LIFO) paddr->special = SPC_NOMOD; return 0; } static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) { compressRecord *prec = (compressRecord *) paddr->precord; + epicsInt32 start = prec->off - prec->nuse; + if(start<0) start += prec->nsam; + if(prec->balg == bufferingALG_FIFO) + *no_elements = prec->nuse; + else *no_elements = prec->nsam; + *offset = start; - *no_elements = prec->nuse; - if (prec->nuse == prec->nsam) - *offset = prec->off; - else - *offset = 0; return 0; } diff --git a/src/std/rec/compressRecord.dbd.pod b/src/std/rec/compressRecord.dbd.pod index 97b84a9a0..14f1bd407 100644 --- a/src/std/rec/compressRecord.dbd.pod +++ b/src/std/rec/compressRecord.dbd.pod @@ -41,6 +41,10 @@ menu(compressALG) { choice(compressALG_Circular_Buffer,"Circular Buffer") choice(compressALG_N_to_1_Median,"N to 1 Median") } +menu(bufferingALG) { + choice(bufferingALG_FIFO, "FIFO Buffer") + choice(bufferingALG_LIFO, "LIFO Buffer") +} recordtype(compress) { =fields VAL @@ -76,6 +80,13 @@ recordtype(compress) { interest(1) menu(compressALG) } + field(BALG,DBF_MENU) { + prompt("Buffering Algorithm") + promptgroup(GUI_ALARMS) + special(SPC_RESET) + interest(1) + menu(bufferingALG) + } field(NSAM,DBF_ULONG) { prompt("Number of Values") promptgroup(GUI_COMPRESS) From a308fb7c1ecbfa42d49b92f69ae4e513fff8ce1c Mon Sep 17 00:00:00 2001 From: Kukhee Kim Date: Thu, 9 Jul 2015 13:34:37 -0700 Subject: [PATCH 2/8] fill zeros into buffer when BALG is changed to LIFO from FIFO. --- src/std/rec/compressRecord.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/std/rec/compressRecord.c b/src/std/rec/compressRecord.c index 84a93f82f..c0feaacfb 100644 --- a/src/std/rec/compressRecord.c +++ b/src/std/rec/compressRecord.c @@ -92,6 +92,8 @@ static void reset(compressRecord *prec) if (prec->alg == compressALG_Average && prec->sptr == 0){ prec->sptr = calloc(prec->nsam, sizeof(double)); } + + if(prec->bptr && prec->nsam) memset(prec->bptr, 0, prec->nsam * sizeof(double)); } static void monitor(compressRecord *prec) From e75f44100e25501614f71080929a6ab45f871f68 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Jan 2016 20:58:58 -0500 Subject: [PATCH 3/8] dbAccess: dbGet wrap at capacity count not valid count Change the usage of rset::get_array_info in dbGet() in the case that offset>0 and no_elementstype == dbfl_type_rec) { field_type = paddr->field_type; - no_elements = paddr->no_elements; + max_elements = no_elements = paddr->no_elements; } else { field_type = pfl->field_type; - no_elements = pfl->no_elements; + max_elements = no_elements = pfl->no_elements; } if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) @@ -906,7 +906,7 @@ long dbGet(DBADDR *paddr, short dbrType, if (n <= 0) { ;/*do nothing*/ } else if (!pfl || pfl->type == dbfl_type_rec) { - status = convert(paddr, pbuf, n, no_elements, offset); + status = convert(paddr, pbuf, n, max_elements, offset); } else { DBADDR localAddr = *paddr; /* Structure copy */ @@ -917,7 +917,7 @@ long dbGet(DBADDR *paddr, short dbrType, localAddr.pfield = (char *) &pfl->u.v.field; else localAddr.pfield = (char *) pfl->u.r.field; - status = convert(&localAddr, pbuf, n, no_elements, offset); + status = convert(&localAddr, pbuf, n, max_elements, offset); } } done: From 840da801fb30f021d43447301f7094544878a7f2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Jan 2016 20:58:58 -0500 Subject: [PATCH 4/8] std/filters: arr wrap on capacity not length --- src/std/filters/arr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/std/filters/arr.c b/src/std/filters/arr.c index b872cd623..9d09c9f4c 100644 --- a/src/std/filters/arr.c +++ b/src/std/filters/arr.c @@ -95,7 +95,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { long end = my->end; long nTarget = 0; long offset = 0; - long nSource = chan->addr.no_elements; + long nSource = chan->addr.no_elements, maxSource = nSource; /* Only array data */ if (pfl->type == dbfl_type_val) { @@ -126,7 +126,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { pfl->u.r.dtor = freeArray; pfl->u.r.pvt = my->arrayFreeList; offset = (offset + start) % chan->addr.no_elements; - dbExtractArrayFromRec(&chan->addr, pdst, nTarget, nSource, offset, my->incr); + dbExtractArrayFromRec(&chan->addr, pdst, nTarget, maxSource, offset, my->incr); pfl->u.r.field = pdst; } } From 4cca4673ca7be2d5a30b2286908e001b5e2fd267 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Jan 2016 20:58:58 -0500 Subject: [PATCH 5/8] compress: copy some text from RRM wiki Still a lot remaining. No idea what to do about the images. --- src/std/rec/compressRecord.dbd.pod | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/std/rec/compressRecord.dbd.pod b/src/std/rec/compressRecord.dbd.pod index 14f1bd407..0d27492bf 100644 --- a/src/std/rec/compressRecord.dbd.pod +++ b/src/std/rec/compressRecord.dbd.pod @@ -9,19 +9,37 @@ =title Compress Record (compress) -... +The data compression record is used to collect and compress data from arrays. +When the INP field references a data array field, +it immediately compresses the entire array into an element of an array using one of several algorithms, +overwriting the previous element. If the INP field obtains its value from a scalar-value field, +the compression record will collect a new sample each time the record is processed +and add it to the compressed data array as a circular buffer. + +The INP link can also specify a constant; +however, if this is the case, the compression algorithms are ignored, +and the record support routines merely return after checking the FLNK field. =head2 Record-specific Menus =head3 Menu compressALG -The ALG field which uses this menu controls the compression algorithm used. - -... - =menu compressALG -... +The ALG field which uses this menu controls the compression algorithm used. + +There are six possible algorithms which can be specified as follows: + +* Circular Buffer +* Average +* N to 1 Low Value +* N to 1 High Value +* N to 1 Average +* N to 1 Median + +=menu bufferingALG + +Selects FIFO (First in first out) or LIFO (Last in first out) insertion order. =head2 Parameter Fields From d2e4fcbbacb8c9da789b0dfc978a86f536071e56 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Jan 2016 20:58:58 -0500 Subject: [PATCH 6/8] compressRecord: LIFO doesn't zero pad Change handling of OFF so that reading a partially populated buffer doesn't pad with zero. Simplify put_value() and get_array_info() --- src/std/rec/compressRecord.c | 103 ++++++++++++++--------------------- 1 file changed, 40 insertions(+), 63 deletions(-) diff --git a/src/std/rec/compressRecord.c b/src/std/rec/compressRecord.c index c0feaacfb..c86b31af5 100644 --- a/src/std/rec/compressRecord.c +++ b/src/std/rec/compressRecord.c @@ -108,67 +108,34 @@ static void monitor(compressRecord *prec) db_post_events(prec, prec->bptr, monitor_mask); } -static void put_value_FIFO(compressRecord *prec, double *psource, int n) -{ - epicsInt32 offset = prec->off; - epicsInt32 nuse = prec->nuse; - epicsInt32 nsam = prec->nsam; - double *pdest = prec->bptr + offset; - int i; - - for (i = 0; i < n; i++) { - *pdest = *psource++; - if (++offset >= nsam) { - pdest = prec->bptr; - offset = 0; - } - else - pdest++; - } - nuse += n; - if (nuse > nsam) - nuse = nsam; - prec->off = offset; - prec->nuse = nuse; - return; -} - -static void put_value_LIFO(compressRecord *prec, double *psource, int n) -{ - epicsInt32 offset = prec->off; - epicsInt32 nuse = prec->nuse; - epicsInt32 nsam = prec->nsam; - epicsInt32 start = offset - nuse; - double *pdest; - int i; - if(start<0) start += nsam; - - for(i = 0; i < n; i++) { - if(--start < 0) start += nsam; - pdest = prec->bptr + start; - *pdest = *psource++; - } - nuse += n; - if(nuse > nsam) nuse = nsam; - offset = start + nuse; - if(offset>=nsam) offset -= nsam; - - prec->off = offset; - prec->nuse = nuse; - - return; -} - static void put_value(compressRecord *prec, double *psource, int n) { - switch(prec->balg) { - case bufferingALG_FIFO: put_value_FIFO(prec, psource, n); break; - case bufferingALG_LIFO: put_value_LIFO(prec, psource, n); break; + int fifo = prec->balg==bufferingALG_FIFO; + epicsUInt32 offset = prec->off; + epicsUInt32 nuse = prec->nuse; + epicsUInt32 nsam = prec->nsam; + + nuse += n; + if(nuse>nsam) + nuse = nsam; + + while(n--) { + /* for LIFO, decrement before */ + if(!fifo) + offset = (offset-1)%nsam; + + prec->bptr[offset] = *psource++; + + /* for FIFO, increment after */ + if(fifo) + offset = (offset+1)%nsam; } - return; + + prec->off = offset; + prec->nuse = nuse; } - + /* qsort comparison function (for median calculation) */ static int compare(const void *arg1, const void *arg2) { @@ -434,13 +401,22 @@ static long cvt_dbaddr(DBADDR *paddr) static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) { + /* offset indicates the next element which would be written. + * In FIFO mode offset-1 is the last valid element + * In LIFO mode offset is the first valid element + * (*offset) should be set to the index of the first valid element + */ compressRecord *prec = (compressRecord *) paddr->precord; - epicsInt32 start = prec->off - prec->nuse; - if(start<0) start += prec->nsam; - if(prec->balg == bufferingALG_FIFO) - *no_elements = prec->nuse; - else *no_elements = prec->nsam; - *offset = start; + epicsUInt32 off = prec->off; + epicsUInt32 nuse = prec->nuse; + epicsUInt32 nsam = prec->nsam; + + *no_elements = nuse; + if(prec->balg == bufferingALG_FIFO) { + *offset = (off-nuse)%nsam; + } else { + *offset = off; + } return 0; } @@ -449,7 +425,8 @@ static long put_array_info(DBADDR *paddr, long nNew) { compressRecord *prec = (compressRecord *) paddr->precord; - prec->off = (prec->off + nNew) % prec->nsam; + if(prec->balg == bufferingALG_FIFO) + prec->off = (prec->off + nNew) % prec->nsam; prec->nuse += nNew; if (prec->nuse > prec->nsam) prec->nuse = prec->nsam; From f814398d775e8f55076519b73ec1a995ff3ae555 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Jan 2016 20:58:58 -0500 Subject: [PATCH 7/8] std/rec/test: add compressTest test circular buffer mode for FIFO and LIFO --- src/std/rec/test/Makefile | 7 + src/std/rec/test/compressTest.c | 351 +++++++++++++++++++++++++ src/std/rec/test/compressTest.db | 7 + src/std/rec/test/epicsRunRecordTests.c | 3 + 4 files changed, 368 insertions(+) create mode 100644 src/std/rec/test/compressTest.c create mode 100644 src/std/rec/test/compressTest.db diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index 5e7a8fb29..f5a60a751 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -38,6 +38,13 @@ testHarness_SRCS += linkRetargetLinkTest.c TESTFILES += ../linkRetargetLink.db TESTS += linkRetargetLinkTest +TESTPROD_HOST += compressTest +compressTest_SRCS += compressTest.c +compressTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp +testHarness_SRCS += compressTest.c +TESTFILES += ../compressTest.db +TESTS += compressTest + TARGETS += $(COMMON_DIR)/asTestIoc.dbd asTestIoc_DBD += base.dbd asTestIoc_DBD += asTest.dbd diff --git a/src/std/rec/test/compressTest.c b/src/std/rec/test/compressTest.c new file mode 100644 index 000000000..e9085c68b --- /dev/null +++ b/src/std/rec/test/compressTest.c @@ -0,0 +1,351 @@ +/*************************************************************************\ +* Copyright (c) 2016 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include "dbUnitTest.h" +#include "testMain.h" +#include "dbLock.h" +#include "errlog.h" +#include "dbAccess.h" +#include "epicsMath.h" + +#include "aiRecord.h" +#include "compressRecord.h" + +#define testDEq(A,B,D) testOk(fabs((A)-(B))<(D), #A " (%f) ~= " #B " (%f)", A, B) + +void recTestIoc_registerRecordDeviceDriver(struct dbBase *); + +static +void checkArrD(const char *pv, long elen, double a, double b, double c, double d) +{ + double buf[4]; + double expect[4]; + long nReq = NELEMENTS(buf), i; + unsigned match; + DBADDR addr; + + expect[0] = a; + expect[1] = b; + expect[2] = c; + expect[3] = d; + + if(dbNameToAddr(pv, &addr)) + testAbort("Unknown PV '%s'", pv); + + if(dbGet(&addr, DBR_DOUBLE, buf, NULL, &nReq, NULL)) + testAbort("Failed to get '%s'", pv); + + match = elen==nReq; + for(i=0; i=0.01) + testDiag("[%ld] -> %f != %f", i, expect[i], buf[i]); + } +} + +static +void checkArrI(const char *pv, long elen, epicsInt32 a, epicsInt32 b, epicsInt32 c, epicsInt32 d) +{ + epicsInt32 buf[4]; + epicsInt32 expect[4]; + long nReq = NELEMENTS(buf), i; + unsigned match; + DBADDR addr; + + expect[0] = a; + expect[1] = b; + expect[2] = c; + expect[3] = d; + + if(dbNameToAddr(pv, &addr)) + testAbort("Unknown PV '%s'", pv); + + if(dbGet(&addr, DBR_LONG, buf, NULL, &nReq, NULL)) + testAbort("Failed to get '%s'", pv); + + match = elen==nReq; + for(i=0; i %d != %d", i, (int)expect[i], (int)buf[i]); + } +} + +static +void testFIFOCirc(void) +{ + aiRecord *vrec; + compressRecord *crec; + double *cbuf; + + testDiag("Test FIFO"); + + testdbPrepare(); + + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); + + recTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("compressTest.db", NULL, "ALG=Circular Buffer,BALG=FIFO Buffer,NSAM=4"); + + vrec = (aiRecord*)testdbRecordPtr("val"); + crec = (compressRecord*)testdbRecordPtr("comp"); + + eltc(0); + testIocInitOk(); + eltc(1); + + dbScanLock((dbCommon*)crec); + cbuf = crec->bptr; + + testOk1(crec->off==0); + testOk1(crec->inx==0); + testOk1(crec->nuse==0); + + testDiag("Push 1.1"); + vrec->val = 1.1; + dbProcess((dbCommon*)crec); + + /* In FIFO mode the valid elements a cbuf[(off-nuse-1)%size] through cbuf[(off-1)%size] */ + testOk1(crec->off==1); + testOk1(crec->inx==0); + testOk1(crec->nuse==1); + testDEq(cbuf[0], 1.1, 0.1); + testDEq(cbuf[1], 0.0, 0.1); + testDEq(cbuf[2], 0.0, 0.1); + testDEq(cbuf[3], 0.0, 0.1); + checkArrD("comp", 1, 1.1, 0, 0, 0); + + testDiag("Push 2.1"); + vrec->val = 2.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==2); + testOk1(crec->inx==0); + testOk1(crec->nuse==2); + testDEq(cbuf[0], 1.1, 0.1); + testDEq(cbuf[1], 2.1, 0.1); + testDEq(cbuf[2], 0.0, 0.1); + testDEq(cbuf[3], 0.0, 0.1); + checkArrD("comp", 2, 1.1, 2.1, 0, 0); + + testDiag("Push 3.1"); + vrec->val = 3.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==3); + testOk1(crec->inx==0); + testOk1(crec->nuse==3); + testDEq(cbuf[0], 1.1, 0.1); + testDEq(cbuf[1], 2.1, 0.1); + testDEq(cbuf[2], 3.1, 0.1); + testDEq(cbuf[3], 0.0, 0.1); + checkArrD("comp", 3, 1.1, 2.1, 3.1, 0); + + testDiag("Push 4.1"); + vrec->val = 4.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==0); + testOk1(crec->inx==0); + testOk1(crec->nuse==4); + testDEq(cbuf[0], 1.1, 0.1); + testDEq(cbuf[1], 2.1, 0.1); + testDEq(cbuf[2], 3.1, 0.1); + testDEq(cbuf[3], 4.1, 0.1); + checkArrD("comp", 4, 1.1, 2.1, 3.1, 4.1); + + testDiag("Push 5.1"); + vrec->val = 5.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==1); + testOk1(crec->inx==0); + testOk1(crec->nuse==4); + testDEq(cbuf[0], 5.1, 0.1); + testDEq(cbuf[1], 2.1, 0.1); + testDEq(cbuf[2], 3.1, 0.1); + testDEq(cbuf[3], 4.1, 0.1); + checkArrD("comp", 4, 2.1, 3.1, 4.1, 5.1); + + testDiag("Push 6.1"); + vrec->val = 6.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==2); + testOk1(crec->inx==0); + testOk1(crec->nuse==4); + testDEq(cbuf[0], 5.1, 0.1); + testDEq(cbuf[1], 6.1, 0.1); + testDEq(cbuf[2], 3.1, 0.1); + testDEq(cbuf[3], 4.1, 0.1); + checkArrD("comp", 4, 3.1, 4.1, 5.1, 6.1); + + dbScanUnlock((dbCommon*)crec); + + testDiag("Reset"); + testdbPutFieldOk("comp.RES", DBF_LONG, 0); + + dbScanLock((dbCommon*)crec); + testOk1(crec->off==0); + testOk1(crec->inx==0); + testOk1(crec->nuse==0); + checkArrD("comp", 0, 0, 0, 0, 0); + dbScanUnlock((dbCommon*)crec); + + testIocShutdownOk(); + + testdbCleanup(); +} + +static +void testLIFOCirc(void) +{ + aiRecord *vrec; + compressRecord *crec; + double *cbuf; + + testDiag("Test LIFO"); + + testdbPrepare(); + + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); + + recTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("compressTest.db", NULL, "ALG=Circular Buffer,BALG=LIFO Buffer,NSAM=4"); + + vrec = (aiRecord*)testdbRecordPtr("val"); + crec = (compressRecord*)testdbRecordPtr("comp"); + + eltc(0); + testIocInitOk(); + eltc(1); + + dbScanLock((dbCommon*)crec); + cbuf = crec->bptr; + + testOk1(crec->off==0); + testOk1(crec->inx==0); + testOk1(crec->nuse==0); + + testDiag("Push 1.1"); + vrec->val = 1.1; + dbProcess((dbCommon*)crec); + + testDiag("off %u", crec->off); + testOk1(crec->off==3); + testOk1(crec->inx==0); + testOk1(crec->nuse==1); + testDEq(cbuf[0], 0.0, 0.1); + testDEq(cbuf[1], 0.0, 0.1); + testDEq(cbuf[2], 0.0, 0.1); + testDEq(cbuf[3], 1.1, 0.1); + checkArrD("comp", 1, 1.1, 0, 0, 0); + + testDiag("Push 2.1"); + vrec->val = 2.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==2); + testOk1(crec->inx==0); + testOk1(crec->nuse==2); + testDEq(cbuf[0], 0.0, 0.1); + testDEq(cbuf[1], 0.0, 0.1); + testDEq(cbuf[2], 2.1, 0.1); + testDEq(cbuf[3], 1.1, 0.1); + checkArrD("comp", 2, 2.1, 1.1, 0, 0); + checkArrI("comp", 2, 2, 1, 0, 0); + + testDiag("Push 3.1"); + vrec->val = 3.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==1); + testOk1(crec->inx==0); + testOk1(crec->nuse==3); + testDEq(cbuf[0], 0.0, 0.1); + testDEq(cbuf[1], 3.1, 0.1); + testDEq(cbuf[2], 2.1, 0.1); + testDEq(cbuf[3], 1.1, 0.1); + checkArrD("comp", 3, 3.1, 2.1, 1.1, 0); + checkArrI("comp", 3, 3, 2, 1, 0); + + testDiag("Push 4.1"); + vrec->val = 4.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==0); + testOk1(crec->inx==0); + testOk1(crec->nuse==4); + testDEq(cbuf[0], 4.1, 0.1); + testDEq(cbuf[1], 3.1, 0.1); + testDEq(cbuf[2], 2.1, 0.1); + testDEq(cbuf[3], 1.1, 0.1); + checkArrD("comp", 4, 4.1, 3.1, 2.1, 1.1); + checkArrI("comp", 4, 4, 3, 2, 1); + + testDiag("Push 5.1"); + vrec->val = 5.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==3); + testOk1(crec->inx==0); + testOk1(crec->nuse==4); + testDEq(cbuf[0], 4.1, 0.1); + testDEq(cbuf[1], 3.1, 0.1); + testDEq(cbuf[2], 2.1, 0.1); + testDEq(cbuf[3], 5.1, 0.1); + checkArrD("comp", 4, 5.1, 4.1, 3.1, 2.1); + checkArrI("comp", 4, 5, 4, 3, 2); + + testDiag("Push 6.1"); + vrec->val = 6.1; + dbProcess((dbCommon*)crec); + + testOk1(crec->off==2); + testOk1(crec->inx==0); + testOk1(crec->nuse==4); + testDEq(cbuf[0], 4.1, 0.1); + testDEq(cbuf[1], 3.1, 0.1); + testDEq(cbuf[2], 6.1, 0.1); + testDEq(cbuf[3], 5.1, 0.1); + checkArrD("comp", 4, 6.1, 5.1, 4.1, 3.1); + + dbScanUnlock((dbCommon*)crec); + + testDiag("Reset"); + testdbPutFieldOk("comp.RES", DBF_LONG, 0); + + dbScanLock((dbCommon*)crec); + testOk1(crec->off==0); + testOk1(crec->inx==0); + testOk1(crec->nuse==0); + checkArrD("comp", 0, 0, 0, 0, 0); + dbScanUnlock((dbCommon*)crec); + + testIocShutdownOk(); + + testdbCleanup(); +} + +MAIN(compressTest) +{ + testPlan(116); + testFIFOCirc(); + testLIFOCirc(); + return testDone(); +} diff --git a/src/std/rec/test/compressTest.db b/src/std/rec/test/compressTest.db new file mode 100644 index 000000000..59fc620ba --- /dev/null +++ b/src/std/rec/test/compressTest.db @@ -0,0 +1,7 @@ +record(ai, "val") {} +record(compress, "comp") { + field(INP, "val NPP") + field(ALG, "$(ALG)") + field(BALG,"$(BALG)") + field(NSAM,"$(NSAM)") +} diff --git a/src/std/rec/test/epicsRunRecordTests.c b/src/std/rec/test/epicsRunRecordTests.c index 3476d2138..5612917cc 100644 --- a/src/std/rec/test/epicsRunRecordTests.c +++ b/src/std/rec/test/epicsRunRecordTests.c @@ -13,6 +13,7 @@ #include "epicsExit.h" int analogMonitorTest(void); +int compressTest(void); int arrayOpTest(void); int asTest(void); int linkRetargetLinkTest(void); @@ -23,6 +24,8 @@ void epicsRunRecordTests(void) runTest(analogMonitorTest); + runTest(compressTest); + runTest(arrayOpTest); runTest(asTest); From 61435206805a1b9fc6ef0932b46188b47dc78110 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Jan 2016 21:46:00 -0500 Subject: [PATCH 8/8] update release notes --- documentation/RELEASE_NOTES.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 8ae4e76d3..6f258ed8b 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -20,6 +20,12 @@ --> +

compressRecord buffering order

+ +

The compressRecord has a new field BALG which can select between +FIFO (append) and LIFO (prepend) ordering for insertion of new elements. +FIFO ordering is the default.

+

Database Multi-locking

dbLock.c is re-written with an expanded API, and the removal of global mutex locks.