Getting Started

Getting Started with EPICS

Installation on Linux/UNIX/Darwin (Mac)

1. Installing EPICS. What is it about?

We assume that you know more or less what EPICS is. Here we want to start
from scratch and get to the point where we have a working server, offering some
PVs for reading (caget or pvget) and writing
(caput or pvput), and we read and write on them from
another terminal, either on the same machine or on another one in the same
network. If you are going to use two different machines, you will have to
repeat the steps for installing EPICS for both of them.

2. Prepare your system

You need make, c++ and libreadline to compile from source. On macOS these
dependencies can be installed by using e.g. homebrew. On Linux you
can use apt-get install.

3. Install EPICS

mkdir $HOME/EPICS
cd $HOME/EPICS
git clone --recursive https://github.com/epics-base/epics-base.git
cd epics-base
make

After compiling you should put the path into $HOME/.profile or
into $HOME/.bashrc by adding the following to either one of those
files:

export EPICS_BASE=${HOME}/EPICS/epics-base
export EPICS_HOST_ARCH=$(${EPICS_BASE}/startup/EpicsHostArch)
export PATH=${EPICS_BASE}/bin/${EPICS_HOST_ARCH}:${PATH}

EpicsHostArch is a program provided by EPICS that returns the architecture
of your system. Thus the code above should be fine for every architecture.

4. Test EPICS

Now log out and log in again, so that your new path is set correctly.
Alternatively, you can execute the three lines above beginning with export
directly from the terminal.

Run softIoc and, if everything is ok, you should see an EPICS
prompt.

softIoc
epics>

You can exit with ctrl-c or by typing exit.

Voilà.

Ok, that is not very impressive, but at least you know that EPICS is
installed correctly. So now let us try something more complex, which will
hopefully suggest how EPICS works.

In whatever directory you like, prepare a file test.db that
reads like

record(ai, "temperature:water")
{
        field(DESC, "Water temperature in the fish tank")
}

This file defines a record instance called temperature:water, which
is an analog input (ai) record. As you can imagine DESC stays for
Description. Now we start softIoc again, but this time using this
record database.

softIoc -d test.db

Now, from your EPICS prompt, you can list the available records with the
dbl command and you will see something like

epics> dbl
temperature:water
epics>

Open a new terminal (we call it nr. 2) and try the command line tools
caget and caput. You will see something like

your prompt> caget temperature:water
temperature:water              0
your prompt> caget temperature:water.DESC
temperature:water.DESC         Water temperature in the fish tank
your prompt> caput temperature:water 21
Old : temperature:water              0
New : temperature:water              21
your prompt> caput temperature:water 24
Old : temperature:water              21
New : temperature:water              24
your prompt> caget temperature:water 
temperature:water              24
 ... etc.

Now open yet another terminal (nr. 3) and try camonitor as

camonitor temperature:water

First, have a look at what happens when you change the temperature:water
value from terminal nr. 2 using caput. Then, try to change the
value by some tiny amounts, like 15.500001, 15.500002, 15.500003… You will
see that camonitor reacts but the readings do not change. If you
wanted to see more digits, you could run

camonitor -g8 temperature:water

For further details on the Channel Access protocol, including documentation
on the caput, caget, camonitor
command line tools, please refer to the Channel Access Reference Manual.

In real life, however, it is unlikely that the 8 digits returned by your
thermometer (in this example) are all significant. We should thus limit the
traffic to changes of the order of, say, a hundredth of a degree. To do this,
we add one line to the file test.db, so that it reads

record(ai, "temperature:water")
{
        field(DESC, "Water temperature in Lab 10")
        field(MDEL, ".01")
}

MDEL stands for Monitor Deadband. If you now run

softIoc -d test.db

with the new test.db file, you will see that
camonitor reacts only to changes that are larger than 0.01.

This was just a simple example. Please refer to the Record Reference Manual for further
information.

5. Create a demo/test ioc to test ca and pva

mkdir -p $HOME/EPICS/TEST/testIoc
cd $HOME/EPICS/TEST/testIoc
makeBaseApp.pl -t example testIoc
makeBaseApp.pl -i -t example testIoc
make
cd iocBoot/ioctestIoc
chmod u+x st.cmd
ioctestIoc> ./st.cmd
#!../../bin/darwin-x86/testIoc
< envPaths 
epicsEnvSet("IOC","ioctestIoc") 
epicsEnvSet("TOP","/Users/maradona/EPICS/TEST/testIoc") 
epicsEnvSet("EPICS_BASE","/Users/maradona/EPICS/epics-base") 
cd "/Users/maradona/EPICS/TEST/testIoc" 
## Register all support components 
dbLoadDatabase "dbd/testIoc.dbd" 
testIoc_registerRecordDeviceDriver pdbbase 
## Load record instances dbLoadTemplate "db/user.substitutions" 
dbLoadRecords "db/testIocVersion.db", "user=junkes" 
dbLoadRecords "db/dbSubExample.db", "user=junkes" 
#var mySubDebug 1 
#traceIocInit 
cd "/Users/maradona/EPICS/TEST/testIoc/iocBoot/ioctestIoc" 
iocInit 
Starting iocInit 
############################################################################ 
## EPICS R7.0.1.2-DEV 
## EPICS Base built Mar 8 2018 
############################################################################ 
cas warning: Configured TCP port was unavailable. 
cas warning: Using dynamically assigned TCP port 52907, 
cas warning: but now two or more servers share the same UDP port. 
cas warning: Depending on your IP kernel this server may not be 
cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST) 
iocRun: All initialization complete 
2018-03-09T13:07:02.475 Using dynamically assigned TCP port 52908. 
## Start any sequence programs 
#seq sncExample, "user=maradona" epics> dbl
maradona:circle:tick
maradona:compressExample
maradona:line:b
maradona:aiExample
maradona:aiExample1
maradona:ai1
maradona:aiExample2
 ... etc. ...
epics>

Now in another terminal, one can try command line tools like

  1. caget, caput, camonitor,
    cainfo (Channel Access)
  2. pvget, pvput, pvlist,
    eget … (PVAccess)

6. Add the asyn package

cd $HOME/EPICS
mkdir support
cd support
git clone https://github.com/epics-modules/asyn.git
cd asyn

Edit $HOME/EPICS/spport/asyn/configure/RELEASE and set
EPICS_BASE like

EPICS_BASE=${HOME}/EPICS/epics-base

Comment IPAC=... and SNCSEQ=..., as they are not
needed for the moment. The whole file should read:

 #RELEASE Location of external products
HOME=/Users/maradona
SUPPORT=$(HOME)/EPICS/support
-include $(TOP)/../configure/SUPPORT.$(EPICS_HOST_ARCH)
# IPAC is only necessary if support for Greensprings IP488 is required
# IPAC release V2-7 or later is required.
#IPAC=$(SUPPORT)/ipac-2-14
# SEQ is required for testIPServer
#SNCSEQ=$(SUPPORT)/seq-2-2-5
# EPICS_BASE 3.14.6 or later is required
EPICS_BASE=$(HOME)/EPICS/epics-base
-include $(TOP)/../configure/EPICS_BASE.$(EPICS_HOST_ARCH)

Now, run

make

7. Install StreamDevice (by Dirk Zimoch, PSI)

StreamDevice does not come with its own top location and
top/configure directory. It expects to be put into an already
existing top directory structure. We can simply create one with
makeBaseApp.pl

cd $HOME/EPICS/support
mkdir stream
cd stream/
makeBaseApp.pl -t support
git clone https://github.com/paulscherrerinstitute/StreamDevice.git
cd StreamDevice/
rm GNUmakefile

Now we must edit the
$HOME/EPICS/support/stream/configure/RELEASE . The not-commented
lines must read

# Variables and paths to dependent modules:
MODULES = ${HOME}/EPICS/support
# If using the sequencer, point SNCSEQ at its top directory:
#SNCSEQ = $(MODULES)/seq-ver
# EPICS_BASE should appear last so earlier modules can override stuff:
EPICS_BASE = ${HOME}/EPICS/epics-base
# These lines allow developers to override these RELEASE settings
# without having to modify this file directly.
-include $(TOP)/../RELEASE.local
#-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
-include $(TOP)/configure/RELEASE.local
ASYN=$(MODULES)/asyn

Remember that $(NAME) works if it is defined within the same
file, but ${NAME} with curly brackets must be used if a shell
variable is meant. It is possible that the compiler does not like some of the
substitutions. In that case, replace the ${NAME} variables with
full paths, like /Users/maradona/EPICS....

Finally run make (we are in the directory
...EPICS/support/stream/StreamDevice)

Creation of an Input/Output Controller (IOC)

An IOC allows to talk to devices e.g. via ethernet. Create a directory for
the IOCs. For example $HOME/EPICS/IOCs

cd $HOME/EPICS; mkdir IOCs; cd IOCs

Create a top for an IOC called sampleIOC

mkdir sampleIOC; cd sampleIOC
makeBaseApp.pl -t example sampleIOC
makeBaseApp.pl -i -t example sampleIOC
Using target architecture darwin-x86 (only one available)
The following applications are available:
sampleIOC
What application should the IOC(s) boot?
The default uses the IOC's name, even if not listed above.
Application name? (just return)

Now, by running make, a sample IOC like the demo/test IOC is
built. Next, we want to add asyn and StreamDevice to the IOC. For this, we add
the stream and asyn libraries to the Makefile. Edit
sampleIOCApp/src/Makefile and add the block

#add asyn and streamDevice to this IOC production libs
sampleIOC_LIBS += stream
sampleIOC_LIBS += asyn

The application must also load asyn.dbd and
stream.dbd to use StreamDevice . This can be put into a generated
dbd, e.g into xxxSupport.dbd which already gets included by the
Makefile. So the xxxSupport.dbd now reads:

cat sampleIOCApp/src/xxxSupport.dbd
include "xxxRecord.dbd"
device(xxx,CONSTANT,devXxxSoft,"SoftChannel")
#
include "stream.dbd"
include "asyn.dbd"
registrar(drvAsynIPPortRegisterCommands)
registrar(drvAsynSerialPortRegisterCommands)
registrar(vxi11RegisterCommands)

To find the dbd files, you have to add the paths to these files in
configure/RELEASE:

...
# Build variables that are NOT used in paths should be set in
# the CONFIG_SITE file.
# Variables and paths to dependent modules:
SUPPORT = ${HOME}/EPICS/support
ASYN=$(SUPPORT)/asyn
STREAM=$(SUPPORT)/stream
# If using the sequencer, point SNCSEQ at its top directory:
#SNCSEQ = $(MODULES)/seq-ver
 ...

If make was done before, make distclean is
probably required. Anyway, then make. The newly created IOC can be
run with:

cd iocBoot/iocsampleIOC/
chmod u+x st.cmd
 ./st.cmd

Not very interesting yet, because there is no database file nor a protocol
file.

ls -la sampleIOCApp/Db/
total 56
drwxr-xr-x 11 maradona  staff   374  Jun  1  16:47  .
drwxr-xr-x  5 maradona  staff   170  Jun  1  12:46  ..
-rw-r--r--  1 maradona  staff   523  Jun  1  12:46  Makefile
drwxr-xr-x  2 maradona  staff    68  Jun  1  16:47  O.Common
drwxr-xr-x  3 maradona  staff   102  Jun  1  16:47  O.darwin-x86
-rw-r--r--  1 maradona  staff  1761  Jun  1  12:46  circle.db
-rw-r--r--  1 maradona  staff  1274  Jun  1  12:46  dbExample1.db
-rw-r--r--  1 maradona  staff   921  Jun  1  12:46  dbExample2.db
-rw-r--r--  1 maradona  staff   286  Jun  1  12:46  dbSubExample.db
-rw-r--r--  1 maradona  staff   170  Jun  1  12:46  sampleIOCVersion.db
-rw-r--r--  1 maradona  staff   307  Jun  1  12:46  user.substitutions

Note that this is a Db directory and not the db
directory that is in ./sampleIOC . For MDOxxxx scopes by Tektronix, the
database (.db) and protocol (.proto) file can look
something like

cat MDO.db
record(stringin, $(P)$(R)idn){
    field(DESC, "Asks for info blabla")
    field(DTYP, "stream")
    field(INP, "@MDO.proto getStr(*IDN,99) $(PORT) $(A)")
    field(PINI, "YES")
}

cat MDO.proto
Terminator = LF;
getStr{
    out "$1?";
    in "%s";
    @replytimeout {out "$1?"; in "%s";}
}

Now, we add to sampleIOCApp/Db/Makefile the information that
these files must be included in the compilation. So

cat sampleIOCApp/Db/Makefile
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS BELOW HERE
# Install databases, templates & substitutions like this
DB += circle.db
DB += dbExample1.db
DB += dbExample2.db
DB += sampleIOCVersion.db
DB += dbSubExample.db
DB += user.substitutions
DB += MDO.db
DB += MDO.proto
# If .db template is not named *.template add
# _TEMPLATE = 
include $(TOP)/configure/RULES
#----------------------------------------
# ADD EXTRA GNUMAKE RULES BELOW HERE

Again, make in directory sampleIOC. Finally, we add IP port
configuration, setting the Stream path and loading the database to the
st.cmd file. The st.cmd should read:

cat st.cmd

#!../../bin/darwin-x86/sampleIOC

#- You may have to change sampleIOC to something else
#- everywhere it appears in this file

< envPaths

epicsEnvSet ("STREAM_PROTOCOL_PATH","$(TOP)/db")

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/sampleIOC.dbd"
sampleIOC_registerRecordDeviceDriver pdbbase

## Load record instances
dbLoadTemplate "db/user.substitutions"
dbLoadRecords "db/sampleIOCVersion.db", "user=UUUUUU"
dbLoadRecords "db/dbSubExample.db", "user=UUUUUU"

#IF if the user also defines EPICS_CAS_INTF_ADDR_LIST then beacon address
#list automatic configuration is constrained to the network interfaces specified
#therein, and therefore only the broadcast addresses of the specified LAN interfaces,
#and the destination addresses of all specified point-to-point links, will be automatically configured.
#epicsEnvSet ("EPICS_CAS_INTF_ADDR_LIST","aaa.aaa.aaa.aaa")

# connect to the device ... IP-Address ! Port 2025 used by textronix, see manual
drvAsynIPPortConfigure("L0","bbb.bbb.bbb.bbb:pppp",0,0,0)

## Load record instances
dbLoadRecords("db/MDO.db", "P=UUUUUU:,PORT=L0,R=MDO:,L=0,A=0")

#- Set this to see messages from mySub
#var mySubDebug 1

#- Run this to trace the stages of iocInit
#traceIocInit

cd "${TOP}/iocBoot/${IOC}"
iocInit

## Start any sequence programs
#seq sncExample, "user=UUUUUU"

In here, you have to replace UUUUUU with the user name that runs
the EPICS IOC (you?). bbb.bbb.bbb.bbb is the IP of the device (e.g.
the scope) and pppp the port on which it listens.
EPICS_CAS_INTF_ADDR_LIST can be used if there are two network
interfaces (e.g. wlan and eth0).

The following commands might be necessary with multiple network
interfaces:

export EPICS_CA_ADDR_LIST=ccc.ccc.ccc.ccc << Broadcast address of the network
export EPICS_CA_AUTO_ADDR_LIST=NO