Difference between revisions of "How to use GPIB ports with linux-gpib and StreamDevice"

From EPICSWIKI
(Started linux-gpib HowTo)
 
Line 1: Line 1:
STEP 1: In a fresh and clean directory, do
== STEP 1: Create GPIB application ==
makeBaseApp.pl -t example gpib
In a fresh and clean directory, do
makeBaseApp.pl -t example -i -a linux-x86 -p gpib gpib
      makeBaseApp.pl -t example gpib
      makeBaseApp.pl -t example -i -a linux-x86 -p gpib gpib
   
   
STEP 2: Append to configure/RELEASE
== STEP 2: Use asyn and StreamDevice support ==
ASYN=/opt/epics/support/asyn
Append to configure/RELEASE
STREAMS=/opt/epics/support/streamdevice
      ASYN=/opt/epics/support/asyn
      STREAMS=/opt/epics/support/streamdevice
   
   
Make sure you have asyn and StreamDevice installed and supply the correct  
Make sure you have asyn and StreamDevice installed and supply the correct paths to your EPICS support directories.
paths to your EPICS support directories.
   
   
STEP 3: Create a protocol file, gpibApp/Db/yourdev.proto, like this:
== STEP 3: Create a protocol file ==
Create a protocol file
      gpibApp/Db/yourdev.proto
like this:
 
      === gpibApp/Db/yourdev.proto ===
      Terminator = CR LF;
   
   
=== gpibApp/Db/yourdev.proto ===
      getCurrentStep {
Terminator = CR LF;
              out ":CURR:STEP?";
              in "%f";
      }
   
   
getCurrentStep {
      setCurrentStep {
        out ":CURR:STEP?";
              out ":CURR:STEP %f";
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, gpibApp/Db/yourdev.db, matching the protocol like  
== STEP 4: Create a database ==
this:
Create a database
      gpibApp/Db/yourdev.db
matching the protocol from STEP 3 like this:
   
   
=== gpibApp/Db/yourdev.db ===
      === gpibApp/Db/yourdev.db ===
record (ai, "$(P)currentStep")
      record (ai, "$(P)currentStep")
{
      {
        field (SCAN, "Passive")
              field (SCAN, "Passive")
        field (DTYP, "stream")
              field (DTYP, "stream")
        field (INP, "@yourdev.proto getCurrentStep $(PORT) $(ADDR)")
              field (INP, "@yourdev.proto getCurrentStep $(PORT) $(ADDR)")
}
      }
   
   
record (ao, "$(P)setCurrentStep")
      record (ao, "$(P)setCurrentStep")
{
      {
        field (SCAN, "Passive")
              field (SCAN, "Passive")
        field (DTYP, "stream")
              field (DTYP, "stream")
        field (OUT, "@yourdev.proto setCurrentStep $(PORT) $(ADDR)")
              field (OUT, "@yourdev.proto setCurrentStep $(PORT) $(ADDR)")
}
      }
=============================
      =============================
   
   
STEP 5: In order to register your database with the build system, add the line
In order to register your database with the build system, add the line
DB += yourdev.db
      DB += yourdev.db
in the middle of gpibApp/Db/Makefile.
in the middle of
      gpibApp/Db/Makefile.
   
   
STEP 6: Have gpibApp/src/Makefile read:
== STEP 5: Adapt application Makefile ==
Have
      gpibApp/src/Makefile
read:
   
   
=== gpibApp/src/Makefile ===
      === gpibApp/src/Makefile ===
TOP=../..
      TOP=../..
include $(TOP)/configure/CONFIG
      include $(TOP)/configure/CONFIG
   
   
# build an ioc application
      # build an ioc application
PROD_IOC = gpib
      PROD_IOC = gpib
PROD_LIBS += asyn
      PROD_LIBS += asyn
PROD_LIBS += stream
      PROD_LIBS += stream
   
   
# gpib.dbd will be created and installed
      # gpib.dbd will be created and installed
DBD += gpib.dbd
      DBD += gpib.dbd
   
   
# gpib.dbd will be made up from these files:
      # gpib.dbd will be made up from these files:
gpib_DBD += base.dbd
      gpib_DBD += base.dbd
gpib_DBD += asyn.dbd
      gpib_DBD += asyn.dbd
gpib_DBD += drvAsynIPPort.dbd
      gpib_DBD += drvAsynIPPort.dbd
gpib_DBD += drvAsynSerialPort.dbd
      gpib_DBD += drvAsynSerialPort.dbd
gpib_DBD += drvLinuxGpib.dbd
      gpib_DBD += drvLinuxGpib.dbd
gpib_DBD += stream.dbd
      gpib_DBD += stream.dbd
   
   
# softIOC house-keeping
      # softIOC house-keeping
gpib_SRCS += gpib_registerRecordDeviceDriver.cpp
      gpib_SRCS += gpib_registerRecordDeviceDriver.cpp
gpib_SRCS_DEFAULT += gpibMain.cpp
      gpib_SRCS_DEFAULT += gpibMain.cpp
gpib_LIBS += $(EPICS_BASE_IOC_LIBS)
      gpib_LIBS += $(EPICS_BASE_IOC_LIBS)
   
   
include $(TOP)/configure/RULES
      include $(TOP)/configure/RULES
============================
      ============================
   
   
STEP 7: Have the IOC's st.cmd look like this:
== STEP 6: Create an IOC startup script ==
Have the IOC's st.cmd look like this:
   
   
=== iocBoot/iocgpib/st.cmd ===
      === iocBoot/iocgpib/st.cmd ===
#!../../bin/linux-x86/gpib
      #!../../bin/linux-x86/gpib
   
   
< envPaths
      < envPaths
epicsEnvSet(STREAM_PROTOCOL_PATH, "../../gpibApp/Db")
      epicsEnvSet(STREAM_PROTOCOL_PATH, "../../gpibApp/Db")
cd ${TOP}
      cd ${TOP}
   
   
## 1 Register all support components
      ## 1 Register all support components
dbLoadDatabase("dbd/gpib.dbd")
      dbLoadDatabase("dbd/gpib.dbd")
gpib_registerRecordDeviceDriver(pdbbase)
      gpib_registerRecordDeviceDriver(pdbbase)
   
   
## 2 Configure your asynPorts
      ## 2 Configure your asynPorts
# 2a GPIB: portname, autoConnect, boardId, timeout, 5th_arg
      # 2a GPIB: portname, autoConnect, boardId, timeout, 5th_arg
GpibBoardDriverConfig("L0", "1", "0", "3", "0")
      GpibBoardDriverConfig("L0", "1", "0", "3", "0")
# Note: boardId is the GPIB address *of your GPIB controller board*. The
      # Note: boardId is the GPIB address *of your GPIB controller board*. The
# GPIB address of the _device_ is supplied to dbLoadRecords in step 3.
      # GPIB address of the _device_ is supplied to dbLoadRecords in step 3.
# 2b TCP/IP socket:
      # 2b TCP/IP socket:
#drvAsynIPPortConfigure("IPPORT","192.168.0.1:6789")
      #drvAsynIPPortConfigure("IPPORT","192.168.0.1:6789")
# 2c Serial: "COM1", 9600 bps, 8N1, flow contr.: XON/XOFF
      # 2c Serial: "COM1", 9600 bps, 8N1, flow contr.: XON/XOFF
#drvAsynSerialPortConfigure ("SERIALPORT", "/dev/ttyS0", 0, 0, 0)
      #drvAsynSerialPortConfigure ("SERIALPORT", "/dev/ttyS0", 0, 0, 0)
#asynSetOption ("SERIALPORT", 0, "baud", "9600")
      #asynSetOption ("SERIALPORT", 0, "baud", "9600")
#asynSetOption ("SERIALPORT", 0, "bits", "8")
      #asynSetOption ("SERIALPORT", 0, "bits", "8")
#asynSetOption ("SERIALPORT", 0, "parity", "none")
      #asynSetOption ("SERIALPORT", 0, "parity", "none")
#asynSetOption ("SERIALPORT", 0, "stop", "1")
      #asynSetOption ("SERIALPORT", 0, "stop", "1")
#asynSetOption ("SERIALPORT", 0, "clocal", "Y")
      #asynSetOption ("SERIALPORT", 0, "clocal", "Y")
#asynSetOption ("SERIALPORT", 0, "crtscts", "N")
      #asynSetOption ("SERIALPORT", 0, "crtscts", "N")
# 2d vxi11: ...
      # 2d vxi11: ...
   
   
## 3 Load record instances
      ## 3 Load record instances
# make sure you have your device's GPIB address right!
      # make sure you have your device's GPIB address right!
dbLoadRecords("db/yourdev.db", "P=${IOC}:,PORT=L0,ADDR=2")
      dbLoadRecords("db/yourdev.db", "P=${IOC}:,PORT=L0,ADDR=2")
   
   
cd ${TOP}/iocBoot/${IOC}
      cd ${TOP}/iocBoot/${IOC}
iocInit()
      iocInit()
   
   
==============================
      ==============================
   
   
STEP 8: Finally run
== STEP 7: Build and test IOC ==
make
Finally run
cd iocBoot/iocgpib
      make
chmod +x st.cmd
      cd iocBoot/iocgpib
./st.cmd
      chmod +x st.cmd
      ./st.cmd
   
   
to get something like
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  
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  
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  
setting is correct, that's why the device timeouts. With the exemplary  
debugging information provided by StreamDevice at hand, it is a joy to  
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  
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  
_really_ sends. Here, the getCurrentStep protocol would need to be changed to  
   
   
Terminator = LF;
      Terminator = LF;
getCurrentStep {
      getCurrentStep {
        out ":CURR:STEP?";
              out ":CURR:STEP?";
in "%fADC";
              in "%fADC";
}
      }
   
   
You can reload the protocol in the iocsh via "streamReload", either for one or  
You can reload the protocol in the iocsh via "streamReload", either for one or  
for all records. Without rebooting the IOC. Without any recompilation.
for all records. Without rebooting the IOC. Without any recompilation.
   
   
Once the protocol works, do a dbpf/caput iocgpib:currentStep.SCAN ".1 second"  
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  
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  
send out readings on its own if possible and parse them in a protocol run  
from an record with .SCAN="I/O Intr".
from an record with .SCAN="I/O Intr".
   
   
StreamDevice offers a broad range of so called format converters (the "%f" in  
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  
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  
a regular expression string converter that you can use to parse your favorite  
stock quote from a web page into an EPICS variable.
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.