% Configure the compilation environment
% setenv('MW_MINGW64_LOC','D:\msys64\ucrt64');
% 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')
    mkdir(filePath);  % Create the target folder.
    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('Device 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, 'SWP_Profile.mat'));  % Directly load the SWP_Profile_TypeDef structure.

% Define the SWP_ProfileIn pointer and SWP_ProfileOut pointer.
SWP_ProfileIn = SWP_Profile;
SWP_ProfileOut = SWP_Profile;

% Call the SWP_ProfileDeInit function.
Status = calllib('htra_api', 'SWP_ProfileDeInit', Device, SWP_ProfileIn);
get(SWP_ProfileIn); % Print the value of SWP_ProfileIn.

% Modify some parameters of the SWP_ProfileIn structure.
SWP_ProfileIn.StartFreq_Hz = 9e3; % Configure the start frequency.
SWP_ProfileIn.StopFreq_Hz = 3e9;  % Configure the stop frequency.
SWP_ProfileIn.RefLevel_dBm = 0;   % Configure the reference level.
SWP_ProfileIn.RBWMode = 0;        % Configure RBWMode.
SWP_ProfileIn.RBW_Hz = 300e3;     % Configure RBW.

load(fullfile(filePath, 'TraceInfo.mat'));  % Directly load the SWP_TraceInfo_TypeDef structure.

% Call the SWP_Configuration function.
Status = calllib('htra_api', 'SWP_Configuration', Device, SWP_ProfileIn, SWP_ProfileOut, TraceInfo);

% If the configuration is successfully applied (Status == 0)
if Status == 0
    get(SWP_ProfileOut); % Print the value of SWP_ProfileOut.
    get(TraceInfo);      % Print the value of TraceInfo.
    fprintf('Configuration successfully\n');
else
    % If the call fails, print the error message and close the device.
    fprintf('SWP_Configuration Call error Status = %d\n', Status);
    Device_Close(Device); 
    
    % Return 0 and terminate the function execution.
    return;
end

% Create Frequency to store SWP frequency data, and create PowerSpec_dBm to store SWP amplitude data.
Frequency = double(1:TraceInfo.FullsweepTracePoints);
PowerSpec_dBm = single(1:TraceInfo.FullsweepTracePoints);

% Convert C-language type parameters to MATLAB types.
Frequency_p = libpointer('doublePtr', Frequency);
PowerSpec_dBm_p = libpointer('singlePtr', PowerSpec_dBm);

% The full spectrum of this device is formed by stitching multiple frames together.
% This parameter is used to return the sequence number of the current frame during the stitching process.
HopIndex = int32(0);

% Indicates the index of the current frame among all frames, used to identify the position of the current frame being processed.
FrameIndex = int32(0);

% Create the HopIndex_p pointer.
HopIndex_p = libpointer('int32Ptr', HopIndex);

% Create the FrameIndex_p pointer.
FrameIndex_p = libpointer('int32Ptr', FrameIndex);

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

% Acquire SWP data n times.
n = 10000; 
for t = 1:n
    % TraceInfo.TotalHops represents the number of frames under the current configuration.
    % Therefore, calling SWP_GetPartialSweep TraceInfo.TotalHops times can obtain a complete trace.
    for i = 1:TraceInfo.TotalHops 
        Status = calllib('htra_api', 'SWP_GetPartialSweep', Device, Frequency_p + (i-1) * TraceInfo.PartialsweepTracePoints, PowerSpec_dBm_p + (i-1) * TraceInfo.PartialsweepTracePoints, HopIndex_p, FrameIndex_p, MeasAuxInfo);     
        if Status ~= 0
            % If the call fails, print the error message and close the device.
            fprintf('SWP_Configuration Call error Status = %d\n', Status);

            % Return 0 and terminate the function execution.
            return;
        end
    end
    
    nPeaks = 6;  % Assume there are up to 6 peaks.
    [Power_Max, Freq_Max] = deal([]);  % Initialize.
    Power_temp = PowerSpec_dBm_p.Value;

    % Plot the SWP spectrum.
    plot(Frequency_p.Value, PowerSpec_dBm_p.Value);
    ylim([-130, SWP_ProfileOut.RefLevel_dBm]);
    xlim([min(Frequency_p.Value), max(Frequency_p.Value)]);
    hold on;
    
    for i = 1:nPeaks
        [maxValue, maxIndex] = max(Power_temp);  % Find the maximum value in the current array and its index.
        Power_Max(i) = maxValue;                 % Store the maximum value in the result array.
        Freq_Max(i) = Frequency_p.Value(maxIndex);
        Power_temp(maxIndex) = -Inf;             % Set the position of the maximum value to negative infinity to find the next maximum value.
   
        bar(Frequency_p.Value(maxIndex), maxValue, 'r', 'LineStyle', ':');
        text(Frequency_p.Value(maxIndex), SWP_ProfileOut.RefLevel_dBm, char('a' + i - 1), 'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom');
        text(0.05, 1-0.05*i, [char('a' + i - 1)  ': Frequency: ' num2str(Frequency_p.Value(maxIndex)), ': Power: ' num2str(maxValue)], 'Units', 'normalized');
    end
    
    xlabel('Frequency');
    ylabel('Power');
    pause(0.01); 
    clf;
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');