classdef (Hidden = true) Sfunction < rtw.connectivity.CodeInfoSfunction
%SFUNCTION creates an s-function with interface defined by CodeInfo
%
%   This is an undocumented class. Its methods and properties are likely to
%   change without warning from one release to the next.

%   Copyright 2008-2024 The MathWorks, Inc.

    properties (SetAccess = 'private', GetAccess = 'protected')
       SILPILWrapperUtils;
       NeedToProcessExceptions;
       TransferInterfaceUtils;
       
       %Sfunction/Mex switching
       SimStructType = 'SimStruct *'; %Default to Simulink version
       SimStructArg = 'S, '; %Default to having a SimStructArg
       SimStructArgSingle = 'S';
       ErrorFunction = 'ssSetErrorStatus( S,'; %Default to Sfunction errors
       LocaltargetIOFdType = 'targetIOFd_T * ';
       LocalRTIOStreamType = 'XIL_RtIOStreamData_T* ';
       LocalCodeInstrServiceDataType = 'CodeInstrServiceData_T';
       LocalIOBufferType = 'XIL_IOBuffer_T* ';       
       LocalpCommErrorOccurredType = 'int * ';       
       LocalpIsXILApplicationStartedType = 'int * ';
       MATLABCoderNoECTestingMode = false;
       ReturnArgString = '';
    end    
    
    properties (SetAccess = 'immutable', GetAccess = 'protected')
        % Strictly, IsTriggered/IsFcnCallTriggered are only needed by
        % rtw.pil.ModelBlockSfunction, but due to the call to the
        % overloaded method "validateInterface" in the constructor of
        % Sfunction, they must be initialized in advance.
        IsTriggered;
        IsFcnCallTriggered;
    end
    
    properties (SetAccess = 'private', GetAccess = 'private')        
        IsMexTarget = false;
        PWorkInfo;
        ByteReorderingTestMode;
        TypesWithDiffWordOrderDoneInit = false;
        TypesWithDiffWordOrderEnumVals;
        IsUsingCommServiceAPI;
        IsNeededMemUnitXform;
        IsRowMajorTransformNeeded = false;
        SupportImages = false;
        SupportHalf = false;
        CheckRuntimeOffsetInitWarn (1,1) logical = false;
    end
    
    properties (Constant, GetAccess = 'private')
        InitializeTaskId = intmax('uint32');        
        SvrExecArgsVarName = 'fcExecArgs';
        SvrInArgsVarName   = 'inArgs';
        SvrOutArgsVarName  = 'outArgs';
        SvrFcnInvokeArgName = 'args';
        SvrInOutArgPostfixIn  = '_InOut_Input';
        SvrInOutArgPostfixOut = '_InOut_Output';
    end
    
    properties (Constant, GetAccess = 'protected')
        XILUtilsVarName = 'pXILUtils';
    end
    
    properties (SetAccess = 'protected', GetAccess = 'protected')
        HasModelWideEvents = false;
        NeedsPeriodicOutputUpdateFcn = false;
        HasExplicitPartitions = false;
    end
    
    methods
        % constructor
        function this = Sfunction(silPILWrapperUtils, ...                                          
                                  sfunSourcePath, ...
                                  sfunOutDir, ...
                                  varargin)
            narginchk(3, 5);
            
            parser = inputParser;
            parser.addParameter('TimingInterfaceFlags', ...
                rtw.connectivity.TimingInterfaceFlags.withDefaultValues, ...
                @(x)isa(x, 'rtw.connectivity.TimingInterfaceFlags'));
            parser.parse(varargin{:});
            timingInterfaceFlags = parser.Results.TimingInterfaceFlags;
            
            % validate arg            
            rtw.connectivity.Utils.validateArg(silPILWrapperUtils, ...
                'rtw.pil.SILPILWrapperUtils');
            
            % call super class constructor                             
            designDataLocation = silPILWrapperUtils.getInfoStruct.designDataLocation;
            this@rtw.connectivity.CodeInfoSfunction(silPILWrapperUtils.getCodeInfoUtils, ...
                                                    sfunSourcePath, ...
                                                    sfunOutDir, ...
                                                    designDataLocation, ...
                                                    silPILWrapperUtils.getSILPILInterface.getClientInterface.XilNoWrapper, ...
                                                    timingInterfaceFlags);
            
            % store SILPILWrapperUtils
            this.SILPILWrapperUtils = silPILWrapperUtils;
            
            %Setup IsMexTarget argument
            if silPILWrapperUtils.getSILPILInterface.getInTheLoopType == rtw.pil.InTheLoopType.MATLABFcn
                this.IsMexTarget = true;
            else
                this.IsMexTarget = false;
            end
            
            this.TransferInterfaceUtils = coder.internal.connectivity.TransferInterfaceUtils(true);
             
            % Store IsTriggered/IsFcnCallTriggered for use by
            % validateInterface in derived classes.
            this.IsTriggered = timingInterfaceFlags.IsTriggered;
            this.IsFcnCallTriggered = timingInterfaceFlags.IsFcnCallTriggered;

            % The generated Sfunction/Mex calls into C++ modules. These C++
            % modules process exceptions differently for mex target and
            % Simulink Sfunction. For Simulink, the C++ modules catch the
            % exceptions and process errors using
            % slsvAssignErrorQueueToSimStruct, where the Simulink engine in
            % this case will flush these errors.
            % However, for the mex target, we don't have such capability,
            % so instead, the C++ module will create a
            % MathWorks::MException::MExceptionEnvelope, cache it and
            % return an error flag. The generated mex file will need to get
            % these cached exceptions and explicitly display them (setting 
            % NeedToProcessExceptions to true will accomplish this)
            this.NeedToProcessExceptions = this.IsMexTarget;            
            
            % create the data elements for the server and caller functions
            this.initCallerAndServerFunctions;
            
            % must be before initPWorkInfo
            this.initIsNeededMemUnitXform;
            
            % initialize PWorkInfo           
            this.initPWorkInfo;
            
            %Set Model wide events
            this.HasModelWideEvents = this.getCodeInfoUtils.hasModelWideEvents();
                        
            % validate the component interface.
            this.validateInterface;
            
            %If MEXTarget modify Properties
            if this.IsMexTarget

                this.CodeFunctionArgDecs = '';
                this.CodeFunctionArgs = '';
                
                this.SimStructType = '';
                this.SimStructArg = '';
                this.SimStructArgSingle = '';
                this.ErrorFunction = 'mexErrMsgTxt( ';
                this.LocaltargetIOFdType = '';
                this.LocalRTIOStreamType = '';
                this.LocalIOBufferType = '';
                this.LocalpCommErrorOccurredType = '';
                this.LocalpIsXILApplicationStartedType = '';
                
                this.MATLABCoderNoECTestingMode =  this.SILPILWrapperUtils.getInfoStruct.noECTestingMode;
            end
            
            this.IsUsingCommServiceAPI = rtw.connectivity.Utils.isCommServiceAPIEnabled;
            if (this.IsUsingCommServiceAPI)
                assert(this.SILPILWrapperUtils.getSILPILInterface.isSIL,...
                    'USING_CS_API only supports SIL simulations.');
            end 
            
            this.initializeTypeSupport();
        end
        
        function build(this, lDefaultMexCompilerKey)            
            append = false;            
            callCBeautifier = true;
            obfuscateCode = this.SILPILWrapperUtils.shouldObfuscateXILWrapperFiles;
            if this.IsMexTarget
                % MATLAB Coder only supports UTF-8 as of 21a
                encoding = 'UTF-8';
            else
                encoding = slCharacterEncoding;
            end
            this.writeOutput(append, callCBeautifier, obfuscateCode, encoding);
            buildSfunction(this, lDefaultMexCompilerKey);            
        end
        function getPWorkValue(this, returnType, varName, PWorkIdx, declareData)
        
            if declareData
                declareType = [returnType ' * '];
            else
                declareType = '';
            end
            if ~this.IsMexTarget
                % Get the required PWork
                this.writer.wLine('%s%s = (%s *) ssGetPWorkValue(S, %s);', ...
                    declareType, ...
                    varName, ...
                    returnType, ...
                    PWorkIdx);
            end
        end
        % every argument of every caller function has its own storage in PWork
        function pWorkIdx = getCallerFunctionArgumentPWorkIdx(this, callerFunctionInfo, dataInterface)
            callerFunctionsInfo = this.codeInfoUtils.getUndefinedCallerFunctionsInfo;
            assert(~isempty(callerFunctionsInfo), ...
                'callerFunctionsInfo must be non-empty to get the argument PWork idx');
            runningArgsCount = 0;
            for callFcnIdx = 1:length(callerFunctionsInfo)
                if isequal(callerFunctionInfo, callerFunctionsInfo(callFcnIdx))
                    dataInterfaces = callerFunctionInfo.getAllDataInterfaces;
                    for dIdx = 1:length(dataInterfaces)
                        if isequal(dataInterface, dataInterfaces(dIdx))
                            pWorkIdx = int2str(this.PWorkInfo.CallerFunctionsIdx + ...
                                runningArgsCount + dIdx -1);
                            return;
                        end
                    end
                end
                runningArgsCount = runningArgsCount + ...
                    length(callerFunctionsInfo(callFcnIdx).getAllDataInterfaces);
            end
        end
    end
    
    methods (Access = 'protected')
        
        % initialize "dataInterfacePtr" for parameter data
        function writeSectionGetParameterDataInterfacePtr(this, dataInterface, sfunIdx) %#ok<INUSD>
            assert(this.IsMexTarget, 'Must be overridden for non-Mex Target');
        end
        
        function writeSectionHeader(this)

            if ~this.IsMexTarget
                writeSectionHeader@rtw.connectivity.CodeInfoSfunction(this);
            else
                
                [~, mexName, mexExt] = fileparts(this.getSfunSourcePath);
                mexName = [mexName mexExt];
                this.writer.writeCellLines({'/*';
                    [' * ' mexName];
                    ' *';
                    ' * Automatically generated host I/O interface for:';
                    [' * Component: ' this.codeInfo.Name];
                    });
                % optional customization
                this.writeHeaderCustomizationHook;
                this.writer.writeCellLines({' *';
                    ' */';
                    '';});
            end
        end                                       
        
        function writeHeaderCustomizationHook(this)
            if this.IsMexTarget
                SILModeName = 'Execution';
            else
                SILModeName = 'Simulation';
            end
            this.writer.wLine(' * %s Mode: %s', ...
                SILModeName, ...
                this.SILPILWrapperUtils.getSILPILInterface.getSimModeAcronym);
        end
        
        function sfunIdx = getSfunIdxForInputDataInterface(~, dataInterfaceIdx)
            % zero-based idx
            sfunIdx = int2str(dataInterfaceIdx - 1);
        end
        
        function writeSectionPreprocessor(this)
            
            if ~this.IsMexTarget
                % call the super class method
                writeSectionPreprocessor@rtw.connectivity.CodeInfoSfunction(this);
            else
                this.writer.wLine('#include <stdio.h>');
                % for memcpy
                this.writer.wLine('#include <string.h>');
                this.writeSectionAdditionalIncludes;
                this.writer.newLine;
            end
            
            % include xil utils
            this.writer.writeLine('#include "coder/connectivity_core/xilutils/xilutils.h"');
            if ~this.IsMexTarget
                this.writer.writeLine('#include "coder/simulinkcoder/xilutils_sl/xilutils_sl.h"');
            end
            
            % include the services
            if this.IsUsingCommServiceAPI
                this.writer.writeLine('#include "coder/target_connection/ConnectionOptions_CInterface.h"');
                this.writer.writeLine('#include "coder/target_connection/TargetConnection_CInterface.h"');
            else
                
                % Include any additional headers required by the RtIOStream
                % implementation
                headers = this.getRtIOStreamAdditionalIncludeHeaders();
                for i = 1:length(headers)                    
                    this.writer.writeLine('#include "%s"', headers{i});
                end
                
                this.writer.newLine;
                
                this.writer.writeLine('#include "coder/connectivity/xilcomms_rtiostream/xilcomms_rtiostream.h"');
            end
            this.writer.writeLine('#include "coder/connectivity/XILHostAppSvc/XILHostAppSvc_CInterface.h"');
            if ~this.IsMexTarget
                this.writer.wLine('#include "messages/slMessagesSfcnBridge.h"');
                this.writer.wLine('#include "mwstringutil.h"');
                if this.SupportImages
                    this.writer.wLine('#include "image/slImageSFcnAPI.h"');
                end
            end
            
            isCodeInstrumentationEnabled = this.SILPILWrapperUtils.isCodeInstrumentationEnabled;
            if isCodeInstrumentationEnabled
                this.writer.writeLine('#include "coder/connectivity/CodeInstrHostAppSvc/CodeInstrHostAppSvc_CInterface.h"');
            end
            
            if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
                this.writer.writeLine('#include "coder/connectivity/CoderAssumpHostAppSvc/CoderAssumpHostAppSvc_CInterface.h"');
            end
                        
            if this.IsNeededMemUnitXform            
                this.writer.writeLine('#include "coder/connectivity/memunit/MemUnitTransformerAPI.h"');
                this.writer.newLine;
            end

            if this.IsMexTarget
                fcnName = this.SILPILWrapperUtils.getSILPILInterface.getCodeName;
                [infoName, apiName] = rtw.pil.Sfunction.generateInterfaceFileNames(fcnName);
                
                this.writer.wLine('#include "%s.h"', apiName);
                this.writer.wLine('#include "%s.h"', infoName);
                this.writer.wLine('#include "coder/connectivity/memunit/MemUnitTransformerType.h"');
                hostInterfaceHeader = 'xil_host_interface.h';
                this.writeXILHostInterfaceHeader(hostInterfaceHeader);
                this.writer.wLine('#include "%s"', hostInterfaceHeader);
            end
            
            if this.SILPILWrapperUtils.needToProcessServerFcns || this.codeInfoUtils.hasUndefinedCallerFunctions
                this.writer.writeLine('#include "simtarget/slSimTgtClientServerAPIBridge.h"');                
            end
            
            symbolicDimsDefs = this.codeInfo.SymbolicDimensionDefinitions;
            if ~isempty(symbolicDimsDefs)
                this.writer.writeLine('/* symbolic dimension definitions */');
            end
            for dimsIdx=1:length(symbolicDimsDefs)
                symbDimName  = symbolicDimsDefs(dimsIdx).Name;
                symbDimValue = symbolicDimsDefs(dimsIdx).Value;
                this.writer.writeLine('#ifndef %s', symbDimName);
                this.writer.writeLine('static const int_T %s = %d;', ...
                                      symbDimName, symbDimValue);
                this.writer.writeLine('static const int_T Rte_SysCon_%s = %d;', ...
                                      symbDimName, symbDimValue);
                this.writer.writeLine('#elif %s != %d', ...
                                      symbDimName, symbDimValue);
                this.writer.writeLine('# error "%s should be equal to %d"', ...
                                      symbDimName, symbDimValue);
                this.writer.writeLine('#endif');
            end
            
            if ~isempty(this.SILPILWrapperUtils.getLoggingData)
                this.writer.wLine('#include "AsyncioQueueCAPI.h"');
                this.writer.newLine;
            end
        end
               
        function writeSectionProcessParameters(this)
           if ~this.IsMexTarget
               writeSectionProcessParameters@rtw.connectivity.CodeInfoSfunction(this); 
           end            
        end
        
        function writeSectionCheckParameters(this)
            if ~this.IsMexTarget
                writeSectionCheckParameters@rtw.connectivity.CodeInfoSfunction(this);
            end
        end        
        
        function writeSectionExportFunctionsWrappers(this)
           if this.IsMexTarget
              return; 
           end                                                
            
           if this.codeInfoUtils.needsExportFunctionWrapper(this.SILPILWrapperUtils.getInfoStruct())
               numPorts = this.codeInfoUtils.getNumExportFunctionsInports;               
               for portIdx = 1:numPorts
                   % 0-based indices in s-function
                   sfunPortIdx = int2str(portIdx - 1);
                   % see if we have an OutputFunction
                   outputFcn = this.codeInfoUtils.getExportFunctionsCodeInfoOutputFunction(portIdx);
                   if ~isempty(outputFcn) 
                       % empty codeInfoData => optimized function
                       if isempty(outputFcn.codeInfoData)
                           this.writer.writeLine('/*');
                           outputFcnName = '';
                       else
                           outputFcnName = outputFcn.codeInfoData.Prototype.Name;
                           this.writer.writeCellLines({'/*';
                               ' * This function is a wrapper around the "output-update" function for';
                               [' * system "' outputFcnName '".']});
                       end
                       this.writer.writeCellLines({' * This function is explicitly called';
                           [' * by the function-call initiator which drives input port ' sfunPortIdx];
                           ' * of this S-Function.';
                           ' */';});
                       fcnName = this.getExportFunctionStepFcnName(sfunPortIdx, outputFcnName);
                       this.writer.writeLine(['static ssFcnCallErr_T ' fcnName '(SimStruct *S, int_T ssEl, int_T ssTid) {']);
                       this.writer.incIndent;
                       this.writer.writeCellLines({'/* Reserved arguments */';
                           '(void)ssEl;';
                           '(void)ssTid;'});
                       if isempty(outputFcn.codeInfoData)
                           this.writer.writeLine('/* Output-update function is empty */');
                       else
                           if this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid
                               this.writeSectionExportFunctionStepBody(outputFcn);
                           end
                       end
                       this.writer.writeLine('/* Default return status. */');
                       this.writer.writeLine('return(SS_FCNCALL_NO_ERR);');
                       this.writer.decIndent;
                       this.writer.writeLine('}');
                       this.writer.newLine;
                   end                   
               end                                                                                          
           end
        end                               
        
        function writeSectionInitDataStoreIndices(this) %#ok<MANU>
            % hook method for subclasses to override
        end
        
        function writeSectionInitStringOutputMemory(this)
            %For outputs we need to initialize the memory for all strings
            %outputs.
            % NOTE: we may consider removing this as now Simulink engine initializes all string output buffers
            
            % The following 2 lines do not work when parameters are inlined, because
            % getDataInterfacesForFunction does not count those constant output in
            % See g1735814 for more details
            %initFuns = this.codeInfo.InitializeFunctions;
            %outportIndices = this.codeInfoUtils.getDataInterfacesForFunction(initFuns, 'output');

            % Only add this for Simulink S-Function 
            if ~this.IsMexTarget
                % Get indices directly from outports
                outportIndices = 1:length(this.codeInfo.Outports);
                [dataInterfaces, ~, ~] = ...
                    this.getDataInterfaces(outportIndices, 'output');
                if ~isempty(dataInterfaces)
                    for dataInterface = dataInterfaces
                        dataElements = dataInterface.getHostDataElements;
                        if dataElements(1).getType.isChar()
                            sfunIdx = this.getSfunIdxForDataInterface(dataInterface);

                            this.writer.wBlockStart('');
                            % initialize the dataInterface pointer
                            isHostToTarget = false;
                            this.writeSectionDataInterfacePtr(dataInterface, sfunIdx, isHostToTarget);


                            for i = 1:length(dataElements)
                                dataElement = dataElements(i);
                                storageId = dataElement.getDtypeId;

                                simulinkCType = rtw.connectivity.TypeUtils.builtinToHostCType(storageId);

                                if(~dataElement.SkipForCommonAncestorProcessing)

                                    hostPtr = 'dataInterfacePtr';
                                    if strcmp(simulinkCType,'char_T')
                                        this.writer.wLine('suInitializeSILStringOutput(%s);', hostPtr);
                                    end
                                end
                            end
                            this.writer.wBlockEnd;
                        end
                    end
                end
            end
        end
        
        function writeSectionInitStringLogging(this)
            %We need to initialize the memory for all string signals
            dataInterfaces = this.SILPILWrapperUtils.getLoggingData;
            dataInterfaces = rtw.pil.LoggingUtils.filterUnneededBufferUpload(dataInterfaces);
            for dataInterface = dataInterfaces
                pWorkIdx = this.getLoggingTmpVarPWorkIdx(dataInterface);
                if dataInterface.getIsNVBus
                    rtw.pil.LoggingUtils.writeSectionInitStringFields(this.writer, dataInterface, pWorkIdx);
                else
                    dataElements = dataInterface.getHostDataElements();
                    dataElement = dataElements(1);
                    tmpVarName = 'tmpVarMemory';
                    if dataElement.getDtypeId == rtw.connectivity.CodeInfoTypeEnum.TypeChar
                        this.writer.wBlockStart('');
                        this.getPWorkValue('void', tmpVarName, pWorkIdx, true);
                        this.writer.wLine('suInitializeSILStringOutput(%s);', tmpVarName);
                        this.writer.wBlockEnd;
                    end
                end
            end
        end
        
        function fcnName = getExportFunctionStepFcnName(~, sfunPortIdx, ~)
            fcnName = ['mdlExportedOutputFcn' sfunPortIdx];
        end
        
        function writeSectionServerFunctionStepBody(this, ...
                outputTask, errorReturn, serverFcnIndex)
            
            inportIndices  = this.codeInfoUtils.getInputPortsForTask(outputTask);
            paramIndices   = this.getParamIndicesForFunction(outputTask.codeInfoData);
            outportIndices = this.codeInfoUtils.getOutputPortsForTask(outputTask);
            
            % Transfer DataStores for this server
            dsReadIndices  = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                this.codeInfoUtils.getReaderSharedDataStoresForTask(outputTask), 'dsread');
            dsWriteIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                this.codeInfoUtils.getWriterSharedDataStoresForTask(outputTask), 'dswrite');
            sharedLocalDataStoreIndices = [];
            
            loggingIndices = [];
            
            % var dims support           
            inportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(outputTask.codeInfoData, 'inputsize');
            outportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(outputTask.codeInfoData, 'outputsize');
            
            this.writer.writeLine('{');
            this.writer.incIndent;
            
            if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                this.writer.wLine('time_T taskTime = ssGetT(S);');
            end
            
            % use zero-based codeInfoIndex of function interface as the tid
            tid = outputTask.id;
            taskTiming = outputTask.codeInfoData.Timing;
            % step
            this.writeSectionPILIOCommand('XIL_OUTPUT_COMMAND', ...
                inportIndices, ...
                inportSizesIndices, ...
                paramIndices, ...
                dsReadIndices, ...
                dsWriteIndices, ...
                sharedLocalDataStoreIndices, ...
                outportIndices, ...
                outportSizesIndices, ...
                loggingIndices, ...
                serverFcnIndex, ...
                tid, ...
                taskTiming, ...
                errorReturn);
            
            this.writer.decIndent;
            this.writer.writeLine('}');
        end
        
        function writeSectionExportFunctionStepBody(this, ...
                outputTask)
            inportIndices = this.codeInfoUtils.getInputPortsForTask(outputTask);
            inportIndices = this.SILPILWrapperUtils.getDFInputPortsIndices(inportIndices);
            paramIndices = this.getParamIndicesForFunction(outputTask.codeInfoData);
            outportIndices = this.codeInfoUtils.getOutputPortsForTask(outputTask);
            
            % Transfer DataStores for this exported function
            dsReadIndices =  this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                this.codeInfoUtils.getReaderSharedDataStoresForTask(outputTask), 'dsread');
            dsWriteIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                this.codeInfoUtils.getWriterSharedDataStoresForTask(outputTask), 'dswrite');
            sharedLocalDataStoreIndices = [];
            
            % signal logging support
            loggingIndices = this.codeInfoUtils.getLoggingForTask(outputTask);
            
            % deal with server functions separately in 
            % writeSectionServerFunctionStepBody
            serverFcnIndex = []; 
            
            % var dims support           
            inportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(outputTask.codeInfoData, 'inputsize');
            outportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(outputTask.codeInfoData, 'outputsize');
            
            this.writer.writeLine('{');
            this.writer.incIndent;
            
            if this.SILPILWrapperUtils.isCodeInstrumentationEnabled || ~isempty(loggingIndices)
                this.writer.wLine('time_T taskTime = ssGetT(S);');
            end
            
            % use zero-based codeInfoIndex of function interface as the tid
            tid = outputTask.id;
            taskTiming = outputTask.codeInfoData.Timing;
            this.ReturnArgString = ' SS_FCNCALL_ERR'; %Set error return string
                                                      %use return arg
                                                      %string mechanism as
                                                      %some deep callers            
            % step
            this.writeSectionPILIOCommand('XIL_OUTPUT_COMMAND', ...
                inportIndices, ...
                inportSizesIndices, ...
                paramIndices, ...
                dsReadIndices, ...
                dsWriteIndices, ...
                sharedLocalDataStoreIndices, ...
                outportIndices, ...
                outportSizesIndices, ...
                loggingIndices, ...
                serverFcnIndex, ...
                tid, ...
                taskTiming);
            this.ReturnArgString = ''; %Reset return arg string
            
            this.writer.decIndent;
            this.writer.writeLine('}');
        end                   
        
        function writeSectionServerFunctionWrappers(this)   
            serverFcnInfos = this.SILPILWrapperUtils.getServerFunctionsInfo;
            for svrFcnIdx = 1:length(serverFcnInfos)
                serverFcnInfo = serverFcnInfos(svrFcnIdx);
                serverFcnInterface = serverFcnInfo.getCodeInfoData;
                % if this function is active
                if rtw.pil.CodeInfoData.isInterfaceActive(serverFcnInterface) && serverFcnInfo.IsExported
                    this.writer.writeCellLines({'/*';
                        ' * This function is a wrapper around the "output-update" function for';
                        [' * the server subsystem "' serverFcnInterface.Prototype.Name '".'];
                        ' */';});
                    fcnName = rtw.pil.Sfunction.getServerFunctionWrapperName(serverFcnInterface);
                    this.writer.wBlockStart('static void %s(SimStruct *S, int_T tid, _ssFcnCallExecArgs *%s)',...
                        fcnName, rtw.pil.Sfunction.SvrExecArgsVarName);
                    
                    outputFcn = [];
                    outputFcn.codeInfoData = serverFcnInterface;
                    outputFcn.id = serverFcnInfo.getTID;
                    
                    errorReturn = 'return;';
                    if this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid && ~isempty(outputFcn.codeInfoData.Timing)
                        this.writeSectionServerFunctionStepBody(outputFcn, errorReturn, svrFcnIdx);
                    end
                    this.writer.wBlockEnd;
                end
            end
        end
        
        function writeSectionSetInputPortSampleTime(this)
            if ~this.IsMexTarget
                %Sample times only relevant for Simulink
                writeSectionSetInputPortSampleTime@rtw.connectivity.CodeInfoSfunction(this);
            end
        end
        
        function writeSectionSetOutputPortSampleTime(this)
            if ~this.IsMexTarget
                %Sample times only relevant for Simulink
                writeSectionSetOutputPortSampleTime@rtw.connectivity.CodeInfoSfunction(this);
            end
        end
        
        function writeSectionInitializeSampleTimes(this)
            if ~this.IsMexTarget
                %Sample times only relevant for Simulink
                writeSectionInitializeSampleTimes@rtw.connectivity.CodeInfoSfunction(this);
            end
        end
        
        function isInitializeConditionsRequired = isInitializeConditionsRequired(this) %#ok<MANU>
            isInitializeConditionsRequired = false;
        end
        
        function writeSectionInitializeConditions(this)
            if ~this.IsMexTarget

                writeSectionInitializeConditions@rtw.connectivity.CodeInfoSfunction(this);
            end
        end
                
        function writeSectionInitializeConditionsBody(this)  %#ok<MANU>
            % template method for subclasses to override                        
        end
        
        function writeSectionSetWorkWidths(this)
            if ~this.IsMexTarget

                writeSectionSetWorkWidths@rtw.connectivity.CodeInfoSfunction(this);                                
            end
        end
        
        function indices = getSFunctionParamIndices(this)            
            % default is all of base and model workspace tunable params
            indices = this.SILPILWrapperUtils.getSupportedTunableWorkspaceParams;
        end
        
        function writeSectionCheckParametersBody(this)            
            % Notes from ertsfcnbody.tlc
            %
            % - Dimensions must match exactly.
            % - If the original RTP was real, then the sfcnParam must also be real.
            %   If the original RTP was complex, the sfcnParam could be real / complex.
            % - We do not need to check data type because the data type of the evaluated
            %   dialog parameter will be transformed as necessary when the S-Function
            %   registers run-time parameters.        
            
            % check S-Function parameters
            indices = this.getSFunctionParamIndices;
            workspaceParams = this.codeInfo.Parameters(indices);
            numParams = length(workspaceParams);            
            for paramIdx=1:numParams
                sfunParamIdx = int2str(paramIdx - 1);
                param = workspaceParams(paramIdx);
                type = rtw.connectivity.CodeInfoTypeUtils.getSimulinkInterfaceType(param);                                                
                % dimensions
                this.writer.wBlockStart('', param.GraphicalName);
                symbDims = rtw.connectivity.CodeInfoTypeUtils.getSymbolicDimensions(type);
                numDims = length(symbDims);                
                this.writer.writeLine(['int_T dims[' int2str(numDims) '];']);
                for dimIdx = 1:numDims
                    this.writer.writeLine(['dims[' int2str(dimIdx-1) '] = ' symbDims{dimIdx} ';']);
                end
                % complexity                
                if rtw.connectivity.CodeInfoTypeUtils.isComplex(type)
                    isComplex = '1';
                else
                    isComplex = '0';
                end                                                                                     
                % check param
                this.writer.writeLine(['ssCheckSFcnParamValueAttribs(S, ' ...
                                       sfunParamIdx ', ' ... % dialog parameter index                                      
                                       '"' param.GraphicalName '", ' ... % dialog param name
                                       'DYNAMICALLY_TYPED, ' ...
                                       int2str(numDims) ', ' ...
                                       'dims, ' ...
                                       isComplex ');']);                    
                this.writer.wBlockEnd;
            end
        end
        
        function writeSectionRegisterRuntimeParams(this)
            % setup S-Function parameters
            indices = this.getSFunctionParamIndices;
            params = this.codeInfo.Parameters(indices);
            numParams = length(params);
            if numParams > 0
               this.writer.wComment('Set number of run-time parameters');
               this.writer.writeLine(['if (!ssSetNumRunTimeParams(S, ' ...
                                      int2str(numParams) ')) return;']);
            end
            xrelOrderedParamNames = this.SILPILWrapperUtils.getSILPILInterface.XRelOrderedParamNames;
            
            for paramIdx=1:numParams
                sfunParamIdx = int2str(paramIdx - 1);
                param = params(paramIdx);
                type = rtw.connectivity.CodeInfoTypeUtils.getSimulinkInterfaceType(param);
                
                this.writer.wBlockStart('');
                % setup dataTypeId variable
                if rtw.connectivity.CodeInfoTypeUtils.isBusOrStruct(type)
                    this.writeSectionStructParamDatatypeId(sfunParamIdx, type);
                else
                    includeCodeBlock = false;
                    allowDuplicates = true;
                    this.writeSectionInitializeSizesDatatypeId(type, includeCodeBlock, allowDuplicates);         
                end
                % Parameter naming
                
                if this.SILPILWrapperUtils.getSILPILInterface.isXRelBlock
                    % Find the *original* index of the parameter with the
                    % current graphical name
                    idx = find(strcmp(param.GraphicalName, xrelOrderedParamNames), 1);
                    if isempty(idx)
                        % Catch scenario where cross-release block mask does
                        % not contain expected info about parameters.
                        % This should never happen unless it has been
                        % explicitly changed manually (which should not
                        % happen).
                        assert(false, 'Did not find parameter with graphical name %s in cross-release block', param.GraphicalName);
                    end
                    sfunParamName = sprintf('p%d', idx);
                else
                    sfunParamName = ['P' sfunParamIdx '_' param.GraphicalName];
                end
                
                % register Run Time Parameter
                this.writer.writeLine(['ssRegDlgParamAsRunTimeParam(S, ' ...
                                       sfunParamIdx ', ' ... % Index of the dialog parameter
                                       sfunParamIdx ', ' ... % Index of the run-time parameter
                                       '"', sfunParamName '", ' ... % Run time param name
                                       'dataTypeId);']);    
                this.writer.writeLine('if (ssGetErrorStatus(S) != (NULL)) return;');                
                this.writer.wBlockEnd;
            end
            
            indices = this.SILPILWrapperUtils.getInstPArgumentIndices();
            params = this.codeInfo.Parameters(indices);
            numParams = length(params);
            for idx = 1:numParams
                type = rtw.connectivity.CodeInfoTypeUtils.getSimulinkInterfaceType(params(idx));
                
                
                % setup dataTypeId variable
                [~, namedObject] = rtw.connectivity.CodeInfoTypeUtils.getCodeInfoStoredValueDTypeId(type);
                if rtw.connectivity.CodeInfoTypeUtils.isBusOrStruct(type) && ~isempty(namedObject)
                    includeCodeBlock = true;
                    allowDuplicates = false;
                    this.writeSectionInitializeSizesDatatypeId(type, includeCodeBlock, allowDuplicates);         
                end
            end
        
        end
        
        function writeSectionSetWorkWidthsBody(this)
            % test data type checksums for types in CodeInfo that have
            % checksums
            namedObjects = {};
            codeInfoTypes = this.codeInfo.Types;
            
            for codeInfoTypeIdx = 1:length(codeInfoTypes)
                codeInfoType = codeInfoTypes(codeInfoTypeIdx);
                baseType = rtw.connectivity.CodeInfoTypeUtils.getBaseType(codeInfoType);
                namedObject = baseType.Identifier;
                if any(strcmp(namedObjects, namedObject))
                    % already processed
                    continue;
                end
                
                namedObjects{end+1} = namedObject; %#ok<AGROW>
                
                typeChecksum = this.codeInfoUtils.getArray(baseType.TypeChecksum);
                hasTypeChecksum = ~isempty(typeChecksum) && ...
                    any(typeChecksum > 0);
                
                % When Data Type Override (DTO) is enabled, dataType.Name
                % returns data type name with a DTO prefix such as
                % "dtoScl_" and Checksum corresponds to the DTO version
                % of the type, not the original version of the data
                % type.   The ssCallGetDataTypeChecksum is DTO aware
                % and accepts only the original non-DTO version of the data
                % type.    Therefore, we remove the DTO prefix before
                % calling ssCallGetDataTypeChecksum.    This mechanism
                % makes sure that the SIL/PIL s-function is always in
                % the correct DTO context.
                %
                % Note that "dtoScl_", "dtoDbl_" and "dtoSgl_"
                % identifier names are reserved and cannot be
                % used by end users.
                dtName = rtw.connectivity.CodeInfoTypeUtils.removeDataTypeOverridePrefix(namedObject);
                % Only attempt to validate checksum for data types
                % corresponding to global objects otherwise
                % ssCallGetDataTypeChecksum will fail.
                %
                % This includes:
                %
                % Enums (user-defined only, g2019723)
                % Workspace objects: buses, aliases, etc.
                %
                % In particular, this filters Lookup Table struct
                % types which do not directly correspond to workspace
                % objects - see g1251598.
                %
                % If no checksum skip validation. (Needed for buses 
                % containing container implementation types (e.g. std::array))
                if (baseType.isEnum && ~isempty(meta.class.fromName(dtName)) &&...
                        meta.class.fromName(dtName).Enumeration) || ...
                        globalDataItemExists(dtName, ...
                        this.SILPILWrapperUtils.getInfoStruct.designDataLocation) && hasTypeChecksum 
                    
                    
                    this.writer.wBlockStart('');
                    % get current checksum
                    this.writer.wLine('const uint32_T *currChecksumVals;');
                    this.writer.wLine('ssCallGetDataTypeChecksum(S, "%s", &currChecksumVals);', dtName);
                    % g947942: if ssCallGetDataTypeChecksum fails, the error is implicitly
                    % assigned to the SimStruct and checksumVals is set to NULL
                    this.writer.wBlockStart(['if ((currChecksumVals != NULL) && ' ...
                        '(currChecksumVals[0] != %sU || \n' ...
                        'currChecksumVals[1] != %sU || \n' ...
                        'currChecksumVals[2] != %sU || \n' ...
                        'currChecksumVals[3] != %sU))'], ...
                        int2str(typeChecksum(1)), ...
                        int2str(typeChecksum(2)), ...
                        int2str(typeChecksum(3)), ...
                        int2str(typeChecksum(4)));
                    
                    this.writer.wLine('mxArray * prhs[ %d ];', 2);
                    this.writer.writeLine('prhs[0] = mxCreateString("PIL:pil:DataTypeChecksumError");');
                    this.writer.writeLine('prhs[1] = mxCreateString("%s");', dtName);
                    this.writer.writeLine('xilSimulinkUtilsStaticErrorHandle(2, prhs, S);');
                    
                    errorReturn = sprintf('return%s;', this.ReturnArgString);
                    this.writer.wLine('%s', errorReturn);
                    
                    this.writer.wBlockEnd;
                    this.writer.wBlockEnd;
                end
            end                        
        end
        
        function writeSectionEnable(this)
            if ~this.IsMexTarget
                %Enable only relevant for Simulink
                writeSectionEnable@rtw.connectivity.CodeInfoSfunction(this);
            end
        end
        
        function writeSectionEmptyEnableDisableFunction(this, isEnable)            
            if isEnable
               type = 'enable'; 
               fun = this.codeInfo.EnableFunction;
            else
               type = 'disable';
               fun = this.codeInfo.DisableFunction;
            end
            
            assert(isempty(fun), ...
                   'CodeInfo %s function not empty!', type);
            
            if isEnable
                this.writer.wBlockStart('if (ssGetT(S) != ssGetTStart(S)) ');
            end
               
            % throw error
            errorReturn = 'return;';
            this.writeError(errorReturn, ...
                            'PIL:pil:EnableDisableCallbackError', ...
                            sprintf('mxCreateString("%s")', type), ...    
                            sprintf('mxCreateString("%s")', type));
                        
            if isEnable
               this.writer.wBlockEnd; 
            end
        end                
        
        function writeSectionDisable(this)
            if ~this.IsMexTarget
                %Disable only relevant for Simulink
                writeSectionDisable@rtw.connectivity.CodeInfoSfunction(this);
            end
        end                
        
        function writeSectionTrailer(this)
            if ~this.IsMexTarget
                %Trailer only relevant for Simulink
                writeSectionTrailer@rtw.connectivity.CodeInfoSfunction(this);
            end
        end
        
        function writeSectionAdditionalIncludes(this)
           if this.IsMexTarget
               %Even with MEXAPI front end mex.h needed for "safe" printf
               %statements
               this.writer.wLine('#include "mex.h"');
           else
               % superclass implementation
               writeSectionAdditionalIncludes@rtw.connectivity.CodeInfoSfunction(this);
           end
        end

        function mexLibs = getMEXLibs(this)
            if this.IsMexTarget
                mexLibs = {};
            else
                mexLibs = {'-lfixedpoint', '-lmwsimulink', '-lmwsl_simtarget_core', '-lmwsl_simtarget_instrumentation', '-lmwstringutil'};
            end
        end
                
        % implementation of superclass hook method
        function mexOptions = getAdditionalMEXOptions(this)
            mexOptions = {};            
            if this.IsNeededMemUnitXform
                mexOptions{end+1} = '-lmwcoder_connectivity_memunit';                
                memUnitTransformerInclude = fullfile...
                    (matlabroot, 'toolbox', 'coder', 'connectivity_core', 'c');
                mexOptions{end+1} = ['-I' memUnitTransformerInclude];
            end
            
            if ismac
                %Suppress invalid source encoding warning on MAC see
                %g1585521
                mexOptions{end+1} = 'CFLAGS=$CFLAGS -Wno-invalid-source-encoding';
            end
            
            isCodeInstrumentationEnabled = this.SILPILWrapperUtils.isCodeInstrumentationEnabled;
            if isCodeInstrumentationEnabled
                mexOptions{end+1} = '-lmwcoder_CodeInstrHostAppSvc';
                profilingInclude = fullfile(matlabroot, ...
                                           'toolbox', ...
                                           'coder', ...
                                           'profile', ...
                                           'src');
                mexOptions{end+1} = ['-I' profilingInclude];
            end
            
            if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
                mexOptions{end+1} = '-lmwcoder_CoderAssumpHostAppSvc';
            end
            
            if ~isempty(this.SILPILWrapperUtils.getLoggingData)
                asyncioQueueInclude = fullfile(matlabroot, 'extern', 'include', 'sl_AsyncioQueue');
                mexOptions{end+1} = ['-I' asyncioQueueInclude];
                mexOptions{end+1} = '-lmwsl_AsyncioQueue';
            end
            
            if this.SupportImages
                imageInclude = fullfile(matlabroot, 'extern', 'include', 'images');
                mexOptions{end+1} = ['-I' imageInclude];
            end
            
            % add required mex options for xil utils
            mexOptions{end+1} = '-lmwxilutils';
            if ~this.IsMexTarget
                mexOptions{end+1} = '-lmwxilutils_sl';
            end
            
            % add required mex options for the services
            mexOptions{end+1} = '-lmwcoder_XILHostAppSvc';       
            if this.IsUsingCommServiceAPI
                mexOptions{end+1} = '-lmwcoder_target_connection';
            else
                mexOptions{end+1} = '-lmwxilcomms_rtiostream';
                % rtiostreamcs module needs definition of libH_type
                utilsInclude = fullfile(matlabroot, ...
                    'toolbox', ...
                    'coder', ...                    
                    'rtiostream', ...
                    'src', ...
                    'utils_host');
                mexOptions{end+1} = ['-I' utilsInclude];
                
                if this.isRtIOStreamCCall
                    mexOptions{end+1} = '-lmwrtiostreamutils';
                end
            end                        
            
            % remove any duplicate entries
            mexOptions = unique(mexOptions);
            
            % This is a debug build if SILDebugging is enabled or
            % DEBUG_BUILD is explicitly set on the make command of the
            % model or if this is a debug build configuration (BTI)
            makeCommand = this.SILPILWrapperUtils.getParam('MakeCommand');
            debugBuildFound = coder.internal.isDebugFromMakeCommand(makeCommand);
            debuggingEnabled = this.SILPILWrapperUtils.getDebuggingInfo().IsEnabled;
            isDebugBuildConfiguration = strcmp(...
                this.SILPILWrapperUtils.getParam('BuildConfiguration'), 'Debug');
            if debugBuildFound || debuggingEnabled || isDebugBuildConfiguration           
                mexOptions{end+1} = '-g';
            end
            
        end
        
        function buildSfunction(this, lDefaultMexCompilerKey)
            if ~this.IsMexTarget
                %If not MATLAB Coder SIL use super class method
                buildSfunction@rtw.connectivity.CodeInfoSfunction...
                    (this, lDefaultMexCompilerKey);
                
            else
                %For MEX Targets (MATLAB Coder in particular). The
                %mexFunction must export additional symbols beyond the
                %basic mexFunction. Unfortunately the mex function
                %explicitly hides all symbols other than mexFunction so it
                %isn't efficient to use that route (each compiler uses a
                %different mechanism to expose/hide symbols).
                %The MATLAB Coder team have already solved this problem so
                %this code makes use of their functions for achieving this.
                
                silpilInterface = this.SILPILWrapperUtils.getSILPILInterface;
                langExt = silpilInterface.getTargetExtension();
                fcnPath = silpilInterface.getCodeDir;
                fcnName = silpilInterface.getCodeName;
                [sfunPath, sfunName, sfunExt] = fileparts(this.getSfunSourcePath);
                
                %Create a dummy bare bones BuildInfo for the mex function
                bldParams.buildInfo = RTW.BuildInfo;
                bldParams.buildInfo.addBuildArgs('MLC_TARGET_NAME',sfunName);
                bldParams.buildInfo.addKeyValuePair('Token','EMC_PROJECT',sfunName);
                bldParams.buildInfo.addCompileFlags('-DMATLAB_MEX_FILE', 'OPTS');
 
                %Make sure start DIR Token is inserted into Makefile
                bldParams.buildInfo.Settings.LocalAnchorDir = this.sfunOutDir;
                bldParams.buildInfo.addIncludePaths('$(START_DIR)');
 
                
                [infoName, apiName, mexFilename] = rtw.pil.Sfunction.generateInterfaceFileNames(fcnName);
                
                bldParams.buildInfo.addSourceFiles([sfunName sfunExt], sfunPath);

                %Add interface folder to path
                interfaceDirName = 'interface';
                if ispc
                    %To support UNC paths with older compilers on PC based
                    %hosts need to use full path to interface directory
                    infoPath = fullfile(fileparts(sfunPath), interfaceDirName);
                else
                    %For non PC hosts, can't use full path as any spaces
                    %cause problems
                    infoPath = fullfile('..', interfaceDirName);
                end
                
                 bldParams.buildInfo.addSourceFiles(sprintf('%s%s', ...
                    infoName, langExt), infoPath);
                
                bldParams.buildInfo.addSourceFiles(sprintf('%s%s', ...
                    apiName, langExt), infoPath);
                bldParams.buildInfo.addSourceFiles(sprintf('%s%s', ...
                    mexFilename, langExt), infoPath);
                
                bldParams.buildInfo.addSourcePaths(infoPath);
                bldParams.buildInfo.addIncludePaths(infoPath);
                
                bldParams.buildInfo.addSourcePaths(sfunPath, 'BuildDir');
                bldParams.buildInfo.addSourcePaths(this.sfunOutDir, 'StartDir');
                
                %XIL folder is always a child of the MATLAB Coder build
                %folder so add it's location relatively except on Windows
                %when we must use an absolute path.
                bldParams.buildInfo.addSourcePaths('../.');
                if ispc
                    bldParams.buildInfo.addIncludePaths(fcnPath);
                else
                    bldParams.buildInfo.addIncludePaths('../.');
                end
                
                
                %Create a dummy bare bones MEX config set, set the debug
                %flag off for now.
                bldParams.configInfo = coder.MexCodeConfig;
                bldParams.configInfo.EnableDebugging = false;
                
                %As per CodeInfoSfunction always link in fixedpoint library
                bldParams.buildInfo.addSysLibs('fixedpoint');
                
                %Retrieve a tflControl (this will be empty)
                bldParams.tflControl = emlcprivate('getEmlTflControl',sfunName);
                
                %Create an empty third party library list
                bldParams.tplUseClassNames = {};
                
                %Get project
                bldParams.project = this.SILPILWrapperUtils.getSILPILInterface.getMATLABCoderProject;

                % The MEX SIL wrapper does not require OpenMP
                bldParams.isParallelUsed = false;
                
                %Now process mex options created in Additional Mex Options                
                mexOptions = this.getAdditionalMEXOptions;
                compilerFlagPrefix = 'CFLAGS=$CFLAGS';
                for idx = 1:numel(mexOptions)
                    
                    if ~isempty(regexp(mexOptions{idx},'^-I','once'))
                        %Extract Include paths
                        bldParams.buildInfo.addIncludePaths(mexOptions{idx}(3:end));
                        
                    elseif ~isempty(regexp(mexOptions{idx},'^-l','once'))
                        % Add all system libraries
                        bldParams.buildInfo.addSysLibs(mexOptions{idx}(3:end));
                        
                    elseif strcmp(mexOptions{idx}, '-g')
                        %Check if debugging flag set
                        bldParams.configInfo.EnableDebugging = true;
                        
                    elseif strncmp(mexOptions{idx}, compilerFlagPrefix, length(compilerFlagPrefix))
                        curMexOption = mexOptions{idx};
                        trimmedFlags = strtrim(curMexOption(length(compilerFlagPrefix)+1:end));
                        %Add compiler flags
                        bldParams.buildInfo.addCompileFlags(trimmedFlags, 'OPTS');
                        
                    else
                        %Found another type of option. Flag an error
                        assert(false,'Unknown mex option %s', mexOptions{idx});
                    end
                end
                
                %Call build process for Mex function
                bldMode = coder.internal.BuildMode.Normal;
                buildResults = emlcprivate('emcBuildMEX',bldParams,bldMode);
                if ~buildResults.success
                    rtw.pil.ProductInfo.error(...
                        'pil', 'MEXCompilationFailed', ...
                        buildResults.message, ...
                        buildResults.Log);
                end
            end
                
        end
               
        function writeSectionUserFunctions(this)                
            this.writeSimulinkBlockPathFunction();
            this.writeComputeTaskTickOffsetFunction();
            this.writeRuntimeChecksForOffsetInitWarn();

            this.writer.wLine('static void callStopHookAndFreeSFcnMemory(%s%s);', ...
               this.SimStructType, this.SimStructArgSingle);
            this.writer.wLine('static void mdlTerminate(%s%s);', ...
               this.SimStructType, this.SimStructArgSingle);
            this.writer.wLine('static void xilThrowException(void* %s);', ...
               this.XILUtilsVarName);
                        
            this.writeSectionGrowTargetIOFdFcn();
            this.writer.newLine();
            
            this.writeSectionCloseAndFreeTargetIOFdFcn();
            this.writer.newLine();
            
            % comm service asynchronously pass data to app services, so no
            % need to pull data
            if ~this.IsUsingCommServiceAPI
                this.writeSectionRecvFcn();
                this.writer.newLine();
            end
            this.writeSectionSendFcn();
            this.writer.newLine();
            this.writeSectionCommandDispatchFcn();
            this.writer.newLine();
            this.writeSectionCommandResponseFcn();
            
            if this.IsMexTarget 
               this.writeSectionXILReadFcn();
               this.writeSectionXILWriteFcn();
            
               this.writer.wLine('static void mdlCleanupRuntimeResources();');
                this.writer.wLine('static void mdlInitializeSizes();');
                this.writer.wLine('static void mdlSetupRuntimeResources();');
                this.writer.wLine('static void mdlStart();');
                
               this.writeSectionXILInitializeHost();
            else
                this.writeSectionXILReadFcnSL();
                this.writeSectionXILWriteFcnSL();
                this.writeSectionXILRWStringDataFcns();
                %emit host serialization/deser functions
                if this.supportsCoderArray() && ...
                        rtw.connectivity.CodeInfoUtils.hasCoderArray(this.codeInfo)
                    this.writer.wLine(this.codeInfo.XILHostSerializationFunctionDefinitions);
                end
            end
            this.writer.newLine();
                
            if this.NeedToProcessExceptions
                % we should only need to manually process exceptions if
                % NeedToProcessExceptions is true (a.k.a this.IsMexTarget)
                this.writeSectionProcessExceptionFcn();
                this.writer.newLine();
            end
            
            if this.SILPILWrapperUtils.isCodeInstrumentationEnabled()
                this.writeSectionCodeInstrServiceDataFcn();
                this.writer.newLine();
            end
            this.writeSectionCallStopHookAndFreeSFcnMemoryFcn();
            this.writeSectionCallPrintfHook();
            this.writeSectionPILIOCommandResponseFunctions();
            this.writer.newLine();
            
            if ~this.IsMexTarget
                % function to convert Simulink type to Mem Unit transformer
                % type only needed with Simulink.
                this.writeSectionSSTypeIDToMemUnitTypeID();

               this.writeSectionGetBusElementDimension();
               this.writeSectionProcessParamsFcn();
            end
            
            this.writeSectionStartAndSetupApplication();
            this.writeSectionSendInitializeCommand();
            
            this.writeSectionUserFunctionsTrailer();
            this.writer.newLine();
        end
        
        function writeSimulinkBlockPathFunction(this)             %#ok<MANU>
        end

        function writeComputeTaskTickOffsetFunction(~)
            % No-op implementation
        end
        
        function writeSectionUserFunctionsTrailer(this)            %#ok<MANU>
        end
        
        function writeSectionGlobalData(this)            
           % structure that contains the information required to
           % call rtiostream from this s-function
           this.writer.wComment('Response case labels');
           this.writer.writeLine('enum ResponseIDs {');
           this.writer.incIndent;
           this.writer.wLine('RESPONSE_ERROR = 0,');
           this.writer.wLine('RESPONSE_OUTPUT_PRE_DATA = 1,');
           this.writer.wLine('RESPONSE_OUTPUT_DATA = 2,');
           this.writer.wLine('RESPONSE_PRINTF = 3,');
           this.writer.wLine('RESPONSE_FOPEN = 4,');
           this.writer.wLine('RESPONSE_FPRINTF = 5,');
           this.writer.wLine('RESPONSE_SIGNAL_RAISED = 6,');
           this.writer.wLine('RESPONSE_EXCEPTION = 7');
           this.writer.decIndent;
           this.writer.writeLine('};');
                      
           % structure to store file descriptor array
           this.writer.newLine;
           this.writer.writeLine('typedef struct {');
           this.writer.incIndent;
           this.writer.writeLine('FILE ** Fd;');
           this.writer.writeLine('mwSize size;');
           this.writer.writeLine('int32_T fidOffset;');
           this.writer.decIndent;
           this.writer.writeLine('} targetIOFd_T;');
           
           % enum to represent XIL command ids
           this.writer.newLine;
           this.writer.wBlockStart('typedef enum');
           this.writer.wLine('XIL_INIT_COMMAND = 0,');
           this.writer.wLine('XIL_INITIALIZE_COMMAND,');
           this.writer.wLine('XIL_SYSTEM_INITIALIZE_COMMAND,');
           this.writer.wLine('XIL_OUTPUT_COMMAND,');
           this.writer.wLine('XIL_TERMINATE_COMMAND,');
           this.writer.wLine('XIL_ENABLE_COMMAND,');
           this.writer.wLine('XIL_DISABLE_COMMAND,');
           this.writer.wLine('XIL_CONST_OUTPUT_COMMAND,');
           this.writer.wLine('XIL_PROCESS_PARAMS_COMMAND,');
           this.writer.wLine('XIL_CLIENT_SERVER_COMMAND,');
           this.writer.wLine('XIL_SHUTDOWN_COMMAND,');
           this.writer.wLine('XIL_UPDATE_COMMAND,');
           this.writer.wLine('XIL_SYSTEM_RESET_COMMAND,');
           this.writer.wLine('XIL_PAUSE_COMMAND');           
           this.writer.wBlockEnd;
           this.writer.wLine('XIL_COMMAND_TYPE_ENUM;');
           
           if ~this.IsMexTarget
               if this.SupportHalf
                   %When we're supporting Half-precision write out a local
                   %host definition for that type. This will be replaced.
                   %This needs replacing by a static header file.
                   this.writer.newLine;
                   this.writer.wLine('typedef struct {');
                   this.writer.incIndent;
                   this.writer.wLine('uint16_T bitPattern;');
                   this.writer.decIndent;
                   this.writer.wLine('} real16_T;');
                   this.writer.newLine;
               end
           end
           
           if this.IsMexTarget
               %Static data initializations, to store "pWork" values.
               this.writer.newLine;
               this.writer.wLine('static targetIOFd_T *targetIOFdPtr = NULL;');
               if ~this.IsUsingCommServiceAPI
                   this.writer.wLine('static XIL_RtIOStreamData_T* rtIOStreamDataPtr = NULL;');
                   this.writer.wLine('static SIL_DEBUGGING_DATA_T* silDebuggingDataPtr = NULL;');
               end
               this.writer.wLine('static XIL_IOBuffer_T* IOBufferPtr = NULL;');
               this.writer.wLine('static int* pCommErrorOccurred = NULL;');
               this.writer.wLine('static int* pIsXILApplicationStarted = NULL;');
               this.writer.wLine('static void* pXILService = NULL;');
               this.writer.wLine('static void* pComms = NULL;');
               this.writer.wLine('static void* pConnectionOptions = NULL;');
               this.writer.wLine('static void* %s = NULL;',this.XILUtilsVarName);
               this.writer.wLine('static void* pMemUnitTransformer = NULL;');               
               
               if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                   this.writer.wLine('static char* pXilAppDir = NULL;');
                   this.writer.wLine('static void* pCodeInstrService = NULL;');
                   this.writer.wLine('static time_T simTime = 1;');
               end
               
               if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
                   this.writer.wLine('static void* pCoderAssumptionsApp = NULL;');
               end               
               
               %Clean up protection flag
               this.writer.wLine('static boolean_T pKeepUtilsActive=0;');
               %Protection flag to prevent MEX API terminate function being
               %called during MEX at exit call.
               this.writer.wLine('static boolean_T executingClearMEX=0;');

               %ClearUp function to call in MEX API
               this.writer.wLine('static void (*cleanUp)(void);');
           end
           
           this.writer.newLine;
        end
        
        function numPWork = getNumPWork(this)
            assert(getNumPWork@rtw.connectivity.CodeInfoSfunction(this) == 0,...
                   'Unexpected number of PWorks');            
            numPWork = this.PWorkInfo.NumPWork;            
        end
        
        function pWorkIdx = getSharedDataStorePWorkIdx(this, ds)
            allSharedDataStores = this.SILPILWrapperUtils.getDataStoresToTransferInterfaces();
            assert(~isempty(allSharedDataStores), ...
                'Must have shared data stores to get the PWork idx');
            % lookup the index
            
            match = find(ds == allSharedDataStores);
            assert(isscalar(match), 'Must have 1-1 mapping between dsread/dswrite and shared data store list.');
            offset = match - 1;
            pWorkIdx = int2str(this.PWorkInfo.SharedDataStoresIdx + offset);
        end
                
        function pWorkIdx = getRtIOStreamPWorkIdx(this)
           % RtIOStream uses idx 0 or 1 depending
           % on execution profiling           
           pWorkIdx = int2str(this.PWorkInfo.RtIOStreamIdx);                      
        end                
        
        function pWorkIdx = getXILUtilsPWorkIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.XILUtilsIdx);
        end
        
        function pWorkIdx = getCommsPWorkIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.CommsIdx);
        end
        
        function pWorkIdx = getConnectionOptionsPWorkIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.ConnectionOptionsIdx);
        end
        
        function pWorkIdx = getXILServicePWorkIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.XILServiceIdx);
        end
        
        function pWorkIdx = getCodeInstrServicePWorkIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.CodeInstrServiceIdx);
        end
        
        function pWorkIdx = getCodeInstrMultiRunDataIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.CodeInstrMultiRunDataIdx);
        end
        
        function pWorkIdx = getXilAppDirIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.xilAppDirIdx);
        end
        
        function pWorkIdx = getCoderAssumptionsPWorkIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.CoderAssumptionsIdx);
        end
        
        function pWorkIdx = getCommErrorOccurredIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.CommErrorOccurred);
        end
        
        function pWorkIdx = getIsXILApplicationStartedIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.IsXILApplicationStarted);
        end
                
        function pWorkIdx = getIOBufferPWorkIdx(this)
           % get the index of the IOBuffer
           pWorkIdx = int2str(this.PWorkInfo.IOBufferIdx); 
        end
        
        function pWorkIdx = getSILDebuggingPWorkIdx(this)           
           pWorkIdx = int2str(this.PWorkInfo.SILDebuggingIdx); 
        end                        
        
        function pWorkIdx = getTargetIOFdArrPWorkIdx(this)
            % get the index of targetIOFd
            pWorkIdx = int2str(this.PWorkInfo.targetIOFdArrIdx);
        end
        
        function pWorkIdx = getMemUnitTransformerPWorkIdx(this)
            % get the index of MemUnitTransformer
            pWorkIdx = int2str(this.PWorkInfo.MemUnitTransformerIdx);
        end
        
        function pWorkIdx = getLoggingElementPWorkIdx(this, dataInterface)
            loggingData = this.SILPILWrapperUtils.getLoggingData;            
            assert(~isempty(loggingData), ...
                'Signal and state logging data must be non-empty to get the Element PWork idx');
            pWorkIdx = int2str(this.PWorkInfo.LoggingElementIdx + dataInterface.getDataInterfaceIdx - 1);
        end       
        
        function pWorkIdx = getLoggingTmpVarPWorkIdx(this, dataInterface)
            loggingData = this.SILPILWrapperUtils.getLoggingData;            
            assert(~isempty(loggingData), ...
                'Signal and state logging data must be non-empty to get the TmpVar PWork idx');
            pWorkIdx = int2str(this.PWorkInfo.LoggingTmpVarIdx + dataInterface.getDataInterfaceIdx - 1);
        end
        
        function pWorkIdx = getLoggingOffsetPWorkIdx(this, dataInterface)
            loggingData = this.SILPILWrapperUtils.getLoggingData;
            assert(~isempty(loggingData), ...
                'Signal and state logging data must be non-empty to get the TmpVar PWork idx');
            pWorkIdx = int2str(this.PWorkInfo.LoggingOffsetVarIdx + dataInterface.getDataInterfaceIdx - 1);
        end
        
        function pWorkIdx = getIsLoggingActiveIdx(this)
            pWorkIdx = int2str(this.PWorkInfo.IsLoggingActiveIdx);
        end
        
        
        function writeSectionInitializeSizesRegisterSimulinkAndCallerFunctions(this)            
            svrFcns = this.SILPILWrapperUtils.getServerFunctionsInfo;
            % register all the caller functions, both defined and undefined
            callerFcns = this.codeInfoUtils.getAllCallerFunctionsInfo;
                    
            allFcns = [];
            for fcnIdx = 1:length(svrFcns)
                allFcns{end+1} = svrFcns(fcnIdx); %#ok<AGROW>
            end
            
            for fcnIdx = 1:length(callerFcns)
                callerFcn = callerFcns(fcnIdx);
                if ~this.SILPILWrapperUtils.isServerFunctionFromOldAUTOSARClientBlock(...
                        callerFcn.getOperationName)
                    allFcns{end+1} = callerFcns(fcnIdx); %#ok<AGROW>
                end
            end
            
            for fcnIdx = 1:length(allFcns)
                fcn = allFcns{fcnIdx};
                if isa(fcn, 'rtw.pil.QueuedIOFunctionInfo')
                    %Skip Message functions.
                    continue;
                end
                
                % if this function is active
                if rtw.pil.CodeInfoData.isInterfaceActive(fcn.getCodeInfoData)
                    if isa(fcn, 'rtw.pil.ServerFunctionInfo') && fcn.IsExported && fcn.CompPortIndex < 0
                        slFcnName = fcn.getSlFunctionName;
                        this.writer.wBlockStartComment('',['Register Simulink function: ' slFcnName]);
                        
                        % Generate server function wrapper name from
                        % CodeInfo representation.
                        svrImpFcnName = rtw.pil.Sfunction.getServerFunctionWrapperName(fcn.getCodeInfoData);
                        svrImpFcnPointer = sprintf('&%s', svrImpFcnName);
                        
                        % Register the function wrapper against the 
                        % (non-scoped) name of the Simulink Function.
                        this.writer.writeLine('slcsSetSimulinkFunctionPtr(S, "%s", %s);',fcn.getSlFunctionName,...
                            svrImpFcnPointer);
                        this.writer.wBlockEnd; %register function end
                    end
                end
            end
        end
        
        function writeSectionInitializeSizesBodyHeader(this)
            if ~this.IsMexTarget
                % call super class method
                writeSectionInitializeSizesBodyHeader@rtw.connectivity.CodeInfoSfunction(this);
            end
        end
        
        function writeSectionInitializeSizesBody(this)
            % write header
            this.writeSectionInitializeSizesBodyHeader;
            % process DWorks
            this.writeSectionInitializeSizesDWorks;
            % process Global DS
            if ~this.IsMexTarget
                this.writeSectionInitializeSizesGlobalDS;
            end
            % process Inports and outports
            this.writeSectionInitializeSizesBodyInportsAndOutports;
            % get trailer
            if ~this.IsMexTarget
                this.writeSectionInitializeSizesBodyTrailer;
                if this.isXrelBlock
                    % register support for row major code generation
                    this.writer.wLine('ssSetSupportedForRowMajorCodeGen(S, true);');
                    % set array layout of this S-Function
                    if this.IsRowMajorTransformNeeded                                                
                        arrayLayout = 'SS_ROW_MAJOR';
                    else
                        arrayLayout = 'SS_COLUMN_MAJOR';
                    end
                    this.writer.wLine('ssSetArrayLayoutForCodeGen(S, %s);', ...
                        arrayLayout);
                end
            end        
            
            if this.SILPILWrapperUtils.needToProcessServerFcns || this.codeInfoUtils.hasUndefinedCallerFunctions
                 this.writeSectionInitializeSizesRegisterSimulinkAndCallerFunctions;
            end
        end
        
        % override super class method
        function writeSectionSetNumPWork(this)
            if this.IsMexTarget
                writeSectionSetNumPWork@rtw.connectivity.CodeInfoSfunction(this)
            else
                % For Simulink workflows, don't register PWorks during 
                % codegen or they will be declared in code generated for 
                % the parent model.
                %
                % We need to mirror this for External Mode simulations
                % to avoid the following:
                %   * Checksum mismatches (due to the PWorks being in the Dwork vector)
                %   * Attempting to start the XIL target application during
                %     external mode simulation for the parent model
                numPWork = this.getNumPWork;
                this.writer.wBlockStart('if(ssRTWGenIsCodeGen(S) || ssIsExternalSim(S) )');
                this.writer.writeLine('ssSetNumPWork(S, 0);');
                this.writer.wBlockMiddle('else');
                this.writer.writeLine(['ssSetNumPWork(S, ' int2str(numPWork) ');']);
                this.writer.wBlockEnd;
            end
        end
        
        function isLittle = isLittleEndian(this)
            byte_order = this.getEndianess;
            switch byte_order
              case 'Unspecified'                   
                rtw.pil.ProductInfo.error(...
                    'pil', 'UnspecifiedByteOrder', ...
                    this.SILPILWrapperUtils.getComponentForDiagnostics());
              case 'LittleEndian'
                isLittle=true;
              case 'BigEndian'
                isLittle=false;
              otherwise
                rtw.pil.ProductInfo.error('pil', 'UnknownByteOrder', byte_order);
            end
        end
        
        function lTypesWithDiffWordOrderEnumVals = getTypesWithDiffWordOrder(this)
        % Some types may have word ordering that differs from the byte ordering
        % (e.g. floating point types on C166 or Lego)
                
            if ~this.TypesWithDiffWordOrderDoneInit                
                                
                codeInfoTypes = enumeration('rtw.connectivity.CodeInfoTypeEnum');
                
                dataTypeServices = this.SILPILWrapperUtils.getTargetServices().getDataTypeService();
                
                wordLen = dataTypeServices.getWordSize();
                byteOrder = dataTypeServices.getEndianess();          
                    
                lTypesWithDiffWordOrderEnumVals = {};
                for i=1:length(codeInfoTypes)
                    codeInfoType = codeInfoTypes(i);
                    if strcmp(codeInfoType,'TypeOpaque')
                        %Opaque Types can't be probed.
                        continue;
                    end
                    dtSize = rtw.connectivity.TypeUtils.builtinHostByteSize(codeInfoType);
                    if (dtSize * 8) > wordLen
                        % multi-word datatype
                        dt = rtw.connectivity.TypeUtils.codeInfoTypeIdToType(codeInfoType);                        
                        dtWordOrder = dataTypeServices.getMultiWordDataTypeWordOrder(dt);
                        if ~strcmp(dtWordOrder, byteOrder)
                            lTypesWithDiffWordOrderEnumVals{end+1} = ...
                            rtw.connectivity.TypeUtils.getMemUnitEnumTypeFromStorageId(codeInfoType);  %#ok<AGROW>
                        end
                    end
                end
                this.TypesWithDiffWordOrderDoneInit = true;
                this.TypesWithDiffWordOrderEnumVals = lTypesWithDiffWordOrderEnumVals;
            end
            lTypesWithDiffWordOrderEnumVals = this.TypesWithDiffWordOrderEnumVals;
            
        end
        
        function writeSectionMemUnitXformerInit(this)
            
            if this.IsNeededMemUnitXform
                
                this.writer.wBlockStart('');
                this.writer.writeLine('boolean_T rtnVal;')
                if ~this.IsMexTarget
                    this.writer.writeLine('void * pMemUnitTransformer;')
                end

                wordLen = this.SILPILWrapperUtils.getParam('TargetWordSize')/8;
                assert(wordLen==1||wordLen==2||wordLen==4||wordLen==8, ...
                       'Must be a supported word length');
                this.writer.writeLine('const uint_T tgtWordLen = %d;', wordLen);
                this.writer.writeLine('boolean_T isByteAddressable = %d;', ...
                                      this.SILPILWrapperUtils.getTargetServices().getDataTypeService().getIsByteAddressable());

                typesWithDiffWordOrderEnumVals = this.getTypesWithDiffWordOrder;
                this.writer.writeLine('size_t numTypesDiffWordOrder = %d;',...
                                      length(typesWithDiffWordOrderEnumVals));
                if ~isempty(typesWithDiffWordOrderEnumVals)
                    typesWithDiffWordOrderEnumValsStr='';
                    for i=1:length(typesWithDiffWordOrderEnumVals)
                        typesWithDiffWordOrderEnumValsStr=sprintf...
                            ('%s, %s', typesWithDiffWordOrderEnumValsStr, typesWithDiffWordOrderEnumVals{i});
                    end
                    typesWithDiffWordOrderEnumValsStr = sprintf...
                        ('{%s}', typesWithDiffWordOrderEnumValsStr(3:end));
                    this.writer.writeLine('mem_unit_type_T diffWordOrderTypes[] = %s;', ...
                                          typesWithDiffWordOrderEnumValsStr);
                else
                    this.writer.writeLine...
                        ('mem_unit_type_T * diffWordOrderTypes = NULL;');
                end
                
                isLittleEndian = this.isLittleEndian;
                this.writer.writeLine('boolean_T isLittleEndian = %d;', ...
                                      isLittleEndian);
                this.writer.writeLine('rtnVal = memUnitXformer_Init(');
                this.writer.incIndent;
                this.writer.writeLine('&pMemUnitTransformer, ');
                this.writer.writeLine('tgtWordLen, ');
                this.writer.writeLine('isByteAddressable, ');
                this.writer.writeLine('isLittleEndian,');
                this.writer.writeLine('%d, diffWordOrderTypes);', ...
                                      length(typesWithDiffWordOrderEnumVals));
                this.writer.decIndent;

                this.writer.wBlockStart('if (rtnVal !=0)');
                this.writeErrorCall('Error in allocating memory for memory unit converter');
                this.writer.wLine('return%s;', this.ReturnArgString);
                this.writer.wBlockEnd; %if (rtnVal !=0)
                this.setPWorkValue(this.getMemUnitTransformerPWorkIdx, 'pMemUnitTransformer');
                this.writer.wBlockEnd;
                
            elseif ~this.IsMexTarget
                % cache a null ptr as placeholder for pMemUnitTransformer,
                % the transformer will not use it but we still need to pass
                % it to the xilRead/xilWrite APIs
                this.writer.wBlockStart('');
                this.setPWorkValue(this.getMemUnitTransformerPWorkIdx, 'NULL');
                this.writer.wBlockEnd;
            end
        end
        
        function  writeSectionCreateXILUtils(this)
            % create pXILUtils
            this.writer.wBlockStart('');
            this.writer.wLine('int retValXILUtils = XIL_UTILS_SUCCESS;');
            if ~this.IsMexTarget
                this.writer.wLine('void* %s = NULL;',this.XILUtilsVarName);
            end            
            % create the appropriate XIL Utils depending on context
            if this.IsMexTarget
                this.writer.wBlockStart('if (%s == NULL)',this.XILUtilsVarName)
                this.writer.writeLine('retValXILUtils = xilMATLABUtilsCreate(&%s);',...
                    this.XILUtilsVarName);
                this.writer.wBlockEnd(); %if this.XILUtilsVarName == NULL
            else
                this.writer.writeLine('retValXILUtils = xilSimulinkUtilsCreate(&%s, %s);',...
                    this.XILUtilsVarName, this.SimStructArgSingle);
            end
            this.writer.wBlockStart('if (retValXILUtils!=XIL_UTILS_SUCCESS)');
            % we can't use writeSectionProcessException since this requires
            % that we've successfully created XIL Utils
            this.writeErrorCall('Error instantiating XIL Utils!');
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; %if (retValXILUtils)            
            this.setPWorkValue(this.getXILUtilsPWorkIdx, this.XILUtilsVarName);
            this.writer.wBlockEnd; % pXILUtils creation
        end
        

        function writeSectionSetupRTRForFunctionPort(this)            
            svrFcns = this.SILPILWrapperUtils.getServerFunctionsInfo;
            for fcnIdx = 1 : length(svrFcns)
                fcn = svrFcns(fcnIdx);
                % If this function is active and associated with function port
                if rtw.pil.CodeInfoData.isInterfaceActive(fcn.getCodeInfoData) && ...
                    isa(fcn, 'rtw.pil.ServerFunctionInfo') && fcn.IsExported &&...
                    fcn.CompPortIndex >= 0

                    this.writer.wBlockStart('');
                    this.writer.wComment(...
                        ['Set up execution service for function port element: '...
                        fcn.ScopeName '.' fcn.getSlFunctionName]);

                    % Generate server function wrapper name from CodeInfo representation
                    svrWrpFcnName = rtw.pil.Sfunction.getServerFunctionWrapperName(fcn.getCodeInfoData);

                    % Setup the ExecService with the function pointer
                    this.writer.writeLine('slcsSetupFunctionPortExecService(S, %d, "%s", &%s);', ...
                        fcn.CompPortIndex, fcn.getSlFunctionName, svrWrpFcnName);
                    this.writer.wBlockEnd;
                end
            end
        end

        function writeSectionSetupRTRBody(this)

            if ~this.IsMexTarget
                % For Simulink-based workflows return early if code gen.
                % Must not access XIL wrapper PWorks.
                this.writeSectionReturnIfCodeGen;
            end
            
            % Exclude for internal testing mode
            if ~this.MATLABCoderNoECTestingMode
                % implement dynamic check of In-the-Loop version
                this.writer.wBlockStart('');
                % call checkEmbeddedCoderInstalled, if it exists
                this.writer.wLine('mxArray * error = NULL;');
                this.writer.wLine('error = mexCallMATLABWithTrap( 0, NULL, 0, NULL, "rtw.pil.checkEmbeddedCoderInstalled");');
                this.writer.wBlockStart('if (error != NULL)');
                this.writeCallToMEXAPITerminateFunction();
                this.writer.wLine('mexCallMATLAB( 0, NULL, 1, &error, "throw");');
                this.writer.wBlockEnd(); %If Error
                this.writer.wBlockEnd(); %Check Embedded Coder version code block
            end
            
            % Implement dynamic check of In-the-Loop version
            sfunVersion = rtw.pil.getPILVersion;
            numLHS = 1;
            this.writer.wBlockStart('');
            % call getPILVersion, if it exists - trap any errors
            this.writer.writeCellLines({'mxArray * lhs[1];'; ...
                'mxArray * error = NULL;'; ...
                'char * installVersion;'; ...
                ['error = mexCallMATLABWithTrap(' int2str(numLHS) ', lhs, ' ...
                '0, NULL, "rtw.pil.getPILVersion");'];});
            % check for errors
            this.writer.wBlockStart('if (error != NULL)');
            this.writer.wLine('mxDestroyArray(error);');
            this.writeCallToMEXAPITerminateFunction();
            this.writeErrorCall(['Failed to determine the installed In-the-Loop version for comparison against the In-the-Loop s-function version (release ' sfunVersion '). ' ...
                'To avoid this error, remove the In-the-Loop s-function from your MATLAB path (e.g. delete it or move to a clean working directory).']);
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; % if (error != NULL)
            
            this.writer.wBlockStart('if (mxIsEmpty(lhs[0]))');
            this.writeCallToMEXAPITerminateFunction();
            this.writeErrorCall('rtw.pil.getPILVersion returned empty!')
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; % if (mxIsEmpty(lhs[0]))
            
            % get the string
            this.writer.writeLine('installVersion = mxArrayToString(lhs[0]);');
            % lhs has been copied into other storage - free
            this.writeSectionDestroyArray('lhs', numLHS);
            
            
            this.writer.wBlockStart('if (installVersion == NULL)');
            this.writeCallToMEXAPITerminateFunction();
            this.writeErrorCall('Failed to determine installed In-the-Loop version.');
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; % if (installVersion == NULL)
            
            % compare install vs sfun version and throw error if needed
            %
            % note that this error is thrown early in mdlInitializeSizes,
            % before option SS_OPTION_CALL_TERMINATE_ON_EXIT takes effect.
            % This avoids all calling out to rtw.pil.SILPILInterface, which
            % we only want to do if we have a valid s-function.
            this.writer.wBlockStart('if (strcmp(installVersion, "%s") != 0)', sfunVersion);
            this.writeErrorCall(['The In-the-Loop s-function is incompatible with the installed In-the-Loop version (see ver(''matlab'')); ' ...
                'it was generated for release ' sfunVersion '. ' ...
                'To avoid this error, remove the In-the-Loop s-function from your MATLAB path (e.g. delete it or move to a clean working directory)'])
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; % if (strcmp(installVersion, "%s") != 0)
            
            % free strings
            this.writer.writeLine('mxFree(installVersion);');
            this.writer.wBlockEnd();
            this.writer.newLine;
            
            % create XILUtils
            this.writeSectionCreateXILUtils;
            
            this.writeRuntimeChecks();
            
            % Memory unit transformer
            this.writeSectionMemUnitXformerInit;
            
            % define shared data store memory and store in PWork
            if ~this.IsMexTarget
                allSharedDataStores = this.SILPILWrapperUtils.getDataStoresToTransferInterfaces();
                this.writeSectionDefineSharedDataStoreTmpVars(allSharedDataStores);
            end
            % define logging tmp var memory and store in PWork
            loggingData = this.SILPILWrapperUtils.getLoggingData;
            this.writeSectionRegistrationBusLogging(loggingData);
            this.writeSectionDefineLoggingTmpVars(loggingData);
            % define tmp var memory for all arguments for caller functions and store in PWork        
            callerFunctionsInfo = this.codeInfoUtils.getUndefinedCallerFunctionsInfo;
            this.writeSectionDefineAllCallerFunctionArgsTmpVars(callerFunctionsInfo);
            
            % initialize CommErrorOccurred
            this.writer.wBlockStart('');
            this.writer.wLine('%spCommErrorOccurred = (int *) mxCalloc(1, sizeof(int));', this.LocalpCommErrorOccurredType);
            this.writer.wBlockStart('if (pCommErrorOccurred == NULL)');
            this.writeErrorCall('Error in allocating memory for pCommErrorOccurred through mxCalloc.');
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; % if (pCommErrorOccurred == NULL)
            this.writer.writeLine('*pCommErrorOccurred = 0;');
            this.writer.writeLine('mexMakeMemoryPersistent(pCommErrorOccurred);');
            this.setPWorkValue( this.getCommErrorOccurredIdx, 'pCommErrorOccurred');
            this.writer.wBlockEnd;
            
            % initialize pIsXILApplicationStarted
            this.writer.wBlockStart('');
            this.writer.wLine('%spIsXILApplicationStarted = (int *) mxCalloc(1, sizeof(int));', this.LocalpIsXILApplicationStartedType);
            this.writer.wBlockStart('if (pIsXILApplicationStarted == NULL)');
            this.writeErrorCall('Error in allocating memory for pIsXILApplicationStarted through mxCalloc.');
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; % if (pIsXILApplicationStarted == NULL)
            this.writer.writeLine('*pIsXILApplicationStarted = 0;');
            this.writer.writeLine('mexMakeMemoryPersistent(pIsXILApplicationStarted);');
            this.setPWorkValue( this.getIsXILApplicationStartedIdx, 'pIsXILApplicationStarted');
            this.writer.wBlockEnd;
            
            if ~this.IsMexTarget || this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                this.writer.wBlockStart('');
                %call method 
                this.writeSectionSFunctionInitializeHook(loggingData)
                this.writer.wBlockEnd();
            end
            
            if this.SILPILWrapperUtils.needToProcessServerFcns || this.codeInfoUtils.hasUndefinedCallerFunctions
                 this.writeSectionSetupRTRForFunctionPort();
            end
        end
        

        function writeSectionSFunctionInitializeHook(this,loggingData)
            %This method can only be called for Simulink Coder or for
            %MATLAB Coder with Execution Profiling turned on.
            assert(~this.IsMexTarget || this.SILPILWrapperUtils.isCodeInstrumentationEnabled,...
                'Not using Simulink Coder or using MATLAB coder with Execution Profiling on.')
            
            errorReturn = sprintf('return%s;', this.ReturnArgString);
            
            
            if this.IsMexTarget && this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                % MATLAB Coder Case with Execution Profiling turned on
                % call sfunctionMLInitializeHook 
                % declarations
                numRHS = 3;
                numLHS = 1;
                this.writer.writeLine(['mxArray *rhs[' int2str(numRHS) '];']);
                this.writer.writeLine(['mxArray *lhs[' int2str(numLHS) '];']);
                this.writeCallMATLABTypeAndPathInputs( 0 );
                % determine the path of the top model (i.e. top of the model
                % reference hierarchy)
                this.writer.wBlockStart('');
                this.callMATLAB(numLHS, numRHS, 'rtw.pil.SILPILInterface.sfunctionMLInitializeHook', errorReturn);
                this.writer.wBlockEnd;
                
            else
                % Simulink Coder case            
                % call sfunctionInitializeHook
                % declarations
                numRHS = 4; 
                numLHS = 2;
                this.writer.writeLine(['mxArray *rhs[' int2str(numRHS) '];']);
                this.writer.writeLine(['mxArray *lhs[' int2str(numLHS) '];']);
                this.writeCallMATLABTypeAndPathInputs( 0 );
                % determine the path of the top model (i.e. top of the model
                % reference hierarchy)
                this.writer.wLine('rhs[3] = mxCreateString(%s);', this.getSimulinkModelPath);
                this.writer.wBlockStart('');
                this.callMATLAB(numLHS, numRHS, 'rtw.pil.SILPILInterface.sfunctionInitializeHook', errorReturn);
                this.writer.wBlockEnd;
            
            
                % signal logging - don't write this section if this is a MEX
                % build as no signal logging possible in MATLAB Coder
                if ~this.IsMexTarget
                    this.writer.wBlockStart('');
                   
                    numLoggingData = length(loggingData);
                    for i=1:numLoggingData
                        dataInterface = loggingData(i);
                        pWorkIdx = this.getLoggingElementPWorkIdx(dataInterface);
                        pWorkOffsetIdx = this.getLoggingOffsetPWorkIdx(dataInterface);
                        this.writeSectionInitLoggingOnSDI(dataInterface, pWorkIdx, pWorkOffsetIdx);
                    end
                    
                    this.writer.newLine;
                    this.freeSimulinkBlockPath; %Explicitly not straight after MATLAB Call as used by signal logging.
                    this.writer.wBlockEnd('');
                    
                    % create logging active flag
                    if ~isempty(loggingData)
                        this.writer.wBlockStart('');
                        isLoggingActiveVarName = 'isLoggingActive';
                        this.writer.wLine('boolean_T* %s = (boolean_T*) mxMalloc(sizeof(boolean_T));', isLoggingActiveVarName);
                        this.writer.wLine('*%s = false;', isLoggingActiveVarName);
                        this.writer.wLine('mexMakeMemoryPersistent(%s);', isLoggingActiveVarName);
                        this.setPWorkValue(this.getIsLoggingActiveIdx, isLoggingActiveVarName);
                        this.writer.wBlockEnd;
                    end
                     
                    if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                        % create shared map for containing the async queues of the
                        % Execution time profiler
                        % in case of Matlab coder, async queues are only stored
                        % within the profiler
                        this.writer.wBlockStart('');
                        this.writer.writeLine('void * multiRunDataPtr = xilSimulinkUtilsStaticInitMultiRunInstrData();');
                        this.setPWorkValue(this.getCodeInstrMultiRunDataIdx, ...
                            'multiRunDataPtr');
                        this.writer.wBlockEnd();
                        
                        this.writer.writeLine('char * pXilAppDir;');
                    end
                end
            end
            
            %For both MATLAB Coder (with Execution Profiling) and Simulink Coder cases
                
            if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                % store absolute path to XIL directory
                this.writer.writeLine('pXilAppDir = mxArrayToString(lhs[0]);');
                this.writer.writeLine('mexMakeMemoryPersistent(pXilAppDir);');
                this.setPWorkValue(this.getXilAppDirIdx(), 'pXilAppDir');
                this.writer.newLine;
                
            end
            
            % free lhs
            this.writeSectionDestroyArray('lhs', numLHS);
        end

        function writeSectionCleanupRTRBody(this)
            
            if ~this.IsMexTarget
                % For Simulink-based workflows return early if code gen.
                % Must not access XIL wrapper PWorks.
                this.writeSectionReturnIfCodeGen;
            end
            
            if this.SILPILWrapperUtils.isCodeInstrumentationEnabled && ...
                    ~this.IsMexTarget
                % terminate profiler async queues
                this.writer.wBlockStart('');
                this.writer.writeLine('void * pCodeInstrMultiRunData = NULL;');
                this.getPWorkValue('void', 'pCodeInstrMultiRunData', ...
                    this.getCodeInstrMultiRunDataIdx, false);
                this.writer.writeLine('xilSimulinkUtilsStaticFreeMultiRunInstrData(pCodeInstrMultiRunData);');
                this.writer.wBlockEnd();
                
                %free memory storing the path to XIL directory
                this.writer.wBlockStart('');
                this.writer.writeLine('char * pXilAppDir = NULL;');
                this.getPWorkValue('char', 'pXilAppDir', ...
                    this.getXilAppDirIdx, false);      
                this.writer.wBlockStart('if (pXilAppDir != NULL)');
                this.writer.writeLine('mxFree(pXilAppDir);');
                this.setFreedPWorkValueToNull('pXilAppDir', this.getXilAppDirIdx);
                this.writer.wBlockEnd(); %'if (pXilAppDir != NULL)'
                this.writer.wBlockEnd();
            end

            % terminate async queues for logged signals
            loggingData = this.SILPILWrapperUtils.getLoggingData;
            for i=1:length(loggingData)
                this.writeSectionTermLoggingOnSDI(...
                    this.getLoggingElementPWorkIdx(loggingData(i)));
            end
            if ~isempty(loggingData)
               this.writer.wBlockStart('');
               isLoggingActiveVarName = 'isLoggingActive';
               this.getPWorkValue('boolean_T', isLoggingActiveVarName, this.getIsLoggingActiveIdx, true);
               this.writer.wBlockStart('if (%s != NULL)', isLoggingActiveVarName);
               this.writer.wLine('mxFree(%s);', isLoggingActiveVarName);
               this.setFreedPWorkValueToNull(isLoggingActiveVarName, this.getIsLoggingActiveIdx);
               this.writer.wBlockEnd;
               this.writer.wBlockEnd;
           end
            
            % free pIsXILApplicationStarted and pCommErrorOccurred
            if ~this.IsMexTarget
                this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');
            else
                this.writer.wBlockStart('');
            end
            this.getPWorkValue('int', 'pIsXILApplicationStarted', this.getIsXILApplicationStartedIdx, true);
            this.getPWorkValue('int', 'pCommErrorOccurred', this.getCommErrorOccurredIdx, true);
            this.writer.wBlockStart('if (pIsXILApplicationStarted != NULL)');
            % if called from within error clean up, mark application as
            % stopped only
            if this.IsMexTarget
                this.writer.wBlockStart('if (pKeepUtilsActive == 0)');
            end
            this.writer.writeLine('mxFree(pIsXILApplicationStarted);');
            this.setFreedPWorkValueToNull('pIsXILApplicationStarted', this.getIsXILApplicationStartedIdx);
            if this.IsMexTarget
                this.writer.wBlockEnd; %if pKeepUtilsActive == 0
            end
            this.writer.wBlockEnd; %if (pIsXILApplicationStarted != NULL)
            this.writer.wBlockStart('if (pCommErrorOccurred != NULL)');
            this.writer.writeLine('mxFree(pCommErrorOccurred);');
            this.setFreedPWorkValueToNull('pCommErrorOccurred', this.getCommErrorOccurredIdx);
            this.writer.wBlockEnd; %if (pCommErrorOccurred != NULL
            
            % close the code block, it is OK have the same code in both
            % branches of this if/else as it helps keeping track of which
            % block is being closed.
            if ~this.IsMexTarget %#ok<IFBDUP>
                this.writer.wBlockEnd; %if (ssGetPWork(S) != NULL)
            else
                this.writer.wBlockEnd; %'' 
            end
            
            % define memory associated with all arguments of all the caller functions
            callerFunctionsInfo = this.codeInfoUtils.getUndefinedCallerFunctionsInfo;
            for callFcnIdx = 1:length(callerFunctionsInfo)
                argsDataInterfaces = callerFunctionsInfo(callFcnIdx).getAllDataInterfaces;
                this.writeSectionFreeTmpVars(argsDataInterfaces, 'CallerFunctionArgs',...
                    callerFunctionsInfo(callFcnIdx));
            end
            
            % define logging tmp var memory and store in PWork
            loggingData = this.SILPILWrapperUtils.getLoggingData;
            [loggingDataToDelete, sharingDataIdx] = rtw.pil.LoggingUtils.filterUnneededBufferUpload(loggingData);
            this.writeSectionFreeTmpVars(loggingDataToDelete, 'logging');
            this.writeSectionNullInSharedLoggingTmpVars(loggingData, sharingDataIdx);
            
            % free memory associated with shared data stores
            if ~this.IsMexTarget
                allSharedDataStores = this.SILPILWrapperUtils.getDataStoresToTransferInterfaces();
                this.writeSectionFreeTmpVars(allSharedDataStores, 'datastore');
            end
            
            % free the memory unit converter
            writeSectionMemUnitTransformerDestroy();
            
            % delete the cached PILInterface if needed
            this.writeSectionDeleteCachedPILInterface();
            
            % free XIL utils
            if this.IsMexTarget
                this.writer.wBlockStart('if (pKeepUtilsActive != 1)');
            else
                this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');
            end
            this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);

            this.writer.wBlockStart('if(%s != NULL)', this.XILUtilsVarName);
            this.writer.wLine('xilUtilsDestroy(%s);', this.XILUtilsVarName);
            this.setFreedPWorkValueToNull(this.XILUtilsVarName, this.getXILUtilsPWorkIdx);
            this.writer.wBlockEnd;
            if this.IsMexTarget
                this.writer.wBlockEnd(); % if pKeepUtilsActive != 1
            else
                this.writer.wBlockEnd; %if (ssGetPWork(S) != NULL)
            end
            
            function writeSectionMemUnitTransformerDestroy
               if this.IsNeededMemUnitXform
                   % make sure PWork itself has been initialized
                   if ~this.IsMexTarget
                       this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');
                   end
                   % make sure PWork contents have been initialized
                   this.getPWorkValue('void', 'pMemUnitTransformer', this.getMemUnitTransformerPWorkIdx, true);
                   this.writer.wBlockStart('if (pMemUnitTransformer != NULL)');
                   this.writer.writeLine('memUnitXformer_Destroy(pMemUnitTransformer);');
                   this.setFreedPWorkValueToNull('pMemUnitTransformer', this.getMemUnitTransformerPWorkIdx);
                   this.writer.wBlockEnd; % if (pMemUnitTransformer != NULL)
                   if ~this.IsMexTarget
                       this.writer.wBlockEnd; % if (ssGetPWork(S) != NULL)
                   end
               end
           end
        end

        function writeSectionStartBody(this)
            % check that mdlStart is called only once
            if ~this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid
               % If component boundary validation failed, return early,
               % leaving a stub.
               return;
            end
           
            this.writer.wBlockStart('');
            if ~this.IsMexTarget
                this.getPWorkValue('int', 'pIsXILApplicationStartedLocal', this.getIsXILApplicationStartedIdx, true);
            else
                this.writer.wLine('int *pIsXILApplicationStartedLocal = pIsXILApplicationStarted;');
            end
            this.writer.wBlockStart('if (pIsXILApplicationStartedLocal != NULL && (*pIsXILApplicationStartedLocal) != 0)');
            this.writeErrorCall('Failed to start the application: another instance is already running.');
            this.writer.wLine('return %s;', this.ReturnArgString);
            this.writer.wBlockEnd();
            this.writer.wBlockEnd();
            
            % start the application
            this.writer.wBlockStart('');
            this.writer.wLine('boolean_T applicationStarted = startAndSetupApplication(%s);',...
                this.SimStructArgSingle);
            this.writer.wBlockStart('if (!applicationStarted)');
            this.writer.wLine('callStopHookAndFreeSFcnMemory(%s);', this.SimStructArgSingle);
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd();
            this.writer.wBlockEnd();
            
            this.writeSectionStartSendInitializeCommand;
        end
        
        function writeSectionStartSendInitializeCommand(this)
            % Is overridden in subclasses
            this.writer.wLine('sendInitializeCommand(%s);',...
                this.SimStructArgSingle);
        end
        
        function writeSectionPause(this)
           if ~this.IsMexTarget
               % If not MATLAB Coder SIL use super class method
               writeSectionPause@rtw.connectivity.CodeInfoSfunction(this);
           end
        end

        function writeSectionPauseBody(this)
            
            % Return early if generating code - must not access XIL
            % wrapper PWorks
            this.writeSectionReturnIfCodeGen;
            
            % check the event: pause (simStatus==SIM_PAUSE) or resume
            % (simStatus==SIM_CONTINUE)
            this.writer.wBlockStart('if (simStatus == SIM_PAUSE)');
            % simulation is paused
            % step 1. send message to the target
            inportIndices = [];
            paramIndices = [];
            dsReadIndices = [];
            dsWriteIndices = [];
            sharedLocalDataStoreIndices = [];
            outportIndices = [];
            loggingIndices = [];
            serverFcnIndex = [];
            inportSizesIndices = [];
            outportSizesIndices = [];
            errorReturn = sprintf('return %s;', this.ReturnArgString);
            tid = [];
            taskTiming = [];
            this.writeSectionPILIOCommand('XIL_PAUSE_COMMAND', ...
                                          inportIndices, ...
                                          inportSizesIndices, ...
                                          paramIndices, ...
                                          dsReadIndices, ...
                                          dsWriteIndices, ...
                                          sharedLocalDataStoreIndices, ...
                                          outportIndices, ...
                                          outportSizesIndices, ...
                                          loggingIndices, ...
                                          serverFcnIndex, ...
                                          tid, ...
                                          taskTiming, ...
                                          errorReturn);
            % step 2. call hook: sfunctionPILPauseHook
            assert(~this.IsMexTarget, 'only expect to deal with no mex targets');
            this.writer.wBlockStart(''); 
            this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
            this.writer.wBlockStart('if (%s)', this.XILUtilsVarName);
            numRHS = 3;
            this.writer.writeLine(['mxArray *rhs[' int2str(numRHS) '];']);
            this.writeCallMATLABTypeAndPathInputs( 0 );
            % rhs will get freed automatically by xilUtilsCallMATLAB       
            this.writer.wBlockStart('if (xilUtilsCallMATLAB(%s, 0, NULL, %d, rhs, "rtw.pil.SILPILInterface.sfunctionPILPauseHook")!= XIL_UTILS_SUCCESS)', this.XILUtilsVarName, numRHS);
            this.writer.writeLine(errorReturn);
            this.writer.wBlockEnd; % if (xilUtilsCallMATLAB)
            this.freeSimulinkBlockPath;
            this.writer.wBlockEnd; % if (pXILUtils)
            this.writer.wBlockEnd;
            this.writer.wBlockEnd; % simStatus == SIM_PAUSE
        end
        
       function writeSectionProcessParametersBody(this)
           if ~this.IsMexTarget
               % Return early if generating code from Simulink target -
               % must not access XIL wrapper PWorks.
               this.writeSectionReturnIfCodeGen;
           end
           this.writer.wLine('processParams(S);');                      
       end             
       
       function [blockPathVariable, nElems] = ...
               writeLastSignalStreamingBlockPath(this, blockPath)

           nElems = numel(blockPath);
           this.writer.writeLine('const char * blockPathStrs[%d];', nElems);
           for i = 1:nElems
               this.writer.writeLine('blockPathStrs[%d] = "%s";', i - 1, coder.internal.getEscapedString(blockPath{i}));
           end

           % set element block path variable
           blockPathVariable = 'blockPathStrs';
       end
       
       function writeSectionTermLoggingOnSDI(this, pWorkIdx)
           this.writer.wBlockStart('');
           this.writer.writeLine(['sdiAsyncQueueHandle aSyncQueue = ssGetPWorkValue(S, ' ...
               pWorkIdx ');']);
           % aSyncQueue is NULL if fast restart is OFF and data logging
           % override is ON and has disabled streaming for the signal
           this.writer.wBlockStart('if (aSyncQueue != NULL)');
           this.writer.writeLine('sdiTerminateStreaming(&aSyncQueue);');
           this.writer.writeLine('ssSetPWorkValue(S, %s, NULL);', pWorkIdx);
           this.writer.wBlockEnd();
           this.writer.wBlockEnd();
       end
       
       function writeSectionInitLoggingOnSDI(this, dataInterface, pWorkIdx, pWorkOffsetIdx)
           codeInfoDataInterface = dataInterface.getRTWDataInterface;
           elementArgs.dataInterface = dataInterface;
           elementArgs.pWorkIdx = pWorkIdx;
           elementArgs.pWorkOffsetIdx = pWorkOffsetIdx;
           % determine if sample time is constant
           isConst = strcmp(codeInfoDataInterface.Timing.TimingMode, ...
               'ONESHOT');
           elementArgs.isConst = isConst;
           
           this.writer.wBlockStart('');
           this.getPWorkValue('void', this.XILUtilsVarName, ...
               this.getXILUtilsPWorkIdx, true);
           [blockPathVariable, nElems] = ...
               this.writeLastSignalStreamingBlockPath(dataInterface.getEscapedBlockPath);
           elementArgs.blockPath = blockPathVariable;
           elementArgs.blockPathLength = nElems;
           this.writeSectionInitAQForLogging(elementArgs);
           this.writer.wBlockEnd;
       end
       
       function writeSectionInitAQForLogging (this, elementArgs)
           dataInterface = elementArgs.dataInterface;
           dataElements = dataInterface.getHostDataElements;
           
           isBusLoggingSupported = coder.internal.connectivity.featureOn('BusLogging');
           % at this point, we assume that dataInterfaces for NVBuses are
           % passed to this method if and only if BusLogging is active.
           % However, the code to manage NVBus is under feature control
           % as an additional security step
           if isBusLoggingSupported
               [isStandardSignal, dataElements, numDataElements] = ...
                   rtw.pil.LoggingUtils.processDataElements(dataInterface, dataElements);
           else
               % without bus support, we only process the first dataElement
               dataElements = dataElements(1);
               numDataElements = 1;
               isStandardSignal = true;
           end
           
           this.writer.wBlockStart('');
           % declare main AQ and data type handles (dtH)
           this.writer.wLine('void *AQ = NULL;');
           if isStandardSignal
               this.writer.wLine('const void *dtH = NULL;');
           else
               this.writer.wLine('const void *dtH[%d] = {NULL};', numDataElements);
           end
           offsetVarName = 'signalOffset';
           this.writer.wLine('int *%s = (int *) ssGetPWorkValue(S, %s);', offsetVarName, elementArgs.pWorkOffsetIdx);
           
           lDimSize = cell(1, numDataElements);
           lDimName = cell(1, numDataElements);
           lComplex = cell(1, numDataElements);
           portIdx = int2str(dataInterface.getPortIdx());
           escapedLoggingName = ['"' dataInterface.getEscapedLoggingName() '"'];
           propagatedName = ['"' dataInterface.getPropagatedName() '"'];
           escapedUnit = ['"' dataInterface.getEscapedUnit() '"'];
           sampleTime = dataInterface.getSamplePeriod();
           offset = num2str(dataInterface.getRTWDataInterface().Timing.SampleOffset);
           decimation = int2str(dataInterface.getDecimation());
           maxPoints = int2str(dataInterface.getMaxPoints());
           domain = ['"' dataInterface.getDomain() '"'];
           blockPath = elementArgs.blockPath;
           blockPathLength = elementArgs.blockPathLength;
           sidElems = dataInterface.getEscapedTimerSeriesSID();
           sidNumElems = numel(sidElems);
           assert(blockPathLength == sidNumElems, 'SID and Block must have the same number of elements');
           sidElemVarName = 'sidChain';
           this.writer.wLine('const char* %s[%d];', sidElemVarName, sidNumElems);

           % get all dataElements types. We need them for computing both
           % dimensions and dtHs
           types = cell(1, numDataElements);
           for i = 1 : numDataElements
               types{i} = dataElements(i).getType();
           end
           
           % don't marge the following two loops otherwise all the
           % declarations aren't collected at the beginning of the code
           % block. writeSymbolicDimsVarInitialization declares and assign
           % the dimension at the same time while dtHs are only assigned
           %
           % For each dataElement, generate its dimensions
           this.writer.wComment('Generate dimensions');
           for i = 1 : numDataElements
               dataElement = dataElements(i);
               type = types{i};
               [isComplex, isReal, symbolicDimensions] = dataElement.getComplexInfo;
               isString = false;
               if isComplex
                   assert(isReal, 'only expect to process real dataElements');
                   dimensions = symbolicDimensions;
                   lComplex{i} = 'true';
               else
                   lComplex{i} = 'false';
                   if type.isChar
                       dimensions = {'1'}; % Simulink doesn't support strings arrays
                       isString = true;
                   else
                       dimensions = dataInterface.getSymbolicDimensions(dataElement);
                   end
               end
               regionLength = dataInterface.getRegionLength();
               if isBusLoggingSupported && ~isString && regionLength > 0 && ...
                       dataInterface.getIsNVBus() && numDataElements == 1 && ...
                       dataInterface.getBusSelectorIndex() > 0 && ...
                       isscalar(dimensions) && str2double(dimensions{1}) > regionLength
                   % A special case happens when we log a signal which is 
                   % from a bus selector and then one or more selector 
                   % objects.
                   % In this case, we need to update its dimension to 
                   % configure SDI correctly and this cannot be done in 
                   % getSymbolicDimensions because that method is shared 
                   % with the generation of the host/target side: they need
                   % to upload the entire bus, the trim is done later on 
                   % the host.
                   % For array of (non-bus) elements it isn't a problem 
                   % because we upload the sub-array directly and 
                   % getSymbolicDimensions returns the correct dimension 
                   % already.
                   % For entire buses isn't an issue (size is 1).
                   % For part of bus array, it is fine as well
                   dimensions = {num2str(regionLength)};
               end
               lDimSize{i} = int2str(length(dimensions));
               lDimName{i} = sprintf('dims_%d', i);
               this.writeSymbolicDimsVarInitialization(dimensions, lDimName{i});
           end
           % generate SID chain
           for sidIndex = 1:sidNumElems
               % dataInterface.getRTWDataInterface.SID may return values 
               % like model_mid3:4#out:1 - remove port suffix
               this.writer.wLine('%s[%d] = "%s";', sidElemVarName, sidIndex - 1, strtok(sidElems{sidIndex}, '#'));
           end
           % for each dataElement, generate its type
           this.writer.wComment('Generate data type');
           for i = 1 : numDataElements
               if isStandardSignal
                   dtHAssignment = 'dtH';
               else
                   dtHAssignment = sprintf('dtH[%d]', i-1);
                   this.writer.wBlockStart('');
               end
               type = types{i};
               rtw.pil.LoggingUtils.writeSectionInitAQDataType(this.writer, ...
                   this.SILPILWrapperUtils, this.codeInfoUtils, type, dtHAssignment);
               if ~isStandardSignal
                   this.writer.wBlockEnd();
               end
           end

           if this.SILPILWrapperUtils.isLoggingFromTransformedModel()
               lXILUtilsVarName = 'NULL';
           else
               lXILUtilsVarName = this.XILUtilsVarName;
           end
           
           % compute the offset in case of only part of the data interface
           % is logged (the target uploads the entire memory area and it is
           % up to the host side to receive it and pass to SDI only the
           % portion we want to log)
           rtw.pil.LoggingUtils.computeOffset(this.writer, offsetVarName, dataInterface, isBusLoggingSupported);
           if isStandardSignal
               % standard signal - it doesn't belong to a structure
               commonFields = [lXILUtilsVarName ', ' ...
                   escapedLoggingName ', ' ...
                   propagatedName ', ' ...
                   escapedUnit ', ' ...
                   lDimSize{1}, ',', ...
                   lDimName{1} ',' ...
                   portIdx ', '...
                   lComplex{1} ', ' ...
                   sampleTime ', ' ...
                   offset ', ' ...
                   decimation ', ' ...
                   maxPoints ', ' ...
                   blockPath ',' ...
                   sidElemVarName ',' ...
                   num2str(blockPathLength) ',' ...
                   domain];
               this.writer.wLine(['AQ = xilSimulinkUtilsCreateSDISignal(' coder.internal.getEscapedString(commonFields) ', dtH);']);
           else
               % non-virtual bus
               
               % create hierarchy tree from all DataElements
               [whoIsTheParent, childName, childType, childDim, childDims, hierOwner, leafNames] = ...
                   rtw.pil.LoggingUtils.extractNVBusStruct(dataInterface);
               
               % serialize complexity, dimension and variables for each leaf
               leafComplexStr = lComplex{1};
               leafDimSizeStr = sprintf('%s', lDimSize{1});
               hierOwnerStr = sprintf('%d', hierOwner(1));
               leafNameStr = sprintf('"%s"', leafNames{1});
               for i = 2 : numDataElements
                   leafComplexStr = sprintf('%s, %s', leafComplexStr, lComplex{i});
                   leafDimSizeStr = sprintf('%s, %s', leafDimSizeStr, lDimSize{i});
                   hierOwnerStr = sprintf('%s, %d', hierOwnerStr, hierOwner(i));
                   leafNameStr = sprintf('%s, "%s"', leafNameStr, leafNames{i});
               end
               % serialize variables about the struct hierarchy
               hierParentIdStr = sprintf('%d', whoIsTheParent(1));
               hierNamesStr = sprintf('"%s"', childName{1});
               hierDimStr = sprintf('%d', childDim(1));
               numHierElems = length(childType);
               for i=2:numHierElems
                   hierParentIdStr = sprintf('%s, %d', hierParentIdStr, whoIsTheParent(i));
                   hierNamesStr = sprintf('%s, "%s"', hierNamesStr, childName{i});
                   hierDimStr = sprintf('%s, %d', hierDimStr, childDim(i));
               end
               % create another code block to define new variables
               this.writer.wBlockStart('');
               % define all variables: leaves and hierarchy
               this.writer.wLine('const char* leafNames[%d] = {%s};', numDataElements, leafNameStr);
               this.writer.wLine('int leafOffset[%d];', numDataElements);
               this.writer.wLine('bool leafComplex[] = {%s};', leafComplexStr);
               this.writer.wLine('int* leafDimNames[%d];', numDataElements);
               for i = 1:numDataElements
                   this.writer.wLine('leafDimNames[%d] = %s;', i-1, lDimName{i});
               end
               this.writer.wLine('int leafDimSizes[] = {%s};', leafDimSizeStr);
               this.writer.wLine('int hierNum = %d;', numHierElems);
               this.writer.wLine('const char* hierNames[] = {%s};', hierNamesStr);
               this.writer.wLine('int hierParentId[] = {%s};', hierParentIdStr);
               this.writer.wLine('int hierOwner[] = {%s};', hierOwnerStr);
               this.writer.wLine('int hierSizes[%d];', numHierElems);
               this.writer.wLine('slDataTypeAccess * dta = ssGetDataTypeAccess(S);');
               this.writer.wLine('const char * bpath = ssGetPath(S);');
               this.writer.wLine('int offsetIdx;');
               this.writer.wLine('int hierDim[] = {%s};', hierDimStr);
               % generate dimensions for each node in the hierarchy
               for i=1:numHierElems
                   dims = childDims{i};
                   tmpHierDims = sprintf('%d', str2double(dims{1}));
                   for j=2:length(dims)
                       tmpHierDims = sprintf('%s, %d', tmpHierDims, str2double(dims{j}));
                   end
                   this.writer.wLine('int hierDims_%d[] = {%s};', i-1, tmpHierDims);
               end
               this.writer.wLine('int* hierDims[%d];', numHierElems);
               for i=1:numHierElems
                   this.writer.wLine('hierDims[%d] = hierDims_%d;', i-1, i-1);
               end

               % serialize offset and name for each leaf
               rtw.pil.LoggingUtils.writeSectionFieldsInNVBus(this.writer, 'leafOffset', dataElements);
               % serialize size for each node in the hierarchy
               rtw.pil.LoggingUtils.writeSectionNodeSizeInNVBus(this.writer, 'hierSizes', childType);
               % create AQ
               commonFields = [lXILUtilsVarName ', ' ...
                   escapedLoggingName ', ' ...
                   propagatedName ', ' ...
                   portIdx ', '...
                   sampleTime ', ' ...
                   offset ', ' ...
                   decimation ', ' ...
                   maxPoints ', ' ...
                   blockPath ',' ...
                   sidElemVarName ',' ...
                   num2str(blockPathLength) ',' ...
                   domain];
               this.writer.wLine(['AQ = xilSimulinkUtilsCreateSDINVBus(' ...
                   '%s, hierSizes, %d, leafNames, leafOffset, dtH, '...
                   'leafComplex, leafDimSizes, leafDimNames, hierNum, '...
                   'hierNames, hierParentId, hierOwner, hierDim, hierDims);'], ...
                       coder.internal.getEscapedString(commonFields), numDataElements);
               this.writer.wBlockEnd();
           end
           
           this.writer.wLine('ssSetPWorkValue(S, %s, AQ);', elementArgs.pWorkIdx);
           this.writer.wBlockEnd();
       end
       
       function paramIndices = getParamIndicesForFunction(this, functionInterface)
           % use codeInfoUtils implementation to get parameters
           paramIndices = this.codeInfoUtils.getParamIndicesForFunctionImpl(...
               functionInterface, this.SILPILWrapperUtils);
       end
       
       function writeSectionConstOutputCommand(this)
           inportIndices = [];
           paramIndices = [];
           dsReadIndices = [];
           dsWriteIndices = [];
           sharedLocalDataStoreIndices = [];
           outportIndices = this.codeInfoUtils.getOutputPortsForRates(this.codeInfoUtils.getRates('ONESHOT'));
           loggingIndices = [];                     
           inportSizesIndices = [];
           % constant outputs var dims not supported
           outportSizesIndices = [];
           serverFcnIndex = [];
           % step
           %
           % tid not used
           tid = [];
           taskTiming = [];
           this.writeSectionPILIOCommand('XIL_CONST_OUTPUT_COMMAND', ...
               inportIndices, ...
               inportSizesIndices, ...
               paramIndices, ...
               dsReadIndices, ...
               dsWriteIndices, ...
               sharedLocalDataStoreIndices, ...
               outportIndices, ...
               outportSizesIndices, ...
               loggingIndices, ...
               serverFcnIndex, ...
               tid, ...
               taskTiming);           
       end
       
       function writeSectionOutputs(this)
           if ~this.IsMexTarget
               %If not MATLAB Coder SIL use super class method
               writeSectionOutputs@rtw.connectivity.CodeInfoSfunction(this);
               
           else
               taskIdx = 1;
               this.writeSectionOutputsBody(taskIdx);
           end
       end
       
       function writeSectionUpdate(this)
           if ~this.IsMexTarget
               %If not MATLAB Coder SIL use super class method
               writeSectionUpdate@rtw.connectivity.CodeInfoSfunction(this);
           end
       end
       
       function writeSectionCommonOutputUpdateBody(this,type,taskIdx)
           if this.codeInfoUtils.isSampleTimeIndependent || ((strcmp(type,'XIL_OUTPUT_COMMAND') && taskIdx ~= 1))
               % schedule inherited task (taskIdx = 1) or Reset/Terminate task
               
               tasks = this.getTasksSampleTimeIndependent(type);
               
               if ~isempty(tasks)
                   
                   tid = tasks(taskIdx).id;
                   % the explicit tasking code is generated in entry functions.
                   % There's no need to regenerate them into step body. Thus, skip them.
                   if this.skipExplicitTaskingTaskInExportFunctions(tasks(taskIdx)) && ...
                           taskIdx==1
                       return;
                   end
                   if ~this.IsMexTarget
                       this.writer.wComment('inherited (possibly triggered) single rate scheduling');
                       this.writer.wBlockStart('if (tid != CONSTANT_TID)');
                   end
                   
                   %
                   % Generate the output/update function call
                   %                   
                   [inportIndices,...
                       inportSizesIndices,...
                       paramIndices,...
                       dsReadIndices,...
                       dsWriteIndices,...
                       sharedLocalDataStoreIndices,...
                       outportIndices,...
                       outportSizesIndices,...
                       loggingIndices,...
                       serverFcnIndex] = generateIndices(this,type,tasks(taskIdx));                   
                   
                   if  ~isempty(loggingIndices) || ...
                           (this.SILPILWrapperUtils.isCodeInstrumentationEnabled && ~this.IsMexTarget )
                       % note: for signal logging/singletasking, "rate time" must be calculated for
                       % each specific rate. With execution
                       % profiling/singletasking the rate time cannot currently be
                       % determined and this may result in a rounding error differences (g837111).
                       this.writer.wLine('time_T taskTime = ssGetT(S);');
                   end
                   taskTiming = tasks(taskIdx).codeInfoData.Timing;
                   this.writeSectionPILIOCommand(type,...
                       inportIndices,...
                       inportSizesIndices,...
                       paramIndices,...
                       dsReadIndices,...
                       dsWriteIndices,...
                       sharedLocalDataStoreIndices,...
                       outportIndices,...
                       outportSizesIndices,...
                       loggingIndices,...
                       serverFcnIndex,...
                       tid, ...
                       taskTiming);
                   
                   if ~this.IsMexTarget
                       this.writer.wBlockEnd; % if (tid != CONSTANT_TID)
                   end
               end
           else
               % schedule periodic tasks
               
               if ismember(type, {'XIL_OUTPUT_COMMAND', 'XIL_UPDATE_COMMAND'}) ...
                    && this.IsConstant
                    % Constant models have no periodic tasks.
                    tasks = [];
                    taskNames = {};
               else
               [tasks, taskNames] = this.getTasksScheduledWithName(type);
               end
               
               multitasking = this.codeInfoUtils.isMultiTasking;
               multirate = this.codeInfoUtils.isMultiRate;
               
               for taskIdx = 1:length(tasks)
                   task = tasks(taskIdx);
                   taskName = taskNames{taskIdx};
                   
                   % the explicit tasking code is generated in entry functions.
                   % There's no need to regenerate them into step body. Thus, skip them.
                   if this.skipExplicitTaskingTaskInExportFunctions(task)
                       continue;
                   end
                   
                   if multitasking
                       % multitasking implies multirate
                       this.writer.writeLine('/* Multirate, multitasking scheduling */');
                   else
                       if multirate
                           this.writer.writeLine('/* Multirate, singletasking scheduling */');
                       else
                           
                           this.writer.writeLine('/* Singlerate scheduling */');
                       end
                   end
                   % in the single-tasking case, all sample rates are
                   % scheduled to transfer their I/O data with the task base rate
                   %
                   % for signal logging, we must further restrict updating the
                   % timeseries so that we don't log too many data points
                   % for sub-rates
                   this.writer.wComment(['check for sample time hit associated with task ' int2str(taskIdx)]);
                   [sampleHitCExpr, ~] = this.getRateSampleHitCExpr(task.codeInfoData.Timing);
                   if ~isempty(sampleHitCExpr)
                       this.writer.wBlockStart(['if (' sampleHitCExpr ')']);
                       this.writer.wLine('%s(%s, tid);', taskName, this.SimStructArgSingle);
                       this.writer.wBlockEnd; % if (' sampleHitCExpr ')
                   end
               end
           end
       end
       function writeSectionPeriodicFunctions(this)
           
           if this.IsConstant
               % Constant models have no periodic functions!
               return;
           end
           
           callTypes = {'XIL_OUTPUT_COMMAND','XIL_UPDATE_COMMAND'};
           for idx = 1:numel(callTypes)
               type = callTypes{idx};
                   
               % schedule periodic tasks
               [tasks, taskNames] = this.getTasksScheduledWithName(type);
               multitasking = this.codeInfoUtils.isMultiTasking;               
               
               for taskIdx = 1:length(tasks)
                   task = tasks(taskIdx);
                   taskName = taskNames{taskIdx};
                   
                   % the explicit periodic tasking code is generated in entry functions.
                   % There's no need to regenerate them into step body. Thus, skip them.
                   if this.skipExplicitTaskingTaskInExportFunctions(task)
                       continue;
                   end
                   
                   this.writer.wBlockStart('static void %s(%s%s, int tid)', taskName, this.SimStructType, this.SimStructArgSingle);
                   if this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid
                   %
                   % Generate the output/update function call
                   %
                   tid = task.id;
                   taskTiming = task.codeInfoData.Timing;
                   [inportIndices,...
                       inportSizesIndices,...
                       paramIndices,...
                       dsReadIndices,...
                       dsWriteIndices,...
                       sharedLocalDataStoreIndices,...
                       outportIndices,...
                       outportSizesIndices,...
                       loggingIndices,...
                       serverFcnIndex] = generateIndices(this,type,task);

                   if (~isempty(loggingIndices) && multitasking ) || ...
                           this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                       % note: for signal logging/singletasking, "rate time" must be calculated for
                       % each specific rate. With execution
                       % profiling/singletasking the rate time cannot currently be
                       % determined and this may result in a rounding error differences (g837111).
                           [~, sampleTimeIndexCExpr] = this.getRateSampleHitCExpr(task.codeInfoData.Timing);
                       this.writer.wLine(['time_T taskTime = ssGetTaskTime(S, ' sampleTimeIndexCExpr ');']);
                   end
                   
                   this.writeSectionPILIOCommand(type, ...
                       inportIndices,...
                       inportSizesIndices,...
                       paramIndices,...
                       dsReadIndices,...
                       dsWriteIndices,...
                       sharedLocalDataStoreIndices,...
                       outportIndices,...
                       outportSizesIndices,...
                       loggingIndices,...
                       serverFcnIndex,...
                       tid, ...
                       taskTiming);
                   end
                   this.writer.wBlockEnd; % if (' sampleHitCExpr ')
               end
           end
       end
       
       function [inportIndices,...
               inportSizesIndices,...
               paramIndices,...
               dsReadIndices,...
               dsWriteIndices,...
               sharedLocalDataStoreIndices,...
               outportIndices,...
               outportSizesIndices,...
               loggingIndices,...
               serverFcnIndex] = generateIndices(this,type,task)
           switch type
               case 'XIL_UPDATE_COMMAND'
                   tmp_inport = this.codeInfoUtils.getInputPortsForTask(task);
                   inportIndices = this.SILPILWrapperUtils.getNonDFInputPortsIndices(tmp_inport); %inportIndices
                   inportSizesIndices = this.codeInfoUtils.getInportSizesIndices(inportIndices); %inportSizesIndices
                   paramIndices = []; %paramIndices
                   dsReadIndices = []; %dsReadIndices
                   dsWriteIndices = []; %dsWriteIndices
                   sharedLocalDataStoreIndices = []; % Only needed in XIL_INITIALIZE_COMMAND
                   outportIndices = []; %outportIndices
                   outportSizesIndices = []; %outportSizesIndices
                   loggingIndices = []; %loggingIndices
                   serverFcnIndex = []; %serverFcnIndex
               case 'XIL_OUTPUT_COMMAND'
                   tmp_inport = this.codeInfoUtils.getInputPortsForTask(task);
                   
                   if (~this.IsMexTarget)
                       inportIndices = this.SILPILWrapperUtils.getDFInputPortsIndices(tmp_inport);%inportIndices
                   else
                       inportIndices = tmp_inport;
                   end
                   inportSizesIndices = this.codeInfoUtils.getInportSizesIndices(tmp_inport);%inportSizesIndices
                   paramIndices = this.getParamIndicesForFunction(task.codeInfoData);%paramIndices
                   dsReadIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                       this.codeInfoUtils.getReaderSharedDataStoresForTask(task), 'dsread');%dsReadIndices
                   dsWriteIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                       this.codeInfoUtils.getWriterSharedDataStoresForTask(task), 'dswrite'); %dsWriteIndices
                   sharedLocalDataStoreIndices = []; % Only needed in XIL_INITIALIZE_COMMAND
                   outportIndices = this.codeInfoUtils.getOutputPortsForTask(task);%outportIndices
                   outportSizesIndices = this.codeInfoUtils.getOutportSizesIndices(outportIndices); %outportSizesIndices
                   loggingIndices = this.codeInfoUtils.getLoggingForTask(task); %loggingIndices
                   serverFcnIndex= []; %severFcnIndex
               otherwise
                   assert(false, 'Unrecognized type: %s.', type);
           end
       end
       
       function tasks = getTasksSampleTimeIndependent(this,type)
           switch type
               case 'XIL_UPDATE_COMMAND'
                   tasks = this.codeInfoUtils.getUpdateTasks;
               case 'XIL_OUTPUT_COMMAND'
                   tasks = this.codeInfoUtils.getOutputTasks;
               otherwise
                   assert(false, 'Unrecognized type: %s.', type);
                   
           end
       end
       
       function [tasks, taskNames] = getTasksScheduledWithName(this, type)
           xilTaskNameFormat = 'XIL%sTID%02d';
           switch type
               case 'XIL_UPDATE_COMMAND'
                   periodicTasks = this.codeInfoUtils.getUpdateTasksForTimingMode('PERIODIC');
                   aperiodicTasks = this.codeInfoUtils.getUpdateTasksForTimingMode('APERIODIC');
                   tasks = [periodicTasks aperiodicTasks];
                   taskName = 'update';
               case 'XIL_OUTPUT_COMMAND'
                   periodicTasks = this.codeInfoUtils.getOutputTasksForTimingMode('PERIODIC');
                   aperiodicTasks = this.codeInfoUtils.getOutputTasksForTimingMode('APERIODIC');
                   tasks = [periodicTasks aperiodicTasks];
                   taskName = 'output';
               otherwise
                   assert(false, 'Unrecognized type: %s.', type);
           end
           taskNames = cell(numel(tasks),1);
           for idx = 1:numel(tasks)
               taskNames{idx} = sprintf(xilTaskNameFormat,taskName, idx);
           end
       end
       
       function writeSectionUpdateBody(this, ~)
           
           this.writeSectionCommonOutputUpdateBody('XIL_UPDATE_COMMAND',1);
           
       end
       
       function writeSectionOutputsBody(this, taskIdx)
           if ~this.IsMexTarget
               % Return early for Simulink workflows if generating code -
               % must not access XIL wrapper PWorks.
               this.writeSectionReturnIfCodeGen;
           end
           
           % schedule constant outputs if necessary
           if this.codeInfoUtils.hasConstOutput
               this.writer.wComment('set constant outputs');
               this.writer.wBlockStart('if (tid == CONSTANT_TID)');
               this.writeSectionConstOutputCommand;
               this.writer.wBlockEnd; % if (tid == CONSTANT_TID)
           end
           
           this.writeSectionCommonOutputUpdateBody('XIL_OUTPUT_COMMAND',taskIdx);
           
           if this.IsMexTarget
               %Insert return statement if application function has a return
               %argument
               [~, returnArgName, returnArgImpl] = this.getReturnArgData(taskIdx);
               if ~isempty(returnArgImpl)
                   this.writer.wLine('return %s;', returnArgName);
                   this.ReturnArgString = '';
               end
           end
       end
       
       function writeSectionPILIOCommandPostProcessSimData(this, ...
               dataElement, ...
               sfunIdx, ...
               simulinkCType, ...
               taskId) %#ok<INUSD>
           
           if isa(dataElement.getDataInterface, 'rtw.pil.CodeInfoData')
               dataInterfaceType = dataElement.getDataInterface.getDataInterfaceType;
               switch dataInterfaceType
                   case 'outputsize'
                       % set current dimensions
                       [~, tmpAddress] = this.getTmpIOVariable(dataElement);
                       dimensions = dataElement.getDimensions;
                       assert(isscalar(dimensions), 'outputsize dimensions must be scalar!');
                       switch dataElement.getDtypeId
                           case rtw.connectivity.CodeInfoTypeEnum.TypeInt8
                               type = 'VARSIZE_TYPE_8BIT';
                           case rtw.connectivity.CodeInfoTypeEnum.TypeInt16
                               type = 'VARSIZE_TYPE_16BIT';
                           case rtw.connectivity.CodeInfoTypeEnum.TypeInt32
                               type = 'VARSIZE_TYPE_32BIT';
                           otherwise
                               assert(false, 'Expected 8/16/32-bit int for variable size data!');
                       end
                       this.writer.wLine('xilGetSetCurrentPortDims(S, %s, %s, %d, %d, (void *) %s, %s);', ...
                           'VARSIZE_SET_OUTPUT', ...
                           sfunIdx, ...
                           dataElement.getVarDimIndex, ...
                           dimensions, ...
                           tmpAddress, ...
                           type);
                   otherwise
                       % do nothing
               end
           end
       end
       
       % define how command data is initialized in the s-function
       function writeSectionPILIOCommandGetSimDataPtr(this, ...
               dataElement, ...
               sfunIdx, ...
               simulinkCType, ...
               taskId)
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
           simDataCType = memUnitInfo.ioDataType;
           dataInterface = dataElement.getDataInterface();
           if isa(dataInterface, 'rtw.pil.CommandData')
               dataInterfaceName = dataInterface.getName();
               switch dataInterfaceName
                   case 'FCNID'
                       this.writer.writeLine([simulinkCType ' commandDataFcnid = 0;']);
                       this.writer.writeLine(['simDataMemUnitPtr = (' simDataCType ' *) &commandDataFcnid;']);
                   case 'FCNID_AND_TID'
                       assert(~isempty(taskId), 'writeSectionPILIOCommandGetSimDataPtr: empty taskId');
                       if this.IsMexTarget
                           this.writer.wLine([simulinkCType ' commandDataFcnidTID[2] = {0, 0};']);
                           this.writer.wLine('commandDataFcnidTID[1] = taskID;');
                       else
                           this.writer.writeLine([simulinkCType ' commandDataFcnidTID[2] = {0, ' int2str(taskId) '};']);
                       end
                       this.writer.writeLine(['simDataMemUnitPtr = (' simDataCType ' *) &commandDataFcnidTID[0];']);
                   case {'SERVER_FUNCTION_ID' ...
                           'COMMAND_COMPLETE' ...
                           'PRINTF_ERROR' ...
                           'PRINTF_SIZE' ...
                           'FOPEN_FID' ...
                           'FOPEN_NAME_SIZE' ...
                           'FPRINTF_ERROR' ...
                           'FPRINTF_FID' ...
                           'FPRINTF_SIZE'}
                       this.writer.writeLine(['simDataMemUnitPtr = (' simDataCType ' *) &' dataInterfaceName ';']);
                   otherwise
                       assert(false, 'Unexpected command data name: %s', dataInterfaceName);
               end
           elseif isa(dataInterface, 'rtw.pil.TaskCounterOffsetData')
               this.writer.wLine('int_T tidIdx = %d;', dataInterface.TID);
               this.writer.wLine('uint32_T taskCounterOffset = computeTaskTickOffset(S, tidIdx);');
               if this.isVerbose()
                   this.writer.wLine('mexPrintf("Sample Time Offset for TID(%d) is %d\n", tidIdx, taskCounterOffset);')
               end
               this.writer.writeLine(['simDataMemUnitPtr = (' simDataCType ' *) &taskCounterOffset;']);
           elseif isa(dataInterface, 'rtw.pil.CodeInfoData')
               dataInterfaceType = dataInterface.getDataInterfaceType();
               switch dataInterfaceType
                   case 'parameter'
                       simDataCType = memUnitInfo.ioDataType;
                       this.writer.writeLine('simDataMemUnitPtr = (%s *) dataInterfacePtr;', simDataCType);
                   case {'inputsize', 'outputsize'}
                       simDataCType = rtw.connectivity.TypeUtils.builtinToHostCType(memUnitInfo.memUnitType);
                       switch dataElement.getDtypeId
                           case rtw.connectivity.CodeInfoTypeEnum.TypeInt8
                               type = 'VARSIZE_TYPE_8BIT';
                           case rtw.connectivity.CodeInfoTypeEnum.TypeInt16
                               type = 'VARSIZE_TYPE_16BIT';
                           case rtw.connectivity.CodeInfoTypeEnum.TypeInt32
                               type = 'VARSIZE_TYPE_32BIT';
                           otherwise
                               assert(false, 'Expected 8/16/32-bit int for variable size data!');
                       end
                       [tmpDefinition, tmpAddress] = this.getTmpIOVariable(dataElement);
                       this.writer.writeLine(tmpDefinition);
                       if strcmp(dataInterfaceType, 'inputsize')
                           % read current dims
                           direction = 'VARSIZE_GET_INPUT';
                       else
                           % seed with current dimensions in case we're
                           % sending to the target
                           direction = 'VARSIZE_GET_OUTPUT';
                       end
                       dimensions = dataElement.getDimensions;
                       assert(isscalar(dimensions), 'inputsize/outputsize dimensions must be scalar!');
                       this.writer.wLine('xilGetSetCurrentPortDims(S, %s, %s, %d, %d, (void *) %s, %s);', ...
                           direction, ...
                           sfunIdx, ...
                           dataElement.getVarDimIndex, ...
                           dimensions, ...
                           tmpAddress, ...
                           type);
                       this.writer.writeLine(['simDataMemUnitPtr = (' simDataCType ' *) ' tmpAddress ';']);
                   otherwise
                       this.writer.wComment(sprintf('DataInterface: %s, %u', ...
                           dataInterfaceType, ...
                           dataInterface.getDataInterfaceIdx));
                       this.writer.wLine('simDataMemUnitPtr = ( %s *) dataInterfacePtr;', simDataCType);
               end
           else
               assert(false, 'Unexpected dataElement class: %s', class(dataElement));
           end
       end
           
       % define which command data is associated with which command
       % override in a subclass to support extra commands / extra command
       % data
       function commandDataToProcess = getPILIOCommandDataToProcess(this, PILCommand) %#ok<INUSL>
          switch PILCommand
              case {'XIL_INIT_COMMAND' ...
                    'XIL_PROCESS_PARAMS_COMMAND' ...
                    'XIL_INITIALIZE_COMMAND' ...
                    'XIL_CONST_OUTPUT_COMMAND' ...
                    'XIL_TERMINATE_COMMAND' ...
                    'XIL_SYSTEM_RESET_COMMAND' ...
                    'XIL_PAUSE_COMMAND'}
                  commandDataToProcess = {'FCNID'};
              case {'XIL_ENABLE_COMMAND' ...
                    'XIL_DISABLE_COMMAND' ...
                    'XIL_CLIENT_SERVER_COMMAND' ...
                    'XIL_UPDATE_COMMAND' ...
                    'XIL_OUTPUT_COMMAND'}
                  % send TID too
                  commandDataToProcess = {'FCNID_AND_TID'};
              case {'XIL_SHUTDOWN_COMMAND'}
                  commandDataToProcess = [];
              otherwise
                  assert(false, 'Unexpected In-the-Loop command: %s', PILCommand);
          end           
       end                                 
            
       % shared code for input and output bus handling
       function writeSectionProcessDataElementHeader(this, ...
                                                     dataElement, ...
                                                     simulinkCType, ...
                                                     taskId)
           this.writer.wBlockStart('');
           
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
           simDataCType = memUnitInfo.ioDataType;
           this.writer.writeLine([simDataCType ' * simDataMemUnitPtr;']);
           
           simDataCharPtrOffset = '';           
           if dataElement.isStructElement
               if(~this.IsMexTarget)
                   [ElementOffset, ~, ~] = dataElement.getFinalStructElementOffset;
                   if(dataElement.NumPrevSameAncestorElements)
                       this.writer.writeLine('uint32_T offsetIdx;');
                       this.writer.wBlockStart('for( offsetIdx=%d; offsetIdx< %d; offsetIdx++)', ...
                           ElementOffset, ...
                           ElementOffset+dataElement.NumPrevSameAncestorElements+1);
                   else
                       this.writer.writeLine('uint32_T offsetIdx = %d;', ElementOffset);
                   end
               end
               
               if isa(dataElement.getDataInterface, 'rtw.pil.CodeInfoData')
                   dataInterfaceType = dataElement.getDataInterface.getDataInterfaceType;
                   if strcmp(dataInterfaceType, 'inputsize') || strcmp(dataInterfaceType, 'outputsize')
                       isInputOutputSize = true;
                   else
                       isInputOutputSize = false;
                   end
                   assert(strcmp(dataInterfaceType, 'input') || ...
                          strcmp(dataInterfaceType, 'output') || ...
                          isInputOutputSize || ...
                          strcmp(dataInterfaceType, 'parameter') || ...
                          strcmp(dataInterfaceType, 'serverFcnInputArg') || ...
                          strcmp(dataInterfaceType, 'serverFcnOutputArg') || ...
                          strcmp(dataInterfaceType, 'serverFcnInputOutputArg') || ...
                          strcmp(dataInterfaceType, 'callerFcnInputArg') || ...
                          strcmp(dataInterfaceType, 'callerFcnOutputArg') || ...
                          strcmp(dataInterfaceType, 'callerFcnInputOutputArg') || ...
                          strcmp(dataInterfaceType, 'queuedFcnInputArg') || ...
                          strcmp(dataInterfaceType, 'queuedFcnOutputArg') || ...
                          strcmp(dataInterfaceType, 'dsread') || ...
                          strcmp(dataInterfaceType, 'dswrite') || ...
                          strcmp(dataInterfaceType, 'sharedLocalDataStore') || ...
                          strcmp(dataInterfaceType, 'siglog') || ...
                          strcmp(dataInterfaceType, 'statelog'), ...
                          'Unexpected dataInterfaceType for bus: %s', dataInterfaceType);
               else
                   isInputOutputSize = false;
               end
               % offsetting is not necessary for input/output size data
               if ~isInputOutputSize
                   if ~this.IsMexTarget
                       % access the API that will give us Bus size and offset information
                       this.writer.writeLine('slDataTypeAccess * dta = ssGetDataTypeAccess(S);');
                       this.writer.writeLine('const char * bpath = ssGetPath(S);');
                   end
                   dataElement.writeStructArrayHeader(this.writer);
                   if this.IsMexTarget
                       %For MATLAB Coder the Host side function is
                       %target-like and should use pure pointer arithmetic
                       %and no SS functions.
                       isHost = false;
                   else
                       isHost = true;
                   end
                   simDataCharPtrOffset = dataElement.getStructArrayOffset(isHost);
               end
           end
           simDataCharPtrOffset = [simDataCharPtrOffset dataElement.getCharOffsetInArrayImplementation()];
           
           % body
           sfunIdx = this.getSfunIdxForDataInterface(dataElement.getDataInterface);
           this.writeSectionPILIOCommandGetSimDataPtr(dataElement, ...
               sfunIdx, ...
               simulinkCType, ...
               taskId);
           
           if ~isempty(simDataCharPtrOffset)  
               % - simDataCharPtrOffset is a BYTE offset
               % - simDataMemUnitPtr is a MEMUNIT ptr
               %
               % In order to apply pointer arithmetic correctly, we
               % must cast to char to do the addition, then finally 
               % cast back to the memunit type.
               this.writer.writeLine(['simDataMemUnitPtr = (' simDataCType '*) (((char *) simDataMemUnitPtr)' simDataCharPtrOffset ');']);
           end                      
       end
       
       % shared code for input and output bus handling
       function writeSectionProcessDataElementTrailer(this, ...
               dataElement)
                                                             
           if dataElement.isStructElement
               if isa(dataElement.getDataInterface, 'rtw.pil.CodeInfoData'), ... 
                       dataInterfaceType = dataElement.getDataInterface.getDataInterfaceType;
                   if strcmp(dataInterfaceType, 'inputsize') || strcmp(dataInterfaceType, 'outputsize')
                       isInputOutputSize = true;
                   else
                       isInputOutputSize = false;
                   end
               else
                   isInputOutputSize = false;
               end
               % offsetting is not necessary for input/output size data
               if ~isInputOutputSize   
                   dataElement.writeStructArrayTrailer(this.writer);
               end
           end
           this.writer.wBlockEnd;
           
           if(~this.IsMexTarget && ...
                   dataElement.isStructElement &&...
                   dataElement.NumPrevSameAncestorElements)
                   this.writer.wBlockEnd;
           end
       end
       
       function writeSectionRecvFcn(this)
           this.writer.wComment('receive one packet of data and dispatch to owning application');
           this.writer.wBlockStart('static boolean_T recvData(%s%svoid* pComms)',...
               this.SimStructType, this.SimStructArg);
           
           this.writer.newLine;           
           this.getPWorkValue('int', 'pCommErrorOccurred', this.getCommErrorOccurredIdx, true);
           this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
           
           % need to access pCommErrorOccurred PWork
           this.writer.newLine;
           this.writer.wBlockStart('if (pCommErrorOccurred == NULL)');
           this.writeErrorCall('pCommErrorOccurred is NULL.');
           this.writer.writeLine('return XILHOSTAPPSVC_ERROR;');
           this.writer.wBlockEnd;
                      
           
           % need to access pXILUtils PWork
           this.writer.newLine;
           this.writer.wBlockStart('if (%s == NULL)', this.XILUtilsVarName);
           this.writeErrorCall([this.XILUtilsVarName ' is NULL.']);
           this.writer.writeLine('return XILHOSTAPPSVC_ERROR;');
           this.writer.wBlockEnd;
           
           % recv one packet of data and dispatch to owning application
           this.writer.newLine;
           this.writer.wLine('*pCommErrorOccurred = (xilCommsRun(pComms, %s) != XILCOMMS_RTIOSTREAM_SUCCESS);',...
               this.XILUtilsVarName);
           this.writer.writeLine('return (*pCommErrorOccurred?XILHOSTAPPSVC_ERROR:XILHOSTAPPSVC_SUCCESS);');
           
           this.writer.newLine;           
           this.writer.wBlockEnd; % static boolean_T recvData
       end
                     
       function writeSectionSendFcn(this)
           this.writer.wComment('send data via xil comms');
           this.writer.wBlockStart('static boolean_T sendData(%s%svoid* pXILService, XIL_IOBuffer_T* IOBuffer, mwSize sendSize)', ...
               this.SimStructType, this.SimStructArg);
           this.writer.newLine;           
           this.getPWorkValue('int', 'pCommErrorOccurred', this.getCommErrorOccurredIdx, true);
           
           % need to access pCommErrorOccurred PWork
           this.writer.newLine;
           this.writer.wBlockStart('if (pCommErrorOccurred == NULL)');
           this.writeErrorCall('pCommErrorOccurred is NULL.');
           this.writer.writeLine('return XILHOSTAPPSVC_ERROR;');
           this.writer.wBlockEnd();
           
           % send
           this.writer.newLine;
           this.writer.wLine(['*pCommErrorOccurred = (xilHostAppSvcSend('...
               'pXILService, IOBuffer->data, sendSize) != XILHOSTAPPSVC_SUCCESS);']);
           this.writer.writeLine('return (*pCommErrorOccurred?XILHOSTAPPSVC_ERROR:XILHOSTAPPSVC_SUCCESS);');
           
           this.writer.newLine;           
           this.writer.wBlockEnd; % static boolean_T sendData
       end
              
       % the target IO file descriptor buffer grow function
       function writeSectionGrowTargetIOFdFcn(this)
           
           this.writer.writeLine('/* grow the buffer for target I/O Fd array');
           this.writer.writeLine(' * targetIOFd->Fd is NULL on failure */');
           this.writer.wBlockStart('static void growTargetIOFd(%s%stargetIOFd_T * IOFd, mwSize requiredSize)', ...
               this.SimStructType, this.SimStructArg);
           
           % never shrink the buffer!
           this.writer.wBlockStart('if (IOFd->size < requiredSize)');
           this.writer.writeLine('IOFd->Fd = (FILE**)mxRealloc(IOFd->Fd, requiredSize * sizeof(FILE*));');
           if this.isVerbose()
              this.writer.writeLine('mexPrintf("Reallocating IOFd: new size %lu\n", requiredSize);');
           end
           this.writer.wBlockStart('if (IOFd->Fd == NULL)');

           % error out if mxRealloc fails
           this.writeErrorCall('growTargetIOFd: mxRealloc failed.');
           this.writer.wBlockMiddle('else'); % if (IOFd->Fd == NULL)
           % mark memory of Fd to persist
           this.writer.writeLine('mexMakeMemoryPersistent(IOFd->Fd);');
           this.writer.writeLine('IOFd->size = requiredSize;');
                                
           this.writer.wBlockEnd; % if (IOFd->Fd == NULL)
           
           this.writer.wBlockEnd; % if (IOFd->size < requiredSize)
           
           this.writer.wBlockEnd; % static void growTargetIOFd
       end
       
       function writeSectionCloseAndFreeTargetIOFdFcn(this)
          this.writer.wBlockStart('static void closeAndFreeTargetIOFd(%s%s)', ...
              this.SimStructType, this.SimStructArgSingle);          
          this.writer.writeLine('int i;');
          if ~this.IsMexTarget
              this.writer.wBlockStart('if(ssGetPWork(S) != NULL)');
          end
          this.getPWorkValue('targetIOFd_T', 'targetIOFdPtr', this.getTargetIOFdArrPWorkIdx, true);
          this.writer.wBlockStart('if(targetIOFdPtr != NULL)');
          this.writer.wBlockStart('if (targetIOFdPtr->Fd != NULL)');
          this.writer.wBlockStart('for(i=0; i<targetIOFdPtr->size; i++)');
          this.writer.wBlockStart('if (targetIOFdPtr->Fd[i] != NULL)');
          this.writer.writeLine('fclose(targetIOFdPtr->Fd[i]);');
          this.writer.wBlockEnd; % if (targetIOFdPtr->Fd[i] != NULL)
          this.writer.wBlockEnd; % for loop          
          this.writer.writeLine('mxFree(targetIOFdPtr->Fd);');                    
          this.writer.wBlockEnd; % if targetIOFdPtr->Fd != NULL
          
          this.writer.writeLine('mxFree(targetIOFdPtr);');
          this.writer.wBlockEnd; % if targetIOFdPtr != NULL

          % set PWork to NULL
          this.setFreedPWorkValueToNull('targetIOFdPtr', this.getTargetIOFdArrPWorkIdx);
          
          if ~this.IsMexTarget
              this.writer.wBlockEnd; % if ssGetPWork(S) != NULL
          end
          this.writer.wBlockEnd;
       end
          
       function writeSectionProcessParamsFcn(this)
           this.writer.wComment('Process params function shared between mdlStart and mdlProcessParams');
           this.writer.wBlockStart('static void processParams(SimStruct * S)');
           
           if ~this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid
               % If component boundary validation failed, close the block
               % leaving a stub, and return early.
               this.writer.wBlockEnd();
               return;
           end
           
           this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');           
           this.getPWorkValue('int', 'pIsXILApplicationStarted', this.getIsXILApplicationStartedIdx, true);
           this.writer.wBlockStart('if ((pIsXILApplicationStarted!=NULL) && (*pIsXILApplicationStarted==1))');
 
           this.writer.wComment('update run time params');
           this.writer.writeLine('ssUpdateAllTunableParamsAsRunTimeParams(S);');          
           
           inportIndices = [];
           paramIndices = this.TransferInterfaceUtils.getParametersToTransfer(this.SILPILWrapperUtils);
           outportIndices = [];
           dsReadIndices = [];
           dsWriteIndices = [];
           sharedLocalDataStoreIndices = [];
           loggingIndices = [];
           inportSizesIndices = [];
           outportSizesIndices = [];
           serverFcnIndex = [];
           % process params
           %
           % tid not used
           tid = [];
           taskTiming = [];
           this.writeSectionPILIOCommand('XIL_PROCESS_PARAMS_COMMAND', ...
               inportIndices, ...
               inportSizesIndices, ...
               paramIndices, ...
               dsReadIndices, ...
               dsWriteIndices, ...
               sharedLocalDataStoreIndices, ...
               outportIndices, ...
               outportSizesIndices, ...
               loggingIndices, ...
               serverFcnIndex, ...
               tid, ...
               taskTiming);

           this.writer.wBlockEnd; % if ((pIsXILApplicationStarted!=NULL) && (*pIsXILApplicationStarted==1))
           this.writer.wBlockEnd; % if (ssGetPWork(S) != NULL)
           this.writer.wBlockEnd; % static void processParams
       end
       
       
       function writeSectionSSTypeIDToMemUnitTypeID(this)
           
           this.writer.wComment('Convert Simulink Type ID to Mem Unit Type ID');
           this.writer.wBlockStart('static mem_unit_type_T simulinkToMemUnitType(SimStruct * S, DTypeId simulinkTypeID)');
           returnVar = 'memUnitType';
           this.writer.wLine('mem_unit_type_T %s = MEM_UNIT_INVALID_TYPE;', returnVar);
           this.writer.wBlockStart('switch (simulinkTypeID)');
           
           this.writer.wBlockStart('case SS_DOUBLE:');
           this.writer.wLine('%s = MEM_UNIT_DOUBLE_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_DOUBLE
           this.writer.wBlockStart('case SS_SINGLE:');
           this.writer.wLine('%s = MEM_UNIT_SINGLE_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_SINGLE
           
           this.writer.wBlockStart('case SS_INT8:');
           this.writer.wLine('%s = MEM_UNIT_INT8_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_INT8
           this.writer.wBlockStart('case SS_UINT8:');
           this.writer.wLine('%s = MEM_UNIT_UINT8_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_UINT8
           
           this.writer.wBlockStart('case SS_INT16:');
           this.writer.wLine('%s = MEM_UNIT_INT16_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_INT16
           this.writer.wBlockStart('case SS_UINT16:');
           this.writer.wLine('%s = MEM_UNIT_UINT16_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_UINT16
           
           this.writer.wBlockStart('case SS_INT32:');
           this.writer.wLine('%s = MEM_UNIT_INT32_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_INT32
           this.writer.wBlockStart('case SS_UINT32:');
           this.writer.wLine('%s = MEM_UNIT_UINT32_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_UINT32
           
           this.writer.wBlockStart('case SS_BOOLEAN:');
           this.writer.wLine('%s = MEM_UNIT_BOOLEAN_TYPE;', returnVar);
           this.writer.wLine('break;');
           this.writer.wBlockEnd; % case SS_BOOLEAN
           
           this.writer.wBlockStart('default:');

           this.writer.wBlockStart('if (ssGetDataTypeIsSpecifiedInteger(S,simulinkTypeID,0,64))'); 
           this.writer.wLine('memUnitType = MEM_UNIT_UINT64_TYPE;');
           this.writer.wLine('break;');
           this.writer.wBlockEnd(); % if UINT64
           
           this.writer.wBlockStart('else if (ssGetDataTypeIsSpecifiedInteger(S,simulinkTypeID,1,64))');
           this.writer.wLine('memUnitType = MEM_UNIT_INT64_TYPE;');
           this.writer.wLine('break;');
           this.writer.wBlockEnd(); % else if INT64


           this.writer.wBlockStart('else if (ssGetDataTypeIsHalfPrecision(S,simulinkTypeID))');
           this.writer.wLine('memUnitType = MEM_UNIT_UINT16_TYPE;');
           this.writer.wLine('break;');
           this.writer.wBlockEnd(); % else if half

           this.writer.wBlockStart('else if (ssGetDataTypeIsFixedPoint(S,simulinkTypeID) && (ssGetDataTypeFxpContainWordLen(S,simulinkTypeID) == 64))');
           this.writer.wLine('memUnitType = (ssGetDataTypeFxpIsSigned(S,simulinkTypeID)? MEM_UNIT_INT64_TYPE:MEM_UNIT_UINT64_TYPE);');
           this.writer.wLine('break;');
           this.writer.wBlockEnd(); % else if fixed-point 64
           
           this.writer.wBlockStart('else');
           % throw error
           errorReturn = sprintf('return %s;', returnVar);
           this.writeError(errorReturn, ...
               'PIL:pilverification:UnknownDataType', ...
               'mxCreateDoubleScalar(simulinkTypeID)');
           
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % else
           this.writer.wBlockEnd; % default end
           this.writer.wBlockEnd; % switch (simulinkTypeID)
           
           this.writer.wLine('return %s;', returnVar);
           this.writer.wBlockEnd; % static mem_unit_Type_T simulinkToMemUnitType(SimStruct * S, DTypeId simulinkTypeID)
       end
       
        
       function writeSectionCommandDispatchFcn(this)
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
           
           isVerbose = this.isVerbose();
           this.writer.wComment('implements command dispatch');
           
           this.writer.wBlockStart('static boolean_T commandDispatch(%s%sXIL_IOBuffer_T* IOBuffer, mwSize dataOutSize)', ...
               this.SimStructType, this.SimStructArg);
           
           % get pXILService
           this.getPWorkValue('void', 'pXILService', this.getXILServicePWorkIdx, true);                      
           this.writer.wBlockStart('if (pXILService == NULL)');
           this.writeErrorCall('pXILService is NULL!');
           this.writer.wLine('return XILHOSTAPPSVC_ERROR;');
           this.writer.wBlockEnd(); % (pXILService == NULL)
           
           % send
           if isVerbose
               this.writer.writeLine(['mexPrintf("commandDispatch: tx --> %u * ' memUnitInfo.ioDataType '\n", dataOutSize);']);
           end
           this.writer.wLine('');
           this.writer.wComment('send the data');
           this.writer.wBlockStart('if (sendData(%spXILService, IOBuffer, dataOutSize) != XILHOSTAPPSVC_SUCCESS)',...
               this.SimStructArg);
           this.writeSectionProcessException;
           this.writer.writeLine('return XILHOSTAPPSVC_ERROR;');
           this.writer.wBlockEnd; % if (sendData)
           this.writer.writeLine('return XILHOSTAPPSVC_SUCCESS;');
           this.writer.wBlockEnd; % static boolean_T commandDispatch
       end
       
       function writeSectionCommandResponseFcn(this)                     
           commandComplete = this.SILPILWrapperUtils.getCommandData('COMMAND_COMPLETE');
           commandCompleteName = commandComplete.getName;
           this.writer.wComment('implements command response');
               this.writer.wBlockStart('static boolean_T commandResponse(%s%sXIL_IOBuffer_T* IOBuffer, XILCommandResponseType* commandType)', ...
                   this.SimStructType, this.SimStructArg);
           % get pXILService           
           this.getPWorkValue('void', 'pXILService', this.getXILServicePWorkIdx, true);                      
           this.writer.wBlockStart('if (pXILService == NULL)');
           this.writeErrorCall('pXILService is NULL!');
           this.writer.wLine('return XILHOSTAPPSVC_ERROR;');
           this.writer.wBlockEnd(); % (pXILService == NULL)           
           
           this.writer.wBlockStart('');
                      
           this.writer.wComment('receive the response data');
           % Geck g1051917 captures unifying these 2 branches and checking 
           % whether client/server will work with comm server API.
           if this.IsUsingCommServiceAPI
               this.writer.wBlockStart('if (xilHostAppSvcWaitForDataFromTarget(pXILService)!=XILHOSTAPPSVC_SUCCESS)');               
               this.writeSectionProcessException;
               this.writer.writeLine('return XILHOSTAPPSVC_ERROR;');
               this.writer.wBlockEnd; % if (xilHostAppSvcWaitForDataFromTarget)  
                        
               % Geck g1051917 captures making client/server work with comm server API.
               this.writer.writeLine('*commandType = XIL_STEP_COMPLETE;');               
           else
               % define commandComplete
               this.writer.writeLine(['uint8_T ' commandCompleteName ' = 0;']);
               
               % get pComms
               this.getPWorkValue('void', 'pComms', this.getCommsPWorkIdx, true);
               this.writer.wBlockStart('if (pComms == NULL)');
               this.writeErrorCall('pComms is NULL!');
               this.writer.wLine('return XILHOSTAPPSVC_ERROR;');
               this.writer.wBlockEnd(); % (pComms == NULL)
           
               this.writer.wBlockStart(['while (!' commandCompleteName ')']);               
               this.writer.wLine('xilHostAppSvcSetIsResponseComplete(pXILService,  0);');
               this.writer.wBlockStart('if (recvData(%spComms) != XILHOSTAPPSVC_SUCCESS)',...
                   this.SimStructArg);
               this.writeSectionProcessException;
               this.writer.writeLine('return XILHOSTAPPSVC_ERROR;');
               this.writer.wBlockEnd; % if (recvData)
               this.writer.wLine(sprintf('%s = xilHostAppSvcGetIsResponseComplete(pXILService);', commandCompleteName));
               this.writer.wBlockEnd; % while
               
               this.writer.wComment('determine command response type');
               this.writer.writeLine('*commandType = (XILCommandResponseType) %s;', commandCompleteName)
           end
               this.writer.writeLine('IOBuffer->nextMemUnit = (void*)IOBuffer->data;');
               
               % set received data size, and set data available flag
               % Geck g1051917 captures renaming this API to xilHostAppSvcGetPayloadSize           
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
           this.writer.writeLine('IOBuffer->bufferDataSize = xilHostAppSvcGetPayloadSizeForOneStep(pXILService)*%d;', memUnitInfo.memUnitBytes);
               this.writer.writeLine('IOBuffer->readData = ((IOBuffer->bufferDataSize>0)?true:false);');
           this.writer.writeLine('return XILHOSTAPPSVC_SUCCESS;');
           
           
           this.writer.wBlockEnd;
           
           
           this.writer.wBlockEnd; % static boolean_T commandResponse
       end
       
       function writeSectionCodeInstrServiceDataFcn(this)
           memUnitSizeBytesName = 'memUnitSizeBytes';
           
           this.writer.wComment('returns data needed by code instrumentation service');
           this.writer.wBlockStart('static %s* codeInstrServiceData(%s%suint8_T %s)',...              
               this.LocalCodeInstrServiceDataType,...
               this.SimStructType, this.SimStructArg, ...
               memUnitSizeBytesName);

           this.writer.wLine('%s* pCodeInstrServiceData = (%s*) mxCalloc(1, sizeof(%s));',...
                             this.LocalCodeInstrServiceDataType,...
                             this.LocalCodeInstrServiceDataType,...
                             this.LocalCodeInstrServiceDataType);

           errorReturn = 'return NULL;';
           this.writeSimulinkBlockPath(errorReturn);      
           
           this.writer.newLine;
           this.writer.wBlockStart('if (pCodeInstrServiceData == NULL)');
           this.writeErrorCall('Error in allocating memory for code instrumentation data through mxCalloc.');
           this.writer.writeLine('return NULL;');
           this.writer.wBlockEnd; % (pCodeInstrServiceData == NULL)
           
           % get the stored info path for instrumentation
           if ~this.IsMexTarget
               this.getPWorkValue('char', 'pXilAppDir', this.getXilAppDirIdx(), true)
           end
           
           this.writer.wBlockStart('if (pXilAppDir == NULL)');
           this.writeErrorCall('pXilAppDir is NULL.');
           this.writer.writeLine('return NULL;');
           this.writer.wBlockEnd(); %'if (pXilAppDir == NULL)'
           
           % set the info path for instrumentation to the value stored
           % during initialization
           this.writer.writeLine('pCodeInstrServiceData->infoPath = %s;',...
                   'pXilAppDir');
           
           this.writer.writeLine('pCodeInstrServiceData->blockPath = %s;',...
                                 'simulinkBlockPath');
           
           this.writer.writeLine('pCodeInstrServiceData->rootModel = %s;',...
                                 this.getSimulinkModelPath);
           
           this.writer.writeLine('pCodeInstrServiceData->memUnitSize = %s;',...
                                 memUnitSizeBytesName);
           
           isTimeProfilingEnabledText = 'false';
           isStackProfilingEnabledText = 'false';
           if this.SILPILWrapperUtils.isProfilingEnabled
               if this.SILPILWrapperUtils.StackProfilingEnabled
                   isTimeProfilingEnabledText = 'false';
                   isStackProfilingEnabledText = 'true';
               else
                   isTimeProfilingEnabledText = 'true';
               end
           end
           this.writer.writeLine('pCodeInstrServiceData->isTimeProfilingEnabled = %s;',...
                                 isTimeProfilingEnabledText);
           this.writer.writeLine('pCodeInstrServiceData->isStackProfilingEnabled = %s;',...
                                 isStackProfilingEnabledText);
                             
           
           silPILInterface = this.SILPILWrapperUtils.getSILPILInterface;
           this.writer.writeLine('pCodeInstrServiceData->inTheLoopType = %d;',...
                                 int32(silPILInterface.getInTheLoopType));
           
           clientInterface = silPILInterface.getClientInterface;
           silPILInterfaceFcnStr = clientInterface.getSILPILInterfaceFcnStr;
           this.writer.writeLine('pCodeInstrServiceData->silPilInterfaceFcn = "%s";',...
                                 silPILInterfaceFcnStr);
           
           this.writer.newLine;

           this.writer.writeLine('return pCodeInstrServiceData;');
           this.writer.wBlockEnd;
       end

       

       function writeSectionCodeInstrServiceSetTime(this, PILCommand)
           narginchk(2, 2);
           
           this.writer.newLine;
           this.writer.wComment('provide the time information to the code instrumentation service');
           this.writer.wBlockStart('');           
                      
           if this.IsMexTarget
               if strcmp(PILCommand, 'XIL_OUTPUT_COMMAND')
                   timeVarName = 'simTime++';
               elseif strcmp(PILCommand, 'XIL_TERMINATE_COMMAND')
                   %If this is the Terminate command, need to step time
                   %back one. Note: simTime will always be at least 1 when
                   %terminate can be called.
                   timeVarName = '--simTime';
               else                   
                   timeVarName = 'simTime';
               end
           else
               this.getPWorkValue('void', 'pCodeInstrService', this.getCodeInstrServicePWorkIdx, true);
               if strcmp(PILCommand, 'XIL_OUTPUT_COMMAND')
                   % task time has already been evaluated
                   timeVarName = 'taskTime';
               else
                   % we are not in mdlOutputs; use ssGetT to get the simulation time
                   timeVarName = 'simTime';
                   this.writer.wLine('time_T %s = ssGetT(S);', timeVarName);
               end
           end
           
           % provide the time information to the code instrumentation
           % service
           this.writer.wBlockStart('if (pCodeInstrService != NULL)');
           this.writer.wLine('codeInstrHostAppSvcSetTime(pCodeInstrService, %s);', timeVarName);
           this.writer.wBlockEnd;
           this.writer.wBlockEnd;
           this.writer.newLine;
       end
       
       function writeSectionPILIOCommand(this, ...
                                         PILCommand, ...
                                         inportIndices, ...
                                         inportSizesIndices, ...
                                         paramIndices, ...
                                         dsReadIndices, ...
                                         dsWriteIndices, ...
                                         sharedLocalDataStoreIndices, ...
                                         outportIndices, ...
                                         outportSizesIndices, ...
                                         loggingIndices, ...
                                         serverFcnIndex,...
                                         taskId, ...
                                         taskTiming, ...
                                         errorReturn)   
                                     
           narginchk(14, 15);
           if nargin < 15
               errorReturn = sprintf('return%s;', this.ReturnArgString);
           end
           
           if strcmp(PILCommand,'XIL_OUTPUT_COMMAND') && this.IsMexTarget
               this.writer.wBlockStart('void xilPreEntryPointHost(uint32_T taskID)');
           else
               this.writer.wBlockStart(''); % code block
           end
           allOutportSizesData = this.writeSectionXILPreEntryPointHost( ...
               PILCommand, ...
               inportIndices, ...
               inportSizesIndices, ...
               paramIndices, ...
               dsReadIndices, ...
               outportSizesIndices, ...
               serverFcnIndex,...
               taskId, ...
               taskTiming, ...
               errorReturn);
           

           this.writer.wBlockEnd(); %xilPreEntryPointHost(taskID) || code block

           if strcmp(PILCommand,'XIL_OUTPUT_COMMAND') && this.IsMexTarget
               this.writer.wBlockStart('void xilEntryPointHost(uint32_T taskID)');
           else
               this.writer.wBlockStart(''); % code block
           end
           
           this.writeSectionXILEntryPointHost(...
               PILCommand, ...
               outportIndices, ...
               outportSizesIndices, ...
               dsWriteIndices, ...
               sharedLocalDataStoreIndices, ...
               loggingIndices, ...
               serverFcnIndex,...
               taskId, ...
               allOutportSizesData, ...
               errorReturn);
           
           this.writer.wBlockEnd(); % xilEntryPointHost(taskID) || code block
           
           
           if strcmp(PILCommand,'XIL_OUTPUT_COMMAND')
               if this.IsMexTarget
                   this.writer.wBlockStart('void xilPostEntryPointHost(uint32_T taskID)');
               else
                   this.writer.wBlockStart(''); % code block
               end
                   
               this.writeSectionXILPostEntryPointHost(...
                   PILCommand, ...
                   errorReturn);

               if this.IsMexTarget
                   this.writer.wLine('callPrintfHook(%s);',...
                       this.SimStructArgSingle);
               end

               this.writer.wBlockEnd(); % xilPostEntryPointHost(taskID) || code block

           end
       end              
                
       function writeSectionProcessException(this)
           if ~this.NeedToProcessExceptions
               % we should only process exceptions if 
               % NeedToProcessExceptions is true (a.k.a this.IsMexTarget)
               return
           end  
           this.writer.wLine('xilThrowException(%s);', this.XILUtilsVarName);                      
       end              
           
       function writeSectionProcessExceptionFcn(this)
           % This is MATLAB Coder only as this function is only called
           % when this.IsMexTarget is true
           
           this.writer.wBlockStart('static void xilThrowException(void* %s)', ...
               this.XILUtilsVarName);
           
           errorReturn = sprintf('return%s;', this.ReturnArgString);
           
           this.writer.wBlockStart('if (%s == NULL)', this.XILUtilsVarName);
           this.writer.wLine('mexPrintf("%s is NULL!");', this.XILUtilsVarName);
           this.writer.wLine('%s', errorReturn);
           this.writer.wBlockEnd; %if (pXILUtils)
           
           this.writer.wLine('pKeepUtilsActive = 1;');
           this.writer.wLine('callStopHookAndFreeSFcnMemory();');
           this.writeCallToMEXAPITerminateFunction();
           this.writer.wLine('mxArray* pMException = xilMATLABUtilsGetException(%s);',...
               this.XILUtilsVarName);
           
           % cleanup open resources (including xilUtils) before throwing
           % exception
           this.writer.wLine('mdlCleanupRuntimeResources();');
           
           
           this.writer.wBlockStart('if (pMException == NULL)');
           this.writer.wLine('mexPrintf("pMException is NULL!\n");');
           this.writer.wBlockMiddle('else')
           this.writer.wLine('mexCallMATLAB(0, NULL, 1, &pMException, "rtw.pil.SILPILInterface.throwMException");');
           this.writer.wBlockEnd; %if (pMException)
           
           this.writer.wBlockEnd; % function
                                 
       end
       
       function writeSectionDestroyArray(this, arrayPtr, numElements)
           if numElements < 4
              for i=1:numElements
                this.writer.writeLine(['mxDestroyArray(' arrayPtr ...
                                       '[' int2str(i-1) ']);']);
              end
           else
               this.writer.wBlockStart('');
               
               this.writer.writeLine('int i;');
               this.writer.wBlockStart(['for (i=0; i<' int2str(numElements) '; i++)']); 

               this.writer.writeLine(['mxDestroyArray(' arrayPtr '[i]);']);
               this.writer.wBlockEnd; % for (i=0; i<' int2str(numElements) '; i++)
               
               this.writer.wBlockEnd;
           end
       end

       function writeSectionTerminate(this)
           if ~this.IsMexTarget
               this.writer.wBlockStart('static void mdlTerminate(%s)', this.CodeFunctionArgDecs);
           else
               fcnName = this.SILPILWrapperUtils.getSILPILInterface.getCodeName;
               this.writer.wBlockStart('void %s_xil_terminate()', fcnName);
           end
           
           if this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid
               this.writeSectionTerminateBody;
           end
           this.writer.wBlockEnd; % mdlTerminate/<fcn>_xil_terminate
       end
       
       function writeSectionTerminateBody(this)
           %Setup necessary guarding and condition variables
           this.writeSectionTerminateShutdownPreCode();

           % transfer necessary I/O during Terminate call
           termFun  = this.codeInfo.TerminateFunctions;
           if this.SILPILWrapperUtils.getClientInterface.syncIODuringOneShot() && this.HasModelWideEvents
               inportIndices = unique([this.codeInfoUtils.getDataInterfacesForFunction(termFun, 'input') ...
                   this.codeInfoUtils.getInputPortsForRates(this.codeInfoUtils.getRates('TERMINATE'))]);
           else
               inportIndices = [];
           end
           paramIndices = [];
           dsReadIndices = [];
           dsWriteIndices = [];
           sharedLocalDataStoreIndices = [];
           % Transfer Data Store Writes to TERMINATE call (Though not with
           % S-function based modes as Data Stores can't be accessed)
           termTask = this.codeInfoUtils.getTerminateTasks();
           if ~isempty(termTask) && ...
                   this.SILPILWrapperUtils.getSILPILInterface.getInTheLoopType~=rtw.pil.InTheLoopType.Block
               dsWriteIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                   this.codeInfoUtils.getWriterSharedDataStoresForTask(termTask, 'term'), 'dswrite'); %Extra Argument needed to workaround G1411813
               dsReadIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                   this.codeInfoUtils.getReaderSharedDataStoresForTask(termTask, 'term'), 'dsread'); %Extra Argument needed to workaround G1411813
           end
           if this.SILPILWrapperUtils.getClientInterface.syncIODuringOneShot() && this.HasModelWideEvents
               outportIndices = this.codeInfoUtils.getDataInterfacesForFunction(termFun, 'output');
           else
               outportIndices = [];
           end
           if this.HasModelWideEvents
               loggingIndices = this.codeInfoUtils.getLoggingForRates(this.codeInfoUtils.getRates('TERMINATE'));
           else
               loggingIndices = [];
           end
           serverFcnIndex = [];
           inportSizesIndices = [];
           outportSizesIndices = [];
           
           if this.IsMexTarget
               errorReturn = sprintf('return%s;', this.ReturnArgString);
           else
               
               errorReturn = sprintf('callStopHookAndFreeSFcnMemory(%s); \n return%s;',...
                   this.SimStructArgSingle, this.ReturnArgString);
           end
           
           % issue XIL_TERMINATE_COMMAND command. This instructs the SIL/PIL
           % target application to call the model_terminate function on
           % the target (if there is one)
           %
           % tid not used
           tid = [];
           taskTiming = [];
           this.writeSectionPILIOCommand('XIL_TERMINATE_COMMAND', ...
               inportIndices, ...
               inportSizesIndices, ...
               paramIndices, ...
               dsReadIndices, ...
               dsWriteIndices, ...
               sharedLocalDataStoreIndices, ...
               outportIndices, ...
               outportSizesIndices, ...
               loggingIndices, ...
               serverFcnIndex, ...
               tid, ...
               taskTiming, ...
               errorReturn);
           
           if this.IsMexTarget
               %Close out the _xil_terminate function, and start the
               %_xil_shutdown function.
               %Need to split the functions to ensure outputs are processed
               %and shutdown executed correctly.
               
               this.writer.wBlockEnd; %if (!commErrorOccurred)
               this.writer.wBlockEnd; %if (isXILApplicationStarted)
               this.writer.wBlockEnd; % void <fcn>_xil_terminate()
               
               fcnName = this.SILPILWrapperUtils.getSILPILInterface.getCodeName;
               this.writer.wBlockStart('void %s_xil_shutdown()',fcnName);
               
               this.writeSectionTerminateShutdownPreCode();
               
               errorReturn = sprintf('callStopHookAndFreeSFcnMemory(%s); \n return%s;',...
                   this.SimStructArgSingle, this.ReturnArgString);
           end
           
           % Reset Data store indices for SHUTDOWN call
           dsWriteIndices = [];
           
           % issue XIL_SHUTDOWN_COMMAND command - this instructs the SIL/PIL
           % target application to shut down
           this.writeSectionPILIOCommand('XIL_SHUTDOWN_COMMAND', ...
               inportIndices, ...
               inportSizesIndices, ...
               paramIndices, ...
               dsReadIndices, ...
               dsWriteIndices, ...
               sharedLocalDataStoreIndices,...
               outportIndices, ...
               outportSizesIndices, ...
               loggingIndices, ...
               serverFcnIndex, ...
               tid, ...
               taskTiming, ...
               errorReturn);
           
           this.writer.wBlockEnd; %if (!commErrorOccurred)
           
           % disable logging
           this.writeLoggingFlag(false);
           
           this.writer.wBlockEnd; %if (isXILApplicationStarted)
           % Ensure all memory is freed up as function is unloaded from
           % memory G1350285
           this.writer.wLine('callStopHookAndFreeSFcnMemory(%s);',...
               this.SimStructArgSingle);
           
           % in case of MATLAB coder, call mdlCleanupRuntimeResources
           % manually to free memory allocated in mdlSetupRuntimeResources
           if this.IsMexTarget
               this.writer.wLine('mdlCleanupRuntimeResources();');
           end
       end
       
       %Write out code used at the top of the Terminate and Shutdown calls.
       function writeSectionTerminateShutdownPreCode(this)
           
           this.writer.writeLine('int commErrorOccurred = 0;');
           this.writer.writeLine('int isXILApplicationStarted = 0;');
           if this.IsMexTarget
               this.writer.wComment('MEX function is being cleared');
               this.writer.wLine('executingClearMEX = 1;');
           end
           
           this.writer.newLine;
           this.writer.wBlockStart('');
           if ~this.IsMexTarget
               % return if codegen
               this.writeSectionReturnIfCodeGen;
               this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');
           end
           this.getPWorkValue('int', 'pCommErrorOccurred', this.getCommErrorOccurredIdx, true);
           this.getPWorkValue('int', 'pIsXILApplicationStarted', this.getIsXILApplicationStartedIdx, true);
           
           this.writer.wBlockStart('if (pCommErrorOccurred != NULL)');
           this.writer.writeLine('commErrorOccurred = *pCommErrorOccurred;');
           this.writer.wBlockEnd; %if (pCommErrorOccurred != NULL
           
           this.writer.wBlockStart('if (pIsXILApplicationStarted != NULL)');
           this.writer.writeLine('isXILApplicationStarted = *pIsXILApplicationStarted;');
           this.writer.wBlockEnd; %if (pIsXILApplicationStarted != NULL)
           
           if ~this.IsMexTarget
               this.writer.wBlockEnd; %if (ssGetPWork(S) != NULL)
           end
           this.writer.wBlockEnd;
           this.writer.newLine;
           
           this.writer.wBlockStart('if (isXILApplicationStarted)');
           this.writer.wBlockStart('if (!commErrorOccurred)');
       end
       
       function writeSectionStartAndSetupApplication(this)
           
           if ~this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid
               % If component boundary validation failed, then there is no
               % need to write this function at all.
               return;
           end

           cacheReturnArgString = this.ReturnArgString;
           this.ReturnArgString = ' false';
           errorReturn = sprintf('return%s;', this.ReturnArgString);

           this.writer.wBlockStart('static boolean_T startAndSetupApplication(%s%s)', ...
               this.SimStructType, this.SimStructArgSingle);
           
           % Start application
           this.writer.wBlockStart('');
           
           % call sfunctionPILStartHook
           this.writer.wBlockStart('');
           numRHS = 4;
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
           this.writer.writeLine(['mxArray *rhs[' int2str(numRHS) '];']);
           this.writeCallMATLABTypeAndPathInputs(0, errorReturn);
           this.writer.wLine('rhs[3] = mxCreateString("%s");', memUnitInfo.ioDataTypeMATLAB);
           this.writer.wBlockStart('');
           this.callMATLAB(0, numRHS, 'rtw.pil.SILPILInterface.sfunctionPILStartHook', errorReturn)
           this.writer.wBlockEnd;
           this.freeSimulinkBlockPath;
           this.writer.wBlockEnd;
           
           % set the application has started
           this.writer.wBlockStartComment('', 'record that the XIL application has started');
           this.getPWorkValue('int', 'pIsXILApplicationStarted', this.getIsXILApplicationStartedIdx, true);
           this.writer.writeLine('*pIsXILApplicationStarted = 1;');
           this.setPWorkValue( this.getIsXILApplicationStartedIdx, 'pIsXILApplicationStarted');
           this.writer.wBlockEnd;
           
           this.writer.wBlockEnd;

           % Must follow sfunctionPILInitCommand because we need the
           % Communicator to be initialized in order to retrieve the
           % streamID
           
           % call sfunctionGetRtIOStreamInfoHook
           this.writer.wBlockStart('');
           % declarations
           numRHS = 3;
           numLHS = 5;
           this.writer.writeCellLines({['mxArray *rhs[' int2str(numRHS) '];'];
               ['mxArray *lhs[' int2str(numLHS) '];'];});
           this.writeCallMATLABTypeAndPathInputs(0, errorReturn);
           this.writer.wBlockStart('');
           this.callMATLAB(numLHS, numRHS, 'rtw.pil.SILPILInterface.sfunctionGetRtIOStreamInfoHook', errorReturn);
           this.writer.wBlockEnd;
           this.freeSimulinkBlockPath;
           if ~this.IsUsingCommServiceAPI
               % initialize rtIOStreamData
               this.writer.wBlockStart('');
               this.writer.wLine('%srtIOStreamDataPtr = (XIL_RtIOStreamData_T*) mxCalloc(1, sizeof(XIL_RtIOStreamData_T));', ...
                   this.LocalRTIOStreamType);
               this.writer.wBlockStart('if (rtIOStreamDataPtr == NULL)');
               this.writeErrorCall('Error in allocating memory through mxCalloc.');
               this.writer.wLine(errorReturn);
               this.writer.wBlockEnd; % (rtIOStreamDataPtr == NULL)
               
               % copy out the data we need
               % mxArrayToString ptr must be freed with mxFree!
               this.writer.writeLine('rtIOStreamDataPtr->lib = mxArrayToString(lhs[0]);');
               % must free later with mxDestroyArray
               this.writer.writeLine('rtIOStreamDataPtr->MATLABObject = mxDuplicateArray(lhs[1]);');
               % make sure mx allocated memory remains in tact between
               % s-function invocations!
               this.writer.writeLine('mexMakeMemoryPersistent(rtIOStreamDataPtr);');
               this.writer.writeLine('mexMakeMemoryPersistent(rtIOStreamDataPtr->lib);');
               this.writer.writeLine('mexMakeArrayPersistent(rtIOStreamDataPtr->MATLABObject);');
               this.writer.writeLine('rtIOStreamDataPtr->streamID = *mxGetPr(lhs[2]);');
               this.writer.writeLine('rtIOStreamDataPtr->recvTimeout = *mxGetPr(lhs[3]);');
               this.writer.writeLine('rtIOStreamDataPtr->sendTimeout = *mxGetPr(lhs[4]);');
               this.writer.writeLine('rtIOStreamDataPtr->isRtIOStreamCCall = %d;', this.isRtIOStreamCCall);
               this.writer.writeLine('rtIOStreamDataPtr->ioMxClassID = %s;', memUnitInfo.ioDataClass);
               this.writer.writeLine('rtIOStreamDataPtr->ioDataSize = sizeof(%s);', memUnitInfo.ioDataType);
               rtioStreamAppService = this.SILPILWrapperUtils.getTargetServices().getRtIOStreamApplicationService();
               this.writer.writeLine('rtIOStreamDataPtr->targetRecvBufferSizeBytes = %d;',...
                   rtioStreamAppService.getReceiveBufferSize());
               % On the target the send-buffer size is increased to account for the command complete
               % field, so add one memUnit to the send buffer size to account for it.
               this.writer.writeLine('rtIOStreamDataPtr->targetSendBufferSizeBytes = %d + %d;',...
                   rtioStreamAppService.getSendBufferSize(), memUnitInfo.memUnitBytes);
               
               if this.isRtIOStreamCCall
                   % load the library for direct RtIOStream access from this s-function
                   this.writer.wBlockStart('');
                   this.writer.writeLine('int errorStatus = rtIOStreamLoadLib(&rtIOStreamDataPtr->libH, rtIOStreamDataPtr->lib);')
                   
                   this.writer.wBlockStart('if (errorStatus)');
                   this.writeErrorCall('rtIOStreamLoadLib failed.');
                   this.writer.wLine(errorReturn);
                   this.writer.wBlockEnd; % if (errorStatus)
                   
                   this.writer.wBlockEnd;
               end
               this.setPWorkValue( this.getRtIOStreamPWorkIdx, 'rtIOStreamDataPtr');
                        
               this.writer.wBlockEnd;
           end
           
           % free lhs
           this.writeSectionDestroyArray('lhs', numLHS);
           this.writer.wBlockEnd;
           
           % initialize IOBuffer
           this.writer.wBlockStart('');
           this.writer.wLine('%sIOBufferPtr = (XIL_IOBuffer_T *) mxCalloc(1, sizeof(XIL_IOBuffer_T));', this.LocalIOBufferType);
           this.writer.wBlockStart('if (IOBufferPtr == NULL)');
           this.writeErrorCall('Error in allocating memory through mxCalloc.');
           this.writer.wLine(errorReturn);
           this.writer.wBlockEnd; % (IOBufferPtr == NULL)
           this.writer.writeLine('mexMakeMemoryPersistent(IOBufferPtr);');
           this.setPWorkValue( this.getIOBufferPWorkIdx, 'IOBufferPtr');
           this.writer.wBlockEnd;
           
           if ~this.IsUsingCommServiceAPI
               % initialize silDebuggingData
               this.writer.wBlockStart('');
               if this.IsMexTarget
                   this.writeSimulinkBlockPath(errorReturn);
                   this.writer.wLine('silDebuggingDataPtr = (SIL_DEBUGGING_DATA_T*) mxCalloc(1, sizeof(SIL_DEBUGGING_DATA_T));');
               else
                   this.writer.wLine('SIL_DEBUGGING_DATA_T* silDebuggingDataPtr = (SIL_DEBUGGING_DATA_T*) mxCalloc(1, sizeof(SIL_DEBUGGING_DATA_T));');
                   this.writeSimulinkBlockPath(errorReturn);
               end
               this.writer.wBlockStart('if (silDebuggingDataPtr == NULL)');
               this.writeErrorCall('Error in allocating memory through mxCalloc for SIL_DEBUGGING_DATA_T.');
               this.writer.wLine(errorReturn);
               this.writer.wBlockEnd; % (silDebuggingDataPtr == NULL)
               silPILInterface = this.SILPILWrapperUtils.getSILPILInterface;
               clientInterface = silPILInterface.getClientInterface;
               fcnStr = clientInterface.getSILPILInterfaceFcnStr;
               this.writer.writeLine('silDebuggingDataPtr->componentBlockPath = strcpy((char *) mxCalloc(strlen(simulinkBlockPath)+1, sizeof(char)), simulinkBlockPath);');
               this.writer.writeLine('silDebuggingDataPtr->SILPILInterfaceFcnStr = strcpy((char*) mxCalloc(%d, sizeof(char)), "%s");', length(fcnStr)+1, fcnStr);
               this.writer.writeLine('silDebuggingDataPtr->inTheLoopType = %d;', int32(silPILInterface.getInTheLoopType));
               this.writer.writeLine('mexMakeMemoryPersistent(silDebuggingDataPtr);');
               this.writer.writeLine('mexMakeMemoryPersistent(silDebuggingDataPtr->componentBlockPath);');
               this.writer.writeLine('mexMakeMemoryPersistent(silDebuggingDataPtr->SILPILInterfaceFcnStr);');
               this.setPWorkValue( this.getSILDebuggingPWorkIdx, 'silDebuggingDataPtr');
               this.freeSimulinkBlockPath();
               this.writer.wBlockEnd;
           end
           
           % initialize the file descriptor array
           this.writer.wBlockStart('');
           this.writer.wLine('%stargetIOFdPtr = (targetIOFd_T *) mxCalloc(1, sizeof(targetIOFd_T));', ...
               this.LocaltargetIOFdType);
           this.writer.wBlockStart('if (targetIOFdPtr == NULL)');
           this.writer.wLine(errorReturn);
           this.writer.wBlockEnd; % (targetIOFdPtr == NULL)
           
           this.writer.writeLine('mexMakeMemoryPersistent(targetIOFdPtr);');
           this.writer.writeLine('targetIOFdPtr->size = 0;');
           this.writer.writeLine('targetIOFdPtr->Fd = NULL;');
           % initial value for fidOffset;
           this.writer.writeLine('targetIOFdPtr->fidOffset = -1;');
           
           % store to PWork
           this.setPWorkValue( this.getTargetIOFdArrPWorkIdx, 'targetIOFdPtr');
           
           this.writer.wBlockEnd;
           
           % create various XIL services and store on PWork
           this.writer.wBlockStart('');
           
           % for MEX target, we already defined these as static global
           if ~this.IsMexTarget
               this.writer.wLine('void* pConnectionOptions = NULL;');
               this.writer.wLine('void* pComms = NULL;');
               this.writer.wLine('void* pXILService = NULL;');
               this.writer.wLine('void* pMemUnitTransformer = NULL;');
           end
           
           % prepare arguments required to instantiate the various services
           this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
           memUnitSizeBytes =  rtw.connectivity.TypeUtils.builtinHostByteSize(...
               memUnitInfo.memUnitType);
           this.writer.writeLine('uint8_T memUnitSizeBytes = %d;',...
               memUnitSizeBytes);
           this.writer.writeLine('uint8_T ioDataTypeSizeBytes = sizeof(%s);',...
               memUnitInfo.ioDataType);
           if ~this.IsUsingCommServiceAPI
               this.getPWorkValue('XIL_RtIOStreamData_T', 'rtIOStreamDataPtr',...
                   this.getRtIOStreamPWorkIdx, true);
               this.getPWorkValue('SIL_DEBUGGING_DATA_T', 'silDebuggingDataPtr',...
                   this.getSILDebuggingPWorkIdx, true);
           end
           this.getPWorkValue('XIL_IOBuffer_T', 'IOBufferPtr',...
               this.getIOBufferPWorkIdx, true);
           
           if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
               this.writer.newLine;
               if ~this.IsMexTarget
                   this.writer.writeLine('void* pCodeInstrService = NULL;');
               end
               this.writer.writeLine('%s* pCodeInstrServiceData = codeInstrServiceData(%smemUnitSizeBytes);',...
                   this.LocalCodeInstrServiceDataType, this.SimStructArg);
               this.writer.newLine;
           end
           
           if ~this.IsMexTarget && this.SILPILWrapperUtils.isCoderAssumptionsEnabled
               this.writer.writeLine('void * pCoderAssumptionsApp = NULL;');
           end
           
           if this.IsNeededMemUnitXform
               this.getPWorkValue('void', 'pMemUnitTransformer', ...
                   this.getMemUnitTransformerPWorkIdx, false);
           end
           
           % instantiate comm service
           if this.IsUsingCommServiceAPI
               % ConnectionOptions
               this.writer.wBlockStart(['if (!ConnectionOptionsCreate('...
                   '&pConnectionOptions))']);
               this.writeSectionProcessException;
               this.writer.wLine(errorReturn);
               this.writer.wBlockEnd; %if (ConnectionOptionsCreate)
               
               this.writer.wBlockStart('');
               % declarations
               numRHS = 3;
               numLHS = 1;
               this.writer.wLine('uint16_T portNum;');
               this.writer.writeCellLines({['mxArray *rhs[' int2str(numRHS) '];'];
                   ['mxArray *lhs[' int2str(numLHS) '];'];});
               this.writeCallMATLABTypeAndPathInputs(0, errorReturn);
               this.writer.wBlockStart('');
               this.callMATLAB(numLHS, numRHS, 'rtw.pil.SILPILInterface.sfunctionGetServerPortNumber', errorReturn);
               this.writer.wBlockEnd(); % empty block
               this.freeSimulinkBlockPath;
               this.writer.wLine('portNum = *mxGetPr(lhs[0]);');
               this.writer.wLine('mxDestroyArray(lhs[0]);');
               this.writer.wLine('ConnectionOptionsSetIPPort(pConnectionOptions, portNum);');
               this.writer.wLine('ConnectionOptionsSetHostName(pConnectionOptions, "localhost");');
               this.writer.wLine('ConnectionOptionsSetTransport(pConnectionOptions, (int32_T)0);'); %TCPIP
               this.writer.wBlockEnd;
               
               
               % TargetConnection
               this.writer.wBlockStart(['if (!TargetConnectionCreate('...
                   '&pComms, pConnectionOptions))']);
               this.writeSectionProcessException;
               this.writer.wLine(errorReturn);
               this.writer.wBlockEnd; %if (TargetConnectionCreate)
           else
               this.writer.wBlockStart(['if (xilCommsCreate('...
                   '&pComms, rtIOStreamDataPtr, silDebuggingDataPtr, '...
                   'memUnitSizeBytes, pMemUnitTransformer, %s, %d) '...
                   '!= XILCOMMS_RTIOSTREAM_SUCCESS)'],...
                   this.XILUtilsVarName, ...
                   this.isVerbose());
               this.writeSectionProcessException;
               this.writer.wLine(errorReturn);
               this.writer.wBlockEnd; %if (xilCommsCreate)
           end
           
           % call xilHostAppSvcCreate
           this.writer.wBlockStart(['if (xilHostAppSvcCreate('...
               '&pXILService, pComms, %s, IOBufferPtr, '...
               'memUnitSizeBytes, ioDataTypeSizeBytes, %d) '...
               '!= XILHOSTAPPSVC_SUCCESS)'], this.XILUtilsVarName,...
               this.IsUsingCommServiceAPI);
           this.writeSectionProcessException;
           this.writer.wLine(errorReturn);
           this.writer.wBlockEnd; %if (xilHostAppSvcCreate)
           
           % call codeInstrHostAppSvcCreate
           if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
               % section id size
               this.writer.wBlockStart('');
               this.writer.writeLine('void * pCodeInstrMultiRunData = NULL;');
               if ~this.IsMexTarget
                   this.getPWorkValue('void', 'pCodeInstrMultiRunData', ...
                       this.getCodeInstrMultiRunDataIdx, false);
               end
               
               lTargetWordSize = this.SILPILWrapperUtils.getParam('TargetWordSize');
               idTypeSize = coder.profile.ExecTimeConfig.getIdTypeSize(lTargetWordSize);
               this.writer.wBlockStart(['if (codeInstrHostAppSvcCreate('...
                   '&pCodeInstrService, pCodeInstrServiceData, pComms, '...
                   'pMemUnitTransformer, %d, %s, memUnitSizeBytes, %d, pCodeInstrMultiRunData) '...
                   '!= CODEINSTRHOSTAPPSVC_SUCCESS)'],...
                   idTypeSize, this.XILUtilsVarName, this.IsUsingCommServiceAPI);
               this.writeSectionProcessException;
               this.freeCodeInstrServiceData();
               this.writer.wLine(errorReturn);
               this.writer.wBlockEnd; %if (codeInstrHostAppSvcCreate)
               
               this.writer.newLine;
               this.freeCodeInstrServiceData();
               this.writer.newLine;
               this.writer.wBlockEnd();
           end
           
           % call coderAssumpHostAppSvcCreate
           if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
               config = this.SILPILWrapperUtils.getConfigInterface;
               configProdEqTarget = strcmp(config.getParam('ProdEqTarget'), 'on');
               % Use the SILPILWrapperUtils to get the root model (for the
               % case of SIL/PIL block generation).
               configCodeGenComponent = this.SILPILWrapperUtils.getSILPILInterface().getRootModel();
               configIsSimulinkConfig = ~this.IsMexTarget;
               % currently, always disable verbose output
               verbose = false;
               isSIL=this.SILPILWrapperUtils.getSILPILInterface.isSIL;
               this.writer.wBlockStart('');
               % We use an mxArray in case we need to ultimately support
               % Unicode component names.
               %
               % The ownership of the codeGenComponent mxArray will get
               % transferred to the coderAssumpHostAppSvcCreate function,
               % which will be responsible for destroying it.
               this.writer.wLine('mxArray * codeGenComponent = mxCreateString("%s");', ...
                   configCodeGenComponent);
               % Write SILPILInterfaceFcnStr, InTheLoopType and BlockPath arguments
               this.writer.writeLine(['mxArray *rhs[' int2str(3) '];']);
               % elements of rhs are cleared by coderAssumpHostAppSvcCreate
               this.writeCallMATLABTypeAndPathInputs(0, errorReturn);
               % Write call to coderAssumpHostAppSvcCreate
               this.writer.wBlockStart(['if (coderAssumpHostAppSvcCreate('...
                   '&pCoderAssumptionsApp, pComms, %s, %d, %d, codeGenComponent, rhs[0], rhs[1], rhs[2], %d, %d, %d) '...
                   '!= CODERASSUMPHOSTAPPSVC_SUCCESS)'],...
                   this.XILUtilsVarName, ...
                   verbose, ...
                   configProdEqTarget, ...
                   configIsSimulinkConfig,...
                   this.IsUsingCommServiceAPI,...
                   isSIL);
               this.writeSectionProcessException;
               this.writer.wLine(errorReturn);
               this.writer.wBlockEnd; %if (coderAssumpHostAppSvcCreate)
               this.freeSimulinkBlockPath; % free memory allocated by writeCallMATLABTypeAndPathInputs via getSimulinkBlockPath
               this.writer.wBlockEnd;
           end
           
           % register services
           if ~this.IsUsingCommServiceAPI
               this.writer.writeLine('xilCommsRegisterApplication(pComms, pXILService);');
               if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                   this.writer.writeLine('xilCommsRegisterApplication(pComms, pCodeInstrService);');
               end
               if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
                   this.writer.writeLine('xilCommsRegisterApplication(pComms, pCoderAssumptionsApp);');
               end
           end
           
           % store the services on PWork
           this.setPWorkValue(this.getXILServicePWorkIdx, 'pXILService');
           if this.IsUsingCommServiceAPI
               this.setPWorkValue(this.getConnectionOptionsPWorkIdx, 'pConnectionOptions');
           end
           this.setPWorkValue(this.getCommsPWorkIdx, 'pComms');
           this.setPWorkValue(this.getXILUtilsPWorkIdx, this.XILUtilsVarName);
           if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
               this.setPWorkValue(this.getCodeInstrServicePWorkIdx, 'pCodeInstrService');
           end
           if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
               this.setPWorkValue(this.getCoderAssumptionsPWorkIdx, 'pCoderAssumptionsApp');
           end
           this.writer.wBlockEnd; %creation services block
           
           % send INIT command to test the full comms process
           inportIndices = [];
           inportSizesIndices = [];
           paramIndices = [];
           dsReadIndices = [];
           dsWriteIndices = [];
           sharedLocalDataStoreIndices = [];
           outportIndices = [];
           outportSizesIndices = [];
           loggingIndices = [];
           serverFcnIndex = [];
           % issue command
           %
           % Need to provide tid used by execution profiling
           tid = rtw.pil.Sfunction.InitializeTaskId;
           taskTiming = [];
           this.writeSectionPILIOCommand('XIL_INIT_COMMAND', ...
               inportIndices, ...
               inportSizesIndices, ...
               paramIndices, ...
               dsReadIndices, ...
               dsWriteIndices, ...
               sharedLocalDataStoreIndices, ...
               outportIndices, ...
               outportSizesIndices, ...
               loggingIndices, ...
               serverFcnIndex, ...
               tid, ...
               taskTiming,...
               errorReturn);
           %
           
           if ~this.IsMexTarget
               this.writer.wComment('initialize parameters');
               % call processParams
               this.writer.wLine('processParams(%s);', this.CodeFunctionArgs);
           end
           
           % write update global data store
           this.writeSectionInitDataStoreIndices();
           
           % initialize String outputs
           this.writeSectionInitStringOutputMemory();
           % initialize String logged signals (C API does not support strings)
           this.writeSectionInitStringLogging();
           
           % enable logging
           this.writeLoggingFlag(true);
           
           this.writer.wLine('return true;');
           this.writer.wBlockEnd; % setupAndStartApplication
           this.ReturnArgString = cacheReturnArgString;
       end
           
       function writeSectionSendInitializeCommand(this)
           this.writer.wBlockStart('static void sendInitializeCommand(%s%s)', ...
               this.SimStructType, this.SimStructArgSingle);

           if ~this.SILPILWrapperUtils.ComponentBoundaryValidation.IsValid
               this.writer.wBlockEnd();
               return;
           end
           
           % determine if there is any I/O to transfer (handle both
           % initialize and Start)
           funs = this.codeInfo.InitializeFunctions;
           inportIndices = this.codeInfoUtils.getDataInterfacesForFunction(funs, 'input');
           inportIndices = this.codeInfoUtils.getAdditionalInitializeInportIndices(inportIndices);
           
           % Transfer parameters and InstP model arguments
           paramIndices = [this.getParamIndicesForFunction(funs), ...
               this.SILPILWrapperUtils.getInstPArgumentIndices()];
           
           if this.SILPILWrapperUtils.getClientInterface.syncIODuringOneShot()
               outportIndices = this.codeInfoUtils.getDataInterfacesForFunction(funs, 'output');
           else
               outportIndices = [];
           end
           inportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(funs, 'inputsize');
           outportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(funs, 'outputsize');
           
           % Transfer Data Store Reads to INITIALIZE call
           initTask = this.codeInfoUtils.getInitializeTasks();
           dsReadIndices = [];
           for taskIdx = 1:length(initTask)
               dsReadIndices = [dsReadIndices ...
                   this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                   this.codeInfoUtils.getReaderSharedDataStoresForTask(initTask(taskIdx), 'init'), 'dsread')]; %#ok<AGROW> %Extra Argument needed to workaround G1411813
           end
           dsReadIndices = unique(dsReadIndices,'stable');
           dsWriteIndices = [];
           for taskIdx = 1:length(initTask)
               dsWriteIndices = [dsWriteIndices ...
                   this.SILPILWrapperUtils.getDataStoresToTransferIndices(...
                   this.codeInfoUtils.getWriterSharedDataStoresForTask(initTask(taskIdx), 'init'), 'dswrite')]; %#ok<AGROW> %Extra Argument needed to workaround G1411813
           end
           dsWriteIndices = unique(dsWriteIndices,'stable');
           sharedLocalDataStoreIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
               1:length(this.codeInfoUtils.getSharedLocalDataStores), 'initializeSharedLocal');
           
           % process constant sig logs after the initialize command
           loggingIndices = this.codeInfoUtils.getLoggingForRates(this.codeInfoUtils.getRates('ONESHOT'));
           if this.HasModelWideEvents
               loggingIndices = [loggingIndices ...
                   this.codeInfoUtils.getLoggingForRates(this.codeInfoUtils.getRates('INITIALIZE'))];
           end
           serverFcnIndex = [];
           
           % issue command
           tid = rtw.pil.Sfunction.InitializeTaskId;
           taskTiming = [];
           this.writeSectionPILIOCommand('XIL_INITIALIZE_COMMAND', ...
               inportIndices, ...
               inportSizesIndices, ...
               paramIndices, ...
               dsReadIndices, ...
               dsWriteIndices, ...
               sharedLocalDataStoreIndices, ...
               outportIndices, ...
               outportSizesIndices, ...
               loggingIndices, ...
               serverFcnIndex, ...
               tid, ...
               taskTiming);
           this.writer.wBlockEnd;
       end

       function writeSectionCallPrintfHook(this)
           % retrieve & print target stdout, stderr
           if this.IsMexTarget
               this.writer.wBlockStart('static void callPrintfHook(%s%s)', ...
                   this.SimStructType, this.SimStructArgSingle);

               numRHS = 3;
               this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
               this.writer.wBlockStart('if (%s)', this.XILUtilsVarName);
               this.writer.writeLine(['mxArray *rhs[' int2str(numRHS) '];']);
               this.writeCallMATLABTypeAndPathInputs( 0 );
               % rhs will get freed automatically by xilUtilsCallMATLAB
               this.writer.wLine('xilUtilsCallMATLAB(%s, 0, NULL, %d, rhs, "rtw.pil.SILPILInterface.sfunctionPrintfHook");', ...
                   this.XILUtilsVarName, numRHS);
               this.writer.wBlockEnd; %if (pXILUtils)

               this.writer.wBlockEnd; %static void callPrintfHook
           end
       end
       
       function writeSectionCallStopHookAndFreeSFcnMemoryFcn(this)
           % free all memory allocated by this SFunction
           
          this.writer.wBlockStart('static void callStopHookAndFreeSFcnMemory(%s%s)', ...
               this.SimStructType, this.SimStructArgSingle);
           
           % We only need a return argument from xilUtilsCallMATLAB for
           % MATLAB Coder
           callMATLABReturnArg = '';
           if this.IsMexTarget 
               errorVar = 'errorOccurred';
               callMATLABReturnArg = [errorVar ' = '];
               this.writer.wLine('bool %sXIL_UTILS_SUCCESS;', callMATLABReturnArg);
           end
           
           % This is where the files get closed before calling the hook of
           % code coverage tools such as LDRA.
           % The memory used is also get freed
           this.writer.wLine('closeAndFreeTargetIOFd(%s);', ...
               this.SimStructArgSingle);
           
           if ~this.IsMexTarget          
               this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');
           end           
           
           this.getPWorkValue('int', 'pCommErrorOccurred', this.getCommErrorOccurredIdx, true);
           this.getPWorkValue('int', 'pIsXILApplicationStarted', this.getIsXILApplicationStartedIdx, true);
           
           % Guard call into stop hook so it only happens when
           % application has started.
           this.writer.wBlockStart('if ((pIsXILApplicationStarted != NULL) && (*pIsXILApplicationStarted == 1))');
           
           % call sfunctionPILStopHook
           numRHS = 3;
           this.writer.wBlockStart('');
           this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
           this.writer.wBlockStart('if (%s)', this.XILUtilsVarName);
           this.writer.writeLine(['mxArray *rhs[' int2str(numRHS) '];']);
           this.writeCallMATLABTypeAndPathInputs( 0 );
           % rhs will get freed automatically by xilUtilsCallMATLAB
           this.writer.wLine('%sxilUtilsCallMATLAB(%s, 0, NULL, %d, rhs, "rtw.pil.SILPILInterface.sfunctionPILStopHook");', ...
               callMATLABReturnArg, this.XILUtilsVarName, numRHS);
           this.freeSimulinkBlockPath;
           this.writer.wBlockEnd; %if (pXILUtils)
           this.writer.wBlockEnd; %
           this.writer.wBlockEnd;
           
           % reset pIsXILApplicationStarted
           % if called from within error clean up, mark application as
           % stopped only
           this.writer.wBlockStart('if (pIsXILApplicationStarted != NULL)');
           this.writer.wLine('*pIsXILApplicationStarted = 0;');
           this.writer.wBlockEnd; %if (pIsXILApplicationStarted != NULL)

           if ~this.IsMexTarget
               this.writer.wBlockEnd; %if (ssGetPWork(S) != NULL)
           end
           
           % free rtIOStreamData and IOBufferPtr
           
           if ~this.IsMexTarget
               % make sure PWork itself has been initialized
               this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');
               this.writer.writeLine('XIL_IOBuffer_T* IOBufferPtr;');
           end
           
           if ~this.IsUsingCommServiceAPI
               this.getPWorkValue('XIL_RtIOStreamData_T', 'rtIOStreamDataPtr', this.getRtIOStreamPWorkIdx, true);
               this.getPWorkValue('SIL_DEBUGGING_DATA_T', 'silDebuggingDataPtr', this.getSILDebuggingPWorkIdx, true);
               % make sure PWork contents have been initialized
               this.writer.wBlockStart('if (rtIOStreamDataPtr != NULL)');
               if this.isRtIOStreamCCall
                   % given that rtIOStreamDataPtr is valid, the RtIOStream
                   % library must have been loaded so unload it now.
                   %
                   % flag error via ssSetErrorStatus but carry on
                   this.writer.wBlockStart('');
                   this.writer.writeLine('int errorStatus = rtIOStreamUnloadLib(&rtIOStreamDataPtr->libH);')
                   this.writer.wBlockStart('if (errorStatus)');
                   this.writeErrorCall('rtIOStreamUnloadLib failed.');
                   this.writer.wBlockEnd; % if (errorStatus)
                   this.writer.wBlockEnd;
               end
               % free lib string (need mxFree owing to allocation via
               % mxArrayToString)
               this.writer.writeLine('mxFree(rtIOStreamDataPtr->lib);');
               % free MATLABObject (need mxDestroyArray owing to allocation
               % via mxDuplicateArray)
               this.writer.writeLine('mxDestroyArray(rtIOStreamDataPtr->MATLABObject);');
               % free rtIOStreamData
               this.writer.writeLine('mxFree(rtIOStreamDataPtr);');
               
               % mark the PWork as NULL
               this.setFreedPWorkValueToNull('rtIOStreamDataPtr', this.getRtIOStreamPWorkIdx);
               this.writer.wBlockEnd; % if (rtIOStreamDataPtr != NULL)
               
               % free silDebuggingDataPtr
               this.writer.wBlockStart('if (silDebuggingDataPtr != NULL)');
               this.writer.writeLine('mxFree(silDebuggingDataPtr->componentBlockPath);');
               this.writer.writeLine('mxFree(silDebuggingDataPtr->SILPILInterfaceFcnStr);');
               this.writer.writeLine('mxFree(silDebuggingDataPtr);');
               % mark the PWork as NULL
               this.setFreedPWorkValueToNull('silDebuggingDataPtr', this.getSILDebuggingPWorkIdx);
               this.writer.wBlockEnd; % if (silDebuggingDataPtr != NULL)
           end
           
           this.getPWorkValue('XIL_IOBuffer_T', 'IOBufferPtr', this.getIOBufferPWorkIdx, false);
           this.writer.wBlockStart('if (IOBufferPtr != NULL)');
           % free data
           this.writer.writeLine('mxFree(IOBufferPtr->data);');
           % free IOBufferPtr
           this.writer.writeLine('mxFree(IOBufferPtr);');
           
           % mark the PWork as NULL
           this.setFreedPWorkValueToNull('IOBufferPtr', this.getIOBufferPWorkIdx);
           
           this.writer.wBlockEnd; %if (IOBufferPtr != NULL)
           
           % close files and free the memory used if this has not been done
           this.writer.wLine('closeAndFreeTargetIOFd(%s);', ...
               this.SimStructArgSingle);
           
           if ~this.IsMexTarget
               this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');
           end
           this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
           this.getPWorkValue('void', 'pComms', this.getCommsPWorkIdx, true);
           
           if this.IsUsingCommServiceAPI
               this.getPWorkValue('void', 'pConnectionOptions', this.getConnectionOptionsPWorkIdx, true);
           end
           
           this.getPWorkValue('void', 'pXILService', this.getXILServicePWorkIdx, true);                      
           
           if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
               this.getPWorkValue('void', 'pCodeInstrService', this.getCodeInstrServicePWorkIdx, true);
           end
           
           if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
               this.getPWorkValue('void', 'pCoderAssumptionsApp', this.getCoderAssumptionsPWorkIdx, true);
           end                      
           
           % free code instr service
           if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
               this.writer.wBlockStart('if(pCodeInstrService != NULL)');
               memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
               memUnitSizeBytes = rtw.connectivity.TypeUtils.builtinHostByteSize(...
                   memUnitInfo.memUnitType);
               this.writer.writeLine('uint8_T memUnitSizeBytes = %d;',...
                   memUnitSizeBytes);
               this.writer.writeLine('%s* pCodeInstrServiceData = codeInstrServiceData(%smemUnitSizeBytes);',...
                   this.LocalCodeInstrServiceDataType, this.SimStructArg);
               this.writer.wLine('codeInstrHostAppSvcDestroy(pCodeInstrService, pCodeInstrServiceData);');
               
               this.writer.wNewLine;
               this.freeCodeInstrServiceData();
               this.writer.wBlockEnd;
               
               % mark the PWork as NULL
               this.setFreedPWorkValueToNull('pCodeInstrService', this.getCodeInstrServicePWorkIdx);
           end
           
           % free Coder Assumptions App
           if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
               this.writer.wBlockStart('if(pCoderAssumptionsApp != NULL)');
               this.writer.wLine('coderAssumpHostAppSvcDestroy(pCoderAssumptionsApp);');                              
               % mark the PWork as NULL
               this.setFreedPWorkValueToNull('pCoderAssumptionsApp', this.getCoderAssumptionsPWorkIdx);
               this.writer.wBlockEnd;
           end
           
           % free xil service
           this.writer.wBlockStart('if(pXILService != NULL)');
           this.writer.wLine('xilHostAppSvcDestroy(pXILService);');
           this.setFreedPWorkValueToNull('pXILService', this.getXILServicePWorkIdx);
           this.writer.wBlockEnd;
           
           % Freeing the comm service deletes all App Services, so only do 
           % this once App Service destroy hooks have executed
           if this.IsUsingCommServiceAPI               
               this.writer.wBlockStart('if(pComms != NULL)');
               this.writer.wLine('TargetConnectionDestroy(pComms);');
               this.setFreedPWorkValueToNull('pComms', this.getCommsPWorkIdx);
               this.writer.wBlockEnd;
               this.writer.wBlockStart('if(pConnectionOptions != NULL)');
               this.writer.wLine('ConnectionOptionsDestroy(pConnectionOptions);');
               this.setFreedPWorkValueToNull('pConnectionOptions', this.getConnectionOptionsPWorkIdx);
               this.writer.wBlockEnd;               
           else
               this.writer.wBlockStart('if(pComms != NULL)');
               this.writer.wLine('xilCommsDestroy(pComms);');
               this.setFreedPWorkValueToNull('pComms', this.getCommsPWorkIdx);
               this.writer.wBlockEnd;               
           end
                     
           if ~this.IsMexTarget
               this.writer.wBlockEnd;
           end
           
           if ~this.IsMexTarget
               this.writer.wBlockEnd; % if (ssGetPWork(S) != NULL)
           end
           
           if this.IsMexTarget
               this.writer.wComment('Reset pKeepUtilsActive flag');
               this.writer.wLine('pKeepUtilsActive = 0;');
               this.writer.wComment('Throw any errors occurred in the call to stopHook');
               this.writer.wBlockStart('if (%s != XIL_UTILS_SUCCESS)', errorVar);
               this.writeSectionProcessException;
               this.writer.wBlockEnd; % if (errorval != XIL_UTILS_SUCCESS) 
           end
           
           this.writer.wBlockEnd; %static void callStopHookAndFreeSFcnMemory
       end
           
       % write the path to the Simulink block
       function writeSimulinkBlockPath(this, ~)
           if this.IsMexTarget
               silpilInterface = this.SILPILWrapperUtils.getSILPILInterface;
               codeDir = silpilInterface.getCodeDir;
               fcnName = silpilInterface.getCodeName;
               fullBlockPath = fullfile(codeDir, fcnName);
               encodedBlockPath = rtw.pil.Sfunction.escapeCString(fullBlockPath);
               this.writer.wLine('const char * simulinkBlockPath = "%s";', encodedBlockPath);
           else
               this.writer.wLine('const char * simulinkBlockPath = ssGetPath(S);');
           end
       end
       
       % free any required memory associated with the Simulink block path
       function freeSimulinkBlockPath(this) %#ok<MANU>
          % no memory to free - just using ssGetPath
       end
       function freeCodeInstrServiceData(this)
           this.writer.wLine('mxFree(pCodeInstrServiceData);');
       end
       
       % return the string required to get the "Top Model" name if
       % applicable
       function value = getSimulinkModelPath(this)
           if this.IsMexTarget
               value = '""';
           else
               value = 'ssGetPath(_ssGetRootSS(S))';
           end
       end
       
       % Write out the InTheLoopType and BlockPath Arguments for MATLAB
       % function calls
       function writeCallMATLABTypeAndPathInputs(this, startIdx, errorReturn)
           narginchk(2, 3);
           if nargin == 3
               this.writeSimulinkBlockPath(errorReturn);
           else
               this.writeSimulinkBlockPath();
           end
           silPILInterface = this.SILPILWrapperUtils.getSILPILInterface;
           clientInterface = silPILInterface.getClientInterface;
           fcnStr = clientInterface.getSILPILInterfaceFcnStr;
           this.writer.wLine('rhs[ %d ] = mxCreateString("%s");', startIdx, fcnStr);
           this.writer.wLine('rhs[ %d ] = mxCreateDoubleScalar( %d );', startIdx + 1, int32(silPILInterface.getInTheLoopType));
           this.writer.wLine('rhs[ %d ] = mxCreateString(simulinkBlockPath);', startIdx + 2);
       end
       
       function value = getEndianess(this)
           if this.SILPILWrapperUtils.getSILPILInterface.isSIL
               % For SIL use host endianess
               isHostLittleEndian = rtw.pil.SILPILInterface.isHostLittleEndian;
               if isHostLittleEndian
                   value='LittleEndian';
               else
                   value='BigEndian';
               end
           else
               % For PIL use target setting
               value = this.SILPILWrapperUtils.getParam('TargetEndianess');
           end
       end                                            
       
       function sfunIdx = getSfunIdxForDataInterface(this, ...
                                                     dataInterface)           
           if isa(dataInterface, 'rtw.pil.CodeInfoData')
               % correctly calculate sfunIdx
               dataInterfaceType = dataInterface.getDataInterfaceType;
               dataInterfaceIdx = dataInterface.getDataInterfaceIdx;
               switch dataInterfaceType
                   case 'input'
                       sfunIdx = this.getSfunIdxForInputDataInterface(dataInterfaceIdx);
                   case 'output'
                       % zero-based idx
                       sfunIdx = int2str(dataInterfaceIdx - 1);
                   case {'dsread', 'dswrite', 'sharedLocalDataStore'}
                       % lookup dsread or dswrite in the context of shared data stores
                       if strcmp('dsread', dataInterfaceType)
                           ds = this.codeInfoUtils.getReaderSharedDataStores(dataInterfaceIdx);
                       elseif strcmp('dswrite', dataInterfaceType)
                           ds = this.codeInfoUtils.getWriterSharedDataStores(dataInterfaceIdx);
                       else
                           ds = this.codeInfoUtils.getSharedLocalDataStores(dataInterfaceIdx);
                       end
                       allSharedDataStores = this.SILPILWrapperUtils.getDataStoresToTransferInterfaces();
                       match = find(ds == allSharedDataStores);
                       assert(isscalar(match), 'Must have 1-1 mapping between dsread/dswrite and shared data store list.');
                       sfunIdx = int2str(match - 1);
                   case {'siglog', 'statelog', ...
                         'serverFcnInputArg', ...
                         'serverFcnOutputArg', ...
                         'serverFcnInputOutputArg', ...
                         'callerFcnInputArg', ...
                         'callerFcnOutputArg', ...
                         'callerFcnInputOutputArg', ...
                         'queuedFcnInputArg', ...
                         'queuedFcnOutputArg', ...
                         'internal'}
                       % N/A
                       sfunIdx = [];
                   case 'inputsize'
                       % get the corresponding Inport index
                       dataInterfaceIdx = dataInterface.getDataInterfaceIdx;
                       sfunIdx = int2str(this.codeInfoUtils.getInportSizesPortIdx(dataInterfaceIdx) - 1);
                   case {'outputsize'}
                       dataInterfaceIdx = dataInterface.getDataInterfaceIdx;
                       sfunIdx = int2str(this.codeInfoUtils.getOutportSizesPortIdx(dataInterfaceIdx) - 1);
                   otherwise
                       assert(false, 'Unexpected dataInterfaceType: %s', dataInterfaceType);
               end
           elseif isa(dataInterface, 'rtw.pil.NonCodeInfoData')
               % N/A
               sfunIdx = [];
           else
               assert(false, 'Unexpected dataInterface class: %s', class(dataInterface));
           end                                                                           
       end              
       
       function validateInterface(this)            
           % determine if this target is byte addressable or word addressable
           dataTypeService = this.SILPILWrapperUtils.getTargetServices().getDataTypeService();
           isByteAddressable = dataTypeService.getIsByteAddressable();
           
           % get word size
           word_len = dataTypeService.getWordSize();
           if ~isByteAddressable                              
               % check for supported word sizes
               switch word_len
                   % word addressable support not extended for 64-bit at
                   % this time because there are no known example
                   % architectures and it's difficult to test on the host 
                   % because code generation always requires a native 
                   % 32-bit type which violates our assumptions in 
                   % ExtendedHardwareConfig.m.
                   case {16 32}
                       % fine - only support regular word sizes (eg. not 24-bits)
                   otherwise
                       rtw.pil.ProductInfo.error('pil', 'UnsupportedWordSize', int2str(word_len));
               end
           end
           % validate byte_order
           byte_order = this.getEndianess;
           switch byte_order
               case 'Unspecified'                   
                  rtw.pil.ProductInfo.error('pil', 'UnspecifiedByteOrder', this.SILPILWrapperUtils.getComponentForDiagnostics());
               case {'LittleEndian' 'BigEndian'}
                   % fine
               otherwise
                   rtw.pil.ProductInfo.error('pil', 'UnknownByteOrder', byte_order);
           end
           
           % validate I/O data interfaces and build a unique list of I/O datatypes
           this.SILPILWrapperUtils.validateIODataInterfaces;
           
           if (~this.codeInfoUtils.isExportFunctions && ...
                   ~this.HasModelWideEvents && ...
                   this.codeInfoUtils.isSampleTimeIndependent && ...
                   this.useHybridSampleTimes)
              rtw.pil.ProductInfo.error('pil', 'UnsupportedInheritedTsWithSampleTimeIndependentSystem');
           end
       end
       
       % return definition string for "tmp" dataElement variable and a string
       % containing the address of that variable
       function [tmpDefinition, tmpAddress] = getTmpIOVariable(this, ...
                                                               dataElement) %#ok<INUSL>
           simulinkDTypeId = dataElement.getDtypeId;
           simulinkCType = rtw.connectivity.TypeUtils.builtinToHostCType(simulinkDTypeId);
           tmpIOVarName = 'tmpIOVar';
           numElements = dataElement.getNumElements;
           if numElements == 1
               numElementsStr = '';
               tmpAddress = ['&' tmpIOVarName];
           else
               numElementsStr = ['[' num2str(numElements) ']'];
               tmpAddress = ['&' tmpIOVarName '[0]'];
           end
           tmpDefinition = [simulinkCType ' ' tmpIOVarName numElementsStr ';'];
       end  
 
        function writeError(this, errorReturn, errorId, varargin)
            diagnosticType = 'Error';
            this.writeDiagnostic(errorReturn, errorId, diagnosticType, varargin{:})
        end

        function writeWarning(this, warnId, varargin)
            diagnosticType = 'Warning';
            % No return logic required for warning diagnostics
            warnReturn =  '';
            this.writeDiagnostic(warnReturn, warnId, diagnosticType, varargin{:})
        end

        function writeDiagnostic(this, diagnosticReturn, messageId, diagnosticType, varargin)
            arguments
                this
                diagnosticReturn (1,:) char 
                messageId (1,:) char
                diagnosticType (1,:) char {mustBeMember(diagnosticType, {'Error','Warning'})}
            end
            arguments (Repeating)
                varargin
            end

            %Perform clean up tasks before throwing error
            if this.IsMexTarget
                if strcmp(diagnosticType, 'Warning')
                    assert(false, ...
                        'xilUtilsHandleWarning is not implemented for MATLAB Coder workflows!');
                end
                this.writer.wLine('pKeepUtilsActive = 1;');
                this.writer.wLine('callStopHookAndFreeSFcnMemory(%s);',...
                    this.SimStructArgSingle);

                this.writeCallToMEXAPITerminateFunction();
            end

            this.writer.wBlockStart('');
            this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);

            numDiagnosticArgs = length(varargin);
            numRHS = numDiagnosticArgs + 1;
            this.writer.wLine('mxArray * rhs[ %d ];', numRHS);
            this.writer.writeLine(['rhs[0] = mxCreateString("' messageId '");']);
            for i=1:numDiagnosticArgs
                this.writer.writeLine(['rhs[' int2str(i) '] = ' varargin{i} ';']);
            end
            
            % Call xilUtilsHandleWarning or xilUtilsHandleError
            this.writer.wLine('xilUtilsHandle%s(%s, %d , rhs );', ...
                diagnosticType, this.XILUtilsVarName, numRHS);

            % Clean up all arrays created by mxCreate methods
            for i = 1:numRHS
                index = i - 1;
                this.writer.writeLine('mxDestroyArray(rhs[%d]);', index);
            end
            if isempty(diagnosticReturn)
                this.writer.wComment('continue');
            else
                % exit the calling function correctly
                this.writer.writeLine(diagnosticReturn);
            end
            this.writer.wBlockEnd();
        end

        
        function writeSectionInitializeSizesBodyInportsAndOutports(this) %#ok<MANU>
            % template method to be overridden in subclass
        end 
        
          
        function writeSectionInitializeSizesDWorks(this) %#ok<MANU>
                % template method to be overridden in subclass
        end
        
        function skipTask = skipExplicitTaskingTaskInExportFunctions(this, task)
            % the explicit tasking code is generated in entry functions.
            % There's no need to regenerate them into step body.
            skipTask = this.codeInfoUtils.isExportFunctions && ...
                strcmp(task.codeInfoData.Timing.TaskingMode, 'EXPLICIT_TASKING') && ...
                ~this.HasExplicitPartitions;
        end
        
        function writeRuntimeChecks(this) %#ok<MANU>
            % template method to be overridden in subclass
        end

        function registerCoderArrayType(this, dataInterface)
            % register dynamic type, this will give us the container type
            % ID to use in the serializer/deserializer
            
            % get data type ID for contained type
            implementation = dataInterface.Implementation;
            highType = implementation.Type;
            highType = rtw.connectivity.CodeInfoTypeUtils.getBaseTypeFromMatrixOrPointer(highType);
            if highType.isComplex()
                highType = highType.BaseType;
            end
            this.writer.wLine('DTypeId dataTypeIdReg = ssGetDataTypeId(S, "%s");', highType.Name);
            % construct dimensions string
            dims = dataInterface.Type.Dimensions;
            ndims = length(dims);
            dimsCell = cell(ndims,1);
            for idx = 1 : ndims
                if (isinf(dims(idx)))
                    dimsCell{idx} = 'SS_INT32_INF_DIM';
                else
                    dimsCell{idx} = num2str(dims(idx));
                end
            end
            dimsStr = strjoin(dimsCell, ', ');
            dimsStr = strcat('{', dimsStr, '}');
            % register the dynamic type
            regFcnCallStr = 'ssRegisterDynamicArrayDataType';
            this.writer.wLine('DTypeId dynmatContainedDataTypeId = dataTypeIdReg;');
            this.writer.wLine('int_T dynmatContainedDataDims[%d] = %s;', ndims, dimsStr);
            this.writer.wLine('DTypeId dtId = %s(S, dynmatContainedDataTypeId, %d, &dynmatContainedDataDims[0], %d);',...
                regFcnCallStr, ndims, rtw.connectivity.CodeInfoUtils.isCoderArrayDataComplex(implementation.CodeType));
            this.writer.wLine('if(dtId == INVALID_DTYPE_ID) return%s;', this.ReturnArgString);
        end

        % transfer Simulink input data into mxArrays ready for passing to
        % MATLAB
        function writeSectionPILIOCommandProcessHostToTargetData(this, ...
                dataInterfaces, ...
                taskId)
            if ~isempty(dataInterfaces)
                for dataInterface = dataInterfaces
                    sfunIdx = this.getSfunIdxForDataInterface(dataInterface);
                    isImageLoop = false;
                    if dataInterface.IsImageInterface && dataInterface.getType().isMatrix
                        isImageLoop = true;
                        loopSize = prod(dataInterface.getType.Dimensions);
                        this.writer.wBlockStart('for (int elemIdx = 0; elemIdx < %d; elemIdx++)', loopSize);
                    else
                        this.writer.wBlockStart('');
                    end
                    % initialize the dataInterface pointer
                    isHostToTarget = true;
                    this.writeSectionDataInterfacePtr(dataInterface, sfunIdx, isHostToTarget);

                    lNeedToTransformThisDataInterface = ...
                        this.IsRowMajorTransformNeededForThisDataInterface(dataInterface);
                    if lNeedToTransformThisDataInterface
                        % row major transpose
                        this.writeSectionRowMajorInputTranspose(dataInterface, sfunIdx);
                    end

                    rtwDataInterface = dataInterface.getRTWDataInterface();
                    implementation = rtwDataInterface.Implementation;
                    if rtw.connectivity.CodeInfoUtils.shouldUseOpaqueRegion(implementation) && ...
                            rtw.connectivity.CodeInfoUtils.isCoderArray(implementation) && ...
                            this.supportsCoderArray()
                        isHostToTarget = true;
                        this.writeOpaqueRegionSerDeserForCoderArray(rtwDataInterface, isHostToTarget);
                    elseif rtw.connectivity.CodeInfoUtils.isParameterizedLUTImplementation(implementation)
                        this.writeSectionCustomLUTSerializer(implementation);
                    else

                        dataElements = dataInterface.getHostDataElements();
                        for i = 1:length(dataElements)
                            dataElement = dataElements(i);
                            if(this.IsMexTarget || ~dataElement.SkipForCommonAncestorProcessing)
                                storageId = dataElement.getDtypeId;
                                numElements = dataElement.getSymbolicNumElements;
                                if isImageLoop
                                    numElements = sprintf('%d', dataElement.ImageSize);
                                end
                                if dataElement.IsImage
                                    underlyingType = rtw.connectivity.TypeUtils.OpaqueImageTypeGetUnderlyingType(dataElement.getType);
                                    simulinkCType = rtw.connectivity.TypeUtils.builtinToHostCType(underlyingType);
                                    storageId = rtw.connectivity.TypeUtils.getStorageIdFromCType(underlyingType);
                                else
                                    simulinkCType = rtw.connectivity.TypeUtils.builtinToHostCType(storageId);
                                end
                                % shared code for buses
                                this.writeSectionProcessDataElementHeader(dataElement, ...
                                    simulinkCType, ...
                                    taskId);

                                outbound = true;
                                hostPtr = 'simDataMemUnitPtr';
                                tgtPtr = 'mxMemUnitPtr';
                                numElementsVar = 'num_elements';
                                this.writer.wBlockStart(''); % New scope required for Windows compiler
                                this.writeSectionNumElementsForCopyData(dataElement, numElementsVar, numElements);
                                this.writeSectionPILIOCommandCopyData...
                                    (storageId, hostPtr, tgtPtr,...
                                    dataElement.getDataInterface.IsProtocolData, outbound,...
                                    dataElement);
                                this.writer.wBlockEnd;
                                % shared code for buses
                                this.writeSectionProcessDataElementTrailer(dataElement);
                            end
                        end
                    end
                    this.writer.wBlockEnd; %Empty or for elemIdx
                end
            end
        end

        function numMemUnits = addMemUnitsForTaskCounterOffsets(~, numMemUnits)
            % no-op implementation
        end

        function writeSectionTransferTaskCounterOffsets(~, ~)
            % No-op implementation
        end
   
    end

    methods (Static, Access=private)  
        
        function [infoName, apiName, mexFileName] = generateInterfaceFileNames(fcnName)
            fcnPrefix = sprintf('_coder_%s', fcnName);
            infoName = sprintf('%s_info', fcnPrefix);
            apiName = sprintf('%s_api', fcnPrefix);
            mexFileName = sprintf('%s_mex', fcnPrefix);
        end
                
        function name = getServerFunctionWrapperName(codeInfoOutputFunction)
            name = sprintf('mServerSubsystem_%s_sf', codeInfoOutputFunction.Prototype.Name);
        end
        
        function escapedString = escapeCString(plainString)
            % escape input string for use as a C string
            %
            % escape \'s, e.g. \ -> \\, \n -> \\n
            escapedString = strrep(plainString, '\', '\\');
            % escape "'s
            escapedString = strrep(escapedString, '"', '\"');
            % escape ?'s
            escapedString = strrep(escapedString, '?', '\?');
        end
        
        function [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                addMemoryUnits(totalH2TBufferMemUnits, ...
                               totalSymbolicH2TBufferMemUnits, ...
                               numMemUnits, numSymbolicMemUnits)
            if Inf == numMemUnits
               if isempty(totalSymbolicH2TBufferMemUnits)
                   totalSymbolicH2TBufferMemUnits = numSymbolicMemUnits;
               else
                   totalSymbolicH2TBufferMemUnits = ...
                       sprintf('%s + %s', totalSymbolicH2TBufferMemUnits, numSymbolicMemUnits);
               end                   
           else
               totalH2TBufferMemUnits = totalH2TBufferMemUnits + numMemUnits;
           end
           
        end
        
                
        function needToTransformThisType = IsRowMajorTransformNeededForThisType(types)
            
            arguments
                types (1,:) coder.descriptor.types.Type
            end
            
            numTypes = length(types);
            needToTransformThisType = false(1, numTypes);
            for idx = 1:numTypes
                symbolicDims = rtw.connectivity.CodeInfoTypeUtils.getSymbolicDimensions(types(idx));
                nDims = length(symbolicDims);
                
                needToTransformThisType(idx) = ...
                    rtw.connectivity.CodeInfoTypeUtils.isBusOrStruct(types(idx)) || (nDims ~= 1);
            end
        end

        function charOut = boolToChar(boolIn)
            if boolIn
                charOut = 'true';
            else
                charOut = 'false';
            end
        end
        
        function isSupported = supportsCoderArray()
            isSupported = slfeature('SLDynamicArrays') && ...
                matlab.internal.feature("XILDynamicArrays");
        end
    end

    methods (Static)                                                    
        function validateBooleanRemapping(platformDataTypes, diString)
            % Check boolean is not remapped to anything with size greater
            % than the smallest integer word length. This is not supported
            % because it breaks assumptions about equality of host/target
            % datatype size
            %
            % static function to ease unit testing

            if platformDataTypes.Size==0
                % Might not be defined for a MATLAB Coder or previous release workflow
                return
            end

            % Determine the boolean replacement base type, if any
            platformTypesArray = platformDataTypes.toArray;
            booleanIdx = strcmp({platformTypesArray.Name}, 'boolean');
            assert(sum(booleanIdx)==1, ...
                   'The boolean type must be defined once and once only')
            booleanType = platformTypesArray(booleanIdx);
            booleanBaseType = booleanType.ReplacementBaseType;

            if ~isempty(booleanBaseType)
                % Determine allowed base types (container size must be
                % equal to the word size of the smallest integer type)
                integerWordLengths = [platformTypesArray.FixedWidthIntegerWordLen];
                integerWordLengths = integerWordLengths(integerWordLengths~=0);
                smallestIntegerWordLength = min(integerWordLengths);
                allowedBaseTypeWordLengths = [8 16 32 64];
                allowedBaseTypeWordLengths = allowedBaseTypeWordLengths...
                    (allowedBaseTypeWordLengths<=smallestIntegerWordLength);
                allowedBaseTypes = [ ...
                    "boolean" ...
                    "int" + allowedBaseTypeWordLengths ...
                    "uint" + allowedBaseTypeWordLengths ...
                    ];

                if ~any(strcmp(booleanBaseType, allowedBaseTypes))
                    rtw.pil.ProductInfo.error('pil', ...
                        'BooleanRemapInvalidType', ...
                        booleanType.Symbol, ...
                        diString, ...
                        booleanBaseType, ...
                        join(allowedBaseTypes, ', '));
                end
            end
        end                        
    end
    
    methods (Access = 'private') 
               
               
        function isVerbose = isVerbose(this)
            isVerbose = this.SILPILWrapperUtils.getComponentArgs().getVerboseCommunicationOutput();
        end
        
        function writeLoggingFlag(this, status)
            % modify logging flag
            if ~isempty(this.SILPILWrapperUtils.getLoggingData)
                this.writer.wBlockStart('');
                isLoggingActiveVarName = 'isLoggingActive';
                this.getPWorkValue('boolean_T', isLoggingActiveVarName, this.getIsLoggingActiveIdx, true);
                if status
                    this.writer.wLine('*%s = true;', isLoggingActiveVarName);
                else
                    this.writer.wLine('*%s = false;', isLoggingActiveVarName);
                end
                this.writer.wBlockEnd;
            end
        end
        
        % define pointer to the top-level data interface
        function writeSectionDataInterfacePtr(this, dataInterface, sfunIdx, isHostToTarget)
            if isa(dataInterface, 'rtw.pil.CodeInfoData')                
                % initialize dataInterfacePtr
                dataInterfaceType = dataInterface.getDataInterfaceType;
                this.writer.wComment(sprintf('DataInterface: %s, %u', ...
                    dataInterfaceType, ...
                    dataInterface.getDataInterfaceIdx));
                if ismember(dataInterfaceType, {'input','output'})
                    accessMethodEnd = '';
                    ssAccessMethodMidfix = '';
                    if dataInterface.IsImageInterface
                        
                        ssAccessMethodSuffix = 'ImageData';
                        if dataInterface.getType().isMatrix
                            ssAccessMethodMidfix = 'NonScalar';
                            accessMethodEnd = ', elemIdx';
                        end
                    else
                        ssAccessMethodSuffix = 'Signal';
                    end
                end
                switch dataInterfaceType
                    case 'input'
                        this.writer.wLine('void * dataInterfacePtr = (void *) ssGet%sInputPort%s(S, %s%s);', ...
                            ssAccessMethodMidfix, ssAccessMethodSuffix, sfunIdx, accessMethodEnd);
                    case 'output'                        
                        this.writer.wLine('void * dataInterfacePtr = (void *) ssGet%sOutputPort%s(S, %s%s);', ...
                            ssAccessMethodMidfix, ssAccessMethodSuffix, sfunIdx, accessMethodEnd);
                    case {'dsread', 'dswrite', 'sharedLocalDataStore'}
                        dataInterface = dataInterface.getRTWDataInterface;
                        pWorkIdx = this.getSharedDataStorePWorkIdx(dataInterface);
                        this.getPWorkValue('void', 'dataInterfacePtr', pWorkIdx, true);
                    case 'parameter'                        
                        this.writer.wLine('void * dataInterfacePtr;');
                        this.writeSectionGetParameterDataInterfacePtr(dataInterface, sfunIdx);
                    case {'siglog', 'statelog'}
                        pWorkIdx = this.getLoggingTmpVarPWorkIdx(dataInterface);
                        this.getPWorkValue('void', 'dataInterfacePtr', pWorkIdx, true);
                    case {'inputsize', 'outputsize'}
                        % no data interface level processing for variable
                        % size information - see
                        % writeSectionPILIOCommandGetSimDataPtr in
                        % ModelBlockSfunction
                    case {'serverFcnInputArg', 'serverFcnOutputArg', 'serverFcnInputOutputArg'}
                        execArgsVarName = rtw.pil.Sfunction.SvrExecArgsVarName;
                        argIdx = dataInterface.getSlArgPosition - 1; % 0-based index
                        switch dataInterfaceType
                            case 'serverFcnInputArg'
                                argsVarName = rtw.pil.Sfunction.SvrInArgsVarName;
                            case 'serverFcnOutputArg'
                                argsVarName = rtw.pil.Sfunction.SvrOutArgsVarName;
                            case 'serverFcnInputOutputArg'
                                if isHostToTarget
                                    argsVarName = rtw.pil.Sfunction.SvrInArgsVarName;
                                    argIdx = argIdx(1);
                                else                                    
                                    argsVarName = rtw.pil.Sfunction.SvrOutArgsVarName;
                                    argIdx = argIdx(2);
                                end
                            otherwise
                                assert(false, 'Unrecognized dataInterfaceType: %s.', dataInterfaceType);
                        end
                        this.writer.wLine('void * dataInterfacePtr = ( void *) (%s->%s[%d].dataPtr);',...
                            execArgsVarName, argsVarName, argIdx);
                    case {'callerFcnInputArg', 'callerFcnOutputArg', 'callerFcnInputOutputArg'}
                        argIdx = dataInterface.getSlArgPosition - 1; % 0-based index
                        fcnInfo = dataInterface.getFunctionInfo;
                        totalNumInArgs = fcnInfo.getSLTotalNumInArgs();
                        
                        % NOTE: Using slcsInvokeSimulinkFunction we now need to pack
                        % inputs and outputs into one argument list. That list is
                        % ordered Inputs and then Outputs. In/Out arguments are listed
                        % in both lists in position, so will appear twice.
                        % the argument index returned above returns a scalar value for
                        % inputs and outputs, but a 2 element array for input/output
                        % arguments. The first element is the input index, the second
                        % argument is the output. So we need to add these two arguments
                        % in correctly. For ALL outputs (output and out version of
                        % in/out) we take the returned index and then offset that value
                        % by the TOTAL number of inputs (inputs and in versions of
                        % in/out).
                        argsVarName = rtw.pil.Sfunction.SvrFcnInvokeArgName;
                        switch dataInterfaceType
                            case 'callerFcnInputArg'
                            case 'callerFcnOutputArg'
                                argIdx = argIdx + totalNumInArgs; %Add outputs after inputs
                            case 'callerFcnInputOutputArg'
                                if isHostToTarget
                                    argIdx = argIdx(2) + totalNumInArgs; %Add outputs after inputs
                                else                                    
                                    argIdx = argIdx(1);
                                end
                            otherwise
                                assert(false, 'Unrecognized dataInterfaceType: %s.', dataInterfaceType);
                        end
                        this.writer.wLine('void * dataInterfacePtr = ( void *) (%s[%d].dataPtr);',...
                            argsVarName, argIdx);
                    case {'queuedFcnInputArg'}
                        argsVarName = rtw.pil.Sfunction.SvrFcnInvokeArgName;
                        this.writer.wLine('void * dataInterfacePtr = ( void *) (%s);',...
                            argsVarName);
                    case {'queuedFcnOutputArg'}
                        argIdx = dataInterface.getDataInterfaceIdx;
                        if (argIdx == 0)
                            %Return arg so use known name
                            argsVarName = '&returnArg';
                        else
                            argsVarName = rtw.pil.Sfunction.SvrFcnInvokeArgName;
                        end                        
                        this.writer.wLine('void * dataInterfacePtr = ( void *) (%s);',...
                            argsVarName);
                    case {'internal'}
                        tmpVar = dataInterface.getRTWDataInterfaceImplementation.OpaqueRegion.RuntimeResourcesDefinition;
                        % See design for Timer Service, but SIL can't
                        % properly use host side Opaque Regions yet. So
                        % instead use data captured in the Opaque Region to
                        % get the needed code to get the Time.
                        tmpPieces = strsplit(tmpVar, newline);
                        % Extract variable name to transfer the time
                        varName=regexp(tmpPieces{2},'xilHost\w+\(S, &(\w+)\);$','tokens');
                        this.writer.wLine('%s', tmpPieces{1});
                        this.writer.wLine('void * dataInterfacePtr = ( void *) (&%s);',varName{1}{:});

                    otherwise
                        assert(false, 'Unexpected dataInterfaceType: %s', dataInterfaceType);
                end
            end
        end
        
        function writeSectionRowMajorTranspose(this, ...
                info)
            % call utility to transpose a whole data interface
            this.writer.wLine(['dataInterfacePtr = xilSimulinkUtilsTranspose(%s, ' ...
                '%s, ' ...
                'dataInterfacePtr, ' ...
                '%s, ' ...
                '%s, ' ...
                '%u, ' ...
                '%s, ' ...
                '%u);'], ...
                this.XILUtilsVarName, ...
                info.dataTypeIdVar, ...
                info.dstPtr, ...
                info.dimsVar, ...
                info.nDims, ...
                info.direction, ...
                info.complex);
        end
                
        function writeSectionRowMajorOutputTranspose(this, dataInterface, sfunIdx)
            % row2col major transposes
            if isa(dataInterface, 'rtw.pil.CodeInfoData')                
                % transpose the data interface
                dataInterfaceType = dataInterface.getDataInterfaceType;
                isVarSizeOutput = false;
                switch dataInterfaceType
                    case 'output'
                        % Specifying dataInterfacePtr twice specifies
                        % in-place transform.   % TODO: Optimize.
                        dstPtr = 'dataInterfacePtr';
                        isVarSizeOutput = this.codeInfoUtils.isOutportVarSize(dataInterface.getRTWDataInterface);   
                    case {'dswrite', ...
                          'sharedLocalDataStore', ...
                          'siglog', ...
                          'statelog', ...
                          'serverFcnOutputArg', ...
                          'serverFcnInputOutputArg', ...
                          'callerFcnInputArg', ...
                          'callerFcnInputOutputArg'}
                        % Specifying dataInterfacePtr twice specifies
                        % in-place transform.   % TODO: Optimize
                        dstPtr = 'dataInterfacePtr';
                    case 'outputsize'
                        % no transpose required for variable size
                        % dimensions data since it is a vector not an
                        % array.   Additionally, although it can be part of
                        % a struct, it can never be an array of structs
                        % scenario; this is not supported.
                        return;
                    otherwise
                        assert(false, 'Unknown dataInterfaceType: %s', dataInterfaceType);
                end
                this.writer.wBlockStart('');
                % TODO: push higher up so we don't keep creating this
                % variable
                this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
                info = this.writeRowMajorTransposeDataInterfaceInfo(dataInterface);
                if isVarSizeOutput
                    % update dims with current size
                    isInput = false;
                    this.writeRowMajorTransposeUpdateDimensions(info, dataInterface, sfunIdx, isInput);
                end                
                info.direction = 'ROW_TO_COLUMN_TRANSPOSE';                
                info.dstPtr = dstPtr;
                this.writeSectionRowMajorTranspose(info);
                this.writer.wBlockEnd;
            end
        end                  
        
        function writeSectionRowMajorInputTranspose(this, dataInterface, sfunIdx)
            % col2row major transposes
            if isa(dataInterface, 'rtw.pil.CodeInfoData')                                
                % transpose the data interface
                dataInterfaceType = dataInterface.getDataInterfaceType;
                isVarSizeInput = false;
                switch dataInterfaceType
                    case 'input' 
                        % Input data must be treated as read-only.
                        % NULL dstPtr means a temporary buffer is returned and
                        % assigned to dataInterfacePtr
                        dstPtr = 'NULL';
                        isVarSizeInput = this.codeInfoUtils.isInportVarSize(dataInterface.getRTWDataInterface);
                    case {'parameter', 'serverFcnInputArg'}
                        % Input data must be treated as read-only.
                        % NULL dstPtr means a temporary buffer is returned and
                        % assigned to dataInterfacePtr
                        dstPtr = 'NULL';
                    case {'dsread', 'serverFcnInputOutputArg','callerFcnOutputArg', 'callerFcnInputOutputArg'}
                        % Specifying dataInterfacePtr twice specifies
                        % in-place transform.   % TODO: Optimize
                        dstPtr = 'dataInterfacePtr';
                    case {'outputsize', 'inputsize'}
                        % no transpose required for variable size
                        % dimensions data since it is a vector not an
                        % array.   Additionally, although it can be part of
                        % a struct, it can never be an array of structs
                        % scenario; this is not supported.
                        return;
                    otherwise
                        assert(false, 'Unknown dataInterfaceType: %s', dataInterfaceType);
                end
                this.writer.wBlockStart('');                                                
                % TODO: push higher up so we don't keep creating this
                % variable
                this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);                
                info = this.writeRowMajorTransposeDataInterfaceInfo(dataInterface);
                if isVarSizeInput
                    % update dims with current size
                    isInput = true;
                    this.writeRowMajorTransposeUpdateDimensions(info, dataInterface, sfunIdx, isInput);                    
                end
                info.direction = 'COLUMN_TO_ROW_TRANSPOSE';
                info.dstPtr = dstPtr;
                this.writeSectionRowMajorTranspose(info);
                this.writer.wBlockEnd;
            end
        end
        
        function info = writeRowMajorTransposeDataInterfaceInfo(this, dataInterface)
            % return struct containing data required as input arguments to
            % the row major transpose
            info.dataTypeIdVar = 'dataTypeId';
            this.writer.writeLine('DTypeId %s = INVALID_DTYPE_ID;', info.dataTypeIdVar);
            type = dataInterface.getHostType;
            symbolicDims = rtw.connectivity.CodeInfoTypeUtils.getSymbolicDimensions(type);
            info.dimsVar = 'rowMajorDims';
            info.nDims = length(symbolicDims);
            this.writeSymbolicDimsVarInitialization(symbolicDims, info.dimsVar);

            if rtw.connectivity.CodeInfoTypeUtils.isComplex(type)
                info.complex = true;
            else
                info.complex = false;
            end
            if rtw.connectivity.CodeInfoTypeUtils.isBusOrStruct(type)
                structType = rtw.connectivity.CodeInfoTypeUtils.getBaseType(type);
                this.writer.wLine('dataTypeId = ssGetDataTypeId(S, "%s");', structType.Identifier);
            else
                % storage datatype id is sufficient for builtin, fixed-point and enum
                % (int32)                
                storageId = rtw.connectivity.CodeInfoTypeUtils.getCodeInfoStoredValueDTypeId(type);
                if (storageId == rtw.connectivity.CodeInfoTypeEnum.TypeInt64) || ...
                        (storageId == rtw.connectivity.CodeInfoTypeEnum.TypeUInt64)
                   % no mapping to built in type id; use type name
                   baseType = rtw.connectivity.CodeInfoTypeUtils.getBaseType(type);
                   this.writer.wLine('dataTypeId = ssGetDataTypeId(S, "%s");', baseType.Name);
                elseif storageId == rtw.connectivity.CodeInfoTypeEnum.TypeHalf                    
                    this.writer.wLine('dataTypeId = ssRegisterDataTypeHalfPrecision(%s, 0);', ...
                        this.CodeFunctionArgs);
                else
                   storageId = this.SILPILWrapperUtils.getTypeUtils.builtinTypeToTypeId(rtw.connectivity.TypeUtils.codeInfoTypeIdToType(storageId));
                   this.writer.wLine('dataTypeId = %d;', storageId); 
                end                                
            end
        end
        
        function writeRowMajorTransposeUpdateDimensions(this, info, dataInterface, sfunIdx, isInput)
            % update dims with current size
            %
            % for var size, at the data interface level, if we have a bus it must
            % be scalar therefore no update of dimensions is
            % required prior to transpose                        
            type = dataInterface.getHostType;
            if ~rtw.connectivity.CodeInfoTypeUtils.isBusOrStruct(type)
                elementOffset = 0;                
                dimsAddress = sprintf('&%s[0]', info.dimsVar);                
                if isInput
                    direction = 'VARSIZE_GET_INPUT';
                else
                    direction = 'VARSIZE_GET_OUTPUT';
                end                
                % dimsVar is an int array
                type = 'VARSIZE_TYPE_32BIT';               
                this.writer.wLine('xilGetSetCurrentPortDims(S, %s, %s, %d, %d, (void *) %s, %s);', ...
                    direction, ...
                    sfunIdx, ...
                    elementOffset, ...
                    info.nDims, ...
                    dimsAddress, ...
                    type);                
            end            
        end

        function callMATLAB(this, numLHS, numRHS, functionName, errorReturn)
                                    
            assert(ischar(errorReturn), 'errorReturn must be char');            
            assert(ischar(functionName ), 'functionName  must be char');            
            assert(numLHS >= 0, 'numLHS should be greater or equal to zero');            
            assert(numRHS  >= 0, 'numRHS  should be greater or equal to zero');
            
            if numLHS~=0
                callMATLABStr = sprintf('xilUtilsCallMATLAB(%s, %d, lhs, %d, rhs, "%s")', ...
                    this.XILUtilsVarName, numLHS, numRHS, functionName);
            else
                callMATLABStr = sprintf('xilUtilsCallMATLAB(%s, %d, 0, %d, rhs, "%s")', ...
                    this.XILUtilsVarName, numLHS, numRHS, functionName);
            end            
            % Get XILUtils for xilUtilsCallMATLAB
            this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
            
            this.writer.wBlockStart('if (%s!=XIL_UTILS_SUCCESS)', callMATLABStr);
            
            if this.IsMexTarget
                % MATLAB Coder use-case, xilUtilsCallMATLAB implementation
                % in C++ will capture errors that may occur while
                % calling functionName.
                % Explicitly call xilThrowException, this will force the
                % mex to terminate and then call the function which is
                % registered with mexAtExit (in this case the terminate method)
                this.writeSectionProcessException();
            end
            
            % Simulink Coder use-case. Report if an error occurred.
            % xilUtilsCallMATLAB will simply post the error on the
            % SimStruct but not throw.
            this.writer.wLine('%s', errorReturn);
            this.writer.wBlockEnd;
                
        end
        
        function initIsNeededMemUnitXform(this)     
           lTypesWithDiffWordOrderEnumVals = this.getTypesWithDiffWordOrder;

           this.IsNeededMemUnitXform = ~(this.isLittleEndian) || ...
               ~(this.SILPILWrapperUtils.getTargetServices().getDataTypeService().getIsByteAddressable()) || ...
               ~isempty(lTypesWithDiffWordOrderEnumVals);
        end
        
        function writeVariableDeclaration(this, typeName, name, size)
            if size > 0
                this.writer.wLine('%s %s[%d];', typeName, name, size);
            else
                this.writer.wLine('%s *%s = NULL;', typeName, name);
            end
        end
            
       % helper function to get rtw.pil.CodeInfoData's for a set of data interfaces       
       % the total number of memunits is also returned
       function [dataInterfaces, numMemUnits, numSymbolicMemUnits] = ...
               getDataInterfaces(this, indices, dataInterfaceType)  
           
           numMemUnits = 0;
           numSymbolicMemUnits = '0';
           dataInterfaces = rtw.pil.CodeInfoData.empty;
           if isempty(indices)
               return;
           end
           [elements, dataInterfaces] = rtw.pil.CodeInfoData.createHostDataElements(this.SILPILWrapperUtils, indices, dataInterfaceType);
           numMemUnits = elements.getTotalMemUnitSize(this.SILPILWrapperUtils.getMemUnitInfo.memUnitBytes);
           numSymbolicMemUnits = sprintf('(%s)', ...
               elements.getTotalMemUnitSymbolicSize(this.SILPILWrapperUtils.getMemUnitInfo.memUnitBytes));
       end
       
       function [totalH2TBufferMemUnits,...
                 totalSymbolicH2TBufferMemUnits, ...
                 commandData,...
                 allInportData,...
                 allInportSizesData,...
                 allOutportSizesData,...
                 allParamData,...
                 allDSReadData,...
                 allServerFcnInputArgsData, ...
                 allInternalData, ...
                 commandDataSize] =...
                      getAllHostToTargetDataInterfaces(this,...
                                                                   PILCommand,...
                                                                   inportIndices, ...
                                                                   inportSizesIndices, ...
                                                                   outportSizesIndices, ...
                                                                   paramIndices, ...
                                                                   dsReadIndices, ...
                                                                   serverFcnIndex, ...
                                                                   taskTiming)
           % bundle inputs, params and dsRead together as input data
           %
           % record the total udata buffer size for this command
           % note that Udata includes commandData
           totalH2TBufferMemUnits = 0;
           totalSymbolicH2TBufferMemUnits = '';
           
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
           
           % get the command data
           commandDataToProcess = this.getPILIOCommandDataToProcess(PILCommand);                          
           commandDataElements = rtw.pil.DataElement.empty;
           commandData = rtw.pil.CommandData.empty;
           for i=1:length(commandDataToProcess)
               newCommandData = this.SILPILWrapperUtils.getCommandData(commandDataToProcess{i});
               commandData = [commandData newCommandData]; %#ok<AGROW>
               commandDataElements = [commandDataElements newCommandData.getHostDataElements]; %#ok<AGROW>
           end
           numMemUnits = commandDataElements.getTotalMemUnitSize(memUnitInfo.memUnitBytes);

           if strcmp(PILCommand, 'XIL_INITIALIZE_COMMAND')
               numMemUnits = this.addMemUnitsForTaskCounterOffsets(numMemUnits);
           end
                                                             
           % note: command data is not part of numContiguousInputs but is
           % part of udata...           
           totalH2TBufferMemUnits = totalH2TBufferMemUnits + numMemUnits;
           
           % add 1 for command id
           totalH2TBufferMemUnits = totalH2TBufferMemUnits + 1;
           
           commandDataSize = int2str(totalH2TBufferMemUnits);
           
           if this.IsMexTarget
                % Clear data elements, these are processed by MATLAB Coder
                % functions.
                allInportData = [];
                allInportSizesData = [];
                allOutportSizesData = [];
                allParamData = [];
                allDSReadData = [];
                allServerFcnInputArgsData = [];
                allInternalData = [];
           else                     
               % get data for specified inports
               [allInportData, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(inportIndices, 'input');
               [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               [allInportSizesData, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(inportSizesIndices, ...
                   'inputsize');
               [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % NOTE: outport sizes are transferred both from the host to the
               % target and from the target to the host!
               [allOutportSizesData, numMemUnits,numSymbolicMemUnits] = ...
                   this.getDataInterfaces(outportSizesIndices, ...
                   'outputsize');
               [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % get data for specified parameters
               [allParamData, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(paramIndices, 'parameter');
               [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % get data for specified dsRead
               %
               [allDSReadData, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(dsReadIndices, 'dsread');
               [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);              

               % Calculate transfer interface
               internalDataInterfaceIndices = ...
                   this.TransferInterfaceUtils.getInternalDataToUpload(this.codeInfo, taskTiming);
               if ~strcmp(PILCommand, 'XIL_OUTPUT_COMMAND')
                   internalDataInterfaceIndices = [];
               end
               [~, allInternalData, numMemUnits, numSymbolicMemUnits] =  ...
                   this.TransferInterfaceUtils.getDataInterfaces(this.SILPILWrapperUtils, ...
                   internalDataInterfaceIndices, 'internal');
               [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % Get the server function input args data
               [allServerFcnInputArgsData, numMemUnits, ...
                   numSymbolicMemUnits] = this.getDataInterfaces( ...
                   serverFcnIndex, 'serverFcnInputArg');
               [totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalH2TBufferMemUnits, totalSymbolicH2TBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);
           end          

           if isempty(totalSymbolicH2TBufferMemUnits)
               totalSymbolicH2TBufferMemUnits = int2str(totalH2TBufferMemUnits);
           elseif 0 < totalH2TBufferMemUnits
               totalSymbolicH2TBufferMemUnits = ...
                   sprintf('%s + %d', totalSymbolicH2TBufferMemUnits, ...
                           totalH2TBufferMemUnits);
           end
       end
       
       function [allOutportData,...
                 allDSWriteData,...
                 sharedLocalDataStoreElements,...
                 signalLoggingData,...
                 stateLoggingData,...
                 allServerFcnOutputArgsData,...
                 totalT2HBufferMemUnits, ...
                 totalSymbolicT2HBufferMemUnits] =...
                    getAllTargetToHostDataInterfaces(this,...
                                                                   outportIndices, ...
                                                                   outportSizesIndices,...
                                                                   dsWriteIndices, ...
                                                                   sharedLocalDataStoreIndices, ...
                                                                   signalLoggingIndices, ...
                                                                   stateLoggingIndices, ...
                                                                   serverFcnIndex)                                                            
           % bundle outputs and dsWrite together as output data
           %
           % record the total ydata buffer size for this command
           totalT2HBufferMemUnits = 0;
           totalSymbolicT2HBufferMemUnits = '';
             
           if this.IsMexTarget
                % Clear data elements, these are processed by MATLAB Coder
                % functions.
                allOutportData = [];
                allDSWriteData = [];
                sharedLocalDataStoreElements = [];
                signalLoggingData = [];
                stateLoggingData = [];
                allServerFcnOutputArgsData = [];
           else              

               memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;

               % get data for specified outports
               [allOutportData, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(outportIndices, 'output');
               [totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % process outport sizes upload
               % NOTE: outport sizes are transferred both from the host to the
               % target and from the target to the host!
               [~, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(outportSizesIndices, ...
                   'outputsize');
               [totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % get data for specified dsWrite
               [allDSWriteData, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(dsWriteIndices, 'dswrite');
               [totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % get data for shared local data stores
               [sharedLocalDataStoreElements, numMemUnits, numSymbolicMemUnits] = ...
                   this.getDataInterfaces(sharedLocalDataStoreIndices, 'sharedLocalDataStore');
               [totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);

               % get the signal logging Data
               loggingData = this.SILPILWrapperUtils.getLoggingData;
               signalLoggingData = loggingData(signalLoggingIndices);
               signalLoggingDataToUpload = rtw.pil.LoggingUtils.filterUnneededBufferUpload(signalLoggingData);
               signalLoggingDataElements = rtw.pil.DataElement.empty;
               for i=1:length(signalLoggingDataToUpload)
                   signalLoggingDataElements = [signalLoggingDataElements signalLoggingDataToUpload(i).getHostDataElements]; %#ok<AGROW>
               end
               numMemUnits = signalLoggingDataElements.getTotalMemUnitSize(memUnitInfo.memUnitBytes);
               totalT2HBufferMemUnits = totalT2HBufferMemUnits + numMemUnits;

               % get the state logging Data
               stateLoggingData = loggingData(stateLoggingIndices);
               stateLoggingDataElements = rtw.pil.DataElement.empty;
               for i=1:length(stateLoggingData)
                   stateLoggingDataElements = [stateLoggingDataElements stateLoggingData(i).getHostDataElements]; %#ok<AGROW>
               end
               numMemUnits = stateLoggingDataElements.getTotalMemUnitSize(memUnitInfo.memUnitBytes);
               totalT2HBufferMemUnits = totalT2HBufferMemUnits + numMemUnits;

               % Get the server function output args data
               [allServerFcnOutputArgsData, numMemUnits, ...
                   numSymbolicMemUnits] = this.getDataInterfaces( ...
                   serverFcnIndex, 'serverFcnOutputArg');
               [totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits] = ...
                   rtw.pil.Sfunction.addMemoryUnits( ...
                   totalT2HBufferMemUnits, totalSymbolicT2HBufferMemUnits, ...
                   numMemUnits, numSymbolicMemUnits);
           end

           if isempty(totalSymbolicT2HBufferMemUnits)
               totalSymbolicT2HBufferMemUnits = int2str(totalT2HBufferMemUnits);
           elseif 0 < totalT2HBufferMemUnits
               totalSymbolicT2HBufferMemUnits = ...
                   sprintf('%s + %d', totalSymbolicT2HBufferMemUnits, ...
                           totalT2HBufferMemUnits);
           end
       end
           
             
       function writeSectionPILIOCommandProcessAllHostToTargetData(...
                                                   this,...
                                                   PILCommand,...
                                                   taskId,...
                                                   commandData,...
                                                   allInportData,...
                                                   allInportSizesData,...
                                                   allOutportSizesData,...
                                                   allParamData,...
                                                   allDSReadData,...
                                                   internalData, ...
                                                   allServerFcnInputArgsData)
           % process command data
           this.writeSectionPILIOCommandProcessHostToTargetData(commandData, taskId);

           if strcmp(PILCommand, 'XIL_INITIALIZE_COMMAND')
               this.writeSectionTransferTaskCounterOffsets(taskId);
           end

           % read data stores from Simulink into temp variables
           isRead = true;
           this.writeSectionReadWriteSharedDataStores(allDSReadData, isRead);

           % Sort all interfaces so that all the ones processed by
           % OpaqueRegion are written first. This is needed to match the
           % order data is read on the target (i.e. immediate 
           % de-serialization of data on the target)
           % In the future we need to across multiple interface type
           % combine Immediate de-serialization (Opaque Region) and
           % deferred (legacy transfer) items. If we use transfer utils
           % properly this will be easy.
           % Process internal first to keep in sync with target.
           allDataInterfaces = [internalData, ...
                               allInportData,...
                               allInportSizesData,...
                               allOutportSizesData,...
                               allParamData,...
                               allDSReadData,...
                               allServerFcnInputArgsData];
           plainInterfaces = rtw.pil.CodeInfoData.empty();
           opaqueInterfaces = rtw.pil.CodeInfoData.empty();
           for idx = 1:length(allDataInterfaces)
               if ~isempty(allDataInterfaces(idx))
               implementation = allDataInterfaces(idx).getRTWDataInterfaceImplementation();
                   if ~isempty(implementation) && ...
                           rtw.connectivity.CodeInfoUtils.shouldUseOpaqueRegion(implementation)
                       opaqueInterfaces(end+1) = allDataInterfaces(idx); %#ok<AGROW>
                   else
                       plainInterfaces(end+1) = allDataInterfaces(idx); %#ok<AGROW>
                   end
               end
           end
           allDataInterfaces = [opaqueInterfaces plainInterfaces];

           this.writeSectionPILIOCommandProcessHostToTargetData(allDataInterfaces, ...
               taskId);     
       end     
              
       % transfer mxArray output data from MATLAB to Simulink       
       function writeSectionPILIOCommandProcessTargetToHostData(this, ...
                                                          dataInterfaces, ...
                                                          taskId, ...
                                                          tgtPtr)                                                                                
           if ~isempty(dataInterfaces)                      
               for dataInterface = dataInterfaces
                   sfunIdx = this.getSfunIdxForDataInterface(dataInterface);
                   
                   isImageLoop = false;                   
                   if dataInterface.IsImageInterface && dataInterface.getType().isMatrix
                       isImageLoop = true;
                       loopSize = prod(dataInterface.getType().Dimensions);
                       this.writer.wBlockStart('for (int elemIdx = 0; elemIdx < %d; elemIdx++)', loopSize);
                   else
                       this.writer.wBlockStart('');
                   end
                   % initialize the dataInterface pointer
                   isHostToTarget = false;
                   this.writeSectionDataInterfacePtr(dataInterface, sfunIdx, isHostToTarget);
                   rtwDataInterface = dataInterface.getRTWDataInterface();
                   implementation = rtwDataInterface.Implementation;
                   if rtw.connectivity.CodeInfoUtils.shouldUseOpaqueRegion(implementation) && ...
                           rtw.connectivity.CodeInfoUtils.isCoderArray(implementation) && ...
                           this.supportsCoderArray()
                       isHostToTarget = false;
                       this.writeOpaqueRegionSerDeserForCoderArray(rtwDataInterface, isHostToTarget);
                   else
                       dataElements = dataInterface.getHostDataElements;
                       for  i = 1:length(dataElements)
                           dataElement = dataElements(i);
                           if(this.IsMexTarget || ~dataElement.SkipForCommonAncestorProcessing)
                               storageId = dataElement.getDtypeId;

                               numElements = dataInterface.getSymbolicNumElements(dataElement);
                               if dataElement.IsImage
                                   if isImageLoop
                                       numElements = sprintf('%d', dataElement.ImageSize);
                                   end
                                   underlyingType = rtw.connectivity.TypeUtils.OpaqueImageTypeGetUnderlyingType(dataElement.getType);
                                   simulinkCType = rtw.connectivity.TypeUtils.builtinToHostCType(underlyingType);
                                   storageId = rtw.connectivity.TypeUtils.getStorageIdFromCType(underlyingType);
                               else
                                   simulinkCType = rtw.connectivity.TypeUtils.builtinToHostCType(storageId);
                               end
                               % shared code for buses
                               this.writeSectionProcessDataElementHeader(dataElement, ...
                                   simulinkCType, ...
                                   taskId);

                               hostPtr = 'simDataMemUnitPtr';
                               outbound = false;
                               numElementsVar = 'num_elements';
                               this.writer.wBlockStart(''); % New scope required for Windows compiler
                               this.writeSectionNumElementsForCopyData(dataElement, numElementsVar, numElements);
                               this.writeSectionPILIOCommandCopyData...
                                   (storageId, hostPtr, tgtPtr,...
                                   dataElement.getDataInterface.IsProtocolData, outbound, ...
                                   dataElement);
                               this.writer.wBlockEnd;

                               % hook for post processing
                               this.writeSectionPILIOCommandPostProcessSimData(dataElement, ...
                                   sfunIdx, ...
                                   simulinkCType, ...
                                   taskId);

                               % shared code for buses
                               this.writeSectionProcessDataElementTrailer(dataElement);
                           end
                       end
                   end

                   lNeedToTransformThisDataInterface = ...
                       this.IsRowMajorTransformNeededForThisDataInterface(dataInterface);
                   if lNeedToTransformThisDataInterface
                       % row major transpose
                       this.writeSectionRowMajorOutputTranspose(dataInterface, sfunIdx);
                   end
                   this.writer.wBlockEnd;
               end
           end
       end 
 
       function writeSectionNumElementsForCopyData(this, dataElement, numElementsVar, numElements)
           
           getNumElementsInForLoop = true;
           if (~dataElement.isStructElement || this.IsMexTarget)
               % Non structure dataElement OR MATLAB coder target
               getNumElementsInForLoop = false;
           else
               % SimStruct APIs are unable to extract Complex data type size.
               % When Real and Imag parts have the same data type,  
               % cType can be directly used in the optimized for loop for complex data elements.
               [~, TypeIdentifier, IsComplex] = dataElement.getFinalStructElementOffset;
               if (dataElement.NumPrevSameAncestorElements==0 ||IsComplex)
                   getNumElementsInForLoop = false;
               end
           end
           
           if(getNumElementsInForLoop)
               this.writer.wLine('DTypeId dType = ssGetDataTypeId(S, "%s");', TypeIdentifier);
               this.writer.wLine('size_t %s;', numElementsVar);
               this.writer.wLine('const int_T * busElementsDims;');
               this.writer.wLine('int_T busElementNumDims;');              
               this.writer.wLine('DTypeId elemTypeId = ssGetBusElementDataType(S, dType, offsetIdx);');
               % Special branch for string element
               this.writer.wBlockStart('if (ssIsStringDataType(S, elemTypeId))');
               this.writer.wLine('%s = ssGetStringDataTypeBufferSize(%s elemTypeId);', numElementsVar, this.SimStructArg);
               % else branch
               this.writer.wBlockMiddle('else');
               this.writer.wLine('%s = getBusElementDimension(%s dType, offsetIdx, &busElementsDims, &busElementNumDims); ', numElementsVar, this.SimStructArg);
               this.writer.wBlockEnd; % else
           else
               this.writer.wLine('size_t %s = %s;', numElementsVar, numElements);
           end
       end
       
       function writeSectionPILIOCommandDefineResponseTypes(this,...
                                                        processResponseTypeSize)
                                                    
           % support response target_io.c packets
           if processResponseTypeSize
               this.writer.wLine('#define RESPONSE_TYPE_SIZE 8');
           end
           
           if this.codeInfoUtils.hasUndefinedCallerFunctions
               this.writer.wLine('#define RESPONSE_CS_REQUEST_SERVICE 9');
           end

       end
       
       function writeSectionPILIOCommandGrowIOBuffer(this, dataOutSize, errorReturn, isVerbose)
           % grow global IOBufferPtr if required
           this.getPWorkValue('void', 'pXILService', this.getXILServicePWorkIdx, true);
           this.writer.wBlockStart('if (pXILService != NULL)');           
           this.writer.wBlockStart('if (xilHostAppSvcGrowIOBuffer(pXILService, IOBufferPtr, %s, %d)!=XILHOSTAPPSVC_SUCCESS)',...
               dataOutSize, isVerbose);
           this.writeSectionProcessException;
           this.writer.writeLine(errorReturn);
           this.writer.wBlockEnd; %if (xilHostAppSvcGrowIOBuffer)           
       end
           
       function writeSectionPILIOCommandCommandDispatch(this, errorReturn)
           this.writer.wComment('dispatch command to the target')
           % use the running size captured in the IO Buffer Pointer as the
           % size of the command
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo();
           if memUnitInfo.supportsOnlyByteIO
               % byte I/O -  present data as bytes
               dataOutSize = 'IOBufferPtr->bufferDataSize';
           else
               % mem unit I/O - present data as mem units
               dataOutSize = sprintf('IOBufferPtr->bufferDataSize / %d', memUnitInfo.memUnitBytes);
           end
           this.writer.wBlockStart('if (commandDispatch(%sIOBufferPtr, %s)!=XILHOSTAPPSVC_SUCCESS)', ...
               this.SimStructArg, dataOutSize);
           if isempty(errorReturn)
               this.writer.wComment('continue');
           else
               this.writer.writeLine(errorReturn);
           end
           this.writer.wBlockEnd; % if commandDispatch
       end
       
       function writeSectionPILIOCommandWriteCommandId(this, command)
           % process command id
           this.writer.wComment('write command id');
           
               this.writer.wBlockStart('');
           memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
           memUnitCType = rtw.connectivity.TypeUtils.builtinToHostCType(memUnitInfo.memUnitType);
           this.writer.wLine('%s commandDataArg = (%s) %s;', memUnitCType, memUnitCType, command);
               
           isRead = false;
           skipMemUnitTransform = true;
           this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                '&commandDataArg', '1');
               
               this.writer.wBlockEnd();
           end

       function writeSectionPILIOCommandErrorAndTargetIOResponseCases(this, errorReturn)
           silpilInterface = this.SILPILWrapperUtils.getSILPILInterface;
           langExt = silpilInterface.getTargetExtension();
           this.writer.wLine('case RESPONSE_ERROR:');
           this.writer.wLine('case RESPONSE_PRINTF:');
           this.writer.wLine('case RESPONSE_FOPEN:');
           this.writer.wLine('case RESPONSE_FPRINTF:');
           if strcmp(langExt,'.cpp')
               this.writer.wLine('case RESPONSE_EXCEPTION:');
           end
           this.writer.wBlockStart('case RESPONSE_SIGNAL_RAISED:');
               this.writer.wBlockStart('if (processErrorAndTargetIOResponseCases(%s responseId)== XILHOSTAPPSVC_ERROR)', this.SimStructArg);
           this.writer.wLine(errorReturn);
           this.writer.wBlockEnd;
           this.writer.wLine('break;');
           this.writer.wBlockEnd;
       end
       
       function writeSectionPILIOCommandErrorAndTargetIOResponseFunction(this)
           
               processXFcnArgDef = sprintf('');
               processXFcnArg = '';
           
           this.writer.wBlockStart('static boolean_T processErrorAndTargetIOResponseCases(%s %s const int responseId%s)', this.SimStructType, this.SimStructArg, processXFcnArgDef);
           
           cachedSimStructArg = this.SimStructArg;
           if ~this.IsMexTarget
               this.SimStructArg = 'S';
           end
           this.writer.writeLine('boolean_T processResponseStatus;');
           this.writer.wBlockStart('switch (responseId)');
           caseResponseError = 'RESPONSE_ERROR';
           this.writer.wBlockStart('case %s:', caseResponseError); % response_error
           this.wLineVerboseString(caseResponseError);
           this.writer.writeLine('processResponseStatus = processResponseError(%s %s);',this.SimStructArg, processXFcnArg);
           this.writer.writeLine('break;');
           this.writer.wBlockEnd;
           caseResponsePrintf = 'RESPONSE_PRINTF';
           this.writer.wBlockStart('case %s:', caseResponsePrintf); % response_printf
           this.wLineVerboseString(caseResponsePrintf);
           this.writer.writeLine('processResponseStatus = processResponsePrintf(%s %s);',this.SimStructArg, processXFcnArg);
           this.writer.writeLine('break;');
           this.writer.wBlockEnd;
           caseResponseFopen = 'RESPONSE_FOPEN';
           this.writer.wBlockStart('case %s:', caseResponseFopen); % response_fopen
           this.wLineVerboseString(caseResponseFopen);
           this.writer.writeLine('processResponseStatus = processResponseFopen(%s %s);',this.SimStructArg, processXFcnArg);
           this.writer.writeLine('break;');
           this.writer.wBlockEnd;
           caseResponseFprintf = 'RESPONSE_FPRINTF';
           this.writer.wBlockStart('case %s:', caseResponseFprintf); % response_fprintf
           this.wLineVerboseString(caseResponseFprintf);
           this.writer.writeLine('processResponseStatus = processResponseFprintf(%s %s);',this.SimStructArg, processXFcnArg);
           this.writer.writeLine('break;');
           this.writer.wBlockEnd;
           caseResponseSignal = 'RESPONSE_SIGNAL_RAISED';
           this.writer.wBlockStart('case %s:', caseResponseSignal); % response_signal_raised
           this.wLineVerboseString(caseResponseSignal);
           this.writer.writeLine('processResponseStatus = processResponseSignalRaised(%s %s);',this.SimStructArg, processXFcnArg);
           this.writer.writeLine('break;');
           this.writer.wBlockEnd;
            
           silpilInterface = this.SILPILWrapperUtils.getSILPILInterface;
           langExt = silpilInterface.getTargetExtension();
           if strcmp(langExt,'.cpp')
               caseResponseException = 'RESPONSE_EXCEPTION';
               this.writer.wBlockStart('case %s:', caseResponseException); % response_exception
               this.wLineVerboseString(caseResponseException);
               this.writer.writeLine('processResponseStatus = processResponseException(%s %s);',this.SimStructArg, processXFcnArg);
               this.writer.writeLine('break;');
               this.writer.wBlockEnd;
           end
           
           this.writer.wBlockStart('default:');           
           errorReturn = 'processResponseStatus = XILHOSTAPPSVC_ERROR;';                      
           this.writeError(errorReturn,...
                            'PIL:pilverification:UnknownResponseId',...
                            'mxCreateDoubleScalar(responseId)');
           this.writer.wBlockEnd;
           this.writer.wBlockEnd; % switch responseId

           this.writer.wBlockStart('if (processResponseStatus == XILHOSTAPPSVC_ERROR)');
           this.writer.wLine('callStopHookAndFreeSFcnMemory(%s);',...
               this.SimStructArgSingle);
           this.writer.wBlockEnd; % if block
           this.writer.writeLine('return processResponseStatus;');

           this.writer.wBlockEnd; % static processResponses
           this.SimStructArg = cachedSimStructArg;
       end
        
        %writeSectionPILIOCommandErrorResponseFunction
        function writeSectionPILIOCommandErrorResponseFunction(this, mxCTypeMemUnit)
                        
                this.writer.wBlockStart('static boolean_T processResponseError(%s %s)', this.SimStructType, this.SimStructArg);
                this.writer.wLine('%s errorId;', mxCTypeMemUnit);
                
            isRead = true;
            skipMemUnitTransform = true;
            this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                           '&errorId', '1');
            
            this.writer.wBlockStart('if (errorId)');
            errorReturn = 'return XILHOSTAPPSVC_ERROR;';
            % throw error
            this.writeError(errorReturn,...
                'PIL:pilverification:PILError', ...
                'mxCreateDoubleScalar(errorId)');
            this.writer.wBlockEnd; % if (errorId)
            this.writer.writeLine('return XILHOSTAPPSVC_SUCCESS;');
            this.writer.wBlockEnd; % static processResponseError
        end
        
        
        function writeSectionPILIOCommandPrintfResponseFunction(this, taskId, isVerbose)
                this.writer.wBlockStart('static boolean_T processResponsePrintf(%s %s)', this.SimStructType, this.SimStructArg);
            this.writer.writeLine('const int TARGET_IO_SUCCESS = 0;');
            % read in the error code
            printfError = this.SILPILWrapperUtils.getCommandData('PRINTF_ERROR');
            printfErrorDataElements = printfError.getHostDataElements;
            printfErrorName = printfError.getName;
            printfErrorHostCType = rtw.connectivity.TypeUtils.builtinToHostCType(printfErrorDataElements.getDtypeId);
            % define target buffer
            this.writer.writeLine([printfErrorHostCType ' ' printfErrorName ';']);
            
            % read in the printf data
            printfSize = this.SILPILWrapperUtils.getCommandData('PRINTF_SIZE');
            printfSizeDataElements = printfSize.getHostDataElements;
            printfSizeName = printfSize.getName;
            printfHostCType = rtw.connectivity.TypeUtils.builtinToHostCType(printfSizeDataElements.getDtypeId);
            % define target buffer
            this.writer.writeLine([printfHostCType ' ' printfSizeName ';']);
            
            tgtPtr = '*mxMemUnitPtrPtr';
            this.writeSectionPILIOCommandProcessTargetToHostData(printfError, ...
                taskId, tgtPtr);
            
            this.writeSectionPILIOCommandProcessTargetToHostData(printfSize, ...
                taskId, tgtPtr);
            
            if isVerbose
                this.writer.writeLine(['mexPrintf("RESPONSE_PRINTF, PRINTF_ERROR = %u, PRINTF_SIZE = %u\n", ' printfErrorName ', ' printfSizeName ');']);
            end
            
            % process error Id
            this.writer.wBlockStart('if (%s != TARGET_IO_SUCCESS)', printfErrorName);
            errorReturn = 'return XILHOSTAPPSVC_ERROR;';
            this.writeError(errorReturn, ...
                'PIL:pil:TargetIOError', ...
                ['mxCreateDoubleScalar(' printfErrorName ')']);
            
            this.writer.wBlockMiddle('else'); % if (%s != TARGET_IO_SUCCESS)'
            this.writer.writeLine('uint8_T *pPrintBuff;');
                this.writer.writeLine(['pPrintBuff = (uint8_T *) mxCalloc(' printfSizeName ', sizeof(uint8_T));']);
                this.writer.wBlockStart('if (pPrintBuff != NULL)');
                % process the data
            this.processTargetIOData('pPrintBuff', printfSizeName);
            % validate the string
                %
                % null termination char will stop mexPrintf
            this.writer.wBlockStart('if (pPrintBuff[%s-1] == %s)', printfSizeName, '''\0''');
            this.writer.writeLine('mexPrintf("%s", pPrintBuff);');
            this.writer.writeLine('mexEvalString("pause(0)");');    % required to flush the buffers to the MATLAB command line
            this.writer.wBlockEnd; % if (pPrintBuff[%s-1] == %s)', printfSizeName, '''\0'''
            
                this.writer.writeLine('mxFree(pPrintBuff);');
                this.writer.wBlockEnd; %if (pPrintBuff != NULL)
            this.writer.wBlockEnd; %if (%s != TARGET_IO_SUCCESS)'
            
            this.writer.writeLine('return XILHOSTAPPSVC_SUCCESS;');
            this.writer.wBlockEnd; % static response_printf
        end
    
        
        function writeSectionPILIOCommandFopenResponseFunction(this, taskId, isVerbose)
                this.writer.wBlockStart('static boolean_T processResponseFopen(%s %s)', this.SimStructType, this.SimStructArg);
            % read in the fopen options
            fopenFid = this.SILPILWrapperUtils.getCommandData('FOPEN_FID');            
            fopenFidName = fopenFid.getName;
            fopenFidDataElements = fopenFid.getHostDataElements;
            fopenFidHostCType = rtw.connectivity.TypeUtils.builtinToHostCType(fopenFidDataElements.getDtypeId);
            % define target buffer
            this.writer.writeLine([fopenFidHostCType ' ' fopenFidName ';']);
            % get the size of file name string
            fopenNameSize = this.SILPILWrapperUtils.getCommandData('FOPEN_NAME_SIZE');
            fopenNameSizeName = fopenNameSize.getName;
            fopenNameSizeDataElements = fopenNameSize.getHostDataElements;
            fopenNameSizeHostCtype = rtw.connectivity.TypeUtils.builtinToHostCType(fopenNameSizeDataElements.getDtypeId);
            % define target buffer
            this.writer.writeLine([fopenNameSizeHostCtype ' ' fopenNameSizeName ';']);
            
            if ~this.IsMexTarget
                % define targetIOFdPtr
                this.writer.wLine('targetIOFd_T *targetIOFdPtr;');
            end
            
            % process data
            tgtPtr = '*mxMemUnitPtrPtr';
            this.writeSectionPILIOCommandProcessTargetToHostData(fopenFid, ...
                taskId, tgtPtr);
            this.writeSectionPILIOCommandProcessTargetToHostData(fopenNameSize, ...
                taskId, tgtPtr);
            if isVerbose
                this.writer.writeLine(['mexPrintf("RESPONSE_FOPEN, FOPEN_FID = %u, FOPEN_NAME_SIZE = %u\n", ' fopenFidName ', ' fopenNameSizeName ');']);
            end
            this.getPWorkValue('targetIOFd_T', 'targetIOFdPtr', this.getTargetIOFdArrPWorkIdx, false);
            
            this.writer.wBlockStart('if (targetIOFdPtr != NULL)');
            this.writer.wComment('check fid increments by 1');
            this.writer.wBlockStart(['if (targetIOFdPtr->fidOffset + 1 == ' fopenFidName ')']);
            this.writer.writeLine(['targetIOFdPtr->fidOffset = ' fopenFidName ';']);
            % increase fid storage capacity by 1
            if isempty(this.SimStructArg)
                args = 'targetIOFdPtr';
            else
                args = sprintf('%s, %s', this.SimStructArg, 'targetIOFdPtr');
            end
            this.writer.writeLine('growTargetIOFd(%s, targetIOFdPtr->fidOffset + 1);', args);
            
            this.writer.wBlockStart('if (targetIOFdPtr->Fd != NULL) ');
            this.writer.writeLine('uint8_T *pFopenBuff;');
            
            % make sure new FILE ** is initialized to NULL
            this.writer.wLine('targetIOFdPtr->Fd[targetIOFdPtr->fidOffset] = NULL;');
            
                this.writer.writeLine(['pFopenBuff = (uint8_T *) mxCalloc(' fopenNameSizeName ', sizeof(uint8_T));']);
                this.writer.wBlockStart('if (pFopenBuff != NULL)');
            this.processTargetIOData('pFopenBuff', fopenNameSizeName);       
            % validate the filename
            this.writer.wBlockStart('if (pFopenBuff[%s-1] == %s)', fopenNameSizeName, '''\0''');
            this.writer.writeLine('FILE * tmpFd = NULL;');
            % open the file
            this.writer.writeLine('tmpFd = fopen((char *) pFopenBuff,"w");');
            this.writer.wBlockStart('if (tmpFd != NULL)');
            this.writer.writeLine('/* save the file descriptor */');
            this.writer.writeLine('targetIOFdPtr->Fd[targetIOFdPtr->fidOffset] = tmpFd;');
            this.writer.wBlockMiddle('else');
            errorReturn = 'return XILHOSTAPPSVC_ERROR;';
            % error out if fopen fails
            this.writeError(errorReturn,...
                'PIL:pil:TargetIOFopenError', ...
                'mxCreateString((char *) pFopenBuff)');
            this.writer.wBlockEnd;
            
                this.writer.wBlockEnd; % if \0
                this.writer.writeLine('mxFree(pFopenBuff);');
            
            this.writer.wBlockEnd; % if pFopenBuff != NULL
            this.writer.wBlockEnd; % if Fd != NULL
            this.writer.wBlockMiddle('else'); % if fidOffset + 1
            % error out if we received an invalid fid
            this.writeError(errorReturn,...
                'PIL:pil:TargetIOFopenFidError', ...
                ['mxCreateDoubleScalar(' fopenFidName ')']);
            this.writer.wBlockEnd; % if fidOffset + 1
            this.writer.wBlockEnd; % targetIOFdPtr != NULL
            
                
            this.writer.writeLine('return XILHOSTAPPSVC_SUCCESS;');
            this.writer.wBlockEnd; % end static function
        end
        
        function writeSectionPILIOCommandFprintfResponseFunction(this, taskId, isVerbose)
                this.writer.wBlockStart('static boolean_T processResponseFprintf(%s %s)', this.SimStructType, this.SimStructArg);
            % read in the fprintf error id
            this.writer.writeLine('const int TARGET_IO_SUCCESS = 0;');
            fprintfError = this.SILPILWrapperUtils.getCommandData('FPRINTF_ERROR');
            fprintfErrorName = fprintfError.getName;
            fprintfErrorDataElements = fprintfError.getHostDataElements;
            fprintfErrorHostCType = rtw.connectivity.TypeUtils.builtinToHostCType(fprintfErrorDataElements.getDtypeId);
            % define target buffer
            this.writer.writeLine([fprintfErrorHostCType ' ' fprintfErrorName ';']);
            
            % read in the fprintf data
            fprintfFid = this.SILPILWrapperUtils.getCommandData('FPRINTF_FID');
            fprintfFidName = fprintfFid.getName;
            fprintfFidDataElements = fprintfFid.getHostDataElements;
            fprintfFidHostCType = rtw.connectivity.TypeUtils.builtinToHostCType(fprintfFidDataElements.getDtypeId);
            % define target buffer
            this.writer.writeLine([fprintfFidHostCType ' ' fprintfFidName ';']);
            
            % get the size of file name string
            fprintfSize = this.SILPILWrapperUtils.getCommandData('FPRINTF_SIZE');
            fprintfSizeName = fprintfSize.getName;
            fprintfSizeDataElements = fprintfSize.getHostDataElements;
            fprintfSizeHostCtype = rtw.connectivity.TypeUtils.builtinToHostCType(fprintfSizeDataElements.getDtypeId);
            % define target buffer
            this.writer.writeLine([fprintfSizeHostCtype ' ' fprintfSizeName ';']);
            
            tgtPtr = '*mxMemUnitPtrPtr';
            this.writeSectionPILIOCommandProcessTargetToHostData(fprintfError, ...
                taskId, tgtPtr);
            
            this.writeSectionPILIOCommandProcessTargetToHostData(fprintfFid, ...
                taskId, tgtPtr);
            
            this.writeSectionPILIOCommandProcessTargetToHostData(fprintfSize, ...
                taskId, tgtPtr);
            
            if isVerbose
                this.writer.writeLine(['mexPrintf("RESPONSE_FPRINTF, FPRINTF_ERROR = %u, FPRINTF_FID = %u, FPRINTF_SIZE = %u\n", ' ...
                    fprintfErrorName ', ' fprintfFidName ', ' fprintfSizeName ');']);
            end
            
            errorReturn = 'return XILHOSTAPPSVC_ERROR;';
            % process error Id
            this.writer.wBlockStart('if (%s != TARGET_IO_SUCCESS)', fprintfErrorName);
            this.writeError(errorReturn, ...
                'PIL:pil:TargetIOError', ...
                ['mxCreateDoubleScalar(' fprintfErrorName ')']);
            this.writer.wBlockMiddle('else'); %if (%s != TARGET_IO_SUCCESS)
            this.getPWorkValue('targetIOFd_T', 'targetIOFdPtr', this.getTargetIOFdArrPWorkIdx, true);
            
            this.writer.wBlockStart('if (targetIOFdPtr != NULL)');
            this.writer.wBlockStart(['if (targetIOFdPtr->size > ' fprintfFidName ')']);
            this.writer.wBlockStart(['if (targetIOFdPtr->Fd[' fprintfFidName '] != NULL)']);
            this.writer.writeLine('uint8_T *pFprintfBuff;');
            
                this.writer.writeLine(['pFprintfBuff = (uint8_T *) mxCalloc(' fprintfSizeName ', sizeof(uint8_T));']);
                    this.writer.wBlockStart('if (pFprintfBuff != NULL)');
            this.processTargetIOData('pFprintfBuff', fprintfSizeName);
            
            % validate the string
            this.writer.wBlockStart('if (pFprintfBuff[%s-1] == %s)', fprintfSizeName, '''\0''');
            this.writer.writeLine(['fprintf(targetIOFdPtr->Fd[' fprintfFidName '], "%s", pFprintfBuff);']);
            this.writer.wBlockEnd;
                this.writer.writeLine('mxFree(pFprintfBuff);');
                this.writer.wBlockEnd; % if pFprintfBuff != NULL
            this.writer.wBlockEnd; % targetIOFdPtr->Fd[fid] != NULL
            this.writer.wBlockEnd; % targetIOFdPtr->size
            this.writer.wBlockEnd; % targetIOFdPtr != NULL
            this.writer.wBlockEnd; % !TARGET_IO_SUCCESS

            this.writer.writeLine('return XILHOSTAPPSVC_SUCCESS;')
            this.writer.wBlockEnd; % static boolean_T RESPONSE_FPRINTF
        end
        
        %writeSectionPILIOCommandSignalRaisedResponseFunction
        function writeSectionPILIOSignalRaisedResponseFunction(this, mxCTypeMemUnit)
                this.writer.wBlockStart('static boolean_T processResponseSignalRaised(%s %s)', this.SimStructType, this.SimStructArg);
            this.writer.wLine('const char *signalStr[6] = {"SIGFPE","SIGILL","SIGABRT","SIGSEGV","SIGEXIT","Unknown Signal"};');
                this.writer.wLine('%s errorId;', mxCTypeMemUnit);
            isRead = true;
            skipMemUnitTransform = true;
            this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                    '&errorId', '1');
            
            
            errorReturn = 'return XILHOSTAPPSVC_ERROR;';
            errorStringCreation = 'mxCreateString(signalStr[errorId])';
            if this.IsMexTarget
                exitRequestErrorID = 'Connectivity:target:MATLABCoderCaughtTargetExitRequest';
                if this.SILPILWrapperUtils.getSILPILInterface.isSIL
                    caughtSignalMessage = 'Connectivity:target:MATLABCoderCaughtTargetSignalWithStderr';
                else
                    caughtSignalMessage = 'Connectivity:target:MATLABCoderCaughtTargetSignal';
                end
                exitRequestErrorArgs = {exitRequestErrorID};
                errorArgs = {caughtSignalMessage, errorStringCreation};
            else
                exitRequestErrorID = 'Connectivity:target:CaughtTargetExitRequest';
                crashTime = 'mxCreateDoubleScalar(ssGetT(S))';
                if this.SILPILWrapperUtils.getSILPILInterface.isSIL
                    caughtSignalMessage = 'Connectivity:target:CaughtTargetSignalWithStderr';
                else
                    caughtSignalMessage = 'Connectivity:target:CaughtTargetSignal';
                end
                exitRequestErrorArgs = {exitRequestErrorID, crashTime};
                errorArgs = {caughtSignalMessage, errorStringCreation, crashTime};
            end
            
            this.writer.wBlockStart('if (strcmp(signalStr[errorId], "SIGEXIT")==0)');
            % Throw error for when the application makes an exit request e.g. exit()
            this.writeError(errorReturn, exitRequestErrorArgs{:});
            this.writer.wBlockMiddle('else');
            % Throw error for standard signal raised
            this.writeError(errorReturn, errorArgs{:});
            this.writer.wBlockEnd; % if block
            this.writer.wBlockEnd; % static processResponseSignalRaised
        end
        
        function writeSectionReadException(this,bufferVariableName,bufferLengthVariableName)

            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo();
            
            this.writer.wLine('uint32_T %s;',bufferLengthVariableName);
            isRead = true;
            skipMemUnitTransform = false;
            this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                sprintf('(%s *)&%s', memUnitInfo.ioDataType, bufferLengthVariableName), '1', "TypeUInt32");
            this.writer.wLine('%s *%s = (%s *) mxCalloc(%s+1, sizeof(%s));', memUnitInfo.ioDataType, bufferVariableName, memUnitInfo.ioDataType, bufferLengthVariableName, memUnitInfo.ioDataType);
            this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                sprintf('&(%s[0])', bufferVariableName), bufferLengthVariableName);
        end

        %writeSectionPILIOExceptionResponseFunction
        function writeSectionPILIOExceptionResponseFunction(this)
            
            this.writer.wBlockStart('static boolean_T processResponseException(%s %s)', this.SimStructType, this.SimStructArg);

            this.writeSectionReadException('exception','exceptionLength');

            this.writer.wBlockStart('if(exceptionLength)');

                this.writeSectionReadException('exceptionType','exceptionTypeLength');

                if this.IsMexTarget
                    caughtSignalMessage = 'Connectivity:target:MATLABCoderCaughtTargetException';
                    errorArgs = {caughtSignalMessage, 'mxCreateString((const char*)exceptionType)', 'mxCreateString((const char*)exception)'};
                else
                    crashTime = 'mxCreateDoubleScalar(ssGetT(S))';
                    caughtSignalMessage = 'Connectivity:target:CaughtTargetException';
                    errorArgs = {caughtSignalMessage, 'mxCreateString((const char*)exceptionType)', 'mxCreateString((const char*)exception)', crashTime};
                end

                errorReturn = 'mxFree(exception); mxFree(exceptionType); return XILHOSTAPPSVC_ERROR;';

                this.writeError(errorReturn,...
                errorArgs{:});
            
            this.writer.wBlockMiddle('else');

                if this.IsMexTarget
                    caughtSignalMessage = 'Connectivity:target:MATLABCoderCaughtUnknownTargetException';
                    errorArgs = {caughtSignalMessage };
                else
                    crashTime = 'mxCreateDoubleScalar(ssGetT(S))';
                    caughtSignalMessage = 'Connectivity:target:CaughtUnknownTargetException';
                    errorArgs = {caughtSignalMessage, crashTime};
                end

                errorReturn = 'mxFree(exception); return XILHOSTAPPSVC_ERROR;';

                this.writeError(errorReturn,...
                errorArgs{:});
            
            this.writer.wBlockEnd;

            this.writer.wBlockEnd; % static processResponseException
        
        end
        
        function writeSectionPILIOCommandResponseFunctions(this)            
            % Response error function
            
            cachedSimStructArg = this.SimStructArg;
            if ~this.IsMexTarget
                this.SimStructArg = 'S';
            end
            cachedError = this.ReturnArgString;
            this.ReturnArgString = ' XILHOSTAPPSVC_ERROR';
            
            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
            mxCTypeMemUnit =  rtw.connectivity.TypeUtils.builtinToHostCType(memUnitInfo.memUnitType);
            this.writeSectionPILIOCommandErrorResponseFunction(mxCTypeMemUnit);
            this.writer.newLine;
            
            % Response print function
            taskId = []; % Not used
            
            isVerbose = this.isVerbose();
        
            this.writeSectionPILIOCommandPrintfResponseFunction(taskId, isVerbose);
            this.writer.newLine;
            
            % Response fopen function
            this.writeSectionPILIOCommandFopenResponseFunction(taskId, isVerbose);
            this.writer.newLine;
            
            % Response fprintf function
            this.writeSectionPILIOCommandFprintfResponseFunction(taskId, isVerbose);
            this.writer.newLine;

            % Signal Raised response function
            this.writeSectionPILIOSignalRaisedResponseFunction(mxCTypeMemUnit);
            this.writer.newLine;
            
            silpilInterface = this.SILPILWrapperUtils.getSILPILInterface;
            langExt = silpilInterface.getTargetExtension();

            if strcmp(langExt,'.cpp')
                % Exception response function
                this.writeSectionPILIOExceptionResponseFunction();
                this.writer.newLine;
            end
            
            this.SimStructArg = cachedSimStructArg;
            % Error and TargetIO response functions
            this.writeSectionPILIOCommandErrorAndTargetIOResponseFunction();
            this.ReturnArgString = cachedError;
            this.writer.newLine;
        end
         
        function writeSectionPILIOCommandOutputDataResponseCase(this,...
                                                               taskId, ...
                                                               allOutportData,...
                                                               allOutportSizesData,...
                                                               allDSWriteData,...
                                                               sharedLocalDataStoreElements,...
                                                               signalLoggingData,...
                                                               stateLoggingData,...
                                                               allServerFcnOutputArgsData, ...
                                                               verboseOutput, ...
                                                               errorReturn)
           this.writer.wBlockStart('case RESPONSE_OUTPUT_PRE_DATA:');
           if ~isempty(verboseOutput)
               this.writer.writeLine(verboseOutput);
           end
           if this.IsMexTarget
               % Return immediately, data is marshaled external to XIL
               % files.
               this.writer.wLine('%s', errorReturn);
           else
               tgtPtr = 'mxMemUnitPtr';
               % process state logging Data
               this.writeSectionPILIOCommandProcessTargetToHostData(stateLoggingData, ...
                   taskId, tgtPtr);
               this.writeSectionUpdateLoggedData(stateLoggingData);
           end
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % case RESPONSE_OUTPUT_PRE_DATA
           
           this.writer.wBlockStart('case RESPONSE_OUTPUT_DATA:');
           
           if ~isempty(verboseOutput)
              this.writer.writeLine(verboseOutput);
           end
           
           if this.IsMexTarget
               % Return immediately, data is marshaled external to XIL
               % files.
               this.writer.wLine('%s', errorReturn);
           else
               % make sure we process data that via OpaqueRegion first and
               % then data via address table
               hasHostSideOpaqueRegion = @(x)(x.HasTargetSideOpaqueRegion && ...
                   rtw.connectivity.CodeInfoUtils.isCoderArray(x.getRTWDataInterfaceImplementation()) && ...
                   this.supportsCoderArray());
               % get the indices of data using OpaqueRegion in all categories
               allOutportDataORIdx = arrayfun(hasHostSideOpaqueRegion, allOutportData);
               allOutportSizesDataORIdx = arrayfun(hasHostSideOpaqueRegion, allOutportSizesData);
               allDSWriteDataORIdx = arrayfun(hasHostSideOpaqueRegion, allDSWriteData);
               sharedLocalDataStoreElementsORIdx = arrayfun(hasHostSideOpaqueRegion, sharedLocalDataStoreElements);
               signalLoggingDataORIdx = arrayfun(hasHostSideOpaqueRegion, signalLoggingData);
               allServerFcnOutputArgsDataORIdx = arrayfun(hasHostSideOpaqueRegion, allServerFcnOutputArgsData);
                
               % process all data using OpaqueRegion
               this.processCommandOutputResponseCases(taskId,allOutportData(allOutportDataORIdx),...
                   allOutportSizesData(allOutportSizesDataORIdx),...
                   allDSWriteData(allDSWriteDataORIdx),...
                   sharedLocalDataStoreElements(sharedLocalDataStoreElementsORIdx),...
                   signalLoggingData(signalLoggingDataORIdx),...
                   allServerFcnOutputArgsData(allServerFcnOutputArgsDataORIdx));
               % process all data using address table
               this.processCommandOutputResponseCases(taskId,allOutportData(~allOutportDataORIdx),...
                   allOutportSizesData(~allOutportSizesDataORIdx),...
                   allDSWriteData(~allDSWriteDataORIdx),...
                   sharedLocalDataStoreElements(~sharedLocalDataStoreElementsORIdx),...
                   signalLoggingData(~signalLoggingDataORIdx),...
                   allServerFcnOutputArgsData(~allServerFcnOutputArgsDataORIdx));
           end

           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % case RESPONSE_OUTPUT_DATA
       end

       function processCommandOutputResponseCases(this,taskId, ...
                                                   allOutportData,...
                                                   allOutportSizesData,...
                                                   allDSWriteData,...
                                                   sharedLocalDataStoreElements,...
                                                   signalLoggingData,...
                                                   allServerFcnOutputArgsData)

               % process output size data prior to processing output data
               % so that the host's row major transform can access the current
               % sizes
               tgtPtr = 'mxMemUnitPtr';
               this.writeSectionPILIOCommandProcessTargetToHostData(allOutportSizesData, ...
                   taskId, tgtPtr);
               
               this.writeSectionPILIOCommandProcessTargetToHostData(allOutportData, ...
                   taskId, tgtPtr);
               
               % process dsWrite
               isRead = false;
               this.writeSectionPILIOCommandProcessTargetToHostData(allDSWriteData, ...
                   taskId, tgtPtr);
               
               % write data stores to Simulink
               this.writeSectionReadWriteSharedDataStores(allDSWriteData, isRead);
               
               if this.SILPILWrapperUtils.getSILPILInterface.getInTheLoopType~=rtw.pil.InTheLoopType.Block
                   % process shared local data stores
                   this.writeSectionPILIOCommandProcessTargetToHostData(sharedLocalDataStoreElements, ...
                       taskId, tgtPtr);
                   
                   
                   % write shared local data stores to Simulink
                   this.writeSectionReadWriteSharedDataStores(sharedLocalDataStoreElements, isRead);
               end
               % process signal logging Data
               signalLoggingDataToUpload = rtw.pil.LoggingUtils.filterUnneededBufferUpload(signalLoggingData);
               this.writeSectionPILIOCommandProcessTargetToHostData(signalLoggingDataToUpload, ...
                   taskId, tgtPtr);
               this.writeSectionUpdateLoggedData(signalLoggingData);
               
               % process server function output arguments
               this.writeSectionPILIOCommandProcessTargetToHostData(allServerFcnOutputArgsData, ...
                   taskId, tgtPtr);
       end
      
       function writeSectionPILIOCommandTypeSizeResponseCase(...
               this, mxCTypeMemUnit, errorReturn)
           
           this.writer.wBlockStart('case RESPONSE_TYPE_SIZE:');
           
           % get sizes
           this.writer.writeLine([mxCTypeMemUnit ' typeBytes;']);
               this.writer.writeLine([mxCTypeMemUnit ' typeId;']);
           isRead = true;
           skipMemUnitTransform = true;
           this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                   {'&typeId','&typeBytes'}, {'1','1'});
           
           toolSingleType = this.SILPILWrapperUtils.getTypeUtils.builtinToToolClassId('single');
           toolDoubleType = this.SILPILWrapperUtils.getTypeUtils.builtinToToolClassId('double');
           
           
           this.writer.wBlockStart('switch (typeId)');
           this.writer.wBlockStart('case %s:', toolSingleType);
           
           hostBytes = rtw.connectivity.TypeUtils.builtinHostByteSize('single');
           this.writer.wBlockStart(['if (typeBytes != ' int2str(hostBytes) ')']);
           
           % throw error
           this.writeError(errorReturn, ...
               'PIL:pilverification:SingleUnsupported', ...
               ['mxCreateDoubleScalar(' int2str(hostBytes) ')'], ...
               'mxCreateDoubleScalar(typeBytes)');
           this.writer.wBlockEnd; % if (typeBytes != ' int2str(hostBytes) ')
           
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % case "single"
           
           this.writer.wBlockStart('case %s:', toolDoubleType);
           
           hostBytes = rtw.connectivity.TypeUtils.builtinHostByteSize('double');
           this.writer.wBlockStart(['if (typeBytes != ' int2str(hostBytes) ')']);
           
           % throw error
           this.writeError(errorReturn, ...
               'PIL:pilverification:DoubleUnsupported', ...
               ['mxCreateDoubleScalar(' int2str(hostBytes) ')'], ...
               'mxCreateDoubleScalar(typeBytes)');
           this.writer.wBlockEnd; % if (typeBytes != ' int2str(hostBytes) ')
           
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % case "double"
           
           this.writer.wBlockStart('default:');
           
           % throw error
           this.writeError(errorReturn, ...
               'PIL:pilverification:UnknownTypeId', ...
               'mxCreateDoubleScalar(typeId)');
           
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % end default
           
           this.writer.wBlockEnd; % switch (typeId)
           
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % case RESPONSE_TYPE_SIZE
       end
       
       function writeSectionPILIOCommandCSRequestServiceResponseCase(...
               this, errorReturn, isVerbose)
           
           this.writer.wBlockStart('case RESPONSE_CS_REQUEST_SERVICE:');           
           callerFunctionsInfo = this.codeInfoUtils.getUndefinedCallerFunctionsInfo;
                                 
           this.writer.wComment('read server function id');
           
           svrFunctionId = this.SILPILWrapperUtils.getCommandData('SERVER_FUNCTION_ID');
           svrFunctionIdVarName = svrFunctionId.getName;
           svrFunctionIdDataElements = svrFunctionId.getHostDataElements;
           svrFunctionIdHostCType = rtw.connectivity.TypeUtils.builtinToHostCType(svrFunctionIdDataElements.getDtypeId);
           % define target buffer
           this.writer.writeLine([svrFunctionIdHostCType ' ' svrFunctionIdVarName ';']);
                                
           taskId = []; % not used
           tgtPtr = 'mxMemUnitPtr';
           this.writeSectionPILIOCommandProcessTargetToHostData(svrFunctionId, ...
               taskId, tgtPtr);                                 
           this.writer.wBlockStart('switch (%s)', svrFunctionIdVarName);
           
           % It would be nice to know from codeInfo the exact caller
           % functions that each task has (perhaps based on the Timing
           % info), but since we don't know that information yet, we will
           % write the cases for all the function calls in the model.
           for callerFcnIdx = 1:length(callerFunctionsInfo)
               callerFunctionInfo = callerFunctionsInfo(callerFcnIdx);
               task = [];
               task.codeInfoData = callerFunctionInfo.getCodeInfoData;
               this.writer.wBlockStart('case %d:', callerFunctionInfo.getFcnId);
               slFcnName = callerFunctionInfo.getSlFunctionName;
               this.writer.wComment(['Prepare arguments to call Simulink function: ' slFcnName]);
               
               % Define specArgs
               argVarName = rtw.pil.Sfunction.SvrFcnInvokeArgName;
               argPointerAccessString = callerFunctionInfo.defineArgsForSLCall(this.writer, argVarName);
               % process caller function input arguments               
               outputArgsCData = callerFunctionInfo.getOutputArgsDataElements;
               if ~isempty(outputArgsCData)
                   outputArgsMemSymbolicUnits = ...
                       outputArgsCData.getTotalMemUnitSymbolicSize(...
                           this.SILPILWrapperUtils.getMemUnitInfo.memUnitBytes);
               else
                   outputArgsMemSymbolicUnits = '';
               end
               
               this.writer.newLine;
               callerFunctionInfo.writeSfunctionDataAssignmentForSLCall(this,  this.writer, argVarName);
                              
               % copy data from IOBuffer: process inArgs
               taskId = []; % not used
               this.writeSectionPILIOCommandProcessTargetToHostData(...
                   callerFunctionInfo.getInputArgsDataInterfaces, ...
                   taskId, ...
                   tgtPtr);
                              
               % copy data from IOBuffer: process DataStore writes. Because
               % we don't know which DataStores the Simulink Function uses,
               % we transfer all DataStore writes from the target. If, one
               % day, codeInfo captures the DataStores part of the
               % DirectReads and DirectWrites, then we should be able to
               % transfer the DataStores that are only used by the Simulink
               % Function.
               outportIndices = []; % not used
               outportSizesIndices = []; % not used
               signalLoggingIndices = []; % not used
               statelLoggingIndices = []; % not used
               dsWriteIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                   this.codeInfoUtils.getWriterSharedDataStoresForTask(task), 'dswrite');
               sharedLocalDataStoreIndices = []; % not used
               serverFcnIndex = []; % not used
               [~, allDSWriteData] =...
                   this.getAllTargetToHostDataInterfaces(...
                   outportIndices, ...
                   outportSizesIndices,...
                   dsWriteIndices, ...
                   sharedLocalDataStoreIndices, ...
                   signalLoggingIndices, ...
                   statelLoggingIndices, ...
                   serverFcnIndex);
               
               this.writeSectionPILIOCommandProcessTargetToHostData(allDSWriteData, ...
                   taskId, tgtPtr);
               
               % write data stores to Simulink
               isRead = false;
               this.writeSectionReadWriteSharedDataStores(allDSWriteData, isRead);
           
               % Finally, call slcsRequestService if one is registered.
               %
               % Note that Simulink allows a caller block that calls into a
               % server function that does not exist. In this case, the
               % caller block outputs zeros. Since we initialized the memory
               % for the output args with calloc, this should return zeros.
               % Ideally, in this case, it would be more efficient to
               % determine this scenario upfront when we are generating the
               % XIL wrapper and have the target code return zeros without
               % the need to come up to the host, but this would involve
               % that we do a graphical search throughout the model
               % hierarchy since a server block is allowed to exist
               % anywhere (even outside the XIL component). Doing a graphical
               % search is not ideal, so this was not implemented.
               this.writer.newLine;
               callerFunctionInfo.writeCallToFunction(this.writer, this.SimStructArg, argVarName, argPointerAccessString);
                   
               this.writer.newLine;
               this.writer.wComment('send the result down to the target');
               
               % prepare DataElements to transfer to the target.
               % Regarding the DS reads, we currently transfer all the DS
               % reads. Ideally, if codeInfo captures the DS reads part of
               % it DirectReads and DirectWrites, then we would only need
               % to transfer the DS reads for this task.
               inportIndices = []; % not used
               inportSizesIndices = []; % not used
               outportSizesIndices = []; % not used
               paramIndices = []; % not used
               
               dsReadIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                   this.codeInfoUtils.getReaderSharedDataStoresForTask(task), 'dsread');
               serverFcnIndex = []; % not used
               taskTiming = [];
               [~,...
                totalSymbolicHostToTargetBufferMemUnits, ...
                commandData,...
                ~,...
                ~,...
                ~,...
                ~,...
                allDSReadData] =...
                    this.getAllHostToTargetDataInterfaces(...
                                                               'XIL_CLIENT_SERVER_COMMAND',...
                                                               inportIndices,...
                                                               inportSizesIndices,...
                                                               outportSizesIndices,...
                                                               paramIndices,...
                                                               dsReadIndices,...
                                                               serverFcnIndex, ...
                                                               taskTiming);
               
               if ~isempty(outputArgsMemSymbolicUnits)
                  totalSymbolicHostToTargetBufferMemUnits = ...
                      sprintf('%s + %s', ...
                              totalSymbolicHostToTargetBufferMemUnits, ...
                              outputArgsMemSymbolicUnits);
               end
               
               % grow I/O buffer
               memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
               if memUnitInfo.supportsOnlyByteIO && 1 ~= memUnitInfo.memUnitBytes
                   % byte I/O
                   % present data as bytes - for word addressable targets,
                   % words will have byte order of MATLAB host computer
                   expectedDataOutSize = sprintf( ...
                       '(%s) * %d', totalSymbolicHostToTargetBufferMemUnits, ...
                       memUnitInfo.memUnitBytes);
               else
                   % mem unit I/O
                   % present data as mem units
                   expectedDataOutSize = totalSymbolicHostToTargetBufferMemUnits;
               end
               this.writer.wBlockStart(''); % Start of scope around pXILService
               this.writeSectionPILIOCommandGrowIOBuffer(expectedDataOutSize, errorReturn, isVerbose);
               
                   this.writer.wLine('IOBufferPtr->bufferDataSize = 0;');
               this.writer.wBlockStart('if (IOBufferPtr->data != NULL)');
               
               % write command id
               this.writeSectionPILIOCommandWriteCommandId('XIL_CLIENT_SERVER_COMMAND');
               
               % process command data
               this.writeSectionPILIOCommandProcessHostToTargetData(...
                   commandData, callerFunctionInfo.getTID);
               
               % process out Args
               this.writeSectionPILIOCommandProcessHostToTargetData(...
                   callerFunctionInfo.getOutputArgsDataInterfaces, ...
                   taskId);
               
               % process dsRead: read data stores from Simulink and send
               % down to the target
               isRead = true;
               this.writeSectionReadWriteSharedDataStores(allDSReadData, isRead);
                  this.writeSectionPILIOCommandProcessHostToTargetData(allDSReadData, ...
                   taskId);                                            
                                                     
               % dispatch command to the target
               this.writeSectionPILIOCommandCommandDispatch(errorReturn);
               
               this.writer.wBlockEnd; %if (IOBufferPtr->data != NULL)
                                                          
               this.writer.wBlockEnd; %if (pXILService != NULL) 
               
               this.writer.wBlockEnd; % End of scope around pXILService
               
               this.writer.writeLine('break;');
               this.writer.wBlockEnd; % case callerFunctionInfo.getFcnId
           end
           this.writer.wBlockStart('default:');
           
           % throw error
           this.writeError(errorReturn, ...
               'PIL:pilverification:UnknownResponseId', ...
               'mxCreateDoubleScalar(responseId)');
           
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % default end
           
           this.writer.wBlockEnd; % switch callerFunctionInfo.getFcnId end
           
           this.writer.writeLine('break;');
           this.writer.wBlockEnd; % case RESPONSE_CS_REQUEST_SERVICE
       end
                   
       function writeArgDataPtrAndSizeAssignment(this, callerFunctionInfo,...
               argDataInterface, argVarName, slArgPosition)
           pWorkIdx = this.getCallerFunctionArgumentPWorkIdx(callerFunctionInfo, argDataInterface);
           slArgPositionStr = num2str(slArgPosition-1); %0-based
           argPtr = sprintf('%s[%s].dataPtr', argVarName, slArgPositionStr);
           this.getPWorkValue('void', argPtr , pWorkIdx, false);
       end
       
       function writeSectionDefineIntegerTmpVar(this, pWorkIdx)
           this.writer.wBlockStart('');

           this.writer.wComment('Tmp var: offset siglog/statelog');
           elementSize = 'sizeof(int)';
           % allocate memory - will be freed in mdlTerminate
           this.writer.wLine('void * tmpVarMemory = calloc(1, %s);', elementSize);
           % check memory allocation
           this.writer.wBlockStart('if (tmpVarMemory == NULL)');
           this.writeErrorCall('Error in allocating memory through calloc.');
           this.writer.wLine('return %s;', this.ReturnArgString);
           this.writer.wBlockEnd; % if (tmpVarMemory == NULL)
           % store in PWork
           this.setPWorkValue( pWorkIdx, 'tmpVarMemory');
           this.writer.wBlockEnd;
       end
       
       function writeReuseSectionDefineTmpVar(this, dataElement, pWorkIdx, pWorkIdxReuse)
           this.writer.wBlockStart('');

           % escape *'s which could incorrectly close the comment           
           dataInterfaceString = strrep(dataElement.getDataInterface.getString(this.SILPILWrapperUtils), ...
                                        '*', '-*-');           
           this.writer.wComment(['Tmp var: ' dataInterfaceString]);
           this.getPWorkValue('void', 'tmpVarMemory', pWorkIdxReuse, true);
           % store in PWork
           this.setPWorkValue( pWorkIdx, 'tmpVarMemory');
           this.writer.wBlockEnd;
       end
       
       function writeSectionDefineTmpVar(this, dataElement, pWorkIdx)
           this.writer.wBlockStart('');

           % escape *'s which could incorrectly close the comment           
           dataInterfaceString = strrep(dataElement.getDataInterface.getString(this.SILPILWrapperUtils), ...
                                        '*', '-*-');           
           this.writer.wComment(['Tmp var: ' dataInterfaceString]);
           if dataElement.isStructElement
               [~, numElements, hostElementSize] = dataElement.getStructArrayTopLevelInfo;
               elementSize = hostElementSize.str;
               if hostElementSize.needsDTA
                   % access the API that will give us Bus size information
                   this.writer.writeLine('slDataTypeAccess * dta = ssGetDataTypeAccess(S);');
                   this.writer.writeLine('const char * bpath = ssGetPath(S);');
               end
           else
               simulinkDTypeId = dataElement.getDtypeId;
               if simulinkDTypeId == rtw.connectivity.CodeInfoTypeEnum.TypeChar
                   numElements.Symbolic = '1';
                   numElements.Numerical = 1;
                   elementSize = 'sizeof(void*)';
               else
                   simulinkCType = rtw.connectivity.TypeUtils.builtinToHostCType(simulinkDTypeId);
                   numElements.Symbolic = dataElement.getSymbolicNumElements;
                   numElements.Numerical = dataElement.getNumElements;
                   elementSize = ['sizeof(' simulinkCType ')'];
               end
           end
           % allocate memory - will be freed in mdlTerminate
           this.writer.writeLine(['void * tmpVarMemory = calloc(' numElements.Symbolic ', ' elementSize ');']);
           % check memory allocation
           this.writer.wBlockStart('if (tmpVarMemory == NULL)');

           this.writeErrorCall('Error in allocating memory through calloc.');
           this.writer.wLine('return%s;', this.ReturnArgString);
           this.writer.wBlockEnd; % if (tmpVarMemory == NULL)
           
           % initialize argument data for old AUTOSAR client block. We don't
           % need to do this for the new caller block because it is not
           % possible to simulate a caller block with no Simulink function.
           % However, for the old client block, it is supported, so we need
           % to make sure we initialize the argument data properly as it
           % will be sent down to the target.
           if isa(dataElement.getDataInterface, 'rtw.pil.FunctionArgData') &&...
                   this.SILPILWrapperUtils.isServerFunctionFromOldAUTOSARClientBlock(...
                   dataElement.getDataInterface.getFunctionInfo.getCodeInfoData.Prototype.Name) &&...
                   ~dataElement.isStructElement
               [~, initVal] = dataElement.getDefaultInitialization(this.SILPILWrapperUtils);
               this.writer.wBlockStart('');
               this.writer.writeLine('%s* tmpVarMemoryData = (%s*)tmpVarMemory;', simulinkCType, simulinkCType);
               if numElements.Numerical > 1
                   % get an expression to use in a loop with index variable i
                   this.writer.writeLine('int elementIdx;');
                   this.writer.wBlockStart('for (elementIdx=0; elementIdx<%s; elementIdx++)', numElements.Symbolic);
                   this.writer.writeLine('tmpVarMemoryData[elementIdx] = %d;', initVal);
                   this.writer.wBlockEnd;
               else
                   this.writer.writeLine('*(tmpVarMemoryData) = %d;', initVal);
               end
               this.writer.wBlockEnd;
           end
           
           % store in PWork
           this.setPWorkValue( pWorkIdx, 'tmpVarMemory');
           this.writer.wBlockEnd;
       end
        
       function val = getByteReorderingTestMode(this)
           if isempty(this.ByteReorderingTestMode)
               this.ByteReorderingTestMode = strcmp(getenv('ByteReorderingTestMode'), '1');
           end
           val = this.ByteReorderingTestMode;
       end
       
       % allocate memory for each shared data store tmp var and store in PWork
       function writeSectionDefineSharedDataStoreTmpVars(this, dataInterfaces)          
          for diIdx = 1:length(dataInterfaces)
             ds = dataInterfaces(diIdx);
             % create dataElements containing contiguous elements of the
             % current data interface
             dataElements = rtw.pil.CodeInfoData.createUnspecifiedDataElements(ds, ...
                 this.SILPILWrapperUtils);             
             % the first element has all we need
             dataElement = dataElements(1);
             pWorkIdx = this.getSharedDataStorePWorkIdx(ds);
             if rtw.connectivity.CodeInfoUtils.isCoderArray(ds.Implementation) && ...
                     ~rtw.connectivity.CodeInfoUtils.isBusWithCoderArrayElement(ds.Implementation.CodeType)
                 this.writeSectionDefineTmpVarForCoderArrayDsm(dataElement.getDataInterface(), pWorkIdx);
             else
                 this.writeSectionDefineTmpVar(dataElement, pWorkIdx);
             end
          end
       end                                                        
       
       function writeSectionRegistrationBusLogging(this, dataInterfaces)
           % register buses for logging
            if ~this.IsMexTarget && coder.internal.connectivity.featureOn('BusLogging')
                numLoggingData = length(dataInterfaces);

                % get the type names of all the buses in the model
                for i=1:numLoggingData
                    dataInterface = dataInterfaces(i);
                    type = dataInterface.getHostType();
                    % setup dataTypeId variable, and if there a named bus
                    % attached, define that type in the standard way
                    [~, namedObject] = rtw.connectivity.CodeInfoTypeUtils.getCodeInfoStoredValueDTypeId(type);
                    if rtw.connectivity.CodeInfoTypeUtils.isBusOrStruct(type) && ~isempty(namedObject)
                        includeCodeBlock = true;
                        allowDuplicates = true;
                        this.writeSectionInitializeSizesDatatypeId(type, includeCodeBlock, allowDuplicates);
                    end
                end
            end
       end
       
       % allocate memory for each logging tmp var and store in PWork
       function writeSectionDefineLoggingTmpVars(this, dataInterfaces)          
          [~, idReuse] = rtw.pil.LoggingUtils.filterUnneededBufferUpload(dataInterfaces);
          for diIdx = 1:length(dataInterfaces)
             dataInterface = dataInterfaces(diIdx);
             pWorkIdx = this.getLoggingTmpVarPWorkIdx(dataInterface);
              % create dataElements containing contiguous elements of the
              % current data interface
             dataElements = dataInterface.getHostDataElements;
             % the first element has all we need
             dataElement = dataElements(1);
             if idReuse(diIdx) == diIdx
                 this.writeSectionDefineTmpVar(dataElement, pWorkIdx);
             else
                 pWorkIdxToReuse = this.getLoggingTmpVarPWorkIdx(dataInterfaces(idReuse(diIdx)));
                 this.writeReuseSectionDefineTmpVar(dataElement, pWorkIdx, pWorkIdxToReuse);
             end
             pWorkIdx = this.getLoggingOffsetPWorkIdx(dataInterface);
             this.writeSectionDefineIntegerTmpVar(pWorkIdx);
          end
       end         
       
       % allocate memory for all arguments of all the caller functions and
       % store in PWork
       function writeSectionDefineAllCallerFunctionArgsTmpVars(this, callerFunctionsInfo)   
           for callFcnIdx = 1:length(callerFunctionsInfo) 
               callerFunctionInfo = callerFunctionsInfo(callFcnIdx);
               args = callerFunctionInfo.getAllCodeInfoArgs;
               for codeInfoArgIdx = 1:length(args)
                   if callerFunctionInfo.skipSLProcessingForArg(args(codeInfoArgIdx))
                       continue
                   end
                   arg = args(codeInfoArgIdx);
                   codeArgPosition = callerFunctionInfo.getCodeArgPosition(arg);
                   dataInterface = callerFunctionInfo.getDataInterfacesForArgs(codeArgPosition);
                   dataElements = callerFunctionInfo.getDataElementsForArgs(codeArgPosition);
                   % the first element has all we need
                   dataElement = dataElements(1);
                   pWorkIdx = this.getCallerFunctionArgumentPWorkIdx(callerFunctionInfo, dataInterface);
                   this.writeSectionDefineTmpVar(dataElement, pWorkIdx);
               end
           end
       end  
       
       % free PWork memory for each tmp var
       function writeSectionFreeTmpVars(this, dataInterfaces, type, callerFunctionInfo)          
           narginchk(3, 4);
           if nargin < 4
               assert(~strcmp(type, 'CallerFunctionArgs'),...
                   'incorrect number of inputs for type CallerFunctionArgs');
               callerFunctionInfo = [];
           end
          numDI = length(dataInterfaces);
          if numDI > 0
             this.writer.wBlockStart('if (ssGetPWork(S) != NULL)');

             for diIdx = 1:numDI
                 dataInterface = dataInterfaces(diIdx);                 
                 switch type
                     case {'logging', 'statelogging'}
                        pWorkIdx = this.getLoggingTmpVarPWorkIdx(dataInterface); 
                     case 'datastore'
                        pWorkIdx = this.getSharedDataStorePWorkIdx(dataInterface);     
                     case 'CallerFunctionArgs'
                         pWorkIdx = this.getCallerFunctionArgumentPWorkIdx(callerFunctionInfo, dataInterface);
                     otherwise
                         assert(false, 'Unknown type: %s', type);
                 end                                  
                 this.writer.wBlockStart('');
                 
                 % free
                 this.getPWorkValue('void', 'tmpVarMemory', pWorkIdx, true);
                 this.writer.wBlockStart('if (tmpVarMemory != NULL)');
                 
                 if strcmp(type, 'datastore') && (...
                         rtw.connectivity.CodeInfoUtils.isCoderArray(dataInterface.Implementation) && ...
                         ~rtw.connectivity.CodeInfoUtils.isBusWithCoderArrayElement(dataInterface.Implementation.CodeType))
                     this.registerCoderArrayType(dataInterface)
                     % invoke the coder::array destructor, this will free
                     % the memory allocated to store the array data
                     this.writer.wLine('ssDestroyDynamicArrayForDt(S, dtId, tmpVarMemory);');
                 end
                 this.writer.writeLine('free(tmpVarMemory);');
                 % set PWork to NULL
                 this.setFreedPWorkValueToNull('tmpVarMemory', pWorkIdx);
                 this.writer.wBlockEnd; % if (tmpVarMemory != NULL)
                 
                 this.writer.wBlockEnd;
             end
             this.writer.wBlockEnd; % if (ssGetPWork(S) != NULL)
          end
       end
       
       % set PWork to NULL for logging DataInterface sharing the same tmp
       % memory
       function writeSectionNullInSharedLoggingTmpVars(this, dataInterfaces, reuseIdx)
           for diIdx = 1:length(dataInterfaces)
               if reuseIdx(diIdx) == diIdx
                   continue;
               end
               dataInterface = dataInterfaces(diIdx);
               pWorkIdx = this.getLoggingTmpVarPWorkIdx(dataInterface);
               this.writer.wBlockStart('');
               
               this.getPWorkValue('void', 'tmpVarMemory', pWorkIdx, true);
               this.writer.wBlockStart('if (tmpVarMemory != NULL)');
               % set PWork to NULL
               this.setFreedPWorkValueToNull('tmpVarMemory', pWorkIdx);
               this.writer.wBlockEnd; % if (tmpVarMemory != NULL)
               
               this.writer.wBlockEnd; % if (ssGetPWork(S) != NULL)
           end
       end
       
       % read shared data stores from Simulink or shared data stores to Simulink
       function writeSectionReadWriteSharedDataStores(this, dataInterfaces, isRead)           
           if ~isempty(dataInterfaces)
               if isRead
                   ssMacro = 'ssReadFromDataStore';
               else
                   ssMacro = 'ssWriteToDataStore';
               end
               for dataInterface = dataInterfaces
                   this.writer.writeLine([ssMacro '(S, ' ...
                       this.getSfunIdxForDataInterface(dataInterface) ', ' ...
                       'ssGetPWorkValue(S, ' this.getSharedDataStorePWorkIdx(dataInterface.getRTWDataInterface) '));']);
               end
           end
       end
       
       % register logged data to Simulink
       function writeSectionUpdateLoggedData(this, dataInterfaces)
           if ~isempty(dataInterfaces)
               this.writer.wBlockStart('');
               isLoggingActiveVarName = 'isLoggingActive';
               this.getPWorkValue('boolean_T', isLoggingActiveVarName, this.getIsLoggingActiveIdx, true);
               this.writer.wBlockStart('if (%s)', isLoggingActiveVarName);
               
               isSampleTimeIndependent = this.codeInfoUtils.isSampleTimeIndependent;
               isMultiTasking = this.codeInfoUtils.isMultiTasking;
               isExportFcnDiagram = this.codeInfoUtils.isExportFcnDiagram;
               for dataInterface = dataInterfaces
                   dataInterfaceType = dataInterface.getDataInterfaceType;
                   switch dataInterfaceType
                       % move in dataInterface?
                       case 'siglog'
                           lComment = 'Update logged signal';
                       case 'statelog'
                           lComment = 'Update logged state';
                       otherwise
                           assert(false, [dataInterfaceType ' not supported as data interface type']);
                   end
                   pWorkTgtIdx = this.getLoggingElementPWorkIdx(dataInterface);
                   pWorkOffsetIdx = this.getLoggingOffsetPWorkIdx(dataInterface);
                   pWorkSrcIdx = this.getLoggingTmpVarPWorkIdx(dataInterface);
                   timing = dataInterface.getRTWDataInterface.Timing;
                   % determine if sample time is constant
                   isConstSampleTime = strcmp(timing.TimingMode, 'ONESHOT');
                   % No guard needed for ExportFcnDiagram.
                   % No guard needed for (export functions) async rates.
                   isAsyncSampleTime = strcmp(timing.TimingMode, 'ASYNCHRONOUS');
                   isEventSampleTime = this.HasModelWideEvents && ...
                       any(strcmp(timing.TimingMode, {'INITIALIZE', 'TERMINATE'}));
                   % do we need an extra rate guard to make sure we don't log
                   % too much data in the single tasking case
                   needSingleTaskingRateGuard = ~isSampleTimeIndependent && ...
                       ~isMultiTasking && ...
                       ~isConstSampleTime && ...
                       ~isExportFcnDiagram && ...
                       ~isAsyncSampleTime && ...
                       ~isEventSampleTime;
                   if needSingleTaskingRateGuard
                       [sampleHitCExpr, sampleTimeIndexCExpr] = this.getRateSampleHitCExpr(timing);
                       this.writer.wBlockStart(['if (' sampleHitCExpr ')']);
                       % use rate specific time
                       timeVarName = 'rateTime';
                       this.writer.wLine('time_T %s = ssGetTaskTime(S, %s);',...
                           timeVarName, sampleTimeIndexCExpr);
                   else
                       timeVarName = 'taskTime';
                   end
                   if isConstSampleTime || isEventSampleTime
                       this.writer.wBlockStart('');
                   else
                       this.writer.wBlockStart('if (ssGetLogOutput(S))');
                   end
                   % NOTE: time series index is currently always 0
                   this.writer.wComment(lComment);
                   this.writer.wLine('void **pwork = ssGetPWork(S);');
                   if isConstSampleTime || isEventSampleTime || isAsyncSampleTime
                       % isAsyncSampleTime is needed with client/server
                       this.writer.wLine('time_T %s = ssGetT(S);', timeVarName);
                   end
                   this.writer.wLine('sdiAsyncQueueHandle aSyncQueue = ssGetPWorkValue(S, %s);', pWorkTgtIdx);
                   this.writer.wBlockStart('if (aSyncQueue != NULL)');
                   this.writer.wLine('uint8_T * addr = (uint8_T *)pwork[%s];', pWorkSrcIdx);
                   this.writer.wLine('int offset = *((int*)ssGetPWorkValue(S, %s));', pWorkOffsetIdx);
                   this.writer.wLine('sdiWriteSignal(aSyncQueue, %s, addr + offset);', timeVarName);
                   this.writer.wBlockEnd();
                   if needSingleTaskingRateGuard
                       this.writer.wBlockEnd;
                   end
                   this.writer.wBlockEnd;
               end
               this.writer.wBlockEnd;
               this.writer.wBlockEnd;
           end
       end
       
       function isRtIOStreamCCall = isRtIOStreamCCall(this)
           
            rtIOStream = this.SILPILWrapperUtils.getTargetServices().getRtIOStreamApplicationService().getRtIOStreamInstance();              
            isRtIOStreamCCall = isa(rtIOStream, 'rtw.connectivity.RtIOStreamWrapper');  
        end
      
       function includeHeaders = getRtIOStreamAdditionalIncludeHeaders(this)
           includeHeaders = this.SILPILWrapperUtils.getTargetServices().getRtIOStreamApplicationService().getRtIOStreamInstance().getIncludeHeaders();
       end
          
       function writeSectionPILIOCommandMemUnitTransform...
               (this, ...
                memUnitTypeEnum, ...
                hostPtr, ...
                tgtPtr,...
                outbound,...
                numElements)                
           
           if outbound
               directionEnum='MEM_UNIT_XFORM_OUTBOUND';
           else
               directionEnum='MEM_UNIT_XFORM_INBOUND';
           end
           this.writer.wBlockStart(''); % New scope required for Windows compiler
           memUnitTransformIdExpr = sprintf('MEM_UNIT_XFORM_ID(%s, %s)',...
                                            memUnitTypeEnum, directionEnum);
           this.getPWorkValue('void', 'pMemUnitTransformer', ...
                                      this.getMemUnitTransformerPWorkIdx, true);

           srcPtrStr = sprintf('(void **) &%s', hostPtr);
           dstPtrStr = sprintf('(void **) &%s', tgtPtr);
           
           this.writer.writeLine('memUnitXformer_DoXform');
           this.writer.incIndent;
           this.writer.writeLine('(pMemUnitTransformer, ');
           this.writer.writeLine('%s, ', memUnitTransformIdExpr);
           this.writer.writeLine('%s, %s, %s);', srcPtrStr, dstPtrStr, numElements);
           this.writer.decIndent;
           this.writer.wBlockEnd('');

       end
       
       function writeSectionPILIOCommandCopyData...
               (this, ...
                storageId, ...
                hostPtr, ...
                tgtPtr,...
                isPrototcolData,...
                outbound, ...
                dataElement) 

           this.writer.wBlockStart(''); % New scope required for Windows compiler

           skipMemUnitTransformForProtocolData = this.IsNeededMemUnitXform && ...
               this.getByteReorderingTestMode() && isPrototcolData;           
           if outbound
               srcPtr = hostPtr;
               dstPtr = tgtPtr;
           else
               srcPtr = tgtPtr;
               dstPtr = hostPtr;
           end

           cType = dataElement.HostCType;
           
           if this.IsMexTarget && dataElement.IsEnum
               %If MATLAB Coder and Enum, we need to cast between
               %integer type and enum type (named type).
               
               [~, NamedObject] = ...
                   rtw.connectivity.CodeInfoTypeUtils.getCodeInfoStoredValueDTypeId(dataElement.getType);
               
               if outbound
                   srcTypeName = NamedObject;
                   dstTypeName = cType;
               else
                   srcTypeName = cType;
                   dstTypeName = NamedObject;
               end
               
               this.writer.wBlockStart('');
               enumElemIndex = 'enumElemIdx';
               tmpVar = 'enumTmpVar';
               
               this.writer.wLine('int %s;', enumElemIndex);
               this.writer.wBlockStart('for (%s=0; %s<%d; %s++)', ...
                   enumElemIndex, ...
                   enumElemIndex, dataElement.getNumElements, ...
                   enumElemIndex);
               
               isRead = ~outbound;
               skipMemUnitTransform = false;
                   if outbound
                       %Cast and take a copy of source data to get to the
                       %destination data type
                       this.writer.wLine('%s %s = ( %s ) (*(( %s *) %s));', ...
                           dstTypeName, tmpVar, ...
                           dstTypeName, srcTypeName, srcPtr);
                       
                       this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                           sprintf('((uint8_T*)&(%s))',tmpVar), '1', storageId);
                   else
                       
                       this.writer.wLine('%s enumTempVarInt = 0;', cType);
                       this.writer.wLine('%s %s;', dstTypeName, tmpVar);
                       
                       this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                           '((uint8_T*)&(enumTempVarInt))', '1', storageId);
                       
                       %Cast and take a copy of source data to get to the
                       %destination data type
                       this.writer.wLine('%s = ( %s ) ((( %s ) enumTempVarInt));', ...
                           tmpVar, ...
                           dstTypeName, srcTypeName);
                       %Memcpy element into destination pointer. Use memcpy to
                       %avoid any alignment issues.
                       this.writer.wLine('memcpy(( void * ) %s, &%s, sizeof( %s ));', ...
                           dstPtr, tmpVar, dstTypeName);
                   end
                   
                   
                   %Move on "Enum" pointer
                   this.writer.wLine('%s+= sizeof(%s)/sizeof(*%s);', hostPtr, ...
                       NamedObject, hostPtr)
                   
               this.writer.wBlockEnd; %for loop
               
               this.writer.wBlockEnd; %Code block
               
           else
               
               isVarsizeInputTransfer = false;
               if this.IsMexTarget && ...
                       outbound && ...
                       this.codeInfoUtils.isa(dataElement.getDataInterface.getRTWDataInterface.Implementation,'TypedCollection')
                   %Only for MATLAB Coder and Inputs.
                   
                   % For basic data type inputs, MATLAB only allocates
                   % enough memory for the actual input size [for
                   % variable sized arguments], so for XIL we must only
                   % access that valid number of elements, although for
                   % XIL we will still transmit the maximum size for
                   % the input. See G1074493 for more details.
                   
                   isStructElement = dataElement.isStructElement;
                   if ~isStructElement
                       %Applies to all non struct element data
                       dataElementList = dataElement.getDataInterface.getHostDataElements;
                       lastDataElement = dataElementList(end);
                       isVarsizeInputTransfer = (dataElement~=lastDataElement);
                       
                   end
               end
               if isVarsizeInputTransfer
                   
                   %For elements apart from the size (which is
                   %always the last element in a
                   %RTW.TypedCollection)
                   numElementsCopiedVar = 'actualNumElements';
                   
                   sizeFirstElement = this.getIOPortPtr(outbound, ...
                       0, ...
                       lastDataElement);
                   
                   %Modify point pointer return to allow us to get
                   %the first value.
                   if prod(lastDataElement.getDimensions)~=1
                       sizeVarName = regexprep(sizeFirstElement, '^&', '');
                   else
                       %For arrays of size one, CodeInfo returns
                       %the pointer with no index, so need to
                       %explicitly de-reference it. (A known
                       %feature of CodeInfo)
                       sizeVarName = sprintf('*%s',sizeFirstElement);
                   end
                   this.writer.wLine('size_t %s = %s;', ...
                       numElementsCopiedVar, sizeVarName);
                   if outbound && this.IsMexTarget
                       this.writer.wLine('%s *tmpLocalData = (%s *) mxCalloc(%s, sizeof(%s));', cType, ...
                           cType, dataElement.getSymbolicNumElements, cType);                       
                   end
                   
                   if prod(lastDataElement.getDimensions)~=1
                       %If more than one size dimension, need to
                       %calculate the total number of elements
                       this.writer.wLine('size_t nDims = %d;', ...
                           lastDataElement.getDimensions);
                       this.writer.wLine('size_t dim = 1;');
                       
                       this.writer.wBlockStart('for (dim = 1; dim < nDims; ++dim)');
                       indexedSizeVarName = regexprep(sizeVarName,'\[0\]\)$','\[dim\]\)');
                       this.writer.wLine('%s *= %s;', numElementsCopiedVar, indexedSizeVarName);
                       this.writer.wBlockEnd; % for loop
                   end
                   if outbound && this.IsMexTarget
                       this.writer.wLine('memcpy(&(tmpLocalData[0]), %s, (size_t)(%s * sizeof(%s)));', ...
                           srcPtr, numElementsCopiedVar, cType);
                       srcPtr = '&(tmpLocalData[0])';                       
                   end
                   
               end
               
               isVerbose = this.isVerbose();
               if isVerbose 
                   if outbound
                       dataDirectionMessage = 'Copying host to target data: ';                       
                   else
                       dataDirectionMessage = 'Copying target to host data: ';                       
                   end
                   if this.IsMexTarget
                       dataMessage = sprintf('mexPrintf("%s");', dataDirectionMessage);
                   else
                       dataMessage = sprintf('mexPrintf("T=%%ld; %s", (long) ssGetT(S));', dataDirectionMessage);
                   end
               end
               
               
               if this.IsMexTarget
                       if outbound
                           dstPtr = srcPtr;
                       end
                       
                       if isVerbose && outbound
                           % Read/Write API means we need to either check
                           % the data before or after the read/write.
                           this.writeVerboseDataDisplay(dstPtr, ...
                               dataMessage, ...
                               dataElement.getSymbolicNumElements, ...
                               cType);
                       end
                       
                   isRead = ~outbound;
                   this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransformForProtocolData, ...
                           dstPtr, 'num_elements', storageId);
                       
                       if isVerbose && ~outbound
                           this.writeVerboseDataDisplay(dstPtr, ...
                               dataMessage, ...
                               dataElement.getSymbolicNumElements, ...
                               cType);
                       end
                       
                       if outbound && isVarsizeInputTransfer
                           this.writer.wLine('mxFree(tmpLocalData);');
                       end
                   
               else
                   if isVerbose && outbound
                       
                       this.writeVerboseDataDisplay(hostPtr, ...
                           dataMessage, ...
                           dataElement.getSymbolicNumElements, ...
                           cType);
                   end
                   getDataTypeSizeInForLoop = true;
                   if (~dataElement.isStructElement)
                       % Non structure dataElement OR MATLAB coder target
                       getDataTypeSizeInForLoop = false;
                   else
                       [~, ~, IsComplex] = dataElement.getFinalStructElementOffset;
                       % SimStruct APIs are unable to extract Complex data type size.
                       % When Real and Imag parts have the same data type,
                       % cType can be used directly in the optimized for loop for complex data elements.
                       if (dataElement.NumPrevSameAncestorElements==0 ||IsComplex)
                           getDataTypeSizeInForLoop = false;
                       end
                   end
                   
                   if getDataTypeSizeInForLoop
                       % Need a branch here for string element
                       this.writer.wBlockStart('if (ssIsStringDataType(S, elemTypeId))');
                       this.writeSectionXILReadWriteStringCall(~outbound, hostPtr);
                       this.writer.wBlockMiddle('else'); % if (ssIsStringDataType(S, elemTypeId))

                       % we're inside a bus so memUnitEnumType is a call to
                       % simulinkToMemUnitType which can error, make sure
                       % we return early in that case to avoid reading
                       % invalid data
                       elemMemUnitTypeString = 'elemMemUnitType';
                       this.writer.wLine('const mem_unit_type_T %s = simulinkToMemUnitType(S, ssGetDataTypeStorageId(S, elemTypeId));', ...
                           elemMemUnitTypeString);
                       this.writer.wBlockStart('if (elemMemUnitType == MEM_UNIT_INVALID_TYPE)');
                       this.writer.wLine('return%s;', this.ReturnArgString);
                       this.writer.wBlockEnd(); %if (elemMemUnitType == MEM_UNIT_INVALID_TYPE)

                       this.writer.wBlockStart(''); % to scope variables and avoid declaration-after-statement
                       this.writeSectionXILReadWriteCall(~outbound, skipMemUnitTransformForProtocolData, ...
                           hostPtr, 'num_elements', [], elemMemUnitTypeString);
                       this.writer.wBlockEnd; % to scope variables and avoid declaration-after-statement
                       this.writer.wBlockEnd; % else
                   else
                       % Basic data copy
                       if strcmp(cType, 'char_T')
                           %Interface is a string, us string copy API.
                           this.writeSectionXILReadWriteStringCall(~outbound, hostPtr);
                       else

                           this.writeSectionXILReadWriteCall(~outbound, skipMemUnitTransformForProtocolData, ...
                               hostPtr, 'num_elements', storageId);

                       end
                   end

                   if isVerbose && ~outbound
                       this.writeVerboseDataDisplay(dstPtr, ...
                           dataMessage, ...
                           dataElement.getSymbolicNumElements, ...
                           cType);
                   end
               end
           end

           this.writer.wBlockEnd;
       end
       
       function writeSectionXILReadWriteStringCall(this, inbound, hostPtr)
           
           if inbound
               this.writer.wLine('xilReadStringData(S, %s, num_elements);', hostPtr);
           else
               this.writer.wLine('xilWriteStringData(S, %s, num_elements);', hostPtr);
           end
       end
               
       function writeSectionXILRWStringDataFcns(this)
           
               
               bytesVar = 'maxBytesConsumed';

               this.writer.wBlockStart('static boolean_T xilWriteStringData(SimStruct *S, uint8_T *srcPtr, size_t numElements)');
               this.writer.wLine('size_t %s;', bytesVar);
               ioBufferPtrVar = 'IOBufferPtr';
               this.writer.wLine('void* dstPtr = NULL;');
               this.writer.wLine('XIL_IOBuffer_T* %s = NULL;', ioBufferPtrVar);
               this.getPWorkValue('XIL_IOBuffer_T', ioBufferPtrVar, this.getIOBufferPWorkIdx, false);
               this.writer.wLine('%s = numElements * sizeof(char_T);', bytesVar);
               this.writer.wLine('dstPtr = %s->nextMemUnit;', ioBufferPtrVar);
               this.writer.wLine('suWriteSILStringInput((char *)dstPtr, (int32_T)numElements, srcPtr);');
               this.writer.wLine('%s->nextMemUnit =  (uint8_T*)%s->nextMemUnit + (%s/sizeof(uint8_T));', ioBufferPtrVar, ioBufferPtrVar, bytesVar);
               this.writer.wLine('%s->bufferDataSize = (size_t) ((uint8_T*)%s->nextMemUnit - (uint8_T*)%s->data);', ioBufferPtrVar, ioBufferPtrVar, ioBufferPtrVar);
               this.writer.wLine('return XILHOSTAPPSVC_SUCCESS;');
               this.writer.wBlockEnd();

                   
                   
               this.writer.wBlockStart('static boolean_T xilReadStringData(SimStruct *S, uint8_T *dstPtr, size_t numElements)');
               this.writer.wLine('size_t %s;', bytesVar);
               ioBufferPtrVar = 'IOBufferPtr';
               this.writer.wLine('void* srcPtr = NULL;');
               this.writer.wLine('XIL_IOBuffer_T* %s = NULL;', ioBufferPtrVar);
               this.getPWorkValue('XIL_IOBuffer_T', ioBufferPtrVar, this.getIOBufferPWorkIdx, false);
               this.writer.wLine('%s = numElements * sizeof(char_T);', bytesVar);
               this.writer.wLine('srcPtr = %s->nextMemUnit;', ioBufferPtrVar);
                   this.writer.wLine('suWriteSILStringOutput(dstPtr, (char *)srcPtr, (int32_T)numElements);');
               this.writer.wLine('%s->nextMemUnit =  (uint8_T*)%s->nextMemUnit + (%s/sizeof(uint8_T));', ioBufferPtrVar, ioBufferPtrVar, bytesVar);
               this.writer.wLine('IOBufferPtr->bufferDataSize -= maxBytesConsumed;');
               this.writer.wLine('IOBufferPtr->readData = ((IOBufferPtr->bufferDataSize>0)?true:false);');
               this.writer.wLine('return XILHOSTAPPSVC_SUCCESS;');
               this.writer.wBlockEnd();
                   
               end
       
       function writeSectionXILReadFcn(this)
           this.writer.wBlockStart('boolean_T xilReadData(uint8_T *dst, size_t numElements, mem_unit_type_T dataTypeId)');
           transformerVar = 'pMemUnitTransformer';
           skipMemUnitTransform = this.boolToChar(~this.IsNeededMemUnitXform);
           this.writer.wLine('return xilReadDataInternal(dst, numElements, dataTypeId, %s, IOBufferPtr, %s, %s, pXILService);', ...
               skipMemUnitTransform, transformerVar, num2str(this.SILPILWrapperUtils.getMemUnitInfo().memUnitBytes));
           
           this.writer.wBlockEnd;
           end

       function writeSectionXILReadFcnSL(this)
           this.writer.wBlockStart('boolean_T xilReadData(SimStruct *S, uint8_T *dst, size_t numElements, mem_unit_type_T dataTypeId)');
           ioBufferPtrVar = 'IOBufferPtr';
           transformerVar = 'pMemUnitTransformer';
           xilServiceVar = 'pXILService';

           this.writer.wLine('XIL_IOBuffer_T* %s = NULL;', ioBufferPtrVar);
           this.writer.wLine('void* %s = NULL;', transformerVar);
           this.writer.wLine('void* %s = NULL;', xilServiceVar);
           
           this.getPWorkValue('XIL_IOBuffer_T', ioBufferPtrVar, this.getIOBufferPWorkIdx, false);
           this.getPWorkValue('void', transformerVar, this.getMemUnitTransformerPWorkIdx, false);
           this.getPWorkValue('void', xilServiceVar, this.getXILServicePWorkIdx, false);
          
           skipMemUnitTransform = this.boolToChar(~this.IsNeededMemUnitXform);
           this.writer.wLine('return xilReadDataInternal(dst, numElements, dataTypeId, %s, %s, %s, %s, %s);', ...
               skipMemUnitTransform, ioBufferPtrVar, transformerVar, num2str(this.SILPILWrapperUtils.getMemUnitInfo().memUnitBytes), xilServiceVar);

           this.writer.wBlockEnd;
       end
       
       function writeSectionXILWriteFcn(this)
           this.writer.wBlockStart('boolean_T xilWriteData(uint8_T *src, size_t numElements, mem_unit_type_T dataTypeId)');
           transformerVar = 'pMemUnitTransformer';
           skipMemUnitTransform = this.boolToChar(~this.IsNeededMemUnitXform);
           this.writer.wLine('return xilWriteDataInternal(src, numElements, dataTypeId, %s, IOBufferPtr, %s, %s, pXILService);', ...
               skipMemUnitTransform, transformerVar, num2str(this.SILPILWrapperUtils.getMemUnitInfo().memUnitBytes));
           
           this.writer.wBlockEnd;
           end
       
       function writeSectionXILWriteFcnSL(this)
           this.writer.wBlockStart('boolean_T xilWriteData(SimStruct *S, uint8_T *src, size_t numElements, mem_unit_type_T dataTypeId)');
           
           ioBufferPtrVar = 'IOBufferPtr';
           transformerVar = 'pMemUnitTransformer';
           xilServiceVar = 'pXILService';

           this.writer.wLine('XIL_IOBuffer_T* %s = NULL;', ioBufferPtrVar);
           this.writer.wLine('void* %s = NULL;', transformerVar);
           this.writer.wLine('void* %s = NULL;', xilServiceVar);
           
           this.getPWorkValue('XIL_IOBuffer_T', ioBufferPtrVar, this.getIOBufferPWorkIdx, false);
 
           transformerVar = 'pMemUnitTransformer';
           this.getPWorkValue('void', transformerVar, this.getMemUnitTransformerPWorkIdx, false);

           this.getPWorkValue('void', xilServiceVar, this.getXILServicePWorkIdx, false);

           skipMemUnitTransform = this.boolToChar(~this.IsNeededMemUnitXform);
           this.writer.wLine('return xilWriteDataInternal(src, numElements, dataTypeId, %s, %s, %s, %s, %s);', ...
               skipMemUnitTransform, ioBufferPtrVar, transformerVar, num2str(this.SILPILWrapperUtils.getMemUnitInfo().memUnitBytes), xilServiceVar);
           
           this.writer.wBlockEnd;
       end
       
       function writeSectionGetBusElementDimension(this)
           this.writer.wBlockStart('static size_t getBusElementDimension(%s %s DTypeId dType, int_T offsetIdx, const int_T ** dimsOut, int_T * numDims)', ...
               this.SimStructType, this.SimStructArg);
           this.writer.wLine('int_T numDimensions   = ssGetBusElementNumDimensions(%s dType, offsetIdx);', this.SimStructArg);
           this.writer.wLine('const int_T *dims = ssGetBusElementDimensions(%s dType, offsetIdx);', this.SimStructArg);
           this.writer.wLine('size_t numElements = 1;');
           this.writer.wLine('int j = 0;');
           this.writer.wBlockStart('for(j = 0; j< numDimensions; j++)');
           this.writer.wLine('numElements *= dims[j];');
           this.writer.wBlockEnd(); % For loop end
           this.writer.wLine('*dimsOut = dims;');
           this.writer.wLine('*numDims = numDimensions;');
           this.writer.wLine('return numElements;');
           this.writer.wBlockEnd;
       end
       
        function initCallerAndServerFunctions(this)
            % create the data elements for the server and caller functions
            svrFcns = this.SILPILWrapperUtils.getServerFunctionsInfo;
            for fcnIdx = 1:length(svrFcns)
                svrFcns(fcnIdx).createDataElementsForIOArgs(this.SILPILWrapperUtils);
            end

            callerFcns = this.codeInfoUtils.getAllCallerFunctionsInfo;
            for fcnIdx = 1:length(callerFcns)
                callerFcns(fcnIdx).createDataElementsForIOArgs(this.SILPILWrapperUtils);
            end
        end        
       
        function initPWorkInfo(this)
            numPWork = 0;
            
            % profiling data
            isCodeInstrumentationEnabled = this.SILPILWrapperUtils.isCodeInstrumentationEnabled;
            
            % rtiostream data
            RtIOStreamIdx = numPWork;
            numPWork = numPWork + 1;            
            
            % signal and state logging data
            loggingData = this.SILPILWrapperUtils.getLoggingData;
            if ~isempty(loggingData)                
                % pwork size depends on the number sig logs
                loggingLogSize = length(loggingData);                                                
                LoggingElementIdx = numPWork;
                numPWork = numPWork + loggingLogSize;
                LoggingTmpVarIdx = numPWork;
                numPWork = numPWork + loggingLogSize;
                LoggingOffsetVarIdx = numPWork;
                numPWork = numPWork + loggingLogSize;
                IsLoggingActiveIdx = numPWork;
                numPWork = numPWork + 1;
            else
                LoggingElementIdx = -1;
                LoggingTmpVarIdx = -1;
                LoggingOffsetVarIdx = -1;
                IsLoggingActiveIdx = -1;
            end
            
            % shared data stores data
            
            numSharedDataStores = length(this.SILPILWrapperUtils.getDataStoresToTransferInterfaces());
            if numSharedDataStores > 0
                SharedDataStoresIdx = numPWork;
                numPWork = numPWork + numSharedDataStores;
            else
                SharedDataStoresIdx = -1;
            end
            
            % Client/Server: Caller functions arguments
            callerFunctionsInfo = this.codeInfoUtils.getUndefinedCallerFunctionsInfo;
            numCallerFunctions = length(callerFunctionsInfo);
            numArgsForAllCallerFunctions = 0;
            for callFcnIdx = 1:numCallerFunctions
                callerFunctionInfo = callerFunctionsInfo(callFcnIdx);                
                numArgsForAllCallerFunctions = numArgsForAllCallerFunctions +...
                    callerFunctionInfo.getNumInArgs + ...
                    callerFunctionInfo.getNumOutArgs + ...
                    callerFunctionInfo.getNumReturnArg + ...
                    (2*callerFunctionInfo.getNumInOutArgs);
            end
                        
            if numCallerFunctions > 0
                CallerFunctionsIdx = numPWork;
                numPWork = numPWork + numArgsForAllCallerFunctions;
            else
                CallerFunctionsIdx = -1;
            end
            
            % entry for the IOBufferPtr
            IOBufferIdx = numPWork;
            numPWork = numPWork + 1;
            
            SILDebuggingIdx = numPWork;
            numPWork = numPWork + 1;                        
            
            % entry for targetIOFd
            targetIOFdArrIdx = numPWork;
            numPWork = numPWork + 1;
                        
            CommErrorOccurred = numPWork;
            numPWork = numPWork + 1;

            IsXILApplicationStarted = numPWork;
            numPWork = numPWork + 1;
            
            XILUtilsIdx = numPWork;
            numPWork = numPWork + 1;
            
            CommsIdx = numPWork;
            numPWork = numPWork + 1;
            
            ConnectionOptionsIdx = numPWork;
            numPWork = numPWork + 1;
            
            XILServiceIdx = numPWork;
            numPWork = numPWork + 1;

            if isCodeInstrumentationEnabled
                CodeInstrServiceIdx = numPWork;
                numPWork = numPWork + 1;
                
                CodeInstrMultiRunDataIdx = numPWork;
                numPWork = numPWork + 1;

                xilAppDirIdx = numPWork;
                numPWork = numPWork + 1;
            end         
            
            if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
                CoderAssumptionsIdx = numPWork;
                numPWork = numPWork + 1;
            end
            
            % MemUnit Converter
                MemUnitTransformerIdx = numPWork;
                numPWork = numPWork + 1;
            
            pWorkInfo.RtIOStreamIdx = RtIOStreamIdx;
            pWorkInfo.LoggingElementIdx = LoggingElementIdx;
            pWorkInfo.LoggingTmpVarIdx = LoggingTmpVarIdx;
            pWorkInfo.LoggingOffsetVarIdx = LoggingOffsetVarIdx;
            pWorkInfo.IsLoggingActiveIdx = IsLoggingActiveIdx;
            pWorkInfo.SharedDataStoresIdx = SharedDataStoresIdx;
            pWorkInfo.CallerFunctionsIdx = CallerFunctionsIdx;            
            pWorkInfo.IOBufferIdx = IOBufferIdx;
            pWorkInfo.SILDebuggingIdx = SILDebuggingIdx;            
            pWorkInfo.targetIOFdArrIdx = targetIOFdArrIdx;            
            pWorkInfo.CommErrorOccurred = CommErrorOccurred;            
            pWorkInfo.IsXILApplicationStarted = IsXILApplicationStarted;
            pWorkInfo.MemUnitTransformerIdx = MemUnitTransformerIdx;
            pWorkInfo.XILUtilsIdx = XILUtilsIdx;
            pWorkInfo.CommsIdx = CommsIdx;
            pWorkInfo.ConnectionOptionsIdx = ConnectionOptionsIdx;
            pWorkInfo.XILServiceIdx = XILServiceIdx;
            if isCodeInstrumentationEnabled
                pWorkInfo.CodeInstrServiceIdx = CodeInstrServiceIdx;
                pWorkInfo.CodeInstrMultiRunDataIdx = CodeInstrMultiRunDataIdx;
                pWorkInfo.xilAppDirIdx = xilAppDirIdx;
            end
            if this.SILPILWrapperUtils.isCoderAssumptionsEnabled
                pWorkInfo.CoderAssumptionsIdx = CoderAssumptionsIdx;
            end
            
            pWorkInfo.NumPWork = numPWork;
            % initialize property
            this.PWorkInfo = pWorkInfo;            
        end                   
        
        function writeErrorCall(this, errorMessage)
            this.writer.wLine('%s"%s");', this.ErrorFunction, errorMessage);
        end
        
        function lDir = buildFolderAbsoluteDir(this)
            % this method returns the absolute path of the application folder
            componentArgs = this.SILPILWrapperUtils.getComponentArgs();
            appDir = componentArgs.getApplicationCodePath();
            if this.IsMexTarget
                lDir = rtw.pil.Sfunction.escapeCString(appDir);
            else
                lDir = strrep(appDir, '\', '/');
            end
        end        
        
        function setPWorkValue(this, PWorkIdx, VarName)
            if ~this.IsMexTarget
                % Set the required PWork
                this.writer.wLine('ssSetPWorkValue(S, %s, %s);', PWorkIdx, VarName);
            end
        end                
        
        function [returnType, returnArgName, returnArgImpl, isBaseType] = getReturnArgData(this, taskIdx)
            
            returnType = 'void';
            returnArgName = '';
            returnArgImpl = [];
            isBaseType = false;
            
            if this.IsMexTarget
                %Return early. No output for API Based MEX call.
                return;
            end
            
            outputTask = this.SILPILWrapperUtils.getCodeInfoUtils.getOutputTasks();
            
            if ~isempty(outputTask(taskIdx).codeInfoData.ActualReturn)
                returnArgImpl = outputTask(taskIdx).codeInfoData.ActualReturn.Implementation;
                
                storageImplementation = this.SILPILWrapperUtils.getBaseStorageImplementation(returnArgImpl);
                
                % C storage type gives structtype for struct data and
                % complextype for complex data
                storageType = rtw.connectivity.CodeInfoTypeUtils.getCStorageType(...
                    storageImplementation.Type);
                returnType = storageType.Identifier;
                returnArgName = returnArgImpl.Identifier;
                
                isBaseType = ~(storageType.isComplex || storageType.isStructure);

                
            end
        end
        
        %Method determines if current implementation is actually a pointer.
        %This is needed because codeInfo can't directly tell us this
        %information, so we have to implementation in the Prototype Argument
        %list and use it's properties there.
        function isPointer = getArgAccess(this, implementation)
            
            outputTask = this.SILPILWrapperUtils.getCodeInfoUtils.getOutputTasks();
            
            isPointer = false;
            for taskIdx = 1:numel(outputTask)
                
                for idx = 1:numel(outputTask(taskIdx).codeInfoData.ActualArgs)
                    if isequal(outputTask(taskIdx).codeInfoData.ActualArgs(idx).Implementation, implementation)
						%Found a match, so break out of the loop and return
						%the isPointer flag.
                        isPointer = outputTask(taskIdx).codeInfoData.Prototype.Arguments(idx).Type.isPointer;
						break;
                    end
                end
            end            
        end
        
        %Method returns the function arguments for the current list of
        %interfaces. The return is used to create the function definition.
        function functionArgs = getArgStringForInterfaces(this, dataInterfaces, returnArgImpl)
            functionArgs = '';

            for idx = 1:numel(dataInterfaces)
                if returnArgImpl == dataInterfaces(idx).Implementation
                    %Ignore return argument, that is processed elsewhere
                else
                    
                    storageImplementationList = this.SILPILWrapperUtils.getBaseStorageImplementation(dataInterfaces(idx).Implementation);
                    
                    if isempty(storageImplementationList)
                        %An empty storage Implementation means the current
                        %data Interface is a constant input.
                        continue;
                    end
                    
                    for storeImplIdx = 1:numel(storageImplementationList)
                        storageImplementation = storageImplementationList(storeImplIdx);
                        if ~isempty(functionArgs)
                            argSep = ', ';
                        else
                            argSep = '';
                        end
                        
                        % C storage type gives structtype for struct data and
                        % complextype for complex data
                        storageType = rtw.connectivity.CodeInfoTypeUtils.getCStorageType(...
                            storageImplementation.Type);
                        typeIdentifier = storageType.Identifier;
                        % handle multidimensional signals
                        if rtw.connectivity.CodeInfoTypeUtils.isVector(...
                            storageImplementation.Type, ...
                            this.SILPILWrapperUtils.getSILPILInterface.getClientInterface)
                            symbolicNumElements = ...
                                rtw.connectivity.CodeInfoTypeUtils.getSymbolicWidth(...
                                    storageImplementation.Type);
                            storage_size_str = sprintf('[%s]', symbolicNumElements);
                        else
                            storage_size_str = '';
                        end
                        
                        isPtr = getArgAccess(this, dataInterfaces(idx).Implementation);
                        
                        %could use getExpression from codeInfo here, but
                        %need to define and then undef the data
                        dataIdentifier = storageImplementation.Identifier;
                        
                        if isPtr
                            ptrMod = '*';
                        else
                            ptrMod = '';
                        end
                        
                        typeIdentifier = sprintf('%s%s ', ...
                            typeIdentifier, ...
                            ptrMod);
                        varIdWithSize = sprintf('%s%s', ...
                            dataIdentifier, ...
                            storage_size_str);
                        
                        %Add next argument to list of function arguments
                        functionArgs = [functionArgs sprintf('%s%s%s%s', ...
                            argSep, ...
                            typeIdentifier, ...
                            varIdWithSize)]; %#ok<AGROW>
                    end
                end
            end
            if ~isempty(functionArgs)
                %If the function has some arguments pad it.
                functionArgs = sprintf(' %s ', functionArgs);
            end
        end
        
        function writeSectionExportFunctionEnableBody(this, ...
                outputTask)
            % no data transfer for enable fcn
            inportIndices = [];
            paramIndices = [];
            outportIndices = [];
            dsReadIndices = [];
            dsWriteIndices = [];
            sharedLocalDataStoreIndices = [];
            loggingIndices = [];
            inportSizesIndices = [];
            outportSizesIndices = [];
            serverFcnIndex = [];
            
            % use zero-based codeInfoIndex as the tid
            tid = outputTask.id;
            taskTiming = [];
            errorReturn = 'return SS_FCNCALL_ERR;';
            % step
            this.writeSectionPILIOCommand('XIL_ENABLE_COMMAND', ...
                inportIndices, ...
                inportSizesIndices, ...
                paramIndices, ...
                dsReadIndices, ...
                dsWriteIndices, ...
                sharedLocalDataStoreIndices, ...
                outportIndices, ...
                outportSizesIndices, ...
                loggingIndices, ...
                serverFcnIndex, ...
                tid, ...
                taskTiming, ...
                errorReturn);
        end
        
        function writeSectionExportFunctionDisableBody(this, ...
                outputTask)
            inportIndices = this.codeInfoUtils.getInputPortsForTask(outputTask);
            paramIndices = this.getParamIndicesForFunction(outputTask.codeInfoData);
            outportIndices = this.codeInfoUtils.getOutputPortsForTask(outputTask);
            
            % Transfer DataStores for this task
            dsReadIndices =  this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                this.codeInfoUtils.getReaderSharedDataStoresForTask(outputTask), 'dsread');
            dsWriteIndices = this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                this.codeInfoUtils.getWriterSharedDataStoresForTask(outputTask), 'dswrite');
            sharedLocalDataStoreIndices = [];
            
            loggingIndices = [];
            
            % var dims support           
            inportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(outputTask.codeInfoData, 'inputsize');
            outportSizesIndices = this.codeInfoUtils.getDataInterfacesForFunction(outputTask.codeInfoData, 'outputsize');
            serverFcnIndex = [];
            
            % use zero-based codeInfoIndex of function interface as the tid
            tid = outputTask.id;
            taskTiming = [];
            errorReturn = 'return SS_FCNCALL_ERR;';
            % step
            this.writeSectionPILIOCommand('XIL_DISABLE_COMMAND', ...
                inportIndices, ...
                inportSizesIndices, ...
                paramIndices, ...
                dsReadIndices, ...
                dsWriteIndices, ...
                sharedLocalDataStoreIndices, ...
                outportIndices, ...
                outportSizesIndices, ...
                loggingIndices, ...
                serverFcnIndex, ...
                tid, ...
                taskTiming, ...
                errorReturn);
        end
        
        % Helper function to write out call to xilReadData/xilWriteData
        % functions. Abstracts some of the details of the call away,
        % including any protection to prevent byte ordering for testing and
        % determining the default memUnitType.
        function writeSectionXILReadWriteCall(this, isReadCall, skipMemUnitTransform, ...
                dataArgStr, elementCountStr, dataTypeId, memUnitTypeString)

            ioBufferPtrVar = 'IOBufferPtr';
            transformerVar = 'pMemUnitTransformer';
            xilServiceVar = 'pXILService';
            simStructArg = {};

            % directly call the internal implementation as a way to skip 
            % the transform when the read/write APIs would instead use it
            useInternalImplementation = this.IsNeededMemUnitXform && skipMemUnitTransform;

            if ~this.IsMexTarget
                if useInternalImplementation
                    this.getPWorkValue('XIL_IOBuffer_T', ioBufferPtrVar, this.getIOBufferPWorkIdx, true);
                    this.getPWorkValue('void', transformerVar, this.getMemUnitTransformerPWorkIdx, true);
                    this.getPWorkValue('void', xilServiceVar, this.getXILServicePWorkIdx, true);
                else
                    simStructArg = {'S'};
                end
            end
            
            if isReadCall
                if useInternalImplementation
                    xilFcnName = 'xilReadDataInternal';
                else
                    xilFcnName = 'xilReadData';
                end
            else
                if useInternalImplementation
                    xilFcnName = 'xilWriteDataInternal';
                else
                    xilFcnName = 'xilWriteData';
                end
            end
            
            % Determine Mem Unit Data Type string. 
            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo();
            if nargin == 5
                % No type supplied, use default Mem unit type
                memUnitTypeString = rtw.connectivity.TypeUtils.getMemUnitEnumTypeFromStorageId(memUnitInfo.memUnitType);
            elseif nargin == 6
                memUnitTypeString = rtw.connectivity.TypeUtils.getMemUnitEnumTypeFromStorageId(dataTypeId);
            end
            if ~iscell(dataArgStr)
                dataArgStr = {dataArgStr};
                elementCountStr = {elementCountStr};
            end
            
            

            % Insert calls to xil data read/write function
            memUnitBytesString = num2str(this.SILPILWrapperUtils.getMemUnitInfo().memUnitBytes);
            for idx = 1:numel(dataArgStr)
                currDataArgStr = dataArgStr(idx);
                if memUnitInfo.memUnitBytes > 1
                    % cast to uint8_T if the type of argument is greater
                    % than 1 byte
                    currDataArgStr = {sprintf('(%s)%s', 'uint8_T*', dataArgStr{idx})};
                end
                if useInternalImplementation
                    extraArgs = {memUnitBytesString, xilServiceVar};
                    args = strjoin([simStructArg, ...
                        currDataArgStr, elementCountStr(idx), ...
                        {memUnitTypeString}, ...
                        {this.boolToChar(skipMemUnitTransform)}, ...
                        {ioBufferPtrVar}, {transformerVar}, extraArgs], ', ');
                else
                    args = strjoin([simStructArg, ...
                        currDataArgStr, elementCountStr(idx), ...
                        {memUnitTypeString}], ', ');
                end
                this.writer.wBlockStart('if (%s(%s) != XILHOSTAPPSVC_SUCCESS)', xilFcnName, args);
                this.writer.wLine('return%s;', this.ReturnArgString);
                this.writer.wBlockEnd();
            end            
        end
        
        function writeXILHostInterfaceHeader(this, hostInterfaceHeaderFile)
            % Write Host Interface header file
            
            headerPath = fileparts(this.getSfunSourcePath);
            hWriter = coder.internal.connectivity.HostInterfaceHeaderWriter(headerPath, ...
                hostInterfaceHeaderFile);
            append = false;            
            callCBeautifier = true;
            obfuscateCode = this.SILPILWrapperUtils.shouldObfuscateXILWrapperFiles;
            hWriter.writeOutput(append, callCBeautifier, obfuscateCode);
        end
        
        function setFreedPWorkValueToNull(this, pWorkName, pWorkIdx)
            % Ensure Pwork value is reset to NULL to allow safe checking G1330071
            this.setPWorkValue( pWorkIdx, 'NULL');
            if this.IsMexTarget
                this.writer.wLine('%s = NULL;', pWorkName);
            end
        end
        
        function writeCallToMEXAPITerminateFunction(this)
            % Before throwing an error to terminate the XIL MEX, call the
            % MEX API terminate function to clean up memory there.
            if this.IsMexTarget
                % Ensure MEX API memory is tidied up. See G1350607
                this.writer.wBlockStart('if (!executingClearMEX)');
                this.writer.wComment('About to throw an error, call MEX API terminate function, unless MEX is clearing');
                this.writer.wLine('(*cleanUp)();');                
                this.writer.wBlockEnd; %MEX is clearing.
            end
        end
        
        function writeVerboseDataDisplay(this, dataPtr, dataMessage, numElements, cType)
            this.writer.wBlockStart('');
            this.writer.wLine('int elementIdx;');
            this.writer.wLine(dataMessage);
            this.writer.wBlockStart('for (elementIdx = 0; elementIdx < %s * sizeof(%s); elementIdx++)', numElements, cType);
            this.writer.wLine(['mexPrintf("%u, ", (unsigned int) (' dataPtr ')[elementIdx]);']);
            this.writer.wBlockEnd;
            this.writer.wLine('mexPrintf("\n");');
            this.writer.wBlockEnd;
        end
        
        function writeSectionXILInitializeHost(this)
            this.writer.wBlockStart('void xilInitializeHost(void (*cleanUpArg)(void))');
            this.writer.wLine('cleanUp = cleanUpArg;');
            this.writer.wLine('mdlInitializeSizes();');
            this.writer.wLine('mdlSetupRuntimeResources();');
            this.writer.wLine('mdlStart();');
            this.writer.wBlockEnd(); %xilInitializeHost function
        end
        
        function allOutportSizesData = writeSectionXILPreEntryPointHost(this, ...
                PILCommand, ...
                inportIndices, ...
                inportSizesIndices, ...
                paramIndices, ...
                dsReadIndices, ...
                outportSizesIndices, ...
                serverFcnIndex,...
                taskId, ...
                taskTiming, ...
                errorReturn)
            
            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;            
            
            % Get all the dataInterfaces (and their total number of MemUnits) that we
            % want to transfer from the host to the target.
            %
            % NOTE: The reason we pass outportSizesIndices is because
            % outport sizes are transferred both from the host to the
            % target and from the target to the host!
            [~,...
                totalSymbolicHostToTargetBufferMemUnits, ...
                commandData,...
                allInportData,...
                allInportSizesData,...
                allOutportSizesData,...
                allParamData,...
                allDSReadData,...
                allServerFcnInputArgsData, ...
                internalData, ...
                commandDataSize] =...
                this.getAllHostToTargetDataInterfaces(...
                PILCommand,...
                inportIndices, ...
                inportSizesIndices, ...
                outportSizesIndices, ...
                paramIndices, ...
                dsReadIndices, ...
                serverFcnIndex, ...
                taskTiming);
            
            if memUnitInfo.supportsOnlyByteIO && 1 ~= memUnitInfo.memUnitBytes
                % byte I/O
                % present data as bytes - for word addressable targets,
                % words will have byte order of MATLAB host computer
                dataOutSize = sprintf( ...
                    '(%s) * %d', ...
                    totalSymbolicHostToTargetBufferMemUnits, ...
                    memUnitInfo.memUnitBytes);               
            else
                % mem unit I/O
                % present data as mem units
                dataOutSize = totalSymbolicHostToTargetBufferMemUnits;                
            end
            
            % define memUnitPtr
            this.getPWorkValue('XIL_IOBuffer_T', 'IOBufferPtr', this.getIOBufferPWorkIdx, true);
            
            isVerbose = this.isVerbose();
            if isVerbose
                this.writer.writeLine(['mexPrintf("' PILCommand ':\n");']);
            end
            
           if strcmp(PILCommand,'XIL_INITIALIZE_COMMAND') && ...
                   this.CheckRuntimeOffsetInitWarn && ~this.IsMexTarget
                 % Call into function to check for potential runtime
                 % warnings related to offset initialization
                 this.writer.writeLine('checkRuntimeOffsetInitWarn(S);');
           end

            % IOBufferPtr could be NULL if initialization didn't succeed.
            this.writer.wBlockStart('if (IOBufferPtr != NULL)');
            
            if this.IsMexTarget
                assert(dataOutSize == commandDataSize, ...
                    'Only expect command data for MATLAB Coder');
            end
            % grow I/O buffer
            this.writeSectionPILIOCommandGrowIOBuffer(dataOutSize, errorReturn, isVerbose);
            
            % Reset buffer data size to zero, before adding data
            this.writer.wLine('IOBufferPtr->bufferDataSize = 0;');
            
            this.writer.wBlockStart('if (IOBufferPtr->data != NULL)');
            
            % write command id
            this.writeSectionPILIOCommandWriteCommandId(PILCommand);                      
            
            this.writeSectionPILIOCommandProcessAllHostToTargetData(...
                PILCommand,...
                taskId,...
                commandData,...
                allInportData,...
                allInportSizesData,...
                allOutportSizesData,...
                allParamData,...
                allDSReadData,...
                internalData, ...
                allServerFcnInputArgsData);
                      
            this.writer.wBlockEnd; % scope end
            this.writer.wBlockEnd; % scope end
            this.writer.wBlockEnd; % scope end
        end
        function writeSectionXILEntryPointHost(this, ...
                PILCommand, ...
                outportIndices, ...
                outportSizesIndices, ...
                dsWriteIndices, ...
                sharedLocalDataStoreIndices, ...
                loggingIndices, ...
                serverFcnIndex,...
                taskId, ...
                allOutportSizesData, ...
                errorReturn)
            
            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
            
            this.writer.wBlockStart('');
            
            % Get all the DataInterfaces (and their total number of MemUnits) that we
            % want to transfer from the target to the host.
            [allOutportData,...
                allDSWriteData,...
                sharedLocalDataStoreElements,...
                signalLoggingData,...
                stateLoggingData,...
                allServerFcnOutputArgsData,...
                ~,... % totalTargetToHostBufferMemUnits,...
                totalSymbolicTargetToHostBufferMemUnits] = ...
                this.getAllTargetToHostDataInterfaces(...
                outportIndices, ...
                outportSizesIndices,...
                dsWriteIndices, ...
                sharedLocalDataStoreIndices, ...
                this.codeInfoUtils.getSignalLoggingIndices(loggingIndices), ...
                this.codeInfoUtils.getStateLoggingIndices(loggingIndices), ...
                serverFcnIndex);
            
            % get command id
            processResponseTypeSize = strcmp(PILCommand, 'XIL_INIT_COMMAND');
                                   
            if strcmp('0',totalSymbolicTargetToHostBufferMemUnits) && ~this.IsMexTarget
                %Never process outputs if no data or using Read Write API
                processResponseOutput = false;
            else
                processResponseOutput = true;
            end
            
            % define memUnitPtr
            mxCTypeMemUnit =  rtw.connectivity.TypeUtils.builtinToHostCType(memUnitInfo.memUnitType);
            this.getPWorkValue('XIL_IOBuffer_T', 'IOBufferPtr', this.getIOBufferPWorkIdx, true);
            
            isVerbose = this.isVerbose();
            if isVerbose
                this.writer.writeLine(['mexPrintf("' PILCommand ':\n");']);
            end            
            
            % provide the time information to the code
            % instrumentation app service
            if this.SILPILWrapperUtils.isCodeInstrumentationEnabled
                this.writeSectionCodeInstrServiceSetTime(PILCommand);
            end
            
            % dispatch command to the target
            this.writeSectionPILIOCommandCommandDispatch(errorReturn);
            
            
            if ~strcmp(PILCommand,'XIL_SHUTDOWN_COMMAND')
                
                this.writer.wBlockStart('');
                this.writer.writeLine('XILCommandResponseType commandResponseType = XIL_COMMAND_NOT_COMPLETE;');
                
                this.writer.wBlockStart('while (commandResponseType != XIL_STEP_COMPLETE)');
                this.writer.wComment('receive command from the target');
                
                    this.writer.wBlockStart('if (commandResponse(%sIOBufferPtr, &commandResponseType) != XILHOSTAPPSVC_SUCCESS)',...
                    this.SimStructArg);
                if isempty(errorReturn)
                    this.writer.wComment('continue');
                else
                    this.writer.writeLine(errorReturn);
                end
                this.writer.wBlockEnd; % if (commandResponse...)
                
                %
                % process outputs, if required
                %
                    this.writer.wBlockStart('if (IOBufferPtr->readData)');
                
                % define variables
                this.writer.writeLine([mxCTypeMemUnit ' responseId = 0;']);
                
                % define response types
                this.writeSectionPILIOCommandDefineResponseTypes(processResponseTypeSize);
                
                if isVerbose
                    this.writer.writeLine(['mexPrintf("' PILCommand ': processing response...\n");']);
                end
                
                % loop until all data has been processed
                if this.codeInfoUtils.hasUndefinedCallerFunctions
                    % When we process RESPONSE_CS_REQUEST_SERVICE, we re-use
                    % the IOBuffer to send the response down to the target.
                    % Because we re-use the same buffer, we
                    % need another condition to exit this while loop. We
                    % never expect any other data to be in the buffer when
                    % we process RESPONSE_CS_REQUEST_SERVICE.
                    this.writer.wBlockStart(['while ((IOBufferPtr->readData) && '...
                        '(responseId!=RESPONSE_CS_REQUEST_SERVICE))']);
                else
                    this.writer.wBlockStart('while (IOBufferPtr->readData)');
                end
                % process the response id
                this.writer.wComment('read response id');
                isRead = true;
                skipMemUnitTransform = true;
                this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                        '&responseId', '1');
                this.writer.wBlockStart('switch (responseId)');
                
                % Write cases RESPONSE_ERROR, RESPONSE_PRINTF,
                % RESPONSE_FOPEN, RESPONSE_FPRINTF, RESPONSE_SIGNAL_RAISED
                this.writeSectionPILIOCommandErrorAndTargetIOResponseCases(errorReturn);
                
                % write case RESPONSE_OUTPUT_DATA:
                if processResponseOutput
                    if isVerbose
                        if memUnitInfo.supportsOnlyByteIO && 1 ~= memUnitInfo.memUnitBytes
                            % byte I/O
                            % present data as bytes - for word addressable targets,
                            % words will have byte order of MATLAB host computer
                            expectedResponseOutputSymbolicSize = sprintf( ...
                                '(%s) * %d', ...
                                totalSymbolicTargetToHostBufferMemUnits, ...
                                memUnitInfo.memUnitBytes);
                        else
                            % mem unit I/O
                            % present data as mem units
                            expectedResponseOutputSymbolicSize = ...
                                totalSymbolicTargetToHostBufferMemUnits;
                        end
                        verboseOutput = ['mexPrintf("' PILCommand ...
                            ': RESPONSE_OUTPUT_DATA, (1 + ' ...
                            expectedResponseOutputSymbolicSize ') * ' ...
                            memUnitInfo.ioDataType '\n");'];
                    else
                        verboseOutput = [];
                    end
                    this.writeSectionPILIOCommandOutputDataResponseCase(...
                        taskId, ...
                        allOutportData,...
                        allOutportSizesData,...
                        allDSWriteData,...
                        sharedLocalDataStoreElements,...
                        signalLoggingData,...
                        stateLoggingData, ...
                        allServerFcnOutputArgsData, ...
                        verboseOutput, ...
                        errorReturn);
                end
                
                % write case RESPONSE_TYPE_SIZE:
                if processResponseTypeSize
                    this.writeSectionPILIOCommandTypeSizeResponseCase(...
                        mxCTypeMemUnit,errorReturn);
                end
                
                % process caller functions
                if this.canProcessCallerFunctions(PILCommand)
                    % write case RESPONSE_CS_REQUEST_SERVICE:
                    this.writeSectionPILIOCommandCSRequestServiceResponseCase(...
                        errorReturn, isVerbose);
                end
                
                this.writer.wBlockStart('default:');
                
                % throw error
                this.writeError(errorReturn, ...
                    'PIL:pilverification:UnknownResponseId', ...
                    'mxCreateDoubleScalar(responseId)');
                
                this.writer.writeLine('break;');
                this.writer.wBlockEnd; % default end
                this.writer.wBlockEnd; % switch end
                this.writer.wBlockEnd; % while end - loop until all data has been processed
                this.writer.wBlockEnd; % dataInSize end
                
                
                this.writer.wBlockEnd; % while (commandResponseType != XIL_STEP_COMPLETE)
                
                this.writer.wBlockEnd; % scope end around commandResponseType
            end %In SHUTDOWN
            
            this.writer.wBlockEnd; % scope end
        end
        
        function writeSectionXILPostEntryPointHost(this, ...
                PILCommand, ...
                errorReturn)
            
            narginchk(2, 3);
            if nargin < 3
                errorReturn = sprintf('return%s;', this.ReturnArgString);
            end
            
            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;            
            
            % get command id
            processResponseTypeSize = strcmp(PILCommand, 'XIL_INIT_COMMAND');
            

            % define memUnitPtr
            mxCTypeMemUnit =  rtw.connectivity.TypeUtils.builtinToHostCType(memUnitInfo.memUnitType);
            this.getPWorkValue('XIL_IOBuffer_T', 'IOBufferPtr', this.getIOBufferPWorkIdx, true);
            
            isVerbose = this.isVerbose();
            if isVerbose
                this.writer.writeLine(['mexPrintf("' PILCommand ':\n");']);
            end           
            
                
            %
            % Process any further commands from target
            %
                this.writer.wBlockStart('if (IOBufferPtr->readData)');
            
            % define variables
            this.writer.writeLine([mxCTypeMemUnit ' responseId = 0;']);
            
            % define response types
            this.writeSectionPILIOCommandDefineResponseTypes(processResponseTypeSize);
            
            if isVerbose
                this.writer.writeLine(['mexPrintf("' PILCommand ': processing response...\n");']);
            end
            
            % loop until all data has been processed
            if this.codeInfoUtils.hasUndefinedCallerFunctions
                % When we process RESPONSE_CS_REQUEST_SERVICE, we re-use
                % the IOBuffer to send the response down to the target.
                % Because we re-use the same buffer, we
                % need another condition to exit this while loop. We
                % never expect any other data to be in the buffer when
                % we process RESPONSE_CS_REQUEST_SERVICE.
            this.writer.wBlockStart(['while ((IOBufferPtr->readData) && '...
                    '(responseId!=RESPONSE_CS_REQUEST_SERVICE))']);
            else
                    this.writer.wBlockStart('while (IOBufferPtr->readData)');
            end
            % process the response id
            this.writer.wComment('read response id');
            isRead = true;
            skipMemUnitTransform = true;
            this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                    '&responseId', '1');
            this.writer.wBlockStart('switch (responseId)');
            
            % Write cases RESPONSE_ERROR, RESPONSE_PRINTF,
            % RESPONSE_FOPEN, RESPONSE_FPRINTF, RESPONSE_SIGNAL_RAISED
            this.writeSectionPILIOCommandErrorAndTargetIOResponseCases(errorReturn);
            
            
            % write case RESPONSE_TYPE_SIZE:
            if processResponseTypeSize
                this.writeSectionPILIOCommandTypeSizeResponseCase(...
                    mxCTypeMemUnit,errorReturn);
            end
            
            % process caller functions
            if this.canProcessCallerFunctions(PILCommand)
                % write case RESPONSE_CS_REQUEST_SERVICE:
                this.writeSectionPILIOCommandCSRequestServiceResponseCase(...
                    errorReturn, isVerbose);
            end
            
            this.writer.wBlockStart('default:');
            
            % throw error
            this.writeError(errorReturn, ...
                'PIL:pilverification:UnknownResponseId', ...
                'mxCreateDoubleScalar(responseId)');
            
            this.writer.writeLine('break;');
            this.writer.wBlockEnd; % default end
            this.writer.wBlockEnd; % switch end
            this.writer.wBlockEnd; % while end - loop until all data has been processed
            this.writer.wBlockEnd; % dataInSize end
        end
        
        function canProcessCallFunctions = canProcessCallerFunctions(this, PILCommand)
            canProcessCallFunctions = this.codeInfoUtils.hasUndefinedCallerFunctions && ...
                        (strcmp(PILCommand, 'XIL_OUTPUT_COMMAND') || ...
                         strcmp(PILCommand, 'XIL_INITIALIZE_COMMAND') || ...
                        (this.HasModelWideEvents && ...
                        (strcmp(PILCommand, 'XIL_INITIALIZE_COMMAND') || ...
                        strcmp(PILCommand, 'XIL_TERMINATE_COMMAND') || ...
                        strcmp(PILCommand, 'XIL_SYSTEM_INITIALIZE_COMMAND'))));
        end
        
        
        function lNeedToTransformThisDataInterface = IsRowMajorTransformNeededForThisDataInterface(this, dataInterface)
            lImpl = dataInterface.getRTWDataInterfaceImplementation;
            if this.codeInfoUtils.isa(lImpl, 'CustomVariable')
                % Row-major transformation for TLC-based CSCs is
                % defined by the layout specification on in the TLC.
                lDataInterfaceIsCandidateForTransform = strcmp(lImpl.Layout, 'row-mat');
            else
                lDataInterfaceIsCandidateForTransform = this.IsRowMajorTransformNeeded;
                if dataInterface.IsImageInterface
                    lDataInterfaceIsCandidateForTransform = false;
                end
            end
            
            if lDataInterfaceIsCandidateForTransform
                % Transform is only needed for buses and multi-dimensional
                % data.
                % 
                % Checking for nDims == 1 avoids processing of types which 
                % only have a single dimension, which includes string data. 
                % This avoids the need to keep track of the dynamically 
                % allocated data type id for the string data type, which 
                % is required by the row major transform utilities.
                % 
                % Note: to easily support symbolic dimensions of [A B] we 
                % do not optimize for explicit row / column vectors like 
                % [1 10] or [10 1] at this time. Regular vector dimensions 
                % like [10] are optimized though.
                %
                % Strings inside of buses are processed via the usual 
                % transform which queries the data type table for the 
                % elements within the bus.
                %
                
                needToTransformThisType = ...
                    rtw.pil.Sfunction.IsRowMajorTransformNeededForThisType(dataInterface.getHostType());
                lNeedToTransformThisDataInterface = any(needToTransformThisType);
                if ~isscalar(needToTransformThisType)
                    assert(this.codeInfoUtils.isa(lImpl, 'TypedCollection'), ...
                        'Non-scalar types should be associated to TypedCollection');
                    if lNeedToTransformThisDataInterface                                              
                        error = MSLException( ...
                            'PIL:pil_subsystem:UnsupportedRowMajorMuxedPort', ...
                            this.SILPILWrapperUtils.getComponentForDiagnostics(), ...
                            dataInterface.getString(this.SILPILWrapperUtils));
                        error.throw();
                    end
                end
            else
                lNeedToTransformThisDataInterface = false;
            end
        end
        
        % StructParams are handled specially - we get the datatype id from
        % the parameter itself
        function writeSectionStructParamDatatypeId(this, sfunParamIdx, type)
            this.writeStructParamDtChecksum(type);
            this.writer.writeLine('DTypeId dataTypeId = INVALID_DTYPE_ID;');            
            this.writer.writeLine(['ssGetSFcnParamDataType(S, ' ...
                                   sfunParamIdx ', &dataTypeId);']);
            this.writer.writeLine('if (dataTypeId == INVALID_DTYPE_ID) return;');
            % validate the type against the checksum
            this.writer.writeLine(['ssCheckStructParamChecksum(S, ' sfunParamIdx ', dtChecksum);']);
        end
        
        function writeStructParamDtChecksum(this, type)            
            % write out the checksum value for a Bus or Struct
            
            assert(rtw.connectivity.CodeInfoTypeUtils.isBusOrStruct(type), ...
                'Type must be bus / struct to get checksum');
            baseType = rtw.connectivity.CodeInfoTypeUtils.getBaseType(type);
            dtChecksum = baseType.Checksum;
            
            % write out the checksum value            
            this.writer.writeLine(['uint32_T dtChecksum[4] = {' ...
                int2str(dtChecksum(1)) 'U, ' ...
                int2str(dtChecksum(2)) 'U, ' ...
                int2str(dtChecksum(3)) 'U, ' ...
                int2str(dtChecksum(4)) 'U};']);                                             
        end
        function initializeTypeSupport(this)
            
            if ~this.IsMexTarget                                              
                codeDescriptorUtils = this.getCodeInfoUtils;
                % check to see if we need to transform data to row major
                % ordering. When the data type preserves dimensions it
                % is implicitly row major.
                this.IsRowMajorTransformNeeded = codeDescriptorUtils.IsRowMajor;
                
                this.SupportImages = codeDescriptorUtils.HasImageTypes;
                this.SupportHalf = codeDescriptorUtils.HasHalfTypes;
            end
        end
                
        function writeSectionDeleteCachedPILInterface(this)
            if this.SILPILWrapperUtils.getSILPILInterface().shouldRemoveCachedPILInterface()
                numRHS = 3;
                this.getPWorkValue('void', this.XILUtilsVarName, this.getXILUtilsPWorkIdx, true);
                this.writer.wBlockStart('if (%s)', this.XILUtilsVarName);
                this.writer.writeLine(['mxArray *rhs[' int2str(numRHS) '];']);
                this.writeCallMATLABTypeAndPathInputs( 0 );
                % rhs will get freed automatically by xilUtilsCallMATLAB
                this.writer.wLine('xilUtilsCallMATLAB(%s, 0, NULL, %d, rhs, "rtw.pil.SILPILInterface.sfunctionDeletePILDataHook");', ...
                    this.XILUtilsVarName, numRHS);
                this.writer.wBlockEnd(); % if
            end
        end

        function wLineVerboseString(this, message)
            if this.isVerbose()
                this.writer.wLine('mexPrintf("%s\\n");', message);
            end
        end

        function processTargetIOData(this, bufferName, sizeName)
            isByteAddressable = this.SILPILWrapperUtils.getTargetServices().getDataTypeService().getIsByteAddressable();
            isRead = true;
            if isByteAddressable
                buffAddress = sprintf('&(%s[0])', bufferName);
                skipMemUnitTransform = false;
                this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ... 
                           buffAddress, sizeName);
            else
                memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo;
                memUnitCType = rtw.connectivity.TypeUtils.builtinToHostCType(memUnitInfo.memUnitType);
                this.writer.writeLine('%s *tempBuff;', memUnitCType);
                this.writer.writeLine('tempBuff = (%s *) mxCalloc(%s, sizeof(%s));', ...
                    memUnitCType, sizeName, memUnitCType);
                skipMemUnitTransform = true;
                this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                    '&(tempBuff[0])', sizeName);

                this.writer.writeLine('int i;');
                this.writer.wBlockStart(['for(i=0; i<' sizeName '; i++)']);
                this.writer.writeLine('%s[i] = (uint8_T) (tempBuff)[i];', bufferName);
                this.writer.wBlockEnd;
                this.writer.writeLine('mxFree(tempBuff);');
            end
        end

        function writeSectionCustomLUTSerializer(this, implementation)
            % Write a serializer for parameterized LUT objects, i.e. buses
            % with pointer elements

            highType = implementation.Type;
            if highType.isMatrix()
                highType = highType.BaseType;
            end
            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo();
            simDataCType = memUnitInfo.ioDataType;

            this.writer.wLine('DTypeId lutDataType = ssGetDataTypeId(S, "%s");', highType.Name);
            this.writer.wLine('%s * simDataMemUnitPtr;', simDataCType);
            this.writer.writeLine('slDataTypeAccess * dta = ssGetDataTypeAccess(S);');
            this.writer.writeLine('const char * bpath = ssGetPath(S);');
            numElementsVar = 'numElements';

            % loop over the number of elements in the LUT/bus
            this.writer.wBlockStart('for(uint32_T offsetIdx=0; offsetIdx< %d; offsetIdx++)', ...
                length(highType.Elements));
            
            this.writer.wLine('size_t %s;', numElementsVar);
            this.writer.wLine('const int_T * busElementsDims;');
            this.writer.wLine('int_T busElementNumDims;');
            this.writer.wLine('DTypeId elemTypeId = ssGetBusElementDataType(S, lutDataType, offsetIdx);');
            % update simDataMemUnitPtr to point to the current element
            this.writer.wLine('simDataMemUnitPtr = (%s *)dataInterfacePtr;', simDataCType);
            this.writer.wLine(['simDataMemUnitPtr = (%s *) (((char *)simDataMemUnitPtr) +' ...
                'dtaGetDataTypeElementOffset(dta, bpath, lutDataType, offsetIdx));'], simDataCType);
            
            % deal with pointer elements
            this.writer.wBlockStart('if (ssIsPointerDataType(S, elemTypeId))');
            this.writer.wLine('DTypeId pointerTypeId = elemTypeId;');
            this.writer.wLine('size_t complexFac = ssGetPointerContainedDataComplexity(S, pointerTypeId) ? 2:1;');
            this.writer.wLine('%s = ssGetPointerContainedDataWidth(S, pointerTypeId, simDataMemUnitPtr) * complexFac;', numElementsVar);
            this.writer.wLine('elemTypeId = ssGetPointerContainedDataType(S, pointerTypeId);');
            this.writer.wLine('simDataMemUnitPtr = (%s*)ssGetPointerContainedData(S, pointerTypeId, simDataMemUnitPtr);', simDataCType);
            % deal with non-pointer elements
            this.writer.wBlockMiddle('else');
            this.writer.wLine('%s = getBusElementDimension(%s lutDataType, offsetIdx, &busElementsDims, &busElementNumDims); ', numElementsVar, this.SimStructArg);
            this.writer.wBlockEnd(); % else
            
            % get the memUnitType for the data of the current element
            this.writer.wBlockStart(''); % scope 1
            elemMemUnitTypeString = 'elemMemUnitType';
            this.writer.wLine('const mem_unit_type_T %s = simulinkToMemUnitType(S, ssGetDataTypeStorageId(S, elemTypeId));', ...
                elemMemUnitTypeString);
            this.writer.wBlockStart('if (%s == MEM_UNIT_INVALID_TYPE)', elemMemUnitTypeString);
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd(); %if (elemMemUnitType == MEM_UNIT_INVALID_TYPE)
            this.writer.wBlockStart(''); % scope 2
            
            % serialize data of the current element
            isRead = false;
            skipMemUnitTransform = false;
            this.writeSectionXILReadWriteCall(isRead, skipMemUnitTransform, ...
                'simDataMemUnitPtr', numElementsVar, [], elemMemUnitTypeString);
            this.writer.wBlockEnd(); % scope 2
            this.writer.wBlockEnd(); % scope 1
            this.writer.wBlockEnd(); % for

        end

        function writeOpaqueRegionSerDeserForCoderArray(this, rtwDataInterface, isHostToTarget)
            % Setup arguments for Coder Array serializer/deserializer and
            % invoke API. 
            % Call site has the following prototype:
            % xilHostSerializer(S, simDataMemUnitPtr, dtId); or
            % xilHostDeserializer(S, simDataMemUnitPtr, dtId); where
            % - S, is the SimStruct argument
            % - simDataMemUnitPtr, is a "ioDataType" pointer to a data 
            %   source or destination (e.g. an input port or an output port).
            %   Takes the same address of "dataInterfacePtr" which is set
            %   before calling this method.
            % - dtId, is a DTypeId with the data type id registered for a
            %   specific dynamic array type. It can be obtained by
            %   registering the dynamic type.

            implementation = rtwDataInterface.Implementation;
            opaqueRegion = implementation.OpaqueRegion;
            if isHostToTarget
                rwApi = opaqueRegion.SerializeInputData.getFunctionCall(rtwDataInterface, coder.descriptor.HostOrTargetEnum.Host);
            else
                rwApi = opaqueRegion.DeserializeOutputData.getFunctionCall(rtwDataInterface, coder.descriptor.HostOrTargetEnum.Host);
            end
            % argument r should be simDataMemUnitPtr
            memUnitInfo = this.SILPILWrapperUtils.getMemUnitInfo();
            simDataCType = memUnitInfo.ioDataType;
            this.writer.wLine('%s * simDataMemUnitPtr;', simDataCType)

            if ~rtw.connectivity.CodeInfoUtils.isBusWithCoderArrayElement(implementation.CodeType)
                this.registerCoderArrayType(rtwDataInterface);
            end
            
            % emit the serializer
            this.writer.wLine('simDataMemUnitPtr = (%s *)dataInterfacePtr;', simDataCType);
            this.writer.wLine('%s', rwApi);
        end

        function writeSectionDefineTmpVarForCoderArrayDsm(this, dataInterface, pWorkIdx)
            % allocate a coder array
            this.writer.wBlockStart('');
            this.writer.wLine('slDataTypeAccess * dta = ssGetDataTypeAccess(S);');
            this.writer.wLine('const char * bpath = ssGetPath(S);');
            this.writer.writeLine('void * tmpVarMemory = NULL;');

            % escape *'s which could incorrectly close the comment
            dataInterfaceString = strrep(dataInterface.getString(this.SILPILWrapperUtils), ...
                '*', '-*-');
            this.writer.wComment(['Tmp var: ' dataInterfaceString]);

            rtwDataInterface = dataInterface.getRTWDataInterface();
            this.registerCoderArrayType(rtwDataInterface);
            % allocate memory to contain 1 object of coder array type
            this.writer.writeLine('tmpVarMemory = calloc(1, dtaGetDataTypeSize(dta, bpath, dtId));');
            this.writer.wBlockStart('if (tmpVarMemory == NULL)');
            this.writeErrorCall('Error in allocating memory for coder::array.');
            this.writer.wLine('return%s;', this.ReturnArgString);
            this.writer.wBlockEnd; % if (tmpVarMemory == NULL)
            % invoke the constructor to instantiate the required
            % coder::array object in the preallocated memory
            this.writer.wLine('ssCreateDynamicArrayForDt(S, dtId, tmpVarMemory);');

            % store in PWork
            this.setPWorkValue(pWorkIdx, 'tmpVarMemory');
            this.writer.wBlockEnd;
        end

        function writeRuntimeChecksForOffsetInitWarn(this)
            % For top-model CodeInterface, when model initialize is invoked
            % at an offset from t=0s, there can be numerical mismatches.
            % When required, implement a runtime check for throwing
            % warnings related to this issue.
            isTopModelXilInterface = isequal(this.SILPILWrapperUtils.getSILPILInterface().getInTheLoopType(), ...
                rtw.pil.InTheLoopType.ModelBlockStandalone);

            if isTopModelXilInterface
                initTask = this.codeInfoUtils.getInitializeTasks();
                dsReadIndices = [];
                for taskIdx = 1:length(initTask)
                    dsReadIndices = [dsReadIndices ...
                        this.SILPILWrapperUtils.getDataStoresToTransferIndices( ...
                        this.codeInfoUtils.getReaderSharedDataStoresForTask(initTask(taskIdx), 'init'), 'dsread')]; %#ok<AGROW>
                end

                isSingleTasking = strcmp(this.SILPILWrapperUtils.getParam('EnableMultiTasking'), 'off');
                isMultiRate = this.codeInfoUtils.isMultiRate();

                hasDSReadDuringInit = ~isempty(dsReadIndices);
                hasTopModelRateScheduler = isSingleTasking && isMultiRate && ~this.codeInfoUtils.isExportFunctions();

                this.CheckRuntimeOffsetInitWarn = hasDSReadDuringInit || hasTopModelRateScheduler;
                if this.CheckRuntimeOffsetInitWarn
                    this.writer.wBlockStart('static void checkRuntimeOffsetInitWarn(SimStruct *S)');
                    this.writer.writeLine('time_T simulationTime = ssGetT(S);');
                    this.writer.wBlockStart('if (simulationTime>0)');
                    modelName = this.SILPILWrapperUtils.getComponentForDiagnostics();
                    if hasDSReadDuringInit
                        this.writeWarning('PIL:pil:TopMdlInitWarnDSReadDuringInit', ...
                            sprintf('mxCreateString("%s")', modelName));
                    end
                    if hasTopModelRateScheduler
                        this.writeWarning('PIL:pil:TopMdlInitWarnTimingMismatch', ...
                            sprintf('mxCreateString("%s")', modelName));
                    end
                    this.writer.wBlockEnd('if (simulationTime>0)');
                    this.writer.wBlockEnd('checkRuntimeOffsetInitWarn(SimStruct *S)');
                end
            end
        end
    end
end

% LocalWords:  Fac
