classdef (Hidden = true) ModelBlockPIL < handle
%MODELBLOCKPIL code generation entry point into Model block PIL
%
%   This is an undocumented class. Its methods and properties are likely to
%   change without warning from one release to the next.

%   Copyright 2008-2020 The MathWorks, Inc.

    
    methods (Static = true)

        function XILErrorCheckHook(iMdl, iXilMdlBlks, runChecksForProtectedModels, isUpdateDiagram)
            % Called from ModelRefCompileHierarchy.cpp to apply 
            % error checks before any SIM/RTW targets are built.                                   
             
            % enforce that there must always be blocks to process
            assert(~isempty(iXilMdlBlks), 'No pil/sil Model blocks to process');
                   
            % validate referenced model configuration will build
            % successfully
            rtw.pil.ModelBlockPIL.RTWErrorCheckHookModelConfig(iMdl, iXilMdlBlks);
            
            % apply coverage and profiling validation checks
            rtw.pil.ModelBlockPIL.RTWErrorCheckHookCoverage(iMdl, iXilMdlBlks);
            rtw.pil.ModelBlockPIL.RTWErrorCheckHookProfiling(iMdl, iXilMdlBlks); 
            
            % apply validation for each referenced component
            processedComponentList = {};
            processedTargetServices = {};
            
            isRLS = rtw.pil.ModelBlockPIL.isRLS(iMdl);
            for i=1:length(iXilMdlBlks)
                xilModelBlock = iXilMdlBlks(i);
                
                isProtected = rtw.pil.ModelBlockPIL.isModelProtected(xilModelBlock);
                if isProtected && ~runChecksForProtectedModels
                    % For protected models, delay running the checks until
                    % the protected models are unpacked (and thus the
                    % serialized configSet is available). These checks will
                    % run again when we call XILBuildHook from
                    % NormalModeCompileManager.cpp (at which point the
                    % protected models are unpacked).
                    continue;
                end
                                                              
                
                % create configInterface object:
                % For protected models, the model is not available, so we
                % load up the serialized configSet in binfo.
                %
                % For non-protected models, the model is available, so we
                % can get its active configset.
                isModelReferenceTarget = ...
                    rtw.pil.ModelBlockPIL.isModelReferenceTarget(xilModelBlock);
                [configInterface,xilComponent] =...
                    rtw.pil.ModelBlockPIL.createConfigInterfaceModelBlock(xilModelBlock,...
                    isModelReferenceTarget);
                
                
                if isModelReferenceTarget
                   componentSuffix = '_mdlref'; 
                else
                   componentSuffix = '_stdalone'; 
                end                
                fullComponent = [xilComponent componentSuffix];                
                                                                
                if ~any(strcmp(processedComponentList, fullComponent))
                    rtw.pil.ModelBlockPIL.checkERTTargetOrGRTTarget(configInterface);
                    
                    % error checks for protected models
                    if isProtected
                        rtw.pil.ModelBlockPIL.RTWErrorCheckProtectedModel(iMdl, xilModelBlock);
                    end
                    
                    if ~isModelReferenceTarget                                               
                        % apply AUTOSAR shared validation
                        rtw.pil.AutosarTargetInterface.sharedValidation(configInterface);  
                       
                        % For standalone targets we need to handle logging
                        % checks in MATLAB code because the build does not 
                        % do this for us.
                        %
                        % If not protected, then by getting the config
                        % interface, we have loaded the model.
                        rtw.pil.ModelBlockPIL.standaloneDataLoggingValidation(xilComponent, isProtected);
                        
                    end
                    processedComponentList{end+1} = fullComponent; %#ok<AGROW>                    
                end                

                % Since the model might be protected, obtain the configset
                % with compiler information via configInterface
                cs = getConfig(configInterface);
            
                % Determine compiler information based on default mex configuration.
                % The DefaultCompInfo object must be instantiated only at the beginning
                % of the build and before any change of pwd. If default mex setup is
                % queried later in the build process after changing pwd it will not
                % pick up any mex configuration file in the original pwd.
                lDefaultMexCompInfo = coder.internal.DefaultCompInfo.createDefaultCompInfo;
                
                isSIL = rtw.pil.ModelBlockPIL.isSIL(xilModelBlock);
                lXilCompInfo = i_getXilCompInfo(isSIL, cs, lDefaultMexCompInfo);                
                
                % Validate the connectivity configuration for the model
                % block.
                isReadOnly = rtw.pil.ModelBlockPIL.isReadOnly(isRLS, isProtected);
                processedTargetServices = ...
                    rtw.pil.ModelBlockPIL.RTWErrorCheckHookTargetServices( ...
                    xilModelBlock, configInterface, ...
                    processedTargetServices, isUpdateDiagram, lXilCompInfo, isReadOnly);
            end
        end
        
            
        function validateConfigration(isSIL, configInterface, xilCompInfo, isProtectedModel, isReadOnly)

            if isSIL
                rtw.pil.ModelBlockPIL.checkSilCompatibility(configInterface, isProtectedModel, isReadOnly, xilCompInfo);
            else
                rtw.pil.ModelBlockPIL.checkPilCompatibility(configInterface, isReadOnly)
            end
        end
            
        function XILBuildHook(iMdl, iXilMdlBlkPaths, buildXILApplication, varargin)
            % Called from NormalModeCompileManager.cpp to build the SIL/PIL
            % wrapper for a set of Model blocks in SIL/PIL mode.                        
            
            %
            % code below written to support multi instance
            %
            
            % Repeat the error checking, since we after multi-instance
            % normal mode has made copied models.  We may catch 
            % multi-instance errors that aren't easily caught before
            % expansion
            % 
            % The other use-case for running these checks again is
            % protected models, since at this point, the slxp files should
            % have been unpacked by the build process (and thus the
            % serialized configSet is available)
                        
            % iXilMdlBlkPaths contains the full paths (crossing model reference
            % boundaries) of each model block under XIL.
            %
            % The last element of the model block paths in iXilMdlBlkPaths
            % contains the block path of the model block under XIL from its
            % parent model. Strip the final elements from the paths to validate
            % the model blocks in XIL mode.
            
            iXilMdlBlks = cellfun(@(p) p(end), iXilMdlBlkPaths);
            
            runChecksForProtectedModels = true;
            
            % skip XILErrorCheckHook for top-model SIL/PIL because the
            % necessary checks have already been done in build_pil_target.m
            isTopModelXILSim = coder.connectivity.TopModelSILPIL.isTopModelXILHarness(iMdl);                            
            if ~isTopModelXILSim
                rtw.pil.ModelBlockPIL.XILErrorCheckHook(iMdl, iXilMdlBlks,...
                    runChecksForProtectedModels, ~buildXILApplication);
            end
            
            p = inputParser();
            p.KeepUnmatched = true;
            p.addParameter('TopModelAccelWithProfiling', false, @islogical);
            p.addParameter('CodeProfilingSaveOptionsAllDataTop', 'SummaryOnly', @ischar);
            p.parse(varargin{1:end});
            if p.Results.TopModelAccelWithProfiling
                topModelOriginalParams = containers.Map('KeyType', 'char', 'ValueType', 'any');
                topModelOriginalParams('CodeExecutionProfiling') = 'on';
                topModelOriginalParams('CodeProfilingSaveOptions') = p.Results.CodeProfilingSaveOptionsAllDataTop;
            else
                topModelOriginalParams = [];
            end
            
            % Determine compiler information based on default mex configuration.
            % The DefaultCompInfo object must be instantiated only at the beginning
            % of the build and before any change of pwd. If default mex setup is
            % queried later in the build process after changing pwd it will not
            % pick up any mex configuration file in the original pwd.
            lMexCompInfoDefault = coder.internal.DefaultCompInfo.createDefaultCompInfo;
            
            % keep track of which referenced models we built PIL
            % applications for
            builtComponentList = {};
            for i=1:length(iXilMdlBlkPaths)
                xilModelBlockPath = iXilMdlBlkPaths{i};
                xilModelBlock = xilModelBlockPath(end);
                isModelReferenceTarget = ...
                    rtw.pil.ModelBlockPIL.isModelReferenceTarget(xilModelBlock);
                
                % create configInterface object:
                % For protected models, the model is not available, so we
                % load up the serialized configSet in binfo.
                %
                % For non-protected models, the model is available, so we
                % can get its active configset.
                if isModelReferenceTarget
                   componentSuffix = '_mdlref'; 
                else
                   componentSuffix = '_stdalone'; 
                end
                [configInterface, xilComponent] =...
                    rtw.pil.ModelBlockPIL.createConfigInterfaceModelBlock(xilModelBlock,...
                    isModelReferenceTarget);        

                % Since the model might be protected, obtain the configset
                % with compiler information via configInterface
                cs = getConfig(configInterface);

                isSIL = rtw.pil.ModelBlockPIL.isSIL(xilModelBlock);
                lXilCompInfo = i_getXilCompInfo(isSIL, cs, lMexCompInfoDefault);

                fullComponent = [xilComponent componentSuffix];                   
                % retrieve the PIL interface object (cached in the Model
                % block's PILData)
                pilInterface = rtw.pil.ModelBlockPIL.getPILInterface...
                    (xilModelBlockPath, configInterface, iMdl, topModelOriginalParams, ...
                    buildXILApplication, lXilCompInfo);
                % make sure application is up to date, but don't do this 
                % repeatedly for the same application
                if ~any(strcmp(builtComponentList, fullComponent))
                    if buildXILApplication
                        if isSIL
                            disp('### Preparing to start SIL simulation ...');
                        else
                            disp('### Preparing to start PIL simulation ...');
                        end
                    end
                    % bring the wrapper up to date
                    isPILBlockConfigure = false;
                    buildSFunctionOnly = ~buildXILApplication;
                    pilInterface.buildWrapper...
                        (isPILBlockConfigure, buildSFunctionOnly, lXilCompInfo, ...
                         lMexCompInfoDefault.DefaultMexCompilerKey);
                    
                    % bring the application up to date
                    if buildXILApplication
                        % Do deferred validation checks validation checks
                        pilInterface.getSILPILWrapperUtils.runDeferredValidation;
                        buildApplication(pilInterface, lXilCompInfo, ...
                            lMexCompInfoDefault.DefaultMexCompilerKey);
                    end
                    builtComponentList{end+1} = fullComponent; %#ok<AGROW>
                end
                % download will be performed dynamically in
                % rtw.pil.ComponentBridge on receipt of "PIL_INIT_COMMAND"
            end
        end  
        
        function XILBuildOneStandaloneTarget(topModel, ...
                                             xilComponentModel, ...
                                             isSIL, ...
                                             pushNags, ...
                                             defaultCompInfo, ...
                                             xilCompInfo, ...
                                             topModelAccelWithProfiling)            
            % Build the standalone code generation target for one model
            % that will simulate in SIL or PIL mode
            
            % If the top-model and the xilComponentModel are the same
            % then this is the top-model SIL/PIL scenario
            isTopModelXILSim = strcmp(topModel, xilComponentModel);
                        
            silDebugging = strcmp(get_param(topModel, 'SILDebugging'), 'on');
            lCodeExecutionProfilingTop = strcmp(get_param(topModel, 'CodeExecutionProfiling'), 'on');
            lCodeCoverageSettings = slprivate('getCodeCoverageSettings', ...
                topModel);
            
            % reuse top-model XIL build to make sure that
            % STANDALONE_SUPPRESS_EXE is active...
            callSlbuild = @(generateCodeOnly) (...
                sl('slbuild_private', xilComponentModel,...
                'StandaloneCoderTarget',...
                'TopModelXILSim', isTopModelXILSim, ...
                'TopModelAccelWithProfiling', topModelAccelWithProfiling,...
                'CodeExecutionProfilingTop', lCodeExecutionProfilingTop, ...
                'CodeCoverageSettings', lCodeCoverageSettings, ...
                'InstrumentationSettingsModel', topModel, ...
                'SILDebugging', silDebugging, ...
                'TopModelSilOrPilBuild',true,...
                'TopModelIsSilMode', isSIL,...
                'OkayToPushNags', pushNags, ...
                'SlbXilCompInfo', xilCompInfo, ...
                'SlbDefaultCompInfo', defaultCompInfo, ...
                'generateCodeOnly', generateCodeOnly ...
                ));
            
            % check for any referenced models within the XIL component
            allLevels = false;
            % note: refModels always contains xilComponentModel
            assert(bdIsLoaded(xilComponentModel), ...
                'Expect xilComponentModel to already be loaded.');
            refModels = find_mdlrefs(xilComponentModel, allLevels);
            if (length(refModels) > 1) && ...
                    Simulink.CodeMapping.isAutosarCompliant(xilComponentModel) && ...
                    ~Simulink.CodeMapping.isAutosarAdaptiveSTF(xilComponentModel)
                % For Classic AUTOSAR we first do a code generation
                % only build to generate the RTE, before building
                % again with generateCodeOnly off. This allows
                % model references with dependencies on the RTE to
                % compile.
                generateCodeOnly = true;
                result = callSlbuild(generateCodeOnly);
                if result.buildCancelled
                    DAStudio.error('PIL:pil:SimCancelledByUser');
                end
            end
            
            % Avoid warning about XmlOptions not inherited from
            % architecture model when doing SIL on a component
            % block in architecture model
            if Simulink.CodeMapping.isAutosarCompliant(xilComponentModel) &&...
                    Simulink.internal.isArchitectureModel(topModel, 'AUTOSARArchitecture')
                resetCompBuildParam = onCleanup(@()set_param(xilComponentModel,...
                    'IsComponentBuildFromComposition', 'off'));
                set_param(xilComponentModel, 'IsComponentBuildFromComposition', 'on');
            end
            
            % build with compile
            generateCodeOnly = false;
            result = callSlbuild(generateCodeOnly);
            if result.buildCancelled
                DAStudio.error('PIL:pil:SimCancelledByUser');
            end            
        end
        
        function XILBuildStandaloneTargets(topModel, xilMdlBlks, pushNags, topModelAccelWithProfiling)     
            % Called from ModelRefCompileHierarchy.cpp to
            % build standalone code generation targets for a set of Model
            % blocks in SIL/PIL mode.
                
            % Determine compiler information based on default mex configuration.
            % The DefaultCompInfo object must be instantiated only at the beginning
            % of the build and before any change of pwd. If default mex setup is
            % queried later in the build process after changing pwd it will not
            % pick up any mex configuration file in the original pwd.
            lDefaultCompInfo = coder.internal.DefaultCompInfo.createDefaultCompInfo;
            
            % keep track of which referenced models we built XIL
            % applications for
            builtComponentList = {};
            for i=1:length(xilMdlBlks)
                xilModelBlock = xilMdlBlks(i);
                isProtected = rtw.pil.ModelBlockPIL.isModelProtected(xilModelBlock);                  
                if isProtected
                    % this is a protected model, so code must have already
                    % been unpacked and built if necessary.
                    continue;
                end
                
                xilComponentModel = get_param(xilModelBlock, 'ModelName');                    
                
                if ~any(strcmp(builtComponentList, xilComponentModel))                    
                    isSIL = rtw.pil.ModelBlockPIL.isSIL(xilModelBlock);                    
                    lXilCompInfo = i_getXilCompInfo(isSIL, getActiveConfigSet(xilComponentModel), lDefaultCompInfo);
                    if ishandle(topModel)
                        topModel = get_param(topModel,'Name');
                    end
                    % build
                    rtw.pil.ModelBlockPIL.XILBuildOneStandaloneTarget(topModel, ...
                                                                      xilComponentModel, ...
                                                                      isSIL, ...
                                                                      pushNags, ...
                                                                      lDefaultCompInfo, ...
                                                                      lXilCompInfo, ...
                                                                      topModelAccelWithProfiling);
                    builtComponentList{end+1} = xilComponentModel; %#ok<AGROW>                                       
                end                                                
            end                                                            
        end
                                
        function config = getNamedConnectivityConfig(configName)
            if strcmp(configName, 'Software-in-the-Loop (SIL)')
                config = coder.connectivity.connectivityconfig.getSILConnectivityConfig();
            else            
                targetRegistry = RTW.TargetRegistry.get;
                connectivityConfigs = coder.internal.getConnectivityConfigs(targetRegistry);
                % search for desired config
                indices = strcmp({connectivityConfigs.ConfigName}, configName);
                config = connectivityConfigs(indices);            
            end
        end
        
        function checkPilCompatibility(configInterface, isReadOnly)
            
            % error out if some model settings are not compatible for PIL            
            rtw.pil.ModelBlockPIL.checkModelForSILPILCompatibility(configInterface, isReadOnly);
            
            % make sure word size maps to one of the integer sizes
            isPIL = true;
            rtw.pil.SlHardwareConfigHelper.checkWordSize(configInterface, isPIL, isReadOnly);
        end
        
        % note: this method is public because it is used by the hyperlink
        % created by getPILInterface - it is not intended for end users
        function config = getPilConnectivityConfig...
                (modelOrConfigInterface, lSkipConfigCheck, lXilCompInfo, isReadOnly)
            
            if ~isa(modelOrConfigInterface, 'coder.connectivity.ConfigInterface')
                rtw.connectivity.Utils.validateArg(modelOrConfigInterface, 'char');
                % support call-sites where model is passed. Create 
                % configInterface for this model
                model = modelOrConfigInterface;
                configSet = getActiveConfigSet(model);
                clientInterface = coder.connectivity.SimulinkInterface;
                configInterface = clientInterface.createConfigInterface(...
                    configSet, model);
            else                
                configInterface = modelOrConfigInterface;
            end
            pilComponent = configInterface.getCodeGenComponent;
            
            rtw.pil.ModelBlockPIL.checkPilCompatibility(configInterface, isReadOnly);
            
            % get the list of potential configs for this component                        
            
            pilConfigs = coder.connectivity.connectivityconfig.getPILConnectivityConfig(configInterface, lXilCompInfo.XilMexCompInfo);
            
            if isempty(pilConfigs)
                if lSkipConfigCheck
                    % If doing update_model_reference_targets don't worry -
                    % we'll get an error if we try to actually simulate
                    % model at the top of the hierarchy.  But we might
                    % just be generating code.  In which case, simply
                    % return a known good config so that we have an
                    % S-function to use to push information up the model
                    % reference hierarchy.  The S-function will get
                    % re-written to reflect real hardware if the configuration
                    % changes to one that has a valid connectivity config.
                    config = rtw.pil.ModelBlockPIL.getNamedConnectivityConfig('Software-in-the-Loop (SIL)');
                    config.ConfigName = 'Update-model-reference-targets (PIL)';
                    return;
                end
                % see what configs are available
                allConfigs = coder.internal.getConnectivityConfigs(RTW.TargetRegistry.get());
                
                if ~isempty(allConfigs)
                    allConfigsLink = rtw.pil.ModelBlockPIL.getConfigsHyperlink(allConfigs);                    
                    rtw.pil.ProductInfo.error('pil', ...
                                              'PILNoMatchingConfigs', ...
                                              pilComponent, ...
                                              allConfigsLink);               
                else
                    rtw.pil.ProductInfo.error('pil','PILNoConfigs');
                end
            end
            %
            % currently no choice of config possible for PIL
            %
            if length(pilConfigs) > 1                
                conflictingConfigsLink = ...
                    rtw.pil.ModelBlockPIL.getConfigsHyperlink(pilConfigs);              
                configRegLink = targets_hyperlink_manager...
                    ('new', ...
                     'rtw.connectivity.ConfigRegistry', ...
                     'doc rtw.connectivity.ConfigRegistry');      
                rtw.pil.ProductInfo.error('pil', ...
                                          'PILMultipleConfigs', ...
                                          pilComponent, ...
                                          conflictingConfigsLink, ...
                                          configRegLink);                                           
            end
            % set the validated config for PIL
            config = pilConfigs;
        end     

        function config = getSilConnectivityConfig(model, lXilCompInfo, isReadOnly)
            % create configInterface for this model
            configSet = getActiveConfigSet(model);
            clientInterface = coder.connectivity.SimulinkInterface;
            configInterface = clientInterface.createConfigInterface(...
                configSet, model);
            
            % check SIL compatibility and return SIL config
            isProtectedModel = false;                     
            config = rtw.pil.ModelBlockPIL.checkSilCompatibilityAndGetSilConfig(...
                                configInterface, isProtectedModel, isReadOnly, lXilCompInfo);
        end
     
        
        
        % Return true if the given block is a copied multi-instance normal
        % mode model, false otherwise.  This requires that the models
        % containing the blocks are all opened
        function isInCopiedModel = isBlockInCopiedModel(block)
            model = bdroot(block);
            paramVal = get_param(model, 'ModelReferenceMultiInstanceNormalModeCopy');
            isInCopiedModel = strcmp(paramVal, 'on');
        end
        
        function link = getConfigsHyperlink(configs)
            link = '';
            numConfigs = length(configs);
            for i=1:numConfigs
                config = configs(i);
                if i==numConfigs
                    spacer = '';
                else
                    spacer = ', ';
                end
                link = [link targets_hyperlink_manager('new', ...
                    config.ConfigName, ...
                    @disp, config) spacer]; %#ok<AGROW>
            end
        end
        
        function blockListStr = makeBlockListString(blockList)
            blockListStr = '';
            for i = 1:length(blockList)
                block = getfullname(blockList(i));
                blockListStr = [blockListStr block newline]; %#ok<AGROW>
            end
        end
        
        function isModelReferenceTarget = isModelReferenceTarget(modelBlock)
            % Return whether Model block in SIL or PIL mode is configured
            % for model reference code interface or top model
            % code interface
            simMode = get_param(modelBlock,'SimulationMode');
            assert(any(strcmpi({'processor-in-the-loop (pil)',...
                           'software-in-the-loop (sil)'},...
                          simMode)),'Simulation mode must be SIL or PIL');

            isModelReferenceTarget = ~strcmp(get_param(modelBlock, 'CodeInterface'), ...
                                                                   'Top model');
        end
        
        function modelInterface = getModelInterfaceForTLC(lModelBlock, isModelReferenceTarget)
            % GetModelInterfaceForTLC
            lPILData = get_param(lModelBlock, 'PILData');
            assert(~isempty(lPILData), 'PILData should not be empty for block %s', lModelBlock);
            assert(isa(lPILData, 'rtw.pil.SILPILInterface'), 'PILData in block %s should be a rtw.pil.SILPILInterface', lModelBlock);
            
            xilComponent = rtw.pil.ModelBlockPIL.getXilComponentName(lModelBlock);
            lCodeDir = lPILData.getCodeDir;
            loadConfigSet = false;
            savedInfoStruct = rtw.pil.ModelBlockPIL.getSavedInfoStruct( ...
                xilComponent, isModelReferenceTarget, lCodeDir, loadConfigSet);
            modelInterface = savedInfoStruct.modelInterface;
        end
        
        function childModelsWithProfiling = getChildModelsWithProfilingForBlock(lModelBlock)
            lPILData = get_param(lModelBlock, 'PILData');
            assert(~isempty(lPILData), 'PILData should not be empty for block %s', lModelBlock);
            assert(isa(lPILData, 'rtw.pil.SILPILInterface'), 'PILData in block %s should be a rtw.pil.SILPILInterface', lModelBlock);
            
            xilComponent = rtw.pil.ModelBlockPIL.getXilComponentName(lModelBlock);
            lCodeDir = lPILData.getCodeDir;
            
            % Get the saved infoStruct
            isModelReferenceTarget = strcmp(get_param(lModelBlock, 'CodeInterface'), ...
                'Model reference');
            loadConfigSet = false;
            savedInfoStruct = rtw.pil.ModelBlockPIL.getSavedInfoStruct( ...
                xilComponent, isModelReferenceTarget, lCodeDir, loadConfigSet);
            
            % We need to temporarily flip the cached STF in infoMATFileMgr
            lConfigInterface = lPILData.getSILPILWrapperUtils.getConfigInterface;
            lChildSystemTargetFile = lConfigInterface.getParam('SystemTargetFile');
            
            if isModelReferenceTarget
                lModelReferenceTargetType = 'RTW';
            else
                lModelReferenceTargetType = 'NONE';
            end
            [~, lGenSettings] = coder.internal.getSTFInfo...
                (xilComponent, ...
                'systemtargetfile', lChildSystemTargetFile, ...
                'noTLCSettings', true, ...
                'modelreferencetargettype', lModelReferenceTargetType);
            
            % Initialize infoMATFileMgr. The previous state of infoMATFileMgr is
            % automatically restored when the cleanup is executed.
            cleanupGenSettingsCache = coder.internal.infoMATFileMgr...
                ([], [], [], [], ...
                'InitializeGenSettings', lGenSettings);
            
            lChildModels = savedInfoStruct.modelRefsAll;
            nChildModels = numel(lChildModels);
            lKeepIdx = false(1, nChildModels);
            
            for kChildModel = 1:nChildModels
                childInfoStruct = coder.internal.infoMATFileMgr('load', ...
                    'binfo', ...
                    lChildModels{kChildModel}, ...
                    'RTW');          % Always RTW for child models.
                lCodeProfilingInstrChild = get_param...
                    (childInfoStruct.configSet, 'CodeProfilingInstrumentation');
                if ~strcmp(lCodeProfilingInstrChild, 'off')
                    lKeepIdx(kChildModel) = true;
                end
            end
            
            % Clean up change to GenSettings
            cleanupGenSettingsCache.delete;
            
            childModelsWithProfiling = lChildModels(lKeepIdx);
            lCodeProfilingInstrThis = lConfigInterface.getParam('CodeProfilingInstrumentation');
            if ~strcmp(lCodeProfilingInstrThis, 'off')
                childModelsWithProfiling = [childModelsWithProfiling, xilComponent];
            end
        end
        
        function childModelsWithProfiling = getChildModelsWithProfiling(lParentModel, lModelBlockList)
            
            assert(iscell(lModelBlockList));
            
            % This code path should only ever be used in Top Model
            % accelerator mode.  In this case, a Model Block in SIL/PIL
            % mode can only exist in the top model, since it cannot exist
            % in a model for which the SIM target is built.
            %
            % Assert that this is indeed the case.
            assert(all(startsWith(lModelBlockList, [lParentModel, '/'])));
            
            % Get a list of unique referenced models, so we don't query the
            % same model twice.
            lModelList = cellfun(@(x)rtw.pil.ModelBlockPIL.getXilComponentName(x), ...
                lModelBlockList, 'UniformOutput', false);
            [~, lUniqueIdx] = unique(lModelList, 'stable');
            lModelBlockList = lModelBlockList(lUniqueIdx);
            
            % Now find any child models with profiling
            childModelsWithProfiling = {};
            for kModelBlock = 1:numel(lModelBlockList)
                childModelsWithProfiling = [ ...
                    childModelsWithProfiling, ...
                    rtw.pil.ModelBlockPIL.getChildModelsWithProfilingForBlock(lModelBlockList{kModelBlock}), ...
                    ]; %#ok<AGROW>
            end
            childModelsWithProfiling = unique(childModelsWithProfiling, 'stable');
        end
        
       
        function prodHW = getHostProdHW()
            % select the appropriate host prod hardware
            archstr = computer('arch');
            switch archstr
                case 'win64'
                    prodHW = 'Intel->x86-64 (Windows64)';
                case 'glnxa64'
                    prodHW = 'Intel->x86-64 (Linux 64)';
                case 'maci64'
                    prodHW = 'Intel->x86-64 (Mac OS X)';
                otherwise
                    assert(false, 'Unknown arch: %s', archstr);
            end
        end
        
       function pwsEnableLongLong = getPWSEnableLongLong(componentName)
            % special handling for Windows64 which is the default
            % hardware implementation and requires long long to be
            % enabled in order for uint64 (corresponding to native
            % word size) to get typedef'd in rtwtypes.h
            if strcmp(get_param(componentName, 'ProdHWDeviceType'), ...
                    'Intel->x86-64 (Windows64)')
                pwsEnableLongLong = true;
            else
                pwsEnableLongLong = false;                
            end            
       end
        
       function checkERTTargetOrGRTTarget(configInterface)
            rtw.connectivity.Utils.validateArg(configInterface,...
                'coder.connectivity.ConfigInterface');
            xilComponent = configInterface.getCodeGenComponent;
            activeConfigSet = configInterface.getResolvedConfig;            
            if ~rtw.pil.Config.isERTTargetOrGRTTarget(activeConfigSet)
                DAStudio.error('PIL:pil:ModelNotDerivedFromERTOrGRT',...
                    xilComponent);
            end
       end
    end
    
    methods (Access = 'private', Static = true)
        function [isProtected, modelName, modelInfo] = isModelProtected(modelBlock)
            isProtected = strcmp(get_param(modelBlock, 'ProtectedModel'), 'on');
            modelName = '';
            modelInfo = [];
            if isProtected
                modelFile = get_param(modelBlock, 'ModelFile');
                modelInfo = Simulink.ModelReference.ProtectedModel.getOptions(modelFile);
                modelName = modelInfo.modelName;
            end
        end
        
        function lXilComp = getXilComponentName(lModelBlock)
            [isProtected, lXilComp] = rtw.pil.ModelBlockPIL.isModelProtected(lModelBlock);
            if ~isProtected
                lXilComp = get_param(lModelBlock, 'ModelName');
            end
        end
        
        function [configInterface,xilComponent] = createConfigInterfaceModelBlock(...
                xilModelBlock, isModelReferenceTarget)
            % create configInterface object:
            % For protected models, the model is not available, so we load
            % up the serialized configSet in binfo.
            %
            % For non-protected models, the model is available, so we can
            % get its active configset.
            clientInterface = coder.connectivity.SimulinkInterface;
            [isProtected, xilComponent] = rtw.pil.ModelBlockPIL.isModelProtected(xilModelBlock);            
            if isProtected
                buildDirInfo = RTW.getBuildDir(xilComponent);
                if isModelReferenceTarget
                    codeDir = fullfile(buildDirInfo.CodeGenFolder,...
                        buildDirInfo.ModelRefRelativeBuildDir);
                else
                    codeDir = buildDirInfo.BuildDirectory;
                end
                % Get the saved infoStruct
                loadConfigSet = true;
                savedInfoStruct = rtw.pil.ModelBlockPIL.getSavedInfoStruct( ...
                    xilComponent, isModelReferenceTarget, ...
                    codeDir, ...
                    loadConfigSet);
                
                % create configInterface
                configInterface = clientInterface.createConfigInterfaceFromInfoStruct(...
                    savedInfoStruct, xilComponent);
            else
                % non-protected, so load the model
                xilComponent = get_param(xilModelBlock, 'ModelName');
                load_system(xilComponent);
                configSet = getActiveConfigSet(xilComponent);
                configInterface = clientInterface.createConfigInterface(...
                    configSet, xilComponent);
            end
        end
                
        function RTWErrorCheckProtectedModel(iMdl, xilModelBlock)
            
            % Code coverage of a protected referenced model is not
            % supported
            cov_settings = slprivate('getCodeCoverageSettings', iMdl);
            if strcmp(cov_settings.ReferencedModelCoverage, 'on')
                DAStudio.error...
                    ('Simulink:protectedModel:CodeCoverageNotSupportedForProtectedModel', ...
                    iMdl,...
                    getfullname(xilModelBlock),...
                    iMdl);
            end
            
            % SIL debugging of a protected referenced model is not
            % supported
            if strcmp(get_param(iMdl, 'SILDebugging'), 'on')
                DAStudio.error...
                    ('Simulink:protectedModel:SILDebuggingNotSupportedForProtectedModel', ...
                    iMdl,...
                    getfullname(xilModelBlock),...
                    iMdl);
            end
        end
        
        
        % Do error checks for multi-SIL/PIL blocks ensuring the target services
        % for each block can be run concurrently.
        function processedServices = RTWErrorCheckHookTargetServices...
            (xilModelBlock, configInterface, processedServices, isUpdateDiagram, lXilCompInfo, isReadOnly)

            rtw.connectivity.Utils.validateArg(configInterface, 'coder.connectivity.ConfigInterface');

            options = coder.connectivity.VerificationOptions(rtw.pil.ModelBlockPIL.isSIL(xilModelBlock));       
            isProtected = rtw.pil.ModelBlockPIL.isModelProtected(xilModelBlock);
            rtw.pil.ModelBlockPIL.validateConfigration(options.IsSIL, configInterface, lXilCompInfo, isProtected, isReadOnly);                
            
            [targetServices, errorMessage] = coder.connectivity.createTargetServices(configInterface, options, lXilCompInfo.XilMexCompInfo);
            if ~isempty(errorMessage)                
                if (isUpdateDiagram)
                    % As we are only updating diagram we can return the SIL
                    % target service if there is an error returning the true
                    % one. We only need it to propagate information up the
                    % hierarchy. If PIL is then run this will be re-calculated.
                    options.IsSIL = true;
                    targetServices = coder.connectivity.createTargetServices(configInterface, options, lXilCompInfo.XilMexCompInfo);
                else
                    error(errorMessage);
                end
            end

            assert(~isempty(targetServices), 'Target services should be instantiated.');

            for i = 1:length(processedServices)
                service = processedServices{i};
                canRunWith = service.runsConcurrentlyWith(targetServices);

                if (~canRunWith)
                    rtw.pil.ProductInfo.error('pil', 'PILConfigNotMultiInstance', getfullname(xilModelBlock), targetServices.getName());
                end
            end               

            processedServices{end+1} = targetServices;
        end
                
            
        % Do error checks related to model reference configurations
        function RTWErrorCheckHookModelConfig(iMdl, iXilMdlBlks)


            % We can only validate unprotected model blocks at this point
            % as protected model blocks have not been unpacked.
            mblocks = iXilMdlBlks(~arrayfun(@rtw.pil.ModelBlockPIL.isModelProtected, ...
                                 iXilMdlBlks));

            topModelName = get_param(iMdl, 'Name');

            %We need more than one model to compare 
            numModels = length(mblocks);
            if numModels < 2
                return;
            end

            structs = cell(1, numModels);
            models = cell(1, numModels);
            modelBlockSTFs = cell(1, numModels);
            for i = 1:numModels

                % Generate the shared utils structure for the current model
                modelBlock = mblocks(i);
                modelName = get_param(modelBlock, 'ModelName');

                % we need to load the model to provide this check
                load_system(modelName);

                cs = getActiveConfigSet(modelName);
                
                % Get the shared utility checksum
                newStruct = coder.internal.getDefaultUtilStruct(modelName, ... 
                                                                [], ...
                                                                'RTW', ...
                                                                [], ...
                                                                cs);
                                                            
                % The only checksums we care about validating against are
                % the models we have processed for the same system target
                % file. Get the models and structures to compare to
                stf = get_param(cs, 'SystemTargetFile');                
                sameSTF = strcmp(stf, modelBlockSTFs);
                structsToCompare = structs(sameSTF);
                modelsToCompare = models(sameSTF);               
                modelInstances = strcmp(modelName, models);
                
                % Compare the referenced model structure with the previous
                % models if we have a model to compare to and if we haven't
                % seen this model before
                if ~isempty(structsToCompare) && ~any(modelInstances)
                    cellfun(@(m, s) rtw.pil.ModelBlockPIL.validateSharedUtilities(topModelName, modelName, newStruct, m, s), modelsToCompare, structsToCompare);
                end
                
                modelBlockSTFs{i} = stf;
                structs{i} = newStruct;
                models{i} = modelName;
            end            
        end
        
        function validateSharedUtilities(topModel, modelA, structA, modelB, structB)
            
            % Perform the shared utils comparison, if the comparison
            % results in a shared utils conflict (i.e. the shared utilities
            % checksums are different and they have the same shared utility
            % folder.
            comp = coder.internal.SharedUtilsChecksumComparison(modelA, modelB, structA, structB);            
            if comp.SharedUtilsFolderConflict
                comp.addSolutionMessege('RTW:buildProcess:sharedUtilsInconsistentModelsXILResolve')
                comp.throwError('RTW:buildProcess:sharedUtilsInconsistentModelsXIL', ...
                    topModel);
            end
        end
        
        
        % Load infoStruct from binfo
        function savedInfoStruct = getSavedInfoStruct(xilComponent, isModelReferenceTarget, lCodeDir, loadConfigSet)
            lBinfoMATFile = coderprivate.getBinfoMATFileAndCodeName(lCodeDir);
            if isModelReferenceTarget
                tgt = 'RTW';
            else
                tgt = 'NONE';
            end
            try
                savedInfoStruct = coder.internal.infoMATFileMgr(...
                    'loadPostBuild', 'binfo', xilComponent, tgt,...
                    lBinfoMATFile, loadConfigSet);
            catch origE
                % construct standard error with origE as cause
                [newId, newMessage] = rtw.pil.ProductInfo.message(...
                    'pilverification', 'ErrorGeneratedCodeIncomplete');
                newException = MException(newId, ...
                    newMessage);
                newException = newException.addCause(origE);
                throw(newException);
            end
        end
        
        % Do error checks related to profiling
        function RTWErrorCheckHookProfiling(iMdl, iXilMdlBlks) 

            if strcmp(get_param(iMdl, 'CodeExecutionProfiling'), 'on')
                if  length(iXilMdlBlks) > 1
                    % This error message is not reachable in normal 
                    rtwprivate('rtwattic', 'clean'); % g738047, prevent drool of
                                                     % getSourceSubsystemName

                    origModelBlocks = ~arrayfun(@rtw.pil.ModelBlockPIL.isBlockInCopiedModel, ...
                                               iXilMdlBlks);
                    origModelBlocks = iXilMdlBlks(origModelBlocks);

                    if(length(origModelBlocks) == 1)
                        DAStudio.error...
                            ('CoderProfile:ExecutionTime:ModelBlockNameClashOneBlock', ...
                             getfullname(origModelBlocks(1)));
                    else
                        blockListStr = rtw.pil.ModelBlockPIL.makeBlockListString...
                            (origModelBlocks);
                        DAStudio.error...
                            ('CoderProfile:ExecutionTime:ModelBlockNameClash', ...
                             blockListStr);
                    end
                end
            end
        end
            
        % Do error checks related to coverage
        function RTWErrorCheckHookCoverage(iMdl, iXilMdlBlks)
            if length(iXilMdlBlks)>1
                cov_settings = get_param(iMdl, 'CodeCoverageSettings');
                if (~strcmp(cov_settings.CoverageTool, 'None') && ...
                        strcmp(cov_settings.ReferencedModelCoverage, 'on'))
                    
                    % There are more than one XIL model blocks and
                    % coverage is turned on.  This is not supported.  This
                    % can happen because there is one XIL model block in
                    % the hierarchy, but in a model block that is
                    % referenced multiple times, or because there are
                    % multiple XIL model blocks in the hierarchy.  We need
                    % to report a different error for these two cases.
                    origModelBlocks = ~arrayfun(@rtw.pil.ModelBlockPIL.isBlockInCopiedModel, iXilMdlBlks);
                    origModelBlocks = iXilMdlBlks(origModelBlocks);
                    
                    % Highlight the blocks
                    for i = 1:length(origModelBlocks)
                        hilite_system(origModelBlocks(i));
                    end
                    
                    % Report the appropriate error
                    if(length(origModelBlocks) == 1)
                        blockListStr = getfullname(origModelBlocks(1));
                        rtw.pil.ProductInfo.error('pil', 'ModelBlockPILSingleInsCodeCovOneBlock', blockListStr);
                    else
                        blockListStr = rtw.pil.ModelBlockPIL.makeBlockListString(origModelBlocks);
                        rtw.pil.ProductInfo.error('pil', 'ModelBlockPILSingleInsCodeCov', blockListStr);
                    end
                end
                
                % There are more than one SIL/PIL model blocks.  If any of
                % these are PIL, error, because a PIL mode block cannot
                % be simulated with any other SIL/PIL model blocks.
                silBlocks = arrayfun(@(b) rtw.pil.ModelBlockPIL.isSIL(b), iXilMdlBlks);
                pilBlocks = ~silBlocks;
                if ~(all(silBlocks) || all(pilBlocks))
                    sillockListStr = rtw.pil.ModelBlockPIL.makeBlockListString(iXilMdlBlks(silBlocks));
                    pillockListStr = rtw.pil.ModelBlockPIL.makeBlockListString(iXilMdlBlks(pilBlocks));
                    rtw.pil.ProductInfo.error('pil', 'ModelBlockSILAndPIL', sillockListStr, pillockListStr);
                end
            end
        end     
        
        function pilData = getPILData(pilModelBlock, inTheLoopType)
            handler = coder.connectivity.PILDataHandler.createHandler(inTheLoopType);
            pilData = handler.getPILData(pilModelBlock);
        end
        
        function isSIL = isSIL(pilModelBlock)
            simMode = lower(get_param(pilModelBlock,'SimulationMode'));
            assert(any(strcmp({'processor-in-the-loop (pil)',...
                           'software-in-the-loop (sil)'},...
                          simMode)),'Simulation mode must be SIL or PIL');
            if strcmp(simMode, 'software-in-the-loop (sil)')
               isSIL = true; 
            else
               isSIL = false;
            end
        end
        
        function pilInterface = getPILInterface(pilModelBlockPath, configInterface, ...
                iMdl, topModelOriginalParams, buildingApplication, lXilCompInfo)
            % find the connectivity config that is valid for this
            % component
            %
            % Note: there is 1 PIL application per PIL component, therefore
            % all instances of the same component use the same config                            

            % reuse public static method getConnectivityConfig to
            % implement a useful hyperlink callback
            pilModelBlock = pilModelBlockPath(end);
            isRLS = rtw.pil.ModelBlockPIL.isRLS(iMdl);
            rtw.connectivity.Utils.validateArg(configInterface, 'coder.connectivity.ConfigInterface');            
            isSIL = rtw.pil.ModelBlockPIL.isSIL(pilModelBlock);
            
            options = coder.connectivity.VerificationOptions(isSIL);
            [targetServices, errorMessage] = coder.connectivity.createTargetServices(configInterface, options, lXilCompInfo.XilMexCompInfo);
                        
            if ~isempty(errorMessage)                
                if (buildingApplication)
                    error(errorMessage);
                else                
                    % If we are not going to be building the XIL application,
                    % we can permit a default config to be used to get us the
                    % S-function for diagram update.  Everything will get
                    % re-generated if the config name changes later on.
                    options.IsSIL = true;
                    targetServices = coder.connectivity.createTargetServices(configInterface, options, lXilCompInfo.XilMexCompInfo);                    
                end
            end
            
            if ~isSIL
                if coder.connectivity.TopModelSILPIL.isTopModelXILHarness(iMdl)
                    componentType = 'model';
                else
                    componentType = 'referenced model';
                end
                link = targets_hyperlink_manager...
                       ('new', ...
                        targetServices.getName(), ...
                        @disp, ...
                        targetServices);
                pilComponent = configInterface.getCodeGenComponent;
                disp(['### Connectivity configuration for ' componentType ...
                      ' "' pilComponent '": ' link ' ###']);                            
            end
                               
            % determine the code gen dir
            componentPath = configInterface.getCodeGenComponent;   
            buildDirInfo = RTW.getBuildDir(componentPath);

            if isRLS % using RLS workflow
                % set codeDir to the component sub-folder (subsystem_context)
                harnessInfo = Simulink.harness.internal.getHarnessInfoForHarnessBD(iMdl);
                [codeDir, codedescriptorDir] = rtw.pil.RLSUtils.getRLSFoldersFromHarnessInfo(harnessInfo);
                rlsSubsystemName = harnessInfo.ownerFullPath;
                inTheLoopType = rtw.pil.InTheLoopType.Subsystem;
            else
                isModelReferenceTarget = ...
                    rtw.pil.ModelBlockPIL.isModelReferenceTarget(pilModelBlock);
                if isModelReferenceTarget
                    codeDir = fullfile(buildDirInfo.CodeGenFolder,...
                                       buildDirInfo.ModelRefRelativeBuildDir);                  
                    inTheLoopType = rtw.pil.InTheLoopType.ModelBlock;
                else
                    % choose standalone build dir:
                    % this is enough to trigger isUpToDate to detect changes
                    codeDir = buildDirInfo.BuildDirectory;    
                    inTheLoopType = rtw.pil.InTheLoopType.ModelBlockStandalone;
                end
                codedescriptorDir = codeDir;
                rlsSubsystemName = '';
            end
            
            % check for existing PILData
            pilInterface = rtw.pil.ModelBlockPIL.getPILData(pilModelBlock, inTheLoopType);
            if isempty(pilInterface) || ~isa(pilInterface, 'rtw.pil.SILPILInterface')
                createPILInterface = true;
            else 
                createPILInterface = false;
            end                        
            
            if ~createPILInterface
               % Does PILInterface need updating?               
               if ~pilInterface.isUpToDate(codeDir, targetServices, iMdl)                   
                  createPILInterface = true; 
               end                
            end            
            
            if createPILInterface	
                % create an instance of the interface class                
                clientInterface = coder.connectivity.SimulinkInterface;                
                blockPath = getfullname(pilModelBlockPath);
                if ~iscell(blockPath)
                    blockPath = {blockPath};
                end
                pilInterface = rtw.pil.SILPILInterface(buildDirInfo.CodeGenFolder, ...
                                                       codeDir, ...
                                                       inTheLoopType, ...
                                                       clientInterface, ...
                                                       targetServices, ...
                                                       lXilCompInfo, ...
                                                       isSIL, ...
                                                       'TopModel', iMdl,...
                                                       'TopModelOriginalParams', topModelOriginalParams, ...
                                                       'Owner', pilModelBlock, ...
                                                       'BlockPath', blockPath, ...
                                                       'CodeDescriptorDir', codedescriptorDir, ...
                                                       'RLSSubsystemName', rlsSubsystemName);
                % set the PILData
                handler = coder.connectivity.PILDataHandler.createHandler(inTheLoopType);
                handler.setPILData(pilModelBlock, pilInterface);
            end
        end                                                       
        
        function checkIfModelIsCompatibleWithSilNoPWS...
                (configInterface, isProtectedModel, lXilCompInfo)
                  
            % assert if someone call this method when portable word sizes
            % is enabled
            rtw.connectivity.Utils.validateArg(configInterface,...
                'coder.connectivity.ConfigInterface');
            model = configInterface.getCodeGenComponent;
            isPortableWordSzEnabled =...
                strcmp(getParam(configInterface,'PortableWordSizes'),'on');
            assert(~isPortableWordSzEnabled, ...
                'expected portable word sizes for %s to be disabled', model);
            
            % construct hyperlink/text which will be used if we throw an
            % incompatible SIL config error message
            commandText = ['helpview(fullfile(docroot,''toolbox'','...
                '''ecoder'',''helptargets.map''),'...
                '''validate_ert_prod_code_using_portable_word_size'')'];
            portableWordSzLink = ...
                targets_hyperlink_manager('new', ...
                'Configuring Hardware Implementation Settings for SIL', ...
                commandText);
            
            [~,portableWordSzMessage] = rtw.pil.ProductInfo.message(...
                'pil',...
                'PortableWordSizesRecommendation',...
                portableWordSzLink);
            
            % Determine if we are using toolchain or TMF approach for this
            % model.                                 
            lIsToolchainBased = isa(lXilCompInfo.ToolchainOrTMF, 'coder.make.ToolchainInfo');
            
            % check that a supported host-based TMF/Toolchain is specified.
            % We only do this check if "PortableWordSizes" is not
            % enabled on the model. If "PortableWordSizes" is enabled
            % on the model, we will automatically build the generated
            % code with the appropriate host tmf/toolchain without forcing 
            % the user to change the tmf/toolchain setting on the model.
                
            if ~lIsToolchainBased
                
                activeConfigSet = configInterface.getResolvedConfig;
                isGRT = activeConfigSet.getComponent('Code Generation').getComponent('Target').isGRTTarget;
                if isGRT
                    %If GRT based, TMF is not supported                    
                    rtw.pil.ProductInfo.error('pil', ...
                        'SILGRTtmfNotSupport', ...
                        model);
                end
                
                % Check that we have a non-empty tmf. There is no
                % equivalent for this in the toolchain world.
                if strcmp(getParam(configInterface,'GenerateMakefile'),'on')                    
                    if isProtectedModel
                        tmf = fullfile(matlabroot, ...
                            configInterface.getInfoStruct.TemplateMakefile);
                    else
                        tmf = coder.make.internal.getTMF ...
                              (model, get_param(model,'RTWTemplateMakefile'), ...
                              lXilCompInfo.XilMexCompInfo);
                    end
                else
                    tmf = '';
                end
                
                if isempty(tmf)
                    rtw.pil.ProductInfo.error('pil', ...
                                              'SILNoTmf', ...
                                               model,...
                                               portableWordSzMessage);
                end
            end

            % Check for supported TMF/Toolchain. Use the same check that 
            % we perform to determine if a compiler can be used for building a
            % simulation target, i.e. check the property SupportsBuildingMEXFuncs.
            lToolchainInfo = lXilCompInfo.ToolchainInfo;
            supportedToolchainOrTMF = ~isempty(lToolchainInfo) && ...
                lToolchainInfo.SupportsBuildingMEXFuncs;
            if ~supportedToolchainOrTMF
                if lIsToolchainBased
                    if isempty(lToolchainInfo)
                        %No toolchain from build process, use a default
                        %name.
                        rtw.pil.ProductInfo.error('pil', ...
                            'SILIncompatibleInvalidToolchain',...
                            model,...
                            portableWordSzMessage);
                    else
                        rtw.pil.ProductInfo.error('pil', ...
                            'SILIncompatibleToolchain',...
                            model,...
                            lToolchainInfo.Name, ...
                            portableWordSzMessage);
                    end
                else
                    rtw.pil.ProductInfo.error('pil', ...
                                              'SILIncompatibleTmf', ...
                                              model,...
                                              lXilCompInfo.TMFProperties.TemplateMakefile, ...
                                              portableWordSzMessage);
                end
            end                        
            
            % atomic sizes
            %
            % SIL scheduling is non-real-time => it doesn't matter what
            % atomic sizes are assumed in the generated code, it
            % won't alter results during SIL simulation.    
        end       
        
        function checkSilCompatibility(configInterface, isProtectedModel, isReadOnly, lXilCompInfo)
            
            % error out if some model settings are not compatible for
            % SIL/PIL
            rtw.connectivity.Utils.validateArg(configInterface,...
                'coder.connectivity.ConfigInterface');
            rtw.pil.ModelBlockPIL.checkModelForSILPILCompatibility(configInterface, isReadOnly);
            
            % determine if portable word sizes is enabled on the model
            isPortableWordSzEnabled =...
                strcmp(getParam(configInterface,'PortableWordSizes'),'on');
            
            if ~isPortableWordSzEnabled
                % check if the model is compatible with SIL and throw an
                % appropriate error message when it is not.
                rtw.pil.ModelBlockPIL.checkIfModelIsCompatibleWithSilNoPWS(...
                    configInterface, isProtectedModel, lXilCompInfo);
            end
            
            % Check that hardware configuration is compatible with host 
            % builds.           
            silHWImplValidator = rtw.pil.SILHWImplValidation(configInterface);
            silHWImplValidator.checkHostWordLengths;    % (Internally checks whether PWS is enabled)
            silHWImplValidator.checkHostImplProps;
            rtw.pil.SlHardwareConfigHelper.throwWarningOrErrors(silHWImplValidator, isReadOnly);
            
            % make sure word size maps to one of the integer sizes
            isPIL = false;   %   checkSilCompatibilityAndGetSilConfig is a SIL specific method
            rtw.pil.SlHardwareConfigHelper.checkWordSize(configInterface, isPIL, isReadOnly);
        end
               
        function config = checkSilCompatibilityAndGetSilConfig...
                (configInterface, isProtectedModel, isReadOnly, lXilCompInfo)
            
            rtw.pil.ModelBlockPIL.checkSilCompatibility(configInterface, isProtectedModel, isReadOnly, lXilCompInfo);
            
            % get the ConfigRegistry object
            config = coder.connectivity.connectivityconfig.getSILConnectivityConfig();
        end
                
        function config = getSilConnectivityConfigModelBlock...
                (configInterface, xilModelBlock, lXilCompInfo, isReadOnly)
            
            % check SIL compatibility and return SIL config
            rtw.connectivity.Utils.validateArg(configInterface,...
                'coder.connectivity.ConfigInterface');
            isProtected = rtw.pil.ModelBlockPIL.isModelProtected(xilModelBlock);
            config = rtw.pil.ModelBlockPIL.checkSilCompatibilityAndGetSilConfig...
                (configInterface, isProtected, isReadOnly, lXilCompInfo);
        end
        
        function checkModelForSILPILCompatibility(configInterface, isReadOnly)
            %tmf RTW.MSVCBuild is not supported by SIL or PIL
            rtw.connectivity.Utils.validateArg(configInterface,...
                'coder.connectivity.ConfigInterface');
            xilComponent = configInterface.getCodeGenComponent;
            if strcmp(getParam(configInterface, 'TemplateMakefile'), 'RTW.MSVCBuild')
               rtw.pil.ProductInfo.error('pil', ...
                   'MSVCBuildTmfNotSupported', ...
                   xilComponent);
            end
                        
            % ert_shrlib.tlc is not supported by SIL/PIL because this
            % target builds a library and our generated makefile for SIL/PIL
            % does not support that.
            if strcmp(getParam(configInterface, 'SystemTargetFile'), 'ert_shrlib.tlc')
               rtw.pil.ProductInfo.error('pil', ...
                   'SharedLibraryTargetNotSupported', ...
                   xilComponent);
            end
            
            % autosar_adaptive.tlc (and derived targets) are not supported
            % by SIL/PIL because we do not generate all necessary artifacts
            % yet
            if strcmp(get_param(configInterface, 'AutosarCompliant'), 'on') && ...
                    strcmp(get_param(configInterface, 'CodeInterfacePackaging'), 'C++ class')
                rtw.pil.ProductInfo.error('pil', ...
                   'AUTOSARAdaptiveSilPilMode', ...
                   xilComponent);
            end
            
            % validate the current configuration supports Mat-file logging
            rtw.pil.ModelBlockPIL.validateMATfileLoggingSupport(configInterface, isReadOnly);
        end
        
        function standaloneDataLoggingValidation(xilComponent, isProtected)
            % With a Top Model code interface, ToWorkspace and Scope blocks
            % configured to log data can save the logged data to a MAT
            % file if MatFileLogging is enabled. If MatFileLogging is not
            % enabled, then these blocks will not log data in SIL/PIL mode.
            %
            % Verify that ToWorkspace or Scope blocks have supported
            % configurations and if an unsupported data logging combination
            % is present, issue warning or error.
            %
            % The equivalent checks get carried out during block diagram
            % compile for the model reference code interface.
            if ~isProtected
                % Default settings for find_system exclude
                % commented blocks and non-active variants.
                % That's consistent with what's needed here.
                %
                % The model will have been loaded when the config interface
                % was created.
                assert(bdIsLoaded(xilComponent), 'Model %s should be loaded', xilComponent);
                lMATFileLogging = strcmp(get_param(xilComponent, 'MatFileLogging'), 'on');
                if ~lMATFileLogging
                    if Simulink.internal.useFindSystemVariantsMatchFilter()
                        lToWorkspace = find_system(get_param(xilComponent, 'handle'), ...
                            'LookUnderMasks', 'all', ...
                            'MatchFilter', @Simulink.match.codeCompileVariants, ... % code compile variants only (post compilation)
                            'IncludeCommented', 'off', ...
                            'FirstResultOnly', 'on', ...  % stop on finding first ToWorkspace block
                            'BlockType', 'ToWorkspace');
                    else
                        lToWorkspace = find_system(get_param(xilComponent, 'handle'), ...
                            'LookUnderMasks', 'all', ...
                            'Variants', 'ActivePlusCodeVariants', ...
                            'IncludeCommented', 'off', ...
                            'BlockType', 'ToWorkspace');
                    end
                    if ~isempty(lToWorkspace)
                        rtw.pil.ModelBlockPIL.throwStandaloneDataLoggingExceptionOrWarning(xilComponent, 'ToWorkspace');
                    end
                    if Simulink.internal.useFindSystemVariantsMatchFilter()
                        lDataLoggingScopes = find_system(get_param(xilComponent, 'handle'), ...
                            'LookUnderMasks', 'all', ...
                            'MatchFilter', @Simulink.match.codeCompileVariants, ... % code compile variants only (post compilation)
                            'IncludeCommented', 'off', ...
                            'FirstResultOnly', 'on', ...  % stop on finding first ToWorkspace block
                            'BlockType', 'Scope', ...
                            'DataLogging', 'on');
                    else
                        lDataLoggingScopes = find_system(get_param(xilComponent, 'handle'), ...
                            'LookUnderMasks', 'all', ...
                            'Variants', 'ActivePlusCodeVariants', ...
                            'IncludeCommented', 'off', ...
                            'BlockType', 'Scope', ...
                            'DataLogging', 'on');
                    end
                    if ~isempty(lDataLoggingScopes)
                        rtw.pil.ModelBlockPIL.throwStandaloneDataLoggingExceptionOrWarning(xilComponent, 'Scope');
                    end
                end
            end
        end
        
        function throwStandaloneDataLoggingExceptionOrWarning(xilComponent, blockType)
            lDataLoggingDiagnosticSetting = get_param(xilComponent, 'ModelReferenceDataLoggingMessage');
            lMessageToIssue = message('PIL:pil:StandaloneDataLoggingNeedsMATFileLogging', xilComponent, blockType);
            % Need to check whether we should be
            % throwing an error.
            switch lDataLoggingDiagnosticSetting
                case 'error'
                    MException(lMessageToIssue).throw;
                case 'warning'
                    warning(lMessageToIssue);
                case 'none'
                    % Do nothing
                otherwise
                    assert(false, 'DataLoggingDiagnosticSetting must be error, warning, or none');
            end
        end
        
        function validateMATfileLoggingSupport(configInterface, isReadOnly)
            % Error out if mat-file logging and allocation function are
            % both active.
            % In this scenario data logging cannot be started because no
            % start-function description is available in codeInfo. 
            % SIL/PIL will replace mat-file logging, therefore we're not
            % going to support this combination of parameters.
            if strcmp(configInterface.getParam('MatFileLogging'), 'on') && ...
                strcmp(configInterface.getParam('GenerateAllocFcn'), 'on')
            
                readOnlyActionIDs = {};
                fullAccessActionsIds = {'MATFileLogging'};
                exception = coder.connectivity.AccessDependentDiagnostic(...
                    'PIL:pil:UnsupportedMATfileLogging', ...
                    readOnlyActionIDs, ...
                    fullAccessActionsIds,...
                    configInterface.getCodeGenComponent);
                exception.throw(isReadOnly);
            end
        end                
        
        function res = isRLS(topModel)
            % given a topModel, return true if the RLS workflow is active
            res = strcmp(get_param(topModel, 'XILRLSWorkflow'), 'on');
        end
        
        function res = isReadOnly(isRLS, isProtected)
            % return true if RLS or protected
            res = isRLS || isProtected;
        end
    end
end


function lXilCompInfo = i_getXilCompInfo(isSIL, cs, lMexCompInfoDefault)
isPws = strcmp(get_param(cs, 'PortableWordSizes'), 'on');
lIsSilAndPws = isSIL && isPws;

lXilCompInfo = coder.internal.utils.XilCompInfo.slCreateXilCompInfo...
    (cs, lMexCompInfoDefault, lIsSilAndPws);
end

% LocalWords:  pil Configs configs cgv TMF Tmf tmf vc vcx lcc Endianess sil
% LocalWords:  SILPIL TMF's
