static void testAValExpr(const char* expr, double* args, double** aargs, double* expected, int length) { unsigned char rpn[255]; short err; double val; double aval[12]; epicsUInt32 amask; if (aCalcPostfix(expr, rpn, &err)) { testDiag("postfix: %s in expression '%s'", aCalcErrorStr(err), expr); return; } if (aCalcPerform(args, 12, aargs, 12, 12, &val, aval, rpn, 12, &amask)) { testDiag("calcPerform: error evaluating '%s'", expr); return; } bool pass = true; int i = 0; for (i = 0; i < length; i += 1) { if (finite(expected[i]) && finite(aval[i])) { if (fabs(expected[i] - aval[i]) > 1e-8) { pass = false; break; } } else if (isnan(expected[i]) && !isnan(aval[i])) { pass = false; break; } else if (aval[i] != expected[i]) { pass = false; break; } } if(!testOk(pass, "%s", expr)) { testDiag("Expected aval[%d]: %f, Got: %f", i, expected[i], aval[i]); } }
static void testValExpr(const char* expr, double* args, double** aargs, double expected) { unsigned char rpn[255]; short err; double val; double aval[1]; epicsUInt32 amask; if (aCalcPostfix(expr, rpn, &err)) { testDiag("postfix: %s in expression '%s'", aCalcErrorStr(err), expr); return; } if (aCalcPerform(args, 12, aargs, 12, 3, &val, aval, rpn, 1, &amask)) { testDiag("calcPerform: error evaluating '%s'", expr); return; } bool pass; if (finite(expected) && finite(val)) { pass = fabs(expected - val) < 1e-8; } else if (isnan(expected)) { pass = (bool) isnan(val); } else { pass = (val == expected); } if(!testOk(pass, "%s", expr)) { testDiag("Expected: %f, Got: %f", expected, val); } }
static long special(dbAddr *paddr, int after) { acalcoutRecord *pcalc = (acalcoutRecord *)(paddr->precord); rpvtStruct *prpvt = (struct rpvtStruct *)pcalc->rpvt; dbAddr Addr; dbAddr *pAddr = &Addr; short error_number; int fieldIndex = dbGetFieldIndex(paddr); int lnkIndex; DBLINK *plink; double *pvalue; unsigned short *plinkValid; if (!after) return(0); switch (fieldIndex) { case acalcoutRecordCALC: pcalc->clcv = aCalcPostfix(pcalc->calc, pcalc->rpcl, &error_number); if (pcalc->clcv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: special(): Illegal CALC field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->clcv,DBE_VALUE); return(0); break; case acalcoutRecordOCAL: pcalc->oclv = aCalcPostfix(pcalc->ocal, pcalc->orpc, &error_number); if (pcalc->oclv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: special(): Illegal OCAL field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->oclv,DBE_VALUE); return(0); break; case acalcoutRecordNUSE: if ((pcalc->nuse < 0) || (pcalc->nuse > pcalc->nelm)) { pcalc->nuse = pcalc->nelm; db_post_events(pcalc,&pcalc->nuse,DBE_VALUE); return(-1); } return(0); break; case(acalcoutRecordINPA): case(acalcoutRecordINPB): case(acalcoutRecordINPC): case(acalcoutRecordINPD): case(acalcoutRecordINPE): case(acalcoutRecordINPF): case(acalcoutRecordINPG): case(acalcoutRecordINPH): case(acalcoutRecordINPI): case(acalcoutRecordINPJ): case(acalcoutRecordINPK): case(acalcoutRecordINPL): case(acalcoutRecordINAA): case(acalcoutRecordINBB): case(acalcoutRecordINCC): case(acalcoutRecordINDD): case(acalcoutRecordINEE): case(acalcoutRecordINFF): case(acalcoutRecordINGG): case(acalcoutRecordINHH): case(acalcoutRecordINII): case(acalcoutRecordINJJ): case(acalcoutRecordINKK): case(acalcoutRecordINLL): case(acalcoutRecordOUT): lnkIndex = fieldIndex - acalcoutRecordINPA; plink = &pcalc->inpa + lnkIndex; pvalue = &pcalc->a + lnkIndex; plinkValid = &pcalc->inav + lnkIndex; if (plink->type == CONSTANT) { if (fieldIndex <= acalcoutRecordINPL) { recGblInitConstantLink(plink,DBF_DOUBLE,pvalue); db_post_events(pcalc,pvalue,DBE_VALUE); } *plinkValid = acalcoutINAV_CON; if (fieldIndex == acalcoutRecordOUT) prpvt->outlink_field_type = DBF_NOACCESS; } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) { /* PV resides on this ioc */ *plinkValid = acalcoutINAV_LOC; if (fieldIndex == acalcoutRecordOUT) { prpvt->outlink_field_type = pAddr->field_type; if ((pAddr->field_type >= DBF_INLINK) && (pAddr->field_type <= DBF_FWDLINK)) { if (!(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):special:non-CA link to link field\n", plink->value.pv_link.pvname); } } if (pcalc->wait && !(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):special: Can't wait with non-CA link attribute\n", plink->value.pv_link.pvname); } } } else { /* pv is not on this ioc. Callback later for connection stat */ *plinkValid = acalcoutINAV_EXT_NC; /* DO_CALLBACK, if not already scheduled */ if (!prpvt->wd_id_1_LOCK) { callbackRequestDelayed(&prpvt->checkLinkCb,.5); prpvt->wd_id_1_LOCK = 1; prpvt->caLinkStat = CA_LINKS_NOT_OK; } if (fieldIndex == acalcoutRecordOUT) prpvt->outlink_field_type = DBF_NOACCESS; /* don't know */ } db_post_events(pcalc,plinkValid,DBE_VALUE); return(0); break; default: recGblDbaddrError(S_db_badChoice,paddr,"calc: special"); return(S_db_badChoice); } return(0); }
static long init_record(acalcoutRecord *pcalc, int pass) { DBLINK *plink; int i; double *pvalue; unsigned short *plinkValid; short error_number; acalcoutDSET *pacalcoutDSET; dbAddr Addr; dbAddr *pAddr = &Addr; rpvtStruct *prpvt; if (pass==0) { pcalc->vers = VERSION; pcalc->rpvt = (void *)calloc(1, sizeof(struct rpvtStruct)); if ((pcalc->nuse < 0) || (pcalc->nuse > pcalc->nelm)) { pcalc->nuse = pcalc->nelm; db_post_events(pcalc,&pcalc->nuse,DBE_VALUE|DBE_LOG); } return(0); } if (!(pacalcoutDSET = (acalcoutDSET *)pcalc->dset)) { recGblRecordError(S_dev_noDSET,(void *)pcalc,"acalcout:init_record"); return(S_dev_noDSET); } /* must have write defined */ if ((pacalcoutDSET->number < 5) || (pacalcoutDSET->write == NULL)) { recGblRecordError(S_dev_missingSup,(void *)pcalc,"acalcout:init_record"); return(S_dev_missingSup); } prpvt = (rpvtStruct *)pcalc->rpvt; plink = &pcalc->inpa; pvalue = &pcalc->a; plinkValid = &pcalc->inav; for (i=0; i<(MAX_FIELDS+ARRAY_MAX_FIELDS+1); i++, plink++, pvalue++, plinkValid++) { if (plink->type == CONSTANT) { /* Don't InitConstantLink the array links or the output link. */ if (i < MAX_FIELDS) { recGblInitConstantLink(plink,DBF_DOUBLE,pvalue); db_post_events(pcalc,pvalue,DBE_VALUE); } *plinkValid = acalcoutINAV_CON; if (plink == &pcalc->out) prpvt->outlink_field_type = DBF_NOACCESS; } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) { /* the PV we're linked to resides on this ioc */ *plinkValid = acalcoutINAV_LOC; if (plink == &pcalc->out) { prpvt->outlink_field_type = pAddr->field_type; if ((pAddr->field_type >= DBF_INLINK) && (pAddr->field_type <= DBF_FWDLINK)) { if (!(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):init_record:non-CA link to link field\n", plink->value.pv_link.pvname); } } if (pcalc->wait && !(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):init_record: Can't wait with non-CA link attribute\n", plink->value.pv_link.pvname); } } } else { /* pv is not on this ioc. Callback later for connection stat */ *plinkValid = acalcoutINAV_EXT_NC; prpvt->caLinkStat = CA_LINKS_NOT_OK; if (plink == &pcalc->out) prpvt->outlink_field_type = DBF_NOACCESS; /* don't know field type */ } db_post_events(pcalc,plinkValid,DBE_VALUE); } pcalc->clcv = aCalcPostfix(pcalc->calc,pcalc->rpcl,&error_number); if (pcalc->clcv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: init_record: Illegal CALC field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->clcv,DBE_VALUE); pcalc->oclv = aCalcPostfix(pcalc->ocal, pcalc->orpc,&error_number); if (pcalc->oclv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: init_record: Illegal OCAL field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->oclv,DBE_VALUE); callbackSetCallback(checkLinksCallback, &prpvt->checkLinkCb); callbackSetPriority(0, &prpvt->checkLinkCb); callbackSetUser(pcalc, &prpvt->checkLinkCb); prpvt->wd_id_1_LOCK = 0; if (prpvt->caLinkStat == CA_LINKS_NOT_OK) { callbackRequestDelayed(&prpvt->checkLinkCb,1.0); prpvt->wd_id_1_LOCK = 1; } if (pacalcoutDSET->init_record ) { return (*pacalcoutDSET->init_record)(pcalc); } return(0); }