%hScanLTEWaveformViewer launches a viewer to display the decoded information
%   viewer = hScanLTEWaveformViewer creates a viewer interface which contains
%   all widgets corresponding to the decoded information.

%   Copyright 2019 The MathWorks, Inc.

classdef hScanLTEWaveformViewer < handle
    properties
        % Set signal source type
        SignalSourceType = hScanLTEWaveformSourceType.Captured;
    end
    properties (Hidden)
        % Buffers for storing X-data and Y-data. X-data include array of
        % user selected frequencies and Y-data includes all the reference
        % signal measurements corresponding to first, second, and third
        % detected cells
        xValues                             
        yRSRQ1
        yRSRQ2
        yRSRQ3
        yRSRP1
        yRSRP2
        yRSRP3
        yRSSI1
        yRSSI2
        yRSSI3
        Y_low
        Y_high
        % If user selects two frequency ranges, using properties below make
        % sure there is no connection between two ranges
        noLineYband
        noLineXband
        Nofbands = 1
        %Update plot time to time with out clipping using the properties below 
        CenterFreq = 869*1e6:100*1e3:894.0*1e6
        xLowLim = 869
        xHigLim = 894
        yLowLim = -20
        yHigLim = 20
        plotFlag = 0
        %Update decoded information in to the viewer using following fields
        NumCells = 0
        FrequencyCorrection = 0
        validCellArray
        freqCellStartInd = 0
        freqCellCount
        CellFreq
        ValidCellsindex
        RMScount = 0
        ValidFrequencyCount = 0
        NumOfMIBs = 0
        NumOfSIBs = 0
        RSMs = struct('RSRPdBm',NaN,'RSRQdB',NaN,'RSSIdBm',NaN);
        MIBs = struct('NDLRB',[],'DuplexMode',[],'CyclicPrefix',[],'NCellID',[],'NSubframe',[],'CellRefP',[],'PHICHDuration',[],'Ng',[],'NFrame',[]);
        SIBs = struct('RNTI',[],'PRBSet',[],'NLayers',[],'Modulation',[],'RV',[],'TxScheme',[],'crc',[],'SIBMessage','');
        CellsFound
    end
    properties (SetAccess = private, Dependent)
        CellID
        CenterFrequency
        PlotType
    end
    properties (Access = private)
        FileHandle = -1
        FigureHandle = -1
        ParentHandle = -1
        GUIHandles
        pDispStr
    end
    methods
        function obj = hScanLTEWaveformViewer(varargin)
            p = inputParser;
            addParameter(p,'SignalSourceType',hScanLTEWaveformSourceType.Captured);
            addParameter(p,'ParentHandle',-1);
            parse(p,varargin{:});
            obj.SignalSourceType = p.Results.SignalSourceType;
            obj.ParentHandle = p.Results.ParentHandle;
            renderGUI(obj);
            reset(obj);
        end
        function reset(obj)
            % Reset all the fields in the viewer, when user clicks start
            % search button for second time
            obj.xValues = [];
            obj.yRSRQ1 = [];
            obj.yRSRQ2 = [];
            obj.yRSRQ3 = [];
            obj.yRSRP1 = [];
            obj.yRSRP2 = [];
            obj.yRSRP3 = [];
            obj.yRSSI1 = [];
            obj.yRSSI2 = [];
            obj.yRSSI3 = [];
            obj.Y_low = [];
            obj.Y_high = [];
            obj.Nofbands = 1;
            obj.CenterFreq = 869*1e6:100*1e3:894.0*1e6;
            obj.xLowLim = 869;
            obj.xHigLim = 894;
            obj.yLowLim = -20;
            obj.yHigLim = 20;
            obj.plotFlag = 0;
            obj.NumCells = 0;
            obj.FrequencyCorrection = 0;
            obj.validCellArray = [];
            obj.freqCellStartInd = 0;
            obj.freqCellCount = 0;
            obj.CellFreq = [];
            obj.ValidCellsindex = [];
            obj.RMScount = 0;
            obj.ValidFrequencyCount = 0;
            obj.NumOfMIBs = 0;
            obj.NumOfSIBs = 0;
            obj.RSMs = struct('RSRPdBm',NaN,'RSRQdB',NaN,'RSSIdBm',NaN);
            obj.MIBs = struct('NDLRB',[],'DuplexMode',[],'CyclicPrefix',[],'NCellID',[],'NSubframe',[],'CellRefP',[],'PHICHDuration',[],'Ng',[],'NFrame',[]);
            obj.SIBs = struct('RNTI',[],'PRBSet',[],'NLayers',[],'Modulation',[],'RV',[],'TxScheme',[],'crc',[],'SIBMessage','');
            obj.CellsFound = [];
        end
        function closeGUI(obj)
            % Close viewer
            if ishandle(obj.FigureHandle) && isvalid(obj.FigureHandle)
                close(obj.FigureHandle)
            end
        end
        function value = get.CellID(obj)
            % Det 'Detected cell ID' drop down value
            value = obj.GUIHandles.CellIDValue.Value;
        end
        function set.CellID(obj,value)
            % Set 'Detected cell ID' drop down value
            obj.GUIHandles.CellIDValue.Value = value;
        end
        function value = get.CenterFrequency(obj)
            % Get 'Frequency of detected cells (MHz)' drop down value
            value = obj.GUIHandles.CenterFrequencyValue.Value;
        end
        function set.CenterFrequency(obj,value)
            % Set 'Frequency of detected cells (MHz)' drop down value
            obj.GUIHandles.CenterFrequencyValue.Value = value;
        end
        function value = get.PlotType(obj)
            % Get 'Reference signal measurement plot' drop down value
            value = obj.GUIHandles.PlotTypeValue.Value;
        end
        function set.PlotType(obj,value)
            % Set 'Reference signal measurement plot' drop down value
            obj.GUIHandles.PlotTypeValue.Value = value;
        end
        function update(obj,enbMIB,rsMeas,validCell,validCellCount,...
                pdsch,sigSrc,scannerParams,count)
            %Update all the decoded information on to viewer
            if (count == 1)
                reset(obj);
            end
            global stopStatus
            if ~stopStatus
                updateFreq = sigSrc.CenterFrequency/1e6;
                obj.validCellArray = validCell;
                if validCellCount>0
                    % Update cell frequency,cell id,MIB information only if cell is detected
                    updateFrequencies(obj,validCell,validCellCount,updateFreq);
                    updateCellIDs(obj,validCell,validCellCount,enbMIB);
                    updateMIB(obj,validCell,validCellCount,enbMIB);
                    updateRSMs(obj,rsMeas);
                    if scannerParams.isSibDecoding% Update SIB1 information on viewer only if user selects MIB and SIB1 decoding
                        updateSIB(obj,validCell,validCellCount,pdsch)
                    end
                    updateRadioStatus(obj);
                end
                obj.Nofbands = scannerParams.Nofbands;
                if(obj.Nofbands == 2)
                    % If user provides two different frequency ranges make sure
                    % plot between two bands is not connected
                    obj.noLineXband = scannerParams.noLineXband;
                    obj.noLineYband = nan(1,length(scannerParams.noLineXband));
                end
                %Update reference signal measurements and corresponding plot
                %on viewer
                updateRSMeasurements(obj,updateFreq,rsMeas);
                updateXaxisLimits(obj,scannerParams);
                plotRSMeas(obj);
            end
        end
        function greyViewer(obj,status)  
            % Grey all the fields in the viewer, when user changes any of
            % the input parameters after decoding information for the first
            % time
            if (strcmp(status,'on'))
                bgColor = [1 1 1]; %set background color to white
                fgColor = [0 0 0]; %set foreground color to black
            else
                if ~strcmp(obj.GUIHandles.CenterFrequencyValue.String,'N/A')
                    bgColor = [0.94 0.94 0.94];%set background color to grey
                    fgColor = [0.65 0.65 0.65];%set background color to less grey
                else
                    bgColor = [1 1 1];%set background color to white
                    fgColor = [0 0 0]; %set foreground color to black
                    status = 'on';
                end
            end
            obj.GUIHandles.PlotTypeValue.Enable = status;
            obj.GUIHandles.Ax.Color = bgColor;
            % Update Center frequencies drop down
            obj.GUIHandles.CenterFrequencyValue.Enable = status;
            % Update cell ids drop down
            obj.GUIHandles.CellIDValue.Enable = status;
            % Update MIB settings panel
            obj.GUIHandles.hDuplexModeValue.ForegroundColor = fgColor;
            obj.GUIHandles.hCyclicPrefixValue.ForegroundColor = fgColor;
            obj.GUIHandles.hndlrbValue.ForegroundColor = fgColor;
            obj.GUIHandles.hCellRefPValue.ForegroundColor = fgColor;
            obj.GUIHandles.hPHICHDurationValue.ForegroundColor = fgColor;
            obj.GUIHandles.hNgValue.ForegroundColor = fgColor;
            obj.GUIHandles.hNFrameValue.ForegroundColor = fgColor;
            obj.GUIHandles.hMIBStatusText.ForegroundColor = fgColor;
            % Update SIB1 settings panel
            obj.GUIHandles.hRNTIValue.ForegroundColor = fgColor;
            obj.GUIHandles.hPRBSetValue.ForegroundColor = fgColor;
            obj.GUIHandles.hNLayersValue.ForegroundColor = fgColor;
            obj.GUIHandles.hModulationValue.ForegroundColor = fgColor;
            obj.GUIHandles.hRVValue.ForegroundColor = fgColor;
            obj.GUIHandles.hTxSchemeValue.ForegroundColor = fgColor;
            obj.GUIHandles.hCRCValue.ForegroundColor = fgColor;
            obj.GUIHandles.hSIB1StatusText.ForegroundColor = fgColor;
            % Update RS measurements panel
            obj.GUIHandles.hRSRQValue.ForegroundColor = fgColor;
            obj.GUIHandles.hRSRPValue.ForegroundColor  = fgColor;
            obj.GUIHandles.hRSSIValue.ForegroundColor = fgColor;
            drawnow;            
        end
        function clearViewer(obj)
            % Clear all the strings in the viewer, when user clicks start
            % search button for second time
            % Clear Plot
            cla(obj.GUIHandles.Ax);
            % Clear Center frequencies
            obj.GUIHandles.CenterFrequencyValue.Value = 1;
            obj.GUIHandles.CenterFrequencyValue.String = 'N/A';
            % Clear cell ids
            obj.GUIHandles.CellIDValue.Value = 1;
            obj.GUIHandles.CellIDValue.String = 'N/A';
            % Clear MIB settings
            obj.GUIHandles.hDuplexModeValue.String = '';
            obj.GUIHandles.hCyclicPrefixValue.String = '';
            obj.GUIHandles.hndlrbValue.String = '';
            obj.GUIHandles.hCellRefPValue.String = '';
            obj.GUIHandles.hPHICHDurationValue.String = '';
            obj.GUIHandles.hNgValue.String = '';
            obj.GUIHandles.hNFrameValue.String = '';
            obj.GUIHandles.hMIBStatusText.String = '';
            % Clear SIB1 settings
            obj.GUIHandles.hRNTIValue.String = '';
            obj.GUIHandles.hPRBSetValue.String = '';
            obj.GUIHandles.hNLayersValue.String = '';
            obj.GUIHandles.hModulationValue.String = '';
            obj.GUIHandles.hRVValue.String = '';
            obj.GUIHandles.hTxSchemeValue.String = '';
            obj.GUIHandles.hCRCValue.String = '';
            obj.GUIHandles.hSIB1StatusText.String = '';
            % Clear RS measurements
            obj.GUIHandles.hRSRQValue.String = '';
            obj.GUIHandles.hRSRPValue.String  = '';
            obj.GUIHandles.hRSSIValue.String = '';
        end
        function updateFrequencies(obj,validCell,validCellCount,updateFreq)
            %Update decoded frequency information in to drop down 
            obj.ValidFrequencyCount = obj.ValidFrequencyCount +1;
            obj.ValidCellsindex(obj.ValidFrequencyCount,:) =  validCell;
            obj.CellFreq(obj.ValidFrequencyCount) = updateFreq;
            obj.freqCellCount(obj.ValidFrequencyCount) = validCellCount;
            if(obj.ValidFrequencyCount == 1)
                obj.freqCellStartInd(obj.ValidFrequencyCount) = 1;
            else
                obj.freqCellStartInd(obj.ValidFrequencyCount) = obj.freqCellStartInd(obj.ValidFrequencyCount-1)+obj.freqCellCount(obj.ValidFrequencyCount-1);
            end
            sigSrcType = obj.SignalSourceType;
            if strcmp(sigSrcType,'Captured')
                obj.GUIHandles.CenterFrequencyValue.String = num2str(updateFreq);
            else
                if(obj.ValidFrequencyCount > 1)
                    obj.GUIHandles.CenterFrequencyValue.String = [str2num(obj.GUIHandles.CenterFrequencyValue.String); updateFreq];
                else
                    obj.GUIHandles.CenterFrequencyValue.String = updateFreq;
                end
            end
        end
        function updateCellIDs(obj,validCell,validCellCount,enbMIB)
            %Update decoded cell ID information in to drop down 
            obj.NumCells = obj.NumCells + validCellCount;
            switch validCellCount
                case 1
                    obj.CellsFound(obj.NumCells) = enbMIB(find(validCell,1)).NCellID;
                case 2
                    obj.CellsFound(obj.NumCells-1) = enbMIB(find(validCell,1)).NCellID;
                    obj.CellsFound(obj.NumCells) = enbMIB(find(validCell(find(validCell,1)+1:end),1)+1).NCellID;
                case 3
                    obj.CellsFound(obj.NumCells-2) = enbMIB(1).NCellID;
                    obj.CellsFound(obj.NumCells-1) = enbMIB(2).NCellID;
                    obj.CellsFound(obj.NumCells) = enbMIB(3).NCellID;
            end
            if (obj.ValidFrequencyCount == 1)
                switch obj.freqCellCount(1)
                    case 1
                        obj.GUIHandles.CellIDValue.String = obj.CellsFound(1);
                    case 2
                        obj.GUIHandles.CellIDValue.String = [obj.CellsFound(1) obj.CellsFound(2)];
                    case 3
                        obj.GUIHandles.CellIDValue.String = [obj.CellsFound(1) obj.CellsFound(2) obj.CellsFound(3)];
                end
            end
        end
        function updateMIB(obj,validCell,validCellCount,enbMIB)
            %Update decoded MIB information in to a buffer
            obj.NumOfMIBs = obj.NumOfMIBs+validCellCount;
            switch validCellCount
                case 1
                    obj.MIBs(obj.NumOfMIBs) = enbMIB(find(validCell,1));
                case 2
                    obj.MIBs(obj.NumOfMIBs-1) = enbMIB(find(validCell,1));
                    obj.MIBs(obj.NumOfMIBs) = enbMIB(find(validCell(find(validCell,1)+1:end),1)+1);
                case 3
                    obj.MIBs(obj.NumOfMIBs-2) = enbMIB(1);
                    obj.MIBs(obj.NumOfMIBs-1) = enbMIB(2);
                    obj.MIBs(obj.NumOfMIBs) = enbMIB(3);
            end
            updateMIBStrings(obj,1);
        end
        function updateRSMs(obj,rsMeas)
            %Update decoded reference signal measurements in to a buffer
            obj.RMScount = obj.RMScount + 3;
            obj.RSMs(obj.RMScount-2) = rsMeas(1);
            obj.RSMs(obj.RMScount-1) = rsMeas(2);
            obj.RSMs(obj.RMScount) = rsMeas(3);
            updateRSMStrings(obj,1);
        end
        function updateSIB(obj,validCell,validCellCount,pdsch)
            %Update decoded SIB1 information in to a buffer
            obj.NumOfSIBs = obj.NumOfSIBs + validCellCount;
            switch validCellCount
                case 1
                    obj.SIBs(obj.NumOfSIBs) = pdsch(find(validCell,1));
                case 2
                    obj.SIBs(obj.NumOfSIBs-1) = pdsch(find(validCell,1));
                    obj.SIBs(obj.NumOfSIBs) = pdsch(find(validCell(find(validCell,1)+1:end),1)+1);
                case 3
                    obj.SIBs(obj.NumOfSIBs-2) = pdsch(1);
                    obj.SIBs(obj.NumOfSIBs-1) = pdsch(2);
                    obj.SIBs(obj.NumOfSIBs) = pdsch(3);
            end
            updateSIB1Strings(obj,1);
        end
        function updateRSMeasurements(obj,updateFreq,rsMeas)
            %Update plot data in to a buffer
                if((obj.Nofbands == 2)&&((round((obj.noLineXband(1)-(0.1e6))- updateFreq*1e6))==0))
                    obj.xValues= [obj.xValues updateFreq obj.noLineXband];
                    obj.yRSRP1 = [obj.yRSRP1 rsMeas(1).RSRPdBm obj.noLineYband];
                    obj.yRSRP2 = [obj.yRSRP2 rsMeas(2).RSRPdBm obj.noLineYband];
                    obj.yRSRP3 = [obj.yRSRP3 rsMeas(3).RSRPdBm obj.noLineYband];
                    obj.yRSRQ1 = [obj.yRSRQ1 rsMeas(1).RSRQdB obj.noLineYband];
                    obj.yRSRQ2 = [obj.yRSRQ2 rsMeas(2).RSRQdB obj.noLineYband];
                    obj.yRSRQ3 = [obj.yRSRQ3 rsMeas(3).RSRQdB obj.noLineYband];
                    obj.yRSSI1 = [obj.yRSSI1 rsMeas(1).RSSIdBm obj.noLineYband];
                    obj.yRSSI2 = [obj.yRSSI2 rsMeas(2).RSSIdBm obj.noLineYband];
                    obj.yRSSI3 = [obj.yRSSI3 rsMeas(3).RSSIdBm obj.noLineYband];
                else
                    obj.xValues = [obj.xValues updateFreq];
                    obj.yRSRP1 = [obj.yRSRP1 rsMeas(1).RSRPdBm];
                    obj.yRSRP2 = [obj.yRSRP2 rsMeas(2).RSRPdBm];
                    obj.yRSRP3 = [obj.yRSRP3 rsMeas(3).RSRPdBm];
                    obj.yRSRQ1 = [obj.yRSRQ1 rsMeas(1).RSRQdB];
                    obj.yRSRQ2 = [obj.yRSRQ2 rsMeas(2).RSRQdB];
                    obj.yRSRQ3 = [obj.yRSRQ3 rsMeas(3).RSRQdB];
                    obj.yRSSI1 = [obj.yRSSI1 rsMeas(1).RSSIdBm];
                    obj.yRSSI2 = [obj.yRSSI2 rsMeas(2).RSSIdBm];
                    obj.yRSSI3 = [obj.yRSSI3 rsMeas(3).RSSIdBm];
                end
        end
        function plotRSMeas(obj)
            %Update the plot by updating the reference signal
            %measurements over each frequency
            updateYaxisLimits(obj)
            RSPlotType = obj.GUIHandles.PlotTypeValue.Value;
            RSMArray = struct2array(obj.RSMs);
            switch RSPlotType
                case 1
                    Y1Values = obj.yRSRQ1;
                    Y2Values = obj.yRSRQ2;
                    Y3Values = obj.yRSRQ3;
                    LabelString = 'RSRQ (dB)';
                    RSMsforDataTip = RSMArray(2:3:end);
                case 2
                    Y1Values = obj.yRSRP1;
                    Y2Values = obj.yRSRP2;
                    Y3Values = obj.yRSRP3;
                    LabelString = 'RSRP (dBm)';
                    RSMsforDataTip = RSMArray(1:3:end);
                case 3
                    Y1Values = obj.yRSSI1;
                    Y2Values = obj.yRSSI2;
                    Y3Values = obj.yRSSI3;
                    LabelString = 'RSSI (dBm)';
                    RSMsforDataTip = RSMArray(3:3:end);
            end
            optCodeForPlot(obj,Y1Values,Y2Values,Y3Values,LabelString,RSMsforDataTip);
        end
        function optCodeForPlot(obj,Y1Values,Y2Values,Y3Values,LabelString,RSMsforDataTip)
            hold off
            if(~isempty(Y1Values))
                dt = datacursormode(obj.FigureHandle);
                dt.Enable = 'on';
                plot(obj.xValues,Y1Values,'-b.');
                grid on;
                hold on;
                if(~(obj.NumCells == 0))
                    [~,highLightDetectedXposition] = ismember(obj.CellFreq,obj.xValues);
                    highLightpositions = nan(1,length(obj.xValues));
                    highLightpositions(highLightDetectedXposition) = Y1Values(highLightDetectedXposition);
                    hold on;
                    hplot1 = plot(obj.xValues,highLightpositions ,'p',...
                        'LineWidth',2,...
                        'MarkerEdgeColor','red',...
                        'MarkerFaceColor',[0.5,0.5,0.5],'DisplayName','1st detected cell');
                    hplot2 = plot(obj.xValues,Y2Values,'p',...
                        'LineWidth',2,...
                        'MarkerEdgeColor','green',...
                        'MarkerFaceColor',[0.5,0.5,0.5],'DisplayName','2nd detected cell');
                    hplot3 = plot(obj.xValues,Y3Values,'p',...
                        'LineWidth',2,...
                        'MarkerEdgeColor','black',...
                        'MarkerFaceColor',[0.5,0.5,0.5],'DisplayName','3rd detected cell');
                    if any(obj.freqCellCount>2)
                        legend([hplot1 hplot2 hplot3],'1st detected cell','2nd detected cell','3rd detected cell');
                        
                    elseif any(obj.freqCellCount>1)
                        legend([hplot1 hplot2 ],'1st detected cell','2nd detected cell');
                    else
                        legend(hplot1,'1st detected cell');                        
                    end                    
                    legend('boxon');
                end
                if(~isnan(obj.Y_low) && ~isnan(obj.Y_low))
                    axis(obj.GUIHandles.Ax,[obj.xLowLim/1e6 obj.xHigLim/1e6 obj.Y_low obj.Y_high]);
                end
                dt.UpdateFcn = {@hScanLTEWaveformDataTip,obj.CellsFound,RSMsforDataTip,obj.CellFreq,obj.freqCellCount};
            end
            set(obj.GUIHandles.Ax.XLabel,'String','Frequency (MHz)');
            set(obj.GUIHandles.Ax.YLabel,'String',LabelString);
            set(obj.GUIHandles.Ax.Title,'String',[LabelString(1:4),' vs Frequency']);
            drawnow;
        end

        function updateYaxisLimits(obj)
            %Update Y-limits based on the measurement type selected in the
            %'Reference signal measurement plot drop down'
            RSPlotType = obj.GUIHandles.PlotTypeValue.Value;
            switch RSPlotType
                case 1
                    YlimitsCal(obj,obj.yRSRQ1,obj.yRSRQ2,obj.yRSRQ3);
                case 2
                    YlimitsCal(obj,obj.yRSRP1,obj.yRSRP2,obj.yRSRP3);
                case 3
                    YlimitsCal(obj,obj.yRSSI1,obj.yRSSI2,obj.yRSSI3);
            end
        end
        function YlimitsCal(obj,Yrsms1,Yrsms2,Yrsms3)
            %Based on decoded Reference signal measurements fix the
            %Y-limits for the plot, make sure that measurements are not
            %clipped from the plot
            maxRSM = max(max(Yrsms1,max(Yrsms2,Yrsms3)));
            minRSM = min(min(Yrsms1,min(Yrsms2,Yrsms3)));
            yDataRng = abs(maxRSM - minRSM);
            yMinAdjust = 0.15*yDataRng;
            yMaxAdjust = 0.5*yDataRng;
            yMin = minRSM-yMinAdjust;
            yMax = maxRSM+yMaxAdjust;
            if(yMin == yMax)
                obj.Y_low = yMin - ((sign(yMin))*0.1*yMin);
                obj.Y_high = yMin + ((sign(yMin))*0.1*yMin);
            else
                obj.Y_low = yMin;
                obj.Y_high = yMax;
            end
        end
        function updateXaxisLimits(obj,scannerParams)
            %Based on provided frequency range fix the X-limits for the plot
            obj.xLowLim = scannerParams.xLowFreq;
            obj.xHigLim = scannerParams.xHigFreq;
        end
        function delete(obj)
            if ishandle(obj.FigureHandle) && isvalid(obj.FigureHandle)
                close(obj.FigureHandle)
            end
        end
    end
    methods (Access = private)
        function updateGUI(obj)
            if ~isa(obj.FigureHandle,'matlab.ui.Figure') ...
                    || ~isvalid(obj.FigureHandle)
                renderGUI(obj);
            end
        end
        function updateRadioStatus(obj)
            if ~isa(obj.FigureHandle,'matlab.ui.Figure') ...
                    || ~isvalid(obj.FigureHandle)
                renderGUI(obj);
            end
        end
        function renderGUI(obj)
            % Create all the uicontrol fields for the viewer
            if ~ishandle(obj.ParentHandle) || ~isvalid(obj.ParentHandle)
                obj.FigureHandle = figure('Position',[100 100 850 700],...
                    'Visible','on',...
                    'HandleVisibility','on',...
                    'Color',[0.8 0.8 0.8],...
                    'MenuBar','none',...
                    'Name','LTE Scanner',...
                    'IntegerHandle','off',...
                    'NumberTitle','off',...
                    'Tag','LTE Scanner');
                movegui(obj.FigureHandle,'center')
                obj.ParentHandle = uicontainer(obj.FigureHandle);
            else
                obj.FigureHandle = ancestor(obj.ParentHandle,'figure');
            end
            % Set the object handle
            setappdata(obj.FigureHandle,'ViewerHandle',obj);
            % Create main container
            hMain = uicontainer('Parent',obj.ParentHandle);
            % Create the main grid
            hGridMain = siglayout.gridbaglayout(hMain);
            hGridMain.HorizontalWeights = [1 1 1];
            hGridMain.VerticalWeights = [6 1 5];
            % Create container for Center frequency text
            hmiddleContainer = uicontainer(obj.ParentHandle);
            add(hGridMain,hmiddleContainer,2,1:3,'MinimumWidth',830,'MinimumHeight',25);
            hGridmiddle = siglayout.gridbaglayout(hmiddleContainer);
            hGridmiddle.HorizontalWeights = [1 1 1 1 1 1 1];
            hGridmiddle.VerticalWeights = 1;
            % Center frequency text
            hCenterFrequencyText = uicontrol(hmiddleContainer,...
                'Style','text',...
                'String','Frequency of detected cells (MHz):',...
                'HorizontalAlignment','left',...
                'Tag','CenterFrequencyText','FontSize',10);
            % Center frequency popup menu
            obj.GUIHandles.CenterFrequencyValue = uicontrol(hmiddleContainer,...
                'Style','popupmenu',...
                'String','N/A',...
                'HorizontalAlignment','left',...
                'Callback',@obj.centerFrequencyCallback,...
                'Tag','CenterFrequencyValue','FontSize',10,'Tooltip',...
                'Select frequency to view decoded information for the selected cell ID');
            % Cell ID text
            hCellIDText = uicontrol(hmiddleContainer,...
                'Style','text',...
                'String','Detected cell ID:',...
                'HorizontalAlignment','left',...
                'Tag','CellIDText','FontSize',10);
            % Cell ID popup menu
            obj.GUIHandles.CellIDValue = uicontrol(hmiddleContainer,...
                'Style','popupmenu',...
                'String','N/A',...
                'HorizontalAlignment','left',...
                'Callback',@obj.cellIdCallback,...
                'Tag','CellIDValue','FontSize',10,'Tooltip',...
                'Select cell ID to view decoded information for the selected frequency');
            dummy  =  uicontainer(hmiddleContainer);
            add(hGridmiddle,hCenterFrequencyText,1,1,'Fill','Both','MinimumWidth',0.9*hCenterFrequencyText.Extent(3));
            add(hGridmiddle,obj.GUIHandles.CenterFrequencyValue,1,2,'Fill','Both','MinimumWidth',hCellIDText.Extent(3),'MinimumHeight',5*hCellIDText.Extent(3));
            add(hGridmiddle,hCellIDText,1,4,'Fill','Both','MinimumWidth',0.8*hCellIDText.Extent(3));
            add(hGridmiddle,obj.GUIHandles.CellIDValue,1,5,'Fill','Both','MinimumWidth',hCellIDText.Extent(3));
            hCenterFrequencyText.Position(2) = obj.GUIHandles.CenterFrequencyValue.Position(2)*0.98;
            hCellIDText.Position(2) = obj.GUIHandles.CenterFrequencyValue.Position(2)*0.98;
            add(hGridmiddle,dummy,1,6:7,'MinimumWidth',hCenterFrequencyText.Extent(3)/2);
            % Create container MIB settings panel
            hMibPanel = uipanel(obj.ParentHandle,'Title','Cell settings from MIB decoding','FontSize',10);
            hGridMIB = siglayout.gridbaglayout(hMibPanel);
            hGridMIB.HorizontalWeights = [1 1];
            hGridMIB.VerticalWeights = [1 1 1 1 1 1 1 1];
            add(hGridMain,hMibPanel,3,1,'MinimumWidth',265,'MinimumHeight',230);
            dummy  =  uicontainer(hmiddleContainer);
            add(hGridMIB,dummy,1,1:2,'Fill','Both');
            % Create Duplex Mode text
            hDuplexModeText = uicontrol(hMibPanel,...
                'Style','text',...
                'String','  DuplexMode:',...
                'HorizontalAlignment','left',...
                'Tag','DuplexModeText','FontSize',10);
            add(hGridMIB,hDuplexModeText,2,1,'Fill','Both');
            % Create Duplex Mode Value
            obj.GUIHandles.hDuplexModeValue = uicontrol(hMibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','DuplexModeValue','FontSize',10);
            add(hGridMIB,obj.GUIHandles.hDuplexModeValue,2,2,'Fill','Both');
            % Create Cyclic Prefix text
            hCyclcicPrefixText = uicontrol(hMibPanel,...
                'Style','text',...
                'String','  CyclicPrefix:',...
                'HorizontalAlignment','left',...
                'Tag','CyclicPrefixText','FontSize',10);
            add(hGridMIB,hCyclcicPrefixText,3,1,'Fill','Both');
            % Create Cyclic Prefix Value
            obj.GUIHandles.hCyclicPrefixValue = uicontrol(hMibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','CyclicPrefixValue','FontSize',10);
            add(hGridMIB,obj.GUIHandles.hCyclicPrefixValue,3,2,'Fill','Both');
            % Create NDLRB text
            hndlrbText = uicontrol(hMibPanel,...
                'Style','text',...
                'String','  NDLRB:',...
                'HorizontalAlignment','left',...
                'Tag','NDLRBText','FontSize',10);
            add(hGridMIB,hndlrbText,4,1,'Fill','Both');
            % Create NDLRB Value
            obj.GUIHandles.hndlrbValue = uicontrol(hMibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','NDLRBValue','FontSize',10);
            add(hGridMIB,obj.GUIHandles.hndlrbValue,4,2,'Fill','Both');
            % Create CellRefP text
            hCellRefPText = uicontrol(hMibPanel,...
                'Style','text',...
                'String','  CellRefP: ',...
                'HorizontalAlignment','left',...
                'Tag','CellRefPText','FontSize',10);
            add(hGridMIB,hCellRefPText,5,1,'Fill','Both');
            % Create CellRefP Value
            obj.GUIHandles.hCellRefPValue = uicontrol(hMibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','CellRefPValue','FontSize',10);
            add(hGridMIB,obj.GUIHandles.hCellRefPValue,5,2,'Fill','Both');
            % Create PHICHDuration text
            hPHICHDurationText = uicontrol(hMibPanel,...
                'Style','text',...
                'String','  PHICHDuration: ',...
                'HorizontalAlignment','left',...
                'Tag','PHICHDurationText','FontSize',10);
            add(hGridMIB,hPHICHDurationText,6,1,'Fill','Both');
            % Create PHICHDuration Value
            obj.GUIHandles.hPHICHDurationValue = uicontrol(hMibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','PHICHDurationValue','FontSize',10);
            add(hGridMIB,obj.GUIHandles.hPHICHDurationValue,6,2,'Fill','Both');
            % Create Ng text
            hNgText = uicontrol(hMibPanel,...
                'Style','text',...
                'String','  Ng: ',...
                'HorizontalAlignment','left',...
                'Tag','NgText','FontSize',10);
            add(hGridMIB,hNgText,7,1,'Fill','Both');
            % Create Ng Value
            obj.GUIHandles.hNgValue = uicontrol(hMibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','NgValue','FontSize',10);
            add(hGridMIB,obj.GUIHandles.hNgValue,7,2,'Fill','Both');
            % Create NFrame text
            hNFrameText = uicontrol(hMibPanel,...
                'Style','text',...
                'String','  NFrame: ',...
                'HorizontalAlignment','left',...
                'Tag','NFrameText','FontSize',10);
            add(hGridMIB,hNFrameText,8,1,'Fill','Both');
            % Create NFrame Value
            obj.GUIHandles.hNFrameValue = uicontrol(hMibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','NFrameValue','FontSize',10);
            add(hGridMIB,obj.GUIHandles.hNFrameValue,8,2,'Fill','Both');
            % Create SIB Settings panel
            hSibPanel = uipanel(obj.ParentHandle,...
                'Title','PDSCH settings from DCI decoding','FontSize',10);
            hGridSIB = siglayout.gridbaglayout(hSibPanel);
            hGridSIB.HorizontalWeights = [1 1];
            hGridSIB.VerticalWeights = [1 1 1 1 1 1 1 1];
            add(hGridMain,hSibPanel,3,2,'MinimumWidth',270,'MinimumHeight',230);
            dummy  =  uicontainer(hSibPanel);
            add(hGridSIB,dummy,1,1:2,'Fill','Both');
            % Create RNTI text
            hRNTIText = uicontrol(hSibPanel,...
                'Style','text',...
                'String','  RNTI:',...
                'HorizontalAlignment','left',...
                'Tag','RNTIText','FontSize',10);
            add(hGridSIB,hRNTIText,2,1,'Fill','Both');
            % Create RNTI Value
            obj.GUIHandles.hRNTIValue = uicontrol(hSibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','RNTIValue','FontSize',10);
            add(hGridSIB,obj.GUIHandles.hRNTIValue,2,2,'Fill','Both');
            % Create PRB Set text
            hPRBSetText = uicontrol(hSibPanel,...
                'Style','text',...
                'String','  PRBSet:',...
                'HorizontalAlignment','left',...
                'Tag','PRBSetText','FontSize',10);
            add(hGridSIB,hPRBSetText,3,1,'Fill','Both');
            % Create PRB Set Value
            obj.GUIHandles.hPRBSetValue = uicontrol(hSibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','PRBSetValue','FontSize',10);
            add(hGridSIB,obj.GUIHandles.hPRBSetValue,3,2,'Fill','Both');
            % Create N Layers text
            hNLayersText = uicontrol(hSibPanel,...
                'Style','text',...
                'String','  NLayers:',...
                'HorizontalAlignment','left',...
                'Tag','NLayersText','FontSize',10);
            add(hGridSIB,hNLayersText,4,1,'Fill','Both');
            % Create N Layers Value
            obj.GUIHandles.hNLayersValue = uicontrol(hSibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','NLayersValue','FontSize',10);
            add(hGridSIB,obj.GUIHandles.hNLayersValue,4,2,'Fill','Both');
            % Create Modulation text
            hModulationText = uicontrol(hSibPanel,...
                'Style','text',...
                'String','  Modulation: ',...
                'HorizontalAlignment','left',...
                'Tag','ModulationText','FontSize',10);
            add(hGridSIB,hModulationText,5,1,'Fill','Both');
            % Create Modulation Value
            obj.GUIHandles.hModulationValue = uicontrol(hSibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','ModulationValue','FontSize',10);
            add(hGridSIB,obj.GUIHandles.hModulationValue,5,2,'Fill','Both');
            % Create RV text
            hRVText = uicontrol(hSibPanel,...
                'Style','text',...
                'String','  RV: ',...
                'HorizontalAlignment','left',...
                'Tag','RVText','FontSize',10);
            add(hGridSIB,hRVText,6,1,'Fill','Both');
            % Create RV Value
            obj.GUIHandles.hRVValue = uicontrol(hSibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','RVValue','FontSize',10);
            add(hGridSIB,obj.GUIHandles.hRVValue,6,2,'Fill','Both');
            % Create Tx Scheme text
            hTxSchemeText = uicontrol(hSibPanel,...
                'Style','text',...
                'String','  TxScheme: ',...
                'HorizontalAlignment','left',...
                'Tag','TxSchemeText','FontSize',10);
            add(hGridSIB,hTxSchemeText,7,1,'Fill','Both');
            % Create Tx Scheme Value
            obj.GUIHandles.hTxSchemeValue = uicontrol(hSibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','TxSchemeValue','FontSize',10);
            add(hGridSIB,obj.GUIHandles.hTxSchemeValue,7,2,'Fill','Both');
            % Create CRC text
            hCRCText = uicontrol(hSibPanel,...
                'Style','text',...
                'String','  CRC: ',...
                'HorizontalAlignment','left',...
                'Tag','CRCText','FontSize',10);
            add(hGridSIB,hCRCText,8,1,'Fill','Both');
            % Create CRC Value
            obj.GUIHandles.hCRCValue = uicontrol(hSibPanel,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','CRCValue','FontSize',10);
            add(hGridSIB,obj.GUIHandles.hCRCValue,8,2,'Fill','Both');
            % Create Reference signal measurements Panel
            hRSMeasurements = uipanel(obj.ParentHandle,...
                'Title','Reference signal measurements','FontSize',10);
            hGridRS = siglayout.gridbaglayout(hRSMeasurements);
            hGridRS.HorizontalWeights = [1 1];
            hGridRS.VerticalWeights = [1 1 1 1 1 1 1 1];
            add(hGridMain,hRSMeasurements,3,3,'MinimumWidth',265,'MinimumHeight',230);
            dummy  =  uicontainer(hmiddleContainer);
            add(hGridRS,dummy,1,1:2,'MinimumHeight',10);
            % Create RSRQ text
            hRSRQText = uicontrol(hRSMeasurements,...
                'Style','text',...
                'String','  RSRQ (dB):',...
                'HorizontalAlignment','left',...
                'Tag','RSRQText','FontSize',10);
            add(hGridRS,hRSRQText,2,1,'Fill','Both');
            % Create RSRQ Value
            obj.GUIHandles.hRSRQValue = uicontrol(hRSMeasurements,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','RSRQValue','FontSize',10);
            add(hGridRS,obj.GUIHandles.hRSRQValue,2,2,'Fill','Both');
            % Create RSRP text
            hRSRPText = uicontrol(hRSMeasurements,...
                'Style','text',...
                'String','  RSRP (dBm):',...
                'HorizontalAlignment','left',...
                'Tag','RSRPText','FontSize',10);
            add(hGridRS,hRSRPText,3,1,'Fill','Both');
            % Create RSRQ Value
            obj.GUIHandles.hRSRPValue = uicontrol(hRSMeasurements,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','RSRPValue','FontSize',10);
            add(hGridRS,obj.GUIHandles.hRSRPValue,3,2,'Fill','Both');
            % Create RSSI text
            hRSSIText = uicontrol(hRSMeasurements,...
                'Style','text',...
                'String','  RSSI (dBm):',...
                'HorizontalAlignment','left',...
                'Tag','RSSIText','FontSize',10);
            add(hGridRS,hRSSIText,4,1,'Fill','Both');
            % Create RSRQ Value
            obj.GUIHandles.hRSSIValue = uicontrol(hRSMeasurements,...
                'Style','text',...
                'HorizontalAlignment','left',...
                'Tag','RSSIValue','FontSize',10);
            add(hGridRS,obj.GUIHandles.hRSSIValue,4,2,'Fill','Both');
            dummy  =  uicontainer(hmiddleContainer);
            add(hGridRS,dummy,5:8,1:2,'Fill','Both');
            % Create Axes
            haxesContainer =  uipanel(obj.ParentHandle);
            hGridAxes = siglayout.gridbaglayout(haxesContainer);
            hGridAxes.HorizontalWeights = 1;
            hGridAxes.VerticalWeights = [1 6];
            add(hGridMain,haxesContainer,1,1:3,'MinimumWidth',830,'MinimumHeight',370);            
            hplotDropDown = uicontainer(haxesContainer);
            hGridplotDropDown = siglayout.gridbaglayout(hplotDropDown);
            hGridplotDropDown.HorizontalWeights = [1 1 1 1];
            hGridplotDropDown.VerticalWeights = [1 1];
            add(hGridAxes,hplotDropDown,1,1,'Fill','Both');
            % create Reference signal measurements plot text
            hGridPlotTypeText = uicontrol(hplotDropDown,...
                'Style','text',...
                'String','Reference signal measurement plot:',...
                'HorizontalAlignment','left',...
                'Tag','PlotTypeText','FontSize',10);            
            % create Reference signal measurements plot value
            obj.GUIHandles.PlotTypeValue = uicontrol(hplotDropDown,...
                'Style','popupmenu',...
                'String',{'RSRQ','RSRP','RSSI'},...
                'HorizontalAlignment','left',...
                'Callback',@obj.PlotTypeCallback,...
                'Tag','PlotTypeValue','FontSize',10,'Tooltip','Select reference signal measurement plot type');
            add(hGridplotDropDown,hGridPlotTypeText,2,1,'MinimumWidth',hGridPlotTypeText.Extent(3));
            add(hGridplotDropDown,obj.GUIHandles.PlotTypeValue,2,2,'MinimumWidth',3*obj.GUIHandles.PlotTypeValue.Extent(3),'MinimumHeight',obj.GUIHandles.PlotTypeValue.Extent(4));
            obj.GUIHandles.Ax = axes(haxesContainer);
            set(obj.GUIHandles.Ax.Title,'String','RSRQ vs Frequency')
            set(obj.GUIHandles.Ax.XLabel,'String','Frequency (MHz)')
            set(obj.GUIHandles.Ax.YLabel,'String','RSRQ (dB)')
            obj.GUIHandles.Ax.YGrid ='on';
            obj.GUIHandles.Ax.XGrid ='on';
            obj.GUIHandles.Ax.XLim = [obj.xLowLim obj.xHigLim];
            obj.GUIHandles.Ax.YLim = [obj.yLowLim obj.yHigLim];
            add(hGridAxes,obj.GUIHandles.Ax,2,1:3,'MinimumWidth',710,'MinimumHeight',220);
            dummy_axes = gca;
            dummy_axes.Toolbar.Visible = 'on';
            drawnow;
        end
        function cellIdCallback(obj,src,~)
            %'Detected cell ID' drop down call back 
            if obj.NumOfMIBs
                index = obj.freqCellStartInd(obj.GUIHandles.CenterFrequencyValue.Value)+(src.Value-1);
                updateMIBStrings(obj,index);
                RSMIndex = 3*(obj.GUIHandles.CenterFrequencyValue.Value-1)+(src.Value);
                updateRSMStrings(obj,RSMIndex);
                if obj.NumOfSIBs
                    updateSIB1Strings(obj,index);
                end
            end
        end
        function centerFrequencyCallback(obj,src,~)
            %'Frequency of detected cells(MHz)' drop down call back 
            if obj.NumOfMIBs
                obj.GUIHandles.CellIDValue.Value = 1;
                switch obj.freqCellCount(src.Value)
                    case 1
                        obj.GUIHandles.CellIDValue.String = obj.CellsFound(obj.freqCellStartInd(src.Value));
                    case 2
                        obj.GUIHandles.CellIDValue.String = [obj.CellsFound(obj.freqCellStartInd(src.Value))...
                            obj.CellsFound(obj.freqCellStartInd(src.Value)+1)];
                    case 3
                        obj.GUIHandles.CellIDValue.String = [obj.CellsFound(obj.freqCellStartInd(src.Value))...
                            obj.CellsFound(obj.freqCellStartInd(src.Value)+1)...
                            obj.CellsFound(obj.freqCellStartInd(src.Value)+2)];
                end
                updateMIBStrings(obj,obj.freqCellStartInd(src.Value));
                RSMIndex = 3*(src.Value-1)+1;
                updateRSMStrings(obj,RSMIndex);
                if obj.NumOfSIBs
                    updateSIB1Strings(obj,obj.freqCellStartInd(src.Value));
                end
            end
        end
        function updateMIBStrings(obj,index)
            %Update MIB Information in to the fields of 'Cell settings from
            %MIB decoding' panel
            obj.GUIHandles.hDuplexModeValue.String = obj.MIBs(index).DuplexMode;
            obj.GUIHandles.hCyclicPrefixValue.String = obj.MIBs(index).CyclicPrefix;
            obj.GUIHandles.hndlrbValue.String = obj.MIBs(index).NDLRB;
            obj.GUIHandles.hCellRefPValue.String = obj.MIBs(index).CellRefP;
            obj.GUIHandles.hPHICHDurationValue.String = obj.MIBs(index).PHICHDuration;
            obj.GUIHandles.hNgValue.String = obj.MIBs(index).Ng;
            obj.GUIHandles.hNFrameValue.String = obj.MIBs(index).NFrame;
            drawnow;
        end
        function updateSIB1Strings(obj,index)
            %Update SIB1 information in to the fields of 'PDSCH settings
            %from DCI decoding' panel
            obj.GUIHandles.hRNTIValue.String = obj.SIBs(index).RNTI;
            colCountForPRBSet = size(obj.SIBs(index).PRBSet');
            if (colCountForPRBSet(1) == 1)
                if (colCountForPRBSet(2) > 6)
                    obj.GUIHandles.hPRBSetValue.FontSize = 8;
                else
                    obj.GUIHandles.hPRBSetValue.FontSize = 10;
                end
            else
                obj.GUIHandles.hPRBSetValue.FontSize = 8;
            end
            obj.GUIHandles.hPRBSetValue.String = num2str(obj.SIBs(index).PRBSet');
            obj.GUIHandles.hNLayersValue.String = obj.SIBs(index).NLayers;
            obj.GUIHandles.hModulationValue.String = obj.SIBs(index).Modulation;
            obj.GUIHandles.hRVValue.String = obj.SIBs(index).RV;
            obj.GUIHandles.hTxSchemeValue.String = obj.SIBs(index).TxScheme;
            obj.GUIHandles.hCRCValue.String = obj.SIBs(index).crc;
            drawnow;
        end
        function updateRSMStrings(obj,index)
            %Update RSM values in to the fields of 'Reference signal
            %measurements' panel
            obj.GUIHandles.hRSRQValue.String = obj.RSMs(index).RSRQdB;
            obj.GUIHandles.hRSRPValue.String  = obj.RSMs(index).RSRPdBm;
            obj.GUIHandles.hRSSIValue.String = obj.RSMs(index).RSSIdBm;
            drawnow;
        end
        function PlotTypeCallback(obj,~,~)
            %'Reference signal measurement plot' drop down call back 
            plotRSMeas(obj);
        end
    end
end