kerneltest/e32test/usbho/t_otgdi/src/b2bwatchers.cpp
changeset 0 a41df078684a
child 43 c1f20ce4abcf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/usbho/t_otgdi/src/b2bwatchers.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,553 @@
+// 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);
+	}