%% Create an S-Function Outcome Selector
% This example shows how to create a selector for an S-Function using the
% |slcoverage.SFcnSelector| class.

% Copyright 2020 The MathWorks, Inc.

%%
% In this example, your model has an S-Function named
% |RejectDoublePress_sfun|. Inside the S-Function, suppose that the
% condition |rtb_AccelResSwOUT| is never false, and you want to justify
% this false outcome in the coverage report.

%%
%
% <<../sfun_to_filter.png>>
%


%%
% Load the model.

modelName = 'ex_cc_cruise_control_doublepress_sfun';
load_system(modelName)

%%
% Configure coverage settings using a |Simulink.SimulationInput| object.

covSet = Simulink.SimulationInput(modelName);
covSet = covSet.setModelParameter('CovEnable','on');
covSet = covSet.setModelParameter('CovMetricStructuralLevel','ConditionDecision');
covSet = covSet.setModelParameter('CovSFcnEnable','on');
covSet = covSet.setModelParameter('CovSaveSingleToWorkspaceVar','on');
covSet = covSet.setModelParameter('CovSaveName','covData');
covSet = covSet.setModelParameter('SimAnalyzeCustomCode','on');

%%
% Simulate the model using |covSet| as the input.

simOut = sim(covSet);
covData = simOut.covData;

%%
% Create a selector object for the outcome missing coverage by using the
% |slcoverage.SFcnSelector| class. To select a condition outcome inside an
% S-Function, use the |SFcnInstanceCppConditionOutcome| enumeration as the
% first input. The second input is the block ID or block path to the
% S-Function. The third input is the file name of the source file that
% contains the expression, |RejectDoublePress_sfun_wrapper.c|. The fourth
% input is the name of the function that contains the condition,
% |RejectDoublePress_sfun_Outputs_wrapper|. The fifth input is the
% expression which owns the outcome, which is |rtb_AccelResSwOUT &&
% CoastSetSwIn[0]|, because this parent decision owns the condition
% |rtb_AccelResSwOUT|. 

%%
% The sixth input is the index of the expression that
% owns the outcome relative to its parent, and because |rtb_AccelResSwOUT|
% is the first condition in its parent decision, this input is |1|. The
% seventh input is the outcome index, which is |1| because this is the |F|
% case of a Boolean expression. The final input is the index of the parent
% expression relative to the function, and because |rtb_AccelResSwOUT &&
% CoastSetSwIn[0]| is the second decision in the function, this input is
% |2|.

enum = slcoverage.SFcnSelectorType.SFcnInstanceCppConditionOutcome;
SFunID = Simulink.ID.getSID([modelName, '/RejectDoublePress']);
sel = slcoverage.SFcnSelector(enum,SFunID,'RejectDoublePress_sfun_wrapper.c',...
   'RejectDoublePress_sfun_Outputs_wrapper','rtb_AccelResSwOUT && CoastSetSwIn[0]',1,1,2);

%%
% Create a |Filter| object and a rule based on the selector, then add the
% rule to the filter.

filt = slcoverage.Filter;
rule = slcoverage.FilterRule(sel,'Tested elsewhere',...
           slcoverage.FilterMode.Justify);
addRule(filt,rule);
setFilterName(filt,'S-Function Filter')

%%
% Save the filter as |sfunfilter| and add it to the cvdata object for
% |my_func.c| by setting the |filter| property to the filter file name.

save(filt,'sfunfilter');
covData.filter = 'sfunfilter';

%%
% Generate a coverage report.

cvhtml('codeCovReport',covData)

%%
% Review the report. Click the |RejectDoublePress_sfun| link under
% S-Function Code Coverage Results to see the filtered outcome under
% Objects Filtered from Coverage Analysis.