一、 基础知识介绍

1.缩略语

BTIF: Bluetooth Interface

BTU : Bluetooth Upper Layer

BTM: Bluetooth Manager

BTE: Bluetooth embedded system

BTA :Blueetooth application layer

CO: call out\CI: call in

HF : Handsfree Profile

HH: HID Host Profile

HL: Health Device Profile

V:audio\vidio

ag: audio gateway

r: audio/video registration

gattc: GATT client

BLE: Bluetooth Low Energy

2.蓝牙协议栈框架图:

1.基带层(BB)提供了两种不同的物理链路(同步面向连接链路SCO Synchronous Connection Oriented和异步无连接链路ACL Asynchronous Connection Less),负责跳频和蓝牙数据及信息帧的传输,且对所有类型的数据包提供了不同层次的前向纠错码(FEC Frequency Error Correction)或循环沉余度差错校验(CTC Cyclic Redundancy Check);

2.LMP层负责两个或多个设备链路的建立和拆除及链路的安全和控制,如鉴权和加密、控制和协商基带包的大小等,它为上层软件模块提供了不同的访问入口;

3.蓝牙主机控制器接口HCI (Host Controller Interface)由基带控制器、连接管理器、控制和事件寄存器等组成。它是蓝牙协议中软硬件之间的接口,它提供了一个调用下层BB、LM、状态和控制寄存器等硬件的统一命令,上、下两个模块接口之间的消息和数据的传递必须通过HCI的解释才能进行。HCI层以上的协议软件实体运行在主机上,而HCI以下的功能由蓝牙设备耒完成,二者之间通过传输层进行交互。

4.中间协议层由逻辑链路控制与适配协议L2CAP (Logical Link Control and Adaptation Protocol)、服务发现协议 SDP (Service Discovery Protocol)、串口仿真协议或称线缆替换协议 RFCOM 和二进制电话控制协议 TCS (Telephony Control protocol Spectocol)组成。

L2CAP 是蓝牙协议栈的核心组成部分,也是其它协议实现的基础。它位于基带之上,向上层提供面向连接的和无连接的数据服务。它主要完成数据的拆装、服务质量控制,协议的复用、分组的分割和重组(Segmentation And Reassembly)及组提取等功能。L2CAP允许高达64KB的数据分组。

5.SDP是一个基于客户/服务器结构的协议。它工作在 L2CAP层之上,为上层应用程序提供一种机制来发现可用的服务及其属性,而服务的属性包括服务的类型及该服务所需的机制或协议信息。

6.RFCOMM 是一个仿真有线链路的无线数据仿真协议,符合ETSI 标准的 TS 07.10串口仿真协议。它在蓝牙基带上仿真RS-232的控制和数据信号,为原先使用串行连接的上层业务提供传送能力。

7.TCS是一个基于 ITU-T Q.931 建议的采用面向比特的协议,它定义了用于蓝牙设备之间建立语音和数据呼叫的控制信令(Call Control Signalling),并负责处理蓝牙设备组的移动管理过程。

整个bluedroid可以分为两大模块:BTIF,BTE

BTIF:提供bluedroid对外的接口

BTE:bluedroid的内部处理,又细分为BTA,BTU,BTM和HCI

BTA:bluedroid中各profile的逻辑实现和处理

BTU:承接BTA与HCI

BTM:蓝牙配对与链路管理

HCI:读取或写入数据到蓝牙hw

二、代码分析(写hidraw节点数据流程):

1.初始化:

external\bluetooth\bluedroid\btif\src\bluetooth.c 

static const bt_interface_t bluetoothInterface = {
sizeof(bluetoothInterface),
init,
enable,
disable,
cleanup,
get_adapter_properties,
get_adapter_property,
set_adapter_property,
get_remote_device_properties,
get_remote_device_property,
set_remote_device_property,
get_remote_service_record,
get_remote_services,
start_discovery,
cancel_discovery,
create_bond,
remove_bond,
cancel_bond,
get_connection_state,
pin_reply,
ssp_reply,
get_profile_interface, //根据profile获得对应的接口
dut_mode_configure,
dut_mode_send,
#if BLE_INCLUDED == TRUE
le_test_mode,
#else
NULL,
#endif
config_hci_snoop_log,
set_os_callouts,
read_energy_info,
}; ......
if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
        return btif_hh_get_interface(); //获得HID Host Profile 

external\bluetooth\bluedroid\btif\src\btif_hh.c

static const bthh_interface_t bthhInterface = {
sizeof(bthhInterface),
init,
connect,
disconnect,
virtual_unplug,
set_info,
get_protocol,
set_protocol,
// get_idle_time,
// set_idle_time,
get_report,
set_report,
send_data,
cleanup,
};

init函数里注册传入的回调函数:

/*******************************************************************************
**
** Function btif_hh_init
**
** Description initializes the hh interface
**
** Returns bt_status_t
**
*******************************************************************************/
static bt_status_t init( bthh_callbacks_t* callbacks )
{
UINT32 i;
BTIF_TRACE_EVENT("%s", __FUNCTION__); bt_hh_callbacks = callbacks;
memset(&btif_hh_cb, , sizeof(btif_hh_cb));
for (i = ; i < BTIF_HH_MAX_HID; i++){
btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
}
/* Invoke the enable service API to the core to set the appropriate service_id */
btif_enable_service(BTA_HID_SERVICE_ID);
return BT_STATUS_SUCCESS;
}

external\bluetooth\bluedroid\btif\src\btif_core.c

/*******************************************************************************
**
** Function btif_enable_service
**
** Description Enables the service 'service_ID' to the service_mask.
** Upon BT enable, BTIF core shall invoke the BTA APIs to
** enable the profiles
**
** Returns bt_status_t
**
*******************************************************************************/
bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id)
{
tBTA_SERVICE_ID *p_id = &service_id; /* If BT is enabled, we need to switch to BTIF context and trigger the
* enable for that profile
*
* Otherwise, we just set the flag. On BT_Enable, the DM will trigger
* enable for the profiles that have been enabled */ btif_enabled_services |= (1 << service_id); BTIF_TRACE_DEBUG("%s: current services:0x%x", __FUNCTION__, btif_enabled_services); if (btif_is_enabled())
{ //注册回调,发送消息
btif_transfer_context(btif_dm_execute_service_request,
BTIF_DM_ENABLE_SERVICE,
(char*)p_id, sizeof(tBTA_SERVICE_ID), NULL);
} return BT_STATUS_SUCCESS;
}

2.创建线程和准备启动调度:

/*******************************************************************************
**
** Function btif_init_bluetooth
**
** Description Creates BTIF task and prepares BT scheduler for startup
**
** Returns bt_status_t
**
*******************************************************************************/ bt_status_t btif_init_bluetooth()
{
UINT8 status;
btif_config_init();
bte_main_boot_entry(); /* As part of the init, fetch the local BD ADDR */
memset(&btif_local_bd_addr, , sizeof(bt_bdaddr_t));
btif_fetch_local_bdaddr(&btif_local_bd_addr); /* start btif task */
status = GKI_create_task(btif_task, BTIF_TASK, BTIF_TASK_STR,
(UINT16 *) ((UINT8 *)btif_task_stack + BTIF_TASK_STACK_SIZE),
sizeof(btif_task_stack)); if (status != GKI_SUCCESS)
return BT_STATUS_FAIL; return BT_STATUS_SUCCESS;
}

处理线程函数:

/*******************************************************************************
**
** Function btif_task
**
** Description BTIF task handler managing all messages being passed
** Bluetooth HAL and BTA.
**
** Returns void
**
*******************************************************************************/ static void btif_task(UINT32 params)
{
UINT16 event;
BT_HDR *p_msg;
UNUSED(params); BTIF_TRACE_DEBUG("btif task starting"); btif_associate_evt(); for(;;)
{
/* wait for specified events */
event = GKI_wait(0xFFFF, ); /*
* Wait for the trigger to init chip and stack. This trigger will
* be received by btu_task once the UART is opened and ready
*/
if (event == BT_EVT_TRIGGER_STACK_INIT)
{
BTIF_TRACE_DEBUG("btif_task: received trigger stack init event");
#if (BLE_INCLUDED == TRUE)
btif_dm_load_ble_local_keys();
#endif
BTA_EnableBluetooth(bte_dm_evt);
} /*
* Failed to initialize controller hardware, reset state and bring
* down all threads
*/
if (event == BT_EVT_HARDWARE_INIT_FAIL)
{
BTIF_TRACE_DEBUG("btif_task: hardware init failed");
bte_main_disable();
btif_queue_release();
GKI_task_self_cleanup(BTIF_TASK);
bte_main_shutdown();
btif_dut_mode = ;
btif_core_state = BTIF_CORE_STATE_DISABLED;
HAL_CBACK(bt_hal_cbacks,adapter_state_changed_cb,BT_STATE_OFF);
break;
} if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
break; if(event & TASK_MBOX_1_EVT_MASK)
{
while((p_msg = GKI_read_mbox(BTU_BTIF_MBOX)) != NULL) //读取消息
{
BTIF_TRACE_VERBOSE("btif task fetched event %x", p_msg->event); switch (p_msg->event)
{
case BT_EVT_CONTEXT_SWITCH_EVT:
btif_context_switched(p_msg); //传递消息给注册的回调函数
break;
default:
BTIF_TRACE_ERROR("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
break;
} GKI_freebuf(p_msg);
}
}
} btif_disassociate_evt(); BTIF_TRACE_DEBUG("btif task exiting");
}

之前先开启了蓝牙服务:

/*******************************************************************************
**
** Function BTA_EnableBluetooth
**
** Description Enables bluetooth service. This function must be
** called before any other functions in the BTA API are called.
**
**
** Returns tBTA_STATUS
**
*******************************************************************************/
tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback)
{ tBTA_DM_API_ENABLE *p_msg; /* Bluetooth disabling is in progress */
if (bta_dm_cb.disabling)
return BTA_FAILURE; memset(&bta_dm_cb, , sizeof(bta_dm_cb)); bta_sys_register (BTA_ID_DM, &bta_dm_reg );
bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg ); /* if UUID list is not provided as static data */
bta_sys_eir_register(bta_dm_eir_update_uuid); if ((p_msg = (tBTA_DM_API_ENABLE *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE))) != NULL)
{
p_msg->hdr.event = BTA_DM_API_ENABLE_EVT;
p_msg->p_sec_cback = p_cback;
bta_sys_sendmsg(p_msg);
return BTA_SUCCESS;
}
return BTA_FAILURE; }

external\bluetooth\bluedroid\btif\src\btif_dm.c

根据消息请求对应服务:

void btif_dm_execute_service_request(UINT16 event, char *p_param)
{
BOOLEAN b_enable = FALSE;
bt_status_t status;
if (event == BTIF_DM_ENABLE_SERVICE)
{
b_enable = TRUE;
}
status = btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable); //执行服务请求
if (status == BT_STATUS_SUCCESS)
{
bt_property_t property;
bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS]; /* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
sizeof(local_uuids), local_uuids);
btif_storage_get_adapter_property(&property);
HAL_CBACK(bt_hal_cbacks, adapter_properties_cb,
BT_STATUS_SUCCESS, , &property);
}
return;
}

执行A2DP/HID/HFP等服务

bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
BOOLEAN b_enable)
{
/* Check the service_ID and invoke the profile's BT state changed API */
switch (service_id)
{
case BTA_HFP_SERVICE_ID:
case BTA_HSP_SERVICE_ID:
{
btif_hf_execute_service(b_enable);
}break;
case BTA_A2DP_SERVICE_ID:
{
btif_av_execute_service(b_enable);
}break;
case BTA_HID_SERVICE_ID:
{
btif_hh_execute_service(b_enable);
}break;
case BTA_HFP_HS_SERVICE_ID:
{
btif_hf_client_execute_service(b_enable);
}break;
case BTA_MAP_SERVICE_ID:
{
btif_mce_execute_service(b_enable);
}break;
default:
BTIF_TRACE_ERROR("%s: Unknown service being enabled", __FUNCTION__);
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}

external\bluetooth\bluedroid\btif\src\btif_hh.c

启动/关闭 HID服务

/*******************************************************************************
**
** Function btif_hh_execute_service
**
** Description Initializes/Shuts down the service
**
** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
**
*******************************************************************************/
bt_status_t btif_hh_execute_service(BOOLEAN b_enable)
{
if (b_enable)
{
/* Enable and register with BTA-HH */
BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt);
}
else {
/* Disable HH */
BTA_HhDisable();
}
return BT_STATUS_SUCCESS;
}

external\bluetooth\bluedroid\bta\hh\bta_hh_api.c

/*******************************************************************************
**
** Function BTA_HhEnable
**
** Description Enable the HID host. This function must be called before
** any other functions in the HID host API are called. When the
** enable operation is complete the callback function will be
** called with BTA_HH_ENABLE_EVT.
**
**
** Returns void
**
*******************************************************************************/
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); //注册主处理函数 APPL_TRACE_ERROR("Calling BTA_HhEnable");
p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE)); if (p_buf != NULL)
{
memset(p_buf, , 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);
}
}

external\bluetooth\bluedroid\btif\co\bta_hh_co.c

HID Host Profile 部分初始化,创建HID事件监听线程:btif_hh_poll_event_thread

/*******************************************************************************
**
** Function bta_hh_co_open
**
** Description When connection is opened, this call-out function is executed
** by HH to do platform specific initialization.
**
** Returns void.
*******************************************************************************/
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 = ; 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[], p_dev->bd_addr.address[], p_dev->bd_addr.address[],
p_dev->bd_addr.address[], p_dev->bd_addr.address[]);
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<) {
p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
if (p_dev->fd < ){
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 = ;
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
break;
}
p_dev = NULL;
} if (p_dev == NULL) {
// Did not find a device reconnection case. Find an empty slot now.
for (i = ; i < BTIF_HH_MAX_HID; i++) {
if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
p_dev = &btif_hh_cb.devices[i];
p_dev->dev_handle = dev_handle;
p_dev->attr_mask = attr_mask;
p_dev->sub_class = sub_class;
p_dev->app_id = app_id;
p_dev->local_vup = FALSE; btif_hh_cb.device_num++;
// This is a new device,open the uhid driver now.
p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
if (p_dev->fd < ){
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 = ;
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
} break;
}
}
} if (p_dev == NULL) {
APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __FUNCTION__);
return;
} p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
APPL_TRACE_DEBUG("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
}

poll监听HID驱动的事件:

/*******************************************************************************
**
** Function btif_hh_poll_event_thread
**
** Description the polling thread which polls for event from UHID driver
**
** Returns void
**
*******************************************************************************/
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[];
int ret;
pfds[].fd = p_dev->fd;
pfds[].events = POLLIN; while(p_dev->hh_keep_polling){
ret = poll(pfds, , );
if (ret < ) {
APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __FUNCTION__, strerror(errno));
break;
}
if (pfds[].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 = -;
return ;
}

解析HID驱动的事件:

/* 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, , sizeof(ev));
if(!p_dev)
{
APPL_TRACE_ERROR("%s: Device not found",__FUNCTION__)
return -;
}
ret = read(p_dev->fd, &ev, sizeof(ev));
if (ret == ) {
APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
strerror(errno));
return -EFAULT;
} else if (ret < ) {
APPL_TRACE_ERROR("%s:Cannot read uhid-cdev: %s", __FUNCTION__,
strerror(errno));
return -errno;
} else if (ret != sizeof(ev)) {
APPL_TRACE_ERROR("%s:Invalid size read from uhid-dev: %ld != %lu",
__FUNCTION__, ret, sizeof(ev));
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:
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 ;
}

--->

/*******************************************************************************
**
** Function btif_btif_hh_setreport
**
** Description setreport initiated from the BTIF thread context
**
** Returns void
**
*******************************************************************************/
#define COMMAND_PATCH
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;
} #ifdef COMMAND_PATCH
if(report[] != 0x5B) /*判断report id!=0x5B,执行默认的request,需要response*/
BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
else{ /*判断report id==0x5B,发送command,不需要response*/
BD_ADDR* bda = (BD_ADDR*)&p_dev->bd_addr;
BTIF_TRACE_DEBUG("Send Command Size %",size);
p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
BTA_HhSendData(p_dev->dev_handle,*bda,p_buf);
}
#else
BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
#endif }

发送数据到HID设备:

/*******************************************************************************
**
** Function BTA_HhSendData
**
** Description This function send DATA transaction to HID device.
**
** Parameter dev_handle: device handle
** dev_bda: remote device address
** p_data: data to be sent in the DATA transaction; or
** the data to be write into the Output Report of a LE HID
** device. The report is identified the report ID which is
** the value of the byte (UINT8 *)(p_buf + 1) + p_buf->offset.
** p_data->layer_specific needs to be set to the report type,
** it can be OUTPUT report, or FEATURE report.
**
** Returns void
**
*******************************************************************************/
void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_data)
{
UNUSED(dev_bda);
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT)
{
APPL_TRACE_ERROR("ERROR! Wrong report type! Write Command only valid for output report!");
return;
}
#endif
bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, (UINT8)p_data->layer_specific, , , p_data);
}

-->

/*******************************************************************************
**
** Function bta_hh_snd_write_dev
**
*******************************************************************************/
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, , 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); //发送数据到hid处理进程
}
}

external\bluetooth\bluedroid\bta\hh\bta_hh_main.c

BTA_HhEnable时注册的HID主处理函数进行数据接收和处理:

/*******************************************************************************
**
** Function bta_hh_hdl_event
**
** Description HID host main event handling function.
**
**
** Returns void
**
*******************************************************************************/
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);
}

HID状态机事件处理函数

/*******************************************************************************
**
** 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); //各事件处理函数列表,写节点为action(8)-> bta_hh_write_dev_act
} #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;
}

--->

/*******************************************************************************
**
** Function bta_hh_write_dev_act
**
** Description Write device action. can be SET/GET/DATA transaction.
**
** Returns void
**
*******************************************************************************/
void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
BTA_HH_FST_TRANS_CB_EVT; #if BTA_HH_LE_INCLUDED == TRUE
if (p_cb->is_le_device){
    //调用到这里t_type为10(HID_TRANS_DATA)即开始通过 BTA_HhSendData 函数发送数据方式:
APPL_TRACE_DEBUG("bta_hh_le_write_dev_act : p_data->api_sndcmd.t_type = %d ",p_data->api_sndcmd.t_type);
bta_hh_le_write_dev_act(p_cb, p_data);
}
else
#endif
{ cbdata.handle = p_cb->hid_handle; /* match up BTE/BTA report/boot mode def */
if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL)
{
p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\
HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE;
} if (HID_HostWriteDev (p_cb->hid_handle,
p_data->api_sndcmd.t_type,
p_data->api_sndcmd.param,
p_data->api_sndcmd.data,
p_data->api_sndcmd.rpt_id,
p_data->api_sndcmd.p_data) != HID_SUCCESS)
{
APPL_TRACE_ERROR("HID_HostWriteDev Error ");
cbdata.status = BTA_HH_ERR; if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
p_data->api_sndcmd.t_type != HID_TRANS_DATA)
(* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
(* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
}
else
{ switch(p_data->api_sndcmd.t_type)
{
case HID_TRANS_SET_PROTOCOL:
/* fall through */
case HID_TRANS_GET_REPORT:
/* fall through */
case HID_TRANS_SET_REPORT:
/* fall through */
case HID_TRANS_GET_PROTOCOL:
/* fall through */
case HID_TRANS_GET_IDLE:
/* fall through */
case HID_TRANS_SET_IDLE:/* set w4_handsk event name for callback function use */
p_cb->w4_evt = event;
break;
case HID_TRANS_DATA: /* output report */
/* fall through */
case HID_TRANS_CONTROL:
/* no handshake event will be generated */
/* if VC_UNPLUG is issued, set flag */
if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
p_cb->vp = TRUE; break;
/* currently not expected */
case HID_TRANS_DATAC:
default:
APPL_TRACE_DEBUG("bta_hh_write_dev_act:: cmd type = %d",
p_data->api_sndcmd.t_type);
break;
} /* if not control type transaction, notify PM for energy control */
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
{
/* inform PM for mode change */
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND)
{
bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
{
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
} }
return;
}

--->

/*******************************************************************************
**
** Function bta_hh_le_write_dev_act
**
** Description Write LE device action. can be SET/GET/DATA transaction.
**
** Returns void
**
*******************************************************************************/
void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
switch(p_data->api_sndcmd.t_type) //上面打印结果是10,即对应:HID_TRANS_DATA
{
case HID_TRANS_SET_PROTOCOL:
p_cb->w4_evt = BTA_HH_SET_PROTO_EVT;
bta_hh_le_set_protocol_mode(p_cb, p_data->api_sndcmd.param);
break; case HID_TRANS_GET_PROTOCOL:
bta_hh_le_get_protocol_mode(p_cb);
break; case HID_TRANS_GET_REPORT:
bta_hh_le_get_rpt(p_cb,
BTA_HH_LE_SRVC_DEF,
p_data->api_sndcmd.param,
p_data->api_sndcmd.rpt_id);
break; case HID_TRANS_SET_REPORT:
bta_hh_le_write_rpt(p_cb,
BTA_HH_LE_SRVC_DEF,
BTA_GATTC_TYPE_WRITE,
p_data->api_sndcmd.param,
p_data->api_sndcmd.p_data,
BTA_HH_SET_RPT_EVT);
break; case HID_TRANS_DATA: /* output report */ bta_hh_le_write_rpt(p_cb,
BTA_HH_LE_SRVC_DEF,
BTA_GATTC_TYPE_WRITE_NO_RSP,
p_data->api_sndcmd.param,
p_data->api_sndcmd.p_data,
BTA_HH_DATA_EVT);
break; case HID_TRANS_CONTROL:
/* no handshake event will be generated */
/* if VC_UNPLUG is issued, set flag */
if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND ||
p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
{
bta_hh_le_suspend(p_cb, p_data->api_sndcmd.param);
}
break; default:
APPL_TRACE_ERROR("%s unsupported transaction for BLE HID device: %d",
__func__, p_data->api_sndcmd.t_type);
break;
}
}

-->

/*******************************************************************************
**
** Function bta_hh_le_write_rpt
**
** Description SET_REPORT/or DATA output on a LE HID Report
**
** Returns void
**
*******************************************************************************/
void bta_hh_le_write_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst,
tBTA_GATTC_WRITE_TYPE write_type,
tBTA_HH_RPT_TYPE r_type,
BT_HDR *p_buf, UINT16 w4_evt )
{
tBTA_HH_LE_RPT *p_rpt;
tBTA_GATTC_CHAR_ID char_id;
UINT8 *p_value, rpt_id; if (p_buf == NULL || p_buf->len == 0)
{
APPL_TRACE_ERROR("bta_hh_le_write_rpt: Illegal data");
return;
} /* strip report ID from the data */
p_value = (UINT8 *)(p_buf + 1) + p_buf->offset;
STREAM_TO_UINT8(rpt_id, p_value);
p_buf->len -= 1; p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id); if (p_rpt == NULL)
{
APPL_TRACE_ERROR("bta_hh_le_write_rpt: no matching report 0x%02x",rpt_id);
GKI_freebuf(p_buf);
return;
} APPL_TRACE_ERROR("bta_hh_le_write_rpt: ReportID: 0x%02x Data Len: %d", rpt_id, p_buf->len); p_cb->w4_evt = w4_evt; bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst, UUID_SERVCLASS_LE_HID, &char_id.srvc_id);
bta_hh_le_fill_16bits_char_id(p_rpt->inst_id, p_rpt->uuid, &char_id.char_id); LOG_DEBUG("%s: BTA_GATTC_WriteCharValue::", __FUNCTION__); BTA_GATTC_WriteCharValue(p_cb->conn_id,
&char_id,
write_type, /* default to use write request */ //之前reportid 0x5b的patch使 write_type为BTA_GATTC_TYPE_WRITE_NO_RSP
p_buf->len,
p_value,
BTA_GATT_AUTH_REQ_NONE); }

-->

/*******************************************************************************
**
** 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)); APPL_TRACE_DEBUG("BTA_GATTC_WriteCharValue : write_type=%d",write_type); 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); //设置数据类型后发送到gatt层
}
return;
}

应用层传下来的消息到GATT层:

external\bluetooth\bluedroid\stack\btu\btu_task.c

/*******************************************************************************
**
** Function btu_task
**
** Description This is the main task of the Bluetooth Upper Layers unit.
** It sits in a loop waiting for messages, and dispatches them
** to the appropiate handlers.
**
** Returns should never return
**
*******************************************************************************/
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, );
if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
{
/* indicates BT ENABLE abort */
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
"btu_task start abort!");
return ();
}
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", , , ); raise_priority_a2dp(TASK_HIGH_BTU); /* Wait for, and process, events */
for (;;)
{
event = GKI_wait (0xFFFF, ); 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 + ));
GKI_freebuf (p_msg);
break; case BT_EVT_TO_OBX_SR_L2C_MSG:
obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + ));
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 + ));
GKI_freebuf (p_msg);
break; case BT_EVT_TO_OBX_CL_L2C_MSG:
obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + ));
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 (), 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 = ;
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, ); 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 != )
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 = ;
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 != )
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 > )
GKI_start_timer(TIMER_3, p_tle->ticks, FALSE);
} else {
GKI_stop_timer(TIMER_3);
}
} if (event & EVENT_MASK(APPL_EVT_7))
break;
} return();
}

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

/*******************************************************************************
**
** Function bta_sys_event
**
** Description BTA event handler; called from task event handler.
**
**
** Returns void
**
*******************************************************************************/
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 >> ); /* 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 client事件处理函数:

/*******************************************************************************
**
** Function bta_gattc_hdl_event
**
** Description GATT client main event handling function.
**
**
** Returns BOOLEAN
**
*******************************************************************************/
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;
}

gatt client事件处理状态机

/*******************************************************************************
**
** Function bta_gattc_sm_execute
**
** Description State machine event handling function for GATTC
**
**
** Returns BOOLEAN : TRUE if queued client request buffer can be immediately released
** else FALSE
**
*******************************************************************************/
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 = ; 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;
}

->

/*******************************************************************************
**
** Function bta_gattc_write
**
** Description Write an attribute
**
** Returns None.
**
*******************************************************************************/
void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
UINT16 handle = ;
tGATT_VALUE attr = {};
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)) == )
{
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, , 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);
}
}
}

->

/*******************************************************************************
**
** Function GATTC_Write
**
** Description This function is called to write the value of an attribute to
** the server.
**
** Parameters conn_id: connection identifier.
** type - attribute write type.
** p_write - write operation parameters.
**
** Returns GATT_SUCCESS if command started successfully.
**
*******************************************************************************/
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 = ;
} 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;
}

->

/*******************************************************************************
**
** Function gatt_check_enc_req
**
** Description check link security.
**
** Returns TRUE if encrypted, otherwise FALSE.
**
*******************************************************************************/
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;
}

->

/*******************************************************************************
**
** Function gatt_sec_check_complete
**
** Description security check complete and proceed to data sending action.
**
** Returns void.
**
*******************************************************************************/
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);
}
}

->

/*******************************************************************************
**
** Function gatt_act_write
**
** Description GATT write operation.
**
** Returns void.
**
*******************************************************************************/
void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act)
{
tGATT_TCB *p_tcb = p_clcb->p_tcb;
UINT8 rt = GATT_SUCCESS, op_code = ;
tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; if (p_attr)
{
switch (p_clcb->op_subtype)
{
case GATT_WRITE_NO_RSP:
p_clcb->s_handle = p_attr->handle;
op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE;
rt = gatt_send_write_msg(p_tcb,
p_clcb->clcb_idx,
op_code,
p_attr->handle,
p_attr->len,
,
p_attr->value);
break; case GATT_WRITE:
if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
{
p_clcb->s_handle = p_attr->handle; rt = gatt_send_write_msg(p_tcb,
p_clcb->clcb_idx,
GATT_REQ_WRITE,
p_attr->handle,
p_attr->len,
,
p_attr->value);
}
else /* prepare write for long attribute */
{
gatt_send_prepare_write(p_tcb, p_clcb);
}
break; case GATT_WRITE_PREPARE:
gatt_send_prepare_write(p_tcb, p_clcb);
break; default:
rt = GATT_INTERNAL_ERROR;
GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
break;
}
}
else
rt = GATT_INTERNAL_ERROR; if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED)
|| (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
{
if (rt != GATT_SUCCESS)
{
GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x", op_code);
}
gatt_end_operation(p_clcb, rt, NULL);
}
}

->

/*******************************************************************************
**
** Function gatt_send_write_msg
**
** Description This real function send out the ATT message for write.
**
** Returns status code
**
*******************************************************************************/
UINT8 gatt_send_write_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code,
UINT16 handle, UINT16 len,
UINT16 offset, UINT8 *p_data)
{
tGATT_CL_MSG msg; msg.attr_value.handle = handle;
msg.attr_value.len = len;
msg.attr_value.offset = offset; memcpy (msg.attr_value.value, p_data, len); /* write by handle */
return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
}

->

/*******************************************************************************
**
** Function attp_send_cl_msg
**
** Description This function sends the client request or confirmation message
** to server.
**
** Parameter p_tcb: pointer to the connectino control block.
** clcb_idx: clcb index
** op_code: message op code.
** p_msg: pointer to message parameters structure.
**
** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
**
**
*******************************************************************************/
tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
{
tGATT_STATUS status = GATT_NO_RESOURCES;
BT_HDR *p_cmd = NULL;
UINT16 offset = , handle; if (p_tcb != NULL)
{
switch (op_code)
{
case GATT_REQ_MTU:
if (p_msg->mtu <= GATT_MAX_MTU_SIZE)
{
p_tcb->payload_size = p_msg->mtu;
p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
}
else
status = GATT_ILLEGAL_PARAMETER;
break; case GATT_REQ_FIND_INFO:
case GATT_REQ_READ_BY_TYPE:
case GATT_REQ_READ_BY_GRP_TYPE:
if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) &&
p_msg->browse.s_handle <= p_msg->browse.e_handle)
{
p_cmd = attp_build_browse_cmd(op_code,
p_msg->browse.s_handle,
p_msg->browse.e_handle,
p_msg->browse.uuid);
}
else
status = GATT_ILLEGAL_PARAMETER;
break; case GATT_REQ_READ_BLOB:
offset = p_msg->read_blob.offset;
/* fall through */
case GATT_REQ_READ:
handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle;
/* handle checking */
if (GATT_HANDLE_IS_VALID (handle))
{
p_cmd = attp_build_handle_cmd(op_code, handle, offset);
}
else
status = GATT_ILLEGAL_PARAMETER;
break; case GATT_HANDLE_VALUE_CONF:
p_cmd = attp_build_opcode_cmd(op_code);
break; case GATT_REQ_PREPARE_WRITE:
offset = p_msg->attr_value.offset;
/* fall through */
case GATT_REQ_WRITE:
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
{
         //先调用这里
p_cmd = attp_build_value_cmd (p_tcb->payload_size,
op_code, p_msg->attr_value.handle,
offset,
p_msg->attr_value.len,
p_msg->attr_value.value);
}
else
status = GATT_ILLEGAL_PARAMETER;
break; case GATT_REQ_EXEC_WRITE:
p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
break; case GATT_REQ_FIND_TYPE_VALUE:
p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
break; case GATT_REQ_READ_MULTI:
p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
p_msg->read_multi.num_handles,
p_msg->read_multi.handles);
break; default:
break;
}

     //再调用这里
if (p_cmd != NULL)
status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd); }
else
{
GATT_TRACE_ERROR("Peer device not connected");
} return status;
}

-->

/*******************************************************************************
**
** Function attp_build_value_cmd
**
** Description Build a attribute value request
**
** Returns None.
**
*******************************************************************************/
BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
UINT16 offset, UINT16 len, UINT8 *p_data)
{
BT_HDR *p_buf = NULL;
UINT8 *p, *pp, pair_len, *p_pair_len; if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL)
{
p = pp =(UINT8 *)(p_buf + ) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM (p, op_code);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = ; if (op_code == GATT_RSP_READ_BY_TYPE)
{
p_pair_len = p;
pair_len = len + ;
UINT8_TO_STREAM (p, pair_len);
p_buf->len += ;
}
if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ)
{
UINT16_TO_STREAM (p, handle);
p_buf->len += ;
} if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE )
{
UINT16_TO_STREAM (p, offset);
p_buf->len += ;
} if (len > && p_data != NULL)
{
/* ensure data not exceed MTU size */
if (payload_size - p_buf->len < len)
{
len = payload_size - p_buf->len;
/* update handle value pair length */
if (op_code == GATT_RSP_READ_BY_TYPE)
*p_pair_len = (len + ); GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
} ARRAY_TO_STREAM (p, p_data, len);
p_buf->len += len;
}
}
return p_buf;
}

—>

/*******************************************************************************
**
** Function attp_cl_send_cmd
**
** Description Send a ATT command or enqueue it.
**
** Returns GATT_SUCCESS if command sent
** GATT_CONGESTED if command sent but channel congested
** GATT_CMD_STARTED if command queue up in GATT
** GATT_ERROR if command sending failure
**
*******************************************************************************/
tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
{
tGATT_STATUS att_ret = GATT_SUCCESS; if (p_tcb != NULL)
{
cmd_code &= ~GATT_AUTH_SIGN_MASK; /* no pending request or value confirmation */
if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
cmd_code == GATT_HANDLE_VALUE_CONF)
{
att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd); //发送数据到l2cap层
if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
{
/* do not enq cmd if handle value confirmation or set request */
if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
{
gatt_start_rsp_timer (clcb_idx); //如果是write request数据类型,则会创建定时器等待respond(5s超时)
gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
}
}
else
att_ret = GATT_INTERNAL_ERROR;
}
else
{
att_ret = GATT_CMD_STARTED;
gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
}
}
else
att_ret = GATT_ERROR; return att_ret;
}

->

/*******************************************************************************
**
** Function attp_send_msg_to_l2cap
**
** Description Send message to L2CAP.
**
*******************************************************************************/
tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
{
UINT16 l2cap_ret; if (p_tcb->att_lcid == L2CAP_ATT_CID)
l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
else
l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP); if (l2cap_ret == L2CAP_DW_FAILED)
{
GATT_TRACE_ERROR("ATT failed to pass msg:0x%0x to L2CAP",
*((UINT8 *)(p_toL2CAP + ) + p_toL2CAP->offset));
return GATT_INTERNAL_ERROR;
}
else if (l2cap_ret == L2CAP_DW_CONGESTED)
{
GATT_TRACE_DEBUG("ATT congested, message accepted");
return GATT_CONGESTED;
}
return GATT_SUCCESS;
}

->

/*******************************************************************************
**
** Function L2CA_SendFixedChnlData
**
** Description Write data on a fixed channel.
**
** Parameters: Fixed CID
** BD Address of remote
** Pointer to buffer of type BT_HDR
**
** Return value L2CAP_DW_SUCCESS, if data accepted
** L2CAP_DW_FAILED, if error
**
*******************************************************************************/
UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf)
{
tL2C_LCB *p_lcb;
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; L2CAP_TRACE_API ("L2CA_SendFixedChnlData() CID: 0x%04x BDA: %08x%04x", fixed_cid,
(rem_bda[]<<)+(rem_bda[]<<)+(rem_bda[]<<)+rem_bda[], (rem_bda[]<<)+rem_bda[]); #if BLE_INCLUDED == TRUE
if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
transport = BT_TRANSPORT_LE;
#endif /* Check CID is valid and registered */
if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
|| (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
{
L2CAP_TRACE_ERROR ("L2CA_SendFixedChnlData() Invalid CID: 0x%04x", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
} /* Fail if BT is not yet up */
if (!BTM_IsDeviceUp())
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - BTU not ready", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
} /* We need to have a link up */
if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport)) == NULL ||
/* if link is disconnecting, also report data sending failure */
p_lcb->link_state == LST_DISCONNECTING)
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - no LCB", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
} if ((p_lcb->peer_chnl_mask[] & ( << fixed_cid)) == )
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - peer does not support fixed chnl: 0x%04x", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
} p_buf->event = ;
p_buf->layer_specific = L2CAP_FLUSHABLE_CH_BASED; if (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])
{
if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
{
L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - no CCB for chnl: 0x%4x", fixed_cid);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
}
} /* If already congested, do not accept any more packets */
if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
{
L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested \
xmit_hold_q.count: %u buff_quota: %u", fixed_cid,
p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->xmit_hold_q.count,
p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->buff_quota);
GKI_freebuf (p_buf);
return (L2CAP_DW_FAILED);
} l2c_enqueue_peer_data (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL], p_buf); l2c_link_check_send_pkts (p_lcb, NULL, NULL); /* If there is no dynamic CCB on the link, restart the idle timer each time something is sent */
if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb)
{
l2cu_no_dynamic_ccbs (p_lcb);
} if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
return (L2CAP_DW_CONGESTED); return (L2CAP_DW_SUCCESS);
}

调用 l2c_enqueue_peer_data 让数据进入到当前 ccb 的 xmit_hold_q 队列中,暂存此数据包。

/*******************************************************************************
**
** Function l2c_enqueue_peer_data
**
** Description Enqueues data destined for the peer in the ccb. Handles
** FCR segmentation and checks for congestion.
**
** Returns void
**
*******************************************************************************/
void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
{
UINT8 *p; if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
{
p_buf->event = ;
}
else
{
/* Save the channel ID for faster counting */
p_buf->event = p_ccb->local_cid; /* Step back to add the L2CAP header */
p_buf->offset -= L2CAP_PKT_OVERHEAD;
p_buf->len += L2CAP_PKT_OVERHEAD; /* Set the pointer to the beginning of the data */
p = (UINT8 *)(p_buf + ) + p_buf->offset; /* Now the L2CAP header */
UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
UINT16_TO_STREAM (p, p_ccb->remote_cid);
} GKI_enqueue (&p_ccb->xmit_hold_q, p_buf); l2cu_check_channel_congestion (p_ccb);  //检测当前 Channel 拥堵情况 #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
/* if new packet is higher priority than serving ccb and it is not overrun */
if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority )
&&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > ))
{
/* send out higher priority packet */
p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
}
#endif /* if we are doing a round robin scheduling, set the flag */
if (p_ccb->p_lcb->link_xmit_quota == )
l2cb.check_round_robin = TRUE;
}

-->

/******************************************************************************
**
** Function l2cu_check_channel_congestion
**
** Description check if any change in congestion status
**
** Returns None
**
*******************************************************************************/
void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
{
UINT16 q_count = GKI_queue_length(&p_ccb->xmit_hold_q); #if (L2CAP_UCD_INCLUDED == TRUE)
if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
{
q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count;
}
#endif
/* If the CCB queue limit is subject to a quota, check for congestion */
/* if this channel has outgoing traffic */
if (p_ccb->buff_quota != )
{
/* If this channel was congested */
if ( p_ccb->cong_sent )
{
/* If the channel is not congested now, tell the app */
        //在函数 l2c_link_adjust_chnl_allocation 中配置此值
        //p_ccb->buff_quota = quota_per_weighted_chnls[p_ccb->ertm_info.user_tx_pool_id] * p_ccb->tx_data_rate;
if (q_count <= (p_ccb->buff_quota / )) //当前CCB中的 xmit_hold_q 小于 buffer_quota 值的一半,即认为已经不拥堵
{
p_ccb->cong_sent = FALSE;
if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u",
p_ccb->local_cid, q_count, p_ccb->buff_quota); /* Prevent recursive calling */
l2cb.is_cong_cback_context = TRUE;
(*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE);
l2cb.is_cong_cback_context = FALSE;
}
#if (L2CAP_UCD_INCLUDED == TRUE)
else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
{
if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
p_ccb->p_lcb->ucd_out_sec_pending_q.count,
p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE );
}
}
#endif
#if (L2CAP_NUM_FIXED_CHNLS > 0)
else
{
UINT8 xx;
for (xx = ; xx < L2CAP_NUM_FIXED_CHNLS; xx ++)
{
if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb)
{
if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
(* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, FALSE);
break;
}
}
}
#endif
}
}
else
{
/* If this channel was not congested but it is congested now, tell the app */
if (q_count > p_ccb->buff_quota)
{
p_ccb->cong_sent = TRUE;
if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
p_ccb->local_cid, q_count, p_ccb->buff_quota); (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE);
}
#if (L2CAP_UCD_INCLUDED == TRUE)
else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
{
if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
{
L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
p_ccb->p_lcb->ucd_out_sec_pending_q.count,
p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE );
}
}
#endif
#if (L2CAP_NUM_FIXED_CHNLS > 0)
else
{
UINT8 xx;
for (xx = ; xx < L2CAP_NUM_FIXED_CHNLS; xx ++)
{
if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb)
{
if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
(* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, TRUE);
break;
}
}
}
#endif
}
}
}
}

L2CAP层是通过 l2c_link_check_send_pkts 这个函数发送数据包:

/*******************************************************************************
**
** Function l2c_link_check_send_pkts
**
** Description This function is called to check if it can send packets
** to the Host Controller. It may be passed the address of
** a packet to send.
**
** Returns void
**
*******************************************************************************/
void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
{
int xx;
BOOLEAN single_write = FALSE; //最后 Link Disc 用来把 CCB 中的数据包放到 Link 上的队列发,速度加快 /* Save the channel ID for faster counting */
if (p_buf)//一般数据包都为空,只有发送 L2CAP 发送 command/response 或 发送 S-Frame 才用到
{
if (p_ccb != NULL) //这个 case 就是 当前 Link 即将断开的情况了
{
p_buf->event = p_ccb->local_cid;
single_write = TRUE;
}
else
p_buf->event = ; p_buf->layer_specific = ;
//把这个数据包放到 当前 link 上的 link_xmit_data_q队列中
GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf); //没有发送窗口了,需要 RR 看看有没有别的数据包可以发
if (p_lcb->link_xmit_quota == )
{
#if BLE_INCLUDED == TRUE if (p_lcb->transport == BT_TRANSPORT_LE)
l2cb.ble_check_round_robin = TRUE;
else
#endif
l2cb.check_round_robin = TRUE;
}
} /* If this is called from uncongested callback context break recursive calling.
** This LCB will be served when receiving number of completed packet event.
*/
if (l2cb.is_cong_cback_context)//当前 Link 拥堵了,不发送数据包直接返回
return; /* If we are in a scenario where there are not enough buffers for each link to
** have at least 1, then do a round-robin for all the LCBs
*/
if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == ) )
{
if (p_lcb == NULL)
p_lcb = l2cb.lcb_pool;
else if (!single_write)
p_lcb++; /* Loop through, starting at the next */
//没有足够buffer发送窗口了,在所有的 Link 上做一次 RR
for (xx = ; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
{
/* If controller window is full, nothing to do */
if ( (l2cb.controller_xmit_window ==
#if (BLE_INCLUDED == TRUE)
&& (p_lcb->transport == BT_TRANSPORT_BR_EDR)
#endif
)
#if (BLE_INCLUDED == TRUE)
|| (p_lcb->transport == BT_TRANSPORT_LE && l2cb.controller_le_xmit_window == )
#endif
|| (l2cb.round_robin_unacked >= l2cb.round_robin_quota) )
break; /* Check for wraparound */
if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
p_lcb = &l2cb.lcb_pool[]; if ( (!p_lcb->in_use)
|| (p_lcb->partial_segment_being_sent)
|| (p_lcb->link_state != LST_CONNECTED)
|| (p_lcb->link_xmit_quota != )
|| (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
continue; /* See if we can send anything from the Link Queue */
//首先从当前 Link 上的 link_xmit_data_q 中取出数据包并发送
if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)
{
l2c_link_send_to_lower (p_lcb, p_buf);
}
else if (single_write)//如果是 single_write 设置为 TRUE,说明数据包 已经在 link_xmit_data_q 发送了,没必要在执行下面的 code 了
{
/* If only doing one write, break out */
break;
}
/* If nothing on the link queue, check the channel queue */
//Link 上的 Queue 中没有东西可以发送,查找 CCB 中的 Queue,直到找到一个为止。
else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
{
l2c_link_send_to_lower (p_lcb, p_buf);
}
} /* If we finished without using up our quota, no need for a safety check */
if ( (l2cb.controller_xmit_window > )
&& (l2cb.round_robin_unacked < l2cb.round_robin_quota)
#if (BLE_INCLUDED == TRUE)
&& (p_lcb->transport == BT_TRANSPORT_BR_EDR)
#endif
)
l2cb.check_round_robin = FALSE; #if (BLE_INCLUDED == TRUE)
if ( (l2cb.controller_le_xmit_window > )
&& (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota)
&& (p_lcb->transport == BT_TRANSPORT_LE))
l2cb.ble_check_round_robin = FALSE;
#endif
}
else /* if this is not round-robin service */
{
/* If a partial segment is being sent, can't send anything else */
if ( (p_lcb->partial_segment_being_sent)
|| (p_lcb->link_state != LST_CONNECTED)
|| (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
return; /* See if we can send anything from the link queue */
#if (BLE_INCLUDED == TRUE)
while ( ((l2cb.controller_xmit_window != && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
(l2cb.controller_le_xmit_window != && (p_lcb->transport == BT_TRANSPORT_LE)))
&& (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#else
while ( (l2cb.controller_xmit_window != )
&& (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#endif
{
if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) == NULL)
break; if (!l2c_link_send_to_lower (p_lcb, p_buf))
break;
} if (!single_write)//确保不是在链路 disc 状态下
{
/* See if we can send anything for any channel */
#if (BLE_INCLUDED == TRUE)
while ( ((l2cb.controller_xmit_window != && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
(l2cb.controller_le_xmit_window != && (p_lcb->transport == BT_TRANSPORT_LE)))
&& (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#else
while ((l2cb.controller_xmit_window != ) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#endif
{
if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)//找到一个数据包来发送
break; if (!l2c_link_send_to_lower (p_lcb, p_buf))
break;
}
} /* There is a special case where we have readjusted the link quotas and */
/* this link may have sent anything but some other link sent packets so */
/* so we may need a timer to kick off this link's transmissions. */
if ( (p_lcb->link_xmit_data_q.count) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
} }

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

  1. 如果当前数据包 p_buf 的长度小于 ACL 包的最大值,sent_not_acked 加1,整个 L2CAP 的 controller_xmit_window 减1。然后通过 L2C_LINK_SEND_ACL_DATA 将此数据包发送出去。
  2. 如果当前数据包 p_buf 的长度大于 ACL 包的最大值,先看看能分成几个分包(为了求的几个窗口能容下),然后窗口值减掉这些分包个数,然后将整个数据包交给 L2C_LINK_SEND_ACL_DATA (大于ACL包长度),具体分包发送由 H5(串口) 部分来负责。
/*******************************************************************************
**
** Function l2c_link_send_to_lower
**
** Description This function queues the buffer for HCI transmission
**
** Returns TRUE for success, FALSE for fail
**
*******************************************************************************/
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 == )
{
#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 = ; #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 - ) / acl_data_size; /* If doing round-robin, then only 1 segment each time */
if (p_lcb->link_xmit_quota == )
{
num_segs = ;
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 == )
l2cb.ble_round_robin_unacked += num_segs;
}
else
#endif
{
l2cb.controller_xmit_window -= num_segs; if (p_lcb->link_xmit_quota == )
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;
}

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 队列中获取数据包,并将其发送。

/******************************************************************************
**
** Function bte_main_hci_send
**
** Description BTE MAIN API - This function is called by the upper stack to
** send an HCI message. The function displays a protocol trace
** message (if enabled), and then calls the 'transmit' function
** associated with the currently selected HCI transport
**
** Returns None
**
******************************************************************************/
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 + ), \
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;
}

external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c

bt_hc_worker_thread负责处理hci事件

/*******************************************************************************
**
** Function bt_hc_worker_thread
**
** Description Mian worker thread
**
** Returns void *
**
*******************************************************************************/
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", , , );
tx_cmd_pkts_pending = FALSE; raise_priority_a2dp(TASK_HIGH_HCI_WORKER); while (lib_running)
{
pthread_mutex_lock(&hc_cb.mutex);
while (ready_events == )
{
pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex);
}
events = ready_events;
ready_events = ;
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 > ))
{
/* 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 = -; /* Calling vendor-specific part */
if (bt_vnd_if)
result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL); if (result == -)
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[];
int sending_msg_count = ;
int sending_hci_cmd_pkts_count = ;
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[]))
{
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 = ; 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 = ; pthread_exit(NULL); return NULL; // compiler friendly
}

send to : userial.c

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

/*******************************************************************************
**
** Function userial_write
**
** Description Write data to the userial port
**
** Returns Number of bytes actually written to the userial port. This
** may be less than len.
**
*******************************************************************************/
uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
{
int ret, total = ; while(len != )
{
#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);
}

write /dev/hidraw* 节点数据下发流程大致如上,敬请勘误~!

 

Bluedroid: 蓝牙协议栈源码剖析的更多相关文章

  1. 5.2【Linux 内核网络协议栈源码剖析】socket 函数剖析 ☆☆☆

    深度剖析网络协议栈中的 socket 函数,可以说是把前面介绍的串联起来,将网络协议栈各层关联起来. 应用层 FTP SMTP HTTP ... 传输层 TCP UDP 网络层 IP ICMP ARP ...

  2. 【Linux 内核网络协议栈源码剖析】网络栈主要结构介绍(socket、sock、sk_buff,etc)

    原文:http://blog.csdn.net/wenqian1991/article/details/46700177 通过前面的分析,可以发现,网络协议栈中的数据处理,都是基于各类结构体,所有有关 ...

  3. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

  4. Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

    声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...

  5. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  6. 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析

    项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...

  7. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  8. SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现

    SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即“service”阶段.在“service”阶段中,每一次Http请求到来,容器都会启动一个请求线程,通过serv ...

  9. 自己实现多线程的socket,socketserver源码剖析

    1,IO多路复用 三种多路复用的机制:select.poll.epoll 用的多的两个:select和epoll 简单的说就是:1,select和poll所有平台都支持,epoll只有linux支持2 ...

随机推荐

  1. python logging日志输出个文件中

    # -*- coding:utf-8 -*- import logging # 引入logging模块 import os.path import time # 第一步,创建一个logger logg ...

  2. Adobe Photoshop CC 2018 v19.0 简体中文正式版下载安装破解(附注册机+破解教程) 32/64位(安装破解注意事项是什么)

    Adobe Photoshop CC 2018 v19.0 简体中文正式版下载安装破解(附注册机+破解教程) 32/64位(安装破解注意事项是什么) 一.总结 一句话总结:下载安装破解教程文中都有,需 ...

  3. codeforces590b//Chip 'n Dale Rescue Rangers//Codeforces Round #327 (Div. 1)

    题意:从一点到另一点,前t秒的风向与t秒后风向不同,问到另一点的最短时间 挺难的,做不出来,又参考了别人的代码.先得到终点指向起点的向量,设T秒钟能到.如果T>t则受风1作用t秒,风2作用T-t ...

  4. Confluence 6 可以自定义的元素

    色彩配色方案允许你对 UI 中的元素色彩进行编辑,包括顶部条,标签页和背景色. 有一些下面的 UI 元素被用在特定的主题中,配色方案的修改可能不会对这些元素有效. 顶部条(Top Bar)—— 顶部导 ...

  5. Confluence 6 指派和撤销空间权限

    指派空间权限 希望添加一个新用户或者用户组到权限列表中,从希望选择的选项中查找用户组或者用户,然后选择 添加(Add).用户和用户组将会显示在列表中:选择你希望引用的权限,然后选择 保存所有(Save ...

  6. ubuntu下安装CAJ阅读器

    目录 1.ubuntu下wine的基本介绍 (1)wine的介绍 (2)wine的安装 (3)exe文件的安装 (4)exe程序的卸载 (6)wine的基本使用 2.CAJ阅读器的安装 (1)首先放上 ...

  7. New Roads CodeForces - 746G (树,构造)

    大意:构造n结点树, 高度$i$的结点有$a_i$个, 且叶子有k个. 先确定主链, 然后贪心放其余节点. #include <iostream> #include <algorit ...

  8. WEB环境相关技术、配置

    一.简介(基本概念) web开发中基本概念和用到的技术: A — AJAX AJAX 全称为“ Asynchronous JavaScript and XML ”(异步 JavaScript 和 XM ...

  9. python-django rest framework框架之解析器

    1.解析器 : 对请求的数据进行解析 - 请求体进行解析. 解析器在你不拿请求体数据时 不会调用. class UsersView(APIView): def get(self,request,*ar ...

  10. vue 关于npm run build 的小问题

    vue项目使用npm run build命令进行打包操作,打包之后试运行报错,报错为: 且命令行警告信息为: 解决办法: 找到项目目录下的config文件夹里的index.js文件,将build对象下 ...