Code covered by the BSD License  

Highlights from
Gilson HPLC Pump RS232 communication

Gilson HPLC Pump RS232 communication

by

 

Communicates with Gilson HPLC pumps via RS232 (and 508 interface module)

gilsonpumpobjcomm(type, serialObject, deviceID, command)
function response = gilsonpumpobjcomm(type, serialObject, deviceID, command)
% GILSONPUMPOBJCOMM Reads and writes data from Gilson pumps
% gilsonpumpobjcomm(type, serialObject, deviceID, command) writes or reads
% information from Gilson pumps (specifically designed for the 305, but
% probably works the same for other pumps), connected via the Gilson 506C
% interface through RS232 (the pumps connect to the interface via RS422).
% type is 'read' or 'write', serialObject is the serial port object,
% deviceID the ID of the Gilson pump (they are set to 1 by default, but may
% be between 1 and 63 depending on the system - the interface is usually
% 63), command is the command to be read/written.  If reading a value,
% function responds with the requested value.  If writing a value, the
% response is [1 value] if successful.  For both read and write operations,
% the response is -1 if the controller returns an unexpected message, -2 if
% there was no response, or -3 if any of the arguments were invalid.

% Normal usage:

% e.g. 1 response = gilsonpumpobjcomm('read', serialObject, 1, 'W') - reads
% the version number of the pump e.g. '305V3.0'.

% e.g. 2 response = gilsonpumpobjcomm('write', serialObject, 1, 's0100')
% writes a flow rate of 1 mL min-1 to the pump, returning a 1 if
% successful.


% Range:

% type = 'read' or 'write'

% serialObject = serial object

% deviceID = unsigned integer: 1-63

% command = string


% checks the number of arguments
error(nargchk(4, 4, nargin))

% error handling
if ~ischar(type) || all(~strcmp(type, {'read', 'write'}))
    % errors
    error('type must be "read" or "write"')
    
elseif ~isa(serialObject, 'serial') || ~isvalid(serialObject) || ~strcmp(serialObject.Status, 'open')
    % errors
    error('serialObject must be a valid open serial object.')
    
elseif ~isnumeric(deviceID) || ~isscalar(deviceID) || deviceID < 1 || deviceID > 63 || deviceID ~= round(deviceID)
    % errors
    error('deviceID must be an unsigned integer from 1 to 63')
    
elseif ~isschar(command) || ~isvector(command)
    % errors
    error('command must be a string')
    
elseif strcmp(type, 'read') && numel(command) ~= 1
    % errors
    error('Read commands must only be a single character')
end

% flushes anything in the buffer
fread(serialObject);

% all Gilson commands must be sent byte by byte, so are sent and read using
% fwrite and fread, respectively

% parses the deviceID
deviceID = deviceID + 128;

% alerts device that this command is for that device
fwritetc(serialObject, deviceID)

% device ALWAYS responds with the deviceID back if it heard it
freadmatchbyte(serialObject, deviceID, 'Gilson device did not respond to ID check')

% defines line feed and carriage return characters for readability
LF = char(10);
CR = char(13);

% inserted a pause BEFORE the command to give it time in case timers
% interrupt the usual course of action (which they will) - MATLAB is being
% extremely strange with this - a "40ms" pause is turning into ~400 ms
%if ~isfield(serialObject.UserData, 'realTermHandle')
    % pause it
    pause(0.04)
%end

% different protocols required for different commands
if strcmp(type, 'write')
    % if the command is to be written ("Buffered" in Gilson documentation
    % parlance), an LF is sent to the device, to which the device always
    % respond with an LF - but it MAY not immediately do so - should try at
    % least twice to make sure it does behave
    try
        % attempts to match the byte to LF - if it doesn't work...
        fwritetc(serialObject, LF)
        
        % reads it back
        freadmatchbyte(serialObject, LF, 'Gilson device did not respond to the command to start writing a value')
        
    catch
        % it'll try again, only this time, if it errors the program will
        % stop completely
        fwritetc(serialObject, LF)
        
        % reads it back
        freadmatchbyte(serialObject, LF, 'Gilson device did not respond to the command to start writing a value')
    end

    % the command is then written byte by byte, with the device echoing
    % back the same command byte
    for m = 1:numel(command)
        % writes the command
        fwritetc(serialObject, command(m))

        % device ALWAYS responds with the command byte back if it heard it
        freadmatchbyte(serialObject, command(m), 'Gilson device did not respond to one of the command bytes')
    end
    
    % at the end of the write, the last character must be a carriage
    % return
    fwritetc(serialObject, CR)
    
    % device then responds with CR
    freadmatchbyte(serialObject, CR, 'Gilson device did not respond to signal to finish writing command')

else
    % if its reading...('Immediate' in Gilson parlance - is able to
    % interrupt 'Buffered' commands - useful if something isn't working
    % correctly, although calling the deviceID also does the same thing)
    
    % defines ack character for convenience and readability
    ack = char(6);
    
    % defines the read error message
    readError = 'Gilson device did not respond to a request for the next byte to be read';

    % sends the command
    fwritetc(serialObject, command)

    % device responds with the first byte
    responseNum(1) = freadbyte(serialObject, readError);
    
    % initialises the ticker
    ticker = 1;
    
    % if data is not empty (covered by freadbyte) or not larger than 128,
    % read more data - note that the matrix is not preallocated here and
    % MATLAB will complain, but it should remain reasonably small - it is
    % not possible to pre-guess the matrix size
    while responseNum(ticker) < 128
        % requests the next byte of data
        fwritetc(serialObject, ack)

        % reads the next byte
        responseNum(ticker + 1) = freadbyte(serialObject, readError);
        
        % increments ticker
        ticker = ticker + 1;
    end

    % the last byte to be sent is the ASCII number for the last character,
    % but + 128 to signify that this is the last character.  GSIOC does not
    % appear to transmit any data larger than 128 unless it is a deviceID,
    % or it is the last byte of data.
    
    % modifies the last byte and converts it into ASCII
    response = char([responseNum(1:end - 1), responseNum(end) - 128]);
end

% the pump does not seem to behave properly unless a pause is left after
% the command has finished (despite it responding to some commands very
% quickly
%if ~isfield(serialObject.UserData.realTermHandle)
    % pause it
    pause(0.02)
%end


function fwritetc(serialObject, data)
% FWRITETC writes data to a serialObject using fwrite, but in a try-catch loop
% in case it errors

% sends data
fwrite(serialObject, data, 'async')


function freadmatchbyte(serialObject, matchByte, errorMessage)
% FREADBYTE reads a single byte from a serialObject using fwrite, seeing if it
% matches matchByte, and erroring with the errorMessage if it does not

% reads a byte out and compares it    
if fread(serialObject, 1) ~= matchByte
    % errors
    error(errorMessage)
end


function byte = freadbyte(serialObject, errorMessage)
% FREADBYTE reads a single byte from a serialObject using fwrite, seeing if it
% is empty (i.e. it timed out), and erroring with the errorMessage if it
% is.

% fetches byte
byte = fread(serialObject, 1);

% if its empty (timed out), error
if isempty(byte)
    % errors
    error(errorMessage)
end

Contact us