藍芽HFP協議AT命令流程
藍芽HFP協議主要是指HF和AG之間的信令互動,我們知道藍芽耳機和手機配對之後,耳機會發三個最基本的AT命令,分別是
AT+BRSF, AT+CIND=?, AT+CIND?
協議棧接收AT命令的流程
1 BTA層從rfcomn接收藍芽耳機發送過來的AT命令,在bta_ag_rfc_data裡面會執行一個無線迴圈,呼叫PORT_ReadData函式不斷的讀取AT命令,讀取到AT指令後,呼叫bta_ag_at_parse函式解析AT命令,該函式的功能是用來判斷是否是合適的AT命令
void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { UINT16 len; char buf[BTA_AG_RFC_READ_MAX]; UNUSED(p_data); memset(buf, 0, BTA_AG_RFC_READ_MAX); APPL_TRACE_DEBUG("bta_ag_rfc_data"); /* do the following */ for(;;) { /* read data from rfcomm; if bad status, we're done */ if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) != PORT_SUCCESS) { break; } /* if no data, we're done */ if (len == 0) { break; } /* run AT command interpreter on data */ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); bta_ag_at_parse(&p_scb->at_cb, buf, len); bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); /* no more data to read, we're done */ if (len < BTA_AG_RFC_READ_MAX) { break; } } }
2 在bta_ag_at_parse函式裡面,如果AT命令正確,就呼叫bta_ag_process_at函式解析AT命令,如果AT命令正確,就呼叫callback函式,如程式碼中的(*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len) { int i = 0; char* p_save; if (p_cb->p_cmd_buf == NULL) { if ((p_cb->p_cmd_buf = (char *) GKI_getbuf(p_cb->cmd_max_len)) == NULL) { APPL_TRACE_ERROR("%s: GKI_getbuf() failed allocation", __func__); return; } p_cb->cmd_pos = 0; } for (i = 0; i < len;) { while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len) { /* Skip null characters between AT commands. */ if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) { i++; continue; } p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++]; if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') { p_cb->p_cmd_buf[p_cb->cmd_pos] = 0; if ((p_cb->cmd_pos > 2) && (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') && (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) { p_save = p_cb->p_cmd_buf; p_cb->p_cmd_buf += 2; bta_ag_process_at(p_cb); p_cb->p_cmd_buf = p_save; } p_cb->cmd_pos = 0; } else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B ) { p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0; (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf); p_cb->cmd_pos = 0; } else { ++p_cb->cmd_pos; } } if (i < len) p_cb->cmd_pos = 0; } }
3 而這個callback函式的初始化是在開啟藍芽後,bta裡面的bta_ag_rfc_open函式裡面,如下程式碼所示:
p_scb->at_cb.p_cmd_cback = (tBTA_AG_AT_CMD_CBACK *) bta_ag_at_cback_tbl[p_scb->conn_service];
const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] =
{
bta_ag_at_hsp_cback,
bta_ag_at_hfp_cback
};
4 所以對於HFP協議,將會呼叫到bta_ag_at_hfp_cback函式,在這個函式裡面,將會對AT命令進行處理.呼叫btif_context_switched函式將訊息傳遞到btif層,然後通過btif_hf_upstreams_evth函式對訊息進行處理,以判斷是否上傳到
JNI層,進一步上報給APP層。
下面的Log可以印證上面的4步
01-03 21:38:50.500 9401 9447 I bt_btif : bta_sys_event: Event 0x50b
01-03 21:38:50.500 9401 9447 D bt_btif : bta_ag_rfc_data
01-03 21:38:50.500 9401 9447 D bt_btif : bta_ag_at_hfp_cback: AT command 14, arg_type 8, int_arg 0, arg =?
01-03 21:38:50.560 9401 9431 D bt_btif : btif_context_switched for event: 14 01-03 21:38:50.560 9401 9431 D bt_btif : btif_hf_upstreams_evt: event=BTA_AG_AT_CIND_EVT 01-03 21:38:50.560 9401 9431 I bt_btif : HAL bt_hf_callbacks->cind_cmd_cb
01-03 21:38:50.560 9401 9431 D HeadsetStateMachine: Enter onAtCind()
APP下發AT命令到協議棧的流程
以CIND命令為例,看看onAtCind函式,這個函式會發一個EVENT_TYPE_AT_CIND訊息,而處理這個訊息的函式是processAtCind,而這個processAtCind函式最終會呼叫一個native方法:cindResponseNative,這個native方法最終會呼叫到協議棧btif層的cind_response方法,cind_response方法會呼叫到BTA_AgResult方法
private void onAtCind(byte[] address) {
StackEvent event = new StackEvent(EVENT_TYPE_AT_CIND);
event.device = getDevice(address);
sendMessage(STACK_EVENT, event);
}
private void processAtCind(BluetoothDevice device) {
int call, call_setup;
if(device == null) {
Log.w(TAG, "processAtCind device is null");
return;
}
/* Handsfree carkits expect that +CIND is properly responded to
Hence we ensure that a proper response is sent
for the virtual call too.*/
if (isVirtualCallInProgress()) {
call = 1;
call_setup = 0;
} else {
// regular phone call
call = mPhoneState.getNumActiveCall();
call_setup = mPhoneState.getNumHeldCall();
}
cindResponseNative(mPhoneState.getService(), call,
call_setup, mPhoneState.getCallState(),
mPhoneState.getSignal(), mPhoneState.getRoam(),
mPhoneState.getBatteryCharge(), getByteAddress(device));
}
看看BTA_AgResult方法,這個方法會向BTA傳送BTA_AG_API_RESULT_EVT的event,而處理這個event的方法是bta_sys_event
void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data)
{
tBTA_AG_API_RESULT *p_buf;
if ((p_buf = (tBTA_AG_API_RESULT *) GKI_getbuf(sizeof(tBTA_AG_API_RESULT))) != NULL)
{
p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
p_buf->hdr.layer_specific = handle;
p_buf->result = result;
if(p_data)
{
memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
}
bta_sys_sendmsg(p_buf);
}
}
看看bta_sys_event方法,而這個方法裡面會呼叫bta_ag的bta_ag_hdl_event方法進行處理相應的event,而這個event的處理函式是bta_ag_api_result,這個函式向協議棧下發AT命令
void bta_sys_event(BT_HDR *p_msg)
{
UINT8 id;
BOOLEAN freebuf = TRUE;
APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event);
/* get subsystem id from event */
id = (UINT8) (p_msg->event >> 8);
/* verify id and call subsystem event handler */
if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
{
freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
}
else
{
APPL_TRACE_WARNING("BTA got unregistered event id %d", id);
}
if (freebuf)
{
GKI_freebuf(p_msg);
}
}
log印證上述的分析
01-03 21:38:50.560 9401 9453 D bt_btif : BTHF: cind_response 01-03 21:38:50.560 9401 9447 I bt_btif : bta_sys_event: Event 0x506 01-03 21:38:50.560 9401 9447 D bt_btif : bta_ag_hdl_event: Event 0x0506 01-03 21:38:50.560 9401 9447 D bt_btif : bta_ag_api_result: p_scb 0x9a446648 01-03 21:38:50.560 9401 9447 I bt_btif : bta_ag_sm_execute: Handle 0x0001, State 2, Event 0x0506 01-03 21:38:50.560 9401 9447 D bt_btif : bta_ag_hfp_result : res = 3