clf
clc
clearvars -except coeff

delete(daqfind)
figure(1);
set(gcf, 'Units', 'centimeters')
set(gcf, 'PaperUnits','centimeters');
pos = get(gcf,'Position');
set(gcf, 'PaperSize', [pos(3) pos(4)]);
set(gcf, 'PaperPositionMode', 'manual');
set(gcf, 'PaperPosition', [0 0 pos(3) pos(4)]);

GUImode = 'nothing';
capt = 0;
stopit = 0;
saveit = 0;
cont = -1;
changeit = 0;
calib = 0;
sampleFreq = 1000;
secdisp = 5;
numchan = 4;
EMGdata = zeros(secdisp*sampleFreq,numchan);
EMGstore = zeros(secdisp*sampleFreq,numchan);
chan = [2 3 5 6];

%define the capture button
captbutton=uicontrol('style','pushbutton',...
    'string','Capture', ...
    'fontsize',12, ...
    'position',[30,1,100,25], ...
    'callback','GUImode = ''capt'';');

%define the continuous button
contbutton=uicontrol('style','pushbutton',...
    'string','Continuous', ...
    'fontsize',12, ...
    'position',[130,1,100,25], ...
    'callback','if strcmp(GUImode,''cont'') GUImode=''contend''; else GUImode=''contstart''; end');

%define the save button
savebutton=uicontrol('style','pushbutton',...
    'string','Save', ...
    'fontsize',12, ...
    'position',[230,1,100,25], ...
    'callback','GUImode=''save'';');

%define the quit button
quitbutton=uicontrol('style','pushbutton',...
    'string','Quit', ...
    'fontsize',12, ...
    'position',[330,1,100,25], ...
    'callback','GUImode=''stop'';');

%define the calib button
calibbutton=uicontrol('style','pushbutton',...
    'string','Calib', ...
    'fontsize',12, ...
    'position',[460,390,50,25], ...
    'callback','GUImode=''calib'';');

%define the function editable popupmenu field
timebaseVector = [1 2 5 10];
for i=1:length(timebaseVector)
    timeString{i} = num2str(timebaseVector(i));
end
timelist=uicontrol('style','popupmenu',...
    'string',timeString, ...
    'fontsize',12, ...
    'value',3,...
    'position',[430,3,100,25],...
    'callback','changeit=1; secdisp = timebaseVector(get(timelist,''Value''));');

%define some static text
titletext=uicontrol('style','text',...
    'string','OptoMyoGram',...
    'fontsize',12, ...
    'position',[225,393,120,20]);

%define some static text
calibtext=uicontrol('style','text',...
    'string','------',...
    'background','red',...
    'fontsize',12, ...
    'position',[75,390,75,20]);

% initialize plot command
time = linspace(0,5,length(EMGdata));
H = plot(time,EMGdata);
ylabel('Voltage')
ylim([0 numchan]);

%define the input
adaptor = 'nidaq';
adaptorData = daqhwinfo(adaptor);
id = adaptorData.InstalledBoardIds{1} ;
Fs = 5000;

% Configure the analog input object to trigger manually.
ai = analoginput(adaptor, id);
set(ai, 'SamplesPerTrigger', secdisp*sampleFreq); % 1/100 second
set(ai, 'TriggerRepeat', 1);
set(ai, 'TriggerType', 'manual');
set(ai, 'InputType', 'SingleEnded');
for i=chan
    eval(['ch' num2str(i) ' = addchannel(ai,' num2str(i-1) ');']);
end

% Configure the analog input rate.
set(ai, 'SampleRate', sampleFreq);

% initialize calibration
calibdur = 1;
heurdur = 10;
fingertext = {'Pointer' 'Middle' 'Ring' 'Pinky' 'Thumb' 'Nothing'}; % titles of fingers
heur = zeros(4*heurdur,1); % guess history
if exist('coeff') && ~isempty(coeff) % ask to reuse calibration data
    button = questdlg('Use previous calibration data?');
    if strcmp(button,'No')
        coeff = []; % clear coeff otherwise
    end
else
    coeff = [];
end

while ~strcmp(GUImode,'stop')
    tic;
    
    if changeit % change duration to display
        EMGdata = zeros(secdisp*sampleFreq,numchan);
        EMGstore = zeros(secdisp*sampleFreq,numchan);
        time = linspace(0,secdisp,secdisp*sampleFreq);
        for i=1:numchan % clear graph
            set(H(i),'XData',time,'YData',EMGdata(:,i));
        end
        xlim([0 secdisp]);
        set(ai, 'SamplesPerTrigger', secdisp*sampleFreq); % update plot
        drawnow;
        changeit=0;
    end
    
    switch GUImode
        case 'calib'
            if ~isempty(coeff) % safety check
                button = questdlg('Recalibrate?');
                if strcmp(button,'Yes')
                    coeff = [];
                end
            end
            if isempty(coeff)
                set(ai, 'SamplesPerTrigger', calibdur*sampleFreq);
                for i=1:length(fingertext) % collect data for each finger
                    set(calibtext,'String',fingertext{i});
                    drawnow;
                    uiwait(helpdlg(['Please move your ' lower(fingertext{i}) ' finger for ' num2str(calibdur) ' seconds'])); % prompts
                    set(calibtext,'background','green');
                    start(ai);
                    trigger(ai);
                    [dataRaw,~] = getdata(ai, ai.SamplesPerTrigger); % collect data
                    stop(ai);
                    set(calibtext,'background','red');
                    
                    coeff{i} = princomp(dataRaw); % store coeff
                    
                    EMGdata = dataRaw-repmat(mean(dataRaw),length(dataRaw),1);
                    for j=1:numchan
                        set(H(j),'XData',linspace(0,calibdur,length(dataRaw)),'YData',(EMGdata(:,j)-min(EMGdata(:,j)))/(max(EMGdata(:,j))-min(EMGdata(:,j)))+j-1) %update y vector size
                    end
                    drawnow;
                    pause(2); % allow user to see
                end
            end
            msgbox('Calibration complete');
            set(calibtext,'string','------');
            GUImode = 'nothing';
        case 'capt'
            set(ai, 'SamplesPerTrigger', 60*secdisp*sampleFreq); % update plot
            set(captbutton,'string','-----');   drawnow;
            start(ai);
            trigger(ai);
            [dataRaw,~] = getdata(ai, ai.SamplesPerTrigger); % start daq
            stop(ai);
            
            EMGdata = dataRaw - ones(length(dataRaw),1)*mean(dataRaw); % remove mean
            
            for i=1:numchan % update plot
                set(H(i),'XData',linspace(0,secdisp,60*secdisp*sampleFreq),'YData',EMGdata(:,i)+i-1) %update y vector size
            end
            set(captbutton,'string','Capture');
            GUImode = 'nothing';
        case 'save'
            saveit=0;
            [FileName,PathName] = uiputfile; % prompt user
            print(gcf,'-dpng',[PathName FileName '_plot'],'-r600')
            save([PathName FileName '_EMGdata.txt'],'EMGdata','-ASCII');
            save([PathName FileName '_dataRaw.txt'],'dataRaw','-ASCII');
            msgbox('Saving complete');
            GUImode = 'nothing';
        case 'contstart' % set variables
            set(contbutton,'string','Stop');
            set(ai, 'SamplesPerTrigger', .25*sampleFreq); % 1/4 second
            for i=1:numchan
                set(H(i),'XData',linspace(0,secdisp,secdisp*sampleFreq),'YData',zeros(secdisp*sampleFreq,1)+i-1) %update y vector size
            end
            GUImode = 'cont';
        case 'cont'
            start(ai);
            trigger(ai);
            [dataRaw,~] = getdata(ai, ai.SamplesPerTrigger); % get data chunk
            stop(ai);
            
            EMGstore = [EMGstore(length(dataRaw)+1:end,:); dataRaw]; % keep raw data history
            EMGdata = EMGstore - repmat(mean(EMGstore),length(EMGstore),1); % remove mean
            
            stdvect = zeros(length(fingertext),1); % init std vect
            for j=1:length(fingertext)
                temp = EMGstore*coeff{j};
                stdvect(j) = std(temp(:,end)); % find std of last dim
            end
            [~, ind] = min(stdvect); % find closest fit
            heur = [ind; heur(1:end-1)]; % update heuristic
            guess = mode(heur); % find most common guess
            numoccur = find(heur==guess); % find number of occurances
            
            if guess~=0 && length(numoccur)>length(heur)/2
                set(calibtext,'background','green','string',fingertext{guess}); % over 50% confident
            else
                set(calibtext,'background','red','string','------'); % no idea...
            end
            
            for j=1:numchan % update plot
                set(H(j),'YData',(EMGdata(:,j)-min(EMGdata(:,j)))/(max(EMGdata(:,j))-min(EMGdata(:,j)))+j-1)
            end
        case 'contend'
            set(contbutton,'string','Continuous');
            GUImode = 'nothing';
    end
    pause(.05-toc)
end

close all;
delete(ai);

