function onAfterCodeGen(hCS, buildInfo)
%ONAFTERCODEGEN Hook point for after code generation

%   Copyright 2019-2022 The MathWorks, Inc.

data = codertarget.data.getData(hCS);
if isfield(data.Runtime, 'FlashLoad')
    if isequal(data.Runtime.FlashLoad, 1)
        buildInfo.addLinkFlags('--define BOOT_FROM_FLASH');
    end
end

if strcmpi ('CortexM4', codertarget.targethardware.getProcessingUnitName(hCS))
    buildInfo.addDefines('-DCM','SkipForSil');
end

modelName = get_param(getModel(hCS),'Name');
if ~isempty(which('codertarget.tic2000.internal.getRootDir'))
    buildInfo.addIncludePaths(fullfile(codertarget.tic2000.internal.getSpPkgRootDir,'inc'));
end
if isequal(get_param(modelName,'ModelReferenceTargetType'),'NONE')
    addPeripheralDriverFiles(modelName,buildInfo);
end

loc_validateOverrunInterruptFunction(hCS);

codertarget.arm_cortex_m.internal.generateMultiTaskingFunctionARMv7M(hCS, buildInfo);

loc_registerMCANData(hCS,buildInfo);

loc_verifyThirdPartyTools(hCS,buildInfo);

% Check whether in debug mode. Prior to compile stage, we must do this by querying the
% configuration set.
cfgName = get_param(hCS, 'BuildConfiguration');
if isequal(cfgName, 'Specify')
    copts = get_param(hCS, 'CustomToolchainOptions');
    coptKeys = {copts{1:2:end}}; %#ok<CCAT1>
    optionIdx = find(cellfun(@any, strfind(coptKeys,'C Compiler')), 1);
    copts = copts{2*optionIdx};
    if ~isempty(regexp(copts, '(?<!\-)\<-g\>', 'once'))
        buildInfo.addDefines({'-D_DEBUG'});
    end
else
    tcInfo = buildInfo.getBuildToolInfo('ToolchainInfo');
    cfg = tcInfo.getBuildConfigurationNoCheck(cfgName);
    cOptions = cfg.getOption('C Compiler').getValue();
    if ~isempty (find(cellfun(@any, strfind(cOptions, '-g')), 1))
        buildInfo.addDefines({'-D_DEBUG'});
    end
end

% Register Config set data
loc_registerConfigSetData(hCS);

% DDUX Data logging
loc_logDDUXData(hCS, buildInfo);

loc_addExtModePILInfo(hCS, buildInfo);

%Adding 'loc_registerEthernetData' in the end to get TCP/IP communication stage exact in between of
%code generation and build stage
loc_registerEthernetData(hCS,buildInfo);

try
    isESBEnabled = codertarget.utils.isESBEnabled(modelName) && ...
        codertarget.utils.isTaskManagerFound(modelName);
catch
    isESBEnabled = false;
end

pName = 'ESB.ProcessingUnit';
isCLA = codertarget.data.isValidParameter(hCS, pName) && ...
    contains(codertarget.data.getParameterValue(hCS, pName), 'CLA');

% TO DO: Move IPC defines to soc.arm.internal.onAfterCodeGen (g3144521)

if isESBEnabled || isCLA
    soc.arm.internal.onAfterCodeGen(hCS, buildInfo);
end

end

%------------------------------LOG DDUX DATA------------------------------
function loc_logDDUXData(hCS, buildInfo)
try
    supportedTags = codertarget.armM.internal.getSupportedBlockTags();
    dduxObj = matlabshared.internal.SLSPKGUtility(supportedTags);
    modelName = get_param(hCS.getModel, 'Name');
    modeOfOperation = '';
    if isequal(get_param(modelName,'SimulationMode'), 'processor-in-the-loop (pil)') && ...
            codertarget.data.isValidParameter(hCS, 'PIL')
        PILData = codertarget.data.getParameterValue(hCS, 'PIL');
        if isequal(PILData.Interface, 'TCP/IP')
            % Register TCP/IP PIL as mode of operation
            modeOfOperation = 'PIL - TCP/IP';
        elseif isequal(PILData.Interface, 'Serial')
            % Register Serial PIL as mode of operation
            modeOfOperation = 'PIL - Serial';
        end
    end
    if ~isempty (modeOfOperation)
        dduxObj.dataUpdate(hCS, buildInfo.ComponentName, modeOfOperation);
    else
        dduxObj.dataUpdate(hCS, buildInfo.ComponentName);
    end
    delete(dduxObj);
catch
end
end

%--- Function to register the Config set peripherals for DDUX data logging---
function loc_registerConfigSetData(hCS)
modelName = get_param(hCS.getModel, 'Name');
modelHandle = get_param(modelName,'Handle');

% Profiling
if isequal(get_param(hCS,'CodeExecutionProfiling'), 'on')
    profilingEnable = get_param(hCS,'CodeExecutionProfiling');
    codertarget.resourcemanager.set(modelHandle, 'Profiling', 'ProfilingEnable', profilingEnable);
end

% Overrun detection
if isfield(codertarget.data.getData(hCS),'OverRunDetection')
    overrunDetectionData = codertarget.data.getParameterValue(hCS, 'OverRunDetection');
    if isequal(overrunDetectionData.Enable_overrun_detection, 1)
        codertarget.resourcemanager.set(modelHandle, 'OverrunDetection', 'OverrunDetectionEnable', overrunDetectionData.Enable_overrun_detection);
    end
end
end

%% OverrunDetection
% InterruptNumber validation with hardware interrupt.
function loc_validateOverrunInterruptFunction(hCS)
if isfield(codertarget.data.getData(hCS),'OverRunDetection')
    overrunDetectionData = codertarget.data.getParameterValue(hCS, 'OverRunDetection');
    if isfield(overrunDetectionData,'Custom_Logic') &&...
            strcmp(overrunDetectionData.Custom_Logic,'Trigger interrupt')

        if codertarget.resourcemanager.isregistered('', 'ArmCortexMInt', 'ArmCortexMIntblocks',hCS)
            ArmCortexMInt = codertarget.resourcemanager.get('', 'ArmCortexMInt', 'ArmCortexMIntblocks',hCS);
        end

        if ~exist('ArmCortexMInt','var')
            msg = message('TIC2000:codegen:OverrunDetectionARMInterruptConfiguration',str2double(overrunDetectionData.Interrupt_Number));
            sldiagviewer.reportWarning(msg.getString,'MessageId',msg.Identifier);
        elseif ~ismember(overrunDetectionData.Interrupt_Number,ArmCortexMInt)
            msg = message('TIC2000:codegen:OverrunDetectionARMInterruptConfiguration',str2double(overrunDetectionData.Interrupt_Number));
            sldiagviewer.reportWarning(msg.getString,'MessageId',msg.Identifier);
        end
    end
end
end

%% MCAN
% Register MCAN data
function loc_registerMCANData(hCS,buildInfo)
if codertarget.resourcemanager.isregistered('','MCAN', 'MCANRxFIFO0Size',hCS) &&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANRxFIFO1Size',hCS)&&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANStdFiltCount',hCS) &&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANExtFiltCount',hCS) &&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANRxBuffCount',hCS) &&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANTxFIFOElemSize',hCS)&&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANRxFIFO0ElemSize',hCS) &&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANRxFIFO1ElemSize',hCS) &&...
        codertarget.resourcemanager.isregistered('','MCAN', 'MCANRxBuffElemSize',hCS)
    MCANRxFIFO0Size = codertarget.resourcemanager.get('','MCAN', 'MCANRxFIFO0Size',hCS);
    MCANRxFIFO1Size = codertarget.resourcemanager.get('','MCAN', 'MCANRxFIFO1Size',hCS);
    MCANStdFiltCount = codertarget.resourcemanager.get('','MCAN', 'MCANStdFiltCount',hCS);
    MCANExtFiltCount = codertarget.resourcemanager.get('','MCAN', 'MCANExtFiltCount',hCS);
    MCANRxBuffCount = codertarget.resourcemanager.get('','MCAN', 'MCANRxBuffCount',hCS);
    MCANTxFIFOElemSize = codertarget.resourcemanager.get('','MCAN', 'MCANTxFIFOElemSize',hCS);
    MCANRxFIFO0ElemSize = codertarget.resourcemanager.get('','MCAN', 'MCANRxFIFO0ElemSize',hCS);
    MCANRxFIFO1ElemSize = codertarget.resourcemanager.get('','MCAN', 'MCANRxFIFO1ElemSize',hCS);
    MCANRxBuffElemSize = codertarget.resourcemanager.get('','MCAN', 'MCANRxBuffElemSize',hCS);
    buildInfo.addDefines({['-DMW_MCAN_RX_FIFO0_SIZE=' num2str(double(MCANRxFIFO0Size))]});
    buildInfo.addDefines({['-DMW_MCAN_RX_FIFO1_SIZE=' num2str(double(MCANRxFIFO1Size))]});
    buildInfo.addDefines({['-DMW_MCAN_STD_FILT_COUNT=' num2str(double(MCANStdFiltCount))]});
    buildInfo.addDefines({['-DMW_MCAN_EXT_FILT_COUNT=' num2str(double(MCANExtFiltCount))]});
    buildInfo.addDefines({['-DMW_MCAN_RX_BUFF_COUNT=' num2str(double(MCANRxBuffCount))]});
    buildInfo.addDefines({['-DMW_TXELEMETSIZE=' num2str(double(MCANTxFIFOElemSize))]});
    buildInfo.addDefines({['-DMW_RXF0ELEMETSIZE=' num2str(double(MCANRxFIFO0ElemSize))]});
    buildInfo.addDefines({['-DMW_RXF1ELEMETSIZE=' num2str(double(MCANRxFIFO1ElemSize))]});
    buildInfo.addDefines({['-DMW_RXBUFFELEMETSIZE=' num2str(double(MCANRxBuffElemSize))]});
end
end

%% Add peripheral drivers files to build when IPC peripheral is used
function addPeripheralDriverFiles(modelName,buildInfo)
ipcDriverBlocks = findIPCDriverBlocks(modelName);
if ~isempty(ipcDriverBlocks)
    % Add flags to indicate cores involved in IPC
    % IPCBetween = 0 --> c28X CPU1 and c28x CPU2 (CPU1_CPU2_IPC)
    % IPCBetween = 1 --> c28x CPU1 and ARM CPU3 (CPU1_CM_IPC)
    % IPCBetween = 2 --> c28x CPU2 and ARM CPU3 (CPU2_CM_IPC)
    % IPCBetween = 3 --> c28x CPU1 and CPU1 CLA (CPU1_CLA_IPC)
    % IPCBetween = 4 --> c28x CPU2 and CPU2 CLA (CPU2_CLA_IPC)

    % TO DO: Add check if the total buffer allocated size can fit the IPC
    % shared message RAM (g3144492)

    % Counters for the number of IPC channels betweeen cores
    countCPUIPCBlks = 0;
    countCPU1CMBlks = 0;
    countCPU2CMBlks = 0;
    countCPUCLAIPCBlks = 0;

    % List of IPC channel numbers between cores
    ChannelNumCPU = [];
    ChannelNumCPU1CM = [];
    ChannelNumCPU2CM = [];
    ChannelNumCPUCLA = [];

    for i = 1:numel(ipcDriverBlocks)
        IPCBetween = get_param(ipcDriverBlocks{i},'IPCBetween');
        if(IPCBetween == '0')
            addDefines(buildInfo, '-DCPU1_CPU2_IPC','SkipForSil');
            ChannelNumCPU(end + 1) = str2num(get_param(ipcDriverBlocks{i},'ChannelNum'));
        elseif(IPCBetween == '1')
            addDefines(buildInfo, '-DCPU1_CM_IPC','SkipForSil');
            ChannelNumCPU1CM(end + 1) = str2num(get_param(ipcDriverBlocks{i},'ChannelNum'));
        elseif(IPCBetween == '2')
            addDefines(buildInfo, '-DCPU2_CM_IPC','SkipForSil');
            ChannelNumCPU2CM(end + 1) = str2num(get_param(ipcDriverBlocks{i},'ChannelNum'));
        elseif(IPCBetween == '3')
            addDefines(buildInfo, '-DCPU1_CLA_IPC','SkipForSil');
            ChannelNumCPUCLA(end + 1) = str2num(get_param(ipcDriverBlocks{i},'ChannelNum'));
        elseif(IPCBetween == '4')
            addDefines(buildInfo, '-DCPU2_CLA_IPC','SkipForSil');
            ChannelNumCPUCLA(end + 1) = str2num(get_param(ipcDriverBlocks{i},'ChannelNum'));
        end
    end

    % Define macros for the IPC channel lists and IPC channel count between cores

    % Define IPC channel macros for CPU1_CPU2_IPC
    if ~isempty(ChannelNumCPU)
        ChannelNumCPU = sort(unique(ChannelNumCPU));
        ChannelNumCPUString = sprintf('%.0f,',ChannelNumCPU);
        ChannelNumCPUString = ChannelNumCPUString(1:end-1);

        countCPUIPCBlks = numel(ChannelNumCPU);

        addDefines(buildInfo, sprintf(['MW_IPC_CHANNELS_CPU_LIST={' ChannelNumCPUString '}']));
        addDefines(buildInfo, sprintf(['MW_NUM_IPC_CHANNELS_CPU=' num2str(countCPUIPCBlks)]));
    end

    % Define IPC channel macros for CPU1_CM_IPC
    if ~isempty(ChannelNumCPU1CM)
        ChannelNumCPU1CM = sort(unique(ChannelNumCPU1CM));
        ChannelNumCPU1CMString = sprintf('%.0f,',ChannelNumCPU1CM);
        ChannelNumCPU1CMString = ChannelNumCPU1CMString(1:end-1);

        countCPU1CMBlks = numel(ChannelNumCPU1CM);

        addDefines(buildInfo, sprintf(['MW_IPC_CHANNELS_CPU1CM_LIST={' ChannelNumCPU1CMString '}']));
        addDefines(buildInfo, sprintf(['MW_NUM_IPC_CHANNELS_CPU1CM=' num2str(countCPU1CMBlks)]));
    end

    % Define IPC channel macros for CPU2_CM_IPC
    if ~isempty(ChannelNumCPU2CM)
        ChannelNumCPU2CM = sort(unique(ChannelNumCPU2CM));
        ChannelNumCPU2CMString = sprintf('%.0f,',ChannelNumCPU2CM);
        ChannelNumCPU2CMString = ChannelNumCPU2CMString(1:end-1);

        countCPU2CMBlks = numel(ChannelNumCPU2CM);

        addDefines(buildInfo, sprintf(['MW_IPC_CHANNELS_CPU2CM_LIST={' ChannelNumCPU2CMString '}']));
        addDefines(buildInfo, sprintf(['MW_NUM_IPC_CHANNELS_CPU2CM=' num2str(countCPU2CMBlks)]));
    end

    addDefines(buildInfo, sprintf(['MW_NUM_IPC_CHANNELS=' num2str(max([countCPUIPCBlks countCPU1CMBlks countCPU2CMBlks]))]));

    % Define IPC channel macros for CPU1_CLA_IPC and CPU2_CLA_IPC
    if ~isempty(ChannelNumCPUCLA)
        ChannelNumCPUCLA = sort(unique(ChannelNumCPUCLA));
        ChannelNumCPUCLAString = sprintf('%.0f,',ChannelNumCPUCLA);
        ChannelNumCPUCLAString = ChannelNumCPUCLAString(1:end-1);

        countCPUCLAIPCBlks = numel(ChannelNumCPUCLA);

        addDefines(buildInfo, sprintf(['MW_IPC_CHANNELS_CPUCLA_LIST={' ChannelNumCPUCLAString '}']));
    end

    addDefines(buildInfo, sprintf(['MW_NUM_IPC_CHANNELS_CPUCLA=' num2str(countCPUCLAIPCBlks)]));

    % Add source file required for IPC
    buildInfo.addSourceFiles('mw_soc_c2000_ipc.c',fullfile(soc.tic2000.internal.getRootFolder,'src'));
    addDefines(buildInfo, sprintf('IPC_BLOCK_INCLUDED=1'));
end
end

%% Find IPC Driver blocks in SOCB model
function ipcDriverBlocks = findIPCDriverBlocks(modelName)
% Lists IPC driver blocks from referenced models
% This function should be called from top model only
refModels = find_mdlrefs(modelName, 'MatchFilter', @Simulink.match.allVariants);
ipcDriverBlocks = [];
for i = 1:numel(refModels)
    ipcDriverBlocks = [ipcDriverBlocks;find_system(refModels{i},'regexp','on','BlockType','SubSystem','MaskType','Interprocess.+','ReferenceBlock','procinterlib.+')]; %#ok<AGROW>
end
end

%% Ethernet
function loc_registerEthernetData(hCS,buildInfo)
numUdpReceiveBlocks = codertarget.resourcemanager.get('','UDP','numUDPReceiveBlks', hCS);
maxUdpReceiveLength = codertarget.resourcemanager.get('','UDP','MaxReceiveLength', hCS);
maxUdpTransmitLength = codertarget.resourcemanager.get('','UDP','MaxTransmitLength', hCS);
maxTcpReceiveLength = codertarget.resourcemanager.get('','TCP','MaxReceiveLength', hCS);
numTcpReceiveBlocks = codertarget.resourcemanager.get('','TCP','numTCPReceiveBlks', hCS);
numTcpSendBlocks = codertarget.resourcemanager.get('','TCP','numTCPSendBlks', hCS);
numUdpSendBlocks = codertarget.resourcemanager.get('','UDP','numUDPSendBlks', hCS);
isTcpReceiveClientPresent = codertarget.resourcemanager.get('','TCP','isTCPReceiveClient', hCS);
isTcpSendClientPresent = codertarget.resourcemanager.get('','TCP','isTCPSendClient', hCS);
data = codertarget.data.getData(hCS);

ExternModeSelected = get_param(hCS,'ExtMode');
modelCodegenMgr = coder.internal.ModelCodegenMgr.getInstance(getModel(hCS));
xilInfo = modelCodegenMgr.MdlRefBuildArgs.XilInfo;
isPIL = xilInfo.IsPil;


% DHCP extmode, UDP broadcast
if (isPIL && isequal(data.PIL.Interface,'TCP/IP')) ||...
        ((isequal(ExternModeSelected,'on') && (isequal(data.ExtMode.Configuration,'XCP on TCP/IP'))))
    numTcpReceiveBlocks = numTcpReceiveBlocks + 1;
    numTcpSendBlocks = numTcpSendBlocks + 1;
    numUdpSendBlocks =  numUdpSendBlocks + 1;
    numUdpReceiveBlocks = numUdpReceiveBlocks + 1;
end

if ~isempty(numUdpReceiveBlocks)
    buildInfo.addDefines({['-DMW_NUM_UDP_RECEIVE_BLKS=' num2str(double(numUdpReceiveBlocks))]});
    buildInfo.addDefines({['-DMW_UDP_MAX_RECEIVE_LENGTH=' num2str(double(maxUdpReceiveLength))]});
end

if ~isempty(numTcpReceiveBlocks)
    buildInfo.addDefines({['-DMW_NUM_TCP_RECEIVE_BLKS=' num2str(double(numTcpReceiveBlocks))]});
    buildInfo.addDefines({['-DMW_TCP_MAX_RECEIVE_LENGTH=' num2str(double(maxTcpReceiveLength))]});
end

if ~isempty(numTcpSendBlocks)
    buildInfo.addDefines({['-DMW_NUM_TCP_TRANSMIT_BLKS=' num2str(double(numTcpSendBlocks))]});
end

if ~isempty(numUdpSendBlocks)
    buildInfo.addDefines({['-DMW_NUM_UDP_TRANSMIT_BLKS=' num2str(double(numUdpSendBlocks))]});
    buildInfo.addDefines({['-DMW_UDP_MAX_TRANSMIT_LENGTH=' num2str(double(maxUdpTransmitLength))]});
end

if ~isequal(numUdpSendBlocks,0) || ~isequal(numUdpReceiveBlocks,0) || ~isequal(numTcpReceiveBlocks,0) || ~isequal(numTcpSendBlocks,0)
    buildInfo.addDefines({'-DMW_ETH_INIT=1'});
end

% Lwip define to add hostname
if ~isempty(numTcpReceiveBlocks)||~isempty(numUdpReceiveBlocks)
    buildInfo.addDefines({'-DLWIP_NETIF_HOSTNAME=1'});
end

if ~isempty(numTcpReceiveBlocks)||~isempty(numUdpReceiveBlocks)
    MacAddrStr = data.Ethernet.MacAddr;
    mac_octet = strsplit(MacAddrStr,'-');
    if ~isempty(mac_octet)
        addDefines(buildInfo, sprintf('MW_MAC_ADDR1=0x%s', mac_octet{1}));
        addDefines(buildInfo, sprintf('MW_MAC_ADDR2=0x%s', mac_octet{2}));
        addDefines(buildInfo , sprintf('MW_MAC_ADDR3=0x%s', mac_octet{3}));
        addDefines(buildInfo, sprintf('MW_MAC_ADDR4=0x%s', mac_octet{4}));
        addDefines(buildInfo, sprintf('MW_MAC_ADDR5=0x%s', mac_octet{5}));
        addDefines(buildInfo, sprintf('MW_MAC_ADDR6=0x%s', mac_octet{6}));
    end
end
if (isPIL && isequal(data.PIL.Interface,'TCP/IP')) || (isequal(ExternModeSelected,'on') && (isequal(data.ExtMode.Configuration,'XCP on TCP/IP'))) &&...
        ~((numTcpReceiveBlocks > 1) || (numTcpSendBlocks >1) || (numUdpReceiveBlocks > 1) || (numUdpSendBlocks > 1))

    if codertarget.target.isCoderTarget(hCS)
        C2000WarePath = codertarget.tic2000.internal.getThirdPartyToken(hCS, 'Texas Instruments C2000Ware');
    end
    sharedroot = strrep(codertarget.tic2000.internal.getSharedRootDir(),'\','/');
    buildInfo.addSourceFiles('c2838xM4_ethernet_wrapper.c',fullfile(sharedroot,'src'), 'SkipForSil');
    lwiproot = fullfile(C2000WarePath,'libraries','communications','Ethernet','third_party','lwip','lwip-2.1.2');
    buildInfo.addSourceFiles('mem.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('netif.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('tcp_in.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('init.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('memp.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('dhcp.c',fullfile(lwiproot,'src','core','ipv4'), 'SkipForSil');
    buildInfo.addSourceFiles('pbuf.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('timeouts.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('def.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('udp.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('tcp.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('tcp_out.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('ip4_frag.c',fullfile(lwiproot,'src','core','ipv4'), 'SkipForSil');
    buildInfo.addSourceFiles('icmp.c',fullfile(lwiproot,'src','core','ipv4'), 'SkipForSil');
    buildInfo.addSourceFiles('ip.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('ip4.c',fullfile(lwiproot,'src','core','ipv4'), 'SkipForSil');
    buildInfo.addSourceFiles('ip4_addr.c',fullfile(lwiproot,'src','core','ipv4'), 'SkipForSil');
    buildInfo.addSourceFiles('etharp.c',fullfile(lwiproot,'src','core','ipv4'), 'SkipForSil');
    buildInfo.addSourceFiles('stats.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('ethernet.c',fullfile(C2000WarePath,'driverlib','f2838x','driverlib_cm'), 'SkipForSil');
    buildInfo.addSourceFiles('inet_chksum.c',fullfile(lwiproot,'src','core'), 'SkipForSil');
    buildInfo.addSourceFiles('sys_arch.c',fullfile(lwiproot,'ports','C2000'), 'SkipForSil');
    buildInfo.addSourceFiles('f2838xif.c',fullfile(lwiproot,'ports','C2000','netif'), 'SkipForSil');
    buildInfo.addSourceFiles('platform_port.c',fullfile(C2000WarePath,'driverlib','f2838x','driverlib_cm'), 'SkipForSil');
    buildInfo.addSourceFiles('cputimer.c',fullfile(C2000WarePath,'driverlib','f2838x','driverlib_cm'), 'SkipForSil');
end

if isequal(isTcpSendClientPresent,1) || isequal(isTcpReceiveClientPresent,1)
    if isequal(isTcpReceiveClientPresent,1) && isequal(isTcpSendClientPresent,1)
        errorArg = 'TCP Receive and TCP Send blocks';
    elseif isequal(isTcpSendClientPresent,1)
        errorArg = 'TCP Send block';
    elseif isequal(isTcpReceiveClientPresent,1)
        errorArg = 'TCP Receive block';
    end
    communication_stage = sldiagviewer.createStage('TCP/IP Communication','ModelName', get_param(hCS.getModel,'Name'));
    MSLDiagnostic('TIC2000:codegen:SeverWarningInClientMode', errorArg,'TCPClietDiagnostics').reportAsInfo;
    stageCleanup = onCleanup(@() delete(communication_stage));
end
end

% -------------------------Verify 3P tools---------------------------------
function loc_verifyThirdPartyTools(hCS,buildInfo)
if isequal(get_param(hCS,'GenCodeOnly'), 'off')
    % Check tokens for header/source file path
    tokenName = 'C2000WAREINSTALLDIR';
    tpName = 'C2000Ware';
    targetInfo = codertarget.attributes.getTargetHardwareAttributes(hCS);
    tokenRequired = 0;
    for tokenIdx = 1:numel(targetInfo.Tokens)
        if isequal(targetInfo.Tokens{tokenIdx}.Name, tokenName)
            tokenRequired = 1;
        end
    end
    % Verify target xml file
    targetFolder = codertarget.target.getTargetFolder(hCS);
    attribFileName = codertarget.target.getThirdPartyToolsRegistrationFileName(targetFolder);
    thirdPartyFileDoesNotExists = ~isequal(exist(attribFileName, 'file'), 2);
    if thirdPartyFileDoesNotExists
        MSLDiagnostic('TIC2000:codegen:ThirdPartyToolNotSetup',get_param(hCS,'Toolchain')).reportAsError;
    end
    % Verify CGT
    h = codertarget.thirdpartytools.ThirdPartyToolInfo(attribFileName);
    attributes = h.getThirdPartyTools();
    loc_verifySelectedToolchain(hCS, buildInfo, attributes);

    % Verify C2000Ware directory
    tokenFound = 0;
    pathValid = 0;
    if exist(attribFileName, 'file') && tokenRequired
        for i=1:numel(attributes)
            if strcmp(attributes{i}{:}.TokenName, tokenName)
                tokenFound = 1;
                % Check for the given token if path registered is valid
                if (exist(attributes{i}{:}.RootFolder, 'dir') == 7)
                    pathValid = 1;
                end
            end
        end
    end
    if ((tokenFound == 0 || pathValid == 0) && tokenRequired)
        MSLDiagnostic('TIC2000:codegen:ThirdPartyToolNotSetup',tpName).reportAsError;
    end
end
end

% --------------------------Verify CGT-------------------------------------
function loc_verifySelectedToolchain(hCS, buildInfo, attributes)
toolchain = buildInfo.getBuildToolInfo('ToolchainInfo');
path = toolchain.getBuildTool('C Compiler').getPath;
token = regexp(path,'\$\(([a-zA-Z_][\w_]*)\)', 'tokens','once');
if ~isempty(token)
    macro = toolchain.getMacro(token{1});
    if ~isempty(macro)
        compilerToken = regexp(macro,'\$\(([a-zA-Z_][\w_]*)\)','tokens','once');
        if ~isempty(compilerToken)
            isFound = false;
            for j=1:numel(attributes)
                if isequal(attributes{j}{:}.Category,'toolchain') && ...
                        isequal(attributes{j}{:}.TokenName,compilerToken{1})
                    if (exist(attributes{j}{:}.RootFolder, 'dir') == 7)
                        isFound = true;
                    end
                end
            end
            if ~isFound
                MSLDiagnostic('TIC2000:codegen:ThirdPartyToolNotSetup',get_param(hCS,'Toolchain')).reportAsError;
            end
        end
    end
end
end

%% Add external mode and PIL info
% This flags will be used in "MW_f2838x_cm_includes.h" to add UART and UDMA
% specific files
function loc_addExtModePILInfo(hCS, buildInfo)
ExternModeSelected = get_param(hCS,'ExtMode');
modelCodegenMgr = coder.internal.ModelCodegenMgr.getInstance(getModel(hCS));
xilInfo = modelCodegenMgr.MdlRefBuildArgs.XilInfo;
isPIL = xilInfo.IsPil;
if isPIL && codertarget.data.isValidParameter(hCS,'PIL')
    pilData = codertarget.data.getParameterValue(hCS,'PIL');
    if isequal(pilData.Interface,'Serial')
        buildInfo.addDefines({'-DMW_PIL_SERIAL_FLAG=1'});
    end
elseif isequal(ExternModeSelected,'on') &&...
        codertarget.data.isValidParameter(hCS,'ExtMode')
    extModeData = codertarget.data.getParameterValue(hCS,'ExtMode');
    if isequal(extModeData.Configuration,'XCP on Serial')
        buildInfo.addDefines({'-DMW_EXTMODE_SERIAL_FLAG=1'});
    end
end

% Add define statement specific to Profiler
if isequal(strcmp(get_param(hCS,'CodeExecutionProfiling'),'on'),1)
    buildInfo.addDefines('MW_EXEC_PROFILER_ON');
end
if ~isequal(get_param(hCS,'HardwareBoardFeatureSet'),'SoCBlockset')
    % Required for EC only
    loc_addSupportToUseRealTimeInExtMode(hCS,buildInfo);
end

% Manage resources for model references
loc_manageModelReferenceResources(hCS, buildInfo);
end

% --Adds support to use realtime stamp logs during external mode simulation
function loc_addSupportToUseRealTimeInExtMode(hCS,buildInfo)
extModeXcp = isequal(get_param(hCS,'ExtModeMexFile'),'ext_xcp');
enableRealTimeLog = codertarget.data.isValidParameter(hCS,'ExtMode.UseRealtimeStampLogging') ...
    && logical(codertarget.data.getParameterValue(hCS,'ExtMode.UseRealtimeStampLogging'));

if extModeXcp && enableRealTimeLog
    defs = buildInfo.getDefines;
    toremove = contains(defs,'XCP_TIMESTAMP_BASED_ON_SIMULATION_TIME');
    if any(toremove)
        buildInfo.deleteDefines(defs(toremove));
    end
    [timerUnit,timerPreScalar] = codertarget.registry.xcpExternalModeHardwareTimerData(hCS);
    buildInfo.addDefines(['-DMW_TIMER_PRESCALE_FOR_XCP=', num2str(timerPreScalar)], 'SkipForSil');
    buildInfo.addDefines(['-DXCP_TIMESTAMP_UNIT=' timerUnit], 'SkipForSil');
end
end

% ----- Function to save peripheral information of all models to a mat file
% to use the information during code generation and use the defines
% information of all reference model in top model
function loc_manageModelReferenceResources(obj, buildInfo)

if isa(obj, 'Simulink.ConfigSet') || ...
        isa(obj, 'Simulink.ConfigSetRef')
    hCS = obj;
elseif isa(obj,'CoderTarget.SettingsController')
    hCS = obj.getConfigSet;
else
    hCS = getActiveConfigSet(obj);
end

modelName = get_param(hCS.getModel, 'Name');
if isequal(get_param(modelName,'ModelReferenceTargetType'),'NONE')
    % promote defines from ref model to top model
    codeDesc = coder.getCodeDescriptor(modelName);
    refMdls = codeDesc.getReferencedModelNames;
    for i = 1:length(refMdls)
        childMdl = refMdls{i};
        buildDir = RTW.getBuildDir(childMdl);
        buildInfoFile = fullfile(buildDir.CodeGenFolder, buildDir.ModelRefRelativeBuildDir,'buildInfo.mat');
        if isfile(buildInfoFile)
            buildInfoMat = matfile(buildInfoFile);
            defineFlags = getDefines(buildInfoMat.buildInfo);
            toAdd = contains(defineFlags,'-DMW');
            if any(toAdd)
                buildInfo.addDefines(defineFlags(toAdd));
            end
        end
    end
end
end


