% Configure the compilation environment
% setenv('MW_MINGW64_LOC','D:\Apps\msys64\mingw64');
% mex -setup C++

filePath = fullfile(pwd, 'htra_api_mat');  

% Check if the folder exists, create the folder if it does not
if ~exist(filePath, 'dir')
    run('htra_api.m');
    filePath = fullfile(pwd, 'htra_api_mat');  
end

% Load htra_api.dll
if not(libisloaded('htra_api.dll'))   
    loadlibrary('.\htra_api\htra_api.dll','.\htra_api\htra_api.h'); % Ensure the .dll and .h file paths are correct
end

libfunctions('htra_api'); % View all functions in the API

% Open the device
Device = libpointer; % Create Device pointer
DevNum = 0;
Status = 0;

load(fullfile(filePath, 'BootProfile.mat'));   % Directly load BootProfile_TypeDef structure
load(fullfile(filePath, 'BootInfo.mat'));  % Directly load BootInfo_TypeDef structure

IS_USB = 1;  % Default to USB device, set to 0 if using Ethernet device

if IS_USB == 1
    % Configure USB interface
    BootProfile.PhysicalInterface = 0;
else
    % Configure ETH interface
    BootProfile.PhysicalInterface = 3;
    BootProfile.ETH_IPVersion = 0;
    BootProfile.ETH_RemotePort = 5000;
    BootProfile.ETH_ReadTimeOut = 5000;
    BootProfile.ETH_IPAddress = [192, 168, 1, 100];
end

% Call Device_Open function
Status = calllib('htra_api', 'Device_Open', Device, DevNum, BootProfile, BootInfo);

if Status == 0
    get(BootProfile); % Print the values of BootProfile
    get(BootInfo); % Print the values of BootInfo    
    fprintf('The device is turned on successfully\n');
else
    % Device failed to open, handle different error statuses
    switch Status
        case -1
            fprintf('Error - Check the power supply of the device, the connection of the data cable, and check that the driver is installed correctly\n');
        case -3
            fprintf('Error - RF calibration file is missing, please copy the RF calibration file to the CalFile folder\n');
        case -4
            fprintf('Error - IF calibration file is missing, please copy the IF calibration file to the CalFile folder\n');
        case -5
            fprintf('Error - Profile is missing, please copy the profile to the CalFile folder\n');
        case -6
            fprintf('Error - The device spec file is missing, please copy the device spec file to the CalFile folder\n');
        otherwise
            fprintf('Device turn on failed: Returns another error Status = %d', Status);
    end

    % Return error status value
    return ;
end

load(fullfile(filePath, 'RTA_Profile.mat'));  % Directly load RTA_Profile_TypeDef structure

% Define RTA_ProfileIn and RTA_ProfileOut pointers
RTA_ProfileIn = RTA_Profile;
RTA_ProfileOut = RTA_Profile;

% Call RTA_ProfileDeInit function
Status = calllib('htra_api', 'RTA_ProfileDeInit', Device, RTA_ProfileIn);

% Modify certain parameters in the RTA_ProfileIn structure
RTA_ProfileIn.CenterFreq_Hz = 2.44e9;    % Set center frequency
RTA_ProfileIn.RefLevel_dBm = -20;       % Set reference level
RTA_ProfileIn.DecimateFactor = 2;       % Set decimation factor
RTA_ProfileIn.TriggerAcqTime = 0.1;     % Trigger acquisition time of 10µs
RTA_ProfileIn.TriggerMode = 0;          % FixedPoints mode

load(fullfile(filePath, 'RTA_FrameInfo.mat'));  % Directly load RTA_FrameInfo_TypeDef structure

% Call RTA_Configuration function
Status = calllib('htra_api', 'RTA_Configuration', Device, RTA_ProfileIn, RTA_ProfileOut, RTA_FrameInfo);

% If configuration delivery is successful (Status == 0)
if Status == 0
    get(RTA_FrameInfo); % Print the values of RTA_FrameInfo
    fprintf('Configuration delivery succeeded\n');
else
    % If the call fails, print the error message and close the device
    fprintf('RTA_Configuration Call error Status = %d\n', Status);
    Device_Close(Device);
    
    % Return 0 to end the function execution
    return;
end

% Directly load RTA_PlotInfo structure file
load(fullfile(filePath, 'RTA_PlotInfo.mat'));  
% Directly load TriggerInfo structure file
load(fullfile(filePath, 'TriggerInfo.mat'));  

% Directly load MeasAuxInfo structure file
load(fullfile(filePath, 'MeasAuxInfo.mat'));  

% Create SpectrumStream to store RTA spectrum data
SpectrumStream = libpointer('uint8Ptr', 1:RTA_FrameInfo.PacketValidPoints);

% % Calculate frequency axis

Freq = linspace(RTA_FrameInfo.StartFrequency_Hz, RTA_FrameInfo.StopFrequency_Hz, RTA_FrameInfo.FrameWidth);  % M points

% Create SpectrumBitmap to store RTA probability density map
SpectrumBitmap = libpointer('uint16Ptr', 1:RTA_FrameInfo.FrameHeight * RTA_FrameInfo.FrameWidth);

% Get n IQ data points
n = 1000000000;

% Determine when to call IQS_BusTriggerStart based on TriggerOutMode value
if strcmp(RTA_ProfileOut.TriggerMode, 'Adaptive')
    % When TriggerOutMode == 1, execute IQS_BusTriggerStart once
    Status = calllib('htra_api', 'RTA_BusTriggerStart', Device);
end

Power = single(zeros(RTA_FrameInfo.FrameWidth, RTA_FrameInfo.PacketFrame));

for t = 1:n
    % If TriggerOutMode == 0, execute IQS_BusTriggerStart each loop iteration
    if strcmp(RTA_ProfileOut.TriggerMode, 'FixedPoints')
        Status = calllib('htra_api', 'RTA_BusTriggerStart', Device);
    end

    for i = 1:RTA_FrameInfo.PacketCount % When RTA_ProfileOut.TriggerMode=Adaptive, RTA_FrameInfo.PacketCount = 1.
        Status = calllib('htra_api', 'RTA_GetRealTimeSpectrum', Device, SpectrumStream, SpectrumBitmap, RTA_PlotInfo, TriggerInfo, MeasAuxInfo);
        if Status ~= 0
            fprintf('RTA_GetRealTimeSpectrum Call error Status = %d\n', Status); % If call fails, print error message and close the device
            return; % Return 0 to end the function execution
        end
        
        % 确保 Power 是 (M × N)
        Power(:) = SpectrumStream.value(1:RTA_FrameInfo.FrameWidth * RTA_FrameInfo.PacketFrame); 
        Power = reshape(Power, RTA_FrameInfo.FrameWidth, RTA_FrameInfo.PacketFrame);
        Power = Power * RTA_PlotInfo.ScaleTodBm + RTA_PlotInfo.OffsetTodBm;

        time = linspace(0, 2.4, RTA_FrameInfo.PacketFrame);  % N points
        [TimeGrid, FreqGrid] = meshgrid(time, Freq);  % (M × N)
        
        % 绘图
        surf(TimeGrid, FreqGrid, Power, 'EdgeColor', 'none');
        xlabel('Time(secs)');
        ylabel('Frequency(Hz)');
        zlabel('Power(dBm)');
        zlim([-120, RTA_ProfileOut.RefLevel_dBm]);  
        caxis([-120, RTA_ProfileOut.RefLevel_dBm]);
        colorbar;
        colormap jet;
        view(45, 45);
        title('Spectrum Analysis');
        axis xy; axis tight;
        
        % Pre-create the figure object
        h = surf(time, Freq, Power, 'EdgeColor', 'none');
        xlabel('Time(secs)');
        ylabel('Frequency(Hz)');
        zlabel('Power(dBm)');
        zlim([-120, RTA_ProfileOut.RefLevel_dBm]);  
        caxis([-120, RTA_ProfileOut.RefLevel_dBm]);
        colorbar;
        colormap jet;
        view(45, 45);  % Adjust the view angle
        title('Spectrum Analysis');
        axis xy; axis tight;

        if i > 1
            offset = 0;
            for cnt = 1:RTA_FrameInfo.PacketFrame
                % Get new data column from SpectrumStream.value with the offset
                new_data = single(SpectrumStream.value(offset + 1:offset + RTA_FrameInfo.FrameWidth));  % Get current column data
                new_data = new_data * RTA_PlotInfo.ScaleTodBm + RTA_PlotInfo.OffsetTodBm;
                
                % Insert new data at the end of Power, remove the first column
                Power(:, 1:end-1) = Power(:, 2:end);  % Remove the first column of Power
                Power(:, end) = new_data;  % Insert new data column at the end

                % Update offset to ensure correct data reading next time
                offset = offset + RTA_FrameInfo.FrameWidth;  % Shift by FrameWidth data points
                pause(0.06);

                time = linspace(0, 2.4, RTA_FrameInfo.PacketFrame);  % N points
                [TimeGrid, FreqGrid] = meshgrid(time, Freq);  % (M × N)

                % 绘图
                surf(TimeGrid, FreqGrid, Power, 'EdgeColor', 'none');
                xlabel('Time(secs)');
                ylabel('Frequency(Hz)');
                zlabel('Power(dBm)');
                zlim([-120, RTA_ProfileOut.RefLevel_dBm]);  
                caxis([-120, RTA_ProfileOut.RefLevel_dBm]);
                colorbar;
                colormap jet;
                view(45, 45);
                title('Spectrum Analysis');
                axis xy; axis tight;
            end
        else
            Power(:) = SpectrumStream.value(1:RTA_FrameInfo.FrameWidth * RTA_FrameInfo.PacketFrame); % Reshape SpectrumStream.value into a FrameWidth x PacketFrame matrix
            Power = Power * RTA_PlotInfo.ScaleTodBm + RTA_PlotInfo.OffsetTodBm; % Use Scale and Offset

            time = linspace(0, 2.4, RTA_FrameInfo.PacketFrame);  % N points
            [TimeGrid, FreqGrid] = meshgrid(time, Freq);  % (M × N)

            % 绘图
            surf(TimeGrid, FreqGrid, Power, 'EdgeColor', 'none');
            xlabel('Time(secs)');
            ylabel('Frequency(Hz)');
            zlabel('Power(dBm)');
            zlim([-120, RTA_ProfileOut.RefLevel_dBm]);  
            caxis([-120, RTA_ProfileOut.RefLevel_dBm]);
            colorbar;
            colormap jet;
            view(45, 45);
            title('Spectrum Analysis');
            axis xy; axis tight;
        end
    end
        
    % Plot the RTA spectrum graph
    plot(Freq, Power);  
    ylim([-130, RTA_ProfileOut.RefLevel_dBm]);
    xlim([min(Freq), max(Freq)]);  % Set the x-axis limits to the minimum and maximum frequency values
    pause(0.03);  % Pause for 0.03 seconds
    
    end
    
    % Call the Device_Close function to close the device
    Status = calllib('htra_api', 'Device_Close', Device);
    
    clear all;  % Clear all variables from the workspace
    
    % Unload the library file
    unloadlibrary('htra_api');   
    disp('Uninstall complete'); 

