Files
caClientLessons/caLesson1/caLesson1.c

172 lines
5.8 KiB
C

/* caLesson1.c
by Dirk Zimoch, 2007
This is a very simple channel access client program.
It uses the EPICS R3.13 channel access functions
but can as well run with EPICS 3.14.
*/
#include <stdio.h>
/* include EPICS headers */
#include <cadef.h>
/*
#define WITH_NOT_EXISTING_CHANNEL
*/
/* Strings describing the connection status of a channel */
const char *channel_state_str[4] = {
"not found",
"connection lost",
"connected",
"closed"
};
int main ()
{
chid beamcurrentID;
double beamcurrent;
chid gapID;
double gap;
#ifdef WITH_NOT_EXISTING_CHANNEL
chid doesnotexistID;
double doesnotexist;
#endif
int status;
/* Step1: initialize channel access and search for all channels. */
ca_task_initialize();
/* Assign channel names to channel IDs. */
ca_search ("ARIDI-PCT:CURRENT", &beamcurrentID);
#ifdef WITH_NOT_EXISTING_CHANNEL
ca_search ("doesnotexist", &doesnotexistID);
#endif
ca_search ("X10SA-ID-GAP:READ", &gapID);
/* Nothing has been sent to the network so far! */
/* Send all requests in parallel, wait for maximal 5.0 seconds. */
printf ("searching ...\n");
status = ca_pend_io(5.0);
/* This ca_pend_io() is a very expensive action in terms of network
bandwidth because UDP broadcasts are sent to all IOCs in the subnet.
For every broadcast, each IOC has to check if it owns one of the
requested channels. If no IOC replies, the boradcast request
is repeated up to 100 times.
Do not search for obsolete channels! If channels have been
removed, also remove them from your clients to reduce unnecessary
broadcast traffic. Check the spelling of channel names if
channels don't connect.
One broadcast package can contain many channel requests. This
is much more efficient than sending only one request at a time.
Thus, always try to connect all channels at once, using only
one ca_pend_io() after all ca_search() calls. This also speeds up
your program: waiting 10 seconds for 1000 channels in parallel
is much shorter than even waiting only 1 second for 1000 sequential
channel searches. ca_pend_io() returns early when all channels are
found.
*/
/* Check for errors */
switch (status)
{
case ECA_NORMAL:
printf ("all channels found\n");
break;
case ECA_TIMEOUT:
printf ("some channels not found yet\n");
break;
default:
printf ("unexpected error while searching: %s\n",
ca_message(status));
}
/* If not all channels can be found now, the IOC is probably down.
Searching continues in the background and channels connect
automatically when the IOC comes up.
Try to uncomment the #define WITH_NOT_EXISTING_CHANNEL above to
see what happens if a channel cannot be found.
Normally, ca_search() should not be called any more after startup.
There may be exceptions, when channels are added dynamically to a
running program. But this is not the normal case.
Connected channels may disconnect and reconnect later automatically
when an IOC reboots. Always keep this in mind when doing any
network traffic. Any long-lived program, such as GUIs or servers,
MUST be written in a way to survive disconnected channels and
they MUST react in a reasonable manner.
It depends on the application and is generally is your problem what
"reasonable" means.
*/
/* Step 2: do channel access data transfer. */
ca_get(DBR_DOUBLE, beamcurrentID, &beamcurrent);
#ifdef WITH_NOT_EXISTING_CHANNEL
ca_get(DBR_DOUBLE, doesnotexistID, &doesnotexist);
#endif
ca_get(DBR_DOUBLE, gapID, &gap);
/* Nothing has been sent to the network so far! */
/* Send all request in parallel, wait for maximal 1.0 second. */
printf ("reading ...\n");
status = ca_pend_io(1.0);
/* As before, it increases network performance to do as many ca_get()
calls as possible with one ca_pend_io(). In opposite to searching,
data transfer is done via TCP. Thus, it affects only the client
and the IOC and all network components in between. It does not
affect all IOCs on the same network as searching does! But still,
many requests can be sent in the same message if they go to the
same IOC -- which is often the case. Luckily, you don't have to
care about this. Just always try to read as many channels as
possible in parallel.
*/
switch (status)
{
case ECA_NORMAL:
printf ("all values received\n");
break;
case ECA_TIMEOUT:
printf ("some values not received\n");
break;
default:
printf ("unexpected error while reading: %s\n",
ca_message(status));
}
/* Print values of all channels but inform the user
if a channel is connected or not. The value of a
not connected channel is not valid, of course.
Never take such a value for serious!
Always when the result of ca_pend_io() after ca_get()
is not ECA_NORMAL, you MUST check ca_state() of all
involved channels before trusting any value.
*/
printf ("Beam current (%s): %g\n",
channel_state_str[ca_state(beamcurrentID)],
beamcurrent);
#ifdef WITH_NOT_EXISTING_CHANNEL
printf ("Does not exist (%s): %g\n",
channel_state_str[ca_state(doesnotexistID)],
doesnotexist);
#endif
printf ("Gap (%s): %g\n",
channel_state_str[ca_state(gapID)],
gap);
/* Last step: free all channel access resources */
ca_task_exit();
return 0;
}