function data = Temperature_Test_Double( ...
    mode, modeParam, delay, fileName, varargin)
%function data = Temperature_Test_Double( ...
%    mode, modeParam, delay, fileName, <Parameters>)
%
%Collects and logs temperature data on the Lakeshore temperature
%controller.
%
%
%INPUTS
%
%mode               Either 'f' or 'a'
%                   The program can be run in two modes.  In the mode with 
%                       mode set to 'f' (follow), the program collects data 
%                       until the temperature "modeParam" is reached. 
%                   In the mode with tempFollow set to 'a' (alone), the program
%                       collects "modeParam" number of data points and is not 
%                       sensitive to any particular temperature.
%
%modeParam          Positive scalar
%                   Represnts either the target temperature in Kelving or 
%                       in ohms or temperautre in Kelvin (follow mode) or 
%                       number of data points (alone mode).
%
%delay              Positive Scalar
%                   Time delay (in seconds) between consecutive data points. The
%                       time between successive points will always be slightly 
%                       longer, as the time for receiving data from the device 
%                       is not counted in this number.
%                   Suggested Value: 1
%
%fileName           File name for output data file
%                   Data file is a comma delimited .csv file containing the data
%                   with the following order of columns
%                       Time Elapsed since First Data Point
%                       Temperature A
%                       Temperature B
%                       Temperature Average
%
%
%OPTIONAL PARAMETERS
%
%SaveFolder         Folder to save output data .csv file.
%                   Default: [pwd]/Data_[YYYYmmDD]/
%
%Units              Units of sensor (either temperature or raw resistance)
%                   Expected: 'K' or 'Ohm'
%                   Default: 'K'
%
%OUTPUTS
%
%data               N x 4 matrix
%                   Contains data in 4 columns:
%                       Time Elapsed
%                       Temperature A
%                       Temperature B
%                       Temperature Average
%
%
%NOTES
%
%If the program exits with errors, call delete(instrfind) at the command
%prompt to reset the hardware connections.
%
%
%ACKNOWLEDGEMENTS
%
%Inspired by supercond_ul.m written by David Tam (tam@phys.columbia.edu) and 
%Benjamin Nachumi (peripatetic1@yahoo.com).
%
%
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
%X Author:          Sky Cheung                                                X
%X Date Created:    21 Feb 2015                                               X
%X Last Modified:   23 Feb 2015                                               X
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
%

%Input Parsing
p = inputParser;

%Defaults
defaultSaveFolder = sprintf('%s\\Data_%s', pwd, datestr(now,'YYYY-mm-DD') );
defaultUnits = 'K';

%Expected
expectedMode = {'a','f'};
expectedUnits = {'K','Ohm'};

%Parsing Conditions for Required Arguments
addRequired(p, 'mode', @(x) any( validatestring( x, ...
    expectedMode) ) );
addRequired(p, 'modeParam', @(x) validateattributes( x, ...
    {'numeric'}, {'nonempty','scalar','nonnegative'} ) );
addRequired(p, 'delay', @(x) validateattributes( x, ...
    {'numeric'}, {'nonempty','scalar','nonnegative'} ) );
addRequired(p, 'fileName', @(x) validateattributes( x, ...
     {'char'}, {'nonempty'} ) );

%Parsing Conditions for Optional Parameters
addParameter(p, 'SaveFolder', defaultSaveFolder, @(x) validateattributes( x, ... 
    {'char'}, {'nonempty'} ) );
addParameter(p, 'Units', defaultUnits, @(x) any( validatestring( x, ...
    expectedUnits) ) );

%Parsing Inputs
parse(p, mode, modeParam, delay, fileName, varargin{:});

%Getting proper inputs
mode = p.Results.mode;
modeParam = p.Results.modeParam;
delay = p.Results.delay;
fileName = p.Results.fileName;
saveFolder = p.Results.SaveFolder;
units = p.Results.Units;

%Delete Stucture
clear p;

%Alone mode parameter must be an integer
if strcmp(mode,'a') && logical( abs( round(modeParam) - modeParam ) > eps )
    error('modeParam must be an integer in alone mode.');
end

%initialize some things
pause on

%Create and open instrument objects, and echo their names
lakeshore = visa('ni','gpib0::12::INSTR');
fopen(lakeshore);
fprintf(lakeshore,'*IDN?');
lakeshoreName = fscanf(lakeshore);
%Removing trailing whitespace
lakeshoreName = strtrim(lakeshoreName);

%Preparing Cleanup function to ensure proper disconnection
finishUp = onCleanup(@() Disconnect_Ports( lakeshore ) );

%Echoing names
fprintf('Successfully connected to:\n%s\n', ...
    lakeshoreName );

%start heater and begin logging data points
fprintf('Strike any key to begin data collection ...\n');
pause;

%Preparing output file
if ~isdir(saveFolder)
    mkdir(saveFolder);
end
fName = sprintf('%s\\%s.txt', saveFolder, fileName);
numColumns = 4;

%Holding plot
hold on;

%Axis Labels
xlabel('Time Elapsed (min)');
if strcmp(units, 'K')
    ylabel('Temperature (K)');
else
    ylabel('Resistance (\Omega)');
end

%Command to acquire sensor temperatures (or resistances)
switch units
    case 'K'
        GetReadingA = sprintf('%sRDG?%s', 'K', 'a');
        GetReadingB = sprintf('%sRDG?%s', 'K', 'b');
    case 'Ohm'
        GetReadingA = sprintf('%sRDG?%s', 'S', 'a'); 
        GetReadingB = sprintf('%sRDG?%s', 'S', 'b');
end %End of sensor command

%Switch for different modes
switch mode
    %Follow Mode
    case 'f'
        %Preallocate Data with 1000 rows
        preallocateNum = 1e3;
        data = zeros(preallocateNum, numColumns);
        dataCount = 1;

        %Start Timer
        timer = tic;
        
        %Get temperature
        fprintf(lakeshore, '%s\n', GetReadingA);
        oldTempA = fscanf(lakeshore,'%f');
        fprintf(lakeshore, '%s\n', GetReadingB);
        oldTempB = fscanf(lakeshore,'%f');
        %Computing Average
        oldTempAvg = 0.5 * (oldTempA + oldTempB);
        
        %Sign of the difference
        oldTempSign = sign(oldTempAvg - modeParam);
    
        newTempSign = oldTempSign;
        
        currentTime = 0;
        %While loop to continually collect data until the sign of the difference
        %has changed (crossover of target temperature)
        while isequal(newTempSign, oldTempSign)
            %Check if extra rows need to be added
            if mod(dataCount,preallocateNum) == 0
                %Add 1000 extra rows
                data = [data; zeros(preallocateNum, numColumns)];
            end
            %Acquiring current temperature
            fprintf(lakeshore, '%s\n', GetReadingA);
            newTempA = fscanf(lakeshore,'%f');
            fprintf(lakeshore, '%s\n', GetReadingB);
            newTempB = fscanf(lakeshore,'%f');
            %Average
            newTempAvg = 0.5 * (newTempA + newTempB);
            
            if currentTime ~= 0
                %Get time elapsed in minutes
                currentTime = toc(timer) / 60;
            end
            
            %Sign of the difference
            newTempSign = sign(newTempAvg - modeParam);
            
            %New Data
            newData = ...
                [currentTime, newTempA, newTempB, newTempAvg];
            
            %Write new data to file
            dlmwrite( fName, newData, ...
                'delimiter', ',', ...
                'newline', 'pc', ...
                'precision', '%.6e', ...
                '-append');
            
            %Update Plot
            plot(currentTime, newTempA, 'r+' );
            plot(currentTime, newTempB, 'b+' );
            plot(currentTime, newTempAvg, 'm+' );

            %Storing current measurements into data matrix
            data(dataCount,:) = newData;
            
            %Increment Data Count
            dataCount = dataCount + 1;
            %Delay
            pause(delay);
            %Changing current time for if statement (other than 0)
            currentTime = 1;
        end %End of while loop
        %Stripping away extra preallocated rows
        data = data(any(data,2),:);
    %End of Follow Mode
    
    %Alone Mode
    case 'a'
        %Preallocate Data
        data = zeros(modeParam, numColumns);
        
        %For loop for alone mode
        for j = 1:modeParam
            %Acquiring Temperatures
            fprintf(lakeshore, '%s\n', GetReadingA);
            newTempA = fscanf(lakeshore,'%f');
            fprintf(lakeshore, '%s\n', GetReadingB);
            newTempB = fscanf(lakeshore,'%f');
            %Average
            newTempAvg = 0.5 *(newTempA + newTempB);
            
            if j == 1
                %Start Timer
                timer = tic;
                currentTime = 0;
            else
                %Get time elapsed in minutes
                currentTime = toc(timer) / 60;
            end
            
            %New Data
            data(j,:) = ...
                [currentTime, newTempA, newTempB, newTempAvg];
            
            %Write new data to file
            dlmwrite( fName, data(j,:), ...
                'delimiter', ',', ...
                'newline', 'pc', ...
                'precision', '%.6e', ...
                '-append');
            
            %Update Plot
            plot(currentTime, newTempA, 'r+' );
            plot(currentTime, newTempB, 'b+' );
            plot(currentTime, newTempAvg, 'm+' );
            
            %Delay
            pause(delay);
        end %End of alone mode for loop
    %End of alone mode
    
end %End of switch for mode

end %End of Temperature_Test_Double.m

%Disconnect upon completion
function Disconnect_Ports(lakeshore)
    %Lakeshore
    fprintf('Removing Lakeshore connection.\n');    
    fclose(lakeshore);
    
    fprintf('Disconnecting ports.\n');  
    delete(instrfind);
    
    fprintf('Successfully disconnected.\n');  
end %End of Disconnect_Ports
