--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/device/t_serial.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -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 <e32base.h>
+#include <e32base_private.h>
+#include <e32test.h>
+#include <e32cons.h>
+#include <e32svr.h>
+#include <e32hal.h>
+#include <d32comm.h>
+#include <e32uid.h>
+#include <hal.h>
+#include "d_lddturnaroundtimertest.h"
+#include <u32hal.h>
+
+//#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;i<aBuf.Length();i++)
+ {
+ aBuf[i]=(TText8)character;
+ if(++character>anEndChar)
+ 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)
+ {
+ TInt v=aLeft[(i*8)+j];
+ buf.AppendFormat(_L8("%02x "),v);
+ }
+ else
+ buf.AppendFormat(_L8(" "));
+ }
+ buf.AppendFormat(_L8(" | "));
+ for (TInt k=0;k<8;k++)
+ {
+ if ((i*8)+k>=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;i<numTests;i++)
+ {
+ if (theCaps1.iRate&KSpeeds[i].iMask && theCaps2.iRate&KSpeeds[i].iMask)
+ {
+ mess.Format(_L("read/write @ %s Bps"),KSpeeds[i].iName);
+ test.Next(mess);
+ 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("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;i<KSamples;i++)
+ {
+ test.Printf(_L("."));
+
+ TUint8* inBuf=new TUint8[KBufSize];
+ TUint8* outBuf=new TUint8[KBufSize];
+ TPtr8 outDes(outBuf,KBufSize,KBufSize);
+ TPtr8 inDes(inBuf,KBufSize,KBufSize);
+
+
+ RTimer tim;
+ tim.CreateLocal();
+ TRequestStatus readStatus;
+ TRequestStatus timeStatus;
+
+ StripeMem(outDes,'A','Z');
+ inDes.FillZ();
+
+ TTime startTime;
+ startTime.HomeTime();
+ for (TInt l=0;l<KNumWrites;l++)
+ {
+ inDes.SetLength(KBufSize/3);
+ theSerialPorts[0]->Read(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<KSamples;j++)
+ {
+ avg=avg+samples[j];
+ }
+ avg/=KSamples;
+ test.Printf(_L(" Average time = %d ms\n\r"),avg);
+ test.Printf(_L("Press a key\n\r"));
+ test.Getch();
+
+ test.End();
+ }
+
+void testBreak()
+///
+/// Tests serial breaks
+///
+ {
+ TBuf<256> 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;i<numTests;i++)
+ {
+ c0.iDataBits=KFrameTypes[i].iData;
+ c0.iStopBits=KFrameTypes[i].iStop;
+ c0.iParity=KFrameTypes[i].iParity;
+ TInt r=theSerialPorts[0]->SetConfig(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;i<KXonNumReads-1;++i)
+ {
+ inDes.FillZ();
+ timer.After(timeStatus,450000);
+ User::WaitForRequest(timeStatus);
+ test(timeStatus==KErrNone);
+
+ test.Printf(_L("Reading after delay (%d of %d) avail = %d\n\r"),i+2,KXonNumReads, theSerialPorts[0]->QueryReceiveBuffer());
+ 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;j<numTests;j++)
+ {
+ mess.Format(_L("read/write using %s "),KHandshakes[j].iName);
+ test.Next(mess);
+ c0.iHandshake=c1.iHandshake=KHandshakes[j].iHandshake;
+
+ if((theCaps1.iHandshake & KHandshakes[j].iHandshake)
+ && (theCaps2.iHandshake & KHandshakes[j].iHandshake))
+ {
+ test(theSerialPorts[0]->SetConfig(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;i<KXonNumReads;i++)
+ {
+ inDes.FillZ();
+#if defined (__WINS__)
+ User::After(600000);
+#else
+ User::After(300000);
+#endif
+ test.Printf(_L("Reading %d after delay (%d of %d) avail = %d\r\n"),KHWReadSize, i+1,KXonNumReads, theSerialPorts[0]->QueryReceiveBuffer());
+ 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;i<KWriteSize;i++)
+ {
+ tim.After(timStat,10000000);
+ TRequestStatus readStat;
+ singleCharReadDes.SetLength(0);
+ theSerialPorts[readPort]->Read(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;i<KWriteSize;i++)
+ {
+ TRequestStatus writeStat;
+ tim.After(timStat,5000000);
+ theSerialPorts[writePort]->Write(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;i<KWriteSize;i++)
+ {
+ if (i%32==0)
+ test.Printf(_L("\r%c"),KSpinner[spin++%4]);
+
+ TRequestStatus readStat;
+ TRequestStatus writeStat;
+ theSerialPorts[1]->Read(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;i<KWriteSize;i++)
+ {
+ if (i%32==0)
+ test.Printf(_L("\r%c"),KSpinner[spin++%4]);
+ TRequestStatus readStat;
+ readDes.SetLength(KWriteSize/2);
+ theSerialPorts[1]->Read(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; i<KMaxPdds; ++i)
+ {
+ if (i==0)
+ pddName.Append(TChar('0'));
+ else if (i>0)
+ 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);
+ }