// Copyright (c) 2007-2010 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:
// @file testdevicebase.cpp
// @internalComponent
// 
//

#include "TestDeviceBase.h"
#include "UsbDescriptorOffsets.h"
#include "testdebug.h"
#include <e32test.h>
#include "softwareconnecttimer.h"
#include "wakeuptimer.h"
#include "controltransferrequests.h"
#include "testinterfacebase.h"
#include "PBASE-T_USBDI-0486.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "TestDeviceBaseTraces.h"
#endif
#include <e32property.h>

namespace NUnitTesting_USBDI
	{

RUsbTestDevice::RUsbTestDevice()
: 	iStateWatcher(NULL), 
	iCurrentState(EUsbcDeviceStateUndefined), 
	iDeviceEp0(NULL), 
	iConnectTimer(NULL), iWakeupTimer(NULL),
	iAuxBuffer(NULL)
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_RUSBTESTDEVICE_ENTRY, this );
	OstTraceFunctionExit1( RUSBTESTDEVICE_RUSBTESTDEVICE_EXIT, this );
	}
	
RUsbTestDevice::RUsbTestDevice(CBaseTestCase* aTestCase)
: 	iStateWatcher(NULL), 
	iCurrentState(EUsbcDeviceStateUndefined), 
	iDeviceEp0(NULL), 
	iConnectTimer(NULL), iWakeupTimer(NULL),
	iAuxBuffer(NULL)
	{
	OstTraceFunctionEntryExt( RUSBTESTDEVICE_RUSBTESTDEVICE_ENTRY_DUP01, this );
	iTestCase = aTestCase;
	OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_RUSBTESTDEVICE, "iTestCase = %d", iTestCase);
	OstTraceFunctionExit1( RUSBTESTDEVICE_RUSBTESTDEVICE_EXIT_DUP01, this );
	}
		
void RUsbTestDevice::ResetState()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_RESETSTATE_ENTRY, this );
	iCurrentState = EUsbcDeviceStateUndefined;
	OstTraceFunctionExit1( RUSBTESTDEVICE_RESETSTATE_EXIT, this );
	}

RUsbTestDevice::~RUsbTestDevice()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_RUSBTESTDEVICE_ENTRY_DUP02, this );
	
	OstTraceFunctionExit1( RUSBTESTDEVICE_RUSBTESTDEVICE_EXIT_DUP02, this );
	}
	
void RUsbTestDevice::Close()
	{
OstTraceFunctionEntry1( RUSBTESTDEVICE_CLOSE_ENTRY, this );

	delete iWakeupTimer;
	delete iConnectTimer;
	delete iDeviceEp0;
	delete iStateWatcher;
		
	iInterfaces.ResetAndDestroy();

	iClientDriver.Close(); 
	
	if(!iTestCase->IsHost()) // process only started in client rom
		{
        // create a publish/subscribe key to allow usbhost_usbman to be killed
        // cleanly
        static const TUid KWordOfDeathCat = {0x01066600};
        static const TInt KWordOfDeathKey = 0x01066601;
        static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy);
        TInt r = RProperty::Define(KWordOfDeathCat, KWordOfDeathKey, RProperty::EInt,KAllowAllPolicy, KAllowAllPolicy, 0);
        if(r != KErrNone)
            {
            OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_CLOSE, "Could not create the WordOfDeath P&S   (%d)", r);
            }
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_CLOSE_DUP01, "killing t_usbhost_usbman.exe");
        RProperty::Set(KWordOfDeathCat, KWordOfDeathKey, KErrAbort);   // Send the word of death
        User::After(1000000); //allow time for t_usbhost_usbman.exe to clean up
		}
	OstTraceFunctionExit1( RUSBTESTDEVICE_CLOSE_EXIT, this );
	}


void RUsbTestDevice::SubscribeToReports(TRequestStatus& aObserverStatus)
	{
	OstTraceFunctionEntryExt( RUSBTESTDEVICE_SUBSCRIBETOREPORTS_ENTRY, this );
	
	// Signal the request as pending
	
	iObserverStatus = &aObserverStatus;
	*iObserverStatus = KRequestPending;
	OstTraceFunctionExit1( RUSBTESTDEVICE_SUBSCRIBETOREPORTS_EXIT, this );
	}


void RUsbTestDevice::CancelSubscriptionToReports()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_CANCELSUBSCRIPTIONTOREPORTS_ENTRY, this );
	
	// Signal the request as cancelled
	User::RequestComplete(iObserverStatus,KErrCancel);
	OstTraceFunctionExit1( RUSBTESTDEVICE_CANCELSUBSCRIPTIONTOREPORTS_EXIT, this );
	}
	
		
void RUsbTestDevice::OpenL()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_OPENL_ENTRY, this );
	TInt err = KErrNone;
	
	OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_OPENL, "starting t_usbhost_usbman.exe");
	TInt r = iOtgUsbMan.Create(_L("t_usbhost_usbman.exe"), _L("client"));
	gtest(r == KErrNone);
	iOtgUsbMan.Resume();	
	
	User::After(1500000);
	
	// Open channel to driver
	err = iClientDriver.Open(0);
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP01, "<Error %d> Unable to open a channel to USB client driver",err);
		User::Leave(err);
		}
	
	// Hide bus from host while interfaces are being set up
	err = iClientDriver.DeviceDisconnectFromHost();
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP02, "<Error %d> unable to disconnect device from host",err);
		User::Leave(err);
		}
	
	// Create the client usb state watcher
	iStateWatcher = CUsbClientStateWatcher::NewL(iClientDriver,*this);
		
	// Create the Ep0 reader
	iDeviceEp0 = CDeviceEndpoint0::NewL(*this);
		
	// Create the timer for software connection/disconnection
	iConnectTimer = CSoftwareConnectTimer::NewL(*this);
	
	// Create the timer for remote wakeup events
	iWakeupTimer = CRemoteWakeupTimer::NewL(*this);
	_LIT8(KYes, "yes");
	_LIT8(KNo, "no");
	User::LeaveIfError(iClientDriver.DeviceCaps(iDeviceCaps));
 	OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP03, "------ USB device capabilities -------");
	OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP04, "Number of endpoints:                %d",iDeviceCaps().iTotalEndpoints);	
	OstTraceExt1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP05, "Supports Software-Connect:          %s",iDeviceCaps().iConnect ? KYes() : KNo());
	OstTraceExt1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP06, "Device is Self-Powered:             %S",iDeviceCaps().iSelfPowered ? KYes() : KNo());
	OstTraceExt1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP07, "Supports Remote-Wakeup:             %S",iDeviceCaps().iRemoteWakeup ? KYes() : KNo());
	OstTraceExt1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP08, "Supports High-speed:                %S",iDeviceCaps().iHighSpeed ? KYes() : KNo());
	OstTraceExt1(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP09, "Supports unpowered cable detection: %S",(iDeviceCaps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ? KYes() : KNo());
	OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_OPENL_DUP10, "--------------------------------------");
	
	OstTraceFunctionExit1( RUSBTESTDEVICE_OPENL_EXIT, this );
	}


TInt RUsbTestDevice::SetClassCode(TUint8 aClassCode,TUint8 aSubClassCode,TUint8 aDeviceProtocol)
	{
    OstTraceFunctionEntryExt( RUSBTESTDEVICE_SETCLASSCODE_ENTRY, this );

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETCLASSCODE, "<Error %d> Unable to obtain device descriptor",err);
		}
	else
		{
		deviceDescriptor[KDevDescOffset_bDeviceClass] = aClassCode;
		deviceDescriptor[KDevDescOffset_bDeviceSubClass] = aSubClassCode;
		deviceDescriptor[KDevDescOffset_bDeviceProtocol] = aDeviceProtocol;	
		
		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETCLASSCODE_DUP01, "<Error %d> Unable to set the device dsecriptor",err);
			}
		}
	OstTraceFunctionExitExt( RUSBTESTDEVICE_SETCLASSCODE_EXIT, this, err );
	return err;
	}


TInt RUsbTestDevice::SetUsbSpecification(TUint16 aSpecification)
	{
    OstTraceFunctionEntryExt( RUSBTESTDEVICE_SETUSBSPECIFICATION_ENTRY, this );

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETUSBSPECIFICATION, "<Error %d> Unable to obtain device descriptor",err);
		}
	else
		{
		// Set bcdUSB
		TUint8* p = reinterpret_cast<TUint8*>(&aSpecification);
		deviceDescriptor[KDevDescOffset_bcdUSB] = *p;
		deviceDescriptor[KDevDescOffset_bcdUSB+1] = *(p+1);
		
		// Symbian currently supports only devices with one configuration by selecting the configurations
		// that has the lowest power consumption
		
		deviceDescriptor[KDevDescOffset_bNumConfigurations] = 0x01;
		
		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETUSBSPECIFICATION_DUP01, "<Error %d> Unable to set the device dsecriptor",err);
			}
		}
	OstTraceFunctionExitExt( RUSBTESTDEVICE_SETUSBSPECIFICATION_EXIT, this, err );
	return err;
	}


TInt RUsbTestDevice::SetVendor(TUint16 aVendorId)
	{
    OstTraceFunctionEntryExt( RUSBTESTDEVICE_SETVENDOR_ENTRY, this );

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETVENDOR, "<Error %d> Unable to obtain device descriptor",err);
		}
	else
		{
		// Set VID
		TUint8* p = reinterpret_cast<TUint8*>(&aVendorId);
		deviceDescriptor[KDevDescOffset_idVendor] = *p;
		deviceDescriptor[KDevDescOffset_idVendor+1] = *(p+1);
		
		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETVENDOR_DUP01, "<Error %d> Unable to set the device descriptor",err);
			}
		}
	OstTraceFunctionExitExt( RUSBTESTDEVICE_SETVENDOR_EXIT, this, err );
	return err;
	}


TInt RUsbTestDevice::SetProduct(TUint16 aProductId,const TDesC16& aProductString,
				const TDesC16& aManufacturerString,const TDesC16& aSerialNumberString)
	{
    OstTraceFunctionEntryExt( RUSBTESTDEVICE_SETPRODUCT_ENTRY, this );

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETPRODUCT, "<Error %d> Unable to obtain device descriptor",err);
		}
	else
		{
		// Set PID
		TUint8* p = reinterpret_cast<TUint8*>(&aProductId);
		deviceDescriptor[KDevDescOffset_idProduct] = *p;
		deviceDescriptor[KDevDescOffset_idProduct+1] = *(p+1);
		
		err = iClientDriver.SetDeviceDescriptor(deviceDescriptor);
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETPRODUCT_DUP01, "<Error %d> Unable to set the device dsecriptor",err);
			OstTraceFunctionExitExt( RUSBTESTDEVICE_SETPRODUCT_EXIT, this, err );
			return err;
			}
		
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_SETPRODUCT_DUP02, "Product Identity set");
	
		// Product string
		err = iClientDriver.SetProductStringDescriptor(aProductString);
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETPRODUCT_DUP03, "<Error %d> Unable to set product string descriptor",err);
			OstTraceFunctionExitExt( RUSBTESTDEVICE_SETPRODUCT_EXIT_DUP01, this, err );
			return err;
			}

		// Manufacturer string
		err = iClientDriver.SetManufacturerStringDescriptor(aManufacturerString);
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETPRODUCT_DUP04, "<Error %d> Unable to set the manufacturer string descriptor",err);
			OstTraceFunctionExitExt( RUSBTESTDEVICE_SETPRODUCT_EXIT_DUP02, this, err );
			return err;
			}
	
		// Serial number string
		err = iClientDriver.SetSerialNumberStringDescriptor(aSerialNumberString);
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETPRODUCT_DUP05, "<Error %d> Unable to set the serial number string descriptor",err);
			OstTraceFunctionExitExt( RUSBTESTDEVICE_SETPRODUCT_EXIT_DUP03, this, err );
			return err;
			}
		}
	OstTraceFunctionExitExt( RUSBTESTDEVICE_SETPRODUCT_EXIT_DUP04, this, KErrNone );
	return KErrNone;
	}


TInt RUsbTestDevice::SetConfigurationString(const TDesC16& aConfigString)
	{
    OstTraceFunctionEntryExt( RUSBTESTDEVICE_SETCONFIGURATIONSTRING_ENTRY, this );

	TInt err(iClientDriver.SetConfigurationStringDescriptor(aConfigString));
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SETCONFIGURATIONSTRING, "<Error %d> Unable to set configuration string descriptor",err);
		}
	OstTraceFunctionExitExt( RUSBTESTDEVICE_SETCONFIGURATIONSTRING_EXIT, this, err );
	return err;
	}


void RUsbTestDevice::AddInterface(CInterfaceBase* aInterface)
	{
	OstTraceFunctionEntryExt( RUSBTESTDEVICE_ADDINTERFACE_ENTRY, this );
		
	// Add the interface to the device
	TInt err = iInterfaces.Append(aInterface);
	
	if(err != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_ADDINTERFACE, "<Error %d> Unable to add interface",err);
		return ReportError(err);
		}
	OstTraceFunctionExit1( RUSBTESTDEVICE_ADDINTERFACE_EXIT, this );
	}


CInterfaceBase& RUsbTestDevice::Interface(TInt aIndex)
	{
	OstTraceFunctionEntryExt( RUSBTESTDEVICE_INTERFACE_ENTRY, this );
	OstTraceFunctionExit1( RUSBTESTDEVICE_INTERFACE_EXIT, this );
	return *iInterfaces[aIndex];
	}


void RUsbTestDevice::SoftwareConnect()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_SOFTWARECONNECT_ENTRY, this );
	TInt err(iClientDriver.PowerUpUdc());
	if((err != KErrNone) && (err != KErrNotReady))
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SOFTWARECONNECT, "<Error %d> Power Up Udc",err);
		ReportError(err);
		}
		
	if(iDeviceCaps().iConnect) 
		{
		err = iClientDriver.DeviceConnectToHost();
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SOFTWARECONNECT_DUP01, "<Error %d> Unable to connect to the host",err);
			ReportError(err);
			}
		}
	else
		{
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_SOFTWARECONNECT_DUP02, "Please connect device to Host");
		}	
	OstTraceFunctionExit1( RUSBTESTDEVICE_SOFTWARECONNECT_EXIT, this );
	}   	
	 
void RUsbTestDevice::SoftwareDisconnect()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_SOFTWAREDISCONNECT_ENTRY, this );
	
	if(iDeviceCaps().iConnect) 
		{
		TInt err(iClientDriver.DeviceDisconnectFromHost());
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_SOFTWAREDISCONNECT, "<Error %d> Unable to disconnect from the host",err);
			ReportError(err);
			}
		}
	else
		{
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_SOFTWAREDISCONNECT_DUP01, "Please disconnect device from Host");
		}
		
	OstTraceFunctionExit1( RUSBTESTDEVICE_SOFTWAREDISCONNECT_EXIT, this );
	}       


void RUsbTestDevice::RemoteWakeup()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_REMOTEWAKEUP_ENTRY, this );
	if(iDeviceCaps().iConnect) 
		{
		TInt err(iClientDriver.SignalRemoteWakeup());
		if(err != KErrNone)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_REMOTEWAKEUP, "<Error %d> Unable to perform a remote wakeup",err);
			ReportError(err);
			}
		}
	else
		{
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_REMOTEWAKEUP_DUP01, "remote wakeup not supported");
		}
	OstTraceFunctionExit1( RUSBTESTDEVICE_REMOTEWAKEUP_EXIT, this );
	}


TInt RUsbTestDevice::ProcessRequestL(TUint8 aRequest,TUint16 aValue,TUint16 aIndex,
	TUint16 aDataReqLength,const TDesC8& aPayload)
	{
	OstTraceFunctionEntryExt( RUSBTESTDEVICE_PROCESSREQUESTL_ENTRY, this );
	
	if(aRequest == KVendorEmptyRequest)
		{
		// Handle an empty request (i.e. do nothing)
		
		AcknowledgeRequestReceived();
		}
	else if(aRequest == KVendorReconnectRequest)
		{
		// Handle a reconnect requests from the host
		
		AcknowledgeRequestReceived();
		iConnectTimer->SoftwareReConnect(aValue);
		}
	else if(aRequest == KVendorDisconnectDeviceAThenConnectDeviceCRequest)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL, "**aRequest == KVendorDisconnectDeviceAThenConnectDeviceCRequest, this = 0x%08x", this);
		// Handle a reconnect requests from the host		
		AcknowledgeRequestReceived();			
		
		SoftwareDisconnect();	
		User::After(1000000);
		//	connect device C now	
		CUT_PBASE_T_USBDI_0486* iTestCaseT_USBDI_0486 = reinterpret_cast<CUT_PBASE_T_USBDI_0486*>(iTestCase);
		Close(); 		
		
		User::After(3000000);
		iTestCaseT_USBDI_0486->TestDeviceC()->OpenL(KTestDeviceC_SN);		
		// Connect the device to the host	
		iTestCaseT_USBDI_0486->TestDeviceC()->SoftwareConnect();
		OstTraceFunctionExitExt( RUSBTESTDEVICE_PROCESSREQUESTL_EXIT, this, KErrAbort );
		return KErrAbort;
		}
	else if(aRequest == KVendorDisconnectDeviceCThenConnectDeviceARequest)
		{
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP01, "**aRequest == KVendorDisconnectDeviceCThenConnectDeviceARequest, this = 0x%08x", this);
		// Handle a reconnect requests from the host		
		AcknowledgeRequestReceived();		
		 
		SoftwareDisconnect();	
		User::After(1000000); 
		 
		//	connect device A now	
		CUT_PBASE_T_USBDI_0486* iTestCaseT_USBDI_0486 = reinterpret_cast<CUT_PBASE_T_USBDI_0486*>(iTestCase);
		
		
		Close();		
		User::After(3000000); 		
		iTestCaseT_USBDI_0486->Cancel();
		iTestCaseT_USBDI_0486->HandleDeviceDConnection();
		iTestCaseT_USBDI_0486->TestDeviceD()->OpenL(iTestCaseT_USBDI_0486->TestCaseId());	
		
		// Connect the device to the host	
		iTestCaseT_USBDI_0486->TestDeviceD()->SoftwareConnect();	
		OstTraceFunctionExitExt( RUSBTESTDEVICE_PROCESSREQUESTL_EXIT_DUP01, this, KErrAbort );
		return KErrAbort;
		}		
	else if(aRequest == KVendorTestCasePassed)
		{ 
		// Test case has completed successfully 
		// so report to client test case that host is happy		
		
		AcknowledgeRequestReceived();
		ReportError(KErrNone);
		}
	else if(aRequest == KVendorTestCaseFailed)
		{
		// The test case has failed, so report to client test case
		// and display/log the error message
		
		AcknowledgeRequestReceived();
		
		HBufC16* msg = HBufC16::NewL(aPayload.Length());
		msg->Des().Copy(aPayload);
		OstTraceExt1(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP02, "<Host> Test case failed: %S",*msg);
		delete msg;
		msg = 0;
		ReportError(-aValue);
		}
	else if(aRequest == KVendorRemoteWakeupRequest)
		{
		// Handle a remote wakeup request

		AcknowledgeRequestReceived();
		iWakeupTimer->WakeUp(aValue);
		}
	else if(aRequest == KVendorPutPayloadRequest)
		{
		// Handle a payload request from the host

		AcknowledgeRequestReceived();
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP03, "Put payload");
		if(aPayload.Compare(_L8("DEADBEEF")) != 0)
			{
			OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP04, "<Error %d> Payload not as expected",KErrCorrupt);
			ReportError(KErrCorrupt);
			}
		}
	else if(aRequest == KVendorGetPayloadRequest)
		{
		// Handle a payload request to the host

		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP05, "Get payload");
		__ASSERT_DEBUG(iAuxBuffer, User::Panic(_L("Trying to write non-allocated buffer"), KErrGeneral));
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP06, "iAuxBuffer = ....");
        OstTraceData(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP56, "", iAuxBuffer->Ptr(), iAuxBuffer->Length());
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP07, "\n");
		
		//Perform synchronous write to EP0
		//This allows the subsequent 'Read' request to
		//take place
		TInt ret = iDeviceEp0->SendDataSynchronous(*iAuxBuffer);
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP08, "Write (from device callback) executed with error %d", ret);
		}
	else if(aRequest == KVendorUnrespondRequest)
		{
		// Do not acknowledge this request
		
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP09, "Unrespond request: continually NAK the host");
		}
	else if(aRequest == KVendorStallRequest)
		{
		// Stall the specified endpoint
		
		AcknowledgeRequestReceived();
		OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_PROCESSREQUESTL_DUP10, "Stalling endpoint %d",aValue);
						
		}
	else
		{
		// Maybe forward to derived classes
		}
	OstTraceFunctionExitExt( RUSBTESTDEVICE_PROCESSREQUESTL_EXIT_DUP02, this, KErrNone );
	return KErrNone;
	}


void RUsbTestDevice::StateChangeL(TUsbcDeviceState aNewState,TInt aChangeCompletionCode)
	{
	OstTraceFunctionEntryExt( RUSBTESTDEVICE_STATECHANGEL_ENTRY, this );
	
	OstTraceExt2(TRACE_NORMAL, RUSBTESTDEVICE_STATECHANGEL, "Client state change to %d err=%d",aNewState,aChangeCompletionCode);
	
	// Notify the test case of failed state change notification
	
	if(aChangeCompletionCode != KErrNone)
		{
		return ReportError(aChangeCompletionCode);
		}
	
	// Check the state change
	
	if(iCurrentState == EUsbcDeviceStateConfigured)
		{
		// Device is already in a fully configured state
		
		if(aNewState == EUsbcDeviceStateConfigured)
			{
			// Do nothing as this is the current state anyway
			}
		else
			{
			// The is a state change from EUsbcDeviceStateConfigured to aNewState
			// so stop reading from control ep0
			
			OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_STATECHANGEL_DUP01, "Ignoring control ep0");
			
			// Stop reading ep0 directed requests
			
			StopEp0Reading();
			
			// Update state
						
			iCurrentState = aNewState;
			}
		}
	else
		{
		// Device is not in a fully configured state
		
		if(aNewState == EUsbcDeviceStateConfigured)
			{
			// Device has now been placed into a fully configured state by the host
			// so start reading from control ep0
			
			OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_STATECHANGEL_DUP02, "Reading from control ep0");
			
			// Start reading ep0 directed requests
			
			StartEp0Reading();
			
			// Update state
						
			iCurrentState = aNewState;
			}
		else
			{
			// Just update the state
			
			iCurrentState = aNewState;
			}
		}
				
	// Forward the state change notification to derived classes
	
	OnStateChangeL(aNewState);
	OstTraceFunctionExit1( RUSBTESTDEVICE_STATECHANGEL_EXIT, this );
	}
	

void RUsbTestDevice::StartEp0Reading()
	{
    OstTraceFunctionEntry1( RUSBTESTDEVICE_STARTEP0READING_ENTRY, this );

	// Start reading device directed ep0 requests
	
	TInt err(iDeviceEp0->Start());
	if(err != KErrNone)
		{
		return ReportError(err);
		}
		
	// Start reading interface directed requests
			
	TInt interfaceCount(iInterfaces.Count());
	for(TInt i=0; i<interfaceCount; i++)
		{
		iInterfaces[i]->StartEp0Reading();
		}
	OstTraceFunctionExit1( RUSBTESTDEVICE_STARTEP0READING_EXIT, this );
	}


void RUsbTestDevice::StopEp0Reading()
	{
    OstTraceFunctionEntry1( RUSBTESTDEVICE_STOPEP0READING_ENTRY, this );

	// Stop reading interface directed requests
	
	TInt interfaceCount(iInterfaces.Count());
	for(TInt i=0; i<interfaceCount; i++)
		{
		iInterfaces[i]->StopEp0Reading();
		}
		
	// Stop reading device directed requests from ep0
			
	TInt err(iDeviceEp0->Stop());
	if(err != KErrNone)
		{
		return ReportError(err);
		}
	OstTraceFunctionExit1( RUSBTESTDEVICE_STOPEP0READING_EXIT, this );
	}


void RUsbTestDevice::AcknowledgeRequestReceived()
	{
	OstTraceFunctionEntry1( RUSBTESTDEVICE_ACKNOWLEDGEREQUESTRECEIVED_ENTRY, this );
	
	TInt err(iDeviceEp0->Reader().Acknowledge());
	OstTrace1(TRACE_NORMAL, RUSBTESTDEVICE_ACKNOWLEDGEREQUESTRECEIVED, "err = %d",err);
	if(err != KErrNone)
		{
		ReportError(err);
		}
	OstTraceFunctionExit1( RUSBTESTDEVICE_ACKNOWLEDGEREQUESTRECEIVED_EXIT, this );
	}



void RUsbTestDevice::ReportError(TInt aCompletionCode)
	{
	OstTraceFunctionEntryExt( RUSBTESTDEVICE_REPORTERROR_ENTRY, this );
	OstTraceExt3(TRACE_NORMAL, RUSBTESTDEVICE_REPORTERROR, "err or aCompletionCode = %d, observer status = %d, KRequestPending = %d",
			aCompletionCode, iObserverStatus->Int(), KRequestPending);
	if(*iObserverStatus == KRequestPending)
		{
		OstTrace0(TRACE_NORMAL, RUSBTESTDEVICE_REPORTERROR_DUP01, "In complete request");
		User::RequestComplete(iObserverStatus,aCompletionCode);
		}
	OstTraceFunctionExit1( RUSBTESTDEVICE_REPORTERROR_EXIT, this );
	}
	

	}
	
