blob: 1f8380f4e02d891c05adc71b5077fb060ea16b22 [file] [log] [blame]
% 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