Extended Device Support interface.

This commit is contained in:
Andrew Johnson
2005-10-31 20:54:10 +00:00
parent 109db70d32
commit 12727edb36
7 changed files with 272 additions and 122 deletions

View File

@@ -13,6 +13,21 @@
<h2 align="center">Changes since 3.14.7</h2>
<h4>Runtime Hardware Address Changes</h4>
<p>An Extended Device Support mechanism has been introduced which is
designed as a safe way to widen the API between iocCore and the device
support software it interfaces with. An extended device support can
now be notified of changes to a record's hardware address, and is
given the chance to approve or reject that change.</p>
<p>As a result of introducing this notification mechanism, any device
support that was capable of handling runtime address changes in prior
versions of Base will have to be updated to provide the new interface,
since the absence of extended device support is now taken to mean that
runtime address changes are not understood by the device support.
This requirement is not expected to affect many EPICS sites.</p>
<h4>POSIX thread priority scheduling</h4>
<p>POSIX thread priority scheduling is now supported. There is a new
user option USE_POSIX_THREAD_PRIORITY_SCHEDULING in the CONFIG_SITE
@@ -32,6 +47,7 @@ should contain location definitions for EPICS modules only.</p>
configure/RELEASE and moved to configure/os/CONFIG_SITE.Common.RTEMS. The
configure/RELEASE* files should contain location definitions for EPICS modules
only.</p>
<h4>event generator and event receiver record support </h3>
All apsEvent specific record support has been removed from base
@@ -51,7 +67,6 @@ of the standard tasks failed. This is because they were passing
their threadid rather than using epicsThreadGetIdSelf.
It was possible to call taskwdInsert before the threadid was actually set.</p>
<h4>dbLock and dbBkpt</h4>
<p>dbLockGetLockId incorrectly always returned 0. dbBkpt (database breakpoint
facility) is the only code that needed this. This caused unknown errors
@@ -63,7 +78,6 @@ if the dbBkpt facility is used.</p>
<h4>epicsExport.h</h4>
<p>Add additional cast to prevent 'strict aliaising' warnings.</p>
<h4>iocsh</h4>
<p>I/O redirection from vxWorks startup scripts now works.</p>
@@ -83,7 +97,6 @@ server required.</p>
<p>Set IOC_NAME and IOC_STARTUP_SCRIPT environment variables from bootstrap
parameters.</p>
<h4>OS X</h4>
<p>Builds on Tiger.</p>
<p>Readline now used by default.</p>

View File

@@ -35,6 +35,7 @@
#include "link.h"
#include "dbFldTypes.h"
#include "recSup.h"
#include "devSup.h"
#include "caeventmask.h"
#include "db_field_log.h"
#include "dbCommon.h"
@@ -1029,6 +1030,188 @@ long epicsShareAPI dbGet(DBADDR *paddr,short dbrType,
return(status);
}
devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *pdbRecordType, int dtyp) {
return (devSup *)ellNth(&pdbRecordType->devList, dtyp+1);
}
devSup* epicsShareAPI dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset) {
devSup *pdevSup = (devSup *)ellFirst(&prdes->devList);
while (pdevSup) {
if (pdset == pdevSup->pdset) return pdevSup;
pdevSup = (devSup *)ellNext(&pdevSup->node);
}
return NULL;
}
static long dbPutFieldLink(
DBADDR *paddr,short dbrType,const void *pbuffer,long nRequest)
{
long status = 0;
long special=paddr->special;
dbCommon *precord = (dbCommon *)(paddr->precord);
DBLINK *plink = (DBLINK *)paddr->pfield;
const char *pstring = (const char *)pbuffer;
DBENTRY dbEntry;
dbFldDes *pfldDes = (dbFldDes *)paddr->pfldDes;
DBADDR dbaddr;
devSup *pdevSup = NULL;
struct dset *new_dset = NULL;
struct dsxt *new_dsxt = NULL;
int inpOut;
short scan;
if ((dbrType!=DBR_STRING) && (dbrType!=DBR_CHAR) && (dbrType!=DBR_UCHAR))
return S_db_badDbrtype;
if (((dbrType==DBR_CHAR) || (dbrType==DBR_UCHAR)) &&
(pstring[nRequest] != '\0'))
return S_db_badField;
dbInitEntry(pdbbase,&dbEntry);
status=dbFindRecord(&dbEntry,precord->name);
if (!status) status=dbFindField(&dbEntry,pfldDes->name);
if (status) return status;
inpOut = !(strcmp(pfldDes->name,"INP") && strcmp(pfldDes->name,"OUT"));
dbLockSetGblLock();
dbLockSetRecordLock(precord);
if (inpOut) {
pdevSup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
if (pdevSup == NULL ||
(new_dset = pdevSup->pdset) == NULL ||
(new_dsxt = pdevSup->pdsxt) == NULL ||
new_dsxt->add_record == NULL ||
(precord->dset &&
((pdevSup = dbDSETtoDevSup(precord->rdes, precord->dset)) == NULL ||
pdevSup->pdsxt == NULL ||
pdevSup->pdsxt->del_record == NULL))) {
status = S_db_noSupport;
goto unlock;
}
}
scan = precord->scan;
if (inpOut && (scan==SCAN_IO_EVENT)) {
scanDelete(precord);
precord->scan = SCAN_PASSIVE;
}
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;
break;
case CONSTANT:
break; /* do nothing */
case PV_LINK:
case MACRO_LINK:
break; /* should never get here */
default: /* Hardware address */
if (!inpOut)
status = S_db_badHWaddr;
else
status = pdevSup->pdsxt->del_record(precord);
if (status) goto restoreScan;
break;
}
if (special) status = putSpecial(paddr,0);
if (!status) status=dbPutString(&dbEntry,pstring);
if (inpOut) {
precord->dset = new_dset;
precord->dpvt = NULL;
precord->pact = FALSE;
}
if (!status && special) status = putSpecial(paddr,1);
if (status) goto restoreScan;
switch (plink->type) { /* New link type */
case PV_LINK:
if (plink==&precord->tsel) recGblTSELwasModified(plink);
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 = dbCalloc(1,sizeof(struct dbAddr));
*pdbAddr = dbaddr; /* NB: structure copy */;
plink->value.pv_link.precord = precord;
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;
plink->value.pv_link.precord = precord;
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;
}
}
break;
case CONSTANT:
break;
case DB_LINK:
case CA_LINK:
case MACRO_LINK:
break; /* should never get here */
default: /* Hardware address */
if (!inpOut)
status = S_db_badHWaddr;
else
status = new_dsxt->add_record(precord);
if (status) {
precord->dset = 0;
precord->pact = TRUE;
goto restoreScan;
}
break;
}
db_post_events(precord,plink,DBE_VALUE|DBE_LOG);
restoreScan:
if (inpOut && (scan==SCAN_IO_EVENT)) { /* undo scanDelete() */
precord->scan = scan;
scanAdd(precord);
}
if (scan != precord->scan)
db_post_events(precord, &precord->scan, DBE_VALUE|DBE_LOG);
unlock:
dbLockSetGblUnlock();
dbFinishEntry(&dbEntry);
return status;
}
long epicsShareAPI dbPutField(
DBADDR *paddr,short dbrType,const void *pbuffer,long nRequest)
{
@@ -1038,107 +1221,17 @@ long epicsShareAPI dbPutField(
dbCommon *precord = (dbCommon *)(paddr->precord);
short dbfType = paddr->field_type;
if(special==SPC_ATTRIBUTE) return(S_db_noMod);
if(special==SPC_ATTRIBUTE)
return S_db_noMod;
/*check for putField disabled*/
if(precord->disp) {
if((void *)(&precord->disp) != paddr->pfield) return(S_db_putDisabled);
}
if(dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) {
DBLINK *plink = (DBLINK *)paddr->pfield;
DBENTRY dbEntry;
dbFldDes *pfldDes = (dbFldDes *)paddr->pfldDes;
char buffer[MAX_STRING_SIZE+2];
int len,j;
char *lastblank;
if (precord->disp &&
(void *)(&precord->disp) != paddr->pfield)
return(S_db_putDisabled);
if(dbrType!=DBR_STRING) return(S_db_badDbrtype);
/*begin kludge for old db_access MAX_STRING_SIZE*/
/*Allow M for MS and (N or NM) for NMS */
if(strlen((char *)pbuffer)>=MAX_STRING_SIZE) {
errlogPrintf("dbPutField input string length >= MAX_STRING_SIZE");
return(S_db_badField);
}
strncpy(buffer,(char *)pbuffer,MAX_STRING_SIZE);
buffer[MAX_STRING_SIZE] = 0;
/*Strip trailing blanks*/
len = strlen(buffer);
for(j=len-1; j>0; j--) {
if(buffer[j]==' ')
buffer[j] = 0;
else
break;
}
lastblank = strrchr(buffer,' ');
if(lastblank) {
if(strcmp(lastblank,"M")==0) {
strcpy(lastblank,"MS");
} else {
if((strcmp(lastblank,"N")==0) || (strcmp(lastblank,"NM")==0)) {
strcpy(lastblank,"NMS");
}
}
}
/*End kludge for old db_access MAX_STRING_SIZE*/
dbLockSetGblLock();
dbLockSetRecordLock(precord);
if((plink->type == DB_LINK)||(plink->type == CA_LINK)) {
if(plink->type == DB_LINK) {
free(plink->value.pv_link.pvt);
plink->value.pv_link.pvt = 0;
plink->type = PV_LINK;
dbLockSetSplit(precord);
} else if(plink->type == CA_LINK) {
dbCaRemoveLink(plink);
}
plink->value.pv_link.getCvt = 0;
plink->value.pv_link.pvlMask = 0;
plink->value.pv_link.lastGetdbrType = 0;
plink->type = PV_LINK;
}
dbInitEntry(pdbbase,&dbEntry);
status=dbFindRecord(&dbEntry,precord->name);
if(!status) status=dbFindField(&dbEntry,pfldDes->name);
if(!status && special) status = putSpecial(paddr,0);
if(!status) status=dbPutString(&dbEntry,buffer);
dbFinishEntry(&dbEntry);
if(!status && special) status = putSpecial(paddr,1);
if(status) goto done;
if(plink->type == PV_LINK) {
DBADDR dbaddr;
if(dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK)
return dbPutFieldLink(paddr,dbrType,pbuffer,nRequest);
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.precord = precord;
plink->value.pv_link.pvt = pdbAddr;
dbLockSetRecordLock(pdbAddr->precord);
dbLockSetMerge(precord,pdbAddr->precord);
} else {/*It is a CA link*/
char *pperiod;
plink->type = CA_LINK;
plink->value.pv_link.precord = precord;
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;
}
}
}
db_post_events(precord,plink,DBE_VALUE|DBE_LOG);
done:
dbLockSetGblUnlock();
return(status);
}
dbScanLock(precord);
status=dbPut(paddr,dbrType,pbuffer,nRequest);
if(status==0){

View File

@@ -184,6 +184,7 @@ struct dbr_alDouble {DBRalDouble};
#define S_db_Blocked (M_dbAccess|39) /*Request is Blocked*/
#define S_db_putDisabled (M_dbAccess|41) /*putFields are disabled*/
#define S_db_badHWaddr (M_dbAccess|43) /*Hardware link type not on INP/OUT*/
#define S_db_bkptSet (M_dbAccess|53) /*Breakpoint already set*/
#define S_db_bkptNotSet (M_dbAccess|55) /*No breakpoint set in record*/
#define S_db_notStopped (M_dbAccess|57) /*Record not stopped*/
@@ -227,6 +228,8 @@ 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(

View File

@@ -41,6 +41,7 @@ typedef struct devSup {
int link_type;
/*Following only available on run time system*/
struct dset *pdset;
struct dsxt *pdsxt; /* Extended device support */
}devSup;
typedef struct dbDeviceMenu {

View File

@@ -3798,6 +3798,7 @@ void epicsShareAPI dbDumpDevice(DBBASE *pdbbase,const char *recordTypeName)
printf("\t choice: %s\n",pdevSup->choice);
printf("\tlink_type: %d\n",pdevSup->link_type);
printf("\t pdset: %p\n",(void *)pdevSup->pdset);
printf("\t pdsxt: %p\n",(void *)pdevSup->pdsxt);
}
if(recordTypeName) break;
}

View File

@@ -27,12 +27,19 @@ typedef long (*DEVSUPFUN)(); /* ptr to device support function*/
typedef struct dset { /* device support entry table */
long number; /*number of support routines*/
DEVSUPFUN report; /*print report*/
DEVSUPFUN init; /*init support*/
DEVSUPFUN init_record; /*init support for particular record*/
DEVSUPFUN init; /*init support layer*/
DEVSUPFUN init_record; /*init device for particular record*/
DEVSUPFUN get_ioint_info; /* get io interrupt information*/
/*other functions are record dependent*/
}dset;
struct dbCommon;
typedef struct dsxt { /* device support extension table */
long (*add_record)(struct dbCommon *precord);
long (*del_record)(struct dbCommon *precord);
/* Recordtypes are *not* allowed to extend this table */
} dsxt;
#define S_dev_noDevSup (M_devSup| 1) /*SDR_DEVSUP: Device support missing*/
#define S_dev_noDSET (M_devSup| 3) /*Missing device support entry table*/
#define S_dev_missingSup (M_devSup| 5) /*Missing device support routine*/
@@ -46,6 +53,12 @@ typedef struct dset { /* device support entry table */
#define S_dev_Conflict (M_devSup|21) /*Multiple records accessing same signal*/
#define S_dev_noDeviceFound (M_devSup|23) /*No device found at specified address*/
/* This routine is defined in src/misc/iocInit.c */
extern void devExtend(dsxt *pdsxt);
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@@ -178,42 +178,62 @@ LOCAL void initRecSup(void)
return;
}
static long do_nothing(struct dbCommon *precord) { return 0; }
/* Dummy DSXT used for soft device supports */
struct dsxt devSoft_DSXT = {
do_nothing,
do_nothing
};
LOCAL devSup *pthisDevSup = NULL;
LOCAL void initDevSup(void)
{
dbRecordType *pdbRecordType;
devSup *pdevSup;
struct dset *pdset;
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup;
pdevSup = (devSup *)ellNext(&pdevSup->node)) {
pdset = registryDeviceSupportFind(pdevSup->name);
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pthisDevSup = (devSup *)ellFirst(&pdbRecordType->devList);
pthisDevSup;
pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) {
pdset = registryDeviceSupportFind(pthisDevSup->name);
if (pdset==0) {
errlogPrintf("device support %s not found\n",pdevSup->name);
errlogPrintf("device support %s not found\n",pthisDevSup->name);
continue;
}
pdevSup->pdset = pdset;
if(pdset->init) (*pdset->init)(0);
if (pthisDevSup->link_type == CONSTANT)
pthisDevSup->pdsxt = &devSoft_DSXT;
pthisDevSup->pdset = pdset;
if (pdset->init) (*pdset->init)(0);
}
}
return;
}
void devExtend(dsxt *pdsxt)
{
if (!pthisDevSup)
errlogPrintf("devExtend() called outside of initDevSup()\n");
else
pthisDevSup->pdsxt = pdsxt;
}
LOCAL void finishDevSup(void)
{
dbRecordType *pdbRecordType;
devSup *pdevSup;
struct dset *pdset;
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup;
pdevSup = (devSup *)ellNext(&pdevSup->node)) {
if(!(pdset = pdevSup->pdset)) continue;
if(pdset->init) (*pdset->init)(1);
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pthisDevSup = (devSup *)ellFirst(&pdbRecordType->devList);
pthisDevSup;
pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) {
pdset = pthisDevSup->pdset;
if (pdset && pdset->init) (*pdset->init)(1);
}
}
@@ -253,7 +273,7 @@ LOCAL void initDatabase(void)
precord->pact=FALSE;
/* Init DSET NOTE that result may be NULL */
pdevSup = (devSup *)ellNth(&pdbRecordType->devList,precord->dtyp+1);
pdevSup = dbDTYPtoDevSup(pdbRecordType,precord->dtyp);
pdset = (pdevSup ? pdevSup->pdset : 0);
precord->dset = pdset;
if(prset->init_record) (*prset->init_record)(precord,0);
@@ -306,6 +326,12 @@ LOCAL void initDatabase(void)
}
}
}
pdevSup = dbDTYPtoDevSup(pdbRecordType,precord->dtyp);
if (pdevSup) {
struct dsxt *pdsxt = pdevSup->pdsxt;
if (pdsxt && pdsxt->add_record)
(*pdsxt->add_record)(precord);
}
}
}