function UpdateSimulinkBlocksHelper(h)
% Function updateSimulinkBlocksHelper is a helper function to be called as part of slupdate.
% it is not intended to be called directly from the command line.

% Copyright 1990-2023 The MathWorks, Inc.

if h.CheckFlags.BlockReplace
    if matlab.internal.feature("RationalisedUpgradeChecks")==0
        ReplaceInfoCurrent = getReplaceInfoCurrent();
        ReplaceInfoLegacy = getReplaceInfoLegacy();
        ReplaceInfo = [ReplaceInfoLegacy; ReplaceInfoCurrent];
    else
        if h.RunLegacyChecks
            ReplaceInfo = getReplaceInfoLegacy();
        else
            ReplaceInfo = getReplaceInfoCurrent;
        end
    end

    replaceBlocks(h, ReplaceInfo);
    
    % The following code is to handle Rtwt target updates.
    % It is here until a package is created to hold all the updateHelper
    % functions.
    context = getContext(h);

    sys = context;    
    while strcmp(get_param(sys, 'Type'), 'block')
        sys = get_param(sys, 'parent');
    end

    switch(lower(get_param(sys, 'SystemTargetFile')))
      case {'win_tgt.tlc', 'rtwin.tlc'}  % Change for RTWin
        name = get_param(sys, 'name');
        funcSetA = uSafeSetParam(h, sys, 'SystemTargetFile','rtwin.tlc');
        funcSetB = uSafeSetParam(h, sys, 'TemplateMakefile','rtwintmf');
        appendTransaction(h, name, h.MiscUpdateReasonStr, {funcSetA, funcSetB});
    end

    % Update configuration sets
    % (e.g., synchronize the configset with changes to system target file).
    try
        updateConfigSets(h);
    catch e
        MSLDiagnostic('SimulinkBlocks:upgrade:unableToUpdateCS', e.message).reportAsWarning;
    end
    
     %any other action needed to update the model for this product in a
     %non-compiled state
end
   
if h.CheckFlags.Compiled
    if matlab.internal.feature("RationalisedUpgradeChecks")==0
        ReplaceInfoCurrent = getCompiledReplaceInfoCurrent();
        ReplaceInfoLegacy = getCompiledReplaceInfoLegacy();
        ReplaceInfo = [ReplaceInfoLegacy; ReplaceInfoCurrent];
    else
        if h.RunLegacyChecks
            ReplaceInfo = getCompiledReplaceInfoLegacy();
        else
            ReplaceInfo = getCompiledReplaceInfoCurrent;
        end
    end
    replaceBlocks(h, ReplaceInfo);
end

end


function ReplaceInfo = getReplaceInfoCurrent

ReplaceInfo = { ...
 { 'MaskType','Repeating table'}, @callSimulinkBlockUpgradeFunction, 'ReplaceRepeatingSequenceDuplicates'; ...
 { 'MaskType','First-Order Hold'}, @callSimulinkBlockUpgradeFunction, 'ReplaceFOHBlock';...
 { 'BlockType', 'Reciprocal'}, @callSimulinkBlockUpgradeFunction, 'ReplaceHDLReciprocal';...
 { 'BlockType', 'Interpolation_n-D'}, @callSimulinkBlockUpgradeFunction, 'UpdateInterpNDValidIndexFlatInterp';...
 };

ReplaceInfo = cell2struct(ReplaceInfo, { 'BlockDesc', 'ReplaceFcn', 'data'}, 2);

end



function ReplaceInfo = getReplaceInfoLegacy

portZeroPad = zeros(1, length(get_param('built-in/Subsystem','Ports')) - 2);
dot_linked_lib = sprintf('simulink_need_slupdate/Dot\nProduct');

% collect other product entries to top for deletion.
ReplaceInfo = { ...
 { 'BlockType','Reference', ...
   'SourceBlock',sprintf('simulink_obsolete/Matrix\nConcatenation')}, ...
   @callSimulinkBlockUpgradeFunction, 'ReplaceSFcnMatrixConcatenation';...
 { 'BlockType','Reference', ...
   'SourceBlock','simulink_obsolete/Reshape'}, ...
   @callSimulinkBlockUpgradeFunction, 'ReplaceSFcnReshape';...
 { 'MaskType',sprintf('Weighted Moving Average'), ...
   'ReferenceBlock', sprintf('simulink_need_slupdate/Weighted\nMoving Average')}, ...
   @callSimulinkBlockUpgradeFunction, 'ReplaceSFcnWeightedMovingAverage';...
 { 'MaskType','PID(2) Controller'}, @callSimulinkBlockUpgradeFunction, 'ReplacePIDApproxDerivWithPID1dof';...
 { 'MaskType','PID Controller'}, @callSimulinkBlockUpgradeFunction, 'ReplacePIDIdealDerivWithPID1dof';...
 { 'BlockType','Reference', 'SourceBlock','rtwinlib/Adapter' }, @callSimulinkBlockUpgradeFunction, 'delete_block';...
 { 'BlockType','Reference', 'SourceBlock','rtwinlib/RT In' }, @callSimulinkBlockUpgradeFunction, 'ReplaceRTWinInOut';...
 { 'BlockType','Reference', 'SourceBlock','rtwinlib/RT Out' }, @callSimulinkBlockUpgradeFunction, 'ReplaceRTWinInOut';...
 ...
 { 'MaskType','Dot Product','referenceBlock',dot_linked_lib}, @callSimulinkBlockUpgradeFunction, 'ReplaceDotProduct';...
 { 'MaskType','Pulse Generator', ...
   'MaskPromptString',['Pulse period (secs):|Pulse width:|Pulse height:|'...
                        'Pulse start time:'] }, @callSimulinkBlockUpgradeFunction, 'ReplacePulseGen';...
 { 'MaskType','Pulse Generator', ...
   'LinkStatus', 'none', ...
   'MaskPromptString','Period (secs):|Duty cycle (% of period):|Amplitude:|Start time:'}, ...
 @callSimulinkBlockUpgradeFunction, 'ReplacePulseGen2';...
 { 'MaskType','Crossing' }, @callSimulinkBlockUpgradeFunction, 'ReplaceHitCross';...
 { 'BlockType','S-Function','FunctionName','sfunmem' }, @callSimulinkBlockUpgradeFunction, 'ReplaceSFunMem';...
 { 'BlockType','S-Function','FunctionName','quantize','Mask','on'}, @callSimulinkBlockUpgradeFunction, 'ReplaceQuantizer';...
 { 'MaskType','Graph scope.', ...
   'MaskPromptString',['Time range:|y-min:|y-max:|', ...
   'Line type (rgbw-:*). Separate each plot by ''/'':'] }, @callSimulinkBlockUpgradeFunction, 'ReplaceGraphScope';...
 { 'MaskType','2-D Table Lookup' }, @callSimulinkBlockUpgradeFunction, 'Replace2DTableLookup';...
 { 'MaskType','LookupIdxSearch' }, @callSimulinkBlockUpgradeFunction, 'ReplaceSfunPrelookup';...
 { 'MaskType','LookupNDInterpIdx' }, @callSimulinkBlockUpgradeFunction, 'ReplaceSfunInterpND';...
 { 'MaskType','Lookup Table (2-D)' }, @callSimulinkBlockUpgradeFunction, 'Replace2DTableLookup';...
 { 'MaskType','Limited integrator.' }, @callSimulinkBlockUpgradeFunction, 'ReplaceLimitedIntegrator';...
 { 'MaskType','Limited Integrator.' }, @callSimulinkBlockUpgradeFunction, 'ReplaceLimitedIntegrator';...
 { 'BlockType','ResetIntegrator' }, @callSimulinkBlockUpgradeFunction, 'ReplaceResetIntegrator';...
 { 'BlockType','Integrator' }, @callSimulinkBlockUpgradeFunction, 'ReplaceContinuousIntegrator';...
 { 'BlockType','ToWorkspace'}, @callSimulinkBlockUpgradeFunction, 'UpdateToWorkspace';...
 { 'BlockType','ElementaryMath'}, @callSimulinkBlockUpgradeFunction, 'ReplaceElMath';...
 { 'BlockType','Outport', 'OutputWhenDisabled', 'held' }, @callSimulinkBlockUpgradeFunction, 'FixOutportIC';...
 { 'BlockType','From', 'CloseFcn', 'tagdialog Close'}, ...
    @callSimulinkBlockUpgradeFunction, 'ReplaceCloseFcnWithEmptyStr';...
 { 'MaskType','Matrix Gain','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceMatrixGain';...
 { 'MaskType','Coulombic and Viscous Friction','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceCoulombic';...
 { 'MaskType','XY scope.','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceXYScope';...
 { 'MaskType','chirp','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceChirp';...
 { 'MaskType',' Ramp','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceRamp';...
 { 'MaskType','Repeating table','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceRepeatingSequence';...  
 { 'MaskType','PID Controller','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplacePID';...
 { 'MaskType','PID(2) Controller','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplacePID2';...
 { 'BlockType','SubSystem','ports',[2 2 portZeroPad],'Mask','off','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceLatchWithRef';...
 { 'BlockType','SubSystem','ports',[3 2 portZeroPad],'Mask','off','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'ReplaceLatchWithRef';...
 ...
 { 'MaskType','First Order Hold','LinkStatus','none','MaskPromptString','Sample time:'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Discrete Transfer Function with Initial Outputs','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Discrete Transfer Function with Initial States','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Discrete Zero-Pole with Initial Outputs','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Discrete Zero-Pole with Initial States','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','State-Space with Initial Outputs','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Transfer Function with Initial Outputs','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Transfer Function with Initial States','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Zero-Pole with Initial Outputs','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Zero-Pole with Initial States','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Auto Correlator','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Spectrum Analyzer'}, @callSimulinkBlockUpgradeFunction, 'ReplaceSpectrumAnalyzer';...
 { 'MaskType','Cross Correlator','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Digital clock','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Derivative for linearization','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Delay for linearization.','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Cart2Polar','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Cart2Sph','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','CelsiusToFahrenheit','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','DegreesToRadians','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','FahrenheitToCelsius','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Polar2Cart','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','RadiansToDegrees','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Sph2Cart','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 { 'MaskType','Sign','LinkStatus','none'}, @callSimulinkBlockUpgradeFunction, 'replaceBlockWithLink';...
 ... 
 { 'SFBlockType', 'MATLAB Function' }, @callSimulinkBlockUpgradeFunction, 'UpdateEMLFimath';...
 { 'SFBlockType', 'Truth Table' }, @callSimulinkBlockUpgradeFunction, 'UpdateSFTruthTableFimath';...
 { 'BlockType', 'Math','Operator','1/sqrt' }, @callSimulinkBlockUpgradeFunction, 'ReplaceRSqrt';... 
 ...
 { 'MaskType', 'DocBlock' }, @callSimulinkBlockUpgradeFunction, 'CompressRTFDocBlock';...
 { 'BlockType', 'ModelReference', 'ProtectedModel', 'on' }, @callSimulinkBlockUpgradeFunction, 'HandleProtectedModels'; ...
 { 'SearchDepth', 1, 'BlockType', 'Inport' }, @callSimulinkBlockUpgradeFunction, sl('getFcnHandle', 'SetBlockForArraysOfBuses'); ...
 { 'SearchDepth', 1, 'BlockType', 'Outport' }, @callSimulinkBlockUpgradeFunction, sl('getFcnHandle', 'SetBlockForArraysOfBuses'); ...
};

ReplaceInfo = cell2struct(ReplaceInfo, { 'BlockDesc', 'ReplaceFcn', 'data'}, 2);

end

function ReplaceInfo = getCompiledReplaceInfoCurrent
% Totally three functions are needed
% first function: register the compile check
% second function: get the compiled data
% third function: post compile action such as replace the block, give
% warnings...

ReplaceInfo = { ...
    {'RegExp', 'Off','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','ToWorkspace'}, @callSimulinkBlockUpgradeFunction, 'ToWorkspaceCompileCheck'; ...
    {'RegExp', 'Off','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','S-Function'}, @callSimulinkBlockUpgradeFunction, 'UpdateSFunctions'; ...
    {'RegExp', 'Off','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','UnitDelay'}, @callSimulinkBlockUpgradeFunction, 'UnitDelayRegisterCompileCheck' ...  
};

ReplaceInfo = cell2struct(ReplaceInfo, { 'BlockDesc', 'ReplaceFcn', 'data' }, 2);
end



function ReplaceInfo = getCompiledReplaceInfoLegacy
% Totally three functions are needed
% first function: register the compile check
% second function: get the compiled data
% third function: post compile action such as replace the block, give
% warnings...

ReplaceInfo = { ...
    {'RegExp', 'Off','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','Lookup'}, @callSimulinkBlockUpgradeFunction, 'Lookup1D2DRegisterCompileCheck'; ...
    {'RegExp', 'Off','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','Lookup2D'}, @callSimulinkBlockUpgradeFunction, 'Lookup1D2DRegisterCompileCheck'; ...
    {'RegExp', 'Off','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','DiscreteFir'}, @callSimulinkBlockUpgradeFunction, 'DiscreteFIRRegisterCompileCheck'; ...
    {'RegExp',  'on','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','MultiPortSwitch', 'DataPortOrder', '^Z|^O'}, @callSimulinkBlockUpgradeFunction, 'MPSwitchRegisterCompileCheck'; ...
    {'RegExp', 'Off','FollowLinks', 'off','LookUnderMasks', 'all','Type', 'block','BlockType','Math','Operator','sqrt' }, @callSimulinkBlockUpgradeFunction, 'MathRegisterCompileCheck';...
};

ReplaceInfo = cell2struct(ReplaceInfo, { 'BlockDesc', 'ReplaceFcn', 'data' }, 2);
end




function updateConfigSets(h)
%UPDATECONFIGSETS  Report on all configsets that need to be updated.
    
    mdl = bdroot(getContext(h));

    if (strcmp(get_param(mdl, 'BlockDiagramType'), 'model') && ...
        license('test', 'Real-Time_Workshop'))

        % Initialize variables
        csToUpdate = '';
        funcSet = {};
        
        % Loop through configsets in the model
        csNames = getConfigSets(mdl);
        for idx = 1:length(csNames)
            csName = csNames{idx};
            wsVarName = '';
            cs = getConfigSet(mdl, csName);
            if isa(cs, 'Simulink.ConfigSetRef')
                try
                    wsVarName = cs.WSVarName;
                    cs  = cs.getRefConfigSet;
                catch %#ok<CTCH>
                    % Skip this configset - no valid reference configset found
                    continue;
                end
            end
            
            outOfDate = slprivate('updateCS', cs, 'CheckIfAnythingOutOfDate');
            
            if outOfDate
                % Record transactions for reporting purposes
                funcSet{end+1,1} = {'sl','updateCS', cs, 'UpdateIfAnythingOutOfDate'}; %#ok<*AGROW>
                csToUpdate = [csToUpdate, sprintf(', '), csName];
        
                % Do update if required
                if doUpdate(h)
                    slprivate('updateCS', cs, 'UpdateIfAnythingOutOfDate');
                    if ~isempty(wsVarName)
                        MSLDiagnostic('SimulinkBlocks:upgrade:configSetRefUpdatingSourceConfigSet', ...
                                         wsVarName).reportAsWarning;
                    end                
                end
            end
        end
        
        if ~isempty(csToUpdate)
            csToUpdate = csToUpdate(3:end);  % Remove leading ', '
            msgTxt = DAStudio.message('SimulinkBlocks:upgrade:configSetsToBeUpdated', csToUpdate);
            appendTransaction(h, mdl, msgTxt, funcSet);
        end
    end
end

%[EOF] UpdateSimulinkBlocks
