Hello World for EPICS


As a new user to EPICS — an open-source, distributed, control system normally used to control large-scale particle accelerators — I wanted a nice soft introduction to the first steps of installation and implementation.  I was looking for an EPICS equivalent to the “Hello World” code normally used as the very first piece of code a new user, but I just couldn’t find it.  After a lot of trial and error, and a significant amount of help from a large number of experts, I feel proficient enough to implement a small control system.  Several examples of this can be found in some of my previous blog entries, but here I will try to give the simplest example I can imagine of an EPICS implementation.

Install EPICS

I’m assuming you have access to a working EPICS installation.  Perhaps you followed my instructions to install it on a Raspberry Pi (click here), or you’re working in a Docker container (click here), but I will assume that everything is ready to go.

Simplest possible system

This is supposed to be a “Hello World” version of an EPICS installation, and such systems rarely do anything useful.  That is no less true for this implementation.

Instead of trying to control some external device — examples of which can already be found on this blog — I will build a system that does nothing more than increment a counter.  That’s it.  One Process Variable (a PV) that increases its value by 1 once per second.

Preparation

First, make a space to work in.

mkdir -p ~/Apps/epics/helloWorld
cd ~/Apps/epics/helloWorld

Now, use the convenience application provided by EPICS to create the appropriate layout for an Input-Output Controller (IOC).  Note that the second command will query you for an application name, but I normally leave this blank by hitting “Enter” at that prompt.

makeBaseApp.pl -t ioc helloWorld
makeBaseApp.pl -i -t ioc helloWorld

If all has gone well so far, you should now have the correct directory layout to start building your toy system.

Building

Now we need to add the functionality to increment a counter.  Move to the source directory.

cd helloWorldApp/src/

In this directory, create a new file called testProc.cpp, and put the following code into it.

#include <stdio.h>
#include <subRecord.h>
#include <registryFunction.h>
#include <epicsExport.h>

static int testProc(subRecord *precord) {

    precord->val++;

    return 0;
}

/* Note the function must be registered at the end!*/
epicsRegisterFunction(testProc);

This function takes a pointer to an EPICS “subRecord” as input, and this is a data structure associated with EPICS sub-routines.  A sub-routine in EPICS is basically a PV that relies on C-code (like that you have just written) to feed the PV with the correct value.

The body of the function is painfully simple.  It takes the current value of the record, and increments it by one.

Lastly, the function must be registered with EPICS.

For EPICS to be made aware that this is a function, it must also be added to another file.  In the same directory as the testProc.cpp file that you have just made, create a new file called testProc.dbd and add the following to it.  (Yes, it really is just one line.)

function(testProc)

Now you need to let the Makefile know about these two new files.  In the same directory, open up the Makefile, and add the following two lines to the appropriate places (you can see where to add them by following the guidance of the comments in that file).

helloWorld_DBD += testProc.dbd
helloWorld_SRCS += testProc.cpp

Next, we associate this subroutine with a PV.  Move to the right directory.

cd ../Db

Create a new file called testProc.db containing the following.

record(sub, testVal) {
     field(SNAM, testProc)
     field(SCAN, "1 second")
}

This will create a subroutine record called testVal, associated with a subroutine named (SNAM) testProc, that will update (SCAN) once per second.

In the same directory edit the Makefile to include the following line.  Note that it is important that this is added to the appropriate section of the Makefile (immediately after the “#DB += xxx.db” line).

DB += testProc.db

Lastly, we need to edit the file that will become the entry-point of the whole system.  Move to the right place,

cd ../../iocBoot/iochelloWorld/

Open the st.cmd file, and find the section that deals with loading record instances.  Add the following line at the appropriate place (again, follow the comments in the file for guidance),

dbLoadRecords("db/testProc.db")

Compiling

At this point you have done everything you need to do to make this work.  All that is left is to compile the code and run it.

Go to the top-level of the IOC and make the executable.

cd ~/Apps/epics/helloWorld
make
chmod a+x iocBoot/iochelloWorld/st.cmd

Running

cd iocBoot/iochelloWorld/
 ./st.cmd

Congratulations!

Now the IOC should be running, and you should be able to view and monitor the value of testVal as it happily increments itself once a second.

camonitor testVal

Leave a comment