From c649b90a26310a7df262c82c07a00d997570f784 Mon Sep 17 00:00:00 2001 From: Bob Zieman Date: Sun, 18 Nov 1990 21:47:01 +0000 Subject: [PATCH] Initial revision --- src/ca/access.c | 1469 +++++++++++++++++++++++++++++++++++++++++ src/ca/acctst.c | 185 ++++++ src/ca/catime.c | 139 ++++ src/ca/conn.c | 87 +++ src/ca/convert.c | 502 ++++++++++++++ src/ca/flow_control.c | 84 +++ src/ca/iocinf.c | 857 ++++++++++++++++++++++++ src/ca/iocinf.h | 317 +++++++++ src/ca/iocmsg.h | 77 +++ src/ca/net_convert.h | 160 +++++ src/ca/service.c | 325 +++++++++ src/ca/test_event.c | 52 ++ 12 files changed, 4254 insertions(+) create mode 100644 src/ca/access.c create mode 100644 src/ca/acctst.c create mode 100644 src/ca/catime.c create mode 100644 src/ca/conn.c create mode 100644 src/ca/convert.c create mode 100644 src/ca/flow_control.c create mode 100644 src/ca/iocinf.c create mode 100644 src/ca/iocinf.h create mode 100644 src/ca/iocmsg.h create mode 100644 src/ca/net_convert.h create mode 100644 src/ca/service.c create mode 100644 src/ca/test_event.c diff --git a/src/ca/access.c b/src/ca/access.c new file mode 100644 index 000000000..994d90733 --- /dev/null +++ b/src/ca/access.c @@ -0,0 +1,1469 @@ +/************************************************************************/ +/* */ +/* L O S A L A M O S */ +/* Los Alamos National Laboratory */ +/* Los Alamos, New Mexico 87545 */ +/* */ +/* Copyright, 1986, The Regents of the University of California. */ +/* */ +/* */ +/* History */ +/* ------- */ +/* */ +/* Date Programmer Comments */ +/* ---- ---------- -------- */ +/* 8/87 Jeff Hill Init Release */ +/* 1/90 Jeff HIll switched order in task exit */ +/* so events are deleted first */ +/* then closed */ +/* */ +/*_begin */ +/************************************************************************/ +/* */ +/* Title: IOC high level access routines */ +/* File: atcs:[ca]access.c */ +/* Environment: VMS, UNIX, VRTX */ +/* Equipment: VAX, SUN, VME */ +/* */ +/* */ +/* Purpose */ +/* ------- */ +/* */ +/* ioc high level access routines */ +/* */ +/* */ +/* 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 */ +/* */ +/* */ +/************************************************************************/ +/*_end */ + +/* the following support riu.h */ +#ifdef VMS +#include stsdef.h +#include ssdef.h +#include psldef.h +#else +#endif + +#include + +#ifdef vxWorks +# include +# include +/*# include */ +#endif + +#include +#include +#include +#include +#include + + +/****************************************************************/ +/* Macros for syncing message insertion into send buffer */ +/****************************************************************/ + +#define SNDBEG(STRUCTURE) \ +SND_BEG(STRUCTURE, &iiu[chix->iocix]) + +#define SND_BEG(STRUCTURE, PIIU)\ +LOCK SND_BEG_NOLOCK(STRUCTURE,PIIU) + +#define SND_BEG_NOLOCK(STRUCTURE,PIIU) \ +{ \ + void send_msg(); \ + register struct STRUCTURE *mptr; \ + register unsigned short msgsize = sizeof(*mptr); \ + register struct ioc_in_use *psendiiu = (PIIU); \ + if(psendiiu->send->stk + msgsize > psendiiu->max_msg)send_msg(); \ + mptr = (struct STRUCTURE *) (psendiiu->send->buf + psendiiu->send->stk); + + +#define SNDEND \ +SNDEND_NOLOCK UNLOCK + + +#define SNDEND_NOLOCK \ +psendiiu->send->stk += msgsize;} + + +#define SNDBEG_VARIABLE(POSTSIZE) \ +LOCK SNDBEG_VARIABLE_NOLOCK(POSTSIZE) + + +#define SNDBEG_VARIABLE_NOLOCK(POSTSIZE) \ +{ \ + void send_msg(); \ + register struct extmsg *mptr; \ + register unsigned short msgsize = sizeof(*mptr) + POSTSIZE; \ + register struct ioc_in_use *psendiiu = &iiu[chix->iocix]; \ + if(psendiiu->send->stk+sizeof(*mptr)+POSTSIZE > psendiiu->max_msg) \ + send_msg(); \ + mptr = (struct extmsg *) (psendiiu->send->buf + psendiiu->send->stk); + + + +/****************************************************************/ +/* Macros for error checking */ +/****************************************************************/ +#define CHIXCHK(CHIX) \ +{ \ + register unsigned short iocix = CHIX->iocix; \ + if( iocix == BROADCAST_IIU || \ + (iocix >= nxtiiu && iocix != LOCAL_IIU) || \ + INVALID_DB_REQ(CHIX->type)) \ + return ECA_BADCHID; \ +} + +#define INITCHK\ +if(!ca_static)\ + ca_task_initialize(); + + +static struct extmsg nullmsg; + + + + +ca_task_initialize +#ifdef VAXC +(void) +#else +() +#endif +{ + int status; + char *taskName(); + char name[15]; + void *db_init_events(); + int ca_import(); + + if(!ca_static){ + +# ifdef vxWorks + { + int options; + + 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(); + } +# endif + + ca_static = (struct ca_static *) malloc(sizeof(*ca_static)); + if(!ca_static) + abort(); + memset(ca_static, NULL, sizeof(*ca_static)); + +# ifdef VMS + status = lib$get_ef(&io_done_flag); + if(status != SS$_NORMAL) + lib$signal(status); +# endif + +# ifdef vxWorks + + FASTLOCKINIT(&client_lock); + + 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(); +# endif + + } + + return ECA_NORMAL; +} + +#ifdef vxWorks +ca_import(moms_tid) +int moms_tid; +{ + 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(); + + return ECA_NORMAL; +} +#endif + + +#ifdef vxWorks +static +ca_add_task_variable() +{ + static void ca_task_exit_tcbx(); + static char ca_installed; + int status; + + status = taskVarAdd(VXTHISTASKID, &ca_static); + if(status == ERROR) + abort(); + + /* + only one delete hook for all CA tasks + */ + if(vxTas(&ca_installed)){ + status = taskDeleteHookAdd(ca_task_exit_tcbx); + if(status == ERROR){ + logMsg("ca_init_task: could not add CA delete routine\n"); + abort(); + } + } + + return ECA_NORMAL; +} +#endif + + + +/* + 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 +#ifdef VAXC +(void) +#else +() +#endif +{ + void ca_task_exit_tid(); + +# ifdef vxWorks + ca_task_exit_tid(VXTHISTASKID); +# else + ca_task_exit_tid(0); +#endif + + return ECA_NORMAL; +} + + +#ifdef vxWorks +static void +ca_task_exit_tcbx(ptcbx) +TCBX *ptcbx; +{ + void ca_task_exit_tid(); + + ca_task_exit_tid((int) ptcbx->taskId); +} +#endif + + +static void +ca_task_exit_tid(tid) +int tid; +{ + int i; + chid chix; + evid monix; + struct ca_static *ca_temp; + +# ifdef vxWorks + ca_temp = (struct ca_static *) taskVarGet(tid, &ca_static); + if(ca_temp == (struct ca_static *) ERROR) + return; + +# else + ca_temp = ca_static; +# endif + + /* if allready in the exit state just NOOP */ +# ifdef vxWorks + if(!vxTas(&ca_temp->ca_exit_in_progress)) + return; +# else + if(ca_temp->ca_exit_in_progress) + return; + ca_temp->ca_exit_in_progress = TRUE; +# endif + + if(ca_temp){ +# ifdef vxWorks + logMsg("ca_task_exit: Removing task %x from CA\n",tid); +# endif + +/********** + LOCK; +***********/ + + 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"); + } + +# ifdef vxWorks + {int status; + status = db_close_events(ca_temp->ca_evuser); + if(status==ERROR) + SEVCHK(ECA_INTERNAL, "could not close event facility by id"); + } + + if(ca_temp->ca_event_buf) + if(free(ca_temp->ca_event_buf)) + 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"); + } + + while(chix = (chid) lstGet(&ca_temp->ca_chidlist_pend)){ + if(free(chix)<0) + SEVCHK(ECA_INTERNAL, "Corrupt pending chid list"); + } + + while(chix = (chid) lstGet(&ca_temp->ca_chidlist_noreply)){ + if(free(chix)<0) + SEVCHK(ECA_INTERNAL, "Corrupt unanswered chid list"); + } + +/************** + UNLOCK; +***************/ + + if(free(ca_temp)<0) + SEVCHK(ECA_INTERNAL, "Unable to free task static variables"); + + +/* + Only remove task variable if user is call 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) + {int status; + status = taskVarDelete(tid, &ca_static); + if(status == ERROR) + SEVCHK(ECA_INTERNAL, "Unable to remove ca_static from task var list"); + + } +# endif + + ca_static = (struct ca_static *) NULL; + + } +} + + +ca_array_build +#ifdef VAXC +( +char *name_str, +chtype get_type, +unsigned int get_count, +chid *chixptr, +void *pvalue +) +#else +(name_str,get_type,get_count,chixptr,pvalue) +char *name_str; +chtype get_type; +unsigned int get_count; +chid *chixptr; +void *pvalue; +#endif +{ + long status; + chid chix; + int strcnt; + unsigned short castix; + struct in_addr broadcast_addr(); + + /* + make sure that chix is NULL on fail + */ + *chixptr = NULL; + + INITCHK; + + if(INVALID_DB_REQ(get_type) && get_type != TYPENOTCONN) + return ECA_BADTYPE; + + /* + Cant check his count on build since we dont know the + native count yet. + */ + + /* Put some reasonable limit on user supplied string size */ + strcnt = strlen(name_str) + 1; + if(strcnt > MAX_STRING_SIZE || strcnt==1 ) + return ECA_STRTOBIG; + + + if(strcnt==1 ) + return ECA_BADSTR; + + + /* 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; + + /* 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(); + + *(struct db_addr *)chix->paddr = tmp_paddr; + chix->type = ( (struct db_addr *)chix->paddr )->field_type; + chix->count = ( (struct db_addr *)chix->paddr )->no_elements; + chix->iocix = LOCAL_IIU; + 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(status!=OK){ + free(chix->paddr); + *chixptr = (chid) free(chix); + return ECA_GETFAIL; + } + } + LOCK; + lstAdd(&chidlist_conn, chix); + UNLOCK; + + return ECA_NORMAL; + } + } +# endif + + LOCK; + + status = alloc_ioc ( + broadcast_addr(), + IPPROTO_UDP, + &chix->iocix + ); + if(~status & CA_M_SUCCESS){ + *chixptr = (chid) free(chix); + goto exit; + } + + chix->type = TYPENOTCONN; /* invalid initial type */ + chix->paddr = (void *)NULL; /* invalid initial paddr */ + + /* save stuff for build retry if required */ + chix->build_type = get_type; + chix->build_count = get_count; + chix->build_value = (void *) pvalue; + chix->name_length = strcnt; + + /* Save this channels name for retry if required */ + strncpy(chix+1, name_str, strcnt); + + lstAdd(&chidlist_pend, chix); + status = build_msg(chix, FALSE); + +exit: + + UNLOCK; + + return status; + +} + + + +/* + +NOTE: *** lock must be on while in this routine *** + +*/ +build_msg(chix,retry) +chid chix; +int retry; +{ + register int size; + register int cmd; + + if(chix->build_count && chix->build_type != TYPENOTCONN){ + size = chix->name_length + sizeof(struct extmsg); + cmd = IOC_BUILD; + } + else{ + size = chix->name_length; + cmd = IOC_SEARCH; + } + + + SNDBEG_VARIABLE_NOLOCK(size) + + mptr->m_cmmd = htons(cmd); + mptr->m_postsize = htons(size); + mptr->m_available = (long) chix; + mptr->m_type = 0; + mptr->m_count = 0; + mptr->m_paddr = 0; + + if(cmd == IOC_BUILD){ + /* msg header only on db read req */ + mptr++; + mptr->m_postsize = 0; + mptr->m_cmmd = htons(IOC_READ); + 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; + + if(!retry) + SETPENDRECV; + } + + /* channel name string */ + /* forces a NULL at the end because strcnt is allways >= strlen + 1 */ + mptr++; + strncpy(mptr, chix+1, chix->name_length); + + if(!retry) + SETPENDRECV; + + SNDEND_NOLOCK; + + return ECA_NORMAL; + +} + + + +ca_array_get +#ifdef VAXC +( +chtype type, +unsigned int count, +chid chix, +register void *pvalue +) +#else +(type,count,chix,pvalue) +chtype type; +unsigned int count; +chid chix; +register void *pvalue; +#endif +{ + CHIXCHK(chix); + + if(INVALID_DB_REQ(type)) + return ECA_BADTYPE; + + if(count > chix->count) + return ECA_BADCOUNT; + +# ifdef vxWorks + { + int status; + + if(chix->iocix == LOCAL_IIU){ + status = db_get_field( + chix->paddr, + type, + pvalue, + count, + FALSE); + if(status==OK) + return ECA_NORMAL; + else + return ECA_GETFAIL; + } + } +# endif + + + SNDBEG(extmsg) + + /* msg header only on db read req */ + mptr->m_postsize = 0; + mptr->m_cmmd = htons(IOC_READ); + mptr->m_type = htons(type); + mptr->m_available = (long) pvalue; + mptr->m_count = htons(count); + mptr->m_paddr = chix->paddr; + SNDEND + + SETPENDRECV; + return ECA_NORMAL; +} + + +ca_array_put +#ifdef VAXC +( +chtype type, +unsigned int count, +chid chix, +void *pvalue +) +#else +(type,count,chix,pvalue) +register chtype type; +unsigned int count; +chid chix; +register void *pvalue; +#endif +{ + register int postcnt; + register int tmp; + register void *pdest; + register int i; + register int size; + + CHIXCHK(chix); + + if(INVALID_DB_REQ(type)) + return ECA_BADTYPE; + + if(count > chix->count) + return ECA_BADCOUNT; + +# ifdef vxWorks + { + int status; + + if(chix->iocix == LOCAL_IIU){ + status = db_put_field( chix->paddr, + type, + pvalue, + count); + if(status==OK) + return ECA_NORMAL; + else + return ECA_PUTFAIL; + } + } +# endif + + size = dbr_value_size[type]; + postcnt = dbr_size[type] + size*(count-1); + SNDBEG_VARIABLE(postcnt) + pdest = (void *)(mptr+1); + + for(i=0; i< count; i++){ + + switch(type){ + case DBR_INT: + case DBR_ENUM: + *(short *)pdest = htons(*(short *)pvalue); + break; + + case DBR_FLOAT: + /* most compilers pass all floats as doubles */ + htonf(pvalue, pdest); + break; + + case DBR_STRING: + + /* + If arrays of strings are passed I assume each is MAX_STRING_SIZE + or less and copy count * MAX_STRING_SIZE bytes into the outgoing + IOC message. + */ + if(count>1){ + memcpy(pdest,pvalue,postcnt); + goto array_loop_exit; + } + + /* Put some reasonable limit on user supplied string size */ + { unsigned int strsize; + strsize = strlen(pvalue) + 1; + /* Make sure string is aligned to short word boundaries for MC68000 */ + /* forces a NULL at the end because strcnt is allways >= strlen + 1 */ + strsize = BI_ROUND(strsize+1)<<1; + if(strsize>MAX_STRING_SIZE) + return ECA_STRTOBIG; + memcpy(pdest,pvalue,strsize); + } + break; + + /* 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[type])(pvalue,pdest,TRUE,count); +# else + if(pdest != pvalue) + memcpy(pdest,pvalue,postcnt); +# endif + + goto array_loop_exit; + default: + return ECA_BADTYPE; + } + (char *) pdest += size; + (char *) pvalue += size; + } + +array_loop_exit: + + mptr->m_cmmd = htons(IOC_WRITE); + mptr->m_postsize = htons(postcnt); + mptr->m_type = htons(type); + mptr->m_count = htons(count); + mptr->m_paddr = chix->paddr; + mptr->m_available = (long) chix; + SNDEND + + return ECA_NORMAL; +} + + +/* + Specify a event subroutine to be run once when pending IO completes + + 1) event sub runs right away if no IO pending + 2) event sub runs when pending IO completes otherwise + +*/ +ca_add_io_event +#ifdef VAXC +( +void (*ast)(), +void *astarg +) +#else +(ast,astarg) +void (*ast)(); +void *astarg; +#endif +{ + register struct pending_io_event *pioe; + + if(pndrecvcnt<1) + (*ast)(astarg); + else{ + LOCK; + pioe = (struct pending_io_event *) malloc(sizeof(*pioe)); + if(!pioe) + return ECA_ALLOCMEM; + pioe->io_done_arg = astarg; + pioe->io_done_sub = ast; + lstAdd(&ioeventlist,pioe); + UNLOCK; + } + + return ECA_NORMAL; +} + + + + +ca_add_array_event +#ifdef VAXC +( +chtype type, +unsigned int count, +chid chix, +void (*ast)(), +void *astarg, +ca_real p_delta, +ca_real n_delta, +ca_real timeout, +evid *monixptr +) +#else +(type,count,chix,ast,astarg,p_delta,n_delta,timeout,monixptr) +chtype type; +unsigned int count; +chid chix; +void (*ast)(); +void *astarg; +ca_real p_delta; +ca_real n_delta; +ca_real timeout; +evid *monixptr; +#endif +{ + register evid monix; + + CHIXCHK(chix); + + if(INVALID_DB_REQ(type)) + return ECA_BADTYPE; + + if(count > chix->count) + return ECA_BADCOUNT; + + if(count == 0) + count = chix->count; + + + /* AST descriptor */ +# ifdef vxWorks + monix = (evid) malloc(sizeof(*monix)+db_sizeof_event_block()); +# else + monix = (evid) malloc(sizeof(*monix)); +# endif + if(!monix) + return ECA_ALLOCMEM; + + /* they dont have to supply one if they dont want to */ + if(monixptr) + *monixptr = monix; + + monix->chan = chix; + monix->usr_func = ast; + monix->usr_arg = astarg; + monix->type = type; + monix->count = count; + + LOCK; + /* Place in the channel list */ + lstAdd(&eventlist, monix); + UNLOCK; + +# ifdef vxWorks + { + struct monops mon; + register int status; + void ca_event_handler(); + + if(chix->iocix == LOCAL_IIU){ + status = db_add_event( evuser, + chix->paddr, + ca_event_handler, + monix, + DBE_VALUE | DBE_ALARM, + monix+1); + if(status == ERROR) + return ECA_DBLCLFAIL; + + /* force event to be called at least once */ + db_post_single_event(monix+1); + return ECA_NORMAL; + + } + } +# endif + + SNDBEG(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; + + /* 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); + + SNDEND + return ECA_NORMAL; +} + + +#ifdef vxWorks +static void +ca_event_handler(monix, paddr, hold) +register evid monix; +register struct db_addr *paddr; +int hold; +{ + register int status; + register int count = monix->count; + register chtype type = monix->type; + union db_access_val valbuf; + void *pval; + register unsigned size; + + if(type == paddr->field_type){ + pval = paddr->pfield; + status = OK; + } + else{ + if(count == 1) + size = dbr_size[type]; + else + size = (count-1)*dbr_value_size[type]+dbr_size[type]; + + if( size <= sizeof(valbuf) ) + pval = (void *) &valbuf; + else if( size <= event_buf_size ) + pval = event_buf; + else{ + if(free(event_buf)) + abort(); + pval = event_buf = (void *) malloc(size); + if(!pval) + abort(); + event_buf_size = size; + } + status = db_get_field( paddr, + type, + pval, + count, + TRUE); + } + + if(status == ERROR) + logMsg("CA post event get error\n"); + else + (*monix->usr_func)( monix->usr_arg, + monix->chan, + type, + count, + pval); + + return; +} +#endif + + + +#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 +#ifdef VAXC +(register evid monix) +#else +(monix) +register evid monix; +#endif +{ + register chid chix = monix->chan; /* for SNDBEG */ + + CHIXCHK(chix); + +# 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; +} + + + + +/* +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 +#ifdef VAXC +(ca_real timeout) +#else +(timeout) +ca_real timeout; +#endif +{ + void send_msg(); + time_t beg_time; + time_t clock(); + int chidcnt; + int chidstart; + +# ifdef vxWorks + static int sysfreq; + + if(!sysfreq) + sysfreq = SYSFREQ; +# endif + + INITCHK; + + if(post_msg_active) + return ECA_EVDISALLOW; + + + /* Flush the send buffers */ + LOCK; + send_msg(); + UNLOCK; + + if(pndrecvcnt<1) + return ECA_NORMAL; + + if(timeout<0.0) + return ECA_TIMEOUT; + + /* The number of polls to wait on a chid */ + chidstart = (CASTTMO+pndrecvcnt*LKUPTMO)/DELAYVAL + 1; + chidcnt = chidstart; + + beg_time = time(NULL); + + while(TRUE){ +# ifdef UNIX + { + void recv_msg_select(); + struct timeval itimeout; + + itimeout.tv_usec = SYSFREQ * DELAYVAL; + itimeout.tv_sec = 0; + LOCK; + recv_msg_select(&itimeout); + UNLOCK; + } +# endif +# ifdef vxWorks + { + int dummy; + unsigned int clockticks = DELAYVAL * sysfreq; + vrtxPend(&io_done_flag,clockticks,&dummy); + } +# endif +# ifdef VMS + { + int status; + unsigned int systim[2]={-SYSFREQ*DELAYVAL,~0}; + + status = sys$setimr(io_done_flag, systim, NULL, MYTIMERID, NULL); + if(status != SS$_NORMAL) + lib$signal(status); + status = sys$waitfr(io_done_flag); + if(status != SS$_NORMAL) + lib$signal(status); + } +# endif + if(pndrecvcnt<1) + return ECA_NORMAL; + + chidcnt--; + if(chidcnt<1){ + if(chidlist_pend.count) + chid_retry(TRUE); + chidstart += chidstart; + chidcnt = chidstart; + } + if(timeout != 0.0) + if(timeoutcur_read_seq++; + SND_BEG_NOLOCK(extmsg, piiu) + *mptr = nullmsg; + mptr->m_cmmd = htons(IOC_READ_SYNC); + SNDEND_NOLOCK + } + pndrecvcnt = 0; + UNLOCK; + + return ECA_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 +#ifdef VAXC +(void) +#else +() +#endif +{ + void send_msg(); + + INITCHK; + + /* Flush the send buffers */ + LOCK; + send_msg(); + UNLOCK; + + return ECA_NORMAL; +} + + + ca_signal(ca_status,message) +int ca_status; +char *message; +{ + static char *severity[] = + { + "Warning", + "Success", + "Error", + "Info", + "Fatal", + "Fatal", + "Fatal", + "Fatal" + }; + + if( CA_EXTRACT_MSG_NO(ca_status) >= NELEMENTS(ca_message_text) ){ + message = "corrupt status"; + ca_status = ECA_INTERNAL; + } + + printf( +"CA.Diagnostic.....................................................\n"); + + printf( +" Message: [%s]\n", ca_message_text[CA_EXTRACT_MSG_NO(ca_status)]); + + if(message) + printf( +" Severity: [%s] Context: [%s]\n", + severity[CA_EXTRACT_SEVERITY(ca_status)], + message); + else + printf( +" Severity: [%s]\n", severity[CA_EXTRACT_SEVERITY(ca_status)]); + + + if( !(ca_status & CA_M_SUCCESS) ){ +# ifdef VMS + lib$signal(0); +# endif +# ifdef vxWorks + ti(taskIdCurrent); + tt(taskIdCurrent); +# endif + abort(); + } + + printf( +"..................................................................\n"); + + +} + + + + +ca_busy_message(piiu) +register struct ioc_in_use *piiu; +{ + void send_msg(); + + SND_BEG(extmsg, piiu) + *mptr = nullmsg; + mptr->m_cmmd = htons(IOC_EVENTS_OFF); + SNDEND_NOLOCK + send_msg(); + UNLOCK; + +} + +ca_ready_message(piiu) +register struct ioc_in_use *piiu; +{ + void send_msg(); + + SND_BEG(extmsg, piiu) + *mptr = nullmsg; + mptr->m_cmmd = htons(IOC_EVENTS_ON); + SNDEND_NOLOCK + send_msg(); + UNLOCK; + +} diff --git a/src/ca/acctst.c b/src/ca/acctst.c new file mode 100644 index 000000000..ed084780d --- /dev/null +++ b/src/ca/acctst.c @@ -0,0 +1,185 @@ +/* + A CA test/debug routine +*/ + + + +/* System includes */ +#include +#ifdef vxWorks +#include +#endif + +#include +#include +#include + +/* +#define CA_TEST_CHNL "AI_T2000" +*/ +#define CA_TEST_CHNL "AI_T2000.DESC" +#define CA_TEST_CHNL4 "AI_DOGGY" + + +#define NUM 1 + + +#ifdef vxWorks +spacctst() +{ + int acctst(); + + return taskSpawn("acctst",200,VX_FP_TASK,20000,acctst); +} +#endif + + +#ifdef vxWorks +acctst() +#else +main() +#endif +{ + chid chix1; + chid chix2; + chid chix3; + chid chix4; + void ca_test_event(); + void null_event(); + struct dbr_gr_float *ptr; + float delay = .003; + + long status; + long pid; + long i,j; + float delta = 1.0; + long monix; + char string[41]; + float value; + float *pfloat; + struct dbr_ctrl_float *pctrl; + char pstring[NUM][MAX_STRING_SIZE]; + void write_event(); + + + SEVCHK(ca_task_initialize(),"Unable to initialize"); + + printf("begin\n"); +# ifdef VMS + lib$init_timer(); +# endif + + 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++){ + 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); + } + + + SEVCHK(ca_search(CA_TEST_CHNL4,&chix4),NULL); + SEVCHK(ca_search(CA_TEST_CHNL,&chix2),NULL); + + for(i=0;i<1;i++) + SEVCHK(ca_search(CA_TEST_CHNL,&chix1),NULL); + + status = ca_pend_io(1.0); + + if(INVALID_DB_REQ(chix1->type)) + printf("Failed to locate %s\n",CA_TEST_CHNL); + if(INVALID_DB_REQ(chix2->type)) + printf("Failed to locate %s\n",CA_TEST_CHNL); + if(INVALID_DB_REQ(chix3->type)) + printf("Failed to locate %s\n",CA_TEST_CHNL); + if(INVALID_DB_REQ(chix4->type)) + printf("Failed to locate %s\n",CA_TEST_CHNL4); +/* + SEVCHK(status,NULL); + if(status == ECA_TIMEOUT) + exit(); +*/ + +# ifdef VMS + lib$show_timer(); +#endif + + pfloat = &ptr->value; + for(i=0;itype)){ + ca_add_event(DBR_FLOAT, chix4, ca_test_event, 0xaaaaaaaa, &monix); + ca_clear_event(monix); + } + if(VALID_DB_REQ(chix4->type)){ + ca_add_event(DBR_FLOAT, chix4, ca_test_event, 0xaaaaaaaa, &monix); + ca_clear_event(monix); + } + + 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); + } + + pfloat = (float *) malloc(sizeof(float)*NUM); + + + if(VALID_DB_REQ(chix1->type)) + if(pfloat) + for(i=0;i +#ifdef vxWorks +#include +#endif + +#include +#include +#include + +#define CA_TEST_CHNL "AI_2000" + + +#ifdef vxWorks +spcatime() +{ + int acctst(); + + return taskSpawn("acctst",200,VX_FP_TASK,20000,acctst); +} +#endif + +#define NUM 1 + +catime() +{ + chid ai_1; + + long status; + long i,j; + void *ptr; + int ca_array_put(); + int ca_array_get(); + + + SEVCHK(ca_task_initialize(),"Unable to initialize"); + + + SEVCHK(ca_search(CA_TEST_CHNL,&ai_1),NULL); + status = ca_pend_io(5.0); + SEVCHK(status,NULL); + if(status == ECA_TIMEOUT) + exit(); + + ptr = (void *) malloc(NUM*sizeof(union db_access_val)+NUM*MAX_STRING_SIZE); + if(!ptr) + exit(); + + printf("channel name %s native type %d native count %d\n",ai_1+1,ai_1->type,ai_1->count); + + + for(i=0;i +#include +#include +#include +#include + + +chid_retry(silent) +char silent; +{ + register chid chix; + register unsigned int retry_cnt = 0; + char string[100]; + void send_msg(); + + if(!chidlist_pend.count) + return ECA_NORMAL; + + 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; + + if(retry_cnt && !silent){ + 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; +{ + register chid chix; + register chid nextchix; + + 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; + } + } + +} diff --git a/src/ca/convert.c b/src/ca/convert.c new file mode 100644 index 000000000..6691d595a --- /dev/null +++ b/src/ca/convert.c @@ -0,0 +1,502 @@ +#include +#include + +#ifdef vxWorks +# define memcpy(D,S,N) bcopy(S,D,N) +# define memset(D,V,N) bfill(D,N,V) +#endif + + +/**************************************************************************** +** cvrt_sts_string(s,d) +** struct dbr_sts_string *s pointer to source struct +** struct dbr_sts_string *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** converts fields of struct in VAX format to IEEE format +** or +** converts fields of struct in IEEE format to fields with VAX +** format; +****************************************************************************/ + +cvrt_sts_string(s,d,encode,num) +struct dbr_sts_string *s; /* source */ +struct dbr_sts_string *d; /* destination */ +int encode; /* do VAX to IEEE */ +int num; /* number of values */ +{ + + /* convert ieee to vax format or vax to ieee */ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + if (num == 1) /* if single value */ + strcpy(d->value,s->value); + else + memcpy(d->value,s->value,(MAX_STRING_SIZE * num)); + + return 1; +} + + + + +/**************************************************************************** +** cvrt_sts_int(s,d) +** struct dbr_sts_int *s pointer to source struct +** struct dbr_sts_int *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** converts fields ofstruct in VAX format to ieee format +** or +** converts fields of struct in IEEE format to fields with VAX +** format +****************************************************************************/ + +cvrt_sts_int(s,d,encode,num) +struct dbr_sts_int *s; /* source */ +struct dbr_sts_int *d; /* destination */ +int encode; /* if true, vax to ieee */ +int num; /* number of values */ +{ + register i; + short *sval_ptr,*dval_ptr; /* ptrs to source, destination */ + + /* convert vax to ieee or ieee to vax format -- same code*/ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + + if (num == 1) /* single value */ + d->value = ntohs(s->value); + else /* array chan-- multiple pts */ + { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0; i < num; i++){ + *dval_ptr = ntohs(*sval_ptr); + sval_ptr++; + dval_ptr++; + } + } + + + return 1; +} + + + + +/**************************************************************************** +** cvrt_sts_float(s,d) +** struct dbr_sts_float *s pointer to source struct +** struct dbr_sts_float *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** if encode +** converts struct in VAX format to ieee format +** else +** converts fields of struct in IEEE format to fields with VAX +** format; +****************************************************************************/ + +cvrt_sts_float(s,d,encode,num) +struct dbr_sts_float *s; /* source */ +struct dbr_sts_float *d; /* destination */ +int encode; /* it true, vax to ieee */ +int num; /* number of values */ +{ + register i; + float *sval_ptr,*dval_ptr; + + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + + if(encode) /* vax to ieee convert */ + if(num == 1){ + htonf(&s->value, &d->value); + } + else + { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + htonf(sval_ptr,dval_ptr); + sval_ptr++; + dval_ptr++; + } + } + + else /* ieee to vax convert */ + if(num == 1){ + ntohf(&s->value,&d->value); + } + else + { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + ntohf(sval_ptr,dval_ptr); + dval_ptr++; + sval_ptr++; + } + } + + return 1; +} + + + + +/**************************************************************************** +** cvrt_sts_enum(s,d) +** struct dbr_sts_enum *s pointer to source struct +** struct dbr_sts_enum *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** converts fields of struct in IEEE format to fields with VAX format +** or +** converts fields of struct in VAX format to fields with IEEE format +** +****************************************************************************/ + +cvrt_sts_enum(s,d,encode,num) +struct dbr_sts_enum *s; /* source */ +struct dbr_sts_enum *d; /* destination */ +int encode; /* if true, vax to ieee */ +int num; /* number of values */ +{ + register i; + short *dval_ptr,*sval_ptr; + + /* convert vax to ieee or ieee to vax --same code */ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + if (num == 1) + d->value = ntohs(s->value); + else { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0; i < num; i++){ + *dval_ptr = ntohs(*sval_ptr); + dval_ptr++; + sval_ptr++; + } + } + return 1; +} + + + + +/**************************************************************************** +** cvrt_gr_int(s,d) +** struct dbr_gr_int *s pointer to source struct +** struct dbr_gr_int *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** converts fields of struct in IEEE format to fields with VAX format +** or +** converts fields of struct in VAX format to fields with IEEE format +** +****************************************************************************/ + +cvrt_gr_int(s,d,encode,num) +struct dbr_gr_int *s; /* source */ +struct dbr_gr_int *d; /* destination */ +int encode; /* if true, vax to ieee */ +int num; /* number of values */ +{ + register i; + short *sval_ptr,*dval_ptr; + + /* convert ieee to vax or vax to ieee -- same code */ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + strcpy(d->units,s->units); + + d->upper_disp_limit = ntohs(s->upper_disp_limit); + d->lower_disp_limit = ntohs(s->lower_disp_limit); + d->upper_alarm_limit = ntohs(s->upper_alarm_limit); + d->upper_warning_limit = ntohs(s->upper_warning_limit); + d->lower_alarm_limit = ntohs(s->lower_alarm_limit); + d->lower_warning_limit = ntohs(s->lower_warning_limit); + + if (num == 1) + d->value = ntohs(s->value); + else { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + *dval_ptr = ntohs(*sval_ptr); + dval_ptr++; + sval_ptr++; + } + } + + + return 1; +} + + + + +/**************************************************************************** +** cvrt_gr_float(s,d) +** struct dbr_gr_float *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** if encode +** converts struct in VAX format to ieee format +** else +** converts fields of struct in IEEE format to fields with VAX +** format; +****************************************************************************/ + +cvrt_gr_float(s,d,encode,num) +struct dbr_gr_float *s; /* source */ +struct dbr_gr_float *d; /* destination */ +int encode; /* if true, vax to ieee */ +int num; /* number of values */ +{ + register i; + float *sval_ptr,*dval_ptr; + + /* these are same for vax to ieee or ieee to vax */ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + d->precision = ntohs(s->precision); + strcpy(d->units,s->units); + + if (encode) /* vax to ieee convert */ + { + if (num == 1){ + htonf(&s->value, &d->value); + } + else { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + htonf(sval_ptr,dval_ptr); + dval_ptr++; + sval_ptr++; + } + } + htonf(&s->upper_disp_limit,&d->upper_disp_limit); + htonf(&s->lower_disp_limit, &d->lower_disp_limit); + htonf(&s->upper_alarm_limit, &d->upper_alarm_limit); + htonf(&s->upper_warning_limit, &d->upper_warning_limit); + htonf(&s->lower_alarm_limit, &d->lower_alarm_limit); + htonf(&s->lower_warning_limit, &d->lower_warning_limit); + } + else /* ieee to vax convert */ + { + if (num == 1){ + ntohf(&s->value, &d->value); + } + else { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + ntohf(sval_ptr,dval_ptr); + dval_ptr++; + sval_ptr++; + } + } + ntohf(&s->upper_disp_limit,&d->upper_disp_limit); + ntohf(&s->lower_disp_limit, &d->lower_disp_limit); + ntohf(&s->upper_alarm_limit, &d->upper_alarm_limit); + ntohf(&s->upper_warning_limit, &d->upper_warning_limit); + ntohf(&s->lower_alarm_limit, &d->lower_alarm_limit); + ntohf(&s->lower_warning_limit, &d->lower_warning_limit); + } + + + return 1; +} + + + + +/**************************************************************************** +** cvrt_ctrl_int(s,d) +** struct dbr_gr_int *s pointer to source struct +** struct dbr_gr_int *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** converts fields of struct in IEEE format to fields with VAX format +** or +** converts fields of struct in VAX format to fields with IEEE format +** +****************************************************************************/ + +cvrt_ctrl_int(s,d,encode,num) +struct dbr_ctrl_int *s; /* source */ +struct dbr_ctrl_int *d; /* destination */ +int encode; /* if true, vax to ieee */ +int num; /* number of values */ +{ + register i; + short *sval_ptr,*dval_ptr; + + /* vax to ieee or ieee to vax -- same code */ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + strcpy(d->units,s->units); + + d->upper_disp_limit = ntohs(s->upper_disp_limit); + d->lower_disp_limit = ntohs(s->lower_disp_limit); + d->upper_alarm_limit = ntohs(s->upper_alarm_limit); + d->upper_warning_limit = ntohs(s->upper_warning_limit); + d->lower_alarm_limit = ntohs(s->lower_alarm_limit); + d->lower_warning_limit = ntohs(s->lower_warning_limit); + d->lower_ctrl_limit = ntohs(s->lower_ctrl_limit); + d->upper_ctrl_limit = ntohs(s->upper_ctrl_limit); + + if (num == 1) + d->value = ntohs(s->value); + else { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + *dval_ptr = ntohs(*sval_ptr); + dval_ptr++; + sval_ptr++; + } + } + + + return 1; +} + + + + +/**************************************************************************** +** cvrt_ctrl_float(s,d) +** struct dbr_ctrl_float *s pointer to source struct +** struct dbr_ctrl_float *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** if encode +** converts struct in VAX format to ieee format +** else +** converts fields of struct in IEEE format to fields with VAX +** format; +****************************************************************************/ + +cvrt_ctrl_float(s,d,encode,num) +struct dbr_ctrl_float *s; /* source */ +struct dbr_ctrl_float *d; /* destination */ +int encode; /* if true, vax to ieee */ +int num; /* number of values */ +{ + register i; + float *sval_ptr,*dval_ptr; + + /* these are the same for ieee to vaax or vax to ieee */ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + d->precision = ntohs(s->precision); + strcpy(d->units,s->units); + if (encode) /* vax to ieee convert */ + { + if (num == 1){ + htonf(&s->value, &d->value); + } + else { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + htonf(sval_ptr,dval_ptr); + dval_ptr++; + sval_ptr++; + } + } + htonf(&s->upper_disp_limit,&d->upper_disp_limit); + htonf(&s->lower_disp_limit, &d->lower_disp_limit); + htonf(&s->upper_alarm_limit, &d->upper_alarm_limit); + htonf(&s->upper_warning_limit, &d->upper_warning_limit); + htonf(&s->lower_alarm_limit, &d->lower_alarm_limit); + htonf(&s->lower_warning_limit, &d->lower_warning_limit); + htonf(&s->lower_ctrl_limit, &d->lower_ctrl_limit); + htonf(&s->upper_ctrl_limit, &d->upper_ctrl_limit); + } + else /* ieee to vax convert */ + { + if (num == 1){ + ntohf(&s->value, &d->value); + } + else { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0;i < num; i++){ + ntohf(sval_ptr,dval_ptr); + dval_ptr++; + sval_ptr++; + } + } + ntohf(&s->lower_disp_limit, &d->lower_disp_limit); + ntohf(&s->upper_alarm_limit, &d->upper_alarm_limit); + ntohf(&s->upper_warning_limit, &d->upper_warning_limit); + ntohf(&s->lower_alarm_limit, &d->lower_alarm_limit); + ntohf(&s->lower_warning_limit, &d->lower_warning_limit); + ntohf(&s->lower_ctrl_limit, &d->lower_ctrl_limit); + ntohf(&s->upper_ctrl_limit, &d->upper_ctrl_limit); + } + + + return 1; +} + + +/**************************************************************************** +** cvrt_ctrl_enum(s,d) +** struct dbr_ctrl_enum *s pointer to source struct +** struct dbr_ctrl_enum *d pointer to destination struct +** int encode; boolean, if true vax to ieee +** else ieee to vax +** +** if encode +** converts struct in VAX format to ieee format +** else +** converts fields of struct in IEEE format to fields with VAX +** format; +****************************************************************************/ + +cvrt_ctrl_enum(s,d,encode,num) +struct dbr_ctrl_enum *s; /* source */ +struct dbr_ctrl_enum *d; /* destination */ +int encode; /* if true, vax to ieee */ +int num; /* number of values */ +{ + register i; + short *sval_ptr,*dval_ptr; + + /* vax to ieee or ieee to vax -- same code */ + d->status = ntohs(s->status); + d->severity = ntohs(s->severity); + d->no_str = ntohs(s->no_str); + memcpy(d->strs,s->strs,sizeof(s->strs)); + + if (num == 1) /* single value */ + d->value = ntohs(s->value); + else /* array chan-- multiple pts */ + { + sval_ptr = &(s->value); + dval_ptr = &(d->value); + for (i = 0; i < num; i++){ + *dval_ptr = ntohs(*sval_ptr); + dval_ptr++; + sval_ptr++; + } + } + + return 1; +} diff --git a/src/ca/flow_control.c b/src/ca/flow_control.c new file mode 100644 index 000000000..feecd37a3 --- /dev/null +++ b/src/ca/flow_control.c @@ -0,0 +1,84 @@ +/************************************************************************/ +/* */ +/* L O S A L A M O S */ +/* Los Alamos National Laboratory */ +/* Los Alamos, New Mexico 87545 */ +/* */ +/* Copyright, 1986, The Regents of the University of California. */ +/* */ +/* */ +/* History */ +/* ------- */ +/* */ +/* Date Programmer Comments */ +/* ---- ---------- -------- */ +/* 6/89 Jeff Hill Init Release */ +/* */ +/*_begin */ +/************************************************************************/ +/* */ +/* Title: IOC network flow control module */ +/* File: atcs:[ca]flow_control.c */ +/* Environment: VMS. UNIX, VRTX */ +/* Equipment: VAX, SUN, VME */ +/* */ +/* */ +/* Purpose */ +/* ------- */ +/* */ +/* ioc flow control module */ +/* */ +/* */ +/* Special comments */ +/* ------- -------- */ +/* */ +/************************************************************************/ +/*_end */ + + +#include +#include +#include +#include +#ifdef vxWorks +#include +#endif +#include +#include +#include + + +/* +Keep track of how many times messages have come with out a break in between +*/ +flow_control(piiu) +struct ioc_in_use *piiu; +{ + unsigned nbytes; + register int status; + register int busy = piiu->client_busy; + + status = socket_ioctl( piiu->sock_chan, + FIONREAD, + &nbytes); + if(status < 0) + return ERROR; + + if(nbytes){ + piiu->contiguous_msg_count++; + if(!busy) + if(piiu->contiguous_msg_count > MAX_CONTIGUOUS_MSG_COUNT){ + piiu->client_busy = TRUE; + ca_busy_message(piiu); + } + } + else{ + piiu->contiguous_msg_count=0; + if(busy){ + ca_ready_message(piiu); + piiu->client_busy = FALSE; + } + } + + return; +} diff --git a/src/ca/iocinf.c b/src/ca/iocinf.c new file mode 100644 index 000000000..5c1603ade --- /dev/null +++ b/src/ca/iocinf.c @@ -0,0 +1,857 @@ +/************************************************************************/ +/* */ +/* L O S A L A M O S */ +/* Los Alamos National Laboratory */ +/* Los Alamos, New Mexico 87545 */ +/* */ +/* Copyright, 1986, The Regents of the University of California. */ +/* */ +/* */ +/* History */ +/* ------- */ +/* */ +/* Date Programmer Comments */ +/* ---- ---------- -------- */ +/* 8/87 Jeff Hill Init Release */ +/* */ +/*_begin */ +/************************************************************************/ +/* */ +/* Title: IOC socket interface module */ +/* File: atcs:[ca]iocinf.c */ +/* Environment: VMS. UNIX, VRTX */ +/* Equipment: VAX, SUN, VME */ +/* */ +/* */ +/* Purpose */ +/* ------- */ +/* */ +/* ioc socket interface module */ +/* */ +/* */ +/* Special comments */ +/* ------- -------- */ +/* */ +/************************************************************************/ +/*_end */ + + +/* Allocate storage for global variables in this module */ +#define GLBLSOURCE +#ifdef VMS +#include +#include +#include +#else +#endif + +#include +#include + +#ifdef vxWorks +#include +#include +#endif + +#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 ? */ +/* +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 */ +#endif + +#ifndef NFDBITS +#define NFDBITS (sizeof(int) * NBBY) /* bits per mask */ +#endif + +#ifndef FD_SET +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#endif + +#ifndef FD_ISSET +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#endif + +#ifndef FD_CLR +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#endif + +/* 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}; + + +/* + LOCK should be on while in this routine +*/ + alloc_ioc(net_addr, net_proto, iocix) +struct in_addr net_addr; +int net_proto; +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 */ + piiu->sock_addr.sin_addr = net_addr; + + /* set socket domain */ + piiu->sock_addr.sin_family = AF_INET; + + piiu->sock_proto = net_proto; + + + switch(net_proto) + { + case IPPROTO_TCP: + /* set the port */ + piiu->sock_addr.sin_port = htons(SERVER_NUM); + + /* allocate a socket */ + sock = socket( AF_INET, /* domain */ + SOCK_STREAM, /* type */ + 0); /* deflt proto */ + if(sock == ERROR) + return ECA_SOCK; + + piiu->sock_chan = sock; + + /* set TCP buffer sizes only if BSD 4.3 sockets */ + /* temporarily turned off */ +# ifdef ZEBRA + + i = (MAX_MSG_SIZE+sizeof(int)) * 2; + status = setsockopt( sock, + SOL_SOCKET, + SO_SNDBUF, + &i, + sizeof(i)); + if(status == -1){ + socket_close(sock); + return ECA_ALLOCMEM; + } + status = setsockopt( sock, + SOL_SOCKET, + SO_RCVBUF, + &i, + sizeof(i)); + if(status == -1){ + 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){ + socket_close(sock); + return ECA_CONN; + } + + /* + place the broadcast addr/port in the stream so the + ioc will know where this is coming from. + */ + i = sizeof(src); + status = getsockname( iiu[BROADCAST_IIU].sock_chan, + &src, + &i); + if(status == ERROR){ + printf("alloc_ioc: cant get my name %d\n",MYERRNO); + abort(); + } + src.sin_addr.s_addr = + (local_addr(iiu[BROADCAST_IIU].sock_chan))->sin_addr.s_addr; + status = send( piiu->sock_chan, + &src, + sizeof(src), + 0); + + 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 */ + 0); /* deflt proto */ + if(sock == ERROR) + return ECA_SOCK; + + piiu->sock_chan = sock; + + + /* + The following only needed on BSD 4.3 machines + */ + status = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&true,sizeof(true)); + if(status<0){ + printf("%d\n",MYERRNO); + socket_close(sock); + return ECA_CONN; + } + + + 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)); + if(status<0){ + printf("%d\n",MYERRNO); + SEVCHK(ECA_INTERNAL,"bind failed"); + } + + piiu->max_msg = MAX_UDP - sizeof(iiu[nxtiiu].send->stk); + + break; + default: + printf("alloc_ioc: ukn protocol\n"); + abort(); + } + + /* 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; + } + piiu->send->stk = 0; + if(! (piiu->recv = (struct buffer *) malloc(sizeof(struct buffer))) ){ + socket_close(sock); + return ECA_ALLOCMEM; + } + piiu->recv->stk = 0; + + /* Set up recv thread for VMS */ +# ifdef VMS + { + void recv_msg_ast(); + status = sys$qio( NULL, + sock, + IO$_RECEIVE, + &piiu->iosb, + recv_msg_ast, + nxtiiu, + piiu->recv->buf, + sizeof(piiu->recv->buf), + NULL, + &piiu->recvfrom, + sizeof(piiu->recvfrom), + NULL); + if(status != SS$_NORMAL){ + lib$signal(status); + exit(); + } + } +# else +# ifdef vxWorks + { + void recv_task(); + int pri; + char name[15]; + + status == taskPriorityGet(VXTASKIDSELF, &pri); + if(status<0) + SEVCHK(ECA_INTERNAL,NULL); + + name[0]=NULL; + strncat(name,"RD ", sizeof(name)-1); + strncat(name, taskName(VXTHISTASKID), sizeof(name)-1); + + status = taskSpawn( name, + pri-1, + VX_FP_TASK, + 4096, + recv_task, + (unsigned) nxtiiu, + taskIdSelf()); + if(status<0) + SEVCHK(ECA_INTERNAL,NULL); + + iiu[nxtiiu].recv_tid = status; + + } +# endif +# endif + + *iocix = nxtiiu++; + + return ECA_NORMAL; +} + + + +/* + 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; + + /**********************************************************************/ + /* Note: this routine must not be called at AST level */ + /**********************************************************************/ + for(iocix=0;iocixstk){ + + /* 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 + + 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 */ + + while(TRUE){ + status = sendto( iiu[iocix].sock_chan, + pmsg, + cnt, + 0, + &iiu[iocix].sock_addr, + sizeof(iiu[iocix].sock_addr)); + if(status == cnt) + break; + + if(status>=0){ + if(status>cnt) + SEVCHK(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); + break; + } + + /* + Ensure we do not accumulate extra recv messages (for TCP) + */ +# ifdef UNIX + { + void recv_msg_select(); + recv_msg_select(¬imeout); + } +# endif + TCPDELAY; + } + + /* reset send stack */ + iiu[iocix].send->stk = 0; + } + +} + + + +/* + Recieve incomming messages + 1) Wait no longer than timeout + 2) Return early if nothing outstanding + +*/ +#ifdef UNIX +void +recv_msg_select(ptimeout) +struct timeval *ptimeout; +{ + unsigned iocix; + long status; + void recv_msg(); + + for(iocix=0; iocix 0){ + + for(iocix=0; iocixsock_proto){ + case IPPROTO_TCP: + tcp_recv_msg(iocix); + flow_control(piiu); + break; + + case IPPROTO_UDP: + udp_recv_msg(iocix); + break; + + default: + printf("send_msg: ukn protocol\n"); + abort(); + } + + return; +} + + + +void +tcp_recv_msg(iocix) +unsigned iocix; +{ + 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; + + + + while(TRUE){ + 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 < 0){ + if(MYERRNO != EWOULDBLOCK){ + if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) + printf("unexpected recv error 1 = %d\n",MYERRNO); + + SEVCHK(ECA_DISCONN, host_from_addr(piiu->sock_addr.sin_addr)); + mark_chids_disconnected(iocix); + return; + } + } + + /* try again on status of 0 or -1 and EWOULDBLOCK */ + TCPDELAY; + } + + + /* 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; + } + + + timeoutcnt = byte_cnt + 3000; + for(byte_sum = 0; byte_sum < byte_cnt; byte_sum += status){ + +# ifdef DEBUG + if(byte_sum) + printf( "recv_msg(): Warning- reading %d leftover bytes \n", + byte_cnt-byte_sum); +# endif + + 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); + + SEVCHK(ECA_DISCONN, host_from_addr(piiu->sock_addr.sin_addr)); + mark_chids_disconnected(iocix); + return; + } + + status = 0; + if(--timeoutcnt < 0){ + printf("recv_msg(): TCP message bdy wait timed out\n"); + abort(); + } + } + + /* 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); + + return; +} + + + +void +udp_recv_msg(iocix) +unsigned iocix; +{ + struct ioc_in_use *piiu = &iiu[iocix]; + unsigned long byte_cnt; + int status; + struct buffer *rcvb = piiu->recv; + int sock = piiu->sock_chan; + struct sockaddr_in reply; + int reply_size = sizeof(reply); + char *ptr; + unsigned nchars; + + + rcvb->stk =0; + do{ + + status = recvfrom( + sock, + &rcvb->buf[rcvb->stk], + MAX_UDP, + 0, + &reply, + &reply_size); + if(status < sizeof(int)){ + /* op would block which is ok to ignore till ready later */ + if(MYERRNO == EWOULDBLOCK) + break; + SEVCHK(ECA_INTERNAL,"unexpected udp recv error"); + } + + /* switch from 68000 to VAX byte order */ + byte_cnt = (unsigned long) ntohl(*(int *)&rcvb->buf[rcvb->stk]); +# ifdef DEBUG + 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(): header %d actual %d\n",byte_cnt,status); + break; + } + rcvb->stk += byte_cnt; + + *(struct in_addr *) &rcvb->buf[rcvb->stk] = reply.sin_addr; + rcvb->stk += sizeof(reply.sin_addr); + + if(rcvb->stk + MAX_UDP > MAX_MSG_SIZE) + break; + + /* + More comming ? + */ + status = socket_ioctl( sock, + FIONREAD, + &nchars); + if(status<0) + SEVCHK(ECA_INTERNAL,"unexpected udp ioctl err\n"); + + }while(nchars); + + for( ptr = rcvb->buf; + ptr < &rcvb->buf[rcvb->stk]; + ptr += byte_cnt + sizeof(reply.sin_addr)){ + byte_cnt = (unsigned long) ntohl(*(int *)ptr); + + /* post message to the user */ + post_msg( ptr + sizeof(int), + byte_cnt - sizeof(int), + *(struct in_addr *)(ptr+byte_cnt), + piiu); + } + + return; +} + + + + +#ifdef vxWorks +void +recv_task(iocix,moms_tid) +unsigned iocix; +int moms_tid; +{ + 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(); + + while(TRUE) + recv_msg(iocix); +} +#endif + +#ifdef VMS +void +recv_msg_ast(iocix) +int iocix; +{ + 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; + + 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 +#ifdef WINTCP + paddr = (struct sockaddr_in *) ((char *)&piiu->recvfrom+sizeof(short)); +#else + paddr = (struct sockaddr_in *) (char *)&piiu->recvfrom; +#endif + + piiu->recv->stk += io_count; + io_count = piiu->recv->stk; + + 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_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; + } + + 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->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(piiu->sock_proto == IPPROTO_TCP) + flow_control(piiu); + + piiu->recv->stk = 0; + io_status = sys$qio( NULL, + piiu->sock_chan, + IO$_RECEIVE, + &piiu->iosb, + recv_msg_ast, + iocix, + piiu->recv->buf, + sizeof(piiu->recv->buf), + NULL, + &piiu->recvfrom, + sizeof(piiu->recvfrom), + NULL); + if(io_status != SS$_NORMAL) + lib$signal(io_status); + + return; +} +#endif + + + diff --git a/src/ca/iocinf.h b/src/ca/iocinf.h new file mode 100644 index 000000000..1b7805110 --- /dev/null +++ b/src/ca/iocinf.h @@ -0,0 +1,317 @@ +/************************************************************************/ +/* */ +/* L O S A L A M O S */ +/* Los Alamos National Laboratory */ +/* Los Alamos, New Mexico 87545 */ +/* */ +/* Copyright, 1986, The Regents of the University of California. */ +/* */ +/* */ +/* History */ +/* ------- */ +/* */ +/* Date Programmer Comments */ +/* ---- ---------- -------- */ +/* 8/87 Jeff Hill Init Release */ +/* 1/90 Jeff Hill fd_set in the UNIX version only */ +/* */ +/*_begin */ +/************************************************************************/ +/* */ +/* Title: channel access TCPIP interface include file */ +/* File: atcs:[ca]iocinf.h */ +/* Environment: VMS, UNIX, VRTX */ +/* */ +/* */ +/* Purpose */ +/* ------- */ +/* */ +/* ioc interface include */ +/* */ +/* */ +/* Special comments */ +/* ------- -------- */ +/* Use GLBLTYPE to define externals so we can change the all at */ +/* once from VAX globals to generic externals */ +/* */ +/************************************************************************/ +/*_end */ + +#ifndef INClstLibh +#include +#endif + +#ifndef _TYPES_ +# include +#endif + +#ifndef __IN_HEADER__ +#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 +#endif + +#define IODONESUB\ +{\ + register struct pending_io_event *pioe;\ + LOCK;\ + if(ioeventlist.count)\ + while(pioe = (struct pending_io_event *) lstGet(&ioeventlist)){\ + (*pioe->io_done_sub)(pioe->io_done_arg);\ + if(free(pioe))abort();\ + }\ + UNLOCK;\ +} + +#define VALID_MSG(PIIU) (piiu->read_seq == piiu->cur_read_seq) + +#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 + +/* size of object in bytes rounded up to nearest long word */ +#define QUAD_ROUND(A) (((A)+3)>>2) +#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A))) + +/* 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 */ +/************************************************************************/ + +/* stk must be above and contiguous with buf ! */ +struct buffer{ + unsigned long stk; + 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 */ +#define MAXIIU 25 +#define LOCAL_IIU (MAXIIU+100) +#define BROADCAST_IIU 0 + +struct pending_io_event{ + NODE node; + void (*io_done_sub)(); + void *io_done_arg; +}; + + +#define MAX_CONTIGUOUS_MSG_COUNT 2 + + +#define iiu (ca_static->ca_iiu) +#define pndrecvcnt (ca_static->ca_pndrecvcnt) +#define chidlist_pend (ca_static->ca_chidlist_pend) +#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) +#ifdef UNIX +#define readch (ca_static->ca_readch) +#define writech (ca_static->ca_writech) +#define execch (ca_static->ca_execch) +#endif +#define post_msg_active (ca_static->ca_post_msg_active) +#ifdef vxWorks +#define io_done_flag (ca_static->ca_io_done_flag) +#define evuser (ca_static->ca_evuser) +#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) +#endif +#ifdef VMS +#define io_done_flag (ca_static->ca_io_done_flag) +#endif + +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; +#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 +#ifdef vxWorks + int ca_io_done_flag; + void *ca_evuser; + FAST_LOCK ca_client_lock; + void *ca_event_buf; + unsigned ca_event_buf_size; + int ca_tid; +#endif + struct ioc_in_use{ + unsigned contiguous_msg_count; + unsigned client_busy; + int sock_proto; + struct sockaddr_in sock_addr; + int sock_chan; + int max_msg; + struct buffer *send; + struct buffer *recv; + unsigned read_seq; + unsigned cur_read_seq; +#ifdef VMS /* for qio ASTs */ + struct sockaddr_in recvfrom; + struct iosb iosb; +#endif +#ifdef vxWorks + int recv_tid; +#endif + } ca_iiu[MAXIIU]; +}; + +/* + GLOBAL VARIABLES + There should only be one - add others to ca_static above -joh +*/ +#ifdef GLBLSOURCE +# ifdef VAXC +# define GLBLTYPE globaldef +# else +# define GLBLTYPE +# endif +#else +# ifdef VAXC +# define GLBLTYPE globalref +# else +# define GLBLTYPE extern +# endif +#endif + +GLBLTYPE +struct ca_static *ca_static; + +#ifdef VMS +GLBLTYPE +char ca_unique_address; +# define MYTIMERID (&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) + +*/ diff --git a/src/ca/iocmsg.h b/src/ca/iocmsg.h new file mode 100644 index 000000000..81abad0b8 --- /dev/null +++ b/src/ca/iocmsg.h @@ -0,0 +1,77 @@ +#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 + +*/ + +#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 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 */ + + + /* 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 */ + /* 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 */ + + + + + /* extmsg - the nonvariant part of each message sent/recv + by the request server. + */ + + +struct extmsg { + unsigned short m_cmmd; /* operation to be performed */ + 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 */ + unsigned long m_available; /* undefined message location for use + * by client processes */ +}; + + + /* for monitor 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 */ +}; + +struct monops { /* monitor req opi to ioc */ + struct extmsg m_header; + struct mon_info m_info; +}; + +#endif diff --git a/src/ca/net_convert.h b/src/ca/net_convert.h new file mode 100644 index 000000000..d50eb250a --- /dev/null +++ b/src/ca/net_convert.h @@ -0,0 +1,160 @@ +/************************************************************************/ +/* So byte swapping can be performed in line for efficiency */ +/* (WINTCP has library routines with the same same functionality */ +/* but more than twice the delay) JH */ +/* WARNING: WILL NOT WORK ON TYPES FLOAT OR DOUBLE */ +/* (use *(long *)& to perform type convert without reformat) */ +/************************************************************************/ + +#ifdef VAX +# define ntohs(SHORT)\ + ((unsigned short)(((short)(SHORT))<<8 | ((unsigned short)(SHORT))>>8 )) +# define htons(SHORT)\ + ((unsigned short)(((short)(SHORT))<<8 | ((unsigned short)(SHORT))>>8 )) +#else +# define ntohs(SHORT) (SHORT) +# define htons(SHORT) (SHORT) +#endif + + +#ifdef VAX +# define ntohl(LONG)\ + (\ + ((long)(LONG))<<24 |\ + ((unsigned long)(LONG))>>24 |\ + (((long)(LONG))&0x00ff0000)>>8 |\ + (((long)(LONG))&0x0000ff00)<<8\ + ) +# define htonl(LONG)\ + (\ + ((long)(LONG))<<24 |\ + ((unsigned long)(LONG))>>24 |\ + (((long)(LONG))&0x00ff0000)>>8 |\ + (((long)(LONG))&0x0000ff00)<<8\ + ) +#else +# define ntohl(LONG) (LONG) +# define htonl(LONG) (LONG) +#endif + + +/************************************************************************/ +/* So float convert can be performed in line for efficiency */ +/* (THIS ASSUMES IEEE IS THE NETWORK FLOATING POINT FORMAT) */ +/************************************************************************/ +struct ieeeflt{ + unsigned mant :23; + unsigned exp :8; + unsigned sign :1; +}; + +/* Exponent sign bias */ +#define IEEE_SB 127 + +/* Conversion Range */ +/* -126sign;\ + if( (short)((struct mitflt *) (MIT))->exp < EXPMINIEEE + MIT_SB){\ + exp = 0;\ + mant = 0;\ + }\ + else{\ + exp = (short)((struct mitflt *) (MIT))->exp-MIT_SB+IEEE_SB;\ + mant = (((struct mitflt *) (MIT))->mant1<<16) |\ + ((struct mitflt *) (MIT))->mant2;\ + }\ + ((struct ieeeflt *) (IEEE))->mant = mant;\ + ((struct ieeeflt *) (IEEE))->exp = exp;\ + ((struct ieeeflt *) (IEEE))->sign = sign;\ + *(long *)(IEEE) = ntohl(*(long*)(IEEE));\ + } + +# 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){\ + exp = EXPMAXMIT + MIT_SB;\ + mant2 = ~0;\ + mant1 = ~0;\ + }\ + else if( ((struct ieeeflt *) (IEEE))->exp == 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);\ + }\ + ((struct mitflt *) (MIT))->exp = exp;\ + ((struct mitflt *) (MIT))->mant2 = mant2;\ + ((struct mitflt *) (MIT))->mant1 = mant1;\ + ((struct mitflt *) (MIT))->sign = sign;\ + } + + +#else +# define ntohf(NET,HOST) {*(float *)(HOST) = *(float *)(NET);} +# define htonf(HOST,NET) {*(float *)(NET) = *(float *)(HOST);} +#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 (); + +static +int (*cvrt[])() + = + { + 0, + 0, + 0, + 0, + cvrt_sts_string, + cvrt_sts_int, + cvrt_sts_float, + cvrt_sts_enum, + cvrt_gr_int, + cvrt_gr_float, + cvrt_ctrl_int, + cvrt_ctrl_float, + cvrt_ctrl_enum + }; +#endif diff --git a/src/ca/service.c b/src/ca/service.c new file mode 100644 index 000000000..080c11283 --- /dev/null +++ b/src/ca/service.c @@ -0,0 +1,325 @@ +/************************************************************************/ +/* */ +/* L O S A L A M O S */ +/* Los Alamos National Laboratory */ +/* Los Alamos, New Mexico 87545 */ +/* */ +/* Copyright, 1986, The Regents of the University of California. */ +/* */ +/* */ +/* History */ +/* ------- */ +/* */ +/* Date Programmer Comments */ +/* ---- ---------- -------- */ +/* 8/87 Jeff Hill Init Release */ +/* 1/90 Jeff Hill Made cmmd for errors which */ +/* eliminated the status field */ +/* */ +/*_begin */ +/************************************************************************/ +/* */ +/* Title: channel access service routines */ +/* File: atcs:[ca]servuice.c */ +/* Environment: VMS, UNIX, VRTX */ +/* Equipment: VAX, SUN, VME */ +/* */ +/* */ +/* Purpose */ +/* ------- */ +/* */ +/* channel access service routines */ +/* */ +/* */ +/* Special comments */ +/* ------- -------- */ +/* */ +/************************************************************************/ +/*_end */ + +#ifdef VMS +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include + + +void post_msg(hdrptr,bufcnt,net_addr,piiu) +register struct extmsg *hdrptr; +register long bufcnt; +struct in_addr net_addr; +struct ioc_in_use *piiu; +{ + evid monix; + long msgcnt; + long tmp; + char *name; + + register void * t_available; + register unsigned short t_postsize; + register unsigned short t_cmmd; + register chtype t_type; + register unsigned short t_count; + 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", + bufcnt, + pndrecvcnt); +# endif + + /* byte swap the message up front */ + t_available = (void *) hdrptr->m_available; + t_postsize = ntohs(hdrptr->m_postsize); + t_cmmd = ntohs(hdrptr->m_cmmd); + t_type = ntohs(hdrptr->m_type); + t_count = ntohs(hdrptr->m_count); + t_size = dbr_size[t_type]; + + + + 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: + { + /* 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; + + 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; + + 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 + + for(i=0; iusr_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 */ + ); + + break; + } + case IOC_SEARCH: + case IOC_BUILD: + BUFCHK(sizeof(*hdrptr)); + if( ((chid)t_available)->paddr ){ + int iocix = ((chid)t_available)->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); + } + + /* 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); + + /* 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; + + /* decrement the outstanding IO count */ + CLRPENDRECV; + + break; + + case IOC_READ_SYNC: + BUFCHK(sizeof(struct extmsg)); + piiu->read_seq++; + break; + + case IOC_ERROR: + { + char context[255]; + + BUFCHK(sizeof(struct extmsg) + t_postsize); + + 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; + } + + default: + printf("post_msg(): Corrupt message or unsupported m_cmmd type\n"); + return; + } + + bufcnt -= msgcnt; + hdrptr = (struct extmsg *) (msgcnt + (char *) hdrptr); + + } + + + post_msg_active--; + +} + diff --git a/src/ca/test_event.c b/src/ca/test_event.c new file mode 100644 index 000000000..ae757ae3c --- /dev/null +++ b/src/ca/test_event.c @@ -0,0 +1,52 @@ +/* System includes */ + +#include +#include + + +void +ca_test_event(usr,chix,type,count,pval) +void *usr; +chid chix; +chtype type; +int count; +void *pval; +{ + + 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){ + case DBR_STRING: + printf("Value:\t<%s>\n",pval); + break; + case DBR_INT: + case DBR_ENUM: + printf("Value:\t<%d>\n",*(int *)pval); + break; + case DBR_FLOAT: + printf("Value:\t<%f>\n",*(float *)pval); + break; + case DBR_STS_STRING: + printf("Value:\t<%s>\n",((struct dbr_sts_string *)pval)->value); + break; + case DBR_STS_INT: + printf("Value:\t<%d>\n",((struct dbr_sts_int *)pval)->value); + break; + case DBR_STS_FLOAT: + printf("Value:\t<%f>\n",((struct dbr_sts_float *)pval)->value); + break; + case DBR_STS_ENUM: + printf("Value:\t<%d>\n",((struct dbr_sts_enum *)pval)->value); + break; + case DBR_GR_FLOAT: + printf("Value:\t<%f>\n",((struct dbr_gr_float *)pval)->value); + break; + + default: + printf("Sorry test_event does not handle this type monitor yet\n"); + } +} +