bluetooth/btstack/eirman/eirmanager.cpp
changeset 0 29b1cd4cb562
child 23 32ba20339036
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include "eirmanager.h"
       
    22 #include <bluetooth/hcicommandqueue.h>
       
    23 #include <bttypes.h>
       
    24 #include <bluetooth/hci/commandcompleteevent.h>
       
    25 #include <bluetooth/hci/commandstatusevent.h>
       
    26 #include <bluetooth/hci/command.h>
       
    27 #include <bluetooth/hci/hciconsts.h>
       
    28 #include <bluetooth/hci/writeextendedinquiryresponsecommand.h>
       
    29 #include <bluetooth/logger.h>
       
    30 #include "eirmansession.h"
       
    31 #include "linkmgr.h"
       
    32 #include "eirmanpanics.h"
       
    33 
       
    34 #ifdef __FLOG_ACTIVE
       
    35 _LIT8(KLogComponent, LOG_COMPONENT_EIRMANAGER);
       
    36 #endif
       
    37 
       
    38 __ASSERT_COMPILE(KReservedNameBytes + KReservedUuid16Bytes + KReservedUuid128Bytes + KReservedManufacturerSpecificDataBytes + KReservedTxPowerLevelBytes == KEirPacketSize);
       
    39 
       
    40 CEirManager* CEirManager::NewL(MHCICommandQueue& aCommandQueue, CLinkMgrProtocol& aLinkMgrProtocol)
       
    41 	{
       
    42 	LOG_STATIC_FUNC
       
    43 	
       
    44 	CEirManager* self = new(ELeave) CEirManager(aCommandQueue, aLinkMgrProtocol);
       
    45 	CleanupStack::PushL(self);
       
    46 	self->ConstructL();
       
    47 	CleanupStack::Pop(self);
       
    48 	return self;
       
    49 	}
       
    50 
       
    51 CEirManager::~CEirManager()
       
    52 	{
       
    53 	LOG_FUNC
       
    54 	
       
    55 	// Delete all registered tags
       
    56 	for(TInt8 i = static_cast<TInt8>(EEirTagName); i < static_cast<TInt8>(EEirTagRESERVED); i++)
       
    57 		{
       
    58 		__ASSERT_DEBUG(!iNotifiees[i].iNotifiee, EIR_MANAGER_PANIC(EEirManagerNotifieeNotCleared));
       
    59 		}
       
    60 	
       
    61 	iCommandQueue.MhcqRemoveAllCommands(*this);
       
    62 	delete iWriteEirTimer;
       
    63 	}
       
    64 
       
    65 CEirManager::CEirManager(MHCICommandQueue& aCommandQueue, CLinkMgrProtocol& aLinkMgrProtocol)
       
    66 	: iOffersStale(EFalse)
       
    67 	, iCmdId(KInvalidCommandQueueItemId)
       
    68 	, iCmdCount(0)
       
    69 	, iCommandQueue(aCommandQueue)
       
    70 	, iLinkMgrProtocol(aLinkMgrProtocol)
       
    71 	{
       
    72 	LOG_FUNC
       
    73 	}
       
    74 
       
    75 void CEirManager::ConstructL()
       
    76 	{
       
    77 	LOG_FUNC
       
    78 	iWriteEirTimer = CWriteEirTimer::NewL(*this);
       
    79 	}
       
    80 
       
    81 void CEirManager::UnhookClient(TEirTag aTag)
       
    82 	{
       
    83 	LOG_FUNC
       
    84 	if (iNotifiees[aTag].iNotifiee)
       
    85 		{
       
    86 		iNotifiees[aTag].iNotifiee = NULL;
       
    87 		if(iNotifiees[aTag].iTagData)
       
    88 			{
       
    89 			delete iNotifiees[aTag].iTagData;
       
    90 			iNotifiees[aTag].iTagData = NULL;
       
    91 			}			
       
    92 		}
       
    93 	}
       
    94 
       
    95 // A client register aTag with EirManager
       
    96 TInt CEirManager::RegisterTag(TEirTag aTag, MEirManagerNotifiee& aNotifiee)
       
    97 	{
       
    98 	LOG_FUNC
       
    99 	TInt ret = KErrNone;
       
   100 	LOG1(_L("CEirManager::RegisterTag tag = %d"), aTag);
       
   101 
       
   102 	if(!TagValid(aTag))
       
   103 		{
       
   104 		LOG1(_L("CEirManager::RegisterTag INVALID TAG: %d"), aTag);
       
   105 		ret = KErrArgument;
       
   106 		}
       
   107 	else if(!TagAllowed(aTag))
       
   108 		{
       
   109 		LOG(_L("CEirManager::RegisterTag: IN USE"));
       
   110 		ret = KErrInUse;
       
   111 		}
       
   112 	else
       
   113 		{
       
   114 		iNotifiees[aTag].iNotifiee = &aNotifiee;
       
   115 		iNotifiees[aTag].iTagData = NULL;
       
   116 		iNotifiees[aTag].iOfferedBytes = 0;
       
   117 		iNotifiees[aTag].iEirDataMode = EEirDataComplete;
       
   118 		iNotifiees[aTag].iState = 0x00;
       
   119 
       
   120 		if (!OffersPending() && NeedToOffer())
       
   121 			{
       
   122 			// Do not consider this for insertion yet if there are offers pending.
       
   123 			// Instead, once the offers have been responded to, this client will be dealt with
       
   124 			NotifyClients();
       
   125 			}
       
   126 		}
       
   127 	return ret;
       
   128 	}
       
   129 
       
   130 // A client deregister aTag with EirManager
       
   131 void CEirManager::DeregisterTag(TEirTag aTag)
       
   132 	{
       
   133 	LOG_FUNC
       
   134 	LOG1(_L("CEirManager::DeregisterTag tag = %d"), aTag);
       
   135 
       
   136 	if(!TagValid(aTag))
       
   137 		{
       
   138 		LOG1(_L("CEirManager::DeregisterTag INVALID TAG: %d"), aTag);
       
   139 		return;
       
   140 		}
       
   141 
       
   142 	if (iNotifiees[aTag].iNotifiee)
       
   143 		{
       
   144 		UnhookClient(aTag);	
       
   145 		if(iNotifiees[aTag].iRequiredBytes > 0)
       
   146 			{
       
   147 			// It did require some bytes and now requires none, reevaluate offers
       
   148 			iNotifiees[aTag].iState &= ~KNeedOffer;
       
   149 			// A client could storm in a deregister before setting data - so we remove
       
   150 			// any pending offer as a SetData after deregistering will be errored - any
       
   151 			// previous offer has been voided.
       
   152 			iNotifiees[aTag].iState &= ~KOfferPending;
       
   153 			if(!OffersPending())
       
   154 				{
       
   155 				NotifyClients();
       
   156 				}
       
   157 			else if(iNotifiees[aTag].iOfferedBytes > 0)
       
   158 				{
       
   159 				iOffersStale = ETrue;
       
   160 				}
       
   161 			}
       
   162 		if(!NeedToOffer() && !OffersPending())
       
   163 			{
       
   164 			TryToUpdateHostController();
       
   165 			}
       
   166 		// Now tidy up offer and requested values (they are no longer valid).
       
   167 		iNotifiees[aTag].iRequiredBytes = 0;
       
   168 		iNotifiees[aTag].iOfferedBytes = 0;
       
   169 		}
       
   170 	}
       
   171 
       
   172 TInt CEirManager::SetData(TEirTag aTag, TDesC8& aData, TEirDataMode aEirDataMode)
       
   173 	{
       
   174 	LOG_FUNC
       
   175 	LOG1(_L("CEirManager::SetData tag = %d"), aTag);
       
   176 	
       
   177 	if(!iLinkMgrProtocol.IsExtendedInquiryResponseSupportedLocally())
       
   178 		{
       
   179 		return KErrNotSupported;
       
   180 		}
       
   181 
       
   182 	if(!TagValid(aTag))
       
   183 		{
       
   184 		LOG1(_L("CEirManager::SetData INVALID TAG: %d"), aTag);
       
   185 		return KErrArgument;
       
   186 		}
       
   187 
       
   188 	if(!iNotifiees[aTag].iNotifiee)
       
   189 		{
       
   190 		// No client registered with this tag
       
   191 		return KErrNotFound;
       
   192 		}
       
   193 
       
   194 	LOG2(_L("CEirManager::SetData data len = %d offered bytes: %d"), aData.Length(), iNotifiees[aTag].iOfferedBytes);
       
   195 
       
   196 	if (!(iNotifiees[aTag].iState & KOfferPending))
       
   197 		{
       
   198 		// No offer pending for this tag
       
   199 		return KErrNotReady;		
       
   200 		}
       
   201 	if(iNotifiees[aTag].iOfferedBytes < aData.Length())
       
   202 		{
       
   203 		// Client wants to publish more data than allowed to
       
   204 		return KErrTooBig;
       
   205 		}
       
   206 		
       
   207 	TInt ret = KErrNone;
       
   208 	
       
   209 	HBufC8** tagdata;
       
   210 	
       
   211 	FindTagData(aTag, tagdata);
       
   212 	
       
   213 	// Free up whatever there was before
       
   214 	if (*tagdata)
       
   215 		{
       
   216 		delete *tagdata;
       
   217 		}
       
   218 
       
   219 	HBufC8* data = NULL;
       
   220 
       
   221 	// If the descriptor is empty, mark the heap buffer pointer as NULL, 
       
   222 	// meaning that the client is registered for this tag, but there is no currently no data available for it
       
   223 	if(aData.Length() != 0x0)
       
   224 		{
       
   225 		data = aData.Alloc();
       
   226 		if (!data)
       
   227 			{
       
   228 			LOG(_L("CEirManager::SetData: NO MEMORY "));
       
   229 			ret = KErrNoMemory;
       
   230 			}
       
   231 		}
       
   232 
       
   233 	*tagdata = data;
       
   234 
       
   235 	// We no longer have a value pending.
       
   236 	iNotifiees[aTag].iState &= ~KOfferPending;
       
   237 	iNotifiees[aTag].iEirDataMode = aEirDataMode;
       
   238 
       
   239 	if(NeedToOffer() && !OffersPending())
       
   240 		{
       
   241 		NotifyClients();
       
   242 		}
       
   243 
       
   244 	if(!NeedToOffer() && !OffersPending())
       
   245 		{
       
   246 
       
   247 		// Regardless of whether the allocation failed or not, check whether all offers have been accepted
       
   248 		// and update the Host Controller accordingly
       
   249 		TryToUpdateHostController();
       
   250 		}
       
   251 		
       
   252 	LOG1(_L("CEirManager::SetData returning = %d"), ret);
       
   253 	return ret;
       
   254 	}
       
   255 
       
   256 void CEirManager::MhcqcCommandEventReceived(const THCIEventBase& aEvent, 
       
   257 											const CHCICommandBase* /*aRelatedCommand*/)
       
   258 	{
       
   259 	LOG_FUNC
       
   260 	if(aEvent.EventCode() == ECommandCompleteEvent)
       
   261 		{
       
   262 		const THCICommandCompleteEvent& completeEvent = static_cast<const THCICommandCompleteEvent&>(aEvent);
       
   263 		if(completeEvent.CommandOpcode() == KWriteExtendedInquiryResponseOpcode)
       
   264 			{
       
   265 			--iCmdCount;
       
   266 			}
       
   267 		else
       
   268 			{
       
   269 			LOG1(_L("Warning!! Unexpected Command Complete Event Received (command opcode: 0x%04x)"), completeEvent.CommandOpcode());
       
   270 			__ASSERT_DEBUG(EFalse, EIR_MANAGER_PANIC(EEirManagerUnexpectedCompleteEvent));
       
   271 			}
       
   272 		}
       
   273 	else
       
   274 		{
       
   275 		LOG1(_L("Warning!! Unexpected Event Received (event code: 0x%02x)"), aEvent.EventCode());
       
   276 		__ASSERT_DEBUG(EFalse, EIR_MANAGER_PANIC(EEirManagerUnexpectedEvent));
       
   277 		}
       
   278 	}
       
   279 
       
   280 void CEirManager::MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* aCommand)
       
   281 	{
       
   282 	LOG_FUNC
       
   283 	aErrorCode = aErrorCode;   // Avoid unused warning
       
   284 	LOG1(_L("\taErrorCode = %d"), aErrorCode);
       
   285 	if(aCommand && aCommand->Opcode() == KWriteExtendedInquiryResponseOpcode)
       
   286 		{
       
   287 		--iCmdCount;
       
   288 		}
       
   289 	else
       
   290 		{
       
   291 		LOG(_L("Warning!! Unexpected Error Received"));
       
   292 		if(aCommand)
       
   293 			{
       
   294 			LOG1(_L("\taCommand->Opcode() = 0x%04x"), aCommand->Opcode());
       
   295 			}
       
   296 		}
       
   297 	}
       
   298 
       
   299 void CEirManager::WriteExtendedInquiryResponseL(TBool aFECRequired, const TDesC8& aEir)
       
   300 	{
       
   301 	LOG_FUNC
       
   302 	if(iCmdCount > 0)
       
   303 		{
       
   304 		// There is at least 1 outstanding command in the queue
       
   305 		TInt err = iCommandQueue.MhcqRemoveCommand(iCmdId, *this);
       
   306 		if(err == KErrNone)
       
   307 			{
       
   308 			--iCmdCount;
       
   309 			}
       
   310 		// else if there was an error it is because the command cannot be removed
       
   311 		// "at this time" so we just "leak" it.  This isn't a problem, this was a 
       
   312 		// best effort optimisation.
       
   313 		}
       
   314 	CWriteExtendedInquiryResponseCommand* cmd = CWriteExtendedInquiryResponseCommand::NewL(aFECRequired ? 1 : 0, aEir);
       
   315 	// Ownership of cmd transfered
       
   316 	iCmdId = iCommandQueue.MhcqAddCommandL(cmd, *this);
       
   317 	++iCmdCount;
       
   318 	}
       
   319 
       
   320 // Check whether a specific tag is allowed to be registered
       
   321 TBool CEirManager::TagAllowed(TEirTag aTag) const
       
   322 	{
       
   323 	LOG_FUNC
       
   324 	// We don't support 32 bit UUIDs
       
   325 	return (aTag!=EEirTagSdpUuid32);
       
   326 	}
       
   327 	
       
   328 // Check whether aTag is present
       
   329 TBool CEirManager::TagPresent(TEirTag aTag) const
       
   330 	{
       
   331 	LOG_FUNC
       
   332 	return (iNotifiees[aTag].iNotifiee != NULL);
       
   333 	}
       
   334 
       
   335 // Find the registered data for aTag
       
   336 void CEirManager::FindTagData(TEirTag aTag, HBufC8**& aOutPointerToData)
       
   337 	{
       
   338 	LOG_FUNC
       
   339 	aOutPointerToData = &iNotifiees[aTag].iTagData;
       
   340 	}
       
   341 
       
   342 // Count the number of registered tags
       
   343 TInt CEirManager::TagCount() const
       
   344 	{
       
   345 	LOG_FUNC
       
   346 	TInt count = 0;
       
   347 	for (TInt i=0; i<EEirTagRESERVED; i++)
       
   348 		{
       
   349 		if (iNotifiees[i].iNotifiee)
       
   350 			{
       
   351 			count++;
       
   352 			}
       
   353 		}
       
   354 	return count;
       
   355 	}
       
   356 
       
   357 TBool CEirManager::OffersPending() const
       
   358 	{
       
   359 	LOG_FUNC
       
   360 	for (TInt i=0; i<EEirTagRESERVED; i++)
       
   361 		{
       
   362 		if(iNotifiees[i].iState & KOfferPending)
       
   363 			{
       
   364 			return ETrue;
       
   365 			}
       
   366 		}
       
   367 	return EFalse;
       
   368 	}
       
   369 
       
   370 TBool CEirManager::NeedToOffer() const
       
   371 	{
       
   372 	LOG_FUNC
       
   373 	if(iOffersStale)
       
   374 		{
       
   375 		return ETrue;
       
   376 		}
       
   377 	for (TInt i=0; i<EEirTagRESERVED; i++)
       
   378 		{
       
   379 		if (iNotifiees[i].iState & KNeedOffer)
       
   380 			{
       
   381 			return ETrue;
       
   382 			}
       
   383 		}
       
   384 	return EFalse;
       
   385 	}
       
   386 
       
   387 // Notify EirManager there is a change of data from aTag client
       
   388 TInt CEirManager::NewData(TEirTag aTag, TInt aRequiredBytes)
       
   389 	{
       
   390 	LOG_FUNC
       
   391 	if(!iLinkMgrProtocol.IsExtendedInquiryResponseSupportedLocally())
       
   392 		{
       
   393 		return KErrNotSupported;
       
   394 		}
       
   395 
       
   396 	// including 2 bytes for length and tag
       
   397 	TInt requiredBytes = 0;
       
   398 	TInt currentBytes = iNotifiees[aTag].iRequiredBytes;
       
   399 	if(aRequiredBytes > 0)
       
   400 		{
       
   401 		requiredBytes = aRequiredBytes + KEirLengthTagLength;
       
   402 		}
       
   403 	else if(aTag == EEirTagName && aRequiredBytes == 0)
       
   404 		{
       
   405 		// This is a special case for device without local name
       
   406 		requiredBytes = KEirLengthTagLength;
       
   407 		}
       
   408 	else
       
   409 		{
       
   410 		requiredBytes = 0;
       
   411 		}
       
   412 	
       
   413 	iNotifiees[aTag].iRequiredBytes = requiredBytes; // always record what we last asked for.
       
   414 	
       
   415 	if(!(iNotifiees[aTag].iState & KNeedOffer))
       
   416 		{
       
   417 		// We currently aren't marked as needing an offer so we will need to fix that...
       
   418 		iNotifiees[aTag].iState |= KNeedOffer;
       
   419 		if(requiredBytes == currentBytes && !(iNotifiees[aTag].iState & KOfferPending) && !iOffersStale)
       
   420 			{
       
   421 			// If the same then we handle locally, if we aren't already waiting.
       
   422 			DoNotify(aTag);
       
   423 			}
       
   424 		else if(!OffersPending())
       
   425 			{
       
   426 			// If not waiting for anybody then lets kick off a round.
       
   427 			NotifyClients();
       
   428 			}
       
   429 		}
       
   430 	return KErrNone;
       
   431 	}
       
   432 	
       
   433 // Notify all registered clients about their allocated data length
       
   434 void CEirManager::NotifyClients()
       
   435 	{
       
   436 
       
   437 	LOG_FUNC
       
   438 
       
   439 	// go around each notifiee and ask for values
       
   440 	// our policy at the moment is: 
       
   441 	// after allocating reserved bytes for each tag, we will prioritize tag with big granularity
       
   442 
       
   443 	ComputeOfferLengths(); 
       
   444 
       
   445 	for (TInt i = 0; i<EEirTagRESERVED; i++)
       
   446 		{
       
   447 		if(TagPresent((TEirTag) i))
       
   448 			{
       
   449 			DoNotify((TEirTag)i);
       
   450 			}
       
   451 		}
       
   452 	}
       
   453 
       
   454 // Notify each tag about the available data length
       
   455 void CEirManager::DoNotify(TEirTag aTag)
       
   456 	{
       
   457 	LOG_FUNC
       
   458 
       
   459 	iNotifiees[aTag].iState &= ~KNeedOffer; // We got an offer!
       
   460 	
       
   461 	// Only make valid offers: offers more than 0 and 0 offers with non 0 request
       
   462 	if(iNotifiees[aTag].iOfferedBytes > 0)
       
   463 		{
       
   464 		// Notify client about offered bytes
       
   465 		iNotifiees[aTag].iState |= KOfferPending;
       
   466 		iNotifiees[aTag].iNotifiee->MemnEirBlockAvailable(aTag, iNotifiees[aTag].iOfferedBytes);
       
   467 		}
       
   468 	else if(iNotifiees[aTag].iOfferedBytes == 0)
       
   469 		{
       
   470 		if(iNotifiees[aTag].iRequiredBytes > 0)
       
   471 			{
       
   472 			// Notify client about 0 offer and not expecting client to call back
       
   473 			iNotifiees[aTag].iState |= KOfferPending;
       
   474 			iNotifiees[aTag].iNotifiee->MemnEirBlockAvailable(aTag, iNotifiees[aTag].iOfferedBytes);
       
   475 			}
       
   476 		else if(iNotifiees[aTag].iRequiredBytes == 0)
       
   477 			{
       
   478 			// request 0 and offered 0, delete client
       
   479 			iNotifiees[aTag].iState &= ~KNeedOffer;
       
   480 			delete iNotifiees[aTag].iTagData;
       
   481 			iNotifiees[aTag].iTagData = NULL;
       
   482 			}
       
   483 		}
       
   484 	}
       
   485 
       
   486 void CEirManager::ComputeOfferLengths()
       
   487 	{
       
   488 	LOG_FUNC
       
   489 	// count bytes available for EIR data, including length and tag
       
   490 	// due to the low cost of Tx Power Level, it is always given a space in EIR
       
   491 	TInt availableEirSize = EIRPacketSize();
       
   492 	TInt reservedByteForName = KReservedNameBytes - (KEirPacketSize - availableEirSize);
       
   493 	TInt totalSpare = 0;
       
   494 
       
   495 	ComputeClientInitialOffer(EEirTagName, totalSpare, reservedByteForName);
       
   496 	ComputeClientInitialOffer(EEirTagSdpUuid16, totalSpare, KReservedUuid16Bytes);
       
   497 	ComputeClientInitialOffer(EEirTagSdpUuid128, totalSpare, KReservedUuid128Bytes);
       
   498 	ComputeClientInitialOffer(EEirTagManufacturerSpecific, totalSpare, KReservedManufacturerSpecificDataBytes, ETrue);
       
   499 	ComputeClientInitialOffer(EEirTagTxPowerLevel, totalSpare, KReservedTxPowerLevelBytes, ETrue);
       
   500 
       
   501 	// if there is still bytes left after allocating the reserved bytes, 
       
   502 	// we will try to allocate them by giving high priority to tag with bigger granularity
       
   503 	/* tag			granularity (byte)
       
   504 	   name				1
       
   505 	  uuid16			2
       
   506 	  uuid128			16
       
   507 	  manufacturer		length
       
   508 	*/
       
   509 	LOG4(_L("RequiredBytes **** Name: %d, UUID16: %d, UUID128: %d, Manu: %d"), 
       
   510 			iNotifiees[0].iRequiredBytes, iNotifiees[1].iRequiredBytes, iNotifiees[3].iRequiredBytes, iNotifiees[4].iRequiredBytes);
       
   511 	LOG4(_L("OfferedBytes ----- Name: %d, UUID16: %d, UUID128: %d, Manu: %d"), 
       
   512 			iNotifiees[0].iOfferedBytes, iNotifiees[1].iOfferedBytes, iNotifiees[3].iOfferedBytes, iNotifiees[4].iOfferedBytes);
       
   513 	LOG1(_L("totalSpare: %d"), totalSpare);
       
   514 	ComputeClientFinalOffer(EEirTagManufacturerSpecific, totalSpare, KReservedManufacturerSpecificDataBytes, ETrue);
       
   515 	ComputeClientFinalOffer(EEirTagSdpUuid128, totalSpare, K128BitUuidGranularity);
       
   516 	ComputeClientFinalOffer(EEirTagSdpUuid16, totalSpare, K16BitUuidGranularity);
       
   517 	ComputeClientFinalOffer(EEirTagName, totalSpare, KDeviceNameGranularity);
       
   518 	// Tx Power Level should be after the allocating the reserved bytes
       
   519 	iOffersStale = EFalse; // We now know any "staleness" has been corrected.
       
   520 
       
   521 	LOG(_L("After allocating reserved"));
       
   522 	LOG4(_L("RequiredBytes **** Name: %d, UUID16: %d, UUID128: %d, Manu: %d"),
       
   523 			iNotifiees[0].iRequiredBytes, iNotifiees[1].iRequiredBytes, iNotifiees[3].iRequiredBytes, iNotifiees[4].iRequiredBytes);
       
   524 	LOG4(_L("OfferedBytes ----- Name: %d, UUID16: %d, UUID128: %d, Manu: %d"),
       
   525 			iNotifiees[0].iOfferedBytes, iNotifiees[1].iOfferedBytes, iNotifiees[3].iOfferedBytes, iNotifiees[4].iOfferedBytes);
       
   526 	LOG1(_L("totalSpare: %d"), totalSpare);
       
   527 	}
       
   528 
       
   529 /* compute offer based on client's request and the reserved bytes for this client*/
       
   530 void CEirManager::ComputeClientInitialOffer(TEirTag aTag, TInt& aTotalSpare, TInt aReservedBytes,
       
   531 											TBool aIsAllOrNothing)
       
   532 	{
       
   533 	if(TagPresent(aTag))
       
   534 		{
       
   535 		if(aIsAllOrNothing)
       
   536 			{
       
   537 			if(iNotifiees[aTag].iRequiredBytes <= aReservedBytes)
       
   538 				{
       
   539 				iNotifiees[aTag].iOfferedBytes = iNotifiees[aTag].iRequiredBytes;
       
   540 				aTotalSpare += (aReservedBytes - iNotifiees[aTag].iRequiredBytes);
       
   541 				iNotifiees[aTag].iEirDataMode = EEirDataComplete;
       
   542 				}
       
   543 			else
       
   544 				{
       
   545 				// the request exceeds reserved bytes for this client, the client is offered nothing
       
   546 				iNotifiees[aTag].iOfferedBytes = 0;
       
   547 				iNotifiees[aTag].iEirDataMode = EEirDataPartial;
       
   548 				aTotalSpare += aReservedBytes;
       
   549 				}
       
   550 			}
       
   551 		else
       
   552 			{
       
   553 			if(iNotifiees[aTag].iRequiredBytes <= aReservedBytes)
       
   554 				{
       
   555 				iNotifiees[aTag].iOfferedBytes = iNotifiees[aTag].iRequiredBytes;
       
   556 				aTotalSpare += (aReservedBytes - iNotifiees[aTag].iRequiredBytes);
       
   557 				iNotifiees[aTag].iEirDataMode = EEirDataComplete;
       
   558 				}
       
   559 			else
       
   560 				{
       
   561 				iNotifiees[aTag].iOfferedBytes = aReservedBytes;
       
   562 				iNotifiees[aTag].iEirDataMode = EEirDataPartial;
       
   563 				}
       
   564 			}
       
   565 		}
       
   566 	else
       
   567 		{
       
   568 		aTotalSpare += aReservedBytes;
       
   569 		}
       
   570 	}
       
   571 
       
   572 /* compute offer based on client's request and the spared bytes from the initial offers*/
       
   573 void CEirManager::ComputeClientFinalOffer(TEirTag aTag, TInt& aTotalSpare, TUint aGranularity,
       
   574 				  TBool aIsAllOrNothing)
       
   575 	{
       
   576 	if(iNotifiees[aTag].iRequiredBytes > iNotifiees[aTag].iOfferedBytes)
       
   577 		{
       
   578 		if(aIsAllOrNothing)
       
   579 			{
       
   580 			// this means we have more data to publish, which also indicates
       
   581 			// it required bytes are more than reserved bytes for this tag
       
   582 			if(iNotifiees[aTag].iRequiredBytes <= aTotalSpare)
       
   583 				{
       
   584 				aTotalSpare -= iNotifiees[aTag].iRequiredBytes;
       
   585 				iNotifiees[aTag].iOfferedBytes = iNotifiees[aTag].iRequiredBytes;
       
   586 				iNotifiees[aTag].iEirDataMode = EEirDataComplete;
       
   587 				}
       
   588 			}
       
   589 		else
       
   590 			{
       
   591 			// this means we have more data to publish
       
   592 			if((iNotifiees[aTag].iRequiredBytes - iNotifiees[aTag].iOfferedBytes) <= aTotalSpare)
       
   593 				{
       
   594 				aTotalSpare -= (iNotifiees[aTag].iRequiredBytes - iNotifiees[aTag].iOfferedBytes);
       
   595 				iNotifiees[aTag].iOfferedBytes = iNotifiees[aTag].iRequiredBytes;
       
   596 				iNotifiees[aTag].iEirDataMode = EEirDataComplete;
       
   597 				}
       
   598 			else
       
   599 				{
       
   600 				iNotifiees[aTag].iOfferedBytes += (aTotalSpare - aTotalSpare % aGranularity);
       
   601 				aTotalSpare %= aGranularity;
       
   602 				}
       
   603 			}
       
   604 		}
       
   605 	}
       
   606 
       
   607 // Calculate the valid size of EIR packet, excluding payload header	
       
   608 TInt CEirManager::EIRPacketSize() const
       
   609 	{
       
   610 	LOG_FUNC
       
   611 	TInt total = 0;
       
   612 	// default value of valid EIR packet is for using DM1
       
   613 	TInt ret = KEirPacketSize - KEirDM1PayloadHeaderSize;
       
   614 	for (TInt i = 0; i<EEirTagRESERVED; i++)
       
   615 		{
       
   616 		if(TagPresent((TEirTag) i) && iNotifiees[i].iRequiredBytes > 0)
       
   617 			{
       
   618 			total += iNotifiees[i].iRequiredBytes;
       
   619 			// Including 2 bytes for the length and tag
       
   620 			total += KEirLengthTagLength;
       
   621 			}
       
   622 		}
       
   623 		
       
   624 	if(total > KEirDM1PacketSize)
       
   625 		{
       
   626 		// None DM1 packet has 2 bytes of payload header, recalculate...
       
   627 		ret = KEirPacketSize - KEirNoneDM1PayloadHeaderSize;
       
   628 		}
       
   629 
       
   630 	return ret;
       
   631 	}
       
   632 
       
   633 void CEirManager::UpdateHostControllerL()
       
   634 	{
       
   635 	LOG_FUNC
       
   636 	
       
   637 	/* We don't handle the situation of handware swapping after stack is started
       
   638 	 * when the device changed from 2.1 to 2.0 and EIR is no longer supports, 
       
   639 	 * we'll quietly stop writing EIR and return KErrNotSupported for future requests.
       
   640 	we
       
   641 	 */
       
   642 	__ASSERT_DEBUG(iLinkMgrProtocol.IsExtendedInquiryResponseSupportedLocally(), EIR_MANAGER_PANIC(EEirManagerEirNotSupported));
       
   643 	TBuf8<KHCIExtendedInquiryResponseMaxLength> eir;
       
   644 
       
   645 	for (TInt i = 0; i<EEirTagRESERVED; i++)
       
   646 		{
       
   647 		TExtendedInquiryResponseDataType dataType = EEirLocalNamePartial;
       
   648 
       
   649 		// Skip non-registered and data-empty tags
       
   650 		if(iNotifiees[i].iNotifiee)
       
   651 			{
       
   652 			if(i == EEirTagName || iNotifiees[i].iTagData)
       
   653 				{
       
   654 				// We'll always try to publish empty device name according to the spec
       
   655 				switch (i)
       
   656 					{
       
   657 					// Name should go first
       
   658 					case EEirTagName:
       
   659 					dataType = iNotifiees[i].iEirDataMode == EEirDataPartial ? EEirLocalNamePartial : EEirLocalNameComplete;
       
   660 					break;
       
   661 					
       
   662 					case EEirTagSdpUuid16:
       
   663 					dataType = iNotifiees[i].iEirDataMode == EEirDataPartial ?  EEirUUID16Partial : EEirUUID16Complete;
       
   664 					break;
       
   665 									
       
   666 					case EEirTagSdpUuid128:
       
   667 					dataType = iNotifiees[i].iEirDataMode == EEirDataPartial ?  EEirUUID128Partial : EEirUUID128Complete;
       
   668 					break;
       
   669 					
       
   670 					case EEirTagManufacturerSpecific:
       
   671 					dataType = EEirVendorSpecific;
       
   672 					break;
       
   673 					
       
   674 					case EEirTagTxPowerLevel:
       
   675 					dataType = EEirTxPowerLevel;
       
   676 					break;
       
   677 					}
       
   678 				if(iNotifiees[i].iTagData)
       
   679 					{
       
   680 					// Data Structure length, add a byte for the Data Type
       
   681 					eir.Append(iNotifiees[i].iTagData->Length() + 1);
       
   682 					// Data Structure data: Data Type
       
   683 					eir.Append(dataType);
       
   684 					// Data Structure data: EIR data
       
   685 					eir.Append(*(iNotifiees[i].iTagData));
       
   686 					}
       
   687 				else
       
   688 					{
       
   689 					// Here is the case of empty device name again
       
   690 					eir.Append(1);
       
   691 					// Data Structure data: Data Type
       
   692 					eir.Append(dataType);
       
   693 					}
       
   694 				}
       
   695 			}
       
   696 		}
       
   697 
       
   698 	LOG1(_L("CEirManager::UpdateHostController about to send %d bytes of EIR data"), eir.Length());
       
   699 	// Send this down HCI
       
   700 	WriteExtendedInquiryResponseL(ETrue, eir);
       
   701 
       
   702 	LOG(_L("------- EIR verbose display"));
       
   703 	LOGHEXDESC(eir);
       
   704 	}
       
   705 
       
   706 void CEirManager::TryToUpdateHostController()
       
   707 	{
       
   708 	// In case there is an outstanding write eir command (a timer running) already, Cancel()
       
   709 	iWriteEirTimer->Cancel();
       
   710 	
       
   711 	// Start the timer to gurad against from clients' updates flooding the controller
       
   712 	iWriteEirTimer->Start();
       
   713 	}
       
   714 
       
   715 
       
   716 CWriteEirTimer* CWriteEirTimer::NewL(CEirManager& aEirManager)
       
   717 	{
       
   718 	CWriteEirTimer* timer = new (ELeave) CWriteEirTimer(aEirManager);
       
   719 	CleanupStack::PushL(timer);
       
   720 	timer->ConstructL();
       
   721 	CleanupStack::Pop(timer);
       
   722 	return timer;
       
   723 	}
       
   724 
       
   725 
       
   726 CWriteEirTimer::CWriteEirTimer(CEirManager& aEirManager)
       
   727 : CTimer(EPriorityStandard), iEirManager(aEirManager)
       
   728 	{
       
   729 	}
       
   730 
       
   731 void CWriteEirTimer::Start()
       
   732 	{
       
   733 	After(KWriteEirTimeout);
       
   734 	}
       
   735 
       
   736 void CWriteEirTimer::ConstructL()
       
   737 	{
       
   738 	CTimer::ConstructL();
       
   739 	CActiveScheduler::Add(this);
       
   740 	}
       
   741 
       
   742 void CWriteEirTimer::RunL()
       
   743 	{
       
   744 	// timer expires, which means no more write eir request within life of the time (1 second)
       
   745 	// write eir here now
       
   746 	iEirManager.UpdateHostControllerL();
       
   747 	}
       
   748 
       
   749 TInt CWriteEirTimer::RunError(TInt IF_FLOGGING(aError))
       
   750 	{
       
   751 	LOG_FUNC
       
   752 	// The only reason the error occurs is that the WriteExtendedInquiryResponseL has failed
       
   753 	// This may be caused by invalid EIR data, we'll do nothing here.
       
   754 	LOG1(_L("CWriteEirTimer::RunError() %d: "), aError);
       
   755 	return KErrNone;
       
   756 	}