bluetooth/btstack/rfcomm/rfcommmuxer.h
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/rfcomm/rfcommmuxer.h	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,287 @@
+// Copyright (c) 1999-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 RFCOMMMUXER_H
+#define RFCOMMMUXER_H
+
+#include <es_prot.h>
+#include <bttypes.h>
+#include "rfcommsap.h"
+#include "rfcommframe.h"
+#include "rfcommflow.h"
+
+class CRfcommSignalFrame;
+class CRfcommMuxChannel;
+class CRfcommFlowStrategyFactory;
+class CMuxChannelStateFactory;
+class TRfcommFlowStrategy;
+/**
+   Acts as the TS7.10 multiplexer.
+   
+   There is one of these per remote device, as only one RFCOMM
+   multiplexer session can be run between two devices.  This class
+   acts as an internal socket binding to a lower level SAP.  Thus we
+   derive from MSocketNotify so that the SAP can directly notify us of events.
+
+**/
+NONSHARABLE_CLASS(CRfcommMuxer) : public CBase, public MSocketNotify
+	{
+friend class CRfcommProtocol;
+friend class CRfcommMuxChannel;
+
+public:
+	// Create/destroy
+
+	// Two flavours of factory - one takes an L2CAP connection which should 
+	// be used by the Mux channel associated with this muxer. The other 
+	// takes a CProtocolBase which it can use to create its own connection
+	static CRfcommMuxer* NewL(CRfcommProtocol& aProt, CProtocolBase& aL2CAP,
+							  CMuxChannelStateFactory& aFactory);
+
+	static CRfcommMuxer* NewL(CRfcommProtocol& aProt, CServProviderBase* aSAP,
+							  CMuxChannelStateFactory& aFactory);
+	
+	~CRfcommMuxer();
+	// Interface for the Protocol to request services
+	void Bind(TBTDevAddr& aAddr);
+	void AddSAP(CRfcommSAP& aSAP);
+	void DetachSAP(CRfcommSAP& aSAP);
+
+	void GetInboundServerChannelsInUse(TFixedArray<TBool, KMaxRfcommServerChannel>& aChannelInUse);
+	
+	// Interface for the SAPs to request actions
+	TUint8 MakeOutboundDLCI(TUint8 aServerChannel);
+	TUint8 MakeInboundDLCI(TUint8 aServerChannel);
+	TUint8 MakeServerChannel(TUint8 aDLCI);
+
+	TInt SendSABM(CRfcommSAP& aSAP);
+	TInt SendMSC(CRfcommSAP& aSAP, TUint8 aFlags);
+	TInt SendMSCRsp(CRfcommSAP& aSAP, TUint8 aFlags);
+	TInt SendRLS(CRfcommSAP& aSAP, TUint8 aStatus);
+	TInt SendRLSRsp(CRfcommSAP& aSAP, TUint8 aStatus);
+	TInt SendRPN(CRfcommSAP& aSAP, TBool aCommand, TUint8 aLength, 
+				 const TRfcommRPNTransaction& aRPNTransaction);
+	TInt SendUA(CRfcommSAP& aSAP);
+	TInt SendUA(TUint8 aDLCI);
+	TInt SendPN(CRfcommSAP& aSAP, const TRfcommPortParams& params);
+	TInt SendPNResponse(CRfcommSAP& aSAP, const TRfcommPortParams& params);
+	void SendDISC(CRfcommSAP& aSAP);
+	void SendDISC(TUint8 aDLCI);
+	void SendDM(TUint8 aDLCI);
+	TInt SendFCon();
+	TInt SendFCoff();
+	void Donate(CRfcommSAP& aSAP, TUint8 aCredit); //TRY_CBFC
+	TInt Write(CRfcommSAP& aSAP, TUint8 aCredit, const TDesC8& aData);
+	void SetCanHandleData(CRfcommSAP& aSAP, TBool aCanReceive);
+	TInt GetMaxDataSize() const;
+	TInt Ioctl(TUint aLevel, TUint aName, TDes8* aOption);
+	void CancelIoctl(TUint aLevel, TUint aName);
+	TInt SetOption(TUint aLevel, TUint aName, const TDesC8 &aOption);
+	TInt GetOption(TUint aLevel, TUint aName, TDes8 &aOption);
+	
+	// From MSocketNotify
+	void NewData(TUint aCount);
+	void CanSend();
+	void ConnectComplete();
+	void ConnectComplete(const TDesC8& aConnectData);
+	void ConnectComplete(CServProviderBase& aSSP);
+	void ConnectComplete(CServProviderBase& aSSP,const TDesC8& aConnectData);
+	void CanClose(TDelete aDelete=EDelete);
+	void CanClose(const TDesC8& aDisconnectData,TDelete aDelete=EDelete);
+	void Error(TInt anError,TUint anOperationMask=EErrorAllOperations);
+	void Disconnect(void);
+	void Disconnect(TDesC8& aDisconnectData);
+	void IoctlComplete(TDesC8 *aBuf);
+
+	void NoBearer(const TDesC8& /*aConnectionInf*/) {};
+	void Bearer(const TDesC8& /*aConnectionInf*/) {};
+
+	// Other functions
+	void PropagateIoctlCompletion(TInt aError, TUint aIoctlLevel, TUint aIoctlName, TDesC8* aBuf);
+	void FrameResponseTimeout(CRfcommFrame* aFrame);
+	
+	void ClearResponseQueue(CRfcommSAP& aSAP);
+	void ClearOutboundQueue(CRfcommSAP& aSAP);
+	
+	void MuxChannelUp();
+	void MuxChannelDown();	// the MuxChannel has gone down - so notify SAPs
+	void MuxChannelError(TBool aFatal, TInt anError);
+	void MuxChannelClosed();	// the MuxChannel has gone down - no need for the muxer
+	void CloseSAPs();
+	const TBTDevAddr& RemoteBTAddr() const;
+	CRfcommSAP* FindSAP(const TUint8 aDLCI);
+//TRY_CBFC
+	void DisallowCBFC();
+	void AllowCBFC();
+	TRfcommFlowStrategy* FlowStrategy();
+	CRfcommFlowStrategyFactory::TFlowStrategies FlowType();
+	TBool SetFlowType(CRfcommFlowStrategyFactory::TFlowStrategies aFlowType);
+
+
+
+private:
+
+	enum TInitiationDirection
+		{
+		KInitiationDirectionIncoming,	//	0
+		KInitiationDirectionOutgoing	//	1
+		};
+		
+	CRfcommMuxer(CRfcommProtocol& aProtocol, TInitiationDirection); 
+	void ConstructL(CMuxChannelStateFactory& aFactory, CProtocolBase& aL2CAP);
+	void ConstructL(CMuxChannelStateFactory& aFactory, CServProviderBase* aSAP);
+	void CommonConstructL();
+
+	// Processing incoming frames
+	void ProcessFrame();
+	void ParseCtrlMessageL();
+	void ParsePNL(TInt aOffset, TInt aLen, TUint8& aDLCI, TRfcommPortParams& aParams);
+	void ParseRPN(TInt aOffset, TInt aLen, TUint8& aDLCI, 
+				  TRfcommRPNTransaction* aRPNTransactionPtr=NULL);
+	void ProcessDataFrame(TUint8 aDLCI, TBool aPoll);
+	TInt GetTypeFieldL(TInt& aType, TInt aPos);
+	TInt GetLengthFieldL(TInt& aLen, TInt aPos);
+	void HandleDISC(TUint8 aDLCI);
+	void HandleSABM(TUint8 aDLCI);
+	void HandleUA(TUint8 aDLCI);
+	void HandleDM(TUint8 aDLCI);
+	void HandlePN(TBool aCommand, TUint8 aDLCI, TRfcommPortParams& aParams);
+	void HandleRPN(const TBool& aCommand, const TUint8& aDLCI, 
+				   const TRfcommRPNTransaction* aRPNTransactionPtr=NULL);
+	void HandleTest(TBool aCommand, TInt aOffset, TInt aLen);
+	void HandleFCon(TBool aCommand);
+	void HandleFCoff(TBool aCommand);
+	void HandleMSC(TBool aCommand, TUint8 aDLCI, TUint8 aSignals);
+	void HandleRLS(TBool aCommand, TUint8 aDLCI, TUint8 aStatus);
+	
+	// Packet utility functions
+	TBool CheckFCS(TUint8 aFCS, TUint8 aCtrl);
+	TUint8 DecodeDLCI(TUint8 aAddr);
+	void DecodeLengthAndCredit(TBool aCBFC);
+	TUint8 BuildAddr(TUint8 aDLCI, TBool aCommand);
+	void EnqueFrame(CRfcommFrame* aFrm);
+	void TryToSend();
+	TInt CtrlFrameResponse(TUint8 aDLCI);
+	void MuxCtrlResponse(TUint8 aType);
+	void MuxCtrlResponseDM(TUint8 aDLCI);
+	
+	// Flow control
+	void SetSendBlocked(CRfcommSAP& aSAP, TBool aState);
+	void SignalSAPsCanSend();
+	TBool ClearToSend() const
+			{return iCanSend;}
+	void SetCanSend(TBool aState)   //< True if OK to send
+			{iCanSend=aState;}
+	TBool L2CAPBlocked() const
+			{return iL2CAPSendBlocked;}
+	void L2CAPBlocked(TBool aState)
+			{iL2CAPSendBlocked=aState;}
+
+	// Constructing packets
+	CRfcommMuxCtrlFrame* NewSignalFrame(TInt aCommandLength, TBool aCommand, CRfcommSAP* aSAP =NULL);
+	CRfcommCtrlFrame* NewFrame(CRfcommSAP* aSAP =NULL);
+	CRfcommDataFrame* NewDataFrame(TUint8 aDLCI, TInt aLen, TUint8 aCredit, CRfcommSAP* aSAP=NULL);
+
+	// Sending packets
+	TInt TransmitSABM(TUint8 aDLCI, CRfcommSAP* aSAP =NULL);
+	TInt TransmitUA(TUint8 aDLCI, CRfcommSAP* aSAP =NULL);
+	TInt TransmitDISC(TUint8 aDLCI, CRfcommSAP* aSAP =NULL);
+	TInt TransmitDM(TUint8 aDLCI, TBool aPFBit, CRfcommSAP* aSAP =NULL);	
+	TInt TransmitPN(TUint8 aDLCI, TBool aCommand, const TRfcommPortParams& aParams,
+					CRfcommSAP* aSAP =NULL);
+	TInt TransmitRPN(TUint8 aDLCI, TBool aCommand, TUint8 aLen,
+					 const TRfcommRPNTransaction& aRPNTransaction, CRfcommSAP* aSAP = NULL);
+	TInt TransmitNSC(TBool aCommand, TUint8 aType);
+	TInt TransmitFCon(TBool aCommand, CRfcommSAP* aSAP =NULL);
+	TInt TransmitFCoff(TBool aCommand, CRfcommSAP* aSAP =NULL);
+	TInt TransmitMSC(TUint8 aDLCI, TBool aCommand, TUint8 aSignals,
+					  CRfcommSAP* aSAP =NULL);
+	TInt TransmitTest(TBool aCommand, const TDesC8& aData, CRfcommSAP* aSAP =NULL);
+	TInt TransmitRLS(TBool aCommand, TUint8 aDLCI, TUint8 aStatus,
+					 CRfcommSAP* aSAP =NULL);
+
+	
+	// Callbacks & timers
+	static TInt IdleTimerExpired(TAny* aMux);
+	static TInt TryToSendCallbackStatic(TAny* aMux);
+	void TryToSendCallback();
+	void CheckForIdle(TBool aClosing = EFalse);
+	void QueIdleTimer();
+	void DequeIdleTimer();
+
+	// Utility
+	void DeleteQueuedFrames();
+	CRfcommSAP* FindConnectedOrListeningSAP(const TUint8 aDLCI);
+	TUint8 MakeDLCI(TUint8 aServerChannel, TUint8 aDirectionBit);
+
+	// Reception of data from L2CAP
+	TBool CanProcessNewData() const;
+	void SetNoFreeSpace(TInt aDLCI, TBool aNoSpace);
+
+	// Debug
+#ifdef __FLOG_ACTIVE
+	void ExplainOutgoingFrame(CRfcommFrame* aFrm, CRfcommMuxer* aMux );
+	void LogMuxCommand(CRfcommSAP* aSAP, CRfcommMuxer* aMux, TUint8 aCommand);
+#endif
+	
+	// Data items
+	TDblQue<CRfcommSAP> iSAPs;  //< SAPs using this Mux
+	TDblQue<CRfcommFrame> iOutboundQ; //< Frames to send
+	TDblQue<CRfcommFrame> iResponseQ; //< Frames waiting for a response
+	TInt iOutboundQLength;
+	CRfcommProtocol& iProtocol;
+	CServProviderBase* iBoundSAP;
+	TInt iL2CAPMTU;
+	TBTDevAddr  iRemoteAddr;
+	const TInt iDirection; //< 1 if we are initiating, else 0
+
+	TBool iClosing;  //< True if we are closing down our channel
+	TDeltaTimerEntry  iIdleTimerEntry; //< Disconnection idle timer
+	TBool  iIdleTimerQueued;
+	TInt iMuxIdleTimeout;
+
+	CAsyncCallBack* iSendCallback;
+	HBufC8*  iNextPacket;   // Next packet coming up from L2CAP
+
+	TInt iCurrentHeaderLength; //< Length of the current frame's header
+	TInt iCurrentDataLength;  //< Length of the current frame's data
+
+	// Ioctls
+	TUint  iIoctlLevel;
+	TUint  iIoctlName;
+	
+	// Flow control
+	TBool  iCanSend;  //< False if remote has asked us not to send (FCoff)
+	TDblQue<CRfcommSAP> iBlockedSAPs;  //< SAPs that are blocked
+	// Control over reading from L2CAP
+	TInt     iPacketsWaiting;   //< Number of packets L2CAP has for us
+	TUint32  iSAPNoFreeSpaceMask[2];  //< Mask showing which SAP have no space left
+	TInt	 iDataFramesSent;
+	// Mux channel
+	CRfcommMuxChannel* iMuxChannel;
+	TBool  iL2CAPSendBlocked;  // Is L2CAP ok to send data?
+	//TRY_CBFC
+	TBool iCBFCDisallowed; // ensure flow strategy set to Mux type when object is instantiated
+	TBool iTriedCBFC;	// have we tried to set CBFC ?
+	TInt iCurrentCredit; // a temporary store for the received frame credit
+	TInt iInitialTxCredit;	// used as default credit for new SAPs
+	TRfcommFlowStrategy* iFlowStrategy;
+	
+	// Go on a Q
+	TDblQueLink iLink;
+	};
+
+
+#endif