kerneltest/e32test/usbho/t_usbdi/src/TestDeviceBase.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2007-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:
// @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 <e32property.h>

namespace NUnitTesting_USBDI
	{

RUsbTestDevice::RUsbTestDevice()
: 	iStateWatcher(NULL), 
	iCurrentState(EUsbcDeviceStateUndefined), 
	iDeviceEp0(NULL), 
	iConnectTimer(NULL), iWakeupTimer(NULL),
	iAuxBuffer(NULL)
	{
	}
	
RUsbTestDevice::RUsbTestDevice(CBaseTestCase* aTestCase)
: 	iStateWatcher(NULL), 
	iCurrentState(EUsbcDeviceStateUndefined), 
	iDeviceEp0(NULL), 
	iConnectTimer(NULL), iWakeupTimer(NULL),
	iAuxBuffer(NULL)
	{
	LOG_FUNC	
	iTestCase = aTestCase;
	RDebug::Printf("iTestCase = %d", iTestCase);
	}
		
void RUsbTestDevice::ResetState()
	{
	iCurrentState = EUsbcDeviceStateUndefined;
	}

RUsbTestDevice::~RUsbTestDevice()
	{
	LOG_FUNC
	
	}
	
void RUsbTestDevice::Close()
	{
	LOG_FUNC

	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)
            {
            RDebug::Print(_L("Could not create the WordOfDeath P&S   (%d)"), r);
            }
		RDebug::Printf("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
		}
	}


void RUsbTestDevice::SubscribeToReports(TRequestStatus& aObserverStatus)
	{
	LOG_FUNC
	
	// Signal the request as pending
	
	iObserverStatus = &aObserverStatus;
	*iObserverStatus = KRequestPending;
	}


void RUsbTestDevice::CancelSubscriptionToReports()
	{
	LOG_FUNC
	
	// Signal the request as cancelled
	User::RequestComplete(iObserverStatus,KErrCancel);
	}
	
		
void RUsbTestDevice::OpenL()
	{
	LOG_FUNC	
	TInt err = KErrNone;
	
	RDebug::Printf("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)
		{
		RDebug::Printf("<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)
		{
		RDebug::Printf("<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));
 	RDebug::Printf("------ USB device capabilities -------");
	RDebug::Printf("Number of endpoints:                %d",iDeviceCaps().iTotalEndpoints);	
	RDebug::Printf("Supports Software-Connect:          %S",iDeviceCaps().iConnect ? &KYes() : &KNo());
	RDebug::Printf("Device is Self-Powered:             %S",iDeviceCaps().iSelfPowered ? &KYes() : &KNo());
	RDebug::Printf("Supports Remote-Wakeup:             %S",iDeviceCaps().iRemoteWakeup ? &KYes() : &KNo());
	RDebug::Printf("Supports High-speed:                %S",iDeviceCaps().iHighSpeed ? &KYes() : &KNo());
	RDebug::Printf("Supports unpowered cable detection: %S",(iDeviceCaps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ? &KYes() : &KNo());
	RDebug::Printf("--------------------------------------");
	
	}


TInt RUsbTestDevice::SetClassCode(TUint8 aClassCode,TUint8 aSubClassCode,TUint8 aDeviceProtocol)
	{
	LOG_FUNC

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		RDebug::Printf("<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)
			{
			RDebug::Printf("<Error %d> Unable to set the device dsecriptor",err);
			}
		}
	return err;
	}


TInt RUsbTestDevice::SetUsbSpecification(TUint16 aSpecification)
	{
	LOG_FUNC

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		RDebug::Printf("<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)
			{
			RDebug::Printf("<Error %d> Unable to set the device dsecriptor",err);
			}
		}
	return err;
	}


TInt RUsbTestDevice::SetVendor(TUint16 aVendorId)
	{
	LOG_FUNC

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		RDebug::Printf("<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)
			{
			RDebug::Printf("<Error %d> Unable to set the device descriptor",err);
			}
		}
	return err;
	}


TInt RUsbTestDevice::SetProduct(TUint16 aProductId,const TDesC16& aProductString,
				const TDesC16& aManufacturerString,const TDesC16& aSerialNumberString)
	{
	LOG_FUNC

	// Get Device descriptor
	TBuf8<KUsbDescSize_Device> deviceDescriptor;
	TInt err(iClientDriver.GetDeviceDescriptor(deviceDescriptor));
	if(err != KErrNone)
		{
		RDebug::Printf("<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)
			{
			RDebug::Printf("<Error %d> Unable to set the device dsecriptor",err);
			return err;
			}
		
		RDebug::Printf("Product Identity set");
	
		// Product string
		err = iClientDriver.SetProductStringDescriptor(aProductString);
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to set product string descriptor",err);
			return err;
			}

		// Manufacturer string
		err = iClientDriver.SetManufacturerStringDescriptor(aManufacturerString);
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to set the manufacturer string descriptor",err);
			return err;
			}
	
		// Serial number string
		err = iClientDriver.SetSerialNumberStringDescriptor(aSerialNumberString);
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to set the serial number string descriptor",err);
			return err;
			}
		}
	return KErrNone;
	}


TInt RUsbTestDevice::SetConfigurationString(const TDesC16& aConfigString)
	{
	LOG_FUNC

	TInt err(iClientDriver.SetConfigurationStringDescriptor(aConfigString));
	if(err != KErrNone)
		{
		RDebug::Printf("<Error %d> Unable to set configuration string descriptor",err);
		}
	return err;
	}


void RUsbTestDevice::AddInterface(CInterfaceBase* aInterface)
	{
	LOG_FUNC
		
	// Add the interface to the device
	TInt err = iInterfaces.Append(aInterface);
	
	if(err != KErrNone)
		{
		RDebug::Printf("<Error %d> Unable to add interface",err);
		return ReportError(err);
		}
	}


CInterfaceBase& RUsbTestDevice::Interface(TInt aIndex)
	{
	return *iInterfaces[aIndex];
	}


void RUsbTestDevice::SoftwareConnect()
	{
	LOG_FUNC
	TInt err(iClientDriver.PowerUpUdc());
	if((err != KErrNone) && (err != KErrNotReady))
		{
		RDebug::Printf("<Error %d> Power Up Udc",err);
		ReportError(err);
		}
		
	if(iDeviceCaps().iConnect) 
		{
		err = iClientDriver.DeviceConnectToHost();
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to connect to the host",err);
			ReportError(err);
			}
		}
	else
		{
		RDebug::Printf("Please connect device to Host");
		}	
	}   	
	 
void RUsbTestDevice::SoftwareDisconnect()
	{
	LOG_FUNC
	
	if(iDeviceCaps().iConnect) 
		{
		TInt err(iClientDriver.DeviceDisconnectFromHost());
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to disconnect from the host",err);
			ReportError(err);
			}
		}
	else
		{
		RDebug::Printf("Please disconnect device from Host");
		}
		
	}       


void RUsbTestDevice::RemoteWakeup()
	{
	LOG_FUNC
	if(iDeviceCaps().iConnect) 
		{
		TInt err(iClientDriver.SignalRemoteWakeup());
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to perform a remote wakeup",err);
			ReportError(err);
			}
		}
	else
		{
		RDebug::Printf("remote wakeup not supported");
		}
	}


TInt RUsbTestDevice::ProcessRequestL(TUint8 aRequest,TUint16 aValue,TUint16 aIndex,
	TUint16 aDataReqLength,const TDesC8& aPayload)
	{
	LOG_FUNC
	
	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)
		{
		RDebug::Printf("**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();
		return KErrAbort;
		}
	else if(aRequest == KVendorDisconnectDeviceCThenConnectDeviceARequest)
		{
		RDebug::Printf("**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();	
		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);
		RDebug::Printf("<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();
		RDebug::Printf("Put payload");
		if(aPayload.Compare(_L8("DEADBEEF")) != 0)
			{
			RDebug::Printf("<Error %d> Payload not as expected",KErrCorrupt);
			ReportError(KErrCorrupt);
			}
		}
	else if(aRequest == KVendorGetPayloadRequest)
		{
		// Handle a payload request to the host

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


void RUsbTestDevice::StateChangeL(TUsbcDeviceState aNewState,TInt aChangeCompletionCode)
	{
	LOG_FUNC
	
	RDebug::Printf("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
			
			RDebug::Printf("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
			
			RDebug::Printf("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);
	}
	

void RUsbTestDevice::StartEp0Reading()
	{
	LOG_FUNC

	// 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();
		}
	}


void RUsbTestDevice::StopEp0Reading()
	{
	LOG_FUNC

	// 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);
		}
	}


void RUsbTestDevice::AcknowledgeRequestReceived()
	{
	LOG_FUNC
	
	TInt err(iDeviceEp0->Reader().Acknowledge());
	RDebug::Printf("err = %d",err);
	if(err != KErrNone)
		{
		ReportError(err);
		}
	}



void RUsbTestDevice::ReportError(TInt aCompletionCode)
	{
	LOG_FUNC
	RDebug::Printf("err or aCompletionCode = %d, observer status = %d, KRequestPending = %d",
			aCompletionCode, iObserverStatus->Int(), KRequestPending);
	if(*iObserverStatus == KRequestPending)
		{
		RDebug::Printf("In complete request");
		User::RequestComplete(iObserverStatus,aCompletionCode);
		}
	}
	

	}