Permit breakpoint tables to run any direction as long as the slope doesn't

change sign. Reduced memory requirement by making the table a contiguous
array rather than an array of pointers to intervals. Improved error reporting.
This commit is contained in:
Andrew Johnson
2006-10-26 16:05:23 +00:00
parent 5c7fa0e3be
commit 7dc2eec5aa
4 changed files with 219 additions and 157 deletions

View File

@@ -15,11 +15,7 @@
* Date: 04OCT95
* This is adaptation of old bldCvtTable
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "ellLib.h"
#include "dbBase.h"
#include "dbStaticLib.h"
#include "epicsPrint.h"
@@ -27,125 +23,181 @@
#define epicsExportSharedSymbols
#include "dbAccess.h"
#include "cvtTable.h"
static brkTable *findBrkTable(short linr)
{
dbMenu *pdbMenu;
pdbMenu = dbFindMenu(pdbbase,"menuConvert");
if(!pdbMenu) {
epicsPrintf("findBrkTable: menuConvert does not exist\n");
return(0);
if (!pdbMenu) {
epicsPrintf("findBrkTable: menuConvert not loaded!\n");
return NULL;
}
if(linr<0 || linr>=pdbMenu->nChoice) {
epicsPrintf("findBrkTable linr %d but menuConvert has %d choices\n",
if (linr < 0 || linr >= pdbMenu->nChoice) {
epicsPrintf("findBrkTable: linr=%d but menuConvert only has %d choices\n",
linr,pdbMenu->nChoice);
return(0);
return NULL;
}
return(dbFindBrkTable(pdbbase,pdbMenu->papChoiceValue[linr]));
return dbFindBrkTable(pdbbase,pdbMenu->papChoiceValue[linr]);
}
long epicsShareAPI cvtRawToEngBpt(double *pval,short linr,short init, void **ppbrk,
short *plbrk)
{
double val=*pval;
long status=0;
/* Used by both ao and ai record types */
long epicsShareAPI cvtRawToEngBpt(double *pval, short linr, short init,
void **ppbrk, short *plbrk)
{
double val = *pval;
long status = 0;
brkTable *pbrkTable;
brkInt *pInt;
brkInt *pnxtInt;
brkInt *pInt, *nInt;
short lbrk;
int number;
if (linr < 2)
return -1;
if(linr < 2) return(-1);
if(init==TRUE || *ppbrk == NULL) { /*must find breakpoint table*/
if (init || *ppbrk == NULL) {
pbrkTable = findBrkTable(linr);
if(!pbrkTable) return(S_dbLib_badField);
if (!pbrkTable)
return S_dbLib_badField;
*ppbrk = (void *)pbrkTable;
/* Just start at the beginning */
*plbrk=0;
}
pbrkTable = (struct brkTable *)*ppbrk;
*plbrk = 0;
} else
pbrkTable = (brkTable *)*ppbrk;
number = pbrkTable->number;
lbrk = *plbrk;
/*make sure we dont go off end of table*/
if( (lbrk+1) >= number ) lbrk--;
pInt = pbrkTable->papBrkInt[lbrk];
pnxtInt = pbrkTable->papBrkInt[lbrk+1];
/* find entry for increased value */
while( (pnxtInt->raw) <= val ) {
lbrk++;
pInt = pbrkTable->papBrkInt[lbrk];
if( lbrk >= number-1) {
status=1;
break;
}
pnxtInt = pbrkTable->papBrkInt[lbrk+1];
}
while( (pInt->raw) > val) {
if(lbrk==0) {
status=1;
break;
}
lbrk--;
pInt = pbrkTable->papBrkInt[lbrk];
/* Limit index to the size of the table */
if (lbrk < 0)
lbrk = 0;
else if (lbrk > number-2)
lbrk = number-2;
pInt = & pbrkTable->paBrkInt[lbrk];
nInt = pInt + 1;
if (nInt->raw > pInt->raw) {
/* raw values increase down the table */
while (val > nInt->raw) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while (val < pInt->raw) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
} else {
/* raw values decrease down the table */
while (val <= nInt->raw) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while(val > pInt->raw) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
}
*plbrk = lbrk;
*pval = pInt->eng + (val - pInt->raw) * pInt->slope;
return(status);
return status;
}
long epicsShareAPI cvtEngToRawBpt(double *pval,short linr,short init,
void **ppbrk,short *plbrk)
{
double val=*pval;
long status=0;
brkTable *pbrkTable;
brkInt *pInt;
brkInt *pnxtInt;
short lbrk;
int number;
/* Used by the ao record type */
long epicsShareAPI cvtEngToRawBpt(double *pval, short linr, short init,
void **ppbrk, short *plbrk)
{
double val = *pval;
long status = 0;
brkTable *pbrkTable;
brkInt *pInt, *nInt;
short lbrk;
int number;
if(linr < 2) return(-1);
if(init==TRUE || *ppbrk == NULL) { /*must find breakpoint table*/
if (linr < 2)
return -1;
if (init || *ppbrk == NULL) { /*must find breakpoint table*/
pbrkTable = findBrkTable(linr);
if(!pbrkTable) return(S_dbLib_badField);
if (!pbrkTable)
return S_dbLib_badField;
*ppbrk = (void *)pbrkTable;
/* Just start at the beginning */
*plbrk=0;
}
pbrkTable = (struct brkTable *)*ppbrk;
number = pbrkTable->number;
lbrk = *plbrk;
/*make sure we dont go off end of table*/
if( (lbrk+1) >= number ) lbrk--;
pInt = pbrkTable->papBrkInt[lbrk];
pnxtInt = pbrkTable->papBrkInt[lbrk+1];
/* find entry for increased value */
while( (pnxtInt->eng) <= val ) {
lbrk++;
pInt = pbrkTable->papBrkInt[lbrk];
if( lbrk >= number-1) {
status=1;
break;
}
pnxtInt = pbrkTable->papBrkInt[lbrk+1];
}
while( (pInt->eng) > val) {
if(lbrk==0) {
status=1;
break;
}
lbrk--;
pInt = pbrkTable->papBrkInt[lbrk];
}
if(pInt->slope!=0){
*plbrk = lbrk;
*pval = pInt->raw + (val - pInt->eng) / pInt->slope;
}
else {
return(status);
}
return(0);
/* start at the beginning */
*plbrk = 0;
} else
pbrkTable = (brkTable *)*ppbrk;
number = pbrkTable->number;
lbrk = *plbrk;
/* Limit index to the size of the table */
if (lbrk < 0)
lbrk = 0;
else if (lbrk > number-2)
lbrk = number-2;
pInt = & pbrkTable->paBrkInt[lbrk];
nInt = pInt + 1;
if (nInt->eng > pInt->eng) {
/* eng values increase down the table */
while (val > nInt->eng) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while (val < pInt->eng) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
} else {
/* eng values decrease down the table */
while (val <= nInt->eng) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while (val > pInt->eng) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
}
*plbrk = lbrk;
*pval = pInt->raw + (val - pInt->eng) / pInt->slope;
return status;
}

View File

@@ -65,7 +65,7 @@ typedef struct brkTable { /* breakpoint table */
ELLNODE node;
char *name; /*breakpoint table name */
long number; /*number of brkInt in this table*/
struct brkInt **papBrkInt; /* ptr to array of ptr to brkInt */
struct brkInt *paBrkInt; /* ptr to array of brkInts */
}brkTable;
typedef struct dbFldDes{ /* field description */

View File

@@ -823,77 +823,84 @@ static void dbBreakHead(char *name)
static void dbBreakItem(char *value)
{
if(duplicate) return;
double dummy;
if (duplicate) return;
if (epicsScanDouble(value, &dummy) != 1) {
yyerrorAbort("Non-numeric value in breaktable");
}
allocTemp(epicsStrDup(value));
}
static void dbBreakBody(void)
{
brkTable *pnewbrkTable;
brkInt *paBrkInt;
brkTable *pbrkTable;
int number;
int number, down=0;
int i,choice;
GPHENTRY *pgphentry;
if(duplicate) {
if (duplicate) {
duplicate = FALSE;
return;
}
pnewbrkTable = (brkTable *)popFirstTemp();
pnewbrkTable->number = number = ellCount(&tempList)/2;
if(number*2 != ellCount(&tempList))
yyerrorAbort("dbBreakBody: Odd number of values");
pnewbrkTable->papBrkInt = dbCalloc(number,sizeof(brkInt));
for(i=0; i<number; i++) {
double raw,eng;
char *praw;
char *peng;
number = ellCount(&tempList);
if (number % 2) {
yyerrorAbort("breaktable: Raw value missing");
return;
}
number /= 2;
if (number < 2) {
yyerrorAbort("breaktable: Must have at least two points!");
return;
}
pnewbrkTable->number = number;
pnewbrkTable->paBrkInt = paBrkInt = dbCalloc(number, sizeof(brkInt));
for (i=0; i<number; i++) {
double val;
char *str;
praw = (char *)popFirstTemp();
peng = (char *)popFirstTemp();
if((epicsScanDouble(praw, &raw)!=1) || (sscanf(peng,"%lf",&eng)!=1) ) {
yyerrorAbort("dbbrkTable: Illegal table value");
}
free((void *)praw);
free((void *)peng);
pnewbrkTable->papBrkInt[i] = dbCalloc(1,sizeof(brkInt));
pnewbrkTable->papBrkInt[i]->raw = raw;
pnewbrkTable->papBrkInt[i]->eng = eng;
str = (char *)popFirstTemp();
epicsScanDouble(str, &paBrkInt[i].raw);
free(str);
str = (char *)popFirstTemp();
epicsScanDouble(str, &paBrkInt[i].eng);
free(str);
}
/* Compute slopes */
for(i=0; i<number-1; i++) {
pnewbrkTable->papBrkInt[i]->slope =
(pnewbrkTable->papBrkInt[i+1]->eng - pnewbrkTable->papBrkInt[i]->eng)/
(pnewbrkTable->papBrkInt[i+1]->raw - pnewbrkTable->papBrkInt[i]->raw);
}
if(number>1) {
pnewbrkTable->papBrkInt[number-1]->slope =
pnewbrkTable->papBrkInt[number-2]->slope;
for (i=0; i<number-1; i++) {
double slope =
(paBrkInt[i+1].eng - paBrkInt[i].eng)/
(paBrkInt[i+1].raw - paBrkInt[i].raw);
if (i == 0) {
down = (slope < 0);
} else if (down != (slope < 0)) {
yyerrorAbort("breaktable: curve slope changes sign");
return;
}
paBrkInt[i].slope = slope;
}
/* Continue with last slope beyond the final point */
paBrkInt[number-1].slope = paBrkInt[number-2].slope;
/* Add brkTable in sorted order */
pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
while(pbrkTable) {
choice = strcmp(pbrkTable->name,pnewbrkTable->name);
if(choice==0) {
ellInsert(&pdbbase->bptList,ellPrevious((ELLNODE *)pbrkTable),
(ELLNODE *)pnewbrkTable);
gphDelete(pdbbase->pgpHash,pbrkTable->name,&pdbbase->bptList);
ellDelete(&pdbbase->bptList,(ELLNODE *)pbrkTable);
break;
} else if(choice>0) {
ellInsert(&pdbbase->bptList,ellPrevious((ELLNODE *)pbrkTable),
while (pbrkTable) {
if (strcmp(pbrkTable->name, pnewbrkTable->name) > 0) {
ellInsert(&pdbbase->bptList, ellPrevious((ELLNODE *)pbrkTable),
(ELLNODE *)pnewbrkTable);
break;
}
pbrkTable = (brkTable *)ellNext(&pbrkTable->node);
}
if (!pbrkTable) ellAdd(&pdbbase->bptList, &pnewbrkTable->node);
pgphentry = gphAdd(pdbbase->pgpHash,pnewbrkTable->name,&pdbbase->bptList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
pgphentry->userPvt = pnewbrkTable;
if (!pgphentry) {
yyerrorAbort("dbBreakBody: gphAdd failed");
return;
}
if(!pbrkTable) ellAdd(&pdbbase->bptList,&pnewbrkTable->node);
pgphentry->userPvt = pnewbrkTable;
}
static void dbRecordHead(char *recordType,char *name, int visible)

View File

@@ -716,8 +716,7 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
gphDelete(pdbbase->pgpHash,pbrkTable->name,&pdbbase->bptList);
ellDelete(&pdbbase->bptList,&pbrkTable->node);
free(pbrkTable->name);
for(i=0; i<pbrkTable->number; i++)
free((void *)(pbrkTable->papBrkInt[i]));
free((void *)pbrkTable->paBrkInt);
free((void *)pbrkTable);
pbrkTable = pbrkTableNext;
}
@@ -1225,18 +1224,20 @@ long epicsShareAPI dbWriteBreaktableFP(DBBASE *pdbbase,FILE *fp)
{
brkTable *pbrkTable;
brkInt *pbrkInt;
int ind;
int i;
if(!pdbbase) {
if (!pdbbase) {
fprintf(stderr,"pdbbase not specified\n");
return(-1);
}
for(pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
pbrkTable; pbrkTable = (brkTable *)ellNext(&pbrkTable->node)) {
for (pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
pbrkTable;
pbrkTable = (brkTable *)ellNext(&pbrkTable->node)) {
fprintf(fp,"breaktable(%s) {\n",pbrkTable->name);
for(ind=0; ind<pbrkTable->number; ind++) {
pbrkInt = pbrkTable->papBrkInt[ind];
fprintf(fp,"\t%e %e\n",pbrkInt->raw,pbrkInt->eng);
pbrkInt = pbrkTable->paBrkInt;
for(i=0; i < pbrkTable->number; i++) {
fprintf(fp,"\t%e, %e\n",pbrkInt->raw,pbrkInt->eng);
pbrkInt++;
}
fprintf(fp,"}\n");
}
@@ -3856,11 +3857,13 @@ void epicsShareAPI dbDumpBreaktable(DBBASE *pdbbase,const char *name)
}
for(pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
pbrkTable; pbrkTable = (brkTable *)ellNext(&pbrkTable->node)) {
if(name && strcmp(name,pbrkTable->name)!=0) continue;
if (name && strcmp(name,pbrkTable->name)!=0) continue;
printf("breaktable(%s) {\n",pbrkTable->name);
for(ind=0; ind<pbrkTable->number; ind++) {
pbrkInt = pbrkTable->papBrkInt[ind];
printf("\t%f %e %f\n",pbrkInt->raw,pbrkInt->slope,pbrkInt->eng);
pbrkInt = pbrkTable->paBrkInt;
for(ind=0; ind < pbrkTable->number; ind++) {
printf("\traw=%f slope=%e eng=%f\n",
pbrkInt->raw, pbrkInt->slope, pbrkInt->eng);
pbrkInt++;
}
printf("}\n");
}