bluetooth/btstack/linkmgr/physicallinks.cpp
branchRCL_3
changeset 17 32ba20339036
parent 16 9f17f914e828
child 18 1f10b9300be6
--- a/bluetooth/btstack/linkmgr/physicallinks.cpp	Tue May 11 17:15:36 2010 +0300
+++ b/bluetooth/btstack/linkmgr/physicallinks.cpp	Tue May 25 13:54:55 2010 +0300
@@ -927,7 +927,12 @@
 void CPhysicalLink::ConnectionComplete(THCIErrorCode aErr, const TBTConnect& aConn)
 	{
 	LOG_FUNC
-	if (aErr == KErrNone)
+	ConnectionComplete(CHciUtil::SymbianErrorCode(aErr), aConn);
+	}
+
+void CPhysicalLink::ConnectionComplete(TInt aResult, const TBTConnect& aConn)
+	{
+	if (aResult == KErrNone)
 		{
 		if(aConn.iLinkType == ESCOLink && !iSyncLogicalLink)
 			{
@@ -936,12 +941,9 @@
 			//a remote device to respond to a connection request.
 			iLinksMan.Baseband().UpdateModelForConnectionError(aConn.iBdaddr, aConn.iLinkType);
 
-			if(aErr==EOK) // if error, aConn.iConnH will refer to the ACL link used to initialise the SCO link, so dont disconnect that
-				{
-				//The baseband might actually have established a SCO link, so send a Disconnect.
-				//If no SCO link exists the command will fail gracefully.
-				TRAP_IGNORE(iLinksMan.HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
-				}
+			//The baseband might actually have established a SCO link, so send a Disconnect.
+			//If no SCO link exists the command will fail gracefully.
+			TRAP_IGNORE(iLinksMan.HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
 
 			return;
 			}
@@ -989,7 +991,7 @@
 			if (aConn.iEncryptMode)
 				{
 				// pretend there's been an encryption event
-				EncryptionChange(aErr, aConn.iConnH, aConn.iEncryptMode);
+				EncryptionChange(EOK, aConn.iConnH, aConn.iEncryptMode);
 				}
 			}
 
@@ -1061,13 +1063,13 @@
 			}
 
 		iLinksMan.Baseband().UpdateModelForConnectionError(aConn.iBdaddr, aConn.iLinkType);
-		NotifyLogicalLinkError(aConn.iLinkType, CHciUtil::SymbianErrorCode(aErr));
+		NotifyLogicalLinkError(aConn.iLinkType, aResult);
 		if (aConn.iLinkType == EACLLink)
 			{
 			// BT 1.2 says that as the ACL Link goes up and down, so does the physical link
 			// so if the ACL Link has gone, so has this
 			// for SCO we remain in place.
-			TBTBasebandEventNotification event(ENotifyPhysicalLinkError, CHciUtil::SymbianErrorCode(aErr));
+			TBTBasebandEventNotification event(ENotifyPhysicalLinkError, aResult);
 			NotifyStateChange(event);
 			delete this;
 			}
@@ -1700,73 +1702,60 @@
 	{
 	LOG_FUNC
 	if (!IsConnected())
+		{
+		LOG(_L8("Physical link not connected, no arbitration executed"));
 		return KErrDisconnected;
-
-	if ( aImmediately )
-		{
-		iArbitrationDelay->Cancel();
-		return DoArbitrate(aLocalPriority);		
 		}
-	else if (iArbitrationDelay->IsActive())
-		{
-		return KErrNone;
-		}
-	else
-		{
-		iArbitrationDelay->Start(aLocalPriority);
-		return KErrNone;
-		}
+	// The arbitration delay object will decide how much delay
+	return iArbitrationDelay->Start(aImmediately, aLocalPriority);
 	}
 
 TInt CPhysicalLink::DoArbitrate(TBool aLocalPriority)
 	{
+	LOG_FUNC
 	if (!IsConnected())
 		{
+		LOG(_L8("Physical link not connected, no arbitration executed"));
 		return KErrDisconnected;
 		}
 
 	//start arbitrate process with what our local controller supports
 	TUint8 allowedModesMask = EHoldMode | EParkMode | ESniffMode; // local features sorted out later
-	TBool roleSwitchAllowed = EFalse;
-
- 	if (iLinksMan.LinkManagerProtocol().IsRoleSwitchSupportedLocally() && iLinksMan.RoleSwitchAllowed())
- 		{
- 		roleSwitchAllowed = ETrue;
- 		}
-
+	TBool roleSwitchAllowed = iLinksMan.LinkManagerProtocol().IsRoleSwitchSupportedLocally() && iLinksMan.RoleSwitchAllowed();
+	LOG2(_L8("Arbitration: link policy (LPM:0x%02x, Role:0x%x) - Prior to proxies"), allowedModesMask, roleSwitchAllowed);
+	
 	// ask proxies what they want from the PHY
- 	TUint8 requestedModeMask = 0;
- 	TUint8 requestedMode = 0;
- 	TBool activeModeIsRequested = EFalse;
+	TUint16 requestedModeMask = 0; // mask of current LPM requests from proxy's
+	static const TUint16 KExplicitActiveMode = 0x0100; // special bit for explicit active mode requests
+	
 	TSglQueIter<CBTProxySAP> iter(iProxySAPs);
 	while (iter)
 		{
 		CBTProxySAP* proxy = iter++;
 
- 		requestedMode = proxy->GetRequestedModes();
- 		requestedModeMask |= requestedMode;
-
-		if (requestedMode == EActiveMode && proxy->RequestedActiveMode())
- 			{
- 			// An Active Mode request will override all other local low power mode requests
- 			// but continue to collect the requirement from the other proxies..
- 			activeModeIsRequested = ETrue;
- 			}
-
-		allowedModesMask &= proxy->GetAllowedModes();
-		roleSwitchAllowed &= proxy->IsRoleSwitchAllowed();
+		TUint8 requestedMode = proxy->GetRequestedModes();
+		requestedModeMask |= requestedMode;
+
+		TBool explicitActiveModeRequest = proxy->RequestedActiveMode();
+		if (requestedMode == EActiveMode && explicitActiveModeRequest)
+			{
+			requestedModeMask |= KExplicitActiveMode;
+			}
+
+		TUint8 allowedModes = proxy->GetAllowedModes();
+		allowedModesMask &= allowedModes;
+		
+		TBool roleSwitchAllowedByProxy = proxy->IsRoleSwitchAllowed();
+		roleSwitchAllowed = roleSwitchAllowed && roleSwitchAllowedByProxy;
+		
+		LOG4(_L8("Arbitration: Proxy(0x%08x) - requested mode = 0x%04x, link policy (LPM:0x%02x, Role:0x%x)"), proxy, requestedMode, allowedModes, roleSwitchAllowedByProxy);
 		}
-
- 	if (activeModeIsRequested)
- 		{
- 		// Any Active Mode request will override all other low power mode requests,
- 		// so overwrite the requestedModeMask but keep allowedModesMask and roleSwitchAllowed
- 		// as specified by all the local proxies
- 		requestedModeMask = EActiveMode;
- 		}
+	LOG2(_L8("Arbitration: link policy (LPM:0x%02x, Role:0x%x) - after proxies"), allowedModesMask, roleSwitchAllowed);
 
 	// clear out modes not supported by local Controller
+	// Future improvement - what about modes supported by the remote device?
 	allowedModesMask &= iLinksMan.LinkManagerProtocol().ModesSupportedLocally();
+	LOG2(_L8("Arbitration: link policy (LPM:0x%02x, Role:0x%x) - only supported modes"), allowedModesMask, roleSwitchAllowed);
 
 	if(iOverrideParkRequests)
 		{
@@ -1774,13 +1763,11 @@
 		// The only way to guarantee this is to disallow PARK via the link policy settings.
 		allowedModesMask &= ~EParkMode;
 		}
-
-	if(allowedModesMask != iLinkPolicy.LowPowerModePolicy()
-		|| roleSwitchAllowed != iLinkPolicy.IsSwitchAllowed())
-		{
-		// Controller policy for the connection needs updating
-		SetModesAllowed(allowedModesMask, roleSwitchAllowed);
-		}
+	LOG2(_L8("Arbitration: link policy (LPM:0x%02x, Role:0x%x) - overrides applied"), allowedModesMask, roleSwitchAllowed);
+
+	// Controller policy for the connection may need updating
+	SetModesAllowed(allowedModesMask, roleSwitchAllowed);
+	LOG2(_L8("Arbitration: link policy (LPM:0x%02x, Role:0x%x) - submitted"), allowedModesMask, roleSwitchAllowed);
 
 	//If OverrideLPM flag is set, we do not disable LP modes via the link policy settings
 	//This is done because OverrideLPM should not prevent remotes putting us into an LPM
@@ -1790,9 +1777,11 @@
 		// We need to ensure the physical link is in active mode.
 		allowedModesMask = EActiveMode;
 		}
-
-	TUint8 modeChangeMask = static_cast<TUint8>(requestedModeMask & allowedModesMask);
-	TUint8 modeCompareMask = 0;
+	LOG2(_L8("Arbitration: link policy (LPM:0x%02x, Role:0x%x) - post setting overrides applied"), allowedModesMask, roleSwitchAllowed);
+
+	TUint16 modeChangeMask = requestedModeMask & (static_cast<TUint16>(allowedModesMask)|KExplicitActiveMode);
+	TUint16 modeCompareMask = 0;
+	LOG2(_L8("Arbitration: mode change mask = 0x%04x, local priority = 0x%x"), modeChangeMask, aLocalPriority);
 
 	if(aLocalPriority)
 		{
@@ -1809,57 +1798,89 @@
 		// modeCompareMask should start only having zero bits where
 		// requestedModeMask has a zero bit and iPreviousRequestedModeMask does not
 		// i.e. a mode is newly no longer requested.
-		modeCompareMask = requestedModeMask | ~iPreviousRequestedModeMask;
+		modeCompareMask = ~((requestedModeMask ^ iPreviousRequestedModeMask) & iPreviousRequestedModeMask);
 
 		// Remove bits from modeCompareMask that are not in allowedModesMask
 		// We cannot stay in a power mode that we do not allow.
-		modeCompareMask &= allowedModesMask;
+		modeCompareMask &= (static_cast<TUint16>(allowedModesMask)|KExplicitActiveMode);
 		}
+	LOG1(_L8("Arbitration: Comparison mask = 0x%04x"), modeCompareMask);
 
 	iPreviousRequestedModeMask = requestedModeMask; // Update previous requested to current value.
 
-	TUint8 currentModeMask = static_cast<TUint8>(iLinkState.LinkMode());
+	// get the current mode.
+	TBTLinkMode currentMode = iLinkState.LinkMode();
+	TUint16 currentModeMask = static_cast<TUint16>(currentMode);
+	if(currentModeMask == EActiveMode)
+		{
+		// if in active mode then could have been because of an explicit active mode request
+		currentModeMask |= KExplicitActiveMode;
+		}
+	LOG1(_L8("Arbitration: Current mode mask = 0x%04x"), currentModeMask);
+	
 	if(modeCompareMask & currentModeMask)
 		{
+		LOG2(_L8("Arbitration: Comparison mask (0x%04x) matched, so staying in current mode (0x%04x)"), modeCompareMask, currentModeMask);
 		// The current state is the same as the permitted required role(s).
 		return KErrNone;
 		}
-
-	if(modeChangeMask == EActiveMode && currentModeMask != EActiveMode)
+	
+	TBTLinkMode nextMode = EActiveMode;
+	// Determine which LPM we should be in (if any)
+	if(modeChangeMask & KExplicitActiveMode)
 		{
-		// The current low power mode should be exited.
-		return RequestActive();
+		nextMode = EActiveMode;
 		}
-
-	if(modeChangeMask != EActiveMode)
+	else if(modeChangeMask & EHoldMode)
+		{
+		nextMode = EHoldMode;
+		}
+	else if(modeChangeMask & ESniffMode)
 		{
-		if(currentModeMask != EActiveMode)
+		nextMode = ESniffMode;
+		}
+	else if(modeChangeMask & EParkMode)
+		{
+		nextMode = EParkMode;
+		}
+	LOG2(_L8("Arbitration: Arbitrating mode 0x%02x -> 0x%02x"), currentMode, nextMode);
+	
+	if(nextMode != currentMode)
+		{
+		if(currentMode != EActiveMode)
 			{
-			// The system is currently in a low power mode.  Exit this before
-			// entering the new mode.
-			TInt rerr = RequestActive();
-			if(rerr != KErrNone)
+			LOG(_L8("Arbitration: Exiting existing LPM mode..."));
+			TInt err = RequestActive();
+			if(err != KErrNone)
 				{
-				return rerr;
+				return err;
 				}
 			}
-
-		if(modeChangeMask & EHoldMode)
+		if(nextMode == EHoldMode)
 			{
+			LOG(_L8("Arbitration: Entering Hold mode..."));
 			return RequestHold();
 			}
-		if(modeChangeMask & ESniffMode)
+		else if(nextMode == ESniffMode)
 			{
+			LOG(_L8("Arbitration: Entering Sniff mode..."));
 			return RequestSniff();
 			}
-		if(modeChangeMask & EParkMode)
+		else if(nextMode == EParkMode)
 			{
+			LOG(_L8("Arbitration: Entering Park mode..."));
 			return RequestPark();
 			}
+		else if(nextMode == EActiveMode)
+			{
+			LOG(_L8("Arbitration: Staying in Active mode..."));
+			return KErrNone;
+			}
+		// Shouldn't reach here, we have a strange mode
+		DEBUG_PANIC_LINENUM;
 		}
 
-	// This point in the code is reached if the Link Policy settings are
-	// changed but the mode is not.	 Return OK error code.
+	LOG(_L8("Arbitration: Already in correct LPM, not doing anything"));
 	return KErrNone;
 	}
 
@@ -1880,10 +1901,10 @@
 void CPhysicalLink::StartArbitrationTimer() const
 	{
 	LOG_FUNC
-	iArbitrationDelay->Start();
+	iArbitrationDelay->Restart();
 	}
 
-TInt CPhysicalLink::Connect(TBasebandPageTimePolicy aPolicy)
+void CPhysicalLink::Connect(TBasebandPageTimePolicy aPolicy)
 	{
 	LOG_FUNC
 	// assume that we will be master until told otherwise
@@ -1902,16 +1923,20 @@
 	// optimise paging (as a best-effort attempt).
 	TBasebandTime pagetimeout = CalculatePageTimeout(aPolicy, psrm, clockOffset & KHCIClockOffsetValidBit);
 	iLinksMan.TryToChangePageTimeout(pagetimeout);
+	
+	// Set state in anticipation of the connection
+	iLinkState.SetLinkState(TBTBasebandLinkState::ELinkPending);
+	iLinksMan.Baseband().UpdateModel(iDevice.Address(), pkt, EACLLink);
+	iLinkState.SetLinkRole(EMaster);
 
 	TRAPD(ret, iLinksMan.HCIFacade().ConnectL(iDevice.Address(), pkt, psrm, psm, clockOffset, allowRoleSwitch));
-	if(ret==KErrNone)
+	if(ret != KErrNone) // a physical link is in charge of it's own destiny.
 		{
-		iLinkState.SetLinkState(TBTBasebandLinkState::ELinkPending);
-		iLinksMan.Baseband().UpdateModel(iDevice.Address(), pkt, EACLLink);
-		iLinkState.SetLinkRole(EMaster);
+		TBTConnect conn;
+		conn.iBdaddr = BDAddr();
+		conn.iLinkType = EACLLink;
+		ConnectionComplete(ret, conn);
 		}
-
-	return ret;
 	}
 
 TInt CPhysicalLink::SCOConnect()
@@ -2264,7 +2289,7 @@
 		(aEvent.EventType() & ENotifyHoldMode)) &&
 		(aEvent.ErrorCode() == KErrNone))
 		{
-		iArbitrationDelay->Start();
+		iArbitrationDelay->Restart();
 		}
 	}
 
@@ -3378,17 +3403,18 @@
 // CArbitrationDelayTimer
 
 CArbitrationDelayTimer::CArbitrationDelayTimer(CPhysicalLink* aParent)
-	:CTimer(CActive::EPriorityStandard),
-	iParent(aParent)
+	: CTimer(CActive::EPriorityStandard)
+	, iParent(aParent)
 	{
 	LOG_FUNC
+	ASSERT_DEBUG(iParent);
+	CActiveScheduler::Add(this);
 	}
 
 void CArbitrationDelayTimer::ConstructL()
 	{
 	LOG_FUNC
 	CTimer::ConstructL();
-	CActiveScheduler::Add(this);
 	}
 
 CArbitrationDelayTimer* CArbitrationDelayTimer::NewL(CPhysicalLink* aParent)
@@ -3401,16 +3427,46 @@
 	return self;
 	}
 
-void CArbitrationDelayTimer::Start(TBool aLocalPriority)
+TInt CArbitrationDelayTimer::Start(TBool aImmediate, TBool aLocalPriority)
 	{
 	LOG_FUNC
 	// Work out what the local priority will be now
-	TBool localPriority = iLocalPriority || aLocalPriority;
-	Cancel(); // cancel current timer (will also reset priority so ...
-	iLocalPriority = localPriority; // set the new priority)
+	iLocalPriority = iLocalPriority || aLocalPriority;
+	LOG1(_L8("Arbitraion: Local Priority now %d"), iLocalPriority);
+	if(aImmediate)
+		{
+		LOG(_L8("Arbitraion: Immediate Arbitration Requested..."));
+		CancelButPreserveLocalPriority();
+		return DoArbitrate();
+		}
+	else if(!IsActive())
+		{
+		LOG(_L8("Arbitraion: Arbitration requested, will execute after delay timer..."));
+		After(KBTArbitrationDelay);
+		}
+	else // timer is already on its way
+		{
+		LOG(_L8("Arbitraion: Arbitration delay timer still pending..."));
+		}
+	return KErrNone;
+	}
+
+void CArbitrationDelayTimer::Restart()
+	{
+	LOG_FUNC
+	LOG(_L8("Arbitraion: Arbitration timer restarted..."));
+	CancelButPreserveLocalPriority();
 	After(KBTArbitrationDelay);
 	}
 
+void CArbitrationDelayTimer::CancelButPreserveLocalPriority()
+	{
+	LOG_FUNC
+	TBool localPriority = iLocalPriority;
+	Cancel();
+	iLocalPriority = localPriority;
+	}
+
 
 void CArbitrationDelayTimer::RunL()
 /**
@@ -3418,10 +3474,16 @@
 **/
 	{
 	LOG_FUNC
-	if (iParent)
-		{
-		iParent->DoArbitrate(iLocalPriority);
-		}
+	LOG(_L8("Arbitraion: Delayed Arbitration executing..."));
+	static_cast<void>(DoArbitrate()); // ignore the error (always has been...)
+	}
+
+TInt CArbitrationDelayTimer::DoArbitrate()
+	{
+	LOG_FUNC
+	TBool localPriority = iLocalPriority;
+	iLocalPriority = EFalse;
+	return iParent->DoArbitrate(localPriority);
 	}
 
 void CArbitrationDelayTimer::DoCancel()