function indices = getTurboIOIndices(blkLen,n,mLen,varargin)
%getTurboIOIndices Compute output indices for turbo coding
%
%   INDICES = getTurboIOIndices(BLKLEN,N,MLEN) computes the output indices
%   for a given input block length, BLKLEN, number of output streams, N,
%   and the number of registers, MLEN, relative to the fully encoded
%   output. In this mode, the second interleaved, systematic bit-stream is
%   punctured. Both N and MLEN are specified as for the constituent
%   encoder. INDICES are of length equal to (BLKLEN+MLEN)*(2*N-1).
%
%   INDICES = getTurboIOIndices(BLKLEN,N,MLEN,'LTE') computes the output
%   indices for a given input block length, BLKLEN, number of output
%   streams, N, and the number of registers, MLEN, with LTE-like tail bit
%   reordering. For LTE, in addition to the second systematic stream being
%   punctured, the tail bits are also reordered as per 3GPP TS 36.212.
%   INDICES are of length equal to (BLKLEN*(2*N-1) + MLEN*2*N).
%
%   Use INDICES as the input indices for the decoder and output indices for
%   the encoder components.
%
%   Example:
%   %   Compute indices for a block length of 100 for rate-1/2 encoder with
%   %   memory length of 3. The output indices are of length (100+3)*3.
%   indices = getTurboIOIndices(100,2,3);
%   
%   See also comm.TurboEncoder, comm.TurboDecoder.

%   Copyright 2020 The MathWorks, Inc.

%#codegen

%   Reference:
%   [1] 3GPP TS 36.212, "3rd Generation partnership project; Technical 
%   specification group radio access network; Evolved Universal Terrestrial
%   Radio Access (E-UTRA); Multiplexing and channel coding". Section
%   5.1.3.2.

    narginchk(3,4);
    fcnName = mfilename;
    if nargin==4  % (blkLen,n,mLen,'LTE')
        mode = varargin{1};
        mode = validatestring(mode,{'LTE'},fcnName);        
    else % (blkLen,n,mLen)
        mode = 'punc2ndSys';
    end
    validateattributes(blkLen,{'numeric'},{'scalar','integer','nonnegative'}, ...
        fcnName,'BLKLEN');
    validateattributes(n,{'numeric'},{'scalar','integer','>',1}, ...
        fcnName,'N');
    validateattributes(mLen,{'numeric'},{'scalar','integer','positive'}, ...
            fcnName,'MLEN');
        
    if (blkLen > 0)
        fullOutLen = (blkLen+mLen)*n*2;

        % Data bits only
        dataIndices = reshape((1:(blkLen*n*2)).',n*2,blkLen);
        outDataIndices = dataIndices([1:n n+2:2*n],:); % Puncture 2nd Systematic

        % Tail bits only
        tailIndices = reshape((blkLen*n*2+1:fullOutLen).',n*2,mLen);

        if strcmpi(mode,'LTE')

            tailInd1 = tailIndices(1:n,:);
            tailInd2 = tailIndices(n+1:2*n,:);

            % Output indices, with reordered tail
            indices = [outDataIndices(:); tailInd1(:); tailInd2(:)];

        else

            % Puncture 2nd systematic tail also
            tailInd = tailIndices([1:n n+2:2*n],:);

            % Output indices
            indices = [outDataIndices(:); tailInd(:)];

        end
    else
        indices = zeros(0,1);
    end
end
