--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanldd/wlan_common/umac_common/src/umacpacketscheduler.cpp Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,851 @@
+/*
+* 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: The one and only packet scheduler
+*
+*/
+
+/*
+* %version: 28 %
+*/
+
+#include "config.h"
+#include "umacpacketscheduler.h"
+#include "umacpacketschedulerclient.h"
+#include "UmacContextImpl.h"
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+WlanPacketScheduler::WlanPacketScheduler(
+ MWlanPacketSchedulerClient& aWlanPacketSchedulerClient )
+ : iPacketSchedulerClient(aWlanPacketSchedulerClient),
+ iCurrent( NULL ),
+ iTxPipelineActive( ETrue ),
+ iNumOfPackets( 0 ),
+ iNumOfNotCompletedPackets( 0 ),
+ iFlags( 0 )
+ {
+ // initially mark all as free
+ for ( TPacketIdCntxs::iterator pos = iPacketIdCntxs.begin()
+ ; pos != iPacketIdCntxs.end() ; ++pos )
+ {
+ pos->iFree = ETrue;
+ }
+ // initially mark all as free
+ for ( TPacketElements::iterator pos = iPacketElements.begin()
+ ; pos != iPacketElements.end() ; ++pos )
+ {
+ pos->iFree = ETrue;
+ }
+ // initially mark all as free
+ fill( iQueueStates.begin(), iQueueStates.end(), EQueueNotFull );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanPacketScheduler::Push(
+ WlanContextImpl& aCtxImpl,
+ const TAny* aPacket,
+ TUint32 aLength,
+ WHA::TQueueId aQueueId,
+ TUint32 aPacketId,
+ const TDataBuffer* aMetaHeader,
+ TBool aMore,
+ TBool aMulticastData,
+ TBool aUseSpecialRatePolicy )
+ {
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::Push: aMulticastData: %d"),
+ aMulticastData );
+
+ SElement* free_slot = FreeElementSlot();
+ if ( !free_slot )
+ {
+ // no free element slot was found,
+ // which means that all slots are in use
+ // we do nothing else than silently fail the operation
+ OsTracePrint( KPacketScheduler | KWarningLevel, (TUint8*)
+ ("UMAC: packetscheduler Push: no free slot found -> fail") );
+
+ // packet push failure we must signal
+ // set up a flag to signal client at later time to retry
+ // this operation
+ iFlags |= KSignalPushPacket;
+
+ return EFalse;
+ }
+
+ // one more packet to schedule
+ ++iNumOfPackets;
+
+ // store packet send context
+ free_slot->iFree = EFalse; // context is no longer free
+ free_slot->iPacket = aPacket;
+ free_slot->iLength = aLength;
+
+ // extract a free packet ID context
+ SPacketIdCntx* packet_id_cnxt = FreePacketIdCntx();
+ if ( !packet_id_cnxt )
+ {
+ // no free element was found
+ // we should allways enough of elements available
+ // so this issue means that we have either:
+ // 1) programming error
+ // 2) too small element storage
+ // in any case the issue must be solved at compile time not runtime
+ OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
+ return EFalse;
+ }
+
+ ++iNumOfNotCompletedPackets;
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::Push: the nbr of packets not yet completed by WHA layer is now: %d"),
+ iNumOfNotCompletedPackets );
+
+ // store packet ID context
+ packet_id_cnxt->iQueueId = aQueueId;
+ packet_id_cnxt->iFrameId = aPacketId;
+ packet_id_cnxt->iMetaHeader = aMetaHeader;
+ packet_id_cnxt->iFree = EFalse; // this id is no longer free
+ packet_id_cnxt->iMulticastData = aMulticastData;
+ packet_id_cnxt->iUseSpecialRatePolicy = aUseSpecialRatePolicy;
+
+ // link packet element to packet id context
+ free_slot->iPacketIdCntx = packet_id_cnxt;
+
+ if ( iCurrent )
+ {
+ if ( iTxPipelineActive )
+ {
+ // it is not logical to have a valid current pointer
+ // when the tx pipeline is active
+ OsAssert( (TUint8*)("UMAC * panic"),
+ (TUint8*)(WLAN_FILE), __LINE__ );
+ }
+
+ // we have a existing current pointer
+ // it means that the tx pipeline is stopped
+ // lets see if the pushed packet has a
+ // queue full status and proceed from that
+
+ if ( iQueueStates[packet_id_cnxt->iQueueId] == EQueueNotFull )
+ {
+ // as the pushed packet goes to non full queue let's
+ // set the one with highest priority as the current packet to send
+ if ( Priority( packet_id_cnxt->iQueueId ) >
+ Priority( iCurrent->iPacketIdCntx->iQueueId ) )
+ {
+ iCurrent = free_slot;
+ }
+ else
+ {
+ // no action
+ }
+ }
+ else // --- != EQueueNotFull ---
+ {
+ // pushed packet queue is full -> no action
+ OsTracePrint(
+ KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::Push: queue for the pushed packet is full, queue id: %d"),
+ packet_id_cnxt->iQueueId );
+ }
+ }
+ else // --- iCurrent ---
+ {
+ // we do not have a valid current pointer, which means that all
+ // the packets pending inside the scheduler have a queue full status
+ // tough luck, but we can live with it...
+ if ( iQueueStates[packet_id_cnxt->iQueueId] == EQueueNotFull )
+ {
+ // the pushed packet queue is not full queue
+ // so we shall mark it as the current one
+ iCurrent = free_slot;
+ }
+ }
+
+ if ( iTxPipelineActive && iCurrent )
+ {
+ // packet scheduling feasible
+ // as tx pipeline is active and we have a current packet to be send
+ iPacketSchedulerClient.CallPacketSchedule( aCtxImpl, aMore );
+ }
+
+ if (
+ // push packet signalling to client flagged
+ iFlags & KSignalPushPacket
+ // AND
+ &&
+ // packet scheduler is not full
+ !Full() )
+ {
+ iFlags &= ~KSignalPushPacket;
+ iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl );
+ }
+
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// make internal state as empty
+// ---------------------------------------------------------------------------
+//
+void WlanPacketScheduler::Flush( WlanContextImpl& aCtxImpl )
+ {
+ // remove all pending packet transmission entrys
+ // and call correct completion method for user plane packets
+ OsTracePrint(
+ KPacketScheduler,
+ (TUint8*)("UMAC: WlanPacketScheduler::Flush") );
+
+ for ( TPacketElements::iterator pos = iPacketElements.begin();
+ pos != iPacketElements.end();
+ ++pos )
+ {
+ if ( pos->iFree == EFalse )
+ // slot in use -> complete the packet and release the slot
+ {
+ pos->iFree = ETrue;
+ iPacketSchedulerClient.OnPacketFlushEvent(
+ aCtxImpl,
+ pos->iPacketIdCntx->iFrameId,
+ const_cast<TDataBuffer*>(pos->iPacketIdCntx->iMetaHeader) );
+
+ // as we won't be getting a packet tx completion for this packet
+ // mark also the corresponding packet context free
+ pos->iPacketIdCntx->iFree = ETrue;
+ --iNumOfNotCompletedPackets;
+ }
+ }
+
+ // NOTE: we do not clear other packet ID contexts as there can be pending
+ // packet transmissions, which means we should get packet transmission
+ // callbacks and we must map the context then
+
+ iCurrent = NULL;
+ iNumOfPackets = 0;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanPacketScheduler::SchedulePackets(
+ WlanContextImpl& aCtxImpl,
+ TBool aMore )
+ {
+ if ( !(iTxPipelineActive && iCurrent) )
+ {
+ // nothing to do
+ return;
+ }
+
+ typedef
+ Carray<
+ SPacketIdCntx*,
+ KNumOfElements,
+ EFalse, // no delete pointees
+ NoCopy<SPacketIdCntx*> // disallow copying
+ > TPacketIdCntxsPtrs;
+
+ // this critter stores the xferred packet id contexes in case of
+ // synchronous xfer occurs and we must manullay call
+ // completion method for the frame ids
+ TPacketIdCntxsPtrs packetid_cntxs;
+ TPacketIdCntxsPtrs::iterator pos( packetid_cntxs.begin() );
+
+ WHA::TStatus status ( WHA::KSuccess );
+
+ // send all packets that are feasible for sending
+ // as long as the adpatation layer does not stop
+ // the tx pipeline
+ do
+ {
+ // store current packet id context
+ *pos = iCurrent->iPacketIdCntx;
+
+
+ // trace the frame critter
+ OsTracePrint( KPacketScheduler,
+ (TUint8*)("UMAC: scheduling dot11 packet for tx"),
+ *(reinterpret_cast<const Sdot11MacHeader*>(iCurrent->iPacket)) );
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: queue ID: %d"),
+ (*pos)->iQueueId );
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: frame ID: %d"),
+ (*pos)->iFrameId );
+ OsTracePrint( KPacketScheduler,
+ (TUint8*)("UMAC: WlanPacketScheduler::SchedulePackets: packet id: 0x%08x"),
+ reinterpret_cast<WHA::TPacketId>(*pos) );
+
+ // are multiple packets ready for sending in the same context
+ TBool morePackets ( aMore || MultipleReadyPacketsPending() );
+
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: more: %d"),
+ morePackets );
+
+ // determine and store the current Tx rate & rate policy to be used
+ // with the Tx queue in question
+ //
+ TUint8 txPolicyId ( 0 );
+ aCtxImpl.TxRatePolicy(
+ iCurrent->iPacketIdCntx->iQueueId,
+ iCurrent->iPacketIdCntx->iUseSpecialRatePolicy,
+ iCurrent->iPacketIdCntx->iRequestedTxRate,
+ txPolicyId );
+
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: txRate: 0x%08x"),
+ iCurrent->iPacketIdCntx->iRequestedTxRate );
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: txPolicyId: %d"),
+ txPolicyId );
+
+ const TUint8 KSizeOfTuint32 ( sizeof( TUint32 ) );
+ const TUint8 KOffBy (
+ reinterpret_cast<TUint32>(iCurrent->iPacket) % KSizeOfTuint32 );
+
+ if ( KOffBy )
+ {
+ // The frame start address is not 32 bit aligned. This can
+ // happen e.g. if the frame was left pending during
+ // roaming, and we roamed from a non-QoS nw to a QoS nw, or vice
+ // versa. That makes the alignment to be off by 2 bytes. The only
+ // way to get the start address correctly aligned is to copy the
+ // whole frame. Note, that we always leave enough empty space at
+ // the end of the frame buffer to enable this
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: Frame start address 0x%08x not aligned; fixing it"),
+ reinterpret_cast<TUint32>(iCurrent->iPacket) );
+ os_memcpy(
+ reinterpret_cast<TUint8*>(
+ const_cast<TAny*>(iCurrent->iPacket)) +
+ ( KSizeOfTuint32 - KOffBy ),
+ reinterpret_cast<const TUint8*>(iCurrent->iPacket),
+ iCurrent->iLength );
+
+ iCurrent->iPacket =
+ reinterpret_cast<const TUint8*>(iCurrent->iPacket) +
+ ( KSizeOfTuint32 - KOffBy );
+
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: New frame start address: 0x%08x"),
+ reinterpret_cast<TUint32>(iCurrent->iPacket) );
+ }
+
+ status = aCtxImpl.Wha().SendPacket(
+ iCurrent->iPacket,
+ iCurrent->iLength,
+ iCurrent->iPacketIdCntx->iQueueId,
+ txPolicyId,
+ // note that this value is not relevant when autonomous rate
+ // adaptation is being used
+ iCurrent->iPacketIdCntx->iRequestedTxRate,
+ morePackets,
+ // packet id passed is used as an act to a complex type
+ reinterpret_cast<WHA::TPacketId>(*pos),
+ aCtxImpl.iWlanMib.dot11CurrentTxPowerLevel,
+ aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetime[
+ iCurrent->iPacketIdCntx->iQueueId],
+ NULL );
+
+ // store current time in packet context
+ iCurrent->iPacketIdCntx->iSendReqTimeStamp = os_systemTime();
+
+ ++pos; // next free slot
+ // for the possible following frame submissions within this Tx loop we
+ // cannot use this indication of more frames in UMAC adaptation any more
+ // as it is valid only for the first submission
+ aMore = EFalse;
+
+ OsTracePrint(
+ KPacketScheduler,
+ (TUint8*)("UMAC: WlanPacketScheduler::SchedulePackets: SendPacket status: %d"),
+ status);
+
+ if ( status == WHA::KPending )
+ {
+ // stop the tx pipeline
+ StopTxPipeLine();
+ // packet was accepted for delivery
+ --iNumOfPackets;
+ iCurrent->iFree = ETrue; // mark as free
+ }
+ else if ( status == WHA::KQueueFull )
+ {
+ OsTracePrint(
+ KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SchedulePackets: queue for the current packet is full, queue id: %d"),
+ iCurrent->iPacketIdCntx->iQueueId );
+
+ // packet was discarded
+ // we may schedule from another queue
+ // this is done automatically as we are executing a loop
+ TranmsitQueueFull( iCurrent->iPacketIdCntx->iQueueId );
+
+ // do not clear context as this packet needs to be resend
+ // at some point
+ }
+ else if ( status == WHA::KSuccessXfer )
+ {
+ // synchronous xfer occurred and no packet transfer
+ // method gets called for the packets send in this context,
+ // which means that we must manually call completion method
+ // for all of those packets
+ --iNumOfPackets; // packet was accepted for delivery
+ iCurrent->iFree = ETrue; // mark as free
+
+ // call completion method for all stacked packet id contexes
+ // as they are part of a synchronous xfer
+ for ( TPacketIdCntxsPtrs::iterator beg
+ = packetid_cntxs.begin()
+ ; beg != pos
+ ; ++beg )
+ {
+ iPacketSchedulerClient.OnPacketTransferComplete(
+ aCtxImpl,
+ (*beg)->iFrameId,
+ const_cast<TDataBuffer*>((*beg)->iMetaHeader) );
+ }
+
+ // now as all have been handled
+ // clear the stack by resetting the position
+ // to begin of the buffer
+ pos = packetid_cntxs.begin();
+ }
+ else if ( status == WHA::KSuccess )
+ {
+ // this is the success scenario
+ --iNumOfPackets; // packet was accepted for delivery
+ iCurrent->iFree = ETrue; // mark as free
+ }
+ else if ( status == WHA::KSuccessQueueFull )
+ {
+ // packet was accepted
+ --iNumOfPackets;
+ // ... but the destination queue is now full
+ TranmsitQueueFull( iCurrent->iPacketIdCntx->iQueueId );
+ // we may schedule from another queue
+ // this is done automatically as we are executing a loop
+
+ iCurrent->iFree = ETrue; // mark as free
+ }
+ else
+ {
+ // adaptation programming error
+ OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
+ }
+
+ // select new current packet that is to be transferred,
+ // if such exists
+ SetNextCurrent();
+
+ // stop packet sending if tx pipeleline is stopped or there
+ // is no current packet to be xferred
+ } while ( iCurrent && iTxPipelineActive );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanPacketScheduler::SendPacketTransfer(
+ WlanContextImpl& aCtxImpl,
+ WHA::TPacketId aPacketId )
+ {
+ OsTracePrint(
+ KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SendPacketTransfer: packet id: 0x%08x"),
+ aPacketId);
+
+ // tx pipeline is always activated by this method
+ StartTxPipeLine();
+
+ if ( iCurrent )
+ {
+ // current packet to be xferred exists
+ // notify the client code of this
+ iPacketSchedulerClient.CallPacketSchedule( aCtxImpl, EFalse );
+ }
+
+ // call packet transfer completion method,
+ // with client supplied frame id
+ const SPacketIdCntx* packet_id_cnxt
+ = reinterpret_cast<const SPacketIdCntx*>(aPacketId);
+ iPacketSchedulerClient.OnPacketTransferComplete(
+ aCtxImpl,
+ packet_id_cnxt->iFrameId,
+ const_cast<TDataBuffer*>(packet_id_cnxt->iMetaHeader) );
+
+ if ( // push packet signaling to client flagged
+ iFlags & KSignalPushPacket
+ // AND
+ &&
+ // packet scheduler is not full
+ !Full() )
+ {
+ iFlags &= ~KSignalPushPacket;
+ iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl );
+ }
+
+ if ( // someone is waiting for internal Tx buffer to become available
+ aCtxImpl.InternalTxBufBeingWaited()
+ // AND
+ &&
+ // packet scheduler still is not full
+ !Full() )
+ {
+ aCtxImpl.ClearInternalTxBufBeingWaitedFlag();
+ iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanPacketScheduler::SendPacketComplete(
+ WlanContextImpl& aCtxImpl,
+ WHA::TStatus aStatus,
+ WHA::TPacketId aPacketId,
+ WHA::TRate aRate,
+ TUint32 aPacketQueueDelay,
+ TUint32 aMediaDelay,
+ TUint8 aAckFailures )
+ {
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SendPacketComplete: packet id: 0x%08x"),
+ aPacketId);
+
+ // determine the packet context related to this frame
+ SPacketIdCntx* packet_id_cnxt
+ = reinterpret_cast<SPacketIdCntx*>(aPacketId);
+
+ // calculate Total Tx Delay for this frame.
+ // Using the TUint type for the result is safe
+ const TUint totalTxDelay =
+ os_systemTime() -
+ packet_id_cnxt->iSendReqTimeStamp;
+
+ // as packet has been processed from device transmit queue
+ // mark that queue as not full
+ iQueueStates[packet_id_cnxt->iQueueId] = EQueueNotFull;
+
+ // note the queue via which the packet was transmitted
+ const WHA::TQueueId queueId ( packet_id_cnxt->iQueueId );
+
+ // note the originally requested Tx rate
+ const WHA::TRate requestedTxRate( packet_id_cnxt->iRequestedTxRate );
+
+ // this context can now be reused
+ packet_id_cnxt->iFree = ETrue;
+ --iNumOfNotCompletedPackets;
+
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::SendPacketComplete: the nbr of packets not yet completed by WHA layer is now: %d"),
+ iNumOfNotCompletedPackets );
+
+ // adjust current packet pointer if needed
+ SetCurrentPacket( *packet_id_cnxt );
+
+ if ( iTxPipelineActive && iCurrent )
+ {
+ // packet scheduling feasible
+ // as tx pipeline is active and we have a current packet to be sent
+ iPacketSchedulerClient.CallPacketSchedule( aCtxImpl, EFalse );
+ }
+
+ // notify client of event
+ iPacketSchedulerClient.OnPacketSendComplete(
+ aCtxImpl,
+ aStatus,
+ packet_id_cnxt->iFrameId,
+ aRate,
+ aPacketQueueDelay,
+ aMediaDelay,
+ totalTxDelay,
+ aAckFailures,
+ queueId,
+ requestedTxRate,
+ packet_id_cnxt->iMulticastData );
+
+ if (
+ // push packet signalling to client flagged
+ iFlags & KSignalPushPacket
+ // AND
+ &&
+ // packet scheduler is not full
+ !Full() )
+ {
+ iFlags &= ~KSignalPushPacket;
+ iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanPacketScheduler::GetWhaTxStatus(
+ const WlanContextImpl& aCtxImpl,
+ TWhaTxQueueState& aTxQueueState ) const
+ {
+ if ( aCtxImpl.QosEnabled() )
+ {
+ for ( TUint queueId = 0; queueId < EQueueIdMax; ++queueId )
+ {
+ aTxQueueState[queueId] =
+ static_cast<TTxQueueState>(iQueueStates[queueId]);
+ }
+ }
+ else
+ {
+ for ( TUint queueId = 0; queueId < EQueueIdMax; ++queueId )
+ {
+ aTxQueueState[queueId] =
+ static_cast<TTxQueueState>(iQueueStates[ELegacy]);
+ }
+ }
+
+ return iTxPipelineActive;
+ }
+
+// ---------------------------------------------------------------------------
+// check do we have more than the current packet ready for transmit
+// ---------------------------------------------------------------------------
+//
+TBool WlanPacketScheduler::MultipleReadyPacketsPending()
+ {
+ TUint32 cntr( 0 );
+
+ for ( TPacketElements::iterator pos = iPacketElements.begin()
+ ; pos != iPacketElements.end()
+ ; ++pos )
+ {
+ if ( pos->iFree == EFalse )
+ // element in use
+ {
+ if ( iQueueStates[pos->iPacketIdCntx->iQueueId] == EQueueNotFull )
+ // and in non empty queue
+ {
+ if ( ++cntr > 1 )
+ // multiple entries found
+ {
+ OsTracePrint( KPacketScheduler, (TUint8*)
+ ("UMAC: WlanPacketScheduler::MultipleReadyPacketsPending: multiple pending entries exist for non-full queue(s)") );
+
+ // terminate the loop
+ break;
+ }
+ }
+ }
+ }
+
+ return (cntr > 1);
+ }
+
+// ---------------------------------------------------------------------------
+// select new current packet to be transmitted if one exists
+// ---------------------------------------------------------------------------
+//
+void WlanPacketScheduler::SetNextCurrent()
+ {
+ // no current exist as we setting a new one
+ iCurrent = NULL;
+
+ if ( !iNumOfPackets )
+ {
+ // as no packets exist there can not be a current one
+ return;
+ }
+
+ TPacketElements::iterator pos( iPacketElements.begin() );
+ TUint cntr( iNumOfPackets );
+ while ( cntr )
+ {
+ // process max amount of packets
+ // we have pending inside the scheduler
+ if ( pos->iFree == EFalse )
+ {
+ // element in use -> process it
+
+ if ( iCurrent )
+ {
+ // a current packet exists
+ if (
+ // packet is in non full queue
+ iQueueStates[pos->iPacketIdCntx->iQueueId]
+ == EQueueNotFull
+ // AND
+ &&
+ // has higher prioty than the current packet
+ ( Priority( pos->iPacketIdCntx->iQueueId )
+ > Priority( iCurrent->iPacketIdCntx->iQueueId ) ) )
+ {
+ // which means it is the new current packet
+ iCurrent = pos;
+ }
+ }
+ else // --- iCurrent ---
+ {
+ // there is no current packet
+
+ if (
+ // packet is in non full queue
+ iQueueStates[pos->iPacketIdCntx->iQueueId]
+ == EQueueNotFull )
+ {
+ // which means it is the new current packet
+ iCurrent = pos;
+ }
+ }
+
+ --cntr;
+ }
+ ++pos;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+WlanPacketScheduler::SPacketIdCntx* WlanPacketScheduler::FreePacketIdCntx()
+ {
+ const TPacketIdCntxsPredicate unary_predicate;
+
+ // find first free element
+ SPacketIdCntx* pos
+ = find_if(
+ iPacketIdCntxs.begin(),
+ iPacketIdCntxs.end(),
+ unary_predicate );
+
+ return (pos != iPacketIdCntxs.end() ? pos : NULL);
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+WlanPacketScheduler::SElement* WlanPacketScheduler::FreeElementSlot()
+ {
+ const TElementPredicate unary_predicate;
+
+ // find first free element
+ SElement* pos
+ = find_if(
+ iPacketElements.begin(),
+ iPacketElements.end(),
+ unary_predicate );
+
+ return (pos != iPacketElements.end() ? pos : NULL);
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanPacketScheduler::SetCurrentPacket(
+ const SPacketIdCntx& aCompletedCntx )
+ {
+ TBool skip_current( EFalse );
+
+ if ( iCurrent )
+ {
+ // current packet to be scheduled exists
+
+ if ( Priority( iCurrent->iPacketIdCntx->iQueueId ) >=
+ Priority( aCompletedCntx.iQueueId ) )
+ {
+ // the current packet has at least equal priority as the
+ // processed one, which means that there is no need
+ // to adjust the current pointer
+
+ // skip setting current
+ skip_current = ETrue;
+ }
+ else
+ {
+ // processed packet has a higher priority as the current one,
+ // which means that we have to check do we have packets in that
+ // queue as the new current packet have to be set from those
+ // packets (as they have higher priority)
+ }
+ }
+ else // --- iCurrent ---
+ {
+ // there is no current packet, which means that we have to check do we
+ // have packets in the same queue as the processed one
+ // as the current packet have to be set from those
+ // packets (if any exists)
+ }
+
+ // check and adjust if needed the current packet pointer
+ // to point to the highest prioriy packet in non full transmit queue
+
+ if ( skip_current == EFalse )
+ {
+ TPacketElements::iterator pos( iPacketElements.begin() );
+ TUint cntr( iNumOfPackets );
+ while ( cntr )
+ {
+ // process max amount of packets
+ // we have pending inside the scheduler
+ if ( pos->iFree == EFalse )
+ {
+ // element in use -> process it
+ if ( iCurrent )
+ {
+ // a current packet exists
+
+ if ( // packet is in non full queue
+ iQueueStates[pos->iPacketIdCntx->iQueueId]
+ == EQueueNotFull
+ // AND
+ &&
+ // has higher prioty than the current packet
+ ( Priority( pos->iPacketIdCntx->iQueueId )
+ > Priority( iCurrent->iPacketIdCntx->iQueueId ) ) )
+ {
+ // which means it is the new current packet
+ iCurrent = pos;
+ }
+ }
+ else // --- iCurrent ---
+ {
+ // there is no current packet
+ if ( // packet is in non full queue
+ iQueueStates[pos->iPacketIdCntx->iQueueId]
+ == EQueueNotFull )
+ {
+ // which means it is the new current packet
+ iCurrent = pos;
+ }
+ }
+
+ --cntr;
+ }
+ ++pos;
+ }
+ }
+ }