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:
250
src/db/cvtBpt.c
250
src/db/cvtBpt.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user