diff -r 000000000000 -r a41df078684a kerneltest/e32test/device/t_serial.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/device/t_serial.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,2944 @@ +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\device\t_serial.cpp +// +// + +//#define _DEBUG_DEVCOMM + +#define __E32TEST_EXTENSION__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "d_lddturnaroundtimertest.h" +#include + +//#define DRIVER_TRACE_ON // disables or adjusts timeout for tests affected by LDD trace + +// Enable aggressive paging policy if required +#if 0 +#define WDP_ENABLED // affects some tests +#define FLUSH_WDP_CACHE UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0) +#else +#define FLUSH_WDP_CACHE +#endif + +#if defined (__WINS__) +#define PDD_NAME _L("ECDRV.PDD") +#define LDD_NAME _L("ECOMM.LDD") +#else +#define PDD_NAME _L("EUART") +#define LDD_NAME _L("ECOMM") +#endif + +const char KSpinner[]={'|','/','-','\\',}; + +#include "../power/async.h" + +#define CHECK(r,v) {if ((r)!=(v)) {test.Printf(_L("Line %d Expected %d Got %d\n"),__LINE__,(v),(r)); test(0);}} + +// constant expressions for elements in an array, and 1st address past the end +#define ELEMENTS(A) (sizeof(A)/sizeof(A[0])) +#define LIMIT(A) (A + ELEMENTS(A)) + +// Our own comms object with synchronous writes +class RComm : public RBusDevComm + { +public: + TInt WriteS(const TDesC8& aDes); + TInt WriteS(const TDesC8& aDes,TInt aLength); + // Override the read functions to flush the paging cache + inline void Read(TRequestStatus &aStatus,TDes8 &aDes) + { + FLUSH_WDP_CACHE; + RBusDevComm::Read(aStatus, aDes); + } + inline void Read(TRequestStatus &aStatus,TDes8 &aDes,TInt aLength) + { + FLUSH_WDP_CACHE; + RBusDevComm::Read(aStatus, aDes, aLength); + } + inline void ReadOneOrMore(TRequestStatus &aStatus,TDes8 &aDes) + { + FLUSH_WDP_CACHE; + RBusDevComm::ReadOneOrMore(aStatus, aDes); + } + }; + +LOCAL_D RTest test(_L("T_SERIAL")); +RComm* theSerialPorts[2]; +TCommCaps2 theCaps1Buf; +TCommCapsV02& theCaps1=theCaps1Buf(); +TCommCaps2 theCaps2Buf; +TCommCapsV02& theCaps2=theCaps2Buf(); +TInt PortA; +TInt PortB; + +const TInt KWriteSize=250; +const TInt KXonNumReads=0x10; +const TInt KXonReadSize=0x400; + +class TSpeedAndName + { +public: + TUint iMask; + TBps iSpeed; + const TText* iName; + }; + +class TSpeedAndNameV2 + { +public: + TUint iMask; + TBps iSpeed; + const TText* iName; + TUint iBps; + }; + +const TSpeedAndName KSpeeds[]= + { +// {KCapsBps50,EBps50,_S("50")}, +// {KCapsBps75,EBps75,_S("75")}, +// {KCapsBps110,EBps110,_S("110")}, +// {KCapsBps134,EBps134,_S("134")}, +// {KCapsBps150,EBps150,_S("150")}, +// {KCapsBps300,EBps300,_S("300")}, +// {KCapsBps600,EBps600,_S("600")}, +// {KCapsBps1200,EBps1200,_S("1200")}, +// {KCapsBps1800,EBps1800,_S("1800")}, +// {KCapsBps2000,EBps2000,_S("2000")}, +// {KCapsBps2400,EBps2400,_S("2400")}, +// {KCapsBps3600,EBps3600,_S("3600")}, +// {KCapsBps4800,EBps4800,_S("4800")}, +// {KCapsBps7200,EBps7200,_S("7200")}, + {KCapsBps9600,EBps9600,_S("9600")}, + {KCapsBps19200,EBps19200,_S("19200")}, +// {KCapsBps38400,EBps38400,_S("38400")}, + {KCapsBps57600,EBps57600,_S("57600")}, + {KCapsBps115200,EBps115200,_S("115200")}, + }; + +// These speeds are used to test break handling +const TSpeedAndNameV2 KBreakSpeeds[]= + { +// {KCapsBps50,EBps50,_S("50"),50}, +// {KCapsBps75,EBps75,_S("75"),75}, +// {KCapsBps110,EBps110,_S("110"),110}, +// {KCapsBps134,EBps134,_S("134"),134}, +// {KCapsBps150,EBps150,_S("150"),150}, + {KCapsBps300,EBps300,_S("300"),300}, +// {KCapsBps600,EBps600,_S("600"),600}, + {KCapsBps1200,EBps1200,_S("1200"),1200}, +// {KCapsBps1800,EBps1800,_S("1800"),1800}, +// {KCapsBps2000,EBps2000,_S("2000"),2000}, +// {KCapsBps2400,EBps2400,_S("2400"),2400}, +// {KCapsBps3600,EBps3600,_S("3600"),3600}, + {KCapsBps4800,EBps4800,_S("4800"),4800}, +// {KCapsBps7200,EBps7200,_S("7200"),7200}, +// {KCapsBps9600,EBps9600,_S("9600"),9600}, +// {KCapsBps19200,EBps19200,_S("19200"),19200}, +// {KCapsBps38400,EBps38400,_S("38400"),38400}, + {KCapsBps57600,EBps57600,_S("57600"),57600}, + {KCapsBps115200,EBps115200,_S("115200"),115200}, + }; + +// Multiplying factors to give Min turnaround times in microseconds between Rx and Tx +#if defined (__WINS__) +const TUint KTurnaroundTimes[] = +{ + 150, + 120, + 90, + 60 +}; +#else +const TUint KTurnaroundTimes[] = +{ +#ifdef DRIVER_TRACE_ON + 150, + 120, + 90, + 60 +#else + 15, + 12, + 9, + 6 +#endif +}; +#endif + +class TFrameAndName + { +public: + TDataBits iData; + TStopBits iStop; + TParity iParity; + const TText* iName; + }; + +const TFrameAndName KFrameTypes[]= + { + {EData8,EStop1,EParityNone,_S("8,N,1")}, + {EData8,EStop1,EParityEven,_S("8,E,1")}, + {EData8,EStop1,EParityOdd,_S("8,O,1")}, + + {EData8,EStop2,EParityNone,_S("8,N,2")}, + {EData8,EStop2,EParityEven,_S("8,E,2")}, + {EData8,EStop2,EParityOdd,_S("8,O,2")}, + + {EData7,EStop2,EParityNone,_S("7,N,2")}, + {EData7,EStop2,EParityEven,_S("7,E,2")}, + {EData7,EStop2,EParityOdd,_S("7,O,2")}, + + {EData7,EStop1,EParityNone,_S("7,N,1")}, + {EData7,EStop1,EParityEven,_S("7,E,1")}, + {EData7,EStop1,EParityOdd,_S("7,O,1")}, + +// {EData6,EStop2,EParityNone,_S("6,N,2")}, +// {EData6,EStop2,EParityEven,_S("6,E,2")}, +// {EData6,EStop2,EParityOdd,_S("6,O,2")}, + +// {EData6,EStop1,EParityNone,_S("6,N,1")}, +// {EData6,EStop1,EParityEven,_S("6,E,1")}, +// {EData6,EStop1,EParityOdd,_S("6,O,1")}, + +// {EData5,EStop1,EParityNone,_S("5,N,1")}, +// {EData5,EStop1,EParityEven,_S("5,E,1")}, +// {EData5,EStop1,EParityOdd,_S("5,O,1")}, + }; + +class THandShakeAndName + { +public: + TUint iHandshake; + const TText* iName; + }; + +THandShakeAndName KHandshakes[]= + { +// {KConfigObeyDSR,_S("DSR/DTR")}, // most cables don't actually support this + {KConfigObeyCTS,_S("CTS/RTS")}, +// {KConfigObeyDCD,_S("DCD")}, + }; + +enum TSerialTestFault + { + EBadArg, + }; +_LIT(KLddFileName, "D_LDDTURNAROUNDTIMERTEST.LDD"); +RLddTest1 ldd; + +#ifdef _DEBUG_DEVCOMM +void CommDebug(RBusDevComm& aComm) + { + TCommDebugInfoPckg infopckg; + TCommDebugInfo& info = infopckg(); + aComm.DebugInfo(infopckg); + + test.Printf(_L(" LDD State : TX RX \r\n")); + test.Printf(_L(" Busy : %10d %10d\r\n"), info.iTxBusy, info.iRxBusy); + test.Printf(_L(" Held : %10d %10d\r\n"), info.iTxHeld, info.iRxHeld); + test.Printf(_L(" Length : %10d %10d\r\n"), info.iTxLength, info.iRxLength); + test.Printf(_L(" Offset : %10d %10d\r\n"), info.iTxOffset, info.iRxOffset); + test.Printf(_L(" Int Count : %10d %10d\r\n"), info.iTxIntCount, info.iRxIntCount); + test.Printf(_L(" Err Count : %10d %10d\r\n"), info.iTxErrCount, info.iRxErrCount); + test.Printf(_L(" Buf Count : %10d %10d\r\n"), info.iTxBufCount, info.iRxBufCount); + test.Printf(_L(" Fill/Drain : %10d %10d\r\n"), info.iFillingTxBuf, info.iFillingTxBuf); + test.Printf(_L(" XON : %10d %10d\r\n"), info.iTxXon, info.iRxXon); + test.Printf(_L(" XOFF : %10d %10d\r\n"), info.iTxXoff, info.iRxXoff); + test.Printf(_L(" Chars : %10d %10d\r\n"), info.iTxChars, info.iRxChars); +// test.Printf(_L(" DFC Pending : %10d %10d\r\n"), info.iTxDfcPend, info.iTxDfcPend); +// test.Printf(_L(" DFC Run/Count : %10d %10d\r\n"), info.iRunningDfc, info.iDfcCount); +// test.Printf(_L(" DFC Req/Do/Drain : %10d %10d %10d\r\n"), info.iDfcReqSeq, info.iDfcHandlerSeq, info.iDoDrainSeq); + } +#else +void CommDebug(RBusDevComm& /*aComm*/) + { + test.Printf(_L("Debug Dump not available\r\n")); + } +#endif + +TInt RComm::WriteS(const TDesC8& aDes) +// +// Syncronous write +// + { + + return(WriteS(aDes,aDes.Length())); + } + + +TInt RComm::WriteS(const TDesC8& aDes,TInt aLength) +// +// Syncronous write +// + { + + TRequestStatus s; + + // Force there to be paging events + FLUSH_WDP_CACHE; + + // + Write(s,aDes,aLength); + User::WaitForRequest(s); + return(s.Int()); + } + +void Panic(TSerialTestFault const& aFault) +// +// Panic the test code +// + { + User::Panic(_L("Comm Test"),aFault); + } + +void StripeMem(TDes8& aBuf,TUint aStartChar,TUint anEndChar) +// +// Mark a buffer with repeating byte pattern +// + { + + __ASSERT_ALWAYS(aStartChar<=anEndChar,Panic(EBadArg)); + if (aStartChar==anEndChar) + { + aBuf.Fill(aStartChar); + return; + } + + TUint character=aStartChar; + for (TInt i=0;ianEndChar) + character=aStartChar; + } + } + +#define COLUMN_HEADER _L(" InBuf | outbuf\n\r") + +bool CompareDescriptors(TDes8 &aLeft,TDes8 &aRight) +// +// Compare a couple of descriptors and dump them if they don't match +// + { + TInt lLen=aLeft.Length(); + TInt rLen=aRight.Length(); + TInt minLen=Min(lLen,rLen); + + aRight.SetLength(minLen); + aLeft.SetLength(minLen); + bool r = (aLeft.Compare(aRight)==0); + if (!r) + { + RDebug::Print(_L("Compare failed - dumping descriptors\n\r")); + TInt len=aLeft.Length(); + RDebug::Print(COLUMN_HEADER); + TBuf8<0x100> buf; + for (TInt i=0;i<=len/8;i++) + { + buf.Zero(); + buf.SetLength(0); + buf.AppendFormat(_L8("%4d: "),i*8); + + for (TInt j=0;j<8;j++) + { + if ((i*8)+j=len) + break; + TInt v=aRight[(i*8)+k]; + buf.AppendFormat(_L8("%02x "),v); + } + buf.AppendFormat(_L8("\r\n")); + RDebug::RawPrint(buf); + } + } + + if (!r) { + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + aRight.SetLength(rLen); + aLeft.SetLength(lLen); + } + return r; +} + +TInt CheckedWrite(TInt aBufSize) +// +// Write a buffer from one serial port to the other and vice versa. +// + { + TUint8* inBuf=new TUint8[aBufSize]; + test(inBuf!=NULL); + TUint8* outBuf=new TUint8[aBufSize]; + test(outBuf!=NULL); + TPtr8 outDes(outBuf,aBufSize,aBufSize); + TPtr8 inDes(inBuf,aBufSize,aBufSize); + + RTimer tim; + tim.CreateLocal(); + TRequestStatus readStatus; + TRequestStatus timeStatus; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + const TInt KReadFirstPort=0; + const TInt KWriteFirstPort=1; + + // Check the driver rejects an attempt to read more data than the buffer allows + theSerialPorts[KReadFirstPort]->Read(readStatus,inDes,aBufSize+1); + test(readStatus==KErrGeneral); + + // Start reading for real + theSerialPorts[KReadFirstPort]->Read(readStatus,inDes); + test_Equal(KRequestPending, readStatus.Int()); + + // Synchronous write + TInt ret=theSerialPorts[KWriteFirstPort]->WriteS(outDes,aBufSize); + test(ret==KErrNone); + + // Set a 6 second timer going + const TUint KTimeOut=12000000; + tim.After(timeStatus,KTimeOut); + test(timeStatus==KRequestPending); + + // Wait for EITHER the read to complete, OR for the timer to timeout + User::WaitForRequest(readStatus,timeStatus); + if (timeStatus==KErrNone) // timer completed normally... oh dear, what happened to the read?? + { + test.Printf(_L("RComm::Read() timed out!\n\r")); + theSerialPorts[KReadFirstPort]->ReadCancel(); + test(EFalse); // fail + } + else + { + tim.Cancel(); + if (readStatus!=KErrNone) + test.Printf(_L("Read Failed! (%d)\n\r"),readStatus.Int()); + test(readStatus==KErrNone); + test(ret==KErrNone); + test.Printf(_L("\rRead %d of %d\n\r"),inDes.Length(),outDes.Length()); + test(CompareDescriptors(outDes,inDes)); + } + + test.Printf(_L("\t\t\tReverse\n")); + theSerialPorts[KWriteFirstPort]->Read(readStatus,inDes,aBufSize); + theSerialPorts[KReadFirstPort]->WriteS(outDes,aBufSize); + User::WaitForRequest(readStatus); + tim.After(timeStatus,KTimeOut); + test(timeStatus==KRequestPending); + User::WaitForRequest(readStatus,timeStatus); + if (timeStatus==KErrNone) + { + test.Printf(_L("Timed Out!\n\r")); + theSerialPorts[KWriteFirstPort]->ReadCancel(); + test(EFalse); // fail + } + else + { + tim.Cancel(); + if (readStatus!=KErrNone) + test.Printf(_L("Read Failed! (%d)\n\r"),readStatus.Int()); + test(readStatus==KErrNone); + test(ret==KErrNone); + test.Printf(_L("\rRead %d of %d\n\r"),inDes.Length(),outDes.Length()); + outDes.SetLength(inDes.Length()); + test(CompareDescriptors(outDes,inDes)); + } + + tim.Close(); + delete [] inBuf; + delete [] outBuf; + + return inDes.Length(); + } + +TUint CheckZeroTurnaround(TInt aBufSize, TUint aDirection) +// +// Checks that when a Turnaround of 0ms was selected the write takes place immediately +// aBufSize is selected such as it takes only slightly less than User timer granularity +// at the Baud rate selected to transmit that buffer. +// Checks that it takes less than a User side timer tick to complete a Write request +// at the selected Baud rate. Therefore proving the write is not being delayed in the driver +// + { + TUint8* inBuf=new TUint8[aBufSize]; + test(inBuf!=NULL); + TUint8* outBuf=new TUint8[aBufSize]; + test(outBuf!=NULL); + TPtr8 outDes(outBuf,aBufSize,aBufSize); + TPtr8 inDes(inBuf,aBufSize,aBufSize); + TInt numberRead = 0; + + TTimeIntervalMicroSeconds32 aTimeOut=0; + UserHal::TickPeriod(aTimeOut); + + RTimer timeoutTimer; + timeoutTimer.CreateLocal(); + TRequestStatus readStatus; + TRequestStatus writeStatus; + TRequestStatus timeStatus; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + const TUint port_A = aDirection?1:0; + const TUint port_B = 1 - port_A; + + // queue a read on port_A + test.Printf(_L("\r\nRead %d \r\n"), port_A); + theSerialPorts[port_A]->Read(readStatus,inDes); + test(readStatus==KRequestPending); + + // write on port_B to complete read + theSerialPorts[port_B]->SetMinTurnaroundTime(0); + theSerialPorts[port_B]->Write(writeStatus,outDes,aBufSize); + test(writeStatus==KRequestPending || writeStatus==KErrNone ); + + // start the local turnaround timer + timeoutTimer.After(timeStatus, (20*aTimeOut.Int())); // give it a 20% margin + test(timeStatus==KRequestPending); + + User::WaitForRequest(readStatus, timeStatus); + + if(timeStatus == KErrNone) + { + // if timeout first -> BAD + test.Printf(_L("Timed out!\r\n")); + theSerialPorts[port_A]->ReadCancel(); + test(EFalse); // fail + } + else + { + // else read was first -> GOOD + timeoutTimer.Cancel(); + + if (readStatus!=KErrNone) + test.Printf(_L("Read Failed! (%d)\n\r"),readStatus.Int()); + test(readStatus==KErrNone); + test(writeStatus==KErrNone); + test.Printf(_L("Good, read OK and took less than timeout\r\n")); + test(CompareDescriptors(outDes,inDes)); + numberRead = inDes.Length(); + } + timeoutTimer.Close(); + delete inBuf; + delete outBuf; + + return numberRead; + } + + +TUint TimedCheckedWrite(TInt aBufSize, TUint aTurnaround, TUint aDirection) +// +// Checks that Write requests are delayed if a Turnaround != 0 is selected. +// aTurnarund is chosen to be significantly greater than the time it takes to transmit +// a buffer of aBufSize at the Baud rate. +// Checks that for a given Turnaround time it always takes > that time to transmit +// a buffer of aBufSize. +// aDirection specifies the direction of transmission. +// + { + TUint8* inBuf=new TUint8[aBufSize]; + test(inBuf!=NULL); + TUint8* outBuf=new TUint8[aBufSize]; + test(outBuf!=NULL); + TPtr8 outDes(outBuf,aBufSize,aBufSize); + TPtr8 inDes(inBuf,aBufSize,aBufSize); + TInt numberRead = 0; + + TTimeIntervalMicroSeconds32 p=0; + UserHal::TickPeriod(p); + TInt tPeriod = p.Int(); + + const TUint KTimeOut = 1500000; // 1500 milliseconds + RTimer timeoutTimer; + timeoutTimer.CreateLocal(); + TRequestStatus readStatus; + TRequestStatus writeStatus; + TRequestStatus timeStatus; + + RTimer turnaroundTimer; + turnaroundTimer.CreateLocal(); + TRequestStatus turnaroundTimerStatus; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + const TUint port_A = aDirection?1:0; + const TUint port_B = 1 - port_A; + + // set turnaround on port_A + TInt r = theSerialPorts[port_A]->SetMinTurnaroundTime(aTurnaround+tPeriod); + test(r== KErrNone); + r = theSerialPorts[port_B]->SetMinTurnaroundTime(0); + test(r== KErrNone); + + // queue a short read on port_A + test.Printf(_L("\r\nRead %d to set turnaround %d\r\n"), port_A, aTurnaround+tPeriod); + theSerialPorts[port_A]->Read(readStatus,inDes); + test(readStatus==KRequestPending); + + // start the local turnaround timer + turnaroundTimer.After(turnaroundTimerStatus, aTurnaround); + test(turnaroundTimerStatus==KRequestPending); + + // write on port_B to complete read and start the driver's turnaround timer on A + theSerialPorts[port_B]->Write(writeStatus,outDes,aBufSize); + test((writeStatus==KRequestPending)||(writeStatus==KErrNone)); // may complete before coming back here as buffer size's small + + User::WaitForRequest(readStatus); + test(readStatus==KErrNone); + test(writeStatus==KErrNone); + test(CompareDescriptors(outDes,inDes)); + inDes.FillZ(); + + // queue a short read on port_B + theSerialPorts[port_B]->Read(readStatus, inDes); + test(readStatus==KRequestPending); + + // write on port_A + theSerialPorts[port_A]->Write(writeStatus,outDes,aBufSize); + test(writeStatus==KRequestPending); + + // wait on both the read on port_B and the local turnaround timer + User::WaitForRequest(readStatus, turnaroundTimerStatus); + + if(turnaroundTimerStatus == KErrNone) + { + // if local turnaround timeout first -> GOOD + // start big timeout and wait on either timeout or read on port_B + timeoutTimer.After(timeStatus, KTimeOut); + test(timeStatus==KRequestPending); + + User::WaitForRequest(readStatus, timeStatus); + if(timeStatus == KErrNone) + { + // if timeout first -> BAD + test.Printf(_L("Timed out!\r\n")); + + theSerialPorts[port_B]->ReadCancel(); + test(EFalse); // fail + } + else + { + // else read was first -> GOOD + timeoutTimer.Cancel(); + + if (readStatus!=KErrNone) + test.Printf(_L("Read Failed! (%d)\n\r"),readStatus.Int()); + test(readStatus==KErrNone); + test(writeStatus==KErrNone); + test.Printf(_L("Good, read OK, write took longer than turnaround\r\n")); + test(CompareDescriptors(outDes,inDes)); + numberRead = inDes.Length(); + } + } + else if(readStatus == KErrNone) + { + TInt timerStatus = turnaroundTimerStatus.Int(); + // else read was first -> BAD + turnaroundTimer.Cancel(); + test.Printf(_L("read completed before turnaround\r\n")); + test.Printf(_L("turnaroundTImer status %d ms!\r\n"),timerStatus); + test(EFalse); // fail + } + + timeoutTimer.Close(); + turnaroundTimer.Close(); + delete inBuf; + delete outBuf; + + return numberRead; + } + +// Checks that setting the turnaround first time before any read or write, will start the +// turnaround timer. It is make sure that first write will be delayed atleast min turnaround +// time. +void TestFirstDelayedWrite(TInt aBufSize, TUint aTurnaround, TUint aDirection) + { + test.Printf(_L("Loading logical device for getting kernel timer tick & count\n")); + TInt r=User::LoadLogicalDevice(KLddFileName); + test(r == KErrNone || r == KErrAlreadyExists); + + test.Printf(_L("Opening of logical device\n")); + r = ldd.Open(); + test(r == KErrNone || r == KErrAlreadyExists); + + + // Create input and an output buffers + TUint8* inBuf=new TUint8[aBufSize]; + test(inBuf!=NULL); + TUint8* outBuf=new TUint8[aBufSize]; + test(outBuf!=NULL); + + // Fill the output buffer with stuff and empty the input buffer + TPtr8 outDes(outBuf,aBufSize,aBufSize); + TPtr8 inDes(inBuf,aBufSize,aBufSize); + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + + // Configure both ports to 9600bps. + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[0]->Config(cBuf1); + TCommConfig cBuf2; + TCommConfigV01& c2=cBuf2(); + theSerialPorts[0]->Config(cBuf2); + c1.iHandshake=0; + c2.iHandshake=0; + c2.iFifo=EFifoDisable; + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityNone; + c2.iRate=c1.iRate=EBps9600; + r = theSerialPorts[0]->SetConfig(cBuf1); + test_Equal(KErrNone, r); + r = theSerialPorts[1]->SetConfig(cBuf2); + test(r == KErrNone); + + // Create a timer + RTimer timeoutTimer; + timeoutTimer.CreateLocal(); + TRequestStatus readStatus = 0xbaadf00d; + TRequestStatus writeStatus = 0xbaadf00d; + //TRequestStatus timeStatus = 0xbaadf00d; + + const TUint port_A = aDirection?1:0; + const TUint port_B = 1 - port_A; + + TUint time1 = 0, time2 = 0, time3 = 0; + // set turnaround on port_A + r = theSerialPorts[port_A]->SetMinTurnaroundTime(aTurnaround); + test(r== KErrNone); + + //Capture the turnaround time + ldd.Test_getTimerCount(time1); + + // set turnaround on port_B + r = theSerialPorts[port_B]->SetMinTurnaroundTime(0); + test(r== KErrNone); + + // queue a short read on port_B + theSerialPorts[port_B]->Read(readStatus, inDes); + /* BOGUS TEST: Zero-length reads complete immediately. + test_Equal(KRequestPending, readStatus.Int()); + */ + + // write on port_A + theSerialPorts[port_A]->Write(writeStatus,outDes,aBufSize); + /* BOGUS TEST + test(writeStatus==KRequestPending); + */ + + /* BOGUS TEST + The turnaround timer exists to introduce small delays between SUCCESSIVE reads & writes, + so as not to flummox IrDA transceivers which are slow in changing between write & read + modes. Setting a timer value does not have an immediate effect, it will + apply *after* the next read/write. + + // start a local timeout with aTurnaround/3 and wait on it + timeoutTimer.After(timeStatus, aTurnaround/3); + test(timeStatus==KRequestPending); + User::WaitForRequest(timeStatus); + test(timeStatus==KErrNone); + + // check that read on port_B has not completed yet (write on port_A has been delayed in the driver) + test_Equal(KRequestPending, readStatus.Int()); + */ + + // wait for write to complete + User::WaitForRequest(writeStatus); + if(writeStatus == KErrNone) + { + //record the time of write complete + ldd.Test_getTimerCount(time2); + } + + //Wait for read to complete + User::WaitForRequest(readStatus); + test(readStatus==KErrNone); + + //Covert turnaround time to timer ticks + time3 = aTurnaround / 1000; + ldd.Test_getTimerTicks(time3); + + test.Printf(_L("Time1 %d\n"), time1); + test.Printf(_L("Time2 %d\n"), time2); + test.Printf(_L("Time3 %d\n"), time3); + //Write takes apporximately 250 ticks to write. + time2 = (time2 - time1); //Includes turnaround time + write time + time1 = time3 > time2 ? time3 - time2 : time2 - time3; + test.Printf(_L("Time differece %d\n"), time1); + //test(time1 == 0 || time1 == 1); <-- Apparently unreasonable on SMP hardware + + timeoutTimer.Close(); + test.Printf(_L("Closing the channel\n")); + ldd.Close(); + + test.Printf(_L("Freeing logical device\n")); + r = User::FreeLogicalDevice(KLddFileName);; + test(r==KErrNone); + + delete inBuf; + delete outBuf; + + } + + + + +TUint ChangeTurnaroundTimeInDelayedWrite(TInt aBufSize, TUint aTurnaround, TUint aNewTurnaround, TUint aDirection) +// +// Checks that a delayed write will go based on the new timeout value if the Turnaround time is changed +// when a write is being delayed in the driver +// aBufSize is such that transmission of a buffer of that size at the baud rate selected << aTurnaround +// Check that a Write is being delayed by a previous Read and that changing the turnaround will adjust +// the turnaround timer based on the new value and write will happend after minturnaround time has elapsed +// + { + test.Printf(_L("Loading logical device for getting kernel timer tick & count\n")); + TInt r=User::LoadLogicalDevice(KLddFileName); + test(r == KErrNone || r == KErrAlreadyExists); + + test.Printf(_L("Opening of logical device\n")); + r = ldd.Open(); + test(r == KErrNone || r == KErrAlreadyExists); + + TUint8* inBuf=new TUint8[aBufSize]; + test(inBuf!=NULL); + TUint8* outBuf=new TUint8[aBufSize]; + test(outBuf!=NULL); + TPtr8 outDes(outBuf,aBufSize,aBufSize); + TPtr8 inDes(inBuf,aBufSize,aBufSize); + TInt numberRead = 0; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + RTimer timeoutTimer; + timeoutTimer.CreateLocal(); + TRequestStatus readStatus; + TRequestStatus writeStatus; + TRequestStatus timeStatus; + + const TUint port_A = aDirection?1:0; + const TUint port_B = 1 - port_A; + + // set turnaround on port_A + r = theSerialPorts[port_A]->SetMinTurnaroundTime(aTurnaround); + test(r== KErrNone); + // set turnaround on port_B + r = theSerialPorts[port_B]->SetMinTurnaroundTime(0); + test(r== KErrNone); + + // Issue a zero length read on port_A + theSerialPorts[port_A]->Read(readStatus,inDes,0); + User::WaitForRequest(readStatus); + test(readStatus==KErrNone); + //Record the start of turnaround time on port_A + TUint time1 = 0, time2 = 0, time3 = 0; + ldd.Test_getTimerCount(time1); + + // queue a short read on port_B + theSerialPorts[port_B]->Read(readStatus, inDes); + test(readStatus==KRequestPending); + + // write on port_A + theSerialPorts[port_A]->Write(writeStatus,outDes,aBufSize); + test(writeStatus==KRequestPending); + + // start a local timeout with aTurnaround/3 and wait on it + timeoutTimer.After(timeStatus, aTurnaround/3); + test(timeStatus==KRequestPending); + User::WaitForRequest(timeStatus); + test(timeStatus==KErrNone); + + // check that read on port_B has not completed yet (write on port_A has been delayed in the driver) +#ifndef WDP_ENABLED // lots of paging screws up timing assumptions + test(readStatus==KRequestPending); + test(writeStatus==KRequestPending); +#endif + + // change turnaround on port_A (should adjust turnaround time accordingly) + r = theSerialPorts[port_A]->SetMinTurnaroundTime(aNewTurnaround); + test(r==KErrNone); + + //Check read on port_B & write on port_A is still delayed. +#if !defined(DRIVER_TRACE_ON) && !defined(WDP_ENABLED) + test(readStatus==KRequestPending); + test(writeStatus==KRequestPending); +#endif + // wait for write to complete + User::WaitForRequest(writeStatus); + if(writeStatus == KErrNone) + { + //record the time of write complete + ldd.Test_getTimerCount(time2); + } + + //Wait for read to complete + User::WaitForRequest(readStatus); + test(readStatus==KErrNone); + + //Calculate the turnaround time, write should be delayed. + time3 = aNewTurnaround/1000; + //Convert to timer ticks + ldd.Test_getTimerTicks(time3); + test.Printf(_L("aTurnaround = %d, aNewTurnaround = %d\n"), aTurnaround, aNewTurnaround); + test.Printf(_L("Time1 = %d\n"), time1); + test.Printf(_L("Time2 = %d\n"), time2); + test.Printf(_L("Time3 = %d\n"), time3); + time1 = time2 - time1; + time1 = time3 > time1 ? (time3 - time1) : (time1 - time3); + test.Printf(_L("Time difference %d\n"), time1); +#if !defined(DRIVER_TRACE_ON) && !defined(WDP_ENABLED) +// test((time1 == 1) || (time1 == 0)); +#endif + test.Printf(_L("Write delayed for requested time\r\n")); + test(CompareDescriptors(outDes,inDes)); + numberRead = inDes.Length(); + + timeoutTimer.Close(); + test.Printf(_L("Closing the channel\n")); + ldd.Close(); + + test.Printf(_L("Freeing logical device\n")); + r = User::FreeLogicalDevice(KLddFileName);; + test(r==KErrNone); + + delete inBuf; + delete outBuf; + + return numberRead; + } + + +TUint StopInDelayedWrite(TInt aBufSize, TUint aTurnaround, TUint aDirection) +// +// Checks that when a write is being delayed and then is cancelled the driver's turnaround timer continues +// ticking and if another write is queued it will be delayed by the remaining time +// aBufSize is such that transmission of a buffer of that size at the baud rate selected << aTurnaround +// Check that a Write is being delayed by a previous Read and that changing the Turnaround will make it +// go ahead immediately +// + { + TUint8* inBuf=new TUint8[aBufSize]; + test(inBuf!=NULL); + TUint8* outBuf=new TUint8[aBufSize]; + test(outBuf!=NULL); + TPtr8 outDes(outBuf,aBufSize,aBufSize); + TPtr8 inDes(inBuf,aBufSize,aBufSize); + TInt numberRead = 0; + + TTimeIntervalMicroSeconds32 p=0; + UserHal::TickPeriod(p); + TInt tPeriod = p.Int(); + + const TUint KTimeOut = 1500000; // 150 milliseconds + RTimer timeoutTimer; + timeoutTimer.CreateLocal(); + TRequestStatus readStatus; + TRequestStatus writeStatus; + TRequestStatus timeStatus; + + RTimer turnaroundTimer; + turnaroundTimer.CreateLocal(); + TRequestStatus turnaroundTimerStatus; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + const TUint port_A = aDirection?1:0; + const TUint port_B = 1 - port_A; + + // set turnaround on port_A + TInt r = theSerialPorts[port_A]->SetMinTurnaroundTime(aTurnaround+tPeriod); + test(r== KErrNone); + r = theSerialPorts[port_B]->SetMinTurnaroundTime(0); + test(r== KErrNone); + + + // queue a zero length read to start the turnaround on port_A + test.Printf(_L("\r\nRead Zero Length on %d to start turnaround %d\r\n"), port_A, aTurnaround); + test.Printf(_L("\r\nUsing %d character buffers\r\n"),aBufSize); + + theSerialPorts[port_A]->Read(readStatus,inDes,0); + User::WaitForRequest(readStatus); + test(readStatus==KErrNone); + + // start the local turnaround timer + turnaroundTimer.After(turnaroundTimerStatus, aTurnaround); + test(turnaroundTimerStatus==KRequestPending); + + // queue a short read on port_B + theSerialPorts[port_B]->Read(readStatus, inDes); + test(readStatus==KRequestPending); + + // write on port_A + theSerialPorts[port_A]->Write(writeStatus,outDes,aBufSize); + test(writeStatus==KRequestPending); + + // start a local timeout with aTurnaround/3 and wait on it + timeoutTimer.After(timeStatus, aTurnaround/3); + test(timeStatus==KRequestPending); + User::WaitForRequest(timeStatus); + test(timeStatus==KErrNone); + + // check that read on port_B has not completed yet (write on port_A has been delayed in the driver) + test(readStatus==KRequestPending); + + // cancel write on port_A + theSerialPorts[port_A]->WriteCancel(); + test(writeStatus==KErrCancel); + + // ...and restart it again + theSerialPorts[port_A]->Write(writeStatus,outDes,aBufSize); +#ifndef DRIVER_TRACE_ON + test(writeStatus==KRequestPending); +#endif + + // wait on both the read on port_B and the local turnaround timer + User::WaitForRequest(readStatus, turnaroundTimerStatus); + + // We are expecting this to have gone off by now... + if(turnaroundTimerStatus == KErrNone) // this local timer is LESS than the driver turnaround + { + // if local turnaround timeout first -> GOOD + // start big timeout and wait on either timeout or read on port_B + timeoutTimer.After(timeStatus, KTimeOut); + test(timeStatus==KRequestPending); + + User::WaitForRequest(readStatus, timeStatus); + if(timeStatus == KErrNone) + { + // if timeout first -> BAD + test.Printf(_L("Timed out!\r\n")); + + theSerialPorts[port_B]->ReadCancel(); + test(EFalse); // fail + } + else + { + // else read was first -> GOOD + timeoutTimer.Cancel(); + + if (readStatus!=KErrNone) + test.Printf(_L("Read Failed! (%d) - should have completed (on delayed write data)\n\r"),readStatus.Int()); + test(readStatus==KErrNone); + test(writeStatus==KErrNone); + test.Printf(_L("OK, write later than turnaround\r\n")); + test(CompareDescriptors(outDes,inDes)); + numberRead = inDes.Length(); + } + } + // failed here => second write has gone off faster than expected... + else if(readStatus == KErrNone) + { + // else read was first -> BAD + TInt timerStatus = turnaroundTimerStatus.Int(); + turnaroundTimer.Cancel(); + test.Printf(_L("read completed before turnaround\r\n")); + test.Printf(_L("Turnaround timer status = %d\r\n"),timerStatus); + test(EFalse); // fail + } + + timeoutTimer.Close(); + turnaroundTimer.Close(); + delete inBuf; + delete outBuf; + + return numberRead; + } + +void turnaroundTestReadWrite() +// +// Read and write at various speeds, with various turnarounds +// Check that the data received data matches sent data + { + // Open both serial ports + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + // Perform the read/write test at each baudrate for 8N1, no handshaking + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[0]->Config(cBuf1); + TCommConfig cBuf2; + TCommConfigV01& c2=cBuf2(); + theSerialPorts[0]->Config(cBuf2); + c1.iHandshake=0; + c2.iHandshake=0; + c2.iFifo=EFifoDisable; + + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityNone; + c2.iRate=c1.iRate=EBps9600; + + TBuf<0x40> msg; + + test.Start(_L("Read/write test with default turnaround and at 9600 Bps")); + + TTimeIntervalMicroSeconds32 p=0; + UserHal::TickPeriod(p); + TInt tPeriod = p.Int(); + test.Printf(_L("Tick period %d\r\n"), tPeriod); + + TUint aBufLength = 96*p.Int()/10000; + test.Printf(_L("Need to transmit %d chars at 9600 Bps\r\n"), aBufLength); // let's try with 10*tick period (approx) + + theSerialPorts[0]->SetConfig(cBuf1); + theSerialPorts[1]->SetConfig(cBuf2); + + // These work fine + test(CheckZeroTurnaround(aBufLength, 0)==aBufLength); + test(CheckZeroTurnaround(aBufLength, 1)==aBufLength); + + test.Next(_L("Read/write test at various speeds and min turnarounds")); +#if defined (__WINS__) + const TUint KShortBufferSize=100; +#else + const TUint KShortBufferSize=10; +#endif + TUint direction=0; + for(TUint i = 0; i < ELEMENTS(KSpeeds); ++i) + { + TInt turnaround; + turnaround = KTurnaroundTimes[i]*p.Int(); + + if (theCaps1.iRate&KSpeeds[i].iMask && theCaps2.iRate&KSpeeds[i].iMask) + { + msg.Format(_L("\r\nRead/write @ %s Bps with %d millisec turnaround\r\n"), KSpeeds[i].iName, turnaround/1000); + test.Next(msg); + + c1.iRate=KSpeeds[i].iSpeed; + TInt r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + c2.iRate=KSpeeds[i].iSpeed; + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + test.Printf(_L("Do TimedCheckedWrite\r\n")); + test(TimedCheckedWrite(KShortBufferSize, turnaround, direction)==KShortBufferSize); + } + else + { + msg.Format(_L("%s Bps not supported\r\n"),KSpeeds[i].iName); + test.Next(msg); + } + + direction=1-direction; + + msg.Format(_L("\r\nRead turnaround time back\r\n")); + test.Next(msg); + + TInt n = theSerialPorts[0]->MinTurnaroundTime(); + test(n==turnaround+tPeriod); + + msg.Format(_L("Value returned was %d\r\n"), n/1000); + test.Next(msg); + + test.Printf(_L("Decrease turnaroundtime during delayed write\n")); + test(ChangeTurnaroundTimeInDelayedWrite(KShortBufferSize, turnaround, turnaround - 10000, direction)==KShortBufferSize); + + test.Printf(_L("Increase turnaroundtime during delayed write\n")); + test(ChangeTurnaroundTimeInDelayedWrite(KShortBufferSize, turnaround, turnaround + 30000 ,direction)==KShortBufferSize); + + direction=1-direction; + + test.Printf(_L("\r\nDo StopInDelayedWrite @ %s Bps\r\n"), KSpeeds[i].iName); + test(StopInDelayedWrite(KShortBufferSize, turnaround, direction)==KShortBufferSize); + } + + // return defaults for following tests + + msg.Format(_L("\r\nSet default turnaround (0) on both ports \r\n")); + test.Next(msg); + + test(theSerialPorts[0]->SetMinTurnaroundTime(0)==KErrNone); + test(theSerialPorts[1]->SetMinTurnaroundTime(0)==KErrNone); + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + msg.Format(_L("\r\n... End of turnaround tests ...\r\n")); + test.Next(msg); + + test.End(); + } + +void testReadWrite() +// +// Read and write at various speeds + { + test.Start(_L("Testing read and write")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[0]->Config(cBuf1); + TCommConfig cBuf2; + TCommConfigV01& c2=cBuf2(); + theSerialPorts[0]->Config(cBuf2); + c1.iHandshake=0; + c2.iHandshake=0; + c2.iFifo=EFifoDisable; + + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityNone; + c2.iRate=c1.iRate=EBps9600; + + TBuf<0x40> mess; + test.Printf(_L("Delayed first write\n")); + TestFirstDelayedWrite(0, 2343750, 1); + + TInt numTests=sizeof(KSpeeds)/sizeof(TSpeedAndName); + for (TInt i=0;iSetConfig(cBuf1); + test(r==KErrNone); + c2.iRate=KSpeeds[i].iSpeed; + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + test.Printf(_L("DoCheckedWrite\r\n")); + test(CheckedWrite(KWriteSize)==KWriteSize); + } + else + { + mess.Format(_L("%s Bps not supported"),KSpeeds[i].iName); + test.Next(mess); + } + } + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + test.End(); + } + +void testTiming() +// +// Read and write at various speeds + { + + test.Start(_L("Testing read and write speed")); + const TInt KSamples=10; + const TInt KNumWrites=100; + const TInt KBufSize=2000; + test.Printf(_L("%d sets of %d by %d characters @ 19200\n\r"),KSamples,KNumWrites,KBufSize); + + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[0]->Config(cBuf1); + TCommConfig cBuf2; + TCommConfigV01& c2=cBuf2(); + theSerialPorts[0]->Config(cBuf2); + c1.iHandshake=0; + c2.iHandshake=0; + c2.iFifo=EFifoDisable; + + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityNone; + c2.iRate=c1.iRate=EBps19200; + + TInt r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + TUint samples[KSamples]; + + for (TInt i=0;iRead(readStatus,inDes); + + TInt ret=theSerialPorts[1]->WriteS(outDes,KBufSize); + const TUint KTimeOut=6000000; + tim.After(timeStatus,KTimeOut); + + User::WaitForRequest(readStatus,timeStatus); + + + if (timeStatus==KErrNone) + { + test.Printf(_L("Timed Out!\n\r")); + theSerialPorts[0]->ReadCancel(); + } + else + { + tim.Cancel(); + if (readStatus!=KErrNone) + test.Printf(_L("Read Failed! (%d)\n\r"),readStatus.Int()); + test(readStatus==KErrNone); + test(ret==KErrNone); + test(inDes.Length()==inDes.MaxLength()); + test(inDes.Length()==KBufSize); + test(CompareDescriptors(outDes,inDes)); + } + + } + TTime endTime; + endTime.HomeTime(); + + TInt64 delta=endTime.MicroSecondsFrom(startTime).Int64(); + delta=delta/1000; + TInt delta32=I64INT(delta); + samples[i]=delta32; + test.Printf(_L("Read/Write %d time = %d ms\n\r"),KNumWrites*KBufSize,delta32); + } + + TInt avg=0; + for (TInt j=0;j msg; + test.Next(_L("Testing breaks")); + + TCommConfig cBuf0; + TCommConfigV01& c0=cBuf0(); + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + + TRequestStatus breakStatus; + TRequestStatus readStatus; + TRequestStatus writeStatus; + TRequestStatus timerStatus; + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + theSerialPorts[0]->Config(cBuf0); + theSerialPorts[1]->Config(cBuf1); + c0.iRate=c1.iRate=EBps110; + c0.iParityError=c1.iParityError=0; + c0.iHandshake=c1.iHandshake=0; + + c0.iDataBits=c1.iDataBits=EData8; + c0.iStopBits=c1.iStopBits=EStop1; + c0.iParity=c1.iParity=EParityNone; + + + r=theSerialPorts[0]->SetConfig(cBuf0); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + +for(TUint i = 0; i < ELEMENTS(KBreakSpeeds) ; ++i) + { + if (theCaps1.iRate&KBreakSpeeds[i].iMask && theCaps2.iRate&KBreakSpeeds[i].iMask) + { + msg.Format(_L("Break tests @ %s Bps"), KBreakSpeeds[i].iName); + test.Start(msg); + + c0.iRate=KBreakSpeeds[i].iSpeed; + TInt r=theSerialPorts[0]->SetConfig(cBuf0); + test(r==KErrNone); + c1.iRate=KBreakSpeeds[i].iSpeed; + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + + + // should take more than 1.5s + + HBufC8* bigReadBuffer=HBufC8::NewL(KWriteSize); + HBufC8* bigWriteBuffer=HBufC8::NewMaxL(KWriteSize); + TPtr8 bigReadBufferPtr(bigReadBuffer->Des()); + TPtr8 bigWriteBufferPtr(bigWriteBuffer->Des()); + + StripeMem(bigWriteBufferPtr, 'A', 'Z'); + bigReadBufferPtr.FillZ(); + + + const TUint KWriteSize=1024 + KBreakSpeeds[i].iBps/4; + const TInt KTimerTime=1500000; + const TInt KBreakTime=3000000; + const TInt KMinTurnaroundTime=150000; + + RTimer timer; + test(timer.CreateLocal()==KErrNone); + + +// Test 1 + test.Start(_L("Break after write")); + //- start a user timer which will expire just after the TX would complete with no break + timer.After(timerStatus, KTimerTime); + + //- request TX (and RX) and request a break + theSerialPorts[0]->Write(writeStatus, *bigWriteBuffer, KWriteSize); + theSerialPorts[0]->Break(breakStatus, KBreakTime); + theSerialPorts[1]->Read(readStatus, bigReadBufferPtr, KWriteSize); + + // Make sure the timer completes first + User::WaitForRequest(writeStatus, readStatus); + User::WaitForRequest(breakStatus); + + test(readStatus!=KErrNone && readStatus!=KRequestPending); + test(breakStatus==KErrNone); + test(writeStatus==KErrNone || writeStatus==KRequestPending); // Can be still pending, since if the read is completed with an error then the write won't complete since the buffers may fill up + test(timerStatus==KErrNone); + + if (writeStatus==KRequestPending) + theSerialPorts[0]->WriteCancel(); + +// Test 2 + test.Next(_L("Write after break")); + //- start a user timer which will expire just after the TX would complete with no break + timer.After(timerStatus, KTimerTime); + + //- request TX (and RX) and request a break + theSerialPorts[1]->Read(readStatus, bigReadBufferPtr, KWriteSize); + theSerialPorts[0]->Break(breakStatus, KBreakTime); + theSerialPorts[0]->Write(writeStatus, *bigWriteBuffer, KWriteSize); + + // Make sure the timer completes first + User::WaitForRequest(breakStatus); + User::WaitForRequest(writeStatus, readStatus); + + test(readStatus!=KErrNone && readStatus!=KRequestPending); + test(breakStatus==KErrNone); + test(writeStatus==KErrNone || writeStatus==KRequestPending); // write may not be able to cmoplete due to no remaining pending read + test(timerStatus==KErrNone); + + if (writeStatus==KRequestPending) + theSerialPorts[0]->WriteCancel(); + +// Test 3 + test.Next(_L("Cancellation of break")); + //- Check cancellation of breaks + + //- request TX (and RX) and request a break + theSerialPorts[0]->Break(breakStatus, KBreakTime); + theSerialPorts[1]->Read(readStatus, bigReadBufferPtr, KWriteSize); + theSerialPorts[0]->Write(writeStatus, *bigWriteBuffer, KWriteSize); + + //- cancel break + theSerialPorts[0]->BreakCancel(); + + User::WaitForRequest(breakStatus); + test(breakStatus.Int()==KErrCancel); + + User::WaitForRequest(readStatus); + + if (writeStatus==KRequestPending) + theSerialPorts[0]->WriteCancel(); + +// Test 4 + + test.Next(_L("Break during turnaround")); + //- Check break still works during turnaround + test (KErrNone==theSerialPorts[0]->SetMinTurnaroundTime(KMinTurnaroundTime)); + + theSerialPorts[0]->Read(readStatus, bigReadBufferPtr, 1); + theSerialPorts[1]->Write(writeStatus, *bigWriteBuffer, 1); + User::WaitForRequest(readStatus); + User::WaitForRequest(writeStatus); + + //- start a user timer which will expire just after the TX would complete with no break + timer.After(timerStatus, KTimerTime); + + //- request TX (and RX) and request a break + theSerialPorts[0]->Break(breakStatus, KBreakTime); + theSerialPorts[1]->Read(readStatus, bigReadBufferPtr, KWriteSize); + theSerialPorts[0]->Write(writeStatus, *bigWriteBuffer, KWriteSize); + + // Make sure the timer completes first + User::WaitForRequest(writeStatus, readStatus); + User::WaitForRequest(breakStatus); + + test(readStatus!=KErrNone && readStatus!=KRequestPending); + test(breakStatus==KErrNone); + test(writeStatus==KErrNone || writeStatus==KRequestPending); + test(timerStatus==KErrNone); + + if (writeStatus==KRequestPending) + theSerialPorts[0]->WriteCancel(); + + test (KErrNone==theSerialPorts[0]->SetMinTurnaroundTime(0)); + +// End tests + timer.Close(); + test.End(); + test.End(); + } + else + { + msg.Format(_L("%s Bps not supported"),KBreakSpeeds[i].iName); + test.Next(msg); + } + } // end rate loop + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + } + + + +void testFraming() +// +// Test framing +// + { + test.Start(_L("Testing framing")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf0; + TCommConfigV01& c0=cBuf0(); + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + TBuf<0x40> mess; + + theSerialPorts[0]->Config(cBuf0); + c0.iRate=EBps9600; + c0.iHandshake=0; + theSerialPorts[1]->Config(cBuf1); + c1.iRate=EBps9600; + c1.iHandshake=0; + + TInt numTests=sizeof(KFrameTypes)/sizeof(TFrameAndName); + for (TInt i=0;iSetConfig(cBuf0); + if (r==KErrNone) + { + + c1.iDataBits=KFrameTypes[i].iData; + c1.iStopBits=KFrameTypes[i].iStop; + c1.iParity=KFrameTypes[i].iParity; + r=theSerialPorts[1]->SetConfig(cBuf1); + if(r==KErrNone) + { + mess.Format(_L("read/write using %s "),KFrameTypes[i].iName); + test.Next(mess); + test(CheckedWrite(KWriteSize)==KWriteSize); + } + } + + if (r!=KErrNone) + test.Printf(_L("%s not supported\n\r"),KFrameTypes[i].iName); + } + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + test.End(); + } +// +void testTerminators() +// +// Test termination masks - assumes that Checked write stripes memory starting with 'A' +// + { + + test.Next(_L("Testing termination masks")); + + TCommConfig cBuf; + TCommConfigV01& c=cBuf(); + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + theSerialPorts[0]->Config(cBuf); + c.iTerminator[0]='C'; + c.iTerminatorCount=1; + c.iHandshake=0; + + c.iDataBits=EData8; + c.iStopBits=EStop1; + c.iParity=EParityNone; + + r=theSerialPorts[0]->SetConfig(cBuf); + test(r==KErrNone); + + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[1]->Config(cBuf1); + + c1.iDataBits=EData8; + c1.iStopBits=EStop1; + c1.iParity=EParityNone; + + c1.iTerminator[0]='C'; + c1.iTerminatorCount=1; + c1.iHandshake=0; + + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + + User::After(100000); + theSerialPorts[0]->ResetBuffers(); + theSerialPorts[1]->ResetBuffers(); + + test(CheckedWrite(KWriteSize)==3); + + // Clear the ldd buffers + theSerialPorts[0]->ResetBuffers(); + theSerialPorts[1]->ResetBuffers(); + + c.iTerminator[0]='Z'; + c.iTerminator[1]='X'; + c.iTerminator[2]='Y'; + c.iTerminator[3]='D'; + + c1.iTerminator[0]='Z'; + c1.iTerminator[1]='X'; + c1.iTerminator[2]='Y'; + c1.iTerminator[3]='D'; + +/* Not yet - we have too much buffering in the driver & device. + Unfortunately the ResetBuffers() above doesn't (and really can't) go + deep enough. Under WINS NT buffers up some data and the following read + (inside checked write) completes before the WriteS (and infact, after + reading a semi random number of characters) + + c.iTerminatorCount=4; + c1.iTerminatorCount=4; + r=theSerialPorts[0]->SetConfig(cBuf); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + + test(CheckedWrite(KWriteSize)==4); + theSerialPorts[0]->Config(cBuf); +*/ + // Reset termination mask. + c.iTerminatorCount=0; + c1.iTerminatorCount=0; + r=theSerialPorts[0]->SetConfig(cBuf); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + } + +void testXonXoff() +// +// tests XonXoff +// + { + test.Next(_L("Testing xon xoff")); + test.Start(_L("Setup")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf; + TCommConfigV01& c=cBuf(); + + theSerialPorts[0]->Config(cBuf); + c.iHandshake=KConfigObeyXoff|KConfigSendXoff; + c.iStopBits=EStop1; + c.iParity=EParityNone; + c.iDataBits=EData8; + c.iRate=EBps19200; + c.iXonChar=0x11; + c.iXoffChar=0x13; + c.iParityError=KConfigXonXoffDebug; + c.iTerminatorCount=0; + test(theSerialPorts[0]->SetConfig(cBuf)==KErrNone); + + theSerialPorts[1]->Config(cBuf); + c.iHandshake=KConfigObeyXoff|KConfigSendXoff; + c.iStopBits=EStop1; + c.iParity=EParityNone; + c.iDataBits=EData8; + c.iRate=EBps19200; + c.iXonChar=0x11; + c.iXoffChar=0x13; + c.iParityError=KConfigXonXoffDebug; + c.iTerminatorCount=0; + test(theSerialPorts[1]->SetConfig(cBuf)==KErrNone); + + theSerialPorts[0]->SetReceiveBufferLength(0x400); + theSerialPorts[1]->SetReceiveBufferLength(0x400); + + const TInt KXonWriteSize=KXonNumReads*KXonReadSize; + + TUint8* inBuf=new TUint8[KXonReadSize]; + TUint8* outBuf=new TUint8[KXonWriteSize]; + TPtr8 outDes(outBuf,KXonWriteSize,KXonWriteSize); + TPtr8 inDes(inBuf,KXonReadSize,KXonReadSize); + + TRequestStatus readStatus; + TRequestStatus writeStatus; + TRequestStatus timeStatus; + RTimer timer; + timer.CreateLocal(); + TInt writePos=0; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + test.Next(_L("Write bytes to com1")); + test.Printf(_L("Reading after delay (1 of %d) avail = %d\n\r"),KXonNumReads, theSerialPorts[0]->QueryReceiveBuffer()); + theSerialPorts[0]->Read(readStatus,inDes,KXonReadSize); + theSerialPorts[1]->Write(writeStatus,outDes,KXonWriteSize); + timer.After(timeStatus,1000000); + User::WaitForRequest(readStatus,timeStatus); + test(readStatus==KErrNone); + test(timeStatus==KRequestPending); + TPtrC8 aOutDes = outDes.Mid(writePos,KXonReadSize); + test(CompareDescriptors(inDes,(TDes8&)aOutDes)); + + writePos+=KXonReadSize; + + if (timeStatus==KRequestPending) + User::WaitForRequest(timeStatus); + + TInt i; + for (i=0;iQueryReceiveBuffer()); + theSerialPorts[0]->Read(readStatus,inDes,KXonReadSize); + timer.After(timeStatus,1000000); + User::WaitForRequest(readStatus,timeStatus); + if (readStatus!=KErrNone) + test.Printf(_L("Read error %d\n\r"),readStatus.Int()); + test(readStatus==KErrNone); + test(timeStatus==KRequestPending); + TPtrC8 aOutDes = outDes.Mid(writePos,KXonReadSize); + test(CompareDescriptors(inDes,(TDes8&)aOutDes)); + timer.Cancel(); + writePos+=KXonReadSize; + } + + test.Next(_L("2nd Large Write complete")); + test(writeStatus==KErrNone); + + delete [] inBuf; + delete [] outBuf; + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + test.End(); + } + +// +void testHWHandshaking() +// +// test hardware hand shaking +// + { + +#if defined (__WINS__) +const TInt KHWReadSize=0x2000; +#else +const TInt KHWReadSize=0x400; +#endif + + test.Start(_L("Testing hardware handshaking")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf0; + TCommConfigV01& c0=cBuf0(); + TBuf<0x40> mess; + theSerialPorts[0]->Config(cBuf0); + c0.iRate=EBps115200; + c0.iParityError=0; + c0.iHandshake=0; + + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + test(theSerialPorts[0]->SetConfig(cBuf0)==KErrNone); + + theSerialPorts[1]->Config(cBuf1); + c1.iRate=EBps115200; + c1.iParityError=0; + c1.iHandshake=0; + test(theSerialPorts[1]->SetConfig(cBuf1)==KErrNone); + + const TInt KXonWriteSize=KXonNumReads*KHWReadSize; + + TUint8* inBuf=new TUint8[KHWReadSize]; + TUint8* outBuf=new TUint8[KXonWriteSize]; + TPtr8 outDes(outBuf,KXonWriteSize,KXonWriteSize); + TPtr8 inDes(inBuf,KHWReadSize,KHWReadSize); + +//TUint8* inBuf2=new TUint8[KXonWriteSize]; +//TPtr8 inDes2(inBuf2,KXonWriteSize,KXonWriteSize); + +#if defined (__WINS__) + theSerialPorts[0]->SetReceiveBufferLength(0x50); + theSerialPorts[1]->SetReceiveBufferLength(0x50); +#else + theSerialPorts[0]->SetReceiveBufferLength(0x400); + theSerialPorts[1]->SetReceiveBufferLength(0x400); +#endif + + TInt numTests=sizeof(KHandshakes)/sizeof(THandShakeAndName); + for(TInt j=0;jSetConfig(cBuf0)==KErrNone); + test(theSerialPorts[1]->SetConfig(cBuf1)==KErrNone); + TRequestStatus readStatus; + TRequestStatus writeStatus; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + theSerialPorts[1]->Write(writeStatus,outDes,KXonWriteSize); + +//TRequestStatus writeStatus2; +//theSerialPorts[0]->Write(writeStatus2,outDes,KXonWriteSize); + + TInt i; + for (i=0;iQueryReceiveBuffer()); + theSerialPorts[0]->Read(readStatus,inDes,KHWReadSize); + User::WaitForRequest(readStatus); + test(readStatus==KErrNone); + TPtrC8 aOutDes = outDes.Mid(KHWReadSize*i,KHWReadSize); + test(CompareDescriptors(inDes,(TDes8&)aOutDes)); + test(inDes.Length()==KHWReadSize); + } + + test.Next(_L("2nd Large Write complete")); + User::WaitForRequest(writeStatus); + test(writeStatus==KErrNone); + +//theSerialPorts[1]->Read(readStatus,inDes2,KXonWriteSize); +//User::WaitForRequest(writeStatus2); +//test(writeStatus2==KErrNone); + +//User::WaitForRequest(readStatus); +//test(readStatus==KErrNone); + + } + else + { + test.Printf(_L("Config not supported\r\n")); + } + } + delete [] inBuf; + delete [] outBuf; + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + test.End(); + } + +void testWriteZero() +// +// Test a write of 0 bytes is still blocked by CTS flow control. +// Test does a flow controlled Write(0) which is blocked by the remote +// port state being closed (hence remote RTS disasserted, hence writer's +// CTS likewise). Then it opens the remote port and asserts RTS - this +// unblocks the original Write(0). +// + { + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + + test.Next(_L("Testing Write 0")); + + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[0]->Config(cBuf1); + c1.iRate=EBps19200; + c1.iParityError=0; + c1.iHandshake=KConfigObeyCTS; + + r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + + test.Start(_L("Test Write(0) with remote RTS disasserted blocks")); + TRequestStatus writeStat; + theSerialPorts[0]->Write(writeStat,TPtr8(NULL,0),0); + + RTimer timer; + timer.CreateLocal(); + TRequestStatus timeStatus; + timer.After(timeStatus,1000000); + User::WaitForRequest(timeStatus,writeStat); + + test(timeStatus==KErrNone); + test(writeStat==KRequestPending); + + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf2; + TCommConfigV01& c2=cBuf2(); + theSerialPorts[1]->Config(cBuf2); + c2.iRate=EBps19200; + c2.iParityError=0; + c2.iHandshake |= KConfigFreeRTS; + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + test.Next(_L("Test Write(0) with remote RTS asserted completes")); + timer.After(timeStatus,10000000); + theSerialPorts[1]->SetSignals(KSignalRTS,0); + + User::WaitForRequest(timeStatus,writeStat); + if (writeStat==KRequestPending) + test.Printf(_L(" Timed out!\n")); + User::After(2000000); + + test(writeStat==KErrNone); + test(timeStatus==KRequestPending); + + timer.Cancel(); + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + test.End(); + } + + +void testSingleCharacterReads() +// +// Test reading one character at a time. +// + { + const TInt KWriteSize=100; + test.Start(_L("Test partial reads")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf0; + TCommConfigV01& c0=cBuf0(); + theSerialPorts[0]->Config(cBuf0); + + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[1]->Config(cBuf1); + + c0.iRate=c1.iRate=EBps9600; + c0.iParityError=c1.iParityError=0; + c0.iHandshake=c1.iHandshake=KConfigObeyCTS; + + c0.iDataBits=c1.iDataBits=EData8; + c0.iStopBits=c1.iStopBits=EStop1; + c0.iParity=c1.iParity=EParityNone; + + r=theSerialPorts[0]->SetConfig(cBuf0); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + test.Printf(_L("Setconfig OK\r\n")); + + TInt bufSiz=KWriteSize+3+(KWriteSize/2); + + r=theSerialPorts[0]->SetReceiveBufferLength(bufSiz); + if (r!=KErrNone) + test.Printf(_L("Setting buffers to %d bytes for com0 failed %d\n\r"),bufSiz,r); + r=theSerialPorts[1]->SetReceiveBufferLength(bufSiz+1); + if (r!=KErrNone) + test.Printf(_L("Setting buffers to %d bytes for com1 failed %d\n\r"),bufSiz,r); + + TUint8* singleCharReadBuf=new TUint8[1]; + test(singleCharReadBuf!=NULL); + TPtr8 singleCharReadDes(singleCharReadBuf,1,1); + TUint8* multiCharWriteBuf=new TUint8[KWriteSize]; + test(multiCharWriteBuf!=NULL); + TPtr8 multiCharWriteDes(multiCharWriteBuf,KWriteSize,KWriteSize); + multiCharWriteDes.Fill('m'); + + RTimer tim; + tim.CreateLocal(); + + for (TInt j=0;j<2;j++) + { + TInt readPort=0; + TInt writePort=0; + readPort=1-j; + writePort=j; + + TBuf<256> message; + message.Format(_L("Reading single chars from port %d, writing %d to port %d"),readPort,multiCharWriteDes.Length(),writePort); + test.Next(message); + + TRequestStatus readZeroStat; + theSerialPorts[readPort]->Read(readZeroStat,singleCharReadDes,0);//a zero length read completes immediately and + User::WaitForRequest(readZeroStat); //will wake up the receiver + test.Printf(_L("Have done a read zero: %d\n\r"),readZeroStat.Int()); + User::After(1000000); + + TRequestStatus multiWriteStat; + theSerialPorts[writePort]->Write(multiWriteStat,multiCharWriteDes); +// User::WaitForRequest(multiWriteStat); +// test.Printf(_L("Have done a write: %d\n\r"),multiWriteStat.Int()); + + TRequestStatus timStat; + TInt spin=0; + for (TInt i=0;iRead(readStat,singleCharReadDes); + User::WaitForRequest(readStat,timStat); + + test.Printf(_L("r")); + if (i%32==0) + test.Printf(_L("\r%c"),KSpinner[spin++%4]); + + if (readStat!=KErrNone) + { + TBuf<256> message; + if (readStat==KRequestPending) + { + message.Format(_L("\n\rRead timed out after %d chars (of %d)\n\r"),i,KWriteSize); + /*if (multiWriteStat==KErrNone) + { + User::WaitForRequest(multiWriteStat); + theSerialPorts[readPort]->ReadCancel(); + theSerialPorts[writePort]->Write(multiWriteStat,multiCharWriteDes); + }*/ + } + else + if (readStat!=KErrOverflow && readStat!=KErrCommsOverrun) + message.Format(_L("\n\rRead Failed %d after %d chars (of %d)\n\r"),readStat.Int(),i,KWriteSize); + + test.Printf(message); + User::After(2000000); + test(EFalse); + } + + tim.Cancel(); + if (singleCharReadDes[0]!='m') + { + test.Printf(_L("Received character: 0x%02x\n"),singleCharReadDes[0]); + test(EFalse); + } + } + + test.Printf(_L("Done\n\r")); + + tim.After(timStat,1000000); + User::WaitForRequest(timStat,multiWriteStat); + if (timStat.Int()==KErrNone) + { + test.Printf(_L("Lost at least one char!\n\r")); + theSerialPorts[writePort]->WriteCancel(); + test(EFalse); + } + else + { + tim.Cancel(); + } + } + + TUint8* singleCharWriteBuf=new TUint8[1]; + test(singleCharWriteBuf!=NULL); + TPtr8 singleCharWriteDes(singleCharWriteBuf,1,1); + singleCharWriteDes.Fill('s'); + TUint8* multiCharReadBuf=new TUint8[KWriteSize]; + test(multiCharReadBuf!=NULL); + TPtr8 multiCharReadDes(multiCharReadBuf,KWriteSize,KWriteSize); + + for (TInt k=0;k<2;k++) + { + TInt readPort=0; + TInt writePort=0; + + readPort=k; + writePort=1-k; + + TRequestStatus multiReadStat; + theSerialPorts[readPort]->Read(multiReadStat,multiCharReadDes); + + TBuf<256> message; + message.Format(_L("Writing single chars to port %d"),readPort); + test.Next(message); + + TRequestStatus timStat; + TInt spin=0; + for (TInt i=0;iWrite(writeStat,singleCharWriteDes); + User::WaitForRequest(writeStat,timStat); + + if ((i%32)==0) + test.Printf(_L("\r%c"),KSpinner[spin++%4]); + + if (writeStat!=KErrNone) + { + TBuf<256> message; + if (writeStat==KRequestPending) + message.Format(_L("\n\rWrite timed out after %d chars (of %d)\n\r"),i,KWriteSize); + else + message.Format(_L("\n\rWrite Failed %d after %d chars (of %d)\n\r"),writeStat.Int(),i,KWriteSize); + + test.Printf(message); + } + test(writeStat==KErrNone); + tim.Cancel(); + } + test.Printf(_L("Done\n\r")); + + tim.After(timStat,1000000); + User::WaitForRequest(timStat,multiReadStat); + if (timStat.Int()==KErrNone) + { + test.Printf(_L("Lost at least one char!\n\r")); + theSerialPorts[readPort]->ReadCancel(); + test(EFalse); + } + else + { + tim.Cancel(); + test(multiReadStat==KErrNone); + test(multiCharWriteDes.Length()==multiCharWriteDes.MaxLength()); + } + } + + test.End(); + tim.Close(); + + delete [] multiCharWriteBuf; + delete [] singleCharReadBuf; + delete [] singleCharWriteBuf; + delete [] multiCharReadBuf; + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + } + +void testBiDirectionalSingleCharacterReads() +// +// Test reading and writing one character at a time. +// + { + + test.Start(_L("Test concurrent partial reads and writes")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf0; + TCommConfigV01& c0=cBuf0(); + theSerialPorts[0]->Config(cBuf0); + + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[1]->Config(cBuf1); + + c0.iRate=c1.iRate=EBps9600; + c0.iParityError=c1.iParityError=0; + c0.iHandshake=c1.iHandshake=KConfigObeyCTS; + + c0.iDataBits=c1.iDataBits=EData8; + c0.iStopBits=c1.iStopBits=EStop1; + c0.iParity=c1.iParity=EParityNone; + + r=theSerialPorts[0]->SetConfig(cBuf0); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + + const TInt KWriteSize=4000; + TUint8* singleCharReadBuf=new TUint8[1]; + test(singleCharReadBuf!=NULL); + TPtr8 singleCharReadDes(singleCharReadBuf,1,1); + TUint8* multiCharWriteBuf=new TUint8[KWriteSize]; + test(multiCharWriteBuf!=NULL); + TPtr8 multiCharWriteDes(multiCharWriteBuf,KWriteSize,KWriteSize); + multiCharWriteDes.Fill('m'); + TUint8* singleCharWriteBuf=new TUint8[1]; + test(singleCharWriteBuf!=NULL); + TPtr8 singleCharWriteDes(singleCharWriteBuf,1,1); + singleCharWriteDes.Fill('s'); + TUint8* multiCharReadBuf=new TUint8[KWriteSize]; + test(multiCharReadBuf!=NULL); + TPtr8 multiCharReadDes(multiCharReadBuf,KWriteSize,KWriteSize); + + TRequestStatus multiWriteStat; + TRequestStatus multiReadStat; + theSerialPorts[0]->Write(multiWriteStat,multiCharWriteDes); + theSerialPorts[0]->Read(multiReadStat,multiCharReadDes); + + TInt spin=0; + for (TInt i=0;iRead(readStat,singleCharReadDes); + theSerialPorts[1]->Write(writeStat,singleCharWriteDes); + User::WaitForRequest(readStat); + User::WaitForRequest(writeStat); + + if (readStat!=KErrNone) + { + test.Printf(_L("Read Failed %d after %d chars\n\r"),readStat.Int(),i); + test(EFalse); + } + if (writeStat!=KErrNone) + { + test.Printf(_L("Write Failed %d after %d chars\n\r"),writeStat.Int(),i); + test(EFalse); + } + } + + test.Printf(_L("\n\r")); + + RTimer tim; + tim.CreateLocal(); + TRequestStatus timStat; + tim.After(timStat,3000000); + User::WaitForRequest(multiWriteStat,timStat); + test(timStat==KRequestPending); + tim.Cancel(); + User::WaitForRequest(timStat); + test(timStat==KErrCancel); + test(multiWriteStat==KErrNone); + tim.After(timStat,3000000); + User::WaitForRequest(multiReadStat,timStat); + test(timStat==KRequestPending); + tim.Cancel(); + tim.Close(); + User::WaitForRequest(timStat); + test(timStat==KErrCancel); + test(multiReadStat==KErrNone); + test(multiCharWriteDes.Length()==multiCharWriteDes.MaxLength()); + + test.End(); + + delete [] multiCharWriteBuf; + delete [] singleCharReadBuf; + delete [] singleCharWriteBuf; + delete [] multiCharReadBuf; + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + } + +void testMultiTerminatorCompletion() +// +// Test multiple terminator completions +// + { + test.Next(_L("Test partial reads with terminators")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + TCommConfig cBuf0; + TCommConfigV01& c0=cBuf0(); + theSerialPorts[0]->Config(cBuf0); + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[1]->Config(cBuf1); + + c0.iRate=c1.iRate=EBps9600; + c0.iParityError=c1.iParityError=0; + + c0.iHandshake=c1.iHandshake=KConfigObeyCTS; + + c0.iDataBits=c1.iDataBits=EData8; + c0.iStopBits=c1.iStopBits=EStop1; + c0.iParity=c1.iParity=EParityNone; + + r=theSerialPorts[0]->SetConfig(cBuf0); + test(r==KErrNone); + c1.iTerminator[0]='a'; + c1.iTerminatorCount=1; + r=theSerialPorts[1]->SetConfig(cBuf1); + test(r==KErrNone); + const TInt KWriteSize=4000; + TUint8* writeBuf=new TUint8[KWriteSize]; + test(writeBuf!=NULL); + TPtr8 writeDes(writeBuf,KWriteSize,KWriteSize); + writeDes.Fill('a'); + TUint8* readBuf=new TUint8[KWriteSize]; + test(readBuf!=NULL); + TPtr8 readDes(readBuf,KWriteSize,KWriteSize); + TRequestStatus writeStat; + theSerialPorts[0]->Write(writeStat,writeDes); + test(writeStat==KRequestPending); + TInt spin=0; + for (TInt i=0;iRead(readStat,readDes); + User::WaitForRequest(readStat); + test(readStat==KErrNone); + test(readDes.Length()==1); + } + test.Printf(_L("\n\r")); + User::WaitForRequest(writeStat); + + delete [] readBuf; + delete [] writeBuf; + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + } + +void TestSimpleWriting() + { + test.Next(_L("Test we can still write 0->1")); + const TPtrC8 string1=_L8("If you strike me down, I shall become more powerful than you can possibly imagine."); + TBuf8<100> inBuf; + TRequestStatus stat; + theSerialPorts[1]->Read(stat,inBuf,string1.Length()); + test(stat==KRequestPending); + TInt r=theSerialPorts[0]->WriteS(string1,string1.Length()); + test(r==KErrNone); + User::WaitForRequest(stat); + test(stat==KErrNone); + test(inBuf==string1); + + test.Next(_L("Test we can still write 1->0")); + const TPtrC8 string2=_L8("Who's the more foolish... the fool or the fool who follows him?"); + theSerialPorts[0]->Read(stat,inBuf,string2.Length()); + test(stat==KRequestPending); + r=theSerialPorts[1]->WriteS(string2,string2.Length()); + test(r==KErrNone); + User::WaitForRequest(stat); + test(stat==KErrNone); + test(inBuf==string2); + } + +void TestPower() + { + test.Next(_L("Power up and down")); + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + test.Start(_L("Power down while writing 0->1")); + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[0]->Config(cBuf1); + TCommConfig cBuf2; + TCommConfigV01& c2=cBuf2(); + theSerialPorts[1]->Config(cBuf2); + c1.iFifo=EFifoEnable; + + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityEven; + c1.iRate=c2.iRate=EBps19200; + c1.iHandshake=c2.iHandshake=0; + + r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + RTimer timer; + test(timer.CreateLocal()==KErrNone); + TTime wakeup; + wakeup.HomeTime(); + wakeup+=TTimeIntervalSeconds(10); + TRequestStatus done; + timer.At(done,wakeup); + test(done==KRequestPending); + RAsyncSwitchOff async; + r=async.Start(2000000); + test(r==KErrNone); + +// test(PowerCheckedWrite(KWriteSize*200)==KErrNone); + + const TUint bigWriteSize=KWriteSize*200; + TUint8* inBuf=new TUint8[bigWriteSize]; + test(inBuf!=NULL); + TUint8* outBuf=new TUint8[bigWriteSize]; + test(outBuf!=NULL); + TPtr8 outDes(outBuf,bigWriteSize,bigWriteSize); + TPtr8 inDes(inBuf,bigWriteSize,bigWriteSize); + + RTimer tim; + tim.CreateLocal(); + TRequestStatus readStatus; + TRequestStatus timeStatus; + + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + theSerialPorts[0]->Read(readStatus,inDes,bigWriteSize); + test(readStatus==KRequestPending); + + test.Printf(_L("Write.........")); + r=theSerialPorts[1]->WriteS(outDes,bigWriteSize); + test(r==KErrAbort); + test.Printf(_L("Aborted by power down\n")); + r=async.Wait(); + test(r==KErrNone); + r=async.Start(2000000); + test(r==KErrNone); + const TUint KTimeOut=6000000; + tim.After(timeStatus,KTimeOut); + User::WaitForRequest(readStatus,timeStatus); + if (timeStatus==KErrNone) + { + test.Printf(_L("Timed Out!\n\r")); + theSerialPorts[0]->ReadCancel(); + test(EFalse); + } + tim.Cancel(); + test(readStatus==KErrAbort); + r=async.Wait(); + test(r==KErrNone); + + User::WaitForRequest(done); + test(done==KErrNone); + + test.Next(_L("Reset config")); + TestSimpleWriting(); + test.Next(_L("Close and reopen")); + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + + theSerialPorts[0]->Config(cBuf1); + theSerialPorts[1]->Config(cBuf2); + c1.iFifo=EFifoEnable; + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityNone; + c1.iRate=c2.iRate=EBps19200; + c1.iHandshake=c2.iHandshake=0; + + r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + TestSimpleWriting(); + + test.Next(_L("Power down while writing 1->0")); + theSerialPorts[0]->Config(cBuf1); + theSerialPorts[1]->Config(cBuf2); + c1.iFifo=EFifoEnable; + + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityEven; + c1.iRate=c2.iRate=EBps9600; + c1.iHandshake=c2.iHandshake=0; + + r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + wakeup.HomeTime(); + wakeup+=TTimeIntervalSeconds(10); + timer.At(done,wakeup); + test(done==KRequestPending); + r=async.Start(2000000); + test(r==KErrNone); + +// test(PowerCheckedWrite(KWriteSize*200)==KErrNone); + StripeMem(outDes,'A','Z'); + inDes.FillZ(); + + theSerialPorts[1]->Read(readStatus,inDes,bigWriteSize); + test(readStatus==KRequestPending); + + test.Printf(_L("Write.........")); + r=theSerialPorts[0]->WriteS(outDes,bigWriteSize); + test(r==KErrAbort); + test.Printf(_L("Aborted by power down\n")); + tim.After(timeStatus,KTimeOut); + User::WaitForRequest(readStatus,timeStatus); + if (timeStatus==KErrNone) + { + test.Printf(_L("Timed Out!\n\r")); + theSerialPorts[1]->ReadCancel(); + test(EFalse); + } + tim.Cancel(); + CHECK(readStatus.Int(),KErrAbort); + r=async.Wait(); + test(r==KErrNone); + + User::WaitForRequest(done); + test(done==KErrNone); + + test.Next(_L("Reset config")); + TestSimpleWriting(); + test.Next(_L("Close and reopen")); + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + theSerialPorts[0]->Config(cBuf1); + theSerialPorts[1]->Config(cBuf2); + c1.iFifo=EFifoEnable; + c2.iDataBits=c1.iDataBits=EData8; + c2.iStopBits=c1.iStopBits=EStop1; + c2.iParity=c1.iParity=EParityNone; + c1.iRate=c2.iRate=EBps19200; + c1.iHandshake=c2.iHandshake=0; + + r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + TestSimpleWriting(); + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + test.Next(_L("Test signals are preserved")); + + r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + r=theSerialPorts[1]->Open(PortB); + test(r==KErrNone); + r=theSerialPorts[1]->QueryReceiveBuffer(); + test(r==0); + + if((theCaps1.iHandshake & KCapsFreeRTSSupported) && (theCaps2.iHandshake & KCapsFreeRTSSupported)) + {//should also check for KConfigFreeDTR + theSerialPorts[0]->Config(cBuf1); + theSerialPorts[1]->Config(cBuf2); + + c1.iHandshake=KConfigFreeRTS|KConfigFreeDTR; + c2.iHandshake=KConfigFreeRTS|KConfigFreeDTR; + r=theSerialPorts[0]->SetConfig(cBuf1); + CHECK(r,KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf2); + CHECK(r,KErrNone); + + theSerialPorts[0]->SetSignals(KSignalRTS,KSignalDTR); + theSerialPorts[1]->SetSignals(KSignalDTR,KSignalRTS); + + TUint signals=theSerialPorts[0]->Signals(); + //test(signals==(KSignalRTS|KSignalDSR));//something weird happens here under WINS - the CD line is set(?) + CHECK((signals&(KSignalRTS|KSignalDSR)) , (KSignalRTS|KSignalDSR)); + signals=theSerialPorts[1]->Signals(); + CHECK(signals,(KSignalDTR|KSignalCTS)); + + wakeup.HomeTime(); + wakeup+=TTimeIntervalSeconds(10); + timer.At(done,wakeup); + r=async.Start(5000000); + CHECK(r,KErrNone); + test(done==KRequestPending); + User::WaitForRequest(done); + test(done==KErrNone); + r=async.Wait(); + CHECK(r,KErrNone); + + User::After(100000); // wait for both ports to power back up + signals=theSerialPorts[0]->Signals(); + //test(signals==(KSignalRTS|KSignalDSR)); + CHECK((signals&(KSignalRTS|KSignalDSR)) , (KSignalRTS|KSignalDSR)); + signals=theSerialPorts[1]->Signals(); + CHECK(signals,(KSignalDTR|KSignalCTS)); + } + + c1.iHandshake=0; + c2.iHandshake=0; + r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + r=theSerialPorts[1]->SetConfig(cBuf2); + test(r==KErrNone); + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + test.End(); + } + +void testSwitchIrDA() + { + test.Next(_L("Switch to IrDA")); +//Open the serial port channel. + + TInt r=theSerialPorts[0]->Open(PortA); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + + theSerialPorts[0]->Caps(theCaps1Buf); + if (!(theCaps1.iSIR&KCapsSIR115kbps)) + { + theSerialPorts[0]->Close(); + test.Printf(_L("\t\tIrDA not supported\n")); + return; + } + + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + + +//Configure the channel for IrDA at 115.2k baud. + TCommConfig cBuf1; + TCommConfigV01& c1=cBuf1(); + theSerialPorts[0]->Config(cBuf1); + c1.iSIREnable=ESIREnable; + c1.iRate=EBps115200; + c1.iDataBits=EData8; + c1.iParity=EParityNone; + c1.iStopBits=EStop1; + c1.iHandshake=0; + c1.iHandshake|=KConfigFreeDTR; + c1.iHandshake|=KConfigFreeRTS; + r=theSerialPorts[0]->SetConfig(cBuf1); + test(r==KErrNone); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test(r==0); + const TUint8 KData[1] ={0x00}; + const TPtrC8 KDataPtr(KData,1); + TRequestStatus stat; + theSerialPorts[0]->Write(stat,KDataPtr); + User::WaitForRequest(stat); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test.Printf(_L("ReceiveBuf = %d\n"),r); +// test(r==0); + + theSerialPorts[0]->Write(stat,KDataPtr); + User::WaitForRequest(stat); + User::After(1000000); + r=theSerialPorts[0]->QueryReceiveBuffer(); + test.Printf(_L("ReceiveBuf = %d\n"),r); + while (theSerialPorts[0]->QueryReceiveBuffer()) + { + TBuf8<1> buf; + theSerialPorts[0]->Read(stat,buf,1); + test.Printf(_L("Data = "),&buf); + User::WaitForRequest(stat); + test.Printf(_L("%d\n"),buf[0]); + } + r=theSerialPorts[0]->QueryReceiveBuffer(); + test.Printf(_L("ReceiveBuf = %d\n"),r); + theSerialPorts[0]->Write(stat,KDataPtr); + User::WaitForRequest(stat); +//Check for any received data pending (the answer is 1! Which is incorrect as nothing has sent me any IrDA data) + r=theSerialPorts[0]->QueryReceiveBuffer(); + test.Printf(_L("ReceiveBuf = %d\n"),r); +// test(r==0); + theSerialPorts[0]->Write(stat,KDataPtr); + User::WaitForRequest(stat); + User::After(1000000); + r=theSerialPorts[0]->QueryReceiveBuffer(); + + theSerialPorts[0]->Close(); + } + +GLDEF_C TInt E32Main() +// +// +// + { + +#if defined (__WINS__) + test.SetLogged(ETrue); // log to $TEMP/EPOCWIND.OUT +#else + test.SetLogged(EFalse); //turn off serial port debugging! +#endif + + + test.Title(); + test.Start(_L("Serial loopback test")); + + TInt muid=0; + test(HAL::Get(HAL::EMachineUid, muid)==KErrNone); +//CF + TBool isAssabet=(muid==HAL::EMachineUid_Assabet); + + PortA=0; + PortB=3; // used to be 1 but it apparently doesn't exist + TBuf <0x100> cmd; + User::CommandLine(cmd); + + TBool stress = EFalse; + if (cmd.Length()>0) + { + if (cmd.Length() == 1) + { + if ((cmd[0] == 'S') || (cmd[0] == 's')) + stress = ETrue; + } + else + { + if (cmd[0]>='0' && cmd[0]<='9') + PortA=(TInt)(cmd[0]-'0'); + if (cmd[2]>='0' && cmd[2]<='9') + PortB=(TInt)(cmd[2]-'0'); + if ((cmd[cmd.Length()-1] == 'S') || (cmd[cmd.Length()-1] == 's')) + stress = ETrue; + } + } + + + test.Printf(_L("Primary Port:%d Secondary Port:%d\n\r"),PortA,PortB); + + + TInt r; + TBuf<10> pddName=PDD_NAME; + test.Next(_L("Load PDDs")); +#ifdef __WINS__ + const TInt KMaxPdds=0; +#else + const TInt KMaxPdds=10; +#endif + TInt i; + for (i=-1; i0) + pddName[pddName.Length()-1] = (TText)('0'+i); + r=User::LoadPhysicalDevice(pddName); + if (r==KErrNone || r==KErrAlreadyExists) + test.Printf(_L("PDD %S loaded\n"),&pddName); + } + + test.Next(_L("Load LDD")); + r=User::LoadLogicalDevice(LDD_NAME); + test.Printf(_L("Load LDD Return %d\n\r"),r); + + test.Next(_L("Create RComm objects")); + theSerialPorts[0]=new RComm; + theSerialPorts[1]=new RComm; + test(theSerialPorts[0]!=NULL); + test(theSerialPorts[1]!=NULL); +// + + do + { + + test.Next(_L("Open:")); + r=theSerialPorts[0]->Open(PortA); + test.Printf(_L("Open(Unit0)=%d\n\r"),r); + test(r==KErrNone); + r=theSerialPorts[1]->Open(PortB); + test.Printf(_L("Open(Unit1)=%d\n\r"),r); + test(r==KErrNone); + + test.Next(_L("Get caps")); + theSerialPorts[0]->Caps(theCaps1Buf); + test(r==KErrNone); + theSerialPorts[1]->Caps(theCaps2Buf); + test(r==KErrNone); + + theSerialPorts[0]->Close(); + theSerialPorts[1]->Close(); + + testReadWrite(); + + // testTiming(); + + turnaroundTestReadWrite(); + + testTerminators(); + testHWHandshaking(); + + if((theCaps1.iHandshake & KCapsObeyXoffSupported) && (theCaps2.iHandshake & KCapsObeyXoffSupported)) + testXonXoff(); + + if((theCaps1.iHandshake & KCapsObeyCTSSupported) && (theCaps2.iHandshake & KCapsObeyCTSSupported)) + { + testSingleCharacterReads(); + testWriteZero(); + //CF - see description of problem with testTerminators() + if (!isAssabet) testMultiTerminatorCompletion(); + testBiDirectionalSingleCharacterReads(); + } + + testFraming(); + testBreak(); + testSwitchIrDA(); + } while (stress); + + User::After(3000000); + test.End(); + return(KErrNone); + }