TV发送数据到遥控器

版权声明:本文为博主原创文章,未经博主允许不得转载。
https://blog.csdn.net/huangweiqing80/article/details/82715474
下面以TV向蓝牙遥控器发送指令,让遥控器打开麦克风为例来分析

一、将数据写入内核节点
res = ioctl(hidraw_fd, HIDIOCSFEATURE(12), buf);
将数据写入/dev/hidraw节点,kernel会将数据分发到/dev/uhid节点
uhid.txt

二、HID Host Profile 部分初始化

void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask,
                    UINT8 app_id)
{
    UINT32 i;
    btif_hh_device_t *p_dev = NULL;

    if (dev_handle == BTA_HH_INVALID_HANDLE) {
        APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...",
                           __FUNCTION__, dev_handle);
        return;
    }

    for (i = 0; i < BTIF_HH_MAX_HID; i++) {
        p_dev = &btif_hh_cb.devices[i];
        if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
            p_dev->dev_handle == dev_handle) {
            // We found a device with the same handle. Must be a device reconnected.
            APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
                                                                "dev_status = %d",__FUNCTION__,
                                                                p_dev->dev_status);
            APPL_TRACE_WARNING("%s:     bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
                 p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
                 p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
                 APPL_TRACE_WARNING("%s:     attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
                                  __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);

            if(p_dev->fd<0) {
                p_dev->fd = TEMP_FAILURE_RETRY(open(dev_path, O_RDWR | O_CLOEXEC));    //dev_path="/dev/uhid"
                if (p_dev->fd < 0){
                    APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
                                                                    __FUNCTION__,strerror(errno));
                }else
                    APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
            }
            p_dev->hh_keep_polling = 1;
            p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
            break;
        }
        p_dev = NULL;
    }

创建HID事件监听线程
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);

static void *btif_hh_poll_event_thread(void *arg)
{

    btif_hh_device_t *p_dev = arg;
    APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
    struct pollfd pfds[1];
    int ret;
    pfds[0].fd = p_dev->fd;
    pfds[0].events = POLLIN;

    while(p_dev->hh_keep_polling){
        ret = TEMP_FAILURE_RETRY(poll(pfds, 1, 50));
        if (ret < 0) {
            APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __FUNCTION__, strerror(errno));
            break;
        }
        if (pfds[0].revents & POLLIN) {
            APPL_TRACE_DEBUG("btif_hh_poll_event_thread: POLLIN");
            ret = uhid_event(p_dev);
            if (ret){
                break;
            }
        }
    }

    p_dev->hh_poll_thread_id = -1;
    return 0;
}

可以看到这是一个while死循环,只有当uhid_event返回为1时,才会调出这个死循环
2.2监听事件
下面来看看ret = uhid_event(p_dev);

/* Internal function to parse the events received from UHID driver*/
static int uhid_event(btif_hh_device_t *p_dev)
{
    struct uhid_event ev;
    ssize_t ret;
    memset(&ev, 0, sizeof(ev));
    if(!p_dev)
    {
        APPL_TRACE_ERROR("%s: Device not found",__FUNCTION__)
        return -1;
    }
    ret = TEMP_FAILURE_RETRY(read(p_dev->fd, &ev, sizeof(ev)));
    if (ret == 0) {
        APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
                                                 strerror(errno));
        return -EFAULT;
    } else if (ret < 0) {
        APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __FUNCTION__,
                                                strerror(errno));
        return -errno;
    } else if (ret < (ssize_t)sizeof(ev.type)) {
        APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
                         __FUNCTION__, ret, sizeof(ev.type));
        return -EFAULT;
    }

    switch (ev.type) {
    case UHID_START:
        APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
        break;
    case UHID_STOP:
        APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
        break;
    case UHID_OPEN:
        APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
        break;
    case UHID_CLOSE:
        APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
        break;
    case UHID_OUTPUT:
        if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) {
            APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
                             __FUNCTION__, ret,
                             sizeof(ev.type) + sizeof(ev.u.output));
            return -EFAULT;
        }

        APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d"
                            ,ev.u.output.rtype, ev.u.output.size);
        //Send SET_REPORT with feature report if the report type in output event is FEATURE
        if(ev.u.output.rtype == UHID_FEATURE_REPORT)
            btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT,
                              ev.u.output.size, ev.u.output.data);
        else if(ev.u.output.rtype == UHID_OUTPUT_REPORT)
            btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT,
                              ev.u.output.size, ev.u.output.data);
        else
            btif_hh_setreport(p_dev, BTHH_INPUT_REPORT,
                              ev.u.output.size, ev.u.output.data);
           break;
    case UHID_OUTPUT_EV:
        APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
        break;
    case UHID_FEATURE:
        APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
        break;
    case UHID_FEATURE_ANSWER:
        APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
        break;

    default:
        APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
    }

    return 0;
}

2.3将数据加入消息队列
当TV向遥控器发送数据时。走的是case UHID_OUTPUT:
会调用到btif_hh_setreport语句

/*******************************************************************************
**
** Function         btif_btif_hh_setreport
**
** Description      setreport initiated from the BTIF thread context
**
** Returns          void
**
*******************************************************************************/
void btif_hh_setreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type, UINT16 size,
                            UINT8* report)
{
    BT_HDR* p_buf = create_pbuf(size, report);
    if (p_buf == NULL) {
        APPL_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, size = %d", __FUNCTION__, size);
        return;
    }
    BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
}

void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, BT_HDR *p_data)
{
    bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data);
}

static void bta_hh_snd_write_dev(UINT8 dev_handle, UINT8 t_type, UINT8 param,
                                 UINT16 data, UINT8 rpt_id, BT_HDR  *p_data)
{
    tBTA_HH_CMD_DATA *p_buf;
    UINT16          len = (UINT16) (sizeof(tBTA_HH_CMD_DATA) );

    if ((p_buf = (tBTA_HH_CMD_DATA *)GKI_getbuf(len))!= NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_HH_CMD_DATA));

        p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
        p_buf->hdr.layer_specific   = (UINT16) dev_handle;
        p_buf->t_type   = t_type;
        p_buf->data     = data;
        p_buf->param    = param;
        p_buf->p_data   = p_data;
        p_buf->rpt_id   = rpt_id;

        bta_sys_sendmsg(p_buf);
    }
}

event事件是p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
调用bta_sys_sendmsg将buff加入到btu_bta_msg_queue消息队列

void bta_sys_sendmsg(void *p_msg)
{
    // There is a race condition that occurs if the stack is shut down while
    // there is a procedure in progress that can schedule a task via this
    // message queue. This causes |btu_bta_msg_queue| to get cleaned up before
    // it gets used here; hence we check for NULL before using it.
    if (btu_bta_msg_queue)
        fixed_queue_enqueue(btu_bta_msg_queue, p_msg);
}

void fixed_queue_enqueue(fixed_queue_t *queue, void *data) {
  assert(queue != NULL);
  assert(data != NULL);

  semaphore_wait(queue->enqueue_sem);

  pthread_mutex_lock(&queue->lock);
  list_append(queue->list, data);
  pthread_mutex_unlock(&queue->lock);

  semaphore_post(queue->dequeue_sem);
}

2.4消息处理
蓝牙协议栈消息队列与处理的关联中讲过btu_bta_msg_queue消息队列对应的消息处理函数就是btu_bta_msg_ready
下面我们来看看蓝牙协议栈怎么通过btu_bta_msg_ready来讲数据发送到对端设备

void btu_bta_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
    BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
    bta_sys_event(p_msg);
}

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);
    }

}

从上面的代码,我们可以看到,在bta_sys_event()里,会根据具体的event值,移位操作得到子模块的id,再根据这个id值,得到子模块注册时候传入的evt_hdlr函数,然后调用这个函数去处理。我们再以BTA模块来分析。
2.5 evt_hdlr函数

*******************************************************************************/
void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback)
{
    tBTA_HH_API_ENABLE *p_buf;

    /* register with BTA system manager */
    bta_sys_register(BTA_ID_HH, &bta_hh_reg);

    LOG_INFO("%s sec_mask:0x%x p_cback:%p", __func__, sec_mask, p_cback);
    p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE));

    if (p_buf != NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_HH_API_ENABLE));

        p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
        p_buf->p_cback = p_cback;
        p_buf->sec_mask = sec_mask;

        bta_sys_sendmsg(p_buf);
    }
}

注册BTA系统管理bta_sys_register(BTA_ID_HH, &bta_hh_reg);
下面我们来看看bta_hh_reg这个结构体的值

static const tBTA_SYS_REG bta_hh_reg =
{
    bta_hh_hdl_event,
    BTA_HhDisable
};

再来看看tBTA_SYS_REG 这个结构体的定义

typedef struct
{
    tBTA_SYS_EVT_HDLR   *evt_hdlr;
    tBTA_SYS_DISABLE    *disable;
} tBTA_SYS_REG;

从结构体的定义可以看出,bta_hh_reg 结构体的evt_hdlr成员就是bta_hh_hdl_event
所以2.4中讲到的bta_sys_event中用到的evt_hdlr(BTA模块)就是bta_hh_hdl_event

BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
{
    UINT8           index = BTA_HH_IDX_INVALID;
    tBTA_HH_DEV_CB *p_cb = NULL;

    switch (p_msg->event)
    {
        case BTA_HH_API_ENABLE_EVT:
            bta_hh_api_enable((tBTA_HH_DATA *) p_msg);
            break;

        case BTA_HH_API_DISABLE_EVT:
            bta_hh_api_disable();
            break;

        case BTA_HH_DISC_CMPL_EVT:          /* disable complete */
            bta_hh_disc_cmpl();
            break;

        default:
            /* all events processed in state machine need to find corresponding
                CB before proceed */
            if (p_msg->event == BTA_HH_API_OPEN_EVT)
            {
                index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
            }
            else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)
            {
                /* if add device */
                if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
                {
                    index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);
                }
                else /* else remove device by handle */
                {
                    index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
// btla-specific ++
                    /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination
                      * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting
                      * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN.
                      * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we
                      * force the index to be IDX_INVALID
                      */
                    if ((index != BTA_HH_IDX_INVALID) &&
                        (bta_hh_cb.kdev[index].in_use == FALSE)) {
                        index = BTA_HH_IDX_INVALID;
                    }
// btla-specific --
                }
            }
            else if (p_msg->event == BTA_HH_INT_OPEN_EVT)
            {
                index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
            }
            else
                index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);

            if (index != BTA_HH_IDX_INVALID)
                p_cb = &bta_hh_cb.kdev[index];

#if BTA_HH_DEBUG
            APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index);
#endif
            bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg);
    }
    return (TRUE);
}

我们在2.3中bta_hh_snd_write_dev函数知道我们要处理的事件是BTA_HH_API_WRITE_DEV_EVT;
所以在这个函数中处理我们的事件的case是进入到default中;default case首先要根据index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);找到index索引,然后再找到对应的p_cb = &bta_hh_cb.kdev[index];之后再调用状态机bta_hh_sm_execute进行处理
下面我们来看看这个状态机处理函数

/*******************************************************************************
**
** Function         bta_hh_sm_execute
**
** Description      State machine event handling function for HID Host
**
**
** Returns          void
**
*******************************************************************************/
void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
{
    tBTA_HH_ST_TBL  state_table;
    UINT8           action;
    tBTA_HH         cback_data;
    tBTA_HH_EVT     cback_event = 0;
#if BTA_HH_DEBUG == TRUE
    tBTA_HH_STATE   in_state ;
    UINT16          debug_event = event;
#endif

    memset(&cback_data, 0, sizeof(tBTA_HH));

    /* handle exception, no valid control block was found */
    if (!p_cb)
    {
        /* BTA HH enabled already? otherwise ignore the event although it's bad*/
        if (bta_hh_cb.p_cback != NULL)
        {
            switch (event)
            {
            /* no control block available for new connection */
            case BTA_HH_API_OPEN_EVT:
                cback_event = BTA_HH_OPEN_EVT;
                /* build cback data */
                bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
                cback_data.conn.status  = BTA_HH_ERR_DB_FULL;
                cback_data.conn.handle  = BTA_HH_INVALID_HANDLE;
                break;
            /* DB full, BTA_HhAddDev */
            case BTA_HH_API_MAINT_DEV_EVT:
                cback_event = p_data->api_maintdev.sub_event;

                if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT)
                {
                    bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
                    cback_data.dev_info.status    = BTA_HH_ERR_DB_FULL;
                    cback_data.dev_info.handle    = BTA_HH_INVALID_HANDLE;
                }
                else
                {
                    cback_data.dev_info.status    = BTA_HH_ERR_HDL;
                    cback_data.dev_info.handle    = (UINT8)p_data->api_maintdev.hdr.layer_specific;
                }
                break;
            case BTA_HH_API_WRITE_DEV_EVT:
                cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
                        BTA_HH_FST_TRANS_CB_EVT;
                if (p_data->api_sndcmd.p_data != NULL)
                {
                    GKI_freebuf(p_data->api_sndcmd.p_data);
                }
                if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
                    p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
                    p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
                {
                    cback_data.dev_status.status = BTA_HH_ERR_HDL;
                    cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                }
                else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
                    p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
                {
                    cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                    cback_data.hs_data.status = BTA_HH_ERR_HDL;
                    /* hs_data.rsp_data will be all zero, which is not valid value */
                }
                else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL &&
                         p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
                {
                    cback_data.status = BTA_HH_ERR_HDL;
                    cback_event = BTA_HH_VC_UNPLUG_EVT;
                }
                else
                    cback_event = 0;
                break;

            case BTA_HH_API_CLOSE_EVT:
                cback_event = BTA_HH_CLOSE_EVT;

                cback_data.dev_status.status = BTA_HH_ERR_HDL;
                cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                break;

            default:
                /* invalid handle, call bad API event */
                APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific);
                /* Free the callback buffer now */
                if (p_data != NULL && p_data->hid_cback.p_data != NULL)
                {
                    GKI_freebuf(p_data->hid_cback.p_data);
                    p_data->hid_cback.p_data = NULL;
                }
                break;
            }
           if (cback_event)
               (* bta_hh_cb.p_cback)(cback_event, &cback_data);
        }
    }
    /* corresponding CB is found, go to state machine */
    else
    {
#if BTA_HH_DEBUG == TRUE
        in_state = p_cb->state;
        APPL_TRACE_EVENT("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
                          in_state, bta_hh_state_code(in_state),
                          bta_hh_evt_code(debug_event));
#endif

        if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST))
        {
            APPL_TRACE_ERROR("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
                              p_cb->state,event);
            return;
        }
        state_table = bta_hh_st_tbl[p_cb->state - 1];

        event &= 0xff;

        p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;

        if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
        {
            (*bta_hh_action[action])(p_cb, p_data);
        }

#if BTA_HH_DEBUG == TRUE
        if (in_state != p_cb->state)
        {
            APPL_TRACE_DEBUG("HH State Change: [%s] -> [%s] after Event [%s]",
                          bta_hh_state_code(in_state),
                          bta_hh_state_code(p_cb->state),
                          bta_hh_evt_code(debug_event));
        }
#endif
    }

    return;
}

这个状态机逻辑是先根据当前状态获取到对应的状态表,再根据发过来的事件获取当前状态下该事件的处理函数,同时将状态切到对应的下一个状态。从上面的函数中我们可以看到这个状态机的状态表bta_hh_st_tbl如下:

const tBTA_HH_ST_TBL bta_hh_st_tbl[] =
{
    bta_hh_st_idle,
    bta_hh_st_w4_conn,
    bta_hh_st_connected
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
    ,bta_hh_st_w4_sec
#endif
};

当前状态是已连接,那么对应的状态表为bta_hh_st_connected,如下:

const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] =
{
/* Event                          Action                 Next state */
/* BTA_HH_API_OPEN_EVT      */    {BTA_HH_IGNORE,        BTA_HH_CONN_ST    },
/* BTA_HH_API_CLOSE_EVT     */    {BTA_HH_API_DISC_ACT,  BTA_HH_CONN_ST    },
/* BTA_HH_INT_OPEN_EVT      */    {BTA_HH_OPEN_ACT,      BTA_HH_CONN_ST    },
/* BTA_HH_INT_CLOSE_EVT     */    {BTA_HH_CLOSE_ACT,     BTA_HH_IDLE_ST    },
/* BTA_HH_INT_DATA_EVT      */    {BTA_HH_DATA_ACT,      BTA_HH_CONN_ST    },
/* BTA_HH_INT_CTRL_DATA     */    {BTA_HH_CTRL_DAT_ACT,  BTA_HH_CONN_ST    },
/* BTA_HH_INT_HANDSK_EVT    */    {BTA_HH_HANDSK_ACT,    BTA_HH_CONN_ST    },
/* BTA_HH_SDP_CMPL_EVT      */    {BTA_HH_IGNORE,         BTA_HH_CONN_ST       },
/* BTA_HH_API_WRITE_DEV_EVT */    {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST    },
/* BTA_HH_API_GET_DSCP_EVT  */    {BTA_HH_GET_DSCP_ACT,  BTA_HH_CONN_ST    },
/* BTA_HH_API_MAINT_DEV_EVT */    {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST    },
/* BTA_HH_OPEN_CMPL_EVT        */    {BTA_HH_IGNORE,         BTA_HH_CONN_ST    }
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
/* BTA_HH_GATT_CLOSE_EVT    */    ,{BTA_HH_GATT_CLOSE,    BTA_HH_IDLE_ST    }
/* BTA_HH_GATT_OPEN_EVT    */    ,{BTA_HH_IGNORE,        BTA_HH_CONN_ST    }
/* BTA_HH_START_ENC_EVT    */    ,{BTA_HH_IGNORE,        BTA_HH_CONN_ST     }
/* BTA_HH_ENC_CMPL_EVT     */    ,{BTA_HH_IGNORE,        BTA_HH_CONN_ST     }
/* READ_CHAR_CMPL_EVT */         ,{BTA_HH_LE_READ_CHAR,  BTA_HH_CONN_ST     }
/* WRITE_CHAR_CMPL_EVT*/         ,{BTA_HH_LE_WRITE,      BTA_HH_CONN_ST     }
/* READ_DESCR_CMPL_EVT */        ,{BTA_HH_LE_READ_DESCR, BTA_HH_CONN_ST     }   /* do not currently read any descr when connection up */
/* WRITE_DESCR_CMPL_EVT */       ,{BTA_HH_WRITE_DESCR,   BTA_HH_CONN_ST     }   /* do not currently write any descr when connection up */
/* SCPP_UPDATE_EVT */            ,{BTA_HH_LE_UPDATE_SCPP,  BTA_HH_CONN_ST   }
/* BTA_HH_GATT_ENC_CMPL_EVT */   ,{BTA_HH_IGNORE,        BTA_HH_CONN_ST     }
#endif
};

从表中我们可以看到我们的Event是BTA_HH_WRITE_DEV_ACT,对应的Action是BTA_HH_WRITE_DEV_ACT,对应的Next state为BTA_HH_W4_CONN_ST。
我们看看BTA_HH_WRITE_DEV_ACT的定义,在一个枚举中定义的,对应的值是8

/* state machine action enumeration list */
enum
{
    BTA_HH_API_DISC_ACT,        /* HID host process API close action    */
    BTA_HH_OPEN_ACT,            /* HID host process BTA_HH_EVT_OPEN     */
    BTA_HH_CLOSE_ACT,           /* HID host process BTA_HH_EVT_CLOSE    */
    BTA_HH_DATA_ACT,            /* HID host receive data report         */
    BTA_HH_CTRL_DAT_ACT,
    BTA_HH_HANDSK_ACT,
    BTA_HH_START_SDP,           /* HID host inquery                     */
    BTA_HH_SDP_CMPL,
    BTA_HH_WRITE_DEV_ACT,
    BTA_HH_GET_DSCP_ACT,
    BTA_HH_MAINT_DEV_ACT,
    BTA_HH_OPEN_CMPL_ACT,
    BTA_HH_OPEN_FAILURE,
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
    BTA_HH_GATT_CLOSE,
    BTA_HH_LE_OPEN_FAIL,
    BTA_HH_GATT_OPEN,
    BTA_HH_W4_LE_READ_CHAR,
    BTA_HH_LE_READ_CHAR,
    BTA_HH_W4_LE_READ_DESCR,
    BTA_HH_LE_READ_DESCR,
    BTA_HH_W4_LE_WRITE,
    BTA_HH_LE_WRITE,
    BTA_HH_WRITE_DESCR,
    BTA_HH_START_SEC,
    BTA_HH_SEC_CMPL,
    BTA_HH_LE_UPDATE_SCPP,
    BTA_HH_GATT_ENC_CMPL,
#endif
    BTA_HH_NUM_ACTIONS
};

我们看BTA_HH_WRITE_DEV_ACT对应的函数,到bta_hh_action中查,在bta_hh_main.c.c中:

/* action functions */
const tBTA_HH_ACTION bta_hh_action[] =
{
    bta_hh_api_disc_act,
    bta_hh_open_act,
    bta_hh_close_act,
    bta_hh_data_act,
    bta_hh_ctrl_dat_act,
    bta_hh_handsk_act,
    bta_hh_start_sdp,
    bta_hh_sdp_cmpl,
    bta_hh_write_dev_act,
    bta_hh_get_dscp_act,
    bta_hh_maint_dev_act,
    bta_hh_open_cmpl_act,
    bta_hh_open_failure
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
    ,bta_hh_gatt_close
    ,bta_hh_le_open_fail
    ,bta_hh_gatt_open
    ,bta_hh_w4_le_read_char_cmpl
    ,bta_hh_le_read_char_cmpl
    ,bta_hh_w4_le_read_descr_cmpl
    ,bta_hh_le_read_descr_cmpl
    ,bta_hh_w4_le_write_cmpl
    ,bta_hh_le_write_cmpl
    ,bta_hh_le_write_char_descr_cmpl
    ,bta_hh_start_security
    ,bta_hh_security_cmpl
    ,bta_hh_le_update_scpp
    ,bta_hh_le_notify_enc_cmpl
#endif
};

我们同样找到枚举值为8的函数为bta_hh_write_dev_act,所以我们的事件BTA_HH_WRITE_DEV_ACT对应的处理函数是bta_hh_write_dev_act
下面bta_hh_write_dev_act函数的调用流程是
bta_hh_write_dev_act ==>bta_hh_le_write_dev_act ==>bta_hh_le_write_rpt ==>BTA_GATTC_WriteCharValue
下面我们来看看BTA_GATTC_WriteCharValue函数的定义

/*******************************************************************************
**
** Function         BTA_GATTC_WriteCharValue
**
** Description      This function is called to write characteristic value.
**
** Parameters       conn_id - connection ID.
**                    p_char_id - characteristic ID to write.
**                    write_type - type of write.
**                  len: length of the data to be written.
**                  p_value - the value to be written.
**
** Returns          None
**
*******************************************************************************/
void BTA_GATTC_WriteCharValue ( UINT16 conn_id,
                                tBTA_GATTC_CHAR_ID *p_char_id,
                                tBTA_GATTC_WRITE_TYPE  write_type,
                                UINT16 len,
                                UINT8 *p_value,
                                tBTA_GATT_AUTH_REQ auth_req)
{
    tBTA_GATTC_API_WRITE  *p_buf;

    if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len);

        p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
        p_buf->hdr.layer_specific = conn_id;
        p_buf->auth_req = auth_req;

        memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
        memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));

        p_buf->write_type = write_type;
        p_buf->len = len;

        if (p_value && len > 0)
        {
            p_buf->p_value = (UINT8 *)(p_buf + 1);
            memcpy(p_buf->p_value, p_value, len);
        }

        bta_sys_sendmsg(p_buf);
    }
    return;
}

这里有调用bta_sys_sendmsg将数据加入到消息队列,但此时的事件是p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
这里有重新走了一遍,但此时走的是BTA_GATTC子系统了。
可以参考Android蓝牙源码分析——BTA层消息分发
Android蓝牙源码分析——Gatt写设备
这里跟Android蓝牙源码分析——Gatt写设备一文中类似,在Android蓝牙源码分析——Gatt写设备一文中讲到最后数据被丢到L2CAP层处理进行处理,这里我在键attp_cl_send_cmd最后的调用流程分析一下
attp_cl_send_cmd==>attp_send_msg_to_l2cap ==>L2CA_SendFixedChnlData ==>l2c_link_check_send_pkts ==>l2c_link_send_to_lower ==>bte_main_hci_send ==>hci->transmit_downward(event, p_msg);
可以看到数据最后是通过HCI层发送出去的

猜你喜欢

转载自blog.csdn.net/huangweiqing80/article/details/82715474