--- /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;
+ }
+ }
+