|
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 // This file implements a loopback driver for use with 3GNIF test harness. |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 */ |
|
21 |
|
22 #include <c32comm.h> |
|
23 #include <c32comm_internal.h> |
|
24 |
|
25 #include "Loopback.h" |
|
26 #include "LoopbackConfig.h" |
|
27 #include "LoopbackTimer.h" |
|
28 #include "LoopbackQueue.h" |
|
29 |
|
30 CHWPort::CHWPort(TUint aUnit) : iRole(ECommRoleDTE), iPortName(aUnit) |
|
31 { |
|
32 TName name; |
|
33 name.Format(_L("%d"),aUnit); |
|
34 SetName(&name); |
|
35 } |
|
36 |
|
37 static void CloseObject(TAny* anObject) |
|
38 /** |
|
39 * This method simply closes an object from the cleanup stack. The object must contain |
|
40 * a Close method. |
|
41 * |
|
42 * @param anObject - a TAny pointer to the object to close. |
|
43 */ |
|
44 { |
|
45 ((CObject*)anObject)->Close(); |
|
46 } |
|
47 |
|
48 CHWPort* CHWPort::NewPacketLoopbackL(TUint aUnit, TUint aDelay, TUint aPacketLength, TUint aQueueLength) |
|
49 /** |
|
50 * This method is used by the factory object to create the new CHWPort instances. |
|
51 * After newing the CHWPort object, the buffer is created, roles and signals are defaulted, |
|
52 * and names are initialized. |
|
53 * |
|
54 * @param aUnit - the port number to create. |
|
55 * @param aDelay - the delay for sending on the port |
|
56 * @param aPacketLength - the size in bytes of a packet |
|
57 * @param aQueueLength - the maximum number of packets to queue |
|
58 * |
|
59 * @return A pointer to the created object |
|
60 */ |
|
61 { |
|
62 LOGTEXT2(_L8("PKTLOOPBACK:NewL: Called for Unit %d"), aUnit); |
|
63 |
|
64 CHWPort *p = new(ELeave) CHWPort(aUnit); |
|
65 TCleanupItem closePort(CloseObject,p); |
|
66 CleanupStack::PushL(closePort); |
|
67 p->ConstructPacketLoopbackL(aDelay, aPacketLength, aQueueLength); |
|
68 CleanupStack::Pop(p); |
|
69 |
|
70 return p; |
|
71 } |
|
72 |
|
73 CHWPort* CHWPort::NewSerialLoopbackL(TUint aUnit, TUint aDelay, TUint aBufferSize) |
|
74 /** |
|
75 * This method is used by the factory object to create the new CHWPort instances. |
|
76 * After newing the CHWPort object, the buffer is created, roles and signals are defaulted, |
|
77 * and names are initialized. |
|
78 * |
|
79 * @param aUnit - the port number to create. |
|
80 * @param aDelay - the delay for sending on the port |
|
81 * @param aBuffersize - the size of the buffer to allocate |
|
82 * |
|
83 * @return A pointer to the created object |
|
84 */ |
|
85 { |
|
86 LOGTEXT2(_L8("PKTLOOPBACK:NewL: Called for Unit %d"), aUnit); |
|
87 |
|
88 CHWPort *p = new(ELeave) CHWPort(aUnit); |
|
89 TCleanupItem closePort(CloseObject,p); |
|
90 CleanupStack::PushL(closePort); |
|
91 p->ConstructSerialLoopbackL(aDelay, aBufferSize); |
|
92 CleanupStack::Pop(p); |
|
93 |
|
94 return p; |
|
95 } |
|
96 |
|
97 void CHWPort::ConstructSerialLoopbackL(TUint aDelay, TUint aBufferSize) |
|
98 { |
|
99 iWriteDelayTimer = CLoopbackTimer::NewL(aDelay, this); |
|
100 iFlowControlChange = CFlowControlChange::NewL(iPortName, this); |
|
101 |
|
102 iPortType = ESerialLoopbackPortType; |
|
103 TCommConfigV01 *config = &iConfig(); |
|
104 iReadWriteQueue = CSerialBufferQueue::NewL(aBufferSize, config); |
|
105 } |
|
106 |
|
107 void CHWPort::ConstructPacketLoopbackL(TUint aDelay, TUint aPacketLength, TUint aQueueLength) |
|
108 { |
|
109 iWriteDelayTimer = CLoopbackTimer::NewL(aDelay, this); |
|
110 iFlowControlChange = CFlowControlChange::NewL(iPortName, this); |
|
111 iReadWriteQueue = CPacketBufferQueue::NewL(aPacketLength, aQueueLength); |
|
112 } |
|
113 |
|
114 TUint CHWPort::PortName() const |
|
115 { |
|
116 return iPortName; |
|
117 } |
|
118 |
|
119 void CHWPort::SetLoopbackPort(CHWPort* aHWPort) |
|
120 /** |
|
121 * This method sets up the loopback port member of the CHWPort. It is used after |
|
122 * both ports have been created (NewL). This allows each port to "know" to whom he is |
|
123 * connected. |
|
124 * |
|
125 * @param aHWPort - the port which THIS port should be connected to. |
|
126 */ |
|
127 { |
|
128 LOGTEXT2(_L8("PKTLOOPBACK:SetLoopbackPort: Unit %d..."), iPortName); |
|
129 |
|
130 // Now set up the loopback |
|
131 iLoopbackPort = aHWPort; |
|
132 } |
|
133 |
|
134 TBool CHWPort::GetFlowControl() const |
|
135 /** |
|
136 * @return ETrue if flow control is on, EFalse if it is not |
|
137 */ |
|
138 { |
|
139 return iFlowControlChange->FlowControlIsOn(); |
|
140 } |
|
141 |
|
142 void CHWPort::StartFlowControl() |
|
143 /** |
|
144 * Performs any necessary actions to set flow control on |
|
145 */ |
|
146 { |
|
147 iWriteDelayTimer->Cancel(); |
|
148 } |
|
149 |
|
150 void CHWPort::StopFlowControl() |
|
151 /** |
|
152 * Performs any necessary actions to stop flow control |
|
153 */ |
|
154 { |
|
155 if (!iLoopbackPort) |
|
156 { |
|
157 return; |
|
158 } |
|
159 |
|
160 if (iReadWriteQueue->IsWriteBufferEmpty()) |
|
161 { |
|
162 return; |
|
163 } |
|
164 |
|
165 TInt nextWriteLen = iReadWriteQueue->PeekNextWriteBuffer().Length(); |
|
166 if (!iLoopbackPort->iReadWriteQueue->IsReadBufferFull(nextWriteLen) |
|
167 && !iWriteDelayTimer->IsActive()) |
|
168 { |
|
169 iWriteDelayTimer->Start(); |
|
170 } |
|
171 } |
|
172 |
|
173 TInt CHWPort::GetReadRequestStatus() |
|
174 /** |
|
175 * @return The status that Read() calls are to complete with |
|
176 */ |
|
177 { |
|
178 TInt readRequestStatus = KErrNone; |
|
179 TInt ret = RProperty::Get(KUidPSCsyReadResultCategory, iPortName, readRequestStatus); |
|
180 if (ret == KErrNone) |
|
181 return readRequestStatus; |
|
182 // if we can't find this property, we make everything work |
|
183 return KErrNone; |
|
184 } |
|
185 |
|
186 TInt CHWPort::GetWriteRequestStatus() |
|
187 /** |
|
188 * @return The status that Write() calls are to complete with |
|
189 */ |
|
190 { |
|
191 TInt writeRequestStatus = KErrNone; |
|
192 TInt ret = RProperty::Get(KUidPSCsyWriteResultCategory, iPortName, writeRequestStatus); |
|
193 if (ret == KErrNone) |
|
194 return writeRequestStatus; |
|
195 // if we can't find this property, we make everything work |
|
196 return KErrNone; |
|
197 } |
|
198 |
|
199 void CHWPort::StartRead(const TAny* aClientBuffer, TInt aLength) |
|
200 /** |
|
201 * This method queues a read operation to the driver. If the read length is zero (which is a |
|
202 * special case used during initialization) the read completes immediately. |
|
203 * If the read buffer is insufficient in size, the read completes with error KErrOverflow. |
|
204 * |
|
205 * @param aClientBuffer - a TAny * to the buffer into which data is placed. |
|
206 * @param aLength - the length of the buffer supplied |
|
207 */ |
|
208 { |
|
209 LOGTEXT2(_L8("PKTLOOPBACK:StartRead: Unit %d..."), iPortName); |
|
210 |
|
211 // Because a length of zero is a special case (for initialization), we will complete this immediately |
|
212 if(aLength == 0) |
|
213 { |
|
214 ReadCompleted(KErrNone); |
|
215 return; |
|
216 } |
|
217 else if(aLength < 0) |
|
218 { |
|
219 // if the read is through the function ReadOneOrMore, the length will be negative |
|
220 // in this CSY, the behavior is always ReadOneOrMore |
|
221 aLength = -aLength; |
|
222 iReadOneOrMore = ETrue; |
|
223 } |
|
224 else // aLength > 0 |
|
225 { |
|
226 iReadOneOrMore = EFalse; |
|
227 } |
|
228 |
|
229 // Save the client read buffer |
|
230 iClientReadBuffer = aClientBuffer; |
|
231 iClientReadBufferLength = aLength; |
|
232 iReadPending = ETrue; |
|
233 |
|
234 // if there is already an entry in the read buffer, we can complete the read now |
|
235 TryToCompleteRead(); |
|
236 } |
|
237 |
|
238 void CHWPort::TryToCompleteRead() |
|
239 /** |
|
240 * This method attempts to complete reads - it is either called as they are initially issued (and is |
|
241 * completed if there is data already in the read buffer), or is is called later, when data is supplied |
|
242 * to the read buffer (and is completed if there is a read waiting) |
|
243 * Data is moved from the buffer associated with this port to a buffer that was supplied by the client |
|
244 * when the read was issued. |
|
245 */ |
|
246 |
|
247 { |
|
248 LOGTEXT2(_L8("PKTLOOPBACK:TryToCompleteRead: Unit %d ..."), iPortName); |
|
249 |
|
250 // If there is not read pending or no loopback port, we can't complete a read |
|
251 if (!iReadPending) |
|
252 return; |
|
253 |
|
254 if (!iLoopbackPort) |
|
255 return; |
|
256 |
|
257 // Determine if there an entry available to be read |
|
258 if (iReadWriteQueue->IsReadBufferEmpty()) |
|
259 return; |
|
260 |
|
261 TInt res = KErrNone; |
|
262 TBool completeIfBufferNotFull; |
|
263 TPtrC8 nextReadBuffer = iReadWriteQueue->PeekNextReadBuffer(completeIfBufferNotFull); |
|
264 if ( iClientReadBufferLength > nextReadBuffer.Length() ) |
|
265 { |
|
266 if (iPortType == ESerialLoopbackPortType) |
|
267 { |
|
268 if (iReadOneOrMore == EFalse) |
|
269 { |
|
270 if (!completeIfBufferNotFull) |
|
271 { |
|
272 return; |
|
273 } |
|
274 } |
|
275 } |
|
276 } |
|
277 |
|
278 TInt readRequestStatus = GetReadRequestStatus(); |
|
279 if ( (iClientReadBufferLength < nextReadBuffer.Length()) && (iPortType == EPacketLoopbackPortType) ) |
|
280 { |
|
281 // The client buffer is not large enough |
|
282 res = KErrOverflow; |
|
283 } |
|
284 else if (readRequestStatus != KErrNone) |
|
285 { |
|
286 // We are configured to complete with an error |
|
287 res = readRequestStatus; |
|
288 iReadWriteQueue->DiscardNextReadBuffer(); |
|
289 } |
|
290 else |
|
291 { |
|
292 // Write the data to the client's supplied buffer |
|
293 res = IPCWrite(iClientReadBuffer, nextReadBuffer, 0); |
|
294 if(res == KErrNone) |
|
295 { |
|
296 // It is normally the writing buffer's responsibility to start the timer, but in the case where the |
|
297 // reading port's buffer is full, now that the read buffer is no longer full, we have to signal to the |
|
298 // writing port to start sending again |
|
299 if (!iLoopbackPort->iReadWriteQueue->IsWriteBufferEmpty()) |
|
300 { |
|
301 TInt nextWriteLen = iLoopbackPort->iReadWriteQueue->PeekNextWriteBuffer().Length(); |
|
302 if (iReadWriteQueue->IsReadBufferFull(nextWriteLen) |
|
303 && !iLoopbackPort->iWriteDelayTimer->IsActive() ) |
|
304 { |
|
305 iLoopbackPort->iWriteDelayTimer->Start(); |
|
306 } |
|
307 } |
|
308 // Read has been completed successfully, so dequeue |
|
309 iReadWriteQueue->DiscardNextReadBuffer(); |
|
310 } |
|
311 } |
|
312 // complete the read |
|
313 iReadPending = EFalse; |
|
314 LOGTEXT3(_L8("PKTLOOPBACK:TryToCompleteRead: Unit %d completing read with error %d"), iPortName, res); |
|
315 ReadCompleted(res); |
|
316 } |
|
317 |
|
318 void CHWPort::ReadCancel() |
|
319 /** |
|
320 * Cancel a pending read and complete it with KErrCancel. The handling of the CActive class |
|
321 * will by default complete any outstanding read with KErrCancel, but it is cleaner to handle |
|
322 * that processing here. |
|
323 */ |
|
324 { |
|
325 LOGTEXT2(_L8("PKTLOOPBACK:ReadCancel: Unit %d..."), iPortName); |
|
326 |
|
327 iReadPending = EFalse; |
|
328 |
|
329 ReadCompleted(KErrCancel); |
|
330 } |
|
331 |
|
332 TInt CHWPort::WriteBuf(const TAny* aClientBuffer, TInt aLength) |
|
333 /** |
|
334 * This method queues the client buffer to the loopback port. |
|
335 * A delay in the port is simulated, so the read corresponding to this buffer will not complete |
|
336 * until after this delay. The buffers are queued up and sent one per delay period. |
|
337 * |
|
338 * @param aClientBuffer - a TAny * to the buffer which contains the data to write |
|
339 * @param aLength - the length of the buffer. |
|
340 * |
|
341 * @return KErrNone if everything is okay, KErrOverflow if the write queue is full and no more entries can be written until some have been sent, |
|
342 * KErrNotReady if the loopback port has not yet been opened or there is no loopback port configured for this port, or KErrArgument if the supplied buffer is too large |
|
343 */ |
|
344 { |
|
345 TInt res = KErrNone; |
|
346 |
|
347 LOGTEXT2(_L8("PKTLOOPBACK:WriteBuf: Unit %d..."), iPortName); |
|
348 |
|
349 TInt writeRequestStatus = GetWriteRequestStatus(); |
|
350 if (writeRequestStatus != KErrNone) |
|
351 return writeRequestStatus; |
|
352 |
|
353 // Fill the receiving buffer |
|
354 if (aLength != 0) |
|
355 { |
|
356 if (iReadWriteQueue->IsWriteBufferFull(aLength)) |
|
357 { |
|
358 return KErrOverflow; |
|
359 } |
|
360 if (aLength > iReadWriteQueue->BufferSize()) |
|
361 { |
|
362 return KErrArgument; |
|
363 } |
|
364 |
|
365 TPtr8 currentPacket = iReadWriteQueue->AppendToWriteBuffer(aLength); |
|
366 |
|
367 res = IPCRead(aClientBuffer, currentPacket); |
|
368 if(res != KErrNone) |
|
369 return res; |
|
370 } |
|
371 // Queue up the request and start the timer to simulate the delay in sending the data across the port |
|
372 if (!iWriteDelayTimer->IsActive()) |
|
373 { |
|
374 iWriteDelayTimer->Start(); |
|
375 } |
|
376 |
|
377 return KErrNone; |
|
378 } |
|
379 |
|
380 void CHWPort::TimerCallBack() |
|
381 /** |
|
382 * This method is called after the simulated delay for sending data across the port |
|
383 */ |
|
384 { |
|
385 if (!iLoopbackPort) |
|
386 { |
|
387 return; |
|
388 } |
|
389 |
|
390 if (iReadWriteQueue->IsWriteBufferEmpty()) |
|
391 { |
|
392 return; |
|
393 } |
|
394 |
|
395 TPtrC8 writeBuffer = iReadWriteQueue->PeekNextWriteBuffer(); |
|
396 if (iLoopbackPort->iReadWriteQueue->IsReadBufferFull(writeBuffer.Length())) |
|
397 { |
|
398 return; |
|
399 } |
|
400 |
|
401 // Move the buffer from the write queue to the read queue |
|
402 iLoopbackPort->iReadWriteQueue->AppendToReadBuffer(writeBuffer); |
|
403 iReadWriteQueue->DiscardNextWriteBuffer(); |
|
404 |
|
405 // If the loopback port has a read outstanding it can complete now |
|
406 iLoopbackPort->TryToCompleteRead(); |
|
407 // If there is another write outstanding we have to simulate a delay for that entry |
|
408 if (!iReadWriteQueue->IsWriteBufferEmpty() && !iWriteDelayTimer->IsActive()) |
|
409 { |
|
410 iWriteDelayTimer->Start(); |
|
411 } |
|
412 } |
|
413 |
|
414 TInt CHWPort::QueryReceiveBuffer(TInt& aLength) const |
|
415 /** |
|
416 * This method returns the length of the buffer associated with this instance of the |
|
417 * port. |
|
418 * |
|
419 * @param aLength - a reference to return the length of the buffer. |
|
420 */ |
|
421 { |
|
422 LOGTEXT2(_L8("PKTLOOPBACK:QueryReceiveBuffer: Unit %d..."), iPortName); |
|
423 |
|
424 TBool dummy; |
|
425 const TPtrC8& iReadBuf = iReadWriteQueue->PeekNextReadBuffer(dummy); |
|
426 aLength = iReadBuf.Length(); |
|
427 return KErrNone; |
|
428 } |
|
429 |
|
430 void CHWPort::ResetBuffers(TUint) |
|
431 /** |
|
432 * This method resets the buffer used by this loopback port |
|
433 * |
|
434 * @note Note that most ResetBuffers methods derived from CPort allow a parameter for flags. |
|
435 * This ResetBuffers method does not. |
|
436 * |
|
437 * @param Not Used |
|
438 */ |
|
439 { |
|
440 LOGTEXT2(_L8("PKTLOOPBACK:ResetBuffers: Unit %d..."), iPortName); |
|
441 |
|
442 iReadWriteQueue->Clear(); |
|
443 } |
|
444 |
|
445 void CHWPort::StartWrite(const TAny* aClientBuffer,TInt aLength) |
|
446 /** |
|
447 * This method queues a write operation to the driver. |
|
448 * |
|
449 * @param aClientBuffer - a TAny * to the buffer into which data should be read. |
|
450 * @param aLength - the length of the data to be written. |
|
451 */ |
|
452 { |
|
453 |
|
454 LOGTEXT2(_L8("PKTLOOPBACK:StartWrite: Unit %d..."), iPortName); |
|
455 |
|
456 TInt res = WriteBuf(aClientBuffer, aLength); |
|
457 |
|
458 LOGTEXT3(_L8("PKTLOOPBACK:StartWrite: Completing Write for Unit %d with error %d"), iPortName, res); |
|
459 WriteCompleted(res); |
|
460 } |
|
461 |
|
462 void CHWPort::WriteCancel() |
|
463 /** |
|
464 * This method cancels a pending write and issues a WriteCompleted with the result |
|
465 * KErrCancel. |
|
466 */ |
|
467 |
|
468 { |
|
469 LOGTEXT2(_L8("PKTLOOPBACK:WriteCancel: Unit %d..."), iPortName); |
|
470 |
|
471 WriteCompleted(KErrCancel); |
|
472 } |
|
473 |
|
474 void CHWPort::Break(TInt /*aTime*/) |
|
475 /** |
|
476 * This method is currently not implemented in the loopback driver as breaks are |
|
477 * not supported. |
|
478 */ |
|
479 { |
|
480 LOGTEXT2(_L8("PKTLOOPBACK:Break is not supported: Unit %d..."), iPortName); |
|
481 } |
|
482 |
|
483 void CHWPort::BreakCancel() |
|
484 /** |
|
485 * This method is currently not implemented in the loopback driver as breaks are |
|
486 * not supported. |
|
487 */ |
|
488 { |
|
489 LOGTEXT2(_L8("PKTLOOPBACK:BreakCancel is not supported: Unit %d..."), iPortName); |
|
490 } |
|
491 |
|
492 TInt CHWPort::GetConfig(TDes8& /*aDes*/) const |
|
493 /** |
|
494 * This gets the current configuration from the loopback driver. |
|
495 * |
|
496 * @return KErrNotSupported |
|
497 */ |
|
498 { |
|
499 LOGTEXT2(_L8("PKTLOOPBACK:GetConfig is not supported: Unit %d..."), iPortName); |
|
500 |
|
501 return KErrNotSupported; |
|
502 } |
|
503 |
|
504 TInt CHWPort::SetConfig(const TDesC8& aDes) |
|
505 /** |
|
506 * This sets the current configuration for the loopback driver. Note that |
|
507 * no error checking is done when setting the configuration. |
|
508 * |
|
509 * @return KErrNotSupported |
|
510 */ |
|
511 { |
|
512 LOGTEXT2(_L8("PKTLOOPBACK:SetConfig is not supported: Unit %d..."), iPortName); |
|
513 |
|
514 iConfig.Copy(aDes); |
|
515 |
|
516 return KErrNone; |
|
517 } |
|
518 |
|
519 TInt CHWPort::GetCaps(TDes8& aDes) |
|
520 /** |
|
521 * This gets the supported capabilities from the loopback driver. The actual capabilities of |
|
522 * the driver will vary based on the role the port is playing (DCE or DTE). The loopback driver |
|
523 * supports capabilities via TCommCapsV01 and TCommCapsV02. |
|
524 * |
|
525 * @param aDes - a TDes8 reference to copy the capabilities into. |
|
526 * |
|
527 * @return KErrNone - Everything is okay, KErrNotSupported it the length of the descriptor passed to this method indicates a |
|
528 * capabilities structure which we don't support. |
|
529 */ |
|
530 { |
|
531 LOGTEXT2(_L8("PKTLOOPBACK:GetCaps: Unit %d..."), iPortName); |
|
532 |
|
533 if(aDes.Length()==sizeof(TCommCapsV01)) |
|
534 { |
|
535 TCommCapsV01* commcaps=(TCommCapsV01*)(aDes.Ptr()); |
|
536 // We've got all of these |
|
537 commcaps->iRate=0x3fffff; |
|
538 commcaps->iDataBits=0xf; |
|
539 commcaps->iStopBits=0x3; |
|
540 commcaps->iParity=0x1f; |
|
541 commcaps->iFifo=0x1; |
|
542 commcaps->iHandshake=0; |
|
543 commcaps->iSignals=0x3f; |
|
544 commcaps->iSIR=0x0; |
|
545 return KErrNone; |
|
546 } |
|
547 else if(aDes.Length()==sizeof(TCommCapsV02)) |
|
548 { |
|
549 TCommCapsV02* commcaps=(TCommCapsV02*)(aDes.Ptr()); |
|
550 commcaps->iRate=0x3fffff; |
|
551 commcaps->iDataBits=0xf; |
|
552 commcaps->iStopBits=0x3; |
|
553 commcaps->iParity=0x1f; |
|
554 commcaps->iFifo=0x1; |
|
555 commcaps->iHandshake=0; |
|
556 commcaps->iSignals=0x3f; |
|
557 commcaps->iSIR=0x0; |
|
558 commcaps->iNotificationCaps=0; |
|
559 commcaps->iRoleCaps=0x0; |
|
560 return KErrNone; |
|
561 } |
|
562 else |
|
563 return KErrNotSupported; |
|
564 } |
|
565 |
|
566 TInt CHWPort::SetServerConfig(const TDesC8& /*aDes*/) |
|
567 /** |
|
568 * This sets the current server configuration for the loopback driver. The loopback driver |
|
569 * stores this information but does nothing with it. |
|
570 * |
|
571 * @param aDes - a TDes8 reference to copy the configuration from. |
|
572 * |
|
573 * @return KErrNotSupported |
|
574 */ |
|
575 { |
|
576 LOGTEXT2(_L8("PKTLOOPBACK:SetServerConfig is not supported: Unit %d..."), iPortName); |
|
577 |
|
578 return KErrNotSupported; |
|
579 } |
|
580 |
|
581 TInt CHWPort::GetServerConfig(TDes8& /*aDes*/) |
|
582 /** |
|
583 * This gets the current server configuration for the loopback driver. The loopback driver |
|
584 * stores this information but does nothing with it other than return it here. |
|
585 * |
|
586 * @param aDes - a TDes8 reference to copy the configuration to. |
|
587 * |
|
588 * @return KErrNotSupported |
|
589 */ |
|
590 { |
|
591 LOGTEXT2(_L8("PKTLOOPBACK:GetServerConfig is not supported: Unit %d..."), iPortName); |
|
592 |
|
593 return KErrNotSupported; |
|
594 } |
|
595 |
|
596 TInt CHWPort::GetSignals(TUint& aSignals) |
|
597 /** |
|
598 * This method retrieves the current setting of the signals for THIS port. |
|
599 * |
|
600 * @param aSignals - A reference to a TUint to return the signal settings. |
|
601 * |
|
602 * @return KErrNotSupported |
|
603 */ |
|
604 { |
|
605 LOGTEXT2(_L8("PKTLOOPBACK:GetSignals is not supported: Unit %d..."), iPortName); |
|
606 |
|
607 aSignals = 0; |
|
608 return KErrNotSupported; |
|
609 } |
|
610 |
|
611 TInt CHWPort::SetSignalsToMark(TUint /*aSignals*/) |
|
612 /** |
|
613 * This method asserts the signals specified by the parameter aSignals. |
|
614 * |
|
615 * @param aSignals - a bitmask specifying which signals to assert (See definition |
|
616 * of KSignalDCD, KSignalCTS, etc. for bit values). |
|
617 * |
|
618 * @return KErrNotSupported |
|
619 */ |
|
620 { |
|
621 LOGTEXT2(_L8("PKTLOOPBACK:SetSignalsToMark is not supported: Unit %d..."), iPortName); |
|
622 |
|
623 return KErrNotSupported; |
|
624 } |
|
625 |
|
626 |
|
627 |
|
628 TInt CHWPort::SetSignalsToSpace(TUint /*aSignals*/) |
|
629 /** |
|
630 * This method de-asserts the signals specified by the parameter aSignals. |
|
631 * |
|
632 * @return KErrNotSupported |
|
633 */ |
|
634 { |
|
635 LOGTEXT2(_L8("PKTLOOPBACK:SetSignalsToSpace is not supported: Unit %d..."), iPortName); |
|
636 |
|
637 return KErrNotSupported; |
|
638 } |
|
639 |
|
640 TInt CHWPort::GetReceiveBufferLength(TInt& /*aLength*/) const |
|
641 /** |
|
642 * This method is currently not implemented in the loopback driver. Calling this |
|
643 * method will return an error |
|
644 * |
|
645 * @return KErrNotSupported |
|
646 */ |
|
647 { |
|
648 LOGTEXT2(_L8("PKTLOOPBACK:GetReceiveBufferLength is not supported: Unit %d..."), iPortName); |
|
649 |
|
650 return KErrNotSupported; |
|
651 } |
|
652 |
|
653 TInt CHWPort::SetReceiveBufferLength(TInt /*aLength*/) |
|
654 /** |
|
655 * This method is currently not implemented in the loopback driver. Calling this |
|
656 * method will return an error |
|
657 * |
|
658 * @return KErrNotSupported |
|
659 */ |
|
660 { |
|
661 LOGTEXT2(_L8("PKTLOOPBACK:SetReceiveBufferLength is not supported: Unit %d..."), iPortName); |
|
662 |
|
663 return KErrNotSupported; |
|
664 } |
|
665 |
|
666 void CHWPort::Destruct() |
|
667 /** |
|
668 * This method is simply deletes this instance of the port, comitting sucide. |
|
669 */ |
|
670 { |
|
671 delete this; |
|
672 } |
|
673 |
|
674 |
|
675 |
|
676 void CHWPort::NotifySignalChange(TUint /*aSignalMask*/) |
|
677 /** |
|
678 * This method sets up a request to be notified when a signal change occurs on the specified |
|
679 * signals. Later operations will send a message to the requestor indicating the signal |
|
680 * change. |
|
681 * |
|
682 * @param aSignalMask - the signals that the caller is interested in monitoring. |
|
683 */ |
|
684 { |
|
685 LOGTEXT2(_L8("PKTLOOPBACK:NotifySignalChange is not supported: Unit %d..."), iPortName); |
|
686 } |
|
687 |
|
688 |
|
689 void CHWPort::NotifySignalChangeCancel() |
|
690 /** |
|
691 * This method cancels an outstanding request to be notified when a signal change occurs. Any |
|
692 * outstanding signal change request will be completed with KErrCancel. |
|
693 */ |
|
694 { |
|
695 LOGTEXT2(_L8("PKTLOOPBACK:NotifySignalChangeCancel is not supported: Unit %d..."), iPortName); |
|
696 } |
|
697 |
|
698 |
|
699 void CHWPort::NotifyConfigChange() |
|
700 /** |
|
701 * This method is currently not implemented in the loopback driver. |
|
702 */ |
|
703 { |
|
704 LOGTEXT2(_L8("PKTLOOPBACK:NotifyConfigChange is not supported: Unit %d..."), iPortName); |
|
705 } |
|
706 |
|
707 void CHWPort::NotifyConfigChangeCancel() |
|
708 /** |
|
709 * This method is currently not implemented in the loopback driver. |
|
710 */ |
|
711 { |
|
712 LOGTEXT2(_L8("PKTLOOPBACK:NotifyConfigChangeCancel is not supported: Unit %d..."), iPortName); |
|
713 } |
|
714 |
|
715 void CHWPort::NotifyFlowControlChange() |
|
716 /** |
|
717 * This method is currently not implemented in the loopback driver. |
|
718 */ |
|
719 { |
|
720 LOGTEXT2(_L8("PKTLOOPBACK:NotifyFlowControlChange is not supported: Unit %d..."), iPortName); |
|
721 } |
|
722 |
|
723 void CHWPort::NotifyFlowControlChangeCancel() |
|
724 /** |
|
725 * This method is currently not implemented in the loopback driver. |
|
726 */ |
|
727 { |
|
728 LOGTEXT2(_L8("PKTLOOPBACK:NotifyFlowControlChangeCancel is not supported: Unit %d..."), iPortName); |
|
729 } |
|
730 |
|
731 |
|
732 void CHWPort::NotifyBreak() |
|
733 /** |
|
734 * This method is currently not implemented in the loopback driver. |
|
735 */ |
|
736 { |
|
737 LOGTEXT2(_L8("PKTLOOPBACK:NotifyBreak is not supported: Unit %d..."), iPortName); |
|
738 } |
|
739 |
|
740 void CHWPort::NotifyBreakCancel() |
|
741 /** |
|
742 * This method is currently not implemented in the loopback driver. |
|
743 */ |
|
744 { |
|
745 LOGTEXT2(_L8("PKTLOOPBACK:NotifyBreakCancel is not supported: Unit %d..."), iPortName); |
|
746 } |
|
747 |
|
748 void CHWPort::NotifyDataAvailable() |
|
749 /** |
|
750 * This method is currently not implemented in the loopback driver. |
|
751 */ |
|
752 { |
|
753 LOGTEXT2(_L8("PKTLOOPBACK:NotifyDataAvailable is not supported: Unit %d..."), iPortName); |
|
754 } |
|
755 |
|
756 void CHWPort::NotifyDataAvailableCancel() |
|
757 /** |
|
758 * This method is currently not implemented in the loopback driver. |
|
759 */ |
|
760 { |
|
761 LOGTEXT2(_L8("PKTLOOPBACK:NotifyDataAvailableCancel is not supported: Unit %d..."), iPortName); |
|
762 } |
|
763 |
|
764 void CHWPort::NotifyOutputEmpty() |
|
765 /** |
|
766 * This method is currently not implemented in the loopback driver. |
|
767 */ |
|
768 { |
|
769 LOGTEXT2(_L8("PKTLOOPBACK:NotifyOutputEmpty is not supported: Unit %d..."), iPortName); |
|
770 } |
|
771 |
|
772 void CHWPort::NotifyOutputEmptyCancel() |
|
773 /** |
|
774 * This method is currently not implemented in the loopback driver. |
|
775 */ |
|
776 { |
|
777 LOGTEXT2(_L8("PKTLOOPBACK:NotifyOutputEmptyCancel is not supported: Unit %d..."), iPortName); |
|
778 } |
|
779 |
|
780 TInt CHWPort::GetFlowControlStatus(TFlowControl& /* aFlowControl */) |
|
781 /** |
|
782 * This method is currently not implemented in the loopback driver. |
|
783 * |
|
784 * @return KErrNotSupported |
|
785 */ |
|
786 { |
|
787 LOGTEXT2(_L8("PKTLOOPBACK:GetFlowControlStatus is not supported: Unit %d..."), iPortName); |
|
788 |
|
789 return KErrNotSupported; |
|
790 } |
|
791 |
|
792 TInt CHWPort::GetRole(TCommRole& aRole) |
|
793 /** |
|
794 * This method returns the current Role that this port is playing (ECommRoleDCE or ECommRoleDTE) |
|
795 * |
|
796 * @param aRole - a reference to a TCommRole to return the role value in. |
|
797 * |
|
798 * @return KErrNone |
|
799 */ |
|
800 { |
|
801 LOGTEXT3(_L8("PKTLOOPBACK:GetRole: Unit %d, aRole %d..."), iPortName, aRole); |
|
802 |
|
803 aRole = iRole; |
|
804 return KErrNone; |
|
805 } |
|
806 |
|
807 TInt CHWPort::SetRole(TCommRole aRole) |
|
808 /** |
|
809 * This method sets the role of the port. Additionally, it sets the default state of the |
|
810 * signals for this type of port. This is the first place where signals are set as a port |
|
811 * is opening. The ports will assert their output signals with the exception of DCD (which |
|
812 * is an output signal from the DCE). DCD is left to be driven by the test harness. |
|
813 * |
|
814 * A test could be put into place to insure that each port is in a different role. This was |
|
815 * not done at this time for backwards compatibility reasons. |
|
816 * |
|
817 * @param aRole - the TCommRole value that this port should be set to. |
|
818 * |
|
819 * @return KErrNone |
|
820 */ |
|
821 { |
|
822 LOGTEXT3(_L8("PKTLOOPBACK:SetRole: Unit %d, aRole %d..."), iPortName, aRole); |
|
823 |
|
824 if (ECommRoleDTE == aRole) |
|
825 { |
|
826 SetSignalsToMark(KSignalDTR|KSignalRTS); |
|
827 } |
|
828 else // DCE |
|
829 { |
|
830 SetSignalsToMark(KSignalDSR|KSignalCTS); |
|
831 } |
|
832 |
|
833 |
|
834 // Informational test only. This will produce output to the log file if both sides have the |
|
835 // same role set. With both sides having the same role, none of the signal handling will |
|
836 // function properly. |
|
837 #if defined (_DEBUG) |
|
838 if (iLoopbackPort) |
|
839 { |
|
840 TCommRole otherSide; |
|
841 iLoopbackPort->GetRole(otherSide); |
|
842 if (otherSide == aRole) |
|
843 LOGTEXT3(_L8("PKTLOOPBACK:SetRole: Unit %d...Both sides same role %d"), iPortName, aRole); |
|
844 } |
|
845 #endif |
|
846 |
|
847 iRole = aRole; |
|
848 return KErrNone; |
|
849 } |
|
850 |
|
851 CHWPort::~CHWPort() |
|
852 /** |
|
853 * This method is the standard destructor for the port. It deletes the buffer |
|
854 * which was allocated to the port and resets the loopback port pointer to NULL. |
|
855 */ |
|
856 { |
|
857 delete iFlowControlChange; |
|
858 iFlowControlChange = NULL; |
|
859 |
|
860 delete iReadWriteQueue; |
|
861 iReadWriteQueue = NULL; |
|
862 |
|
863 delete iWriteDelayTimer; |
|
864 iWriteDelayTimer = NULL; |
|
865 |
|
866 if(iLoopbackPort) |
|
867 { |
|
868 iLoopbackPort->SetLoopbackPort(NULL); |
|
869 iLoopbackPort->iWriteDelayTimer->Cancel(); |
|
870 } |
|
871 |
|
872 ((CHWPortFactory*)Owner())->Remove(this); |
|
873 } |
|
874 |
|
875 void CHWPort::FreeMemory() |
|
876 /** |
|
877 * This method is currently not implemented in the loopback driver. |
|
878 */ |
|
879 {} |
|
880 |
|
881 CHWPort* CHWPortFactory::FindPort(TUint aUnit) |
|
882 /** |
|
883 * Returns the port corresponding to the unit aUnit |
|
884 * |
|
885 * @param aUnit The port number for the port object to find |
|
886 * |
|
887 * @return The port object corresponding to unit aUnit |
|
888 */ |
|
889 { |
|
890 for (TInt i = 0; i < iPorts.Count(); i++) |
|
891 { |
|
892 if (iPorts[i]->PortName() == aUnit) |
|
893 return iPorts[i]; |
|
894 } |
|
895 return NULL; |
|
896 } |
|
897 |
|
898 CPort* CHWPortFactory::NewPortL(const TUint aUnit) |
|
899 /** |
|
900 * This method creates a new port object. It identifies the new object with the unit number that |
|
901 * is supplied. If both ports that are supported by the CHWPortFactory object have been created, |
|
902 * then the loopback ports are initialized. |
|
903 * |
|
904 * @param aUnit - The unit number to create. |
|
905 * |
|
906 * @return CPort * - A pointer to the newly created object. |
|
907 */ |
|
908 { |
|
909 LOGTEXT2(_L8("PKTLOOPBACK:NewPortL: Unit %d"), aUnit); |
|
910 |
|
911 // Get the settings for the given port. The iLoopbackConfig will look at the test's ini file for this information |
|
912 TLoopbackConfigItem portSettings; |
|
913 if (iLoopbackConfig) |
|
914 { |
|
915 if (iLoopbackConfig->GetPortSettings(aUnit, portSettings) != KErrNone) |
|
916 User::Leave(KErrNotFound); |
|
917 } |
|
918 else |
|
919 { |
|
920 User::Leave(KErrNotFound); |
|
921 } |
|
922 |
|
923 // If the port already exists, just return it |
|
924 CHWPort *existingPort = FindPort(aUnit); |
|
925 if (existingPort) |
|
926 { |
|
927 LOGTEXT2(_L8("Loopback:NewPortL: Unit %d already exists! @%x"), aUnit); |
|
928 return existingPort; |
|
929 } |
|
930 // Create the port and add it to the list of ports |
|
931 CHWPort *newPort; |
|
932 if (iLoopbackConfig->PortType() == ESerialLoopbackPortType) |
|
933 { |
|
934 newPort = CHWPort::NewSerialLoopbackL(aUnit, portSettings.iDelay, portSettings.iBufferSize); |
|
935 } |
|
936 else |
|
937 { |
|
938 newPort = CHWPort::NewPacketLoopbackL(aUnit, portSettings.iDelay, portSettings.iPacketLength, portSettings.iQueueLength); |
|
939 } |
|
940 CleanupStack::PushL(newPort); |
|
941 iPorts.AppendL(newPort); |
|
942 CleanupStack::Pop(newPort); |
|
943 |
|
944 // Get the name of the opposite loopback port |
|
945 TUint oppositePortName; |
|
946 if (portSettings.iPortA == aUnit) |
|
947 oppositePortName = portSettings.iPortB; |
|
948 else |
|
949 oppositePortName = portSettings.iPortA; |
|
950 |
|
951 // If the opposite loopback port is open, set it as the current port's loopback |
|
952 CHWPort *oppositePort = FindPort(oppositePortName); |
|
953 if (oppositePort) |
|
954 { |
|
955 oppositePort->SetLoopbackPort(newPort); |
|
956 newPort->SetLoopbackPort(oppositePort); |
|
957 } |
|
958 return newPort; |
|
959 } |
|
960 |
|
961 void CHWPortFactory::Info(TSerialInfo &aSerialInfo) |
|
962 /** |
|
963 * This method fills information into the passed structure. It is required for factory objects. |
|
964 * |
|
965 * @param aSerialInfo - a reference to the structure to fill in. |
|
966 */ |
|
967 { |
|
968 aSerialInfo.iDescription = KSerialDescription; |
|
969 aSerialInfo.iName = KSerialName; |
|
970 aSerialInfo.iLowUnit = KCommLowUnit; |
|
971 aSerialInfo.iHighUnit = KCommHighUnit; |
|
972 } |
|
973 |
|
974 CHWPortFactory::CHWPortFactory() |
|
975 /** |
|
976 * This method is the constructor for the factory object. |
|
977 * We initialize iPorts to contain the number of ports from KMinLoopBackPort to KMaxLoopBackPort |
|
978 */ |
|
979 { |
|
980 TName name(KSerialName); |
|
981 SetName(&name); |
|
982 iVersion = TVersion(KEC32MajorVersionNumber,KEC32MinorVersionNumber,KEC32BuildVersionNumber); |
|
983 |
|
984 // Create the object to read the loopback port settings for this test |
|
985 TRAP_IGNORE(iLoopbackConfig = CLoopbackConfig::NewL()); |
|
986 } |
|
987 |
|
988 void CHWPortFactory::Remove(CHWPort* aPort) |
|
989 /** |
|
990 * This method removes an instance of the CHWPort from the factory package CHWPortFactory. |
|
991 * The object is not deleted. |
|
992 * |
|
993 * @param aPort - The pointer to the CHWPort pointer to be removed from the factory object. |
|
994 * |
|
995 * @note If the passed in value does not match a current port, this method will panic. |
|
996 */ |
|
997 { |
|
998 LOGTEXT2(_L8("PKTLOOPBACK:Remove: Port %d"), aPort->PortName()); |
|
999 for (TInt i = 0; i < iPorts.Count(); i++) |
|
1000 { |
|
1001 if(iPorts[i] == aPort) |
|
1002 { |
|
1003 iPorts.Remove(i); |
|
1004 return; |
|
1005 } |
|
1006 } |
|
1007 User::Panic(_L("CHWPortFactory: Port not found"),0); |
|
1008 } |
|
1009 |
|
1010 CHWPortFactory::~CHWPortFactory() |
|
1011 /** |
|
1012 * This method is the destructor for the factory object. |
|
1013 */ |
|
1014 { |
|
1015 delete iLoopbackConfig; |
|
1016 iLoopbackConfig = NULL; |
|
1017 LOGDESTROY(); |
|
1018 } |
|
1019 |
|
1020 /** |
|
1021 Returns capabilities for requested port |
|
1022 */ |
|
1023 TSecurityPolicy CHWPortFactory::PortPlatSecCapability(TUint /*aPort*/) const |
|
1024 { |
|
1025 return TSecurityPolicy(TSecurityPolicy::EAlwaysPass); |
|
1026 } |
|
1027 |
|
1028 extern "C" |
|
1029 { |
|
1030 IMPORT_C CSerial * LibEntry(void); // Force export |
|
1031 |
|
1032 EXPORT_C CSerial * LibEntry(void) |
|
1033 /** |
|
1034 * This method is the library's main entry point. It simply new's the factory object. |
|
1035 */ |
|
1036 { |
|
1037 return new CHWPortFactory; |
|
1038 } |
|
1039 |
|
1040 } // extern "C" |
|
1041 |
|
1042 |