classdef RtIOStreamApplicationFramework < rtw.connectivity.TargetApplicationFramework
%RTIOSTREAMAPPLICATIONFRAMEWORK provides a BUILDINFO for use with SIL/PIL
%
%   RTIOSTREAMAPPLICATIONFRAMEWORK provides a BUILDINFO object containing SIL/PIL
%   specific files (including SIL/PIL main.c) that will be combined, by
%   MAKEFILEBUILDER, with the SIL/PIL component libraries to create the SIL/PIL
%   application.
%
%   You must make a subclass and add source files, libraries, include paths and
%   preprocessor defines required to build an application for the target
%   environment to the BUILDINFO object. The additional files may include code
%   for hardware initialization as well as device driver code for an rtIOStream
%   communications channel.
%
%
%   See also RTW.CONNECTIVITY.MAKEFILEBUILDER, RTW.BUILDINFO,
%   RTW.MYPIL.TARGETAPPLICATIONFRAMEWORK

%   Copyright 2007-2020 The MathWorks, Inc.

    methods
        function this = RtIOStreamApplicationFramework(componentArgs)
            narginchk(1, 1);
            
            % call super class constructor
            this@rtw.connectivity.TargetApplicationFramework(componentArgs);
            %
            % add to the BuildInfo property
            %
            xilSrcPath = this.getXILSrcPath;
            xilAppPath = componentArgs.getApplicationCodePath;            
            
            % get the BuildInfo object to add to
            buildInfo = this.getBuildInfo;
            % get the xil source files and path
            staticXilSrcs = { ...
                'xil_interface_lib.c', ...
                'xil_data_stream.c', ...
                'xil_services.c'};
            staticXilSrcsPath = repmat({xilSrcPath}, size(staticXilSrcs));

            % get the xil header files and path
            staticXilIncls = { ...
                'xil_interface.h', ...
                'xil_interface_common.h', ...
                'xil_interface_lib.h', ...
                'xil_interface_lib_private.h', ...
                'xil_data_stream.h', ...
                'xil_common.h', ...
                'comms_interface.h'};
            staticXilInclsPath = repmat({xilSrcPath}, size(staticXilIncls));

            % get SIL/PIL wrappers source files and path
            targetLang = componentArgs.getParam('TargetLang');
            [sourceFilename, sourceExt] = ...
                rtw.pil.SILPILInterface.getWrapperSourceFilenameAndExt(targetLang);
            xilInterfaceFileName = [sourceFilename sourceExt];
            wrapperXilSrcs = {xilInterfaceFileName};
            wrapperXilSrcsPath = {xilAppPath};
            
            % get <matlabroot>\extern\include
            externIncludesDir = fullfile(matlabroot, 'extern', 'include');
            
            % add communication and application services files
            % When the services manager is available, we should use it to
            % add these files to buildInfo. For PIL over CS, we would need
            % to add the .cpp files not the precompiled lib.
            xilTgtAppSvcIncludeDir = fullfile(externIncludesDir,...
                'coder','connectivity','XILTgtAppSvc');
            % get TgtAppSvc include files and path
            xilTgtAppSvcIncls = { ...
                'XILTgtAppSvc.h', ...
                'XILTgtAppSvc_CInterface.h'};
            xilTgtAppSvcInclsPath = repmat({xilTgtAppSvcIncludeDir}, size(xilTgtAppSvcIncls));
            if rtw.connectivity.Utils.isCommServiceAPIEnabled                
                buildInfo.addSourceFiles('xilcomms_cs.c', xilSrcPath);
                if ispc
                    libFolder = fullfile(matlabroot, 'extern','lib', ...
                        computer('arch'), 'microsoft');
                    ext = '.lib';                    
                else                    
                    libFolder = fullfile(matlabroot, 'bin', computer('arch'));
                    ext=system_dependent('GetSharedLibExt');
                end
                
                commLib = fullfile(libFolder, ['libmwcoder_target_services' ext]);
                xilLib = fullfile(libFolder, ['libmwcoder_XILTgtAppSvc' ext]);
                
                libs = {commLib xilLib};
                rtw.pil.RtIOStreamApplicationFramework.addLibsToBuildInfo(buildInfo, libs);                
                
                % Initialize empty cell arrays, to be reviewed in g1818595.
                rtIOStreamXilSrcs = {};
                rtIOStreamXilSrcsPath = {};
                rtIOStreamXilIncls = {};
                rtIOStreamXilInclsPath = {};
                rtIOStreamUtilsSrcs = {};
                rtIOStreamUtilsIncls = {};
                rtIOStreamUtilsPath = {};
                rtIOStreamIncls = {};
                rtIOStreamInclsPath = {};
            else                
                % add rtiostream-based implementation of comms layer
                rtIOStreamXilSrcs = { ...
                    'xilcomms_rtiostream.c', ...
                    'xil_rtiostream.c'};
                rtIOStreamXilSrcsPath = repmat({xilSrcPath}, size(rtIOStreamXilSrcs));
                rtIOStreamXilIncls = {'rx_tx_buffer_sizes.h'};
                rtIOStreamXilInclsPath = {xilSrcPath};
                
                % add rtIOStream utility files to buildInfo
                rtIOStreamUtilsSrcs = {'rtiostream_utils.c'}; 
                rtIOStreamUtilsIncls = {'rtiostream_utils.h'};
                rtIOStreamUtilsPath = {fullfile(matlabroot,'toolbox',...
                    'coder','rtiostream','src','utils')};

                rtIOStreamIncls = {'rtiostream.h'};
                rtIOStreamInclsPath = fullfile(matlabroot, ...
                    'toolbox', ...
                    'coder', ...
                    'rtiostream', ...
                    'src');
            end 
            
            % if SIL enabled signal handler
            if componentArgs.isSIL
                signalHandlerDefineName = 'XIL_SIGNAL_HANDLER';
                buildInfo.addDefines([signalHandlerDefineName '=1'], 'OPTS');
                featureVal = coder.internal.connectivity.featureOn('DisableSubnormalsForSIL');
                denormalConfigValue = componentArgs.getParam('DenormalBehavior');
                SILSubnormalDefineName = 'SIL_DISABLE_SUBNORMAL_SUPPORT';
                if ~strcmp(denormalConfigValue,'GradualUnderflow') && (featureVal == 0)
                    switch denormalConfigValue
                        case 'FlushToZero'
                            subnormalSettingInt = 1;
                        case 'DenormalsAsZeros'
                            subnormalSettingInt = 2;
                        otherwise
                            assert(false,'Unexpected setting for DenormalBehavior')
                    end
                    buildInfo.addDefines([SILSubnormalDefineName '=' num2str(subnormalSettingInt)], 'OPTS');
                elseif (featureVal ~= 0)                    
                    buildInfo.addDefines([SILSubnormalDefineName '=' num2str(featureVal)], 'OPTS');
                end
                
            end
            % coder assumptions app files
            if componentArgs.CoderAssumptionsEnabled                
                CAEnabled = true;
                % add the static files
                staticCASrcs = coder.assumptions.CoderAssumptions.getXILAppStaticSourceFileNames;
                staticCASrcsPath = repmat({xilSrcPath}, size(staticCASrcs));
                staticCAIncls = coder.assumptions.CoderAssumptions.getXILAppStaticHeaderFileNames;
                staticCAInclsPath =  repmat({xilSrcPath}, size(staticCAIncls));

                % link precompiled library only if XIL compiler information
                % available
                lXilCompInfo = componentArgs.getXilCompInfo();
                
                isPWS = strcmp(componentArgs.getConfigInterface.getParam('PortableWordSizes'),'on');
                libExt = lXilCompInfo.XilLibraryExt;

                caPath = coder.assumptions.CoderAssumptions.getBuildFolder(...
                    componentArgs.getCoderAssumptionsAnchorDir());
                libBuildDir = coder.assumptions.CoderAssumptions.getLibraryBuildFolder( ...
                    caPath, componentArgs.isSIL, isPWS);
                caLibName = fullfile(libBuildDir, ...
                                     coder.assumptions.CoderAssumptions.getLibraryName( ...
                                         componentArgs.getComponentCodeName, libExt));
                rtw.pil.RtIOStreamApplicationFramework.addLibsToBuildInfo(buildInfo, caLibName);
                
                externIncludesDir = fullfile(matlabroot, 'extern', 'include');
                caAppInclsPath = {fullfile(externIncludesDir,...
                    'coder', 'connectivity', 'CoderAssumpTgtAppSvc')};
                caAppIncls = {'CoderAssumpTgtAppSvc_CInterface.h'};
                if rtw.connectivity.Utils.isCommServiceAPIEnabled                   
                    coderAssumpTgtLib = fullfile(libFolder, ['libmwcoder_CoderAssumpTgtAppSvc' ext]);
                    rtw.pil.RtIOStreamApplicationFramework.addLibsToBuildInfo(buildInfo, coderAssumpTgtLib);
                    rtiostreamCASrcs = {};
                    rtiostreamCASrcsPath = {};
                else
                    % add rtiostream-based implementation
                    rtiostreamCASrcs = {'coder_assumptions_rtiostream.c'};
                    rtiostreamCASrcsPath = {xilSrcPath};
                end
                allCASources = [staticCASrcs, rtiostreamCASrcs];
                allCASourcesPaths = [staticCASrcsPath, rtiostreamCASrcsPath];
                allCAIncludes = [staticCAIncls, caAppIncls];
                allCAIncludesPaths = [staticCAInclsPath, caAppInclsPath];
            else
                CAEnabled = false;
                allCASources = {};
                allCASourcesPaths = {};
                allCAIncludes = {};
                allCAIncludesPaths = {};
                caAppInclsPath = {};
                caPath = {};
            end
            
            % add all the source paths
            buildInfo.addSourcePaths([xilSrcPath, rtIOStreamUtilsPath]);
            % add all the include paths
            buildInfo.addIncludePaths( ...
                [xilSrcPath, xilAppPath, externIncludesDir, xilTgtAppSvcIncludeDir, rtIOStreamUtilsPath, rtIOStreamInclsPath, caAppInclsPath, caPath]);
            % add all source files
            buildInfo.addSourceFiles( ...
                [staticXilSrcs, wrapperXilSrcs, rtIOStreamXilSrcs, rtIOStreamUtilsSrcs, allCASources], ...
                [staticXilSrcsPath, wrapperXilSrcsPath, rtIOStreamXilSrcsPath, rtIOStreamUtilsPath, allCASourcesPaths]);
            % add all Include files
            buildInfo.addIncludeFiles( ...
                [staticXilIncls, rtIOStreamXilIncls, rtIOStreamUtilsIncls, xilTgtAppSvcIncls, rtIOStreamIncls, allCAIncludes], ...
                [staticXilInclsPath, rtIOStreamXilInclsPath, rtIOStreamUtilsPath, xilTgtAppSvcInclsPath, rtIOStreamInclsPath, allCAIncludesPaths]);
            
            coderAssumptionsDefineName = 'CODER_ASSUMPTIONS_ENABLED';            
            buildInfo.addDefines(sprintf('%s=%d', ...
                coderAssumptionsDefineName, CAEnabled), ...
                'OPTS');           
        end
        
        % method to add the specified SIL/PIL main.c to the BuildInfo
        function addPILMain(this, type)
            buildInfo = this.getBuildInfo; 
            type = lower(type);
            switch type
                case 'target'
                    buildInfo.addSourceFiles('pil_main.c', this.getXILSrcPath);        
                case 'host'
                    buildInfo.addSourceFiles('sil_main.c', this.getXILSrcPath);      
                otherwise
                    rtw.pil.ProductInfo.error('pil', 'UnknownMainType', type);
            end                        
        end                
    end
    
    methods (Static, Hidden, Access = public)
        function addLibsToBuildInfo(buildInfo, libs)
            libs = cellstr(libs);
            priority = 1000;
            precompiled = true;
            linkOnly = true;
            for i = 1:length(libs)
                lib = libs{i};
                [libPath, libName, libExt] = fileparts(lib);
                buildInfo.addLinkObjects([libName libExt], libPath, priority, ...
                    precompiled, linkOnly);
            end
        end
    end
    
    methods (Hidden)
        function addTargetIo(this)
            % add "target_io" module
            buildInfo = this.getBuildInfo;
            coder.connectivity.PILApplicationDependencies.addTargetIoDependenciesToBuildInfo(buildInfo);
        end
    end
    
    methods (Hidden, Static, Access = 'public')
        function xilSrcPath = getXILSrcPath()
            xilSrcPath = fullfile(matlabroot, ...
                'toolbox', ...
                'rtw', ...
                'targets', ...
                'pil', ...
                'c');
        end
    end
end
