<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki-ext.aps.anl.gov/epics/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=StefanHeim</id>
	<title>EPICSWIKI - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-ext.aps.anl.gov/epics/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=StefanHeim"/>
	<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Special:Contributions/StefanHeim"/>
	<updated>2026-07-12T12:38:02Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.36.1</generator>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_Set_Up_a_Soft_IOC_Framework_on_Linux&amp;diff=2835</id>
		<title>How to Set Up a Soft IOC Framework on Linux</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_Set_Up_a_Soft_IOC_Framework_on_Linux&amp;diff=2835"/>
		<updated>2009-02-18T19:53:52Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Fix typo.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This evolved from my notes when doing this for the soft IOCs at BESSY. Please add or correct things as you find them wrong or out-of-date.''&lt;br /&gt;
&lt;br /&gt;
The following instructions are based on our Debian Linux machines. (Which version? I don't really care. ''Too stable'', I guess.) Other distributions (or other Unixes) might have different commands and different places for things. This is especially true for the Debian &amp;lt;tt&amp;gt;/etc/init.d&amp;lt;/tt&amp;gt; script I'm attaching to this page. If you create a different script for a different distribution, please add it to this page. Others will be able to use it. The general steps will be the same on all distributions, though.&lt;br /&gt;
&lt;br /&gt;
Knowledge of general system administration tasks (creating user accounts etc.) is assumed.&lt;br /&gt;
&lt;br /&gt;
I was giving a talk on [ftp://ftp.desy.de/pub/EPICS/meeting-2007/SoftIOC_Admin.pdf Administration of Soft IOCs under Linux] at the [http://epics.desy.de/content/e2/e127/index_eng.html EPICS Collaboration Meeting in April 2007] that partly covered this issue.&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
== Why are we doing this? ==&lt;br /&gt;
&lt;br /&gt;
When using soft IOCs in production, they should be treated as important system services:&lt;br /&gt;
* Soft IOCs should be started and stopped by the system.&lt;br /&gt;
* There should be a fallback system you can easily switch over to in case of hardware failures.&lt;br /&gt;
&lt;br /&gt;
Other objectives were:&lt;br /&gt;
In the same way as for VME IOCs, the application developer should be able to reset the soft IOC without needing root access to the host.&lt;br /&gt;
* The IOC application developer should be able to start and stop IOCs manually.&lt;br /&gt;
&lt;br /&gt;
When multiple soft IOCs share the same host (and the same IP address), Channel Access can not tell them apart. Access Security will not be able to distiguish between CA connections coming from different soft IOCs. When debugging CA clients, CA will not be able to tell you which of the soft IOCs a connection goes to.&lt;br /&gt;
* Channel Access should be able to distinguish between different soft IOCs, even if they are hosted on the same machine.&lt;br /&gt;
&lt;br /&gt;
I was considering using a virtualization layer (based on VMware) to allow running soft IOCs in an encapsulated environment. I found the effort too high, the layer too thick, and the expected performance hit too hard - only to get a separate IP address for each soft IOC.&lt;br /&gt;
&lt;br /&gt;
When debugging and/or trying to look what is happening on an IOC, the developer does not necessarily know if the database is running on a VME based or on a host based soft IOC. &lt;br /&gt;
* Console access (and logging console output) should be uniform: working the same way for soft as for VME IOCs.&lt;br /&gt;
&lt;br /&gt;
The setup necessary to achieve this is described in the document [[How to Set Up Console Access and Logging for VME and Soft IOCs]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Concept ==&lt;br /&gt;
&lt;br /&gt;
To allow Access Security telling the soft IOCs apart, they are run under separate user names.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt; utility will be used as an environment that allows to start soft IOCs in the background and connect to their consoles later, much like the serial consoles of VME IOCs. (See the &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt; link on the [http://www.aps.anl.gov/epics/extensions/index.php Extensions Page]. Formerly, the &amp;lt;tt&amp;gt;screen&amp;lt;/tt&amp;gt; facility was used, but reported problems, e.g. IOCs hanging up after console access, made us change to something less complex.)&lt;br /&gt;
&lt;br /&gt;
Attaching to a soft IOC console will be done through &amp;lt;tt&amp;gt;ssh&amp;lt;/tt&amp;gt;, using a special console access key. Ssh is set up with the matching &amp;lt;tt&amp;gt;telnet&amp;lt;/tt&amp;gt; commands that reattach to the soft IOCs. Opening an ssh connection using the console access key to the user &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; on the soft IOC host will immediately attach to the console of the soft IOC named &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; (that is running as user &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Setting up Your Machine =&lt;br /&gt;
== Create User Accounts and ssh Access ==&lt;br /&gt;
&lt;br /&gt;
=== Soft IOC Administrator Account ===&lt;br /&gt;
&lt;br /&gt;
Create a generic user account that application developers will use to start/stop soft IOCs. (We call it &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Put the public ssh keys of the application developers into &amp;lt;tt&amp;gt;~/.ssh/authorized_keys&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ssh Key Pairs ===&lt;br /&gt;
&lt;br /&gt;
As &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;, create one key pair for this user, and another key pair for console access.&lt;br /&gt;
&lt;br /&gt;
=== Soft IOCs ===&lt;br /&gt;
&lt;br /&gt;
Create one user account for each soft IOC you intend to host. User name should be the IOC name, the group is not really important. (Maybe create a group &amp;lt;tt&amp;gt;iocs&amp;lt;/tt&amp;gt; that you put all of them into?)&lt;br /&gt;
&lt;br /&gt;
Into each of the &amp;lt;tt&amp;gt;~/.ssh/authorized_keys&amp;lt;/tt&amp;gt; files, put two public keys:&lt;br /&gt;
# The public ssh key of &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# The public ssh key for console access.&lt;br /&gt;
&lt;br /&gt;
In front of the console access key, put the &amp;lt;tt&amp;gt;telnet&amp;lt;/tt&amp;gt; command to reattach to the soft IOC console. For a user/IOC &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; that provides console access on port &amp;lt;tt&amp;gt;24703&amp;lt;/tt&amp;gt;, the line should look like this:&lt;br /&gt;
&lt;br /&gt;
 command=&amp;quot;telnet localhost 24703&amp;quot; ssh-rsa AAAAB3NzaC1yc2EAAAA.....&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Configure the sudo Facility ==&lt;br /&gt;
&lt;br /&gt;
=== Allow the iocadm User to Start and Stop Soft IOCs ===&lt;br /&gt;
&lt;br /&gt;
On the soft IOC host, allow iocadm to use sudo to execute commands as any of the soft IOC users. &amp;lt;tt&amp;gt;/etc/sudoers&amp;lt;/tt&amp;gt; should have a line like:&lt;br /&gt;
&lt;br /&gt;
 iocadm ALL = (ioc123, ioc124, ioc125) NOPASSWD: ALL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Setup the Start/Stop script ==&lt;br /&gt;
&lt;br /&gt;
=== Create the /etc/init.d script ===&lt;br /&gt;
&lt;br /&gt;
I'm attaching the script that we're using as &amp;lt;tt&amp;gt;/etc/init.d/softIOC&amp;lt;/tt&amp;gt;. It got quite huge and complex - ''sorry!''. It has been modelled after Debian's skeleton scripts, you should probably adapt it to match the standards that your distribution implies.&lt;br /&gt;
&lt;br /&gt;
It contains the local settings for where to find things, routines to read in the configuration file, the code necessary to start/stop a soft IOC as a different user under &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt;, and the usual &amp;lt;tt&amp;gt;init.d&amp;lt;/tt&amp;gt; script stuff that checks command line arguments and calls the other routines.&lt;br /&gt;
&lt;br /&gt;
''If you have a script working for a different distribution, please add it to this page, as it could make life easier for others!''&lt;br /&gt;
&lt;br /&gt;
=== Create the Configuration File ===&lt;br /&gt;
&lt;br /&gt;
The configuration file contains a section for each of the soft IOCs. A section starts with the IOC name followed by a colon, and ends with an empty line.&lt;br /&gt;
&lt;br /&gt;
Within a section you can set special variables used by the &amp;lt;tt&amp;gt;softIOC&amp;lt;/tt&amp;gt; script as well as environment variables that will be set for the soft IOC.&lt;br /&gt;
&lt;br /&gt;
The special section &amp;lt;tt&amp;gt;global:&amp;lt;/tt&amp;gt; contains settings that will be applied to ''all'' soft IOCs (may be overridden by the IOC section).&lt;br /&gt;
&lt;br /&gt;
The special line &amp;lt;tt&amp;gt;auto:&amp;lt;/tt&amp;gt; contains the names of the soft IOCs that should be started when the script is run as part of the system boot-up process.&lt;br /&gt;
&lt;br /&gt;
Section and IOC names are not case sensitive.&lt;br /&gt;
&lt;br /&gt;
So a minimal configuration file could look like this (remember the empty line that is required after each section):&lt;br /&gt;
&lt;br /&gt;
 AUTO:   ioc123&lt;br /&gt;
 &lt;br /&gt;
 GLOBAL:&lt;br /&gt;
 &lt;br /&gt;
 ioc123:&lt;br /&gt;
 &lt;br /&gt;
 ioc124:&lt;br /&gt;
 &lt;br /&gt;
 ioc125:&lt;br /&gt;
&lt;br /&gt;
== Distribute the Required Stuff to the Soft IOC Host ==&lt;br /&gt;
&lt;br /&gt;
=== EPICS Base ===&lt;br /&gt;
&lt;br /&gt;
Soft IOCS will need libraries from EPICS base. Make sure these are existing and can be found.&lt;br /&gt;
&lt;br /&gt;
=== Code and Databases ===&lt;br /&gt;
&lt;br /&gt;
Add the soft IOC host to the code deployment scheme you are using. The soft IOC binaries, databases, and start up scripts must be available for the soft IOCs to be started.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Start Your Soft IOCs =&lt;br /&gt;
&lt;br /&gt;
== Start the IOCs using the startup script ==&lt;br /&gt;
&lt;br /&gt;
Starting and stopping the soft IOCs should work now! Ssh to the soft IOC host as &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt; and try calling the startup script:&lt;br /&gt;
&lt;br /&gt;
 /etc/init.d/softIOC start ioc123&lt;br /&gt;
&lt;br /&gt;
== Watch them run ==&lt;br /&gt;
&lt;br /&gt;
Ssh to the soft IOC host using the console access key and see if you can get access to the IOC console:&lt;br /&gt;
&lt;br /&gt;
 ssh -i ~iocadm/.ssh/console_access -t ioc123@iochost&lt;br /&gt;
&lt;br /&gt;
You should be directly connected to your IOC's console.&lt;br /&gt;
&lt;br /&gt;
== Check if Starting IOCs at reboot works ==&lt;br /&gt;
&lt;br /&gt;
If you made entries to the &amp;lt;tt&amp;gt;auto:&amp;lt;/tt&amp;gt; section, reboot the machine to check that starting IOCs at boot time works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''''Good luck!'''''&lt;br /&gt;
&lt;br /&gt;
[mailto:Ralph.Lange_at_bessy.de Ralph Lange (BESSY)]&lt;br /&gt;
&lt;br /&gt;
created: [[User:RalphLange|Ralph]] 05:08, 26 Apr 2007 (CDT)&lt;br /&gt;
&lt;br /&gt;
last edit: [[User:RalphLange|Ralph]] 11:17, 12 Feb 2009 (CDT)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= The Startup Script =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;/etc/init.d/softIOC&amp;lt;/tt&amp;gt; script for Debian Linux&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
# Author: &amp;lt;Ralph.Lange@bessy.de&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# History:&lt;br /&gt;
#          2006-03-12: Adapted from D. Herrendörfer's ca-gateway script&lt;br /&gt;
#          2006-04-04: Bugfix in config file parser&lt;br /&gt;
#          2008-05-20: Adapted to procServ&lt;br /&gt;
&lt;br /&gt;
# Do NOT &amp;quot;set -e&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# !! This script is located on a mounted file system&lt;br /&gt;
# !! It must be run after the mountnfs.sh script&lt;br /&gt;
&lt;br /&gt;
PATH=/sbin:/usr/sbin:/bin:/usr/bin&lt;br /&gt;
DESC=&amp;quot;EPICS soft IOCs&amp;quot;&lt;br /&gt;
SCRIPTNAME=/etc/init.d/softIOC&lt;br /&gt;
HOST=`uname -n`&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCSERV=/usr/local/bin/procServ&lt;br /&gt;
CONFFILE=/opt/IOC/softIOC/softiocs.$HOST&lt;br /&gt;
HOMEDIRS=/home/controls&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Check for config file&lt;br /&gt;
if [ ! -r $CONFFILE ]&lt;br /&gt;
then&lt;br /&gt;
        echo &amp;quot;Error: Can't find configuration file $CONFFILE!&amp;quot;&lt;br /&gt;
        exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Functions that read in the configuration file&lt;br /&gt;
#&lt;br /&gt;
clear_options()&lt;br /&gt;
{&lt;br /&gt;
        for option in &amp;quot;CA_AUTO&amp;quot; &amp;quot;CA_ADDR&amp;quot; &amp;quot;CA_PORT&amp;quot; &amp;quot;IOC_USER&amp;quot; &amp;quot;PORT&amp;quot;&lt;br /&gt;
        do&lt;br /&gt;
                unset $option;&lt;br /&gt;
        done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
evaluate_options()&lt;br /&gt;
{&lt;br /&gt;
        while [ $# != 0 ]&lt;br /&gt;
        do&lt;br /&gt;
                TAG=`echo $1 | tr [:lower:] [:upper:]`&lt;br /&gt;
                case &amp;quot;$TAG&amp;quot; in&lt;br /&gt;
                &amp;quot;#&amp;quot;)            ;;&lt;br /&gt;
                &amp;quot;CA_AUTO&amp;quot; | &amp;quot;CA_ADDR&amp;quot; | &amp;quot;CA_PORT&amp;quot; | &amp;quot;COREDUMPSIZE&amp;quot; | \&lt;br /&gt;
                &amp;quot;HOMEDIR&amp;quot; | &amp;quot;BOOTDIR&amp;quot; | &amp;quot;IOC_USER&amp;quot; | &amp;quot;PORT&amp;quot; )&lt;br /&gt;
                                # Test the presence of values for the current option&lt;br /&gt;
                                OPTION=$TAG&lt;br /&gt;
                                shift&lt;br /&gt;
                                if [ -z $TAG -o $TAG = &amp;quot;#&amp;quot; ]&lt;br /&gt;
                                then&lt;br /&gt;
                                        echo &amp;quot;$CONFFILE: Value(s) required for $TAG.&amp;quot;;&lt;br /&gt;
                                        exit 1&lt;br /&gt;
                                else&lt;br /&gt;
                                        VALUE=$1&lt;br /&gt;
                                        shift&lt;br /&gt;
                                fi&lt;br /&gt;
                                # If more values follow assign them too&lt;br /&gt;
                                while [ $1 != '#'  -a  $# != 0 ]&lt;br /&gt;
                                do&lt;br /&gt;
                                        VALUE=&amp;quot;$VALUE $1&amp;quot;&lt;br /&gt;
                                        shift;&lt;br /&gt;
                                done&lt;br /&gt;
                                eval ${OPTION}=\$VALUE&lt;br /&gt;
                                ;;&lt;br /&gt;
                *)              echo &amp;quot;$CONFFILE: Unknown option $1.&amp;quot;&lt;br /&gt;
                                exit 1&lt;br /&gt;
                esac&lt;br /&gt;
                shift&lt;br /&gt;
        done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default_options()&lt;br /&gt;
{&lt;br /&gt;
        # Set IOC defaults for options&lt;br /&gt;
        # (may be overridden in config file)&lt;br /&gt;
        IOC_LC=$1&lt;br /&gt;
        IOC_UC=`echo $1 | tr [:lower:] [:upper:]`&lt;br /&gt;
&lt;br /&gt;
        if [[ &amp;quot;$IOC_LC&amp;quot; = &amp;quot;mdi&amp;quot;* ]]&lt;br /&gt;
            then&lt;br /&gt;
            TOP=DiagR3.14.9.0.1-Tornado2.2.1&lt;br /&gt;
        elif [[ &amp;quot;$IOC_LC&amp;quot; = *&amp;quot;p&amp;quot; ]]&lt;br /&gt;
            then&lt;br /&gt;
            TOP=MLS-Controls&lt;br /&gt;
        else&lt;br /&gt;
            TOP=BII-Controls/base-3-14&lt;br /&gt;
        fi&lt;br /&gt;
&lt;br /&gt;
        BOOTDIR=/opt/IOC/$TOP/boot/$IOC_UC&lt;br /&gt;
        HOMEDIR=$HOMEDIRS/$IOC_LC&lt;br /&gt;
        PIDFILE=$HOMEDIR/$IOC_LC.pid&lt;br /&gt;
        ENVFILE=$HOMEDIR/$IOC_LC.env&lt;br /&gt;
        IOC_USER=$IOC_LC&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
assign_options()&lt;br /&gt;
{&lt;br /&gt;
        # Find $TAG section&lt;br /&gt;
        # Remove comments&lt;br /&gt;
        # Remove leading and trailing whitespace&lt;br /&gt;
        # Remove $TAG: tag&lt;br /&gt;
        # Join lines ending with a &amp;quot;\&amp;quot;&lt;br /&gt;
        # Mark end of option with a &amp;quot;#&amp;quot;&lt;br /&gt;
        # Remove unnecessary whitespace&lt;br /&gt;
        TAG=$1&lt;br /&gt;
        SECTION=`sed -n &amp;quot;/^$TAG:/I,/^[\t ]*$/p&amp;quot; $CONFFILE | \&lt;br /&gt;
                 sed -n '/^[^#]/p' | \&lt;br /&gt;
                 sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' \&lt;br /&gt;
                     -e &amp;quot;s/$TAG://I&amp;quot; \&lt;br /&gt;
                     -e :a -e '/\\\\$/N; s/\\\\\\n//; ta' \&lt;br /&gt;
                     -e 's/$/ \#/' \&lt;br /&gt;
                     -e 's/[\t ]/ /g'`&lt;br /&gt;
        evaluate_options $SECTION&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
get_iocs()&lt;br /&gt;
{&lt;br /&gt;
        # Get IOCs from command line or AUTO: entry in configuration file&lt;br /&gt;
        # Test for matching section in configuration file&lt;br /&gt;
        if [ $# = 0 ]&lt;br /&gt;
        then&lt;br /&gt;
                TEST_LIST=`grep -i '^AUTO:' &amp;quot;$CONFFILE&amp;quot; | cut -d: -f2- | tr [:upper:] [:lower:]`&lt;br /&gt;
        else&lt;br /&gt;
                TEST_LIST=&amp;quot;$@&amp;quot;&lt;br /&gt;
        fi&lt;br /&gt;
&lt;br /&gt;
        CHECKED_LIST=&amp;quot;&amp;quot;&lt;br /&gt;
        for IOC in $TEST_LIST&lt;br /&gt;
        do&lt;br /&gt;
                grep -qi &amp;quot;^$IOC:&amp;quot; $CONFFILE&lt;br /&gt;
                if [ $? = 0 ]&lt;br /&gt;
                then&lt;br /&gt;
                        CHECKED_LIST=&amp;quot;$CHECKED_LIST $IOC&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo $CHECKED_LIST&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
set_cmdenvopts()&lt;br /&gt;
{&lt;br /&gt;
        # Set up the environment setup string&lt;br /&gt;
&lt;br /&gt;
        SETENV=&amp;quot;LINES=60 &amp;quot;`test ! -z &amp;quot;$CA_AUTO&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_AUTO_ADDR_LIST=\&amp;quot;$CA_AUTO\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$CA_ADDR&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_ADDR_LIST=\&amp;quot;$CA_ADDR\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$CA_PORT&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_SERVER_PORT=\&amp;quot;$CA_PORT\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$BOOTDIR&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export BOOTDIR=\&amp;quot;$BOOTDIR\&amp;quot;;&amp;quot;`&lt;br /&gt;
&lt;br /&gt;
        # Set up the options for the procserv program&lt;br /&gt;
&lt;br /&gt;
        PROCSERVOPTS=`test ! -z &amp;quot;$IOC_USER&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;-n \&amp;quot;$IOC_USER\&amp;quot;&amp;quot;`&lt;br /&gt;
        PROCSERVOPTS=&amp;quot;$PROCSERVOPTS &amp;quot;`test ! -z &amp;quot;$COREDUMPSIZE&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;--coresize \&amp;quot;$COREDUMPSIZE\&amp;quot;&amp;quot;`&lt;br /&gt;
        PROCSERVOPTS=&amp;quot;$PROCSERVOPTS -q -c $BOOTDIR -p $PIDFILE -i ^D^C^] $PORT&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that starts the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_start()&lt;br /&gt;
{&lt;br /&gt;
        # Return&lt;br /&gt;
        #   0 if daemon has been started&lt;br /&gt;
        #   1 if daemon was already running&lt;br /&gt;
        #   2 if daemon could not be started&lt;br /&gt;
        # Add code here, if necessary, that waits for the process to be ready&lt;br /&gt;
        # to handle requests from services started subsequently which depend&lt;br /&gt;
        # on this one.  As a last resort, sleep for some time.&lt;br /&gt;
&lt;br /&gt;
        echo -n &amp;quot;Starting soft IOCs ... &amp;quot;&lt;br /&gt;
        MYIOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$MYIOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $MYIOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                set_cmdenvopts&lt;br /&gt;
&lt;br /&gt;
                if [ -d $BOOTDIR ]&lt;br /&gt;
                    then&lt;br /&gt;
                    if [ -d $HOMEDIR ]&lt;br /&gt;
                        then&lt;br /&gt;
&lt;br /&gt;
                        sudo -H -u $IOC sh -c &amp;quot;$SETENV (env &amp;gt; $ENVFILE; /sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR \&lt;br /&gt;
                            --pidfile $PIDFILE --startas $PROCSERV --name procServ --test &amp;gt; /dev/null)&amp;quot;&lt;br /&gt;
                        if [ &amp;quot;$?&amp;quot; = 1 ]&lt;br /&gt;
                            then&lt;br /&gt;
                            echo -n &amp;quot;&amp;lt;was running&amp;gt; &amp;quot;&lt;br /&gt;
                            else&lt;br /&gt;
                            sudo -H -u $IOC sh -c &amp;quot;$SETENV (env &amp;gt; $ENVFILE; /sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR \&lt;br /&gt;
                                --pidfile $PIDFILE --startas $PROCSERV --name procServ -- $PROCSERVOPTS ./st.cmd)&amp;quot;&lt;br /&gt;
                            if [ &amp;quot;$?&amp;quot; = 1 ]&lt;br /&gt;
                                then&lt;br /&gt;
                                echo -n &amp;quot;&amp;lt;failed&amp;gt; &amp;quot;&lt;br /&gt;
                            fi&lt;br /&gt;
                        fi&lt;br /&gt;
&lt;br /&gt;
                    else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Home directory $HOMEDIR does not exist! Ignoring $IOC&amp;quot;&lt;br /&gt;
                    fi&lt;br /&gt;
                else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Boot directory $BOOTDIR does not exist! Ignoring $IOC&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that stops the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_stop()&lt;br /&gt;
{&lt;br /&gt;
        # Return&lt;br /&gt;
        #   0 if daemon has been stopped&lt;br /&gt;
        #   1 if daemon was already stopped&lt;br /&gt;
        #   2 if daemon could not be stopped&lt;br /&gt;
        #   other if a failure occurred&lt;br /&gt;
&lt;br /&gt;
        echo -n &amp;quot;Stopping soft IOCs ... &amp;quot;&lt;br /&gt;
        MYIOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$MYIOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $MYIOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                set_cmdenvopts&lt;br /&gt;
&lt;br /&gt;
                sudo -H -u $IOC sh -c &amp;quot;/sbin/start-stop-daemon --stop --quiet --pidfile $PIDFILE --name procServ --test &amp;gt; /dev/null&amp;quot;&lt;br /&gt;
                if [ $? = 1 ]&lt;br /&gt;
                    then&lt;br /&gt;
                    echo -n &amp;quot;&amp;lt;not running&amp;gt; &amp;quot;&lt;br /&gt;
                    else&lt;br /&gt;
                    sudo -H -u $IOC sh -c &amp;quot;/sbin/start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name procServ&amp;quot;&lt;br /&gt;
                    if [ $? = 1 ]&lt;br /&gt;
                        then&lt;br /&gt;
                        echo -n &amp;quot;&amp;lt;failed&amp;gt; &amp;quot;&lt;br /&gt;
                    else&lt;br /&gt;
                        sudo -H -u $IOC sh -c &amp;quot;rm -f $PIDFILE&amp;quot;&lt;br /&gt;
                    fi&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that sends a SIGHUP to the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_reload() {&lt;br /&gt;
        #&lt;br /&gt;
        # If the daemon can reload its configuration without&lt;br /&gt;
        # restarting (for example, when it is sent a SIGHUP),&lt;br /&gt;
        # then implement that here.&lt;br /&gt;
        #&lt;br /&gt;
#       start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME&lt;br /&gt;
#       return 0&lt;br /&gt;
&lt;br /&gt;
        echo &amp;quot;Restarting soft IOCs ... &amp;quot;&lt;br /&gt;
        STARTDIR=$PWD&lt;br /&gt;
        IOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$IOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $IOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                if [ -d $BOOTDIR ]&lt;br /&gt;
                then&lt;br /&gt;
                        cd &amp;quot;$BOOTDIR&amp;quot;&lt;br /&gt;
# restart it!&lt;br /&gt;
                        echo -e &amp;quot;\ndebug: Reloading ioc $IOC&amp;quot;&lt;br /&gt;
                        cd &amp;quot;$STARTDIR&amp;quot;&lt;br /&gt;
                else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Boot directory $BOOTDIR does not exist! Entry for $NET ignored!&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
COMMAND=$1&lt;br /&gt;
shift&lt;br /&gt;
IOCS=`echo $@ | tr [:upper:] [:lower:]`&lt;br /&gt;
&lt;br /&gt;
case &amp;quot;$COMMAND&amp;quot; in&lt;br /&gt;
  start)&lt;br /&gt;
        do_start $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  stop)&lt;br /&gt;
        do_stop $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  #reload|force-reload)&lt;br /&gt;
        #&lt;br /&gt;
        # If do_reload() is not implemented then leave this commented out&lt;br /&gt;
        # and leave 'force-reload' as an alias for 'restart'.&lt;br /&gt;
        #&lt;br /&gt;
        #log_daemon_msg &amp;quot;Reloading $DESC&amp;quot; &amp;quot;$NAME&amp;quot;&lt;br /&gt;
        #do_reload&lt;br /&gt;
        #log_end_msg $?&lt;br /&gt;
        #;;&lt;br /&gt;
  restart|force-reload)&lt;br /&gt;
        #&lt;br /&gt;
        # If the &amp;quot;reload&amp;quot; option is implemented then remove the&lt;br /&gt;
        # 'force-reload' alias&lt;br /&gt;
        #&lt;br /&gt;
        do_stop $IOCS&lt;br /&gt;
        sleep 1&lt;br /&gt;
        do_start $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  *)&lt;br /&gt;
        #echo &amp;quot;Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}&amp;quot; &amp;gt;&amp;amp;2&lt;br /&gt;
        echo &amp;quot;Usage: $SCRIPTNAME {start|stop|restart|force-reload} [iocs ...]&amp;quot; &amp;gt;&amp;amp;2&lt;br /&gt;
        exit 3&lt;br /&gt;
        ;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_Set_Up_a_Soft_IOC_Framework_on_Linux&amp;diff=1651</id>
		<title>How to Set Up a Soft IOC Framework on Linux</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_Set_Up_a_Soft_IOC_Framework_on_Linux&amp;diff=1651"/>
		<updated>2009-02-18T16:56:04Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Break excessively long lines in init script. This time alter the correct lines.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This evolved from my notes when doing this for the soft IOCs at BESSY. Please add or correct things as you find them wrong or out-of-date.''&lt;br /&gt;
&lt;br /&gt;
The following instructions are based on our Debian Linux machines. (Which version? I don't really care. ''Too stable'', I guess.) Other distributions (or other Unixes) might have different commands and different places for things. This is especially true for the Debian &amp;lt;tt&amp;gt;/etc/init.d&amp;lt;/tt&amp;gt; script I'm attaching to this page. If you create a different script for a different distribution, please add it to this page. Others will be able to use it. The general steps will be the same on all distributions, though.&lt;br /&gt;
&lt;br /&gt;
Knowledge of general system administration tasks (creating user accounts etc.) is assumed.&lt;br /&gt;
&lt;br /&gt;
I was giving a talk on [ftp://ftp.desy.de/pub/EPICS/meeting-2007/SoftIOC_Admin.pdf Administration of Soft IOCs under Linux] at the [http://epics.desy.de/content/e2/e127/index_eng.html EPICS Collaboration Meeting in April 2007] that partly covered this issue.&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
== Why are we doing this? ==&lt;br /&gt;
&lt;br /&gt;
When using soft IOCs in production, they should be treated as important system services:&lt;br /&gt;
* Soft IOCs should be started and stopped by the system.&lt;br /&gt;
* There should be a fallback system you can easily switch over to in case of hardware failures.&lt;br /&gt;
&lt;br /&gt;
Other objectives were:&lt;br /&gt;
In the same way as for VME IOCs, the application developer should be able to reset the soft IOC without needing root access to the host.&lt;br /&gt;
* The IOC application developer should be able to start and stop IOCs manually.&lt;br /&gt;
&lt;br /&gt;
When multiple soft IOCs share the same host (and the same IP address), Channel Access can not tell them apart. Access Security will not be able to distiguish between CA connections coming from different soft IOCs. When debugging CA clients, CA will not be able to tell you which of the soft IOCs a connection goes to.&lt;br /&gt;
* Channel Access should be able to distinguish between different soft IOCs, even if they are hosted on the same machine.&lt;br /&gt;
&lt;br /&gt;
I was considering using a virtualization layer (based on VMware) to allow running soft IOCs in an encapsulated environment. I found the effort too high, the layer too thick, and the expected performance hit too hard - only to get a separate IP address for each soft IOC.&lt;br /&gt;
&lt;br /&gt;
When debugging and/or trying to look what is happening on an IOC, the developer does not necessarily know if the database is running on a VME based or on a host based soft IOC. &lt;br /&gt;
* Console access (and logging console output) should be uniform: working the same way for soft as for VME IOCs.&lt;br /&gt;
&lt;br /&gt;
The setup necessary to achieve this is described in the document [[How to Set Up Console Access and Logging for VME and Soft IOCs]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Concept ==&lt;br /&gt;
&lt;br /&gt;
To allow Access Security telling the soft IOCs apart, they are run under separate user names.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt; utility will be used as an environment that allows to start soft IOCs in the background and connect to their consoles later, much like the serial consoles of VME IOCs. (See the &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt; link on the [http://www.aps.anl.gov/epics/extensions/index.php Extensions Page]. Formerly, the &amp;lt;tt&amp;gt;screen&amp;lt;/tt&amp;gt; facility was used, but reported problems, e.g. IOCs hanging up after console access, made us change to something less complex.)&lt;br /&gt;
&lt;br /&gt;
Attaching to a soft IOC console will be done through &amp;lt;tt&amp;gt;ssh&amp;lt;/tt&amp;gt;, using a special console access key. Ssh is set up with the matching &amp;lt;tt&amp;gt;telnet&amp;lt;/tt&amp;gt; commands that reattach to the soft IOCs. Opening an ssh connection using the console access key to the user &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; on the soft IOC host will immediately attach to the console of the soft IOC named &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; (that is running as user &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Setting up Your Machine =&lt;br /&gt;
== Create User Accounts and ssh Access ==&lt;br /&gt;
&lt;br /&gt;
=== Soft IOC Administrator Account ===&lt;br /&gt;
&lt;br /&gt;
Create a generic user account that application developers will use to start/stop soft IOCs. (We call it &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Put the public ssh keys of the application developers into &amp;lt;tt&amp;gt;~/.ssh/authorized_keys&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ssh Key Pairs ===&lt;br /&gt;
&lt;br /&gt;
As &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;, create one key pair for this user, and another key pair for console access.&lt;br /&gt;
&lt;br /&gt;
=== Soft IOCs ===&lt;br /&gt;
&lt;br /&gt;
Create one user account for each soft IOC you intend to host. User name should be the IOC name, the group is not really important. (Maybe create a group &amp;lt;tt&amp;gt;iocs&amp;lt;/tt&amp;gt; that you put all of them into?)&lt;br /&gt;
&lt;br /&gt;
Into each of the &amp;lt;tt&amp;gt;~/.ssh/authorized_keys&amp;lt;/tt&amp;gt; files, put two public keys:&lt;br /&gt;
# The public ssh key of &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# The public ssh key for console access.&lt;br /&gt;
&lt;br /&gt;
In front of the console access key, put the &amp;lt;tt&amp;gt;telnet&amp;lt;/tt&amp;gt; command to reattach to the soft IOC console. For a user/IOC &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; that provides console access on port &amp;lt;tt&amp;gt;24703&amp;lt;/tt&amp;gt;, the line should look like this:&lt;br /&gt;
&lt;br /&gt;
 command=&amp;quot;telnet localhost 24703&amp;quot; ssh-rsa AAAAB3NzaC1yc2EAAAA.....&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Configure the sudo Facility ==&lt;br /&gt;
&lt;br /&gt;
=== Allow the iocadm User to Start and Stop Soft IOCs ===&lt;br /&gt;
&lt;br /&gt;
On the soft IOC host, allow iocadm to use sudo to execute commands as any of the soft IOC users. &amp;lt;tt&amp;gt;/etc/sudoers&amp;lt;/tt&amp;gt; should have a line like:&lt;br /&gt;
&lt;br /&gt;
 iocadm ALL = (ioc123, ioc124, ioc125) NOPASSWD: ALL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Setup the Start/Stop script ==&lt;br /&gt;
&lt;br /&gt;
=== Create the /etc/init.d script ===&lt;br /&gt;
&lt;br /&gt;
I'm attaching the script that we're using as &amp;lt;tt&amp;gt;/etc/init.d/softIOC&amp;lt;/tt&amp;gt;. It got quite huge and complex - ''sorry!''. It has been modelled after Debian's skeleton scripts, you should probably adapt it to match the standards that your distribution implies.&lt;br /&gt;
&lt;br /&gt;
It contains the local settings for where to find things, routines to read in the configuration file, the code necessary to start/stop a soft IOC as a different user under &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt;, and the usual &amp;lt;tt&amp;gt;init.d&amp;lt;/tt&amp;gt; script stuff that checks command line arguments and calls the other routines.&lt;br /&gt;
&lt;br /&gt;
''If you have a script working for a different distribution, please add it to this page, as it could make life easier for others!''&lt;br /&gt;
&lt;br /&gt;
=== Create the Configuration File ===&lt;br /&gt;
&lt;br /&gt;
The configuration file contains a section for each of the soft IOCs. A section starts with the IOC name followed by a colon, and ends with an empty line.&lt;br /&gt;
&lt;br /&gt;
Within a section you can set special variables used by the &amp;lt;tt&amp;gt;softIOC&amp;lt;/tt&amp;gt; script as well as environment variables that will be set for the soft IOC.&lt;br /&gt;
&lt;br /&gt;
The special section &amp;lt;tt&amp;gt;global:&amp;lt;/tt&amp;gt; contains settings that will be applied to ''all'' soft IOCs (may be overridden by the IOC section).&lt;br /&gt;
&lt;br /&gt;
The special line &amp;lt;tt&amp;gt;auto:&amp;lt;/tt&amp;gt; contains the names of the soft IOCs that should be started when the script is run as part of the system boot-up process.&lt;br /&gt;
&lt;br /&gt;
Section and IOC names are not case sensitive.&lt;br /&gt;
&lt;br /&gt;
So a minimal configuration file could look like this (remember the empty line that is required after each section):&lt;br /&gt;
&lt;br /&gt;
 AUTO:   ioc123&lt;br /&gt;
 &lt;br /&gt;
 GLOBAL:&lt;br /&gt;
 &lt;br /&gt;
 ioc123:&lt;br /&gt;
 &lt;br /&gt;
 ioc124:&lt;br /&gt;
 &lt;br /&gt;
 ioc125:&lt;br /&gt;
&lt;br /&gt;
== Distribute the Required Stuff to the Soft IOC Host ==&lt;br /&gt;
&lt;br /&gt;
=== EPICS Base ===&lt;br /&gt;
&lt;br /&gt;
Soft IOCS will need libraries from EPICS base. Make sure these are existing and can be found.&lt;br /&gt;
&lt;br /&gt;
=== Code and Databases ===&lt;br /&gt;
&lt;br /&gt;
Add the soft IOC host to the code deployment scheme you are using. The soft IOC binaries, databases, and start up scripts must be available for the soft IOCs to be started.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Start Your Soft IOCs =&lt;br /&gt;
&lt;br /&gt;
== Start the IOCs using the startup script ==&lt;br /&gt;
&lt;br /&gt;
Starting and stopping the soft IOCs should work now! Ssh to the soft IOC host as &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt; and try calling the startup script:&lt;br /&gt;
&lt;br /&gt;
 /etc/init.d/softIOC start ioc123&lt;br /&gt;
&lt;br /&gt;
== Watch them run ==&lt;br /&gt;
&lt;br /&gt;
Ssh to the soft IOC host using the console access key and see if you can get access to the IOC console:&lt;br /&gt;
&lt;br /&gt;
 ssh -i ~iocadm/.ssh/console_access -t ioc123@iochost&lt;br /&gt;
&lt;br /&gt;
You should be directly connected to your IOC's console.&lt;br /&gt;
&lt;br /&gt;
== Check if Starting IOCs at reboot works ==&lt;br /&gt;
&lt;br /&gt;
If you made entries to the &amp;lt;tt&amp;gt;auto:&amp;lt;/tt&amp;gt; section, reboot the machine to check that starting IOCs at boot time works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''''Good luck!'''''&lt;br /&gt;
&lt;br /&gt;
[mailto:Ralph.Lange_at_bessy.de Ralph Lange (BESSY)]&lt;br /&gt;
&lt;br /&gt;
created: [[User:RalphLange|Ralph]] 05:08, 26 Apr 2007 (CDT)&lt;br /&gt;
&lt;br /&gt;
last edit: [[User:RalphLange|Ralph]] 11:17, 12 Feb 2009 (CDT)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= The Startup Script =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;/etc/init.d/softIOC&amp;lt;/tt&amp;gt; script for Debian Linux&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
# Author: &amp;lt;Ralph.Lange@bessy.de&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# History:&lt;br /&gt;
#          2006-03-12: Adapted from D. Herrendörfer's ca-gateway script&lt;br /&gt;
#          2006-04-04: Bugfix in config file parser&lt;br /&gt;
#          2008-05-20: Adapted to procServ&lt;br /&gt;
&lt;br /&gt;
# Do NOT &amp;quot;set -e&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# !! This script is located on a mounted file system&lt;br /&gt;
# !! It must be run after the mountnfs.sh script&lt;br /&gt;
&lt;br /&gt;
PATH=/sbin:/usr/sbin:/bin:/usr/bin&lt;br /&gt;
DESC=&amp;quot;EPICS soft IOCs&amp;quot;&lt;br /&gt;
SCRIPTNAME=/etc/init.d/softIOC&lt;br /&gt;
HOST=`uname -n`&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCSERV=/usr/local/bin/procServ&lt;br /&gt;
CONFFILE=/opt/IOC/softIOC/softiocs.$HOST&lt;br /&gt;
HOMEDIRS=/home/controls&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Check for config file&lt;br /&gt;
if [ ! -r $CONFFILE ]&lt;br /&gt;
then&lt;br /&gt;
        echo &amp;quot;Error: Can't find configuration file $CONFFILE!&amp;quot;&lt;br /&gt;
        exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Functions that read in the configuration file&lt;br /&gt;
#&lt;br /&gt;
clear_options()&lt;br /&gt;
{&lt;br /&gt;
        for option in &amp;quot;CA_AUTO&amp;quot; &amp;quot;CA_ADDR&amp;quot; &amp;quot;CA_PORT&amp;quot; &amp;quot;IOC_USER&amp;quot; &amp;quot;PORT&amp;quot;&lt;br /&gt;
        do&lt;br /&gt;
                unset $option;&lt;br /&gt;
        done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
evaluate_options()&lt;br /&gt;
{&lt;br /&gt;
        while [ $# != 0 ]&lt;br /&gt;
        do&lt;br /&gt;
                TAG=`echo $1 | tr [:lower:] [:upper:]`&lt;br /&gt;
                case &amp;quot;$TAG&amp;quot; in&lt;br /&gt;
                &amp;quot;#&amp;quot;)            ;;&lt;br /&gt;
                &amp;quot;CA_AUTO&amp;quot; | &amp;quot;CA_ADDR&amp;quot; | &amp;quot;CA_PORT&amp;quot; | &amp;quot;COREDUMPSIZE&amp;quot; | \&lt;br /&gt;
                &amp;quot;HOMEDIR&amp;quot; | &amp;quot;BOOTDIR&amp;quot; | &amp;quot;IOC_USER&amp;quot; | &amp;quot;PORT&amp;quot; )&lt;br /&gt;
                                # Test the presence of values for the current option&lt;br /&gt;
                                OPTION=$TAG&lt;br /&gt;
                                shift&lt;br /&gt;
                                if [ -z $TAG -o $TAG = &amp;quot;#&amp;quot; ]&lt;br /&gt;
                                then&lt;br /&gt;
                                        echo &amp;quot;$CONFFILE: Value(s) required for $TAG.&amp;quot;;&lt;br /&gt;
                                        exit 1&lt;br /&gt;
                                else&lt;br /&gt;
                                        VALUE=$1&lt;br /&gt;
                                        shift&lt;br /&gt;
                                fi&lt;br /&gt;
                                # If more values follow assign them too&lt;br /&gt;
                                while [ $1 != '#'  -a  $# != 0 ]&lt;br /&gt;
                                do&lt;br /&gt;
                                        VALUE=&amp;quot;$VALUE $1&amp;quot;&lt;br /&gt;
                                        shift;&lt;br /&gt;
                                done&lt;br /&gt;
                                eval ${OPTION}=\$VALUE&lt;br /&gt;
                                ;;&lt;br /&gt;
                *)              echo &amp;quot;$CONFFILE: Unknown option $1.&amp;quot;&lt;br /&gt;
                                exit 1&lt;br /&gt;
                esac&lt;br /&gt;
                shift&lt;br /&gt;
        done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default_options()&lt;br /&gt;
{&lt;br /&gt;
        # Set IOC defaults for options&lt;br /&gt;
        # (may be overridden in config file)&lt;br /&gt;
        IOC_LC=$1&lt;br /&gt;
        IOC_UC=`echo $1 | tr [:lower:] [:upper:]`&lt;br /&gt;
&lt;br /&gt;
        if [[ &amp;quot;$IOC_LC&amp;quot; = &amp;quot;mdi&amp;quot;* ]]&lt;br /&gt;
            then&lt;br /&gt;
            TOP=DiagR3.14.9.0.1-Tornado2.2.1&lt;br /&gt;
        elif [[ &amp;quot;$IOC_LC&amp;quot; = *&amp;quot;p&amp;quot; ]]&lt;br /&gt;
            then&lt;br /&gt;
            TOP=MLS-Controls&lt;br /&gt;
        else&lt;br /&gt;
            TOP=BII-Controls/base-3-14&lt;br /&gt;
        fi&lt;br /&gt;
&lt;br /&gt;
        BOOTDIR=/opt/IOC/$TOP/boot/$IOC_UC&lt;br /&gt;
        HOMEDIR=$HOMEDIRS/$IOC_LC&lt;br /&gt;
        PIDFILE=$HOMEDIR/$IOC_LC.pid&lt;br /&gt;
        ENVFILE=$HOMEDIR/$IOC_LC.env&lt;br /&gt;
        IOC_USER=$IOC_LC&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
assign_options()&lt;br /&gt;
{&lt;br /&gt;
        # Find $TAG section&lt;br /&gt;
        # Remove comments&lt;br /&gt;
        # Remove leading and trailing whitespace&lt;br /&gt;
        # Remove $TAG: tag&lt;br /&gt;
        # Join lines ending with a &amp;quot;\&amp;quot;&lt;br /&gt;
        # Mark end of option with a &amp;quot;#&amp;quot;&lt;br /&gt;
        # Remove unecessary whitespace&lt;br /&gt;
        TAG=$1&lt;br /&gt;
        SECTION=`sed -n &amp;quot;/^$TAG:/I,/^[\t ]*$/p&amp;quot; $CONFFILE | \&lt;br /&gt;
                 sed -n '/^[^#]/p' | \&lt;br /&gt;
                 sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' \&lt;br /&gt;
                     -e &amp;quot;s/$TAG://I&amp;quot; \&lt;br /&gt;
                     -e :a -e '/\\\\$/N; s/\\\\\\n//; ta' \&lt;br /&gt;
                     -e 's/$/ \#/' \&lt;br /&gt;
                     -e 's/[\t ]/ /g'`&lt;br /&gt;
        evaluate_options $SECTION&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
get_iocs()&lt;br /&gt;
{&lt;br /&gt;
        # Get IOCs from command line or AUTO: entry in configuration file&lt;br /&gt;
        # Test for matching section in configuration file&lt;br /&gt;
        if [ $# = 0 ]&lt;br /&gt;
        then&lt;br /&gt;
                TEST_LIST=`grep -i '^AUTO:' &amp;quot;$CONFFILE&amp;quot; | cut -d: -f2- | tr [:upper:] [:lower:]`&lt;br /&gt;
        else&lt;br /&gt;
                TEST_LIST=&amp;quot;$@&amp;quot;&lt;br /&gt;
        fi&lt;br /&gt;
&lt;br /&gt;
        CHECKED_LIST=&amp;quot;&amp;quot;&lt;br /&gt;
        for IOC in $TEST_LIST&lt;br /&gt;
        do&lt;br /&gt;
                grep -qi &amp;quot;^$IOC:&amp;quot; $CONFFILE&lt;br /&gt;
                if [ $? = 0 ]&lt;br /&gt;
                then&lt;br /&gt;
                        CHECKED_LIST=&amp;quot;$CHECKED_LIST $IOC&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo $CHECKED_LIST&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
set_cmdenvopts()&lt;br /&gt;
{&lt;br /&gt;
        # Set up the environment setup string&lt;br /&gt;
&lt;br /&gt;
        SETENV=&amp;quot;LINES=60 &amp;quot;`test ! -z &amp;quot;$CA_AUTO&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_AUTO_ADDR_LIST=\&amp;quot;$CA_AUTO\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$CA_ADDR&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_ADDR_LIST=\&amp;quot;$CA_ADDR\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$CA_PORT&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_SERVER_PORT=\&amp;quot;$CA_PORT\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$BOOTDIR&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export BOOTDIR=\&amp;quot;$BOOTDIR\&amp;quot;;&amp;quot;`&lt;br /&gt;
&lt;br /&gt;
        # Set up the options for the procserv program&lt;br /&gt;
&lt;br /&gt;
        PROCSERVOPTS=`test ! -z &amp;quot;$IOC_USER&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;-n \&amp;quot;$IOC_USER\&amp;quot;&amp;quot;`&lt;br /&gt;
        PROCSERVOPTS=&amp;quot;$PROCSERVOPTS &amp;quot;`test ! -z &amp;quot;$COREDUMPSIZE&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;--coresize \&amp;quot;$COREDUMPSIZE\&amp;quot;&amp;quot;`&lt;br /&gt;
        PROCSERVOPTS=&amp;quot;$PROCSERVOPTS -q -c $BOOTDIR -p $PIDFILE -i ^D^C^] $PORT&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that starts the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_start()&lt;br /&gt;
{&lt;br /&gt;
        # Return&lt;br /&gt;
        #   0 if daemon has been started&lt;br /&gt;
        #   1 if daemon was already running&lt;br /&gt;
        #   2 if daemon could not be started&lt;br /&gt;
        # Add code here, if necessary, that waits for the process to be ready&lt;br /&gt;
        # to handle requests from services started subsequently which depend&lt;br /&gt;
        # on this one.  As a last resort, sleep for some time.&lt;br /&gt;
&lt;br /&gt;
        echo -n &amp;quot;Starting soft IOCs ... &amp;quot;&lt;br /&gt;
        MYIOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$MYIOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $MYIOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                set_cmdenvopts&lt;br /&gt;
&lt;br /&gt;
                if [ -d $BOOTDIR ]&lt;br /&gt;
                    then&lt;br /&gt;
                    if [ -d $HOMEDIR ]&lt;br /&gt;
                        then&lt;br /&gt;
&lt;br /&gt;
                        sudo -H -u $IOC sh -c &amp;quot;$SETENV (env &amp;gt; $ENVFILE; /sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR \&lt;br /&gt;
                            --pidfile $PIDFILE --startas $PROCSERV --name procServ --test &amp;gt; /dev/null)&amp;quot;&lt;br /&gt;
                        if [ &amp;quot;$?&amp;quot; = 1 ]&lt;br /&gt;
                            then&lt;br /&gt;
                            echo -n &amp;quot;&amp;lt;was running&amp;gt; &amp;quot;&lt;br /&gt;
                            else&lt;br /&gt;
                            sudo -H -u $IOC sh -c &amp;quot;$SETENV (env &amp;gt; $ENVFILE; /sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR \&lt;br /&gt;
                                --pidfile $PIDFILE --startas $PROCSERV --name procServ -- $PROCSERVOPTS ./st.cmd)&amp;quot;&lt;br /&gt;
                            if [ &amp;quot;$?&amp;quot; = 1 ]&lt;br /&gt;
                                then&lt;br /&gt;
                                echo -n &amp;quot;&amp;lt;failed&amp;gt; &amp;quot;&lt;br /&gt;
                            fi&lt;br /&gt;
                        fi&lt;br /&gt;
&lt;br /&gt;
                    else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Home directory $HOMEDIR does not exist! Ignoring $IOC&amp;quot;&lt;br /&gt;
                    fi&lt;br /&gt;
                else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Boot directory $BOOTDIR does not exist! Ignoring $IOC&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that stops the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_stop()&lt;br /&gt;
{&lt;br /&gt;
        # Return&lt;br /&gt;
        #   0 if daemon has been stopped&lt;br /&gt;
        #   1 if daemon was already stopped&lt;br /&gt;
        #   2 if daemon could not be stopped&lt;br /&gt;
        #   other if a failure occurred&lt;br /&gt;
&lt;br /&gt;
        echo -n &amp;quot;Stopping soft IOCs ... &amp;quot;&lt;br /&gt;
        MYIOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$MYIOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $MYIOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                set_cmdenvopts&lt;br /&gt;
&lt;br /&gt;
                sudo -H -u $IOC sh -c &amp;quot;/sbin/start-stop-daemon --stop --quiet --pidfile $PIDFILE --name procServ --test &amp;gt; /dev/null&amp;quot;&lt;br /&gt;
                if [ $? = 1 ]&lt;br /&gt;
                    then&lt;br /&gt;
                    echo -n &amp;quot;&amp;lt;not running&amp;gt; &amp;quot;&lt;br /&gt;
                    else&lt;br /&gt;
                    sudo -H -u $IOC sh -c &amp;quot;/sbin/start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name procServ&amp;quot;&lt;br /&gt;
                    if [ $? = 1 ]&lt;br /&gt;
                        then&lt;br /&gt;
                        echo -n &amp;quot;&amp;lt;failed&amp;gt; &amp;quot;&lt;br /&gt;
                    else&lt;br /&gt;
                        sudo -H -u $IOC sh -c &amp;quot;rm -f $PIDFILE&amp;quot;&lt;br /&gt;
                    fi&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that sends a SIGHUP to the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_reload() {&lt;br /&gt;
        #&lt;br /&gt;
        # If the daemon can reload its configuration without&lt;br /&gt;
        # restarting (for example, when it is sent a SIGHUP),&lt;br /&gt;
        # then implement that here.&lt;br /&gt;
        #&lt;br /&gt;
#       start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME&lt;br /&gt;
#       return 0&lt;br /&gt;
&lt;br /&gt;
        echo &amp;quot;Restarting soft IOCs ... &amp;quot;&lt;br /&gt;
        STARTDIR=$PWD&lt;br /&gt;
        IOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$IOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $IOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                if [ -d $BOOTDIR ]&lt;br /&gt;
                then&lt;br /&gt;
                        cd &amp;quot;$BOOTDIR&amp;quot;&lt;br /&gt;
# restart it!&lt;br /&gt;
                        echo -e &amp;quot;\ndebug: Reloading ioc $IOC&amp;quot;&lt;br /&gt;
                        cd &amp;quot;$STARTDIR&amp;quot;&lt;br /&gt;
                else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Boot directory $BOOTDIR does not exist! Entry for $NET ignored!&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
COMMAND=$1&lt;br /&gt;
shift&lt;br /&gt;
IOCS=`echo $@ | tr [:upper:] [:lower:]`&lt;br /&gt;
&lt;br /&gt;
case &amp;quot;$COMMAND&amp;quot; in&lt;br /&gt;
  start)&lt;br /&gt;
        do_start $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  stop)&lt;br /&gt;
        do_stop $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  #reload|force-reload)&lt;br /&gt;
        #&lt;br /&gt;
        # If do_reload() is not implemented then leave this commented out&lt;br /&gt;
        # and leave 'force-reload' as an alias for 'restart'.&lt;br /&gt;
        #&lt;br /&gt;
        #log_daemon_msg &amp;quot;Reloading $DESC&amp;quot; &amp;quot;$NAME&amp;quot;&lt;br /&gt;
        #do_reload&lt;br /&gt;
        #log_end_msg $?&lt;br /&gt;
        #;;&lt;br /&gt;
  restart|force-reload)&lt;br /&gt;
        #&lt;br /&gt;
        # If the &amp;quot;reload&amp;quot; option is implemented then remove the&lt;br /&gt;
        # 'force-reload' alias&lt;br /&gt;
        #&lt;br /&gt;
        do_stop $IOCS&lt;br /&gt;
        sleep 1&lt;br /&gt;
        do_start $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  *)&lt;br /&gt;
        #echo &amp;quot;Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}&amp;quot; &amp;gt;&amp;amp;2&lt;br /&gt;
        echo &amp;quot;Usage: $SCRIPTNAME {start|stop|restart|force-reload} [iocs ...]&amp;quot; &amp;gt;&amp;amp;2&lt;br /&gt;
        exit 3&lt;br /&gt;
        ;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_Set_Up_a_Soft_IOC_Framework_on_Linux&amp;diff=1649</id>
		<title>How to Set Up a Soft IOC Framework on Linux</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_Set_Up_a_Soft_IOC_Framework_on_Linux&amp;diff=1649"/>
		<updated>2009-02-18T16:51:19Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Break excessively long lines in init script.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''This evolved from my notes when doing this for the soft IOCs at BESSY. Please add or correct things as you find them wrong or out-of-date.''&lt;br /&gt;
&lt;br /&gt;
The following instructions are based on our Debian Linux machines. (Which version? I don't really care. ''Too stable'', I guess.) Other distributions (or other Unixes) might have different commands and different places for things. This is especially true for the Debian &amp;lt;tt&amp;gt;/etc/init.d&amp;lt;/tt&amp;gt; script I'm attaching to this page. If you create a different script for a different distribution, please add it to this page. Others will be able to use it. The general steps will be the same on all distributions, though.&lt;br /&gt;
&lt;br /&gt;
Knowledge of general system administration tasks (creating user accounts etc.) is assumed.&lt;br /&gt;
&lt;br /&gt;
I was giving a talk on [ftp://ftp.desy.de/pub/EPICS/meeting-2007/SoftIOC_Admin.pdf Administration of Soft IOCs under Linux] at the [http://epics.desy.de/content/e2/e127/index_eng.html EPICS Collaboration Meeting in April 2007] that partly covered this issue.&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
== Why are we doing this? ==&lt;br /&gt;
&lt;br /&gt;
When using soft IOCs in production, they should be treated as important system services:&lt;br /&gt;
* Soft IOCs should be started and stopped by the system.&lt;br /&gt;
* There should be a fallback system you can easily switch over to in case of hardware failures.&lt;br /&gt;
&lt;br /&gt;
Other objectives were:&lt;br /&gt;
In the same way as for VME IOCs, the application developer should be able to reset the soft IOC without needing root access to the host.&lt;br /&gt;
* The IOC application developer should be able to start and stop IOCs manually.&lt;br /&gt;
&lt;br /&gt;
When multiple soft IOCs share the same host (and the same IP address), Channel Access can not tell them apart. Access Security will not be able to distiguish between CA connections coming from different soft IOCs. When debugging CA clients, CA will not be able to tell you which of the soft IOCs a connection goes to.&lt;br /&gt;
* Channel Access should be able to distinguish between different soft IOCs, even if they are hosted on the same machine.&lt;br /&gt;
&lt;br /&gt;
I was considering using a virtualization layer (based on VMware) to allow running soft IOCs in an encapsulated environment. I found the effort too high, the layer too thick, and the expected performance hit too hard - only to get a separate IP address for each soft IOC.&lt;br /&gt;
&lt;br /&gt;
When debugging and/or trying to look what is happening on an IOC, the developer does not necessarily know if the database is running on a VME based or on a host based soft IOC. &lt;br /&gt;
* Console access (and logging console output) should be uniform: working the same way for soft as for VME IOCs.&lt;br /&gt;
&lt;br /&gt;
The setup necessary to achieve this is described in the document [[How to Set Up Console Access and Logging for VME and Soft IOCs]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Concept ==&lt;br /&gt;
&lt;br /&gt;
To allow Access Security telling the soft IOCs apart, they are run under separate user names.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt; utility will be used as an environment that allows to start soft IOCs in the background and connect to their consoles later, much like the serial consoles of VME IOCs. (See the &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt; link on the [http://www.aps.anl.gov/epics/extensions/index.php Extensions Page]. Formerly, the &amp;lt;tt&amp;gt;screen&amp;lt;/tt&amp;gt; facility was used, but reported problems, e.g. IOCs hanging up after console access, made us change to something less complex.)&lt;br /&gt;
&lt;br /&gt;
Attaching to a soft IOC console will be done through &amp;lt;tt&amp;gt;ssh&amp;lt;/tt&amp;gt;, using a special console access key. Ssh is set up with the matching &amp;lt;tt&amp;gt;telnet&amp;lt;/tt&amp;gt; commands that reattach to the soft IOCs. Opening an ssh connection using the console access key to the user &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; on the soft IOC host will immediately attach to the console of the soft IOC named &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; (that is running as user &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Setting up Your Machine =&lt;br /&gt;
== Create User Accounts and ssh Access ==&lt;br /&gt;
&lt;br /&gt;
=== Soft IOC Administrator Account ===&lt;br /&gt;
&lt;br /&gt;
Create a generic user account that application developers will use to start/stop soft IOCs. (We call it &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Put the public ssh keys of the application developers into &amp;lt;tt&amp;gt;~/.ssh/authorized_keys&amp;lt;/tt&amp;gt; of &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== ssh Key Pairs ===&lt;br /&gt;
&lt;br /&gt;
As &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;, create one key pair for this user, and another key pair for console access.&lt;br /&gt;
&lt;br /&gt;
=== Soft IOCs ===&lt;br /&gt;
&lt;br /&gt;
Create one user account for each soft IOC you intend to host. User name should be the IOC name, the group is not really important. (Maybe create a group &amp;lt;tt&amp;gt;iocs&amp;lt;/tt&amp;gt; that you put all of them into?)&lt;br /&gt;
&lt;br /&gt;
Into each of the &amp;lt;tt&amp;gt;~/.ssh/authorized_keys&amp;lt;/tt&amp;gt; files, put two public keys:&lt;br /&gt;
# The public ssh key of &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# The public ssh key for console access.&lt;br /&gt;
&lt;br /&gt;
In front of the console access key, put the &amp;lt;tt&amp;gt;telnet&amp;lt;/tt&amp;gt; command to reattach to the soft IOC console. For a user/IOC &amp;lt;tt&amp;gt;ioc123&amp;lt;/tt&amp;gt; that provides console access on port &amp;lt;tt&amp;gt;24703&amp;lt;/tt&amp;gt;, the line should look like this:&lt;br /&gt;
&lt;br /&gt;
 command=&amp;quot;telnet localhost 24703&amp;quot; ssh-rsa AAAAB3NzaC1yc2EAAAA.....&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Configure the sudo Facility ==&lt;br /&gt;
&lt;br /&gt;
=== Allow the iocadm User to Start and Stop Soft IOCs ===&lt;br /&gt;
&lt;br /&gt;
On the soft IOC host, allow iocadm to use sudo to execute commands as any of the soft IOC users. &amp;lt;tt&amp;gt;/etc/sudoers&amp;lt;/tt&amp;gt; should have a line like:&lt;br /&gt;
&lt;br /&gt;
 iocadm ALL = (ioc123, ioc124, ioc125) NOPASSWD: ALL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Setup the Start/Stop script ==&lt;br /&gt;
&lt;br /&gt;
=== Create the /etc/init.d script ===&lt;br /&gt;
&lt;br /&gt;
I'm attaching the script that we're using as &amp;lt;tt&amp;gt;/etc/init.d/softIOC&amp;lt;/tt&amp;gt;. It got quite huge and complex - ''sorry!''. It has been modelled after Debian's skeleton scripts, you should probably adapt it to match the standards that your distribution implies.&lt;br /&gt;
&lt;br /&gt;
It contains the local settings for where to find things, routines to read in the configuration file, the code necessary to start/stop a soft IOC as a different user under &amp;lt;tt&amp;gt;procServ&amp;lt;/tt&amp;gt;, and the usual &amp;lt;tt&amp;gt;init.d&amp;lt;/tt&amp;gt; script stuff that checks command line arguments and calls the other routines.&lt;br /&gt;
&lt;br /&gt;
''If you have a script working for a different distribution, please add it to this page, as it could make life easier for others!''&lt;br /&gt;
&lt;br /&gt;
=== Create the Configuration File ===&lt;br /&gt;
&lt;br /&gt;
The configuration file contains a section for each of the soft IOCs. A section starts with the IOC name followed by a colon, and ends with an empty line.&lt;br /&gt;
&lt;br /&gt;
Within a section you can set special variables used by the &amp;lt;tt&amp;gt;softIOC&amp;lt;/tt&amp;gt; script as well as environment variables that will be set for the soft IOC.&lt;br /&gt;
&lt;br /&gt;
The special section &amp;lt;tt&amp;gt;global:&amp;lt;/tt&amp;gt; contains settings that will be applied to ''all'' soft IOCs (may be overridden by the IOC section).&lt;br /&gt;
&lt;br /&gt;
The special line &amp;lt;tt&amp;gt;auto:&amp;lt;/tt&amp;gt; contains the names of the soft IOCs that should be started when the script is run as part of the system boot-up process.&lt;br /&gt;
&lt;br /&gt;
Section and IOC names are not case sensitive.&lt;br /&gt;
&lt;br /&gt;
So a minimal configuration file could look like this (remember the empty line that is required after each section):&lt;br /&gt;
&lt;br /&gt;
 AUTO:   ioc123&lt;br /&gt;
 &lt;br /&gt;
 GLOBAL:&lt;br /&gt;
 &lt;br /&gt;
 ioc123:&lt;br /&gt;
 &lt;br /&gt;
 ioc124:&lt;br /&gt;
 &lt;br /&gt;
 ioc125:&lt;br /&gt;
&lt;br /&gt;
== Distribute the Required Stuff to the Soft IOC Host ==&lt;br /&gt;
&lt;br /&gt;
=== EPICS Base ===&lt;br /&gt;
&lt;br /&gt;
Soft IOCS will need libraries from EPICS base. Make sure these are existing and can be found.&lt;br /&gt;
&lt;br /&gt;
=== Code and Databases ===&lt;br /&gt;
&lt;br /&gt;
Add the soft IOC host to the code deployment scheme you are using. The soft IOC binaries, databases, and start up scripts must be available for the soft IOCs to be started.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Start Your Soft IOCs =&lt;br /&gt;
&lt;br /&gt;
== Start the IOCs using the startup script ==&lt;br /&gt;
&lt;br /&gt;
Starting and stopping the soft IOCs should work now! Ssh to the soft IOC host as &amp;lt;tt&amp;gt;iocadm&amp;lt;/tt&amp;gt; and try calling the startup script:&lt;br /&gt;
&lt;br /&gt;
 /etc/init.d/softIOC start ioc123&lt;br /&gt;
&lt;br /&gt;
== Watch them run ==&lt;br /&gt;
&lt;br /&gt;
Ssh to the soft IOC host using the console access key and see if you can get access to the IOC console:&lt;br /&gt;
&lt;br /&gt;
 ssh -i ~iocadm/.ssh/console_access -t ioc123@iochost&lt;br /&gt;
&lt;br /&gt;
You should be directly connected to your IOC's console.&lt;br /&gt;
&lt;br /&gt;
== Check if Starting IOCs at reboot works ==&lt;br /&gt;
&lt;br /&gt;
If you made entries to the &amp;lt;tt&amp;gt;auto:&amp;lt;/tt&amp;gt; section, reboot the machine to check that starting IOCs at boot time works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''''Good luck!'''''&lt;br /&gt;
&lt;br /&gt;
[mailto:Ralph.Lange_at_bessy.de Ralph Lange (BESSY)]&lt;br /&gt;
&lt;br /&gt;
created: [[User:RalphLange|Ralph]] 05:08, 26 Apr 2007 (CDT)&lt;br /&gt;
&lt;br /&gt;
last edit: [[User:RalphLange|Ralph]] 11:17, 12 Feb 2009 (CDT)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= The Startup Script =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;/etc/init.d/softIOC&amp;lt;/tt&amp;gt; script for Debian Linux&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
# Author: &amp;lt;Ralph.Lange@bessy.de&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# History:&lt;br /&gt;
#          2006-03-12: Adapted from D. Herrendörfer's ca-gateway script&lt;br /&gt;
#          2006-04-04: Bugfix in config file parser&lt;br /&gt;
#          2008-05-20: Adapted to procServ&lt;br /&gt;
&lt;br /&gt;
# Do NOT &amp;quot;set -e&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# !! This script is located on a mounted file system&lt;br /&gt;
# !! It must be run after the mountnfs.sh script&lt;br /&gt;
&lt;br /&gt;
PATH=/sbin:/usr/sbin:/bin:/usr/bin&lt;br /&gt;
DESC=&amp;quot;EPICS soft IOCs&amp;quot;&lt;br /&gt;
SCRIPTNAME=/etc/init.d/softIOC&lt;br /&gt;
HOST=`uname -n`&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCSERV=/usr/local/bin/procServ&lt;br /&gt;
CONFFILE=/opt/IOC/softIOC/softiocs.$HOST&lt;br /&gt;
HOMEDIRS=/home/controls&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Check for config file&lt;br /&gt;
if [ ! -r $CONFFILE ]&lt;br /&gt;
then&lt;br /&gt;
        echo &amp;quot;Error: Can't find configuration file $CONFFILE!&amp;quot;&lt;br /&gt;
        exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Functions that read in the configuration file&lt;br /&gt;
#&lt;br /&gt;
clear_options()&lt;br /&gt;
{&lt;br /&gt;
        for option in &amp;quot;CA_AUTO&amp;quot; &amp;quot;CA_ADDR&amp;quot; &amp;quot;CA_PORT&amp;quot; &amp;quot;IOC_USER&amp;quot; &amp;quot;PORT&amp;quot;&lt;br /&gt;
        do&lt;br /&gt;
                unset $option;&lt;br /&gt;
        done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
evaluate_options()&lt;br /&gt;
{&lt;br /&gt;
        while [ $# != 0 ]&lt;br /&gt;
        do&lt;br /&gt;
                TAG=`echo $1 | tr [:lower:] [:upper:]`&lt;br /&gt;
                case &amp;quot;$TAG&amp;quot; in&lt;br /&gt;
                &amp;quot;#&amp;quot;)            ;;&lt;br /&gt;
                &amp;quot;CA_AUTO&amp;quot; | &amp;quot;CA_ADDR&amp;quot; | &amp;quot;CA_PORT&amp;quot; | &amp;quot;COREDUMPSIZE&amp;quot; | \&lt;br /&gt;
                &amp;quot;HOMEDIR&amp;quot; | &amp;quot;BOOTDIR&amp;quot; | &amp;quot;IOC_USER&amp;quot; | &amp;quot;PORT&amp;quot; )&lt;br /&gt;
                                # Test the presence of values for the current option&lt;br /&gt;
                                OPTION=$TAG&lt;br /&gt;
                                shift&lt;br /&gt;
                                if [ -z $TAG -o $TAG = &amp;quot;#&amp;quot; ]&lt;br /&gt;
                                then&lt;br /&gt;
                                        echo &amp;quot;$CONFFILE: Value(s) required for $TAG.&amp;quot;;&lt;br /&gt;
                                        exit 1&lt;br /&gt;
                                else&lt;br /&gt;
                                        VALUE=$1&lt;br /&gt;
                                        shift&lt;br /&gt;
                                fi&lt;br /&gt;
                                # If more values follow assign them too&lt;br /&gt;
                                while [ $1 != '#'  -a  $# != 0 ]&lt;br /&gt;
                                do&lt;br /&gt;
                                        VALUE=&amp;quot;$VALUE $1&amp;quot;&lt;br /&gt;
                                        shift;&lt;br /&gt;
                                done&lt;br /&gt;
                                eval ${OPTION}=\$VALUE&lt;br /&gt;
                                ;;&lt;br /&gt;
                *)              echo &amp;quot;$CONFFILE: Unknown option $1.&amp;quot;&lt;br /&gt;
                                exit 1&lt;br /&gt;
                esac&lt;br /&gt;
                shift&lt;br /&gt;
        done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default_options()&lt;br /&gt;
{&lt;br /&gt;
        # Set IOC defaults for options&lt;br /&gt;
        # (may be overridden in config file)&lt;br /&gt;
        IOC_LC=$1&lt;br /&gt;
        IOC_UC=`echo $1 | tr [:lower:] [:upper:]`&lt;br /&gt;
&lt;br /&gt;
        if [[ &amp;quot;$IOC_LC&amp;quot; = &amp;quot;mdi&amp;quot;* ]]&lt;br /&gt;
            then&lt;br /&gt;
            TOP=DiagR3.14.9.0.1-Tornado2.2.1&lt;br /&gt;
        elif [[ &amp;quot;$IOC_LC&amp;quot; = *&amp;quot;p&amp;quot; ]]&lt;br /&gt;
            then&lt;br /&gt;
            TOP=MLS-Controls&lt;br /&gt;
        else&lt;br /&gt;
            TOP=BII-Controls/base-3-14&lt;br /&gt;
        fi&lt;br /&gt;
&lt;br /&gt;
        BOOTDIR=/opt/IOC/$TOP/boot/$IOC_UC&lt;br /&gt;
        HOMEDIR=$HOMEDIRS/$IOC_LC&lt;br /&gt;
        PIDFILE=$HOMEDIR/$IOC_LC.pid&lt;br /&gt;
        ENVFILE=$HOMEDIR/$IOC_LC.env&lt;br /&gt;
        IOC_USER=$IOC_LC&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
assign_options()&lt;br /&gt;
{&lt;br /&gt;
        # Find $TAG section&lt;br /&gt;
        # Remove comments&lt;br /&gt;
        # Remove leading and trailing whitespace&lt;br /&gt;
        # Remove $TAG: tag&lt;br /&gt;
        # Join lines ending with a &amp;quot;\&amp;quot;&lt;br /&gt;
        # Mark end of option with a &amp;quot;#&amp;quot;&lt;br /&gt;
        # Remove unecessary whitespace&lt;br /&gt;
        TAG=$1&lt;br /&gt;
        SECTION=`sed -n &amp;quot;/^$TAG:/I,/^[\t ]*$/p&amp;quot; $CONFFILE | \&lt;br /&gt;
                 sed -n '/^[^#]/p' | \&lt;br /&gt;
                 sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' \&lt;br /&gt;
                     -e &amp;quot;s/$TAG://I&amp;quot; \&lt;br /&gt;
                     -e :a -e '/\\\\$/N; s/\\\\\\n//; ta' \&lt;br /&gt;
                     -e 's/$/ \#/' \&lt;br /&gt;
                     -e 's/[\t ]/ /g'`&lt;br /&gt;
        evaluate_options $SECTION&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
get_iocs()&lt;br /&gt;
{&lt;br /&gt;
        # Get IOCs from command line or AUTO: entry in configuration file&lt;br /&gt;
        # Test for matching section in configuration file&lt;br /&gt;
        if [ $# = 0 ]&lt;br /&gt;
        then&lt;br /&gt;
                TEST_LIST=`grep -i '^AUTO:' &amp;quot;$CONFFILE&amp;quot; | cut -d: -f2- | tr [:upper:] [:lower:]`&lt;br /&gt;
        else&lt;br /&gt;
                TEST_LIST=&amp;quot;$@&amp;quot;&lt;br /&gt;
        fi&lt;br /&gt;
&lt;br /&gt;
        CHECKED_LIST=&amp;quot;&amp;quot;&lt;br /&gt;
        for IOC in $TEST_LIST&lt;br /&gt;
        do&lt;br /&gt;
                grep -qi &amp;quot;^$IOC:&amp;quot; $CONFFILE&lt;br /&gt;
                if [ $? = 0 ]&lt;br /&gt;
                then&lt;br /&gt;
                        CHECKED_LIST=&amp;quot;$CHECKED_LIST $IOC&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo $CHECKED_LIST&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
set_cmdenvopts()&lt;br /&gt;
{&lt;br /&gt;
        # Set up the environment setup string&lt;br /&gt;
&lt;br /&gt;
        SETENV=&amp;quot;LINES=60 &amp;quot;`test ! -z &amp;quot;$CA_AUTO&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_AUTO_ADDR_LIST=\&amp;quot;$CA_AUTO\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$CA_ADDR&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_ADDR_LIST=\&amp;quot;$CA_ADDR\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$CA_PORT&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export EPICS_CA_SERVER_PORT=\&amp;quot;$CA_PORT\&amp;quot;;&amp;quot;`&lt;br /&gt;
        SETENV=&amp;quot;$SETENV &amp;quot;`test ! -z &amp;quot;$BOOTDIR&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;export BOOTDIR=\&amp;quot;$BOOTDIR\&amp;quot;;&amp;quot;`&lt;br /&gt;
&lt;br /&gt;
        # Set up the options for the procserv program&lt;br /&gt;
&lt;br /&gt;
        PROCSERVOPTS=`test ! -z &amp;quot;$IOC_USER&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;-n \&amp;quot;$IOC_USER\&amp;quot;&amp;quot;`&lt;br /&gt;
        PROCSERVOPTS=&amp;quot;$PROCSERVOPTS &amp;quot;`test ! -z &amp;quot;$COREDUMPSIZE&amp;quot; &amp;amp;&amp;amp; echo &amp;quot;--coresize \&amp;quot;$COREDUMPSIZE\&amp;quot;&amp;quot;`&lt;br /&gt;
        PROCSERVOPTS=&amp;quot;$PROCSERVOPTS -q -c $BOOTDIR -p $PIDFILE -i ^D^C^] $PORT&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that starts the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_start()&lt;br /&gt;
{&lt;br /&gt;
        # Return&lt;br /&gt;
        #   0 if daemon has been started&lt;br /&gt;
        #   1 if daemon was already running&lt;br /&gt;
        #   2 if daemon could not be started&lt;br /&gt;
        # Add code here, if necessary, that waits for the process to be ready&lt;br /&gt;
        # to handle requests from services started subsequently which depend&lt;br /&gt;
        # on this one.  As a last resort, sleep for some time.&lt;br /&gt;
&lt;br /&gt;
        echo -n &amp;quot;Starting soft IOCs ... &amp;quot;&lt;br /&gt;
        MYIOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$MYIOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $MYIOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                set_cmdenvopts&lt;br /&gt;
&lt;br /&gt;
                if [ -d $BOOTDIR ]&lt;br /&gt;
                    then&lt;br /&gt;
                    if [ -d $HOMEDIR ]&lt;br /&gt;
                        then&lt;br /&gt;
&lt;br /&gt;
                        sudo -H -u $IOC sh -c &amp;quot;$SETENV (env &amp;gt; $ENVFILE; /sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR --pidfile $PIDFILE --startas $PROCSERV --name procServ --test &amp;gt; /dev/null)&amp;quot;&lt;br /&gt;
                        if [ &amp;quot;$?&amp;quot; = 1 ]&lt;br /&gt;
                            then&lt;br /&gt;
                            echo -n &amp;quot;&amp;lt;was running&amp;gt; &amp;quot;&lt;br /&gt;
                            else&lt;br /&gt;
                            sudo -H -u $IOC sh -c &amp;quot;$SETENV (env &amp;gt; $ENVFILE; /sbin/start-stop-daemon --start --quiet --chdir $BOOTDIR --pidfile $PIDFILE --startas $PROCSERV --name procServ -- $PROCSERVOPTS ./st.cmd)&amp;quot;&lt;br /&gt;
                            if [ &amp;quot;$?&amp;quot; = 1 ]&lt;br /&gt;
                                then&lt;br /&gt;
                                echo -n &amp;quot;&amp;lt;failed&amp;gt; &amp;quot;&lt;br /&gt;
                            fi&lt;br /&gt;
                        fi&lt;br /&gt;
&lt;br /&gt;
                    else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Home directory $HOMEDIR does not exist! Ignoring $IOC&amp;quot;&lt;br /&gt;
                    fi&lt;br /&gt;
                else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Boot directory $BOOTDIR does not exist! Ignoring $IOC&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that stops the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_stop()&lt;br /&gt;
{&lt;br /&gt;
        # Return&lt;br /&gt;
        #   0 if daemon has been stopped&lt;br /&gt;
        #   1 if daemon was already stopped&lt;br /&gt;
        #   2 if daemon could not be stopped&lt;br /&gt;
        #   other if a failure occurred&lt;br /&gt;
&lt;br /&gt;
        echo -n &amp;quot;Stopping soft IOCs ... &amp;quot;&lt;br /&gt;
        MYIOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$MYIOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $MYIOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                set_cmdenvopts&lt;br /&gt;
&lt;br /&gt;
                sudo -H -u $IOC sh -c &amp;quot;/sbin/start-stop-daemon --stop --quiet \&lt;br /&gt;
                         --pidfile $PIDFILE --name procServ --test &amp;gt; /dev/null&amp;quot;&lt;br /&gt;
                if [ $? = 1 ]&lt;br /&gt;
                    then&lt;br /&gt;
                    echo -n &amp;quot;&amp;lt;not running&amp;gt; &amp;quot;&lt;br /&gt;
                    else&lt;br /&gt;
                    sudo -H -u $IOC sh -c &amp;quot;/sbin/start-stop-daemon --stop \&lt;br /&gt;
             --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name procServ&amp;quot;&lt;br /&gt;
                    if [ $? = 1 ]&lt;br /&gt;
                        then&lt;br /&gt;
                        echo -n &amp;quot;&amp;lt;failed&amp;gt; &amp;quot;&lt;br /&gt;
                    else&lt;br /&gt;
                        sudo -H -u $IOC sh -c &amp;quot;rm -f $PIDFILE&amp;quot;&lt;br /&gt;
                    fi&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# Function that sends a SIGHUP to the daemon/service&lt;br /&gt;
#&lt;br /&gt;
do_reload() {&lt;br /&gt;
        #&lt;br /&gt;
        # If the daemon can reload its configuration without&lt;br /&gt;
        # restarting (for example, when it is sent a SIGHUP),&lt;br /&gt;
        # then implement that here.&lt;br /&gt;
        #&lt;br /&gt;
#       start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME&lt;br /&gt;
#       return 0&lt;br /&gt;
&lt;br /&gt;
        echo &amp;quot;Restarting soft IOCs ... &amp;quot;&lt;br /&gt;
        STARTDIR=$PWD&lt;br /&gt;
        IOCS=`get_iocs $@`&lt;br /&gt;
        [ &amp;quot;$IOCS&amp;quot; = &amp;quot;&amp;quot; ] &amp;amp;&amp;amp; echo -n &amp;quot;&amp;lt;none&amp;gt; &amp;quot;&lt;br /&gt;
        for IOC in $IOCS&lt;br /&gt;
        do&lt;br /&gt;
                echo -n &amp;quot;$IOC &amp;quot;&lt;br /&gt;
                clear_options&lt;br /&gt;
                default_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;GLOBAL&amp;quot;&lt;br /&gt;
                assign_options &amp;quot;$IOC&amp;quot;&lt;br /&gt;
                if [ -d $BOOTDIR ]&lt;br /&gt;
                then&lt;br /&gt;
                        cd &amp;quot;$BOOTDIR&amp;quot;&lt;br /&gt;
# restart it!&lt;br /&gt;
                        echo -e &amp;quot;\ndebug: Reloading ioc $IOC&amp;quot;&lt;br /&gt;
                        cd &amp;quot;$STARTDIR&amp;quot;&lt;br /&gt;
                else&lt;br /&gt;
                        echo -e &amp;quot;\nWarning: Boot directory $BOOTDIR does not exist! Entry for $NET ignored!&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
        done&lt;br /&gt;
        echo &amp;quot;... done.&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
COMMAND=$1&lt;br /&gt;
shift&lt;br /&gt;
IOCS=`echo $@ | tr [:upper:] [:lower:]`&lt;br /&gt;
&lt;br /&gt;
case &amp;quot;$COMMAND&amp;quot; in&lt;br /&gt;
  start)&lt;br /&gt;
        do_start $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  stop)&lt;br /&gt;
        do_stop $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  #reload|force-reload)&lt;br /&gt;
        #&lt;br /&gt;
        # If do_reload() is not implemented then leave this commented out&lt;br /&gt;
        # and leave 'force-reload' as an alias for 'restart'.&lt;br /&gt;
        #&lt;br /&gt;
        #log_daemon_msg &amp;quot;Reloading $DESC&amp;quot; &amp;quot;$NAME&amp;quot;&lt;br /&gt;
        #do_reload&lt;br /&gt;
        #log_end_msg $?&lt;br /&gt;
        #;;&lt;br /&gt;
  restart|force-reload)&lt;br /&gt;
        #&lt;br /&gt;
        # If the &amp;quot;reload&amp;quot; option is implemented then remove the&lt;br /&gt;
        # 'force-reload' alias&lt;br /&gt;
        #&lt;br /&gt;
        do_stop $IOCS&lt;br /&gt;
        sleep 1&lt;br /&gt;
        do_start $IOCS&lt;br /&gt;
        ;;&lt;br /&gt;
  *)&lt;br /&gt;
        #echo &amp;quot;Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}&amp;quot; &amp;gt;&amp;amp;2&lt;br /&gt;
        echo &amp;quot;Usage: $SCRIPTNAME {start|stop|restart|force-reload} [iocs ...]&amp;quot; &amp;gt;&amp;amp;2&lt;br /&gt;
        exit 3&lt;br /&gt;
        ;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=2846</id>
		<title>How to use GPIB ports with linux-gpib and StreamDevice</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=2846"/>
		<updated>2008-01-18T17:42:59Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Add my name, email address and date&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document evolved from a [[http://www.aps.anl.gov/epics/tech-talk/2008/msg00046.php|reply]] I sent to tech-talk to someone who was struggling with the setup of his GPIB device using devGpib.&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
The following instructions explain the setup of an EPICS softIOC to talk to a GPIB device on Linux.&lt;br /&gt;
&lt;br /&gt;
The instructions are based on Debian Linux, but should be easily adaptable to other flavors of Linux.&lt;br /&gt;
&lt;br /&gt;
= Prerequisites =&lt;br /&gt;
You need linux-gpib[http://linux-gpib.sourceforge.net/], EPICS base[http://www.aps.anl.gov/epics/base/R3-14/index.php], asyn[http://www.aps.anl.gov/epics/modules/soft/asyn/], and StreamDevice[http://epics.web.psi.ch/software/streamdevice/].&lt;br /&gt;
&lt;br /&gt;
== linux-gpib installation ==&lt;br /&gt;
On Debian, you can just do&lt;br /&gt;
      apt-get install gpib-modules-source module-assistant&lt;br /&gt;
      module-assistant auto-install gpib-modules-source&lt;br /&gt;
to build and install the kernel modules of the &amp;lt;tt&amp;gt;linux-gpib&amp;lt;/tt&amp;gt; driver for your kernel. Similarly, by issuing&lt;br /&gt;
      apt-get install libgpib0 libgpib0-dev libgpib-bin&lt;br /&gt;
you can install the user space part of &amp;lt;tt&amp;gt;linux-gpib&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
On other distributions, check for the availability of &amp;lt;tt&amp;gt;linux-gpib&amp;lt;/tt&amp;gt; packages. You can always resort to compiling linux-gpib youself. Refer to the linux-gpib documentation[http://linux-gpib.sourceforge.net/doc_html/index.html] for this.&lt;br /&gt;
&lt;br /&gt;
Once you have linux-gpib installed, it's time to configure your interface board. Assuming you have a single GPIB interface board in your machine, you'll need to&lt;br /&gt;
&lt;br /&gt;
* figure out the board type, i.e. find out what low-level driver from linux-gpib does support you board, e.g. &amp;lt;tt&amp;gt;ines_pci&amp;lt;/tt&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
* give the interface board an arbitrary name, e.g. &amp;lt;tt&amp;gt;L0&amp;lt;/tt&amp;gt;. You'll need to use this name as the first parameter to the &amp;lt;tt&amp;gt;GpibBoardDriverConfig&amp;lt;/tt&amp;gt; command in the &amp;lt;tt&amp;gt;st.cmd&amp;lt;/tt&amp;gt; of your softIOC later on. There seems to be a convention for the name to start with &amp;quot;L&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
To be able to use the interface board as &amp;lt;tt&amp;gt;/dev/gpib0&amp;lt;/tt&amp;gt;, put something like&lt;br /&gt;
&lt;br /&gt;
      interface {&lt;br /&gt;
              minor = 0       /* board index, minor = 0 is /dev/gpib0 */&lt;br /&gt;
              board_type = &amp;quot;ines_pci&amp;quot; /* type of interface board being used */&lt;br /&gt;
              name = &amp;quot;L0&amp;quot;     /* board name */&lt;br /&gt;
              pad = 0         /* primary address of interface */&lt;br /&gt;
              sad = 0         /* secondary address of interface */&lt;br /&gt;
              timeout = T3s   /* timeout for commands */&lt;br /&gt;
              eos = 0x0a      /* EOS Byte, 0xa is LF and 0xd is CR */&lt;br /&gt;
              set-reos = yes  /* Terminate read if EOS */&lt;br /&gt;
              set-bin = no    /* Compare EOS 8-bit */&lt;br /&gt;
              set-xeos = no   /* Assert EOI whenever EOS byte is sent */&lt;br /&gt;
              set-eot = yes   /* Assert EOI with last byte on writes */&lt;br /&gt;
              master = yes    /* interface board is system controller */&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
in &amp;lt;tt&amp;gt;/etc/gpib_conf&amp;lt;/tt&amp;gt;, load the kernel driver for your board&lt;br /&gt;
      modprobe ines_pci&lt;br /&gt;
and finally run&lt;br /&gt;
      gpib_config&lt;br /&gt;
&lt;br /&gt;
=== Verify connection to GPIB board ===&lt;br /&gt;
Verify you can talk to the board using &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
      sheim@txm1:~$ ibtest&lt;br /&gt;
      Do you wish to open a (d)evice or an interface (b)oard?&lt;br /&gt;
              (you probably want to open a device): b&lt;br /&gt;
      enter name of interface board (or device) you wish to open: L0&lt;br /&gt;
      trying to open board named 'L0'&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : l&lt;br /&gt;
      DAV off&lt;br /&gt;
      NDAC on&lt;br /&gt;
      NRFD off&lt;br /&gt;
      IFC off&lt;br /&gt;
      REN on&lt;br /&gt;
      SRQ off&lt;br /&gt;
      ATN off&lt;br /&gt;
      EOI on&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x164  &amp;lt; CMPL REM CIC LACS &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 0&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : q&lt;br /&gt;
      sheim@txm1:~$&lt;br /&gt;
&lt;br /&gt;
=== Verify connection to the GPIB device===&lt;br /&gt;
Assuming your device has GPIB address 2 and will answer to the command &amp;quot;:FETC?&amp;quot;, test it with &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt; like this:&lt;br /&gt;
&lt;br /&gt;
      sheim@brixen:~$ ibtest&lt;br /&gt;
      Do you wish to open a (d)evice or an interface (b)oard?&lt;br /&gt;
              (you probably want to open a device): d&lt;br /&gt;
      enter primary gpib address for device you wish to open [0-30]: 2&lt;br /&gt;
      trying to open pad = 2 on /dev/gpib0 ...&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : w&lt;br /&gt;
      enter a string to send to your device: :FETC?&lt;br /&gt;
      sending string: :FETC?&lt;br /&gt;
&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x2100  &amp;lt; END CMPL &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 7&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : r&lt;br /&gt;
      enter maximum number of bytes to read [1024]:&lt;br /&gt;
      trying to read 1024 bytes from device...&lt;br /&gt;
      received string: '-000.0003E-12ADC&lt;br /&gt;
      '&lt;br /&gt;
      Number of bytes read: 17&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x2100  &amp;lt; END CMPL &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 17&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : q&lt;br /&gt;
      sheim@brixen:~$&lt;br /&gt;
&lt;br /&gt;
If communication with the device works using &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt;, the setup of the softIOC is trivial if you stick to the 7-step recipe in section 3.&lt;br /&gt;
&lt;br /&gt;
== EPICS installation ==&lt;br /&gt;
Since I maintain Debian packages for EPICS base, all support modules and all extensions I use, here I just do:&lt;br /&gt;
&lt;br /&gt;
      apt-get install epics-base epics-support-asyn epics-support-streamdevice&lt;br /&gt;
&lt;br /&gt;
Until I find the time to publish my Debian EPICS archive (sid, lenny, etch, sarge and several Ubuntu versions available), or if you are using a different distribution anyway, you'll have to stick to compiling and installing EPICS base, asyn and StreamDevice yourself.&lt;br /&gt;
&lt;br /&gt;
= The softIOC =&lt;br /&gt;
Now it's time to set up the actual softIOC.&lt;br /&gt;
&lt;br /&gt;
== STEP 1: Create GPIB application ==&lt;br /&gt;
In a fresh and clean directory, do&lt;br /&gt;
      makeBaseApp.pl -t example gpib&lt;br /&gt;
      makeBaseApp.pl -t example -i -a linux-x86 -p gpib gpib&lt;br /&gt;
 &lt;br /&gt;
== STEP 2: Use asyn and StreamDevice support ==&lt;br /&gt;
Append to configure/RELEASE&lt;br /&gt;
      ASYN=/opt/epics/support/asyn&lt;br /&gt;
      STREAMS=/opt/epics/support/streamdevice&lt;br /&gt;
 &lt;br /&gt;
Make sure you have asyn and StreamDevice installed and supply the correct paths to your EPICS support directories.&lt;br /&gt;
 &lt;br /&gt;
== STEP 3: Create a protocol file ==&lt;br /&gt;
Create a protocol file&lt;br /&gt;
      gpibApp/Db/yourdev.proto&lt;br /&gt;
like this:&lt;br /&gt;
&lt;br /&gt;
      === gpibApp/Db/yourdev.proto ===&lt;br /&gt;
      Terminator = CR LF;&lt;br /&gt;
 &lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      setCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP %f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      ================================&lt;br /&gt;
 &lt;br /&gt;
 You might want to consult the SCPI command reference for your device and &lt;br /&gt;
 implement whatever part of the protocol you may need.&lt;br /&gt;
 &lt;br /&gt;
== STEP 4: Create a database ==&lt;br /&gt;
Create a database&lt;br /&gt;
      gpibApp/Db/yourdev.db&lt;br /&gt;
matching the protocol from STEP 3 like this:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/Db/yourdev.db ===&lt;br /&gt;
      record (ai, &amp;quot;$(P)currentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (INP,  &amp;quot;@yourdev.proto getCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      record (ao, &amp;quot;$(P)setCurrentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (OUT,  &amp;quot;@yourdev.proto setCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
      =============================&lt;br /&gt;
 &lt;br /&gt;
In order to register your database with the build system, add the line&lt;br /&gt;
      DB += yourdev.db&lt;br /&gt;
in the middle of&lt;br /&gt;
      gpibApp/Db/Makefile.&lt;br /&gt;
 &lt;br /&gt;
== STEP 5: Adapt application Makefile ==&lt;br /&gt;
Have&lt;br /&gt;
      gpibApp/src/Makefile&lt;br /&gt;
read:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/src/Makefile ===&lt;br /&gt;
      TOP=../..&lt;br /&gt;
      include $(TOP)/configure/CONFIG&lt;br /&gt;
 &lt;br /&gt;
      # build an ioc application&lt;br /&gt;
      PROD_IOC = gpib&lt;br /&gt;
      PROD_LIBS += asyn&lt;br /&gt;
      PROD_LIBS += stream&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be created and installed&lt;br /&gt;
      DBD += gpib.dbd&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be made up from these files:&lt;br /&gt;
      gpib_DBD += base.dbd&lt;br /&gt;
      gpib_DBD += asyn.dbd&lt;br /&gt;
      gpib_DBD += drvAsynIPPort.dbd&lt;br /&gt;
      gpib_DBD += drvAsynSerialPort.dbd&lt;br /&gt;
      gpib_DBD += drvLinuxGpib.dbd&lt;br /&gt;
      gpib_DBD += stream.dbd&lt;br /&gt;
 &lt;br /&gt;
      # softIOC house-keeping&lt;br /&gt;
      gpib_SRCS += gpib_registerRecordDeviceDriver.cpp&lt;br /&gt;
      gpib_SRCS_DEFAULT += gpibMain.cpp&lt;br /&gt;
      gpib_LIBS += $(EPICS_BASE_IOC_LIBS)&lt;br /&gt;
 &lt;br /&gt;
      include $(TOP)/configure/RULES&lt;br /&gt;
      ============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 6: Create an IOC startup script ==&lt;br /&gt;
Have the IOC's st.cmd look like this:&lt;br /&gt;
 &lt;br /&gt;
      === iocBoot/iocgpib/st.cmd ===&lt;br /&gt;
      #!../../bin/linux-x86/gpib&lt;br /&gt;
 &lt;br /&gt;
      &amp;lt; envPaths&lt;br /&gt;
      epicsEnvSet(STREAM_PROTOCOL_PATH, &amp;quot;../../gpibApp/Db&amp;quot;)&lt;br /&gt;
      cd ${TOP}&lt;br /&gt;
 &lt;br /&gt;
      ## 1 Register all support components&lt;br /&gt;
      dbLoadDatabase(&amp;quot;dbd/gpib.dbd&amp;quot;)&lt;br /&gt;
      gpib_registerRecordDeviceDriver(pdbbase)&lt;br /&gt;
 &lt;br /&gt;
      ## 2 Configure your asynPorts&lt;br /&gt;
      # 2a GPIB: portname, autoConnect, boardId, timeout, 5th_arg&lt;br /&gt;
      GpibBoardDriverConfig(&amp;quot;L0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;3&amp;quot;, &amp;quot;0&amp;quot;)&lt;br /&gt;
      # Note1: The portname has to match the interface name of your board&lt;br /&gt;
      #        from /etc/gpib.conf!&lt;br /&gt;
      # Note2: boardId is the GPIB address *of your GPIB controller board*.&lt;br /&gt;
      #        The GPIB address of the _device_ itself is supplied to&lt;br /&gt;
      #        dbLoadRecords under step 3 below.&lt;br /&gt;
      # 2b TCP/IP socket: IPaddress:port&lt;br /&gt;
      #drvAsynIPPortConfigure(&amp;quot;IPPORT&amp;quot;,&amp;quot;192.168.0.1:6789&amp;quot;)&lt;br /&gt;
      # 2c Serial: &amp;quot;COM1&amp;quot;, 9600 bps, 8N1, flow contr.: XON/XOFF&lt;br /&gt;
      #drvAsynSerialPortConfigure (&amp;quot;SERIALPORT&amp;quot;, &amp;quot;/dev/ttyS0&amp;quot;, 0, 0, 0)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;baud&amp;quot;, &amp;quot;9600&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;bits&amp;quot;, &amp;quot;8&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;parity&amp;quot;, &amp;quot;none&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;stop&amp;quot;, &amp;quot;1&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;clocal&amp;quot;, &amp;quot;Y&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;crtscts&amp;quot;, &amp;quot;N&amp;quot;)&lt;br /&gt;
      # 2d vxi11: ...&lt;br /&gt;
 &lt;br /&gt;
      ## 3 Load record instances&lt;br /&gt;
      # Make sure you have your device's GPIB address right!&lt;br /&gt;
      dbLoadRecords(&amp;quot;db/yourdev.db&amp;quot;, &amp;quot;P=${IOC}:,PORT=L0,ADDR=2&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
      cd ${TOP}/iocBoot/${IOC}&lt;br /&gt;
      iocInit()&lt;br /&gt;
 &lt;br /&gt;
      ==============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 7: Build and test IOC ==&lt;br /&gt;
Finally run&lt;br /&gt;
      make&lt;br /&gt;
      cd iocBoot/iocgpib&lt;br /&gt;
      chmod +x st.cmd&lt;br /&gt;
      ./st.cmd&lt;br /&gt;
 &lt;br /&gt;
to get something like&lt;br /&gt;
 &lt;br /&gt;
 Starting iocInit&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 ## EPICS R3.14.9-3 $R3-14-9$ $2007/02/05 16:31:45$&lt;br /&gt;
 ## EPICS Base built Jan 17 2008&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 iocInit: All initialization complete&lt;br /&gt;
 epics&amp;gt; dbl&lt;br /&gt;
 iocgpib:currentStep&lt;br /&gt;
 iocgpib:setCurrentStep&lt;br /&gt;
 epics&amp;gt; dbpf iocgpib:currentStep.PROC 1&lt;br /&gt;
 DBR_UCHAR: 1 0x1&lt;br /&gt;
 epics&amp;gt; 2008/01/18 05:17:01.124 L0 addr 2 : device timed out.&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: Timeout after reading 17 &lt;br /&gt;
 bytes &amp;quot;-000.0007E-12ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: 4 bytes surplus input &amp;quot;ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: after 13 bytes: &amp;quot;-000.0007E-12&amp;quot;&lt;br /&gt;
 epics&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
The response here comes from my Keithley 6517A sitting at address 2 and &lt;br /&gt;
doesn't exactly match what we expect. In fact, not even our EOS terminator &lt;br /&gt;
setting is correct, that's why the device timeouts. With the exemplary &lt;br /&gt;
debugging information provided by StreamDevice at hand, it is a joy to &lt;br /&gt;
incrementally fix the &amp;quot;in&amp;quot; clauses in yourdev.proto to match what the device &lt;br /&gt;
_really_ sends. Here, the getCurrentStep protocol would need to be changed to &lt;br /&gt;
 &lt;br /&gt;
      Terminator = LF;&lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%fADC&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
You can reload the protocol in the iocsh via &amp;quot;streamReload&amp;quot;, either for one or &lt;br /&gt;
for all records. Without rebooting the IOC. Without any recompilation.&lt;br /&gt;
 &lt;br /&gt;
Once the protocol works, do a dbpf/caput iocgpib:currentStep.SCAN &amp;quot;.1 second&amp;quot; &lt;br /&gt;
to have your IOC poll the device regularly. Or even better, have the device &lt;br /&gt;
send out readings on its own if possible and parse them in a protocol run &lt;br /&gt;
from an record with .SCAN=&amp;quot;I/O Intr&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
StreamDevice offers a broad range of so called format converters (the &amp;quot;%f&amp;quot; in &lt;br /&gt;
the in clause of the getCurrentStep protocol in yourdev.proto). There's even &lt;br /&gt;
a regular expression string converter that you can use to parse your favorite &lt;br /&gt;
stock quote from a web page into an EPICS variable.&lt;br /&gt;
&lt;br /&gt;
-&amp;lt;i&amp;gt;Stefan Heim &amp;lt;tt&amp;gt;&amp;lt;sheim@bessy.de&amp;gt;&amp;lt;/tt&amp;gt;, Jan 18 2008&amp;lt;/i&amp;gt;&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1470</id>
		<title>How to use GPIB ports with linux-gpib and StreamDevice</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1470"/>
		<updated>2008-01-18T17:40:19Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Small improvements.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document evolved from a [[http://www.aps.anl.gov/epics/tech-talk/2008/msg00046.php|reply]] I sent to tech-talk to someone who was struggling with the setup of his GPIB device using devGpib.&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
The following instructions explain the setup of an EPICS softIOC to talk to a GPIB device on Linux.&lt;br /&gt;
&lt;br /&gt;
The instructions are based on Debian Linux, but should be easily adaptable to other flavors of Linux.&lt;br /&gt;
&lt;br /&gt;
= Prerequisites =&lt;br /&gt;
You need linux-gpib[http://linux-gpib.sourceforge.net/], EPICS base[http://www.aps.anl.gov/epics/base/R3-14/index.php], asyn[http://www.aps.anl.gov/epics/modules/soft/asyn/], and StreamDevice[http://epics.web.psi.ch/software/streamdevice/].&lt;br /&gt;
&lt;br /&gt;
== linux-gpib installation ==&lt;br /&gt;
On Debian, you can just do&lt;br /&gt;
      apt-get install gpib-modules-source module-assistant&lt;br /&gt;
      module-assistant auto-install gpib-modules-source&lt;br /&gt;
to build and install the kernel modules of the &amp;lt;tt&amp;gt;linux-gpib&amp;lt;/tt&amp;gt; driver for your kernel. Similarly, by issuing&lt;br /&gt;
      apt-get install libgpib0 libgpib0-dev libgpib-bin&lt;br /&gt;
you can install the user space part of &amp;lt;tt&amp;gt;linux-gpib&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
On other distributions, check for the availability of &amp;lt;tt&amp;gt;linux-gpib&amp;lt;/tt&amp;gt; packages. You can always resort to compiling linux-gpib youself. Refer to the linux-gpib documentation[http://linux-gpib.sourceforge.net/doc_html/index.html] for this.&lt;br /&gt;
&lt;br /&gt;
Once you have linux-gpib installed, it's time to configure your interface board. Assuming you have a single GPIB interface board in your machine, you'll need to&lt;br /&gt;
&lt;br /&gt;
* figure out the board type, i.e. find out what low-level driver from linux-gpib does support you board, e.g. &amp;lt;tt&amp;gt;ines_pci&amp;lt;/tt&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
* give the interface board an arbitrary name, e.g. &amp;lt;tt&amp;gt;L0&amp;lt;/tt&amp;gt;. You'll need to use this name as the first parameter to the &amp;lt;tt&amp;gt;GpibBoardDriverConfig&amp;lt;/tt&amp;gt; command in the &amp;lt;tt&amp;gt;st.cmd&amp;lt;/tt&amp;gt; of your softIOC later on. There seems to be a convention for the name to start with &amp;quot;L&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
To be able to use the interface board as &amp;lt;tt&amp;gt;/dev/gpib0&amp;lt;/tt&amp;gt;, put something like&lt;br /&gt;
&lt;br /&gt;
      interface {&lt;br /&gt;
              minor = 0       /* board index, minor = 0 is /dev/gpib0 */&lt;br /&gt;
              board_type = &amp;quot;ines_pci&amp;quot; /* type of interface board being used */&lt;br /&gt;
              name = &amp;quot;L0&amp;quot;     /* board name */&lt;br /&gt;
              pad = 0         /* primary address of interface */&lt;br /&gt;
              sad = 0         /* secondary address of interface */&lt;br /&gt;
              timeout = T3s   /* timeout for commands */&lt;br /&gt;
              eos = 0x0a      /* EOS Byte, 0xa is LF and 0xd is CR */&lt;br /&gt;
              set-reos = yes  /* Terminate read if EOS */&lt;br /&gt;
              set-bin = no    /* Compare EOS 8-bit */&lt;br /&gt;
              set-xeos = no   /* Assert EOI whenever EOS byte is sent */&lt;br /&gt;
              set-eot = yes   /* Assert EOI with last byte on writes */&lt;br /&gt;
              master = yes    /* interface board is system controller */&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
in &amp;lt;tt&amp;gt;/etc/gpib_conf&amp;lt;/tt&amp;gt;, load the kernel driver for your board&lt;br /&gt;
      modprobe ines_pci&lt;br /&gt;
and finally run&lt;br /&gt;
      gpib_config&lt;br /&gt;
&lt;br /&gt;
=== Verify connection to GPIB board ===&lt;br /&gt;
Verify you can talk to the board using &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
      sheim@txm1:~$ ibtest&lt;br /&gt;
      Do you wish to open a (d)evice or an interface (b)oard?&lt;br /&gt;
              (you probably want to open a device): b&lt;br /&gt;
      enter name of interface board (or device) you wish to open: L0&lt;br /&gt;
      trying to open board named 'L0'&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : l&lt;br /&gt;
      DAV off&lt;br /&gt;
      NDAC on&lt;br /&gt;
      NRFD off&lt;br /&gt;
      IFC off&lt;br /&gt;
      REN on&lt;br /&gt;
      SRQ off&lt;br /&gt;
      ATN off&lt;br /&gt;
      EOI on&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x164  &amp;lt; CMPL REM CIC LACS &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 0&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : q&lt;br /&gt;
      sheim@txm1:~$&lt;br /&gt;
&lt;br /&gt;
=== Verify connection to the GPIB device===&lt;br /&gt;
Assuming your device has GPIB address 2 and will answer to the command &amp;quot;:FETC?&amp;quot;, test it with &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt; like this:&lt;br /&gt;
&lt;br /&gt;
      sheim@brixen:~$ ibtest&lt;br /&gt;
      Do you wish to open a (d)evice or an interface (b)oard?&lt;br /&gt;
              (you probably want to open a device): d&lt;br /&gt;
      enter primary gpib address for device you wish to open [0-30]: 2&lt;br /&gt;
      trying to open pad = 2 on /dev/gpib0 ...&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : w&lt;br /&gt;
      enter a string to send to your device: :FETC?&lt;br /&gt;
      sending string: :FETC?&lt;br /&gt;
&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x2100  &amp;lt; END CMPL &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 7&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : r&lt;br /&gt;
      enter maximum number of bytes to read [1024]:&lt;br /&gt;
      trying to read 1024 bytes from device...&lt;br /&gt;
      received string: '-000.0003E-12ADC&lt;br /&gt;
      '&lt;br /&gt;
      Number of bytes read: 17&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x2100  &amp;lt; END CMPL &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 17&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : q&lt;br /&gt;
      sheim@brixen:~$&lt;br /&gt;
&lt;br /&gt;
If communication with the device works using &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt;, the setup of the softIOC is trivial if you stick to the 7-step recipe in section 3.&lt;br /&gt;
&lt;br /&gt;
== EPICS installation ==&lt;br /&gt;
Since I maintain Debian packages for EPICS base, all support modules and all extensions I use, here I just do:&lt;br /&gt;
&lt;br /&gt;
      apt-get install epics-base epics-support-asyn epics-support-streamdevice&lt;br /&gt;
&lt;br /&gt;
Until I find the time to publish my Debian EPICS archive (sid, lenny, etch, sarge and several Ubuntu versions available), or if you are using a different distribution anyway, you'll have to stick to compiling and installing EPICS base, asyn and StreamDevice yourself.&lt;br /&gt;
&lt;br /&gt;
= The softIOC =&lt;br /&gt;
Now it's time to set up the actual softIOC.&lt;br /&gt;
&lt;br /&gt;
== STEP 1: Create GPIB application ==&lt;br /&gt;
In a fresh and clean directory, do&lt;br /&gt;
      makeBaseApp.pl -t example gpib&lt;br /&gt;
      makeBaseApp.pl -t example -i -a linux-x86 -p gpib gpib&lt;br /&gt;
 &lt;br /&gt;
== STEP 2: Use asyn and StreamDevice support ==&lt;br /&gt;
Append to configure/RELEASE&lt;br /&gt;
      ASYN=/opt/epics/support/asyn&lt;br /&gt;
      STREAMS=/opt/epics/support/streamdevice&lt;br /&gt;
 &lt;br /&gt;
Make sure you have asyn and StreamDevice installed and supply the correct paths to your EPICS support directories.&lt;br /&gt;
 &lt;br /&gt;
== STEP 3: Create a protocol file ==&lt;br /&gt;
Create a protocol file&lt;br /&gt;
      gpibApp/Db/yourdev.proto&lt;br /&gt;
like this:&lt;br /&gt;
&lt;br /&gt;
      === gpibApp/Db/yourdev.proto ===&lt;br /&gt;
      Terminator = CR LF;&lt;br /&gt;
 &lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      setCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP %f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      ================================&lt;br /&gt;
 &lt;br /&gt;
 You might want to consult the SCPI command reference for your device and &lt;br /&gt;
 implement whatever part of the protocol you may need.&lt;br /&gt;
 &lt;br /&gt;
== STEP 4: Create a database ==&lt;br /&gt;
Create a database&lt;br /&gt;
      gpibApp/Db/yourdev.db&lt;br /&gt;
matching the protocol from STEP 3 like this:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/Db/yourdev.db ===&lt;br /&gt;
      record (ai, &amp;quot;$(P)currentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (INP,  &amp;quot;@yourdev.proto getCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      record (ao, &amp;quot;$(P)setCurrentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (OUT,  &amp;quot;@yourdev.proto setCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
      =============================&lt;br /&gt;
 &lt;br /&gt;
In order to register your database with the build system, add the line&lt;br /&gt;
      DB += yourdev.db&lt;br /&gt;
in the middle of&lt;br /&gt;
      gpibApp/Db/Makefile.&lt;br /&gt;
 &lt;br /&gt;
== STEP 5: Adapt application Makefile ==&lt;br /&gt;
Have&lt;br /&gt;
      gpibApp/src/Makefile&lt;br /&gt;
read:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/src/Makefile ===&lt;br /&gt;
      TOP=../..&lt;br /&gt;
      include $(TOP)/configure/CONFIG&lt;br /&gt;
 &lt;br /&gt;
      # build an ioc application&lt;br /&gt;
      PROD_IOC = gpib&lt;br /&gt;
      PROD_LIBS += asyn&lt;br /&gt;
      PROD_LIBS += stream&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be created and installed&lt;br /&gt;
      DBD += gpib.dbd&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be made up from these files:&lt;br /&gt;
      gpib_DBD += base.dbd&lt;br /&gt;
      gpib_DBD += asyn.dbd&lt;br /&gt;
      gpib_DBD += drvAsynIPPort.dbd&lt;br /&gt;
      gpib_DBD += drvAsynSerialPort.dbd&lt;br /&gt;
      gpib_DBD += drvLinuxGpib.dbd&lt;br /&gt;
      gpib_DBD += stream.dbd&lt;br /&gt;
 &lt;br /&gt;
      # softIOC house-keeping&lt;br /&gt;
      gpib_SRCS += gpib_registerRecordDeviceDriver.cpp&lt;br /&gt;
      gpib_SRCS_DEFAULT += gpibMain.cpp&lt;br /&gt;
      gpib_LIBS += $(EPICS_BASE_IOC_LIBS)&lt;br /&gt;
 &lt;br /&gt;
      include $(TOP)/configure/RULES&lt;br /&gt;
      ============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 6: Create an IOC startup script ==&lt;br /&gt;
Have the IOC's st.cmd look like this:&lt;br /&gt;
 &lt;br /&gt;
      === iocBoot/iocgpib/st.cmd ===&lt;br /&gt;
      #!../../bin/linux-x86/gpib&lt;br /&gt;
 &lt;br /&gt;
      &amp;lt; envPaths&lt;br /&gt;
      epicsEnvSet(STREAM_PROTOCOL_PATH, &amp;quot;../../gpibApp/Db&amp;quot;)&lt;br /&gt;
      cd ${TOP}&lt;br /&gt;
 &lt;br /&gt;
      ## 1 Register all support components&lt;br /&gt;
      dbLoadDatabase(&amp;quot;dbd/gpib.dbd&amp;quot;)&lt;br /&gt;
      gpib_registerRecordDeviceDriver(pdbbase)&lt;br /&gt;
 &lt;br /&gt;
      ## 2 Configure your asynPorts&lt;br /&gt;
      # 2a GPIB: portname, autoConnect, boardId, timeout, 5th_arg&lt;br /&gt;
      GpibBoardDriverConfig(&amp;quot;L0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;3&amp;quot;, &amp;quot;0&amp;quot;)&lt;br /&gt;
      # Note1: The portname has to match the interface name of your board&lt;br /&gt;
      #        from /etc/gpib.conf!&lt;br /&gt;
      # Note2: boardId is the GPIB address *of your GPIB controller board*.&lt;br /&gt;
      #        The GPIB address of the _device_ itself is supplied to&lt;br /&gt;
      #        dbLoadRecords under step 3 below.&lt;br /&gt;
      # 2b TCP/IP socket: IPaddress:port&lt;br /&gt;
      #drvAsynIPPortConfigure(&amp;quot;IPPORT&amp;quot;,&amp;quot;192.168.0.1:6789&amp;quot;)&lt;br /&gt;
      # 2c Serial: &amp;quot;COM1&amp;quot;, 9600 bps, 8N1, flow contr.: XON/XOFF&lt;br /&gt;
      #drvAsynSerialPortConfigure (&amp;quot;SERIALPORT&amp;quot;, &amp;quot;/dev/ttyS0&amp;quot;, 0, 0, 0)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;baud&amp;quot;, &amp;quot;9600&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;bits&amp;quot;, &amp;quot;8&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;parity&amp;quot;, &amp;quot;none&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;stop&amp;quot;, &amp;quot;1&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;clocal&amp;quot;, &amp;quot;Y&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;crtscts&amp;quot;, &amp;quot;N&amp;quot;)&lt;br /&gt;
      # 2d vxi11: ...&lt;br /&gt;
 &lt;br /&gt;
      ## 3 Load record instances&lt;br /&gt;
      # Make sure you have your device's GPIB address right!&lt;br /&gt;
      dbLoadRecords(&amp;quot;db/yourdev.db&amp;quot;, &amp;quot;P=${IOC}:,PORT=L0,ADDR=2&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
      cd ${TOP}/iocBoot/${IOC}&lt;br /&gt;
      iocInit()&lt;br /&gt;
 &lt;br /&gt;
      ==============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 7: Build and test IOC ==&lt;br /&gt;
Finally run&lt;br /&gt;
      make&lt;br /&gt;
      cd iocBoot/iocgpib&lt;br /&gt;
      chmod +x st.cmd&lt;br /&gt;
      ./st.cmd&lt;br /&gt;
 &lt;br /&gt;
to get something like&lt;br /&gt;
 &lt;br /&gt;
 Starting iocInit&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 ## EPICS R3.14.9-3 $R3-14-9$ $2007/02/05 16:31:45$&lt;br /&gt;
 ## EPICS Base built Jan 17 2008&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 iocInit: All initialization complete&lt;br /&gt;
 epics&amp;gt; dbl&lt;br /&gt;
 iocgpib:currentStep&lt;br /&gt;
 iocgpib:setCurrentStep&lt;br /&gt;
 epics&amp;gt; dbpf iocgpib:currentStep.PROC 1&lt;br /&gt;
 DBR_UCHAR: 1 0x1&lt;br /&gt;
 epics&amp;gt; 2008/01/18 05:17:01.124 L0 addr 2 : device timed out.&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: Timeout after reading 17 &lt;br /&gt;
 bytes &amp;quot;-000.0007E-12ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: 4 bytes surplus input &amp;quot;ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: after 13 bytes: &amp;quot;-000.0007E-12&amp;quot;&lt;br /&gt;
 epics&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
The response here comes from my Keithley 6517A sitting at address 2 and &lt;br /&gt;
doesn't exactly match what we expect. In fact, not even our EOS terminator &lt;br /&gt;
setting is correct, that's why the device timeouts. With the exemplary &lt;br /&gt;
debugging information provided by StreamDevice at hand, it is a joy to &lt;br /&gt;
incrementally fix the &amp;quot;in&amp;quot; clauses in yourdev.proto to match what the device &lt;br /&gt;
_really_ sends. Here, the getCurrentStep protocol would need to be changed to &lt;br /&gt;
 &lt;br /&gt;
      Terminator = LF;&lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%fADC&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
You can reload the protocol in the iocsh via &amp;quot;streamReload&amp;quot;, either for one or &lt;br /&gt;
for all records. Without rebooting the IOC. Without any recompilation.&lt;br /&gt;
 &lt;br /&gt;
Once the protocol works, do a dbpf/caput iocgpib:currentStep.SCAN &amp;quot;.1 second&amp;quot; &lt;br /&gt;
to have your IOC poll the device regularly. Or even better, have the device &lt;br /&gt;
send out readings on its own if possible and parse them in a protocol run &lt;br /&gt;
from an record with .SCAN=&amp;quot;I/O Intr&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
StreamDevice offers a broad range of so called format converters (the &amp;quot;%f&amp;quot; in &lt;br /&gt;
the in clause of the getCurrentStep protocol in yourdev.proto). There's even &lt;br /&gt;
a regular expression string converter that you can use to parse your favorite &lt;br /&gt;
stock quote from a web page into an EPICS variable.&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1469</id>
		<title>How to use GPIB ports with linux-gpib and StreamDevice</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1469"/>
		<updated>2008-01-18T17:08:48Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Elaborate on low-level setup&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document evolved from a [[http://www.aps.anl.gov/epics/tech-talk/2008/msg00046.php|reply]] I sent to tech-talk to someone who was struggling with the setup of his GPIB device using devGpib.&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
The following instructions explain the setup of an EPICS softIOC to talk to a GPIB device on Linux.&lt;br /&gt;
&lt;br /&gt;
The instructions are based on Debian Linux, but should be easily adaptable to other flavors of Linux.&lt;br /&gt;
&lt;br /&gt;
= Prerequisites =&lt;br /&gt;
You need linux-gpib[http://linux-gpib.sourceforge.net/], epics-base[http://www.aps.anl.gov/epics/base/R3-14/index.php], asyn[http://www.aps.anl.gov/epics/modules/soft/asyn/], and StreamDevice[http://epics.web.psi.ch/software/streamdevice/].&lt;br /&gt;
&lt;br /&gt;
== linux-gpib installation ==&lt;br /&gt;
On Debian, you can just do&lt;br /&gt;
      apt-get install gpib-modules-source module-assistant&lt;br /&gt;
      module-assistant auto-install gpib-modules-source&lt;br /&gt;
to build and install the kernel modules of the linux-gpib driver for your kernel. Similarly, by issuing&lt;br /&gt;
      apt-get install libgpib0 libgpib0-dev libgpib-bin&lt;br /&gt;
you can install the user space part of linux-gpib.&lt;br /&gt;
&lt;br /&gt;
On other distributions, check for the availability of linux-gpib packages. You can always resort to compiling linux-gpib youself. Refer to the linux-gpib documentation[http://linux-gpib.sourceforge.net/doc_html/index.html] for this.&lt;br /&gt;
&lt;br /&gt;
Once you have linux-gpib installed, it's time to configure your interface board. Assuming you have a single GPIB interface board in your machine, you'll need to&lt;br /&gt;
&lt;br /&gt;
* figure out the board type, i.e. find out what low-level driver from linux-gpib does support you board, e.g. &amp;lt;tt&amp;gt;ines_pci&amp;lt;/tt&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
* give the interface board an arbitrary name, e.g. &amp;lt;tt&amp;gt;L0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To be able to use the interface board as &amp;lt;tt&amp;gt;/dev/gpib0&amp;lt;/tt&amp;gt;, put something like&lt;br /&gt;
&lt;br /&gt;
      interface {&lt;br /&gt;
              minor = 0       /* board index, minor = 0 is /dev/gpib0 */&lt;br /&gt;
              board_type = &amp;quot;ines_pci&amp;quot; /* type of interface board being used */&lt;br /&gt;
              name = &amp;quot;L0&amp;quot;     /* board name */&lt;br /&gt;
              pad = 0         /* primary address of interface */&lt;br /&gt;
              sad = 0         /* secondary address of interface */&lt;br /&gt;
              timeout = T3s   /* timeout for commands */&lt;br /&gt;
              eos = 0x0a      /* EOS Byte, 0xa is LF and 0xd is CR */&lt;br /&gt;
              set-reos = yes  /* Terminate read if EOS */&lt;br /&gt;
              set-bin = no    /* Compare EOS 8-bit */&lt;br /&gt;
              set-xeos = no   /* Assert EOI whenever EOS byte is sent */&lt;br /&gt;
              set-eot = yes   /* Assert EOI with last byte on writes */&lt;br /&gt;
              master = yes    /* interface board is system controller */&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
in &amp;lt;tt&amp;gt;/etc/gpib_conf&amp;lt;/tt&amp;gt;, load the kernel driver for your board&lt;br /&gt;
      modprobe ines_pci&lt;br /&gt;
and finally run&lt;br /&gt;
      gpib_config&lt;br /&gt;
&lt;br /&gt;
=== Verify connection to GPIB board ===&lt;br /&gt;
Verify you can talk to the board using &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
      sheim@txm1:~$ ibtest&lt;br /&gt;
      Do you wish to open a (d)evice or an interface (b)oard?&lt;br /&gt;
              (you probably want to open a device): b&lt;br /&gt;
      enter name of interface board (or device) you wish to open: L0&lt;br /&gt;
      trying to open board named 'L0'&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : l&lt;br /&gt;
      DAV off&lt;br /&gt;
      NDAC on&lt;br /&gt;
      NRFD off&lt;br /&gt;
      IFC off&lt;br /&gt;
      REN on&lt;br /&gt;
      SRQ off&lt;br /&gt;
      ATN off&lt;br /&gt;
      EOI on&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x164  &amp;lt; CMPL REM CIC LACS &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 0&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : q&lt;br /&gt;
      sheim@txm1:~$&lt;br /&gt;
&lt;br /&gt;
=== Verify connection to the GPIB device===&lt;br /&gt;
Assuming your device has GPIB address 2 and will answer to the command &amp;quot;:FETC?&amp;quot;, test it with &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt; like this:&lt;br /&gt;
&lt;br /&gt;
      sheim@brixen:~$ ibtest&lt;br /&gt;
      Do you wish to open a (d)evice or an interface (b)oard?&lt;br /&gt;
              (you probably want to open a device): d&lt;br /&gt;
      enter primary gpib address for device you wish to open [0-30]: 2&lt;br /&gt;
      trying to open pad = 2 on /dev/gpib0 ...&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : w&lt;br /&gt;
      enter a string to send to your device: :FETC?&lt;br /&gt;
      sending string: :FETC?&lt;br /&gt;
&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x2100  &amp;lt; END CMPL &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 7&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : r&lt;br /&gt;
      enter maximum number of bytes to read [1024]:&lt;br /&gt;
      trying to read 1024 bytes from device...&lt;br /&gt;
      received string: '-000.0003E-12ADC&lt;br /&gt;
      '&lt;br /&gt;
      Number of bytes read: 17&lt;br /&gt;
      gpib status is:&lt;br /&gt;
      ibsta = 0x2100  &amp;lt; END CMPL &amp;gt;&lt;br /&gt;
      iberr= 0&lt;br /&gt;
&lt;br /&gt;
      ibcnt = 17&lt;br /&gt;
      You can:&lt;br /&gt;
              w(a)it for an event&lt;br /&gt;
              write (c)ommand bytes to bus (system controller only)&lt;br /&gt;
              send (d)evice clear (device only)&lt;br /&gt;
              change remote (e)nable line (system controller only)&lt;br /&gt;
              (g)o to standby (release ATN line, system controller only)&lt;br /&gt;
              send (i)nterface clear (system controller only)&lt;br /&gt;
              ta(k)e control (assert ATN line, system controller only)&lt;br /&gt;
              get bus (l)ine status (board only)&lt;br /&gt;
              go to local (m)ode&lt;br /&gt;
              change end (o)f transmission configuration&lt;br /&gt;
              (q)uit&lt;br /&gt;
              (r)ead string&lt;br /&gt;
              perform (s)erial poll (device only)&lt;br /&gt;
              change (t)imeout on io operations&lt;br /&gt;
              request ser(v)ice (board only)&lt;br /&gt;
              (w)rite data string&lt;br /&gt;
      : q&lt;br /&gt;
      sheim@brixen:~$&lt;br /&gt;
&lt;br /&gt;
If communication with the device works using &amp;lt;tt&amp;gt;ibtest&amp;lt;/tt&amp;gt;, the setup of the softIOC is trivial if you stick to the 7-step recipe in section 3.&lt;br /&gt;
&lt;br /&gt;
== EPICS installation ==&lt;br /&gt;
Since I maintain Debian packages for EPICS base, all support modules and all extensions I use, here I just do:&lt;br /&gt;
&lt;br /&gt;
      apt-get install epics-base epics-support-asyn epics-support-streamdevice&lt;br /&gt;
&lt;br /&gt;
Until I find the time to publish my Debian EPICS archive (sid, lenny, etch, sarge and several Ubuntu versions available), or if you are using a different distribution anyway, you'll have to stick to compiling and installing yourself.&lt;br /&gt;
&lt;br /&gt;
= The softIOC =&lt;br /&gt;
Now it's time to set up the actual softIOC.&lt;br /&gt;
&lt;br /&gt;
== STEP 1: Create GPIB application ==&lt;br /&gt;
In a fresh and clean directory, do&lt;br /&gt;
      makeBaseApp.pl -t example gpib&lt;br /&gt;
      makeBaseApp.pl -t example -i -a linux-x86 -p gpib gpib&lt;br /&gt;
 &lt;br /&gt;
== STEP 2: Use asyn and StreamDevice support ==&lt;br /&gt;
Append to configure/RELEASE&lt;br /&gt;
      ASYN=/opt/epics/support/asyn&lt;br /&gt;
      STREAMS=/opt/epics/support/streamdevice&lt;br /&gt;
 &lt;br /&gt;
Make sure you have asyn and StreamDevice installed and supply the correct paths to your EPICS support directories.&lt;br /&gt;
 &lt;br /&gt;
== STEP 3: Create a protocol file ==&lt;br /&gt;
Create a protocol file&lt;br /&gt;
      gpibApp/Db/yourdev.proto&lt;br /&gt;
like this:&lt;br /&gt;
&lt;br /&gt;
      === gpibApp/Db/yourdev.proto ===&lt;br /&gt;
      Terminator = CR LF;&lt;br /&gt;
 &lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      setCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP %f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      ================================&lt;br /&gt;
 &lt;br /&gt;
 You might want to consult the SCPI command reference for your device and &lt;br /&gt;
 implement whatever part of the protocol you may need.&lt;br /&gt;
 &lt;br /&gt;
== STEP 4: Create a database ==&lt;br /&gt;
Create a database&lt;br /&gt;
      gpibApp/Db/yourdev.db&lt;br /&gt;
matching the protocol from STEP 3 like this:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/Db/yourdev.db ===&lt;br /&gt;
      record (ai, &amp;quot;$(P)currentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (INP,  &amp;quot;@yourdev.proto getCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      record (ao, &amp;quot;$(P)setCurrentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (OUT,  &amp;quot;@yourdev.proto setCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
      =============================&lt;br /&gt;
 &lt;br /&gt;
In order to register your database with the build system, add the line&lt;br /&gt;
      DB += yourdev.db&lt;br /&gt;
in the middle of&lt;br /&gt;
      gpibApp/Db/Makefile.&lt;br /&gt;
 &lt;br /&gt;
== STEP 5: Adapt application Makefile ==&lt;br /&gt;
Have&lt;br /&gt;
      gpibApp/src/Makefile&lt;br /&gt;
read:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/src/Makefile ===&lt;br /&gt;
      TOP=../..&lt;br /&gt;
      include $(TOP)/configure/CONFIG&lt;br /&gt;
 &lt;br /&gt;
      # build an ioc application&lt;br /&gt;
      PROD_IOC = gpib&lt;br /&gt;
      PROD_LIBS += asyn&lt;br /&gt;
      PROD_LIBS += stream&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be created and installed&lt;br /&gt;
      DBD += gpib.dbd&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be made up from these files:&lt;br /&gt;
      gpib_DBD += base.dbd&lt;br /&gt;
      gpib_DBD += asyn.dbd&lt;br /&gt;
      gpib_DBD += drvAsynIPPort.dbd&lt;br /&gt;
      gpib_DBD += drvAsynSerialPort.dbd&lt;br /&gt;
      gpib_DBD += drvLinuxGpib.dbd&lt;br /&gt;
      gpib_DBD += stream.dbd&lt;br /&gt;
 &lt;br /&gt;
      # softIOC house-keeping&lt;br /&gt;
      gpib_SRCS += gpib_registerRecordDeviceDriver.cpp&lt;br /&gt;
      gpib_SRCS_DEFAULT += gpibMain.cpp&lt;br /&gt;
      gpib_LIBS += $(EPICS_BASE_IOC_LIBS)&lt;br /&gt;
 &lt;br /&gt;
      include $(TOP)/configure/RULES&lt;br /&gt;
      ============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 6: Create an IOC startup script ==&lt;br /&gt;
Have the IOC's st.cmd look like this:&lt;br /&gt;
 &lt;br /&gt;
      === iocBoot/iocgpib/st.cmd ===&lt;br /&gt;
      #!../../bin/linux-x86/gpib&lt;br /&gt;
 &lt;br /&gt;
      &amp;lt; envPaths&lt;br /&gt;
      epicsEnvSet(STREAM_PROTOCOL_PATH, &amp;quot;../../gpibApp/Db&amp;quot;)&lt;br /&gt;
      cd ${TOP}&lt;br /&gt;
 &lt;br /&gt;
      ## 1 Register all support components&lt;br /&gt;
      dbLoadDatabase(&amp;quot;dbd/gpib.dbd&amp;quot;)&lt;br /&gt;
      gpib_registerRecordDeviceDriver(pdbbase)&lt;br /&gt;
 &lt;br /&gt;
      ## 2 Configure your asynPorts&lt;br /&gt;
      # 2a GPIB: portname, autoConnect, boardId, timeout, 5th_arg&lt;br /&gt;
      GpibBoardDriverConfig(&amp;quot;L0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;3&amp;quot;, &amp;quot;0&amp;quot;)&lt;br /&gt;
      # Note: boardId is the GPIB address *of your GPIB controller board*. The&lt;br /&gt;
      # GPIB address of the _device_ is supplied to dbLoadRecords in step 3.&lt;br /&gt;
      # 2b TCP/IP socket:&lt;br /&gt;
      #drvAsynIPPortConfigure(&amp;quot;IPPORT&amp;quot;,&amp;quot;192.168.0.1:6789&amp;quot;)&lt;br /&gt;
      # 2c Serial: &amp;quot;COM1&amp;quot;, 9600 bps, 8N1, flow contr.: XON/XOFF&lt;br /&gt;
      #drvAsynSerialPortConfigure (&amp;quot;SERIALPORT&amp;quot;, &amp;quot;/dev/ttyS0&amp;quot;, 0, 0, 0)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;baud&amp;quot;, &amp;quot;9600&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;bits&amp;quot;, &amp;quot;8&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;parity&amp;quot;, &amp;quot;none&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;stop&amp;quot;, &amp;quot;1&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;clocal&amp;quot;, &amp;quot;Y&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;crtscts&amp;quot;, &amp;quot;N&amp;quot;)&lt;br /&gt;
      # 2d vxi11: ...&lt;br /&gt;
 &lt;br /&gt;
      ## 3 Load record instances&lt;br /&gt;
      # make sure you have your device's GPIB address right!&lt;br /&gt;
      dbLoadRecords(&amp;quot;db/yourdev.db&amp;quot;, &amp;quot;P=${IOC}:,PORT=L0,ADDR=2&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
      cd ${TOP}/iocBoot/${IOC}&lt;br /&gt;
      iocInit()&lt;br /&gt;
 &lt;br /&gt;
      ==============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 7: Build and test IOC ==&lt;br /&gt;
Finally run&lt;br /&gt;
      make&lt;br /&gt;
      cd iocBoot/iocgpib&lt;br /&gt;
      chmod +x st.cmd&lt;br /&gt;
      ./st.cmd&lt;br /&gt;
 &lt;br /&gt;
to get something like&lt;br /&gt;
 &lt;br /&gt;
 Starting iocInit&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 ## EPICS R3.14.9-3 $R3-14-9$ $2007/02/05 16:31:45$&lt;br /&gt;
 ## EPICS Base built Jan 17 2008&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 iocInit: All initialization complete&lt;br /&gt;
 epics&amp;gt; dbl&lt;br /&gt;
 iocgpib:currentStep&lt;br /&gt;
 iocgpib:setCurrentStep&lt;br /&gt;
 epics&amp;gt; dbpf iocgpib:currentStep.PROC 1&lt;br /&gt;
 DBR_UCHAR: 1 0x1&lt;br /&gt;
 epics&amp;gt; 2008/01/18 05:17:01.124 L0 addr 2 : device timed out.&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: Timeout after reading 17 &lt;br /&gt;
 bytes &amp;quot;-000.0007E-12ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: 4 bytes surplus input &amp;quot;ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: after 13 bytes: &amp;quot;-000.0007E-12&amp;quot;&lt;br /&gt;
 epics&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
The response here comes from my Keithley 6517A sitting at address 2 and &lt;br /&gt;
doesn't exactly match what we expect. In fact, not even our EOS terminator &lt;br /&gt;
setting is correct, that's why the device timeouts. With the exemplary &lt;br /&gt;
debugging information provided by StreamDevice at hand, it is a joy to &lt;br /&gt;
incrementally fix the &amp;quot;in&amp;quot; clauses in yourdev.proto to match what the device &lt;br /&gt;
_really_ sends. Here, the getCurrentStep protocol would need to be changed to &lt;br /&gt;
 &lt;br /&gt;
      Terminator = LF;&lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%fADC&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
You can reload the protocol in the iocsh via &amp;quot;streamReload&amp;quot;, either for one or &lt;br /&gt;
for all records. Without rebooting the IOC. Without any recompilation.&lt;br /&gt;
 &lt;br /&gt;
Once the protocol works, do a dbpf/caput iocgpib:currentStep.SCAN &amp;quot;.1 second&amp;quot; &lt;br /&gt;
to have your IOC poll the device regularly. Or even better, have the device &lt;br /&gt;
send out readings on its own if possible and parse them in a protocol run &lt;br /&gt;
from an record with .SCAN=&amp;quot;I/O Intr&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
StreamDevice offers a broad range of so called format converters (the &amp;quot;%f&amp;quot; in &lt;br /&gt;
the in clause of the getCurrentStep protocol in yourdev.proto). There's even &lt;br /&gt;
a regular expression string converter that you can use to parse your favorite &lt;br /&gt;
stock quote from a web page into an EPICS variable.&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=HowTo_Documents&amp;diff=1595</id>
		<title>HowTo Documents</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=HowTo_Documents&amp;diff=1595"/>
		<updated>2008-01-18T15:40:38Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Add link to linux-gpib howto page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a directory of various How-To documents written by members of the EPICS collaboration.  Contributions to this page are most welcome!&lt;br /&gt;
&lt;br /&gt;
=== EPICS Base on Different Architectures and Operating Systems ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.aps.anl.gov/epics/base/RTEMS/tutorial/ Getting Started with EPICS on RTEMS]&lt;br /&gt;
* [[HowToPC104|Getting Started with R3.14.7 on a PC104 running Linux]]&lt;br /&gt;
* [[How To Port EPICS to a new OS/Architecture]]&lt;br /&gt;
&lt;br /&gt;
=== Drivers and Device Support ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/R4-8/tutorial.html How To Do Serial (using Asyn Driver)]&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/BeginnerGuideToASYN-VXI11.pdf Beginners Guide to using VXI-11 (with Asyn Driver)]&lt;br /&gt;
* [[How to make your EPICS driver operating system independent]]&lt;br /&gt;
* [[How To Write Device Support that uses Asyn Driver]] ''(Incomplete!)''&lt;br /&gt;
* [[How to use GPIB ports with linux-gpib and StreamDevice]]&lt;br /&gt;
&lt;br /&gt;
=== Applications ===&lt;br /&gt;
&lt;br /&gt;
* [[How To Install Channel Archiver On Scientific Linux]]&lt;br /&gt;
* [[What PV Save and Restore Tools are available]]&lt;br /&gt;
&lt;br /&gt;
=== Infrastructure and Other Stuff ===&lt;br /&gt;
&lt;br /&gt;
* [[How To Set Up a Linux Box as an IOC Boot Server]]&lt;br /&gt;
* [[How To Set Up a Mirror of the EPICS Web Site]]&lt;br /&gt;
* [[How to Set Up a Soft IOC Framework on Linux]]&lt;br /&gt;
* [[How to Set Up Console Access and Logging for VME and Soft IOCs]]&lt;br /&gt;
* [[How to Set Up NAL (Nagios Alarm Handler) to monitor an EPICS network]]&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1468</id>
		<title>How to use GPIB ports with linux-gpib and StreamDevice</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1468"/>
		<updated>2008-01-18T15:39:11Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== STEP 1: Create GPIB application ==&lt;br /&gt;
In a fresh and clean directory, do&lt;br /&gt;
      makeBaseApp.pl -t example gpib&lt;br /&gt;
      makeBaseApp.pl -t example -i -a linux-x86 -p gpib gpib&lt;br /&gt;
 &lt;br /&gt;
== STEP 2: Use asyn and StreamDevice support ==&lt;br /&gt;
Append to configure/RELEASE&lt;br /&gt;
      ASYN=/opt/epics/support/asyn&lt;br /&gt;
      STREAMS=/opt/epics/support/streamdevice&lt;br /&gt;
 &lt;br /&gt;
Make sure you have asyn and StreamDevice installed and supply the correct paths to your EPICS support directories.&lt;br /&gt;
 &lt;br /&gt;
== STEP 3: Create a protocol file ==&lt;br /&gt;
Create a protocol file&lt;br /&gt;
      gpibApp/Db/yourdev.proto&lt;br /&gt;
like this:&lt;br /&gt;
&lt;br /&gt;
      === gpibApp/Db/yourdev.proto ===&lt;br /&gt;
      Terminator = CR LF;&lt;br /&gt;
 &lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      setCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP %f&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      ================================&lt;br /&gt;
 &lt;br /&gt;
 You might want to consult the SCPI command reference for your device and &lt;br /&gt;
 implement whatever part of the protocol you may need.&lt;br /&gt;
 &lt;br /&gt;
== STEP 4: Create a database ==&lt;br /&gt;
Create a database&lt;br /&gt;
      gpibApp/Db/yourdev.db&lt;br /&gt;
matching the protocol from STEP 3 like this:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/Db/yourdev.db ===&lt;br /&gt;
      record (ai, &amp;quot;$(P)currentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (INP,  &amp;quot;@yourdev.proto getCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      record (ao, &amp;quot;$(P)setCurrentStep&amp;quot;)&lt;br /&gt;
      {&lt;br /&gt;
              field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
              field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
              field (OUT,  &amp;quot;@yourdev.proto setCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
      }&lt;br /&gt;
      =============================&lt;br /&gt;
 &lt;br /&gt;
In order to register your database with the build system, add the line&lt;br /&gt;
      DB += yourdev.db&lt;br /&gt;
in the middle of&lt;br /&gt;
      gpibApp/Db/Makefile.&lt;br /&gt;
 &lt;br /&gt;
== STEP 5: Adapt application Makefile ==&lt;br /&gt;
Have&lt;br /&gt;
      gpibApp/src/Makefile&lt;br /&gt;
read:&lt;br /&gt;
 &lt;br /&gt;
      === gpibApp/src/Makefile ===&lt;br /&gt;
      TOP=../..&lt;br /&gt;
      include $(TOP)/configure/CONFIG&lt;br /&gt;
 &lt;br /&gt;
      # build an ioc application&lt;br /&gt;
      PROD_IOC = gpib&lt;br /&gt;
      PROD_LIBS += asyn&lt;br /&gt;
      PROD_LIBS += stream&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be created and installed&lt;br /&gt;
      DBD += gpib.dbd&lt;br /&gt;
 &lt;br /&gt;
      # gpib.dbd will be made up from these files:&lt;br /&gt;
      gpib_DBD += base.dbd&lt;br /&gt;
      gpib_DBD += asyn.dbd&lt;br /&gt;
      gpib_DBD += drvAsynIPPort.dbd&lt;br /&gt;
      gpib_DBD += drvAsynSerialPort.dbd&lt;br /&gt;
      gpib_DBD += drvLinuxGpib.dbd&lt;br /&gt;
      gpib_DBD += stream.dbd&lt;br /&gt;
 &lt;br /&gt;
      # softIOC house-keeping&lt;br /&gt;
      gpib_SRCS += gpib_registerRecordDeviceDriver.cpp&lt;br /&gt;
      gpib_SRCS_DEFAULT += gpibMain.cpp&lt;br /&gt;
      gpib_LIBS += $(EPICS_BASE_IOC_LIBS)&lt;br /&gt;
 &lt;br /&gt;
      include $(TOP)/configure/RULES&lt;br /&gt;
      ============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 6: Create an IOC startup script ==&lt;br /&gt;
Have the IOC's st.cmd look like this:&lt;br /&gt;
 &lt;br /&gt;
      === iocBoot/iocgpib/st.cmd ===&lt;br /&gt;
      #!../../bin/linux-x86/gpib&lt;br /&gt;
 &lt;br /&gt;
      &amp;lt; envPaths&lt;br /&gt;
      epicsEnvSet(STREAM_PROTOCOL_PATH, &amp;quot;../../gpibApp/Db&amp;quot;)&lt;br /&gt;
      cd ${TOP}&lt;br /&gt;
 &lt;br /&gt;
      ## 1 Register all support components&lt;br /&gt;
      dbLoadDatabase(&amp;quot;dbd/gpib.dbd&amp;quot;)&lt;br /&gt;
      gpib_registerRecordDeviceDriver(pdbbase)&lt;br /&gt;
 &lt;br /&gt;
      ## 2 Configure your asynPorts&lt;br /&gt;
      # 2a GPIB: portname, autoConnect, boardId, timeout, 5th_arg&lt;br /&gt;
      GpibBoardDriverConfig(&amp;quot;L0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;3&amp;quot;, &amp;quot;0&amp;quot;)&lt;br /&gt;
      # Note: boardId is the GPIB address *of your GPIB controller board*. The&lt;br /&gt;
      # GPIB address of the _device_ is supplied to dbLoadRecords in step 3.&lt;br /&gt;
      # 2b TCP/IP socket:&lt;br /&gt;
      #drvAsynIPPortConfigure(&amp;quot;IPPORT&amp;quot;,&amp;quot;192.168.0.1:6789&amp;quot;)&lt;br /&gt;
      # 2c Serial: &amp;quot;COM1&amp;quot;, 9600 bps, 8N1, flow contr.: XON/XOFF&lt;br /&gt;
      #drvAsynSerialPortConfigure (&amp;quot;SERIALPORT&amp;quot;, &amp;quot;/dev/ttyS0&amp;quot;, 0, 0, 0)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;baud&amp;quot;, &amp;quot;9600&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;bits&amp;quot;, &amp;quot;8&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;parity&amp;quot;, &amp;quot;none&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;stop&amp;quot;, &amp;quot;1&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;clocal&amp;quot;, &amp;quot;Y&amp;quot;)&lt;br /&gt;
      #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;crtscts&amp;quot;, &amp;quot;N&amp;quot;)&lt;br /&gt;
      # 2d vxi11: ...&lt;br /&gt;
 &lt;br /&gt;
      ## 3 Load record instances&lt;br /&gt;
      # make sure you have your device's GPIB address right!&lt;br /&gt;
      dbLoadRecords(&amp;quot;db/yourdev.db&amp;quot;, &amp;quot;P=${IOC}:,PORT=L0,ADDR=2&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
      cd ${TOP}/iocBoot/${IOC}&lt;br /&gt;
      iocInit()&lt;br /&gt;
 &lt;br /&gt;
      ==============================&lt;br /&gt;
 &lt;br /&gt;
== STEP 7: Build and test IOC ==&lt;br /&gt;
Finally run&lt;br /&gt;
      make&lt;br /&gt;
      cd iocBoot/iocgpib&lt;br /&gt;
      chmod +x st.cmd&lt;br /&gt;
      ./st.cmd&lt;br /&gt;
 &lt;br /&gt;
to get something like&lt;br /&gt;
 &lt;br /&gt;
 Starting iocInit&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 ## EPICS R3.14.9-3 $R3-14-9$ $2007/02/05 16:31:45$&lt;br /&gt;
 ## EPICS Base built Jan 17 2008&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 iocInit: All initialization complete&lt;br /&gt;
 epics&amp;gt; dbl&lt;br /&gt;
 iocgpib:currentStep&lt;br /&gt;
 iocgpib:setCurrentStep&lt;br /&gt;
 epics&amp;gt; dbpf iocgpib:currentStep.PROC 1&lt;br /&gt;
 DBR_UCHAR: 1 0x1&lt;br /&gt;
 epics&amp;gt; 2008/01/18 05:17:01.124 L0 addr 2 : device timed out.&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: Timeout after reading 17 &lt;br /&gt;
 bytes &amp;quot;-000.0007E-12ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: 4 bytes surplus input &amp;quot;ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: after 13 bytes: &amp;quot;-000.0007E-12&amp;quot;&lt;br /&gt;
 epics&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
The response here comes from my Keithley 6517A sitting at address 2 and &lt;br /&gt;
doesn't exactly match what we expect. In fact, not even our EOS terminator &lt;br /&gt;
setting is correct, that's why the device timeouts. With the exemplary &lt;br /&gt;
debugging information provided by StreamDevice at hand, it is a joy to &lt;br /&gt;
incrementally fix the &amp;quot;in&amp;quot; clauses in yourdev.proto to match what the device &lt;br /&gt;
_really_ sends. Here, the getCurrentStep protocol would need to be changed to &lt;br /&gt;
 &lt;br /&gt;
      Terminator = LF;&lt;br /&gt;
      getCurrentStep {&lt;br /&gt;
              out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
              in &amp;quot;%fADC&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
You can reload the protocol in the iocsh via &amp;quot;streamReload&amp;quot;, either for one or &lt;br /&gt;
for all records. Without rebooting the IOC. Without any recompilation.&lt;br /&gt;
 &lt;br /&gt;
Once the protocol works, do a dbpf/caput iocgpib:currentStep.SCAN &amp;quot;.1 second&amp;quot; &lt;br /&gt;
to have your IOC poll the device regularly. Or even better, have the device &lt;br /&gt;
send out readings on its own if possible and parse them in a protocol run &lt;br /&gt;
from an record with .SCAN=&amp;quot;I/O Intr&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
StreamDevice offers a broad range of so called format converters (the &amp;quot;%f&amp;quot; in &lt;br /&gt;
the in clause of the getCurrentStep protocol in yourdev.proto). There's even &lt;br /&gt;
a regular expression string converter that you can use to parse your favorite &lt;br /&gt;
stock quote from a web page into an EPICS variable.&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1466</id>
		<title>How to use GPIB ports with linux-gpib and StreamDevice</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_use_GPIB_ports_with_linux-gpib_and_StreamDevice&amp;diff=1466"/>
		<updated>2008-01-18T13:55:02Z</updated>

		<summary type="html">&lt;p&gt;StefanHeim: Started linux-gpib HowTo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;STEP 1: In a fresh and clean directory, do&lt;br /&gt;
 makeBaseApp.pl -t example gpib&lt;br /&gt;
 makeBaseApp.pl -t example -i -a linux-x86 -p gpib gpib&lt;br /&gt;
 &lt;br /&gt;
 STEP 2: Append to configure/RELEASE&lt;br /&gt;
 ASYN=/opt/epics/support/asyn&lt;br /&gt;
 STREAMS=/opt/epics/support/streamdevice&lt;br /&gt;
 &lt;br /&gt;
 Make sure you have asyn and StreamDevice installed and supply the correct &lt;br /&gt;
 paths to your EPICS support directories.&lt;br /&gt;
 &lt;br /&gt;
 STEP 3: Create a protocol file, gpibApp/Db/yourdev.proto, like this:&lt;br /&gt;
 &lt;br /&gt;
 === gpibApp/Db/yourdev.proto ===&lt;br /&gt;
 Terminator = CR LF;&lt;br /&gt;
 &lt;br /&gt;
 getCurrentStep {&lt;br /&gt;
         out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
 in &amp;quot;%f&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 setCurrentStep {&lt;br /&gt;
 out &amp;quot;:CURR:STEP %f&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 ================================&lt;br /&gt;
 &lt;br /&gt;
 You might want to consult the SCPI command reference for your device and &lt;br /&gt;
 implement whatever part of the protocol you may need.&lt;br /&gt;
 &lt;br /&gt;
 STEP 4: Create a database, gpibApp/Db/yourdev.db, matching the protocol like &lt;br /&gt;
 this:&lt;br /&gt;
 &lt;br /&gt;
 === gpibApp/Db/yourdev.db ===&lt;br /&gt;
 record (ai, &amp;quot;$(P)currentStep&amp;quot;)&lt;br /&gt;
 {&lt;br /&gt;
         field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
         field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
         field (INP, &amp;quot;@yourdev.proto getCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 record (ao, &amp;quot;$(P)setCurrentStep&amp;quot;)&lt;br /&gt;
 {&lt;br /&gt;
         field (SCAN, &amp;quot;Passive&amp;quot;)&lt;br /&gt;
         field (DTYP, &amp;quot;stream&amp;quot;)&lt;br /&gt;
         field (OUT, &amp;quot;@yourdev.proto setCurrentStep $(PORT) $(ADDR)&amp;quot;)&lt;br /&gt;
 }&lt;br /&gt;
 =============================&lt;br /&gt;
 &lt;br /&gt;
 STEP 5: In order to register your database with the build system, add the line&lt;br /&gt;
 DB += yourdev.db&lt;br /&gt;
 in the middle of gpibApp/Db/Makefile.&lt;br /&gt;
 &lt;br /&gt;
 STEP 6: Have gpibApp/src/Makefile read:&lt;br /&gt;
 &lt;br /&gt;
 === gpibApp/src/Makefile ===&lt;br /&gt;
 TOP=../..&lt;br /&gt;
 include $(TOP)/configure/CONFIG&lt;br /&gt;
 &lt;br /&gt;
 # build an ioc application&lt;br /&gt;
 PROD_IOC = gpib&lt;br /&gt;
 PROD_LIBS += asyn&lt;br /&gt;
 PROD_LIBS += stream&lt;br /&gt;
 &lt;br /&gt;
 # gpib.dbd will be created and installed&lt;br /&gt;
 DBD += gpib.dbd&lt;br /&gt;
 &lt;br /&gt;
 # gpib.dbd will be made up from these files:&lt;br /&gt;
 gpib_DBD += base.dbd&lt;br /&gt;
 gpib_DBD += asyn.dbd&lt;br /&gt;
 gpib_DBD += drvAsynIPPort.dbd&lt;br /&gt;
 gpib_DBD += drvAsynSerialPort.dbd&lt;br /&gt;
 gpib_DBD += drvLinuxGpib.dbd&lt;br /&gt;
 gpib_DBD += stream.dbd&lt;br /&gt;
 &lt;br /&gt;
 # softIOC house-keeping&lt;br /&gt;
 gpib_SRCS += gpib_registerRecordDeviceDriver.cpp&lt;br /&gt;
 gpib_SRCS_DEFAULT += gpibMain.cpp&lt;br /&gt;
 gpib_LIBS += $(EPICS_BASE_IOC_LIBS)&lt;br /&gt;
 &lt;br /&gt;
 include $(TOP)/configure/RULES&lt;br /&gt;
 ============================&lt;br /&gt;
 &lt;br /&gt;
 STEP 7: Have the IOC's st.cmd look like this:&lt;br /&gt;
 &lt;br /&gt;
 === iocBoot/iocgpib/st.cmd ===&lt;br /&gt;
 #!../../bin/linux-x86/gpib&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt; envPaths&lt;br /&gt;
 epicsEnvSet(STREAM_PROTOCOL_PATH, &amp;quot;../../gpibApp/Db&amp;quot;)&lt;br /&gt;
 cd ${TOP}&lt;br /&gt;
 &lt;br /&gt;
 ## 1 Register all support components&lt;br /&gt;
 dbLoadDatabase(&amp;quot;dbd/gpib.dbd&amp;quot;)&lt;br /&gt;
 gpib_registerRecordDeviceDriver(pdbbase)&lt;br /&gt;
 &lt;br /&gt;
 ## 2 Configure your asynPorts&lt;br /&gt;
 # 2a GPIB: portname, autoConnect, boardId, timeout, 5th_arg&lt;br /&gt;
 GpibBoardDriverConfig(&amp;quot;L0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;3&amp;quot;, &amp;quot;0&amp;quot;)&lt;br /&gt;
 # Note: boardId is the GPIB address *of your GPIB controller board*. The&lt;br /&gt;
 # GPIB address of the _device_ is supplied to dbLoadRecords in step 3.&lt;br /&gt;
 # 2b TCP/IP socket:&lt;br /&gt;
 #drvAsynIPPortConfigure(&amp;quot;IPPORT&amp;quot;,&amp;quot;192.168.0.1:6789&amp;quot;)&lt;br /&gt;
 # 2c Serial: &amp;quot;COM1&amp;quot;, 9600 bps, 8N1, flow contr.: XON/XOFF&lt;br /&gt;
 #drvAsynSerialPortConfigure (&amp;quot;SERIALPORT&amp;quot;, &amp;quot;/dev/ttyS0&amp;quot;, 0, 0, 0)&lt;br /&gt;
 #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;baud&amp;quot;, &amp;quot;9600&amp;quot;)&lt;br /&gt;
 #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;bits&amp;quot;, &amp;quot;8&amp;quot;)&lt;br /&gt;
 #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;parity&amp;quot;, &amp;quot;none&amp;quot;)&lt;br /&gt;
 #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;stop&amp;quot;, &amp;quot;1&amp;quot;)&lt;br /&gt;
 #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;clocal&amp;quot;, &amp;quot;Y&amp;quot;)&lt;br /&gt;
 #asynSetOption (&amp;quot;SERIALPORT&amp;quot;, 0, &amp;quot;crtscts&amp;quot;, &amp;quot;N&amp;quot;)&lt;br /&gt;
 # 2d vxi11: ...&lt;br /&gt;
 &lt;br /&gt;
 ## 3 Load record instances&lt;br /&gt;
 # make sure you have your device's GPIB address right!&lt;br /&gt;
 dbLoadRecords(&amp;quot;db/yourdev.db&amp;quot;, &amp;quot;P=${IOC}:,PORT=L0,ADDR=2&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
 cd ${TOP}/iocBoot/${IOC}&lt;br /&gt;
 iocInit()&lt;br /&gt;
 &lt;br /&gt;
 ==============================&lt;br /&gt;
 &lt;br /&gt;
 STEP 8: Finally run&lt;br /&gt;
 make&lt;br /&gt;
 cd iocBoot/iocgpib&lt;br /&gt;
 chmod +x st.cmd&lt;br /&gt;
 ./st.cmd&lt;br /&gt;
 &lt;br /&gt;
 to get something like&lt;br /&gt;
 &lt;br /&gt;
 ===&lt;br /&gt;
 Starting iocInit&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 ## EPICS R3.14.9-3 $R3-14-9$ $2007/02/05 16:31:45$&lt;br /&gt;
 ## EPICS Base built Jan 17 2008&lt;br /&gt;
 ############################################################################&lt;br /&gt;
 iocInit: All initialization complete&lt;br /&gt;
 epics&amp;gt; dbl&lt;br /&gt;
 iocgpib:currentStep&lt;br /&gt;
 iocgpib:setCurrentStep&lt;br /&gt;
 epics&amp;gt; dbpf iocgpib:currentStep.PROC 1&lt;br /&gt;
 DBR_UCHAR: 1 0x1&lt;br /&gt;
 epics&amp;gt; 2008/01/18 05:17:01.124 L0 addr 2 : device timed out.&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: Timeout after reading 17 &lt;br /&gt;
 bytes &amp;quot;-000.0007E-12ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: 4 bytes surplus input &amp;quot;ADC&amp;lt;0a&amp;gt;&amp;quot;&lt;br /&gt;
 2008/01/18 05:17:01.125 iocgpib:currentStep: after 13 bytes: &amp;quot;-000.0007E-12&amp;quot;&lt;br /&gt;
 epics&amp;gt; &lt;br /&gt;
 ===&lt;br /&gt;
 &lt;br /&gt;
 The response here comes from my Keithley 6517A sitting at address 2 and &lt;br /&gt;
 doesn't exactly match what we expect. In fact, not even our EOS terminator &lt;br /&gt;
 setting is correct, that's why the device timeouts. With the exemplary &lt;br /&gt;
 debugging information provided by StreamDevice at hand, it is a joy to &lt;br /&gt;
 incrementally fix the &amp;quot;in&amp;quot; clauses in yourdev.proto to match what the device &lt;br /&gt;
 _really_ sends. Here, the getCurrentStep protocol would need to be changed to &lt;br /&gt;
 &lt;br /&gt;
 Terminator = LF;&lt;br /&gt;
 getCurrentStep {&lt;br /&gt;
         out &amp;quot;:CURR:STEP?&amp;quot;;&lt;br /&gt;
 in &amp;quot;%fADC&amp;quot;;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 You can reload the protocol in the iocsh via &amp;quot;streamReload&amp;quot;, either for one or &lt;br /&gt;
 for all records. Without rebooting the IOC. Without any recompilation.&lt;br /&gt;
 &lt;br /&gt;
 Once the protocol works, do a dbpf/caput iocgpib:currentStep.SCAN &amp;quot;.1 second&amp;quot; &lt;br /&gt;
 to have your IOC poll the device regularly. Or even better, have the device &lt;br /&gt;
 send out readings on its own if possible and parse them in a protocol run &lt;br /&gt;
 from an record with .SCAN=&amp;quot;I/O Intr&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
 StreamDevice offers a broad range of so called format converters (the &amp;quot;%f&amp;quot; in &lt;br /&gt;
 the in clause of the getCurrentStep protocol in yourdev.proto). There's even &lt;br /&gt;
 a regular expression string converter that you can use to parse your favorite &lt;br /&gt;
 stock quote from a web page into an EPICS variable.&lt;/div&gt;</summary>
		<author><name>StefanHeim</name></author>
	</entry>
</feed>