usbmgmt/usbmgrtest/t_acm_wins/src/t_acm_wins.cpp
changeset 0 c9bc50fca66e
child 15 f92a4f87e424
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgrtest/t_acm_wins/src/t_acm_wins.cpp	Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,920 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+* This program executes all the tests in the ACM CSY Test Specification v 0.1
+* on the host, and is to be used in conjunction with the device-side application (t_acm).
+*
+*/
+
+// Includes ////////////////////////////////////////////////////////////////////
+
+/* Symbian OS includes */
+#include <e32base.h>
+#include <e32cons.h>
+#include <e32math.h>
+
+#define WIN32_LEAN_AND_MEAN
+
+/* Windows i/o for serial device */
+#include <windows.h>
+#include <wchar.h>
+
+// Defines and enumerations /////////////////////////////////////////////////////
+
+#define _printf console->Printf
+#define _getch console->Getch
+#define LEAVE(_x) VerboseLeaveL(_x, __LINE__, TPtrC8((const TUint8*)__FILE__), _L8(#_x))
+#define LEAVEIFERROR(_x) VerboseLeaveIfErrorL(_x, __LINE__, TPtrC8((const TUint8*)__FILE__), _L8(#_x))
+#define CHECK(_x) if (! (_x)) VerboseLeaveL(KErrGeneral, __LINE__, TPtrC8((const TUint8*)__FILE__), _L8(#_x))
+
+#define MAX_BUFFER_SIZE 1024
+
+// Flow control constants
+enum	FlowControl_Modes {KFLOW_NONE, KFLOW_RTSCTS, KFLOW_DTRDSR};
+
+// Global Variables /////////////////////////////////////////////////////////////
+
+HANDLE	hSerial;	// An MS Windows handle for the serial port
+DCB		OldDcb;		// for storing the original serial device context
+DCB		newDcb;
+
+// For holding our new serial port parameteres
+struct SerialParameters
+	{
+	char			*comport;					// which port
+	unsigned long	pktsize, pktcount, maxwait;	// packet config
+	unsigned long	baud, bits, stop;			// serial parameters
+	unsigned char	parity;
+	enum	FlowControl_Modes	flowcontrol;	// flow control handshaking
+} SerialParams;
+
+LOCAL_D CConsoleBase* console;	// A Symbian command console
+
+_LIT(KPortName, "COM3");		// Windows serial port name
+
+RTimer timer;	// A timer for use by several of the tests
+
+// Some buffers allocated on the heap for functions with large
+// stack usage so we don't get a __chkstk error.
+char writeBufbig[MAX_BUFFER_SIZE];
+char readBufbig[MAX_BUFFER_SIZE];
+
+// Functions //////////////////////////////////////////////////////////////////
+
+void VerboseLeaveL(TInt aError, TInt aLineNum, const TDesC8& aFileName, const TDesC8& aCode)
+/**
+ * For bombing out usefully.
+ */
+	{
+	TInt filenameOffset = aFileName.LocateReverse('\\') + 1;
+	if (filenameOffset < 0) filenameOffset = 1;
+	TPtrC8 shortFileName = aFileName.Mid(filenameOffset);
+	TBuf<64> fName, code;
+	fName.Copy(shortFileName.Left(64));
+	code.Copy(aCode.Left(64));
+	_printf(_L("ERROR (%d) on line %d of file %S\n"), aError, aLineNum, &fName);
+	_printf(_L("Code: %S\n\n"), &code);
+	_printf(_L("[ press any key ]"));
+	_getch();
+	User::Leave(aError);
+	}
+
+void VerboseLeaveIfErrorL(TInt aError, TInt aLineNum, const TDesC8& aFileName, const TDesC8& aCode)
+/**
+ * For bombing out usefully if there's an error.
+ */
+	{
+	if (aError) 
+		VerboseLeaveL(aError, aLineNum, aFileName, aCode);
+	}
+
+void SetWindowsSerialParams()
+/**
+ * Set up the new serial parameters with which to run the tests.
+ */
+{
+	// parameter 1 is port name
+	// read in COM port name (this parameter must be specified!)
+	SerialParams.comport = new char[10];
+	strcpy(SerialParams.comport, "COM3");
+
+	// default packet size
+	SerialParams.pktsize = 1024;
+
+	// default no of packets
+	SerialParams.pktcount = 1;
+
+	// default wait for data return
+	SerialParams.maxwait = 30;
+
+	// default flow control
+	SerialParams.flowcontrol = KFLOW_RTSCTS;
+
+	// default data rate
+	// baud rate 0 (port's default) standard rates 300 -> 115200
+	SerialParams.baud = 0;
+
+	// default bits per char
+	SerialParams.bits = 8;
+
+	// default parity
+	SerialParams.parity = 'N';
+
+	// default 9 is stop bits
+	SerialParams.stop = 1;
+}
+
+static int	InitializePort()
+/**
+ * Store the old state of the serial port and set it up for our tests.
+ */
+{
+	DCB				dcb;
+	COMMTIMEOUTS	CommsTimeouts;
+
+	// Setup comms device receive & transmit buffers
+	if(SetupComm(hSerial, 16384, 16384) == 0)
+	{
+		LEAVE(-1);
+	}
+
+	// Purge all characters from the output and input buffers
+	// and terminate any pending read or write operations 
+	if(PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR) == 0)
+	{
+		LEAVE(-1);
+	}
+
+	dcb.DCBlength = sizeof(DCB);
+	if(GetCommState(hSerial, &dcb) == 0)
+	{
+		// not a serial device
+		LEAVE(-1);
+	}
+
+    memcpy(&OldDcb, &dcb, sizeof(DCB));
+
+	// General initialization for both transmitted and received bytes
+	// using port's default baud rate etc..., so read it
+	SerialParams.baud = dcb.BaudRate;		// Get baud rate 
+	SerialParams.bits = dcb.ByteSize;		// Get number of bits 
+	if(dcb.StopBits == 2)					// Get number of stop bits to be used
+		SerialParams.stop = 2;
+	else
+		SerialParams.stop = 1;
+
+	// Get parity scheme
+	if((dcb.fParity == FALSE) || (dcb.Parity == 0))
+	{
+		SerialParams.parity = 'N';
+	}
+	else
+	{
+		switch(dcb.Parity)
+		{
+		case 1:	SerialParams.parity = 'O'; break;
+		case 2:	SerialParams.parity = 'E'; break;
+		case 3:	SerialParams.parity = 'M'; break;
+		case 4:	SerialParams.parity = 'S'; break;
+		default:	SerialParams.parity = 'N'; break;  // shouldn't happen
+		}
+	}
+	dcb.fBinary = TRUE;				// Set binary mode 
+
+	// Setup hardware flow control
+	if(SerialParams.flowcontrol == KFLOW_RTSCTS)
+	{
+		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;	// Specify the type of RTS flow control
+		dcb.fOutxCtsFlow = 1;						// Specify whether the CTS signal is monitored
+
+		dcb.fDtrControl = DTR_CONTROL_ENABLE;	// Specify the type of DTR flow control
+		dcb.fOutxDsrFlow = 0;					// Specify whether the DSR signal is monitored
+	}
+	else if(SerialParams.flowcontrol == KFLOW_DTRDSR)
+	{
+		dcb.fRtsControl = RTS_CONTROL_ENABLE;	// Specify the type of RTS flow control
+		dcb.fOutxCtsFlow = 0;						// Specify whether the CTS signal is monitored
+
+		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;// Specify the type of DTR flow control
+		dcb.fOutxDsrFlow = 1;					// Specify whether the DSR signal is monitored
+	}
+	else // KFLOW_NONE
+	{
+		dcb.fRtsControl = RTS_CONTROL_ENABLE;	// Specify the type of RTS flow control
+		dcb.fOutxCtsFlow = 0;					// Specify whether the CTS signal is monitored
+
+		dcb.fDtrControl = DTR_CONTROL_ENABLE;	// Specify the type of DTR flow control
+		dcb.fOutxDsrFlow = 0;					// Specify whether the DSR signal is monitored
+	}
+
+	dcb.fInX = dcb.fOutX = 0;
+	dcb.fDsrSensitivity = 0;
+	dcb.fErrorChar = 0;
+	dcb.fNull = 0;
+	dcb.fAbortOnError = 1;
+
+	// Configure the communications device according 
+	// to the specifications in the device-control block
+	// The function reinitializes all hardware and control settings, 
+	// but does not empty output or input queues
+	if(SetCommState(hSerial, &dcb) == 0)
+	{
+		LEAVE(-1);
+	}
+
+	// Set timeout parameters for comms device
+	/* A value of MAXDWORD, combined with zero values for both the 
+	 * ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, 
+	 * specifies that the read operation is to return immediately with 
+	 * the characters that have already been received, even if no characters 
+	 * have been received.
+	 */
+
+	CommsTimeouts.ReadIntervalTimeout = 0xFFFFFFFF;
+	CommsTimeouts.ReadTotalTimeoutMultiplier = 0;
+	CommsTimeouts.ReadTotalTimeoutConstant = 1000;
+
+	// CBR_9600 is approximately 1byte/ms. For our purposes be generous 
+	// & allow double the expected time per character
+	if(SerialParams.maxwait > 1)
+	{
+		CommsTimeouts.WriteTotalTimeoutMultiplier = 0;
+		CommsTimeouts.WriteTotalTimeoutConstant = (SerialParams.maxwait - 1) * 1000;
+	}
+	else
+	{
+		CommsTimeouts.WriteTotalTimeoutMultiplier = 2*CBR_9600/dcb.BaudRate;
+		CommsTimeouts.WriteTotalTimeoutConstant = 1000;
+	}
+
+	if(0 == SetCommTimeouts(hSerial, &CommsTimeouts))
+	{
+		LEAVE(-1);
+	}
+
+	if(0 == SetCommMask(hSerial, EV_RXCHAR | EV_ERR /* | EV_TXEMPTY */))
+	{
+		LEAVE(-1);
+	}
+
+	return 0;
+}
+
+void OpenComPort()
+/**
+ * Create a Windows com port for our serial device.
+ */
+{
+	hSerial = INVALID_HANDLE_VALUE;
+	wchar_t  *fullname = new wchar_t[50];
+    
+	// Open comms device
+	wcscpy(fullname, L"\\\\.\\com3");
+	hSerial = CreateFile(fullname,
+						 GENERIC_READ | GENERIC_WRITE,
+						 0,                    // exclusive access
+						 NULL,                 // no security attrs
+						 OPEN_EXISTING,
+						 FILE_ATTRIBUTE_NORMAL,
+						 NULL ) ;
+
+	// return if handle for comms device is invalid
+	if (hSerial == INVALID_HANDLE_VALUE)
+	{
+		delete[] fullname;
+		LEAVE(GetLastError());
+	}
+	else 
+	{
+		if(InitializePort())
+		{
+			// Close comms device and event handles for overlapped read and write
+			CloseHandle(hSerial);
+			hSerial = INVALID_HANDLE_VALUE;
+		}
+	}
+	delete[] fullname;
+}
+
+void FillBuffer(char *buffer, int size)
+/**
+ * Fills the buffer with incrementing data
+ */
+	{
+	for (TInt i=0; i<size; i++)
+		{
+		// Need the & 0xff to remove the truncation warning
+		buffer[i] = (char)((i%256) & 0xff);
+		}
+	}
+
+bool CheckBuffer(char *buffer, int size)
+/**
+ * Checks the buffer is filled with incrementing data
+ */
+	{
+	for (TInt i=0; i<size; i++)
+		{
+		if (buffer[i] != i%256)
+		return FALSE;
+		}
+
+	return TRUE;
+	}
+
+void ReadData(char *RxBuffer, int size)
+/**
+ * Read the given amount of data into a buffer from the serial port.
+ */
+{
+	unsigned long Count;
+	long total = 0;
+
+	while (total < size) {
+	  if(ReadFile(hSerial, RxBuffer, size, &Count, NULL) == 0)
+	  {
+		_printf(_L("ReadFile() returned error code: %d.\n"), GetLastError());
+	  }
+	  else
+	  {
+		total += Count;
+	  }
+	}
+
+}
+
+void WriteData(char *TxBuffer, int size)
+/**
+ * Write the given data over the serial port.
+ */
+{
+	unsigned long TxCount;
+
+	if(WriteFile(hSerial, TxBuffer, size, &TxCount, NULL) == 0)
+	{
+		_printf(_L("WriteFile() returned error code: %d.\n"), GetLastError());
+	}
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+void DataStress_SizeVary_TestL()
+/**
+ * Perform a single test.
+ */
+	{
+	_printf(_L("\n----------------------------------\n"));
+	_printf(_L("This test performs varying size read\n"));
+	_printf(_L("and writes to and from the device.\n"));
+	_printf(_L("------------------------------------\n\n"));
+
+	// Purge all characters from the output and input buffers
+	// and terminate any pending read or write operations 
+	if(PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR) == 0)
+		{
+		CloseHandle(hSerial);
+		LEAVE(-1);
+		}
+
+	_printf(_L("Writing data\n"));
+	for (int i = 1; i<MAX_BUFFER_SIZE; i*=2)
+		{
+		FillBuffer(writeBufbig, i);
+		WriteData(writeBufbig, i);
+		}
+
+	_printf(_L("Writing more data\n"));
+	for (int i = 1; i<MAX_BUFFER_SIZE; i*=2)
+		{	
+		FillBuffer(writeBufbig, i);
+		WriteData(writeBufbig, i);
+		}
+
+	_printf(_L("Reading data\n"));
+	for (int i = 1; i<MAX_BUFFER_SIZE; i*=2)
+		{
+		memset(readBufbig, 0, MAX_BUFFER_SIZE);
+		ReadData(readBufbig, i);
+		_printf(_L("%d "), i);
+		}
+
+	_printf(_L("\nTest complete.\n"));
+	}
+
+
+void DataStress_RateVary_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	TInt i;
+
+	_printf(_L("\n----------------------------------\n"));
+	_printf(_L("This test performs varying speed read\n"));
+	_printf(_L("and writes to and from the host.\n"));
+	_printf(_L("Press any key to quit.\n"));
+	_printf(_L("------------------------------------\n\n"));
+
+	_printf(_L("Setting handshaking & receive buffer length\n"));
+
+	_printf(_L("Writing data\n"));
+	for (i = 1; i<100; i++)
+		{
+		FillBuffer(writeBufbig, MAX_BUFFER_SIZE);
+		WriteData(writeBufbig, MAX_BUFFER_SIZE);
+		}
+
+	_printf(_L("Writing more data\n"));
+	for (i = 1; i<20; i++)
+		{
+		FillBuffer(writeBufbig, MAX_BUFFER_SIZE);
+		WriteData(writeBufbig, MAX_BUFFER_SIZE);
+		}
+
+	_printf(_L("Reading data\n"));
+	for (i = 1; i<100; i++)
+		{
+		memset(readBufbig, 0, MAX_BUFFER_SIZE);
+		ReadData(readBufbig, MAX_BUFFER_SIZE);
+		CheckBuffer(readBufbig, MAX_BUFFER_SIZE);
+
+		}
+
+	_printf(_L("\nTest complete\n"));
+}
+
+void TimeOut_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n---------------------------\n"));
+	_printf(_L("This test exercises the read\n"));
+	_printf(_L("and write timeouts on the device.\n"));
+	_printf(_L("Press any key to quit.\n"));
+	_printf(_L("-----------------------------\n\n"));
+
+
+	_printf(_L("In this test the host sits around while the device times out.\n"));
+	_printf(_L("Press a key when finished.\n"));
+	_getch();
+
+	_printf(_L("\nTest complete\n"));
+}
+
+void CancelTx_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n----------------------------------------\n"));
+	_printf(_L("This tests the read/write cancel feature\n"));
+	_printf(_L("Press any key to quit.\n"));
+	_printf(_L("------------------------------------------\n\n"));
+
+	_printf(_L("In this test the host sits around while the device cancels.\n"));
+	_printf(_L("Press a key when finished.\n"));
+	_getch();
+
+	_printf(_L("\nTest complete\n"));
+}
+
+void InterruptTx_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n--------------------------------\n"));
+	_printf(_L("This tests the read/write cancel\n"));
+	_printf(_L("when the USB cable is pulled\n"));
+	_printf(_L("----------------------------------\n\n"));
+
+	// Close the handle. If we don't do this before the device operator starts 
+	// pulling the cable out and plugging it in again then we'll never be able 
+	// to open it again afterwards. (This is also seen in HyperTerminal- 
+	// solution: reboot HyperTerminal.)
+	CloseHandle(hSerial);
+
+	// The device will attempt to read, then the cable will be pulled.
+	_printf(_L("Press any key when the device reports\n"));
+	_printf(_L("that the test is complete.\n"));
+	_getch();
+
+	// restart the serial device
+	OpenComPort();
+
+	_printf(_L("\nTest complete\n"));
+}
+
+void Shutdown_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n-----------------------------------\n"));
+	_printf(_L("This tests the USB Manager shutdown\n"));
+	_printf(_L("during reads and writes.\n"));
+	_printf(_L("Press any key to quit.\n"));
+	_printf(_L("-------------------------------------\n\n"));
+
+	_printf(_L("In this test the host sits around while\n"));
+	_printf(_L(" the device shuts down the USB manager.\n"));
+	_printf(_L("Press a key when finished.\n"));
+	_getch();
+
+	_printf(_L("\nTest complete\n"));
+}
+
+void BufferOverrun_TestL()
+/**
+ * Test updated from that in the ACM unit test specification to
+ * read/write messages bigger than the receive and transmit buffers.
+ * Changed as previous test was no longer valid.
+ */
+{
+	#define MAX_BIG_BUFFER_SIZE	(1024*8)
+	char bigBuf[MAX_BIG_BUFFER_SIZE];
+
+	_printf(_L("\n--------------------------------\n"));
+	_printf(_L("This tests read/writes which are\n"));
+	_printf(_L("bigger than the buffer length.\n"));
+	_printf(_L("----------------------------------\n\n"));
+
+	_printf(_L("Writing data.\nBuffer length: %d"), MAX_BIG_BUFFER_SIZE);
+	FillBuffer(bigBuf, MAX_BIG_BUFFER_SIZE);
+	WriteData(bigBuf, MAX_BIG_BUFFER_SIZE);
+
+	_printf(_L("done.\nReading data\nBuffer length: %d"), MAX_BIG_BUFFER_SIZE);
+	ReadData(bigBuf, MAX_BIG_BUFFER_SIZE);
+
+	_printf(_L(" done.\nTest complete\n"));
+}
+
+void Break_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n--------------------------------\n"));
+	_printf(_L("This tests break and break cancel.\n"));
+	_printf(_L("----------------------------------\n\n"));
+
+	_printf(_L("In this test the host sits around while\n"));
+	_printf(_L("the device issues some breaks.\n"));
+	_printf(_L("Press a key when finished.\n"));
+	_getch();
+
+	// TODO: should also do host-requested breaks. And NotifyBreaks.
+	_printf(_L("\nTest complete\n"));
+}
+
+void SignalChange_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n---------------------------------------\n"));
+	_printf(_L("This tests signal change notifications.\n"));
+	_printf(_L("---------------------------------------\n\n"));
+
+
+	_printf(_L("Press any key to send a signal change.\n"));
+	_getch();
+
+	newDcb.DCBlength = sizeof(DCB);
+    memcpy(&OldDcb, &newDcb, sizeof(DCB));
+
+	newDcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
+	
+	(void) SetCommState(hSerial, &newDcb);
+
+	_printf(_L("\nTest complete\n"));
+}
+
+void FlowControl_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n-------------------------------------------\n"));
+	_printf(_L("This tests flow control change notifications.\n"));
+	_printf(_L("---------------------------------------------\n\n"));
+
+	_printf(_L("Host side does nothing in this test. Press any key.\n"));
+	_getch();
+
+	_printf(_L("\nTest complete\n"));
+}
+
+void ConfigChange_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	DCB		dcb;
+
+	_printf(_L("\n------------------------------- -----\n"));
+	_printf(_L("This tests config change notifications.\n"));
+	_printf(_L("---------------------------------------\n\n"));
+
+	
+	_printf(_L("Press any key to send a new configuration.\n"));
+	_getch();
+
+	dcb.DCBlength = sizeof(DCB);
+    memcpy(&OldDcb, &dcb, sizeof(DCB));
+	dcb.BaudRate=38400;
+
+	(void) SetCommState(hSerial, &dcb);
+	
+	_printf(_L("\nTest complete\n"));
+}
+
+
+void SecondClient_TestL()
+/**
+ * Perform a single test.
+ */
+{
+	_printf(_L("\n---------------------------------------\n"));
+	_printf(_L("This tests that we can have a second\n"));
+	_printf(_L("client with non-exclusive access.\n"));
+	_printf(_L("Press any key to quit.\n"));
+	_printf(_L("---------------------------------------\n\n"));
+
+	_printf(_L("Writing data\n"));
+	FillBuffer(writeBufbig, MAX_BUFFER_SIZE);
+	WriteData(writeBufbig, MAX_BUFFER_SIZE);
+	WriteData(writeBufbig, MAX_BUFFER_SIZE);
+
+	_printf(_L("Reading data\n"));
+	memset(readBufbig, 0, 256);
+	ReadData(readBufbig, 256);
+	CheckBuffer(readBufbig, 256);
+
+	_printf(_L("\nTest complete\n"));
+}
+
+
+// ******************************************************************
+// The following are placholders for the ACMRq tests.
+// These tests need no support on the platform end, as yet.
+// The functions are left here incase someday some support is needed.
+// ******************************************************************
+
+void ACMRq_EncapCommand_TestL()
+{
+	 // Not needed to support this here
+}
+
+void ACMRq_Break_TestL()
+{
+	 // TODO: can we check for break status here ?
+}
+
+void ACMRq_SetFeature_TestL()
+{
+	 // TODO: Test doesn't make sense.
+}
+
+void ACMRq_ClearFeature_TestL()
+{
+	 // TODO: Test doesn't make sense.
+}
+
+void ACMRq_SetCoding_TestL()
+{
+	 // TODO: Can we check the line codeing here ?
+}
+
+void ACMRq_CtrlState_TestL()
+{
+	 // TODO: Test doesn't make sense.
+}
+
+void ACMRq_EncapResp_TestL()
+{
+	 // Not needed to support this here.
+}
+
+void ACMRq_CommsFeature_TestL()
+{
+	 // Not needed to support this here.
+}
+
+void ACMRq_GetCoding_TestL()
+{
+	 // Not needed to support this here.
+}
+
+
+void ACMNtf_SendState_TestL()
+{
+	 // TODO: SendSerialState() ???
+}
+
+void ACMNtf_Status_TestL()
+{
+	 // TODO: SendNetworkConnection() ???
+}
+
+void ACMNtf_RespAvail_TestL()
+{
+	 // Test not supported.
+}
+
+void Loopback_TestL()
+/**
+ * Perform a single test.
+ */
+	{
+	_printf(_L("\n---------------------------------------------\n"));
+	_printf(_L("This test writes data out of the USB ACM port\n"));
+	_printf(_L("and check that it is correctly echoed back.\n"));
+	_printf(_L("---------------------------------------------\n\n"));
+
+	// Purge all characters from the output and input buffers
+	// and terminate any pending read or write operations 
+	if(PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR) == 0)
+		{
+		LEAVE(GetLastError());
+		}
+
+	for (char i=0; i<100; i++)
+		{
+		memset(readBufbig, 0, MAX_BUFFER_SIZE);	// clear the read buffer
+		memset(writeBufbig, i, MAX_BUFFER_SIZE);	// fill the write buffer with known data
+		_printf(_L("%d: "), (TInt)i);
+		WriteData(writeBufbig, 64);
+		//FlushFileBuffers(hSerial);
+		ReadData(readBufbig, 64);
+		for (int j=0; j<64; j++)
+			{
+			if (readBufbig[j] != i)
+				{
+				_printf(_L("Buffer contents error.\n"));
+				for (int k=0; k<64; k++)
+					{
+					_printf(_L("%d "), readBufbig[k]);
+					}
+				_printf(_L("\n"));
+				return;
+				}
+			}
+		}
+	}
+
+void mainL()
+/**
+ * This function controls test execution as directed by the user.
+ */
+	{
+	TRequestStatus status;
+
+	memset(&SerialParams, 0, sizeof(struct SerialParameters));
+	SetWindowsSerialParams();
+
+	OpenComPort();
+
+	_printf(_L("Opened com port. [press any key]")); _getch();
+
+	TBool noExit = ETrue;
+	while (noExit)
+		{
+			_printf(_L("\nAvailable tests:\n\n"));
+			_printf(_L("1. Data stress, size varies (test 2.1.1)\n"));
+			_printf(_L("2. Data stress, rate varies (test 2.1.2)\n"));
+			_printf(_L("3. Timeout (test 2.2)\n"));
+			_printf(_L("4. Cancel Transfer (test 2.3)\n"));
+			_printf(_L("5. Interrupt Transfer (test 2.4)\n"));
+			_printf(_L("6. Shutdown (test 2.5)\n"));
+			_printf(_L("7. Buffer overrun (test 2.6)\n"));
+			_printf(_L("8. Break (test 2.7)\n"));
+			_printf(_L("9. Event notification, signal change (test 2.8.1)\n"));
+			_printf(_L("a. Event notification, flow control (test 2.8.2)\n"));
+			_printf(_L("b. Event notification, config change (test 2.8.3)\n"));
+			_printf(_L("c. Second client (test 2.9)\n"));
+/*			_printf(_L("d. ACM request, encapsulated command (test 2.10.1)\n"));
+			_printf(_L("e. ACM request, break (test 2.10.2)\n"));
+			_printf(_L("f. ACM request, setting feature (test 2.10.3)\n"));
+			_printf(_L("g. ACM request, clearing feature (test 2.10.4)\n"));
+			_printf(_L("h. ACM request, setting line coding (test 2.10.5)\n"));
+			_printf(_L("i. ACM request, control line state (test 2.10.6)\n"));
+			_printf(_L("j. ACM request, encapsualted response (test 2.10.7)\n"));
+			_printf(_L("k. ACM request, comms feature (test 2.10.8)\n"));
+			_printf(_L("l. ACM request, getting line coding (test 2.10.9)\n"));
+			_printf(_L("m. ACM Notifications, send serial state (test 2.11.1)\n"));
+			_printf(_L("n. ACM Notifications, network status (test 2.11.2)\n"));
+			_printf(_L("o. ACM Notifications, response available (test 2.11.3)\n"));
+*/			_printf(_L("p. Loopback test (test 2.12)\n"));
+			_printf(_L("\n"));
+			_printf(_L("\nSelection (x to exit): "));
+
+			char ch = (char) _getch();
+			_printf(_L("\n"));
+			switch (ch)
+				{
+			case '1': DataStress_SizeVary_TestL();	break;
+			case '2': DataStress_RateVary_TestL();	break;
+			case '3': TimeOut_TestL();	break;
+			case '4': CancelTx_TestL();	break;
+			case '5': InterruptTx_TestL();	break;
+			case '6': Shutdown_TestL();	break;
+			case '7': BufferOverrun_TestL();	break;
+			case '8': Break_TestL();	break;
+			case '9': SignalChange_TestL();	break;
+			case 'A':
+			case 'a': FlowControl_TestL();	break;
+			case 'B':
+			case 'b': ConfigChange_TestL();	break;
+			case 'C':
+			case 'c': SecondClient_TestL();	break;
+			case 'D':
+			case 'd': ACMRq_EncapCommand_TestL();	break;
+			case 'E':
+			case 'e': ACMRq_Break_TestL();	break;
+			case 'F':
+			case 'f': ACMRq_SetFeature_TestL();	break;
+			case 'G':
+			case 'g': ACMRq_ClearFeature_TestL();	break;
+			case 'H':
+			case 'h': ACMRq_SetCoding_TestL();	break;
+			case 'I':
+			case 'i': ACMRq_CtrlState_TestL();	break;
+			case 'J':
+			case 'j': ACMRq_EncapResp_TestL();	break;
+			case 'K':
+			case 'k': ACMRq_CommsFeature_TestL();	break;
+			case 'L':
+			case 'l': ACMRq_GetCoding_TestL();	break;
+			case 'M':
+			case 'm': ACMNtf_SendState_TestL();	break;
+			case 'N':
+			case 'n': ACMNtf_Status_TestL();	break;
+			case 'O':
+			case 'o': ACMNtf_RespAvail_TestL();	break;
+			case 'P':
+			case 'p': Loopback_TestL(); break;
+			case 'x':
+			case 'X':
+				noExit = EFalse;
+				break;
+			default:
+				_printf(_L("\nInvalid key\n"));
+				break;
+				}
+
+			if (noExit)
+				{
+				_printf(_L("Test Complete. Press a key.\n"));
+				_getch();
+				}
+		}
+
+		(void) SetCommState(hSerial, &OldDcb);
+		CloseHandle(hSerial);
+		delete[] SerialParams.comport;
+	}
+
+void consoleMainL()
+/**
+ * Create a console and run mainL().
+ */
+	{
+	console=Console::NewL(_L("T_ACM"),TSize(KConsFullScreen,KConsFullScreen));
+	CleanupStack::PushL(console);
+	mainL();
+	CleanupStack::PopAndDestroy();
+	}
+
+GLDEF_C TInt E32Main()
+/**
+ * Standard Symbian entry point. Sets stuff up and deals with the cleanup stack.
+ */
+	{
+	__UHEAP_MARK;
+	CTrapCleanup* cleanupStack=CTrapCleanup::New();
+
+	// create the timer for use during some of the tests
+	timer.CreateLocal();
+
+	TRAP_IGNORE(consoleMainL());
+	delete cleanupStack;
+	timer.Close();
+	__UHEAP_MARKEND;
+	return 0;
+	}
+
+