/*************************************************************************\ * Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* recGbl.c */ /* Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd */ /* * Author: Marty Kraimer * Date: 11-7-90 */ #include #include #include #include #include #include "dbDefs.h" #include "epicsTime.h" #include "epicsPrint.h" #include "dbBase.h" #include "dbFldTypes.h" #include "link.h" #include "dbAddr.h" #include "db_field_log.h" #include "errlog.h" #include "devSup.h" #include "dbCommon.h" #include "caeventmask.h" #define epicsExportSharedSymbols #include "dbAccessDefs.h" #include "dbNotify.h" #include "dbCa.h" #include "dbEvent.h" #include "dbScan.h" #include "recGbl.h" /* Hook Routines */ RECGBL_ALARM_HOOK_ROUTINE recGblAlarmHook = NULL; /* local routines */ static void getMaxRangeValues(short field_type, double *pupper_limit, double *plower_limit); void epicsShareAPI recGblDbaddrError(long status, const struct dbAddr *paddr, const char *pmessage) { dbCommon *precord = 0; dbFldDes *pdbFldDes = 0; if(paddr) { pdbFldDes = paddr->pfldDes; precord = paddr->precord; } errPrintf(status,0,0, "PV: %s.%s " "error detected in routine: %s\n", (paddr ? precord->name : "Unknown"), (pdbFldDes ? pdbFldDes->name : ""), (pmessage ? pmessage : "Unknown")); return; } void epicsShareAPI recGblRecordError(long status, void *pdbc, const char *pmessage) { dbCommon *precord = pdbc; errPrintf(status,0,0, "PV: %s %s\n", (precord ? precord->name : "Unknown"), (pmessage ? pmessage : "")); return; } void epicsShareAPI recGblRecSupError(long status, const struct dbAddr *paddr, const char *pmessage, const char *psupport_name) { dbCommon *precord = 0; dbFldDes *pdbFldDes = 0; dbRecordType *pdbRecordType = 0; if(paddr) { precord = paddr->precord; pdbFldDes = paddr->pfldDes; if(pdbFldDes) pdbRecordType = pdbFldDes->pdbRecordType; } errPrintf(status,0,0, "Record Support Routine (%s) " "Record Type %s " "PV %s.%s " " %s\n", (psupport_name ? psupport_name : "Unknown"), (pdbRecordType ? pdbRecordType->name : "Unknown"), (paddr ? precord->name : "Unknown"), (pdbFldDes ? pdbFldDes->name : ""), (pmessage ? pmessage : "")); return; } void epicsShareAPI recGblGetPrec(const struct dbAddr *paddr,long *precision) { dbFldDes *pdbFldDes = paddr->pfldDes; switch(pdbFldDes->field_type){ case(DBF_SHORT): *precision = 0; break; case(DBF_USHORT): *precision = 0; break; case(DBF_LONG): *precision = 0; break; case(DBF_ULONG): *precision = 0; break; case(DBF_FLOAT): case(DBF_DOUBLE): if(*precision<0 || *precision>15) *precision=15; break; default: break; } return; } void epicsShareAPI recGblGetGraphicDouble( const struct dbAddr *paddr,struct dbr_grDouble *pgd) { dbFldDes *pdbFldDes = paddr->pfldDes; getMaxRangeValues(pdbFldDes->field_type,&pgd->upper_disp_limit, &pgd->lower_disp_limit); return; } void epicsShareAPI recGblGetAlarmDouble( const struct dbAddr *paddr,struct dbr_alDouble *pad) { pad->upper_alarm_limit = 0; pad->upper_warning_limit = 0; pad->lower_warning_limit = 0; pad->lower_alarm_limit = 0; return; } void epicsShareAPI recGblGetControlDouble( const struct dbAddr *paddr,struct dbr_ctrlDouble *pcd) { dbFldDes *pdbFldDes=paddr->pfldDes; getMaxRangeValues(pdbFldDes->field_type,&pcd->upper_ctrl_limit, &pcd->lower_ctrl_limit); return; } int epicsShareAPI recGblInitConstantLink( struct link *plink,short dbftype,void *pdest) { if(plink->type != CONSTANT) return(FALSE); if(!plink->value.constantStr) return(FALSE); switch(dbftype) { case DBF_STRING: strcpy((char *)pdest,plink->value.constantStr); break; case DBF_CHAR : { epicsInt16 value; epicsInt8 *pvalue = (epicsInt8 *)pdest; sscanf(plink->value.constantStr,"%hi",&value); *pvalue = value; } break; case DBF_UCHAR : { epicsUInt16 value; epicsUInt8 *pvalue = (epicsUInt8 *)pdest; sscanf(plink->value.constantStr,"%hu",&value); *pvalue = value; } break; case DBF_SHORT : sscanf(plink->value.constantStr,"%hi",(epicsInt16 *)pdest); break; case DBF_USHORT : case DBF_ENUM : case DBF_MENU : case DBF_DEVICE : sscanf(plink->value.constantStr,"%hu",(epicsUInt16 *)pdest); break; case DBF_LONG : *(epicsInt32 *)pdest = strtol(plink->value.constantStr, NULL, 0); break; case DBF_ULONG : *(epicsUInt32 *)pdest = strtoul(plink->value.constantStr, NULL, 10); break; case DBF_FLOAT : epicsScanFloat(plink->value.constantStr, (epicsFloat32 *)pdest); break; case DBF_DOUBLE : epicsScanDouble(plink->value.constantStr, (epicsFloat64 *)pdest); break; default: epicsPrintf("Error in recGblInitConstantLink: Illegal DBF type\n"); return(FALSE); } return(TRUE); } unsigned short epicsShareAPI recGblResetAlarms(void *precord) { dbCommon *pdbc = precord; epicsEnum16 prev_stat = pdbc->stat; epicsEnum16 prev_sevr = pdbc->sevr; epicsEnum16 new_stat = pdbc->nsta; epicsEnum16 new_sevr = pdbc->nsev; epicsEnum16 val_mask = 0; epicsEnum16 stat_mask = 0; pdbc->stat = new_stat; pdbc->sevr = new_sevr; pdbc->nsta = 0; pdbc->nsev = 0; if (prev_sevr != new_sevr) { stat_mask = DBE_ALARM; db_post_events(pdbc, &pdbc->sevr, DBE_VALUE); } if (prev_stat != new_stat) { stat_mask |= DBE_VALUE; } if (stat_mask) { db_post_events(pdbc, &pdbc->stat, stat_mask); val_mask = DBE_ALARM; if (!pdbc->ackt || new_sevr >= pdbc->acks) { pdbc->acks = new_sevr; db_post_events(pdbc, &pdbc->acks, DBE_VALUE); } if (recGblAlarmHook) { (*recGblAlarmHook)(pdbc, prev_sevr, prev_stat); } } return val_mask; } void epicsShareAPI recGblFwdLink(void *precord) { dbCommon *pdbc = precord; dbScanFwdLink(&pdbc->flnk); /*Handle dbPutFieldNotify record completions*/ if(pdbc->ppn) dbNotifyCompletion(pdbc); if(pdbc->rpro) { /*If anyone requested reprocessing do it*/ pdbc->rpro = FALSE; scanOnce(pdbc); } /*In case putField caused put we are all done */ pdbc->putf = FALSE; } void epicsShareAPI recGblGetTimeStamp(void *pvoid) { dbCommon* prec = (dbCommon*)pvoid; struct link *plink = &prec->tsel; if (plink->type != CONSTANT) { struct pv_link *ppv_link = &plink->value.pv_link; if (ppv_link->pvlMask & pvlOptTSELisTime) { if (dbGetTimeStamp(plink, &prec->time)) errlogPrintf("recGblGetTimeStamp: dbGetTimeStamp failed, %s.TSEL = %s\n", prec->name, ppv_link->pvname); return; } dbGetLink(&prec->tsel, DBR_SHORT, &prec->tse, 0, 0); } if (prec->tse != epicsTimeEventDeviceTime) { if (epicsTimeGetEvent(&prec->time, prec->tse)) errlogPrintf("recGblGetTimeStamp: epicsTimeGetEvent failed, %s.TSE = %d\n", prec->name, prec->tse); } } void epicsShareAPI recGblTSELwasModified(struct link *plink) { struct pv_link *ppv_link = &plink->value.pv_link; char *pfieldname; if (plink->type != PV_LINK) { errlogPrintf("recGblTSELwasModified called for non PV_LINK\n"); return; } /*If pvname ends in .TIME then just ask for VAL*/ /*Note that the VAL value will not be used*/ pfieldname = strstr(ppv_link->pvname, ".TIME"); if (pfieldname) { strcpy(pfieldname, ".VAL"); ppv_link->pvlMask |= pvlOptTSELisTime; } } static void getMaxRangeValues(short field_type, double *pupper_limit, double *plower_limit) { switch(field_type){ case(DBF_CHAR): *pupper_limit = -128.0; *plower_limit = 127.0; break; case(DBF_UCHAR): *pupper_limit = 255.0; *plower_limit = 0.0; break; case(DBF_SHORT): *pupper_limit = (double)SHRT_MAX; *plower_limit = (double)SHRT_MIN; break; case(DBF_ENUM): case(DBF_USHORT): *pupper_limit = (double)USHRT_MAX; *plower_limit = (double)0; break; case(DBF_LONG): /* long did not work using cast to double */ *pupper_limit = 2147483647.; *plower_limit = -2147483648.; break; case(DBF_ULONG): *pupper_limit = (double)ULONG_MAX; *plower_limit = (double)0; break; case(DBF_FLOAT): *pupper_limit = (double)1e+30; *plower_limit = (double)-1e30; break; case(DBF_DOUBLE): *pupper_limit = (double)1e+30; *plower_limit = (double)-1e30; break; } return; }