diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/rfcomm/rfcommmuxchannel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btstack/rfcomm/rfcommmuxchannel.h Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,340 @@ +// 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 RFCOMMMUXCHANNEL_H +#define RFCOMMMUXCHANNEL_H + +#include +#include "debug.h" +#include "rfcommframe.h" +#include "rfcommmuxer.h" +#include "rfcommutil.h" + +class CMuxChannelState; +class TMuxChannelState; + +/** + Factory for the Mux channel states + + The states are flyweight classes +**/ +NONSHARABLE_CLASS(CMuxChannelStateFactory) : public CBase + { +public: + static CMuxChannelStateFactory* NewL(); + ~CMuxChannelStateFactory(); + enum TChannelState + { + EClosed, + EWaitForLink, + EError, + ELinkUp, + EWaitForSABMResp, + EOpen, + EClosing, + // *** keep next one last *** + ERfcommChannelMaxState, + }; + + TMuxChannelState* GetState(TChannelState aState); + TInt StateIndex(const TMuxChannelState* aState) const; +private: + void ConstructL(); + TFixedArray iStates; + }; + +/** + Manages the mux channel (DLCI 0) and the L2CAP link + + Before an RFCOMM session can be used, a L2CAP link to the remote + host must be established and the multiplexer control channel must + be brought up. When the RFCOMM session is no longer required, or + when the remote end wishes to close things down, the control + channel and the L2CAP link must be terminated. + + As both these operations have multiple steps and interesting + failure modes, a state machine is implemented to control this. +**/ +NONSHARABLE_CLASS(CRfcommMuxChannel) : public CBase + { +friend class TMuxChannelState; +friend class TMuxChannelStateClosed; +friend class TMuxChannelStateWaitForLink; +friend class TMuxChannelStateError; +friend class TMuxChannelStateConnected; +friend class TMuxChannelStateLinkUp; +friend class TMuxChannelStateWaitForSABMResp; +friend class TMuxChannelStateOpen; +friend class TMuxChannelStateClosing; + +public: + CRfcommMuxChannel(CMuxChannelStateFactory& aFactory, CRfcommMuxer& aMux, + CServProviderBase& aSAP, CMuxChannelStateFactory::TChannelState aInitialState); + ~CRfcommMuxChannel(); + + // Requests from the muxer + void SetAddress(TBTDevAddr& aAddr); + void Open(); + void Close(); + TBool IsOpen(); + TInt MaxDataSize(); + + // Rfcomm events + void UA(); + void DISC(); + void DM(); + void PN(TBool aCommand, TRfcommPortParams& aParams); + void SABM(); + void FrameTimeout(CRfcommFrame* aFrm); + + // L2CAP events (passed on from the mux) + void Disconnect(); + void CanClose(); + void ConnectComplete(); + void Error(TInt aError,TUint aOperationMask); + TBool CanAttachSAP(); + +private: + TInt TransmitSABM(); + TInt TransmitUA(); + TInt TransmitDISC(); + TInt TransmitDM(); + TInt TransmitPN(TBool aCommand, const TRfcommPortParams& aParams); + void QueIdleTimer(TInt aDelay); + void DequeIdleTimer(); + static TInt IdleTimerCallback(TAny*); + + CServProviderBase& iSAP; + CRfcommMuxer& iMux; + TMuxChannelState* iState; + TBool iClosePending; + TBool iOpenPending; + TDeltaTimerEntry iIdleTimer; + TBool iIdleTimerQueued; + TInt iMaxDataSize; + }; + + +/** + Base class for mux channel states. + + This implements a basic set of behaviours for all states that can + then be overridden. All the states are flyweight classes. +**/ +NONSHARABLE_CLASS(TMuxChannelState) + { +public: + TMuxChannelState(CMuxChannelStateFactory& aFactory); + + virtual void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); + virtual void Open(CRfcommMuxChannel& aContext); + virtual void Close(CRfcommMuxChannel& aContext); + virtual TBool IsOpen(CRfcommMuxChannel& aContext); + virtual void UA(CRfcommMuxChannel& aContext); + virtual void DISC(CRfcommMuxChannel& aContext); + virtual void DM(CRfcommMuxChannel& aContext); + virtual void PN(CRfcommMuxChannel& aContext, + TBool aCommand, TRfcommPortParams& + aParams); + virtual void SABM(CRfcommMuxChannel& aContext); + virtual void FrameTimeout(CRfcommMuxChannel& aContext, + CRfcommFrame* aFrm); + virtual void Disconnect(CRfcommMuxChannel& aContext); + virtual void CanClose(CRfcommMuxChannel& aContext); + virtual void ConnectComplete(CRfcommMuxChannel& aContext); + virtual void Error(CRfcommMuxChannel& aContext, TInt aError, + TUint aOperationMask); + virtual void IdleTimeout(CRfcommMuxChannel& aContext); + virtual TBool CanAttachSAP(); + +protected: + // Sets the state, but doesn't enter it. + void SetState(CRfcommMuxChannel& aContext, CMuxChannelStateFactory::TChannelState aState); + void PanicInState(TRFCOMMPanic aPanic) const; + void DebugPanicInState(TRFCOMMPanic aPanic) const; + +protected: + CMuxChannelStateFactory& iFactory; +#ifdef __FLOG_ACTIVE + TBuf<48> iName; +#endif + }; + +/** + Closed state. + + This is the state we start in when this end is to initiate the L2CAP link. + + On an Open() we do the active connect. + +**/ +NONSHARABLE_CLASS(TMuxChannelStateClosed) : public TMuxChannelState + { +public: + TMuxChannelStateClosed(CMuxChannelStateFactory& aFactory); + + void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); + void Open(CRfcommMuxChannel& aContext); + void Close(CRfcommMuxChannel& aContext); + }; + +/** + Waiting for the L2CAP link to come up. +**/ +NONSHARABLE_CLASS(TMuxChannelStateWaitForLink) : public TMuxChannelState + { +public: + TMuxChannelStateWaitForLink(CMuxChannelStateFactory& aFactory); + + void ConnectComplete(CRfcommMuxChannel& aContext); + void Close(CRfcommMuxChannel& aContext); + void Error(CRfcommMuxChannel& aContext, TInt aError, + TUint aOperationMask); + }; + +/** + The Error state + + This represents a fatal error on the L2CAP link (SAP) such that it + would be pointless to attempt to reconnect the channel with the + same SAP. + + Entry to this state should be terminal to our associated muxer. +**/ +NONSHARABLE_CLASS(TMuxChannelStateError) : public TMuxChannelState + { +public: + TMuxChannelStateError(CMuxChannelStateFactory& aFactory); + + void Open(CRfcommMuxChannel& aContext); + void Close(CRfcommMuxChannel& aContext); + TBool CanAttachSAP(); + }; + +/** + Base class for all the connected states. + + This implements the connected superstate, with the superstate + behaviours. It also includes some default behaviours for its + substates. + + The connected state is when the L2CAP link is up. +**/ +NONSHARABLE_CLASS(TMuxChannelStateConnected) : public TMuxChannelState + { +public: + TMuxChannelStateConnected(CMuxChannelStateFactory& aFactory); + + void FrameTimeoutHelper(CRfcommMuxChannel& aContext); + + // These functions are over-ridden from TMuxChannelState + void Disconnect(CRfcommMuxChannel& aContext); + + // ...and these will also be over-ridden in child states + virtual void SABM(CRfcommMuxChannel& aContext); + virtual void FrameTimeout(CRfcommMuxChannel& aContext, + CRfcommFrame* aFrm); + virtual void Error(CRfcommMuxChannel& aContext, TInt aError, + TUint aOperationMask); + }; + +/** + The L2CAP link is up + + This class is entered when the link comes up, or when the mux + channel is disconnected without closing the l2cap link. From here, + a timeout will close the link. + + This is the initial state for the mux channel if the muxer was + created due to an incoming connection. + + From here, the SABM/UA exchange occurs to bring up the mux channel, + and the DISC/UA to return to here. Eventually a timeout, link + disconnection or Close() will cause the link to be dropped. +**/ +NONSHARABLE_CLASS(TMuxChannelStateLinkUp) : public TMuxChannelStateConnected + { +public: + TMuxChannelStateLinkUp(CMuxChannelStateFactory& aFactory); + + // Over-ridden from parent class: + void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); + void Open(CRfcommMuxChannel& aContext); + void Close(CRfcommMuxChannel& aContext); + void SABM(CRfcommMuxChannel& aContext); + void DISC(CRfcommMuxChannel& aContext); + void IdleTimeout(CRfcommMuxChannel& aContext); + void FrameTimeout(CRfcommMuxChannel& aContext, CRfcommFrame* aFrm); + }; + +/** + Waiting for the mux channel to be connected +**/ +NONSHARABLE_CLASS(TMuxChannelStateWaitForSABMResp) : public TMuxChannelStateConnected + { +public: + TMuxChannelStateWaitForSABMResp(CMuxChannelStateFactory& aFactory); + + void UA(CRfcommMuxChannel& aContext); + void DM(CRfcommMuxChannel& aContext); + void SABM(CRfcommMuxChannel& aContext); + void DISC(CRfcommMuxChannel& aContext); + void Close(CRfcommMuxChannel& aContext); + }; + +/** + The mux channel is now fully open + + At this point the muxer is signalled that it can start to use the + channel. + +**/ +NONSHARABLE_CLASS(TMuxChannelStateOpen) : public TMuxChannelStateConnected + { +public: + TMuxChannelStateOpen(CMuxChannelStateFactory& aFactory); + + void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); + TBool IsOpen(CRfcommMuxChannel& aContext); + void Close(CRfcommMuxChannel& aContext); + void SABM(CRfcommMuxChannel& aContext); + void DISC(CRfcommMuxChannel& aContext); + }; + +/** + Closing down the L2CAP Link + + The whole mux channel is no longer required, so the link is being + closed. +**/ +NONSHARABLE_CLASS(TMuxChannelStateClosing) : public TMuxChannelStateConnected + { +public: + TMuxChannelStateClosing(CMuxChannelStateFactory& aFactory); + // Over-ridden from parent: + void FrameTimeout(CRfcommMuxChannel& aContext, + CRfcommFrame* aFrm); + void CanClose(CRfcommMuxChannel& aContext); + TBool CanAttachSAP(); + }; + +#ifdef __FLOGGING__ +#define STATENAME(x) iName=_L(x) +#else +#define STATENAME(x) +#endif + +#include "rfcommmuxchannel.inl" +#endif