classdef (Hidden = true) TransferInterfaceUtils < handle
%TRANSFERINTERFACEUTILS Manage data interfaces for Host-to-Target and
%Target-to-host data transfers.
%Ultimately the determination of all transfer interfaces (e.g. which to
%transfer) should be moved to here. This means we can manage in one place
%all transfers so they are easy to match between host and target. In
%addition we can then manage (group) legacy and Opaque Region based
%interfaces which is important on the target side, because Opaque Region
%interfaces are immediate transfers, whilst legacy interfaces are deferred
%transfers.
%
%   This is an undocumented class. Its methods and properties are likely to
%   change without warning from one release to the next.

%   Copyright 2021-2022 The MathWorks, Inc.

properties (Access = public)
    IsHost = true;
end

methods
    function this = TransferInterfaceUtils(isHost)
        %Constructor
        this.IsHost = isHost;
    end
    
    function internalDataInterfaceIndices = getInternalDataToUpload(~, componentInterface, taskTiming)
        allInternalData = componentInterface.InternalData;
                    
        dataInterfaceRange = 1:length(allInternalData);
        dataInterfacesToKeep = false(1, length(allInternalData));
        for idx=1:numel(allInternalData)
            if ~isempty(allInternalData(idx).Implementation) && ...
                    ~isempty(allInternalData(idx).Implementation.OpaqueRegion) && ...
                    (isequal(allInternalData(idx).Timing, taskTiming) || ...
                    isequal(allInternalData(idx).Timing,componentInterface.TimingProperties(1)))
                %Match to current timing, OR Base Rate (for Export
                %Functions)
                %Logic here optimized for Timer Service behavior but this
                %should not be Timer Service specific.
                dataInterfacesToKeep(idx) = true;
            end
        end
        internalDataInterfaceIndices = dataInterfaceRange(dataInterfacesToKeep);
    end

    function paramIndices = getParametersToTransfer(~, silPILWrapperUtils)
        % process params with tunable storage
        tunableParamsIndices = silPILWrapperUtils.getSupportedTunableWorkspaceParams();
        % transfer any instance specific model arguments, this is
        % needed to sync parameter values after they have been changed
        % by a parameter writer block
        instPArgsIndices = silPILWrapperUtils.getInstPArgumentIndices();
        paramIndices = [tunableParamsIndices, instPArgsIndices];
        if ~isempty(silPILWrapperUtils.RTESWCHeaderUtils)
            % filter out parameters that may have been optimized out of the
            % AUTOSAR RTE
            paramIndices = silPILWrapperUtils.RTESWCHeaderUtils.filterParametersToTransfer(...
                silPILWrapperUtils.getCodeInfoUtils(), paramIndices);
        end
    end
    
    function [dataElements, dataInterfaces, numMemUnits, numSymbolicMemUnits] = ...
            getDataInterfaces(this, SILPILWrapperUtils, indices, dataInterfaceType)
        %Method brings together current S-function and Target interface
        %determination of basic interfaces to transfer. This needs plumbing
        %in to all transfer determinations. It groups logic into one method
        %to aid synchronization.
        
        numMemUnits = 0;
        numSymbolicMemUnits = '0';
        dataInterfaces = rtw.pil.CodeInfoData.empty;
        dataElements = rtw.pil.DataElement.empty;
        if isempty(indices)
            return;
        end
        if this.IsHost
            [dataElements, dataInterfaces] = rtw.pil.CodeInfoData.createHostDataElements(SILPILWrapperUtils, indices, dataInterfaceType);
            numMemUnits = dataElements.getTotalMemUnitSize(SILPILWrapperUtils.getMemUnitInfo.memUnitBytes);
            numSymbolicMemUnits = sprintf('(%s)', ...
                dataElements.getTotalMemUnitSymbolicSize(SILPILWrapperUtils.getMemUnitInfo.memUnitBytes));
        else
            [dataElements, dataInterfaces] = rtw.pil.CodeInfoData.createTargetDataElements(SILPILWrapperUtils, indices, dataInterfaceType);
        end
    end
end
    
end
