Computer Laboratory > Theo Markettos > Theo's notes and tips > Driving National Instrument GPIB devices from Matlab on Linux

 

Matlab provides an instrument control toolbox to drive GPIB devices under Windows. However this doesn't seem to work under Linux (Matlab 7.2.0.294). It appears, while there's a driver for National Instrument GPIB devices under Linux, the Matlab-GPIB interface isn't implemented.

Here we present a simple way to send GPIB commands from Linux.

We make us of NI's Linux driver. To interface this to Matlab we create a C-language program which uses Matlab's MEX external interface. The NI GPIB driver, when installed, can be linked to a C program using -lgpibapi.

Receive function

A Matlab function resultString=ibrd(gpibPrimaryAddress,bytesToRead) to receive bytes as Matlab strings from the GPIB device is presented below:

#include "ni488.h"
#include <stdlib.h>
#include <stdio.h>
#include "mex.h"

int i;
int Device = 0;                   /* Device unit descriptor                  */
int BoardIndex = 0;               /* Interface Index (GPIB0=0,GPIB1=1,etc.)  */

#define RESPONSE_LENGTH 100       /* default length of maximum response we can read from the GPIB device */

/* this is the entry point called from Matlab */
/* resultString = ibrd(gpibPrimaryAddress) */
/* resultString = ibrd(gpibPrimaryAddress,bytesToRead) */
void mexFunction(
    int nlhs, mxArray *plhs,
    int nrhs, const mxArray *prhs)
{    
   int   PrimaryAddress = 2;      /* Primary address of the device           */
   int   SecondaryAddress = 0;    /* Secondary address of the device         */
   char  Buffer101;             /* Read buffer       */
   int   readLength=0;                                
   
  int mrows, ncols;
   char *input_buf, *output_buf;
  int   buflen,status;
    
  /* Check for proper number of arguments. */
  if (nrhs != 1 && nrhs!=2) {
    mexErrMsgTxt("One or two inputs required.");
  }
  
  /* The first input must be an integer.*/
  mrows = mxGetM(prhs0);
  ncols = mxGetN(prhs0);
  if (!mxIsDouble(prhs0) || mxIsComplex(prhs0) ||
      !(mrows == 1 && ncols == 1)) {
    mexErrMsgTxt("Input must be a single integer");
  }  

 /* read the address parameter from the supplied Matlab matrix */
 PrimaryAddress = (int) *(mxGetPr(prhs0));
 
 /* if we're supplied with a number of bytes to read, use that instead of
  * our default of RESPONSE_LENGTH */
 if (nrhs>1)
 {
  /* The input must be a noncomplex scalar double.*/
  mrows = mxGetM(prhs1);
  ncols = mxGetN(prhs1);
  if (!mxIsDouble(prhs1) || mxIsComplex(prhs1) ||
      !(mrows <= 1 && ncols <= 1)) {
    mexErrMsgTxt("Input must be a noncomplex scalar double.");
  }
   /* if it's a null matrix, ignore it */
   if (mrows == 0 || ncols == 0) {
    readLength=0;
  }
  else
  {
     readLength = (int) *(mxGetPr(prhs1));
  }
 }
 else
     readLength=0;
 
 if (readLength==0)
     readLength=RESPONSE_LENGTH;
 
  /* Allocate memory for output string. */
  output_buf = mxCalloc(readLength, sizeof(char));

/*****************************************************************************
 * GPIB Initialization - Done only once at the beginning of your application.
 *****************************************************************************/

   Device = ibdev(                /* Create a unit descriptor handle         */
         BoardIndex,              /* Board Index (GPIB0 = 0, GPIB1 = 1, ...) */
         PrimaryAddress,          /* Device primary address                  */
         SecondaryAddress,        /* Device secondary address                */
         T10s,                    /* Timeout setting (T10s = 10 seconds)     */
         1,                       /* Assert EOI line at end of write         */
         0);                      /* EOS termination mode                    */
   if (ibsta & ERR) {             /* Check for GPIB Error                    */
      mexErrMsgTxt("ibdev Error"); 
   }

  
/*****************************************************************************
 * Main Application Body - Write the majority of your GPIB code here.
 *****************************************************************************/

   ibrd(Device, output_buf, readLength);     /* Read bytes from the device */    
     if (ibsta & ERR) {
        mexErrMsgTxt("ibrd Error");	
        }
     output_bufibcntl = '\0';         /* Null terminate the ASCII string         */

   ibonl(Device, 0);              /* Take the device offline                 */
   if (ibsta & ERR) {
      mexErrMsgTxt("ibonl Error");	
   }

 /* return a pointer to the result string to Matlab */
 plhs0 = mxCreateString(output_buf);
}

Send function

...and a send function ibwrt(gpibAddress,stringToSend):

#include "ni488.h"
#include <stdlib.h>
#include <stdio.h>
#include "mex.h"

int i;
int Device = 0;                   /* Device unit descriptor                  */
int BoardIndex = 0;               /* Interface Index (GPIB0=0,GPIB1=1,etc.)  */
	
/* ibwrt(gpibPrimaryAddress,stringToSend) */	
void mexFunction(
    int nlhs, mxArray *plhs,
    int nrhs, const mxArray *prhs)
{    
   int   PrimaryAddress;      /* Primary address of the device           */
   int   SecondaryAddress = 0;    /* Secondary address of the device         */
   
  int mrows, ncols;
   char *input_buf, *output_buf;
  int   buflen,status;
  
  /* Check for proper number of arguments. */
  if (nrhs != 2) {
    mexErrMsgTxt("2 inputs required.");
  }
  
  /* The input 0 must be a noncomplex scalar double.*/
  mrows = mxGetM(prhs0);
  ncols = mxGetN(prhs0);
  if (!mxIsDouble(prhs0) || mxIsComplex(prhs0) ||
      !(mrows == 1 && ncols == 1)) {
    mexErrMsgTxt("Input must be a noncomplex scalar double.");
  }

  /* Assign pointers to each input and output. */
  PrimaryAddress = (int) *(mxGetPr(prhs0));
  /*printf("PrimaryAddress = %d\n",PrimaryAddress);*/
  
  /* Input 1 must be a string. */
  if (mxIsChar(prhs1) != 1)
    mexErrMsgTxt("Input must be a string.");

  /* Input 1 must be a row vector. */
  if (mxGetM(prhs1) != 1)
    mexErrMsgTxt("Input must be a row vector.");
    
  /* Get the length of the input string. */
  buflen = (mxGetM(prhs1) * mxGetN(prhs1)) + 1;

  /* Allocate memory for input and output strings. */
  input_buf = mxCalloc(buflen, sizeof(char));

  /* Copy the string data from prhs0 into a C string 
   * input_buf. */
  status = mxGetString(prhs1, input_buf, buflen);
  if (status != 0) 
    mexWarnMsgTxt("Not enough space. String is truncated.");

/*****************************************************************************
 * Initialization - Done only once at the beginning of your application.
 *****************************************************************************/

   Device = ibdev(                /* Create a unit descriptor handle         */
         BoardIndex,              /* Board Index (GPIB0 = 0, GPIB1 = 1, ...) */
         PrimaryAddress,          /* Device primary address                  */
         SecondaryAddress,        /* Device secondary address                */
         T10s,                    /* Timeout setting (T10s = 10 seconds)     */
         1,                       /* Assert EOI line at end of write         */
         0);                      /* EOS termination mode                    */
   if (ibsta & ERR) {             /* Check for GPIB Error                    */
      mexErrMsgTxt("ibdev Error"); 
   }

/*****************************************************************************
 * Main Application Body - Write the majority of your GPIB code here.
 *****************************************************************************/

   ibwrt(Device, input_buf, buflen-1);     /* Send the command   */
   if (ibsta & ERR) {
      mexErrMsgTxt("ibwrt Error");
   }

   ibonl(Device, 0);              /* Take the device offline                 */
   if (ibsta & ERR) {
      mexErrMsgTxt("ibonl Error");	
   }

}

These need to be compiled from within Matlab - you need GCC and the GPIB library installed. To compile, issue:

>> mex -lgpibapi ibwrt.c
>> mex -lgpibapi ibrd.c

then you can call the functions as in this example to access GPIB device 2:

>> ibwrt(2,'xsetup0');
>> ibwrt(2,'xr');
>> response=ibrd(2)

response =

XM0000334

>> ibwrt(2,'xr');
>> response=ibrd(2,4)

response =

XM00

>> response=ibrd(2,5)

response =

00334

>>

It would be fairly straightforward for these functions to pass through another parameter to select the secondary address of the device.