/* 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")); } }
/**************************************************************************** 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; }