Bluedroid 函数分析:bta_dm_gattc_register
我们先来看看在bluedroid 里面有多少地方调用到这里:

可以看出除了 它自己声明的地方,有三处 调用到这个函数。
一处是 进行discovery,一处是进行search的时候,还有一次是bta_dm_sys_hw_cback 中,这个在bta_dm_enable的时候就已经注册了,所有其实最先注册的地方就是bta_dm_sys_hw_cback ,以后即使有地方调用该函数进行GATT 注册,也不会真正的再次注册。
另外 这个函数 其实是BTA_GATTC_AppRegister的包装,但是它限定了app_uuid 全部为0x87,由此我们得知此uuid 标识device manager 模块注册到gatt 中情况。
下面进行函数的分析:
/*******************************************************************************
**
** Function bta_dm_gattc_register
**
** Description Register with GATTC in DM if BLE is needed.
**
**
** Returns void
**
*******************************************************************************/
static void bta_dm_gattc_register(void)
{
tBT_UUID app_uuid = {LEN_UUID_128,{}}; if (bta_dm_search_cb.client_if == BTA_GATTS_INVALID_IF)
{
memset (&app_uuid.uu.uuid128, 0x87, LEN_UUID_128);
BTA_GATTC_AppRegister(&app_uuid, bta_dm_gattc_callback);//回调
}
}
首先组建了一个uuid 的结构,然后调用了BTA_GATTC_AppRegister 来进一步注册,继续看:
bta_dm_gattc_callback 这个函数是注册到DM 模块的回调函数,初步看一下,该函数主要处理的事件:BTA_GATTC_REG_EVT、BTA_GATTC_OPEN_EVT、BTA_GATTC_SEARCH_RES_EVT、BTA_GATTC_SEARCH_CMPL_EVT、BTA_GATTC_CLOSE_EVT。
下面我们看看bta_dm_gattc_register的具体的实现:
/*******************************************************************************
**
** Function BTA_GATTC_AppRegister
**
** Description This function is called to register application callbacks
** with BTA GATTC module.
**
** Parameters p_app_uuid - applicaiton UUID
** p_client_cb - pointer to the application callback function.
**
** Returns None
**
*******************************************************************************/
void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb)
{
tBTA_GATTC_API_REG *p_buf; if (bta_sys_is_register(BTA_ID_GATTC) == FALSE)
{
bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);//如果BTA GATTC模块没有注册到BTA,那么先注册
} if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL)
{
p_buf->hdr.event = BTA_GATTC_API_REG_EVT;//发送事件注册到BTA——GATTC
if (p_app_uuid != NULL)
memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
p_buf->p_cback = p_client_cb; bta_sys_sendmsg(p_buf);
}
return;
}
我们看到是发送event BTA_GATTC_API_REG_EVT 到btu task来处理,可以预想,这个工作结束之后肯定是调用bta_dm_gattc_callback处理的event 是应该是BTA_GATTC_REG_EVT,
我们继续看看,btu task 对这个event 的处理:
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;
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;
...
BTA_ID_GATTC 注册到sys 里面的注册信息, 对应的handler 就是bta_gattc_hdl_event ,我们继续看对 注册 的实质性操作:
/*******************************************************************************
**
** Function bta_gattc_register
**
** Description Register a GATT client application with BTA.
**
** Returns void
**
*******************************************************************************/
void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
UINT8 i;
tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid;//拿出uuid
tBTA_GATTC_INT_START_IF *p_buf;
tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES; APPL_TRACE_DEBUG("bta_gattc_register state %d",p_cb->state);//gattc 模块的状态
memset(&cb_data, , sizeof(cb_data));
cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES;
...
/* todo need to check duplicate uuid */
for (i = ; i < BTA_GATTC_CL_MAX; i ++)//gattc 模块里面有32个slot可供注册
{
if (!p_cb->cl_rcb[i].in_use)//找一个没有被use的slot
{
if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == )//注册到stack-gatt
{
APPL_TRACE_ERROR("Register with GATT stack failed.");
status = BTA_GATT_ERROR;
}
else//注册成功,那么在BTA的模块中记录注册的相关的信息
{
p_cb->cl_rcb[i].in_use = TRUE;
p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback;//就是
memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));//保存相应的uuid /* BTA use the same client interface as BTE GATT statck */
cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if;//client_if,该值在BTE和BTA里面的值是一样的 if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL)
{
p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT;//再次向btu task 发送任务
p_buf->client_if = p_cb->cl_rcb[i].client_if; bta_sys_sendmsg(p_buf);
status = BTA_GATT_OK;
}
else
{
GATT_Deregister(p_cb->cl_rcb[i].client_if); status = BTA_GATT_NO_RESOURCES;
memset( &p_cb->cl_rcb[i], , sizeof(tBTA_GATTC_RCB));
}
break;
}
}
} /* callback with register event */
if (p_data->api_reg.p_cback)
{
if (p_app_uuid != NULL)
memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID)); cb_data.reg_oper.status = status;
(*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data);//调用回调,果然还是上报BTA_GATTC_REG_EVT 这个event
}
}
我们还是分成几个部分来分析这个问题:
- GATT_Register
- BTA_GATTC_INT_START_IF_EVT
- p_data->api_reg.p_cback---BTA_GATTC_REG_EVT
下面先看
GATT_Register的实现:
这里发现 GATT_register 这个注册到BTE 模块也有一个callback 函数:bta_gattc_cl_cback ,这个回调 就是汇报状态到BTA 层面,其是一簇函数:
static tGATT_CBACK bta_gattc_cl_cback =
{
bta_gattc_conn_cback,
bta_gattc_cmpl_cback,
bta_gattc_disc_res_cback,
bta_gattc_disc_cmpl_cback,
NULL,
bta_gattc_enc_cmpl_cback,
bta_gattc_cong_cback
};
从名字上面 大概都能看出其功能。我们看看 GATT_register:
/*******************************************************************************
**
** Function GATT_Register
**
** Description This function is called to register an application
** with GATT
**
** Parameter p_app_uuid128: Application UUID
** p_cb_info: callback functions.
**
** Returns 0 for error, otherwise the index of the client registered with GATT
**
*******************************************************************************/
tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
{
tGATT_REG *p_reg;
UINT8 i_gatt_if=;
tGATT_IF gatt_if=; gatt_dbg_display_uuid(*p_app_uuid128); for (i_gatt_if = , p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)//注册到BTE GATT的大本营是gatt_cb
{
if (p_reg->in_use && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
{
GATT_TRACE_ERROR("application already registered.");
return ;
}
} for (i_gatt_if = , p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
{
if (!p_reg->in_use)
{
memset(p_reg, , sizeof(tGATT_REG));
i_gatt_if++; /* one based number 从开始计数*/
p_reg->app_uuid128 = *p_app_uuid128;
gatt_if =
p_reg->gatt_if = (tGATT_IF)i_gatt_if;//发现这个gatt_if就是reg结构在gatt_cb中index+1
p_reg->app_cb = *p_cb_info;//回调的函数簇 保存在reg结构里面
p_reg->in_use = TRUE; break;
}
}
return gatt_if;
}
这个函数很简单,正如注释描述:“This function is called to register an application with GATT”
之前比较困惑的gatt_if,其实就是注册的结构体在gatt_cb 里面的index+1,那这个gatt_if 和保存在bta_gattc_cb中注册信息的index 有什么关系?没有关系。bta_gattc_cb.cl_rcb[index_bta].client_if = gatt_if
下面分析一下第三点:
p_data->api_reg.p_cback---BTA_GATTC_REG_EVT
/*******************************************************************************
**
** Function bta_dm_gattc_callback
**
** Description This is GATT client callback function used in DM.
**
** Parameters:
**
*******************************************************************************/
static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
{
switch (event)
{
case BTA_GATTC_REG_EVT:
if (p_data->reg_oper.status == BTA_GATT_OK)
bta_dm_search_cb.client_if = p_data->reg_oper.client_if;//保存gatt_if在bta_dm_search_cb结构中
else
bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF;
break;
该回调非常的简单,就是上报了gatt_if 给bta_dm_search_cb结构。其实到这里可以说 注册的流程已经走完了。
下面看
BTA_GATTC_INT_START_IF_EVT的处理
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
...
case BTA_GATTC_INT_START_IF_EVT:
bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
...
程序走到当前的状态,其实 是已经配对完成了,在做GATT相关的处理,
/*******************************************************************************
**
** Function bta_gattc_start_if
**
** Description start an application interface.
**
** Returns none.
**
*******************************************************************************/
void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
{
UNUSED(p_cb); if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) !=NULL )//找到bta 层的reg,这里的client_if不是reg的index,是根据client_if的匹配来查找的
{
GATT_StartIf(p_msg->int_start_if.client_if);
}
else
{
APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if );
}
}
/*******************************************************************************
**
** Function GATT_StartIf
**
** Description This function is called after registration to start receiving
** callbacks for registered interface. Function may call back
** with connection status and queued notifications
**
** Parameter gatt_if: applicaiton interface.
**
** Returns None.
**
*******************************************************************************/
void GATT_StartIf (tGATT_IF gatt_if)
{
tGATT_REG *p_reg;
tGATT_TCB *p_tcb;
BD_ADDR bda;
UINT8 start_idx, found_idx;
UINT16 conn_id;
tGATT_TRANSPORT transport ; if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
{
start_idx = ;
while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))//查找已经连的设备
{
p_tcb = gatt_find_tcb_by_addr(bda, transport);
if (p_reg->app_cb.p_conn_cb && p_tcb)
{
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);//tcb_idx是tcb 在gatt_cb里面的index
(*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, , transport);//回调
}
start_idx = ++found_idx;//继续查找
}
}
}
目前还不清楚conn_id 有什么作用,先分析其构成:
#define GATT_CREATE_CONN_ID(tcb_idx, gatt_if) ((UINT16) ((((UINT8)(tcb_idx) ) << 8) | ((UINT8) (gatt_if))))
tcb的index 是高八位,gatt_if是第八位
如果是刚刚注册的case,那么这里应是不会查找到已经连的设备.
关于gatt registeration的分析 就先到这里.
Bluedroid 函数分析:bta_dm_gattc_register的更多相关文章
- Bluedroid 函数分析:BTA_GATTC_Open
进行GATT 通信,首先要打开GATT 的通道.下面我们分析BTA_GATTC_Open 这个函数: 这个函数在bta_gattc_api.c 文件中定义,这个是一个接口文件,里面没有做真正的open ...
- split(),preg_split()与explode()函数分析与介
split(),preg_split()与explode()函数分析与介 发布时间:2013-06-01 18:32:45 来源:尔玉毕业设计 评论:0 点击:965 split()函数可以实 ...
- string函数分析
string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把 ...
- start_amboot()函数分析
一.整体流程 start_amboot()函数是执行完start.S汇编文件后第一个C语言函数,完成的功能自然还是初始化的工作 . 1.全局变量指针r8设定,以及全局变量区清零 2.执行一些类初始化函 ...
- uboot的jumptable_init函数分析
一.函数说明 函数功能:安装系统函数指针 函数位置:common/exports.c 二.函数分析 void jumptable_init (void) { int i; gd->jt = (v ...
- Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析
Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /* ...
- 31.QPainter-rotate()函数分析-文字旋转不倾斜,图片旋转实现等待
在上章和上上上章: 28.QT-QPainter介绍 30.QT-渐变之QLinearGradient. QConicalGradient.QRadialGradient 学习了QPainter基础绘 ...
- 如何验证一个地址可否使用—— MmIsAddressValid函数分析
又是一篇内核函数分析的博文,我个人觉得Windows的内核是最好的老师,当你想实现一个功能之前可以看看Windows内核是怎么做的,说不定就有灵感呢:) 首先看下官方的注释说明: /*++ Routi ...
- STM32F10X固件库函数——串口清状态位函数分析
STM32F10X固件库函数——串口清状态位函数分析 最近在测试串口热插拔功能的时候,意外发现STM32F10X的串口库函数中,清理串口状态位函数稍稍有点不解.下面是改函数的源码: /******** ...
随机推荐
- 【Java入门提高篇】Day34 Java容器类详解(十五)WeakHashMap详解
源码详解系列均基于JDK8进行解析 说明 在Java容器详解系列文章的最后,介绍一个相对特殊的成员:WeakHashMap,从名字可以看出它是一个 Map.它的使用上跟HashMap并没有什么区别,所 ...
- linux服务器系统盘坏且系统盘为软raid的修复方法
1 需要换新盘的情况 1.1 一块盘grub损坏修复 一块盘grub损坏修复(可通过另一块盘进入系统的情况).更换硬盘的方式,可以热插拔,也可以服务器断电后更换,但如果是热插拔,可能会导致盘符变更.坏 ...
- V4L2 driver -整体架构
我的uvc开源地址:gitee-uvc 字符设备驱动程序核心:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间. V4L2 驱动核心:主要是构建一个内核中标准视频设备驱动的框架 ...
- <!DOCTYPE>标签与table高度100% (转)
<!DOCTYPE>标签可声明三种DTD类型,分别表示严格版本.过渡版本以及基于框架的 HTML 文档. 三种HTML文档类型: HTML 4.01 规定了三种文档类型:Strict.Tr ...
- 【错误记录】PowerShell 超级无语的语法错误(令人怀疑人生)
曾经做过测试,本文是本章优秀测试人员的精神,必须定位到原因,不然吃不下饭.其实可以很容易绕过这种问题. 环境: PowerShell 5.1.16299.64 Windows 10 现有代码如下: # ...
- webpack打包去掉console.log打印与debugger调试
如图,找到build/webpack.prod.conf.js 在 UglifyJsPlugin 插件下添加下列代码 drop_debugger: true, drop_console: true
- DAG 动态规划 巴比伦塔 B - The Tower of Babylon
题目:The Tower of Babylon 这是一个DAG 模型,有两种常规解法 1.记忆化搜索, 写函数,去查找上一个符合的值,不断递归 2.递推法 方法一:记忆化搜索 #include < ...
- MP实战系列(三)之实体类讲解
首先说一句,mybatis plus实在太好用了! mybaits plus的实体类: 以我博客的用户类作为讲解 package com.blog.entity; import com.baomido ...
- ES6生成器函数generator
ES6生成器函数generator generator是ES6新增的一个特殊函数,通过 function* 声明,函数体内通过 yield 来指明函数的暂停点,该函数返回一个迭代器,并且函数执行到 y ...
- B-Tree外存数据结构 _(外存储器—磁盘)第一部分
1.外存储器—磁盘 计算机存储设备一般分为两种:内存储器(main memory)和外存储器(external memory).内存存取速度快,但容量小,价格昂贵,而且不能长期保存数据(在不通电情况下 ...