|
1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #ifndef RFCOMMMUXCHANNEL_H |
|
17 #define RFCOMMMUXCHANNEL_H |
|
18 |
|
19 #include <e32base.h> |
|
20 #include "debug.h" |
|
21 #include "rfcommframe.h" |
|
22 #include "rfcommmuxer.h" |
|
23 #include "rfcommutil.h" |
|
24 |
|
25 class CMuxChannelState; |
|
26 class TMuxChannelState; |
|
27 |
|
28 /** |
|
29 Factory for the Mux channel states |
|
30 |
|
31 The states are flyweight classes |
|
32 **/ |
|
33 NONSHARABLE_CLASS(CMuxChannelStateFactory) : public CBase |
|
34 { |
|
35 public: |
|
36 static CMuxChannelStateFactory* NewL(); |
|
37 ~CMuxChannelStateFactory(); |
|
38 enum TChannelState |
|
39 { |
|
40 EClosed, |
|
41 EWaitForLink, |
|
42 EError, |
|
43 ELinkUp, |
|
44 EWaitForSABMResp, |
|
45 EOpen, |
|
46 EClosing, |
|
47 // *** keep next one last *** |
|
48 ERfcommChannelMaxState, |
|
49 }; |
|
50 |
|
51 TMuxChannelState* GetState(TChannelState aState); |
|
52 TInt StateIndex(const TMuxChannelState* aState) const; |
|
53 private: |
|
54 void ConstructL(); |
|
55 TFixedArray<TMuxChannelState*, ERfcommChannelMaxState> iStates; |
|
56 }; |
|
57 |
|
58 /** |
|
59 Manages the mux channel (DLCI 0) and the L2CAP link |
|
60 |
|
61 Before an RFCOMM session can be used, a L2CAP link to the remote |
|
62 host must be established and the multiplexer control channel must |
|
63 be brought up. When the RFCOMM session is no longer required, or |
|
64 when the remote end wishes to close things down, the control |
|
65 channel and the L2CAP link must be terminated. |
|
66 |
|
67 As both these operations have multiple steps and interesting |
|
68 failure modes, a state machine is implemented to control this. |
|
69 **/ |
|
70 NONSHARABLE_CLASS(CRfcommMuxChannel) : public CBase |
|
71 { |
|
72 friend class TMuxChannelState; |
|
73 friend class TMuxChannelStateClosed; |
|
74 friend class TMuxChannelStateWaitForLink; |
|
75 friend class TMuxChannelStateError; |
|
76 friend class TMuxChannelStateConnected; |
|
77 friend class TMuxChannelStateLinkUp; |
|
78 friend class TMuxChannelStateWaitForSABMResp; |
|
79 friend class TMuxChannelStateOpen; |
|
80 friend class TMuxChannelStateClosing; |
|
81 |
|
82 public: |
|
83 CRfcommMuxChannel(CMuxChannelStateFactory& aFactory, CRfcommMuxer& aMux, |
|
84 CServProviderBase& aSAP, CMuxChannelStateFactory::TChannelState aInitialState); |
|
85 ~CRfcommMuxChannel(); |
|
86 |
|
87 // Requests from the muxer |
|
88 void SetAddress(TBTDevAddr& aAddr); |
|
89 void Open(); |
|
90 void Close(); |
|
91 TBool IsOpen(); |
|
92 TInt MaxDataSize(); |
|
93 |
|
94 // Rfcomm events |
|
95 void UA(); |
|
96 void DISC(); |
|
97 void DM(); |
|
98 void PN(TBool aCommand, TRfcommPortParams& aParams); |
|
99 void SABM(); |
|
100 void FrameTimeout(CRfcommFrame* aFrm); |
|
101 |
|
102 // L2CAP events (passed on from the mux) |
|
103 void Disconnect(); |
|
104 void CanClose(); |
|
105 void ConnectComplete(); |
|
106 void Error(TInt aError,TUint aOperationMask); |
|
107 TBool CanAttachSAP(); |
|
108 |
|
109 private: |
|
110 TInt TransmitSABM(); |
|
111 TInt TransmitUA(); |
|
112 TInt TransmitDISC(); |
|
113 TInt TransmitDM(); |
|
114 TInt TransmitPN(TBool aCommand, const TRfcommPortParams& aParams); |
|
115 void QueIdleTimer(TInt aDelay); |
|
116 void DequeIdleTimer(); |
|
117 static TInt IdleTimerCallback(TAny*); |
|
118 |
|
119 CServProviderBase& iSAP; |
|
120 CRfcommMuxer& iMux; |
|
121 TMuxChannelState* iState; |
|
122 TBool iClosePending; |
|
123 TBool iOpenPending; |
|
124 TDeltaTimerEntry iIdleTimer; |
|
125 TBool iIdleTimerQueued; |
|
126 TInt iMaxDataSize; |
|
127 }; |
|
128 |
|
129 |
|
130 /** |
|
131 Base class for mux channel states. |
|
132 |
|
133 This implements a basic set of behaviours for all states that can |
|
134 then be overridden. All the states are flyweight classes. |
|
135 **/ |
|
136 NONSHARABLE_CLASS(TMuxChannelState) |
|
137 { |
|
138 public: |
|
139 TMuxChannelState(CMuxChannelStateFactory& aFactory); |
|
140 |
|
141 virtual void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); |
|
142 virtual void Open(CRfcommMuxChannel& aContext); |
|
143 virtual void Close(CRfcommMuxChannel& aContext); |
|
144 virtual TBool IsOpen(CRfcommMuxChannel& aContext); |
|
145 virtual void UA(CRfcommMuxChannel& aContext); |
|
146 virtual void DISC(CRfcommMuxChannel& aContext); |
|
147 virtual void DM(CRfcommMuxChannel& aContext); |
|
148 virtual void PN(CRfcommMuxChannel& aContext, |
|
149 TBool aCommand, TRfcommPortParams& |
|
150 aParams); |
|
151 virtual void SABM(CRfcommMuxChannel& aContext); |
|
152 virtual void FrameTimeout(CRfcommMuxChannel& aContext, |
|
153 CRfcommFrame* aFrm); |
|
154 virtual void Disconnect(CRfcommMuxChannel& aContext); |
|
155 virtual void CanClose(CRfcommMuxChannel& aContext); |
|
156 virtual void ConnectComplete(CRfcommMuxChannel& aContext); |
|
157 virtual void Error(CRfcommMuxChannel& aContext, TInt aError, |
|
158 TUint aOperationMask); |
|
159 virtual void IdleTimeout(CRfcommMuxChannel& aContext); |
|
160 virtual TBool CanAttachSAP(); |
|
161 |
|
162 protected: |
|
163 // Sets the state, but doesn't enter it. |
|
164 void SetState(CRfcommMuxChannel& aContext, CMuxChannelStateFactory::TChannelState aState); |
|
165 void PanicInState(TRFCOMMPanic aPanic) const; |
|
166 void DebugPanicInState(TRFCOMMPanic aPanic) const; |
|
167 |
|
168 protected: |
|
169 CMuxChannelStateFactory& iFactory; |
|
170 #ifdef __FLOG_ACTIVE |
|
171 TBuf<48> iName; |
|
172 #endif |
|
173 }; |
|
174 |
|
175 /** |
|
176 Closed state. |
|
177 |
|
178 This is the state we start in when this end is to initiate the L2CAP link. |
|
179 |
|
180 On an Open() we do the active connect. |
|
181 |
|
182 **/ |
|
183 NONSHARABLE_CLASS(TMuxChannelStateClosed) : public TMuxChannelState |
|
184 { |
|
185 public: |
|
186 TMuxChannelStateClosed(CMuxChannelStateFactory& aFactory); |
|
187 |
|
188 void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); |
|
189 void Open(CRfcommMuxChannel& aContext); |
|
190 void Close(CRfcommMuxChannel& aContext); |
|
191 }; |
|
192 |
|
193 /** |
|
194 Waiting for the L2CAP link to come up. |
|
195 **/ |
|
196 NONSHARABLE_CLASS(TMuxChannelStateWaitForLink) : public TMuxChannelState |
|
197 { |
|
198 public: |
|
199 TMuxChannelStateWaitForLink(CMuxChannelStateFactory& aFactory); |
|
200 |
|
201 void ConnectComplete(CRfcommMuxChannel& aContext); |
|
202 void Close(CRfcommMuxChannel& aContext); |
|
203 void Error(CRfcommMuxChannel& aContext, TInt aError, |
|
204 TUint aOperationMask); |
|
205 }; |
|
206 |
|
207 /** |
|
208 The Error state |
|
209 |
|
210 This represents a fatal error on the L2CAP link (SAP) such that it |
|
211 would be pointless to attempt to reconnect the channel with the |
|
212 same SAP. |
|
213 |
|
214 Entry to this state should be terminal to our associated muxer. |
|
215 **/ |
|
216 NONSHARABLE_CLASS(TMuxChannelStateError) : public TMuxChannelState |
|
217 { |
|
218 public: |
|
219 TMuxChannelStateError(CMuxChannelStateFactory& aFactory); |
|
220 |
|
221 void Open(CRfcommMuxChannel& aContext); |
|
222 void Close(CRfcommMuxChannel& aContext); |
|
223 TBool CanAttachSAP(); |
|
224 }; |
|
225 |
|
226 /** |
|
227 Base class for all the connected states. |
|
228 |
|
229 This implements the connected superstate, with the superstate |
|
230 behaviours. It also includes some default behaviours for its |
|
231 substates. |
|
232 |
|
233 The connected state is when the L2CAP link is up. |
|
234 **/ |
|
235 NONSHARABLE_CLASS(TMuxChannelStateConnected) : public TMuxChannelState |
|
236 { |
|
237 public: |
|
238 TMuxChannelStateConnected(CMuxChannelStateFactory& aFactory); |
|
239 |
|
240 void FrameTimeoutHelper(CRfcommMuxChannel& aContext); |
|
241 |
|
242 // These functions are over-ridden from TMuxChannelState |
|
243 void Disconnect(CRfcommMuxChannel& aContext); |
|
244 |
|
245 // ...and these will also be over-ridden in child states |
|
246 virtual void SABM(CRfcommMuxChannel& aContext); |
|
247 virtual void FrameTimeout(CRfcommMuxChannel& aContext, |
|
248 CRfcommFrame* aFrm); |
|
249 virtual void Error(CRfcommMuxChannel& aContext, TInt aError, |
|
250 TUint aOperationMask); |
|
251 }; |
|
252 |
|
253 /** |
|
254 The L2CAP link is up |
|
255 |
|
256 This class is entered when the link comes up, or when the mux |
|
257 channel is disconnected without closing the l2cap link. From here, |
|
258 a timeout will close the link. |
|
259 |
|
260 This is the initial state for the mux channel if the muxer was |
|
261 created due to an incoming connection. |
|
262 |
|
263 From here, the SABM/UA exchange occurs to bring up the mux channel, |
|
264 and the DISC/UA to return to here. Eventually a timeout, link |
|
265 disconnection or Close() will cause the link to be dropped. |
|
266 **/ |
|
267 NONSHARABLE_CLASS(TMuxChannelStateLinkUp) : public TMuxChannelStateConnected |
|
268 { |
|
269 public: |
|
270 TMuxChannelStateLinkUp(CMuxChannelStateFactory& aFactory); |
|
271 |
|
272 // Over-ridden from parent class: |
|
273 void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); |
|
274 void Open(CRfcommMuxChannel& aContext); |
|
275 void Close(CRfcommMuxChannel& aContext); |
|
276 void SABM(CRfcommMuxChannel& aContext); |
|
277 void DISC(CRfcommMuxChannel& aContext); |
|
278 void IdleTimeout(CRfcommMuxChannel& aContext); |
|
279 void FrameTimeout(CRfcommMuxChannel& aContext, CRfcommFrame* aFrm); |
|
280 }; |
|
281 |
|
282 /** |
|
283 Waiting for the mux channel to be connected |
|
284 **/ |
|
285 NONSHARABLE_CLASS(TMuxChannelStateWaitForSABMResp) : public TMuxChannelStateConnected |
|
286 { |
|
287 public: |
|
288 TMuxChannelStateWaitForSABMResp(CMuxChannelStateFactory& aFactory); |
|
289 |
|
290 void UA(CRfcommMuxChannel& aContext); |
|
291 void DM(CRfcommMuxChannel& aContext); |
|
292 void SABM(CRfcommMuxChannel& aContext); |
|
293 void DISC(CRfcommMuxChannel& aContext); |
|
294 void Close(CRfcommMuxChannel& aContext); |
|
295 }; |
|
296 |
|
297 /** |
|
298 The mux channel is now fully open |
|
299 |
|
300 At this point the muxer is signalled that it can start to use the |
|
301 channel. |
|
302 |
|
303 **/ |
|
304 NONSHARABLE_CLASS(TMuxChannelStateOpen) : public TMuxChannelStateConnected |
|
305 { |
|
306 public: |
|
307 TMuxChannelStateOpen(CMuxChannelStateFactory& aFactory); |
|
308 |
|
309 void Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer = ETrue); |
|
310 TBool IsOpen(CRfcommMuxChannel& aContext); |
|
311 void Close(CRfcommMuxChannel& aContext); |
|
312 void SABM(CRfcommMuxChannel& aContext); |
|
313 void DISC(CRfcommMuxChannel& aContext); |
|
314 }; |
|
315 |
|
316 /** |
|
317 Closing down the L2CAP Link |
|
318 |
|
319 The whole mux channel is no longer required, so the link is being |
|
320 closed. |
|
321 **/ |
|
322 NONSHARABLE_CLASS(TMuxChannelStateClosing) : public TMuxChannelStateConnected |
|
323 { |
|
324 public: |
|
325 TMuxChannelStateClosing(CMuxChannelStateFactory& aFactory); |
|
326 // Over-ridden from parent: |
|
327 void FrameTimeout(CRfcommMuxChannel& aContext, |
|
328 CRfcommFrame* aFrm); |
|
329 void CanClose(CRfcommMuxChannel& aContext); |
|
330 TBool CanAttachSAP(); |
|
331 }; |
|
332 |
|
333 #ifdef __FLOGGING__ |
|
334 #define STATENAME(x) iName=_L(x) |
|
335 #else |
|
336 #define STATENAME(x) |
|
337 #endif |
|
338 |
|
339 #include "rfcommmuxchannel.inl" |
|
340 #endif |