/****************************************************************************
NAME    
    hfpHandleCmerAtAck

DESCRIPTION
    Called when we receive OK/ ERROR in response to the AT+CMER cmd. If we're
    not getting call hold params from the AG then the SLC is complete.

RETURNS
    void
*/
void hfpHandleCmerAtAck(hfp_link_data* link, hfp_lib_status status)
{
    if (hfpSlcCheckAtAck(link, status))
    {
        /* If TWC not enabled this is the last AT command in the SLC establishment */
        if (!hfFeatureEnabled(HFP_THREE_WAY_CALLING) || !agFeatureEnabled(link, AG_THREE_WAY_CALLING))
            hfpSendSlcConnectCfmToApp(link, NULL, hfp_connect_success);
    }
}
/****************************************************************************
NAME	
	hfpHandleRfcommConnectCfm

DESCRIPTION
	Outcome of the RFCOMM connect request or response.

RETURNS
	void
*/
void hfpHandleRfcommConnectCfm(HFP *hfp, const CL_RFCOMM_CONNECT_CFM_T *cfm)
{
    /* Check the status of the rfcomm connect cfm */
    if (cfm->status == rfcomm_connect_success)
    {
		/* Store the sink */
		hfp->sink = cfm->sink;

        /* RFCOMM connection is up! Check which profile is supported by this task */
        if (supportedProfileIsHsp(hfp->hfpSupportedProfile))
        {
	        hfp->agSupportedProfile = hfp_headset_profile;
	        
            /* HSP supported - SLC is up so tell the app */
            hfpSendSlcConnectCfmToApp(hfp_connect_success, hfp);
        }
        else if (supportedProfileIsHfp(hfp->hfpSupportedProfile))
        {
            /* Initiate SLC establishment */
			MessageSend(&hfp->task, HFP_INTERNAL_AT_BRSF_REQ, 0);
        }
        else
        {
            /* This should never happen */
            HFP_DEBUG(("Unhandled profile type 0x%x\n", hfp->hfpSupportedProfile));
        }

		/* Check for data in the buffer */
		hfpHandleReceivedData(hfp, StreamSourceFromSink(cfm->sink));
    }
    else
    {
        /* RFCOMM connect failed - Tell the app. */
        hfpSendSlcConnectCfmToApp(convertRfcommConnectStatus(cfm->status), hfp);
    }
	
	/* Free the rfcomm lock */
	hfp->rfcomm_lock = FALSE;
}
/****************************************************************************
NAME	
	hfpHandleRfcommDisconnectInd

DESCRIPTION
	Indication that the RFCOMM connection has been disconnected.

RETURNS
	void
*/
void hfpHandleRfcommDisconnectInd(HFP *hfp, const CL_RFCOMM_DISCONNECT_IND_T *ind)
{
	if (hfp->state == hfpSlcConnecting)
	{   /* Rfcomm connection has been shutdown during the SLC connection process */
    	/* Cancel the AT response timeout message because we'll have no more AT cmds being sent */
    	(void) MessageCancelAll(&hfp->task, HFP_INTERNAL_WAIT_AT_TIMEOUT_IND);
    	
	    /* Report a failed connect attempt to app */
		hfpSendSlcConnectCfmToApp(hfp_connect_slc_failed, hfp);
	}
	else
	{   /* Convert the rfc disconnect status into its hfp counterpart and inform library */
    	MAKE_HFP_MESSAGE(HFP_INTERNAL_SLC_DISCONNECT_IND);
    	message->status = convertRfcommDisconnectStatus(ind->status);
    	MessageSend(&hfp->task, HFP_INTERNAL_SLC_DISCONNECT_IND, message);
    }
}
/****************************************************************************
NAME
    hfpHandleDisconnectRequest

DESCRIPTION
    We're in the right state and have received a disconnect request, 
    handle it here.

RETURNS
    void
*/
void hfpHandleDisconnectRequest(hfp_link_data* link)
{
    if (link->audio_sink)
    {
        MAKE_HFP_MESSAGE(HFP_INTERNAL_SLC_DISCONNECT_REQ);
        message->link = link;
        /* If we have a SCO/eSCO active need to tear that down first */
        hfpHandleAudioDisconnectReq(link);
        /* Queue up the SLC disconnect message */
        MessageSendConditionally(&theHfp->task, HFP_INTERNAL_SLC_DISCONNECT_REQ, message, (uint16 *) &link->audio_sink);    /*lint !e740 */
    }
    else 
    {
        /* If recovering from link loss or timed out we need to be sure to force disconnect */
        if (link->ag_link_loss_state == hfp_link_loss_recovery || link->ag_link_loss_state == hfp_link_loss_timeout)
        {
            /* Link was recovering from link loss, stop the procedure */
            MessageId message_id = hfpGetLinkTimeoutMessage(link, HFP_RFCOMM_LINK_LOSS_TIMEOUT_LINK_0_IND);
            MessageCancelFirst(&theHfp->task, message_id);
            hfpHandleRfcommLinkLossAbort(link, TRUE);
        }
        /* Either no link loss or we aborted link loss recovery. Now bring down the link. */
        else
        {
            /* Can only get here from searching/outgoing/incoming/connected/complete */
            if(link->ag_slc_state == hfp_slc_searching)
            {
                /* Notify application of connection failure (link will be reset so SDP results ignored) */
                hfpSendSlcConnectCfmToApp(link, NULL, hfp_connect_sdp_fail);
            }
            else
            {
                /* Request the connection lib aborts/disconnects the RFCOMM connection */
                ConnectionRfcommDisconnectRequest(&theHfp->task, hfpGetLinkSink(link));
            }
        }
    }
}
Exemple #5
0
/* Helper function to try an HSP search if HFP failed */
static void hfpSdpRetry(hfp_link_data* link)
{
    hfp_service_data* service;
    
    /* Mask out the profile that just failed */
    link->ag_profiles_to_try &= ~link->service->profile;
    /* Get whichever profile is left to try */
    service = hfpGetServiceFromProfile(link->ag_profiles_to_try);
    
    if(service)
    {
        bdaddr bd_addr;
        /* Ignore the result, link must have a bd_addr */
        (void)hfpGetLinkBdaddr(link, &bd_addr);
        
        /* Try the next service... */
        hfpGetProfileServerChannel(link, service, &bd_addr);
        return;
    }
    
    /* Nothing more to do, SLC has failed */
    hfpSendSlcConnectCfmToApp(link, NULL, hfp_connect_sdp_fail);
}
Exemple #6
0
/****************************************************************************
NAME    
    hfpHandleServiceSearchAttributeCfm

DESCRIPTION
    Service search has completed, check it has succeeded and get the required
    attrubutes from the returned list.

RETURNS
    void
*/
void hfpHandleServiceSearchAttributeCfm(const CL_SDP_SERVICE_SEARCH_ATTRIBUTE_CFM_T *cfm)
{
    /* Get the link from the bdaddr */
    hfp_link_data* link = hfpGetLinkFromBdaddr(&cfm->bd_addr);
    
    /* The link may have been pulled from under us by an early
    disconnect request. If this has happened ignore SDP result */
    if(link)
    {
        /* Check the outcome of the service search */
        if (cfm->status == sdp_response_success)
        {
            uint16 sdp_data  =  0;
            
            if(link->ag_slc_state == hfp_slc_searching)
            {
                if (getRfcommChannelNumber(cfm->attributes, cfm->attributes+cfm->size_attributes, &sdp_data))
                {
                    /* We have an rfcomm channel we can proceed with the connection establishment */
                    hfpSetLinkSlcState(link, hfp_slc_outgoing);
                    /* Use the local channel to specify the security requirements for this connection */
                    ConnectionRfcommConnectRequest(&theHfp->task, &cfm->bd_addr, link->service->rfc_server_channel, sdp_data, 0);
                }
                else
                {
                    /* Received unexpected data.  Should never happen since we're issuing the search and should 
                       know what we're looking.  However, if it does, treat as SDP failure.   */
                    hfpSdpRetry(link);
                }
            }
            else if(link->ag_slc_state == hfp_slc_connected)
            {
                /* If SLC is up then this must be a features request */
                if (getHfpAgSupportedFeatures(cfm->attributes, cfm->attributes+cfm->size_attributes, &sdp_data))
                {    /* Send an internal message with the supported features. */
                    hfpHandleSupportedFeaturesNotification(link, sdp_data);
                }
                /*
                else
                {
                    Received unexpected data.  Should never happen since we're issuing the search and should 
                    know what we're looking.  However, if it does, just ignore since SLC setup is already 
                    being continued.
                }
                */
            }
        }
        else
        {
            /* RFCOMM channel search failed, tell the application */
            if(link->ag_slc_state == hfp_slc_searching)
            {
                if (cfm->status == sdp_no_response_data)
                {
                    /* Retry next profile if possible... */
                    hfpSdpRetry(link);
                }
                else
                {
                    /* Generic fail by default */
                    hfp_connect_status status = hfp_connect_failed;
                    
                    /* Was it a page timeout? */
                    if (cfm->status == sdp_connection_error)
                        status = hfp_connect_timeout;
                    
                    /* Tell the app */
                    hfpSendSlcConnectCfmToApp(link, NULL, status);
                }
            }
        }
    }
}
/****************************************************************************
NAME    
hfpHandleCallHoldSupportInd

DESCRIPTION
    Call hold parameters received and parsed. 

RETURNS
    void
*/
static void hfpHandleCallHoldSupportInd(Task link_ptr)
{
    hfp_link_data* link = (hfp_link_data*)link_ptr;
    /* Inform the app the SLC has been established */
    hfpSendSlcConnectCfmToApp(link, NULL, hfp_connect_success);
}
/****************************************************************************
NAME	
	hfpHandleServiceSearchAttributeCfm

DESCRIPTION
	Service search has completed, check it has succeeded and get the required
	attrubutes from the returned list.

RETURNS
	void
*/
void hfpHandleServiceSearchAttributeCfm(HFP *hfp, const CL_SDP_SERVICE_SEARCH_ATTRIBUTE_CFM_T *cfm)
{
	/* Check the outcome of the service search */
	if (cfm->status == sdp_response_success)
	{		
		uint16 sdp_data = 0;

		switch ( hfp->sdp_search_mode )
		{
		case hfp_sdp_search_rfcomm_channel:
			if (getRfcommChannelNumber(cfm->attributes, cfm->attributes+cfm->size_attributes, &sdp_data))
			{	/* We have an rfcomm channel we can proceed with the connection establishment */
			
				HFP_INTERNAL_RFCOMM_CONNECT_REQ_T message ;
				message.addr = cfm->bd_addr;
				message.rfc_channel = sdp_data;
					
				if (hfp->state == hfpSlcConnecting)
					hfpHandleRfcommConnectRequest(hfp, &message);
			
			}
			else
			{
				/* Received unexpected data.  Should never happen since we're issuing the search and should 
			       know what we're looking.  However, if it does, assume a failure has occurred as below.   */
			       
				/* Tell the app the connection attempt has failed. */
			    hfpSendSlcConnectCfmToApp(hfp_connect_sdp_fail, hfp);
			}
			break;
		case hfp_sdp_search_profile_version:
			
			if (getHfpAgProfileVersion(cfm->attributes, cfm->attributes+cfm->size_attributes, &sdp_data))
			{	/* Obtained version of HFP running on AG */
				hfp->agSupportedProfile = (hfp_profile)sdp_data;
				
				if( supportedProfileIsHfp15(hfp->agSupportedProfile) )
				{
					hfpSendRemoteAGProfileVerIndToApp(hfp->agSupportedProfile, hfp);
				}
			}
			else
			{
				/* Received unexpected data.  Should never happen since we're issuing the search and should 
			       know what we're looking.  However, if it does, assume a failure has occurred as below.   */

				/* Incorrect response from AG, so assume it's running HFP v1.0 */
				hfp->agSupportedProfile = hfp_handsfree_profile;
			}
			
			break;
		case hfp_sdp_search_supported_features:
			if (getHfpAgSupportedFeatures(cfm->attributes, cfm->attributes+cfm->size_attributes, &sdp_data))
			{	/* Send an internal message with the supported features. */
				hfpHandleSupportedFeaturesNotification(hfp, sdp_data);
			}
			else
			{
				/* Received unexpected data.  Should never happen since we're issuing the search and should 
			       know what we're looking.  However, if it does, just ignore since SLC setup is already 
			       being continued.                                                                         */
			}
			break;
		default:
			/* 
				else ... We have received data we don't know what to do with.
				This shouldn't happen since we're issuing the search and should 
				know what we're looking for so for the moment just ignore.
			*/
			break;
		}
	}
	else
	{
		switch ( hfp->sdp_search_mode )
		{
		case hfp_sdp_search_rfcomm_channel:
			/* A RFCOMM connection will not exist at this point */
            if (cfm->status == sdp_no_response_data)
			{	/* Tell the app the connection attempt has failed. */
			    hfpSendSlcConnectCfmToApp(hfp_connect_sdp_fail, hfp);
		    }
            else if (cfm->status == sdp_connection_error)
            {	/* If it was a page timeout the client would like to know */
                hfpSendSlcConnectCfmToApp(hfp_connect_timeout, hfp);
            }
            else
            {	/* All other sdp fails */
                hfpSendSlcConnectCfmToApp(hfp_connect_failed, hfp);
            }
			break;
		case hfp_sdp_search_profile_version:
			/* No response from AG, so assume it's running HFP v1.0 */
			hfp->agSupportedProfile = hfp_handsfree_profile;
			break;
		case hfp_sdp_search_supported_features:
			/* Just ignore.  SLC setup is already being continued */
			break;
		default:
			/* 
				else ... We have received data we don't know what to do with.
				This shouldn't happen since we're issuing the search and should 
				know what we're looking for so for the moment just ignore.
			*/
			break;
		}
	}
	
	
	/* Reset sdp search mode */
	hfp->sdp_search_mode = hfp_sdp_search_none;
}