wlan_bearer/wlanldd/wlan_common/umac_common/src/umacsignalpredictor.cpp
changeset 0 c40eb8fe8501
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanldd/wlan_common/umac_common/src/umacsignalpredictor.cpp	Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,589 @@
+/*
+* Copyright (c) 2007-2008 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 WlanSignalPredictor class.
+*
+*/
+
+/*
+* %version: 7 %
+*/
+
+#include "config.h"
+#include "umacsignalpredictor.h"
+
+
+static const TUint KThousand = 1000;
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+WlanSignalPredictor::WlanSignalPredictor()
+    :
+    iTimeToWarnLevel( KTimeToIndicationLevel ),
+    iWindowSize( KWindowSizeDefault ),
+    iTimeToNextInd( KTimeToNextIndication ),
+    iWarningLevel( KRoamLevel ),
+    iValueCount( 0 ),
+    iMedianCount( 0 ),
+    iLatestMedian( 0 ),
+    iOldestValue( 0 ),
+    iLatestValue( 0 ),
+    iLeastRcpi( 0 ),
+    iMaxRcpi( 0 ),
+    iValueCountMax( KValueCountMax ),
+    iMinValueCountForPrediction( KMinValueCountForPrediction ),
+    iRunning( ETrue )
+    {
+    os_memset( iLevelTable, KDummy, sizeof( iLevelTable ) );
+    os_memset( iMedianTable,KDummy, sizeof( iMedianTable ) );
+    iRoamed.iDone = EFalse;
+
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::WlanSignalPredictor") );
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanSignalPredictor::ConfigureSignalPredictor( 
+    TUint32     aTimeToWarnLevel,
+    TUint32     aTimeToNextInd,
+    WHA::TRcpi  aRcpiWarnLevel )
+    {
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::ConfigureSignalPredictor") );
+
+    iTimeToWarnLevel = ( aTimeToWarnLevel ) ? aTimeToWarnLevel / KThousand : 
+                                              iTimeToWarnLevel;
+
+    iTimeToNextInd = ( aTimeToNextInd ) ? aTimeToNextInd / KThousand : 
+                                          iTimeToNextInd;
+
+    iWarningLevel = ( aRcpiWarnLevel ) ? aRcpiWarnLevel : iWarningLevel;
+    
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::iTimeToWarnLevel: %d"), 
+        iTimeToWarnLevel );
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::iTimeToNextInd: %d"), 
+        iTimeToNextInd );
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::iWarningLevel: %d"), 
+        iWarningLevel );
+    
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanSignalPredictor::InsertNewRcpi( 
+    TUint32    aTimestamp, 
+    WHA::TRcpi aRcpi )
+    {
+    // Check all preconditions for prediction
+
+    // Check state of module SPC Stopped
+    if ( EFalse == iRunning ) 
+        {
+        return EFalse;
+        }
+    
+    // Convert the timestamp from microseconds to milliseconds
+    aTimestamp = aTimestamp / KThousand;
+
+    // If new timestamp is old enough from the latest one.
+    if ( iValueCount && 
+         (aTimestamp < (iLevelTable[iLatestValue].iTimestamp + KValueDelay) ) )
+        {
+        return EFalse;
+        }
+
+    // Remove too old values
+    if ( iValueCount )
+        {
+        RemoveOldValues( aTimestamp );
+        }
+
+    // Insert the new value
+    return InsertValue( aTimestamp, aRcpi );
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanSignalPredictor::GetLatestMedian( 
+    TUint32 aTimestamp,
+    TUint8& aLastMedian ) const
+    {
+    // Convert the timestamp into milliseconds
+    aTimestamp = aTimestamp / KThousand;
+
+    if ( iMedianCount )
+        {
+        // Check first if the latest median is too old already.
+        if ( iWindowSize >= 
+             Delay( iMedianTable[iLatestMedian].iTimestamp, aTimestamp ) )
+            {
+            aLastMedian = iMedianTable[iLatestMedian].iRcpi;
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanSignalPredictor::GetLatestRcpi( 
+    TUint32 aTimestamp,
+    TUint8& aLatestRcpi )
+    {
+    // Convert the timestamp into milliseconds
+    aTimestamp = aTimestamp / KThousand;
+
+    RemoveOldValues( aTimestamp );
+    
+    if ( iValueCount )
+        {
+        aLatestRcpi = iLevelTable[iLatestValue].iRcpi;
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanSignalPredictor::RemoveOldValues( 
+    TUint32 aTimestamp )
+    {
+    TBool oldFound( ETrue );
+    
+    while ( oldFound && iValueCount )
+        {
+        TUint32 deltaTime = 
+            Delay( iLevelTable[iOldestValue].iTimestamp, aTimestamp );
+        if ( deltaTime > iWindowSize )
+            {
+            RemoveValue( iOldestValue );
+            }
+        else
+            {
+            oldFound = EFalse;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void WlanSignalPredictor::RemoveValue( 
+    TUint8 aIndex )
+    {
+    // The only one is removed.
+    if ( KOneValue == iValueCount )
+        {
+        os_memset( iLevelTable, KDummy, sizeof( iLevelTable ) );
+        iValueCount  = 0;
+        iOldestValue = 0;
+        iLatestValue = 0;
+        iLeastRcpi   = 0;
+        iMaxRcpi     = 0;
+        return;
+        }
+    // The biggest rcpi is removed.
+    else if ( aIndex == iMaxRcpi )
+        {
+        iLevelTable[iLevelTable[aIndex].iPrev].iNext = iValueCountMax;
+        iMaxRcpi = iLevelTable[aIndex].iPrev;
+        }
+    // The least rcpi is removed.
+    else if ( aIndex == iLeastRcpi )
+        {
+        iLevelTable[iLevelTable[aIndex].iNext].iPrev = iValueCountMax;
+        iLeastRcpi = iLevelTable[aIndex].iNext;
+        }
+    // The middle rcpi is removed.
+    else
+        {
+        iLevelTable[iLevelTable[aIndex].iPrev].iNext = iLevelTable[aIndex].iNext;
+        iLevelTable[iLevelTable[aIndex].iNext].iPrev = iLevelTable[aIndex].iPrev;
+        }
+       
+    os_memset( &iLevelTable[aIndex], KDummy, sizeof( TValue ) );
+    
+    iOldestValue++;
+    if ( iOldestValue == iValueCountMax )
+        {
+        iOldestValue = 0;
+        }
+    iValueCount--;
+    }
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanSignalPredictor::InsertValue( 
+    TUint32    aTimestamp, 
+    WHA::TRcpi aRcpi )
+    {
+    // If rcpi storage is full remove the oldest one to get space for new one
+    if ( iValueCount == iValueCountMax )
+        {
+        RemoveValue( iOldestValue );
+        }
+    // Insert the new value into rcpi storage
+    if ( !iValueCount )
+        {
+        // First item in rcpi storage.
+        iOldestValue = 0;
+        iLatestValue = 0;
+        iLeastRcpi   = 0;
+        iMaxRcpi     = 0;
+        iLevelTable[iOldestValue].iTimestamp = aTimestamp;
+        iLevelTable[iOldestValue].iRcpi      = aRcpi;
+        iLevelTable[iOldestValue].iPrev      = iValueCountMax;
+        iLevelTable[iOldestValue].iNext      = iValueCountMax;
+        }
+    else
+        {
+        // Already items in storage.
+        TBool  biggerFound( EFalse );
+        TUint8 tmpLeastIndex( iLeastRcpi );
+
+        iLatestValue++;
+        if ( iLatestValue == iValueCountMax )
+            {
+            iLatestValue = 0;
+            }
+        iLevelTable[iLatestValue].iTimestamp = aTimestamp;
+        iLevelTable[iLatestValue].iRcpi      = aRcpi;
+
+        // Insert this right place in Rcpi order.
+        while ( !biggerFound )
+            {
+            if ( iLevelTable[tmpLeastIndex].iRcpi > aRcpi )
+                {
+                if ( tmpLeastIndex == iLeastRcpi )
+                    {
+                    iLevelTable[iLatestValue ].iPrev = iValueCountMax;
+                    iLevelTable[iLatestValue ].iNext = tmpLeastIndex;
+                    iLevelTable[tmpLeastIndex].iPrev = iLatestValue; 
+                    iLeastRcpi = iLatestValue;
+                    }
+                else 
+                    {
+                    iLevelTable[iLatestValue ].iPrev = iLevelTable[tmpLeastIndex].iPrev;
+                    iLevelTable[iLatestValue ].iNext = tmpLeastIndex;
+                    iLevelTable[tmpLeastIndex].iPrev = iLatestValue; 
+                    iLevelTable[iLevelTable[iLatestValue].iPrev].iNext = iLatestValue;
+                    }
+                biggerFound = ETrue;
+                }
+            else
+                {
+                if ( tmpLeastIndex == iMaxRcpi )
+                    {
+                    // Biggest rcpi value.
+                    iLevelTable[iMaxRcpi].iNext     = iLatestValue;
+                    iLevelTable[iLatestValue].iPrev = iMaxRcpi;
+                    iLevelTable[iLatestValue].iNext = iValueCountMax;
+                    iMaxRcpi    = iLatestValue;
+                    biggerFound = ETrue;
+                    }
+                }
+            tmpLeastIndex = iLevelTable[tmpLeastIndex].iNext;
+            }
+        }
+    iValueCount++;
+
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::InsertValue Rcpi: %d"), 
+        aRcpi );
+
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::InsertValue Timestamp: %d"), 
+        aTimestamp );
+
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::InsertValue Rcpi count: %d"), 
+        iValueCount );
+
+
+	// Check first if the latest filtered value is old enough so that new
+	// value can be added. If not, no new value is added.
+	TUint32 FilterDelay = Delay( iMedianTable[iLatestMedian].iTimestamp, 
+								 iLevelTable[iLatestValue].iTimestamp );
+
+	if ( FilterDelay < KMedianDelay )
+		{
+		OsTracePrint( KRxFrame, (TUint8*) 
+			("UMAC: WlanSignalPredictor::InsertValue: Too small delay between medians %d, No prediction. "), 
+			FilterDelay );
+
+		return EFalse;
+		}
+
+	// Calculate weight to be used in mean filter.
+	// Median weight factor ratio 4/7 is experimental value. ratio 10/1 would 
+    // mean in practise that NewMean = GetCurrentMedian()
+	// and Ratio 1/1000 NewMean =  latest iLevelTable[iLatestValue].iRcpi 	
+	TUint8 WeightFactor = ( iValueCount * 4 ) / 7;
+
+	// Get new filtered value using floating mean filter.
+	// Previous value (=LatestMedian at this point) is weighted using
+	// value above.
+	TUint8 NewMean = ( iMedianTable[iLatestMedian].iRcpi * WeightFactor + 
+                       GetCurrentMedian() ) / ( WeightFactor + 1 );
+
+	OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::InsertValue WeightFactor: %d"), 
+        WeightFactor );
+
+	OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::InsertValue NewMean: %d"), 
+        NewMean );
+
+    return InsertMedian( aTimestamp, NewMean );
+    }
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TUint8 WlanSignalPredictor::GetCurrentMedian() const
+    {
+    
+    TUint8 tempIdx( iLeastRcpi );
+
+    if ( KOneValue == iValueCount )
+        {
+        return iLevelTable[tempIdx].iRcpi;
+        }
+    else if ( iValueCount % 2 )
+        {
+        for ( TUint8 i = 1; i <= iValueCount/2; i++ )
+            {
+            tempIdx = iLevelTable[tempIdx].iNext;
+            }
+        return iLevelTable[tempIdx].iRcpi;
+        }
+    else
+        {
+        for ( TUint8 i = 1; i < iValueCount/2; i++ )
+            {
+            tempIdx = iLevelTable[tempIdx].iNext;
+            }
+        return ( (iLevelTable[tempIdx].iRcpi + 
+                 iLevelTable[iLevelTable[tempIdx].iNext].iRcpi)/2 );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanSignalPredictor::InsertMedian( 
+    TUint32 aTimestamp, 
+    TUint8  aMedian )
+    {
+    TUint32 deltaTime( 0 );
+    
+    if ( !iMedianCount )
+        {
+        iMedianCount  = KOneValue;
+        iLatestMedian = 0;
+        iMedianTable[iLatestMedian].iTimestamp = aTimestamp;
+        iMedianTable[iLatestMedian].iRcpi      = aMedian;
+        }
+    else
+        {
+        deltaTime = Delay( iMedianTable[iLatestMedian].iTimestamp, aTimestamp );
+        if ( deltaTime > iWindowSize )
+            {
+            os_memset( iMedianTable,KDummy, sizeof( iMedianTable ) );
+            iLatestMedian = 0;
+            iMedianCount  = KOneValue;
+            iMedianTable[iLatestMedian].iTimestamp = aTimestamp;
+            iMedianTable[iLatestMedian].iRcpi      = aMedian;
+            }
+        else
+            {
+            iLatestMedian = iLatestMedian ? 0 : 1;
+            iMedianCount  = 2;
+            iMedianTable[iLatestMedian].iTimestamp = aTimestamp;
+            iMedianTable[iLatestMedian].iRcpi      = aMedian;
+            }
+        }
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::InsertMedian Median: %d"), 
+        aMedian );
+
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::InsertMedian MedianCount: %d"), 
+        iMedianCount );
+
+    return GetPrediction();
+    }
+
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TBool WlanSignalPredictor::GetPrediction()
+    {
+    OsTracePrint( KRxFrame, (TUint8*)
+        ("UMAC: WlanSignalPredictor::GetPrediction") );
+
+    // Roaming indication delay check.
+    if ( iRoamed.iDone )
+        {
+        if ( iTimeToNextInd >= 
+             Delay(iRoamed.iTimestamp, iMedianTable[iLatestMedian].iTimestamp) )
+            {
+            OsTracePrint( KRxFrame, (TUint8*)
+                ("UMAC: WlanSignalPredictor::Latest roaming indication delay not past: No prediction") );
+
+            // Old indication still not enough old.
+            return EFalse;
+            }
+        else
+            {
+            OsTracePrint( KRxFrame, (TUint8*)
+                ("UMAC: WlanSignalPredictor::Latest roaming indication delay past: Get prediction") );
+            // Old indication old enough to send new one, clean the flag.
+            iRoamed.iDone = EFalse;
+            }
+        }
+
+    // One median value, is it under warning level.
+    if ( iMinValueCountForPrediction > iValueCount )
+        {
+        OsTracePrint( KRxFrame, (TUint8*)
+            ("UMAC: WlanSignalPredictor:: Count of rcpi values not enough:") );
+
+		// If latest filtered value is below warning level
+		if ( iMedianTable[iLatestMedian].iRcpi < iWarningLevel )
+			{
+            OsTracePrint( KRxFrame, (TUint8*)
+                ("UMAC: WlanSignalPredictor:: Last median under Warning level: Send roam indication.") );
+			}
+		else
+			{
+            OsTracePrint( KRxFrame, (TUint8*)
+                ("UMAC: WlanSignalPredictor:: No prediction.") );
+			return EFalse;
+			}
+        }
+
+    // Is the latest median bigger or equal than old one.
+    else if ( iMedianTable[iLatestMedian].iRcpi >= 
+              iMedianTable[iLatestMedian?0:1].iRcpi )
+        {
+        OsTracePrint( KRxFrame, (TUint8*)
+            ("UMAC: WlanSignalPredictor:: Last median above old one: No roam indication.") );
+        return EFalse;
+        }
+        // Otherwise count the prediction for roaming indication.
+        else
+            {
+            TUint32 Drop( 0 );
+            TUint32 DropPeriod( 0 );
+            TUint32 DropToRoam( 0 );
+            TUint32 TimeToRoam( 0 );
+
+            Drop = iMedianTable[iLatestMedian ? 0 : 1].iRcpi - 
+                   iMedianTable[iLatestMedian].iRcpi;
+
+            DropToRoam = iMedianTable[iLatestMedian].iRcpi - iWarningLevel;
+
+            DropPeriod = Delay( iMedianTable[iLatestMedian ? 0 : 1].iTimestamp, 
+                                iMedianTable[iLatestMedian].iTimestamp);
+
+            TimeToRoam = ( DropPeriod * DropToRoam ) / Drop;
+
+            OsTracePrint( KRxFrame, (TUint8*)
+                ("UMAC: WlanSignalPredictor::GetPrediction TimeToRoam: %d ms."), 
+                TimeToRoam );
+
+		    // Level comparison changed to use
+		    // filtered signal value. This significantly
+		    // reduces amount of indications.
+            if ( TimeToRoam	< iTimeToWarnLevel && 
+                 KDiffRoamLevel	> iMedianTable[iLatestMedian].iRcpi )
+                {
+                OsTracePrint( KRxFrame, (TUint8*) 
+                    ("UMAC: WlanSignalPredictor::All conditions ok. Send roam indication.")  );
+                }
+             else
+                {
+                 OsTracePrint( KRxFrame, (TUint8*) 
+                    ("UMAC: WlanSignalPredictor::Some conditions nok. No roam indication.")  );
+                return EFalse;
+                }
+            }
+    
+    // If we get this point, roaming indication is sent. Save the indication info.
+    iRoamed.iDone = ETrue;
+    iRoamed.iTimestamp = iMedianTable[iLatestMedian].iTimestamp;
+    
+    // Start roaming
+    return ETrue;
+    }
+
+
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+TUint32 WlanSignalPredictor::Delay( 
+    TUint32 aOldTime, 
+    TUint32 aNewTime ) const
+    {
+    TUint32 delay;
+    if ( aOldTime > aNewTime )
+        {
+        delay = ~aOldTime + 1 + aNewTime;
+        }
+    else
+        {
+        delay = aNewTime - aOldTime;    
+        }
+    return delay;
+    }
+
+
+
+
+