|
1 // Copyright (c) 1997-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 #include <bluetooth/logger.h> |
|
17 #include <cs_port.h> |
|
18 #include "btcomm.h" |
|
19 #include "btstate.h" |
|
20 #include "btcommactive.h" |
|
21 #include <btmanclient.h> |
|
22 #include "BTSimTimer.h" |
|
23 |
|
24 #ifdef __FLOG_ACTIVE |
|
25 _LIT8(KLogComponent, LOG_COMPONENT_BT_COMM); |
|
26 #endif |
|
27 |
|
28 CBTPortProxy* CBTPortProxy::NewL(TUint32 aPortNo,CBTPort *aParent,CBTPortStateFactory *aFactory) |
|
29 /** |
|
30 CBTPortProxy NewL(..) creates an instance of the BT Port Proxy. |
|
31 This is the object that represents the CSY state pattern context. |
|
32 |
|
33 In order to avoid deadlock between the esock and c32 threads it is |
|
34 necessary to employ a locking mechanism to serialise synchronous |
|
35 accesses to esock thread. This mechanism works as follows: |
|
36 |
|
37 1) Defer all synchronous access attempts on esock via the CSY until |
|
38 a locker active object has been run. |
|
39 2) When we hit the RunL of this locker active object we know that |
|
40 the present session on the esock server is exclusive - ie all |
|
41 other esock sessions are temporarily disabled. |
|
42 3) At this point, it is possible to run the original synchronous |
|
43 request on esock safe in the knowledge that no other esock session |
|
44 can deadlock the c32 thread. This is the DoLockedActions phase. |
|
45 4) Once the request has completed the unlocker active object is invoked |
|
46 to release the exlusive session lock on esock. |
|
47 */ |
|
48 { |
|
49 LOG_STATIC_FUNC |
|
50 CBTPortProxy *pp; |
|
51 pp=new (ELeave) CBTPortProxy(aPortNo); |
|
52 CleanupStack::PushL(pp); |
|
53 pp->InitL(aParent,aFactory); |
|
54 CleanupStack::Pop(); |
|
55 return pp; |
|
56 } |
|
57 |
|
58 void CBTPortProxy::InitL(CBTPort *aParent,CBTPortStateFactory *aFactory) |
|
59 /** |
|
60 Initialises the CBTPortProxy context and enters the 'starting' state. |
|
61 This is where we create the PortLocker, Port Reader, Port Writer, |
|
62 circular read buffer and fixed write buffer. Note that we also fire up |
|
63 the state machine here too (with an EStarting::Entry). |
|
64 This is thus the main CSY Bootstrap function. |
|
65 **/ |
|
66 { |
|
67 LOG_FUNC |
|
68 iPort=aParent; |
|
69 iPortStateFactory=aFactory; |
|
70 iState=&iPortStateFactory->GetState(CBTPortStateFactory::EIdle); |
|
71 iPortLocker=CBTPortLocker::NewL(this); |
|
72 iCircularReadBuf=CBTPortBuffer::NewL(this,KBTCOMMCircularBufferLength); |
|
73 iReadBuf=HBufC8::NewMaxL(KBTCOMMRecvBufferLength); |
|
74 |
|
75 iSendBuf=HBufC8::NewMaxL(KBTCOMMSendBufferLength); |
|
76 iSendBufPtr.Set(iSendBuf->Des()); |
|
77 |
|
78 iReadOutBuf=HBufC8::NewMaxL(KBTCOMMCircularBufferLength); |
|
79 iReadBufPtr.Set(iReadOutBuf->Des()); |
|
80 |
|
81 iPortReader=CBTPortReader::NewL(this); |
|
82 iPortWriter=CBTPortWriter::NewL(this); |
|
83 |
|
84 iSockServConnector = CSockServConnector::NewL(iSockServ); |
|
85 |
|
86 User::LeaveIfError(iRegServ.Connect()); |
|
87 User::LeaveIfError(iPortSettings.Open(iRegServ)); |
|
88 |
|
89 CActiveScheduler::Add(this); |
|
90 |
|
91 iShutdownTimer = CBTTimerSimple::NewL(EPriorityLow,this); |
|
92 |
|
93 iState->Open(this); |
|
94 } |
|
95 |
|
96 |
|
97 CBTPortProxy::CBTPortProxy(TUint32 aPortNo) |
|
98 : CActive (EPriorityStandard), iPortNo(aPortNo), |
|
99 iSendBufPtr(NULL,0,0), |
|
100 iReadBufPtr(NULL,0,0) |
|
101 /** |
|
102 CBTPortProxy constructor. |
|
103 **/ |
|
104 { |
|
105 LOG_FUNC |
|
106 } |
|
107 |
|
108 /** |
|
109 Initiates the destruction of the port its proxy and the corresponding states. |
|
110 Calls to this method should be made by the state responsible for destructing |
|
111 the CSY. |
|
112 No further methods should be invoked after this call. |
|
113 */ |
|
114 void CBTPortProxy::DestructContext() |
|
115 { |
|
116 LOG_FUNC |
|
117 if(iPort->AccessCount()) |
|
118 { |
|
119 // someone else managed to reopen us lets not die :-) |
|
120 // and check to see if we have a cached read or write request |
|
121 if(iClientWritePtr||iClientReadPtr) |
|
122 { |
|
123 LOG(_L("**CBTPortProxy::DestructContext - Cached Read/Write check **")); |
|
124 //then kickstart the starting state (we can only be in the starting state) |
|
125 ((TBTPortStateIdle*) iState)->SockServConnect(this); |
|
126 } |
|
127 return; |
|
128 } |
|
129 //else go down |
|
130 iPort->DestructNow(); //taking CBTPortProxy with it |
|
131 } |
|
132 |
|
133 CBTPortProxy::~CBTPortProxy() |
|
134 /** |
|
135 CBTPortProxy destructor. |
|
136 **/ |
|
137 { |
|
138 LOG_FUNC |
|
139 Cancel(); |
|
140 delete iPortReader; |
|
141 delete iPortWriter; |
|
142 delete iPortLocker; |
|
143 delete iSockServConnector; |
|
144 delete iSendBuf; |
|
145 delete iReadBuf; |
|
146 delete iCircularReadBuf; |
|
147 delete iReadOutBuf; |
|
148 delete iShutdownTimer; |
|
149 iPortSettings.Close(); |
|
150 iRegServ.Close(); |
|
151 } |
|
152 |
|
153 void CBTPortProxy::RunL() |
|
154 { |
|
155 LOG_FUNC |
|
156 LOG1(_L("CBTPortProxy::RunL with result %d"), iStatus.Int()); |
|
157 iState->DoRunL(this); |
|
158 } |
|
159 |
|
160 void CBTPortProxy::DoCancel() |
|
161 /** |
|
162 CBTPortProxy::DoCancel |
|
163 With a normal active object this function would cancel |
|
164 any outstanding requests on aysnchronous services. In |
|
165 this case we cannot do that as to make a synchronous |
|
166 request on esock we need to be in the locker. Instead |
|
167 we ensure that when we do a Cancel() we have passed |
|
168 through the closing state, which cancels things in the |
|
169 locker. |
|
170 |
|
171 If there are any requests outstanding when Cancel() is |
|
172 called then this thread will block doing |
|
173 User::WaitForRequest() to eat the signal. |
|
174 **/ |
|
175 { |
|
176 LOG_FUNC |
|
177 } |
|
178 |
|
179 void CBTPortProxy::StartWriter() |
|
180 /** |
|
181 CBTPortProxy StartWrite. |
|
182 This function is invoked by the state machine |
|
183 on the context when it wishes to start a write. |
|
184 Note that this function has to fragment the writes |
|
185 into sensible chunks to write across RFComm. The |
|
186 size of these chunks is dictated by |
|
187 KBTCOMMSendBufferLength. |
|
188 **/ |
|
189 { |
|
190 LOG_FUNC |
|
191 iPortWriter->QueueWrite(iSendBufPtr); |
|
192 } |
|
193 |
|
194 void CBTPortProxy::DoWriteCompleted(TInt aError) |
|
195 { |
|
196 LOG_FUNC |
|
197 iState->DoWriteCompleted(this,aError); |
|
198 } |
|
199 |
|
200 void CBTPortProxy::StopWriter() |
|
201 /** |
|
202 CBTPortProxy StopWrite. |
|
203 This function is invoked by the state machine |
|
204 on the context when it wishes to stop a write |
|
205 **/ |
|
206 { |
|
207 LOG_FUNC |
|
208 } |
|
209 |
|
210 void CBTPortProxy::StartReader() |
|
211 /** |
|
212 CBTPortProxy StartReader. |
|
213 This function is invoked by the state machine |
|
214 on the context when it wishes to queue a read. |
|
215 **/ |
|
216 { |
|
217 LOG_FUNC |
|
218 iPortReader->StartReading(); |
|
219 } |
|
220 |
|
221 void CBTPortProxy::DoReadCompleted(TInt aError) |
|
222 /** |
|
223 Completes the reads to the state indicating that new data arrived from socket. |
|
224 |
|
225 According to the delegated state it will check to see if it has reached |
|
226 its circular buffer watermark and hence refrain from re-queueing another |
|
227 read to the socket. |
|
228 */ |
|
229 { |
|
230 LOG_FUNC |
|
231 iState->DoReadCompleted(this,aError); // new data arrived from the socket |
|
232 } |
|
233 |
|
234 /** |
|
235 Checks whether the low watermark for the circular read-in (from the socket) buffer has been passed. |
|
236 This method wil be used by the friendly open state to restart the reader if |
|
237 necessary. |
|
238 */ |
|
239 TBool CBTPortProxy::ReadInBufferLowWatermarkReached() |
|
240 { |
|
241 LOG_FUNC |
|
242 if (iCircularReadBuf->Count()<=KBTCOMMCircularBufferLowWatermark) |
|
243 { |
|
244 return ETrue; |
|
245 } |
|
246 return EFalse; |
|
247 } |
|
248 |
|
249 /** |
|
250 Checks whether the high watermark for the circular read-in (from the socket) buffer has been reached or passed. |
|
251 This method wil be used by the friendly open state to start or stop the |
|
252 reader if necessary. |
|
253 */ |
|
254 TBool CBTPortProxy::ReadInBufferHighWatermarkReached() |
|
255 { |
|
256 LOG_FUNC |
|
257 if (iCircularReadBuf->Count()>=KBTCOMMCircularBufferHighWatermark) |
|
258 { |
|
259 return ETrue; |
|
260 } |
|
261 return EFalse; |
|
262 } |
|
263 |
|
264 void CBTPortProxy::StopReader() |
|
265 { |
|
266 LOG_FUNC |
|
267 iPortReader->StopReading(); |
|
268 } |
|
269 |
|
270 void CBTPortProxy::StartLocker() |
|
271 { |
|
272 LOG_FUNC |
|
273 iPortLocker->LockSession(); |
|
274 } |
|
275 |
|
276 void CBTPortProxy::DoLockedAction() |
|
277 { |
|
278 LOG_FUNC |
|
279 iState->DoLockedAction(this); |
|
280 } |
|
281 |
|
282 void CBTPortProxy::StopLocker() |
|
283 { |
|
284 LOG_FUNC |
|
285 iPortLocker->UnlockSession(); |
|
286 } |
|
287 |
|
288 TBool CBTPortProxy::IsLockerOn() |
|
289 { |
|
290 LOG_FUNC |
|
291 return (iPortLocker->IsSessionLocked()); |
|
292 } |
|
293 |
|
294 void CBTPortProxy::StartShutdownTimerL() |
|
295 { |
|
296 LOG_FUNC |
|
297 iShutdownTimer->CancelAlarm(); |
|
298 iShutdownTimer->After(KBtcommShutdownTimer); |
|
299 } |
|
300 |
|
301 void CBTPortProxy::CancelShutDownTimer() |
|
302 { |
|
303 LOG_FUNC |
|
304 iShutdownTimer->CancelAlarm(); |
|
305 } |
|
306 |
|
307 void CBTPortProxy::ShutdownAlarm() |
|
308 /** |
|
309 ShutdownAlarm() is the callback of the shutdown timer. |
|
310 To be called for the final stage of closing down connection to ESock. |
|
311 */ |
|
312 { |
|
313 LOG_FUNC |
|
314 // this startlocker will basically invoke the locked action of the |
|
315 // closing state |
|
316 StartLocker(); |
|
317 } |
|
318 |
|
319 // Methods to be called by the Open state only |
|
320 void CBTPortProxy::SetWriteCancelPending() |
|
321 { |
|
322 LOG_FUNC |
|
323 iWriteCancelationPending=ETrue; |
|
324 } |
|
325 |
|
326 TBool CBTPortProxy::IsWriteCancelPending() |
|
327 { |
|
328 LOG_FUNC |
|
329 return iWriteCancelationPending; |
|
330 } |
|
331 |
|
332 TBool CBTPortProxy::IsNetDbInUse() |
|
333 { |
|
334 LOG_FUNC |
|
335 return iNetDbInUse; |
|
336 } |
|
337 |
|
338 void CBTPortProxy::SetNetDbInUse() |
|
339 { |
|
340 LOG_FUNC |
|
341 iNetDbInUse=ETrue; |
|
342 } |
|
343 |
|
344 void CBTPortProxy::SetNetDbNotInUse() |
|
345 { |
|
346 LOG_FUNC |
|
347 iNetDbInUse=EFalse; |
|
348 } |
|
349 |
|
350 // ********************* PUBLIC INTERFACE *************************** |
|
351 |
|
352 void CBTPortProxy::Write(const TAny* aClientBuffer,TInt aLength) |
|
353 /** |
|
354 CBTPortProxy Write. |
|
355 The CBTPort has attempted a Write. |
|
356 **/ |
|
357 { |
|
358 LOG_FUNC |
|
359 iState->Write(this,const_cast<TAny*>(aClientBuffer),aLength); |
|
360 } |
|
361 |
|
362 void CBTPortProxy::WriteCancel() |
|
363 /** |
|
364 CBTPortProxy WriteCancel. |
|
365 The CBTPort has attempted to cancel a write. |
|
366 Delegate behaviour to the active state. |
|
367 **/ |
|
368 { |
|
369 LOG_FUNC |
|
370 iState->WriteCancel(this); |
|
371 } |
|
372 |
|
373 void CBTPortProxy::DoWriteCancel() |
|
374 /** |
|
375 Only to be called by the active state, NOT directly. |
|
376 This will cancel the ESock write. |
|
377 */ |
|
378 { |
|
379 LOG_FUNC |
|
380 iWriteCancelationPending=EFalse; |
|
381 iSocket.CancelWrite(); |
|
382 } |
|
383 |
|
384 void CBTPortProxy::Read(const TAny* aClientBuffer,TInt aLength) |
|
385 /** |
|
386 Delegates the client Read request to the active state. |
|
387 If the state is the Open state then the request is serviced |
|
388 otherwise it gets cached. |
|
389 |
|
390 @param aLength is either the bytecount to be read or -1 |
|
391 indicating a 'Read One Or More bytes' request |
|
392 **/ |
|
393 { |
|
394 LOG_FUNC |
|
395 iClientReadOneOrMore=EFalse; |
|
396 if (aLength<0) |
|
397 { |
|
398 aLength=-aLength; |
|
399 iClientReadOneOrMore=ETrue; |
|
400 } |
|
401 iState->Read(this,const_cast<TAny*>(aClientBuffer),aLength); |
|
402 } |
|
403 |
|
404 void CBTPortProxy::ReadCancel() |
|
405 /** |
|
406 Delegates 'cancel the read' behaviour to the active state. |
|
407 **/ |
|
408 { |
|
409 LOG_FUNC |
|
410 iState->ReadCancel(this); |
|
411 } |
|
412 |
|
413 TInt CBTPortProxy::QueryReceiveBuffer(TInt& aLength) |
|
414 /** |
|
415 Retrieves number of bytes waiting in the receive buffer. |
|
416 */ { |
|
417 LOG_FUNC |
|
418 aLength=iCircularReadBuf->Length(); |
|
419 return KErrNone; |
|
420 } |
|
421 |
|
422 TInt CBTPortProxy::GetReceiveBufferLength(TInt& aLength) |
|
423 /** |
|
424 Sets aLength to KBTCOMMRecvBufferLength. |
|
425 Always returns KErrNone; |
|
426 */ { |
|
427 LOG_FUNC |
|
428 aLength=KBTCOMMRecvBufferLength; |
|
429 return KErrNone; |
|
430 } |
|
431 |
|
432 void CBTPortProxy::Close() |
|
433 /** |
|
434 Delegates Close request to the active state. |
|
435 **/ |
|
436 { |
|
437 LOG_FUNC |
|
438 iState->Close(this); |
|
439 } |
|
440 |
|
441 void CBTPortProxy::MoveToErrorState() |
|
442 { |
|
443 LOG_FUNC |
|
444 iState=&iPortStateFactory->GetState(CBTPortStateFactory::EError); |
|
445 // Notify the error state as we move in to it about the current error. |
|
446 iState->Error(this,iLastError); |
|
447 } |
|
448 |
|
449 void CBTPortProxy::ResetRxBuffer() |
|
450 { |
|
451 LOG_FUNC |
|
452 iCircularReadBuf->Reset(); |
|
453 } |