static long processAo(aoRecord *pr) { devInt32Pvt *pPvt = (devInt32Pvt *)pr->dpvt; asynStatus status; double value; if (getCallbackValue(pPvt)) { /* We got a callback from the driver */ if (pPvt->result.status == asynSuccess) { pr->rval = pPvt->result.value; pr->udf = 0; value = (double)pr->rval + (double)pr->roff; if(pr->aslo!=0.0) value *= pr->aslo; value += pr->aoff; if (pr->linr == menuConvertNO_CONVERSION){ ; /*do nothing*/ } else if ((pr->linr == menuConvertLINEAR) || (pr->linr == menuConvertSLOPE)) { value = value*pr->eslo + pr->eoff; } else { if(cvtRawToEngBpt(&value,pr->linr,pr->init, (void *)&pr->pbrk,&pr->lbrk)!=0) { asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, "%s devAsynInt32 cvtRawToEngBpt failed\n", pr->name); (void)recGblSetSevr(pr, WRITE_ALARM, INVALID_ALARM); return -1; } } pr->val = value; pr->udf = isnan(value); } } else if(pr->pact == 0) { pPvt->result.value = pr->rval; if(pPvt->canBlock) pr->pact = 1; status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0); if((status==asynSuccess) && pPvt->canBlock) return 0; if(pPvt->canBlock) pr->pact = 0; reportQueueRequestStatus(pPvt, status); } if(pPvt->result.status == asynSuccess) { return 0; } else { pasynEpicsUtils->asynStatusToEpicsAlarm(pPvt->result.status, WRITE_ALARM, &pPvt->alarmStat, INVALID_ALARM, &pPvt->alarmSevr); (void)recGblSetSevr(pr, pPvt->alarmStat, pPvt->alarmSevr); pPvt->result.status = asynSuccess; return -1; } }
static long processAo(aoRecord *pr) { devInt32Pvt *pPvt = (devInt32Pvt *)pr->dpvt; asynStatus status; double value; getCallbackValue(pPvt); if(pPvt->gotValue) { /* This code is for I/O Intr scanned output records, which are not tested yet. */ pr->rval = pPvt->value; pr->udf = 0; value = (double)pr->rval + (double)pr->roff; if(pr->aslo!=0.0) value *= pr->aslo; value += pr->aoff; if (pr->linr == menuConvertNO_CONVERSION){ ; /*do nothing*/ } else if ((pr->linr == menuConvertLINEAR) || (pr->linr == menuConvertSLOPE)) { value = value*pr->eslo + pr->eoff; }else{ if(cvtRawToEngBpt(&value,pr->linr,pr->init, (void *)&pr->pbrk,&pr->lbrk)!=0) { asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, "%s devAsynInt32 cvtRawToEngBpt failed\n", pr->name); recGblSetSevr(pr, READ_ALARM, INVALID_ALARM); goto done; } } pr->val = value; pr->udf = isnan(value); } else if(pr->pact == 0) { pPvt->value = pr->rval; if(pPvt->canBlock) pr->pact = 1; status = pasynManager->queueRequest(pPvt->pasynUser, 0, 0); if((status==asynSuccess) && pPvt->canBlock) return 0; if(pPvt->canBlock) pr->pact = 0; if(status != asynSuccess) { asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, "%s devAsynInt32 queueRequest %s\n", pr->name,pPvt->pasynUser->errorMessage); recGblSetSevr(pr, WRITE_ALARM, INVALID_ALARM); } } done: pPvt->gotValue = 0; return 0; }
static void convert(aiRecord *prec) { double val; val = (double)prec->rval + (double)prec->roff; /* adjust slope and offset */ if(prec->aslo!=0.0) val*=prec->aslo; val+=prec->aoff; /* convert raw to engineering units and signal units */ switch (prec->linr) { case menuConvertNO_CONVERSION: break; /* do nothing*/ case menuConvertLINEAR: case menuConvertSLOPE: val = (val * prec->eslo) + prec->eoff; break; default: /* must use breakpoint table */ if (cvtRawToEngBpt(&val,prec->linr,prec->init,(void *)&prec->pbrk,&prec->lbrk)!=0) { recGblSetSevr(prec,SOFT_ALARM,MAJOR_ALARM); } } /* apply smoothing algorithm */ if (prec->smoo != 0.0){ if (prec->init) prec->val = val; /* initial condition */ prec->val = val * (1.00 - prec->smoo) + (prec->val * prec->smoo); }else{ prec->val = val; } prec->udf = isnan(prec->val); return; }
/* Callback from driver for every received tag, for ao record: * Check if * * 1) pact set -> this is the "finshed the write" callback * 2) pact not set -> this is the "new value" callback * Tag value is either different from current record value * or there is no current record value: * 2a) disconnected; process record to set WRITE/INVALID * 2b) PLC's value != record's idea of the current value * 2c) record is UDF, so this is the first time we get a value * from the PLC after a reboot * Causing process if necessary to update the record. * That process()/scanOnce() call should NOT cause the record to write * to the PLC because the xxx_write method will notice that * the PLC and record value agree. * It will, however, trigger CA monitors. * * Problem: Alarms are handled before "write_xx" is called. * So we have to set udf in here, * then process() can recognize udf and finally it will * call write_xx. */ static void check_ao_callback(void *arg) { aoRecord *rec = (aoRecord *) arg; struct rset *rset= (struct rset *)(rec->rset); DevicePrivate *pvt = (DevicePrivate *)rec->dpvt; double dbl; CN_DINT dint; eip_bool process = false; /* We are about the check and even set val, & rval -> lock */ dbScanLock((dbCommon *)rec); if (rec->pact) { if (rec->tpro) printf("EIP check_ao_callback('%s'), pact=%d\n", rec->name, rec->pact); (*rset->process) ((dbCommon *)rec); dbScanUnlock((dbCommon *)rec); return; } /* Check if record's (R)VAL is current */ if (!check_data((dbCommon *)rec)) { if (rec->tpro) printf("EIP check_ao_callback('%s'), no data\n", rec->name); (*rset->process) ((dbCommon *)rec); dbScanUnlock((dbCommon *)rec); return; } if (get_CIP_typecode(pvt->tag->data) == T_CIP_REAL) { if (rec->tpro) printf("EIP check_ao_callback('%s') w/ real data\n", rec->name); if (get_CIP_double(pvt->tag->data, pvt->element, &dbl) && (rec->udf || rec->sevr == INVALID_ALARM || rec->val != dbl)) { if (rec->tpro) printf("'%s': got %g from driver\n", rec->name, dbl); if (!rec->udf && pvt->special & SPCO_FORCE) { if (rec->tpro) printf("'%s': will re-write record's value %g\n", rec->name, rec->val); } else { rec->val = rec->pval = dbl; rec->udf = false; if (rec->tpro) printf("'%s': updated record's value %g\n", rec->name, rec->val); } process = true; } } else { if (rec->tpro) printf("EIP check_ao_callback('%s') w/ int. data\n", rec->name); if (get_CIP_DINT(pvt->tag->data, pvt->element, &dint) && (rec->udf || rec->sevr == INVALID_ALARM || rec->rval != dint)) { if (rec->tpro) printf("AO '%s': got %ld from driver\n", rec->name, (long)dint); if (!rec->udf && pvt->special & SPCO_FORCE) { if (rec->tpro) printf("AO '%s': will re-write record's rval 0x%X\n", rec->name, (unsigned int)rec->rval); } else { /* back-convert raw value into val (copied from ao init) */ dbl = (double)dint + (double)rec->roff; if (rec->aslo!=0.0) dbl *= rec->aslo; dbl += rec->aoff; switch (rec->linr) { case menuConvertNO_CONVERSION: rec->val = rec->pval = dbl; rec->udf = false; break; case menuConvertLINEAR: case menuConvertSLOPE: dbl = dbl*rec->eslo + rec->eoff; rec->val = rec->pval = dbl; rec->udf = false; break; default: if (cvtRawToEngBpt(&dbl,rec->linr,rec->init, (void *)&rec->pbrk, &rec->lbrk)!=0) break; /* cannot back-convert */ rec->val = rec->pval = dbl; rec->udf = false; } if (rec->tpro) printf("'%s': updated record's value to %g\n", rec->name, rec->val); } process = true; } } dbScanUnlock((dbCommon *)rec); /* Does record need processing and is not periodic? */ if (process && rec->scan < SCAN_1ST_PERIODIC) scanOnce(rec); }
static long init_record(aoRecord *prec, int pass) { struct aodset *pdset; double eoff = prec->eoff, eslo = prec->eslo; double value; if (pass==0) return(0); /* ao.siml must be a CONSTANT or a PV_LINK or a DB_LINK */ if (prec->siml.type == CONSTANT) { recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm); } if(!(pdset = (struct aodset *)(prec->dset))) { recGblRecordError(S_dev_noDSET,(void *)prec,"ao: init_record"); return(S_dev_noDSET); } /* get the initial value if dol is a constant*/ if (prec->dol.type == CONSTANT) { if(recGblInitConstantLink(&prec->dol,DBF_DOUBLE,&prec->val)) prec->udf = isnan(prec->val); } /* must have write_ao function defined */ if ((pdset->number < 6) || (pdset->write_ao ==NULL)) { recGblRecordError(S_dev_missingSup,(void *)prec,"ao: init_record"); return(S_dev_missingSup); } prec->init = TRUE; /*The following is for old device support that doesnt know about eoff*/ if ((prec->eslo==1.0) && (prec->eoff==0.0)) { prec->eoff = prec->egul; } if (pdset->init_record) { long status=(*pdset->init_record)(prec); if (prec->linr == menuConvertSLOPE) { prec->eoff = eoff; prec->eslo = eslo; } switch(status){ case(0): /* convert */ value = (double)prec->rval + (double)prec->roff; if(prec->aslo!=0.0) value *= prec->aslo; value += prec->aoff; if (prec->linr == menuConvertNO_CONVERSION){ ; /*do nothing*/ } else if ((prec->linr == menuConvertLINEAR) || (prec->linr == menuConvertSLOPE)) { value = value*prec->eslo + prec->eoff; }else{ if(cvtRawToEngBpt(&value,prec->linr,prec->init, (void *)&prec->pbrk,&prec->lbrk)!=0) break; } prec->val = value; prec->udf = isnan(value); break; case(2): /* no convert */ break; default: recGblRecordError(S_dev_badInitRet,(void *)prec,"ao: init_record"); return(S_dev_badInitRet); } } prec->oval = prec->pval = prec->val; prec->mlst = prec->val; prec->alst = prec->val; prec->lalm = prec->val; prec->oraw = prec->rval; prec->orbv = prec->rbv; return(0); }