--- /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 <e32base.h>
+#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<TMuxChannelState*, ERfcommChannelMaxState> 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