function [str, status] = MemMapVariableCheck(modelName)
%% Check for MemMap parameters
str =sprintf('Checking MemMap custom storage class parameters for model ''%s.''',modelName);
disp(str)
status =1;
standardtypes = {'auto'; 'double'; 'single'; 'int32'; 'uint32'; 'int16'; 'uint16'; 'int8'; 'uint8'};
% Add code to check the memory map for the MemMap data objects to insure
% that none of the data objects memory specifications overlap.
%% Find all of the parameters of type MemMap in the model.
% refWSVars is a structure containing the names of the referenced
% variables along with the handles to the blocks that reference the
% variable
%% Get all the referenced WS variables that are MemMap parameters
refWSVars = get_param(modelName, 'ReferencedWSVars');
refVarNames = cell(size(refWSVars));
match=cell(1);
numcount = 0;
for i=1:length(refWSVars)
refVarNames{i} = refWSVars(i).Name;
obj = evalin('base',refWSVars(i).Name);
if isa(obj,'Simulink.Data')
if (strcmp(obj.RTWInfo.CustomStorageClass,'MemoryAddress') ...
&& strcmp(obj.RTWInfo.StorageClass,'Custom'))
numcount = numcount + 1;
match{numcount}=refWSVars(i).Name;
end
end
end
% Truncate the list to those that match
%% Get the list of MemoryAddress variables in the base workspace
if(~isempty(match{1})) % If any exists, check the addresses, etc.
% Step through the list and create a memory map then check for uniqueness
addresses = cell(1);
hexaddresses = cell(1);
nummatch = length(match);
stepsize = zeros(1,nummatch);
hexstep = cell(1);
matchprint = cell(1);
datatype = cell(1);
numelements = zeros(1,nummatch);
baseaddress = zeros(1,nummatch);
maxvar = 10;
maxtype = 4;
% % % startrange = [];
% % % endrange = [];
numcols = zeros(1,nummatch);
for ii = 1:nummatch
dim = evalin('base',[match{ii},'.dimensions']);
numcols(ii) = dim(2);
numelements(ii) = dim(1) * dim(2);
if(numelements(ii) > 1)
matchprint{ii} = [match{ii}, '(', num2str(dim(1)),',', num2str(dim(2)),')'];
else
matchprint{ii} = match{ii};
end
maxvar = max(maxvar,length(matchprint{ii}));
%Account for user-defined data types: AliasType,Numerictype, fixdt
% Determine the data type
datatype{ii} = evalin('base',[match{ii},'.DataType']);
maxtype = max(maxtype,length(datatype{ii}));
% Check for non-standard data types
if isempty(strmatch(datatype{ii},standardtypes))
% Get the nonstandard data type
if (strncmpi(datatype{ii},'fixdt',5))
% Strip out the word length
[Signed, remainder] = strtok(datatype{ii},',');
WordLength = strtok(remainder,',');
switchtype = 'Fixed';
else
vartype = evalin('base',['class(',datatype{ii},')']);
if strcmpi(vartype,'Simulink.NumericType')
switchtype = evalin('base',[datatype{ii},'.DataTypeMode']);
% Check if the numeric type is non-standard data type
if isempty(strmatch(switchtype,standardtypes))
WordLength = evalin('base',[datatype{ii},'.WordLength']);
switchtype = 'Fixed';
end
end
if strcmpi(vartype,'Simulink.AliasType')
tmptype = evalin('base',[datatype{ii},'.BaseType']);
if isempty(strmatch(tmptype,standardtypes))
vartype = evalin('base',['class(',tmptype,')']);
if strcmpi(vartype,'Simulink.NumericType')
switchtype = evalin('base',[tmptype,'.DataTypeMode']);
% Check if the numeric type is non-standard data type
if isempty(strmatch(switchtype,standardtypes))
WordLength = evalin('base',[tmptype,'.WordLength']);
switchtype = 'Fixed';
end
end
end
else
switchtype = tmptype;
end
end
else
switchtype = datatype{ii};
end
switch switchtype
case 'Fixed'
stepsize(ii) = WordLength; % Fixed-point data type
case 'single'
stepsize(ii) = 32; % 4 bytes (32 bits) for a single
case {'int32', 'uint32'}
stepsize(ii) = 32; % 4 bytes (32 bits) for a int32
case {'int16', 'uint16'}
stepsize(ii) = 16; % 2 bytes (16 bits) for a int16
case {'int8', 'uint8'}
stepsize(ii) = 8; % 1 bytes (8 bits) for a int8
case 'boolean'
stepsize(ii) = 8; % 1 bytes (8 bits) for a boolean
case {'double', 'auto'}
stepsize(ii) = 64; % 8 bytes (64 bits) for a double/auto
otherwise
error(['Non supported data type: ', datatype{ii}]);
end
address = evalin('base',[match{ii},'.RTWInfo.CustomAttributes.MemoryAddress']);
baseaddress(ii) = hex2dec(address(2:end));
for jj = 1:numelements(ii)
addresses{ii,jj} = (baseaddress(ii) + (jj-1)*stepsize(ii));
hexaddresses{ii,jj} = ['0x',dec2hex(addresses{ii,jj}, 8)];
end
end
%% Sort based on memory location
[newlist, indx] = sort(baseaddress);
%reorder other items
nmatch = cell(1);
nmatchprint = cell(1);
ndatatype = cell(1);
naddresses = cell(1);
nhexaddresses = cell(1);
stepsize = stepsize(indx);
for ii = 1:nummatch
nmatch{ii} = match{indx(ii)};
nmatchprint{ii} = matchprint{indx(ii)};
ndatatype{ii} = datatype{indx(ii)};
for jj = 1:max(numelements)
naddresses{ii,jj} = addresses{indx(ii),jj};
nhexaddresses{ii,jj} = hexaddresses{indx(ii),jj};
end
hexstep{ii} = [num2str(stepsize(ii)), '(0x', dec2hex(stepsize(ii),2),')'];
end
match = nmatch;
matchprint = nmatchprint;
datatype = ndatatype;
addresses = naddresses;
hexaddresses = nhexaddresses;
numelements = numelements(indx);
numcols = numcols(indx);
%% Check the addresses for overlap
overlapflag = 0;
[nrows,ncols] = size(addresses);
% Find next valid addresses
check = zeros(1,nrows);
check(1) = addresses{1,1};
checkhex = cell(1);
checkhex{1} = hexaddresses{1};
for ii = 1:nrows
for jj = 1:ncols % Find the next valid address
if (~isempty(addresses{ii,jj}))
check(ii+1) = addresses{ii,jj} + stepsize(ii);
checkhex{ii+1} = ['0x',dec2hex(check(ii+1), 8)];
end
end
end
for ii = 2:nrows
if(addresses{ii,1} < check(ii))
overlapflag = 1;
break; % Exit for loop if there is an overlap
end
end
%% Display memory map
button = questdlg(sprintf('Model contains Custom Storage Class MemMap parameters\nShow memory map?'));
% Format the memory table
if (strcmpi(button,'yes'))
hdrst1 ='Variable ';
hdrst2 =' ';
hdrst3 =' ';
for ss = length(hdrst1):maxvar % pad with trailing spaces as needed
hdrst1 = [hdrst1, ' '];
hdrst2 = [hdrst2, ' '];
hdrst3 = [hdrst3, ' '];
end
hdrst1 = [hdrst1, ' Data '];
hdrst2 = [hdrst2, ' Type '];
hdrst3 = [hdrst3, ' '];
for ss = length(hdrst1):maxtype % pad with trailing spaces as needed
hdrst1 = [hdrst1, ' '];
hdrst2 = [hdrst2, ' '];
hdrst3 = [hdrst3, ' '];
end
hdrst1 = [hdrst1, ' Word '];
hdrst2 = [hdrst2, ' Length '];
hdrst3 = [hdrst3, ' '];
hdrst1 = [hdrst1, 'Available '];
hdrst2 = [hdrst2, 'Starting '];
hdrst3 = [hdrst3, 'Address '];
hdrst1 = [hdrst1, ' Assigned '];
hdrst2 = [hdrst2, ' Addresses'];
addressindx = strfind(hdrst1,'Assigned');
disp(' ');
disp(' ');
disp('***** Custom Storage Class MemMap Parameters: Memory Map *****');
disp(' ');
disp(hdrst1);
disp(hdrst2);
disp(hdrst3);
for kk = 1:nrows
bstr = 'sprintf(''%s';
for ss = length(matchprint{kk}):maxvar % pad with trailing spaces as needed
bstr = [bstr, ' '];
end
bstr = [bstr, ' %s'];
for ss = length(datatype{kk}):maxtype % pad with trailing spaces as needed
bstr = [bstr, ' '];
end
bstr = [bstr, ' %8s %s '];
numacross = min(numcols(kk),10);
for ll = 1:numelements(kk)
if (mod(ll,numacross)==0 && ll ~= numelements(kk))
if(numacross ~= numcols(kk))
bstr = [bstr '%s %% Columns wrapped\n'];
else
bstr = [bstr '%s\n'];
end
for ss = 1:addressindx-1
bstr = [bstr, ' '];
end
else
bstr = [bstr '%s '];
end
end
bstr = [bstr ''''];
bstr = [bstr ',matchprint{kk}, datatype{kk}, hexstep{kk}, checkhex{kk}, hexaddresses{kk,1:numelements(kk)})'];
disp(eval(bstr));
end
disp(' ');
disp(' ');
disp(' ');
end
%% Send an errorand stop build process
if(overlapflag)
error('Memory address overlap in MemMap parameters between parameter:\n%s and %s \nCheck memory map',match{ii-1}, match{ii});
end
end
end % end of MemMapVariableCheck function
%% Notes