diff --git a/src/db/Makefile.Unix b/src/db/Makefile.Unix index a23dd6af9..5c394a224 100644 --- a/src/db/Makefile.Unix +++ b/src/db/Makefile.Unix @@ -5,6 +5,7 @@ include $(EPICS)/config/CONFIG_BASE INC += drvTS.h INC += drvSup.h INC += callback.h +INC += dbLock.h INC += dbAccess.h INC += dbConvert.h INC += dbEvent.h diff --git a/src/db/Makefile.Vx b/src/db/Makefile.Vx index 1fa8c9f75..fb4df6497 100644 --- a/src/db/Makefile.Vx +++ b/src/db/Makefile.Vx @@ -25,6 +25,7 @@ DBINSTALL += epics.db DBINSTALL += epicsLIBOBJS SRCS.c = \ + ../dbLock.c\ ../dbAccess.c\ ../dbBkpt.c\ ../dbConvert.c\ @@ -40,12 +41,13 @@ SRCS.c = \ ../recGbl.c\ ../callback.c\ ../taskwd.c \ - ../dbCaLink.c\ - ../dbCaDblink.c\ + ../dbCa.c\ + ../dbcal.c\ ../devLib.c\ ../initHooks.c LIBOBJS = \ + dbLock.o\ dbAccess.o\ dbBkpt.o\ dbConvert.o\ @@ -61,8 +63,8 @@ LIBOBJS = \ recGbl.o\ callback.o\ taskwd.o\ - dbCaLink.o \ - dbCaDblink.o\ + dbCa.o \ + dbcal.o \ devLib.o PROD = initHooks.o diff --git a/src/db/callback.c b/src/db/callback.c index 55e0ad10c..8fc4afb6d 100644 --- a/src/db/callback.c +++ b/src/db/callback.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #define QUEUESIZE 1000 @@ -129,9 +130,11 @@ void callbackRequest(CALLBACK *pcallback) } } +static char *priorityName[3] = {"Low","Medium","High"}; static void start(int ind) { int priority; + char taskName[20]; if((callbackSem[ind] = semBCreate(SEM_Q_FIFO,SEM_EMPTY))==NULL) errMessage(0,"semBcreate failed while starting a callback task\n"); @@ -144,7 +147,8 @@ static void start(int ind) } if((callbackQ[ind] = rngCreate(sizeof(CALLBACK *) * QUEUESIZE)) == NULL) errMessage(0,"rngCreate failed while starting a callback task"); - callbackTaskId[ind] = taskSpawn(CALLBACK_NAME,priority, + sprintf(taskName,"cb%s",priorityName[ind]); + callbackTaskId[ind] = taskSpawn(taskName,priority, CALLBACK_OPT,CALLBACK_STACK, (FUNCPTR)callbackTask,ind, 0,0,0,0,0,0,0,0,0); diff --git a/src/db/dbAccess.c b/src/db/dbAccess.c index 130300063..96aae52a1 100644 --- a/src/db/dbAccess.c +++ b/src/db/dbAccess.c @@ -54,7 +54,6 @@ #include -#include #include #include #include @@ -74,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -90,7 +90,7 @@ static short mapDBFToDBR[DBF_NTYPES] = { DBR_STRING, DBR_CHAR, DBR_UCHAR, DBR_SHORT, DBR_USHORT, DBR_LONG, DBR_ULONG, DBR_FLOAT, DBR_DOUBLE, DBR_ENUM, DBR_ENUM, DBR_ENUM, - DBR_NOACCESS, DBR_NOACCESS, DBR_NOACCESS, DBR_NOACCESS + DBR_STRING, DBR_STRING, DBR_STRING, DBR_NOACCESS }; /* @@ -100,500 +100,39 @@ static short mapDBFToDBR[DBF_NTYPES] = { * that flag becomes unset. */ #define MAX_LOCK 10 - -/* - * The lock structure for each database lock set. A lockset is the - * connected graph of all adjacent nodes to a record (with one - * exception, single-valued NPP NMS gets), where adjacent is defined - * as a record connected by a get, put, or forward link to the current - * record. - */ -struct scanLock { - FAST_LOCK lock; - void *precord; - ULONG start_time; - int task_id; -}; - -static struct { - int nset; /* Number of sets */ - struct scanLock *pscanLock; /*addr of array of struct scanLock */ -} dbScanPvt; -struct rset *dbGetRset(struct dbAddr *paddr) +static long putSpecial(DBADDR *paddr,int pass) { - return(((struct dbFldDes *)paddr->pfldDes)->pdbRecDes->prset); -} - -int dbIsValueField(struct dbFldDes *pdbFldDes) -{ - if(pdbFldDes->pdbRecDes->indvalFlddes == pdbFldDes->indRecDes) - return(TRUE); - else - return(FALSE); -} - -int dbGetFieldIndex(struct dbAddr *paddr) -{ - return(((struct dbFldDes *)paddr->pfldDes)->indRecDes); -} - -/* - * Initialize the record's dbCommon structure. - * dbCommon is the set of all fields that are - * common to all record types. These fields serve - * as a header to each record's structure. - */ -long dbCommonInit(dbCommon *precord, int pass) -{ - long status; - - if (pass == 0) - return(0); - - /* - * Init 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 = recGblInitFastInLink(&(precord->sdis), - (void *) precord, DBR_SHORT, "DISA"); - if (status) - recGblRecordError(status, (void *) precord, "dbCommonInit: SDIS"); - /* - * Initialize the time stamp link. - */ - status = recGblInitFastInLink(&(precord->tsel), - (void *) precord, DBR_SHORT, "TSE"); - - if (status) - recGblRecordError(status, (void *)precord, "dbCommonInit: TSEL"); - + long int (*pspecial)()=NULL; + struct rset *prset; + dbCommon *precord=(dbCommon *)(paddr->precord); + long status=0; + long special=paddr->special; + + prset = dbGetRset(paddr); + if(special<100) { /*global processing*/ + if((special==SPC_NOMOD) && (pass==0)) { + status = S_db_noMod; + recGblDbaddrError(status,paddr,"dbPut"); + return(status); + }else if(special==SPC_SCAN){ + if(pass==0) + scanDelete(precord); + else + scanAdd(precord); + }else if((special==SPC_AS) && (pass==1)) { + asChangeGroup((ASMEMBERPVT *)&precord->asp,precord->asg); + } + }else { + if( prset && (pspecial = (prset->special))) { + status=(*pspecial)(paddr,pass); + if(status) return(status); + } else if(pass==0){ + recGblRecSupError(S_db_noSupport,paddr,"dbPut", "special"); + return(S_db_noSupport); + } + } return(0); -} /* end dbCommonInit() */ - -void dbScanLock(dbCommon *precord) -{ - struct scanLock *pscanLock; - short lset=((dbCommon *)precord)->lset - 1; - - /* Move range check to iocInit */ - if(lset < 0 || lset >= dbScanPvt.nset) { - errMessage(S_db_badLset, "Lock Set out of range:dbScanLock"); - taskSuspend(taskIdSelf()); - } - pscanLock = dbScanPvt.pscanLock + lset; - FASTLOCK(&pscanLock->lock); - pscanLock->start_time = tickGet(); - pscanLock->task_id = taskIdSelf(); - pscanLock->precord = (void *)precord; - return; -} - -void dbScanUnlock(dbCommon *precord) -{ - struct scanLock *pscanLock; - short lset=((dbCommon *)precord)->lset - 1; - - /* Put check in iocInit() */ - if(lset<0 || lset>=dbScanPvt.nset) { - errMessage(S_db_badLset,"Lock Set out of range:dbScanUnlock"); - taskSuspend(taskIdSelf()); - } - pscanLock = dbScanPvt.pscanLock + lset; - pscanLock->precord = NULL; - FASTUNLOCK(&pscanLock->lock); - return; -} - -void dbScanLockInit(int nset) -{ - struct scanLock *pscanLock; - int i; - - dbScanPvt.nset = nset; - - /* - * Allocate one scan lock structure for each - * lockset in the database. - */ - pscanLock = calloc((size_t)nset, (size_t)sizeof(struct scanLock)); - - dbScanPvt.pscanLock = pscanLock; - - /* - * Initialize scan lock structure for - * all locksets. This includes - * initializing the FASTLOCK semaphore. - */ - for (i=0; ilock); - pscanLock->precord=NULL; - pscanLock->start_time=0; - pscanLock->task_id=0; - } - return; -} - -/* - * Process a record if its scan field is passive. - * Will notify if processing is complete by callback. - * (only if you are interested in completion) - */ -long dbScanPassive(dbCommon *pfrom, dbCommon *pto) -{ - long status; - - /* if not passive just return success */ - 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 dbScanLink(dbCommon *pfrom, dbCommon *pto) -{ - long status; - - if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto); - status = dbProcess(pto); - return(status); -} - -/* - * Process the record. - * 1. Check for breakpoints. - * 2. Check the process active flag (PACT). - * 3. Check the disable link. - * 4. Check the RSET (record support entry table) exists. - * 5. Run the process routine specific to the record type. - * 6. Check to see if record contents should be automatically printed. - */ -long dbProcess(dbCommon *precord) -{ - struct rset *prset; - unsigned char tpro=precord->tpro; - short lset = precord->lset; - long status = 0; - static char trace=0; - static int trace_lset=0; - int set_trace=FALSE; - - /* - * 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_not_empty) { - /* - * 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 (vxTas(&trace)) { - trace_lset = lset; - set_trace = TRUE; - } - } - - /* If already active dont process */ - if (precord->pact) { - struct rset *prset; - struct valueDes valueDes; - unsigned short monitor_mask; - - if (trace && trace_lset==lset) - printf("active: %s\n",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; - prset=(struct rset *)precord->rset; - - if (prset && prset->get_value) { - (*prset->get_value)(precord, &valueDes); - db_post_events(precord, valueDes.pvalue, 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 = recGblGetFastLink(&(precord->sdis), - (void *)precord, &(precord->disa)); - - /* if disabled check disable alarm severity and return success */ - if (precord->disa == precord->disv) { - struct valueDes valueDes; - - if (trace && trace_lset==lset) - printf("disabled: %s\n",precord->name); - - /*take care of caching and notifyCompletion*/ - precord->rpro = FALSE; - if (precord->ppn) - dbNotifyCompletion(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; - - /* anyone waiting for an event on this record?*/ - if (precord->mlis.count == 0) - goto all_done; - - db_post_events(precord, &precord->stat, DBE_VALUE); - db_post_events(precord, &precord->sevr, DBE_VALUE); - prset=(struct rset *)precord->rset; - - if (prset && prset->get_value) { - (*prset->get_value)(precord, &valueDes); - db_post_events(precord, valueDes.pvalue, DBE_VALUE|DBE_ALARM); - } - goto all_done; - } - - /* locate record processing routine */ - /* put this in iocInit() !!! */ - if (!(prset=(struct rset *)precord->rset) || !(prset->process)) { - precord->pact=1;/*set pact TRUE so error is issued only once*/ - recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess"); - status = S_db_noRSET; - if (trace && trace_lset == lset) - printf("failure: %s\n", precord->name); - - goto all_done; - } - - if (trace && trace_lset==lset) - printf("process: %s\n", precord->name); - - /* process record */ - status = (*prset->process)(precord); - - /* - * Print record's fields if PRINT_MASK set in breakpoint field - */ - if (lset_stack_not_empty) { - dbPrint(precord); - } - -all_done: - if (set_trace) { - trace_lset = 0; - trace = 0; - } - - return(status); -} - -/* - * Fill out a database structure (*paddr) for - * a record given by the name "pname." - * - * Returns error codes from StaticLib module, not - * from dbAccess. - */ -long dbNameToAddr(char *pname,DBADDR *paddr) -{ - DBENTRY dbEntry; - long status=0; - struct rset *prset; - dbFldDes *pflddes; - - dbInitEntry(pdbbase,&dbEntry); - if(status = dbFindRecord(&dbEntry,pname)) return(status); - paddr->precord = dbEntry.precnode->precord; - if(!dbEntry.pfield) { - if(status=dbFindField(&dbEntry,"VAL"))return(status); - } - paddr->pfield = dbEntry.pfield; - pflddes = dbEntry.pflddes; - paddr->pfldDes = (void *)pflddes; - paddr->field_type = pflddes->field_type; - paddr->dbr_field_type = mapDBFToDBR[pflddes->field_type]; - paddr->field_size = pflddes->size; - paddr->special = pflddes->special; - - /*if special is SPC_DBADDR then call cvt_dbaddr */ - /*it may change pfield,no_elements,field_type,dbr_field_type,*/ - /*field_size,and special*/ - paddr->no_elements=1; - if( ((paddr->special)==SPC_DBADDR) - && (prset=dbGetRset(paddr)) - && (prset->cvt_dbaddr) ) - status = (*prset->cvt_dbaddr)(paddr); - - return(status); -} - -long dbValueSize( - short dbr_type -) -{ - /* sizes for value associated with each DBR request type */ - static long size[] = { - MAX_STRING_SIZE, /* STRING */ - sizeof(char), /* CHAR */ - sizeof(unsigned char), /* UCHAR */ - sizeof(short), /* SHORT */ - sizeof(unsigned short), /* USHORT */ - sizeof(long), /* LONG */ - sizeof(unsigned long), /* ULONG */ - sizeof(float), /* FLOAT */ - sizeof(double), /* DOUBLE */ - sizeof(unsigned short)}; /* ENUM */ - - return(size[dbr_type]); -} - -long dbBufferSize( - short dbr_type, - long options, - long no_elements -) -{ - long nbytes=0; - - nbytes += dbValueSize(dbr_type) * no_elements; - if(options & DBR_STATUS) nbytes += dbr_status_size; - if(options & DBR_UNITS) nbytes += dbr_units_size; - if(options & DBR_PRECISION) nbytes += dbr_precision_size; - if(options & DBR_TIME) nbytes += dbr_time_size; - if(options & DBR_ENUM_STRS) nbytes += dbr_enumStrs_size; - if(options & DBR_GR_LONG) nbytes += dbr_grLong_size; - if(options & DBR_GR_DOUBLE) nbytes += dbr_grDouble_size; - if(options & DBR_CTRL_LONG) nbytes += dbr_ctrlLong_size; - if(options & DBR_CTRL_DOUBLE)nbytes += dbr_ctrlDouble_size; - if(options & DBR_AL_LONG) nbytes += dbr_alLong_size; - if(options & DBR_AL_DOUBLE) nbytes += dbr_alDouble_size; - return(nbytes); -} - -/* - * Get value through fast input link. - * - * 1. Check for and call channel access routine instead if appropriate - * 2. Set PACT flag - * 3. Process record if process passive field set - * 4. Maximize severity through the link if flag set - * 5. Reset PACT flag - */ -long dbFastLinkGet( - struct link *plink, - dbCommon *precord, - void *pdest) -{ - long status = 0; - char pact = precord->pact; - - precord->pact = TRUE; - - /* - * Test for CA_LINK - */ - if (plink->type == CA_LINK) { - status = dbCaGetLink(plink); - } - else { - struct db_link *pdb_link = &(plink->value.db_link); - DBADDR *pdb_addr = (DBADDR *) (pdb_link->pdbAddr); - - if (pdb_link->process_passive) { - status = dbScanPassive(precord, pdb_addr->precord); - - if (status) { - precord->pact = pact; - return(status); - } - } - - if (pdb_link->maximize_sevr) { - recGblSetSevr(precord, LINK_ALARM, pdb_addr->precord->sevr); - } - - /* - * Call conversion routine - */ - status = (*(pdb_link->conversion))(pdb_addr->pfield, pdest, pdb_addr); - } - - precord->pact = pact; - return(status); -} - -long dbGetField( -DBADDR *paddr, -short dbrType, -void *pbuffer, -long *options, -long *nRequest, -void *pflin -) -{ - dbCommon *precord = (dbCommon *)(paddr->precord); - long status; - - dbScanLock(precord); - status = dbGet(paddr,dbrType,pbuffer,options,nRequest,pflin); - dbScanUnlock(precord); - return(status); -} - -long dbGetLink( - struct db_link *pdblink, - dbCommon *pdest, - short dbrType, - void *pbuffer, - long *options, - long *nRequest -) -{ - DBADDR *paddr=(DBADDR*)(pdblink->pdbAddr); - dbCommon *psource=paddr->precord; - long status; - - if(pdblink->process_passive && psource->scan==0) { - status=dbScanPassive(pdest,psource); - if(status) return(status); - } - if(pdblink->maximize_sevr) recGblSetSevr(pdest,LINK_ALARM,psource->sevr); - - status= dbGet(paddr,dbrType,pbuffer,options,nRequest,NULL); - if(status) recGblRecordError(status,(void *)pdest,"dbGetLink"); - return(status); } static void get_enum_strs(DBADDR *paddr,void **ppbuffer, @@ -773,30 +312,16 @@ static void get_alarm(DBADDR *paddr,void **ppbuffer, return; } -long dbGet( -DBADDR *paddr, -short dbrType, -void *pbuffer, -long *options, -long *nRequest, -void *pflin -) +static void getOptions(DBADDR *paddr,void **poriginal,long *options,void *pflin) { db_field_log *pfl= (db_field_log *)pflin; - long no_elements=paddr->no_elements; - long offset; struct rset *prset; short field_type=paddr->field_type; - long (*pconvert_routine)(); - dbCommon *pcommon; - long status; - long *perr_status=NULL; + dbCommon *pcommon; + void *pbuffer = *poriginal; prset=dbGetRset(paddr); - - if(!(*options)) goto GET_DATA; - /* Process options */ pcommon = (dbCommon *)(paddr->precord); if( (*options) & DBR_STATUS ) { @@ -809,11 +334,11 @@ void *pflin } *((unsigned short *)pbuffer)++ = pcommon->acks; *((unsigned short *)pbuffer)++ = pcommon->ackt; - *perr_status = 0; } if( (*options) & DBR_UNITS ) { if( prset && prset->get_units ){ char * pchar = (char *)pbuffer; + (*prset->get_units)(paddr,pchar); pchar[DB_UNITS_SIZE-1] = '\0'; } else { @@ -823,15 +348,18 @@ void *pflin pbuffer = (char *)pbuffer + dbr_units_size; } if( (*options) & DBR_PRECISION ) { - struct dbr_precision *pdbr_precision=( struct dbr_precision *)pbuffer; + struct dbr_precision *pdbr_precision= + (struct dbr_precision *)pbuffer; - if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE) && prset && prset->get_precision ){ + if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE) + && prset && prset->get_precision ){ (*prset->get_precision)(paddr,pbuffer); if(pdbr_precision->field_width<=0) - pdbr_precision->field_width = pdbr_precision->precision + 5; + pdbr_precision->field_width = + pdbr_precision->precision + 5; } else { memset(pbuffer,'\0',dbr_precision_size); - *options = (*options) ^ DBR_PRECISION; /*Turn off DBR_PRECISION*/ + *options = (*options)^DBR_PRECISION; /*Turn off DBR_PRECISION*/ } pbuffer = (char *)pbuffer + dbr_precision_size; } @@ -844,237 +372,612 @@ void *pflin *((unsigned long *)pbuffer)++ = pcommon->time.nsec; } } - if( (*options) & DBR_ENUM_STRS ) get_enum_strs(paddr,&pbuffer,prset,options); + if( (*options) & DBR_ENUM_STRS ) + get_enum_strs(paddr,&pbuffer,prset,options); if( (*options) & (DBR_GR_LONG|DBR_GR_DOUBLE )) get_graphics(paddr,&pbuffer,prset,options); if((*options) & (DBR_CTRL_LONG | DBR_CTRL_DOUBLE )) get_control(paddr,&pbuffer,prset,options); if((*options) & (DBR_AL_LONG | DBR_AL_DOUBLE )) get_alarm(paddr,&pbuffer,prset,options); + *poriginal = pbuffer; +} + +struct rset *dbGetRset(struct dbAddr *paddr) +{ + return(((struct dbFldDes *)paddr->pfldDes)->pdbRecDes->prset); +} + +int dbIsValueField(struct dbFldDes *pdbFldDes) +{ + if(pdbFldDes->pdbRecDes->indvalFlddes == pdbFldDes->indRecDes) + return(TRUE); + else + return(FALSE); +} + +int dbGetFieldIndex(struct dbAddr *paddr) +{ + return(((struct dbFldDes *)paddr->pfldDes)->indRecDes); +} -GET_DATA: +/* + * Process a record if its scan field is passive. + * Will notify if processing is complete by callback. + * (only if you are interested in completion) + */ +long dbScanPassive(dbCommon *pfrom, dbCommon *pto) +{ + long status; + + /* if not passive just return success */ + if(pto->scan != 0) return(0); - if(*nRequest==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 dbScanLink(dbCommon *pfrom, dbCommon *pto) +{ + long status; + + if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto); + status = dbProcess(pto); + return(status); +} + +/* + * Process the record. + * 1. Check for breakpoints. + * 2. Check the process active flag (PACT). + * 3. Check the disable link. + * 4. Check the RSET (record support entry table) exists. + * 5. Run the process routine specific to the record type. + * 6. Check to see if record contents should be automatically printed. + */ +long dbProcess(dbCommon *precord) +{ + struct rset *prset = (struct rset *)precord->rset; + dbRecDes *pdbRecDes = (dbRecDes *)precord->rdes; + unsigned char tpro=precord->tpro; + unsigned long lset; + long status = 0; + static char trace=0; + static unsigned long trace_lset=0; + int set_trace=FALSE; + dbFldDes *pdbFldDes; + + lset = dbLockGetLockId(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_not_empty) { + /* + * 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 (vxTas(&trace)) { + trace_lset = lset; + set_trace = TRUE; + } + } + + /* If already active dont process */ + if (precord->pact) { + unsigned short monitor_mask; + + if (trace && trace_lset==lset) + printf("active: %s\n",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; + pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->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); + + /* if disabled check disable alarm severity and return success */ + if (precord->disa == precord->disv) { + if (trace && trace_lset==lset) + printf("disabled: %s\n",precord->name); + + /*take care of caching and notifyCompletion*/ + precord->rpro = FALSE; + if (precord->ppn) dbNotifyCompletion(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 = pdbRecDes->papFldDes[pdbRecDes->indvalFlddes]; + db_post_events(precord, + (void *)(((char *)precord) + pdbFldDes->offset), + DBE_VALUE|DBE_ALARM); + goto all_done; + } + + /* locate record processing routine */ + /* put this in iocInit() !!! */ + if (!(prset=(struct rset *)precord->rset) || !(prset->process)) { + precord->pact=1;/*set pact TRUE so error is issued only once*/ + recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess"); + status = S_db_noRSET; + if (trace && trace_lset == lset) + printf("failure: %s\n", precord->name); + + goto all_done; + } + if (trace && trace_lset==lset) printf("process: %s\n", precord->name); + /* process record */ + status = (*prset->process)(precord); + /* Print record's fields if PRINT_MASK set in breakpoint field */ + if (lset_stack_not_empty) { + dbPrint(precord); + } +all_done: + if (set_trace) { + trace_lset = 0; + trace = 0; + } + return(status); +} + +/* + * Fill out a database structure (*paddr) for + * a record given by the name "pname." + * + * Returns error codes from StaticLib module, not + * from dbAccess. + */ +long dbNameToAddr(char *pname,DBADDR *paddr) +{ + DBENTRY dbEntry; + long status=0; + struct rset *prset; + dbFldDes *pflddes; + + dbInitEntry(pdbbase,&dbEntry); + if(status = dbFindRecord(&dbEntry,pname)) return(status); + paddr->precord = dbEntry.precnode->precord; + if(!dbEntry.pfield) { + if(status=dbFindField(&dbEntry,"VAL"))return(status); + } + paddr->pfield = dbEntry.pfield; + pflddes = dbEntry.pflddes; + paddr->pfldDes = (void *)pflddes; + paddr->field_type = pflddes->field_type; + paddr->dbr_field_type = mapDBFToDBR[pflddes->field_type]; + paddr->field_size = pflddes->size; + paddr->special = pflddes->special; + + /*if special is SPC_DBADDR then call cvt_dbaddr */ + /*it may change pfield,no_elements,field_type,dbr_field_type,*/ + /*field_size,and special*/ + paddr->no_elements=1; + if(((paddr->special)==SPC_DBADDR) + && (prset=dbGetRset(paddr)) + && (prset->cvt_dbaddr)) status = (*prset->cvt_dbaddr)(paddr); + return(status); +} + +long dbValueSize( + short dbr_type +) +{ + /* sizes for value associated with each DBR request type */ + static long size[] = { + MAX_STRING_SIZE, /* STRING */ + sizeof(char), /* CHAR */ + sizeof(unsigned char), /* UCHAR */ + sizeof(short), /* SHORT */ + sizeof(unsigned short), /* USHORT */ + sizeof(long), /* LONG */ + sizeof(unsigned long), /* ULONG */ + sizeof(float), /* FLOAT */ + sizeof(double), /* DOUBLE */ + sizeof(unsigned short)}; /* ENUM */ + + return(size[dbr_type]); +} + + +long dbBufferSize( + short dbr_type, + long options, + long no_elements +) +{ + long nbytes=0; + + nbytes += dbValueSize(dbr_type) * no_elements; + if(options & DBR_STATUS) nbytes += dbr_status_size; + if(options & DBR_UNITS) nbytes += dbr_units_size; + if(options & DBR_PRECISION) nbytes += dbr_precision_size; + if(options & DBR_TIME) nbytes += dbr_time_size; + if(options & DBR_ENUM_STRS) nbytes += dbr_enumStrs_size; + if(options & DBR_GR_LONG) nbytes += dbr_grLong_size; + if(options & DBR_GR_DOUBLE) nbytes += dbr_grDouble_size; + if(options & DBR_CTRL_LONG) nbytes += dbr_ctrlLong_size; + if(options & DBR_CTRL_DOUBLE)nbytes += dbr_ctrlDouble_size; + if(options & DBR_AL_LONG) nbytes += dbr_alLong_size; + if(options & DBR_AL_DOUBLE) nbytes += dbr_alDouble_size; + return(nbytes); +} + +long 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) { + dbCommon *precord = plink->value.pv_link.precord; + struct pv_link *ppv_link = &(plink->value.pv_link); + DBADDR *paddr = ppv_link->pvt; + + /* 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(ppv_link->pvlMask&pvlOptMS) + recGblSetSevr(precord,LINK_ALARM,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,(void *)precord,"GetLinkValue"); + recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM); + return(status); + } + /* attempt to make a fast link */ + if((!poptions || (*poptions == 0)) + && (no_elements == 1) + && (!pnRequest || (*pnRequest == 1))) { + ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType]; + status = (*ppv_link->getCvt) (paddr->pfield,pbuffer, paddr); + }else{ + status=dbGet(paddr,dbrType,pbuffer,poptions,pnRequest,NULL); + ppv_link->getCvt = 0; + } + } + ppv_link->lastGetdbrType = dbrType; + if(status){ + recGblRecordError(status,(void *)precord,"dbGetLinkValue"); + recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM); + } + }else if(plink->type==CA_LINK) { + struct dbCommon *precord = plink->value.pv_link.precord; + struct pv_link *pcalink = &(plink->value.pv_link); + unsigned short sevr; + + status=dbCaGetLink(plink,dbrType,pbuffer,&sevr,pnRequest); + if(status) { + recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM); + }else if(pcalink->pvlMask&pvlOptMS){ + recGblSetSevr(precord,LINK_ALARM,sevr); + } + if(poptions) *poptions = 0; + } else { + status = -1; + errMessage(-1,"dbGetLinkValue: Illegal link type"); + taskSuspend(0); + } + return(status); +} + +long dbPutLinkValue(struct link *plink,short dbrType, + 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); + if(ppv_link->pvlMask&pvlOptMS) + recGblSetSevr(pdest,LINK_ALARM,psource->sevr); + if(status) return(status); + if((paddr->pfield==(void *)&pdest->proc) + || (ppv_link->pvlMask&pvlOptPP && pdest->scan==0)) { + /*Note:If ppn then dbNotifyCancel will reprocess*/ + /*if dbPutField caused asyn record to process */ + /* ask for reprocessing*/ + if(!psource->ppn && pdest->putf) pdest->rpro = TRUE; + /* otherwise ask for the record to be processed*/ + else 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 { + status=-1; + errMessage(-1,"dbPutLinkValue: Illegal link type"); + taskSuspend(0); + } + return(status); +} + +long dbGetField( DBADDR *paddr,short dbrType,void *pbuffer, + long *options,long *nRequest,void *pflin) +{ + dbCommon *precord = (dbCommon *)(paddr->precord); + long status = 0; + short dbfType = paddr->field_type; + + dbScanLock(precord); + if(dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) { + DBENTRY dbEntry; + dbFldDes *pfldDes = (dbFldDes *)paddr->pfldDes; + char *rtnString; + char *pbuf = (char *)pbuffer; + + if(dbrType!=DBR_STRING) { + status = S_db_badDbrtype; + goto done; + } + if(options && (*options)) + getOptions(paddr,(void **)&pbuf,options,pflin); + dbInitEntry(pdbbase,&dbEntry); + if(status = dbFindRecord(&dbEntry,precord->name)) goto done; + if(status = dbFindField(&dbEntry,pfldDes->name)) goto done; + rtnString = dbGetString(&dbEntry); + /*begin kludge for old db_access MAX_STRING_SIZE*/ + if(strlen(rtnString)>=MAX_STRING_SIZE) { + strncpy(pbuf,rtnString,MAX_STRING_SIZE-1); + pbuf[MAX_STRING_SIZE-1] = 0; + } else { + strcpy(pbuf,rtnString); + } + /*end kludge for old db_access MAX_STRING_SIZE*/ + dbFinishEntry(&dbEntry); + goto done; + + } else { + status = dbGet(paddr,dbrType,pbuffer,options,nRequest,pflin); + } +done: + dbScanUnlock(precord); + return(status); +} + +long dbGet(DBADDR *paddr,short dbrType,void *pbuffer,long *options, + long *nRequest,void *pflin) +{ + db_field_log *pfl= (db_field_log *)pflin; + long no_elements=paddr->no_elements; + long offset; + struct rset *prset; + short field_type=paddr->field_type; + long (*pconvert_routine)(); + long status = 0; + char message[80]; + + + prset=dbGetRset(paddr); + if(options && (*options)) { + void *pbuf = pbuffer; + + getOptions(paddr,&pbuf,options,pflin); + pbuffer = pbuf; + } + if(nRequest && *nRequest==0) return(0); /* Check for valid request */ if( INVALID_DB_REQ(dbrType) || (field_type>DBF_DEVICE) ){ - char message[80]; - sprintf(message,"dbGet - database request type is %d",dbrType); recGblDbaddrError(S_db_badDbrtype,paddr,message); - if(perr_status) *perr_status = S_db_badDbrtype; return(S_db_badDbrtype); } - /* check for array */ if( no_elements>1 && prset && (prset->get_array_info) ) { status = (*prset->get_array_info)(paddr,&no_elements,&offset); } else offset=0; - if(no_elements<(*nRequest)) *nRequest = no_elements; - if(!(pconvert_routine=dbGetConvertRoutine[field_type][dbrType])) { - char message[80]; + if(offset==0 && (!nRequest || no_elements==1)) { + if(nRequest) *nRequest = 1; + if(pfl!=NULL) { + DBADDR localAddr; - sprintf(message,"dbGet - database request type is %d",dbrType); - recGblDbaddrError(S_db_badDbrtype,paddr,message); - if(perr_status) *perr_status = S_db_badDbrtype; - return(S_db_badDbrtype); - } - /* convert database field to buffer type and place it in the buffer */ - if(pfl!=NULL) { - DBADDR localAddr; - - memcpy(&localAddr,paddr,sizeof(localAddr)); - /*Use longest field size*/ - localAddr.pfield = (char *)&pfl->field; - status=(*pconvert_routine)(&localAddr,pbuffer,*nRequest, - no_elements,offset); + localAddr = *paddr; /*Structure copy*/ + localAddr.pfield = (char *)&pfl->field; + status = (*dbFastGetConvertRoutine[field_type][dbrType]) + (localAddr.pfield,pbuffer, &localAddr); + } else { + status = (*dbFastGetConvertRoutine[field_type][dbrType]) + (paddr->pfield,pbuffer, paddr); + } } else { - status=(*pconvert_routine)(paddr,pbuffer,*nRequest, - no_elements,offset); + long n; + + if(nRequest) { + if(no_elements<(*nRequest)) *nRequest = no_elements; + n = no_elements; + } else { + n = 1; + } + pconvert_routine=dbGetConvertRoutine[field_type][dbrType]; + if(!pconvert_routine) { + sprintf(message,"dbGet - database request type is %d", + dbrType); + recGblDbaddrError(S_db_badDbrtype,paddr,message); + return(S_db_badDbrtype); + } + /* convert database field and place it in the buffer */ + if(pfl!=NULL) { + DBADDR localAddr; + + localAddr = *paddr; /*Structure copy*/ + localAddr.pfield = (char *)&pfl->field; + status=(*pconvert_routine)(&localAddr,pbuffer,n, + no_elements,offset); + } else { + status=(*pconvert_routine)(paddr,pbuffer,n, + no_elements,offset); + } } - if(perr_status) *perr_status = status; return(status); } -/* - * Put value through fast link - * - * 1. Check for and call channel access routine instead if appropriate - * 2. Set PACT flag - * 3. Propagate Maximize severity - * 4. Check if put was made to force processing field - * 5. Process record if process passive field set - * 6. Check field for special processing - * - * pl_record stands for pointer to local record. - * pr_record stands for pointer to remote record. - */ -long dbFastLinkPut(struct link *plink,dbCommon *pl_record,void *psource) +long dbPutField(DBADDR *paddr,short dbrType,void *pbuffer,long nRequest) { - long status = 0; - char pact = pl_record->pact; - - pl_record->pact = TRUE; - - /* - * Check for CA Link - */ - if (plink->type == CA_LINK) { - long options = 0; - long nRequest = 1; - - dbCaPutLink(plink, &options, &nRequest); - } - else { - struct db_link *pdb_link = &(plink->value.db_link); - DBADDR *paddr = (DBADDR *) (pdb_link->pdbAddr); - dbCommon *pdest = (dbCommon *) paddr->precord; - dbFldDes *pfldDes = (dbFldDes *) (paddr->pfldDes); - long special = paddr->special; - struct rset *prset; - int isValueField; - long int (*pspecial)() = NULL; - - prset = dbGetRset(paddr); - - if (special) { - if (special < 100) { - if (special == SPC_NOMOD) { - recGblDbaddrError(S_db_noMod,paddr,"dbPut"); - pl_record->pact = pact; - return(S_db_noMod); - } - else { - if (special == SPC_SCAN) { - scanDelete(pdest); - } - } - } - else { - if (prset && (pspecial = (prset->special))) { - status = (*pspecial)(paddr, 0); - if (status) { - pl_record->pact = pact; - return(status); - } - } - else { - recGblRecSupError(S_db_noSupport, paddr, "dbPut", "special"); - pl_record->pact = pact; - return(S_db_noSupport); - } - } - } - - /* - * Call conversion routine - */ - status = (*(pdb_link->conversion))(psource, paddr->pfield, paddr); - - if (status) { - pl_record->pact = pact; - return(status); - } - - /* - * Check for special processing - */ - if (special) { - if (special < 100) { /*global processing*/ - if (special == SPC_SCAN) { - scanAdd(pdest); - } - else if (special == SPC_AS) { - asChangeGroup((ASMEMBERPVT *)&pdest->asp, pdest->asg); - } - } - else { - status = (*pspecial)(paddr, 1); - if (status) { - pl_record->pact = pact; - return(status); - } - } - } - - /* - * Propagate events for this field - * if the field is VAL and process_passive is true - * don't propagate. - */ - - isValueField = dbIsValueField(pfldDes); - if (isValueField) pdest->udf=FALSE; - if(pdest->mlis.count && - (!isValueField || (!pfldDes->process_passive))) - db_post_events(pdest,paddr->pfield,DBE_VALUE); - - if (pdb_link->maximize_sevr) { - recGblSetSevr(pdest, LINK_ALARM, pl_record->sevr); - } - - if ((paddr->pfield == (void *) &pdest->proc) || - (pdb_link->process_passive && pdest->scan == 0)) { - - /* - * Note: If ppn then dbNotifyCancel will handle reprocessing - * if dbPutField caused asyn record to process ask for reprocessing - */ - if (!pl_record->ppn && pdest->putf) - pdest->rpro = TRUE; - - /* otherwise ask for the record to be processed*/ - else status = dbScanLink(pl_record, pdest); - } - } - pl_record->pact = pact; - return(status); -} - -long dbPutLink( - struct db_link *pdblink, - dbCommon *psource, - short dbrType, - void *pbuffer, - long nRequest -) -{ - DBADDR *paddr=(DBADDR*)(pdblink->pdbAddr); - dbCommon *pdest=paddr->precord; - long status; - - status=dbPut(paddr,dbrType,pbuffer,nRequest); - if(pdblink->maximize_sevr) - recGblSetSevr(pdest,LINK_ALARM,psource->sevr); - if(status) return(status); - - if((paddr->pfield==(void *)&pdest->proc) - || (pdblink->process_passive && pdest->scan==0)) { - /*Note: If ppn then dbNotifyCancel will handle reprocessing*/ - /*if dbPutField caused asyn record to process ask for reprocessing*/ - if(!psource->ppn && pdest->putf) pdest->rpro = TRUE; - /* otherwise ask for the record to be processed*/ - else status=dbScanLink(psource,pdest); - } - return(status); -} - -long dbPutField( - DBADDR *paddr, - short dbrType, - void *pbuffer, - long nRequest -) -{ - long status; - dbFldDes *pfldDes=(dbFldDes *)(paddr->pfldDes); - dbCommon *precord = (dbCommon *)(paddr->precord); + long status = 0; + long special=paddr->special; + dbFldDes *pfldDes=(dbFldDes *)(paddr->pfldDes); + dbCommon *precord = (dbCommon *)(paddr->precord); + short dbfType = paddr->field_type; /*check for putField disabled*/ if(precord->disp) { if((void *)(&precord->disp) != paddr->pfield) return(0); } + 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(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 */ + strcpy(buffer,(char *)pbuffer); + /*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) { + 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); + if(status=dbFindRecord(&dbEntry,precord->name)) goto done; + if(status=dbFindField(&dbEntry,pfldDes->name)) goto done; + /* check for special processing is required */ + if(special) { + status = putSpecial(paddr,0); + if(status) return(status); + } + if(status=dbPutString(&dbEntry,buffer)) goto done; + if(plink->type == PV_LINK) { + DBADDR dbaddr; + + 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; + dbLockSetMerge(precord,pdbAddr->precord); + } else {/*It is a CA link*/ + char *pperiod; + + plink->type = CA_LINK; + plink->value.pv_link.precord = precord; + 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; + } + } + } + if(special) { + status = putSpecial(paddr,1); + if(status) return(status); + } + db_post_events(precord,plink,DBE_VALUE); + dbFinishEntry(&dbEntry); +done: + dbLockSetGblUnlock(); + return(status); + } dbScanLock(precord); status=dbPut(paddr,dbrType,pbuffer,nRequest); if(status==0){ @@ -1133,25 +1036,19 @@ long offset; return(0); } -long dbPut( - DBADDR *paddr, - short dbrType, - void *pbuffer, - long nRequest -) +long dbPut(DBADDR *paddr,short dbrType,void *pbuffer,long nRequest) { long no_elements=paddr->no_elements; long dummy; long offset; - long (*pconvert_routine)(); - long int (*pspecial)()=NULL; struct rset *prset; - dbCommon *precord=(dbCommon *)(paddr->precord); + dbCommon *precord=(dbCommon *)(paddr->precord); long status=0; dbFldDes *pfldDes; long special=paddr->special; short field_type=paddr->field_type; int isValueField; + char message[80]; if(dbrType==DBR_PUT_ACKT && field_type<=DBF_DEVICE) { status=putAckt(paddr,pbuffer,(long)1,(long)1,(long)0); @@ -1159,12 +1056,7 @@ long dbPut( } else if(dbrType==DBR_PUT_ACKS && field_type<=DBF_DEVICE) { status=putAcks(paddr,pbuffer,(long)1,(long)1,(long)0); return(status); - /* Check for valid request */ - } else if( INVALID_DB_REQ(dbrType) || (field_type>DBF_DEVICE) - || (!(pconvert_routine=dbPutConvertRoutine[dbrType][field_type])) ) - { - char message[80]; - + } else if( INVALID_DB_REQ(dbrType) || (field_type>DBF_DEVICE)) { sprintf(message,"dbPut - database request type is %d",dbrType); recGblDbaddrError(S_db_badDbrtype,paddr,message); return(S_db_badDbrtype); @@ -1174,61 +1066,36 @@ long dbPut( /* check for special processing is required */ if(special) { - if(special<100) { /*global processing*/ - if(special==SPC_NOMOD) { - status = S_db_noMod; - recGblDbaddrError(status,paddr,"dbPut"); - return(status); - }else if(special==SPC_SCAN){ - scanDelete(precord); + status = putSpecial(paddr,0); + if(status) return(status); + } + if(no_elements<=1) { + status = (*dbFastPutConvertRoutine[dbrType][field_type]) + (pbuffer,paddr->pfield, paddr); + } else { + if(prset && (prset->get_array_info) ) { + status= (*prset->get_array_info) + (paddr,&dummy,&offset); } - } - else { - if( prset && (pspecial = (prset->special))) { - status=(*pspecial)(paddr,0); - if(status) return(status); - } else { - recGblRecSupError(S_db_noSupport,paddr,"dbPut", - "special"); - return(S_db_noSupport); + else offset=0; + if(no_elements<(nRequest)) nRequest = no_elements; + status=(*dbPutConvertRoutine[dbrType][field_type]) + (paddr,pbuffer,nRequest,no_elements,offset); + /* update array info */ + if(prset && (prset->put_array_info) ) { + status= (*prset->put_array_info) + (paddr,nRequest); } - } } - - /* check for array */ - if( no_elements>1 && prset && (prset->get_array_info) ) { - status= (*prset->get_array_info)(paddr,&dummy,&offset); - } - else offset=0; - if(no_elements<(nRequest)) nRequest = no_elements; - - /* convert database field to buffer type and place it in the buffer */ - status=(*pconvert_routine)(paddr,pbuffer,nRequest,no_elements,offset); - - /* update array info */ - if( no_elements>1 && prset && (prset->put_array_info) ) { - status= (*prset->put_array_info)(paddr,nRequest); - } - if(status) return(status); /* check for special processing is required */ if(special) { - if(special<100) { /*global processing*/ - if(special==SPC_SCAN) { - scanAdd(precord); - } else if(special==SPC_AS) { - asChangeGroup((ASMEMBERPVT *)&precord->asp,precord->asg); - } - } - else { - status=(*pspecial)(paddr,1); - if(status) return(status); - } + status = putSpecial(paddr,1); + if(status) return(status); } - /* propagate events for this field */ - /* if the field is VAL and process_passive is true dont propagate*/ + /* if the field is VAL and pvlMask&pvlOptPP is true dont propagate*/ pfldDes = (dbFldDes *)(paddr->pfldDes); isValueField = dbIsValueField(pfldDes); if (isValueField) precord->udf=FALSE; diff --git a/src/db/dbAccess.h b/src/db/dbAccess.h index d62068ab7..87fe1f212 100644 --- a/src/db/dbAccess.h +++ b/src/db/dbAccess.h @@ -36,18 +36,22 @@ * .06 02-02-94 mrk added definitions for dbPutNotify * .07 03-18-94 mcn added breakpoint codes, fast link protos */ - + #ifndef INCdbAccessh #define INCdbAccessh #include #include #include #include +#ifdef vxWorks +#include +#endif +#include #include #include #include #include - + typedef struct dbAddr{ struct dbCommon *precord;/* address of record */ void *pfield; /* address of field */ @@ -251,68 +255,75 @@ struct dbr_alDouble {DBRalDouble}; #define S_db_cntCont (M_dbAccess|65) /*Cannot resume dbContTask*/ /* Global Database Access Routines*/ +#define dbGetLink(PLNK,DBRTYPE,PBUFFER,OPTIONS,NREQUEST) \ + (((((PLNK)->type == CONSTANT)&&(!(NREQUEST))) ||\ + (! (((PLNK)->type == DB_LINK) || ((PLNK)->type == CA_LINK)) ))\ + ? 0\ + : dbGetLinkValue((PLNK),(DBRTYPE), \ + (void *)(PBUFFER),(OPTIONS),(NREQUEST))) +#define dbPutLink(PLNK,DBRTYPE,PBUFFER,NREQUEST) \ + ((((PLNK)->type == CONSTANT) ||\ + (! (((PLNK)->type == DB_LINK) || ((PLNK)->type == CA_LINK)) ))\ + ? 0\ + : dbPutLinkValue((PLNK),(DBRTYPE),(void *)(PBUFFER),(NREQUEST))) #ifdef __STDC__ struct rset *dbGetRset(struct dbAddr *paddr); int dbIsValueField(struct dbFldDes *pdbFldDes); int dbGetFieldIndex(struct dbAddr *paddr); -long dbCommonInit(struct dbCommon *precord, int pass); -void dbScanLock(struct dbCommon *precord); -void dbScanUnlock(struct dbCommon *precord); -void dbScanLockInit(int nset); long dbScanPassive(struct dbCommon *pfrom,struct dbCommon *pto); long dbProcess(struct dbCommon *precord); long dbNameToAddr(char *pname,struct dbAddr *); -long dbGetLink(struct db_link *,struct dbCommon *precord,short dbrType, +long dbGetLinkValue(struct link *,short dbrType, void *pbuffer,long *options,long *nRequest); +long dbGetField(struct dbAddr *,short dbrType,void *pbuffer,long *options, + long *nRequest,void *pfl); +long dbGet(struct dbAddr *,short dbrType,void *pbuffer,long *options, + long *nRequest,void *pfl); +long dbPutLinkValue(struct link *,short dbrType,void *pbuffer,long nRequest); long dbPutField(struct dbAddr *,short dbrType,void *pbuffer,long nRequest); +long dbPut(struct dbAddr *,short dbrType,void *pbuffer,long nRequest); long dbPutNotify(PUTNOTIFY *pputnotify); /*dbNotifyAdd called by dbScanPassive and dbScanLink*/ void dbNotifyAdd(struct dbCommon *pfrom,struct dbCommon *pto); void dbNotifyCancel(PUTNOTIFY *pputnotify); -/*dbNotifyCompletion called by recGblFwdLink and dbProcess */ -void dbNotifyCompletion(struct dbCommon *precord); /*called only by recGblFwdLink*/ -long dbPut(struct dbAddr *,short dbrType,void *pbuffer,long nRequest); -long dbGetField(struct dbAddr *,short dbrType,void *pbuffer,long *options,long *nRequest,void *pfl); -long dbGet(struct dbAddr *,short dbrType,void *pbuffer,long *options,long *nRequest,void *pfl); -long dbPutLink(struct db_link *,struct dbCommon *precord,short dbrType, - void *pbuffer,long nRequest); +/*dbNotifyCompletion called by recGblFwdLink */ +void dbNotifyCompletion(struct dbCommon *precord); long dbBufferSize(short dbrType,long options,long nRequest); long dbValueSize(short dbrType); -long dbCaAddInlink(struct link *plink,void *pdest_record,char *dest_fieldname); -long dbCaAddOutlink(struct link *plink,void *psource_record,char *source_fieldname); -long dbCaPutLink(struct link *plink,long *poptions,long *pnRequest); -long dbCaGetLink(struct link *plink); -void dbCaLinkInit(int pass); -long dbFastLinkGet(struct link *plink, struct dbCommon *precord, void *pdest); -long dbFastLinkPut(struct link *plink, struct dbCommon *precord, void *psource); -long cvt_uninit(void *from, void *to, struct dbAddr *paddr); -long cvt_dummy(void *from, void *to, struct dbAddr *paddr); +void dbCaLinkInit(void); +void dbCaAddLink(struct link *plink); +void dbCaRemoveLink(struct link *plink); +long dbCaGetLink(struct link *plink,short dbrType,void *pbuffer, + unsigned short *psevr,long *nRequest); +long dbCaPutLink(struct link *plink,short dbrType,void *pbuffer,long nRequest); + long dbScanLink(struct dbCommon *pfrom, struct dbCommon *pto); #else -void dbScanLock(); -void dbScanUnlock(); -void dbScanLockInit(); +struct rset *dbGetRset(); +int dbIsValueField(); +int dbGetFieldIndex(); long dbScanPassive(); long dbProcess(); long dbNameToAddr(); -long dbGetLink(); +long dbGetLinkValue(); +long dbGetField(); +long dbGet(); +long dbPutLinkValue(); long dbPutField(); long dbPut(); -long dbGetField(); -long dbPutLink(); +long dbPutNotify(); +void dbNotifyAdd(); +void dbNotifyCancel(); +void dbNotifyCompletion(); long dbBufferSize(); long dbValueSize(); -long dbCaAddInlink(); -long dbCaAddOutlink(); -long dbCaPutLink(); +void dbCaLinkInit(); +void dbCaAddLink(); +void dbCaRemoveLink(); long dbCaGetLink(); -long dbFastLinkGet(); -long dbFastLinkPut(); -long cvt_uninit(); -long cvt_dummy(); +long dbCaPutLink(); long dbScanLink(); - #endif /*__STDC__*/ #endif /*INCdbAccessh*/ diff --git a/src/db/dbBkpt.c b/src/db/dbBkpt.c index 4102128db..f0a7893b3 100644 --- a/src/db/dbBkpt.c +++ b/src/db/dbBkpt.c @@ -28,6 +28,9 @@ * Modification Log: * ----------------- * $Log$ + * Revision 1.6 1995/11/29 14:23:28 mrk + * Changes for replacing default.dctsdr by all ascii files + * * Revision 1.5 1995/02/23 21:45:03 mcn * Fixed locking error. OOPS. * @@ -76,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -174,7 +178,7 @@ static SEM_ID bkpt_stack_sem; * lockset to be continued from differs from this * variable. */ -static short last_lset = 0; +static unsigned long last_lset = 0; /* * FIND_LOCKSET() finds the stack entry @@ -185,7 +189,7 @@ static short last_lset = 0; #define FIND_LOCKSET(precord, pnode) \ pnode = (struct LS_LIST *) lstFirst(&lset_stack); \ while ((pnode) != NULL) { \ - if ((pnode)->l_num == (precord)->lset) break; \ + if (pnode->l_num == dbLockGetLockId(precord)) break; \ pnode = (struct LS_LIST *) lstNext((NODE *)pnode); \ } \ @@ -346,7 +350,7 @@ long dbb(char *record_name) pnode->taskid = 0; pnode->step = 0; - pnode->l_num = precord->lset; + pnode->l_num = dbLockGetLockId(precord); lstAdd(&lset_stack, (NODE *)pnode); } @@ -639,7 +643,7 @@ static void dbBkptCont(struct dbCommon *precord) /* remove execution semaphore */ semDelete(pnode->ex_sem); - printf("\n BKPT> End debug of lockset %d\n-> ", pnode->l_num); + printf("\n BKPT> End debug of lockset %lu\n-> ", pnode->l_num); /* free list node */ free(pnode); @@ -698,8 +702,7 @@ int dbBkpt(struct dbCommon *precord) } /* Check disable flag */ - recGblGetFastLink(&precord->sdis, (void *) precord, &precord->disa); - + dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0); if (precord->disa == precord->disv) { /* * Do not process breakpoints if the record is disabled, @@ -917,7 +920,7 @@ long dbstat() while (pnode != NULL) { if (pnode->precord != NULL) { - printf("LSet: %5.5d Stopped at: %-28.28s #B: %5.5d T: 0x%7.7x\n", + printf("LSet: %lu Stopped at: %-28.28s #B: %5.5d T: 0x%7.7x\n", pnode->l_num, pnode->precord->name, lstCount(&pnode->bp_list), pnode->taskid); /* for each entrypoint detected, print out entrypoint statistics */ @@ -932,7 +935,7 @@ long dbstat() } } else { - printf("LSet: %5.5d #B: %5.5d T: 0x%7.7x\n", + printf("LSet: %lu #B: %5.5d T: 0x%7.7x\n", pnode->l_num, lstCount(&pnode->bp_list), pnode->taskid); } diff --git a/src/db/dbBkpt.h b/src/db/dbBkpt.h index 89de41e6b..fdeca15df 100644 --- a/src/db/dbBkpt.h +++ b/src/db/dbBkpt.h @@ -32,6 +32,7 @@ #ifndef INCdbBkptsh #define INCdbBkptsh 1 +#include /* Needs to be put into dbTest.h ! */ long dbpr(char *name, int level); @@ -73,7 +74,7 @@ struct LS_LIST { SEM_ID ex_sem; /* semaphore for execution queue */ int taskid; /* saved taskid for the task in stepping mode */ int step; /* one if currently "stepping," else zero */ - short l_num; /* lockset number */ + unsigned long l_num; /* lockset number */ }; /* Values for BKPT (breakpoint) field in record */ diff --git a/src/db/dbCa.c b/src/db/dbCa.c new file mode 100644 index 000000000..80b7748b8 --- /dev/null +++ b/src/db/dbCa.c @@ -0,0 +1,439 @@ +/* dbCa.c */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1991 Regents of the University of California, +and the University of Chicago Board of Governors. + +This software was developed under a United States Government license +described on the COPYRIGHT_Combined file included as part +of this distribution. +**********************************************************************/ + +/**************************************************************** +* +* Current Author: Bob Dalesio +* Contributing Author: Marty Kraimer +* Date: 26MAR96 +* +* Complete replacement for dbCaDblink.c dbCaLink.c (Nicholas T. Karonis) +* +* Modification Log: +* ----------------- +* .01 26MAR96 lrd rewritten for simplicity, robustness and flexibility +****************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "cadef.h" +#include "caerr.h" +#include "alarm.h" +#include "db_access.h" +#include "link.h" +#include "task_params.h" +#include "errMdef.h" +#include "epicsPrint.h" +#include "dbCommon.h" +#include "dbCa.h" +/*Following is because dbScan.h causes include for dbAccess.h*/ +void scanOnce(void *precord); + +static ELLLIST caList; /* Work list for dbCaTask */ +static SEM_ID caListSem; /*Mutual exclusions semaphores for caList*/ +static SEM_ID caWakeupSem; /*wakeup semaphore for dbCaTask*/ +void dbCaTask(); /*The Channel Access Task*/ + +void dbCaLinkInit(void) +{ + ellInit(&caList); + caListSem = semBCreate(SEM_Q_PRIORITY,SEM_FULL); + caWakeupSem = semBCreate(SEM_Q_PRIORITY,SEM_EMPTY); + if(!caListSem || !caWakeupSem) { + printf("dbCaLinkInit: semBCreate failed\n"); + return; + } + taskSpawn("dbCaLink", DB_CA_PRI, DB_CA_OPT, + DB_CA_STACK, (FUNCPTR) dbCaTask, + 0,0,0,0,0,0,0,0,0,0); +} + +void dbCaAddLink( struct link *plink) +{ + caLink *pca; + + pca = (caLink*)dbCalloc(1,sizeof(caLink)); + pca->plink = plink; + plink->type = CA_LINK; + plink->value.pv_link.pvt = pca; + if((pca->lock = semBCreate(SEM_Q_PRIORITY,SEM_FULL)) == NULL){ + printf("dbCaAddLink: semBCreate failed\n"); + taskSuspend(0); + } + semTake(caListSem,WAIT_FOREVER); + pca->link_action = CA_CONNECT; + ellAdd(&caList,&pca->node); + semGive(caListSem); + semGive(caWakeupSem); + return; +} + +void dbCaRemoveLink( struct link *plink) +{ + caLink *pca = (caLink *)plink->value.pv_link.pvt; + + if(!pca) return; + semTake(caListSem,WAIT_FOREVER); + if(!pca->link_action){/*If not on work list add it*/ + ellAdd(&caList,&pca->node); + } + pca->link_action = CA_DELETE; + plink->value.pv_link.pvt = 0; + pca->plink = 0; + semGive(caListSem); + semGive(caWakeupSem); +} + + +long dbCaGetLink(struct link *plink,short dbrType, char *pdest, + unsigned short *psevr,long *nelements) +{ + caLink *pca = (caLink *)plink->value.pv_link.pvt; + long status = 0; + long (*pconvert)(); + STATUS semStatus; + + if(!pca) { + epicsPrintf("dbCaGetLink: record %s pv_link.pvt is NULL\n", + plink->value.pv_link.precord); + return(-1); + } + semStatus = semTake(pca->lock,WAIT_FOREVER); + if(semStatus!=OK) { + epicsPrintf("dbCaGetLink: semStatus!OK\n"); + taskSuspend(0); + } + if(ca_field_type(pca->chid) == TYPENOTCONN){ + pca->sevr = INVALID_ALARM; + goto done; + } + if(!ca_read_access(pca->chid)) { + pca->sevr = INVALID_ALARM; + goto done; + } + if((pca->dbrType == DBR_ENUM) + && (dbDBRnewToDBRold[dbrType] == DBR_STRING)) { + /*Must ask server for DBR_STRING*/ + if(!pca->pgetString) { + pca->pgetString = dbCalloc(MAX_STRING_SIZE,sizeof(char)); + semGive(pca->lock); + semTake(caListSem,WAIT_FOREVER); + pca->link_action = CA_MONITOR_STRING; + semGive(caListSem); + semGive(caWakeupSem); + semStatus = semTake(pca->lock,WAIT_FOREVER); + if(semStatus!=OK) { + epicsPrintf("dbCaGetLink: semStatus!OK\n"); + taskSuspend(0); + } + } + if(!pca->gotInString) { + pca->sevr = INVALID_ALARM; + goto done; + } + if(nelements) *nelements = 1; + pconvert=dbFastGetConvertRoutine[dbDBRoldToDBFnew[DBR_STRING]][dbrType]; + status = (*(pconvert))(pca->pgetString, pdest, 0); + goto done; + } + if(!pca->gotInNative){ + pca->sevr = INVALID_ALARM; + goto done; + } + if(!nelements || *nelements == 1){ + pconvert= + dbFastGetConvertRoutine[dbDBRoldToDBFnew[pca->dbrType]][dbrType]; + status = (*(pconvert))(pca->pgetNative, pdest, 0); + }else{ + unsigned long ntoget = *nelements; + struct db_addr dbAddr; + + if(ntoget > pca->nelements) ntoget = pca->nelements; + *nelements = ntoget; + pconvert = dbGetConvertRoutine[dbDBRoldToDBFnew[pca->dbrType]][dbrType]; + memset((void *)&dbAddr,0,sizeof(dbAddr)); + dbAddr.pfield = pca->pgetNative; + /*Following will only be used for pca->dbrType == DBR_STRING*/ + dbAddr.field_size = MAX_STRING_SIZE; + status = (*(pconvert))(&dbAddr,pdest,nelements,ntoget,0); + } +done: + if(psevr) *psevr = pca->sevr; + semGive(pca->lock); + return(status); +} + +long dbCaPutLink(struct link *plink,short dbrType, + void *psource,long nelements) +{ + caLink *pca = (caLink *)plink->value.pv_link.pvt; + long (*pconvert)(); + long status = 0; + STATUS semStatus; + short link_action; + + if(!pca) { + epicsPrintf("dbCaPutLink: record %s pv_link.pvt is NULL\n", + plink->value.pv_link.precord); + return(-1); + } + /* put the new value in */ + semStatus = semTake(pca->lock,WAIT_FOREVER); + if(semStatus!=OK) { + epicsPrintf("dbCaGetLink: semStatus!OK\n"); + taskSuspend(0); + } + if(ca_state(pca->chid) != cs_conn) { + semGive(pca->lock); + return(-1); + } + if((pca->dbrType == DBR_ENUM) + && (dbDBRnewToDBRold[dbrType] == DBR_STRING)) { + /*Must send DBR_STRING*/ + if(!pca->pputString) + pca->pputString = dbCalloc(MAX_STRING_SIZE,sizeof(char)); + pconvert=dbFastPutConvertRoutine[dbrType][dbDBRoldToDBFnew[DBR_STRING]]; + status = (*(pconvert))(psource,pca->pputString, 0); + link_action = CA_WRITE_STRING; + pca->gotOutString = TRUE; + } else { + if(nelements == 1){ + pconvert = dbFastPutConvertRoutine + [dbrType][dbDBRoldToDBFnew[pca->dbrType]]; + status = (*(pconvert))(psource,pca->pputNative, 0); + }else{ + struct db_addr dbAddr; + pconvert = dbPutConvertRoutine + [dbrType][dbDBRoldToDBFnew[pca->dbrType]]; + memset((void *)&dbAddr,0,sizeof(dbAddr)); + dbAddr.pfield = pca->pputNative; + /*Following only used for DBF_STRING*/ + dbAddr.field_size = MAX_STRING_SIZE; + status = (*(pconvert))(&dbAddr,psource,nelements,pca->nelements,0); + } + link_action = CA_WRITE_NATIVE; + pca->gotOutNative = TRUE; + } + if(pca->newWrite) pca->nNoWrite++; + pca->newWrite = TRUE; + semGive(pca->lock); + /* link it into the action list */ + semTake(caListSem,WAIT_FOREVER); + if(!pca->link_action && ca_write_access(pca->chid)){ + pca->link_action = link_action; + ellAdd(&caList,&pca->node); + } + semGive(caListSem); + semGive(caWakeupSem); + return(status); +} + + +static void caEventHandler(struct event_handler_args arg) +{ + caLink *pca = (caLink *)arg.usr; + struct link *plink; + long size; + + if(!pca) { + epicsPrintf("caEventHandler why was arg.usr NULL\n"); + return; + } + plink = pca->plink; + if(arg.status != ECA_NORMAL) { + dbCommon *precord = 0; + + if(plink) precord = (dbCommon *)plink->value.pv_link.precord; + if(precord) + epicsPrintf("dbCa: caEventHandler record %s error %s\n", + precord->name,ca_message(arg.status)); + else + epicsPrintf("dbCa: caEventHandler error %s\n", + ca_message(arg.status)); + return; + } + if(!arg.dbr) { + epicsPrintf("caEventHandler why was arg.dbr NULL\n"); + return; + } + semTake(pca->lock,WAIT_FOREVER); + size = arg.count * dbr_value_size[arg.type]; + if((arg.type==DBR_STS_STRING) + && (ca_field_type(pca->chid)==DBR_ENUM)) { + memcpy(pca->pgetString,dbr_value_ptr(arg.dbr,arg.type),size); + pca->gotInString = TRUE; + } else switch (arg.type){ + case DBR_STS_STRING: + case DBR_STS_SHORT: + case DBR_STS_FLOAT: + case DBR_STS_ENUM: + case DBR_STS_CHAR: + case DBR_STS_LONG: + case DBR_STS_DOUBLE: + memcpy(pca->pgetNative,dbr_value_ptr(arg.dbr,arg.type),size); + pca->gotInNative = TRUE; + break; + default: + errMessage(-1,"dbCa: caEventHandler Logic Error\n"); + break; + } + pca->sevr=(unsigned short)((struct dbr_sts_double *)arg.dbr)->severity; + plink = pca->plink; + if(plink) { + struct pv_link *ppv_link = &(plink->value.pv_link); + dbCommon *precord = ppv_link->precord; + + if(precord) { + if((ppv_link->pvlMask&pvlOptCP) + || ((ppv_link->pvlMask&pvlOptCPP)&&(precord->scan==0))) + scanOnce(ppv_link->precord); + } + } + semGive(pca->lock); +} + +static void dbCaLinkConnectionHandler(struct connection_handler_args arg) +{ + caLink *pca; + int status; + + pca = ca_puser(arg.chid); + if(!pca) return; + if(ca_state(arg.chid) != cs_conn){ + pca->nDisconnect++; + return; + } + semTake(pca->lock,WAIT_FOREVER); + if((pca->nelements != ca_element_count(arg.chid)) + || (pca->dbrType != ca_field_type(arg.chid))){ + DBLINK *plink = pca->plink; + + if(plink) plink->value.pv_link.getCvt = 0; + free(pca->pgetNative); + free(pca->pputNative); + pca->pgetNative = NULL; + pca->pputNative = NULL; + pca->gotInNative = FALSE; + pca->gotOutNative = FALSE; + pca->gotInString = FALSE; + } + if(pca->pgetNative == NULL){ + short element_size; + + pca->nelements = ca_element_count(arg.chid); + pca->dbrType = ca_field_type(arg.chid); + element_size = dbr_value_size[ca_field_type(arg.chid)]; + pca->pgetNative = dbCalloc(pca->nelements,element_size); + pca->pputNative = dbCalloc(pca->nelements,element_size); + status = ca_add_array_event( + ca_field_type(arg.chid)+DBR_STS_STRING, ca_element_count(arg.chid), + arg.chid, caEventHandler,pca,0.0,0.0,0.0,0); + if(status!=ECA_NORMAL) + epicsPrintf("dbCaTask ca_search_and_connect %s\n", + ca_message(status)); + if(pca->pgetString) { + status = ca_add_array_event(DBR_STS_STRING,1, + arg.chid, caEventHandler,pca,0.0,0.0,0.0,0); + if(status!=ECA_NORMAL) + epicsPrintf("dbCaTask ca_search_and_connect %s\n", + ca_message(status)); + } + } + semGive(pca->lock); + semTake(caListSem,WAIT_FOREVER); + if(pca->gotOutNative && !pca->link_action) { + pca->link_action = CA_WRITE_NATIVE; + ellAdd(&caList,&pca->node); + } + semGive(caListSem); +} + +void dbCaTask() +{ + caLink *pca; + short link_action; + int status; + + SEVCHK(ca_task_initialize(),NULL); + /* channel access event loop */ + while (TRUE){ + semTake(caWakeupSem,WAIT_FOREVER); + while(TRUE) { /* process all requests in caList*/ + semTake(caListSem,WAIT_FOREVER); + if(pca = (caLink *)ellFirst(&caList)){/*Take off list head*/ + ellDelete(&caList,&pca->node); + link_action = pca->link_action; + pca->link_action = 0; + semGive(caListSem); /*Give it back immediately*/ + switch(link_action) { + case CA_CONNECT: + status = ca_search_and_connect( + pca->plink->value.pv_link.pvname, + &(pca->chid), + dbCaLinkConnectionHandler,(void *)pca); + if(status!=ECA_NORMAL) + epicsPrintf("dbCaTask ca_search_and_connect %s\n", + ca_message(status)); + break; + case CA_DELETE: + if(pca->chid) ca_clear_channel(pca->chid); + free(pca->pgetNative); + free(pca->pputNative); + free(pca->pgetString); + free(pca->pputString); + semDelete(pca->lock); + free(pca); + break; + case CA_WRITE_NATIVE: + if(ca_state(pca->chid) == cs_conn){ + status = ca_array_put( + pca->dbrType,pca->nelements, + pca->chid,pca->pputNative); + if(status==ECA_NORMAL){ + pca->newWrite = FALSE; + } + } + break; + case CA_WRITE_STRING: + if(ca_state(pca->chid) == cs_conn){ + status = ca_array_put( + DBR_STRING,1, + pca->chid,pca->pputString); + if(status==ECA_NORMAL) { + pca->newWrite = FALSE; + } + } + break; + case CA_MONITOR_STRING: + if(ca_state(pca->chid) == cs_conn){ + status = ca_add_array_event(DBR_STS_STRING,1, + pca->chid, caEventHandler,pca,0.0,0.0,0.0,0); + if(status!=ECA_NORMAL) + epicsPrintf("dbCaTask ca_add_array_event %s\n", + ca_message(status)); + } + break; + }/*switch*/ + } else { + semGive(caListSem); + break; /*caList is empty*/ + } + } + SEVCHK(ca_flush_io(),0); + } +} diff --git a/src/db/dbCa.h b/src/db/dbCa.h new file mode 100644 index 000000000..d777c2b5a --- /dev/null +++ b/src/db/dbCa.h @@ -0,0 +1,53 @@ +/* dbCa.h.c */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1991 Regents of the University of California, +and the University of Chicago Board of Governors. + +This software was developed under a United States Government license +described on the COPYRIGHT_Combined file included as part +of this distribution. +**********************************************************************/ + +/**************************************************************** +* +* Current Author: Bob Dalesio +* Contributing Author: Marty Kraimer +* Date: 08APR96 +* +* +* Modification Log: +* ----------------- +* .01 08APR96 mrk Made separate module for dbcal +****************************************************************/ + +/* for input links */ +#define CA_CONNECT 1 +#define CA_DELETE 2 +#define CA_WRITE_NATIVE 3 +#define CA_WRITE_STRING 4 +#define CA_MONITOR_STRING 5 +typedef struct caLink +{ + ELLNODE node; + struct link *plink; + chid chid; + void *pgetNative; + void *pputNative; + char *pgetString; + char *pputString; + long nelements; + SEM_ID lock; + unsigned long nDisconnect; + unsigned long nNoWrite; + short dbrType; + short link_action; + unsigned short sevr; + char gotInNative; + char gotOutNative; + char gotInString; + char gotOutString; + char newWrite; +}caLink; diff --git a/src/db/dbCaDblink.c b/src/db/dbCaDblink.c deleted file mode 100644 index 5d547132c..000000000 --- a/src/db/dbCaDblink.c +++ /dev/null @@ -1,757 +0,0 @@ -/* dbCaDblink.c */ -/* base/src/db $Id$ */ -/**************************************************************** -* -* Author: Nicholas T. Karonis -* Date: 01-01-92 -* -* Experimental Physics and Industrial Control System (EPICS) -* -* Copyright 1991, the Regents of the University of California, -* and the University of Chicago Board of Governors. -* -* This software was produced under U.S. Government contracts: -* (W-7405-ENG-36) at the Los Alamos National Laboratory, -* and (W-31-109-ENG-38) at Argonne National Laboratory. -* -* Initial development by: -* The Controls and Automation Group (AT-8) -* Ground Test Accelerator -* Accelerator Technology Division -* Los Alamos National Laboratory -* -* Co-developed with -* The Controls and Computing Group -* Accelerator Systems Division -* Advanced Photon Source -* Argonne National Laboratory -* -* Modification Log: -* ----------------- -* -****************************************************************/ - -/**************************************************************** -* -* This file exists because it is currently not possible to have a single .c -* file that contains BOTH channel access calls AND calls to the NEW db -* functions. This file calls a number of NEW db functions (dbNameToAddr(), -* dbScanLock(), dbScanUnlock(), and dbPut()). If it were possible to mix -* channel access calls and new db calls, the contents of this file should be -* placed into dbCaLink.c as the all the externally visible functions in this -* file are only called from functions in that file. Additionally, many of the -* data structures found in this file would no longer be necessary. -* -****************************************************************/ - -/* needed for NULL */ -#include -#include -#include - -/* needed for PVNAME_SZ and FLDNAME_SZ ... must be before dbAccess.h */ -#include -#include - -/* needed for dbNameToAddr() */ -#include - -/* needed for struct dbCommon ... should be removed when */ -/* MAXSEVERITY_FROM_PDBADDR moved to another header file */ -#include - -/* needed for (db_field_log *) NULL parm passed to dbGet() */ -#include - -#include -#include - -/* needed for recGblSetSevr() macro */ -#include - -/* these should be in dbFldTypes.h where */ -/* the valid DBF and DBR types are defined */ - -#define INVALID_DBR -1 -#define INVALID_DBF -1 - -/* this macro was defined by list of DBF and DBR types */ -/* found in dbFldTypes.h and belongs in that header file. */ - -#define DBF_TO_DBR(DBF) \ - ((DBF) == DBF_STRING ? DBR_STRING : \ - ((DBF) == DBF_CHAR ? DBR_CHAR : \ - ((DBF) == DBF_UCHAR ? DBR_UCHAR : \ - ((DBF) == DBF_SHORT ? DBR_SHORT : \ - ((DBF) == DBF_USHORT ? DBR_USHORT : \ - ((DBF) == DBF_LONG ? DBR_LONG : \ - ((DBF) == DBF_ULONG ? DBR_ULONG : \ - ((DBF) == DBF_FLOAT ? DBR_FLOAT : \ - ((DBF) == DBF_DOUBLE ? DBR_DOUBLE : \ - ((DBF) == DBF_ENUM ? DBR_ENUM : \ - ((DBF) == DBF_MENU ? DBR_ENUM : \ - ((DBF) == DBF_DEVICE ? DBR_ENUM : \ - INVALID_DBF )))))))))))) - -/* this macro should be in recSup.h */ -/* to hide the fact that the precord */ -/* field needs to be accessed from a */ -/* dbaddr to set a new severity. */ -#define MAXSEVERITY_FROM_PDBADDR(PDBADDR, NEWSTATUS, NEWSEVERITY) \ - recGblSetSevr((struct dbCommon *) (PDBADDR)->precord, \ - (NEWSTATUS), (NEWSEVERITY)); - -/* START definitions from db_access.c */ - -#define oldDBF_STRING 0 -#define oldDBF_INT 1 -#define oldDBF_SHORT 1 -#define oldDBF_FLOAT 2 -#define oldDBF_ENUM 3 -#define oldDBF_CHAR 4 -#define oldDBF_LONG 5 -#define oldDBF_DOUBLE 6 - -/* data request buffer types */ -#define oldDBR_STRING oldDBF_STRING -#define oldDBR_INT oldDBF_INT -#define oldDBR_SHORT oldDBF_INT -#define oldDBR_FLOAT oldDBF_FLOAT -#define oldDBR_ENUM oldDBF_ENUM -#define oldDBR_CHAR oldDBF_CHAR -#define oldDBR_LONG oldDBF_LONG -#define oldDBR_DOUBLE oldDBF_DOUBLE -#define oldDBR_STS_STRING 7 -#define oldDBR_STS_INT 8 -#define oldDBR_STS_SHORT 8 -#define oldDBR_STS_FLOAT 9 -#define oldDBR_STS_ENUM 10 -#define oldDBR_STS_CHAR 11 -#define oldDBR_STS_LONG 12 -#define oldDBR_STS_DOUBLE 13 -#define oldDBR_TIME_STRING 14 -#define oldDBR_TIME_INT 15 -#define oldDBR_TIME_SHORT 15 -#define oldDBR_TIME_FLOAT 16 -#define oldDBR_TIME_ENUM 17 -#define oldDBR_TIME_CHAR 18 -#define oldDBR_TIME_LONG 19 -#define oldDBR_TIME_DOUBLE 20 -#define oldDBR_GR_STRING 21 -#define oldDBR_GR_INT 22 -#define oldDBR_GR_SHORT 22 -#define oldDBR_GR_FLOAT 23 -#define oldDBR_GR_ENUM 24 -#define oldDBR_GR_CHAR 25 -#define oldDBR_GR_LONG 26 -#define oldDBR_GR_DOUBLE 27 -#define oldDBR_CTRL_STRING 28 -#define oldDBR_CTRL_INT 29 -#define oldDBR_CTRL_SHORT 29 -#define oldDBR_CTRL_FLOAT 30 -#define oldDBR_CTRL_ENUM 31 -#define oldDBR_CTRL_CHAR 32 -#define oldDBR_CTRL_LONG 33 -#define oldDBR_CTRL_DOUBLE 34 - -/* END definitions from db_access.c */ - -/**************************************/ -/* */ -/* Externally Visible Local Functions */ -/* */ -/**************************************/ - -long dbCaCopyPvar(); /* called from dbCaLink.c */ -long dbCaDbPut(); /* called from dbCaLink.c */ -long dbCaMaximizeSeverity(); /* called from dbCaLink.c */ -long dbCaNameToAddr(); /* called from dbCaLink.c */ - -/* conversion routines */ - -short dbCaNewDbfToNewDbr(); /* called from dbCaLink.c */ -/* these two go away when channel access learns new db technology */ -short dbCaNewDbrToOldDbr(); /* called from dbCaLink.c */ -short dbCaOldDbrToNewDbr(); /* called from dbCaLink.c */ -short dbCaOldDbrToOldDbrSts(); /* called from dbCaLink.c */ - -/* these should be moved to db access */ -char *dbCaRecnameFromDbCommon(); /* called from dbCaLink.c */ -short dbCaDbfFromDbAddr(); /* called from dbCaLink.c */ -long dbCaNelementsFromDbAddr(); /* called from dbCaLink.c */ - -/**************************************************************** -* -* EXTERNALLY VISIBLE FUNCTIONS -* -****************************************************************/ - -/**************************************************************** -* -* Description: -* -* Input: -* -* Output: -* -* Returns: -* -* Logic: -* -* Notes: -* Typically this routine is called from a place that has no -* knowledge about struct dbAddr, therefore pdbaddr comes in as -* a void *. -* -****************************************************************/ - -short dbCaDbfFromDbAddr(pdbaddr) -void *pdbaddr; -{ - -short rc; - - if (pdbaddr) - rc = ((struct dbAddr *) pdbaddr)->field_type; - else - rc = (short) INVALID_DBF; - - return rc; - -} /* end dbCaDbfFromDbAddr() */ - -/**************************************************************** -* -* long dbCaNameToAddr(pvarname) -* char *pvarname; -* -* Description: -* During record initialization a record was found to have an input link -* whose source is in a different physical database (on another IOC). This -* function registers that input link as remote. -* -* Input: -* char *pvarname name of destination pvar for input link -* -* Output: None. -* -* Returns: -* any rc from dbNameToAddr() -* S_dbCa_nullarg - received a NULL pointer in one of the args -* S_dbCa_failedmalloc - could not dynamically allocate memory -* -* Notes: -* The name of the destination pvar for this input link serves as -* the primary key when relating the the Input List in this file -* to the Input List in dbCaLink.c as each input link has exactly one source -* (i.e., name of destination of input link --FD--> input link). -* -* This function is called by dbCaAddInlink() in dbCaLink.c. -* -****************************************************************/ - -long dbCaNameToAddr(pvarname, ppdbaddr) -char *pvarname; -void **ppdbaddr; -{ - -char errmsg[100]; -long rc; - - if (pvarname) - { - if (ppdbaddr) - { - if (*ppdbaddr = (void *) calloc - ((unsigned) 1, (unsigned) sizeof (struct dbAddr))) - { - rc = dbNameToAddr(pvarname, (struct dbAddr *) *ppdbaddr); - - if (!RTN_SUCCESS(rc)) - free(*ppdbaddr); - } - else - { - rc = S_dbCa_failedmalloc; - sprintf(errmsg, - "ERROR: dbCaNameToAddr() could not calloc dbAddr for dpvar >%s<", - pvarname); - errMessage(S_dbCa_failedmalloc, errmsg); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaNameToAddr() got NULL ppdest_dbaddr"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaNameToAddr() got NULL pvarname"); - } /* endif */ - - return rc; - -} /* end dbCaNameToAddr() */ - -/**************************************************************** -* -* Description: -* A record is being processed that has an output link that refers to a -* process variable on another physical database (another IOC). This function -* copies the value from the source pvar into the temporary store of the output -* node. -* -* Input: -* -* Output: None. -* -* Returns: -* any rc from dbGet() -* S_dbCa_nullarg - received a NULL pointer in one of the args -* -* Notes: -* The source pvar name is used as the primary key to index the Output List -* in this file. -* The two arguments poptions and pnrequest are passed because this function -* uses dbGet() to transfer the data from the record to the temporary store -* in the Output List. -* This function is called by dbCaPutLink() in dbCaLink.c. -* -****************************************************************/ - -long dbCaCopyPvar(psource_dbaddr, dest_old_dbr_type, pval, - poptions, pnrequest) -void *psource_dbaddr; -short dest_old_dbr_type; -void *pval; -long *poptions; -long *pnrequest; -{ - -long rc; - - if (psource_dbaddr) - { - if (pval) - { - if (poptions) - { - if (pnrequest) - rc = dbGet((struct dbAddr *) psource_dbaddr, - dest_old_dbr_type, (caddr_t) pval, - poptions, pnrequest, (db_field_log *) NULL); - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaCopyPvar() got NULL pnrequest"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaCopyPvar() got NULL poptions"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, "ERROR: dbCaCopyPvar() got NULL pval"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaCopyPvar() got NULL psource_dbaddr"); - } /* endif */ - - return rc; - -} /* end dbCaCopyPvar() */ - -/**************************************************************** -* -* long dbCaMaximizeSeverity(dest_pvarname, new_severity, new_status) -* char dest_pvarname; -* unsigned short new_severity; -* unsigned short new_status; -* -* Description: -* A record is being processed that has an input link that refers to a -* process variable on another physical database (another IOC) and the input -* link is MS. The severity of the source record is appropriately propogated -* to the destination record. -* -* Input: -* char dest_pvarname destination pvar name -* unsigned short new_severity new alarm severity -* unsigned short new_status new alarm status -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_foundnull - found a NULL pointer where one should not be -* S_dbCa_nullarg - encountered a NULL pointer in one of the input args -* -* Notes: -* The dest pvar name is used as the primary key to index the Input List -* in this file. -* This function is called by dbCaGetLink() in dbCaLink.c. -* -****************************************************************/ - -long dbCaMaximizeSeverity(pdest_dbaddr, new_severity, new_status) -void *pdest_dbaddr; -unsigned short new_severity; -unsigned short new_status; -{ - -long rc; - - if (pdest_dbaddr) - { - rc = 0L; - - MAXSEVERITY_FROM_PDBADDR ((struct dbAddr *) pdest_dbaddr, - new_status, new_severity) - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR:dbCaMaximizeSeverity() got NULL pdest_dbaddr"); - } /* endif */ - - return rc; - -} /* end dbCaMaximizeSeverity() */ - -/**************************************************************** -* -* Description: -* A record is being processed that has an input link that refers to a -* process variable on another physical database (another IOC). This function -* copies the value in the temporary store of the input node into the -* destination. -* -* Input: -* -* Output: None. -* -* Returns: -* any rc from dbPut() -* S_dbCa_nullarg - encountered a NULL pointer in one of the input args -* -* Notes: -* The source pvar name is used as the primary key to index the Input List -* in this file. -* This function is called by dbCaGetLink() in dbCaLink.c. -* -****************************************************************/ - -long dbCaDbPut(pdest_dbaddr, dest_revised_new_dbr_type, pval, nelements) -void *pdest_dbaddr; -short dest_revised_new_dbr_type; -void *pval; -long nelements; -{ - -long rc; - - if (pdest_dbaddr) - { - if (nelements > 0L) - { -/* printf("dbCaDbPut(): writing to >%s< link revised new dbr type %d nelements %ld\n", (((struct dbAddr *) pdest_dbaddr)->precord)->name, dest_revised_new_dbr_type, nelements); */ - if (pval) - /* this stuff is copied from dbPutField() without */ - /* honoring the ascii definition process passive */ - /* for writing to this field within the record. */ - /* */ - /* since this function is called during record */ - /* processing, it is assumed that the record has */ - /* been successfully locked. */ - - rc = dbPut((struct dbAddr *) pdest_dbaddr, - dest_revised_new_dbr_type, (caddr_t) pval, nelements); - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, "ERROR: dbCaDbPut() got NULL pval"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaDbPut() got non-positive nelements"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, "ERROR: dbCaDbPut() got NULL ppdest_dbaddr"); - } /* endif */ - - return rc; - -} /* end dbCaDbPut() */ - -/**************************************************************** -* -* Description: -* -* Input: -* -* Output: -* -* Returns: -* -* Logic: -* -* Notes: -* Typically this routine is called from a place that has no -* knowledge about struct dbAddr, therefore pdbaddr comes in as -* a void *. -* -****************************************************************/ - -long dbCaNelementsFromDbAddr(pdbaddr) -void *pdbaddr; -{ - -long rc; - - if (pdbaddr) - rc = ((struct dbAddr *) pdbaddr)->no_elements; - else - rc = -1L; - - return rc; - -} /* end dbCaNelementsFromDbAddr() */ - -/**************************************************************** -* -* short dbCaNewDbfToNewDbr(new_dbf_type) -* short new_dbf_type; -* -* Description: -* This function converts DBF_XXX -> DBR_XXX both using new db technology. -* -* Input: -* short new_dbf_type DBF type to be converted. -* -* Output: None. -* -* Returns: -* -1 - conversion failed -* new DBR type -* -* Notes: -* It is assumed that -1 is an invalid new DBR type and that DBF_INT and -* DBF_SHORT are defined to be the same thing. -* -****************************************************************/ - -short dbCaNewDbfToNewDbr(new_dbf_type) -short new_dbf_type; -{ - - return ((short) DBF_TO_DBR(new_dbf_type)); - -} /* end dbCaNewDbfToNewDbr() */ - -/**************************************************************** -* -* short dbCaNewDbrToOldDbr(new_dbr_type) -* short new_dbr_type; -* -* Description: -* This function converts new DBR_XXX types old DBR_XXX types. -* -* Input: -* short new_dbr_type new DBR type to be converted -* -* Output: None. -* -* Returns: -* -1 - conversion failed -* old DBR type -* -* Notes: -* It is assumed that -1 is an invalid old DBR type and that DBR_INT and -* DBR_SHORT are defined to be the same thing. -* -****************************************************************/ - -short dbCaNewDbrToOldDbr(new_dbr_type) -short new_dbr_type; -{ - -short old_dbr_type; - - switch (new_dbr_type) - { - case DBR_STRING: old_dbr_type = oldDBR_STRING; break; - case DBR_CHAR: old_dbr_type = oldDBR_CHAR; break; - /* case DBR_UCHAR: old_dbr_type = oldDBR_CHAR; break; */ - case DBR_UCHAR: old_dbr_type = oldDBR_SHORT; break; - case DBR_SHORT: old_dbr_type = oldDBR_SHORT; break; - /* case DBR_USHORT: old_dbr_type = oldDBR_ENUM; break; */ - case DBR_USHORT: old_dbr_type = oldDBR_LONG; break; - case DBR_LONG: old_dbr_type = oldDBR_LONG; break; - case DBR_ULONG: old_dbr_type = oldDBR_LONG; break; - case DBR_FLOAT: old_dbr_type = oldDBR_FLOAT; break; - case DBR_DOUBLE: old_dbr_type = oldDBR_DOUBLE; break; - case DBR_ENUM: old_dbr_type = oldDBR_ENUM; break; - - /* Unrecognizable ... don't know what to do for now */ - default: old_dbr_type = -1; break; - } /* end switch() */ - - return old_dbr_type; - -} /* end dbCaNewDbrToOldDbr() */ - -/**************************************************************** -* -* short dbCaOldDbrToNewDbr(new_dbr_type) -* short new_dbr_type; -* -* Description: -* This function converts old DBR_XXX types new DBR_XXX types. -* -* Input: -* short old_dbr_type old DBR type to be converted -* -* Output: None. -* -* Returns: -* -1 - conversion failed -* new DBR type -* -* Notes: -* It is assumed that -1 is an invalid new DBR type and that oldDBR_INT and -* oldDBR_SHORT are defined to be the same thing. -* -****************************************************************/ - -short dbCaOldDbrToNewDbr(old_dbr_type) -short old_dbr_type; -{ - -short new_dbr_type; - - switch (old_dbr_type) - { - - case oldDBR_STRING: new_dbr_type = DBR_STRING; break; - /* case oldDBR_INT: */ - case oldDBR_SHORT: new_dbr_type = DBR_SHORT; break; - case oldDBR_FLOAT: new_dbr_type = DBR_FLOAT; break; - case oldDBR_ENUM: new_dbr_type = DBR_ENUM; break; - case oldDBR_CHAR: new_dbr_type = DBR_UCHAR; break; - case oldDBR_LONG: new_dbr_type = DBR_LONG; break; - case oldDBR_DOUBLE: new_dbr_type = DBR_DOUBLE; break; - - /* Unrecognizable ... don't know what to do for now */ - default: new_dbr_type = -1; break; - } /* end switch() */ - - return new_dbr_type; - -} /* end dbCaOldDbrToNewDbr() */ - -/**************************************************************** -* -* short dbCaOldDbrToOldDbrSts(old_dbr_type) -* short old_dbr_type; -* -* Description: -* This function converts old DBR_XXX types to old DBR_STS_XXX types. -* -* Input: -* short old_dbr_type old DBR type to be converted -* -* Output: None. -* -* Returns: -* -1 - conversion failed -* old DBR_STS type -* -* Logic: -* convert -* -* Notes: -* It is assumed that -1 is an invalid old DBR_STS type and that oldDBR_INT -* and oldDBR_SHORT are defined to be the same thing. -* -****************************************************************/ - -short dbCaOldDbrToOldDbrSts(old_dbr_type) -short old_dbr_type; -{ - -short old_dbr_sts_type; - - switch (old_dbr_type) - { - - case oldDBR_STRING: old_dbr_sts_type = oldDBR_STS_STRING; break; - /* case oldDBR_INT: */ - case oldDBR_SHORT: old_dbr_sts_type = oldDBR_STS_SHORT; break; - case oldDBR_FLOAT: old_dbr_sts_type = oldDBR_STS_FLOAT; break; - case oldDBR_ENUM: old_dbr_sts_type = oldDBR_STS_ENUM; break; - case oldDBR_CHAR: old_dbr_sts_type = oldDBR_STS_CHAR; break; - case oldDBR_LONG: old_dbr_sts_type = oldDBR_STS_LONG; break; - case oldDBR_DOUBLE: old_dbr_sts_type = oldDBR_STS_DOUBLE; break; - - /* Unrecognizable ... don't know what to do for now */ - default: old_dbr_sts_type = -1; break; - } /* end switch() */ - - return old_dbr_sts_type; - -} /* end dbCaOldDbrToOldDbrSts() */ - -/**************************************************************** -* -* Description: -* -* Input: -* -* Output: -* -* Returns: -* -* Logic: -* -* Notes: -* Typically this routine is called from a place that has no -* knowledge about struct dbCommon, therefore precord comes in as -* a void *. -* -****************************************************************/ - -char *dbCaRecnameFromDbCommon(precord) -void *precord; -{ - -char *rc; - - if (precord) - rc = ((struct dbCommon *) precord)->name; - else - rc = (char *) NULL; - - return rc; - -} /* end dbCaRecnameFromDbCommon() */ diff --git a/src/db/dbCaLink.c b/src/db/dbCaLink.c deleted file mode 100644 index 77d74d1ad..000000000 --- a/src/db/dbCaLink.c +++ /dev/null @@ -1,2366 +0,0 @@ -/* dbCaLink.c */ -/* share/src/db @(#)dbCaLink.c 1.8 2/3/94 */ - -/**************************************************************** -* -* Author: Nicholas T. Karonis -* Date: 01-01-92 -* -* Experimental Physics and Industrial Control System (EPICS) -* -* Copyright 1991, the Regents of the University of California, -* and the University of Chicago Board of Governors. -* -* This software was produced under U.S. Government contracts: -* (W-7405-ENG-36) at the Los Alamos National Laboratory, -* and (W-31-109-ENG-38) at Argonne National Laboratory. -* -* Initial development by: -* The Controls and Automation Group (AT-8) -* Ground Test Accelerator -* Accelerator Technology Division -* Los Alamos National Laboratory -* -* Co-developed with -* The Controls and Computing Group -* Accelerator Systems Division -* Advanced Photon Source -* Argonne National Laboratory -* -* Modification Log: -* ----------------- -* .01 07-16-92 jba changed VALID_ALARM to INVALID_ALARM -* .01 07-16-92 jba changes made to remove compile warning msgs -* -****************************************************************/ - -#include -#include - -#include -#include -#include - -/* needed for calloc */ -#include - -/* needed for sprintf */ -#include - -/* needed for vxTas */ -#include - -/* needed for PVNAME_SZ and FLDNAME_SZ */ -#include - -/* needed for struct link */ -#include - -/* needed for FastLock stuff */ -#include - -/* needed for alarm handling */ -#include - -/* needed for spawnTask priority parms */ -#include - -/* needed for #define memcpy() */ -#include - -#include - -#include -#include - -#define PVARNAMELENGTH ((PVNAME_SZ)+(FLDNAME_SZ)+2) -#define NODESPERCALLOC 10 - -#define BOOL char - -/*******************/ -/* */ -/* Data Structures */ -/* */ -/*******************/ - -/* for input links */ - -struct input_pvar -{ - struct input_pvar *next; - void *pdest_dbaddr; - char source_name[PVARNAMELENGTH]; - chid cid; - char dest_name[PVARNAMELENGTH]; - void *pvalue; - short dest_old_dbr_type; - short dest_old_dbr_sts_type; /* for checking in my_event_handler() */ - short revised_dest_new_dbr_type; - unsigned short source_severity; - int dest_old_dbr_element_size; /* for calloc() and memcpy() */ - FAST_LOCK lock; - BOOL maximize_severity; - BOOL needs_reading; - long dest_nelements; /* for calloc() and check in my_event_handler() */ - long last_rcvd_nelements; /* set in my_event_handler() and used in */ - /* dbCaGetLink()'s call to dbCaDbPut() */ -}; /* end struct input_pvar */ - -/* for output links */ - -struct output_pvar -{ - struct output_pvar *next; - struct output_pvar *write_next; - void *psource_dbaddr; - void *pvalue; - char dest_name[PVARNAMELENGTH]; - char source_name[PVARNAMELENGTH]; - chid cid; - short source_old_dbr_type; /* for output demon ca_put() */ - short source_new_dbr_type; /* for dbCaPutLink() call to dbGet() */ - short revised_source_new_dbr_type; - FAST_LOCK lock; - BOOL valid_value; - BOOL on_writelist; - long source_nelements; /* for calloc() and check on dbCaPutLink() */ - long last_nelements_written; /* set by dbCaPutLink(); ca_array_put() uses */ -}; /* end struct output_pvar */ - -/*******************************/ -/* */ -/* Internally Global Variables */ -/* */ -/*******************************/ - -static struct input_pvar *Input_pvar_avail_hdr; -static struct input_pvar *Pvar_inputlist_hdr; - -static struct output_pvar *Output_pvar_avail_hdr; -static struct output_pvar *Pvar_outputlist_hdr; -static struct output_pvar *Pvar_writelist_hdr; -static struct output_pvar *Pvar_disconnectedlist_hdr; - -static FAST_LOCK Buffer; - -/* Binary Semaphore to signal inspect Pvar_outputlist_hdr */ -/* static FAST_LOCK LookAtBuffer; */ -static SEM_ID LookAtBuffer; - -/****************************************/ -/* */ -/* Externally Visibile Remote Functions */ -/* */ -/****************************************/ - -/* in dbCaDbLink.c */ - -long dbCaNameToAddr(); -long dbCaCopyPvar(); -long dbCaMaximizeSeverity(); -long dbCaDbPut(); -short dbCaNewDbfToNewDbr(); /* conversion */ -/* these two should go away when channel access understands new db technology */ -short dbCaNewDbrToOldDbr(); /* conversion */ -short dbCaOldDbrToNewDbr(); /* conversion */ -short dbCaOldDbrToOldDbrSts(); /* conversion */ -/* these should be part of db access ... currently in dbCaDbLink.c */ -char *dbCaRecnameFromDbCommon(); -short dbCaDbfFromDbAddr(); -long dbCaNelementsFromDbAddr(); - -/**************************************/ -/* */ -/* Externally Visible Local Functions */ -/* */ -/**************************************/ - -long dbCaAddInlink(); /* called for each input CA_LINK DURING rec init */ -long dbCaAddOutlink(); /* called for each output CA_LINK DURING rec init */ -long dbCaGetLink(); /* called by rec proc when inputing on CA_LINK */ -void dbCaLinkInit(); /* called once BEFORE any rec init */ -void dbCaProcessInlinks(); /* SPAWNED once AFTER all rec init */ -void dbCaProcessOutlinks(); /* SPAWNED once AFTER all rec init */ -long dbCaPutLink(); /* called by rec proc when outputing on CA_LINK */ - -/***************************/ -/* */ -/* Private Local Functions */ -/* */ -/***************************/ - -static long flush_channel_request_buffer(); -static void init_global_vars(); -static void my_connection_handler(); -static void my_event_handler(); -static struct input_pvar *pop_input_pvar(); -static struct output_pvar *pop_output_pvar(); -static long process_asynch_events(); -static void process_asynch_events_task(); -static void push_input_pvar(); -static void push_output_pvar(); -static long queue_add_event_from_input_pvar(); -static long queue_ca_array_put(); -static long queue_ca_build_and_connect(); -static long queue_ca_search(); -static long task_initialize_channel_access(); - -/**************************************************************** -* -* EXTERNALLY VISIBLE FUNCTIONS -* -****************************************************************/ - -/**************************************************************** -* -* long dbCaAddInlink(plink, precord, dest_fieldname) -* struct link *plink; -* void *precord; -* char *dest_fieldname; -* -* Description: -* During record initialization a record was found to have an input link -* whose source is in a different physical database (on another IOC). This -* function registers that input link as remote and changes he link type from -* PV_LINK to CA_LINK. -* -* Input: -* struct link *plink pointer to input link structure -* char *dest_recname name of destination record -* char *dest_fieldname name of destiantion field -* short dest_new_dbf_type dest DBF type using NEW db technology -* int dest_fld_size size of destination field -* -* Output: None. -* -* Returns: -* any rc from dbNameToAddr() -* S_dbCa_nullarg - received a NULL pointer in one of the input args -* S_dbCa_failedmalloc - could not dynamically allocate memory -* -* Notes: -* In registering this input link, the db address of the destination process -* variable is recorded in a separate list through a function call to -* dbCaNameToAddr() found in dbCaLink.c. -* -****************************************************************/ - -long dbCaAddInlink(plink, pdest_record, dest_fieldname) -struct link *plink; -void *pdest_record; -char *dest_fieldname; -{ - -struct input_pvar *pi; -char *dest_recname; -char errmsg[100]; -long rc; - - if (plink) - { - if (pdest_record) - { - if (dest_fieldname) - { - if (pi = pop_input_pvar()) - { - if (dest_recname = dbCaRecnameFromDbCommon(pdest_record)) - { - /* moving dest name into struct input_pvar */ - strncpy(pi->dest_name, dest_recname, PVNAME_SZ); - pi->dest_name[PVNAME_SZ] = '\0'; - strcat(pi->dest_name, "."); - strncat(pi->dest_name, dest_fieldname, FLDNAME_SZ); - - /* in dbCaLink.c */ - rc = dbCaNameToAddr(pi->dest_name, - &(pi->pdest_dbaddr)); - - if (RTN_SUCCESS(rc)) - { - /* new DBF -> old DBR */ - pi->dest_old_dbr_type = - dbCaNewDbrToOldDbr(dbCaNewDbfToNewDbr(dbCaDbfFromDbAddr(pi->pdest_dbaddr))); - - if (dbr_type_is_valid(pi->dest_old_dbr_type)) - { - pi->revised_dest_new_dbr_type = - dbCaOldDbrToNewDbr(pi->dest_old_dbr_type); - - pi->dest_old_dbr_element_size = - (int) dbr_size[pi->dest_old_dbr_type]; - - if ((pi->dest_nelements = - dbCaNelementsFromDbAddr(pi->pdest_dbaddr)) - != -1L) - { - /* memory allocation */ - if (pi->pvalue = - (void *) calloc ((unsigned int) pi->dest_nelements, - (unsigned) pi->dest_old_dbr_element_size)) - { -/* printf("dbCaAddInlink(): nelements %d * dest old dbr size %d = %d bytes at starting at >%x<\n", (unsigned int) pi->dest_nelements, (unsigned) pi->dest_old_dbr_element_size, (unsigned int) pi->dest_nelements * (unsigned) pi->dest_old_dbr_element_size, pi->pvalue); */ - - /* old DBR -> old DBR_STS */ - pi->dest_old_dbr_sts_type = - dbCaOldDbrToOldDbrSts(pi->dest_old_dbr_type); - - /* moving source name */ - /* into struct input_pvar */ - strcpy(pi->source_name, - plink->value.pv_link.pvname); - - /* preserving MS/NMS specification */ - if (plink->value.pv_link.maximize_sevr) - pi->maximize_severity = TRUE; - else - pi->maximize_severity = FALSE; - - /* pushing this input_pvar */ - /* onto the list */ - - pi->next = Pvar_inputlist_hdr; - Pvar_inputlist_hdr = pi; - - /* changing the link type and */ - /* connecting this input_pvar */ - /* the the struct link */ - - plink->type = CA_LINK; - plink->value.ca_link = (void *) pi; - } - else - { - rc = S_dbCa_failedmalloc; - sprintf(errmsg, - "ERROR: dbCaAddInlink() unable to calloc %d bytes for pvalue", - pi->dest_nelements * pi->dest_old_dbr_element_size); - errMessage(S_dbCa_failedmalloc, errmsg); - - push_input_pvar(pi); - } /* endif */ - } - else - { - rc = S_dbCa_dbfailure; - - errMessage(S_dbCa_dbfailure, - "ERROR: dbCaAddInlink() unable to find nelements"); - - push_input_pvar(pi); - } /* endif */ - } - else - { - rc = S_dbCa_dbfailure; - - errMessage(S_dbCa_dbfailure, - "ERROR: dbCaAddInlink() unable to convert new DBF->old DBR"); - - push_input_pvar(pi); - } /* endif */ - } - else - { - rc = S_dbCa_dbfailure; - - sprintf(errmsg, - "ERROR: dbCaAddInlink() unable to find db addr for >%s<", - pi->dest_name); - errMessage(S_dbCa_dbfailure, errmsg); - - push_input_pvar(pi); - } /* endif */ - } - else - { - rc = S_dbCa_dbfailure; - errMessage(S_dbCa_dbfailure, - "ERROR: dbCaAddInlink() found NULL dest_recname"); - - push_input_pvar(pi); - } /* endif */ - } - else - { - rc = S_dbCa_failedmalloc; - errMessage(S_dbCa_failedmalloc, - "ERROR: dbCaAddInlink() could not pop_input_pvar()"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaAddInlink() got NULL dest_fieldname"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaAddInlink() got NULL pdest_record"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaAddInlink() got NULL plink"); - } /* endif */ - - return rc; - -} /* end dbCaAddInlink() */ - -/**************************************************************** -* -* Description: -* During record initialization a record was found to have an output link -* whose destination is in a different physical database (on another IOC). This -* function registers that output link as remote and changes he link type from -* PV_LINK to CA_LINK. -* -* Input: -* struct link *plink pointer to output link structure -* char *source_recname name of source record -* char *source_fieldname name of source field -* short source_new_dbf_type source DBF type using NEW db technology -* int source_fld_size size of source field -* -* Output: None. -* -* Returns: -* any rc from dbNameToAddr() -* S_dbCa_nullarg - received a NULL pointer in one of the input args -* S_dbCa_failedmalloc - could not dynamically allocate memory -* -* Notes: -* In registering this output link, the db address of the source process -* variable is recorded in a separate list through a function call to -* dbCaNameToAddr() found in dbCaLink.c. -* -****************************************************************/ - -long dbCaAddOutlink(plink, psource_record, source_fieldname) -struct link *plink; -void *psource_record; -char *source_fieldname; -{ - -struct output_pvar *po; -int source_old_dbr_element_size; -char *source_recname; -char errmsg[100]; -long rc; - - if (plink) - { - if (psource_record) - { - if (source_fieldname) - { - if (po = pop_output_pvar()) - { - if (source_recname = - dbCaRecnameFromDbCommon(psource_record)) - { - /* moving source name into struct output_pvar */ - - strncpy(po->source_name, source_recname, PVNAME_SZ); - po->source_name[PVNAME_SZ] = '\0'; - strcat(po->source_name, "."); - strncat(po->source_name, source_fieldname, FLDNAME_SZ); - - /* in dbCaDblink.c */ - rc = dbCaNameToAddr(po->source_name, - &(po->psource_dbaddr)); - - if (RTN_SUCCESS(rc)) - { - /* new DBF -> old DBR */ - po->source_old_dbr_type = - dbCaNewDbrToOldDbr( - dbCaNewDbfToNewDbr( - dbCaDbfFromDbAddr(po->psource_dbaddr))); - - if (dbr_type_is_valid(po->source_old_dbr_type)) - { - po->revised_source_new_dbr_type = - dbCaOldDbrToNewDbr(po->source_old_dbr_type); - - source_old_dbr_element_size = - (int) dbr_size[po->source_old_dbr_type]; - - if ((po->source_nelements = - dbCaNelementsFromDbAddr(po->psource_dbaddr)) - != -1L) - { - /* memory allocation */ - if (po->pvalue = - (void *) calloc ((unsigned int) po->source_nelements, - (unsigned) source_old_dbr_element_size)) - { - /* moving dest name into */ - /* struct output_pvar */ - - strcpy(po->dest_name, - plink->value.pv_link.pvname); - /* for dbGet() */ - po->source_new_dbr_type = - dbCaNewDbfToNewDbr( - dbCaDbfFromDbAddr( - po->psource_dbaddr)); - - po->valid_value = FALSE; - po->on_writelist = FALSE; - - /* pushing this output_pvar */ - /* onto the list */ - - po->next = Pvar_outputlist_hdr; - Pvar_outputlist_hdr = po; - - /* changing the link type and */ - /* connecting this output_pvar */ - /* the the struct link */ - - plink->type = CA_LINK; - plink->value.ca_link = (void *) po; - } - else - { - rc = S_dbCa_failedmalloc; - - sprintf(errmsg, - "ERROR: dbCaAddOutlink() could not calloc %d bytes for pvar", - po->source_nelements*source_old_dbr_element_size); - errMessage(S_dbCa_failedmalloc, errmsg); - - push_output_pvar(po); - - } /* endif */ - } - else - { - rc = S_dbCa_dbfailure; - - errMessage(S_dbCa_dbfailure, - "ERROR: dbCaAddOutlink() unable to find nelements"); - - push_output_pvar(po); - - } /* endif */ - } - else - { - rc = S_dbCa_dbfailure; - - errMessage(S_dbCa_dbfailure, - "ERROR: dbCaAddOutlink() unable to convert new DBF->old DBR"); - - push_output_pvar(po); - - } /* endif */ - } - else - { - push_output_pvar(po); - } /* endif */ - - } - else - { - rc = S_dbCa_dbfailure; - errMessage(S_dbCa_dbfailure, - "ERROR: dbCaAddInlink() found NULL dest_recname"); - - push_output_pvar(po); - - } /* endif */ - } - else - { - rc = S_dbCa_failedmalloc; - - errMessage(S_dbCa_failedmalloc, - "ERROR: dbCaAddOutlink() could not pop_output_pvar()"); - } /* endif */ - - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaAddOutlink() NULL source_fieldname"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaAddOutlink() NULL psource_record"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaAddOutlink() got NULL plink"); - } /* endif */ - - return rc; - -} /* end dbCaAddOutlink() */ - -/**************************************************************** -* -* long dbCaGetLink(plink) -* struct link *plink; -* -* Description: -* A record is being processed that has an input link that refers to a -* process variable on another physical database (another IOC). This function -* copies the value in the temporary store of the input node into the -* destination. If MS is specified on this link, the severity of the source -* record is appropriately propogated to the destination record. -* -* Input: -* struct link *plink pointer to input link structure -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_nullarg - received a NULL pointer in one of the input args -* S_dbCa_foundnull - found a NULL pointer where one should not be -* any rc from dbPut() -* -* Notes: -* Presumably this link was properly registered during record initialization -* by calling dbCaAddInlink(). If the monitor connection is broken, an alarm -* condition is raised and no data is transferred. The value is only copied -* from the temporary store to the destination if its value changed since the -* last read. In copying the value from the temporary store to the destination, -* a call is made to dbCaDbPut() in dbCaDbLink.c which ultimately calls dbPut(). -* -****************************************************************/ - -long dbCaGetLink(plink) -struct link *plink; -{ - -struct input_pvar *pi; -long rc; - -/* printf("ENTER dbCaGetLink()\n"); */ - if (plink) - { - if (pi = (struct input_pvar *) plink->value.ca_link) - { - - FASTLOCK(&(pi->lock)); - - if (ca_field_type(pi->cid) == TYPENOTCONN) - /* channel is disconnected. either */ - /* NEVER connected or LOST connection. */ - - /* in dbCaDblink.c */ - rc = dbCaMaximizeSeverity(pi->pdest_dbaddr, - (unsigned short) INVALID_ALARM, (unsigned short) LINK_ALARM); - else - { -/* printf("dbCaGetLink() found channel connected and needs_reading %c\n", (pi->needs_reading ? 'T' :'F')); */ - rc = 0L; - - if (pi->maximize_severity) /* if input link is MS */ - /* in dbCaDblink.c */ - rc = dbCaMaximizeSeverity(pi->pdest_dbaddr, - pi->source_severity, (unsigned short) LINK_ALARM); - - if (RTN_SUCCESS(rc) && pi->needs_reading) - { -/* printf("dbCaGetLink() calling dbCaDbPut() sourceaddr >%x<\n", pi->pvalue); */ - pi->needs_reading = FALSE; - - /* in dbCaDbLink.c */ - rc = dbCaDbPut(pi->pdest_dbaddr, - pi->revised_dest_new_dbr_type, pi->pvalue, - pi->last_rcvd_nelements); - } /* endif */ - } /* endif */ - - FASTUNLOCK(&(pi->lock)); - } - else - { - rc = S_dbCa_foundnull; - errMessage(S_dbCa_foundnull, "ERROR: dbCaGetLink() got NULL pi"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, "ERROR: dbCaGetLink() found NULL plink"); - } /* endif */ - -/* printf("EXIT dbCaGetLink()\n"); */ - return rc; - -} /* end dbCaGetLink() */ - -/**************************************************************** -* -* void dbCaLinkInit(count) -* int count; -* -* Description: -* This function is called twice during IOC initialization. The first time -* it is called it initializes the all the appropriate memory. The second time -* it is called it spawns two new vxWorks tasks, one to process remote input -* links and the other to process remote output links. -* -* Input: -* int count indicates which call this is (count = {1,2}) -* -* Output: None. -* -* Returns: None. -* -* Notes: -* The first call is this function is made at the beginning of IOC -* initialization and the second call is made at the very end of IOC -* initialization. During its first invocation, a call is made to -* dbCaDbInlinkInit() in dbCaDblink.c to initialize that environment as well. -* -****************************************************************/ - -void dbCaLinkInit(count) -int count; -{ - - if (count == 1) - init_global_vars(); - - if (count == 2) - { - taskSpawn(DB_CA_INPUT_NAME, DB_CA_INPUT_PRI, DB_CA_INPUT_OPT, - DB_CA_INPUT_STACK, (FUNCPTR) dbCaProcessInlinks, - 0,0,0,0,0,0,0,0,0,0); - - taskSpawn(DB_CA_OUTPUT_NAME, DB_CA_OUTPUT_PRI, DB_CA_OUTPUT_OPT, - DB_CA_OUTPUT_STACK, (FUNCPTR) dbCaProcessOutlinks, - 0,0,0,0,0,0,0,0,0,0); - } /* endif */ - -} /* end dbCaLinkInit() */ - -/**************************************************************** -* -* void dbCaProcessInlinks() -* -* Description: -* This function is spawned during IOC initialization (initRecSup()) AFTER -* processing all record initialization routines. It process input links that -* originate on remote process variables. -* -* This function establishes monitors on the remote source process -* variables and registers the my_event_handler() and the event handler routine. -* It then waits forever for events to occur. -* -* Input: None. -* -* Output: None. -* -* Returns: None. -* -* Notes: -* If the database on this IOC does NOT have any input links that refer to -* remote pvars, this function ends immediately and the spawned vxWorks task -* dies. Either this function terminates immediately or it never terminates. -* -****************************************************************/ - -void dbCaProcessInlinks() -{ - -struct input_pvar *pi; -long status; - - if (Pvar_inputlist_hdr) - { - /* have at least one remote db input link */ - - status = task_initialize_channel_access(); - - /* queueing ca_search()'s */ - - for (pi = Pvar_inputlist_hdr; - RTN_SUCCESS(status) && pi; - pi = pi->next) - status = queue_ca_search(pi->source_name, &(pi->cid)); - - if (RTN_SUCCESS(status)) - { - status = flush_channel_request_buffer(); - - for (pi = Pvar_inputlist_hdr; - RTN_SUCCESS(status) && pi; - pi = pi->next) - status = queue_add_event_from_input_pvar(pi); - - if (RTN_SUCCESS(status)) - if (RTN_SUCCESS(flush_channel_request_buffer())) - process_asynch_events((float) 0); - } /* endif */ - } /* endif */ - -} /* end dbCaProcessInlinks() */ - -/**************************************************************** -* -* void dbCaProcessOutlinks() -* -* Description: -* This function is spawned during IOC initialization (initRecSup()) AFTER -* processing all record initialization routines. It process output links that -* refer to remote process variables. This function is the output demon. -* -* This function establishes the connections to the remote destination -* process variables and registers my_connection_handler() as the connection -* hanlder routine for each connection. It then waits to be signaled. Once -* signaled, it writes all the values in Write List returns the nodes in the -* Write List back to the Output List. -* -* Input: None. -* -* Output: None. -* -* Returns: None. -* -* Notes: -* If the database on this IOC does NOT have any output links that refer -* to remote pvars, this function ends immediately and the spawned vxWorks task -* dies. Either this function terminates immediately or it never termintates. -* -* This function is signaled during record processing to inspect the nodes -* on the Write List. There is no guarantee that the connections will be in -* tact. Nodes whose connections are broken are placed onto the Disconnected -* List (temporarily) and returned to the Write List (not the Output List) -* at the end. When connections are re-established, the connection handler -* my_connection_handler() signals this function to inspect the Write List -* again. -* -****************************************************************/ - -void dbCaProcessOutlinks() -{ - -struct output_pvar *po; -long status; -BOOL done; - - - if (Pvar_outputlist_hdr) - { - /* have at least one remote db output link */ - - status = task_initialize_channel_access(); - - taskSpawn(DB_CA_PROC_ASYNCH_EV_TASK_NAME, DB_CA_PROC_ASYNCH_EV_TASK_PRI, - DB_CA_PROC_ASYNCH_EV_TASK_OPT, DB_CA_PROC_ASYNCH_EV_TASK_STACK, - (FUNCPTR) process_asynch_events_task, taskIdSelf(), - 0,0,0,0,0,0,0,0,0); - - /* queueing ca_build_and_connect()'s */ - - for (po = Pvar_outputlist_hdr; - RTN_SUCCESS(status)&& po; - po = po->next) - status = queue_ca_build_and_connect(po); - - if (RTN_SUCCESS(status)) - status = flush_channel_request_buffer(); - -/* printf("\n-- ENTERING OUTLINK MAIN LOOP\n\n"); */ - - while (RTN_SUCCESS(status)) - { - - /* P(LookAtBuffer) */ - /* FASTLOCK(&LookAtBuffer); */ - semTake(LookAtBuffer, WAIT_FOREVER); -/* printf("Output demon just woke up\n"); */ - - /* grabbing ALL the nodes in the writelist list ... one at a time */ - - done = FALSE; - - while (!done && RTN_SUCCESS(status)) - { - FASTLOCK(&Buffer); - if (po = Pvar_writelist_hdr) - Pvar_writelist_hdr = po->write_next; - FASTUNLOCK(&Buffer); - - if (po) - { - FASTLOCK(&(po->lock)); - - if (po->valid_value) - { - /* we have a valid value here ... needs to be written */ - if (ca_field_type(po->cid) == TYPENOTCONN) - { - /* raising an alarm disconnected */ - status = dbCaMaximizeSeverity(po->psource_dbaddr, - (unsigned short) INVALID_ALARM, - (unsigned short) LINK_ALARM); - - /* pushing this node onto the disconnected list */ - po->write_next = Pvar_disconnectedlist_hdr; - Pvar_disconnectedlist_hdr = po; - } - else - { - po->on_writelist = FALSE; -/* printf("Output demon just before ca_array_put()\n"); */ - status = queue_ca_array_put(po); - if (RTN_SUCCESS(status)) - status = flush_channel_request_buffer(); - } /* endif */ - } - else - /* the value here is invalid ... */ - /* simply remove node from writelist */ - po->on_writelist = FALSE; - - FASTUNLOCK(&(po->lock)); - } - else - done = TRUE; - } /* endwhile */ - - /* moving the nodes on the disconnected */ - /* list back onto the writelist */ - if (RTN_SUCCESS(status) && Pvar_disconnectedlist_hdr) - { - - /* there are nodes on the disconnected list */ - - FASTLOCK(&Buffer); - - if (Pvar_writelist_hdr) - { - /* moving nodes one at a time */ - while (Pvar_disconnectedlist_hdr) - { - po = Pvar_disconnectedlist_hdr; - Pvar_disconnectedlist_hdr = po->write_next; - - po->write_next = Pvar_writelist_hdr; - Pvar_writelist_hdr = po; - } /* endwhile */ - } - else - { - /* moving the whole list at once */ - Pvar_writelist_hdr = Pvar_disconnectedlist_hdr; - Pvar_disconnectedlist_hdr = (struct output_pvar *) NULL; - } /* endif */ - - FASTUNLOCK(&Buffer); - - } /* endif */ - } /* endwhile */ - } /* endif */ - -/* printf("dbCaProcessOutlinks() FOUND NO REMOTE OUTPUT PVARS\n"); */ - -} /* end dbCaProcessOutlinks() */ - -/**************************************************************** -* -* long dbCaPutLink(plink, poptions, pnrequest) -* struct link *plink; -* long *poptions; -* long *pnrequest; -* -* Description: -* A record is being processed that has an output link that refers to a -* process variable on another physical database (another IOC). This function -* copies the value from the source pvar into the temporary store of the output -* node. It then places the output node onto the Write List and signals the -* output demon (dbCaProcessOutlinks()). -* -* Input: -* struct link *plink pointer to output link structure -* long *poptions as passed to dbGet() -* long *pnrequest as passed to dbGet() -* -* Output: None. -* -* Returns: -* 0 - Success or raised alarm -* S_dbCa_nullarg - received a NULL pointer in one of the input args -* S_dbCa_foundnull - found a NULL pointer where one should not be -* any rc from dbGet() -* -* Notes: -* Presumably this link was properly registered during record initialization -* by calling dbCaAddOutlink(). In copying the value from the source pvar to -* the temporary store, a call is made to dbCaCopyPvar() in dbCaDblink.c which -* ultimately makes a call to dbGet(), hence the need for the two arguments -* poptions and pnrequest. -* -* The connection handler (my_connection_handler()) is called whenever -* the connection status of the channel changes. If the connection status -* goes from disconnected->connected, the connection hanlder checks if the -* value has ever been written to the remote pvar. If it has, it immediately -* schedules the nodes value to be written again, even though the record was -* not processed, and signals the output demon. Hence the need to record the -* fact that the value was ever written. -* -* As this function is called during record processing, it cannot wait for -* anything for an extended period of time. Before copying the value to the -* temporary store, it must lock the node on the Output List. This function -* is contending for the lock with the output demon and the connection handler. -* The output demon locks the node and then issues a ca_put() ... that could -* take too long. Therefore, a newly locking mechanism is employed here, -* FASTLOCKNOWAIT. It attempts to grab the LOCK. If it succeeds it returns -* TRUE. If it fails it returns FALSE. In either case, it returns immediately. -* -****************************************************************/ - -long dbCaPutLink(plink, poptions, pnrequest) -struct link *plink; -long *poptions; -long *pnrequest; -{ - -struct output_pvar *po; -char errmsg[100]; -long rc; - - if (plink) - { - if (poptions) - { - if (pnrequest) - { - if (po = (struct output_pvar *) plink->value.ca_link) - { - if (po->source_nelements <= *pnrequest) - { - /* NOTE: there are three unlocks associated with */ - /* this lock. only ONE unlock will be executed */ - /* there are three of them for an optimization */ - /* reason. We want to assure that the node is */ - /* unlocked BEFORE V(LookAtBuffer), otherwise the */ - /* other task will wake up and HAVE to switch back */ - /* to this task in order to unlock the node and then */ - /* switch back again to resume processing. */ - - if (FASTLOCKNOWAIT(&(po->lock))) - { - /* copying pvar value to output_pvar struct */ - /* in dbCaDblink.c */ -/* printf("dbCaPutLink() got LOCK and calling dbCaCopyPvar()\n"); */ - rc = dbCaCopyPvar(po->psource_dbaddr, - po->revised_source_new_dbr_type, - po->pvalue, poptions, pnrequest); - - if (RTN_SUCCESS(rc)) - { - /* successful copy */ - - /* checking if just overwrote last value that */ - /* was never sent and raising an alarm if */ - /* necessary. */ - if (po->valid_value && po->on_writelist) - /* in dbCaDblink.c */ - rc = dbCaMaximizeSeverity(po->psource_dbaddr, - (unsigned short) INVALID_ALARM, - (unsigned short) LINK_ALARM); - - po->valid_value = TRUE; - po->last_nelements_written = *pnrequest; - - if (!(po->on_writelist)) - { - /* not on writelist ... placing there */ - po->on_writelist = TRUE; - - /* placing node onto write list */ - FASTLOCK(&Buffer); - po->write_next = Pvar_writelist_hdr; - Pvar_writelist_hdr = po; - FASTUNLOCK(&Buffer); - - /* V(LookAtBuffer) awakens */ - /* ProcessOutlinks() */ - -/* printf("dbCaPutLink() V(LookAtBuffer)\n"); */ - /* FASTUNLOCK(&LookAtBuffer); */ - semGive(LookAtBuffer); - } /* endif */ - } - else - { - /* failed copy */ - po->valid_value = FALSE; - - /* raising an alarm to reflect failed copy */ - /* have (arbitrarily) decided to change the */ - /* rc in doing so ... could just as easily */ - /* not have changed the rc and returned what */ - /* was returned from dbCaCopyPvar() instead */ - /* in dbCaDblink.c */ - rc = dbCaMaximizeSeverity(po->psource_dbaddr, - (unsigned short) INVALID_ALARM, - (unsigned short) LINK_ALARM); - } /* endif */ - - FASTUNLOCK(&(po->lock)); - } - else -{ -/* printf("dbCaPutLink() could not get LOCK\n"); */ - /* could not get lock immediately */ - /* aborting write and raising an alarm */ - - /* in dbCaDblink.c */ - rc = dbCaMaximizeSeverity(po->psource_dbaddr, - (unsigned short) INVALID_ALARM, - (unsigned short) LINK_ALARM); -} - } - else - { - rc = S_dbCa_dbfailure; - sprintf(errmsg, - "ERROR: dbCaPutLink() requested %ld max %ld", - *pnrequest, po->source_nelements); - errMessage(S_dbCa_dbfailure, errmsg); - } /* endif */ - } - else - { - rc = S_dbCa_foundnull; - errMessage(S_dbCa_foundnull, - "ERROR: dbCaPutLink() found NULL po"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaPutLink() got NULL pnrequest"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaPutLink() got NULL poptions"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: dbCaPutLink() got NULL plink"); - } /* endif */ - - return rc; - -} /* end dbCaPutLink() */ - -/**************************************************************** -* -* PRIVATE FUNCTIONS -* -****************************************************************/ - -/**************************************************************** -* -* static long flush_channel_request_buffer() -* -* Description: -* Flushes the channel access buffer by calling ca_flush_io(). -* -* Input: None. -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_unknownECA - unknown status rc from ca_flush_io() -* -* Notes: None. -* -****************************************************************/ - -static long flush_channel_request_buffer() -{ - -int status; -char errmsg[100]; -long rc; - - status = ca_flush_io(); - - switch (status) - { - case ECA_NORMAL: - rc = 0L; - break; - default: - rc = S_dbCa_unknownECA; - sprintf(errmsg, - "ERROR: flush_channel_request_buffer() unrecognizable status returned %d", - status); - errMessage(S_dbCa_unknownECA, errmsg); - break; - } /* end switch() */ - - return rc; - -} /* end flush_channel_request_buffer() */ - -/**************************************************************** -* -* static void init_global_vars() -* -* Description: -* Initializes the linked list headers to NULL. Initializes the -* necessary binary semaphores appropriately. -* -* Input: None. -* -* Output: None. -* -* Returns: None. -* -* Notes: None. -* -****************************************************************/ - -static void init_global_vars() -{ - - /* Avail Headers */ - Input_pvar_avail_hdr = (struct input_pvar *) NULL; - Output_pvar_avail_hdr = (struct output_pvar *) NULL; - - /* Input List and Output List */ - Pvar_inputlist_hdr = (struct input_pvar *) NULL; - Pvar_outputlist_hdr = (struct output_pvar *) NULL; - - /* Write List and Disconnected List */ - Pvar_writelist_hdr = (struct output_pvar *) NULL; - Pvar_disconnectedlist_hdr = (struct output_pvar *) NULL; - - /* Buffer LOCK */ - FASTLOCKINIT(&Buffer); - - /* Binary Semaphore: initial value = 0 */ - /* FASTLOCKINIT(&LookAtBuffer); */ - LookAtBuffer = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY); - /* FASTLOCK(&LookAtBuffer); */ - /* semTake(LookAtBuffer, WAIT_FOREVER); */ - -} /* end init_global_vars() */ - -/**************************************************************** -* -* static void my_connection_handler(arg) -* struct connection_handler_args arg; -* -* Description: -* The connection status of one of the output channels has changed. If -* the connection has gone from disconnected->connected, this routine re-writes -* the value to the destiantion pvar. -* -* Input: -* struct connection_handler_args arg -* -* from epicsH/cadef.h -* struct connection_handler_args -* { -* chid chid; Channel id -* long op; External codes for channel access operations -* }; -* -* Output: None. -* -* Returns: None. -* -* Notes: -* No matter where the node started when this function started, if the -* connection is now in tact and the node's value was ever writen, the node -* ends up on the Write List and the output demon is signaled. -* -****************************************************************/ - -static void my_connection_handler(arg) -struct connection_handler_args arg; -{ - -struct output_pvar *po; - -/* printf("my_connection_handler() change in connection connection\n"); */ - if (arg.op == CA_OP_CONN_UP) - { -/* printf("my_connection_handler() detected DOWN--->UP\n"); */ - /* connection on this channel re-established */ - - if (po = (struct output_pvar *) ca_puser(arg.chid)) - { - - FASTLOCK(&(po->lock)); - - if (po->valid_value) - { -/* printf("my_connection_handler() value needs to be written\n"); */ - /* This value has been ca_put()'d in the past. */ - /* Need to do it now immediately to more closely */ - /* simulate database activities when all records */ - /* reside on a single IOC ... the source record */ - /* (and hence the whole database) assumes that */ - /* the target record has the last value written. */ - /* This helps to make that assumption reliable. */ - - if (!(po->on_writelist)) - { -/* printf("my_connection_handler() placing value onto writelist\n"); */ - po->on_writelist = TRUE; - - /* placing node onto write list */ - FASTLOCK(&Buffer); - po->write_next = Pvar_writelist_hdr; - Pvar_writelist_hdr = po; - FASTUNLOCK(&Buffer); - } /* endif */ - - /* optimization to place unlock here ... before */ - /* V() ... but need it after *else* also */ - - FASTUNLOCK(&(po->lock)); - -/* printf("my_connection_handler() signalling V() output demon\n"); */ - /* V(LookAtBuffer) to awaken ProcessOutlinks() */ - /* FASTUNLOCK(&LookAtBuffer); */ - semGive(LookAtBuffer); - } - else - FASTUNLOCK(&(po->lock)); - } - else - errMessage(S_dbCa_foundnull, - "ERROR: my_connection_handler() found NULL po"); - } /* endif */ - -} /* end my_connection_handler() */ - -/**************************************************************** -* -* static void my_event_handler(arg) -* struct event_handler_args arg; -* -* Description: -* This function is the user-supplied event handler routine. It gets -* called whenever the an event occurs associated with one the remote source -* pvars. It copies the value from the incoming event_handler_args to the -* temporary store of the input node. -* -* Input: -* struct event_handler_args arg -* from epicsH/cadef.h -* struct event_handler_args -* { -* void *usr; User argument supplied when event added -* chid chid; Channel id -* long type; the type of the value returned (long aligned) -* long count; the element count of the item returned -* void *dbr; Pointer to the value returned -* }; -* -* Output: None. -* -* Returns: None. -* -* Notes: -* Presumably a monitor has been established on these remote source -* pvars and a wait for events has already been issued by dbCaProcessInlinks(). -* -* After the value is copied to the temporary store, it is later read -* into the destination pvar during record processing via a call to -* dbCaGetLink(). The indication that this node's value has been changed is -* an optimization to avoid moving redundant data during record processing. -* -* arg.type is coming in as an old database DBR_STS_XXX type. We cannot -* convert it to new database DBR_XXX type here because this file only -* understands old database types as a result of including db_access.h -* -* Because the arg.type is DBR_STS_XXX type, arg.dbr is a pointer to a data -* structure that has short status, short severity, and xxxxx value. Here are -* the names of the different data structures based on the DBR_STS_XXX type as -* copied from db_access.h -* -* DBR_STS_STRING returns a string status structure (dbr_sts_string) -* DBR_STS_SHORT returns a short status structure (dbr_sts_short) -* DBR_STS_INT returns a short status structure (dbr_sts_int) -* DBR_STS_FLOAT returns a float status structure (dbr_sts_float) -* DBR_STS_ENUM returns an enum status structure (dbr_sts_enum) -* DBR_STS_CHAR returns a char status structure (dbr_sts_char) -* DBR_STS_LONG returns a long status structure (dbr_sts_long) -* DBR_STS_DOUBLE returns a double status structure (dbr_sts_double) -* -* Currently, DBR_STS_INT and DBR_STS_SHORT are defined to be the same -* thing, therefore they both cannot reside as distinct cases in the switch. -* -****************************************************************/ - -static void my_event_handler(arg) -struct event_handler_args arg; -{ - -struct input_pvar *pi; -char errmsg[100]; - -/* for debugging */ -/* -char buff[100]; -char sevr_buff[20]; -*/ -char print_line[500]; - - if (pi = (struct input_pvar *) arg.usr) - { - if (pi->pvalue) - { -/* printf("my_event_handler(): GOT dbr type %d nelements %ld EXP dbr type %d max %ld destaddr >%x<\n", arg.type, arg.count, pi->dest_old_dbr_sts_type, pi->dest_nelements, pi->pvalue); */ - /* checking that channel access gave us what we asked for */ - if (arg.type == pi->dest_old_dbr_sts_type) - { - /* checking that we did not receive */ - /* more than we allocated for */ - if (arg.count <= pi->dest_nelements) - { -/* sprintf(print_line, "my_event_handler(): spvar >%s< --> dpvar >%s< ", pi->source_name, pi->dest_name); */ - FASTLOCK(&(pi->lock)); - - switch (arg.type) - { - case DBR_STS_STRING: - pi->needs_reading = TRUE; - pi->last_rcvd_nelements = arg.count; - -/* bcopy( */ -/* (char *) ((struct dbr_sts_string *) arg.dbr)->value, */ -/* (char *) pi->pvalue, */ -/* (arg.count * pi->dest_old_dbr_element_size)); */ - memcpy( - (char *) pi->pvalue, - (char *) ((struct dbr_sts_string *) arg.dbr)->value, - (arg.count * pi->dest_old_dbr_element_size)); - pi->source_severity = - (unsigned short) ((struct dbr_sts_string *) arg.dbr)->severity; - -/* strcat(print_line, "DBR_STS_STRING "); */ -/* sprintf(buff, ">%s< ", */ -/* (char *) ((struct dbr_sts_string *) arg.dbr)->value); */ -/* strcat(print_line, buff); */ - break; - /* case DBR_STS_INT: */ - case DBR_STS_SHORT: - pi->needs_reading = TRUE; - pi->last_rcvd_nelements = arg.count; - -/* bcopy( */ -/* (char *) &(((struct dbr_sts_short *) arg.dbr)->value), */ -/* (char *) pi->pvalue, */ -/* (arg.count * pi->dest_old_dbr_element_size)); */ - memcpy( - (char *) pi->pvalue, - (char *) &(((struct dbr_sts_short *) arg.dbr)->value), - (arg.count * pi->dest_old_dbr_element_size)); - pi->source_severity = - (unsigned short) ((struct dbr_sts_short *) arg.dbr)->severity; - -/* strcat(print_line, "DBR_STS_SHORT "); */ -/* sprintf(buff, ">%d< ", */ -/* (short) ((struct dbr_sts_short *) arg.dbr)->value); */ -/* strcat(print_line, buff); */ - break; - case DBR_STS_FLOAT: - pi->needs_reading = TRUE; - pi->last_rcvd_nelements = arg.count; - -/* bcopy( */ -/* (char *) &(((struct dbr_sts_float *) arg.dbr)->value), */ -/* (char *) pi->pvalue, */ -/* (arg.count * pi->dest_old_dbr_element_size)); */ - memcpy( - (char *) pi->pvalue, - (char *) &(((struct dbr_sts_float *) arg.dbr)->value), - (arg.count * pi->dest_old_dbr_element_size)); - pi->source_severity = - (unsigned short) ((struct dbr_sts_float *) arg.dbr)->severity; - -/* strcat(print_line, "DBR_STS_FLOAT "); */ -/* sprintf(buff, ">%f< ", */ -/* (float) ((struct dbr_sts_float *) arg.dbr)->value); */ -/* strcat(print_line, buff); */ - break; - case DBR_STS_ENUM: - pi->needs_reading = TRUE; - pi->last_rcvd_nelements = arg.count; - -/* bcopy( */ -/* (char *) &(((struct dbr_sts_enum *) arg.dbr)->value), */ -/* (char *) pi->pvalue, */ -/* (arg.count * pi->dest_old_dbr_element_size)); */ - memcpy( - (char *) pi->pvalue, - (char *) &(((struct dbr_sts_enum *) arg.dbr)->value), - (arg.count * pi->dest_old_dbr_element_size)); - pi->source_severity = - (unsigned short) ((struct dbr_sts_enum *) arg.dbr)->severity; - -/* strcat(print_line, "DBR_STS_SHORT "); */ -/* sprintf(buff, ">%d< ", */ -/* (short) ((struct dbr_sts_enum *) arg.dbr)->value); */ -/* strcat(print_line, buff); */ - break; - case DBR_STS_CHAR: - pi->needs_reading = TRUE; - pi->last_rcvd_nelements = arg.count; - -/* bcopy( */ -/* (char *) &(((struct dbr_sts_char *) arg.dbr)->value), */ -/* (char *) pi->pvalue, */ -/* (arg.count * pi->dest_old_dbr_element_size)); */ - memcpy( - (char *) pi->pvalue, - (char *) &(((struct dbr_sts_char *) arg.dbr)->value), - (arg.count * pi->dest_old_dbr_element_size)); - pi->source_severity = - (unsigned short) ((struct dbr_sts_char *) arg.dbr)->severity; - -/* strcat(print_line, "DBR_STS_CHAR "); */ -/* sprintf(buff, ">%c< ", */ -/* (unsigned char) ((struct dbr_sts_char *) arg.dbr)->value); */ - break; - case DBR_STS_LONG: - pi->needs_reading = TRUE; - pi->last_rcvd_nelements = arg.count; - -/* bcopy( */ -/* (char *) &(((struct dbr_sts_long *) arg.dbr)->value), */ -/* (char *) pi->pvalue, */ -/* (arg.count * pi->dest_old_dbr_element_size)); */ - memcpy( - (char *) pi->pvalue, - (char *) &(((struct dbr_sts_long *) arg.dbr)->value), - (arg.count * pi->dest_old_dbr_element_size)); - pi->source_severity = - (unsigned short) ((struct dbr_sts_long *) arg.dbr)->severity; - -/* strcat(print_line, "DBR_STS_LONG "); */ -/* sprintf(buff, ">%ld< ", */ -/* (long) ((struct dbr_sts_long *) arg.dbr)->value); */ - break; - case DBR_STS_DOUBLE: - pi->needs_reading = TRUE; - pi->last_rcvd_nelements = arg.count; - -/* bcopy( */ -/* (char *) &(((struct dbr_sts_double *) arg.dbr)->value), */ -/* (char *) pi->pvalue, */ -/* (arg.count * pi->dest_old_dbr_element_size)); */ - memcpy( - (char *) pi->pvalue, - (char *) &(((struct dbr_sts_double *) arg.dbr)->value), - (arg.count * pi->dest_old_dbr_element_size)); - pi->source_severity = - (unsigned short) ((struct dbr_sts_double *) arg.dbr)->severity; - -/* strcat(print_line, "DBR_STS_DOUBLE "); */ -/* sprintf(buff, ">%f< ", */ - /* (double) ((struct dbr_sts_double *) arg.dbr)->value); */ -/* strcat(print_line, buff); */ - break; - default: - strcat(print_line, "UNKNOWN "); - strcat(print_line, "**** "); - break; - } /* end switch() */ - - FASTUNLOCK(&(pi->lock)); - - } - else - { - sprintf(errmsg, - "ERROR: my_event_handler() ca delivered %ld elements while maximum is %ld", - arg.count, pi->dest_nelements); - - errMessage(S_dbCa_cafailure, errmsg); - } /* endif */ - } - else - { - sprintf(errmsg, - "ERROR: my_event_handler() ca delivered DBR %d while %d was expected", - arg.type, pi->dest_old_dbr_sts_type); - - errMessage(S_dbCa_cafailure, errmsg); - } /* endif */ - - } - else - errMessage(S_dbCa_foundnull, - "ERROR: my_event_handler() found NULL pi->pvalue"); - } - else - errMessage(S_dbCa_foundnull, "ERROR: my_event_handler() found NULL pi"); - -} /* end my_event_handler() */ - -/**************************************************************** -* -* static struct input_pvar *pop_input_pvar() -* -* Description: -* Pops a fresh input pvar node off the avail list. -* -* Input: None. -* -* Output: None. -* -* Returns: -* address of fresh node -* NULL if unable to allocate a node -* -* Notes: -* The LOCKs associated with the nodes are only initialized immediately -* after acquiring the memory for the node while the rest of the fields in -* the structure are initialized every time the node is popped off the list. -* -* It is also assumed that -1 is an invalid dest_old_dbr_sts_type as well -* as an invalid record severity. -* -****************************************************************/ - -static struct input_pvar *pop_input_pvar() -{ - -struct input_pvar *rc; -int i; - - if (Input_pvar_avail_hdr != (struct input_pvar *) NULL) - { - rc = Input_pvar_avail_hdr; - Input_pvar_avail_hdr = rc->next; - } - else - { - if ((Input_pvar_avail_hdr - = (struct input_pvar *) calloc - ((unsigned) NODESPERCALLOC, - (unsigned) (sizeof (struct input_pvar)))) - != (struct input_pvar *) NULL) - { - for (rc = Input_pvar_avail_hdr, i=0; i < (NODESPERCALLOC-1); i ++) - { - FASTLOCKINIT(&(rc->lock)); - rc->next = rc + 1; - rc++; - } /* endfor */ - FASTLOCKINIT(&(rc->lock)); - rc->next = (struct input_pvar *) NULL; - - rc = Input_pvar_avail_hdr; - Input_pvar_avail_hdr = rc->next; - } - else - rc = (struct input_pvar *) NULL; - } /* endif */ - - if (rc) - { - rc->next = (struct input_pvar *) NULL; - rc->pdest_dbaddr = (void *) NULL; - rc->source_name[0] = '\0'; - rc->dest_name[0] = '\0'; - rc->pvalue = (void *) NULL; - rc->maximize_severity = FALSE; - rc->dest_old_dbr_element_size = 0; - rc->dest_old_dbr_type = (short) -1; /* hopefully -1 is not */ - /* valid old_dbr_type */ - rc->revised_dest_new_dbr_type = (short) -1; /* hopefully -1 is not */ - /* valid new_dbr_type */ - rc->dest_old_dbr_sts_type = (short) -1; /* hopefully -1 is not */ - /* valid old_dbr_sts_type */ - rc->source_severity = (unsigned short) -1; /* hopefully -1 is not a */ - /* valid status/severity */ - rc->needs_reading = FALSE; - rc->dest_nelements = (long) -1; - rc->last_rcvd_nelements = (long) -1; - } /* endif */ - - return rc; - -} /* end pop_input_pvar() */ - -/**************************************************************** -* -* static struct output_pvar *pop_output_pvar() -* -* Description: -* Pops a fresh output pvar node off the avail list. -* -* Input: None. -* -* Output: None. -* -* Returns: -* address of fresh node -* NULL if unable to allocate a node -* -* Notes: -* The LOCKs associated with the nodes are only initialized immediately -* after acquiring the memory for the node while the rest of the fields in -* the structure are initialized every time the node is popped off the list. -* -* It is also assumed that -1 is an invalid source_old_dbr_type. -* -****************************************************************/ - -static struct output_pvar *pop_output_pvar() -{ - -struct output_pvar *rc; -int i; - - if (Output_pvar_avail_hdr != (struct output_pvar *) NULL) - { - rc = Output_pvar_avail_hdr; - Output_pvar_avail_hdr = rc->next; - } - else - { - if ((Output_pvar_avail_hdr = - (struct output_pvar *) calloc - ((unsigned) NODESPERCALLOC, - (unsigned) (sizeof (struct output_pvar)))) - != (struct output_pvar *) NULL) - { - for (rc = Output_pvar_avail_hdr, i=0; i < (NODESPERCALLOC-1); i ++) - { - FASTLOCKINIT(&(rc->lock)); - rc->next = rc + 1; - rc++; - } /* endfor */ - FASTLOCKINIT(&(rc->lock)); - rc->next = (struct output_pvar *) NULL; - - rc = Output_pvar_avail_hdr; - Output_pvar_avail_hdr = rc->next; - } - else - rc = (struct output_pvar *) NULL; - } /* endif */ - - if (rc) - { - rc->next = (struct output_pvar *) NULL; - rc->write_next = (struct output_pvar *) NULL; - rc->psource_dbaddr = (void *) NULL; - rc->pvalue = (void *) NULL; - rc->dest_name[0] = '\0'; - rc->source_name[0] = '\0'; - rc->source_old_dbr_type = (short) -1; /* hope -1 invalid dbr_type */ - rc->source_new_dbr_type = (short) -1; /* hope -1 invalid dbr_type */ - rc->revised_source_new_dbr_type = (short) -1; /* hope -1 invalid */ - /* dbr_type */ - rc->source_nelements = -1L; - rc->last_nelements_written = -1L; - rc->valid_value = FALSE; - rc->on_writelist = FALSE; - } /* endif */ - - return rc; - -} /* end pop_output_pvar() */ - -/**************************************************************** -* -* static long process_asynch_events(seconds) -* float seconds; -* -* Description: -* Queues a waits for events on remote monitors by calling ca_pend_event(). -* -* Input: -* float seconds number of seconds to wait for events (0 means forever) -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_ECA_EVDISALLOW - attempted to execute from within an event handler -* S_dbCa_unknownECA - unrecognizable status rc from ca_pend_event() -* -* Notes: -* If seconds = 0 then no status is ever returned. -* -****************************************************************/ - -static long process_asynch_events(seconds) -float seconds; -{ - -int status; -char errmsg[100]; -long rc; - - status = ca_pend_event(seconds); - - /* from here down won't get executed if */ - /* ca_pend_event(0.0) i.e., waiting forever */ - - switch (status) - { - case ECA_NORMAL: - rc = 0L; - break; - case ECA_TIMEOUT: - rc = 0L; - break; - case ECA_EVDISALLOW: - rc = S_dbCa_ECA_EVDISALLOW; - errMessage(S_dbCa_ECA_EVDISALLOW, - "ERROR: process_asynch_events() cannot call inside evt hndlr"); - break; - default: - rc = S_dbCa_unknownECA; - sprintf(errmsg, - "ERROR: process_asynch_events() unrecognizable status returned %d", - status); - errMessage(S_dbCa_unknownECA, errmsg); - break; - } /* end switch() */ - - return rc; - -} /* end process_asynch_events() */ - -/**************************************************************** -* -* static void process_asynch_events_task(parent_task_id) -* int parent_task_id; -* -* Description: -* issues a single call to process_asynch_events(0.0). this is a trick -* suggested by Jeff Hill so that connections that are lost may be -* re-connected when the other IOC is re-booted. without this trick, -* a lost connection to another IOC will remain lost, even if the other -* IOC successfully re-boots. -* -* Input: -* int parent_task_id vxWorks taskid of dbCaProcessOutlinks -* -* Output: None. -* -* Returns: -* -* Notes: -* -****************************************************************/ - -static void process_asynch_events_task(parent_task_id) -int parent_task_id; -{ - - ca_import(parent_task_id); - - /* kludge suggested by Jeff Hill so that we can have reliable */ - /* connection management for vxWorks hosted CA clients */ - process_asynch_events((float) 0.0); - -} /* end process_asynch_events_task() */ - -/**************************************************************** -* -* static void push_input_pvar(ip) -* struct input_pvar *ip; -* -* Description: -* Pushes input pvar back onto avail stack. -* -* Input: -* struct input_pvar *ip node to be pushed -* -* Output: None. -* -* Returns: None. -* -* Notes: None. -* -****************************************************************/ - -static void push_input_pvar(ip) -struct input_pvar *ip; -{ - if (ip) - { - ip->next = Input_pvar_avail_hdr; - Input_pvar_avail_hdr = ip; - } /* endif */ - -} /* end push_input_pvar() */ - -/**************************************************************** -* -* static void push_output_pvar(op) -* struct output_pvar *op; -* -* Description: -* Pushes output pvar back onto avail stack. -* -* Input: -* struct output_pvar *op node to be pushed -* -* Output: None. -* -* Returns: None. -* -* Notes: None. -* -****************************************************************/ - -static void push_output_pvar(op) -struct output_pvar *op; -{ - if (op) - { - op->next = Output_pvar_avail_hdr; - Output_pvar_avail_hdr = op; - } /* endif */ - -} /* end push_output_pvar() */ - -/**************************************************************** -* -* static long queue_add_event_from_input_pvar(pi) -* struct input_pvar *pi; -* -* Description: -* Queues a monitor on a remote source process input variable and registers -* my_event_handler() as the event hanlder by calling ca_add_array_event(). -* -* Input: -* struct input_pvar *pi pointer to input pvar structure to estab monitor -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_nullarg - got NULL pi -* S_dbCa_ECA_BADCHID - ECA_BADCHID -* S_dbCa_ECA_BADTYPE - ECA_BADTYPE -* S_dbCa_ECA_ALLOCMEM - ECA_ALLOCMEM -* S_dbCa_ECA_ADDFAIL - ECA_ADDFAIL -* S_dbCa_unknownECA - unknown rc from ca_add_array_event() -* -* Notes: None. -* -****************************************************************/ - -static long queue_add_event_from_input_pvar(pi) -struct input_pvar *pi; -{ - -int status; -char errmsg[100]; -long rc; - - if (pi) - { - - status = ca_add_array_event((chtype) pi->dest_old_dbr_sts_type, - pi->dest_nelements, - pi->cid, my_event_handler, pi,0.0,0.0,0.0, (evid *) NULL); - - switch (status) - { - case ECA_NORMAL: - rc = 0L; - break; - case ECA_BADCHID: - rc = S_dbCa_ECA_BADCHID; - errMessage(S_dbCa_ECA_BADCHID, - "ERROR: queue_add_event_from_input_pvar() unconnected/corrupted CHID"); - break; - case ECA_BADTYPE: - rc = S_dbCa_ECA_BADTYPE; - errMessage(S_dbCa_ECA_BADTYPE, - "ERROR: queue_add_event_from_input_pvar() unknown GET_TYPE"); - break; - case ECA_ALLOCMEM: - rc = S_dbCa_ECA_ALLOCMEM; - errMessage(S_dbCa_ECA_ALLOCMEM, - "ERROR: queue_add_event_from_input_pvar() unable to alloc mem"); - break; - case ECA_ADDFAIL: - rc = S_dbCa_ECA_ADDFAIL; - errMessage(S_dbCa_ECA_ADDFAIL, - "ERROR: queue_add_event_from_input_pvar() local db event add failed"); - break; - default: - rc = S_dbCa_unknownECA; - sprintf(errmsg, -"ERROR: queue_add_event_from_input_pvar() unrecognizable status returned %d", - status); - errMessage(S_dbCa_unknownECA, errmsg); - } /* end switch() */ - - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: queue_add_event_from_input_pvar() got NULL pi"); - } /* endif */ - - return rc; - -} /* end queue_add_event_from_input_pvar() */ - -/**************************************************************** -* -* static long queue_ca_build_and_connect(po) -* struct output_pvar *po; -* -* Description: -* Queues a search and establishes connections to remote destination pvars -* for output links and registers my_connection_handler() as the connection -* handler routine by calling ca_build_and_connect(). -* -* Input: -* struct output_pvar *po pointer to output node that needs connection -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_nullarg - got NULL po -* S_dbCa_ECA_BADTYPE - ECA_BADTYPE -* S_dbCa_ECA_STRTOBIG - ECA_STRTOBIG -* S_dbCa_ECA_ALLOCMEM - ECA_ALLOCMEM -* S_dbCa_ECA_GETFAIL - ECA_GETFAIL -* S_dbCa_unknownECA - unknown rc from ca_build_and_connect() -* -* Notes: None. -* -****************************************************************/ - -static long queue_ca_build_and_connect(po) -struct output_pvar *po; -{ - -int status; -char errmsg[100]; -long rc; - - if (po) - { - /* pointing channel to this output_pvar struct */ - /* for later use by my_connection_handler() */ - - status = ca_build_and_connect(po->dest_name, (chtype) TYPENOTCONN, - (unsigned long) 0, &(po->cid), (void *) NULL, - my_connection_handler, (void *) po); - - switch (status) - { - case ECA_NORMAL: - rc = 0L; - break; - case ECA_BADTYPE: - rc = S_dbCa_ECA_BADTYPE; - errMessage(S_dbCa_ECA_BADTYPE, - "ERROR: queue_ca_build_and_connect() unknown GET_TYPE"); - break; - case ECA_STRTOBIG: - rc = S_dbCa_ECA_STRTOBIG; - errMessage(S_dbCa_ECA_STRTOBIG, - "ERROR: queue_ca_build_and_connect() string too big"); - break; - case ECA_ALLOCMEM: - rc = S_dbCa_ECA_ALLOCMEM; - errMessage(S_dbCa_ECA_ALLOCMEM, - "ERROR: queue_ca_build_and_connect() unable to allocate memory"); - break; - case ECA_GETFAIL: - rc = S_dbCa_ECA_GETFAIL; - errMessage(S_dbCa_ECA_GETFAIL, - "ERROR: queue_ca_build_and_connect() a local database get failed"); - break; - default: - rc = S_dbCa_unknownECA; - sprintf(errmsg, - "ERROR: queue_ca_build_and_connect() unrecognizable status returned %d", - status); - errMessage(S_dbCa_unknownECA, errmsg); - break; - } /* end switch() */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: queue_ca_build_and_connect() got NULL po"); - } /* endif */ - - return rc; - -} /* end queue_ca_build_and_connect() */ - -/**************************************************************** -* -* Description: -* Queues the writing of the value from the temporary store of an output -* node by calling ca_put(). -* -* Input: -* struct output_pvar *po pointer to the node that has the output value -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_nullarg - got NULL po -* S_dbCa_ECA_BADCHID - ECA_BADCHID -* S_dbCa_ECA_BADTYPE - ECA_BADTYPE -* S_dbCa_ECA_BADCOUNT - ECA_BADCOUNT -* S_dbCa_ECA_STRTOBIG - ECA_STRTOBIG -* S_dbCa_ECA_PUTFAIL - ECA_PUTFAIL -* S_dbCa_unknownECA - unknown rc from ca_put() -* -* Notes: None. -* -****************************************************************/ - -static long queue_ca_array_put(po) -struct output_pvar *po; -{ - -int status; -char errmsg[100]; -long rc; - - if (po) - { - status = ca_array_put(po->source_old_dbr_type, - (unsigned long) po->last_nelements_written, po->cid, po->pvalue); - - switch (status) - { - case ECA_NORMAL: - rc = 0L; - break; - case ECA_BADCHID: - rc = S_dbCa_ECA_BADCHID; - errMessage(S_dbCa_ECA_BADCHID, - "ERROR: queue_ca_put() unconnected/corrupted CHID"); - break; - case ECA_BADTYPE: - rc = S_dbCa_ECA_BADTYPE; - errMessage(S_dbCa_ECA_BADTYPE, - "ERROR: queue_ca_put() unknown GET_TYPE"); - break; - case ECA_BADCOUNT: - rc = S_dbCa_ECA_BADCOUNT; - errMessage(S_dbCa_ECA_BADCOUNT, -"ERROR: queue_ca_put() requested count larger than actual chnl elmnt count"); - break; - case ECA_STRTOBIG: - rc = S_dbCa_ECA_STRTOBIG; - errMessage(S_dbCa_ECA_STRTOBIG, - "ERROR: queue_ca_put() unusually large string supplied"); - break; - case ECA_PUTFAIL: - rc = S_dbCa_ECA_PUTFAIL; - errMessage(S_dbCa_ECA_PUTFAIL, - "ERROR: queue_ca_put() a local database put failed"); - break; - default: - rc = S_dbCa_unknownECA; - sprintf(errmsg, - "ERROR: queue_ca_put() unrecognizable status returned %d", - status); - errMessage(S_dbCa_unknownECA, errmsg); - } /* end switch() */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, "ERROR: queue_ca_put() got NULL po"); - } /* endif */ - - return rc; - -} /* end queue_ca_array_put() */ - -/**************************************************************** -* -* static long queue_ca_search(name, pcid) -* char *name; -* chid *pcid; -* -* Description: -* Queues a ca_search(). -* -* Input: -* char *name name of remote pvar -* chid *pcid pointer to channel -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_nullarg - got NULL name or NULL pcid -* S_dbCa_ECA_BADTYPE - ECA_BADTYPE -* S_dbCa_ECA_STRTOBIG - ECA_STRTOBIG -* S_dbCa_ECA_ALLOCMEM - ECA_ALLOCMEM -* S_dbCa_ECA_GETFAIL - ECA_GETFAIL -* S_dbCa_unknownECA - unknown rc from ca_search() -* -* Notes: None. -* -****************************************************************/ - -static long queue_ca_search(name, pcid) -char *name; -chid *pcid; -{ - -int status; -char errmsg[100]; -long rc; - - if (name) - { - if (pcid) - { - status = ca_search(name, pcid); - - switch (status) - { - case ECA_NORMAL: - rc = 0L; - break; - case ECA_BADTYPE: - rc = S_dbCa_ECA_BADTYPE; - errMessage(S_dbCa_ECA_BADTYPE, - "ERROR: queue_ca_search() unknown GET_TYPE"); - break; - case ECA_STRTOBIG: - rc = S_dbCa_ECA_STRTOBIG; - errMessage(S_dbCa_ECA_STRTOBIG, - "ERROR: queue_ca_search() string too big"); - break; - case ECA_ALLOCMEM: - rc = S_dbCa_ECA_ALLOCMEM; - errMessage(S_dbCa_ECA_ALLOCMEM, - "ERROR: queue_ca_search() unable to allocate memory"); - break; - case ECA_GETFAIL: - rc = S_dbCa_ECA_GETFAIL; - errMessage(S_dbCa_ECA_GETFAIL, - "ERROR: queue_ca_search() a local database get failed"); - break; - default: - rc = S_dbCa_unknownECA; - sprintf(errmsg, - "ERROR: queue_ca_search() unrecognizable status returned %d", - status); - errMessage(S_dbCa_unknownECA, errmsg); - break; - } /* end switch() */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, - "ERROR: queue_ca_search() got NULL pcid"); - } /* endif */ - } - else - { - rc = S_dbCa_nullarg; - errMessage(S_dbCa_nullarg, "ERROR: queue_ca_search() got NULL name"); - } /* endif */ - - return rc; - -} /* end queue_ca_search() */ - -/**************************************************************** -* -* static long task_initialize_channel_access() -* -* Description: -* Initializes channel access for calling task by calling -* ca_task_initialize(). -* -* Input: None. -* -* Output: None. -* -* Returns: -* 0 - Success -* S_dbCa_ECA_ALLOCMEM - ECA_ALLOCMEM -* S_dbCa_unknownECA - unknown rc from ca_task_initialize() -* -* Notes: -* Must be called exactly once by each task making calls to channel access. -* -****************************************************************/ - -static long task_initialize_channel_access() -{ - -int status; -char errmsg[100]; -long rc; - - status = ca_task_initialize(); - - switch (status) - { - case ECA_NORMAL: - rc = 0L; - break; - case ECA_ALLOCMEM: - rc = S_dbCa_ECA_ALLOCMEM; - errMessage(S_dbCa_ECA_ALLOCMEM, - "ERROR: task_initialize_channel_access() unable to allocate memory"); - break; - default: - rc = S_dbCa_unknownECA; - sprintf(errmsg, - "ERROR: task_initialize_channel_access() unrecognizable status returned %d", - status); - errMessage(S_dbCa_unknownECA, errmsg); - break; - } /* end switch() */ - - return rc; - -} /* end task_initialize_channel_access() */ diff --git a/src/db/dbCommon.db b/src/db/dbCommon.db index c0e1b6bdb..17c850ade 100644 --- a/src/db/dbCommon.db +++ b/src/db/dbCommon.db @@ -46,13 +46,11 @@ field(TSEL,DBF_INLINK) { prompt("Time Stamp Link") promptgroup(GUI_SCAN) - special(SPC_NOMOD) interest(1) } field(DTYP,DBF_DEVICE) { prompt("Device Type") promptgroup(GUI_LINKS) - special(SPC_NOMOD) interest(1) } field(DISV,DBF_SHORT) { @@ -66,7 +64,6 @@ field(SDIS,DBF_INLINK) { prompt("Scanning Disable") promptgroup(GUI_SCAN) - special(SPC_NOMOD) interest(1) } field(MLOK,DBF_NOACCESS) { @@ -134,11 +131,6 @@ interest(1) menu(menuAlarmSevr) } - field(LSET,DBF_SHORT) { - prompt("Lock Set") - special(SPC_NOMOD) - interest(4) - } field(LCNT,DBF_UCHAR) { prompt("Lock Count") special(SPC_NOMOD) @@ -208,6 +200,20 @@ size(4) extra("void *dpvt") } + field(RDES,DBF_NOACCESS) { + prompt("Address of dbRecDes") + special(SPC_NOMOD) + interest(4) + size(4) + extra("void *rdes") + } + field(LSET,DBF_NOACCESS) { + prompt("Lock Set") + special(SPC_NOMOD) + interest(4) + size(4) + extra("void *lset") + } field(PRIO,DBF_MENU) { prompt("Scheduling Priority") promptgroup(GUI_SCAN) @@ -241,6 +247,5 @@ field(FLNK,DBF_FWDLINK) { prompt("Forward Process Link") promptgroup(GUI_LINKS) - special(SPC_NOMOD) interest(1) } diff --git a/src/db/dbConvert.c b/src/db/dbConvert.c index b7b2ddb5b..82ce733c8 100644 --- a/src/db/dbConvert.c +++ b/src/db/dbConvert.c @@ -1502,22 +1502,17 @@ static long getFloatString( { char *pbuffer = (char *)pto; float *psrc=(float *)(paddr->pfield); - long status; - int precision; + long status = 0; + int precision = 0; struct rset *prset; if((prset=dbGetRset(paddr)) && (prset->get_precision)) status = (*prset->get_precision)(paddr,&precision); else status=S_db_precision; - if(status) { - recGblRecSupError(status,paddr,"dbGet","get_precision"); - return(status); - } - if(nRequest==1 && offset==0) { cvtFloatToString(*psrc,pbuffer,precision); - return(0); + return(status); } psrc += offset; while (nRequest) { @@ -1529,7 +1524,7 @@ static long getFloatString( psrc++; nRequest--; } - return(0); + return(status); } static long getFloatChar( @@ -1711,22 +1706,17 @@ static long getDoubleString( { char *pbuffer = (char *)pto; double *psrc=(double *)(paddr->pfield); - long status; - int precision; + long status = 0; + int precision = 0; struct rset *prset; if((prset=dbGetRset(paddr)) && (prset->get_precision)) status = (*prset->get_precision)(paddr,&precision); else status=S_db_precision; - if(status) { - recGblRecSupError(status,paddr,"dbGet","get_precision"); - return(status); - } - if(nRequest==1 && offset==0) { cvtDoubleToString(*psrc,pbuffer,precision); - return(0); + return(status); } psrc += offset; while (nRequest) { @@ -1738,7 +1728,7 @@ static long getDoubleString( psrc++; nRequest--; } - return(0); + return(status); } static long getDoubleChar( @@ -2105,7 +2095,7 @@ static long getMenuString(DBADDR *paddr, void *pto, { char *pbuffer = (char *)pto; dbFldDes *pdbFldDes = (dbFldDes *)paddr->pfldDes; - dbMenu *pdbMenu = (dbMenu *)pdbFldDes->ftPvt; + dbMenu *pdbMenu; char **papChoiceValue; char *pchoice; unsigned short choice_ind= *((unsigned short*)paddr->pfield); @@ -2114,7 +2104,9 @@ static long getMenuString(DBADDR *paddr, void *pto, recGblDbaddrError(S_db_onlyOne,paddr,"dbGet(getMenuString)"); return(S_db_onlyOne); } - if( !pdbMenu || choice_ind>=pdbMenu->nChoice + if(!pdbFldDes + || !(pdbMenu = (dbMenu *)pdbFldDes->ftPvt) + || (choice_ind>=pdbMenu->nChoice) || !(papChoiceValue = pdbMenu->papChoiceValue) || !(pchoice=papChoiceValue[choice_ind])) { recGblDbaddrError(S_db_badChoice,paddr,"dbGet(getMenuString)"); @@ -2129,7 +2121,7 @@ static long getDeviceString(DBADDR *paddr, void *pto, { char *pbuffer = (char *)pto; dbFldDes *pdbFldDes = (dbFldDes *)paddr->pfldDes; - dbDeviceMenu *pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; + dbDeviceMenu *pdbDeviceMenu; char **papChoice; char *pchoice; unsigned short choice_ind= *((unsigned short*)paddr->pfield); @@ -2138,7 +2130,9 @@ static long getDeviceString(DBADDR *paddr, void *pto, recGblDbaddrError(S_db_onlyOne,paddr,"dbGet(getDeviceString)"); return(S_db_onlyOne); } - if( !pdbDeviceMenu || choice_ind>=pdbDeviceMenu->nChoice + if(!pdbFldDes + || !(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt) + || (choice_ind>=pdbDeviceMenu->nChoice ) || !(papChoice = pdbDeviceMenu->papChoice) || !(pchoice=papChoice[choice_ind])) { recGblDbaddrError(S_db_badChoice,paddr,"dbGet(getDeviceString)"); @@ -2465,7 +2459,7 @@ static long putStringEnum( if(status == S_db_noRSET) { recGblRecSupError(status,paddr,"dbPutField","put_enum_str"); } else { - recGblDbaddrError(status,paddr,"dbPut(putStringEnum)"); + recGblRecordError(status,(void *)paddr->precord,pbuffer); } return(status); } @@ -2475,7 +2469,7 @@ static long putStringMenu( { char *pbuffer = (char *)pfrom; dbFldDes *pdbFldDes = (dbFldDes *)paddr->pfldDes; - dbMenu *pdbMenu = (dbMenu *)pdbFldDes->ftPvt; + dbMenu *pdbMenu; char **papChoiceValue; char *pchoice; unsigned short *pfield= (unsigned short*)(paddr->pfield); @@ -2486,7 +2480,9 @@ static long putStringMenu( recGblDbaddrError(S_db_onlyOne,paddr,"dbPut(putStringMenu)"); return(S_db_onlyOne); } - if( pdbMenu && (papChoiceValue = pdbMenu->papChoiceValue)) { + if(pdbFldDes + && (pdbMenu = (dbMenu *)pdbFldDes->ftPvt) + && (papChoiceValue = pdbMenu->papChoiceValue)) { nChoice = pdbMenu->nChoice; for(ind=0; indpapChoice)) { + if(pdbFldDes + && (pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt) + && (papChoice = pdbDeviceMenu->papChoice)) { nChoice = pdbDeviceMenu->nChoice; for(ind=0; indpfield); - long status; - int precision; + long status = 0; + int precision = 0; struct rset *prset; short size=paddr->field_size; @@ -3730,14 +3728,10 @@ static long putFloatString( status = (*prset->get_precision)(paddr,&precision); else status=S_db_precision; - if(status) { - recGblRecSupError(status,paddr,"dbPutField","get_precision"); - return(status); - } if(nRequest==1 && offset==0) { cvtFloatToString(*pbuffer,pdest,precision); - return(0); + return(status); } pdest += (size*offset); while (nRequest) { @@ -3749,7 +3743,7 @@ static long putFloatString( pdest += size; nRequest--; } - return(0); + return(status); } static long putFloatChar( @@ -3931,8 +3925,8 @@ static long putDoubleString( { double *pbuffer = (double *)pfrom; char *pdest=(char *)(paddr->pfield); - long status; - int precision; + long status = 0; + int precision = 0; struct rset *prset; short size=paddr->field_size; @@ -3940,14 +3934,10 @@ static long putDoubleString( status = (*prset->get_precision)(paddr,&precision); else status=S_db_precision; - if(status) { - recGblRecSupError(status,paddr,"dbPutField","get_precision"); - return(status); - } if(nRequest==1 && offset==0) { cvtDoubleToString(*pbuffer,pdest,precision); - return(0); + return(status); } pdest += (size*offset); while (nRequest) { @@ -3959,7 +3949,7 @@ static long putDoubleString( pdest += size; nRequest--; } - return(0); + return(status); } static long putDoubleChar( diff --git a/src/db/dbConvert.h b/src/db/dbConvert.h index 3a7d8751e..36059807f 100644 --- a/src/db/dbConvert.h +++ b/src/db/dbConvert.h @@ -29,7 +29,8 @@ * .01 13OCT95 mrk Created header file as part of extracting convert from * dbLink */ - + + #include extern long (*dbGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1]) (DBADDR *paddr, void *pbuffer,long nRequest, long no_elements, long offset); diff --git a/src/db/dbFastLinkConv.c b/src/db/dbFastLinkConv.c index 0a8eb4e59..49b5952b8 100644 --- a/src/db/dbFastLinkConv.c +++ b/src/db/dbFastLinkConv.c @@ -85,41 +85,21 @@ extern struct dbBase *pdbbase; * will have this conversion. */ -/* Uninitialized Conversion */ -long cvt_uninit( - void *from, - void *to, - struct dbAddr *paddr) -{ - recGblDbaddrError(-1,paddr,"cvt_uninit: uninitialized link"); - return(-1); -} - -/* - * Dummy Conversion - * In the case of an unsupported conversion, run this - * dummy function instead to avoid a bus error. - */ -long cvt_dummy( - void *from, - void *to, - struct dbAddr *paddr) -{ return(-1); } - /* Convert String to String */ static long cvt_st_st( char *from, char *to, struct dbAddr *paddr) { - char size = paddr->field_size; - - if (size >= MAX_STRING_SIZE) - size = MAX_STRING_SIZE - 1; + char size; + if(paddr && paddr->field_sizefield_size - 1; + } else { + size = MAX_STRING_SIZE - 1; + } strncpy(to, from, size); *(to+size) = '\000'; - return(0); } @@ -257,10 +237,10 @@ static long cvt_st_e( unsigned short *to, struct dbAddr *paddr) { - struct rset *prset; + struct rset *prset = 0; long status; - prset = dbGetRset(paddr); + if(paddr) prset = dbGetRset(paddr); if (prset && prset->put_enum_str) return (*prset->put_enum_str)(paddr, from); @@ -760,24 +740,17 @@ static long cvt_f_st( char *to, struct dbAddr *paddr) { - struct rset *prset; + struct rset *prset = 0; long status = 0; - long precision = 2; + long precision = 0; - prset = dbGetRset(paddr); + if(paddr) prset = dbGetRset(paddr); if (prset && prset->get_precision) - (*prset->get_precision)(paddr, &precision); + status = (*prset->get_precision)(paddr, &precision); else status = S_db_precision; - - if (status) { - recGblRecSupError(status, paddr, "dbGetField", "get_precision"); - return(status); - } - cvtFloatToString(*from, to, precision); - return(status); } @@ -850,24 +823,17 @@ static long cvt_d_st( char *to, struct dbAddr *paddr) { - struct rset *prset; + struct rset *prset = 0; long status = 0; - long precision = 2; + long precision = 0; - prset = dbGetRset(paddr); + if(paddr) prset = dbGetRset(paddr); if (prset && prset->get_precision) - (*prset->get_precision)(paddr, &precision); + status = (*prset->get_precision)(paddr, &precision); else status = S_db_precision; - - if (status) { - recGblRecSupError(status, paddr, "dbGetField", "get_precision"); - return(status); - } - cvtDoubleToString(*from, to, precision); - return(status); } @@ -1005,10 +971,10 @@ static long cvt_e_st_get( char *to, struct dbAddr *paddr) { - struct rset *prset; + struct rset *prset = 0; long status; - prset = dbGetRset(paddr); + if(paddr) prset = dbGetRset(paddr); if (prset && prset->get_enum_str) return (*prset->get_enum_str)(paddr, to); @@ -1032,12 +998,15 @@ static long cvt_menu_st( char *to, struct dbAddr *paddr) { - dbFldDes *pdbFldDes = (dbFldDes *)paddr->pfldDes; - dbMenu *pdbMenu = (dbMenu *)pdbFldDes->ftPvt; + dbFldDes *pdbFldDes; + dbMenu *pdbMenu; char **papChoiceValue; char *pchoice; - if( !pdbMenu || *from>=pdbMenu->nChoice + if(! paddr + || !(pdbFldDes = (dbFldDes *)paddr->pfldDes) + || !(pdbMenu = (dbMenu *)pdbFldDes->ftPvt) + || *from>=pdbMenu->nChoice || !(papChoiceValue = pdbMenu->papChoiceValue) || !(pchoice=papChoiceValue[*from])) { recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_menu_st)"); @@ -1054,12 +1023,15 @@ static long cvt_device_st( char *to, struct dbAddr *paddr) { - dbFldDes *pdbFldDes = (dbFldDes *)paddr->pfldDes; - dbDeviceMenu *pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; + dbFldDes *pdbFldDes; + dbDeviceMenu *pdbDeviceMenu; char **papChoice; char *pchoice; - if( !pdbDeviceMenu || *from>=pdbDeviceMenu->nChoice + if(!paddr + || !(pdbFldDes = (dbFldDes *)paddr->pfldDes) + || !(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt) + || *from>=pdbDeviceMenu->nChoice || !(papChoice= pdbDeviceMenu->papChoice) || !(pchoice=papChoice[*from])) { recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_device_st)"); diff --git a/src/db/dbLock.c b/src/db/dbLock.c new file mode 100644 index 000000000..6da857648 --- /dev/null +++ b/src/db/dbLock.c @@ -0,0 +1,495 @@ +/* dbLock.c */ +/* Author: Marty Kraimer Date: 12MAR96 */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1991 Regents of the University of California, +and the University of Chicago Board of Governors. + +This software was developed under a United States Government license +described on the COPYRIGHT_Combined file included as part +of this distribution. +**********************************************************************/ + +/* Modification Log: + * ----------------- + * .01 12MAR96 mrk Initial Implementation +*/ + +/************** DISCUSSION OF DYNAMIC LINK MODIFICATION ********************** + +Since the purpose of lock sets is to prevent multiple tasks from simultaneously +accessing records in set, dynamically changing lock sets presents a problem. + +Four problems arise: + +1) Two tasks simultaneoulsy trying to change lock sets +2) Another task has successfully issued a dbScanLock and currently owns it. +3) A task is waiting for dbScanLock. +4) While lock set is being changed, a task issues a dbScanLock. + +Solution: + +A routine attempting to modify a link must do the following: + +Call dbLockSetGblLock before modifying any link and dbLockSetGblUnlock after. +Call dbLockSetRecordLock for any record referenced during change. +Call dbLockSetSplit before changing any link that is originally a DB_LINK +Call dbLockSetMerge if changed link becomes a DB_LINK. + +Discussion: + + +Each problem above is solved as follows: +1) dbLockGlobal solves this problem. +2) dbLockSetRecordLock solves this problem. +3) After changing lock sets original semId id deleted. + This makes all tasks in semTake for that semaphore fail. + The code in dbScanLock makes task recover. +4) The global variable changingLockSets and code in + dbScanLock and semFlush in dbLockSetGblUnlock solves + this problem. + +Note that all other tasks are prevented from processing records between +dbLockSetGblLock and dbLockSetGblUnlock. + +dblls may crash if executed while lock sets are being modified. +It is NOT a good idea to make it more robust by issuing dbLockSetGblLock +since this will delay all other tasks. +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STATIC static + +STATIC int lockListInitialized = FALSE; + +STATIC ELLLIST lockList; +STATIC SEM_ID globalLockSemId; +STATIC SEM_ID globalWaitSemid; +STATIC unsigned long id = 0; +STATIC int changingLockSets = FALSE; + +typedef struct lockSet { + ELLNODE node; + ELLLIST recordList; + SEM_ID semId; + ULONG start_time; + int task_id; + dbCommon *precord; + unsigned long id; +} lockSet; + +typedef struct lockRecord { + ELLNODE node; + lockSet *plockSet; + dbCommon *precord; +} lockRecord; + +/*private routines */ +STATIC void initLockList(void) +{ + ellInit(&lockList); + if((globalLockSemId = semBCreate(SEM_Q_FIFO,SEM_FULL))==0) { + errMessage(0,"allocLockNode called semBCreate\n"); + exit(-1); + } + if((globalWaitSemid = semBCreate(SEM_Q_FIFO,SEM_EMPTY))==0) { + errMessage(0,"allocLockNode called semBCreate\n"); + exit(-1); + } + lockListInitialized = TRUE; +} + +STATIC lockSet * allocLock(lockRecord *plockRecord) +{ + lockSet *plockSet; + + if(!lockListInitialized) initLockList(); + plockSet = dbCalloc(1,sizeof(lockSet)); + ellInit(&plockSet->recordList); + plockRecord->plockSet = plockSet; + id++; + plockSet->id = id; + ellAdd(&plockSet->recordList,&plockRecord->node); + ellAdd(&lockList,&plockSet->node); + if((plockSet->semId = semBCreate(SEM_Q_FIFO,SEM_FULL))==0) { + errMessage(0,"allocLockNode called semBCreate\n"); + exit(-1); + } + return(plockSet); +} + +/*Add new lockRecord to lockSet list*/ +STATIC void lockAddRecord(lockSet *plockSet,lockRecord *pnew) +{ + pnew->plockSet = plockSet; + ellAdd(&plockSet->recordList,&pnew->node); +} + +void dbLockSetGblLock(void) +{ + STATUS status; + + if(!lockListInitialized) initLockList(); + status = semTake(globalLockSemId,WAIT_FOREVER); + if(status!=OK) { + epicsPrintf("dbLockSetGblLock failure\n"); + taskSuspend(0); + } + changingLockSets = TRUE; +} + +void dbLockSetGblUnlock(void) +{ + taskLock(); + changingLockSets = FALSE; + semFlush(globalWaitSemid); + taskUnlock(); + semGive(globalLockSemId); + return; +} + +void dbLockSetRecordLock(dbCommon *precord) +{ + lockRecord *plockRecord = (lockRecord *)precord->lset; + lockSet *plockSet; + STATUS status; + + /*Make sure that dbLockSetGblLock was called*/ + if(!changingLockSets) { + epicsPrintf("dbLockSetRecordLock called before dbLockSetGblLock\n"); + taskSuspend(0); + } + /*Must make sure that no other task has lock*/ + if(!plockRecord) return; + plockSet = plockRecord->plockSet; + if(!plockSet) return; + if(plockSet->task_id==taskIdSelf()) return; + /*Wait for up to 1 minute*/ + status = semTake(plockRecord->plockSet->semId,sysClkRateGet()*60); + if(status==OK) { + plockSet->start_time = tickGet(); + plockSet->task_id = taskIdSelf(); + plockSet->precord = (void *)precord; + /*give it back in case it will not be changed*/ + semGive(plockRecord->plockSet->semId); + return; + } + /*Should never reach this point*/ + epicsPrintf("dbLockSetRecordLock timeout caller 0x%x owner 0x%x", + taskIdSelf(),plockSet->task_id); + epicsPrintf(" record %s\n",precord->name); + return; +} + +void dbScanLock(dbCommon *precord) +{ + lockRecord *plockRecord = (lockRecord *)precord->lset; + lockSet *plockSet; + STATUS status; + + while(TRUE) { + if(changingLockSets) { + semTake(globalWaitSemid,WAIT_FOREVER); + continue; + } + status = semTake(plockRecord->plockSet->semId,WAIT_FOREVER); + /*semTake fails if semDelete was called while active*/ + if(status==OK) break; + } + plockSet = plockRecord->plockSet; + plockSet->start_time = tickGet(); + plockSet->task_id = taskIdSelf(); + plockSet->precord = (void *)precord; + return; +} + +void dbScanUnlock(dbCommon *precord) +{ + lockRecord *plockRecord = (lockRecord *)precord->lset; + + if(!plockRecord || !plockRecord->plockSet) { + epicsPrintf("dbScanUnlock plockRecord or plockRecord->plockSet NULL\n"); + return; + } + semGive(plockRecord->plockSet->semId); + return; +} + +unsigned long dbLockGetLockId(dbCommon *precord) +{ + lockRecord *plockRecord = (lockRecord *)precord->lset; + lockSet *plockSet; + + if(!plockRecord) return(0); + plockSet = plockRecord->plockSet; + if(!plockSet) return(0); + return(plockSet->id); +} + +void dbLockInitRecords(dbBase *pdbbase) +{ + int link; + dbRecDes *pdbRecDes; + dbFldDes *pdbFldDes; + dbRecordNode *pdbRecordNode; + dbCommon *precord; + DBLINK *plink; + int nrecords=0; + lockRecord *plockRecord; + + /*Allocate and initialize a lockRecord for each record instance*/ + for(pdbRecDes = (dbRecDes *)ellFirst(&pdbbase->recDesList); pdbRecDes; + pdbRecDes = (dbRecDes *)ellNext(&pdbRecDes->node)) { + nrecords += ellCount(&pdbRecDes->recList); + } + /*Allocate all of them at once */ + plockRecord = dbCalloc(nrecords,sizeof(lockRecord)); + for(pdbRecDes = (dbRecDes *)ellFirst(&pdbbase->recDesList); pdbRecDes; + pdbRecDes = (dbRecDes *)ellNext(&pdbRecDes->node)) { + for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecDes->recList); + pdbRecordNode; + pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) { + precord = pdbRecordNode->precord; + plockRecord->precord = precord; + precord->lset = plockRecord; + plockRecord++; + } + } + for(pdbRecDes = (dbRecDes *)ellFirst(&pdbbase->recDesList); pdbRecDes; + pdbRecDes = (dbRecDes *)ellNext(&pdbRecDes->node)) { + for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecDes->recList); + pdbRecordNode; + pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) { + precord = pdbRecordNode->precord; + if(!(precord->name[0])) continue; + for(link=0; linkno_links; link++) { + DBADDR *pdbAddr; + + pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[link]]; + plink = (DBLINK *)((char *)precord + pdbFldDes->offset); + if(plink->type != DB_LINK) continue; + pdbAddr = (DBADDR *)(plink->value.pv_link.pvt); + /* The current record is in a different lockset -IF- + * 1. Input link + * 2. Not Process Passive + * 3. Not Maximize Severity + * 4. Not An Array Operation - single element only + */ + if (pdbFldDes->field_type==DBF_INLINK + && !(plink->value.pv_link.pvlMask&pvlOptPP) + && !(plink->value.pv_link.pvlMask&pvlOptMS) + && pdbAddr->no_elements<=1) continue; + dbLockSetMerge(precord,pdbAddr->precord); + } + plockRecord = (lockRecord *)precord->lset; + if(!plockRecord->plockSet) allocLock(plockRecord); + } + } +} + +void dbLockSetMerge(dbCommon *pfirst,dbCommon *psecond) +{ + lockRecord *p1lockRecord = (lockRecord *)pfirst->lset; + lockRecord *p2lockRecord = (lockRecord *)psecond->lset; + lockSet *p1lockSet; + lockSet *p2lockSet; + + p1lockSet = p1lockRecord->plockSet; + p2lockSet = p2lockRecord->plockSet; + if(!p1lockSet) { + if(p2lockSet) { + lockAddRecord(p2lockSet,p1lockRecord); + return; + } + p1lockSet = allocLock(p1lockRecord); + } + if(p1lockSet == p2lockSet) return; + if(!p2lockSet) { + lockAddRecord(p1lockSet,p2lockRecord); + return; + } + /*Move entire second list to first*/ + p2lockRecord = (lockRecord *)ellFirst(&p2lockSet->recordList); + while(p2lockRecord) { + p2lockRecord->plockSet = p1lockSet; + p2lockRecord = (lockRecord *)ellNext(&p2lockRecord->node); + } + ellConcat(&p1lockSet->recordList,&p2lockSet->recordList); + if(semDelete(p2lockSet->semId)!=OK) { + errMessage(0,"dbLockSetMerge calling semDelete"); + taskSuspend(0); + } + ellDelete(&lockList,&p2lockSet->node); + free((void *)p2lockSet); + return; +} + +void dbLockSetSplit(dbCommon *psource) +{ + lockSet *plockSet; + lockRecord *plockRecord; + dbCommon *precord; + int link; + dbRecDes *pdbRecDes; + dbFldDes *pdbFldDes; + DBLINK *plink; + int nrecordsInSet,i; + dbCommon **paprecord; + + plockRecord = (lockRecord *)psource->lset; + if(!plockRecord) { + errMessage(-1,"dbLockSetSplit called before lockRecord allocated"); + return; + } + plockSet = plockRecord->plockSet; + if(!plockSet) { + errMessage(-1,"dbLockSetSplit called without lockSet allocated"); + return; + } + /*First remove all records from lock set*/ + nrecordsInSet = ellCount(&plockSet->recordList); + paprecord = dbCalloc(nrecordsInSet,sizeof(dbCommon *)); + for(plockRecord = (lockRecord *)ellFirst(&plockSet->recordList), i=0; + plockRecord; + plockRecord = (lockRecord *)ellNext(&plockRecord->node), i++) { + paprecord[i] = plockRecord->precord; + plockRecord->plockSet = 0; + } + /*Now recompute lock sets */ + for(i=0; ilset; + if(!(precord->name[0])) continue; + pdbRecDes = (dbRecDes *)precord->rdes; + for(link=0; linkno_links; link++) { + DBADDR *pdbAddr; + + pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[link]]; + plink = (DBLINK *)((char *)precord + pdbFldDes->offset); + if(plink->type != DB_LINK) continue; + + pdbAddr = (DBADDR *)(plink->value.pv_link.pvt); + if (pdbFldDes->field_type==DBF_INLINK + && !(plink->value.pv_link.pvlMask&pvlOptPP) + && !(plink->value.pv_link.pvlMask&pvlOptMS) + && pdbAddr->no_elements<=1) continue; + dbLockSetMerge(precord,pdbAddr->precord); + } + if(!plockRecord->plockSet) allocLock(plockRecord); + } + if(semDelete(plockSet->semId)!=OK) { + errMessage(0,"dbLockSetSplit calling semDelete"); + taskSuspend(0); + } + ellDelete(&lockList,&plockSet->node); + free((void *)plockSet); + free((void *)paprecord); +} + +extern struct dbBase *pdbbase; +long dblls(char *recordname,int level) +{ + int link; + DBENTRY dbentry; + DBENTRY *pdbentry=&dbentry; + long status; + dbCommon *precord; + lockSet *plockSet; + lockRecord *plockRecord; + dbRecDes *pdbRecDes; + dbFldDes *pdbFldDes; + DBLINK *plink; + + if(recordname) { + dbInitEntry(pdbbase,pdbentry); + status = dbFindRecord(pdbentry,recordname); + if(status) { + printf("Record not found\n"); + dbFinishEntry(pdbentry); + return(0); + } + precord = pdbentry->precnode->precord; + dbFinishEntry(pdbentry); + plockRecord = (lockRecord *)precord->lset; + if(!plockRecord) return(0); + plockSet = plockRecord->plockSet; + } else { + plockSet = (lockSet *)ellFirst(&lockList); + } + for( ; plockSet; plockSet = (lockSet *)ellNext(&plockSet->node)) { + double lockSeconds; + + printf("Lock Set %lu %d members", + plockSet->id,ellCount(&plockSet->recordList)); + if(semTake(plockSet->semId,NO_WAIT)==OK) { + semGive(plockSet->semId); + printf(" Not Locked\n"); + } else { + lockSeconds = plockSet->start_time; + lockSeconds = (tickGet() - lockSeconds) / sysClkRateGet(); + printf(" Locked %f seconds", lockSeconds); + printf(" task 0x%x",plockSet->task_id); + if(! plockSet->precord || !plockSet->precord->name) + printf(" NULL record or record name\n"); + else + printf(" record %s\n",plockSet->precord->name); + } + if(level==0) { + if(recordname) break; + continue; + } + for(plockRecord = (lockRecord *)ellFirst(&plockSet->recordList); + plockRecord; plockRecord = (lockRecord *)ellNext(&plockRecord->node)) { + precord = plockRecord->precord; + pdbRecDes = (dbRecDes *)precord->rdes; + printf("%s\n",precord->name); + if(level<=1) continue; + for(link=0; (linkno_links) ; link++) { + DBADDR *pdbAddr; + + pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[link]]; + plink = (DBLINK *)((char *)precord + pdbFldDes->offset); + if(plink->type != DB_LINK) continue; + pdbAddr = (DBADDR *)(plink->value.pv_link.pvt); + printf("\t%s",pdbFldDes->name); + if(pdbFldDes->field_type==DBF_INLINK) { + printf("\t INLINK"); + } else if(pdbFldDes->field_type==DBF_OUTLINK) { + printf("\tOUTLINK"); + } else if(pdbFldDes->field_type==DBF_FWDLINK) { + printf("\tFWDLINK"); + } + printf(" %s %s", + ((plink->value.pv_link.pvlMask&pvlOptPP)?" PP":"NPP"), + ((plink->value.pv_link.pvlMask&pvlOptMS)?" MS":"NMS")); + printf(" %s\n",pdbAddr->precord->name); + } + } + if(recordname) break; + } + return(0); +} diff --git a/src/db/dbLock.h b/src/db/dbLock.h new file mode 100644 index 000000000..4574b6806 --- /dev/null +++ b/src/db/dbLock.h @@ -0,0 +1,36 @@ +/* dbLock.h */ +/* Author: Marty Kraimer Date: 12MAR96 */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +**********************************************************************/ + +/* Modification Log: + * ----------------- + * .01 12MAR96 mrk Initial Implementation +*/ +#ifndef INCdbLockh +#define INCdbLockh +void dbScanLock(struct dbCommon *precord); +void dbScanUnlock(struct dbCommon *precord); +unsigned long dbLockGetLockId(struct dbCommon *precord); + +void dbLockInitRecords(dbBase *pdbbase); +void dbLockSetMerge(struct dbCommon *pfirst,struct dbCommon *psecond); +void dbLockSetSplit(struct dbCommon *psource); +/*The following are for code that modifies lock sets*/ +void dbLockSetGblLock(void); +void dbLockSetGblUnlock(void); +void dbLockSetRecordLock(struct dbCommon *precord); + +long dblls(char *recordname,int level); /*list all records in same lock set*/ +/* If recordname NULL then all records*/ +/* level = (0,1,2) (lock set state, + recordname, +DB links) */ + +#endif /*INCdbLockh*/ diff --git a/src/db/dbScan.c b/src/db/dbScan.c index 6c0a7473a..b5193ea06 100644 --- a/src/db/dbScan.c +++ b/src/db/dbScan.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -72,7 +73,7 @@ extern struct dbBase *pdbbase; /* SCAN ONCE */ -#define ONCE_QUEUE_SIZE 256 +int onceQueueSize = 256; static SEM_ID onceSem; static RING_ID onceQ; static int onceTaskId; @@ -426,9 +427,15 @@ static void onceTask(void) } } +int scanOnceSetQueueSize(int size) +{ + onceQueueSize = size; + return(0); +} + static void initOnce(void) { - if((onceQ = rngCreate(sizeof(void *) * ONCE_QUEUE_SIZE))==NULL){ + if((onceQ = rngCreate(sizeof(void *) * onceQueueSize))==NULL){ errMessage(0,"dbScan: initOnce failed"); exit(1); } @@ -485,10 +492,12 @@ static void initPeriodic() static void spawnPeriodic(int ind) { - struct scan_list *psl; + struct scan_list *psl; + char taskName[20]; psl = papPeriodic[ind]; - periodicTaskId[ind] = taskSpawn(PERIODSCAN_NAME,PERIODSCAN_PRI-ind, + sprintf(taskName,"scan%d",psl->ticks); + periodicTaskId[ind] = taskSpawn(taskName,PERIODSCAN_PRI-ind, PERIODSCAN_OPT,PERIODSCAN_STACK, (FUNCPTR )periodicTask,(int)psl, 0,0,0,0,0,0,0,0,0); diff --git a/src/db/dbScan.h b/src/db/dbScan.h index f645f53bc..007027650 100644 --- a/src/db/dbScan.h +++ b/src/db/dbScan.h @@ -50,6 +50,7 @@ void post_event(int event); void scanAdd(struct dbCommon *); void scanDelete(struct dbCommon *); void scanOnce(void *precord); +int scanOnceSetQueueSize(int size); int scanppl(void); /*print periodic lists*/ int scanpel(void); /*print event lists*/ int scanpiol(void); /*print io_event list*/ diff --git a/src/db/dbTest.c b/src/db/dbTest.c index 3d65d4fa7..9329641c0 100644 --- a/src/db/dbTest.c +++ b/src/db/dbTest.c @@ -57,8 +57,6 @@ long dbtgf(char *pname); /*test get field*/ long dbtpf(char *pname,char *pvalue); /*test put field*/ long dbior(char *pdrvName,int type); /*I/O report */ int dbhcr(void); /*Hardware Configuration Report*/ -long dblls(int lockset); /*list lock sets*/ -int dbllsdblinks(int lset); /*List dblinks for each record in lock set*/ #include #include @@ -72,6 +70,7 @@ int dbllsdblinks(int lset); /*List dblinks for each record in lock set*/ #include #include #include +#include #include #include #include @@ -110,8 +109,8 @@ static void dbpr_init_msg(TAB_BUFFER *pMsgBuff,int tab_size); static void dbpr_insert_msg(TAB_BUFFER *pMsgBuff,int len,int tab_size); static void dbpr_msg_flush(TAB_BUFFER *pMsgBuff,int tab_size); static void dbprReportLink( - TAB_BUFFER *pMsgBuff,char *pfield_name,struct link *plink, - short field_type,int tab_size); + TAB_BUFFER *pMsgBuff,char *precord_name, char *pfield_name, + struct link *plink, short field_type,int tab_size); static void dbprReportMenu( TAB_BUFFER *pMsgBuff,struct dbCommon *precord,dbFldDes *pdbFldDes, unsigned short choice_value,int tab_size); @@ -693,37 +692,6 @@ int dbhcr(void) return(0); } -long dblls(int lockset) -{ - DBENTRY dbentry; - DBENTRY *pdbentry=&dbentry; - long status; - struct dbCommon *precord; - - dbInitEntry(pdbbase,pdbentry); - status = dbFirstRecdes(pdbentry); - printf(" lset lcnt disv disa pact\n"); - while(!status) { - status = dbFirstRecord(pdbentry); - while(!status) { - precord = pdbentry->precnode->precord; - if(lockset==0 || lockset==precord->lset) { - printf("%5.5d %5.5d %5.5d %5.5d %5.5d %s\n", - precord->lset, - precord->lcnt, - precord->disv, - precord->disa, - precord->pact, - precord->name); - } - status = dbNextRecord(pdbentry); - } - status = dbNextRecdes(pdbentry); - } - dbFinishEntry(pdbentry); - return(0); -} - static char *dbf[DBF_NTYPES]={ "STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG", "FLOAT","DOUBLE","ENUM","MENU","DEVICE", @@ -1150,18 +1118,11 @@ static int dbpr_report( *(unsigned short *)pfield, tab_size); break; case DBF_INLINK: - dbprReportLink(pMsgBuff, pfield_name, - (struct link *) pfield, pdbFldDes->field_type, tab_size); - break; case DBF_OUTLINK: - dbprReportLink(pMsgBuff, pfield_name, - (struct link *) pfield, pdbFldDes->field_type, tab_size); - break; case DBF_FWDLINK: - dbprReportLink(pMsgBuff, pfield_name, + dbprReportLink(pMsgBuff, paddr->precord->name,pfield_name, (struct link *) pfield, pdbFldDes->field_type, tab_size); break; - break; default: sprintf(pmsg, "%s: dbpr: Unknown field_type", pfield_name); dbpr_msgOut(pMsgBuff, tab_size); @@ -1269,129 +1230,39 @@ static void dbpr_msg_flush(TAB_BUFFER *pMsgBuff,int tab_size) } static void dbprReportLink( - TAB_BUFFER *pMsgBuff,char *pfield_name,struct link *plink, - short field_type,int tab_size) + TAB_BUFFER *pMsgBuff,char *precordname,char *pfield_name, + struct link *plink, short field_type,int tab_size) { - char *pmsg = pMsgBuff->message; - switch(plink->type) { - case CONSTANT: - sprintf(pmsg,"%4s: %s", pfield_name, plink->value.constantStr); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case PV_LINK: - if(field_type != DBF_FWDLINK) { - sprintf(pmsg,"%4s: PV_LINK pp=%1d ms=%1d %s", - pfield_name, - plink->value.pv_link.process_passive, - plink->value.pv_link.maximize_sevr, - plink->value.pv_link.pvname); - } else { - sprintf(pmsg,"%4s: PV_LINK %s", - pfield_name, - plink->value.pv_link.pvname); - } - dbpr_msgOut(pMsgBuff,tab_size); - break; - case VME_IO: - sprintf(pmsg,"%4s: VME card=%2d signal=%2d parm=%s", - pfield_name, - plink->value.vmeio.card,plink->value.vmeio.signal, - plink->value.vmeio.parm); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case VXI_IO: - if(plink->value.vxiio.flag==0) - { - sprintf(pmsg,"%4s: VXI frame=%2d slot=%2d signal=%2d parm=%s", - pfield_name, - plink->value.vxiio.frame, - plink->value.vxiio.slot, - plink->value.vxiio.signal, - plink->value.vxiio.parm); - } - else - { - sprintf(pmsg,"%4s: VXI la=%2d signal=%2d parm=%s", - pfield_name, - plink->value.vxiio.la, - plink->value.vxiio.signal, - plink->value.vxiio.parm); - } - dbpr_msgOut(pMsgBuff,tab_size); - break; - case CAMAC_IO: - sprintf(pmsg,"%4s: CAMAC b=%2d c=%2d n=%2d a=%2d f=%2d parm=%s", - pfield_name, - plink->value.camacio.b,plink->value.camacio.c, - plink->value.camacio.n,plink->value.camacio.a, - plink->value.camacio.f,plink->value.camacio.parm); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case AB_IO: - sprintf(pmsg,"%4s: ABIO link=%2d adaptor=%2d card=%2d signal=%2d parm=%s", - pfield_name, - plink->value.abio.link,plink->value.abio.adapter, - plink->value.abio.card,plink->value.abio.signal, - plink->value.abio.parm); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case GPIB_IO: - sprintf(pmsg,"%4s: GPIB link=%2d addr=%2d parm=%s", - pfield_name, - plink->value.gpibio.link, plink->value.gpibio.addr, - &plink->value.gpibio.parm[0]); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case BITBUS_IO: - sprintf(pmsg,"%4s: BITBUS link=%2d node=%2d port=%2d signal=%2d parm=%s", - pfield_name, - plink->value.bitbusio.link,plink->value.bitbusio.node, - plink->value.bitbusio.port,plink->value.bitbusio.signal, - &plink->value.bitbusio.parm[0]); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case BBGPIB_IO: - sprintf(pmsg,"%4s: BBGPIBIO link=%2d bbaddr=%2d gpibio=%2d parm=%s", - pfield_name, - plink->value.bbgpibio.link,plink->value.bbgpibio.bbaddr, - plink->value.bbgpibio.gpibaddr, - &plink->value.bbgpibio.parm[0]); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case INST_IO: - sprintf(pmsg,"%4s: INSTIO parm=%s", - pfield_name, - &plink->value.instio.string[0]); - dbpr_msgOut(pMsgBuff,tab_size); - break; - case DB_LINK: - if(field_type != DBF_FWDLINK) { - DBADDR *paddr = (DBADDR *)plink->value.db_link.pdbAddr; + char *pmsg = pMsgBuff->message; + DBENTRY dbEntry; + DBENTRY *pdbEntry; + long status; + char *pvalue; - sprintf(pmsg,"%4s: DB_LINK pp=%1d ms=%1d %s", - pfield_name, - plink->value.db_link.process_passive, - plink->value.db_link.maximize_sevr, - paddr->precord->name); - }else{ - sprintf(pmsg,"%4s: DB_LINK %.32s", - pfield_name, - ((struct dbCommon *)( - ((DBADDR *)plink->value.db_link.pdbAddr) - ->precord))->name); + pdbEntry = &dbEntry; + dbInitEntry(pdbbase,pdbEntry); + status = dbFindRecord(pdbEntry,precordname); + if(!status) status = dbFindField(pdbEntry,pfield_name); + if(status) { + sprintf(pmsg,"%4s: dbGetString Failed", pfield_name); + } else { + int ind; + + for(ind=0; indtype) break; + } + if(ind>=LINK_NTYPES) { + sprintf(pmsg,"%4s: Illegal Link Type", pfield_name); + } else { + pvalue = dbGetString(pdbEntry); + sprintf(pmsg,"%4s:%s %s", + pfield_name, + pamaplinkType[ind].strvalue, + pvalue); } - dbpr_msgOut(pMsgBuff,tab_size); - break; - case CA_LINK: - sprintf(pmsg,"%4s: CA_LINK",pfield_name); - dbpr_msgOut(pMsgBuff,tab_size); - break; - default: - sprintf(pmsg,"%4s: dbprReportLink: Illegal link.type", - pfield_name); - dbpr_msgOut(pMsgBuff,tab_size); - break; } + dbpr_msgOut(pMsgBuff,tab_size); + dbFinishEntry(&dbEntry); return; } @@ -1478,45 +1349,3 @@ char *record_name; return(0); } - -int dbllsdblinks(int lset) -{ - int link; - dbRecDes *pdbRecDes; - dbFldDes *pdbFldDes; - dbRecordNode *pdbRecordNode; - dbCommon *precord; - DBLINK *plink; - - for(pdbRecDes = (dbRecDes *)ellFirst(&pdbbase->recDesList); pdbRecDes; - pdbRecDes = (dbRecDes *)ellNext(&pdbRecDes->node)) { - for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecDes->recList); - pdbRecordNode; - pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) { - precord = pdbRecordNode->precord; - if(!(precord->name[0])) continue; - if(precord->lset != lset) continue; - printf("%s\n",precord->name); - for(link=0; (linkno_links) ; link++) { - DBADDR *pdbAddr; - - pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[link]]; - plink = (DBLINK *)((char *)precord + pdbFldDes->offset); - if(plink->type != DB_LINK) continue; - pdbAddr = (DBADDR *)(plink->value.db_link.pdbAddr); - if(pdbFldDes->field_type==DBF_INLINK) { - printf("\t INLINK"); - } else if(pdbFldDes->field_type==DBF_OUTLINK) { - printf("\tOUTLINK"); - } else if(pdbFldDes->field_type==DBF_FWDLINK) { - printf("\tFWDLINK"); - } - printf(" %s %s", - ((plink->value.db_link.process_passive)?" PP":"NPP"), - ((plink->value.db_link.maximize_sevr)?" MS":"NMS")); - printf(" %s\n",pdbAddr->precord->name); - } - } - } - return(0); -} diff --git a/src/db/db_access.c b/src/db/db_access.c index 2a517d458..b4fa3bb75 100644 --- a/src/db/db_access.c +++ b/src/db/db_access.c @@ -116,6 +116,9 @@ #define oldDBR_PUT_ACKT oldDBR_CTRL_DOUBLE + 1 #define oldDBR_PUT_ACKS oldDBR_PUT_ACKT + 1 #define oldDBR_STSACK_STRING oldDBR_PUT_ACKS + 1 + +/*Following is defined in db_access.h*/ +extern unsigned short dbDBRnewToDBRold[DBR_ENUM+1]; /* function declarations */ @@ -572,8 +575,6 @@ void fill(pbuffer,size,fillchar) /* * DB_NAME_TO_ADDR */ -static short mapNewToOld[]={0,4,4,1,5,5,6,2,6,3}; - short db_name_to_addr(pname,paddr) char *pname; struct dbAddr *paddr; @@ -588,7 +589,7 @@ short db_name_to_addr(pname,paddr) recGblDbaddrError(S_db_badDbrtype,paddr,"db_name_to_addr error"); return(-2); } - paddr->dbr_field_type = mapNewToOld[ftype]; + paddr->dbr_field_type = dbDBRnewToDBRold[ftype]; return(0); } else diff --git a/src/db/db_access.h b/src/db/db_access.h index de24ec387..c670960b9 100644 --- a/src/db/db_access.h +++ b/src/db/db_access.h @@ -237,6 +237,54 @@ READONLY int epicsTypeToDBR_XXXX [lastEpicsType+1] = { epicsShareExtern READONLY int epicsTypeToDBR_XXXX [lastEpicsType+1]; #endif +/*Definitions that allow old database access to use new conversion routines*/ +#define newDBF_DEVICE 11 +#define newDBR_ENUM 9 +#ifdef __STDC__ +void *dbCalloc(size_t nobj,size_t size); +void *dbMalloc(size_t size); +extern long (*dbGetConvertRoutine[newDBF_DEVICE+1][newDBR_ENUM+1]) + (struct db_addr *paddr, void *pbuffer,long nRequest, + long no_elements, long offset); +extern long (*dbPutConvertRoutine[newDBR_ENUM+1][newDBF_DEVICE+1]) + (struct db_addr *paddr, void *pbuffer,long nRequest, + long no_elements, long offset); +extern long (*dbFastGetConvertRoutine[newDBF_DEVICE+1][newDBR_ENUM+1])(); +extern long (*dbFastPutConvertRoutine[newDBR_ENUM+1][newDBF_DEVICE+1])(); +#else +extern long (*dbGetConvertRoutine[newDBF_DEVICE+1][newDBR_ENUM+1]) (); +extern long (*dbPutConvertRoutine[newDBR_ENUM+1][newDBF_DEVICE+1]) (); +extern long (*dbFastGetConvertRoutine[newDBF_DEVICE+1][newDBR_ENUM+1])(); +extern long (*dbFastPutConvertRoutine[newDBR_ENUM+1][newDBF_DEVICE+1])(); +#endif /*__STDC__*/ + +/*Conversion between old and new DBR types*/ +extern unsigned short dbDBRoldToDBFnew[DBR_DOUBLE+1]; +extern unsigned short dbDBRnewToDBRold[newDBR_ENUM+1]; +#ifdef DB_TEXT_GLBLSOURCE +unsigned short dbDBRoldToDBFnew[DBR_DOUBLE+1] = { + 0, /*DBR_STRING to DBF_STRING*/ + 3, /*DBR_INT to DBF_SHORT*/ + 7, /*DBR_FLOAT to DBF_FLOAT*/ + 9, /*DBR_ENUM to DBF_ENUM*/ + 1, /*DBR_CHAR to DBF_CHAR*/ + 5, /*DBR_LONG to DBF_LONG*/ + 8 /*DBR_DOUBLE to DBF_DOUBLE*/ +}; +unsigned short dbDBRnewToDBRold[newDBR_ENUM+1] = { + 0, /*DBR_STRING to DBR_STRING*/ + 4, /*DBR_CHAR to DBR_CHAR*/ + 4, /*DBR_UCHAR to DBR_CHAR*/ + 1, /*DBR_SHORT to DBR_SHORT*/ + 5, /*DBR_USHORT to DBR_LONG*/ + 5, /*DBR_LONG to DBR_LONG*/ + 6, /*DBR_ULONG to DBR_DOUBLE*/ + 2, /*DBR_FLOAT to DBR_FLOAT*/ + 6, /*DBR_DOUBLE to DBR_DOUBLE*/ + 3, /*DBR_ENUM to DBR_ENUM*/ +}; +#endif /*DB_TEXT_GLBLSOURCE*/ + /* * The DBR_XXXX types are indicies into this array */ @@ -290,7 +338,7 @@ epicsShareExtern READONLY epicsType DBR_XXXXToEpicsType [LAST_BUFFER_TYPE+1]; #define EP_SCAN 0x01 #define EP_INIT 0x02 #define EP_CALC 0x03 - + /* values returned for each field type * DBR_STRING returns a NULL terminated string * DBR_SHORT returns an unsigned short diff --git a/src/db/db_addr.h b/src/db/db_addr.h index 701d664b0..3f418738a 100644 --- a/src/db/db_addr.h +++ b/src/db/db_addr.h @@ -39,7 +39,7 @@ struct db_addr{ void *asPvt; /*Access Security Private */ short pad1; /*not used by old */ short no_elements; /* number of elements in arrays of data */ - short pad2; /* not used by old */ + short new_field_type; /* field type for new database access*/ short field_size; /* size of the field being accessed */ /* from database for values of waveforms */ short special; /* special processing */ diff --git a/src/db/dbcal.c b/src/db/dbcal.c new file mode 100644 index 000000000..cd2de2162 --- /dev/null +++ b/src/db/dbcal.c @@ -0,0 +1,125 @@ +/* dbcal.c */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1991 Regents of the University of California, +and the University of Chicago Board of Governors. + +This software was developed under a United States Government license +described on the COPYRIGHT_Combined file included as part +of this distribution. +**********************************************************************/ + +/**************************************************************** +* +* Current Author: Marty Kraimer +* Date: 10APR96 +* +* +* Modification Log: +* ----------------- +* .01 10APR96 mrk list db to CA links +****************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "dbStaticLib.h" +#include "link.h" +/*definitions needed because of old vs new database access*/ +#undef DBR_SHORT +#undef DBR_PUT_ACKT +#undef DBR_PUT_ACKS +#undef VALID_DB_REQ +#undef INVALID_DB_REQ +/*end of conflicting definitions*/ +#include "cadef.h" +#include "epicsPrint.h" +#include "dbCommon.h" +#include "dbCa.h" +extern struct dbBase *pdbbase; + +long dbcal(char *precordname,int level) +{ + DBENTRY dbentry; + DBENTRY *pdbentry=&dbentry; + long status; + dbCommon *precord; + dbRecDes *pdbRecDes; + dbFldDes *pdbFldDes; + DBLINK *plink; + int ncalinks=0; + int nconnected=0; + int noReadAccess=0; + int noWriteAccess=0; + unsigned long nDisconnect=0; + unsigned long nNoWrite=0; + caLink *pca; + int j; + + + dbInitEntry(pdbbase,pdbentry); + status = dbFirstRecdes(pdbentry); + while(!status) { + status = dbFirstRecord(pdbentry); + while(!status) { + if(!precordname + || (strcmp(precordname,dbGetRecordName(pdbentry)) ==0)) { + pdbRecDes = pdbentry->precdes; + precord = (dbCommon *)pdbentry->precnode->precord; + for(j=0; jno_links; j++) { + pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[j]]; + plink = (DBLINK *)((char *)precord + pdbFldDes->offset); + if (plink->type == CA_LINK) { + ncalinks++; + pca = (caLink *)plink->value.pv_link.pvt; + if(pca && (ca_field_type(pca->chid) != TYPENOTCONN)) { + nconnected++; + nDisconnect += pca->nDisconnect; + nNoWrite += pca->nNoWrite; + if(!ca_read_access(pca->chid)) noReadAccess++; + if(!ca_write_access(pca->chid)) noWriteAccess++; + if(level>1) { + printf(" connected"); + printf("%s",ca_host_name(pca->chid)); + if(!ca_read_access(pca->chid)) + printf(" no_read_access"); + if(!ca_write_access(pca->chid)) + printf(" no_write_access"); + printf(" %s.%s %s", + precord->name, + pdbFldDes->name, + plink->value.pv_link.pvname); + printf(" nDisconnect %lu nNoWrite %lu\n", + pca->nDisconnect,pca->nNoWrite); + } + } else { + if(level>0) { + printf("not_connected %s.%s", + precord->name,pdbFldDes->name); + printf(" nDisconnect %lu nNoWrite %lu\n", + pca->nDisconnect,pca->nNoWrite); + } + } + } + } + if(precordname) goto done; + } + status = dbNextRecord(pdbentry); + } + status = dbNextRecdes(pdbentry); + } +done: + printf("ncalinks %d",ncalinks); + printf(" not connected %d",(ncalinks - nconnected)); + printf(" no_read_access %d",noReadAccess); + printf(" no_write_access %d\n",noWriteAccess); + printf(" nDisconnect %lu nNoWrite %lu\n",nDisconnect,nNoWrite); + dbFinishEntry(pdbentry); + return(0); +} diff --git a/src/db/initHooks.c b/src/db/initHooks.c index a1c9ce223..7a3988cab 100644 --- a/src/db/initHooks.c +++ b/src/db/initHooks.c @@ -73,8 +73,6 @@ int callNumber; break; case INITHOOKafterInitDatabase : break; - case INITHOOKafterCaLinkInit2 : - break; case INITHOOKafterFinishDevSup : break; case INITHOOKafterScanInit : diff --git a/src/db/initHooks.h b/src/db/initHooks.h index 825d7476d..43eb4e2f1 100644 --- a/src/db/initHooks.h +++ b/src/db/initHooks.h @@ -45,11 +45,10 @@ #define INITHOOKafterInitDevSup 7 #define INITHOOKafterTS_init 8 #define INITHOOKafterInitDatabase 9 -#define INITHOOKafterCaLinkInit2 10 -#define INITHOOKafterFinishDevSup 11 -#define INITHOOKafterScanInit 12 -#define INITHOOKafterInterruptAccept 13 -#define INITHOOKafterInitialProcess 14 -#define INITHOOKatEnd 15 +#define INITHOOKafterFinishDevSup 10 +#define INITHOOKafterScanInit 11 +#define INITHOOKafterInterruptAccept 12 +#define INITHOOKafterInitialProcess 13 +#define INITHOOKatEnd 14 #endif /*INCinitHooksh*/ diff --git a/src/db/iocInit.c b/src/db/iocInit.c index 371b47ca9..dc9106897 100644 --- a/src/db/iocInit.c +++ b/src/db/iocInit.c @@ -79,12 +79,13 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -115,9 +116,6 @@ LOCAL long initRecSup(void); LOCAL long initDevSup(void); LOCAL long finishDevSup(void); LOCAL long initDatabase(void); -LOCAL void createLockSets(void); -LOCAL void createLockSetsExtraPass(int *anyChange); -LOCAL short makeSameSet(struct dbAddr *paddr,short set,int *anyChange); LOCAL long initialProcess(void); LOCAL long getResources(char *fname); LOCAL int getResourceToken(FILE *fp, char *pToken, unsigned maxToken); @@ -142,7 +140,7 @@ int iocInit(char * pResourceFilename) } if (!pdbbase) { - logMsg("iocInit aborting because No database loaded by dbReadDatabase\n", + logMsg("iocInit aborting because No database\n", 0,0,0,0,0,0); return(-1); } @@ -182,8 +180,8 @@ int iocInit(char * pResourceFilename) (void)taskDelay(sysClkRateGet()/10); if (pinitHooks) (*pinitHooks)(INITHOOKafterCallbackInit); - /* Initialize Channel Access Link mechanism. Pass #1 */ - dbCaLinkInit((int) 1); + /* Initialize Channel Access Link mechanism. */ + dbCaLinkInit(); if (pinitHooks) (*pinitHooks)(INITHOOKafterCaLinkInit1); if (initDrvSup() != 0) @@ -207,12 +205,9 @@ int iocInit(char * pResourceFilename) if (initDatabase() != 0) logMsg("iocInit: Database Failed during Initialization\n",0,0,0,0,0,0); - createLockSets(); + dbLockInitRecords(pdbbase); if (pinitHooks) (*pinitHooks)(INITHOOKafterInitDatabase); - dbCaLinkInit((int) 2); - if (pinitHooks) (*pinitHooks)(INITHOOKafterCaLinkInit2); - if (finishDevSup() != 0) logMsg("iocInit: Device Support Failed during Finalization\n", 0,0,0,0,0,0); @@ -428,6 +423,7 @@ LOCAL long initDatabase(void) precord = pdbRecordNode->precord; if(!(precord->name[0])) continue; precord->rset = prset; + precord->rdes = pdbRecDes; FASTLOCKINIT(&precord->mlok); ellInit(&(precord->mlis)); @@ -438,8 +434,6 @@ LOCAL long initDatabase(void) pdevSup = (devSup *)ellNth(&pdbRecDes->devList,precord->dtyp+1); pdset = (pdevSup ? pdevSup->pdset : 0); precord->dset = pdset; - /* Initialize dbCommon - First pass (pass=0) */ - rtnval = dbCommonInit(precord,0); if(!prset->init_record) continue; rtnval = (*prset->init_record)(precord,0); if (status==0) status = rtnval; @@ -457,50 +451,29 @@ LOCAL long initDatabase(void) pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) { precord = pdbRecordNode->precord; if(!(precord->name[0])) continue; - /* - * Convert all PV_LINKs to DB_LINKs or CA_LINKs - * Figures out what type of link to use. A - * database link local to the IOC, or a channel - * access link across the network. - */ + /* Convert all PV_LINKs to DB_LINKs or CA_LINKs */ /* For all the links in the record type... */ for(j=0; jno_links; j++) { pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[j]]; plink = (DBLINK *)((char *)precord + pdbFldDes->offset); if (plink->type == PV_LINK) { - /* - * Lookup record name in database - * If a record is _not_ local to the IOC, it is a - * channel access link, otherwise it is a - * database link. - */ - if(dbNameToAddr(plink->value.pv_link.pvname,&dbaddr) == 0) { + 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.db_link.pdbAddr = pdbAddr; - /*Initialize conversion to "uninitialized" conversion */ - plink->value.db_link.conversion = cvt_uninit; - } else { - /* - * Not a local process variable ... assuming a CA_LINK - * Only supporting Non Process Passive links, - * Input Maximize Severity/No Maximize Severity(MS/NMS) - * , and output NMS - * links ... The following code checks for this. - */ - if (errVerbose && - (plink->value.db_link.process_passive - || (pdbFldDes->field_type == DBF_OUTLINK - && plink->value.db_link.maximize_sevr))) { - status = S_db_badField; - errPrintf(status,__FILE__,__LINE__,"%s.%s %s", - precord->name,pdbFldDes->name, - " PP and/or MS illegal"); - status = 0; - } + plink->value.pv_link.pvt = pdbAddr; + } else {/*It is a CA link*/ + char *pperiod; + + dbCaAddLink(plink); + if(pdbFldDes->field_type==DBF_FWDLINK) { + pperiod = strrchr(plink->value.pv_link.pvname,'.'); + if(pperiod && strstr(pperiod,"PROC")) + plink->value.pv_link.pvlMask |= pvlOptFWD; + } } } } @@ -518,8 +491,6 @@ LOCAL long initDatabase(void) /* Find pointer to record instance */ precord = pdbRecordNode->precord; if(!(precord->name[0])) continue; - rtnval = dbCommonInit(precord,1); - if (status==0) status = rtnval; precord->rset = prset; if(!prset->init_record) continue; rtnval = (*prset->init_record)(precord,1); @@ -529,199 +500,6 @@ LOCAL long initDatabase(void) return(status); } -LOCAL void createLockSets(void) -{ - int link; - dbRecDes *pdbRecDes; - dbFldDes *pdbFldDes; - dbRecordNode *pdbRecordNode; - dbCommon *precord; - DBLINK *plink; - short nset,maxnset,newset; - int again; - int anyChange; - - nset = 0; - for(pdbRecDes = (dbRecDes *)ellFirst(&pdbbase->recDesList); pdbRecDes; - pdbRecDes = (dbRecDes *)ellNext(&pdbRecDes->node)) { - for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecDes->recList); - pdbRecordNode; - pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) { - precord = pdbRecordNode->precord; - if(!(precord->name[0])) continue; - if(precord->lset) continue; /*already in a lock set*/ - /* - * At First, assume record is in a different lockset - * We shall see later if this assumption is incorrect. - */ - precord->lset = maxnset = ++nset; - /* - * Use the process active flag to eliminate traversing - * cycles in the database "graph" - */ - precord->pact = TRUE; again = TRUE; - while(again) { - again = FALSE; - for(link=0; (linkno_links&&!again) ; link++) { - DBADDR *pdbAddr; - - pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[link]]; - plink = (DBLINK *)((char *)precord + pdbFldDes->offset); - if(plink->type != DB_LINK) continue; - - pdbAddr = (DBADDR *)(plink->value.db_link.pdbAddr); - - /* The current record is in a different lockset -IF- - * 1. Input link - * 2. Not Process Passive - * 3. Not Maximize Severity - * 4. Not An Array Operation - single element only - */ - if (pdbFldDes->field_type==DBF_INLINK - && ( !(plink->value.db_link.process_passive) - && !(plink->value.db_link.maximize_sevr)) - && pdbAddr->no_elements<=1) continue; - - /* - * Combine the lock sets of the current record with the - * remote record pointed to by the link. (recursively) - */ - newset = makeSameSet(pdbAddr,precord->lset,&anyChange); - - /* - * Perform an iteration of the while-loop again - * if we find that the record pointed to by - * the link has its lockset set earlier. If - * it has, set the current record's lockset to - * that of the link's endpoint. - */ - if (newset!=precord->lset) { - if(precord->lset==maxnset && maxnset==nset) nset--; - precord->lset = newset; - again = TRUE; - break; - } - } - } - precord->pact = FALSE; - } - } - anyChange = TRUE; - while(anyChange) { - anyChange = FALSE; - createLockSetsExtraPass(&anyChange); - } - dbScanLockInit(nset); -} - -LOCAL void createLockSetsExtraPass(int *anyChange) -{ - int link; - dbRecDes *pdbRecDes; - dbFldDes *pdbFldDes; - dbRecordNode *pdbRecordNode; - dbCommon *precord; - DBLINK *plink; - int again; - - for(pdbRecDes = (dbRecDes *)ellFirst(&pdbbase->recDesList); pdbRecDes; - pdbRecDes = (dbRecDes *)ellNext(&pdbRecDes->node)) { - for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecDes->recList); - pdbRecordNode; - pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) { - precord = pdbRecordNode->precord; - if(!(precord->name[0])) continue; - /*Prevent cycles in database graph*/ - precord->pact = TRUE; again = TRUE; - while(again) { - short newset; - - again = FALSE; - for(link=0; (linkno_links&&!again) ; link++) { - DBADDR *pdbAddr; - - pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[link]]; - plink = (DBLINK *)((char *)precord + pdbFldDes->offset); - if(plink->type != DB_LINK) continue; - pdbAddr = (DBADDR *)(plink->value.db_link.pdbAddr); - if(pdbFldDes->field_type==DBF_INLINK - && ( !(plink->value.db_link.process_passive) - && !(plink->value.db_link.maximize_sevr)) - && pdbAddr->no_elements<=1) continue; - - newset = makeSameSet(pdbAddr,precord->lset,anyChange); - if (newset!=precord->lset) { - precord->lset = newset; - *anyChange = TRUE; - again = TRUE; - break; - } - } - } - precord->pact = FALSE; - } - } -} - -LOCAL short makeSameSet(struct dbAddr *paddr, short lset,int *anyChange) -{ - dbCommon *precord = paddr->precord; - short link; - dbRecDes *pdbRecDes; - dbFldDes *pdbFldDes; - DBLINK *plink; - int again; - - /*Prevent cycles in database graph*/ - if(precord->pact) return(((precord->lsetlset : lset)); - - /* - * If the lock set of the link's endpoint is already set - * to the lockset we are setting it to, return... - */ - if(lset == precord->lset) return(lset); - - /* - * If the record has an uninitialized lock set field, - * we set it here. - */ - if(precord->lset == 0) precord->lset = lset; - - /* - * If the record is already in a lockset determined earlier, - * return that lock set. - */ - if(precord->lset < lset) return(precord->lset); - /* set pact to prevent cycles */ - precord->lset = lset; precord->pact = TRUE; again = TRUE; - while(again) { - again = FALSE; - pdbRecDes = ((dbFldDes *)paddr->pfldDes)->pdbRecDes; - for(link=0; linkno_links; link++) { - DBADDR *pdbAddr; - short newset; - - pdbFldDes = pdbRecDes->papFldDes[pdbRecDes->link_ind[link]]; - plink = (DBLINK *)((char *)precord + pdbFldDes->offset); - if(plink->type != DB_LINK) continue; - pdbAddr = (DBADDR *)(plink->value.db_link.pdbAddr); - if( pdbFldDes->field_type==DBF_INLINK - && ( !(plink->value.db_link.process_passive) - && !(plink->value.db_link.maximize_sevr) ) - && pdbAddr->no_elements<=1) continue; - newset = makeSameSet(pdbAddr,precord->lset,anyChange); - if(newset != precord->lset) { - precord->lset = newset; - again = TRUE; - *anyChange = TRUE; - break; - } - } - } - precord->pact = FALSE; - return(precord->lset); -} - /* * Process database records at initialization if * their pini (process at init) field is set. @@ -745,7 +523,15 @@ LOCAL long initialProcess(void) } return(0); } + + + +int dbLoadDatabase(char *filename,char *path) +{ + return(dbReadDatabase(&pdbbase,filename,path)); +} +/*Remaining code supplied by Bob Zieman*/ #define MAX 256 #define SAME 0 @@ -1098,8 +884,3 @@ LOCAL int getResourceTokenInternal(FILE *fp, char *pToken, unsigned maxToken) } return 0; } - -int dbLoadDatabase(char *filename,char *path) -{ - return(dbReadDatabase(&pdbbase,filename,path)); -} diff --git a/src/db/recGbl.c b/src/db/recGbl.c index b8d53915a..b23fdcd5e 100644 --- a/src/db/recGbl.c +++ b/src/db/recGbl.c @@ -111,27 +111,32 @@ void recGblRecSupError(long status,struct dbAddr *paddr,char *pcaller_name, { char buffer[200]; struct dbCommon *precord; - dbFldDes *pdbFldDes=(dbFldDes *)(paddr->pfldDes); - dbRecDes *pdbRecDes = pdbFldDes->pdbRecDes; + dbFldDes *pdbFldDes = 0; + dbRecDes *pdbRecDes = 0; + if(paddr) pdbFldDes=(dbFldDes *)(paddr->pfldDes); + if(pdbFldDes) pdbRecDes = pdbFldDes->pdbRecDes; buffer[0]=0; strcat(buffer,"Record Support Routine ("); if(psupport_name) strcat(buffer,psupport_name); else strcat(buffer,"Unknown"); - strcat(buffer,") not available.\nRecord Type is "); - strcat(buffer,pdbRecDes->name); - if(paddr) { /* print process variable name */ + strcat(buffer,") not available.\n"); + if(pdbRecDes) { + strcat(buffer,"Record Type is "); + strcat(buffer,pdbRecDes->name); + if(paddr) { /* print process variable name */ precord=(struct dbCommon *)(paddr->precord); strcat(buffer,", PV is "); strcat(buffer,precord->name); strcat(buffer,"."); strcat(buffer,pdbFldDes->name); - strcat(buffer," "); + strcat(buffer,"\n"); + } } if(pcaller_name) { - strcat(buffer,"\nerror detected in routine: "); + strcat(buffer,"error detected in routine: "); strcat(buffer,pcaller_name); } errMessage(status,buffer); @@ -164,7 +169,7 @@ void recGblGetPrec(struct dbAddr *paddr,long *precision) } return; } - + void recGblGetGraphicDouble(struct dbAddr *paddr,struct dbr_grDouble *pgd) { dbFldDes *pdbFldDes=(dbFldDes *)(paddr->pfldDes); @@ -174,7 +179,7 @@ void recGblGetGraphicDouble(struct dbAddr *paddr,struct dbr_grDouble *pgd) return; } - + void recGblGetAlarmDouble(struct dbAddr *paddr,struct dbr_alDouble *pad) { pad->upper_alarm_limit = 0; @@ -184,7 +189,7 @@ void recGblGetAlarmDouble(struct dbAddr *paddr,struct dbr_alDouble *pad) return; } - + void recGblGetControlDouble(struct dbAddr *paddr,struct dbr_ctrlDouble *pcd) { dbFldDes *pdbFldDes=(dbFldDes *)(paddr->pfldDes); @@ -246,70 +251,6 @@ int recGblInitConstantLink(struct link *plink,short dbftype,void *pdest) return(TRUE); } -long recGblGetLinkValue(struct link *plink,void *pdbc,short dbrType, - void *pdest,long *poptions,long *pnRequest) -{ - struct dbCommon *precord = pdbc; - long status=0; - unsigned char pact; - - pact = precord->pact; - precord->pact = TRUE; - switch (plink->type){ - case(CONSTANT): - *pnRequest = 0; - break; - case(DB_LINK): - status=dbGetLink(&(plink->value.db_link), - precord,dbrType,pdest,poptions,pnRequest); - if(status) - recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM); - break; - case(CA_LINK): - status=dbCaGetLink(plink); - if(status) - recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM); - break; - default: - status=-1; - recGblSetSevr(precord,SOFT_ALARM,INVALID_ALARM); - } - precord->pact = pact; - return(status); -} - -long recGblPutLinkValue(struct link *plink,void *pdbc,short dbrType, - void *psource,long *pnRequest) -{ - struct dbCommon *precord = pdbc; - long options=0; - long status=0; - unsigned char pact; - - pact = precord->pact; - precord->pact = TRUE; - switch (plink->type){ - case(CONSTANT): - break; - case(DB_LINK): - status=dbPutLink(&(plink->value.db_link), - precord,dbrType,psource,*pnRequest); - if(status) - recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM); - break; - case(CA_LINK): - status = dbCaPutLink(plink, &options, pnRequest); - if(status) - recGblSetSevr(precord,LINK_ALARM,INVALID_ALARM); - break; - default: - status=-1; - recGblSetSevr(precord,SOFT_ALARM,INVALID_ALARM); - } - precord->pact = pact; - return(status); -} - unsigned short recGblResetAlarms(void *precord) { struct dbCommon *pdbc = precord; @@ -342,10 +283,15 @@ unsigned short recGblResetAlarms(void *precord) void recGblFwdLink(void *precord) { struct dbCommon *pdbc = precord; + static short fwdLinkValue = 1; if(pdbc->flnk.type==DB_LINK ) { - struct dbAddr *paddr = pdbc->flnk.value.db_link.pdbAddr; + struct dbAddr *paddr = pdbc->flnk.value.pv_link.pvt; dbScanPassive(precord,paddr->precord); + } else + if((pdbc->flnk.type==CA_LINK) + && (pdbc->flnk.value.pv_link.pvlMask & pvlOptFWD)) { + dbCaPutLink(&pdbc->flnk,DBR_SHORT,&fwdLinkValue,1); } /*Handle dbPutFieldNotify record completions*/ if(pdbc->ppn) dbNotifyCompletion(pdbc); @@ -358,18 +304,14 @@ void recGblFwdLink(void *precord) pdbc->putf = FALSE; } - + void recGblGetTimeStamp(void* prec) { struct dbCommon* pr = (struct dbCommon*)prec; - long nRequest=1; - long options=0; if(pr->tsel.type!=CONSTANT) { - recGblGetLinkValue(&(pr->tsel),(void*)pr, - DBR_SHORT,&(pr->tse),&options,&nRequest); - + dbGetLink(&(pr->tsel), DBR_SHORT,&(pr->tse),0,0); TSgetTimeStamp((int)pr->tse,(struct timespec*)&pr->time); } else @@ -420,131 +362,3 @@ static void getMaxRangeValues(field_type,pupper_limit,plower_limit) } return; } - -/* Fast link initialization routines */ - -/* - * String if bad database request type chosen - */ -static char *bad_in_req_type = "recGblInitFastInLink: Bad database request type"; -static char *bad_out_req_type = "recGblInitFastInLink: Bad database request type"; - -/* - * Initialize fast input links. - */ -long recGblInitFastInLink( - struct link *plink, - void *precord, - short dbrType, - char *fld_name) -{ - long status = 0; - struct db_link *pdb_link = &(plink->value.db_link); - struct dbAddr *pdb_addr = (struct dbAddr *) (pdb_link->pdbAddr); - long (*cvt_func)(); - - /* - * Check for CA_LINK - */ - if (plink->type == PV_LINK) { - status = dbCaAddInlink(plink, (struct dbCommon *) precord, fld_name); - return(status); - } - - /* - * Return if not database link (A constant link, for example) - */ - if (plink->type != DB_LINK) - return(0); - - /* - * Check for legal conversion range... - */ - if ((pdb_addr->field_type < DBF_STRING) || - (pdb_addr->field_type > DBF_DEVICE) || - ( dbrType < DBR_STRING) || - ( dbrType > DBR_ENUM)) { - - pdb_link->conversion = cvt_dummy; - recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_in_req_type); - return(S_db_badDbrtype); - } - - /* - * Lookup conversion function - */ - cvt_func = dbFastGetConvertRoutine[pdb_addr->field_type][dbrType]; - - if (cvt_func == NULL) { - pdb_link->conversion = cvt_dummy; - recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_in_req_type); - return(S_db_badDbrtype); - } - - /* - * Put function it into conversion field (Run Time Link) - */ - pdb_link->conversion = cvt_func; - - return(0); -} - -/* - * Initialize fast output links. - */ -long recGblInitFastOutLink( - struct link *plink, - void *precord, - short dbrType, - char *fld_name) -{ - long status = 0; - struct db_link *pdb_link = &(plink->value.db_link); - struct dbAddr *pdb_addr = (struct dbAddr *) (pdb_link->pdbAddr); - long (*cvt_func)(); - - /* - * Check for CA_LINK - */ - if (plink->type == PV_LINK) { - status = dbCaAddOutlink(plink, (struct dbCommon *) precord, fld_name); - return(status); - } - - /* - * Return if not database link (A constant link, for example) - */ - if (plink->type != DB_LINK) - return(0); - - /* - * Check for legal conversion range... - */ - if ((pdb_addr->field_type < DBF_STRING) || - (pdb_addr->field_type > DBF_DEVICE) || - ( dbrType < DBR_STRING) || - ( dbrType > DBR_ENUM)) { - - pdb_link->conversion = cvt_dummy; - recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_out_req_type); - return(S_db_badDbrtype); - } - /* - * Lookup conversion function - */ - cvt_func = dbFastPutConvertRoutine[dbrType][pdb_addr->field_type]; - - if (cvt_func == NULL) { - pdb_link->conversion = cvt_dummy; - recGblDbaddrError(S_db_badDbrtype, pdb_addr, bad_out_req_type); - return(S_db_badDbrtype); - } - - /* - * Put function it into conversion field (Run Time Link) - */ - pdb_link->conversion = cvt_func; - - return(0); -} - diff --git a/src/db/recGbl.h b/src/db/recGbl.h index c7a7cfbe5..fe7eefce0 100644 --- a/src/db/recGbl.h +++ b/src/db/recGbl.h @@ -50,7 +50,7 @@ #include #endif #include - + /************************************************************************* * The following must match definitions in global menu definitions *************************************************************************/ @@ -62,22 +62,6 @@ /*************************************************************************/ -#define recGblGetFastLink(PLNK,PREC,PVAL) \ -\ - ((((PLNK)->type == CONSTANT) ||\ - (! (((PLNK)->type == DB_LINK) || ((PLNK)->type == CA_LINK)) ))\ - ? 0\ - : dbFastLinkGet((PLNK),(struct dbCommon *)(PREC),(PVAL))) - - -#define recGblPutFastLink(PLNK,PREC,PVAL) \ -\ - ((((PLNK)->type == CONSTANT) ||\ - (! (((PLNK)->type == DB_LINK) || ((PLNK)->type == CA_LINK)) ))\ - ? 0\ - : dbFastLinkPut((PLNK),(struct dbCommon *)(PREC),(PVAL))) - - #define recGblSetSevr(PREC,NSTA,NSEV) \ (\ ((PREC)->nsev<(NSEV))\ @@ -85,7 +69,7 @@ : FALSE\ ) - + /* Global Record Support Routines*/ void recGblDbaddrError(long status, struct dbAddr *paddr, char *pcaller_name); void recGblRecordError(long status, void *precord, char *pcaller_name); @@ -95,13 +79,7 @@ void recGblGetControlDouble(struct dbAddr *paddr, struct dbr_ctrlDouble *pcd); void recGblGetAlarmDouble(struct dbAddr *paddr, struct dbr_alDouble *pad); void recGblGetPrec(struct dbAddr *paddr, long *pprecision); int recGblInitConstantLink(struct link *plink,short dbftype,void *pdest); -long recGblGetLinkValue(struct link *plink,void *precord, - short dbrType,void *pdest,long *poptions,long *pnRequest); -long recGblPutLinkValue(struct link *plink,void *precord, - short dbrType,void *pdest,long *pnRequest); unsigned short recGblResetAlarms(void *precord); void recGblFwdLink(void *precord); void recGblGetTimeStamp(void *precord); -long recGblInitFastInLink(struct link *plink, void *precord, short dbrType, char *fld_name); -long recGblInitFastOutLink(struct link *plink, void *precord, short dbrType, char *fld_name); #endif /*INCrecGblh*/ diff --git a/src/db/task_params.h b/src/db/task_params.h index 89f876e75..7bdc43324 100644 --- a/src/db/task_params.h +++ b/src/db/task_params.h @@ -51,8 +51,14 @@ * to 60 sec * .17 03-18-94 mcn added entries for breakpoint tasks * $Log$ + * Revision 1.1 1996/01/25 21:13:29 mrk + * moved includes; .ascii=> .db; path changes + * * Revision 1.27 1995/11/29 19:27:59 jhill * added $Log$ + * added Revision 1.1 1996/01/25 21:13:29 mrk + * added moved includes; .ascii=> .db; path changes + * added * */ @@ -65,14 +71,12 @@ /* Task Names */ #define IOEVENTSCAN_NAME "scanIo" #define EVENTSCAN_NAME "scanEvent" -#define CALLBACK_NAME "callback" #define SCANONCE_NAME "scanOnce" #define SMCMD_NAME "smCommand" #define SMRESP_NAME "smResponse" #define ABDONE_NAME "abDone" #define ABSCAN_NAME "abScan" #define ABCOS_NAME "abBiCosScanner" -#define PERIODSCAN_NAME "scanPeriod" #define MOMENTARY_NAME "momentary" #define WFDONE_NAME "wfDone" #define SEQUENCER_NAME "sequencer" @@ -95,9 +99,6 @@ #define BBTXLINK_NAME "bbTx" #define BBRXLINK_NAME "bbRx" #define BBWDTASK_NAME "bbwd" -#define DB_CA_INPUT_NAME "dbCaInput" -#define DB_CA_OUTPUT_NAME "dbCaOutput" -#define DB_CA_PROC_ASYNCH_EV_TASK_NAME "process_asynch_events_task" #define EPICSPRINT_NAME "epicsPrint" #define LOG_RESTART_NAME "logRestart" @@ -126,9 +127,7 @@ #define PERIODSCAN_PRI 59 /* Periodic Scanners - Slowest rate */ #define SEQUENCER_PRI 70 #define XY240_PRI 111 /* xy 240 dio scanner */ -#define DB_CA_INPUT_PRI 100 -#define DB_CA_OUTPUT_PRI 100 -#define DB_CA_PROC_ASYNCH_EV_TASK_PRI 100 +#define DB_CA_PRI 100 #define SCANNER_PRI 150 #define REQ_SRVR_PRI 181 /* Channel Access TCP request server*/ #define CA_CLIENT_PRI 180 /* Channel Access clients */ @@ -182,9 +181,7 @@ #define BBTXLINK_OPT VX_FP_TASK|VX_STDIO #define BBRXLINK_OPT VX_FP_TASK|VX_STDIO #define BBWDTASK_OPT VX_FP_TASK|VX_STDIO -#define DB_CA_INPUT_OPT (VX_FP_TASK | VX_STDIO) -#define DB_CA_OUTPUT_OPT (VX_FP_TASK | VX_STDIO) -#define DB_CA_PROC_ASYNCH_EV_TASK_OPT (VX_FP_TASK | VX_STDIO) +#define DB_CA_OPT (VX_FP_TASK | VX_STDIO) #define XY_240_OPT (0) /* none */ #define LOG_RESTART_OPT (VX_FP_TASK) @@ -221,9 +218,7 @@ #define BBRXLINK_STACK 5000 #define BBTXLINK_STACK 5000 #define BBWDTASK_STACK 5000 -#define DB_CA_INPUT_STACK 20000 -#define DB_CA_OUTPUT_STACK 20000 -#define DB_CA_PROC_ASYNCH_EV_TASK_STACK 20000 +#define DB_CA_STACK 10000 #define XY_240_STACK 4096 #define LOG_RESTART_STACK 0x1000 diff --git a/src/dbStatic/dbBase.h b/src/dbStatic/dbBase.h index 35c59a312..1f6b095f4 100644 --- a/src/dbStatic/dbBase.h +++ b/src/dbStatic/dbBase.h @@ -125,7 +125,7 @@ typedef struct dbRecDes { char **papsortFldName;/* ptr to array of ptr to fld names*/ short *sortFldInd; /* addr of array of ind in papFldDes*/ dbFldDes *pvalFldDes; /*pointer dbFldDes for VAL field*/ - short indvalFlddes; /*ind in apFldDes*/ + short indvalFlddes; /*ind in papFldDes*/ dbFldDes **papFldDes; /* ptr to array of ptr to fldDes*/ /*The following are only available on run time system*/ struct rset *prset; diff --git a/src/dbStatic/dbLexRoutines.c b/src/dbStatic/dbLexRoutines.c index 4012148f1..4492f25b6 100644 --- a/src/dbStatic/dbLexRoutines.c +++ b/src/dbStatic/dbLexRoutines.c @@ -238,7 +238,7 @@ static int db_yyinput(char *buf, int max_size) pinputFileNow = (inputFile *)ellLast(&inputFileList); if(!pinputFileNow) return(0); } - if(dbDebug) fprintf(stderr,"%s",my_buffer); + if(dbStaticDebug) fprintf(stderr,"%s",my_buffer); pinputFileNow->line_num++; my_buffer_ptr = &my_buffer[0]; } diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index 864aa6093..2ab8dac87 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -18,7 +18,7 @@ of this distribution. * .02 09-10-93 mrk dbIsDefault always returns FALSE for DEVCHOICE * .03 02-23-94 mrk dbPutString to DEV_CHOICE. Ok if no INP or OUT */ - + #ifdef vxWorks #include #include @@ -50,12 +50,12 @@ of this distribution. #include #include -int dbDebug = 0; +int dbStaticDebug = 0; #define messagesize 100 #define RPCL_LEN 184 long postfix(char *pinfix, char *ppostfix,short *perror); -static char *ppstring[2]={"NPP","PP"}; +static char *ppstring[5]={"NPP","PP","CA","CP","CPP"}; static char *msstring[2]={"NMS","MS"}; static int mapDBFtoDCT[DBF_NOACCESS+1] = { @@ -78,10 +78,6 @@ struct form { static char *promptCONSTANT[] = { "Constant:"}; -static char *promptPV_LINK[] = { - " PV Name:", - " Process Passive?", - " Maximize Severity?"}; static char *promptVME_IO[] = { " card:", "signal:", @@ -129,10 +125,87 @@ static char *promptVXI_IO[] = { " Signal:", " parm:"}; -static char **promptAddr[VXI_IO+1]; -static int formlines[VXI_IO+1]; +/*Each DBF link type is separate case*/ +#define FWD_LINK VXI_IO+1 +#define IN_LINK FWD_LINK+1 +#define OUTLINK IN_LINK+1 +static char *promptFWD_LINK[] = { + " PV Name:"}; +static char *promptIN_LINK[] = { + " PV Name:", + "NPP PP CA CP CPP:" + " NMS or MS:"}; +static char *promptOUT_LINK[] = { + " PV Name:", + "NPP PP CA:" + "NMS or MS:"}; +static char **promptAddr[OUTLINK+1]; +static int formlines[OUTLINK+1]; /* internal routines*/ +/*checkDevChoice initializes INP or OUT field*/ +static char *pNullString = ""; +static long checkDevChoice(DBENTRY *pdbentry, long link_type) +{ + dbFldDes *savepflddes = pdbentry->pflddes; + void *savepfield = pdbentry->pfield; + short saveindfield = pdbentry->indfield; + dbFldDes *pflddes; + DBLINK *plink; + long status=0; + + status = dbFindField(pdbentry,"INP"); + if(status) status = dbFindField(pdbentry,"OUT"); + if(!status) { + pflddes = pdbentry->pflddes; + plink = (DBLINK *)(pdbentry->pfield); + if(plink->type == link_type) goto clean_up; + if(link_type==CONSTANT && plink->type==PV_LINK)goto clean_up; + if(link_type!=CONSTANT && plink->type==PV_LINK) { + status = S_dbLib_badField; + goto clean_up; + } + plink->type = link_type; + if(plink->type==CONSTANT) free((void *)plink->value.constantStr); + memset((char *)plink,0,sizeof(struct link)); + switch(plink->type) { + case VME_IO: plink->value.vmeio.parm = pNullString; break; + case CAMAC_IO: plink->value.camacio.parm = pNullString; break; + case AB_IO: plink->value.abio.parm = pNullString; break; + case GPIB_IO: plink->value.gpibio.parm = pNullString; break; + case BITBUS_IO: plink->value.bitbusio.parm = pNullString; break; + case INST_IO: plink->value.instio.string = pNullString; break; + case BBGPIB_IO: plink->value.bbgpibio.parm = pNullString; break; + case VXI_IO: plink->value.vxiio.parm = pNullString; break; + } + } else { + if(link_type==CONSTANT) status = 0; + else status = S_dbLib_badField; + } +clean_up: + pdbentry->pflddes = savepflddes; + pdbentry->pfield = savepfield; + pdbentry->indfield = saveindfield; + return(status); +} + +static long putParmString(char **pparm,char *pstring) +{ + size_t size; + + size = strlen(pstring) + 1; + if(size>=MAX_STRING_SIZE) return(S_dbLib_badLink); + if(*pparm && (*pparm != pNullString)) free((void *)(*pparm)); + *pparm = dbCalloc(size, sizeof(char *)); + strcpy(*pparm,pstring); + return(0); +} + +void dbFreeParmString(char **pparm) +{ + if(*pparm && (*pparm != pNullString)) free((void *)(*pparm)); +} + static void dbFreePath(DBBASE *pdbbase) { ELLLIST *ppathList; dbPathNode *pdbPathNode; @@ -157,12 +230,11 @@ static void initForms(void) if(!firstTime) return; firstTime = FALSE; - for(i=0; i<=VXI_IO; i++) { + for(i=0; i<=OUTLINK; i++) { promptAddr[i] = NULL; formlines[i] = 0; } promptAddr[CONSTANT] = promptCONSTANT; formlines[CONSTANT] = 1; - promptAddr[PV_LINK] = promptPV_LINK; formlines[PV_LINK] = 4; promptAddr[VME_IO] = promptVME_IO; formlines[VME_IO] = 3; promptAddr[CAMAC_IO] = promptCAMAC_IO; formlines[CAMAC_IO] = 6; promptAddr[RF_IO] = promptRF_IO; formlines[RF_IO] = 4; @@ -172,6 +244,9 @@ static void initForms(void) promptAddr[INST_IO] = promptINST_IO; formlines[INST_IO] = 1; promptAddr[BBGPIB_IO]= promptBBGPIB_IO;formlines[BBGPIB_IO]= 4; promptAddr[VXI_IO] = promptVXI_IO; formlines[VXI_IO] = 6; + promptAddr[FWD_LINK] = promptFWD_LINK; formlines[FWD_LINK] = 1; + promptAddr[IN_LINK] = promptIN_LINK; formlines[IN_LINK] = 3; + promptAddr[OUTLINK] = promptOUT_LINK; formlines[OUTLINK] = 3; } static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess) @@ -219,6 +294,36 @@ static char *getpMessage(DBENTRY *pdbentry) return(pdbentry->message); } +static long putPvLink(DBENTRY *pdbentry,short pvlMask,char *pvname) +{ + dbFldDes *pflddes; + DBLINK *plink; + char *pname; + + dbGetFieldAddress(pdbentry); + pflddes = pdbentry->pflddes; + if(!pflddes) return(-1); + plink = (DBLINK *)pdbentry->pfield; + if(!plink) return(-1); + switch (pflddes->field_type) { + case DBF_INLINK: + case DBF_OUTLINK: + case DBF_FWDLINK: + if(plink->type != PV_LINK) return(S_dbLib_badLink); + pname = plink->value.pv_link.pvname; + if(pname) free((void *)pname); + pname = dbCalloc(strlen(pvname)+1,sizeof(char)); + plink->value.pv_link.pvname = pname; + strcpy(pname,pvname); + plink->value.pv_link.pvlMask = pvlMask; + return(0); + default: + errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); + } + return(S_dbLib_badLink); +} + +/*Public only for dbStaticRun*/ void dbInitDeviceMenu(DBENTRY *pdbentry) { dbRecDes *precdes = pdbentry->precdes; @@ -273,7 +378,7 @@ void *dbMalloc(size_t size) #endif return(NULL); } - + dbBase *dbAllocBase(void) { dbBase *pdbbase; @@ -288,7 +393,7 @@ dbBase *dbAllocBase(void) initForms(); return (pdbbase); } - + void dbFreeBase(dbBase *pdbbase) { dbMenu *pdbMenu; @@ -657,7 +762,9 @@ long dbWriteRecDesFP(DBBASE *pdbbase,FILE *fp,char *recdesName) } } if(pdbFldDes->special) { - for(j=0; jspecial >= SPC_NTYPES) { + fprintf(fp,"\t\tspecial(%d)\n",pdbFldDes->special); + } else for(j=0; jspecial) { fprintf(fp,"\t\tspecial(%s)\n", pamapspcType[j].strvalue); @@ -854,14 +961,20 @@ int dbGetNRecdes(DBENTRY *pdbentry) long dbCreateRecord(DBENTRY *pdbentry,char *precordName) { dbRecDes *precdes = pdbentry->precdes; + dbFldDes *pdbFldDes; PVDENTRY *ppvd; ELLLIST *preclist = NULL; dbRecordNode *precnode = NULL; dbRecordNode *pNewRecNode = NULL; long status; + devSup *pdevSup; - if((int)strlen(precordName)>PVNAME_SZ) return(S_dbLib_nameLength); if(!precdes) return(S_dbLib_recdesNotFound); + /*Get size of NAME field*/ + pdbFldDes = precdes->papFldDes[0]; + if(!pdbFldDes || (strcmp(pdbFldDes->name,"NAME")!=0)) + return(S_dbLib_nameLength); + if((int)strlen(precordName)>=pdbFldDes->size) return(S_dbLib_nameLength); /* clear callers entry */ zeroDbentry(pdbentry); if(!dbFindRecord(pdbentry,precordName)) return (S_dbLib_recExists); @@ -885,7 +998,11 @@ long dbCreateRecord(DBENTRY *pdbentry,char *precordName) pdbentry->precnode = pNewRecNode; ppvd = dbPvdAdd(pdbentry->pdbbase,precdes,pNewRecNode); if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);} - return (0); + /*If any device support exists let checkDevChoice give default for INP/OUT*/ + pdevSup = (devSup *)ellFirst(&precdes->devList); + if(!pdevSup) return(0); + status = checkDevChoice(pdbentry,pdevSup->link_type); + return (status); } long dbDeleteRecord(DBENTRY *pdbentry) @@ -981,6 +1098,7 @@ long dbRenameRecord(DBENTRY *pdbentry,char *newName) { dbBase *pdbbase = pdbentry->pdbbase; dbRecDes *precdes = pdbentry->precdes; + dbFldDes *pdbFldDes; dbRecordNode *precnode = pdbentry->precnode; PVDENTRY *ppvd; ELLLIST *preclist; @@ -988,7 +1106,12 @@ long dbRenameRecord(DBENTRY *pdbentry,char *newName) long status; DBENTRY dbentry; - if((int)strlen(newName)>PVNAME_SZ) return(S_dbLib_nameLength); + if(!precdes) return(S_dbLib_recdesNotFound); + /*Get size of NAME field*/ + pdbFldDes = precdes->papFldDes[0]; + if(!pdbFldDes || (strcmp(pdbFldDes->name,"NAME")!=0)) + return(S_dbLib_nameLength); + if((int)strlen(newName)>=pdbFldDes->size) return(S_dbLib_nameLength); if(!precnode) return(S_dbLib_recNotFound); dbInitEntry(pdbentry->pdbbase,&dbentry); status = dbFindRecord(&dbentry,newName); @@ -1229,17 +1352,23 @@ char *dbGetString(DBENTRY *pdbentry) } break; case PV_LINK: - if(plink->value.pv_link.process_passive<0 - ||plink->value.pv_link.process_passive>1) - plink->value.pv_link.process_passive=0; - if(plink->value.pv_link.maximize_sevr<0 - ||plink->value.pv_link.maximize_sevr>1) - plink->value.pv_link.maximize_sevr=0; + case CA_LINK: + case DB_LINK: { + int ppind; + short pvlMask; + + pvlMask = plink->value.pv_link.pvlMask; + if(pvlMask&pvlOptPP) ppind=1; + else if(pvlMask&pvlOptCA) ppind=2; + else if(pvlMask&pvlOptCP) ppind=3; + else if(pvlMask&pvlOptCPP) ppind=4; + else ppind=0; sprintf(message,"%s %s %s", plink->value.pv_link.pvname, - ppstring[plink->value.pv_link.process_passive], - msstring[plink->value.pv_link.maximize_sevr]); + ppstring[ppind], + msstring[pvlMask&pvlOptMS]); break; + } case VME_IO: sprintf(message,"#C%d S%d @%s", plink->value.vmeio.card,plink->value.vmeio.signal, @@ -1307,6 +1436,8 @@ char *dbGetString(DBENTRY *pdbentry) strcpy(message,"0"); break; case PV_LINK: + case CA_LINK: + case DB_LINK: sprintf(message,"%s", plink->value.pv_link.pvname); break; @@ -1321,41 +1452,6 @@ char *dbGetString(DBENTRY *pdbentry) return (message); } -/* utility routines used by dbPutString */ -static long checkDevChoice(DBENTRY *pdbentry, long link_type) -{ - dbFldDes *savepflddes = pdbentry->pflddes; - void *savepfield = pdbentry->pfield; - short saveindfield = pdbentry->indfield; - dbFldDes *pflddes; - DBLINK *plink; - long status=0; - - status = dbFindField(pdbentry,"INP"); - if(status) status = dbFindField(pdbentry,"OUT"); - if(!status) { - pflddes = pdbentry->pflddes; - plink = (DBLINK *)(pdbentry->pfield); - if(plink->type == link_type) goto clean_up; - if(link_type==CONSTANT && plink->type==PV_LINK)goto clean_up; - if(link_type!=CONSTANT && plink->type==PV_LINK) { - status = S_dbLib_badField; - goto clean_up; - } - if(plink->type==CONSTANT) free((void *)plink->value.constantStr); - memset((char *)plink,0,sizeof(struct link)); - plink->type = link_type; - } else { - if(link_type==CONSTANT) status = 0; - else status = S_dbLib_badField; - } -clean_up: - pdbentry->pflddes = savepflddes; - pdbentry->pfield = savepfield; - pdbentry->indfield = saveindfield; - return(status); -} - long dbPutString(DBENTRY *pdbentry,char *pstring) { dbFldDes *pflddes = pdbentry->pflddes; @@ -1457,8 +1553,8 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) switch(plink->type) { case CONSTANT: case PV_LINK: { - int pp=0; - int ms=0; + short ppOpt = 0; + short msOpt = 0; char *end; double tempval; @@ -1481,13 +1577,18 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) if(plink->type==CONSTANT) dbCvtLinkToPvlink(pdbentry); end = strchr(pstr,' '); if(end) { - if(strstr(end," PP")) pp = TRUE; - if(strstr(end,".PP")) pp = TRUE; - if(strstr(end," MS")) ms = TRUE; - if(strstr(end,".MS")) ms = TRUE; + if(strstr(end,"NPP")) ppOpt = 0; + else if(strstr(end,"PP")) ppOpt = pvlOptPP; + else if(strstr(end,"CA")) ppOpt = pvlOptCA; + else if(strstr(end,"CP")) ppOpt = pvlOptCP; + else if(strstr(end,"CPP")) ppOpt = pvlOptCPP; + else ppOpt = 0; + if(strstr(end,"NMS")) msOpt = 0; + else if(strstr(end,"MS")) msOpt = pvlOptMS; + else msOpt = 0; *end = 0; } - status = dbPutPvlink(pdbentry,pp,ms,pstr); + status = putPvLink(pdbentry,ppOpt|msOpt,pstr); return(0); } case VME_IO: { @@ -1501,11 +1602,7 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) if(!(end = strchr(pstr,'S'))) return (S_dbLib_badField); pstr = end + 1; sscanf(pstr,"%hd",&plink->value.vmeio.signal); - plink->value.vmeio.parm[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.vmeio.parm[0],pstr); - } + status = putParmString(&plink->value.vmeio.parm,pstr); } break; case CAMAC_IO: { @@ -1534,11 +1631,7 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) pstr = end + 1; sscanf(pstr,"%hd",&plink->value.camacio.f); } - plink->value.camacio.parm[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.camacio.parm[0],pstr); - } + status = putParmString(&plink->value.camacio.parm,pstr); } break; case RF_IO: { @@ -1577,11 +1670,7 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) if(!(end = strchr(pstr,'S'))) return (S_dbLib_badField); pstr = end + 1; sscanf(pstr,"%hd",&plink->value.abio.signal); - plink->value.abio.parm[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.abio.parm[0],pstr); - } + status = putParmString(&plink->value.abio.parm,pstr); } break; case GPIB_IO: { @@ -1595,11 +1684,7 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) if(!(end = strchr(pstr,'A'))) return (S_dbLib_badField); pstr = end + 1; sscanf(pstr,"%hd",&plink->value.gpibio.addr); - plink->value.gpibio.parm[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.gpibio.parm[0],pstr); - } + status = putParmString(&plink->value.gpibio.parm,pstr); } break; case BITBUS_IO: { @@ -1627,11 +1712,7 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) pstr = end + 1; sscanf(pstr,"%hd",&tmp_val); plink->value.bitbusio.signal=(unsigned char)tmp_val; - plink->value.bitbusio.parm[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.bitbusio.parm[0],pstr); - } + status = putParmString(&plink->value.bitbusio.parm,pstr); } break; case BBGPIB_IO: { @@ -1655,11 +1736,7 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) pstr = end + 1; sscanf(pstr,"%hd",&tmp_val); plink->value.bbgpibio.gpibaddr=tmp_val; - plink->value.bbgpibio.parm[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.bbgpibio.parm[0],pstr); - } + status = putParmString(&plink->value.bbgpibio.parm,pstr); } break; case VXI_IO: { @@ -1688,21 +1765,11 @@ long dbPutString(DBENTRY *pdbentry,char *pstring) } else { plink->value.vxiio.signal = 0; } - plink->value.vxiio.parm[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.vxiio.parm[0],pstr); - } + status = putParmString(&plink->value.vxiio.parm,pstr); } break; case INST_IO: { - char *end; - - plink->value.instio.string[0] = 0; - if(end = strchr(pstr,'@')) { - pstr = end + 1; - strcpy(&plink->value.instio.string[0],pstr); - } + status = putParmString(&plink->value.instio.string,pstr); } break; } @@ -1892,7 +1959,7 @@ char *dbGetRange(DBENTRY *pdbentry) strcpy(message,"Not a valid field type"); return (message); } - + brkTable *dbFindBrkTable(dbBase *pdbbase,char *name) { GPHENTRY *pgph; @@ -2076,6 +2143,7 @@ char **dbGetFormPrompt(DBENTRY *pdbentry) char **dbGetFormValue(DBENTRY *pdbentry) { struct form *pform = pdbentry->formpvt; + dbFldDes *pflddes = pdbentry->pflddes; DBLINK *plink; char **value; @@ -2091,12 +2159,27 @@ char **dbGetFormValue(DBENTRY *pdbentry) *value = 0; } break; - case PV_LINK: + case PV_LINK: { + short pvlMask = plink->value.pv_link.pvlMask; + strcpy(*value,plink->value.pv_link.pvname); value++; - strcpy(*value, (plink->value.pv_link.process_passive ? "Yes" : "No")); - value++; - strcpy(*value, (plink->value.pv_link.maximize_sevr ? "Yes" : "No")); + switch(pflddes->field_type) { + case DBF_INLINK: + case DBF_OUTLINK: + if(pvlMask&pvlOptPP) strcpy(*value,"PP"); + else if(pvlMask&pvlOptCA) strcpy(*value,"CA"); + else if(pvlMask&pvlOptCP) strcpy(*value,"CP"); + else if(pvlMask&pvlOptCPP) strcpy(*value,"CPP"); + else strcpy(*value,"NPP"); + value++; + if(pvlMask&pvlOptMS) strcpy(*value,"MS"); + else strcpy(*value,"NMS"); + value++; + default: + break; + } + } break; case VME_IO: cvtShortToString(plink->value.vmeio.card,*value); @@ -2204,6 +2287,7 @@ long dbPutForm(DBENTRY *pdbentry,char **value) long lvalue; double dvalue; char *endp; + long status = 0; if(!pform) return(S_dbLib_badLink); plink = pform->plink; @@ -2226,17 +2310,28 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(plink->value.constantStr,*value); break; case PV_LINK: { - int pp=0; - int ms=0; + short ppOpt = 0; + short msOpt = 0; char *pstr; pstr = *value; **verify = 0; value++; verify++; - pp = ((strchr(*value,'Y') || strchr(*value,'y') ? TRUE : FALSE)); + **verify = 0; /*Initialize verify to NULL*/ + if(!(*value)) ppOpt = 0; + else if(strstr(*value,"NPP")) ppOpt = 0; + else if(strstr(*value,"PP")) ppOpt = pvlOptPP; + else if(strstr(*value,"CA")) ppOpt = pvlOptCA; + else if(strstr(*value,"CP")) ppOpt = pvlOptCP; + else if(strstr(*value,"CPP")) ppOpt = pvlOptCPP; + else strcpy(*verify,"Illegal. Chose a value"); value++; verify++; - ms = ((strchr(*value,'Y') || strchr(*value,'y') ? TRUE : FALSE)); - dbPutPvlink(pdbentry,pp,ms,pstr); + **verify = 0; /*Initialize verify to NULL*/ + if(!(*value)) msOpt = 0; + else if(strstr(*value,"NMS")) msOpt = 0; + else if(strstr(*value,"MS")) msOpt = pvlOptMS; + else strcpy(*verify,"Illegal. Chose a value"); + putPvLink(pdbentry,ppOpt|msOpt,pstr); } break; case VME_IO: @@ -2254,7 +2349,7 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(*verify,"Illegal. Must be number"); } value++; verify++; - strncpy(plink->value.vmeio.parm,*value,VME_PARAM_SZ-1); + status = putParmString(&plink->value.vmeio.parm,*value); break; case CAMAC_IO: lvalue = strtol(*value,&endp,0); @@ -2292,7 +2387,7 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(*verify,"Illegal. Must be number"); } value++; verify++; - strncpy(plink->value.camacio.parm,*value,CAMAC_PARAM_SZ-1); + status = putParmString(&plink->value.camacio.parm,*value); break; case RF_IO: lvalue = strtol(*value,&endp,0); @@ -2352,7 +2447,7 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(*verify,"Illegal. Must be number"); } value++; verify++; - strncpy(plink->value.abio.parm,*value,AB_PARAM_SZ-1); + status = putParmString(&plink->value.abio.parm,*value); break; case GPIB_IO: lvalue = strtol(*value,&endp,0); @@ -2369,7 +2464,7 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(*verify,"Illegal. Must be number"); } value++; verify++; - strncpy(plink->value.gpibio.parm,*value,LINK_PARAM_SZ-1); + status = putParmString(&plink->value.gpibio.parm,*value); **verify = 0; break; case BITBUS_IO: @@ -2401,11 +2496,11 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(*verify,"Illegal. Must be number"); } value++; verify++; - strncpy(plink->value.bitbusio.parm,*value,LINK_PARAM_SZ-1); + status = putParmString(&plink->value.bitbusio.parm,*value); **verify = 0; break; case INST_IO: - strncpy(plink->value.instio.string,*value,INSTIO_FLD_SZ-1); + status = putParmString(&plink->value.instio.string,*value); **verify = 0; break; case BBGPIB_IO: @@ -2430,7 +2525,7 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(*verify,"Illegal. Must be number"); } value++; verify++; - strncpy(plink->value.bbgpibio.parm,*value,LINK_PARAM_SZ-1); + status = putParmString(&plink->value.bbgpibio.parm,*value); **verify = 0; break; case VXI_IO: @@ -2465,13 +2560,13 @@ long dbPutForm(DBENTRY *pdbentry,char **value) strcpy(*verify,"Illegal. Must be number"); } value++; verify++; - strncpy(plink->value.vxiio.parm,*value,VXI_PARAM_SZ-1); + status = putParmString(&plink->value.vxiio.parm,*value); **verify = 0; break; default : return(S_dbLib_badLink); } - return(0); + return(status); } char **dbVerifyForm(DBENTRY *pdbentry,char **value) @@ -2517,7 +2612,7 @@ long dbGetLinkField(DBENTRY *pdbentry,int index) dbGetFieldAddress(pdbentry); return(0); } - + int dbGetLinkType(DBENTRY *pdbentry) { dbFldDes *pflddes; @@ -2567,6 +2662,7 @@ long dbCvtLinkToConstant(DBENTRY *pdbentry) if(plink->type == CONSTANT) return(0); if(plink->type != PV_LINK) return(S_dbLib_badLink); free((void *)plink->value.pv_link.pvname); + plink->value.pv_link.pvname = 0; plink->type = CONSTANT; if(pflddes->initial) { plink->value.constantStr = @@ -2588,6 +2684,7 @@ long dbCvtLinkToPvlink(DBENTRY *pdbentry) dbGetFieldAddress(pdbentry); pflddes = pdbentry->pflddes; if(!pflddes) return(-1); + if(!pdbentry->precnode || !pdbentry->precnode->precord) return(-1); plink = (DBLINK *)pdbentry->pfield; if(!plink) return(-1); switch (pflddes->field_type) { @@ -2598,9 +2695,9 @@ long dbCvtLinkToPvlink(DBENTRY *pdbentry) if(plink->type != CONSTANT) return(S_dbLib_badLink); free(plink->value.constantStr); plink->type = PV_LINK; - plink->value.pv_link.process_passive = 0; - plink->value.pv_link.maximize_sevr = 0; + plink->value.pv_link.pvlMask = 0; plink->value.pv_link.pvname = 0; + plink->value.pv_link.precord = pdbentry->precnode->precord; return(0); default: errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); @@ -2608,65 +2705,6 @@ long dbCvtLinkToPvlink(DBENTRY *pdbentry) return(S_dbLib_badLink); } -long dbPutPvlink(DBENTRY *pdbentry,int pp,int ms,char *pvname) -{ - dbFldDes *pflddes; - DBLINK *plink; - char *pname; - - dbGetFieldAddress(pdbentry); - pflddes = pdbentry->pflddes; - if(!pflddes) return(-1); - plink = (DBLINK *)pdbentry->pfield; - if(!plink) return(-1); - switch (pflddes->field_type) { - case DBF_INLINK: - case DBF_OUTLINK: - case DBF_FWDLINK: - if(plink->type != PV_LINK) return(S_dbLib_badLink); - pname = plink->value.pv_link.pvname; - if(pname) free((void **)pname); - pname = dbCalloc(strlen(pvname)+1,sizeof(char)); - plink->value.pv_link.pvname = pname; - strcpy(pname,pvname); - plink->value.pv_link.process_passive = pp; - plink->value.pv_link.maximize_sevr = ms; - return(0); - default: - errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); - } - return(S_dbLib_badLink); -} - -long dbGetPvlink(DBENTRY *pdbentry,int *pp,int *ms,char *pvname) -{ - dbFldDes *pflddes; - DBLINK *plink; - - dbGetFieldAddress(pdbentry); - pflddes = pdbentry->pflddes; - if(!pflddes) return(-1); - plink = (DBLINK *)pdbentry->pfield; - if(!plink) return(-1); - switch (pflddes->field_type) { - case DBF_INLINK: - case DBF_OUTLINK: - case DBF_FWDLINK: - if(plink->type != PV_LINK) return(S_dbLib_badLink); - if(plink->value.pv_link.pvname) { - strcpy(pvname,plink->value.pv_link.pvname); - } else { - strcpy(pvname,"0"); - } - *pp = plink->value.pv_link.process_passive; - *ms = plink->value.pv_link.maximize_sevr; - return(0); - default: - errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); - return(NULL); - } -} - void dbDumpPath(DBBASE *pdbbase) { ELLLIST *ppathList; diff --git a/src/dbStatic/dbStaticLib.h b/src/dbStatic/dbStaticLib.h index aa1e1c7c1..60c08a8ec 100644 --- a/src/dbStatic/dbStaticLib.h +++ b/src/dbStatic/dbStaticLib.h @@ -162,8 +162,6 @@ long dbGetLinkField(DBENTRY *pdbentry,int index); int dbGetLinkType(DBENTRY *pdbentry); long dbCvtLinkToConstant(DBENTRY *pdbentry); long dbCvtLinkToPvlink(DBENTRY *pdbentry); -long dbPutPvlink(DBENTRY *pdbentry,int pp,int ms,char *pvname); -long dbGetPvlink(DBENTRY *pdbentry,int *pp,int *ms,char *pvname); /*dump routines*/ void dbDumpPath(DBBASE *pdbbase); @@ -183,7 +181,7 @@ void dbReportDeviceConfig(DBBASE *pdbbase,FILE *report); void *dbCalloc(size_t nobj,size_t size); void *dbMalloc(size_t size); -extern int dbDebug; +extern int dbStaticDebug; #define S_dbLib_recdesNotFound (M_dbLib| 1) /*Record Type does not exist*/ #define S_dbLib_recExists (M_dbLib| 3) /*Record Already exists*/ diff --git a/src/dbStatic/dbStaticNoRun.c b/src/dbStatic/dbStaticNoRun.c index 5d5728f0d..20dcb18e8 100644 --- a/src/dbStatic/dbStaticNoRun.c +++ b/src/dbStatic/dbStaticNoRun.c @@ -31,31 +31,31 @@ of this distribution. long dbAllocRecord(DBENTRY *pdbentry,char *precordName) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; dbFldDes *pflddes; void **papField; int i; char *pstr; - if(!precdes) return(S_dbLib_recdesNotFound); + if(!pdbRecDes) return(S_dbLib_recdesNotFound); if(!precnode) return(S_dbLib_recNotFound); - precnode->precord = dbCalloc(precdes->no_fields,sizeof(void *)); + precnode->precord = dbCalloc(pdbRecDes->no_fields,sizeof(void *)); papField = (void **)precnode->precord; - for(i=0; ino_fields; i++) { - pflddes = precdes->papFldDes[i]; + for(i=0; ino_fields; i++) { + pflddes = pdbRecDes->papFldDes[i]; if(!pflddes) continue; switch(pflddes->field_type) { case DBF_STRING: if(pflddes->size <= 0) { - fprintf(stderr,"size=0 for %s.%s\n",precdes->name,pflddes->name); + fprintf(stderr,"size=0 for %s.%s\n",pdbRecDes->name,pflddes->name); pflddes->size = 1; } papField[i] = dbCalloc(pflddes->size,sizeof(char)); if(pflddes->initial) { - if(strlen(pflddes->initial) >= pflddes->size) { + if(strlen(pflddes->initial) >= (unsigned)(pflddes->size)) { fprintf(stderr,"initial size > size for %s.%s\n", - precdes->name,pflddes->name); + pdbRecDes->name,pflddes->name); } else { strcpy((char *)papField[i],pflddes->initial); } @@ -107,44 +107,52 @@ long dbAllocRecord(DBENTRY *pdbentry,char *precordName) long dbFreeRecord(DBENTRY *pdbentry) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; dbFldDes *pflddes = pdbentry->pflddes; void **pap; int i,field_type; - if(!precdes) return(S_dbLib_recdesNotFound); + if(!pdbRecDes) return(S_dbLib_recdesNotFound); if(!precnode) return(S_dbLib_recNotFound); if(!precnode->precord) return(S_dbLib_recNotFound); pap = (void **)precnode->precord; precnode->precord = NULL; - for(i=0; ino_fields; i++) { - pflddes = precdes->papFldDes[i]; + for(i=0; ino_fields; i++) { + pflddes = pdbRecDes->papFldDes[i]; field_type = pflddes->field_type; if(field_type==DBF_INLINK || field_type==DBF_OUTLINK || field_type==DBF_FWDLINK) { struct link *plink = (struct link *)pap[i]; - if(plink->type== CONSTANT) - free((void *)plink->value.constantStr); - if(plink->type==PV_LINK) - free((void *)plink->value.pv_link.pvname); + switch(plink->type) { + case CONSTANT: free((void *)plink->value.constantStr); break; + case PV_LINK: free((void *)plink->value.pv_link.pvname); break; + case VME_IO: dbFreeParmString(&plink->value.vmeio.parm); break; + case CAMAC_IO: dbFreeParmString(&plink->value.camacio.parm); break; + case AB_IO: dbFreeParmString(&plink->value.abio.parm); break; + case GPIB_IO: dbFreeParmString(&plink->value.gpibio.parm); break; + case BITBUS_IO: dbFreeParmString(&plink->value.bitbusio.parm);break; + case INST_IO: dbFreeParmString(&plink->value.instio.string); break; + case BBGPIB_IO: dbFreeParmString(&plink->value.bbgpibio.parm);break; + case VXI_IO: dbFreeParmString(&plink->value.vxiio.parm); break; + } } free(pap[i]); } free((void *)pap); return(0); } - + long dbGetFieldAddress(DBENTRY *pdbentry) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; dbFldDes *pflddes = pdbentry->pflddes; void **pap; - if(!precdes) return(S_dbLib_recdesNotFound); + if(!pdbRecDes) return(S_dbLib_recdesNotFound); if(!precnode) return(S_dbLib_recNotFound); if(!pflddes) return(S_dbLib_flddesNotFound); if(!precnode->precord) return(0); @@ -155,11 +163,11 @@ long dbGetFieldAddress(DBENTRY *pdbentry) char *dbRecordName(DBENTRY *pdbentry) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; void **pap; - if(!precdes) return(0); + if(!pdbRecDes) return(0); if(!precnode) return(0); if(!precnode->precord) return(0); pap = (void **)precnode->precord; @@ -190,8 +198,7 @@ int dbIsDefaultValue(DBENTRY *pdbentry) if(!pfield) return(TRUE); if(!pflddes->initial) return(FALSE); return(strcmp((char *)pfield,(char *)pflddes->initial)==0); - case DBF_MENU: - case DBF_DEVICE: { + case DBF_MENU: { unsigned short val,ival; if(!pfield) return(FALSE); @@ -200,6 +207,18 @@ int dbIsDefaultValue(DBENTRY *pdbentry) sscanf(pflddes->initial,"%hu",&ival); return((val==ival)?TRUE:FALSE); } + case DBF_DEVICE: { + dbRecDes *pdbRecDes = pdbentry->precdes; + devSup *pdevSup; + + if(!pdbRecDes) { + epicsPrintf("dbIsDefaultValue: pdbRecDes is NULL??\n"); + return(FALSE); + } + pdevSup = (devSup *)ellFirst(&pdbRecDes->devList); + if(!pdevSup) return(TRUE); + return(FALSE); + } case DBF_INLINK: case DBF_OUTLINK: case DBF_FWDLINK: { @@ -243,7 +262,7 @@ long dbPutStringNum(DBENTRY *pdbentry,char *pstring) if(!precnode->precord) return(S_dbLib_recNotFound); if(!pflddes) return(S_dbLib_flddesNotFound); if(pfield) { - if(strlen(pfield) < strlen(pstring)) { + if((unsigned)strlen(pfield) < (unsigned)strlen(pstring)) { free((void *)pfield); pfield = NULL; } diff --git a/src/dbStatic/dbStaticPvt.h b/src/dbStatic/dbStaticPvt.h index 9d00368e7..5f5b397b4 100644 --- a/src/dbStatic/dbStaticPvt.h +++ b/src/dbStatic/dbStaticPvt.h @@ -34,6 +34,7 @@ /*Following are not intended for client code */ void dbInitDeviceMenu(DBENTRY *pdbentry); +void dbFreeParmString(char **pparm); /*The following routines have different versions for run-time no-run-time*/ long dbAllocRecord(DBENTRY *pdbentry,char *precordName); @@ -61,7 +62,7 @@ typedef struct{ dbRecordNode *precnode; }PVDENTRY; int dbPvdTableSize(int size); -extern int dbDebug; +extern int dbStaticDebug; void dbPvdInitPvt(DBBASE *pdbbase); PVDENTRY *dbPvdFind(DBBASE *pdbbase,char *name,int lenname); PVDENTRY *dbPvdAdd(DBBASE *pdbbase,dbRecDes *precdes,dbRecordNode *precnode); diff --git a/src/dbStatic/dbStaticRun.c b/src/dbStatic/dbStaticRun.c index b2e9d4cd4..9ad6d2944 100644 --- a/src/dbStatic/dbStaticRun.c +++ b/src/dbStatic/dbStaticRun.c @@ -152,23 +152,23 @@ static void doubleToString(double value,char *preturn) long dbAllocRecord(DBENTRY *pdbentry,char *precordName) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; dbFldDes *pflddes; int i; char *precord; char *pfield; - if(!precdes) return(S_dbLib_recdesNotFound); + if(!pdbRecDes) return(S_dbLib_recdesNotFound); if(!precnode) return(S_dbLib_recNotFound); - precnode->precord = dbCalloc(1,precdes->rec_size); + precnode->precord = dbCalloc(1,pdbRecDes->rec_size); precord = (char *)precnode->precord; - if(precdes->rec_size == 0) { + if(pdbRecDes->rec_size == 0) { epicsPrintf("dbAllocRecord(%s) record_size =0\n", - precdes->name); + pdbRecDes->name); return(S_dbLib_noRecSup); } - pflddes = precdes->papFldDes[0]; + pflddes = pdbRecDes->papFldDes[0]; if(!pflddes) { epicsPrintf("dbAllocRecord pflddes for NAME not found\n"); return(S_dbLib_flddesNotFound); @@ -179,9 +179,9 @@ long dbAllocRecord(DBENTRY *pdbentry,char *precordName) } pfield = precord + pflddes->offset; strcpy(pfield,precordName); - for(i=1; ino_fields; i++) { + for(i=1; ino_fields; i++) { - pflddes = precdes->papFldDes[i]; + pflddes = pdbRecDes->papFldDes[i]; if(!pflddes) continue; pfield = precord + pflddes->offset; pdbentry->pfield = (void *)pfield; @@ -192,7 +192,7 @@ long dbAllocRecord(DBENTRY *pdbentry,char *precordName) if(pflddes->initial) { if(strlen(pflddes->initial) >= pflddes->size) { epicsPrintf("initial size > size for %s.%s\n", - precdes->name,pflddes->name); + pdbRecDes->name,pflddes->name); } else { strcpy(pfield,pflddes->initial); } @@ -207,8 +207,6 @@ long dbAllocRecord(DBENTRY *pdbentry,char *precordName) case DBF_FLOAT: case DBF_DOUBLE: case DBF_ENUM: - case DBF_DEVICE: - if(!pflddes->ftPvt) dbInitDeviceMenu(pdbentry); case DBF_MENU: if(pflddes->initial) { long status; @@ -216,9 +214,12 @@ long dbAllocRecord(DBENTRY *pdbentry,char *precordName) status = dbPutStringNum(pdbentry,pflddes->initial); if(status) epicsPrintf("Error initializing %s.%s initial %s\n", - precdes->name,pflddes->name,pflddes->initial); + pdbRecDes->name,pflddes->name,pflddes->initial); } break; + case DBF_DEVICE: + if(!pflddes->ftPvt) dbInitDeviceMenu(pdbentry); + break; case DBF_INLINK: case DBF_OUTLINK: case DBF_FWDLINK: { @@ -242,10 +243,10 @@ long dbAllocRecord(DBENTRY *pdbentry,char *precordName) long dbFreeRecord(DBENTRY *pdbentry) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; - if(!precdes) return(S_dbLib_recdesNotFound); + if(!pdbRecDes) return(S_dbLib_recdesNotFound); if(!precnode) return(S_dbLib_recNotFound); if(!precnode->precord) return(S_dbLib_recNotFound); free(precnode->precord); @@ -255,11 +256,11 @@ long dbFreeRecord(DBENTRY *pdbentry) long dbGetFieldAddress(DBENTRY *pdbentry) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; dbFldDes *pflddes = pdbentry->pflddes; - if(!precdes) return(S_dbLib_recdesNotFound); + if(!pdbRecDes) return(S_dbLib_recdesNotFound); if(!precnode) return(S_dbLib_recNotFound); if(!pflddes) return(S_dbLib_flddesNotFound); if(!precnode->precord) return(0); @@ -269,16 +270,16 @@ long dbGetFieldAddress(DBENTRY *pdbentry) char *dbRecordName(DBENTRY *pdbentry) { - dbRecDes *precdes = pdbentry->precdes; + dbRecDes *pdbRecDes = pdbentry->precdes; dbRecordNode *precnode = pdbentry->precnode; dbFldDes *pflddes; char *precord; - if(!precdes) return(0); + if(!pdbRecDes) return(0); if(!precnode) return(0); if(!precnode->precord) return(0); precord = (char *)precnode->precord; - pflddes = precdes->papFldDes[0]; + pflddes = pdbRecDes->papFldDes[0]; if(!pflddes) return(NULL); return(precord + pflddes->offset); } @@ -377,8 +378,7 @@ int dbIsDefaultValue(DBENTRY *pdbentry) return((field==0.0)); } case DBF_ENUM: - case DBF_MENU: - case DBF_DEVICE: { + case DBF_MENU: { unsigned short field = *(unsigned short *)pfield; unsigned long ltemp; @@ -388,10 +388,30 @@ int dbIsDefaultValue(DBENTRY *pdbentry) } return((field==0)); } + case DBF_DEVICE: { + dbRecDes *pdbRecDes = pdbentry->precdes; + devSup *pdevSup; + + if(!pdbRecDes) { + epicsPrintf("dbIsDefaultValue: pdbRecDes is NULL??\n"); + return(FALSE); + } + pdevSup = (devSup *)ellFirst(&pdbRecDes->devList); + if(!pdevSup) return(TRUE); + return(FALSE); + } case DBF_INLINK: case DBF_OUTLINK: - case DBF_FWDLINK: - return(TRUE); /*Dont know what to do with this!!*/ + case DBF_FWDLINK: { + struct link *plink = (struct link *)pfield; + + if(!plink) return(FALSE); + if(plink->type!=CONSTANT) return(FALSE); + if(plink->value.constantStr == 0) return(TRUE); + if(strcmp(plink->value.constantStr,pflddes->initial)==0) + return(TRUE); + return(FALSE); + } default: return(TRUE); } @@ -583,8 +603,8 @@ void dbGetRecordtypeSizeOffset(dbRecDes *pdbRecDes) (void *)&sizeOffset, &type); if (vxstatus != OK) { status = S_rec_noSizeOffset; - errPrintf(status,__FILE__,__LINE__,"%s",pdbRecDes->name); - return; + errPrintf(status,__FILE__,__LINE__,"%s",name); + exit(1); } sizeOffset(pdbRecDes); } diff --git a/src/dbStatic/dbYacc.y b/src/dbStatic/dbYacc.y index b85aaa5d0..0b4cf53db 100644 --- a/src/dbStatic/dbYacc.y +++ b/src/dbStatic/dbYacc.y @@ -37,31 +37,31 @@ database_item: include include: tokenINCLUDE tokenSTRING { - if(dbDebug>2) printf("include : %s\n",$2); + if(dbStaticDebug>2) printf("include : %s\n",$2); dbIncludeNew($2); }; path: tokenPATH tokenSTRING { - if(dbDebug>2) printf("path : %s\n",$2); + if(dbStaticDebug>2) printf("path : %s\n",$2); dbPathCmd($2); }; addpath: tokenADDPATH tokenSTRING { - if(dbDebug>2) printf("addpath : %s\n",$2); + if(dbStaticDebug>2) printf("addpath : %s\n",$2); dbAddPathCmd($2); }; menu_head: '(' tokenSTRING ')' { - if(dbDebug>2) printf("menu_head %s\n",$2); + if(dbStaticDebug>2) printf("menu_head %s\n",$2); dbMenuHead($2); }; menu_body: '{' choice_list '}' { - if(dbDebug>2) printf("menu_body\n"); + if(dbStaticDebug>2) printf("menu_body\n"); dbMenuBody(); } | include ; @@ -70,19 +70,19 @@ choice_list: choice_list choice | choice; choice: tokenCHOICE '(' tokenSTRING ',' tokenSTRING ')' { - if(dbDebug>2) printf("choice %s %s\n",$3,$5); + if(dbStaticDebug>2) printf("choice %s %s\n",$3,$5); dbMenuChoice($3,$5); } ; recordtype_head: '(' tokenSTRING ')' { - if(dbDebug>2) printf("recordtype_head %s\n",$2); + if(dbStaticDebug>2) printf("recordtype_head %s\n",$2); dbRecordtypeHead($2); }; recordtype_body: '{' recordtype_field_list '}' { - if(dbDebug>2) printf("recordtype_body\n"); + if(dbStaticDebug>2) printf("recordtype_body\n"); dbRecordtypeBody(); }; @@ -94,7 +94,7 @@ recordtype_field: tokenFIELD recordtype_field_head recordtype_field_body recordtype_field_head: '(' tokenSTRING ',' tokenSTRING ')' { - if(dbDebug>2) printf("recordtype_field_head %s %s\n",$2,$4); + if(dbStaticDebug>2) printf("recordtype_field_head %s %s\n",$2,$4); dbRecordtypeFieldHead($2,$4); }; @@ -105,14 +105,14 @@ recordtype_field_item_list: recordtype_field_item_list recordtype_field_item recordtype_field_item: tokenSTRING '(' tokenSTRING ')' { - if(dbDebug>2) printf("recordtype_field_item %s %s\n",$1,$3); + if(dbStaticDebug>2) printf("recordtype_field_item %s %s\n",$1,$3); dbRecordtypeFieldItem($1,$3); } | tokenMENU '(' tokenSTRING ')' { char *pmenu; - if(dbDebug>2) printf("recordtype_field_item %s (%s)\n",menuString,$3); + if(dbStaticDebug>2) printf("recordtype_field_item %s (%s)\n",menuString,$3); pmenu = (char *)malloc(strlen(menuString)+1); strcpy(pmenu,menuString); dbRecordtypeFieldItem(pmenu,$3); @@ -122,26 +122,26 @@ recordtype_field_item: tokenSTRING '(' tokenSTRING ')' device: tokenDEVICE '(' tokenSTRING ',' tokenSTRING ',' tokenSTRING ',' tokenSTRING ')' { - if(dbDebug>2) printf("device %s %s %s %s\n",$3,$5,$7,$9); + if(dbStaticDebug>2) printf("device %s %s %s %s\n",$3,$5,$7,$9); dbDevice($3,$5,$7,$9); }; driver: tokenDRIVER '(' tokenSTRING ')' { - if(dbDebug>2) printf("driver %s\n",$3); + if(dbStaticDebug>2) printf("driver %s\n",$3); dbDriver($3); }; break_head: '(' tokenSTRING ')' { - if(dbDebug>2) printf("break_head %s\n",$2); + if(dbStaticDebug>2) printf("break_head %s\n",$2); dbBreakHead($2); }; break_body : '{' break_list '}' { - if(dbDebug>2) printf("break_body\n"); + if(dbStaticDebug>2) printf("break_body\n"); dbBreakBody(); }; @@ -151,20 +151,20 @@ break_list: break_list ',' break_item break_item: tokenSTRING { - if(dbDebug>2) printf("break_item tokenSTRING %s\n",$1); + if(dbStaticDebug>2) printf("break_item tokenSTRING %s\n",$1); dbBreakItem($1); }; record_head: '(' tokenSTRING ',' tokenSTRING ')' { - if(dbDebug>2) printf("record_head %s %s\n",$2,$4); + if(dbStaticDebug>2) printf("record_head %s %s\n",$2,$4); dbRecordHead($2,$4); }; record_body: '{' record_field_list '}' { - if(dbDebug>2) printf("record_body\n"); + if(dbStaticDebug>2) printf("record_body\n"); dbRecordBody(); }; @@ -173,7 +173,7 @@ record_field_list: record_field_list record_field record_field: tokenFIELD '(' tokenSTRING ',' tokenSTRING ')' { - if(dbDebug>2) printf("record_field %s %s\n",$3,$5); + if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$5); dbRecordField($3,$5); } | include ; diff --git a/src/dbStatic/link.h b/src/dbStatic/link.h index 2831cde87..b8648b5cb 100644 --- a/src/dbStatic/link.h +++ b/src/dbStatic/link.h @@ -34,13 +34,15 @@ * .03 9-9-92 frl added vxi link type * .04 12-13-93 mcn added conversion pointer for fast links * .05 1-10-95 jt added rf_io structure + * .06 01-10-96 lrd added ca_link structure fields */ #include +#ifndef INClinkh +#define INClinkh 1 + /* link types */ -#ifndef INClinkLT -#define INClinkLT #define CONSTANT 0 #define PV_LINK 1 #define VME_IO 2 @@ -80,39 +82,32 @@ maplinkType pamaplinkType[LINK_NTYPES] = { }; #endif /*LINK_GBLSOURCE*/ -#endif /*INClinkLT*/ - -#ifndef INClinkh -#define INClinkh 1 -#define INSTIO_FLD_SZ 36 /* field size for instio */ -#define LINK_PARAM_SZ 32 -#define VME_PARAM_SZ 32 -#define AB_PARAM_SZ 28 -#define CAMAC_PARAM_SZ 26 -#define VXI_PARAM_SZ 26 #define VXIDYNAMIC 0 #define VXISTATIC 1 -/* structure of a link to a process variable*/ +/* structure of a PV_LINK DB_LINK and a CA_LINK */ +/*Options defined by pvlMask */ +#define pvlOptMS 0x1 /*Maximize Severity*/ +#define pvlOptPP 0x2 /*Process Passive*/ +#define pvlOptCA 0x4 /*Always make it a CA link*/ +#define pvlOptCP 0x8 /*CA + process on monitor*/ +#define pvlOptCPP 0x10 /*CA + process passive record on monitor*/ +#define pvlOptFWD 0x20 /*Generate ca_put for forward link*/ +typedef long (*LINKCVT)(); struct pv_link { - short process_passive; /* should in/out passive link be processed*/ - short maximize_sevr; /* maximize sevr of link. stat=LINK_ALARM*/ - char *pvname; -}; - -/* structure of a link to a database link */ -struct db_link { - short process_passive; /* should in/out passive link be processed */ - short maximize_sevr; /* maximize sevr of link. stat=LINK_ALARM */ - void *pdbAddr; /* pointer to database address structure */ - long (*conversion)(); /* conversion routine for fast links */ + char *pvname; /*pvname to link to*/ + void *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*/ }; /* structure of a VME io channel */ struct vmeio { short card; short signal; - char parm[VME_PARAM_SZ]; + char *parm; }; /* structure of a CAMAC io channel */ @@ -122,7 +117,7 @@ struct camacio { short n; short a; short f; - char parm[CAMAC_PARAM_SZ]; + char *parm; }; /* structure of a RF io channel */ @@ -141,14 +136,14 @@ struct abio { short adapter; short card; short signal; - char parm[AB_PARAM_SZ]; + char *parm; }; /* structure of a gpib io channel */ struct gpibio { short link; short addr; /* device address */ - char parm[LINK_PARAM_SZ]; + char *parm; }; /* structure of a bitbus io channel */ @@ -157,7 +152,7 @@ struct bitbusio { unsigned char node; unsigned char port; unsigned char signal; - char parm[LINK_PARAM_SZ]; + char *parm; }; /* structure of a bitbus to gpib io channel */ @@ -166,12 +161,12 @@ struct bbgpibio { unsigned char bbaddr; unsigned char gpibaddr; unsigned char pad; - char parm[LINK_PARAM_SZ]; + char *parm; }; /* structure of an instrument io link */ struct instio { - char string[INSTIO_FLD_SZ]; /* the cat of location. + char *string; /* the cat of location. signal.parameter */ }; @@ -182,7 +177,7 @@ struct vxiio{ short slot; short la; /* logical address if flag =1 */ short signal; - char parm[VXI_PARAM_SZ]; + char *parm; }; /* union of possible address structures */ @@ -195,18 +190,15 @@ union value{ struct abio abio; /* allen-bradley io point */ struct gpibio gpibio; struct bitbusio bitbusio; - struct db_link db_link; /* Data base link */ - void *ca_link; /* Channel Access link */ struct instio instio; /* instrument io link */ struct bbgpibio bbgpibio; /* bitbus to gpib io link */ struct vxiio vxiio; /* vxi io */ }; struct link{ - long type; - long pad; union value value; + short type; }; typedef struct link DBLINK; -#endif +#endif /*INClinkh*/