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