Android4.4 BLE HOGP 设备回连

好久没写东西了,今天回来看看,发现以前写的还不算太死板。写写东西也正好理理思路。

废话不多说,进入今天的主题——

Android4.4 环境下 BLE HOGP设备的自动回连

何为BLE?子曰bluetooth low energy,也就是低功耗蓝牙。BLE它是蓝牙SIG后来提出来的,最早的蓝牙是BR\EDR.。

何为HOGP?子曰hid over gatt,也就是基于GATT profile的hid。

那又为何要回连?一般的hid设备为了方便使用,都不会去使用限制用户操作的电源线来供电,而是使用电池。因此省电是对hid设备的一个基本需求,谁愿意带着每过几小时就得充电的蓝牙手环?因此当设备长时间不在使用时,蓝牙的连线应该为了省电而断开;而为了随时都可以再次使用蓝牙设备,回连就显得有必要,从而避免每次花费数十秒的重新建立连线的时间。其实原本蓝牙的hid设备都支持回连,只是那种情况是由hid device来主动连接。而BLE既然自称低功耗,回连就更不可少了。

 

下面就从Android4.4的bluedroid中看看,BLE HOGP设备的回连实现。

 

协议签订好,您就是我们的贵宾了!

首先,当底层acl链路建立起来后,作为HOGP slave的hid device和对端的master就要开始签订一些协议了(虽然称作profile,但个人觉得就是些协议)。GATT需要协商,看看HOGP device都有哪些属性(ATT,即Attribute);而HOGP则要看看你HOGP device的GATT属性值如何,从而决定master该如何通过GATT来处理HOGP device发送过来的消息。当所有的协议都签订好后,这个角色名为slave的HOGP device就将成为master的贵宾了。

 

为什么这么说呢?看看下面的代码:

 
  1. /*******************************************************************************

  2. **

  3. ** Function bta_hh_le_open_cmpl

  4. **

  5. ** Description HID over GATT connection sucessfully opened

  6. **

  7. *******************************************************************************/

  8. void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB *p_cb)

  9. {

  10. APPL_TRACE_DEBUG1("%s", __FUNCTION__);

  11. if ( p_cb->disc_active == BTA_HH_LE_DISC_NONE)

  12. {

  13. #if BTA_HH_DEBUG

  14. bta_hh_le_hid_report_dbg(p_cb);

  15. #endif

  16. bta_hh_le_register_input_notif(p_cb, 0, p_cb->mode, TRUE);

  17. bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);

  18. #if (BTA_HH_LE_RECONN == TRUE)

  19. if (p_cb->status == BTA_HH_OK)

  20. {

  21. bta_hh_le_add_dev_bg_conn(p_cb, TRUE);

  22. }

  23. #endif

  24. }

  25. }

这里是协议签订后的处理。你看注释上不是写着“HID over GATT connection sucessfully opened”么?

之所有称这个slave即将成为我们的贵宾,因为上面的代码它调用bta_hh_le_add_dev_bg_conn,将这个HOGP device加到了表示whitelist的列表中。从此这个设备可以随时断开蓝牙链路,又随时可以再连回来,只要随便按个按键即可。是不是很任性?就像是高级会员才有的权利!看看它究竟做了点什么

 
  1. 1.BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE);

  2. 2.BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL);

 

如果你看过经由GATT接口(而不是settings里头点击设备配对)来建立连接的代码,你就会发现,它和background connection建立的过程类似,只是顺序反了过来。这里的第1步做了很多事儿,它将这个HOGP device先后加到了四个全局的结构数组中:

a)bta_gattc_cb.bg_track
b)gatt_cb.bgconn_dev

c)btm_cb.ble_ctr_cb.bg_dev_list

d)btm_cb.ble_ctr_cb.wl_op_q

有什么用呢?这里仅仅是添加了,并没有真正去执行添加到whitelist中的动作。不过,这里的d)就有点类似host端whitelist的意思,后面会看到,只有在这个里头的HOGP device才会被添加到control(如果不知道host和control,请自觉去脑补蓝牙spec)的whitelist中,controller才会主动连接该设备。而c)项是另一个关于host端的whitelist记录,它和d)配合使用,HOGP device才会真正的被回连。至于剩下的两个,本文不会涉及到,不过这里简单提下。a)如其名是用来track的,我发现在出现某些bug时这个变量才会找到自己的存在感(至于是神马bug,你可以试试多个HOGP device连接同一个master的情况);而b)是gatt层对“贵宾”的记录,对于同一个HOGP device可以有不同gatt_if,但是whitelist只认蓝牙地址,因此只需要在第一次见到这个device时将它设置到host端的whitelist中,有点像”既然您是贵宾,您的家人也是贵宾,我们就不再专门做记录“的意思,不过我还没见过实际的情况。

 

至于第2步,其实它啥也没干,就只是将btm_cb.ble_ctr_cb.bg_conn_type设置成了BTA_DM_BLE_CONN_AUTO,它原来应该是BTM_BLE_CONN_NONE。其实在第1步中,它还会走到下面这段代码中:

 
  1. BOOLEAN btm_ble_resume_bg_conn(void)

  2. {

  3. tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;

  4. BOOLEAN ret = FALSE;

  5.  
  6. if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE)

  7. {

  8. if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)

  9. ret = btm_ble_start_auto_conn(TRUE);

  10.  
  11. if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)

  12. ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback);

  13. }

  14.  
  15. return ret;

  16. }

看吧,第1步它差点就走到了btm_ble_start_auto_conn,直接去执行le create connection了!不过还好,那时候的btm_cb.ble_ctr_cb.bg_conn_type为BTM_BLE_CONN_NONE。这里提下个人的发现,btm_cb.ble_ctr_cb.bg_conn_type一旦被设置为BTA_DM_BLE_CONN_AUTO了,就再也不会变回BTM_BLE_CONN_NONE了。或许有人会问了,后来的HOGP device走到上面的代码会怎么样呢,会在连接已经建立的时候去傻乎乎的再次le create connection么?答案是——你想多了。

 

我们提供优质的回连服务,您无需多虑!

走完上面两步,一切就绪,就等你HOGP device发起disconnect了!不管你多任性,我们都提供优质的回连服务!看看我们如何应对disconnect:

==>btu_hcif_disconnection_comp_evt

==>btm_sec_disconnected

==>btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr, FALSE)

==>btm_ble_resume_bg_conn

这里再次回到这个函数,看来它和回连有很大的渊源,去看看被它调用的btm_ble_start_auto_conn:

 
  1. /*******************************************************************************

  2. **

  3. ** Function btm_ble_start_auto_conn

  4. **

  5. ** Description This function is to start/stop auto connection procedure.

  6. **

  7. ** Parameters start: TRUE to start; FALSE to stop.

  8. **

  9. ** Returns void

  10. **

  11. *******************************************************************************/

  12. BOOLEAN btm_ble_start_auto_conn(BOOLEAN start)

  13. {

  14. tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;

  15. BD_ADDR dummy_bda = {0};

  16. BOOLEAN exec = TRUE;

  17. UINT8 own_addr_type = BLE_ADDR_PUBLIC;

  18. UINT16 scan_int, scan_win;

  19.  
  20. if (start)

  21. {

  22. if (p_cb->conn_state == BLE_CONN_IDLE && btm_ble_count_unconn_dev_in_whitelist() > 0)<span style="white-space:pre"> </span>//step 1

  23. {

  24. btm_execute_wl_dev_operation();<span style="white-space:pre"> </span>//step 2

  25.  
  26. scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int;

  27. scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win;

  28.  
  29. if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */

  30. scan_win, /* UINT16 scan_win */

  31. 0x01, /* UINT8 white_list */

  32. BLE_ADDR_PUBLIC, /* UINT8 addr_type_peer */

  33. dummy_bda, /* BD_ADDR bda_peer */

  34. own_addr_type, /* UINT8 addr_type_own, not allow random address for central */

  35. BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */

  36. BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */

  37. BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */

  38. BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */

  39. 0, /* UINT16 min_len */

  40. 0)) /* UINT16 max_len */

  41. {

  42. /* start auto connection failed */

  43. exec = FALSE;

  44. }

  45. else

  46. {

  47. btm_ble_set_conn_st (BLE_BG_CONN);

  48.  
  49. }

  50. }

  51. else

  52. {

  53. exec = FALSE;

  54. }

  55. }

  56. else

  57. {

  58. if (p_cb->conn_state == BLE_BG_CONN)

  59. {

  60. btsnd_hcic_ble_create_conn_cancel();

  61. btm_ble_set_conn_st (BLE_CONN_CANCEL);

  62.  
  63. }

  64. }

  65. return exec;

  66. }

这里我们不去关注回连使用的le create connection使用了那些参数,只看回连中调用的函数。

step 1:两个判断

第一个很明显,我们之前设置过了。那第二个呢?插入代码:

 
  1. UINT8 btm_ble_count_unconn_dev_in_whitelist(void)

  2. {

  3. tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;

  4. UINT8 i, count = 0;

  5.  
  6. for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++)

  7. {

  8. if (p_cb->bg_dev_list[i].in_use &&

  9. !BTM_IsAclConnectionUp(p_cb->bg_dev_list[i].bd_addr))

  10. {

  11. count ++;

  12. }

  13. }

  14. return count;

  15.  
  16. }

你瞧,前面添加的btm_cb.ble_ctr_cb.bg_dev_list派上用场了吧。这里数了数在btm_cb.ble_ctr_cb.bg_dev_list这个数组中并且没有acl链路(你看,它也不会傻到有acl链路还去再建)的设备有多少个,将总数返回。既然前面添加过,这里就一定返回大于0的结果。因此,两条判断pass,进入step 2。

 

step 2:

添加到贵宾列表——controller的whitelist中去:

 
  1. /*******************************************************************************

  2. **

  3. ** Function btm_execute_wl_dev_operation

  4. **

  5. ** Description execute the pending whitelist device operation(loading or removing)

  6. *******************************************************************************/

  7. BOOLEAN btm_execute_wl_dev_operation(void)

  8. {

  9. tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;

  10. UINT8 i = 0;

  11. BOOLEAN rt = TRUE;

  12.  
  13. for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++)

  14. {

  15. if (p_dev_op->in_use)

  16. {

  17. rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr, p_dev_op->attr);

  18. memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP));

  19. }

  20. else

  21. break;

  22. }

  23. return rt;

  24. }

看看,这里是调用btm_add_dev_to_controller来将我们的HOGP device加到controller的whitelist中了。此外,被添加的设备也被从btm_cb.ble_ctr_cb.wl_op_q中清除了。这里头还有疑问么?(你以为我会告诉你,这里把所有的device,不管连着还是断开的,都加到whitelist中了么?)

 

其实还有一个step 3的,就是上面调用btsnd_hcic_ble_create_ll_conn告诉controller使用whitelist来建立BLE链路。不过它太明显了,就不多说了。

 

到了这里,我们的服务员就已经准备好了,就等着HOGP device上门回连了。没错,是上门回连,因为master只有通过slave的advertisement才能找到HOGP device并重新建立BLE链路。只是这次,master有link key,也有gatt的cache和HOGP的cahce(也可能没有,你可以猜猜看是什么时候),因此省去了很大一块儿SMP和GATT搜索的时间。

 

服务评估:

说来说去,服务好不好都得看bluedroid代码设计的如何。如果顾及的情况不全面,那就会有问题。不过我们不该去吐槽bluedroid的提供者,它”偶然“留下的bug也让我等码农们的生活充实了不少,每次跟boss汇报都有了可观的工作量。下面列几条自动回连服务中存在的疑问:

 

1.一个HOGP设备还好,多个设备又会如何?

2.如果回连的时候master没有gatt cache,那么回连还快得起来么?

3.HOGP device断开链路master就该设置回连,那master想主动断开device,情况又是如何呢?

[cpp] view plain copy

 

  1.   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值