Experimental Physics and Industrial Control System
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
<2008>
2009
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
<2008>
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024