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.

autodetect(availablePorts, selectedInstruments)
function [comPorts, instrumentTypes] = autodetect(availablePorts, selectedInstruments)
% AUTODETECT detects all of the available known instruments and the COM#
% [comPorts, instrumentTypes] = autodetect(availablePorts) detects
% all of the instruments attached to the PC, based on the number of known
% instrument types defined in readco2guiconfig.  If availablePorts is not
% specified, then it retrieves them using getavailablecom.  If
% selectedInstruments is included, then it must be a vector of all of the
% instruments to check for.  Available ports can be left empty ([]).

% e.g. [comPorts, instrumentTypes] = autodetect({'COM1'; 'COM3'; 'COM4'})
% returns all of the instrument types attached to COM ports 1, 3 and 4.

% e.g. 2 [comPorts, instrumentTypes] = autodetect([], [2, 3]) detects all
% of the Jasco pumps and BPRs on all of the COM ports.

% initialises a waitbar
waitBarHandle = waitbar(0, 'Initialising auto-detect...');

% if availablePorts is not specified
if ~nargin || (nargin >= 1 && isempty(availablePorts))
    % finds the available com ports
    availablePorts = getavailablecom;
    
else
    % if the input is a char, turn that into a single cell array
    if ischar(availablePorts)
        % convert it
        availablePorts{1} = availablePorts;
    end
    
    % checks the ports
    for m = 1:numel(availablePorts)
        % checks that the first three letters are 'COM', and that the rest
        % of the string is a number between 1 and 255
        if strcmp(availablePorts{m}(1:3), 'COM')
            % gets the numeric part out
            number = str2double(availablePorts{m}(4:end));
            
            % checks that
            if ~iscomport(number)
                % errors
                error(['Invalid COM port: ', availablePorts{m}])
            end
        end
    end
end

% retrieves object types and commands config from co2guiconfig.mat - all
% the output arguments are structures - only need the objectTypes
[guiConfig, objectTypes] = readco2guiconfig;
clear guiConfig

% pre-allocates the response
instrumentTypes = ones(numel(availablePorts), 1);

% if the instruments was supplied...
if nargin == 2
    % error checking
    if ~isnumeric(selectedInstruments) || ~isavector(selectedInstruments) || any(selectedInstruments < 2) || any(selectedInstruments > numel(objectTypes)) || any(selectedInstruments ~= round(selectedInstruments))
        % errors
        error('If selectedInstruments is supplied, it must a vector with a valid instrument numbers larger than 1 (1 is reserved as a dummy instrument).')
        
    else
        % convert it into a column vector
        if size(selectedInstruments, 2) > 1
            % convert it
            selectedInstruments = selectedInstruments(:);
        end
        
        % convert the object types into those selected (including the dummy
        % instrument, as we start from #2 later)
        objectTypes = objectTypes([1; selectedInstruments]);
    end
end

% turns the warnings off
warning('off', 'MATLAB:serial:fscanf:unsuccessfulRead')
warning('off', 'MATLAB:serial:fread:unsuccessfulRead')

% for each COM port...
for n = 1:numel(availablePorts)
    % updates the waitbar
    waitbar(n / numel(availablePorts), waitBarHandle, sprintf('Scanning %s for instruments...', availablePorts{n}))
    
    % defines the COM port number
    availablePortNumber = str2double(availablePorts{n}(isstrprop(availablePorts{n}, 'digit')));
	
    % for each object type (ignores the first one since this is blank)
    for nn = 2:numel(objectTypes)
        % updates the waitbar again
        waitbar((nn - 1) / (numel(objectTypes) - 1), waitBarHandle, ['Testing for ', objectTypes(nn).name, ' on ', availablePorts{n}])
        
        % have to put commands in a try-catch block so that the function
        % doesn't stop in the middle
        try
            % creates the object (won't error - usually)
            serialObject = feval(str2func(objectTypes(nn).objectCommand), availablePortNumber);
            
            % tries to connect (may error) - does not use the standard
            % connect command in case there are extra steps (like there is
            % with the BPR)
            fopen(serialObject);

            % flow control must be turned off and emulated for sending the
            % command, otherwise MATLAB will hand
            if strcmp(serialObject.FlowControl, 'hardware')
                % turns FlowControl off
                serialObject.FlowControl = 'none';

                % turns the pin off (signals its OK to start sending
                % commands)
                serialObject.DataTerminalReady = 'off';
                
                % Vista needs a brief pause to behave itself correctly -
                % I've left his is for XP too, but in case you wanted to
                % shave off that whole 400 ms, you could try...BUT old
                % MATLAB versions detect Vista as "Microsoft Windows 2000"
                %if isempty(strfind(system_dependent('getos'), 'XP'))
                pause(0.4)
                %end
                
                % turns a flag on for later resetting
                flowControlFlag = true;
                
            else
                % sets flag
                flowControlFlag = false;
            end

            % asks something - if it errors it goes on to the next loop
            answer = feval(str2func(objectTypes(nn).testCommand), serialObject);
            
            % errors it it was a NaN too
            if isnan(answer)
                % errors
                error('Bad instrument response.')
            end

            % if it got this far it didn't error so was successful - assign
            % the value
            instrumentTypes(n) = nn;

            % updates waitbar
            waitbar(1, waitBarHandle, sprintf('A %s is connected to %s...', objectTypes(nn).name, availablePorts{n}))
            
            % if flow control was used, turn the pin back on again
            if flowControlFlag
                % turns the pin back on (stops it misbehaving the next time
                % round)
                serialObject.DataTerminalReady = 'on';
            end
            
            % tidies up
            fclose(serialObject);
            
            % removes objects
            delete(serialObject)

            % breaks out of the loop to try the next COM port
            break
            
        catch
            % tidies up
            delete(serialObject)
            clear serialObject
        end
    end
end

% clears the waitbar
close(waitBarHandle)

% returns all of the comPortNumbers with instrument types higher than 1
% (i.e. not the dummy instrument type)
comPorts = availablePorts(instrumentTypes > 1);
instrumentTypes = instrumentTypes(instrumentTypes > 1);

% if selectedInstruments was supplied, remap the instrument numbers back
% (since objectTypes got stripped down)
if nargin == 2
    % remap the numbers
    instrumentTypes = selectedInstruments(instrumentTypes);
end

Contact us