-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from McSCert/subsys-to-simfunc
Functionality to convert a Subsystem to a Simulink Function
- Loading branch information
Showing
5 changed files
with
322 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
function goodName = isGoodSimFcnName(subsystem, simulinkFcnName) | ||
% isGoodSimFcnName Checks to see if a Simulink Function name is the | ||
% same as any other Simulink Functions in scope at | ||
% the current subsystem level | ||
% Inputs: | ||
% subsystem Path of a subsystem where a Simulink Function | ||
% will be added | ||
% simulinkFcnName Name of the Simulink Function to be added | ||
% | ||
% Outputs: | ||
% goodName Name can be used(1) or not(0) | ||
% | ||
% Example: | ||
% isGoodSimFcnName('SubSystem_Name', 'SimFcnName') | ||
% | ||
% ans = 1 | ||
|
||
% Get callable Simulink Functions at the current scope | ||
[~, prototype] = getCallableFunctions(subsystem); | ||
|
||
% Get the prototype names | ||
prototypeNames = getPrototypeName(prototype); | ||
|
||
% Make sure the prototype name is a cell | ||
if ~iscell(prototypeNames) | ||
prototypeNames = {prototypeNames}; | ||
end | ||
|
||
result = zeros(1, length(prototypeNames)); | ||
|
||
% Loop through each prototype name | ||
for name = 1:length(prototypeNames) | ||
% Compare to the input name | ||
result(name) = ~strcmp(simulinkFcnName, prototypeNames{name}); | ||
end | ||
% Return true if none of the prototype names are the same as the input name | ||
goodName = all(result); | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
function b = isSubsystem(blocks) | ||
% ISSUBSYSTEM Determine if the block is a subsystem. | ||
% | ||
% Inputs: | ||
% block Pathname or handle of a block. | ||
% | ||
% Outputs: | ||
% b Whether the block is a subsystem(1) or not(0). | ||
|
||
% Convert the input to handles | ||
blocks = inputToNumeric(blocks); | ||
|
||
b = zeros(1, length(blocks)); | ||
% Check each block to see if its a subsystem | ||
for block = 1:length(blocks) | ||
try | ||
blockType = get_param(blocks(block), 'BlockType'); | ||
b(block) = strcmpi(blockType, 'SubSystem'); | ||
catch % Unexpected error | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
function simulinkFcnName = reqSimFcnName() | ||
% getSimFcnName Prompts the user for an input Simulink Function name | ||
% until a name is entered which is not the same as | ||
% another Simulink Function in scope | ||
% | ||
% Inputs: | ||
% N/A | ||
% | ||
% Outputs: | ||
% simulinkFcnName Char array which represents a Simulink Function name | ||
% | ||
% Example: | ||
% simulinkFcnName = getSimFcnName() | ||
% | ||
% ans = 'Function_Name' | ||
|
||
%% Dialog Box Parameters | ||
prompt = 'Enter a name for the Simulink Function: '; | ||
dlgtitle = 'Convert Subsystem'; | ||
dims = [1 50]; | ||
definput = {'f'}; | ||
|
||
%% Checking Input | ||
% Loop until the input name is acceptable | ||
while 1 | ||
inputName = inputdlg(prompt, dlgtitle, dims, definput); | ||
% Checks to see if the name shadows other names in scope | ||
if isGoodSimFcnName(gcs, inputName{1}) | ||
break | ||
else | ||
waitfor(msgbox([inputName{1}, ... | ||
' is already used as a Simulink Function in scope.', ... | ||
newline, newline, 'Please enter a new name.'], dlgtitle)); | ||
end | ||
end | ||
simulinkFcnName = inputName{1}; | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
function subToSimFcn(subsystem, simulinkFcnName, visibility) | ||
% subToSimFunc Converts a subsystem to a Simulink Function | ||
% | ||
% Inputs: | ||
% subsystem Path of a subsystem to be converted | ||
% simulinkFcnName Name of the Simulink Function to be created | ||
% visibility Set function visibility to'scoped' or 'global' | ||
% | ||
% Outputs: | ||
% N/A | ||
% | ||
% Example: | ||
% subToSimFunc('Demo_Example/f_Sensor_Trip_1', 'f_Sensor_Trip_i', 'scoped') | ||
% | ||
% Converts 'f_Sensor_Trip_1' subsystem to a | ||
% scoped Simulink Function 'f_SensorTrip_i' | ||
|
||
%% Input Validation | ||
|
||
% Check that the subsystem is loaded | ||
try | ||
assert(ischar(subsystem)); | ||
assert(bdIsLoaded(bdroot(subsystem))); | ||
catch | ||
error('Invalid subsystem. Model may not be loaded or name is invalid.'); | ||
end | ||
|
||
% Check that the function name is valid | ||
try | ||
assert(isvarname(simulinkFcnName)); | ||
catch | ||
error('Invalid function name. Use a valid MATLAB variable name.'); | ||
end | ||
|
||
% Check that the function visibility is valid | ||
try | ||
assert(strcmp(visibility, 'scoped') || strcmp(visibility, 'global')); | ||
catch | ||
error('Invalid function visibility. Use scoped/global visibility.'); | ||
end | ||
|
||
%% Add Trigger to Subsystem | ||
|
||
% Break library link | ||
set_param(subsystem, 'LinkStatus', 'none'); | ||
|
||
% Adding the trigger block to the subsystem and calibrating its parameters | ||
triggerPath = append(subsystem, '/', simulinkFcnName); | ||
add_block('simulink/Ports & Subsystems/Trigger', triggerPath); | ||
set_param(triggerPath, 'TriggerType', 'function-call', ... | ||
'IsSimulinkFunction', 'on', 'FunctionName', simulinkFcnName, ... | ||
'FunctionVisibility', visibility); | ||
|
||
% Set subsystem to atomic execution | ||
set_param(subsystem, 'TreatAsAtomicUnit', 'on'); | ||
|
||
%% Convert Inports to ArgIns | ||
|
||
% Create array of all the inports in the subsystem | ||
allInports = find_system(subsystem, 'SearchDepth', 1, ... | ||
'BlockType', 'Inport'); | ||
|
||
% Getting the parameters for all inports in the subsystem | ||
inportParameters = getPortParameters(allInports); | ||
|
||
% Replace inports with argument inputs | ||
replace_block(subsystem, 'SearchDepth', 1, ... | ||
'BlockType', 'Inport', 'ArgIn', 'noprompt'); | ||
|
||
% Create array of all the argIns in the Simulink Function | ||
allArgIns = find_system(subsystem, 'SearchDepth', 1, 'BlockType', 'ArgIn'); | ||
|
||
% Setting the parameters for all the argument inputs | ||
setArgumentParameters(allArgIns, inportParameters); | ||
|
||
%% Convert Outports to ArgOuts | ||
|
||
% Create array of all the outports in the subsystem | ||
allOutports = find_system(subsystem, 'SearchDepth', 1, ... | ||
'BlockType', 'Outport'); | ||
|
||
% Getting the parameters for all outports in the subsystem | ||
outportParameters = getPortParameters(allOutports); | ||
|
||
% Replace outports with argument outputs | ||
replace_block(subsystem, 'SearchDepth', 1, ... | ||
'BlockType', 'Outport', 'ArgOut', 'noprompt'); | ||
|
||
% Create array of all the argOuts for the Simulink Function | ||
allArgOuts = find_system(subsystem, 'SearchDepth', 1, ... | ||
'BlockType', 'ArgOut'); | ||
|
||
% Setting the parameters for all the argument outputs | ||
setArgumentParameters(allArgOuts, outportParameters); | ||
end | ||
|
||
function parameters = getPortParameters(ports) | ||
% getPortParameters Returns the parameters for an inport or outport | ||
% | ||
% Inputs: | ||
% ports Cell array of inports or outports | ||
% | ||
% Outputs: | ||
% parameters Cell array of parameters including: | ||
% 1) Port | ||
% 2) OutMin | ||
% 3) OutMax | ||
% 4) OutDataTypeStr | ||
% 5) LockScale | ||
% 6) PortDimensions | ||
% 7) ArgumentName | ||
% | ||
% Example: | ||
% parameters = getPortParameters({'System/Subsystem/Inport1'}) | ||
% | ||
% ans = | ||
% 1x7 cell array | ||
% {'1'} {'[]'} {'[]'} {'boolean'} {'off'} {'on'} {'Inport1'} | ||
|
||
%% Get the port parameters | ||
% Init array of parameters for the ports | ||
parameters = cell(length(ports), 7); | ||
% Loop through each port | ||
for port = 1:length(ports) | ||
% Get the port name by splitting the pathname by the backslash | ||
splitPortPath = split(ports{port}, '/'); | ||
% The port name is the last index of splitPortPath | ||
portName = splitPortPath{end}; | ||
% Get the port number | ||
parameters{port, 1} = get_param(ports{port}, 'Port'); | ||
% Get the port minimum output | ||
parameters{port, 2} = get_param(ports{port}, 'OutMin'); | ||
% Get the port maximum output | ||
parameters{port, 3} = get_param(ports{port}, 'OutMax'); | ||
% Get the port data type | ||
parameters{port, 4} = get_param(ports{port}, 'OutDataTypeStr'); | ||
% If data type is set to inherit, set to double by default | ||
try | ||
assert(not(strcmp(parameters{port, 4}, 'Inherit: auto'))); | ||
catch | ||
disp([portName, ... | ||
' data type was set to ''Inherit: auto''', ... | ||
' - setting to ''double''...']); | ||
parameters{port, 4} = 'double'; | ||
end | ||
% Get the port lock scale | ||
parameters{port, 5} = get_param(ports{port}, 'LockScale'); | ||
% Get the port dimension | ||
parameters{port, 6} = get_param(ports{port}, 'PortDimensions'); | ||
% If port dimension is set to inherit, set to 1 by default | ||
try | ||
assert(not(strcmp(parameters{port, 6}, '-1'))) | ||
catch | ||
disp([portName, ... | ||
' dimension was set to ''-1''', ... | ||
' - setting to ''1''...']); | ||
parameters{port, 6} = '1'; | ||
end | ||
% Remove spaces from port name to create a valid variable name | ||
parameters{port, 7} = genvarname(portName); | ||
end | ||
end | ||
|
||
function setArgumentParameters(arguments, parameters) | ||
% setArgumentParameters Sets argIn or ArgOut parameters | ||
% | ||
% Inputs: | ||
% arguments Cell array of argIns or argOuts | ||
% parameters Cell array of parameters for each argument | ||
% | ||
% Outputs: | ||
% N/A | ||
% | ||
% Example: | ||
% setArgumentParameters({'System/Subsystem/argIn1'}, ... | ||
% {'1', '[]', '[]', 'boolean', 'off', 'on', 'Inport1'}) | ||
|
||
%% Set the argument parameters | ||
% Loop through each argument | ||
for arg = 1:length(arguments) | ||
% Set the parameters for each argument | ||
set_param(arguments{arg}, 'Port', parameters{arg, 1}, ... | ||
'OutMin', parameters{arg, 2}, ... | ||
'OutMax', parameters{arg, 3}, ... | ||
'OutDataTypeStr', parameters{arg, 4}, ... | ||
'LockScale', parameters{arg, 5}, ... | ||
'PortDimensions', parameters{arg, 6}, ... | ||
'ArgumentName', parameters{arg, 7}); | ||
end | ||
end |