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
<2002>
2003
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
<2002>
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|