Code covered by the BSD License  

Highlights from
CO2gui - lab control and automation

CO2gui - lab control and automation

by

 

06 Jan 2010 (Updated )

Software used for controlling and data logging lab equipment.

fibreobjcomm(type, serialObject, address, bytes, value)
function output = fibreobjcomm(type, serialObject, address, bytes, value)
% FIBREOBJCOMM low-level communications protocols for the FOR
% fibreobjcomm(type, serialObject, address, bytes, value) sends
% a command to a valid FOR serial object, then errors if the response was
% not expected (this can be omitted or left empty).  The type must be
% "read" or "write", and the address must be either 0, 2, 3, 4, 5, 9, 10
% (although there may be others, to prevent errors these are not permitted.
%  If reading, the value is (optionally) the number of bytes to read, or if
%  writing, the value(s) to write.  This cannot be auto-detected, since for
%  example you may want to write "20" to to a 16 bit address space (e.g.
%  the delay time) - even though this would easily fit into 1 byte.

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

% error handling
if ~isequal(type, 'read') && ~isequal(type, 'write')
    % errors
    error('type must be "read" or "write".')
    
elseif ~isserial(serialObject) || (~isfield(serialObject.UserData, 'realTermHandle') && ~isrunning(serialObject))
    % the serial object must be valid and open to send or receive data
    % (unless there is a realterm handle available)
    error('serialObject must be a valid open serial object')
    
elseif ~isserial(serialObject) || (isfield(serialObject.UserData, 'realTermHandle') && ~isrunning(serialObject.UserData.realTermHandle))
    % if the handle is there, the object must be running (PortOpen is 1)
    error('If the Realterm handle is present, the object must be connected via Realterm.')
    
elseif isfield(serialObject.UserData, 'realTermHandle') && (~isfield(serialObject.UserData, 'captureFileID') || ~isfid(serialObject.UserData.captureFileID))
    % if using realterm, the capture file ID must be there
    error('If using Realterm, the capture file handle must be in the serial object''s UserData.')
    
elseif ~isnumeric(address) || ~isscalar(address) || address ~= uint8(address) 
    % the address must be a particular value, but these are allowed through
    % as an undocumented feature
    error('Address must be valid 8-bit byte, e.g. 0, 2, 3, 4, 5, 9, or 10 (all those currently known).')
    
elseif ~isnumeric(bytes) || ~isscalar(bytes) || bytes ~= uint8(bytes)
    % must be a valid number of bytes to write
    error('Address to read must be a valid number of 8 bit bytes.')
    
elseif nargin >= 5 && strcmp(type, 'write') && (~isnumeric(value) || ~isscalar(value) || value ~= uint32(value))
    % must be a valid number to write
    error('Value to write must be no larger than 2^32.')
end

% defines the command as being the number of bytes to read
command = bytes;

% modifies the command
if strcmp(type, 'write')
    % defines the first part
    command = 128 + command;
end

% defines the rest
command = [command, address];

% if writing, we need to add on the rest of the bytes to write
if strcmp(type, 'write')
    % determine how to encode the values to write
    switch bytes
        case 1
            % do nothing

        case 2
            % encode it
            value = typecast(uint16(value), 'uint8');

        case 4
            % (rare) encode it as uint32
            value = typecast(uint32(value), 'uint8');

        otherwise
            % unknown data type
            error('Unknown data type: could not convert it to 8-bit bytes.')
    end
    
    % add it on
    command = [command, value];
    
    % also set the number of bytes (to read) to (its going to be increased
    % by 2 later) - we only want to see an acknowledgement from the PIC
    bytes = 0;
end

% sends the command
serialwrite(serialObject, [command, fibreobjchecksum(command)])

% DEBUG
%[command, fibreobjchecksum(command)]

% loops round until the buffer is filled (usually requires 2 loops)
for m = 1:20
    % if the bytes in the buffer is filled, then move on (2 bytes added on
    % for the checksum)
    if serialbytesavailable(serialObject) < bytes + 2;
        % wait a bit more
        pause(0.05)
        
    else
        % leave the loop
        break
    end
end

% gets the response - it SHOULD work just fine without specified the number
% of bytes but oh no
if serialbytesavailable(serialObject)
    % reads it in
    response = serialread(serialObject, serialbytesavailable(serialObject))';
    
    % DEBUG
    %response
    
    % if the response was longer than expected... (note that the address
    % byte and the checksum byte are not counted)
    if numel(response) - 2 > bytes
        % give a warning
        warning('fibreObjComm:tooMuchData', 'More data than expected was collected from the FOR.')
    end

    % check the checksum
    if response(end) ~= fibreobjchecksum(response(1:end - 1))
        % give a warning
        warning('fibreObjComm:invalidCheckSum', 'Checksum from FOR was invalid.')
    end

    % check the response
    if strcmp(type, 'write') || numel(response) == 2
        % gets the data
        switch response(1)
            case 0
                % got through successfully

            case 1
                % checksum error writing
                error('Invalid checksum when writing.')

            case 2
                % invalid address
                error('Address does not appear to exist (writing).')

            case 3
                % checksum wrong when reading
                error('Checksum error when reading.')

            case 4
                % address error when reading
                error('Address does not appear to exist (reading).')
        end
        
    else
        % process it
        output = response(2:end - 1);
        
        % if there are two bytes, then convert it into uint16 (no other
        % data formats so far encountered, other than when broadcasting
        % (that is uint32))
        switch numel(output)
            case 1
                % do nothing

            case 2
                % change it
                output = double(typecast(uint8(output), 'uint16'));

            case 4
                % changes it
                output = double(typecast(uint8(output), 'uint32'));

            otherwise
                % not sure what to do
                warning('fibreObjComm:unknownFormat', 'Output was not converted as unusual number of bytes collected.')
        end
    end
    
    % leave a short pause between commands to guarauntee it'll get
    % through, if its the real term device
    if isfield(serialObject.UserData, 'realTermHandle')
        % pause
        pause(0.1)
    end

else
    % error
    error('FOR did not respond to the command.')
end

Contact us