--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devicediagnosticsfw/diagframework/src/diagenginestatemachine.cpp Thu Dec 17 09:07:52 2009 +0200
@@ -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 <DiagFrameworkDebug.h> // 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
+