function dataInfo = hNRUMDataPDUDecode(rlcPDU, seqNumFieldLength) %#codegen
%hNRUMDataPDUDecode RLC UMD PDU decoder
%   DATAINFO = hNRUMDataPDUDecode(RLCPDU, SEQNUMFIELDLENGTH) decodes a
%   radio link control (RLC) unacknowledged mode data (UMD) protocol data
%   unit (PDU) to get the associated information such as RLC service data
%   unit (SDU), segmentation information, sequence number, and segment
%   offset.
%
%   DATAINFO is the RLCPDUInfo object which contains segmentation info,
%   sequence number, segment offset, and RLC SDU properties.
%
%   RLCPDU is the output RLC UMD PDU, specified as a column vector of
%   octets in decimal format.
%
%   SEQNUMFIELDLENGTH is the number of bits used for the RLC UMD PDU
%   sequence number. Specify this value as either 6 or 12. Refer section
%   6.2.3.3 in 3GPP TS 38.322.

%   Copyright 2019 The MathWorks, Inc.

% Validate the input arguments
validateattributes(rlcPDU, {'numeric'}, {'nonempty', 'nonnegative', 'column', '>=', 0, '<=', 255});
validateattributes(seqNumFieldLength, {'numeric'}, {'nonempty', 'positive', 'scalar'});
if ~ismember(seqNumFieldLength, [6 12])
    error('RLC UM sequence number field length must be either 6 or 12.');
end

% Extract the segmentation information present in the first 2 bits of the
% RLC UMD PDU
segmentationInfo = bitshift(rlcPDU(1, 1), -6);
% Get the RLC PDU length
rlcPDULength = length(rlcPDU);
% Extract RLC SDU or RLC SDU segment based on the segmentation information
if (segmentationInfo == 0)
    % Extract the whole RLC SDU from the RLC UMD PDU
    rlcSDU = rlcPDU(2:end, 1);
    % Create a hNRUMDataPDUInfo object with the specified SDU and segmentation
    % information
    dataInfo = hNRUMDataPDUInfo(rlcSDU, rlcPDULength, segmentationInfo);
else
    if seqNumFieldLength == 6
        % Get the sequence number from the last 6 bits of the first byte
        % from the received PDU
        segmentSeqNum = bitand(rlcPDU(1, 1), 63);
        % Set segment offset index to 2 such that it points to segment
        % offset field, except in case of first segment of a SDU
        segmentOffsetIndex = 2;
    else
        % Get the sequence number using the last 4 bits of the first byte
        % and second byte from the received PDU
        segmentSeqNum = bitshift(bitand(rlcPDU(1, 1), 15), 8) + rlcPDU(2, 1);
        % Set segment offset index to 3 such that it points to segment
        % offset field, except in case of first segment of a SDU
        segmentOffsetIndex = 3;
    end

    if segmentationInfo == 1 % Check whether the first segment of the SDU is received
        % Extract the RLC SDU segment from the first segmented RLC UMD PDU
        rlcSDU = rlcPDU(segmentOffsetIndex:end, 1);
        % Create a hNRUMDataPDUInfo object with the specified SDU,
        % segmentation information, and sequence number
        dataInfo = hNRUMDataPDUInfo(rlcSDU, rlcPDULength, segmentationInfo, double(segmentSeqNum));
    else
        % Extract the RLC SDU segment offset information from the middle
        % and last segmented RLC UMD PDUs
        segmentOffset = bitshift(rlcPDU(segmentOffsetIndex, 1), 8) +  rlcPDU(segmentOffsetIndex+1, 1);
        % Extract the RLC SDU segment from the RLC UMD PDU
        rlcSDU = rlcPDU(segmentOffsetIndex+2:end, 1);
        % Create a hNRUMDataPDUInfo object with the specified SDU,
        % segmentation information, sequence number, and segment offset
        dataInfo = hNRUMDataPDUInfo(rlcSDU, rlcPDULength, segmentationInfo, double(segmentSeqNum), double(segmentOffset));
    end
end
end
