--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bthci/hci2implementations/hctls/bcsp/src/hctlbcspFrameQueue.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,727 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "hctlbcspFrameQueue.h"
+
+#include "hctlbcsp.h"
+#include "hctlbcspconsts.h"
+#include "hctlbcspsequencer.h"
+#include "bcsputils.h"
+#include "debug.h"
+#include "hctlbcspframe.h"
+
+CHCTLBcspWindow::CHCTLBcspWindow(TInt aWindowSize, TInt aNumberOfSeqIds)
+ : iEndOfWindow(aWindowSize - 1),
+ iWindowSize(aWindowSize),
+ iNumberOfSeqIds(aNumberOfSeqIds),
+ iFrameQue(_FOFF(CTxHctlBcspFrame,iLink))
+ {
+ LOG_FUNC
+ }
+
+CHCTLBcspWindow* CHCTLBcspWindow::NewL(TInt aWindowSize, TInt aFrameSize, TInt aNumberOfSeqIds)
+ {
+ LOG_STATIC_FUNC
+
+ CHCTLBcspWindow *self = new (ELeave) CHCTLBcspWindow(aWindowSize, aNumberOfSeqIds);
+ CleanupStack::PushL(self);
+ self->ConstructL(aFrameSize);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CHCTLBcspWindow::ConstructL(TInt aFrameSize)
+ {
+ LOG_FUNC
+
+ for(TInt i=0;i<iWindowSize;i++)
+ {
+ CTxHctlBcspFrame *frame = CTxHctlBcspFrame::NewL(aFrameSize);
+ frame->Reset();
+ iFrameQue.AddLast(*frame);
+
+#ifdef _DEBUG_WINDOW
+ LOG1(_L8("frame added 0x%08x"),frame);
+#endif
+ }
+#ifdef _DEBUG_WINDOW
+ TraceWindowVars();
+ TraceQueue();
+#endif
+ }
+
+CHCTLBcspWindow::~CHCTLBcspWindow()
+ {
+ LOG_FUNC
+
+ for (TInt i=0;i<iWindowSize;i++)
+ {
+ CTxHctlBcspFrame* frame = iFrameQue.First();
+ iFrameQue.Remove(*frame);
+ delete frame;
+ }
+ }
+
+TInt CHCTLBcspWindow::StartOfWindow() const
+ {
+ LOG_FUNC
+
+ return iStartOfWindow;
+ }
+
+TInt CHCTLBcspWindow::ToSeqId(TInt aIndex) const
+ {
+ LOG_FUNC
+
+ return (aIndex + iStartOfWindow)%iNumberOfSeqIds;
+ }
+
+TInt CHCTLBcspWindow::ToWindowIndex(TInt aSeqId) const
+ {
+ LOG_FUNC
+
+ TInt index = aSeqId - iStartOfWindow;
+ if ( index < 0 )
+ {
+ index += iNumberOfSeqIds;
+ }
+ return index;
+ }
+
+void CHCTLBcspWindow::IncrementSeqId(TInt &aSeqId) const
+ {
+ aSeqId++;
+ aSeqId %= iNumberOfSeqIds;
+ }
+
+
+CTxHctlBcspFrame* CHCTLBcspWindow::GetFrame(TInt aIndex)
+/**
+ Method to retrieve a frame for transmission
+*/
+ {
+ LOG_FUNC
+
+ __TEST_INVARIANT;
+
+ TInt index = ToWindowIndex(aIndex);
+ __ASSERT_DEBUG((index>=0) && (index<iWindowSize), PANIC(KBcspPanicCat, EBadBcspFrame));
+
+ TSglQueIter<CTxHctlBcspFrame> iter(iFrameQue);
+ CTxHctlBcspFrame* frame = iter++;
+
+ while ( index > 0 )
+ {
+ frame = iter++;
+ index--;
+ }
+
+#ifdef _DEBUG_WINDOW
+ LOG2(_L8("frame got 0x%08x (index:%d)"), frame, aIndex);
+#endif
+
+ return frame;
+ }
+
+TInt CHCTLBcspWindow::FreeFrames()
+/**
+ Method to free up space in transmit queue for sending more BCSP frames
+*/
+ {
+ LOG_FUNC
+
+ __TEST_INVARIANT;
+
+ return ToWindowIndex(iEndOfWindow) - ToWindowIndex(iWritePosition);
+ }
+
+CTxHctlBcspFrame *CHCTLBcspWindow::WriteFrame()
+/**
+ Method to Write a frame to the frame queue
+*/
+ {
+ LOG_FUNC
+
+ CTxHctlBcspFrame *frame = NULL;
+
+ __TEST_INVARIANT;
+
+ if ( iWritePosition != iEndOfWindow )
+ {
+ frame = GetFrame(iWritePosition);
+
+ if(frame)
+ {
+ IncrementSeqId(iWritePosition);
+ // Make sure we're not returning a valid frame to be overwritten
+ __ASSERT_DEBUG(!frame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame));
+ }
+ else
+ {
+ #ifdef _DEBUG_WINDOW
+ FTRACE(FPrintBCSP(_L("Bcsp frame queue blocked (panic now deprecated)")));
+ #endif
+ }
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Post Write"));
+ TraceWindowVars();
+ TraceQueue();
+#endif
+ }
+
+ __TEST_INVARIANT;
+
+ return frame;
+ }
+
+CTxHctlBcspFrame *CHCTLBcspWindow::ReadFrame()
+/**
+ Method to read a frame from the Transmit Queue
+
+ @return CTxHctlBcspFrame * frame
+*/
+ {
+ LOG_FUNC
+
+ CTxHctlBcspFrame *frame = NULL;
+
+ __TEST_INVARIANT;
+
+ if ( iReadPosition != iWritePosition )
+ {
+ frame = GetFrame(iReadPosition);
+ frame->SetSequence(static_cast<TUint8>(iReadPosition));
+
+ if (iReadPosition == iHighReadPosition)
+ {
+ IncrementSeqId(iHighReadPosition);
+ }
+ IncrementSeqId(iReadPosition);
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Post Read"));
+ TraceWindowVars();
+ TraceQueue();
+#endif
+ // Make sure we're returning a valid frame to be used
+ __ASSERT_DEBUG(frame->IsValid(), PANIC(KBcspPanicCat, EBadBcspFrame));
+ }
+
+ __TEST_INVARIANT;
+
+ return frame;
+}
+
+TBool CHCTLBcspWindow::Acknowledged(TInt aAckNo)
+/**
+ Method to handle TxFrame acknowledgement
+ Remove the frame that is acknowledged
+ @param current Rx Ack value, KErrTimedOut if ack timed out
+*/
+ {
+ LOG_FUNC
+
+ TBool framesRemainingInWindow = EFalse;
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Pre Ack"));
+ TraceWindowVars();
+#endif
+
+ __TEST_INVARIANT;
+
+ const TBool resetWindow = ((aAckNo >= 0) && (ToWindowIndex(aAckNo) > ToWindowIndex(iHighReadPosition))) ? ETrue : EFalse;
+
+ if (resetWindow)
+ {
+#ifdef _DEBUG_WINDOW
+ LOG1(_L8("Ack for unsent packet (%d), resetting entire window!!!"), aAckNo);
+#endif
+ // reset frames
+ TSglQueIter<CTxHctlBcspFrame> iter(iFrameQue);
+ CTxHctlBcspFrame *frame = iter++;
+
+ while (iter)
+ {
+ frame->Reset();
+ frame = iter++;
+ }
+
+ //reset window variables
+ iStartOfWindow = aAckNo;
+ iStartOfWindow %= iNumberOfSeqIds;
+
+ iEndOfWindow = iStartOfWindow + iWindowSize-1;
+ iEndOfWindow %= iNumberOfSeqIds;
+
+ iWritePosition = iHighReadPosition = iReadPosition = iStartOfWindow;
+
+ framesRemainingInWindow = ETrue;
+ }
+ else if (iReadPosition != iStartOfWindow) // frames waiting to be acknowledged
+ {
+ LOG1(_L("Ack(%d)"), aAckNo);
+
+ if ( aAckNo >= 0 )
+ {
+ aAckNo %= iNumberOfSeqIds; // Make sure we wrap around at the end of the window
+ LOG1(_L8("Ack(%d)"), aAckNo);
+
+ // TInt readIndex = ackWindowIndex;
+ TBool found = EFalse;
+ TInt i = iStartOfWindow;
+
+ while(!found && (i != iEndOfWindow))
+ {
+ if((i == aAckNo))
+ {
+ found = ETrue;
+ }
+ else if(!found)
+ {
+ // This frame is before the ackWindowIndex therefore we should reset it
+ CTxHctlBcspFrame* frame = iFrameQue.First();
+ frame->Reset();
+ iFrameQue.Remove(*frame);
+ iFrameQue.AddLast(*frame);
+ }
+ IncrementSeqId(i);
+ }
+
+ iStartOfWindow = aAckNo;
+ iStartOfWindow %= iNumberOfSeqIds;
+
+ iEndOfWindow = iStartOfWindow + iWindowSize - 1;
+ iEndOfWindow %= iNumberOfSeqIds;
+ }
+
+ // We've just had an acknowledgement so we need to resend from the start of the buffer
+ iReadPosition = iStartOfWindow;
+
+ // We've just rationalised the window. The write position can remain where it was.
+ framesRemainingInWindow = ETrue;
+ }
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L("Post Ack"));
+ TraceWindowVars();
+ TraceQueue();
+#endif
+
+ __TEST_INVARIANT;
+
+ return framesRemainingInWindow;
+ }
+
+void CHCTLBcspWindow::__DbgTestInvariant(void) const
+/**
+ Debug method
+*/
+ {
+ // Check that the class is internally consistent
+ __ASSERT_DEBUG(iNumberOfSeqIds>0, User::Invariant());
+ __ASSERT_DEBUG((iWindowSize>0) && (iWindowSize <= iNumberOfSeqIds), User::Invariant());
+
+ __ASSERT_DEBUG((iStartOfWindow>=0) && (iStartOfWindow<=iNumberOfSeqIds), User::Invariant());
+ __ASSERT_DEBUG((iEndOfWindow>=0) && (iEndOfWindow<=iNumberOfSeqIds), User::Invariant());
+ __ASSERT_DEBUG((iReadPosition>=0 ) && (iReadPosition<=iNumberOfSeqIds), User::Invariant());
+ __ASSERT_DEBUG((iHighReadPosition>=0 ) && (iHighReadPosition<=iNumberOfSeqIds),User::Invariant());
+ __ASSERT_DEBUG((iWritePosition>=0) && (iWritePosition<=iNumberOfSeqIds), User::Invariant());
+
+ TInt winSize = iEndOfWindow - iStartOfWindow + 1;
+ if ( winSize < 0 )
+ {
+ winSize += iNumberOfSeqIds;
+ }
+ __ASSERT_DEBUG(winSize == iWindowSize, User::Invariant());
+ if ( iWritePosition != iEndOfWindow )
+ {
+ __ASSERT_DEBUG(ToWindowIndex(iReadPosition) <= ToWindowIndex(iHighReadPosition), User::Invariant());
+ __ASSERT_DEBUG(ToWindowIndex(iHighReadPosition) <= ToWindowIndex(iWritePosition), User::Invariant());
+ }
+ }
+
+#ifdef _DEBUG_WINDOW
+void CHCTLBcspWindow::TraceWindowVars() const
+/**
+ Debug method
+*/
+ {
+ LOG_FUNC
+ RProcess process;
+ RThread thread;
+ TName pName = process.Name();
+ TName tName = thread.Name();
+ LOG1(_L8("Process : %S"), &pName);
+ LOG1(_L8("Thread : %S"), &tName);
+ LOG6(_L8("this : 0x%08x SOW : %d, RP : %d, HRP: %d, WP : %d, EOW :%d"),this, iStartOfWindow, iReadPosition, iHighReadPosition, iWritePosition, iEndOfWindow);
+ }
+
+void CHCTLBcspWindow::TraceQueue()
+/**
+ Debug method
+*/
+ {
+ LOG_FUNC
+ LOG1(_L8("Queue Dumping this 0x%08x"), this);
+ TSglQueIter<CTxHctlBcspFrame> iter(iFrameQue);
+ CTxHctlBcspFrame *frame = iter++;
+
+ _LIT(KSpace, " ");
+ _LIT(KWriteMarker, "W");
+ _LIT(KHighMarker, "H");
+ _LIT(KReadMarker, "R");
+
+ TInt index = 0;
+ while ( index < iWindowSize )
+ {
+ LOG6(_L8("%S %S %S this: 0x%08x, frame : 0x%08x, %d"),
+ (index == ToWindowIndex(iWritePosition)) ? &KWriteMarker : &KSpace,
+ (index == ToWindowIndex(iHighReadPosition)) ? &KHighMarker : &KSpace,
+ (index == ToWindowIndex(iReadPosition)) ? &KReadMarker : &KSpace,
+ this,
+ frame,
+ frame->IsValid()
+ );
+ frame = iter++;
+ index++;
+ }
+ }
+#endif
+
+void CHCTLBcspWindow::Reset()
+ {
+ LOG_FUNC
+
+ for(TInt i=0;i<iWindowSize;i++)
+ {
+ CTxHctlBcspFrame* frame = iFrameQue.First();
+ frame->Reset();
+ iFrameQue.Remove(*frame);
+ iFrameQue.AddLast(*frame);
+
+#ifdef _DEBUG_WINDOW
+ LOG1(_L8("frame reset 0x%08x"),frame);
+#endif
+ }
+
+ iStartOfWindow = 0;
+ iReadPosition = 0;
+ iHighReadPosition = 0;
+ iWritePosition = 0;
+ iEndOfWindow = iWindowSize - 1;
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Reset"));
+
+ TraceWindowVars();
+ TraceQueue();
+#endif
+ }
+
+/* *********************************************************************************************
+ * Frame Queue - Manages the frame queues for both Reliable and Unreliable data transfer
+ * ********************************************************************************************* */
+CHCTLBcspFrameQueue* CHCTLBcspFrameQueue::NewL(CHCTLBcsp &aBcsp)
+ {
+ LOG_STATIC_FUNC
+
+ CHCTLBcspFrameQueue *self = new (ELeave) CHCTLBcspFrameQueue(aBcsp);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CHCTLBcspFrameQueue::ConstructL()
+ {
+ LOG_FUNC
+
+ // Create the queues
+ iReliableQueue = CHCTLBcspWindow::NewL(KBcspReliableWindowSize,
+ KMaxReliablePayloadSize,
+ KMaxBcspWindowSize);
+
+ iUnreliableQueue = CHCTLBcspWindow::NewL(KBcspUnreliableQueueSize,
+ KMaxUnreliablePayloadSize,
+ KBcspUnreliableQueueSize+1);
+
+ // Room for Slip encoded packet is twice the size of a full BCSP Packet + 2 for the 0xC0 bytes
+ iSlipEncodedFrame = HBufC8::NewL(2 + ((KMaxReliablePayloadSize + KBcspHeaderBytes + KBcspCrcBytes) * 2));
+ }
+
+CHCTLBcspFrameQueue::CHCTLBcspFrameQueue(CHCTLBcsp& aBcsp)
+ : iBcsp(aBcsp)
+ {
+ LOG_FUNC
+ }
+
+CHCTLBcspFrameQueue::~CHCTLBcspFrameQueue()
+
+ {
+ LOG_FUNC
+
+ delete iUnreliableQueue;
+ delete iReliableQueue;
+ delete iSlipEncodedFrame;
+ }
+
+
+void CHCTLBcspFrameQueue::SetSequencer(CHCTLBcspSequencer& aSequencer)
+/**
+ Simple method to initialise iSequencer with @param &aSequencer
+*/
+ {
+ LOG_FUNC
+
+ iSequencer = &aSequencer;
+ }
+
+TInt CHCTLBcspFrameQueue::GetNextFrame(TDesC8* &aFrame, TBool& aIsReliable)
+/**
+ Method to get the next frame from the frame queue and then to build and slip encode it
+
+ @param &aFrame
+ @param aIsReliable a reference to a TBool which will be set to ETrue if the
+ Frame is from the reliable queue.
+ @return err
+*/
+ {
+ LOG_FUNC
+
+ TInt err = KErrNone;
+
+ CTxHctlBcspFrame *frame = iUnreliableQueue->ReadFrame();
+
+ if ( frame )
+ {
+ // Got unreliable frame
+ iUnreliableQueue->Acknowledged(iUnreliableQueue->StartOfWindow()+1); // Remove the first frame from the window
+ frame->SetSequence(0);
+ aIsReliable = EFalse;
+ }
+ else
+ {
+ // Couldn't get an unreliable frame, so ... get a reliable frame
+ frame = iReliableQueue->ReadFrame();
+
+ if ( !frame )
+ {
+ // We can't get a reliable frame either
+ err = KErrBcspNothingToSend;
+ aIsReliable = EFalse;
+ }
+ else
+ {
+ // We've got a reliable frame - increment the retry count
+ frame->IncrementRetries();
+ frame->SetFlags(iSequencer->TxAck(), ETrue, ETrue);
+ if ( frame->Retries() >= KTxRetryLimit )
+ {
+ err = KErrBcspMaxRetries;
+ }
+
+ aIsReliable = ETrue;
+ }
+ }
+
+ if ( !err )
+ {
+ // No errors so far, so SlipEncode the frame into iSlipEncodedFrame
+ frame->BuildFrame();
+ frame->SlipEncodeFrame(iSlipEncodedFrame->Des());
+ aFrame = iSlipEncodedFrame;
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Got Frame"));
+ LOGHEXRAW(frame->Payload().Ptr(), frame->PayloadLength());
+
+ LOG(_L8("Slip Encoded Frame"));
+ LOGHEXRAW(aFrame->Ptr(), aFrame->Length());
+#endif
+ }
+ else
+ {
+ // Just in case our return code is ignored :->
+ aFrame = NULL;
+ }
+
+ return err;
+ }
+
+TBool CHCTLBcspFrameQueue::AckReceived(TInt aAckValue)
+/**
+ Handle AckReceived @param aAckValue
+
+ call Acknowledged method on relaible queue
+ call CanSend()
+
+ @return ETrue if there are unacknowledged packets remaining
+ in the tx window.
+*/
+ {
+ LOG_FUNC
+
+ TBool ret=iReliableQueue->Acknowledged(aAckValue);
+ CanSend();
+ return ret;
+ }
+
+void CHCTLBcspFrameQueue::AckTimeout()
+/**
+ Handle Rx Ack timeout
+
+ Inform reliable queue to resend frame
+ CanSend
+ Call iSequencer->WakeUp() to trigger the sequencer to pull frames for resending from the
+ reliable frame queue
+*/
+ {
+ LOG_FUNC
+
+ iReliableQueue->Acknowledged(KErrTimedOut);
+ CanSend();
+ iSequencer->WakeUp();
+ }
+
+TInt CHCTLBcspFrameQueue::AddReliableFrame(const TDesC8 &aData, TUint8 aProtocolId)
+/**
+ Method to add a frame to the Tx Reliable queue
+ @param aData - HCI payload
+ @param aProtocolId - ProtocolId eg. ACL, Command
+*/
+ {
+ TInt err = KErrNone;
+ LOG_FUNC
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Adding Frame to Reliable Queue"));
+ LOGHEXDESC(aData);
+#endif
+
+ CTxHctlBcspFrame *frame=iReliableQueue->WriteFrame();
+
+ // A NULL frame is now returned if (on the rare occasion) the frame queue has become blocked.
+ // The original panic has been replaced by an upward error handling path.
+ if (!frame)
+ {
+ err = KErrOverflow;
+ }
+ else
+ {
+ frame->SetProtocolId(aProtocolId);
+ frame->SetPayload(aData);
+ iSequencer->WakeUp();
+ }
+
+ CanSend();
+ return err;
+
+ }
+
+void CHCTLBcspFrameQueue::AddUnreliableFrame(const TDesC8 &aData, TUint8 aProtocolId,
+ TUint8 aAck,
+ TBool aCRCEnabled)
+/**
+ Method to add an Unreliable frame to the unreliable frame queue
+
+ @param aData - HCI payload
+ @param aProtocolId
+ @param aAck
+ @param aCRCState
+
+ Calls wakeup method on the sequencer to trigger frame sending
+*/
+ {
+ LOG_FUNC
+
+ CTxHctlBcspFrame *frame=iUnreliableQueue->WriteFrame();
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Adding Frame to Unreliable Queue"));
+#endif
+
+ LOGHEXDESC(aData);
+ if ( frame )
+ {
+ frame->SetProtocolId(aProtocolId);
+ frame->SetPayload(aData);
+ frame->SetFlags(aAck, aCRCEnabled, EFalse);
+ }
+ // else we've got no free slots - therefore since this is an unreliable Frame we can
+ // just throw it away
+
+ iSequencer->WakeUp();
+ }
+
+void CHCTLBcspFrameQueue::AddUnreliableFrame(TUint8 aProtocolId,
+ TUint8 aAck,
+ TBool aCRCEnabled)
+/**
+ Method to add an empty Unreliable frame to the unreliable frame queue
+ eg. an AckFrame
+
+ @param aProtocolId
+ @param aAck
+ @param aCRCState
+
+*/
+ {
+ LOG_FUNC
+
+ CTxHctlBcspFrame *frame=iUnreliableQueue->WriteFrame();
+
+#ifdef _DEBUG_WINDOW
+ LOG(_L8("Adding Empty Frame to Unreliable Queue"));
+#endif
+
+ if ( frame )
+ {
+ frame->SetProtocolId(aProtocolId);
+ frame->SetPayload();
+ frame->SetFlags(aAck, aCRCEnabled, EFalse);
+ }
+ // else we've got no free slots - therefore since this is an unreliable Frame we can
+ // just throw it away
+
+ iSequencer->WakeUp();
+
+ }
+
+void CHCTLBcspFrameQueue::Reset()
+ {
+ LOG_FUNC
+
+ iReliableQueue->Reset();
+ iUnreliableQueue->Reset();
+ }
+
+void CHCTLBcspFrameQueue::CanSend()
+/**
+ Kicks packet router
+ Only reliable queue is checked here for availability because we don't want to flow control
+ the unreliable packets. Unreliable packets are simply dropped when the queue is full.
+*/
+ {
+ LOG_FUNC
+
+ iBcsp.CanSend(iReliableQueue->FreeFrames()>0);
+ }