% Copyright(c) 2023 SpinCore Technologies, Inc.
% http://www.spincore.com
% 
% This software is provided 'as-is', without any express or implied warranty. 
% In no event will the authors be held liable for any damages arising from the 
% use of this software.
% 
% Permission is granted to anyone to use this software for any purpose, 
% including commercial applications, and to alter it and redistribute it
% freely, subject to the following restrictions:
% 
% 1. The origin of this software must not be misrepresented; you must not
% claim that you wrote the original software. If you use this software in a
% product, an acknowledgment in the product documentation would be appreciated
% but is not required.
% 2. Altered source versions must be plainly marked as such, and must not be
% misrepresented as being the original software.
% 3. This notice may not be removed or altered from any source distribution.
%

%
% \file DirectCapture.m adapted from DirectCapture.c
% 
% \brief This program demonstrates how to use the Direct Ram Capture feature of the 
% RadioProcessor.
% NOTE: This feature is only enabled in the PCI RadioProcessor with Firmware Revisions
% 10-14 and up and USB RadioProcessors with Firmware Revisions 12-5 and up.
% \ingroup R
%
clc; clear;

global SPINAPI_DLL_NAME

SPINAPI_DLL_NAME = 'spinapi64';

addpath('../MATLAB_SpinAPI'); % MATLAB_SpinAPI Folder path address

SpinAPI_Drive = 'C:'; % Modify to the hard drive letter that contains SpinAPI

% Loads spinapi64 library and headers
% All files are located in SpinAPI folder
if ~libisloaded('spinapi64')  % Needs the MinGW-w64 add-on
    loadlibrary([SpinAPI_Drive,'\SpinCore\SpinAPI\lib\spinapi64.dll'], ...
                 [SpinAPI_Drive,'\SpinCore\SpinAPI\include\spinapi.h'], 'addheader',...
                 [SpinAPI_Drive,'\SpinCore\SpinAPI\include\pulseblaster.h'], 'addheader',...
                 [SpinAPI_Drive,'\SpinCore\SpinAPI\include\radioprocessor.h'], 'addheader',...
                 [SpinAPI_Drive,'\SpinCore\SpinAPI\include\dds.h']);
end

% Load constants to the workspace as variables
load('CONST.mat');

%Defines for easy reading.
RAM_SIZE =(16*1024);
BOARD_STATUS_IDLE = 3;
DO_TRIGGER = 1;
NO_TRIGGER = 0;
ADC_FREQUENCY= 75.0;

%The number of points your board will acquire.
%For PCI boards, the full ram size is 16384 points.  For USB boards it is 4*16384 points.
NUMBER_POINTS = 4*16384;

%The number of scans to perform(with signal averaging enabled.)
%If you use signal averaging, please make sure that there is phase coherence between scans.
NUMBER_SCANS = 1;

% These variables are used for the Title Block in Felix  
program_type = 'DirectCapture';
data = zeros(1,NUMBER_POINTS,'int16');
data_imag = zeros(1,NUMBER_POINTS,'int16');
idata = zeros(1,NUMBER_POINTS,'int16');
idata_imag = zeros(1,NUMBER_POINTS,'int16');

% Uncommenting the line below will generate a debug log in your current
% directory that can help debug any problems that you may be experiencing   
% pb_set_debug(1);


fprintf('Copyright(c) 2023 SpinCore Technologies, Inc.\n\n');

fprintf('Using SpinAPI library version %s \n', pb_get_version());

% If there is more than one board in the system, have the user specify. 
numBoards = detect_boards();
if numBoards > 1
    select_boards(numBoards)
end

if pb_init() ~= 0
  error('Error initializing board: %s\n', pb_get_error());
end

pb_set_defaults();
pb_core_clock(ADC_FREQUENCY);	% Set the PulseBlaster Core Operating frequency.
PB_OVERFLOW_STRUCT = struct('adc',0,'cic',0,'fir',0,'average',0);
pb_overflow(1, PB_OVERFLOW_STRUCT);		% Reset the overflow counters.
pb_scan_count(1);		% Reset scan counter.

pb_set_radio_control(RAM_DIRECT);	% Enable direct ram capture.

pb_set_num_points(NUMBER_POINTS);	% This is the number of points that we are going to be capturing.

wait_time = 1000.0 *(NUMBER_POINTS) /(ADC_FREQUENCY * 1e6);	% Time in ms

pb_start_programming(PULSE_PROGRAM);
start = pb_inst_radio_shape(0, 0, 0, 0, 0, 0, NO_TRIGGER, 0, 0, '02', LOOP,NUMBER_SCANS, 1.0 * us);
pb_inst_radio_shape(0, 0, 0, 0, 0, 0, DO_TRIGGER, 0, 0, '01', END_LOOP,start, wait_time * ms);
pb_inst_radio_shape(0, 0, 0, 0, 0, 0, NO_TRIGGER, 0, 0, '02', STOP, 0,1.0 * us);
pb_stop_programming();

fprintf('Performing direct ram capture...\n');

pb_reset();
pb_start();

fprintf('Waiting for the data acquisition to complete.\n');

while pb_read_status() ~= BOARD_STATUS_IDLE  % Wait for the board to complete execution.
    pb_sleep_ms(100);
end 

[ret,data] = pb_get_data_direct(NUMBER_POINTS,data);

pb_unset_radio_control('RAM_DIRECT');	% Disable direct ram capture.

pb_close();

%pb_write_ascii('direct_data.txt', NUMBER_POINTS, 1.0, idata, idata_imag);

fileID = fopen('direct_data.txt','w');

for i = 1:NUMBER_POINTS
    fprintf(fileID,'%d\n', data(i));
end

fclose(fileID);


% The spectrometer frequency does not matter in a direct ram capture. Using 1.0 MHz for
% proper file format.

% Create Title Block String
title_string = strcat('Program = ', program_type);

for i = 1:NUMBER_POINTS
   idata(i) = data(i);
   idata_imag(i) = data_imag(i);
end

  
pb_write_felix('direct_data.fid', title_string, NUMBER_POINTS, ADC_FREQUENCY * 1e6, 1.0, idata, idata_imag);

fprintf('Press enter to continue...\n')
pause; 

% Unload library and free memory
unloadlibrary('spinapi64');


function numBoards = detect_boards()
    numBoards = pb_count_boards();
    if numBoards < 1
        error(['No Boards were detected in your system. Verify that the board is', ...
            ' firmly secured in the PCI slot.']);
    end
end

function select_boards(numBoards)
    while true
        fprintf('Found %d boards in your system. ', numBoards);
        fprintf('Which board should be used? (0-%d): ', (numBoards-1));
        choice = input('');
        if choice < 0 || choice > numBoards-1
            fprintf('Invalid Board Number (%d).\n', choice);
        else 
            pb_select_board(choice);
            fprintf('Board %d selected.\n',choice);
            break
        end 
    end 
end 