% fscan_cw_hop_ext_en.m
% FSCAN + CW + External Trigger HOP demo.
%
% Behavior:
%   - Configure an FSCAN frequency list from start_freq to stop_freq.
%   - Configure the output waveform as CW.
%   - Use the external trigger input as the trigger source.
%   - Each valid rising edge switches the output to the next FSCAN frequency point.
%
% Notes:
%   - Do not call channel_trigger_bus() in external trigger mode.
%   - In HOP mode, frequency switching is controlled by the trigger edge.
%   - The dwell value in tx_config_fscan() is not used as an automatic hop interval.

clc;

%% Optional compiler setup:
setenv('MW_MINGW64_LOC','C:\msys64\mingw64');mex -setup

%% Load DLL

thisDir = fileparts(mfilename('fullpath'));
if isempty(thisDir)
    thisDir = pwd;
end

apiDir = fullfile(thisDir, 'h2_api');
dllPath = fullfile(apiDir, 'h2_api.dll');
headerPath = fullfile(apiDir, 'h2_api_matlab.h');

if exist(dllPath, 'file') ~= 2
    error('Cannot find DLL file: %s', dllPath);
end

if exist(headerPath, 'file') ~= 2
    error('Cannot find header file: %s', headerPath);
end

% Add the DLL folder to PATH so that dependent DLLs can be found.
setenv('PATH', [apiDir ';' getenv('PATH')]);

% Do not force unloadlibrary here. Reuse the loaded library if it already exists.
% This avoids "Cannot unload a library that has outstanding objects" errors.
if ~libisloaded('h2_api')
    loadlibrary(dllPath, headerPath, ...
        'alias', 'h2_api', ...
        'includepath', apiDir);
end

fprintf('h2_api loaded successfully.\n');

%% Open device

Device = libpointer('voidPtrPtr');
DevNum = uint8(0);
chn = libpointer('uint16Ptr', uint16(0));

% Channel buffer. This follows the existing MATLAB demo style.
CHANNEL_COUNT = 8;
CHANNEL_STRUCT_BYTES = 16;
ch_buf = zeros(1, CHANNEL_COUNT * CHANNEL_STRUCT_BYTES, 'uint8');
ch = libpointer('uint8Ptr', ch_buf);

% device_info structure.
deviceinfo.model = 0;
deviceinfo.uid_l64 = 0;
deviceinfo.uid_h32 = 0;
deviceinfo.hardware_version = 0;
deviceinfo.mfw_version = 0;
deviceinfo.ffw_version = 0;
deviceinfo.pmu_version = 0;
deviceinfo.agu_version = 0;
deviceinfo.bus_version = 0;
deviceinfo.eio_version = 0;
deviceinfo.bus_bandwidth = 0;

deviceinfo_p = libstruct('device_info', deviceinfo);

USE_ETH = false;

if USE_ETH
    ETH_STANDARD = uint8(1);

    ethsettings.eth_interface = ETH_STANDARD;
    ethsettings.eth_is_ipv6 = uint8(0);
    ethsettings.eth_ip_address = zeros(1, 16, 'uint8');
    ethsettings.eth_ip_address(1:4) = uint8([192 168 1 100]);
    ethsettings.eth_remote_port = uint16(5000);
    ethsettings.eth_read_timeout = int32(5000);

    ethsettings_p = libstruct('eth_setting', ethsettings);

    Status = calllib('h2_api', 'device_open_eth', ...
        Device, ethsettings_p, ch, chn, deviceinfo_p);

    fprintf('device_open_eth: Status = %d\n', Status);
else
    Status = calllib('h2_api', 'device_open_usb', ...
        Device, DevNum, ch, chn, deviceinfo_p);

    fprintf('device_open_usb: Status = %d\n', Status);
end

if Status ~= 0
    error('Device open failed. Status = %d', Status);
end

fprintf('channel count = %d\n', chn.Value);
disp(get(deviceinfo_p));

%% Configure RF: FSCAN

start_freq = 1.0e9;        % Start frequency: 1 GHz
stop_freq  = 2.0e9;        % Stop frequency: 2 GHz
step_freq  = 100e6;        % Frequency step: 100 MHz
level      = single(0.0);  % Output power: 0 dBm
dwell      = single(10e-3);% Dwell time: 10 ms per frequency point

Status = calllib('h2_api', 'tx_config_fscan', ...
    ch, start_freq, stop_freq, step_freq, level, dwell);

fprintf('tx_config_fscan: Status = %d\n', Status);

if Status ~= 0
    calllib('h2_api', 'device_close', Device);
    error('tx_config_fscan failed. Status = %d', Status);
end

%% Configure trigger: External HOP

% The following enum values must match h2_typedef.h.
% Adjust them if your header uses different values.
TRIGGER_SOURCE_EXTERNAL = uint8(1);
TRIGGER_EDGE_RISING     = uint8(0);
TRIGGER_ACTION_HOP      = uint8(0);

txtrigger.source = TRIGGER_SOURCE_EXTERNAL; % External trigger input.
txtrigger.edge   = TRIGGER_EDGE_RISING;     % Respond to the rising edge.
txtrigger.action = TRIGGER_ACTION_HOP;      % One valid trigger edge switches to the next frequency point.
txtrigger.count  = int32(1);                % Kept for struct completeness. HOP mode usually ignores count.

txtrigger_p = libstruct('tx_trigger', txtrigger);

Status = calllib('h2_api', 'channel_config_trigger', ch, txtrigger_p);
fprintf('channel_config_trigger: Status = %d\n', Status);

if Status ~= 0
    calllib('h2_api', 'device_close', Device);
    error('channel_config_trigger failed. Status = %d', Status);
end

%% Configure baseband: CW

Status = calllib('h2_api', 'tx_config_cw', ch);
fprintf('tx_config_cw: Status = %d\n', Status);

if Status ~= 0
    calllib('h2_api', 'device_close', Device);
    error('tx_config_cw failed. Status = %d', Status);
end

%% Configure output

STATE_ON  = uint8(1);
STATE_OFF = uint8(0);

Status = calllib('h2_api', 'tx_config_output', ch, STATE_ON, STATE_OFF);
fprintf('tx_config_output: Status = %d\n', Status);

if Status ~= 0
    calllib('h2_api', 'device_close', Device);
    error('tx_config_output failed. Status = %d', Status);
end

%% Start channel

Status = calllib('h2_api', 'channel_start', ch);
fprintf('channel_start: Status = %d\n', Status);

if Status ~= 0
    calllib('h2_api', 'device_close', Device);
    error('channel_start failed. Status = %d', Status);
end

%% Wait for external trigger

disp('External trigger HOP mode enabled.');
disp('Waiting for external trigger rising edge...');
disp('Each valid trigger edge switches to the next FSCAN frequency point.');
disp('Do not call channel_trigger_bus() in external trigger mode.');

pause(10);

%% Close device

Status = calllib('h2_api', 'device_close', Device);
fprintf('device_close: Status = %d\n', Status);

disp('Demo complete.');
