Merged compress branch

This commit is contained in:
Andrew Johnson
2016-02-29 13:24:16 -06:00
8 changed files with 653 additions and 205 deletions
+6
View File
@@ -20,6 +20,12 @@
-->
<h3>compressRecord buffering order</h3>
<p>The compressRecord has a new field <tt>BALG</tt> which can select between
FIFO (append) and LIFO (prepend) ordering for insertion of new elements. FIFO
ordering is the default, matching the behviour of previous versions.</p>
<h3>Valgrind Instrumentation</h3>
<p>Valgrind is a software debugging suite provided by many Linux distributions.
+35 -23
View File
@@ -33,8 +33,7 @@ typedef struct myStruct {
static void *myStructFreeList;
static const
chfPluginArgDef opts[] = {
static const chfPluginArgDef opts[] = {
chfInt32 (myStruct, start, "s", 0, 1),
chfInt32 (myStruct, incr, "i", 0, 1),
chfInt32 (myStruct, end, "e", 0, 1),
@@ -67,13 +66,16 @@ static int parse_ok(void *pvt)
return 0;
}
static void freeArray(db_field_log *pfl) {
static void freeArray(db_field_log *pfl)
{
if (pfl->type == dbfl_type_ref) {
freeListFree(pfl->u.r.pvt, pfl->u.r.field);
}
}
static long wrapArrayIndices(long *start, const long increment, long *end, const long no_elements) {
static long wrapArrayIndices(long *start, const long increment, long *end,
const long no_elements)
{
long len = 0;
if (*start < 0) *start = no_elements + *start;
@@ -88,7 +90,8 @@ static long wrapArrayIndices(long *start, const long increment, long *end, const
return len;
}
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
{
myStruct *my = (myStruct*) pvt;
struct dbCommon *prec;
struct rset *prset;
@@ -97,13 +100,16 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
long nTarget = 0;
long offset = 0;
long nSource = chan->addr.no_elements;
long capacity = nSource;
void *pdst;
/* Only array data */
if (pfl->type == dbfl_type_val) {
return pfl;
switch (pfl->type) {
case dbfl_type_val:
/* Only filter arrays */
break;
/* Extract from record */
} else if (pfl->type == dbfl_type_rec) {
case dbfl_type_rec:
/* Extract from record */
if (chan->addr.special == SPC_DBADDR &&
nSource > 1 &&
(prset = dbGetRset(&chan->addr)) &&
@@ -122,32 +128,36 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
pfl->field_size = chan->addr.field_size;
pfl->no_elements = nTarget;
if (nTarget) {
void *pdst = freeListCalloc(my->arrayFreeList);
pdst = freeListCalloc(my->arrayFreeList);
if (pdst) {
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, capacity,
offset, my->incr);
pfl->u.r.field = pdst;
}
}
dbScanUnlock(prec);
chan->addr.pfield = pfieldsave;
}
break;
/* Extract from buffer */
} else if (pfl->type == dbfl_type_ref) {
void *psrc = pfl->u.r.field;
void *pdst = NULL;
case dbfl_type_ref:
pdst = NULL;
nSource = pfl->no_elements;
nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
pfl->no_elements = nTarget;
if (nTarget) { /* Copy the data out */
if (nTarget) {
/* Copy the data out */
void *psrc = pfl->u.r.field;
pdst = freeListCalloc(my->arrayFreeList);
if (!pdst) return pfl;
if (!pdst) break;
offset = start;
dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type, nTarget, nSource, offset, my->incr);
dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type,
nTarget, nSource, offset, my->incr);
}
if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
if (nTarget) {
@@ -155,21 +165,22 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
pfl->u.r.pvt = my->arrayFreeList;
pfl->u.r.field = pdst;
}
break;
}
return pfl;
}
static void channelRegisterPost(dbChannel *chan, void *pvt,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
{
myStruct *my = (myStruct*) pvt;
long start = my->start;
long end = my->end;
long max = 0;
if (probe->no_elements <= 1) return; /* array data only */
if (probe->no_elements <= 1) return; /* array data only */
max = wrapArrayIndices(&start, my->incr, &end, probe->no_elements); /* wrap indices into array */
max = wrapArrayIndices(&start, my->incr, &end, probe->no_elements);
if (max) {
if (!my->arrayFreeList)
freeListInitPvt(&my->arrayFreeList, max * probe->field_size, 2);
@@ -180,7 +191,8 @@ static void channelRegisterPost(dbChannel *chan, void *pvt,
*arg_out = pvt;
}
static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent)
static void channel_report(dbChannel *chan, void *pvt, int level,
const unsigned short indent)
{
myStruct *my = (myStruct*) pvt;
printf("%*sArray (arr): start=%d, incr=%d, end=%d\n", indent, "",
+210 -177
View File
@@ -89,9 +89,12 @@ static void reset(compressRecord *prec)
prec->cvb = 0.0;
prec->res = 0;
/* allocate memory for the summing buffer for conversions requiring it */
if (prec->alg == compressALG_Average && prec->sptr == 0){
if (prec->alg == compressALG_Average && prec->sptr == NULL) {
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)
@@ -108,29 +111,32 @@ static void monitor(compressRecord *prec)
static void put_value(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;
int fifo = (prec->balg == bufferingALG_FIFO);
epicsUInt32 offset = prec->off;
epicsUInt32 nuse = prec->nuse;
epicsUInt32 nsam = prec->nsam;
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;
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;
}
prec->off = offset;
prec->nuse = nuse;
return;
}
/* qsort comparison function (for median calculation) */
static int compare(const void *arg1, const void *arg2)
{
@@ -145,157 +151,167 @@ static int compare(const void *arg1, const void *arg2)
static int compress_array(compressRecord *prec,
double *psource, int no_elements)
{
epicsInt32 i,j;
epicsInt32 nnew;
epicsInt32 nsam=prec->nsam;
double value;
epicsInt32 n;
epicsInt32 i,j;
epicsInt32 n, nnew;
epicsInt32 nsam = prec->nsam;
double value;
/* skip out of limit data */
if (prec->ilil < prec->ihil){
while (((*psource < prec->ilil) || (*psource > prec->ihil))
&& (no_elements > 0)){
no_elements--;
psource++;
}
}
if(prec->n <= 0) prec->n = 1;
n = prec->n;
if(no_elements<n) return(1); /*dont do anything*/
/* determine number of samples to take */
if (no_elements < (nsam * n)) nnew = (no_elements / n);
else nnew = nsam;
/* compress according to specified algorithm */
switch (prec->alg){
case (compressALG_N_to_1_Low_Value):
/* compress N to 1 keeping the lowest value */
for (i = 0; i < nnew; i++){
value = *psource++;
for (j = 1; j < n; j++, psource++){
if (value > *psource) value = *psource;
}
put_value(prec,&value,1);
}
break;
case (compressALG_N_to_1_High_Value):
/* compress N to 1 keeping the highest value */
for (i = 0; i < nnew; i++){
value = *psource++;
for (j = 1; j < n; j++, psource++){
if (value < *psource) value = *psource;
}
put_value(prec,&value,1);
}
break;
case (compressALG_N_to_1_Average):
/* compress N to 1 keeping the average value */
for (i = 0; i < nnew; i++){
value = 0;
for (j = 0; j < n; j++, psource++)
value += *psource;
value /= n;
put_value(prec,&value,1);
}
break;
case (compressALG_N_to_1_Median):
/* compress N to 1 keeping the median value */
/* note: sorts source array (OK; it's a work pointer) */
for (i = 0; i < nnew; i++, psource+=nnew){
qsort(psource,n,sizeof(double),compare);
value=psource[n/2];
put_value(prec,&value,1);
}
break;
/* skip out of limit data */
if (prec->ilil < prec->ihil) {
while (((*psource < prec->ilil) || (*psource > prec->ihil))
&& (no_elements > 0)) {
no_elements--;
psource++;
}
return(0);
}
if (prec->n <= 0)
prec->n = 1;
n = prec->n;
if (no_elements < n)
return 1; /*dont do anything*/
/* determine number of samples to take */
if (no_elements < nsam * n)
nnew = (no_elements / n);
else nnew = nsam;
/* compress according to specified algorithm */
switch (prec->alg){
case compressALG_N_to_1_Low_Value:
/* compress N to 1 keeping the lowest value */
for (i = 0; i < nnew; i++) {
value = *psource++;
for (j = 1; j < n; j++, psource++) {
if (value > *psource)
value = *psource;
}
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_High_Value:
/* compress N to 1 keeping the highest value */
for (i = 0; i < nnew; i++){
value = *psource++;
for (j = 1; j < n; j++, psource++) {
if (value < *psource)
value = *psource;
}
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_Average:
/* compress N to 1 keeping the average value */
for (i = 0; i < nnew; i++) {
value = 0;
for (j = 0; j < n; j++, psource++)
value += *psource;
value /= n;
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_Median:
/* compress N to 1 keeping the median value */
/* note: sorts source array (OK; it's a work pointer) */
for (i = 0; i < nnew; i++, psource += nnew) {
qsort(psource, n, sizeof(double), compare);
value = psource[n / 2];
put_value(prec, &value, 1);
}
break;
}
return 0;
}
static int array_average(compressRecord *prec,
double *psource,epicsInt32 no_elements)
double *psource, epicsInt32 no_elements)
{
epicsInt32 i;
epicsInt32 nnow;
epicsInt32 nsam=prec->nsam;
double *psum;
double multiplier;
epicsInt32 inx=prec->inx;
epicsInt32 nuse,n;
epicsInt32 i;
epicsInt32 nnow;
epicsInt32 nsam=prec->nsam;
double *psum;
double multiplier;
epicsInt32 inx = prec->inx;
epicsInt32 nuse, n;
nuse = nsam;
if(nuse>no_elements) nuse = no_elements;
nnow=nuse;
if(nnow>no_elements) nnow=no_elements;
psum = (double *)prec->sptr;
nuse = nsam;
if (nuse > no_elements)
nuse = no_elements;
nnow = nuse;
if (nnow > no_elements)
nnow=no_elements;
psum = (double *)prec->sptr;
/* add in the new waveform */
if (inx == 0){
for (i = 0; i < nnow; i++)
*psum++ = *psource++;
for(i=nnow; i<nuse; i++) *psum++ = 0;
}else{
for (i = 0; i < nnow; i++)
*psum++ += *psource++;
}
/* add in the new waveform */
if (inx == 0) {
for (i = 0; i < nnow; i++)
*psum++ = *psource++;
for (i = nnow; i < nuse; i++)
*psum++ = 0;
} else {
for (i = 0; i < nnow; i++)
*psum++ += *psource++;
}
/* do we need to calculate the result */
inx++;
if(prec->n<=0)prec->n=1;
n = prec->n;
if (inx<n) {
prec->inx = inx;
return(1);
}
if(n>1) {
psum = (double *)prec->sptr;
multiplier = 1.0/((double)n);
for (i = 0; i < nuse; i++, psum++)
*psum = *psum * multiplier;
}
put_value(prec,prec->sptr,nuse);
prec->inx = 0;
return(0);
/* do we need to calculate the result */
inx++;
if (prec->n <= 0)
prec->n = 1;
n = prec->n;
if (inx < n) {
prec->inx = inx;
return 1;
}
if (n > 1) {
psum = (double *)prec->sptr;
multiplier = 1.0 / n;
for (i = 0; i < nuse; i++, psum++)
*psum = *psum * multiplier;
}
put_value(prec, prec->sptr, nuse);
prec->inx = 0;
return 0;
}
static int compress_scalar(struct compressRecord *prec,double *psource)
{
double value = *psource;
double *pdest=&prec->cvb;
epicsInt32 inx = prec->inx;
double value = *psource;
double *pdest=&prec->cvb;
epicsInt32 inx = prec->inx;
/* compress according to specified algorithm */
switch (prec->alg){
case (compressALG_N_to_1_Low_Value):
if ((value < *pdest) || (inx == 0))
*pdest = value;
break;
case (compressALG_N_to_1_High_Value):
if ((value > *pdest) || (inx == 0))
*pdest = value;
break;
/* for scalars, Median not implemented => use average */
case (compressALG_N_to_1_Average):
case (compressALG_N_to_1_Median):
if (inx == 0)
*pdest = value;
else {
*pdest += value;
if(inx+1>=(prec->n)) *pdest = *pdest/(inx+1);
}
break;
}
inx++;
if(inx>=prec->n) {
put_value(prec,pdest,1);
prec->inx = 0;
return(0);
} else {
prec->inx = inx;
return(1);
}
/* compress according to specified algorithm */
switch (prec->alg) {
case (compressALG_N_to_1_Low_Value):
if ((value < *pdest) || (inx == 0))
*pdest = value;
break;
case (compressALG_N_to_1_High_Value):
if ((value > *pdest) || (inx == 0))
*pdest = value;
break;
/* for scalars, Median not implemented => use average */
case (compressALG_N_to_1_Average):
case (compressALG_N_to_1_Median):
if (inx == 0)
*pdest = value;
else {
*pdest += value;
if (inx + 1 >= prec->n)
*pdest = *pdest / (inx + 1);
}
break;
}
inx++;
if (inx >= prec->n) {
put_value(prec,pdest,1);
prec->inx = 0;
return 0;
} else {
prec->inx = inx;
return 1;
}
}
/*Beginning of record support routines*/
static long init_record(compressRecord *prec, int pass)
{
@@ -305,6 +321,7 @@ static long init_record(compressRecord *prec, int pass)
prec->bptr = calloc(prec->nsam, sizeof(double));
reset(prec);
}
return 0;
}
@@ -350,6 +367,7 @@ static long process(compressRecord *prec)
else
status = 1;
}
/* check event list */
if (status != 1) {
prec->udf = FALSE;
@@ -358,10 +376,11 @@ static long process(compressRecord *prec)
/* process the forward scan link record */
recGblFwdLink(prec);
}
prec->pact = FALSE;
return 0;
}
static long special(DBADDR *paddr, int after)
{
compressRecord *prec = (compressRecord *) paddr->precord;
@@ -388,18 +407,31 @@ 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)
{
/* 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;
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;
}
*no_elements = prec->nuse;
if (prec->nuse == prec->nsam)
*offset = prec->off;
else
*offset = 0;
return 0;
}
@@ -407,7 +439,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;
@@ -440,14 +473,14 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
compressRecord *prec = (compressRecord *) paddr->precord;
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(IHIL):
case indexof(ILIL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
case indexof(VAL):
case indexof(IHIL):
case indexof(ILIL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return 0;
}
@@ -457,14 +490,14 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
compressRecord *prec = (compressRecord *) paddr->precord;
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(IHIL):
case indexof(ILIL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
default:
recGblGetControlDouble(paddr, pcd);
case indexof(VAL):
case indexof(IHIL):
case indexof(ILIL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
default:
recGblGetControlDouble(paddr, pcd);
}
return 0;
}
+31 -5
View File
@@ -9,19 +9,34 @@
=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.
...
The ALG field which uses this menu controls the compression algorithm used by
the record.
=menu compressALG
...
=head3 Menu bufferingALG
The BALG field which uses this menu controls whether new values are inserted at
the beginning or the end of the VAL array.
=menu bufferingALG
=head2 Parameter Fields
@@ -41,6 +56,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 +95,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)
+7
View File
@@ -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
+354
View File
@@ -0,0 +1,354 @@
/*************************************************************************\
* 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<nReq && i<elen; i++) {
match &= fabs(buf[i]-expect[i])<0.01;
}
testOk(match, "dbGet(\"%s\") matches", pv);
if (elen!=nReq)
testDiag("lengths don't match %ld != %ld", elen, nReq);
for (i=0; i<nReq && i<elen; i++) {
if (fabs(buf[i]-expect[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<nReq && i<elen; i++) {
match &= buf[i]==expect[i];
}
testOk(match, "dbGet(\"%s\") matches", pv);
if (elen!=nReq)
testDiag("lengths don't match %ld != %ld", elen, nReq);
for (i=0; i<nReq && i<elen; i++) {
if(buf[i]!=expect[i])
testDiag("[%ld] -> %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 are
* 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();
}
+7
View File
@@ -0,0 +1,7 @@
record(ai, "val") {}
record(compress, "comp") {
field(INP, "val NPP")
field(ALG, "$(ALG)")
field(BALG,"$(BALG)")
field(NSAM,"$(NSAM)")
}
+3
View File
@@ -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);