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.

transitionalgorithmgui.m
function varargout = transitionalgorithmgui(varargin)
% TRANSITIONALGORITHMGUI M-file for transitionalgorithmgui.fig
%      TRANSITIONALGORITHMGUI, by itself, creates a new TRANSITIONALGORITHMGUI or raises the existing
%      singleton*.
%
%      H = TRANSITIONALGORITHMGUI returns the handle to a new TRANSITIONALGORITHMGUI or the handle to
%      the existing singleton*.
%
%      TRANSITIONALGORITHMGUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in TRANSITIONALGORITHMGUI.M with the given input arguments.
%
%      TRANSITIONALGORITHMGUI('Property','Value',...) creates a new TRANSITIONALGORITHMGUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before transitionalgorithmgui_OpeningFunction gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to transitionalgorithmgui_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help transitionalgorithmgui

% Last Modified by GUIDE v2.5 22-Aug-2009 13:41:32

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @transitionalgorithmgui_OpeningFcn, ...
                   'gui_OutputFcn',  @transitionalgorithmgui_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before transitionalgorithmgui is made visible.
function transitionalgorithmgui_OpeningFcn(hObject, eventdata, handles, mainGuiHandle, mainGuiHandles)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to transitionalgorithmgui (see VARARGIN)

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

% stashes away the handles
handles.mainGuiHandle = mainGuiHandle;
handles.mainGuiHandles = mainGuiHandles;
                            
% defines the instrument types and parameters
handles.instrumentClasses = {'press', 'temp'};
handles.parameterClasses = {'menu', 'min', 'max', 'increment', 'rate', 'equilibration'};

% this list is necessary because not all of the names appear at the end!
handles.parameterClassesLast = [true, false, false, true, true, true];

% pre-allocates an array containing all the fields in
handles.allParameters = zeros(numel(handles.instrumentClasses), numel(handles.parameterClasses));

% for each class
for m = 1:numel(handles.instrumentClasses)
    % for each parameter
    for mm = 1:numel(handles.parameterClasses)
        % defines a string
        if handles.parameterClassesLast(mm)
            % put it at the end
            handleString = [handles.instrumentClasses{m}, capitalise(handles.parameterClasses{mm})];
            
        else
            % put it at the beginning
            handleString = [handles.parameterClasses{mm}, capitalise(handles.instrumentClasses{m})];
        end
        
        % forms the handle
        handles.allParameters(m, mm) = handles.(handleString);
    end
end

% defines each instrument (row)
for n = 1:numel(handles.instrumentClasses)
    % defines a column
    handles.(handles.instrumentClasses{n}) = handles.allParameters(n, :);
end

% defines each parameter type
for o = 1:numel(handles.parameterClasses)
    % defines a row
    handles.([handles.parameterClasses{o}, 's']) = handles.allParameters(:, o);
end

% number of pumps
pumps = 2;

% pre-allocates the menus and flow
handles.pumpMenus = zeros(pumps, 1);
handles.flow = zeros(pumps, 1);

% one for the pump menus and the flows
for p = 1:pumps
    % defines the pump menus
    handles.pumpMenus(p) = handles.(sprintf('pumpMenu%d', p));
    handles.flow(p) = handles.(sprintf('flow%d', p));
end

% defines the fields for the algorithm
handles.algorithmParameters = [ handles.equilibrateBefore;...
                                handles.flushSpeed];
                            
% tacks them on to the end for an "all fields" handle (need to unpack the
% array of all parameters to form a column vector)
handles.allFields = [   handles.allParameters(:);...
                        handles.tempMenu2;...
                        handles.useTemp2;...
                        handles.pumpMenus;...
                        handles.flow;...
                        handles.usePump2;...
                        handles.pumpEquilibration;...
                        handles.algorithmParameters];

% gets the details of the current instruments
objectConfig = getappdata(mainGuiHandle, 'objectConfig');

% fill all the menus with the instruments
set([handles.menus; handles.tempMenu2; handles.pumpMenus], 'String', {objectConfig(1:8).name}')

% for each instrument, try and match it with the following pairs of
% parameters
matchParameters = { 'class', 'bpr';...
                    'class', 'temp'};
                
% for each instrument
for p = 1:numel(handles.instrumentClasses)
    % tries to match it
    index = findinstrument(mainGuiHandle, matchParameters{p, 1}, matchParameters{p, 2});

    % if it found something, use the last one (leave it at 1 otherwise)
    if ~isempty(index)
        % changes the menu index
        set(handles.menus(p), 'Value', index(end))
    end
end

% finds the temperature controllers again
tempIndex = findinstrument(mainGuiHandle, 'class', 'temp');

% if there were more than one, pick the second last one as the pre-heater,
% otherwise, disable the temperature slaving
if numel(tempIndex) > 1
    % select it
    set(handles.tempMenu2, 'Value', tempIndex(end - 1))
    
else
    % turn the slaving off (it's on by default)
    set(handles.useTemp2, 'Value', 0)
    
    % runs the callback to correctly disable fields
    useTemp2_Callback(handles.useTemp2, eventdata, handles)
end

% searches for the pumps
pumpIndex = findinstrument(mainGuiHandle, 'class', 'pump');

% if there's more than 1, fill them both, 
if numel(pumpIndex) <= 1
    % fill the first one if there was one
    if ~isempty(pumpIndex)
        % sets the first one
        set(handles.pumpMenu1, 'Value', pumpIndex)
    end
    
    % disable the last one
    set(handles.usePump2, 'Value', 0)
    
    % runs the callback to disable those fields
    usePump2_Callback(handles.usePump2, eventdata, handles)
    
else
    % fill the menus up with the first two (don't need to check the box
    % because the default is to tick it)
    set(handles.pumpMenus, {'Value'}, num2cell(pumpIndex(1:2)))
end
    
% Update handles structure
guidata(hObject, handles)


% --- Outputs from this function are returned to the command line.
function transitionalgorithmgui_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on selection change in pressMenu.
function pressMenu_Callback(hObject, eventdata, handles)
% hObject    handle to pressMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns pressMenu contents as cell array
%        contents{get(hObject,'Value')} returns selected item from pressMenu

% gets the menu index
menuIndex = get(hObject, 'Value');

% decides if the instrument is valid - must be a BPR and be connected
validInstrument = any(menuIndex == findinstrument(handles.mainGuiHandle, 'class', 'bpr')) && getappdata(handles.mainGuiHandle, sprintf('collectDataFlag%d', menuIndex));

% if the current menu value is in the list of current BPRs, enable it,
% otherwise, don't (the handles list excludes the BPR menu itself)
set(handles.press(2:end), 'Enable', onoff(validInstrument))


% --- Executes during object creation, after setting all properties.
function pressMenu_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pressMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in pumpMenu1.
function pumpMenu1_Callback(hObject, eventdata, handles)
% hObject    handle to pumpMenu1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns pumpMenu1 contents as cell array
%        contents{get(hObject,'Value')} returns selected item from pumpMenu1

% gets the menu index
menuIndex = get(hObject, 'Value');

% decides if the instrument is valid - must be a BPR and be connected
validInstrument = any(menuIndex == findinstrument(handles.mainGuiHandle, 'class', 'pump')) && getappdata(handles.mainGuiHandle, sprintf('collectDataFlag%d', menuIndex));

% if the current menu value is in the list of current BPRs, enable it,
% otherwise, don't (the handles list excludes the BPR menu itself)
set(handles.flow1, 'Enable', onoff(validInstrument))


% --- Executes during object creation, after setting all properties.
function pumpMenu1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pumpMenu1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in tempMenu.
function tempMenu_Callback(hObject, eventdata, handles)
% hObject    handle to tempMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns tempMenu contents as cell array
%        contents{get(hObject,'Value')} returns selected item from tempMenu

% gets the menu index
menuIndex = get(hObject, 'Value');

% decides if the instrument is valid - must be a temperature controller and
% be connected
validInstrument = any(menuIndex == findinstrument(handles.mainGuiHandle, 'class', 'temp')) && getappdata(handles.mainGuiHandle, sprintf('collectDataFlag%d', menuIndex));

% if the current menu value is in the list of current BPRs, enable it,
% otherwise, don't (the handles list excludes the BPR menu itself)
set(handles.temp(2:end), 'Enable', onoff(validInstrument))


% --- Executes during object creation, after setting all properties.
function tempMenu_CreateFcn(hObject, eventdata, handles)
% hObject    handle to tempMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Breaks the field up
function fieldDetails = getFieldDetails(hObject)

% gets the parent
fieldDetails.parent = getfigure(hObject);

% retrives the handles
handles = guidata(fieldDetails.parent);

% gets the field tag (stored because you might as well)
fieldDetails.tag = get(hObject, 'Tag');

% finds its index
fieldDetails.index = find(strfindcell(handles.instrumentClasses, fieldDetails.tag));

% finds out which instrument it is
fieldDetails.instrument = handles.instrumentClasses{fieldDetails.index};

% finds which parameter it is (replaces the instrument name in the tag with
% a blank)
fieldDetails.parameter = strrep(fieldDetails.tag, fieldDetails.instrument, '');


% --- Generic increment checking callback
function checkIncrement(hObject, eventdata, handles)
% hObject    handle to whatever called this
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% gets the field information
fieldDetails = getFieldDetails(hObject);

% get numbers
minParameter = str2double(get(handles.([fieldDetails.instrument, 'Min']), 'String'));
maxParameter = str2double(get(handles.([fieldDetails.instrument, 'Max']), 'String'));

% if start and end have been filled in, make sure that they are smaller
% than the range between the two
if ~isnan(minParameter) && ~isnan(maxParameter)
    % get more numbers
    incrementParameter = str2double(get(hObject, 'String'));
    range = abs(minParameter - maxParameter);
    
    % gets the object information
    objectTypes = getappdata(handles.mainGuiHandle, 'objectTypes');
    objectConfig = getappdata(handles.mainGuiHandle, 'objectConfig');
    
    % gets the object type
    objectNumber = get(handles.([fieldDetails.instrument, 'Menu']), 'Value');
    objectType = objectConfig(objectNumber).type;
    
    % gets the increment value
    setPointResolution = objectTypes(objectType).([objectTypes(objectType).mainSetField, 'Resolution']);

    % checks to see that the increment is smaller than or equal to the gap
    if ~isnumber(incrementParameter) || ~incrementParameter || incrementParameter > range || incrementParameter < setPointResolution
        % brings up an error dialog
        warntooltip(hObject, 'The increment must be a positive number smaller than the parameter range, but larger than the resolution of the instrument.')
        
        % clears the box
        set(hObject,'String','')
    end
end


function pressIncrement_Callback(hObject, eventdata, handles)
% hObject    handle to pressIncrement (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of pressIncrement as text
%        str2double(get(hObject,'String')) returns contents of pressIncrement as a double

% calls generic increment callback
checkIncrement(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function pressIncrement_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pressIncrement (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function tempIncrement_Callback(hObject, eventdata, handles)
% hObject    handle to tempIncrement (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of tempIncrement as text
%        str2double(get(hObject,'String')) returns contents of tempIncrement as a double

% calls generic increment callback
checkIncrement(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function tempIncrement_CreateFcn(hObject, eventdata, handles)
% hObject    handle to tempIncrement (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function pressRate_Callback(hObject, eventdata, handles)
% hObject    handle to pressRate (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of pressRate as text
%        str2double(get(hObject,'String')) returns contents of pressRate as a double

% calls the generic number checking callback
checkPositiveNonZeroNumeric(hObject, eventdata, handles)



% --- Executes during object creation, after setting all properties.
function pressRate_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pressRate (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function flushSpeed_Callback(hObject, eventdata, handles)
% hObject    handle to flushSpeed (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of flushSpeed as text
%        str2double(get(hObject,'String')) returns contents of flushSpeed as a double

% calls the generic number checking callback
checkPositiveNonZeroNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function flushSpeed_CreateFcn(hObject, eventdata, handles)
% hObject    handle to flushSpeed (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function tempRate_Callback(hObject, eventdata, handles)
% hObject    handle to tempRate (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of tempRate as text
%        str2double(get(hObject,'String')) returns contents of tempRate as a double

% calls the generic number checking callback
checkPositiveNonZeroNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function tempRate_CreateFcn(hObject, eventdata, handles)
% hObject    handle to tempRate (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function pressEquilibration_Callback(hObject, eventdata, handles)
% hObject    handle to pressEquilibration (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of pressEquilibration as text
%        str2double(get(hObject,'String')) returns contents of pressEquilibration as a double

% calls the generic number checking callback
checkPositiveNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function pressEquilibration_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pressEquilibration (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function pumpEquilibration_Callback(hObject, eventdata, handles)
% hObject    handle to pumpEquilibration (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of pumpEquilibration as text
%        str2double(get(hObject,'String')) returns contents of pumpEquilibration as a double

% calls the generic number checking callback
checkPositiveNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function pumpEquilibration_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pumpEquilibration (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function tempEquilibration_Callback(hObject, eventdata, handles)
% hObject    handle to tempEquilibration (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of tempEquilibration as text
%        str2double(get(hObject,'String')) returns contents of tempEquilibration as a double

% calls the generic number checking callback
checkPositiveNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function tempEquilibration_CreateFcn(hObject, eventdata, handles)
% hObject    handle to tempEquilibration (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in startButton.
function startButton_Callback(hObject, eventdata, handles)
% hObject    handle to startButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of startButton

% gets the state
toggleState = get(hObject, 'Value');

% enables/disables all the fields accordingly
set(handles.allFields, 'Enable', onoff(~toggleState))

% if it was pushed down
if toggleState
    % tries
    try
        % retrieves the object information
        objectConfig = getappdata(handles.mainGuiHandle, 'objectConfig');
        objectTypes = getappdata(handles.mainGuiHandle, 'objectTypes');

        % gets the parameters
        minParameter = cellfun(@str2double, get(handles.mins, 'String'));
        maxParameter = cellfun(@str2double, get(handles.maxs, 'String'));
        increment = cellfun(@str2double, get(handles.increments, 'String'));
        rate = cellfun(@str2double, get(handles.rates, 'String'));
        equilibrationTime = cellfun(@str2double, get(handles.equilibrations, 'String'));

        % calculates a range
        range = abs(maxParameter - minParameter);

        % defines a ramp time (in seconds)
        rampTime = (range ./ rate) * 60;

        % gets the object numbers
        objectNumber = cell2mat(get(handles.menus, 'Value'));
        objectType = [objectConfig(objectNumber).type];
        command = cellfun(@str2func, {objectTypes(objectType).mainCommand}, 'UniformOutput', false);

        % need to generate a ramp timer for each object (can't do arrays of
        % timers - they're not defined - can only do vectors)
        for m = 1:numel(handles.instrumentClasses)
            % defines the serial object
            serialObject(m) = getappdata(handles.mainGuiHandle, sprintf('serialObject%d', objectNumber(m)));

            % generates the timer - key features are that the StopFcn has been
            % set to empty, so that it doesn't delete itself when it gets
            % stopped.
            transitionTimers(m) = ramp( serialObject(m),...
                                        command{m},...
                                        minParameter(m),...
                                        maxParameter(m),...
                                        increment(m),...
                                        rampTime(m),...
                                        'Tag', 'transitionRampTimer',...
                                        'StopFcn', '');

            % define collect data flag
            collectDataFlag = sprintf('collectDataFlag%d', serialObject(m).UserData.objectNumber);
            
            % turns the collect data flag off
            setappdata(handles.mainGuiHandle, collectDataFlag, false)
                                   
            % send the start parameter to the object (done for all timers)
            try
                % tries DEBUG turned off for speed
                feval(command{m}, serialObject(m), minParameter(m))

            catch
                % warning
                warning('transitionTimer:startFailure', 'Could not send initial parameter to the serial object.')
            end
            
            % turns the flag back on
            setappdata(handles.mainGuiHandle, collectDataFlag, true)
        end

        % stores each one more usefully
        pressTimer = transitionTimers(1);
        tempTimer = transitionTimers(2);

        % dodgy bootstrap for the temperature controllers to tie the pre-heater
        % to the main temperature controller
        if get(handles.useTemp2, 'Value')
            % generates the timer (it starts itself) - the timer is not
            % actually manipulated as a variable
            linkTimer = linkvalue(  serialObject(2),...
                                    @tempobjreadsettemp,...
                                    getappdata(handles.mainGuiHandle, sprintf('serialObject%d', get(handles.tempMenu2, 'Value'))),...
                                    @tempobjwritesettemp,...
                                    'Period', 30,...
                                    'Tag', 'tempLinkTimer');
        end

        % store them in the main GUI's appdata
        setappdata(handles.mainGuiHandle, 'transitionTimers', transitionTimers)
        setappdata(handles.mainGuiHandle, 'pressTimer', pressTimer)
        setappdata(handles.mainGuiHandle, 'tempTimer', tempTimer)

        % finds the pump details

        % gets pump 1
        pumpSerialObjects = getappdata(handles.mainGuiHandle, sprintf('serialObject%d', get(handles.pumpMenu1, 'Value')));

        % gets the flow rates (this will break if the box is empty)
        flowRatesString = get(handles.flow1, 'String');
        
        % if it was empty, then error
        if isempty(flowRatesString)
            % error
            error('Flow rates for pump 1 is empty.')
        end
        
        % processes them
        flowRates = textscan(flowRatesString, '%n');
        flowRates = flowRates{1}';

        % define collect data flag
        collectDataFlag = sprintf('collectDataFlag%d', pumpSerialObjects.UserData.objectNumber);

        % turns the collect data flag off
        setappdata(handles.mainGuiHandle, collectDataFlag, false)
        
        % send the first one
        try
            % send it
            pumpobjwriteflow(pumpSerialObjects, flowRates(1))

        catch
            % warnings
            warning('First pump flow rate was not set.')
        end
        
        % turns the collect data flag back on
        setappdata(handles.mainGuiHandle, collectDataFlag, true)

        % if pump 2 is selected, get pump 2 as well
        if get(handles.usePump2, 'Value')
            % adds that
            pumpSerialObjects(2) = getappdata(handles.mainGuiHandle, sprintf('serialObject%d', get(handles.pumpMenu2, 'Value')));

            % gets the flow rates
            flowRateString = get(handles.flow2, 'String');
            
            % gets the flow rates (this will break if the box is empty)
            flowRatesScan = textscan(flowRateString, '%n');
            flowRatesScan = flowRatesScan{1}';

            % if the number of items is not the same, then error
            if size(flowRatesScan) ~= size(flowRates)
                % error
                error('There must be the same number of flow rates for each pump.')
            end
            
            % concatenate them vertically
            flowRates(2, :) = flowRatesScan;
            
            % define collect data flag
            collectDataFlag = sprintf('collectDataFlag%d', pumpSerialObjects(2).UserData.objectNumber);

            % turns the collect data flag off
            setappdata(handles.mainGuiHandle, collectDataFlag, false)

            % send the first one
            try
                % send it
                pumpobjwriteflow(pumpSerialObjects(2), flowRates(2, 1))

            catch
                % warnings
                warning('Second pump flow rate was not set.')
            end
            
            % turns the collect data flag back on
            setappdata(handles.mainGuiHandle, collectDataFlag, true)
        end

        % create timer to monitor the progress, and detect the transitions -
        transitionMonitor = timer(  'TimerFcn', {   @transitionMonitorCallback,...
                                                    handles.mainGuiHandle,...
                                                    pumpSerialObjects,...
                                                    flowRates,...
                                                    equilibrationTime,...
                                                    str2double(get(handles.pumpEquilibration, 'String')) * 60},...
                                                    'ErrorFcn', @transitionMonitorError,...
                                                    'ExecutionMode', 'fixedRate',...
                                                    'Period', 60,...
                                                    'BusyMode', 'drop',...
                                                    'Tag', 'transitionDetection',...
                                                    'UserData', struct( 'timerStart', now,...
                                                                        'timerEnd', [],...
                                                                        'transitionTime', 0,...
                                                                        'transitionUnchangedCounter', 0,...
                                                                        'compositionIndex', 1));

        % if equilibrate before is on, need to send out the initial numbers
        if get(handles.equilibrateBefore, 'Value')
            % start the timers later
            startat([pressTimer; transitionMonitor], now + (equilibrationTime(1) / (60 * 24)))

        else
            % start the press ramp and monitor timers normally
            start([pressTimer; transitionMonitor])
        end

        % DEBUG
        assignin('base', 'tts', transitionTimers)
        assignin('base', 'tm', transitionMonitor)
        assignin('base', 'pt', pressTimer)
        assignin('base', 'tt', tempTimer)

    catch
        % gets the last error
        le = lasterror;
        
        % defines the error message
        errorMessage = 'Could not start transition.';
        
        % if the last error isn't empty, append it
        if ~isempty(le.message)
            % append
            errorMessage = {errorMessage; le.message};
        end
        
        % display a tooltip error
        warntooltip(hObject, errorMessage)
        
        % display it DEBUG
        if iscellstr(errorMessage)
            % displays both lines separately
            disp(errorMessage{1})
            disp(errorMessage{2})
            
        else
            % display it normally
            disp(errorMessage)
        end
        
        % defines the list of possible timers for cleanup
        cleanUpVar = {'transitionTimers', 'linkTimer', 'transitionMonitor'};
        
        % for each object
        for m = 1:numel(cleanUpVar)
            % deletes the timers if need be
            if exist(cleanUpVar{m}, 'var')
                % delete it
                delete(eval(cleanUpVar{m}))
                
            else
                % leave the loop (since these were created in order, the
                % rest of the timers have, by definition, have not been
                % created)
                break
            end
        end
        
        % unpresses the button
        set(hObject, 'Value', 0)
        
        % enables all the fields again
        set(handles.allFields, 'Enable', 'on')
        
        % runs the call backs for the use temp and use pump to correctly
        % enable the fields
        useTemp2_Callback(handles.useTemp2, eventdata, handles)
        usePump2_Callback(handles.usePump2, eventdata, handles)
    end
    
else
    % delete all of the timers involved here
    delete(timerfindall('Tag', 'transitionDetection'))
    delete(timerfindall('Tag', 'transitionRampTimer'))
    delete(timerfindall('Tag', 'tempLinkTimer'))
end


% --- Key callback for making the algorithm detection work
function transitionMonitorCallback(timerObject, eventdata, mainGuiHandle, pumpSerialObjects, flowRates, equilibrationTime, pumpEquilibrationTime)

% fetches the transition timers
transitionTimers = getappdata(mainGuiHandle, 'transitionTimers');
pressTimer = getappdata(mainGuiHandle, 'pressTimer');
tempTimer = getappdata(mainGuiHandle, 'tempTimer');

% checks the validity of the timers
if ~all(isvalid(transitionTimers))
    % display a warning
    warning('transitionCallback:invalidTimer', 'One or more of the transition timers are invalid. Timer has been stopped.')
    
    % stop the timer
    stop(timerObject)
    
    % DEBUG - displays all the current timers
    disp(timerfindall)

else
    % fetches this timer's userdata
    userData = timerObject.UserData;
    
    % gets the transition timers user data
    transitionUserData = transitionTimers.UserData;
    
    % concatenates it (this way is more robust since it deals with fields
    % that don't match)
    transitionUserData = catstructs(transitionUserData{:});
    
    % timers reached the end? (this is used later again)
    reachedEnd = [transitionUserData.reachedEnd];
    
    % checks that the timer start is not later than the current time (this
    % piece of data is filled in at the startat command, i.e. in the
    % future)
    if userData(end).timerStart < now || any(reachedEnd)
        % defines the current timer as the one that is running (bit of a
        % ropey condition - could be better)
        currentTimerIndex = find(isrunning(transitionTimers));

        % defines the current timer
        currentTimer = transitionTimers(currentTimerIndex);

        % defines the next timer as being the next one in the pecking order - if it
        % is the last one, goes back to zero
        if currentTimerIndex == 1
            % set it to 1
            nextTimerIndex = 2;
            nextTimer = tempTimer;

        else
            % sets it to the next one
            nextTimerIndex = 1;
            nextTimer = pressTimer;
        end

        % fetch the pressure drop index
        dropIndex = getappdata(mainGuiHandle, 'pressDropChannel') + 1;

        % get the pico data
        picoData = getappdata(mainGuiHandle, 'picoData');
        picoDataTicker = getappdata(mainGuiHandle, 'picoDataTicker');

        % strips out the unwritten stuff to keep the memory footprint down
        picoData = picoData(1:picoDataTicker - 1, :);

        % then only selects the data that was collected since the last timer
        % was started
        picoData = picoData(picoData(:, 1) > userData(end).timerStart, :);
        
        % only goes any further if there is some data left
        if ~isempty(picoData)        
            % backup the old data (should remove this to keep the memory
            % footprint down)
            oldPicoData = picoData;

            % DATA PROCESSING - currently using a 15 rotation on the data - should
            % work regardless of the direction of the pressure drop

            % if its a temperature ramp, we need to flip the data horizontally
            % (like a book) (or a pressure ramp downwards - but this has not
            % been implemented yet)
            if currentTimerIndex == 2
                % inverts all the rows apart from the first row - so the
                % rotation works correctly
                picoData(:, 2:end) = flipud(picoData(:, 2:end));

                % uses a gentler slope
                slopeA = tand(-20);

            else
                % uses a steeper slope for pressure ramps
                slopeA = tand(-13);
            end

            % coordinate transformation to change the scale - removes any
            % offset
            picoData(:, 1) = picoData(:, 1) - picoData(1, 1);

            % changes the size to make the data set "square"
            picoData(:, 1) = (picoData(:, 1) / picoData(end, 1)) * max(picoData(:, dropIndex));

            % calculate the slope of the perpendicular line
            slopeB = - (1 / slopeA);

            % this was originally done element by element in a loop, but it has
            % been migrated across to vectorised operation, and is ~7 times faster
            % as a result.  although it is more complicated, the original code is
            % retained to understand the processing better

            % pre-allocates the distance vector
            %dist = zeros(size(splitData{n}, 1), 1);

            % calculates the distance between that point and y = -x, if drawing
            % a line y = x (calculated on paper)

            % for a line y = mA*x, y - mA*x = 0

            % for a line y = mBx + c, y - mBx - c = 0, where c is the y
            % intercept if the line continues on to the y-axis, but mA * mB =
            % -1, so we can substitute in mB = - (1 / mA), so that... y = c -
            % (x / mA), or y + (x / mA) - c = 0

            % solving the two simultaneously (adding them together):

            % x = c / (mA - mB), so y = (mA * c) / (mA - mB), i.e. y = mA * x

            % so we need to find c

            % for a line y = mx + c, the gradient is given by:

            % mB = (y2 - y1) / (x2 - x1), where by convention the point (x2,
            % y2) is the "higher" point (in this case the point on the pressure
            % drop curve).  we know mB (slopeB), and we know the pressure drop
            % point (x2 and y2), and we also know that x1 is 0 when it crosses
            % the y axis (x1 is 0). what we don't know is the y intercept, so
            % solving for that... y1 = y2 - mB(x2 - x1), but since x1 is 0...
            % y1 = y2 - (mB * x2)

            % define the points for convenience
            x2 = picoData(:, 1);
            y2 = picoData(:, dropIndex);

            % calculate the y intercept (c) of a y = mB * x type line going
            % through the pressure drop point (for each point - this ia a large
            % matrix operation on the pressure drop)
            c = picoData(:, dropIndex) - (slopeB * picoData(:, 1));

            % intersection
            x1 = c / (slopeA - slopeB);
            y1 = slopeA * x1;

            % calculates the distances between the lines
            dist = sqrt((y2 - y1).^2 + (x2 - x1).^2);

            % gets the minimum distance - the index is the important one, to
            % avoid any awkward coordinate manipulations backwards
            [minDist, minDistIndex] = min(dist);

            % saves the transition DEBUG - this is redone later
            transition = picoData(minDistIndex, 1);

            % gets the figure if its there DEBUG
            plotFigure = getappdata(mainGuiHandle, 'plotFigure');

            % if its empty or not a handle object, generate a new one DEBUG
            if isempty(plotFigure) || ~ishandle(plotFigure)
                % generate a figure DEBUG
                plotFigure = figure;

                % saves it back to appdata DEBUG
                setappdata(mainGuiHandle, 'plotFigure', plotFigure)

            else
                % set the figure to be the current one (without bringing
                % the figure window to the front) DEBUG
                set(0, 'CurrentFigure', plotFigure)
            end

            % need to reprocess the time if we flipped the data
            if currentTimerIndex == 2
                % flip it
                minDistIndex = numel(picoData(:, 1)) - minDistIndex;
            end

            % DEBUG calculates the minimum coordinates
            minX = min(x1);
            minY = min(y1);
            maxX = max(picoData(:, 1));
            maxY = max([picoData(:, dropIndex); dist]);

            % DEBUG
            plot(   picoData(:, 1), picoData(:, dropIndex),...
                    repmat(transition, 2, 1), [picoData(minDistIndex, dropIndex), minDist], '-or',...
                    picoData(:, 1), dist,...
                    x1, y1,...
                    [0, 0], [minY, maxY], '-k',...
                    [minX, maxX], [0, 0], '-k')

            % formats the figure
            set(plotFigure, 'Name', 'Pressure Drop Analysis')

            % formats the plot
            set(get(plotFigure, 'Children'),    'XLim', [minX, maxX],...
                                                'YLim', [minY, maxY])

            % saves the CORRECT transition
            transition = oldPicoData(minDistIndex, 1);
            
        else
            % define it so a NaN so it doesn't pass
            transition = NaN;
        end

        % is it the same as last time?
        if transition == userData(end).transitionTime
            % increment the number of times its OK
            userData(end).transitionUnchangedCounter = userData(end).transitionUnchangedCounter + 1;
            
            % DEBUG
            disp(sprintf('Transition is the same (counter: %d).', userData(end).transitionUnchangedCounter))

        else
            % DEBUG
            disp('Calculated transition has changed, restarting counter.')
            
            % resets it back to 0
            userData(end).transitionUnchangedCounter = 0;

            % records the new transition
            userData(end).transitionTime = transition(1);
            userData(end).data = oldPicoData(minDistIndex, :);
        end
        
        % DEBUG - defines the thresholds for detection - needs to be
        % improved and configurable

        % threshold for consistent transitions - currently set as 20 minutes
        % (the current timer period is 60 s)
        staticTransitionThreshold = (20 * 60) / timerObject.Period;

        % threshold for if nothing is detected - the first run has a much
        % higher fixed threshold until it finds the first transition, when
        % the threshold is much smaller since we already know it is quite
        % close to the phase boundary curve
        if isscalar(userData)
            % set it to 2 hours
            runThreshold = 2 * 60;
            
        else
            % set it to 1 hour DEBUG
            runThreshold = 75;
        end
        
        % calculates the minutes since the beginning of the run
        minsSinceStart = (now - userData(end).timerStart) * 24 * 60;
        
        % time between the transition and the beginning (5 minutes)
        minTransitionTime = 3;
        
        % calculates the time in mins since the beginning of the transition
        transitionMinsSinceStart = (transition - userData(end).timerStart) * 24 * 60;
        
        % assumes the composition won't change, and the next timer won't
        % run either
        changeComposition = false;
        startNextTimer = false;

        % have we reached the threshold for being OK? - this needs to be
        % changed, because sometimes the minimum is the same even though
        % the pressure drop is almost completely flat or featureless, e.g.
        % it picks out a point near the beginning where the transition is
        if userData(end).transitionUnchangedCounter > staticTransitionThreshold && transitionMinsSinceStart > minTransitionTime
            % stop the current timer (deliberately leaving the UserData alone
            % so we can resume the timer again next time we start up) - some
            % issues with the up-down aspect of this
            stop(currentTimer)
            
            % display a message DEBUG
            disp('Transition was successfully detected and confirmed - changing to the next timer.')

            % flag the timer up as being to start next
            startNextTimer = true;

        % has the threshold for stopping the timer completely been reached
        % yet?, or have any of the timers reached the end
        elseif minsSinceStart > runThreshold || any(reachedEnd)
            % stop the timer
            stop(currentTimer)

            % going to change the composition
            changeComposition = true;
            
            % display a message DEBUG
            disp('Changing the composition...')
        end

        % if it was flagged up...
        if startNextTimer
            % record the timer end, because if the next one is being started,
            % then the next one has just been stopped
            userData(end).timerEnd = now;

            % stores the next timer and the counter
            userData(end + 1).timerStart = now + (equilibrationTime(nextTimerIndex) / (60 * 24));
            userData(end).transitionTime = 0;
            userData(end).transitionUnchangedCounter = 0;
            userData(end).compositionIndex = userData(end - 1).compositionIndex;

            % start the next timer after the other time has equilibrated
            % (ideally this would be automated better) - the startat
            % function simply alters the start delay
            startat(nextTimer, userData(end).timerStart)
        end
        
        % if the composition is to be changed... (BAD CODING PRACTICE -
        % should to be rationalised with the one above)
        if changeComposition
            % record the timer end, because if the next one is being started,
            % then the next one has just been stopped
            userData(end).timerEnd = now;
                
            % sees if there are any more flow rates left
            if size(flowRates, 2) > userData(end).compositionIndex
                % stores the next timer and the counter
                userData(end + 1).timerStart = now + (pumpEquilibrationTime / (60 * 24));
                userData(end).transitionTime = 0;
                userData(end).transitionUnchangedCounter = 0;
                userData(end).compositionIndex = userData(end - 1).compositionIndex + 1;

                % send the next composition - for each serial object (does
                % not use numel because its not defined for serial objects)
                for m = 1:prod(size(pumpSerialObjects))
                    % defines the collect data flag
                    collectDataFlag = sprintf('collectDataFlag%d', pumpSerialObjects(m).UserData.objectNumber);
                    
                    % turns the collect data flag off
                    setappdata(mainGuiHandle, collectDataFlag, false)
                    
                    % tries
                    try
                        % sends the command
                        pumpobjwriteflow(pumpSerialObjects(m), flowRates(m, userData(end).compositionIndex))

                    catch
                        % gets the last error
                        le = lasterror;
                        
                        % defines the error message
                        warning('transitionGUI:monitor', 'Did not send the next flow rate.')
                                                
                        % if the last error had something, append it
                        if ~isempty(le.message)
                            % displays it
                            warning('transitionGUI:monitor', le(1).message)
                        end
                        
                        % DEBUG
                        pumpSerialObjects(m)
                        userData(end).compositionIndex
                        m
                        flowRates(m, userData(end).compositionIndex)
                    end
                    
                    % turns it back on
                    setappdata(mainGuiHandle, collectDataFlag, true)
                end

                % need to set the initial values again - for each timer
                for m = 1:prod(size(transitionTimers))
                    % get the timer function and the details out
                    timerFcn = transitionTimers(m).TimerFcn;
                    serialObject = timerFcn{2};
                    collectDataFlag = sprintf('collectDataFlag%d', serialObject.UserData.objectNumber);
                    
                    % gets the timer's user data
                    transitionUserData = transitionTimers(m).UserData;
                    
                    % changes the next parameter to reset it back to the
                    % beginning
                    transitionUserData.nextParameter = transitionUserData.startParameter - transitionUserData.incrementParameter;
                    
                    % changes the reached end (a little redundant, but
                    % makes sure that stuff works)
                    transitionUserData.reachedEnd = false;
                    
                    % saves it back
                    transitionTimers(m).UserData = transitionUserData;
                    
                    % turn the collect data flag off
                    setappdata(mainGuiHandle, collectDataFlag, false)
                    
                    % tries
                    try
                        % sends the command
                        feval(timerFcn{3}, serialObject, transitionUserData.startParameter)

                    catch
                        % displays a warning
                        warning('Did not send initial value resetting command.')
                    end

                    % turns the collect data flag back on
                    setappdata(mainGuiHandle, collectDataFlag, true)
                end
                
                % start the next timer after the other time has equilibrated
                % (ideally this would be automated better) - the startat
                % function simply alters the start delay
                startat(pressTimer, userData(end).timerStart)
            
            else
                % stop this timer - we're done!
                stop(timerObject)
                
                % DEBUG
                disp('Transition timer stopped, reached the end of the run.')
                
                % saves the data to somewhere convenient for later analysis
                picoData = getappdata(handles.mainGuiHandle, 'picoData');
                serialData = getappdata(handles.mainGuiHandle, 'serialData');
                
                % saves them with a dated filename
                save(['transitionscan_', strrep(datestr(now), ':', '_')], 'picoData', 'serialData', 'userData')
            end
        end
        
        % save the user data back
        timerObject.UserData = userData;
        
    elseif sum(isrunning(transitionTimers)) ~= 1
        % displays a warning
        warning('transitionMonitor:noTimers', 'No ramp timers, or more than 1 timer is running at the moment.')
    end
end


% --- Error callback for if it screws up
function transitionMonitorError(timerObject, eventdata)

% brings up an error dialog
errordlg('Transition detection timer has errored and stopped, but has not been deleted.')


% --- Number checking
function checkNumeric(hObject, eventdata, handles)

% defines the number
number = str2double(get(hObject, 'String'));

% checks the number (assumes it is numeric and it is scalar - which is what
% you get from str2double on a string)
if isnan(number) || ~isreal(number) || isinf(number)
    % bring up an error tooltip
    warntooltip(hObject, 'Must use a real, finite number.')
    
    % sets it to empty
    set(hObject, 'String', '')
    
else
    % remove any tooltips if they are there
    delete(findobj(getfigure(hObject), 'UserData', hObject))
end


% --- Number checking
function checkPositiveNumeric(hObject, eventdata, handles)

% defines the number
number = str2double(get(hObject, 'String'));

% checks the number (assumes it is numeric and it is scalar - which is what
% you get from str2double on a string)
if isnan(number) || ~isreal(number) || isinf(number) || number < 0
    % bring up an error tooltip
    warntooltip(hObject, 'Must use a real, finite number greater than or equal to 0.')
    
    % sets it to empty
    set(hObject, 'String', '')
    
else
    % remove any tooltips if they are there
    delete(findobj(getfigure(hObject), 'UserData', hObject))
end


% --- Number checking
function checkPositiveNonZeroNumeric(hObject, eventdata, handles)

% defines the number
number = str2double(get(hObject, 'String'));

% checks the number (assumes it is numeric and it is scalar - which is what
% you get from str2double on a string)
if isnan(number) || ~isreal(number) || isinf(number) || number <= 0
    % bring up an error tooltip
    warntooltip(hObject, 'Must use a real, finite number greater than 0.')
    
    % sets it to empty
    set(hObject, 'String', '')
    
else
    % remove any tooltips if they are there
    delete(findobj(getfigure(hObject), 'UserData', hObject))
end


% --- Checks a list of numbers (flow rates)
function checkPositiveNumericList(hObject, eventdata, handles)

% fetches the string
string = get(hObject, 'String');

% if its empty, do nothing
if ~isempty(string)
    % split it up and unpacks it
    numbers = textscan(string, '%n');
    numbers = numbers{1};
    
    % field tag
    tag = get(hObject, 'Tag');
    
    % if its a pump, fetch the max and min numbers
    if strfind('pump', tag)
        % gets the objectConfig and objectTypes
        objectConfig = getappdata(handles.mainGuiHandle, 'objectConfig');
        objectTypes = getappdata(handles.mainGuiHandle, 'objectTypes');
        
        % gets the field number
        fieldNumberString = tag(isstrprop(tag, 'digit'));
        
        % gets the corresponding instrument number
        objectNumber = get(handles.(['pumpMenu', fieldNumberString]), 'Value');
        objectType = objectConfig(objectNumber).type;
        
        % gets the flows
        minFlow = objectTypes(objectType).minFlow;
        maxFlow = objectTypes(objectType).maxFlow;
        
    else
        % set them to 0 and Inf so that they pass by default
        minFlow = 0;
        maxFlow = Inf;
    end        
    
    % checks the numbers
    if any(isnan(numbers)) || any(isinf(numbers)) || ~isreal(numbers) || any(numbers < 0) || any(numbers < minFlow) || any(numbers > maxFlow)
        % displays a warning tooltip
        warntooltip(hObject, 'Value must be a real number greater than or equal to 0.')
    end
    
else
    % remove any tooltips if they are there
    delete(findobj(getfigure(hObject), 'UserData', hObject))
end


function maxTemp_Callback(hObject, eventdata, handles)
% hObject    handle to maxTemp (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of maxTemp as text
%        str2double(get(hObject,'String')) returns contents of maxTemp as a double

% checks the generic value
checkNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function maxTemp_CreateFcn(hObject, eventdata, handles)
% hObject    handle to maxTemp (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function minPress_Callback(hObject, eventdata, handles)
% hObject    handle to minPress (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of minPress as text
%        str2double(get(hObject,'String')) returns contents of minPress as a double

% checks it
checkPositiveNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function minPress_CreateFcn(hObject, eventdata, handles)
% hObject    handle to minPress (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function flow1_Callback(hObject, eventdata, handles)
% hObject    handle to flow1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of flow1 as text
%        str2double(get(hObject,'String')) returns contents of flow1 as a double

% checks the flow
checkPositiveNumericList(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function flow1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to flow1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function minTemp_Callback(hObject, eventdata, handles)
% hObject    handle to minTemp (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of minTemp as text
%        str2double(get(hObject,'String')) returns contents of minTemp as a double

% checks the generic value
checkNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function minTemp_CreateFcn(hObject, eventdata, handles)
% hObject    handle to minTemp (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in helpButton.
function helpButton_Callback(hObject, eventdata, handles)
% hObject    handle to helpButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of helpButton

% opens a help dialog with the help information in
helpdlg({   '1. Each run starts with a pressure ramp from the minimum value.';...
            '';...
            '2. The pressure-temperature search is conducted for each set of flow rates (must be the same number for each pump).'})


% --- Executes on button press in equilibrateBefore.
function equilibrateBefore_Callback(hObject, eventdata, handles)
% hObject    handle to equilibrateBefore (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of equilibrateBefore


function maxPress_Callback(hObject, eventdata, handles)
% hObject    handle to maxPress (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of maxPress as text
%        str2double(get(hObject,'String')) returns contents of maxPress as a double

% checks it
checkPositiveNumeric(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function maxPress_CreateFcn(hObject, eventdata, handles)
% hObject    handle to maxPress (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in pumpMenu2.
function pumpMenu2_Callback(hObject, eventdata, handles)
% hObject    handle to pumpMenu2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns pumpMenu2 contents as cell array
%        contents{get(hObject,'Value')} returns selected item from pumpMenu2

% gets the menu index
menuIndex = get(hObject, 'Value');

% decides if the instrument is valid - must be a pump and connected
validInstrument = any(menuIndex == findinstrument(handles.mainGuiHandle, 'class', 'pump')) && getappdata(handles.mainGuiHandle, sprintf('collectDataFlag%d', menuIndex));

% if the current menu value is in the list of current pumps, enable it,
% otherwise, don't (the handles list excludes the BPR menu itself)
set(handles.flow2, 'Enable', onoff(validInstrument))
set(handles.usePump2, 'Value', validInstrument)


% --- Executes during object creation, after setting all properties.
function pumpMenu2_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pumpMenu2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function flow2_Callback(hObject, eventdata, handles)
% hObject    handle to flow2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of flow2 as text
%        str2double(get(hObject,'String')) returns contents of flow2 as a double

% checks the flow
checkPositiveNumericList(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function flow2_CreateFcn(hObject, eventdata, handles)
% hObject    handle to flow2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in useTemp2.
function useTemp2_Callback(hObject, eventdata, handles)
% hObject    handle to useTemp2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of useTemp2

% disables the instrument selection for temperature 2
set(handles.tempMenu2, 'Enable', onoff(get(hObject, 'Value')))



% --- Executes on button press in usePump2.
function usePump2_Callback(hObject, eventdata, handles)
% hObject    handle to usePump2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of usePump2

% enables/disables the pump 2 fields accordingly
set([handles.pumpMenu2; handles.flow2], 'Enable', onoff(get(hObject, 'Value')))

% run the pump menu callback to update the other fields if need be (it
% might be an incorrect instrument
pumpMenu2_Callback(handles.pumpMenu2, eventdata, handles)


% --- Executes on selection change in tempMenu2.
function tempMenu2_Callback(hObject, eventdata, handles)
% hObject    handle to tempMenu2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns tempMenu2 contents as cell array
%        contents{get(hObject,'Value')} returns selected item from tempMenu2

% gets the menu index
menuIndex = get(hObject, 'Value');

% decides if the instrument is valid - must be a temperature controller and
% connected
validInstrument = any(menuIndex == findinstrument(handles.mainGuiHandle, 'class', 'temp')) && getappdata(handles.mainGuiHandle, sprintf('collectDataFlag%d', menuIndex));

% if the current menu value is in the list of current temperatire, enable
% it, otherwise, don't (the handles list excludes the temp menu itself),
% also disable the use of the temperature controller as a slave
set(handles.useTemp2,   'Enable', onoff(validInstrument),...
                        'Value', validInstrument)


% --- Executes during object creation, after setting all properties.
function tempMenu2_CreateFcn(hObject, eventdata, handles)
% hObject    handle to tempMenu2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

Contact us