diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanldd/wlan_common/umac_common/src/umacdot11pwrmgmttransitionmode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanldd/wlan_common/umac_common/src/umacdot11pwrmgmttransitionmode.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,677 @@ +/* +* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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: Implementation of the WlanDot11PwrMgmtTransitionMode class. +* +*/ + +/* +* %version: 22 % +*/ + +#include "config.h" +#include "umacdot11pwrmgmttransitionmode.h" +#include "UmacContextImpl.h" +#include "UmacWsaSetPsMode.h" +#include "UmacWsaWriteMib.h" + +#ifndef NDEBUG +const TInt8 WlanDot11PwrMgmtTransitionMode::iName[] + = "dot11-pwrmgmttransitionmode"; + +const TUint8 WlanDot11PwrMgmtTransitionMode::iStateName + [ESTATEMAX][KMaxStateStringLength] = + { + {"EINIT"}, + {"ESETAWAKEMODE"}, + {"ESETWAKEUPINTERVAL"}, + {"ESETPSMODE"}, + {"EWAIT4PWRMGMTTRANSITCOMPLETE"}, + {"ECONTINUEDOT11TRAVERSE"} + }; + +const TUint8 WlanDot11PwrMgmtTransitionMode::iEventName + [EEVENTMAX][KMaxEventStringLength] = + { + {"ESTATEENTRY"}, + {"ETXCOMPLETE"}, + {"EPWRMGMTTRANSITCOMPLETE"}, + {"EABORT"} + }; +#endif + +// this flag is set if we only need to set the wakeup interval. +const TUint32 KOnlySetWakeupInterval = ( 1 << 0 ); +// this flag is set if the status of the latest Set Ps Mode cmd was Success +const TUint32 KSetPsModeSuccess = ( 1 << 1 ); + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// The internal state transition method. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::ChangeInternalState( + WlanContextImpl& aCtxImpl, + TState aNewState ) + { + iState = aNewState; + Fsm( aCtxImpl, ESTATEENTRY ); + } + +// ----------------------------------------------------------------------------- +// The event dispatcher method. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::Fsm( + WlanContextImpl& aCtxImpl, + TEvent aEvent ) + { + OsTracePrint( KPwrStateTransition, + (TUint8*)("UMAC * dot11-pwrmgmttransitionmode * FSM EVENT") ); +#ifndef NDEBUG + OsTracePrint( KPwrStateTransition, (TUint8*)("event:")); + OsTracePrint( KPwrStateTransition, iEventName[aEvent] ); + OsTracePrint( KPwrStateTransition, (TUint8*)("state:")); + OsTracePrint( KPwrStateTransition, iStateName[iState] ); +#endif + + switch ( aEvent ) + { + case ESTATEENTRY: + OnStateEntryEvent( aCtxImpl ); + break; + case ETXCOMPLETE: + OnTxCompleteEvent( aCtxImpl ); + break; + case EPWRMGMTTRANSITCOMPLETE: + OnPwrMgmtTransitCompleteEvent( aCtxImpl ); + break; + case EABORT: + OnAbortEvent( aCtxImpl ); + break; + default: + // catch internal FSM programming error +#ifndef NDEBUG + OsTracePrint( KErrorLevel, (TUint8*)("event:")); + OsTracePrint( KErrorLevel, iEventName[aEvent] ); +#endif + OsAssert( (TUint8*)("* UMAC * panic"), + (TUint8*)(WLAN_FILE), __LINE__ ); + break; + } + } + +// ----------------------------------------------------------------------------- +// Handler for the event. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::OnStateEntryEvent( + WlanContextImpl& aCtxImpl ) + { + TState state( ESTATEMAX ); + + switch ( iState ) + { + case EINIT: + iFlags = 0; + // start of fsm traversal + // disable oid request so we run this fsm in non pre-emptive mode + // regarding oid commands + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC * dot11-pwrmgmttransitionmode * disable oid events") ); + + aCtxImpl.Disable( WlanEventDispatcher::KOidChannel ); + + if (// PS mode desired + aCtxImpl.DesiredDot11PwrMgmtMode() == WHA::KPsEnable + && // AND + // current mode is CAM + aCtxImpl.CurrentDot11PwrMgmtMode() == WHA::KPsDisable ) + { + // change to dot11 PS mode + // start by setting the wakeup interval + state = ESETWAKEUPINTERVAL; + } + else if (// CAM mode desired + aCtxImpl.DesiredDot11PwrMgmtMode() == WHA::KPsDisable + && // AND + // current mode is PS mode + aCtxImpl.CurrentDot11PwrMgmtMode() == WHA::KPsEnable ) + { + // change to dot11 CAM mode + state = ESETAWAKEMODE; + } + else + { + // we have a dot11 power management mode match. + // We can land here e.g. if user changes desired + // dot11 power management mode when we are excuting this fsm + // as we dispacth an oid as the fsm entry action. + // We can come here also when only the wakeup interval needs + // to be changed + + // if the current mode is PS mode we have to make sure + // that we have a wakeup interval match + if ( aCtxImpl.CurrentDot11PwrMgmtMode() == WHA::KPsEnable ) + { + // the way to do that is by re-setting (only) the wakeup + // interval - if necessary + iFlags |= KOnlySetWakeupInterval; + state = ESETWAKEUPINTERVAL; + } + else + { + // the current mode is CAM, so the wakeup interval is + // not relevant; and we are done + state = ECONTINUEDOT11TRAVERSE; + } + } + + ChangeInternalState( aCtxImpl, state ); + break; + case ESETAWAKEMODE: + ActivateDot11AwakeMode( aCtxImpl ); + break; + case ESETWAKEUPINTERVAL: + { + // first check if the wake-up setting already is what it should be. + // if that's the case, we won't set it again + + if ( DifferenceInPsModeWakeupSettings( aCtxImpl ) ) + { + // it's not what it needs to be, so set it + SetWakeUpInterval( aCtxImpl ); + } + else + { + // the wake-up setting is already correct, skip setting it again + // and simulate ETXCOMPLETE event instead + Fsm( aCtxImpl, ETXCOMPLETE ); + } + break; + } + case ESETPSMODE: + ActivateDot11PsMode( aCtxImpl ); + break; + case EWAIT4PWRMGMTTRANSITCOMPLETE: + // nothing to do here than just wait for completion + break; + case ECONTINUEDOT11TRAVERSE: + ContinueDot11StateTraversal( aCtxImpl ); + break; + default: + // catch internal FSM programming error +#ifndef NDEBUG + OsTracePrint( KErrorLevel, (TUint8*)("state:")); + OsTracePrint( KErrorLevel, iStateName[iState] ); +#endif + OsAssert( (TUint8*)("* UMAC * panic"), + (TUint8*)(WLAN_FILE), __LINE__ ); + break; + } + } + +// ----------------------------------------------------------------------------- +// Handler for the event. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::OnTxCompleteEvent( + WlanContextImpl& aCtxImpl ) + { + switch ( iState ) + { + case ESETAWAKEMODE: + case ESETPSMODE: + // as transition has sterted now we just wait for it to complete + ChangeInternalState( aCtxImpl, EWAIT4PWRMGMTTRANSITCOMPLETE ); + break; + case ESETWAKEUPINTERVAL: + if ( iFlags & KOnlySetWakeupInterval ) + { + // we only needed to set the wakeup interval. So we are + // done now + ChangeInternalState( aCtxImpl, ECONTINUEDOT11TRAVERSE ); + } + else + { + // we also need to set the PS mode. This is the most common case + ChangeInternalState( aCtxImpl, ESETPSMODE ); + } + break; + case EWAIT4PWRMGMTTRANSITCOMPLETE: + // a re-entry to this state has occurred while waiting for the + // CommandComplete event to the SetPsMode cmd. + // This will happen when we autonomously issue a (new) WHA cmd - + // during the above mentioned wait period - to react to a change + // which has occurred in the network (e.g. in the Use Protection + // setting or in the QoS parameters). + // Anyhow, no action is required here (except to allow for this + // re-entry to happen) + break; + default: + // catch internal FSM programming error +#ifndef NDEBUG + OsTracePrint( KErrorLevel, (TUint8*)("state:")); + OsTracePrint( KErrorLevel, iStateName[iState] ); +#endif + OsAssert( (TUint8*)("* UMAC * panic"), + (TUint8*)(WLAN_FILE), __LINE__ ); + break; + } + } + +// ----------------------------------------------------------------------------- +// Handler for the event. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::OnPwrMgmtTransitCompleteEvent( + WlanContextImpl& aCtxImpl ) + { + // we can continue dot11 state traversal + ChangeInternalState( aCtxImpl, ECONTINUEDOT11TRAVERSE ); + } + +// --------------------------------------------------------- +// simulate macnotresponding error +// --------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::OnAbortEvent( + WlanContextImpl& aCtxImpl ) + { + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC * dot11-pwrmgmttransitionmode * abort") ); + + DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + +// ----------------------------------------------------------------------------- +// Handler for the event. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::ActivateDot11AwakeMode( + WlanContextImpl& aCtxImpl ) + { + WlanWsaSetPsMode& wha_cmd( aCtxImpl.WsaSetPsMode() ); + wha_cmd.Set( aCtxImpl, WHA::KPsDisable ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd // next state + ); + } + +// ----------------------------------------------------------------------------- +// Handler for the event. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::SetWakeUpInterval( + WlanContextImpl& aCtxImpl ) + { + WHA::SwlanWakeUpInterval* mib + = static_cast + (os_alloc( sizeof( WHA::SwlanWakeUpInterval ) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11PwrMgmtTransitionMode::SetWakeUpInterval: alloc failed, abort") ); + Fsm( aCtxImpl, EABORT ); + return; + } + + // determine the desired new wake-up setting + const TDot11PsModeWakeupSetting KDesiredPsModeConfig ( + aCtxImpl.DesiredPsModeConfig() ); + + // take it into use + + mib->iMode = KDesiredPsModeConfig.iWakeupMode; + mib->iListenInterval = KDesiredPsModeConfig.iListenInterval; + + WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib(); + + wha_cmd.Set( + aCtxImpl, WHA::KMibWlanWakeUpInterval, sizeof(*mib), mib ); + + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC: UMAC: WlanDot11PwrMgmtTransitionMode::SetWakeUpInterval: desired mode: %d"), + mib->iMode ); + OsTracePrint( KPwrStateTransition, + (TUint8*)("UMAC: desired listeninterval: %d"), mib->iListenInterval ); + + // store the new setting also locally + aCtxImpl.iWlanMib.iWlanWakeupInterval = mib->iMode; + aCtxImpl.iWlanMib.iWlanListenInterval = mib->iListenInterval; + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd // next state + ); + + // as the parameters have been supplied we can now deallocate + os_free( mib ); + } + +// ----------------------------------------------------------------------------- +// Handler for the event. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::ActivateDot11PsMode( + WlanContextImpl& aCtxImpl ) + { + WlanWsaSetPsMode& wha_cmd( aCtxImpl.WsaSetPsMode() ); + wha_cmd.Set( aCtxImpl, WHA::KPsEnable ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd // next state + ); + } + +// ----------------------------------------------------------------------------- +// Handler for the event. +// It is guaranteed by the FSM framework that no WHA command is pending +// when this method is entered +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::ContinueDot11StateTraversal( + WlanContextImpl& aCtxImpl ) + { + if ( !( iFlags & KOnlySetWakeupInterval ) ) + { + // we have tried to change the power mgmt mode with SetPsMode + // WHA command + + if ( iFlags & KSetPsModeSuccess ) + { + // the Set PS Mode WHA cmd was successfully executed, which means + // that we were able to communicate with the AP. + // So we can indicate BSS Regained; if necessary + DoRegainedBSSIndication( aCtxImpl ); + } + else + { + if ( !aCtxImpl.SetPsModeCount() ) + { + // the set power mgmt mode counter has counted down to zero, so + // we will indicate Consecutive Power Mode Set Failures (unless + // already indicated) to WLAN Mgmt Client + DoConsecutivePwrModeSetFailuresIndication( aCtxImpl ); + // reset the counter + aCtxImpl.SetPsModeCount(); + // it's possible that we come to this branch again shortly, + // but it really doesn't matter. In any case we will indicate + // Consecutive Power Mode Set Failures only once at maximum + } + else + { + // we have made one (more) unsuccessful attempt to set the power + // mgmt mode, so decrement the counter by one + aCtxImpl.DecrementSetPsModeCount(); + } + } + } + + TBool dot11PwrMgmtTransitComplete ( EFalse ); + const WHA::TPsMode KCurrentPwrMgmtMode( + aCtxImpl.CurrentDot11PwrMgmtMode() ); + + if ( KCurrentPwrMgmtMode == aCtxImpl.DesiredDot11PwrMgmtMode() ) + { + // current dot11 power management mode equals to desired mode + + if ( KCurrentPwrMgmtMode == WHA::KPsEnable ) + { + // as the current and desired mode is PS, we are only done + // if also the wakeup settings are as desired + if ( !DifferenceInPsModeWakeupSettings( aCtxImpl ) ) + { + dot11PwrMgmtTransitComplete = ETrue; + } + else + { + OsTracePrint( KPwrStateTransition, + (TUint8*)("UMAC: wakeup settings not as desired") ); + } + } + else + { + // as the current and desired mode is CAM, we are done + dot11PwrMgmtTransitComplete = ETrue; + } + } + else + { + // current dot11 power management mode does not equal to desired mode. + // Se we are not done and will need to try to do the mode change again. + // No action here. + } + + if ( dot11PwrMgmtTransitComplete ) + { + // desired dot11 power management mode - and settings if the desired + // mode is PS - have been acquired + + ChangeState( aCtxImpl, + *this, // prev state + aCtxImpl.iStates.iInfrastructureNormalMode ); // next state + + if ( aCtxImpl.CurrentDot11PwrMgmtMode() == WHA::KPsEnable ) + { + // as we have entered PS mode, it is time to resume QoS null + // data frame sending, if applicable + aCtxImpl.ResumeQosNullSending(); + } + } + else + { + // dot11 power management mode/settings are not as desired, yet. + // We shall repeat this process + + ChangeState( aCtxImpl, + *this, // prev state + *this // next state + ); + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::Entry( + WlanContextImpl& aCtxImpl ) + { + if ( aCtxImpl.WsaCmdActive() ) + { + // sanity checking code + OsAssert( + (TUint8*)("UMAC * panic"), (TUint8*)(WLAN_FILE), __LINE__ ); + } + + if ( !(aCtxImpl.DispatchEvent()) ) + { + // no state transition occurred + // dispatcher might or might not have had an event to be dispatched + // in any case we are still in the current state and can continue... + if ( iState != EINIT ) + { + // this is NOT the start of the the FSM actions + // note that we send the ETXCOMPLETE event as the states + // that wait for it are the only ones that can be interrupted + // as they are asynchronous operations by nature + // and wait for corresponding WHA completion method + Fsm( aCtxImpl, ETXCOMPLETE ); + } + else + { + // this is the start of the the FSM actions + Fsm( aCtxImpl, ESTATEENTRY ); + } + } + else // --- !(aCtxImpl.DispatchEvent()) + { + // state transition occurred + // we are no longer in the current state, + // so we won't do anything as we might mess things up + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11PwrMgmtTransitionMode::Exit( + WlanContextImpl& aCtxImpl) + { + // reset fsm + iState = EINIT; + + // enable oid requests as we are exiting this dot11 state + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC * dot11-pwrmgmttransitionmode * enable oid events") ); + + aCtxImpl.Enable( WlanEventDispatcher::KOidChannel ); + } + +#ifndef NDEBUG +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +const TInt8* WlanDot11PwrMgmtTransitionMode::GetStateName( + TUint8& aLength ) const + { + aLength = sizeof( iName ); + return iName; + } +#endif + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11PwrMgmtTransitionMode::CommandComplete( + WlanContextImpl& aCtxImpl, + WHA::TCompleteCommandId aCompleteCommandId, + WHA::TStatus aStatus, + const WHA::UCommandCompletionParams& + aCommandCompletionParams ) + { + if ( aCompleteCommandId != WHA::ESetPsModeComplete ) + { + // implementation error + OsTracePrint( KErrorLevel, (TUint8*)("UMAC: command id: %d"), aCompleteCommandId); + OsAssert( (TUint8*)("UMAC panic"), (TUint8*)(WLAN_FILE), __LINE__ ); + } + + OsTracePrint( KPwrStateTransition, + (TUint8*)("UMAC: WlanDot11PwrMgmtTransitionMode::CommandComplete")); + + const WHA::TPsMode KCurrentPwrMgmtMode( + aCommandCompletionParams.iSetPsModeComplete.iDot11PowerManagementMode ); + aCtxImpl.CurrentDot11PwrMgmtMode( KCurrentPwrMgmtMode ); + + // make a note whether the SetPsMode WHA command was executed successfully + // or not + if ( aStatus == WHA::KSuccess ) + { + iFlags |= KSetPsModeSuccess; + + OsTracePrint( KPwrStateTransition, + (TUint8*)("UMAC: transition success: current mode: %d"), + KCurrentPwrMgmtMode); + } + else + { + iFlags &= ~KSetPsModeSuccess; + + OsTracePrint( KWarningLevel | KPwrStateTransition, + (TUint8*)("UMAC: transition failure: current mode: %d"), + KCurrentPwrMgmtMode); + } + + // continue fsm + Fsm( aCtxImpl, EPWRMGMTTRANSITCOMPLETE ); + + // signal global state transition + return ETrue; + } + +// ----------------------------------------------------------------------------- +// as oid reception is disbaled in this dot11 state, reception of this oid +// is a result of a manual oid dispatching +// ----------------------------------------------------------------------------- +// +TBool WlanDot11PwrMgmtTransitionMode::SetPowerMode( + WlanContextImpl& aCtxImpl, + TPowerMode aPowerMode, + TBool aDisableDynamicPowerModeManagement, + TWlanWakeUpInterval aWakeupModeInLightPs, + TUint8 aListenIntervalInLightPs, + TWlanWakeUpInterval aWakeupModeInDeepPs, + TUint8 aListenIntervalInDeepPs ) + { + OsTracePrint( KPwrStateTransition, + (TUint8*)("UMAC: WlanDot11PwrMgmtTransitionMode::SetPowerMode: desired power mode: %d"), + aPowerMode ); + + // store desired new dot11 power management mode by WLAN Mgmt Client + aCtxImpl.ClientDot11PwrMgmtMode( aPowerMode ); + + aCtxImpl.DynamicPwrModeMgtDisabled( aDisableDynamicPowerModeManagement ); + + // it is now also our desired dot11 power management mode + aCtxImpl.DesiredDot11PwrMgmtMode( aCtxImpl.ClientDot11PwrMgmtMode() ); + + aCtxImpl.SetClientLightPsModeConfig( + aWakeupModeInLightPs, + aListenIntervalInLightPs ); + + aCtxImpl.SetClientDeepPsModeConfig( + aWakeupModeInDeepPs, + aListenIntervalInDeepPs ); + + // in case WLAN Mgmt Client wishes to use PS mode, Light PS is the initial + // desired PS mode configuration + aCtxImpl.SetDesiredPsModeConfig( + aCtxImpl.ClientLightPsModeConfig() ); + + // complete the mgmt command + OnOidComplete( aCtxImpl ); + + // signal that no state transition occurred + return EFalse; + }