sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of the License "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // @internalComponent
sl@0: // 
sl@0: //
sl@0: 
sl@0: #include <e32std.h>
sl@0: #include <e32std_private.h>
sl@0: #include <u32std.h> 	// unicode builds
sl@0: #include <e32base.h>
sl@0: #include <e32base_private.h>
sl@0: #include <e32Test.h>	// RTest headder
sl@0: #include "testcaseroot.h"
sl@0: #include "testcasewd.h"
sl@0: #include "testcase0675.h"
sl@0: 
sl@0: #define _REPEATS (oOpenIterations*3)
sl@0: 
sl@0: 
sl@0: 
sl@0: // the name below is used to add a pointer to our construction method to a pointer MAP in 
sl@0: // the class factory
sl@0: _LIT(KTestCaseId,"PBASE-USB_OTGDI-0675");
sl@0: const TTestCaseFactoryReceipt<CTestCase0675> CTestCase0675::iFactoryReceipt(KTestCaseId);	
sl@0: 
sl@0: CTestCase0675* CTestCase0675::NewL(TBool aHost)
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 	CTestCase0675* self = new (ELeave) CTestCase0675(aHost);
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL();
sl@0: 	CleanupStack::Pop(self);
sl@0: 	return self;
sl@0: 	}
sl@0: 	
sl@0: 
sl@0: CTestCase0675::CTestCase0675(TBool aHost)
sl@0: :	CTestCaseRoot(KTestCaseId, aHost)
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 		
sl@0: 	} 
sl@0: 
sl@0: 
sl@0: /**
sl@0:  ConstructL
sl@0: */
sl@0: void CTestCase0675::ConstructL()
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 	iWDTimer = CTestCaseWatchdog::NewL();
sl@0: 	iRepeats = OPEN_REPEATS;
sl@0: 		
sl@0: 	BaseConstructL();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: CTestCase0675::~CTestCase0675()
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 
sl@0: 	Cancel();
sl@0: 	delete iWDTimer;
sl@0: 	
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CTestCase0675::ExecuteTestCaseL()
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 	iCaseStep = EPreconditions;
sl@0: 	
sl@0: 	iRepeats = KOperationRetriesMax;	// VBus event rise retries
sl@0: 	
sl@0: 	CActiveScheduler::Add(this);
sl@0: 	SelfComplete();
sl@0: 
sl@0: 	}
sl@0: 
sl@0: 	
sl@0: void CTestCase0675::DoCancel()
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 
sl@0: 	// cancel our timer
sl@0: 	iTimer.Cancel();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CTestCase0675::CancelKB(CTestCaseRoot *pThis)
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 	CTestCase0675 * p = REINTERPRET_CAST(CTestCase0675 *,pThis);
sl@0: 	// cancel any pending call, and then complete our active obj with a cancel value
sl@0: 	p->iConsole->ReadCancel();
sl@0: 
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CTestCase0675::CancelNotify(CTestCaseRoot *pThis)
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 	CTestCase0675 * p = REINTERPRET_CAST(CTestCase0675 *,pThis);
sl@0: 	// cancel any pending call, and then complete our active obj with a timeout value
sl@0: 	p->otgCancelOtgVbusNotification();
sl@0: 	p->SelfComplete(KTestCaseWatchdogTO);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // This test result depends on all the ID detection tests and the VBus driving and dropping tests have not yet passed
sl@0: void CTestCase0675::DescribePreconditions()
sl@0: 	{
sl@0: 	test.Printf(_L("Insert 'A' connector beforehand.\n"));
sl@0: 	
sl@0: 	}
sl@0: 
sl@0: void CTestCase0675::ContinueAfter(TTimeIntervalMicroSeconds32 aMicroSecs, TCaseSteps aStep)
sl@0: 	{
sl@0: 	LOG_VERBOSE2(_L("Wait %dms before drop VBus"), (TInt)(aMicroSecs.Int()/1000));
sl@0: 	iTimer.After(iStatus, aMicroSecs);
sl@0: 	iCaseStep = aStep;
sl@0: 	SetActive();
sl@0: 	}
sl@0: 
sl@0: // handle event completion	
sl@0: void CTestCase0675::RunStepL()
sl@0: 	{
sl@0: 	LOG_FUNC
sl@0: 	// Obtain the completion code for this CActive obj.
sl@0: 	TInt completionCode(iStatus.Int()); 
sl@0: 	TBuf<MAX_DSTRLEN> aDescription;
sl@0: 	TInt err(0);
sl@0: 
sl@0: 
sl@0: 	switch(iCaseStep)
sl@0: 		{
sl@0: 		case EPreconditions:
sl@0: 			iCaseStep = ELoadLdd;
sl@0: 			if (iAutomated)
sl@0: 				{
sl@0: 				iCaseStep = ELoadLdd;
sl@0: 				SelfComplete();
sl@0: 				break;
sl@0: 				}
sl@0: 			// prompt to insert connector
sl@0: 			test.Printf(KInsertAConnectorPrompt);
sl@0: 			test.Printf(KPressAnyKeyToContinue);
sl@0: 			RequestCharacter();			
sl@0: 			break;
sl@0: 			
sl@0: 			// 1. load the LDD and init.
sl@0: 		case ELoadLdd:
sl@0: 			if (!StepLoadLDD())
sl@0: 				{
sl@0: 				break;
sl@0: 				}
sl@0: 			if (iAutomated)
sl@0: 				iCaseStep = ELoopDriveVBus1;
sl@0: 			else
sl@0: 				iCaseStep = EDetectAPlug;
sl@0: 			SelfComplete();
sl@0: 			break;
sl@0: 			
sl@0: 			// 2. detect 'A' plug now
sl@0: 		case EDetectAPlug:
sl@0: 			if (KTestCaseWatchdogTO == iStatus.Int())
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("User response too slow - FAILED!"));
sl@0: 				}
sl@0: 			if (!otgIdPinPresent())
sl@0: 				{
sl@0: 				test.Printf(KInsertAConnectorPrompt);
sl@0: 				test.Printf(KPressAnyKeyToContinue);
sl@0: 				RequestCharacter();
sl@0: 				iCaseStep = EDetectAPlug;
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				iCaseStep = ELoopDriveVBus1;
sl@0: 				SelfComplete();
sl@0: 				}
sl@0: 			break;
sl@0: 			
sl@0: 			// 3. Control/branch step in the loop
sl@0: 		case ELoopControl:
sl@0: 			if (--iRepeats)
sl@0: 				{
sl@0: 				iCaseStep = ELoopDriveVBus1;
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				iCaseStep = EUnloadLdd;
sl@0: 				}
sl@0: 			SelfComplete();
sl@0: 			break;
sl@0: 			
sl@0: 			// 4. DRIVE VBUS
sl@0: 		case ELoopDriveVBus1:
sl@0: 			iWDTimer->Cancel();
sl@0: 			test.Printf(_L("Drive VBus, iteration %d/%d\n"), OPEN_REPEATS-iRepeats+1, OPEN_REPEATS);
sl@0: 			// test for VBus rise next
sl@0: 			test.Printf(_L("Waiting for VBus Event\n"));
sl@0: 			iStatus = KRequestPending;
sl@0: 			otgQueueOtgVbusNotification( iOTGVBus, iStatus );
sl@0: 			SetActive();
sl@0: 			
sl@0: 			// turn on VBus, since the call is not a Queing a-sync call we do this after the async call
sl@0: 			err = otgBusRequest();	// ok to turn on VBus now
sl@0: 			if (KErrNone != err)
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Raise Vbus - RUsbOtgDriver::BusRequest() FAILED!"));
sl@0: 				}
sl@0: 			iCaseStep = ELoopVerifyVBus1;
sl@0: 			iWDTimer->IssueRequest(KDelayDurationForLocalTrigger, this, &CancelNotify);
sl@0: 	
sl@0: 			break;
sl@0: 			
sl@0: 			// 5. get VBus rise event
sl@0: 		case ELoopVerifyVBus1:
sl@0: 			if (KTestCaseWatchdogTO == iStatus.Int())
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Vbus rise not signalled in time - FAILED!"));
sl@0: 				}
sl@0: 			iWDTimer->Cancel();
sl@0: 
sl@0: 			// check using the API in a syncronous way too
sl@0: 			if (!otgVbusPresent())
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Vbus syncronous call error - FAILED!"));
sl@0: 				}
sl@0: 			iCaseStep = ELoopWait;
sl@0: 			SelfComplete();
sl@0: 			break;
sl@0: 
sl@0: 			// 6. DRIVE/claim VBUS 2nd time
sl@0: 		case ELoopDriveVBus2:
sl@0: 			iWDTimer->Cancel();
sl@0: 			test.Printf(_L("Drive VBus double, iteration %d/%d\n"), OPEN_REPEATS-iRepeats+1, OPEN_REPEATS);
sl@0: 
sl@0: 			err = otgBusRequest();	// duplicate turn on VBus, we expect an error 
sl@0: 			if (KErrUsbOtgVbusAlreadyRaised != err)
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Raise Vbus - RUsbOtgDriver::BusRequest() unexpected result!"));
sl@0: 				}
sl@0: 			iCaseStep = ELoopVerifyVBus2;
sl@0: 			SelfComplete();
sl@0: 			SetActive();
sl@0: 			break;
sl@0: 			
sl@0: 			// 7 - make sure that the error did not end up killing the bus
sl@0: 		case ELoopVerifyVBus2:
sl@0: 			if (!otgVbusPresent())
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Raise Vbus twice resulted in session drop"));
sl@0: 				}
sl@0: 			iCaseStep = ELoopWait;
sl@0: 			SelfComplete();
sl@0: 			SetActive();
sl@0: 			break;
sl@0: 			
sl@0: 			// 9. wait 50ms after applying Vbus before we are allowed to drop again
sl@0: 		case ELoopWait:	
sl@0: 			ContinueAfter(KDelayBeforeBusDropUs, ELoopDropVBus);
sl@0: 			break;
sl@0: 			
sl@0: 		case ELoopDropVBus:
sl@0: 			// 10. drop Bus
sl@0: 			otgQueueOtgVbusNotification(iOTGVBus, iStatus );
sl@0: 			// drop Vbus now, since the call is not a Queing a-sync call we do this after the async call
sl@0: 			otgBusDrop();
sl@0: 			SetActive();
sl@0: 			iCaseStep = ELoopVerifyDrop;
sl@0: 			iWDTimer->IssueRequest(KDelayDurationForLocalTrigger, this, &CancelNotify);
sl@0: 			break;
sl@0: 			
sl@0: 		case ELoopVerifyDrop:
sl@0: 			// 11. get Vbus low event
sl@0: 			if (KTestCaseWatchdogTO == iStatus.Int())
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Vbus drop not signalled in time - FAILED!"));
sl@0: 				}
sl@0: 			iWDTimer->Cancel();
sl@0: 
sl@0: 			// fetch the value			
sl@0: 			otgQueueOtgVbusNotification( iOTGVBus, iStatus );
sl@0: 			otgCancelOtgVbusNotification();
sl@0: 			User::WaitForRequest(iStatus);
sl@0: 
sl@0: 			if (iOTGVBus != RUsbOtgDriver::EVbusLow)
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Vbus drop NOT 'seen' - FAILED!"));
sl@0: 				}
sl@0: 				
sl@0: 			// test again using the 'syncronous' variation
sl@0: 			if (otgVbusPresent())
sl@0: 				{
sl@0: 				return TestFailed(KErrAbort, _L("Vbus syncronous call error - FAILED!"));
sl@0: 				}
sl@0: 				
sl@0: 			// wait 50ms and then go back to beginning
sl@0: 			ContinueAfter(KDelayBeforeBusDropUs, ELoopControl);
sl@0: 			break;
sl@0: 			
sl@0: 		case EUnloadLdd:
sl@0: 			// 12. unload
sl@0: 			if (EFalse == StepUnloadLDD())
sl@0: 				return TestFailed(KErrAbort,_L("unload Ldd failure"));	
sl@0: 			
sl@0: 			iCaseStep = ELastStep;
sl@0: 			SelfComplete();
sl@0: 			break;
sl@0: 			
sl@0: 		case ELastStep:
sl@0: 			TestPassed();
sl@0: 			break;
sl@0: 			
sl@0: 		default:
sl@0: 			test.Printf(_L("<Error> unknown test step"));
sl@0: 			Cancel();
sl@0: 			return (TestFailed(KErrCorrupt, _L("<Error> unknown test step")));
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: