bluetooth/btcomm/src/PORTPROXY.CPP
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btcomm/src/PORTPROXY.CPP	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,453 @@
+// Copyright (c) 1997-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 <cs_port.h>
+#include "btcomm.h"
+#include "btstate.h"
+#include "btcommactive.h"
+#include <btmanclient.h>
+#include "BTSimTimer.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_BT_COMM);
+#endif
+
+CBTPortProxy* CBTPortProxy::NewL(TUint32 aPortNo,CBTPort *aParent,CBTPortStateFactory *aFactory)
+/**
+	CBTPortProxy NewL(..) creates an instance of the BT Port Proxy.
+	This is the object that represents the CSY state pattern context.
+
+	In order to avoid deadlock between the esock and c32 threads it is
+	necessary to employ a locking mechanism to serialise synchronous
+	accesses to esock thread.  This mechanism works as follows:
+
+		1)	Defer all synchronous access attempts on esock via the CSY until 
+			a locker active object has been run.
+		2)	When we hit the RunL of this locker active object we know that
+			the present session on the esock server is exclusive - ie all
+			other esock sessions are temporarily disabled.
+		3)	At this point, it is possible to run the original synchronous 
+			request on esock safe in the knowledge that no other esock session
+			can deadlock the c32 thread.  This is the DoLockedActions phase.
+		4)	Once the request has completed the unlocker active object is invoked
+			to release the exlusive session lock on esock.
+*/
+	{
+	LOG_STATIC_FUNC
+	CBTPortProxy *pp;
+	pp=new (ELeave) CBTPortProxy(aPortNo);
+	CleanupStack::PushL(pp);
+	pp->InitL(aParent,aFactory);
+	CleanupStack::Pop();
+	return pp;
+	}
+
+void CBTPortProxy::InitL(CBTPort *aParent,CBTPortStateFactory *aFactory)
+/**
+	Initialises the CBTPortProxy context and enters the 'starting' state.
+	This is where we create the PortLocker, Port Reader, Port Writer, 
+	circular read buffer and fixed write buffer. Note that we also fire up 
+	the state machine here too (with an EStarting::Entry).  
+	This is thus the main CSY Bootstrap function.
+**/
+	{
+	LOG_FUNC
+	iPort=aParent;
+	iPortStateFactory=aFactory;
+	iState=&iPortStateFactory->GetState(CBTPortStateFactory::EIdle);
+	iPortLocker=CBTPortLocker::NewL(this);
+	iCircularReadBuf=CBTPortBuffer::NewL(this,KBTCOMMCircularBufferLength);
+	iReadBuf=HBufC8::NewMaxL(KBTCOMMRecvBufferLength);
+
+	iSendBuf=HBufC8::NewMaxL(KBTCOMMSendBufferLength);
+	iSendBufPtr.Set(iSendBuf->Des());
+
+	iReadOutBuf=HBufC8::NewMaxL(KBTCOMMCircularBufferLength);
+	iReadBufPtr.Set(iReadOutBuf->Des());
+
+	iPortReader=CBTPortReader::NewL(this);
+	iPortWriter=CBTPortWriter::NewL(this);
+
+	iSockServConnector = CSockServConnector::NewL(iSockServ);
+	
+	User::LeaveIfError(iRegServ.Connect());
+	User::LeaveIfError(iPortSettings.Open(iRegServ));
+
+	CActiveScheduler::Add(this);
+
+	iShutdownTimer = CBTTimerSimple::NewL(EPriorityLow,this);
+
+	iState->Open(this);
+	}
+
+
+CBTPortProxy::CBTPortProxy(TUint32 aPortNo) 
+	: CActive (EPriorityStandard), iPortNo(aPortNo),
+	  iSendBufPtr(NULL,0,0),
+	  iReadBufPtr(NULL,0,0)
+/**
+	CBTPortProxy constructor.
+**/
+	{
+	LOG_FUNC
+	}
+
+/**
+	Initiates the destruction of the port its proxy and the corresponding states.
+	Calls to this method should be made by the state responsible for destructing 
+	the CSY.
+	No further methods should be invoked after this call.
+*/
+void CBTPortProxy::DestructContext()
+	{
+	LOG_FUNC
+	if(iPort->AccessCount())
+		{
+		// someone else managed to reopen us lets not die :-)
+		// and check to see if we have a cached read or write request
+		if(iClientWritePtr||iClientReadPtr)
+			{
+			LOG(_L("**CBTPortProxy::DestructContext - Cached Read/Write check **"));
+			//then kickstart the starting state (we can only be in the starting state)
+			((TBTPortStateIdle*) iState)->SockServConnect(this);
+			}
+		return;
+		}
+	//else go down
+	iPort->DestructNow(); //taking CBTPortProxy with it
+	}
+
+CBTPortProxy::~CBTPortProxy()
+/**
+	CBTPortProxy destructor.
+**/
+	{
+	LOG_FUNC
+	Cancel();
+	delete iPortReader;
+	delete iPortWriter;
+	delete iPortLocker;
+	delete iSockServConnector;
+	delete iSendBuf;
+	delete iReadBuf;
+	delete iCircularReadBuf;
+	delete iReadOutBuf;
+	delete iShutdownTimer;
+	iPortSettings.Close();
+	iRegServ.Close();
+	}
+
+void CBTPortProxy::RunL()
+	{
+	LOG_FUNC
+	LOG1(_L("CBTPortProxy::RunL with result %d"), iStatus.Int());
+	iState->DoRunL(this);
+	}
+
+void CBTPortProxy::DoCancel()
+/**
+	CBTPortProxy::DoCancel
+	With a normal active object this function would cancel 
+	any outstanding requests on aysnchronous services.  In
+	this case we cannot do that as to make a synchronous
+	request on esock we need to be in the locker.  Instead
+	we ensure that when we do a Cancel() we have passed
+	through the closing state, which cancels things in the
+	locker.  
+	
+	If there are any requests outstanding when Cancel() is 
+	called then this thread will block doing
+	User::WaitForRequest() to eat the signal.
+**/
+	{
+	LOG_FUNC
+	}
+
+void CBTPortProxy::StartWriter()
+/**
+	CBTPortProxy StartWrite.
+	This function is invoked by the state machine
+	on the context when it wishes to start a write.
+	Note that this function has to fragment the writes 
+	into sensible chunks to write across RFComm.  The 
+	size of these chunks is dictated by 
+	KBTCOMMSendBufferLength.
+**/
+	{
+	LOG_FUNC
+	iPortWriter->QueueWrite(iSendBufPtr);
+	}
+
+void CBTPortProxy::DoWriteCompleted(TInt aError)
+	{
+	LOG_FUNC
+	iState->DoWriteCompleted(this,aError);
+	}
+
+void CBTPortProxy::StopWriter()
+/**
+	CBTPortProxy StopWrite.
+	This function is invoked by the state machine
+	on the context when it wishes to stop a write
+**/
+	{
+	LOG_FUNC
+	}
+
+void CBTPortProxy::StartReader()
+/**
+	CBTPortProxy StartReader.
+	This function is invoked by the state machine
+	on the context when it wishes to queue a read.
+**/
+	{
+	LOG_FUNC
+	iPortReader->StartReading();
+	}
+
+void CBTPortProxy::DoReadCompleted(TInt aError)
+/**
+	Completes the reads to the state indicating that new data arrived from socket.
+
+	According to the delegated state it will check to see if it has reached 
+	its circular buffer watermark and hence refrain from re-queueing another 
+	read to the socket.
+*/
+	{
+	LOG_FUNC		
+	iState->DoReadCompleted(this,aError); // new data arrived from the socket
+	}
+
+/**
+	Checks whether the low watermark for the circular read-in (from the socket) buffer has been passed.
+	This method wil be used by the friendly open state to restart the reader if
+	necessary.
+*/
+TBool CBTPortProxy::ReadInBufferLowWatermarkReached()
+	{
+	LOG_FUNC
+	if (iCircularReadBuf->Count()<=KBTCOMMCircularBufferLowWatermark)
+		{
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+/**
+	Checks whether the high watermark for the circular read-in (from the socket) buffer has been reached or passed.
+	This method wil be used by the friendly open state to start or stop the 
+	reader if necessary.
+*/
+TBool CBTPortProxy::ReadInBufferHighWatermarkReached()
+	{
+	LOG_FUNC
+	if (iCircularReadBuf->Count()>=KBTCOMMCircularBufferHighWatermark)
+		{
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+void CBTPortProxy::StopReader()
+	{
+	LOG_FUNC
+	iPortReader->StopReading();
+	}
+
+void CBTPortProxy::StartLocker()
+	{
+	LOG_FUNC
+	iPortLocker->LockSession();
+	}
+
+void CBTPortProxy::DoLockedAction()
+	{
+	LOG_FUNC
+	iState->DoLockedAction(this);
+	}
+
+void CBTPortProxy::StopLocker()
+	{
+	LOG_FUNC
+	iPortLocker->UnlockSession();
+	}
+
+TBool CBTPortProxy::IsLockerOn()
+	{
+	LOG_FUNC
+	return (iPortLocker->IsSessionLocked());
+	}
+
+void CBTPortProxy::StartShutdownTimerL()
+	{
+	LOG_FUNC
+	iShutdownTimer->CancelAlarm();
+	iShutdownTimer->After(KBtcommShutdownTimer);
+	}
+
+void CBTPortProxy::CancelShutDownTimer()
+	{
+	LOG_FUNC
+	iShutdownTimer->CancelAlarm();
+	}
+
+void CBTPortProxy::ShutdownAlarm()
+/**
+	ShutdownAlarm() is the callback of the shutdown timer.
+	To be called for the final stage of closing down connection to ESock.
+*/
+	{
+	LOG_FUNC
+	// this startlocker will basically invoke the locked action of the 
+	// closing state
+	StartLocker();
+	}
+
+// Methods to be called by the Open state only
+void CBTPortProxy::SetWriteCancelPending()
+	{
+	LOG_FUNC
+	iWriteCancelationPending=ETrue;
+	}
+
+TBool CBTPortProxy::IsWriteCancelPending()
+	{
+	LOG_FUNC
+	return iWriteCancelationPending;
+	}
+
+TBool CBTPortProxy::IsNetDbInUse()
+	{
+	LOG_FUNC
+	return iNetDbInUse;
+	}
+
+void CBTPortProxy::SetNetDbInUse()
+	{
+	LOG_FUNC
+	iNetDbInUse=ETrue;
+	}
+
+void CBTPortProxy::SetNetDbNotInUse()
+	{
+	LOG_FUNC
+	iNetDbInUse=EFalse;
+	}
+
+// *********************  PUBLIC INTERFACE  ***************************
+
+void CBTPortProxy::Write(const TAny* aClientBuffer,TInt aLength)
+/**
+	CBTPortProxy Write.
+	The CBTPort has attempted a Write.
+**/
+	{
+	LOG_FUNC
+	iState->Write(this,const_cast<TAny*>(aClientBuffer),aLength);
+	}
+
+void CBTPortProxy::WriteCancel()
+/**
+	CBTPortProxy WriteCancel.
+	The CBTPort has attempted to cancel a write.
+	Delegate behaviour to the active state.
+**/
+	{
+	LOG_FUNC
+	iState->WriteCancel(this);  
+	}
+
+void CBTPortProxy::DoWriteCancel()
+/** 
+	Only to be called by the active state, NOT directly.
+	This will cancel the ESock write.
+*/
+	{
+	LOG_FUNC
+	iWriteCancelationPending=EFalse;
+	iSocket.CancelWrite();
+	}
+
+void CBTPortProxy::Read(const TAny* aClientBuffer,TInt aLength)
+/**
+	Delegates the client Read request to the active state.
+	If the state is the Open state then the request is serviced 
+	otherwise it gets cached.
+
+	@param		aLength is either the bytecount to be read or -1
+				indicating a 'Read One Or More bytes' request
+**/
+	{
+	LOG_FUNC
+	iClientReadOneOrMore=EFalse;
+	if (aLength<0)
+        {
+        aLength=-aLength;
+        iClientReadOneOrMore=ETrue;
+        }
+	iState->Read(this,const_cast<TAny*>(aClientBuffer),aLength);	
+	}
+
+void CBTPortProxy::ReadCancel()
+/**
+	Delegates 'cancel the read' behaviour to the active state.
+**/
+	{
+	LOG_FUNC
+	iState->ReadCancel(this);  
+	}
+
+TInt CBTPortProxy::QueryReceiveBuffer(TInt& aLength)
+/**
+	Retrieves number of bytes waiting in the receive buffer.
+*/	{
+	LOG_FUNC
+	aLength=iCircularReadBuf->Length();
+	return KErrNone;
+	}
+
+TInt CBTPortProxy::GetReceiveBufferLength(TInt& aLength)
+/**
+	Sets aLength to KBTCOMMRecvBufferLength.
+	Always returns KErrNone;
+*/	{
+	LOG_FUNC
+	aLength=KBTCOMMRecvBufferLength;
+	return KErrNone;
+	}
+
+void CBTPortProxy::Close()
+/** 
+	Delegates Close request to the active state.
+**/
+	{
+	LOG_FUNC
+	iState->Close(this);
+	}	
+
+void CBTPortProxy::MoveToErrorState()
+	{
+	LOG_FUNC
+	iState=&iPortStateFactory->GetState(CBTPortStateFactory::EError);	
+	// Notify the error state as we move in to it about the current error.
+	iState->Error(this,iLastError);
+	}
+
+void CBTPortProxy::ResetRxBuffer()
+	{
+	LOG_FUNC
+	iCircularReadBuf->Reset();
+	}