diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanldd/wlan_common/umac_common/src/umacnullsendcontroller.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanldd/wlan_common/umac_common/src/umacnullsendcontroller.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,608 @@ +/* +* Copyright (c) 2007-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 WlanNullSendController class +* +*/ + +/* +* %version: 15 % +*/ + +#include "config.h" +#include "umacnullsendcontroller.h" +#include "umacnullsender.h" +#include "UmacContextImpl.h" + + +// ================= MEMBER FUNCTIONS ======================= + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::StartVoiceOverWlanCallMaintenance() + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::StartVoiceOverWlanCallMaintenance") ); + + iFlags |= KVoiceOverWlanCallMaintenanceStarted; + + if ( iFlags & KInVoiceCallState ) + { + RegisterNoVoiceTimeout( iNoVoiceTimeout ); + + if ( ( iWlanContextImpl.UapsdUsedForVoice() ) && + ( iWlanContextImpl.CurrentDot11PwrMgmtMode() == + WHA::KPsEnable ) ) + { + // U-APSD is used for Voice and we are also in PS mode, + // so initiate QoS Null Frame sending by arming the timer + RegisterNullTimeout( iNullTimeout ); + } + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::ResumeQosNullSending() + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::ResumeQosNullSending") ); + + if ( ( iWlanContextImpl.UapsdUsedForVoice() )&& + ( iFlags & KInVoiceCallState ) && + ( iWlanContextImpl.CurrentDot11PwrMgmtMode() == WHA::KPsEnable ) ) + { + // U-APSD is used for Voice, we are in Voice Call state and in PS + // mode, so resume QoS null frame sending by re-arming the timer + RegisterNullTimeout( iNullTimeout ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::OnFrameRx( + WHA::TQueueId aQueueId, + TUint aPayloadLength ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnFrameRx entry: iFlags: 0x%08x"), + iFlags ); + + if ( iFlags & KVoiceOverWlanCallMaintenanceStarted ) + { + if ( iFlags & KInVoiceCallState ) + { + // we are already in Voice Call state + + const TInt64 KTimeNow( os_systemTime() ); + + if ( aQueueId == WHA::EVoice ) + { + // and this is a Voice priority frame. + + iLatestVoiceRxOrTxInVoiceCallState = KTimeNow; + } + else if ( ( aQueueId == WHA::ELegacy ) && + ( aPayloadLength < + iBestEffortVoiceRxLengthThreshold ) ) + { + iBestEffortVoiceRxTimeStamp[iBestEffortVoiceRxInd] = KTimeNow; + iBestEffortVoiceRxInd = + ( iBestEffortVoiceRxInd == + KBestEffortVoiceRxTimeStampCnt - 1 ) ? 0 : + ++iBestEffortVoiceRxInd; + } + else + { + // no action + } + } + else if ( iFlags & KVoiceCallEntryPending ) + { + // we are in Voice Call Entry Pending state + + if ( aQueueId == WHA::EVoice ) + { + // this is a Voice priority frame + + ++iVoiceCallEntryRxCount; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnFrameRx: iVoiceCallEntryRxCount is now: %d"), + iVoiceCallEntryRxCount ); + + if ( iVoiceCallEntryRxCount >= iVoiceCallEntryThreshold ) + { + // We will enter the Voice Call state + EnterVoiceCallState(); + } + } + } + else + { + // we are neither in Voice Call Entry Pending nor Voice Call state + + if ( aQueueId == WHA::EVoice ) + { + // this is a Voice priority frame. + + // It is the 1st Voice priority frame in the period starting + // now + iVoiceCallEntryRxCount = 1; + iVoiceCallEntryTxCount = 0; + + // We enter the Voice Call Entry Pending state by arming + // the relevant timer + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnFrameRx: Enter Voice Call Entry pending state") ); + + RegisterVoiceCallEntryTimeout(); + } + } + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::OnFrameTx( WHA::TQueueId aQueueId ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnFrameTx entry: iFlags: 0x%08x"), + iFlags ); + + iLatestTx = os_systemTime(); + + if ( iFlags & KVoiceOverWlanCallMaintenanceStarted ) + { + if ( iFlags & KInVoiceCallState ) + { + // we are already in Voice Call state + + if ( aQueueId == WHA::EVoice ) + { + // and this is a Voice priority frame. + + iLatestVoiceRxOrTxInVoiceCallState = iLatestTx; + } + } + else if ( iFlags & KVoiceCallEntryPending ) + { + // we are in Voice Call Entry Pending state + + if ( aQueueId == WHA::EVoice ) + { + // this is a Voice priority frame + + ++iVoiceCallEntryTxCount; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnFrameTx: iVoiceCallEntryTxCount is now: %d"), + iVoiceCallEntryTxCount ); + + if ( iVoiceCallEntryTxCount >= iVoiceCallEntryThreshold ) + { + // We will enter the Voice Call state + EnterVoiceCallState(); + } + } + } + else + { + // we are neither in Voice Call Entry Pending nor Voice Call state + + if ( aQueueId == WHA::EVoice ) + { + // this is a Voice priority frame. + + // It is the 1st Voice priority frame in the period starting + // now + iVoiceCallEntryTxCount = 1; + iVoiceCallEntryRxCount = 0; + + // We enter the Voice Call Entry Pending state by arming + // the relevant timer + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnFrameTx: Enter Voice Call Entry pending state") ); + + RegisterVoiceCallEntryTimeout(); + } + } + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::OnVoiceCallEntryTimerTimeout() + { + // as this timer expired we are no more in Voice Call Entry Pending state + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnVoiceCallEntryTimerTimeout: exit entry pending (to idle) state") ); + + iFlags &= ~KVoiceCallEntryPending; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::OnNullTimerTimeout() + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnNullTimerTimeout") ); + + iFlags &= ~KNullTimerArmed; + + if ( iWlanContextImpl.CurrentDot11PwrMgmtMode() == WHA::KPsEnable ) + { + // we are still in PS mode (as we were when this timer was + // armed) + + TUint32 KTimeAfterLatestTx ( + static_cast(os_systemTime() - iLatestTx) ); + + if ( KTimeAfterLatestTx >= iNullTimeout ) + { + // request a QoS Null Data frame to be sent. + // However, if there is a frame Tx (of any frame) already pending, + // we won't request a new frame to be sent. Note that it can really + // be any frame, i.e. for any AC, as we currently always set all the + // ACs as trigger enabled if U-APSD is used + if ( !iWlanContextImpl.UnsentTxPackets() ) + { + if ( !iNullSender.TxNullDataFrame( iWlanContextImpl, ETrue ) ) + { + // frame was not sent because we didn't get a Tx buffer. + // In this case we'll skip the sending + // However, we need to re-arm the timer to trigger the next + // QoS Null Data frame sending + RegisterNullTimeout( iNullTimeout ); + } + } + else + { + // frame Tx already pending, so we don't ask a QoS Null to be sent + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnNullTimerTimeout: frame Tx already pending. New QoS Null Tx request skipped") ); + + // However, we need to re-arm the timer to trigger the next + // QoS Null Data frame sending + RegisterNullTimeout( iNullTimeout ); + } + } + else + { + // No need to send QoS Null; yet. Re-arm the timer with + // a suitable timeout relative to the time of the latest Tx + // in QoS Null frame sending state + RegisterNullTimeout( iNullTimeout - KTimeAfterLatestTx ); + } + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::OnQosNullDataTxCompleted() + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnQosNullDataTxCompleted entry: iFlags: 0x%08x"), + iFlags ); + + if ( iFlags & KVoiceOverWlanCallMaintenanceStarted && + iFlags & KInVoiceCallState && + iWlanContextImpl.CurrentDot11PwrMgmtMode() == WHA::KPsEnable ) + { + // we are doing Voice over WLAN Call maintenance, in Voice Call + // state and also in PS mode + + // as the previous QoS Null Data, i.e. U-APSD Trigger, Frame has been + // transmitted, re-arm the timer for the next round + RegisterNullTimeout( iNullTimeout ); + } + + iLatestTx = os_systemTime(); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::OnNoVoiceTimerTimeout() + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnNoVoiceTimerTimeout entry: iFlags: 0x%08x"), + iFlags ); + + iFlags &= ~KNoVoiceTimerArmed; + const TInt64 KTimeNow( os_systemTime() ); + const TUint32 KTimeAfterLatestVoiceRxOrTxInVoiceCallState ( + static_cast(KTimeNow - + iLatestVoiceRxOrTxInVoiceCallState) ); + + if ( KTimeAfterLatestVoiceRxOrTxInVoiceCallState >= iNoVoiceTimeout ) + { + // no real Voice priority traffic any more. + + // check if there still is traffic which may be Voice traffic + // erroneously tagged as Best Effort priority + if ( KTimeNow - + // the oldest time stamp of these frames that we have in our + // records - or zero if such a time stamp doesn't exist + iBestEffortVoiceRxTimeStamp[iBestEffortVoiceRxInd] > + iBestEffortVoiceRxTimeWindow ) + { + // exit Voice Call state + iFlags &= ~KInVoiceCallState; + + // Send voice call state change indication to engine + iWlanContextImpl.iUmac.OnInDicationEvent( EVoiceCallOff ); + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnNoVoiceTimerTimeout: Exit Voice Call state") ); + + // stop the possibly ongoing Null frame sending by canceling the + // Null timer + CancelNullTimeout(); + } + else + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnNoVoiceTimerTimeout: Continue in Voice Call state") ); + + RegisterNoVoiceTimeout( iNoVoiceTimeout ); + } + } + else + { + // don't exit Voice Call state. Re-arm the timer instead with a + // suitable timeout relative to the latest Voice priority frame + // Rx or Tx in Voice Call state + RegisterNoVoiceTimeout( + iNoVoiceTimeout - KTimeAfterLatestVoiceRxOrTxInVoiceCallState ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::OnKeepAliveTimerTimeout() + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnKeepAliveTimerTimeout") ); + + iFlags &= ~KKeepAliveTimerArmed; + + TUint32 KTimeAfterLatestTx ( + static_cast(os_systemTime() - iLatestTx) ); + + if ( KTimeAfterLatestTx >= iKeepAliveTimeout ) + { + // request a regular Null Data frame to be sent + + // however, if there is a frame Tx (of any frame) already pending, + // we won't request a new frame to be sent. + if ( !iWlanContextImpl.UnsentTxPackets() ) + { + if ( !iNullSender.TxNullDataFrame( iWlanContextImpl, EFalse ) ) + { + // frame was not sent because we didn't get a Tx buffer. + // In this case we'll skip the sending + // However, we need to re-arm the timer to trigger the next + // Null Data frame sending + RegisterKeepAliveTimeout( iKeepAliveTimeout ); + } + } + else + { + // frame Tx already pending, so we don't ask a Null Data to be sent + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::OnKeepAliveTimerTimeout: frame Tx already pending. New Null Data Tx request skipped") ); + + // However, we need to re-arm the timer to trigger the next + // Null Data frame sending + RegisterKeepAliveTimeout( iKeepAliveTimeout ); + } + } + else + { + // No need to send keep alive; yet. Re-arm the timer with + // a suitable timeout relative to the time of the latest frame Tx + RegisterKeepAliveTimeout( iKeepAliveTimeout - KTimeAfterLatestTx ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::RegisterVoiceCallEntryTimeout() + { + CancelVoiceCallEntryTimeout(); + + iWlanContextImpl.iUmac.RegisterTimeout( + iVoiceCallEntryTimeout, + EWlanVoiceCallEntryTimer ); + + iFlags |= KVoiceCallEntryPending; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::RegisterVoiceCallEntryTimeout: timer armed") ); + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::RegisterNullTimeout( + TUint32 aTimeoutInMicroSeconds ) + { + CancelNullTimeout(); + + iWlanContextImpl.iUmac.RegisterTimeout( + aTimeoutInMicroSeconds, + EWlanNullTimer ); + + iFlags |= KNullTimerArmed; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::RegisterNullTimeout: timer armed") ); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::RegisterNoVoiceTimeout( + TUint32 aTimeoutInMicroSeconds ) + { + CancelNoVoiceTimeout(); + + iWlanContextImpl.iUmac.RegisterTimeout( aTimeoutInMicroSeconds, + EWlanNoVoiceTimer ); + iFlags |= KNoVoiceTimerArmed; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::RegisterNoVoiceTimeout: timer armed") ); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::RegisterKeepAliveTimeout( + TUint32 aTimeoutInMicroSeconds ) + { + CancelKeepAliveTimeout(); + + iWlanContextImpl.iUmac.RegisterTimeout( aTimeoutInMicroSeconds, + EWlanKeepAliveTimer ); + + iFlags |= KKeepAliveTimerArmed; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::RegisterKeepAliveTimeout: timer armed") ); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::CancelVoiceCallEntryTimeout() + { + if ( iFlags & KVoiceCallEntryPending ) + { + iWlanContextImpl.iUmac.CancelTimeout( EWlanVoiceCallEntryTimer ); + + iFlags &= ~KVoiceCallEntryPending; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::CancelVoiceCallEntryTimeout: timer cancelled") ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::CancelNullTimeout() + { + if ( iFlags & KNullTimerArmed ) + { + iWlanContextImpl.iUmac.CancelTimeout( EWlanNullTimer ); + + iFlags &= ~KNullTimerArmed; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::CancelNullTimeout: timer cancelled") ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::CancelNoVoiceTimeout() + { + if ( iFlags & KNoVoiceTimerArmed ) + { + iWlanContextImpl.iUmac.CancelTimeout( EWlanNoVoiceTimer ); + + iFlags &= ~KNoVoiceTimerArmed; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::CancelNoVoiceTimeout: timer cancelled") ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::CancelKeepAliveTimeout() + { + if ( iFlags & KKeepAliveTimerArmed ) + { + iWlanContextImpl.iUmac.CancelTimeout( EWlanKeepAliveTimer ); + + iFlags &= ~KKeepAliveTimerArmed; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::CancelKeepAliveTimeout: timer cancelled") ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanNullSendController::EnterVoiceCallState() + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanNullSendController::EnterVoiceCallState") ); + + CancelVoiceCallEntryTimeout(); + + iFlags |= KInVoiceCallState; + + // Send voice call state change indication to engine + iWlanContextImpl.iUmac.OnInDicationEvent( EVoiceCallOn ); + + // arm the No Voice timer so that we also exit the Voice Call + // state at some point + iLatestVoiceRxOrTxInVoiceCallState = os_systemTime(); + RegisterNoVoiceTimeout( iNoVoiceTimeout ); + + if ( ( iWlanContextImpl.UapsdUsedForVoice() ) && + ( iWlanContextImpl.CurrentDot11PwrMgmtMode() == WHA::KPsEnable ) ) + { + // U-APSD is used for Voice and we are also in PS mode, + // so initiate QoS Null Frame sending by arming the timer + RegisterNullTimeout( iNullTimeout ); + } + }