How to use GPIB ports with linux-gpib and StreamDevice

From EPICSWIKI
Revision as of 13:55, 18 January 2008 by StefanHeim (talk | contribs) (Started linux-gpib HowTo)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

STEP 1: 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: 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, 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, gpibApp/Db/yourdev.db, matching the protocol 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)")
}
=============================

STEP 5: In order to register your database with the build system, add the line
DB += yourdev.db
in the middle of gpibApp/Db/Makefile.

STEP 6: 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 7: 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")
# Note: boardId is the GPIB address *of your GPIB controller board*. The
# GPIB address of the _device_ is supplied to dbLoadRecords in step 3.
# 2b TCP/IP socket:
#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 8: 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.