/*
* 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 WlanDot11SoftReset class
*
*/

/*
* %version: 28 %
*/

#include "config.h"
#include "UmacDot11SoftReset.h"
#include "UmacContextImpl.h"
#include "UmacWsaWriteMib.h"
#include "UmacWsaDisconnect.h"
#include "umacconfiguretxqueueparams.h"

#ifndef NDEBUG
const TInt8 WlanDot11SoftReset::iName[] = "dot11-softreset";

const TUint8 WlanDot11SoftReset::iStateName
    [ESTATEMAX][KMaxStateStringLength] = 
    {
        {"EINIT"},
        {"EISSUEDISCONNECT"}, 
        {"ECONFTXQUEUE"},
        {"ECONTINUEDOT11TRAVERSE"}
    };

const TUint8 WlanDot11SoftReset::iEventName
    [EEVENTMAX][KMaxEventStringLength] = 
    {
        {"ESTATEENTRY"}, 
        {"ETXCOMPLETE"},
        {"EABORT"}
    };
#endif 
// ================= MEMBER FUNCTIONS =======================

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11SoftReset::Fsm( 
    WlanContextImpl& aCtxImpl, 
    TEvent aEvent )
    {
#ifndef NDEBUG
    OsTracePrint( 
        KUmacDetails, 
        (TUint8*)("UMAC: WlanDot11SoftReset::Fsm(): event: "));
    OsTracePrint( 
        KUmacDetails, 
        iEventName[aEvent] );
    OsTracePrint( 
        KUmacDetails, 
        (TUint8*)("UMAC: WlanDot11SoftReset::Fsm(): state: ")); 
    OsTracePrint( 
        KUmacDetails, 
        iStateName[iState] );
#endif

    switch ( aEvent )
        {
        case ESTATEENTRY:
            OnStateEntryEvent( aCtxImpl );
            break;
        case ETXCOMPLETE:
            OnTxCompleteEvent( aCtxImpl );
            break;
        case EABORT:
            OnAbortEvent( aCtxImpl );
            break;
        default:
            OsTracePrint( 
                KErrorLevel, 
                (TUint8*)("UMAC: WlanDot11SoftReset::Fsm(): event: %d"), 
                aEvent);        
            OsAssert( 
                (TUint8*)("UMAC: WlanDot11SoftReset::Fsm(): panic"), 
                (TUint8*)(WLAN_FILE), __LINE__ );
            break;
        }
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11SoftReset::OnStateEntryEvent( 
    WlanContextImpl& aCtxImpl )
    {
    OsTracePrint( 
        KUmacDetails, 
        (TUint8*)("UMAC: WlanDot11SoftReset::OnStateEntryEvent()"));

    switch ( iState )
        {
        case EINIT:
            InitActions( aCtxImpl );
            ChangeInternalState( aCtxImpl, EISSUEDISCONNECT );            
            break;
        case EISSUEDISCONNECT:
            IssueDisconnect( aCtxImpl );
            break;
        case ECONFTXQUEUE:
            // configure just the legacy Tx queue    
            ConfigureQueue( aCtxImpl );
            break;
        case ECONTINUEDOT11TRAVERSE:
            ContinueDot11StateTraversal( aCtxImpl );
            break;
        default:
            // programming error
            OsTracePrint( KErrorLevel, (TUint8*)("UMAC: state: %d"), iState);
            OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
        }
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11SoftReset::InitActions( WlanContextImpl& aCtxImpl )
    {
    // we are breaking an existing join so we have to reset some
    // state variables and settings
    aCtxImpl.CurrentDot11PwrMgmtMode( WHA::KPsDisable );
    aCtxImpl.Reassociate( EFalse );
    aCtxImpl.QosEnabled( EFalse );
    aCtxImpl.UapsdEnabled( EFalse );
    DetermineAcUapsdUsage( aCtxImpl );
    aCtxImpl.TerminateVoiceOverWlanCallMaintenance();
    aCtxImpl.MulticastFilteringDisAllowed( EFalse );
    aCtxImpl.ResetMulticastAddresses();
    aCtxImpl.ResetFailedTxPacketCount();            
    aCtxImpl.IeData( NULL );
    aCtxImpl.DisassociatedByAp( EFalse );
    aCtxImpl.ResetTxRateAdaptation();
    os_memset( 
        reinterpret_cast<TUint8*>(&(aCtxImpl.GetNwHtCapabilitiesIe().iData)), 
        0, 
        K802Dot11HtCapabilitiesIeDataLen );

    for ( TUint i = 0; i < WHA::EQueueIdMax; ++i )
        {
        aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetime[i] = 
            aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetimeDefault;
        aCtxImpl.iWlanMib.iMediumTime[i] = KDot11MediumTimeDefault;
        }    
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11SoftReset::OnTxCompleteEvent( 
    WlanContextImpl& aCtxImpl )
    {
    OsTracePrint( 
        KUmacDetails, 
        (TUint8*)("UMAC: WlanDot11SoftReset::OnTxCompleteEvent()"));

    switch ( iState )
        {
        case EISSUEDISCONNECT:
            // continue state traversal
            ChangeInternalState( aCtxImpl, ECONFTXQUEUE );
            break;
        case ECONFTXQUEUE:
            // continue state traversal
            ChangeInternalState( aCtxImpl, ECONTINUEDOT11TRAVERSE );
            break;
        default:
            // catch internal FSM programming error
            OsTracePrint( KErrorLevel, (TUint8*)("UMAC: state: %d"), iState);
            OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
        }
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11SoftReset::OnAbortEvent( 
    WlanContextImpl& aCtxImpl )
    {
    OsTracePrint( KWarningLevel, 
        (TUint8*)("UMAC: WlanDot11SoftReset::OnAbortEvent()") );
    DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding );
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11SoftReset::ContinueDot11StateTraversal( 
    WlanContextImpl& aCtxImpl )
    {
    OsTracePrint( KUmacDetails, (TUint8*)
        ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal()"));

#ifndef NDEBUG
    
    // trace current frame statistics
    
    const TStatisticsResponse& frameStatistics ( aCtxImpl.FrameStatistics() );
       
    OsTracePrint( 
        KUmacDetails, (TUint8*)
        ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: *** current frame statistics ***:") );

    for ( TUint i = 0; i < EQueueIdMax; ++i )
        {
        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: * Access Category: %d *"),
            i );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: successfully received unicast data frames: %d"), 
             frameStatistics.acSpecific[i].rxUnicastDataFrameCount );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: successfully transmitted unicast data frames: %d"), 
             frameStatistics.acSpecific[i].txUnicastDataFrameCount );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: successfully received multicast data frames: %d"), 
             frameStatistics.acSpecific[i].rxMulticastDataFrameCount );
        
        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: successfully transmitted multicast data frames: %d"), 
             frameStatistics.acSpecific[i].txMulticastDataFrameCount );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: nbr of data frame transmit retries: %d"), 
             frameStatistics.acSpecific[i].txRetryCount );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: nbr of data frame WLAN delivery failures: %d"), 
             frameStatistics.acSpecific[i].txErrorCount );                    

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: average data frame Tx media delay in microsecs: %d"), 
            aCtxImpl.AverageTxMediaDelay( static_cast<WHA::TQueueId>(i) ) );                    

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: average data frame total Tx delay in microsecs: %d"), 
             aCtxImpl.AverageTotalTxDelay( static_cast<WHA::TQueueId>(i) ) );                    

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: data frame total Tx delay bin 0 count: %d"), 
             frameStatistics.acSpecific[i].totalTxDelayBin0 );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: data frame total Tx delay bin 1 count: %d"), 
             frameStatistics.acSpecific[i].totalTxDelayBin1 );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: data frame total Tx delay bin 2 count: %d"), 
             frameStatistics.acSpecific[i].totalTxDelayBin2 );

        OsTracePrint( 
            KUmacDetails, (TUint8*)
            ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: data frame total Tx delay bin 3 count: %d"), 
             frameStatistics.acSpecific[i].totalTxDelayBin3 );
        }

    OsTracePrint( 
        KUmacDetails, (TUint8*)
        ("UMAC: WlanDot11SoftReset::ContinueDot11StateTraversal: all ACs: nbr of FCS errors in received MPDUs: %d"), 
         frameStatistics.fcsErrorCount );
#endif

    // change global state: entry procedure triggers action
    ChangeState( aCtxImpl,              
        *this,                                  // prev state
        aCtxImpl.iStates.iMibDefaultConfigure   // next state
        );                               
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11SoftReset::ChangeInternalState( 
    WlanContextImpl& aCtxImpl, 
    TState aNewState )
    {
#ifndef NDEBUG
    OsTracePrint( 
        KUmacDetails, 
        (TUint8*)
        ("UMAC: WlanDot11SoftReset::ChangeInternalState(): old state:"));
    OsTracePrint( 
        KUmacDetails, 
        iStateName[iState] );
    OsTracePrint( 
        KUmacDetails, 
        (TUint8*)
        ("UMAC: WlanDot11SoftReset::ChangeInternalState(): new state:"));
    OsTracePrint( 
        KUmacDetails, 
        iStateName[aNewState] );
#endif

    iState = aNewState;
    Fsm( aCtxImpl, ESTATEENTRY );
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void WlanDot11SoftReset::IssueDisconnect( 
    WlanContextImpl& aCtxImpl )
    {
    // change global state: entry procedure triggers action
    ChangeState( aCtxImpl, 
        *this,                      // prev state
        aCtxImpl.WsaDisconnect()    // next state
        );      
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void WlanDot11SoftReset::ConfigureQueue( 
    WlanContextImpl& aCtxImpl )
    {
    ConfigureTxQueue( aCtxImpl, WHA::ELegacy );    
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
#ifndef NDEBUG 
const TInt8* WlanDot11SoftReset::GetStateName( TUint8& aLength ) const
    {
    aLength = sizeof( iName );
    return iName;
    }
#endif

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void WlanDot11SoftReset::Entry( WlanContextImpl& aCtxImpl )
    {
    if ( aCtxImpl.WsaCmdActive() )
        {
        // sanity checking code
        OsAssert( (TUint8*)("UMAC * panic"), 
            (TUint8*)(WLAN_FILE), __LINE__ );
        }

    // don't want to do event dispatching here as we want
    // to run this dot11 state critter in non pre-emptive mode

    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 );
        }
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void WlanDot11SoftReset::Exit( WlanContextImpl& /*aCtxImpl*/ )
    {
    OsTracePrint( 
        KUmacProtocolState, 
        (TUint8*)("UMAC: WlanDot11SoftReset::Exit()"));

    // reset our local FSM for the next time...
    iState = EINIT;
    }
