Getting Started

Introduction

tclvisais a standard Tcl extension providing a binding to Virtual Instrument Software Architecture (VISA ) API. It allows to use VISA functionality from regular Tcl scripts via set of commands. Most of the commands have similar names and are intuitive to use for the one who knows VISA API. For example, Tcl command visa::open is a front-end for viOpen VISA function. The specifications of VISA can be found here:

http://www.ivifoundation.org/specifications/default.aspx.

As an extention tclvisafollows conventions of Tcl Extension Architecture (TEA). It is loaded dynamically into Tcl shell or Tcl-based application on demand. Please refer to TEA documentations for details:

http://www.tcl.tk/doc/tea/.

Installation

Prior to usage of tclvisaone need VISA implementation installed. There are several known implementations (e.g. National Instruments VISA, or Agilent IO Library Suite). VISA libraries should be installed in proper directories and be available for linking.

tclvisaitself should be installed as a typical Tcl extension. Partcular details of installation, such as target directory, are platform-dependent. Please refer to the documentation of your Tcl version.

If you have no access to system directories to install tclvisainto, you can install into arbitrary directory. In order to make Tcl known about this directory, you should add path to it to TCLLIBPATH environment variable.

Installation in Microsoft Windows

Binary instalation package for Microsoft Windows can be downloaded from tclvisasite. This package contains DLL with compiled library code, documentation and demo scripts. All downloads can be found here:

http://sourceforge.net/projects/tclvisa/files/.

Use in Tcl

In order to start using tclvisawithin Tcl one should issue following command:

package require tclvisa

If the library is properly installed, this command returns version of tclvisaloaded. Library is ready to use. All commands and predefined variables are placed in visa:: namespace.

Programming with tclvisa

VISA Constants

VISA defines a lot of predefined contants with codes of attributes, errors etc. Most of these constants are available in Tcl within visa namespace and without VI_ prefix.

For example, VI_EXCLUSIVE_LOCK constant is represented by visa::EXCLUSIVE_LOCK variable in Tcl. When using these predefined variables in expressions, do not forget adding $ prefix prior to variable name.

Following example demonstrates usage of predefined constant:

# open instrument exclusively
set vi [visa::open $rm "ASRL2::INSTR" $visa::EXCLUSIVE_LOCK]

Channels

Most of VISA functions operate with sessions which are represented in C language by viSession type. In Tcl these sessions are stored in standard channels. E.g. visa::open returns name of Tcl channel to be used in subsequent operations. This approach has following benefits:

tclvisaprovides a procedure to open VISA sessions: visa::open, which is a front-end of viOpen VISA function. But tclvisadoes not provide front-ends for viClose or viWrite VISA functions. Instead one should use standard Tcl commands, such as close or puts. Tcl detects type of the channel and calls proper VISA function internally. For example, when close is issued on VISA channel, opened by visa::open, then viClose function is actually called within Tcl internals.

Following example demonstrates usage of VISA channel:

# open instrument
set vi [visa::open $rm "ASRL2::INSTR"]

# send "reset" command to instrument
puts $vi "*RST"

# close VISA session
close $vi

See also table of correspondence between supported VISA functions and Tcl commands.

Buffering

VISA IO functions, such as viWrite or viRead, by default work with messages, where message is a sequence of bytes of arbitrary length followed by special “end-of-message” character. For example, SCPI messages end with “new line” character (ASCII code is 0Ah). When I send a message terminated by “end-of-message” via viWrite, I can be sure that it is actually sent to the device rather than kept in intermediate buffer. When I call viRead, it returns immediately after receiving of “end-of-message” character regardless of the length of input buffer.

Tcl channels by default work with continuous streams of bytes. IO functions typically block until IO buffer is full or “end-of-data” is detected. For example, read command called without a buffer length specified on file channel blocks until entire file is read. It’s evident that this approach does not work with message-based protocols like SCPI.

Fortunately Tcl offers different buffering options, which can be set or red by fconfigure command. One of them is “-buffering line” which tells Tcl finish current IO operation when “end-of-line” character is received or sent. When buffering type is “line”, read blocks until “end-of-line” is received, and puts actually sends data right after “end-of-line” is found in outcoming data. In the terms or SCPI commands, read blocks until complete response is received from a device.

When VISA channel is created by visa::open, buffering type is automatically set to “line”. If one needs to switch channel mode, then fconfigure command with proper -buffering option should be issued.

IO Timeouts

In VISA API IO message communication timeouts can be specified or read by viSetAttribute and viGetAttribute functions where attribute parameter is set to VI_ATTR_TMO_VALUE.

In tclvisatimeout can be controlled in similar way via visa::set-attribute and visa::get-attribute commands. But preferred and more laconic approach is to use fconfigure Tcl command with standard -timeout option. Look at the example below:

# open an instrument
set vi [visa::open $rm "ASRL1::INSTR"]

# read current timeout value
set tm [fconfigure $vi -timeout]

# set new timeout value
fconfigure $vi -timeout [expr 2 * $tm]

In this example we read current timeout value, then set a new value that is twice the original one.

Inside the tclvisathese invocations of fconfigure are converted to corresponding calls of viGetAttribute and viSetAttribute VISA API functions.

Non-blocking IO

Standard Tcl channels have a -blocking option which “determines whether I/O operations on the channel can cause the process to block indefinitely” (quote from the fconfigure manual).

VISA API does not support non-blocking IO natively, probably because it offers asynchronous operations for that. In tclvisanon-blocking IO is emulated by setting IO timeout to zero.

I.e. when user sets a VISA channel to non-blocking mode by fconfigure command with -blocking 0 option, tclvisainternally sets IO timeout for this channel to zero. When channel is reverted back to the blocking mode (that is the default state for all VISA channels), timeout is restored to the previous value.

See also “Suppressed Errors” section.

Anynchronous IO

Tcl fileevent command cannot be called upon VISA channel. This functionality is not implemented yet.

Support of viWriteAsync and viReadAsync VISA API functions is not implemented too.

Serial-Specific Options

When a standard Tcl channel is backed by a serial port, it has a set of specific options that control baud speed, parity etc.

VISA instruments which are connected to the serial port (their addresses start with ASRL prefix) have full set of corresponding attributes, such as VI_ATTR_ASRL_BAUD, VI_ATTR_ASRL_PARITY and similar. In order to configure, for instance, baud rate one can use visa::set-attribute command with $visa::ATTR_ASRL_BAUD passed as an attribute name. But preferred way is to use fconfigure Tcl command and standard options. See example:

# open an instrument
set vi [visa::open $rm "ASRL1::INSTR"]

# set baud rate, parity, word length and stop bits
fconfigure $vi -mode 9600,n,8,1

From the Tcl code’s point of view channel ‘vi’ behaves like a regular serial port. For example, this channel can be transparently passed to third-party library that implements some serial-based protocol.

All serial-specific options supported and corresponding VISA attributes are listed in table below. Format of each option is described in the fconfigure command manual.

Serial-specific channel options and VISA equivalents:

Tcl option VISA Attribute(s)
handshake VI_ATTR_ASRL_FLOW_CNTRL
mode VI_ATTR_ASRL_BAUD, VI_ATTR_ASRL_PARITY, VI_ATTR_ASRL_DATA_BITS, VI_ATTR_ASRL_STOP_BITS
queue VI_ATTR_ASRL_AVAIL_NUM
ttycontrol VI_ATTR_ASRL_DTR_STATE, VI_ATTR_ASRL_RTS_STATE, VI_ATTR_ASRL_BREAK_STATE
ttystatus VI_ATTR_ASRL_CTS_STATE, VI_ATTR_ASRL_DSR_STATE, VI_ATTR_ASRL_RI_STATE, VI_ATTR_ASRL_DCD_STATE
xchar VI_ATTR_ASRL_XON_CHAR, VI_ATTR_ASRL_XOFF_CHAR

See also demo/fconfigure.tcl script that demonstrates usage of channel options.

Error Handling

All VISA API functions returns viStatus value with error code. Zero code means successfull completion, positive value means that operation returns some warning which may be ignored in the most of cases. Negative code means error that should be handled by application.

In scripting language like Tcl the API developer should follow “KISS” principle and make things as simple as possible. This is why tclvisacommands do not explicitly return error code to the calling script. Instead they return either actual result of operation (say, instance of the new channel created by visa::open command) or nothing, when operation has no any meaningful result (e.g. visa::set-attribute).

When underlying VISA API function returns error, and tclvisacannot handle this error itself, it throws an exception which can be handled by catch command in the calling script. This is a standard and expected behaviour for Tcl command. For example, standard open command throws exception when it cannot open a file. Exception handler receives a string with error code and description in the following format:

    [CODE] Text description

where CODE is the name of the predefined VISA error constant.

In the following example we’re trying to open an instrument that does not actually exist:

# this attempt should return VI_ERROR_RSRC_NFOUND error
if { [catch { set vi [visa::open $rm ASRL99::INSTR] } rc] } {
  puts "Error: $rc"
}

This code produces following output:

Error: [VI_ERROR_RSRC_NFOUND] Insufficient location information
 or resource not present in the system.

Calling side then can parse the error string to retrieve VISA error code which is placed between square brackets.

Suppressed Errors

Some errors returned from VISA functions are suppressed by tclvisa, i.e. do not cause Tcl exceptions:

One can use visa::last-error command to determine the exact status of the last VISA operation. This command returns all errors, including suppressed ones.

Correspondence Between VISA Functions and Tcl Commands

Table below contains list of VISA API functions supported by tclvisaand corresponding commands to use in Tcl.

VISA functions and Tcl equivalents:

VISA API function Tcl Command
viAssertIntrSignal visa::assert-intr-signal
viAssertTrigger visa::assert-trigger
viAssertUtilSignal visa::assert-util-signal
viClear visa::clear
viClose close
viFindNext, viFindRsrc visa::find
viGetAttribute visa::get-attribute
viGpibCommand visa::gpib-command
viGpibControlATN visa::gpib-control-atn
viGpibControlREN visa::gpib-control-ren
viGpibPassControl visa::gpib-pass-control
viGpibSendIFC visa::gpib-send-ifc
viLock visa::lock
viOpen visa::open
viOpenDefaultRM visa::open-default-rm
viParseRsrc visa::parse-rsrc
viPrintf format, puts
viQueryf format, puts, gets, scan
viRead read
viReadToFile visa::read-to-file
viScanf gets, scan
viSetAttribute visa::set-attribute
viUnlock visa::unlock
viWrite puts
viWriteFromFile visa::write-from-file

tclvisaCommand Reference

visa::assert-intr-signal

Purpose

Asserts the specified interrupt or signal. This command is a front-end for viAssertIntrSignal VISA API function.

Syntax

`visa::assert-intr-signal session mode ?statusID?`

Arguments

Return Value

None

Example

# open instrument
set vi [visa::open $rm "ASRL1::INSTR"]

# assert signal
visa::assert-intr-signal $vi $visa::ASSERT_USE_ASSIGNED

See Also

visa::assert-util-signal

visa::assert-trigger

Purpose

Asserts software or hardware trigger. This command is a front-end for viAssertTrigger VISA API function.

Syntax

`visa::assert-trigger session protocol`

Arguments

Return Value

None

Example

# open instrument
set vi [visa::open $rm "ASRL1::INSTR"]

# assert trigger
visa::assert-trigger $vi $visa::TRIG_PROT_DEFAULT

visa::assert-util-signal

Purpose

Asserts or deasserts the specified utility bus signal. This command is a front-end for viAssertUtilSignal VISA API function.

Syntax

`visa::assert-util-signal session line`

Arguments

Return Value

None

Example

# open instrument
set vi [visa::open $rm "ASRL1::INSTR"]

# assert signal
visa::assert-util-signal $vi $visa::UTIL_ASSERT_SYSRESET

See Also

visa::assert-intr-signal

visa::clear

Purpose

Clears a device. This command is a front-end for viClear VISA API function.

Syntax

`visa::clear session`

Arguments

Return Value

None

Example

# open instrument with default access mode and timeout
set vi [visa::open $rm "ASRL1::INSTR"]

# set device to known state
visa::clear $vi

See Also

visa::open

visa::find

Purpose

Queries a VISA system to locate the resources associated with a specified interface. This command is a front-end for viFindRsrc and viFindNext VISA API functions.

Syntax

`visa::open RMsession expr`

Arguments

Return Value

Tcl list with addresses of all resources found. If no resources found that match the given expression, empty list is returned.

Example

# open resource manager session
set rm [visa::open-default-rm]

# get addresses of all serial instruments
foreach addr [visa::find $rm "ASRL?*INSTR"] {
  # address is in $addr variable
}

See Also

visa::open-default-rm

visa::get-attribute

Purpose

Retrieves the state of an attribute. This command is a front-end for viGetAttribute VISA API function.

Syntax

`visa::get-attribute session attribute`

Arguments

Return Value

Attribute value.

Example

# open instrument with default access mode and timeout
set vi [visa::open $rm "ASRL1::INSTR"]

# retrieve current baud rate of a serial bus
set baud [visa::get-attribute $vi $visa::ATTR_ASRL_BAUD]

See Also

visa::set-attribute

visa::gpib-command

Purpose

Write GPIB command bytes on the bus. This command is a front-end for viGpibCommand VISA API function.

Syntax

`visa::gpib-command session buf ?count?`

Arguments

Return Value

Number of bytes actually transferred.

Example

# send command
set cmd ... # this variable contains command
set ret [visa::gpib-command $vi $cmd 10]
puts "$ret bytes are transmitted"

visa::gpib-control-atn

Purpose

Specifies the state of the ATN line and the local active controller state. This command is a front-end for viGpibControlATN VISA API function.

Syntax

`visa::gpib-control-atn session mode`

Arguments

Return Value

None

Example

# open a GPIB interface device
set vi [visa::open ...
# set "assert" state
visa::gpib-control-atn $vi $visa::GPIB_ATN_ASSERT

See Also

visa::gpib-control-ren

visa::gpib-control-ren

Purpose

Controls the state of the GPIB Remote Enable (REN) interface line, and optionally the remote/local state of the device. This command is a front-end for viGpibControlREN VISA API function.

Syntax

`visa::gpib-control-ren session mode`

Arguments

Return Value

None

Example

# open a GPIB interface device
set vi [visa::open ...
# set "assert" state
visa::gpib-control-ren $vi $visa::GPIB_REN_ASSERT

See Also

visa::gpib-control-atn

visa::gpib-pass-control

Purpose

Tell the GPIB device at the specified address to become controller in charge (CIC). This command is a front-end for viGpibPassControl VISA API function.

Syntax

`visa::gpib-pass-control session primAddr ?secAddr?`

Arguments

Return Value

None

Example

# open a GPIB device
set vi [visa::open ...
# affect the device at primary address 1 
#   and without secondary address
visa::gpib-pass-control $vi 1

visa::gpib-send-ifc

Purpose

Pulse the interface clear line (IFC) for at least 100 microseconds. This command is a front-end for viGpibSendIFC VISA API function.

Syntax

`visa::gpib-send-ifc session`

Arguments

Return Value

None

Example

# open a GPIB device
set vi [visa::open ...
# send a signal
visa::gpib-send-ifc $vi

visa::last-error

Purpose

Returns last error occured on the channel or Resource Manager session. This command has no VISA API equivalent.

Syntax

`visa::last-error session`

Arguments

Return Value

List of three elements:

Notes

This command is especially useful when IO operations fail, because exact VISA error is not translated to client code by standard Tcl IO procedures, such as puts or read. In other words, when IO procedure (say, puts) fails on a tclvisachannel, only way to know what exactly occured is to call visa::last-error.

Only result of last operation is stored. All subsequent calls of tclvisaor IO commands on a channel rewrite error information.

The Resource Manager session holds result of last operation the session is used in, for example visa::open or visa::find.

Example

In the following example we’re reading from an instrument and checking whether it timed out.

# read from device
set ans [gets $vi]

if { $ans == "" } {
  # Either timeout error or empty device response
  set err [visa::last-error $vi]
  if { [lindex $err 0] == $visa::ERROR_TMO } {
    puts stderr "Error [lindex $err 1] reading from a device"
    puts stderr "[lindex $err 2]"
  }
}

If the read operation timed out, following message will be displayed:

Error VI_ERROR_TMO reading from a device
The read/write operation was aborted because timeout expired 
while operation was in progress.

visa::lock

Purpose

Establishes an access mode to the specified resource. This command is a front-end for viLock VISA API function.

Syntax

`visa::lock session ?lockType? ?timeout? ?requestedKey?`

Arguments

Return Value

Example

# get exclusive lock and wait forever
visa::lock $vi

# get exclusive lock and wait 5 seconds
visa::lock $vi $visa::EXCLUSIVE_LOCK 5000

# get shared lock and wait 5 seconds
set key [visa::lock $vi $visa::SHARED_LOCK 5000 "MYLOCK"]

See Also

visa::open, visa::unlock

visa::open

Purpose

Opens a session to the specified resource. This command is a front-end for viOpen VISA API function.

Syntax

`visa::open RMsession rsrcName ?accessMode? ?openTimeout?`

Arguments

Return Value

Tcl channel with reference to opened VISA session. This channel can be used in standard Tcl IO procedures, like puts.

Notes

There is no a Tcl wrapper for viClose VISA API function. In order to close a VISA session one should use standard Tcl close command instead, which calls viClose internally.

Example

# open resource manager session
set rm [visa::open-default-rm]

# open instrument with default access mode and timeout
set vi1 [visa::open $rm "ASRL1::INSTR"]

# open instrument exclusively
set vi2 [visa::open $rm "ASRL2::INSTR" $visa::EXCLUSIVE_LOCK]

See Also

visa::open-default-rm

visa::open-default-rm

Purpose

Returns a session to the Default Resource Manager resource. This command is a front-end for viOpenDefaultRM VISA API function.

Syntax

`visa::open-default-rm`

Arguments

None

Return Value

Tcl channel with reference to opened resource manager session. This channel can be used in subsequent tclvisaprocedure calls.

Notes

There is no a Tcl wrapper for viClose VISA API function. In order to close a VISA session one should use standard Tcl close command instead, which calls viClose internally.

Example

# open resource manager session
set rm [visa::open-default-rm]

# use session reference
...

# close session
close $rm

See Also

visa::open

visa::set-attribute

Purpose

Sets the state of an attribute. This command is a front-end for viSetAttribute VISA API function.

Syntax

`visa::set-attribute session attribute attrState`

Arguments

Return Value

None

Example

# open instrument with default access mode and timeout
set vi [visa::open $rm "ASRL1::INSTR"]

# set new baud rate of a serial bus
visa::set-attribute $vi $visa::ATTR_ASRL_BAUD 19200

See Also

visa::get-attribute

visa::parse-rsrc

Purpose

Parse a resource string to get the interface information. This command is a front-end for viParseRsrc VISA API function.

Syntax

`visa::parse-rsrc RMsession rsrcName`

Arguments

Return Value

Example

# open resource manager session
set rm [visa::open-default-rm]

# parse instrument address
lassign [visa::parse-rsrc $rm "ASRL1::INSTR"] intfType intfNum

if { $intfType == $visa::INTF_ASRL } {
  puts "Have serial interface device with interface number $intfNum"
}

See Also

visa::open-default-rm

visa::read-to-file

Purpose

Read data synchronously, and store the transferred data in a file. This command is a front-end for viReadToFile VISA API function.

Syntax

`visa::read-to-file session fileName count`

Arguments

Return Value

Number of bytes actually transferred.

Example

# open instrument with default access mode and timeout
set vi [visa::open $rm "ASRL1::INSTR"]

# read up to 1024 bytes of data 
# or until term char is received
visa::read-to-file $vi "raw.dat" 1024

See Also

visa::write-from-file

visa::unlock

Purpose

Relinquishes a lock for the specified resource. This command is a front-end for viUnlock VISA API function.

Syntax

`visa::unlock session`

Arguments

Return Value

None

Example

# get exclusive lock and wait forever
visa::lock $vi

# release the lock
visa::unlock $vi

See Also

visa::open, visa::lock

visa::write-from-file

Purpose

Take data from a file and write it out synchronously. This command is a front-end for viWriteFromFile VISA API function.

Syntax

`visa::write-from-file session fileName ?count?`

Arguments

Return Value

Number of bytes actually transferred.

Example

# open instrument with default access mode and timeout
set vi [visa::open $rm "ASRL1::INSTR"]

# write entire file content to device
visa::write-from-file $vi "raw.dat"

See Also

visa::read-to-file