classdef TopModelSILPIL < handle
%TOPMODELSILPIL Utilities for Top-model SIL/PIL
%
% This is an undocumented class. Its methods and properties are likely to
% change without warning from one release to the next.

% Copyright 2020 The MathWorks, Inc.

properties (Constant=true, GetAccess=public)
% TODO: unify all code that tests for this description
TopModelXILHarnessDescripton = 'Temporary wrapper for PIL simulation';
end

properties (Constant, Access = 'private')
% map to allow lookup of the active wrapper model for a given
% top-model
WrapperModelMap = containers.Map;
end

methods (Static, Access = 'private')

function tree = getTree(blk)
% Get the block mf0 information about the interface
block = Simulink.BlockDiagram.Internal.getInterfaceModelBlock( get_param(blk,'Handle') );
% Get access to the hierarchy via the port information
tree = block.port.tree;
end

end

methods (Static)
function isTopModelXILHarness = isTopModelXILHarness(model)
% check for the model description that defines the top-model
% SIL/PIL harness model
isTopModelXILHarness = strcmp(get_param(model, 'Description'), ...
coder.connectivity.TopModelSILPIL.TopModelXILHarnessDescripton);
end

function wrapperModel = getWrapperModel(model)
% return the top-model SIL/PIL wrapper model for a given model
wrapperModelMap = coder.connectivity.TopModelSILPIL.WrapperModelMap;
if wrapperModelMap.isKey(model)
wrapperModel = wrapperModelMap(model);
else
wrapperModel = '';
end
end

function updateWrapperModelMap(model, wrapperModel)
% store the association between a model and its top-model
% SIL/PIL wrapper model
wrapperModelMap = coder.connectivity.TopModelSILPIL.WrapperModelMap;
if isempty(wrapperModel) && wrapperModelMap.isKey(model)
wrapperModelMap.remove(model);
else
wrapperModelMap(model) = wrapperModel; %#ok<NASGU>
end
end

% methods for bus element ports

function termBlkH = addTerminatorBlock(model, blkPosn)

% Create terminator block
termName = 'Terminator';
termBlk = [model '/' termName];
termBlkH = add_block('simulink/Sinks/Terminator', termBlk,...
'MakeNameUnique', 'on', 'Position', (blkPosn) );
end

function busSelector = addBusSelectorBlock(model, signals, busPosn)

blockName = [model '/' 'BusSelector'];
busSelector = add_block('simulink/Signal Routing/Bus Selector',...
blockName, 'MakeNameUnique', 'on', 'Position', busPosn);

% For the selector, set signal names and number of signals
selectorStr=strjoin(signals,',');
set_param(busSelector,'OutputSignals',selectorStr);

end

function bep = addBusElementBlock( modelName, dstBlk, portType, portName, element, blkPosn)
% Create In/Out Bus Element block on port identified by name.

% Pick if bus element inport or outport
if strcmp(portType,'In')
bepBlockName = 'simulink/Sources/In Bus Element';
else
bepBlockName = 'simulink/Sinks/Out Bus Element';
end

% Find other buses on port 'portName'
bepsOnPort = find_system(modelName,'FirstResultOnly','on','SearchDepth',1,'PortName',portName,...
'IsBusElementPort','on','Type','Block');

if isempty(bepsOnPort)
% If no bus element has been created for that port in the wrapper
% system, then create a new bus element on new port
bep = add_block(bepBlockName, dstBlk, 'PortName', portName,...
'Element',element, 'Position', blkPosn, 'MakeNameUnique','on',...
'CreateNewPort', 'on', 'OutDataTypeStr', 'Inherit: auto');
else
% If port has already been used, copy that old bus element to ensure
% that this bus element is created on same port
bep = add_block(bepsOnPort{1}, dstBlk, 'Element', element,...
'Position', blkPosn, 'MakeNameUnique','on', 'OutDataTypeStr', 'Inherit: auto');
end

end

function node = getTreeNode(mdlSrcBlk, element)
% Get the node for a given element in the BEP tree hierarchy

tree = coder.connectivity.TopModelSILPIL.getTree(mdlSrcBlk);
% Get the node for this signal
node = Simulink.internal.CompositePorts.TreeNode.findNode(tree, element);

end

function elements = getBusElementsFromTree(mdlSrcBlk)
% Get a list of all elements registered in the bus hierarchy

srcTree = coder.connectivity.TopModelSILPIL.getTree(mdlSrcBlk);
elements = Simulink.internal.CompositePorts.TreeNode.getDotStringsFromTree(srcTree);

end
end
end