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

filePath = fullfile(pwd, 'htra_api_mat');  

% Check whether the folder exists. If it does not exist, create it.
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'); % Pay attention to the file paths of the .dll and .h files.
end

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

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

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

IS_USB = 1;  % USB device by default. Set this value to 0 if a network-port device is used.

if IS_USB == 1
    % Configure the USB interface.
    BootProfile.PhysicalInterface = 0;
else
    % Configure the 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 the Device_Open function.
Status = calllib('htra_api', 'Device_Open', Device, DevNum, BootProfile, BootInfo);

if Status == 0
    get(BootProfile); % Print the value of BootProfile.
    get(BootInfo);    % Print the value of BootInfo.
    fprintf('The device is turned on successfully\n');
else
    % Device opening failed. Handle different error status values.
    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 the error status value.
    return;
end

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

% Define the RTA_ProfileIn pointer and RTA_ProfileOut pointer.
RTA_ProfileIn = RTA_Profile;
RTA_ProfileOut = RTA_Profile;

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

% Modify some parameters of the RTA_ProfileIn structure.
RTA_ProfileIn.CenterFreq_Hz = 2.44e9;   % Set the center frequency.
RTA_ProfileIn.RefLevel_dBm = -30;       % Set the reference level.
RTA_ProfileIn.DecimateFactor = 1;       % Set the decimation factor.
RTA_ProfileIn.TriggerAcqTime = 0.1;     % Set the acquisition time for a single trigger.
RTA_ProfileIn.TriggerMode = 0;          % FixedPoints mode.

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

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

% If the configuration is successfully applied (Status == 0)
if Status == 0
    get(RTA_FrameInfo); % Print the value 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 and terminate the function execution.
    return;
end

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

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

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

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

% Calculate the frequency axis.
Freq = 1:RTA_FrameInfo.FrameWidth;
FreqStep = (RTA_FrameInfo.StopFrequency_Hz - RTA_FrameInfo.StartFrequency_Hz) / (RTA_FrameInfo.FrameWidth - 1);
for i = 1:RTA_FrameInfo.FrameWidth   
    Freq(i) = RTA_FrameInfo.StartFrequency_Hz + FreqStep * i;
end
Freq = Freq';
        
% Create SpectrumBitmap to store the RTA probability density map.
SpectrumBitmap = libpointer('uint16Ptr', 1:RTA_FrameInfo.FrameHeight * RTA_FrameInfo.FrameWidth);

% Acquire IQ data n times.
n = 1000000000;

% Determine where to call RTA_BusTriggerStart according to the TriggerMode value.
if strcmp(RTA_ProfileOut.TriggerMode, 'Adaptive')
    % When TriggerMode is Adaptive, execute RTA_BusTriggerStart once first.
    Status = calllib('htra_api', 'RTA_BusTriggerStart', Device);
end

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

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

    for i = 1:RTA_FrameInfo.PacketCount % When RTA_ProfileOut.TriggerMode is 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 the call fails, print the error message and close the device.
            return; % Return 0 and terminate the function execution.
        end
        
        Power(:) = SpectrumStream.value(1:RTA_FrameInfo.FrameWidth * RTA_FrameInfo.PacketFrame); % Directly reshape SpectrumStream.value into a FrameWidth x PacketFrame matrix.
        Power = Power * RTA_PlotInfo.ScaleTodBm + RTA_PlotInfo.OffsetTodBm; % Apply Scale and Offset.

        time = 0:0.0667:2.4; % Assume the time axis is from 0 to 2.4 seconds with a step of 0.0667.
        surf(time, Freq, Power, 'EdgeColor', 'none'); % Plot the 3D surface.
        xlabel('Time(secs)');
        ylabel('Frequency(Hz)');
        zlabel('Power(dBm)');
        colorbar;
        colormap jet;  % Use the Jet colormap.
        view(45, 45);  % Adjust the view angle.

        % Set the colorbar range.
        caxis([-120, RTA_ProfileOut.RefLevel_dBm]);  % Set the power range of the colorbar.
        title('Spectrum Analysis');
        axis xy; axis tight; colormap(jet); 
        xlabel('Time(ms)');
        ylabel('Frequency(Hz)');
        pause(0.03);   
        
        % 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 a new data column and read the offset data from SpectrumStream.value.
                new_data = single(SpectrumStream.value(offset + 1:offset + RTA_FrameInfo.FrameWidth));  % Get the current column data.
                new_data = new_data * RTA_PlotInfo.ScaleTodBm + RTA_PlotInfo.OffsetTodBm;
                
                % Insert new_data at the end of Power and remove the first column.
                Power(:, 1:end-1) = Power(:, 2:end);  % Remove the first column of Power.
                Power(:, end) = new_data;             % Insert the new data column at the end of Power.

                % Update the offset to ensure the next read is correct.
                offset = offset + RTA_FrameInfo.FrameWidth;  % Offset by FrameWidth data points each time.
                pause(0.06);

                time = flip(0:0.0667:2.4);  % Assume the time axis is from 0 to 2.4 seconds with a step of 0.0667.
                surf(time, Freq, Power, 'EdgeColor', 'none');  % Plot the 3D surface.
                xlabel('Time(secs)');
                ylabel('Frequency(Hz)');
                zlabel('Power(dBm)');
                colorbar;
                colormap jet;  % Use the Jet colormap.
                view(45, 45);  % Adjust the view angle.

                % Set the colorbar range.
                zlim([-120, RTA_ProfileOut.RefLevel_dBm]); 
                caxis([-120, RTA_ProfileOut.RefLevel_dBm]);  % Set the power range of the colorbar.
                title('Spectrum Analysis');
                axis xy; axis tight;
                xlabel('Time(ms)');
                ylabel('Frequency(Hz)');
                pause(0.03);  % Control the display interval.
            end
        else
            Power(:) = SpectrumStream.value(1:RTA_FrameInfo.FrameWidth * RTA_FrameInfo.PacketFrame); % Directly reshape SpectrumStream.value into a FrameWidth x PacketFrame matrix.
            Power = Power * RTA_PlotInfo.ScaleTodBm + RTA_PlotInfo.OffsetTodBm; % Apply Scale and Offset.

            time = flip(0:0.0667:2.4); % Assume the time axis is from 0 to 2.4 seconds with a step of 0.0667.
            surf(time, Freq, Power, 'EdgeColor', 'none'); % Plot the 3D surface.
            xlabel('Time(secs)');
            ylabel('Frequency(Hz)');
            zlabel('Power(dBm)');
            zlim([-120, RTA_ProfileOut.RefLevel_dBm]);  % Set the z-axis range.
            colorbar;
            colormap jet;  % Use the Jet colormap.
            view(45, 45);  % Adjust the view angle.

            % Set the colorbar range.
            caxis([-120, RTA_ProfileOut.RefLevel_dBm]);  % Set the power range of the colorbar.
            caxis([-120, RTA_ProfileOut.RefLevel_dBm]);  % Set the power range of the colorbar.
            title('Spectrum Analysis');
            axis xy; axis tight; colormap(jet); 
            xlabel('Time(ms)');
            ylabel('Frequency(Hz)');
            pause(0.001);   
        end
    end
        
    % Plot the RTA spectrum.
    plot(Freq, Power);  
    ylim([-130, RTA_ProfileOut.RefLevel_dBm]);
    xlim([min(Freq), max(Freq)]);
    pause(0.03);
end

% Call the Device_Close function.
Status = calllib('htra_api', 'Device_Close', Device);

clear all;

% Unload the library file.
unloadlibrary('htra_api');   
disp('Uninstall complete')