diff options
Diffstat (limited to 'bindings/matlab')
-rw-r--r-- | bindings/matlab/CMakeLists.txt | 26 | ||||
-rw-r--r-- | bindings/matlab/iio-wrapper.h | 46 | ||||
-rw-r--r-- | bindings/matlab/iio_installer_script.m | 17 | ||||
-rw-r--r-- | bindings/matlab/iio_sys_obj.m | 474 | ||||
-rw-r--r-- | bindings/matlab/iio_sys_obj_matlab.m | 350 | ||||
-rw-r--r-- | bindings/matlab/libiio_if.m | 701 | ||||
-rw-r--r-- | bindings/matlab/libiio_if_daq2.m | 701 |
7 files changed, 2315 insertions, 0 deletions
diff --git a/bindings/matlab/CMakeLists.txt b/bindings/matlab/CMakeLists.txt new file mode 100644 index 0000000..4eea7d5 --- /dev/null +++ b/bindings/matlab/CMakeLists.txt @@ -0,0 +1,26 @@ +find_program( + MATLAB_EXECUTABLE + NAMES matlab + DOC "Matlab main program" +) +mark_as_advanced(MATLAB_EXECUTABLE) + +option(WITH_MATLAB_BINDINGS_API "Enable MATLAB bindings API" ON) + +if (MATLAB_EXECUTABLE AND NOT SKIP_INSTALL_ALL) + option(MATLAB_BINDINGS "Install MATLAB bindings" ON) + + if (MATLAB_BINDINGS) + install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/libiio" + PATTERN "CMakeLists.txt" EXCLUDE + ) + install( + CODE "execute_process( + COMMAND ${MATLAB_EXECUTABLE} -nodesktop + -nodisplay -r \"cd('${CMAKE_INSTALL_PREFIX}/share/libiio/matlab');iio_installer_script;exit;\" + OUTPUT_QUIET)") + set(WITH_MATLAB_BINDINGS_API ON CACHE BOOL "" FORCE) + endif() +endif() diff --git a/bindings/matlab/iio-wrapper.h b/bindings/matlab/iio-wrapper.h new file mode 100644 index 0000000..ce2b046 --- /dev/null +++ b/bindings/matlab/iio-wrapper.h @@ -0,0 +1,46 @@ +#ifndef MATLAB_LOADLIBRARY +#define MATLAB_LOADLIBRARY +#include <iio.h> + +#ifndef __api +#define __api +#endif + +struct iio_scan_block; + +/** @brief Create a scan block +* @param backend A NULL-terminated string containing the backend to use for +* scanning. If NULL, all the available backends are used. +* @param flags Unused for now. Set to 0. +* @return on success, a pointer to a iio_scan_block structure +* @return On failure, NULL is returned and errno is set appropriately */ +__api struct iio_scan_block * iio_create_scan_block( + const char *backend, unsigned int flags); + + +/** @brief Destroy the given scan block +* @param ctx A pointer to an iio_scan_block structure +* +* <b>NOTE:</b> After that function, the iio_scan_block pointer shall be invalid. */ +__api void iio_scan_block_destroy(struct iio_scan_block *blk); + + +/** @brief Enumerate available contexts via scan block +* @param blk A pointer to a iio_scan_block structure. +* @returns On success, the number of contexts found. +* @returns On failure, a negative error number. +*/ +__api ssize_t iio_scan_block_scan(struct iio_scan_block *blk); + + +/** @brief Get the iio_context_info for a particular context +* @param blk A pointer to an iio_scan_block structure +* @param index The index corresponding to the context. +* @return A pointer to the iio_context_info for the context +* @returns On success, a pointer to the specified iio_context_info +* @returns On failure, NULL is returned and errno is set appropriately +*/ +__api struct iio_context_info *iio_scan_block_get_info( + struct iio_scan_block *blk, unsigned int index); + +#endif diff --git a/bindings/matlab/iio_installer_script.m b/bindings/matlab/iio_installer_script.m new file mode 100644 index 0000000..1276729 --- /dev/null +++ b/bindings/matlab/iio_installer_script.m @@ -0,0 +1,17 @@ +function installer_script(varargin) + if nargin > 0 + install = varargin{1}; % use the command line arguement + else + install = true; % assume install + end + thisDir = fileparts(mfilename('fullpath')); % path to this script + + if install + pathfunc = @addpath; % add paths for installation + else + pathfunc = @rmpath; % remove paths for uninstall + end + + pathfunc(thisDir); + savepath; +end diff --git a/bindings/matlab/iio_sys_obj.m b/bindings/matlab/iio_sys_obj.m new file mode 100644 index 0000000..1f8380f --- /dev/null +++ b/bindings/matlab/iio_sys_obj.m @@ -0,0 +1,474 @@ +% Copyright 2014-15(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 iio_sys_obj < matlab.System & matlab.system.mixin.Propagates ... + & matlab.system.mixin.CustomIcon + % iio_sys_obj System Object block for IIO devices + + properties (Nontunable) + % Public, non-tunable properties. + + %ip_address IP address + ip_address = ''; + + %dev_name Device name + dev_name = ''; + + %in_ch_no Number of input data channels + in_ch_no = 0; + + %in_ch_size Input data channel size [samples] + in_ch_size = 8192; + + %out_ch_no Number of output data channels + out_ch_no = 0; + + %out_ch_size Output data channel size [samples] + out_ch_size = 8192; + end + + properties (Access = protected) + % Protected class properties. + + %iio_dev_cfg Device configuration structure + iio_dev_cfg = []; + end + + properties (Access = private) + % Private class properties. + + %libiio_data_in_dev libiio IIO interface object for the input data device + libiio_data_in_dev = {}; + + %libiio_data_out_dev libiio IIO interface object for the output data device + libiio_data_out_dev = {}; + + %libiio_ctrl_dev libiio IIO interface object for the control device + libiio_ctrl_dev = {}; + + %sys_obj_initialized Holds the initialization status of the system object + sys_obj_initialized = 0; + end + + properties (DiscreteState) + % Discrete state properties. + + %num_cfg_in Numeric type input control channels data + num_cfg_in; + + %str_cfg_in String type input control channels data + str_cfg_in; + end + + methods + %% Constructor + function obj = iio_sys_obj(varargin) + % Construct the libiio interface objects + obj.libiio_data_in_dev = libiio_if(); + obj.libiio_data_out_dev = libiio_if(); + obj.libiio_ctrl_dev = libiio_if(); + + % Support name-value pair arguments when constructing the object. + setProperties(obj,nargin,varargin{:}); + end + end + + methods (Access = protected) + %% Utility functions + + function config = getObjConfig(obj) + % Read the selected device configuration + + % Open the configuration file + fname = sprintf('%s.cfg', obj.dev_name); + fp_cfg = fopen(fname); + if(fp_cfg < 0) + config = {}; + return; + end + + % Build the object configuration structure + config = struct('data_in_device', '',... % Pointer to the data input device + 'data_out_device', '',... % Pointer to the data output device + 'ctrl_device', '',... % Pointer to the control device + 'cfg_ch', [],... % Configuration channels list + 'mon_ch', []); % Monitoring channels list + + % Build the configuration/monitoring channels structure + ch_cfg = struct('port_name', '',... % Name of the port to be displayed on the object block + 'port_attr', '',... % Associated device attribute name + 'ctrl_dev_name', '',... % Control device name + 'ctrl_dev', 0); % Pointer to the control device object + + % Read the object's configuration + while(~feof(fp_cfg)) + line = fgets(fp_cfg); + if(strfind(line,'#')) + continue; + end + if(~isempty(strfind(line, 'channel'))) + % Get the associated configuration/monitoring channels + idx = strfind(line, '='); + line = line(idx+1:end); + line = strsplit(line, ','); + ch_cfg.port_name = strtrim(line{1}); + ch_cfg.port_attr = strtrim(line{3}); + if(length(line) > 4) + ch_cfg.ctrl_dev_name = strtrim(line{4}); + else + ch_cfg.ctrl_dev_name = 'ctrl_device'; + end + if(strcmp(strtrim(line{2}), 'IN')) + config.cfg_ch = [config.cfg_ch ch_cfg]; + elseif(strcmp(strtrim(line{2}), 'OUT')) + config.mon_ch = [config.mon_ch ch_cfg]; + end + elseif(~isempty(strfind(line, 'data_in_device'))) + % Get the associated data input device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_in_device = tmp; + elseif(~isempty(strfind(line, 'data_out_device'))) + % Get the associated data output device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_out_device = tmp; + elseif(~isempty(strfind(line, 'ctrl_device'))) + % Get the associated control device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.ctrl_device = tmp; + end + end + fclose(fp_cfg); + end + + end + + methods (Access = protected) + %% Common functions + function setupImpl(obj) + % Implement tasks that need to be performed only once. + + % Set the initialization status to fail + obj.sys_obj_initialized = 0; + + % Read the object's configuration from the associated configuration file + obj.iio_dev_cfg = getObjConfig(obj); + if(isempty(obj.iio_dev_cfg)) + msgbox('Could not read device configuration!', 'Error','error'); + return; + end + + % Initialize discrete-state properties. + obj.num_cfg_in = zeros(1, length(obj.iio_dev_cfg.cfg_ch)); + obj.str_cfg_in = zeros(length(obj.iio_dev_cfg.cfg_ch), 64); + + % Initialize the libiio data input device + if(obj.in_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_in_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_in_device, 'OUT', ... + obj.in_ch_no, obj.in_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio data output device + if(obj.out_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_out_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_out_device, 'IN', ... + obj.out_ch_no, obj.out_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio control device + if(~isempty(obj.iio_dev_cfg.ctrl_device)) + [ret, err_msg, msg_log] = init(obj.libiio_ctrl_dev, obj.ip_address, ... + obj.iio_dev_cfg.ctrl_device, '', ... + 0, 0); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Assign the control device for each monitoring channel + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + if(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Assign the control device for each configuration channel + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Set the initialization status to success + obj.sys_obj_initialized = 1; + end + + function releaseImpl(obj) + % Release any resources used by the system object. + obj.iio_dev_cfg = {}; + delete(obj.libiio_data_in_dev); + delete(obj.libiio_data_out_dev); + delete(obj.libiio_ctrl_dev); + end + + function varargout = stepImpl(obj, varargin) + % Implement the system object's processing flow. + varargout = cell(1, obj.out_ch_no + length(obj.iio_dev_cfg.mon_ch)); + if(obj.sys_obj_initialized == 0) + return; + end + + % Implement the device configuration flow + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(~isempty(varargin{i + obj.in_ch_no})) + if(length(varargin{i + obj.in_ch_no}) == 1) + new_data = (varargin{i + obj.in_ch_no} ~= obj.num_cfg_in(i)); + else + new_data = ~strncmp(char(varargin{i + obj.in_ch_no}'), char(obj.str_cfg_in(i,:)), length(varargin{i + obj.in_ch_no})); + end + if(new_data == 1) + if(length(varargin{i + obj.in_ch_no}) == 1) + obj.num_cfg_in(i) = varargin{i + obj.in_ch_no}; + str = num2str(obj.num_cfg_in(i)); + else + for j = 1:length(varargin{i + obj.in_ch_no}) + obj.str_cfg_in(i,j) = varargin{i + obj.in_ch_no}(j); + end + obj.str_cfg_in(i,j+1) = 0; + str = char(obj.str_cfg_in(i,:)); + end + writeAttributeString(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev, obj.iio_dev_cfg.cfg_ch(i).port_attr, str); + end + end + end + + % Implement the data transmit flow + writeData(obj.libiio_data_in_dev, varargin); + + % Implement the data capture flow + [~, data] = readData(obj.libiio_data_out_dev); + for i = 1 : obj.out_ch_no + varargout{i} = data{i}; + end + + % Implement the parameters monitoring flow + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + [~, val] = readAttributeDouble(obj.iio_dev_cfg.mon_ch(i).ctrl_dev, obj.iio_dev_cfg.mon_ch(i).port_attr); + varargout{obj.out_ch_no + i} = val; + end + + + end + + function resetImpl(obj) + % Initialize discrete-state properties. + obj.num_cfg_in = zeros(1, length(obj.iio_dev_cfg.cfg_ch)); + obj.str_cfg_in = zeros(length(obj.iio_dev_cfg.cfg_ch), 64); + end + + function num = getNumInputsImpl(obj) + % Get number of inputs. + num = obj.in_ch_no; + + config = getObjConfig(obj); + if(~isempty(config)) + num = num + length(config.cfg_ch); + end + end + + function varargout = getInputNamesImpl(obj) + % Get input names + + % Get the number of input data channels + data_ch_no = obj.in_ch_no; + + % Get number of control channels + cfg_ch_no = 0; + config = getObjConfig(obj); + if(~isempty(config)) + cgf_ch_no = length(config.cfg_ch); + end + + if(data_ch_no + cgf_ch_no ~= 0) + varargout = cell(1, data_ch_no + cgf_ch_no); + for i = 1 : data_ch_no + varargout{i} = sprintf('DATA_IN%d', i); + end + for i = data_ch_no + 1 : data_ch_no + cgf_ch_no + varargout{i} = config.cfg_ch(i - data_ch_no).port_name; + end + else + varargout = {}; + end + end + + function num = getNumOutputsImpl(obj) + % Get number of outputs. + num = obj.out_ch_no; + + config = getObjConfig(obj); + if(~isempty(config)) + num = num + length(config.mon_ch); + end + end + + function varargout = getOutputNamesImpl(obj) + % Get output names + + % Get the number of output data channels + data_ch_no = obj.out_ch_no; + + % Get number of monitoring channels + mon_ch_no = 0; + config = getObjConfig(obj); + if(~isempty(config)) + mon_ch_no = length(config.mon_ch); + end + + if(data_ch_no + mon_ch_no ~= 0) + varargout = cell(1, data_ch_no + mon_ch_no); + for i = 1 : data_ch_no + varargout{i} = sprintf('DATA_OUT%d', i); + end + for i = data_ch_no + 1 : data_ch_no + mon_ch_no + varargout{i} = config.mon_ch(i - data_ch_no).port_name; + end + else + varargout = {}; + end + end + + function varargout = isOutputFixedSizeImpl(obj) + % Get outputs fixed size. + varargout = cell(1, getNumOutputs(obj)); + for i = 1 : getNumOutputs(obj) + varargout{i} = true; + end + end + + function varargout = getOutputDataTypeImpl(obj) + % Get outputs data types. + varargout = cell(1, getNumOutputs(obj)); + for i = 1 : getNumOutputs(obj) + varargout{i} = 'double'; + end + end + + function varargout = isOutputComplexImpl(obj) + % Get outputs data types. + varargout = cell(1, getNumOutputs(obj)); + for i = 1 : getNumOutputs(obj) + varargout{i} = false; + end + end + + function varargout = getOutputSizeImpl(obj) + % Implement if input size does not match with output size. + varargout = cell(1, getNumOutputs(obj)); + for i = 1:obj.out_ch_no + varargout{i} = [obj.out_ch_size 1]; + end + for i = obj.out_ch_no + 1 : length(varargout) + varargout{i} = [1 1]; + end + end + + function icon = getIconImpl(obj) + % Define a string as the icon for the System block in Simulink. + if(~isempty(obj.dev_name)) + icon = obj.dev_name; + else + icon = mfilename('class'); + end + end + + %% Backup/restore functions + function s = saveObjectImpl(obj) + % Save private, protected, or state properties in a + % structure s. This is necessary to support Simulink + % features, such as SimState. + end + + function loadObjectImpl(obj, s, wasLocked) + % Read private, protected, or state properties from + % the structure s and assign it to the object obj. + end + + %% Simulink functions + function z = getDiscreteStateImpl(obj) + % Return structure of states with field names as + % DiscreteState properties. + z = struct([]); + end + end + + methods(Static, Access = protected) + %% Simulink customization functions + function header = getHeaderImpl(obj) + % Define header for the System block dialog box. + header = matlab.system.display.Header(mfilename('class')); + end + + function group = getPropertyGroupsImpl(obj) + % Define section for properties in System block dialog box. + group = matlab.system.display.Section(mfilename('class')); + end + end +end diff --git a/bindings/matlab/iio_sys_obj_matlab.m b/bindings/matlab/iio_sys_obj_matlab.m new file mode 100644 index 0000000..572ec03 --- /dev/null +++ b/bindings/matlab/iio_sys_obj_matlab.m @@ -0,0 +1,350 @@ +% 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 iio_sys_obj_matlab + % iio_sys_obj System Object block for IIO devices + + properties (Access = public) + % Public, non-tunable properties. + + %ip_address IP address + ip_address = ''; + + %dev_name Device name + dev_name = ''; + + %in_ch_no Number of input data channels + in_ch_no = 0; + + %in_ch_size Input data channel size [samples] + in_ch_size = 8192; + + %out_ch_no Number of output data channels + out_ch_no = 0; + + %out_ch_size Output data channel size [samples] + out_ch_size = 8192; + end + + properties (Access = public) + % Protected class properties. + + %iio_dev_cfg Device configuration structure + iio_dev_cfg = []; + end + + properties (Access = private) + % Private class properties. + + %libiio_data_in_dev libiio IIO interface object for the input data device + libiio_data_in_dev = {}; + + %libiio_data_out_dev libiio IIO interface object for the output data device + libiio_data_out_dev = {}; + + %libiio_ctrl_dev libiio IIO interface object for the control device + libiio_ctrl_dev = {}; + + %sys_obj_initialized Holds the initialization status of the system object + sys_obj_initialized = 0; + end + + properties (Access = private) + % Discrete state properties. + + %num_cfg_in Numeric type input control channels data + num_cfg_in; + + %str_cfg_in String type input control channels data + str_cfg_in; + end + + methods + %% Constructor + function obj = iio_sys_obj_matlab(varargin) + % Construct the libiio interface objects + obj.libiio_data_in_dev = libiio_if(); + obj.libiio_data_out_dev = libiio_if(); + obj.libiio_ctrl_dev = libiio_if(); + end + end + + methods (Access = protected) + %% Utility functions + + function config = getObjConfig(obj) + % Read the selected device configuration + + % Open the configuration file + fname = sprintf('%s.cfg', obj.dev_name); + fp_cfg = fopen(fname); + if(fp_cfg < 0) + config = {}; + return; + end + + % Build the object configuration structure + config = struct('data_in_device', '',... % Pointer to the data input device + 'data_out_device', '',... % Pointer to the data output device + 'ctrl_device', '',... % Pointer to the control device + 'cfg_ch', [],... % Configuration channels list + 'mon_ch', [],... % Monitoring channels list + 'in_ch_names', [],... % Configuration channels names + 'out_ch_names', []); % Monitoring channels names + config.in_ch_names = {}; + config.out_ch_names = {}; + + % Build the configuration/monitoring channels structure + ch_cfg = struct('port_name', '',... % Name of the port to be displayed on the object block + 'port_attr', '',... % Associated device attribute name + 'ctrl_dev_name', '',... % Control device name + 'ctrl_dev', 0); % Pointer to the control device object + + % Read the object's configuration + while(~feof(fp_cfg)) + line = fgets(fp_cfg); + if(strfind(line,'#')) + continue; + end + if(~isempty(strfind(line, 'channel'))) + % Get the associated configuration/monitoring channels + idx = strfind(line, '='); + line = line(idx+1:end); + line = strsplit(line, ','); + ch_cfg.port_name = strtrim(line{1}); + ch_cfg.port_attr = strtrim(line{3}); + if(length(line) > 4) + ch_cfg.ctrl_dev_name = strtrim(line{4}); + else + ch_cfg.ctrl_dev_name = 'ctrl_device'; + end + if(strcmp(strtrim(line{2}), 'IN')) + config.cfg_ch = [config.cfg_ch ch_cfg]; + config.in_ch_names = [config.in_ch_names ch_cfg.port_name]; + elseif(strcmp(strtrim(line{2}), 'OUT')) + config.mon_ch = [config.mon_ch ch_cfg]; + config.out_ch_names = [config.out_ch_names ch_cfg.port_name]; + end + elseif(~isempty(strfind(line, 'data_in_device'))) + % Get the associated data input device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_in_device = tmp; + elseif(~isempty(strfind(line, 'data_out_device'))) + % Get the associated data output device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_out_device = tmp; + elseif(~isempty(strfind(line, 'ctrl_device'))) + % Get the associated control device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.ctrl_device = tmp; + end + end + fclose(fp_cfg); + end + + end + + methods (Access = public) + %% Helper functions + function ret = getInChannel(obj, channelName) + % Returns the index of a named input channel + ret = obj.in_ch_no + find(strcmp(obj.iio_dev_cfg.in_ch_names, channelName)); + end + + function ret = getOutChannel(obj, channelName) + % Returns the index of a named output channel + ret = obj.out_ch_no + find(strcmp(obj.iio_dev_cfg.out_ch_names, channelName)); + end + + %% Common functions + function ret = setupImpl(obj) + % Implement tasks that need to be performed only once. + + % Set the initialization status to fail + obj.sys_obj_initialized = 0; + + % Read the object's configuration from the associated configuration file + obj.iio_dev_cfg = getObjConfig(obj); + if(isempty(obj.iio_dev_cfg)) + msgbox('Could not read device configuration!', 'Error','error'); + return; + end + + % Initialize discrete-state properties. + obj.num_cfg_in = zeros(1, length(obj.iio_dev_cfg.cfg_ch)); + obj.str_cfg_in = zeros(length(obj.iio_dev_cfg.cfg_ch), 64); + + % Initialize the libiio data input device + if(obj.in_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_in_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_in_device, 'OUT', ... + obj.in_ch_no, obj.in_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio data output device + if(obj.out_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_out_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_out_device, 'IN', ... + obj.out_ch_no, obj.out_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio control device + if(~isempty(obj.iio_dev_cfg.ctrl_device)) + [ret, err_msg, msg_log] = init(obj.libiio_ctrl_dev, obj.ip_address, ... + obj.iio_dev_cfg.ctrl_device, '', ... + 0, 0); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Assign the control device for each monitoring channel + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + if(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Assign the control device for each configuration channel + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Set the initialization status to success + obj.sys_obj_initialized = 1; + ret = obj; + end + + function releaseImpl(obj) + % Release any resources used by the system object. + obj.iio_dev_cfg = {}; + delete(obj.libiio_data_in_dev); + delete(obj.libiio_data_out_dev); + delete(obj.libiio_ctrl_dev); + end + + function ret = stepImpl(obj, varargin) + % Implement the system object's processing flow. + varargout = cell(1, obj.out_ch_no + length(obj.iio_dev_cfg.mon_ch)); + if(obj.sys_obj_initialized == 0) + return; + end + + % Implement the device configuration flow + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(~isempty(varargin{1}{i + obj.in_ch_no})) + if(length(varargin{1}{i + obj.in_ch_no}) == 1) + new_data = (varargin{1}{i + obj.in_ch_no} ~= obj.num_cfg_in(i)); + else + new_data = ~strncmp(char(varargin{1}{i + obj.in_ch_no}'), char(obj.str_cfg_in(i,:)), length(varargin{1}{i + obj.in_ch_no})); + end + if(new_data == 1) + if(length(varargin{1}{i + obj.in_ch_no}) == 1) + obj.num_cfg_in(i) = varargin{1}{i + obj.in_ch_no}; + str = num2str(obj.num_cfg_in(i)); + else + for j = 1:length(varargin{1}{i + obj.in_ch_no}) + obj.str_cfg_in(i,j) = varargin{1}{i + obj.in_ch_no}(j); + end + obj.str_cfg_in(i,j+1) = 0; + str = char(obj.str_cfg_in(i,:)); + end + writeAttributeString(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev, obj.iio_dev_cfg.cfg_ch(i).port_attr, str); + end + end + end + + % Implement the data transmit flow + writeData(obj.libiio_data_in_dev, varargin{1}); + + % Implement the data capture flow + [~, data] = readData(obj.libiio_data_out_dev); + for i = 1 : obj.out_ch_no + varargout{i} = data{i}; + end + + % Implement the parameters monitoring flow + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + [~, val] = readAttributeDouble(obj.iio_dev_cfg.mon_ch(i).ctrl_dev, obj.iio_dev_cfg.mon_ch(i).port_attr); + varargout{obj.out_ch_no + i} = val; + end + + ret=varargout; + end + + function ret = writeFirData(obj, fir_data_file) + fir_data_str = fileread(fir_data_file); + ret = writeAttributeString(obj.libiio_ctrl_dev, 'in_out_voltage_filter_fir_en', '0'); + if ret<0 + return; + end + ret = writeAttributeString(obj.libiio_ctrl_dev, 'filter_fir_config', fir_data_str); + if ret<0 + return; + end + ret = writeAttributeString(obj.libiio_ctrl_dev, 'in_out_voltage_filter_fir_en', '1'); + if ret<0 + return; + end + end + end +end diff --git a/bindings/matlab/libiio_if.m b/bindings/matlab/libiio_if.m new file mode 100644 index 0000000..9fde04d --- /dev/null +++ b/bindings/matlab/libiio_if.m @@ -0,0 +1,701 @@ +% 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 diff --git a/bindings/matlab/libiio_if_daq2.m b/bindings/matlab/libiio_if_daq2.m new file mode 100644 index 0000000..0ac5708 --- /dev/null +++ b/bindings/matlab/libiio_if_daq2.m @@ -0,0 +1,701 @@ +% 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.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); + if(j < ch_no) + 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 + else + calllib(obj.libname, 'iio_channel_disable', obj.iio_channel{j+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 + [notfound, warnings] = loadlibrary(obj.libname, obj.hname); + 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 |