%%% spectrum.m %%%
% Main function mainly involving GUI code. Other functions (fft_engine and
% rtl_init) are called within this function

function spectrum
clear,clc,close;
% Initialize radio
[rtlsdr,fs,fc,f_min,f_max,nfft] = rtl_init ... 
(16384,2.4e6,100000000,0,8.7,'double');
%%
%%% FIGURE PROPERTIES      % [left bottom width height]   
lcd = get(0);
lcd_resolution = lcd.ScreenSize(3:4); %get actual screen resolution
xsize = 800;
ysize = 600;
fig = figure('units','pixels',...           %center figure into the middle of the screen
    'pos', [lcd_resolution(1)/2-xsize/2,...
    lcd_resolution(2)/2 - ysize/2, ...
    xsize ysize],...
    'Name','Spectrum v2.0','NumberTitle','off',...
    'MenuBar','none','resize','on');    

%%% PANELS, 3 main GUI panels
panel_settings = uipanel('Title','Basic settings','Units','Normalized','Position',...
              [0.08 0.015 0.128 0.26]);     %receiver settings panel
          
panel_tuning = uipanel('Title','Tuning and gain settings','Units','Normalized','Position',...
              [0.215 0.015 0.46 0.26]);    %freq tuning panel
          
panel_fft = uipanel('Title','FFT settings','Units','Normalized','Position',...
            [0.68 0.015 0.31 0.26]);    %fft settings panel 

    % Receiver settings panel section
    textbox_samplerate = uicontrol(panel_settings,'style','text','units','normalized','Position',...
                   [0.04 0.85 0.7 0.095],'String','Sample rate','FontWeight','Bold');   %samplerate textbox

    popupmenu_samplerate = uicontrol(panel_settings,'Style','popup','units','normalized',...
                    'Position',[0.06 0.73 0.9 0.1],'String',{'3.2 MSPS','2.8 MSPS','2.56 MSPS',...
                    '2.4 MSPS','2.048 MSPS','1.92 MSPS','1.8 MSPS','1.4 MSPS','1.024 MSPS','0.25 MSPS'},...
                    'Value',4,'Callback',@SampleRate);  %samplerate popupmenu

    textbox_agc = uicontrol(panel_settings,'style','text','units','normalized','Position',...
                   [0.02 0.53 0.7 0.095],'String','Tuner AGC','FontWeight','Bold');     %agc textbox

    checkbox_agc = uicontrol(panel_settings,'style','checkbox','units','normalized','Position',...
                   [0.08 0.4 0.7 0.095],'String',' OFF','Callback',@agc);   %agc checkbox   

    textbox_freqcorr = uicontrol(panel_settings,'style','text','Units','normalized','Position',...
                   [0.02 0.25 1 0.095],'String','Freq. correction','FontWeight','Bold');    %freq corr textbox

    editbox_freqcorr = uicontrol(panel_settings,'style','edit','units','normalized',...
                   'Position',[0.08 0.08 0.55 0.15],'String','0','Callback',@ppm);  %freq corr editbox

    textbox_ppm =   uicontrol(panel_settings,'style','text','Units','normalized','Position',...
                   [0.65 0.115 0.3 0.095],'String','ppm');  %ppm textbox
        
% Tuning panel section
slider_tuning = uicontrol(panel_tuning,'style','slider','units','normalized',...
        'SliderStep',[1/16500 1/16500],'Min',50e6,'Max',1700e6,'Value',88.4e6,...
        'Position', [0.12 0.845 0.75 0.11],'Callback',@slider_tune);   %slider for tuning
textbox_fmin = uicontrol(panel_tuning,'style','text','units','normalized','Position',...
               [0.003 0.85 0.11 0.095],'String','50 MHz');   %textbox fmin
textbox_fmax = uicontrol(panel_tuning,'style','text','units','normalized','Position',...
               [0.88 0.85 0.11 0.095],'String','1,7 GHz');  %textbox fmax             

textbox_f_actual1 = uicontrol(panel_tuning,'style','text','units','normalized','Position',...
               [0 0.37 0.42 0.14],'String','Actual frequency',...
               'FontWeight','bold','FontSize',13,'FontWeight','Bold');   %dynamic change of the actual frequency textbox           
           
textbox_f_actual2 = uicontrol(panel_tuning,'style','text','units','normalized','Position',...
               [0.015 0.07 0.26 0.22],'String',num2str(rtlsdr.CenterFrequency/1e6),...
               'FontWeight','bold','FontSize',20,'FontWeight','Bold');   %dynamic change of the actual frequency textbox
           
textbox_string2 = uicontrol(panel_tuning,'style','text','units','normalized','Position',...
               [0.27 0.07 0.17 0.22],'String','MHz','FontSize',20);    %MHz, textbox

% Manual tuning section  
% [left bottom width height] 
panel_manual = uipanel('Parent',panel_tuning,'Title','Manual tuning','Units','Normalized','Position',...
              [0.01 0.52 0.3 0.3]); %manual tuning subpanel          
editbox_tuning = uicontrol(panel_manual,'style','edit','units','normalized',...
               'Position',[0.18 0.22 0.55 0.65],'Callback',@numeric_tune); %manual tuning editbox
textbox_manual1 = uicontrol(panel_manual,'style','text','units','normalized','Position',...
               [0.04 0.22 0.13 0.6],'String','f = '); %textbox f
textbox_manual2 = uicontrol(panel_manual,'style','text','units','normalized','Position',...
               [0.735 0.22 0.2 0.6],'String','MHz');   %textbox MHz
           
% RF Gain section
panel_rfgain = uipanel('Parent',panel_tuning,'Title','RF Gain','Units','Normalized','Position',...
              [0.34 0.52 0.65 0.3]);    %rfgain subpanel
slider_rfgain = uicontrol('Parent',panel_rfgain,'style','slider','units', ...
        'normalized','Min',0,'Max',50,'Value',8.7,'SliderStep',[1/500 1/5],...
        'Position', [0.01 0.25 0.8 0.58],'Callback',@rfgain);   %rfgain slider
textbox_rfgain1 = uicontrol('Parent',panel_rfgain,'style','text','units','normalized','Position',...
               [0.82 0.25 0.1 0.6],'String',num2str(rtlsdr.TunerGain),'FontWeight','bold');    %textbox rfgain
textbox_rfgain2 = uicontrol('Parent',panel_rfgain,'style','text','units','normalized','Position',...
               [0.92 0.25 0.07 0.6],'String','dB');  %textbox dB
          
    % FFT settings panel section
    buttongroup = uibuttongroup('Parent',panel_fft,'Visible','on',...
                      'Title','Window','Position',[0.03 0.045 0.47 0.93]);  %group of radiobuttons for choosing the FFT window
    radiobutton0 = uicontrol(buttongroup,'style','radiobutton','units','normalized',...
                    'String','Rectangular','Position',[0.01 0.79 0.9 0.2],'Callback',@wRect);              
    radiobutton1 = uicontrol(buttongroup,'style','radiobutton','units','normalized',...
                    'String','Hamming','Value',1,'Position',[0.01 0.6 0.9 0.2],'Callback',@wHamm);
    radiobutton2 = uicontrol(buttongroup,'style','radiobutton','units','normalized',...
                    'String','Blackman-Harris','Position',[0.01 0.4 0.9 0.2],'Callback',@wBlack);
    radiobutton3 = uicontrol(buttongroup,'style','radiobutton','units','normalized',...
                    'String','Hann','Position',[0.01 0.2 0.9 0.2],'Callback',@wHann);
    radiobutton4 = uicontrol(buttongroup,'style','radiobutton','units','normalized',...
                    'String','Kaiser','Position',[0.01 0.0 0.9 0.2],'Callback',@wKaiser); 

    textbox_fftres = uicontrol('Parent',panel_fft,'style','text','units','normalized','Position',...
                   [0.53 0.9 0.25 0.1],'String','Resolution','FontWeight','Bold');  %textbox fftres

    popupmenu_fftres = uicontrol(panel_fft,'Style', 'popup','units','normalized',...
                    'Position',[0.535 0.78 0.44 0.1],'String',{'512','1024','2048',...
                    '4096','8192','16384','32768','65536','131072','262144'},...
                    'Value',6,'Callback',@fftres);  %popmenu fftres

    textbox_fftoffset1 = uicontrol('Parent',panel_fft,'style','text','units','normalized','Position',...
                   [0.52 0.6 0.27 0.1],'String','PSD offset','FontWeight','Bold');   
    editbox_fftoffset2 = uicontrol('Parent',panel_fft,'style','edit','units','normalized','Position',...
                   [0.535 0.45 0.15 0.12],'String','0','Callback',@fftoffset);
    textbox_fftoffset3 = uicontrol('Parent',panel_fft,'style','text','units','normalized','Position',...
                   [0.7 0.47 0.07 0.1],'String','dB');
               
    pausebutton = uicontrol('Parent',panel_fft,'style','pushbutton','units','normalized','Position',...
                   [0.54 0.06 0.18 0.15],'String','Pause','Callback',@pausefcn);
               
    resumebutton = uicontrol('Parent',panel_fft,'style','pushbutton','units','normalized','Position',...
                   [0.77 0.06 0.2 0.15],'String','Resume','Callback',@resumefcn); 
               
    zoombutton = uicontrol('Parent',panel_fft,'style','pushbutton','units','normalized','Position',...
                   [0.54 0.26 0.18 0.15],'String','Zoom','Callback',@zoomfcn);
               
    databutton = uicontrol('Parent',panel_fft,'style','pushbutton','units','normalized','Position',...
                   [0.77 0.26 0.2 0.15],'String','Data','Callback',@datafcn);                
%%
%%% PASSING DATA BETWEEN FUNCTIONS
WindowType = 1;
offset = 0;
allFigHndl=guihandles(fig);
guidata(fig,allFigHndl)
setappdata(fig,'WindowType',WindowType)
setappdata(fig,'fftoffset',offset)
%%
fft_engine(rtlsdr,f_min,f_max,fs,nfft,fig)  

%% Functions (callbacks) (these functions provide the functionality of each GUI component)
    %%% SLIDER TUNE
    function slider_tune(hObject,evt)       %change center freq as the slider moves
        rtlsdr.CenterFrequency = get(hObject,'Value');   
        actual_freq = get(hObject,'Value');
        set(textbox_f_actual2,'String',num2str(actual_freq./1000000),'FontWeight','bold')
        f_min = rtlsdr.CenterFrequency - fs/2;
        f_max = rtlsdr.CenterFrequency + fs/2;
        fft_engine(rtlsdr,f_min,f_max,fs,nfft,fig);
    end
    
    %%% NUMERIC TUNE
    function numeric_tune(hObject,evt)      %set frequency from using the keyboard
        actual_freq = str2num(get(hObject,'String'))*1e6;     
            if isempty(actual_freq) == 1
                actual_freq = 100e6;
                rtlsdr.CenterFrequency = actual_freq;
                dialog = msgbox('Input must be numeric !','Error');
                uiwait;
            end 
            if actual_freq < 50e6 || actual_freq > 1.75e9
                actual_freq = 100e6;
                rtlsdr.CenterFrequency = actual_freq;
                dialog = msgbox('Frequency must be between 50 MHz and 1.75 GHz !','Error');
                uiwait;
            end        
        rtlsdr.CenterFrequency = actual_freq;
        set(hObject,'String','');
        set(textbox_f_actual2,'String',num2str(actual_freq./1000000),'FontWeight','bold'); %edit current freq in the textbox
        set(slider_tuning,'Value',actual_freq); %change slider position after numeric tuning
        f_min = rtlsdr.CenterFrequency - fs/2;
        f_max = rtlsdr.CenterFrequency + fs/2;        
        fft_engine(rtlsdr,f_min,f_max,fs,nfft,fig);
    end
    
    %%% RF GAIN
    function rfgain(hObject,evt)        %change RF Gain as the slider moves
        rtlsdr.TunerGain = get(hObject,'Value');
        actual_gain = rtlsdr.TunerGain;
        set(textbox_rfgain1,'String',num2str(actual_gain),'FontWeight','bold');
    end
    
    %%% WINDOW SELECTION
    %functions for passing FFT window data to fft_engine function
    
    function WindowType = wRect(hObject,evt)
        WindowType=0;
        allFigHndl=guihandles(fig);
        guidata(fig,allFigHndl)
        setappdata(fig,'WindowType',WindowType)
    end
    
    function WindowType = wHamm(hObject,evt)
        WindowType=1;
        allFigHndl=guihandles(fig);
        guidata(fig,allFigHndl)
        setappdata(fig,'WindowType',WindowType)
    end
    
    function WindowType = wBlack(hObject,evt)
        WindowType=2;
        allFigHndl=guihandles(fig);
        guidata(fig,allFigHndl)
        setappdata(fig,'WindowType',WindowType)
    end

    function WindowType = wHann(hObject,evt)
        WindowType=3;
        allFigHndl=guihandles(fig);     
        guidata(fig,allFigHndl)
        setappdata(fig,'WindowType',WindowType)
    end

    function WindowType = wKaiser(hObject,evt)
        WindowType=4;
        allFigHndl=guihandles(fig);
        guidata(fig,allFigHndl)
        setappdata(fig,'WindowType',WindowType)
    end
    
    %%% SAMPLE RATE SELECTION
    function fs = SampleRate(hObject,evt)
        freq_list = get(popupmenu_samplerate,'Value');
        switch freq_list
            case 1
                fs=3.2e6;
            case 2
                fs=2.8e6;
            case 3
                fs=2.56e6;
            case 4
                fs=2.4e6;
            case 5
                fs=2.048e6;
            case 6
                fs=1.92e6;
            case 7
                fs=1.8e6;
            case 8
                fs=1.4e6;
            case 9
                fs=1.024e6;
            case 10
                fs=0.25e6;
        end
        f_min = rtlsdr.CenterFrequency - fs/2;
        f_max = rtlsdr.CenterFrequency + fs/2;
        fc = str2num(get(textbox_f_actual2,'String'))*1e6;
        release(rtlsdr)
        [rtlsdr,fs,fc,f_min,f_max,nfft] = rtl_init(nfft,fs,fc,0,8.7,'double');
        fft_engine(rtlsdr,f_min,f_max,fs,nfft,fig);
    end    

    %%% AGC SELECTION
    function agc(hObject,evt)
      value = get(checkbox_agc,'Value');
      if value == 1
          release(rtlsdr)
          rtlsdr.EnableTunerAGC = 1;
          set(checkbox_agc,'String',' ON')
      else
          release(rtlsdr)
          rtlsdr.EnableTunerAGC = 0;
          set(checkbox_agc,'String',' OFF')          
      end
    end

    %%% PPM CORRECTION
    function ppm(hObject,evt)
        value = str2num(get(editbox_freqcorr,'String'));
        release(rtlsdr)
        rtlsdr.FrequencyCorrection = value;
    end

    %%% FFT RESOLUTION SELECTION
    function res = fftres(hObject,evt)
        res_list = get(popupmenu_fftres,'Value');
        switch res_list
            case 1
                res=512;
            case 2
                res=1024;
            case 3
                res=2048;
            case 4
                res=4096;
            case 5
                res=8192;
            case 6
                res=16384;
            case 7
                res=32768;
            case 8
                res=65536;
            case 9
                res=131072;
            case 10
                res=262144;
        end
        nfft = res;
        fc = str2num(get(textbox_f_actual2,'String'))*1e6;
        fs = SampleRate(hObject,evt);
        release(rtlsdr)
         [rtlsdr,fs,fc,f_min,f_max,nfft] = rtl_init(nfft,fs,fc,0,8.7,'double');
         fft_engine(rtlsdr,f_min,f_max,fs,nfft,fig);
    end

    function pausefcn(hObject,evt)  %pauses rendering of the spectrum
        uiwait
    end

    function resumefcn(hObject,evt) %resumes rendering of the spectrum
        uiresume
    end

    function zoomfcn(hObject,evt)
        delete(findall(gcf,'Type','hggroup'));  % delete datatip
        zoom on;
    end

    function datafcn(hObject,evt)   %enables data selection cursor
        datacursormode on;
    end

    function offset = fftoffset(hObject,evt)    %shifts Y axis by "offset" dB
        offset=str2num(get(editbox_fftoffset2,'String'));
        allFigHndl=guihandles(fig);     
        guidata(fig,allFigHndl)
        setappdata(fig,'fftoffset',offset)
    end
end        