update to the .measure and meas error messages:

remove crash uipon buggy inputs
add buggy example input file
unify fcn returns: 0 is OK, 1 is bad
Improve on error message for bad syntax
This commit is contained in:
Holger Vogt 2020-01-18 16:49:04 +01:00
parent 76d2a12b07
commit 6b476e99af
2 changed files with 175 additions and 56 deletions

View File

@ -0,0 +1,86 @@
File: buggy-meas-tran.sp
* Simple .measurement examples
* transient simulation of two sine signals with different frequencies
vac1 1 0 DC 0 sin(0 1 1k 0 0)
R1 1 0 100k
vac2 2 0 DC 0 sin(0 1.2 0.9k 0 0)
.tran 10u 5m
*
.measure tra tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2
.measure tran tdiff RIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=3
.measure tran tdiff TRIG v(1 VAL=0.5 RISE=1 TARG v(1) VAL=0.5 FALL=1
.measure tran tdiff TRIG v(1) VAL FALL=3 TARG v(2) VAL=0 FALL=3
.measure tran tdiff TRIG v(1) VAL=-0.6 CROS=1 TARG v(2) VAL=-0.8 CROSS=1
.measure tran tdiff TRIG AT=1m TARG v(2) VAL -0.8 CROSS=3
.measure tran teval WHE v(2)=0.7 CROSS=LAST
.measure tran teval WHEN v(2)==v(1) FALL=LAST
.measure tran teval WHEN v(1)!=v(2) CROSS=LAST
.measure tran yeval FIND v(2) WHEN v(1)=0.2 FALL=2
.measure tran yeval FIND v(2) AT=2 m
.measure tran ymax MAX v(2) fro m=2m to=3m
.measure tran tymax MAX_AT v(2) from=2m to=3m
.measure tran ypp PP v(1) from=2m to=4m
.measure tran yrms RMS v() from=2m to=3.5m
.measure tran yavg AVG v(1) from 2m to=4m
.measure tran yint INTER v(2) from=2m to=3m
.param fval=5
.measure tran yadd param='fval + 7'
.param vout_diff=50k
.meas tran bw_chk param='(vout_diff < 100k) ? 1 : 0'
.measure tran vtest find par('v(2)*v(1)') AT=2.3m
*
.control
run
plot v(1) v(2)
plot i(vac1)
echo
echo good meas lines
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=3
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 FALL=1
meas tran tdiff TRIG v(1) VAL=0 FALL=3 TARG v(2) VAL=0 FALL=3
meas tran tdiff TRIG v(1) VAL=-0.6 CROSS=1 TARG v(2) VAL=-0.8 CROSS=1
meas tran tdiff TRIG AT=1m TARG v(2) VAL=-0.8 CROSS=3
meas tran teval WHEN v(2)=0.7 CROSS=LAST
meas tran teval WHEN v(2)=v(1) FALL=LAST
meas tran teval WHEN v(1)=v(2) CROSS=LAST
meas tran yeval FIND v(2) WHEN v(1)=0.2 FALL=2
meas tran yeval FIND v(2) AT=2m
meas tran ymax MAX v(2) from=2m to=3m
meas tran tymax MAX_AT v(2) from=2m to=3m
meas tran ypp PP v(1) from=2m to=4m
meas tran yrms RMS v(1) from=2m to=3.5m
meas tran yavg AVG v(1) from=2m to=4m
meas tran yint INTEG v(2) from=2m to=3m
meas tran ymax MAX v(2) from=2m to=3m
meas tran tmax WHEN v(2)=YMAX from=1m to=2m
echo
echo buggy input lines
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1)
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1
meas tran tdiff TRIG v(1) VAL=0.5
meas tran tdiff TRIG v(1)
meas tran tdiff TRIG
meas tran tdiff
meas tran
meas
echo
echo more buggy lines
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) VAL=0.5 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) RISE=2
meas tran tdiff TRIG v(1) VAL= RISE=1 TARG v(1) VAL=0.5 RISE=2
meas tran tdiff TRIG v(1) VAL=0.5 RISE= TARG v(1) VAL=0.5 RISE=2
.endc
.end

View File

@ -350,7 +350,7 @@ measure_extract_variables(char *line)
* Function: process a WHEN measurement statement which has been
* parsed into a measurement structure.
* ----------------------------------------------------------------- */
static void
static int
com_measure_when(
MEASUREPTR meas /* in : parsed measurement structure */
)
@ -385,16 +385,16 @@ com_measure_when(
if (d == NULL) {
fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec);
return;
return MEASUREMENT_FAILURE;
}
if (has_d2 && (d2 == NULL)) {
fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec2);
return;
return MEASUREMENT_FAILURE;
}
if (dScale == NULL) {
fprintf(cp_err, "Error: no scale vector.\n");
return;
return MEASUREMENT_FAILURE;
}
prevValue = 0.;
@ -537,13 +537,13 @@ com_measure_when(
* exit when we meet condition */
// meas->m_measured = prevScaleValue + (value2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue);
meas->m_measured = prevScaleValue + (prevValue2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue - value2 + prevValue2);
return;
return MEASUREMENT_OK;
}
if (measurement_pending) {
if ((meas->m_cross == MEASURE_DEFAULT) && (meas->m_rise == MEASURE_DEFAULT) && (meas->m_fall == MEASURE_DEFAULT)) {
/* user didn't request any option, return the first possible case */
meas->m_measured = prevScaleValue + (prevValue2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue - value2 + prevValue2);
return;
return MEASUREMENT_OK;
} else if ((meas->m_cross == MEASURE_LAST_TRANSITION) || (meas->m_rise == MEASURE_LAST_TRANSITION) || (meas->m_fall == MEASURE_LAST_TRANSITION)) {
meas->m_measured = prevScaleValue + (prevValue2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue - value2 + prevValue2);
/* no return - look for last */
@ -577,13 +577,13 @@ com_measure_when(
/* user requested an exact match of cross, rise, or fall
* exit when we meet condition */
meas->m_measured = prevScaleValue + (meas->m_val - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue);
return;
return MEASUREMENT_OK;
}
if (measurement_pending) {
if ((meas->m_cross == MEASURE_DEFAULT) && (meas->m_rise == MEASURE_DEFAULT) && (meas->m_fall == MEASURE_DEFAULT)) {
/* user didn't request any option, return the first possible case */
meas->m_measured = prevScaleValue + (meas->m_val - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue);
return;
return MEASUREMENT_OK;
} else if ((meas->m_cross == MEASURE_LAST_TRANSITION) || (meas->m_rise == MEASURE_LAST_TRANSITION) || (meas->m_fall == MEASURE_LAST_TRANSITION)) {
meas->m_measured = prevScaleValue + (meas->m_val - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue);
/* no return - look for last */
@ -603,6 +603,8 @@ com_measure_when(
if (init_measured_value)
meas->m_measured = NAN;
return MEASUREMENT_OK;
}
@ -611,7 +613,7 @@ com_measure_when(
* parsed into a measurement structure. We make sure to interpolate
* the value when appropriate.
* ----------------------------------------------------------------- */
static void
static int
measure_at(
MEASUREPTR meas, /* in : parsed "at" data */
double at /* in: time to perform measurement */
@ -623,17 +625,23 @@ measure_at(
struct dvec *d, *dScale;
psvalue = pvalue = 0;
if (meas->m_vec == NULL) {
fprintf(stderr, "Error: Syntax error in meas line, missing vector\n");
return MEASUREMENT_FAILURE;
}
d = vec_get(meas->m_vec);
dScale = plot_cur->pl_scale;
if (d == NULL) {
fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec);
return;
return MEASUREMENT_FAILURE;
}
if (dScale == NULL) {
fprintf(cp_err, "Error: no such vector time, frequency or dc.\n");
return;
return MEASUREMENT_FAILURE;
}
/* -----------------------------------------------------------------
@ -670,10 +678,10 @@ measure_at(
if ((i > 0) && (psvalue <= at) && (svalue >= at)) {
meas->m_measured = pvalue + (at - psvalue) * (value - pvalue) / (svalue - psvalue);
return;
return MEASUREMENT_OK;
} else if (dc_check && (i > 0) && (psvalue >= at) && (svalue <= at)) {
meas->m_measured = pvalue + (at - psvalue) * (value - pvalue) / (svalue - psvalue);
return;
return MEASUREMENT_OK;
}
psvalue = svalue;
@ -681,6 +689,7 @@ measure_at(
}
meas->m_measured = NAN;
return MEASUREMENT_OK;
}
@ -690,7 +699,7 @@ measure_at(
* the value here when we have m_from and m_to constraints * so this
* function is slightly wrong. Need to fix in future rev.
* ----------------------------------------------------------------- */
static void
static int
measure_minMaxAvg(
MEASUREPTR meas, /* in : parsed measurement data request */
ANALYSIS_TYPE_T mFunctionType /* in: one of AT_AVG, AT_MIN, AT_MAX, AT_MIN_AT, AT_MAX_AT */
@ -709,10 +718,15 @@ measure_minMaxAvg(
meas->m_measured_at = NAN;
first = 0;
if (meas->m_vec == NULL) {
fprintf(cp_err, "Syntax error in meas line\n");
return MEASUREMENT_FAILURE;
}
d = vec_get(meas->m_vec);
if (d == NULL) {
fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec);
return;
return MEASUREMENT_FAILURE;
}
@ -736,12 +750,12 @@ measure_minMaxAvg(
dScale = vec_get("v-sweep");
} else { /* error */
fprintf(cp_err, "Error: no such analysis type as %s.\n", meas->m_analysis);
return;
return MEASUREMENT_FAILURE;
}
if (dScale == NULL) {
fprintf(cp_err, "Error: no such vector as time, frquency or v-sweep.\n");
return;
return MEASUREMENT_FAILURE;
}
for (i = 0; i < d->v_length; i++) {
@ -801,6 +815,7 @@ measure_minMaxAvg(
break;
default:
fprintf(cp_err, "Error: improper min/max/avg call.\n");
return MEASUREMENT_FAILURE;
}
} else {
switch (mFunctionType) {
@ -829,6 +844,7 @@ measure_minMaxAvg(
}
default :
fprintf(cp_err, "Error: improper min/max/avg call.\n");
return MEASUREMENT_FAILURE;
}
}
@ -851,7 +867,9 @@ measure_minMaxAvg(
}
default :
fprintf(cp_err, "Error: improper min/max/avg call.\n");
return MEASUREMENT_FAILURE;
}
return MEASUREMENT_OK;
}
@ -860,7 +878,7 @@ measure_minMaxAvg(
* parsed into a measurement structure. Here we do interpolate
* the starting and stopping time window so the answer is correct.
* ----------------------------------------------------------------- */
static void
static int
measure_rms_integral(
MEASUREPTR meas, /* in : parsed measurement data request */
ANALYSIS_TYPE_T mFunctionType /* in: one of AT_RMS, or AT_INTEG */
@ -897,7 +915,7 @@ measure_rms_integral(
d = vec_get(meas->m_vec);
if (d == NULL) {
fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec);
return;
return MEASUREMENT_FAILURE;
}
if (ac_check || sp_check) {
@ -908,12 +926,12 @@ measure_rms_integral(
xScale = vec_get("v-sweep");
} else { /* error */
fprintf(cp_err, "Error: no such analysis type as %s.\n", meas->m_analysis);
return;
return MEASUREMENT_FAILURE;
}
if (xScale == NULL) {
fprintf(cp_err, "Error: no such vector as time.\n");
return;
return MEASUREMENT_FAILURE;
}
/* Allocate buffers for calculation. */
@ -1033,6 +1051,7 @@ measure_rms_integral(
txfree(x);
txfree(y);
txfree(width);
return MEASUREMENT_OK;
}
@ -1170,7 +1189,7 @@ measure_parse_stdParams(
continue;
} else {
sprintf(errbuf, "bad syntax. equal sign missing ?\n");
return 0;
return MEASUREMENT_FAILURE;
}
}
@ -1180,7 +1199,7 @@ measure_parse_stdParams(
else {
if (ft_numparse(&pValue, FALSE, &engVal1) < 0) {
sprintf(errbuf, "bad syntax, cannot evaluate right hand side of %s=%s\n", pName, pValue);
return 0;
return MEASUREMENT_FAILURE;
}
}
@ -1208,7 +1227,7 @@ measure_parse_stdParams(
meas->m_at = engVal1;
} else {
sprintf(errbuf, "no such parameter as '%s'\n", pName);
return 0;
return MEASUREMENT_FAILURE;
}
pCnt ++;
@ -1220,20 +1239,20 @@ measure_parse_stdParams(
sprintf(errbuf, "bad syntax of %s\n", pName);
else
sprintf(errbuf, "bad syntax of\n");
return 0;
return MEASUREMENT_FAILURE;
}
// valid vector
if (measure_valid_vector(meas->m_vec) == 0) {
sprintf(errbuf, "no such vector as '%s'\n", meas->m_vec);
return 0;
return MEASUREMENT_FAILURE;
}
// valid vector2
if (meas->m_vec2 != NULL)
if (measure_valid_vector(meas->m_vec2) == 0) {
sprintf(errbuf, "no such vector as '%s'\n", meas->m_vec2);
return 0;
return MEASUREMENT_FAILURE;
}
/* dc: make m_from always less than m_to */
@ -1242,7 +1261,7 @@ measure_parse_stdParams(
SWAP(double, meas->m_from, meas->m_to);
}
return 1;
return MEASUREMENT_OK;
}
@ -1294,29 +1313,30 @@ measure_parse_find(
if (pVal == NULL) {
sprintf(errbuf, "bad syntax of WHEN\n");
return 0;
return MEASUREMENT_FAILURE;
}
if (strcasecmp(pName, "AT") == 0) {
if (ft_numparse((char **) &pVal, FALSE, &meas->m_at) < 0) {
sprintf(errbuf, "bad syntax of WHEN\n");
return 0;
return MEASUREMENT_FAILURE;
}
}
else {
sprintf(errbuf, "bad syntax of WHEN\n");
return 0;
return MEASUREMENT_FAILURE;
}
} else {
if (measure_parse_stdParams(meas, wl, NULL, errbuf) == 0)
return 0;
if (measure_parse_stdParams(meas, wl, NULL, errbuf) ==
MEASUREMENT_FAILURE)
return MEASUREMENT_FAILURE;
}
wl = wl->wl_next;
pCnt ++;
}
return 1;
return MEASUREMENT_OK;
}
@ -1363,7 +1383,7 @@ measure_parse_when(
if (pVar2 == NULL) {
sprintf(errBuf, "bad syntax\n");
return 0;
return MEASUREMENT_FAILURE;
}
meas->m_vec = copy(pVar1);
@ -1379,15 +1399,15 @@ measure_parse_when(
meas->m_val = INPevaluate(&pVar2, &err, 1);
}
} else {
if (measure_parse_stdParams(meas, wl, NULL, errBuf) == 0)
return 0;
if (measure_parse_stdParams(meas, wl, NULL, errBuf) == MEASUREMENT_FAILURE)
return MEASUREMENT_FAILURE;
break;
}
wl = wl->wl_next;
pCnt ++;
}
return 1;
return MEASUREMENT_OK;
}
@ -1436,11 +1456,13 @@ measure_parse_trigtarg(
if (cieq("ac", meas->m_analysis) || cieq("sp", meas->m_analysis))
correct_vec(meas);
} else if (ciprefix("at", p)) {
if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0)
return 0;
if (measure_parse_stdParams(meas, words, wlTarg, errbuf) ==
MEASUREMENT_FAILURE)
return MEASUREMENT_FAILURE;
} else {
if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0)
return 0;
if (measure_parse_stdParams(meas, words, wlTarg, errbuf) ==
MEASUREMENT_FAILURE)
return MEASUREMENT_FAILURE;
break;
}
@ -1450,16 +1472,16 @@ measure_parse_trigtarg(
if (pcnt == 0) {
sprintf(errbuf, "bad syntax of '%s'\n", trigTarg);
return 0;
return MEASUREMENT_FAILURE;
}
// valid vector
if (measure_valid_vector(meas->m_vec) == 0) {
sprintf(errbuf, "no such vector as '%s'\n", meas->m_vec);
return 0;
return MEASUREMENT_FAILURE;
}
return 1;
return MEASUREMENT_OK;
}
@ -1594,7 +1616,8 @@ get_measure2(
measTrig->m_analysis = measTarg->m_analysis = mAnalysis;
if (measure_parse_trigtarg(measTrig, words , wlTarg, "trig", errbuf) == 0) {
if (measure_parse_trigtarg(measTrig, words, wlTarg, "trig", errbuf) ==
MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
goto err_ret1;
}
@ -1612,7 +1635,8 @@ get_measure2(
if (words)
words = words->wl_next; // skip targ
if (measure_parse_trigtarg(measTarg, words , NULL, "targ", errbuf) == 0) {
if (measure_parse_trigtarg(measTarg, words, NULL, "targ", errbuf) ==
MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "TARG", errbuf, autocheck);
goto err_ret1;
}
@ -1673,7 +1697,7 @@ err_ret1:
meas->m_analysis = measFind->m_analysis = mAnalysis;
if (measure_parse_find(meas, words, wlWhen, errbuf) == 0) {
if (measure_parse_find(meas, words, wlWhen, errbuf) == MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "FIND", errbuf, autocheck);
goto err_ret2;
}
@ -1686,7 +1710,7 @@ err_ret1:
if (words)
words = words->wl_next; // skip targ
if (measure_parse_when(measFind, words, errbuf) == 0) {
if (measure_parse_when(measFind, words, errbuf) == MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck);
goto err_ret2;
}
@ -1699,11 +1723,16 @@ err_ret1:
goto err_ret2;
}
measure_at(meas, measFind->m_measured);
if(measure_at(meas, measFind->m_measured) == MEASUREMENT_FAILURE){
goto err_ret2;
}
meas->m_at = measFind->m_measured;
} else {
measure_at(meas, meas->m_at);
if (measure_at(meas, meas->m_at) == MEASUREMENT_FAILURE) {
goto err_ret2;
}
}
if (isnan(meas->m_measured)) {
@ -1737,7 +1766,7 @@ err_ret2:
MEASUREPTR meas;
meas = TMALLOC(struct measure, 1);
meas->m_analysis = mAnalysis;
if (measure_parse_when(meas, words, errbuf) == 0) {
if (measure_parse_when(meas, words, errbuf) == MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck);
goto err_ret3;
}
@ -1776,7 +1805,8 @@ err_ret3:
MEASUREPTR meas;
meas = TMALLOC(struct measure, 1);
meas->m_analysis = mAnalysis;
if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf) == 0) {
if (measure_parse_trigtarg(meas, words, NULL, "trig", errbuf) ==
MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
goto err_ret4;
}
@ -1820,7 +1850,8 @@ err_ret4:
meas->m_analysis = mAnalysis;
if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf) == 0) {
if (measure_parse_trigtarg(meas, words, NULL, "trig", errbuf) ==
MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
goto err_ret5;
}
@ -1863,7 +1894,8 @@ err_ret5:
MEASUREPTR measTrig;
measTrig = TMALLOC(struct measure, 1);
measTrig->m_analysis = mAnalysis;
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf) == 0) {
if (measure_parse_trigtarg(measTrig, words, NULL, "trig", errbuf) ==
MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
goto err_ret6;
}
@ -1914,7 +1946,8 @@ err_ret6:
MEASUREPTR measTrig;
measTrig = TMALLOC(struct measure, 1);
measTrig->m_analysis = mAnalysis;
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf) == 0) {
if (measure_parse_trigtarg(measTrig, words, NULL, "trig", errbuf) ==
MEASUREMENT_FAILURE) {
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
goto err_ret7;
}