--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/L2CapEnhancedDataController.h Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,566 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#ifndef L2CAPENHANCEDDATACONTROLLER_H
+#define L2CAPENHANCEDDATACONTROLLER_H
+
+#include <e32std.h>
+#include <bt_sock.h>
+
+#include "L2CapPDU.h"
+#include "L2CapSDUQueue.h"
+#include "L2CapDataController.h"
+#include "l2signalmgr.h"
+
+
+NONSHARABLE_CLASS(CL2CapStreamingController) : public CL2CapBasicDataController, public MPduOwner
+ {
+public:
+ CL2CapStreamingController(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, CL2CapSDUQueue& aSDUQueue, TL2CapDataControllerConfig* aConfig);
+ virtual ~CL2CapStreamingController();
+
+ virtual void ProcessFlushTimerExpiry();
+
+ // MPduOwner
+ virtual void HandlePduSendComplete(HL2CapPDU& aPdu);
+ virtual void HandlePduSendError(HL2CapPDU& aPdu);
+
+protected:
+ virtual void HandleIncomingIFrameL(RMBufChain& aIFrame);
+ virtual TInt HandleOutgoingIFrame(HIFramePDU* aIFrame);
+
+ virtual HL2CapPDU* GetPduL();
+
+protected:
+ // Window related information, as defined in the spec.
+ // Sequencer for outgoing I-Frame numbers.
+ TUint8 iNextTxSeq;
+ // Next expected incoming I-Frame number.
+ TUint8 iExpectedTxSeq;
+ };
+
+
+NONSHARABLE_CLASS(RL2CapErtmTimerManager) : public RL2CapRetransmissionModeTimerManager
+ {
+public:
+ RL2CapErtmTimerManager(class CL2CapEnhancedReTxController& aClient);
+ void Close();
+
+ void StartLocalBusyDelayTimer();
+ void StopLocalBusyDelayTimer();
+ inline TBool IsLocalBusyDelayTimerRunning() const;
+private:
+ void HandleLocalBusyDelayTimerExpired();
+ static TInt LocalBusyDelayTimerExpired(TAny* aTimerMan);
+private:
+ // Peer Retransmission Timer value is divided by this to obtain the LB delay timer
+ // value to use.
+ const static TInt KLocalBusyDelayTimerDenominator = 2;
+private:
+ TBool iLocalBusyDelayTimerRunning;
+ TDeltaTimerEntry iLocalBusyDelayTimerEntry;
+ };
+
+
+class CL2CapEnhancedReTxController;
+class RL2CapErtmOutgoingQueue;
+
+// Encapsulates a list of unacknowledged I-Frames and an index for fast TxSeqs
+// lookups for SREJ retransmissions.
+NONSHARABLE_CLASS(RL2CapErtmUnacknowledgedIFrames)
+ {
+public:
+ RL2CapErtmUnacknowledgedIFrames();
+ void Close();
+
+ inline void Append(HIFramePDU& aFrame);
+ inline void Remove(HIFramePDU& aFrame);
+ inline HIFramePDU* First() const;
+ inline HIFramePDU* Last() const;
+ inline HIFramePDU* operator[](TUint8 aTxSeq) const;
+ inline TBool IsEmpty() const;
+ inline TDblQueIter<HIFramePDU> Iterator();
+private:
+ // Ordered chronologically, oldest to youngest.
+ TDblQue<HIFramePDU> iFrameList;
+ // Indexed by TxSeq.
+ TFixedArray<HIFramePDU*, KL2CapTxSeqValues> iFrameIndex;
+ };
+
+NONSHARABLE_CLASS(CL2CapErtmDataTransmitter)
+ {
+public:
+ static CL2CapErtmDataTransmitter* NewL(CL2CapEnhancedReTxController& aController);
+ virtual ~CL2CapErtmDataTransmitter();
+
+ void HandleIncomingIFrame(RMBufChain& aIFrame);
+ void HandleIncomingSFrameL(RMBufChain& aSFrame);
+
+ TBool HaveSpaceInOutgoingWindow() const;
+ HIFramePDU* GetIFrameToSendL();
+
+ void HciCompletedIFrame(HIFramePDU& aIFrame);
+
+ void AckTimerExpired();
+
+ inline TBool RemoteBusy() const;
+
+ inline TBool IsWaitAckStatePending() const;
+ inline void EnterWaitAckState();
+ inline TBool InWaitAckState() const;
+
+ inline TUint8 NextTxSeq() const;
+ inline TUint8 ExpectedAckSeq() const;
+
+ inline TBool IsReqSeqValid(TUint8 aReqSeq);
+
+ inline TBool HaveUnackedIFrames() const;
+ inline TBool IsRetransmittingUnackedIFrames() const;
+ inline TBool IsNextUnackedIFrameAwaitingHciCompletion() const;
+
+private:
+ CL2CapErtmDataTransmitter(CL2CapEnhancedReTxController& aController);
+
+ void HandleReqSeqAck(TUint8 aReqSeq);
+ void HandleFinalAck();
+
+ void HandleIncomingSRejL(RMBufChain& aSRejFrame);
+
+ void RetransmitUnackedIFrames();
+
+ inline void SendOrPendL(HIFramePDU& aIFrame);
+
+ inline RL2CapRetransmissionModeTimerManager& TimerMan();
+ inline RL2CapErtmOutgoingQueue& OutgoingQ();
+private:
+ CL2CapEnhancedReTxController& iController;
+
+ // Outgoing window information, as defined by the spec.
+ // Sequencer for outgoing I-Frame numbers. With the little exception that when
+ // a decision to retransmit all unacked I-Frames is made, this gets set to the
+ // first number of the bunch and frames are retransmitted until iUnackedIFrames[iNextTxSeq]
+ // is NULL again.
+ TUint8 iNextTxSeq;
+ // I-Frames preceding this number have been acknowledged by the peer.
+ TUint8 iExpectedAckSeq;
+
+ RL2CapErtmUnacknowledgedIFrames iUnackedIFrames;
+
+ // If remote indicates busy condition we keep transmitting within send window limits,
+ // but disable our retransmission timer.
+ TBool iRemoteBusy;
+
+ // For protecting against duplicates. Explained in HandleIncomingSFrameL().
+ // See state tables in the spec.
+ TBool iSRejActioned;
+ TUint8 iSRejSaveReqSeq;
+
+ // Signals to GetPdu that we need to enter WAIT_ACK.
+ TBool iWaitAckStatePending;
+ // Xmit state WAIT_ACK (syncing ReqSeq to start retransmission from) - see spec.
+ TBool iInWaitAckState;
+ };
+
+
+class CL2CapErtmDataReceiver;
+
+NONSHARABLE_CLASS(TL2CapErtmMissingTxSeqs)
+ {
+public:
+ TL2CapErtmMissingTxSeqs();
+
+ // Register SREJ-requested I-Frame TxSeq.
+ inline void AppendTxSeq(TUint8 aTxSeq);
+
+ // Received an SREJ requested I-Frame. Take note of this fact and indicate whether
+ // it was out of sequence wrt to previous ones. If so, GetNextTxSeqForResend() needs
+ // to be called in a loop to return all the TxSeqs to re-request.
+ TBool ReceivedTxSeq(TUint8 aTxSeq);
+ inline TBool GetNextTxSeqForResend(TUint8& aTxSeq);
+
+ TBool IsTxSeqOnTheList(TUint8 aTxSeq) const;
+ inline TUint8 LastTxSeq() const;
+ inline TBool IsEmpty() const;
+
+ inline TBool AllRequestedFramesReceived() const;
+ inline TUint8 ExpectedSRejTxSeq() const;
+ inline TInt NumMissingTxSeqs() const;
+ inline TBool HaveSpaceForNewTxSeqs(TInt aNumTxSeqs) const;
+ inline void Reset();
+private:
+#ifdef __FLOG_ACTIVE
+ void Log();
+#endif
+public:
+ const static TUint KMaxSRejsInFlight = 1;
+private:
+ TFixedArray<TUint8, KMaxSRejsInFlight> iMissingTxSeqs;
+ // Number of TxSeqs missing since entering SREJ_SENT.
+ // The array is split in two parts - frames already received and the ones we're still
+ // waiting for.
+ TInt iNumMissingTxSeqs;
+ // Frames below this index have been received.
+ TInt iExpectedRecvIdx;
+ // Frames starting from this index need to be re-requested.
+ TInt iResendIdx;
+ };
+
+
+NONSHARABLE_CLASS(TL2CapErtmReceiverStateBase)
+ {
+public:
+ // Note: think about the frame parameter as "the frame that caused the transition",
+ // though it's only really used for SREJ_SENT. Still, this is the cleanest form
+ // of passing the required information.
+ virtual void EnterL(RMBufChain* aIFrame);
+ virtual void ExitL();
+ virtual void HandleIncomingIFrameL(RMBufChain& aIFrame) = 0;
+ virtual void HandlePollL() = 0;
+ virtual TBool IsLocalBusySupported() const;
+
+ // Called to notify the state that the incoming SDU Q has just consumed some
+ // I-Frames and we could slide the receive window if we can (we can't in SREJ_SENT).
+ virtual void TxSeqExpectedBySduQChanged(TUint8 aTxSeq) = 0;
+protected:
+ TL2CapErtmReceiverStateBase(CL2CapErtmDataReceiver& aReceiver);
+protected:
+ CL2CapErtmDataReceiver& iReceiver;
+ };
+
+NONSHARABLE_CLASS(TL2CapErtmReceiverStateRecv) : public TL2CapErtmReceiverStateBase
+ {
+public:
+ TL2CapErtmReceiverStateRecv(CL2CapErtmDataReceiver& aReceiver);
+ virtual void EnterL(RMBufChain* aIFrame);
+ virtual void HandleIncomingIFrameL(RMBufChain& aIFrame);
+ virtual void HandlePollL();
+ virtual TBool IsLocalBusySupported() const;
+ virtual void TxSeqExpectedBySduQChanged(TUint8 aTxSeq);
+ };
+
+NONSHARABLE_CLASS(TL2CapErtmReceiverStateRejSent) : public TL2CapErtmReceiverStateBase
+ {
+public:
+ TL2CapErtmReceiverStateRejSent(CL2CapErtmDataReceiver& aReceiver);
+ virtual void EnterL(RMBufChain* aIFrame);
+ virtual void HandleIncomingIFrameL(RMBufChain& aIFrame);
+ virtual void HandlePollL();
+ virtual void TxSeqExpectedBySduQChanged(TUint8 aTxSeq);
+ };
+
+NONSHARABLE_CLASS(TL2CapErtmReceiverStateSRejSent) : public TL2CapErtmReceiverStateBase
+ {
+public:
+ TL2CapErtmReceiverStateSRejSent(CL2CapErtmDataReceiver& aReceiver);
+ virtual void EnterL(RMBufChain* aIFrame);
+ virtual void ExitL();
+ virtual void HandleIncomingIFrameL(RMBufChain& aIFrame);
+ virtual void HandlePollL();
+ virtual void TxSeqExpectedBySduQChanged(TUint8 aTxSeq);
+private:
+ void SendSRejsUpToReceivedIFrameL(RMBufChain& aIFrame);
+private:
+ TBool iGoToRej;
+ TL2CapErtmMissingTxSeqs iMissingTxSeqs;
+ };
+
+
+// Incoming I-Frame queue. Used both when the SDU Q is full and we have to buffer incoming
+// frames (a whole window is buffered) and when SREJ_SENT is entered and we wait for
+// SREJ-requested retransmissions to come through.
+NONSHARABLE_CLASS(RL2CapErtmIncomingIFrameQueue)
+ {
+public:
+ RL2CapErtmIncomingIFrameQueue();
+ void Close();
+
+ // Enqueue the new I-Frame and try to consume as much of the existing ones as possible.
+ void HandleIncomingIFrameL(RMBufChain& aIFrame, const CL2CapErtmDataReceiver& aReceiver);
+ // Pass as many consequent I-Frames to SDU Q ("consume them") as possible.
+ void ConsumeUpToFirstGapL(const CL2CapErtmDataReceiver& aReceiver);
+ inline void DeleteAllFrames();
+
+ inline TBool IsEmpty() const;
+ inline TUint8 TxSeqExpectedBySduQ() const;
+private:
+ void Insert(RMBufChain& aIFrame);
+#ifdef _DEBUG
+ void LogQ();
+#endif
+private:
+ RMBufPktQ iQueue;
+ // Next TxSeq in sequence for SDU Q.
+ // If we're not in SREJ_SENT, it's = BufferSeq.
+ // If we're in SREJ_SENT, it's >= BufferSeq.
+ TUint8 iTxSeqExpectedBySduQ;
+ };
+
+NONSHARABLE_CLASS(CL2CapErtmDataReceiver)
+ {
+public:
+ static CL2CapErtmDataReceiver* NewL(CL2CapEnhancedReTxController& aController);
+ virtual ~CL2CapErtmDataReceiver();
+
+ void HandleIncomingIFrameL(RMBufChain& aIFrame);
+ void HandleIncomingSFrameL(RMBufChain& aSFrame);
+
+ // Recv window management.
+ void SendPeerAckTimerExpiredL();
+ TBool IsEndOfReceiveWindowApproaching() const;
+ template<typename FrameType>
+ void StampWithReqSeq(FrameType& aFrame);
+
+ // Send SREJ or REJ ?
+ TBool IsSRejPreferredToRej(TUint8 aExpectedTxSeq, TUint8 aReceivedTxSeq);
+
+ // Incoming SDU Q status/LocalBusy.
+ void SetIncomingSduQFullL(TBool aIncomingSduQFull);
+ void UpdateLocalBusyStatusL();
+ inline TBool IsIncomingSduQFull() const;
+ inline TBool LocalBusy() const;
+ void LocalBusyDelayTimerExpired();
+
+ inline void FlushBufferedIncomingIFrames();
+
+ inline TBool IsWaitFStatePending() const;
+ inline void EnterWaitFState();
+ inline TBool InWaitFState() const;
+
+ // Window state accessors, both for state objects and the controller.
+ inline TUint8 ExpectedTxSeq() const;
+ inline void SetExpectedTxSeq(TUint8 aTxSeq);
+ inline void IncExpectedTxSeq();
+
+ inline TUint8 BufferSeq() const;
+ inline void SetBufferSeq(TUint8 aTxSeq);
+
+ inline TUint8 LastAckReqSeq() const;
+
+ inline TUint8 TxSeqExpectedBySduQ() const;
+
+ inline TBool SendAck() const;
+
+ // As defined in the spec.
+ inline TBool IsTxSeqUnexpected(TUint8 aTxSeq);
+ inline TBool IsTxSeqInvalid(TUint8 aTxSeq);
+
+ // Handy helpers.
+ HSFramePDU* GetAckFrameL(TBool aFinal = EFalse);
+ inline void PassToIncomingQL(RMBufChain& aIFrame);
+ inline void PassToSduQL(RMBufChain& aIFrame) const;
+
+ inline void SetStateRecvL();
+ inline void SetStateRejSentL();
+ inline void SetStateSRejSentL(RMBufChain& aUnexpectedIFrame);
+
+ inline RL2CapErtmTimerManager& TimerMan();
+ inline RL2CapErtmOutgoingQueue& OutgoingQ();
+ inline CL2CapEnhancedReTxController& Controller() const;
+
+private:
+ CL2CapErtmDataReceiver(CL2CapEnhancedReTxController& aController);
+ void ConstructL();
+
+ void SetStateL(TL2CapErtmReceiverStateBase& aState, RMBufChain* aIFrame);
+
+ void HandleFinalAckL();
+
+ void EnterLocalBusyL();
+ void ExitLocalBusy();
+
+private:
+ // This value represents the number of frames the peer can still send within its current TxWin
+ // when we decide to send an acknowledgement. E.g. if the peer TxWindow is 20 then we'll send
+ // an acknowledgement after receiving the 18th frame, thus moving the peer's window and ready
+ // to receive next 18 frames before sending the next ack. Sending the ack before the end
+ // of the receive window is reached prevents transmission delays caused by the peer waiting
+ // for an ack before it can send more.
+ const static TUint8 KReceiveWinFreeSpaceLeftToTriggerAck = 2;
+ // Used to decide whether to send an SREJ or a REJ. An SREJ will never be sent if the gap
+ // between ExpectedTxSeq and the received frame's TxSeq is wider than this value.
+ const static TUint8 KSRejMissingFrameThreshold = 1;
+
+ __ASSERT_COMPILE(KSRejMissingFrameThreshold <= TL2CapErtmMissingTxSeqs::KMaxSRejsInFlight);
+
+private:
+ CL2CapEnhancedReTxController& iController;
+
+ // Window variables as defined in the spec.
+ // Next expected I-Frame num.
+ TUint8 iExpectedTxSeq;
+ // Ack num (ReqSeq) that can be sent to the peer. Usually equal to ExpectedTxSeq,
+ // unless SDU Queue is full or we're in SREJ_SENT. IOW the beginning of our receive window.
+ TUint8 iBufferSeq;
+ // Stores the acknowledgment number most recently sent to the peer.
+ // Used to detect that we're reaching the end of peer's send window and hence should
+ // send an ack.
+ TUint8 iLastAckReqSeq;
+
+ // This means SDU queue won't accept any more data, so we can't acknowledge anything new.
+ // Whether LocalBusy can be entered depends on the receive state (RECV only) and other nasty
+ // details.
+ TBool iIncomingSduQFull;
+ // This means we're sending out RNRs instead of RRs. Proper LocalBusy.
+ TBool iLocalBusy;
+ // Xmit state WAIT_F (exiting Local Busy) - see spec.
+ TBool iInWaitFState;
+ // Signals to GetPdu that we need to enter WAIT_F.
+ TBool iWaitFStatePending;
+
+ // This is set to True when we're approaching the end of receive window or the send peer ack
+ // timer expires, or sending a generic ack is needed for some other reason.
+ // While flags are bad bad bad in general because they don't store time-ordering information
+ // of related events (that's why we have the outgoing Q instead), it is fine this case -
+ // - it's legitimate to send a vanilla ack at any time. It's an optimization that prevents
+ // multiple acks to be queued when the outgoing pipe gets clogged for a while but we keep
+ // receiving incoming I-Frames.
+ TBool iSendAck;
+
+ RL2CapErtmIncomingIFrameQueue iIncomingIFrameQ;
+
+ // "Heavyweight" State pattern.
+ TL2CapErtmReceiverStateBase* iReceiveState;
+
+ TL2CapErtmReceiverStateRecv iStateRecv;
+ TL2CapErtmReceiverStateRejSent iStateRejSent;
+ TL2CapErtmReceiverStateSRejSent iStateSRejSent;
+ };
+
+// This encapsulates the managament of the outgoing packet queue.
+// Every packet should go through the queue before it's sent - certain actions need to be
+// executed when a packet is enqueued/dequeued and to make sure that it's always done
+// the queue is hidden in this class.
+NONSHARABLE_CLASS(RL2CapErtmOutgoingQueue)
+ {
+public:
+ RL2CapErtmOutgoingQueue(CL2CapEnhancedReTxController& aController);
+ void Close();
+
+ // These queue frames that can be sent immediately.
+ void QueueIFrameL(HIFramePDU& aIFrame);
+ void QueueAckingSFrame(HSFramePDU& aSFrame);
+ void QueueNonAckingSFrame(HSFramePDU& aSFrame, TUint8 aReqSeq);
+
+ // This queues the I-Frame onto a separate list pending clearing of WAIT_ACK.
+ // It's used for I-Frames requested with SREJs coming through in WAIT_ACK.
+ void PendRetransmitIFrameL(HIFramePDU& aIFrame);
+
+ // This requeues the I-Frames from the pending list onto the normal send queue.
+ void SendPendingRetransmitIFramesL();
+ // Used when we decide to retransmit all I-Frames when we still haven't sent
+ // out the SREJ-requested ones.
+ void CancelPendingRetransmitIFrames();
+
+ void DeleteAllFrames();
+
+ // Called by controller's GetPdu when the link muxer asks for a frame to send.
+ HL2CapPDU* DequeueNextToSend();
+
+ inline TBool HaveFramesToTransmit() const;
+ inline TBool HavePendingRetransmitIFrames() const;
+private:
+ CL2CapEnhancedReTxController& iController;
+ TSglQue<HL2CapPDU> iOutgoingQ;
+ // I-Frames SREJ-requested by the remote when we're in WAIT_ACK and thus can't send data.
+ TSglQue<HIFramePDU> iPendRetransmitIFrameQ;
+ };
+
+NONSHARABLE_CLASS(CL2CapEnhancedReTxController)
+ : public CL2CapBasicDataController, public MPduOwner, public MRetransmissionModeTimerClient
+ {
+public:
+ static CL2CapEnhancedReTxController* NewL(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, CL2CapSDUQueue& aSDUQueue, TL2CapDataControllerConfig* aConfig);
+ virtual ~CL2CapEnhancedReTxController();
+
+ // MPduOwner
+ // Called back by I-Frames on HCI completion.
+ virtual void HandlePduSendComplete(HL2CapPDU& aPdu);
+ virtual void HandlePduSendError(HL2CapPDU& aPdu);
+
+ // Called back by PDUs going out through the HL2CapPDU::DeliverOutgoingPDU
+ // double-dispatch trickery, in the context of GetPduL.
+ virtual TInt HandleOutgoingIFrame(HIFramePDU* aIFrame);
+ virtual TInt HandleOutgoingSFrame(HSFramePDU* aSFrame);
+
+ // Called by the SDU Q when it gets full/space frees up.
+ virtual void SetIncomingSduQFull(TBool aIncomingSduQFull);
+
+ // Called by the SDU Q when the connection is being shutdown by the application
+ // and data needs to be delivered reliably before we disconnect.
+ virtual TBool DeliverOutgoingDataAndSignalToSduQWhenDone();
+ inline TBool IsOutgoingDataPathClosing();
+ // The data transmitter calls this when it wants to notify the SDU Q that it has
+ // delivered all outgoing data and so we can now be destroyed.
+ inline void SignalOutgoingDataDeliveredToSduQ();
+
+ // Incoming Q calls this to pass an I-Frame to the SDU Q.
+ inline void PassToSduQL(RMBufChain& aIFrame);
+
+ // Called from SDU Q when it's got new PDUs to send.
+ virtual void OutgoingPduAvailableOnSduQ();
+
+ // Called to evaluate whether we want to send anything.
+ inline void NotifyMuxerOfPdusToSendIfHaveSome();
+
+ // Puts the current acknowledgement number into the frame being queued for send.
+ // Templated to handle both I-Frames and S-Frames.
+ template<typename FrameType>
+ inline void StampWithReqSeq(FrameType& aFrame);
+
+ // A helper for when a ReqSeq/Final ack needs to be sent - tries to piggy-back on I-Frames.
+ void SendIOrRrOrRnrL(TBool aFinal);
+
+ virtual void LocalBusyDelayTimerExpired();
+
+ inline TBool IsPollOutstanding() const;
+ inline TBool IsFBitValid(TBool aFinal);
+
+ inline RL2CapErtmOutgoingQueue& OutgoingQ();
+ inline RL2CapErtmTimerManager& TimerMan();
+
+protected:
+ CL2CapEnhancedReTxController(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, CL2CapSDUQueue& aSDUQueue, TL2CapDataControllerConfig* aConfig);
+ void ConstructL();
+
+ // These are the entry points for incoming PDUs, called and trapped by a dispatch routine
+ // in CL2CapBasicDataController.
+ virtual void HandleIncomingIFrameL(RMBufChain& aIFrame);
+ virtual void HandleIncomingSFrameL(RMBufChain& aSFrame);
+
+ // Provide a PDU for transmission. Called and trapped by GetPdu in CL2CapBasicDataController.
+ virtual HL2CapPDU* GetPduL();
+
+ void HandleFinalAck();
+
+ // From MErtmModeTimerClient
+ virtual void MonitorTimerExpired();
+ virtual void AckTimerExpired();
+ virtual void SendPeerAckTimerExpired();
+ virtual TUint16 MonitorTimeout();
+ virtual TUint16 RetransmissionTimeout();
+ virtual TUint16 PeerRetransmissionTimeout();
+private:
+ TUint8 iPollSFrameTransmitCount;
+ TBool iDeliverOutgoingDataAndSignalToSduQWhenDone;
+
+ RL2CapErtmOutgoingQueue iOutgoingQ;
+ RL2CapErtmTimerManager iTimerMan;
+ CL2CapErtmDataReceiver* iReceiver;
+ CL2CapErtmDataTransmitter* iTransmitter;
+ };
+
+#include "L2CapEnhancedDataController.inl"
+
+#endif /*L2CAPENHANCEDDATACONTROLLER_H*/