% 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 awg.m adapted from awg.c
% \brief This program demonstrates the use of the shaped pulse feature of the 
% RadioProcessor
% \ingroup RP
% 
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');

CLOCK_FREQ = 75.0;

% User friendly names for the control bits
TX_ENABLE = 1;
TX_DISABLE = 0;
PHASE_RESET = 1;
NO_PHASE_RESET = 0;
DO_TRIGGER = 1;
NO_TRIGGER = 0;
USE_SHAPE = 1;
NO_SHAPE = 0;

% These arrays will hold the value of the shapes to be used for the
% shaped pulse feature.
dds_data = zeros(1024);		% Waveform for the DDS signal itself (normally a sinewave)
shape_data = zeros(1024);	% Waveform for the pulse shape

% 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('Using SpinAPI library version %s \n', pb_get_version());

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

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

pb_core_clock(CLOCK_FREQ);
pb_set_defaults();

% Set the contents of the arrays to the desired waveform
% (see below for the definition of these functions)
shape_data = shape_make_sinc(shape_data, 3);
dds_data = shape_make_sin(dds_data);

% Load the shape data on the board
pb_dds_load(shape_data, DEVICE_SHAPE);
pb_dds_load(dds_data, DEVICE_DDS);

fprintf('\n');
fprintf(['This program demonstrates the shaped pulse feature of the RadioProcessor. It '...
        'will output two sinc shaped pulses, with the amplitude you specify. You can '...
        'also specify the RF frequency used. The TTL outputs are enabled during the '...
        'pulse, and can be used to trigger your oscilloscope.\n\n'...
        'This is is only the basics of what you can do. Please see the RadioProcessor '...
        'documentation and source code of this program for more details.\n\n']);

fprintf('Press CTRL-C at any time to quit\n\n');

% Loop continuously, gathering parameters for the demo, and the programming
% the board appropriately.
 while true
    amp1 = input('Enter amplitude for pulse 1 (value from 0.0 to 1.0): ');
    
    amp2 = input('Enter amplitude for pulse 2 (value from 0.0 to 1.0): ');
    
    freq = input('Enter RF frequency (in MHz): ');
    
    program_and_start(amp1, amp2, freq);
 end

% Release control of the board
pb_close();

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

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


% Program the PulseBlaster-I-300 board to run a simple demo of the shaped pulse
% feature, and then trigger the program. It will output two shaped pulses,
% as described above.

function program_and_start(amp1,amp2,freq)
    load('CONST.mat');
    TX_ENABLE = 1;
    TX_DISABLE = 0;
    PHASE_RESET = 1;
    NO_PHASE_RESET = 0;
    NO_TRIGGER = 0;
    USE_SHAPE = 1;
    NO_SHAPE = 0;

    pb_set_amp(amp1, 0);
    pb_set_amp(amp2, 1);
    % There are two more amplitude registers that can be programmed, but are
    % not used for this demo program.
    % pb_set_amp(0.5, 2);
    % pb_set_amp(0.3, 3);

    % set the frequency for the sine wave
    pb_start_programming(FREQ_REGS);
    pb_set_freq(freq * MHz);
    pb_stop_programming();

    % Set the TX phase to 0.0
    pb_start_programming(TX_PHASE_REGS);  
    pb_set_phase(0.0);	% in degrees
    pb_stop_programming();

    fprintf('Amplitude 1: %f\n', amp1);
    fprintf('Amplitude 2: %f\n', amp2);
    fprintf('Freqency:    %fMHz\n', freq);

    pb_start_programming(PULSE_PROGRAM);

    %10us shaped pulse, with amplitude set by register 0. TTL outputs on
    start = pb_inst_radio_shape(0, 0, 0, 0, TX_ENABLE, NO_PHASE_RESET, NO_TRIGGER, USE_SHAPE, 0, '0F', CONTINUE, 0, 10.0 * us);
    
    %20us shaped pulse, with amplitude set by register 1. TTL outputs on
    pb_inst_radio_shape(0, 0, 0, 0, TX_ENABLE, NO_PHASE_RESET, NO_TRIGGER, USE_SHAPE, 1, '0F', CONTINUE, 0, 20.0 * us);
    
    %Output no pulse for 1ms. reset the phase. TTL outputs off. Execution
    %branches back to the beginning of the pulse program.
    pb_inst_radio_shape(0, 0, 0, 0, TX_DISABLE, PHASE_RESET, NO_TRIGGER, NO_SHAPE, 0, 0, BRANCH, start, 1.0 * ms);
      
    pb_stop_programming();

    pb_reset();
    pb_start();
end 

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 

% The following functions show how to build up arrays with different shapes
% for use with the pb_dds_load() function.

% Make a sinc shape, for use in generating soft pulses.

function shape_data = shape_make_sinc(shape_data, lobes)
    scale = lobes * 2.0 * pi;
    for i = 1:1024
        x = ((i - 512) * scale) / 1024.0;
        if x == 0 
            shape_data(i) = 1.0;
        else
            shape_data(i) = sin(x) / x;
        end
    end
end 

% Make one period of a sinewave
function dds_data = shape_make_sin(dds_data)
    for i = 1:1024
        dds_data(i) = sin(2.0 * pi * (i/1024.0));
    end 
end 

% Make a ramp function. This is an example of a different kind of shape you
% could potentially for a shaped pulse
function shape_data = shape_make_ramp(shape_data)
    for i = 1:1024
        shape_data(i) = i / 1024.0;   
    end 
end 