mirror of
https://github.com/KastnerRG/riffa.git
synced 2025-01-30 23:02:54 +08:00
257 lines
10 KiB
Mathematica
257 lines
10 KiB
Mathematica
|
% ----------------------------------------------------------------------
|
||
|
% Copyright (c) 2015, The Regents of the University of California All
|
||
|
% rights reserved.
|
||
|
%
|
||
|
% Redistribution and use in source and binary forms, with or without
|
||
|
% modification, are permitted provided that the following conditions are
|
||
|
% met:
|
||
|
%
|
||
|
% * Redistributions of source code must retain the above copyright
|
||
|
% notice, this list of conditions and the following disclaimer.
|
||
|
%
|
||
|
% * Redistributions in binary form must reproduce the above
|
||
|
% copyright notice, this list of conditions and the following
|
||
|
% disclaimer in the documentation and/or other materials provided
|
||
|
% with the distribution.
|
||
|
%
|
||
|
% * Neither the name of The Regents of the University of California
|
||
|
% nor the names of its contributors may be used to endorse or
|
||
|
% promote products derived from this software without specific
|
||
|
% prior written permission.
|
||
|
%
|
||
|
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
% A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
|
||
|
% UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
|
% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||
|
% OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||
|
% ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||
|
% TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||
|
% USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||
|
% DAMAGE.
|
||
|
% ----------------------------------------------------------------------
|
||
|
classdef Riffa < handle
|
||
|
% Riffa RIFFA 2.0 interface for Matlab R2008a or greater.
|
||
|
|
||
|
properties (Hidden)
|
||
|
fpga_t;
|
||
|
libname;
|
||
|
end
|
||
|
|
||
|
properties (SetAccess = private)
|
||
|
id;
|
||
|
closed; %If this value is non-zero then the FPGA is closed
|
||
|
end
|
||
|
|
||
|
|
||
|
methods
|
||
|
function obj = Riffa(id_num)
|
||
|
% Constructs a Riffa instance for FPGA with id id_num.
|
||
|
if (nargin ~= 1)
|
||
|
error('You must specify the FPGA id number.');
|
||
|
end
|
||
|
|
||
|
obj.libname = Riffa.load_lib();
|
||
|
obj.fpga_t = calllib(obj.libname,'fpga_open',id_num);
|
||
|
if isNull(obj.fpga_t)
|
||
|
obj.closed = -1;
|
||
|
error('While attempting to access FPGA.')
|
||
|
end
|
||
|
obj.id = id_num;
|
||
|
obj.closed = 0;
|
||
|
end
|
||
|
|
||
|
|
||
|
function close(obj)
|
||
|
% Closes the Riffa instance. Once closed, this instance is no longer
|
||
|
% usable.
|
||
|
if (obj.closed ~= 0)
|
||
|
error('This Riffa instance is closed.');
|
||
|
end
|
||
|
if isNull(obj.fpga_t)
|
||
|
obj.closed = -1;
|
||
|
error('Riffa FPGA handle is NULL!')
|
||
|
end
|
||
|
calllib(obj.libname,'fpga_close',obj.fpga_t);
|
||
|
obj.closed = 1;
|
||
|
end
|
||
|
|
||
|
|
||
|
function sent = send(obj, chnl, data, length, offset, last, timeout)
|
||
|
% Sends length words (4 byte words) from data to FPGA channel chnl.
|
||
|
% The FPGA channel will be sent length, destoff, and last. If last
|
||
|
% is 1, the channel should interpret the end of this send as the end
|
||
|
% of a transaction. If last is 0, the channel should wait for
|
||
|
% additional sends before the end of the transaction. If timeout is
|
||
|
% non-zero, this call will send data and wait up to timeout ms for
|
||
|
% the FPGA to respond (between packets) before timing out. If
|
||
|
% timeout is zero, this call may block indefinitely. Returns the
|
||
|
% number of words sent.
|
||
|
if obj.closed ~= 0
|
||
|
error('This Riffa instance is closed.');
|
||
|
end
|
||
|
if isNull(obj.fpga_t)
|
||
|
obj.closed = -1;
|
||
|
error('Riffa FPGA handle is NULL!')
|
||
|
end
|
||
|
if nargin ~= 7
|
||
|
error('Usage: words_sent = send(chnl, data, length, offset, last, timeout)')
|
||
|
end
|
||
|
if length < 0
|
||
|
error('Length (arg 3) must be non-negative');
|
||
|
end
|
||
|
if offset < 0
|
||
|
error('Offset (arg 4) must be non-negative');
|
||
|
end
|
||
|
if timeout < 0
|
||
|
error('Timeout (arg 6) must be non-negative');
|
||
|
end
|
||
|
fpgaptr = libpointer('fpga_tPtr', obj.fpga_t);
|
||
|
sent = calllib(obj.libname, 'fpga_send', fpgaptr, int32(chnl), ...
|
||
|
data, int32(length), int32(offset), int32(last), int64(timeout));
|
||
|
end
|
||
|
|
||
|
|
||
|
function [recvd, data] = recv(obj, chnl, length, timeout)
|
||
|
% Receives data from the FPGA channel chnl and returns it in the
|
||
|
% data variable. The FPGA channel can send any amount of data, but
|
||
|
% only length words will be returned. The FPGA channel will specify
|
||
|
% an offset which will determine where in the returned data object
|
||
|
% the data will start being written. If the amount of data (plus
|
||
|
% offset) exceed the length specified, then additional data will be
|
||
|
% discarded. If timeout is non-zero, this call will wait up to
|
||
|
% timeout ms for the FPGA to respond (between packets) before
|
||
|
% timing out. If timeout is zero, this call may block indefinitely.
|
||
|
% Returns the number of words received to the data variable.
|
||
|
if obj.closed ~= 0
|
||
|
error('This Riffa instance is closed.');
|
||
|
end
|
||
|
if isNull(obj.fpga_t)
|
||
|
obj.closed = -1;
|
||
|
error('Riffa FPGA handle is NULL!')
|
||
|
end
|
||
|
if nargin ~= 4
|
||
|
error('Usage: words_recvd = recv(chnl, length, timeout)')
|
||
|
end
|
||
|
if length < 0
|
||
|
error('Length (arg 3) must be positive');
|
||
|
end
|
||
|
if timeout < 0
|
||
|
error('Timeout (arg 4) must be positive');
|
||
|
end
|
||
|
dataptr = libpointer('voidPtr', int32(zeros(1, length)));
|
||
|
fpgaptr = libpointer('fpga_tPtr', obj.fpga_t);
|
||
|
recvd = calllib(obj.libname, 'fpga_recv', fpgaptr, int32(chnl), ...
|
||
|
dataptr, int32(length), int64(timeout));
|
||
|
recvd = min(recvd, length);
|
||
|
data = dataptr.Value;
|
||
|
data = data(1:recvd);
|
||
|
end
|
||
|
|
||
|
|
||
|
function reset(obj)
|
||
|
% Resets all FPGA channels connected to this Riffa instance.
|
||
|
if obj.closed ~= 0
|
||
|
error('This Riffa instance is closed.');
|
||
|
end
|
||
|
if isNull(obj.fpga_t)
|
||
|
obj.closed = -1;
|
||
|
error('Riffa FPGA handle is NULL!')
|
||
|
end
|
||
|
calllib(obj.libname,'fpga_reset',obj.fpga_t);
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
methods (Static)
|
||
|
function fpga_info_list = list()
|
||
|
% Returns a fpga_info_list with all FPGAs registered in the system.
|
||
|
libname = Riffa.load_lib();
|
||
|
mstruct_list = struct('num_fpgas', 0,...
|
||
|
'id', [0,0,0,0,0],...
|
||
|
'num_chnls', [0,0,0,0,0],...
|
||
|
'name', int8(zeros(1,80)),...
|
||
|
'vendor_id',[0,0,0,0,0],...
|
||
|
'device_id',[0,0,0,0,0]);
|
||
|
|
||
|
cstruct_list = libstruct('fpga_info_list',mstruct_list);
|
||
|
rc = calllib(libname,'fpga_list',cstruct_list);
|
||
|
fpga_info_list = get(cstruct_list);
|
||
|
if rc ~= 0
|
||
|
fpga_info_list.num_fpgas = 0;
|
||
|
error('Error populating the fpga_info_list struct.');
|
||
|
end
|
||
|
|
||
|
for i=1:fpga_info_list.num_fpgas
|
||
|
fpga_info_list.names{i} = char(fpga_info_list.name(((i-1)*16)+1:(i*16)));
|
||
|
end
|
||
|
|
||
|
fpga_info_list.id = fpga_info_list.id(1:fpga_info_list.num_fpgas);
|
||
|
fpga_info_list.num_chnls = fpga_info_list.num_chnls(1:fpga_info_list.num_fpgas);
|
||
|
fpga_info_list.vendor_id = fpga_info_list.vendor_id(1:fpga_info_list.num_fpgas);
|
||
|
fpga_info_list.device_id = fpga_info_list.device_id(1:fpga_info_list.num_fpgas);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
methods (Static,Hidden,Access=private)
|
||
|
function libname = load_lib()
|
||
|
% Loads the system library and returns the library name.
|
||
|
if ispc == 1
|
||
|
%disp('Running Windows platform');
|
||
|
sharedlibrary = 'C://Windows/System32/riffa.dll';
|
||
|
header = 'riffa.h';
|
||
|
libname = 'riffa';
|
||
|
elseif isunix == 1
|
||
|
%disp ('Running Unix platform');
|
||
|
sharedlibrary = '/usr/local/lib/libriffa.so';
|
||
|
header = '/usr/local/include/riffa.h';
|
||
|
libname = 'libriffa';
|
||
|
else
|
||
|
error('Not running a compatible OS.')
|
||
|
end
|
||
|
|
||
|
if not (libisloaded(libname))
|
||
|
protoname = 'riffa_proto';
|
||
|
protoext = '.m';
|
||
|
if exist(strcat(protoname, protoext), 'file') ~= 2
|
||
|
disp('Creating initial RIFFA library prototype for MATLAB.');
|
||
|
loadlibrary(sharedlibrary, header, 'mfilename', protoname);
|
||
|
buf = {};
|
||
|
d = 0;
|
||
|
searchexp = '''name''\s*,\s*''int8#''';
|
||
|
replaceexp = '''name'', ''int8#80''';
|
||
|
fd = fopen(strcat(protoname, protoext), 'r');
|
||
|
while ~feof(fd)
|
||
|
s = fgetl(fd);
|
||
|
r = regexprep(s, searchexp, replaceexp);
|
||
|
buf = vertcat(buf, r);
|
||
|
d = or(d, ~isequal(r, s));
|
||
|
end
|
||
|
fclose(fd);
|
||
|
if d == 1
|
||
|
fd = fopen(strcat(protoname, protoext), 'w+');
|
||
|
for i=1:size(buf, 1)
|
||
|
fprintf(fd,'%s\n', buf{i});
|
||
|
end
|
||
|
fclose(fd);
|
||
|
unloadlibrary(libname);
|
||
|
disp('RIFFA library prototype created.');
|
||
|
disp('This version of MATLAB has a bug that requires ');
|
||
|
disp('you exit and restart MATLAB before continuing.');
|
||
|
disp('You should only have to do this once, ever.');
|
||
|
error('Exit MATLAB and restart please.');
|
||
|
end
|
||
|
end
|
||
|
disp('Loading RIFFA library.')
|
||
|
loadlibrary(sharedlibrary, @riffa_proto);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|