diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btcomm/src/reader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btcomm/src/reader.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,273 @@ +// 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 "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: +// reader.cpp - all the active reader code +// +// + +#include +#include "btcomm.h" +#include "btcommactive.h" +#include "btcommutil.h" + +CBTPortReader *CBTPortReader::NewL(CBTPortProxy *aParent) +/** + Create new CBTPortReader. + This function creates a new CBTPortReader active object. +**/ + { + CBTPortReader *cc; + cc=new (ELeave) CBTPortReader(); + CleanupStack::PushL(cc); + cc->InitL(aParent); + CleanupStack::Pop(); + CActiveScheduler::Add(cc); + return cc; + } + +void CBTPortReader::InitL(CBTPortProxy *aParent) +/** + CBTPortReader InitL. + This function sets up the local read buffer + that is the first port of call for data read + from the socket. The size of the local read + buffer should be the max size available for + socket datagrams. +**/ + { + iPortProxy=aParent; + iLocalReadBuffer=HBufC8::NewMaxL(KBTCOMMRecvBufferLength); + iLocalReadBufferPtr.Set(iLocalReadBuffer->Des()); + } + +CBTPortReader::~CBTPortReader() +/** + CBTPortReader destructor. +**/ + { + delete iLocalReadBuffer; + Cancel(); + } + +void CBTPortReader::RunL() +/** + CBTPortReader RunL. + Active status cleared. Put the read data into the circular + buffer. After that we can call the DoReadCompleted + function on the corresponding port proxy object. +**/ + { + CBTPortBuffer& circBuf=*(iPortProxy->iCircularReadBuf); + + TInt ret=iStatus.Int(); + if (ret==KErrNone) + { + TUint8 *ptr=CONST_CAST(TUint8*,iLocalReadBufferPtr.Ptr()); + TInt receivedBytes=iLocalReadBufferPtr.Length(); + + // add newly arrived data in the circular buffer +#ifdef _DEBUG + TInt consumed= +#endif + circBuf.Add(ptr,receivedBytes); + + __ASSERT_DEBUG(consumed==receivedBytes,BTCommUtil:: \ + Panic(EBTCommPortReaderPotentialLossOfIncomingData)); + } + + iPortProxy->DoReadCompleted(ret); + } + +void CBTPortReader::QueueRead() +/** + CBTPortReader QueueRead. + This function is invoked to queue a read on the socket. + We just keep queueing reads on the socket here with the + resulting data being fed into the circular read buffer. +**/ + { + if (IsActive()) + { + //__DEBUGGER(); //FIXME + return; + } + else + { + // queue read to socket + iLocalReadBufferPtr.SetLength(0); + iPortProxy->iSocket.RecvOneOrMore(iLocalReadBufferPtr,0,iStatus,iPlen); + SetActive(); + } + } + +void CBTPortReader::StartReading() + { + iKeepReading=ETrue; + QueueRead(); + } + +void CBTPortReader::StopReading() + { + iKeepReading=EFalse; + } + +TBool CBTPortReader::IsReading() + { + return iKeepReading; + } + +void CBTPortReader::DoCancel() +/** + CBTPortReader DoCancel. +**/ + { + if ( iPortProxy->iSocket.SubSessionHandle()) + { + iPortProxy->iSocket.CancelRead(); + } + } + +CBTPortReader::CBTPortReader() + : CActive (EPriorityHigh), + iLocalReadBufferPtr(NULL,0,0) + { + } + +//********************* READ CIRCULAR BUFFER CODE ********************** + +CBTPortBuffer *CBTPortBuffer::NewL(CBTPortProxy* aParent,TInt aBufSize) + { + CBTPortBuffer *buf; + buf=new (ELeave) CBTPortBuffer(aBufSize); + CleanupStack::PushL(buf); + buf->ConstructL(aParent); + CleanupStack::Pop(); + return buf; + } + +void CBTPortBuffer::ConstructL(CBTPortProxy* aParent) +/** + Sets up the circular buffer. +**/ + { + iPortProxy=aParent; + SetLengthL(iCircBufSize); + } + +CBTPortBuffer::CBTPortBuffer(TInt aBufSize) + : CCirBufBase(sizeof(TUint8)), + iCircBufSize(aBufSize) + { + iCircBufSize=aBufSize; + } + +CBTPortBuffer::~CBTPortBuffer() + { + } + +TInt CBTPortBuffer::Add(const TUint8* aPtr,TInt aCount) + { + return DoAdd(aPtr,aCount); + } + +TInt CBTPortBuffer::Remove(TUint8* aPtr,TInt aCount) + { + return DoRemove(aPtr,aCount); + } + +TInt CBTPortBuffer::ScanForTerminator(TReadTerminator& aTerminator) +/** + This function returns the number of bytes to be read of the circ buffer or KErrNotFound. + If the terminator sequence was not found then KErrNotFound is returned to + indicate this, the returned number of bytes does include the terminator + sequence held in aTerminator. +*/ + { + // go through the circbuf trying to find a terminator char. + TInt byteCount=1; + TInt charsFound=KErrNotFound; //ret val from the sequence scan + + TUint8* ptr=iTail; //somehow inefficient for now + TText8 nextChar; + + // init scanning + aTerminator.iNextCharToFindIdx=0; //point to the first char to be scanned + + FOREVER + { + if(ptr>=iPtrE) + {// roll over + ptr=iPtr; + } + + nextChar=*ptr; + + charsFound=ScanForTerminatorSequence(aTerminator,nextChar); + if(charsFound>KErrNone) + {// charsFound will only be positive once + __ASSERT_DEBUG(charsFound==aTerminator.iTerminatorCount, \ + BTCommUtil::Panic(EBTCommPortBufferTerminatorCharNoOtherThanExpected)); + + break; + } + ptr++; // go for the next one + if(byteCount==iCount) + { + break; //we scanned the whole buf + } + byteCount++; // record one more char that will definately be searched + } + + // either returns the no of bytes read or KErrNotFound + if(charsFound>=KErrNone) + { + __ASSERT_DEBUG(byteCount<=iCount,BTCommUtil::Panic(EBTCommPortBufferTerminatedCharsFoundBogus)); + return byteCount; + } + return KErrNotFound; + } + + +TInt CBTPortBuffer::ScanForTerminatorSequence(TReadTerminator& aTerminator, + TText8 aChar) +/** + Will return the number of terminator chars found or KErrNotFound. + The invariant is that the number of chars returned should be equal to + the TReadTerminator::iTerminatorCount. + The control and drive of the 'find the terminator sequence' state machine + is kept in this method. + + To drive this state machine, a client must keep feeding it with aChar until + it returns a positive int or the client's buffer has been exhausted. +*/ + { + //check for the expected character + if(aChar==aTerminator.iTerminatorChars[aTerminator.iNextCharToFindIdx]) + {// the expected character was found + // check to see if we found the whole sequence + if(aTerminator.iNextCharToFindIdx==(aTerminator.iTerminatorCount-1)) + {// yes this was the last expected char in the sequence + TInt ret=aTerminator.iNextCharToFindIdx; + aTerminator.iNextCharToFindIdx=0; //set it back to the first char in the seq + return ret+1; // found so many, return with success + } + // we didn't but still we're doing ok, so prepare for the next one + aTerminator.iNextCharToFindIdx++; + return KErrNotFound; //yet + } + + // the current char wasn't in the terminator sequence or it was + // in an irrelevant position so reset the state machine in order to start again + aTerminator.iNextCharToFindIdx=0; + return KErrNotFound; + }