kerneltest/e32test/usbho/t_usbdi/src/TestInterfaceBase.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 testinterfacebase.cpp
// @internalComponent
// 
//

#include "testdevicebase.h"
#include "testinterfacebase.h"
#include "testinterfacesettingbase.h"
#include "testdebug.h"
#include "controltransferrequests.h"
#include "endpointwriter.h"


namespace NUnitTesting_USBDI
	{

	
CInterfaceBase::CInterfaceBase(RUsbTestDevice& aTestDevice,const TDesC16& aName)
:	iDevice(aTestDevice),
	iInterfaceName(aName),
	iCurrentAlternateInterfaceSetting(0) // The default alternate interface setting will be zero when opened
	{
	}
	
CInterfaceBase::~CInterfaceBase()
	{
	LOG_FUNC
	
	delete iAuxBuffer;
	delete iStallWatcher;
	delete iSelectionWatcher;
		
	// Release all interfaces
	delete iEp0Writer;
	
	// Destroy the endpoint 0 reader
	delete iEp0Reader;
		
	// Destroy interface settings
	iAlternateSettings.ResetAndDestroy();
	
	// Close the channel to the driver
	iClientDriver.Close();
	}
	
	
void CInterfaceBase::BaseConstructL()
	{
	LOG_FUNC
	// Open channel to driver
	TInt err(iClientDriver.Open(0));
	if(err != KErrNone)
		{
		RDebug::Printf("<Error %d> Unable to open a channel to USB client driver",err);
		User::Leave(err);
		}

	// Start the watcher for host selecting alternate interface settings
	iSelectionWatcher = CAlternateInterfaceSelectionWatcher::NewL(iClientDriver,*this);
	
	//
	iStallWatcher = new (ELeave) CEndpointStallWatcher(iClientDriver);
	
	// Create the Ep0 reader/writer
	iEp0Reader = new (ELeave) CControlEndpointReader(iClientDriver,*this);
	iEp0Writer = new (ELeave) CEndpointWriter(iClientDriver,EEndpoint0);

	// Hide bus from host while interfaces are being set up
	iClientDriver.DeviceDisconnectFromHost();
	}


void CInterfaceBase::AddInterfaceSettingL(CInterfaceSettingBase* aInterfaceSetting)
	{
	LOG_FUNC
	
	// Append to the container
	TInt err(iAlternateSettings.Append(aInterfaceSetting));
	if(err != KErrNone)
		{
		RDebug::Printf("<Error %d> Unable to add interface setting",err);
		User::Leave(err);
		}
	
	// Get the current number of alternate interface settings	
	TInt alternateSettingNumber(iAlternateSettings.Count()-1);

	TUint endpointSettingCount(aInterfaceSetting->iInterfaceInfo().iTotalEndpointsUsed);
	
	if(endpointSettingCount > 0)
		{
		RDebug::Printf("%u endpoint(s) to configure for this interface setting",endpointSettingCount);
				
		// Device capabilities
		TUsbDeviceCaps devCaps;
		err = iClientDriver.DeviceCaps(devCaps);
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to retrieve device capabilities",err);
			User::Leave(err);
			}

		// Endpoint capabilities
		TUsbcEndpointData endpointCaps[KUsbcMaxEndpoints];
		TPtr8 dataptr(reinterpret_cast<TUint8*>(endpointCaps), sizeof(endpointCaps), sizeof(endpointCaps));
		err = iClientDriver.EndpointCaps(dataptr);
		if(err != KErrNone)
			{
			RDebug::Printf("<Error %d> Unable to get endpoint capabilities",err);
			User::Leave(err);
			}		
		
		TInt totalEndpoints(devCaps().iTotalEndpoints);
		
		// Loop through available hardware endpoints to find suitable one
		// i.e. endpoints that can be configured
		
		TUint epIndex(0);
		TUint epCount(0);
		
		for(; epIndex<totalEndpoints; epIndex++)
			{
			RDebug::Printf("Examining hardware endpoint %u",epIndex);
			const TUsbcEndpointData ep = endpointCaps[epIndex];
			
			// Check the endpoint index to see if already claimed
			if(!ep.iInUse)
				{			
				RDebug::Printf("...its free");
				const TUsbcEndpointCaps caps(ep.iCaps);
				
				// Information about the endpoint we are looking for	
				TUsbcEndpointInfo& endpointSpec = aInterfaceSetting->iInterfaceInfo().iEndpointData[epCount];
						
				if( (caps.iTypesAndDir & (endpointSpec.iDir | endpointSpec.iType)) == 
					(endpointSpec.iDir | endpointSpec.iType) )
					{
					// Found suitable endpoint
					
					// Create the reader/writer for this endpoint					
					
					if(endpointSpec.iDir == KUsbEpDirIn)
						{
						// Create an endpoint writer for this endpoint
						
						aInterfaceSetting->CreateEndpointWriterL(iClientDriver,(epCount+1));
						RDebug::Printf("Created endpoint writer for endpoint%d",epCount+1);
						}
					else if(endpointSpec.iDir == KUsbEpDirOut)
						{
						// Create an endpoint reader for this endpoint
												
						aInterfaceSetting->CreateEndpointReaderL(iClientDriver,epCount+1);
						RDebug::Printf("Created endpoint reader for endpoint%d",epCount+1);
						}					
					
					epCount++; // Increment to next endpoint spec
					RDebug::Printf("Endpoint %u configured",epCount);
					endpointSpec.iSize = caps.MaxPacketSize();
					
					if(epCount >= endpointSettingCount)
						{
						// Found all desired endpoints
						break;
						}
					}
				}
			else
				{
				RDebug::Printf("...its busy");
				}
			}
		
		RDebug::Printf("Configure %u out of %u endpoints",epCount,endpointSettingCount);			
		
		if(epCount < endpointSettingCount)
			{
			RDebug::Printf("<Error %d> Only managed to configure %u out of %u endpoints",KErrNotFound,epCount,endpointSettingCount);
			User::Leave(KErrNotFound);
			}			
		}
	else
		{
		RDebug::Printf("No endpoints for this interface setting");
		}
	
	// Add the new setting to the device
	err = iClientDriver.SetInterface(alternateSettingNumber,aInterfaceSetting->iInterfaceInfo);
	if(err != KErrNone)
		{
		RDebug::Printf("<Error %d> Unable to set the alternate interface setting %d",err,alternateSettingNumber);
		User::Leave(err);
		}
	
	RDebug::Printf("Alternate interface setting %d set",alternateSettingNumber);
	}


TInt CInterfaceBase::StallEndpoint(TUint16 aEndpointNumber)
	{
	LOG_FUNC
	
	RDebug::Printf("Stalling endpoint%d",aEndpointNumber);
	return iClientDriver.HaltEndpoint(static_cast<TEndpointNumber>(aEndpointNumber));
	}

	
CInterfaceSettingBase& CInterfaceBase::AlternateSetting(TInt aSettingNumber) const
	{
	return *iAlternateSettings[aSettingNumber];
	}

	
TInt CInterfaceBase::InterfaceSettingCount() const
	{
	return iAlternateSettings.Count();
	}


TUint32 CInterfaceBase::ExtractNumberL(const TDesC8& aPayload)
	{
	LOG_FUNC

	// Read the number of repeats and the data supplied by the host, on the specified endpoint
	TLex8 lex(aPayload.Left(KNumberStringLength));
	TUint32 numBytes;
	User::LeaveIfError(lex.Val(numBytes, EDecimal));
	RDebug::Printf("Writing %d bytes using string pattern below to IN endpoint",numBytes);
	RDebug::RawPrint(aPayload.Mid(KNumberStringLength));
	RDebug::Printf(""); //new line
	return numBytes;
	}

void CInterfaceBase::ExtractTwoNumbersL(const TDesC8& aPayload, TUint32& aFirstNum, TUint32& aSecondNum)
	{
	LOG_FUNC

	// Read the number of repeats and the data supplied by the host, on the specified endpoint
	TLex8 lex1(aPayload.Left(KNumberStringLength));
	User::LeaveIfError(lex1.Val(aFirstNum, EDecimal));
	TLex8 lex2(aPayload.Mid(KNumberStringLength, KNumberStringLength));
	User::LeaveIfError(lex2.Val(aSecondNum, EDecimal));
	RDebug::Printf("Writing or Reading a total of %d bytes in repeats of %d bytes using string pattern below to IN endpoint",aFirstNum,aSecondNum);
	RDebug::RawPrint(aPayload.Mid(2*KNumberStringLength));
	RDebug::Printf(""); //new line
	return;
	}

void CInterfaceBase::AlternateInterfaceSelectedL(TInt aAlternateInterfaceSetting)
	{
	LOG_FUNC
	RDebug::Printf("Interface %S:",&iInterfaceName);	
	iCurrentAlternateInterfaceSetting = aAlternateInterfaceSetting;
	}


TInt CInterfaceBase::ProcessRequestL(TUint8 aRequest,TUint16 aValue,TUint16 aIndex,
	TUint16 aDataReqLength,const TDesC8& aPayload)
	{
	LOG_FUNC
	RDebug::Printf("Interface %S:",&iInterfaceName);
	
	switch(aRequest)
		{
		case KVendorEmptyRequest:
			// Acknowledge the request and do nothing
			iEp0Reader->Acknowledge();
			
			RDebug::Printf("Request: Empty");
			break;
			
		case KVendorPutPayloadRequest:
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			RDebug::Printf("Put payload");
			if(aPayload.Compare(_L8("DEADBEEF")) != 0)
				{
				RDebug::Printf("<Error %d> Payload not as expected",KErrCorrupt);
				iDevice.ReportError(KErrCorrupt);
				}
			break;
			
		case KVendorGetPayloadRequest:
			{
			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 = iEp0Writer->WriteSynchronous(*iAuxBuffer, ETrue);
			RDebug::Printf("Write (from interface callback) executed with error %d", ret);
			}
			break;
			
		case KVendorGetRecordedNumBytesReadInPayloadRequest:
			{
			delete iAuxBuffer;
			iAuxBuffer = HBufC8::NewL(KNumberStringLength);
			TPtr8 ptr(iAuxBuffer->Des());
			TInt retValue = 0;
			retValue = AlternateSetting(iCurrentAlternateInterfaceSetting).NumBytesReadSoFarL(aValue);
			ptr.Zero();
			ptr.Format(KNumberFormatString, retValue);
	
			//Perform synchronous write to EP0
			//This allows the subsequent 'Read' request to
			//take place
			TInt ret = iEp0Writer->WriteSynchronous(*iAuxBuffer, ETrue);
			RDebug::Printf("Write (from interface callback) executed with error %d", ret);
			}
			break;
			
		case KVendorGetRecordedNumBytesWrittenInPayloadRequest:
			{
			delete iAuxBuffer;
			iAuxBuffer = HBufC8::NewL(KNumberStringLength);
			TPtr8 ptr(iAuxBuffer->Des());
			TInt retValue = 0;
			retValue = AlternateSetting(iCurrentAlternateInterfaceSetting).NumBytesWrittenSoFarL(aValue);
			ptr.Zero();
			ptr.Format(KNumberFormatString, retValue);
	
			//Perform synchronous write to EP0
			//This allows the subsequent 'Read' request to
			//take place
			TInt ret = iEp0Writer->WriteSynchronous(*iAuxBuffer, ETrue);
			RDebug::Printf("Write (from interface callback) executed with error %d", ret);
			}
			break;
			
		case KVendorWriteToEndpointRequest:
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			RDebug::Printf("Writing %d bytes to IN endpoint (index %d)",aPayload.Length(),aValue);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			
			AlternateSetting(iCurrentAlternateInterfaceSetting).WriteSpecifiedDataToEndpointL(aPayload,aValue);
			break;
			
		case KVendorCancelWriteToEndpointRequest:
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			RDebug::Printf("CANCEL Writing to IN endpoint (index %d)",aValue);
			
			// CANCEL writing the data supplied by the host, back to the host though the specified endpoint
			
			AlternateSetting(iCurrentAlternateInterfaceSetting).CancelWriteDataToEndpointL(aValue);
			break;
			
		case KVendorPatternWriteToEndpointRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the number of repeats and the data supplied by the host, on the specified endpoint
			TUint32 numBytes = ExtractNumberL(aPayload);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			AlternateSetting(iCurrentAlternateInterfaceSetting).WriteSpecifiedDataToEndpointL(aPayload.Mid(KNumberStringLength),numBytes,aValue);
			}
			break;
			
		case KVendorPatternWriteSynchronousToEndpointRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the number of repeats and the data supplied by the host, on the specified endpoint
			TUint32 numBytes = ExtractNumberL(aPayload);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			AlternateSetting(iCurrentAlternateInterfaceSetting).WriteSynchronousSpecifiedDataToEndpointL(aPayload.Mid(KNumberStringLength),numBytes,aValue);
			}
			break;
			
		case KVendorPatternWriteSynchronousToAndHaltEndpointRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the number of repeats and the data supplied by the host, on the specified endpoint
			TUint32 numBytes = ExtractNumberL(aPayload);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			AlternateSetting(iCurrentAlternateInterfaceSetting).WriteSynchronousSpecifiedDataToAndHaltEndpointL(aPayload.Mid(KNumberStringLength),numBytes,aValue);
			}
			break;
			
		case KVendorRepeatedReadAndValidateDataRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the number of bytes to read in total and per individual 'Read' together with the data supplied by the host, on the specified endpoint
			TUint32 numBytesPerRead = 0;
			TUint32 totalNumBytes = 0;
			ExtractTwoNumbersL(aPayload, numBytesPerRead, totalNumBytes);
			RDebug::Printf("Extracted: Number of Bytes per Read = %d, Total Number of Bytes = %d",numBytesPerRead,totalNumBytes);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			AlternateSetting(iCurrentAlternateInterfaceSetting).RepeatedReadAndValidateFromEndpointL(aPayload.Mid(KTwoNumberStringLength),numBytesPerRead,totalNumBytes,aValue);
			}
			break;
			
		case KVendorRepeatedPatternWriteDataRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the number of bytes to write in total and per individual 'Write' together with the data supplied by the host, on the specified endpoint
			TUint32 numBytesPerWrite = 0;
			TUint32 totalNumBytes = 0;
			ExtractTwoNumbersL(aPayload, numBytesPerWrite, totalNumBytes);
			RDebug::Printf("Extracted: Number of Bytes per Read = %d, Total Number of Bytes = %d",numBytesPerWrite,totalNumBytes);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			AlternateSetting(iCurrentAlternateInterfaceSetting).RepeatedWriteSpecifiedDataToEndpointL(aPayload.Mid(KTwoNumberStringLength),numBytesPerWrite,totalNumBytes,aValue);
			}
			break;
			
		case KVendorWriteCachedReadRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			TUint16 readEndpoint = aValue >> 8; //HI 8 buts
			TUint16 writeEndpoint = aValue & 0x00ff; //LO 8 bits
			
			RDebug::Printf("Writing data cached on OUT endpoint (index %d) to IN endpoint (index %d)",readEndpoint,writeEndpoint);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			
			AlternateSetting(iCurrentAlternateInterfaceSetting).WriteCachedEndpointDataToEndpointL(readEndpoint,writeEndpoint);
			}
			break;
			
		case KVendorWriteSynchronousCachedReadRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			TUint16 readEndpoint = aValue >> 8; //HI 8 buts
			TUint16 writeEndpoint = aValue & 0x00ff; //LO 8 bits
			
			RDebug::Printf("Writing data cached on OUT endpoint (index %d) to IN endpoint (index %d)",readEndpoint,writeEndpoint);
			
			// Write the data supplied by the host, back to the host though the specified endpoint
			
			AlternateSetting(iCurrentAlternateInterfaceSetting).WriteSynchronousCachedEndpointDataToEndpointL(readEndpoint,writeEndpoint);
			}
			break;
			
		case KVendorSplitWriteSynchronousCachedReadRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			TUint16 readEndpoint = aValue >> 8; //HI 8 buts
			TUint16 writeEndpoint = aValue & 0x00ff; //LO 8 bits
			RDebug::Printf("Writing data cached on OUT endpoint (index %d) to IN endpoint (index %d) in sections of....",readEndpoint,writeEndpoint);
			
			// Read the number of bytes to use for each Write
			TUint numBytes[KNumSplitWriteSections];
			TUint numBytesWritten = 0;
			for(TUint i=0; i<KNumSplitWriteSections; ++i)
				{
				TLex8 lex(aPayload.Mid(i*KNumberStringLength, KNumberStringLength));
				User::LeaveIfError(lex.Val(numBytes[i], EDecimal));
				RDebug::Printf("%d bytes", numBytes[i]);
				// Write the data supplied by the host, back to the host though the specified endpoint
				AlternateSetting(iCurrentAlternateInterfaceSetting).WriteSynchronousCachedEndpointDataToEndpointL(readEndpoint,writeEndpoint,numBytesWritten,numBytes[i]);
				// Updates bytes written for next round of 'for'loop
				numBytesWritten += numBytes[i];
				}
			}
			break;
			
		case KVendorReadFromEndpointRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the amount of data supplied by the host, on the specified endpoint
			TLex8 lex(aPayload);
			TUint32 numBytes;
			User::LeaveIfError(lex.Val(numBytes, EDecimal));
			RDebug::Printf("Reading %d bytes on OUT endpoint (index %d)",numBytes,aValue);
			AlternateSetting(iCurrentAlternateInterfaceSetting).ReadDataFromEndpointL(numBytes,aValue);
			}
			break;
			
		case KVendorReadFromAndHaltEndpointRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the amount of data supplied by the host, on the specified endpoint
			TLex8 lex(aPayload);
			TUint32 numBytes;
			User::LeaveIfError(lex.Val(numBytes, EDecimal));
			RDebug::Printf("Reading %d bytes on OUT endpoint (index %d) ... then halting endpoint",numBytes,aValue);
			AlternateSetting(iCurrentAlternateInterfaceSetting).ReadDataFromAndHaltEndpointL(numBytes,aValue);
			}
			break;
			
		case KVendorCancelAnyReadFromEndpointRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			RDebug::Printf("CANCEL Reading on OUT endpoint (index %d)",aValue);
			AlternateSetting(iCurrentAlternateInterfaceSetting).CancelAnyReadDataFromEndpointL(aValue);
			}
			break;
			
		case KVendorReadUntilShortFromEndpointRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the amount of data supplied by the host, on the specified endpoint
			TLex8 lex(aPayload);
			TUint32 numBytes;
			User::LeaveIfError(lex.Val(numBytes, EDecimal));
			RDebug::Printf("Reading %d bytes on OUT endpoint (index %d)",numBytes,aValue);
			AlternateSetting(iCurrentAlternateInterfaceSetting).ReadDataUntilShortFromEndpointL(numBytes,aValue);
			}
			break;
			
		case KVendorStringValidationRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			// Read the number of repeats and the data supplied by the host, on the specified endpoint
			TLex8 lex(aPayload.Left(KNumberStringLength));
			RDebug::Printf("NUMBER STRING LENGTH CALCULATED AS %d",KNumberStringLength);
			TUint32 numBytes;
			User::LeaveIfError(lex.Val(numBytes, EDecimal));
			RDebug::Printf("Validation");
			RDebug::Printf("Checking %d bytes using string pattern below exist in the buffer for endpoint %d",numBytes,aValue);
			RDebug::RawPrint(aPayload.Mid(KNumberStringLength));
			
			delete iAuxBuffer;
			iAuxBuffer = HBufC8::NewL(KPassFailStringLength);
			TPtr8 ptr(iAuxBuffer->Des());
			if(AlternateSetting(iCurrentAlternateInterfaceSetting).ValidateCachedEndpointDataL(aPayload.Mid(KNumberStringLength),numBytes,aValue))
				{
				ptr.Copy(KClientPassString);
				}
			else
				{
				ptr.Copy(KClientFailString);
				}
			}
			break;
			
		case KVendorRecordedValidationResultRequest:
			{
			// Acknowledge the request
			iEp0Reader->Acknowledge();
			
			delete iAuxBuffer;
			iAuxBuffer = HBufC8::NewL(KPassFailStringLength);
			TPtr8 ptr(iAuxBuffer->Des());
			if(AlternateSetting(iCurrentAlternateInterfaceSetting).CachedEndpointResultL(aValue))
				{
				ptr.Copy(KClientPassString);
				}
			else
				{
				ptr.Copy(KClientFailString);
				}
			}
			break;
			
		case KVendorUnrespondRequest:
			// Do not acknowledge this request
			
			RDebug::Printf("Unrespond request: continually NAK the host");
			break;
			
		case KVendorStallRequest:
			{
			// Stall the specified endpoint		
			iEp0Reader->Acknowledge();
			RDebug::Printf("Stalling endpoint%d",aValue);
			TInt err = StallEndpoint(aValue);
			if(err != KErrNone)
				{
				RDebug::Printf("<Error %d> unable to stall endpoint index %d",err,aValue);
				iDevice.ReportError(err);
				}
			}

		default:
			// Maybe forward to derived classes
			break;
		}

	return KErrNone;
	}
	

void CInterfaceBase::StartEp0Reading()
	{
	LOG_FUNC
	
	iEp0Reader->ReadRequestsL();
	}
	

void CInterfaceBase::StopEp0Reading()
	{
	LOG_FUNC
	
	iEp0Reader->Cancel();		
	}

	}