serialserver/packetloopbackcsy/src/loopback.cpp
changeset 0 dfb7c4ff071f
child 4 928ed51ddc43
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     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