classdef ParamTuningAppSvc < coder.internal.connectivity.TgtConnAppSvc
% PARAMTUNINGAPPSVC - Implements the Parameter Tuning Application Service for
% Target Connectivity (see coder.internal.connectivity.TgtConnMgr for more
% information).

% Copyright 2014-2017 The MathWorks, Inc.
    
    properties(Access=public)
        % Location of the host-based CAPI file.  ToAsyncQueueAppSvc ctor uses
        % the top model name (based on the obj.topMdlName property) at build
        % time to determine the location of the host-based CAPI file and caches
        % it away here.  This value is used at run-time when a host application
        % calls the start() method to find the host-based CAPI and assumes the
        % location of this file has not changed since build-time.
        %
        hostBasedCAPIFullFileName;
    end
    
    % Service objects should only be instantiated by TgtConnMgr at build-time.
    %
    methods(Access={?coder.internal.connectivity.TgtConnMgr})
        function obj = ParamTuningAppSvc()
            [topMdlName, ~] = coder.internal.connectivity.TgtConnMgr.getTopModelAndBuildArgs();
            
            % Cache the location of the host-based C-API during the build
            % process for use by the start() method at run-time (assumes
            % build directory was not moved between build and run).  Must
            % protect against invalid models where RTW.getBuildDir might
            % throw an error.
            %
            try
                buildDirStruct = RTW.getBuildDir(topMdlName);
                
                obj.hostBasedCAPIFullFileName = fullfile( ...
                    buildDirStruct.BuildDirectory, ...
                    'tmwinternal', ...
                    [topMdlName '_capi_host.' mexext]);
                
            catch ME %#ok
                obj.hostBasedCAPIFullFileName = [];
            end
        end
    end
    
    methods(Access=public)
        function isNeeded = isNeeded(obj) %#ok
            [topMdlName, ~] = coder.internal.connectivity.TgtConnMgr.getTopModelAndBuildArgs();
            
            stf = get_param(topMdlName,'SystemTargetFile');
            isRaccel = strcmp(stf, 'raccel.tlc');

            hObj = getActiveConfigSet(topMdlName);
            isNotCoderTarget = isRaccel || ~codertarget.target.isCoderTarget(hObj);
            
            isNeeded = slfeature('ParamTuningAppSvc') && (isNotCoderTarget || ...
                codertarget.attributes.supportTargetServicesFeature(hObj, 'ParamTuningAppSvc'));
        end
        
        function setupBeforeTLC(obj, mdl) %#ok
        end
    
        function cleanupAfterTLC(obj, mdl) %#ok
        end
    
        function codeStr = getIncludesAndDefinesCode(obj) %#ok
            codeStr = '';
        end
    
        function codeStr = getBackgroundTaskCode(obj) %#ok
            codeStr = '';
        end
    
        function codeStr = getMdlInitCode(obj) %#ok
            codeStr = [ ...
                'if (startParamTuningTgtAppSvc()) {' ...
                '    result = "Could not start ParamTuning app service";' ...
                '    return(result);'  ...
                '}'
                      ];
        end
    
        function codeStr = getMdlTermCode(obj) %#ok
            codeStr = 'terminateParamTuningTgtAppSvc();';
        end
    
        function codeStr = getPreStepCode(obj) %#ok
        % rt_modelMapInfoPtr must be defined as a pointer to the MMI 
        % (rtwCAPI_ModelMappingInfo*).  Access to the MMI is target
        % specific and so this pointer is defined in the appropriate
        % TargetConnection object.  For example, Raccel defines the MMI as
        % exported global in main.c and ERT defines the MMI in the rtModel
        % object which can be accessed through the RT_MODEL define in main.c.
        % It is the TargetConnection's responsibility to generate the
        % necessary code to make rt_modelMapInfoPtr available here.
        %
            codeStr = 'tunePendingParameterChanges(rt_modelMapInfoPtr);';
        end
    
        function codeStr = getPostStepCode(obj) %#ok
            codeStr = '';
        end
        
        function start(obj, argMap) %#ok
            %
            % NOTE: Only start the app service if the host-based CAPI was built
            %       (i.e. if there are structured parameters in the model).
            %       This step allows the host-based CAPI build to be
            %       skipped for models without structured parameters and avoids
            %       the performance overhead of the mex command (which can be
            %       expensive for IMT models).
            %
            if exist(obj.hostBasedCAPIFullFileName, 'file')
                coder.internal.connectivity.ConnectParamTuningAppSvc(...
                    obj.tgtConnMgr.getTargetConnection(), ...
                    obj.hostBasedCAPIFullFileName);
            end
        end
        
        function stop(obj) %#ok
        end
    end
    
    %****************************
    %*
    %* Additional Methods only
    %* for ParamTuningAppSvc
    %*
    %****************************
    
    methods(Access=public)
        function setParam(obj, modelNameOrBlockPath, paramName, value)
            if isempty(obj.tgtConnMgr)
                errId = 'Connectivity:tgtconn:ErrorNoConnection';
                exc = MException(errId, DAStudio.message(errId));
                throw(exc);
            end
            
            coder.internal.connectivity.SetParamTuningAppSvc(...
                obj.tgtConnMgr.getTargetConnection(), ...
                isempty(strfind(modelNameOrBlockPath, '/')), ...
                modelNameOrBlockPath, ...
                paramName, ...
                value);
        end
    
        function tuneParams(obj, varargin)
            narginchk(0, 2); % Only input arg is callback handle
            
            if isempty(obj.tgtConnMgr)
                errId = 'Connectivity:tgtconn:ErrorNoConnection';
                exc = MException(errId, DAStudio.message(errId));
                throw(exc);
            end
            
            if (nargin > 1)
                coder.internal.connectivity.TuneParamTuningAppSvc(...
                    obj.tgtConnMgr.getTargetConnection(),...
                    varargin{1});
            else
                coder.internal.connectivity.TuneParamTuningAppSvc(...
                    obj.tgtConnMgr.getTargetConnection());
            end
        end
    end
end
