Refactor link handling code (incomplete).

* Moved routines into dbLink.h and dbLink.c
  * Created separate routines for DB_LINK processing
  * Added dbinitLink() and dbAddLink()
  * Started a Link Support Entry Table, not used yet
  * Everything should still work as before...
This commit is contained in:
Michael Davidsaver
2012-04-27 13:21:47 -04:00
parent 06d3397342
commit 74b24bbe0f
12 changed files with 874 additions and 609 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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);

View File

@@ -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"

View File

@@ -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;

View File

@@ -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,

623
src/ioc/db/dbLink.c Normal file
View File

@@ -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 <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#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;
}
}

87
src/ioc/db/dbLink.h Normal file
View File

@@ -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 */

View File

@@ -34,6 +34,7 @@
#include "caeventmask.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbLink.h"
#include "dbNotify.h"
#include "dbCa.h"
#include "dbEvent.h"

View File

@@ -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 */

View File

@@ -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) {