EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

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

Subject: Re: USE of CA lib: problem using ca_array_put_callback with strings
From: haquin <[email protected]>
To: Andrew Johnson <[email protected]>
Cc: [email protected]
Date: Fri, 14 Nov 2008 17:34:16 +0100
Sorry for the bad link,
here is the working one: http://lansce.lanl.gov/EPICSdata/ca/client/caX5Ftutor-1.html


You will find attached the C file we are using, it was reconstructed from the above link, Section 3 Writing to PVs and Using Connection Handlers.
the function call that doesn't work correctly is the "ca_put_callback" and the callback function is "an_event_handler"


We tryied with the command line, and we can reproduce the problem, here is the result:
[haquin@accep1 haquin]$ caput -c LB-DIA-ALB-TST2:Read_16bits_Reg.DESC "abcdefg"
Old : LB-DIA-ALB-TST2:Read_16bits_Reg.DESC It's 14-NOV-2008 16:52:23.04
New : LB-DIA-ALB-TST2:Read_16bits_Reg.DESC a
[haquin@accep1 haquin]$ caput LB-DIA-ALB-TST2:Read_16bits_Reg.DESC "abcdefg"
Old : LB-DIA-ALB-TST2:Read_16bits_Reg.DESC a
New : LB-DIA-ALB-TST2:Read_16bits_Reg.DESC abcdefg


Thanx

Andrew Johnson a Ãcrit :
Hi Christophe,

On Friday 14 November 2008 08:01:43 haquin wrote:
I have some problems with the Channel Access library use,
more precisely the use of /*ca_array_put_callback*/ with STRINGS !

We are using a peace of exemple C code, picked-up at :
*http://lansce.lanl.gov/EPICSdata/ca/client*, that uses this CA API.
We have some problems with the ca_array_put_callback when we want to
write strings.

That URL doesn't work any more, can you post at least an extract of the code that you're using, showing both the call to ca_array_put_callback() and your callback routine.


We use this code to put a string in the DESC field of a record,
The problem is that only the first caracter of the string is written to
the PV,
The callback is called, everything seem to bee correct except that there
is only the first caracter in the destination.

I'm not able to recreate the problem on R3.14.10, so it may be a bug in the code you're using (I'm not suggesting that you need to upgrade though, since I'm not aware of any bug fixes in that area of the code). The caput program that comes with base has a -c option that means 'use put callback' and can deal with arrays. Here's how I tested it:


tux% bin/linux-x86_64/caput -c anjHost:aiExample.DESC "New string"
Old : anjHost:aiExample.DESC         Analog input
New : anjHost:aiExample.DESC         New string
tux% bin/linux-x86_64/caput -c -s -a anjHost:aiExample.DESC 1 "Array string"
Old : anjHost:aiExample.DESC         New string
New : anjHost:aiExample.DESC         Array string

Note that the DESC field will only accept a 1-item array; if you try to send more it will fail, demonstrating that caput is doing an array put:

tux% bin/linux-x86_64/caput -c -s -a anjHost:aiExample.DESC 2 String array
Old : anjHost:aiExample.DESC         Array string
Write callback operation timed out
New : anjHost:aiExample.DESC         Array string

- Andrew

#include <cadef.h>
#include <stdio.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);
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 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",
    ca_name(handler_args.chid)); 
  return;
}

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;
}
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){
 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;
}
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) != NULL && strcmp(Name, "quit") !=0;
	 printf("%s\n", "Enter PV name or \"quit\" to stop")){

      ca_pend_event(POLL);
      pCurrent = search(Name);
      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);
  }
}
begin:vcard
fn:Christophe Haquin
n:Haquin;Christophe
email;internet:[email protected]
tel;work:02 31 45 46 61
x-mozilla-html:FALSE
version:2.1
end:vcard


Replies:
Re: USE of CA lib: problem using ca_array_put_callback with strings Andrew Johnson
References:
USE of CA lib: problem using ca_array_put_callback with strings haquin
Re: USE of CA lib: problem using ca_array_put_callback with strings Andrew Johnson

Navigate by Date:
Prev: Re: USE of CA lib: problem using ca_array_put_callback with strings Andrew Johnson
Next: Re: USE of CA lib: problem using ca_array_put_callback with strings Andrew Johnson
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: USE of CA lib: problem using ca_array_put_callback with strings Andrew Johnson
Next: Re: USE of CA lib: problem using ca_array_put_callback with strings Andrew Johnson
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Sep 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·