diff -r 000000000000 -r 9cfd9a3ee49c networkprotocolmodules/networkprotocolmodule/LbsProtocolModule/src/cstatemachinebase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkprotocolmodules/networkprotocolmodule/LbsProtocolModule/src/cstatemachinebase.cpp Tue Feb 02 01:50:39 2010 +0200 @@ -0,0 +1,958 @@ +// Copyright (c) 2006-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: +// This file provides the implementation of the base class for +// protocol state machines used in the Test Protocol Module. +// +// + +/** + @file + @internalTechnology + @released +*/ + +#include "cstatemachinebase.h" +#include "cstatehandlerbase.h" +#include "lbsdevloggermacros.h" + +//----------------------------------------------------------------------------- +// State Machine Base Class +//----------------------------------------------------------------------------- + +/** Standard constructor. +@param aObserver A reference to the state machine observer. +*/ +CStateMachineBase::CStateMachineBase(MStateMachineObserver& aObserver) +: CActive(EPriorityLow), iObserver(aObserver), iProtocolState(EStateReady) + { + ResetSessionId(); + } + + +/** Standard destructor. +*/ +CStateMachineBase::~CStateMachineBase() + { + iCancelSource = ECancelClosing; + Cancel(); + delete iAssistDataTimer; + delete iQueue; + delete iStateHandler; + } + + +/** Retrieve reference to state machine observer. +@return MStateMachineObserver A reference to the observer. +*/ +MStateMachineObserver& CStateMachineBase::Observer() + { + return iObserver; + } + +/** Set session ID +@param aSessionId Identifier to be used by the state machine whenever + the session ID is to be used. +*/ +void CStateMachineBase::SessionId(const TLbsNetSessionId& aSessionId) + { + iSessionId = aSessionId; + } + +/** Reset session ID +*/ +void CStateMachineBase::ResetSessionId() + { + iSessionId.SetSessionOwner(TUid::Uid(0)); + iSessionId.SetSessionNum(0); + } + +/** Get session ID +@return const TLbsNetSessionId& The session ID currently used by the state machine. +*/ +const TLbsNetSessionId& CStateMachineBase::SessionId() const + { + return iSessionId; + } + +/** Set ID for queued session +@param aSessionId Identifier to be used for a queued session. +*/ +void CStateMachineBase::QueueSessionId(const TLbsNetSessionId& aSessionId) + { + iQueueSessionId = aSessionId; + } + +/** Get ID of queued session +@return const TLbsNetSessionId& The session ID of the queued session +*/ +const TLbsNetSessionId& CStateMachineBase::QueueSessionId() const + { + return iQueueSessionId; + } + + +/** Retrieve current general protocol state. +@return CStateMachineBase::TProtocolState The current general + protocol state for this state machine. + +@see CStateMachineBase::TProtocolState +*/ +CStateMachineBase::TProtocolState CStateMachineBase::State() const + { + return iProtocolState; + } + + +/** Start additional assistance data timer. +The state machine calls this when it has issued a request for additional +assistance data from the network. +*/ +void CStateMachineBase::StartAssistDataTimer() + { + if (iAssistDataTimer->IsActive()) + { + iAssistDataTimer->Cancel(); + } + iAssistDataTimer->EventAfter(TTimeIntervalSeconds(KAssistDataTimerDurationInSec), KAssistDataTimerEvent); + } + + +/** Indicates if location request has been received. +@return TBool ETrue if location request has been received. +*/ +TBool CStateMachineBase::IsLocReqReceived() const + { + return iIsLocReqReceived; + } + +/** Indicates if location response has been sent to network. +@return TBool ETrue if location response has been sent. +*/ +TBool CStateMachineBase::IsLocRespSent() const + { + return iIsLocRespSent; + } + +/** Indicates if Measurement Control has been handled. +@return TBool ETrue if Measurement Control has been handled. +*/ +TBool CStateMachineBase::IsMeasureControlHandled() const + { + return iIsMeasureControlHandled; + } + + +/** Indicates if assistance data action is required. +@return TBool ETrue if assistance data action is required. +*/ +TBool CStateMachineBase::IsAssistanceDataActionReq() const + { + return iAssistanceDataActionRequired; + } + + +/** Client close reason. +This is called by state handlers to determine what reason to +provide to the client for the client session closing. +@return TInt Reason value. +*/ +TInt CStateMachineBase::ClientCloseReason() const + { + TInt reason = KErrNone; + + if (KErrPositionHighPriorityReceive == iClientCancelReason) + { + reason = iClientCancelReason; + } + else if (KErrNone == iNetworkCancelReason) + { + switch (iCancelSource) + { + case ECancelNetworkCancel: + reason = KErrCancel; + break; + + case ECancelNetworkError: + reason = KErrDisconnected; + break; + + case ECancelClientTimeout: + case ECancelNetworkTimeout: + reason = KErrTimedOut; + break; + + case ECancelNone: + { + // The reson returned from here is used for teht Session Complete Message from the + // Network Gateway to the NRH, so use the value which was received with the location + // response + reason = LocRespReason(); + if(reason == KErrCancel || reason == KErrPermissionDenied) + { + reason = KErrNone; + } + } + break; + + case ECancelClientCancel: + reason = iClientCancelReason; + break; + + case ECancelClientCancelSilent: + case ECancelClosing: + break; + + default: + User::Panic(KProtocolModulePanic, EProtocolModuleCancelSource); + break; + }; + } + else + { + reason = iNetworkCancelReason; + } + + return reason; + } + + +/** Network close reason. +This is called by state handlers to determine what reason to +provide to the network for the network session closing. +@return TInt Reason value. +*/ +TInt CStateMachineBase::NetworkCloseReason() const + { + TInt reason = KErrNone; + + if (KErrPositionHighPriorityReceive == iNetworkCancelReason) + { + reason = iNetworkCancelReason; + } + else if (KErrNone == iClientCancelReason) + { + switch (iCancelSource) + { + case ECancelClientCancel: + case ECancelClientCancelSilent: + reason = KErrCancel; + break; + + case ECancelClientTimeout: + case ECancelNetworkTimeout: + reason = KErrTimedOut; + break; + + case ECancelNone: + case ECancelNetworkCancel: + case ECancelNetworkError: + case ECancelClosing: + break; + + default: + User::Panic(KProtocolModulePanic, EProtocolModuleCancelSource); + break; + }; + } + else + { + reason = iClientCancelReason; + } + + return reason; + } + + +/** Silent cancellation of LBS client is taking place. +This is called by state handlers to determine if there is a silent cancellation +of the LBS client session taking place, which means that LBS does not receive +any cancel-related messages for this session. +@return TBool A value of ETrue indicates silent client cancellation is taking place. +*/ +TBool CStateMachineBase::IsSilentClientCancel() const + { + return (ECancelClientCancelSilent == iCancelSource); + } + + +/** Network connection error indication. +This is called by state handlers to determine if a network connection error +has been experienced. In this situation the state handlers should not attempt +to send responses to the network. +@return TBool A value of ETrue indicates a network connection error exists. +*/ +TBool CStateMachineBase::IsNetworkConnectionError() const + { + return ((EStateCancelling == iProtocolState) && (ECancelNetworkError == iCancelSource)); + } + + +/** Location request type. +This is called by state handlers to determine what type of location +request is to be specified to LBS. This is usually fixed for a given +state machine, but there is scope to support more than type of request +within a single state machine. +@return MLbsNetworkProtocolObserver::TLbsNetProtocolService request type. +*/ +MLbsNetworkProtocolObserver::TLbsNetProtocolService CStateMachineBase::LocReqType() const + { + return iLocReqType; + } + + +/** Location response reason. +This is called by state handlers to determine what reason to +provide to the network for the location response failure. +@return TInt Reason value. +*/ +TInt CStateMachineBase::LocRespReason() const + { + TInt reason = KErrNone; + // Was a Location response error provided? + if (KErrNone != iLocRespReason) + { + reason = iLocRespReason; + } + // Are we cancelling? + else if (Cancelling()) + { + switch (iCancelSource) + { + case ECancelClientCancel: + case ECancelClientCancelSilent: + if (KErrPositionHighPriorityReceive == iClientCancelReason) + { + reason = iClientCancelReason; + } + else + { + reason = KErrCancel; + } + break; + + case ECancelClientTimeout: + reason = KErrGeneral; + break; + + case ECancelNone: + case ECancelNetworkError: + case ECancelNetworkTimeout: + case ECancelNetworkCancel: + case ECancelClosing: + break; + + default: + User::Panic(KProtocolModulePanic, EProtocolModuleCancelSource); + break; + + }; + } + return reason; + } + + +/** Location response position. +This is called by state handlers to retrieve the most +recent reported position. +@return TPositionInfoBase Currently held location response position +*/ +const TPositionInfoBase& CStateMachineBase::LocRespPosition() const + { + return iLocRespPosInfo; + } + + +/** Reference Location. +This is called by state handlers to retrieve the most +recent reported reference location. +@return TPositionInfoBase Currently held reference position +*/ +const TPositionInfoBase& CStateMachineBase::ReferenceLoc() const + { + return iReferenceLoc; + } + + +/** Location request quality. +This is called by state handlers to retrieve the most +recent location request quality. +@return TLbsNetPosRequestQuality Currently held location request quality +*/ +const TLbsNetPosRequestQuality& CStateMachineBase::LocReqQuality() const + { + return iLocReqQuality; + } + + +/** Location request positioning method. +This is called by state handlers to retrieve the most +recent location request positioning method. +@return TLbsNetPosRequestMethod Currently held location request positioning method +*/ +const TLbsNetPosRequestMethod& CStateMachineBase::PosMethod() const + { + return iPosMethod; + } + + +/** Initialise internal state machine attributes. +This is used when a new protocol procedure commences. +*/ +void CStateMachineBase::InitialiseMachineBase() + { + iTransitionState = ETransitionNull; + iIsCancelPending = EFalse; + iCancelSource = ECancelNone; + iClientCancelReason = KErrNone; + iNetworkCancelReason = KErrNone; + iIsLocReqReceived = EFalse; + iIsLocRespSent = EFalse; + iIsMeasureControlHandled = EFalse; + iIsAdditionalDataExpected = EFalse; + iAssistanceDataActionRequired = EFalse; + iLocRespReason = KErrNone; + + LBSLOG(ELogP2, "CStateMachineBase::InitialiseMachineBase() protocol state ---> EStateActive \n"); + iProtocolState = EStateActive; + iIsMachineQueued = EFalse; + } + + +/** Complete state machine attributes. +This is used when a protocol procedure completes. +*/ +void CStateMachineBase::CompleteMachineBase() + { + LBSLOG(ELogP2, "CStateMachineBase::CompleteMachineBase() protocol state ---> EStateReady\n"); + iProtocolState = EStateReady; + // Inform Protocol Manager that procedure is complete + Observer().ProcedureCompleteInd(); + } + + +/** Store location response. +@param aPosInfo Location information response +*/ +void CStateMachineBase::StoreLocationResp(TInt aReason, const TPositionInfoBase& aPosInfo) + { + iLocRespReason = aReason; + iLocRespPosInfo = reinterpret_cast (aPosInfo); + } + + +/** Store network location cancel reason. +@param aReason The reason for cancelling network location +*/ +void CStateMachineBase::StoreNetLocCancelReason(TInt aReason) + { + iNetLocCancelReason = aReason; + } + + +/** Store location request quality +@param aQuality Location request quality +*/ +void CStateMachineBase::StoreLocReqQuality(const TLbsNetPosRequestQuality& aQuality) + { + iLocReqQuality = aQuality; + } + + +/** Store location request positioning method +@param aPosMethod Location request positioning method +*/ +void CStateMachineBase::StorePosMethod(const TLbsNetPosRequestMethod& aPosMethod) + { + iPosMethod = aPosMethod; + } + + +/** Store reference location +@param aPosInfo Network reference location information +*/ +void CStateMachineBase::StoreRefLoc(const TPositionInfoBase& aPosInfo) + { + iReferenceLoc = reinterpret_cast (aPosInfo); + } + + +/** Enter new state. +This asks the state handler to perform the actions required when +entering a new state. +*/ +void CStateMachineBase::EnterNewState() + { + ASSERT(iStateHandler != NULL); + + // Perform entry actions for the new state + iStateHandler->EntryActions(); + } + + +/** Exit current state. +This asks the state handler to perform the actions required when +exiting from a state. +*/ +void CStateMachineBase::ExitCurrentState() + { + ASSERT(iStateHandler != NULL); + + // Perform exit actions for the current state + iStateHandler->ExitActions(); + } + + +/** Perform a state transition. +This initiates a state transition and performs the first stage of +this by exiting from the current state. +*/ +void CStateMachineBase::PerformStateTransition() + { + if (!IsActive()) + { + iTransitionState = ETransitionExit; + DoStateTransitionStage(); + } + } + + +/** Do one stage of the state transition. +This employs a self-completion mechanism to perform one stage of +a state transition. The state machine object is set active and then its +own status is completed, which results in its RunL being called. +*/ +void CStateMachineBase::DoStateTransitionStage() + { + TRequestStatus* localStatus = &iStatus; + iStatus = KRequestPending; + SetActive(); + User::RequestComplete(localStatus, KErrNone); + } + + +/** Indicates if state machine is cancelling +@return TBool ETrue if machine is cancelling +*/ +TBool CStateMachineBase::Cancelling() const + { + return (EStateCancelling == iProtocolState) ? ETrue : EFalse; + } + + +/** Indicates if state machine is to be cancelled +@return TBool ETrue if machine is to be cancelled +*/ +TBool CStateMachineBase::CancelPending() const + { + return iIsCancelPending; + } + + +/** Cancel state machine +@param aCancelSource The source that decided to cancel. +*/ +void CStateMachineBase::CancelMachine(const TCancelSource& aCancelSource) + { + iIsCancelPending = ETrue; + iCancelSource = aCancelSource; + + // Cancel the active procedure + CancelProcedure(); + + // Perform state transition + if (!IsActive() && (ETransitionNull == iTransitionState)) + { + PerformStateTransition(); + } + } + + +/** Sets state machine attributes to represent cancelling +*/ +void CStateMachineBase::SetMachineAsCancelling() + { + LBSLOG(ELogP2, "CStateMachineBase::SetMachineAsCancelling() protocol state ---> EStateCancelling \n"); + iIsCancelPending = EFalse; + iProtocolState = CStateMachineBase::EStateCancelling; + } + + +/** Cancel state machine +@param aCancelSource The source that decided to cancel. +@param aReason The reason for the cancellation. +*/ +void CStateMachineBase::CancelMachine(const TCancelSource& aCancelSource, + TInt aReason) + { + // Store the specific cancel reason + switch (aCancelSource) + { + case ECancelNetworkCancel: + case ECancelNetworkError: + case ECancelNetworkTimeout: + iNetworkCancelReason = aReason; + break; + + case ECancelClientTimeout: + case ECancelClientCancel: + case ECancelClientCancelSilent: + iClientCancelReason = aReason; + break; + + case ECancelNone: + case ECancelClosing: + break; + + default: + User::Panic(KProtocolModulePanic, EProtocolModuleCancelSource); + break; + }; + + // Cancel the machine + CancelMachine(aCancelSource); + } + + +/** Set state machine as queued. +This is called by individual derived state machines when they need +to enter into a queued state. +*/ +void CStateMachineBase::SetMachineAsQueued() + { + iIsMachineQueued = ETrue; + } + + +/** Set state machine as queued. +This is called by individual derived state machines when they need +to enter into a queued state. +*/ +TBool CStateMachineBase::IsMachineQueued() const + { + return iIsMachineQueued; + } + + +/** Check for a queued request. +Determine if there is a queued request and, if so, handle it. +*/ +void CStateMachineBase::CheckForQueuedRequest() + { + // Check for a pending request + if (!IsActive() && iQueue->IsRequestPending()) + { + // Perform the required action + DoQueuedRequest(iQueue->PopRequest()); + } + } + + +/** Active object completion handler +*/ +void CStateMachineBase::RunL() + { + // Check we have completed ok + if (KErrNone == iStatus.Int()) + { + // Which stage of the transition is this? + switch (iTransitionState) + { + + // About to exit from a state + case ETransitionExit: + // Prepare state machine prior to the transition. + PreStateTransition(); + + // Exit current state. + ExitCurrentState(); + + // Do transition to next stage + iTransitionState = ETransitionEnter; + DoStateTransitionStage(); + break; + + // About to enter a state + case ETransitionEnter: + // Reset transition state value + iTransitionState = ETransitionNull; + + // Perform state machine transition. + StateTransition(); + + // Enter new state. + EnterNewState(); + + // If an assistance data action is required then do it now. + // Note: Deferred until first measurement & control is handled. + if (iAssistanceDataActionRequired) + { + iAssistanceDataActionRequired = EFalse; + iObserver.DoAssistanceDataActions(); + } + + // Perform state machine post-transition actions + // Note: This may initiate another state transition + PostStateTransition(); + + // If the state machine is not active then we can see if there + // are any queued requests to be handled + if (!IsActive()) + { + CheckForQueuedRequest(); + } + break; + + // Not changing state just performing asynchronous activities + case ETransitionNull: + default: + // If an assistance data action is required then do it now. + if (iAssistanceDataActionRequired) + { + iAssistanceDataActionRequired = EFalse; + iObserver.DoAssistanceDataActions(); + } + break; + }; + + } + + } + + +/** Active object cancellation handler +*/ +void CStateMachineBase::DoCancel() + { + iStatus = KErrCancel; + } + + +/** Handle Network Measurement Control indication +A measurement control indication has been received and the associated content +must be stored. Note: At this stage the assistance data has already been handled +by the protocol manager and is thus not passed into this method. + +@param aPosInfo The network reference location +@param aQuality The location request quality +@param aMethod Positioning method to adopt +*/ +void CStateMachineBase::MeasurementControlInd(const TPositionInfoBase& aPosInfo, + const TLbsNetPosRequestQuality& aQuality, + const TLbsNetPosRequestMethod& aPosMethod) + { + // Ensure assistance data action is performed when appropriate + iAssistanceDataActionRequired = ETrue; + + // Store ref location and location request criteria + StoreRefLoc(aPosInfo); + StoreLocReqQuality(aQuality); + StorePosMethod(aPosMethod); + + iIsLocReqReceived = ETrue; + iIsMeasureControlHandled = EFalse; + } + + +/** Handle LBS request for additional Assistance Data +This is called by the protocol manager during an active procedure when +a request has been made by LBS for further assistance data. +*/ +void CStateMachineBase::AssistanceDataReq() + { + // Ensure assistance data action is performed when appropriate + iAssistanceDataActionRequired = ETrue; + iIsAdditionalDataExpected = ETrue; + + // If not already active then we must get the state machine to + // perform asynchronous assistance data actions + if (!IsActive()) + { + DoStateTransitionStage(); + } + } + + +/** Handle Network Additional Assistance data indication +This is called by the protocol manager during an active procedure when +an additional assistance data response is received from the network. +*/ +void CStateMachineBase::AdditionalAssistDataInd() + { + // Stop the related timer + iAssistDataTimer->Cancel(); + + // Ensure assistance data action is performed when appropriate + iAssistanceDataActionRequired = ETrue; + iIsAdditionalDataExpected = EFalse; + + // If not already active then we must get the state machine to + // perform asynchronous assistance data actions + if (!IsActive()) + { + DoStateTransitionStage(); + } + } + + +/** Handle Network Measurement Control Error indication +This is called by the protocol manager during an active procedure when +a measurement control error is received from the network. +@param aCancelRequired Indicates if the derived state machine requires + the state machine to be cancelled as a result of this error. +*/ +void CStateMachineBase::HandleMeasureControlError( + const TBool& aCancelRequired, TInt aReason) + { + // Stop the related timer + iAssistDataTimer->Cancel(); + + // Ensure assistance data action is performed + iAssistanceDataActionRequired = ETrue; + + // Do we have to cancel the state machine? + if (aCancelRequired) + { + iIsMeasureControlHandled = ETrue; + CancelMachine(ECancelNetworkCancel, aReason); + } + else + { + // If not already active then we must get the state machine to + // perform asynchronous assistance data actions + if (!IsActive()) + { + DoStateTransitionStage(); + } + } + } + + +/** Network Measurement Control Error indication +This implements the default actions to be taken if a derived class +does not override this method. +@param aReason The reason for network error +*/ +void CStateMachineBase::MeasurementControlErrorInd(TInt aReason) + { + HandleMeasureControlError(EFalse, aReason); + } + + +/** Handle a network error indication. +*/ +void CStateMachineBase::NetworkErrorInd() + { + // Only handle this the first time + if (ECancelNetworkError != iCancelSource) + { + // Ensure assistance data actions are performed + if (iIsAdditionalDataExpected) + { + iAssistanceDataActionRequired = ETrue; + iIsAdditionalDataExpected = EFalse; + } + // Cancel state machine + CancelMachine(ECancelNetworkError); + } + } + + +//----------------------------------------------------------------------------- +// State Machine Request Queue Class +//----------------------------------------------------------------------------- + +/** Static constructor +@param aMaxEntries Maximum requests to be held in the queue. +@return A new instance of the CStateQueue class. +*/ +CStateQueue* CStateQueue::NewL(TInt aMaxEntries) + { + CStateQueue* self = new (ELeave) CStateQueue(aMaxEntries); + CleanupStack::PushL(self); + self->ConstructL(aMaxEntries); + CleanupStack::Pop(self); + return self; + } + + +/** Default private constructor +@param aMaxEntries Maximum requests to be held in the queue. +*/ +CStateQueue::CStateQueue(TInt aMaxEntries) + : iMaxEntries(aMaxEntries) + { + } + + +/** Destructor +*/ +CStateQueue::~CStateQueue() + { + iQueue.Reset(); + } + + +/** Private second stage constructor +@param aMaxEntries Maximum requests to be held in the queue. +*/ +void CStateQueue::ConstructL(TInt aMaxEntries) + { + iQueue.ReserveL(aMaxEntries); + } + + +/** Check if there is a pending request +@return TBool ETrue if there is a pending request in the queue +*/ +TBool CStateQueue::IsRequestPending() + { + return (0 < iQueue.Count()) ? ETrue : EFalse; + } + + +/** Add a request to the queue +The new request is inserted at the start of the internal array +because this makes it easier to pop the oldest request out of +the array, @see CStateQueue::PopRequest() +@param aNewRequest A number identifying the request to be queued. +@return TInt KErrNone if there is no error queueing the request. +*/ +TInt CStateQueue::AddRequest(TInt aNewRequest) + { + TInt err = KErrOverflow; + if (iMaxEntries > iQueue.Count()) + { + TRAP(err, iQueue.InsertL(aNewRequest, 0)); + } + + return err; + } + + +/** Pop the oldest request off the queue +The entry at the end of the array represents the oldest queued request. +@return TInt The number identifying the popped request +*/ +TInt CStateQueue::PopRequest() + { + TInt request = 0; + if (0 < iQueue.Count()) + { + request = iQueue[iQueue.Count() - 1]; + iQueue.Remove(iQueue.Count() - 1); + } + + return request; + } +