bluetooth/btstack/linkmgr/BasebandModel.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2003-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 // Captures the current slot commitments of our device
       
    15 // so this can be viewed of as representing (partially) the
       
    16 // Basic Piconet Physical *Channel*
       
    17 // 
       
    18 //
       
    19 
       
    20 #include <bt_sock.h>
       
    21 #include <bluetooth/logger.h>
       
    22 #include "linkconsts.h"
       
    23 #include "linkutil.h"
       
    24 #include "basebandsap.h"
       
    25 #include "Basebandmodel.h"
       
    26 #include "hcifacade.h"
       
    27 
       
    28 #ifdef __FLOG_ACTIVE
       
    29 _LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
       
    30 #endif
       
    31 
       
    32 #ifdef _DEBUG
       
    33 PANICCATEGORY("basebndm");
       
    34 #endif
       
    35 
       
    36 TACLLinkType TPhysicalLinkData::ACLActualMinSlots() const
       
    37 	{
       
    38 	LOG_FUNC
       
    39 	return (iACLMaxSlotsAllowed < iACLMinSlotsAllowed) ? ENoACLLink : iACLMinSlotsAllowed;
       
    40 	}
       
    41 
       
    42 TPhysicalLinkData::TPhysicalLinkData()
       
    43 : iBdaddr(0), iConnH(0), iSCOConnH(0), ieSCOConnH(0), iACLMinSlotsAllowed(ENoACLLink), iACLMaxSlotsAllowed(EOneSlotPackets), iSCOMinRequirement(ENoSCOLink), iParked(EFalse)
       
    44 	{
       
    45 	LOG_FUNC
       
    46 	}
       
    47 
       
    48 void TPhysicalLinkData::Park()
       
    49 	{
       
    50 	LOG_FUNC
       
    51 	iParked = ETrue;
       
    52 	}
       
    53 
       
    54 void TPhysicalLinkData::UnPark()
       
    55 	{
       
    56 	LOG_FUNC
       
    57 	iParked = EFalse;
       
    58 	}
       
    59 
       
    60 TBool TPhysicalLinkData::IsParked() const
       
    61 	{
       
    62 	LOG_FUNC
       
    63 	return iParked;
       
    64 	}
       
    65 
       
    66 
       
    67 //PUBLIC FUNCTIONS
       
    68 CBTBasebandModel* CBTBasebandModel::NewL(CLinkMgrProtocol& aLMProt)
       
    69 	{
       
    70 	LOG_STATIC_FUNC
       
    71 	CBTBasebandModel* self = new(ELeave) CBTBasebandModel(aLMProt);
       
    72 	CleanupStack::PushL(self);
       
    73 	self->ConstructL();
       
    74 	CleanupStack::Pop();
       
    75 	return self;
       
    76 	}
       
    77 
       
    78 CBTBasebandModel::~CBTBasebandModel()
       
    79 	{
       
    80 	LOG_FUNC
       
    81 	iLinkData.Reset();
       
    82 	iLinkData.Close();
       
    83 	}
       
    84 
       
    85 TInt CBTBasebandModel::UpdateModel(const TBTDevAddr& aAddr, TUint16 aPacketMask, TLinkType aLinkTypeForPacketMask)
       
    86 	{
       
    87 	LOG_FUNC
       
    88 	TBTConnect conn;
       
    89 	SetupConnectRecord(conn, 0, aAddr, 0, aLinkTypeForPacketMask, EDisabled);
       
    90 	return UpdateModel(conn, aPacketMask);
       
    91 	}
       
    92 
       
    93 TInt CBTBasebandModel::UpdateModel(THCIConnHandle aConnH, TLinkType aLinkTypeForHandle, TUint16 aPacketMask, TLinkType aLinkTypeForPacketMask)
       
    94 	{
       
    95 	LOG_FUNC
       
    96 	//See if link record already exists
       
    97 	TInt found = FindByHandle(aConnH);
       
    98 	//If so, update
       
    99 	if(found != KErrNotFound)
       
   100 		{
       
   101 		if (!iLinkData[found].IsParked())
       
   102 			{
       
   103 			UpdateLink(iLinkData[found], aLinkTypeForPacketMask, aPacketMask);
       
   104 			}
       
   105 		return KErrNone;
       
   106 		}
       
   107 
       
   108 	TPhysicalLinkData ld;
       
   109 	TBTConnect conn;
       
   110 	SetupConnectRecord(conn, aConnH, TBTDevAddr(0), 0, aLinkTypeForHandle, EDisabled);
       
   111 	UpdateLink(ld, conn);
       
   112 	UpdateLink(ld, aLinkTypeForPacketMask, aPacketMask);
       
   113 	iLinkData.Append(ld); //NB failure => we become too tolerant => unnecessary HCI traffic
       
   114 	return KErrNone;
       
   115 	}
       
   116 
       
   117 TInt CBTBasebandModel::UpdateModel(const TBTConnect& aConn)
       
   118 /**
       
   119 	Tries to find the record containing either the BD address, or, if not, the handle
       
   120 	supplied in 'aConn'. 
       
   121 	If successful, updates record with those values in 'aConn' that are not already 
       
   122 	in the record, and a value deduced 'aPacketMask'.
       
   123 	Whether all these values are used for ACL or SCO is decided by 'aConn.iLinkType'.
       
   124 	If unsuccessful, creates a new record with 'aConn', and 'aPacketMask'.
       
   125 */
       
   126 	{
       
   127 	LOG_FUNC
       
   128 	return DoUpdateModel(aConn, 0, ETrue);
       
   129 	}
       
   130 
       
   131 TInt CBTBasebandModel::UpdateModel(const TBTConnect& aConn, TUint16 aPacketMask)
       
   132 /**
       
   133 	Tries to find the record containing either the BD address, or, if not, the handle
       
   134 	supplied in 'aConn'. 
       
   135 	If successful, updates record with those values in 'aConn' that are not already 
       
   136 	in the record, and a value deduced 'aPacketMask'.
       
   137 	Whether all these values are used for ACL or SCO is decided by 'aConn.iLinkType'.
       
   138 	If unsuccessful, creates a new record with 'aConn', and 'aPacketMask'.
       
   139 */
       
   140 	{
       
   141 	LOG_FUNC
       
   142 	return DoUpdateModel(aConn, aPacketMask, EFalse);
       
   143 	}
       
   144 
       
   145 TInt CBTBasebandModel::UpdateModel(THCIConnHandle aConnH, TUint8 aMaxSlots)
       
   146 	{
       
   147 	LOG_FUNC
       
   148 	TInt found = FindByACLHandle(aConnH);
       
   149 	if(found==KErrNotFound)
       
   150 		{
       
   151 		return KErrArgument;
       
   152 		}
       
   153 	//convert param 2 to contraints of CBTBasebandModel
       
   154 	TACLLinkType maxSlots;
       
   155 	switch(aMaxSlots)
       
   156 		{
       
   157 		case 1:
       
   158 			maxSlots = EOneSlotPackets;
       
   159 			break;
       
   160 		case 3:
       
   161 			maxSlots = EThreeSlotPackets;
       
   162 			break;
       
   163 		case 5:
       
   164 			maxSlots = EFiveSlotPackets;
       
   165 			break;
       
   166 		default:
       
   167 			maxSlots = ENoACLLink; //not sure - make most likely to pass
       
   168 			break;
       
   169 		}
       
   170 
       
   171 	iLinkData[found].iACLMaxSlotsAllowed = maxSlots;
       
   172 	return KErrNone;
       
   173 	}
       
   174 
       
   175 void CBTBasebandModel::UpdateModelIfRecordExists(THCIConnHandle aConnH, TUint16 aPacketMask)
       
   176    	{
       
   177 	LOG_FUNC
       
   178    	#pragma message("eSCO ignored in baseband model")
       
   179    	// Updates link bandwidth consumption statistics
       
   180    	
       
   181    	TInt found = FindByACLHandle(aConnH);
       
   182   	if(found != KErrNotFound)
       
   183   		{
       
   184   		UpdateLink(iLinkData[found], EACLLink, aPacketMask);
       
   185   		return;
       
   186    		}
       
   187    		
       
   188 	found = FindBySCOHandle(aConnH);
       
   189 	if(found != KErrNotFound)
       
   190 		{
       
   191 		UpdateLink(iLinkData[found], ESCOLink, aPacketMask);
       
   192 		return;
       
   193 		}
       
   194    	}
       
   195    
       
   196 void CBTBasebandModel::UpdateModelIfNoRecord(THCIConnHandle aConnH, TUint16 aPacketMask, TLinkType aLinkType)
       
   197 	{
       
   198 	LOG_FUNC
       
   199 	if(FindByHandle(aConnH) == KErrNotFound)
       
   200 		{
       
   201 		TBTConnect conn;
       
   202 		SetupConnectRecord(conn, aConnH, TBTDevAddr(0), 0, aLinkType, EDisabled);
       
   203 		TPhysicalLinkData ld;
       
   204 		UpdateLink(ld, conn);
       
   205 		UpdateLink(ld, aLinkType, aPacketMask);
       
   206 		iLinkData.Append(ld); //NB failure => we become too tolerant => unnecessary HCI traffic
       
   207 		}
       
   208 	}
       
   209 
       
   210 void CBTBasebandModel::UpdateModelForDisconnection(THCIConnHandle aConnH, TLinkType aLinkType)
       
   211 	{
       
   212 	LOG_FUNC
       
   213 	TInt found = KErrNotFound;
       
   214 	
       
   215 	LOG2(_L("Baseband model: updating for disconnect. Handle %d, link type %d"), aConnH, aLinkType);
       
   216 	
       
   217 	switch (aLinkType)
       
   218 		{
       
   219 		case EACLLink:
       
   220 			found = FindByACLHandle(aConnH);
       
   221 			if (found != KErrNotFound)
       
   222 				{
       
   223 				iLinkData.Remove(found); //remove record if ACL
       
   224 				}
       
   225 			break;
       
   226 		
       
   227 		case ESCOLink:
       
   228 			found = FindBySCOHandle(aConnH);
       
   229 			if(found != KErrNotFound)
       
   230 				{
       
   231 				iLinkData[found].iSCOConnH = 0; //zero SCO handle if SCO 
       
   232 				iLinkData[found].iSCOMinRequirement = ENoSCOLink;//set SCO requirements to 0
       
   233 				}
       
   234 				
       
   235 		#ifdef _DEBUG
       
   236 			found = FindBySCOHandle(aConnH);
       
   237 			ASSERT_DEBUG(found == KErrNotFound);
       
   238 		#endif
       
   239 			
       
   240 			break;
       
   241 		
       
   242 		case EeSCOLink:
       
   243 			found = FindByeSCOHandle(aConnH);
       
   244 			if (found != KErrNotFound)
       
   245 				{
       
   246 				LOG1(_L("Baseband model: Found eSCO link at index %d"), found);
       
   247 				iLinkData[found].ieSCOConnH = 0; // zero eSCO handle
       
   248 				}
       
   249 				
       
   250 		#ifdef _DEBUG
       
   251 			found = FindByeSCOHandle(aConnH);
       
   252 			ASSERT_DEBUG(found == KErrNotFound);
       
   253 		#endif
       
   254 			
       
   255 			break;
       
   256 		
       
   257 		// Explicitly ignore 'default' in the hope of compiler warnings if link types
       
   258 		// grow again.
       
   259 		}
       
   260 	}
       
   261 
       
   262 void CBTBasebandModel::UpdateModelForConnectionError(TBTDevAddr aAddr, TLinkType aLinkType)
       
   263 	{
       
   264 	LOG_FUNC
       
   265 	TInt found = KErrNotFound;
       
   266 	
       
   267 	LOG1(_L("Baseband model: updating for connection error. link type %d"), aLinkType);
       
   268 	LOG(_L("  BDADDR: "));
       
   269 	LOGBTDEVADDR(aAddr);
       
   270 	
       
   271 	found = FindByAddress(aAddr);
       
   272 
       
   273 	if (found != KErrNotFound)
       
   274 		{
       
   275 		switch(aLinkType)
       
   276 			{
       
   277 			case (EACLLink):
       
   278 				iLinkData.Remove(found); //remove record if ACL
       
   279 				break;
       
   280 				
       
   281 			case (ESCOLink):
       
   282 				iLinkData[found].iSCOConnH = 0; //zero SCO handle 
       
   283 				iLinkData[found].iSCOMinRequirement = ENoSCOLink;//set SCO requirements to 0
       
   284 				break;
       
   285 				
       
   286 			case (EeSCOLink):
       
   287 				LOG1(_L("Baseband model: Found eSCO link at index %d"), found);
       
   288 				iLinkData[found].ieSCOConnH = 0; // zero eSCO handle
       
   289 				break;
       
   290 			}
       
   291 		}
       
   292 	}
       
   293 	
       
   294 void CBTBasebandModel::ParkLink(THCIConnHandle aConnH)
       
   295 	{
       
   296 	LOG_FUNC
       
   297 	TInt found = FindByACLHandle(aConnH);
       
   298 	if (found != KErrNotFound)
       
   299 		{
       
   300 		iLinkData[found].Park();
       
   301 		}
       
   302 	}
       
   303 
       
   304 
       
   305 void CBTBasebandModel::UnParkLink(THCIConnHandle aConnH)
       
   306 	{
       
   307 	LOG_FUNC
       
   308 	TInt found = FindByACLHandle(aConnH);
       
   309 	if (found != KErrNotFound)
       
   310 		{
       
   311 		iLinkData[found].UnPark();
       
   312 		}
       
   313 	}
       
   314 
       
   315 
       
   316 TBool CBTBasebandModel::IsACLPossible() const
       
   317 /**
       
   318 	Decide if ACL link with default packet type is possible
       
   319 	If error, or not sure, return ETrue and let hardware sort it out.
       
   320 */
       
   321 	{
       
   322 	LOG_FUNC
       
   323 	return IsACLPossible(ACLRequirement(KHCIDefaultPacketType));
       
   324 	}
       
   325 
       
   326 
       
   327 TBool CBTBasebandModel::IsSCOPossible() const
       
   328 /**
       
   329 	Decide if SCO link with default packet type is possible
       
   330 	If error, or not sure, return ETrue and let hardware sort it out.
       
   331 */
       
   332 	{
       
   333 	LOG_FUNC
       
   334 	return IsSCOPossible(SCORequirement(KHCIDefaultSCOPacketType));
       
   335 	}
       
   336 
       
   337 
       
   338 
       
   339 //PRIVATE FUNCTIONS
       
   340 CBTBasebandModel::CBTBasebandModel(CLinkMgrProtocol& aLMProt) 
       
   341 : iLinkData(KBTBasebandModelLinkArrayGranularity),
       
   342 iLMProt(aLMProt)
       
   343 	{
       
   344 	LOG_FUNC
       
   345 	}
       
   346 
       
   347 void CBTBasebandModel::ConstructL()
       
   348 	{
       
   349 	LOG_FUNC
       
   350 	}
       
   351 
       
   352 
       
   353 TBool CBTBasebandModel::IsACLPossible(TACLLinkType aACLType) const
       
   354 /**
       
   355 	Decide if another ACL link allowing minimum of 'aACLType' packets
       
   356 	will be allowed by hardware LMP.
       
   357 	If error, or not sure, return ETrue and let hardware sort it out.
       
   358 */
       
   359 	{
       
   360 	LOG_FUNC
       
   361 	TACLLinkType aclLinkType = ENoACLLink;
       
   362 	TInt scoBandwidth = 0;
       
   363 	TInt activePhyCount = 0;
       
   364 	TInt scoCount = 0;
       
   365 	GarnerInfo(activePhyCount, scoCount, aclLinkType, scoBandwidth);
       
   366 	CheckInfo(activePhyCount, scoCount, aclLinkType, scoBandwidth);
       
   367 
       
   368 	// Check that the stack could accommodate another ACL link
       
   369 	if (activePhyCount > KMaxActivePhysicalLinks)
       
   370 		{
       
   371 		return EFalse;
       
   372 		}
       
   373 	
       
   374 	return IsCombinationAllowed(scoBandwidth, aACLType);
       
   375 	}
       
   376 
       
   377 TBool CBTBasebandModel::IsSCOPossible(TSCOLinkType aSCOType) const
       
   378 /**
       
   379 	Decide if SCO link allowing minimum of 'aSCOType' packets
       
   380 	will be allowed by hardware LMP.
       
   381 	If error, or not sure, return ETrue and let hardware sort it out.
       
   382 */
       
   383 	{
       
   384 	LOG_FUNC
       
   385 	TACLLinkType aclLinkType = ENoACLLink;
       
   386 	TInt scoBandwidth = 0;
       
   387 	TInt scoCount = 0;
       
   388 	TInt activePhyCount = 0;
       
   389 	GarnerInfo(activePhyCount, scoCount, aclLinkType, scoBandwidth);
       
   390 	CheckInfo(activePhyCount, scoCount, aclLinkType, scoBandwidth);
       
   391 	
       
   392 	
       
   393 	#ifdef _DEBUG
       
   394 	TInt bw = Bandwidth(aSCOType);
       
   395 	LOG(_L("IsSCOLinkPossible: Pre-existing:-"));
       
   396 	LOG2(_L("IsSCOLinkPossible: PHY count = %d, scoCount = %d, ACL link type = %d, "), activePhyCount, scoCount);
       
   397 	LOG2(_L("IsSCOLinkPossible: ACL link type = %d, scoBandwidth = %d"), aclLinkType, scoBandwidth);
       
   398 	LOG(_L("IsSCOLinkPossible: New requirement:-"));
       
   399 	LOG2(_L("IsSCOLinkPossible: SCO type required = %d, => bandwidth needed = %d"), aSCOType, bw);
       
   400 	#endif
       
   401 
       
   402   	
       
   403   	//Deal with too much SCO
       
   404   	if((scoBandwidth + Bandwidth(aSCOType))>EBandwidthAllUsed)
       
   405    		{
       
   406    		return EFalse;
       
   407    		}
       
   408   	//Deal with too many PHYs using SCOs
       
   409   	if(scoCount>=KMaxPhysicalLinksWithSCO&&aSCOType!=ENoSCOLink)
       
   410    		{
       
   411   		return EFalse;
       
   412   		}
       
   413   	return IsCombinationAllowed(scoBandwidth + Bandwidth(aSCOType), aclLinkType);
       
   414 	}
       
   415 
       
   416 TBool CBTBasebandModel::IsCombinationAllowed(TInt aSCOBandwidth, TACLLinkType aACLType) const
       
   417 	{
       
   418 	LOG_FUNC
       
   419 	//Now go through each ACL/SCOcombination carefully!
       
   420 	switch(aSCOBandwidth)
       
   421 		{
       
   422 		case EBandwidthNoneUsed:
       
   423 			return ETrue;
       
   424 		case EBandwidthOneThirdUsed:
       
   425 			return (aACLType<=EThreeSlotPackets);
       
   426 		case EBandwidthOneHalfUsed:
       
   427 		case EBandwidthTwoThirdsUsed:
       
   428 			return (aACLType<=EOneSlotPackets);
       
   429 		default:
       
   430 			return (aSCOBandwidth <= EBandwidthAllUsed);
       
   431 		}
       
   432 	}
       
   433 
       
   434 TBandwidth CBTBasebandModel::Bandwidth(TSCOLinkType aLinkType) const
       
   435 	{
       
   436 	LOG_FUNC
       
   437 	switch (aLinkType)
       
   438 		{
       
   439 		case ENoSCOLink:
       
   440 			return EBandwidthNoneUsed;
       
   441 			
       
   442 		case ESCODVPackets:
       
   443 			return EBandwidthAllUsed;
       
   444 			
       
   445 		case ESCOHV1Packets:
       
   446 			return EBandwidthAllUsed;
       
   447 			
       
   448 		case ESCOHV2Packets:
       
   449 			return EBandwidthOneHalfUsed;
       
   450 			
       
   451 		case ESCOHV3Packets:
       
   452 			return EBandwidthOneThirdUsed;
       
   453 			
       
   454 		default:
       
   455 			__ASSERT_DEBUG(ETrue, Panic(EBTBasebandModelBadRecord));
       
   456 			return EBandwidthNoneUsed;
       
   457 		}
       
   458 	}
       
   459 
       
   460 void CBTBasebandModel::GarnerInfo(TInt& aActivePhyCount, TInt& aSCOCount, TACLLinkType& aGreatestMinSlotRequirement, TInt& aSCOBandwidth) const
       
   461 	{
       
   462 	LOG_FUNC
       
   463 	aSCOCount = 0;
       
   464 	aGreatestMinSlotRequirement = ENoACLLink;
       
   465 	aSCOBandwidth = 0;
       
   466 
       
   467 	TInt totalPhyCount = iLinkData.Count();
       
   468 	aActivePhyCount = 0;
       
   469 	for (TInt i=(totalPhyCount-1); i>=0; i--)
       
   470 		{
       
   471 		if (!iLinkData[i].IsParked())
       
   472 			{
       
   473 			aActivePhyCount++;
       
   474 			if (iLinkData[i].iSCOMinRequirement != ENoSCOLink)
       
   475 				{
       
   476 				aSCOCount++; //only one SCO link per PHY for the time being
       
   477 				aSCOBandwidth += Bandwidth(iLinkData[i].iSCOMinRequirement);
       
   478 				}
       
   479 			aGreatestMinSlotRequirement = aGreatestMinSlotRequirement<iLinkData[i].ACLActualMinSlots()?
       
   480 								iLinkData[i].iACLMinSlotsAllowed:aGreatestMinSlotRequirement;
       
   481 			}
       
   482 		}
       
   483 	__ASSERT_DEBUG(aSCOBandwidth <= EBandwidthAllUsed,
       
   484 				   Panic(EBTBasebandModelBadRecord));
       
   485 	}
       
   486 
       
   487 void CBTBasebandModel::CheckInfo(TInt __DEBUG_ONLY(aActivePhyCount),
       
   488 								 TInt __DEBUG_ONLY(aSCOCount),
       
   489 								 TACLLinkType __DEBUG_ONLY(aGreatestMinSlotRequirement),
       
   490 								 TInt __DEBUG_ONLY(aSCOBandwidth)) const
       
   491 	{
       
   492 	LOG_FUNC
       
   493 	__ASSERT_DEBUG(aActivePhyCount <= KMaxActivePhysicalLinks,
       
   494 				   Panic(EBTBasebandModelBadRecord));
       
   495 	__ASSERT_DEBUG(aSCOCount <= KMaxPhysicalLinksWithSCO,
       
   496 				   Panic(EBTBasebandModelBadRecord));
       
   497 	__ASSERT_DEBUG((aSCOBandwidth == EBandwidthNoneUsed ||
       
   498 				   aSCOBandwidth == EBandwidthOneThirdUsed ||
       
   499 				   aSCOBandwidth == EBandwidthOneHalfUsed ||
       
   500 				   aSCOBandwidth == EBandwidthTwoThirdsUsed ||
       
   501 				   aSCOBandwidth == EBandwidthAllUsed),
       
   502 				   Panic(EBTBasebandModelBadRecord));
       
   503 	__ASSERT_DEBUG((aGreatestMinSlotRequirement == ENoACLLink ||
       
   504 				   aGreatestMinSlotRequirement == EOneSlotPackets ||
       
   505 				   aGreatestMinSlotRequirement == EThreeSlotPackets ||
       
   506 				   aGreatestMinSlotRequirement == EFiveSlotPackets),
       
   507 				   Panic(EBTBasebandModelBadRecord));
       
   508 	}
       
   509 
       
   510 TBandwidth CBTBasebandModel::CostOfACLLink(TACLLinkType aACLType) const
       
   511 	{
       
   512 	LOG_FUNC
       
   513 	switch(aACLType)
       
   514 		{
       
   515 		case EOneSlotPackets:
       
   516 		return EBandwidthOneTwelfthUsed;
       
   517 		case EThreeSlotPackets:
       
   518 		return EBandwidthFiveSixthsUsed;
       
   519 		case EFiveSlotPackets:
       
   520 		return EBandwidthElevenTwelfthsUsed;
       
   521 		default:
       
   522 		return EBandwidthNoneUsed;
       
   523 		}
       
   524 	}
       
   525 
       
   526 TACLLinkType CBTBasebandModel::ACLRequirement(TUint16 aPacketMask) const
       
   527 	{
       
   528 	LOG_FUNC
       
   529 	if(aPacketMask & (KDM1Packet | KDH1Packet | KAUX1Packet))
       
   530 		{
       
   531 		return EOneSlotPackets;
       
   532 		}
       
   533 	if(aPacketMask & (KDM3Packet | KDH3Packet))
       
   534 		{
       
   535 		return EThreeSlotPackets;
       
   536 		}
       
   537 	if(aPacketMask & (KDM5Packet | KDH5Packet))
       
   538 		{
       
   539 		return EFiveSlotPackets;
       
   540 		}
       
   541 	//No ACL link type given so assume...
       
   542 //	__DEBUGGER();
       
   543 	return ENoACLLink;
       
   544 	}
       
   545 
       
   546 TSCOLinkType CBTBasebandModel::SCORequirement(TUint16 aPacketMask) const
       
   547 	{
       
   548 	LOG_FUNC
       
   549 	//Baseband needs to err towards the least bandwidth used,
       
   550 	//so start checking mask for HV3 packets
       
   551 	if(aPacketMask & ESCOHV3Packets)
       
   552 		{
       
   553 		return ESCOHV3Packets;
       
   554 		}
       
   555 	if(aPacketMask & ESCOHV2Packets)
       
   556 		{
       
   557 		return ESCOHV2Packets;
       
   558 		}
       
   559 	if(aPacketMask & ESCOHV1Packets)
       
   560 		{
       
   561 		return ESCOHV1Packets;
       
   562 		}
       
   563 	//DV as expensive as HV1 but do allow ACL data transmission over
       
   564 	//the physical link on which the SCO link has been created
       
   565 	if(aPacketMask & ESCODVPackets)
       
   566 		{
       
   567 		return ESCODVPackets;
       
   568 		}
       
   569 	//No SCO link type given so assume...
       
   570 	__DEBUGGER();
       
   571 	return ENoSCOLink;
       
   572 	}
       
   573 
       
   574 TInt CBTBasebandModel::FindByAddress(const TBTDevAddr& aAddr) const
       
   575 	{
       
   576 	LOG_FUNC
       
   577 	if(aAddr == TBTDevAddr(0))
       
   578 		//Do not search on zero.
       
   579 		{
       
   580 		return KErrNotFound;
       
   581 		}
       
   582 
       
   583 	TInt count = iLinkData.Count();
       
   584 	for (TInt i=(count-1); i>=0; i--)
       
   585 		{
       
   586 		if (iLinkData[i].iBdaddr == aAddr && (!iLinkData[i].IsParked()))
       
   587 			{
       
   588 			return i;
       
   589 			}
       
   590 		}
       
   591 	return KErrNotFound;
       
   592 	}
       
   593 
       
   594 TInt CBTBasebandModel::FindByHandle(THCIConnHandle aHandle) const
       
   595 	{
       
   596 	LOG_FUNC
       
   597 	TInt ret = FindByACLHandle(aHandle);
       
   598 	if(ret == KErrNotFound)
       
   599 		{
       
   600 		ret = FindBySCOHandle(aHandle);
       
   601 		}
       
   602 	if(ret == KErrNotFound)
       
   603 		{
       
   604 		ret = FindByeSCOHandle(aHandle);
       
   605 		}
       
   606 	return ret;
       
   607 	}	
       
   608 
       
   609 TInt CBTBasebandModel::FindByACLHandle(THCIConnHandle aHandle) const
       
   610 	{
       
   611 	LOG_FUNC
       
   612 	if(!aHandle)
       
   613 		//Do not search on zero.
       
   614 		{
       
   615 		return KErrNotFound;
       
   616 		}
       
   617 
       
   618 	for (TInt i=(iLinkData.Count()-1); i>=0; i--)
       
   619 		{
       
   620 		const TPhysicalLinkData& handle = iLinkData[i];
       
   621 		if ((handle.iConnH == aHandle))
       
   622 			{
       
   623 			return i;
       
   624 			}
       
   625 		}
       
   626 	return KErrNotFound;
       
   627 	}
       
   628 
       
   629 TInt CBTBasebandModel::FindBySCOHandle(THCIConnHandle aHandle) const
       
   630 	{
       
   631 	LOG_FUNC
       
   632 	if(!aHandle)
       
   633 		//Do not search on zero.
       
   634 		{
       
   635 		return KErrNotFound;
       
   636 		}
       
   637 
       
   638 	TInt count = iLinkData.Count();
       
   639 	for (TInt i=(count-1); i>=0; i--)
       
   640 		{
       
   641 		if (iLinkData[i].iSCOConnH == aHandle)
       
   642 			{
       
   643 			return i;
       
   644 			}
       
   645 		}
       
   646 	return KErrNotFound;
       
   647 	}
       
   648 
       
   649 TInt CBTBasebandModel::FindByeSCOHandle(THCIConnHandle aHandle) const
       
   650 	{
       
   651 	LOG_FUNC
       
   652 	if(!aHandle)
       
   653 		//Do not search on zero.
       
   654 		{
       
   655 		return KErrNotFound;
       
   656 		}
       
   657 
       
   658 	TInt count = iLinkData.Count();
       
   659 	for (TInt i=(count-1); i>=0; i--)
       
   660 		{
       
   661 		if (iLinkData[i].ieSCOConnH == aHandle)
       
   662 			{
       
   663 			return i;
       
   664 			}
       
   665 		}
       
   666 	return KErrNotFound;
       
   667 	}
       
   668 
       
   669 TInt CBTBasebandModel::DoUpdateModel(const TBTConnect& aConn, TUint16 aPacketMask, TBool iIgnorePacketMask)
       
   670 /**
       
   671 	Tries to find the record containing either the BD address, or, if not, the handle
       
   672 	supplied in 'aConn'. 
       
   673 	If successful, updates record with those values in 'aConn' that are not already 
       
   674 	in the record, and a value deduced 'aPacketMask'.
       
   675 	Whether all these values are used for ACL or SCO is decided by 'aConn.iLinkType'.
       
   676 	If unsuccessful, creates a new record with 'aConn', and 'aPacketMask'.
       
   677 */
       
   678 	{
       
   679 	LOG_FUNC
       
   680 	//See if link record already exists
       
   681 	TInt found = FindByAddress(aConn.iBdaddr);
       
   682 	if(found == KErrNotFound)
       
   683 		{
       
   684 		//try finding by handle
       
   685 		found = FindByHandle(aConn.iConnH);
       
   686 		}
       
   687 	//If so, update
       
   688 	if(found != KErrNotFound)
       
   689 		{
       
   690 		if (!iLinkData[found].IsParked())
       
   691 			{
       
   692 			UpdateLink(iLinkData[found], aConn);
       
   693 			if(!iIgnorePacketMask)
       
   694 				{
       
   695 				UpdateLink(iLinkData[found], aConn.iLinkType, aPacketMask);
       
   696 				}
       
   697 			}
       
   698 		return KErrNone;
       
   699 		}
       
   700 
       
   701 	//Got to here - this is a new PHY
       
   702 	__ASSERT_DEBUG(aConn.iLinkType==EACLLink, Panic(EBTBasebandModelBadRecord));
       
   703 	if(aConn.iLinkType!=EACLLink)
       
   704 	{
       
   705 	return KErrArgument;
       
   706 	}
       
   707 
       
   708 	TPhysicalLinkData ld;
       
   709 	UpdateLink(ld, aConn);
       
   710 	if(!iIgnorePacketMask)
       
   711 		{
       
   712 		UpdateLink(ld, aConn.iLinkType, aPacketMask);
       
   713 		}
       
   714 	(void)iLinkData.Append(ld); //NB failure => we become too tolerant => unnecessary HCI traffic
       
   715 	return KErrNone;
       
   716 	}
       
   717 
       
   718 void CBTBasebandModel::UpdateLink(TPhysicalLinkData& aLinkData, const TBTConnect& aConn)
       
   719 /**
       
   720 	Use aPacketMask together those values aConn not already in 
       
   721 	aLinkData to update aLinkData.
       
   722 	NB An ACL handle may have been supplied in aConn, 
       
   723 	   but the update is for a SCO Link
       
   724 */
       
   725 	{
       
   726 	LOG_FUNC
       
   727 	LOG5(_L("Baseband model: updating record %d,%d,%d, to %d, type %d"), aLinkData.iConnH, aLinkData.iSCOConnH, aLinkData.ieSCOConnH, aConn.iConnH, aConn.iLinkType);
       
   728 	__ASSERT_DEBUG((aLinkData.iBdaddr==TBTDevAddr(0) || aLinkData.iBdaddr==aConn.iBdaddr),
       
   729 					Panic(EBTBasebandModelBadRecord));
       
   730 	aLinkData.iBdaddr = aConn.iBdaddr;
       
   731 	
       
   732 	switch (aConn.iLinkType)
       
   733 		{
       
   734 		case ESCOLink:
       
   735 			__ASSERT_DEBUG((aLinkData.iSCOConnH==0 || aLinkData.iSCOConnH==aConn.iConnH),
       
   736 							Panic(EBTBasebandModelBadRecord));
       
   737 			aLinkData.iSCOConnH = aConn.iConnH;
       
   738 			break;
       
   739 
       
   740 		case EACLLink:
       
   741 			__ASSERT_DEBUG((aLinkData.iConnH==0 || aLinkData.iConnH==aConn.iConnH),
       
   742 							Panic(EBTBasebandModelBadRecord));
       
   743 			aLinkData.iConnH = aConn.iConnH;
       
   744 			break;
       
   745 		
       
   746 		case EeSCOLink:
       
   747 			__ASSERT_DEBUG((aLinkData.ieSCOConnH==0 || aLinkData.ieSCOConnH==aConn.iConnH),
       
   748 							Panic(EBTBasebandModelBadRecord));
       
   749 			aLinkData.ieSCOConnH = aConn.iConnH;
       
   750 			break;
       
   751 		
       
   752 		default:
       
   753 			Panic(EBTUnknownLogicalLink);
       
   754 		}
       
   755 	}
       
   756 
       
   757 void CBTBasebandModel::UpdateLink(TPhysicalLinkData& aLinkData, TLinkType aLinkType, TUint16 aPacketMask)
       
   758 	{
       
   759 	LOG_FUNC
       
   760 	if(aLinkType==ESCOLink)
       
   761 		{
       
   762 		aLinkData.iSCOMinRequirement = SCORequirement(aPacketMask);
       
   763 		}
       
   764 	else if (aLinkType == EACLLink)
       
   765 		{
       
   766 		aLinkData.iACLMinSlotsAllowed = ACLRequirement(aPacketMask);
       
   767 		}
       
   768 	}
       
   769 
       
   770 void CBTBasebandModel::SetupConnectRecord(TBTConnect& aConn, THCIConnHandle aConnH, 
       
   771 												const TBTDevAddr& aAddr,
       
   772 												TUint aCoD,
       
   773 												TLinkType aLinkType,
       
   774 												TEncryptMode aEncryptMode) const
       
   775 /**
       
   776 	Helper class to fill out a TBTConnect
       
   777 */
       
   778 	{
       
   779 	LOG_FUNC
       
   780     aConn.iConnH = aConnH;
       
   781     aConn.iBdaddr = aAddr;
       
   782     aConn.iCoD = aCoD;
       
   783     aConn.iLinkType = aLinkType;
       
   784     aConn.iEncryptMode = aEncryptMode;
       
   785 	}