Initial revision

This commit is contained in:
Bob Zieman
1990-11-18 21:47:01 +00:00
parent a7fd508504
commit c649b90a26
12 changed files with 4254 additions and 0 deletions

1469
src/ca/access.c Normal file

File diff suppressed because it is too large Load Diff

185
src/ca/acctst.c Normal file
View File

@ -0,0 +1,185 @@
/*
A CA test/debug routine
*/
/* System includes */
#include <vxWorks.h>
#ifdef vxWorks
#include <taskLib.h>
#endif
#include <cadef.h>
#include <caerr.h>
#include <db_access.h>
/*
#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;i<NUM;i++)
printf("Value Returned from build %f\n",pfloat[i]);
#ifdef VMS
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);
}
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<NUM;i++){
for(j=0;j<NUM;j++)
sprintf(&pstring[j][0],"%d",j+100);
SEVCHK(ca_array_put(DBR_STRING,NUM,chix1,pstring),NULL)
SEVCHK(ca_array_get(DBR_FLOAT,NUM,chix1,pfloat),NULL)
}
else
abort();
ca_pend_io(4.0);
# ifdef VMS
lib$show_timer();
# endif
for(i=0;i<NUM;i++)
printf("Value Returned from put/get %f\n",pfloat[i]);
printf("-- Put/Gets done- waiting for Events --\n");
ca_pend_event(30.0);
free(ptr);
free(pfloat);
exit();
}
void null_event()
{
printf("-");
}
void write_event(args)
struct event_handler_args args;
{
float a = *(float *) args.dbr;
a += 10.1;
SEVCHK(ca_rput(args.chid, &a),"write fail in event");
SEVCHK(ca_flush_io(),NULL);
}

139
src/ca/catime.c Normal file
View File

@ -0,0 +1,139 @@
/*
CA performance test
History
joh 09-12-89 Initial release
*/
# ifdef VMS
lib$init_timer();
# endif
# ifdef VMS
lib$show_timer();
#endif
/* System includes */
#include <vxWorks.h>
#ifdef vxWorks
#include <taskLib.h>
#endif
#include <cadef.h>
#include <caerr.h>
#include <db_access.h>
#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<NUM;i++)
((float *)ptr)[i]=1.0;
test(ai_1, "DBR_FLOAT", DBR_FLOAT, NUM, ptr);
for(i=0;i<NUM;i++)
strcpy((char *)ptr+(MAX_STRING_SIZE*i),"1.0");
test(ai_1, "DBR_STRING", DBR_STRING, NUM, ptr);
for(i=0;i<NUM;i++)
((int *)ptr)[i]=1;
test(ai_1, "DBR_INT", DBR_INT, NUM, ptr);
free(ptr);
exit();
}
test(chix, name, type, count, ptr)
chid chix;
int type,count;
void *ptr;
{
int test_put(), test_get(), test_wait();
printf("%s\n",name);
timex(test_put,chix, name, type, count, ptr);
timex(test_get,chix, name, type, count, ptr);
timexN(test_wait,chix, name, type, count, ptr);
}
test_put(chix, name, type, count, ptr)
chid chix;
int type,count;
void *ptr;
{
int i;
for(i=0; i< 10000;i++){
SEVCHK(ca_array_put(type,count,chix,ptr),NULL);
}
SEVCHK(ca_flush_io(),NULL);
}
test_get(chix, name, type, count, ptr)
chid chix;
int type,count;
void *ptr;
{
int i;
for(i=0; i< 10000;i++){
SEVCHK(ca_array_get(type,count,chix,ptr),NULL);
}
SEVCHK(ca_pend_io(0.0),NULL);
}
test_wait(chix, name, type, count, ptr)
chid chix;
int type,count;
void *ptr;
{
SEVCHK(ca_array_get(type,count,chix,ptr),NULL);
SEVCHK(ca_pend_io(0.0),NULL);
}

87
src/ca/conn.c Normal file
View File

@ -0,0 +1,87 @@
/************************************************************************/
/* */
/* 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 connection automation */
/* File: atcs:[ca]access.c */
/* Environment: VMS, UNIX, VRTX */
/* Equipment: VAX, SUN, VME */
/* */
/* */
/* */
/************************************************************************/
/*_end */
#include <vxWorks.h>
#include <cadef.h>
#include <db_access.h>
#include <iocmsg.h>
#include <iocinf.h>
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;
}
}
}

502
src/ca/convert.c Normal file
View File

@ -0,0 +1,502 @@
#include <db_access.h>
#include <net_convert.h>
#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;
}

84
src/ca/flow_control.c Normal file
View File

@ -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 <types.h>
#include <vxWorks.h>
#include <socket.h>
#include <ioctl.h>
#ifdef vxWorks
#include <ioLib.h>
#endif
#include <cadef.h>
#include <iocmsg.h>
#include <iocinf.h>
/*
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;
}

857
src/ca/iocinf.c Normal file
View File

@ -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 <iodef.h>
#include <inetiodef.h>
#include <stsdef.h>
#else
#endif
#include <errno.h>
#include <vxWorks.h>
#ifdef vxWorks
#include <ioLib.h>
#include <taskParams.h>
#endif
#include <types.h>
#include <socket.h>
#include <in.h>
#include <ioctl.h>
#include <cadef.h>
#include <net_convert.h>
#include <iocmsg.h>
#include <iocinf.h>
/* 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;i<NELEMENTS((p)->fds_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<nxtiiu;i++)
if( (net_addr.s_addr == iiu[i].sock_addr.sin_addr.s_addr)
&&
(net_proto == iiu[i].sock_proto)){
*iocix = i;
return ECA_NORMAL;
}
/**********************************************************************/
/* allocate and initialize an IOC info block for unallocated IOC */
/**********************************************************************/
/* is there an IOC In Use block available to allocate */
if(nxtiiu>=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;iocix<nxtiiu;iocix++)
if(iiu[iocix].send->stk){
/* 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(&notimeout);
}
# 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(&notimeout);
}
# 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<nxtiiu; iocix++)
FD_SET(iiu[iocix].sock_chan, &readch);
status = select( sizeof(fd_set)*NBBY,
&readch,
&writech,
&execch,
ptimeout);
while(status > 0){
for(iocix=0; iocix<nxtiiu; iocix++){
if(!FD_ISSET(iiu[iocix].sock_chan,&readch))
continue;
recv_msg(iocix);
}
/* make sure that nothing is left pending */
for(iocix=0;iocix<nxtiiu;iocix++)
FD_SET(iiu[iocix].sock_chan,&readch);
status = select( sizeof(fd_set)*NBBY,
&readch,
NULL,
NULL,
&notimeout);
}
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;
{
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);
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_cnt<sizeof(*pcount)){
printf("recv_msg_ast(): msg over/underflow %u\n",byte_cnt);
break;
}
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,
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

317
src/ca/iocinf.h Normal file
View File

@ -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 <lstLib.h>
#endif
#ifndef _TYPES_
# include <types.h>
#endif
#ifndef __IN_HEADER__
#include <in.h>
#endif
#ifdef vxWorks
#include <fast_lock.h>
#endif
#ifdef VMS
# include <ssdef>
#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)
*/

77
src/ca/iocmsg.h Normal file
View File

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

160
src/ca/net_convert.h Normal file
View File

@ -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 */
/* -126<exp<127 with mantissa of form 1.mant */
#define EXPMINIEEE -126 /* min for norm # IEEE exponent */
#ifdef VAX
struct mitflt{
unsigned mant1 :7;
unsigned exp :8;
unsigned sign :1;
unsigned mant2 :16;
};
/* Exponent sign bias */
# define MIT_SB 129
/* Conversion Ranges */
/* -128<exp<126 with mantissa of form 1.mant */
# define EXPMAXMIT 126 /* max MIT exponent */
/* passed by ref untill beter alternative found */
/* (this includes mapping of fringe reals to zero or infinity) */
/* (byte swaps included in conversion */
# define htonf(MIT,IEEE)\
{\
long exp,mant,sign;\
sign = ((struct mitflt *) (MIT))->sign;\
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

325
src/ca/service.c Normal file
View File

@ -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 <stsdef.h>
#endif
#include <vxWorks.h>
#include <types.h>
#include <cadef.h>
#include <net_convert.h>
#include <db_access.h>
#include <iocmsg.h>
#include <iocinf.h>
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; i<t_count; i++){
/* 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){
/* long word convert/transfer */
case DBR_INT:
case DBR_ENUM:
*(short *)dstptr = ntohs(*(short *)objptr);
break;
case DBR_FLOAT:
tmp = *(long *)objptr;
ntohf(&tmp, dstptr);
break;
case DBR_STRING:
if(dstptr != objptr)
strcpy( dstptr,
objptr);
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[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;
break;
default:
printf("post_msg(): unsupported db fld type in msg ?%d\n",t_type);
abort();
}
(char *) objptr += t_size;
(char *) dstptr += t_size;
}
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 */
);
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--;
}

52
src/ca/test_event.c Normal file
View File

@ -0,0 +1,52 @@
/* System includes */
#include <cadef.h>
#include <db_access.h>
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");
}
}