/*
* 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
* and is to be used in conjunction with the host-side application.
*
*/
#include <e32base.h>
#include <e32cons.h>
#include <e32math.h>
#include <c32comm.h>
#include <usbman.h>
LOCAL_D CConsoleBase* console;
RCommServ TheCommServ;
TCommConfig TheConfigBuf;
TCommConfigV01& TheConfig = TheConfigBuf();
const TInt KReceiveBufferLength = 4096;
const TInt KMaxAcmPortNameLength = 8;
//_LIT(KUsbCsyName, "ECACM");
_LIT(KUsbPortName, "ACM::0");
_LIT(KUsbPortNameAcm1, "ACM::1");
_LIT(KUsbLddName, "EUSBC");
#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))
// A define for stack-based buffers
#define MAX_BUFFER_SIZE 1024
// A bigger buffer on the heap
#define MAX_HEAP_BUFFER_SIZE 1024*8
TBuf8<MAX_HEAP_BUFFER_SIZE> readBigBuf;
// A timer for use by several of the tests
RTimer timer;
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("\nERROR (%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 ReadString(TDes& aDes)
/**
* Reads user input into the start of the descriptor aDes.
*/
{
TChar inputKey;
TInt count = 0;
aDes.Zero();
for (;;)
{
inputKey = (TInt) _getch();
if ((TInt)inputKey == EKeyEnter)
break;
if(inputKey == EKeyBackspace)
{
if (count > 0)
{
_printf(_L("%C"), (TUint) inputKey);
aDes.Delete(--count,1);
}
}
else if(inputKey.IsPrint())
{
_printf(_L("%C"), (TUint) inputKey);
aDes.Append(inputKey);
count++;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* loopback From a Port input by the user to abother port-
* ACM::1 KUsbPortNameAcm1 to ACM::0 KUsbPortName by default
*/
void ReadLoopbackFromPortAToPortBTestL()
{
TRequestStatus consoleStatus;
TRequestStatus status;
RComm portIN;
RComm portOut;
_printf(_L("Enter the packet size:"));
TBufC<8> buf;
TPtr ptr (buf.Des());
ReadString(ptr);
TLex input(buf);
TInt pktlen = 0;
while ((input.Peek()).IsDigit()) {
pktlen = 10*pktlen + (input.Get()) - '0';
}
// Get port names
_printf(_L("\nEnter acm port name as loopback INPUT: (ex ACM::1):"));
TBufC<KMaxAcmPortNameLength> portINName;
TPtr portINNamePtr (portINName.Des());
ReadString(portINNamePtr);
if ( portINNamePtr.Length() == 0 )
{
portINName= KUsbPortNameAcm1;
}
_printf(_L("\nEnter acm port name as loopback OUTPUT: (ex ACM::0):"));
TBufC<KMaxAcmPortNameLength> portOutName;
TPtr portOutNamePtr (portOutName.Des());
ReadString(portOutNamePtr);
if ( portOutNamePtr.Length() == 0 )
{
portOutName = KUsbPortName;
}
_printf(_L("\n----------------------------------------\n"));
_printf(_L("This test listens for data on the ACM port: "));
_printf(portINName);
_printf(_L("\nwrites anything it receives on the ACM port: "));
_printf(portOutName);
_printf(_L("\nPress any key to quit.\n"));
_printf(_L("----------------------------------------\n\n"));
LEAVEIFERROR(portIN.Open(TheCommServ, portINName, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(portIN);
LEAVEIFERROR(portOut.Open(TheCommServ, portOutName, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(portOut);
_printf(_L("Setting handshaking & receive buffer length\n"));
portIN.SetConfig(TheConfigBuf);
portIN.SetReceiveBufferLength(KReceiveBufferLength);
portOut.SetConfig(TheConfigBuf);
portOut.SetReceiveBufferLength(KReceiveBufferLength);
_printf(_L("loopback received data\n"));
console->Read(consoleStatus);
FOREVER
{
portIN.Read(status, readBigBuf, pktlen);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
portIN.ReadCancel();
break;
}
portOut.Write(status, readBigBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
portOut.WriteCancel();
break;
}
}
portOut.WriteCancel();
_printf(_L("\nTest complete\n"));
CleanupStack::PopAndDestroy(2); // portA , portOut
}
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* Original loopback test - uses Read().
*/
void ReadLoopbackTestL()
{
TRequestStatus consoleStatus;
TRequestStatus status;
RComm port;
RComm port2;
_printf(_L("Enter the packet size:"));
TBufC<8> buf;
TPtr ptr (buf.Des());
ReadString(ptr);
TLex input(buf);
TInt pktlen = 0;
while ((input.Peek()).IsDigit()) {
pktlen = 10*pktlen + (input.Get()) - '0';
}
_printf(_L("\n----------------------------------------\n"));
_printf(_L("This test listens for data on the ACM\n"));
_printf(_L("port and echoes anything it receives\n"));
_printf(_L("back to the PC. Press any key to quit.\n"));
_printf(_L("----------------------------------------\n\n"));
LEAVEIFERROR(port.Open(TheCommServ, KUsbPortName, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(port);
LEAVEIFERROR(port2.Open(TheCommServ, _L("ACM::1"), ECommExclusive, ECommRoleDCE));
CleanupClosePushL(port2);
_printf(_L("Setting handshaking & receive buffer length\n"));
port.SetConfig(TheConfigBuf);
port.SetReceiveBufferLength(KReceiveBufferLength);
port2.SetConfig(TheConfigBuf);
port2.SetReceiveBufferLength(KReceiveBufferLength);
_printf(_L("Echoing received data\n"));
console->Read(consoleStatus);
FOREVER
{
port.Read(status, readBigBuf, pktlen);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.ReadCancel();
break;
}
port.Write(status, readBigBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.WriteCancel();
break;
}
}
console->Read(consoleStatus);
FOREVER
{
port2.Read(status, readBigBuf, pktlen);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port2.ReadCancel();
break;
}
port2.Write(status, readBigBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port2.WriteCancel();
break;
}
}
_printf(_L("\nTest complete\n"));
CleanupStack::PopAndDestroy(2); // port , port2
}
/**
* Original loopback test - uses ReadOneOrMore().
*/
void LoopbackTestL()
{
TRequestStatus consoleStatus;
TRequestStatus status;
RComm port;
_printf(_L("\n----------------------------------------\n"));
_printf(_L("This test listens for data on the ACM\n"));
_printf(_L("port and echoes anything it receives\n"));
_printf(_L("back to the PC. Press any key to quit.\n"));
_printf(_L("----------------------------------------\n\n"));
LEAVEIFERROR(port.Open(TheCommServ, KUsbPortName, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(port);
_printf(_L("Setting handshaking & receive buffer length\n"));
port.SetConfig(TheConfigBuf);
port.SetReceiveBufferLength(KReceiveBufferLength);
_printf(_L("Echoing received data\n"));
TBuf8<256> readBuf;
console->Read(consoleStatus);
FOREVER
{
port.ReadOneOrMore(status, readBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.ReadCancel();
break;
}
port.Write(status, readBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.WriteCancel();
break;
}
}
_printf(_L("\nTest complete\n"));
CleanupStack::PopAndDestroy(); // port
}
void ReadWithTerminatorsLoopbackTestL()
{
TRequestStatus consoleStatus;
TRequestStatus status;
RComm port;
// Get terminator characters
_printf(_L("Enter the terminator characters (up to %d):"), KConfigMaxTerminators);
TBufC<KConfigMaxTerminators> termbuf;
TPtr termptr (termbuf.Des());
ReadString(termptr);
TText8 terminators[KConfigMaxTerminators];
if ( termptr.Length() == 0 )
{
_printf(_L("\nno terminators given- not running test"));
return;
}
TUint termCount = 0;
TUint ii;
for ( ii = 0 ; ii < (TUint)termptr.Length() ; ii++ )
{
termCount++;
terminators[ii] = (TText8)termptr[ii];
}
_printf(_L("\nEnter the packet size:"));
TBufC<8> buf;
TPtr ptr (buf.Des());
ReadString(ptr);
TLex input(buf);
TInt pktlen = 0;
while ((input.Peek()).IsDigit()) {
pktlen = 10*pktlen + (input.Get()) - '0';
}
_printf(_L("\n----------------------------------------\n"));
_printf(_L("This test listens for data on the ACM\n"));
_printf(_L("port and echoes anything it receives\n"));
_printf(_L("back to the PC. Press any key to quit.\n"));
_printf(_L("----------------------------------------\n\n"));
LEAVEIFERROR(port.Open(TheCommServ, KUsbPortName, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(port);
_printf(_L("Setting handshaking & receive buffer length\n"));
// Set the config, including terminator characters.
TCommConfig configBuf;
TCommConfigV01& config = configBuf();
port.Config(configBuf);
config.iTerminatorCount = termCount;
for ( ii = 0 ; ii < termCount ; ii++ )
{
config.iTerminator[ii] = terminators[ii];
}
LEAVEIFERROR(port.SetConfig(configBuf));
port.SetReceiveBufferLength(KReceiveBufferLength);
_printf(_L("Echoing received data\n"));
console->Read(consoleStatus);
TBuf8<256> readBuf;
FOREVER
{
port.Read(status, readBuf, pktlen);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.ReadCancel();
break;
}
port.Write(status, readBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.WriteCancel();
break;
}
}
_printf(_L("\nTest complete\n"));
CleanupStack::PopAndDestroy(); // port
}
void AcmLoopback_TestL()
/**
* Runs the test as specified in the ACM unit test specification.
*/
{
TRequestStatus consoleStatus;
TRequestStatus status;
RComm port;
_printf(_L("\n----------------------------------------\n"));
_printf(_L("This test listens for data on the ACM\n"));
_printf(_L("port and echoes anything it receives\n"));
_printf(_L("back to the PC. Press any key to quit.\n"));
_printf(_L("----------------------------------------\n\n"));
LEAVEIFERROR(port.Open(TheCommServ, KUsbPortName, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(port);
_printf(_L("Setting handshaking & receive buffer length\n"));
port.SetConfig(TheConfigBuf);
port.SetReceiveBufferLength(KReceiveBufferLength);
_printf(_L("Echoing received data\n"));
TBuf8<1024> readBuf;
console->Read(consoleStatus);
FOREVER
{
port.ReadOneOrMore(status, readBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.ReadCancel();
break;
}
port.Write(status, readBuf);
User::WaitForRequest(status, consoleStatus);
if (consoleStatus == KRequestPending)
{
if (status != KErrNone)
{
// need to cancel the read to avoid a CBase-77 panic!
console->ReadCancel();
LEAVE(status.Int());
}
}
else
{
port.WriteCancel();
break;
}
_printf(_L("."));
}
_printf(_L("\nTest complete\n"));
CleanupStack::PopAndDestroy(); // port
}
void SetHandshakingL()
/**
* This function allows the user to select a new handshaking mode.
*/
{
RComm port;
TCommCaps capsBuf;
TCommCapsV01& caps = capsBuf();
LEAVEIFERROR(port.Open(TheCommServ, KUsbPortName, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(port);
port.Caps(capsBuf);
_printf(_L("\nPort handshaking capabilities: 0x%X\n"), caps.iHandshake);
_printf(_L("Current handshaking options: 0x%X\n"), TheConfig.iHandshake);
_printf(_L("\nHandshaking options:\n"));
_printf(_L("1. No handshaking\n"));
_printf(_L("2. Toggle Xon/Xoff\n"));
_printf(_L("3. Toggle obey CTS\n"));
_printf(_L("4. Toggle obey DSR / free RTS\n"));
_printf(_L("5. Toggle write buffered complete\n"));
TInt key = (TInt) _getch();
switch (key)
{
case '1':
TheConfig.iHandshake = 0;
break;
case '2':
TheConfig.iHandshake ^= KConfigObeyXoff;
TheConfig.iHandshake ^= KConfigSendXoff;
break;
case '3':
TheConfig.iHandshake ^= KConfigObeyCTS;
break;
case '4':
TheConfig.iHandshake ^= KConfigObeyDSR;
TheConfig.iHandshake ^= KConfigFreeRTS;
break;
case '5':
TheConfig.iHandshake ^= KConfigWriteBufferedComplete;
break;
default:
break;
}
LEAVEIFERROR(port.SetConfig(TheConfigBuf));
_printf(_L("Handshaking options now: 0x%X\n"), TheConfig.iHandshake);
CleanupStack::PopAndDestroy();
}
void mainL()
/**
* This function controls test execution as directed by the user.
*/
{
char ch;
TInt ret = User::LoadLogicalDevice(KUsbLddName);
if ((ret != KErrNone) && (ret != KErrAlreadyExists))
LEAVE(ret);
_printf(_L("Loaded USB LDD\n"));
LEAVEIFERROR(TheCommServ.Connect());
_printf(_L("Connected to C32\n"));
RComm port;
// The port's configuration seems to be junk at the beginning, so we set it to known values.
TheConfig.iRate = EBps115200;
TheConfig.iDataBits = EData8;
TheConfig.iStopBits = EStop1;
TheConfig.iParity = EParityNone;
TheConfig.iHandshake = 0;
TheConfig.iTerminatorCount = 0;
LEAVEIFERROR(port.Open(TheCommServ, KUsbPortNameAcm1, ECommExclusive, ECommRoleDCE));
CleanupClosePushL(port);
port.SetConfig(TheConfigBuf);
_printf(_L("----------------------------------------\n"));
_printf(_L("Initial port config:\n"));
_printf(_L(" Rate: %d bps\n"), TheConfig.iRate);
_printf(_L(" Data bits: %d. Parity type: %d. Stop bits: %d\n"),
TheConfig.iStopBits, TheConfig.iParity, TheConfig.iStopBits);
_printf(_L(" Handshaking options: 0x%X\n"), TheConfig.iHandshake);
_printf(_L("----------------------------------------\n\n"));
CleanupStack::PopAndDestroy(); // port
TBool noExit = ETrue;
while (noExit)
{
_printf(_L("\nAvailable tests:\n\n"));
_printf(_L("1. Read loopback from ACM0->ACM1 test\n"));
_printf(_L("\nSelection (x to exit): "));
ch = (char) _getch();
_printf(_L("\n"));
switch (ch)
{
case '1': ReadLoopbackFromPortAToPortBTestL(); break;
case 'x':
case 'X': noExit = EFalse; break;
default: _printf(_L("\nInvalid key\n")); break;
}
}
TheCommServ.Close();
}
void consoleMainL()
/**
* Create a console and run mainL().
*/
{
console=Console::NewL(_L("T_ACM"),TSize(KConsFullScreen,KConsFullScreen));
CleanupStack::PushL(console);
mainL();
_printf(_L("[ press any key ]"));
_getch();
CleanupStack::PopAndDestroy();
}
GLDEF_C TInt E32Main()
/**
* Runs the test as specified in the ACM unit test specification.
*/
{
__UHEAP_MARK;
CTrapCleanup* cleanupStack=CTrapCleanup::New();
// create the timer for use during some of the tests
timer.CreateLocal();
TRAP_IGNORE(consoleMainL());
delete cleanupStack;
__UHEAP_MARKEND;
return 0;
}