--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/physicallinkmetrics.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,618 @@
+// 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 "physicallinkmetrics.h"
+#include "physicallinks.h"
+#include "linkutil.h"
+#include "ProxySAP.h"
+#include "btsockettimer.h"
+
+#include <bluetooth/hci/hciutil.h>
+#include <bluetooth/hci/readfailedcontactcountercommand.h>
+#include <bluetooth/hci/readlinkqualitycommand.h>
+#include <bluetooth/hci/readrssicommand.h>
+#include <bluetooth/hci/readtransmitpowerlevelcommand.h>
+#include <bluetooth/hci/readrssicompleteevent.h>
+#include <bluetooth/hci/readlinkqualitycompleteevent.h>
+#include <bluetooth/hci/readfailedcontactcountercompleteevent.h>
+#include <bluetooth/hci/readtransmitpowerlevelcompleteevent.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
+#endif
+
+
+
+
+TPLMManager::TPLMManager()
+ :iPLMQue(_FOFF(CBTProxySAP, iPLMLink))
+ {
+ LOG_FUNC
+ }
+void TPLMManager::UpdatePLMState(THciCommandState aPLMState)
+ {
+ LOG_FUNC
+ FTRACE(FPrint(_L("TPLMManager::UpdatePLMState, Previous state :: %d\n"), iPLMState));
+ iPLMState = aPLMState;
+ FTRACE(FPrint(_L("TPLMManager::UpdatePLMState, Changed state :: %d\n"), iPLMState));
+ }
+
+void TPLMManager::RegisterProxySAP(CBTProxySAP& aSAP)
+ {
+ LOG_FUNC
+ iPLMQue.AddLast(aSAP);
+ }
+
+void TPLMManager::UpdatePLMValue(TInt aPLMValue)
+ {
+ LOG_FUNC
+ FTRACE(FPrint(_L("TPLMManager::UpdatePLMValue, Previous PLM value :: %d\n"), (PLMValue())() ));
+ iPLMValue() = aPLMValue;
+ FTRACE(FPrint(_L("TPLMManager::UpdatePLMValue, Changed PLM value :: %d\n"), (PLMValue())() ));
+ }
+
+TPckgBuf<TInt>& TPLMManager::PLMValue()
+ {
+ LOG_FUNC
+ return iPLMValue;
+ }
+
+THciCommandState TPLMManager::PLMState() const
+ {
+ LOG_FUNC
+ return iPLMState;
+ }
+
+void TPLMManager::NotifyQueuedProxySAPs(TInt aErr, TUint aName, TDesC8* aBuf)
+ {
+ LOG_FUNC
+ TDblQueIter<CBTProxySAP> iter(iPLMQue);
+ CBTProxySAP* thisSAP;
+
+ // Iterate through all ProxySAPs that have requested this PLM, notifying them
+ while ((thisSAP = iter++) != NULL)
+ {
+ thisSAP->IoctlComplete(aErr, KSolBtLMProxy, aName, aBuf);
+ thisSAP->iPLMLink.Deque();
+ }
+ }
+
+/*Check if we have any outstanding requests registered by the clients*/
+TBool TPLMManager::AnyOutstandingClientRequest() const
+ {
+ LOG_FUNC
+ if(iPLMQue.IsEmpty())
+ {
+ return EFalse;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+
+// ------------------------------------------------------------------------
+// class CPhysicalLinkMetrics
+// ------------------------------------------------------------------------
+
+
+CPhysicalLinkMetrics* CPhysicalLinkMetrics::NewL(CPhysicalLink& aLink, MHCICommandQueue& aCmdController)
+ {
+ LOG_STATIC_FUNC
+
+ CPhysicalLinkMetrics* self = new(ELeave) CPhysicalLinkMetrics(aLink, aCmdController);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CPhysicalLinkMetrics::CPhysicalLinkMetrics(CPhysicalLink& aLink, MHCICommandQueue& aCmdController)
+ : iParent(aLink),
+ iCmdController(aCmdController),
+ iQueLink(this)
+ {
+ TCallBack plmCb(PLMEventReceived, this);
+ iPLMTimer.Set(plmCb);
+
+ iParent.SubscribeLinkObserver(*this);
+ }
+
+void CPhysicalLinkMetrics::ConstructL()
+ {
+ LOG_FUNC
+ }
+
+CPhysicalLinkMetrics::~CPhysicalLinkMetrics()
+ {
+ RemovePLMCommands();
+ }
+
+void CPhysicalLinkMetrics::PhysicalLinkChange(const TBTBasebandEventNotification& aEvent, CPhysicalLink& /* aPhysicalLink */)
+ {
+ LOG_FUNC;
+ if (aEvent.EventType() == ENotifyPhysicalLinkDown || aEvent.EventType() == ENotifyPhysicalLinkError)
+ {
+ RemovePLMPoll();
+ iRssi.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadRssiIoctl, &iDummyResult);
+ iLinkQuality.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadLinkQualityIoctl, &iDummyResult);
+ iFailedContactCounter.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadFailedContactCounterIoctl, &iDummyResult);
+ iTransmitPowerLevel.NotifyQueuedProxySAPs(KErrDisconnected, KLMReadCurrentTransmitPowerLevelIoctl, &iDummyResult);
+ }
+ }
+
+TPhysicalLinkObserverQLink& CPhysicalLinkMetrics::ObserverQLink()
+ {
+ return iQueLink;
+ }
+
+void CPhysicalLinkMetrics::ReadNewPhysicalLinkMetricValue(TUint aIoctlName, CBTProxySAP& aSAP, TInt aCurrentValue)
+ {
+ LOG_FUNC;
+ switch (aIoctlName)
+ {
+ case KLMReadRssiIoctl:
+ {
+ // If the command has not been issued, we issue now
+ if (iRssi.PLMState() == ECommandIdle)
+ {
+ iRssi.UpdatePLMValue(aCurrentValue);
+ iRssi.RegisterProxySAP(aSAP);
+ //Issue the command and change the state to ECommandIssued
+ ReadRssiCommand();
+ }
+ // Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
+ // different to the currently cached value, we complete straight away
+ else if (iRssi.PLMState() == ECommandBlockedForTimer && aCurrentValue != iRssi.PLMValue()())
+ {
+ aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadRssiIoctl, &iRssi.PLMValue());
+ }
+ // Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
+ // and the value the user has is the same as the cached valuewe just queue the SAP.
+ else
+ {
+ iRssi.RegisterProxySAP(aSAP);
+ }
+ }
+ break;
+ case KLMReadLinkQualityIoctl:
+ {
+ // If the command has not been issued, we issue now
+ if (iLinkQuality.PLMState() == ECommandIdle)
+ {
+ iLinkQuality.UpdatePLMValue(aCurrentValue);
+ iLinkQuality.RegisterProxySAP(aSAP);
+ //Issue the command and change the state to ECommandIssued
+ ReadLinkQualityCommand();
+ }
+ // Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
+ // different to the currently cached value, we complete straight away
+ else if (iLinkQuality.PLMState() == ECommandBlockedForTimer && aCurrentValue != iLinkQuality.PLMValue()())
+ {
+ aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadLinkQualityIoctl, &iLinkQuality.PLMValue());
+ }
+ // Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
+ // and the value the user has is the same as the cached valuewe just queue the SAP.
+ else
+ {
+ iLinkQuality.RegisterProxySAP(aSAP);
+ }
+ }
+ break;
+ case KLMReadFailedContactCounterIoctl:
+ {
+ // If the command has not been issued, we issue now
+ if (iFailedContactCounter.PLMState() == ECommandIdle)
+ {
+ iFailedContactCounter.UpdatePLMValue(aCurrentValue);
+ iFailedContactCounter.RegisterProxySAP(aSAP);
+ //Issue the command and change the state to ECommandIssued
+ ReadFailedContactCounterCommand();
+ }
+ // Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
+ // different to the currently cached value, we complete straight away
+ else if (iFailedContactCounter.PLMState() == ECommandBlockedForTimer && aCurrentValue != iFailedContactCounter.PLMValue()())
+ {
+ aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadFailedContactCounterIoctl, &iFailedContactCounter.PLMValue());
+ }
+ // Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
+ // and the value the user has is the same as the cached valuewe just queue the SAP.
+ else
+ {
+ iFailedContactCounter.RegisterProxySAP(aSAP);
+ }
+ }
+ break;
+ case KLMReadCurrentTransmitPowerLevelIoctl:
+ {
+ // If the command has not been issued, we issue now
+ if (iTransmitPowerLevel.PLMState() == ECommandIdle)
+ {
+ iTransmitPowerLevel.UpdatePLMValue(aCurrentValue);
+ iTransmitPowerLevel.RegisterProxySAP(aSAP);
+ //Issue the command and change the state to ECommandIssued
+ ReadTransmitPowerLevelCommand();
+ }
+ // Otherwise, if the command is waiting for the timer to expire, and the current value the user has is
+ // different to the currently cached value, we complete straight away
+ else if (iTransmitPowerLevel.PLMState() == ECommandBlockedForTimer && aCurrentValue != iTransmitPowerLevel.PLMValue()())
+ {
+ aSAP.IoctlComplete(KErrNone, KSolBtLMProxy, KLMReadCurrentTransmitPowerLevelIoctl, &iTransmitPowerLevel.PLMValue());
+ }
+ // Otherwise, if we are waiting for the command to complete, or we are waiting for the timer to expire,
+ // and the value the user has is the same as the cached valuewe just queue the SAP.
+ else
+ {
+ iTransmitPowerLevel.RegisterProxySAP(aSAP);
+ }
+ }
+ break;
+ default:
+ __ASSERT_DEBUG(EFalse, Panic(EBTProxySAPInvalidIoctl));
+ }
+ }
+
+void CPhysicalLinkMetrics::ReadRssiCommand()
+ {
+ LOG_FUNC
+ TRAPD(err, ReadRssiCommandL());
+ if (err != KErrNone)
+ {
+ iRssi.NotifyQueuedProxySAPs(err, KLMReadRssiIoctl, &iDummyResult);
+ }
+ }
+
+void CPhysicalLinkMetrics::ReadRssiCommandL()
+ {
+ LOG_FUNC
+ // Ownership of cmd transfered even if MhcqAddCommandL leaves
+ CReadRSSICommand* cmd = CReadRSSICommand::NewL(iParent.Handle());
+ iCmdController.MhcqAddCommandL(cmd, *this);
+ iRssi.UpdatePLMState(ECommandIssued);
+ }
+
+void CPhysicalLinkMetrics::ReadLinkQualityCommand()
+ {
+ LOG_FUNC
+ TRAPD(err, ReadLinkQualityCommandL());
+ if (err != KErrNone)
+ {
+ iLinkQuality.NotifyQueuedProxySAPs(err, KLMReadLinkQualityIoctl, &iDummyResult);
+ }
+ }
+
+void CPhysicalLinkMetrics::ReadLinkQualityCommandL()
+ {
+ LOG_FUNC
+ // Ownership of cmd transfered even if MhcqAddCommandL leaves
+ CReadLinkQualityCommand* cmd = CReadLinkQualityCommand::NewL(iParent.Handle());
+ iCmdController.MhcqAddCommandL(cmd, *this);
+ iLinkQuality.UpdatePLMState(ECommandIssued);
+ }
+
+void CPhysicalLinkMetrics::ReadFailedContactCounterCommand()
+ {
+ LOG_FUNC
+ TRAPD(err, ReadFailedContactCounterCommandL());
+ if (err != KErrNone)
+ {
+ iFailedContactCounter.NotifyQueuedProxySAPs(err, KLMReadFailedContactCounterIoctl, &iDummyResult);
+ }
+ }
+
+void CPhysicalLinkMetrics::ReadFailedContactCounterCommandL()
+ {
+ LOG_FUNC
+ // Ownership of cmd transfered even if MhcqAddCommandL leaves
+ CReadFailedContactCounterCommand* cmd = CReadFailedContactCounterCommand::NewL(iParent.Handle());
+ iCmdController.MhcqAddCommandL(cmd, *this);
+ iFailedContactCounter.UpdatePLMState(ECommandIssued);
+ }
+
+void CPhysicalLinkMetrics::ReadTransmitPowerLevelCommand()
+ {
+ LOG_FUNC
+ TRAPD(err, ReadTransmitPowerLevelCommandL());
+ if (err != KErrNone)
+ {
+ iTransmitPowerLevel.NotifyQueuedProxySAPs(err, KLMReadCurrentTransmitPowerLevelIoctl, &iDummyResult);
+ }
+ }
+
+void CPhysicalLinkMetrics::ReadTransmitPowerLevelCommandL()
+ {
+ LOG_FUNC
+ // Ownership of cmd transfered even if MhcqAddCommandL leaves
+ CReadTransmitPowerLevelCommand* cmd = CReadTransmitPowerLevelCommand::NewL(iParent.Handle(), ECurrentTransmitPowerLevel);
+ iCmdController.MhcqAddCommandL(cmd, *this);
+ iTransmitPowerLevel.UpdatePLMState(ECommandIssued);
+ }
+
+void CPhysicalLinkMetrics::MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* aCommand)
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aCommand, Panic(EHCIUnknownCommandEvent)); // this should never happen
+ LOG2(_L("error code:%d opcode:0x%x"), aErrorCode, aCommand->Opcode());
+ switch (aCommand->Opcode())
+ {
+ case KReadFailedContactCounterOpcode:
+ iFailedContactCounter.UpdatePLMState(ECommandIdle);
+ iFailedContactCounter.NotifyQueuedProxySAPs(aErrorCode, KLMReadFailedContactCounterIoctl, &iDummyResult);
+ break;
+
+ case KReadLinkQualityOpcode:
+ iLinkQuality.UpdatePLMState(ECommandIdle);
+ iLinkQuality.NotifyQueuedProxySAPs(aErrorCode, KLMReadLinkQualityIoctl, &iDummyResult);
+ break;
+
+ case KReadRSSIOpcode:
+ iRssi.UpdatePLMState(ECommandIdle);
+ iRssi.NotifyQueuedProxySAPs(aErrorCode, KLMReadRssiIoctl, &iDummyResult);
+ break;
+
+ case KReadTransmitPowerLevelOpcode:
+ iTransmitPowerLevel.UpdatePLMState(ECommandIdle);
+ iTransmitPowerLevel.NotifyQueuedProxySAPs(aErrorCode, KLMReadCurrentTransmitPowerLevelIoctl, &iDummyResult);
+ break;
+
+ default:
+ //LOG1(_L("physicallinkmetrics.cpp: Invalid command opcode, expecting only PLM commands but got %d command"),aCommand->Opcode());
+ __ASSERT_DEBUG(EFalse, Panic(EHCICommandBadArgument));
+ }
+ }
+
+
+// From MHCICommandQueueClient
+void CPhysicalLinkMetrics::MhcqcCommandEventReceived(const THCIEventBase& aEvent,
+ const CHCICommandBase* /*aRelatedCommand*/)
+ {
+ LOG_FUNC
+ switch(aEvent.EventCode())
+ {
+ case ECommandCompleteEvent:
+ {
+ const THCICommandCompleteEvent& completeEvent = THCICommandCompleteEvent::Cast(aEvent);
+ CommandCompleteEvent(completeEvent);
+ break;
+ }
+
+ default:
+ {
+ LOG1(_L("Warning!! Unexpected Event Received (event code:%d)"), aEvent.EventCode());
+ __ASSERT_DEBUG(EFalse, Panic(EHCIUnexpectedEvent));
+ break;
+ }
+ }
+ }
+
+void CPhysicalLinkMetrics::CommandCompleteEvent(const THCICommandCompleteEvent& aEvent)
+ {
+ LOG_FUNC
+ THCIOpcode opcode = aEvent.CommandOpcode();
+
+ switch (opcode)
+ {
+ case KReadFailedContactCounterOpcode:
+ {
+ const TReadFailedContactCounterCompleteEvent& event = TReadFailedContactCounterCompleteEvent::Cast(aEvent);
+ HandleReadFailedContactCounterCompleteEvent(event);
+ }
+ break;
+
+ case KReadLinkQualityOpcode:
+ {
+ const TReadLinkQualityCompleteEvent& event = TReadLinkQualityCompleteEvent::Cast(aEvent);
+ HandleReadLinkQualityCompleteEvent(event);
+ }
+ break;
+
+ case KReadRSSIOpcode:
+ {
+ const TReadRSSICompleteEvent& event = TReadRSSICompleteEvent::Cast(aEvent);
+ HandleReadRssiCompleteEvent(event);
+ }
+ break;
+
+ case KReadTransmitPowerLevelOpcode:
+ {
+ const TReadTransmitPowerLevelCompleteEvent& event = TReadTransmitPowerLevelCompleteEvent::Cast(aEvent);
+ HandleReadTransmitPowerLevelCompleteEvent(event);
+ }
+ break;
+
+ default:
+ LOG2(_L("Warning: Unexpected Command complete event! Opcode %d error code %d"), opcode, aEvent.ErrorCode());
+ __ASSERT_DEBUG(EFalse, Panic(EHCIUnknownCommandCompleteOpcode));
+ break;
+ }
+ }
+
+void CPhysicalLinkMetrics::HandleReadFailedContactCounterCompleteEvent(const TReadFailedContactCounterCompleteEvent& aEvent)
+ {
+ LOG_FUNC
+ TUint8 result = 0;
+ TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
+ if (err == KErrNone)
+ {
+ result = aEvent.FailedContactCounter();
+ }
+
+ if (err != KErrNone || static_cast<TInt>(result) != iFailedContactCounter.PLMValue()())
+ {
+ iFailedContactCounter.UpdatePLMValue(result);
+ // Notify all SAPs via IoctlComplete, with the result or an error code
+ iFailedContactCounter.NotifyQueuedProxySAPs(err, KLMReadFailedContactCounterIoctl, &iFailedContactCounter.PLMValue());
+ }
+ iFailedContactCounter.UpdatePLMState(ECommandBlockedForTimer);
+ QueueNextPLMPollIfNotAlreadyQueued();
+ }
+
+void CPhysicalLinkMetrics::HandleReadLinkQualityCompleteEvent(const TReadLinkQualityCompleteEvent& aEvent)
+ {
+ LOG_FUNC
+ TUint8 result = 0;
+ TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
+ if (err == KErrNone)
+ {
+ result = aEvent.LinkQuality();
+ }
+
+ // Notify all SAPs via IoctlComplete, with the result or an error code
+
+ if (err != KErrNone || static_cast<TInt>(result) != iLinkQuality.PLMValue()())
+ {
+ iLinkQuality.UpdatePLMValue(result);
+ // Notify all SAPs via IoctlComplete, with the result or an error code
+ iLinkQuality.NotifyQueuedProxySAPs(err, KLMReadLinkQualityIoctl, &iLinkQuality.PLMValue());
+ }
+ iLinkQuality.UpdatePLMState(ECommandBlockedForTimer);
+ QueueNextPLMPollIfNotAlreadyQueued();
+ }
+
+void CPhysicalLinkMetrics::HandleReadRssiCompleteEvent(const TReadRSSICompleteEvent& aEvent)
+ {
+ LOG_FUNC
+ TUint8 result = 0;
+ TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
+ if (err == KErrNone)
+ {
+ result = aEvent.RSSI().RSSI();
+ }
+
+ if (err != KErrNone || static_cast<TInt>(result) != iRssi.PLMValue()())
+ {
+ iRssi.UpdatePLMValue(result);
+ // Notify all SAPs via IoctlComplete, with the result or an error code
+ iRssi.NotifyQueuedProxySAPs(err, KLMReadRssiIoctl, &iRssi.PLMValue());
+ }
+ iRssi.UpdatePLMState(ECommandBlockedForTimer);
+ QueueNextPLMPollIfNotAlreadyQueued();
+ }
+
+void CPhysicalLinkMetrics::HandleReadTransmitPowerLevelCompleteEvent(const TReadTransmitPowerLevelCompleteEvent& aEvent)
+ {
+ LOG_FUNC
+ TUint8 result = 0;
+ TInt err = CHciUtil::SymbianErrorCode(aEvent.ErrorCode());
+ if (err == KErrNone)
+ {
+ result = aEvent.TransmitPowerLevel();
+ }
+
+ if (err != KErrNone || static_cast<TInt>(result) != iTransmitPowerLevel.PLMValue()())
+ {
+ iTransmitPowerLevel.UpdatePLMValue(result);
+ // Notify all SAPs via IoctlComplete, with the result or an error code
+ iTransmitPowerLevel.NotifyQueuedProxySAPs(err, KLMReadCurrentTransmitPowerLevelIoctl, &iTransmitPowerLevel.PLMValue());
+ }
+ iTransmitPowerLevel.UpdatePLMState(ECommandBlockedForTimer);
+ QueueNextPLMPollIfNotAlreadyQueued();
+ }
+
+/*static*/ TInt CPhysicalLinkMetrics::PLMEventReceived(TAny* aThis)
+ {
+ static_cast<CPhysicalLinkMetrics*>(aThis)->iPLMTimerQueued = EFalse;
+
+ /*Send the PLM commands if there are any outstanding requests*/
+ static_cast<CPhysicalLinkMetrics*>(aThis)->DoRssiTimerEvent();
+ static_cast<CPhysicalLinkMetrics*>(aThis)->DoLinkQualityTimerEvent();
+ static_cast<CPhysicalLinkMetrics*>(aThis)->DoFailedContactCounterTimerEvent();
+ static_cast<CPhysicalLinkMetrics*>(aThis)->DoTransmitPowerLevelTimerEvent();
+
+ return KErrNone;
+ }
+
+
+void CPhysicalLinkMetrics::DoRssiTimerEvent()
+ {
+ LOG_FUNC
+ iRssi.UpdatePLMState(ECommandIdle);
+ if (iRssi.AnyOutstandingClientRequest())
+ {
+ ReadRssiCommand();
+ }
+ }
+
+void CPhysicalLinkMetrics::DoLinkQualityTimerEvent()
+ {
+ LOG_FUNC
+ iLinkQuality.UpdatePLMState(ECommandIdle);
+ if (iLinkQuality.AnyOutstandingClientRequest())
+ {
+ ReadLinkQualityCommand();
+ }
+ }
+
+void CPhysicalLinkMetrics::DoFailedContactCounterTimerEvent()
+ {
+ LOG_FUNC
+ iFailedContactCounter.UpdatePLMState(ECommandIdle);
+ if (iFailedContactCounter.AnyOutstandingClientRequest())
+ {
+ ReadFailedContactCounterCommand();
+ }
+ }
+
+void CPhysicalLinkMetrics::DoTransmitPowerLevelTimerEvent()
+ {
+ LOG_FUNC
+ iTransmitPowerLevel.UpdatePLMState(ECommandIdle);
+ if (iTransmitPowerLevel.AnyOutstandingClientRequest())
+ {
+ ReadTransmitPowerLevelCommand();
+ }
+ }
+
+void CPhysicalLinkMetrics::RemovePLMCommands()
+ {
+ LOG_FUNC
+ iCmdController.MhcqRemoveAllCommands(*this);
+ }
+
+
+/* A common timer is used for all the 4 PLMs. Which ever PLM command completes first will start the timer
+ * for the subsequent requests. When the timer completes we will send all the PLM commands (for which there are
+ * outstanding requests) and start the timer again with the first completed PLM command.
+ */
+void CPhysicalLinkMetrics::QueueNextPLMPollIfNotAlreadyQueued()
+ {
+ LOG_FUNC
+ TUint sniffInterval = iParent.GetSniffInterval();
+ if(!iPLMTimerQueued)
+ {
+ //If we are in sniff mode (i.e. sniff interval is greater than zero) and the sniff interval is greater
+ // then default PLM poll interval then PLM commands should be sent after every sniff interval only
+ if( sniffInterval > KPLMPollInterval)
+ {
+ BTSocketTimer::Queue(sniffInterval, iPLMTimer);
+ }
+ else
+ {
+ BTSocketTimer::Queue(KPLMPollInterval, iPLMTimer);
+ }
+ iPLMTimerQueued = ETrue;
+ }
+ }
+
+void CPhysicalLinkMetrics::RemovePLMPoll()
+ {
+ LOG_FUNC
+ //It is safe to call remove even if the timer is already removed.
+ BTSocketTimer::Remove(iPLMTimer);
+ iPLMTimerQueued = EFalse;
+ }
+