%hPDSCHBER PDSCH BER GUI
%   hPDSCHBER() will run a GUI which creates BER
%   curves for the Physical Downlink Shared Channel (PDSCH).

%   Copyright 2009-2015 The MathWorks, Inc.

function varargout = hPDSCHBER(varargin)

    % Begin initialization code - DO NOT EDIT
    gui_Singleton = 1;
    gui_State = struct('gui_Name',       mfilename, ...
                       'gui_Singleton',  gui_Singleton, ...
                       'gui_OpeningFcn', @PDSCHBER_OpeningFcn, ...
                       'gui_OutputFcn',  @PDSCHBER_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

end

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

    % Choose default command line output for
    % hPDSCHBER
    handles.output = [];
    hold off;

    % Choose default command line output for
    % hPDSCHBER
    handles.output = [];
    handles.transportBlkIn = [];
    handles.transportBlkOut = [];
    handles.count = 0;
    handles.overLay = 0;
    % stop flag is set to false
    setappdata(handles.stopSimButton, 'stop', 0);
    set(handles.stopSimButton, 'Enable', 'Off');

    % set used SNR values SNR (Eb/No) values in decibels
    getSNR = get(handles.snrdB, 'String');
    SNR = evalin('caller',getSNR);

    handles.SNR = SNR;

    % QPSK Theoretical
    plotTheoreticalBER('QPSK', SNR);

    printLabels();
    
    axis([SNR(1) SNR(length(SNR)) 1e-6 10]); 

    grid on;
    str{1} = 'Theoretical Curve (QPSK)';
    legend(str);
    handles.str = str;

    % Update handles structure
    guidata(hObject, handles);

    % UIWAIT makes hPDSCHBER wait for user response
    % (see UIRESUME) uiwait(handles.controlPanel);
end

%PDSCHBER_OutputFcn outputs from this function are returned to the command
%line
%   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)
function varargout = PDSCHBER_OutputFcn(~, ~, handles) 

    % Get default command line output from handles structure
    varargout{1} = handles.output;

end

%generate_Callback executes on button press in generate
%   hObject handle to generate (see GCBO) eventdata reserved - to be
%   defined in a future version of MATLAB handles structure with handles
%   and user data (see GUIDATA)
function generate_Callback(hObject, ~, handles) %#ok

    % uiwait(handles.controlPanel);

    % set(handles.generate,'Enable','off');
    % set(handles.clearGraph,'Enable','off');
    % set(handles.modulation,'Enable','off');

    % stop flag is set to false
    setappdata(handles.stopSimButton, 'stop',0);
    set(handles.stopSimButton, 'Enable','On');

    if(handles.overLay == 1)
        hold all;
        handles.count = handles.count + 1;
    elseif(handles.overLay == 0)
        hold off;
        handles.count = 1;
    end

    modulation = get(handles.modulation, 'String');
    selectedMod = modulation{get(handles.modulation, 'Value')};
    handles.pdschMods{handles.count} = selectedMod;

    handles.transportBlkIn = str2double(get(handles.tbIn, 'String'));
    handles.transportBlkOut = str2double(get(handles.tbOut, 'String'));

    val = get(handles.rvValues, 'String');
    if(~isempty(val))
        handles.rv = evalin('caller', val);
    else
        handles.rv = [];
    end

    
    val = get(handles.nTurboItrValue, 'String');
    if(~isempty(val))
        handles.nTurboDecIterations = evalin('caller', val);
    else
        handles.nTurboDecIterations = [];
    end

    switch(selectedMod)
        case 'QPSK'
            bps = 2;
        case '16QAM'
            bps = 4;
        case '64QAM'
            bps = 6;
        case '256QAM'
            bps = 8; 
    end

    getSNR = get(handles.snrdB,'String');
    if ~isempty(getSNR)
        SNR = evalin('caller',getSNR);
    else
        SNR = [];
    end
    handles.SNR = SNR;
    
    if(isempty(handles.SNR))
        set(handles.stopSimButton,'Enable','Off');
        uicontrol(handles.tbIn);
        msgbox('SNR is null', ...
            'SNR','error');
        return;
    end

    if(isnan(double(handles.transportBlkIn)))
        set(handles.stopSimButton,'Enable','Off');
        uicontrol(handles.tbIn);
        msgbox('Transport Block Size is incorrect', ...
            'Transport Block Size','error');
        return;   
    else
     tbIn = handles.transportBlkIn;
    end

    if(isnan(double(handles.transportBlkOut)))
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.tbOut);
        msgbox('Available PDSCH Bits is incorrect', ...
            'Available PDSCH Bits', 'error');
        return;
    elseif(mod(handles.transportBlkOut,bps) > 0)
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.tbOut);
        possible1 = ceil(handles.transportBlkOut/bps)*bps;
        possible2 = floor(handles.transportBlkOut/bps)*bps;
        msgbox(['No. of Available PDSCH Bits are not valid for given ' ... 
            'modulation scheme nearest possible sizes are' ...
            ' ' num2str(possible1) ' ' 'or'  ' ' num2str(possible2)], ...
            'Available PDSCH Bits', 'error');
        return;
    else
     tbOut = handles.transportBlkOut;
    end

    if(isempty(handles.nTurboDecIterations))
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.nTurboItrValue);
        msgbox('Turbo decoder iterations is null', ...
            'Turbo decoder iterations', 'error');
        return;
    elseif(isnan(double(handles.nTurboDecIterations)))
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.nTurboItrValue);
        msgbox('Turbo decoder iterations is incorrect', ...
            'Turbo decoder iterations', 'error');
        return;   
    elseif(handles.nTurboDecIterations<1)
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.nTurboItrValue);
        msgbox('Turbo decoder iterations should be greater than 0', ...
            'Turbo decoder iterations', 'error');
        return;
    end

    if(isempty(handles.rv))
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.rvValues);
        msgbox(['Redundancy Version vector value(s) should be in ' ...
            'the range 0 to 3'], 'Redundancy Value', 'error');
        return;
    elseif(isnan(double(handles.rv)))
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.rvValues);
        msgbox(['Redundancy Version vector value(s) should be in ' ...
            'the range 0 to 3'], 'Redundancy Version', 'error');
        return;   
    elseif(sum((handles.rv(:)<0))>0)
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.rvValues);
        msgbox(['Redundancy Version vector value(s) should be in ' ...
            'the range 0 to 3'], 'Redundancy Version', 'error');
        return;
    elseif(sum(handles.rv(:) > 3))
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.rvValues);
        msgbox(['Redundancy Version vector value(s) should be in ' ...
            'the range 0 to 3'], 'Redundancy Version', 'error');
        return;
    else
     rv = handles.rv;
    end


    modulation = handles.pdschMods{handles.count};
    guidata(hObject, handles);


    set(handles.generate, 'Enable', 'off');
    set(handles.clearGraph, 'Enable', 'off');
    set(handles.modulation, 'Enable', 'off');

    PDSCHBitErrorRateExample_BerCurve(tbIn, tbOut, modulation, rv, ...
        handles);
end

%tbIn_Callback
%   hObject handle to tbIn (see GCBO) eventdata  reserved - to be defined
%   in a future version of MATLAB handles structure with handles and user
%   data (see GUIDATA)
function tbIn_Callback(hObject, ~, handles) %#ok
% hObject    handle to tbIn (see GCBO) eventdata  reserved - to be defined
% in a future version of MATLAB handles    structure with handles and user
% data (see GUIDATA)
    handles.transportBlkIn = str2double(get(hObject,'String'));

    guidata(hObject, handles);

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

end

%tbIn_CreateFcn executes during object creation, after setting all
%properties
% hObject handle to tbIn (see GCBO) eventdata  reserved - to be defined in
% a future version of MATLAB handles empty - handles not created until
% after all CreateFcns called
function tbIn_CreateFcn(hObject, ~, ~) %#ok

    % set(hObject,'String',[]);

    % 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

end

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

    handles.transportBlkOut = str2double(get(hObject, 'String'));
    
    guidata(hObject, handles);

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

end

%tbOut_CreateFcn executes during object creation, after setting all
%properties
%   hObject handle to tbOut (see GCBO) eventdata  reserved - to be defined
%   in a future version of MATLAB handles empty - handles not created until
%   after all CreateFcns called
function tbOut_CreateFcn(hObject, ~, ~) %#ok
    % set(hObject,'String',[]);

    % 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

end

% modulation_Callback executes on selection change in modulation
%   hObject handle to modulation (see GCBO) eventdata reserved - to be
%   defined in a future version of MATLAB handles structure with handles
%   and user data (see GUIDATA)
function modulation_Callback(hObject, ~, handles) %#ok


    modulation = get(hObject, 'String');
    newMod = modulation{get(hObject, 'Value')};

    if(handles.overLay == 0)
        hold off;
        str = [];
        handles.mod = [];
        handles.pdschMod = [];
        handles.str = [];
        handles.count = 0;
        handles.theroCount = 1;
        str{1} = ['Theoretical Curve' ' ' '(' newMod ')'];
        handles.str = str;
        drawCurve = 1;
    else
        match = 0;
        drawCurve = 0;
        for index = 1:handles.theroCount
            if(strcmp(handles.mod{index}, newMod))
                match = match + 1;
            end
        end
        if(match == 0)
            drawCurve = 1;
        end
    end
    count = handles.count;
    str = handles.str;
    len = length(str);
    if(handles.overLay == 1)
        hold all;
        if(drawCurve == 1)
            str{len + 1} = ['Theoretical Curve' ' ' '(' newMod ')'];
        end
    end

    getSNR = get(handles.snrdB,'String');
    if ~isempty(getSNR)
        SNR = evalin('caller',getSNR);
    else
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.nTurboItrValue);
        msgbox('SNR is null', ...
            'SNR', 'error');
        return;
    end

    if(drawCurve == 1)
        handles.theroCount = handles.theroCount + 1;
        handles.mod{handles.theroCount} = newMod;
        
        plotTheoreticalBER(newMod,SNR);
    end

    printLabels();
    
    if(length(SNR)>1)
        axis([SNR(1) SNR(length(SNR)) 1e-6 10]); 
    else
        axis([SNR(1)-1 SNR(1)+1 1e-6 10]); 
    end
    grid on;

    if((count + handles.theroCount) > 4)
        legend(str,'Location','SouthWest');
    else
        legend(str);
    end
    legend(str);
    handles.str = str;
    guidata(hObject, handles);
    % Hints: contents = get(hObject,'String') returns modulation contents
    % as cell array
    %        contents{get(hObject,'Value')} returns selected item from
    %        modulation
end

%modulation_CreateFcn executes during object creation, after setting all
%properties
%   hObject handle to modulation (see GCBO) eventdata  reserved - to be
%   defined in a future version of MATLAB handles empty - handles not
%   created until after all CreateFcns called
function modulation_CreateFcn(hObject, ~, handles) %#ok

    % set(hObject,'String','QPSK');
    modulation = get(hObject,'String');
    set(hObject,'Value',1);
    handles.mod{1} = modulation{get(hObject,'Value')};
    handles.theroCount = 1;
    guidata(hObject, handles);

    % Hint: context menu 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

end

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

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

end

%snrdB_CreateFcn executes during object creation, after setting all
%properties
%   hObject handle to snrdB (see GCBO) eventdata  reserved - to be defined
%   in a future version of MATLAB handles empty - handles not created until
%   after all CreateFcns called
function snrdB_CreateFcn(hObject, ~, ~) %#ok

    % 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

end

%clearGraph_Callback executes on button press in clearGraph
%   hObject handle to clearGraph (see GCBO) eventdata  reserved - to be
%   defined in a future version of MATLAB handles structure with handles
%   and user data (see GUIDATA)
function clearGraph_Callback(hObject, ~, handles) %#ok

    handles.count = 0;
    handles.pdschMods = [];
    handles.mod = [];
    handles.str = [];
    modulation = get(handles.modulation, 'String');
    handles.mod{1} = modulation{get(handles.modulation, 'Value')};
    handles.theroCount = 1;
    guidata(hObject, handles);
    hold off;

    getSNR = get(handles.snrdB, 'String');
    if ~isempty(getSNR)
        SNR = evalin('caller',getSNR);
    else
        set(handles.stopSimButton, 'Enable', 'Off');
        uicontrol(handles.nTurboItrValue);
        msgbox('SNR is null', ...
            'SNR', 'error');
        return;
    end

    % Plot theoretical curves
    switch(handles.mod{1})
        case 'QPSK'
            str{1} = 'Theoretical Curve (QPSK)';
        case '16QAM'
            str{1} = 'Theoretical Curve (16QAM)';        
        case '64QAM'
            str{1} = 'Theoretical Curve (64QAM)';
        case '256QAM'
            str{1} = 'Theoretical Curve (256QAM)';
    end
    
    plotTheoreticalBER(handles.mod{1}, SNR);    
    
    printLabels();
    
    if(length(SNR)>1)
        axis([SNR(1) SNR(length(SNR)) 1e-6 10]); 
    else
        axis([SNR(1)-1 SNR(1)+1 1e-6 10]); 
    end
    grid on;
    legend(str);
    handles.str = str;
    set(handles.generate, 'Enable', 'on');
    set(handles.clearGraph, 'Enable', 'on');
    set(handles.modulation, 'Enable', 'on');
    set(handles.stopSimButton, 'Enable', 'Off');
    guidata(hObject, handles);

end

%checkbox1_Callback executes on button press in checkbox1
%   hObject handle to checkbox1 (see GCBO) eventdata  reserved - to be
%   defined in a future version of MATLAB handles structure with handles
%   and user data (see GUIDATA)
function checkbox1_Callback(hObject, ~, handles) %#ok

    overlay = get(hObject,'Value');

    handles.overLay = overlay;
    guidata(hObject, handles);
    % Hint: get(hObject,'Value') returns toggle state of checkbox1

end

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

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

end

%rvValues_CreateFcn executes during object creation, after setting all
%properties
%   hObject handle to rvValues (see GCBO) eventdata reserved - to be
%   defined in a future version of MATLAB handles empty - handles not
%   created until after all CreateFcns called
function rvValues_CreateFcn(hObject, ~, ~) %#ok

    % 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

end

%stopSimButton_Callback executes on button press in stopSimButton
%   hObject handle to stopSimButton (see GCBO) eventdata  reserved - to be
%   defined in a future version of MATLAB handles structure with handles
%   and user data (see GUIDATA)
function stopSimButton_Callback(~, ~, handles) %#ok

    setappdata(handles.stopSimButton, 'stop', 1);

end

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

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

end

%nTurboItrValue_CreateFcn executes during object creation, after setting
%all properties
%   hObject handle to nTurboItrValue (see GCBO) eventdata reserved - to be
%   defined in a future version of MATLAB handles empty - handles not
%   created until after all CreateFcns called
function nTurboItrValue_CreateFcn(hObject, ~, ~) %#ok

    % 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

end

% PDSCHBitErrorRateExample_BerCurve
function [PDSCHBER,SNR] = PDSCHBitErrorRateExample_BerCurve( ...
   transportBlkSize,codedTransBlkSize,modulation,rv,handles)

    % disp(sprintf('Simulation is running. Please be patient.'));

    % Initializing random number generators
    rng('default');
    
    if(handles.overLay == 1)
        hold all;
    elseif(handles.overLay == 0)
        hold off;
        handles.str = [];
    end

    if(getappdata(handles.stopSimButton,'stop'))
        return;
    end

    % Subframe configuration
    enbConfig.NCellID = 100;
    enbConfig.CyclicPrefix = 'Normal';
    enbConfig.NSubframe = 0;
    enbConfig.CellRefP = 1;

    % Transmission mode configuration for PDSCH
    pdschConfig.NLayers = 1;
    pdschConfig.TxScheme = 'Port0';
    pdschConfig.Modulation = {modulation};
    pdschConfig.RNTI = 100;
    pdschConfig.NTurboDecIts = handles.nTurboDecIterations;
    pdschConfig.CSI = 'On';
    count = handles.count;
    SNR = handles.SNR;
    switch (modulation)
        case 'QPSK'
            bitsPerSym = 2;
        case '16QAM'
            bitsPerSym = 4;
        case '64QAM'
            bitsPerSym = 6;
        case '256QAM'
            bitsPerSym = 8;
    end
    noiseVarfactor = sqrt(2*bitsPerSym);

    idxOffset = 0;
    strMatchResult = strfind(handles.str, [modulation ' Uncoded']);
    vectorResult = cell2mat(strMatchResult);
    drawUncoded = isempty(vectorResult);

    % DL-SCH coding configuration
    rvValues = rv;
    rvValuesSting = num2str(rvValues);

    nItsValuesSting = num2str(pdschConfig.NTurboDecIts);

    % set used SNR values SNR (Eb/No) values in decibels
    snr = 10.^(SNR/10);

    % Initial zero vectors for BER
    PDSCHBER = zeros(length(SNR), 1);
    PDSCHBERuncoded = zeros(length(SNR), 1);
    nErrors = zeros(length(SNR), 1);
    nErrorsUncoded = zeros(length(SNR), 1);
    zeroErrorOcc = 0;
    terminate = 0;
    % blkCounter = 0;

    Nmax = 500; % maximum number of iterations
    NminErr = 10000; % minimum number of errors
    inLen = transportBlkSize;
    inLenUncoded = codedTransBlkSize;
    h = waitbar(0, 'Simulation is running. Please be patient.');

    for k = 1:length(SNR)
        blkCounter = 0;
        drawnow;
        if(getappdata(handles.stopSimButton, 'stop'))
            break;
        end
        for l = 1:Nmax
            drawnow;
            if(getappdata(handles.stopSimButton, 'stop'))
                break;
            end
            % DL-SCH data bits
            dlschBits = randi([0 1],transportBlkSize,1);
            softBuffer = {};
            try
                drawnow;
                for rvIndex = 1:length(rvValues)
                    if(getappdata(handles.stopSimButton, 'stop'))
                        break;
                    end

                    % Transmitted block counter
                    blkCounter = blkCounter + 1;

                    % DLSCH transport channel
                    pdschConfig.RV = rvValues(rvIndex);
                    pdschPayload = lteDLSCH(enbConfig, ...
                        pdschConfig, codedTransBlkSize, dlschBits);

                    % PDSCH modulated symbols
                    pdschSymbols = ltePDSCH(enbConfig, ...
                        pdschConfig, pdschPayload);
                    pdschSize = size(pdschSymbols);

                    % Addition of noise
                    noise = (1/noiseVarfactor)*sqrt(1/snr(k))* ...
                        complex(randn(pdschSize),randn(pdschSize));
                    noisySymbols = pdschSymbols + noise;

                    % PDSCH Rx-side
                    rxCW = ltePDSCHDecode(enbConfig, ...
                        pdschConfig, noisySymbols);
                    % Calculating number of errors
                    pdschUncodedErrors = sum(find( ...
(double(pdschPayload)-double(rxCW{1}>0)))~=0); % number of errors in AWGN            

                    if(zeroErrorOcc < 2)           
                        % DL-SCH turbo decoding
                        [rxBits, blkCRCerr, softBuffer] = ...
lteDLSCHDecode(enbConfig, pdschConfig, transportBlkSize, rxCW{1}, ...
softBuffer);

                        % Calculating number of errors in AWGN
                        pdschRxErrors = sum(find((dlschBits- ...
                            double(rxBits)))~=0);

                        % Add errors to previous error counts
                        nErrors(k) = nErrors(k)+ pdschRxErrors; % AWGN
                    end
                    if(rvIndex == 1)
                        nErrorsUncoded(k) = nErrorsUncoded(k)+ ...
                            pdschUncodedErrors; % AWGN
                    end
                    if(~blkCRCerr)
                        break;
                    end
                end
            catch runError
                close(h);
                set(handles.generate, 'Enable', 'on');
                set(handles.clearGraph ,'Enable', 'on');
                set(handles.modulation, 'Enable', 'on');
    %             disp(sprintf('Simulation is not completed.'));
                disp(runError.message);
                loc1 = find(runError.message == '(');
                loc2 = find(runError.message == ')');
                set(handles.stopSimButton,'Enable','Off');
                if(~isempty(loc1) && ~isempty(loc2))
                    uiwait(msgbox(strcat(runError.message(1:loc1(1)), ...
                        runError.stack(2).name, ...
                        runError.message(loc2(2):end)), ...
                        'PDSCH BER EXAMPLE', 'error')); 
                else
                    uiwait(msgbox(runError.message,'PDSCH BER EXAMPLE', ...
                        'error')); 
                end
                return;
            end
            if(nErrors(k)>NminErr && nErrorsUncoded(k)>NminErr)
                break %terminates the innermost loop
            end
        end
        % Calculate BER by dividing number of successful trials by their
        % total number
        PDSCHBER(k) = nErrors(k)/(inLen*blkCounter);
        PDSCHBERuncoded(k) = nErrorsUncoded(k)/(inLenUncoded*l);

        % Early termination build up
        if(PDSCHBER(k) == 0)
            zeroErrorOcc = zeroErrorOcc + 1;
            if(zeroErrorOcc == 1)
                PDSCHBER(k) = 1e-50;
            end
        end
        switch(modulation)
            case 'QPSK'
                if(SNR(k) > 12)
                    terminate = 1;
                end
            case '16QAM'
                if(SNR(k)> 14)
                    terminate =1;
                end
            case '64QAM'
                if(SNR(k) > 19)
                    terminate = 1;
                end
            case '256QAM'
                if(SNR(k) > 24)
                    terminate = 1;
                end
        end
        if(zeroErrorOcc > 2 && terminate == 1)
            break;
        end
        if(zeroErrorOcc>=2 && drawUncoded==0)
            break;
        end

        try
            waitbar(k/length(SNR), h)
        catch
            setappdata(handles.stopSimButton, 'stop', 1);
            set(handles.generate, 'Enable', 'on');
            set(handles.clearGraph, 'Enable', 'on');
            set(handles.modulation, 'Enable', 'on');
            set(handles.stopSimButton, 'Enable', 'Off');
            msgbox('Current simulation has been stopped', ...
'Warning', 'warn');
            return;
        end
    end
    try
        set(handles.generate, 'Enable', 'on');
        set(handles.clearGraph, 'Enable', 'on');
        set(handles.modulation, 'Enable', 'on');
        close(h)
    catch
        set(handles.stopSimButton, 'Enable', 'Off');
        msgbox('Current simulation has been stopped', 'Warning', 'warn');
        return;
    end

    if(handles.overLay == 0)
        plotTheoreticalBER(modulation, SNR);
    end

    if(handles.overLay == 1)
        if(drawUncoded)
            semilogy(SNR, PDSCHBERuncoded, '^-');
        end
        hold all;
        semilogy(SNR, PDSCHBER, '*-');
    elseif(handles.overLay == 0)
        semilogy(SNR, PDSCHBERuncoded, 'r^-');
        hold all;
        semilogy(SNR, PDSCHBER, 'm*-');
    end
    
    printLabels();

    if(length(SNR)>1)
        axis([SNR(1) SNR(length(SNR)) 1e-6 10]); 
    else
        axis([SNR(1)-1 SNR(1)+1 1e-6 10]); 
    end
    grid on;

    str = handles.str;
    len = length(str);

    if(handles.overLay == 1)
        if(drawUncoded)
            str{len+1} = ['PDSCH ' ...
                handles.pdschMods{count} ' ' 'Uncoded'];
            idxOffset = 1;
        end
        str{len+1+idxOffset} = ['PDSCH ' ...
            handles.pdschMods{count} ' ' 'Coded ' ...
            '(RV Seq [' rvValuesSting '], NIts=' nItsValuesSting ')'];
    else
        str{len+1} = ['Theoretical Curve' ' ' '(' modulation ')'];
        str{len+2} = ['PDSCH ' ...
            handles.pdschMods{count} ' ' 'Uncoded'];
        str{len+3} = ['PDSCH ' ...
            handles.pdschMods{count} ' ' 'Coded ' ...
            '(RV Seq [' rvValuesSting '], NIts=' nItsValuesSting ')'];
    end

    if((count + handles.theroCount) > 4)
        legend(str, 'Location', 'SouthWest');
    else
        legend(str);
    end

    % disp(sprintf('Simulation is completed.'));

    handles.str = str;
    guidata(handles.generate, handles);

    set(handles.generate, 'Enable', 'on');
    set(handles.clearGraph, 'Enable', 'on');
    set(handles.modulation, 'Enable', 'on');
    set(handles.stopSimButton, 'Enable', 'Off');
end

function printLabels()
    xlabel('Eb/N0 [dB]');
    ylabel('BER');
    title('BER curve');
end

function plotTheoreticalBER(modulation, SNR)
    switch(modulation)
        case 'QPSK'
            M = 4;
            plotOptions = 'kd-';
        case '16QAM'
            M = 16;
            plotOptions = 'ko-';
        case '64QAM'
            M = 64;
            plotOptions = 'ks-';
        case '256QAM'
            M = 256;
            plotOptions = 'kh-';
    end
    
    awgnBER = berawgn(SNR,'qam',M);
    semilogy(SNR, awgnBER, plotOptions);
    hold all;
end
