Controlling GPIB instruments from MATLAB and Octave with no toolbox at all

Overview

This one is different from the rest of the tutorials here. There is no VISA runtime to install, no Instrument Control Toolbox, no Octave package to compile, and no vendor SDK. It is a small module called XyVXI11 that speaks the VXI-11 protocol itself, written in plain MATLAB code.

The same files run unchanged on MATLAB and on GNU Octave, on Windows, Linux and macOS. There is no Octave variant to pick and no platform-specific build step. The only thing it uses that is not the language itself is java.net.Socket, which both MATLAB and Octave already embed.

Three routes, one instrument:if you have the Instrument Control Toolbox, the MATLAB tutorial is a better starting point, because a supported toolbox beats a small module every time. On Linux with a working instrument-control package, the GNU Octave tutorial does the same. This page is for when neither of those is available to you.

Why this exists

The usual reason is dull and familiar: the licence server has no free Instrument Control Toolbox seats.

MATLAB is generally licensed per toolbox, and in a lot of companies there are far fewer instrument seats than there are engineers. So you sit down to log a measurement, MATLAB tells you the licence is checked out, and you have a choice between waiting for a colleague to close their session and finding another way. That single moment is one of the more common reasons people end up on free tools, and it usually has nothing to do with what they think of MATLAB.

This module is the other way. It needs no licensed toolbox, so it does not touch the licence server at all. If you later decide to move to Octave entirely, the same script comes with you unchanged, which makes the decision smaller than it looks.

It is also handy when a machine is locked down. Installing NI-VISA needs administrator rights and a driver install; this needs a folder on your path.

What you need

  • A GPIBEE, with an instrument on the GPIB bus.
  • MATLAB, any reasonably recent release, started normally rather than with -nojvm. Or GNU Octave, built with Java support.
  • Network access from that machine to the adapter, on port 111 for the RPC portmapper plus the dynamic port the adapter reports back.

That is the whole list. No toolbox, no package, no runtime, no administrator rights.

Check Java first

Everything rests on the embedded Java runtime, so confirm it is there before anything else. At the MATLAB or Octave prompt:

usejava('jvm')

It has to return 1. On MATLAB it will, unless the session was started with -nojvm. On Octave it depends how your build was made: the official Windows and most Linux distribution builds have Java enabled, but a minimal or self-compiled build might not.

If it returns 0, this module cannot open a socket in that installation. Octave has no TCP support of its own, which is exactly why the Java route was chosen over anything else.

Download the example

MatlabOctaveGpibeeExample.zip
The XyVXI11 module and two example scripts. Runs on MATLAB and on Octave, unchanged.
⤓ Download the module

Unpack it somewhere convenient. Nothing gets installed.

What is inside

FileWhat it is
example_basic.mThe first thing to run. One instrument, two queries.
example_gpib_scan.mTalks to the adapter itself: scans the bus and reads a parallel poll.
XyVXI11/The module. This is the folder that goes on your path.
XyVXI11/GpibeeInstrument.mOne instrument, the everyday level: write, query, identity, status byte, trigger, clear.
XyVXI11/GpibeeInterface.mThe adapter's own bus features: scan, parallel poll, raw command bytes.
XyVXI11/Vxi11Client.mThe raw VXI-11 core channel, if you want the protocol calls directly.
XyVXI11/OncRpcClient.mONC RPC over TCP, on the Java socket. The transport underneath.
XyVXI11/getVxi11Port.mAsks the portmapper which port the VXI-11 service is on.
XyVXI11/Xdr.m, XdrReader.mThe wire encoding the protocol uses. You will not call these.

There are three levels, and you can work at whichever suits you. GpibeeInstrument is the one to reach for. GpibeeInterface is for the adapter rather than an instrument. Vxi11Client is the bare protocol, useful if you are doing something unusual or debugging.

Putting it on the path

One line, once per session:

addpath('/path/to/MatlabOctaveGpibeeExample/XyVXI11')

Both example scripts already do this for themselves, working out their own location, so you can run them from anywhere without setting the path first.

Note on naming:XyVXI11 is an ordinary folder, not a namespace package, so the classes are used by their bare names. It is GpibeeInstrument(...), not XyVXI11.GpibeeInstrument(...).

Example 1: one instrument

example_basic.m is the smallest useful thing: connect to one instrument, ask who it is, then ask whether it is unhappy about anything.

ip = '192.168.3.2';
primaryAddress = 4;   % e.g. an HP 34401A on the bench

inst = GpibeeInstrument(ip, primaryAddress);
cleanupObj = onCleanup(@() inst.close());

inst.Timeout = 5; % seconds

idnString = inst.idn();
fprintf('*IDN?: %s\n', idnString);

err = inst.query('SYST:ERR?');
fprintf('SYST:ERR?: %s\n', err);

Change the two values at the top and it is ready. 192.168.3.2 is the address of your GPIBEE, and 4 is the GPIB address of the instrument on the bus. The adapter's web interface shows its own address and can scan the bus for you.

The onCleanup line is worth copying into your own code. It closes the link when the script ends, including when it ends because something threw. Without it, an error halfway through leaves a link open on the adapter, and the next run can find the instrument busy.

What a real run looks like

This is Octave, against a real adapter and a real multimeter:

octave:4> example_basic

*IDN?: HEWLETT-PACKARD,34401A,0,5-1-1
SYST:ERR?: -410,"Query INTERRUPTED"

The first line is the instrument stating its maker, model, serial number and firmware version. If you see that, the whole chain works: Octave reached the adapter over the network, and the adapter reached the instrument over GPIB.

The second line is the instrument's error queue, and it is doing its job. Asking SYST:ERR? after a sequence of commands is a good habit, because an instrument will quietly refuse a command it does not like and carry on as if nothing happened. Here it had something to report rather than the +0,"No error" you get from a clean queue, which is exactly the kind of thing you want to find out about early rather than late.

Example 2: the bus

example_gpib_scan.m talks to the adapter itself rather than to an instrument, so there is no GPIB address in it:

ifc = GpibeeInterface(ip);
cleanupObj = onCleanup(@() ifc.close());

addrs = ifc.scanBus();   % full-bus scan, takes a few seconds
fprintf('Devices found on the bus:\n');
for k = 1:numel(addrs)
    fprintf('  %s\n', addrs{k});
end

ppState = ifc.parallelPoll();
fprintf('Parallel poll (DIO1..DIO8): %d\n', ppState);

Two useful things happen here. The scan walks the bus and reports which addresses answer, which is the fastest way to settle an argument about whether an instrument is really at address 12. The parallel poll reads all eight DIO lines in one bus cycle and returns them as a number from 0 to 255.

These are GPIBEE features rather than standard VXI-11, reached through vendor SCPI commands on the adapter's own interface device. If a future firmware changes that syntax, the commands are all in one place at the top of GpibeeInterface.m.

Run this one first if nothing works:a bus scan needs only the adapter, not a working instrument. If the scan succeeds and example_basic does not, the problem is the GPIB address or the instrument, not the network or the module.

GpibeeInstrument reference

The everyday level. One object, one instrument.

CallWhat it does
GpibeeInstrument(ip, primary)Opens an instrument at a GPIB primary address. Add a third argument for a secondary address, or pass the IP alone to reach the adapter itself.
write(cmd)Sends a command. The terminator is appended for you.
query(cmd)Sends a command and reads the answer. The usual call.
readLine(maxLength)Reads an answer on its own, for a query you sent with write.
readBinary(maxLength)Reads raw bytes rather than text. For waveforms and screenshots.
idn()Shorthand for query('*IDN?').
readStatusByte()Serial poll. Reads the status byte on demand.
trigger()Sends a GPIB trigger to the instrument.
clearDevice()Device clear. The thing to try when an instrument has stopped making sense.
setRemote() / setLocal()Takes the front panel away from the operator, or gives it back.
lockDevice(wait) / unlockDevice()Claims exclusive access, so another program cannot interleave with yours.
TimeoutProperty, in seconds. Defaults to 5.
TerminatorProperty. Appended to every write. Defaults to a newline.
ReadTermCharProperty. The byte a read stops at, 10 by default. Set it to [] to read until the instrument signals the end itself.
close()Releases the link. Let onCleanup call it for you.

GpibeeInterface reference

The adapter rather than an instrument. Bus management.

CallWhat it does
GpibeeInterface(ip)Connects to the adapter's own interface device.
scanBus()Scans the whole bus and returns the addresses that answered. Takes a few seconds.
scanBus(primary)Scans one address only, which is quick.
parallelPoll()Reads DIO1 to DIO8 in one cycle, as a number from 0 to 255.
parallelPollEnable(primary, dioLine, senseHigh)Configures one instrument to answer a parallel poll on a given line.
parallelPollDisable(primary)Undoes that.
sendCommandBytes(bytes)Puts raw GPIB command bytes on the bus. For when nothing else will do.
close()Releases the link.

Addressing

Device names follow the ordinary VXI-11 convention, the same one inside the PyVISA resource strings used elsewhere on this site:

Device nameWhat it reaches
inst0The adapter's own interface device. This is what GpibeeInterface uses.
gpib0,4The instrument at GPIB primary address 4.
gpib0,4,5Primary address 4, secondary address 5.

What it does and does not do

The VXI-11 core channel is complete: creating and destroying links, writes chunked to whatever size the adapter asks for, reads that run until the end of the message or a terminator, status byte, trigger, clear, remote and local, lock and unlock. Protocol errors come back as ordinary MATLAB errors with a message you can read.

Two things are deliberately absent:

  • The interrupt channel, meaning SRQ callbacks. Standard VXI-11 service requests need the client to run its own small RPC server for the instrument to call back into, which is a large thing to carry for a module this size. readStatusByte() covers the common case of checking on demand.
  • The abort channel, for cancelling a call in flight from a second connection.

This code is young

Not extensively tested yet:XyVXI11 is new. The protocol layer has been checked against the specification and exercised end to end, and the run shown further up is real, but it has nowhere near the mileage of the VISA-based examples elsewhere on this site. Treat it as something promising rather than something proven.

That is said plainly because the alternative is worse. If you use it and it works, we would like to know. If you use it and something breaks, we would very much like to know, with whatever MATLAB or Octave printed at you.

This is not a module we intend to publish and forget. It is genuinely interesting to keep extending, fixing and maintaining, and real reports from real benches are what make that worth doing. Write to support@gpibee.com.

Troubleshooting

ProblemSolution
usejava('jvm') returns 0 MATLAB started with -nojvm, or an Octave build without Java. Restart MATLAB normally, or use an Octave build with Java enabled.
Undefined function or variable 'GpibeeInstrument' The XyVXI11 folder is not on the path. Run the addpath line, or run one of the example scripts, which do it themselves.
Connecting fails or hangs Check the adapter answers in a browser at that IP. A firewall between you and it has to allow port 111 and the dynamic port the portmapper hands back.
The connection opens but every read times out Usually the GPIB address rather than the network. Run example_gpib_scan to see which addresses actually answer.
The instrument is busy on the next run A previous link was never closed. In MATLAB or Octave, clear all, and use onCleanup in your own scripts.
You edited a file in XyVXI11 and nothing changed Both MATLAB and Octave cache a class definition for the life of the session. Run clear classes or restart.
Long measurements fail, short ones work The timeout is shorter than the measurement. Raise inst.Timeout, remembering it is in seconds.
Large transfers feel slow On an older Java version the module falls back to reading a byte at a time. It is correct, just unhurried. A newer JVM takes the fast path automatically.
Have the toolbox after all?The MATLAB and GNU Octave tutorials cover the supported routes, and the same instrument appears in Python, C#, LabVIEW, C, Object Pascal and Excel VBA.