├── imgs ├── Cover.png └── SocialPreview.png ├── doc ├── figs │ ├── Demo.png │ ├── GUI.png │ ├── Demo1a.png │ ├── Demo1b.png │ ├── Demo2.png │ ├── Module.pdf │ ├── Interface.png │ ├── ContextMenu1.png │ ├── ContextMenu2.png │ ├── ContextMenu3.png │ ├── McSCert_Logo.pdf │ ├── GuidelineSelector.png │ └── FunctionVisibilityParam.png ├── SimulinkModule_UserGuide.pdf └── tex │ ├── macros.tex │ └── SimulinkModule_UserGuide.tex ├── src ├── Interface │ ├── Iterator │ │ ├── Iterator.m │ │ └── license.txt │ ├── InterfaceHeader.m │ ├── dependencies.m │ ├── InterfaceIterator.m │ ├── getSampleTime.m │ ├── getDataType_MJ.m │ ├── getDimensions.m │ ├── InterfaceItem.m │ └── Interface.m ├── Guidelines │ ├── guidelineSelector.fig │ ├── guideline0001.m │ ├── guideline0002.m │ ├── guideline0004.m │ ├── guideline0003.m │ └── guidelineSelector.m ├── isSubsystem.m ├── isLibraryLink.m ├── inAtomicSubsystem.m ├── reqSimFcnName.m ├── isGoodSimFcnName.m ├── isGlobalDataStore.m ├── subToSimFcn.m └── sl_customization.m ├── .gitignore ├── .gitmodules ├── README.md ├── LICENSE └── example └── Demo.mdl /imgs/Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/imgs/Cover.png -------------------------------------------------------------------------------- /doc/figs/Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/Demo.png -------------------------------------------------------------------------------- /doc/figs/GUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/GUI.png -------------------------------------------------------------------------------- /doc/figs/Demo1a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/Demo1a.png -------------------------------------------------------------------------------- /doc/figs/Demo1b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/Demo1b.png -------------------------------------------------------------------------------- /doc/figs/Demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/Demo2.png -------------------------------------------------------------------------------- /doc/figs/Module.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/Module.pdf -------------------------------------------------------------------------------- /doc/figs/Interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/Interface.png -------------------------------------------------------------------------------- /imgs/SocialPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/imgs/SocialPreview.png -------------------------------------------------------------------------------- /doc/figs/ContextMenu1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/ContextMenu1.png -------------------------------------------------------------------------------- /doc/figs/ContextMenu2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/ContextMenu2.png -------------------------------------------------------------------------------- /doc/figs/ContextMenu3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/ContextMenu3.png -------------------------------------------------------------------------------- /doc/figs/McSCert_Logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/McSCert_Logo.pdf -------------------------------------------------------------------------------- /doc/SimulinkModule_UserGuide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/SimulinkModule_UserGuide.pdf -------------------------------------------------------------------------------- /doc/figs/GuidelineSelector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/GuidelineSelector.png -------------------------------------------------------------------------------- /src/Interface/Iterator/Iterator.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/src/Interface/Iterator/Iterator.m -------------------------------------------------------------------------------- /doc/figs/FunctionVisibilityParam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/doc/figs/FunctionVisibilityParam.png -------------------------------------------------------------------------------- /src/Guidelines/guidelineSelector.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McSCert/Simulink-Module/HEAD/src/Guidelines/guidelineSelector.fig -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | doc/tex/SimulinkModule_UserGuide.aux 3 | doc/tex/SimulinkModule_UserGuide.log 4 | doc/tex/SimulinkModule_UserGuide.out 5 | doc/tex/SimulinkModule_UserGuide.synctex.gz 6 | doc/tex/SimulinkModule_UserGuide.toc 7 | *.asv 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/Utility"] 2 | path = src/Utility 3 | url = https://github.com/McSCert/Simulink-Utility.git 4 | [submodule "src/LineToGotoFrom"] 5 | path = src/LineToGotoFrom 6 | url = https://github.com/McSCert/LineToGotoFrom.git 7 | -------------------------------------------------------------------------------- /src/isSubsystem.m: -------------------------------------------------------------------------------- 1 | function b = isSubsystem(blocks) 2 | % ISSUBSYSTEM Determine if the block is a subsystem. 3 | % 4 | % Inputs: 5 | % block Pathname or handle of a block. 6 | % 7 | % Outputs: 8 | % b Whether the block is a subsystem(1) or not(0). 9 | 10 | % Convert the input to handles 11 | blocks = inputToNumeric(blocks); 12 | 13 | b = zeros(1, length(blocks)); 14 | % Check each block to see if its a subsystem 15 | for block = 1:length(blocks) 16 | try 17 | blockType = get_param(blocks(block), 'BlockType'); 18 | b(block) = strcmpi(blockType, 'SubSystem'); 19 | catch % Unexpected error 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /src/isLibraryLink.m: -------------------------------------------------------------------------------- 1 | function b = isLibraryLink(blocks) 2 | % ISLIBRARYLINK Determines if the block is a link to a library. 3 | % 4 | % Inputs: 5 | % block Pathname or handle of a block. 6 | % 7 | % Outputs: 8 | % b Whether the block is a Library Link(1) or not(0). 9 | 10 | % Convert whatever input to handles 11 | blocks = inputToNumeric(blocks); 12 | 13 | b = zeros(1, length(blocks)); 14 | 15 | % Check if block is a Library Link 16 | for i = 1:length(blocks) 17 | try 18 | b(i) = strcmpi(get_param(blocks(i), 'LinkStatus'), 'resolved') && ... 19 | ~isempty(get_param(blocks(i), 'ReferenceBlock')); 20 | catch % block does not have this parameter 21 | end 22 | end 23 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simulink Module Tool 2 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4321692.svg)](https://doi.org/10.5281/zenodo.4321692) 3 | [![View Simulink Module Tool on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/71952-simulink-module-tool) 4 | 5 | The Simulink Module Tool performs several functions in order to support modular development for Simulink models: 6 | 7 | * Scoping Simulink Functions 8 | * Creating pre-configured Function callers 9 | * Converting SubSystems into Simulink Functions 10 | * Visualizing or printing a syntactic interface 11 | * Listing module dependencies 12 | * Checking guidelines 13 | 14 | 15 | 16 | ## User Guide 17 | For installation and other information, please see the [User Guide](doc/SimulinkModule_UserGuide.pdf). 18 | -------------------------------------------------------------------------------- /src/inAtomicSubsystem.m: -------------------------------------------------------------------------------- 1 | function [isAtomic, sysAtomic] = inAtomicSubsystem(block) 2 | % ISATOMICSUBSYSTEM Determine if the block is contained in an atomic subsystem. 3 | % 4 | % Inputs: 5 | % block Block name. 6 | % 7 | % Outputs: 8 | % isAtomic Whether the block resides in an atomic subsystem(1) or not(0). 9 | % sysAtomic Atomic subsystem in which the block resides. 10 | 11 | isAtomic = false; 12 | sysAtomic = ''; 13 | 14 | parent = get_param(block, 'Parent'); 15 | while ~isempty(parent) 16 | disp(parent) 17 | try 18 | isAtomic = strcmpi(get_param(parent, 'TreatAsAtomicUnit'), 'on'); 19 | if isAtomic 20 | sysAtomic = parent; 21 | return; 22 | end 23 | parent = get_param(parent, 'Parent'); 24 | catch ME 25 | % reached root 26 | if strcmpi(ME.identifier, 'Simulink:Commands:ParamUnknown') 27 | return; 28 | end 29 | end 30 | end 31 | end -------------------------------------------------------------------------------- /src/Interface/InterfaceHeader.m: -------------------------------------------------------------------------------- 1 | classdef InterfaceHeader 2 | % INTERFACEHEADER The headers used in displaying an interface. 3 | properties 4 | Label % Label text. 5 | Handle % Handle of the annotation. 6 | end 7 | methods (Access = public) 8 | function obj = InterfaceHeader(label) 9 | obj.Label = label; 10 | end 11 | function obj = delete(obj) 12 | % DELETE Delete the header from the model. 13 | % 14 | % Inputs: 15 | obj = obj.update; 16 | try 17 | delete(obj.Handle); 18 | catch ME 19 | if ~strcmp(ME.identifier, 'MATLAB:hg:udd_interface:CannotDelete') 20 | rethrow(ME) 21 | end 22 | end 23 | obj.Handle = []; 24 | end 25 | function obj = update(obj) 26 | 27 | if isempty(obj.Handle) 28 | return 29 | end 30 | 31 | sys = bdroot(gcs); 32 | path = [sys '/' obj.Label]; 33 | obj.Handle = get_param(path, 'Handle'); 34 | end 35 | end 36 | end -------------------------------------------------------------------------------- /src/reqSimFcnName.m: -------------------------------------------------------------------------------- 1 | function simulinkFcnName = reqSimFcnName() 2 | % REQSIMFCNNAME Prompt the user to input a Simulink Function name until a 3 | % name is entered which is not the same as another Simulink Function in scope. 4 | % 5 | % Inputs: 6 | % N/A 7 | % 8 | % Outputs: 9 | % simulinkFcnName Char array representing a Simulink Function name. 10 | % 11 | % Example: 12 | % simulinkFcnName = getSimFcnName() 13 | % 14 | % ans = 'Function_Name' 15 | 16 | %% Dialog Box Parameters 17 | prompt = 'Enter a name for the Simulink Function: '; 18 | dlgtitle = 'Convert Subsystem'; 19 | dims = [1 50]; 20 | definput = {'f'}; 21 | 22 | %% Checking Input 23 | % Loop until the input name is acceptable 24 | while 1 25 | inputName = inputdlg(prompt, dlgtitle, dims, definput); 26 | % Check to see if the name shadows other names in scope 27 | if isGoodSimFcnName(gcs, inputName{1}) 28 | break 29 | else 30 | waitfor(msgbox([inputName{1}, ... 31 | ' is already used as a Simulink Function in scope.', ... 32 | char(10), 'Please enter a new name.'], dlgtitle)); 33 | end 34 | end 35 | simulinkFcnName = inputName{1}; 36 | end -------------------------------------------------------------------------------- /src/isGoodSimFcnName.m: -------------------------------------------------------------------------------- 1 | function goodName = isGoodSimFcnName(subsystem, simulinkFcnName) 2 | % ISGOODSIMFCNNAME Check if a Simulink Function name is the same as any other 3 | % Simulink Functions in scope at the current subsystem level. 4 | % 5 | % Inputs: 6 | % subsystem Path of a subsystem where a Simulink Function will be added. 7 | % simulinkFcnName Name of the Simulink Function to be added. 8 | % 9 | % Outputs: 10 | % goodName Whether the name can be used(1) or not(0). 11 | % 12 | % Example: 13 | % isGoodSimFcnName('SubSystem_Name', 'SimFcnName') 14 | % 15 | % ans = 1 16 | 17 | % Get callable Simulink Functions at the current scope 18 | [~, prototype] = getCallableFunctions(subsystem); 19 | 20 | % Get the prototype names 21 | prototypeNames = getPrototypeName(prototype); 22 | 23 | % Make sure the prototype name is a cell 24 | if ~iscell(prototypeNames) 25 | prototypeNames = {prototypeNames}; 26 | end 27 | 28 | result = zeros(1, length(prototypeNames)); 29 | 30 | % Loop through each prototype name 31 | for name = 1:length(prototypeNames) 32 | % Compare to the input name 33 | result(name) = ~strcmp(simulinkFcnName, prototypeNames{name}); 34 | end 35 | % Return true if none of the prototype names are the same as the input name 36 | goodName = all(result); 37 | end -------------------------------------------------------------------------------- /src/Guidelines/guideline0001.m: -------------------------------------------------------------------------------- 1 | function [blocks, location] = guideline0001(model) 2 | % GUIDELINE0001 Check that a model complies to Guideline 1. Return blocks 3 | % that are not in compliance. Blocks are not in compliance if they are not 4 | % placed in the lowest possible hierarchical position that is a common parent 5 | % amoung its callers. 6 | % 7 | % Inputs: 8 | % model Simulink model name. 9 | % 10 | % Outputs: 11 | % blocks Simulink Function block fullnames. 12 | % location Proposed correct location. 13 | 14 | % Get the model 15 | try 16 | model = bdroot(model); 17 | catch % not loaded 18 | error(['Model ''' model ''' is not loaded.']); 19 | end 20 | 21 | fcns = find_system(model, 'BlockType', 'SubSystem'); 22 | fcns = fcns(isSimulinkFcn(fcns) == 1); 23 | currentLocation = get_param(fcns, 'Parent'); 24 | 25 | blocks = {}; 26 | location = {}; 27 | 28 | for i = 1:length(fcns) 29 | % Find corresponding Function callers 30 | callers = findCallers(fcns{i}); 31 | if isempty(callers) 32 | continue 33 | end 34 | % Find lowest common parent of callers 35 | idealLocation = commonParents(callers); 36 | 37 | % If subsystem is not placed in this spot, it can be placed lower or higher 38 | % than its current position 39 | if ~strcmp(idealLocation, currentLocation{i}) 40 | blocks{end+1} = fcns{i}; 41 | location{end+1} = idealLocation; 42 | end 43 | end 44 | end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, McSCert 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/Guidelines/guideline0002.m: -------------------------------------------------------------------------------- 1 | function blocks = guideline0002(model) 2 | % GUIDELINE0002 Check that a model complies to Guideline 2. Return blocks 3 | % that are not in compliance. Blocks are not in compliance if they have global 4 | % visibility, and are not used outside of the model. It is not possible to 5 | % check is all models (loaded and unloaded) use the function, which would 6 | % justify the global visibility. Therefore, we err on the side of caution, and 7 | % return all blocks with global visibility. 8 | % 9 | % Inputs: 10 | % model Simulink model name. 11 | % 12 | % Outputs: 13 | % blocks Simulink Function block names. 14 | 15 | blocks = find_system(model, 'BlockType', 'SubSystem'); 16 | blocks = blocks(isSimulinkFcn(blocks) == 1); 17 | 18 | visibility = cell(size(blocks)); 19 | 20 | for i = 1:length(blocks) 21 | % 1) Get Function Visibility parameter 22 | triggerPort = find_system(blocks{i}, 'SearchDepth', 1, 'FollowLinks', 'on', ... 23 | 'BlockType', 'TriggerPort', ... 24 | 'TriggerType', 'function-call'); 25 | try 26 | visibility{i} = get_param(triggerPort{1}, 'FunctionVisibility'); 27 | catch 28 | % Either not a Simulink Function, or earlier versions of 29 | % Simulink Functions (e.g. 2014b) do not have this parameter 30 | visibility{i} = ''; 31 | continue 32 | end 33 | end 34 | 35 | globalVisibility = strcmp(visibility, 'global') == 1; 36 | blocks = blocks(globalVisibility); 37 | end -------------------------------------------------------------------------------- /src/Guidelines/guideline0004.m: -------------------------------------------------------------------------------- 1 | function blocks = guideline0004(model) 2 | % GUIDELINE0004 Check that a model complies to Guideline 4. Return blocks 3 | % that are not in compliance. Blocks are not in compliance if they interact 4 | % with the base workspace (e.g., To Workspace, From File, etc.) 5 | % 6 | % Inputs: 7 | % model Simulink model name. 8 | % 9 | % Outputs: 10 | % blocks Block fullnames. 11 | 12 | % Get the model 13 | try 14 | model = bdroot(model); 15 | catch % not loaded 16 | error(['Model ''' model ''' is not loaded.']); 17 | end 18 | 19 | ff = find_system(model, 'BlockType', 'FromFile', 'Commented', 'off'); 20 | fs = find_system(model, 'BlockType', 'FromSpreadsheet', 'Commented', 'off'); 21 | fw = find_system(model, 'BlockType', 'FromWorkspace', 'Commented', 'off'); 22 | tf = find_system(model, 'BlockType', 'ToFile', 'Commented', 'off'); 23 | tw = find_system(model, 'BlockType', 'ToWorkspace', 'Commented', 'off'); 24 | 25 | % Global data stores in the base workspace are not be allowed. 26 | % Data Dictionary and model workspace are OK. 27 | dswr = [find_system(model, 'BlockType', 'DataStoreWrite', 'Commented', 'off'); ... 28 | find_system(model, 'BlockType', 'DataStoreRead', 'Commented', 'off');]; 29 | ds = {}; 30 | for i = 1:length(dswr) 31 | [isGlobal, ~, location] = isGlobalDataStore(dswr{i}); 32 | if isGlobal && strcmp(location, 'base') 33 | ds{end+1,1} = dswr{i}; 34 | end 35 | end 36 | 37 | blocks = vertcat(ff, fs, fw, tf, tw, ds); 38 | end -------------------------------------------------------------------------------- /src/Interface/Iterator/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2010, The MathWorks, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution. 13 | * In all cases, the software is, and all modifications and derivatives 14 | of the software shall be, licensed to you solely for use in conjunction 15 | with MathWorks products and service offerings. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /src/Interface/dependencies.m: -------------------------------------------------------------------------------- 1 | function dependencies(sys) 2 | % DEPENDENCIES List the model dependencies in the Command Window. 3 | % 4 | % Inputs: 5 | % sys Model model 6 | % 7 | % Outputs: 8 | % N/A 9 | 10 | sys = bdroot(sys); 11 | 12 | % Initialize counts 13 | mr_n = 0; 14 | ll_n = 0; 15 | dd_n = 0; 16 | 17 | %% 1) Model References 18 | mr = find_system(sys, 'BlockType', 'ModelReference', 'Commented', 'off'); 19 | % Remove non-unique based on ModelFile 20 | modelname = get_param(mr, 'ModelFile'); 21 | [~, idx] = unique(modelname); 22 | mr = mr(idx); 23 | if isempty(mr) 24 | mr = {'N/A'}; 25 | else 26 | mr = replaceNewline(mr); 27 | mr_n = length(mr); 28 | end 29 | 30 | %% 2) Linked Library Blocks 31 | ll = find_system(sys, 'FollowLinks', 'on', 'LinkStatus', 'resolved', 'Commented', 'off'); 32 | % In case sys is a library, remove any dependencies to itself 33 | lib = bdroot(ll); 34 | idx = ~strcmp(lib, sys); 35 | ll = ll(idx); 36 | if isempty(ll) 37 | ll = {'N/A'}; 38 | else 39 | ll = replaceNewline(ll); 40 | ll_n = length(ll); 41 | end 42 | 43 | %% 3) Data Dictionary 44 | try 45 | dd = get_param(sys, 'DataDictionary'); 46 | if isempty(dd) 47 | dd = 'N/A'; 48 | else 49 | dd = replaceNewline(dd); 50 | dd_n = length(dd); 51 | end 52 | catch % Parameter does not exist in earlier versions 53 | dd = 'N/A'; 54 | end 55 | 56 | %% Print 57 | fprintf('Model References (%d)\n', mr_n); 58 | fprintf('------\n'); 59 | for i = 1:length(mr) 60 | fprintf('%s\n', mr{i}); 61 | end 62 | 63 | fprintf('\nLibrary Links (%d)\n', ll_n); 64 | fprintf('------\n'); 65 | for i = 1:length(ll) 66 | fprintf('%s\n', ll{i}); 67 | end 68 | 69 | fprintf('\nData Dictionaries (%d)\n', dd_n); 70 | fprintf('------\n'); 71 | fprintf('%s\n', dd); 72 | end -------------------------------------------------------------------------------- /src/Guidelines/guideline0003.m: -------------------------------------------------------------------------------- 1 | function [blocks, shadows] = guideline0003(model) 2 | % GUIDELINE003 Check that a model complies to Guideline 3. Return blocks 3 | % that are not in compliance. Blocks are not in compliance if they are in the 4 | % scope of one or more function blocks with the same name and parameters. 5 | % 6 | % Inputs: 7 | % model Simulink model name. 8 | % 9 | % Outputs: 10 | % blocks Simulink Function block fullnames. 11 | % shadows Simulink Function block fullnames. 12 | 13 | % Get the model 14 | try 15 | model = bdroot(model); 16 | catch % not loaded 17 | error(['Model ''' model ''' is not loaded.']); 18 | end 19 | 20 | fcns = find_system(model, 'BlockType', 'SubSystem'); 21 | fcns = fcns(isSimulinkFcn(fcns) == 1); 22 | 23 | blocks = {}; 24 | shadows = {}; 25 | 26 | % Note: 27 | % - Functions with the same name in same subsystem (Error) 28 | % - Two global functions with same name in different subsystems (Error) 29 | 30 | for i = 1:length(fcns) 31 | % Get all Simulink functions that are in scope 32 | [inscopeFcns, inscopePrototyes] = getCallableFunctions(get_param(fcns{i}, 'Parent')); 33 | 34 | % Remove itself 35 | i_idx = find(strcmp(inscopeFcns, fcns{i})); 36 | inscopeFcns(i_idx) = ''; 37 | inscopePrototyes(i_idx) = ''; 38 | 39 | % Get function names 40 | %inscopeNames = getPrototypeName(inscopePrototyes); 41 | %n = getPrototypeName(getPrototype(fcns{i})); 42 | 43 | % Check if there are any function prototype that are the same 44 | found = strfind(inscopePrototyes, getPrototype(fcns{i})); 45 | if ~iscell(found) 46 | found = {found}; 47 | end 48 | idx = find(not(cellfun('isempty', found))); 49 | if ~isempty(idx) % If yes, add to list of shadowing functions 50 | blocks{end+1} = fcns{i}; 51 | shadows{end+1} = inscopeFcns(idx); 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /src/Interface/InterfaceIterator.m: -------------------------------------------------------------------------------- 1 | classdef InterfaceIterator < Iterator 2 | 3 | properties(Access = private) 4 | loc; % Current location of traversal. 5 | end 6 | 7 | methods 8 | function newObj = InterfaceIterator(varargin) 9 | narginchk(0,1); 10 | 11 | if nargin == 0 12 | % Store reference to empty interface and position iterator at start. 13 | newObj.collection = Interface(); 14 | newObj.loc = 1; 15 | else 16 | % Store reference to interface and position iterator at start. 17 | newObj.collection = varargin{1}; 18 | newObj.loc = 1; 19 | end 20 | end 21 | 22 | % Concrete implementation. See Iterator superclass. 23 | function el = next(obj) 24 | % NEXT Advance to the next element in sequence in the collection and 25 | % return it. 26 | % 27 | % Inputs: 28 | % obj InterfaceIterator object. 29 | % 30 | % Outputs: 31 | % el Next element in the interface. 32 | 33 | if obj.hasNext() 34 | el = obj.collection.get(obj.loc); 35 | obj.loc = obj.loc + 1; 36 | end 37 | end 38 | 39 | % Concrete implementation. See Iterator superclass. 40 | function next = hasNext(obj) 41 | % HASBEXT Check if the there is another element in the traversal of the 42 | % collection. 43 | % 44 | % Inputs: 45 | % obj InterfaceIterator object. 46 | % 47 | % Outputs: 48 | % next Whether the is another interface element next (1), or 49 | % not (0); 50 | 51 | next = obj.loc <= obj.collection.length(); 52 | end 53 | 54 | % Concrete implementation. See Iterator superclass. 55 | function reset(obj) 56 | % RESET Position iterator at the start. 57 | % 58 | % Inputs: 59 | % obj InterfaceIterator object. 60 | % 61 | % Outputs: 62 | % N/A 63 | 64 | obj.loc = 1; 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /src/Interface/getSampleTime.m: -------------------------------------------------------------------------------- 1 | function time = getSampleTime(block) 2 | % GETSAMPLETIME Determine the block sample time. Based on the 3 | % SampleTime and CompiledSampleTime parameters. Note that some blocks may have 4 | % different sample rates for different ports (e.g. SubSystems containing blocks 5 | % with different rates). Sample time may be more accurate after model 6 | % compilation. 7 | % 8 | % Inputs: 9 | % block Block path or handle. 10 | % 11 | % Outputs: 12 | % time Vector of sample times. 13 | % 14 | % Example: 15 | % >> getSampleTime('ex_compiled_sample_new/Sine Wave3') 16 | % ans = 17 | % 0.5000 18 | % 19 | % >> getSampleTime('ex_compiled_sample_new/Atomic Subsystem') 20 | % ans = 21 | % 3 22 | % 4 23 | % 24 | % See: www.mathworks.com/help/simulink/ug/determining-the-compiled-sample-time-of-a-block.html 25 | % See: https://www.mathworks.com/help/simulink/ug/types-of-sample-time.html 26 | 27 | narginchk(1,1); 28 | 29 | % 1) Get the SampleTime 30 | sampleTime = []; 31 | try 32 | sampleTime = str2double(get_param(block, 'SampleTime')); 33 | catch ME 34 | if ~strcmpi(ME.identifier, 'Simulink:Commands:ParamUnknown') 35 | rethrow(ME) 36 | end 37 | end 38 | 39 | % For Simulink.Signal objects 40 | [isGlobal, obj, ~] = isGlobalDataStore(block); 41 | if isGlobal 42 | sampleTimeDs = obj.SampleTime; 43 | if (isInherited(sampleTime) || isempty(sampleTime)) && ~isempty(sampleTimeDs) 44 | sampleTime = sampleTimeDs; 45 | end 46 | end 47 | 48 | % 2) Get the CompiledSampleTime 49 | compiledSampleTime = get_param(block, 'CompiledSampleTime'); 50 | if iscell(compiledSampleTime) 51 | compiledSampleTime = cell2mat(compiledSampleTime); 52 | end 53 | 54 | % Get the first row only. Documentation doesn't say what the second row is for, 55 | % and it contains zeros 56 | compiledSampleTime = compiledSampleTime(:,1); 57 | 58 | % Finally: Determine which to return. If the compiled time is available, always 59 | % return it because it could be different from the sample time. 60 | if ~isInherited(compiledSampleTime) 61 | time = compiledSampleTime; 62 | elseif isempty(sampleTime) 63 | time = compiledSampleTime; 64 | else 65 | time = sampleTime; 66 | end 67 | end 68 | 69 | function b = isInherited(time) 70 | if ~iscell(time) 71 | b = time == -1; 72 | else 73 | b = false; 74 | end 75 | end -------------------------------------------------------------------------------- /src/Interface/getDataType_MJ.m: -------------------------------------------------------------------------------- 1 | function types = getDataType_MJ(blocks) 2 | % GETDATATYPE_MJ Return the block data type, for each Inport and Outport. 3 | % 4 | % Inputs: 5 | % blocks Array of block paths or handles. 6 | % 7 | % Outputs: 8 | % types Cell array of structs. 9 | % 10 | % Example: 11 | % >> getDataType_MJ('model/In1') 12 | % ans = 13 | % struct with fields: 14 | % Inport: [] 15 | % Outport: 'Inherit: auto' 16 | 17 | blocks = inputToNumeric(blocks); 18 | 19 | % Get block types 20 | blockTypes = get_param(blocks, 'BlockType'); 21 | if ~iscell(blockTypes) || length(blockTypes) == 1 22 | blockTypes = {blockTypes}; 23 | end 24 | 25 | % Create empty struct cell array 26 | types = struct('Inport', [], 'Outport', []); 27 | types = repmat({types}, size(blocks)); 28 | 29 | for i = 1:length(blocks) 30 | b = blocks(i); 31 | 32 | if any(find(strcmp(blockTypes{i}, {'Inport', 'FromFile'}))) 33 | types{i}.Outport = get_param(b, 'OutDataTypeStr'); 34 | 35 | elseif strcmp(blockTypes{i}, 'FromSpreadsheet') 36 | t = get_param(b, 'OutDataTypeStr'); 37 | portHandles = get_param(b, 'PortHandles'); 38 | nOut = length(portHandles.Outport); 39 | types{i}.Outport = repmat(t, nOut, 1); 40 | 41 | elseif strcmp(blockTypes{i}, 'Outport') 42 | types{i}.Inport = get_param(b, 'OutDataTypeStr'); 43 | 44 | elseif strcmp(blockTypes{i}, 'ToFile') 45 | types{i}.Inport = get_param(b, 'SaveFormat'); 46 | 47 | elseif strcmp(blockTypes{i}, 'ToWorkspace') 48 | workspaceData = evalin('base', 'whos'); 49 | idx = ismember({workspaceData.name}, get_param(b, 'VariableName')); 50 | if any(idx) 51 | match = workspaceData(idx); 52 | types{i}.Inport = match.class; 53 | end 54 | 55 | elseif strcmp(blockTypes{i}, 'FromWorkspace') 56 | workspaceData = evalin('base', 'whos'); 57 | idx = ismember({workspaceData.name}, get_param(b, 'VariableName')); 58 | if any(idx) 59 | match = workspaceData(idx); 60 | types{i}.Outport = match.class; 61 | else 62 | types{i}.Outport = get_param(b, 'OutDataTypeStr'); 63 | end 64 | 65 | elseif strcmp(blockTypes{i}, {'DataStoreRead'}) 66 | [isGlobal, obj, ~] = isGlobalDataStore(b); 67 | if isGlobal 68 | types{i}.Outport = obj.DataType; 69 | else 70 | error(['Block ''' getfullname(b) ''' is not a global data store and should not be on the interface.']); 71 | end 72 | 73 | elseif strcmp(blockTypes{i}, {'DataStoreWrite'}) 74 | [isGlobal, obj, ~] = isGlobalDataStore(b); 75 | if isGlobal 76 | types{i}.Inport = obj.DataType; 77 | else 78 | error(['Block ''' getfullname(b) ''' is not a global data store and should not be on the interface.']); 79 | end 80 | 81 | elseif isSimulinkFcn(b) 82 | [intype, outtype] = getFcnArgsType(b); 83 | types{i}.Inport = char(intype); 84 | types{i}.Outport = char(outtype); 85 | 86 | elseif isLibraryLink(b) 87 | %types{i} = 'N/A'; 88 | 89 | elseif strcmp(blockTypes{i}, 'ModelReference') 90 | %types{i} = 'N/A'; 91 | end 92 | end 93 | 94 | % Just return the struct if it's for one element only 95 | if length(types) == 1 96 | types = types{1}; 97 | end 98 | end -------------------------------------------------------------------------------- /doc/tex/macros.tex: -------------------------------------------------------------------------------- 1 | \usepackage{xspace} 2 | 3 | \newcommand{\args}[1] {\textit{#1}} 4 | \newcommand{\cmd}[1] {\texttt{#1}} % Use for command window commands, e.g., \cmd{svn up} 5 | \newcommand{\block}[1] {\textsf{#1}} % Use for Simulink block names, e.g., \cmd{Subsystem1} 6 | \newcommand{\signal}[1] {\textsf{#1}} % Use for Simulink block names, e.g., \cmd{Subsystem1} 7 | \newcommand{\ring}[1] {\textsf{#1}} % Use for files names and paths 8 | \newcommand{\keyword}[1] {\texttt{#1}} % Use for keywords of programming languages, e.g., \keyword{while} 9 | \newcommand{\file}[1] {\texttt{#1}} % Use for files names and paths 10 | \newcommand{\param}[1] {\textsf{#1}} % Use for block parameter names, e.g., \param{BlockType} 11 | 12 | % Matlab Products 13 | \newcommand{\matlab}{\textsc{Matlab}\@\xspace} 14 | \newcommand{\Matlab}{\textsc{Matlab}\@\xspace} 15 | \newcommand{\Simulink}{Simulink\@\xspace} 16 | \newcommand{\simulink}{Simulink\@\xspace} 17 | \newcommand{\SDV}{Simulink Design Verifier\@\xspace} 18 | \newcommand{\mpath}{\Matlab search path\@\xspace} 19 | 20 | % Block Names (not BlockType) 21 | \newcommand{\ds}{\block{Data Store}\@\xspace} 22 | \newcommand{\DSM}{\block{Data Store Memory}\@\xspace} 23 | \newcommand{\DSR}{\block{Data Store Read}\@\xspace} 24 | \newcommand{\DSW}{\block{Data Store Write}\@\xspace} 25 | \newcommand{\DSRW}{\block{Data Store Read/Write}\@\xspace} 26 | \newcommand{\DSMRW}{\block{Data Store Memory/Read/Write}\@\xspace} 27 | 28 | \newcommand{\goto}{\block{Goto}\@\xspace} 29 | \newcommand{\from}{\block{From}\@\xspace} 30 | 31 | \newcommand{\inport}{\block{Inport}\@\xspace} 32 | \newcommand{\outport}{\block{Outport}\@\xspace} 33 | 34 | \newcommand{\argin}{\block{ArgIn}\@\xspace} 35 | \newcommand{\argout}{\block{ArgOut}\@\xspace} 36 | 37 | \newcommand{\constant}{\block{Constant}\@\xspace} 38 | \newcommand{\ground}{\block{Ground}\@\xspace} 39 | \newcommand{\subsystem}{\block{Subsystem}\@\xspace} 40 | 41 | \newcommand{\logic}{\block{Logical Operator}\@\xspace} 42 | \newcommand{\relational}{\block{Relational Operator}\@\xspace} 43 | \newcommand{\ifblk}{\block{If}\@\xspace} 44 | \newcommand{\switch}{\block{Switch}\@\xspace} 45 | \newcommand{\merge}{\block{Merge}\@\xspace} 46 | 47 | \newcommand{\docblock}{\block{DocBlock}\@\xspace} 48 | 49 | \newcommand{\trigger}{\block{Trigger}\@\xspace} 50 | 51 | \newcommand{\simfunc}{\block{Simulink Function}\@\xspace} 52 | \newcommand{\simfunccaller}{\block{Function Caller}\@\xspace} 53 | 54 | \newcommand{\toworkspace}{\block{To Workspace}\@\xspace} 55 | \newcommand{\fromworkspace}{\block{From Workspace}\@\xspace} 56 | 57 | \newcommand{\tofile}{\block{To File}\@\xspace} 58 | \newcommand{\fromfile}{\block{From File}\@\xspace} 59 | 60 | \newcommand{\fromspreadsheet}{\block{From Spreadsheet}\@\xspace} 61 | 62 | \newcommand{\modelref}{\block{Model Reference}\@\xspace} 63 | \newcommand{\library}{\block{Library}\@\xspace} 64 | \newcommand{\librarylink}{\block{Library Link}\@\xspace} 65 | 66 | % Commonly used parameters 67 | \newcommand{\AND}{\param{AND}\@\xspace} 68 | \newcommand{\OR}{\param{OR}\@\xspace} 69 | \newcommand{\NOT}{\param{NOT}\@\xspace} 70 | \newcommand{\NOR}{\param{NOR}\@\xspace} 71 | \newcommand{\NAND}{\param{NAND}\@\xspace} 72 | \newcommand{\XOR}{\param{XOR}\@\xspace} 73 | \newcommand{\NXOR}{\param{NXOR}\@\xspace} 74 | 75 | % Common Abbreviations 76 | % Example 77 | \newcommand{\eg}{\textrm{e.g.,}\@\xspace} 78 | 79 | % That Is To Say 80 | \newcommand{\ie}{\textrm{i.e.,}\@\xspace} 81 | 82 | % And So On 83 | \newcommand{\etc}{\textrm{etc.}\@\xspace} 84 | 85 | % And Others 86 | \newcommand{\etal}{\textrm{et al.}\@\xspace} 87 | 88 | % With Respect To 89 | \newcommand{\wrt}{\textrm{w.r.t.}\@\xspace} 90 | 91 | % Vice Versa 92 | \newcommand{\vrsa}{\textrm{vice versa}\@\xspace} 93 | 94 | % Symbols 95 | 96 | \usepackage{amssymb} 97 | \newcommand{\checkbox}{\makebox[0pt][l]{$\square$}\raisebox{.15ex}{\hspace{0.1em}$\checkmark$}}% 98 | \newcommand{\uncheckbox}{$\square$~}% 99 | -------------------------------------------------------------------------------- /src/Interface/getDimensions.m: -------------------------------------------------------------------------------- 1 | function dims = getDimensions(blocks) 2 | % GETDIMENSIONS Return the block dimensions, for each Inport and Outport. 3 | % 4 | % Inputs: 5 | % blocks Array of block paths or handles. 6 | % 7 | % Outputs: 8 | % dims Cell array of structs. 9 | % 10 | % Example: 11 | % >> getDimensions{'model/In1') 12 | % ans = 13 | % struct with fields: 14 | % Inport: 1 15 | % Outport: [] 16 | 17 | blocks = inputToNumeric(blocks); 18 | 19 | % Get block types 20 | blockTypes = get_param(blocks, 'BlockType'); 21 | if ~iscell(blockTypes) || length(blockTypes) == 1 22 | blockTypes = {blockTypes}; 23 | end 24 | 25 | % Create empty struct cell array 26 | dims = struct('Inport', [], 'Outport', []); 27 | dims = repmat({dims}, size(blocks)); 28 | 29 | for i = 1:length(blocks) 30 | b = blocks(i); 31 | 32 | if strcmp(blockTypes{i}, 'Inport') 33 | dims{i}.Outport = get_param(b, 'PortDimensions'); 34 | 35 | elseif strcmp(blockTypes{i}, 'Outport') 36 | dims{i}.Inport = get_param(b, 'PortDimensions'); 37 | 38 | elseif isSimulinkFcn(b) && ~isLibraryLink(b) 39 | [indim, outdim] = getFcnArgsDim(b); 40 | dims{i}.Inport = cell2mat(indim); 41 | dims{i}.Outport = cell2mat(outdim); 42 | 43 | elseif strcmp(blockTypes{i}, 'DataStoreRead') 44 | [isGlobal, obj, ~] = isGlobalDataStore(b); 45 | if isGlobal 46 | dims{i}.Outport = obj.Dimensions; 47 | else 48 | error(['Block ''' getfullname(b) ''' is not a global data store and should not be on the interface.']); 49 | end 50 | 51 | elseif strcmp(blockTypes{i}, 'DataStoreWrite') 52 | [isGlobal, obj, ~] = isGlobalDataStore(b); 53 | if isGlobal 54 | dims{i}.Inport = obj.Dimensions; 55 | else 56 | error(['Block ''' getfullname(b) ''' is not a global data store and should not be on the interface.']); 57 | end 58 | 59 | elseif any(find(strcmp(blockTypes{i}, {'ToFile', 'FromFile'}))) 60 | % 61 | 62 | elseif strcmp(blockTypes{i}, 'FromSpreadsheet') 63 | % Only one dimensional signals are supported 64 | dims{i}.Outport = ones(1, length(get_param(b, 'PortConnectivity'))); 65 | 66 | elseif strcmp(blockTypes{i}, 'ToWorkspace') 67 | workspaceData = evalin('base', 'whos'); 68 | idx = ismember({workspaceData.name}, get_param(b, 'VariableName')); 69 | if any(idx) 70 | match = workspaceData(idx); 71 | dims{i}.Inport = match.size; 72 | end 73 | 74 | elseif strcmp(blockTypes{i}, 'FromWorkspace') 75 | workspaceData = evalin('base', 'whos'); 76 | idx = ismember({workspaceData.name}, get_param(b, 'VariableName')); 77 | if any(idx) 78 | match = workspaceData(idx); 79 | dims{i}.Outport = match.size; 80 | end 81 | 82 | elseif strcmp(blockTypes{i}, 'ModelReference') 83 | % 84 | end 85 | 86 | 87 | try 88 | dims{i}.Inport = str2num(dims{i}.Inport); 89 | catch 90 | end 91 | try 92 | dims{i}.Outport = str2num(dims{i}.Outport); 93 | catch 94 | end 95 | end 96 | 97 | % Just return the struct if it's for one element only 98 | if length(dims) == 1 99 | dims = dims{1}; 100 | end 101 | end -------------------------------------------------------------------------------- /src/Guidelines/guidelineSelector.m: -------------------------------------------------------------------------------- 1 | function varargout = guidelineSelector(varargin) 2 | % GUIDELINESELECTOR MATLAB code for guidelineSelector.fig 3 | % GUIDELINESELECTOR, by itself, creates a new GUIDELINESELECTOR or raises the existing 4 | % singleton*. 5 | % 6 | % H = GUIDELINESELECTOR returns the handle to a new GUIDELINESELECTOR or the handle to 7 | % the existing singleton*. 8 | % 9 | % GUIDELINESELECTOR('CALLBACK',hObject,eventData,handles,...) calls the local 10 | % function named CALLBACK in GUIDELINESELECTOR.M with the given input arguments. 11 | % 12 | % GUIDELINESELECTOR('Property','Value',...) creates a new GUIDELINESELECTOR or raises the 13 | % existing singleton*. Starting from the left, property value pairs are 14 | % applied to the GUI before guidelineSelector_OpeningFcn gets called. An 15 | % unrecognized property name or invalid value makes property application 16 | % stop. All inputs are passed to guidelineSelector_OpeningFcn via varargin. 17 | % 18 | % *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one 19 | % instance to run (singleton)". 20 | % 21 | % See also: GUIDE, GUIDATA, GUIHANDLES 22 | 23 | % Edit the above text to modify the response to help guidelineSelector 24 | 25 | % Last Modified by GUIDE v2.5 02-Oct-2018 16:40:16 26 | 27 | % Begin initialization code - DO NOT EDIT 28 | gui_Singleton = 1; 29 | gui_State = struct('gui_Name', mfilename, ... 30 | 'gui_Singleton', gui_Singleton, ... 31 | 'gui_OpeningFcn', @guidelineSelector_OpeningFcn, ... 32 | 'gui_OutputFcn', @guidelineSelector_OutputFcn, ... 33 | 'gui_LayoutFcn', [] , ... 34 | 'gui_Callback', []); 35 | if nargin && ischar(varargin{1}) 36 | gui_State.gui_Callback = str2func(varargin{1}); 37 | end 38 | 39 | if nargout 40 | [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); 41 | else 42 | gui_mainfcn(gui_State, varargin{:}); 43 | end 44 | % End initialization code - DO NOT EDIT 45 | 46 | 47 | % --- Executes just before guidelineSelector is made visible. 48 | function guidelineSelector_OpeningFcn(hObject, eventdata, handles, varargin) 49 | % This function has no output args, see OutputFcn. 50 | % hObject handle to figure 51 | % eventdata reserved - to be defined in a future version of MATLAB 52 | % handles structure with handles and user data (see GUIDATA) 53 | % varargin command line arguments to guidelineSelector (see VARARGIN) 54 | 55 | % Choose default command line output for guidelineSelector 56 | handles.output = ''; 57 | 58 | % Update handles structure 59 | guidata(hObject, handles); 60 | 61 | % UIWAIT makes guidelineSelector wait for user response (see UIRESUME) 62 | uiwait(handles.figure1); 63 | 64 | 65 | % --- Outputs from this function are returned to the command line. 66 | function varargout = guidelineSelector_OutputFcn(hObject, eventdata, handles) 67 | % varargout cell array for returning output args (see VARARGOUT); 68 | % hObject handle to figure 69 | % eventdata reserved - to be defined in a future version of MATLAB 70 | % handles structure with handles and user data (see GUIDATA) 71 | 72 | % Set the output values, depending on which button was pressed 73 | if strcmp(handles.output, 'OK') 74 | g0001 = get(handles.checkbox0001, 'Value'); 75 | g0002 = get(handles.checkbox0002, 'Value'); 76 | g0003 = get(handles.checkbox0003, 'Value'); 77 | g0004 = get(handles.checkbox0004, 'Value'); 78 | 79 | varargout{1} = [g0001, g0002, g0003, g0004]; 80 | else 81 | varargout{1} = [0 0 0 0]; 82 | end 83 | 84 | % The figure can be deleted now 85 | delete(handles.figure1); 86 | 87 | 88 | % --- Executes on button press in buttonOK. 89 | function buttonOK_Callback(hObject, eventdata, handles) 90 | % hObject handle to buttonOK (see GCBO) 91 | % eventdata reserved - to be defined in a future version of MATLAB 92 | % handles structure with handles and user data (see GUIDATA) 93 | 94 | % Update which button was pressed 95 | handles.output = get(hObject, 'String'); 96 | 97 | % Update handles structure 98 | guidata(hObject, handles); 99 | 100 | % Use UIRESUME instead of delete because the OutputFcn needs 101 | % to get the updated handles structure. 102 | uiresume(handles.figure1); 103 | 104 | 105 | % --- Executes on button press in checkbox0001. 106 | function checkbox0001_Callback(hObject, eventdata, handles) 107 | % hObject handle to checkbox0001 (see GCBO) 108 | % eventdata reserved - to be defined in a future version of MATLAB 109 | % handles structure with handles and user data (see GUIDATA) 110 | 111 | % Hint: get(hObject,'Value') returns toggle state of checkbox0001 112 | 113 | 114 | % --- Executes on button press in checkbox0002. 115 | function checkbox0002_Callback(hObject, eventdata, handles) 116 | % hObject handle to checkbox0002 (see GCBO) 117 | % eventdata reserved - to be defined in a future version of MATLAB 118 | % handles structure with handles and user data (see GUIDATA) 119 | 120 | % Hint: get(hObject,'Value') returns toggle state of checkbox0002 121 | 122 | 123 | % --- Executes on button press in checkbox0003. 124 | function checkbox0003_Callback(hObject, eventdata, handles) 125 | % hObject handle to checkbox0003 (see GCBO) 126 | % eventdata reserved - to be defined in a future version of MATLAB 127 | % handles structure with handles and user data (see GUIDATA) 128 | 129 | % Hint: get(hObject,'Value') returns toggle state of checkbox0003 130 | 131 | 132 | % --- Executes on button press in checkbox0004. 133 | function checkbox0004_Callback(hObject, eventdata, handles) 134 | % hObject handle to checkbox0004 (see GCBO) 135 | % eventdata reserved - to be defined in a future version of MATLAB 136 | % handles structure with handles and user data (see GUIDATA) 137 | 138 | % Hint: get(hObject,'Value') returns toggle state of checkbox0004 139 | 140 | 141 | % --- Executes when user attempts to close figure1. 142 | function figure1_CloseRequestFcn(hObject, eventdata, handles) 143 | % hObject handle to figure1 (see GCBO) 144 | % eventdata reserved - to be defined in a future version of MATLAB 145 | % handles structure with handles and user data (see GUIDATA) 146 | 147 | if isequal(get(hObject, 'waitstatus'), 'waiting') 148 | % The GUI is still in UIWAIT, use UIRESUME 149 | uiresume(hObject); 150 | else 151 | % The GUI is no longer waiting, just close it 152 | delete(hObject); 153 | end 154 | -------------------------------------------------------------------------------- /src/isGlobalDataStore.m: -------------------------------------------------------------------------------- 1 | function [isGlobal, obj, location] = isGlobalDataStore(block) 2 | % ISGLOBALDATASTORE Determine if a Data Store Read/Write block is a global data 3 | % store, that is, it has a corresponding Simulink.Signal in the base workspace 4 | % or linked data dictionary. 5 | % 6 | % Inputs: 7 | % block Block path or handle. 8 | % 9 | % Outputs: 10 | % isGlobal Whether the block is a global data store (1) or not (0). 11 | % obj Simulink.Signal object corresponding to the block. 12 | % location Object where the Simulink.Signal definition resides. 13 | % 14 | % Example: 15 | % >> [gbl, obj, loc] = isGlobalStateStore('Example/Data Store Write1') 16 | % 17 | % glb = 18 | % logical 19 | % 1 20 | % 21 | % obj = 22 | % Signal with properties: 23 | % CoderInfo: [1x1 Simulink.CoderInfo] 24 | % Description: '' 25 | % DataType: 'double' 26 | % Min: [] 27 | % Max: [] 28 | % Unit: '' 29 | % Dimensions: [1 3] 30 | % DimensionsMode: 'Fixed' 31 | % Complexity: 'real' 32 | % SampleTime: -1 33 | % InitialValue: '' 34 | % 35 | % loc = 36 | % Dictionary with properties: 37 | % DataSources: {0x1 cell} 38 | % HasAccessToBaseWorkspace: 0 39 | % EnableAccessToBaseWorkspace: 0 40 | % HasUnsavedChanges: 1 41 | % NumberOfEntries: 3 42 | 43 | % TODO: Figure out if when the 'EnableAccessToBaseWorkspace' parameter is 44 | % true, this affects the results of this function. See: 45 | % https://www.mathworks.com/help/simulink/slref/simulink.data.dictionary-class.html#d120e428542 46 | 47 | % Convert input to path 48 | block = [get_param(block, 'Parent') '/' get_param(block, 'Name')]; 49 | 50 | % Default vaules: 51 | % If we can't find the associated Memory block, that means that it is a Simuilink.Signal 52 | % elsewhere, but can't detetmine where. This can happen if a model has a 53 | % global data store, but the Simuilink.Signal is not loaded in any workspace. 54 | isGlobal = true; 55 | obj = []; 56 | location = 'unknown'; 57 | 58 | blockType = get_param(block, 'BlockType'); 59 | if ~any(find(strcmp(blockType, {'DataStoreRead', 'DataStoreWrite'}))) 60 | isGlobal = false; 61 | obj = []; 62 | location = []; 63 | else 64 | name = get_param(block, 'DataStoreName'); 65 | 66 | % 0) Model 67 | % Check if the model contains an associated Data Store Memory block. If 68 | % it does, it takes precedence over all other definitions. This is NOT a 69 | % global data store. 70 | 71 | % Search for any associated memory block at the same level or above 72 | % Even if there is a workspace Simulink.Signal with the same name, the 73 | % Data Store Read/Write block will use the Memory block in the model. 74 | parent = get_param(block, 'Parent'); 75 | root = bdroot(block); 76 | memoryAll = find_system(root, 'BlockType', 'DataStoreMemory', 'DataStoreName', name); 77 | memoryHere = find_system(parent, 'SearchDepth', 1, 'BlockType', 'DataStoreMemory', 'DataStoreName', name); 78 | memoryHereAndBelow = find_system(parent, 'BlockType', 'DataStoreMemory', 'DataStoreName', name); 79 | memoryBelow = setdiff(memoryHereAndBelow, memoryHere); 80 | memoryInScope = setdiff(memoryAll, memoryBelow); 81 | if ~isempty(memoryInScope) 82 | isGlobal = false; 83 | obj = []; 84 | location = []; % TODO: Find lowest common ancestor (Get from Rescope Tool) 85 | else 86 | 87 | % 1) Model Workspace 88 | % Check model workspace next, because it takes precedence over 89 | % data dictionary or base workspace definitions. This is NOT a 90 | % global data store. 91 | workspace = get_param(bdroot, 'modelworkspace'); 92 | try 93 | ds = getVariable(workspace, name); 94 | catch ME 95 | if strcmp(ME.identifier, 'Simulink:Data:WksUndefinedVariable') 96 | ds = []; 97 | else 98 | rethrow(ME) 99 | end 100 | end 101 | 102 | if ~isempty(ds) 103 | isGlobal = false; 104 | obj = ds; 105 | location = workspace; 106 | return 107 | end 108 | 109 | % 2) Data Dictionary 110 | % Check data dictionary next, because if a model is linked to a dictionary, 111 | % it no longer refers to the base workspace. 112 | dataDictName = get_param(root, 'DataDictionary'); 113 | if ~isempty(dataDictName) 114 | dataDict = Simulink.data.dictionary.open(dataDictName); 115 | dataSection = getSection(dataDict, 'Design Data'); 116 | try 117 | dataEntry = getEntry(dataSection, name); 118 | catch ME 119 | if strcmp(ME.identifier, 'SLDD:sldd:EntryNotFound') 120 | dataEntry = []; 121 | else 122 | rethrow(ME) 123 | end 124 | end 125 | if ~isempty(dataEntry) 126 | isGlobal = true; 127 | obj = getValue(dataEntry); 128 | location = dataDict; 129 | return 130 | else 131 | isGlobal = false; 132 | obj = []; 133 | location = []; 134 | return 135 | end 136 | 137 | % 3) Base Workspace 138 | else 139 | workspaceData = evalin('base', 'whos'); 140 | idx = ismember({workspaceData.class}, 'Simulink.Signal'); 141 | allDs = workspaceData(idx); 142 | match = strcmp({allDs.name}, name); 143 | if any(match) 144 | ds = allDs(match); 145 | isGlobal = true; 146 | obj = evalin('base', ds.name); 147 | location = 'base'; 148 | end 149 | end 150 | end 151 | end 152 | end -------------------------------------------------------------------------------- /src/subToSimFcn.m: -------------------------------------------------------------------------------- 1 | function subToSimFcn(subsystem, simulinkFcnName, visibility) 2 | % SUBTOSIMFUNC Convert a Subsystem into a Simulink Function. 3 | % 4 | % Inputs: 5 | % subsystem Path of a subsystem to be converted. 6 | % simulinkFcnName Name of the Simulink Function to be created. 7 | % visibility Set function visibility to 'scoped' or 'global'. 8 | % 9 | % Outputs: 10 | % N/A 11 | % 12 | % Example: 13 | % subToSimFunc('Demo_Example/f_Sensor_Trip_1', 'f_Sensor_Trip_i', 'scoped') 14 | 15 | %% Input Validation 16 | % Check that the subsystem model is loaded 17 | try 18 | assert(ischar(subsystem)); 19 | assert(bdIsLoaded(bdroot(subsystem))); 20 | catch 21 | error('Invalid subsystem. Model may not be loaded or name is invalid.'); 22 | end 23 | 24 | % Check that the function name is valid 25 | try 26 | assert(isvarname(simulinkFcnName)); 27 | catch 28 | error('Invalid function name. Use a valid MATLAB variable name.'); 29 | end 30 | 31 | % Check that the function visibility is valid 32 | try 33 | assert(strcmp(visibility, 'scoped') || strcmp(visibility, 'global')); 34 | catch 35 | error('Invalid function visibility. Use scoped/global visibility.'); 36 | end 37 | 38 | %% Add Trigger to Subsystem 39 | % Break library link 40 | set_param(subsystem, 'LinkStatus', 'none'); 41 | 42 | % Adding the trigger block to the subsystem 43 | triggerPath = [subsystem, '/', simulinkFcnName]; 44 | add_block('simulink/Ports & Subsystems/Trigger', triggerPath); 45 | 46 | % Set trigger block parameters 47 | set_param(triggerPath, 'TriggerType', 'function-call'); 48 | try 49 | set_param(triggerPath, 'IsSimulinkFunction', 'on', 'FunctionName', simulinkFcnName); 50 | catch ME 51 | if strcmp(ME.identifier, 'Simulink:Commands:ParamUnknown') 52 | % Version of Simulink is pre-R2014b so doesn't support Simulink Functions 53 | v = ver('Simulink'); 54 | warning(ME.identifier, ['Simulink ' v.Release ' does not support Simulink Functions.']); 55 | else 56 | rethrow(ME) 57 | end 58 | end 59 | try 60 | set_param(triggerPath, 'FunctionVisibility', visibility); 61 | catch ME 62 | if strcmp(ME.identifier, 'Simulink:Commands:ParamUnknown') 63 | % Version of Simulink is pre-R2017b so doesn't support scoping 64 | v = ver('Simulink'); 65 | warning(ME.identifier, ['Simulink ' v.Release ' does not support Simulink Function scope.']); 66 | else 67 | rethrow(ME) 68 | end 69 | end 70 | 71 | %% Set subsystem parameters 72 | set_param(subsystem, 'TreatAsAtomicUnit', 'on'); 73 | 74 | %% Convert Inports to ArgIns 75 | % Create array of all the inports in the subsystem 76 | allInports = find_system(subsystem, 'SearchDepth', 1, 'BlockType', 'Inport'); 77 | 78 | % Get the parameters for all inports in the subsystem 79 | inportParameters = getPortParameters(allInports); 80 | 81 | % Replace inports with argument inputs 82 | replace_block(subsystem, 'SearchDepth', 1, 'BlockType', 'Inport', 'ArgIn', 'noprompt'); 83 | 84 | % Create array of all the argIns in the Simulink Function 85 | allArgIns = find_system(subsystem, 'SearchDepth', 1, 'BlockType', 'ArgIn'); 86 | 87 | % Set the parameters for all the argument inputs 88 | setArgumentParameters(allArgIns, inportParameters); 89 | 90 | %% Convert Outports to ArgOuts 91 | % Create array of all the outports in the subsystem 92 | allOutports = find_system(subsystem, 'SearchDepth', 1, 'BlockType', 'Outport'); 93 | 94 | % Get the parameters for all outports in the subsystem 95 | outportParameters = getPortParameters(allOutports); 96 | 97 | % Replace outports with argument outputs 98 | replace_block(subsystem, 'SearchDepth', 1, 'BlockType', 'Outport', 'ArgOut', 'noprompt'); 99 | 100 | % Create array of all the argOuts for the Simulink Function 101 | allArgOuts = find_system(subsystem, 'SearchDepth', 1, 'BlockType', 'ArgOut'); 102 | 103 | % Set the parameters for all the argument outputs 104 | setArgumentParameters(allArgOuts, outportParameters); 105 | end 106 | 107 | function parameters = getPortParameters(ports) 108 | % getPortParameters Get the parameters for an inport or outport. 109 | % 110 | % Inputs: 111 | % ports Cell array of inports or outports. 112 | % 113 | % Outputs: 114 | % parameters Cell array of parameters including: 115 | % 1) Port 116 | % 2) OutMin 117 | % 3) OutMax 118 | % 4) OutDataTypeStr 119 | % 5) LockScale 120 | % 6) PortDimensions 121 | % 7) ArgumentName 122 | % 123 | % Example: 124 | % parameters = getPortParameters({'System/Subsystem/Inport1'}) 125 | % 126 | % ans = 127 | % 1x7 cell array 128 | % {'1'} {'[]'} {'[]'} {'boolean'} {'off'} {'on'} {'Inport1'} 129 | 130 | %% Get the port parameters 131 | % Init array of parameters for the ports 132 | parameters = cell(length(ports), 7); 133 | % Loop through each port 134 | for port = 1:length(ports) 135 | % Get the port name by splitting the pathname by the backslash 136 | splitPortPath = split(ports{port}, '/'); 137 | % The port name is the last index of splitPortPath 138 | portName = splitPortPath{end}; 139 | % Get the port number 140 | parameters{port, 1} = get_param(ports{port}, 'Port'); 141 | % Get the port minimum output 142 | parameters{port, 2} = get_param(ports{port}, 'OutMin'); 143 | % Get the port maximum output 144 | parameters{port, 3} = get_param(ports{port}, 'OutMax'); 145 | % Get the port data type 146 | parameters{port, 4} = get_param(ports{port}, 'OutDataTypeStr'); 147 | % If data type is set to inherit, set to double by default 148 | try 149 | assert(not(strcmp(parameters{port, 4}, 'Inherit: auto'))); 150 | catch 151 | disp([portName, ... 152 | ' data type was set to ''Inherit: auto''', ... 153 | ' - setting to ''double''...']); 154 | parameters{port, 4} = 'double'; 155 | end 156 | % Get the port lock scale 157 | parameters{port, 5} = get_param(ports{port}, 'LockScale'); 158 | % Get the port dimension 159 | parameters{port, 6} = get_param(ports{port}, 'PortDimensions'); 160 | % If port dimension is set to inherit, set to 1 by default 161 | try 162 | assert(not(strcmp(parameters{port, 6}, '-1'))) 163 | catch 164 | disp([portName, ... 165 | ' dimension was set to ''-1''', ... 166 | ' - setting to ''1''...']); 167 | parameters{port, 6} = '1'; 168 | end 169 | % Remove spaces from port name to create a valid variable name 170 | parameters{port, 7} = genvarname(portName); 171 | end 172 | end 173 | 174 | function setArgumentParameters(arguments, parameters) 175 | % setArgumentParameters Set argIn or ArgOut parameters. 176 | % 177 | % Inputs: 178 | % arguments Cell array of argIns or argOuts. 179 | % parameters Cell array of parameters for each argument. 180 | % 181 | % Outputs: 182 | % N/A 183 | % 184 | % Example: 185 | % setArgumentParameters({'System/Subsystem/argIn1'}, ... 186 | % {'1', '[]', '[]', 'boolean', 'off', 'on', 'Inport1'}) 187 | 188 | %% Set the argument parameters 189 | % Loop through each argument 190 | for arg = 1:length(arguments) 191 | % Set the parameters for each argument 192 | set_param(arguments{arg}, 'Port', parameters{arg, 1}, ... 193 | 'OutMin', parameters{arg, 2}, ... 194 | 'OutMax', parameters{arg, 3}, ... 195 | 'OutDataTypeStr', parameters{arg, 4}, ... 196 | 'LockScale', parameters{arg, 5}, ... 197 | 'PortDimensions', parameters{arg, 6}, ... 198 | 'ArgumentName', parameters{arg, 7}); 199 | end 200 | end -------------------------------------------------------------------------------- /src/sl_customization.m: -------------------------------------------------------------------------------- 1 | %% Register custom menu function to beginning of Simulink Editor's context menu 2 | function sl_customization(cm) 3 | cm.addCustomMenuFcn('Simulink:PreContextMenu', @getSLModuleTool); 4 | end 5 | 6 | %% Define custom menu function: Changing Scope 7 | function schemaFcns = getSLModuleTool(callbackInfo) 8 | schemaFcns = {}; 9 | selection = find_system(gcs, 'Type', 'block', 'Selected', 'on'); 10 | selectedFcns = isSimulinkFcn(selection); 11 | 12 | % Check if the Simulink version supports Simulink Functions 13 | v = ver('Simulink'); 14 | if str2double(v.Version) > 8.3 % Greater than 2014a 15 | verOK = true; 16 | else 17 | verOK = false; 18 | end 19 | 20 | if isempty(gcbs) 21 | schemaFcns{end+1} = @FcnCreatorSchema; 22 | schemaFcns{end+1} = @GuidelineSchema; 23 | schemaFcns{end+1} = @InterfaceSchema; 24 | elseif verOK && isSubsystem(gcbs) && ~isSimulinkFcn(gcbs) && ~isempty(gcbs) 25 | schemaFcns{end+1} = @ConvToSimFcnSchema; 26 | elseif any(selectedFcns) && ~isempty(gcbs) 27 | schemaFcns{end+1} = @ChangeFcnScopeSchema; 28 | schemaFcns{end+1} = @FcnCreatorLocalSchema; 29 | end 30 | end 31 | 32 | %% Define action: Convert Subsystem to Simulink Function 33 | function schema = ConvToSimFcnSchema(callbackInfo) 34 | schema = sl_container_schema; 35 | schema.label = 'Convert Subsystem'; 36 | schema.ChildrenFcns = {@toScopedSimFcn, @toGlobalSimFcn}; 37 | end 38 | 39 | function schema = toScopedSimFcn(callbackInfo) 40 | schema = sl_action_schema; 41 | schema.label = 'To Scoped Simulink Function'; 42 | schema.userdata = 'toScopedSimFcn'; 43 | schema.callback = @toScopedSimFcnCallback; 44 | end 45 | 46 | function toScopedSimFcnCallback(callbackInfo) 47 | simulinkFcnName = reqSimFcnName(); 48 | subsystem = gcbs; 49 | subToSimFcn(subsystem{1}, simulinkFcnName, 'scoped'); 50 | end 51 | 52 | function schema = toGlobalSimFcn(callbackInfo) 53 | schema = sl_action_schema; 54 | schema.label = 'To Global Simulink Function'; 55 | schema.userdata = 'toGlobalSimFcn'; 56 | schema.callback = @toGlobalSimFcnCallback; 57 | end 58 | 59 | function toGlobalSimFcnCallback(callbackInfo) 60 | simulinkFcnName = reqSimFcnName(); 61 | subsystem = gcbs; 62 | subToSimFcn(subsystem{1}, simulinkFcnName, 'global'); 63 | end 64 | 65 | %% Define action: Create Function Caller for Local Function 66 | function schema = FcnCreatorLocalSchema(callbackInfo) 67 | schema = sl_action_schema; 68 | schema.label = 'Create Function Caller'; 69 | schema.userdata = 'createFcnCallerLocal'; 70 | schema.callback = @createFcnCallerLocalCallback; 71 | end 72 | 73 | function createFcnCallerLocalCallback(callbackInfo) 74 | createFcnCallerLocal(gcbs); 75 | end 76 | 77 | %% Define action: Create Function Caller for Any Function 78 | function schema = FcnCreatorSchema(callbackInfo) 79 | schema = sl_action_schema; 80 | schema.label = 'Call Function...'; 81 | schema.userdata = 'createFcnCaller'; 82 | schema.callback = @FcnCreatorCallback; 83 | end 84 | 85 | function FcnCreatorCallback(callbackInfo) 86 | sys = gcs; % Save in case it changes 87 | 88 | % Position the caller in the center of the model 89 | bounds = bounds_of_sim_objects(find_system(sys, 'SearchDepth', 1)); 90 | x = ((bounds(3)-bounds(1))/2) + bounds(1); 91 | y = ((bounds(4)-bounds(2))/2) + bounds(2); 92 | 93 | [fcns, proto] = getCallableFunctions(sys); 94 | idx = functionGUI(fcns, proto); % let user make selection 95 | f = char(fcns(idx)); 96 | p = char(proto(idx)); 97 | 98 | if ~isempty(f) 99 | % Load model is necessary 100 | i = regexp(f, '/', 'once'); 101 | mdl = f(1:i-1); 102 | loaded = bdIsLoaded(mdl); 103 | if ~loaded 104 | load_system(mdl); 105 | end 106 | 107 | createFcnCaller(sys, f, 'prototype', p, 'position', [x, y]); 108 | 109 | % Close model if necessary 110 | if ~loaded 111 | close_system(mdl, 0); 112 | end 113 | end 114 | end 115 | 116 | %% Define action: Change Scope 117 | function schema = ChangeFcnScopeSchema(callbackInfo) 118 | schema = sl_container_schema; 119 | schema.label = 'Change Function Scope'; 120 | schema.userdata = 'changeFcnScope'; 121 | 122 | % Get the functions that are selected and determine their scope 123 | selection = find_system(gcs, 'Type', 'block', 'Selected', 'on'); 124 | selectedFcns = isSimulinkFcn(selection); 125 | fcns = {}; 126 | for i = 1:length(selectedFcns) 127 | if selectedFcns(i) 128 | fcns{end+1,1} = selection{i}; 129 | end 130 | end 131 | scopes = getFcnScope(fcns); 132 | 133 | % Show conversion operations depending on scope 134 | anyGlobal = any(contains2(scopes, char(Scope.Global))); 135 | anyScoped = any(contains2(scopes, char(Scope.Scoped))); 136 | anyLocal = any(contains2(scopes, char(Scope.Local))); 137 | if anyScoped || anyLocal 138 | schema.childrenFcns{end+1} = @GlobalFcnSchema; 139 | end 140 | if anyGlobal || anyLocal 141 | schema.childrenFcns{end+1} = @ScopedFcnSchema; 142 | end 143 | if anyGlobal || anyScoped || anyLocal 144 | schema.childrenFcns{end+1} = @LocalFcnSchema; 145 | end 146 | 147 | % If there are functions selected, but the functions don't have a scope 148 | if isempty(schema.childrenFcns) 149 | schema.state = 'Disabled'; 150 | end 151 | 152 | garbageCollection(); 153 | end 154 | 155 | %% Define action: Convert to Global 156 | function schema = GlobalFcnSchema(callbackInfo) 157 | schema = sl_action_schema; 158 | schema.label = 'To Global Function'; 159 | schema.userdata = 'convertToGlobalFcn'; 160 | schema.callback = @convertToGlobalFcnCallback; 161 | end 162 | 163 | function convertToGlobalFcnCallback(callbackInfo) 164 | setFcnScope(gcbs, Scope.Global, ''); 165 | end 166 | 167 | %% Define action: Convert to Scoped 168 | function schema = ScopedFcnSchema(callbackInfo) 169 | schema = sl_action_schema; 170 | schema.label = 'To Scoped Exported Function'; 171 | schema.userdata = 'convertToScopedFcn'; 172 | schema.callback = @convertToScopedFcnCallback; 173 | end 174 | 175 | function convertToScopedFcnCallback(callbackInfo) 176 | setFcnScope(gcbs, Scope.Scoped, ''); 177 | end 178 | 179 | %% Define action: Convert to Local 180 | function schema = LocalFcnSchema(callbackInfo) 181 | schema = sl_container_schema; 182 | schema.label = 'To Scoped Local Function'; 183 | schema.userdata = 'convertToLocalFcn'; 184 | schema.childrenFcns = {@LocalFcnNewSchema, @LocalFcnExistSchema}; 185 | end 186 | 187 | function schema = LocalFcnNewSchema(callbackInfo) 188 | schema = sl_action_schema; 189 | schema.label = 'In New Subsystem'; 190 | schema.userdata = 'convertToLocalFcnNew'; 191 | schema.callback = @convertToLocalFcnNewCallback; 192 | end 193 | 194 | function convertToLocalFcnNewCallback(callbackInfo) 195 | setFcnScope(gcbs, Scope.Local, ''); 196 | end 197 | 198 | function schema = LocalFcnExistSchema(callbackInfo) 199 | schema = sl_action_schema; 200 | schema.label = 'In Existing Subsystem'; 201 | schema.userdata = 'convertToLocalFcnExist'; 202 | schema.callback = @convertToLocalFcnExistCallback; 203 | end 204 | 205 | function convertToLocalFcnExistCallback(callbackInfo) 206 | subsystem = subsystemGUI(bdroot); 207 | if ~isempty(subsystem) 208 | setFcnScope(gcbs, Scope.Local, subsystem); 209 | end 210 | end 211 | 212 | %% Define action: Check Guidelines 213 | function schema = GuidelineSchema(callbackInfo) 214 | schema = sl_action_schema; 215 | schema.label = 'Check Guidelines...'; 216 | schema.userdata = 'checkGuidelines'; 217 | schema.callback = @CheckGuidelines; 218 | end 219 | 220 | function CheckGuidelines(callbackInfo) 221 | sys = gcs; 222 | guidelines = guidelineSelector; 223 | if guidelines(1) 224 | [blocks, locations] = guideline0001(sys); 225 | fprintf('Guideline 1 ''Simulink Function Placement'' violations: '); 226 | if isempty(blocks) 227 | fprintf('None\n'); 228 | else 229 | fprintf('\n'); 230 | for i = 1:length(blocks) 231 | fprintf('\t%s can be moved to %s\n', replaceNewline(blocks{i}), replaceNewline(locations{i})); 232 | end 233 | fprintf('\n'); 234 | end 235 | end 236 | if guidelines(2) 237 | blocks = guideline0002(sys); 238 | fprintf('Guideline 2 ''Simulink Function Visibility'' violations: '); 239 | if isempty(blocks) 240 | fprintf('None\n'); 241 | else 242 | fprintf('\n'); 243 | for i = 1:length(blocks) 244 | fprintf('\t%s\n', replaceNewline(blocks{i})); 245 | end 246 | fprintf('\n'); 247 | end 248 | end 249 | if guidelines(3) 250 | [blocks, shadows] = guideline0003(sys); 251 | fprintf('Guideline 3 ''Simulink Function Shadowing'' violations: '); 252 | if isempty(blocks) 253 | fprintf('None\n'); 254 | else 255 | fprintf('\n'); 256 | for i = 1:length(blocks) 257 | if ~isempty(shadows{i}) 258 | fprintf('\t%s is shadowed by:\n\t\t%s\n', replaceNewline(blocks{i}), strjoin(replaceNewline(shadows{i}), '\n\t\t')); 259 | end 260 | fprintf('\n'); 261 | end 262 | end 263 | end 264 | if guidelines(4) 265 | blocks = guideline0004(sys); 266 | fprintf('Guideline 4 ''Use of Base Workspace'' violations: '); 267 | if isempty(blocks) 268 | fprintf('None\n'); 269 | else 270 | fprintf('\n'); 271 | for i = 1:length(blocks) 272 | fprintf('\t%s\n', replaceNewline(blocks{i})); 273 | end 274 | fprintf('\n'); 275 | end 276 | end 277 | 278 | garbageCollection(); 279 | end 280 | 281 | %% Define menu: Model Interface 282 | function schema = InterfaceSchema(callbackInfo) 283 | schema = sl_container_schema; 284 | schema.label = 'Interface'; 285 | schema.ChildrenFcns = {@ModelInterfaceSchema, @PrintInterfaceSchema, @DeleteInterface, @PrintDependencies}; 286 | end 287 | 288 | function schema = ModelInterfaceSchema(callbackInfo) 289 | schema = sl_action_schema; 290 | schema.label = 'Show Interface'; 291 | schema.callback = @showInterfaceCallback; 292 | end 293 | 294 | function showInterfaceCallback(callbackInfo) 295 | 296 | garbageCollection(); 297 | 298 | sys = bdroot(gcs); 299 | objName = [sys '_InterfaceObject']; 300 | eval(['global ' objName ';']); 301 | 302 | if interface_exists(sys) 303 | eval([objName ' = load_interface(sys);']); 304 | answer = questdlg('An interface already exists. Do you wish to replace it?', 'Interface Exists'); 305 | if strcmp(answer, 'Yes') 306 | % Delete old representation 307 | eval([objName '.delete();']) 308 | 309 | % Create new interface 310 | eval([objName ' = Interface(sys);']); 311 | eval([objName ' = ' objName '.model();']); 312 | end 313 | else 314 | eval([objName ' = Interface(sys);']); 315 | eval([objName ' = ' objName '.model;']); 316 | end 317 | eval([objName '.saveInterfaceMat;']); 318 | end 319 | 320 | %% Define menu: Print Interface 321 | function schema = PrintInterfaceSchema(callbackInfo) 322 | schema = sl_action_schema; 323 | schema.label = 'Print Interface'; 324 | schema.callback = @printInterfaceCallback; 325 | end 326 | 327 | function printInterfaceCallback(callbackInfo) 328 | sys = bdroot(gcs); 329 | objName = [sys '_InterfaceObject']; 330 | if interface_exists(sys) 331 | eval([objName ' = load_interface(sys);']); 332 | else 333 | eval([objName ' = Interface(sys);']); 334 | end 335 | eval([objName '.print();']); 336 | 337 | garbageCollection(); 338 | end 339 | 340 | %% Delete Interface 341 | function schema = DeleteInterface(callbackInfo) 342 | schema = sl_action_schema; 343 | schema.label = 'Delete Interface'; 344 | schema.userdata = 'DeleteInterface'; 345 | schema.callback = @deleteInterfaceCallback; 346 | 347 | % Hide the delete option when there is nothing to delete 348 | sys = bdroot(gcs); 349 | if interface_exists(sys) 350 | schema.state = 'Enabled'; 351 | else 352 | schema.state = 'Disabled'; 353 | end 354 | end 355 | 356 | function deleteInterfaceCallback(callbackInfo) 357 | sys = bdroot(gcs); 358 | objName = [sys '_InterfaceObject']; 359 | eval(['global ' objName ';']); 360 | 361 | eval([objName ' = load_interface(sys);']); 362 | 363 | eval([objName ' = delete(' objName ');']); 364 | eval(['clear global ' objName ';']); 365 | 366 | garbageCollection(); 367 | end 368 | 369 | function filename = get_interface_filename(sys) 370 | syspath = get_param(sys, 'FileName'); 371 | [path, name, ~] = fileparts(syspath); 372 | ext = '.mat'; 373 | filename = fullfile(path, [name '_Interface' ext]); 374 | end 375 | 376 | function e = interface_exists(sys) 377 | % INTERFACE_EXISTS Determine if there exists an interface for a model. 378 | objName = [sys '_InterfaceObject']; 379 | eval(['global ' objName ';']); 380 | eval(['objEmpty = isempty(' objName ');']); 381 | 382 | filename = get_interface_filename(sys); 383 | 384 | if objEmpty 385 | if isfile(filename) 386 | e = true; 387 | else 388 | e = false; 389 | end 390 | else 391 | e = true; 392 | end 393 | end 394 | 395 | function obj = load_interface(sys) 396 | filename = get_interface_filename(sys); 397 | if interface_exists(sys) 398 | obj = load(filename); 399 | obj = obj.obj; 400 | end 401 | end 402 | 403 | %% Print dependencies 404 | function schema = PrintDependencies(callbackInfo) 405 | schema = sl_action_schema; 406 | schema.label = 'Print Dependencies'; 407 | schema.userdata = 'PrintDependencies'; 408 | schema.callback = @printDependenciesCallback; 409 | end 410 | 411 | function printDependenciesCallback(callbackInfo) 412 | sys = bdroot(gcs); 413 | dependencies(sys); 414 | garbageCollection(); 415 | end 416 | 417 | %% Garbage collection for objects 418 | function garbageCollection() 419 | globals = who('global'); 420 | 421 | suffix = 'InterfaceObject'; 422 | suffixLen = length(suffix) + 1; 423 | 424 | sysAll = cellfun(@(x) x(1:end-suffixLen), globals, 'un', 0); 425 | allSysOpen = find_system('SearchDepth', 0); 426 | globalHasSysOpen = ismember(sysAll, allSysOpen); 427 | 428 | for i = 1:length(globals) 429 | isInterfaceName = ~isempty(strfind(globals{i}, suffix)); 430 | if isInterfaceName 431 | eval(['global ' globals{i} ';']) % Get this object 432 | if ~globalHasSysOpen(i) % Has no associated model open 433 | eval(['x =~ isempty(' globals{i} ');']); 434 | if x 435 | eval(['clearvars -global ' globals{i} ';']); 436 | %eval([globals{i} '.delete;']); 437 | end 438 | else % There is a system open that matches the object name 439 | % A different instance of the same model could be open, so we 440 | % check that the model handles match 441 | sameHdl = false; 442 | try 443 | eval(['objHdl = ' globals{i} '.getHandle;']); 444 | sysHdl = get_param(sysAll{i}, 'Handle'); 445 | sameHdl = (objHdl == sysHdl); 446 | catch 447 | continue 448 | end 449 | 450 | if ~sameHdl %|| ~ishandle(objHdl 451 | eval(['clearvars -global ' globals{i} ';']); 452 | %else 453 | %eval([globals{i} '.delete;']); 454 | end 455 | end 456 | end 457 | end 458 | end 459 | -------------------------------------------------------------------------------- /src/Interface/InterfaceItem.m: -------------------------------------------------------------------------------- 1 | classdef InterfaceItem 2 | properties 3 | BlockType % BlockType. 4 | InterfaceType % Input, Output, or Export. 5 | Handle % Handle of the item that is on the interface. 6 | Name % Name. 7 | Fullpath % Fullpath. 8 | DataType % Output or input types. 9 | Dimensions % Struct of Inport and Outport dimensions. 10 | SampleTime % SameTime. 11 | 12 | % Visual Representation 13 | InterfaceHandle % If the block is represented on the interface by another 14 | % block, this is the handle to that block (not 15 | % applicable for Inports and Outports). 16 | InterfacePath % Fullpath. 17 | GroundHandle % Handle(s) of Ground blocks (or Goto for ports). 18 | GroundPath % Fullpath. 19 | TerminatorHandle % Handle(s) of Terminators blocks (or From for ports). 20 | TerminatorPath % Fullpath. 21 | end 22 | methods (Access = public) 23 | function obj = InterfaceItem(handle) 24 | if nargin == 1 25 | % Perform checks before creating an InterfaceItem 26 | [valid, ~] = itemTypeCheck(handle); 27 | if ~valid 28 | error(['Block ''' get_param(obj.Handle, 'Name') ''' is not a valid InterfaceItem.']); 29 | end 30 | 31 | obj.Handle = inputToNumeric(handle); 32 | obj = autoGetData(obj); 33 | elseif nargin > 1 34 | error('Too many inputs provided.'); 35 | else 36 | error('Not enough inputs provided.'); 37 | end 38 | end 39 | function b = eq(obj1, obj2) 40 | % EQ Check if two InterfaceItems are equal. 41 | % 42 | % Inputs: 43 | % obj1 InterfaceItem. 44 | % obj2 InterfaceItem. 45 | % 46 | % Outputs: 47 | % b Whether or not inputs are equal (1), or not (0). 48 | 49 | if obj1.Handle == obj2.Handle 50 | b = true; 51 | else 52 | b = false; 53 | end 54 | end 55 | function print(obj) 56 | % PRINT Print the item to the Command Window. 57 | % 58 | % Inputs: 59 | % obj InterfaceItem. 60 | % 61 | % Outputs: 62 | % N/A 63 | 64 | % TODO: Currently assumes one sample time. There can be 65 | % multiple times 66 | 67 | if isSimulinkFcn(obj.Handle) 68 | argsIn = find_system(obj.Handle, 'SearchDepth', 1, 'BlockType', 'ArgIn'); 69 | argsOut = find_system(obj.Handle, 'SearchDepth', 1, 'BlockType', 'ArgOut'); 70 | nIn = length(argsIn); 71 | nOut = length(argsOut); 72 | else 73 | handles = get_param(obj.Handle, 'PortHandles'); 74 | nIn = length(handles.Inport); 75 | nOut = length(handles.Outport); 76 | end 77 | 78 | oneInport = (nIn == 1); 79 | oneOutport = (nOut == 1); 80 | 81 | dt = obj.DataType; 82 | dim = obj.Dimensions; 83 | time = obj.SampleTime; 84 | 85 | if strcmp(obj.BlockType, 'ModelReference') || isLibraryLink(obj.Handle) 86 | if isempty(time) 87 | time_i = 'N/A'; 88 | elseif size(time,1) > 1 || size(time,2) > 1 % Non-scalar 89 | time_i = char(strjoin(string(time), ', ')); 90 | time_i = ['[' time_i ']']; 91 | else 92 | time_i = time; 93 | end 94 | 95 | if isnumeric(time_i) && rem(abs(time_i), 1) == 0 96 | time_format = '%i'; 97 | elseif ischar(time_i) 98 | time_format = '%s'; 99 | else 100 | time_format = '%.4f'; 101 | end 102 | fprintf(['%s, N/A, N/A, ' time_format '\n'], obj.Fullpath, time_i); 103 | return 104 | end 105 | 106 | % Only 1 port 107 | if xor(oneInport, oneOutport) 108 | 109 | if oneInport 110 | dt = dt.Inport; 111 | dim = dim.Inport; 112 | else 113 | dt = dt.Outport; 114 | dim = dim.Outport; 115 | end 116 | 117 | % Account for data that is empty or an array 118 | if isempty(dt) 119 | dt = 'N/A'; 120 | end 121 | 122 | if isempty(dim) 123 | dim = 'N/A'; 124 | elseif size(dim,1) > 1 || size(dim,2) > 1 % Non-scalar 125 | dim = ['[' regexprep(num2str(dim), ' +', ', ') ']']; 126 | end 127 | 128 | if isempty(time) 129 | time_i = 'N/A'; 130 | elseif size(time,1) > 1 || size(time,2) > 1 % Non-scalar 131 | time_i = char(strjoin(string(time), ', ')); 132 | time_i = ['[' time_i ']']; 133 | else 134 | time_i = time; 135 | end 136 | 137 | % Account for different formatting 138 | dim_format = '%i'; 139 | if ischar(dim) 140 | dim_format = '%s'; 141 | end 142 | 143 | if isnumeric(time_i) && rem(abs(time_i), 1) == 0 144 | time_format = '%i'; 145 | elseif ischar(time_i) 146 | time_format = '%s'; 147 | else 148 | time_format = '%.4f'; 149 | end 150 | 151 | % Print 152 | fprintf(['%s, %s, ' dim_format ', ' time_format '\n'], obj.Fullpath, dt, dim, time_i); 153 | 154 | % Multiple ports 155 | else 156 | fprintf('%s \n', obj.Fullpath); 157 | 158 | if nIn > 0 159 | fprintf('\t\tIn: '); 160 | for i = 1:nIn 161 | % Account for data that is empty or in an array 162 | if isempty(dt.Inport) 163 | dt_i = 'N/A'; 164 | else 165 | dt_i = dt.Inport(i,:); 166 | end 167 | 168 | if isempty(dim.Inport) 169 | dim_i = 'N/A'; 170 | else 171 | dim_i = dim.Inport(i); 172 | end 173 | 174 | if isempty(time) 175 | time_i = 'N/A'; 176 | elseif size(time,1) > 1 || size(time,2) > 1 % Non-scalar 177 | time_i = char(strjoin(string(time), ', ')); 178 | time_i = ['[' time_i ']']; 179 | else 180 | time_i = time; 181 | end 182 | 183 | % Separate from previous port 184 | if i ~= 1 185 | fprintf('; '); 186 | end 187 | if nIn > 4 && i > 1 188 | fprintf('\n\t\t '); 189 | end 190 | 191 | % Account for different formatting 192 | if ischar(dim_i) 193 | dim_format = '%s'; 194 | else 195 | dim_format = '%i'; 196 | end 197 | 198 | time_format = '%.4f'; 199 | if isnumeric(time_i) && rem(abs(time_i), 1) == 0 200 | time_format = '%i'; 201 | elseif ischar(time_i) 202 | time_format = '%s'; 203 | else 204 | time_format = '%.4f'; 205 | end 206 | 207 | % Print 208 | fprintf(['%s, ' dim_format ', ' time_format], dt_i, dim_i, time_i); 209 | end 210 | end 211 | 212 | if nOut > 0 213 | if nIn > 0 214 | fprintf('\n'); 215 | end 216 | fprintf('\t\tOut: '); 217 | for i = 1:nOut 218 | % Account for data that is empty or in an array 219 | if isempty(dt.Outport) 220 | dt_i = 'N/A'; 221 | else 222 | dt_i = dt.Outport(i,:); 223 | end 224 | 225 | if isempty(dim.Outport) 226 | dim_i = 'N/A'; 227 | else 228 | dim_i = dim.Outport(i); 229 | end 230 | 231 | if isempty(time) 232 | time_i = 'N/A'; 233 | elseif size(time,1) > 1 || size(time,2) > 1 % Non-scalar 234 | time_i = char(strjoin(string(time), ', ')); 235 | time_i = ['[' time_i ']']; 236 | else 237 | time_i = time; 238 | end 239 | 240 | % Separate from previous port 241 | if i ~= 1 242 | fprintf('; '); 243 | end 244 | if nIn > 4 && i > 1 245 | fprintf('\n\t\t '); 246 | end 247 | 248 | % Account for different formatting 249 | if ischar(dim_i) 250 | dim_format = '%s'; 251 | else 252 | dim_format = '%i'; 253 | end 254 | 255 | if isnumeric(time_i) && rem(abs(time_i), 1) == 0 256 | time_format = '%i'; 257 | elseif ischar(time_i) 258 | time_format = '%s'; 259 | else 260 | time_format = '%.4f'; 261 | end 262 | 263 | % Print 264 | fprintf(['%s, ' dim_format ', ' time_format], dt_i, dim_i, time_i); 265 | end 266 | fprintf('\n'); 267 | end 268 | end 269 | end 270 | function obj = deleteFromModel(obj) 271 | % DELETEFROMMODEL Delete the representation of the item in the 272 | % model. 273 | obj = obj.updateHandle; 274 | if any2(strcmp(obj.BlockType, {'Inport', 'Outport'})) 275 | obj = deleteGrndTrm(obj); 276 | % Move inport/outport back 277 | try 278 | moveToConnectedPort(obj.InterfaceHandle, 30); 279 | redraw_block_lines(obj.InterfaceHandle, 'AutoRouting', 'smart'); 280 | catch ME 281 | if ~strcmp(ME.identifier, 'Simulink:Commands:InvSimulinkObjHandle') % The model was closed 282 | rethrow(ME) 283 | end 284 | end 285 | else 286 | try 287 | delete(obj.InterfaceHandle); 288 | obj = deleteGrndTrm(obj); 289 | catch ME 290 | if ~strcmp(ME.identifier, 'MATLAB:hg:udd_interface:CannotDelete') % Already deleted 291 | rethrow(ME) 292 | end 293 | end 294 | end 295 | obj.InterfaceHandle = []; 296 | obj.InterfacePath = []; 297 | end 298 | function obj = updateHandle(obj) 299 | % UPDATEHANDLE Re-populate the handle properties. 300 | % Try getting the handles according to the fullpath. If the 301 | % interface has changed (e.g., inport was deleted), the handle will 302 | % not be found. 303 | try 304 | obj.Handle = get_param(obj.Fullpath, 'Handle'); 305 | catch 306 | obj.Handle = []; 307 | end 308 | 309 | try 310 | obj.InterfaceHandle = get_param(obj.InterfacePath, 'Handle'); 311 | catch 312 | obj.InterfaceHandle = []; 313 | end 314 | 315 | try 316 | for i = 1:length(obj.GroundHandle) 317 | if iscell(obj.GroundPath) 318 | g = obj.GroundPath{i}; 319 | else 320 | g = obj.GroundPath; 321 | end 322 | g = get_param(g, 'Handle'); 323 | obj.GroundHandle(i) = g; 324 | end 325 | catch 326 | obj.GroundHandle = []; 327 | end 328 | 329 | try 330 | for j = 1:length(obj.TerminatorHandle) 331 | if iscell(obj.TerminatorPath) 332 | t = obj.TerminatorPath{j}; 333 | else 334 | t = obj.TerminatorPath; 335 | end 336 | t = get_param(t, 'Handle'); 337 | obj.TerminatorHandle(j) = t; 338 | end 339 | catch 340 | obj.TerminatorHandle = []; 341 | end 342 | end 343 | end 344 | methods (Access = private) 345 | function obj = autoGetData(obj) 346 | % AUTOGETDATA Automatically populate the item's fields based on the model. 347 | % 348 | % Inputs: 349 | % obj InterfaceItem. 350 | % 351 | % Outputs: 352 | % 353 | % obj InterfaceItem. 354 | 355 | % BLOCKTYPE 356 | obj.BlockType = get_param(obj.Handle, 'BlockType'); 357 | 358 | % INTERFACETYPE 359 | [~, obj.InterfaceType] = itemTypeCheck(obj.Handle); 360 | 361 | % NAME 362 | obj.Name = replaceNewline(get_param(obj.Handle, 'Name')); 363 | 364 | % FULLPATH 365 | obj.Fullpath = replaceNewline(getfullname(obj.Handle)); 366 | 367 | % DATATYPE 368 | obj.DataType = getDataType_MJ(obj.Handle); 369 | 370 | % DIMENSIONS 371 | obj.Dimensions = getDimensions(obj.Handle); 372 | 373 | % SAMPLE TIME 374 | obj.SampleTime = getSampleTime(obj.Handle); 375 | 376 | % INTERFACEHANDLE, INERFACEPATH, ETC. 377 | % Added when the interface is modelled only. 378 | end 379 | function obj = deleteGrndTrm(obj) 380 | % DELETEGRNDTRM Delete the ground and terminator elements with their 381 | % lines. 382 | for i = 1:length(obj.GroundHandle) 383 | g = obj.GroundHandle(i); 384 | if ishandle(g) 385 | if strcmp(obj.BlockType, 'Outport') 386 | goto2Line(bdroot(obj.Fullpath), obj.GroundHandle); 387 | else 388 | lines = get_param(g, 'LineHandles'); 389 | delete(lines.Outport); 390 | delete(g); 391 | end 392 | end 393 | end 394 | obj.GroundHandle = []; 395 | obj.GroundPath = []; 396 | 397 | for j = 1:length(obj.TerminatorHandle) 398 | t = obj.TerminatorHandle(j); 399 | if ishandle(t) 400 | if strcmp(obj.BlockType, 'Inport') 401 | goto2Line(bdroot(obj.Fullpath), obj.TerminatorHandle); 402 | else 403 | lines = get_param(t, 'LineHandles'); 404 | delete(lines.Inport); 405 | delete(t); 406 | end 407 | end 408 | end 409 | obj.TerminatorHandle = []; 410 | obj.TerminatorPath = []; 411 | 412 | end 413 | end 414 | end 415 | function [valid, type] = itemTypeCheck(handle) 416 | % ITEMTYPECHECK Check if the item is one of the supported BlockTypes. Return the 417 | % InterfaceType. 418 | % 419 | % Inputs: 420 | % handle Handle to a block. 421 | % 422 | % Outputs: 423 | % valid Whether or not it is a supported InterfaceItem block. 424 | % type 'Input', 'Output', 'Export' 425 | 426 | blocktype = get_param(handle, 'BlockType'); 427 | in = {'Inport', 'FromFile', 'FromWorkspace', 'FromSpreadsheet', 'DataStoreRead'}; 428 | out = {'Outport', 'ToFile', 'ToWorkspace', 'DataStoreWrite'}; 429 | 430 | if isempty(blocktype) 431 | type = ''; 432 | valid = false; 433 | return 434 | end 435 | 436 | if any2(find(strcmp(in, blocktype))) 437 | type = 'Input'; 438 | valid = true; 439 | elseif any2(find(strcmp(out, blocktype))) 440 | type = 'Output'; 441 | valid = true; 442 | elseif isSimulinkFcn(handle) 443 | type = 'Export'; 444 | valid = true; 445 | else 446 | type = ''; 447 | valid = false; 448 | end 449 | end -------------------------------------------------------------------------------- /doc/tex/SimulinkModule_UserGuide.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | %%%%%%%%%%%%%%%%%%%%%%%%% 4 | % Packages & Macros 5 | %%%%%%%%%%%%%%%%%%%%%%%%% 6 | 7 | % For including graphics 8 | \usepackage{graphicx} 9 | 10 | % For title page 11 | \usepackage{datetime} 12 | \newdateformat{monthyeardate}{\monthname[\THEMONTH] \THEYEAR} 13 | 14 | % For supporting linking 15 | \usepackage{hyperref} 16 | \hypersetup{colorlinks,urlcolor=blue,linkcolor=blue} 17 | 18 | % For supporting subfigure captions 19 | \usepackage{subcaption} 20 | 21 | % For making text listings (Figure 7 and 8) 22 | \usepackage{listings} 23 | 24 | % For string comparison in macros 25 | \usepackage{etoolbox} 26 | 27 | % For table colouring (in command line tables) 28 | %\usepackage{colortbl} 29 | 30 | %%%%%%%%%%%%%%%%%%%%%%%%% 31 | % Tool-Specific Macros 32 | %%%%%%%%%%%%%%%%%%%%%%%%% 33 | \input{macros} 34 | 35 | \newcommand{\ToolName}{Simulink Module Tool\@\xspace} 36 | 37 | \newcommand{\menu}[1]{% 38 | \ifstrequal{#1}{1}{Call Function}{}% 39 | \ifstrequal{#1}{2}{Create Function Caller}{}% 40 | \ifstrequal{#1}{3}{Change Function Scope}{}% 41 | \ifstrequal{#1}{4}{Check Guidelines}{}% 42 | \ifstrequal{#1}{5}{Show Interface}{}% 43 | \ifstrequal{#1}{6}{Print Interface}{}% 44 | \ifstrequal{#1}{7}{Print Dependencies}{}% 45 | \ifstrequal{#1}{8}{Delete Interface}{}% 46 | \ifstrequal{#1}{9}{Convert Subsystem}{}% 47 | } 48 | 49 | \newcommand{\func}[1]{% 50 | \ifthenelse{\equal{#1}{1}}{CreateFcnCallerLocal}{}% 51 | \ifthenelse{\equal{#1}{2}}{CreateFcnCaller}{}% 52 | \ifthenelse{\equal{#1}{3}}{setFcnScope}{}% 53 | \ifthenelse{\equal{#1}{4}}{?}{}% 54 | \ifthenelse{\equal{#1}{5}}{?}{}% 55 | \ifthenelse{\equal{#1}{6}}{?}{}% 56 | } 57 | 58 | \newcommand{\demoName}{\cmd{Demo}\@\xspace} 59 | 60 | %%%%%%%%%%%%%%%%%%%%%%%%% 61 | % Document 62 | %%%%%%%%%%%%%%%%%%%%%%%%% 63 | 64 | \begin{document} 65 | 66 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 67 | % Title Page 68 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 69 | \title{\ToolName} 70 | \date{\monthyeardate\today} 71 | \maketitle 72 | \vfill 73 | 74 | \begin{figure} 75 | \centering 76 | \includegraphics{../figs/McSCert_Logo.pdf} \\ 77 | McMaster Centre for Software Certification (McSCert) 78 | \end{figure} 79 | 80 | \newpage 81 | 82 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83 | % Table of Contents 84 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 85 | \tableofcontents 86 | \newpage 87 | 88 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 89 | % Introduction 90 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 91 | \section{Introduction} 92 | 93 | % Briefly, what is the tool? 94 | % Provide any background or references. 95 | The \ToolName performs several functions in order to support modular development for \Simulink models. A \Simulink module structure can be summarized by Figure~\ref{FIG:module}. This tool helps in scoping \simfunc{s}, displaying interfaces, and checking associated guidelines. The following sections explain each of the tool functions. 96 | 97 | \begin{figure} 98 | \centering 99 | \includegraphics[width=0.75\textwidth]{../figs/Module} 100 | \caption{\Simulink module structure based on C.} 101 | \label{FIG:module} 102 | \end{figure} 103 | 104 | \subsection{Simulink Functions} 105 | In \Simulink, a function can be defined via the \simfunc block, and invoked graphically via \simfunccaller blocks. In the modular programming approach to software development, a system is decomposed into modules. Each module must be able to hide information in its implementation, and only expose on the interface information what is to be shared with other modules. One can use \simfunc blocks to selectively hide or expose elements on the interface. However, a thorough understanding of the \simfunc block is necessary in order to know how the \emph{Function Visibility} parameter and location in the model impacts its accessibility and name qualification. 106 | 107 | The \ToolName assists developers with using \simfunc blocks in implementing \Simulink modules. The tool can automatically convert between the different scopes of \simfunc{s}, thereby changing whether it is exposed on the interface or local to the model. The tool also assists users in quickly calling \simfunc{s}, with their appropriate qualifiers, from any location in a model or parent hierarchy, as well as creating \simfunccaller blocks with their \emph{Function prototype}, \emph{Input argument specifications}, and \emph{Output argument specifications} parameters automatically populated (if possible). 108 | 109 | \subsection{Interfaces} 110 | A \Simulink model's interface is commonly considered to be comprised of the \inport{s} and \outport{s} of the top-level system. A module interface should make clear \emph{all} the communication of a module. The \fromfile, \fromspreadsheet, \fromworkspace blocks, and global \ds{s} that are read are also inputs to the model. Elements that are outputs of the model can also include \toworkspace, \tofile, and global \ds{s} that are written to. Additionally, \simfunc definitions can be exported from a model. %A complete definition of a \Simulink module interface is presented in~\cite{paper}. 111 | 112 | The \ToolName automatically extracts the interface of a \Simulink module and either represents it in the the root of the \Simulink module, or prints the interface to the Command Window. 113 | 114 | \subsection{Dependencies} 115 | 116 | A \Simulink model can have many dependencies in the form of \modelref{s}, \library linked blocks, and data dictionaries. These reside outside of the \Simulink module, but are necessary in order to be able to simulate and code generate the model. 117 | 118 | The \ToolName examines the model, determines which dependencies exist, and prints a list to the Command Window. 119 | 120 | \subsection{Guidelines} 121 | Guidelines relating to \simfunc{s} and interfaces are presented in~\cite{paper}. Tables \ref{tbl:guideline1}, \ref{tbl:guideline2}, \ref{tbl:guideline3}, and \ref{tbl:guideline4} outline the guidelines, and the tool automates the checking of these guidelines. 122 | 123 | % Is there more information? 124 | %\subsection*{More Information} 125 | %For more information on the tool and how it can be used in model-based development with \Simulink, please the paper: 126 | 127 | %\vspace{1em} 128 | %Monika Jaskolka, Vera Pantelic, Mark Lawford, and Alan Wassyng, ``Supporting Modularity for \Simulink Models", 2019, \textit{(Manuscript in Preparation)}. 129 | 130 | % Is there more information? 131 | %\subsection*{More Information} 132 | %For more about the theoretical background of ... and how they can be used, an interested reader is referred to: 133 | % 134 | %\vspace{1em} 135 | % 136 | 137 | \newpage 138 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 139 | % How to Use the Tool 140 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 141 | \section{How to Use the Tool} 142 | This section describes what must be done to setup the \ToolName, as well as how to use the tool. 143 | 144 | %--------------------------------------- 145 | % What needs to be done before the tool can be used? 146 | % What needs to be done to a model in order for it to work on said model? 147 | %--------------------------------------- 148 | \subsection{Prerequisites and Installation} 149 | 150 | \begin{enumerate} 151 | \item For full use of the tool, please use \matlab/\Simulink R2017b or newer.\footnote{Simulink functions were introduced in R2014b. The \emph{Function Visibility} parameter was introduced in R2017b.} 152 | 153 | \item To install the tool, use one of the following approaches: 154 | \begin{enumerate} 155 | \item \textbf{Download the \file{.zip} from GitHub} 156 | \begin{enumerate} 157 | \item Unzip the contents into your desired location. 158 | \item Add the unzipped folder and subfolders to your \mpath. 159 | \item Download the \href{https://github.com/McSCert/Simulink-Utility}{Simulink-Utility} in the same manner. Add the folder and subfolders to your \mpath also. This is a dependency for the tool to work correctly. 160 | \item Download the \href{https://github.com/McSCert/LineToGotoFrom}{LineToGotoFrom} tool in the same manner. Add the folder and subfolders to your \mpath also. This is a dependency for the tool to work correctly. 161 | \end{enumerate} 162 | \item \textbf{Use the Git command line} 163 | \begin{enumerate} 164 | \item Use the following command to download the tool and any necessary submodules. 165 | \begin{verbatim} 166 | git clone --recursive https://github.com/McSCert/Simulink-Module 167 | \end{verbatim} 168 | \item Add the folder and subfolders to your \mpath. 169 | \end{enumerate} 170 | \item \textbf{If you already have the files} 171 | \begin{enumerate} 172 | \item Add the tool folder and subfolders to your \mpath. 173 | \end{enumerate} 174 | \end{enumerate} 175 | \item Run \href{https://www.mathworks.com/help/simulink/ug/registering-customizations.html}{sl\_refresh\_customizations} to refresh the Context Menu. 176 | \item Ensure your model is open and unlocked. 177 | \end{enumerate} 178 | 179 | %--------------------------------------- 180 | % How/when do you access the tool? 181 | %--------------------------------------- 182 | \subsection{Getting Started} 183 | The tool can be used via the \Simulink Context Menu, which can be viewed by right-clicking in a model. The following options can be available, depending on what is selected in the model, and which version of \Matlab/\Simulink is used. 184 | 185 | \noindent 186 | Options available when no blocks are selected are (Figure~\ref{FIG:none_selected}): 187 | \begin{itemize} 188 | \item \emph{\menu{1}} %-- R2014b+ 189 | \item \emph{\menu{4}} 190 | \item \emph{\menu{5}} %-- R2016a+ 191 | \item \emph{\menu{6}} %-- R2016a+ 192 | \item \emph{\menu{8}} %-- Only when an interface is shown in the module. 193 | \item \emph{\menu{7}} 194 | \end{itemize} 195 | 196 | \noindent 197 | Options available when one or more \simfunc blocks are selected (Figure~\ref{FIG:simfunc_selected}): 198 | \begin{itemize} 199 | \item \emph{\menu{3}} %-- R2017b+ 200 | \item \emph{\menu{2}} %-- R2014b+ 201 | \end{itemize} 202 | 203 | \noindent 204 | Options available when a \subsystem block is selected (Figure~\ref{FIG:subsystem_selected}): 205 | \begin{itemize} 206 | \item \emph{\menu{9}} %-- R2014b+ 207 | \end{itemize} 208 | 209 | \begin{figure}[!htb] 210 | \centering 211 | \begin{subfigure}[b]{\textwidth} 212 | \centering 213 | \includegraphics[width=0.65\textwidth]{../figs/ContextMenu1} 214 | \caption{Menu options when no \simfunc{s} are selected.} 215 | \label{FIG:none_selected} 216 | \end{subfigure} 217 | 218 | \vspace{1em}% 219 | 220 | \begin{subfigure}[b]{\textwidth} 221 | \centering 222 | \includegraphics[width=\textwidth]{../figs/ContextMenu2} 223 | \caption{Menu options when one or more \simfunc{s} are selected.} 224 | \label{FIG:simfunc_selected} 225 | \end{subfigure} 226 | 227 | \vspace{1em}% 228 | 229 | \begin{subfigure}[b]{\textwidth} 230 | \centering 231 | \includegraphics[width=.85\textwidth]{../figs/ContextMenu3} 232 | \caption{Menu options when a \subsystem is selected.} 233 | \label{FIG:subsystem_selected} 234 | \end{subfigure} 235 | 236 | \caption{Simulink Context Menu with context-dependant tool options visible.} 237 | \label{FIG:contextMenu} 238 | \end{figure} 239 | 240 | %--------------------------------------- 241 | % What are the main uses of the tool? 242 | %--------------------------------------- 243 | \newpage 244 | \subsection{Functionality} 245 | This section describes the tool functionality when it is used from the \Simulink Context Menu (Figure~\ref{FIG:contextMenu}). 246 | 247 | %We will demonstrate on the model shown in Figure~\ref{FIG:examplemodel}. 248 | 249 | %\begin{figure} 250 | % \includegraphics[width=\columnwidth]{../figs/Demo} 251 | % \caption{A \Simulink model (in Interface Display view).} 252 | % \label{FIG:examplemodel} 253 | %\end{figure} 254 | 255 | %------------------------- 256 | \subsubsection{\menu{1}} 257 | %------------------------- 258 | \emph{Note: This option is not available in versions prior to R2014b.} 259 | 260 | Right-clicking anywhere in the model and then selecting \cmd{\menu{1}} from the Context Menu will display the user interface shown in Figure~\ref{FIG:gui}. The listbox shows all \simfunc{s} that can be called from that location in the model. Select a function, press OK, and a \simfunccaller will be created with its \keyword{Prototype}, \keyword{Input argument specifications}, and \keyword{Output argument specifications} parameters automatically populated. 261 | 262 | This function automates the following manual steps: 263 | \begin{enumerate} 264 | \item Drag and drop a \simfunc block from the User-Defined Functions library into the model. 265 | \item Open the \simfunc block parameters. 266 | \item Enter a \keyword{Prototype} from those available. 267 | \item Determine the input and output types and dimensions. Enter them into the \keyword{Input argument specifications} and \keyword{Output argument specifications} fields in the appropriate formatting. 268 | \end{enumerate} 269 | Moreover, it allows you to see which \simfunc{s} are available (\ie in scope) from any location in the model. 270 | 271 | \begin{figure}[htb] 272 | \centering 273 | \includegraphics[width=0.5\textwidth]{../figs/GUI} 274 | \caption{Select Function interface.} 275 | \label{FIG:gui} 276 | \end{figure} 277 | 278 | %------------------------- 279 | \subsubsection{\menu{3}} 280 | %------------------------- 281 | \emph{Note: This option is not available in versions prior to R2017b.} 282 | 283 | Right-clicking directly on one or more \simfunc blocks and then selecting \cmd{\menu{3}} from the Context Menu, will display options for changing the scope of the functions. An example is shown in Figure~\ref{FIG:demo2}. 284 | 285 | The scope of a Simulink function, \ie where it can be used, is determined by both its hierarchal \emph{placement} in the model in which it is defined, and its \emph{Function Visibility} parameter. 286 | The rules for determining the scope of a \simfunc are not straightforward. When a \simfunc is given global function visibility, it can be placed anywhere in a model, and will be available for use anywhere in the model hierarchy (\ie in any subsystems or in the parent model hierarchy). When a \simfunc is given scoped function visibility, its placement in the model affects its accessibility. If placed at root level, it is accessible in the model hierarchy. The difference between a global \simfunc and a scoped \simfunc placed at the root is in the way it is called. In the latter, the function name must be qualified with the model reference block name. If the scoped \simfunc is placed in a subsystem $S$ (\ie not at the root), it is no longer available outside of the model. Instead, it is available in the parent subsystem of $S$ and any descendants. %If a scoped \simfunc being placed in an atomic subsystem, it is accessible only inside the subsystem and its descendants. 287 | 288 | \begin{figure} 289 | \centering 290 | \includegraphics[width=\textwidth]{../figs/Demo2} 291 | \caption{Changing \simfunc scopes.} 292 | \label{FIG:demo2} 293 | \end{figure} 294 | 295 | %------------------------- 296 | \subsubsection{\menu{2}} 297 | %------------------------- 298 | \emph{Note: This option is not available in versions prior to R2014b.} 299 | 300 | Right-clicking on one or more \simfunc blocks and then selecting \cmd{\menu{2}} from the Context Menu, will automatically create corresponding \simfunccaller blocks for the selected functions. The \keyword{Prototype}, \keyword{Input argument specifications}, and \keyword{Output argument specifications} parameters of the new \simfunccaller are automatically populated. An example is shown in Figure~\ref{fig:demo1a}. 301 | 302 | \begin{figure}[!htb] 303 | \centering 304 | \begin{subfigure}[b]{\textwidth} 305 | \centering 306 | \includegraphics[width=\textwidth]{../figs/Demo1a} 307 | \caption{Select \menu{2} from the Context Menu.} 308 | \label{fig:demo1a} 309 | \end{subfigure} 310 | 311 | \vspace{1em}% 312 | 313 | \begin{subfigure}[b]{\textwidth} 314 | \centering 315 | \includegraphics[width=.75\textwidth]{../figs/Demo1b} 316 | \caption{New function callers are added.} 317 | \label{fig:demo1b} 318 | \end{subfigure} 319 | \caption{Example of Simulink Function Caller creation.} 320 | \label{fig:demo1} 321 | \end{figure} 322 | 323 | %------------------------- 324 | \subsubsection{\menu{9}} 325 | %------------------------- 326 | \emph{Note: This option is not available in versions prior to R2014a.} 327 | 328 | Right-clicking on a \subsystem and then selecting \cmd{\menu{9}}, and one of the two option from the Context Menu will convert a \subsystem block into a \simfunc. This will prompt the user for a function name, and perform several functions to reconfigure the \subsystem. This includes converting any \inport/\outport blocks to \argin/\argout blocks, adding a \trigger block, and setting various parameters. 329 | 330 | %------------------------- 331 | \subsubsection{\menu{4}} 332 | %------------------------- 333 | Right-clicking anywhere in the model and then selecting \cmd{\menu{4}} from the Context Menu will display the user interface shown in Figure~\ref{FIG:guideline}. The window shows all the guidelines that can be enabled by the user, and hovering over their names with the cursor will display a brief description of the guideline. The guidelines are detailed in Tables \ref{tbl:guideline1}, \ref{tbl:guideline2}, \ref{tbl:guideline3}, and \ref{tbl:guideline4}. Select one or more guidelines to check, press OK, and the Command Window will display any violations. 334 | 335 | \begin{figure}[htb] 336 | \centering 337 | \includegraphics[width=0.5\textwidth]{../figs/GuidelineSelector} 338 | \caption{Select guidelines GUI.} 339 | \label{FIG:guideline} 340 | \end{figure} 341 | 342 | \begin{table} 343 | \centering 344 | \caption{Guideline on \simfunc placement.} 345 | \label{tbl:guideline1} 346 | \begin{tabular}{|l|p{30em}|} 347 | \hline 348 | ID: Title & 1: \Simulink Function Placement \\ \hline 349 | Priority & Strongly Recommended \\ \hline 350 | \Matlab Version & R2014b and later \\ \hline 351 | Description & Position the \simfunc block in the lowest common parent of its corresponding \simfunccaller blocks. Do not position the \simfunc in the top layer for no reason. Avoid placing \simfunc blocks below their corresponding \simfunccaller blocks. \\ \hline 352 | Rationale & \checkbox Readability \newline 353 | \checkbox Verification and Validation \newline 354 | \checkbox Workflow \newline 355 | \checkbox Code Generation \newline 356 | \uncheckbox Simulation \\ \hline 357 | \end{tabular} 358 | \end{table} 359 | 360 | \begin{table} 361 | \centering 362 | \caption{Guideline on \simfunc visibility.} 363 | \label{tbl:guideline2} 364 | \begin{tabular}{|l|p{30em}|} 365 | \hline 366 | ID: Title & 2: \Simulink Function Visibility \\ \hline 367 | Priority & Strongly Recommended \\ \hline 368 | \Matlab Version & R2017b and later \\ \hline 369 | Description & Limit the \param{Function Visibility} parameter of the \simfunc block's trigger port to \param{scoped} if possible. \newline 370 | \includegraphics[scale=0.6]{../figs/FunctionVisibilityParam} \\ \hline 371 | Rationale & \checkbox Readability \newline 372 | \checkbox Verification and Validation \newline 373 | \checkbox Workflow \newline 374 | \checkbox Code Generation \newline 375 | \uncheckbox Simulation \\ \hline 376 | \end{tabular} 377 | \end{table} 378 | 379 | \begin{table} 380 | \centering 381 | \caption{Guideline on \simfunc shadowing.} 382 | \label{tbl:guideline3} 383 | \begin{tabular}{|l|p{30em}|} 384 | \hline 385 | ID: Title & 3: \Simulink Function Shadowing \\ \hline 386 | Priority & Strongly Recommended \\ \hline 387 | \Matlab Version & R2014b and later \\ \hline 388 | Description & Do not place \simfunc{s} with the same name and input/output arguments within each other's scope. \\ \hline 389 | Rationale & \checkbox Readability \newline 390 | \checkbox Verification and Validation \newline 391 | \checkbox Workflow \newline 392 | \uncheckbox Code Generation \newline 393 | \uncheckbox Simulation \\ \hline 394 | \end{tabular} 395 | \end{table} 396 | 397 | \begin{table} 398 | \centering 399 | \caption{Guideline on using the base workspace.} 400 | \label{tbl:guideline4} 401 | \begin{tabular}{|l|p{30em}|} 402 | \hline 403 | ID: Title & 4: Use of the Base Workspace \\ \hline 404 | Priority & Recommended \\ \hline 405 | \Matlab Version & R2006a and later \\ \hline 406 | Description & Do not use the base workspace for storing, reading, or writing data that a model is dependant on. Instead, place such data in either the model workspace, if it is to be used in a single model, or a data dictionary if it is to be shared across models. This means avoiding the use of the sources, 407 | \begin{itemize} 408 | \item \fromfile 409 | \item \fromworkspace 410 | \item \fromspreadsheet 411 | \end{itemize} 412 | and sinks, 413 | \begin{itemize} 414 | \item \tofile 415 | \item \toworkspace 416 | \end{itemize} 417 | as well as avoiding defining signals, types, \etc in the base workspace. \\ \hline 418 | Rationale & \checkbox Readability \newline 419 | \checkbox Verification and Validation \newline 420 | \checkbox Workflow \newline 421 | \checkbox Code Generation \newline 422 | \checkbox Simulation \\ \hline 423 | \end{tabular} 424 | \end{table} 425 | 426 | %------------------------- 427 | \subsubsection{\menu{5} and \menu{6}} 428 | %------------------------- 429 | \emph{Note: This option is not available in versions prior to R2016a.} 430 | 431 | Right-clicking anywhere in the model and then hovering over \cmd{\menu{5}} or \cmd{\menu{6}} from the Context Menu will give the user options to insert the interface representation in the model (\eg Figure~\ref{FIG:interface_visual}), or print the interface description to the Command Window (\eg Figure~\ref{FIG:interface_text}). 432 | 433 | \begin{figure}[htb] 434 | \begin{subfigure}[b]{.6\textwidth} 435 | \includegraphics[height=1.4\textwidth]{../figs/Interface} 436 | \caption{Visual representation.} 437 | \label{FIG:interface_visual} 438 | \end{subfigure} 439 | \begin{subfigure}[b]{.4\textwidth} 440 | \lstset{basicstyle=\footnotesize\ttfamily, keepspaces=false, columns=flexible,} 441 | \begin{lstlisting} 442 | Inputs 443 | ------ 444 | Inports: 445 | Demo/In1, uint16, 1, 1 446 | 447 | Outputs 448 | ------- 449 | Outports: 450 | Demo/Out1, Inherit: auto, 1, 1 451 | Demo/Out2, Inherit: auto, -1, 1 452 | Demo/Out3, Inherit: auto, -1, Inf 453 | To Files: 454 | Demo/To File1, Timeseries, N/A, 1 455 | Demo/To File2, Timeseries, N/A, 1 456 | Data Store Writes: 457 | Demo/Data Store Write, uint16, 1, 1 458 | 459 | Exports 460 | ------- 461 | Simulink Functions: 462 | Demo/Simulink Function, 463 | In: uint16, 1, -1 464 | Out: uint16, 1, -1 465 | \end{lstlisting} 466 | \caption{Textual description.} 467 | \label{FIG:interface_text} 468 | \end{subfigure} 469 | \caption{\Simulink module interface.} 470 | \label{FIG:simulinkinterface} 471 | \end{figure} 472 | 473 | %------------------------- 474 | \subsubsection{\menu{8}} 475 | %------------------------- 476 | Right-clicking anywhere in the model and then selecting \cmd{\menu{8}} will delete the interface that was created using the \cmd{\menu{5}} option. 477 | 478 | \newpage 479 | %------------------------- 480 | \subsubsection{\menu{7}} 481 | %------------------------- 482 | Right-clicking anywhere in the model and then selecting \cmd{\menu{7}} from the Context Menus will print the dependencies that the model relies on in the Command Window. Dependencies include: \modelref blocks, \library blocks, and data dictionaries. An example of the output is shown in Figure~\ref{FIG:dependencies}. 483 | 484 | \begin{figure}[htb] 485 | \centering 486 | \lstset{basicstyle=\footnotesize\ttfamily, keepspaces=false, columns=flexible,} 487 | \begin{lstlisting} 488 | Model References 489 | ------ 490 | Demo2/ControlModel 491 | Demo2/Subsystem/EstimationModel 492 | 493 | Library Links 494 | ------ 495 | Demo2/Subsystem2/CustomTable 496 | 497 | Data Dictionaries 498 | ------ 499 | definitions.sldd 500 | \end{lstlisting} 501 | \caption{List of dependencies.} 502 | \label{FIG:dependencies} 503 | \end{figure} 504 | 505 | %--------------------------------------- 506 | % What else does the tool do? 507 | %--------------------------------------- 508 | 509 | \subsection{Errors and Warnings} 510 | Any errors or warnings during tool use will be visible in the \matlab Command Window or as pop-up windows. 511 | 512 | \begin{enumerate} 513 | 514 | 515 | \item If a \simfunc is moved and one or more \simfunccaller{s} with the same prototype exist within its previous scope, a warning will appear in the Command Window. It is recommended that the user ensure all \simfunccaller{s} still correctly call the \simfunc. Automatic updating of \simfunccaller blocks is planned for a future version of this tool. 516 | \end{enumerate} 517 | 518 | \subsection{Limitations} 519 | A \Simulink model can depend on or interact with other files and elements via the use of Callbacks\footnote{\url{https://www.mathworks.com/help/simulink/ug/model-callbacks.html}} and S-Functions\footnote{\url{https://www.mathworks.com/help/simulink/sfg/what-is-an-s-function.html}}. Identifying these is not currently supported by the tool. 520 | 521 | \begin{thebibliography}{9} 522 | \bibitem{paper} 523 | Monika Jaskolka, Vera Pantelic, Alan Wassyng, and Mark Lawford, ``Supporting Modularity in \Simulink Models", \emph{arXiv:2007.10120}. 524 | \end{thebibliography} 525 | 526 | \end{document} -------------------------------------------------------------------------------- /example/Demo.mdl: -------------------------------------------------------------------------------- 1 | Model { 2 | Name "Demo2" 3 | Version 8.4 4 | SavedCharacterEncoding "windows-1252" 5 | GraphicalInterface { 6 | NumRootInports 1 7 | Inport { 8 | Name "In1" 9 | BusObject "" 10 | } 11 | NumRootOutports 3 12 | Outport { 13 | Name "Out1" 14 | BusObject "" 15 | BusOutputAsStruct "off" 16 | } 17 | Outport { 18 | Name "Out2" 19 | BusObject "" 20 | BusOutputAsStruct "off" 21 | } 22 | Outport { 23 | Name "Out3" 24 | BusObject "" 25 | BusOutputAsStruct "off" 26 | } 27 | ParameterArgumentNames "" 28 | ComputedModelVersion "1.101" 29 | NumModelReferences 1 30 | ModelReference { 31 | ModelRefBlockPath "Demo2/Model|sl_subsys_for1" 32 | } 33 | NumTestPointedSignals 0 34 | } 35 | PreLoadFcn "DataStore = Simulink.Signal;\nDataStore.Description = 'Stores data for demo.';\nDataStore.DataType = " 36 | "'uint16';\nDataStore.Complexity = 'real';\nDataStore.Dimensions = 1;\nDataStore.SamplingMode='Sample based';\nDataSt" 37 | "ore.SampleTime = 1;" 38 | ScopeRefreshTime 0.035000 39 | OverrideScopeRefreshTime on 40 | DisableAllScopes off 41 | DataTypeOverride "UseLocalSettings" 42 | DataTypeOverrideAppliesTo "AllNumericTypes" 43 | MinMaxOverflowLogging "UseLocalSettings" 44 | MinMaxOverflowArchiveMode "Overwrite" 45 | FPTRunName "Run 1" 46 | MaxMDLFileLineLength 120 47 | Object { 48 | $PropName "BdWindowsInfo" 49 | $ObjectID 1 50 | $ClassName "Simulink.BDWindowsInfo" 51 | Object { 52 | $PropName "WindowsInfo" 53 | $ObjectID 2 54 | $ClassName "Simulink.WindowInfo" 55 | IsActive [1] 56 | Location [463.0, 145.0, 987.0, 945.0] 57 | Object { 58 | $PropName "ModelBrowserInfo" 59 | $ObjectID 3 60 | $ClassName "Simulink.ModelBrowserInfo" 61 | Visible [0] 62 | DockPosition "Left" 63 | Width [50] 64 | Height [50] 65 | Filter [9] 66 | } 67 | Object { 68 | $PropName "ExplorerBarInfo" 69 | $ObjectID 4 70 | $ClassName "Simulink.ExplorerBarInfo" 71 | Visible [1] 72 | } 73 | Object { 74 | $PropName "EditorsInfo" 75 | $ObjectID 5 76 | $ClassName "Simulink.EditorInfo" 77 | IsActive [1] 78 | ViewObjType "SimulinkTopLevel" 79 | LoadSaveID "0" 80 | Extents [933.0, 765.0] 81 | ZoomFactor [1.9293193717277484] 82 | Offset [78.464395537136454, 6.7435549525101521] 83 | } 84 | } 85 | } 86 | Created "Tue Apr 16 13:02:10 2019" 87 | Creator "monika" 88 | UpdateHistory "UpdateHistoryNever" 89 | ModifiedByFormat "%" 90 | LastModifiedBy "monika" 91 | ModifiedDateFormat "%" 92 | LastModifiedDate "Mon Apr 29 22:59:11 2019" 93 | RTWModifiedTimeStamp 478479551 94 | ModelVersionFormat "1.%" 95 | SampleTimeColors off 96 | SampleTimeAnnotations off 97 | LibraryLinkDisplay "none" 98 | WideLines off 99 | ShowLineDimensions off 100 | ShowPortDataTypes off 101 | ShowDesignRanges off 102 | ShowLoopsOnError on 103 | IgnoreBidirectionalLines off 104 | ShowStorageClass off 105 | ShowTestPointIcons on 106 | ShowSignalResolutionIcons on 107 | ShowViewerIcons on 108 | SortedOrder off 109 | ExecutionContextIcon off 110 | ShowLinearizationAnnotations on 111 | ShowMarkup on 112 | BlockNameDataTip off 113 | BlockParametersDataTip off 114 | BlockDescriptionStringDataTip off 115 | ToolBar on 116 | StatusBar on 117 | BrowserShowLibraryLinks off 118 | BrowserLookUnderMasks off 119 | SimulationMode "normal" 120 | PauseTimes "5" 121 | NumberOfSteps 1 122 | SnapshotBufferSize 10 123 | SnapshotInterval 10 124 | NumberOfLastSnapshots 0 125 | LinearizationMsg "none" 126 | Profile off 127 | ParamWorkspaceSource "MATLABWorkspace" 128 | AccelSystemTargetFile "accel.tlc" 129 | AccelTemplateMakefile "accel_default_tmf" 130 | AccelMakeCommand "make_rtw" 131 | TryForcingSFcnDF off 132 | Object { 133 | $PropName "DataLoggingOverride" 134 | $ObjectID 7 135 | $ClassName "Simulink.SimulationData.ModelLoggingInfo" 136 | model_ "Demo2" 137 | Array { 138 | Type "Cell" 139 | Dimension 1 140 | Cell "Demo2" 141 | PropName "logAsSpecifiedByModels_" 142 | } 143 | Array { 144 | Type "Cell" 145 | Dimension 1 146 | Cell "" 147 | PropName "logAsSpecifiedByModelsSSIDs_" 148 | } 149 | } 150 | RecordCoverage off 151 | CovPath "/" 152 | CovSaveName "covdata" 153 | CovMetricSettings "d" 154 | CovNameIncrementing off 155 | CovHtmlReporting on 156 | CovForceBlockReductionOff on 157 | CovEnableCumulative on 158 | covSaveCumulativeToWorkspaceVar on 159 | CovSaveSingleToWorkspaceVar on 160 | CovCumulativeVarName "covCumulativeData" 161 | CovCumulativeReport off 162 | CovReportOnPause on 163 | CovModelRefEnable "Off" 164 | CovExternalEMLEnable off 165 | CovSFcnEnable on 166 | CovBoundaryAbsTol 0.000010 167 | CovBoundaryRelTol 0.010000 168 | CovUseTimeInterval off 169 | CovStartTime 0 170 | CovStopTime 0 171 | ExtModeBatchMode off 172 | ExtModeEnableFloating on 173 | ExtModeTrigType "manual" 174 | ExtModeTrigMode "normal" 175 | ExtModeTrigPort "1" 176 | ExtModeTrigElement "any" 177 | ExtModeTrigDuration 1000 178 | ExtModeTrigDurationFloating "auto" 179 | ExtModeTrigHoldOff 0 180 | ExtModeTrigDelay 0 181 | ExtModeTrigDirection "rising" 182 | ExtModeTrigLevel 0 183 | ExtModeArchiveMode "off" 184 | ExtModeAutoIncOneShot off 185 | ExtModeIncDirWhenArm off 186 | ExtModeAddSuffixToVar off 187 | ExtModeWriteAllDataToWs off 188 | ExtModeArmWhenConnect on 189 | ExtModeSkipDownloadWhenConnect off 190 | ExtModeLogAll on 191 | ExtModeAutoUpdateStatusClock off 192 | ShowModelReferenceBlockVersion off 193 | ShowModelReferenceBlockIO off 194 | Array { 195 | Type "Handle" 196 | Dimension 1 197 | Simulink.ConfigSet { 198 | $ObjectID 8 199 | Version "1.14.3" 200 | Array { 201 | Type "Handle" 202 | Dimension 8 203 | Simulink.SolverCC { 204 | $ObjectID 9 205 | Version "1.14.3" 206 | StartTime "0.0" 207 | StopTime "10.0" 208 | AbsTol "auto" 209 | FixedStep "1" 210 | InitialStep "auto" 211 | MaxOrder 5 212 | ZcThreshold "auto" 213 | ConsecutiveZCsStepRelTol "10*128*eps" 214 | MaxConsecutiveZCs "1000" 215 | ExtrapolationOrder 4 216 | NumberNewtonIterations 1 217 | MaxStep "auto" 218 | MinStep "auto" 219 | MaxConsecutiveMinStep "1" 220 | RelTol "1e-3" 221 | SolverMode "Auto" 222 | EnableConcurrentExecution off 223 | ConcurrentTasks off 224 | Solver "FixedStepDiscrete" 225 | SolverName "FixedStepDiscrete" 226 | SolverJacobianMethodControl "auto" 227 | ShapePreserveControl "DisableAll" 228 | ZeroCrossControl "UseLocalSettings" 229 | ZeroCrossAlgorithm "Nonadaptive" 230 | AlgebraicLoopSolver "TrustRegion" 231 | SolverResetMethod "Fast" 232 | PositivePriorityOrder off 233 | AutoInsertRateTranBlk off 234 | SampleTimeConstraint "Unconstrained" 235 | InsertRTBMode "Whenever possible" 236 | } 237 | Simulink.DataIOCC { 238 | $ObjectID 10 239 | Version "1.14.3" 240 | Decimation "1" 241 | ExternalInput "[t, u]" 242 | FinalStateName "xFinal" 243 | InitialState "xInitial" 244 | LimitDataPoints on 245 | MaxDataPoints "1000" 246 | LoadExternalInput off 247 | LoadInitialState off 248 | SaveFinalState off 249 | SaveCompleteFinalSimState off 250 | SaveFormat "StructureWithTime" 251 | SignalLoggingSaveFormat "Dataset" 252 | SaveOutput on 253 | SaveState off 254 | SignalLogging on 255 | DSMLogging on 256 | InspectSignalLogs off 257 | VisualizeSimOutput on 258 | SaveTime on 259 | ReturnWorkspaceOutputs off 260 | StateSaveName "xout" 261 | TimeSaveName "tout" 262 | OutputSaveName "yout" 263 | SignalLoggingName "logsout" 264 | DSMLoggingName "dsmout" 265 | OutputOption "RefineOutputTimes" 266 | OutputTimes "[]" 267 | ReturnWorkspaceOutputsName "out" 268 | Refine "1" 269 | } 270 | Simulink.OptimizationCC { 271 | $ObjectID 11 272 | Version "1.14.3" 273 | Array { 274 | Type "Cell" 275 | Dimension 8 276 | Cell "ZeroExternalMemoryAtStartup" 277 | Cell "ZeroInternalMemoryAtStartup" 278 | Cell "NoFixptDivByZeroProtection" 279 | Cell "OptimizeModelRefInitCode" 280 | Cell "BooleansAsBitfields" 281 | Cell "PassReuseOutputArgsAs" 282 | Cell "PassReuseOutputArgsThreshold" 283 | Cell "UseSpecifiedMinMax" 284 | PropName "DisabledProps" 285 | } 286 | BlockReduction off 287 | BooleanDataType off 288 | ConditionallyExecuteInputs on 289 | InlineParams off 290 | UseDivisionForNetSlopeComputation "Off" 291 | UseFloatMulNetSlope off 292 | DefaultUnderspecifiedDataType "double" 293 | UseSpecifiedMinMax off 294 | InlineInvariantSignals off 295 | OptimizeBlockIOStorage on 296 | BufferReuse on 297 | EnhancedBackFolding off 298 | CachingGlobalReferences off 299 | GlobalBufferReuse on 300 | StrengthReduction off 301 | ExpressionFolding on 302 | BooleansAsBitfields off 303 | BitfieldContainerType "uint_T" 304 | EnableMemcpy on 305 | MemcpyThreshold 64 306 | PassReuseOutputArgsAs "Structure reference" 307 | ExpressionDepthLimit 2147483647 308 | LocalBlockOutputs on 309 | RollThreshold 5 310 | StateBitsets off 311 | DataBitsets off 312 | ActiveStateOutputEnumStorageType "Native Integer" 313 | ZeroExternalMemoryAtStartup on 314 | ZeroInternalMemoryAtStartup on 315 | InitFltsAndDblsToZero on 316 | NoFixptDivByZeroProtection off 317 | EfficientFloat2IntCast off 318 | EfficientMapNaN2IntZero on 319 | OptimizeModelRefInitCode off 320 | LifeSpan "inf" 321 | MaxStackSize "Inherit from target" 322 | BufferReusableBoundary on 323 | SimCompilerOptimization "Off" 324 | AccelVerboseBuild off 325 | } 326 | Simulink.DebuggingCC { 327 | $ObjectID 12 328 | Version "1.14.3" 329 | RTPrefix "error" 330 | ConsistencyChecking "none" 331 | ArrayBoundsChecking "none" 332 | SignalInfNanChecking "none" 333 | SignalRangeChecking "none" 334 | ReadBeforeWriteMsg "UseLocalSettings" 335 | WriteAfterWriteMsg "UseLocalSettings" 336 | WriteAfterReadMsg "UseLocalSettings" 337 | AlgebraicLoopMsg "warning" 338 | ArtificialAlgebraicLoopMsg "warning" 339 | SaveWithDisabledLinksMsg "warning" 340 | SaveWithParameterizedLinksMsg "none" 341 | CheckSSInitialOutputMsg on 342 | UnderspecifiedInitializationDetection "Simplified" 343 | MergeDetectMultiDrivingBlocksExec "error" 344 | CheckExecutionContextPreStartOutputMsg off 345 | CheckExecutionContextRuntimeOutputMsg off 346 | SignalResolutionControl "TryResolveAllWithWarning" 347 | BlockPriorityViolationMsg "warning" 348 | MinStepSizeMsg "warning" 349 | TimeAdjustmentMsg "none" 350 | MaxConsecutiveZCsMsg "error" 351 | MaskedZcDiagnostic "warning" 352 | IgnoredZcDiagnostic "warning" 353 | SolverPrmCheckMsg "none" 354 | InheritedTsInSrcMsg "warning" 355 | MultiTaskDSMMsg "warning" 356 | MultiTaskCondExecSysMsg "none" 357 | MultiTaskRateTransMsg "error" 358 | SingleTaskRateTransMsg "none" 359 | TasksWithSamePriorityMsg "warning" 360 | SigSpecEnsureSampleTimeMsg "warning" 361 | CheckMatrixSingularityMsg "none" 362 | IntegerOverflowMsg "warning" 363 | Int32ToFloatConvMsg "warning" 364 | ParameterDowncastMsg "error" 365 | ParameterOverflowMsg "error" 366 | ParameterUnderflowMsg "none" 367 | ParameterPrecisionLossMsg "warning" 368 | ParameterTunabilityLossMsg "warning" 369 | FixptConstUnderflowMsg "none" 370 | FixptConstOverflowMsg "none" 371 | FixptConstPrecisionLossMsg "none" 372 | UnderSpecifiedDataTypeMsg "none" 373 | UnnecessaryDatatypeConvMsg "none" 374 | VectorMatrixConversionMsg "none" 375 | InvalidFcnCallConnMsg "error" 376 | FcnCallInpInsideContextMsg "EnableAllAsWarning" 377 | SignalLabelMismatchMsg "none" 378 | UnconnectedInputMsg "warning" 379 | UnconnectedOutputMsg "warning" 380 | UnconnectedLineMsg "warning" 381 | SFcnCompatibilityMsg "none" 382 | FrameProcessingCompatibilityMsg "error" 383 | UniqueDataStoreMsg "none" 384 | BusObjectLabelMismatch "warning" 385 | RootOutportRequireBusObject "warning" 386 | AssertControl "UseLocalSettings" 387 | ModelReferenceIOMsg "none" 388 | ModelReferenceMultiInstanceNormalModeStructChecksumCheck "error" 389 | ModelReferenceVersionMismatchMessage "none" 390 | ModelReferenceIOMismatchMessage "none" 391 | UnknownTsInhSupMsg "warning" 392 | ModelReferenceDataLoggingMessage "warning" 393 | ModelReferenceSymbolNameMessage "warning" 394 | ModelReferenceExtraNoncontSigs "error" 395 | StateNameClashWarn "warning" 396 | SimStateInterfaceChecksumMismatchMsg "warning" 397 | SimStateOlderReleaseMsg "error" 398 | InitInArrayFormatMsg "warning" 399 | StrictBusMsg "ErrorLevel1" 400 | BusNameAdapt "WarnAndRepair" 401 | NonBusSignalsTreatedAsBus "none" 402 | BlockIODiagnostic "none" 403 | SFUnusedDataAndEventsDiag "warning" 404 | SFUnexpectedBacktrackingDiag "warning" 405 | SFInvalidInputDataAccessInChartInitDiag "warning" 406 | SFNoUnconditionalDefaultTransitionDiag "warning" 407 | SFTransitionOutsideNaturalParentDiag "warning" 408 | SFUnconditionalTransitionShadowingDiag "warning" 409 | SFUndirectedBroadcastEventsDiag "warning" 410 | SFTransitionActionBeforeConditionDiag "warning" 411 | IntegerSaturationMsg "warning" 412 | ModelReferenceCSMismatchMessage "none" 413 | } 414 | Simulink.HardwareCC { 415 | $ObjectID 13 416 | Version "1.14.3" 417 | ProdBitPerChar 8 418 | ProdBitPerShort 16 419 | ProdBitPerInt 32 420 | ProdBitPerLong 32 421 | ProdBitPerLongLong 64 422 | ProdBitPerFloat 32 423 | ProdBitPerDouble 64 424 | ProdBitPerPointer 32 425 | ProdLargestAtomicInteger "Char" 426 | ProdLargestAtomicFloat "None" 427 | ProdIntDivRoundTo "Undefined" 428 | ProdEndianess "Unspecified" 429 | ProdWordSize 32 430 | ProdShiftRightIntArith on 431 | ProdLongLongMode off 432 | ProdHWDeviceType "32-bit Generic" 433 | TargetBitPerChar 8 434 | TargetBitPerShort 16 435 | TargetBitPerInt 32 436 | TargetBitPerLong 32 437 | TargetBitPerLongLong 64 438 | TargetBitPerFloat 32 439 | TargetBitPerDouble 64 440 | TargetBitPerPointer 32 441 | TargetLargestAtomicInteger "Char" 442 | TargetLargestAtomicFloat "None" 443 | TargetShiftRightIntArith on 444 | TargetLongLongMode off 445 | TargetIntDivRoundTo "Undefined" 446 | TargetEndianess "Unspecified" 447 | TargetWordSize 32 448 | TargetPreprocMaxBitsSint 32 449 | TargetPreprocMaxBitsUint 32 450 | TargetHWDeviceType "Specified" 451 | TargetUnknown on 452 | ProdEqTarget on 453 | } 454 | Simulink.ModelReferenceCC { 455 | $ObjectID 14 456 | Version "1.14.3" 457 | UpdateModelReferenceTargets "IfOutOfDateOrStructuralChange" 458 | CheckModelReferenceTargetMessage "error" 459 | EnableParallelModelReferenceBuilds off 460 | ParallelModelReferenceErrorOnInvalidPool on 461 | ParallelModelReferenceMATLABWorkerInit "None" 462 | ModelReferenceNumInstancesAllowed "Multi" 463 | PropagateVarSize "Infer from blocks in model" 464 | ModelReferencePassRootInputsByReference on 465 | ModelReferenceMinAlgLoopOccurrences off 466 | PropagateSignalLabelsOutOfModel off 467 | SupportModelReferenceSimTargetCustomCode off 468 | } 469 | Simulink.SFSimCC { 470 | $ObjectID 15 471 | Version "1.14.3" 472 | SFSimEcho on 473 | SimCtrlC on 474 | SimIntegrity on 475 | SimUseLocalCustomCode off 476 | SimParseCustomCode on 477 | SimBuildMode "sf_incremental_build" 478 | SimGenImportedTypeDefs off 479 | } 480 | Simulink.RTWCC { 481 | $BackupClass "Simulink.RTWCC" 482 | $ObjectID 16 483 | Version "1.14.3" 484 | Array { 485 | Type "Cell" 486 | Dimension 16 487 | Cell "IncludeHyperlinkInReport" 488 | Cell "GenerateTraceInfo" 489 | Cell "GenerateTraceReport" 490 | Cell "GenerateTraceReportSl" 491 | Cell "GenerateTraceReportSf" 492 | Cell "GenerateTraceReportEml" 493 | Cell "PortableWordSizes" 494 | Cell "GenerateWebview" 495 | Cell "GenerateCodeMetricsReport" 496 | Cell "GenerateCodeReplacementReport" 497 | Cell "GenerateMissedCodeReplacementReport" 498 | Cell "GenerateErtSFunction" 499 | Cell "CreateSILPILBlock" 500 | Cell "CodeExecutionProfiling" 501 | Cell "CodeProfilingSaveOptions" 502 | Cell "CodeProfilingInstrumentation" 503 | PropName "DisabledProps" 504 | } 505 | SystemTargetFile "grt.tlc" 506 | TLCOptions "" 507 | GenCodeOnly off 508 | MakeCommand "make_rtw" 509 | GenerateMakefile on 510 | PackageGeneratedCodeAndArtifacts off 511 | TemplateMakefile "grt_default_tmf" 512 | PostCodeGenCommand "" 513 | GenerateReport off 514 | RTWVerbose on 515 | RetainRTWFile off 516 | ProfileTLC off 517 | TLCDebug off 518 | TLCCoverage off 519 | TLCAssert off 520 | RTWUseLocalCustomCode off 521 | RTWUseSimCustomCode off 522 | Toolchain "Automatically locate an installed toolchain" 523 | BuildConfiguration "Faster Builds" 524 | IncludeHyperlinkInReport off 525 | LaunchReport off 526 | PortableWordSizes off 527 | CreateSILPILBlock "None" 528 | CodeExecutionProfiling off 529 | CodeExecutionProfileVariable "executionProfile" 530 | CodeProfilingSaveOptions "SummaryOnly" 531 | CodeProfilingInstrumentation off 532 | SILDebugging off 533 | TargetLang "C" 534 | IncludeBusHierarchyInRTWFileBlockHierarchyMap off 535 | GenerateTraceInfo off 536 | GenerateTraceReport off 537 | GenerateTraceReportSl off 538 | GenerateTraceReportSf off 539 | GenerateTraceReportEml off 540 | GenerateWebview off 541 | GenerateCodeMetricsReport off 542 | GenerateCodeReplacementReport off 543 | RTWCompilerOptimization "Off" 544 | RTWCustomCompilerOptimizations "" 545 | CheckMdlBeforeBuild "Off" 546 | SharedConstantsCachingThreshold 1024 547 | Array { 548 | Type "Handle" 549 | Dimension 2 550 | Simulink.CodeAppCC { 551 | $ObjectID 17 552 | Version "1.14.3" 553 | Array { 554 | Type "Cell" 555 | Dimension 28 556 | Cell "IgnoreCustomStorageClasses" 557 | Cell "InsertBlockDesc" 558 | Cell "SFDataObjDesc" 559 | Cell "SimulinkDataObjDesc" 560 | Cell "DefineNamingRule" 561 | Cell "SignalNamingRule" 562 | Cell "ParamNamingRule" 563 | Cell "InlinedPrmAccess" 564 | Cell "CustomSymbolStr" 565 | Cell "IgnoreTestpoints" 566 | Cell "InsertPolySpaceComments" 567 | Cell "MATLABFcnDesc" 568 | Cell "InternalIdentifier" 569 | Cell "CustomSymbolStrGlobalVar" 570 | Cell "CustomSymbolStrType" 571 | Cell "CustomSymbolStrField" 572 | Cell "CustomSymbolStrFcn" 573 | Cell "CustomSymbolStrModelFcn" 574 | Cell "CustomSymbolStrFcnArg" 575 | Cell "CustomSymbolStrBlkIO" 576 | Cell "CustomSymbolStrTmpVar" 577 | Cell "CustomSymbolStrMacro" 578 | Cell "CustomSymbolStrUtil" 579 | Cell "CustomSymbolStrEmxType" 580 | Cell "CustomSymbolStrEmxFcn" 581 | Cell "CustomUserTokenString" 582 | Cell "ReqsInCode" 583 | Cell "BlockCommentType" 584 | PropName "DisabledProps" 585 | } 586 | ForceParamTrailComments off 587 | GenerateComments on 588 | CommentStyle "Auto" 589 | IgnoreCustomStorageClasses on 590 | IgnoreTestpoints off 591 | MaxIdLength 31 592 | PreserveName off 593 | PreserveNameWithParent off 594 | ShowEliminatedStatement on 595 | OperatorAnnotations off 596 | SimulinkDataObjDesc off 597 | SFDataObjDesc off 598 | MATLABFcnDesc off 599 | MangleLength 1 600 | CustomSymbolStrGlobalVar "$R$N$M" 601 | CustomSymbolStrType "$N$R$M_T" 602 | CustomSymbolStrField "$N$M" 603 | CustomSymbolStrFcn "$R$N$M$F" 604 | CustomSymbolStrFcnArg "rt$I$N$M" 605 | CustomSymbolStrBlkIO "rtb_$N$M" 606 | CustomSymbolStrTmpVar "$N$M" 607 | CustomSymbolStrMacro "$R$N$M" 608 | CustomSymbolStrUtil "$N$C" 609 | DefineNamingRule "None" 610 | ParamNamingRule "None" 611 | SignalNamingRule "None" 612 | InsertBlockDesc off 613 | InsertPolySpaceComments off 614 | SimulinkBlockComments on 615 | MATLABSourceComments off 616 | EnableCustomComments off 617 | InternalIdentifier "Shortened" 618 | InlinedPrmAccess "Literals" 619 | ReqsInCode off 620 | UseSimReservedNames off 621 | } 622 | Simulink.GRTTargetCC { 623 | $BackupClass "Simulink.TargetCC" 624 | $ObjectID 18 625 | Version "1.14.3" 626 | Array { 627 | Type "Cell" 628 | Dimension 17 629 | Cell "IncludeMdlTerminateFcn" 630 | Cell "RemoveResetFunc" 631 | Cell "SuppressErrorStatus" 632 | Cell "ERTCustomFileBanners" 633 | Cell "GenerateSampleERTMain" 634 | Cell "MultiInstanceERTCode" 635 | Cell "PurelyIntegerCode" 636 | Cell "SupportNonInlinedSFcns" 637 | Cell "SupportComplex" 638 | Cell "SupportAbsoluteTime" 639 | Cell "SupportContinuousTime" 640 | Cell "ExistingSharedCode" 641 | Cell "GenerateTestInterfaces" 642 | Cell "ModelStepFunctionPrototypeControlCompliant" 643 | Cell "GenerateAllocFcn" 644 | Cell "RemoveDisableFunc" 645 | Cell "PreserveStateflowLocalDataDimensions" 646 | PropName "DisabledProps" 647 | } 648 | TargetFcnLib "ansi_tfl_tmw.mat" 649 | TargetLibSuffix "" 650 | TargetPreCompLibLocation "" 651 | GenFloatMathFcnCalls "NOT IN USE" 652 | TargetLangStandard "C89/C90 (ANSI)" 653 | CodeReplacementLibrary "None" 654 | UtilityFuncGeneration "Auto" 655 | ERTMultiwordTypeDef "System defined" 656 | MultiwordLength 2048 657 | GenerateFullHeader on 658 | GenerateSampleERTMain off 659 | GenerateTestInterfaces off 660 | ModelReferenceCompliant on 661 | ParMdlRefBuildCompliant on 662 | CompOptLevelCompliant on 663 | ConcurrentExecutionCompliant on 664 | IncludeMdlTerminateFcn on 665 | GeneratePreprocessorConditionals "Disable all" 666 | CombineOutputUpdateFcns off 667 | CombineSignalStateStructs off 668 | SuppressErrorStatus off 669 | IncludeFileDelimiter "Auto" 670 | ERTCustomFileBanners off 671 | SupportAbsoluteTime on 672 | LogVarNameModifier "rt_" 673 | MatFileLogging on 674 | MultiInstanceERTCode off 675 | CodeInterfacePackaging "Nonreusable function" 676 | SupportNonFinite on 677 | SupportComplex on 678 | PurelyIntegerCode off 679 | SupportContinuousTime on 680 | SupportNonInlinedSFcns on 681 | SupportVariableSizeSignals off 682 | ParenthesesLevel "Nominal" 683 | CastingMode "Nominal" 684 | MATLABClassNameForMDSCustomization "Simulink.SoftwareTarget.GRTCustomization" 685 | ModelStepFunctionPrototypeControlCompliant off 686 | CPPClassGenCompliant on 687 | AutosarCompliant off 688 | GRTInterface on 689 | GenerateAllocFcn off 690 | GenerateSharedConstants on 691 | UseMalloc off 692 | ExtMode off 693 | ExtModeStaticAlloc off 694 | ExtModeTesting off 695 | ExtModeStaticAllocSize 1000000 696 | ExtModeTransport 0 697 | ExtModeMexFile "ext_comm" 698 | ExtModeIntrfLevel "Level1" 699 | RTWCAPISignals off 700 | RTWCAPIParams off 701 | RTWCAPIStates off 702 | RTWCAPIRootIO off 703 | GenerateASAP2 off 704 | MultiInstanceErrorCode "Error" 705 | } 706 | PropName "Components" 707 | } 708 | } 709 | PropName "Components" 710 | } 711 | Name "Configuration" 712 | ExtraOptions "-aExprFoldComments=1 " 713 | CurrentDlgPage "Data Import//Export" 714 | ConfigPrmDlgPosition [ 338, 291, 1218, 921 ] 715 | } 716 | PropName "ConfigurationSets" 717 | } 718 | Simulink.ConfigSet { 719 | $PropName "ActiveConfigurationSet" 720 | $ObjectID 8 721 | } 722 | Object { 723 | $PropName "DataTransfer" 724 | $ObjectID 20 725 | $ClassName "Simulink.GlobalDataTransfer" 726 | DefaultTransitionBetweenSyncTasks "Ensure deterministic transfer (maximum delay)" 727 | DefaultTransitionBetweenAsyncTasks "Ensure data integrity only" 728 | DefaultTransitionBetweenContTasks "Ensure deterministic transfer (minimum delay)" 729 | DefaultExtrapolationMethodBetweenContTasks "None" 730 | AutoInsertRateTranBlk [0] 731 | } 732 | ExplicitPartitioning off 733 | BlockDefaults { 734 | ForegroundColor "black" 735 | BackgroundColor "white" 736 | DropShadow off 737 | NamePlacement "normal" 738 | FontName "Helvetica" 739 | FontSize 10 740 | FontWeight "normal" 741 | FontAngle "normal" 742 | ShowName on 743 | BlockRotation 0 744 | BlockMirror off 745 | } 746 | AnnotationDefaults { 747 | HorizontalAlignment "center" 748 | VerticalAlignment "middle" 749 | ForegroundColor "black" 750 | BackgroundColor "white" 751 | DropShadow off 752 | FontName "Helvetica" 753 | FontSize 10 754 | FontWeight "normal" 755 | FontAngle "normal" 756 | UseDisplayTextAsClickCallback off 757 | } 758 | LineDefaults { 759 | FontName "Helvetica" 760 | FontSize 9 761 | FontWeight "normal" 762 | FontAngle "normal" 763 | } 764 | MaskDefaults { 765 | SelfModifiable "off" 766 | IconFrame "on" 767 | IconOpaque "on" 768 | RunInitForIconRedraw "off" 769 | IconRotate "none" 770 | PortRotate "default" 771 | IconUnits "autoscale" 772 | } 773 | MaskParameterDefaults { 774 | Evaluate "on" 775 | Tunable "on" 776 | NeverSave "off" 777 | Internal "off" 778 | ReadOnly "off" 779 | Enabled "on" 780 | Visible "on" 781 | ToolTip "on" 782 | } 783 | BlockParameterDefaults { 784 | Block { 785 | BlockType ArgIn 786 | Port "1" 787 | OutMin "[]" 788 | OutMax "[]" 789 | OutDataTypeStr "double" 790 | LockScale off 791 | PortDimensions "1" 792 | SignalType "real" 793 | } 794 | Block { 795 | BlockType ArgOut 796 | Port "1" 797 | OutMin "[]" 798 | OutMax "[]" 799 | OutDataTypeStr "double" 800 | LockScale off 801 | PortDimensions "1" 802 | SignalType "real" 803 | } 804 | Block { 805 | BlockType Constant 806 | Value "1" 807 | VectorParams1D on 808 | SamplingMode "Sample based" 809 | OutMin "[]" 810 | OutMax "[]" 811 | OutDataTypeStr "Inherit: Inherit from 'Constant value'" 812 | LockScale off 813 | SampleTime "inf" 814 | FramePeriod "inf" 815 | PreserveConstantTs off 816 | } 817 | Block { 818 | BlockType DataStoreWrite 819 | DataStoreName "A" 820 | SampleTime "-1" 821 | } 822 | Block { 823 | BlockType FunctionCaller 824 | FunctionPrototype "y=f(x)" 825 | InputArgumentSpecifications "" 826 | OutputArgumentSpecifications "" 827 | SampleTime "-1" 828 | } 829 | Block { 830 | BlockType Inport 831 | Port "1" 832 | OutputFunctionCall off 833 | OutMin "[]" 834 | OutMax "[]" 835 | OutDataTypeStr "Inherit: auto" 836 | LockScale off 837 | BusOutputAsStruct off 838 | PortDimensions "-1" 839 | VarSizeSig "Inherit" 840 | SampleTime "-1" 841 | SignalType "auto" 842 | SamplingMode "auto" 843 | LatchByDelayingOutsideSignal off 844 | LatchInputForFeedbackSignals off 845 | Interpolate on 846 | } 847 | Block { 848 | BlockType ModelReference 849 | ModelNameDialog "" 850 | SimulationMode "Accelerator" 851 | CodeUnderTest "Model reference" 852 | Variant off 853 | GeneratePreprocessorConditionals off 854 | ContentPreviewEnabled off 855 | CopyOfModelProtected off 856 | CopyOfModelName "sl_subsys_for1" 857 | } 858 | Block { 859 | BlockType Outport 860 | Port "1" 861 | OutMin "[]" 862 | OutMax "[]" 863 | OutDataTypeStr "Inherit: auto" 864 | LockScale off 865 | BusOutputAsStruct off 866 | PortDimensions "-1" 867 | VarSizeSig "Inherit" 868 | SampleTime "-1" 869 | SignalType "auto" 870 | SamplingMode "auto" 871 | SourceOfInitialOutputValue "Dialog" 872 | OutputWhenDisabled "held" 873 | InitialOutput "[]" 874 | OutputWhenUnConnected off 875 | } 876 | Block { 877 | BlockType Product 878 | Inputs "2" 879 | Multiplication "Element-wise(.*)" 880 | CollapseMode "All dimensions" 881 | CollapseDim "1" 882 | InputSameDT on 883 | OutMin "[]" 884 | OutMax "[]" 885 | OutDataTypeStr "Inherit: Same as first input" 886 | LockScale off 887 | RndMeth "Zero" 888 | SaturateOnIntegerOverflow on 889 | SampleTime "-1" 890 | } 891 | Block { 892 | BlockType SubSystem 893 | ShowPortLabels "FromPortIcon" 894 | Permissions "ReadWrite" 895 | PermitHierarchicalResolution "All" 896 | TreatAsAtomicUnit off 897 | MinAlgLoopOccurrences off 898 | PropExecContextOutsideSubsystem off 899 | SystemSampleTime "-1" 900 | RTWSystemCode "Auto" 901 | RTWFcnNameOpts "Auto" 902 | RTWFileNameOpts "Auto" 903 | FunctionInterfaceSpec "void_void" 904 | FunctionWithSeparateData off 905 | RTWMemSecFuncInitTerm "Inherit from model" 906 | RTWMemSecFuncExecute "Inherit from model" 907 | RTWMemSecDataConstants "Inherit from model" 908 | RTWMemSecDataInternal "Inherit from model" 909 | RTWMemSecDataParameters "Inherit from model" 910 | SimViewingDevice off 911 | DataTypeOverride "UseLocalSettings" 912 | DataTypeOverrideAppliesTo "AllNumericTypes" 913 | MinMaxOverflowLogging "UseLocalSettings" 914 | Opaque off 915 | MaskHideContents off 916 | SFBlockType "NONE" 917 | Variant off 918 | GeneratePreprocessorConditionals off 919 | ContentPreviewEnabled off 920 | } 921 | Block { 922 | BlockType Sum 923 | IconShape "rectangular" 924 | Inputs "++" 925 | CollapseMode "All dimensions" 926 | CollapseDim "1" 927 | InputSameDT on 928 | AccumDataTypeStr "Inherit: Inherit via internal rule" 929 | OutMin "[]" 930 | OutMax "[]" 931 | OutDataTypeStr "Inherit: Same as first input" 932 | LockScale off 933 | RndMeth "Floor" 934 | SaturateOnIntegerOverflow on 935 | SampleTime "-1" 936 | } 937 | Block { 938 | BlockType ToFile 939 | Filename "untitled.mat" 940 | MatrixName "ans" 941 | SaveFormat "Array" 942 | Decimation "1" 943 | SampleTime "-1" 944 | } 945 | Block { 946 | BlockType TriggerPort 947 | TriggerType "rising" 948 | IsSimulinkFunction off 949 | StatesWhenEnabling "inherit" 950 | PropagateVarSize "During execution" 951 | ShowOutputPort off 952 | OutputDataType "auto" 953 | SampleTimeType "triggered" 954 | SampleTime "1" 955 | ZeroCross on 956 | PortDimensions "-1" 957 | TriggerSignalSampleTime "-1" 958 | OutMin "[]" 959 | OutMax "[]" 960 | OutDataTypeStr "Inherit: auto" 961 | Interpolate on 962 | } 963 | } 964 | System { 965 | Name "Demo2" 966 | Location [463, 145, 1450, 1090] 967 | Open off 968 | ModelBrowserVisibility off 969 | ModelBrowserWidth 200 970 | ScreenColor "white" 971 | PaperOrientation "landscape" 972 | PaperPositionMode "auto" 973 | PaperType "usletter" 974 | PaperUnits "inches" 975 | TiledPaperMargins [0.500000, 0.500000, 0.500000, 0.500000] 976 | TiledPageScale 1 977 | ShowPageBoundaries off 978 | ZoomFactor "193" 979 | ReportName "simulink-default.rpt" 980 | SIDHighWatermark "46" 981 | Block { 982 | BlockType Inport 983 | Name "In1" 984 | SID "46" 985 | Position [155, 133, 185, 147] 986 | ZOrder 335 987 | IconDisplay "Port number" 988 | OutDataTypeStr "uint16" 989 | PortDimensions "1" 990 | SampleTime "1" 991 | } 992 | Block { 993 | BlockType DataStoreWrite 994 | Name "Data Store\nWrite" 995 | SID "41" 996 | Ports [1] 997 | Position [395, 75, 460, 105] 998 | ZOrder 330 999 | DataStoreName "DataStore" 1000 | SampleTime "1" 1001 | } 1002 | Block { 1003 | BlockType FunctionCaller 1004 | Name "Function Caller" 1005 | SID "24" 1006 | Ports [1, 1] 1007 | Position [250, 117, 340, 163] 1008 | ZOrder 323 1009 | FunctionPrototype "y = f(u)" 1010 | InputArgumentSpecifications "uint16(1)" 1011 | OutputArgumentSpecifications "uint16(1)" 1012 | } 1013 | Block { 1014 | BlockType ModelReference 1015 | Name "Model" 1016 | SID "27" 1017 | Ports [0, 2] 1018 | Position [225, 204, 365, 266] 1019 | ZOrder 325 1020 | ModelNameDialog "sl_subsys_for1" 1021 | SimulationMode "Normal" 1022 | ContentPreviewEnabled on 1023 | ModelReferenceVersion "1.66" 1024 | List { 1025 | ListType OutputPortOutputBusAsStructs 1026 | port0 "off" 1027 | port1 "off" 1028 | } 1029 | CopyOfModelName "sl_subsys_for1" 1030 | } 1031 | Block { 1032 | BlockType SubSystem 1033 | Name "Simulink Function" 1034 | SID "19" 1035 | Ports [0, 0, 0, 1] 1036 | Position [245, 32, 345, 74] 1037 | ZOrder 322 1038 | TreatAsAtomicUnit on 1039 | RequestExecContextInheritance off 1040 | ContentPreviewEnabled on 1041 | System { 1042 | Name "Simulink Function" 1043 | Location [258, 83, 1354, 997] 1044 | Open off 1045 | ModelBrowserVisibility off 1046 | ModelBrowserWidth 200 1047 | ScreenColor "white" 1048 | PaperOrientation "landscape" 1049 | PaperPositionMode "auto" 1050 | PaperType "usletter" 1051 | PaperUnits "inches" 1052 | TiledPaperMargins [0.500000, 0.500000, 0.500000, 0.500000] 1053 | TiledPageScale 1 1054 | ShowPageBoundaries off 1055 | ZoomFactor "265" 1056 | Block { 1057 | BlockType TriggerPort 1058 | Name "f" 1059 | SID "20" 1060 | Ports [] 1061 | Position [210, 15, 230, 35] 1062 | ZOrder -2 1063 | ForegroundColor [0.078431, 0.380392, 0.305882] 1064 | TriggerType "function-call" 1065 | IsSimulinkFunction on 1066 | FunctionName "f" 1067 | StatesWhenEnabling "held" 1068 | } 1069 | Block { 1070 | BlockType Constant 1071 | Name "Constant1" 1072 | SID "40" 1073 | Position [75, 170, 105, 200] 1074 | ZOrder 9 1075 | OutDataTypeStr "uint16" 1076 | } 1077 | Block { 1078 | BlockType Constant 1079 | Name "Constant2" 1080 | SID "33" 1081 | Position [75, 220, 105, 250] 1082 | ZOrder 5 1083 | Value "2" 1084 | OutDataTypeStr "uint16" 1085 | } 1086 | Block { 1087 | BlockType Product 1088 | Name "Product" 1089 | SID "34" 1090 | Ports [3, 1] 1091 | Position [295, 49, 330, 271] 1092 | ZOrder 6 1093 | Inputs "**/" 1094 | InputSameDT off 1095 | OutDataTypeStr "uint16" 1096 | RndMeth "Floor" 1097 | SaturateOnIntegerOverflow off 1098 | } 1099 | Block { 1100 | BlockType Sum 1101 | Name "Sum" 1102 | SID "39" 1103 | Ports [2, 1] 1104 | Position [185, 150, 205, 170] 1105 | ZOrder 8 1106 | ShowName off 1107 | IconShape "round" 1108 | Inputs "|++" 1109 | InputSameDT off 1110 | OutDataTypeStr "Inherit: Inherit via internal rule" 1111 | SaturateOnIntegerOverflow off 1112 | } 1113 | Block { 1114 | BlockType ArgIn 1115 | Name "ArgIn1" 1116 | SID "21" 1117 | Position [70, 75, 110, 95] 1118 | ZOrder -4 1119 | DisableCoverage on 1120 | OutDataTypeStr "uint16" 1121 | ArgumentName "u" 1122 | } 1123 | Block { 1124 | BlockType ArgOut 1125 | Name "ArgOut1" 1126 | SID "22" 1127 | Position [385, 150, 425, 170] 1128 | ZOrder -5 1129 | DisableCoverage on 1130 | OutDataTypeStr "uint16" 1131 | ArgumentName "y" 1132 | } 1133 | Line { 1134 | ZOrder 16 1135 | SrcBlock "Product" 1136 | SrcPort 1 1137 | DstBlock "ArgOut1" 1138 | DstPort 1 1139 | } 1140 | Line { 1141 | ZOrder 28 1142 | SrcBlock "Constant2" 1143 | SrcPort 1 1144 | DstBlock "Product" 1145 | DstPort 3 1146 | } 1147 | Line { 1148 | ZOrder 41 1149 | SrcBlock "Sum" 1150 | SrcPort 1 1151 | DstBlock "Product" 1152 | DstPort 2 1153 | } 1154 | Line { 1155 | ZOrder 37 1156 | SrcBlock "ArgIn1" 1157 | SrcPort 1 1158 | Points [36, 0] 1159 | Branch { 1160 | ZOrder 47 1161 | Points [0, 75] 1162 | DstBlock "Sum" 1163 | DstPort 1 1164 | } 1165 | Branch { 1166 | ZOrder 38 1167 | DstBlock "Product" 1168 | DstPort 1 1169 | } 1170 | } 1171 | Line { 1172 | ZOrder 40 1173 | SrcBlock "Constant1" 1174 | SrcPort 1 1175 | DstBlock "Sum" 1176 | DstPort 2 1177 | } 1178 | Annotation { 1179 | SID "35" 1180 | Name "\n