--- /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