/*
	Handle CSR Supported Features request.
*/
void hfpHandleCsrSupportedFeaturesReq(HFP *hfp, HFP_INTERNAL_CSR_SUPPORTED_FEATURES_REQ_T *msg)
{
	switch (hfp->state)
	{
	case hfpInitialising:
	case hfpReady:
	case hfpSlcConnecting:
		/* SLC not connected, return an error */
		hfpSendCsrSupportedFeaturesCfm(hfp, hfp_csr_no_slc, FALSE, FALSE, FALSE, FALSE, FALSE , 0 );
		break;
	case hfpSlcConnected:
	case hfpIncomingCallEstablish:
	case hfpOutgoingCallEstablish:
	case hfpOutgoingCallAlerting:
	case hfpActiveCall:
		{
			/* SLC connected, send the command */
			char cmd[22];
				
			/* Create the AT cmd we're sending */
			sprintf(cmd, "AT+CSRSF=%d,%d,%d,%d,%d,%d\r", (msg->callerName?1:0), (msg->rawText?1:0),
										(msg->smsInd?1:0), (msg->battLevel?1:0), (msg->pwrSource?1:0) , msg->codecs);
										
		
			/* Send the AT cmd over the air */
			hfpSendAtCmd(&hfp->task, strlen(cmd), cmd);
          	hfp->use_csr2csr = TRUE;
            
			break;
		}
	default:
		HFP_DEBUG(("Unknown State [0x%x]\n", hfp->state));
		break;
	}
}
/*
	Handle internal Disable Indicators
*/
void hfpCsrMofifyIndicatorsDisableReq(HFP *hfp)
{
	switch (hfp->state)
	{
	case hfpInitialising:
	case hfpReady:
	case hfpSlcConnecting:
		/* SLC not connected, return an error */
		hfpSendCsrModifyIndicatorsCfm(hfp, hfp_csr_no_slc);
		break;
	case hfpSlcConnected:
	case hfpIncomingCallEstablish:
	case hfpOutgoingCallEstablish:
	case hfpOutgoingCallAlerting:
	case hfpActiveCall:
		{
			/* SLC connected, send the command */
			char cmd[20];
				
			/* Create the AT cmd we're sending */
			sprintf(cmd, "AT+CSR=0\r");
		
			/* Send the AT cmd over the air */
			hfpSendAtCmd(&hfp->task, strlen(cmd), cmd);
			break;
		}
	default:
		HFP_DEBUG(("Unknown State [0x%x]\n", hfp->state));
		break;
	}
}
/****************************************************************************
NAME    
    hfpHandlerThreeWayCallInd

DESCRIPTION
    Handles HFP_CALL_IND_T message from HFP library during threeway calling
    scenario

*/
void hfpHandlerThreeWayCallInd ( const HFP_CALL_IND_T *ind )
{
    headsetHfpState state = stateManagerGetHfpState();

    HFP_DEBUG(("Handling CallInd[%d] in threeway calling state[%d]\n", ind->call, state));

    switch (ind->call)
    {
        case 0: /* not in a call */
        {
            /* last call in the conference has hung up on us go to connected ||
               last call hung up after we were handling held calls */
            if (state == headsetTWCMulticall || state == headsetTWCOnHold)
            {
                stateManagerEnterHfpConnectedState();
            }
            /* callInd:0 in headsetTWCWaiting means active call has ended
               go to incoming as AG will be ringing us now with call that was waiting */
            else if (state == headsetTWCWaiting)
            {
                stateManagerEnterIncomingCallEstablishState();
            }
            break;
        }
        case 1:
            break;
        default:
        break;
    }
}
void hfpHandlerRingInd ( void )
{
	/* Disconnect A2DP audio if it is streaming from a standalone A2DP source */
	if (!IsA2dpSourceAnAg())
		streamControlCeaseA2dpStreaming(TRUE);
	
    if ( !theHeadset.InBandRingEnabled )
    {
    	HFP_DEBUG(("HFP_DEBUG: OutBandRing\n")) ;
		
        /* Play ring tone from configuration */
    }    
	
	if ( (theHeadset.profile_connected == hfp_headset_profile) && !theHeadset.HSPCallAnswered )
    {
		/* If using HSP then use ring indication as incoming call */
		theHeadset.HSPIncomingCallInd = TRUE;
       
        stateManagerEnterIncomingCallEstablishState() ;
       
        MessageCancelAll ( &theHeadset.task , APP_CANCEL_HSP_INCOMING_CALL ) ;
        MessageSendLater ( &theHeadset.task , APP_CANCEL_HSP_INCOMING_CALL , 0 , D_SEC(6) ) ;
    }
    
}
/*
	Handle internal Get SMS request.
*/
void hfpHandleCsrGetSmsReq(HFP *hfp, HFP_INTERNAL_CSR_GET_SMS_REQ_T *msg)
{
	switch (hfp->state)
	{
	case hfpInitialising:
	case hfpReady:
	case hfpSlcConnecting:
		/* SLC not connected, return an error */
		hfpSendCsrSmsCfm(hfp, hfp_csr_no_slc, 0, NULL);
		break;
	case hfpSlcConnected:
	case hfpIncomingCallEstablish:
	case hfpOutgoingCallEstablish:
	case hfpOutgoingCallAlerting:
	case hfpActiveCall:
		{
			/* SLC connected, send the command */
			char cmd[20];
				
			/* Create the AT cmd we're sending */
			sprintf(cmd, "AT+CSRGETSMS=%d\r", msg->index);
		
			/* Send the AT cmd over the air */
			hfpSendAtCmd(&hfp->task, strlen(cmd), cmd);
			break;
		}
	default:
		HFP_DEBUG(("Unknown State [0x%x]\n", hfp->state));
		break;
	}
}
/****************************************************************************
NAME    
    hfpHandleSetActiveIndicatorsReq

DESCRIPTION
    Handle request to set active indicators from the app

AT INDICATION
    +BIA=

RETURNS
    void
*/
void hfpHandleSetActiveIndicatorsReq(hfp_link_data* link)
{
    if(hfpLinkIsHfp106(link))
    {
        static const char atCmd[] = {'A','T','+','B','I','A','='};
        static const char atCmdSeparator[] = {'0',','};
        static const char atEnd[] = {'0','\r','\0'};
        
        /* 'AT+BIA=' takes 7 chars, two chars for each indicator plus one more for '\0' */
        uint16 size_bia = sizeof(atCmd) + (link->ag_supported_indicators.num_indicators * sizeof(atCmdSeparator)) + 1;
        char *bia;
        char *p;
        
        bia = (char*)malloc(size_bia * sizeof(char));
        
        if(bia)
        {
            uint16 i;
            /* Add "AT+BIA=" */
            memmove(bia, atCmd, sizeof(atCmd));
            /* Fill in default value for all indicators "0,"*/
            for(p = bia + sizeof(atCmd); p < bia + size_bia - sizeof(atEnd); p += sizeof(atCmdSeparator))
                memmove(p, atCmdSeparator, sizeof(atCmdSeparator));
            /* Add "0\r\0" */
            memmove(p, atEnd, sizeof(atEnd));
            
            /* set p to point to the first indicator position in the command */
            p = bia + sizeof(atCmd);
            
            /* If app requested to turn indicators off/on update the message with char '0' or '1' */
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.service,         theHfp->optional_indicators.service        );
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.signal_strength, theHfp->optional_indicators.signal_strength);
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.roaming_status,  theHfp->optional_indicators.roaming_status );
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.battery_charge,  theHfp->optional_indicators.battery_charge );
            
            /* Make sure mandatory indicators are all on */
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.call,             hfp_indicator_on);
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.call_setup,       hfp_indicator_on);
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.call_hold_status, hfp_indicator_on);
            hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.indicator_idxs.extra_call_setup, hfp_indicator_on);
            
            /* Make sure any extra indicators the app cares about are on */
            for(i=0; i < link->ag_supported_indicators.num_extra_indicator_idxs; i++)
                hfpUpdateIndicatorsCommand(p, link->ag_supported_indicators.extra_indicator_idxs[i], hfp_indicator_on);
            
            /* Send the command */
            hfpSendAtCmd(link, strlen(bia), bia, hfpBiaCmdPending);
            free(bia);
        }
        else
        {
            HFP_DEBUG(("BIA malloc failed\n")) ;
        }
    }
    else
    {
        /* Skip on the CMEE */
        hfpSendCommonInternalMessage(HFP_INTERNAL_AT_CMEE_REQ, link);
    }
}
void hfpHandleFeatureNegotiationRes ( HFP * hfp , HFP_INTERNAL_CSR_FEATURE_NEGOTIATION_RES_T * msg )
{
    static const char atCmd[] = {'A','T','+','C','S','R','F','N','=','('};
	static const char atEnd[] = {')','\r'};
	char *atStr;
	uint16 atLen = sizeof(atCmd) + sizeof(atEnd) + 3 ; /*one for the indicator, 1 for the comma, 1 for the value*/ 
	
	atStr = (char*)malloc(atLen);
	
	if (atStr)
	{
		uint16 used = sizeof(atCmd);
		memmove(atStr, atCmd, sizeof(atCmd));
		
        
        used += sprintf(&atStr[used], "%d", msg->indicator);
	
    	atStr[used] = ',';
		used++;
	
    	used += sprintf(&atStr[used], "%d", msg->value);
	
    	memmove(&atStr[used], atEnd, sizeof(atEnd));
		
		used+= sizeof(atEnd) ;

		hfpSendAtCmd(&hfp->task, used, atStr);		
		free(atStr);
	}
	else
	{
	   HFP_DEBUG(("malloc failed\n")) ;
	}
}
/****************************************************************************
NAME    
    handleUnexpected    

DESCRIPTION
    This function is called as a result of a message arriving when this
    library was not expecting it.

RETURNS
    void    
*/
static void handleUnexpected(hfpUnexpectedReasonCode code, uint16 type)
{
    type = type;
    code = code;

    HFP_DEBUG(("theHfp handleUnexpected - Code 0x%x MsgId 0x%x\n", code, type));
}
/* Convert from the rfcomm_connect_status returned by the connection lib. */
static hfp_connect_status convertRfcommConnectStatus(rfcomm_connect_status status)
{
    switch (status)
    {
    case rfcomm_connect_success:
        return hfp_connect_success;

    case rfcomm_connect_failed:
        return hfp_connect_failed;

    case rfcomm_server_channel_not_registered:
        return hfp_connect_server_channel_not_registered;

    case rfcomm_connect_timeout:
        return hfp_connect_timeout;

    case rfcomm_connect_rejected:
        return hfp_connect_rejected;

    case rfcomm_normal_disconnect:
        return hfp_connect_normal_disconnect;

    case rfcomm_abnormal_disconnect:
        return hfp_connect_abnormal_disconnect;

    default:
        /* All rfcomm disconnects should be handled above if we get this panic in debug lib */
        HFP_DEBUG(("Unhandled rfc connect status 0x%x\n", status));

		/* Return generic connect fail in "release" lib variant */
        return hfp_connect_failed;
    }
}
/****************************************************************************
NAME	
	HfpLastNumberRedial

DESCRIPTION
	This function issues a request to the AG to perform a last number redial.
	The request is issued on the SLC associated with the hfp profile instance 
	passed in by the application. The message returned indicates whether 
	the command was recognised by the AG or not.

MESSAGE RETURNED
	HFP_LAST_NUMBER_REDIAL_CFM

RETURNS
	void
*/
void HfpLastNumberRedial(HFP *hfp)
{
#ifdef HFP_DEBUG_LIB
	if (!hfp)
		HFP_DEBUG(("Null hfp task ptr passed in.\n"));
#endif

	/* Send an internal message requesting this action */
	MessageSend(&hfp->task, HFP_INTERNAL_AT_BLDN_REQ, 0);
}
/****************************************************************************
NAME    
    hfpHandlerExplicitCallTransferCfm

DESCRIPTION
    Handles HFP_EXPLICIT_CALL_TRANSFER_CFM_T message from HFP library

*/
void hfpHandlerExplicitCallTransferCfm ( const HFP_EXPLICIT_CALL_TRANSFER_CFM_T *cfm )
{
    if (cfm->status == hfp_success)
    {
        stateManagerEnterHfpConnectedState();
    }
    else
    {
        HFP_DEBUG(("HFP: Failure to ExplicitCallTransfer - status[%d]\n", cfm->status));
    }
}
/****************************************************************************
NAME    
    hfpHandlerAddHeldCallCfm

DESCRIPTION
    Handles HFP_ADD_HELD_CALL_CFM_T message from HFP library

*/
void hfpHandlerAddHeldCallCfm ( const HFP_ADD_HELD_CALL_CFM_T *cfm )
{
    if (cfm->status == hfp_success)
    {
        stateManagerEnterTWCMulticallState();
    }
    else
    {
        HFP_DEBUG(("HFP: Failure to AddHeldCall - status[%d]\n", cfm->status));
    }
}
/****************************************************************************
NAME    
    hfpHandlerReleaseHeldRejectWaitingCallCfm

DESCRIPTION
    Handles HFP_RELEASE_HELD_REJECT_WAITING_CALL_CFM_T message from HFP library

*/
void hfpHandlerReleaseHeldRejectWaitingCallCfm ( const HFP_RELEASE_HELD_REJECT_WAITING_CALL_CFM_T *cfm )
{
    /* if successful we're just in a normal active call now */
    if (cfm->status == hfp_success)
    {
        stateManagerEnterActiveCallState();
    }
    else
    {
        HFP_DEBUG(("HFP: Failure to ReleaseHeldRejectWaiting - status[%d]\n", cfm->status));
    }
}
/****************************************************************************
NAME    
    hfpHandlerReleaseActiveAcceptOtherCallCfm

DESCRIPTION
    Handles HFP_RELEASE_ACTIVE_ACCEPT_OTHER_CALL_CFM_T message from HFP library

*/
void hfpHandlerReleaseActiveAcceptOtherCallCfm ( const HFP_RELEASE_ACTIVE_ACCEPT_OTHER_CALL_CFM_T *cfm )
{
    /* if successful we're just in a normal active call now */
    if (cfm->status == hfp_success)
    {
        stateManagerEnterActiveCallState();
    }
    else
    {
        HFP_DEBUG(("HFP: Failure to ReleaseActiveAcceptOther - status[%d]\n", cfm->status));
    }
}
/****************************************************************************
NAME	
	HfpDialMemoryLocation

DESCRIPTION
	This function issues a request to the AG to dial from the the supplied 
	memory_location (the HFP specification defines the command but it is 
	AG implementation dependent how this is implemented). The request is 
	issued on the SLC associated with the hfp profile instance passed in by 
	the application. 
	
	The length argument specifies the length in bytes of the memory_location 
	to be sent. 
	
	The memory_location is the location the AG must dial from. The message 
	returned indicates whether the command was recognised by the AG or not.
	
MESSAGE RETURNED
	HFP_DIAL_MEMORY_CFM

RETURNS
	void
*/
void HfpDialMemoryLocation(HFP *hfp, uint16 length, const uint8 *memory_location)
{
#ifdef HFP_DEBUG_LIB
	if (!hfp)
		HFP_DEBUG(("Null hfp task ptr passed in.\n"));

	if (!length)
		HFP_DEBUG(("Zero length passed in.\n"));

	if (!memory_location)
		HFP_DEBUG(("Null memory location ptr passed in.\n"));
#endif

	/* Send an internal message */
	{
		MAKE_HFP_MESSAGE(HFP_INTERNAL_AT_ATD_MEMORY_REQ);
		message->length = length;
		message->memory = (uint8 *) PanicUnlessMalloc(length);
		memmove(message->memory, memory_location, length);
		MessageSend(&hfp->task, HFP_INTERNAL_AT_ATD_MEMORY_REQ, message);
	}
}
/****************************************************************************
NAME
    hfpHandlerCallWaitingInd

DESCRIPTION
    Handle indication that we have a call waiting.

*/
void hfpHandlerCallWaitingInd( const HFP_CALL_WAITING_IND_T* ind )
{
    headsetHfpState hfp_state = stateManagerGetHfpState();

    if (headsetActiveCall == hfp_state)
    {
        stateManagerEnterTWCWaitingState();
    }
    else
    {
        HFP_DEBUG(("HFP: Got call waiting indication in state [%d]\n", hfp_state));
    }
}
/****************************************************************************
NAME	
	HfpVoiceRecognitionEnable

DESCRIPTION
	Enable / disable voice recognition function at the AG. An SLC for the 
	supplied profile instance (hfp) must already be established before calling 
	this function. The enable flag determines whether a request will be made 
	to the AG to enabe or disable its voice recognition function. The message 
	returned indicates whether the command was recognised by the AG or not. 
	
	The AG may autonomously notify the HFP device of a change in the state of
	its voice recognition function. This notification will be passed on to the 
	application using a HFP_VOICE_RECOGNITION_IND message.

MESSAGE RETURNED
	HFP_VOICE_RECOGNITION_ENABLE_CFM

RETURNS
	void
*/
void HfpVoiceRecognitionEnable(HFP *hfp, bool enable)
{
#ifdef HFP_DEBUG_LIB
	if (!hfp)
		HFP_DEBUG(("Null hfp task ptr passed in.\n"));
#endif

	{
		/* Send an internal message to kick off SLC creation */
		MAKE_HFP_MESSAGE(HFP_INTERNAL_AT_BVRA_REQ);
		message->enable = enable;
		MessageSend(&hfp->task, HFP_INTERNAL_AT_BVRA_REQ, message);
	}
}
/****************************************************************************
NAME    
    hfpHandlerThreeWayCallSetupInd

DESCRIPTION
    Handles HFP_CALL_SETUP_IND_T message from HFP library during threeway calling
    scenario

*/
void hfpHandlerThreeWayCallSetupInd ( const HFP_CALL_SETUP_IND_T *ind )
{
    headsetHfpState state = stateManagerGetHfpState();

    HFP_DEBUG(("Handling CallSetupInd[%d] in threeway calling state[%d]\n", ind->call_setup, state));

    switch (ind->call_setup)
    {
        case hfp_no_call_setup:
        {
            if (state == headsetTWCWaiting)
            {
                /* this is fundamentally broken in the HFP spec...

                   a no_call_setup value in headsetTWCWaiting state can mean any 1 of 3 things:-

                    - the waiting call (that called us) has hung up on us
                    - the waiting call (that we called) has hung up on us
                    - the waiting call (that we called) has accepted our call
                   
                  we'll - arbitrarily - choose to believe the 3rd case, as this'll pass the PTS test */
                stateManagerEnterTWCOnHoldState();
            }
            break;
        }
        case hfp_outgoing_call_setup:
            if (state == headsetActiveCall)
            {
                /* we're in an active call and making an outgoing call ourselves
                   get into threeway waiting state */
                stateManagerEnterTWCWaitingState();
            }
            break;
        case hfp_outgoing_call_alerting_setup:
            /* should only get here if already in TWCWaiting state and want to stay there so ignore */
        case hfp_incoming_call_setup:
			/* Record event if TWC not supported so we can check when currently active call ends */
			if (!(theHeadset.HFP_features.HFP_Supported_Features & HFP_THREE_WAY_CALLING))
			{
				theHeadset.SecondIncomingCall = TRUE;
				return;
			}
			break;
			
        default:
            break;
    }
	
	theHeadset.SecondIncomingCall = FALSE;
}
/*
	Handle CSR Power Source Request
*/
void hfpHandleCsrPowerSourceReq(HFP *hfp, HFP_INTERNAL_CSR_POWER_SOURCE_REQ_T *msg)
{
	if (msg->pwr_status > hfp_csr_pwr_rep_external)
	{
		HFP_DEBUG(("hfpHandleCsrSupportedFeaturesAck : Invalid Power Status parameter\n"));
		return;
	}
	
	switch (hfp->state)
	{
	case hfpInitialising:
	case hfpReady:
	case hfpSlcConnecting:
		/* SLC not connected, Do Nothing */
		break;
	case hfpSlcConnected:
	case hfpIncomingCallEstablish:
	case hfpOutgoingCallEstablish:
	case hfpOutgoingCallAlerting:
	case hfpActiveCall:
		{
			/* SLC connected, send the command */
			char cmd[15];
				
			/* Create the AT cmd we're sending */
			sprintf(cmd, "AT+CSRPWR=%d\r", msg->pwr_status);
		
			/* Send the AT cmd over the air */
			hfpSendAtCmd(&hfp->task, strlen(cmd), cmd);
			break;
		}
	default:
		HFP_DEBUG(("Unknown State [0x%x]\n", hfp->state));
		break;
	}
}
/****************************************************************************
NAME	
	hfpHandleSdpInternalRegisterCfm

DESCRIPTION
	Handle the outcome of the SDP register request if we have initialised
	the profile lib and are registering a service record during the 
	operation of the profile.

RETURNS
	void
*/
void hfpHandleSdpInternalRegisterCfm(HFP *hfp, const HFP_INTERNAL_SDP_REGISTER_CFM_T *cfm)
{
	/* If this failed then we should retry, SDS may have been busy with SDP search */
	if (cfm->status != hfp_success)
	{
		if (hfp->sdp_record_handle == 0)
		{
			/* Register service record */
			hfpRegisterServiceRecord(hfp);
		}

#ifdef HFP_DEBUG_LIB
		HFP_DEBUG(("SDP register request failed\n"));
#endif
	}
}
void HfpCsrPowerLevel(HFP *hfp, uint16 pwr_level)
{
#ifdef HFP_DEBUG_LIB
    if (!hfp)
    {
        HFP_DEBUG(("Null hfp task ptr passed in.\n"));
    }
#endif

	if (hfp->use_csr2csr)
    {
        /* Send an internal message */
        MAKE_HFP_MESSAGE(HFP_INTERNAL_CSR_POWER_LEVEL_REQ);
        message->pwr_level = pwr_level;
        MessageSend(&hfp->task, HFP_INTERNAL_CSR_POWER_LEVEL_REQ, message);
    }
}
void hfpHandlerSpeakerVolumeInd( const HFP_SPEAKER_VOLUME_IND_T *ind )
{
	HFP_DEBUG(("HFP: hfpHandlerSpeakerVolumeInd [%d]\n", ind->volume_gain)) ;
	theHeadset.gHfpVolumeLevel = ind->volume_gain;
	
	if (theHeadset.gHfpVolumeLevel == 0)
		MessageSend(&theHeadset.task, EventVolumeMin, 0);
	
	if (theHeadset.gHfpVolumeLevel == VOL_MAX_VOLUME_LEVEL)
		MessageSend(&theHeadset.task, EventVolumeMax, 0);
			
	if (stateManagerIsA2dpStreaming())
	    return;    
	
	VolumeSetHeadsetVolume(theHeadset.gHfpVolumeLevel, FALSE, FALSE);
	
}
void HfpCsrPowerSource(HFP *hfp, hfp_csr_power_status_report pwr_status)
{
#ifdef HFP_DEBUG_LIB
    if (!hfp)
    {
        HFP_DEBUG(("Null hfp task ptr passed in.\n"));
    }
#endif

	if (hfp->use_csr2csr)
    {
        /* Send an internal message */
        MAKE_HFP_MESSAGE(HFP_INTERNAL_CSR_POWER_SOURCE_REQ);
        message->pwr_status = pwr_status;
        MessageSend(&hfp->task, HFP_INTERNAL_CSR_POWER_SOURCE_REQ, message);
    }
}
/****************************************************************************
NAME    
    hfpHandlerHoldActiveAcceptOtherCallCfm

DESCRIPTION
    Handles HFP_HOLD_ACTIVE_ACCEPT_OTHER_CALL_CFM_T message from HFP library

*/
void hfpHandlerHoldActiveAcceptOtherCallCfm ( const HFP_HOLD_ACTIVE_ACCEPT_OTHER_CALL_CFM_T *cfm )
{
    headsetHfpState hfp_state = stateManagerGetHfpState();
    
    if (cfm->status == hfp_success)
    {
        /* Workaround for ambiguity in HFP spec.
           Only change state if we're in a threeway calling mode.
           This is so that when CHLD=2 is used in an active call (put it on hold), we'll just stay
           in the active call state and therefore generate the correct CHLD=2 (unhold) then CHUP (hangup)
           messages */
        if (hfp_state == headsetTWCWaiting || hfp_state == headsetTWCOnHold)
            stateManagerEnterTWCOnHoldState();
    }
    else
    {
        HFP_DEBUG(("HFP: Failure to HoldActiveAcceptOther - status[%d]\n", cfm->status));
    }
}
/****************************************************************************
NAME    
    audioConnectSco
    
DESCRIPTION
	This function connects the synchronous connection to the CVC EC/NR Algorithm running
    in the Kalimba DSP. 

*/	  
static bool audioConnectSco(AUDIO_SINK_T sink_type, uint32 bandwidth)
{
    bool lResult = FALSE ;
   	
    /* The mode to connect - connected as default */
    AUDIO_MODE_T lMode = AUDIO_MODE_CONNECTED ;
	
	/* Disconnect A2DP audio if it was active */
	streamControlCeaseA2dpStreaming(TRUE);
    
    /* Mute control */
    if (theHeadset.gMuted )
    {
		if (theHeadset.features.MuteSpeakerAndMic)
    	{
        	lMode = AUDIO_MODE_MUTE_BOTH;
    	}
    	else
    	{
        	lMode = AUDIO_MODE_MUTE_MIC;
    	}      
    }    	
    
	if (HfpGetAudioSink(theHeadset.hfp_hsp))
	{
		HFP_DEBUG(("HFP: Route SCO mode=%d mic_mute=%d volindex=%d volgain=%d\n",lMode,theHeadset.gMuted,theHeadset.gHfpVolumeLevel,theHeadset.config->gVolLevels.volumes[theHeadset.gHfpVolumeLevel].hfpGain));
		lResult = AudioConnect((TaskData*)gPlugins,
		 				     HfpGetAudioSink(theHeadset.hfp_hsp),
		 				     sink_type,
							 theHeadset.theCodecTask,
							 theHeadset.config->gVolLevels.volumes[theHeadset.gHfpVolumeLevel].hfpGain,
						   	 bandwidth,
						   	 theHeadset.features.mono ? FALSE : TRUE,
		 					 lMode,
							 NULL,
							 &theHeadset.task);

		theHeadset.dsp_process = dsp_process_sco;
	}	   

	return (lResult=TRUE);
}
/* Record the index of an indicator present in +CIND: and requested by the application */
static void hfpStoreUnhandledIndicator(hfp_link_data* link, uint16 cind_index)
{
    /* Local copy of ptr and count*/
    uint16** extra_indicator_idxs = &link->ag_supported_indicators.extra_indicator_idxs;
    uint16* num_extra_indicator_idxs = &link->ag_supported_indicators.num_extra_indicator_idxs;
    uint16* temp;
    
    /* Make space to store indicator and store it */
    temp = realloc(*extra_indicator_idxs, (*num_extra_indicator_idxs) + 1);
    if(temp)
    {
        *extra_indicator_idxs = temp;
        (*extra_indicator_idxs)[*num_extra_indicator_idxs] = cind_index;
        (*num_extra_indicator_idxs)++;
    }
    else
    {
        HFP_DEBUG(("Extra Indicators realloc failed\n"));
    }
}
Exemple #27
0
/****************************************************************************
NAME    
    hfpGetAgSupportedFeatures

DESCRIPTION
    AG does not support BRSF command so we need to perform an SDP search
    to get its supported features.

RETURNS
    void
*/
void hfpGetAgSupportedFeatures(hfp_link_data* link)
{
    bdaddr link_addr;
    
    if (hfpGetLinkBdaddr(link, &link_addr))
    {
        /* 
            Issue the search request to the connection lib. The max number of attribute bytes
            is set to an arbitrary number, however the aim is to set it to a value so that
            if the remote end returns this many bytes we still have a block big enough to
            copy the data into. 
        */
        ConnectionSdpServiceSearchAttributeRequest(&theHfp->task, &link_addr, 0x32, sizeof(HfpServiceRequest), (uint8 *) HfpServiceRequest, sizeof(supportedFeaturesAttributeRequest), supportedFeaturesAttributeRequest);
    }
    else
    {
        /* Something has gone wrong - panic */
        HFP_DEBUG(("Failed to get link addr\n"));
    }
}
/****************************************************************************
NAME	
	hfpGetAgProfileVersion

DESCRIPTION
	Requests HFP profile version supported by the AG.
	
RETURNS
	void
*/
void hfpGetAgProfileVersion(HFP *hfp)
{
	bdaddr my_addr;

	if (SinkGetBdAddr(hfp->sink, &my_addr))
	{
		/* 
			Issue the search request to the connection lib. The max number of attribute bytes
			is set to an arbitrary number, however the aim is to set it to a value so that
			if the remote end returns this many bytes we still have a block big enough to
			copy the data into. 
		*/
		hfp->sdp_search_mode = hfp_sdp_search_profile_version;
		ConnectionSdpServiceSearchAttributeRequest(&hfp->task, &my_addr, 0x32, sizeof(HfpServiceRequest), (uint8 *) HfpServiceRequest, sizeof(profileDescriptorRequest), profileDescriptorRequest);
	}
	else
	{
		/* Something has gone wrong - panic */
		HFP_DEBUG(("SinkGetBdAddr failed\n"));
	}
}
void HfpCsrGetSms(HFP *hfp, uint16 index)
{
#ifdef HFP_DEBUG_LIB
    if (!hfp)
    {
        HFP_DEBUG(("Null hfp task ptr passed in.\n"));
    }
#endif

	if (hfp->use_csr2csr)
    {
        /* Send an internal message */
        MAKE_HFP_MESSAGE(HFP_INTERNAL_CSR_GET_SMS_REQ);
        message->index = index;
        MessageSend(&hfp->task, HFP_INTERNAL_CSR_GET_SMS_REQ, message);
    }
    else
    {
	    hfpSendCsrSmsCfm(hfp, hfp_csr_not_inited, 0, NULL);
    }
}
/****************************************************************************
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;
}