function tic2000M4LoadExecutable(LoadCommandArgs,exeFileName,~,hCS,varargin)
% TIC2000M4LOADEXECUTABLE Code executed to download the executable to the target

% Copyright 2019-2022 The MathWorks, Inc.

if nargin < 4
    hCS = getActiveConfigSet(bdroot);
end
tgtInfo = codertarget.targethardware.getTargetHardware(hCS);
tgtAttributes = codertarget.attributes.getTargetHardwareAttributes(hCS);
programFile = exeFileName;

selectedToolChain = get_param(hCS, 'Toolchain');
ctd = get_param(hCS,'CoderTargetData');
allowedToolChains = {tgtInfo.ToolChainInfo(:).Name};
[isMatch, ~] = ismember(selectedToolChain, allowedToolChains);
if (nargin > 5)
    isPIL = varargin{1};
else
    isPIL = 0;
end
if ~isMatch
    % Toolchain is not one of the supported for this target
else
    toolRootDir = codertarget.tic2000.internal.getToolchainScriptingFolder(hCS);
    if (exist(toolRootDir, 'dir') == 7)
        if ispc
            cmd = '$(TARGET_SCRIPTING_ROOT)/bin/dss.bat';
        else
            cmd = '$(TARGET_SCRIPTING_ROOT)/bin/dss.sh';
        end
        cmd = strrep(cmd, '$(TARGET_SCRIPTING_ROOT)', toolRootDir);
        loadCommandArg1 = codertarget.utils.replaceTokens(hCS,LoadCommandArgs, tgtAttributes.Tokens);
        cmdEnd = codertarget.data.getParameterValue(hCS, 'Runtime.LoadCommandArg');
        loadCommandArg2 = codertarget.utils.replaceTokens(hCS, ...
            cmdEnd, tgtAttributes.Tokens);
        loadCommandArg1 = coder.make.internal.transformPaths(loadCommandArg1, 'pathType', 'alternate');
        loadCommandArg2 = coder.make.internal.transformPaths(loadCommandArg2, 'pathType', 'alternate');
        programFile = coder.make.internal.transformPaths(programFile, 'pathType', 'alternate');
        loadCommandArg = [loadCommandArg1 ' ' loadCommandArg2];
        argString = sprintf('%s "%s"', loadCommandArg, programFile);
        argString = [argString ' ' '"*" Cortex_M4_0'];
        cmd = [cmd ' ' argString];
        Simulink.output.info(DAStudio.message('TIC2000:codegen:Executabledownload'));
        % Create a UDP object
        if ~isPIL
            if((isfield(ctd,'Ethernet')) && (isfield(ctd.Ethernet,'DhcpEnabled')) && isequal(ctd.Ethernet.DhcpEnabled,1))
                udpObj = codertarget.asyncioplugins.udp.ByteServer(1100);
                udpObj.NonBlocking = true;
                try
                    open(udpObj);
                catch ME
                    if(strcmp(ME.identifier,'udpserver:open:deviceError'))
                        MSLDiagnostic('TIC2000:codegen:PortOpenFail').reportAsWarning;
                    end
                end
            end
        end
        % hCS.getModel will be empty in case of reference model PIL
        if ~isempty(hCS.getModel)
            %Create a new section in the diagonastic viewer for Deployment
            %stage
            download_stage = sldiagviewer.createStage('Download Executable to Hardware','ModelName', get_param(hCS.getModel,'Name'));
            errArg = ' the ''Download Executable to Hardware'' stage';
        else
            errArg = '';
        end
        [~,msg]=system(cmd,'-echo');
		
		if ~isempty(hCS.getModel)
			stageCleanup = onCleanup(@() delete(download_stage));
        end
        if(~any(strfind(msg,'LOAD & RUN DONE')))
            DAStudio.error('TIC2000:codegen:DownloadCallbackError',errArg);
        end
        % XCP on TCP/IP profiling failing sporadically.
        % After adding a delay similar to concerto load executable started
        % working in consecutive runs
        pause(5);
        if ~isPIL
            if((isfield(ctd,'Ethernet')) && (isfield(ctd.Ethernet,'DhcpEnabled')) && isequal(ctd.Ethernet.DhcpEnabled,1))
                % Read if any UDP data received
                for i = 1:10
                    data = udpObj.read(1);
                    if(~isempty(data))
                        break
                    end
                    pause(1);
                end
    
                if(~isempty(data))
                    % Create and display DHCP assigned IP address
                    ipaddr =  [num2str(data.Data(1)) '.' num2str(data.Data(2)) '.' num2str(data.Data(3)) '.' num2str(data.Data(4))];
                    Simulink.output.info(DAStudio.message('TIC2000:codegen:IPAddressReceived',ipaddr));
                    ExternModeSelected = get_param(hCS,'ExtMode');
                    if  (isequal(ExternModeSelected,'on') && (isequal(ctd.ExtMode.Configuration,'XCP on TCP/IP'))) 
                        % Set ExtModeMexArgs for Ext Mode only: This part
                        % will be used for first time connection
						% hCS unlock and lock are the temporary solution for g2683774. Remove it once the changes reaches to Bembed cluster.
						hCS.unlock 
                        set_param(hCS, 'ExtModeMexArgs',['''' ipaddr '''' [' ' num2str(ctd.ConnectionInfo.XCPonTCPIP.Verbose) ' '] '17725']);
						hCS.lock
                        % ExtModeMexArgs will be empty on Disconnect. The
                        % IP information is set through pref and the same will be used on
                        % connect after disconnect 
                        hardwareBoard = codertarget.data.getParameterValue(hCS,'TargetHardware');
                        coProcessorPattern = '\(\w*\W*\S*';
                        hardwareBoard = strtrim(regexprep(hardwareBoard,  coProcessorPattern,''));
						hardwareBoard = [hardwareBoard ' ' 'ARM'];
                        hardwareBoard = (strrep(hardwareBoard, ' ', '_'));
                        hardwareBoard = (strrep(hardwareBoard, '/', '_'));
                        if~(ispref(hardwareBoard,'IPADDRESS_DHCP'))
                            addpref(hardwareBoard,'IPADDRESS_DHCP',ipaddr);
                        end
                        setpref(hardwareBoard,'IPADDRESS_DHCP',ipaddr);
                    end
                else
                    Simulink.output.info(DAStudio.message('TIC2000:codegen:IPAddressNotReceived'));
                end
                close(udpObj);
            end
        end
    else
        MSLDiagnostic('TIC2000:codegen:ThirdPartyToolNotSetup','TI Code Composer Studio').reportAsError;        
    end
end
