// 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:
// This implements the CLinkMgrProtocol object that is the contact point from
// BT PRT to the LinkMgr stack
// At present this class also remembers the configuration of the controller
// -- no particular reason - could be encapsulated in a class that the facade
// knows about.
//
//
#include <bt_sock.h>
#include <bluetooth/logger.h>
#include "debug.h"
#include <utf.h>
#include <bluetooth/hci/hciframe.h>
#include <bluetooth/aclsockaddr.h>
#include "linkmgr.h"
#include "hcifacade.h"
#include "bt.h"
#include "hostresolver.h"
#include "linkmuxer.h"
#include "physicallinksmanager.h"
#include "linkconsts.h"
#include "eirmanserver.h"
#include "eirmanager.h"
#include "eirpublisherlocalname.h"
#include "eirpublishertxpowerlevel.h"
#include "ProxySAP.h"
#include "SCOSAP.h"
#include "ACLSAP.h"
#include "VendorSAP.h"
#include "vendorspecific.h"
#include "Subscribers.h"
#include "BTSec.h"
#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
#endif
#ifdef _DEBUG
PANICCATEGORY("linkmgr");
#endif
const TInt KLengthOfDeviceClass = 11; // 11 bits in the device class portion of the CoD
const TInt KStartingOffsetOfDeviceClass = 2; // 2 LSB bits for format type
const TUint32 KDeviceClassReset = 0; // used to reset persistent data
// Constant which can be ANDed with a complete CoD bitmask to extract the device class portion.
const TInt KDeviceClassBitMask = ((1 << KLengthOfDeviceClass) - 1) << KStartingOffsetOfDeviceClass;
enum TLinkMgrPanic
{
ELinkMgrProtocolOpenedAfterClose,
ELinkMgrProtocolBadAFHHostChannelClassification,
EUnknownFatalError,
ELocalDeviceBadHandle,
ERegistrySessionClosedTooManyTimes,
ERegistrySessionDeletedWhenOpen,
};
void Panic(TLinkMgrPanic aPanic)
// Panic L2CAP due to stack bug.
{
LOG_STATIC_FUNC
_LIT(KL2CAPPanicName, "BTLinkMgr");
User::Panic(KL2CAPPanicName, aPanic);
}
// Construction & Initialisation
CLinkMgrProtocol::CLinkMgrProtocol(CBTSecMan& aSecMan, RBTControlPlane& aControlPlane, CBTCodServiceMan& aCodMan)
: CBluetoothProtocolBase(aSecMan, aControlPlane, aCodMan)
, iDebugModeDefinitionResult(KErrGeneral)
{
LOG_FUNC
TCallBack cb(TryToClose, this);
iIdleTimerEntry.Set(cb);
}
CLinkMgrProtocol::~CLinkMgrProtocol()
/**
Delete all our stuff
**/
{
LOG_FUNC
RemoveIdleTimerEntry();
// Delete setter P&S values
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetScanningStatus);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetLimitedDiscoverableStatus);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetDeviceClass);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetAFHHostChannelClassification);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetAFHChannelAssessmentMode);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetDeviceName);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetAcceptPairedOnlyMode);
// Delete standard P&S values (possibly trying to delete already deleted shared set+get values)
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetLocalDeviceAddress);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetPHYCount);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetConnectingStatus);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetScanningStatus);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetLimitedDiscoverableStatus);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetDeviceClass);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetDeviceName);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetAcceptPairedOnlyMode);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothHostResolverActive);
iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetSimplePairingDebugMode);
delete iPhysicalLinksMgr;
delete iInquiryMgr;
delete iEirManServer;
delete iACLStateFactory;
delete iSCOStateFactory;
SecMan().ClearHCICommandQueue(); // clears up the commands
SecMan().ClearLinksMgrProtocol();
SecMan().ClearPhysicalLinksMgr();
delete iLinkMuxer;
delete iHCIFacade;
delete iRegistryUpdater;
DeletePublications();
iSubscribers.ResetAndDestroy();
iLocalDevice.Close();
delete iRegSess;
}
CLinkMgrProtocol* CLinkMgrProtocol::NewL(CBTSecMan& aSecMan, RBTControlPlane& aControlPlane, CBTCodServiceMan& aCodMan)
{
LOG_STATIC_FUNC
CLinkMgrProtocol* i=new (ELeave) CLinkMgrProtocol(aSecMan, aControlPlane, aCodMan);
return i;
}
void CLinkMgrProtocol::InitL(TDesC& /*aTag*/)
/**
Pre-binding initialise.
Allocate any objects we need here.
ESOCK ensures that this function will only be called once per
object of this class, regardless of how long it hangs around.
**/
{
LOG_FUNC
__ASSERT_DEBUG(!iClosePending, Panic(ELinkMgrProtocolOpenedAfterClose));
__ASSERT_DEBUG(!iIdleEntryQueued, Panic(ELinkMgrProtocolOpenedAfterClose));
__ASSERT_DEBUG(!iHCIFacade, Panic(ELinkMgrProtocolOpenedAfterClose));
// Get the local device settings from persistent store
// By keeping a session open for the lifetime of this protocol
// we prevent RegServ being created during connection time.
LOG(_L("LinkMgr : Initialising RegistryServer"));
iRegSess = CRegistrySession::NewL(*this);
TInt err = iLocalDevice.Open(iRegSess->RegServ());
if (err ==KErrNone)
{
// read local device settings (e.g page scan\inquiry scan) from registry
err = iLocalDevice.Get(iLocalDeviceSettings); // ignore error - can continue
__ASSERT_DEBUG(err==KErrNone, Panic(EUnknownFatalError));
//
// Mask off the service class bits from the CoD -- we're not interested in the
// registry's values for anything other than the device class part.
// There's a nice terminology overload here, as the 'Class of Device' contains
// both a device class and a service class. It might have been nice if the
// getter and setter methods were 'ClassOfDevice', but even that wouldn't help
// much...
//
iLocalDeviceSettings.SetDeviceClass(iLocalDeviceSettings.DeviceClass() & KDeviceClassBitMask);
//NB - no (ELeave) here - in OOM we'd rather continue and not update the registry
//than Leave. All calls to methods are guarded by "if (iRegistryUpdater)"
iRegistryUpdater = new CRegistryUpdater(iLocalDevice, iLocalDeviceSettings);
}
LOG(_L("LinkMgr : Creating HCIFacade (and HCI)"));
iHCIFacade = CHCIFacade::NewL(*this); // Create HCI/HCIFacade first
iPhysicalLinksMgr = CPhysicalLinksManager::NewL(*this, *iHCIFacade, *iRegSess, SecMan(), CodMan());
iPhysicalLinksMgr->SetAcceptPairedOnlyMode(iLocalDeviceSettings.AcceptPairedOnlyMode()); // Tell the physical links manager the persisted value for the accept paired only mode
iHCIFacade->SetPhysicalLinksMgr(*iPhysicalLinksMgr); // Tell HCIFacade of ConnMgr
SecMan().SetPhysicalLinksMgr(*iPhysicalLinksMgr);
SecMan().SetLinksMgrProtocol(*this);
SecMan().SetHCICommandQueue(iHCIFacade->CommandQController());
LOG(_L("LinkMgr : Initialising Link Muxer"));
iLinkMuxer=CLinkMuxer::NewL(*this, *iHCIFacade);
iHCIFacade->SetLinkMuxer(*iLinkMuxer);
iACLStateFactory = CACLLinkStateFactory::NewL();
iSCOStateFactory = CSyncLinkStateFactory::NewL();
LOG(_L("LinkMgr : Initialising EirManServer"));
iEirManServer = CEirManServer::NewL(iHCIFacade->CommandQController(), *this);
LOG(_L("LinkMgr : Initialising InquiryMgr"));
iInquiryMgr = CBTInquiryMgr::NewL(*this);
iInquiryMgr->SetHCICommandQueue(iHCIFacade->CommandQController());
LOG(_L("LinkMgr : Configuring HCIFacade)"));
iHCIFacade->InitL(iLocalDeviceSettings);// passes ownership of device
// Inquiry and page scan is read from BT Registry and set it to P&S
// As there is no listening socket, they are set to OFF on HW yet!
// P&S value is taken to account as soon we open the first listening socket!
DefinePublications(iLocalDeviceSettings.ScanEnable());
// set up subscribers
CSubscriber* subscriber;
subscriber = CDiscoverabilitySubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
subscriber = CLimitedSubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
subscriber = CDeviceClassSubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
subscriber = CAFHHostChannelClassificationSubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
subscriber = CDeviceNameSubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
subscriber = CRegistryRemoteTableSubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
subscriber = CAcceptPairedOnlySubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
subscriber = CAFHChannelAssessmentModeSubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
if(iDebugModeDefinitionResult == KErrNone)
{
// Only subscribe on debug mode if we have managed to successfully define
// the key ourselves (this is because it needs to be protected with the very
// strong CommDD capability).
subscriber = CDebugModeSubscriber::NewL(*this);
CleanupStack::PushL(subscriber);
User::LeaveIfError(iSubscribers.Append(subscriber));
CleanupStack::Pop(subscriber);
}
// set CoD - leave if goes wrong, user's device will be "unknown" otherwise
// NB - In future we should tie this to the SDP Server...(or someother higher API...)
if (iLocalDeviceSettings.DeviceClass() && iLocalDeviceSettings.IsValidDeviceClass())
// Some phones never set their CoD in s/w, we don't want to blat
// over their h/w settings
{
iPendingLocalDeviceSettings.SetDeviceClass(iLocalDeviceSettings.DeviceClass()); //we expect this after power on
}
CodMan().Initialise(); // Cod Service Manager can now get a valid CoD
if(iLocalDeviceSettings.AFHChannelAssessmentMode() == EFalse)
// If this feature is supported it will start off switched on
{
SetAFHChannelAssessmentModeL(iLocalDeviceSettings.AFHChannelAssessmentMode());
}
//Attempt to make sure that controller has the same value as the registry
//and that the P&S key 'KPropertyKeyBluetoothGetLimitedDiscoverableStatus'
//is, as a consequence, 'Set' appropriately (when the associated controller
//event arrives).
DoSetLimitedDiscoverableL(iLocalDeviceSettings.LimitedDiscoverable());
LOG(_L("LinkMgr : Initialising complete"));
}
void CLinkMgrProtocol::DefinePublications(THCIScanEnable aHCIScanEnable)
{
LOG_FUNC
// 6 properties for setting.
// Its possible that these are re-defined below, but we are discarding any KErrAlreadyExists.
// As the setters require more capabilities we ensure that they get defined first.
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetScanningStatus,
RProperty::EInt,
KLOCAL_SERVICES_AND_NETWORK_CONTROL,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
// Even if we initialise KPropertyKeyBluetoothSetScanningStatus to Inquiry &
// Page scanning enabled, it's not turned on at this point. Only when first
// listening socket is opened, this value will control the inquiry scan & page scan
(void)(iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetScanningStatus,
aHCIScanEnable));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetLimitedDiscoverableStatus,
RProperty::EInt,
KLOCAL_SERVICES_AND_NETWORK_CONTROL,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetDeviceClass,
RProperty::EInt,
KLOCAL_SERVICES_AND_NETWORK_CONTROL,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetAFHHostChannelClassification,
RProperty::EByteArray,
KLOCAL_SERVICES_AND_NETWORK_CONTROL,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetAFHChannelAssessmentMode,
RProperty::EInt,
KLOCAL_SERVICES_AND_NETWORK_CONTROL,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetDeviceName,
RProperty::EText,
KLOCAL_SERVICES_AND_NETWORK_CONTROL,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetAcceptPairedOnlyMode,
RProperty::EInt,
KLOCAL_SERVICES_AND_NETWORK_CONTROL,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
iDebugModeDefinitionResult = (iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetSimplePairingDebugMode,
RProperty::EInt,
KLOCAL_SERVICES,
KCOMMDD
));
// Original Get P&S value definitions.
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetLocalDeviceAddress,
RProperty::EByteArray,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetPHYCount,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetConnectingStatus,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetScanningStatus,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetLimitedDiscoverableStatus,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetDeviceClass,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetDeviceName,
RProperty::EText,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetAcceptPairedOnlyMode,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void) (iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothHostResolverActive,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
(void)(iProperty.Define(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetSimplePairingDebugMode,
RProperty::EInt,
KLOCAL_SERVICES,
KLOCAL_SERVICES_AND_NETWORK_CONTROL
));
}
void CLinkMgrProtocol::DeletePublications()
{
LOG_FUNC
//we own them, so they'll get deleted
iProperty.Close();
}
void CLinkMgrProtocol::StartL()
/**
Binding complete.
Startup call from esock. Do nothing
If HCI needs any start-up, do it here.
**/
{
LOG_FUNC
}
// From higher protocol
void CLinkMgrProtocol::BindL(CProtocolBase* protocol, TUint /* id*/)
{
LOG_FUNC
TServerProtocolDesc prtDesc;
protocol->Identify(&prtDesc);
#ifdef TCI
if(prtDesc.iAddrFamily!=KBTAddrFamily || prtDesc.iProtocol!=KTCIL2CAP)
#else
if(prtDesc.iAddrFamily!=KBTAddrFamily || prtDesc.iProtocol!=KL2CAP)
#endif
{
User::Leave(KErrBtEskError);
}
// Store this for error propogation
//
iUpperProtocol = protocol;
}
// Factory functions
CHostResolvProvdBase* CLinkMgrProtocol::NewHostResolverL()
{
LOG_FUNC
return iInquiryMgr->NewHostResolverL();
}
// Query functions
void CLinkMgrProtocol::Identify(TServerProtocolDesc* aDesc) const
//
// Identify request from SOCKET server
//
{
LOG_FUNC
CLinkMgrProtocol::ProtocolIdentity(aDesc);
}
void CLinkMgrProtocol::ProtocolIdentity(TServerProtocolDesc* aDesc)
{
LOG_STATIC_FUNC
_LIT(name,"BTLinkManager");
aDesc->iProtocol=KBTLinkManager;
aDesc->iName=name;
aDesc->iAddrFamily=KBTAddrFamily;
aDesc->iSockType=KUndefinedSockType; // various!
aDesc->iVersion=TVersion(KBTMajor,KBTMinor,KBTBuild);
aDesc->iByteOrder=ELittleEndian;
/*
The following sockets are exposed as RSockets
'Proxy' = a SAP attached to a baseband connection that can influence it
'SCO' = a SAP providing SCO services
Higher protocols can additionally ask for ACL SAPs, but these are not
available as RSockets
This guides the direction of the ServiceInfo below
*/
aDesc->iServiceInfo=KSIDatagram|KSIGracefulClose|KSIBroadcast|KSIQOS|KSICanReconnect|KSIConnectData|KSIDisconnectData; // slightly hijacked connectData
aDesc->iNamingServices=KNSNameResolution;
aDesc->iSecurity=KSocketNoSecurity;
aDesc->iMessageSize=Max(CHctlSynchronousDataFrame::KHCTLMaxSynchronousDataSize, CHctlAclDataFrame::KHCTLMaxACLDataSize);
aDesc->iServiceTypeInfo=ESocketSupport|ECantProcessMBufChains|ENeedMBufs|ETransport
|EPreferDescriptors|EUseCanSend;
aDesc->iNumSockets=100; // one per baseband - including many parked!
}
void CLinkMgrProtocol::Error(TInt aErr, CProtocolBase* /*aProt*/)
{
LOG_FUNC
// A fatal error has occurred (Power off hopefully!). Notify the upper protocol
// (of there is one) and the inquiry manager.
__ASSERT_DEBUG(aErr==KErrHardwareNotAvailable, Panic(EUnknownFatalError));
iInquiryMgr->CompleteCommands(aErr);
iPhysicalLinksMgr->FatalError(aErr);
}
void CLinkMgrProtocol::CloseNow()
/**
Close command from base class.
Called when ref count reaches 0.
We don't actually have to close now, but when we finally
do, we must call CanClose (done within TryToClose). That'll
actually delete us. In the mean time, if a new client tries
to connect to LinkMgr, ESOCK will use this existing one and just
call Open on it.
What we do here, is queue an idle timer entry. It's expiry will
call TryToClose, which'll actually do the close.
**/
{
LOG_FUNC
// synchronously update stack state in Registry
iLocalDevice.Modify(iLocalDeviceSettings); //ignore error
iClosePending = ETrue;
QueIdleTimerEntry();
}
void CLinkMgrProtocol::Open()
/**
Open LinkMgr protocol.
Called everytime a new client (of LinkMgr) wants to use it.
**/
{
LOG_FUNC
LocalOpen();
if(iExternalRef++ == 0)
{
ExternalOpenInit();
}
}
void CLinkMgrProtocol::Close()
{
LOG_FUNC
if(--iExternalRef == 0)
{
ExternalCloseCleanup();
}
LocalClose();
}
void CLinkMgrProtocol::LocalOpen()
{
LOG_FUNC
iClosePending = EFalse;
RemoveIdleTimerEntry();
CProtocolBase::Open();
}
void CLinkMgrProtocol::LocalClose()
{
LOG_FUNC
CProtocolBase::Close();
}
void CLinkMgrProtocol::ExternalOpenInit()
{
LOG_FUNC
TRAP_IGNORE(iLocalNamePublisher = CEirPublisherLocalName::NewL());
TRAP_IGNORE(iTxPowerLevelPublisher = CEirPublisherTxPowerLevel::NewL());
if(iLocalNamePublisher)
{
// Publish the initial name.
iLocalNamePublisher->UpdateName(iLocalDeviceSettings.DeviceName());
}
}
void CLinkMgrProtocol::ExternalCloseCleanup()
{
LOG_FUNC
// Currently just the internal publishers
delete iLocalNamePublisher;
iLocalNamePublisher = NULL;
delete iTxPowerLevelPublisher;
iTxPowerLevelPublisher = NULL;
}
void CLinkMgrProtocol::QueIdleTimerEntry()
/**
Queue idle timer entry.
When this timer expires, it'll call TryToClose, which actually
causes the thing to finally close down.
**/
{
LOG_FUNC
RemoveIdleTimerEntry();
iIdleEntryQueued = ETrue;
BTSocketTimer::Queue(KLinkMgrProtocolIdleTimer, iIdleTimerEntry);
}
void CLinkMgrProtocol::RemoveIdleTimerEntry()
/**
Called whenever we're opened.
Checks there are no idle timer entries queued.
**/
{
LOG_FUNC
if (!iIdleEntryQueued)
return;
BTSocketTimer::Remove(iIdleTimerEntry);
iIdleEntryQueued = EFalse;
}
/*static*/ TInt CLinkMgrProtocol::TryToClose(TAny* aProtocol)
/**
Actually try to close the protocol.
Called after the idle timeout period by the BTSocketTimer. If
we're all set to close down, the thing is closed.
**/
{
LOG_STATIC_FUNC
CLinkMgrProtocol* p=static_cast<CLinkMgrProtocol*>(aProtocol);
p->iIdleEntryQueued = EFalse;
if (p->iClosePending)
{
p->CanClose(); // deletes this
}
return EFalse;
}
CServProviderBase* CLinkMgrProtocol::NewSAPL(TUint aSockType)
/**
Create a new SAP.
The SAP returned is owned by the caller -- this protocol will not clean it up.
esock uses this function to create a new SAP, and esock will delete when it
is finished with it.
**/
{
LOG_FUNC
CServProviderBase* sap = NULL;
switch (aSockType)
{
case KSockBluetoothTypeESCO:
{
sap = CeSCOLink::NewL(*iPhysicalLinksMgr, NULL);
break;
}
case KSockBluetoothTypeSCO:
{
sap = CSCOLink::NewL(*iPhysicalLinksMgr, NULL);
break;
}
case KSockBluetoothTypeACL:
{
// an explicit ACL link has been asked for (by L2CAP)
sap = CACLLink::NewL(*iPhysicalLinksMgr, NULL, *this); // don't know for which PHY at this stage
break;
}
case KSockBluetoothTypeVendorSpecific:
{
if (!iVendorSpecificSAP)
{
sap = CVendorSAP::NewL(*this);
}
else
{
User::Leave(KErrInUse); // only support one :o)
}
break;
}
case KSockBluetoothTypeRawBroadcast:
default:
{
__ASSERT_DEBUG((aSockType > KHCIMinimumHandle && aSockType < KHCIMaximumHandle)||(aSockType==KSockBluetoothTypeRawBroadcast), Panic(EBTProxySAPInvalidCreate));
// if the connection handle has been specified - find the connection: aSockType *is* a ConnectionHandle in this case
CPhysicalLink* phySAP = NULL;
if (aSockType!=KSockBluetoothTypeRawBroadcast)
{
// it's a proxy sap which we should try to bind to the PHY
//
phySAP = iPhysicalLinksMgr->FindPhysicalLink(static_cast<THCIConnHandle>(aSockType));
}
// create Proxy telling it the possible PHY
CBTProxySAP* proxySAP = CBTProxySAP::NewLC(*iPhysicalLinksMgr, phySAP);
CleanupStack::Pop(proxySAP);
sap = proxySAP;
}
}
ASSERT_DEBUG(sap);
return sap;
}
TBTDevHCIVersion CLinkMgrProtocol::GetHWHCIVersion() const
{
LOG_FUNC
return iHWHCIVersion;
}
void CLinkMgrProtocol::SetLocalVersion(THCIErrorCode aErr, TBTDevHCIVersion aHCIVersion, TBTDevLMPVersion aLMPVersion)
{
LOG_FUNC
// we store this for possibly useful later use :-)
if (aErr == EOK)
{
iHWHCIVersion = aHCIVersion; // not especially useful for us: but maybe to exploit >BT1.1
iHWLMPVersion = aLMPVersion; // the LM in the HC ;-)
}
}
void CLinkMgrProtocol::SetOverrideLPMTimeout(TUint aOverrideLPMTimeout)
{
LOG_FUNC
iOverrideLPMTimeout =aOverrideLPMTimeout;
}
TInt CLinkMgrProtocol::StartProtocolListening()
{
LOG_FUNC
return KickDiscoverabilitySubscriber();
}
// oh Dear! void again, how to report failure...
void CLinkMgrProtocol::StopProtocolListening()
{
LOG_FUNC
// NB. If 'KickDiscoverabilitySubscriber' returns an error, then
// we've tried to get the value for ScanStatus, but we've failed.
// Not a lot we can do about it. This means that we may be
// leaving inquiry and page scan enabled with no listeners.
(void)KickDiscoverabilitySubscriber();
}
TInt CLinkMgrProtocol::KickDiscoverabilitySubscriber()
{
/*
Reset P&S with its current value. This will kick
CDiscoverabilitySubscriber's RunL which calls
SetInquiryAndPageScanningL to check for the current
user wishes AND the existance of listeners before
sending the appropriate WriteScanEnable command to
the controller.
*/
LOG_FUNC
TInt scanVal;
TInt err = iProperty.Get(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetScanningStatus, scanVal);
if (err != KErrNone)
{
return err;
}
THCIScanEnable scan = static_cast<THCIScanEnable>(scanVal);
// force CDiscoverabilitySubscriber to try to enable Page and Inquiry scan to HW, when set
(void)(iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetScanningStatus,
scan));
return err;
}
void CLinkMgrProtocol::LocalSupportedFeaturesAvailable()
{
// Set options based on the features
iInquiryMgr->SetInquiryMode();
iEirManServer->NotifyFeaturesReady();
}
void CLinkMgrProtocol::SetLocalFeatures(THCIErrorCode aErr, const TBTFeatures& aMask)
{
LOG_FUNC
if (aErr == EOK)
{
// we store this for possibly useful later use :-)
iHWFeatures = aMask;
}
// else ignore for now...
iEirManServer->NotifyFeaturesReady();
}
void CLinkMgrProtocol::SetLocalCommands(THCIErrorCode aErr, const TBluetoothHciCommands& aMask)
{
LOG_FUNC
if (aErr == EOK)
{
// we store this for possibly useful later use :-)
iHWCommands = aMask;
}
// else ignore for now...
}
void CLinkMgrProtocol::SetInquiryAndPageScanningL()
{
LOG_FUNC
TInt requestedScanVal = 0; // no Inquiry or Page Scanning as default
TInt err = iProperty.Get(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothSetScanningStatus,
requestedScanVal
);
THCIScanEnable requestedScanSetting;
if (!err)
{
requestedScanSetting = static_cast<THCIScanEnable>(requestedScanVal);
}
else
{
// If err == KErrNotFound, we have not published this property yet, but in all error cases
// we will use the current device setting to define the scanning requirements instead.
requestedScanSetting = iLocalDeviceSettings.ScanEnable();
}
// we need to check to see if we have any listeners before we can enable page & inquiry scan
THCIScanEnable validScanSetting;
if(!IsListening() || (requestedScanSetting == EInquiryScanOnly))
{
validScanSetting = ENoScansEnabled;
}
else
{
validScanSetting = requestedScanSetting;
}
iPendingLocalDeviceSettings.SetScanEnable(validScanSetting);
iHCIFacade->WriteScanEnableL(iPendingLocalDeviceSettings.ScanEnable());
if (!err)
{
// Update registry with the requested settings from the _set_ key
iLocalDeviceSettings.SetScanEnable(static_cast<THCIScanEnable>(requestedScanVal));
UpdateSettings();
}
}
void CLinkMgrProtocol::SetAcceptPairedOnlyMode(TBool aOn)
/*
THIS WORKS DIFFERENTLY: It does not involve the controller - it is
purely a stack setting. It is called directly when the user requests
the stack value to be reset.
*/
{
LOG_FUNC
iLocalDeviceSettings.SetAcceptPairedOnlyMode(aOn);
//update UI
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetAcceptPairedOnlyMode,
iLocalDeviceSettings.AcceptPairedOnlyMode()
);
UpdateSettings();
}
void CLinkMgrProtocol::SetSimplePairingDebugMode(TBool aOn)
/*
THIS WORKS DIFFERENTLY: It does not involve the controller - it is
purely a stack setting.
*/
{
LOG_FUNC
//update UI
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetSimplePairingDebugMode,
aOn
);
}
void CLinkMgrProtocol::SetDeviceClassL(TUint32 aCoD)
{
LOG_FUNC
// This method is called from Subscribers when the P&S is used to write a new CoD
TInt err = KErrNone;
err = CodMan().PandSCodHandler(aCoD); // Cod Service Manager will decide what gets written
User::LeaveIfError(err); // P&S CoD failed to write, but at least Codman has a record of it
}
void CLinkMgrProtocol::WriteClassOfDeviceL(TUint32 aCoD)
{
LOG_FUNC
// Only write the CoD bits if they have changed from the existing setting
if (iPendingLocalDeviceSettings.DeviceClass() != aCoD)
{
iPendingLocalDeviceSettings.SetDeviceClass(aCoD);
iHCIFacade->WriteDeviceClassL(aCoD);
}
}
TInt CLinkMgrProtocol::SetLocalDeviceName(const TDesC8& aName)
{
LOG_FUNC
// We trap this HCI command and not the others in Set... to keep the
// error path up to CBTHostResolver::SetHostName
TRAPD(err, iHCIFacade->WriteLocalNameL(aName));
if (err == KErrNone)
{
iPendingLocalDeviceSettings.SetDeviceName(aName);
}
return err;
}
void CLinkMgrProtocol::SetAFHHostChannelClassificationL(const TBTAFHHostChannelClassification& aChannelClassification)
{
LOG_FUNC
iHCIFacade->SetAFHHostChannelClassificationL(aChannelClassification);
}
void CLinkMgrProtocol::SetAFHChannelAssessmentModeL(TBool aMode)
{
LOG_FUNC
iPendingLocalDeviceSettings.SetAFHChannelAssessmentMode(aMode);
iHCIFacade->WriteAFHChannelAssessmentModeL(aMode);
}
void CLinkMgrProtocol::SetLimitedDiscoverableIfChangedL(TBool aOn)
{
LOG_FUNC
// Set limited discoverable if value differs from cached (= registry) value
// and previous change going the opposite way is not pending completion
// See also DoSetLimitedDiscoverableL
if ((aOn == iLocalDeviceSettings.LimitedDiscoverable()) &&
(iPendingLocalDeviceSettings.LimitedDiscoverable() == iLocalDeviceSettings.LimitedDiscoverable()))
return;
DoSetLimitedDiscoverableL(aOn);
}
void CLinkMgrProtocol::DoSetLimitedDiscoverableL(TBool aOn)
{
LOG_FUNC
// HCI spec says we can always send >1 IAC! Controllers will take first
// so we can do what GAP says easily
TUint8 numIACs =0;
TUint iacs[2];
if (aOn)
{
// turn on LIAC
iPendingLocalDeviceSettings.SetLimitedDiscoverable(ETrue);
WriteClassOfDeviceL(iPendingLocalDeviceSettings.DeviceClass() | (EMajorServiceLimitedDiscoverableMode <<
(KLengthOfDeviceClass+KStartingOffsetOfDeviceClass)));
numIACs = 2;
iacs[0] = KLIAC;
iacs[1] = KGIAC;
}
else
{
// turn off LIAC - could do the 1 minute GAP timer?
iPendingLocalDeviceSettings.SetLimitedDiscoverable(EFalse);
WriteClassOfDeviceL(iPendingLocalDeviceSettings.DeviceClass() & ~(EMajorServiceLimitedDiscoverableMode <<
(KLengthOfDeviceClass+KStartingOffsetOfDeviceClass)));
numIACs = 1;
iacs[0] = KGIAC;
}
iHCIFacade->WriteIACLAPL(numIACs, iacs);
}
void CLinkMgrProtocol::UpdateLocalDevicePower(TBTPowerState aState)
{
LOG_FUNC
iLocalDeviceSettings.SetPowerSetting(static_cast<TUint8>(aState));
UpdateSettings();
}
// This is an update method for dealing with the result of asking what the device
// name is. It is used to keep iLocalDeviceSettings.DeviceName(), the P&S device
// name value and the h/w value in sync
void CLinkMgrProtocol::UpdateLocalDeviceName(const TDesC8& aName)
{
LOG_FUNC
iLocalDeviceSettings.SetDeviceName(aName);
// Update the UI with the unicode DeviceName
TBuf16<KHCILocalDeviceNameMaxLength> unicodeName;
(void) CnvUtfConverter::ConvertToUnicodeFromUtf8(unicodeName, iLocalDeviceSettings.DeviceName());
// The return from the above should never be > 0 since aName should have a length <= KHCILocalDeviceNameMaxLength
// hence we shouldn't have any unconverted chars left over. If we get another error then we just have to publish
// the resulting unicode name anyway.
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetDeviceName,
unicodeName
);
UpdateSettings();
}
// This is an update method for dealing with the result of telling the h/w what the device
// name should be. It is used to keep iLocalDeviceSettings.DeviceName(), the P&S device
// name value and the h/w value in sync
void CLinkMgrProtocol::UpdateLocalDeviceName(TBool aSucceeded)
{
LOG_FUNC
if (aSucceeded)
{
TBool isDifferentName =
(iLocalDeviceSettings.DeviceName() != iPendingLocalDeviceSettings.DeviceName());
iLocalDeviceSettings.SetDeviceName(iPendingLocalDeviceSettings.DeviceName());
if(iLocalNamePublisher && isDifferentName)
{
iLocalNamePublisher->UpdateName(iLocalDeviceSettings.DeviceName());
}
}
// Update the UI with the unicode DeviceName
TBuf16<KHCILocalDeviceNameMaxLength> unicodeName;
(void) CnvUtfConverter::ConvertToUnicodeFromUtf8(unicodeName, iLocalDeviceSettings.DeviceName());
// The return from the above should never be > 0 since unicodeName is the same size as utf8Name
// hence we shouldn't have any unconverted chars left over. Similarly ret should not be < 0
// because when we received DeviceName in Unicode we where able to convert it to UTF-8
// without a problem so reversing the conversion should be okay.
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetDeviceName,
unicodeName
);
UpdateSettings();
}
void CLinkMgrProtocol::UpdateLocalDeviceScanEnable(TBool aSucceeded)
{
LOG_FUNC
TInt scan;
TInt err = KErrNone;
// Set scan to be the actual scan enable state of the hardware
if(aSucceeded)
{
// We've set it to the value in iLocalDeviceSettings
scan = iPendingLocalDeviceSettings.ScanEnable();
}
else
{
// We haven't changed it, current value is in the _get_ key
err = iProperty.Get(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetScanningStatus,
scan);
}
if(!err)
{
//update UI with the hardware's settings using the _get_ key
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetScanningStatus,
scan
);
}
}
void CLinkMgrProtocol::UpdateLimitedDiscoverable(TBool aSucceeded)
{
LOG_FUNC
if (aSucceeded)
{
iLocalDeviceSettings.SetLimitedDiscoverable(
iPendingLocalDeviceSettings.LimitedDiscoverable());
}
//update UI
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetLimitedDiscoverableStatus,
iLocalDeviceSettings.LimitedDiscoverable()
);
UpdateSettings();
}
void CLinkMgrProtocol::UpdateDeviceClass(TBool aSucceeded)
{
LOG_FUNC
if (aSucceeded)
{
iLocalDeviceSettings.SetDeviceClass(
iPendingLocalDeviceSettings.DeviceClass());
}
//update UI
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetDeviceClass,
iLocalDeviceSettings.DeviceClass()
);
UpdateSettings();
}
void CLinkMgrProtocol::UpdateDeviceClass(TBool aSucceeded, TUint aCoD)
{
LOG_FUNC
if (aSucceeded)
{
iLocalDeviceSettings.SetDeviceClass(aCoD);
//update UI
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetDeviceClass,
aCoD
);
UpdateSettings();
}
}
void CLinkMgrProtocol::UpdateAFHChannelAssessmentMode(TBool aSucceeded)
{
LOG_FUNC
if (aSucceeded)
{
iLocalDeviceSettings.SetAFHChannelAssessmentMode(
iPendingLocalDeviceSettings.AFHChannelAssessmentMode());
}
UpdateSettings();
}
void CLinkMgrProtocol::UpdateSettings()
{
LOG_FUNC
//Careful! - we new'd it without ELeave
if (iRegistryUpdater)
{
iRegistryUpdater->Update();
}
}
void CLinkMgrProtocol::UpdateInquiryResponseTxPowerLevel(TInt8 aTxPowerLevel)
{
LOG_FUNC
if(iTxPowerLevelPublisher)
{
iTxPowerLevelPublisher->UpdateTxPowerLevel(aTxPowerLevel);
}
}
void CLinkMgrProtocol::SetUIConnecting(TBool aConnecting)
{
LOG_FUNC
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetConnectingStatus,
aConnecting);
}
void CLinkMgrProtocol::SetUINumPhysicalLinks(TUint aNum)
{
LOG_FUNC
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetPHYCount,
aNum);
}
void CLinkMgrProtocol::SetLocalBTAddress(const TBTDevAddr& aAddr)
{
LOG_FUNC
iLocalDeviceAddress = aAddr;
// publish this number - might be useful
const TDesC8& des = aAddr.Des();
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothGetLocalDeviceAddress,
des);
}
void CLinkMgrProtocol::SetUIDiscovering(TInt aDiscoveringState)
{
LOG_FUNC
(void)iProperty.Set(KPropertyUidBluetoothCategory,
KPropertyKeyBluetoothHostResolverActive,
aDiscoveringState);
}
TInt CLinkMgrProtocol::ACLPacketMTU() const
{
LOG_FUNC
return iLinkMuxer->ACLPacketMTU();
}
TInt CLinkMgrProtocol::ControlPlaneMessage(TBTControlPlaneMessage aMessage, TAny* aParam)
{
LOG_FUNC
TInt rerr = KErrNotFound;
CPhysicalLink* con = NULL;
if ((aMessage == ESubscribePhysicalLink) || (aMessage == EUnsubscribePhysicalLink))
{
TPhysicalLinkSubscriptionInfo& subscriptionInfo = *reinterpret_cast<TPhysicalLinkSubscriptionInfo*>(aParam);
con = iPhysicalLinksMgr->FindPhysicalLink(subscriptionInfo.iAddr);
}
else if ((aMessage == ETryToAndThenPreventHostEncryptionKeyRefresh))
{
// For EPreventAutoEncryptionKeyRefresh we pass the address as a TBTDevAddr**
const TBTDevAddr& addr = **reinterpret_cast<const TBTDevAddr**>(aParam);
con = iPhysicalLinksMgr->FindPhysicalLink(addr);
}
else
{
const TBTDevAddr& addr = *reinterpret_cast<const TBTDevAddr*>(aParam);
con = iPhysicalLinksMgr->FindPhysicalLink(addr);
}
if (con)
{
switch (aMessage)
{
case EOverridePark:
rerr = con->OverridePark();
break;
case EUndoOverridePark:
rerr = con->UndoOverridePark();
break;
case EOverrideLPMWithTimeout:
rerr = con->OverrideLPMWithTimeout(iOverrideLPMTimeout);
break;
case EOverrideLPM:
rerr = con->OverrideLPM();
break;
case EUndoOverrideLPM:
rerr = con->UndoOverrideLPM();
break;
case ESubscribePhysicalLink:
{
const TPhysicalLinkSubscriptionInfo& subscriptionInfo = *reinterpret_cast<TPhysicalLinkSubscriptionInfo*>(aParam);
con->SubscribeLinkObserver(subscriptionInfo.iMPhysicalLinkObserver);
break;
}
case EUnsubscribePhysicalLink:
{
const TPhysicalLinkSubscriptionInfo& subscriptionInfo = *reinterpret_cast<TPhysicalLinkSubscriptionInfo*>(aParam);
con->UnsubscribeLinkObserver(subscriptionInfo.iMPhysicalLinkObserver);
break;
}
case ETryToAndThenPreventHostEncryptionKeyRefresh:
{
rerr = con->TryToAndThenPreventHostEncryptionKeyRefresh(aParam);
break;
}
default:
rerr = KErrNotSupported;
break;
};
}
return rerr;
}
void CLinkMgrProtocol::ClearPendingLocalDeviceSettingsCod()
{
LOG_FUNC
// If we know that the h/w has been reset, then we need to ensure that our persistent
// value reflects this. That way we will force the CoD re-write to the hardware.
iPendingLocalDeviceSettings.SetDeviceClass(KDeviceClassReset);
}
//
// CRegistrySession
//
CRegistrySession* CRegistrySession::NewL(CLinkMgrProtocol& aLinkMgrProtocol)
{
LOG_STATIC_FUNC
CRegistrySession* self = new(ELeave) CRegistrySession(aLinkMgrProtocol);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void CRegistrySession::Open()
{
LOG_FUNC
if(iAccessCount++ == 0)
{
iLinkMgrProtocol.LocalOpen();
}
}
void CRegistrySession::Close()
{
LOG_FUNC
__ASSERT_DEBUG(iAccessCount > 0, Panic(ERegistrySessionClosedTooManyTimes));
if(--iAccessCount == 0)
{
iLinkMgrProtocol.LocalClose();
}
}
CRegistrySession::CRegistrySession(CLinkMgrProtocol& aLinkMgrProtocol)
: CBase()
, iAccessCount(0)
, iLinkMgrProtocol(aLinkMgrProtocol)
{
LOG_FUNC
}
void CRegistrySession::ConstructL()
{
LOG_FUNC
User::LeaveIfError(iRegServ.Connect());
}
CRegistrySession::~CRegistrySession()
{
LOG_FUNC
__ASSERT_DEBUG(iAccessCount == 0, Panic(ERegistrySessionDeletedWhenOpen));
iRegServ.Close();
}
RBTRegServ& CRegistrySession::RegServ()
{
LOG_FUNC
return iRegServ;
}
//class CRegistryUpdater
CRegistryUpdater::~CRegistryUpdater()
{
LOG_FUNC
Cancel();
}
CRegistryUpdater::CRegistryUpdater(RBTLocalDevice& aLocalDevice,TBTTrackedLocalDevice& aSettings) :
CActive(CActive::EPriorityStandard),iLocalDevice(aLocalDevice),iStackSettings(aSettings),iRepeatUpdate(EFalse)
{
LOG_FUNC
CActiveScheduler::Add(this);
}
void CRegistryUpdater::Update()
{
LOG_FUNC
__ASSERT_DEBUG(iLocalDevice.SubSessionHandle(), Panic(ELocalDeviceBadHandle));
if (!IsActive())
{
TInt err;
err = iLocalDevice.Get(iRegistrySettings);
// if we can't get settings from registry, we won't be able to update them
if ( err == KErrNone )
{
iStackSettings.Modify(iRegistrySettings);
iStackSettings.ResetChangesMask();
iLocalDevice.Modify(iRegistrySettings,iStatus);
SetActive();
iRepeatUpdate = EFalse;
}
}
else
{
// Even if multiple requests come in while this object is active we only need to
// perform one update since iLocalDevice will accumulated required new settings.
LOG(_L(" -- CRegistryUpdaterAO already active so will repeat the update later."));
iRepeatUpdate = ETrue;
}
}
void CRegistryUpdater::RunL()
{
LOG_FUNC
if (iRepeatUpdate)
{
Update();
}
}
void CRegistryUpdater::DoCancel()
{
LOG_FUNC
iLocalDevice.CancelRequest(iStatus);
iRepeatUpdate = EFalse;
}
//class TBTTrackedLocalDevice
void TBTTrackedLocalDevice::SetAddress(const TBTDevAddr& aAddr)
{
LOG_FUNC
TBTLocalDevice::SetAddress(aAddr);
StoreChange(EAddress);
}
void TBTTrackedLocalDevice::SetDeviceClass(TUint32 aCod)
{
LOG_FUNC
TBTLocalDevice::SetDeviceClass(aCod);
StoreChange(ECoD);
}
void TBTTrackedLocalDevice::SetDeviceName(const TDesC8& aName)
{
LOG_FUNC
TBTLocalDevice::SetDeviceName(aName);
StoreChange(EDeviceName);
}
void TBTTrackedLocalDevice::SetScanEnable(THCIScanEnable aEnable)
{
LOG_FUNC
TBTLocalDevice::SetScanEnable(aEnable);
StoreChange(EScanEnable);
}
void TBTTrackedLocalDevice::SetLimitedDiscoverable(TBool aOn)
{
LOG_FUNC
TBTLocalDevice::SetLimitedDiscoverable(aOn);
StoreChange(ELimitedDiscoverable);
}
void TBTTrackedLocalDevice::SetPowerSetting(TUint8 aPowerSetting)
{
LOG_FUNC
TBTLocalDevice::SetPowerSetting(aPowerSetting);
StoreChange(EPowerSetting);
}
void TBTTrackedLocalDevice::SetAFHChannelAssessmentMode(TBool aOn)
{
LOG_FUNC
TBTLocalDevice::SetAFHChannelAssessmentMode(aOn);
StoreChange(EAFHChannelAssessmentMode);
}
void TBTTrackedLocalDevice::SetAcceptPairedOnlyMode(TBool aOn)
{
LOG_FUNC
TBTLocalDevice::SetAcceptPairedOnlyMode(aOn);
StoreChange(EAcceptPairedOnlyMode);
}
void TBTTrackedLocalDevice::StoreChange(TUint8 aChange)
{
LOG_FUNC
iChangedSettings |= aChange;
}
void TBTTrackedLocalDevice::ResetChangesMask()
{
LOG_FUNC
iChangedSettings = 0;
}
void TBTTrackedLocalDevice::Modify(TBTLocalDevice& aLocalDeviceSettings)
{
LOG_FUNC
if ( iChangedSettings & EAddress )
{
aLocalDeviceSettings.SetAddress(Address());
}
if ( iChangedSettings & ECoD )
{
aLocalDeviceSettings.SetDeviceClass(DeviceClass());
}
if ( iChangedSettings & EDeviceName )
{
aLocalDeviceSettings.SetDeviceName(DeviceName());
}
if ( iChangedSettings & EPowerSetting )
{
aLocalDeviceSettings.SetPowerSetting(PowerSetting());
}
if ( iChangedSettings & EScanEnable )
{
aLocalDeviceSettings.SetScanEnable(ScanEnable());
}
if ( iChangedSettings & ELimitedDiscoverable )
{
aLocalDeviceSettings.SetLimitedDiscoverable(LimitedDiscoverable());
}
if ( iChangedSettings & EAFHChannelAssessmentMode )
{
aLocalDeviceSettings.SetAFHChannelAssessmentMode(AFHChannelAssessmentMode());
}
if ( iChangedSettings & EAcceptPairedOnlyMode )
{
aLocalDeviceSettings.SetAcceptPairedOnlyMode(AcceptPairedOnlyMode());
}
}