Difference between revisions of "How to use GPIB ports with linux-gpib and StreamDevice"
StefanHeim (talk | contribs) (Started linux-gpib HowTo) |
StefanHeim (talk | contribs) |
||
Line 1: | Line 1: | ||
STEP 1: In a fresh and clean directory, do | == 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") | |||
# 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 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 157: | ||
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. |
Revision as of 15:39, 18 January 2008
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") # 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 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.