**SNS Application Development Environment**

**"IOC Application HOWTO"**

**1.0 Prerequisites**

The scope of this "HOWTO" is limited to the Red Hat Linux 7.x/8.x
Operating system and the bash shell. Any extrapolation to other OSes or
Shells is left as an exercise for the reader. Also, there will be no
attempt to teach CVS. Please visit the following web site and learn CVS.
([http://www.cvshome.org](http://www.cvshome.org/))

This document is limited to EPICS BASE version 3.13.5 thru 3.13.8. There
will be no attempt to describe EPICS Base 3.14.1 at this time.

Recommended reading to understand where the Application Development
Environment (ADE) philosophy was derived:

**http://www.aps.anl.gov/asd/controls/epics/EpicsDocumentation/AppDevManuals/iocScm-3.13.2/index.html**

You will also need to read the above document to understand the EPICS
make system.

I will not attempt to duplicate EPICS documentation from the APS. READ
the manual.

Before starting, your EPICS System manager will need to set a few things
up:

-   **Install a suitable cross-compiler for your target architecture**

-   **Install a SNS site modified version of EPICS BASE**

-   **Install a SNS site modified version of EPICS EXTENSIONS**

-   **Setup system level Environment variables for EPICS and application
    development**

**1.1 Environment variables and Directory Structure**

Let\'s begin with defining the root location of your ADE:

\<ADE_TOP\> defines the top-level location of the software components.

For ORNL-SNS,

-   **ADE_TOP = /ade**

For Software components and apps that are shared/common across IOC
applications

we define the following area:

-   **SUPTOP = \${ADE_TOP}/epics/supTop**

The SUPTOP area will contain components such as epics base, extensions,
and driver modules. The driver components will be pushed to a lower
directory called share so that base and extensions stand-out as software
kernel components of the control system.

-   **EPICS_BASE_RELEASE = \${SUPTOP}/base/\<epics-release\>**

```{=html}
<!-- -->
```
-   **EPICS_TOP = \${EPICS_BASE_RELEASE}**

```{=html}
<!-- -->
```
-   **EPICS_EXTENSIONS=\${SUPTOP}/extensions/\<epics-release\>**

Epics Drivers and other shared software applications are placed under
SHARE_RELEASE

-   **SHARE_RELEASE = \${SUPTOP}/share/\<epics-release\>**

```{=html}
<!-- -->
```
-   **SHARE = \${SHARE_RELEASE}**

The following environment variables are used to define the location of
the IOC software applications. The IOC applications should be organized
from a machine oriented view.

-   **IOCTOP_RELEASE = \${ADE_TOP}/epics/iocTop/\<epics-release\>**

```{=html}
<!-- -->
```
-   **IOCTOP=\${IOCTOP_RELEASE}**

All IOCs should begin there boot process from iocCommon. We will used
the IOCS environment variable to define this.

-   **IOCS = \${ADE_TOP}/epics/iocCommon**

When creating new IOC applications the makeBaseApp.pl PERL script is
used to copy SNS style templates and directory structure under \<TOP\>.
Where \<TOP\> refers to the directory in which the makeBaseApp.pl PERL
script is executed. There will be examples on later pages that
demonstrate this as well.

-   **TEMPLATE_TOP = \${SHARE}/snsTemplates/makeBaseApp/top**

```{=html}
<!-- -->
```
-   **EPICS_MBA_TEMPLATE_TOP=\${SHARE}/snsTemplates/makeBaseApp/top**

```{=html}
<!-- -->
```
-   **EPICS_MBA_DEF_APP_TYPE=sns**

The following environment variables are useful for working with VxWorks

-   **WIND_BASE = \<location of your vxWorks installation\>**

```{=html}
<!-- -->
```
-   **WIND_HOST_TYPE = x86-linux**

The following environment variable defines the target architecture that
is being built:

-   **CROSS_TARGETS=ppc603**

Location of vxWorks headers and config files. Currently this is set at
the system level.

We recommend that the following variable be defined in the build system.

For example, \$(VX_DIR)/target.

-   **VX_RELEASE = \<WIND_BASE\>/target**

**1.2 Directory Structure**

Refer to the figures below for the recommended directory structure for
the ADE.

The \<var\> subdirectory is reserved for future use. \<epics\>/\<var\>
could be useful storing ioc error log files, IOC save/restore files,
etc\...

The IOCTOP directory structure should be organized from a machine
oriented view.

The exceptions to machine oriented view are global systems that are
maintained completely in the control systems group. (e.g. CF, PPS, MPS,
timing) . Therefore all subsytems should be created under the machine
areas. The Vacuum subsytems should be changed to follow the machine
oriented model.

  ------------------------------------------------------------------------
  ![](media/image1.jpeg){width="2.307638888888889in"                  
  height="2.7895833333333333in"}Figure 1.2.2 IOCTOP hierarchy         
  ------------------------------------------------------------- ----- ----
  ![](media/image2.jpeg){width="2.0118055555555556in"                 
  height="2.8645833333333335in"}Figure 1.2.1 ADE_TOP hierarchy        

                                                                      

                                                                      
  ------------------------------------------------------------------------

  -----------------------------------------------------------------------
  ![](media/image3.jpeg){width="2.9993055555555554in"
  height="3.4680555555555554in"}Figure 1.2.3 IOCTOP/\<linac\> hierarchy
  -----------------------------------------------------------------------

  -----------------------------------------------------------------------

Next we will show a more detailed look at the IOCTOP hierarchy:

The area called SHARE under SUPTOP does not depend on a certain section
of the accelerator. So after, the EPICS build version is selected via
the system environment variables the components under share will just
appear in alphabetical order. This where drivers and software that may
be shared across application must be placed. Refer to figure 1.2.4 below
to observe our current wealth of drivers.

  -----------------------------------------------------------------------
  ![](media/image4.jpeg){width="4.2375in"
  height="6.847222222222222in"}Figure 1.2.4 SHARE directory structure
  -----------------------------------------------------------------------

  -----------------------------------------------------------------------

**2.0 Creating an IOC Application**

The SNS software team should use the EPICS Source/Release system to
create new applications. The EPICS build environment uses various PERL
scripts to provide structure, templates and a makefiles to facilitate
IOC software creation. To create our first IOC application follow these
steps at your Linux bash shell prompt:

Step 1. Source the appropriate epicsSetup environment script to pick the
Release of epics software.

**\> source
\<ADE_TOP\>/epics/site-setup/epicsSetup-bash-\<epics-release\>**

Step 2: Create a TOP level directory in which to create the new App.
This should be done somewhere in your home directory. Below substitute
\<TOP\> with your directory name. This work should not begin in
production areas. Play in your "sandbox". Once your application is
created and tested it should be imported into the software version
control system. The SNS uses CVS as our versioning control system.

**\> mkdir \<TOP\>**

Step 3: Our SNS standard for production IOCs is to derive the EPICS name
of the IOC from the SNS naming convention. The IOCs EPICS name will also
be used at the network name as well as the alias to get to the IOC\'s
debug port.

For example, *RFQ_HPRF:IOC1* becomes *rfq-hprf-ioc1*

**\> makeBaseApp.pl -T \$TEMPLATE_TOP -t sns \<yourAppName\>**

**\> makeBaseApp.pl -T \$TEMPLATE_TOP -i -t sns \<yourIOCName\>**

Let\'s take a look at Figure 2.1.1 to see what has happened:

  -----------------------------------------------------------------------
  ![](media/image5.wmf)Figure 2.1.1 IOC application directory structure;
  before a build
  -----------------------------------------------------------------------

  -----------------------------------------------------------------------

Step 4: Go to the config directory and modify the RELEASE and CONFIG
files. The RELEASE file contains definitions for the location of
external software components that will be used in this IOC application.

For example, to define the ether_ip driver module add the following line
to the RELEASE file, where \<module-release\> refers to the version
released from CVS.

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- RELEASE file snippet
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

ETHER_IP = \$(SHARE_RELEASE)/ether_ip/\<module-release\>

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- RELEASE file snippet
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

Note: All of make variables in the RELEASE are taken from the EPICS
system environment setup script. Of course, the variables can always be
over-written by simply redefining them before the build of your IOC
application. The EPICS build system also does consistency checks. The
build report errors if the IOC application tries to link to an external
product built against a different version of EPICS Base.

The CONFIG file can be used to override/select the target architecture
built.

Be sure to look at the CROSS_COMPILER_TARGET make system variable. If
this variable is commented out IOC application will attempt to build for
every architecture that was built by EPICS Base. This may not be what
you want. Remember also that the target architecture is meant to be
defined in the EPICS system environment setup.

So, edit the CONFIG file and add the following entry; comment out
everything else.

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- CONFIG file snippet
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

**CROSS_COMPILER_TARGET_ARCHS = \$(CROSS_TARGETS)**

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- CONFIG file snippet
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

**Step 5:** Now descend into \<yourAppName\>App directory and modify the
following files in the src directory:

-   ***baseLIBOBJS*** (select devices, drivers, and records you need

-   ***base.dbd*** (select corresponding database definitions
    corresponding to what you have selected from baseLIBOBJS)

-   ***\<yourAppName\>Include*** (add list of database definitions for
    external products that will be used with this IOC Application)

-   ***Makefile.Host*** (Modify this file to expand the list of dbd
    files and build software components that run on the host only)

-   ***Makefile.Vx*** (Modify this file to build source code for the
    target architecture only)

**Step 6:** Descend into the Db directory located under
\<yourAppName\>App. Here you will create your database using a suitable
tool, such as a texteditor, VDCT, capfast, spread-sheets, etc\... Now
that you have a database created modify the Makefile.Host file to
install your databases as part of the build process.

**Step 7:** Descend into the other directories beneath
\<yourAppName\>App and follow a similar procedure to install products
for edm screens, PLC binaries, alarm handler config, archiver request
files, burt request files, and channel access security config.

**Step 8:** Return to you \<TOP\> directory and build your IOC
Application.

You will notice the following product directories:

-   bin

-   cfg

-   dbd

-   db

-   opi

-   plc

Never modify the files in these product directories!! When the IOC
boots, it will load the products from the product directories. When EDM
screens are launched, they should all reference screens from the
\<TOP\>/opi directory. Remember, once a make clean uninstall is executed
the product directories are gone and any changes you may have made!! So,
if you need to change anything during the proof-of-principle and test
phase modify the file in the source area and rebuild.

**Step 9:** Finally it is time to set up the \<TOP\>/iocBoot and the
\<ADE_TOP\>/epics/iocCommon areas. This will be a detailed description;
so step 9 will be a little long. Be patient, I know you want to get to
CVS checkout, release and versioning procedures.

IOCs should be configured to boot in a consistent way so that
maintenance

and upgrades can be performed and rolled back quickly.

Each IOC will have a directory in \<ADE_TOP\>/epics/iocCommon.

The name of the directory will be the same as the network name of the
IOC.

Files in \<ADE_TOP\>/epics/iocCommon/\<yourIOCName\>

\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

-   ***vxWorksV*** (A symbolic link to the directory where the boot
    kernel is located. This allows kernel upgrades without doing a
    bootChange on the IOC.)

```{=html}
<!-- -->
```
-   ***version*** (A copy of the string printed on the IOC when the
    "version" command is executed at the prompt. This contains the
    entire configuration of the IOC and can be used to restore the
    configuration of a brain-dead IOC.)

```{=html}
<!-- -->
```
-   ***startup.cmd (***The initial startup script of the IOC, this set
    up the IOC's working envirnment, performs nfs mounts and calls the
    st.cmd file in the IOC's iocBoot directory. The directory where
    st.cmd is located should also have the same name as the network name
    of the IOC. The contents of startup.cmd are explained below.)

\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

A description of the vriables defined in the startup.cmd file will be in
the following format:

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

*Variable*

*Set BY:*

*Usage*

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

**iocName:**

***Set by:*** User

***Usage:*** The network name of the IOC, set by the user. Use whenever
the ioc's network name is needed i.e. when locating startup files or
database file in \$SHARE. Should also be used for the prefix in vxStats
substitutions.

**engineer:**

***Set by:*** User

***Usage:*** The primary person on the call list for this IOC.

**epicsBase:**

***Set by:*** User

***Usage:*** The Epics release in use. This is used for the main NFS
mount commands and for calculating other variables.

For settings and components common to the boot process of all IOCs we
define another file called "common.cmd" located in
\<ADE_TOP\>/epics/iocCommon/All

So we begin describing the variables in the common.cmd file in the
following format:

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

*Variable*

*Set BY:*

*Usage*

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

**nfsServer:**

***Set by:*** Epics Administrator

***Usage:*** The server name used in all nfsMount commands.

**SHARE:**

***Set by:*** Epics Administrator

***Usage:*** The local path to the \${SHARE_RELEASE} directory on the
server.

**BASE:**

***Set by:*** Epics Administrator

***Usage:*** The local path to the \$BASE directory on the server.

**IOCTOP:**

***Set by:*** Epics Administrator

***Usage:*** The local path to the \$IOCTOP directory on the server.

There are other EPICS related environment variables that may be listed
in the common.cmd file. If these are not specified the defaults will be
obtained from the EPICS Base build. So the Epics System manager should
be aware and ensure that these variables are set properly. In order that
all IOCs are seen by the Archive server after a network disconnect CA
beacons must be delivered to the Archive server. This is accomplished by
setting EPICS_CA_ADDR_LIST = \<IP address of Archive Server\>.

This holds true for IOC peer communication across subnets. The
EPICS_CA_ADDR_LIST is the responsibility of the user! Okay Step 9 is
really getting long. So let\'s just paste in the example of the three
files IOC startup files needed for booting.

(1) startup.cmd, (2) common.cmd, (3) st.cmd

\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- startup.cmd
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--

**\# startup script for FE_Ctl:IOC1**

**\# This file generated from
/ade/epics/iocCommon/config/startup.template**

**iocName=\"fe-ctl-ioc1\"**

**engineer=\"Fred Jr.\"**

**epicsBase=\"R3.13.7\"**

**\# Execute the common startup stuff**

**\# This performs site nfsmounts and**

**\# defines BASE SHARE and IOCTOP**

**\< ../All/common.cmd**

**\# Execute the startup script**

**cd IOCTOP**

**cd \"front_end\"**

**cd \"iocBoot\"**

**cd iocName**

**\< st.cmd**

**\#**

**\# End FE_Ctl:IOC1**

**\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- startup.cmd
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--**

**\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- common.cmd
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--**

**\# Bootup script to be executed by all IOCS**

**\# put hostAdd commands here**

**\# Set the name of the server for all nfsMount commands**

**\# The Epics site manager must set this name**

**\# Front-end building:**

**nfsServer=\"ics-accl-srv1\"**

**netDevHandle=iosDevFind( \"ics-accl-srv1:\")**

**\# Set the default NFS access user and group**

**nfsAuthUnixSet(nfsServer, 29147, 870, 0)**

**\# Compute and mount SHARE**

**SHARE=malloc(100)**

**sprintf SHARE,\"/ade/epics/supTop/share/%s\",epicsBase**

**nfsMount nfsServer,SHARE,SHARE**

**\# Compute and mount BASE**

**BASE=malloc(100)**

**sprintf BASE,\"/ade/epics/supTop/base/%s\",epicsBase**

**nfsMount nfsServer,BASE,BASE**

**\# Compute and mount IOCTOP**

**IOCTOP=malloc(100)**

**sprintf IOCTOP,\"/ade/epics/iocTop/%s\",epicsBase**

**nfsMount nfsServer,IOCTOP,IOCTOP**

**\# Get rid of the netDev used to boot so that only the correct base**

**\# files are available to the IOC**

**iosDevDelete netDevHandle**

**\# Enviornment variables meaningful to epics**

**putenv(\"EPICS_TS_NTP_INET=172.31.72.101\")**

**putenv(\"EPICS_TS_MIN_WEST=300\")**

**putenv(\"EPICS_CA_ADDR_LIST\",\"172.31.124.100\")**

**#putenv(\"EPICS_CA_CON_TMO\",\"10\")**

**#putenv(\"EPICS_CA_BEACON_PERIOD\",\"\")**

**#putenv(\"EPICS_CA_AUTO_ADDR_LIST\",\"\")**

**#putenv(\"EPICS_CA_REPEATER_PORT\",\"\")**

**#putenv(\"EPICS_CA_SERVER_PORT\",\"\")**

**#putenv(\"EPICS_IOC_LOG_PORT\",\"\")**

**#putenv(\"EPICS_IOC_LOG_INET\",\"\")**

**#putenv(\"EPICS_DB_INCLUDE_PATH\",\"\")**

**\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- common.cmd
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--**

**\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- st.cmd
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--**

\< cdCommands

#\< ../nfsCommands

cd appbin

ld \< iocCore

ld \< seq

ld \< initHooks.o

ld \< bumplessLib

ld \< snsUtilLib

ld \< snsTimingLib

ld \< timingClient

v124sConfig 0, 0x9000, 0x3a, 7, 0.0

cd top

dbLoadDatabase(\"dbd/timingApp.dbd\")

dbLoadRecords(\"db/timingDev.db\")

iocInit

seq(&timeMonitor,\"S=DHT,SS=Tim,N=1,offset=1,size=8\")

seq(&timeMonitor,\"S=DHT,SS=Tim,N=2,offset=11,size=8\")

seq(&timeMonitor,\"S=DHT,SS=Tim,N=3,offset=21,size=8\")

seq(&timeMonitor,\"S=DHT,SS=Tim,N=4,offset=31,size=8\")

seq(&timeMonitor,\"S=DHT,SS=Tim,N=5,offset=41,size=8\")

seq(&timeMonitor,\"S=DHT,SS=Tim,N=6,offset=51,size=8\")

seq(&timeMonitor,\"S=DHT,SS=Tim,N=7,offset=61,size=8\")

seq(&timeMonitor,\"S=DHT,SS=Tim,N=8,offset=71,size=8\")

seq(&timeMonitorTime,\"S=DHT,SS=Tim\")

dbpf \"DHT_Tim:chan_1:name\",\"DHT_Tim:Gate_A1\"

dbpf \"DHT_Tim:chan_2:name\",\"DHT_Tim:Gate_A3\"

dbpf \"DHT_Tim:chan_3:name\",\"DHT_Tim:Gate_A2\"

dbpf \"DHT_Tim:chan_4:name\",\"DHT_Tim:Gate_A8\"

dbpf \"DHT_Tim:chan_5:name\",\"DHT_Tim:Gate_A4\"

dbpf \"DHT_Tim:chan_6:name\",\"DHT_Tim:Gate_A5\"

dbpf \"DHT_Tim:chan_7:name\",\"DHT_Tim:Gate_A6\"

dbpf \"DHT_Tim:chan_8:name\",\"DHT_Tim:Gate_A7\"

**\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-- st.cmd
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\--**

What is missing from the above discussion on IOCs:

1.  Discussion of IOC Log Server

2.  Discussion of bumpless reboot

3.  Discussion of where IOCs save other forms of data such as from a
    scan task, etc..

I am now about 70% complete. Next on the agenda will be a discussion of
software release, versioning control and operations philosophy.

Stay Tuned.

Note \<machine-section\> refers to front_end, linac, ring, etc\... If
the system refers to a global controls area substitute
\<machine-section\> with mpsMaster, timingMaster, etc\...

\> cd \$IOCTOP_RELEASE/\<machine-section\>