wlan_bearer/wlanldd/wlan_common/umac_common/src/UmacTxRateAdaptation.cpp
changeset 0 c40eb8fe8501
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanldd/wlan_common/umac_common/src/UmacTxRateAdaptation.cpp	Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,788 @@
+/*
+* Copyright (c) 2002-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 WlanTxRateAdaptation class
+*
+*/
+
+/*
+* %version: 21 %
+*/
+
+#include "config.h"
+#include "UmacTxRateAdaptation.h"
+#include "UmacContextImpl.h"
+#include "wha_mibDefaultvalues.h"
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+WlanTxRateAdaptation::WlanTxRateAdaptation()
+    {
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::WlanTxRateAdaptation()"));
+
+    // default values for the rate adaptation algorithm parameters
+    //
+    const TUint8 KDefaultMinStepUpCheckpoint        = 10;
+    const TUint8 KDefaultMaxStepUpCheckpoint        = 60;
+    const TUint8 KDefaultStepUpCheckpointFactor     = 2;
+    const TUint8 KDefaultStepDownCheckpoint         = 3;
+    const TUint8 KDefaultMinStepUpThreshold         = 70;
+    const TUint8 KDefaultMaxStepUpThreshold         = 90;
+    const TUint8 KDefaultStepUpThresholdIncrement   = 10;
+    const TUint8 KDefaultStepDownThreshold          = 50;  
+    
+    iAlgorithmParam.iMinStepUpCheckpoint =
+        KDefaultMinStepUpCheckpoint;
+
+    iAlgorithmParam.iMaxStepUpCheckpoint =
+        KDefaultMaxStepUpCheckpoint;
+
+    iAlgorithmParam.iStepUpCheckpointFactor =
+        KDefaultStepUpCheckpointFactor;
+
+    iAlgorithmParam.iStepDownCheckpoint =
+        KDefaultStepDownCheckpoint;
+
+    iAlgorithmParam.iMinStepUpThreshold = 
+        KDefaultMinStepUpThreshold;
+
+    iAlgorithmParam.iMaxStepUpThreshold = 
+        KDefaultMaxStepUpThreshold;
+
+    iAlgorithmParam.iStepUpThresholdIncrement = 
+        KDefaultStepUpThresholdIncrement;
+
+    iAlgorithmParam.iStepDownThreshold = 
+        KDefaultStepDownThreshold;
+        
+    iAlgorithmParam.iDisableProbeHandling = EFalse;
+
+    for ( TUint32 j = 0; j != WHA::EQueueIdMax; ++j )
+        {
+        // initially every Tx queue is mapped to the same (general) Tx
+        // policy
+        iQueue2Policy[j] = WHA::KDefaultTxRatePolicyId;
+        }
+
+    for ( TUint32 i = 0; i != KMaxRatePolicyCount; ++i )
+        {
+        iPolicy[i].iCurrentTxRate = NULL;
+        iPolicy[i].iHead = NULL;
+        iPolicy[i].iTail = NULL;
+        iPolicy[i].iNumOfRates = 0;
+        
+        iPolicy[i].iProbe = EFalse;
+        iPolicy[i].iTxCount = 0;
+        iPolicy[i].iTxFailCount = 0;
+        iPolicy[i].iStepUpCheckpoint = KDefaultMinStepUpCheckpoint;
+        iPolicy[i].iStepUpThreshold = KDefaultMinStepUpThreshold;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::RateStepDown( SPolicy& aPolicy ) const
+    {
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::RateStepDown(): old rate: 0x%08x"), 
+        aPolicy.iCurrentTxRate->iBitRate);
+
+    if ( aPolicy.iCurrentTxRate->iPrev )
+        {
+        // descent rate
+        aPolicy.iCurrentTxRate = aPolicy.iCurrentTxRate->iPrev;
+
+        OsTracePrint( KTxRateAdapt, 
+            (TUint8*)("UMAC: WlanTxRateAdaptation::RateStepDown(): new rate: 0x%08x"), 
+            aPolicy.iCurrentTxRate->iBitRate);
+        }
+    else
+        {
+        // we are already using the lowest rate
+        // nothing to do
+        OsTracePrint( KTxRateAdapt, (TUint8*)
+            ("UMAC: WlanTxRateAdaptation::RateStepDown(): already using the lowest rate") );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanTxRateAdaptation::RateStepUp( SPolicy& aPolicy ) const
+    {
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::RateStepUp(): old rate: 0x%08x"), 
+        aPolicy.iCurrentTxRate->iBitRate);
+
+    TBool status( ETrue );
+
+    if ( aPolicy.iCurrentTxRate->iNext )
+        {
+        // ascend rate
+        aPolicy.iCurrentTxRate = aPolicy.iCurrentTxRate->iNext;
+
+        OsTracePrint( KTxRateAdapt, 
+            (TUint8*)("UMAC: WlanTxRateAdaptation::RateStepUp(): new rate: 0x%08x"), 
+            aPolicy.iCurrentTxRate->iBitRate);
+        }
+    else
+        {
+        // we are already using the highest rate.
+        // Indicate that to the caller
+        status = EFalse;
+
+        OsTracePrint( KTxRateAdapt, (TUint8*)
+            ("UMAC: WlanTxRateAdaptation::RateStepUp(): already using the highest rate") );
+        }
+        
+    return status;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::InsertRate( 
+    TUint8 aPolicyIndex, SBitRate* aBlock ) const
+    {
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC:  WlanTxRateAdaptation::InsertRate(): aPolicyIndex: %d"), 
+        aPolicyIndex);
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC:  WlanTxRateAdaptation::InsertRate(): rate: 0x%08x"), 
+        aBlock->iBitRate);
+
+    // traverse our single linked list of rate entrys
+    // and locate the correct place for the new rate
+    SBitRate* ptr = iPolicy[aPolicyIndex].iHead;
+    SBitRate* prev = ptr;
+
+    do
+        {
+        if ( aBlock->iBitRate < ptr->iBitRate )
+            {
+            // rate to be inserted is smaller than 
+            // the "current" rate
+            break;
+            }
+
+        prev = ptr;
+        ptr = ptr->iNext;
+        } 
+        while ( ptr );
+    
+    if ( ptr )
+        {
+        // correct slot found
+        // link the new rate
+        prev->iNext = aBlock;
+        aBlock->iPrev = prev;
+        aBlock->iNext = ptr;
+        }    
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanTxRateAdaptation::AppendRate( 
+    TUint8 aPolicyIndex,
+    WHA::TRate aRate )
+    {
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC:  WlanTxRateAdaptation::AppendRate(): aPolicyIndex: %d"), 
+        aPolicyIndex);
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC:  WlanTxRateAdaptation::AppendRate(): rate: 0x%08x"), aRate);
+
+    // allocate a new block for the rate
+    SBitRate* block 
+        = static_cast<SBitRate*>(os_alloc( sizeof(SBitRate) ));
+
+    if ( !block )
+        {
+        // alloc failure; we cannot continue
+        OsTracePrint( KErrorLevel, 
+            (TUint8*)("UMAC: WlanTxRateAdaptation::AppendRate(): alloc failure"));        
+
+        return EFalse;
+        }
+
+    block->iBitRate = aRate;
+    block->iNext = NULL;
+    block->iPrev = NULL;
+
+    if ( !iPolicy[aPolicyIndex].iHead )
+        {
+        // this is the first append
+        
+        iPolicy[aPolicyIndex].iHead = block;
+        iPolicy[aPolicyIndex].iTail = iPolicy[aPolicyIndex].iHead;
+        iPolicy[aPolicyIndex].iCurrentTxRate = block;
+        ++iPolicy[aPolicyIndex].iNumOfRates;
+        }
+    else
+        {
+        // not the first rate to append
+        
+        if ( block->iBitRate > iPolicy[aPolicyIndex].iTail->iBitRate )
+            {
+            // new rate bigger than the last one
+            // append to rear
+            iPolicy[aPolicyIndex].iTail->iNext = block;
+            block->iPrev = iPolicy[aPolicyIndex].iTail;
+            // new tail
+            iPolicy[aPolicyIndex].iTail = block;
+            ++iPolicy[aPolicyIndex].iNumOfRates;
+            }
+        else if( block->iBitRate < iPolicy[aPolicyIndex].iTail->iBitRate )
+            {
+            // new rate smaller than the last one
+            // insert the rate to the correct slot
+            InsertRate( aPolicyIndex, block );
+            ++iPolicy[aPolicyIndex].iNumOfRates;
+            }
+        else
+            {
+            // new rate equal to the last one
+            // this cannot happen as we are setting the rates only once
+            // and from a rate bitmask
+            }
+        }
+
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::AppendRate(): num of existing rates: %d"), 
+        iPolicy[aPolicyIndex].iNumOfRates);
+
+    return ETrue;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::Reset( SPolicy& aPolicy ) const
+    {
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::Reset() a policy"));
+
+    // dealloc all rates
+    SBitRate* ptr =  aPolicy.iHead;
+    SBitRate* cache =  ptr;
+
+    while ( ptr )
+        {
+        cache = ptr;
+        ptr = ptr->iNext;
+
+        // free the previous one
+        os_free( cache );        
+        }
+
+    aPolicy.iCurrentTxRate = NULL;
+    aPolicy.iHead = NULL;
+    aPolicy.iTail = NULL;
+    aPolicy.iNumOfRates = 0;
+    
+    aPolicy.iProbe = EFalse;
+    aPolicy.iTxCount = 0;
+    aPolicy.iTxFailCount = 0;
+    aPolicy.iStepUpCheckpoint = iAlgorithmParam.iMinStepUpCheckpoint;
+    aPolicy.iStepUpThreshold = iAlgorithmParam.iMinStepUpThreshold;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanTxRateAdaptation::SetRates( 
+    TUint8 aPolicyId,
+    WHA::TRate aRateBitmask )
+    {
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::SetRates(): aPolicyId: 0x%08x"), aPolicyId);
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::SetRates(): aRateBitmask: 0x%08x"), aRateBitmask);
+
+    // make the list of rates; but 1st clear the list
+    Reset( iPolicy[aPolicyId - 1] );
+
+    // make rates from bitmask
+    const TUint32 cntr_end( 32 );
+    TUint32 cntr( 0 );
+
+    for ( TUint32 bit = 1 ; cntr != cntr_end ; (bit <<= 1) )
+        {
+        if ( aRateBitmask & bit )
+            {
+            // rate is to be set
+            if ( !AppendRate( aPolicyId - 1, aRateBitmask & bit ) )
+                {
+                return EFalse;
+                }
+            }
+
+        ++cntr;
+        }
+
+    // if we got this far, the rates are now in the list
+    
+    return ETrue;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::SetPolicy( 
+    WHA::TQueueId aQueueId, 
+    TUint8 aPolicyId )
+    {
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::SetPolicy(): aQueueId: %d"), 
+        aQueueId);
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::SetPolicy(): aPolicyId: %d"), 
+        aPolicyId);
+
+    iQueue2Policy[aQueueId] = aPolicyId;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::SetCurrentMaxTxRate( 
+    TUint8 aPolicyId, 
+    WHA::TRate aRate )
+    {
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC:  WlanTxRateAdaptation::SetCurrentMaxTxRate(): aPolicyId: %d"), 
+        aPolicyId );
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC:  WlanTxRateAdaptation::SetCurrentMaxTxRate(): aRate: 0x%08x"), 
+        aRate );
+
+    if ( !iPolicy[aPolicyId - 1].iNumOfRates )
+        {
+        // catch implementation error
+        OsAssert( (TUint8*)("UMAC: panic: no rates defined"),
+            (TUint8*)(WLAN_FILE), __LINE__ );
+        }
+
+    // traverse our single linked list of rate entrys from rear (i.e. from 
+    // the highest) to front (i.e. to the lowest) and try to locate the 
+    // provided rate entry, or the next lower one, so that it can be set as 
+    // the current max tx rate
+
+    SBitRate* ptr = iPolicy[aPolicyId - 1].iTail;
+
+    do
+        {
+        if ( ptr->iBitRate <= aRate )
+            {
+            // found
+            break;
+            }
+        else
+            {
+            ptr = ptr->iPrev;            
+            }
+        } 
+        while ( ptr );
+    
+    if ( ptr )
+        {
+        // usable rate was found. Set it as the current rate
+        iPolicy[aPolicyId - 1].iCurrentTxRate = ptr;        
+        }
+    else
+        {
+        // the provided max Tx rate is lower than any of the
+        // rates in this rate policy. In this case we have to set the 
+        // lowest rate in the policy as the current rate (even 
+        // though it is higher than what was requested)
+        iPolicy[aPolicyId - 1].iCurrentTxRate = iPolicy[aPolicyId - 1].iHead;
+        }
+
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC:  WlanTxRateAdaptation::SetCurrentMaxTxRate(): current rate now set to: 0x%08x"), 
+        iPolicy[aPolicyId - 1].iCurrentTxRate->iBitRate );
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::SetAlgorithmParameters( 
+    TUint8 aMinStepUpCheckpoint,
+    TUint8 aMaxStepUpCheckpoint,
+    TUint8 aStepUpCheckpointFactor,
+    TUint8 aStepDownCheckpoint,
+    TUint8 aMinStepUpThreshold,
+    TUint8 aMaxStepUpThreshold,
+    TUint8 aStepUpThresholdIncrement,
+    TUint8 aStepDownThreshold,
+    TBool aDisableProbeHandling )
+    {
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::SetAlgorithmParameters") );
+
+    iAlgorithmParam.iMinStepUpCheckpoint = aMinStepUpCheckpoint;
+    iAlgorithmParam.iMaxStepUpCheckpoint = aMaxStepUpCheckpoint;
+    iAlgorithmParam.iStepUpCheckpointFactor = aStepUpCheckpointFactor;
+    iAlgorithmParam.iStepDownCheckpoint = aStepDownCheckpoint;
+    iAlgorithmParam.iMinStepUpThreshold = aMinStepUpThreshold;
+    iAlgorithmParam.iMaxStepUpThreshold = aMaxStepUpThreshold;
+    iAlgorithmParam.iStepUpThresholdIncrement = aStepUpThresholdIncrement;
+    iAlgorithmParam.iStepDownThreshold = aStepDownThreshold;
+    iAlgorithmParam.iDisableProbeHandling = aDisableProbeHandling;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::RatePolicy( 
+    const WlanContextImpl& aCtxImpl,
+    WHA::TQueueId aQueueId,
+    TBool aUseSpecialRatePolicy,
+    WHA::TRate& aRate, 
+    TUint8& aPolicyId ) const
+    {
+    aPolicyId = iQueue2Policy[aQueueId];
+
+    if ( aCtxImpl.WHASettings().iCapability & 
+         WHA::SSettings::KAutonomousRateAdapt )
+        {
+        // autonomous rate adaptation is being used, i.e. rate adaptation is
+        // handled by lower layers. In this case it's not relevant to specify
+        // a Max Tx Rate and the whole value is not applicable. So we return
+        // zero        
+        const WHA::TRate notRelevant( 0 );
+        aRate = notRelevant;
+        
+        const TUint8 KSpecialTxAutoRatePolicy = 
+            aCtxImpl.SpecialTxAutoRatePolicy();
+        
+        if ( aUseSpecialRatePolicy && KSpecialTxAutoRatePolicy )
+            {
+            aPolicyId = KSpecialTxAutoRatePolicy;
+            }
+        }
+    else
+        {
+        // rate adaptation is handled by this object
+        
+        if ( !iPolicy[aPolicyId - 1].iNumOfRates )
+            {
+            OsAssert( (TUint8*)
+                ("UMAC: WlanTxRateAdaptation::RatePolicy(): panic: no rates defined"),
+                (TUint8*)(WLAN_FILE), __LINE__ );
+            }
+
+        if ( !iPolicy[aPolicyId - 1].iCurrentTxRate )
+            {
+            // catch implementation error
+
+            OsTracePrint( KErrorLevel, 
+                (TUint8*)("UMAC: no current rate specified for policy id: %d"), 
+                aPolicyId );        
+            OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
+            }
+            
+        // return the current Max Tx Rate
+        aRate = iPolicy[aPolicyId - 1].iCurrentTxRate->iBitRate;    
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::OnTxCompleted( 
+    WHA::TRate aRate, 
+    TBool aSuccess,
+    WHA::TQueueId aQueueId,
+    WHA::TRate aRequestedRate )
+    {
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): aRate: 0x%08x"), 
+        aRate);
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): aSuccess: %d"), 
+        aSuccess);
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): aQueueId: %d"), 
+        aQueueId);
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): aRequestedRate: 0x%08x"), 
+        aRequestedRate);
+
+    TBool success( aSuccess );
+
+    TUint8 policyId = iQueue2Policy[aQueueId];
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::OnTxCompleted(): policyId: %d"), 
+        policyId);    
+
+    if ( iPolicy[policyId - 1].iCurrentTxRate )
+        {
+        // as Current Tx Rate is defined for this policy, it means that
+        // this rate adaptation object is configured and we can handle this 
+        // event
+           
+        if ( aSuccess )
+            {
+            // the frame was successfully delivered to nw
+            
+            // from rate adaptation point of view we are interested in the 
+            // actual Tx rate of the frame only if the current rate for the Tx
+            // policy in question is still the same as the originally requested Tx
+            // rate for this frame.
+            // (After we have switched the curent rate to something else, we may
+            // still receive Tx completions for frames which we have requested to 
+            // be sent with the previous rate. We are not interested in their 
+            // actual Tx rate any more.)
+            if ( aRequestedRate == iPolicy[policyId - 1].iCurrentTxRate->iBitRate )
+                {
+                if ( aRate != aRequestedRate )
+                    {
+                    // actual Tx rate was different than the originally requested
+                    // rate. This is a Tx "failure" from Tx rate adaptation point
+                    // of view
+                    OsTracePrint( KTxRateAdapt, (TUint8*)
+                        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): succeeded with a different rate than requested"));
+                    success = EFalse;
+                    }
+                }
+            else
+                {
+                // curent rate of the Tx policy in question not the same any more
+                // as the originally requested rate for this frame. The frame is
+                // ignored from Tx rate adaptation considerations            
+                OsTracePrint( KTxRateAdapt, (TUint8*)
+                    ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): current rate for this Tx policy not same any more as originally requested rate for this frame"));
+                OsTracePrint( KTxRateAdapt, (TUint8*)
+                    ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): frame ignored from Tx rate adaptation considerations"));
+                return;
+                }
+            }
+                
+        TRateStep rateStep = OnTxCompleted( success, iPolicy[policyId - 1] );
+        
+        switch ( rateStep )
+            {
+            case EStepUp:
+                if ( RateStepUp( iPolicy[policyId - 1] ) )
+                    {
+                    // step up succeeded (i.e. there was a higher rate to switch to)
+
+                    // if probe frame handling hasn't been disabled, the next 
+                    // transmitted frame will be handled as a probe frame
+                    if ( !iAlgorithmParam.iDisableProbeHandling )
+                        {
+                        iPolicy[policyId - 1].iProbe = ETrue;                    
+                        }                
+                    }                
+                break;
+            case EStepDown:
+                RateStepDown( iPolicy[policyId - 1] );
+                break;
+            case EKeepCurrent:
+                // nothing to do here
+                break;
+            default:
+                OsTracePrint( KErrorLevel, 
+                    (TUint8*)("UMAC: unkown rate step: %d"), 
+                    rateStep );        
+                OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ );                        
+            }    
+        }
+    else
+        {
+        // Current Tx Rate is not defined for this policy, which means that
+        // this rate adaptation object is not configured (it has been
+        // reset) and cannot handle the event. So we just discard it
+        OsTracePrint( KTxRateAdapt, (TUint8*)
+            ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): Rate adaptation not configured. Tx complete event discarded"));
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanTxRateAdaptation::Reset()
+    {
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::Reset() the whole object"));
+
+    for ( TUint32 j = 0; j != WHA::EQueueIdMax; ++j )
+        {
+        // every Tx queue is mapped to the same (general) Tx policy
+        iQueue2Policy[j] = WHA::KDefaultTxRatePolicyId;
+        }
+
+    for ( TUint32 i = 0; i != KMaxRatePolicyCount; ++i )
+        {
+        // reset the state of every individual Tx policy
+        Reset( iPolicy[i] );
+        }        
+    }
+
+// ---------------------------------------------------------------------------
+// Note: The rate adaptation algorithm requires that:
+// iStepDownCheckpoint <= iStepUpCheckpoint and
+// iStepDownCheckpoint > 1 (or it can also be == 1 if iDisableProbeHandling
+// is ETrue)
+// ---------------------------------------------------------------------------
+//
+WlanTxRateAdaptation::TRateStep WlanTxRateAdaptation::OnTxCompleted( 
+    TBool aSuccess,
+    SPolicy& aPolicy ) const
+    {
+    TRateStep rateStep( EKeepCurrent );
+
+    ++aPolicy.iTxCount;
+
+    if ( !aSuccess )
+        {
+        ++aPolicy.iTxFailCount;
+        }
+
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): iProbe (0 no/1 yes): %d"),
+        aPolicy.iProbe );
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): iTxCount after counting this frame: %d"),
+        aPolicy.iTxCount );
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): iTxFailCount after counting this frame: %d"),
+        aPolicy.iTxFailCount );
+    OsTracePrint( KTxRateAdapt, 
+        (TUint8*)("UMAC: WlanTxRateAdaptation::OnTxCompleted(): iCurrentTxRate: 0x%08x"), 
+        aPolicy.iCurrentTxRate->iBitRate);
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): iStepUpCheckpoint: %d"),
+        aPolicy.iStepUpCheckpoint  );
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): iStepUpThreshold: %d"),
+        aPolicy.iStepUpThreshold  );
+
+    if ( aPolicy.iProbe )
+        {
+        // this was a probe frame; check if a rate change is needed
+        
+        if ( !aSuccess )
+            {
+            // either the Tx failed completely or it succeeded at a lower 
+            // rate than requested
+
+            OsTracePrint( KTxRateAdapt, (TUint8*)
+                ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): probe failure"));
+            
+            // decrement the rate
+            rateStep = EStepDown;
+
+            aPolicy.iStepUpCheckpoint = 
+                ( aPolicy.iStepUpCheckpoint * 
+                  iAlgorithmParam.iStepUpCheckpointFactor 
+                  > iAlgorithmParam.iMaxStepUpCheckpoint ) ? 
+                 iAlgorithmParam.iMaxStepUpCheckpoint :
+                 aPolicy.iStepUpCheckpoint * 
+                 iAlgorithmParam.iStepUpCheckpointFactor;
+            
+            aPolicy.iStepUpThreshold = 
+                ( aPolicy.iStepUpThreshold + 
+                  iAlgorithmParam.iStepUpThresholdIncrement
+                > iAlgorithmParam.iMaxStepUpThreshold ) ?
+                iAlgorithmParam.iMaxStepUpThreshold :
+                aPolicy.iStepUpThreshold + 
+                iAlgorithmParam.iStepUpThresholdIncrement;
+            
+            OsTracePrint( KTxRateAdapt, (TUint8*)
+                ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): new iStepUpCheckpoint: %d"),
+                aPolicy.iStepUpCheckpoint  );
+            OsTracePrint( KTxRateAdapt, (TUint8*)
+                ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): new iStepUpThreshold: %d"),
+                aPolicy.iStepUpThreshold  );
+
+            aPolicy.iTxCount = 0;
+            aPolicy.iTxFailCount = 0;                
+            }
+        else
+            {
+            // Tx success with requested rate; nothing more to do
+            }  
+                          
+        // in any case clear the probe flag
+        aPolicy.iProbe = EFalse;
+        }
+    else 
+        {        
+        if ( aPolicy.iTxCount % iAlgorithmParam.iStepDownCheckpoint == 0 )
+            {
+            // check if the rate should be decremented
+            OsTracePrint( KTxRateAdapt, (TUint8*)
+                ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): check for decrement need"));
+
+            if ( aPolicy.iTxFailCount * 100 
+                 >= iAlgorithmParam.iStepDownThreshold * aPolicy.iTxCount )
+                {
+                // at least iStepDownThreshold % of iTxCount frames have 
+                // "failed" => decrement rate
+                //
+                rateStep = EStepDown;                  
+                aPolicy.iStepUpCheckpoint = 
+                    iAlgorithmParam.iMinStepUpCheckpoint;
+                aPolicy.iStepUpThreshold = 
+                    iAlgorithmParam.iMinStepUpThreshold;
+
+                aPolicy.iTxCount = 0;
+                aPolicy.iTxFailCount = 0;
+                }            
+            }
+
+        if ( rateStep != EStepDown && 
+            aPolicy.iTxCount >= aPolicy.iStepUpCheckpoint )
+            {
+            // check if the rate should be incremented
+            OsTracePrint( KTxRateAdapt, (TUint8*)
+                ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): check for increment need"));
+            
+            if ( ( aPolicy.iTxCount - aPolicy.iTxFailCount ) * 100 
+                 >= aPolicy.iStepUpThreshold *  aPolicy.iTxCount )
+                {
+                // at least iStepUpThreshold % of iTxCount frames have 
+                // "succeeded" => increment rate
+                //
+                rateStep = EStepUp;
+                }
+                
+            aPolicy.iTxCount = 0;
+            aPolicy.iTxFailCount = 0;
+            }
+        }
+        
+    OsTracePrint( KTxRateAdapt, (TUint8*)
+        ("UMAC: WlanTxRateAdaptation::OnTxCompleted(): rateStep: %d (keep = 0, down, up)"),
+        rateStep );
+
+    return rateStep;
+    }