www.gusucode.com > ecoder 案例源码程序 matlab代码 > ecoder/importICD.m
% This script creates data objects and data type objects in the base % workspace. It configures the code generation settings (properties) of the % objects based on the specifications in an ICD. % % To import the specifications from the ICD, you can use the 'xlsread' or % 'readtable' functions. When you use 'readtable', MATLAB stores the % imported data in a table, which can result in cleaner and more readable % MATLAB code. %% Configure Object Properties by Using Imported Data % Some of the column names in the ICD, such as 'DataType' in the 'Signals' % worksheet, match the names of properties of data objects and data type % objects in MATLAB. Some of the cell values in the ICD workbook are % compatible with the property values in MATLAB, for example the value of % the 'DataType' column for the signal 'sensors', which is 'Bus: % EngSensors'. After you import these compatible cell values from the ICD, % you can assign the values directly to the object properties. % % Suppose you store the name of a property as a character vector in the % variable 'propName' and you store the property value in the variable % 'propValue'. Use this command to set the property value: % myDataObject.(propName) = propValue; % You can iteratively % (for example, with a 'for' loop) assign property values to data objects. % % Other column names in the ICD do not directly match property names, for % example 'HeaderFile' in the 'Signals' worksheet (to assign 'HeaderFile' % to a data object, you must use the nested property % 'myDataObject.CoderInfo.CustomAttributes.HeaderFile'). Some cell values % in the ICD are not compatible with property values in MATLAB, for example % the 'Sheet' formula in the 'Parameters' worksheet. For these property % names and cell values, use 'if' and 'switch case' statements in MATLAB to % conditionally set the property values. % % To execute a command or function on each of multiple objects or variables % whose names you store in a cell array of character vectors, use the % function 'eval' in a 'for' loop. For example, if you store the names % of several variables in the cell array of character vectors % 'objectNames', use this command in a 'for' loop with index 'i': % eval([objectNames{i} '.(propName) = propValue;']) %% Designate Name of External File xlsFileName = 'ICD.xls'; %% Import Numeric Types % In this part of the script, use the function 'readtable' to import the raw information % from the ICD. The imported information appears in a table. Each column of % the ICD, such as 'WordLength', appears as a variable in the table. % % The value of each variable in the table is a numeric array or a cell % array of character vectors, depending on the values contained in the % corresponding column of the ICD. To access the numeric data, use % parentheses, (). To access the character vectors in the cells, use % brackets, {}. numTypesRaw = readtable(xlsFileName,'Sheet','Numeric Types'); objectNames = numTypesRaw.Name; % "Name" is a variable in the table "numTypesRaw". % Create a list of the variables (columns) in the table. tableVariables = numTypesRaw.Properties.VariableNames; % Loop through the rows (objects) in the imported data. for row = 1:length(objectNames) objectName = objectNames{row}; % If the object does not exist, create it. Use Simulink.NumericType % objects to represent most data types. if ~exist(objectName) eval([objectName ' = Simulink.NumericType;']) end % Loop through the columns (properties) in the imported data. for col = 1:length(tableVariables) propName = tableVariables{col}; % Store the property value in the variable 'propValue'. Depending % on whether 'readtable' stored the information as a numeric array % or cell array, use parentheses or brackets to access the value. if iscell(numTypesRaw.(propName)) propValue = numTypesRaw.(propName){row}; else propValue = numTypesRaw.(propName)(row); end % Assign the value to the property in the object. if eval(['isprop(' objectName ',''' propName ''')']) && ~strcmp(propValue,'N/A') eval([objectName '.(propName) = propValue;']) end end % These 'if' statements handle special cases where the column name or % cell value from the ICD is not directly compatible with an object % property in MATLAB. if ~strcmp(numTypesRaw.Sign{row},'N/A') if strcmp(numTypesRaw.Sign{row},'yes') eval([objectName '.Signedness = ''Signed'';']) else eval([objectName '.Signedness = ''Unsigned'';']) end end if ~strcmp(numTypesRaw.HeaderFile{row},'N/A') eval([objectName '.HeaderFile = numTypesRaw.HeaderFile{row};']) end end %% Import Structure Types % This part of the script uses the function 'xlsread' to import the % information. The imported information, including the column names, % appears in a cell matrix of character vectors. To access the information % in the cells, use brackets, {}. [~, ~, structTypesRaw] = xlsread(xlsFileName,'Structure Types',''); objectNames = structTypesRaw(2:end,1); propNames = structTypesRaw(1,2:end)'; typeHeaderFiles = {}; % Shave off the first column and the first row, which no longer contain % useful information. structTypesRaw = structTypesRaw(2:end,2:end); for row = 1:length(objectNames) objectName = objectNames{row}; % If data type is 'struct', create a Simulink.Bus object. % Use Simulink.Bus objects to represent structure types in Simulink. DTValue = structTypesRaw{row,strcmp(propNames,'DataType')}; if strcmp(DTValue,'struct') if ~exist(objectName) eval([objectName ' = Simulink.Bus;']) end % Get a list of the elements (Simulink.BusElement objects) in the % bus object. Each element corresponds to a field of the structure % type that the bus object represents. busName = objectName; eval(['elementNames = {' busName '.Elements.Name};']) for col = 1:length(propNames) propName = propNames{col}; propValue = structTypesRaw{row,col}; if eval(['isprop(' objectName ',''' propName ''')']) && ... ~strcmp(propName,'DataType') && ~strcmp(propValue,'N/A') eval([objectName '.(propName) = propValue;']) end end % If the structure type is imported, begin collecting the names of % header files that define imported data types. if eval(['strcmp(' busName '.DataScope,''Imported'')']) eval(['headerFile = ' busName '.HeaderFile;']); if isempty(typeHeaderFiles) typeHeaderFiles = {headerFile}; else typeHeaderFiles = [typeHeaderFiles {headerFile}]; end end % If data type is not 'struct', create an element % (Simulink.BusElement object) for the latest bus object. If the % bus object already has the element, replace the element. else % Determine whether the latest bus object has the element. elementIndex = eval(['strcmp(elementNames,''' objectName ''')']); if isempty(elementIndex) || ~any(elementIndex) eval([objectName ' = Simulink.BusElement;']) else % If the latest bus object has the element, to preserve the % property values of this existing element, copy the element % into a separate variable in the base workspace. eval([objectName ' = ' busName '.Elements(elementIndex);']) end eval([objectName '.Name = objectName;']) for col = 1:length(propNames) propName = propNames{col}; propValue = structTypesRaw{row,col}; if eval(['isprop(' objectName ',''' propName ''')']) && ~strcmp(propValue,'N/A') eval([objectName '.(propName) = propValue;']) end end % Add the Simulink.BusElement object as an element to the latest % bus object. if any(elementIndex) eval([busName '.Elements(elementIndex) = ' objectName ';']) else eval([busName '.Elements = [' busName '.Elements; ' objectName '];']) end eval(['clear ' objectName]) end end %% Import Enumerated Types % This part of the scripts creates enumerated type definitions by using the function % 'Simulink.defineIntEnumType'. enumTypesRaw = readtable(xlsFileName,'Sheet','Enumerated Types'); objectNames = enumTypesRaw.Name; for row = 1:length(objectNames) % If the value in the StorageType column is not 'member', begin a new % enumerated type definition. if ~strcmp(enumTypesRaw.StorageType{row},'member') enumName = objectNames{row}; % The value in the StorageType column can be a specific integer % data type, such as 'int8', or it can be generic 'int'. if strcmp(enumTypesRaw.StorageType{row},'int') storageTypeChar = ''; else storageTypeChar = [',''StorageType'',''' enumTypesRaw.StorageType{row} '''']; end if strcmp(enumTypesRaw.DataScope{row},'Exported') dataScopeChar = ',''DataScope'',''Exported'''; else dataScopeChar = ',''DataScope'',''Imported'''; % If the enumerated type is imported, add the name of the % header file to the list of custom header files that define % imported types. if isempty(typeHeaderFiles) typeHeaderFiles = {enumTypesRaw.HeaderFile{row}}; else typeHeaderFiles = [typeHeaderFiles {enumTypesRaw.HeaderFile{row}}]; end end if strcmp(enumTypesRaw.HeaderFile{row},'N/A') headerFileChar = ''; else headerFileChar = [',''HeaderFile'',''' enumTypesRaw.HeaderFile{row} '''']; end enumMembers = {}; enumIntValues = []; subRow = row+1; % Begin collecting enumeration members from the ICD. Stop % collecting enumeration members when the row represents a % different enumerated type. while subRow <= length(enumTypesRaw.Name) && strcmp(enumTypesRaw.StorageType{subRow},'member') if isempty(enumMembers) enumMembers = {enumTypesRaw.Name{subRow}}; else enumMembers = [enumMembers enumTypesRaw.Name{subRow}]; end if isempty(enumIntValues) enumIntValues = str2double(enumTypesRaw.UnderlyingInt{subRow}); else enumIntValues = [enumIntValues str2double(enumTypesRaw.UnderlyingInt{subRow})]; end subRow = subRow+1; end % Use the function 'Simulink.defineIntEnumType' to define the % enumerated type for use during this MATLAB session. % % If the enumerated type already exists, so that the script cannot % redefine it, explain that the user must close models and clear % variables. try eval(['Simulink.defineIntEnumType(enumName,enumMembers,enumIntValues' storageTypeChar dataScopeChar headerFileChar ')']) catch eval(['sprintf(''Cannot redefine enumerated type ' enumName ' because open models and existing variables use the type. Close the models and clear the variables.'')']) end end end %% Import Signals [~, ~, sigsRaw] = xlsread(xlsFileName,'Signals',''); objectNames = sigsRaw(2:end,1); propNames = sigsRaw(1,2:end)'; sigsRaw = sigsRaw(2:end,2:end); for row = 1:length(objectNames) objectName = objectNames{row}; if ~exist(objectName) eval([objectName ' = Simulink.Signal;']) end % Prepare to use custom storage classes. eval([objectName '.CoderInfo.StorageClass = ''Custom'';']) for col = 1:length(propNames) propName = propNames{col}; propValue = sigsRaw{row,col}; % This switch statement handles special cases. switch propName case 'Owner' % Each Simulink.Signal object can use a custom storage % class, which controls the representation of the data item % in the generated code. For data items that % sldemo_fuelsys_dd_controller owns, use the custom storage % class ExportToFile. For data items that the component % does not own, use ImportFromFile. if strcmp(propValue,'sldemo_fuelsys_dd_controller') eval([objectName '.CoderInfo.CustomStorageClass = ''ExportToFile'';']) eval([objectName '.CoderInfo.CustomAttributes.Owner = propValue;']) else eval([objectName '.CoderInfo.CustomStorageClass = ''ImportFromFile'';']) end case 'HeaderFile' if ~strcmp(propValue','N/A') eval([objectName '.CoderInfo.CustomAttributes.HeaderFile = propValue;']) end case 'DefinitionFile' if ~strcmp(propValue,'N/A') if eval(['strcmp(' objectName '.CoderInfo.CustomStorageClass,''ExportToFile'')']) eval([objectName '.CoderInfo.CustomAttributes.DefinitionFile = propValue;']) elseif eval(['strcmp(' objectName '.CoderInfo.CustomStorageClass,''ImportFromFile'')']) % Start a list of custom source files that define % (allocate memory for) data items. Later, you can % identify these source files for inclusion in the % build process. if ~exist('customSourceFiles') customSourceFiles = {propValue}; else customSourceFiles = [customSourceFiles propValue]; end end end end if eval(['isprop(' objectName ',''' propName ''')']) && ~strcmp(propValue,'N/A') eval([objectName '.(propName) = propValue;']) end end end %% Import Parameters [~, ~, paramsRaw] = xlsread(xlsFileName,'Parameters',''); objectNames = paramsRaw(2:end,1); propNames = paramsRaw(1,2:end)'; paramsRaw = paramsRaw(2:end,2:end); for row = 1:length(objectNames) objectName = objectNames{row}; if ~exist(objectName) eval([objectName '= Simulink.Parameter;']) end eval([objectName '.CoderInfo.StorageClass = ''Custom'';']) for col = 1:length(propNames) propName = propNames{col}; propValue = paramsRaw{row,col}; switch propName case 'Owner' if strcmp(propValue,'sldemo_fuelsys_dd_controller') eval([objectName '.CoderInfo.CustomStorageClass = ''ExportToFile'';']) eval([objectName '.CoderInfo.CustomAttributes.Owner = propValue;']) else eval([objectName '.CoderInfo.CustomStorageClass = ''ImportFromFile'';']) end case 'HeaderFile' if ~strcmp(propValue','N/A') eval([objectName '.CoderInfo.CustomAttributes.HeaderFile = propValue;']) end case 'DefinitionFile' if ~strcmp(propValue,'N/A') if eval(['strcmp(' objectName '.CoderInfo.CustomStorageClass,''ExportToFile'')']) eval([objectName '.CoderInfo.CustomAttributes.DefinitionFile = propValue;']) elseif eval(['strcmp(' objectName '.CoderInfo.CustomStorageClass,''ImportFromFile'')']) if ~exist('customSourceFiles') customSourceFiles = {propValue}; else customSourceFiles = [customSourceFiles propValue]; end end end case 'Value' % When the parameter value is stored in a different % worksheet in the ICD, use 'xlsread' again to import that % value. if strcmp(propValue,'Sheet') eval([objectName '.Value = xlsread(xlsFileName,objectName,'''');']) end end if eval(['isprop(' objectName ',''' propName ''')']) && ... ~strcmp(propValue,'N/A') && ~strcmp(propValue,'Sheet') eval([objectName '.(propName) = propValue;']) end end end %% Set Up Custom Header Files % If you import custom data types, to enable the Stateflow chart in the % model to use the types, add #include statements in the Simulation Target % header file of the model. if ~isempty(typeHeaderFiles) typeHeaderFiles = unique(typeHeaderFiles); headerFileChar = ''; for i = 1:length(typeHeaderFiles) headerFileChar = sprintf([headerFileChar '\n#include "' typeHeaderFiles{i} '"']); end set_param('sldemo_fuelsys_dd_controller',... 'SimCustomHeaderCode',headerFileChar) end %% Set Up Custom Source Files % Use the model configuration parameters to identify the custom source % files that define imported data. When the model compiles the generated % code, the identified source files are included in the compilation. if exist('customSourceFiles') customSourceFiles = unique(customSourceFiles); customSourceFilesList = customSourceFiles{1}; for i = 2:length(customSourceFiles) customSourceFilesList = [customSourceFilesList ',' customSourceFiles{i}]; end set_param('sldemo_fuelsys_dd_controller','CustomSource',customSourceFilesList) end