diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/rfcomm/rfcommframe.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btstack/rfcomm/rfcommframe.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,703 @@ +// Copyright (c) 1999-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: +// + +#include +#include +#include "rfcommframe.h" +#include "rfcommmuxer.h" +#include "rfcommconsts.h" +#include "rfcommutil.h" +#include "rfcommfcs.h" + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_RFCOMM); +#endif + +CRfcommFrame::~CRfcommFrame() + { + iLink.Deque(); + } + +/* + CRfcommCtrlFrame is used for SABM, UA, DISC & DM frames +*/ + +CRfcommCtrlFrame::CRfcommCtrlFrame(CRfcommMuxer& aMux, CRfcommSAP* aSAP) + : CRfcommFrame(aMux, aSAP), + iData(KRfcommCtrlFrameSize) + { + LOG3(_L("RFCOMM: Ctrl Frame 0x%08x created, sap 0x%08x, len %d"), + this, aSAP, iData.Length()); + } + +CRfcommCtrlFrame::CRfcommCtrlFrame(CRfcommMuxer& aMux) + : CRfcommFrame(aMux), + iData(KRfcommCtrlFrameSize) + { + } + +CRfcommCtrlFrame::~CRfcommCtrlFrame() + { + DequeTimer(); + } + +TBool CRfcommCtrlFrame::ResponseNeeded() + { + return iResponseNeeded; + } + +void CRfcommCtrlFrame::QueResponseTimer() + { + if(iResponseNeeded && !iTimerQueued) + { + // Enque this timer + TCallBack cb(TimerExpired, this); + iTimerEntry.Set(cb); + // Timer length dependent on whether this is a SABM for a DLCI other than 0 + BTSocketTimer::Queue( + ( ((iCtrl&~KPollFinalBitmask)==KSABMCtrlField) && ((iAddr>>2)!=KMuxDLCI) + ?KFrameTimerT1SABM:KFrameTimerT1), iTimerEntry); + iTimerQueued=ETrue; + } + } + +void CRfcommCtrlFrame::DequeTimer() + { + if(iTimerQueued) + { + BTSocketTimer::Remove(iTimerEntry); + iTimerQueued=EFalse; + } + } + +TBool CRfcommCtrlFrame::Priority() const + /** + Check whether this RfcommCtrlFrame should + a) jump past the data frames in the queue and + b) be blocked by FCON/FCOFF flow control. + + If the function returns true, the frame will jump and + not be affected by flow control. + **/ + { + //FC ? + switch(iCtrl) + { + case KUIHCBFCCtrlField: + if(!DataLength()) + return ETrue; + default: + break; + } + switch(iCtrl&~KPollFinalBitmask) + { + // + case KUACtrlField: + // Deliberate fall through... + case KDMCtrlField: + // High priority for UAs and DMs + return ETrue; + default: + // Others (i.e. SABMs and DISCs) obey flow control. + return EFalse; + } + // + } + +TInt CRfcommCtrlFrame::TimerExpired(TAny* aFrame) + /** + The T1 timer on a ctrl frame has expired + + This is probably fatal to the mux, and certainly fatal + for any SAP associated with frame. + **/ + { + CRfcommCtrlFrame* frm=static_cast(aFrame); + // Notify the mux that this frame has timed out + LOG2(_L("RFCOMM: Ctrl frame timeout, frame %08x, ctrl %d"), + frm, frm->Ctrl()); + + frm->iTimerQueued=EFalse; + frm->iMuxer.FrameResponseTimeout(frm); + return EFalse; + } + + +void CRfcommCtrlFrame::SetResponseNeeded(TBool aNeed) + { + iResponseNeeded=aNeed; + } + +const TDesC8& CRfcommCtrlFrame::Data() + /** + Returns a reference to the data. + + This function first builds up the data buffer, then sets the length + and the FCS before returning the reference. + **/ + { + __ASSERT_DEBUG(iCtrl != KUIHCtrlField, Panic(ERfcommBadFrameCtrlField)); + __ASSERT_DEBUG(iData.Length()>=4, Panic(ERfcommBadFrameCtrlField)); + LOG1(_L("CRfcommCtrlFrame::Data() - formatting data, length %d"), iData.Length()); + iData[0]=iAddr; + iData[1]=iCtrl; + iData[2]=KRfcommCtrlFrameLengthByte; + iData[3]=CalcFCS(iData.Ptr(), 3); // Calc over all three bytes + return iData; + } + +TInt CRfcommCtrlFrame::Type() const //Shehla - added for ease of Blogging + /** + Returns the typeid for this class + **/ + { + return KCtrlFrameType; + } + +/* + CRfcommUIHFrame is used for all UIH data frames flowing over the link +*/ + +CRfcommUIHFrame* CRfcommUIHFrame::NewL(TInt aInformationLength, CRfcommMuxer& aMux, CRfcommSAP* aSAP) + { + CRfcommUIHFrame* self=new(ELeave) CRfcommUIHFrame( aMux, aSAP); + CleanupStack::PushL(self); + self->ConstructDataBufferL(aInformationLength); + CleanupStack::Pop(); // self + LOG2(_L("RFCOMM: Data Frame 0x%08x created, sap 0x%08x"), self, aSAP); + return self; + } + +CRfcommUIHFrame::CRfcommUIHFrame(CRfcommMuxer& aMux, CRfcommSAP* aSAP) + : CRfcommFrame(aMux, aSAP) + { + } + +CRfcommUIHFrame::~CRfcommUIHFrame() + { + delete iData; + } + +void CRfcommUIHFrame::ConstructDataBufferL(TInt aInformationLength) + /** + Allocate the data buffer to hold the information that will be placed in this frame. + + An allowance is made for the KMaxFrameHeaderLength, ie. addr, ctrl , 2*len = 4 octets + **/ + { + iData=HBufC8::NewL(aInformationLength+KMaxFrameOverhead); + // Reserve max possible space for addr, control, length, and fcs at end + for(TUint8 i=0;i((*iData).Length()-overhead); + return length; + } + +void CRfcommUIHFrame::PutByte(TUint8 aByte) + { + iData->Des().Append(aByte); + } + +void CRfcommUIHFrame::PutLittleEndian16(TUint16 aVal) + { + TUint8* ptr=const_cast((*iData).Ptr()); + ptr+=(*iData).Length(); + iData->Des().SetLength((*iData).Length()+2); + LittleEndian::Put16(ptr, aVal); + } + +void CRfcommUIHFrame::PutLittleEndian32(TUint32 aVal) + { + TUint8* ptr=const_cast((*iData).Ptr()); + ptr+=(*iData).Length(); + iData->Des().SetLength((*iData).Length()+4); + LittleEndian::Put32(ptr, aVal); + } + +void CRfcommUIHFrame::PutData(const TDesC8& aDes) + { + iData->Des().Append(aDes); + } + +const TDesC8& CRfcommUIHFrame::Data() + /** + Build the data frame, then return it + + **/ + { + if(!iFramePrepared) + PrepareDataFrame(); + return iReturnedFrame; + } + +void CRfcommUIHFrame::PrepareDataFrame() + /** + Build the data frame and return it + + Fill in the address, ctrl and length fields, then add the FCS + Don't do any asserts on the basic parts since this can be used + by derived classes. + + An additional complication here is that the length field may + be either 1 or 2 octets, depending on the length of the data + field. + **/ + { + //TUint length=static_cast((*iData).Length()-KMaxFrameHeaderLength); + TUint length = DataLength(); + TPtr8 rwData=iData->Des(); + TInt offset=0; + if(length<=127) + { + // Note the length dependent offset for the Address and Control Octets + offset=1; + // length will be just the 4th octet in the buffer, + // of which we will return everything from the + // second octet onwards... + rwData[3]=static_cast(length<<1 | 1); // Set the E/A bit to 1 + } + else + { + // length will be in both the 3rd and 4th octet in the buffer. + // length is stored as follows; + // + // Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7 Bit 8 + // Octet 1 E/A L1 L2 L3 L4 L5 L6 L7 + // Octet 2 L8 L9 L10 L11 L12 L13 L14 L15 + offset=0; + rwData[2]=static_cast((length & 0x7F)<<1); + rwData[3]=static_cast((length>>7) & 0xFF); + } + + rwData[offset]=iAddr; + rwData[1+offset]=KUIHCtrlField; + rwData.Append(CalcFCS((*iData).Ptr()+offset, 2)); // Calc over two bytes + iReturnedFrame.Set((*iData).Right((*iData).Length()-offset)); + iFramePrepared=ETrue; + } + +void CRfcommUIHFrame::PutByteAt(TInt aOffset, TUint8 aByte) + /** + Insert this byte in the data part of the packet at the + position specified + + @param aOffset The index into the data part of the packet + (after the length field) + **/ + { + (iData->Des())[KMaxFrameHeaderLength+aOffset]=aByte; + } + + + + + + +/* + CRfcommDataFrame is used for UIH data frames designed to carry information +*/ + +CRfcommDataFrame* CRfcommDataFrame::NewL(TInt aInformationLength, CRfcommMuxer& aMux, CRfcommSAP* aSAP) + { + CRfcommDataFrame* self=new(ELeave) CRfcommDataFrame( aMux, aSAP); + CleanupStack::PushL(self); + self->ConstructDataBufferL(aInformationLength); + CleanupStack::Pop(); // self + LOG2(_L("RFCOMM: Data Frame 0x%08x created, sap 0x%08x"), self, aSAP); + return self; + } + +CRfcommDataFrame::CRfcommDataFrame(CRfcommMuxer& aMux, CRfcommSAP* aSAP) + : CRfcommUIHFrame(aMux, aSAP) + { + } + +CRfcommDataFrame::~CRfcommDataFrame() + { + } + + +void CRfcommDataFrame::ConstructDataBufferL(TInt aInformationLength) + /** + Allocate the data buffer to hold the information that will be placed in this frame. + + An allowance is made for the KMaxFrameHeaderLength, ie. addr, ctrl , 2*len = 4 octets + **/ + { + // Reserve max possible space for addr, cont, length + iData=HBufC8::NewL(aInformationLength+KMaxFrameOverhead); + for(TUint8 i=0;i((*iData).Length()-KMaxFrameHeaderLength); + TUint length = DataLength(); + TPtr8 rwData=iData->Des(); + TInt offset=0; + if(length<=127) + { + // Note the length dependent offset for the Address and Control Octets + offset=1; + // length will be just the 4th octet in the buffer, + // of which we will return everything from the + // second octet onwards... + rwData[3]=static_cast(length<<1 | 1); // Set the E/A bit to 1 + } + else + { + // length will be in both the 3rd and 4th octet in the buffer. + // length is stored as follows; + // + // Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7 Bit 8 + // Octet 1 E/A L1 L2 L3 L4 L5 L6 L7 + // Octet 2 L8 L9 L10 L11 L12 L13 L14 L15 + offset=0; + rwData[2]=static_cast((length & 0x7F)<<1); + rwData[3]=static_cast((length>>7) & 0xFF); + } + + rwData[offset]=iAddr; + rwData[1+offset]=KUIHCtrlField; + rwData.Append(CalcFCS((*iData).Ptr()+offset, 2)); // Calc over two bytes + iReturnedFrame.Set((*iData).Right((*iData).Length()-offset)); + iFramePrepared=ETrue; + } + + + + +/* + CRfcommCreditDataFrame is used for UIH data frames designed to carry information and supply credits +*/ + +CRfcommCreditDataFrame* CRfcommCreditDataFrame::NewL(TInt aInformationLength, CRfcommMuxer& aMux, CRfcommSAP* aSAP) + { + CRfcommCreditDataFrame* self=new(ELeave) CRfcommCreditDataFrame( aMux, aSAP); + CleanupStack::PushL(self); + self->ConstructDataBufferL(aInformationLength); + CleanupStack::Pop(); // self + LOG2(_L("RFCOMM: Data Frame 0x%08x created, sap 0x%08x"), self, aSAP); + return self; + } + +CRfcommCreditDataFrame::CRfcommCreditDataFrame(CRfcommMuxer& aMux, CRfcommSAP* aSAP) + : CRfcommDataFrame(aMux, aSAP) + { + } + +CRfcommCreditDataFrame::~CRfcommCreditDataFrame() + { + } + +TInt CRfcommCreditDataFrame::Type() const + { + return KCreditDataFrameType; + } + +void CRfcommCreditDataFrame::SetCredit(TUint8 aCredit) + /** + Add the credit to an outgoing UIH frame + **/ + { + iCredit = aCredit; + } + +TUint8 CRfcommCreditDataFrame::Credit() const + { + return iCredit; + } + + +TUint16 CRfcommCreditDataFrame::DataLength() const + { + TInt overhead = iFramePrepared?KMaxFrameCreditOverhead:KMaxCreditFrameHeaderLength; + TUint16 length=static_cast((*iData).Length()-overhead); + return length; + } + +void CRfcommCreditDataFrame::ConstructDataBufferL(TInt aInformationLength) + /** + Allocate the data buffer to hold the information that will be placed in this frame. + + An allowance is made for the KMaxFrameHeaderLength, ie. addr, ctrl, 2*len, credit = 5 octets + **/ + { + // Reserve max possible space for addr, cont, length + iData=HBufC8::NewL(aInformationLength+KMaxFrameCreditOverhead); + for(TUint8 i=0;i((*iData).Length()-KMaxCreditFrameHeaderLength); + TUint length = DataLength(); + TPtr8 rwData=iData->Des(); + TInt offset=0; + rwData[4]=iCredit; // we're going backwards, credit is after length + if(length<=127) + { + // Note the length dependent offset for the Address and Control Octets + offset=1; + // length will be just the 4th octet in the buffer, + // of which we will return everything from the + // second octet onwards... + rwData[3]=static_cast(length<<1 | 1); // Set the E/A bit to 1 + } + else + { + // length will be in both the 3rd and 4th octet in the buffer. + // length is stored as follows; + // + // Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7 Bit 8 + // Octet 1 E/A L1 L2 L3 L4 L5 L6 L7 + // Octet 2 L8 L9 L10 L11 L12 L13 L14 L15 + offset=0; + rwData[2]=static_cast((length & 0x7F)<<1); + rwData[3]=static_cast((length>>7) & 0xFF); + } + + rwData[offset]=iAddr; + rwData[1+offset]=KUIHCBFCCtrlField; + rwData.Append(CalcFCS((*iData).Ptr()+offset, 2)); // Calc over two bytes + iReturnedFrame.Set((*iData).Right((*iData).Length()-offset)); + iFramePrepared=ETrue; + } + + + +/* + CRfcommMuxCtrlFrame is used for frames carrying mux control + commands on the mux control channel (DLCI 0) +*/ + +CRfcommMuxCtrlFrame* CRfcommMuxCtrlFrame::NewL(TUint8 aCommandValuesLength, CRfcommMuxer& aMux, CRfcommSAP* aSAP) + { + CRfcommMuxCtrlFrame* self=new(ELeave) CRfcommMuxCtrlFrame(aCommandValuesLength, aMux, aSAP); + CleanupStack::PushL(self); + self->ConstructDataBufferL(aCommandValuesLength); + CleanupStack::Pop(); // self + LOG2(_L("RFCOMM: Mux Ctrl Frame 0x%08x created, sap 0x%08x"), self, aSAP); + + return self; + } + +void CRfcommMuxCtrlFrame::ConstructDataBufferL(TInt aCommandValuesLength) + /** + Allocate the data buffer to hold the command that will be + placed in this frame. + + This function takes the number of value octets required by the + command and adds on the appropriate number of octets to allow + for the type and length fields + **/ + { + CRfcommUIHFrame::ConstructDataBufferL(aCommandValuesLength+KShortMuxCommandHeaderLength); + // Reserve space for command type and command length + for(TUint8 i=0;i(aFrame); + // Notify the mux that this frame has timed out + LOG2(_L("RFCOMM: MuxCtrl frame timeout, frame %08x, command %d"), + frm, frm->CommandType()); + /* + BLOG: Timeout on command: + TUint8 command = frm->CommandType(); + switch(command) + { + case KTestType + //KBlogTestCommand + break; + case KPNType + //KBlogPN + break; + case KRPNType + //KBlogRPN + break; + case KFConType + //KBlogFcOn + break; + case KFCoffType + //KBlogFcOff + break; + case KMSCType + //KBlogMSC + break; + case KNSCType + //KBlogNSC + break; + case KRLSType + //KBlogRLS + break; + }; + + //BLOG: MuxCtrl frame timeout, + */ + + frm->iTimerQueued=EFalse; + frm->iMuxer.FrameResponseTimeout(frm); + return EFalse; + } + + +#pragma warning(disable : 4244) // conversion from int to unsigned char + +void CRfcommMuxCtrlFrame::SetCommandType(TUint8 aType, TBool aCommand) + { + iCommandType=(aType << 1) | (aCommand ? 1 : 0); + } + +TUint8 CRfcommMuxCtrlFrame::CommandType() const + { + return iCommandType >> 1; + } + +void CRfcommMuxCtrlFrame::PrepareDataFrame() + /** + Prepare the Mux ctrl frame to be transmitted. + + We add the command type, command length before using the normal + UIH frame PrepareDataFrame to add the normal headers+FCS + **/ + { + __ASSERT_DEBUG((iAddr & 0xfc) == 0, Panic(ERfcommBadFrameAddrField)); + __ASSERT_DEBUG(iCtrl == KUIHCtrlField, Panic(ERfcommBadFrameCtrlField)); + TUint8 byte; + byte= (iCommandType << 1) | 0x01; // add EA bit + PutByteAt(0, byte); + byte=(iCommandLength << 1) | 0x01; // add EA bit + PutByteAt(1, byte); + CRfcommUIHFrame::PrepareDataFrame(); + } + +#pragma warning(default : 4244)