diff --git a/modules/database/src/std/rec/compressRecord.c b/modules/database/src/std/rec/compressRecord.c index b6fafb4ab3..74933bb3d8 100644 --- a/modules/database/src/std/rec/compressRecord.c +++ b/modules/database/src/std/rec/compressRecord.c @@ -149,12 +149,15 @@ static int compare(const void *arg1, const void *arg2) else return 1; } +#define min(a, b) ((a) < (b) ? (a) : (b)) + static int compress_array(compressRecord *prec, double *psource, int no_elements) { - epicsInt32 i,j; + epicsInt32 j; epicsInt32 n, nnew; epicsInt32 nsam = prec->nsam; + epicsUInt32 samples_written = 0; double value; /* skip out of limit data */ @@ -167,61 +170,54 @@ static int compress_array(compressRecord *prec, } if (prec->n <= 0) prec->n = 1; - if (no_elements < prec->n && prec->pbuf != menuYesNoYES) - return 1; /*dont do anything*/ - n = no_elements; + n = prec->n; - /* determine number of samples to take */ - if (no_elements < nsam * n) - nnew = (no_elements / n); - else nnew = nsam; + nnew = min(no_elements, nsam * n); - /* 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++) { + while (nnew > 0) + { + if (nnew < n && prec->pbuf != menuYesNoYES) + break; + + n = min(n, nnew); + switch (prec->alg) + { + case compressALG_N_to_1_Low_Value: value = *psource++; - for (j = 1; j < n; j++, 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++){ + break; + case compressALG_N_to_1_High_Value: value = *psource++; - for (j = 1; j < n; j++, 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++) + break; + case compressALG_N_to_1_Average: + value = *psource++; + for (j = 1; 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) { + } + value = value / n; + break; + case compressALG_N_to_1_Median: + /* note: sorts source array (OK; it's a work pointer) */ qsort(psource, n, sizeof(double), compare); value = psource[n / 2]; - put_value(prec, &value, 1); + psource += n; + break; } - break; + nnew -= n; + put_value(prec, &value, 1); + samples_written++; } - return 0; + return (samples_written > 0); } static int array_average(compressRecord *prec, diff --git a/modules/database/test/std/rec/compressTest.c b/modules/database/test/std/rec/compressTest.c index ed5f31e638..cedb28f485 100644 --- a/modules/database/test/std/rec/compressTest.c +++ b/modules/database/test/std/rec/compressTest.c @@ -469,6 +469,38 @@ testNto1Average(void) { testdbCleanup(); } +void testNto2Average(void) { + DBADDR wfaddr, caddr; + + testDiag("Test N to 1 Average, NSAM=2, N=2"); + + testdbPrepare(); + + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); + + recTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=2"); + + eltc(0); + testIocInitOk(); + eltc(1); + + fetchRecordOrDie("wf", wfaddr); + fetchRecordOrDie("comp", caddr); + + writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.); + + dbScanLock(caddr.precord); + dbProcess(caddr.precord); + + checkArrD("comp", 2, 1.5, 3.5, 0, 0); + dbScanUnlock(caddr.precord); + + testIocShutdownOk(); + testdbCleanup(); +} + void testNto1AveragePartial(void) { double buf = 0.0; @@ -517,6 +549,36 @@ testNto1AveragePartial(void) { testdbCleanup(); } +void +testNtoMPartial(void) { + DBADDR wfaddr, caddr; + + testDiag("Test Average, N to M, Partial"); + + testdbPrepare(); + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); + recTestIoc_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=3,PBUF=YES"); + + eltc(0); + testIocInitOk(); + eltc(1); + + fetchRecordOrDie("wf", wfaddr); + fetchRecordOrDie("comp", caddr); + + writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.); + + dbScanLock(caddr.precord); + dbProcess(caddr.precord); + + checkArrD("comp", 2, 2.0, 4.0, 0, 0); + dbScanUnlock(caddr.precord); + + testIocShutdownOk(); + testdbCleanup(); +} + void testNto1LowValue(void) { double buf = 0.0; @@ -634,12 +696,14 @@ testAIAveragePartial(void) { MAIN(compressTest) { - testPlan(132); + testPlan(134); testFIFOCirc(); testLIFOCirc(); testArrayAverage(); testNto1Average(); + testNto2Average(); testNto1AveragePartial(); + testNtoMPartial(); testAIAveragePartial(); testNto1LowValue(); return testDone();