bluetooth/btstack/l2cap/L2CapSDUQueue.h
changeset 0 29b1cd4cb562
child 51 20ac952a623c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/L2CapSDUQueue.h	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,254 @@
+// Copyright (c) 2004-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 L2CAPSDUQUEUE_H_
+#define L2CAPSDUQUEUE_H_
+
+#include <bt_sock.h>
+
+#include "L2CapSDU.h"
+
+
+class TL2CapDataControllerConfig;
+class CL2CapBasicDataController;
+class CL2CAPMux;
+class CL2CAPConnectionSAP;
+
+NONSHARABLE_CLASS(CL2CapSDUQueue) : public CBase,
+                       public ML2CapSDUHandler
+	{
+public:
+	// Can buffer this many outgoing SDUs.
+	const static TUint8 KDefaultOutboundQueueSize = 2;
+
+	// Can buffer this many incoming SDUs. That's after reassembly, doesn't
+	// include I-Frames that a data controller can buffer on its own.
+	// Note: leaving this at 5 until the problem with legacy data controllers putting
+	// frames on the Q even when they've been told not to is fixed - then should probably
+	// decrease to 2.
+	const static TUint8 KInboundQueueFlowCtrlThreshold = 5;
+
+	// During normal shutdown initiated by our upper layer we try to deliver
+	// all outstanding data, but kill it brutally if this time is exceeded.
+	const static TUint8 KOutgoingQueueClosingTimer = 60;
+
+	enum TIncomingSDUQueueCloseAction
+		{
+		EDrainIncomingQueue,
+		EImmediatelyCloseIncomingQueue,
+		};
+
+	enum TOutgoingSDUQueueCloseAction
+		{
+		EDrainOutgoingQueue,
+		EImmediatelyCloseOutgoingQueue,
+		};
+
+	static CL2CapSDUQueue* NewLC(CL2CAPConnectionSAP& aL2CapSap,
+	                             TL2CAPPort aLocalCID,
+	                             TL2CAPPort aRemoteCID,
+	                             CL2CAPMux& aMuxer,
+	                             TUint16 aPDUSize,
+  	                             TUint8 aOutboundQueueSize,
+	                             TL2CapDataControllerConfig* aConfig,
+	                             TUint16 aFlushTimeout, 
+	                             TUint16 aMaxOutgoingMTU,
+	                             TUint16 aMaxIncomingMTU,
+	                             TBool aCanDropSdus);
+	static CL2CapSDUQueue* NewL(CL2CAPConnectionSAP& aL2CapSap,
+                                TL2CAPPort aLocalCID,
+                                TL2CAPPort aRemoteCID,
+	                            CL2CAPMux& aMuxer,
+	                            TUint16 aPDUSize,
+	                            TUint8 aOutboundQueueSize,
+	                            TL2CapDataControllerConfig* aConfig,
+	                            TUint16 aFlushTimeout, 
+                                TUint16 aMaxOutgoingMTU,
+                                TUint16 aMaxIncomingMTU,
+                                TBool aCanDropSdus);
+ 
+	~CL2CapSDUQueue();
+
+	static TInt CanSendAsyncCallBack(TAny *aSDUQueue);
+	static TInt SDUsSentAsyncCallBack(TAny *aSDUQueue);
+	static TInt QueueClosingAsyncCallBack(TAny *aSDUQueue);
+	
+	static TInt OutgoingQueueClosingTimerExpired(TAny *aSDUQueue);
+	
+	void ProcessFlushTimerExpiry(CL2CapSDU& aL2CapSDU);
+
+	HL2CapPDU* GetPDU();
+	inline TBool HavePDUToSend() const;
+
+	TInt PutIFramePDU(RMBufChain& dataFrame);		
+	void PutBFramePDU(RMBufChain& dataFrame);
+
+	void FlushCurrentlyAssembledSdu();
+	void FlushOldestIncomingSdu();
+	inline TBool IsIncomingQueueFull() const;
+	
+
+	TInt Write(RMBufChain& aSDUData);
+	void Read(RMBufChain& readData);
+		
+	void CloseSDUQueue(TIncomingSDUQueueCloseAction aIncomingQueueAction = EImmediatelyCloseIncomingQueue, 
+	                   TOutgoingSDUQueueCloseAction aOutgoingQueueAction = EImmediatelyCloseOutgoingQueue);
+
+	void DataControllerDeliveredOutgoingData();
+
+	inline void SuspendSDUQueue();
+	void ResumeSDUQueue(TL2CapDataControllerConfig* aConfig,
+	                    TUint16 aFlushTimeout, 
+	                    TUint16 aPDUSize,
+	                    TUint16 aMaxOutgoingMTU,
+	                    TUint16 aMaxIncomingMTU);
+	void UpdateChannelPriority(TUint8 aNewPriority);
+	void ErrorD(TInt aErrorCode);
+
+#ifdef _DEBUG
+	TInt GetDataPlaneConfig(TL2DataPlaneConfig& conf) const;
+	void PretendIncomingSduQFull(TBool aIncomingSduQFull);
+#endif
+
+	inline TUint16 MaxOutgoingMTU() const;
+	inline TUint16 MaxIncomingMTU() const;
+
+	inline TUint16 MaximumPDUSize() const;
+	inline TUint16 OptimalPDUSize() const;
+	inline void SetOptimalPDUSize(TUint16 aPDUSize);
+
+	TBool IsBasicDataVersion() const;
+
+private:
+	void ConstructL(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, TL2CapDataControllerConfig* aConfig);
+	
+	CL2CapSDUQueue(CL2CAPConnectionSAP& aL2CapSap,
+				   TUint8 aOutboundQueueSize,
+	               TUint16 aPDUSize,
+	               TUint16 aFlushTimeout, 
+                   TUint16 aMaxOutgoingMTU,
+                   TUint16 aMaxIncomingMTU,
+                   TBool aCanDropSdus);
+
+
+	void SDURemovedFromOutboundQueue();
+	void CanSend();
+	void SDUsSent();
+
+	TInt HandleIncompleteSDU(RMBufChain& aIncompleteSDU);
+
+	void TryToCloseQueue();
+	void SDUQueueClosed();
+
+	void StartOutgoingQueueClosingTimer();
+	void CancelOutgoingQueueClosingTimer();
+	void HandleOutgoingQueueClosingTimerExpired();
+
+private:		
+	CL2CAPConnectionSAP& iL2CapSap;
+	TUint8 iOutboundQueueSize;
+	
+	CL2CapBasicDataController* iDataController;
+
+	TDblQue<CL2CapSDU> iOutgoingSDUs;
+	TDblQue<CL2CapSDU> iOutgoingPulledSDUs;
+
+	RMBufPktQ iIncomingSDUs;
+	RMBufChain iCurrentIncomingSDU;
+	TUint16 iCurrentIncomingSDULength;
+	
+	TUint16 iFlushTimeout;
+	TUint16 iCurrentPDUSize;
+	TUint16 iMaximumPDUSize;
+	TUint16 iNegotiatedPDUSize;
+	
+	TUint8 iCurrentOutboundQueueLength;
+	TUint16 iCurrentInboundQueueLength;
+	TBool iOutboundSendingBlocked;
+	TBool iOutboundQueueSuspended;
+	
+	CAsyncCallBack* iCanSendAsyncCallBack;
+	CAsyncCallBack* iSDUSentAsyncCallBack;
+	CAsyncCallBack* iQueueClosingCallBack;		
+
+	TBool iSDUQueuesClosing;
+	TBool iIncomingQueueClosed;
+	TBool iOutgoingQueueClosed;
+
+	TDeltaTimerEntry iOutgoingQueueClosingTimer;
+	TBool iOutgoingQueueClosingTimerRunning;
+
+	TUint16 iMaxOutgoingMTU;
+	TUint16 iMaxIncomingMTU;
+
+	TBool	iCanDropSdus;
+	};
+
+
+inline TBool CL2CapSDUQueue::IsIncomingQueueFull() const
+	{
+	return iCurrentInboundQueueLength >= KInboundQueueFlowCtrlThreshold;
+	}
+
+inline TUint16 CL2CapSDUQueue::MaxOutgoingMTU() const
+	{
+	return iMaxOutgoingMTU;
+	}
+	
+inline TUint16 CL2CapSDUQueue::MaxIncomingMTU() const
+	{
+	return iMaxIncomingMTU;
+	}
+
+inline TUint16 CL2CapSDUQueue::MaximumPDUSize() const
+	{
+	return iMaximumPDUSize;
+	}
+
+inline TUint16 CL2CapSDUQueue::OptimalPDUSize() const
+	{
+	return iCurrentPDUSize;
+	}
+
+inline void CL2CapSDUQueue::SetOptimalPDUSize(TUint16 aPDUSize)
+	{
+	iCurrentPDUSize = aPDUSize;
+	}
+
+inline void CL2CapSDUQueue::SuspendSDUQueue()
+	{
+	iOutboundQueueSuspended = ETrue;
+	}
+
+inline TBool CL2CapSDUQueue::HavePDUToSend() const
+	{
+	TBool havePDU = EFalse;
+	if(!iOutgoingSDUs.IsEmpty())
+		{
+		CL2CapSDU* sdu = iOutgoingSDUs.First();
+		// If the outbound queue is suspended, and this is the start
+		// of a new SDU.  Then don't send a PDU.
+		if(!(iOutboundQueueSuspended && sdu->CurrentPDUIsFirstPDU()))
+			{
+			if (!sdu->IsSDUEmpty())
+				{
+				havePDU = ETrue;
+				}
+			}
+		}
+	return havePDU;
+	}
+
+#endif