Draft version. The following package is designed to be used with the [L1 ] GPIB-Tcl package, to aid the use of GPIB devices that use the Standard Commands for Programmable Instrumentation (SCPI) language [L2 ]. The following code was tested on Windows XP system, with a National Instruments [L3 ] PCI GPIB IEEE-488.2 interface card. The SCPI package was written for a project using three Agilent [L4 ] (was HP) instruments, two 34401A multimeters and a 33220A 20Mhz Function/Arbitrary Waveform Generator. The project is now complete and I no-longer have access to the hardware, so cannot test it on a wider range of instruments. The basic idea was to hide the details of the IEEE SCPI register model from the user. Each SCPI command is wrapped in scpi::cmdSend with commands to clear status and error flags and the OPeration Complete command *OPC, which sets the operation complete flag when all preceding commands are complete. This allows scpi::cmdRead to poll the device for completion, without blocking.
Here is the code:
# scpi.tcl -- # # This file implements routines built on top of the tcl-gpib # library. It provides a simple interface to IEEE-488.2 # instruments that use the Standard Commands for Programmable # Instruments (SCPI) language. # # $Id: 14780,v 1.12 2005-12-22 07:00:30 jcw Exp $ # # Change log: # $log$ # package require gpib # package provide scpi 0.1 # SCPI class of commands # Declare namespace. namespace eval scpi { namespace export * variable cpoll variable data } # scpi::cmd -- # # Send (write) a SCPI command to a IEEE-488 instrument # Arguments: # id The id handle for the instrument returned by the gpib open # command. # message The SCPI or IEEE command string # Results: # code OK. # # Example: # scp::cmdSend $id "*rst" ; # Reset instrument # scp::cmdSend $id "SYST:ERR?" ; # Get error from instr. # proc scpi::cmdSend { id message } { variable data gpib clear -device $id # Clear status, Set event register, flush OPC gpib write -device $id -message "*CLS;*ESE 61;*OPC?" set res [ gpib read -device $id ] # Write command+OPC. gpib write -device $id -message "$message;*OPC" set data($id,message) $message return -code ok } # scpi::cmdRead -- # # Perform serialpolls until standard event or time-out. # on Time-out: # Return error with errorInfo. # On standard event: # Check for message in message buffer and read. # Check for Error flags in standard event register # if errors read syst:err? into buffer # return error with errorInfo # else # return data if any. # # Arguments: # id The id handle for the instrument returned by the gpib open # command # # ?tlimit? Optional time limit on serialpoll operations. # ?tpoll? Optional time between serialpoll operations. # # Results: # Code OK # Value data read from instrument if any. # Code ERROR # Value null. # errorInfo Error message and command trace. proc scpi::cmdRead { id {tlimit 2000} {tpoll 100} } { variable cpoll variable data set cpoll(0) 0 # Wait for Standard event OPC set time 0 set cpoll($id) 0 while { ([set res [gpib serialpoll -device $id]] & 0x20 ) != 0x20 } { # puts "Poll: $res" if { $time < $tlimit} { # after $tpoll after $tpoll [list incr ::scpi::cpoll($id) ] if {![info exists tk_version] } { vwait ::scpi::cpoll($id) } else { tkwait variable ::scpi::cpoll($id) } incr time $tpoll } else { set result "Time-out after ${tlimit}ms waiting for Standard Event \ (Operation complete or Error)" return -code error -errorinfo $result } } # Check Message AVailable (MAV) and read Message buffer set result {} while { ([set res [gpib serialpoll -device $id]] & 0x10 ) == 0x10 } { lappend result [ gpib read ] } # Check event register gpib write -device $id -message "*ESR?" set sevent [ gpib read -device $id ] # Check for error bits in Standard event register # if { ( $sevent & 60 ) != 0 } { lappend result $sevent # Get system error gpib write -device $id -message "SYST:ERR?" set serror [ gpib read -device $id ] lappend result $data($id,message) $serror return -code error -errorinfo $result } return -code ok $result } # scpi::cmd -- # # Combines scpi::cmdSend and scpicmdRead in one call. # # Arguments: # id The id handle for the instrument returned by the gpib open # command. # message The SCPI or IEEE command string # # ?tlimit? Optional time limit on serialpoll operations. # ?tpoll? Optional time between serialpoll operations. # # Results: # Code OK # Value data read from instrument if any. # Code ERROR # Value null. # errorInfo Error message and command trace. proc scpi::cmd { id message {tlimit 2000} {tpoll 100} } { cmdSend $id $message cmdRead $id $tlimit $tpoll } # scpi::cmdList -- # # Execute a list of scpi commands on an instrument. # # Arguments: # id The id handle for the instrument returned by the gpib open # command. # mlist A Tcl list of SCPI commands # # ?tlimit? Optional time limit on serialpoll operations. # ?tpoll? Optional time between serialpoll operations. # Results: # Code OK # Value list of data read from instrument if any. # Code ERROR # Value null. # errorInfo Error message and command trace. proc scpi::cmdList { id lmess {tlimit 2000} {tpoll 100} } { global errorInfo set result {} foreach Cmd $lmess { if {[catch {cmd $id $Cmd $tlimit $tpoll} val ] != 0} { set saveInfo $errorInfo error {} $saveInfo return -code error } else { lappend result $val } } return -code ok $result } Simple example of usage:- package require gpib package require scpi # open the GPIB device set dvm1 [gpib open -address 22 -sendeoi true ] # Request a measurement from the DVM. # Wait upto 2 seconds and poll for completion every 200ms. scpi::cmd $dvm1 "meas?" 2000 200 # List of commands to configure DVM. set instrument(dvm1,conf) [list "*RST" \ "*CLS" \ "CONF:VOLT:AC DEF,DEF " \ "DET:BAND 3" \ "TRIG:SOUR IMM"] ; # execute list of commands. scpi::cmdList $dvm1 $instrument(dvm1,conf) more to add here, async usage. # close device gpib close -device $dvm1