美文网首页蓝牙和WIFI
蓝牙笔记 | 蓝牙协议栈应用层GATT

蓝牙笔记 | 蓝牙协议栈应用层GATT

作者: 力卉编程 | 来源:发表于2019-12-31 21:19 被阅读0次

一、应用层传下来的消息到GATT层:
a) 死循环等待蓝牙开启:event = GKI_wait (0xFFFF, 0); 直到出现BT_EVT_PRELOAD_CMPL
b) btu_init_core()
c) BTE_InitStack();bta_sys_init();BTE_InitTraceLevels();
d) GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);通知启动事件
e) 等待消息的来临后处理
f) bta_sys_event(p_msg); //处理上层传来的消息

//external\bluetooth\bluedroid\stack\btu\btu_task.c
BTU_API UINT32 btu_task (UINT32 param)
{
    UINT16           event;
    BT_HDR          *p_msg;
    UINT8            i;
    UINT16           mask;
    BOOLEAN          handled;
    UNUSED(param);

#if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE)
    /* wait an event that HCISU is ready */
    BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
                "btu_task pending for preload complete event");

    for (;;)
    {
        event = GKI_wait (0xFFFF, 0);
        if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
        {
            /* indicates BT ENABLE abort */
            BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
                        "btu_task start abort!");
            return (0);
        }
        else if (event & BT_EVT_PRELOAD_CMPL)
        {
            break;
        }
        else
        {
            BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
                "btu_task ignore evt %04x while pending for preload complete",
                event);
        }
    }

    BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
                "btu_task received preload complete event");
#endif

    /* Initialize the mandatory core stack control blocks
       (BTU, BTM, L2CAP, and SDP)
     */
    btu_init_core();

    /* Initialize any optional stack components */
    BTE_InitStack();

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
    bta_sys_init();
#endif

    /* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
     * reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
     */
#if ( BT_USE_TRACES==TRUE )
    BTE_InitTraceLevels();
#endif

    /* Send a startup evt message to BTIF_TASK to kickstart the init procedure */
    GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);

    prctl(PR_SET_NAME, (unsigned long)"BTU TASK", 0, 0, 0);

    raise_priority_a2dp(TASK_HIGH_BTU);

    /* Wait for, and process, events */
    for (;;)
    {
        event = GKI_wait (0xFFFF, 0);

        if (event & TASK_MBOX_0_EVT_MASK)
        {
            /* Process all messages in the queue */
            while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
            {
                /* Determine the input message type. */
                switch (p_msg->event & BT_EVT_MASK)
                {
                    case BT_EVT_TO_BTU_HCI_ACL:
                        /* All Acl Data goes to L2CAP */
                        l2c_rcv_acl_data (p_msg);
                        break;

                    case BT_EVT_TO_BTU_L2C_SEG_XMIT:
                        /* L2CAP segment transmit complete */
                        l2c_link_segments_xmitted (p_msg);
                        break;

                    case BT_EVT_TO_BTU_HCI_SCO:
#if BTM_SCO_INCLUDED == TRUE
                        btm_route_sco_data (p_msg);
                        break;
#endif

                    case BT_EVT_TO_BTU_HCI_EVT:
                        btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
                        GKI_freebuf(p_msg);

#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
                        /* If host receives events which it doesn't response to, */
                        /* host should start idle timer to enter sleep mode.     */
                        btu_check_bt_sleep ();
#endif
                        break;

                    case BT_EVT_TO_BTU_HCI_CMD:
                        btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
                        break;

#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
                    case BT_EVT_TO_OBX_SR_MSG:
                        obx_sr_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_OBX_SR_L2C_MSG:
                        obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;
#endif

#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
                    case BT_EVT_TO_OBX_CL_MSG:
                        obx_cl_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_OBX_CL_L2C_MSG:
                        obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;
#endif

#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
                    case BT_EVT_TO_BIP_CMDS :
                        bip_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif /* BIP */
#if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE)
                    case BT_EVT_TO_BPP_PR_CMDS:
                        bpp_pr_proc_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
                    case BT_EVT_TO_BPP_SND_CMDS:
                        bpp_snd_proc_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;

#endif /* BPP */

#endif /* OBX */

#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
                    case BT_EVT_TO_BTU_SAP :
                        sap_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif /* SAP */
#if (defined(GAP_CONN_INCLUDED) && GAP_CONN_INCLUDED == TRUE && GAP_CONN_POST_EVT_INCLUDED == TRUE)
                    case BT_EVT_TO_GAP_MSG :
                        gap_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif
                    case BT_EVT_TO_START_TIMER :
                        /* Start free running 1 second timer for list management */
                        GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE);
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_STOP_TIMER:
                        if (GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
                            GKI_stop_timer(TIMER_0);
                        }
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_START_TIMER_ONESHOT:
                        if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                            TIMER_LIST_ENT *tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                            // Start non-repeating timer.
                            GKI_start_timer(TIMER_3, tle->ticks, FALSE);
                        } else {
                            BTM_TRACE_WARNING("Oneshot timer queue empty when received start request");
                        }
                        GKI_freebuf(p_msg);
                        break;

                    case BT_EVT_TO_STOP_TIMER_ONESHOT:
                        if (GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                            GKI_stop_timer(TIMER_3);
                        } else {
                            BTM_TRACE_WARNING("Oneshot timer queue not empty when received stop request");
                        }
                        GKI_freebuf (p_msg);
                        break;

#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
                    case BT_EVT_TO_START_QUICK_TIMER :
                        GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE);
                        GKI_freebuf (p_msg);
                        break;
#endif

                    default:
                        i = 0;
                        mask = (UINT16) (p_msg->event & BT_EVT_MASK);
                        handled = FALSE;

                        for (; !handled && i < BTU_MAX_REG_EVENT; i++)
                        {
                            if (btu_cb.event_reg[i].event_cb == NULL)
                                continue;

                            if (mask == btu_cb.event_reg[i].event_range)
                            {
                                if (btu_cb.event_reg[i].event_cb)
                                {
                                    btu_cb.event_reg[i].event_cb(p_msg);
                                    handled = TRUE;
                                }
                            }
                        }

                        if (handled == FALSE)
                            GKI_freebuf (p_msg);

                        break;
                }
            }
        }


        if (event & TIMER_0_EVT_MASK) {
            GKI_update_timer_list (&btu_cb.timer_queue, 1);

            while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
                TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue);
                if (p_tle->ticks != 0)
                    break;

                GKI_remove_from_timer_list(&btu_cb.timer_queue, p_tle);

                switch (p_tle->event) {
                    case BTU_TTYPE_BTM_DEV_CTL:
                        btm_dev_timeout(p_tle);
                        break;

                    case BTU_TTYPE_BTM_ACL:
                        btm_acl_timeout(p_tle);
                        break;

                    case BTU_TTYPE_L2CAP_LINK:
                    case BTU_TTYPE_L2CAP_CHNL:
                    case BTU_TTYPE_L2CAP_HOLD:
                    case BTU_TTYPE_L2CAP_INFO:
                    case BTU_TTYPE_L2CAP_FCR_ACK:
                        l2c_process_timeout (p_tle);
                        break;

                    case BTU_TTYPE_SDP:
                        sdp_conn_timeout ((tCONN_CB *)p_tle->param);
                        break;

                    case BTU_TTYPE_BTM_RMT_NAME:
                        btm_inq_rmt_name_failed();
                        break;

#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
                    case BTU_TTYPE_RFCOMM_MFC:
                    case BTU_TTYPE_RFCOMM_PORT:
                        rfcomm_process_timeout (p_tle);
                        break;

#endif /* If defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE */

#if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE))
                    case BTU_TTYPE_BNEP:
                        bnep_process_timeout(p_tle);
                        break;
#endif


#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
                    case BTU_TTYPE_AVDT_CCB_RET:
                    case BTU_TTYPE_AVDT_CCB_RSP:
                    case BTU_TTYPE_AVDT_CCB_IDLE:
                    case BTU_TTYPE_AVDT_SCB_TC:
                        avdt_process_timeout(p_tle);
                        break;
#endif

#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
                    case BTU_TTYPE_OBX_CLIENT_TO:
                        obx_cl_timeout(p_tle);
                        break;
#endif
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
                    case BTU_TTYPE_OBX_SERVER_TO:
                        obx_sr_timeout(p_tle);
                        break;

                    case BTU_TTYPE_OBX_SVR_SESS_TO:
                        obx_sr_sess_timeout(p_tle);
                        break;
#endif
#endif

#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
                    case BTU_TTYPE_SAP_TO:
                        sap_process_timeout(p_tle);
                        break;
#endif

                    case BTU_TTYPE_BTU_CMD_CMPL:
                        btu_hcif_cmd_timeout((UINT8)(p_tle->event - BTU_TTYPE_BTU_CMD_CMPL));
                        break;

#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
                    case BTU_TTYPE_HID_HOST_REPAGE_TO :
                        hidh_proc_repage_timeout(p_tle);
                        break;
#endif

#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
                    case BTU_TTYPE_BLE_INQUIRY:
                    case BTU_TTYPE_BLE_GAP_LIM_DISC:
                    case BTU_TTYPE_BLE_GAP_FAST_ADV:
                    case BTU_TTYPE_BLE_OBSERVE:
                        btm_ble_timeout(p_tle);
                        break;

                    case BTU_TTYPE_ATT_WAIT_FOR_RSP:
                        gatt_rsp_timeout(p_tle);
                        break;

                    case BTU_TTYPE_ATT_WAIT_FOR_IND_ACK:
                        gatt_ind_ack_timeout(p_tle);
                        break;
#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE)
                    case BTU_TTYPE_SMP_PAIRING_CMD:
                        smp_rsp_timeout(p_tle);
                        break;
#endif

#endif

#if (MCA_INCLUDED == TRUE)
                    case BTU_TTYPE_MCA_CCB_RSP:
                        mca_process_timeout(p_tle);
                        break;
#endif
                    case BTU_TTYPE_USER_FUNC:
                        {
                            tUSER_TIMEOUT_FUNC  *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
                            (*p_uf)(p_tle);
                        }
                        break;

                    default:
                        i = 0;
                        handled = FALSE;

                        for (; !handled && i < BTU_MAX_REG_TIMER; i++)
                        {
                            if (btu_cb.timer_reg[i].timer_cb == NULL)
                                continue;
                            if (btu_cb.timer_reg[i].p_tle == p_tle)
                            {
                                btu_cb.timer_reg[i].timer_cb(p_tle);
                                handled = TRUE;
                            }
                        }
                        break;
                }
            }

            /* if timer list is empty stop periodic GKI timer */
            if (btu_cb.timer_queue.p_first == NULL)
            {
                GKI_stop_timer(TIMER_0);
            }
        }

#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
        if (event & TIMER_2_EVT_MASK)
        {
            btu_process_quick_timer_evt();
        }
#endif


#if (RPC_INCLUDED == TRUE)
        /* if RPC message queue event */
        if (event & RPCGEN_MSG_EVT)
        {
            if ((p_msg = (BT_HDR *) GKI_read_mbox(RPCGEN_MSG_MBOX)) != NULL)
                RPCT_RpcgenMsg(p_msg);  /* handle RPC message queue */
        }
#endif

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
        if (event & TASK_MBOX_2_EVT_MASK)
        {
            while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
            {
                bta_sys_event(p_msg); //处理上层传来的消息
            }
        }

        if (event & TIMER_1_EVT_MASK)
        {
            bta_sys_timer_update();
        }
#endif

        if (event & TIMER_3_EVT_MASK) {
            BTM_TRACE_API("Received oneshot timer event complete");
            if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                INT32 ticks_since_last_update = GKI_timer_ticks_getinitial(GKI_timer_getfirst(&btu_cb.timer_queue_oneshot));
                GKI_update_timer_list(&btu_cb.timer_queue_oneshot, ticks_since_last_update);
            }

            while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                if (p_tle->ticks != 0)
                    break;

                GKI_remove_from_timer_list(&btu_cb.timer_queue_oneshot, p_tle);

                switch (p_tle->event) {
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
                    case BTU_TTYPE_BLE_RANDOM_ADDR:
                        btm_ble_timeout(p_tle);
                        break;
#endif

                    case BTU_TTYPE_USER_FUNC:
                        {
                            tUSER_TIMEOUT_FUNC  *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
                            (*p_uf)(p_tle);
                        }
                        break;

                    default:
                        // FAIL
                        BTM_TRACE_WARNING("Received unexpected oneshot timer event:0x%x\n",
                            p_tle->event);
                        break;
                }
            }

            /* Update GKI timer with new tick value from first timer. */
            if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                if (p_tle->ticks > 0)
                  GKI_start_timer(TIMER_3, p_tle->ticks, FALSE);
            } else {
                GKI_stop_timer(TIMER_3);
            }
        }

        if (event & EVENT_MASK(APPL_EVT_7))
            break;
    }

    return(0);
}

二、应用层注册的回调函数被调用bta_sys_event:

注意这里有一堆的回调函数:(*bta_sys_cb.reg[id]->evt_hdlr), 不同的id仅处理各自id的消息回调

BTA_API void bta_sys_event(BT_HDR *p_msg)
{
    UINT8       id;
    BOOLEAN     freebuf = TRUE;

    APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event); //event = BTA_HH_API_WRITE_DEV_EVT                        

    /* 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); //Id为0x17,即BTA_ID_HH,回调函数为bta_hh_hdl_event,前面已分析
                                   //Id为0x1f,即为BTA_ID_GATTC,回调函数为bta_gattc_hdl_event,继续往后看
    }    
    else
    {
        APPL_TRACE_WARNING("BTA got unregistered event id %d", id);
    }

    if (freebuf)
    {
        GKI_freebuf(p_msg);
    }

}

三、GATT回调函数处理

最后调用的事件处理:rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg);

BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
    tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
    tBTA_GATTC_CLCB *p_clcb = NULL;
    tBTA_GATTC_RCB      *p_clreg;
    BOOLEAN             rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
    APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event));
#endif
    switch (p_msg->event)
    {
        case BTA_GATTC_API_DISABLE_EVT:
            bta_gattc_disable(p_cb);
            break;

        case BTA_GATTC_API_REG_EVT:
            bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_INT_START_IF_EVT:
            bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_API_DEREG_EVT:
            p_clreg = bta_gattc_cl_get_regcb(((tBTA_GATTC_DATA *)p_msg)->api_dereg.client_if);
            bta_gattc_deregister(p_cb, p_clreg);
            break;

        case BTA_GATTC_API_OPEN_EVT:
            bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_API_CANCEL_OPEN_EVT:
            bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_API_REFRESH_EVT:
            bta_gattc_process_api_refresh(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

#if BLE_INCLUDED == TRUE
        case BTA_GATTC_API_LISTEN_EVT:
            bta_gattc_listen(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;
        case BTA_GATTC_API_BROADCAST_EVT:
            bta_gattc_broadcast(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;
#endif

        case BTA_GATTC_ENC_CMPL_EVT:
            bta_gattc_process_enc_cmpl(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        default:
            if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
                p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA *) p_msg);
            else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT)
                p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA *) p_msg);
            else
                p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);

            if (p_clcb != NULL)
            {
                rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg); //事件处理
            }
            else
            {
                APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
            }

            break;
    }


    return rt;
}
3.1、gatt client事件处理状态机

根据gatt的状态机处理对应的事件:(*bta_gattc_action[action])(p_clcb, p_data);
处理事件最终执行的就是 bta_gattc_write

BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATTC_ST_TBL     state_table;
    UINT8               action;
    int                 i;
    BOOLEAN             rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
    tBTA_GATTC_STATE in_state = p_clcb->state;
    UINT16         in_event = event;
    APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
                      gattc_state_code(in_state),
                      in_event,
                      gattc_evt_code(in_event));
#endif


    /* look up the state table for the current state */
    state_table = bta_gattc_st_tbl[p_clcb->state];

    event &= 0x00FF;

    /* set next state */
    p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];

    /* execute action functions */
    for (i = 0; i < BTA_GATTC_ACTIONS; i++)
    {
        if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
        {
            (*bta_gattc_action[action])(p_clcb, p_data); //执行bta_gattc_write,
            if (p_clcb->p_q_cmd == p_data) {
                /* buffer is queued, don't free in the bta dispatcher.
                 * we free it ourselves when a completion event is received.
                 */
                rt = FALSE;
            }
        }
        else
        {
            break;
        }
    }

#if BTA_GATT_DEBUG == TRUE
    if (in_state != p_clcb->state)
    {
        APPL_TRACE_DEBUG("GATTC [%d] State Change: [%s] -> [%s] after Event [%s]",p_clcb->bta_conn_id,
                          gattc_state_code(in_state),
                          gattc_state_code(p_clcb->state),
                          gattc_evt_code(in_event));
    }
#endif
    return rt;
}
3.2、事件处理函数bta_gattc_write

真正写函数:status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);

void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    UINT16              handle = 0;
    tGATT_VALUE         attr = {0};
    tBTA_GATTC_OP_CMPL  op_cmpl;
    tBTA_GATT_STATUS    status = BTA_GATT_OK;

    if (bta_gattc_enqueue(p_clcb, p_data))
    {
        if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
                                          &p_data->api_write.srvc_id,
                                          &p_data->api_write.char_id,
                                          p_data->api_write.p_descr_type)) == 0)
        {
            status = BTA_GATT_ERROR;
        }
        else
        {
            attr.handle= handle;
            attr.offset = p_data->api_write.offset;
            attr.len    = p_data->api_write.len;
            attr.auth_req = p_data->api_write.auth_req;

            if (p_data->api_write.p_value)
                memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);

            status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
        }

        /* write fail */
        if (status != BTA_GATT_OK)
        {
            memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));

            op_cmpl.status  = status;
            op_cmpl.op_code = GATTC_OPTYPE_WRITE;
            op_cmpl.p_cmpl  = NULL;

            bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
        }
    }
}
3.3、写函数GATTC_Write
  • 会调用安全性检查函数gatt_security_check_start
  • 写函数会依次调用:gatt_send_write_msg、attp_send_cl_msg 、attp_build_value_cmd、- attp_cl_send_cmd、attp_send_msg_to_l2cap、L2CA_SendFixedChnlData
  • l2c_enqueue_peer_data :让数据进入到当前 ccb 的 xmit_hold_q 队列中,暂存此数据包。
  • l2cu_check_channel_congestion: 检查是否可以写
  • l2c_link_check_send_pkts : L2CAP层发送数据包
tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
{
    tGATT_STATUS status = GATT_SUCCESS;
    tGATT_CLCB      *p_clcb;
    tGATT_VALUE     *p;
    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);

    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
         ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
    {
        GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
        return GATT_ILLEGAL_PARAMETER;
    }

    if (gatt_is_clcb_allocated(conn_id))
    {
        GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
        return GATT_BUSY;
    }

    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
    {
        p_clcb->operation  = GATTC_OPTYPE_WRITE;
        p_clcb->op_subtype = type;
        p_clcb->auth_req = p_write->auth_req;

        if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
        {
            memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));

            p =  (tGATT_VALUE *)p_clcb->p_attr_buf;
            if (type == GATT_WRITE_PREPARE)
            {
                p_clcb->start_offset = p_write->offset;
                p->offset = 0;
            }

            if (gatt_security_check_start(p_clcb) == FALSE)
            {
                status = GATT_NO_RESOURCES;
            }
        }
        else
        {
            status = GATT_NO_RESOURCES;
        }

        if (status == GATT_NO_RESOURCES)
            gatt_clcb_dealloc(p_clcb);
    }
    else
    {
        status = GATT_NO_RESOURCES;
    }
    return status;
}
3.4、安全检查 gatt_security_check_start
BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
{
    tGATT_TCB           *p_tcb = p_clcb->p_tcb;
    tGATT_SEC_ACTION    gatt_sec_act;
    tBTM_BLE_SEC_ACT    btm_ble_sec_act;
    BOOLEAN             status = TRUE;
    tBTM_STATUS         btm_status;
    tGATT_SEC_ACTION    sec_act_old =  gatt_get_sec_act(p_tcb);

    gatt_sec_act = gatt_determine_sec_act(p_clcb);

    if (sec_act_old == GATT_SEC_NONE)
        gatt_set_sec_act(p_tcb, gatt_sec_act);

    switch (gatt_sec_act )
    {
        case GATT_SEC_SIGN_DATA:
            GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
            gatt_sign_data(p_clcb);
            break;
        case GATT_SEC_ENCRYPT:
        case GATT_SEC_ENCRYPT_NO_MITM:
        case GATT_SEC_ENCRYPT_MITM:
            if (sec_act_old < GATT_SEC_ENCRYPT)
            {
                GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
                gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
                btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act);
                if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED))
                {
                    GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
                    status = FALSE;
                }
            }
            if (status)
                gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
            break;
        case GATT_SEC_ENC_PENDING:
            gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
            /* wait for link encrypotion to finish */
            break;
        default:
            gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
            break;
    }

    if (status == FALSE)
    {
        gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
        gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    }

    return status;
}
3.5、写蓝牙(动作)结束
void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB   *p_clcb, UINT8 sec_act)
{
    if (p_clcb && p_clcb->p_tcb && GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb))
        gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);

    if (!sec_check_ok)
    {
        gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
    }
    else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
    {
        gatt_act_write(p_clcb, sec_act);
    }
    else if (p_clcb->operation == GATTC_OPTYPE_READ)
    {
        gatt_act_read(p_clcb, p_clcb->counter);
    }
}

四、最终处理函数:l2c_link_send_to_lower

最终 l2c_link_check_send_pkts 把数据包交给了 l2c_link_send_to_lower 来做处理,我们的音乐数据包最终也被从某个 CCB 中的队列出队列给了 l2c_link_send_to_lower。l2c_link_send_to_lower 主要做了这些事情:

  • 如果当前数据包 p_buf 的长度小于 ACL 包的最大值,sent_not_acked 加1,整个 L2CAP 的 controller_xmit_window 减1。然后通过 L2C_LINK_SEND_ACL_DATA 将此数据包发送出去。
  • 如果当前数据包 p_buf 的长度大于 ACL 包的最大值,先看看能分成几个分包(为了求的几个窗口能容下),然后窗口值减掉这些分包个数,然后将整个数据包交给 L2C_LINK_SEND_ACL_DATA (大于ACL包长度),具体分包发送由 H5(串口) 部分来负责。
static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
{
    UINT16      num_segs;
    UINT16      xmit_window, acl_data_size;

    if ((p_buf->len <= btu_cb.hcit_acl_pkt_size
#if (BLE_INCLUDED == TRUE)
        && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
        ((p_lcb->transport == BT_TRANSPORT_LE) && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size))
#else
        )
#endif
        )
    {
        if (p_lcb->link_xmit_quota == 0)
        {
#if (BLE_INCLUDED == TRUE)
            if (p_lcb->transport == BT_TRANSPORT_LE)
                l2cb.ble_round_robin_unacked++;
            else
#endif
                l2cb.round_robin_unacked++;
        }
        p_lcb->sent_not_acked++;
        p_buf->layer_specific = 0;

#if (BLE_INCLUDED == TRUE)
        if (p_lcb->transport == BT_TRANSPORT_LE)
        {
            l2cb.controller_le_xmit_window--;
            L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
        }
        else
#endif
        {
            l2cb.controller_xmit_window--;
            L2C_LINK_SEND_ACL_DATA (p_buf);
        }
    }
    else
    {
#if BLE_INCLUDED == TRUE
        if (p_lcb->transport == BT_TRANSPORT_LE)
        {
            acl_data_size = btu_cb.hcit_ble_acl_data_size;
            xmit_window = l2cb.controller_le_xmit_window;

        }
        else
#endif
        {
            acl_data_size = btu_cb.hcit_acl_data_size;
            xmit_window = l2cb.controller_xmit_window;
        }
        num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;


        /* If doing round-robin, then only 1 segment each time */
        if (p_lcb->link_xmit_quota == 0)
        {
            num_segs = 1;
            p_lcb->partial_segment_being_sent = TRUE;
        }
        else
        {
            /* Multi-segment packet. Make sure it can fit */
            if (num_segs > xmit_window)
            {
                num_segs = xmit_window;
                p_lcb->partial_segment_being_sent = TRUE;
            }

            if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
            {
                num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
                p_lcb->partial_segment_being_sent = TRUE;
            }
        }

        p_buf->layer_specific        = num_segs;
#if BLE_INCLUDED == TRUE
        if (p_lcb->transport == BT_TRANSPORT_LE)
        {
            l2cb.controller_le_xmit_window -= num_segs;
            if (p_lcb->link_xmit_quota == 0)
                l2cb.ble_round_robin_unacked += num_segs;
        }
        else
#endif
        {
            l2cb.controller_xmit_window -= num_segs;

            if (p_lcb->link_xmit_quota == 0)
                l2cb.round_robin_unacked += num_segs;
        }

        p_lcb->sent_not_acked += num_segs;
#if BLE_INCLUDED == TRUE
        if (p_lcb->transport == BT_TRANSPORT_LE)
        {
            L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
        }
        else
#endif
        {
            L2C_LINK_SEND_ACL_DATA (p_buf);
        }
    }

#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
#if (BLE_INCLUDED == TRUE)
    if (p_lcb->transport == BT_TRANSPORT_LE)
    {
        L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
                l2cb.controller_le_xmit_window,
                p_lcb->handle,
                p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
                l2cb.ble_round_robin_quota, l2cb.ble_round_robin_unacked);
    }
    else
#endif
    {
        L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
                l2cb.controller_xmit_window,
                p_lcb->handle,
                p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
                l2cb.round_robin_quota, l2cb.round_robin_unacked);
    }
#endif

    return TRUE;
}

五、hci层处理发送数据函数

l2c_link_send_to_lower 把数据交给了 L2C_LINK_SEND_ACL_DATA,L2C_LINK_SEND_ACL_DATA 其实是 bte_main_hci_send 函数,bte_main_hci_send 函数通过调用 hci 的接口 transmit_buf 来转送数据包。transmit_buf 函数作用比较简单,将此数据包入 tx_q 队列,串口(H5)的守护线程 bt_hc_worker_thread 会从 tx_q 队列中获取数据包,并将其发送。

void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
{
    UINT16 sub_event = event & BT_SUB_EVT_MASK;  /* local controller ID */

    p_msg->event = event;

    OS_PRINTF("bte_main_hci_send event 0x%2x\n",event);

    if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \
       (sub_event == LOCAL_BLE_CONTROLLER_ID))
    {
        if (bt_hc_if)
            bt_hc_if->transmit_buf((TRANSAC)p_msg, \
                                       (char *) (p_msg + 1), \
                                        p_msg->len);
        else
            GKI_freebuf(p_msg);
    }
    else
    {
        APPL_TRACE_ERROR("Invalid Controller ID. Discarding message.");
        GKI_freebuf(p_msg);
    }
}
//在hci中,数据被写入bt driver中
static int transmit_buf(TRANSAC transac, char *p_buf, int len)                                                                                                            
{         
  utils_enqueue(&tx_q, (void *) transac);                                          
  bthc_signal_event(HC_EVENT_TX);                  
  return BT_HC_STATUS_SUCCESS;                                                                                                                  
}  

六、hci层处理事件

bt_hc_worker_thread负责处理hci事件
a) 循环从队列中发送数据:p_hci_if->send(sending_msg_que[i]);
b) 发送完后,退出进程
c) 发送函数:userial_write

//external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
static void *bt_hc_worker_thread(void *arg)
{
    uint16_t events;
    HC_BT_HDR *p_msg, *p_next_msg;

    ALOGI("bt_hc_worker_thread started");
    prctl(PR_SET_NAME, (unsigned long)"bt_hc_worker", 0, 0, 0);
    tx_cmd_pkts_pending = FALSE;

    raise_priority_a2dp(TASK_HIGH_HCI_WORKER);

    while (lib_running)
    {
        pthread_mutex_lock(&hc_cb.mutex);
        while (ready_events == 0)
        {
            pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex);
        }
        events = ready_events;
        ready_events = 0;
        pthread_mutex_unlock(&hc_cb.mutex);

#ifndef HCI_USE_MCT
        if (events & HC_EVENT_RX)
        {
            p_hci_if->rcv();

            if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0))
            {
                /* Got HCI Cmd Credits from Controller.
                 * Prepare to send prior pending Cmd packets in the
                 * following HC_EVENT_TX session.
                 */
                events |= HC_EVENT_TX;
            }
        }
#endif

        if (events & HC_EVENT_PRELOAD)
        {
            userial_open(USERIAL_PORT_1);

            /* Calling vendor-specific part */
            if (bt_vnd_if)
            {
                bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL);
            }
            else
            {
                if (bt_hc_cbacks)
                    bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL);
            }
        }

        if (events & HC_EVENT_POSTLOAD)
        {
            /* Start from SCO related H/W configuration, if SCO configuration
             * is required. Then, follow with reading requests of getting
             * ACL data length for both BR/EDR and LE.
             */
            int result = -1;

            /* Calling vendor-specific part */
            if (bt_vnd_if)
                result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL);

            if (result == -1)
                p_hci_if->get_acl_max_len();
        }

        if (events & HC_EVENT_TX)
        {
            /*
             *  We will go through every packets in the tx queue.
             *  Fine to clear tx_cmd_pkts_pending.
             */
            tx_cmd_pkts_pending = FALSE;
            HC_BT_HDR * sending_msg_que[64];
            int sending_msg_count = 0;
            int sending_hci_cmd_pkts_count = 0;
            utils_lock();
            p_next_msg = tx_q.p_first;
            while (p_next_msg && sending_msg_count <
                            (int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0]))
            {
                if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
                {
                    /*
                     *  if we have used up controller's outstanding HCI command
                     *  credits (normally is 1), skip all HCI command packets in
                     *  the queue.
                     *  The pending command packets will be sent once controller
                     *  gives back us credits through CommandCompleteEvent or
                     *  CommandStatusEvent.
                     */
                    if ((tx_cmd_pkts_pending == TRUE) ||
                        (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
                    {
                        tx_cmd_pkts_pending = TRUE;
                        p_next_msg = utils_getnext(p_next_msg);
                        continue;
                    }
                    sending_hci_cmd_pkts_count++;
                }

                p_msg = p_next_msg;
                p_next_msg = utils_getnext(p_msg);
                utils_remove_from_queue_unlocked(&tx_q, p_msg);
                sending_msg_que[sending_msg_count++] = p_msg;
            }
            utils_unlock();
            int i;
            for(i = 0; i < sending_msg_count; i++)
                p_hci_if->send(sending_msg_que[i]);
            if (tx_cmd_pkts_pending == TRUE)
                BTHCDBG("Used up Tx Cmd credits");

        }

        if (events & HC_EVENT_LPM_ENABLE)
        {
            lpm_enable(TRUE);
        }

        if (events & HC_EVENT_LPM_DISABLE)
        {
            lpm_enable(FALSE);
        }

        if (events & HC_EVENT_LPM_IDLE_TIMEOUT)
        {
            lpm_wake_deassert();
        }

        if (events & HC_EVENT_LPM_ALLOW_SLEEP)
        {
            lpm_allow_bt_device_sleep();
        }

        if (events & HC_EVENT_LPM_WAKE_DEVICE)
        {
            lpm_wake_assert();
        }

        if (events & HC_EVENT_EPILOG)
        {
            /* Calling vendor-specific part */
            if (bt_vnd_if)
                bt_vnd_if->op(BT_VND_OP_EPILOG, NULL);
            else
                break;  // equivalent to HC_EVENT_EXIT
        }

        if (events & HC_EVENT_EXIT)
            break;
    }

    ALOGI("bt_hc_worker_thread exiting");
    lib_running = 0;

    pthread_exit(NULL);

    return NULL;    // compiler friendly
}

七、驱动层调用:

最终write 系统调操作driver的 fops 操作接口集:

//userial.c
uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
{
    int ret, total = 0;

    while(len != 0)
    {
#if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE)
        log_userial_tx_timing(len);
#endif
        ret = write(userial_cb.fd, p_data+total, len);
        total += ret;
        len -= ret;
    }

    return ((uint16_t)total);
}

完~~
文 | 力卉编程

相关文章

网友评论

    本文标题:蓝牙笔记 | 蓝牙协议栈应用层GATT

    本文链接:https://www.haomeiwen.com/subject/qfuioctx.html