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