/// <summary>
        /// Get payoad from PDU by tag type and request ID.
        /// </summary>
        /// <param name="pdu"></param>
        /// <param name="tagType"></param>
        /// <param name="requestId"></param>
        /// <returns></returns>
        private static PduPayload GetPayload(Pdu pdu, uint tagType, ulong?requestId)
        {
            foreach (PduPayload payload in pdu.Payloads)
            {
                if (payload.Type == tagType)
                {
                    if (!requestId.HasValue)
                    {
                        return(payload);
                    }

                    RequestResponsePayload responsePayload = payload as RequestResponsePayload;

                    if (responsePayload != null && responsePayload.RequestId == requestId)
                    {
                        return(payload);
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Parse KSI service response.
        /// </summary>
        /// <param name="data">Response byte array</param>
        /// <param name="requestId">Request ID</param>
        /// <returns></returns>
        public PduPayload Parse(byte[] data, ulong?requestId = null)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            RawTag    rawTag    = null;
            Pdu       pdu       = null;
            LegacyPdu legacyPdu = null;

            try
            {
                using (TlvReader reader = new TlvReader(new MemoryStream(data)))
                {
                    rawTag = new RawTag(reader.ReadTag());
                }

                if (rawTag.Type == GetPduTagType(false))
                {
                    if (_pduVersion == PduVersion.v1)
                    {
                        throw new KsiServiceUnexpectedResponseFormatException("Received PDU v2 response to PDU v1 request. Configure the SDK to use PDU v2 format.");
                    }

                    pdu = GetPdu(rawTag);
                }
                else if (rawTag.Type == GetPduTagType(true))
                {
                    if (_pduVersion == PduVersion.v2)
                    {
                        if (!IsLegacyRequestSupported())
                        {
                            throw new KsiServiceUnexpectedResponseFormatException("Received PDU v1 response to PDU v2 request.");
                        }

                        throw new KsiServiceUnexpectedResponseFormatException("Received PDU v1 response to PDU v2 request. Configure the SDK to use PDU v1 format.");
                    }

                    legacyPdu = GetLegacyPdu(rawTag);
                }
                else
                {
                    throw new KsiServiceException("Unknown response PDU tag type: " + rawTag.Type.ToString("X"));
                }

                if (legacyPdu != null)
                {
                    return(GetLegacyResponsePayload(legacyPdu, requestId));
                }
                else
                {
                    CheckAggregatorConfigChange(pdu);
                    CheckExtenderConfigChange(pdu);

                    return(GetResponsePayload(data, pdu, requestId));
                }
            }
            catch (TlvException e)
            {
                KsiException ksiException = new KsiServiceException("Could not parse response message: " + Base16.Encode(data), e);
                if (requestId.HasValue)
                {
                    Logger.Warn("Request failed (request id: {0}): {1}", requestId, ksiException);
                }
                else
                {
                    Logger.Warn("Request failed: {0}", ksiException);
                }
                throw ksiException;
            }
            catch (KsiException e)
            {
                if (requestId.HasValue)
                {
                    Logger.Warn("Request failed (request id: {0}){1}{2}{1}PDU:{1}{3}", requestId, Environment.NewLine, e, legacyPdu ?? pdu ?? (ITlvTag)rawTag);
                }
                else
                {
                    Logger.Warn("Request failed.{0}{1}{0}PDU:{0}{2}", Environment.NewLine, e, legacyPdu ?? pdu ?? (ITlvTag)rawTag);
                }

                throw;
            }
        }