diff --git a/src/ca/access.c b/src/ca/access.c index 19f862cbc..cafe34132 100644 --- a/src/ca/access.c +++ b/src/ca/access.c @@ -2,7 +2,7 @@ /* */ /* L O S A L A M O S */ /* Los Alamos National Laboratory */ -/* Los Alamos, New Mexico 87545 */ +/* Los Alamos, New Mexico 87545 */ /* */ /* Copyright, 1986, The Regents of the University of California. */ /* */ @@ -16,6 +16,12 @@ /* 1/90 Jeff HIll switched order in task exit */ /* so events are deleted first */ /* then closed */ +/* 3/90 Jeff Hill Changed error message strings */ +/* to allocate in this module only */ +/* & further improved vx task exit */ +/* 021291 joh fixed potential problem with strncpy and */ +/* the vxWorks task name. */ +/* 022791 mda integration of ANL/LANL db code */ /* */ /*_begin */ /************************************************************************/ @@ -32,15 +38,11 @@ /* ioc high level access routines */ /* */ /* */ -/* Special comments */ +/* Special comments */ /* ------- -------- */ /* Things that could be done to improve this code */ -/* 1) Check timeouts on the ca_pend for values to large */ -/* 2) When a chid is marked disconnected any associated */ -/* monitors should be placed in inactive list as well */ -/* 3) Fix the monitor cancel protocol */ -/* 4) Allow them to recieve channel A when channel B changes */ -/* */ +/* 1) Check timeouts on ca_pend for values to large */ +/* 2) Allow them to recieve channel A when channel B changes */ /* */ /************************************************************************/ /*_end */ @@ -50,6 +52,8 @@ #include stsdef.h #include ssdef.h #include psldef.h +#include prcdef.h +#include descrip.h #else #endif @@ -57,12 +61,22 @@ #ifdef vxWorks # include -# include -/*# include */ +# include #endif +/* + * allocate error message string array + * here so I can use sizeof + */ +#define CA_ERROR_GLBLSOURCE + +/* + * allocate db_access message strings here + */ +#define DB_TEXT_GLBLSOURCE #include #include + #include #include #include @@ -75,7 +89,10 @@ #define SNDBEG(STRUCTURE) \ SND_BEG(STRUCTURE, &iiu[chix->iocix]) -#define SND_BEG(STRUCTURE, PIIU) \ +#define SNDBEG_NOLOCK(STRUCTURE) \ +SND_BEG_NOLOCK(STRUCTURE, &iiu[chix->iocix]) + +#define SND_BEG(STRUCTURE, PIIU)\ LOCK SND_BEG_NOLOCK(STRUCTURE,PIIU) #define SND_BEG_NOLOCK(STRUCTURE,PIIU) \ @@ -115,25 +132,58 @@ LOCK SNDBEG_VARIABLE_NOLOCK(POSTSIZE) /****************************************************************/ /* Macros for error checking */ /****************************************************************/ +/* + valid type check filters out disconnected channel +*/ + #define CHIXCHK(CHIX) \ { \ - register unsigned short iocix = CHIX->iocix; \ + register unsigned short iocix = (CHIX)->iocix; \ if( iocix == BROADCAST_IIU || \ (iocix >= nxtiiu && iocix != LOCAL_IIU) || \ - INVALID_DB_REQ(CHIX->type)) \ + INVALID_DB_REQ((CHIX)->type) ) \ return ECA_BADCHID; \ } -#define INITCHK \ -if(!ca_static) \ - ca_task_initialize(); +/* type to detect them using deallocated channel in use block */ +#define TYPENOTINUSE (-2) + +/* allow them to add monitors to a disconnected channel */ +#define LOOSECHIXCHK(CHIX) \ +{ \ + register unsigned short iocix = CHIX->iocix; \ + if( (iocix >= nxtiiu && iocix != LOCAL_IIU) || \ + (CHIX)->type==TYPENOTINUSE ) \ + return ECA_BADCHID; \ +} + +#define INITCHK if(!ca_static) ca_task_initialize(); static struct extmsg nullmsg; +void ca_default_exception_handler(); +void *db_init_events(); +void ca_default_exception_handler(); +void ca_repeater_task(); +int ca_import(); + +#ifdef vxWorks +static check_for_fp(); +static ca_add_task_variable(); +static void ca_task_exit_tid(); +static void issue_get_callback(); +static void ca_event_handler(); +#endif +/* + * + * CA_TASK_INITIALIZE + * + * + */ ca_task_initialize #ifdef VAXC (void) @@ -142,34 +192,82 @@ ca_task_initialize #endif { int status; - char *taskName(); char name[15]; - void *db_init_events(); - int ca_import(); if(!ca_static){ + /* + Spawn the repeater task as needed + */ + if(!repeater_installed()){ +# ifdef UNIX + /* + * This method of spawn places a path name in the code so it has been + * avoided for now + * + * use of fork makes ca and repeaters image larger than required + * + * system("/path/repeater &"); + */ + status = fork(); + if(status<0) + SEVCHK(ECA_INTERNAL,"couldnt spawn the repeater task"); + if(!status) + ca_repeater_task(); +# endif # ifdef vxWorks - { - int options; + status = taskSpawn( + CA_REPEATER_NAME, + CA_REPEATER_PRI, + CA_REPEATER_OPT, + CA_REPEATER_STACK, + ca_repeater_task + ); + if(status<0) + SEVCHK(ECA_INTERNAL,"couldnt spawn the repeater task"); +# endif +# ifdef VMS + { + static $DESCRIPTOR(image, "LAACS_CA_REPEATER"); + static $DESCRIPTOR(name, "CA repeater"); + static $DESCRIPTOR(in, "CONSOLE"); + static $DESCRIPTOR(out, "CONSOLE"); + static $DESCRIPTOR(err, "CONSOLE"); + int privs = ~0; + unsigned long pid; - if(taskOptionsGet(taskIdSelf(),&options)==ERROR) - abort(); - if(!(options & VX_FP_TASK)) - SEVCHK(ECA_NEEDSFP, NULL); - - if(taskOptionsSet(taskIdSelf(),VX_FP_TASK,VX_FP_TASK)==ERROR) - abort(); - - if(ca_add_task_variable()== ERROR) - abort(); + status = sys$creprc( + &pid, + &image, + &in, + &out, + &err, + &privs, + NULL, + &name, + 4, /*base priority */ + NULL, + NULL, + PRC$M_DETACH); + if(status != SS$_NORMAL) + lib$signal(status); +printf("spawning repeater %x\n", pid); + } +# endif } + +# ifdef vxWorks + check_for_fp(); + if(ca_add_task_variable() == ERROR) + abort(); # endif - ca_static = (struct ca_static *) malloc(sizeof(*ca_static)); + ca_static = (struct ca_static *) calloc(1, sizeof(*ca_static)); if(!ca_static) abort(); - memset(ca_static, NULL, sizeof(*ca_static)); + + ca_static->ca_exception_func = ca_default_exception_handler; + ca_static->ca_exception_arg = NULL; # ifdef VMS status = lib$get_ef(&io_done_flag); @@ -178,19 +276,29 @@ ca_task_initialize # endif # ifdef vxWorks + { + char *taskName(); + ca_static->ca_tid = taskIdSelf(); - FASTLOCKINIT(&client_lock); + FASTLOCKINIT(&client_lock); - evuser = (void *) db_init_events(); - if(!evuser) - abort(); + evuser = (void *) db_init_events(); + if(!evuser) + abort(); - name[0]=NULL; - strncat(name,"EV ", sizeof(name)-1); - strncat(name, taskName(VXTHISTASKID), sizeof(name)-1); - status = db_start_events(evuser, name, ca_import, taskIdSelf()); - if(status != OK) - abort(); + strcpy(name, "EV "); + strncat( + name, + taskName(VXTHISTASKID), + sizeof(name)-strlen(name)-1); + status = db_start_events( + evuser, + name, + ca_import, + taskIdSelf()); + if(status != OK) + abort(); + } # endif } @@ -198,28 +306,72 @@ ca_task_initialize return ECA_NORMAL; } + +/* + * + * CHECK_FOR_FP() + * + * + */ #ifdef vxWorks -ca_import(moms_tid) -int moms_tid; +static check_for_fp() { - int status; - - status = taskVarAdd(VXTHISTASKID, &ca_static); - if(status == ERROR) - abort(); - - ca_static = (struct ca_static *) taskVarGet(moms_tid, &ca_static); - if(ca_static == (struct ca_static*)ERROR) - abort(); + { + int options; - return ECA_NORMAL; + if(taskOptionsGet(taskIdSelf(),&options)==ERROR) + abort(); + if(!(options & VX_FP_TASK)){ + ca_signal(ECA_NEEDSFP, NULL); + + if(taskOptionsSet(taskIdSelf(),VX_FP_TASK,VX_FP_TASK)==ERROR) + abort(); + } + } } #endif +/* + * + * CA_IMPORT() + * + * + */ #ifdef vxWorks -static -ca_add_task_variable() +ca_import(moms_tid) +int moms_tid; +{ + int status; + struct ca_static *pcas; + + pcas = (struct ca_static*) taskVarGet(moms_tid, &ca_static); + if(pcas == (struct ca_static*) ERROR) + return ECA_NOCACTX; + + status = taskVarAdd(VXTHISTASKID, &ca_static); + if(status == ERROR) + abort(); + + ca_static = pcas; + + check_for_fp(); + + return ECA_NORMAL; +} +#endif + + + + + +/* + * + * CA_ADD_TASK_VARIABLE() + * + */ +#ifdef vxWorks +static ca_add_task_variable() { static void ca_task_exit_tcbx(); static char ca_installed; @@ -247,10 +399,11 @@ ca_add_task_variable() /* - NOTE: only call this routine if you wish to free resources - prior to task exit- The following is executed routinely at - task exit by the OS. -*/ + * CA_TASK_EXIT() + * + * call this routine if you wish to free resources prior to task + * exit- ca_task_exit() is also executed routinely at task exit. + */ ca_task_exit #ifdef VAXC (void) @@ -259,11 +412,10 @@ ca_task_exit #endif { void ca_task_exit_tid(); - # ifdef vxWorks ca_task_exit_tid(VXTHISTASKID); # else - ca_task_exit_tid(0); + ca_task_exit_tid(NULL); #endif return ECA_NORMAL; @@ -281,15 +433,24 @@ TCBX *ptcbx; } #endif - +/* + * + * CA_TASK_EXIT_TID + * attempts to release all resources alloc to a channel access client + * + * NOTE: on vxWorks if a CA task is deleted or crashes while a + * lock is set then a deadlock will occur when this routine is called. + * + */ static void ca_task_exit_tid(tid) int tid; { int i; chid chix; - evid monix; struct ca_static *ca_temp; + evid monix; + int status; # ifdef vxWorks ca_temp = (struct ca_static *) taskVarGet(tid, &ca_static); @@ -315,41 +476,56 @@ int tid; logMsg("ca_task_exit: Removing task %x from CA\n",tid); # endif -/********** LOCK; -***********/ + /* + Fist I must stop any source of further activity + on vxWorks + */ - for(i=0; i< ca_temp->ca_nxtiiu; i++){ - if(socket_close(ca_temp->ca_iiu[i].sock_chan)<0) - SEVCHK(ECA_INTERNAL, "Corrupt iiu list- close"); - if(free(ca_temp->ca_iiu[i].send)<0) - SEVCHK(ECA_INTERNAL, "Corrupt iiu list- send free"); - if(free(ca_temp->ca_iiu[i].recv)<0) - SEVCHK(ECA_INTERNAL, "Corrupt iiu list- recv free"); -# ifdef vxWorks - taskDelete(ca_temp->ca_iiu[i].recv_tid); -# endif - } - - while(monix = (evid) lstGet(&ca_temp->ca_eventlist)){ -# ifdef vxWorks - {int status; - if(monix->chan->iocix == LOCAL_IIU){ - status = db_cancel_event(monix+1); - if(status==ERROR) - abort(); - } - } -# endif - if(free(monix)<0) - SEVCHK(ECA_INTERNAL, "Corrupt evid list"); - } + /* + The main task is prevented from further CA activity + by the LOCK placed above + */ + /* + stop socket recv tasks + */ # ifdef vxWorks - {int status; + for(i=0; i< ca_temp->ca_nxtiiu; i++){ + /* + dont do a task delete if the + exit handler is running for this task + - it botches vxWorks - + */ + if(tid != ca_temp->ca_iiu[i].recv_tid) + taskDelete(ca_temp->ca_iiu[i].recv_tid); + } +# endif + + /* + Cancel all local events + */ +# ifdef vxWorks + chix = (chid) &ca_temp->ca_local_chidlist; + while(chix = (chid) chix->node.next) + while(monix = (evid) lstGet(&chix->eventq)){ + status = db_cancel_event(monix+1); + if(status==ERROR) + abort(); + if(free(monix)<0) + ca_signal(ECA_INTERNAL, "Corrupt conn evid list"); + } +# endif + + /* + All local events must be canceled prior to closing the + local event facility + */ +# ifdef vxWorks + { status = db_close_events(ca_temp->ca_evuser); if(status==ERROR) - SEVCHK(ECA_INTERNAL, "could not close event facility by id"); + ca_signal(ECA_INTERNAL, "could not close event facility by id"); } if(ca_temp->ca_event_buf) @@ -357,48 +533,71 @@ int tid; abort(); # endif - while(chix = (chid) lstGet(&ca_temp->ca_chidlist_conn)){ -# ifdef vxWorks - if(chix->iocix == LOCAL_IIU) - if(free(chix->paddr)<0) - SEVCHK(ECA_INTERNAL, "Corrupt paddr in chid list"); -# endif - if(free(chix)<0) - SEVCHK(ECA_INTERNAL, "Corrupt connected chid list"); + /* + after activity eliminated: + */ + /* + close all sockets before clearing chid blocks + and remote event blocks + */ + for(i=0; i< ca_temp->ca_nxtiiu; i++){ + if(ca_temp->ca_iiu[i].conn_up) + if(socket_close(ca_temp->ca_iiu[i].sock_chan)<0) + ca_signal(ECA_INTERNAL, "Corrupt iiu list- at close"); + if(free(ca_temp->ca_iiu[i].send)<0) + ca_signal(ECA_INTERNAL, "Corrupt iiu list- send free"); + if(free(ca_temp->ca_iiu[i].recv)<0) + ca_signal(ECA_INTERNAL, "Corrupt iiu list- recv free"); } - while(chix = (chid) lstGet(&ca_temp->ca_chidlist_pend)){ - if(free(chix)<0) - SEVCHK(ECA_INTERNAL, "Corrupt pending chid list"); + /* + remove remote chid blocks and event blocks + */ + for(i=0; i< ca_temp->ca_nxtiiu; i++){ + while(chix = (chid) lstGet(&ca_temp->ca_iiu[i].chidlist)){ + while(monix = (evid) lstGet(&chix->eventq)){ + if(free(monix)<0) + ca_signal(ECA_INTERNAL, "Corrupt conn evid list"); + } + if(free(chix)<0) + ca_signal(ECA_INTERNAL, "Corrupt connected chid list"); + } } - while(chix = (chid) lstGet(&ca_temp->ca_chidlist_noreply)){ - if(free(chix)<0) - SEVCHK(ECA_INTERNAL, "Corrupt unanswered chid list"); - } + /* + remove local chid blocks, paddr blocks, waiting ev blocks + */ +# ifdef vxWorks + while(chix = (chid) lstGet(&ca_temp->ca_local_chidlist)) + if(free(chix)<0) + ca_signal(ECA_INTERNAL, "Corrupt connected chid list"); + lstFree(&ca_temp->ca_dbfree_ev_list); +# endif + + /* remove remote waiting ev blocks */ + lstFree(&ca_temp->ca_free_event_list); + /* remove any pending read blocks */ + lstFree(&ca_temp->ca_pend_read_list); -/************** UNLOCK; -***************/ if(free(ca_temp)<0) - SEVCHK(ECA_INTERNAL, "Unable to free task static variables"); + ca_signal(ECA_INTERNAL, "Unable to free task static variables"); /* - Only remove task variable if user is call this + Only remove task variable if user is calling this from ca_task_exit with the task id = 0 This is because if I delete the task variable from a vxWorks exit handler it botches vxWorks task exit */ # ifdef vxWorks - if(tid == VXTHISTASKID) + if(tid == taskIdSelf()) {int status; status = taskVarDelete(tid, &ca_static); if(status == ERROR) - SEVCHK(ECA_INTERNAL, "Unable to remove ca_static from task var list"); - + ca_signal(ECA_INTERNAL, "Unable to remove ca_static from task var list"); } # endif @@ -407,23 +606,35 @@ int tid; } } + + -ca_array_build +/* + * + * CA_BUILD_AND_CONNECT + * + * + */ +ca_build_and_connect #ifdef VAXC ( char *name_str, chtype get_type, unsigned int get_count, chid *chixptr, -void *pvalue +void *pvalue, +void (*conn_func)(), +void *puser ) #else -(name_str,get_type,get_count,chixptr,pvalue) +(name_str,get_type,get_count,chixptr,pvalue,conn_func,puser) char *name_str; chtype get_type; unsigned int get_count; chid *chixptr; void *pvalue; +void (*conn_func)(); +void *puser; #endif { long status; @@ -449,8 +660,10 @@ void *pvalue; /* Put some reasonable limit on user supplied string size */ strcnt = strlen(name_str) + 1; - if(strcnt > MAX_STRING_SIZE || strcnt==1 ) + if(strcnt > MAX_STRING_SIZE) return ECA_STRTOBIG; + if(strcnt == 1) + return ECA_EMPTYSTR; if(strcnt==1 ) @@ -460,33 +673,36 @@ void *pvalue; /* Make sure string is aligned to short word boundaries for MC68000 */ strcnt = BI_ROUND(strcnt)<<1; - /* allocate CHIU (channel in use) block */ - /* also allocate enough for a copy of this msg */ - *chixptr = chix = (chid) malloc(sizeof(*chix) + strcnt); - if(!chix) - return ECA_ALLOCMEM; - - # ifdef vxWorks /* only for IO machines */ { - struct db_addr tmp_paddr; + struct db_addr tmp_paddr; + struct connection_handler_args args; /* Find out quickly if channel is on this node */ status = db_name_to_addr(name_str, &tmp_paddr); if(status==OK){ - chix->paddr = (void *) malloc(sizeof(struct db_addr)); - if(!chix->paddr) - abort(); + /* allocate CHIU (channel in use) block */ + /* also allocate enough for the channel name & paddr block*/ + *chixptr = chix = (chid) malloc(sizeof(*chix) + + strcnt + sizeof(struct db_addr)); + if(!chix) + abort(); + + chix->paddr = (void *) (strcnt + (char *)(chix+1)); *(struct db_addr *)chix->paddr = tmp_paddr; + chix->puser = puser; + chix->connection_func = conn_func; chix->type = ( (struct db_addr *)chix->paddr )->field_type; chix->count = ( (struct db_addr *)chix->paddr )->no_elements; chix->iocix = LOCAL_IIU; + chix->state = cs_conn; + lstInit(&chix->eventq); strncpy(chix+1, name_str, strcnt); /* check for just a search */ - if(get_count && get_type != TYPENOTCONN){ - status = db_get_field(&tmp_paddr, get_type, pvalue, get_count, FALSE); + if(get_count && get_type != TYPENOTCONN && pvalue){ + status=db_get_field(&tmp_paddr, get_type, pvalue, get_count); if(status!=OK){ free(chix->paddr); *chixptr = (chid) free(chix); @@ -494,13 +710,26 @@ void *pvalue; } } LOCK; - lstAdd(&chidlist_conn, chix); + lstAdd(&local_chidlist, chix); UNLOCK; + if(chix->connection_func){ + args.chid = chix; + args.op = CA_OP_CONN_UP; + + (*chix->connection_func)(args); + } + return ECA_NORMAL; } } -# endif +# endif + + /* allocate CHIU (channel in use) block */ + /* also allocate enough for the channel name */ + *chixptr = chix = (chid) malloc(sizeof(*chix) + strcnt); + if(!chix) + return ECA_ALLOCMEM; LOCK; @@ -514,7 +743,10 @@ void *pvalue; goto exit; } + chix->puser = puser; + chix->connection_func = conn_func; chix->type = TYPENOTCONN; /* invalid initial type */ + chix->count = 0; /* invalid initial count */ chix->paddr = (void *)NULL; /* invalid initial paddr */ /* save stuff for build retry if required */ @@ -522,12 +754,22 @@ void *pvalue; chix->build_count = get_count; chix->build_value = (void *) pvalue; chix->name_length = strcnt; + chix->state = cs_never_conn; + lstInit(&chix->eventq); /* Save this channels name for retry if required */ strncpy(chix+1, name_str, strcnt); - lstAdd(&chidlist_pend, chix); - status = build_msg(chix, FALSE); + lstAdd(&iiu[BROADCAST_IIU].chidlist, chix); + /* set the conn tries back to zero so this channel can be found */ + iiu[BROADCAST_IIU].nconn_tries = 0; + + status = build_msg(chix, FALSE, DONTREPLY); + if(!chix->connection_func){ + SETPENDRECV; + if(VALID_BUILD(chix)) + SETPENDRECV; + } exit: @@ -540,18 +782,19 @@ exit: /* - -NOTE: *** lock must be on while in this routine *** - -*/ -build_msg(chix,retry) + * BUILD_MSG() + * + * NOTE: *** lock must be applied while in this routine *** + * + */ +build_msg(chix,reply_type) chid chix; -int retry; +int reply_type; { register int size; register int cmd; - if(chix->build_count && chix->build_type != TYPENOTCONN){ + if(VALID_BUILD(chix)){ size = chix->name_length + sizeof(struct extmsg); cmd = IOC_BUILD; } @@ -565,23 +808,22 @@ int retry; mptr->m_cmmd = htons(cmd); mptr->m_postsize = htons(size); - mptr->m_available = (long) chix; - mptr->m_type = 0; + mptr->m_available = (int) chix; + mptr->m_type = reply_type; mptr->m_count = 0; - mptr->m_paddr = 0; + mptr->m_pciu = (void *) chix; if(cmd == IOC_BUILD){ /* msg header only on db read req */ mptr++; mptr->m_postsize = 0; - mptr->m_cmmd = htons(IOC_READ); + mptr->m_cmmd = htons(IOC_READ_BUILD); mptr->m_type = htons(chix->build_type); mptr->m_count = htons(chix->build_count); mptr->m_available = (int) chix->build_value; - mptr->m_paddr = chix->paddr; + mptr->m_pciu = 0; + - if(!retry) - SETPENDRECV; } /* channel name string */ @@ -589,9 +831,6 @@ int retry; mptr++; strncpy(mptr, chix+1, chix->name_length); - if(!retry) - SETPENDRECV; - SNDEND_NOLOCK; return ECA_NORMAL; @@ -600,6 +839,12 @@ int retry; +/* + * + * CA_ARRAY_GET() + * + * + */ ca_array_get #ifdef VAXC ( @@ -633,8 +878,7 @@ register void *pvalue; chix->paddr, type, pvalue, - count, - FALSE); + count ); if(status==OK) return ECA_NORMAL; else @@ -652,7 +896,7 @@ register void *pvalue; mptr->m_type = htons(type); mptr->m_available = (long) pvalue; mptr->m_count = htons(count); - mptr->m_paddr = chix->paddr; + mptr->m_pciu = chix->paddr; SNDEND SETPENDRECV; @@ -660,6 +904,112 @@ register void *pvalue; } +/* + * + * CA_ARRAY_GET_CALLBACK() + * + * + * + */ +ca_array_get_callback +#ifdef VAXC +( +chtype type, +unsigned int count, +chid chix, +void (*pfunc)(), +void *arg +) +#else +(type,count,chix,pfunc,arg) +chtype type; +unsigned int count; +chid chix; +void (*pfunc)(); +void *arg; +#endif +{ + int status; + evid monix; + void ca_event_handler(); + void issue_get_callback(); + + CHIXCHK(chix); + + if(INVALID_DB_REQ(type)) + return ECA_BADTYPE; + + if(count > chix->count) + return ECA_BADCOUNT; + +# ifdef vxWorks + if(chix->iocix == LOCAL_IIU){ + struct pending_event ev; + + ev.usr_func = pfunc; + ev.usr_arg = arg; + ev.chan = chix; + ev.type = type; + ev.count = count; + ca_event_handler(&ev, chix->paddr, NULL); + return ECA_NORMAL; + } +# endif + + LOCK; + if(!(monix = (evid) lstGet(&free_event_list))) + monix = (evid) malloc(sizeof *monix); + + if(monix){ + + monix->chan = chix; + monix->usr_func = pfunc; + monix->usr_arg = arg; + monix->type = type; + monix->count = count; + + lstAdd(&pend_read_list, monix); + + issue_get_callback(monix); + + status = ECA_NORMAL; + }else + status = ECA_ALLOCMEM; + + UNLOCK; + return status; +} + + +/* + * + * ISSUE_GET_CALLBACK() + * (lock must be on) + */ +static void issue_get_callback(monix) +register evid monix; +{ + register chid chix = monix->chan; + + SNDBEG_NOLOCK(extmsg) + + /* msg header only on db read notify req */ + mptr->m_cmmd = htons(IOC_READ_NOTIFY); + mptr->m_type = htons(monix->type); + mptr->m_available = (long) monix; + mptr->m_count = htons(monix->count); + mptr->m_pciu = chix->paddr; + mptr->m_postsize = 0; + + SNDEND_NOLOCK; +} + + +/* + * CA_ARRAY_PUT() + * + * + */ ca_array_put #ifdef VAXC ( @@ -721,6 +1071,7 @@ register void *pvalue; break; case DBR_FLOAT: + case DBR_DOUBLE: /* most compilers pass all floats as doubles */ htonf(pvalue, pdest); break; @@ -753,11 +1104,14 @@ register void *pvalue; case DBR_STS_STRING: case DBR_STS_INT: case DBR_STS_FLOAT: + case DBR_STS_DOUBLE: case DBR_STS_ENUM: case DBR_GR_INT: case DBR_GR_FLOAT: + case DBR_GR_DOUBLE: case DBR_CTRL_INT: case DBR_CTRL_FLOAT: + case DBR_CTRL_DOUBLE: case DBR_CTRL_ENUM: # ifdef VAX (*cvrt[type])(pvalue,pdest,TRUE,count); @@ -780,7 +1134,7 @@ array_loop_exit: mptr->m_postsize = htons(postcnt); mptr->m_type = htons(type); mptr->m_count = htons(count); - mptr->m_paddr = chix->paddr; + mptr->m_pciu = chix->paddr; mptr->m_available = (long) chix; SNDEND @@ -789,12 +1143,90 @@ array_loop_exit: /* - Specify a event subroutine to be run once when pending IO completes + * Specify an event subroutine to be run for connection events + * + */ +ca_change_connection_event +#ifdef VAXC +( +chid chix, +void (*pfunc)() +) +#else +(chix, pfunc) +chid chix; +void (*pfunc)(); +#endif +{ - 1) event sub runs right away if no IO pending - 2) event sub runs when pending IO completes otherwise + INITCHK; + LOOSECHIXCHK(chix); -*/ + if(chix->connection_func == pfunc) + return ECA_NORMAL; + + LOCK; + if(chix->type == TYPENOTCONN){ + if(!chix->connection_func){ + CLRPENDRECV; + if(VALID_BUILD(chix)) + CLRPENDRECV; + } + if(!pfunc){ + SETPENDRECV; + if(VALID_BUILD(chix)) + SETPENDRECV; + } + } + chix->connection_func = pfunc; + UNLOCK; + + return ECA_NORMAL; +} + + +/* + * Specify an event subroutine to be run for asynch exceptions + * + */ +ca_add_exception_event +#ifdef VAXC +( +void (*pfunc)(), +void *arg +) +#else +(pfunc,arg) +void (*pfunc)(); +void *arg; +#endif +{ + + INITCHK; + LOCK; + if(pfunc){ + ca_static->ca_exception_func = pfunc; + ca_static->ca_exception_arg = arg; + } + else{ + ca_static->ca_exception_func = ca_default_exception_handler; + ca_static->ca_exception_arg = NULL; + } + UNLOCK; + + return ECA_NORMAL; +} + + +/* + * Specify an event subroutine to be run once pending IO completes + * + * 1) event sub runs right away if no IO pending + * 2) otherwise event sub runs when pending IO completes + * + * Undocumented entry for the VAX OPI which may vanish in the future. + * + */ ca_add_io_event #ifdef VAXC ( @@ -803,12 +1235,14 @@ void *astarg ) #else (ast,astarg) -void (*ast)(); -void *astarg; +void (*ast)(); +void *astarg; #endif { register struct pending_io_event *pioe; + INITCHK; + if(pndrecvcnt<1) (*ast)(astarg); else{ @@ -828,7 +1262,12 @@ void *astarg; -ca_add_array_event +/* + * CA_ADD_MASKED_ARRAY_EVENT + * + * + */ +ca_add_masked_array_event #ifdef VAXC ( chtype type, @@ -839,10 +1278,11 @@ void *astarg, ca_real p_delta, ca_real n_delta, ca_real timeout, -evid *monixptr +evid *monixptr, +long mask ) #else -(type,count,chix,ast,astarg,p_delta,n_delta,timeout,monixptr) +(type,count,chix,ast,astarg,p_delta,n_delta,timeout,monixptr,mask) chtype type; unsigned int count; chid chix; @@ -852,30 +1292,55 @@ ca_real p_delta; ca_real n_delta; ca_real timeout; evid *monixptr; +unsigned mask; #endif { register evid monix; + void ca_request_event(); + int evsize; + register int status; - CHIXCHK(chix); + LOOSECHIXCHK(chix); if(INVALID_DB_REQ(type)) return ECA_BADTYPE; - if(count > chix->count) + /* + * + * + */ + if(count > chix->count && chix->type != TYPENOTCONN) return ECA_BADCOUNT; - if(count == 0) - count = chix->count; + LOCK; - - /* AST descriptor */ + /* event descriptor */ # ifdef vxWorks - monix = (evid) malloc(sizeof(*monix)+db_sizeof_event_block()); + { + static int dbevsize; + + if(chix->iocix == LOCAL_IIU){ + + if(!dbevsize) + dbevsize = db_sizeof_event_block(); + + + if(!(monix = (evid)lstGet(&dbfree_ev_list))) + monix = (evid)malloc(sizeof(*monix)+dbevsize); + } + else + if(!(monix = (evid)lstGet(&free_event_list))) + monix = (evid)malloc(sizeof *monix); + } # else - monix = (evid) malloc(sizeof(*monix)); + if(!(monix = (evid)lstGet(&free_event_list))) + monix = (evid) malloc(sizeof *monix); # endif - if(!monix) - return ECA_ALLOCMEM; + + if(!monix){ + status = ECA_ALLOCMEM; + goto unlock_rtn; + } /* they dont have to supply one if they dont want to */ if(monixptr) @@ -886,16 +1351,14 @@ evid *monixptr; monix->usr_arg = astarg; monix->type = type; monix->count = count; - - LOCK; - /* Place in the channel list */ - lstAdd(&eventlist, monix); - UNLOCK; + monix->p_delta = p_delta; + monix->n_delta = n_delta; + monix->timeout = timeout; + monix->mask = mask; # ifdef vxWorks { struct monops mon; - register int status; void ca_event_handler(); if(chix->iocix == LOCAL_IIU){ @@ -903,45 +1366,108 @@ evid *monixptr; chix->paddr, ca_event_handler, monix, - DBE_VALUE | DBE_ALARM, + mask, monix+1); - if(status == ERROR) - return ECA_DBLCLFAIL; + if(status == ERROR){ + status = ECA_DBLCLFAIL; + goto unlock_rtn; + } - /* force event to be called at least once */ - db_post_single_event(monix+1); - return ECA_NORMAL; + /* + Place in the channel list + - do it after db_add_event so there + is no chance that it will be deleted + at exit before it is completely created + */ + lstAdd(&chix->eventq, monix); + + /* + force event to be called at least once + return warning msg if they have made the queue to full + to force the first (untriggered) event. + */ + if(db_post_single_event(monix+1)==ERROR){ + status = ECA_OVEVFAIL; + goto unlock_rtn; + } + + status = ECA_NORMAL; + goto unlock_rtn; } } # endif - SNDBEG(monops) + /* It can be added to the list any place if it is remote */ + /* Place in the channel list */ + lstAdd(&chix->eventq, monix); + + /* + dont send the message if the conn is down + (it will be sent once connected) + */ + if(chix->iocix!=BROADCAST_IIU) + if(iiu[chix->iocix].conn_up) + ca_request_event(monix); + + status = ECA_NORMAL; + +unlock_rtn: + + UNLOCK; + + return status; +} + + +/* + * CA_REQUEST_EVENT() + * + * LOCK must be applied while in this routine + */ +void ca_request_event(monix) +evid monix; +{ + register chid chix = monix->chan; /* for SNDBEG */ + + /* + * clip to the native count + */ + if(monix->count > chix->count || monix->count == 0) + monix->count = chix->count; + + SNDBEG_NOLOCK(monops) /* msg header */ mptr->m_header.m_cmmd = htons(IOC_EVENT_ADD); mptr->m_header.m_available = (long) monix; mptr->m_header.m_postsize = htons(sizeof(struct mon_info)); - mptr->m_header.m_type = htons(type); - mptr->m_header.m_count = htons(count); - mptr->m_header.m_paddr = chix->paddr; + mptr->m_header.m_type = htons(monix->type); + mptr->m_header.m_count = htons(monix->count); + mptr->m_header.m_pciu = chix->paddr; /* msg body */ - htonf(&p_delta, &mptr->m_info.m_hval); - htonf(&n_delta, &mptr->m_info.m_lval); - htonf(&timeout, &mptr->m_info.m_toval); + htonf(&monix->p_delta, &mptr->m_info.m_hval); + htonf(&monix->n_delta, &mptr->m_info.m_lval); + htonf(&monix->timeout, &mptr->m_info.m_toval); + mptr->m_info.m_mask = htons(monix->mask); - SNDEND - return ECA_NORMAL; + SNDEND_NOLOCK } +/* + * + * CA_EVENT_HANDLER() + * (only for local (for now vxWorks) clients) + * + */ #ifdef vxWorks -static void -ca_event_handler(monix, paddr, hold) +static void ca_event_handler(monix, paddr, hold, pfl) register evid monix; register struct db_addr *paddr; int hold; +caddr_t pfl; { register int status; register int count = monix->count; @@ -972,15 +1498,21 @@ int hold; abort(); event_buf_size = size; } - status = db_get_field( paddr, + status = db_event_get_field(paddr, type, pval, count, - TRUE); + pfl); } - if(status == ERROR) - logMsg("CA post event get error\n"); + /* + * @@@@@@ should tell um with the event handler ? + * or run an exception +@@@@@@@@@@@@@@@@ + */ + if(status == ERROR){ + SEVCHK(ECA_GETFAIL,"Event lost due to local get fail\n"); + } else (*monix->usr_func)( monix->usr_arg, monix->chan, @@ -994,92 +1526,75 @@ int hold; -#ifdef ZEBRA -ca_clear -#ifdef VAXC -(register chid chid) -#else -(chid) -register chid chid; -#endif -{ - - CHIXCHK(chid); - - /* - cancel outstanding events -*/ - -/* - free resources on the IOC -*/ - -/* - free resources here when IOC confirms -*/ - - -# ifdef vxWorks - if(chix->iocix == LOCAL_IIU){ - register int status; - status = db_cancel_event(monix+1); - if(status == ERROR) - return ECA_DBLCLFAIL; - LOCK; - lstDelete(&eventlist, monix); - UNLOCK; - if(free(monix)<0) - return ECA_INTERNAL; - return ECA_NORMAL; - } -# endif - - SNDBEG(extmsg) - - /* msg header */ - mptr->m_cmmd = htons(IOC_EVENT_CANCEL); - mptr->m_available = (long) monix; - mptr->m_postsize = 0; - mptr->m_type = chix->type; - mptr->m_count = chix->count; - mptr->m_paddr = chix->paddr; - - /* NOTE: I free the monitor block only after confirmation from IOC */ - - SNDEND - return ECA_NORMAL; -} -#endif - - + * + * CA_CLEAR_EVENT(MONIX) + * + * Cancel an outstanding event for a channel. + * + * NOTE: returns before operation completes in the server + * (and the client). + * This is a good reason not to allow them to make the monix + * block as part of a larger structure. + * Nevertheless the caller is gauranteed that his specified + * event is disabled and therefore will not run (from this source) + * after leaving this routine. + * + */ ca_clear_event #ifdef VAXC (register evid monix) #else (monix) -register evid monix; +register evid monix; #endif { - register chid chix = monix->chan; /* for SNDBEG */ + register chid chix = monix->chan; /* for SNDBEG */ - CHIXCHK(chix); + LOOSECHIXCHK(chix); + + /* disable any further events from this event block */ + monix->usr_func = NULL; # ifdef vxWorks if(chix->iocix == LOCAL_IIU){ register int status; - status = db_cancel_event(monix+1); - if(status == ERROR) - return ECA_DBLCLFAIL; + + /* + dont allow two threads to delete the same moniitor at once + */ LOCK; - lstDelete(&eventlist, monix); + status = lstFind(&chix->eventq, monix); + if(status != ERROR){ + lstDelete(&chix->eventq, monix); + status = db_cancel_event(monix+1); + } UNLOCK; - if(free(monix)<0) - return ECA_INTERNAL; + if(status == ERROR) + return ECA_BADMONID; + + lstAdd(&dbfree_ev_list, monix); + return ECA_NORMAL; } # endif + /* + dont send the message if the conn is down + (just delete from the queue and return) + + check for conn down while locked to avoid a race + */ + LOCK; + if(!iiu[chix->iocix].conn_up || chix->iocix == BROADCAST_IIU) + lstDelete(&monix->chan->eventq, monix); + UNLOCK; + + if(chix->iocix == BROADCAST_IIU) + return ECA_NORMAL; + if(!iiu[chix->iocix].conn_up) + return ECA_NORMAL; + SNDBEG(extmsg) /* msg header */ @@ -1088,7 +1603,7 @@ register evid monix; mptr->m_postsize = 0; mptr->m_type = chix->type; mptr->m_count = chix->count; - mptr->m_paddr = chix->paddr; + mptr->m_pciu = chix->paddr; /* NOTE: I free the monitor block only after confirmation from IOC */ @@ -1096,61 +1611,163 @@ register evid monix; return ECA_NORMAL; } + +/* + * + * CA_CLEAR_CHANNEL(CHID) + * + * clear the resources allocated for a channel by search + * + * NOTE: returns before operation completes in the server + * (and the client). + * This is a good reason not to allow them to make the monix + * block part of a larger structure. + * Nevertheless the caller is gauranteed that his specified + * event is disabled and therefore will not run + * (from this source) after leaving this routine. + * + */ +ca_clear_channel +#ifdef VAXC +(register chid chix) +#else +(chix) +register chid chix; +#endif +{ + register evid monix; + struct ioc_in_use *piiu = &iiu[chix->iocix]; + LOOSECHIXCHK(chix); + + /* disable their further use of deallocated channel */ + chix->type = TYPENOTINUSE; + + /* the while is only so I can break to the lock exit */ + LOCK; + while(TRUE){ + /* disable any further events from this channel */ + for( monix = (evid) chix->eventq.node.next; + monix; + monix = (evid) monix->node.next) + monix->usr_func = NULL; + /* disable any further get callbacks from this channel */ + for( monix = (evid) pend_read_list.node.next; + monix; + monix = (evid) monix->node.next) + if(monix->chan == chix) + monix->usr_func = NULL; + +# ifdef vxWorks + if(chix->iocix == LOCAL_IIU){ + int status; + + /* + clear out the events for this channel + */ + while(monix = (evid) lstGet(&chix->eventq)){ + status = db_cancel_event(monix+1); + if(status==ERROR) + abort(); + lstAdd(&dbfree_ev_list, monix); + } + + /* + clear out this channel + */ + lstDelete(&local_chidlist, chix); + if(free(chix)<0) + abort(); + + break; /* to unlock exit */ + } +# endif + + /* + dont send the message if the conn is down + (just delete from the queue and return) + + check for conn down while locked to avoid a race + */ + if(!piiu->conn_up || chix->iocix == BROADCAST_IIU){ + lstConcat(&free_event_list, &chix->eventq); + lstDelete(&piiu->chidlist, chix); + if(free(chix)<0) + abort(); + if(chix->iocix != BROADCAST_IIU && !piiu->chidlist.count) + close_ioc(piiu); + } + + if(chix->iocix == BROADCAST_IIU) + break; /* to unlock exit */ + if(!iiu[chix->iocix].conn_up) + break; /* to unlock exit */ + + /* + clear events and all other resources for this chid on the IOC + */ + SNDBEG_NOLOCK(extmsg) + + /* msg header */ + mptr->m_cmmd = htons(IOC_CLEAR_CHANNEL); + mptr->m_available = (int) chix; + mptr->m_type = 0; + mptr->m_count = 0; + mptr->m_pciu = chix->paddr; + mptr->m_postsize = 0; + + /* + NOTE: I free the chid and monitor blocks only after + confirmation from IOC + */ + + SNDEND_NOLOCK + + break; /* to unlock exit */ + } + /* + * message about unexecuted code from SUN's cheaper cc is a compiler + * bug + */ + UNLOCK; + + return ECA_NORMAL; +} /* -NOTE: - This call not implemented with select on VMS or vxWorks - due to its poor implementation in those environments. - - Wallangong's SELECT() does not - return early if a timeout is specified and IO occurs before the end - of the timeout. Above call works because of the short timeout interval. - - Another wallongong bug will cause problems if the timeout in - secs is specified large. I have fixed this by keeping track of - large timeouts myself. - - JH -*/ - -/* NOTE: DELAYVAL must be less than 1.0 */ -#define DELAYVAL 0.150 /* 150 mS */ -#define CASTTMO 0.150 /* 150 mS */ -#define LKUPTMO 0.015 /* 5 mS */ - -#ifdef VMS -#define SYSFREQ 10000000 /* 10 MHz */ -#else -# ifdef vxWorks -# define SYSFREQ sysClkRateGet() /* usually 60 Hz */ -# define time(A) (tickGet()/sysfreq) -# else -# define SYSFREQ 1000000 /* 1 MHz */ -# endif -#endif - -/* -NOTE: -1) Timeout equal to zero blocks indefinately until - all oustanding IO is complete. -2) Timeout other than zero will return with status = ECA_TIMEOUT - when that time period expires and IO is still outstanding. -*/ -ca_pend_io + * NOTE: This call not implemented with select on VMS or vxWorks due to its + * poor implementation in those environments. + * + * Wallangong's SELECT() does not return early if a timeout is specified and IO + * occurs before the end of the timeout. Above call works because of the + * short timeout interval. + * + * Another wallongong bug will cause problems if the timeout in secs is + * specified large. I have fixed this by keeping track of large timeouts + * myself. + * + */ +/************************************************************************/ +/* This routine pends waiting for channel events and calls the */ +/* function specified with add_event when one occurs. If the */ +/* timeout is specified as 0 infinite timeout is assumed. */ +/* if the argument early is specified TRUE then CA_NORMAL is */ +/* returned early (prior to timeout experation) when outstanding */ +/* IO completes. */ +/* ca_flush_io() is called by this routine. */ +/************************************************************************/ #ifdef VAXC -(ca_real timeout) +ca_pend(ca_real timeout, int early) #else -(timeout) +ca_pend(timeout, early) ca_real timeout; +int early; #endif { void send_msg(); time_t beg_time; time_t clock(); - int chidcnt; - int chidstart; # ifdef vxWorks static int sysfreq; @@ -1171,21 +1788,39 @@ ca_real timeout; UNLOCK; if(pndrecvcnt<1) - return ECA_NORMAL; + if(early) + return ECA_NORMAL; - if(timeout<0.0) - return ECA_TIMEOUT; + if(timeoutcur_read_seq++; SND_BEG_NOLOCK(extmsg, piiu) @@ -1253,116 +1883,16 @@ ca_real timeout; } + + + + /* - NOTE: - 1) Timeout of zero causes user process to pend indefinately for - events. - 2) Timeout other than zero specifies a time to pend for events - even if no IO is outstanding. -*/ -ca_pend_event -#ifdef VAXC -(ca_real timeout) -#else -(timeout) -ca_real timeout; -#endif -{ - int status; - void send_msg(); -# ifdef vxWorks - static int sysfreq; - - if(!sysfreq) - sysfreq = SYSFREQ; -# endif - - INITCHK; - - if(post_msg_active) - return ECA_EVDISALLOW; - - if(timeout<0.0) - return ECA_TIMEOUT; - - /* Flush the send buffers */ - LOCK; - send_msg(); - UNLOCK; - -# ifdef vxWorks - { - unsigned int clockticks = timeout * sysfreq; - - if(timeout == 0.0){ - SEMAPHORE sem; - semInit(&sem); - while(TRUE) - semTake(&sem); - } - - taskDelay(clockticks); - - } -# endif - - -# ifdef VMS - { - float mytimeout = timeout; /* conservative */ - - if(timeout == 0.0) - while(TRUE) - sys$hiber(); - - status = lib$wait(&mytimeout); - if(status != SS$_NORMAL) - lib$signal(status); - } -# endif - - -# ifdef UNIX - /* - NOTE: locking here as a comment only in case someone does this on a multi - threaded UNIX. - */ - { - struct timeval itimeout; - unsigned beg_time; - unsigned elapsed; - void recv_msg_select(); - - if(timeout == 0.0) - while(TRUE){ - LOCK; - recv_msg_select(NULL); - UNLOCK; - } - - beg_time = time(NULL); - elapsed = 0; - while(TRUE){ - float delay = timeout-elapsed; - itimeout.tv_usec = (delay- ((int)delay))*SYSFREQ; - itimeout.tv_sec = delay; - LOCK; - recv_msg_select(&itimeout); - UNLOCK; - elapsed = time(NULL)-beg_time; - if(elapsed>timeout) - break; - } - } -# endif - - return ECA_TIMEOUT; -} - - - - + * CA_FLUSH_IO() + * + * + */ ca_flush_io #ifdef VAXC (void) @@ -1382,8 +1912,14 @@ ca_flush_io return ECA_NORMAL; } + - ca_signal(ca_status,message) +/* + * CA_SIGNAL() + * + * + */ +ca_signal(ca_status,message) int ca_status; char *message; { @@ -1419,15 +1955,25 @@ char *message; printf( " Severity: [%s]\n", severity[CA_EXTRACT_SEVERITY(ca_status)]); - - if( !(ca_status & CA_M_SUCCESS) ){ + /* + * + * + * Terminate execution if unsuccessful + * + * + */ + if( !(ca_status & CA_M_SUCCESS) && + CA_EXTRACT_SEVERITY(ca_status) != CA_K_WARNING ){ # ifdef VMS lib$signal(0); # endif # ifdef vxWorks - ti(taskIdCurrent); - tt(taskIdCurrent); + ti(VXTHISTASKID); + tt(VXTHISTASKID); # endif +/*** + abort(ca_status); + ***/ abort(); } @@ -1440,12 +1986,18 @@ char *message; + +/* + * CA_BUSY_MSG() + * + */ ca_busy_message(piiu) register struct ioc_in_use *piiu; { void send_msg(); - SND_BEG(extmsg, piiu) + LOCK; + SND_BEG_NOLOCK(extmsg, piiu) *mptr = nullmsg; mptr->m_cmmd = htons(IOC_EVENTS_OFF); SNDEND_NOLOCK @@ -1454,12 +2006,18 @@ register struct ioc_in_use *piiu; } + +/* + * CA_READY_MSG() + * + */ ca_ready_message(piiu) register struct ioc_in_use *piiu; { void send_msg(); - SND_BEG(extmsg, piiu) + LOCK; + SND_BEG_NOLOCK(extmsg, piiu) *mptr = nullmsg; mptr->m_cmmd = htons(IOC_EVENTS_ON); SNDEND_NOLOCK @@ -1467,3 +2025,79 @@ register struct ioc_in_use *piiu; UNLOCK; } + + +/* + * NOOP_MSG + * (lock must be on) + * + */ +void +noop_msg(piiu) +register struct ioc_in_use *piiu; +{ + SND_BEG_NOLOCK(extmsg, piiu) + *mptr = nullmsg; + mptr->m_cmmd = htons(IOC_NOOP); + SNDEND_NOLOCK +} + + + +/* + * + * Default Exception Handler + * + * + */ +void +ca_default_exception_handler(args) +struct exception_handler_args args; +{ + + /* + NOTE: + I should print additional diagnostic info when time permits...... + */ + + ca_signal(args.stat, args.ctx); +} + + + +/* + * + * call their function with their argument whenever a new fd is added or removed + * (for a manager of the select system call under UNIX) + * + */ +ca_add_fd_registration(func, arg) +void (*func)(); +void *arg; +{ + fd_register_func = func; + fd_register_arg = arg; + + return ECA_NORMAL; +} + + + +/* + * + * call their function with their argument whenever a new fd is added or removed + * (for a manager of the select system call under UNIX) + * + */ +ca_defunct(func, arg) +void (*func)(); +void *arg; +{ +#ifdef VMS + SEVCHK(ECA_DEFUNCT, "you must have a VMS share image mismatch\n"); +#else + SEVCHK(ECA_DEFUNCT, NULL); +#endif +} + + diff --git a/src/ca/acctst.c b/src/ca/acctst.c index ed084780d..3838b9bd7 100644 --- a/src/ca/acctst.c +++ b/src/ca/acctst.c @@ -11,15 +11,18 @@ #endif #include -#include #include /* #define CA_TEST_CHNL "AI_T2000" */ -#define CA_TEST_CHNL "AI_T2000.DESC" -#define CA_TEST_CHNL4 "AI_DOGGY" +#define CA_TEST_CHNL "ca:ai_2000" +#define CA_TEST_CHNL4 "ca:ai_2000" +#define EVENT_ROUTINE null_event +/* +#define EVENT_ROUTINE ca_test_event +*/ #define NUM 1 @@ -60,6 +63,7 @@ main() struct dbr_ctrl_float *pctrl; char pstring[NUM][MAX_STRING_SIZE]; void write_event(); + void conn(); SEVCHK(ca_task_initialize(),"Unable to initialize"); @@ -71,7 +75,9 @@ main() ptr = (struct dbr_gr_float *) malloc(dbr_size[DBR_GR_FLOAT] + dbr_value_size[DBR_GR_FLOAT]*(NUM-1)); - for(i=0;i<2;i++){ + + for(i=0; i<0; i++){ + status = ca_array_build( CA_TEST_CHNL, /* channel ASCII name */ DBR_GR_FLOAT, /* fetch external type */ NUM, /* array element cnt */ @@ -79,16 +85,79 @@ main() ptr /* pointer to recv buf */ ); SEVCHK(status, NULL); + + SEVCHK(ca_build_and_connect( + CA_TEST_CHNL4, + TYPENOTCONN, + 0, + &chix4, + NULL, + conn, + NULL),NULL); + SEVCHK(ca_build_and_connect( + CA_TEST_CHNL, + TYPENOTCONN, + 0, + &chix2, + NULL, + conn, + NULL),NULL); + SEVCHK(ca_build_and_connect( + CA_TEST_CHNL, + TYPENOTCONN, + 0, + &chix1, + NULL, + conn, + NULL),NULL); + status = ca_pend_io(10.0); + SEVCHK(status,NULL); + + SEVCHK(ca_clear_channel(chix4),NULL); + SEVCHK(ca_clear_channel(chix2),NULL); + SEVCHK(ca_clear_channel(chix3),NULL); + SEVCHK(ca_clear_channel(chix1),NULL); + + free(ptr); } - SEVCHK(ca_search(CA_TEST_CHNL4,&chix4),NULL); - SEVCHK(ca_search(CA_TEST_CHNL,&chix2),NULL); + status = ca_array_build( + CA_TEST_CHNL, /* channel ASCII name */ + DBR_GR_FLOAT, /* fetch external type */ + NUM, /* array element cnt */ + &chix3, /* ptr to chid */ + ptr /* pointer to recv buf */ + ); + SEVCHK(status, NULL); - for(i=0;i<1;i++) - SEVCHK(ca_search(CA_TEST_CHNL,&chix1),NULL); + SEVCHK(ca_build_and_connect( + CA_TEST_CHNL4, + TYPENOTCONN, + 0, + &chix4, + NULL, + conn, + NULL),NULL); + SEVCHK(ca_build_and_connect( + CA_TEST_CHNL, + TYPENOTCONN, + 0, + &chix2, + NULL, + conn, + NULL),NULL); + SEVCHK(ca_build_and_connect( + CA_TEST_CHNL, + TYPENOTCONN, + 0, + &chix1, + NULL, + conn, + NULL),NULL); status = ca_pend_io(1.0); + SEVCHK(status,NULL); if(INVALID_DB_REQ(chix1->type)) printf("Failed to locate %s\n",CA_TEST_CHNL); @@ -116,20 +185,26 @@ main() lib$init_timer(); # endif + if(VALID_DB_REQ(chix4->type)){ - ca_add_event(DBR_FLOAT, chix4, ca_test_event, 0xaaaaaaaa, &monix); - ca_clear_event(monix); + status = ca_add_event(DBR_FLOAT, chix4, EVENT_ROUTINE, 0xaaaaaaaa, &monix); + SEVCHK(status,NULL); + SEVCHK(ca_clear_event(monix),NULL); } if(VALID_DB_REQ(chix4->type)){ - ca_add_event(DBR_FLOAT, chix4, ca_test_event, 0xaaaaaaaa, &monix); - ca_clear_event(monix); + status = ca_add_event(DBR_FLOAT, chix4, EVENT_ROUTINE, 0xaaaaaaaa, &monix); + SEVCHK(status,NULL); + SEVCHK(ca_clear_event(monix),NULL); } if(VALID_DB_REQ(chix3->type)){ - ca_add_event(DBR_FLOAT, chix3, ca_test_event, 0xaaaaaaaa, &monix); - ca_add_event(DBR_FLOAT, chix3, write_event, 0xaaaaaaaa, &monix); + status = ca_add_event(DBR_FLOAT, chix3, EVENT_ROUTINE, 0xaaaaaaaa, &monix); + SEVCHK(status,NULL); + status = ca_add_event(DBR_FLOAT, chix3, write_event, 0xaaaaaaaa, &monix); + SEVCHK(status,NULL); } + pfloat = (float *) malloc(sizeof(float)*NUM); @@ -144,7 +219,7 @@ main() else abort(); - ca_pend_io(4.0); + SEVCHK(ca_pend_io(4.0),NULL); # ifdef VMS lib$show_timer(); @@ -152,14 +227,20 @@ main() for(i=0;i100){ + printf("100 occured\n"); + i = 0; + } } @@ -181,5 +267,23 @@ struct event_handler_args args; SEVCHK(ca_rput(args.chid, &a),"write fail in event"); SEVCHK(ca_flush_io(),NULL); +/* +#ifdef vxWorks +taskDelay(20); +#endif +*/ + +} + +void conn(args) +struct connection_handler_args args; +{ + + if(args.op == CA_OP_CONN_UP) + printf("Channel On Line [%s]\n", ca_name(args.chid)); + else if(args.op == CA_OP_CONN_DOWN) + printf("Channel Off Line [%s]\n", ca_name(args.chid)); + else + printf("Ukn conn ev\n"); } diff --git a/src/ca/conn.c b/src/ca/conn.c index ff221d82e..7d554bb11 100644 --- a/src/ca/conn.c +++ b/src/ca/conn.c @@ -2,7 +2,7 @@ /* */ /* L O S A L A M O S */ /* Los Alamos National Laboratory */ -/* Los Alamos, New Mexico 87545 */ +/* Los Alamos, New Mexico 87545 */ /* */ /* Copyright, 1986, The Regents of the University of California. */ /* */ @@ -18,7 +18,7 @@ /************************************************************************/ /* */ /* Title: IOC connection automation */ -/* File: atcs:[ca]access.c */ +/* File: atcs:[ca]conn.c */ /* Environment: VMS, UNIX, VRTX */ /* Equipment: VAX, SUN, VME */ /* */ @@ -26,6 +26,9 @@ /* */ /************************************************************************/ /*_end */ +#ifdef UNIX +#include +#endif #include #include @@ -34,54 +37,127 @@ #include +/* + * + * CHID_RETRY + * + * retry disconnected channels + * + * + * NOTES: + * Lock must be applied while in this routine + */ chid_retry(silent) char silent; { - register chid chix; - register unsigned int retry_cnt = 0; - char string[100]; - void send_msg(); + register chid chix; + register unsigned int retry_cnt = 0; + unsigned int retry_cnt_no_handler = 0; + char string[100]; + int i; + int search_type; - if(!chidlist_pend.count) - return ECA_NORMAL; + /* + * CASTTMO+pndrecvcnt*LKUPTMO)/DELAYVAL + 1 + */ +#define CASTTMO 0.150 /* 150 mS */ +#define LKUPTMO 0.015 /* 15 mS */ - LOCK; - chix = (chid) &chidlist_pend; - while(chix = (chid) chix->node.next){ - build_msg(chix,TRUE); - retry_cnt++; - if(!silent) - ca_signal(ECA_CHIDNOTFND, chix+1); - } - send_msg(); - printf("Sent "); - UNLOCK; + for(i=0; i< nxtiiu; i++){ + if(i != BROADCAST_IIU && iiu[i].conn_up) + continue; - if(retry_cnt && !silent){ - sprintf(string, "%d channels outstanding", retry_cnt); - ca_signal(ECA_CHIDRETRY, string); - } + if(iiu[i].nconn_tries++ > MAXCONNTRIES) + continue; - return ECA_NORMAL; + search_type = (i==BROADCAST_IIU? DONTREPLY: DOREPLY); + + chix = (chid) &iiu[i].chidlist; + while(chix = (chid) chix->node.next){ + if(chix->type != TYPENOTCONN) + continue; + build_msg(chix,search_type); + retry_cnt++; + + if(!(silent || chix->connection_func)){ + ca_signal(ECA_CHIDNOTFND, chix+1); + retry_cnt_no_handler++; + } + } + } + + if(retry_cnt){ + send_msg(); + printf(" "); +#ifdef UNIX + fflush(stdout); +#endif + + if(!silent && retry_cnt_no_handler){ + sprintf(string, "%d channels outstanding", retry_cnt); + ca_signal(ECA_CHIDRETRY, string); + } + } + + return ECA_NORMAL; } + + /* -Locks must be applied while in this routine -*/ -mark_chids_disconnected(iocix) -register unsigned iocix; + * + * + * MARK_SERVER_AVAILABLE + * + * + * NOTES: + * Lock must be applied while in this routine + * + */ +void +mark_server_available(net_addr) +struct in_addr net_addr; { - register chid chix; - register chid nextchix; + int i; + void noop_msg(); - nextchix = (chid) &chidlist_conn.node; - while(chix = nextchix){ - nextchix = (chid) chix->node.next; - if(chix->iocix == iocix){ - lstDelete(&chidlist_conn, chix); - lstAdd(&chidlist_pend, chix); - chix->type = TYPENOTCONN; - } - } + for(i=0;i #include @@ -7,6 +37,219 @@ #endif +/* + * Routine we will do later + * + * + * + */ +no_cvrt() +{ + printf("Sorry, conversion for that type currently not implemented\n"); + exit(); +} +cvrt_sts_char() {no_cvrt();} +cvrt_sts_long() {no_cvrt();} +cvrt_sts_double() {no_cvrt();} + +cvrt_time_string() {no_cvrt();} +cvrt_time_short() {no_cvrt();} +cvrt_time_float() {no_cvrt();} +cvrt_time_enum() {no_cvrt();} +cvrt_time_char() {no_cvrt();} +cvrt_time_long() {no_cvrt();} +cvrt_time_double() {no_cvrt();} + +cvrt_gr_char() {no_cvrt();} +cvrt_gr_double() {no_cvrt();} +cvrt_gr_long() {no_cvrt();} +cvrt_gr_string() {no_cvrt();} +cvrt_gr_enum() {no_cvrt();} + +cvrt_ctrl_char() {no_cvrt();} +cvrt_ctrl_long() {no_cvrt();} +cvrt_ctrl_string() {no_cvrt();} +cvrt_ctrl_double() {no_cvrt();} + + + + + +/* + * CVRT_SHORT() + * + * + * + * + */ +cvrt_short(s,d,encode,num) +short *s; /* source */ +short *d; /* destination */ +int encode; /* cvrt VAX to IEEE if T */ +int num; /* number of values */ +{ + unsigned int i; + + for(i=0; i #include @@ -56,21 +54,21 @@ #include #include #include +#include #include #include #include #include #include -/* For older versions of berkley UNIX types.h and vxWorks types.h */ -/* 64 times sizeof(fd_mask) is the maximum channels on a vax JH */ -/* Yuk - can a maximum channel be determined at run time ? */ /* + * used to be that some TCP/IPs did not include this + */ +#ifdef JUNKYARD typedef long fd_mask; typedef struct fd_set { fd_mask fds_bits[64]; } fd_set; -*/ #ifndef NBBY # define NBBY 8 /* number of bits per byte */ @@ -92,55 +90,22 @@ typedef struct fd_set { #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #endif -/* my version is faster since it is in line */ +/* my version is faster since it is in line */ #define FD_ZERO(p)\ {\ register int i;\ for(i=0;ifds_bits);i++)\ (p)->fds_bits[i]=0;\ } - - -/* 50 mS delay for TCP to finish transmitting */ -/* select wakes you if message is only partly here */ -/* so this wait free's up the processor until it completely arrives */ -#define DELAYVAL 0.050 /* 50 mS */ - -#ifdef VMS -# define SYSFREQ 10000000 /* 10 MHz */ -# define TCPDELAY\ -{float delay = DELAYVAL; static int ef=NULL;\ - int status; int systim[2]={-SYSFREQ*DELAYVAL,~0};\ - if(!ef)ef= lib$get_ef(&ef);\ - status = sys$setimr(ef,systim,NULL,MYTIMERID,NULL);\ - if(~status&STS$M_SUCCESS)lib$signal(status);\ - status = sys$waitfr(ef);\ - if(~status&STS$M_SUCCESS)lib$signal(status);\ -}; #endif -#ifdef vxWorks -/* -############### -insert sysClkRateGet() here ??? -slows it down but works on all systems ?? -############### -*/ -# define SYSFREQ 60 /* 60 Hz */ -# define TCPDELAY taskDelay((unsigned int)DELAYVAL*SYSFREQ); -#endif - -#ifdef UNIX -# define SYSFREQ 1000000 /* 1 MHz */ -/* -# define TCPDELAY if(usleep((unsigned int)DELAYVAL*SYSFREQ))abort(); -*/ -# define TCPDELAY {if(select(0,NULL,NULL,NULL,&tcpdelayval)<0)abort();} -static struct timeval tcpdelayval = {0,(unsigned int)DELAYVAL*SYSFREQ}; -#endif static struct timeval notimeout = {0,0}; +void close_ioc(); + + /* LOCK should be on while in this routine */ @@ -151,50 +116,74 @@ unsigned short *iocix; { int i; int status; - int sock; - int true = TRUE; - struct sockaddr_in src; - struct sockaddr_in *local_addr(); - struct ioc_in_use *piiu; - /**********************************************************************/ /* IOC allready allocated ? */ /**********************************************************************/ for(i=0;i=MAXIIU) return ECA_MAXIOC; - piiu = &iiu[nxtiiu]; + /* set network address block */ + iiu[nxtiiu].sock_addr.sin_addr = net_addr; + iiu[nxtiiu].sock_proto = net_proto; + status = create_net_chan(&iiu[nxtiiu]); + if(status != ECA_NORMAL) + return status; - /* set network address block */ - piiu->sock_addr.sin_addr = net_addr; - - /* set socket domain */ + *iocix = nxtiiu++; + + return ECA_NORMAL; + +} + + + +/**********************************************************************/ +/* allocate and initialize an IOC info block for unallocated IOC */ +/**********************************************************************/ +/* + LOCK should be on while in this routine +*/ +create_net_chan(piiu) +struct ioc_in_use *piiu; +{ + int status; + int sock; + int true = TRUE; + struct sockaddr_in saddr; + int i; + + struct sockaddr_in *local_addr(); + + + /* set socket domain */ piiu->sock_addr.sin_family = AF_INET; - piiu->sock_proto = net_proto; + /* set the port */ + piiu->sock_addr.sin_port = htons(CA_SERVER_PORT); - - switch(net_proto) + switch(piiu->sock_proto) { case IPPROTO_TCP: - /* set the port */ - piiu->sock_addr.sin_port = htons(SERVER_NUM); - /* allocate a socket */ + /* allocate a socket */ sock = socket( AF_INET, /* domain */ SOCK_STREAM, /* type */ 0); /* deflt proto */ @@ -203,9 +192,59 @@ unsigned short *iocix; piiu->sock_chan = sock; + /* + see TCP(4P) this seems to make unsollicited single + events much faster. I take care of queue up as load + increases. + */ + status = setsockopt( sock, + IPPROTO_TCP, + TCP_NODELAY, + &true, + sizeof true); + if(status < 0){ + socket_close(sock); + return ECA_ALLOCMEM; + } + +#ifdef KEEPALIVE + /* + This should cause the connection to be checked periodically + and an error to be returned if it is lost. + + In practice it is not much use since the conn is checked very + infrequently. + */ + status = setsockopt( sock, + SOL_SOCKET, + SO_KEEPALIVE, + &true, + sizeof true); + if(status < 0){ + socket_close(sock); + return ECA_ALLOCMEM; + } +#endif + +#ifdef JUNKYARD +{ +struct linger linger; +int linger_size = sizeof linger; + status = getsockopt( sock, + SOL_SOCKET, + SO_LINGER, + &linger, + &linger_size); + if(status < 0){ + abort(); + } +printf("linger was on:%d linger:%d\n", linger.l_onoff, linger.l_linger); +} +#endif + /* set TCP buffer sizes only if BSD 4.3 sockets */ /* temporarily turned off */ -# ifdef ZEBRA +# ifdef JUNKYARD i = (MAX_MSG_SIZE+sizeof(int)) * 2; status = setsockopt( sock, @@ -213,7 +252,7 @@ unsigned short *iocix; SO_SNDBUF, &i, sizeof(i)); - if(status == -1){ + if(status < 0){ socket_close(sock); return ECA_ALLOCMEM; } @@ -222,49 +261,55 @@ unsigned short *iocix; SO_RCVBUF, &i, sizeof(i)); - if(status == -1){ + if(status < 0){ socket_close(sock); return ECA_ALLOCMEM; } # endif - piiu->max_msg = MAX_TCP; /* connect */ status = connect( sock, - &iiu[nxtiiu].sock_addr, - sizeof(iiu[nxtiiu].sock_addr)); - if(status == -1){ + &piiu->sock_addr, + sizeof(piiu->sock_addr)); + if(status < 0){ + printf("no conn errno %d\n", MYERRNO); socket_close(sock); return ECA_CONN; } + piiu->max_msg = MAX_TCP; + /* place the broadcast addr/port in the stream so the ioc will know where this is coming from. */ - i = sizeof(src); + i = sizeof(saddr); status = getsockname( iiu[BROADCAST_IIU].sock_chan, - &src, + &saddr, &i); if(status == ERROR){ printf("alloc_ioc: cant get my name %d\n",MYERRNO); abort(); } - src.sin_addr.s_addr = + saddr.sin_addr.s_addr = (local_addr(iiu[BROADCAST_IIU].sock_chan))->sin_addr.s_addr; status = send( piiu->sock_chan, - &src, - sizeof(src), + &saddr, + sizeof(saddr), 0); + /* Set non blocking IO for UNIX to prevent dead locks */ +# ifdef UNIX + status = socket_ioctl( piiu->sock_chan, + FIONBIO, + &true); +# endif + break; case IPPROTO_UDP: - /* set the port */ - piiu->sock_addr.sin_port = htons(SERVER_NUM); - /* allocate a socket */ sock = socket( AF_INET, /* domain */ SOCK_DGRAM, /* type */ @@ -274,7 +319,6 @@ unsigned short *iocix; piiu->sock_chan = sock; - /* The following only needed on BSD 4.3 machines */ @@ -285,44 +329,43 @@ unsigned short *iocix; return ECA_CONN; } + memset(&saddr,0,sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* let slib pick lcl addr */ + saddr.sin_port = htons(0); - memset(&src,0,sizeof(src)); - src.sin_family = AF_INET; - src.sin_addr.s_addr = INADDR_ANY; /* let TCP pick lcl addr */ - src.sin_port = 0; /* let TCP pick lcl port */ - - status = bind(sock, &src, sizeof(src)); + status = bind(sock, &saddr, sizeof(saddr)); if(status<0){ printf("%d\n",MYERRNO); - SEVCHK(ECA_INTERNAL,"bind failed"); + ca_signal(ECA_INTERNAL,"bind failed"); } - piiu->max_msg = MAX_UDP - sizeof(iiu[nxtiiu].send->stk); + piiu->max_msg = MAX_UDP - sizeof(piiu->send->stk); break; + default: - printf("alloc_ioc: ukn protocol\n"); - abort(); + ca_signal(ECA_INTERNAL,"alloc_ioc: ukn protocol\n"); } - - /* Set non blocking IO for UNIX to prevent dead locks */ -# ifdef UNIX - status = socket_ioctl( piiu->sock_chan, - FIONBIO, - &true); -# endif - /* setup send_msg(), recv_msg() buffers */ - if(! (piiu->send = (struct buffer *) malloc(sizeof(struct buffer))) ){ - socket_close(sock); - return ECA_ALLOCMEM; - } + if(!piiu->send) + if(! (piiu->send = (struct buffer *) malloc(sizeof(struct buffer))) ){ + socket_close(sock); + return ECA_ALLOCMEM; + } piiu->send->stk = 0; - if(! (piiu->recv = (struct buffer *) malloc(sizeof(struct buffer))) ){ - socket_close(sock); - return ECA_ALLOCMEM; - } + + if(!piiu->recv) + if(! (piiu->recv = (struct buffer *) malloc(sizeof(struct buffer))) ){ + socket_close(sock); + return ECA_ALLOCMEM; + } + piiu->recv->stk = 0; + piiu->conn_up = TRUE; + if(fd_register_func) + (*fd_register_func)(fd_register_arg, sock, TRUE); + /* Set up recv thread for VMS */ # ifdef VMS @@ -333,7 +376,7 @@ unsigned short *iocix; IO$_RECEIVE, &piiu->iosb, recv_msg_ast, - nxtiiu, + piiu, piiu->recv->buf, sizeof(piiu->recv->buf), NULL, @@ -345,108 +388,180 @@ unsigned short *iocix; exit(); } } -# else -# ifdef vxWorks - { +# endif +# ifdef vxWorks + { void recv_task(); int pri; char name[15]; status == taskPriorityGet(VXTASKIDSELF, &pri); if(status<0) - SEVCHK(ECA_INTERNAL,NULL); + ca_signal(ECA_INTERNAL,NULL); - name[0]=NULL; - strncat(name,"RD ", sizeof(name)-1); - strncat(name, taskName(VXTHISTASKID), sizeof(name)-1); + strcpy(name,"RD "); + strncat(name, taskName(VXTHISTASKID), sizeof(name)-strlen(name)-1); status = taskSpawn( name, pri-1, VX_FP_TASK, 4096, recv_task, - (unsigned) nxtiiu, + piiu, taskIdSelf()); if(status<0) - SEVCHK(ECA_INTERNAL,NULL); + ca_signal(ECA_INTERNAL,NULL); - iiu[nxtiiu].recv_tid = status; + piiu->recv_tid = status; - } -# endif + } # endif - *iocix = nxtiiu++; +/* + testing testing +*/ +#ifdef ZEBRA /* vw does not have getsockopt */ +{ +int timeo; +int timeolen = sizeof(timeo); + + status = getsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,&timeo,&timeolen); + if(status<0){ + printf("%d\n",MYERRNO); + } +if(timeolen != sizeof(timeo)) +printf("bomb\n"); + +printf("send %d\n",timeo); + status = getsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&timeo,&timeolen); + if(status<0){ + printf("%d\n",MYERRNO); + } +if(timeolen != sizeof(timeo)) +printf("bomb\n"); + +printf("recv %d\n",timeo); +} +#endif + + return ECA_NORMAL; } - + /* - NOTE: Wallangong select cant be called in an AST with a timeout - since they use timer ASTs to implement thier timeout. + * NOTIFY_CA_REPEATER + * tell the cast repeater that another client has come on line + * + * NOTES: + * 1) local communication only (no LAN traffic) + * + */ +notify_ca_repeater() +{ + struct sockaddr_in saddr; + int status; + struct sockaddr_in *local_addr(); - NOTE: Wallangong select does not return early if IO is present prior - to the timeout expiring. + if(!iiu[BROADCAST_IIU].conn_up) + return; - LOCK should be on while in this routine -*/ + saddr = *( local_addr(iiu[BROADCAST_IIU].sock_chan) ); + saddr.sin_port = htons(CA_CLIENT_PORT); + status = sendto( + iiu[BROADCAST_IIU].sock_chan, + NULL, + 0, /* zero length message */ + 0, + &saddr, + sizeof saddr); + if(status < 0) + abort(); +} + + +/* + * SEND_MSG + * + * NOTE: Wallangong select cant be called in an AST with a timeout since they + * use timer ASTs to implement thier timeout. + * + * NOTE: Wallangong select does not return early if IO is present prior to the + * timeout expiring. + * + * LOCK should be on while in this routine + */ void send_msg() { - unsigned cnt; - void *pmsg; - unsigned iocix; - int status; + unsigned cnt; + void *pmsg; + int status; + register struct ioc_in_use *piiu; /**********************************************************************/ /* Note: this routine must not be called at AST level */ /**********************************************************************/ - for(iocix=0;iocixstk){ + if(!ca_static->ca_repeater_contacted) + notify_ca_repeater(); - /* don't allow UDP recieve messages to que up under UNIX */ -# ifdef UNIX - { - void recv_msg_select(); + + /* don't allow UDP recieve messages to que up under UNIX */ +# ifdef UNIX + { + void recv_msg_select(); /* test for recieve allready in progress and NOOP if so */ if(!post_msg_active) - recv_msg_select(¬imeout); - } -# endif + recv_msg_select(¬imeout); + } +# endif - cnt = iiu[iocix].send->stk + sizeof(iiu[iocix].send->stk); - iiu[iocix].send->stk = htonl(cnt); /* convert for 68000 */ - pmsg = iiu[iocix].send; /* byte cnt then buf */ + for(piiu=iiu;piiu<&iiu[nxtiiu];piiu++) + if(piiu->send->stk){ + + + cnt = piiu->send->stk + sizeof(piiu->send->stk); + piiu->send->stk = htonl(cnt); /* convert for 68000 */ + pmsg = piiu->send; /* byte cnt then buf */ while(TRUE){ - status = sendto( iiu[iocix].sock_chan, + if(piiu->conn_up){ + status = sendto( piiu->sock_chan, pmsg, cnt, 0, - &iiu[iocix].sock_addr, - sizeof(iiu[iocix].sock_addr)); + &piiu->sock_addr, + sizeof(piiu->sock_addr)); + } + else{ + /* send a directed UDP message (for search retries) */ + status = sendto( iiu[BROADCAST_IIU].sock_chan, + pmsg, + cnt, + 0, + &piiu->sock_addr, + sizeof(piiu->sock_addr)); + } if(status == cnt) break; if(status>=0){ if(status>cnt) - SEVCHK(ECA_INTERNAL,"more sent than requested"); + ca_signal(ECA_INTERNAL,"more sent than requested"); cnt = cnt-status; pmsg = (void *) (status+(char *)pmsg); } else if(MYERRNO == EWOULDBLOCK){ } - else{ - if(MYERRNO != EPIPE){ - printf("send_msg(): unexpected error on socket send() %d\n",MYERRNO); - } - SEVCHK(ECA_DISCONN, host_from_addr(iiu[iocix].sock_addr.sin_addr)) - mark_chids_disconnected(iocix); + else{ + if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) + printf("send_msg(): error on socket send() %d\n",MYERRNO); + close_ioc(piiu); break; - } + } /* Ensure we do not accumulate extra recv messages (for TCP) @@ -461,88 +576,100 @@ send_msg() } /* reset send stack */ - iiu[iocix].send->stk = 0; + piiu->send->stk = 0; } } - + /* - Recieve incomming messages - 1) Wait no longer than timeout - 2) Return early if nothing outstanding - -*/ + * RECV_MSG_SELECT() + * + * Asynch notification of incomming messages under UNIX + * 1) Wait no longer than timeout + * 2) Return early if nothing outstanding + * + */ #ifdef UNIX void recv_msg_select(ptimeout) -struct timeval *ptimeout; +struct timeval *ptimeout; { - unsigned iocix; - long status; - void recv_msg(); + long status; + register struct ioc_in_use *piiu; + struct timeval *ptmptimeout; + void recv_msg(); - for(iocix=0; iocixconn_up){ + FD_SET(piiu->sock_chan,&readch); + } - while(status > 0){ + status = select( + sizeof(fd_set)*NBBY, + &readch, + NULL, + NULL, + ptmptimeout); - for(iocix=0; iocixconn_up) + if(FD_ISSET(piiu->sock_chan,&readch) ) + recv_msg(piiu); - status = select( sizeof(fd_set)*NBBY, - &readch, - NULL, - NULL, - ¬imeout); - } + /* + * double check to make sure that nothing is left pending + */ + ptmptimeout = ¬imeout; + } - if(status<0){ - if(MYERRNO == EINTR) - return; - else{ - char text[255]; - sprintf(text,"Error Returned From Select: %d",MYERRNO); - SEVCHK(ECA_INTERNAL,text); - } - } - - return; } #endif void -recv_msg(iocix) -unsigned iocix; +recv_msg(piiu) +struct ioc_in_use *piiu; { - struct ioc_in_use *piiu = &iiu[iocix]; void tcp_recv_msg(); void udp_recv_msg(); switch(piiu->sock_proto){ case IPPROTO_TCP: - tcp_recv_msg(iocix); + + /* #### remove this statement after debug is complete #### */ + if(!piiu->conn_up) + ca_signal(ECA_INTERNAL,"TCP burp at conn close\n"); + + tcp_recv_msg(piiu); flow_control(piiu); + break; case IPPROTO_UDP: - udp_recv_msg(iocix); + udp_recv_msg(piiu); break; default: @@ -556,100 +683,120 @@ unsigned iocix; void -tcp_recv_msg(iocix) -unsigned iocix; +tcp_recv_msg(piiu) +struct ioc_in_use *piiu; { - struct ioc_in_use *piiu = &iiu[iocix]; - unsigned long byte_cnt; - unsigned long byte_sum; - int status; - int timeoutcnt; - struct buffer *rcvb = piiu->recv; - int sock = piiu->sock_chan; + unsigned long byte_cnt; + unsigned long byte_sum; + int status; + int timeoutcnt; + struct buffer *rcvb = piiu->recv; + int sock = piiu->sock_chan; - while(TRUE){ - status = recv( sock, + status = recv( sock, &rcvb->stk, sizeof(rcvb->stk), 0); - if(status == sizeof(rcvb->stk)) - break; - if( status > 0) - SEVCHK(ECA_INTERNAL,"partial recv on request of only 4 bytes"); + if(status != sizeof(rcvb->stk)){ - if( status < 0){ - if(MYERRNO != EWOULDBLOCK){ - if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) - printf("unexpected recv error 1 = %d\n",MYERRNO); + if( status > 0) + ca_signal( + ECA_INTERNAL, + "partial recv on request of only 4 bytes\n"); + else if(status == 0){ + printf("CA: recv of zero length?\n"); + LOCK; + close_ioc(piiu); + UNLOCK; + return; + } + else{ + /* try again on status of 0 or -1 and EWOULDBLOCK */ + if(MYERRNO == EWOULDBLOCK) + return; - SEVCHK(ECA_DISCONN, host_from_addr(piiu->sock_addr.sin_addr)); - mark_chids_disconnected(iocix); - return; - } - } + if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) + printf( "unexpected recv error 1 = %d %d\n", + MYERRNO, + status); - /* try again on status of 0 or -1 and EWOULDBLOCK */ - TCPDELAY; - } + LOCK; + close_ioc(piiu); + UNLOCK; + return; + } + } - /* switch from 68000 to VAX byte order */ - byte_cnt = (unsigned long) ntohl(rcvb->stk) - sizeof(rcvb->stk); - if(byte_cnt>MAX_MSG_SIZE){ - printf("recv_msg(): message overflow %u\n",byte_cnt-MAX_MSG_SIZE); - return; - } + /* switch from 68000 to VAX byte order */ + byte_cnt = (unsigned long) ntohl(rcvb->stk) - sizeof(rcvb->stk); + if(byte_cnt>MAX_MSG_SIZE){ + printf( "recv_msg(): message overflow %u\n", + byte_cnt-MAX_MSG_SIZE); + LOCK; + close_ioc(piiu); + UNLOCK; + return; + } - timeoutcnt = byte_cnt + 3000; - for(byte_sum = 0; byte_sum < byte_cnt; byte_sum += status){ + timeoutcnt = byte_cnt + 3000; + byte_sum = 0; + while(TRUE){ -# ifdef DEBUG - if(byte_sum) - printf( "recv_msg(): Warning- reading %d leftover bytes \n", - byte_cnt-byte_sum); -# endif +# ifdef DEBUG + if(byte_sum) + printf( "recv_msg(): Warning- %d leftover bytes \n", + byte_cnt-byte_sum); +# endif - status = recv( sock, + status = recv( sock, &rcvb->buf[byte_sum], byte_cnt - byte_sum, 0); - if(status < 0){ - if(MYERRNO != EWOULDBLOCK){ - if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) - printf("unexpected recv error 2 = %d\n",MYERRNO); + if(status < 0){ + if(MYERRNO != EWOULDBLOCK){ + if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) + printf("recv error 2 = %d\n",MYERRNO); - SEVCHK(ECA_DISCONN, host_from_addr(piiu->sock_addr.sin_addr)); - mark_chids_disconnected(iocix); - return; - } + LOCK; + close_ioc(piiu); + UNLOCK; + return; + } - status = 0; - if(--timeoutcnt < 0){ - printf("recv_msg(): TCP message bdy wait timed out\n"); - abort(); - } - } + if(--timeoutcnt < 0){ + printf("recv_msg(): message bdy wait tmo\n"); + LOCK; + close_ioc(piiu); + UNLOCK; + abort(); + } + } + else{ + byte_sum += status; + if(byte_sum >= byte_cnt) + break; + } - /* wait for TCP/IP to complete the message transfer */ - TCPDELAY; - } + /* wait for TCP/IP to complete the message transfer */ + TCPDELAY; + } - /* post message to the user */ - post_msg(rcvb->buf, byte_cnt, piiu->sock_addr.sin_addr, piiu); + /* post message to the user */ + post_msg(rcvb->buf, byte_cnt, piiu->sock_addr.sin_addr, piiu); - return; + return; } void -udp_recv_msg(iocix) -unsigned iocix; +udp_recv_msg(piiu) +struct ioc_in_use *piiu; { - struct ioc_in_use *piiu = &iiu[iocix]; unsigned long byte_cnt; int status; struct buffer *rcvb = piiu->recv; @@ -674,7 +821,7 @@ unsigned iocix; /* op would block which is ok to ignore till ready later */ if(MYERRNO == EWOULDBLOCK) break; - SEVCHK(ECA_INTERNAL,"unexpected udp recv error"); + ca_signal(ECA_INTERNAL,"unexpected udp recv error"); } /* switch from 68000 to VAX byte order */ @@ -683,9 +830,9 @@ unsigned iocix; printf("recieved a udp reply of %d bytes\n",byte_cnt); # endif if(byte_cnt != status){ - printf("recv_cast(): corrupt broadcast reply %d\n",MYERRNO); + printf("recv_cast(): corrupt UDP recv %d\n",MYERRNO); printf("recv_cast(): header %d actual %d\n",byte_cnt,status); - break; + return; } rcvb->stk += byte_cnt; @@ -702,7 +849,7 @@ unsigned iocix; FIONREAD, &nchars); if(status<0) - SEVCHK(ECA_INTERNAL,"unexpected udp ioctl err\n"); + ca_signal(ECA_INTERNAL,"unexpected udp ioctl err\n"); }while(nchars); @@ -726,8 +873,8 @@ unsigned iocix; #ifdef vxWorks void -recv_task(iocix,moms_tid) -unsigned iocix; +recv_task(piiu, moms_tid) +struct ioc_in_use *piiu; int moms_tid; { int status; @@ -740,118 +887,269 @@ int moms_tid; if(ca_static == (struct ca_static*)ERROR) abort(); - while(TRUE) - recv_msg(iocix); + while(piiu->conn_up) + recv_msg(piiu); + + /* + Exit recv task + + NOTE on vxWorks I dont want the global channel access + exit handler to run for this pod of tasks when the recv + task exits so I delete the task variable here. + The CA exit handler ignores tasks with out the ca task + var defined. + */ + + status = taskVarDelete(VXTHISTASKID, &ca_static); + if(status == ERROR) + abort(); + + exit(); } #endif + +/* + * + * RECV_MSG_AST() + * + * + */ #ifdef VMS void -recv_msg_ast(iocix) -int iocix; +recv_msg_ast(piiu) +struct ioc_in_use *piiu; { - struct ioc_in_use *piiu = &iiu[iocix]; - short io_status = piiu->iosb.status; - int io_count = piiu->iosb.count; - struct sockaddr_in *paddr; - char *pbuf; - unsigned int *pcount= (unsigned int *) piiu->recv->buf; - int bufsize; + short io_status = piiu->iosb.status; + int io_count = piiu->iosb.count; + struct sockaddr_in *paddr; + char *pbuf; + unsigned int *pcount= (unsigned int *) piiu->recv->buf; + int bufsize; + unsigned long byte_cnt; - unsigned long byte_cnt; - - if(io_status != SS$_NORMAL){ - if(io_status == SS$_CANCEL) - return; - lib$signal(io_status); - } - else{ - /* - NOTE: The following is a bug fix since WIN has returned - the address structure missaligned by 16 bits - - the fix is reliable since this structure happens - to be padded with zeros at the end by more than 16 bits - */ - if(piiu->sock_proto == IPPROTO_TCP) - paddr = (struct sockaddr_in *) &piiu->sock_addr; - else + if(io_status != SS$_NORMAL){ + close_ioc(piiu); + if(io_status != SS$_CANCEL) + lib$signal(io_status); + return; + } + /* + * NOTE: The following is a bug fix since WIN has returned the + * address structure missaligned by 16 bits + * + * the fix is reliable since this structure happens to be padded with + * zeros at the end by more than 16 bits + */ + if(piiu->sock_proto == IPPROTO_TCP) + paddr = (struct sockaddr_in *) &piiu->sock_addr; + else #ifdef WINTCP - paddr = (struct sockaddr_in *) ((char *)&piiu->recvfrom+sizeof(short)); + paddr = (struct sockaddr_in *) + ((char *)&piiu->recvfrom+sizeof(short)); #else - paddr = (struct sockaddr_in *) (char *)&piiu->recvfrom; + paddr = (struct sockaddr_in *) + (char *)&piiu->recvfrom; #endif - piiu->recv->stk += io_count; - io_count = piiu->recv->stk; + piiu->recv->stk += io_count; + io_count = piiu->recv->stk; - while(TRUE){ - pbuf = (char *) (pcount+1); + while(TRUE){ + pbuf = (char *) (pcount+1); - /* switch from 68000 to VAX byte order */ - byte_cnt = (unsigned long) ntohl(*pcount); - if(byte_cnt>MAX_MSG_SIZE || byte_cntMAX_MSG_SIZE || byte_cntsin_addr, piiu); - break; - } - else if(io_count > byte_cnt) - post_msg(pbuf, byte_cnt-sizeof(*pcount), paddr->sin_addr, piiu); - else{ - if(pcount != &piiu->recv->buf){ - memcpy(piiu->recv->buf, pcount, io_count); - piiu->recv->stk = io_count; - } + if(io_count == byte_cnt){ + post_msg( + pbuf, + byte_cnt-sizeof(*pcount), + paddr->sin_addr, + piiu); + break; + } + else if(io_count > byte_cnt) + post_msg( + pbuf, + byte_cnt-sizeof(*pcount), + paddr->sin_addr, + piiu); + else{ + if(pcount != piiu->recv->buf){ + memcpy(piiu->recv->buf, pcount, io_count); + piiu->recv->stk = io_count; + } - bufsize = sizeof(piiu->recv->buf) - piiu->recv->stk; - io_status = sys$qio( NULL, + bufsize = sizeof(piiu->recv->buf) - piiu->recv->stk; + io_status = sys$qio( + NULL, piiu->sock_chan, IO$_RECEIVE, &piiu->iosb, recv_msg_ast, - iocix, + piiu, &piiu->recv->buf[piiu->recv->stk], bufsize, NULL, &piiu->recvfrom, sizeof(piiu->recvfrom), NULL); - if(io_status != SS$_NORMAL) - lib$signal(io_status); - return; - } - io_count -= byte_cnt; - pcount = (int *) (byte_cnt + (char *)pcount); + if(io_status != SS$_NORMAL){ + if(io_status == SS$_IVCHAN) + printf("CA: Unable to requeue AST?\n"); + else + lib$signal(io_status); + } + return; + } + io_count -= byte_cnt; + pcount = (int *) (byte_cnt + (char *)pcount); - } - } + } - if(piiu->sock_proto == IPPROTO_TCP) - flow_control(piiu); + if(piiu->sock_proto == IPPROTO_TCP) + flow_control(piiu); - piiu->recv->stk = 0; - io_status = sys$qio( NULL, + piiu->recv->stk = 0; + io_status = sys$qio( + NULL, piiu->sock_chan, IO$_RECEIVE, &piiu->iosb, recv_msg_ast, - iocix, + piiu, piiu->recv->buf, sizeof(piiu->recv->buf), NULL, &piiu->recvfrom, sizeof(piiu->recvfrom), NULL); - if(io_status != SS$_NORMAL) - lib$signal(io_status); + if(io_status != SS$_NORMAL) + lib$signal(io_status); - return; + return; } #endif + +/* + * + * CLOSE_IOC + * + * set an iiu in the disconnected state + * + * + * NOTES: + * Lock must be applied while in this routine + */ +void +close_ioc(piiu) +struct ioc_in_use *piiu; +{ + register chid chix; + int status; + register evid monix; + struct connection_handler_args args; + + if(!piiu->conn_up) + return; + + /* + * reset send stack- discard pending ops when the conn broke (assume + * use as UDP buffer during disconn) + */ + piiu->send->stk = 0; + piiu->max_msg = MAX_UDP; + piiu->conn_up = FALSE; + +# ifdef UNIX + /* clear unused select bit */ + FD_CLR(piiu->sock_chan, &readch); +# endif + + chix = (chid) &piiu->chidlist.node.next; + while(chix = (chid) chix->node.next){ + chix->type = TYPENOTCONN; + chix->count = 0; + chix->state = cs_prev_conn; + chix->paddr = NULL; + if(chix->connection_func){ + args.chid = chix; + args.op = CA_OP_CONN_DOWN; + (*chix->connection_func)(args); + } + } + + if(fd_register_func) + (*fd_register_func)(fd_register_arg, piiu->sock_chan, FALSE); + + close(piiu->sock_chan); + piiu->sock_chan = -1; + if(piiu->chidlist.count) + ca_signal(ECA_DISCONN, host_from_addr(piiu->sock_addr.sin_addr)); + +} + +/* + * + * Test for the repeater allready installed + * + * NOTE: potential race condition here can result + * in two copies of the repeater being spawned + * however the repeater detectes this prints a message + * and lets the other task start the repeater. + * + * QUESTION: is there a better way to test for a port in use? + * ANSWER: none that I can find. + * + * Problems with checking for the repeater installed + * by attempting to bind a socket to its address + * and port. + * + * 1) Closed socket may not release the bound port + * before the repeater wakes up and tries to grab it. + * Attempting to bind the open socket to another port + * also does not work. + * + */ +repeater_installed() +{ + int status; + int sock; + struct sockaddr_in bd; + + int installed = FALSE; + + /* allocate a socket */ + sock = socket( AF_INET, /* domain */ + SOCK_DGRAM, /* type */ + 0); /* deflt proto */ + if(sock == ERROR) + abort(); + + memset(&bd,0,sizeof bd); + bd.sin_family = AF_INET; + bd.sin_addr.s_addr = htonl(INADDR_ANY); + bd.sin_port = htons(CA_CLIENT_PORT); + status = bind(sock, &bd, sizeof bd); + if(status<0) + if(MYERRNO == EADDRINUSE) + installed = TRUE; + else + abort(); + + + close(sock); + + return installed; +} diff --git a/src/ca/iocinf.h b/src/ca/iocinf.h index 1b7805110..a9ebe650c 100644 --- a/src/ca/iocinf.h +++ b/src/ca/iocinf.h @@ -2,7 +2,7 @@ /* */ /* L O S A L A M O S */ /* Los Alamos National Laboratory */ -/* Los Alamos, New Mexico 87545 */ +/* Los Alamos, New Mexico 87545 */ /* */ /* Copyright, 1986, The Regents of the University of California. */ /* */ @@ -29,13 +29,16 @@ /* ioc interface include */ /* */ /* */ -/* Special comments */ +/* Special comments */ /* ------- -------- */ /* Use GLBLTYPE to define externals so we can change the all at */ /* once from VAX globals to generic externals */ -/* */ +/* */ /************************************************************************/ /*_end */ +#ifndef INCiocinfh +#define INCiocinfh + #ifndef INClstLibh #include @@ -49,39 +52,24 @@ #include #endif -#ifdef vxWorks -#include -#endif - - #ifdef VMS # include #endif - -#ifdef VMS -/************************************************************************/ -/* Provided to enforce one thread at a time code sections */ -/* independent of a particular operating system */ -/************************************************************************/ - /* note: the following must allways be used together */ - /* provided for data structure mutal exclusive lock out */ - /* in the VMS AST environment. */ -# define LOCK\ - {register long astenblwas;\ - astenblwas = sys$setast(FALSE); -# define UNLOCK\ - if(astenblwas == SS$_WASSET)sys$setast(TRUE);} -#else -# ifdef vxWorks -# define LOCK FASTLOCK(&client_lock); -# define UNLOCK FASTUNLOCK(&client_lock); -# else -# define LOCK -# define UNLOCK -# endif +#ifndef INCos_depenh +# include #endif +void send_msg(); + +/* throw out requests prior to last ECA_TIMEOUT from ca_pend */ +#define VALID_MSG(PIIU) (piiu->read_seq == piiu->cur_read_seq) + +/* perform a build to reconnect this channel ? */ +#define VALID_BUILD(CHID)\ +(CHID->build_count && CHID->build_type != TYPENOTCONN && CHID->build_value) + + #define IODONESUB\ {\ register struct pending_io_event *pioe;\ @@ -94,37 +82,10 @@ UNLOCK;\ } -#define VALID_MSG(PIIU) (piiu->read_seq == piiu->cur_read_seq) +enum channel_state{cs_never_conn, cs_prev_conn, cs_conn, closed}; -#ifdef vxWorks -# define SETPENDRECV {pndrecvcnt++;} -# define CLRPENDRECV\ -{if(--pndrecvcnt<1){IODONESUB; vrtxPost(&io_done_flag, TRUE);}} -#else -#ifdef VMS -# define SETPENDRECV {pndrecvcnt++;} -# define CLRPENDRECV\ -{if(--pndrecvcnt<1){IODONESUB; sys$setef(io_done_flag);}} -#else -# define SETPENDRECV {pndrecvcnt++;} -# define CLRPENDRECV\ -{if(--pndrecvcnt<1){IODONESUB;}} -#endif -#endif - -#ifdef WINTCP /* Wallangong */ -/* (the VAXC runtime lib has its own close */ -# define socket_close(S) netclose(S) -# define socket_ioctl(A,B,C) ioctl(A,B,C) -#endif -#ifdef UNIX -# define socket_close(S) close(S) -# define socket_ioctl(A,B,C) ioctl(A,B,C) -#endif -#ifdef vxWorks -# define socket_close(S) close(S) -# define socket_ioctl(A,B,C) ioctl(A,B,C) -#endif +#define SETPENDRECV {pndrecvcnt++;} +#define CLRPENDRECV {if(--pndrecvcnt<1){IODONESUB; POST_IO_EV;}} /* size of object in bytes rounded up to nearest long word */ #define QUAD_ROUND(A) (((A)+3)>>2) @@ -133,39 +94,10 @@ /* size of object in bytes rounded up to nearest short word */ #define BI_ROUND(A) (((A)+1)>>1) #define BI_SIZEOF(A) (QUAD_ROUND(sizeof(A))) - +/* #define MAX(A,B) (((A)>(B))?(A):(B)) #define MIN(A,B) (((A)>(B))?(B):(A)) - -#ifdef vxWorks -#define VXTHISTASKID taskIdCurrent -extern int taskIdCurrent; -#define abort() taskSuspend(taskIdCurrent); -#endif - -#ifdef vxWorks -# define memcpy(D,S,N) bcopy(S,D,N) -# define memset(D,V,N) bfill(D,N,V) -#endif - -#ifdef VMS -#ifdef WINTCP - extern int uerrno; /* Wallongong errno is uerrno */ -# define MYERRNO uerrno -#else - extern volatile int noshare socket_errno; -# define MYERRNO socket_errno -#endif -#else -# ifdef vxWorks -# define MYERRNO (errnoGet()&0xffff) -# else - extern int errno; -# define MYERRNO errno -# endif -#endif - - +*/ /************************************************************************/ /* Structures */ /************************************************************************/ @@ -176,21 +108,10 @@ struct buffer{ char buf[MAX_MSG_SIZE]; /* from iocmsg.h */ }; -#ifdef VMS -struct iosb{ -short status; -unsigned short count; -void *device; -}; -#endif -struct timeval{ - unsigned long tv_sec; - unsigned long tv_usec; -}; - -/* Moved in an allocated structure for vxWorks Compatibility */ +/* indexs into the ioc in use table */ #define MAXIIU 25 +#define INVALID_IIU (MAXIIU+1) #define LOCAL_IIU (MAXIIU+100) #define BROADCAST_IIU 0 @@ -210,9 +131,13 @@ struct pending_io_event{ #define chidlist_conn (ca_static->ca_chidlist_conn) #define chidlist_noreply\ (ca_static->ca_chidlist_noreply) -#define eventlist (ca_static->ca_eventlist) #define ioeventlist (ca_static->ca_ioeventlist) #define nxtiiu (ca_static->ca_nxtiiu) +#define free_event_list (ca_static->ca_free_event_list) +#define pend_read_list (ca_static->ca_pend_read_list) +#define fd_register_func\ + (ca_static->ca_fd_register_func) +#define fd_register_arg (ca_static->ca_fd_register_arg) #ifdef UNIX #define readch (ca_static->ca_readch) #define writech (ca_static->ca_writech) @@ -225,6 +150,8 @@ struct pending_io_event{ #define client_lock (ca_static->ca_client_lock) #define event_buf (ca_static->ca_event_buf) #define event_buf_size (ca_static->ca_event_buf_size) +#define local_chidlist (ca_static->ca_local_chidlist) +#define dbfree_ev_list (ca_static->ca_dbfree_ev_list) #endif #ifdef VMS #define io_done_flag (ca_static->ca_io_done_flag) @@ -233,18 +160,21 @@ struct pending_io_event{ struct ca_static{ unsigned short ca_nxtiiu; long ca_pndrecvcnt; - LIST ca_chidlist_conn; - LIST ca_chidlist_pend; - LIST ca_chidlist_noreply; - LIST ca_eventlist; LIST ca_ioeventlist; + void (*ca_exception_func)(); + void *ca_exception_arg; + void (*ca_connection_func)(); + void *ca_connection_arg; + void (*ca_fd_register_func)(); + void (*ca_fd_register_arg)(); + short ca_exit_in_progress; + unsigned short ca_post_msg_active; + LIST ca_free_event_list; + LIST ca_pend_read_list; + short ca_repeater_contacted; #ifdef UNIX fd_set ca_readch; - fd_set ca_writech; - fd_set ca_execch; #endif - short ca_exit_in_progress; - unsigned short ca_post_msg_active; #ifdef VMS int ca_io_done_flag; #endif @@ -255,6 +185,8 @@ struct ca_static{ void *ca_event_buf; unsigned ca_event_buf_size; int ca_tid; + LIST ca_local_chidlist; + LIST ca_dbfree_ev_list; #endif struct ioc_in_use{ unsigned contiguous_msg_count; @@ -267,6 +199,12 @@ struct ca_static{ struct buffer *recv; unsigned read_seq; unsigned cur_read_seq; + LIST chidlist; /* chans on this connection */ + unsigned nconn_wait; /* number delays before try */ + unsigned nconn_tries; /* number of times conn was tried */ + int conn_up; /* boolean: T-conn /F-disconn */ + unsigned count_to_refresh; /* ndelays to conn retry */ +#define MAXCONNTRIES 3 #ifdef VMS /* for qio ASTs */ struct sockaddr_in recvfrom; struct iosb iosb; @@ -281,7 +219,7 @@ struct ca_static{ GLOBAL VARIABLES There should only be one - add others to ca_static above -joh */ -#ifdef GLBLSOURCE +#ifdef CA_GLBLSOURCE # ifdef VAXC # define GLBLTYPE globaldef # else @@ -305,13 +243,5 @@ char ca_unique_address; #endif -/* -Error handlers needed - -remote_error(user_arg,chid,type,count) -diconnect(user_arg,chid) -connect(user_arg,chid) -io_done(user_arg) - -*/ +#endif diff --git a/src/ca/iocmsg.h b/src/ca/iocmsg.h index 81abad0b8..efd1a7c7d 100644 --- a/src/ca/iocmsg.h +++ b/src/ca/iocmsg.h @@ -1,23 +1,22 @@ #ifndef __IOCMSG__ /* History - 1/90 Jeff Hill removed status field in favor of a - seperate command- saves space on every - successful operation - 09/24/90 Marty Kraimer Temporily changed def for SERVER_NUM + 1/90 joh removed status field in favor of a seperate command- + saves space on every successful operation + + 4-13-90 joh moved server ports to above IPPORT_USERRESERVED + see in.h */ #define __IOCMSG__ /* TCP/UDP port number (bumped each protocol change) */ -#define CA_PROTOCOL_VERSION 2 -/* -#define SERVER_NUM (IPPORT_USERRESERVED+12+CA_PROTOCOL_VERSION) -*/ -#define SERVER_NUM (1102+CA_PROTOCOL_VERSION) +#define CA_PROTOCOL_VERSION 3 +#define CA_PORT_BASE IPPORT_USERRESERVED + 56 +#define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2) +#define CA_CLIENT_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2+1) -#define RSERVERQ 1 /* qid for response server queue */ #define MAX_UDP 1024 #define MAX_TCP (MAX_UDP*16) /* so waveforms fit */ #define MAX_MSG_SIZE (MAX_TCP) /* the larger of tcp and udp max */ @@ -25,22 +24,34 @@ /* values for m_cmmd */ -#define IOC_EVENT_ADD 2 /* add an event */ -#define IOC_NOCMD 4 /* NOOP */ -#define IOC_EVENT_CANCEL 5 /* cancel an event */ -#define IOC_READ 7 /* read and return a channel value*/ -#define IOC_WRITE 9 /* write a channel value */ -#define IOC_SNAPSHOT 11 /* snapshot of the system */ -#define IOC_SEARCH 31 /* IOC channel search */ -#define IOC_BUILD 33 /* Conglomerate of IOC_SEARCH */ +#define IOC_NOOP 0 /* do nothing, but verify TCP */ +#define IOC_EVENT_ADD 1 /* add an event */ +#define IOC_EVENT_CANCEL 2 /* cancel an event */ +#define IOC_READ 3 /* read and return a channel value*/ +#define IOC_WRITE 4 /* write a channel value */ +#define IOC_SNAPSHOT 5 /* snapshot of the system */ +#define IOC_SEARCH 6 /* IOC channel search */ +#define IOC_BUILD 7 /* Conglomerate of IOC_SEARCH */ /* IOC_READ */ /* (optimizes OPI network use) */ -#define IOC_EVENTS_OFF 13 /* flow control */ -#define IOC_EVENTS_ON 14 /* flow control */ -#define IOC_READ_SYNC 16 /* purge old reads */ -#define IOC_ERROR 18 /* an operation failed */ - +#define IOC_EVENTS_OFF 8 /* flow control */ +#define IOC_EVENTS_ON 9 /* flow control */ +#define IOC_READ_SYNC 10 /* purge old reads */ +#define IOC_ERROR 11 /* an operation failed */ +#define IOC_CLEAR_CHANNEL 12 /* free chan resources */ +#define IOC_RSRV_IS_UP 13 /* CA server has joined the net */ +#define IOC_NOT_FOUND 14 /* channel not found */ +#define IOC_READ_NOTIFY 15 /* add a one shot event */ +#define IOC_READ_BUILD 16 /* read accompanying a build */ +#define REPEATER_CONFIRM 17 /* registration confirmation */ + /* + for use with build and search and not_found + (if search fails and its not a broadcast tell + the client to look elesewhere) + */ +#define DOREPLY 10 +#define DONTREPLY 5 /* extmsg - the nonvariant part of each message sent/recv @@ -53,20 +64,19 @@ struct extmsg { unsigned short m_postsize; /* size of message extension */ unsigned short m_type; /* operation data type */ unsigned short m_count; /* operation data count */ - void *m_paddr; /* ptr to struct db_addr */ - /* IOC db field addr info */ + void *m_pciu; /* ptr to server channel in use */ unsigned long m_available; /* undefined message location for use * by client processes */ }; - /* for monitor message extension */ + /* for monitor (event) message extension */ struct mon_info{ - float m_lval; /* low value to look for (deviation low - * for continuous monitors) */ - float m_hval; /* high value (high deviation - * for continuous monitors) */ - float m_toval; /* timeout limit for returning cval */ + float m_lval; /* low delta */ + float m_hval; /* high delta */ + float m_toval; /* period btween samples */ + unsigned short m_mask; /* event select mask */ + unsigned short m_pad; /* extend to 32 bits */ }; struct monops { /* monitor req opi to ioc */ diff --git a/src/ca/net_convert.h b/src/ca/net_convert.h index d50eb250a..e6d9e5deb 100644 --- a/src/ca/net_convert.h +++ b/src/ca/net_convert.h @@ -1,3 +1,18 @@ +/* + * + * N E T _ C O N V E R T . H + * MACROS for rapid conversion between VAX data formats and those used + * by the IOCs + * + * + * joh 09-13-90 force MIT sign to zero if exponent is zero + * to prevent a reseved operand fault. + * + * + */ + + + /************************************************************************/ /* So byte swapping can be performed in line for efficiency */ /* (WINTCP has library routines with the same same functionality */ @@ -95,25 +110,31 @@ struct ieeeflt{ *(long *)(IEEE) = ntohl(*(long*)(IEEE));\ } +/* + * sign must be forced to zero if the exponent is zero to prevent a reserved + * operand fault- joh 9-13-90 + */ # define ntohf(IEEE,MIT)\ {\ long exp,mant2,mant1,sign;\ *(long *)(IEEE) = htonl(*(long*)(IEEE));\ - sign = ((struct ieeeflt *) (IEEE))->sign;\ if( (short)((struct ieeeflt *) (IEEE))->exp > EXPMAXMIT + IEEE_SB){\ + sign = ((struct ieeeflt *) (IEEE))->sign;\ exp = EXPMAXMIT + MIT_SB;\ mant2 = ~0;\ mant1 = ~0;\ }\ else if( ((struct ieeeflt *) (IEEE))->exp == 0){\ + sign = 0;\ exp = 0;\ mant2 = 0;\ mant1 = 0;\ }\ else{\ - exp = ((struct ieeeflt *) (IEEE))->exp+MIT_SB-IEEE_SB;\ - mant2 = ((struct ieeeflt *) (IEEE))->mant;\ - mant1 = (((struct ieeeflt *) (IEEE))->mant>>(unsigned)16);\ + sign = ((struct ieeeflt *) (IEEE))->sign;\ + exp = ((struct ieeeflt *) (IEEE))->exp+MIT_SB-IEEE_SB;\ + mant2 = ((struct ieeeflt *) (IEEE))->mant;\ + mant1 = ((struct ieeeflt *) (IEEE))->mant>>(unsigned)16;\ }\ ((struct mitflt *) (MIT))->exp = exp;\ ((struct mitflt *) (MIT))->mant2 = mant2;\ @@ -128,33 +149,90 @@ struct ieeeflt{ #endif #ifdef VAX -/* cvrt is (array of) (pointer to) (function returning) int */ -int cvrt_sts_string (); -int cvrt_sts_int (); -int cvrt_sts_float (); -int cvrt_sts_enum (); -int cvrt_gr_int (); -int cvrt_gr_float (); -int cvrt_ctrl_int (); -int cvrt_ctrl_float (); -int cvrt_ctrl_enum (); +int cvrt_string(); +int cvrt_short(); +int cvrt_float(); +int cvrt_enum(); +int cvrt_char(); +int cvrt_long(); +int cvrt_double(); +int cvrt_sts_string(); +int cvrt_sts_short(); +int cvrt_sts_float(); +int cvrt_sts_enum(); +int cvrt_sts_char(); +int cvrt_sts_long(); +int cvrt_sts_double(); + +int cvrt_time_string(); +int cvrt_time_short(); +int cvrt_time_float(); +int cvrt_time_enum(); +int cvrt_time_char(); +int cvrt_time_long(); +int cvrt_time_double(); + +int cvrt_gr_string(); +int cvrt_gr_short(); +int cvrt_gr_float(); +int cvrt_gr_enum(); +int cvrt_gr_char(); +int cvrt_gr_long(); +int cvrt_gr_double(); +int cvrt_gr_string(); + +int cvrt_ctrl_string(); +int cvrt_ctrl_short(); +int cvrt_ctrl_float(); +int cvrt_ctrl_enum(); +int cvrt_ctrl_char(); +int cvrt_ctrl_long(); +int cvrt_ctrl_double(); + +/* cvrt is (array of) (pointer to) (function returning) int */ static int (*cvrt[])() = { - 0, - 0, - 0, - 0, + cvrt_string, + cvrt_short, + cvrt_float, + cvrt_enum, + cvrt_char, + cvrt_long, + cvrt_double, + cvrt_sts_string, - cvrt_sts_int, + cvrt_sts_short, cvrt_sts_float, cvrt_sts_enum, - cvrt_gr_int, + cvrt_sts_char, + cvrt_sts_long, + cvrt_sts_double, + + cvrt_time_string, + cvrt_time_short, + cvrt_time_float, + cvrt_time_enum, + cvrt_time_char, + cvrt_time_long, + cvrt_time_double, + + cvrt_gr_string, + cvrt_gr_short, cvrt_gr_float, - cvrt_ctrl_int, + cvrt_gr_enum, + cvrt_gr_char, + cvrt_gr_long, + cvrt_gr_double, + + cvrt_ctrl_string, + cvrt_ctrl_short, cvrt_ctrl_float, - cvrt_ctrl_enum + cvrt_ctrl_enum, + cvrt_ctrl_char, + cvrt_ctrl_long, + cvrt_ctrl_double }; #endif diff --git a/src/ca/service.c b/src/ca/service.c index 080c11283..ed6bc513c 100644 --- a/src/ca/service.c +++ b/src/ca/service.c @@ -2,7 +2,7 @@ /* */ /* L O S A L A M O S */ /* Los Alamos National Laboratory */ -/* Los Alamos, New Mexico 87545 */ +/* Los Alamos, New Mexico 87545 */ /* */ /* Copyright, 1986, The Regents of the University of California. */ /* */ @@ -20,7 +20,7 @@ /************************************************************************/ /* */ /* Title: channel access service routines */ -/* File: atcs:[ca]servuice.c */ +/* File: atcs:[ca]service.c */ /* Environment: VMS, UNIX, VRTX */ /* Equipment: VAX, SUN, VME */ /* */ @@ -31,9 +31,9 @@ /* channel access service routines */ /* */ /* */ -/* Special comments */ +/* Special comments */ /* ------- -------- */ -/* */ +/* */ /************************************************************************/ /*_end */ @@ -41,6 +41,10 @@ #include #endif +#ifdef UNIX +#include +#endif + #include #include @@ -50,8 +54,9 @@ #include #include +void reconnect_channel(); -void post_msg(hdrptr,bufcnt,net_addr,piiu) +void post_msg(hdrptr,bufcnt,net_addr,piiu) register struct extmsg *hdrptr; register long bufcnt; struct in_addr net_addr; @@ -60,7 +65,6 @@ struct ioc_in_use *piiu; evid monix; long msgcnt; long tmp; - char *name; register void * t_available; register unsigned short t_postsize; @@ -70,15 +74,13 @@ struct ioc_in_use *piiu; register unsigned short t_size; int status; -# define BUFCHK(SIZE)\ - msgcnt = (SIZE); if(bufcnt-msgcnt < 0)\ - {printf("post_msg(): expected msg size larger than actual msg\n");return;} # define BUFSTAT\ printf("expected %d left %d\n",msgcnt,bufcnt); post_msg_active++; + while(bufcnt>0){ # ifdef DEBUG printf( "processing message- bytes left %d, pending msgcnt %d\n", @@ -94,223 +96,368 @@ struct ioc_in_use *piiu; t_count = ntohs(hdrptr->m_count); t_size = dbr_size[t_type]; +# ifdef DEBUG + printf( "MSG: cmd:%d type:%d cnt:%d size:%d npost:%d avail:%x\n", + t_cmmd, + t_type, + t_count, + t_size, + t_postsize, + t_available + ); +# endif + msgcnt = sizeof(*hdrptr) + t_postsize; + if(bufcnt-msgcnt < 0){ + printf( + "post_msg(): expected msg size larger than actual msg %d %d\n", + bufcnt, + msgcnt); + post_msg_active--; + return; + } switch(t_cmmd){ - case IOC_EVENT_ADD: - /* run the user's event handler */ - /* m_available points to event descriptor */ - - monix = (evid) t_available; - - /* m_postsize = 0 is a confirmation of a monitor cancel */ - if( !t_postsize ){ - LOCK; - lstDelete(&eventlist, monix); - UNLOCK; - if(free(monix)<0) - printf("Unable to dealloc VM on IOC monitor cancel confirmation\n"); - - BUFCHK(sizeof(*hdrptr)); - break; - } - - /* BREAK LEFT OUT HERE BY DESIGN -JH */ - - case IOC_READ: + case IOC_READ_NOTIFY: { - /* update and convert the user's argument if read */ - /* (m_available points to argument descriptor) */ - /* else update in buffer if a monitor */ - register void *objptr = (void *) (hdrptr+1); - register void *dstptr; - unsigned int i; + /* run the user's event handler */ + /* m_available points to event descriptor */ + struct event_handler_args args; - if(t_cmmd == IOC_READ){ - /* only count get returns if from the current read seq */ - if(!VALID_MSG(piiu)) - break; - dstptr = (void *) t_available; - } - else - dstptr = objptr; + monix = (evid) t_available; - BUFCHK(sizeof(*hdrptr) + t_postsize); -# ifdef DEBUG - BUFSTAT - if(t_cmmd==IOC_READ) - {static short i; printf("global reccnt %d\n",++i);} - else - {static short i; printf("global moncnt %d\n",++i);} -# endif + /* + * Currently only the VAXs need data conversion + */ +# ifdef VAX + (*cvrt[t_type])( hdrptr+1, hdrptr+1, FALSE, t_count); +# endif - for(i=0; iusr_func){ + args.usr = monix->usr_arg; + args.chid = monix->chan; + args.type = t_type; + args.count = t_count; + args.dbr = (void *) (hdrptr+1); - /* perform 2 and 4 byte transfer in line */ - /* NOTE that if we are on a machine that does not require */ - /* conversions these will be NULL macros */ - switch(t_type){ + (*monix->usr_func)(args); + } - /* long word convert/transfer */ - case DBR_INT: - case DBR_ENUM: - *(short *)dstptr = ntohs(*(short *)objptr); - break; + LOCK; + lstDelete(&pend_read_list, monix); + lstAdd(&free_event_list, monix); + UNLOCK; - case DBR_FLOAT: - tmp = *(long *)objptr; - ntohf(&tmp, dstptr); - break; + break; + } + case IOC_EVENT_ADD: + { + /* run the user's event handler */ + /* m_available points to event descriptor */ + struct event_handler_args args; - case DBR_STRING: - if(dstptr != objptr) - strcpy( dstptr, - objptr); - break; + monix = (evid) t_available; - /* record transfer and convert */ - case DBR_STS_STRING: - case DBR_STS_INT: - case DBR_STS_FLOAT: - case DBR_STS_ENUM: - case DBR_GR_INT: - case DBR_GR_FLOAT: - case DBR_CTRL_INT: - case DBR_CTRL_FLOAT: - case DBR_CTRL_ENUM: -# ifdef VAX - (*cvrt[t_type])(objptr,dstptr,(int)FALSE,(int)t_count); -# else - if(dstptr != objptr) - memcpy( dstptr, - objptr, - t_size); -# endif - /* - Conversion Routines handle all elements of an array in one call - for efficiency. - */ - goto array_loop_exit; + /* m_postsize = 0 is a confirmation of a monitor cancel */ + if( !t_postsize ){ + LOCK; + lstDelete(&monix->chan->eventq, monix); + lstAdd(&free_event_list, monix); + UNLOCK; - break; - default: - printf("post_msg(): unsupported db fld type in msg ?%d\n",t_type); - abort(); - } + break; + } - (char *) objptr += t_size; - (char *) dstptr += t_size; + /* only call if not disabled */ + if(!monix->usr_func) + break; - } + /* + * Currently only the VAXs need data conversion + */ +# ifdef VAX + (*cvrt[t_type])( hdrptr+1, hdrptr+1, FALSE, t_count); +# endif -array_loop_exit: - if(t_cmmd == IOC_READ) - /* decrement the outstanding IO count */ - CLRPENDRECV - else - /* call handler */ - (*monix->usr_func)( - monix->usr_arg, /* usr supplied */ - monix->chan, /* channel id */ - t_type, /* type of returned val */ - t_count, /* the element count */ - hdrptr+1 /* ptr to returned val */ - ); + + /* + * Orig version of CA didnt use this strucure. + * This would run faster if I had decided to + * pass a pointer to this structure rather + * than the structure itself early on. + * + * Pumping the arguments on the stack explicitly + * could cause problems if a small item is in + * the structure and we are on a SPARC processor. + * + */ + args.usr = monix->usr_arg; + args.chid = monix->chan; + args.type = t_type; + args.count = t_count; + args.dbr = (void *) (hdrptr+1); + + /* call their handler */ + (*monix->usr_func)(args); + + break; + } + case IOC_READ: + case IOC_READ_BUILD: + { + chid chan = (chid) hdrptr->m_pciu; + + /* only count get returns if from the current read seq */ + if(!VALID_MSG(piiu)) + break; + +if(t_postsize > (t_count-1) * dbr_value_size[t_type] + dbr_size[t_type]) + SEVCHK(ECA_INTERNAL,"about to violate user's buffer"); + + /* + * Currently only the VAXs need data conversion + */ +# ifdef VAX + (*cvrt[t_type])( hdrptr+1, t_available, FALSE, t_count); +# else + /* in line is a little faster */ + if(t_postsize<=sizeof(int)){ + if(t_postsize==sizeof(long)) + *(long *)t_available = *(long *)(hdrptr+1); + else if(t_postsize==sizeof(short)) + *(short *)t_available = *(short *)(hdrptr+1); + else if(t_postsize==sizeof(char)) + *(char *)t_available = *(char *)(hdrptr+1); + }else + memcpy( + t_available, + hdrptr+1, + t_postsize); +# endif + + /* + * decrement the outstanding IO count + * + * This relies on the IOC_READ_BUILD msg returning prior to the + * IOC_BUILD msg. + */ + if( t_cmmd != IOC_READ_BUILD || + (chan->connection_func == NULL && chan->state==cs_never_conn)) + CLRPENDRECV; break; } case IOC_SEARCH: case IOC_BUILD: - BUFCHK(sizeof(*hdrptr)); - if( ((chid)t_available)->paddr ){ - int iocix = ((chid)t_available)->iocix; + { + chid chan = (chid) t_available; + struct ioc_in_use *chpiiu = &iiu[chan->iocix]; - if(iiu[iocix].sock_addr.sin_addr.s_addr==net_addr.s_addr) - printf("burp "); - else{ - char msg[256]; - char acc[64]; - char rej[64]; - sprintf(acc,"%s",host_from_addr(iiu[iocix].sock_addr.sin_addr)); - sprintf(rej,"%s",host_from_addr(net_addr)); - sprintf( msg, - "Channel: %s Accepted: %s Rejected: %s ", - ((chid)t_available)+1, - acc, - rej); - ca_signal(ECA_DBLCHNL, msg); + if( chan->paddr ){ + + if(chpiiu->sock_addr.sin_addr.s_addr==net_addr.s_addr){ + printf("burp "); +#ifdef UNIX + fflush(stdout); +#endif + } + else{ + char msg[256]; + char acc[64]; + char rej[64]; + + sprintf(acc,"%s", + host_from_addr(chpiiu->sock_addr.sin_addr)); + sprintf(rej,"%s",host_from_addr(net_addr)); + sprintf( + msg, + "Channel: %s Accepted: %s Rejected: %s ", + chan+1, + acc, + rej); + ca_signal(ECA_DBLCHNL, msg); + } + + /* + * IOC_BUILD messages allways have a IOC_READ msg following. + * (IOC_BUILD messages are sometimes followed by error + * messages which are ignored on double replies) + */ + if(t_cmmd == IOC_BUILD) + msgcnt += sizeof(struct extmsg) + + (hdrptr+1)->m_postsize; + + break; + } + + if(!chan->connection_func && chan->state==cs_never_conn){ + /* decrement the outstanding IO count */ + CLRPENDRECV; } - /* IOC_BUILD messages allways have a IOC_READ msg following */ - /* (IOC_BUILD messages are sometimes followed by error messages */ - /* which are also ignored on double replies) */ - /* the following cause this message to be ignored for double replies */ - if(t_cmmd == IOC_BUILD) - msgcnt += sizeof(struct extmsg) + (hdrptr+1)->m_postsize; - - break; - } - LOCK; - status = alloc_ioc ( - net_addr, - IPPROTO_TCP, - &((chid)t_available)->iocix - ); - SEVCHK(status, host_from_addr(net_addr)); - SEVCHK(status, ((chid)t_available)+1); + LOCK; + reconnect_channel(hdrptr,net_addr,piiu); + UNLOCK; - /* Update rmt chid fields from extmsg fields */ - ((chid)t_available)->type = t_type; - ((chid)t_available)->count = t_count; - ((chid)t_available)->paddr = hdrptr->m_paddr; - lstDelete(&chidlist_pend, t_available); - lstAdd(&chidlist_conn, t_available); - UNLOCK; + if(chan->connection_func){ + struct connection_handler_args args; - /* decrement the outstanding IO count */ - CLRPENDRECV; - - break; + args.chid = chan; + args.op = CA_OP_CONN_UP; + (*chan->connection_func)(args); + } + break; + } case IOC_READ_SYNC: - BUFCHK(sizeof(struct extmsg)); - piiu->read_seq++; - break; + piiu->read_seq++; + break; - case IOC_ERROR: + case IOC_RSRV_IS_UP: +# ifdef DEBUG + printf( "IOC on line ->[%s]\n", + host_from_addr(t_available)); +# endif + LOCK; + mark_server_available(t_available); + chid_retry(TRUE); + UNLOCK; + break; + + case REPEATER_CONFIRM: + ca_static->ca_repeater_contacted = TRUE; +# ifdef DEBUG + printf("repeater confirmation\n"); +# endif + break; + + case IOC_NOT_FOUND: { - char context[255]; + chid chix = (chid) t_available; + struct ioc_in_use *piiu = &iiu[chix->iocix]; - BUFCHK(sizeof(struct extmsg) + t_postsize); + LOCK; + lstDelete(&piiu->chidlist, chix); + lstAdd(&iiu[BROADCAST_IIU].chidlist, chix); + chix->iocix = BROADCAST_IIU; + if(!piiu->chidlist.count) + close_ioc(piiu); + iiu[BROADCAST_IIU].nconn_tries = 0; + chid_retry(TRUE); + UNLOCK; - name = (char *) host_from_addr(net_addr); - if(!name) - name = "an unregistered IOC"; - - if(t_postsize>sizeof(struct extmsg)) - sprintf(context, "detected by: %s for: %s", name, hdrptr+2); - else - sprintf(context, "detected by: %s", name); - - /* - NOTE: - The orig request is stored as an extmsg structure at - hdrptr+1 - I should print additional diagnostic info using this - info when time permits...... - */ - - SEVCHK(ntohl((int)t_available), context); - break; + break; } + case IOC_CLEAR_CHANNEL: + { + chid chix = (chid) t_available; + struct ioc_in_use *piiu = &iiu[chix->iocix]; + register evid monix; + + + LOCK; + /* remove any orphaned get callbacks for this channel */ + for( monix = (evid) pend_read_list.node.next; + monix; + monix = (evid) monix->node.next) + if(monix->chan == chix){ + lstDelete(&pend_read_list, monix); + lstAdd(&free_event_list, monix); + } + + lstConcat(&free_event_list, &chix->eventq); + lstDelete(&piiu->chidlist, chix); + if(free(chix)<0) + abort(); + if(!piiu->chidlist.count) + close_ioc(piiu); + UNLOCK; + break; + } + case IOC_ERROR: + { + char context[255]; + char *name; + struct extmsg *req = hdrptr+1; + int op; + struct exception_handler_args args; + + + /* + * dont process the message if they have disable notification + */ + if(!ca_static->ca_exception_func) + break; + + name = (char *) host_from_addr(net_addr); + if(!name) + name = "an unregistered IOC"; + + if(t_postsize>sizeof(struct extmsg)) + sprintf(context, "detected by: %s for: %s", name, hdrptr+2); + else + sprintf(context, "detected by: %s", name); + + /* + * Map internal op id to external op id so I can freely change the + * protocol in the future. This is quite wasteful of space however. + */ + switch(ntohs(req->m_cmmd)){ + case IOC_READ_NOTIFY: + case IOC_READ: + op = CA_OP_GET; + break; + case IOC_WRITE: + op = CA_OP_PUT; + break; + case IOC_SEARCH: + case IOC_BUILD: + op = CA_OP_SEARCH; + break; + case IOC_EVENT_ADD: + op = CA_OP_ADD_EVENT; + break; + case IOC_EVENT_CANCEL: + op = CA_OP_CLEAR_EVENT; + break; + default: + op = CA_OP_OTHER; + break; + } + + + args.usr = ca_static->ca_exception_arg; /* user arg */ + args.chid = hdrptr->m_pciu; /* the chid if appropriate */ + args.type = ntohs(req->m_type); /* req type if approp */ + args.count = ntohs(req->m_count); /* req count if approp */ + args.addr = (void *) (req->m_available);/* req user addr if approp */ + args.stat = ntohl((int)t_available); /* the CA message code */ + args.op = op; /* the CA operation */ + args.ctx = context; /* context string */ + (*ca_static->ca_exception_func)(args); + break; + } default: - printf("post_msg(): Corrupt message or unsupported m_cmmd type\n"); - return; + printf("post_msg(): Corrupt Cmd in msg %x\n",t_cmmd); + abort(); } bufcnt -= msgcnt; @@ -323,3 +470,80 @@ array_loop_exit: } + +/* + * + * RECONNECT_CHANNEL() + * LOCK must be on + * + */ +void reconnect_channel(hdrptr,net_addr,piiu) +register struct extmsg *hdrptr; +struct in_addr net_addr; +struct ioc_in_use *piiu; +{ + chid chan = (chid) hdrptr->m_available; + unsigned short newiocix; + evid pevent; + int status; + + void ca_request_event(); + + status = alloc_ioc ( + net_addr, + IPPROTO_TCP, + &newiocix + ); + if(status != ECA_NORMAL){ + printf("... %s ...\n", ca_message(status)); + printf("for %s on %s\n", chan+1, host_from_addr(net_addr)); + printf("ignored broadcast reply- proceeding\n"); + return; + } + + /* Update rmt chid fields from extmsg fields */ + chan->type = ntohs(hdrptr->m_type); + chan->count = ntohs(hdrptr->m_count); + chan->paddr = hdrptr->m_pciu; + + if(chan->iocix != newiocix){ + struct ioc_in_use *chpiiu = &iiu[chan->iocix]; + /* + * The address changed (or was found for the first time) + */ + if(chan->iocix != BROADCAST_IIU) + ca_signal(ECA_NEWADDR, chan+1); + lstDelete(&chpiiu->chidlist, chan); + chan->iocix = newiocix; + lstAdd(&iiu[newiocix].chidlist, chan); + } + + + /* + * NOTE: monitor and callback reissue must occur prior to calling + * their connection routine otherwise they could be requested twice. + */ +#ifdef CALLBACK_REISSUE + /* reissue any outstanding get callbacks for this channel */ + if(pend_read_list.count){ + for( pevent = (evid) pend_read_list.node.next; + pevent; + pevent = (evid) pevent->node.next) + if(pevent->chan == chan){ + issue_get_callback(pevent); + send_msg(); + } + } +#endif + + /* reissue any events (monitors) for this channel */ + if(chan->eventq.count){ + for( pevent = (evid)chan->eventq.node.next; + pevent; + pevent = (evid)pevent->node.next) + ca_request_event(pevent); + send_msg(); + } + chan->state = cs_conn; +} + diff --git a/src/ca/test_event.c b/src/ca/test_event.c index ae757ae3c..db00a4d79 100644 --- a/src/ca/test_event.c +++ b/src/ca/test_event.c @@ -5,48 +5,44 @@ void -ca_test_event(usr,chix,type,count,pval) -void *usr; -chid chix; -chtype type; -int count; -void *pval; +ca_test_event(args) +struct event_handler_args args; { - printf("~~~### in test event for [%s] ###~~~\n",chix+1); - printf("user arg\t%x\n",usr); - printf("val ptr\t%x\n",pval); - printf("mon type\t%x\n",type); - printf("channel type\t%x\n",chix->type); - switch(type){ + printf("~~~### in test event for [%s] ###~~~\n",args.chid+1); + printf("User argument\t%x\n", args.usr); + printf("Native channel data type\t%x\n", args.chid->type); + printf("Monitor data type\t%x\n", args.type); + switch(args.type){ case DBR_STRING: - printf("Value:\t<%s>\n",pval); + printf("Value:\t<%s>\n",args.dbr); break; case DBR_INT: case DBR_ENUM: - printf("Value:\t<%d>\n",*(int *)pval); + printf("Value:\t<%d>\n",*(int *)args.dbr); break; case DBR_FLOAT: - printf("Value:\t<%f>\n",*(float *)pval); + printf("Value:\t<%f>\n",*(float *)args.dbr); break; case DBR_STS_STRING: - printf("Value:\t<%s>\n",((struct dbr_sts_string *)pval)->value); + printf("Value:\t<%s>\n",((struct dbr_sts_string *)args.dbr)->value); break; case DBR_STS_INT: - printf("Value:\t<%d>\n",((struct dbr_sts_int *)pval)->value); + printf("Value:\t<%d>\n",((struct dbr_sts_int *)args.dbr)->value); break; case DBR_STS_FLOAT: - printf("Value:\t<%f>\n",((struct dbr_sts_float *)pval)->value); + printf("Value:\t<%f>\n",((struct dbr_sts_float *)args.dbr)->value); break; case DBR_STS_ENUM: - printf("Value:\t<%d>\n",((struct dbr_sts_enum *)pval)->value); + printf("Value:\t<%d>\n",((struct dbr_sts_enum *)args.dbr)->value); break; case DBR_GR_FLOAT: - printf("Value:\t<%f>\n",((struct dbr_gr_float *)pval)->value); + printf("Value:\t<%f>\n",((struct dbr_gr_float *)args.dbr)->value); break; default: - printf("Sorry test_event does not handle this type monitor yet\n"); + printf( "Sorry test_event does not handle data type %d yet\n", + args.type); } } diff --git a/src/db/dbEvent.c b/src/db/dbEvent.c index 8ce37099c..0292d631f 100644 --- a/src/db/dbEvent.c +++ b/src/db/dbEvent.c @@ -1,29 +1,60 @@ -/* dbEvent.c */ -/* share/src/db $Id$ */ - /* - -dbEvent.c - -routines for scheduling events to lower priority tasks via the RT kernel - -Modification History -joh 00 30Mar89 Created -joh 01 Apr 89 Init Release -joh 02 06-14-89 changed DBCHK to PADDRCHK since we are checking - precord instead of pfield now. -joh 03 07-28-89 Added dynamic que size increase proportional - to nevents -joh 04 08-21-89 Added init function to args of db_start_events() -joh 05 12-21-89 fixed bug where event que not completely - dealloated when there are many events. -joh 06 02-16-90 changed names here and in dbcommon to avoid - confusion for those maintaining this code - (this change does not modify obj code). - mlok became mon_lock - mlst became mon_list -mrk(anl)07 09-18-90 Made changes for new record and device support -*/ + * + * DB_EVENT.C + * + * routines for scheduling events to lower priority tasks via the RT kernel + * + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665-1831 + * + * Control System Software for the GTA Project + * + * Copyright 1988, 1989, the Regents of the University of California. + * + * This software was produced under a U.S. Government contract + * (W-7405-ENG-36) at the Los Alamos National Laboratory, which is + * operated by the University of California for the U.S. Department + * of Energy. + * + * Developed by the Controls and Automation Group (AT-8) + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Direct inqueries to: + * Andy Kozubal, AT-8, Mail Stop H820 + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * Phone: (505) 667-6508 + * E-mail: kozubal@k2.lanl.gov + * + * NOTES: + * 01 I have assumed that all C compilers align unions so that + * a pointer to a field in the union is also a pointer all + * of the other fields in the union. This has been verified + * on our current compiler and several other C compilers. + * + * Modification Log: + * ----------------- + * joh 00 04xx89 Created + * joh 01 043089 Init Release + * joh 02 061489 changed DBCHK to PADDRCHK since we are + * checking precord instead of pfield now. + * joh 03 072889 Added dynamic que size increase proportional + * to nevents + * joh 04 082189 Added init func to args of db_start_events() + * joh 05 122189 fixed bug where event que not completely + * dealloated when there are many events. + * joh 06 021690 changed names here and in dbCommon to avoid + * confusion for those maintaining this code + * (this change does not modify obj code). + * mlok became mlok + * mlst became mlis + * joh 07 030590 improved db_event_list() diagnostic + * joh 08 031590 improved flush wait in db_cancel_event() + * joh 09 112790 added time stamp, alarm, and status logging + * joh 10 112790 source cleanup + */ #include @@ -31,84 +62,117 @@ mrk(anl)07 09-18-90 Made changes for new record and device support #include #include #include - +#include #include -#include +#include #include -#include #include -struct event_block{ - NODE node; - struct dbAddr addr; - void *pfield; /* I modify the copy of pfield above */ - void (*user_sub)(); - void *user_arg; - struct event_que *ev_que; - unsigned char select; - char valque; - unsigned short npend; /* number of times this event is on the que */ -}; +/* function declarations */ +static void wake_cancel(); -union native_value{ - short bval; - short eval; - float rval; + +/* included text from dblib.h */ +/*********************************************************************/ /* - Strings left off for now - - reliable interprocess communication may not be provided with strings - since they will slow down events for more reasonable size values. - - char sval[MAXSTRINGSIZE]; + * Simple native types (anything which is not a string or an array for + * now) logged by db_post_events() for reliable interprocess communication. + * (for other types they get whatever happens to be there when the lower + * priority task pending on the event queue wakes up). Strings would slow down + * events for more reasonable size values. DB fields of native type string + * will most likely change infrequently. + * + */ +union native_value{ +/* + char dbf_string[MAXSTRINGSIZE]; */ + short dbf_int; + short dbf_short; + float dbf_float; + short dbf_enum; + char dbf_char; + long dbf_long; + double dbf_double; }; +/* + * structure to log the state of a data base field at the time + * an event is triggered. + */ +typedef struct{ + unsigned short stat; /* Alarm Status */ + unsigned short sevr; /* Alarm Severity */ + TS_STAMP time; /* time stamp */ + union native_value field; /* field value */ +}db_field_log; + +/*********************************************************************/ + + + +/* what to do with unrecoverable errors */ +#define abort taskSuspend; + +struct event_block{ + NODE node; + struct db_addr *paddr; + void (*user_sub)(); + void *user_arg; + struct event_que *ev_que; + unsigned char select; + char valque; + unsigned short npend; /* n times this event is on the que */ +}; + + #define EVENTQUESIZE EVENTENTRIES *32 #define EVENTENTRIES 16 /* the number of que entries for each event */ #define EVENTQEMPTY ((struct event_block *)NULL) -/* - Reliable intertask communication requires copying the current value - of the channel for later queing so 3 stepper motor steps of 10 each - do not turn into only 10 or 20 total steps part of the time. - - NOTE: locks on this data structure are optimized so a test and set - call is made first. If the lock is allready set then the task - pends on the lock pend sem. Test and set call is much faster than - a semaphore. See LOCKEVUSER. -*/ /* -really a ring buffer -*/ + * Reliable intertask communication requires copying the current value of the + * channel for later queing so 3 stepper motor steps of 10 each do not turn + * into only 10 or 20 total steps part of the time. + * + * NOTE: locks on this data structure are optimized so a test and set call is + * made first. If the lock is allready set then the task pends on the lock + * pend sem. Test and set call is much faster than a semaphore. See + * LOCKEVUSER. + */ + +/* + * really a ring buffer + */ struct event_que{ - struct event_block *evque[EVENTQUESIZE]; - union native_value valque[EVENTQUESIZE]; - unsigned short putix; - unsigned short getix; - unsigned short quota; /* the number of assigned entries*/ + struct event_block *evque[EVENTQUESIZE]; + db_field_log valque[EVENTQUESIZE]; + unsigned short putix; + unsigned short getix; + unsigned short quota; /* the number of assigned entries*/ - /* lock writers to the ring buffer only */ - /* readers must never slow up writers */ - FAST_LOCK writelock; + /* lock writers to the ring buffer only */ + /* readers must never slow up writers */ + FAST_LOCK writelock; - struct event_que *nextque; /* in case que quota exceeded */ - struct event_user *evuser; /* event user parent struct */ + struct event_que *nextque; /* in case que quota exceeded */ + struct event_user *evuser; /* event user parent struct */ }; struct event_user{ - int taskid; /* event handler task id */ - int taskpri; /* event handler task priority */ + int taskid; /* event handler task id */ + int taskpri; /* event handler task pri */ - char pendlck; /* Only one task can pend */ - SEMAPHORE pendsem; /* Wait while empty */ - unsigned char pendexit; /* exit pend task */ + char pendlck; /* Only one task can pend */ + SEMAPHORE pendsem; /* Wait while empty */ + unsigned char pendexit; /* exit pend task */ - unsigned short queovr; /* event que overflow count */ - void (*overflow_sub)(); /* executed for overflow detect */ - void *overflow_arg; /* parameter to above routine */ + unsigned short queovr; /* event que overflow count */ + void (*overflow_sub)();/* called overflow detect */ + void *overflow_arg; /* parameter to above */ - struct event_que firstque; /* the first event que */ + struct event_que firstque; /* the first event que */ }; @@ -133,414 +197,504 @@ FASTUNLOCK(&(RECPTR)->mlok); #define VXTASKIDSELF 0 -/* - >> kernel dependent << - - This is so if we go to a kernel which has different - priority order I can switch all priority inc/dec at once -joh - - on VRTX a lower priority number runs first- hence the minus one -*/ +/* + * >> kernel dependent << + * + * if we go to a kernel which has different priority order I can + * switch all priority inc/dec at once -joh + * + * on VRTX a lower priority number runs first- hence the minus one + */ #define HIGHERPRIORITYINC (-1) #define HIGHER_OR_SAME_PRIORITY_THAN <= + +/* + * DB_EVENT_LIST() + * + * + */ db_event_list(name) char *name; { - struct dbAddr addr; - int status; - struct event_block *pevent; - register struct dbCommon *precord; + struct db_addr addr; + int status; + struct event_block *pevent; + register struct dbCommon *precord; - status = dbNameToAddr(name, &addr); - if(status==ERROR) - return ERROR; + status = db_name_to_addr(name, &addr); + if(status==ERROR) + return ERROR; - precord = (struct dbCommon *) addr.precord; + precord = (struct dbCommon *) addr.precord; + pevent = (struct event_block *) precord->mlis.node.next; - LOCKREC(precord); - for( pevent = (struct event_block *) precord->mlis.node.next; + if(pevent) + printf("List of events (monitors).\n"); + + LOCKREC(precord); + for( ; pevent; pevent = (struct event_block *) pevent->node.next){ -printf(" ev %x\n",pevent); -printf(" ev que %x\n",pevent->ev_que); -printf(" ev user %x\n",pevent->ev_que->evuser); - logMsg("Event for task %x \n", pevent->ev_que->evuser->taskid); - } - UNLOCKREC(precord); - +#ifdef DEBUG + printf(" ev %x\n",pevent); + printf(" ev que %x\n",pevent->ev_que); + printf(" ev user %x\n",pevent->ev_que->evuser); +#endif + printf( "task %x select %x pfield %x behind by %d\n", + pevent->ev_que->evuser->taskid, + pevent->select, + pevent->paddr->pfield, + pevent->npend); + } + UNLOCKREC(precord); } - + /* - Initialize the event facility for this task - Must be called at least once by each task which uses the db event facility - - returns: - ptr to event user block or NULL if memory can't be allocated -*/ + * DB_INIT_EVENTS() + * + * + * Initialize the event facility for this task. Must be called at least once + * by each task which uses the db event facility + * + * returns: ptr to event user block or NULL if memory can't be allocated + */ struct event_user *db_init_events() { - register struct event_user *evuser; - int logMsg(); + register struct event_user *evuser; + int logMsg(); - evuser = (struct event_user *) malloc(sizeof(*evuser)); - if(!evuser) - return NULL; + evuser = (struct event_user *) calloc(1, sizeof(*evuser)); + if(!evuser) + return NULL; - bfill(evuser, sizeof(*evuser), NULL); - evuser->firstque.evuser = evuser; - FASTLOCKINIT(&(evuser->firstque.writelock)); -/* - init_event_que(&evuser->firstevent); + evuser->firstque.evuser = evuser; + FASTLOCKINIT(&(evuser->firstque.writelock)); - evuser->overflow_sub = NULL; - evuser->overflow_arg = NULL; - evuser->pendlck = FALSE; - evuser->taskid = VXTASKIDSELF; -*/ - - return evuser; + return evuser; } -#ifdef ZEBRA -static -init_event_que(ev_que) -struct event_que *ev_que; -{ - register int i; - - bfill(ev_que, sizeof*ev_que), NULL); - + /* - FASTLOCKINIT(&ev_que->writelock); - semInit(&ev_que->pendsem); - ev_que->putix = 0; - ev_que->getix = 0; - ev_que->queovr = 0; - ev_que->quota = 0; - ev_que->nextque = NULL; - for(i=0; ievque[i] = (struct event_block *) EVENTQEMPTY; -*/ -} -#endif - + * DB_CLOSE_EVENTS() + * + * + */ db_close_events(evuser) register struct event_user *evuser; { - /* - Exit not forced on event blocks for now - - this is left to channel access and any other tasks - using this facility which can find them more efficiently. + /* + * Exit not forced on event blocks for now - this is left to channel + * access and any other tasks using this facility which can find them + * more efficiently. + * + * NOTE: not deleting events before calling this routine could be + * hazardous to the system's health. + */ - NOTE: not deleting events before calling this routine - could be hazardous to the system's health. - */ + evuser->pendexit = TRUE; - evuser->pendexit = TRUE; - - /* notify the waiting task */ - semGive(&evuser->pendsem); + /* notify the waiting task */ + semGive(&evuser->pendsem); - return OK; + return OK; } + /* -So the event block structure size but not structure is exported -(used by those who wish for the event block to be a sub structure) -see pevent != NULL on db_add_event() -*/ + * DB_SIZEOF_EVENT_BLOCK() + * + * + * So the event block structure size but not structure is exported (used by + * those who wish for the event block to be a sub structure) see pevent != + * NULL on db_add_event() + */ db_sizeof_event_block() { - return sizeof(struct event_block); + return sizeof(struct event_block); } + + +/* + * DB_EVENT_GET_FIELD() + * + * + */ +db_event_get_field(paddr, buffer_type, pbuffer, no_elements, pfl) + struct db_addr *paddr; + short buffer_type; + char *pbuffer; + unsigned short no_elements; + db_field_log *pfl; +{ + int status; + + status = db_get_field(paddr,buffer_type,pbuffer,no_elements); + + if (pfl == NULL) return(status); + if (buffer_type >= DBR_STS_STRING && buffer_type <= DBR_CTRL_DOUBLE) { + struct dbr_sts_string *pstatus = (struct dbr_sts_string *) pbuffer; + pstatus->status = pfl->stat; + pstatus->severity = pfl->sevr; + } + if (buffer_type >= DBR_TIME_STRING && buffer_type <= DBR_TIME_DOUBLE) { + struct dbr_time_string *ptime = (struct dbr_time_string *) pbuffer; + ptime->stamp = pfl->time; + } + return(status); + +} + + + +/* + * DB_ADD_EVENT() + * + * + */ db_add_event(evuser, paddr, user_sub, user_arg, select, pevent) register struct event_user *evuser; -register struct dbAddr *paddr; +register struct db_addr *paddr; register void (*user_sub)(); register void *user_arg; register unsigned int select; register struct event_block *pevent; /* ptr to event blk (not required) */ { - register struct dbCommon *precord; - register struct event_que *ev_que; - register struct event_que *tmp_que; + register struct dbCommon *precord; + register struct event_que *ev_que; + register struct event_que *tmp_que; - precord = (struct dbCommon *) paddr->precord; +/* (MDA) in LANL stuff, this used to taskSuspend if invalid address + in new code, the mechanism to help do this checking has been removed + (and replaced)? - /* - Don't add events which will not be triggered - */ - if(!select) - return ERROR; + PADDRCHK(paddr); + */ + precord = (struct dbCommon *) paddr->precord; - /* find an event que block with enough quota */ - /* otherwise add a new one to the list */ - ev_que = &evuser->firstque; - while(TRUE){ - if(ev_que->quota < EVENTQUESIZE - EVENTENTRIES) - break; - if(!ev_que->nextque){ - tmp_que = (struct event_que *) malloc(sizeof(*tmp_que)); - if(!tmp_que) - return ERROR; - bfill(tmp_que, sizeof(*tmp_que), NULL); - tmp_que->evuser = evuser; - ev_que->nextque = tmp_que; - ev_que = tmp_que; - FASTLOCKINIT(&(ev_que->writelock)); - break; - } - ev_que = ev_que->nextque; - } + /* + * Don't add events which will not be triggered + */ + if(!select) + return ERROR; - if(!pevent){ - pevent = (struct event_block *) malloc(sizeof(*pevent)); - if(!pevent) - return ERROR; - } + /* find an event que block with enough quota */ + /* otherwise add a new one to the list */ + ev_que = &evuser->firstque; + while(TRUE){ + if(ev_que->quota < EVENTQUESIZE - EVENTENTRIES) + break; + if(!ev_que->nextque){ + tmp_que = (struct event_que *) + calloc(1, sizeof(*tmp_que)); + if(!tmp_que) + return ERROR; + tmp_que->evuser = evuser; + ev_que->nextque = tmp_que; + ev_que = tmp_que; + FASTLOCKINIT(&(ev_que->writelock)); + break; + } + ev_que = ev_que->nextque; + } - pevent->npend = 0; - pevent->user_sub = user_sub; - pevent->user_arg = user_arg; - pevent->addr = *paddr; - pevent->pfield = (void *) paddr->pfield; /* I modify the one above */ - pevent->select = select; + if(!pevent){ + pevent = (struct event_block *) malloc(sizeof(*pevent)); + if(!pevent) + return ERROR; + } - ev_que->quota += EVENTENTRIES; - pevent->ev_que = ev_que; + pevent->npend = 0; + pevent->user_sub = user_sub; + pevent->user_arg = user_arg; + pevent->paddr = paddr; + pevent->select = select; + ev_que->quota += EVENTENTRIES; + pevent->ev_que = ev_que; - /* - Simple types values queued up for reliable interprocess communication - (for other types they get whatever happens to be there upon wakeup) - */ - if(paddr->no_elements != 1) - pevent->valque = FALSE; - else - switch(paddr->field_type){ - case DBR_UCHAR: - case DBR_SHORT: - case DBR_LONG: - case DBR_ULONG: - case DBR_FLOAT: - case DBR_ENUM: - /* change pfield to point to the value que entry */ - pevent->valque = TRUE; - break; - default: - /* leave pfield pointing to the database */ - pevent->valque = FALSE; - break; - } + /* + * Simple types values queued up for reliable interprocess + * communication (for other types they get whatever happens to be + * there upon wakeup) + */ + if( paddr->no_elements == 1 && + dbr_size[paddr->field_type] <= sizeof(union native_value)) + pevent->valque = TRUE; + else + pevent->valque = FALSE; - LOCKREC(precord); - lstAdd(&precord->mlis, pevent); - UNLOCKREC(precord); - - return OK; + LOCKREC(precord); + lstAdd(&precord->mlis, pevent); + UNLOCKREC(precord); + return OK; } - + /* - This routine does not prevent two threads from deleting one block at - the same time. - - This routine does not deallocate the event block since it normally - will be part of a larger structure. -*/ + * DB_CANCEL_EVENT() + * + * + * This routine does not prevent two threads from deleting one block at the + * same time. + * + * This routine does not deallocate the event block since it normally will be + * part of a larger structure. + */ db_cancel_event(pevent) register struct event_block *pevent; { - register struct dbCommon *precord; - int myprio; - int evprio; + register struct dbCommon *precord; + register int status; +/* (MDA) in LANL stuff, this used to taskSuspend if invalid address + PADDRCHK(pevent->paddr); + */ - /* - Disable this event block - */ - pevent->select = NULL; + precord = (struct dbCommon *) pevent->paddr->precord; - precord = (struct dbCommon *) pevent->addr.precord; + LOCKREC(precord); + /* dont let a misplaced event corrupt the queue */ + status = lstFind( &precord->mlis, pevent); + if(status!=ERROR) + lstDelete( &precord->mlis, pevent); + UNLOCKREC(precord); + if(status == ERROR) + return ERROR; - LOCKREC(precord); - lstDelete( &precord->mlis, pevent); - UNLOCKREC(precord); + /* + * Flush the event que so we know event block not left in use. This + * requires placing a fake event which wakes this thread once the + * event queue has been flushed. This replaces a block of code which + * used to lower priority below the event thread to accomplish the + * flush without polling. + */ + if(pevent->npend){ + struct event_block flush_event; + SEMAPHORE flush_sem; + void wake_cancel(); - /* - Decrement event que quota - */ - pevent->ev_que->quota -= EVENTENTRIES; + semInit(&flush_sem); - /* - Flush the event que so we know event block not left in use - This requires temporarily dropping below the priority of the - event handler. This task will not run again until the - handler has flushed its que. - */ - evprio = pevent->ev_que->evuser->taskpri; - if(taskPriorityGet(VXTASKIDSELF, &myprio)==ERROR) - taskSuspend(VXTASKIDSELF); + flush_event = *pevent; + flush_event.user_sub = wake_cancel; + flush_event.user_arg = &flush_sem; + flush_event.npend = 0; - /* - go to a lower priority than the event handler- if not there allready - */ - if(myprio HIGHER_OR_SAME_PRIORITY_THAN evprio){ - if(taskPrioritySet(VXTASKIDSELF, evprio-HIGHERPRIORITYINC)==ERROR) - taskSuspend(VXTASKIDSELF); + if(db_post_single_event(&flush_event)==OK) + semTake(&flush_sem); - /* - Insure that the que is purged of this event - (in case the event task is pending in a user subroutine) - */ - while(pevent->npend) - taskDelay(10); + /* insurance- incase the event could not be queued */ + while(pevent->npend) + taskDelay(10); + } - /* return to origional priority */ - if(taskPrioritySet(VXTASKIDSELF, myprio)==ERROR) - taskSuspend(VXTASKIDSELF); - } - else - while(pevent->npend) - taskDelay(10); + /* + * Decrement event que quota + */ + pevent->ev_que->quota -= EVENTENTRIES; - return OK; + return OK; } + +/* + * WAKE_CANCEL() + * + * a very short routine to inform a db_clear thread that the deleted event + * has been flushed + */ +static void wake_cancel(sem) +SEMAPHORE *sem; +{ + semGive(sem); +} -/* - Specify a routine to be executed for event que overflow condition -*/ + +/* + * DB_ADD_OVERFLOW_EVENT() + * + * Specify a routine to be executed for event que overflow condition + */ db_add_overflow_event(evuser, overflow_sub, overflow_arg) register struct event_user *evuser; register void (*overflow_sub)(); register void *overflow_arg; { - evuser->overflow_sub = overflow_sub; - evuser->overflow_arg = overflow_arg; + evuser->overflow_sub = overflow_sub; + evuser->overflow_arg = overflow_arg; - return OK; + return OK; } - + +/* + * DB_POST_SINGLE_EVENT() + * + * + */ db_post_single_event(pevent) -register struct event_block *pevent; +register struct event_block *pevent; { - register struct event_que *ev_que = pevent->ev_que; - register unsigned int putix; + register struct event_que *ev_que = pevent->ev_que; + int success = FALSE; + struct dbCommon *precord; + register unsigned int putix; - /* - evuser ring buffer must be locked for the multiple - threads writing to it - */ - LOCKEVQUE(ev_que) - putix = ev_que->putix; + precord = (struct dbCommon *) pevent->paddr->precord; - /* add to task local event que */ - if(ev_que->evque[putix] == EVENTQEMPTY){ - pevent->npend++; - ev_que->evque[putix] = pevent; - ev_que->valque[putix] = *(union native_value *)pevent->pfield; + /* + * evuser ring buffer must be locked for the multiple threads writing + * to it + */ + LOCKEVQUE(ev_que) + putix = ev_que->putix; - /* notify the event handler */ - semGive(&ev_que->evuser->pendsem); - ev_que->putix = RNGINC(putix); - } - else - ev_que->evuser->queovr++; + /* add to task local event que */ + if(ev_que->evque[putix] == EVENTQEMPTY){ + pevent->npend++; + ev_que->evque[putix] = pevent; + ev_que->valque[putix].stat = precord->stat; + ev_que->valque[putix].sevr = precord->sevr; + ev_que->valque[putix].time = precord->time; + /* + * use bcopy to avoid a bus error on + * union copy of char in the db at an odd + * address + */ + bcopy( pevent->paddr->pfield, + &ev_que->valque[putix].field, + dbr_size[pevent->paddr->field_type]); - UNLOCKEVQUE(ev_que) + /* notify the event handler */ + semGive(&ev_que->evuser->pendsem); + ev_que->putix = RNGINC(putix); + success = TRUE; + } + else + ev_que->evuser->queovr++; - return OK; + UNLOCKEVQUE(ev_que) + + if(success) + return OK; + else + return ERROR; } + +/* + * DB_POST_EVENTS() + * + * + */ db_post_events(precord,pvalue,select) register struct dbCommon *precord; register union native_value *pvalue; register unsigned int select; { - register struct event_block *event; - register struct event_que *ev_que; - register unsigned int putix; + register struct event_block *event; + register struct event_que *ev_que; + register unsigned int putix; - LOCKREC(precord); + LOCKREC(precord); - for( event = (struct event_block *) precord->mlis.node.next; - event; - event = (struct event_block *) event->node.next){ + for( event = (struct event_block *) precord->mlis.node.next; + event; + event = (struct event_block *) event->node.next){ - ev_que = event->ev_que; - /* - Only send event msg if they are waiting on the field which changed - */ - if( (event->pfield == (void *)pvalue) && (select & event->select) ){ - /* - evuser ring buffer must be locked for the multiple - threads writing to it - */ - LOCKEVQUE(ev_que) - putix = ev_que->putix; + ev_que = event->ev_que; - /* add to task local event que */ - if(ev_que->evque[putix] == EVENTQEMPTY){ + /* + * Only send event msg if they are waiting on the field which + * changed + */ + if( (event->paddr->pfield == (void *)pvalue) && + (select & event->select) ){ - event->npend++; - ev_que->evque[putix] = event; - ev_que->valque[putix] = *pvalue; + /* + * evuser ring buffer must be locked for the multiple + * threads writing to it + */ - /* notify the event handler */ - semGive(&ev_que->evuser->pendsem); + LOCKEVQUE(ev_que) + putix = ev_que->putix; - ev_que->putix = RNGINC(putix); - } - else - ev_que->evuser->queovr++; + /* add to task local event que */ + if(ev_que->evque[putix] == EVENTQEMPTY){ - UNLOCKEVQUE(ev_que) + event->npend++; + ev_que->evque[putix] = event; + ev_que->valque[putix].stat = precord->stat; + ev_que->valque[putix].sevr = precord->sevr; + ev_que->valque[putix].time = precord->time; - } + /* + * use bcopy to avoid a bus error on + * union copy of char in the db at an odd + * address + */ + bcopy( pvalue, + &ev_que->valque[putix].field, + dbr_size[event->paddr->field_type]); + + /* notify the event handler */ + semGive(&ev_que->evuser->pendsem); + + ev_que->putix = RNGINC(putix); + } + else + ev_que->evuser->queovr++; + + UNLOCKEVQUE(ev_que) + + } - } + } - UNLOCKREC(precord); - return OK; + UNLOCKREC(precord); + return OK; } - + +/* + * DB_START_EVENTS() + * + */ db_start_events(evuser,taskname,init_func,init_func_arg) struct event_user *evuser; char *taskname; /* defaulted if NULL */ void (*init_func)(); int init_func_arg; { - int myprio; - int status; - int event_task(); + int myprio; + int status; + int event_task(); - /* only one ca_pend_event thread may be started for each evuser ! */ - while(!vxTas(&evuser->pendlck)) - return ERROR; + /* only one ca_pend_event thread may be started for each evuser ! */ + while(!vxTas(&evuser->pendlck)) + return ERROR; - status = taskPriorityGet(VXTASKIDSELF, &evuser->taskpri); - if(status == ERROR) - return ERROR; + status = taskPriorityGet(VXTASKIDSELF, &evuser->taskpri); + if(status == ERROR) + return ERROR; - evuser->taskpri += HIGHERPRIORITYINC; + evuser->taskpri += HIGHERPRIORITYINC; - evuser->pendexit = FALSE; + evuser->pendexit = FALSE; - if(!taskname) - taskname = EVENT_PEND_NAME; - status = - taskSpawn( taskname, + if(!taskname) + taskname = EVENT_PEND_NAME; + status = + taskSpawn( + taskname, evuser->taskpri, EVENT_PEND_OPT, EVENT_PEND_STACK, @@ -548,131 +702,156 @@ int init_func_arg; evuser, init_func, init_func_arg); - if(status == ERROR) - return ERROR; + if(status == ERROR) + return ERROR; - evuser->taskid = status; + evuser->taskid = status; - return OK; + return OK; } + +/* + * EVENT_TASK() + * + */ event_task(evuser, init_func, init_func_arg) register struct event_user *evuser; register void (*init_func)(); register int init_func_arg; { - register struct event_que *ev_que; + register struct event_que *ev_que; - /* init hook */ - if(init_func) - (*init_func)(init_func_arg); + /* init hook */ + if(init_func) + (*init_func)(init_func_arg); - /* - No need to lock getix as I only allow one thread to call this routine at a time - */ - do{ - semTake(&evuser->pendsem); + /* + * No need to lock getix as I only allow one thread to call this + * routine at a time + */ + do{ + semTake(&evuser->pendsem); - for(ev_que= &evuser->firstque; ev_que; ev_que = ev_que->nextque) - event_read(ev_que); + for( ev_que= &evuser->firstque; + ev_que; + ev_que = ev_que->nextque) - /* - The following do not introduce event latency since they are - not between notification and posting events. - */ - if(evuser->queovr){ - if(evuser->overflow_sub) - (*evuser->overflow_sub)(evuser->overflow_arg, evuser->queovr); - else - logMsg("Events lost, discard count was %d\n",evuser->queovr); - evuser->queovr = 0; - } + event_read(ev_que); - }while(!evuser->pendexit); + /* + * The following do not introduce event latency since they + * are not between notification and posting events. + */ + if(evuser->queovr){ + if(evuser->overflow_sub) + (*evuser->overflow_sub)( + evuser->overflow_arg, + evuser->queovr); + else + logMsg("Events lost, discard count was %d\n", + evuser->queovr); + evuser->queovr = 0; + } - evuser->pendlck = FALSE; + }while(!evuser->pendexit); - /* joh- added this code to free additional event ques */ - { - struct event_que *nextque; - for(ev_que = evuser->firstque.nextque; ev_que; ev_que = nextque){ - nextque = ev_que->nextque; - if(free(ev_que)) - logMsg("evtsk: event user sub que free fail\n"); - } - } - /* end added code */ + evuser->pendlck = FALSE; - if(free(evuser)) - logMsg("evtsk: evuser free fail\n"); + /* joh- added this code to free additional event queues */ + { + struct event_que *nextque; + for( ev_que = evuser->firstque.nextque; + ev_que; + ev_que = nextque){ - return OK; + nextque = ev_que->nextque; + if(free(ev_que)) + logMsg("evtsk: sub queue free fail\n"); + } + } + /* end added code */ + + if(free(evuser)) + logMsg("evtsk: evuser free fail\n"); + + return OK; } - + +/* + * EVENT_READ() + * + */ event_read(ev_que) register struct event_que *ev_que; { - register struct event_block *event; - register unsigned int getix; - register unsigned int nextgetix; - register struct dbAddr *paddr; - register char *pfield; - - /* - Fetch fast register copy - */ - getix = ev_que->getix; - - /* - No need to lock getix as I only allow one thread to call this routine at a time - */ - - for( event=ev_que->evque[getix]; - (event) != EVENTQEMPTY; - getix = nextgetix, event = ev_que->evque[nextgetix]){ - - /* - So I can tell em if more are comming - */ - nextgetix = RNGINC(getix); - - paddr = &event->addr; - - /* - Simple type values queued up for reliable interprocess communication. - (for other types they get whatever happens to be there upon wakeup) - */ - if(event->valque) - paddr->pfield = (char *) &ev_que->valque[getix]; + register struct event_block *event; + register unsigned int getix; + register unsigned int nextgetix; + db_field_log *pfl; - /* - Next event pointer can be used by event tasks to determine - if more events are waiting in the queue - */ - (*event->user_sub)( event->user_arg, - paddr, - ev_que->evque[nextgetix]); /* NULL if no next event */ + /* + * Fetch fast register copy + */ + getix = ev_que->getix; - ev_que->evque[getix] = (struct event_block *) NULL; - event->npend--; + /* + * No need to lock getix as I only allow one thread to call this + * routine at a time + */ - } + for( event=ev_que->evque[getix]; + (event) != EVENTQEMPTY; + getix = nextgetix, event = ev_que->evque[nextgetix]){ - /* - Store back to RAM copy - */ - ev_que->getix = getix; + /* + * So I can tell em if more are comming + */ - return OK; + nextgetix = RNGINC(getix); + + + /* + * Simple type values queued up for reliable interprocess + * communication. (for other types they get whatever happens + * to be there upon wakeup) + */ + if(event->valque) + pfl = &ev_que->valque[getix]; + else + pfl = NULL; + + /* + * Next event pointer can be used by event tasks to determine + * if more events are waiting in the queue + */ + (*event->user_sub)( + event->user_arg, + event->paddr, + /* NULL if no next event */ + ev_que->evque[nextgetix], + pfl); + + ev_que->evque[getix] = (struct event_block *) NULL; + event->npend--; + + } + + /* + * Store back to RAM copy + */ + ev_que->getix = getix; + + return OK; } -#ifdef ZEBRA +#ifdef JUNKYARD struct event_user *tevuser; -struct dbAddr taddr; +struct db_addr taddr; db_test_event(precord_name) @@ -684,10 +863,13 @@ register char *precord_name; if(!tevuser){ tevuser = db_init_events(); - status = dbNameToAddr(precord_name, &taddr); + status = db_name_to_addr(precord_name, &taddr); if(status==ERROR) return ERROR; +/* (MDA) in LANL stuff, this used to taskSuspend if invalid address + PADDRCHK(&taddr); + */ status = db_start_events(tevuser); if(status==ERROR) diff --git a/src/db/db_access.c b/src/db/db_access.c index 425dc8bb3..27183d94d 100644 --- a/src/db/db_access.c +++ b/src/db/db_access.c @@ -2,6 +2,15 @@ /* db_access.c */ /* share/src/db $Id$ */ /* db_access.c - Interface between old database access and new */ +/* + + +/*** + *** note: the order of the DBR_... elements in the "new" structures + *** in db_get_field() is important - and must correspond to + *** the presumed order in dbAccess.c's dbGetField() routine + ***/ + #include #include @@ -12,45 +21,110 @@ #include #include +#include + #ifndef NULL #define NULL 0 #endif + #define oldDBF_STRING 0 #define oldDBF_INT 1 +#define oldDBF_SHORT 1 #define oldDBF_FLOAT 2 #define oldDBF_ENUM 3 -#define oldDBF_NO_ACCESS 4 +#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_FLOAT oldDBF_FLOAT -#define oldDBR_ENUM oldDBF_ENUM -#define oldDBR_STS_STRING 4 -#define oldDBR_STS_INT 5 -#define oldDBR_STS_FLOAT 6 -#define oldDBR_STS_ENUM 7 -#define oldDBR_GR_INT 8 -#define oldDBR_GR_FLOAT 9 -#define oldDBR_CTRL_INT 10 -#define oldDBR_CTRL_FLOAT 11 -#define oldDBR_CTRL_ENUM 12 +#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 -/* structures for old database access*/ + +/* function declarations */ +static adjust_severity(); + + +/* database access address structure (removed from db_access.h and put here) */ +struct db_addr{ + char *precord; /* record number of specified type */ + char *pfield; /* offset from the record origin */ + char *pad0; /* not used by old */ + short pad1; /*not used by old */ + short no_elements; /* number of elements in arrays of data */ + short record_type; /* type of record being accessed */ + short pad2; /* not used by old */ + short field_size; /* size of the field being accessed */ + /* from database for values of waveforms */ + short special; /* special processing */ + short choice_set; /* index of choiceSet GBLCHOICE & RECCHOICE*/ + short field_type; /* field type as seen by database request*/ + /*DBR_STRING,...,DBR_ENUM,DBR_NOACCESS*/ +}; + + + +/* structures for old database access */ + +/* VALUES WITH STATUS STRUCTURES */ + /* structure for a string status field */ struct dbr_sts_string{ short status; /* status of value */ short severity; /* severity of alarm */ - char value[MAX_STRING_SIZE]; /* current value */ + char value[MAX_STRING_SIZE]; /* current value */ }; -/* structure for an integer status field */ +/* structure for an short status field */ struct dbr_sts_int{ short status; /* status of value */ short severity; /* severity of alarm */ short value; /* current value */ }; +struct dbr_sts_short{ + short status; /* status of value */ + short severity; /* severity of alarm */ + short value; /* current value */ +}; /* structure for a float status field */ struct dbr_sts_float{ @@ -66,10 +140,91 @@ struct dbr_sts_enum{ short value; /* current value */ }; - +/* structure for a char status field */ +struct dbr_sts_char{ + short status; /* status of value */ + short severity; /* severity of alarm */ + unsigned char value; /* current value */ +}; +/* structure for a long status field */ +struct dbr_sts_long{ + short status; /* status of value */ + short severity; /* severity of alarm */ + long value; /* current value */ +}; -/* structure for a graphic integer field */ +/* structure for a double status field */ +struct dbr_sts_double{ + short status; /* status of value */ + short severity; /* severity of alarm */ + double value; /* current value */ +}; + +/* VALUES WITH STATUS AND TIME STRUCTURES */ + +/* structure for a string time field */ +struct dbr_time_string{ + short status; /* status of value */ + short severity; /* severity of alarm */ + TS_STAMP stamp; /* time stamp */ + char value[MAX_STRING_SIZE]; /* current value */ +}; + +/* structure for an short time field */ +struct dbr_time_short{ + short status; /* status of value */ + short severity; /* severity of alarm */ + TS_STAMP stamp; /* time stamp */ + short value; /* current value */ +}; + +/* structure for a float time field */ +struct dbr_time_float{ + short status; /* status of value */ + short severity; /* severity of alarm */ + TS_STAMP stamp; /* time stamp */ + float value; /* current value */ +}; + +/* structure for a enum time field */ +struct dbr_time_enum{ + short status; /* status of value */ + short severity; /* severity of alarm */ + TS_STAMP stamp; /* time stamp */ + short value; /* current value */ +}; + +/* structure for a char time field */ +struct dbr_time_char{ + short status; /* status of value */ + short severity; /* severity of alarm */ + TS_STAMP stamp; /* time stamp */ + unsigned char value; /* current value */ +}; + +/* structure for a long time field */ +struct dbr_time_long{ + short status; /* status of value */ + short severity; /* severity of alarm */ + TS_STAMP stamp; /* time stamp */ + long value; /* current value */ +}; + +/* structure for a double time field */ +struct dbr_time_double{ + short status; /* status of value */ + short severity; /* severity of alarm */ + TS_STAMP stamp; /* time stamp */ + double value; /* current value */ +}; + +/* VALUES WITH STATUS AND GRAPHIC STRUCTURES */ + +/* structure for a graphic string */ + /* not implemented; use struct_dbr_sts_string */ + +/* structure for a graphic short field */ struct dbr_gr_int{ short status; /* status of value */ short severity; /* severity of alarm */ @@ -82,6 +237,18 @@ struct dbr_gr_int{ short lower_alarm_limit; short value; /* current value */ }; +struct dbr_gr_short{ + short status; /* status of value */ + short severity; /* severity of alarm */ + char units[8]; /* units of value */ + short upper_disp_limit; /* upper limit of graph */ + short lower_disp_limit; /* lower limit of graph */ + short upper_alarm_limit; + short upper_warning_limit; + short lower_warning_limit; + short lower_alarm_limit; + short value; /* current value */ +}; /* structure for a graphic floating point field */ struct dbr_gr_float{ @@ -98,6 +265,63 @@ struct dbr_gr_float{ float value; /* current value */ }; +/* structure for a graphic enumeration field */ +struct dbr_gr_enum{ + short status; /* status of value */ + short severity; /* severity of alarm */ + short no_str; /* number of strings */ + char strs[16][26]; /* state strings */ + short value; /* current value */ +}; + +/* structure for a graphic char field */ +struct dbr_gr_char{ + short status; /* status of value */ + short severity; /* severity of alarm */ + char units[8]; /* units of value */ + unsigned char upper_disp_limit; /* upper limit of graph */ + unsigned char lower_disp_limit; /* lower limit of graph */ + unsigned char upper_alarm_limit; + unsigned char upper_warning_limit; + unsigned char lower_warning_limit; + unsigned char lower_alarm_limit; + unsigned char value; /* current value */ +}; + +/* structure for a graphic long field */ +struct dbr_gr_long{ + short status; /* status of value */ + short severity; /* severity of alarm */ + char units[8]; /* units of value */ + long upper_disp_limit; /* upper limit of graph */ + long lower_disp_limit; /* lower limit of graph */ + long upper_alarm_limit; + long upper_warning_limit; + long lower_warning_limit; + long lower_alarm_limit; + long value; /* current value */ +}; + +/* structure for a graphic double field */ +struct dbr_gr_double{ + short status; /* status of value */ + short severity; /* severity of alarm */ + short precision; /* number of decimal places */ + char units[8]; /* units of value */ + double upper_disp_limit; /* upper limit of graph */ + double lower_disp_limit; /* lower limit of graph */ + double upper_alarm_limit; + double upper_warning_limit; + double lower_warning_limit; + double lower_alarm_limit; + double value; /* current value */ +}; + +/* VALUES WITH STATUS, GRAPHIC and CONTROL STRUCTURES */ + +/* structure for a control string */ + /* not implemented; use struct_dbr_sts_string */ + /* structure for a control integer */ struct dbr_ctrl_int{ short status; /* status of value */ @@ -113,6 +337,20 @@ struct dbr_ctrl_int{ short lower_ctrl_limit; /* lower control limit */ short value; /* current value */ }; +struct dbr_ctrl_short{ + short status; /* status of value */ + short severity; /* severity of alarm */ + char units[8]; /* units of value */ + short upper_disp_limit; /* upper limit of graph */ + short lower_disp_limit; /* lower limit of graph */ + short upper_alarm_limit; + short upper_warning_limit; + short lower_warning_limit; + short lower_alarm_limit; + short upper_ctrl_limit; /* upper control limit */ + short lower_ctrl_limit; /* lower control limit */ + short value; /* current value */ +}; /* structure for a control floating point field */ struct dbr_ctrl_float{ @@ -140,6 +378,56 @@ struct dbr_ctrl_enum{ short value; /* current value */ }; +/* structure for a control char field */ +struct dbr_ctrl_char{ + short status; /* status of value */ + short severity; /* severity of alarm */ + char units[8]; /* units of value */ + unsigned char upper_disp_limit; /* upper limit of graph */ + unsigned char lower_disp_limit; /* lower limit of graph */ + unsigned char upper_alarm_limit; + unsigned char upper_warning_limit; + unsigned char lower_warning_limit; + unsigned char lower_alarm_limit; + unsigned char upper_ctrl_limit; /* upper control limit */ + unsigned char lower_ctrl_limit; /* lower control limit */ + unsigned char value; /* current value */ +}; + +/* structure for a control long field */ +struct dbr_ctrl_long{ + short status; /* status of value */ + short severity; /* severity of alarm */ + char units[8]; /* units of value */ + long upper_disp_limit; /* upper limit of graph */ + long lower_disp_limit; /* lower limit of graph */ + long upper_alarm_limit; + long upper_warning_limit; + long lower_warning_limit; + long lower_alarm_limit; + long upper_ctrl_limit; /* upper control limit */ + long lower_ctrl_limit; /* lower control limit */ + long value; /* current value */ +}; + +/* structure for a control double field */ +struct dbr_ctrl_double{ + short status; /* status of value */ + short severity; /* severity of alarm */ + short precision; /* number of decimal places */ + char units[8]; /* units of value */ + double upper_disp_limit; /* upper limit of graph */ + double lower_disp_limit; /* lower limit of graph */ + double upper_alarm_limit; + double upper_warning_limit; + double lower_warning_limit; + double lower_alarm_limit; + double upper_ctrl_limit; /* upper control limit */ + double lower_ctrl_limit; /* lower control limit */ + double value; /* current value */ +}; + + /* From $cs/dblib/src/dbiocsubs.c * subroutines @@ -231,11 +519,11 @@ new_alarm(){ /* * DB_NAME_TO_ADDR */ -static short mapNewToOld[]={0,1,1,1,1,2,2,3,4}; +static short mapNewToOld[]={0,1,1,1,1,5,5,2,6,3,7}; db_name_to_addr(pname,paddr) -register char *pname; -register struct dbAddr *paddr; + char *pname; + struct dbAddr *paddr; { long status; short ftype; @@ -275,7 +563,8 @@ unsigned short no_elements; nRequest=no_elements; status = dbGetField(paddr,DBR_STRING,pbuffer,&options,&nRequest); break; - case(oldDBR_INT): +/* case(oldDBR_INT): */ + case(oldDBR_SHORT): options=0; nRequest=no_elements; status = dbGetField(paddr,DBR_SHORT,pbuffer,&options,&nRequest); @@ -290,7 +579,24 @@ unsigned short no_elements; nRequest=no_elements; status = dbGetField(paddr,DBR_ENUM,pbuffer,&options,&nRequest); break; + case(oldDBR_CHAR): + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_CHAR,pbuffer,&options,&nRequest); + break; + case(oldDBR_LONG): + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_LONG,pbuffer,&options,&nRequest); + break; + case(oldDBR_DOUBLE): + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_DOUBLE,pbuffer,&options,&nRequest); + break; case(oldDBR_STS_STRING): + case(oldDBR_GR_STRING): + case(oldDBR_CTRL_STRING): { struct dbr_sts_string *pold = (struct dbr_sts_string *)pbuffer; struct { @@ -305,10 +611,12 @@ unsigned short no_elements; adjust_severity(pbuffer); options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_STRING,&(pold->value[0]),&options,&nRequest); + status = dbGetField(paddr,DBR_STRING,&(pold->value[0]), + &options,&nRequest); } break; - case(oldDBR_STS_INT): +/* case(oldDBR_STS_INT): */ + case(oldDBR_STS_SHORT): { struct dbr_sts_int *pold = (struct dbr_sts_int *)pbuffer; struct { @@ -323,7 +631,8 @@ unsigned short no_elements; adjust_severity(pbuffer); options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_SHORT,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_SHORT,&(pold->value),&options, + &nRequest); } break; case(oldDBR_STS_FLOAT): @@ -341,7 +650,8 @@ unsigned short no_elements; adjust_severity(pbuffer); options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_FLOAT,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_FLOAT,&(pold->value),&options, + &nRequest); } break; case(oldDBR_STS_ENUM): @@ -359,10 +669,218 @@ unsigned short no_elements; adjust_severity(pbuffer); options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_ENUM,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_ENUM,&(pold->value),&options, + &nRequest); } break; - case(oldDBR_GR_INT): + case(oldDBR_STS_CHAR): + { + struct dbr_sts_char *pold = (struct dbr_sts_char *)pbuffer; + struct { + DBRstatus + } new; + + options=DBR_STATUS; + nRequest=0; + status = dbGetField(paddr,DBR_UCHAR,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_UCHAR,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_STS_LONG): + { + struct dbr_sts_long *pold = (struct dbr_sts_long *)pbuffer; + struct { + DBRstatus + } new; + + options=DBR_STATUS; + nRequest=0; + status = dbGetField(paddr,DBR_LONG,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_LONG,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_STS_DOUBLE): + { + struct dbr_sts_double *pold = (struct dbr_sts_double *)pbuffer; + struct { + DBRstatus + } new; + + options=DBR_STATUS; + nRequest=0; + status = dbGetField(paddr,DBR_DOUBLE,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_DOUBLE,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_TIME_STRING): + { + struct dbr_time_string *pold=(struct dbr_time_string *)pbuffer; + struct { + DBRstatus + DBRtime + } new; + + options=DBR_STATUS | DBR_TIME; + nRequest=0; + status = dbGetField(paddr,DBR_STRING,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + pold->stamp = new.time; /* structure copy */ + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_STRING,pold->value,&options, + &nRequest); + } + break; +/* case(oldDBR_TIME_INT): */ + case(oldDBR_TIME_SHORT): + { + struct dbr_time_short *pold=(struct dbr_time_short *)pbuffer; + struct { + DBRstatus + DBRtime + } new; + + options=DBR_STATUS | DBR_TIME; + nRequest=0; + status = dbGetField(paddr,DBR_SHORT,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + pold->stamp = new.time; /* structure copy */ + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_SHORT,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_TIME_FLOAT): + { + struct dbr_time_float *pold=(struct dbr_time_float *)pbuffer; + struct { + DBRstatus + DBRtime + } new; + + options=DBR_STATUS | DBR_TIME; + nRequest=0; + status = dbGetField(paddr,DBR_FLOAT,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + pold->stamp = new.time; /* structure copy */ + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_FLOAT,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_TIME_ENUM): + { + struct dbr_time_enum *pold=(struct dbr_time_enum *)pbuffer; + struct { + DBRstatus + DBRtime + } new; + + options=DBR_STATUS | DBR_TIME; + nRequest=0; + status = dbGetField(paddr,DBR_ENUM,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + pold->stamp = new.time; /* structure copy */ + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_ENUM,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_TIME_CHAR): + { + struct dbr_time_char *pold=(struct dbr_time_char *)pbuffer; + struct { + DBRstatus + DBRtime + } new; + + options=DBR_STATUS | DBR_TIME; + nRequest=0; + status = dbGetField(paddr,DBR_CHAR,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + pold->stamp = new.time; /* structure copy */ + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_CHAR,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_TIME_LONG): + { + struct dbr_time_long *pold=(struct dbr_time_long *)pbuffer; + struct { + DBRstatus + DBRtime + } new; + + options=DBR_STATUS | DBR_TIME; + nRequest=0; + status = dbGetField(paddr,DBR_LONG,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + pold->stamp = new.time; /* structure copy */ + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_LONG,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_TIME_DOUBLE): + { + struct dbr_time_double *pold=(struct dbr_time_double *)pbuffer; + struct { + DBRstatus + DBRtime + } new; + + options=DBR_STATUS | DBR_TIME; + nRequest=0; + status = dbGetField(paddr,DBR_DOUBLE,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + pold->stamp = new.time; /* structure copy */ + adjust_severity(pbuffer); + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_DOUBLE,&(pold->value),&options, + &nRequest); + } + break; +/* case(oldDBR_GR_STRING): NOT IMPLEMENTED - use DBR_STS_STRING */ +/* case(oldDBR_GR_INT): */ + case(oldDBR_GR_SHORT): { struct dbr_gr_int *pold = (struct dbr_gr_int *)pbuffer; struct { @@ -387,7 +905,8 @@ unsigned short no_elements; pold->lower_alarm_limit = new.lower_alarm_limit; options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_SHORT,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_SHORT,&(pold->value),&options, + &nRequest); } break; case(oldDBR_GR_FLOAT): @@ -401,7 +920,8 @@ unsigned short no_elements; DBRalDouble } new; - options=DBR_STATUS|DBR_UNITS|DBR_PRECISION|DBR_GR_DOUBLE|DBR_AL_DOUBLE; + options=DBR_STATUS|DBR_UNITS|DBR_PRECISION|DBR_GR_DOUBLE + |DBR_AL_DOUBLE; nRequest=0; status = dbGetField(paddr,DBR_FLOAT,&new,&options,&nRequest); pold->status = new.status; @@ -417,10 +937,103 @@ unsigned short no_elements; pold->lower_alarm_limit = new.lower_alarm_limit; options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_FLOAT,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_FLOAT,&(pold->value),&options, + &nRequest); } break; - case(oldDBR_CTRL_INT): +/* case(oldDBR_GR_ENUM): see oldDBR_CTRL_ENUM */ + case(oldDBR_GR_CHAR): + { + struct dbr_gr_char *pold = (struct dbr_gr_char *)pbuffer; + struct { + DBRstatus + DBRunits + DBRgrLong + DBRalLong + } new; + + options=DBR_STATUS|DBR_UNITS|DBR_GR_LONG|DBR_AL_LONG; + nRequest=0; + status = dbGetField(paddr,DBR_UCHAR,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + strncpy(pold->units,new.units,8); + pold->upper_disp_limit = new.upper_disp_limit; + pold->lower_disp_limit = new.lower_disp_limit; + pold->upper_alarm_limit = new.upper_alarm_limit; + pold->upper_warning_limit = new.upper_warning_limit; + pold->lower_warning_limit = new.lower_warning_limit; + pold->lower_alarm_limit = new.lower_alarm_limit; + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_UCHAR,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_GR_LONG): + { + struct dbr_gr_long *pold = (struct dbr_gr_long *)pbuffer; + struct { + DBRstatus + DBRunits + DBRgrLong + DBRalLong + } new; + + options=DBR_STATUS|DBR_UNITS|DBR_GR_LONG|DBR_AL_LONG; + nRequest=0; + status = dbGetField(paddr,DBR_LONG,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + strncpy(pold->units,new.units,8); + pold->upper_disp_limit = new.upper_disp_limit; + pold->lower_disp_limit = new.lower_disp_limit; + pold->upper_alarm_limit = new.upper_alarm_limit; + pold->upper_warning_limit = new.upper_warning_limit; + pold->lower_warning_limit = new.lower_warning_limit; + pold->lower_alarm_limit = new.lower_alarm_limit; + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_LONG,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_GR_DOUBLE): + { + struct dbr_gr_double *pold = (struct dbr_gr_double *)pbuffer; + struct { + DBRstatus + DBRunits + DBRprecision + DBRgrDouble + DBRalDouble + } new; + + options=DBR_STATUS|DBR_UNITS|DBR_PRECISION|DBR_GR_DOUBLE + |DBR_AL_DOUBLE; + nRequest=0; + status = dbGetField(paddr,DBR_DOUBLE,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + pold->precision = new.precision; + strncpy(pold->units,new.units,8); + pold->upper_disp_limit = new.upper_disp_limit; + pold->lower_disp_limit = new.lower_disp_limit; + pold->upper_alarm_limit = new.upper_alarm_limit; + pold->upper_warning_limit = new.upper_warning_limit; + pold->lower_warning_limit = new.lower_warning_limit; + pold->lower_alarm_limit = new.lower_alarm_limit; + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_DOUBLE,&(pold->value),&options, + &nRequest); + } + break; +/* case(oldDBR_CTRL_INT): */ + case(oldDBR_CTRL_SHORT): { struct dbr_ctrl_int *pold = (struct dbr_ctrl_int *)pbuffer; struct { @@ -431,7 +1044,8 @@ unsigned short no_elements; DBRalLong } new; - options=DBR_STATUS|DBR_UNITS|DBR_GR_LONG|DBR_CTRL_LONG|DBR_AL_LONG; + options=DBR_STATUS|DBR_UNITS|DBR_GR_LONG|DBR_CTRL_LONG + |DBR_AL_LONG; nRequest=0; status = dbGetField(paddr,DBR_SHORT,&new,&options,&nRequest); pold->status = new.status; @@ -448,7 +1062,8 @@ unsigned short no_elements; pold->lower_ctrl_limit = new.lower_ctrl_limit; options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_SHORT,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_SHORT,&(pold->value),&options, + &nRequest); } break; case(oldDBR_CTRL_FLOAT): @@ -463,7 +1078,8 @@ unsigned short no_elements; DBRalDouble } new; - options=DBR_STATUS|DBR_UNITS|DBR_PRECISION|DBR_GR_DOUBLE|DBR_CTRL_DOUBLE|DBR_AL_DOUBLE; + options=DBR_STATUS|DBR_UNITS|DBR_PRECISION|DBR_GR_DOUBLE + |DBR_CTRL_DOUBLE|DBR_AL_DOUBLE; nRequest=0; status = dbGetField(paddr,DBR_FLOAT,&new,&options,&nRequest); pold->status = new.status; @@ -481,9 +1097,11 @@ unsigned short no_elements; pold->lower_ctrl_limit = new.lower_ctrl_limit; options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_FLOAT,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_FLOAT,&(pold->value),&options, + &nRequest); } break; + case(oldDBR_GR_ENUM): case(oldDBR_CTRL_ENUM): { struct dbr_ctrl_enum *pold = (struct dbr_ctrl_enum *)pbuffer; @@ -503,13 +1121,118 @@ unsigned short no_elements; if(no_str>16) no_str=16; pold->no_str = no_str; for (i=0; istrs[i],new.strs[i],sizeof(pold->strs[i])); + strncpy(pold->strs[i],new.strs[i], + sizeof(pold->strs[i])); /*now get values*/ options=0; nRequest=no_elements; - status = dbGetField(paddr,DBR_ENUM,&(pold->value),&options,&nRequest); + status = dbGetField(paddr,DBR_ENUM,&(pold->value),&options, + &nRequest); } break; + case(oldDBR_CTRL_CHAR): + { + struct dbr_ctrl_char *pold = (struct dbr_ctrl_char *)pbuffer; + struct { + DBRstatus + DBRunits + DBRgrLong + DBRctrlLong + DBRalLong + } new; + + options=DBR_STATUS|DBR_UNITS|DBR_GR_LONG|DBR_CTRL_LONG + |DBR_AL_LONG; + nRequest=0; + status = dbGetField(paddr,DBR_UCHAR,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + strncpy(pold->units,new.units,8); + pold->upper_disp_limit = new.upper_disp_limit; + pold->lower_disp_limit = new.lower_disp_limit; + pold->upper_alarm_limit = new.upper_alarm_limit; + pold->upper_warning_limit = new.upper_warning_limit; + pold->lower_warning_limit = new.lower_warning_limit; + pold->lower_alarm_limit = new.lower_alarm_limit; + pold->upper_ctrl_limit = new.upper_ctrl_limit; + pold->lower_ctrl_limit = new.lower_ctrl_limit; + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_UCHAR,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_CTRL_LONG): + { + struct dbr_ctrl_long *pold = (struct dbr_ctrl_long *)pbuffer; + struct { + DBRstatus + DBRunits + DBRgrLong + DBRctrlLong + DBRalLong + } new; + + options=DBR_STATUS|DBR_UNITS|DBR_GR_LONG|DBR_CTRL_LONG + |DBR_AL_LONG; + nRequest=0; + status = dbGetField(paddr,DBR_LONG,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + strncpy(pold->units,new.units,8); + pold->upper_disp_limit = new.upper_disp_limit; + pold->lower_disp_limit = new.lower_disp_limit; + pold->upper_alarm_limit = new.upper_alarm_limit; + pold->upper_warning_limit = new.upper_warning_limit; + pold->lower_warning_limit = new.lower_warning_limit; + pold->lower_alarm_limit = new.lower_alarm_limit; + pold->upper_ctrl_limit = new.upper_ctrl_limit; + pold->lower_ctrl_limit = new.lower_ctrl_limit; + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_LONG,&(pold->value),&options, + &nRequest); + } + break; + case(oldDBR_CTRL_DOUBLE): + { + struct dbr_ctrl_double *pold=(struct dbr_ctrl_double *)pbuffer; + struct { + DBRstatus + DBRunits + DBRprecision + DBRgrDouble + DBRctrlDouble + DBRalDouble + } new; + + options=DBR_STATUS|DBR_UNITS|DBR_PRECISION|DBR_GR_DOUBLE + |DBR_CTRL_DOUBLE|DBR_AL_DOUBLE; + nRequest=0; + status = dbGetField(paddr,DBR_DOUBLE,&new,&options,&nRequest); + pold->status = new.status; + pold->severity = new.severity; + adjust_severity(pbuffer); + pold->precision = new.precision; + strncpy(pold->units,new.units,8); + pold->upper_disp_limit = new.upper_disp_limit; + pold->lower_disp_limit = new.lower_disp_limit; + pold->upper_alarm_limit = new.upper_alarm_limit; + pold->upper_warning_limit = new.upper_warning_limit; + pold->lower_warning_limit = new.lower_warning_limit; + pold->lower_alarm_limit = new.lower_alarm_limit; + pold->upper_ctrl_limit = new.upper_ctrl_limit; + pold->lower_ctrl_limit = new.lower_ctrl_limit; + options=0; + nRequest=no_elements; + status = dbGetField(paddr,DBR_DOUBLE,&(pold->value),&options, + &nRequest); + } + break; + + default: return(-1); } @@ -517,11 +1240,35 @@ unsigned short no_elements; return(0); } -/* the old software did not have a severity of INFO */ +/* the old software did not have a severity of INFO or VALID */ static adjust_severity(pbuffer) -struct dbr_sts_string *pbuffer; + struct dbr_sts_string *pbuffer; { -if (pbuffer->severity > 0) pbuffer->severity--; + +/*** + *** Map {NO,INFO,MINOR,MAJOR,VALID} alarms onto {NO,MINOR,MAJOR} alarms of + *** GTA ( from GTA's ..../h/fields.h ) + ***/ + +#define GTA_NO_ALARM 0x0 +#define GTA_MINOR 0x1 +#define GTA_MAJOR 0x2 + + switch(pbuffer->severity) { + case NO_ALARM: pbuffer->severity = GTA_NO_ALARM; + break; + case INFO_ALARM: pbuffer->severity = GTA_NO_ALARM; + break; + case MINOR_ALARM: pbuffer->severity = GTA_MINOR; + break; + case MAJOR_ALARM: pbuffer->severity = GTA_MAJOR; + break; + case VALID_ALARM: pbuffer->severity = GTA_MAJOR; + break; + default: + break; + } + } /* DB_PUT_FIELD put a field and convert it to the desired type */ @@ -538,7 +1285,8 @@ char *psrc; /* where to get it from */ case(oldDBR_STRING): status = dbPutField(paddr,DBR_STRING,psrc,(long)no_elements); break; - case(oldDBR_INT): +/* case(oldDBR_INT): */ + case(oldDBR_SHORT): status = dbPutField(paddr,DBR_SHORT,psrc,(long)no_elements); break; case(oldDBR_FLOAT): @@ -547,14 +1295,134 @@ char *psrc; /* where to get it from */ case(oldDBR_ENUM): status = dbPutField(paddr,DBR_ENUM,psrc,(long)no_elements); break; - case(oldDBR_CTRL_INT): + case(oldDBR_CHAR): + status = dbPutField(paddr,DBR_UCHAR,psrc,(long)no_elements); + break; + case(oldDBR_LONG): + status = dbPutField(paddr,DBR_LONG,psrc,(long)no_elements); + break; + case(oldDBR_DOUBLE): + status = dbPutField(paddr,DBR_DOUBLE,psrc,(long)no_elements); + break; + case(oldDBR_STS_STRING): + status = dbPutField(paddr,DBR_STRING, + ((struct dbr_sts_string *)psrc)->value,(long)no_elements); + break; +/* case(oldDBR_STS_INT): */ + case(oldDBR_STS_SHORT): status = dbPutField(paddr,DBR_SHORT, - &(((struct dbr_ctrl_int *)psrc)->value),(long)no_elements); + &(((struct dbr_sts_short *)psrc)->value),(long)no_elements); + break; + case(oldDBR_STS_FLOAT): + status = dbPutField(paddr,DBR_FLOAT, + &(((struct dbr_sts_float *)psrc)->value),(long)no_elements); + break; + case(oldDBR_STS_ENUM): + status = dbPutField(paddr,DBR_ENUM, + &(((struct dbr_sts_enum *)psrc)->value),(long)no_elements); + break; + case(oldDBR_STS_CHAR): + status = dbPutField(paddr,DBR_UCHAR, + &(((struct dbr_sts_char *)psrc)->value),(long)no_elements); + break; + case(oldDBR_STS_LONG): + status = dbPutField(paddr,DBR_LONG, + &(((struct dbr_sts_long *)psrc)->value),(long)no_elements); + break; + case(oldDBR_STS_DOUBLE): + status = dbPutField(paddr,DBR_DOUBLE, + &(((struct dbr_sts_double *)psrc)->value),(long)no_elements); + break; + case(oldDBR_TIME_STRING): + status = dbPutField(paddr,DBR_TIME, + ((struct dbr_time_string *)psrc)->value,(long)no_elements); + break; +/* case(oldDBR_TIME_INT): */ + case(oldDBR_TIME_SHORT): + status = dbPutField(paddr,DBR_SHORT, + &(((struct dbr_time_short *)psrc)->value),(long)no_elements); + break; + case(oldDBR_TIME_FLOAT): + status = dbPutField(paddr,DBR_FLOAT, + &(((struct dbr_time_float *)psrc)->value),(long)no_elements); + break; + case(oldDBR_TIME_ENUM): + status = dbPutField(paddr,DBR_ENUM, + &(((struct dbr_time_enum *)psrc)->value),(long)no_elements); + break; + case(oldDBR_TIME_CHAR): + status = dbPutField(paddr,DBR_UCHAR, + &(((struct dbr_time_char *)psrc)->value),(long)no_elements); + break; + case(oldDBR_TIME_LONG): + status = dbPutField(paddr,DBR_LONG, + &(((struct dbr_time_long *)psrc)->value),(long)no_elements); + break; + case(oldDBR_TIME_DOUBLE): + status = dbPutField(paddr,DBR_DOUBLE, + &(((struct dbr_time_double *)psrc)->value),(long)no_elements); + break; + case(oldDBR_GR_STRING): + /* no struct dbr_gr_string - use dbr_sts_string instead */ + status = dbPutField(paddr,DBR_STRING, + ((struct dbr_sts_string *)psrc)->value,(long)no_elements); + break; +/* case(oldDBR_GR_INT): */ + case(oldDBR_GR_SHORT): + status = dbPutField(paddr,DBR_SHORT, + &(((struct dbr_gr_short *)psrc)->value),(long)no_elements); + break; + case(oldDBR_GR_FLOAT): + status = dbPutField(paddr,DBR_FLOAT, + &(((struct dbr_gr_float *)psrc)->value),(long)no_elements); + break; + case(oldDBR_GR_ENUM): + status = dbPutField(paddr,DBR_ENUM, + &(((struct dbr_gr_enum *)psrc)->value),(long)no_elements); + break; + case(oldDBR_GR_CHAR): + status = dbPutField(paddr,DBR_UCHAR, + &(((struct dbr_gr_char *)psrc)->value),(long)no_elements); + break; + case(oldDBR_GR_LONG): + status = dbPutField(paddr,DBR_LONG, + &(((struct dbr_gr_long *)psrc)->value),(long)no_elements); + break; + case(oldDBR_GR_DOUBLE): + status = dbPutField(paddr,DBR_DOUBLE, + &(((struct dbr_gr_double *)psrc)->value),(long)no_elements); + break; + case(oldDBR_CTRL_STRING): + /* no struct dbr_ctrl_string - use dbr_sts_string instead */ + status = dbPutField(paddr,DBR_STRING, + ((struct dbr_sts_string *)psrc)->value,(long)no_elements); + break; +/* case(oldDBR_CTRL_INT): */ + case(oldDBR_CTRL_SHORT): + status = dbPutField(paddr,DBR_SHORT, + &(((struct dbr_ctrl_short *)psrc)->value),(long)no_elements); break; case(oldDBR_CTRL_FLOAT): status = dbPutField(paddr,DBR_FLOAT, &(((struct dbr_ctrl_float *)psrc)->value),(long)no_elements); break; + case(oldDBR_CTRL_ENUM): + status = dbPutField(paddr,DBR_ENUM, + &(((struct dbr_ctrl_enum *)psrc)->value),(long)no_elements); + break; + case(oldDBR_CTRL_CHAR): + status = dbPutField(paddr,DBR_UCHAR, + &(((struct dbr_ctrl_char *)psrc)->value),(long)no_elements); + break; + case(oldDBR_CTRL_LONG): + status = dbPutField(paddr,DBR_LONG, + &(((struct dbr_ctrl_long *)psrc)->value),(long)no_elements); + break; + case(oldDBR_CTRL_DOUBLE): + status = dbPutField(paddr,DBR_DOUBLE, + &(((struct dbr_ctrl_double *)psrc)->value),(long)no_elements); + break; + default: return(-1); } diff --git a/src/db/db_test.c b/src/db/db_test.c index 5c4d407fb..4efc10c22 100644 --- a/src/db/db_test.c +++ b/src/db/db_test.c @@ -1,7 +1,3 @@ - -/* db_test.c */ -/* share/src/db $Id$ */ - /* * * database access subroutines @@ -34,6 +30,10 @@ * ----------------- */ #include + +/* function declarations */ +static print_returned(); + /* * TGF @@ -41,7 +41,7 @@ */ char tgf_buffer[1200]; #define MAX_ELEMS 250 -int tgf(name,index) +int gft(name,index) char *name; register short index; { @@ -58,51 +58,109 @@ register short index; printf(" Field Address: 0x%x\n",addr.pfield); printf(" Field Size: %d\n",addr.field_size); printf(" No Elements: %d\n",addr.no_elements); - printf(" Special: %d\n",addr.special); - printf(" Choice Set: %d\n",addr.choice_set); number_elements = ((addr.no_elements > MAX_ELEMS)?MAX_ELEMS:addr.no_elements); /* failedfetch as each type */ if (db_get_field(paddr,DBR_STRING,tgf_buffer,1) < 0) - printf("DBR_STRING failed\n"); + printf("\n\tDBR_STRING failed"); else print_returned(DBR_STRING,tgf_buffer,number_elements); - if (db_get_field(paddr,DBR_INT,tgf_buffer,number_elements) < 0) - printf("DBR_INT failed\n"); - else print_returned(DBR_INT,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_SHORT,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_SHORT failed"); + else print_returned(DBR_SHORT,tgf_buffer,number_elements); if (db_get_field(paddr,DBR_FLOAT,tgf_buffer,number_elements) < 0) - printf("DBR_FLOAT failed\n"); + printf("\n\tDBR_FLOAT failed"); else print_returned(DBR_FLOAT,tgf_buffer,number_elements); if (db_get_field(paddr,DBR_ENUM,tgf_buffer,number_elements) < 0) - printf("DBR_ENUM failed\n"); + printf("\n\tDBR_ENUM failed"); else print_returned(DBR_ENUM,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_CHAR,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_CHAR failed"); + else print_returned(DBR_CHAR,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_LONG,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_LONG failed"); + else print_returned(DBR_LONG,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_DOUBLE,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_DOUBLE failed"); + else print_returned(DBR_DOUBLE,tgf_buffer,number_elements); if (db_get_field(paddr,DBR_STS_STRING,tgf_buffer,1) < 0) - printf("DBR_STS_STRING failed\n"); + printf("\n\tDBR_STS_STRING failed"); else print_returned(DBR_STS_STRING,tgf_buffer,number_elements); - if (db_get_field(paddr,DBR_STS_INT,tgf_buffer,number_elements) < 0) - printf("DBR_STS_INT failed\n"); - else print_returned(DBR_STS_INT,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_STS_SHORT,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_STS_SHORT failed"); + else print_returned(DBR_STS_SHORT,tgf_buffer,number_elements); if (db_get_field(paddr,DBR_STS_FLOAT,tgf_buffer,number_elements) < 0) - printf("DBR_STS_FLOAT failed\n"); + printf("\n\tDBR_STS_FLOAT failed"); else print_returned(DBR_STS_FLOAT,tgf_buffer,number_elements); if (db_get_field(paddr,DBR_STS_ENUM,tgf_buffer,number_elements) < 0) - printf("DBR_STS_ENUM failed\n"); + printf("\n\tDBR_STS_ENUM failed"); else print_returned(DBR_STS_ENUM,tgf_buffer,number_elements); - if (db_get_field(paddr,DBR_GR_INT,tgf_buffer,number_elements) < 0) - printf("DBR_GR_INT failed\n"); - else print_returned(DBR_GR_INT,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_STS_CHAR,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_STS_CHAR failed"); + else print_returned(DBR_STS_CHAR,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_STS_LONG,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_STS_LONG failed"); + else print_returned(DBR_STS_LONG,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_STS_DOUBLE,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_STS_DOUBLE failed"); + else print_returned(DBR_STS_DOUBLE,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_TIME_STRING,tgf_buffer,1) < 0) + printf("\n\tDBR_TIME_STRING failed"); + else print_returned(DBR_TIME_STRING,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_TIME_SHORT,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_TIME_SHORT failed"); + else print_returned(DBR_TIME_SHORT,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_TIME_FLOAT,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_TIME_FLOAT failed"); + else print_returned(DBR_TIME_FLOAT,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_TIME_ENUM,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_TIME_ENUM failed"); + else print_returned(DBR_TIME_ENUM,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_TIME_CHAR,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_TIME_CHAR failed"); + else print_returned(DBR_TIME_CHAR,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_TIME_LONG,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_TIME_LONG failed"); + else print_returned(DBR_TIME_LONG,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_TIME_DOUBLE,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_TIME_DOUBLE failed"); + else print_returned(DBR_TIME_DOUBLE,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_GR_STRING,tgf_buffer,1) < 0) + printf("\n\tDBR_GR_STRING failed"); + else print_returned(DBR_GR_STRING,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_GR_SHORT,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_GR_SHORT failed"); + else print_returned(DBR_GR_SHORT,tgf_buffer,number_elements); if (db_get_field(paddr,DBR_GR_FLOAT,tgf_buffer,number_elements) < 0) - printf("DBR_GR_FLOAT failed\n"); + printf("\n\tDBR_GR_FLOAT failed"); else print_returned(DBR_GR_FLOAT,tgf_buffer,number_elements); - if (db_get_field(paddr,DBR_CTRL_INT,tgf_buffer,number_elements) < 0) - printf("DBR_CTRL_INT failed\n"); - else print_returned(DBR_CTRL_INT,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_GR_ENUM,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_GR_ENUM failed"); + else print_returned(DBR_GR_ENUM,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_GR_CHAR,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_GR_CHAR failed"); + else print_returned(DBR_GR_CHAR,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_GR_LONG,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_GR_LONG failed"); + else print_returned(DBR_GR_LONG,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_GR_DOUBLE,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_GR_DOUBLE failed"); + else print_returned(DBR_GR_DOUBLE,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_CTRL_SHORT,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_CTRL_SHORT failed"); + else print_returned(DBR_CTRL_SHORT,tgf_buffer,number_elements); if (db_get_field(paddr,DBR_CTRL_FLOAT,tgf_buffer,number_elements) < 0) - printf("DBR_CTRL_FLOAT failed\n"); + printf("\n\tDBR_CTRL_FLOAT failed"); else print_returned(DBR_CTRL_FLOAT,tgf_buffer,number_elements); - if (db_get_field(paddr,DBR_CTRL_ENUM,tgf_buffer,number_elements) < 0) - printf("DBR_CTRL_ENUM failed\n"); - else print_returned(DBR_CTRL_ENUM,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_CTRL_CHAR,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_CTRL_CHAR failed"); + else print_returned(DBR_CTRL_CHAR,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_CTRL_LONG,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_CTRL_LONG failed"); + else print_returned(DBR_CTRL_LONG,tgf_buffer,number_elements); + if (db_get_field(paddr,DBR_CTRL_DOUBLE,tgf_buffer,number_elements) < 0) + printf("\n\tDBR_CTRL_DOUBLE failed"); + else print_returned(DBR_CTRL_DOUBLE,tgf_buffer,number_elements); printf("\n"); return(0); } @@ -111,7 +169,7 @@ register short index; * TPF * Test put field */ -int tpf(pname,pvalue,index) +int pft(pname,pvalue,index) char *pname; char *pvalue; register short index; @@ -141,26 +199,54 @@ register short index; printf(" Field Address: 0x%x\n",addr.pfield); printf(" Field Size: %d\n",addr.field_size); printf(" No Elements: %d\n",addr.no_elements); - printf(" Special: %d\n",addr.special); - printf(" Choice Set: %d\n",addr.choice_set); - if (db_put_field(paddr,DBR_STRING,pvalue,1) < 0) printf(" failed\n"); - if (db_get_field(paddr,DBR_STRING,buffer,1) < 0) printf("failed\n"); + if (db_put_field(paddr,DBR_STRING,pvalue,1) < 0) printf("\n\t failed "); + if (db_get_field(paddr,DBR_STRING,buffer,1) < 0) printf("\n\tfailed"); else print_returned(DBR_STRING,buffer,1); - if(addr.field_type<=DBF_STRING || addr.field_type>=DBF_NO_ACCESS)return(0); + if(addr.field_type<=DBF_STRING || addr.field_type>=DBF_NO_ACCESS) + return(0); if(sscanf(pvalue,"%hd",&shortvalue)==1) { - if (db_put_field(paddr,DBR_INT,&shortvalue,1) < 0) printf(" INT failed\n"); - if (db_get_field(paddr,DBR_INT,buffer,1) < 0) printf("INT GET failed\n"); - else print_returned(DBR_INT,buffer,1); + if (db_put_field(paddr,DBR_SHORT,&shortvalue,1) < 0) + printf("\n\t SHORT failed "); + if (db_get_field(paddr,DBR_SHORT,buffer,1) < 0) + printf("\n\t SHORT GET failed"); + else print_returned(DBR_SHORT,buffer,1); + } + if(sscanf(pvalue,"%ld",&longvalue)==1) { + if (db_put_field(paddr,DBR_LONG,&longvalue,1) < 0) + printf("\n\t LONG failed "); + if (db_get_field(paddr,DBR_LONG,buffer,1) < 0) + printf("\n\t LONG GET failed"); + else print_returned(DBR_LONG,buffer,1); } if(sscanf(pvalue,"%f",&floatvalue)==1) { - if (db_put_field(paddr,DBR_FLOAT,&floatvalue,1) < 0) printf("FLOAT failed\n"); - if (db_get_field(paddr,DBR_FLOAT,buffer,1) < 0) printf("FLOAT GET failed\n"); - else print_returned(DBR_FLOAT,buffer,1); + if (db_put_field(paddr,DBR_FLOAT,&floatvalue,1) < 0) + printf("\n\t FLOAT failed "); + if (db_get_field(paddr,DBR_FLOAT,buffer,1) < 0) + printf("\n\t FLOAT GET failed"); + else print_returned(DBR_FLOAT,buffer,1); + } + if(sscanf(pvalue,"%f",&floatvalue)==1) { + doublevalue=floatvalue; + if (db_put_field(paddr,DBR_DOUBLE,&doublevalue,1) < 0) + printf("\n\t DOUBLE failed "); + if (db_get_field(paddr,DBR_DOUBLE,buffer,1) < 0) + printf("\n\t DOUBLE GET failed"); + else print_returned(DBR_DOUBLE,buffer,1); + } + if(sscanf(pvalue,"%hd",&shortvalue)==1) { + charvalue=(unsigned char)shortvalue; + if (db_put_field(paddr,DBR_CHAR,&charvalue,1) < 0) + printf("\n\t CHAR failed "); + if (db_get_field(paddr,DBR_CHAR,buffer,1) < 0) + printf("\n\t CHAR GET failed"); + else print_returned(DBR_CHAR,buffer,1); } if(sscanf(pvalue,"%hu",&shortvalue)==1) { - if (db_put_field(paddr,DBR_ENUM,&shortvalue,1) < 0) printf("ENUM failed\n"); - if (db_get_field(paddr,DBR_ENUM,buffer,1) < 0) printf("ENUM GET failed\n"); - else print_returned(DBR_ENUM,buffer,1); + if (db_put_field(paddr,DBR_ENUM,&shortvalue,1) < 0) + printf("\n\t ENUM failed "); + if (db_get_field(paddr,DBR_ENUM,buffer,1) < 0) + printf("\n\t ENUM GET failed"); + else print_returned(DBR_ENUM,buffer,1); } printf("\n"); return(0); @@ -172,30 +258,30 @@ register short index; * print out the values in a database access interface structure */ static print_returned(type,pbuffer,count) -register short type; -register char *pbuffer; -short count; + register short type; + register char *pbuffer; + short count; { register short i; switch(type){ case (DBR_STRING): - printf("DBR_STRING: %s",pbuffer); + printf("\n\tDBR_STRING Value: %s",pbuffer); break; - case (DBR_INT): + case (DBR_SHORT): { register short *pvalue = (short *)pbuffer; - printf("DBR_INT: "); + printf("\n\tDBR_SHORT "); for (i = 0; i < count; i++,pvalue++){ printf("%d ",*(short *)pvalue); - if ((i % 16) == 15) printf("\t\n"); + if ((i % 16) == 15) printf("\n\t"); } break; } case (DBR_FLOAT): { register float *pvalue = (float *)pbuffer; - printf("DBR_FLOAT: "); + printf("\n\tDBR_FLOAT "); for (i = 0; i < count; i++,pvalue++){ printf("%6.4f ",*(float *)pvalue); if ((i % 16) == 15) printf("\n\t"); @@ -205,23 +291,59 @@ short count; case (DBR_ENUM): { register short *pvalue = (short *)pbuffer; - printf("DBR_ENUM: %d",*pvalue); + printf("\n\tDBR_ENUM %d",*pvalue); + break; + } + case (DBR_CHAR): + { + int value; + + printf("\n\tDBR_CHAR "); + for (i = 0; i < count; i++,pbuffer++){ + value = *(unsigned char *)pbuffer; + printf("%d ",value); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_LONG): + { + register long *pvalue = (long *)pbuffer; + printf("\n\tDBR_LONG "); + for (i = 0; i < count; i++,pvalue++){ + printf("0x%x ",*pvalue); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_DOUBLE): + { + register double *pvalue = (double *)pbuffer; + printf("\n\tDBR_DOUBLE "); + for (i = 0; i < count; i++,pvalue++){ + printf("%6.4f ",(float)(*pvalue)); + if ((i % 16) == 15) printf("\n\t"); + } break; } case (DBR_STS_STRING): + case (DBR_GR_STRING): + case (DBR_CTRL_STRING): { register struct dbr_sts_string *pvalue = (struct dbr_sts_string *) pbuffer; - printf("DBR_STS_STRING %2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_STS_STRING %2d %2d",pvalue->status, + pvalue->severity); printf("\tValue: %s",pvalue->value); break; } - case (DBR_STS_INT): + case (DBR_STS_SHORT): { - register struct dbr_sts_int *pvalue - = (struct dbr_sts_int *)pbuffer; + register struct dbr_sts_short *pvalue + = (struct dbr_sts_short *)pbuffer; register short *pshort = &pvalue->value; - printf("DBR_STS_INT %2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_STS_SHORT %2d %2d",pvalue->status, + pvalue->severity); printf("\tValue: "); for (i = 0; i < count; i++,pshort++){ printf("%d ",*pshort); @@ -234,7 +356,8 @@ short count; register struct dbr_sts_float *pvalue = (struct dbr_sts_float *)pbuffer; register float *pfloat = &pvalue->value; - printf("DBR_STS_FLOAT %2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_STS_FLOAT %2d %2d",pvalue->status, + pvalue->severity); printf("\tValue: "); for (i = 0; i < count; i++,pfloat++){ printf("%6.4f ",*pfloat); @@ -246,21 +369,165 @@ short count; { register struct dbr_sts_enum *pvalue = (struct dbr_sts_enum *)pbuffer; - printf("DBR_STS_ENUM %2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_STS_ENUM %2d %2d",pvalue->status, + pvalue->severity); printf("\tValue: %d",pvalue->value); break; } - case (DBR_GR_INT): + case (DBR_STS_CHAR): { - register struct dbr_gr_int *pvalue - = (struct dbr_gr_int *)pbuffer; + register struct dbr_sts_char *pvalue + = (struct dbr_sts_char *)pbuffer; + register unsigned char *pchar = &pvalue->value; + short value; + + printf("\n\tDBR_STS_CHAR %2d %2d",pvalue->status, + pvalue->severity); + printf("\tValue: "); + for (i = 0; i < count; i++,pchar++){ + value=*pchar; + printf("%d ",value); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_STS_LONG): + { + register struct dbr_sts_long *pvalue + = (struct dbr_sts_long *)pbuffer; + register long *plong = &pvalue->value; + printf("\n\tDBR_STS_LONG %2d %2d",pvalue->status, + pvalue->severity); + printf("\tValue: "); + for (i = 0; i < count; i++,plong++){ + printf("0x%lx ",*plong); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_STS_DOUBLE): + { + register struct dbr_sts_double *pvalue + = (struct dbr_sts_double *)pbuffer; + register double *pdouble = &pvalue->value; + printf("\n\tDBR_STS_DOUBLE %2d %2d",pvalue->status, + pvalue->severity); + printf("\tValue: "); + for (i = 0; i < count; i++,pdouble++){ + printf("%6.4f ",(float)(*pdouble)); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_TIME_STRING): + { + register struct dbr_time_string *pvalue + = (struct dbr_time_string *) pbuffer; + printf("\n\tDBR_TIME_STRING %2d %2d",pvalue->status, + pvalue->severity); + printf("\n\tTimeStamp: %lx %lx \n\tValue: ", + pvalue->stamp.secPastEpoch, pvalue->stamp.nsec); + printf("%s\n\t",pvalue->value); + break; + } + case (DBR_TIME_SHORT): + { + register struct dbr_time_short *pvalue + = (struct dbr_time_short *)pbuffer; register short *pshort = &pvalue->value; - printf("DBR_GR_INT %2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_TIME_SHORT %2d %2d",pvalue->status, + pvalue->severity); + printf("\tTimeStamp: %lx %lx \n\tValue: ", + pvalue->stamp.secPastEpoch, pvalue->stamp.nsec); + for (i = 0; i < count; i++,pshort++){ + printf("%d ",*pshort); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_TIME_FLOAT): + { + register struct dbr_time_float *pvalue + = (struct dbr_time_float *)pbuffer; + register float *pfloat = &pvalue->value; + printf("\n\tDBR_TIME_FLOAT %2d %2d",pvalue->status, + pvalue->severity); + printf("\tTimeStamp: %lx %lx \n\tValue: ", + pvalue->stamp.secPastEpoch, pvalue->stamp.nsec); + for (i = 0; i < count; i++,pfloat++){ + printf("%6.4f ",*pfloat); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_TIME_ENUM): + { + register struct dbr_time_enum *pvalue + = (struct dbr_time_enum *)pbuffer; + printf("\n\tDBR_TIME_ENUM %2d %2d",pvalue->status, + pvalue->severity); + printf("\tTimeStamp: %lx %lx \n\tValue: ", + pvalue->stamp.secPastEpoch, pvalue->stamp.nsec); + printf("%d\n\t",pvalue->value); + break; + } + case (DBR_TIME_CHAR): + { + register struct dbr_time_char *pvalue + = (struct dbr_time_char *)pbuffer; + register unsigned char *pchar = &pvalue->value; + printf("\n\tDBR_TIME_CHAR %2d %2d",pvalue->status, + pvalue->severity); + printf("\tTimeStamp: %lx %lx \n\tValue: ", + pvalue->stamp.secPastEpoch, pvalue->stamp.nsec); + for (i = 0; i < count; i++,pchar++){ + printf("%d ",(short)(*pchar)); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_TIME_LONG): + { + register struct dbr_time_long *pvalue + = (struct dbr_time_long *)pbuffer; + register long *plong = &pvalue->value; + printf("\n\tDBR_TIME_LONG %2d %2d",pvalue->status, + pvalue->severity); + printf("\tTimeStamp: %lx %lx \n\tValue: ", + pvalue->stamp.secPastEpoch, pvalue->stamp.nsec); + for (i = 0; i < count; i++,plong++){ + printf("0x%lx ",*plong); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_TIME_DOUBLE): + { + register struct dbr_time_double *pvalue + = (struct dbr_time_double *)pbuffer; + register double *pdouble = &pvalue->value; + printf("\n\tDBR_TIME_DOUBLE %2d %2d",pvalue->status, + pvalue->severity); + printf("\tTimeStamp: %lx %lx \n\tValue: ", + pvalue->stamp.secPastEpoch, pvalue->stamp.nsec); + for (i = 0; i < count; i++,pdouble++){ + printf("%6.4f ",(float)(*pdouble)); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_GR_SHORT): + { + register struct dbr_gr_short *pvalue + = (struct dbr_gr_short *)pbuffer; + register short *pshort = &pvalue->value; + printf("\n\tDBR_GR_SHORT %2d %2d",pvalue->status, + pvalue->severity); printf(" %.8s %6d %6d %6d %6d %6d %6d",pvalue->units, pvalue->upper_disp_limit,pvalue->lower_disp_limit, pvalue->upper_alarm_limit,pvalue->upper_warning_limit, pvalue->lower_warning_limit,pvalue->lower_alarm_limit); - printf("\nValue:\t"); + printf("\n\tValue: "); for (i = 0; i < count; i++,pshort++){ printf("%d ",*pshort); if ((i % 16) == 15) printf("\n\t"); @@ -272,32 +539,105 @@ short count; register struct dbr_gr_float *pvalue = (struct dbr_gr_float *)pbuffer; register float *pfloat = &pvalue->value; - printf("DBR_GR_FLOAT%2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_GR_FLOAT%2d %2d",pvalue->status, + pvalue->severity); printf(" %3d %.8s\n\t%6.4f %6.4f %6.4f %6.4f %6.4f %6.4f", pvalue->precision, pvalue->units, pvalue->upper_disp_limit,pvalue->lower_disp_limit, pvalue->upper_alarm_limit,pvalue->upper_warning_limit, pvalue->lower_warning_limit,pvalue->lower_alarm_limit); - printf("\nValue\t"); + printf("\n\tValue: "); for (i = 0; i < count; i++,pfloat++){ printf("%6.4f ",*pfloat); if ((i % 16) == 15) printf("\n\t"); } break; } - case (DBR_CTRL_INT): + case (DBR_GR_ENUM): + case (DBR_CTRL_ENUM): { - register struct dbr_ctrl_int *pvalue - = (struct dbr_ctrl_int *)pbuffer; + register struct dbr_gr_enum *pvalue + = (struct dbr_gr_enum *)pbuffer; + printf("\n\tDBR_GR_ENUM%2d %2d",pvalue->status, + pvalue->severity); + printf("\n\t%3d",pvalue->no_str); + for (i = 0; i < pvalue->no_str; i++) + printf("\n\t%.26s",pvalue->strs[i]); + printf("\n\tValue: %d",pvalue->value); + break; + } + case (DBR_GR_CHAR): + { + register struct dbr_gr_char *pvalue + = (struct dbr_gr_char *)pbuffer; + register unsigned char *pchar = &pvalue->value; + printf("\n\tDBR_GR_CHAR%2d %2d",pvalue->status, + pvalue->severity); + printf(" %.8s %4d %4d %4d %4d %4d %4d",pvalue->units, + pvalue->upper_disp_limit,pvalue->lower_disp_limit, + pvalue->upper_alarm_limit,pvalue->upper_warning_limit, + pvalue->lower_warning_limit,pvalue->lower_alarm_limit); + printf("\n\tValue: "); + for (i = 0; i < count; i++,pchar++){ + printf("%d ",(short)(*pchar)); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_GR_LONG): + { + register struct dbr_gr_long *pvalue + = (struct dbr_gr_long *)pbuffer; + register long *plong = &pvalue->value; + printf("\n\tDBR_GR_LONG %2d %2d",pvalue->status, + pvalue->severity); + printf("%.8s\n\t%8d %8d %8d %8d %8d %8d",pvalue->units, + pvalue->upper_disp_limit,pvalue->lower_disp_limit, + pvalue->upper_alarm_limit,pvalue->upper_warning_limit, + pvalue->lower_warning_limit,pvalue->lower_alarm_limit); + printf("\n\tValue: "); + for (i = 0; i < count; i++,plong++){ + printf("0x%lx ",*plong); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_GR_DOUBLE): + { + register struct dbr_gr_double *pvalue + = (struct dbr_gr_double *)pbuffer; + register double *pdouble = &pvalue->value; + printf("\n\tDBR_GR_DOUBLE %2d %2d",pvalue->status, + pvalue->severity); + printf(" %3d %.8s\n\t%6.4f %6.4f %6.4f %6.4f %6.4f %6.4f", + pvalue->precision, pvalue->units, + (float)(pvalue->upper_disp_limit), + (float)(pvalue->lower_disp_limit), + (float)(pvalue->upper_alarm_limit), + (float)(pvalue->upper_warning_limit), + (float)(pvalue->lower_warning_limit), + (float)(pvalue->lower_alarm_limit)); + printf("\n\tValue: "); + for (i = 0; i < count; i++,pdouble++){ + printf("%6.4f ",(float)(*pdouble)); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_CTRL_SHORT): + { + register struct dbr_ctrl_short *pvalue + = (struct dbr_ctrl_short *)pbuffer; register short *pshort = &pvalue->value; - printf("DBR_CTRL_INT %2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_CTRL_SHORT %2d %2d",pvalue->status, + pvalue->severity); printf(" %.8s\n\t%6d %6d %6d %6d %6d %6d",pvalue->units, pvalue->upper_disp_limit,pvalue->lower_disp_limit, pvalue->upper_alarm_limit,pvalue->upper_warning_limit, pvalue->lower_warning_limit,pvalue->lower_alarm_limit); printf(" %6d %6d", pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit); - printf("\n\t"); + printf("\n\tValue: "); for (i = 0; i < count; i++,pshort++){ printf("%d ",*pshort); if ((i % 16) == 15) printf("\n\t"); @@ -309,7 +649,8 @@ short count; register struct dbr_ctrl_float *pvalue = (struct dbr_ctrl_float *)pbuffer; register float *pfloat = &pvalue->value; - printf("DBR_CTRL_FLOAT %2d %2d",pvalue->status,pvalue->severity); + printf("\n\tDBR_CTRL_FLOAT %2d %2d",pvalue->status, + pvalue->severity); printf(" %3d %.8s\n\t%6.4f %6.4f %6.4f %6.4f %6.4f %6.4f", pvalue->precision, pvalue->units, pvalue->upper_disp_limit,pvalue->lower_disp_limit, @@ -317,25 +658,78 @@ short count; pvalue->lower_warning_limit,pvalue->lower_alarm_limit); printf(" %6.4f %6.4f", pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit); - printf("\n\t"); + printf("\n\tValue: "); for (i = 0; i < count; i++,pfloat++){ printf("%6.4f ",*pfloat); if ((i % 16) == 15) printf("\n\t"); } break; } - case (DBR_CTRL_ENUM): + case (DBR_CTRL_CHAR): { - register struct dbr_ctrl_enum *pvalue - = (struct dbr_ctrl_enum *)pbuffer; - printf("DBR_GR_ENUM%2d %2d",pvalue->status,pvalue->severity); - printf("\n\t%3d",pvalue->no_str); - for (i = 0; i < pvalue->no_str; i++) - printf("\n\t%.26s",pvalue->strs[i]); - printf("Value: %d",pvalue->value); + register struct dbr_ctrl_char *pvalue + = (struct dbr_ctrl_char *)pbuffer; + register unsigned char *pchar = &pvalue->value; + printf("\n\tDBR_CTRL_CHAR %2d %2d",pvalue->status, + pvalue->severity); + printf(" %.8s %4d %4d %4d %4d %4d %4d",pvalue->units, + pvalue->upper_disp_limit,pvalue->lower_disp_limit, + pvalue->upper_alarm_limit,pvalue->upper_warning_limit, + pvalue->lower_warning_limit,pvalue->lower_alarm_limit); + printf(" %4d %4d", + pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit); + printf("\n\tValue: "); + for (i = 0; i < count; i++,pchar++){ + printf("%4d ",(short)(*pchar)); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_CTRL_LONG): + { + register struct dbr_ctrl_long *pvalue + = (struct dbr_ctrl_long *)pbuffer; + register long *plong = &pvalue->value; + printf("\n\tDBR_CTRL_LONG %2d %2d",pvalue->status, + pvalue->severity); + printf(" %.8s %8d %8d\n\t%8d %8d %8d %8d",pvalue->units, + pvalue->upper_disp_limit,pvalue->lower_disp_limit, + pvalue->upper_alarm_limit,pvalue->upper_warning_limit, + pvalue->lower_warning_limit,pvalue->lower_alarm_limit); + printf(" %8d %8d", + pvalue->upper_ctrl_limit,pvalue->lower_ctrl_limit); + printf("\n\tValue: "); + for (i = 0; i < count; i++,plong++){ + printf("0x%lx ",*plong); + if ((i % 16) == 15) printf("\n\t"); + } + break; + } + case (DBR_CTRL_DOUBLE): + { + register struct dbr_ctrl_double *pvalue + = (struct dbr_ctrl_double *)pbuffer; + register double *pdouble = &pvalue->value; + printf("\n\tDBR_CTRL_DOUBLE%2d %2d",pvalue->status, + pvalue->severity); + printf(" %3d %.8s\n\t%6.6f %6.6f %6.6f %6.6f %6.6f %6.6f", + pvalue->precision, pvalue->units, + (float)(pvalue->upper_disp_limit), + (float)(pvalue->lower_disp_limit), + (float)(pvalue->upper_alarm_limit), + (float)(pvalue->upper_warning_limit), + (float)(pvalue->lower_warning_limit), + (float)(pvalue->lower_alarm_limit)); + printf(" %6.6f %6.6f", + (float)(pvalue->upper_ctrl_limit), + (float)(pvalue->lower_ctrl_limit)); + printf("\n\tValue: "); + for (i = 0; i < count; i++,pdouble++){ + printf("%6.6f ",(float)(*pdouble)); + if ((i % 16) == 15) printf("\n\t"); + } break; } } - printf("\n"); } diff --git a/src/db/iocInit.c b/src/db/iocInit.c index 3d270b76c..e7a446e53 100644 --- a/src/db/iocInit.c +++ b/src/db/iocInit.c @@ -1,5 +1,5 @@ /* iocInit.c ioc initialization */ -/* share/src/db $Id$ */ +/* share/src/db @(#)iocInit.c 1.7 3/6/91 */ #include #include @@ -29,15 +29,14 @@ static initialized=FALSE; - /* define forward references*/ -long initBusController(); -long sdrLoad(); -long initDrvSup(); -long initRecSup(); -long initDevSup(); -long initDatabase(); -long addToSet(); +extern long initBusController(); +extern long sdrLoad(); +extern long initDrvSup(); +extern long initRecSup(); +extern long initDevSup(); +extern long initDatabase(); +extern long addToSet(); iocInit(pfilename) @@ -70,7 +69,10 @@ char * pfilename; logMsg("Scanners Initialized\n"); rsrv_init(); logMsg("Channel Access Servers Initialized\n"); + ts_init(); + logMsg("Time Stamp Driver Initialized\n"); logMsg("iocInit: All initialization complete\n"); + return(0); } @@ -88,7 +90,7 @@ long initBusController(){ /*static */ return(0); } -static long initDrvSup() /* Locate all driver support entry tables */ +long initDrvSup() /* Locate all driver support entry tables */ { char *pname; char name[40]; @@ -122,7 +124,7 @@ static long initDrvSup() /* Locate all driver support entry tables */ return(rtnval); } -static long initRecSup() +long initRecSup() { char name[40]; int i; @@ -164,7 +166,7 @@ static long initRecSup() return(rtnval); } -static long initDevSup() /* Locate all device support entry tables */ +long initDevSup() /* Locate all device support entry tables */ { char *pname; char name[40]; @@ -218,7 +220,7 @@ static long initDevSup() /* Locate all device support entry tables */ return(rtnval); } -static long initDatabase() +long initDatabase() { char name[PVNAME_SZ+FLDNAME_SZ+2]; short i,j,k; @@ -332,7 +334,7 @@ static long initDatabase() return(rtnval); } -static long addToSet(precord,record_type,lookAhead,i,j,lset) +long addToSet(precord,record_type,lookAhead,i,j,lset) struct dbCommon *precord; /* record being added to lock set*/ short record_type; /* record being added to lock set*/ short lookAhead; /*should following records be checked*/