|
1 // Copyright (c) 2004-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 /** |
|
17 @file |
|
18 @internalComponent |
|
19 */ |
|
20 |
|
21 #include <bluetooth/logger.h> |
|
22 #include <remcon/remconbearerobserver.h> |
|
23 #include <remcon/remconconverterplugin.h> |
|
24 #include <remconaddress.h> |
|
25 #include "remconserialbearer.h" |
|
26 #include "sender.h" |
|
27 #include "receiver.h" |
|
28 #include "utils.h" |
|
29 |
|
30 #ifdef __FLOG_ACTIVE |
|
31 _LIT8(KLogComponent, LOG_COMPONENT_REMCON_REF_SER_BEARER); |
|
32 #endif |
|
33 |
|
34 PANICCATEGORY("SerialBear"); |
|
35 |
|
36 /** |
|
37 Factory function. |
|
38 @return Ownership of a new CRemConSerialBearer. |
|
39 */ |
|
40 CRemConSerialBearer* CRemConSerialBearer::NewL(TBearerParams& aParams) |
|
41 { |
|
42 LOG_STATIC_FUNC |
|
43 CRemConSerialBearer* self = new(ELeave) CRemConSerialBearer(aParams); |
|
44 CleanupStack::PushL(self); |
|
45 self->ConstructL(); |
|
46 CLEANUPSTACK_POP1(self); |
|
47 return self; |
|
48 } |
|
49 |
|
50 /** |
|
51 Destructor. |
|
52 */ |
|
53 CRemConSerialBearer::~CRemConSerialBearer() |
|
54 { |
|
55 LOG_LINE |
|
56 LOG_FUNC |
|
57 |
|
58 delete iSender; |
|
59 delete iReceiver; |
|
60 |
|
61 iComm.Close(); |
|
62 iCommServ.Close(); |
|
63 |
|
64 /*#ifndef __WINS__ |
|
65 if ( iUsb.Handle() ) |
|
66 { |
|
67 // Can't do anything with error here. |
|
68 (void)iUsb.Stop(); |
|
69 } |
|
70 iUsb.Close(); |
|
71 #endif |
|
72 */ |
|
73 } |
|
74 |
|
75 /** |
|
76 Constructor. |
|
77 */ |
|
78 CRemConSerialBearer::CRemConSerialBearer(TBearerParams& aParams) |
|
79 : CRemConBearerPlugin(aParams) |
|
80 { |
|
81 LOG_FUNC |
|
82 } |
|
83 |
|
84 /** |
|
85 2nd-phase construction. |
|
86 */ |
|
87 void CRemConSerialBearer::ConstructL() |
|
88 { |
|
89 // NB The sender and receiver have references to our RComm. We protect our |
|
90 // down-calls in case the port subsession is not open. |
|
91 iSender = CSender::NewL(iComm, *this); |
|
92 iReceiver = CReceiver::NewL(iComm, *this); |
|
93 |
|
94 /*#ifndef __WINS__ |
|
95 // Connect and Start USB to begin with. |
|
96 LEAVEIFERRORL(iUsb.Connect()); |
|
97 TRequestStatus stat; |
|
98 iUsb.Start(stat); |
|
99 User::WaitForRequest(stat); |
|
100 LEAVEIFERRORL(stat.Int()); |
|
101 #endif |
|
102 */ |
|
103 // We trap and discard errors from this 'connection' attempt. We don't |
|
104 // want to fail RemCon server initialisation because the port is being |
|
105 // used by someone else. When RemCon wants to send a command, it will |
|
106 // expect the bearer to reconnect. |
|
107 // In any case a controller client is allowed to request a |
|
108 // connection-oriented channel over this bearer- this will result in |
|
109 // another 'connection' attempt. |
|
110 TRAPD(err, ConnectL()); |
|
111 // If we 'connected' OK, throw an indication up to RemCon. |
|
112 if ( err == KErrNone ) |
|
113 { |
|
114 TRemConAddress addr; |
|
115 addr.BearerUid() = Uid(); |
|
116 err = Observer().ConnectIndicate(addr); |
|
117 if ( err != KErrNone ) |
|
118 { |
|
119 // We couldn't successfully tell RemCon about our connection, so |
|
120 // tear it down. |
|
121 ClosePort(); |
|
122 } |
|
123 } |
|
124 |
|
125 if ( iComm.SubSessionHandle() ) |
|
126 { |
|
127 Receive(); |
|
128 } |
|
129 |
|
130 // TRemConAddress addr; |
|
131 // addr.BearerUid() = Uid(); |
|
132 // addr.Addr() = _L8("different"); |
|
133 // Observer().ConnectIndicate(addr); |
|
134 |
|
135 LOG(_L("<<CRemConSerialBearer::ConstructL")); |
|
136 } |
|
137 |
|
138 TAny* CRemConSerialBearer::GetInterface(TUid aUid) |
|
139 { |
|
140 LOG_FUNC; |
|
141 LOG1(_L("\taUid = 0x%08x"), aUid); |
|
142 |
|
143 TAny* ret = NULL; |
|
144 if ( aUid == TUid::Uid(KRemConBearerInterface1) ) |
|
145 { |
|
146 ret = reinterpret_cast<TAny*>( |
|
147 static_cast<MRemConBearerInterface*>(this) |
|
148 ); |
|
149 } |
|
150 |
|
151 LOG1(_L("\tret = [0x%08x]"), ret); |
|
152 return ret; |
|
153 } |
|
154 |
|
155 void CRemConSerialBearer::ConnectRequest(const TRemConAddress& aAddr) |
|
156 { |
|
157 LOG(KNullDesC8); |
|
158 LOG_FUNC; |
|
159 // This bearer does not use client-specified connection data. The |
|
160 // connection data gives the *remote* address to connect to. This is not a |
|
161 // valid concept in the wired case. |
|
162 |
|
163 // This ASSERTS if we already have the port open!!!! |
|
164 TRAPD(connectErr, ConnectL()); |
|
165 |
|
166 TInt err = Observer().ConnectConfirm(aAddr, connectErr); |
|
167 // If there was an error in RemCon we should drop the connection otherwise |
|
168 // RemCon might get surprised by later incoming messages on a connection |
|
169 // it doesn't know exists. Otherwise, start listening for incoming data. |
|
170 // Of course, don't start listening unless the port opened OK |
|
171 // (connectErr). |
|
172 if ( err != KErrNone || connectErr != KErrNone ) |
|
173 { |
|
174 ClosePort(); |
|
175 } |
|
176 else |
|
177 { |
|
178 Receive(); |
|
179 } |
|
180 } |
|
181 |
|
182 void CRemConSerialBearer::DisconnectRequest(const TRemConAddress& aAddr) |
|
183 { |
|
184 LOG(KNullDesC8); |
|
185 LOG_FUNC; |
|
186 |
|
187 // make sure we are connected before disconnect |
|
188 ASSERT_ALWAYS(iCommServ.Handle()); |
|
189 |
|
190 // Undo everything done in Connect (without assuming that Connect |
|
191 // completed successfully). Must cancel any outstanding requests for this |
|
192 // to be safe. |
|
193 ClosePort(); |
|
194 Observer().DisconnectConfirm(aAddr, KErrNone); |
|
195 } |
|
196 |
|
197 void CRemConSerialBearer::ConnectL() |
|
198 { |
|
199 LOG_FUNC; |
|
200 |
|
201 #if defined (__WINS__) |
|
202 #define PDD_NAME _L("ECDRV") |
|
203 #define LDD_NAME _L("ECOMM") |
|
204 #else // __GCC32__ |
|
205 #define PDD_NAME _L("EUART1") |
|
206 #define LDD_NAME _L("ECOMM") |
|
207 #endif |
|
208 |
|
209 // make sure we aren't connected |
|
210 ASSERT_ALWAYS(!iCommServ.Handle()); |
|
211 |
|
212 TInt r=User::LoadPhysicalDevice(PDD_NAME); |
|
213 if (r!=KErrNone && r!=KErrAlreadyExists) |
|
214 { |
|
215 LEAVEIFERRORL(r); |
|
216 } |
|
217 r=User::LoadLogicalDevice(LDD_NAME); |
|
218 if (r!=KErrNone && r!=KErrAlreadyExists) |
|
219 { |
|
220 LEAVEIFERRORL(r); |
|
221 } |
|
222 |
|
223 _LIT(KModule, "ECUART"); |
|
224 #if defined (__WINS__) |
|
225 _LIT(KPort, "COMM::1"); |
|
226 #else |
|
227 // _LIT(KPort, "COMM::2"); // On H2 and H4 this is the IR port |
|
228 // use COMM::2 for Lubbock. |
|
229 _LIT(KPort, "COMM::3"); // need this for H2 and H4 board |
|
230 #endif |
|
231 |
|
232 LEAVEIFERRORL(iCommServ.Connect()); |
|
233 |
|
234 // if appropriate close will unloadcommmodule internally |
|
235 CleanupClosePushL(iCommServ); |
|
236 |
|
237 LEAVEIFERRORL(iCommServ.LoadCommModule(KModule)); |
|
238 |
|
239 // as above if not connected this should be NULL |
|
240 ASSERT_ALWAYS(!iComm.SubSessionHandle()); |
|
241 |
|
242 LEAVEIFERRORL(iComm.Open(iCommServ, KPort, ECommExclusive)); |
|
243 |
|
244 // put these on clean up stack - will call close if we leave |
|
245 CleanupClosePushL(iComm); |
|
246 |
|
247 // Put the port's config into a known state. |
|
248 TCommConfig portSettings; |
|
249 LEAVEIFERRORL(iComm.Config(portSettings)); |
|
250 portSettings().iRate = EBps115200; |
|
251 portSettings().iDataBits = EData8; |
|
252 portSettings().iStopBits = EStop1; |
|
253 LEAVEIFERRORL(iComm.SetConfig(portSettings)); |
|
254 |
|
255 CleanupStack::Pop(2,&iCommServ);// pop iComm then iCommServ |
|
256 |
|
257 /* clear out the serial port so we know we start from fresh... |
|
258 simple expedient (that hopefully will work), try and receive 20 bytes, |
|
259 then cancel the receive. Given the current behaviour of the read cancel this |
|
260 will return any characters that are currently in the serial port buffers |
|
261 */ |
|
262 ASSERT_DEBUG(iReceiver); |
|
263 Receive(); |
|
264 iReceiver->Cancel(); |
|
265 } |
|
266 |
|
267 void CRemConSerialBearer::ClosePort() |
|
268 { |
|
269 LOG_FUNC; |
|
270 |
|
271 ASSERT_DEBUG(iSender); |
|
272 iSender->Cancel(); |
|
273 ASSERT_DEBUG(iReceiver); |
|
274 iReceiver->Cancel(); |
|
275 iComm.Close(); |
|
276 iCommServ.Close(); |
|
277 } |
|
278 |
|
279 TInt CRemConSerialBearer::SendResponse(TUid aInterfaceUid, |
|
280 TUint aOperationId, |
|
281 TUint /*aTransactionId*/, // we don't care about this transaction ID |
|
282 RBuf8& aData, |
|
283 const TRemConAddress& /*aAddr*/) |
|
284 { |
|
285 LOG(KNullDesC8); |
|
286 LOG_FUNC; |
|
287 LOG1(_L("\taOperationId = 0x%02x"), aOperationId); |
|
288 |
|
289 TInt ret = DoSend(aInterfaceUid, aOperationId, aData, ERemConResponse); |
|
290 |
|
291 LOG1(_L("\tret = %d"), ret); |
|
292 return ret; |
|
293 } |
|
294 |
|
295 TInt CRemConSerialBearer::SendCommand(TUid aInterfaceUid, |
|
296 TUint aOperationId, |
|
297 TUint aTransactionId, |
|
298 RBuf8& aData, |
|
299 const TRemConAddress& /*aAddr*/) |
|
300 { |
|
301 LOG(KNullDesC8()); |
|
302 LOG_FUNC; |
|
303 LOG1(_L("\taOperationId = 0x%02x"), aOperationId); |
|
304 |
|
305 iTransactionId = aTransactionId; |
|
306 TInt ret = DoSend(aInterfaceUid, aOperationId, aData, ERemConCommand); |
|
307 |
|
308 LOG1(_L("\tret = %d"), ret); |
|
309 return ret; |
|
310 } |
|
311 |
|
312 TInt CRemConSerialBearer::DoSend(TUid aInterfaceUid, |
|
313 TUint aOperationId, |
|
314 RBuf8& aData, |
|
315 TRemConMessageType aMsgType) |
|
316 { |
|
317 LOG_FUNC; |
|
318 |
|
319 TInt ret = KErrInUse; |
|
320 |
|
321 // make sure we are connected |
|
322 ASSERT_ALWAYS(iComm.SubSessionHandle()); |
|
323 |
|
324 // Check we're not already busy sending. |
|
325 ASSERT_DEBUG(iSender); |
|
326 if ( iSender->IsActive() ) |
|
327 { |
|
328 ret = KErrInUse; |
|
329 } |
|
330 else |
|
331 { |
|
332 ret = Observer().InterfaceToBearer(Uid(), aInterfaceUid, aOperationId, aData, aMsgType, iOutMsg); |
|
333 if ( ret == KErrNone ) |
|
334 { |
|
335 LOG1(_L("\tsending text \"%S\""), &iOutMsg); |
|
336 iSender->Send(iOutMsg); |
|
337 } |
|
338 } |
|
339 |
|
340 // If no error, we took ownership of aData- we've finished with it now. |
|
341 if ( ret == KErrNone ) |
|
342 { |
|
343 aData.Close(); |
|
344 } |
|
345 |
|
346 LOG1(_L("\tret = %d"), ret); |
|
347 return ret; |
|
348 } |
|
349 |
|
350 void CRemConSerialBearer::MsoSendComplete(TInt aError) |
|
351 { |
|
352 LOG(KNullDesC8); |
|
353 LOG_FUNC; |
|
354 LOG1(_L("\taError = %d"), aError); |
|
355 (void)aError; |
|
356 |
|
357 // We don't do anything. How does RemCon get to know of this? Does it |
|
358 // care? No. A command which never gets a response is standard remote |
|
359 // control behaviour. The user will retry, and doesn't need an InfoMsg to |
|
360 // tell them anything about it. |
|
361 } |
|
362 |
|
363 TInt CRemConSerialBearer::GetResponse(TUid& aInterfaceUid, |
|
364 TUint& aTransactionId, |
|
365 TUint& aOperationId, |
|
366 RBuf8& aData, |
|
367 TRemConAddress& aAddr) |
|
368 { |
|
369 LOG_FUNC; |
|
370 |
|
371 ASSERT_DEBUG(iReceiver); |
|
372 // RemCon shouldn't call use unless we prompted them to with NewResponse. |
|
373 ASSERT_DEBUG(!iReceiver->IsActive()); |
|
374 // The message should be a response, unless RemCon is being buggy and |
|
375 // calling GetResponse at bad times. |
|
376 ASSERT_DEBUG(iMsgType == ERemConResponse); |
|
377 |
|
378 TRAPD(err, DoGetResponseL(aInterfaceUid, aOperationId, aData, aAddr)); |
|
379 LOG3(_L("\taInterfaceUid = 0x%08x, aOperationId = 0x%02x, msgType = %d"), |
|
380 aInterfaceUid, aOperationId, iMsgType); |
|
381 |
|
382 // The serial bearer only has one incoming message in it at once, so we |
|
383 // don't need any queueing or anything fancy to get the transaction ID- |
|
384 // it's just the last one RemCon told us. |
|
385 aTransactionId = iTransactionId; |
|
386 |
|
387 // Repost read request on port. |
|
388 Receive(); |
|
389 |
|
390 LOG1(_L("\terr = %d"), err); |
|
391 return err; |
|
392 } |
|
393 |
|
394 void CRemConSerialBearer::DoGetResponseL(TUid& aInterfaceUid, |
|
395 TUint& aOperationId, |
|
396 RBuf8& aData, |
|
397 TRemConAddress& aAddr) |
|
398 { |
|
399 LOG_FUNC; |
|
400 |
|
401 aInterfaceUid = iInterfaceUid; |
|
402 aOperationId = iOperationId; |
|
403 ASSERT_DEBUG(aData.MaxLength() == 0); |
|
404 // Pass ownership of this to RemCon. |
|
405 aData.CreateL(iData); |
|
406 |
|
407 aAddr.BearerUid() = Uid(); |
|
408 aAddr.Addr() = KNullDesC8(); |
|
409 } |
|
410 |
|
411 TInt CRemConSerialBearer::GetCommand(TUid& aInterfaceUid, |
|
412 TUint& aTransactionId, |
|
413 TUint& aOperationId, |
|
414 RBuf8& aData, |
|
415 TRemConAddress& aAddr) |
|
416 { |
|
417 LOG_FUNC; |
|
418 |
|
419 ASSERT_DEBUG(iReceiver); |
|
420 // RemCon shouldn't call use unless we prompted them to with NewCommand. |
|
421 ASSERT_DEBUG(!iReceiver->IsActive()); |
|
422 // The message should be a command, unless RemCon is being buggy and |
|
423 // calling GetCommand at bad times. |
|
424 ASSERT_DEBUG(iMsgType == ERemConCommand); |
|
425 |
|
426 TRAPD(err, DoGetCommandL(aInterfaceUid, aOperationId, aData, aAddr)); |
|
427 LOG3(_L("\taInterfaceUid = 0x%08x, aOperationId = 0x%02x, msgType = %d"), |
|
428 aInterfaceUid, aOperationId, iMsgType); |
|
429 |
|
430 // The serial bearer only has one incoming message in it at once, so we |
|
431 // don't need any queueing or anything fancy to get the transaction ID- |
|
432 // it's just the last one RemCon told us. |
|
433 aTransactionId = iTransactionId; |
|
434 |
|
435 // Repost read request on port. |
|
436 Receive(); |
|
437 |
|
438 LOG1(_L("\terr = %d"), err); |
|
439 return err; |
|
440 } |
|
441 |
|
442 void CRemConSerialBearer::DoGetCommandL(TUid& aInterfaceUid, |
|
443 TUint& aOperationId, |
|
444 RBuf8& aData, |
|
445 TRemConAddress& aAddr) |
|
446 { |
|
447 LOG_FUNC; |
|
448 |
|
449 aInterfaceUid = iInterfaceUid; |
|
450 aOperationId = iOperationId; |
|
451 // Pass ownership of this to RemCon. |
|
452 aData.CreateL(iData); |
|
453 |
|
454 aAddr.BearerUid() = Uid(); |
|
455 aAddr.Addr() = KNullDesC8(); |
|
456 } |
|
457 |
|
458 // Utility to repost a read on the port. |
|
459 void CRemConSerialBearer::Receive() |
|
460 { |
|
461 LOG_FUNC; |
|
462 |
|
463 ASSERT_DEBUG(iComm.SubSessionHandle()); |
|
464 ASSERT_DEBUG(iReceiver); |
|
465 /* we should check we aren't currently trying to receive. |
|
466 In this design we only kick off a receive when we aren't already trying to read something already. |
|
467 If we get this wrong the SetActive in iReceiver->Receive will blow up, so we'll assert here so we know. |
|
468 This configuration is for test code not real life so there is no 'real' problem anyway. |
|
469 */ |
|
470 ASSERT_DEBUG(!iReceiver->IsActive()); |
|
471 /* you might expect to see an iReceiver->Cancel() here BUT there are problems with doing this |
|
472 a) The underlying RComm::Read may just decide to put the 5 bytes of message it currently has in |
|
473 the buffer (if we happen to call this half way through an incoming message). In this case this |
|
474 bearer will NEVER recover as it assumes it will only receive the proper complete 30 byte message |
|
475 and makes no attempt to get back in step (it will have 5 bytes from one message + 25 from another for ever). |
|
476 b) We are pretty confident we don't need to (see above). |
|
477 */ |
|
478 iReceiver->Receive(iInMsg); |
|
479 } |
|
480 |
|
481 void CRemConSerialBearer::MroReceiveComplete(TInt aError) |
|
482 { |
|
483 LOG(KNullDesC8); |
|
484 LOG_FUNC; |
|
485 LOG2(_L("\taError = %d, iInMsg = \"%S\""), aError, &iInMsg); |
|
486 |
|
487 // If any error occurred either getting or decoding the message, we need |
|
488 // to re-post now. Otherwise, we wait until after RemCon has picked up the |
|
489 // message until we re-post a read. |
|
490 if ( aError == KErrNone ) |
|
491 { |
|
492 TRemConAddress addr; |
|
493 addr.BearerUid() = Uid(); |
|
494 addr.Addr() = KNullDesC8(); |
|
495 |
|
496 aError = Observer().BearerToInterface(Uid(), |
|
497 iInMsg, |
|
498 iInMsg, |
|
499 iInterfaceUid, |
|
500 iOperationId, |
|
501 iMsgType, |
|
502 iData); |
|
503 |
|
504 if ( aError == KErrNone ) |
|
505 { |
|
506 if ( iMsgType == ERemConCommand ) |
|
507 { |
|
508 iTransactionId = Observer().NewTransactionId(); |
|
509 aError = Observer().NewCommand(addr); |
|
510 } |
|
511 else if ( iMsgType == ERemConResponse ) |
|
512 { |
|
513 aError = Observer().NewResponse(addr); |
|
514 } |
|
515 else |
|
516 { |
|
517 // drop the message (malformed- not apparently a command or response) |
|
518 aError = KErrNotSupported; |
|
519 } |
|
520 } |
|
521 // else drop the message (either no converter for that interface UID or it couldn't convert the message) |
|
522 } |
|
523 // else just drop the message (error receiving it) |
|
524 |
|
525 // If we successfully told RemCon there was a new message to pick up, |
|
526 // don't repost our port read until RemCon has come back and picked up the |
|
527 // message. If there was any error, then RemCon isn't going to come back |
|
528 // for this message- it's effectively dropped- and we should re-post our |
|
529 // request now. |
|
530 if ( aError != KErrNone ) |
|
531 { |
|
532 Receive(); |
|
533 } |
|
534 } |
|
535 |
|
536 TSecurityPolicy CRemConSerialBearer::SecurityPolicy() const |
|
537 { |
|
538 return TSecurityPolicy(ECapabilityLocalServices); |
|
539 } |
|
540 |
|
541 void CRemConSerialBearer::ClientStatus(TBool aControllerPresent, TBool aTargetPresent) |
|
542 { |
|
543 LOG2(_L("CRemConSerialBearer::ClientStatus aControllerPresent = %d, aTargetPresent = %d"), |
|
544 aControllerPresent, aTargetPresent); |
|
545 (void)aControllerPresent; |
|
546 (void)aTargetPresent; |
|
547 |
|
548 // I don't care. |
|
549 } |