--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgrtest/usbcontrolapp/exampleusbcontrolapp/exampleusbcontrolapp.cpp Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,1555 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+*
+*/
+
+#include "exampleusbcontrolapp.h"
+
+#include <e32cons.h>
+#include <e32debug.h>
+// For Message Watcher
+#include <d32otgdi_errors.h>
+#include <d32usbdi_errors.h>
+#include <usb/usbshared.h>
+
+
+#define LOG(A,B) RDebug::Print(_L("UsbControlApp: " L##A),B)
+#define PNT(A) RDebug::Print(_L("UsbControlApp: " L##A))
+#define BLN(A) RDebug::Print(_L("" L##A))
+#define PANIC Panic(__LINE__)
+
+
+#ifdef __USB_DEBUG__
+#define DBG_PANIC Panic(__LINE__)
+#else
+#define DBG_PANIC
+#endif
+
+
+void Panic(TInt aLine)
+ {
+ RDebug::Printf("UsbControlApp: PANIC line=%d", aLine);
+ User::Panic(_L("USBCONTROLAPP"), aLine);
+ }
+
+void RunAppL()
+ {
+ CUsbControlAppEngine* engine = CUsbControlAppEngine::NewLC();
+ engine->Start();
+ CleanupStack::PopAndDestroy(engine);
+ }
+
+TInt E32Main()
+ {
+ __UHEAP_MARK;
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ CActiveScheduler* activeScheduler = new CActiveScheduler;
+ TInt err = KErrNoMemory;
+ if(cleanup && activeScheduler)
+ {
+ CActiveScheduler::Install(activeScheduler);
+ PNT("*** UsbControlApp E32Main ***\n");
+ TRAP(err, RunAppL());
+ }
+ delete activeScheduler;
+ delete cleanup;
+ __UHEAP_MARKEND;
+ return err;
+ }
+
+
+CShutdownMonitor* CShutdownMonitor::NewL(MShutdownInterface& aControlAppEngine)
+ {
+ CShutdownMonitor* self = new(ELeave) CShutdownMonitor(aControlAppEngine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CShutdownMonitor::CShutdownMonitor(MShutdownInterface& aControlAppEngine)
+ : CActive(EPriorityLow) // Low so all notifications that want to be serviced will be done first
+ , iParentControlAppEngine(aControlAppEngine)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CShutdownMonitor::ConstructL()
+ {
+ // Monitor the KUsbControlAppShutdownKey property to tell us when to shut down
+ TInt err = iShutdownProp.Attach(KUidUsbControlAppCategory, KUsbControlAppShutdownKey);
+ LOG("CShutdownMonitor::ConstructL iShutdownProp.Attach() => %d", err);
+ User::LeaveIfError(err);
+ iShutdownProp.Subscribe(iStatus);
+ SetActive();
+ TInt val;
+ // Make sure the cuurent value is 0 - shut down when this changes to 1
+ err = iShutdownProp.Get(val);
+ LOG("CShutdownMonitor::ConstructL() iShutdownProp.Get(val) val => %d", val);
+ LOG("CShutdownMonitor::ConstructL() iShutdownProp.Get(val) err => %d", err);
+ User::LeaveIfError(err);
+ __ASSERT_ALWAYS(val==0, PANIC);
+ }
+
+CShutdownMonitor::~CShutdownMonitor()
+ {
+ iShutdownProp.Close();
+ }
+
+void CShutdownMonitor::RunL()
+ {
+ // Request to shut everything down made in USB Aware App
+ TInt val;
+ TInt err = iShutdownProp.Get(val);
+ LOG("CShutdownMonitor::RunL iShutdownProp.Get(val) err => %d", err);
+ LOG("CShutdownMonitor::RunL iShutdownProp.Get(val) val => %d", val);
+ Cancel(); // Not interested in any more notifications
+ iParentControlAppEngine.Stop(); // Stopping Active Scheduler will results in the destructor getting called
+ }
+
+void CShutdownMonitor::DoCancel()
+ {
+ iShutdownProp.Cancel();
+ }
+
+
+CUsbControlAppEngine* CUsbControlAppEngine::NewLC()
+ {
+ CUsbControlAppEngine* self = new(ELeave) CUsbControlAppEngine();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ PNT("\nConstructed Control App\n");
+ return self;
+ }
+
+CUsbControlAppEngine::~CUsbControlAppEngine()
+ {
+ PNT("\nClosing Control App\n");
+ iViewerMsgQ.Close();
+ delete iShutdownMonitor;
+ delete iStateMachine;
+ delete iMessageWatcher;
+ delete iConnIdleWatcher;
+ delete iVBusWatcher;
+ delete iIdPinWatcher;
+ iUsb.Close();
+ }
+
+CUsbControlAppEngine::CUsbControlAppEngine()
+ {
+ }
+
+void CUsbControlAppEngine::ConstructL()
+ {
+ // Start session to USBMAN
+ TInt err = iUsb.Connect();
+ LOG("CUsbControlAppEngine::ConstructL() iUsb.Connect() err=%d", err);
+ User::LeaveIfError(err);
+ // Set this as the single controller of USBMAN
+ err = iUsb.SetCtlSessionMode(ETrue);
+ LOG("CUsbControlAppEngine::ConstructL() iUsb.SetCtlSessionMode(ETrue) err=%d", err);
+ User::LeaveIfError(err);
+ iStateMachine = CControlAppStateMachine::NewL(*this);
+ // Create Watcher Active Objects to monitor events
+ iIdPinWatcher = CIdPinWatcher::NewL(*this);
+ iVBusWatcher = CVBusWatcher::NewL(*this);
+ iConnIdleWatcher= CConnectionIdleWatcher::NewL(*this);
+ iMessageWatcher = CMessageWatcher::NewL(*this);
+
+ iShutdownMonitor = CShutdownMonitor::NewL(*this);
+ // Create message queue between exampleusbcontrolapp.exe & usbviewer.exe for showing user messages
+ err = iViewerMsgQ.CreateGlobal(KControlAppViewerMsgQName, KControlAppViewerMsgQSlots);
+ LOG("CUsbControlAppEngine::ConstructL() iViewerMsgQ.CreateGlobal err => %d", err);
+ User::LeaveIfError(err);
+ // Stop USB services if they are started so system can start from a known state
+ err = StopUsbServices();
+ LOG("CUsbControlAppEngine::ConstructL() StopUsbServices() err=%d", err);
+ User::LeaveIfError(err);
+ // Last thing - allow State Machine to find a main state by sending it a StartUp event
+ iStateMachine->StartUp();
+ }
+
+void CUsbControlAppEngine::Start()
+ {
+ CActiveScheduler::Start(); // Get everything running
+ }
+
+void CUsbControlAppEngine::Stop() const
+ {
+ CActiveScheduler::Stop();
+ }
+
+// Called by State Machine
+TInt CUsbControlAppEngine::StopUsbServices()
+ {
+ TRequestStatus status;
+ iUsb.TryStop(status);
+ User::WaitForRequest(status);
+ LOG("CUsbControlAppEngine::StopUsbServices() status.Int()=%d", status.Int());
+ return status.Int();
+ }
+
+TInt CUsbControlAppEngine::StartUsbServices()
+ {
+ const TInt KACMPersonality = 1;
+ TRequestStatus status;
+ iUsb.TryStart(KACMPersonality, status);
+ User::WaitForRequest(status);
+ LOG("CUsbControlAppEngine::StartUsbServices() status.Int()=%d", status.Int());
+ return status.Int();
+ }
+
+TInt CUsbControlAppEngine::EnableFunctionDriverLoading()
+ {
+ TInt err = iUsb.EnableFunctionDriverLoading();
+ LOG("CUsbControlAppEngine::EnableFunctionDriverLoading() err=%d", err);
+ return err;
+ }
+
+void CUsbControlAppEngine::DisableFunctionDriverLoading()
+ {
+ PNT("CUsbControlAppEngine::DisableFunctionDriverLoading()\n");
+ iUsb.DisableFunctionDriverLoading();
+ }
+
+TInt CUsbControlAppEngine::BusRequest()
+ {
+ TInt err = iUsb.BusRequest();
+ LOG("CUsbControlAppEngine::BusRequest() err=%d", err);
+ return err;
+ }
+
+TInt CUsbControlAppEngine::BusDrop()
+ {
+ TInt err = iUsb.BusDrop();
+ LOG("CUsbControlAppEngine::BusDrop() err=%d", err);
+ return err;
+ }
+
+TInt CUsbControlAppEngine::BusRespondSrp()
+ {
+ TInt err = iUsb.BusRespondSrp();
+ LOG("CUsbControlAppEngine::BusRespondSrp() err=%d", err);
+ return err;
+ }
+
+TInt CUsbControlAppEngine::ClearVBusError()
+ {
+ TInt err = iUsb.BusClearError();
+ LOG("CUsbControlAppEngine::ClearVBusError() err=%d", err);
+ return err;
+ }
+
+// Must divide the user message to be displayed into segments that will fit on the usbviewer.exe window.
+// Because the viewer.exe displays Events in a downward scrolling list with the latest entry at the top,
+// the user message segments must be sent in reverse order.
+void CUsbControlAppEngine::DisplayUserMessage(const TDesC& aUserMsg)
+ {
+ LOG("CUsbControlAppEngine::DisplayUserMessage(\"%S\")\n", &aUserMsg);
+ TInt msgLength = aUserMsg.Length();
+ TInt lastBitLength = msgLength % KEventLineMsgNumCharacters;
+ LOG("CUsbControlAppEngine::DisplayUserMessage lastBitLength => %d", lastBitLength);
+ if (lastBitLength) // show the 'last bit' segment of the message which is not divisible by KEventLineMsgNumCharacters
+ {
+ TBuf<KEventLineNumCharacters> buf(KPrefix);
+ TPtrC text = aUserMsg.Right(lastBitLength);
+ buf.Append(text);
+ LOG("CUsbControlAppEngine::DisplayUserMessage iViewerMsgQ.Send(buf) buf => %S", &buf);
+ TInt err = iViewerMsgQ.Send(buf);
+ LOG("CUsbControlAppEngine::DisplayUserMessage iViewerMsgQ.Send(buf) err => %d", err);
+ }
+ msgLength -= lastBitLength;
+ while (msgLength > 0) // show the segments of the message which are exactly divisible by KEventLineMsgNumCharacters
+ {
+ // TBuf of length KEventLineNumCharacters = KPrefix of length 2 + Mid bit of length KEventLineMsgNumCharacters
+ TBuf<KEventLineNumCharacters> buf(KPrefix);
+ TPtrC text = aUserMsg.Mid(msgLength-KEventLineMsgNumCharacters, KEventLineMsgNumCharacters);
+ buf.Append(text);
+ LOG("CUsbControlAppEngine::DisplayUserMessage iViewerMsgQ.Send(buf) buf => %S", &buf);
+ TInt err = iViewerMsgQ.Send(buf);
+ LOG("CUsbControlAppEngine::DisplayUserMessage iViewerMsgQ.Send(buf) err => %d", err);
+ msgLength -= KEventLineMsgNumCharacters;
+ }
+ }
+
+// Called by Watchers. Will forward as event to State Machine.
+void CUsbControlAppEngine::SetIdPin(TInt aIdPin)
+ {
+ PNT("CUsbControlAppEngine::SetIdPin()\n");
+ iIdPin = aIdPin;
+ __ASSERT_ALWAYS(iStateMachine, PANIC);
+ aIdPin ? iStateMachine->IdPinPresent() : iStateMachine->IdPinAbsent();
+ }
+
+void CUsbControlAppEngine::SetVBus(TInt aVBus)
+ {
+ PNT("CUsbControlAppEngine::SetVBus()\n");
+ iVBus = aVBus;
+ __ASSERT_ALWAYS(iStateMachine, PANIC);
+ aVBus ? iStateMachine->VBusRise() : iStateMachine->VBusDrop();
+ }
+
+void CUsbControlAppEngine::SetConnectionIdle(TInt aConnIdle)
+ {
+ PNT("CUsbControlAppEngine::SetConnectionIdle()\n");
+ iConnIdle = aConnIdle;
+ __ASSERT_ALWAYS(iStateMachine, PANIC);
+ aConnIdle ? iStateMachine->ConnectionIdle() : iStateMachine->ConnectionActive();
+ }
+
+void CUsbControlAppEngine::MessageReceived(CMessageWatcher::TMessageWatcherNotifications aMessageNotification)
+ {
+ switch(aMessageNotification)
+ {
+ case CMessageWatcher::EUsbMessageRequestSession :
+ PNT("CUsbControlAppEngine::MessageReceived() EUsbMessageRequestSession\n");
+ iStateMachine->RequestSessionCalled();
+ break;
+ case CMessageWatcher::EUsbMessageSrpReceived :
+ PNT("CUsbControlAppEngine::MessageReceived() EUsbMessageSrpReceived\n");
+ iStateMachine->SrpDetected();
+ break;
+ case CMessageWatcher::EErrUsbOtgSrpTimeout :
+ PNT("CUsbControlAppEngine::MessageReceived() EErrUsbOtgSrpTimeout\n");
+ iStateMachine->SrpTimeout();
+ break;
+ case CMessageWatcher::EErrUsbOtgVbusError :
+ PNT("CUsbControlAppEngine::MessageReceived() EErrUsbOtgVbusError\n");
+ iStateMachine->VBusError();
+ break;
+ default:
+ PANIC;
+ }
+ }
+
+RUsb& CUsbControlAppEngine::Usb()
+ {
+ return iUsb;
+ }
+
+TInt CUsbControlAppEngine::GetIdPin()
+ {
+ return iIdPin;
+ }
+
+TInt CUsbControlAppEngine::GetVBus()
+ {
+ return iVBus;
+ }
+
+
+CControlAppStateMachine* CControlAppStateMachine::NewL(MControlAppEngineInterface& aControlAppEngine)
+ {
+ CControlAppStateMachine* self = new(ELeave) CControlAppStateMachine(aControlAppEngine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ PNT("CControlAppStateMachine::NewL\n");
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CControlAppStateMachine::~CControlAppStateMachine()
+ {
+ delete iStateAServicesStopped;
+ delete iStateAServicesStarted;
+ delete iStateBServicesStarted;
+ delete iStateBServicesStopped;
+ delete iStateInitial;
+ delete iInactivityTimer;
+ }
+
+CControlAppStateMachine::CControlAppStateMachine(MControlAppEngineInterface& aControlAppEngine)
+ : iParentControlAppEngine(aControlAppEngine)
+ , iTriggerSrp(EFalse)
+ {
+ }
+
+void CControlAppStateMachine::ConstructL()
+ {
+ iInactivityTimer = CInactivityTimer::NewL(*this);
+ iStateInitial = new(ELeave) CControlAppStateInitial(*this);
+ iStateBServicesStopped = new(ELeave) CControlAppStateBServicesStopped(*this);
+ iStateBServicesStarted = new(ELeave) CControlAppStateBServicesStarted(*this);
+ iStateAServicesStarted = new(ELeave) CControlAppStateAServicesStarted(*this);
+ iStateAServicesStopped = new(ELeave) CControlAppStateAServicesStopped(*this);
+ SetState(EStateInitial);
+ }
+
+void CControlAppStateMachine::SetState(TControlAppState aState)
+ {
+ TPtrC StateString(NULL, 0);
+ // 123456789
+ _LIT(KInitial, " Initial ");
+ _LIT(KBStopped, "B-Stopped");
+ _LIT(KBStarted, "B-Started");
+ _LIT(KAStopped, "A-Stopped");
+ _LIT(KAStarted, "A-Started");
+ switch(aState)
+ {
+ case EStateInitial :
+ StateString.Set(KInitial);
+ iCurrentState = iStateInitial;
+ break;
+ case EStateBServicesStopped :
+ StateString.Set(KBStopped);
+ iCurrentState = iStateBServicesStopped;
+ break;
+ case EStateBServicesStarted :
+ StateString.Set(KBStarted);
+ iCurrentState = iStateBServicesStarted;
+ break;
+ case EStateAServicesStopped :
+ StateString.Set(KAStopped);
+ iCurrentState = iStateAServicesStopped;
+ break;
+ case EStateAServicesStarted :
+ StateString.Set(KAStarted);
+ iCurrentState = iStateAServicesStarted;
+ break;
+ default : PANIC;
+ }
+ // (123456789) ***
+ BLN("");
+ PNT("******************************************************");
+ LOG("*** CControlAppStateMachine::SetState(%S) ***", &StateString);
+ PNT("******************************************************");
+ BLN("");
+ }
+
+// State Machine's publicly visible interface...
+// Initial
+void CControlAppStateMachine::StartUp()
+ {
+ PNT("CControlAppStateMachine::StartUp() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->StartUp();
+ }
+
+// B-Stopped, B-Started
+void CControlAppStateMachine::IdPinPresent()
+ {
+ PNT("CControlAppStateMachine::IdPinPresent() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->IdPinPresent();
+ }
+
+// B-Stopped, A-Started
+void CControlAppStateMachine::VBusRise()
+ {
+ PNT("CControlAppStateMachine::VBusRise() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->VBusRise();
+ }
+
+// B-Started, A-Started
+void CControlAppStateMachine::VBusDrop()
+ {
+ PNT("CControlAppStateMachine::VBusDrop() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->VBusDrop();
+ }
+
+// A-Started, A-Stopped
+void CControlAppStateMachine::IdPinAbsent()
+ {
+ PNT("CControlAppStateMachine::IdPinAbsent() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->IdPinAbsent();
+ }
+
+// A-Started
+void CControlAppStateMachine::ConnectionIdle()
+ {
+ PNT("CControlAppStateMachine::ConnectionIdle() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->ConnectionIdle();
+ }
+
+// A-Started
+void CControlAppStateMachine::ConnectionActive()
+ {
+ PNT("CControlAppStateMachine::ConnectionActive() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->ConnectionActive();
+ }
+
+// B-Stopped, A-Stopped, B-Started, A-Started
+void CControlAppStateMachine::RequestSessionCalled()
+ {
+ PNT("CControlAppStateMachine::RequestSessionCalled() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->RequestSessionCalled();
+ }
+
+// B-Started
+void CControlAppStateMachine::SrpTimeout()
+ {
+ PNT("CControlAppStateMachine::SrpTimeout() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->SrpTimeout();
+ }
+
+// A-Stopped
+void CControlAppStateMachine::SrpDetected()
+ {
+ PNT("CControlAppStateMachine::SrpDetected() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->SrpDetected();
+ }
+
+// A-Started, A-Stopped
+void CControlAppStateMachine::VBusError()
+ {
+ PNT("CControlAppStateMachine::VBusError() - event will be forwarded to current state\n");
+ __ASSERT_ALWAYS(iCurrentState, PANIC);
+ // Could implement global USB enabled/disabled policy here by allowing/preventing event reaching current state
+ iCurrentState->VBusError();
+ }
+
+void CControlAppStateMachine::ResetInactivityTimer()
+ {
+ PNT("CControlAppStateMachine::ResetInactivityTimer()\n");
+ iInactivityTimer->Reset();
+ }
+
+void CControlAppStateMachine::CancelInactivityTimer()
+ {
+ PNT("CControlAppStateMachine::CancelInactivityTimer()\n");
+ iInactivityTimer->Cancel();
+ }
+
+void CControlAppStateMachine::InactivityTimerExpired()
+ {
+ PNT("CControlAppStateMachine::InactivityTimerExpired()\n");
+ iCurrentState->InactivityTimerExpired();
+ }
+
+
+CControlAppStateMachine::CInactivityTimer* CControlAppStateMachine::CInactivityTimer::NewL(CControlAppStateMachine& aParentStateMachine)
+ {
+ PNT("CControlAppStateMachine::CInactivityTimer::NewL()\n");
+ CControlAppStateMachine::CInactivityTimer* self = new(ELeave) CControlAppStateMachine::CInactivityTimer(aParentStateMachine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CControlAppStateMachine::CInactivityTimer::~CInactivityTimer()
+ {
+ PNT("CControlAppStateMachine::CInactivityTimer::~CInactivityTimer()\n");
+ Cancel();
+ iTimer.Close();
+ }
+
+CControlAppStateMachine::CInactivityTimer::CInactivityTimer(CControlAppStateMachine& aParentStateMachine)
+ : CActive(EPriorityStandard)
+ , iParentStateMachine(aParentStateMachine)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CControlAppStateMachine::CInactivityTimer::ConstructL()
+ {
+ PNT("CControlAppStateMachine::CInactivityTimer::ConstructL\n");
+ TInt err = iTimer.CreateLocal();
+ LOG("CInactivityTimer::ConstructL iTimer.CreateLocal() => %d",err);
+ User::LeaveIfError(err);
+ }
+
+void CControlAppStateMachine::CInactivityTimer::Reset()
+ {
+ PNT("CControlAppStateMachine::CInactivityTimer::Reset()\n");
+ if (IsActive())
+ {
+ PNT("CControlAppStateMachine::CInactivityTimer::Reset() - IsActive() so Cancel() before setting RTimer\n");
+ Cancel(); // Reset
+ }
+ iTimer.After(iStatus, KInactivityTimerPeriod); // 10 sec
+ SetActive();
+ }
+
+void CControlAppStateMachine::CInactivityTimer::RunL()
+ {
+ PNT("CControlAppStateMachine::CInactivityTimer::RunL() - calling iParentState.InactivityTimerExpired()\n");
+ iParentStateMachine.InactivityTimerExpired();
+ }
+
+void CControlAppStateMachine::CInactivityTimer::DoCancel()
+ {
+ PNT("CControlAppStateMachine::CInactivityTimer::DoCancel()\n");
+ iTimer.Cancel();
+ }
+
+
+// Base state...
+CControlAppStateMachine::CControlAppStateBase::CControlAppStateBase(CControlAppStateMachine& aParentStateMachine)
+ : iParentStateMachine(aParentStateMachine)
+ {
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::StartUp()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::StartUp() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::IdPinPresent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::IdPinPresent() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::VBusRise()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::VBusRise() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::VBusDrop()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::VBusDrop() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::IdPinAbsent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::IdPinAbsent() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::ConnectionIdle()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::ConnectionIdle() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::ConnectionActive()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::ConnectionActive() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::InactivityTimerExpired()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::InactivityTimerExpired() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::RequestSessionCalled()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::RequestSessionCalled() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::SrpTriggered()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::SrpTriggered() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::SrpTimeout()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::SrpTimeout() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::SrpDetected()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::SrpDetected() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+void CControlAppStateMachine::CControlAppStateBase::VBusError()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBase::VBusError() - ERROR: unexpected event in current state\n");
+ DBG_PANIC;
+ }
+
+
+// Initial state...
+CControlAppStateMachine::CControlAppStateInitial::CControlAppStateInitial(CControlAppStateMachine& aParentStateMachine)
+ : CControlAppStateBase(aParentStateMachine)
+ {
+ }
+
+void CControlAppStateMachine::CControlAppStateInitial::VBusRise()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::VBusRise() - no action: wait for StartUp event\n");
+ }
+
+void CControlAppStateMachine::CControlAppStateInitial::VBusDrop()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::VBusDrop() - no action: wait for StartUp event\n");
+ }
+
+void CControlAppStateMachine::CControlAppStateInitial::IdPinPresent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::IdPinPresent() - no action: wait for StartUp event\n");
+ }
+
+void CControlAppStateMachine::CControlAppStateInitial::IdPinAbsent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::IdPinAbsent() - no action: wait for StartUp event\n");
+ }
+
+void CControlAppStateMachine::CControlAppStateInitial::ConnectionIdle()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::ConnectionIdle() - no action: wait for StartUp event\n");
+ }
+
+void CControlAppStateMachine::CControlAppStateInitial::ConnectionActive()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::ConnectionActive() - no action: wait for StartUp event\n");
+ }
+
+void CControlAppStateMachine::CControlAppStateInitial::StartUp()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp()\n");
+ // Determine state to move to from the Initial
+ if (iParentStateMachine.iParentControlAppEngine.GetIdPin())
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Id Pin detected\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StartUsbServices();
+ if (!err) // Started USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Started USB services\n");
+ iParentStateMachine.SetState(EStateAServicesStarted);
+ err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err) // Started USB services & enabled FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Enabled FD loading\n");
+ }
+ else // Started USB services & couldn't enable FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ }
+ // Regardless of whether enabling FD loading succeeded or not do BusRequest() to power VBus
+ err = iParentStateMachine.iParentControlAppEngine.BusRequest();
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() BusRequest() successful\n");
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() BusRequest() failed\n");
+ // This error only indicates whether USBMAN server got the request without any problem.
+ // VBus could still fail to go up but this is only likely if there is a Bus Error - this is
+ // handled in a separate event though.
+ _LIT(KMsgCouldntPowerUsbDevice, "Error: Couldn't power USB device - press 'R' to try again");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntPowerUsbDevice);
+ // CControlAppStateAServicesStarted::VBusRise() ensures Inactivity Timer is activated when the BusRequest()
+ // is successful, but when it fails we must ensure USB services will be eventually stopped:
+ iParentStateMachine.ResetInactivityTimer();
+ }
+ }
+ else // Couldn't start USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Couldn't start USB services\n");
+ _LIT(KMsgCouldntStartUsb, "Error: Couldn't start USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStartUsb);
+ iParentStateMachine.SetState(EStateAServicesStopped); // Since Id Pin is present
+ }
+ } // if (iParentStateMachine.iParentControlAppEngine.GetIdPin())
+ else // i.e. no Id Pin
+ {
+ if (iParentStateMachine.iParentControlAppEngine.GetVBus())
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Id Pin Absent & VBus detected\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StartUsbServices();
+ if (!err) // Started USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Started USB services\n");
+ iParentStateMachine.SetState(EStateBServicesStarted);
+ err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err) // Started USB services & enabled FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Enabled FD loading\n");
+ }
+ else // Started USB services & couldn't enable FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ }
+ }
+ else // Couldn't start USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Couldn't start USB services\n");
+ iParentStateMachine.SetState(EStateBServicesStopped); // even though VBus
+ _LIT(KMsgCouldntStartUsb, "Error: Couldn't start USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStartUsb);
+ }
+ } // if (iParentStateMachine.iParentControlAppEngine.GetVBus())
+ else // if (iParentStateMachine.iParentControlAppEngine.GetVBus())
+ {
+ PNT("CControlAppStateMachine::CControlAppStateInitial::StartUp() Id Pin Absent & VBus not detected\n");
+ iParentStateMachine.SetState(EStateBServicesStopped);
+ }
+ } // else i.e. no Id Pin
+ }
+
+
+// BServicesStopped state...
+CControlAppStateMachine::CControlAppStateBServicesStopped::CControlAppStateBServicesStopped(CControlAppStateMachine& aParentStateMachine)
+ : CControlAppStateBase(aParentStateMachine)
+ {
+ }
+
+// Power detected on VBus
+// Try to move to B-Started
+void CControlAppStateMachine::CControlAppStateBServicesStopped::VBusRise()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::VBusRise() VBus detected\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StartUsbServices();
+ if (!err) // Started USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::VBusRise() Started USB services\n");
+ iParentStateMachine.SetState(EStateBServicesStarted);
+ err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err) // Started USB services & enabled FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::VBusRise() Enabled FD loading\n");
+ }
+ else // Started USB services & couldn't enable FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::VBusRise() couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ }
+ }
+ else // Couldn't start USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::VBusRise() Couldn't start USB services\n");
+ _LIT(KMsgCouldntStartUsb, "Error: Couldn't start USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStartUsb);
+ }
+ }
+
+// Id Pin detected
+// Try to move to A-Started
+void CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StartUsbServices();
+ if (!err) // Started USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent() Started USB services\n");
+ iParentStateMachine.SetState(EStateAServicesStarted);
+ err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err) // Started USB services & enabled FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent() Enabled FD loading\n");
+ }
+ else // Started USB services & couldn't enable FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent() Couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ }
+ // Regardless of whether enabling FD loading succeeded or not, attempt to power VBus
+ err = iParentStateMachine.iParentControlAppEngine.BusRequest();
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent() BusRequest() successful\n");
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent() BusRequest() failed\n");
+ // This error only indicates whether USBMAN server got the request without any problem.
+ // VBus could still fail to go up but this is only likely if there is a Bus Error - this is
+ // handled in a separate event though.
+ _LIT(KMsgCouldntPowerUsbDevice, "Error: Couldn't power USB device - press 'R' to try again");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntPowerUsbDevice);
+ // CControlAppStateAServicesStarted::VBusRise() ensures Inactivity Timer is activated when the BusRequest()
+ // is successful, but when it fails we must ensure USB services will be eventually stopped:
+ iParentStateMachine.ResetInactivityTimer();
+ }
+ }
+ else // Couldn't start USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinPresent() Couldn't start USB services\n");
+ iParentStateMachine.SetState(EStateAServicesStopped); // Since Id Pin is present
+ _LIT(KMsgCouldntStartUsb, "Error: Couldn't start USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStartUsb);
+ }
+ }
+
+// RUsb::RequestSession() called from USB Aware App
+// Try to move to B-Started and trigger SRP
+void CControlAppStateMachine::CControlAppStateBServicesStopped::RequestSessionCalled()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::RequestSessionCalled()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StartUsbServices();
+ if (!err) // Started USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::RequestSessionCalled() Started USB services\n");
+ iParentStateMachine.SetState(EStateBServicesStarted); // Do this before SrpTriggered()
+ err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err) // Started USB services & enabled FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::RequestSessionCalled() Enabled FD loading\n");
+ iParentStateMachine.iCurrentState->SrpTriggered(); // Internally generated event in B-Started state
+ }
+ else // Started USB services & couldn't enable FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::RequestSessionCalled() Couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ // No point doing SRP since wont be able to enumerate peripheral
+ }
+ }
+ else // Couldn't start USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::RequestSessionCalled() Couldn't start USB services\n");
+ _LIT(KMsgCouldntStartUsb, "Error: Couldn't start USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStartUsb);
+ }
+ }
+
+void CControlAppStateMachine::CControlAppStateBServicesStopped::VBusDrop()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::VBusDrop() no action: this A-Device dropped VBus before moving into this state\n");
+ DBG_PANIC;
+ }
+
+
+// BServicesStarted state...
+CControlAppStateMachine::CControlAppStateBServicesStarted::CControlAppStateBServicesStarted(CControlAppStateMachine& aParentStateMachine)
+ : CControlAppStateBase(aParentStateMachine)
+ {
+ }
+
+// VBus not being powered any more by remote device
+// Try to stop USB services and move to B-Stopped
+void CControlAppStateMachine::CControlAppStateBServicesStarted::VBusDrop()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::VBusDrop()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StopUsbServices();
+ if (!err) // Stopped USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::VBusDrop() Stopped USB services\n");
+ iParentStateMachine.SetState(EStateBServicesStopped);
+ }
+ else // Couldn't stop USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::VBusDrop() Couldn't stop USB services\n");
+ // Stay in current state B-Started.
+ // VBus probably dropped as a result of B-Plug being withdrawn (or remote A-Device powering down VBus).
+ // If A-Plug inserted, will move to A-Started from this state. (If VBus is re-powered, in the correct state too).
+ _LIT(KMsgCouldntStopUsb, "Error: Couldn't stop USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStopUsb);
+ }
+ }
+
+// We've come from B-Stopped to trigger an SRP
+// If SRP times out (notification from USBMAN will be another separate event received) we'll return to B-Stopped.
+// If SRP successful, VBus will be powered and we can stay in the current state.
+void CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTriggered()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTriggered()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.BusRequest(); // SRP
+ // If no err, we don't have to do anything
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTriggered() BusRequest for SRP successful\n");
+ }
+ else // Was problem doing SRP - won't get SRP timeout event - go back to B-Stopped now
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTriggered() BusRequest for SRP failed\n");
+ _LIT(KMsgFailedBecomingHost, "Error: Failed to become Host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgFailedBecomingHost);
+ err = iParentStateMachine.iParentControlAppEngine.StopUsbServices();
+ if (!err) // Cleaned up by stopping USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTriggered() Stopped USB services\n");
+ iParentStateMachine.SetState(EStateBServicesStopped);
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTriggered() Couldn't stop USB services\n");
+ _LIT(KMsgCouldntStopUsb, "Error: Couldn't stop USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStopUsb);
+ // Stay in current state B-Started.
+ // Can re-try SRP by doing RequestSession() -> BusRequest() in this state.
+ // No event received if B-Plug is withdrawn.
+ // If A-Plug inserted, will move to A-Started from this state.
+ }
+ }
+ }
+
+// Message notification from USBMAN that SRP requested earlier has timed out.
+// Try to move to B-Stopped
+void CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTimeout()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTimeout()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StopUsbServices();
+ if (!err) // Stopped USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTimeout() Stopped USB services\n");
+ iParentStateMachine.SetState(EStateBServicesStopped);
+ }
+ else // Couldn't stop USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::SrpTimeout() Couldn't stop USB services\n");
+ _LIT(KMsgCouldntStopUsb, "Error: Couldn't stop USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStopUsb);
+ // Stay in current state B-Started.
+ // Can re-try SRP by doing RequestSession() -> BusRequest() in this state.
+ // No event received if B-Plug is withdrawn.
+ // If A-Plug inserted, will move to A-Started from this state.
+ }
+ }
+
+// Will see when SRP successful
+void CControlAppStateMachine::CControlAppStateBServicesStarted::VBusRise()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::VBusRise()\n");
+ }
+
+// Time taken to notice the drop in VBus by which time the Id Pin has been inserted.
+// Cater for the IdPinPresent event in this state therefore.
+// Try to power VBus and move to A-Started state
+void CControlAppStateMachine::CControlAppStateBServicesStarted::IdPinPresent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::IdPinPresent()\n");
+ iParentStateMachine.SetState(EStateAServicesStarted); // Since Id Pin present and USB services still started.
+ // USB services already started but may have failed to enable FD loading previously so try again (calling twice does no harm)
+ TInt err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::IdPinPresent() Enabled FD loading\n");
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::IdPinPresent() Couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ }
+ err = iParentStateMachine.iParentControlAppEngine.BusRequest();
+ if (!err) // Powered VBus
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::IdPinPresent() Powered VBus\n");
+ }
+ else // Couldn't power VBus
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::IdPinPresent() Couldn't power VBus\n");
+ // RequestSession() in A-Started will have the effect of powering VBus
+ _LIT(KMsgCouldntPowerUsbDevice, "Error: Couldn't power USB device - press 'R' to try again");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntPowerUsbDevice);
+ // CControlAppStateAServicesStarted::VBusRise() ensures Inactivity Timer is activated when the BusRequest()
+ // is successful, but when it fails we must ensure USB services will be eventually stopped:
+ iParentStateMachine.ResetInactivityTimer();
+ }
+ }
+
+// Let underlying OTG deal with what this means in this state
+void CControlAppStateMachine::CControlAppStateBServicesStarted::RequestSessionCalled()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStarted::RequestSessionCalled()\n");
+ (void) iParentStateMachine.iParentControlAppEngine.BusRequest(); // Not interested in error code
+ }
+
+
+// AServicesStarted state...
+CControlAppStateMachine::CControlAppStateAServicesStarted::CControlAppStateAServicesStarted(CControlAppStateMachine& aParentStateMachine)
+ : CControlAppStateBase(aParentStateMachine)
+ {
+ }
+
+// A-Plug has been removed
+// Try to move to B-Stopped state
+void CControlAppStateMachine::CControlAppStateAServicesStarted::IdPinAbsent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::IdPinAbsent()\n");
+ // BusDrop() not needed as VBus unpowered at a lower level if Id Pin not present
+ TInt err = iParentStateMachine.iParentControlAppEngine.StopUsbServices();
+ if (!err) // Stopped USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::IdPinAbsent() Stopped USB services (BusDrop unnecessary here)\n");
+ iParentStateMachine.SetState(EStateBServicesStopped);
+ }
+ else // Couldn't stop USB services started & Id Pin absent - go to B-Started
+ {
+ PNT("CControlAppStateMachine::CControlAppStateBServicesStopped::IdPinAbsent() Couldn't stop USB services\n");
+ // Move to B-Started since no Id Pin but USB services still started.
+ iParentStateMachine.SetState(EStateBServicesStarted);
+ _LIT(KMsgCouldntStopUsb, "Error: Couldn't stop USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStopUsb);
+ }
+ }
+
+// Remote B-Device sent SRP
+// It is possible for VBus to be down in A-Started state so SRP could arrive
+void CControlAppStateMachine::CControlAppStateAServicesStarted::SrpDetected()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::SrpDetected()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.BusRespondSrp();
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::SrpDetected() BusRespondSrp() succeeded\n");
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::SrpDetected() BusRespondSrp() error\n");
+ _LIT(KMsgCouldntPowerUsbDevice, "Error: Couldn't power USB device");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntPowerUsbDevice);
+ }
+ }
+
+void CControlAppStateMachine::CControlAppStateAServicesStarted::VBusRise()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::VBusRise() - start Inactivity Timer...\n");
+ iParentStateMachine.ResetInactivityTimer();
+ }
+
+void CControlAppStateMachine::CControlAppStateAServicesStarted::ConnectionIdle()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::ConnectionIdle()\n");
+ iParentStateMachine.ResetInactivityTimer();
+ }
+
+void CControlAppStateMachine::CControlAppStateAServicesStarted::ConnectionActive()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::ConnectionActive()\n");
+ iParentStateMachine.CancelInactivityTimer();
+ }
+
+void CControlAppStateMachine::CControlAppStateAServicesStarted::InactivityTimerExpired()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::InactivityTimerExpired()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.BusDrop();
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::InactivityTimerExpired() Dropped VBus\n");
+ err = iParentStateMachine.iParentControlAppEngine.StopUsbServices();
+ if (!err) // Stopped USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::InactivityTimerExpired() Stopped USB services\n");
+ iParentStateMachine.SetState(EStateAServicesStopped);
+ }
+ else // Couldn't stop USB services started & Id Pin present - stay in A-Started
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::InactivityTimerExpired() Couldn't stop USB services\n");
+ _LIT(KMsgCouldntStopUsb, "Error: Couldn't stop USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStopUsb);
+ }
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::InactivityTimerExpired() Can't drop VBus\n");
+ _LIT(KMsgCouldntDropVBus, "Error: Couldn't drop VBus to save power. Unplug device.");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntDropVBus);
+ }
+ }
+
+// Let underlying OTG deal with what this means in this state
+void CControlAppStateMachine::CControlAppStateAServicesStarted::RequestSessionCalled()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::RequestSessionCalled()\n");
+ (void) iParentStateMachine.iParentControlAppEngine.BusRequest(); // Not interested in error code
+ }
+
+void CControlAppStateMachine::CControlAppStateAServicesStarted::VBusError()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStarted::VBusError()\n");
+ iParentStateMachine.CancelInactivityTimer(); // To prevent a BusDrop being done - VBus is already down.
+ (void) iParentStateMachine.iParentControlAppEngine.ClearVBusError(); // Not interested in error code
+ // A call to RequestSession() will be necessary to raise VBus again
+ _LIT(KMsgVBusError, "Error: Couldn't power USB device - please unplug");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgVBusError);
+ }
+
+
+// AServicesStopped state...
+CControlAppStateMachine::CControlAppStateAServicesStopped::CControlAppStateAServicesStopped(CControlAppStateMachine& aParentStateMachine)
+ : CControlAppStateBase(aParentStateMachine)
+ {
+ }
+
+// A-Plug been removed
+// Try to move to B-Stopped
+void CControlAppStateMachine::CControlAppStateAServicesStopped::IdPinAbsent()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::IdPinAbsent()\n");
+ iParentStateMachine.SetState(EStateBServicesStopped);
+ }
+
+// Remote B-Device sent SRP
+// Try to move to A-Started
+void CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StartUsbServices();
+ if (!err) // Started USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected() Started USB services\n");
+ iParentStateMachine.SetState(EStateAServicesStarted);
+ // Need to enable FD loading for when the roles revert back to their defaults
+ // for after the role swap that follows the BusRespondSRP()
+ err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err) // Started USB services & enabled FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected() Enabled FD loading\n");
+ }
+ else // Started USB services & couldn't enable FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected() Couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ }
+ // Regardless of whether FD loading succeeded
+ err = iParentStateMachine.iParentControlAppEngine.BusRespondSrp();
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected() BusRespondSrp() succeeded\n");
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected() BusRespondSrp() error\n");
+ // In A-Started, if no activity for a while (which will be the case if BusRespondSRP() failed = VBus unpowered)
+ // Inactivity Timer will expire and send the system back to A-Stopped.
+ _LIT(KMsgCouldntPowerUsbDevice, "Error: Couldn't power USB device");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntPowerUsbDevice);
+ }
+ }
+ else // Couldn't start USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::SrpDetected() Couldn't start USB services\n");
+ _LIT(KMsgCouldntStartUsb, "Error: Couldn't start USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStartUsb);
+ }
+ }
+
+// Local USB Aware App would like to use USB services
+// Try to move to A-Started
+void CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled()\n");
+ TInt err = iParentStateMachine.iParentControlAppEngine.StartUsbServices();
+ if (!err) // Started USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled() Started USB services\n");
+ iParentStateMachine.SetState(EStateAServicesStarted);
+ // In A-Started, if no activity for a while, which will be the case if
+ // EnableFunctionDriverLoading() fails (= no host activity) or BusRequest() fails (= no VBus)
+ // Inactivity Timer will expire soon and send the system back to A-Stopped.
+ err = iParentStateMachine.iParentControlAppEngine.EnableFunctionDriverLoading();
+ if (!err) // Started USB services & enabled FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled() Enabled FD loading\n");
+ }
+ else // Started USB services & couldn't enable FD loading
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled() Couldn't enable FD loading\n");
+ _LIT(KMsgCouldntEnableFdLoading, "Error: Couldn't enable driver loading - can't function as host");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntEnableFdLoading);
+ }
+ // Regardless of whether enabling FD loading succeeded
+ err = iParentStateMachine.iParentControlAppEngine.BusRequest();
+ if (!err)
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled() BusRequest() succeeded\n");
+ }
+ else
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled() BusRequest() error\n");
+ _LIT(KMsgCouldntPowerUsbDevice, "Error: Couldn't power USB device");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntPowerUsbDevice);
+ // CControlAppStateAServicesStarted::VBusRise() ensures Inactivity Timer is activated when the BusRequest()
+ // is successful, but when it fails we must ensure USB services will be eventually stopped:
+ iParentStateMachine.ResetInactivityTimer();
+ }
+ }
+ else // Couldn't start USB services
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::RequestSessionCalled() Couldn't start USB services\n");
+ _LIT(KMsgCouldntStartUsb, "Error: Couldn't start USB services");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgCouldntStartUsb);
+ }
+ }
+
+void CControlAppStateMachine::CControlAppStateAServicesStopped::VBusError()
+ {
+ PNT("CControlAppStateMachine::CControlAppStateAServicesStopped::VBusError()\n");
+ (void) iParentStateMachine.iParentControlAppEngine.ClearVBusError(); // Not interested in error code
+ // A call to RequestSession() will be necessary to raise VBus again
+ _LIT(KMsgVBusError, "Error: Couldn't power USB device - please unplug");
+ iParentStateMachine.iParentControlAppEngine.DisplayUserMessage(KMsgVBusError);
+ }
+
+
+CIdPinWatcher* CIdPinWatcher::NewL(MControlAppEngineWatcherInterface& aControlAppEngine)
+ {
+ CIdPinWatcher* self = new(ELeave) CIdPinWatcher(aControlAppEngine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CIdPinWatcher::~CIdPinWatcher()
+ {
+ Cancel();
+ iIdPinProp.Close();
+ }
+
+CIdPinWatcher::CIdPinWatcher(MControlAppEngineWatcherInterface& aControlAppEngine)
+ : CActive(EPriorityStandard)
+ , iParentControlAppEngine(aControlAppEngine)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CIdPinWatcher::ConstructL()
+ {
+ TInt err = iIdPinProp.Attach(KUidUsbManCategory, KUsbOtgIdPinPresentProperty);
+ LOG("CIdPinWatcher::ConstructL iIdPinProp.Attach(KUidUsbManCategory, KUsbOtgIdPinPresentProperty) => %d",err);
+ User::LeaveIfError(err);
+
+ SubscribeForNotification();
+
+ // Get the current value and update the Engine
+ TInt val;
+ err = iIdPinProp.Get(val);
+ LOG("CIdPinWatcher::ConstructL iIdPinProp.Get(val) => %d",err);
+ User::LeaveIfError(err);
+ iParentControlAppEngine.SetIdPin(val);
+ }
+
+void CIdPinWatcher::SubscribeForNotification()
+ {
+ iIdPinProp.Subscribe(iStatus);
+ SetActive();
+ }
+
+void CIdPinWatcher::RunL()
+ {
+ SubscribeForNotification();
+ // Get newly changed value
+ TInt val;
+ User::LeaveIfError(iIdPinProp.Get(val));
+ // Update value in Engine
+ iParentControlAppEngine.SetIdPin(val);
+ }
+
+void CIdPinWatcher::DoCancel()
+ {
+ iIdPinProp.Cancel();
+ }
+
+
+
+CVBusWatcher* CVBusWatcher::NewL(MControlAppEngineWatcherInterface& aControlAppEngine)
+ {
+ CVBusWatcher* self = new(ELeave) CVBusWatcher(aControlAppEngine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CVBusWatcher::~CVBusWatcher()
+ {
+ Cancel();
+ iVBusProp.Close();
+ }
+
+CVBusWatcher::CVBusWatcher(MControlAppEngineWatcherInterface& aControlAppEngine)
+ : CActive(EPriorityStandard)
+ , iParentControlAppEngine(aControlAppEngine)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CVBusWatcher::ConstructL()
+ {
+ TInt err = iVBusProp.Attach(KUidUsbManCategory, KUsbOtgVBusPoweredProperty);
+ LOG("CVBusWatcher::ConstructL iVBusProp.Attach(KUidUsbManCategory, KUsbOtgVBusPoweredProperty) => %d",err);
+ User::LeaveIfError(err);
+
+ SubscribeForNotification();
+
+ // Get the current value and update the Engine
+ TInt val;
+ err = iVBusProp.Get(val);
+ LOG("CVBusWatcher::ConstructL iVBusProp.Get(val) => %d",err);
+ User::LeaveIfError(err);
+ iParentControlAppEngine.SetVBus(val);
+ }
+
+void CVBusWatcher::SubscribeForNotification()
+ {
+ iVBusProp.Subscribe(iStatus);
+ SetActive();
+ }
+
+void CVBusWatcher::RunL()
+ {
+ SubscribeForNotification();
+ // Get newly changed value
+ TInt val;
+ User::LeaveIfError(iVBusProp.Get(val));
+ // Update value in Engine
+ iParentControlAppEngine.SetVBus(val);
+ }
+
+void CVBusWatcher::DoCancel()
+ {
+ iVBusProp.Cancel();
+ }
+
+
+
+CConnectionIdleWatcher* CConnectionIdleWatcher::NewL(MControlAppEngineWatcherInterface& aControlAppEngine)
+ {
+ CConnectionIdleWatcher* self = new(ELeave) CConnectionIdleWatcher(aControlAppEngine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CConnectionIdleWatcher::~CConnectionIdleWatcher()
+ {
+ Cancel();
+ iConnIdleProp.Close();
+ }
+
+CConnectionIdleWatcher::CConnectionIdleWatcher(MControlAppEngineWatcherInterface& aControlAppEngine)
+ : CActive(EPriorityStandard)
+ , iParentControlAppEngine(aControlAppEngine)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CConnectionIdleWatcher::ConstructL()
+ {
+ TInt err = iConnIdleProp.Attach(KUidUsbManCategory, KUsbOtgConnectionIdleProperty);
+ LOG("CConnectionIdleWatcher::ConstructL iIdPinProp.Attach(KUidUsbManCategory, KUsbOtgConnectionIdleProperty) => %d",err);
+ User::LeaveIfError(err);
+
+ SubscribeForNotification();
+
+ // Get the current value and update the Engine
+ TInt val;
+ err = iConnIdleProp.Get(val);
+ LOG("CConnectionIdleWatcher::ConstructL iConnIdleProp.Get(val) => %d",err);
+ User::LeaveIfError(err);
+ iParentControlAppEngine.SetConnectionIdle(val);
+ }
+
+void CConnectionIdleWatcher::SubscribeForNotification()
+ {
+ iConnIdleProp.Subscribe(iStatus);
+ SetActive();
+ }
+
+void CConnectionIdleWatcher::RunL()
+ {
+ SubscribeForNotification();
+ // Get newly changed value
+ TInt val;
+ User::LeaveIfError(iConnIdleProp.Get(val));
+ // Update value in Engine
+ iParentControlAppEngine.SetConnectionIdle(val);
+ }
+
+void CConnectionIdleWatcher::DoCancel()
+ {
+ iConnIdleProp.Cancel();
+ }
+
+
+
+CMessageWatcher* CMessageWatcher::NewL(MControlAppEngineWatcherInterface& aControlAppEngine)
+ {
+ CMessageWatcher* self = new(ELeave) CMessageWatcher(aControlAppEngine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CMessageWatcher::~CMessageWatcher()
+ {
+ Cancel();
+ }
+
+CMessageWatcher::CMessageWatcher(MControlAppEngineWatcherInterface& aControlAppEngine)
+ : CActive(EPriorityStandard)
+ , iParentControlAppEngine(aControlAppEngine)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CMessageWatcher::ConstructL()
+ {
+ iParentControlAppEngine.Usb().MessageNotification(iStatus, iMessage);
+ SetActive();
+ }
+
+void CMessageWatcher::DoCancel()
+ {
+ iParentControlAppEngine.Usb().MessageNotificationCancel();
+ }
+
+void CMessageWatcher::RunL()
+ {
+ TInt err = iStatus.Int();
+ if (err)
+ {
+ LOG("CMessageWatcher::RunL() iStatus.Int()=%d", err);
+ }
+ else
+ {
+ switch(iMessage)
+ {
+ case KErrUsbOtgVbusError:
+ iParentControlAppEngine.MessageReceived(EErrUsbOtgVbusError);
+ break;
+ case KErrUsbOtgSrpTimeout:
+ iParentControlAppEngine.MessageReceived(EErrUsbOtgSrpTimeout);
+ break;
+ case KUsbMessageSrpReceived:
+ iParentControlAppEngine.MessageReceived(EUsbMessageSrpReceived);
+ break;
+ case KUsbMessageRequestSession:
+ iParentControlAppEngine.MessageReceived(EUsbMessageRequestSession);
+ break;
+ default: // The State Machine is not interested in any other messages
+ break;
+ }
+
+ LOG("CMessageWatcher::RunL() msg = %d", iMessage);
+ } // else
+
+ iParentControlAppEngine.Usb().MessageNotification(iStatus, iMessage);
+ SetActive();
+ }
+
+