% 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'))   
    try
        % Try to load the dynamic link library and its header file.
        loadlibrary('.\htra_api\htra_api.dll','.\htra_api\htra_api.h'); 
    catch ME
        % Catch any errors that may occur during loading. ME is an MException object that contains detailed error information.
        fprintf('Failed to load htra_api.dll or htra_api.h: %s\n', ME.message);
        
        % Terminate the program. Please check whether htra_api.dll or htra_api.h exists in the htra_api folder located in the same directory as this .m file.
        % If these two files do not exist, please copy htra_api.dll or htra_api.h from the attached materials\Windows\HTRA_API\x64\htra_api folder to the htra_api folder located in the same directory as this .m file.
        fprintf('The program will end, please check whether the file path and file exist.\n');
        
        return;
        % Terminate the execution of the current function or script.
    end
end

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

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

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

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

IS_USB = 0;  % Defaults to network device, set IS_USB to 1 for USB device.

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

% Directly load the IQS_Profile_TypeDef structure.
load(fullfile(filePath, 'IQS_Profile.mat')); 

% 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 some parameters of the IQS_ProfileIn structure.
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 = 0;        % Configure the trigger mode.
IQS_ProfileIn.TriggerLength = 16384;  % 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')); 

IQ_data = int16(1:IQS_StreamInfo.PacketSamples * 2);

% Interleaved IQ time-domain data. A single channel may be in i8, i16, or i32 format.
AlternIQStream = libpointer('int16Ptr', IQ_data);

% Coefficient for converting integer values to absolute voltage values in volts.
ScaleToV = single(0);                                           
ScaleToV_p = libpointer('singlePtr', ScaleToV);

% Create I and Q arrays to store I and Q data separately.
I_data = 1:IQS_StreamInfo.StreamSamples;
Q_data = 1:IQS_StreamInfo.StreamSamples;

% Acquire IQ data n times.
n = 10000;

% Determine where to call IQS_BusTriggerStart and how much array space to allocate 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);
    I_data = 1:IQS_StreamInfo.PacketSamples;
    Q_data = 1:IQS_StreamInfo.PacketSamples;
end

for j = 1:n
    if strcmp(IQS_ProfileOut.TriggerMode, 'FixedPoints')
        Status = calllib('htra_api', 'IQS_BusTriggerStart', Device);
    end

    for i = 1:IQS_StreamInfo.PacketCount
        if Status == 0
            Status = calllib('htra_api', 'IQS_GetIQStream', Device, AlternIQStream, ScaleToV_p, TriggerInfo, MeasAuxInfo);
            
            % Determine the valid number of points in the current packet, especially for the last packet.
            if i == IQS_StreamInfo.PacketCount && ...
               mod(IQS_StreamInfo.StreamSamples, IQS_StreamInfo.PacketSamples) ~= 0 && ...
               strcmp(IQS_ProfileOut.TriggerMode, 'FixedPoints')
                Points = mod(IQS_StreamInfo.StreamSamples, IQS_StreamInfo.PacketSamples);
            else
                Points = IQS_StreamInfo.PacketSamples;
            end

            % Calculate the storage offset. MATLAB indexing starts from 1.
            offset = (i-1) * IQS_StreamInfo.PacketSamples;

            % Extract the current data packet and convert it.
            currentIQ = double(AlternIQStream.Value(1:2*Points)) * ScaleToV_p.Value;

            % Separate I/Q data and store them into arrays.
            I_Data(offset+1 : offset+Points) = currentIQ(1:2:end);
            Q_Data(offset+1 : offset+Points) = currentIQ(2:2:end);
           
        else
            fprintf('IQS_GetIQStream Call error Status = %d\n', Status);
            return;
        end
    end
       
    % Dynamically plot the accumulated data.
    currentEnd = offset + Points;
    plot(1:currentEnd, I_Data(1:currentEnd), 1:currentEnd, Q_Data(1:currentEnd));

    % Dynamically adjust the axes.
    currentY = [I_Data(1:currentEnd), Q_Data(1:currentEnd)];
    yMin = min(currentY);
    yMax = max(currentY);
    axis([0 currentEnd yMin yMax]);

    pause(0.01);
end

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

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

clear all;

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