devicediagnosticsfw/diagframework/src/diagenginestatemachine.cpp
branchRCL_3
changeset 26 19bba8228ff0
parent 0 b497e44ab2fc
--- /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 <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
+