os/kernelhwsrv/kerneltest/e32test/ethernet/pump/etherpump.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1996-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 the License "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 // e32test\ethernet\etherpump.cpp
    15 // Abbreviations - PSP (Professional Symbian Programming)
    16 // 
    17 //
    18 
    19 #define __USE_LDDPDD__
    20 #define __USE_TIMER__
    21 
    22 #include <e32base.h>
    23 #include <e32base_private.h>
    24 #include <e32cons.h>
    25 #include <e32svr.h>
    26 
    27 #include <d32ethernet.h>
    28 
    29 #include "activeio.h"
    30 
    31 #define LDD_NAME _L("Enet")
    32 #if (!defined __WINS__)
    33 #define PDD_NAME _L("Ethernet")
    34 #else
    35 
    36 //#define PDD_NAME _L("EthernetWins")
    37 #define PDD_NAME _L("Ethernet")
    38 #endif
    39 
    40 
    41 // changed from const to static
    42 //const TUint8 DestMacAddr[] = {0x00,0x50,0xDA,0xE9,0x69,0xCA};
    43 
    44 // MAC address with second bit 1
    45 static TUint8 DestMacAddr[] = {0x02,0xB0,0xD0,0x64,0x98,0x02};
    46 
    47 
    48 // for random functions
    49 #include <e32math.h>
    50 
    51 
    52 void StripeMem(TUint8 *aBuf, TInt aStartPos, TInt anEndPos, TUint aStartChar, TUint anEndChar, TInt aOffset)
    53 //
    54 // Mark a buffer with repeating byte pattern
    55 //
    56     {
    57     TUint character=aStartChar+(aOffset%((anEndChar+1)-aStartChar));
    58 
    59     for (TInt i=aStartPos;i<anEndPos;i++)
    60 	{
    61 	aBuf[i]=(TText8)character;
    62 	if(++character>anEndChar)
    63 	    character=aStartChar;
    64 	}
    65     }
    66 
    67 void StripeDes(TDes8 &aBuf, TInt aStartPos, TInt anEndPos, TUint aStartChar, TUint anEndChar, TInt aOffset)
    68     {
    69     StripeMem((TUint8 *)aBuf.Ptr(), aStartPos, anEndPos, aStartChar, anEndChar, aOffset);
    70     }
    71 
    72 TBool CheckMem(TUint8 *aBuf, TInt aStartPos, TInt anEndPos, TUint aStartChar, TUint anEndChar, TInt aOffset)
    73 //
    74 // Mark a buffer with repeating byte pattern
    75 //
    76     {
    77     TUint character=aStartChar+(aOffset%((anEndChar+1)-aStartChar));
    78 
    79     for (TInt i=aStartPos;i<anEndPos;i++)
    80 	{
    81 	if (aBuf[i]!=(TText8)character)
    82 	    return EFalse;
    83 	if(++character>anEndChar)
    84 	    character=aStartChar;
    85 	}
    86     return ETrue;
    87     }
    88 
    89 TBool CheckDes(TDes8 &aBuf, TInt aStartPos, TInt anEndPos, TUint aStartChar, TUint anEndChar, TInt aOffset)
    90     {
    91     return CheckMem((TUint8 *)aBuf.Ptr(), aStartPos, anEndPos, aStartChar, anEndChar, aOffset);
    92     }
    93 
    94 
    95 void StripeMem32(TUint *aBuf, TInt aStartPos, TInt aEndPos)
    96 //
    97 // Mark a buffer with repeating byte pattern
    98 //
    99     {
   100     aStartPos >>= 2;
   101     aEndPos >>= 2;
   102 	
   103     for (TInt i=aStartPos;i<aEndPos;i++)
   104 	{
   105 	aBuf[i]=i<<2;
   106 	}
   107     }
   108 
   109 void StripeDes32(TDes8 &aBuf, TInt aStartPos, TInt anEndPos)
   110     {
   111     StripeMem32((TUint*)aBuf.Ptr(), aStartPos, anEndPos);
   112     }
   113 
   114 // Standard Epoc32 Library Console class
   115 static CConsoleBase* console;
   116 
   117 
   118 // xxxLC means method can Leave and has pushed something on the Cleanup stack
   119 // Caller is responsible for popping it.
   120 CDemoControl* CDemoControl::NewLC()
   121     {
   122     CDemoControl* self = new (ELeave) CDemoControl(EPriorityNormal);
   123     CleanupStack::PushL(self);
   124     self->ConstructL();
   125     return self;
   126     }
   127 TInt CDemoControl::Callback(TAny* aControl)
   128 // Callback function for timer expiry
   129 // Just pump another packet at the server
   130 // It's a static so call a class member to access private data
   131     {
   132     CIOBuffer* buf = ((CDemoControl*)aControl)->CreateSendPacketL();
   133 
   134     ((CDemoControl*)aControl)->iWriteQueue.AddLast(*buf);
   135     ((CDemoControl*)aControl)->iWriter->WriteL(buf->Ptr());
   136 
   137     return KErrNone;
   138     }
   139 
   140 
   141 void CDemoControl::ConstructL()
   142 // Second Phase construction
   143     {
   144     // Add us to the Active Scheduler for the thread
   145     CActiveScheduler::Add(this);
   146     // Create the Read and Write Active Objects
   147     // The 'this' pointer is the MxxxNotify callback interface that CDemoControl is derived from
   148     // Pass a reference to the Server session so they can make read and write requests
   149 
   150     iWriter = CDemoWriter::NewL(*this,iCard);
   151     iReader = CDemoReader::NewL(*this,iCard);
   152 
   153     User::LoadPhysicalDevice(PDD_NAME);
   154     User::LoadLogicalDevice(LDD_NAME);
   155 
   156 #if (defined __USE_TIMER__)
   157     iIfState = EIdle;
   158     iTimer = CPeriodic::NewL(EPriorityNormal);
   159 #endif
   160 
   161     iWriteQueue.SetOffset(CIOBuffer::LinkOffset());
   162 
   163     HelpText();
   164 
   165     }
   166 
   167 void CDemoControl::EmptyWriteQueue()
   168     {
   169     TSglQueIter<CIOBuffer> iter(iWriteQueue);
   170     CIOBuffer* buf;
   171     while (buf = iter++, buf!=NULL)
   172 	{
   173 	iWriteQueue.Remove(*buf);
   174 	delete buf;
   175 	}
   176     }
   177 
   178 CDemoControl::~CDemoControl()
   179     {
   180     // Cancel this classes read request to the Console
   181     Cancel();
   182     if(iIfState != EIdle)
   183 	{
   184 	EmptyWriteQueue();
   185 	StopCard();
   186 	}
   187 
   188     User::FreeLogicalDevice(LDD_NAME);
   189     User::FreePhysicalDevice(PDD_NAME);
   190 
   191 
   192 #if (defined __USE_TIMER__)
   193     iTimer->Cancel();
   194     delete iTimer;
   195 #endif
   196 
   197     delete iWriter;
   198     delete iReader;
   199     }
   200 
   201 void CDemoControl::RequestCharacter()
   202 // Request a character from the CConsoleBase class and set us to Active
   203     {
   204     // Read() will result in our iStatus being set to KRequestPending 0x80000001
   205     console->Read(iStatus);
   206     // SetActive sets our iActive to ETrue
   207     SetActive();
   208     }
   209 
   210 void CDemoControl::RunL()
   211 // Mandatory override of pure virtual called from active scheduler Start()
   212 // Key method called when the Active Scheduler semaphore is
   213 // signalled and the iStatus has been completed for this Active Object
   214     {
   215     ProcessKeyPress(TChar(console->KeyCode()));
   216     RequestCharacter();
   217     // We now return control to the scheduler loop
   218     }
   219 
   220 void CDemoControl::DoCancel()
   221 // Mandatory override of pure virtual, called from Cancel()
   222     {
   223     // Cancels an outstanding request to the console
   224     console->ReadCancel();
   225     }
   226 
   227 static const TUint KEscChar = 0x1b;
   228 void CDemoControl::ProcessKeyPress(TChar aChar)
   229 // Process commands from the console
   230 // Executes in the context of the class RunL()
   231     {
   232     TInt err = KErrNone;
   233     if(aChar == KEscChar)
   234 	{
   235 	// Modifies loop control flag value so the scheduler loop exits
   236 	CActiveScheduler::Stop();
   237 	}
   238     else if(aChar == 'h' || aChar == 'H')
   239 	{
   240 	HelpText();
   241 	}
   242     else
   243 	{
   244 	// Add Command Handler Methods here
   245 	switch(aChar)
   246 	    {
   247 	    case 'p'	:
   248 	    case 'P'	:
   249 		TRAP(err,PumpL());
   250 		break;
   251 	    case 'e'	:
   252 	    case 'E'	:
   253 		TRAP(err,EchoL());
   254 		break;
   255 	    case 'r'	:
   256 	    case 'R'	:
   257 		TRAP(err,ReadL());
   258 		break;
   259 	    case 's'	:
   260 	    case 'S'	:
   261 		TRAP(err,StopL());
   262 		break;
   263 		case 'c'	:
   264 		case 'C'	:
   265 		TRAP(err,SendAndCompareEchoL());
   266 		break;
   267 		case 'd'	:
   268 		case 'D'	:
   269 		TRAP(err,ReadAndSetDestMacL());
   270 		break;
   271 		case 'm'	:
   272 		case 'M'	:
   273 			ReadAndDisplaySettings();
   274 		break;				
   275 	    default		:
   276 		break;
   277 	    }
   278 
   279 	if(err != KErrNone)
   280 	    {
   281 	    PrintError(aChar);
   282 	    }
   283 	else
   284 	    {
   285 	    _LIT(KMess,"State = %d\r\n");
   286 	    console->ClearScreen();
   287 	    console->SetPos(0,0);
   288 	    console->Printf(KMess,iIfState);
   289 	    }
   290 	}
   291     }
   292 
   293 void CDemoControl::HelpText() const
   294     {
   295 	_LIT(KMess,"Press 'Esc' to exit \r\nPress 'H' for Help \r\nPress 'P' for Data Pump \r\nPress 'E' for Echo \r\nPress 'R' for Read \r\nPress 'C' for send and Compare echo \r\nPress 'D' to set dest MAC\r\nPress 'M' to display Settings\r\nPress 'S' to Stop");
   296 	console->ClearScreen();
   297     console->SetPos(0,5);
   298     console->Printf(KMess);
   299     }
   300 
   301 void CDemoControl::PrintError(TChar aChar)
   302     {
   303     //_LIT(KMess,"Command Error = %c State = %d\r\n1 = Idle\r\n2 = Echo\r\n3 = Read\r\n4 = Pump");
   304 	_LIT(KMess,"Command Error = %c State = %d\r\n0 = Idle\r\n1 = Echo\r\n2 = Read\r\n3 = Pump\r\n4 = send & Compare echo");
   305 	console->ClearScreen();
   306     console->SetPos(0,5);
   307     console->Printf(KMess,(char)aChar,iIfState);	
   308     }
   309 
   310 void CDemoControl::EchoL()
   311     {
   312     if(iIfState != EIdle)
   313 	{
   314 	User::Leave(KErrInUse);
   315 	}
   316     StartCardL();
   317 
   318     iReadBuffer.SetMax();
   319     iReadBuffer.FillZ();
   320     iReader->ReadL(iReadBuffer);
   321 
   322     iIfState = EEcho;
   323     }
   324 
   325 void CDemoControl::PumpL()
   326     {
   327     console->ClearScreen();
   328 
   329     if(iIfState != EIdle)
   330 	{
   331 	User::Leave(KErrInUse);
   332 	}
   333 #if (defined __USE_TIMER__)
   334     iTimer->Start(0,1,TCallBack(Callback,this));
   335 #endif
   336     StartCardL();
   337 	
   338     iReadBuffer.SetMax();
   339     iReadBuffer.FillZ();
   340     iReader->ReadL(iReadBuffer);
   341 
   342 #if (!defined __USE_TIMER__)
   343     CIOBuffer* buf = CreateSendPacketL();
   344 
   345     iWriteQueue.AddLast(*buf);
   346     iWriter->WriteL(buf->Ptr());
   347 #endif
   348 
   349     iIfState = EPump;
   350     }
   351 
   352 void CDemoControl::ReadAndDisplaySettings()
   353 //
   354 // Read and display the current config
   355 //
   356     {
   357     TBuf8<32> config;
   358 
   359     User::LeaveIfError(iCard.Open(0));
   360     User::After(2000);
   361 
   362     // MAC Address starts at the 4th byte
   363     config.SetMax();
   364     iCard.Config(config);
   365 
   366 
   367     console->Printf(_L("\n\nEthernet Speed :"));
   368     switch (config[0])
   369 	{
   370 	case KEthSpeedUnknown:
   371 	    console->Printf(_L(" Unknown\n"));
   372 	    break;
   373 	case KEthSpeedAuto:
   374 	    console->Printf(_L(" Auto\n"));
   375 	    break;
   376 	case KEthSpeed10BaseT:
   377 	    console->Printf(_L(" 10 MBit\n"));
   378 	    break;
   379 	case KEthSpeed100BaseTX:
   380 	    console->Printf(_L(" 100 MBit\n"));
   381 	    break;
   382 	default:
   383 	    console->Printf(_L(" ERROR\n"));
   384 	}
   385 
   386     console->Printf(_L("Duplex Setting :"));
   387     switch (config[1])
   388 	{
   389 	case KEthDuplexUnknown:
   390 	    console->Printf(_L(" Unknown\n"));
   391 	    break;
   392 	case KEthDuplexAuto:
   393 	    console->Printf(_L(" Auto\n"));
   394 	    break;
   395 	case KEthDuplexFull:
   396 	    console->Printf(_L(" Full\n"));
   397 	    break;
   398 	case KEthDuplexHalf:
   399 	    console->Printf(_L(" Half\n"));
   400 	    break;
   401 	default:
   402 	    console->Printf(_L(" ERROR\n"));
   403 	}
   404 
   405     console->Printf(_L("MAC :"));
   406     console->Printf(_L(" %2x:%2x:%2x:%2x:%2x:%2x\n\n"),
   407 		 config[2], config[3],
   408 		 config[4], config[5],
   409 		 config[6], config[7]);
   410 
   411 	console->Printf(_L("\nPress any key to continue..\n") );
   412 
   413 	console->Getch();
   414 
   415 	iCard.Close();
   416     }
   417 
   418 
   419 CIOBuffer* CDemoControl::CreateSendPacketL()
   420     {
   421     CIOBuffer* buf = CIOBuffer::NewL(1500);
   422     // Copy in the Destination mac address
   423     buf->Ptr().SetLength(6);
   424     buf->Ptr().Copy(DestMacAddr,6);
   425 
   426     // Copy in the source mac address read from the driver
   427     //buf->Ptr().Append(&iConfig[3],6);
   428 	buf->Ptr().Append(&iConfig[2],6);
   429 	
   430     // EtherII framing
   431     buf->Ptr().Append(0x08);
   432     buf->Ptr().Append(0x06);
   433     buf->Ptr().SetMax();
   434     StripeDes(buf->Ptr(), 14, buf->Ptr().Length(), '@', 'Z',0);
   435     return buf;
   436     }
   437 
   438 void CDemoControl::ReadL()
   439     {
   440     if(iIfState != EIdle)
   441 	{
   442 	User::Leave(KErrInUse);
   443 	}
   444 	
   445     StartCardL();
   446 	
   447     iReadBuffer.SetMax();
   448     iReadBuffer.FillZ();
   449     iReader->ReadL(iReadBuffer);
   450 
   451     iIfState = ERead;
   452     }
   453 
   454 
   455 
   456 
   457 CIOBuffer* CDemoControl::CreateRandomPacketL(TInt aOffset)
   458 	{
   459 	CIOBuffer* buf = CIOBuffer::NewL(1500);
   460 	// Copy in the Destination mac address
   461 	buf->Ptr().SetLength(6);
   462 	buf->Ptr().Copy(DestMacAddr,6);
   463 #if (defined __USE_LDDPDD__)
   464 	// Copy in the source mac address read from the driver
   465 	//buf->Ptr().Append(&iConfig[3],6);
   466 	buf->Ptr().Append(&iConfig[2],6);
   467 #else
   468 	buf->Ptr().Append(DummyMac,6);
   469 #endif
   470 	// EtherII framing
   471 	buf->Ptr().Append(0x08);
   472 	buf->Ptr().Append(0x06);
   473 	buf->Ptr().SetMax();
   474 	
   475 	StripeDes(buf->Ptr(), 14, buf->Ptr().Length(), '@', 'Z',aOffset);
   476 	return buf;
   477 }
   478 
   479 
   480 TInt CDemoControl::iSendAndEchoCmpCounter = 0;
   481 
   482 void CDemoControl::CompareEcho()
   483 {
   484 	iSendAndEchoSame = 
   485 		CheckDes(iReadBuffer, 14, /*iReadBuffer.Length() - 4*/ 1500 - 4, '@', 'Z', iIntRandomOffset);
   486 										// - 4 for trailer
   487 	console->Printf(_L("\r\nSent & Received Random Packet no: %d \r\n"), iSendAndEchoCmpCounter );
   488 	
   489 	if( iSendAndEchoSame )
   490 		console->Printf( _L("Echo Same: TRUE \r\n") );
   491 	else
   492 		console->Printf( _L("Echo Same: FALSE \r\n") );
   493 	
   494 
   495 }
   496 
   497 void CDemoControl::SendAndCompareEchoL()
   498 {
   499 	if(iIfState != EIdle)
   500 		{
   501 		User::Leave(KErrInUse);
   502 		}
   503 
   504 	iSendAndEchoSame = EFalse;
   505 
   506 	StartCardL();
   507 	
   508 	// empty write buffer before start - nothing else should write 
   509 	// when iIfState = ESendAndCmpEcho
   510 	EmptyWriteQueue();
   511 	
   512 	iIfState = ESendAndCmpEcho;
   513 
   514 	// time for generating seed for rand function
   515 	TTime time;
   516 	time.HomeTime(); 
   517 
   518 	// change seed after 10 frames sent
   519 	if( 0 == (iSendAndEchoCmpCounter % 10) )
   520 	{
   521 		iIntSeed = time.Int64();
   522 	}
   523 
   524 	iIntRandomOffset = Math::Rand( iIntSeed );
   525 
   526 	CIOBuffer* buf = CreateRandomPacketL( iIntRandomOffset );
   527 	
   528 	iWriteQueue.AddLast(*buf);
   529 	iWriter->WriteL(buf->Ptr());
   530 }
   531 
   532 void CDemoControl::HandleWriteCompleteSndCmpEchoModeL()
   533 {
   534 	
   535 	CIOBuffer* buf = iWriteQueue.First();
   536 	iWriteQueue.Remove(*buf);
   537 	delete buf;
   538 
   539 	iSendAndEchoCmpCounter = ++iSendAndEchoCmpCounter;
   540 		
   541 	// empty read buffer
   542 	iReadBuffer.SetMax();
   543 	iReadBuffer.FillZ();	
   544 	// read echo
   545 	iReader->ReadL(iReadBuffer);
   546 }
   547 
   548 void CDemoControl::HandleReadCompleteSndCmpEchoModeL()
   549 {
   550 	CompareEcho();
   551 
   552 	// empty read buffer
   553 	iReadBuffer.SetMax();
   554     iReadBuffer.FillZ();
   555 
   556 //	iIfState = EIdle;
   557 }
   558 
   559 void CDemoControl::ReadAndSetDestMacL()
   560 {
   561 	
   562 	TUint8 upper=0;
   563 	TInt i =0;
   564 	//TInt consPos = 0;
   565 	TChar c;
   566 	TInt pos; 
   567 	TUint8 value;
   568 
   569 	TBuf<20> validChars(_L("0123456789abcdef"));
   570 
   571 	TUint8 newDestMacAddr[] = {0x00,0x00,0x00,0x00,0x00,0x00};
   572 
   573 	_LIT(KMess,"Type new dest MAC (12 hexagonal digits):\r\n");
   574 	console->ClearScreen();
   575 	console->SetPos(0,0);
   576 	console->Printf(KMess,iIfState);
   577 
   578 	for(i = 0; i < 12; i++)
   579 	{
   580 		c = console->Getch();
   581 		c.LowerCase();
   582 		if((pos = validChars.Locate(c))==KErrNotFound)
   583 		    {
   584 		    //pos = upper;
   585 			User::Leave(KErrNotFound); 
   586 		    //break;
   587 		    }
   588 		console->SetPos(i, 1);
   589 		console->Printf(_L("%c"), (char)c);
   590 		if(i%2)
   591 		{
   592 			upper = newDestMacAddr[i / 2];
   593 			value = (TUint8)pos;
   594 			//value = (TUint8)((upper<<4) | value);
   595 			newDestMacAddr[i / 2] = (TUint8)((upper<<4) | value);
   596 		}
   597 		else
   598 			newDestMacAddr[i / 2] = (TUint8)pos;
   599 		
   600 	}
   601 
   602 	for(i = 0; i < 6; i++)
   603 		DestMacAddr[i] = newDestMacAddr[i];
   604 
   605 	console->Printf(_L("\nSetting MAC to %2x:%2x:%2x:%2x:%2x:%2x\n"),
   606 			 DestMacAddr[0], DestMacAddr[1], DestMacAddr[2],
   607 			 DestMacAddr[3], DestMacAddr[4], DestMacAddr[5]);
   608 
   609 	console->Printf(_L("\nPress any key to continue..\n") );
   610 
   611 	console->Getch();
   612 
   613    return; 
   614 }
   615 
   616 //-jk
   617 
   618 void CDemoControl::StopL()
   619     {
   620     if(iIfState == EIdle)
   621 		{
   622 		User::Leave(KErrInUse);
   623 		}
   624 
   625     EmptyWriteQueue();
   626 #if (defined __USE_TIMER__)
   627     if(iIfState == EPump)
   628 	{
   629 		iTimer->Cancel();
   630 		_LIT(KMess,"\r\nPackets Pumped = %d\r\n");
   631 		console->Printf(KMess,iPacketsWritten);
   632 		console->Printf(_L("\r\nPress any key to continue..\r\n") );
   633 		console->Getch();
   634 	}
   635 #endif
   636     StopCard();
   637 
   638     iIfState = EIdle;
   639     }
   640 
   641 void CDemoControl::StartCardL()
   642     {
   643 //	User::LeaveIfError(iCard.Open(iCard.VersionRequired(),0,NULL));
   644     User::LeaveIfError(iCard.Open(0));
   645     User::After(2000000);
   646 //	TBuf8<8> ioctlBuf;
   647 //	ioctlBuf.SetLength(1);
   648 //	ioctlBuf[0] = KIoControlGetStatus;
   649 //	TRequestStatus status;
   650 //	iCard.IOControl(iStatus,ioctlBuf);
   651 //	User::WaitForRequest(status);
   652 //	if(ioctlBuf[0] != KEventPCCardReady)
   653 //		{
   654 //		iCard.Close();
   655 //		User::Leave(KErrNotReady);
   656 //		}
   657     // MAC Address starts at the 2nd byte
   658     iConfig.SetMax();
   659     iCard.Config(iConfig);
   660 
   661     iPacketsRead = 0;
   662     iPacketsWritten = 0;
   663     console->ClearScreen();
   664     }
   665 
   666 void CDemoControl::StopCard()
   667     {
   668 	
   669     iCard.ReadCancel();
   670     iCard.WriteCancel();
   671     iWriter->Cancel();
   672     iReader->Cancel();
   673 	
   674     iCard.Close();
   675 		
   676     }
   677 
   678 void CDemoControl::ReadCompleteL(const TInt aStatus)
   679 // Read completed by the server
   680     {
   681     iPacketsRead++;
   682     console->SetPos(0,1);
   683     _LIT(KMess,"Read  Complete Status = %d Packets Read    = %d\r\n");
   684     console->Printf(KMess,aStatus,iPacketsRead);
   685 	RDebug::Print(KMess,aStatus,iPacketsRead);
   686     // Validate the received buffer with what we sent
   687 
   688     switch(iIfState)
   689 	{
   690 	case EPump:
   691 	    HandleReadCompletePumpModeL();
   692 	    break;
   693 
   694 	case EEcho:
   695 	    HandleReadCompleteEchoModeL();
   696 	    break;
   697 		
   698 	case ERead:
   699 	    HandleReadCompleteReadModeL();
   700 	    break;
   701 
   702 	case ESendAndCmpEcho:
   703 		HandleReadCompleteSndCmpEchoModeL();
   704 		break;
   705 		
   706 	default:
   707 	    break;
   708 	}
   709     iReadBuffer.SetMax();
   710     iReadBuffer.FillZ();
   711     iReader->ReadL(iReadBuffer);
   712     }
   713 
   714 void CDemoControl::WriteCompleteL(const TInt aStatus)
   715 // Write completed by the server
   716     {
   717     iPacketsWritten++;
   718     console->SetPos(0,0);
   719     _LIT(KMess,"Write Complete Status = %d Packets Written = %d\r\n");
   720     console->Printf(KMess,aStatus,iPacketsWritten);
   721 
   722     switch(iIfState)
   723 	{
   724 	case EPump:
   725 	    HandleWriteCompletePumpModeL();
   726 	    break;
   727 
   728 	case EEcho:
   729 	    HandleWriteCompleteEchoModeL();
   730 	    break;
   731 
   732 	case ESendAndCmpEcho:
   733 			HandleWriteCompleteSndCmpEchoModeL();
   734 			break;
   735 	
   736 	default:
   737 	    break;
   738 	}
   739     }
   740 
   741 void CDemoControl::HandleWriteCompleteEchoModeL()
   742     {
   743     CIOBuffer* buf = iWriteQueue.First();
   744     iWriteQueue.Remove(*buf);
   745     delete buf;
   746     if(!iWriteQueue.IsEmpty())
   747 	{
   748 	buf = iWriteQueue.First();
   749 	iWriter->WriteL(buf->Ptr());
   750 	}
   751     }
   752 
   753 void CDemoControl::HandleReadCompleteEchoModeL()
   754     // In echo mode we send out what we receive and there could potentialy be a write
   755     // outstanding.
   756     // Get a new CIOBuffer copy the read data to the new write buffer
   757     // Queue it but only WriteL() it if the queue was empty
   758     {
   759     TBool sendNow = EFalse;
   760     (iWriteQueue.IsEmpty()) ? (sendNow = ETrue) : (sendNow = EFalse);
   761     // Add it to the queue
   762     CIOBuffer* buf = CIOBuffer::NewL(iReadBuffer.Length());
   763 	
   764     buf->Ptr() = iReadBuffer;
   765 
   766     // Flip Mac Addresses in buf
   767     FlipMacAddresses(buf->Ptr());
   768 
   769     iWriteQueue.AddLast(*buf);
   770     if(sendNow)
   771 	{
   772 	iWriter->WriteL(buf->Ptr());
   773 	}
   774     }
   775 
   776 void CDemoControl::FlipMacAddresses(TDes8& aBuf)
   777     {
   778     TUint32 length = aBuf.Length();
   779     aBuf.SetLength(6);
   780     TBuf8<6> dest(aBuf);
   781     aBuf.SetLength(12);
   782     aBuf.Copy(&aBuf[6],6);
   783     aBuf.SetLength(6);
   784     aBuf.Append(dest);
   785     aBuf.SetLength(length);
   786     }
   787 
   788 void CDemoControl::HandleWriteCompletePumpModeL()
   789     // In pump mode we never need to queue so just reuse the last buffer
   790     {
   791 #if (defined __USE_TIMER__)
   792     CIOBuffer* buf = iWriteQueue.First();
   793     iWriteQueue.Remove(*buf);
   794     delete buf;
   795 #else
   796     CIOBuffer* buf = iWriteQueue.First();
   797     iWriter->WriteL(buf->Ptr());
   798 #endif
   799     }
   800 
   801 void CDemoControl::HandleReadCompletePumpModeL()
   802     {
   803     }
   804 
   805 void CDemoControl::HandleReadCompleteReadModeL()
   806     {
   807     }
   808 
   809 //////////////
   810 
   811 CDemoWriter* CDemoWriter::NewL(MWriterNotify& aNotify,RBusDevEthernet& aCard)
   812 // Standard CBase derived creation of the Writer object
   813     {
   814     CDemoWriter* self = new (ELeave) CDemoWriter(EPriorityNormal);
   815     CleanupStack::PushL(self);
   816     self->ConstructL(aNotify,aCard);
   817     CleanupStack::Pop();
   818     return self;
   819     }
   820 
   821 
   822 void CDemoWriter::WriteL(const TDesC8& aBuffer)
   823 // Write data to the server
   824     {
   825     // Sanity check on the state of the active object
   826     if(IsActive())
   827 	{
   828 #if (defined __USE_TIMER__)
   829 	return;
   830 #else
   831 	User::Leave(KErrNotReady);
   832 #endif
   833 	}
   834     RDebug::Print(_L("About to write\n"));
   835     iCard->Write(iStatus,aBuffer);
   836 
   837     SetActive();
   838     }
   839 
   840 CDemoWriter::~CDemoWriter()
   841     {
   842     // Just in case, does not hurt to call if object is not active
   843     Cancel();
   844     }
   845 
   846 
   847 void CDemoWriter::ConstructL(MWriterNotify& aNotify,RBusDevEthernet& aCard)
   848 // Second phase construction. Does not actually leave 
   849     {
   850     CActiveScheduler::Add(this);
   851     iNotify = &aNotify;
   852     iCard = &aCard;
   853     }
   854 
   855 
   856 void CDemoWriter::RunL()
   857 // Just call back into the parent to notify Write completion
   858     {
   859     // Pass the status
   860     iNotify->WriteCompleteL(iStatus.Int());
   861     }
   862 
   863 void CDemoWriter::DoCancel()
   864 // Called by the CActive base class Cancel()
   865 // Only called if our TRequestStatus is still active 
   866     {
   867     }
   868 
   869 ///////
   870 
   871 
   872 CDemoReader* CDemoReader::NewL(MReaderNotify& aNotify,RBusDevEthernet& aCard)
   873 // Standard CBase derived creation of the Reader object
   874     {
   875     CDemoReader* self = new (ELeave) CDemoReader(EPriorityNormal+1);
   876     CleanupStack::PushL(self);
   877     self->ConstructL(aNotify,aCard);
   878     CleanupStack::Pop();
   879     return self;
   880     }
   881 
   882 
   883 void CDemoReader::ReadL(TDes8& aBuffer)
   884     {
   885     // Sanity Check
   886     if(IsActive())
   887 	{
   888 	User::Leave(KErrNotReady);
   889 	}
   890     RDebug::Print(_L("About to read\n"));
   891     iCard->Read(iStatus,aBuffer);
   892 
   893     SetActive();
   894     }
   895 
   896 CDemoReader::~CDemoReader()
   897     {
   898     // Just in case, does not hurt to call if object is not active
   899     Cancel();
   900     }
   901 
   902 
   903 void CDemoReader::ConstructL(MReaderNotify& aNotify,RBusDevEthernet& aCard)
   904 // Second phase construction. Does not actually leave 
   905     {
   906     CActiveScheduler::Add(this);
   907     iNotify = &aNotify;
   908     iCard = &aCard;
   909     }
   910 
   911 
   912 void CDemoReader::RunL()
   913 // Just call back into the parent to notify read completion
   914     {
   915     // Pass the status
   916     iNotify->ReadCompleteL(iStatus.Int());
   917     }
   918 
   919 void CDemoReader::DoCancel()
   920 // Called by the CActive base class Cancel()
   921 // Only called if our TRequestStatus is still active 
   922     {
   923     }
   924 
   925 ///////
   926 
   927 static void DriveEngineL()
   928     {
   929     // Create an Active Scheduler for the thread
   930     // Only one Active Scheduler per thread
   931     CActiveScheduler* myActiveScheduler = new(ELeave) CActiveScheduler;
   932     CleanupStack::PushL(myActiveScheduler);
   933     // Install the Active Scheduler
   934     CActiveScheduler::Install(myActiveScheduler);
   935     // Create of program control class derived from CActive
   936     // The ConstructL() of CDemoControl adds itself to the Active Scheduler
   937     RDebug::Print(_L("New demo Cntrol\n"));
   938     CDemoControl* demo = CDemoControl::NewLC();
   939     // Request a character from the the console to kick the
   940     // Active scheduler into life. If this is not done then we will block on the
   941     // Scheduler loop semaphore forever.
   942     RDebug::Print(_L("demo Control request char\n"));
   943     demo->RequestCharacter();
   944     // Active scheduler now enters its control loop
   945     // We can exit this loop and hence the program by calling CActiveScheduler::Stop()
   946     // from a RunL().
   947     // IMPORTANT :-
   948     // From now on all this thread's processing takes place from the RunL()'s of
   949     // the Active objects that have been added to the Active Scheduler
   950     RDebug::Print(_L("Start scheduler\n"));
   951     myActiveScheduler->Start();
   952     // Remove and delete demo and myActiveScheduler
   953     CleanupStack::PopAndDestroy(2);	
   954     }
   955 
   956 static void MainL()
   957     {
   958     // String Literal MACRO initialises a Descriptor
   959     //_LIT(KTitle,"EtherPump");
   960     //console=Console::NewL(KTitle,TSize(KDefaultConsWidth,KDefaultConsHeight));
   961     console=Console::NewL(_L("EtherPump"),TSize(KConsFullScreen,KConsFullScreen));
   962     RDebug::Print(_L("Console created\n"));
   963     CleanupStack::PushL(console);
   964     RDebug::Print(_L("and put on cu stack\n"));
   965     // TRAP
   966     TRAPD(err,DriveEngineL());
   967     if(err != KErrNone)
   968 	{
   969 	_LIT(KErrText,"Function Leave Code = %d\r\n");
   970 	console->Printf(KErrText,err);
   971 	}
   972 
   973     _LIT(KAnyKey,"Hit Any Key to Exit");
   974     console->ClearScreen();
   975     console->Printf(KAnyKey);
   976     console->Getch();
   977     CleanupStack::PopAndDestroy(1);
   978     }
   979 
   980 // Entry point for all Epoc32 executables
   981 // See PSP Chapter 2 Getting Started
   982 GLDEF_C TInt E32Main()
   983     {
   984     // Heap balance checking
   985     // See PSP Chapter 6 Error Handling
   986     RDebug::Print(_L("create cu stack\n"));
   987     __UHEAP_MARK;
   988     CTrapCleanup* cleanup = CTrapCleanup::New();
   989     if(cleanup == NULL)
   990 	{
   991 	return KErrNoMemory;
   992 	}
   993     RDebug::Print(_L("Run mainL\n"));
   994     TRAPD(err,MainL());
   995     _LIT(KPanic,"Etherpump");
   996     __ASSERT_ALWAYS(!err, User::Panic(KPanic,err));
   997     delete cleanup;
   998     __UHEAP_MARKEND;
   999     return KErrNone;
  1000     }
  1001 ///////////////////////
  1002 
  1003 // Generic Buffer class
  1004 // Currently used for transmit buffers
  1005 CIOBuffer::CIOBuffer() : iBufPtr(NULL,0)
  1006     {
  1007     }
  1008 
  1009 CIOBuffer::~CIOBuffer()
  1010 // Free the HBuf if there is one
  1011     {
  1012     FreeData();
  1013     }
  1014 
  1015 TPtr8& CIOBuffer::Ptr()
  1016     {
  1017     return iBufPtr;
  1018     }
  1019 
  1020 CIOBuffer* CIOBuffer::NewL(const TInt aSize)
  1021 // Creation where we new the HBuf
  1022     {
  1023     CIOBuffer * self = new (ELeave) CIOBuffer;
  1024     CleanupStack::PushL(self);
  1025     self->ConstructL(aSize);
  1026     CleanupStack::Pop();
  1027     return self;
  1028     }
  1029 
  1030 void CIOBuffer::ConstructL(const TInt aSize)
  1031 // Construction where we new the HBuf
  1032     {
  1033     iBuf = HBufC8::NewL(aSize);
  1034     TPtr8 temp=iBuf->Des();
  1035     iBufPtr.Set(temp);
  1036     }
  1037 
  1038 CIOBuffer* CIOBuffer::NewL(HBufC8* aBuf)
  1039 // HBuf provided
  1040     {
  1041     CIOBuffer * self = new (ELeave) CIOBuffer;
  1042     CleanupStack::PushL(self);
  1043     self->ConstructL(aBuf);
  1044     CleanupStack::Pop();
  1045     return self;
  1046     }
  1047 
  1048 void CIOBuffer::ConstructL(HBufC8* aBuffer)
  1049     {
  1050     Assign(aBuffer);
  1051     }
  1052 
  1053 TInt CIOBuffer::LinkOffset()
  1054     {
  1055     return _FOFF(CIOBuffer,iLink);	
  1056     }
  1057 
  1058 void CIOBuffer::Assign(HBufC8* aBuffer)
  1059     {
  1060     iBuf = aBuffer;
  1061     if(aBuffer)
  1062 	{
  1063 	TPtr8 temp=iBuf->Des();
  1064 	iBufPtr.Set(temp);
  1065 	}
  1066     }
  1067 
  1068 HBufC8*	CIOBuffer::Data() const
  1069     {
  1070     return iBuf;
  1071     }
  1072 
  1073 void CIOBuffer::FreeData()
  1074     {
  1075     if(iBuf)
  1076 	{
  1077 	delete iBuf;
  1078 	iBuf = NULL;
  1079 	}
  1080     }