Copy of old lessons from afs webpage

This commit is contained in:
2026-02-06 10:10:27 +01:00
commit 80df91d0df
43 changed files with 6945 additions and 0 deletions
+130
View File
@@ -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
+13
View File
@@ -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
+118
View File
@@ -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;
}
+124
View File
@@ -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;
}