classdef OptionalPortManager < handle
%OPTIONALPORTMANAGER Manage optional block inports/outports and labels
% OPM = OPTIONALPORTMANAGER(Name,Value) creates a utility object for
% programmatically adding/removing optional block inports/outports
% and their custom port label display.
%
% OPTIONALPORTMANAGER properties:
% BlockPath - Path of the block being managed
% UseMaskDisplay - Flag to use mask display
% MaskDisplayString - String for mask display
%
% OPTIONALPORTMANAGER methods:
% changeToInport - Change a block to an inport
% changeToGround - Change a block to a ground
% changeToConstant - Change a block to a constant
% changeToOutport - Change a block to an outport
% changeToTerminator - Change a block to a terminator
%
% Name-Value pair options:
% 'BlockPath' - Path of the block (default: gcb)
% 'FirstOptionalInport' - Number of first optional inport (default: 1)
% 'FirstOptionalOutport' - Number of first optional outport (default: 1)
% 'PermanentMaskDisplay' - Permanent mask display string (default: '')
%
% Example:
%
% blockDisplay = "fprintf('My Block');";
% blockDisplay = sprintf('%s\n%s', blockDisplay, "port_label('input',1,'u');");
% blockDisplay = sprintf('%s\n%s', blockDisplay, "port_label('output',1,'y');");
%
% portManager = OptionalPortManager('BlockPath',gcb,...
% 'FirstOptionalInport',2,...
% 'FirstOptionalOutport',2,...
% 'PermanentMaskDisplay',blockDisplay);
%
% if UseInportABC
% portManager.changeToInport('abc','PortDimensions','[1 1]','SampleTime','Ts');
% else
% portManager.changeToGround('abc');
% end
%
% if UseOutportXYZ
% portManager.changeToOutport('xyz','Label','XYZ_{K}','TexMode','on');
% else
% portManager.changeToTerminator('xyz');
% end
% Copyright 2025 The MathWorks, Inc.
%% Properties
properties (SetAccess = private)
BlockPath (1,1) string = ""
MaskDisplayString (1,1) string = ""
end
properties (SetAccess=immutable)
UseMaskDisplay (1,1) logical = true
end
properties (Access = private)
Inport (1,1) double {mustBePositive,mustBeInteger} = 1
Outport (1,1) double {mustBePositive,mustBeInteger} = 1
end
methods
function obj = OptionalPortManager(arguments)
%OPTIONALPORTMANAGER Construct an instance of this class
% OBJ = OPTIONALPORTMANAGER(ARGUMENTS) creates an OptionalPortManager
% object with the specified name-value pair arguments.
%
% Name-Value pair arguments:
% 'BlockPath' - Path of the block (default: gcb)
% 'FirstOptionalInport' - Number of first optional inport (default: 1)
% 'FirstOptionalOutport' - Number of first optional outport (default: 1)
% 'PermanentMaskDisplay' - Permanent mask display string (default: '')
%
% See also OPTIONALPORTMANAGER
arguments
arguments.BlockPath (1,1) string = gcb()
arguments.FirstOptionalInport (1,1) double {mustBePositive,mustBeInteger} = 1
arguments.FirstOptionalOutport (1,1) double {mustBePositive,mustBeInteger} = 1
arguments.PermanentMaskDisplay (1,1) string = ""
end
obj.BlockPath = arguments.BlockPath;
obj.Inport = arguments.FirstOptionalInport;
obj.Outport = arguments.FirstOptionalOutport;
obj.MaskDisplayString = arguments.PermanentMaskDisplay;
obj.UseMaskDisplay = strlength(obj.MaskDisplayString)~=0;
% always reset mask display first to avoid warning
if obj.UseMaskDisplay
maskobj = get_param(obj.BlockPath,'MaskObject');
maskobj.Display = "";
end
end
end
%% Public methods
methods
function h = changeToInport(obj, name, arguments)
%CHANGETOINPORT Change a block to an inport
% H = CHANGETOINPORT(OBJ, NAME, ARGUMENTS) changes the specified
% block to an inport and returns its handle.
%
% Name-Value pair arguments:
% 'PortDimensions' - Dimensions of the port (default: '-1')
% 'OutDataTypeStr' - Output data type (default: 'Inherit: auto')
% 'SignalType' - Signal type (default: 'auto')
% 'SampleTime' - Sample time (default: '-1')
% 'Label' - Port label (default: '')
% 'TexMode' - TeX mode for label (default: 'off')
%
% See also OPTIONALPORTMANAGER
arguments
obj (1,1) slcontrollib.internal.maskutils.OptionalPortManager
name (1,1) string
arguments.PortDimensions (1,1) string = '-1'
arguments.OutDataTypeStr (1,1) string = 'Inherit: auto'
arguments.SignalType (1,1) string = 'auto'
arguments.SampleTime (1,1) string = '-1'
arguments.Label (1,1) string = name
arguments.TexMode (1,1) string {mustBeMember(arguments.TexMode,["on";"off"])} = 'off'
end
%% append mask display
obj.MaskDisplayString = sprintf('%s\n%s',obj.MaskDisplayString,...
"port_label('input',"+obj.Inport+",'"+arguments.Label+...
"','texmode','"+arguments.TexMode+"');");
%% replace ground/constant block with inport block when needed
block = obj.BlockPath+"/"+name;
if ~strcmp(get_param(block,"BlockType"),'Inport')
slInternal('replace_block',block,'built-in/Inport');
end
arguments.Port = num2str(obj.Inport);
arguments = rmfield(arguments,["Label";"TexMode"]);
obj.safeSetParam(block,arguments);
%% increase optional port number, return block handle and update mask display
obj.Inport = obj.Inport + 1;
h = get_param(block,'Handle');
updateMaskDisplay(obj);
end
function h = changeToGround(obj, name)
%CHANGETOGROUND Change a block to a ground
% H = CHANGETOGROUND(OBJ, NAME) changes the specified block to a
% ground block and returns its handle.
%
% See also OPTIONALPORTMANAGER
arguments
obj (1,1) slcontrollib.internal.maskutils.OptionalPortManager
name (1,1) string
end
%% replace inport block with ground block only when needed
block = obj.BlockPath+"/"+name;
if ~strcmp(get_param(block,"BlockType"),'Ground')
slInternal('replace_block',block,'built-in/Ground');
end
%% return block handle and update mask display
h = get_param(block,'Handle');
updateMaskDisplay(obj);
end
function h = changeToConstant(obj, name, arguments)
%CHANGETOCONSTANT Change a block to a constant
% H = CHANGETOCONSTANT(OBJ, NAME, ARGUMENTS) changes the specified
% block to a constant block and returns its handle.
%
% Name-Value pair arguments:
% 'Value' - Constant value (default: '1')
% 'SampleTime' - Sample time (default: 'inf')
% 'VectorParams1D' - 1-D vector parameters (default: 'on')
% 'OutDataTypeStr' - Output data type (default: "Inherit: Inherit from 'Constant value'")
%
% See also OPTIONALPORTMANAGER
arguments
obj (1,1) slcontrollib.internal.maskutils.OptionalPortManager
name (1,1) string
arguments.Value (1,1) string = '1'
arguments.SampleTime (1,1) string = 'inf'
arguments.VectorParams1D (1,1) string = 'on'
arguments.OutDataTypeStr (1,1) string = "Inherit: Inherit from 'Constant value'"
end
%% replace inport block with constant block only when needed
block = obj.BlockPath+"/"+name;
if ~strcmp(get_param(block,"BlockType"),'Constant')
slInternal('replace_block',block,'built-in/Constant');
end
obj.safeSetParam(block,arguments);
%% return block handle and update mask display
h = get_param(block,'Handle');
updateMaskDisplay(obj);
end
function h = changeToOutport(obj, name, arguments)
%CHANGETOOUTPORT Change a block to an outport
% H = CHANGETOOUTPORT(OBJ, NAME, ARGUMENTS) changes the specified
% block to an outport and returns its handle.
%
% Name-Value pair arguments:
% 'PortDimensions' - Dimensions of the port (default: '-1')
% 'OutDataTypeStr' - Output data type (default: 'Inherit: auto')
% 'SignalType' - Signal type (default: 'auto')
% 'SampleTime' - Sample time (default: '-1')
% 'Label' - Port label (default: '')
% 'TexMode' - TeX mode for label (default: 'off')
%
% See also OPTIONALPORTMANAGER
arguments
obj (1,1) slcontrollib.internal.maskutils.OptionalPortManager
name (1,1) string
arguments.PortDimensions (1,1) string = '-1'
arguments.OutDataTypeStr (1,1) string = 'Inherit: auto'
arguments.SignalType (1,1) string = 'auto'
arguments.SampleTime (1,1) string = '-1'
arguments.Label (1,1) string = name
arguments.TexMode (1,1) string {mustBeMember(arguments.TexMode,["on";"off"])} = 'off'
end
%% append mask display
obj.MaskDisplayString = sprintf('%s\n%s',obj.MaskDisplayString,...
"port_label('output',"+obj.Outport+",'"+arguments.Label+...
"','texmode','"+arguments.TexMode+"');");
%% replace terminator block with inport block only when needed
block = obj.BlockPath+"/"+name;
if ~strcmp(get_param(block,"BlockType"),'Outport')
slInternal('replace_block',block,'built-in/Outport');
end
arguments.Port = num2str(obj.Outport);
arguments = rmfield(arguments,["Label";"TexMode"]);
obj.safeSetParam(block,arguments);
%% increase optional port number, return block handle and update mask display
obj.Outport = obj.Outport + 1;
h = get_param(block,'Handle');
updateMaskDisplay(obj);
end
function h = changeToTerminator(obj, name)
%CHANGETOTERMINATOR Change a block to a terminator
% H = CHANGETOTERMINATOR(OBJ, NAME) changes the specified block to a
% terminator block and returns its handle.
%
% See also OPTIONALPORTMANAGER
arguments
obj (1,1) slcontrollib.internal.maskutils.OptionalPortManager
name (1,1) string
end
%% replace outport block with terminator block only when needed
block = obj.BlockPath+"/"+name;
if ~strcmp(get_param(block,"BlockType"),'Terminator')
slInternal('replace_block',block,'built-in/Terminator');
end
%% return block handle and update mask display
h = get_param(block,'Handle');
updateMaskDisplay(obj);
end
end
%% Private methods
methods (Access = private)
function updateMaskDisplay(obj)
%% set mask display with custom mask icon and port labels
maskObj = get_param(obj.BlockPath,'MaskObject');
if obj.UseMaskDisplay
maskObj.Display = sprintf('%s',obj.MaskDisplayString);
else
maskObj.Display = "";
end
end
end
%% Static private methods
methods (Access=private,Static)
function safeSetParam(block,paramStruct)
%% set parameters without erroring
paramStruct = namedargs2cell(paramStruct);
try %#ok<TRYNC>
set_param(block,paramStruct{:});
end
end
end
end