/****************************************************************************** * * Copyright (c) 2014 The Android Open Source Project * Copyright (C) 2003-2012 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #include #include #include "common/bt_defs.h" #include "bta/bta_api.h" #include "bta/bta_sys.h" #include "bta/bta_hf_client_api.h" #include "bta_hf_client_int.h" #if (BTA_HF_INCLUDED == TRUE) /* uncomment to enable extra debug */ /* #define BTA_HF_CLIENT_DEBUG TRUE */ #ifndef BTA_HF_CLIENT_DEBUG #define BTA_HF_CLIENT_DEBUG FALSE #endif #if BTA_HF_CLIENT_DEBUG == TRUE static char *bta_hf_client_evt_str(UINT16 event); static char *bta_hf_client_state_str(UINT8 state); #endif /* state machine states */ enum { BTA_HF_CLIENT_INIT_ST, BTA_HF_CLIENT_OPENING_ST, BTA_HF_CLIENT_OPEN_ST, BTA_HF_CLIENT_CLOSING_ST }; /* state machine action enumeration list */ enum { BTA_HF_CLIENT_REGISTER, BTA_HF_CLIENT_DEREGISTER, BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_START_OPEN, BTA_HF_CLIENT_RFC_ACP_OPEN, BTA_HF_CLIENT_SCO_LISTEN, BTA_HF_CLIENT_SCO_CONN_OPEN, BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_SCO_OPEN, BTA_HF_CLIENT_SCO_CLOSE, BTA_HF_CLIENT_SCO_SHUTDOWN, BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_RFC_OPEN, BTA_HF_CLIENT_RFC_FAIL, BTA_HF_CLIENT_DISC_INT_RES, BTA_HF_CLIENT_RFC_DO_OPEN, BTA_HF_CLIENT_DISC_FAIL, BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_DISC_ACP_RES, BTA_HF_CLIENT_SVC_CONN_OPEN, BTA_HF_CLIENT_SEND_AT_CMD, #if (BTM_SCO_HCI_INCLUDED == TRUE) BTA_HF_CLIENT_CI_SCO_DATA, #endif BTA_HF_CLIENT_NUM_ACTIONS, }; #define BTA_HF_CLIENT_IGNORE BTA_HF_CLIENT_NUM_ACTIONS /* type for action functions */ typedef void (*tBTA_HF_CLIENT_ACTION)(tBTA_HF_CLIENT_DATA *p_data); /* action functions table, indexed with action enum */ const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = { /* BTA_HF_CLIENT_REGISTER */ bta_hf_client_register, /* BTA_HF_CLIENT_DEREGISTER */ bta_hf_client_deregister, /* BTA_HF_CLIENT_START_DEREG */ bta_hf_client_start_dereg, /* BTA_HF_CLIENT_RFC_DO_CLOSE */ bta_hf_client_rfc_do_close, /* BTA_HF_CLIENT_START_CLOSE */ bta_hf_client_start_close, /* BTA_HF_CLIENT_START_OPEN */ bta_hf_client_start_open, /* BTA_HF_CLIENT_RFC_ACP_OPEN */ bta_hf_client_rfc_acp_open, /* BTA_HF_CLIENT_SCO_LISTEN */ bta_hf_client_sco_listen, /* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open, /* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close, /* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open, /* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close, /* BTA_HF_CLIENT_SCO_SHUTDOWN */ bta_hf_client_sco_shutdown, /* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db, /* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail, /* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open, /* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail, /* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res, /* BTA_HF_CLIENT_RFC_DO_OPEN */ bta_hf_client_rfc_do_open, /* BTA_HF_CLIENT_DISC_FAIL */ bta_hf_client_disc_fail, /* BTA_HF_CLIENT_RFC_CLOSE */ bta_hf_client_rfc_close, /* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data, /* BTA_HF_CLIENT_DISC_ACP_RES */ bta_hf_client_disc_acp_res, /* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open, /* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* BTA_HF_CLIENT_CI_SCO_DATA */ bta_hf_client_ci_sco_data, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; /* state table information */ #define BTA_HF_CLIENT_ACTIONS 2 /* number of actions */ #define BTA_HF_CLIENT_NEXT_STATE 2 /* position of next state */ #define BTA_HF_CLIENT_NUM_COLS 3 /* number of columns in state tables */ /* state table for init state */ const UINT8 bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = { /* Event Action 1 Action 2 Next state */ /* API_REGISTER_EVT */ {BTA_HF_CLIENT_REGISTER, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_DEREGISTER, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* API_OPEN_EVT */ {BTA_HF_CLIENT_START_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_ACP_OPEN, BTA_HF_CLIENT_SCO_LISTEN, BTA_HF_CLIENT_OPEN_ST}, /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; /* state table for opening state */ const UINT8 bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = { /* Event Action 1 Action 2 Next state */ /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_CLOSING_ST}, /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* API_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_OPEN, BTA_HF_CLIENT_SCO_LISTEN, BTA_HF_CLIENT_OPEN_ST}, /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_DISC_INT_RES, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* DISC_OK_EVT */ {BTA_HF_CLIENT_RFC_DO_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_DISC_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; /* state table for open state */ const UINT8 bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = { /* Event Action 1 Action 2 Next state */ /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_CLOSING_ST}, /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* API_CLOSE_EVT */ {BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* RFC_DATA_EVT */ {BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_DISC_ACP_RES, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_CONN_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_SEND_AT_CMD, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_CI_SCO_DATA, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; /* state table for closing state */ const UINT8 bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = { /* Event Action 1 Action 2 Next state */ /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; /* type for state table */ typedef const UINT8 (*tBTA_HF_CLIENT_ST_TBL)[BTA_HF_CLIENT_NUM_COLS]; /* state table */ const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = { bta_hf_client_st_init, bta_hf_client_st_opening, bta_hf_client_st_open, bta_hf_client_st_closing }; /* HF Client control block */ #if BTA_DYNAMIC_MEMORY == FALSE tBTA_HF_CLIENT_CB bta_hf_client_cb; #else tBTA_HF_CLIENT_CB *bta_hf_client_cb_ptr; #endif /******************************************************************************* ** ** Function bta_hf_client_scb_init ** ** Description Initialize an HF_Client service control block. ** ** ** Returns void ** *******************************************************************************/ void bta_hf_client_scb_init(void) { APPL_TRACE_DEBUG("%s", __FUNCTION__); memset(&bta_hf_client_cb.scb, 0, sizeof(tBTA_HF_CLIENT_SCB)); bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX; bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD; } /******************************************************************************* ** ** Function bta_hf_client_scb_disable ** ** Description Disable a service control block. ** ** ** Returns void ** *******************************************************************************/ void bta_hf_client_scb_disable(void) { APPL_TRACE_DEBUG("%s", __FUNCTION__); bta_hf_client_scb_init(); (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_DISABLE_EVT, NULL); } /******************************************************************************* ** ** Function bta_hf_client_resume_open ** ** Description Resume opening process. ** ** ** Returns void ** *******************************************************************************/ void bta_hf_client_resume_open (void) { APPL_TRACE_DEBUG ("%s", __FUNCTION__); /* resume opening process. */ if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_INIT_ST) { bta_hf_client_cb.scb.state = BTA_HF_CLIENT_OPENING_ST; bta_hf_client_start_open (NULL); } } /******************************************************************************* ** ** Function bta_hf_client_colli_timer_cback ** ** Description HF Client connection collision timer callback ** ** ** Returns void ** *******************************************************************************/ static void bta_hf_client_colli_timer_cback (TIMER_LIST_ENT *p_tle) { APPL_TRACE_DEBUG("%s", __FUNCTION__); if (p_tle) { bta_hf_client_cb.scb.colli_tmr_on = FALSE; /* If the peer haven't opened connection, restart opening process */ bta_hf_client_resume_open (); } } /******************************************************************************* ** ** Function bta_hf_client_collision_cback ** ** Description Get notified about collision. ** ** ** Returns void ** *******************************************************************************/ void bta_hf_client_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) { UNUSED(status); UNUSED(app_id); UNUSED(peer_addr); if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPENING_ST) { if (id == BTA_ID_SYS) { /* ACL collision */ APPL_TRACE_WARNING ("HF Client found collision (ACL) ..."); } else if (id == BTA_ID_HS) { /* RFCOMM collision */ APPL_TRACE_WARNING ("HF Client found collision (RFCOMM) ..."); } else { APPL_TRACE_WARNING ("HF Client found collision (\?\?\?) ..."); } bta_hf_client_cb.scb.state = BTA_HF_CLIENT_INIT_ST; /* Cancel SDP if it had been started. */ if (bta_hf_client_cb.scb.p_disc_db) { (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db); bta_hf_client_free_db(NULL); } /* reopen registered server */ /* Collision may be detected before or after we close servers. */ bta_hf_client_start_server(); /* Start timer to handle connection opening restart */ bta_hf_client_cb.scb.colli_timer.p_cback = (TIMER_CBACK *)&bta_hf_client_colli_timer_cback; bta_sys_start_timer(&bta_hf_client_cb.scb.colli_timer, 0, BTA_HF_CLIENT_COLLISION_TIMER); bta_hf_client_cb.scb.colli_tmr_on = TRUE; } } /******************************************************************************* ** ** Function bta_hf_client_api_enable ** ** Description Handle an API enable event. ** ** ** Returns void ** *******************************************************************************/ static void bta_hf_client_api_enable(tBTA_HF_CLIENT_DATA *p_data) { /* initialize control block */ memset(&bta_hf_client_cb, 0, sizeof(tBTA_HF_CLIENT_CB)); /* store callback function */ bta_hf_client_cb.p_cback = p_data->api_enable.p_cback; /* check if mSBC support enabled */ #if 0 // todo char value[PROPERTY_VALUE_MAX]; property_get("ro.bluetooth.hfp.ver", value, "0"); if (strcmp(value, "1.6") == 0) { bta_hf_client_cb.msbc_enabled = TRUE; } #else bta_hf_client_cb.msbc_enabled = FALSE; #endif bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD; /* set same setting as AG does */ BTM_WriteVoiceSettings(AG_VOICE_SETTINGS); bta_sys_collision_register (BTA_ID_HS, bta_hf_client_collision_cback); /* call callback with enable event */ (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_ENABLE_EVT, NULL); } /******************************************************************************* ** ** Function bta_hf_client_api_disable ** ** Description Handle an API disable event. ** ** ** Returns void ** *******************************************************************************/ static void bta_hf_client_api_disable(tBTA_HF_CLIENT_DATA *p_data) { if (!bta_sys_is_register (BTA_ID_HS)) { APPL_TRACE_ERROR("BTA HF Client is already disabled, ignoring ..."); return; } /* De-register with BTA system manager */ bta_sys_deregister(BTA_ID_HS); bta_hf_client_sm_execute(BTA_HF_CLIENT_API_DEREGISTER_EVT, p_data); bta_sys_collision_register (BTA_ID_HS, NULL); } /******************************************************************************* ** ** Function bta_hf_client_hdl_event ** ** Description Data HF Client main event handling function. ** ** ** Returns BOOLEAN ** *******************************************************************************/ BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg) { #if BTA_HF_CLIENT_DEBUG == TRUE APPL_TRACE_DEBUG("bta_hf_client_hdl_event %s (0x%x)", bta_hf_client_evt_str(p_msg->event), p_msg->event); #endif switch (p_msg->event) { /* handle enable event */ case BTA_HF_CLIENT_API_ENABLE_EVT: bta_hf_client_api_enable((tBTA_HF_CLIENT_DATA *) p_msg); break; /* handle disable event */ case BTA_HF_CLIENT_API_DISABLE_EVT: bta_hf_client_api_disable((tBTA_HF_CLIENT_DATA *) p_msg); break; default: bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA *) p_msg); break; } return TRUE; } /******************************************************************************* ** ** Function bta_hf_client_sm_execute ** ** Description State machine event handling function for HF Client ** ** ** Returns void ** *******************************************************************************/ void bta_hf_client_sm_execute(UINT16 event, tBTA_HF_CLIENT_DATA *p_data) { tBTA_HF_CLIENT_ST_TBL state_table; UINT8 action; int i; #if BTA_HF_CLIENT_DEBUG == TRUE UINT16 in_event = event; UINT8 in_state = bta_hf_client_cb.scb.state; /* Ignore displaying of AT results when not connected (Ignored in state machine) */ if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPEN_ST) { APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)", bta_hf_client_cb.scb.state, bta_hf_client_state_str(bta_hf_client_cb.scb.state), event, bta_hf_client_evt_str(event)); } #endif event &= 0x00FF; if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) { APPL_TRACE_ERROR("HF Client evt out of range, ignoring..."); return; } /* look up the state table for the current state */ state_table = bta_hf_client_st_tbl[bta_hf_client_cb.scb.state]; /* set next state */ bta_hf_client_cb.scb.state = state_table[event][BTA_HF_CLIENT_NEXT_STATE]; /* execute action functions */ for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++) { if ((action = state_table[event][i]) != BTA_HF_CLIENT_IGNORE) { (*bta_hf_client_action[action])(p_data); } else { break; } } #if BTA_HF_CLIENT_DEBUG == TRUE if (bta_hf_client_cb.scb.state != in_state) { APPL_TRACE_EVENT("BTA HF Client State Change: [%s] -> [%s] after Event [%s]", bta_hf_client_state_str(in_state), bta_hf_client_state_str(bta_hf_client_cb.scb.state), bta_hf_client_evt_str(in_event)); } #endif } static void send_post_slc_cmd(void) { bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE; bta_hf_client_send_at_bia(); bta_hf_client_send_at_ccwa(TRUE); bta_hf_client_send_at_cmee(TRUE); bta_hf_client_send_at_cops(FALSE); bta_hf_client_send_at_btrh(TRUE, 0); bta_hf_client_send_at_clip(TRUE); } /******************************************************************************* ** ** Function bta_hf_client_slc_seq ** ** Description Handles AT commands sequence required for SLC creation ** ** ** Returns void ** *******************************************************************************/ void bta_hf_client_slc_seq(BOOLEAN error) { APPL_TRACE_DEBUG("bta_hf_client_slc_seq cmd: %u", bta_hf_client_cb.scb.at_cb.current_cmd); if (error) { /* SLC establishment error, sent close rfcomm event */ APPL_TRACE_ERROR("HFPClient: Failed to create SLC due to AT error, disconnecting (%u)", bta_hf_client_cb.scb.at_cb.current_cmd); bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL); return; } if (bta_hf_client_cb.scb.svc_conn) { return; } switch (bta_hf_client_cb.scb.at_cb.current_cmd) { case BTA_HF_CLIENT_AT_NONE: bta_hf_client_send_at_brsf(); break; case BTA_HF_CLIENT_AT_BRSF: if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_CODEC) { bta_hf_client_send_at_bac(); break; } bta_hf_client_send_at_cind(FALSE); break; case BTA_HF_CLIENT_AT_BAC: bta_hf_client_send_at_cind(FALSE); break; case BTA_HF_CLIENT_AT_CIND: bta_hf_client_send_at_cind(TRUE); break; case BTA_HF_CLIENT_AT_CIND_STATUS: bta_hf_client_send_at_cmer(TRUE); break; case BTA_HF_CLIENT_AT_CMER: if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY) { bta_hf_client_send_at_chld('?', 0); } else { bta_hf_client_svc_conn_open(NULL); send_post_slc_cmd(); } break; case BTA_HF_CLIENT_AT_CHLD: bta_hf_client_svc_conn_open(NULL); send_post_slc_cmd(); break; default: /* If happen there is a bug in SLC creation procedure... */ APPL_TRACE_ERROR("HFPClient: Failed to create SLCdue to unexpected AT command, disconnecting (%u)", bta_hf_client_cb.scb.at_cb.current_cmd); bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL); break; } } #if BTA_HF_CLIENT_DEBUG == TRUE #ifndef CASE_RETURN_STR #define CASE_RETURN_STR(const) case const: return #const; #endif static char *bta_hf_client_evt_str(UINT16 event) { switch (event) { CASE_RETURN_STR(BTA_HF_CLIENT_API_REGISTER_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_API_DEREGISTER_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_API_OPEN_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_API_CLOSE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_OPEN_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_RFC_OPEN_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_RFC_CLOSE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_RFC_DATA_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_DISC_ACP_RES_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_DISC_INT_RES_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_DISC_OK_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_DISC_FAIL_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_API_ENABLE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_API_DISABLE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_SCO_OPEN_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_SCO_CLOSE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_SEND_AT_CMD_EVT) default: return "Unknown HF Client Event"; } } static char *bta_hf_client_state_str(UINT8 state) { switch (state) { CASE_RETURN_STR(BTA_HF_CLIENT_INIT_ST) CASE_RETURN_STR(BTA_HF_CLIENT_OPENING_ST) CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_ST) CASE_RETURN_STR(BTA_HF_CLIENT_CLOSING_ST) default: return "Unknown HF Client State"; } } #endif #endif /* #if (BTA_HF_INCLUDED == TRUE) */