1. 程式人生 > >藍芽HFP協議AT命令流程

藍芽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