% 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')
    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.
load(fullfile(filePath, 'DeviceState.mat'));   % Directly load the DeviceState_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, 'IQS_Profile.mat'));  % Directly load the IQS_Profile_TypeDef structure.

% Define the IQS_ProfileIn pointer and IQS_ProfileOut pointer.
IQS_ProfileIn = IQS_Profile;
IQS_ProfileOut = IQS_Profile;

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

% Modify the parameters of IQS mode.
IQS_ProfileIn.CenterFreq_Hz = 1e9;   % Configure the center frequency.
IQS_ProfileIn.RefLevel_dBm = 0;      % Configure the reference level.
IQS_ProfileIn.DecimateFactor = 2;    % Configure the decimation factor.
IQS_ProfileIn.TriggerMode = 1;       % Configure the trigger mode.
IQS_ProfileIn.TriggerLength = 16242; % Configure the number of points collected in a single trigger.

% Directly load the IQS_StreamInfo_TypeDef structure.
load(fullfile(filePath, 'IQS_StreamInfo.mat'));  

% Call the IQS_Configuration function.
Status = calllib('htra_api', 'IQS_Configuration', Device, IQS_ProfileIn, IQS_ProfileOut, IQS_StreamInfo);

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

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

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

DSP = libpointer; % Create a DSP pointer.
Status = calllib('htra_api', 'DSP_Open', DSP);

% Directly load the DSP_FFT_TypeDef structure.
load(fullfile(filePath, 'DSP_FFT.mat'));  

% Define the DSP_FFTIn pointer and DSP_FFTOut pointer.
DSP_FFTIn = DSP_FFT;
DSP_FFTOut = DSP_FFT;

% Define an unsigned 32-bit integer with an initial value of 0.
TracePoints = uint32(0);  
TracePoints_p = libpointer('uint32Ptr', TracePoints);
Status = calllib('htra_api', 'DSP_FFT_DeInit', DSP_FFTIn);

DSP_FFTIn.Calibration = 0;                                                        % Configure whether to enable calibration. 0 means calibration is disabled; other values enable calibration.
DSP_FFTIn.DetectionRatio = 1;                                                     % Configure the detection ratio.
DSP_FFTIn.TraceDetector = 2;                                                      % Configure the detector type.
DSP_FFTIn.FFTSize = IQS_StreamInfo.PacketSamples * IQS_StreamInfo.PacketCount;    % Configure the FFT size.
DSP_FFTIn.Intercept = 1;                                                          % Configure the intercept ratio.
DSP_FFTIn.SamplePts = IQS_StreamInfo.PacketSamples * IQS_StreamInfo.PacketCount;  % Configure the number of sample points.
DSP_FFTIn.WindowType = 0;                                                         % Configure the window type.

% Define a double-precision floating-point value.
RBWRatio = 0;  
RBWRatio_p = libpointer('doublePtr', RBWRatio);
Status = calllib('htra_api', 'DSP_FFT_Configuration', DSP, DSP_FFTIn, DSP_FFTOut, TracePoints_p, RBWRatio_p);

% Create Frequency to store the SWP frequency data.
Frequency = double(1:TracePoints_p.Value);

% Create PowerSpec_dBm to store the SWP amplitude data.
Spectrum = single(1:TracePoints_p.Value);
disp(TracePoints_p.Value)

% Create Frequency_p to store the SWP frequency data.
Frequency_p = libpointer('doublePtr', Frequency);
Spectrum_p = libpointer('singlePtr', Spectrum);

% Directly load the IQStream_TypeDef structure.
load(fullfile(filePath, 'IQStream.mat'));  

n = 10000;

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

for j = 1:n
    % If TriggerMode == FixedPoints, execute IQS_BusTriggerStart in each loop.
    if strcmp(IQS_ProfileOut.TriggerMode, 'FixedPoints')
        Status = calllib('htra_api', 'IQS_BusTriggerStart', Device);
    end

    for i = 1:IQS_StreamInfo.PacketCount      
        Status = calllib('htra_api', 'IQS_GetIQStream_PM1', Device, IQStream);      
        if Status ~= 0
            % If the call fails, print the error message and close the device.
            fprintf('IQS_GetIQStream Call error Status = %d\n', Status);

            % Return 0 and terminate the function execution.
            return;
        end
    end

    Status = calllib('htra_api', 'DSP_FFT_IQSToSpectrum', DSP, IQStream, Frequency_p, Spectrum_p);   

    if Status ~= 0
        % If the call fails, print the error message and close the device.
        fprintf('DSP_FFT_IQSToSpectrum Call error Status = %d\n', Status);

        % Return 0 and terminate the function execution.
        return;
    end

    % Plot the SWP spectrum.
    plot(Frequency_p.Value, Spectrum_p.Value);
    ylim([-130, IQStream.IQS_Profile.RefLevel_dBm]);
    xlim([min(Frequency_p.Value), max(Frequency_p.Value)]);
    pause(0.01);
end

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

% Call the DSP_Close function.
Status = calllib('htra_api', 'DSP_Close', DSP);

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

clear all;

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