diff -r b183ec05bd8c -r 19bba8228ff0 devicediagnosticsfw/diagframework/src/diagenginestatemachine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devicediagnosticsfw/diagframework/src/diagenginestatemachine.cpp Wed Sep 01 12:27:42 2010 +0100 @@ -0,0 +1,362 @@ +/* +* Copyright (c) 2007 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: Class definition of CStateMachine +* +*/ + + +// CLASS DECLARATION +#include "diagenginestatemachine.h" // DiagFwInternal::CStateMachine + +// SYSTEM INCLUDE FILES +#include // LOGSTRING + +// USER INCLUDE FILES +#include "diagenginestatemachineobserver.h" // DiagFwInternal::MStateMachineObserver +#include "diagengineeventbasic.h" // DiagFwInternal::CEventBasic +#include "diagframework.pan" // Panics + + +namespace DiagFwInternal + { +// ======== LOCAL DATA ========== +struct TStateTableEntry + { + TState iInputState; + TEvent iEventType; + TState iOutputState; + }; + + +static const TStateTableEntry KStateTable[] = + { + // current state input event output state + { + EStateNotReady, EEventExecute, EStateCreatingPlan + }, + { + EStateCreatingPlan, EEventPlanCreated, EStateRunning + }, + { + EStateSuspended, EEventResumeToRunning, EStateRunning + }, + { + EStateSuspended, EEventResumeToCreatingPlan, EStateCreatingPlan + }, + { + EStateFinalizing, EEventFinalized, EStateStopped, + }, + // ALL EStateAny MUST be listed in below. + // This makes sure that more specific transition happens before + // any state transitions occur. + { + EStateAny, EEventAllPluginsCompleted, EStateFinalizing + }, + { + EStateAny, EEventCancelAll, EStateCancelAll + }, + { + EStateAny, EEventSuspend, EStateSuspended + }, + { + EStateAny, EEventVoiceCallActive, EStateSuspended + } + }; + +static const TInt KStateTableSize = sizeof( KStateTable )/sizeof( TStateTableEntry ); + + +// ======== LOCAL FUNCTIONS ======== + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// CStateMachine::ConstructL() +// --------------------------------------------------------------------------- +// +void CStateMachine::ConstructL() + { + } + + +// --------------------------------------------------------------------------- +// CStateMachine::NewL() +// --------------------------------------------------------------------------- +// +CStateMachine* CStateMachine::NewL( MStateMachineObserver& aObserver ) + { + CStateMachine* self = CStateMachine::NewLC( aObserver ); + CleanupStack::Pop( self ); + return self; + } + + +// --------------------------------------------------------------------------- +// CStateMachine::NewLC() +// --------------------------------------------------------------------------- +// +CStateMachine* CStateMachine::NewLC( MStateMachineObserver& aObserver ) + { + CStateMachine* self = new( ELeave )CStateMachine( aObserver ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// --------------------------------------------------------------------------- +// CStateMachine::CStateMachine +// --------------------------------------------------------------------------- +// +CStateMachine::CStateMachine( MStateMachineObserver& aObserver ) + : CActive( EPriorityStandard ), + iObserver( aObserver ), + iEventQueue(), + iState( EStateNotReady ) + { + CActiveScheduler::Add( this ); + } + + +// --------------------------------------------------------------------------- +// CStateMachine::~CStateMachine +// --------------------------------------------------------------------------- +// +CStateMachine::~CStateMachine() + { + Cancel(); + iEventQueue.ResetAndDestroy(); + iEventQueue.Close(); + } + + +// --------------------------------------------------------------------------- +// CStateMachine::AddEventL +// --------------------------------------------------------------------------- +// +void CStateMachine::AddEventL( CEventBasic* aEvent ) + { + __ASSERT_ALWAYS( aEvent, Panic( EDiagFrameworkBadArgument ) ); + + LOGSTRING2( "CStateMachine::AddEventL: Type = %S", &( aEvent->ToString() ) ) + + CleanupStack::PushL( aEvent ); + iEventQueue.AppendL( aEvent ); // owership transfer + CleanupStack::Pop( aEvent ); + // do not set aEvent to NULL, since it is used later + + TState nextState = CheckStateTable( iState, aEvent->GetType() ); + + if ( nextState != EStateAny && nextState != iState ) + { + // state change happened. + TState prevState = iState; + iState = nextState; + + iObserver.HandleStateChangedL( prevState, iState, *aEvent ); + } + + ReactivateQueue(); + } + + +// --------------------------------------------------------------------------- +// CStateMachine::AddEventL +// --------------------------------------------------------------------------- +// +void CStateMachine::AddEventL( TEvent aEventId ) + { + // simple event. Create a basic event type + AddEventL( new( ELeave )CEventBasic( aEventId ) ); + } + + +// --------------------------------------------------------------------------- +// CStateMachine::CurrentState +// --------------------------------------------------------------------------- +// +TState CStateMachine::CurrentState() const + { + return iState; + } + +// --------------------------------------------------------------------------- +// CStateMachine::HandleError +// --------------------------------------------------------------------------- +// +void CStateMachine::HandleError( TInt aError ) + { + iState = iObserver.HandleError( iState, aError ); + } + +// --------------------------------------------------------------------------- +// From CActive +// CStateMachine::RunL +// --------------------------------------------------------------------------- +// +void CStateMachine::RunL() + { + // Note that ReactivateQueue() must always be called before observer method + // is called. This is because observer may delete state machine + // during the callback. To prevent crashes, callback MUST BE the + // last funciton to call before returning. + if ( iEventQueue.Count() > 0 ) + { + // there is an item in the event queue. + // Pop and execute the event. + CEventBasic* event = iEventQueue[0]; + iEventQueue.Remove( 0 ); + + // always reactivate the queue before calling observer + ReactivateQueue(); + + CleanupStack::PushL( event ); + iObserver.HandleEventL( *event ); + CleanupStack::PopAndDestroy( event ); + + // must return immediately to make sure that no member variables + // are accessed after observer is called. + return; + } + else + { + LOGSTRING( "CStateMachine::RunL(). Called for no reason?" ) + __ASSERT_DEBUG( 0, Panic( EDiagFrameworkCorruptStateMachine ) ); + } + } + +// --------------------------------------------------------------------------- +// From CActive +// CStateMachine::DoCancel +// --------------------------------------------------------------------------- +// +void CStateMachine::DoCancel() + { + // Nothing to do here.. + } + +// --------------------------------------------------------------------------- +// From CActive +// CStateMachine::RunError +// --------------------------------------------------------------------------- +// +TInt CStateMachine::RunError( TInt aError ) + { + HandleError( aError ); + return KErrNone; + } + + +// --------------------------------------------------------------------------- +// CStateMachine::CheckStateTable +// --------------------------------------------------------------------------- +// +TState CStateMachine::CheckStateTable( TState aCurrState, TEvent aEvent ) const + { + TState outputState = EStateAny; + TBool isFound = EFalse; + + for ( TInt i = 0; i < KStateTableSize && !isFound; i++ ) + { + if ( ( KStateTable[i].iInputState == EStateAny || + aCurrState == KStateTable[i].iInputState ) && + aEvent == KStateTable[i].iEventType ) + { + outputState = KStateTable[i].iOutputState; + isFound = ETrue; + } + } + return outputState; + } + +// --------------------------------------------------------------------------- +// CStateMachine::ReactivateQueue +// --------------------------------------------------------------------------- +// +void CStateMachine::ReactivateQueue() + { + if ( !IsActive() && iEventQueue.Count() > 0 ) + { + // reactivate only if it is not already active, and there is something + // in the queue + TRequestStatus* stat = &iStatus; + User::RequestComplete( stat, KErrNone ); + SetActive(); + } + } + +// --------------------------------------------------------------------------- +// CStateMachine::StateName +// --------------------------------------------------------------------------- +// + +#if _DEBUG +const TDesC& CStateMachine::StateName( TState aState ) const + { + _LIT( KStateAny, "EStateAny" ); + _LIT( KStateNotReady, "EStateNotReady" ); + _LIT( KStateCreatingPlan,"EStateCreatingPlan" ); + _LIT( KStateRunning, "EStateRunning" ); + _LIT( KStateStopped, "EStateStopped" ); + _LIT( KStateCancelAll, "EStateCancelAll" ); + _LIT( KStateSuspended, "EStateSuspended" ); + _LIT( KStateFinalizing, "EStateFinalizing" ); + + switch ( aState ) + { + case EStateAny: + return KStateAny(); + + case EStateNotReady: + return KStateNotReady(); + + case EStateCreatingPlan: + return KStateCreatingPlan(); + + case EStateRunning: + return KStateRunning(); + + case EStateStopped: + return KStateStopped(); + + case EStateCancelAll: + return KStateCancelAll(); + + case EStateSuspended: + return KStateSuspended(); + + case EStateFinalizing: + return KStateFinalizing(); + + default: + _LIT( KUnknownState, "* Unknown State *"); + return KUnknownState(); + } + } + +#else // #if _DEBUG + +// non-debug version. +const TDesC& CStateMachine::StateName( TState /* aState */ ) const + { + _LIT( KNonDebugStateName, "?" ); + return KNonDebugStateName(); + } + +#endif // #else _DEBUG + + } // end of namespace DiagFwInternal + +// End of File +