Code covered by the BSD License  

Highlights from
GSIOC RS232 communication files

GSIOC RS232 communication files



For communicating with GSIOC devices via RS232

gsiocobjcomm(type, serialObject, deviceID, command)
function response = gsiocobjcomm(type, serialObject, deviceID, command)
% GSIOCOBJCOMM Reads and writes data from GSIOC devices
% gsiocobjcomm(type, serialObject, deviceID, command) writes or reads
% information from GSIOC devices (initially designed for the 305, but
% probably works the same for other devices), 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 GSIOC device (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 = gsiocobjcomm('read', serialObject, 1, 'W') - reads
% the version number of the device e.g. '305V3.0'.

% e.g. 2 response = gsiocobjcomm('write', serialObject, 1, 's0100') writes
% a flow rate of 1 mL min-1 to the device, 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 ~ischar(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')

% flushes anything in the buffer

% 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, 'GSIOC 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

% 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
        % attempts to match the byte to LF - if it doesn't work...
        fwritetc(serialObject, LF)
        % reads it back
        freadmatchbyte(serialObject, LF, 'GSIOC device did not respond to the command to start writing a value')
        % it'll try again, only this time, if it errors the program will
        % stop completely
        fwritetc(serialObject, LF)
        % reads it back
        freadmatchbyte(serialObject, LF, 'GIOSC device did not respond to the command to start writing a value')

    % 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), 'GSIOC device did not respond to one of the command bytes')
    % 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, 'GSIOC device did not respond to signal to finish writing command')

    % 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 = 'GSIOC 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
    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;

    % 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]);

% 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

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

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

Contact us