702 lines
30 KiB
Matlab
702 lines
30 KiB
Matlab
|
% Copyright 2014(c) Analog Devices, Inc.
|
||
|
%
|
||
|
% 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 Analog Devices, Inc. nor the names of its
|
||
|
% contributors may be used to endorse or promote products derived
|
||
|
% from this software without specific prior written permission.
|
||
|
% - The use of this software may or may not infringe the patent rights
|
||
|
% of one or more patent holders. This license does not release you
|
||
|
% from the requirement that you obtain separate licenses from these
|
||
|
% patent holders to use this software.
|
||
|
% - Use of the software either in source or binary form or filter designs
|
||
|
% resulting from the use of this software, must be connected to, run
|
||
|
% on or loaded to an Analog Devices Inc. component.
|
||
|
%
|
||
|
% THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||
|
% INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
|
||
|
% PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
|
%
|
||
|
% IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||
|
% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY
|
||
|
% RIGHTS, 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 libiio_if < handle
|
||
|
% libiio_if Interface object for for IIO devices
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Protected properties
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
properties (Access = protected)
|
||
|
libname = 'libiio';
|
||
|
hname = 'iio-wrapper.h';
|
||
|
dev_name = '';
|
||
|
data_ch_no = 0;
|
||
|
data_ch_size = 0;
|
||
|
dev_type = '';
|
||
|
iio_ctx = {};
|
||
|
iio_dev = {};
|
||
|
iio_buffer = {};
|
||
|
iio_channel = {};
|
||
|
iio_buf_size = 8192;
|
||
|
iio_scan_elm_no = 0;
|
||
|
if_initialized = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Static private methods
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
methods (Static, Access = private)
|
||
|
function out = modInstanceCnt(val)
|
||
|
% Manages the number of object instances to handle proper DLL unloading
|
||
|
persistent instance_cnt;
|
||
|
if isempty(instance_cnt)
|
||
|
instance_cnt = 0;
|
||
|
end
|
||
|
instance_cnt = instance_cnt + val;
|
||
|
out = instance_cnt;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Protected methods
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
methods (Access = protected)
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Creates the network context
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, err_msg, msg_log] = createNetworkContext(obj, ip_address)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
err_msg = '';
|
||
|
msg_log = [];
|
||
|
|
||
|
% Create the network context
|
||
|
obj.iio_ctx = calllib(obj.libname, 'iio_create_network_context', ip_address);
|
||
|
|
||
|
% Check if the network context is valid
|
||
|
if (isNull(obj.iio_ctx))
|
||
|
obj.iio_ctx = {};
|
||
|
err_msg = 'Could not connect to the IIO server!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Increase the object's instance count
|
||
|
libiio_if.modInstanceCnt(1);
|
||
|
msg_log = [msg_log sprintf('%s: Connected to IP %s\n', class(obj), ip_address)];
|
||
|
|
||
|
% Set the return code to success
|
||
|
ret = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Releases the network context and unload the libiio library
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function releaseContext(obj)
|
||
|
calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx);
|
||
|
obj.iio_ctx = {};
|
||
|
instCnt = libiio_if.modInstanceCnt(-1);
|
||
|
if(instCnt == 0)
|
||
|
unloadlibrary(obj.libname);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Checks the compatibility of the different software modules.
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, err_msg, msg_log] = checkVersions(obj)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
err_msg = '';
|
||
|
msg_log = [];
|
||
|
|
||
|
% Create a set of pointers to read the iiod and dll versions
|
||
|
data = zeros(1, 10);
|
||
|
remote_pMajor = libpointer('uint32Ptr', data(1));
|
||
|
remote_pMinor = libpointer('uint32Ptr', data(2));
|
||
|
remote_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]);
|
||
|
local_pMajor = libpointer('uint32Ptr', data(1));
|
||
|
local_pMinor = libpointer('uint32Ptr', data(2));
|
||
|
local_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]);
|
||
|
|
||
|
% get remote libiio version
|
||
|
calllib(obj.libname, 'iio_context_get_version', obj.iio_ctx, remote_pMajor, remote_pMinor, remote_pGitTag);
|
||
|
% extract git hash without trailing null char
|
||
|
remote_githash = remote_pGitTag.Value(1:7);
|
||
|
remote_version_str = sprintf('Remote libiio version: %d.%d, (git-%s)', remote_pMajor.Value, remote_pMinor.Value, remote_githash);
|
||
|
msg_log = [msg_log sprintf('%s: %s\n', class(obj), remote_version_str)];
|
||
|
|
||
|
% get local libiio version
|
||
|
calllib(obj.libname, 'iio_library_get_version', local_pMajor, local_pMinor, local_pGitTag);
|
||
|
local_githash = local_pGitTag.Value(1:7);
|
||
|
local_version_str = sprintf('Local libiio version: %d.%d, (git-%s)', local_pMajor.Value, local_pMinor.Value, local_githash);
|
||
|
msg_log = [msg_log sprintf('%s: %s\n', class(obj), local_version_str)];
|
||
|
|
||
|
if(remote_pMajor.Value < local_pMajor.Value)
|
||
|
err_msg = ['The libiio version running on the device is outdated! ' ...
|
||
|
'Run the adi_update_tools.sh script to get libiio up to date.'];
|
||
|
return;
|
||
|
elseif(remote_pMajor.Value > local_pMajor.Value)
|
||
|
err_msg = ['The libiio version on the local host is outdated! ' ...
|
||
|
'On Windows, reinstall the dll using the latest installer ' ...
|
||
|
'from the Analog Devices wiki.'];
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Set the return code to success
|
||
|
ret = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Detect if the specified device is present in the system
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, err_msg, msg_log] = initDevice(obj, dev_name)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
err_msg = '';
|
||
|
msg_log = [];
|
||
|
|
||
|
% Store the device name
|
||
|
obj.dev_name = dev_name;
|
||
|
|
||
|
% Get the number of devices
|
||
|
nb_devices = calllib(obj.libname, 'iio_context_get_devices_count', obj.iio_ctx);
|
||
|
|
||
|
% If no devices are present return with error
|
||
|
if(nb_devices == 0)
|
||
|
err_msg = 'No devices were detected in the system!';
|
||
|
return;
|
||
|
end
|
||
|
msg_log = [msg_log sprintf('%s: Found %d devices in the system\n', class(obj), nb_devices)];
|
||
|
|
||
|
% Detect if the targeted device is installed
|
||
|
dev_found = 0;
|
||
|
for i = 0 : nb_devices - 1
|
||
|
dev = calllib(obj.libname, 'iio_context_get_device', obj.iio_ctx, i);
|
||
|
name = calllib(obj.libname, 'iio_device_get_name', dev);
|
||
|
if(strcmp(name, dev_name))
|
||
|
obj.iio_dev = dev;
|
||
|
dev_found = 1;
|
||
|
break;
|
||
|
end
|
||
|
clear dev;
|
||
|
end
|
||
|
|
||
|
% Check if the target device was detected
|
||
|
if(dev_found == 0)
|
||
|
err_msg = 'Could not find target configuration device!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
msg_log = [msg_log sprintf('%s: %s was found in the system\n', class(obj), obj.dev_name)];
|
||
|
|
||
|
% Set the return code to success
|
||
|
ret = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Initializes the output data channels
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, err_msg, msg_log] = initOutputDataChannels(obj, ch_no, ch_size)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
err_msg = '';
|
||
|
msg_log = [];
|
||
|
|
||
|
% Save the number of channels and size
|
||
|
obj.data_ch_no = ch_no;
|
||
|
obj.data_ch_size = ch_size;
|
||
|
|
||
|
% Get the number of channels that the device has
|
||
|
nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev);
|
||
|
if(nb_channels == 0)
|
||
|
err_msg = 'The selected device does not have any channels!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Enable the data channels
|
||
|
if(ch_no ~= 0)
|
||
|
% Check if the device has output channels. The
|
||
|
% logic here assumes that a device can have
|
||
|
% only input or only output channels
|
||
|
obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0);
|
||
|
is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1});
|
||
|
if(is_output == 0)
|
||
|
err_msg = 'The selected device does not have output channels!';
|
||
|
return;
|
||
|
end
|
||
|
% Enable all the channels
|
||
|
for j = 0 : nb_channels - 1
|
||
|
obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j);
|
||
|
calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1});
|
||
|
is_scan_element = calllib(obj.libname, 'iio_channel_is_scan_element', obj.iio_channel{j+1});
|
||
|
if(is_scan_element == 1)
|
||
|
obj.iio_scan_elm_no = obj.iio_scan_elm_no + 1;
|
||
|
end
|
||
|
end
|
||
|
msg_log = [msg_log sprintf('%s: Found %d output channels for the device %s\n', class(obj), obj.iio_scan_elm_no, obj.dev_name)];
|
||
|
|
||
|
% Check if the number of channels in the device
|
||
|
% is greater or equal to the system object
|
||
|
% input channels
|
||
|
if(obj.iio_scan_elm_no < ch_no)
|
||
|
obj.iio_channel = {};
|
||
|
err_msg = 'The selected device does not have enough output channels!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Enable the DAC buffer output
|
||
|
obj.if_initialized = 1;
|
||
|
ret = writeAttributeString(obj, 'altvoltage0*raw', '0');
|
||
|
obj.if_initialized = 0;
|
||
|
if(ret < 0)
|
||
|
obj.iio_channel = {};
|
||
|
err_msg = 'Could not enable the DAC buffer output!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Create the IIO buffer used to write data
|
||
|
obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no;
|
||
|
obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,...
|
||
|
obj.data_ch_size, 1);
|
||
|
end
|
||
|
|
||
|
msg_log = [msg_log sprintf('%s: %s output data channels successfully initialized\n', class(obj), obj.dev_name)];
|
||
|
|
||
|
% Set the return code to success
|
||
|
ret = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Initializes the input data channels
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, err_msg, msg_log] = initInputDataChannels(obj, ch_no, ch_size)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
err_msg = '';
|
||
|
msg_log = [];
|
||
|
|
||
|
% Save the number of channels and size
|
||
|
obj.data_ch_no = ch_no;
|
||
|
obj.data_ch_size = ch_size;
|
||
|
|
||
|
% Get the number of channels that the device has
|
||
|
nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev);
|
||
|
if(nb_channels == 0)
|
||
|
err_msg = 'The selected device does not have any channels!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Enable the system object output channels
|
||
|
if(ch_no ~= 0)
|
||
|
% Check if the device has input channels. The
|
||
|
% logic here assumes that a device can have
|
||
|
% only input or only output channels
|
||
|
obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0);
|
||
|
is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1});
|
||
|
if(is_output == 1)
|
||
|
err_msg = 'The selected device does not have input channels!';
|
||
|
return;
|
||
|
end
|
||
|
msg_log = [msg_log sprintf('%s: Found %d input channels for the device %s\n', class(obj), nb_channels, obj.dev_name)];
|
||
|
|
||
|
% Check if the number of channels in the device
|
||
|
% is greater or equal to the system object
|
||
|
% output channels
|
||
|
if(nb_channels < ch_no)
|
||
|
obj.iio_channel = {};
|
||
|
err_msg = 'The selected device does not have enough input channels!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Enable the channels
|
||
|
for j = 0 : ch_no - 1
|
||
|
obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j);
|
||
|
calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1});
|
||
|
end
|
||
|
for j = ch_no : nb_channels - 1
|
||
|
obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j);
|
||
|
calllib(obj.libname, 'iio_channel_disable', obj.iio_channel{j+1});
|
||
|
end
|
||
|
% Create the IIO buffer used to read data
|
||
|
obj.iio_buf_size = obj.data_ch_size * obj.data_ch_no;
|
||
|
obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev, obj.iio_buf_size, 0);
|
||
|
end
|
||
|
|
||
|
msg_log = [msg_log sprintf('%s: %s input data channels successfully initialized\n', class(obj), obj.dev_name)];
|
||
|
|
||
|
% Set the return code to success
|
||
|
ret = 0;
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Public methods
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
methods
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Constructor
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function obj = libiio_if()
|
||
|
% Constructor
|
||
|
obj.if_initialized = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Destructor
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function delete(obj)
|
||
|
% Release any resources used by the system object.
|
||
|
if((obj.if_initialized == 1) && libisloaded(obj.libname))
|
||
|
if(~isempty(obj.iio_buffer))
|
||
|
calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer);
|
||
|
end
|
||
|
if(~isempty(obj.iio_ctx))
|
||
|
calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx);
|
||
|
end
|
||
|
obj.iio_buffer = {};
|
||
|
obj.iio_channel = {};
|
||
|
obj.iio_dev = {};
|
||
|
obj.iio_ctx = {};
|
||
|
instCnt = libiio_if.modInstanceCnt(-1);
|
||
|
if(instCnt == 0)
|
||
|
unloadlibrary(obj.libname);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Initializes the libiio interface
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, err_msg, msg_log] = init(obj, ip_address, ...
|
||
|
dev_name, dev_type, ...
|
||
|
data_ch_no, data_ch_size)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
err_msg = '';
|
||
|
msg_log = [];
|
||
|
|
||
|
% Save the device type
|
||
|
obj.dev_type = dev_type;
|
||
|
|
||
|
% Set the initialization status to fail
|
||
|
obj.if_initialized = 0;
|
||
|
|
||
|
% Load the libiio library
|
||
|
if(~libisloaded(obj.libname))
|
||
|
try
|
||
|
% ignore unknown type warnings due to header parsing limitations
|
||
|
warnState = warning('off', 'MATLAB:loadlibrary:TypeNotFound');
|
||
|
cleanupObj = onCleanup(@()warning(warnState));
|
||
|
[notfound, warnings] = loadlibrary(obj.libname, obj.hname, 'addheader', 'iio.h');
|
||
|
cleanupObj = []; % restore the warning state
|
||
|
catch exception
|
||
|
err_msg = exception.message;
|
||
|
return;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if(~libisloaded(obj.libname))
|
||
|
err_msg = 'Could not load the libiio library!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Create the network context
|
||
|
[ret, err_msg, msg_log] = createNetworkContext(obj, ip_address);
|
||
|
if(ret < 0)
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Check the software versions
|
||
|
[ret, err_msg, msg_log_new] = checkVersions(obj);
|
||
|
msg_log = [msg_log msg_log_new];
|
||
|
if(ret < 0)
|
||
|
releaseContext(obj);
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Initialize the device
|
||
|
[ret, err_msg, msg_log_new] = initDevice(obj, dev_name);
|
||
|
msg_log = [msg_log msg_log_new];
|
||
|
if(ret < 0)
|
||
|
releaseContext(obj);
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Initialize the output data channels
|
||
|
if(strcmp(dev_type, 'OUT'))
|
||
|
[ret, err_msg, msg_log_new] = initOutputDataChannels(obj, data_ch_no, data_ch_size);
|
||
|
msg_log = [msg_log msg_log_new];
|
||
|
if(ret < 0)
|
||
|
releaseContext(obj);
|
||
|
return;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
% Initialize the input data channels
|
||
|
if(strcmp(dev_type, 'IN'))
|
||
|
[ret, err_msg, msg_log_new] = initInputDataChannels(obj, data_ch_no, data_ch_size);
|
||
|
msg_log = [msg_log msg_log_new];
|
||
|
if(ret < 0)
|
||
|
releaseContext(obj);
|
||
|
return;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
% Set the initialization status to success
|
||
|
obj.if_initialized = 1;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Implement the data capture flow
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, data] = readData(obj)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
data = cell(1, obj.data_ch_no);
|
||
|
for i = 1 : obj.data_ch_no
|
||
|
data{i} = zeros(obj.data_ch_size, 1);
|
||
|
end
|
||
|
|
||
|
% Check if the interface is initialized
|
||
|
if(obj.if_initialized == 0)
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Check if the device type is output
|
||
|
if(~strcmp(obj.dev_type, 'IN'))
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Read the data
|
||
|
calllib(obj.libname, 'iio_buffer_refill', obj.iio_buffer);
|
||
|
buffer = calllib(obj.libname, 'iio_buffer_first', obj.iio_buffer, obj.iio_channel{1});
|
||
|
setdatatype(buffer, 'int16Ptr', obj.iio_buf_size);
|
||
|
for i = 1 : obj.data_ch_no
|
||
|
data{i} = double(buffer.Value(i:obj.data_ch_no:end));
|
||
|
end
|
||
|
|
||
|
% Set the return code to success
|
||
|
ret = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Implement the data transmit flow
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function ret = writeData(obj, data)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
|
||
|
% Check if the interface is initialized
|
||
|
if(obj.if_initialized == 0)
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Check if the device type is input
|
||
|
if(~strcmp(obj.dev_type, 'OUT'))
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Destroy the buffer
|
||
|
calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer);
|
||
|
obj.iio_buffer = {};
|
||
|
|
||
|
% Enable the DAC buffer output
|
||
|
ret = writeAttributeString(obj, 'altvoltage0*raw', '0');
|
||
|
if(ret < 0)
|
||
|
obj.iio_channel = {};
|
||
|
err_msg = 'Could not enable the DAC buffer output!';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Create the IIO buffer used to write data
|
||
|
obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no;
|
||
|
obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,...
|
||
|
obj.data_ch_size, 1);
|
||
|
|
||
|
% Transmit the data
|
||
|
buffer = calllib(obj.libname, 'iio_buffer_start', obj.iio_buffer);
|
||
|
setdatatype(buffer, 'int16Ptr', obj.iio_buf_size);
|
||
|
for i = 1 : obj.data_ch_no
|
||
|
buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = int16(data{i});
|
||
|
end
|
||
|
for i = obj.data_ch_no + 1 : obj.iio_scan_elm_no
|
||
|
buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = 0;
|
||
|
end
|
||
|
calllib(obj.libname, 'iio_buffer_push', obj.iio_buffer);
|
||
|
|
||
|
% Set the return code to success
|
||
|
ret = 0;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Find an attribute based on the name. The name can contain wildcard '*' characters
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, ch, attr] = findAttribute(obj, attr_name)
|
||
|
% Initialize the return values
|
||
|
ret = -1;
|
||
|
ch = 0;
|
||
|
attr = '';
|
||
|
|
||
|
% Check if the interface is initialized
|
||
|
if(obj.if_initialized == 0)
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Check if this is a device attribute
|
||
|
name = calllib(obj.libname, 'iio_device_find_attr', obj.iio_dev, attr_name);
|
||
|
if(~isempty(name))
|
||
|
ret = 0;
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% This is a channel attribute, search for the corresponding channel
|
||
|
chn_no = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev);
|
||
|
for k = 0 : chn_no - 1
|
||
|
ch = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, k);
|
||
|
attr_no = calllib(obj.libname, 'iio_channel_get_attrs_count', ch);
|
||
|
attr_found = 0;
|
||
|
for l = 0 : attr_no - 1
|
||
|
attr = calllib(obj.libname, 'iio_channel_get_attr', ch, l);
|
||
|
name = calllib(obj.libname, 'iio_channel_attr_get_filename', ch, attr);
|
||
|
% The attribute to find can contain wildcard '*' characters,
|
||
|
% search for all the substrings in the attribute name
|
||
|
str_find = strsplit(attr_name, '*');
|
||
|
str_find = str_find(find(~strcmp(str_find, '')));
|
||
|
has_wildcard = ~isempty(strfind(attr_name, '*'));
|
||
|
attr_found = 1;
|
||
|
for i = 1 : length(str_find)
|
||
|
if(has_wildcard == 0)
|
||
|
ret = strcmp(name, str_find{i});
|
||
|
if(ret == 0)
|
||
|
ret = [];
|
||
|
end
|
||
|
else
|
||
|
ret = strfind(name, str_find{i});
|
||
|
end
|
||
|
if(isempty(ret))
|
||
|
attr_found = 0;
|
||
|
break;
|
||
|
end
|
||
|
end
|
||
|
if(attr_found == 1)
|
||
|
break;
|
||
|
end
|
||
|
clear attr;
|
||
|
end
|
||
|
% Check if the attribute was found
|
||
|
if(attr_found == 0)
|
||
|
clear ch;
|
||
|
else
|
||
|
ret = 1;
|
||
|
break;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Read an attribute as a double value
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, val] = readAttributeDouble(obj, attr_name)
|
||
|
% Find the attribute
|
||
|
[ret, ch, attr] = findAttribute(obj, attr_name);
|
||
|
if(ret < 0)
|
||
|
val = 0;
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Create a double pointer to be used for data read
|
||
|
data = zeros(1, 10);
|
||
|
pData = libpointer('doublePtr', data(1));
|
||
|
|
||
|
% Read the attribute value
|
||
|
if(ret > 0)
|
||
|
calllib(obj.libname, 'iio_channel_attr_read_double', ch, attr, pData);
|
||
|
clear ch;
|
||
|
clear attr;
|
||
|
else
|
||
|
calllib(obj.libname, 'iio_device_attr_read_double', obj.iio_dev, attr_name, pData);
|
||
|
end
|
||
|
val = pData.Value;
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Read an attribute as a string value
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function [ret, val] = readAttributeString(obj, attr_name)
|
||
|
% Find the attribute
|
||
|
[ret, ch, attr] = findAttribute(obj, attr_name);
|
||
|
if(ret < 0)
|
||
|
val = '';
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Create a pointer to be used for data read
|
||
|
data = char(ones(1, 512));
|
||
|
pData = libpointer('stringPtr', data);
|
||
|
|
||
|
% Read the attribute value
|
||
|
if(ret > 0)
|
||
|
[~, ~, ~, val] = calllib(obj.libname, 'iio_channel_attr_read', ch, attr, pData, 512);
|
||
|
clear ch;
|
||
|
clear attr;
|
||
|
else
|
||
|
[~, ~, ~, val] = calllib(obj.libname, 'iio_device_attr_read', obj.iio_dev, attr_name, pData, 512);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Write a string double value
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function ret = writeAttributeDouble(obj, attr_name, val)
|
||
|
% Find the attribute
|
||
|
[ret, ch, attr] = findAttribute(obj, attr_name);
|
||
|
if(ret < 0)
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Write the attribute
|
||
|
if(ret > 0)
|
||
|
calllib(obj.libname, 'iio_channel_attr_write_double', ch, attr, val);
|
||
|
clear ch;
|
||
|
clear attr;
|
||
|
else
|
||
|
calllib(obj.libname, 'iio_device_attr_write_double', obj.iio_dev, attr_name, val);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
%% Write a string attribute value
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
function ret = writeAttributeString(obj, attr_name, str)
|
||
|
% Find the attribute
|
||
|
[ret, ch, attr] = findAttribute(obj, attr_name);
|
||
|
if(ret < 0)
|
||
|
return;
|
||
|
end
|
||
|
|
||
|
% Write the attribute
|
||
|
if(ret > 0)
|
||
|
calllib(obj.libname, 'iio_channel_attr_write', ch, attr, str);
|
||
|
clear ch;
|
||
|
clear attr;
|
||
|
else
|
||
|
calllib(obj.libname, 'iio_device_attr_write', obj.iio_dev, attr_name, str);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|