% 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 pb24_ex2.m adapted from pb24_ex2.c
% \brief This example makes use of all instructions (except WAIT).
% The user will see:
%  -the outputs on for 1.0 second
%  -the outputs off for 0.5 seconds
%  -half of the outputs (0xF0F0F0) on for 0.5 seconds
%  -the outputs turning off and on three times with a period of 0.3 seconds 
%  -the outputs off for 1.5 seconds
% 
% This program loops back to the begining when it finishes.
% \ingroup pb24
%
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');

% 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


% User input clock
clock = input_clock();

fprintf('Clock frequency: %fMHz\n\n', clock);
fprintf('The outputs should now be repeating the following pattern:\n\n');
fprintf('-on for 1.0 second\n');
fprintf('-off for 0.5 seconds\n');
fprintf('-half (0xF0F0F0) on for 0.5 seconds\n');
fprintf('-off and on three times with a period of 0.3 seconds\n');
fprintf('-off for 1.5 seconds\n\n');

% Tell the driver what clock frequency the board has (in MHz)
pb_core_clock(clock);

pb_start_programming(PULSE_PROGRAM);

% Since we are going to jump forward in our program, we need to 
% define this variable by hand.  Instructions start at 0 and count up
sub = 5;

% Instruction format
% int pb_inst(int flags, int inst, int inst_data, int length)

% Instruction 0 - Jump to Subroutine at Instruction 5 in 1s
start = pb_inst_pbonly('FFFFFF', JSR, sub, 1000.0 * ms);

% Loop. Instructions 1 and 2 will be repeated 3 times
% Instruction 1 - Beginning of Loop (Loop 3 times).  Continue to next
% instruction in 1s
loop = pb_inst_pbonly(0, LOOP, 3, 150.0 * ms);
% Instruction 2 - End of Loop.  Return to beginning of loop or continue
% to next instruction in .5 s
pb_inst_pbonly('FFFFFF', END_LOOP, loop, 150.0 * ms);

%  Instruction 3 - Stay here for (5*100ms) then continue to Instruction 4
pb_inst_pbonly(0, LONG_DELAY, 5, 100.0 * ms);

% Instruction 4 - Branch to 'start' (Instruction 0) in 1 s
pb_inst_pbonly(0, BRANCH, start, 1000.0 * ms);

% Subroutine
% Instruction 5 - Continue to next instruction in 1 * s
pb_inst_pbonly(0, CONTINUE, 0, 500.0 * ms);
% Instruction 6 - Return from Subroutine to Instruction 1 in .5*s
pb_inst_pbonly('F0F0F0', RTS, 0, 500.0 * ms);

pb_stop_programming();

% Trigger the pulse program
pb_reset();
pb_start();

% Read the status register
status = pb_read_status();
fprintf('status: %d \n', status);
fprintf(pb_status_message());
fprintf('\n');

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

pb_stop();
pb_close();

% 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 

function clock = input_clock()
    clock = input('\nPlease enter internal clock frequency (MHz): ');
end