EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  <20022003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  <20022003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: CA client library and Connection handler
From: "Jeff Hill" <[email protected]>
To: "'Adam Jon DeGrush'" <[email protected]>, <[email protected]>
Date: Thu, 31 Jan 2002 15:43:49 -0700
Adam,

I built the test program at the following URL and it appears to run
without seg faulting against the latest versions of EPICS R3.13 and
R3.14. I did notice that I could get the program to fail if I entered an
empty PV name by hitting the carriage return. The program stopped on a
SEVCHK of the status from ca_create_channel (ca_search) because this
function will not accept an empty channel name. 

http://mesa53.lanl.gov/lansce8/Epics/ca/client/caX5Ftutor-6.html#HEADING
6-0

I had to fix a few minor syntax errors to get this code to build. I have
attached my version. I will also add that I didn't write this program.

>From your letter it is difficult to guess at the root cause of your
troubles. However I will agree with Brian's advice about installing the
connection handler only once when you create the channel, and also that
confusing problems are often easier to identify in a source level
debugger.

Please take a look at the stack trace in the debugger and if the cause
isn't obvious then it would be ok to send your hopefully simplified and
self contained example source code and I will take a look.

The latest CA ref manual for EPICS R3.14 can be found at this URL. It's
a bit easier o use because it has a hyperlink index. There are a few CA
functions that are present in R3.14, mentioned in this manual, but not
in R3.13. 

http://www.aps.anl.gov/epics/modules/base/CA3_14_0beta1.html

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include <cadef.h>

#define MAXLEN  20
#define POLL 1.0e-9
#define SHRT_DLY 0.1
#define LNG_DLY 0.25

struct Channel{
    dbr_string_t name;
    chid chan;
    struct Channel *next;
    struct Channel *prev;
} *pFirst = NULL, *pLast;

void connect_handler1(struct connection_handler_args);
void connect_handler2(struct connection_handler_args);
void an_event_handler(struct event_handler_args);
struct Channel *search(char *Name);

int main()
{
	int status, i, j, k;
	dbr_float_t *pValue;
	dbr_string_t Value;
	dbr_string_t Name[MAXLEN];
	struct Channel *pCurrent;
	unsigned long Nelem; 
	
	/* initialize Channel Access task */
	SEVCHK(ca_task_initialize(), "Unable to initialize");
	
	/* Get channel names and establish connection for each.*/
	/* Allocate memory for first node, and then for each       */
	/* addtional node after connection is established. Loop   */
	/* until user enters"quit".
*/
	for (printf("Enter a channel name.\n"),
		pCurrent=(struct Channel *)calloc(1, sizeof(struct
Channel));
	gets(pCurrent->name) != NULL && strcmp(pCurrent->name, "quit")
!= 0;
	printf("Enter a channel name or \"quit\" to stop.\n")){
		
		status = ca_search_and_connect(
			pCurrent->name, /* name string */
			&(pCurrent->chan),/* chid */
			connect_handler1, /* connection handler */
			pCurrent      /* user-supplied address */ );
		SEVCHK(status, NULL);
		ca_pend_event(LNG_DLY);
		if (ca_state(pCurrent->chan) != cs_conn)
			printf("couldn't establish connection to %s;
ignoring\n", pCurrent->name);
		else 
			pCurrent =(struct Channel *)
calloc(1,sizeof(struct Channel));
	}
	
	/* Install a different connection handler on each channel. */
	if(pFirst != NULL){
		for (pCurrent = pFirst; pCurrent != NULL; pCurrent =
pCurrent->next){
	
status=ca_change_connection_event(pCurrent->chan, connect_handler2);
			SEVCHK(status, "ca_change_connection_event:
couldn't change handler");
		}
		
		ca_flush_io();
		
		/* Loop until "quit" is entered. Get Channel name. If */
		/* found, prompt for values; else skip rest of loop.
*/
		/* Call ca_put_callback().
*/
		for (	i = 0, printf("%s\n%s\n", "Enter the PV's name",
"Enter \"quit\" to stop");
				gets(Name[0]) != NULL && strcmp(Name[0],
"quit") !=0;
				printf("%s\n", "Enter PV name or
\"quit\" to stop")){
			
			ca_pend_event(POLL);
			pCurrent = search(Name[0]);
			if(pCurrent == NULL){
				printf("Cannot find channel name in
list. Disconnected?\n");
				continue;
			}
			Nelem = ca_element_count(pCurrent->chan);
			if(Nelem == 1){
				printf("Enter value.\n");
				if(gets(Value) != NULL){
					status =
ca_put_callback(DBR_STRING,   /* external type */
						pCurrent->chan,
/* chid */
						Value,
/* string of value */
						an_event_handler,
/* callback */
						pCurrent   /* user
supplied address */);
					SEVCHK(status, NULL);
				}
			}
			else if (Nelem > 1){
				printf("Enter up to %u values or q to
quit.\n", Nelem);
				pValue = (float *) calloc(Nelem,
sizeof(*pValue));
				for(k = 0; (j = scanf("%f", pValue+k))
== 1 && j != EOF && k < Nelem; k++);
				j = getchar();
				status =
ca_array_put_callback(DBR_FLOAT,      /* external type */
					Nelem,  /* no. of elements to be
sent */
					pCurrent->chan,
/* chid */
					pValue,                    /*
array of values */
					an_event_handler,             /*
callback */
					pCurrent       /* user supplied
address */ );
				SEVCHK(status, NULL);
			}
			ca_pend_event(SHRT_DLY);
		}
		return(0);
	}
	return (0);
}
	
void connect_handler2(struct connection_handler_args connect_args)
{
	struct Channel *pCurrent;
	struct Channel *pPrevious, *pNext;

	/* if connection down, free memory of user       */
	/* supplied address, and delete nodes from list. */
	if (connect_args.op == CA_OP_CONN_DOWN){
		pCurrent = ca_puser(connect_args.chid);
		if(pCurrent != pLast && pCurrent != pFirst){
			pPrevious = pCurrent->prev;
			pNext = pCurrent->next;
			pPrevious->next = pNext;
			pNext->prev = pPrevious;
			free(pCurrent);
		}
		else if (pCurrent == pLast && pCurrent != pFirst){
			pLast = pCurrent->prev;
			pLast->next = NULL;
			free(pCurrent);
		}
		else if (pCurrent == pFirst && pCurrent != pLast){
			pFirst = pCurrent->next;
			pFirst->prev = NULL;
			free(pCurrent);
		}
		else if(pCurrent == pFirst && pCurrent == pLast){
			pFirst = NULL;
			pLast = NULL;
			free(pCurrent);
		}
		printf("%s: channel disconnected.\n",
ca_name(connect_args.chid));
	}
	/* if re-connected, re-allocate memory */
	else if(connect_args.op == CA_OP_CONN_UP){
		pCurrent = (struct Channel *) calloc(1, sizeof(struct
Channel));
		ca_set_puser ( connect_args.chid, pCurrent );
		strcpy(pCurrent->name, ca_name(connect_args.chid));
		pCurrent->chan = connect_args.chid;
		if (pFirst == NULL){
			pFirst = pCurrent;
			pFirst->prev = NULL;
			pLast = pCurrent;
			pCurrent->next = NULL;
		}
		else{
			pLast->next = pCurrent;
			pCurrent->prev = pLast;
			pCurrent->next = NULL;
			pLast = pCurrent;
		}
		printf("%s: channel re-connected.\n", pCurrent->name);
	}
	return;
}

void an_event_handler(struct event_handler_args handler_args)
{
  
	if (handler_args.status != ECA_NORMAL){
		printf("channel %s: put operation not sucessful.\n",
				ca_name(handler_args.chid));
		SEVCHK(handler_args.status, NULL);
	}
	else
		printf("channel %s: put operation completed.\n"); 
	return;
}

struct Channel *search(char *Name)
{
	struct Channel *pCurrent;
	int flag = 0;
	if(pFirst != NULL){
		for(pCurrent = pFirst; pCurrent != NULL; pCurrent =
pCurrent->next){
			if(strcmp(pCurrent->name, Name) == 0){
				flag = 1;
				break;
			}
		}
	}
	if(flag)
		return (pCurrent);
	else
		return (NULL);
}

void connect_handler1(struct connection_handler_args connect_args)
{
	struct Channel *pCurrent;

	/* set point to user-supplied address */
	pCurrent = ca_puser(connect_args.chid);

	/* if connection up, intialize list or add node */
	if(connect_args.op == CA_OP_CONN_UP){
		if(pFirst == NULL){
			pFirst = pCurrent;
			pFirst->prev = NULL;
			pLast = pCurrent;
		}
		pLast->next = pCurrent;
		pCurrent->prev = pLast;
		pCurrent->next = NULL;
		pLast = pCurrent;
		printf("%s is connected.\n", pCurrent->name);
	}
	/* if connection down, print message. This block */
	/*  is unlikely to ever be used.
*/
	else
		printf("%s is not connected.\n", pCurrent->name);
	return;
}


> -----Original Message-----
> From: Adam Jon DeGrush [mailto:[email protected]]
> Sent: Wednesday, January 30, 2002 5:54 PM
> To: [email protected]
> Subject: CA client library and Connection handler
> 
> 
> Hello All,
> 
> I am relatively new to epics so I apologize if my question seems
poorly
> informed.
> 
> I am trying to monitor the connection of channels using
> ca_change_connection_event from the client library and am having
> difficulty getting it to work. I would like to do a group poll
> (synchronous or asynchronously) of my channels at a certain frequency
> and
> would like make sure that my channels are connected before I do this.
I
> though I could just install a connection handler like in the example:
> 
>     for (pCurrent = pFirst; pCurrent != NULL; pCurrent = pCurrent-
> >next){
>        status=ca_change_connection_event(pCurrent->chan,
> 	                                myHandler);
>        SEVCHK(status, "ca_change_connection_event:
> 			couldn't change handler");
>        }
> and then have something like:
> 
> while(1){
> 	ca_pend_event(POLL); //
> 	myGroupPoll();
> 	nanosleep(fiveseconds,NULL);
>         }
> 
> and then have my handler either block or remove from my list those
> channels that have been disconnected. Instead when I run it and
> disconnect
> a channel there is a pause of about 5 seconds and then a segmentation
> violation( although I think handler does get called).  The same thing
> happens if I remove myGroupPoll().
> 
> In addition I seem the same behavior running the example code given
at:
> 
> http://mesa53.lanl.gov/lansce8/Epics/ca/client/caX5Ftutor-
> 6.html#HEADING6-0
> 
> Any help would be greatly appreciated.
> 
> Thanks,
> Adam DeGrush




Replies:
RE: CA client library and Connection handler Adam Jon DeGrush
References:
CA client library and Connection handler Adam Jon DeGrush

Navigate by Date:
Prev: RE: caTCL with R3.14 and Linux Jeff Hill
Next: RE: CA client library and Connection handler Adam Jon DeGrush
Index: 1994  1995  1996  1997  1998  1999  2000  2001  <20022003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: CA client library and Connection handler Brian McAllister
Next: RE: CA client library and Connection handler Adam Jon DeGrush
Index: 1994  1995  1996  1997  1998  1999  2000  2001  <20022003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 10 Aug 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·