--- /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 <bluetooth/logger.h>
+#include <es_sock.h>
+#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<CRfcommCtrlFrame*>(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<KMaxFrameOverhead-1;++i)
+ PutByte(0x00);
+ }
+
+TInt CRfcommUIHFrame::Type() const
+ {
+ return KDataFrameType;
+ }
+
+TBool CRfcommUIHFrame::ResponseNeeded()
+ {
+ return EFalse;
+ }
+
+void CRfcommUIHFrame::QueResponseTimer()
+ /**
+ Never a response for data frames, so do nothing
+ **/
+ {
+ // Nothing
+ }
+
+void CRfcommUIHFrame::DequeTimer()
+ {
+ // Do nothing
+ }
+
+TBool CRfcommUIHFrame::Priority() const
+ {
+ return EFalse;
+ }
+
+TUint16 CRfcommUIHFrame::DataLength() const
+ {
+ TInt overhead = iFramePrepared?KMaxFrameOverhead:KMaxFrameHeaderLength;
+ TUint16 length=static_cast<TUint16>((*iData).Length()-overhead);
+ return length;
+ }
+
+void CRfcommUIHFrame::PutByte(TUint8 aByte)
+ {
+ iData->Des().Append(aByte);
+ }
+
+void CRfcommUIHFrame::PutLittleEndian16(TUint16 aVal)
+ {
+ TUint8* ptr=const_cast<TUint8*>((*iData).Ptr());
+ ptr+=(*iData).Length();
+ iData->Des().SetLength((*iData).Length()+2);
+ LittleEndian::Put16(ptr, aVal);
+ }
+
+void CRfcommUIHFrame::PutLittleEndian32(TUint32 aVal)
+ {
+ TUint8* ptr=const_cast<TUint8*>((*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<TUint16>((*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<TUint8>(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<TUint8>((length & 0x7F)<<1);
+ rwData[3]=static_cast<TUint8>((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<KMaxFrameOverhead-1;++i)
+ PutByte(0x00);
+ }
+
+void CRfcommDataFrame::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<TUint16>((*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<TUint8>(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<TUint8>((length & 0x7F)<<1);
+ rwData[3]=static_cast<TUint8>((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<TUint16>((*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<KMaxFrameCreditOverhead-1;++i)
+ PutByte(0x00);
+ }
+
+void CRfcommCreditDataFrame::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<TUint16>((*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<TUint8>(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<TUint8>((length & 0x7F)<<1);
+ rwData[3]=static_cast<TUint8>((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<KShortMuxCommandHeaderLength;++i)
+ PutByte(0x00);
+ }
+
+
+CRfcommMuxCtrlFrame::CRfcommMuxCtrlFrame(TUint8 aCommandValuesLength, CRfcommMuxer& aMux, CRfcommSAP* aSAP)
+ : CRfcommUIHFrame(aMux, aSAP),
+ iCommandLength(aCommandValuesLength)
+ {
+ }
+
+CRfcommMuxCtrlFrame::~CRfcommMuxCtrlFrame()
+ {
+ if(iTimerQueued)
+ BTSocketTimer::Remove(iTimerEntry);
+ }
+
+TInt CRfcommMuxCtrlFrame::Type() const
+ {
+ return KMuxCtrlFrameType;
+ }
+
+void CRfcommMuxCtrlFrame::SetResponseNeeded(TBool aNeed)
+ {
+ iResponseNeeded=aNeed;
+ }
+
+TBool CRfcommMuxCtrlFrame::ResponseNeeded()
+ {
+ return iResponseNeeded;
+ }
+
+void CRfcommMuxCtrlFrame::QueResponseTimer()
+ /*
+ Que a timer if necessary
+ */
+ {
+ if(iResponseNeeded && !iTimerQueued)
+ {
+ // Enque this timer
+ TCallBack cb(TimerExpired, this);
+ iTimerEntry.Set(cb);
+ BTSocketTimer::Queue(KFrameTimerT2, iTimerEntry);
+ iTimerQueued=ETrue;
+ }
+ }
+
+void CRfcommMuxCtrlFrame::DequeTimer()
+ {
+ if(iTimerQueued)
+ {
+ BTSocketTimer::Remove(iTimerEntry);
+ iTimerQueued=EFalse;
+ }
+ }
+
+TBool CRfcommMuxCtrlFrame::Priority() const
+ {
+ return ETrue;
+ }
+
+TInt CRfcommMuxCtrlFrame::TimerExpired(TAny* aFrame)
+ {
+ CRfcommMuxCtrlFrame* frm=static_cast<CRfcommMuxCtrlFrame*>(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)