zoukankan      html  css  js  c++  java
  • bluedroid源代码分析之ACL包发送和接收(一)

    很多其它内容请參照我的个人网站: http://stackvoid.com/

    ACL 链路在 Bluetooth 中很重要,一些重要的应用如 A2DP, 基于 RFCOMM 的应用,BNEP等都要建立 ACL 链路,发送/接收ACL 包。今天跟大家一起来分析 ACL 包发送/接收流程,以及涉及到的重要 command/event。


    ACL包发送

    以下的图(点击大图)是各种应用层使用 L2CAP 的 API:L2CA_DataWrite 发送数据流的过程,此API继续往下走,我仅分析了正常数据流的走向(临时没有考虑别的情况)。

    ACL_01


    应用层数据到 L2CAP 的入口

    我们如果一个听音乐的场景,Mike跟大家一起分析音乐数据流 AVDTP 下面层的传送。

    在 AVDTP 中,全部的功能想发送 Data,必须调用 avdt_ad_write_req 这个函数。Mike 就从这个函数入手分析。

     1 //当CCB或SCB给l2cap的 Channel 发送数据时。他们终于都会使用到L2CAP的 API:L2CA_Data_Write
     2 UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
     3 {
     4     UINT8   tcid;
     5 
     6     /* get tcid from type, scb */
     7     tcid = avdt_ad_type_to_tcid(type, p_scb);
     8 
     9 
    10     return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
    11 }
    12 //L2CA_DataWrite的返回形式有三种,各自是:
    13 //1. L2CAP_DW_SUCCESS:此数据写成功
    14 //2.L2CAP_DW_CONGESTED:写数据成功,可是当前信道拥堵
    15 //3.L2CAP_DW_FAILED:写数据失败
    16 UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data)
    17 {
    18     L2CAP_TRACE_API2 ("L2CA_DataWrite()  CID: 0x%04x  Len: %d", cid, p_data->len);
    19     return l2c_data_write (cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
    20 }

    当我们的音乐数据流到达 l2c_data_write 这个函数时,标志数据流正式进入到L2CAP层。 我们在以下的源代码中深入分析 l2c_data_write 这个函数。

    l2c_data_write 这个函数做的事情主要有:

    1. 依据參数 cid(Channel ID) 找到 相应的 ccb(Channel Control Block), 找不到返回 L2CAP_DW_FAILED
    2. 假设測试者 打开 TESTER 这个宏,发送随意数据,当数据大小 大于 MTU 最大值,也会返回 L2CAP_DW_FAILED
    3. 通过检查 p_ccb->cong_sent 字段,TRUE。则说明当前 Channel 已经拥挤,此时L2CAP的这个Channel不在接收数据,返回 L2CAP_DW_FAILED
    4. 以上三个条件都通过。说明数据可发送。将数据通过 l2c_csm_execute 继续处理。

      进入 l2c_csm_execute 函数,标志着这笔数据已经成功交给 l2CAP 来处理。与上层已经没有关系了。

    5. l2c_csm_execute 函数运行结束后,再次检查 p_ccb->cong_sent 字段,看看当前的 Channel 是否拥挤,假设拥挤则告诉上层 L2CAP_DW_CONGESTED,否则返回 L2CAP_DW_SUCCESS,表示数据已经成功发送。

      1 //返回的数据跟上面的 L2CA_DataWrite 作用同样
      2 UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flags)
      3 {
      4     tL2C_CCB        *p_ccb;
      5 
      6     //遍历l2cb.ccb_pool。通过Channel ID找到相应的Channel Control Block
      7     //l2cu_find_ccb_by_cid 见以下源代码凝视
      8     if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
      9     {
     10         L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
     11         GKI_freebuf (p_data);
     12         return (L2CAP_DW_FAILED);
     13     }
     14 
     15 #ifndef TESTER /* Tester may send any amount of data. otherwise sending message
     16                   bigger than mtu size of peer is a violation of protocol */
     17     if (p_data->len > p_ccb->peer_cfg.mtu)
     18     {
     19         L2CAP_TRACE_WARNING1 ("L2CAP - CID: 0x%04x  cannot send message bigger than peer's mtu size", cid);
     20         GKI_freebuf (p_data);
     21         return (L2CAP_DW_FAILED);
     22     }
     23 #endif
     24 
     25     /* channel based, packet based flushable or non-flushable */
     26     //Bluedroid中默认的是 L2CAP_FLUSHABLE_CH_BASED
     27     //这个 layer_specific 在 数据发送的 l2c_link_send_to_lower 中表示 ACL包分包 个数
     28     p_data->layer_specific = flags;
     29 
     30     //发现本 Channel 已经拥堵,直接返回L2CAP_DW_FAILED 告诉上层等会再发数据
     31     //当几个应用 共用 此 Channel 可能会出现这样的情况
     32     if (p_ccb->cong_sent)
     33     {
     34         L2CAP_TRACE_ERROR3 ("L2CAP - CID: 0x%04x cannot send, already congested  xmit_hold_q.count: %u  buff_quota: %u",
     35                             p_ccb->local_cid, p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
     36 
     37         GKI_freebuf (p_data);
     38         return (L2CAP_DW_FAILED);
     39     }
     40     //毫无疑问啦,这个函数就是我们继续须要分析的函数
     41     l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data);
     42 
     43     //已经将上层的这笔数据发送完,假设此 Channel 拥挤了(之前发送这笔包还没拥挤)
     44     //返回 L2CAP_DW_CONGESTED 告诉上层当前信道拥挤,你要给我L2CAP层发数据,是不发下来的
     45     if (p_ccb->cong_sent)
     46         return (L2CAP_DW_CONGESTED);
     47 
     48     //成功发送。而且此时 Channel 并不拥挤
     49     return (L2CAP_DW_SUCCESS);
     50 }
     51 
     52 //通过 Channel ID 找到 Channel Control Block
     53 tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, UINT16 local_cid)
     54 {
     55     tL2C_CCB    *p_ccb = NULL;
     56 #if (L2CAP_UCD_INCLUDED == TRUE)
     57     UINT8 xx;
     58 #endif
     59 
     60     if (local_cid >= L2CAP_BASE_APPL_CID) //大于或等于 0x0040 说明不是 Fixed Channel
     61     {
     62         /* find the associated CCB by "index" */
     63         local_cid -= L2CAP_BASE_APPL_CID;
     64 
     65         if (local_cid >= MAX_L2CAP_CHANNELS)
     66             return NULL;
     67 
     68         p_ccb = l2cb.ccb_pool + local_cid; //直接通过地址偏移找到
     69 
     70         /* make sure the CCB is in use */
     71         if (!p_ccb->in_use)
     72         {
     73             p_ccb = NULL;
     74         }
     75         /* make sure it's for the same LCB */
     76         else if (p_lcb && p_lcb != p_ccb->p_lcb)
     77         {
     78             p_ccb = NULL;
     79         }
     80     }
     81 #if (L2CAP_UCD_INCLUDED == TRUE) //默认是关闭的,既然从上层来的都是 数据包了,我觉得不会用到 Fixed Channel
     82     else
     83     {
     84         /* searching fixed channel */
     85         p_ccb = l2cb.ccb_pool;
     86         for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
     87         {
     88             if ((p_ccb->local_cid == local_cid)
     89               &&(p_ccb->in_use)
     90               &&(p_lcb == p_ccb->p_lcb))
     91                 break;
     92             else
     93                 p_ccb++;
     94         }
     95         if ( xx >= MAX_L2CAP_CHANNELS )
     96             return NULL;
     97     }
     98 #endif
     99 
    100     return (p_ccb);
    101 }

    下一篇博客我们来看看 L2CAP 层的处理。


    很多其它内容请參照我的个人网站: http://stackvoid.com/

  • 相关阅读:
    Qt内存回收机制
    Qt坐标系统
    Qt信号与槽的使用
    Qt初始化代码基本说明
    Qt下载、安装及环境搭建
    搭建CentOs7的WebServer
    Laying out a webpage is easy with flex
    Let's write a framework.
    使用go语言开发一个后端gin框架的web项目
    个人总结的J2EE目前知道的涵盖面,从大方向入手,多写单元测试,加强基础
  • 原文地址:https://www.cnblogs.com/llguanli/p/6854887.html
Copyright © 2011-2022 走看看