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, 0, sizeof(btif_hh_cb)); for (i = 0; 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, 0, 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, 0); /* * 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 = 0; 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, 0, 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, 1, &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, 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); } }
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 = 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 = open(dev_path, O_RDWR | O_CLOEXEC); 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; } if (p_dev == NULL) { // Did not find a device reconnection case. Find an empty slot now. for (i = 0; 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 < 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; } } } 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[1]; int ret; pfds[0].fd = p_dev->fd; pfds[0].events = POLLIN; while(p_dev->hh_keep_polling){ ret = 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; }
解析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, 0, sizeof(ev)); if(!p_dev) { APPL_TRACE_ERROR("%s: Device not found",__FUNCTION__) return -1; } ret = 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 != 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 0; }
--->
/******************************************************************************* ** ** 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[0] != 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, 0, 0, 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, 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); //发送数据到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, 0); if (event & EVENT_MASK(GKI_SHUTDOWN_EVT)) { /* indicates BT ENABLE abort */ BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING, "btu_task start abort!"); return (0); } else if (event & BT_EVT_PRELOAD_CMPL) { break; } else { BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING, "btu_task ignore evt %04x while pending for preload complete", event); } } BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API, "btu_task received preload complete event"); #endif /* Initialize the mandatory core stack control blocks (BTU, BTM, L2CAP, and SDP) */ btu_init_core(); /* Initialize any optional stack components */ BTE_InitStack(); #if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE) bta_sys_init(); #endif /* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init() * reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL */ #if ( BT_USE_TRACES==TRUE ) BTE_InitTraceLevels(); #endif /* Send a startup evt message to BTIF_TASK to kickstart the init procedure */ GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT); prctl(PR_SET_NAME, (unsigned long)"BTU TASK", 0, 0, 0); raise_priority_a2dp(TASK_HIGH_BTU); /* Wait for, and process, events */ for (;;) { event = GKI_wait (0xFFFF, 0); if (event & TASK_MBOX_0_EVT_MASK) { /* Process all messages in the queue */ while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL) { /* Determine the input message type. */ switch (p_msg->event & BT_EVT_MASK) { case BT_EVT_TO_BTU_HCI_ACL: /* All Acl Data goes to L2CAP */ l2c_rcv_acl_data (p_msg); break; case BT_EVT_TO_BTU_L2C_SEG_XMIT: /* L2CAP segment transmit complete */ l2c_link_segments_xmitted (p_msg); break; case BT_EVT_TO_BTU_HCI_SCO: #if BTM_SCO_INCLUDED == TRUE btm_route_sco_data (p_msg); break; #endif case BT_EVT_TO_BTU_HCI_EVT: btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg); GKI_freebuf(p_msg); #if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) /* If host receives events which it doesn't response to, */ /* host should start idle timer to enter sleep mode. */ btu_check_bt_sleep (); #endif break; case BT_EVT_TO_BTU_HCI_CMD: btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg); break; #if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE) #if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE) case BT_EVT_TO_OBX_SR_MSG: obx_sr_proc_evt((tOBX_PORT_EVT *)(p_msg + 1)); GKI_freebuf (p_msg); break; case BT_EVT_TO_OBX_SR_L2C_MSG: obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1)); GKI_freebuf (p_msg); break; #endif #if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE) case BT_EVT_TO_OBX_CL_MSG: obx_cl_proc_evt((tOBX_PORT_EVT *)(p_msg + 1)); GKI_freebuf (p_msg); break; case BT_EVT_TO_OBX_CL_L2C_MSG: obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1)); GKI_freebuf (p_msg); break; #endif #if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE) case BT_EVT_TO_BIP_CMDS : bip_proc_btu_event(p_msg); GKI_freebuf (p_msg); break; #endif /* BIP */ #if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE) case BT_EVT_TO_BPP_PR_CMDS: bpp_pr_proc_event(p_msg); GKI_freebuf (p_msg); break; case BT_EVT_TO_BPP_SND_CMDS: bpp_snd_proc_event(p_msg); GKI_freebuf (p_msg); break; #endif /* BPP */ #endif /* OBX */ #if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE) case BT_EVT_TO_BTU_SAP : sap_proc_btu_event(p_msg); GKI_freebuf (p_msg); break; #endif /* SAP */ #if (defined(GAP_CONN_INCLUDED) && GAP_CONN_INCLUDED == TRUE && GAP_CONN_POST_EVT_INCLUDED == TRUE) case BT_EVT_TO_GAP_MSG : gap_proc_btu_event(p_msg); GKI_freebuf (p_msg); break; #endif case BT_EVT_TO_START_TIMER : /* Start free running 1 second timer for list management */ GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE); GKI_freebuf (p_msg); break; case BT_EVT_TO_STOP_TIMER: if (GKI_timer_queue_is_empty(&btu_cb.timer_queue)) { GKI_stop_timer(TIMER_0); } GKI_freebuf (p_msg); break; case BT_EVT_TO_START_TIMER_ONESHOT: if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) { TIMER_LIST_ENT *tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot); // Start non-repeating timer. GKI_start_timer(TIMER_3, tle->ticks, FALSE); } else { BTM_TRACE_WARNING("Oneshot timer queue empty when received start request"); } GKI_freebuf(p_msg); break; case BT_EVT_TO_STOP_TIMER_ONESHOT: if (GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) { GKI_stop_timer(TIMER_3); } else { BTM_TRACE_WARNING("Oneshot timer queue not empty when received stop request"); } GKI_freebuf (p_msg); break; #if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) case BT_EVT_TO_START_QUICK_TIMER : GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE); GKI_freebuf (p_msg); break; #endif default: i = 0; mask = (UINT16) (p_msg->event & BT_EVT_MASK); handled = FALSE; for (; !handled && i < BTU_MAX_REG_EVENT; i++) { if (btu_cb.event_reg[i].event_cb == NULL) continue; if (mask == btu_cb.event_reg[i].event_range) { if (btu_cb.event_reg[i].event_cb) { btu_cb.event_reg[i].event_cb(p_msg); handled = TRUE; } } } if (handled == FALSE) GKI_freebuf (p_msg); break; } } } if (event & TIMER_0_EVT_MASK) { GKI_update_timer_list (&btu_cb.timer_queue, 1); while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue)) { TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue); if (p_tle->ticks != 0) break; GKI_remove_from_timer_list(&btu_cb.timer_queue, p_tle); switch (p_tle->event) { case BTU_TTYPE_BTM_DEV_CTL: btm_dev_timeout(p_tle); break; case BTU_TTYPE_BTM_ACL: btm_acl_timeout(p_tle); break; case BTU_TTYPE_L2CAP_LINK: case BTU_TTYPE_L2CAP_CHNL: case BTU_TTYPE_L2CAP_HOLD: case BTU_TTYPE_L2CAP_INFO: case BTU_TTYPE_L2CAP_FCR_ACK: l2c_process_timeout (p_tle); break; case BTU_TTYPE_SDP: sdp_conn_timeout ((tCONN_CB *)p_tle->param); break; case BTU_TTYPE_BTM_RMT_NAME: btm_inq_rmt_name_failed(); break; #if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) case BTU_TTYPE_RFCOMM_MFC: case BTU_TTYPE_RFCOMM_PORT: rfcomm_process_timeout (p_tle); break; #endif /* If defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE */ #if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE)) case BTU_TTYPE_BNEP: bnep_process_timeout(p_tle); break; #endif #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) case BTU_TTYPE_AVDT_CCB_RET: case BTU_TTYPE_AVDT_CCB_RSP: case BTU_TTYPE_AVDT_CCB_IDLE: case BTU_TTYPE_AVDT_SCB_TC: avdt_process_timeout(p_tle); break; #endif #if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE) #if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE) case BTU_TTYPE_OBX_CLIENT_TO: obx_cl_timeout(p_tle); break; #endif #if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE) case BTU_TTYPE_OBX_SERVER_TO: obx_sr_timeout(p_tle); break; case BTU_TTYPE_OBX_SVR_SESS_TO: obx_sr_sess_timeout(p_tle); break; #endif #endif #if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE) case BTU_TTYPE_SAP_TO: sap_process_timeout(p_tle); break; #endif case BTU_TTYPE_BTU_CMD_CMPL: btu_hcif_cmd_timeout((UINT8)(p_tle->event - BTU_TTYPE_BTU_CMD_CMPL)); break; #if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE) case BTU_TTYPE_HID_HOST_REPAGE_TO : hidh_proc_repage_timeout(p_tle); break; #endif #if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE) case BTU_TTYPE_BLE_INQUIRY: case BTU_TTYPE_BLE_GAP_LIM_DISC: case BTU_TTYPE_BLE_GAP_FAST_ADV: case BTU_TTYPE_BLE_OBSERVE: btm_ble_timeout(p_tle); break; case BTU_TTYPE_ATT_WAIT_FOR_RSP: gatt_rsp_timeout(p_tle); break; case BTU_TTYPE_ATT_WAIT_FOR_IND_ACK: gatt_ind_ack_timeout(p_tle); break; #if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE) case BTU_TTYPE_SMP_PAIRING_CMD: smp_rsp_timeout(p_tle); break; #endif #endif #if (MCA_INCLUDED == TRUE) case BTU_TTYPE_MCA_CCB_RSP: mca_process_timeout(p_tle); break; #endif case BTU_TTYPE_USER_FUNC: { tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param; (*p_uf)(p_tle); } break; default: i = 0; handled = FALSE; for (; !handled && i < BTU_MAX_REG_TIMER; i++) { if (btu_cb.timer_reg[i].timer_cb == NULL) continue; if (btu_cb.timer_reg[i].p_tle == p_tle) { btu_cb.timer_reg[i].timer_cb(p_tle); handled = TRUE; } } break; } } /* if timer list is empty stop periodic GKI timer */ if (btu_cb.timer_queue.p_first == NULL) { GKI_stop_timer(TIMER_0); } } #if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) if (event & TIMER_2_EVT_MASK) { btu_process_quick_timer_evt(); } #endif #if (RPC_INCLUDED == TRUE) /* if RPC message queue event */ if (event & RPCGEN_MSG_EVT) { if ((p_msg = (BT_HDR *) GKI_read_mbox(RPCGEN_MSG_MBOX)) != NULL) RPCT_RpcgenMsg(p_msg); /* handle RPC message queue */ } #endif #if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE) if (event & TASK_MBOX_2_EVT_MASK) { while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL) { bta_sys_event(p_msg); //处理上层传来的消息 } } if (event & TIMER_1_EVT_MASK) { bta_sys_timer_update(); } #endif if (event & TIMER_3_EVT_MASK) { BTM_TRACE_API("Received oneshot timer event complete"); if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) { TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot); INT32 ticks_since_last_update = GKI_timer_ticks_getinitial(GKI_timer_getfirst(&btu_cb.timer_queue_oneshot)); GKI_update_timer_list(&btu_cb.timer_queue_oneshot, ticks_since_last_update); } while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) { TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot); if (p_tle->ticks != 0) break; GKI_remove_from_timer_list(&btu_cb.timer_queue_oneshot, p_tle); switch (p_tle->event) { #if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE) case BTU_TTYPE_BLE_RANDOM_ADDR: btm_ble_timeout(p_tle); break; #endif case BTU_TTYPE_USER_FUNC: { tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param; (*p_uf)(p_tle); } break; default: // FAIL BTM_TRACE_WARNING("Received unexpected oneshot timer event:0x%x\n", p_tle->event); break; } } /* Update GKI timer with new tick value from first timer. */ if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) { TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot); if (p_tle->ticks > 0) GKI_start_timer(TIMER_3, p_tle->ticks, FALSE); } else { GKI_stop_timer(TIMER_3); } } if (event & EVENT_MASK(APPL_EVT_7)) break; } return(0); }
应用层注册的回调函数被调用:
/******************************************************************************* ** ** 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 >> 8); /* verify id and call subsystem event handler */ if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) { freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); //Id为0x17,即BTA_ID_HH,回调函数为bta_hh_hdl_event,前面已分析 //Id为0x1f,即为BTA_ID_GATTC,回调函数为bta_gattc_hdl_event,继续往后看 } else { APPL_TRACE_WARNING("BTA got unregistered event id %d", id); } if (freebuf) { GKI_freebuf(p_msg); } }
gatt 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 = 0; i < BTA_GATTC_ACTIONS; i++) { if ((action = state_table[event][i]) != BTA_GATTC_IGNORE) { (*bta_gattc_action[action])(p_clcb, p_data); //执行bta_gattc_write, if (p_clcb->p_q_cmd == p_data) { /* buffer is queued, don't free in the bta dispatcher. * we free it ourselves when a completion event is received. */ rt = FALSE; } } else { break; } } #if BTA_GATT_DEBUG == TRUE if (in_state != p_clcb->state) { APPL_TRACE_DEBUG("GATTC [%d] State Change: [%s] -> [%s] after Event [%s]",p_clcb->bta_conn_id, gattc_state_code(in_state), gattc_state_code(p_clcb->state), gattc_evt_code(in_event)); } #endif return rt; }
->
/******************************************************************************* ** ** 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 = 0; tGATT_VALUE attr = {0}; tBTA_GATTC_OP_CMPL op_cmpl; tBTA_GATT_STATUS status = BTA_GATT_OK; if (bta_gattc_enqueue(p_clcb, p_data)) { if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, &p_data->api_write.srvc_id, &p_data->api_write.char_id, p_data->api_write.p_descr_type)) == 0) { status = BTA_GATT_ERROR; } else { attr.handle= handle; attr.offset = p_data->api_write.offset; attr.len = p_data->api_write.len; attr.auth_req = p_data->api_write.auth_req; if (p_data->api_write.p_value) memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len); status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr); } /* write fail */ if (status != BTA_GATT_OK) { memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL)); op_cmpl.status = status; op_cmpl.op_code = GATTC_OPTYPE_WRITE; op_cmpl.p_cmpl = NULL; bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); } } }
->
/******************************************************************************* ** ** 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 = 0; } if (gatt_security_check_start(p_clcb) == FALSE) { status = GATT_NO_RESOURCES; } } else { status = GATT_NO_RESOURCES; } if (status == GATT_NO_RESOURCES) gatt_clcb_dealloc(p_clcb); } else { status = GATT_NO_RESOURCES; } return status; }
->
/******************************************************************************* ** ** 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 = 0; 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, 0, 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, 0, 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 = 0, 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 + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM (p, op_code); p_buf->offset = L2CAP_MIN_OFFSET; p_buf->len = 1; if (op_code == GATT_RSP_READ_BY_TYPE) { p_pair_len = p; pair_len = len + 2; UINT8_TO_STREAM (p, pair_len); p_buf->len += 1; } if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) { UINT16_TO_STREAM (p, handle); p_buf->len += 2; } if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE ) { UINT16_TO_STREAM (p, offset); p_buf->len += 2; } if (len > 0 && 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 + 2); 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 + 1) + 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[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); #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[0] & (1 << fixed_cid)) == 0) { 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 = 0; 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 = 0; } 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 + 1) + 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 > 0)) { /* 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 == 0) 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 != 0) { /* 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 / 2)) //当前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 = 0; 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 = 0; 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 = 0; p_buf->layer_specific = 0; //把这个数据包放到 当前 link 上的 link_xmit_data_q队列中 GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf); //没有发送窗口了,需要 RR 看看有没有别的数据包可以发 if (p_lcb->link_xmit_quota == 0) { #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 == 0) ) { 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 = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) { /* If controller window is full, nothing to do */ if ( (l2cb.controller_xmit_window == 0 #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 == 0 ) #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[0]; if ( (!p_lcb->in_use) || (p_lcb->partial_segment_being_sent) || (p_lcb->link_state != LST_CONNECTED) || (p_lcb->link_xmit_quota != 0) || (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 > 0) && (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 > 0) && (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 != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) || (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE))) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) #else while ( (l2cb.controller_xmit_window != 0) && (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 != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) || (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE))) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) #else while ((l2cb.controller_xmit_window != 0) && (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 主要做了这些事情:
/******************************************************************************* ** ** 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 == 0) { #if (BLE_INCLUDED == TRUE) if (p_lcb->transport == BT_TRANSPORT_LE) l2cb.ble_round_robin_unacked++; else #endif l2cb.round_robin_unacked++; } p_lcb->sent_not_acked++; p_buf->layer_specific = 0; #if (BLE_INCLUDED == TRUE) if (p_lcb->transport == BT_TRANSPORT_LE) { l2cb.controller_le_xmit_window--; L2C_LINK_SEND_BLE_ACL_DATA (p_buf); } else #endif { l2cb.controller_xmit_window--; L2C_LINK_SEND_ACL_DATA (p_buf); } } else { #if BLE_INCLUDED == TRUE if (p_lcb->transport == BT_TRANSPORT_LE) { acl_data_size = btu_cb.hcit_ble_acl_data_size; xmit_window = l2cb.controller_le_xmit_window; } else #endif { acl_data_size = btu_cb.hcit_acl_data_size; xmit_window = l2cb.controller_xmit_window; } num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size; /* If doing round-robin, then only 1 segment each time */ if (p_lcb->link_xmit_quota == 0) { num_segs = 1; p_lcb->partial_segment_being_sent = TRUE; } else { /* Multi-segment packet. Make sure it can fit */ if (num_segs > xmit_window) { num_segs = xmit_window; p_lcb->partial_segment_being_sent = TRUE; } if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked)) { num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked); p_lcb->partial_segment_being_sent = TRUE; } } p_buf->layer_specific = num_segs; #if BLE_INCLUDED == TRUE if (p_lcb->transport == BT_TRANSPORT_LE) { l2cb.controller_le_xmit_window -= num_segs; if (p_lcb->link_xmit_quota == 0) l2cb.ble_round_robin_unacked += num_segs; } else #endif { l2cb.controller_xmit_window -= num_segs; if (p_lcb->link_xmit_quota == 0) l2cb.round_robin_unacked += num_segs; } p_lcb->sent_not_acked += num_segs; #if BLE_INCLUDED == TRUE if (p_lcb->transport == BT_TRANSPORT_LE) { L2C_LINK_SEND_BLE_ACL_DATA(p_buf); } else #endif { L2C_LINK_SEND_ACL_DATA (p_buf); } } #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE) #if (BLE_INCLUDED == TRUE) if (p_lcb->transport == BT_TRANSPORT_LE) { L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d", l2cb.controller_le_xmit_window, p_lcb->handle, p_lcb->link_xmit_quota, p_lcb->sent_not_acked, l2cb.ble_round_robin_quota, l2cb.ble_round_robin_unacked); } else #endif { L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d", l2cb.controller_xmit_window, p_lcb->handle, p_lcb->link_xmit_quota, p_lcb->sent_not_acked, l2cb.round_robin_quota, l2cb.round_robin_unacked); } #endif return TRUE; }
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 + 1), \ p_msg->len); else GKI_freebuf(p_msg); } else { APPL_TRACE_ERROR("Invalid Controller ID. Discarding message."); GKI_freebuf(p_msg); } }
在hci中,数据被写入bt driver中
static int transmit_buf(TRANSAC transac, char *p_buf, int len) { utils_enqueue(&tx_q, (void *) transac); bthc_signal_event(HC_EVENT_TX); return BT_HC_STATUS_SUCCESS; }
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", 0, 0, 0); tx_cmd_pkts_pending = FALSE; raise_priority_a2dp(TASK_HIGH_HCI_WORKER); while (lib_running) { pthread_mutex_lock(&hc_cb.mutex); while (ready_events == 0) { pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex); } events = ready_events; ready_events = 0; pthread_mutex_unlock(&hc_cb.mutex); #ifndef HCI_USE_MCT if (events & HC_EVENT_RX) { p_hci_if->rcv(); if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0)) { /* Got HCI Cmd Credits from Controller. * Prepare to send prior pending Cmd packets in the * following HC_EVENT_TX session. */ events |= HC_EVENT_TX; } } #endif if (events & HC_EVENT_PRELOAD) { userial_open(USERIAL_PORT_1); /* Calling vendor-specific part */ if (bt_vnd_if) { bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL); } else { if (bt_hc_cbacks) bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL); } } if (events & HC_EVENT_POSTLOAD) { /* Start from SCO related H/W configuration, if SCO configuration * is required. Then, follow with reading requests of getting * ACL data length for both BR/EDR and LE. */ int result = -1; /* Calling vendor-specific part */ if (bt_vnd_if) result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL); if (result == -1) p_hci_if->get_acl_max_len(); } if (events & HC_EVENT_TX) { /* * We will go through every packets in the tx queue. * Fine to clear tx_cmd_pkts_pending. */ tx_cmd_pkts_pending = FALSE; HC_BT_HDR * sending_msg_que[64]; int sending_msg_count = 0; int sending_hci_cmd_pkts_count = 0; utils_lock(); p_next_msg = tx_q.p_first; while (p_next_msg && sending_msg_count < (int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0])) { if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD) { /* * if we have used up controller's outstanding HCI command * credits (normally is 1), skip all HCI command packets in * the queue. * The pending command packets will be sent once controller * gives back us credits through CommandCompleteEvent or * CommandStatusEvent. */ if ((tx_cmd_pkts_pending == TRUE) || (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts)) { tx_cmd_pkts_pending = TRUE; p_next_msg = utils_getnext(p_next_msg); continue; } sending_hci_cmd_pkts_count++; } p_msg = p_next_msg; p_next_msg = utils_getnext(p_msg); utils_remove_from_queue_unlocked(&tx_q, p_msg); sending_msg_que[sending_msg_count++] = p_msg; } utils_unlock(); int i; for(i = 0; i < sending_msg_count; i++) p_hci_if->send(sending_msg_que[i]); if (tx_cmd_pkts_pending == TRUE) BTHCDBG("Used up Tx Cmd credits"); } if (events & HC_EVENT_LPM_ENABLE) { lpm_enable(TRUE); } if (events & HC_EVENT_LPM_DISABLE) { lpm_enable(FALSE); } if (events & HC_EVENT_LPM_IDLE_TIMEOUT) { lpm_wake_deassert(); } if (events & HC_EVENT_LPM_ALLOW_SLEEP) { lpm_allow_bt_device_sleep(); } if (events & HC_EVENT_LPM_WAKE_DEVICE) { lpm_wake_assert(); } if (events & HC_EVENT_EPILOG) { /* Calling vendor-specific part */ if (bt_vnd_if) bt_vnd_if->op(BT_VND_OP_EPILOG, NULL); else break; // equivalent to HC_EVENT_EXIT } if (events & HC_EVENT_EXIT) break; } ALOGI("bt_hc_worker_thread exiting"); lib_running = 0; pthread_exit(NULL); return NULL; // compiler friendly }
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 = 0; while(len != 0) { #if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE) log_userial_tx_timing(len); #endif ret = write(userial_cb.fd, p_data+total, len); total += ret; len -= ret; } return ((uint16_t)total); }
write /dev/hidraw* 节点数据下发流程大致如上,敬请勘误~!