diff -r 000000000000 -r dfb7c4ff071f commsfwsupport/commselements/StateMachine/src/StateMachine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwsupport/commselements/StateMachine/src/StateMachine.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,215 @@ +// Copyright (c) 2003-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: +// Offers a base class for an asynchronous state machine +// +// + +/** + @file +*/ + +#include "StateMachine.h" +#include "AsynchEvent.h" + + +#ifdef _DEBUG +// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module +// (if it could happen through user error then you should give it an explicit, documented, category + code) +_LIT(KSpecAssert_ElemStateMachStM, "ElemStateMachStM"); +#endif + +EXPORT_C CStateMachine::CStateMachine() : + CActive( EPriorityStandard ) + { + CActiveScheduler::Add(this); + } + +EXPORT_C CStateMachine::~CStateMachine() + { + delete iFragment; + } + +EXPORT_C HBufC8* CStateMachine::ReAllocL( TInt aNewLength ) +/** + * Re-allocates the instance fragment + * + * @param aNewLength a length to put into the buffer + * @return a pointer to the allocated fragment + */ + { + if ( !iFragment ) + { + iFragment = HBufC8::NewL( aNewLength ); + } + else + { + TInt n = iFragment->Length(); + if ( (iFragment->Des().MaxLength() - n) < aNewLength ) + { + iFragment = iFragment->ReAllocL( aNewLength + n ); + } + } + return iFragment; + } + +EXPORT_C void CStateMachine::Start( TRequestStatus* aClientStatus, CAsynchEvent* aErrorEvent, MStateMachineNotify* aStateMachineNotify ) +/** + * Starts the state machine + * + * @param aClientStatus the client request to complete on completion + * @param aErrorEvent an error event to execute on error + * @param aStateMachineNotify a notifier to receive state achine events + */ + { + //history is set beforehand + iLastError = KErrNone; + iClientStatus = aClientStatus; + if (iClientStatus != NULL) + *iClientStatus = KRequestPending; + iErrorEvent = aErrorEvent; + iSuspendRequest = EFalse; + iStateMachineNotify = aStateMachineNotify; + //jump to RunL + TRequestStatus* p=&iStatus; + if ( !IsActive() ) + { + SetActive(); + } + User::RequestComplete( p, KErrNone ); + } + +EXPORT_C void CStateMachine::Cancel( TInt aLastError ) +/** + * Cancels the state machine with an error + * + * @param aLastError a desired error code. + * if the last eror is KErrNone the state machine + * will be cancelled and client request will be completed with KErrCancel. + * In any other case the active event will become the error event and the + * processing continues. + */ + { + iSuspendRequest = EFalse; + if ( aLastError == KErrNone ) + { + iErrorEvent = 0; + } + //cancel the current activity + CActive::Cancel(); + iLastError = KErrCancel; + iActiveEvent = iErrorEvent; + if ( iActiveEvent ) + { + //jump to RunL //!!This makes the cancel asynchronous + TRequestStatus* p=&iStatus; + SetActive(); + User::RequestComplete( p, KErrNone ); + } + } + +EXPORT_C void CStateMachine::DoCancel() +/** + * completes the cancel request + * + */ + { + if ( !iErrorEvent ) //otherwise the "cancel" completes after the error event has been sent + { + OnCompletion(); + } + } + +EXPORT_C void CStateMachine::OnError() +/** + * Called from ::RunL when an error occures + * + */ + { + if ( iLastError != KErrNone ) + { + if ( iActiveEvent != iErrorEvent ) + { + iActiveEvent = 0; + } + } + else + { + iLastError = iStatus.Int(); + iActiveEvent = iErrorEvent; + } + } + +EXPORT_C void CStateMachine::RunL() +/** + * Called on completion of one active event + * + */ + { + if ( iStatus.Int() != KErrNone ) + {//error + OnError(); + } + if ( iActiveEvent ) + {//process iActiveEvent if not iSuspendRequest + if ( iSuspendRequest ) + { + if ( iStateMachineNotify ) + {//return value ignored + iStateMachineNotify->OnCompletion( this ); + } + } + else + { + SetActive(); + iActiveEvent = iActiveEvent->ProcessL( iStatus ); + } + } + else + {//complete the state machine task + OnCompletion(); + } + } + +EXPORT_C TInt CStateMachine::RunError(TInt aError) +/** + * RunL left. Complete status with the aError and let RunL function to handle it + * + */ + { + //if RunL (ProcessL) leaves the current request must not be completed + __ASSERT_DEBUG(IsActive(), User::Panic(KSpecAssert_ElemStateMachStM, 1)); + iActiveEvent = 0; + TRequestStatus* p=&iStatus; + User::RequestComplete( p, aError ); + return KErrNone; //no error propagation to central error handler + } + +EXPORT_C void CStateMachine::OnCompletion() +/** + * Called by RunL when the state machine has completed its task. + * + */ + { + //!!!notifier cannot delete this + TBool bDelete = iStateMachineNotify ? iStateMachineNotify->OnCompletion( this ) : EFalse; + if ( iClientStatus ) + { + User::RequestComplete( iClientStatus, iLastError ); + } + if ( bDelete ) + { + delete this; + } + } +