bluetooth/btstack/linkmgr/physicallinkmetrics.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <bluetooth/logger.h>
       
    17 
       
    18 #include "physicallinkmetrics.h"
       
    19 #include "physicallinks.h"
       
    20 #include "linkutil.h"
       
    21 #include "ProxySAP.h"
       
    22 #include "btsockettimer.h"
       
    23 
       
    24 #include <bluetooth/hci/hciutil.h>
       
    25 #include <bluetooth/hci/readfailedcontactcountercommand.h>
       
    26 #include <bluetooth/hci/readlinkqualitycommand.h>
       
    27 #include <bluetooth/hci/readrssicommand.h>
       
    28 #include <bluetooth/hci/readtransmitpowerlevelcommand.h>
       
    29 #include <bluetooth/hci/readrssicompleteevent.h>
       
    30 #include <bluetooth/hci/readlinkqualitycompleteevent.h>
       
    31 #include <bluetooth/hci/readfailedcontactcountercompleteevent.h>
       
    32 #include <bluetooth/hci/readtransmitpowerlevelcompleteevent.h>
       
    33 
       
    34 #ifdef __FLOG_ACTIVE
       
    35 _LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
       
    36 #endif
       
    37 
       
    38 
       
    39 
       
    40 
       
    41 TPLMManager::TPLMManager()
       
    42 	:iPLMQue(_FOFF(CBTProxySAP, iPLMLink))
       
    43 	{
       
    44 	LOG_FUNC
       
    45 	}
       
    46 void TPLMManager::UpdatePLMState(THciCommandState aPLMState)
       
    47 	{
       
    48 	LOG_FUNC
       
    49 	FTRACE(FPrint(_L("TPLMManager::UpdatePLMState, Previous state :: %d\n"), iPLMState));
       
    50 	iPLMState = aPLMState;
       
    51 	FTRACE(FPrint(_L("TPLMManager::UpdatePLMState, Changed state :: %d\n"), iPLMState));
       
    52 	}
       
    53 
       
    54 void TPLMManager::RegisterProxySAP(CBTProxySAP& aSAP)
       
    55 	{
       
    56 	LOG_FUNC
       
    57 	iPLMQue.AddLast(aSAP);
       
    58 	}
       
    59 
       
    60 void TPLMManager::UpdatePLMValue(TInt aPLMValue)
       
    61 	{
       
    62 	LOG_FUNC
       
    63 	FTRACE(FPrint(_L("TPLMManager::UpdatePLMValue, Previous PLM value :: %d\n"), (PLMValue())() ));
       
    64 	iPLMValue() = aPLMValue;
       
    65 	FTRACE(FPrint(_L("TPLMManager::UpdatePLMValue, Changed PLM value :: %d\n"), (PLMValue())() ));
       
    66 	}
       
    67 
       
    68 TPckgBuf<TInt>& TPLMManager::PLMValue()
       
    69 	{
       
    70 	LOG_FUNC
       
    71 	return iPLMValue;
       
    72 	}
       
    73 
       
    74 THciCommandState TPLMManager::PLMState() const
       
    75 	{
       
    76 	LOG_FUNC
       
    77 	return iPLMState;
       
    78 	}
       
    79 
       
    80 void TPLMManager::NotifyQueuedProxySAPs(TInt aErr, TUint aName, TDesC8* aBuf)
       
    81 	{
       
    82 	LOG_FUNC
       
    83 	TDblQueIter<CBTProxySAP> iter(iPLMQue);
       
    84 	CBTProxySAP* thisSAP;
       
    85 	
       
    86 	// Iterate through all ProxySAPs that have requested this PLM, notifying them
       
    87 	while ((thisSAP = iter++) != NULL)
       
    88 		{
       
    89 		thisSAP->IoctlComplete(aErr, KSolBtLMProxy, aName, aBuf);
       
    90 		thisSAP->iPLMLink.Deque();
       
    91 		}
       
    92 	}
       
    93 
       
    94 /*Check if we have any outstanding requests registered by the clients*/
       
    95 TBool TPLMManager::AnyOutstandingClientRequest() const
       
    96 	{
       
    97 	LOG_FUNC
       
    98 	if(iPLMQue.IsEmpty())
       
    99 		{
       
   100 		return EFalse;
       
   101 		}
       
   102 	else
       
   103 		{
       
   104 		return ETrue;
       
   105 		}
       
   106 	}
       
   107 
       
   108 // ------------------------------------------------------------------------
       
   109 // class CPhysicalLinkMetrics
       
   110 // ------------------------------------------------------------------------
       
   111 
       
   112 
       
   113 CPhysicalLinkMetrics* CPhysicalLinkMetrics::NewL(CPhysicalLink& aLink, MHCICommandQueue& aCmdController)
       
   114 	{
       
   115 	LOG_STATIC_FUNC
       
   116 	
       
   117 	CPhysicalLinkMetrics* self = new(ELeave) CPhysicalLinkMetrics(aLink, aCmdController);
       
   118 	CleanupStack::PushL(self);
       
   119 	self->ConstructL();
       
   120 	CleanupStack::Pop(self);
       
   121 	return self;
       
   122 	}
       
   123 
       
   124 CPhysicalLinkMetrics::CPhysicalLinkMetrics(CPhysicalLink& aLink, MHCICommandQueue& aCmdController)
       
   125 	: iParent(aLink),
       
   126 	  iCmdController(aCmdController),
       
   127 	  iQueLink(this)
       
   128 	{
       
   129 	TCallBack plmCb(PLMEventReceived, this);
       
   130 	iPLMTimer.Set(plmCb);
       
   131 	
       
   132 	iParent.SubscribeLinkObserver(*this);
       
   133 	}
       
   134 
       
   135 void CPhysicalLinkMetrics::ConstructL()
       
   136 	{
       
   137 	LOG_FUNC
       
   138 	}
       
   139 
       
   140 CPhysicalLinkMetrics::~CPhysicalLinkMetrics()
       
   141 	{
       
   142 	RemovePLMCommands();
       
   143 	}
       
   144 
       
   145 void CPhysicalLinkMetrics::PhysicalLinkChange(const TBTBasebandEventNotification& aEvent, CPhysicalLink& /* aPhysicalLink */)
       
   146 	{
       
   147 	LOG_FUNC;
       
   148 	if (aEvent.EventType() == ENotifyPhysicalLinkDown || aEvent.EventType() == ENotifyPhysicalLinkError)
       
   149 		{
       
   150 		RemovePLMPoll();
       
   151 		iRssi.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadRssiIoctl, &iDummyResult);
       
   152 		iLinkQuality.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadLinkQualityIoctl, &iDummyResult);
       
   153 		iFailedContactCounter.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadFailedContactCounterIoctl, &iDummyResult);
       
   154 		iTransmitPowerLevel.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadCurrentTransmitPowerLevelIoctl, &iDummyResult);
       
   155 		}
       
   156 	}
       
   157 
       
   158 TPhysicalLinkObserverQLink& CPhysicalLinkMetrics::ObserverQLink()
       
   159 	{
       
   160 	return iQueLink;
       
   161 	}
       
   162 
       
   163 void CPhysicalLinkMetrics::ReadNewPhysicalLinkMetricValue(TUint aIoctlName, CBTProxySAP& aSAP, TInt aCurrentValue)
       
   164 	{
       
   165 	LOG_FUNC;
       
   166 	switch (aIoctlName)
       
   167 		{
       
   168 		case KLMReadRssiIoctl:
       
   169 			{
       
   170 			// If the command has not been issued, we issue now
       
   171 			if (iRssi.PLMState() == ECommandIdle)
       
   172 				{
       
   173 				iRssi.UpdatePLMValue(aCurrentValue);
       
   174 				iRssi.RegisterProxySAP(aSAP);
       
   175 				//Issue the command and change the state to ECommandIssued
       
   176 				ReadRssiCommand();
       
   177 				}
       
   178 			// Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
       
   179 			// different to the currently cached value, we complete straight away
       
   180 			else if (iRssi.PLMState() == ECommandBlockedForTimer && aCurrentValue != iRssi.PLMValue()())
       
   181 				{
       
   182 				aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadRssiIoctl, &iRssi.PLMValue());
       
   183 				}
       
   184 			// Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
       
   185 			// and the value the user has is the same as the cached valuewe just queue the SAP.
       
   186 			else
       
   187 				{
       
   188 				iRssi.RegisterProxySAP(aSAP);
       
   189 				}
       
   190 			}
       
   191 			break;
       
   192 		case KLMReadLinkQualityIoctl:
       
   193 			{
       
   194 			// If the command has not been issued, we issue now
       
   195 			if (iLinkQuality.PLMState() == ECommandIdle)
       
   196 				{
       
   197 				iLinkQuality.UpdatePLMValue(aCurrentValue);
       
   198 				iLinkQuality.RegisterProxySAP(aSAP);
       
   199 				//Issue the command and change the state to ECommandIssued
       
   200 				ReadLinkQualityCommand();
       
   201 				}
       
   202 			// Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
       
   203 			// different to the currently cached value, we complete straight away
       
   204 			else if (iLinkQuality.PLMState() == ECommandBlockedForTimer && aCurrentValue != iLinkQuality.PLMValue()())
       
   205 				{
       
   206 				aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadLinkQualityIoctl, &iLinkQuality.PLMValue());
       
   207 				}
       
   208 			// Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
       
   209 			// and the value the user has is the same as the cached valuewe just queue the SAP.
       
   210 			else
       
   211 				{
       
   212 				iLinkQuality.RegisterProxySAP(aSAP);
       
   213 				}
       
   214 			}
       
   215 			break;
       
   216 		case KLMReadFailedContactCounterIoctl:
       
   217 			{
       
   218 			// If the command has not been issued, we issue now
       
   219 			if (iFailedContactCounter.PLMState() == ECommandIdle)
       
   220 				{
       
   221 				iFailedContactCounter.UpdatePLMValue(aCurrentValue);
       
   222 				iFailedContactCounter.RegisterProxySAP(aSAP);
       
   223 				//Issue the command and change the state to ECommandIssued
       
   224 				ReadFailedContactCounterCommand();
       
   225 				}
       
   226 			// Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
       
   227 			// different to the currently cached value, we complete straight away
       
   228 			else if (iFailedContactCounter.PLMState() == ECommandBlockedForTimer && aCurrentValue != iFailedContactCounter.PLMValue()())
       
   229 				{
       
   230 				aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadFailedContactCounterIoctl, &iFailedContactCounter.PLMValue());
       
   231 				}
       
   232 			// Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
       
   233 			// and the value the user has is the same as the cached valuewe just queue the SAP.
       
   234 			else
       
   235 				{
       
   236 				iFailedContactCounter.RegisterProxySAP(aSAP);
       
   237 				}
       
   238 			}
       
   239 			break;
       
   240 		case KLMReadCurrentTransmitPowerLevelIoctl:
       
   241 			{
       
   242 			// If the command has not been issued, we issue now
       
   243 			if (iTransmitPowerLevel.PLMState() == ECommandIdle)
       
   244 				{
       
   245 				iTransmitPowerLevel.UpdatePLMValue(aCurrentValue);
       
   246 				iTransmitPowerLevel.RegisterProxySAP(aSAP);
       
   247 				//Issue the command and change the state to ECommandIssued
       
   248 				ReadTransmitPowerLevelCommand();
       
   249 				}
       
   250 			// Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
       
   251 			// different to the currently cached value, we complete straight away
       
   252 			else if (iTransmitPowerLevel.PLMState() == ECommandBlockedForTimer && aCurrentValue != iTransmitPowerLevel.PLMValue()())
       
   253 				{
       
   254 				aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadCurrentTransmitPowerLevelIoctl, &iTransmitPowerLevel.PLMValue());
       
   255 				}
       
   256 			// Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
       
   257 			// and the value the user has is the same as the cached valuewe just queue the SAP.
       
   258 			else
       
   259 				{
       
   260 				iTransmitPowerLevel.RegisterProxySAP(aSAP);
       
   261 				}
       
   262 			}
       
   263 			break;
       
   264 		default:
       
   265 			__ASSERT_DEBUG(EFalse, Panic(EBTProxySAPInvalidIoctl));
       
   266 		}
       
   267 	}
       
   268 
       
   269 void CPhysicalLinkMetrics::ReadRssiCommand()
       
   270 	{
       
   271 	LOG_FUNC
       
   272 	TRAPD(err, ReadRssiCommandL());
       
   273 	if (err != KErrNone)
       
   274 		{
       
   275 		iRssi.NotifyQueuedProxySAPs(err, KLMReadRssiIoctl, &iDummyResult);
       
   276 		}
       
   277 	}
       
   278 
       
   279 void CPhysicalLinkMetrics::ReadRssiCommandL()
       
   280 	{
       
   281 	LOG_FUNC
       
   282 	// Ownership of cmd transfered even if MhcqAddCommandL leaves
       
   283 	CReadRSSICommand* cmd = CReadRSSICommand::NewL(iParent.Handle());
       
   284 	iCmdController.MhcqAddCommandL(cmd, *this);
       
   285 	iRssi.UpdatePLMState(ECommandIssued);
       
   286 	}
       
   287 
       
   288 void CPhysicalLinkMetrics::ReadLinkQualityCommand()
       
   289 	{
       
   290 	LOG_FUNC
       
   291 	TRAPD(err, ReadLinkQualityCommandL());
       
   292 	if (err != KErrNone)
       
   293 		{
       
   294 		iLinkQuality.NotifyQueuedProxySAPs(err, KLMReadLinkQualityIoctl, &iDummyResult);
       
   295 		}
       
   296 	}
       
   297 
       
   298 void CPhysicalLinkMetrics::ReadLinkQualityCommandL()
       
   299 	{
       
   300 	LOG_FUNC
       
   301 	// Ownership of cmd transfered even if MhcqAddCommandL leaves
       
   302 	CReadLinkQualityCommand* cmd = CReadLinkQualityCommand::NewL(iParent.Handle());
       
   303 	iCmdController.MhcqAddCommandL(cmd, *this);
       
   304 	iLinkQuality.UpdatePLMState(ECommandIssued);
       
   305 	}
       
   306 
       
   307 void CPhysicalLinkMetrics::ReadFailedContactCounterCommand()
       
   308 	{
       
   309 	LOG_FUNC
       
   310 	TRAPD(err, ReadFailedContactCounterCommandL());
       
   311 	if (err != KErrNone)
       
   312 		{
       
   313 		iFailedContactCounter.NotifyQueuedProxySAPs(err, KLMReadFailedContactCounterIoctl, &iDummyResult);
       
   314 		}
       
   315 	}
       
   316 
       
   317 void CPhysicalLinkMetrics::ReadFailedContactCounterCommandL()
       
   318 	{
       
   319 	LOG_FUNC
       
   320 	// Ownership of cmd transfered even if MhcqAddCommandL leaves
       
   321 	CReadFailedContactCounterCommand* cmd = CReadFailedContactCounterCommand::NewL(iParent.Handle());
       
   322 	iCmdController.MhcqAddCommandL(cmd, *this);
       
   323 	iFailedContactCounter.UpdatePLMState(ECommandIssued);
       
   324 	}
       
   325 
       
   326 void CPhysicalLinkMetrics::ReadTransmitPowerLevelCommand()
       
   327 	{
       
   328 	LOG_FUNC
       
   329 	TRAPD(err, ReadTransmitPowerLevelCommandL());
       
   330 	if (err != KErrNone)
       
   331 		{
       
   332 		iTransmitPowerLevel.NotifyQueuedProxySAPs(err, KLMReadCurrentTransmitPowerLevelIoctl, &iDummyResult);
       
   333 		}
       
   334 	}
       
   335 
       
   336 void CPhysicalLinkMetrics::ReadTransmitPowerLevelCommandL()
       
   337 	{
       
   338 	LOG_FUNC
       
   339 	// Ownership of cmd transfered even if MhcqAddCommandL leaves
       
   340 	CReadTransmitPowerLevelCommand* cmd = CReadTransmitPowerLevelCommand::NewL(iParent.Handle(), ECurrentTransmitPowerLevel);
       
   341 	iCmdController.MhcqAddCommandL(cmd, *this);
       
   342 	iTransmitPowerLevel.UpdatePLMState(ECommandIssued);
       
   343 	}
       
   344 
       
   345 void CPhysicalLinkMetrics::MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* aCommand)
       
   346 	{
       
   347 	LOG_FUNC
       
   348 	__ASSERT_DEBUG(aCommand, Panic(EHCIUnknownCommandEvent));   // this should never happen
       
   349 	LOG2(_L("error code:%d opcode:0x%x"), aErrorCode, aCommand->Opcode());
       
   350 	switch (aCommand->Opcode())
       
   351 		{
       
   352 		case KReadFailedContactCounterOpcode:
       
   353 			iFailedContactCounter.UpdatePLMState(ECommandIdle);			
       
   354 			iFailedContactCounter.NotifyQueuedProxySAPs(aErrorCode, KLMReadFailedContactCounterIoctl, &iDummyResult);
       
   355 			break;
       
   356 		
       
   357 		case KReadLinkQualityOpcode:
       
   358 			iLinkQuality.UpdatePLMState(ECommandIdle);
       
   359 			iLinkQuality.NotifyQueuedProxySAPs(aErrorCode, KLMReadLinkQualityIoctl, &iDummyResult);
       
   360 			break;
       
   361 		
       
   362 		case KReadRSSIOpcode:
       
   363 			iRssi.UpdatePLMState(ECommandIdle);
       
   364 			iRssi.NotifyQueuedProxySAPs(aErrorCode, KLMReadRssiIoctl, &iDummyResult);			
       
   365 			break;
       
   366 		
       
   367 		case KReadTransmitPowerLevelOpcode:
       
   368 			iTransmitPowerLevel.UpdatePLMState(ECommandIdle);
       
   369 			iTransmitPowerLevel.NotifyQueuedProxySAPs(aErrorCode, KLMReadCurrentTransmitPowerLevelIoctl, &iDummyResult);						
       
   370 			break;
       
   371 			
       
   372 		default:
       
   373 			//LOG1(_L("physicallinkmetrics.cpp: Invalid command opcode, expecting only PLM commands but got %d command"),aCommand->Opcode());
       
   374 			__ASSERT_DEBUG(EFalse, Panic(EHCICommandBadArgument));
       
   375 		}
       
   376 	}
       
   377 
       
   378 
       
   379 // From MHCICommandQueueClient
       
   380 void CPhysicalLinkMetrics::MhcqcCommandEventReceived(const THCIEventBase& aEvent,
       
   381 													 const CHCICommandBase* /*aRelatedCommand*/)
       
   382 	{
       
   383 	LOG_FUNC
       
   384 	switch(aEvent.EventCode())
       
   385 		{
       
   386 		case ECommandCompleteEvent:
       
   387 			{
       
   388 			const THCICommandCompleteEvent& completeEvent = THCICommandCompleteEvent::Cast(aEvent);
       
   389 			CommandCompleteEvent(completeEvent);
       
   390 			break;
       
   391 			}
       
   392 		
       
   393 		default:
       
   394 			{
       
   395 			LOG1(_L("Warning!! Unexpected Event Received (event code:%d)"), aEvent.EventCode());
       
   396 			__ASSERT_DEBUG(EFalse, Panic(EHCIUnexpectedEvent));
       
   397 			break;
       
   398 			}
       
   399 		}	
       
   400 	}
       
   401 
       
   402 void CPhysicalLinkMetrics::CommandCompleteEvent(const THCICommandCompleteEvent& aEvent)
       
   403 	{
       
   404 	LOG_FUNC
       
   405 	THCIOpcode opcode = aEvent.CommandOpcode();
       
   406 
       
   407 	switch (opcode)
       
   408 		{
       
   409 		case KReadFailedContactCounterOpcode:
       
   410 			{
       
   411 			const TReadFailedContactCounterCompleteEvent& event = TReadFailedContactCounterCompleteEvent::Cast(aEvent);
       
   412 			HandleReadFailedContactCounterCompleteEvent(event);
       
   413 			}
       
   414 			break;
       
   415 		
       
   416 		case KReadLinkQualityOpcode:
       
   417 			{
       
   418 			const TReadLinkQualityCompleteEvent& event = TReadLinkQualityCompleteEvent::Cast(aEvent);
       
   419 			HandleReadLinkQualityCompleteEvent(event);
       
   420 			}
       
   421 			break;
       
   422 		
       
   423 		case KReadRSSIOpcode:
       
   424 			{
       
   425 			const TReadRSSICompleteEvent& event = TReadRSSICompleteEvent::Cast(aEvent);
       
   426 			HandleReadRssiCompleteEvent(event);
       
   427 			}
       
   428 			break;
       
   429 		
       
   430 		case KReadTransmitPowerLevelOpcode:
       
   431 			{
       
   432 			const TReadTransmitPowerLevelCompleteEvent& event = TReadTransmitPowerLevelCompleteEvent::Cast(aEvent);
       
   433 			HandleReadTransmitPowerLevelCompleteEvent(event);
       
   434 			}
       
   435 			break;
       
   436 		
       
   437 		default:
       
   438 			LOG2(_L("Warning: Unexpected Command complete event! Opcode %d error code %d"), opcode, aEvent.ErrorCode());
       
   439 			__ASSERT_DEBUG(EFalse, Panic(EHCIUnknownCommandCompleteOpcode));
       
   440 			break;
       
   441 		}
       
   442 	}
       
   443 
       
   444 void CPhysicalLinkMetrics::HandleReadFailedContactCounterCompleteEvent(const TReadFailedContactCounterCompleteEvent& aEvent)
       
   445 	{
       
   446 	LOG_FUNC
       
   447 	TUint8 result = 0;
       
   448 	TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
       
   449 	if (err == KErrNone)
       
   450 		{
       
   451 		result = aEvent.FailedContactCounter();
       
   452 		}
       
   453 	
       
   454 	if (err != KErrNone || static_cast<TInt>(result) != iFailedContactCounter.PLMValue()())
       
   455 		{
       
   456 		iFailedContactCounter.UpdatePLMValue(result);
       
   457 		// Notify all SAPs via IoctlComplete, with the result or an error code
       
   458 		iFailedContactCounter.NotifyQueuedProxySAPs(err, KLMReadFailedContactCounterIoctl, &iFailedContactCounter.PLMValue());
       
   459 		}
       
   460 	iFailedContactCounter.UpdatePLMState(ECommandBlockedForTimer);		
       
   461 	QueueNextPLMPollIfNotAlreadyQueued();	
       
   462 	}
       
   463 
       
   464 void CPhysicalLinkMetrics::HandleReadLinkQualityCompleteEvent(const TReadLinkQualityCompleteEvent& aEvent)
       
   465 	{
       
   466 	LOG_FUNC
       
   467 	TUint8 result = 0;
       
   468 	TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
       
   469 	if (err == KErrNone)
       
   470 		{
       
   471 		result = aEvent.LinkQuality();
       
   472 		}
       
   473 	
       
   474 	// Notify all SAPs via IoctlComplete, with the result or an error code
       
   475 
       
   476 	if (err != KErrNone || static_cast<TInt>(result) != iLinkQuality.PLMValue()())
       
   477 		{
       
   478 		iLinkQuality.UpdatePLMValue(result);
       
   479 		// Notify all SAPs via IoctlComplete, with the result or an error code
       
   480 		iLinkQuality.NotifyQueuedProxySAPs(err, KLMReadLinkQualityIoctl, &iLinkQuality.PLMValue());
       
   481 		}
       
   482 	iLinkQuality.UpdatePLMState(ECommandBlockedForTimer);
       
   483 	QueueNextPLMPollIfNotAlreadyQueued();
       
   484 	}
       
   485 
       
   486 void CPhysicalLinkMetrics::HandleReadRssiCompleteEvent(const TReadRSSICompleteEvent& aEvent)
       
   487 	{
       
   488 	LOG_FUNC
       
   489 	TUint8 result = 0;
       
   490 	TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
       
   491 	if (err == KErrNone)
       
   492 		{
       
   493 		result = aEvent.RSSI().RSSI();
       
   494 		}
       
   495 	
       
   496 	if (err != KErrNone || static_cast<TInt>(result) != iRssi.PLMValue()())
       
   497 		{
       
   498 		iRssi.UpdatePLMValue(result);
       
   499 		// Notify all SAPs via IoctlComplete, with the result or an error code
       
   500 		iRssi.NotifyQueuedProxySAPs(err, KLMReadRssiIoctl, &iRssi.PLMValue());
       
   501 		}
       
   502 	iRssi.UpdatePLMState(ECommandBlockedForTimer);
       
   503 	QueueNextPLMPollIfNotAlreadyQueued();
       
   504 	}
       
   505 
       
   506 void CPhysicalLinkMetrics::HandleReadTransmitPowerLevelCompleteEvent(const TReadTransmitPowerLevelCompleteEvent& aEvent)
       
   507 	{
       
   508 	LOG_FUNC
       
   509 	TUint8 result = 0;
       
   510 	TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
       
   511 	if (err == KErrNone)
       
   512 		{
       
   513 		result = aEvent.TransmitPowerLevel();
       
   514 		}
       
   515 	
       
   516 	if (err != KErrNone || static_cast<TInt>(result) != iTransmitPowerLevel.PLMValue()())
       
   517 		{
       
   518 		iTransmitPowerLevel.UpdatePLMValue(result);
       
   519 		// Notify all SAPs via IoctlComplete, with the result or an error code
       
   520 		iTransmitPowerLevel.NotifyQueuedProxySAPs(err, KLMReadCurrentTransmitPowerLevelIoctl, &iTransmitPowerLevel.PLMValue());
       
   521 		}
       
   522 	iTransmitPowerLevel.UpdatePLMState(ECommandBlockedForTimer);
       
   523 	QueueNextPLMPollIfNotAlreadyQueued();
       
   524 	}
       
   525 
       
   526 /*static*/ TInt CPhysicalLinkMetrics::PLMEventReceived(TAny* aThis)
       
   527 	{
       
   528 	static_cast<CPhysicalLinkMetrics*>(aThis)->iPLMTimerQueued = EFalse;	
       
   529 	
       
   530 	/*Send the PLM commands if there are any outstanding requests*/	
       
   531 	static_cast<CPhysicalLinkMetrics*>(aThis)->DoRssiTimerEvent();
       
   532 	static_cast<CPhysicalLinkMetrics*>(aThis)->DoLinkQualityTimerEvent();
       
   533 	static_cast<CPhysicalLinkMetrics*>(aThis)->DoFailedContactCounterTimerEvent();
       
   534 	static_cast<CPhysicalLinkMetrics*>(aThis)->DoTransmitPowerLevelTimerEvent();
       
   535 	
       
   536 	return KErrNone;
       
   537 	}
       
   538 
       
   539 
       
   540 void CPhysicalLinkMetrics::DoRssiTimerEvent()
       
   541 	{
       
   542 	LOG_FUNC
       
   543 	iRssi.UpdatePLMState(ECommandIdle);
       
   544 	if (iRssi.AnyOutstandingClientRequest())
       
   545 		{
       
   546 		ReadRssiCommand();
       
   547 		}
       
   548 	}
       
   549 
       
   550 void CPhysicalLinkMetrics::DoLinkQualityTimerEvent()
       
   551 	{
       
   552 	LOG_FUNC
       
   553 	iLinkQuality.UpdatePLMState(ECommandIdle);
       
   554 	if (iLinkQuality.AnyOutstandingClientRequest())
       
   555 		{
       
   556 		ReadLinkQualityCommand();
       
   557 		}
       
   558 	}
       
   559 
       
   560 void CPhysicalLinkMetrics::DoFailedContactCounterTimerEvent()
       
   561 	{
       
   562 	LOG_FUNC
       
   563 	iFailedContactCounter.UpdatePLMState(ECommandIdle);
       
   564 	if (iFailedContactCounter.AnyOutstandingClientRequest())
       
   565 		{
       
   566 		ReadFailedContactCounterCommand();
       
   567 		}
       
   568 	}
       
   569 
       
   570 void CPhysicalLinkMetrics::DoTransmitPowerLevelTimerEvent()
       
   571 	{
       
   572 	LOG_FUNC
       
   573 	iTransmitPowerLevel.UpdatePLMState(ECommandIdle);
       
   574 	if (iTransmitPowerLevel.AnyOutstandingClientRequest())
       
   575 		{
       
   576 		ReadTransmitPowerLevelCommand();
       
   577 		}
       
   578 	}
       
   579 
       
   580 void CPhysicalLinkMetrics::RemovePLMCommands()
       
   581 	{
       
   582 	LOG_FUNC
       
   583 	iCmdController.MhcqRemoveAllCommands(*this);
       
   584 	}
       
   585 
       
   586 
       
   587 /* A common timer is used for all the 4 PLMs. Which ever PLM command completes first will start the timer  
       
   588  * for the subsequent requests. When the timer completes we will send all the PLM commands (for which there are 
       
   589  * outstanding requests) and start the timer again with the first completed PLM command.
       
   590  */ 
       
   591 void CPhysicalLinkMetrics::QueueNextPLMPollIfNotAlreadyQueued()
       
   592 	{	
       
   593 	LOG_FUNC
       
   594 	TUint sniffInterval = iParent.GetSniffInterval();
       
   595 	if(!iPLMTimerQueued)
       
   596 		{
       
   597 		//If we are in sniff mode (i.e. sniff interval is greater than zero) and the sniff interval is greater 
       
   598 		// then default PLM poll interval then PLM commands should be sent after every sniff interval only  
       
   599 		if( sniffInterval > KPLMPollInterval)
       
   600 			{
       
   601 			BTSocketTimer::Queue(sniffInterval, iPLMTimer);
       
   602 			}
       
   603 		else
       
   604 			{
       
   605 			BTSocketTimer::Queue(KPLMPollInterval, iPLMTimer);
       
   606 			}
       
   607 		iPLMTimerQueued = ETrue;
       
   608 		}
       
   609 	}
       
   610 
       
   611 void CPhysicalLinkMetrics::RemovePLMPoll()
       
   612 	{
       
   613 	LOG_FUNC
       
   614 	//It is safe to call remove even if the timer is already removed.
       
   615 	BTSocketTimer::Remove(iPLMTimer);
       
   616 	iPLMTimerQueued = EFalse;
       
   617 	}
       
   618