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

#include <e32base.h>
#include <e32base_private.h>
#include <d32usbc.h>
#include "endpointwriter.h"
#include "testdebug.h"

namespace NUnitTesting_USBDI
	{
const TUint KMaxTransferBuffer = 0x1000;


CEndpointWriter::CEndpointWriter(RDevUsbcClient& aClientDriver,TEndpointNumber aEndpoint)
:	CActive(EPriorityStandard),
	iClientDriver(aClientDriver),
	iEndpoint(aEndpoint),
	iBufPtr(NULL,0)
	{
	CActiveScheduler::Add(this);
	}
	
					
CEndpointWriter::~CEndpointWriter()
	{
	LOG_FUNC
	
	Cancel();
	if(iBuffer)
		{
		RDebug::Printf("Freeing %d bytes", iBuffer->Size());
		}
	delete iBuffer;
	}


void CEndpointWriter::DoCancel()
	{
	LOG_FUNC
	
	// Cancel the write to the endpoint
	
	iClientDriver.WriteCancel(iEndpoint);
	}
	
	
TUint CEndpointWriter::NumBytesWrittenSoFar()
	{
	return iNumBytesWritten;
	}

void CEndpointWriter::RunL()
	{
	LOG_FUNC
	
	TInt completionCode(iStatus.Int());
	RDebug::Printf("Write completed, err=%d",completionCode);
	
	iNumBytesWritten += iNumBytesOnCurrentWrite; // all zero if not a repeated write
	if(iNumBytesWritten < iTotalNumBytes)
		//This conditional will not be entered for non-repeat cases because then 
		//'iNumBytesWritten' and 'iTotalNumBytes' will both be zero.
		{
		TUint totalNumBytesStillToWrite = iTotalNumBytes - iNumBytesWritten;

		//NB iNumBytesOnCurrentWrite should remain at the requested 'bytes per Write' value until the last iteration
		iNumBytesOnCurrentWrite = totalNumBytesStillToWrite <= iNumBytesOnCurrentWrite ? totalNumBytesStillToWrite : iNumBytesOnCurrentWrite;

		//Only add a ZLP, if requested and if the last 'Write'
		TBool useUsb = totalNumBytesStillToWrite <= iNumBytesOnCurrentWrite ? iUseZLP : EFalse;
		TPtrC8 writeDesc = iBufPtr.Mid(iNumBytesWritten%iDataPatternLength, iNumBytesOnCurrentWrite);
		RDebug::Printf("Total Bytes To Write = %d, Bytes Still To Write = %d, Bytes Written = %d, Bytes on Current 'Write'", iTotalNumBytes, totalNumBytesStillToWrite, iNumBytesWritten, iNumBytesOnCurrentWrite);
		 
		RDebug::Printf("\n");
		RDebug::Printf("First 256 bytes (or all) of data to write");
		RDebug::RawPrint(writeDesc);
		RDebug::Printf("\n");
		
		
		Write(writeDesc, useUsb, EFalse);
		}
	else
		{
		if(iBuffer!=NULL)
			{
			RDebug::Printf("Freeing %d bytes", iBuffer->Size());
			}
		else
			{
			RDebug::Printf("iBuffer is NULL");
			}
		if(iTotalNumBytes != 0)
			//if a repeated write
			{
			RDebug::Printf("Total Bytes = %d, Bytes Written = %d", iTotalNumBytes, iNumBytesWritten);
			}
		delete iBuffer;
		iBuffer = 0;
		iNumBytesOnCurrentWrite = 0;
		iNumBytesWritten = 0;
		iTotalNumBytes = 0;
		iDataPatternLength = 0;
		iUseZLP = EFalse;
		}
	}


TInt CEndpointWriter::RunError(TInt aError)
	{
	LOG_FUNC
	
	aError = KErrNone;
	return aError;
	}


void CEndpointWriter::Write(const TDesC8& aData, TBool aUseZLP, TBool aCreateBuffer)
	{
	LOG_FUNC
	
  	if(aCreateBuffer == EFalse)
  		{
  		RDebug::Printf("Use ZLP %d", aUseZLP?1:0);
  		iClientDriver.Write(iStatus,iEndpoint,aData,aData.Length(),aUseZLP);
  		SetActive();
 		return;
  		}

	
	//Copy aData to this object's buffer
	//'aData' will go out of scope before the USB driver 'Write' completes	
	delete iBuffer;
  	iBuffer = NULL;
	iBuffer = HBufC8::NewL(aData.Length());
	iBufPtr.Set(iBuffer->Des());
	iBufPtr.Copy(aData);

	// Write the data to the host through the endpoint (host opened pipe)
	RDebug::Printf("Write Length = %d", iBufPtr.Length());
	RDebug::RawPrint(iBufPtr);
	RDebug::Printf("\n");
	RDebug::Printf("Use ZLP %d", aUseZLP?1:0);
	iClientDriver.Write(iStatus,iEndpoint,iBufPtr,iBufPtr.Length(),aUseZLP);
	SetActive();
	}

TInt CEndpointWriter::WriteSynchronous(const TDesC8& aData, TBool aUseZLP)
	{
	LOG_FUNC
	
	TRequestStatus status = KRequestPending;
	RDebug::Printf("Write Length = %d", aData.Length());
	RDebug::RawPrint(aData);
	RDebug::Printf("\n");
	RDebug::Printf("Use ZLP %d", aUseZLP?1:0);
	iClientDriver.Write(status,iEndpoint,aData,aData.Length(),aUseZLP);
	User::WaitForRequest(status);
	RDebug::Printf("Write has completed with error %d", status.Int());
	return status.Int();
	}

void CEndpointWriter::WriteSynchronousUsingPatternL(const TDesC8& aData, const TUint aNumBytes, const TBool aUseZLP)
	{
	LOG_FUNC

	TBool useZLP = EFalse; //only want this if you are making the last call to client Write (=WriteSynchronous)
	if(aNumBytes <= aData.Length())
	//Don't need to allocate a buffer and copy to it - write will be done synchronously
		{
		if(aUseZLP)
			{
			useZLP = ETrue;
			}
		WriteSynchronous(aData.Left(aNumBytes),useZLP);
		}

	else if(aNumBytes <= KMaxTransferBuffer)
	//Create a buffer based on the data pattern sent and use just one 'Synchronous Write'
		{
		if(aUseZLP)
			{
			useZLP = ETrue;
			}
	  	TInt repeats = aNumBytes/aData.Length();
	  	TInt extraBytes = aNumBytes%aData.Length();
	  	delete iBuffer;
	  	iBuffer = NULL;
	 	iBuffer = HBufC8::NewL(aNumBytes);
	 	TPtr8 ptr = iBuffer->Des();
	 	ptr.Zero();
	  	for(TUint i =0; i<repeats; i++)
	  		{
	  		ptr.Append(aData);
	  		}
	  	if(extraBytes)
	  		{
	  		ptr.Append(aData.Left(extraBytes));
	  		}
	  	WriteSynchronous(ptr, useZLP);
	  	delete iBuffer;
		}

	else
	//Create a buffer based on the data pattern sent and use SEVERAL 'Synchronous Write's
		{
		//Write data in reasonably sized chunks
		//Create buffer using max whole number of data patterns
	  	TInt repeats = KMaxTransferBuffer/aData.Length();
	  	CreateBigBuffer(aData, repeats);

		//Now write data
	  	repeats = aNumBytes/iBufPtr.Length(); //re-use 'repeats'
	  	TInt endBytes = aNumBytes%iBufPtr.Length();
	  	for(TInt i=0;i<repeats;i++)
	  		{
			if(i==(repeats-1)&&endBytes==0)
				//last loop - request ZLP if appropriate
				{
				WriteSynchronous(*iBuffer, aUseZLP); //if last 'Write'
				}
			else
				{
				WriteSynchronous(*iBuffer, EFalse);
				}
	  		}
	  	if(endBytes)
	  		{
			WriteSynchronous(iBufPtr.Left(endBytes), aUseZLP); //if last 'Write'
	  		}
		}
	delete iBuffer;
	iBuffer = 0;
	}

void CEndpointWriter::WriteSynchronousUsingPatternL(const TDesC8& aData, const TUint aNumBytes)
	{
	WriteSynchronousUsingPatternL(aData, aNumBytes, ETrue);
	}

void CEndpointWriter::WriteSynchronousUsingPatternAndHaltL(const TDesC8& aData, const TUint aNumBytes)
	{
	LOG_FUNC
	WriteSynchronousUsingPatternL(aData, aNumBytes, EFalse);
	iClientDriver.HaltEndpoint(iEndpoint);
	}

void CEndpointWriter::WriteUsingPatternL(const TDesC8& aData, const TUint aNumBytes, const TBool aUseZLP)
	{
	LOG_FUNC

	RDebug::Printf("Allocating %d bytes", aNumBytes);
  	delete iBuffer;
  	iBuffer = NULL;
	iBuffer = HBufC8::NewL(aNumBytes);
	RDebug::Printf("Allocated %d bytes", aNumBytes);
	iBufPtr.Set(iBuffer->Des());
	iBufPtr.Zero();
	TInt repeats = aNumBytes/aData.Length();
	for(TUint i =0; i<repeats; i++)
		{
		iBufPtr.Append(aData);
		}
	if(TInt extraBytes = aNumBytes%aData.Length())
		{
		iBufPtr.Append(aData.Left(extraBytes));
		}
	Write(*iBuffer, aUseZLP, EFalse);
	}

void CEndpointWriter::WriteInPartsUsingPatternL(const TDesC8& aData, const TUint aNumBytesPerWrite, TUint aTotalNumBytes, const TBool aUseZLP)
	{
	LOG_FUNC

	iUseZLP = aUseZLP;
	TInt repeats = aNumBytesPerWrite/aData.Length() + 1;
	repeats *= 2;
	CreateBigBuffer(aData, repeats);
	iDataPatternLength = aData.Length();
	iTotalNumBytes = aTotalNumBytes;
	iNumBytesOnCurrentWrite = aNumBytesPerWrite;
	iNumBytesWritten = 0;
	Write(iBufPtr.Mid(iNumBytesWritten%iDataPatternLength, iNumBytesOnCurrentWrite), EFalse, EFalse); //this is not the first 'Write' so do not use a ZLP
	RDebug::Printf("Write %d bytes",iNumBytesOnCurrentWrite);
	RDebug::Printf("Total Bytes = %d, Data Pattern Length = %d", iTotalNumBytes, iDataPatternLength);
	}

void CEndpointWriter::CreateBigBuffer(const TDesC8& aData, const TUint aRepeats)
/*
Create a payload buffer a section of which can always be used for each cyclic 'Write'.
*/
	{
	//We require a buffer containing a sufficient number of repeats of the data pattern
	//to allow us simply to use a section of it for any individual 'Write' payload.
 	delete iBuffer;
 	iBuffer = NULL;
 	RDebug::Printf("Data buffer is using %d repeats of string starting...\n\"%S\"", aRepeats, &aData);
 	iBuffer = HBufC8::NewL(aRepeats*aData.Length());
	iBufPtr.Set(iBuffer->Des());
	iBufPtr.Zero();
 	for(TUint i =0; i<aRepeats; i++)
  		{
  		iBufPtr.Append(aData);
  		}
	}

	}