kerneltest/e32test/usbho/t_otgdi/src/b2bwatchers.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:
// testcaseb2broot.cpp
// @internalComponent
// 
//

#include <e32std.h>
#include <e32std_private.h>
#include <u32std.h> 	// unicode builds
#include <e32base.h>
#include <e32base_private.h>
#include <e32cons.h>
#include <e32Test.h>	// RTest header
#include <e32ver.h>
#include <e32def.h>
#include <e32def_private.h>
#include <d32otgdi.h>		// OTGDI header
#include <d32usbc.h>		// USBCC header
#include "testcaseroot.h"
#include "b2bwatchers.h"



void CNotifyWatcherBase::RunL()
	{
	DisplayEvent(); 
	iHandler.HandleEvent(iWatchType, GetEventValue()); // report the event upwards

	IssueAgain(); 
	SetActive();
	}


CNotifyCollector::CNotifyCollector(TRequestStatus &aStatus)  : iStatusStep(aStatus) 
	{
	LOG_FUNC
	TTimeIntervalDays oneday(1);
	iTimeStarted.HomeTime();
	iTimeStarted += (oneday); // force all durations to produce a negative (invalid) value
	}


/***************************************************************
 *  ~CNotifyCollector
 */ 
CNotifyCollector::~CNotifyCollector()
	{
	LOG_FUNC
	
	ClearAllEvents(); // free event arrays

	iNotifyObjects.Close();
	iFailureEvents.Close();
	iRequiredEvents.Close();
	iReceivedEvents.Close();
	}


/* The test-case calls this to clear the events stored.
 * Both the expected and already recieved events get cleared, this method 
 * is typically called at the start of each test-step
 */
void CNotifyCollector::ClearAllEvents(TBool aClearRecieved/*=ETrue*/, TBool aClearRequired /*=ETrue*/)
	{
	//LOG_FUNC
	if (aClearRequired)
		{
		iRequiredEvents.Reset();
		iFailureEvents.Reset();
		}
	if (aClearRecieved)
		{
		iReceivedEvents.Reset();
		}
	}


/* Creates and starts all 4 observers
 * Note: The Watchdog does not get started, because it needs an interval
 */
void CNotifyCollector::CreateObserversL(COtgRoot &aOtgDriver)
	{
	LOG_FUNC
	TInt watchType;
	ASSERT(aOtgDriver.LddLoaded());
	
	for (watchType=EWatcherTimeouts; watchType < EWatcherInvalid; watchType++)
		{
		CNotifyWatcherBase *pWatcher=0;
		switch ((TWatcherNotifyType )watchType)
			{
			case EWatcherTimeouts:
				pWatcher = COtgWatchdogWatcher::NewL(*this,  EWatcherTimeouts, aOtgDriver);
				break;
			case EWatcherState:
				pWatcher = COtgStateWatcher::NewL(*this , EWatcherState, aOtgDriver);
				break;
			case EWatcherEvent:
				pWatcher = COtgEventWatcher::NewL(*this, EWatcherEvent, aOtgDriver);
				break;
			case EWatcherMessage:
				pWatcher = COtgMessageWatcher::NewL(*this, EWatcherMessage, aOtgDriver);
				break;
			case EWatcherPeripheralState:
				pWatcher = CPeripheralStateWatcher::NewL(*this, EWatcherPeripheralState, aOtgDriver);
				break;
			case EWatcherAConnectionIdle:
				pWatcher = CAConnectionIdleWatcher::NewL(*this, EWatcherAConnectionIdle, aOtgDriver);
				break;

			}
		// the TRequest object is added to scheduler in it's own constructor
		
		// add it to our list so we can kill them after the test.
		iNotifyObjects.Append(pWatcher);
		//LOG_VERBOSE3(_L("Added watcher type %d, TRequest= %08X.\n"), iType, (TInt)(&pWatcher->iStatus));	
		
		// start all watchers, except for the watchdog
		if (watchType != EWatcherTimeouts)
			{
			pWatcher->StartWatching(-1);
			}
		}
	test.Printf(_L("\n"));
	}


/* NOTE: OTG must still be loaded or else we cannot cancel the outstanding event watches here!
 */
void CNotifyCollector::DestroyObservers()
	{
	LOG_FUNC
	
	// Free the Watchers
	for (TInt idx=0; idx < iNotifyObjects.Count(); idx++)
		{
		LOG_VERBOSE2(_L(".. %d .."), idx);		
		delete iNotifyObjects[idx];	// they will call their own Cancel() methods
		}
	iNotifyObjects.Close();	
	}


void CNotifyCollector::AddRequiredNotification(TWatcherNotifyType aType, TInt aValue)
	{
	AddRequiredOrFailureNotification(aType, aValue, EFalse);
	}

void CNotifyCollector::	AddFailureNotification(const TWatcherNotifyType aType, TInt aValue)
	{
	AddRequiredOrFailureNotification(aType, aValue, ETrue);
	}

/* Checks that a watcher for the event exists, and then adds it to a list of events required for a PASS condition
 * The timout event does not get added to this list.
 * If the parameter is a time, the timer gets started
 * If aEventMeansFailure is set True, then the reception of the event will cause the current test step to fail
 */	
void CNotifyCollector::AddRequiredOrFailureNotification(TWatcherNotifyType aType, TInt aValue, TBool aEventMeansFailure)
	{
	CNotifyWatcherBase *pWatcher=0;
	TInt index=0;
	TBuf<MAX_DSTRLEN> aDescription;	

	// print a usefull debug message
	switch (aType)
		{
		case EWatcherTimeouts:
			break;
		case EWatcherState:
			COtgRoot::OtgStateString(static_cast<RUsbOtgDriver::TOtgState>(aValue), aDescription);
			LOG_VERBOSE3(_L("AddRequiredNotification() State %d '%S' wanted\n"), aValue, &aDescription);
			break;
		case EWatcherEvent:
			COtgRoot::OtgEventString(static_cast<RUsbOtgDriver::TOtgEvent>(aValue), aDescription);
			LOG_VERBOSE3(_L("AddRequiredNotification() Event %d '%S' wanted\n"), aValue, &aDescription);
			break;
		case EWatcherMessage:
			COtgRoot::OtgMessageString(static_cast<RUsbOtgDriver::TOtgMessage>(aValue), aDescription);
			LOG_VERBOSE3(_L("AddRequiredNotification() Message %d '%S' wanted\n"), aValue, &aDescription);
			break;
		case EWatcherPeripheralState:
			COtgRoot::PeripheralStateString(static_cast<TUint>(aValue), aDescription);
			LOG_VERBOSE3(_L("AddRequiredNotification() Peripheral State %d '%S' wanted\n"), aValue, &aDescription);
			break;
		case EWatcherAConnectionIdle:
			COtgRoot::AConnectionIdleString(static_cast<RUsbOtgDriver::TOtgConnection>(aValue), aDescription);
			LOG_VERBOSE3(_L("AddRequiredNotification() AConnectionIdle %d '%S' wanted\n"), aValue, &aDescription);
			break;

		}
	
	// Find the watcher if possible
	while (index < iNotifyObjects.Count())
		{

		TEST_ASSERTION(iNotifyObjects[index]!=NULL, _L("iNotifyObjects element gone!"));

		if (iNotifyObjects[index]->GetType() == aType)
			{
			pWatcher = iNotifyObjects[index];
			break;
			}
		index++;
		}
	
	TEST_ASSERTION(pWatcher!=NULL, _L("pWatcher=0!"));
	if (aType == EWatcherTimeouts)	
		{ // other watchers are already running, but we start the timer now
		pWatcher->StartWatching(aValue);
		}
	else
		{ // timeouts are not added to the Q
		TOtgObservedEvent evt(aType, aValue);	
		if(aEventMeansFailure)
			{
			iFailureEvents.Append(evt);
			}
		else
			{
			iRequiredEvents.Append(evt);
			}
		}
	// flag as pending
	iStatusStep = KRequestPending;
	iTimeStarted.HomeTime();
	}


/* Return the number of milliseconds since the last call to AddRequiredNotification()
 */
TInt CNotifyCollector::DurationElapsed()
	{
	TTime TimeEnd;
	TInt Millisec;

	TimeEnd.HomeTime();
	TTimeIntervalMicroSeconds ivlMicro(TimeEnd.MicroSecondsFrom(iTimeStarted));
	Millisec = (TInt)(ivlMicro.Int64())/1000;	// USB times are in uSec, but in ms for the user layer

	if (Millisec < 0)
		Millisec = -1; // TRUE for when the Notifiers are not yet being used.
	return(Millisec);				
	}


/* Search for an event in the received Q
 * @return :TRUE if the specified event has been received
 */
TBool CNotifyCollector::EventReceivedAlready(const TOtgObservedEvent& aEvent)
	{
	for (TInt idx=0; idx < iReceivedEvents.Count(); idx++)
		if (iReceivedEvents[idx] == aEvent)
			return(ETrue);
	return(EFalse);
	}

/* Search for an event in the failure event queue
 * @return :TRUE if the specified event does denote a failure
 */
TBool CNotifyCollector::IsFailureEvent(TOtgObservedEvent &aEvent)
	{
	for (TInt idx=0; idx < iFailureEvents.Count(); idx++)
		if (iFailureEvents[idx] == aEvent)
			return(ETrue);
	return(EFalse);
	}

/* @return 0 if the watcher has not yet been created. (for instance early in the test)
 */
CNotifyWatcherBase* CNotifyCollector::GetWatcher(TWatcherNotifyType aType)
	{
	CNotifyWatcherBase *pWatcher=0;
	// Find the watcher 
	TInt index=0;
	
	while (index < iNotifyObjects.Count())
		{

		TEST_ASSERTION(iNotifyObjects[index]!=NULL, _L("iNotifyObjects element gone!"));

		if (iNotifyObjects[index]->GetType() == aType)
			{
			pWatcher = iNotifyObjects[index];
			break;
			}
		index++;
		}

	return(pWatcher);
	}


/* Process the event. The OTG watchers are responsible for renewing themselves
 * but the Timer event does not renew
 */
void CNotifyCollector::HandleEvent(TWatcherNotifyType aType, TInt aValue)
	{
	if (aType == EWatcherTimeouts)
		{
		test.Printf(_L("Step timed out..(%dms).\n\n"), GetWatcher(aType)->GetEventValue());
		CompleteStep(KTestCaseWatchdogTO);
		return;
		}
	
	TOtgObservedEvent evt(aType, aValue);
	TInt start=0;
	iReceivedEvents.Append(evt);  // store incomming evt

	//	Check to see whether the event denotes a failure for this event
	if (IsFailureEvent(evt))
		{
		test.Printf(_L("This event denotes failure for this test\n"));
		CompleteStep(KTestCaseFailureEventReceived);
		return;
		}
	
	if (iRequiredEvents.Count())
		{
		// itterate all required events, search for each one in the incomming events list
		while (start< iRequiredEvents.Count())
			{
				//LOG_VERBOSE3(_L("Search for=[%d,%d] :"), 
				//					iRequiredEvents[start].GetType(), iRequiredEvents[start].GetValue());
				
				if (!EventReceivedAlready(iRequiredEvents[start]))
					return;	// missing still, continue
			start++; 
			}
		// found all the required events
		LOG_VERBOSE1(_L("Found all.\n"));
		CompleteStep(KErrNone);
		}
	else
		{
		test.Printf(_L("Warning : No required events!\n"));
		}	
	}

//	Complete the test step's TRequestStatus (checking it is currently KRequestPending
//	to try and avoid multiple completions).
//
void CNotifyCollector::CompleteStep(TInt aCompletionCode)
	{
	if(iStatusStep.Int() != KRequestPending)
		{
		test.Printf(_L("Can't complete step - not KRequestPending!\n"));
		}
	else
		{
		TRequestStatus *StatusStepPtr = &iStatusStep;
		User::RequestComplete(StatusStepPtr, aCompletionCode);
		}
	}

/****************************************************************************
 * COtg Watchdog Watcher
 */
COtgWatchdogWatcher *COtgWatchdogWatcher::NewL(MOtgNotificationHandler &wdHandler, 
												const TWatcherNotifyType aWatchType, 
												COtgRoot &aOtgRoot)
	{
	LOG_FUNC 
	COtgWatchdogWatcher* self = new (ELeave) COtgWatchdogWatcher(wdHandler, aWatchType, aOtgRoot);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}


void COtgWatchdogWatcher::ConstructL()
	{
	LOG_FUNC
	
	iTimer.CreateLocal();
	iIntervalMs = -1;
	}


void COtgWatchdogWatcher::StepExpired(TInt aInterval) 
	{
	LOG_FUNC ; 
	iHandler.HandleEvent(EWatcherTimeouts, aInterval) ; 
	}


void COtgWatchdogWatcher::RunL()
	{ 
	//LOG_FUNC 
	StepExpired(iIntervalMs); 
	}


void COtgWatchdogWatcher::StartTimer(TInt aIntervalMs)
	{
	LOG_FUNC ;

	iIntervalMs = aIntervalMs;	// save value for printing latter 
	if (IsActive()) //cancel the last timer we set, this is easier than cancelling it in each test-step
		{
		iTimer.Cancel();
		User::WaitForRequest(iStatus); // swallow it
		iTimer.After(iStatus, aIntervalMs*1000);
		}
	else
		{
		iTimer.After(iStatus, aIntervalMs*1000);
		SetActive();
		}
	LOG_VERBOSE2(_L("wd Timer %dms\n"), aIntervalMs)
	}	


/****************************************************************************
 * OTG Event/State/Message Watchers
 */
COtgMessageWatcher* COtgMessageWatcher::NewL(MOtgNotificationHandler &wdHandler, 
										const TWatcherNotifyType aWatchType, 
										COtgRoot &aOtgRoot)
	{
	LOG_FUNC 
	COtgMessageWatcher* self = new (ELeave) COtgMessageWatcher(wdHandler, aWatchType, aOtgRoot);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}


void COtgMessageWatcher::DisplayEvent()
	{
	TBuf<MAX_DSTRLEN> aDescription;	
	iOtgRoot.OtgMessageString(iMessage, aDescription);
	test.Printf(_L("Received Message %d '%S'\n"), iMessage, &aDescription);
	}


COtgStateWatcher* COtgStateWatcher::NewL(MOtgNotificationHandler &wdHandler, 
										const TWatcherNotifyType aWatchType, 
										COtgRoot &aOtgRoot)
	{
	LOG_FUNC 
	COtgStateWatcher* self = new (ELeave) COtgStateWatcher(wdHandler, aWatchType, aOtgRoot);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}


void COtgStateWatcher::DisplayEvent() 
	{
	//LOG_FUNC
	TBuf<MAX_DSTRLEN> aDescription;	
	iOtgRoot.OtgStateString(iState, aDescription);
	test.Printf(_L("Received State %d '%S'\n"), iState, &aDescription);
	}


COtgEventWatcher* COtgEventWatcher::NewL(MOtgNotificationHandler &wdHandler, 
										const TWatcherNotifyType aWatchType, 
										COtgRoot &aOtgRoot)
	{
	//LOG_FUNC 
	COtgEventWatcher* self = new (ELeave) COtgEventWatcher(wdHandler, aWatchType, aOtgRoot);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

void COtgEventWatcher::DisplayEvent()
	{
	TBuf<MAX_DSTRLEN> aDescription;	
	iOtgRoot.OtgEventString(iEvent, aDescription);
	test.Printf(_L("Received Event %d '%S'\n"), iEvent, &aDescription);
	}

CPeripheralStateWatcher* CPeripheralStateWatcher::NewL(MOtgNotificationHandler &wdHandler, 
														const TWatcherNotifyType aWatchType, 
														COtgRoot &aOtgRoot)
	{
	//LOG_FUNC 
	CPeripheralStateWatcher* self = new (ELeave) CPeripheralStateWatcher(wdHandler, aWatchType, aOtgRoot);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

void CPeripheralStateWatcher::DisplayEvent()
	{
	TBuf<MAX_DSTRLEN> aDescription;	
	iOtgRoot.PeripheralStateString(iPeripheralState, aDescription);
	test.Printf(_L("Peripheral State %d '%S'\n"), iPeripheralState, &aDescription);
	}

CAConnectionIdleWatcher* CAConnectionIdleWatcher::NewL(MOtgNotificationHandler &wdHandler, 
														const TWatcherNotifyType aWatchType, 
														COtgRoot &aOtgRoot)
	{
	//LOG_FUNC 
	CAConnectionIdleWatcher* self = new (ELeave) CAConnectionIdleWatcher(wdHandler, aWatchType, aOtgRoot);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

void CAConnectionIdleWatcher::RunL()
	{
	//	We need to override the RunL for this event type, as
	//	the semantics of the asynchronous function are somewhat
	//	different to the rest of the ones being serviced by 
	//	CNotifyWatcherBase.
	//
	//	In the case of QueueOtgConnectionNotification, the value
	//	passed in is updated *immediately* to reflect the current
	//	activity or otherwise of the connection (unlike the other
	//	async functions which update the value on completion).
	//	The completion in the case of QueueOtgConnectionNotification
	//	is used to indicate that the value has changed, and
	//	another request should be queued to pick up this new value.
	//
	//	The practical upshot of this is that the IssueAgain needs
	//	to happen before the event is displayed and handled...
	
	IssueAgain(); 
	DisplayEvent(); 
	iHandler.HandleEvent(iWatchType, GetEventValue()); // report the event upwards
	SetActive();
	}


void CAConnectionIdleWatcher::DisplayEvent()
	{
	TBuf<MAX_DSTRLEN> aDescription;	
	iOtgRoot.AConnectionIdleString(iAConnectionIdle, aDescription);
	test.Printf(_L("AConnectionIdle %d '%S'\n"), iAConnectionIdle, &aDescription);
	}