diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile index 324edecb5..132861fda 100644 --- a/src/ioc/db/Makefile +++ b/src/ioc/db/Makefile @@ -21,6 +21,7 @@ INC += dbChannel.h INC += dbConvert.h INC += dbConvertFast.h INC += dbEvent.h +INC += dbLink.h INC += dbLock.h INC += dbNotify.h INC += dbScan.h @@ -57,6 +58,7 @@ dbCore_SRCS += dbBkpt.c dbCore_SRCS += dbChannel.c dbCore_SRCS += dbConvert.c dbCore_SRCS += dbFastLinkConv.c +dbCore_SRCS += dbLink.c dbCore_SRCS += dbNotify.c dbCore_SRCS += dbScan.c dbCore_SRCS += dbEvent.c diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index bca64397a..10dc7f468 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -46,6 +46,7 @@ #include "dbAddr.h" #include "callback.h" #include "dbScan.h" +#include "dbLink.h" #include "dbLock.h" #include "dbEvent.h" #include "dbConvert.h" @@ -90,17 +91,6 @@ static short mapDBFToDBR[DBF_NTYPES] = { /* The following is to handle SPC_AS */ static SPC_ASCALLBACK spcAsCallback = 0; -static void inherit_severity(const struct pv_link *ppv_link, - dbCommon *pdest, epicsEnum16 stat, epicsEnum16 sevr) -{ - switch(ppv_link->pvlMask&pvlOptMsMode) { - case pvlOptNMS: break; - case pvlOptMSI: if (sevr < INVALID_ALARM) break; - case pvlOptMS: recGblSetSevr(pdest,LINK_ALARM,sevr); break; - case pvlOptMSS: recGblSetSevr(pdest,stat,sevr); break; - } -} - void epicsShareAPI dbSpcAsRegisterCallback(SPC_ASCALLBACK func) { spcAsCallback = func; @@ -420,10 +410,10 @@ long epicsShareAPI dbPutAttribute( int epicsShareAPI dbIsValueField(const struct dbFldDes *pdbFldDes) { - if(pdbFldDes->pdbRecordType->indvalFlddes == pdbFldDes->indRecordType) - return(TRUE); + if (pdbFldDes->pdbRecordType->indvalFlddes == pdbFldDes->indRecordType) + return TRUE; else - return(FALSE); + return FALSE; } int epicsShareAPI dbGetFieldIndex(const struct dbAddr *paddr) @@ -431,50 +421,6 @@ int epicsShareAPI dbGetFieldIndex(const struct dbAddr *paddr) return paddr->pfldDes->indRecordType; } -long epicsShareAPI dbGetNelements(const struct link *plink,long *nelements) -{ - switch(plink->type) { - case CONSTANT: - *nelements = 0; - return(0); - case DB_LINK: { - DBADDR *paddr = (DBADDR *)plink->value.pv_link.pvt; - *nelements = paddr->no_elements; - return(0); - } - case CA_LINK: - return(dbCaGetNelements(plink,nelements)); - default: - break; - } - return(S_db_badField); -} - -int epicsShareAPI dbIsLinkConnected(const struct link *plink) -{ - switch(plink->type) { - case DB_LINK: return(TRUE); - case CA_LINK: return(dbCaIsLinkConnected(plink)); - default: break; - } - return(FALSE); -} - -int epicsShareAPI dbGetLinkDBFtype(const struct link *plink) -{ - switch(plink->type) { - case DB_LINK: - { - DBADDR *paddr = (DBADDR *)plink->value.pv_link.pvt; - - return((int)paddr->field_type); - } - case CA_LINK: return(dbCaGetLinkDBFtype(plink)); - default: break; - } - return(-1); -} - /* * Process a record if its scan field is passive. * Will notify if processing is complete by callback. @@ -482,48 +428,13 @@ int epicsShareAPI dbGetLinkDBFtype(const struct link *plink) */ long epicsShareAPI dbScanPassive(dbCommon *pfrom, dbCommon *pto) { - long status; - /* if not passive just return success */ - if(pto->scan != 0) return(0); + if (pto->scan != 0) + return 0; - if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto); - status = dbProcess(pto); - return(status); -} - -/*KLUDGE: Following needed so that dbPutLink to PROC field works correctly*/ -long epicsShareAPI dbScanLink(dbCommon *pfrom, dbCommon *pto) -{ - long status; - unsigned char pact; - - if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto); - pact = pfrom->pact; - pfrom->pact = TRUE; - status = dbProcess(pto); - pfrom->pact = pact; - return(status); -} - -void epicsShareAPI dbScanFwdLink(struct link *plink) -{ - dbCommon *precord; - struct pv_link *pvlink; - short fwdLinkValue; - - if(plink->type!=DB_LINK && plink->type!=CA_LINK) return; - pvlink = &plink->value.pv_link; - precord = pvlink->precord; - if(plink->type==DB_LINK) { - dbAddr *paddr = (dbAddr *)plink->value.pv_link.pvt; - dbScanPassive(precord,paddr->precord); - return; - } - if(!(pvlink->pvlMask & pvlOptFWD)) return; - fwdLinkValue = 1; - dbCaPutLink(plink,DBR_SHORT,&fwdLinkValue,1); - return; + if (pfrom && pfrom->ppn) + dbNotifyAdd(pfrom,pto); + return dbProcess(pto); } /* @@ -537,119 +448,125 @@ void epicsShareAPI dbScanFwdLink(struct link *plink) */ long epicsShareAPI dbProcess(dbCommon *precord) { - struct rset *prset = precord->rset; - dbRecordType *pdbRecordType = precord->rdes; - unsigned char tpro=precord->tpro; - long status = 0; - int *ptrace; - int set_trace=FALSE; - dbFldDes *pdbFldDes; - int callNotifyCompletion = FALSE; + struct rset *prset = precord->rset; + dbRecordType *pdbRecordType = precord->rdes; + unsigned char tpro = precord->tpro; + long status = 0; + int *ptrace; + int set_trace = FALSE; + dbFldDes *pdbFldDes; + int callNotifyCompletion = FALSE; - ptrace = dbLockSetAddrTrace(precord); + ptrace = dbLockSetAddrTrace(precord); + /* + * Note that it is likely that if any changes are made + * to dbProcess() corresponding changes will have to + * be made in the breakpoint handler. + */ + + /* see if there are any stopped records or breakpoints */ + if (lset_stack_count != 0) { /* - * Note that it is likely that if any changes are made - * to dbProcess() corresponding changes will have to - * be made in the breakpoint handler. + * Check to see if the record should be processed + * and activate breakpoint accordingly. If this + * function call returns non-zero, skip record + * support and fall out of dbProcess(). This is + * done so that a dbContTask() can be spawned to + * take over record processing for the lock set + * containing a breakpoint. */ + if (dbBkpt(precord)) + goto all_done; + } - /* see if there are any stopped records or breakpoints */ - if (lset_stack_count != 0) { - /* - * Check to see if the record should be processed - * and activate breakpoint accordingly. If this - * function call returns non-zero, skip record - * support and fall out of dbProcess(). This is - * done so that a dbContTask() can be spawned to - * take over record processing for the lock set - * containing a breakpoint. - */ - if (dbBkpt(precord)) - goto all_done; + /* check for trace processing*/ + if (tpro) { + if(*ptrace==0) { + *ptrace = 1; + set_trace = TRUE; } + } - /* check for trace processing*/ - if (tpro) { - if(*ptrace==0) { - *ptrace = 1; - set_trace = TRUE; - } - } + /* If already active dont process */ + if (precord->pact) { + unsigned short monitor_mask; - /* If already active dont process */ - if (precord->pact) { - unsigned short monitor_mask; + if (*ptrace) + printf("%s: Active %s\n", + epicsThreadGetNameSelf(), precord->name); + /* raise scan alarm after MAX_LOCK times */ + if (precord->stat==SCAN_ALARM) goto all_done; + if (precord->lcnt++ !=MAX_LOCK) goto all_done; + if (precord->sevr>=INVALID_ALARM) goto all_done; + recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM); + monitor_mask = recGblResetAlarms(precord); + monitor_mask |= DBE_VALUE|DBE_LOG; + pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes]; + db_post_events(precord, + (void *)(((char *)precord) + pdbFldDes->offset), + monitor_mask); + goto all_done; + } + else precord->lcnt = 0; - if (*ptrace) printf("%s: Active %s\n", - epicsThreadGetNameSelf(), precord->name); - /* raise scan alarm after MAX_LOCK times */ - if (precord->stat==SCAN_ALARM) goto all_done; - if (precord->lcnt++ !=MAX_LOCK) goto all_done; - if (precord->sevr>=INVALID_ALARM) goto all_done; - recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM); - monitor_mask = recGblResetAlarms(precord); - monitor_mask |= DBE_VALUE|DBE_LOG; - pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes]; - db_post_events(precord, - (void *)(((char *)precord) + pdbFldDes->offset), - monitor_mask); - goto all_done; - } - else precord->lcnt = 0; + /* + * Check the record disable link. A record will not be + * processed if the value retrieved through this link + * is equal to constant set in the record's disv field. + */ + status = dbGetLink(&precord->sdis, DBR_SHORT, &precord->disa, 0, 0); - /* - * Check the record disable link. A record will not be - * processed if the value retrieved through this link - * is equal to constant set in the record's disv field. - */ - status = dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0); + /* if disabled check disable alarm severity and return success */ + if (precord->disa == precord->disv) { + if(*ptrace) + printf("%s: Disabled %s\n", + epicsThreadGetNameSelf(), precord->name); - /* if disabled check disable alarm severity and return success */ - if (precord->disa == precord->disv) { - if(*ptrace) printf("%s: Disabled %s\n", - epicsThreadGetNameSelf(), precord->name); - /*take care of caching and notifyCompletion*/ - precord->rpro = FALSE; - precord->putf = FALSE; - callNotifyCompletion = TRUE; - /* raise disable alarm */ - if (precord->stat==DISABLE_ALARM) goto all_done; - precord->sevr = precord->diss; - precord->stat = DISABLE_ALARM; - precord->nsev = 0; - precord->nsta = 0; - db_post_events(precord, &precord->stat, DBE_VALUE); - db_post_events(precord, &precord->sevr, DBE_VALUE); - pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes]; - db_post_events(precord, - (void *)(((char *)precord) + pdbFldDes->offset), - DBE_VALUE|DBE_ALARM); - goto all_done; - } + /*take care of caching and notifyCompletion*/ + precord->rpro = FALSE; + precord->putf = FALSE; + callNotifyCompletion = TRUE; - /* locate record processing routine */ - /* put this in iocInit() !!! */ - if (!(prset=precord->rset) || !(prset->process)) { - callNotifyCompletion = TRUE; - precord->pact=1;/*set pact TRUE so error is issued only once*/ - recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess"); - status = S_db_noRSET; - if (*ptrace) printf("%s: No RSET for %s\n", - epicsThreadGetNameSelf(), precord->name); - goto all_done; - } - if(*ptrace) printf("%s: Process %s\n", - epicsThreadGetNameSelf(), precord->name); - /* process record */ - status = (*prset->process)(precord); - /* Print record's fields if PRINT_MASK set in breakpoint field */ - if (lset_stack_count != 0) { - dbPrint(precord); - } + /* raise disable alarm */ + if (precord->stat==DISABLE_ALARM) goto all_done; + precord->sevr = precord->diss; + precord->stat = DISABLE_ALARM; + precord->nsev = 0; + precord->nsta = 0; + db_post_events(precord, &precord->stat, DBE_VALUE); + db_post_events(precord, &precord->sevr, DBE_VALUE); + pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes]; + db_post_events(precord, + (void *)(((char *)precord) + pdbFldDes->offset), + DBE_VALUE|DBE_ALARM); + goto all_done; + } + + /* locate record processing routine */ + /* FIXME: put this in iocInit() !!! */ + if (!(prset=precord->rset) || !(prset->process)) { + callNotifyCompletion = TRUE; + precord->pact=1;/*set pact TRUE so error is issued only once*/ + recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess"); + status = S_db_noRSET; + if (*ptrace) + printf("%s: No RSET for %s\n", + epicsThreadGetNameSelf(), precord->name); + goto all_done; + } + if(*ptrace) + printf("%s: Process %s\n", + epicsThreadGetNameSelf(), precord->name); + /* process record */ + status = (*prset->process)(precord); + /* Print record's fields if PRINT_MASK set in breakpoint field */ + if (lset_stack_count != 0) { + dbPrint(precord); + } all_done: - if (set_trace) *ptrace = 0; - if(callNotifyCompletion && precord->ppn) dbNotifyCompletion(precord); - return(status); + if (set_trace) *ptrace = 0; + if(callNotifyCompletion && precord->ppn) dbNotifyCompletion(precord); + return(status); } /* @@ -776,121 +693,6 @@ int epicsShareAPI dbLoadRecords(const char* file, const char* subs) } -long epicsShareAPI dbGetLinkValue(struct link *plink, short dbrType, - void *pbuffer, long *poptions, long *pnRequest) -{ - long status = 0; - - if (plink->type == CONSTANT) { - if (poptions) *poptions = 0; - if (pnRequest) *pnRequest = 0; - } else if (plink->type == DB_LINK) { - struct pv_link *ppv_link = &(plink->value.pv_link); - DBADDR *paddr = ppv_link->pvt; - dbCommon *precord = plink->value.pv_link.precord; - - /* scan passive records with links that are process passive */ - if (ppv_link->pvlMask&pvlOptPP) { - dbCommon *pfrom = paddr->precord; - unsigned char pact; - - pact = precord->pact; - precord->pact = TRUE; - status = dbScanPassive(precord,pfrom); - precord->pact = pact; - if (status) return status; - } - if(precord!= paddr->precord) { - inherit_severity(ppv_link,precord,paddr->precord->stat,paddr->precord->sevr); - } - - if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) { - status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); - } else { - unsigned short dbfType = paddr->field_type; - long no_elements = paddr->no_elements; - - if (dbrType < 0 || dbrType > DBR_ENUM || - dbfType > DBF_DEVICE) { - status = S_db_badDbrtype; - recGblRecordError(status, precord, "GetLinkValue Failed"); - recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); - return status; - } - /* attempt to make a fast link */ - if ((!poptions || *poptions == 0) && - no_elements == 1 && - (!pnRequest || *pnRequest == 1) && - paddr->special != SPC_ATTRIBUTE) { - ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType]; - status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); - } else { - ppv_link->getCvt = 0; - status = dbGet(paddr, dbrType, pbuffer, poptions, pnRequest, NULL); - } - } - ppv_link->lastGetdbrType = dbrType; - if (status) { - recGblRecordError(status, precord, "dbGetLinkValue"); - recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); - } - } else if (plink->type == CA_LINK) { - struct dbCommon *precord = plink->value.pv_link.precord; - const struct pv_link *pcalink = &plink->value.pv_link; - epicsEnum16 sevr, stat; - - status=dbCaGetLink(plink,dbrType,pbuffer,&stat,&sevr,pnRequest); - if (status) { - recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); - } else { - inherit_severity(pcalink,precord,stat,sevr); - } - if (poptions) *poptions = 0; - } else { - cantProceed("dbGetLinkValue: Illegal link type"); - } - return status; -} - -long epicsShareAPI dbPutLinkValue(struct link *plink, short dbrType, - const void *pbuffer, long nRequest) -{ - long status = 0; - - if (plink->type == DB_LINK) { - struct dbCommon *psource = plink->value.pv_link.precord; - struct pv_link *ppv_link = &plink->value.pv_link; - DBADDR *paddr = (DBADDR *)ppv_link->pvt; - dbCommon *pdest = paddr->precord; - - status = dbPut(paddr, dbrType, pbuffer, nRequest); - inherit_severity(ppv_link,pdest,psource->nsta,psource->nsev); - if (status) return status; - - if (paddr->pfield == &pdest->proc || - (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) { - /*if dbPutField caused asyn record to process */ - /* ask for reprocessing*/ - if (pdest->putf) { - pdest->rpro = TRUE; - } else { /* otherwise ask for the record to be processed*/ - status = dbScanLink(psource, pdest); - } - } - if (status) - recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM); - } else if (plink->type == CA_LINK) { - struct dbCommon *psource = plink->value.pv_link.precord; - - status = dbCaPutLink(plink, dbrType, pbuffer, nRequest); - if (status < 0) - recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM); - } else { - cantProceed("dbPutLinkValue: Illegal link type"); - } - return status; -} - static long getLinkValue(DBADDR *paddr, short dbrType, char *pbuf, long *nRequest) { @@ -1076,10 +878,9 @@ static long dbPutFieldLink(DBADDR *paddr, dbCommon *precord = paddr->precord; dbFldDes *pfldDes = paddr->pfldDes; long special = paddr->special; - DBLINK *plink = (DBLINK *)paddr->pfield; + struct link *plink = (struct link *)paddr->pfield; const char *pstring = (const char *)pbuffer; DBENTRY dbEntry; - DBADDR dbaddr; struct dsxt *old_dsxt = NULL; struct dset *new_dset = NULL; struct dsxt *new_dsxt = NULL; @@ -1150,21 +951,8 @@ static long dbPutFieldLink(DBADDR *paddr, switch (plink->type) { /* Old link type */ case DB_LINK: - free(plink->value.pv_link.pvt); - plink->value.pv_link.pvt = 0; - plink->type = PV_LINK; - plink->value.pv_link.getCvt = 0; - plink->value.pv_link.pvlMask = 0; - plink->value.pv_link.lastGetdbrType = 0; - dbLockSetSplit(precord); - break; - case CA_LINK: - dbCaRemoveLink(plink); - plink->type = PV_LINK; - plink->value.pv_link.getCvt = 0; - plink->value.pv_link.pvlMask = 0; - plink->value.pv_link.lastGetdbrType = 0; + dbRemoveLink(plink); break; case CONSTANT: @@ -1211,35 +999,7 @@ static long dbPutFieldLink(DBADDR *paddr, switch (plink->type) { /* New link type */ case PV_LINK: - if (plink == &precord->tsel) - recGblTSELwasModified(plink); - plink->value.pv_link.precord = precord; - - if (!(plink->value.pv_link.pvlMask & (pvlOptCA|pvlOptCP|pvlOptCPP)) && - (dbNameToAddr(plink->value.pv_link.pvname, &dbaddr) == 0)) { - /* It's a DB link */ - DBADDR *pdbAddr; - - plink->type = DB_LINK; - pdbAddr = dbMalloc(sizeof(struct dbAddr)); - *pdbAddr = dbaddr; /* NB: structure copy */; - plink->value.pv_link.pvt = pdbAddr; - dbLockSetRecordLock(pdbAddr->precord); - dbLockSetMerge(precord, pdbAddr->precord); - } else { /* Make it a CA link */ - char *pperiod; - - plink->type = CA_LINK; - if (pfldDes->field_type == DBF_INLINK) { - plink->value.pv_link.pvlMask |= pvlOptInpNative; - } - dbCaAddLink(plink); - if (pfldDes->field_type == DBF_FWDLINK) { - pperiod = strrchr(plink->value.pv_link.pvname, '.'); - if (pperiod && strstr(pperiod, "PROC")) - plink->value.pv_link.pvlMask |= pvlOptFWD; - } - } + dbAddLink(precord, plink, pfldDes->field_type); break; case CONSTANT: @@ -1267,7 +1027,7 @@ restoreScan: } postScanEvent: if (scan != precord->scan) - db_post_events(precord, &precord->scan, DBE_VALUE|DBE_LOG); + db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG); unlock: dbLockSetGblUnlock(); finish: @@ -1424,139 +1184,3 @@ long epicsShareAPI dbPut(DBADDR *paddr, short dbrType, return status; } -/* various utility routines */ -long epicsShareAPI dbGetControlLimits( - const struct link *plink,double *low, double *high) -{ - struct buffer { - DBRctrlDouble - double value; - } buffer; - DBADDR *paddr; - long options = DBR_CTRL_DOUBLE; - long number_elements = 0; - long status; - - if(plink->type == CA_LINK) return(dbCaGetControlLimits(plink,low,high)); - if(plink->type !=DB_LINK) return(S_db_notFound); - paddr = (DBADDR *)plink->value.pv_link.pvt; - status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0); - if(status) return(status); - *low = buffer.lower_ctrl_limit; - *high = buffer.upper_ctrl_limit; - return(0); -} - -long epicsShareAPI dbGetGraphicLimits( - const struct link *plink,double *low, double *high) -{ - struct buffer { - DBRgrDouble - double value; - } buffer; - DBADDR *paddr; - long options = DBR_GR_DOUBLE; - long number_elements = 0; - long status; - - if(plink->type == CA_LINK) return(dbCaGetGraphicLimits(plink,low,high)); - if(plink->type !=DB_LINK) return(S_db_notFound); - paddr = (DBADDR *)plink->value.pv_link.pvt; - status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0); - if(status) return(status); - *low = buffer.lower_disp_limit; - *high = buffer.upper_disp_limit; - return(0); -} - -long epicsShareAPI dbGetAlarmLimits(const struct link *plink, - double *lolo, double *low, double *high, double *hihi) -{ - struct buffer { - DBRalDouble - double value; - } buffer; - DBADDR *paddr; - long options = DBR_AL_DOUBLE; - long number_elements = 0; - long status; - - if(plink->type == CA_LINK) - return(dbCaGetAlarmLimits(plink,lolo,low,high,hihi)); - if(plink->type !=DB_LINK) return(S_db_notFound); - paddr = (DBADDR *)plink->value.pv_link.pvt; - status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0); - if(status) return(status); - *lolo = buffer.lower_alarm_limit; - *low = buffer.lower_warning_limit; - *high = buffer.upper_warning_limit; - *hihi = buffer.upper_alarm_limit; - return(0); -} - -long epicsShareAPI dbGetPrecision(const struct link *plink,short *precision) -{ - struct buffer { - DBRprecision - double value; - } buffer; - DBADDR *paddr; - long options = DBR_PRECISION; - long number_elements = 0; - long status; - - if(plink->type == CA_LINK) return(dbCaGetPrecision(plink,precision)); - if(plink->type !=DB_LINK) return(S_db_notFound); - paddr = (DBADDR *)plink->value.pv_link.pvt; - status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0); - if(status) return(status); - *precision = buffer.precision.dp; - return(0); -} - -long epicsShareAPI dbGetUnits( - const struct link *plink,char *units,int unitsSize) -{ - struct buffer { - DBRunits - double value; - } buffer; - DBADDR *paddr; - long options = DBR_UNITS; - long number_elements = 0; - long status; - - if(plink->type == CA_LINK) return(dbCaGetUnits(plink,units,unitsSize)); - if(plink->type !=DB_LINK) return(S_db_notFound); - paddr = (DBADDR *)plink->value.pv_link.pvt; - status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0); - if(status) return(status); - strncpy(units,buffer.units,unitsSize); - return(0); -} - -long epicsShareAPI dbGetAlarm(const struct link *plink, - epicsEnum16 *status,epicsEnum16 *severity) -{ - DBADDR *paddr; - - if(plink->type == CA_LINK) return(dbCaGetAlarm(plink,status,severity)); - if(plink->type !=DB_LINK) return(S_db_notFound); - paddr = (DBADDR *)plink->value.pv_link.pvt; - if (status) *status = paddr->precord->stat; - if (severity) *severity = paddr->precord->sevr; - return(0); -} - -long epicsShareAPI dbGetTimeStamp(const struct link *plink,epicsTimeStamp *pstamp) -{ - DBADDR *paddr; - - if (plink->type == CA_LINK) - return dbCaGetTimeStamp(plink,pstamp); - if (plink->type != DB_LINK) - return S_db_notFound; - paddr = (DBADDR *)plink->value.pv_link.pvt; - *pstamp = paddr->precord->time; - return 0; -} diff --git a/src/ioc/db/dbAccess.h b/src/ioc/db/dbAccess.h index 909774323..96246b302 100644 --- a/src/ioc/db/dbAccess.h +++ b/src/ioc/db/dbAccess.h @@ -3,8 +3,7 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found +* EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbAccess.h */ @@ -22,6 +21,7 @@ #include "dbAddr.h" #include "dbLock.h" #include "dbAccessDefs.h" +#include "dbLink.h" #include "dbCa.h" #include "dbCommon.h" #include "db_field_log.h" diff --git a/src/ioc/db/dbAccessDefs.h b/src/ioc/db/dbAccessDefs.h index 6c12d3df5..81fe939a4 100644 --- a/src/ioc/db/dbAccessDefs.h +++ b/src/ioc/db/dbAccessDefs.h @@ -3,8 +3,7 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found +* EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbAccessDefs.h */ @@ -199,76 +198,30 @@ struct dbr_alDouble {DBRalDouble}; #define S_db_cntCont (M_dbAccess|65) /*Cannot resume dbContTask*/ #define S_db_noMemory (M_dbAccess|66) /*unable to allocate data structure from pool*/ -/* Global Database Access Routines*/ -#define dbGetLink(PLNK, DBRTYPE, PBUFFER, OPTIONS, NREQUEST) \ - ( ( ( (PLNK)->type == CONSTANT ) && \ - ( (NREQUEST) == 0) &&\ - ( (OPTIONS) == 0) ) \ - ? 0 \ - : dbGetLinkValue((PLNK),(DBRTYPE), \ - (void *)(PBUFFER), (OPTIONS), (NREQUEST) ) ) -#define dbPutLink(PLNK, DBRTYPE, PBUFFER, NREQUEST) \ - ( ( (PLNK)->type == CONSTANT) \ - ? 0 \ - : dbPutLinkValue( (PLNK), (DBRTYPE), (void *)(PBUFFER), (NREQUEST) ) ) -#define dbGetPdbAddrFromLink(PLNK) \ - ( ( (PLNK)->type != DB_LINK ) \ - ? 0 \ - : ( ( (struct dbAddr *)( (PLNK)->value.pv_link.pvt) ) ) ) -#define dbGetSevr(PLINK,PSEVERITY) \ - dbGetAlarm((PLINK),NULL,(PSEVERITY)) - epicsShareFunc long epicsShareAPI dbPutSpecial(struct dbAddr *paddr,int pass); epicsShareFunc struct rset * epicsShareAPI dbGetRset(const struct dbAddr *paddr); epicsShareFunc long epicsShareAPI dbPutAttribute( const char *recordTypename,const char *name,const char*value); epicsShareFunc int epicsShareAPI dbIsValueField(const struct dbFldDes *pdbFldDes); epicsShareFunc int epicsShareAPI dbGetFieldIndex(const struct dbAddr *paddr); -epicsShareFunc long epicsShareAPI dbGetNelements( - const struct link *plink,long *nelements); -epicsShareFunc int epicsShareAPI dbIsLinkConnected(const struct link *plink); -epicsShareFunc int epicsShareAPI dbGetLinkDBFtype(const struct link *plink); -epicsShareFunc long epicsShareAPI dbScanLink( - struct dbCommon *pfrom, struct dbCommon *pto); epicsShareFunc long epicsShareAPI dbScanPassive( struct dbCommon *pfrom,struct dbCommon *pto); -epicsShareFunc void epicsShareAPI dbScanFwdLink(struct link *plink); epicsShareFunc long epicsShareAPI dbProcess(struct dbCommon *precord); epicsShareFunc long epicsShareAPI dbNameToAddr( const char *pname,struct dbAddr *); epicsShareFunc devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *prdes, int dtyp); epicsShareFunc devSup* epicsShareAPI dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset); -epicsShareFunc long epicsShareAPI dbGetLinkValue( - struct link *,short dbrType,void *pbuffer,long *options,long *nRequest); epicsShareFunc long epicsShareAPI dbGetField( struct dbAddr *,short dbrType,void *pbuffer,long *options, long *nRequest,void *pfl); epicsShareFunc long epicsShareAPI dbGet( struct dbAddr *,short dbrType,void *pbuffer,long *options, long *nRequest,void *pfl); -epicsShareFunc long epicsShareAPI dbPutLinkValue( - struct link *,short dbrType,const void *pbuffer,long nRequest); epicsShareFunc long epicsShareAPI dbPutField( struct dbAddr *,short dbrType,const void *pbuffer,long nRequest); epicsShareFunc long epicsShareAPI dbPut( struct dbAddr *,short dbrType,const void *pbuffer,long nRequest); -/* various utility routines */ -epicsShareFunc long epicsShareAPI dbGetControlLimits( - const struct link *plink,double *low, double *high); -epicsShareFunc long epicsShareAPI dbGetGraphicLimits( - const struct link *plink,double *low, double *high); -epicsShareFunc long epicsShareAPI dbGetAlarmLimits( - const struct link *plink,double *lolo, double *low, double *high, double *hihi); -epicsShareFunc long epicsShareAPI dbGetPrecision( - const struct link *plink,short *precision); -epicsShareFunc long epicsShareAPI dbGetUnits( - const struct link *plink,char *units,int unitsSize); -epicsShareFunc long epicsShareAPI dbGetAlarm( - const struct link *plink, epicsEnum16 *status,epicsEnum16 *severity); -epicsShareFunc long epicsShareAPI dbGetTimeStamp( - const struct link *plink,epicsTimeStamp *pstamp); - typedef void(*SPC_ASCALLBACK)(struct dbCommon *); /*dbSpcAsRegisterCallback called by access security */ epicsShareFunc void epicsShareAPI dbSpcAsRegisterCallback(SPC_ASCALLBACK func); diff --git a/src/ioc/db/dbBkpt.c b/src/ioc/db/dbBkpt.c index f865ba80c..681886676 100644 --- a/src/ioc/db/dbBkpt.c +++ b/src/ioc/db/dbBkpt.c @@ -65,6 +65,7 @@ #include "dbAddr.h" #include "dbAccessDefs.h" #include "dbScan.h" +#include "dbLink.h" #include "dbLock.h" #include "recGbl.h" #include "dbTest.h" diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c index 9f90dabc0..5db15d323 100644 --- a/src/ioc/db/dbCa.c +++ b/src/ioc/db/dbCa.c @@ -411,6 +411,13 @@ int dbCaIsLinkConnected(const struct link *plink) return pca->isConnected; } +void dbCaScanFwdLink(struct link *plink) { + short fwdLinkValue = 1; + + if (plink->value.pv_link.pvlMask & pvlOptFWD) + dbCaPutLink(plink, DBR_SHORT, &fwdLinkValue, 1); +} + #define pcaGetCheck \ assert(plink); \ if (plink->type != CA_LINK) return -1; \ @@ -639,7 +646,7 @@ done: static void eventCallback(struct event_handler_args arg) { caLink *pca = (caLink *)arg.usr; - DBLINK *plink; + struct link *plink; size_t size; dbCommon *precord = 0; struct dbr_time_double *pdbr_time_double; diff --git a/src/ioc/db/dbCa.h b/src/ioc/db/dbCa.h index ee0fee1ca..bf6f2edd9 100644 --- a/src/ioc/db/dbCa.h +++ b/src/ioc/db/dbCa.h @@ -40,6 +40,7 @@ epicsShareFunc long dbCaPutLinkCallback(struct link *plink, #define dbCaPutLink(plink, dbrType, pbuffer, nRequest) \ dbCaPutLinkCallback((plink), (dbrType), (pbuffer), (nRequest), 0, 0) epicsShareFunc int dbCaIsLinkConnected(const struct link *plink); +epicsShareFunc void dbCaScanFwdLink(struct link *plink); /* The following are available after the link is connected*/ epicsShareFunc long dbCaGetNelements(const struct link *plink, diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c new file mode 100644 index 000000000..870183136 --- /dev/null +++ b/src/ioc/db/dbLink.c @@ -0,0 +1,623 @@ +/*************************************************************************\ +* Copyright (c) 2010 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. + \*************************************************************************/ +/* dbLink.c */ +/* $Id$ */ +/* + * Original Authors: Bob Dalesio, Marty Kraimer + * Current Author: Andrew Johnson + */ + +#include +#include +#include +#include +#include + +#include "dbDefs.h" +#include "epicsThread.h" +#include "errlog.h" +#include "cantProceed.h" +#include "cvtFast.h" +#include "epicsTime.h" +#include "alarm.h" +#include "ellLib.h" +#include "dbStaticLib.h" +#include "dbBase.h" +#include "link.h" +#include "dbFldTypes.h" +#include "recSup.h" +#include "devSup.h" +#include "caeventmask.h" +#include "db_field_log.h" +#include "dbCommon.h" +#include "dbFldTypes.h" +#include "special.h" +#include "errMdef.h" +#define epicsExportSharedSymbols +#include "dbAddr.h" +#include "dbLink.h" +#include "callback.h" +#include "dbScan.h" +#include "dbLock.h" +#include "dbEvent.h" +#include "dbConvert.h" +#include "dbConvertFast.h" +#include "epicsEvent.h" +#include "dbCa.h" +#include "dbBkpt.h" +#include "dbNotify.h" +#include "dbAccessDefs.h" +#include "recGbl.h" + +static void inherit_severity(const struct pv_link *ppv_link, dbCommon *pdest, + epicsEnum16 stat, epicsEnum16 sevr) +{ + switch (ppv_link->pvlMask & pvlOptMsMode) { + case pvlOptNMS: + break; + case pvlOptMSI: + if (sevr < INVALID_ALARM) + break; + /* Fall through */ + case pvlOptMS: + recGblSetSevr(pdest, LINK_ALARM, sevr); + break; + case pvlOptMSS: + recGblSetSevr(pdest, stat, sevr); + break; + } +} + +/***************************** Constant Links *****************************/ + +static long dbConstGetNelements(const struct link *plink, long *nelements) +{ + *nelements = 0; + return 0; +} + +static long dbConstGetLink(struct link *plink, short dbrType, void *pbuffer, + epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest) +{ + if (pnRequest) + *pnRequest = 0; + return 0; +} + +/***************************** Database Links *****************************/ + +static long dbDbInitLink(struct link *plink, short dbfType) +{ + DBADDR dbaddr; + long status; + DBADDR *pdbAddr; + + status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr); + if (status) + return status; + + plink->type = DB_LINK; + pdbAddr = dbCalloc(1, sizeof(struct dbAddr)); + *pdbAddr = dbaddr; /* structure copy */ + plink->value.pv_link.pvt = pdbAddr; + return 0; +} + +static long dbDbAddLink(struct link *plink, short dbfType) +{ + long status = dbDbInitLink(plink, dbfType); + + if (!status) { + DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt; + dbCommon *precord = plink->value.pv_link.precord; + + dbLockSetRecordLock(pdbAddr->precord); + dbLockSetMerge(precord, pdbAddr->precord); + } + return status; +} + +static void dbDbRemoveLink(struct link *plink) +{ + free(plink->value.pv_link.pvt); + plink->value.pv_link.pvt = 0; + plink->value.pv_link.getCvt = 0; + plink->value.pv_link.lastGetdbrType = 0; + dbLockSetSplit(plink->value.pv_link.precord); +} + +static int dbDbIsLinkConnected(const struct link *plink) +{ + return TRUE; +} + +static int dbDbGetDBFtype(const struct link *plink) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + + return paddr->field_type; +} + +static long dbDbGetElements(const struct link *plink, long *nelements) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + + *nelements = paddr->no_elements; + return 0; +} + +static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, + epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest) +{ + struct pv_link *ppv_link = &plink->value.pv_link; + DBADDR *paddr = ppv_link->pvt; + dbCommon *precord = plink->value.pv_link.precord; + long status; + + /* scan passive records if link is process passive */ + if (ppv_link->pvlMask & pvlOptPP) { + unsigned char pact = precord->pact; + + precord->pact = TRUE; + status = dbScanPassive(precord, paddr->precord); + precord->pact = pact; + if (status) + return status; + } + *pstat = paddr->precord->stat; + *psevr = paddr->precord->sevr; + + if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) { + status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); + } else { + unsigned short dbfType = paddr->field_type; + + if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE) + return S_db_badDbrtype; + + if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1) + && paddr->special != SPC_ATTRIBUTE) { + ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType]; + status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); + } else { + ppv_link->getCvt = NULL; + status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL); + } + ppv_link->lastGetdbrType = dbrType; + } + return status; +} + +static long dbDbGetControlLimits(const struct link *plink, double *low, + double *high) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + struct buffer { + DBRctrlDouble + double value; + } buffer; + long options = DBR_CTRL_DOUBLE; + long number_elements = 0; + long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, + NULL); + + if (status) + return status; + + *low = buffer.lower_ctrl_limit; + *high = buffer.upper_ctrl_limit; + return 0; +} + +static long dbDbGetGraphicLimits(const struct link *plink, double *low, + double *high) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + struct buffer { + DBRgrDouble + double value; + } buffer; + long options = DBR_GR_DOUBLE; + long number_elements = 0; + long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, + NULL); + + if (status) + return status; + + *low = buffer.lower_disp_limit; + *high = buffer.upper_disp_limit; + return 0; +} + +static long dbDbGetAlarmLimits(const struct link *plink, double *lolo, + double *low, double *high, double *hihi) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + struct buffer { + DBRalDouble + double value; + } buffer; + long options = DBR_AL_DOUBLE; + long number_elements = 0; + long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, + 0); + + if (status) + return status; + + *lolo = buffer.lower_alarm_limit; + *low = buffer.lower_warning_limit; + *high = buffer.upper_warning_limit; + *hihi = buffer.upper_alarm_limit; + return 0; +} + +static long dbDbGetPrecision(const struct link *plink, short *precision) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + struct buffer { + DBRprecision + double value; + } buffer; + long options = DBR_PRECISION; + long number_elements = 0; + long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, + 0); + + if (status) + return status; + + *precision = buffer.precision.dp; + return 0; +} + +static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + struct buffer { + DBRunits + double value; + } buffer; + long options = DBR_UNITS; + long number_elements = 0; + long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, + 0); + + if (status) + return status; + + strncpy(units, buffer.units, unitsSize); + return 0; +} + +static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status, + epicsEnum16 *severity) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + + if (status) + *status = paddr->precord->stat; + if (severity) + *severity = paddr->precord->sevr; + return 0; +} + +static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp) +{ + DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; + + *pstamp = paddr->precord->time; + return 0; +} + +static long dbDbPutValue(struct link *plink, short dbrType, + const void *pbuffer, long nRequest) +{ + struct pv_link *ppv_link = &plink->value.pv_link; + struct dbCommon *psrce = ppv_link->precord; + DBADDR *paddr = (DBADDR *) ppv_link->pvt; + dbCommon *pdest = paddr->precord; + long status = dbPut(paddr, dbrType, pbuffer, nRequest); + + inherit_severity(ppv_link, pdest, psrce->nsta, psrce->nsev); + if (status) + return status; + + if (paddr->pfield == (void *) &pdest->proc || + (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) { + /* if dbPutField caused asyn record to process */ + /* ask for reprocessing*/ + if (pdest->putf) { + pdest->rpro = TRUE; + } else { /* process dest record with source's PACT true */ + unsigned char pact; + + if (psrce && psrce->ppn) + dbNotifyAdd(psrce, pdest); + pact = psrce->pact; + psrce->pact = TRUE; + status = dbProcess(pdest); + psrce->pact = pact; + } + } + return status; +} + +static void dbDbScanFwdLink(struct link *plink) +{ + dbCommon *precord = plink->value.pv_link.precord; + dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt; + + dbScanPassive(precord, paddr->precord); +} + +lset dbDb_lset = { dbDbInitLink, dbDbAddLink, dbDbRemoveLink, + dbDbIsLinkConnected, dbDbGetDBFtype, dbDbGetElements, dbDbGetValue, + dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits, + dbDbGetPrecision, dbDbGetUnits, dbDbGetAlarm, dbDbGetTimeStamp, + dbDbPutValue, dbDbScanFwdLink }; + +/***************************** Generic Link API *****************************/ + +void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType) +{ + plink->value.pv_link.precord = precord; + + if (plink == &precord->tsel) + recGblTSELwasModified(plink); + + if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) { + /* Make it a DB link if possible */ + if (!dbDbInitLink(plink, dbfType)) + return; + } + + /* Make it a CA link */ + if (dbfType == DBF_INLINK) + plink->value.pv_link.pvlMask |= pvlOptInpNative; + + dbCaAddLink(plink); + if (dbfType == DBF_FWDLINK) { + char *pperiod = strrchr(plink->value.pv_link.pvname, '.'); + + if (pperiod && strstr(pperiod, "PROC")) { + plink->value.pv_link.pvlMask |= pvlOptFWD; + } else { + errlogPrintf("%s.FLNK is a Channel Access Link " + " but does not link to a PROC field\n", precord->name); + } + } +} + +void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType) +{ + plink->value.pv_link.precord = precord; + + if (plink == &precord->tsel) + recGblTSELwasModified(plink); + + if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) { + /* Make it a DB link if possible */ + if (!dbDbAddLink(plink, dbfType)) + return; + } + + /* Make it a CA link */ + if (dbfType == DBF_INLINK) + plink->value.pv_link.pvlMask |= pvlOptInpNative; + + dbCaAddLink(plink); + if (dbfType == DBF_FWDLINK) { + char *pperiod = strrchr(plink->value.pv_link.pvname, '.'); + + if (pperiod && strstr(pperiod, "PROC")) + plink->value.pv_link.pvlMask |= pvlOptFWD; + } +} + +void dbRemoveLink(struct link *plink) +{ + switch (plink->type) { + case DB_LINK: + dbDbRemoveLink(plink); + break; + case CA_LINK: + dbCaRemoveLink(plink); + break; + default: + cantProceed("dbRemoveLink: Unexpected link type %d\n", plink->type); + } + plink->type = PV_LINK; + plink->value.pv_link.pvlMask = 0; +} + +int dbIsLinkConnected(const struct link *plink) +{ + switch (plink->type) { + case DB_LINK: + return dbDbIsLinkConnected(plink); + case CA_LINK: + return dbCaIsLinkConnected(plink); + } + return FALSE; +} + +int dbGetLinkDBFtype(const struct link *plink) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetDBFtype(plink); + case CA_LINK: + return dbCaGetLinkDBFtype(plink); + } + return -1; +} + +long dbGetNelements(const struct link *plink, long *nelements) +{ + switch (plink->type) { + case CONSTANT: + return dbConstGetNelements(plink, nelements); + case DB_LINK: + return dbDbGetElements(plink, nelements); + case CA_LINK: + return dbCaGetNelements(plink, nelements); + } + return S_db_badField; +} + +long dbGetLinkValue(struct link *plink, short dbrType, void *pbuffer, + long *poptions, long *pnRequest) +{ + struct dbCommon *precord = plink->value.pv_link.precord; + epicsEnum16 sevr = 0, stat = 0; + long status; + + if (poptions && *poptions) { + printf("dbGetLinkValue: Use of poptions no longer supported\n"); + *poptions = 0; + } + + switch (plink->type) { + case CONSTANT: + status = dbConstGetLink(plink, dbrType, pbuffer, &stat, &sevr, + pnRequest); + break; + case DB_LINK: + status = dbDbGetValue(plink, dbrType, pbuffer, &stat, &sevr, pnRequest); + break; + case CA_LINK: + status = dbCaGetLink(plink, dbrType, pbuffer, &stat, &sevr, pnRequest); + break; + default: + cantProceed("dbGetLinkValue: Illegal link type"); + } + if (status) { + recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); + } else { + inherit_severity(&plink->value.pv_link, precord, stat, sevr); + } + return status; +} + +long dbGetControlLimits(const struct link *plink, double *low, double *high) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetControlLimits(plink, low, high); + case CA_LINK: + return dbCaGetControlLimits(plink, low, high); + } + return S_db_notFound; +} + +long dbGetGraphicLimits(const struct link *plink, double *low, double *high) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetGraphicLimits(plink, low, high); + case CA_LINK: + return dbCaGetGraphicLimits(plink, low, high); + } + return S_db_notFound; +} + +long dbGetAlarmLimits(const struct link *plink, double *lolo, double *low, + double *high, double *hihi) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetAlarmLimits(plink, lolo, low, high, hihi); + case CA_LINK: + return dbCaGetAlarmLimits(plink, lolo, low, high, hihi); + } + return S_db_notFound; +} + +long dbGetPrecision(const struct link *plink, short *precision) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetPrecision(plink, precision); + case CA_LINK: + return dbCaGetPrecision(plink, precision); + } + return S_db_notFound; +} + +long dbGetUnits(const struct link *plink, char *units, int unitsSize) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetUnits(plink, units, unitsSize); + case CA_LINK: + return dbCaGetUnits(plink, units, unitsSize); + } + return S_db_notFound; +} + +long dbGetAlarm(const struct link *plink, epicsEnum16 *status, + epicsEnum16 *severity) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetAlarm(plink, status, severity); + case CA_LINK: + return dbCaGetAlarm(plink, status, severity); + } + return S_db_notFound; +} + +long dbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp) +{ + switch (plink->type) { + case DB_LINK: + return dbDbGetTimeStamp(plink, pstamp); + case CA_LINK: + return dbCaGetTimeStamp(plink, pstamp); + } + return S_db_notFound; +} + +long dbPutLinkValue(struct link *plink, short dbrType, const void *pbuffer, + long nRequest) +{ + long status; + + switch (plink->type) { + case DB_LINK: + status = dbDbPutValue(plink, dbrType, pbuffer, nRequest); + break; + case CA_LINK: + status = dbCaPutLink(plink, dbrType, pbuffer, nRequest); + break; + default: + cantProceed("dbPutLinkValue: Illegal link type %d", plink->type); + } + if (status) { + struct dbCommon *precord = plink->value.pv_link.precord; + + recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); + } + return status; +} + +void dbScanFwdLink(struct link *plink) +{ + switch (plink->type) { + case DB_LINK: + dbDbScanFwdLink(plink); + break; + case CA_LINK: + dbCaScanFwdLink(plink); + break; + } +} + diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h new file mode 100644 index 000000000..0f2e14da8 --- /dev/null +++ b/src/ioc/db/dbLink.h @@ -0,0 +1,87 @@ +/*************************************************************************\ +* Copyright (c) 2010 The 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. +\*************************************************************************/ +/* + * dbLink.h + * + * Created on: Mar 21, 2010 + * Author: Andrew Johnson + */ + +#ifndef INC_dbLink_H +#define INC_dbLink_H + +#include "link.h" +#include "shareLib.h" + +typedef struct lset { + long (*initLink)(struct link *plink, short dbfType); + long (*addLink)(struct link *plink, short dbfType); + void (*removeLink)(struct link *plink); + int (*isLinkConnected)(const struct link *plink); + int (*getDBFtype)(const struct link *plink); + long (*getElements)(const struct link *plink, long *nelements); + long (*getValue)(struct link *plink, short dbrType, void *pbuffer, + epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest); + long (*getControlLimits)(const struct link *plink, double *lo, double *hi); + long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi); + long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo, + double *hi, double *hihi); + long (*getPrecision)(const struct link *plink, short *precision); + long (*getUnits)(const struct link *plink, char *units, int unitsSize); + long (*getAlarm)(const struct link *plink, epicsEnum16 *status, + epicsEnum16 *severity); + long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp); + long (*putValue)(struct link *plink, short dbrType, + const void *pbuffer, long nRequest); + void (*scanFwdLink)(struct link *plink); +} lset; + +#define dbGetLink(PLNK, DBRTYPE, PBUFFER, OPTIONS, NREQUEST) \ + ( ( ( (PLNK)->type == CONSTANT ) && \ + ( (NREQUEST) == 0) && \ + ( (OPTIONS) == 0) ) \ + ? 0 \ + : dbGetLinkValue((PLNK),(DBRTYPE), \ + (void *)(PBUFFER), (OPTIONS), (NREQUEST) ) ) + +#define dbPutLink(PLNK, DBRTYPE, PBUFFER, NREQUEST) \ + ( ( (PLNK)->type == CONSTANT) \ + ? 0 \ + : dbPutLinkValue( (PLNK), (DBRTYPE), (void *)(PBUFFER), (NREQUEST) ) ) + +#define dbGetSevr(PLINK, PSEVERITY) \ + dbGetAlarm((PLINK), NULL, (PSEVERITY)); + +epicsShareFunc void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType); +epicsShareFunc void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType); +epicsShareFunc void dbRemoveLink(struct link *plink); +epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements); +epicsShareFunc int dbIsLinkConnected(const struct link *plink); +epicsShareFunc int dbGetLinkDBFtype(const struct link *plink); +epicsShareFunc long dbGetLinkValue(struct link *, short dbrType, void *pbuffer, + long *options, long *nRequest); +epicsShareFunc long dbGetControlLimits(const struct link *plink, double *low, + double *high); +epicsShareFunc long dbGetGraphicLimits(const struct link *plink, double *low, + double *high); +epicsShareFunc long dbGetAlarmLimits(const struct link *plink, double *lolo, + double *low, double *high, double *hihi); +epicsShareFunc long dbGetPrecision(const struct link *plink, short *precision); +epicsShareFunc long dbGetUnits(const struct link *plink, char *units, + int unitsSize); +epicsShareFunc long dbGetAlarm(const struct link *plink, epicsEnum16 *status, + epicsEnum16 *severity); +epicsShareFunc long dbGetTimeStamp(const struct link *plink, + epicsTimeStamp *pstamp); +epicsShareFunc long dbPutLinkValue(struct link *, short dbrType, + const void *pbuffer, long nRequest); +epicsShareFunc void dbScanFwdLink(struct link *plink); + + +#endif /* INC_dbLink_H */ diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index 7cdf69a19..828126e63 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -34,6 +34,7 @@ #include "caeventmask.h" #define epicsExportSharedSymbols #include "dbAccessDefs.h" +#include "dbLink.h" #include "dbNotify.h" #include "dbCa.h" #include "dbEvent.h" diff --git a/src/ioc/dbStatic/link.h b/src/ioc/dbStatic/link.h index c9818f6f0..ef3cfc69d 100644 --- a/src/ioc/dbStatic/link.h +++ b/src/ioc/dbStatic/link.h @@ -1,27 +1,24 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2010 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 Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found +* EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* link.h */ -/* base/include $Revision-Id$ */ +/* $Id$ */ /* - * Original Author: Bob Dalesio - * Current Author: Marty Kraimer - * Date: 6-1-90 + * Original Authors: Bob Dalesio, Marty Kraimer */ +#ifndef INC_link_H +#define INC_link_H + #include "dbDefs.h" #include "shareLib.h" -#ifndef INClinkh -#define INClinkh 1 - #ifdef __cplusplus extern "C" { #endif @@ -55,8 +52,8 @@ epicsShareExtern maplinkType pamaplinkType[]; /* structure of a PV_LINK DB_LINK and a CA_LINK */ /*Options defined by pvlMask */ #define pvlOptMsMode 0x3 /*Maximize Severity mode selection*/ -#define pvlOptNMS 0 /*Dont Maximize Severity*/ -#define pvlOptMS 1 /*Maximize Severity allways*/ +#define pvlOptNMS 0 /*Don't Maximize Severity*/ +#define pvlOptMS 1 /*Maximize Severity always*/ #define pvlOptMSI 2 /*Maximize Severity if INVALID*/ #define pvlOptMSS 3 /*Maximize Severity and copy Status*/ #define pvlOptPP 0x4 /*Process Passive*/ @@ -77,14 +74,15 @@ struct macro_link { }; struct dbCommon; +struct pvlet; struct pv_link { - char *pvname; /*pvname to link to*/ - struct dbCommon *precord; /*Address of record containing link*/ - void *pvt; /*CA or DB private*/ - LINKCVT getCvt; /*input conversion function*/ - short pvlMask; /*Options mask*/ - short lastGetdbrType; /*last dbrType for DB or CA get*/ + char *pvname; /* pvname link points to */ + struct dbCommon *precord; /* Address of record owning link */ + void *pvt; /* CA or DB private */ + LINKCVT getCvt; /* input conversion function */ + short pvlMask; /* Options mask */ + short lastGetdbrType; /* last dbrType for DB or CA get */ }; /* structure of a VME io channel */ @@ -150,13 +148,12 @@ struct bbgpibio { /* structure of an instrument io link */ struct instio { - char *string; /* the cat of location. - signal.parameter */ + char *string; }; /* structure of a vxi link */ struct vxiio{ - short flag; /* 0 = frame/slot, 1 = SA */ + short flag; /* 0 = frame/slot, 1 = SA */ short frame; short slot; short la; /* logical address if flag =1 */ @@ -165,7 +162,7 @@ struct vxiio{ }; /* union of possible address structures */ -union value{ +union value { char *constantStr; /*constant string*/ struct macro_link macro_link; /* link containing macro substitution*/ struct pv_link pv_link; /* link to process variable*/ @@ -180,9 +177,9 @@ union value{ struct vxiio vxiio; /* vxi io */ }; -struct link{ - union value value; - short type; +struct link { + union value value; + short type; char *text; /* original INP/OUT link text */ }; @@ -191,4 +188,4 @@ typedef struct link DBLINK; #ifdef __cplusplus } #endif -#endif /*INClinkh*/ +#endif /* INC_link_H */ diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c index 9f9c1a385..f4e3b7e9e 100644 --- a/src/ioc/misc/iocInit.c +++ b/src/ioc/misc/iocInit.c @@ -41,7 +41,6 @@ #include "taskwd.h" #include "callback.h" #include "dbCommon.h" -#include "dbLock.h" #include "devSup.h" #include "drvSup.h" #include "menuConvert.h" @@ -426,48 +425,18 @@ static void doInitRecord0(dbRecordType *pdbRecordType, dbCommon *precord, static void doResolveLinks(dbRecordType *pdbRecordType, dbCommon *precord, void *user) { + dbFldDes **papFldDes = pdbRecordType->papFldDes; + short *link_ind = pdbRecordType->link_ind; devSup *pdevSup; int j; - /* Convert all PV_LINKs to DB_LINKs or CA_LINKs */ /* For all the links in the record type... */ for (j = 0; j < pdbRecordType->no_links; j++) { - dbFldDes *pdbFldDes = - pdbRecordType->papFldDes[pdbRecordType->link_ind[j]]; + dbFldDes *pdbFldDes = papFldDes[link_ind[j]]; DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset); - if (plink->type == PV_LINK) { - DBADDR dbaddr; - - if (plink == &precord->tsel) recGblTSELwasModified(plink); - if (!(plink->value.pv_link.pvlMask&(pvlOptCA|pvlOptCP|pvlOptCPP)) - && (dbNameToAddr(plink->value.pv_link.pvname,&dbaddr)==0)) { - DBADDR *pdbAddr; - - plink->type = DB_LINK; - pdbAddr = dbCalloc(1,sizeof(struct dbAddr)); - *pdbAddr = dbaddr; /*structure copy*/; - plink->value.pv_link.pvt = pdbAddr; - } else {/*It is a CA link*/ - - if (pdbFldDes->field_type == DBF_INLINK) { - plink->value.pv_link.pvlMask |= pvlOptInpNative; - } - dbCaAddLink(plink); - if (pdbFldDes->field_type == DBF_FWDLINK) { - char *pperiod = - strrchr(plink->value.pv_link.pvname,'.'); - - if (pperiod && strstr(pperiod,"PROC")) { - plink->value.pv_link.pvlMask |= pvlOptFWD; - } else { - errlogPrintf("%s.FLNK is a Channel Access Link " - " but does not link to a PROC field\n", - precord->name); - } - } - } - } + if (plink->type == PV_LINK) + dbInitLink(precord, plink, pdbFldDes->field_type); } pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp); if (pdevSup) {