Copy of old lessons from afs webpage
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
# Example EPICS Makefile
|
||||
|
||||
# If you don't modify this file it will create
|
||||
# a program with the name of the current directory
|
||||
# from all C and C++ source files found and link
|
||||
# it to the EPICS client libraries.
|
||||
|
||||
# Where is EPICS base?
|
||||
EPICS = /usr/local/epics/base
|
||||
|
||||
# Where to install the program)?
|
||||
BINDIR = .
|
||||
#BINDIR = bin/$(EPICS_HOST_ARCH)
|
||||
|
||||
# What is the name of the program?
|
||||
# Add one line for each program if the program name
|
||||
# is not equal to the directory name
|
||||
PROGRAM +=
|
||||
|
||||
# List all sources of the program if not simply
|
||||
# all *.c *.cc *.C *.cxx *.cpp files in this
|
||||
# directory should be used.
|
||||
# Add one line for each source file.
|
||||
# If you build more than one PROGRAM, list
|
||||
# the sources separately for each program like
|
||||
# SRCS_<program> += <filename>
|
||||
SRCS +=
|
||||
|
||||
# list all include directories
|
||||
INCDIRS += $(EPICS)/include/os/Linux
|
||||
INCDIRS += $(EPICS)/include
|
||||
|
||||
# list all library directories
|
||||
LIBDIRS += $(EPICS)/lib/$(EPICS_HOST_ARCH)
|
||||
|
||||
# list all libraries (ca and Com are EPICS)
|
||||
LIBS += ca Com
|
||||
|
||||
#optimize:
|
||||
CFLAGS += -O3
|
||||
#debug:
|
||||
CFLAGS += -g
|
||||
|
||||
# don't touch the code below this line unless you know what you're doing.
|
||||
CPPFLAGS += $(INCDIRS:%=-I %)
|
||||
|
||||
CFLAGS += -MMD
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += $(USR_CFLAGS)
|
||||
|
||||
LDFLAGS += $(LIBDIRS:%=-L %)
|
||||
LDFLAGS += $(LIBDIRS:%=-Wl,-rpath,%)
|
||||
LDFLAGS += $(LIBS:%=-l %)
|
||||
|
||||
ifeq ($(words $(PROGRAM)),0)
|
||||
PROGRAM = $(notdir $(PWD))
|
||||
endif
|
||||
|
||||
SRCS += $(SRCS_$(PROGRAM))
|
||||
ifeq ($(words $(SRCS)),0)
|
||||
SRCS += $(wildcard *.c)
|
||||
SRCS += $(wildcard *.cc)
|
||||
SRCS += $(wildcard *.C)
|
||||
SRCS += $(wildcard *.cxx)
|
||||
SRCS += $(wildcard *.cpp)
|
||||
endif
|
||||
|
||||
OBJS = $(addprefix O.$(EPICS_HOST_ARCH)/,$(addsuffix .o,$(basename $(SRCS))))
|
||||
|
||||
ifndef EPICS_HOST_ARCH
|
||||
$(error EPICS_HOST_ARCH variable is missing on your system!)
|
||||
endif
|
||||
|
||||
.PHONY:
|
||||
.PHONY: build clean realclean
|
||||
build:
|
||||
|
||||
clean:
|
||||
rm -rf O.*
|
||||
|
||||
realclean: clean
|
||||
rm -f $(foreach prog,$(PROGRAM),$(BINDIR)/$(prog))
|
||||
|
||||
O.%:
|
||||
mkdir $@
|
||||
|
||||
$(BINDIR):
|
||||
mkdir -p $@
|
||||
|
||||
ifeq ($(words $(PROGRAM)),1)
|
||||
|
||||
build: $(BINDIR)/$(PROGRAM)
|
||||
|
||||
ifneq ($(BINDIR),.)
|
||||
$(PROGRAM): $(BINDIR)/$(PROGRAM)
|
||||
endif
|
||||
|
||||
$(BINDIR)/$(PROGRAM): $(BINDIR) O.$(EPICS_HOST_ARCH) O.$(EPICS_HOST_ARCH)/$(PROGRAM)
|
||||
rm -f $@
|
||||
cp O.$(EPICS_HOST_ARCH)/$(@F) $@
|
||||
|
||||
O.$(EPICS_HOST_ARCH)/$(PROGRAM): $(OBJS)
|
||||
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
else
|
||||
|
||||
build:
|
||||
for prog in $(PROGRAM); do make PROGRAM=$$prog; done
|
||||
|
||||
$(PROGRAM):
|
||||
make PROGRAM=$@
|
||||
|
||||
endif
|
||||
|
||||
O.$(EPICS_HOST_ARCH)/%.o: %.c
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||
|
||||
O.$(EPICS_HOST_ARCH)/%.o: %.cc
|
||||
$(CXX) -c $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) $< -o $@
|
||||
|
||||
O.$(EPICS_HOST_ARCH)/%.o: %.C
|
||||
$(CXX) -c $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) $< -o $@
|
||||
|
||||
O.$(EPICS_HOST_ARCH)/%.o: %.cxx
|
||||
$(CXX) -c $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) $< -o $@
|
||||
|
||||
O.$(EPICS_HOST_ARCH)/%.o: %.cpp
|
||||
$(CXX) -c $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) $< -o $@
|
||||
|
||||
-include O.$(EPICS_HOST_ARCH)/*.d
|
||||
@@ -0,0 +1,13 @@
|
||||
The two files caLesson4a.c and caLesson4b.c do exactly
|
||||
the same.
|
||||
|
||||
The difference is that caLesson4a.c uses EPICS 3.13-style
|
||||
functions which are deprecated in EPICS 3.14.
|
||||
|
||||
caLesson4a.c compiles with 3.13 and 3.14,
|
||||
caLesson4b.c only compiles with 3.14.
|
||||
|
||||
To see what has changed try
|
||||
diff caLesson4a.c caLesson4b.c
|
||||
or
|
||||
tkdiff caLesson4a.c caLesson4b.c
|
||||
@@ -0,0 +1,118 @@
|
||||
/* caLesson4.c
|
||||
by Dirk Zimoch, 2007
|
||||
|
||||
In this lesson we will learn to use monitors to read channels
|
||||
whenever they change instead of polling them.
|
||||
|
||||
Whenever you need to know about changes quickly, use monitors
|
||||
instead of high rate polling. It unnecessarily wastes network
|
||||
bandwidth to ask for a value 10 times per second when it only
|
||||
changes about once per minute. With any poll rate, you will
|
||||
always have a delay and you might still miss short peaks. With
|
||||
monitors you won't. And it only produces network traffic when
|
||||
something "interesting" happens.
|
||||
|
||||
For analog (i.e. DOUBLE) values, it is defined in the record
|
||||
how much change is required to be "interesting". For other types,
|
||||
e.g. ENUM, every change is "interesting".
|
||||
|
||||
To reduce the level of confusion, we leave away PV and macros for
|
||||
now and use the CA fundtions directly.
|
||||
|
||||
This file uses EPICS 3.13 functions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* include EPICS headers */
|
||||
#include <cadef.h>
|
||||
#define epicsAlarmGLOBAL
|
||||
#include <alarm.h>
|
||||
|
||||
/* This is a user-defined callback function.
|
||||
Whenever a channel has a new value, this function is called.
|
||||
See /usr/local/epics/base/include/cadef.h for the definition of
|
||||
struct event_handler_args.
|
||||
We don't use the fields 'count' and 'usr' here. The field 'count'
|
||||
if for arrays (that comes later) and 'usr' is an arbitrary pointer
|
||||
which you can pass to the monitor installation function (see below).
|
||||
*/
|
||||
static void monitor(struct event_handler_args args)
|
||||
{
|
||||
if (args.status != ECA_NORMAL)
|
||||
{
|
||||
/* Something went wrong. */
|
||||
SEVCHK(args.status, "monitor");
|
||||
return;
|
||||
}
|
||||
/* Let's have a look at the type of the data.
|
||||
It should be one of the types that we have requested.
|
||||
*/
|
||||
switch (args.type)
|
||||
{
|
||||
case DBR_STS_DOUBLE:
|
||||
{
|
||||
const struct dbr_sts_double* data = args.dbr;
|
||||
printf ("%s = %#g %s\n",
|
||||
ca_name(args.chid), data->value,
|
||||
epicsAlarmSeverityStrings[data->severity]);
|
||||
break;
|
||||
}
|
||||
case DBR_STS_ENUM:
|
||||
{
|
||||
const struct dbr_sts_enum* data = args.dbr;
|
||||
printf ("%s = %i %s\n",
|
||||
ca_name(args.chid),
|
||||
data->value,
|
||||
epicsAlarmSeverityStrings[data->severity]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf ("%s unsupported data type\n", ca_name(args.chid));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
char* gapName="X10SA-ID-GAP:READ";
|
||||
char* doneName="X10SA-ID-GAP:DONE";
|
||||
chid gapChannel, doneChannel;
|
||||
double search_timeout = 5.0; /* seconds */
|
||||
|
||||
/* Step1: initialize channel access and search for all channels. */
|
||||
ca_task_initialize();
|
||||
|
||||
ca_search(gapName, &gapChannel);
|
||||
ca_search(doneName, &doneChannel);
|
||||
|
||||
SEVCHK(ca_pend_io(search_timeout), "ca_search");
|
||||
|
||||
/* Step 2: setup the monitors */
|
||||
|
||||
/* Create two monitors with different data types.
|
||||
Connect them to the same callback function.
|
||||
The 4th argument will be passed to the 'usr' element
|
||||
in the handler arguments. We don't need it here.
|
||||
*/
|
||||
ca_add_event(DBR_STS_DOUBLE, gapChannel, monitor, NULL, NULL);
|
||||
ca_add_event(DBR_STS_ENUM, doneChannel, monitor, NULL, NULL);
|
||||
/* In EPICS 3.13, too many different things are called
|
||||
"event". I guess, this is the reason why this function
|
||||
has been renamed in 3.14 to ca_create_subscription.
|
||||
I would have preferred ca_create_monitor, however.
|
||||
*/
|
||||
SEVCHK(ca_flush_io(), "ca_add_event");
|
||||
/* We have used ca_flush_io() here because there is nothing
|
||||
to wait for. We just send out the request.
|
||||
Note: ca_pend_io(timeout) works like ca_flush_io() plus
|
||||
additional waiting for outstanding replies.
|
||||
*/
|
||||
|
||||
/* Step 3: wait forever and do Channel Access in the background */
|
||||
ca_pend_event(0.0);
|
||||
|
||||
/* We should never reach this point! */
|
||||
printf("Done\n");
|
||||
ca_task_exit();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/* caLesson4.c
|
||||
by Dirk Zimoch, 2007
|
||||
|
||||
In this lesson we will learn to use monitors to read channels
|
||||
whenever they change instead of polling them.
|
||||
|
||||
Whenever you need to know about changes quickly, use monitors
|
||||
instead of high rate polling. It unnecessarily wastes network
|
||||
bandwidth to ask for a value 10 times per second when it only
|
||||
changes about once per minute. With any poll rate, you will
|
||||
always have a delay and you might still miss short peaks. With
|
||||
monitors you won't. And it only produces network traffic when
|
||||
something "interesting" happens.
|
||||
|
||||
For analog (i.e. DOUBLE) values, it is defined in the record
|
||||
how much change is required to be "interesting". For other types,
|
||||
e.g. ENUM, every change is "interesting".
|
||||
|
||||
To reduce the level of confusion, we leave away PV and macros for
|
||||
now and use the CA fundtions directly.
|
||||
|
||||
This file uses EPICS 3.14 functions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* include EPICS headers */
|
||||
#include <cadef.h>
|
||||
#define epicsAlarmGLOBAL
|
||||
#include <alarm.h>
|
||||
|
||||
/* This is a user-defined callback function.
|
||||
Whenever a channel has a new value, this function is called.
|
||||
See /usr/local/epics/base/include/cadef.h for the definition of
|
||||
struct event_handler_args.
|
||||
We don't use the fields 'count' and 'usr' here. The field 'count'
|
||||
if for arrays (that comes later) and 'usr' is an arbitrary pointer
|
||||
which you can pass to the monitor installation function (see below).
|
||||
*/
|
||||
static void monitor(struct event_handler_args args)
|
||||
{
|
||||
if (args.status != ECA_NORMAL)
|
||||
{
|
||||
/* Something went wrong. */
|
||||
SEVCHK(args.status, "monitor");
|
||||
return;
|
||||
}
|
||||
/* Let's have a look at the type of the data.
|
||||
It should be one of the types that we have requested.
|
||||
*/
|
||||
switch (args.type)
|
||||
{
|
||||
case DBR_STS_DOUBLE:
|
||||
{
|
||||
const struct dbr_sts_double* data = args.dbr;
|
||||
printf ("%s = %#g %s\n",
|
||||
ca_name(args.chid), data->value,
|
||||
epicsAlarmSeverityStrings[data->severity]);
|
||||
break;
|
||||
}
|
||||
case DBR_STS_ENUM:
|
||||
{
|
||||
const struct dbr_sts_enum* data = args.dbr;
|
||||
printf ("%s = %i %s\n",
|
||||
ca_name(args.chid),
|
||||
data->value,
|
||||
epicsAlarmSeverityStrings[data->severity]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf ("%s unsupported data type\n", ca_name(args.chid));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
char* gapName="X10SA-ID-GAP:READ";
|
||||
char* doneName="X10SA-ID-GAP:DONE";
|
||||
chid gapChannel, doneChannel;
|
||||
double search_timeout = 5.0; /* seconds */
|
||||
|
||||
/* Step1: initialize channel access and search for all channels. */
|
||||
ca_context_create(ca_disable_preemptive_callback);
|
||||
|
||||
/* ca_create_channel has more parameters than the old ca_search
|
||||
but we don't need them here.
|
||||
*/
|
||||
ca_create_channel(gapName, NULL, NULL, CA_PRIORITY_DEFAULT, &gapChannel);
|
||||
ca_create_channel(doneName, NULL, NULL, CA_PRIORITY_DEFAULT, &doneChannel);
|
||||
|
||||
SEVCHK(ca_pend_io(search_timeout), "ca_search");
|
||||
|
||||
/* Step 2: setup the monitors */
|
||||
|
||||
/* Create two monitors with different data types.
|
||||
Connect them to the same callback function.
|
||||
The 6th argument will be passed to the 'usr' element
|
||||
in the handler arguments. We don't need it here.
|
||||
*/
|
||||
ca_create_subscription(DBR_STS_DOUBLE, 1, gapChannel,
|
||||
DBE_VALUE|DBE_ALARM, monitor, NULL, NULL);
|
||||
ca_create_subscription(DBR_STS_ENUM, 1, doneChannel,
|
||||
DBE_VALUE|DBE_ALARM, monitor, NULL, NULL);
|
||||
/* In 3.13 we have actually used a macro with default
|
||||
values for some arguments. Here, we have to specify:
|
||||
* we want scalars, not arrays (count=1)
|
||||
* we are interested in value and alarm changes
|
||||
*/
|
||||
|
||||
SEVCHK(ca_flush_io(), "ca_add_event");
|
||||
/* We have used ca_flush_io() here because there is nothing
|
||||
to wait for. We just send out the request.
|
||||
Note: ca_pend_io(timeout) works like ca_flush_io() plus
|
||||
additional waiting for outstanding replies.
|
||||
*/
|
||||
|
||||
/* Step 3: wait forever and do Channel Access in the background */
|
||||
ca_pend_event(0.0);
|
||||
|
||||
/* We should never reach this point! */
|
||||
printf("Done\n");
|
||||
ca_context_destroy();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user