bluetooth/btstack/linkmgr/linkmuxer.cpp
changeset 0 29b1cd4cb562
child 22 9f17f914e828
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // HCIChannelMux.cpp
       
    15 // HCI Channel Multiplexer implementation. 
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <bluetooth/logger.h>
       
    20 #include <bluetooth/hcicommandqueue.h>
       
    21 #include "linkmuxer.h"
       
    22 #include "AclDataQController.h"
       
    23 #include "linkconsts.h"
       
    24 #include "hcifacade.h"
       
    25 
       
    26 #ifdef __FLOG_ACTIVE
       
    27 _LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
       
    28 #endif
       
    29 
       
    30 CLinkMuxer* CLinkMuxer::NewL(CLinkMgrProtocol& aLinkMgrProtocol, CHCIFacade& aHCIFacade)
       
    31 	{
       
    32 	LOG_STATIC_FUNC
       
    33 	CLinkMuxer* self = new (ELeave) CLinkMuxer(aLinkMgrProtocol, aHCIFacade);
       
    34 	CleanupStack::PushL(self);
       
    35 	self->ConstructL();
       
    36 	CleanupStack::Pop();
       
    37 	return self;
       
    38 	}
       
    39 
       
    40 void CLinkMuxer::ConstructL()
       
    41 	{
       
    42 	LOG_FUNC
       
    43 	// Get pointer to CommandQ
       
    44 	iCommandController = &iHCIFacade.CommandQController();
       
    45 
       
    46 #ifdef PROXY_COMMUNICATES
       
    47 	const TUint16 noBufs = iHCIFacade.ReadACLReportingInterval();
       
    48 #else
       
    49 	const TUint16 noBufs = ++iHCIFacade.ReadACLReportingInterval(); // another slot for bc handle
       
    50 #endif
       
    51 	const TUint16 framingOverhead = iHCIFacade.ReadACLFramingOverhead();
       
    52 
       
    53 	iDataController= CACLDataQController::NewL(iLinkMgrProtocol, 
       
    54 			                                   *this,
       
    55 											   KHCIACLMinDataBufferSize,
       
    56 											   framingOverhead,
       
    57 			                                   noBufs);
       
    58 
       
    59 	// Tell the limited data Q controller our data credits from HC is 0 
       
    60 	// when we establish how many HC really has we will notify again
       
    61 	// that will happen on the reception of the first ReadBufferSize result
       
    62 	iDataController->InitialDataCredits(0);
       
    63 
       
    64 	iChannelsFree = iHCIFacade.HCTLState();
       
    65 
       
    66 	TCallBack cb(TryToSendCallBackStatic, this);
       
    67 	iSendCallBack = new (ELeave)CAsyncCallBack(cb, EActiveMedPriority);
       
    68 	}
       
    69 
       
    70 CLinkMuxer::CLinkMuxer(CLinkMgrProtocol& aLinkMgrProtocol, CHCIFacade& aHCIFacade)
       
    71 	: iHCIFacade(aHCIFacade), iChannelsFree(KHCITransportNoChannels), iLinkMgrProtocol(aLinkMgrProtocol) 
       
    72 /**
       
    73 	We expect the transport to notify us when the transport channels are ready
       
    74 **/
       
    75 	{
       
    76 	LOG_FUNC
       
    77 	}
       
    78 
       
    79 CLinkMuxer::~CLinkMuxer()
       
    80 	{
       
    81 	LOG_FUNC
       
    82     delete iSendCallBack;
       
    83 	delete iDataController;
       
    84 	}
       
    85 
       
    86 TInt CLinkMuxer::ACLPacketMTU() const
       
    87 	{
       
    88 	LOG_FUNC
       
    89 	__ASSERT_DEBUG(iACLPacketMTU, Panic(ELinkMgrPacketMTUUseBeforeSet));
       
    90 	return iACLPacketMTU;
       
    91 	}
       
    92 
       
    93 
       
    94 TInt CLinkMuxer::TryToSendCallBackStatic(TAny* aCLinkMuxer)
       
    95 	{
       
    96 	LOG_STATIC_FUNC
       
    97 	static_cast<CLinkMuxer*>(aCLinkMuxer)->DoSend();
       
    98 	return EFalse;
       
    99 	}
       
   100 
       
   101 void CLinkMuxer::TryToSend()
       
   102 	{
       
   103 	LOG_FUNC
       
   104 	// fireup async callback
       
   105 	iSendCallBack->CallBack();
       
   106 	}
       
   107 
       
   108 void CLinkMuxer::DoSend()
       
   109 /**
       
   110 	This is the method where it is decided whether a command or data packet will be issued next.
       
   111 	A send may not occur - the signal to send may have occurred through the addition to a Q
       
   112 	whereas the destination channel for the relevant packet may not be free
       
   113 
       
   114 	There could have been a 'Strategy' pattern here, for applying different
       
   115 	scheduling in the future. The likely hood of this is very low, hence the 
       
   116 	simpler implementation.
       
   117 
       
   118 	The scheduling is very simple:
       
   119 	If we have command packets to send and credits to do so ,send one
       
   120 	otherwise send a data packet if possible/available.
       
   121 */
       
   122 	{
       
   123 	LOG_FUNC
       
   124 	LOG1(_L("LinkMuxer: Dosend- free channels 0x%04x"), iChannelsFree);
       
   125 
       
   126 	if (!iChannelsFree)
       
   127 		return;  // no channel to send on available
       
   128 
       
   129 	TUint   theDataQLevel=0;
       
   130 	TUint16 theDataCredits=0;
       
   131 
       
   132 	iDataController->GetDataQRecords(theDataQLevel,theDataCredits);
       
   133 	
       
   134 	// the assumption here is that a channel is free
       
   135 	// note the implicit precedence of commands over data
       
   136 	
       
   137 	if (iChannelsFree & KHCITransportCommandChannel)
       
   138 		{
       
   139 		// have commands and command channel is free
       
   140 		iCommandController->DoSend();
       
   141 		}
       
   142 
       
   143 	if((iChannelsFree & KHCITransportACLDataChannel)
       
   144 		&& theDataQLevel && theDataCredits)
       
   145 		{
       
   146 		// have data, and credits, and data channel is free, try to send some data
       
   147 		iDataController->IssueNextACLDataFragment(); // may or may not issue!
       
   148 		}
       
   149 	}
       
   150 
       
   151 
       
   152 /**
       
   153 	When channels become free this method gets called to tell the muxer
       
   154 	The muxer takes the opportunity to attempt a send
       
   155 */
       
   156 
       
   157 void CLinkMuxer::ChannelsFree(THCITransportChannel aChannel)
       
   158 	{
       
   159 	LOG_FUNC
       
   160 	iChannelsFree |= aChannel;
       
   161 
       
   162 	if (iChannelsFree != KHCITransportNoChannels)
       
   163 		{
       
   164 		// only call async callback - don't call synchronous
       
   165 		TryToSend();
       
   166 		}
       
   167 	}
       
   168 /**
       
   169 	When channels become closed this method is called to remove them
       
   170 	from the "free" list.
       
   171 	
       
   172 	Note: The channels that require closing have their respective bits set
       
   173 		hence the reason for the bit inversion within this method.
       
   174 */
       
   175 
       
   176 void CLinkMuxer::ChannelsClosed(THCITransportChannel aChannel)
       
   177 	{
       
   178 	LOG_FUNC
       
   179 	iChannelsFree &= (~aChannel);
       
   180 	iChannelsFree &= KHCITransportAllChannels;
       
   181 	}
       
   182 
       
   183 
       
   184 #ifdef STACK_SCO_DATA
       
   185 TBool CLinkMuxer::CanWriteSCOData()
       
   186 	{
       
   187 	LOG_FUNC
       
   188 	return (iChannelsFree & KHCITransportSCODataChannel);
       
   189 	}
       
   190 #endif
       
   191 
       
   192 void CLinkMuxer::RecordHostControllerToHostFlowControl(TBool aFlowFlag)
       
   193 /**
       
   194 	Called when HCIFacade receives a Command Complete event to the SetHostControllerToHostFlowControl command
       
   195 	@param	aFlowFlag - true is command succeeded, false otherwise
       
   196 
       
   197 **/
       
   198     {
       
   199 	LOG_FUNC
       
   200      // check our current mode
       
   201     switch (iFlowControlMode)
       
   202         {
       
   203         case ENoFlowControl:
       
   204             {
       
   205 #ifdef _DEBUG
       
   206             if(aFlowFlag) 
       
   207                 {iFlowControlMode=EFlowControlFromHostControllerOnly;}
       
   208 #else
       
   209             Panic(ELinkMgrNoFlowControlSetInReleaseBuild);
       
   210 #endif
       
   211             break;
       
   212         }
       
   213         case EFlowControlToHostControllerOnly:
       
   214             {
       
   215             if(aFlowFlag)
       
   216                 {iFlowControlMode=ETwoWayFlowControlEnabled;}
       
   217             break;
       
   218             }
       
   219         case EFlowControlFromHostControllerOnly:
       
   220             {
       
   221 #ifdef _DEBUG
       
   222             if(aFlowFlag==EFalse)
       
   223                 {iFlowControlMode=ENoFlowControl;}
       
   224 #else
       
   225             Panic(ELinkMgrNoFlowControlSetInReleaseBuild);
       
   226 #endif
       
   227             break;
       
   228             }
       
   229         case ETwoWayFlowControlEnabled:
       
   230             {
       
   231             if(aFlowFlag==EFalse)
       
   232 				{
       
   233 				// tried to do two-way but the HC can't to HC->H FC
       
   234 				iFlowControlMode=EFlowControlToHostControllerOnly;
       
   235 				}
       
   236             break;
       
   237             }
       
   238 		default:
       
   239 			Panic(ELinkMgrNoSuchFlowControlMode);
       
   240         } //switch
       
   241 	}    
       
   242 
       
   243 
       
   244 CACLDataQController* CLinkMuxer::HandleLocalReadBufferSizeResult(
       
   245 			TUint16 aAclMaxLen,
       
   246 			TUint8 /*aScoMaxLen*/,
       
   247 			TUint16 aNoACL,
       
   248 			TUint16 /*aNoSCO*/)
       
   249 /**
       
   250 	This method handles the results of the local (intra HCI) inquiry of the HC 
       
   251 	buffer capabilities.
       
   252 	The results are then used for setting the HCI MTU (=HC MTU) and for 
       
   253 	modeling the HC's pool usage.
       
   254 	This method must be called very early upon start-up in order to set up the 
       
   255 	data Q and its controller, for the flow control between L2CAP -> HCI -> 
       
   256 	HC. 
       
   257 
       
   258 	@param aAclMaxLen Maximum length of each ACLDataPacket.
       
   259 	@param aScoMaxLen Maximum length of each SCODataPacket.
       
   260 	@param aNoACL Total no. of ACL Data Packets.
       
   261 	@param aNoSCO Total no. of SCO Data Packets.
       
   262 	@return Return address (not ownership) of new/same ACL Data Controller.
       
   263 */
       
   264     {
       
   265 	LOG_FUNC
       
   266 	LOG2(_L("CLinkMuxer::HandleLocalReadBufferSizeResult aAclMaxLen = %d, aNoACL = %d"), 
       
   267 		aAclMaxLen, aNoACL);
       
   268 
       
   269 	const TUint preferredNumBuffers = Max(
       
   270 			static_cast<TInt>(KHCIPreferedNumberOfHCIACLDataBuffers),
       
   271 			static_cast<TInt>(aNoACL)
       
   272 			);
       
   273 
       
   274 	// If the HC supports more buffers than we already allocated (in 
       
   275 	// ConstructL) then make a new (bigger!) Q controller. NB This may fail, 
       
   276 	// in which case just go with the earlier one- we always return from this 
       
   277 	// (non-leaving) function leaving behind a valid iDataController.
       
   278 	TUint16 bufSize;
       
   279 	TUint numBufs;
       
   280 	iDataController->GetBufferInfo(bufSize, numBufs);
       
   281 	if ( preferredNumBuffers >= numBufs )
       
   282 		{
       
   283 		const TUint16 framingOverhead = iHCIFacade.ReadACLFramingOverhead();
       
   284 
       
   285 		CACLDataQController* tmpDataQController = NULL;
       
   286 		TRAP_IGNORE(tmpDataQController = 
       
   287  					CACLDataQController::NewL(iLinkMgrProtocol,
       
   288 									*this, 
       
   289 									aAclMaxLen,
       
   290 									framingOverhead,
       
   291 									preferredNumBuffers));
       
   292 		if ( tmpDataQController )
       
   293 			{
       
   294 			delete iDataController;
       
   295 			iDataController = tmpDataQController;
       
   296 			}
       
   297 		}
       
   298 
       
   299 	// Tell the data Q controller our HC data credits 
       
   300 	iDataController->InitialDataCredits(aNoACL); 
       
   301 
       
   302 	iDataController->GetBufferInfo(bufSize, numBufs);
       
   303 	iACLPacketMTU = bufSize;
       
   304  	__ASSERT_DEBUG(numBufs >= iHCIFacade.ReadACLReportingInterval(), 
       
   305 		Panic(ELinkMgrDataQBufferIsNotSufficient));
       
   306 
       
   307 	LOG1(_L("CLinkMuxer::HandleLocalReadBufferSizeResult iDataController = 0x%08x"), 
       
   308 		iDataController);
       
   309 
       
   310 	return iDataController;
       
   311 	}
       
   312 
       
   313 //
       
   314 // End of file