% 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)) cfg_ch_no = length(config.cfg_ch); end if(data_ch_no + cfg_ch_no ~= 0) varargout = cell(1, data_ch_no + cfg_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 + cfg_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