精华内容
下载资源
问答
  • 2021-01-08 15:25:48

    1. 前言

    了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connection)是一个相当消耗资源(power和带宽)的过程。特别是当没有数据传输的时候,所消耗的资源完全被浪费了。因而,对很多蓝牙设备来说(特别是功耗敏感的设备),希望在无数可传的时候,能够断开连接。但是,由于跳频(hopping)以及物理通道(Physical Channel)划分的缘故,经典蓝牙连接建立的速度实在难以忍受(要好几秒)。对那些突发的数据传输来说,几秒钟的连接延迟,简直是灾难。

    因此,蓝牙SIG制订BLE规范的时候,充分考虑了这方面的需求,极大的简化了连接的建立过程,使连接速度可以达到毫秒级(最快3.75ms就可以搞定)。与此同时,为了节省功耗,也调整了跳频的策略。至此,相比广播通信而言,BLE面向连接的通信,几乎没有额外的代价。

    在“蓝牙协议分析(5)_BLE广播通信相关的技术分析”中,我们对BLE的广播通信有了比较全面的了解,本文将接着分析和面向连接的通信有关的技术,包括连接的建立和断开、BLE跳频(Hopping)技术、Link Layer的应答、重传、流控、等等。

    2. 怎样才算是建立了连接?

    开始之前,我们先回答一个问题,对通信的双方而言,怎样才算建立了连接呢?

    从字面上理解,建立了连接,就是指:

    二者之间,建立了一条专用的通道,它们可以随时随地的通信。

    当然,在蓝牙这种资源有限的通信系统中,通道无法独占,退而求其次,分时也Okay。因此,在BLE中建立了连接,是这样定义的:

    在约定的时间段内,双方都到一个指定的物理Channel上通信。

    其中,“约定好的时间段”,是时分的概念。而“到指定的物理Channel上”,是跳频的概念。后面的分析,将会围绕这两个概念进行。

    另外,和“蓝牙协议分析(5)_BLE广播通信相关的技术分析”类似,我们也将从Link Layer、HCI、GAP三个层次,分别介绍。

    3. Link Layer

    3.1 角色的定义

    和经典蓝牙一样,协议为处于连接状态的BLE设备,定义了两种Link Layer角色:Master和Slave。Master是连接的发起方(Initiator),可以决定和连接有关的参数(很重要,后面会详细介绍)。Slave是连接的接受方(Advertiser),可以请求(或建议)连接参数,但无法决定。

    注1:两个BLE设备之间,只能建立一条连接。

    3.2 PDU的定义

    和广播通信不同,面向连接的通信使用特定的PDU,称作Data Channel PDU,格式如下(LSB---->MSB):

     

    Header(16 bits)Payload(Variable size)MIC(32 bits)

     

    16bits的Header的格式如下:

    LLID(2 bits)NESN (1bit)SN(1 bit)MD(1 bit)RFU(3 bits)Length(8 bits)

    Data Channel传输的PDU有两类,一类是数据,称作LL Data PDU,另一类中控制信息,称作LL Control PDU。LLID用于区分PDU的类型,具体可参考后面3.2.1和3.2.2的描述。

    NESN(Next Expected Sequence Number)和SN(Sequence Number),用于数据传输过程中的应答(Acknowledgement)和流控(Flow Control),具体可参考后面3.7的介绍。

    MD(More Data),用于连接的关闭(或者说保持),具体可参考后面3.5的介绍。

    RFU(Reserved for Future Use)。

    Length,有效数据的长度(Payload+MIC),只有8-bits,因此Link Layer所能传输的最大数据是255 bytes(有MIC的话是251bytes),如果L2CAP需要传输更多的数据,需要分包之后传输(这也是L2CAP的主要功能之一,具体可参考“蓝牙协议分析(3)_蓝牙低功耗(BLE)协议栈介绍”)。

    Payload是有效数据(SDU,L2CAP的PDU),长度由Header中的Length字段觉得,有效范围是0~255。

    3.2.1 LL Data PDU

    LL Data PDU有两种:

    Header中的LLID=01b时,Continuation fragment of an L2CAP message, or an Empty PDU。这种类型的PDU,要么是一个未传输完成L2CAP message(长度超过255,被拆包,此时不是第一个),要么是一个空包(Header中的Length为0)。

    Header中的LLID=10b时,Start of an L2CAP message or a complete L2CAP message with no fragmentation。这种类型的PDU,要么是L2CAP message的第一个包,要么是不需要拆包的完整的L2CAP message,无论哪种情况,Header中的Length均不能为0。

    3.2.2 LL Control PDU

    Header中的LLID=11b时,表示这个数据包是用于控制、管理LL连接的LL control PDU。LL control PDU的payload的格式如下:

    Opcode(1 octet)CtrlData(0 ~ 26 octets)

    其中Opcode指示控制&管理packet的类型,包括:

    LL_CONNECTION_UPDATE_REQ,连接参数的更新;
    LL_CHANNEL_MAP_REQ,Channel map的更新;
    LL_TERMINATE_IND,连接即将被关闭的通知(可以通知被关闭的原因);
    LL_ENC_REQ、LL_ENC_RSP、LL_START_ENC_REQ、LL_START_ENC_RSP,加密有关的请求;等等,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”。

    3.3 连接的建立

    对BLE来说,连接建立的过程很简单,包括:

    1)处于connectable状态设备(Advertiser),按照一定的周期广播ADV_IND或者ADV_DIRECT_IND包(可参考“蓝牙协议分析(5)_BLE广播通信相关的技术分析”)。

    2)主动连接的设备(Initiator),在收到广播包之后,会回应一个CONNECT_REQ请求,该请求携带了可决定后续“通信时序”的参数,例如双方在哪一个时间点、哪一个Physical Channel收发数据,等等,后面会详细描述。

    3)Initiator在发出CONNECT_REQ数据包之后,自动转变为Connection状态,成为Master角色(注意:这是“自动”的,不需要等待另一方的回应)。同样,Advertiser在收到CONNECT_REQ请求之后,也自动转变为Connection状态,成为Slave角色。

    4)此后,双方按照CONNECT_REQ参数所给出的约定,定时到切换到某一个Physical Channel上,按照Master->Slave然后Slave->Master的顺序,收发数据,直至连接断开。

    master在发出连接请求的时候,需要在CONNECT_REQ PDU的payload中,定义和连接有关的参数。payload的格式如下:

    InitA (6 octets)AdvA (6 octets)LL Data (22 octets)

     

    其中InitA和AdvA分别是Master和Slave的蓝牙地址,LL data则包含了所有的连接参数,包括:

    AA
    (4 octets)
    CRCInit
    (3 octets)
    WinSize
    (1 octet)
    WinOffset
    (2 octets)
    Interval
    (2 octets)
    Latency
    (2 octets)
    Timeout
    (2 octets)
    ChM
    (5 octets)
    Hop
    (5 bits)
    SCA
    (3 bits)

    AA,LL Connection的Access Address,在不同设备组合之间,需要唯一,并遵守一些原则,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”。

    CRCInit,用于CRC计算的一个初始值,由Link Layer随机生成。

    WinSize和WinOffset,全称是transmitWindowSize和transmitWindowOffset,用于决定连接双方收发数据的时间窗口(第2章提到的时分的概念)。下面3.4小节会详细介绍。

    connInterval,全称是connInterval,连接双方收发数据的周期。由于一个Master可能会和多个Slave建立连接,因此蓝牙的信道资源不能被某一个LL Connection所独占,所以一个收发周期中,可能有多个连接进行收发数据(具体的时间窗口,由transmitWindowOffset决定)。下面3.4小节会详细介绍。

    Latency和Timeout,全称是connSlaveLatency和connSupervisionTimeout,和连接超时、自动断开有关,具体可参考3.4小节的描述。

    ChM的全称是Channel map,用于标识当前使用和未使用的Physical Channel。Hop的全称是hopIncrement,它和ChM一起决定了数据传输过程中的跳频算法,具体可参考3.6小节的描述。

    SCA(sleep clock accuracy),用于定义最差的Master睡眠时钟精度,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”,本文不再详细介绍。

    3.4 连接建立后的通信过程

    3.3小节提到,当Master发出/Slave收到CONNECT_REQ后,就自动进入连接状态,那双方在收发数据的时间窗口怎么确定呢?可参考下面图片1和图片2:

    BLE连接时序---Master视角

    图片1 BLE连接时序---Master视角

    BLE连接时序---Slave视角

    图片2 BLE连接时序---Slave视角

    1)从Master的视角看,当它发出CONNECT_REQ后,会在1.25 ms + transmitWindowOffset到1.25ms + transmitWindowOffset + transmitWindowSize之间,发送第一个packet(M->S)。同理,Slave在收到CONNECT_REQ之后,也会在相应的时间区间去接收packet(M->S)。

    a)transmitWindowOffset可以控制这个LL Connection使用哪一段时间进行通信,从而保证了同一个Master和多个Slave之间的多个连接,可以互不影响的通信(时分)。transmitWindowOffset的取值范围是:0 ms到connInterval(后面会介绍connInterval)。

    b)从Master发出CONNECT_REQ,到Slave接收到CONNECT_REQ,是有一定的时间延迟的,因此需要一定的时间窗口(transmitWindowSize),才能保证第一个packet能否正确的发送并被接收。transmitWindowSize必须是1.25ms的倍数,最小值是1.25 ms,最大值是(connInterval - 1.25 ms),但不能超过10ms。

    c)正常情况下,所有“M->S”数据包的发送,不能超过transmitWindowSize,以便留出S->M的时间。但第一个packet例外(参考上面图片1)。

    2)Master发出第一个packet之后,将以此为起始点(称作anchor point),以connInterval为周期,接着发送后续的packet(M->S),以及接收Slave的packet(S->M),具体可参考上面图片1。

    a)这样以connInterval为周期的发送(M->S)、接收(S->M)组合(可能有多个),称作Connection Event。因此BLE面向连接的通信的基础,就是Connection Event。

    b)connInterval的大小,决定了数据传输的周期。对一个连接来说,每个周期只能有一次的收发,因此connInterval的选择,直接决定了数据传输的速度。BLE协议规定,connInterval必须是1.25ms的倍数,范围是7.5ms~4s。

    3)Slave如果没有收到第一个packet(M->S),则会以1.25 ms + transmitWindowOffset为起点,等待connInterval之后,再次尝试接收,直到接收到为止。Slave接收到packet之后,则以收到该packet的时间点为起始点(anchor point),以connInterval为周期,接着接收后续的packet(M->S),以及发送packet给Master(S->M),具体可参考上面图片2。

    注2,关于数据传输的速率:
    由上面的通信过程可知,BLE面向连接的通信速率,是由connInterval以及每个Connection Event中所传输的数据量决定的。
    由上面3.2的描述可知,LL Data PDU的有效负荷不能超过255(251)bytes,不过考虑到一次传输的效率、错误处理等因素,具体的Link Layer不会使用这么大的packet。相应地,为了提高传输速度,一般会在一个Connection Event中,传输多个packet。以iOS为例,它可能会在一个Connection Event中,传输6个packets,每个packet的长度是20bytes。
    另外,很多平台为了保证自身作为Master的性能,会限制connInterval的最小值,以iOS为例,最小值是30ms。因此,可估算得到相应的传输速率为20B * 6 / 30ms = 32kbps,是相当缓慢的。

    注3:BLE的面向连接通信是使用跳频技术的,即每次Connection Event,都会使用不同Physical Channel收发数据,具体的跳频机制,可参考3.6小节的介绍。

    3.5 连接的控制与管理

    连接建立之后,Master或者Slave可以借助Link Layer Control Protocol (LLCP),通过LL Control PDU,对连接进行管理控制,包括:

    Connection Update Procedure,连接参数(包括connInterval,connSlaveLatency,connSupervisionTimeout)更新的通知。只能由Master发起。

    Channel Map Update Procedure,更新Channel map。只能由Master发起。

    Encryption Procedure,对连接进行加密,可由master或者slave发起。

    Termination Procedure,断开连接。

    Connection Parameters Request Procedure,请求更新连接参数(connInterval,connSlaveLatency,connSupervisionTimeout),Slave或者Master都可以发起,和Connection Update Procedure不同是,这是一个协商的过程,不是一定能够成功。

    LE Ping Procedure,类似于网络协议中ping操作。

    等等。不再详细介绍,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”。

    3.6 连接超时及断开

    BLE连接断开的原因有两种:一种是预期内的、主动断开,此时会走3.4小节提到的Termination Procedure过程;第二种是一些非预期的原因导致的超时断开,如距离超出、遭受严重的干扰、突然断电等。

    对于第一种,是协议内的正常流程,没有什么好说的。而对于第二种,则需要一些timeout机制,检测这写异常情况,具体如下。

    1)Master和Slave的Link Layer,都会启动一个名称为TLLconnSupervision的timer,每接收到一个有效的数据包时,该timer都会重置。

    2)连接建立的过程中,如果TLLconnSupervision超过6 * connInterval(没有接收到第一个数据包),则认为连接建立失败。

    3)在连接成功之后,如果TLLconnSupervision超过connSupervisionTimeout,则说明link loss,则执行超时断开。connSupervisionTimeout是一个可配置的参数,范围是100ms~32s,并且不能大于(1 + connSlaveLatency) * connInterval * 2。

    4)BLE协议允许slave忽略掉“connSlaveLatency”个Connection Event,在被忽略的这段时间内,Slave不需要收发数据包,也不会增加TLLconnSupervision,从而引发超时断开。connSlaveLatency是一个整数,有效范围应该在0到((connSupervisionTimeout / (connInterval*2)) - 1)之间,并且不能大于500。

    注4:connSlaveLatency是一个非常有用的参数,它允许Slave在数据通信不频繁的时候,忽略掉一些Connection Event,进而可以睡得更久,更加省电。

    3.7 跳频(Hopping)策略

    BLE的跳频策略是非常简单的,即:每一个Connection Event,更换一次Physical Channel,当然,master和slave需要按照相同的约定更换,不然就无法通信。这个约定如下:

     

    图片3 BLE跳频策略

    1)首先,使用一个Basic的算法,利用lastUnmappedChannel和hopIncrement,计算出unmappedChannel。

    a)lastUnmappedChannel在连接建立之初的值是0,每一次Connection Event计算出新的unmappedChannel之后,会更新lastUnmappedChannel。

    b)hopIncrement是由Master在连接建立时随机指定的,范围是5到16(可参考3.3中的Hop)。

    c)确定unmappedChannel的算法为:unmappedChannel = (lastUnmappedChannel + hopIncrement) mod 37,本质上就是每隔“hopIncrement”个Channel取一次,相当直白和简单。

    2)计算出unmappedChannel之后,查找当前的Channel map,检查unmappedChannel所代表的Channel是否为used channel。如果是,恭喜,找到了。

    Channel map也是由master,在连接建立时,或者后来的Channel map update的时候指定的。

    3)如果不是,将所有的used Channel以升序的方式见一个表,表的长度是numUsedChannels,用unmappedChannel和numUsedChannels做模运算,得到一个index,从按照该index,从表中取出对应的channel即可。

    3.8 应答(Acknowledgement)和流控(Flow Control)

    由3.2小节的描述可知,LL Data PDU的Header中,有NESN(Next Expected Sequence Number)和SN(Sequence Number)两个标记,利用它们,可以很轻松的在Link Layer实现应答、重传、流控等机制。

    为了实现这些功能,Link Layer会为每个连接创建两个变量,transmitSeqNum和nextExpectedSeqNum(为了和packet的SN/NESN bit区分,我们将它们简称为sn和nesn),并在连接建立的时候,它们都被初始化为0。

    sn用于标识本地设备(Link Layer)发送出去的packets。

    nesn是对端设备(Link Layer)用来应答本地设备发送的packet,或者请求本地设备重发packet。

    Link Layer在收发packet时,会遵循如下的原则(可结合下面图片4理解):

    注5:下面图片4是从“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”中截的一张图,不过spec中画的有问题,我用红色字体改正了。另外,这个图片非常有歧义、难以理解,我会在下面解释。

    1)无论是Master还是Slave,发送packet的时候,都会将当前的sn和nesn copy到packet的SN和NESN bit中。

    2)无论是Master还是Slave,当接收到一个packet的时候,会将该packet的NESN bit和本地的sn比较:如果相同,说明该packet是对端设备发来的NAK packet(请求重发),则需要将旧的packet重新发送出去;如果不同,说明是对端设备发来的ACK packet(数据被正确接收),则需要将本地的sn加1,接着发送新的packet。

    a)以上过程可参考下面图片4中的左边部分。

    b)本地的sn,代表本地设备已经发送出去的packet,而packet中的NESN bit,代表对端设备期望本地设备发送的packet。如果二者相同,说明对方期望下次发送的packet,和我们已经发送的packet相同,因此是NAK信号,要求重发。如果二者不同,说明对方设备期望发送一个新的packet,也说明我们上次发送的packet已经成功接收,因此可以将本地的sn加1了。

    3)无论是Master还是Slave,当接收到一个packet的时候,会将该packet的SN bit和本地的nesn比较:如果相同,则说明是一个新的packet,接收即可,同时将本地的nesn加1;如果不同,则说明是一个旧的packet,什么都不需要处理。

    a)以上过程可参考下面图片4中的右边部分。

    b)packet中的SN bit,代表对端设备正在发送的packet,而本地设备的nesn,代表本地设备期望对端设备发送的packet。如果二者相同,则说明是一个期望的packet(新的),就可以收下该packet,并将期望值加1(nesn加1)。如果二者不同,说明不是本地设备期望的packet,什么都不做就可以了。

    4)上面2)和3)两个步骤,是相互独立的,因此一个NAK packet,也可能携带新的数据,反之亦然。

    5)当一个设备无法接收新的packet的时候(例如RX buffer已满),它可以采取不增加nesn的方式,发送NAK packet。对端设备收到该类型的packet之后,会发送旧的packet(图片4左边部分的“TX old data, sn”分支)。该设备收到这样旧的packet的时候,不会做任何处理(图片4右边部分的“Ignore RX data”分支)。这就是Link Layer的流控机制(Flow control)

    BLE应答和流控机制

    图片4 BLE应答和流控机制

    4. HCI

    HCI(Host Control Interface)的功能就简单多了,就是要封装Link Layer所提供的功能,包括两类。

    1)连接的建立、关闭、参数设置、管理等,这一类是通过HCI command/event(其格式可参考“蓝牙协议分析(5)_BLE广播通信相关的技术分析”中的介绍)完成的,包括:

    LE Create Connection Command,建立连接的命令,需要提供连接有关的参数,包括connInterval(Conn_Interval_Min和Conn_Interval_Max)、connSlaveLatency(Conn_Latency)和connSupervisionTimeout(Supervision_Timeout)。

    LE Create Connection Cancel Command,取消或者断开连接。

    LE Connection Update Command,更新连接参数,包括connInterval(Conn_Interval_Min和Conn_Interval_Max)、connSlaveLatency(Conn_Latency)和connSupervisionTimeout(Supervision_Timeout)。

    LE Set Host Channel Classification Command,配置Channel map。

    LE Read Channel Map Command,读取Channel map。

    等等。

    有关这些命令的具体描述,可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 2, Part E] Host Controller Interface Functional Specification”。

    2)对ACL data的封装和转发,不再详细说明。

    6. GAP

    GAP(Generic Access Profile)的主要功能,是定义BLE设备所具备的能力,以实现互联互通的功能。

    对BEL基于连接的通信来说,GAP定义了4种连接有关的模式(不同的产品形态,可以选择是否支持这些模式,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C] 9.3 CONNECTION MODES AND PROCEDURES”):

    Non-connectable mode,不可被连接。

    Directed connectable mode,可以被“直连”(在知道对方蓝牙地址的情况下的快速连接)。

    Undirected connectable mode,可以被“盲连”(不知道对方蓝牙地址)。

    Auto connection establishment procedure,可以被自动连接(不需要host干预)。

    相应地,GAP定义了5中和这些模式有关的过程(不同的产品形态,可以选择是否支持这些过程):

    General connection establishment procedure,通用的连接建立过程,搜索、发现、连接,都需要Host参与。

    Selective connection establishment procedure,有选择的连接建立过程,Host需要告诉Controller,自己只希望于特定的设备建立连接。

    Direct Connection Establishment Procedure,直接和某一个已知设备建立连接(对方也知道我们)。

    Connection Parameter Update Procedure,连接参数的更新过程。

    Terminate Connection Procedure,断开连接。

    这些mode和procedure的具体描述,可参考蓝牙spec[1]。

    7. 参考文档

    [1] Core_v4.2.pdf

    更多相关内容
  • 本文章主要讲下蓝牙RFCOMM协议(bluetooth rfcomm)的概念以及在整个蓝牙协议的起的作用 一. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:蓝牙综合介绍 ,主要介绍蓝牙的...

    零. 概述

    本文章主要讲下蓝牙RFCOMM协议(bluetooth rfcomm)的帧格式,包括Address,Control,Length Indicator,Information,FCS等

    一. 声明

    本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下:

    第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍。

    第二篇:Transport层介绍,主要介绍蓝牙协议栈跟蓝牙芯片之前的硬件传输协议,比如基于UART的H4,H5,BCSP,基于USB的H2等

    第三篇:传统蓝牙controller介绍,主要介绍传统蓝牙芯片的介绍,包括射频层(RF),基带层(baseband),链路管理层(LMP)等

    第四篇:传统蓝牙host介绍,主要介绍传统蓝牙的协议栈,比如HCI,L2CAP,SDP,RFCOMM,HFP,SPP,HID,AVDTP,AVCTP,A2DP,AVRCP,OBEX,PBAP,MAP等等一系列的协议吧。

    第五篇:低功耗蓝牙controller介绍,主要介绍低功耗蓝牙芯片,包括物理层(PHY),链路层(LL)

    第六篇:低功耗蓝牙host介绍,低功耗蓝牙协议栈的介绍,包括HCI,L2CAP,ATT,GATT,SM等

    第七篇:蓝牙芯片介绍,主要介绍一些蓝牙芯片的初始化流程,基于HCI vendor command的扩展

    第八篇:附录,主要介绍以上常用名词的介绍以及一些特殊流程的介绍等。

    另外,开发板如下所示,对于想学习蓝牙协议栈的最好人手一套。以便更好的学习蓝牙协议栈,相信我,学完这一套视频你将拥有修改任何协议栈的能力(比如Linux下的bluez,Android下的bluedroid)。

    -------------------------------------------------------------------------------------------------------------------------

    CSDN学院链接(进入选择你想要学习的课程):https://edu.csdn.net/lecturer/5352?spm=1002.2001.3001.4144

    蓝牙交流扣扣群:970324688

    Github代码:https://github.com/sj15712795029/bluetooth_stack

    入手开发板:https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22329603896.18.5aeb41f973iStr&id=622836061708

    蓝牙学习目录https://blog.csdn.net/XiaoXiaoPengBo/article/details/107727900

    --------------------------------------------------------------------------------------------------------------------------

    二.RFCOMM帧格式

    2.1 参数Address:

    EA参数:这部分在蓝牙RFCOMM协议中一直为1

    C/R参数:此部分是代表RFCOMM的command还是response,官方解释如下:

    这个理解起来稍微我有绕,我翻译一下:

    C/R(命令/响应)位表示帧是命令还是响应,它的值不仅取决于帧是否携带命令或响应,还有信道的哪一端发送帧。建立连接的设备(通过在DLCI 0上发送SABM命令)称为initiator。响应的设备(通过在DLCI 0上发送UA响应)称为responder。网络上都对这个地方说明的模凌两可,对于上面的这段话其实也说的模棱两可,我来总结下:

    1)对于(SABM,UA,DM,DISC)帧,这些统称为命令帧,initiator发送给responder,C/R=1,response相应initiator C/R也为1。

    2)对于(SABM,UA,DM,DISC)帧,这些统称为命令帧,response发送给initiator C/R为0,initiator响应给responder,C/R=0.

    3)对于UIH帧,这个称为数据帧,initiator发送给responder,C/R=1,response发送给initiator C/R为0.

    总结图标如下:

    为了便于我上面的总结理解,那么加一个流程图,来加深你们的印象

    下面我们用BTsnopp来一一看下以上个3case:

    1)对于(SABM,UA,DM,DISC)帧,这些统称为命令帧,initiator发送给responder,C/R=1,response相应initiator C/R也为1。

    分别解析如下:

    从截图看出是对方来连接我们signaling,所以对方是initiator,所以对方发送SABM种的C/R是1,而我们回复的UA帧中的C/R也为1

    以下例子都是以对方为initiator来说明

    2)对于(SABM,UA,DM,DISC)帧,这些统称为命令帧,response发送给initiator C/R为0,initiator响应给responder,C/R=0.

    从1)中我们可以看到我们是responder,对方是initiator,所以按照我们发送给对方的SABM帧的C/R是0,对方回应我们的也是0

    3)对于UIH帧,这个称为数据帧,initiator发送给responder,C/R=1,response发送给initiator C/R为0.

    上图解析如下:

    可以看到对方给我们的UIH帧C/R为1,我们给对方的UIH帧C/R为0

    讲到这里你应该明白了C/R位了吧,我感觉我是全网在这里说明最清晰的。

    D参数:这个同样比较绕,我们来看下官方解释

    D其实就是DLCI中的direction bit

    网上也没有一个特别明确的说明,我自己总结了下,感觉也是比较清晰:

    建立连接的设备(通过在DLCI 0上发送SABM命令)称为initiator。响应的设备(通过在DLCI 0上发送UA响应)称为responder,这点在上面我们也已经说明了。initiator自己的D=1,responder自己的D=0,所以如果在DLCI已经建立连接后,后续initiator连接responder某一个profile的时候(比如HFP),那么应该是DCLI=0+ server chanel<<1,如果是responder连接initiator的某一个profile,那么应该是DCLI=1+ server channel<<1

    后续交互封包的UIH的DCLI一直不变

    举几个例子来说明下这里(remote是initiator,local是responder):

    来一个initiator连接responder的btsnoop

    可以发现server channel是9,那么按照算法应该是0+9<<1,所以DCLI应该是0x12

    来一个responder连接initiator的btsnoop

    可以发现server channel是13,那么按照算法应该是1+13<<1,所以DCLI应该是0x1B

    Server channel:说白了就是上层profile的rfcomm channel

    注册到SDP中,整个流程就是SDP问询对方的RFCOMM channel,然后再发起RFCOMM的连接(比如HFP,HSP,SPP,OPP等),连接完毕交互完参数,就相当于上层profile连接成功

    2.2 Control参数

    主要是标示RFCOMM frame type是什么,截图如下:

    帧分别作用如下:

    SABM:异步平衡模式设置指令 SABM 命令可以用在异步平衡模式下,并且它的控制字段只能有一个字节。设备通过首先发送 UA 应答来确认接收到 SABM命令,DLC 发送和接收状态变量都必须设定为 0。用大白话讲就是连接命令

    UA:未加编号的确认应答。 UA 应答用在设备对接收到 SABM 和 DISC 后的确认应答

    DM:断开连接模式应答。DM 应答是用来报告设备从数据链路逻辑地断开连接这么一种状态的。在断开模式下,不支持任何命令,直到收到了 SABM 命令,然后停止断开模式。在断开模式下,接收到了 DISC 命令,则要向对方发送一个 DM 应答。

    DISC:断开连接指令。用 DISC 命令可以用来结束一个正在运行或者刚刚开始的模式。它就是通知一方另一方悬置操作,设备必须假定一个逻辑断开模式。在执行这个命令之前,接收设备要通过发送 UA 应答来确认接受 DISC 命令。在DLCI0 中,DISC 命令的发送也和其他的 DLCI 具有同意的意思。

    UIH:带头校验的未编号信息命令和应答用 UIH 命令/应答可以通过不影响V(S)或 V(R)变量来相互发送信息。UIH 是用在传输一些信息的完整性没有它要在正确的 DLCI 上传输重要的情况下的。 FCS 只在地址和控制字段进行计算。 UIH用于对差错码要求不是很高的场合,如语音。

    P/F Bit:P/F是Poll/Final位

    在Commands中,被称为P(poll)位;而在Responses中则被称为F(final)位,大概用法我自己总结如下:

    1)对于(SABM,UA,DM,DISC)帧,这些统称为命令帧,command跟response都设置为1就好。

    2)对于UIH帧,除了给对方credit设置为1外,UIH user帧以及UIH多路控制帧都设置为0就好了。

    2.3 Length Indicator参数

    L1 到 L7 位表示数据字段的长度,其默认值为 31 字节。同样,它可以根据 EA位进行扩展。当 EA=0 时,它接下来的字节如下表表示就可以表示 15 个数字。也就是RFCOMM的后续len是32~32767 byte的字节。

    2.4 Information Field参数

    UIH帧数据,只对UIH帧有效,后续再一一介绍下UIH的格式

    2.5 FCS参数

    帧校验序列(FCS)根据不同帧类型在不同域集上进行运算.下面列出需要进行帧运算的字段:

    对于 SABM、DISC、UA、DM 帧:在地址、控制和长度标志字段上进行运算;

    对于 UIH 帧:在地址和控制字段上进行运算。

    展开全文
  • 蓝牙BLE协议分析【附代码实例】

    千次阅读 2020-08-14 18:55:36
    目录0x01 蓝牙概述0x02 蓝牙技术分类Basic Rate(BR)/AMPLow Energy(LE)0x03 蓝牙架构0x04 蓝牙协议应用层(App Layer)L2CAP(Logical Link Control and Adaptation Protocol Layer)逻辑层(Logical Layer)...

    0x01 蓝牙概述

    蓝牙技术起源于爱立信在1994年提出的方案,旨在解决移动电话和其他配件之间进行低功耗、低成本的无线通信连接的方法。

    蓝牙发展历史

    • 第一代蓝牙主要是指90年代的V1.0~V1.2版本,是关于段距离通信的早期探索,此时还存在许多问题,应用不是特别广泛
    • 第二代蓝牙主要是00年中V2.0~V2.1版本,新增了EDR(Enhanced Data Rate)技术提高传输速率,以及体验及安全
    • 第三代蓝牙主要是00年末V3.0版本,新增了802.11 WiFi协议,引入了AMP(Generic Alternate MAC/PHY)交替射频技术,极大的提高了传输速率并降低功耗
    • 第四代蓝牙是10年以来的V4.0~V4.2版本,主推LE(Low Energy)低功耗,大约仅消耗十分之一,将三种规格,包括经典蓝牙、高速蓝牙、和蓝牙低功耗,集中在一起形成一套综合协议规范
    • 第五代蓝牙是16年开始提出的V5.0版本,主要是为了支持物联网,在功耗、传输速率、有效传输距离、数据包容量方面都做了极大的提升

    下面的分析都是基于V4.1版本,方便入门,可以理解很多核心协议的设计思想

    0x02 蓝牙技术分类

    蓝牙技术包含蓝牙发展过程中的两套技术,但是这两套原理和实现都不一样,也无法实现互通

    Basic Rate(BR)/AMP

    最初的蓝牙技术,包括可选的EDR(Enhanced Data Rate)技术和交替使用的MAC层和PHY层扩展 AMP(Alternate MAC and PHY layer extension)【优化传输速度的过程】

    解释:蓝牙诞生之初使用的BR技术,传输速率很低,随着发展而变得无法支持,所以引入了EDR,这时还没有修改软硬件架构,但是之后又落伍了,所以直接引入了WiFi的底层协议,也就是MAC/PHY扩展,但这部分的实现就无法直接更替,所以BR/EDR只能与AMP交替使用

    Low Energy(LE)

    蓝牙低功耗,则不关心传输速率,而是从降低功耗的角度实现的另一套技术,跟前面的协议没有丝毫关系

    0x03 蓝牙架构

    structure

    蓝牙协议将蓝牙整体分成了两层架构,底层是核心协议,描述了蓝牙核心技术的基础和规范,应用层协议则基于具体需求,使用核心协议提供的机制,实现不同的功能策略

    核心协议包含两部分,Host和Controller,这两部分在不同的蓝牙协议版本中略有区别,但大致上是,Controller完成硬件侧的规范制订,包括信号调制解调,会抽象出用于通信的逻辑链路,可能存在一个或多个,如LE Controller、BR/EDR Controller;Host则在逻辑链路的基础上完成更友好的封装,屏蔽掉技术细节,方便应用层对数据的使用

    0x04 蓝牙协议

    蓝牙协议也采用层次结构,自下而上依次为物理层、逻辑层、L2CAP层和应用层

    protocol

    应用层(App Layer)
    为不同场景定义规范,提出Profile(一项服务)的概念,实现各种应用功能

    L2CAP(Logical Link Control and Adaptation Protocol Layer)

    • 逻辑链路控制和适配协议,负责管理逻辑链路,使得不同应用可共享一个逻辑链路,类似端口的实现
    • 在逻辑链路的基础上,抽象出与具体技术无关的数据传输信道,如单/广播,然后对上以L2CAP channel endpoints的概念,为不同应用程序提供独立的传输通道

    逻辑层(Logical Layer)

    • 提供设备对象之间逻辑传输,在物理层的基础上,建立逻辑信道,主要基于传输类型来划分,包括控制类传输(负责底层物理链路的管理)、用户类传输(负责用户数据传输)和其他特殊类型的传输
    • 不同的逻辑信道(Logical Link)会在下层对应Logical Transport,实现流控、应答、重传等机制

    物理层(Physical Layer)

    • 负责提供数据传输的物理通道

    • 物理链路(Physical Link):对物理信道的进一步封装

    • 物理信道(Physical channel):三种蓝牙技术都使用相同的频段和频率范围,但是具体实现都不一样

      • BR/EDR频段分成了79个channel,每个占1M带宽;采用跳频技术(Hopping),即物理信道随机占用某一channel;定义了五种物理信道,每次只能在一种物理信道上通信,采用时分方式
        • Inquiry Scan Physical Channel:用于发现操作,即搜索/被搜索
        • Page Scan Physical Channel:用于连接操作,即连接/被连接
        • Basic Piconet Physical Channel:用于连接状态下通信,使用79个跳频点
        • Adapted Piconet Physical Channel:用于连接状态下通信,使用较少RF跳频点
        • Synchronization Scan Channel:用于无连接的广播通信
      • AMP直接使用WIFI的物理层规范,只有一个物理信道,用于已连接设备之间的高速数据通信
      • LE频段分成了40个channel,每个占2M带宽;有两种物理信道,每次只能在一种物理信道上通信,采用时分方式
        • Advertisement Broadcast Channel:用于设备间无连接广播通信,包括发现/连接操作
        • Piconet channel:用于连接状态下通信

    0x05 BLE协议栈

    实现一个BLE应用,需要一个支持BLE射频的芯片,然后基于一个与芯片配套的协议栈,开发蓝牙应用。

    协议栈的作用就是软件和硬件之间的桥梁,对应用数据进行封包然后生成可以通过射频发送的空中数据包及其逆向过程。

    BLE-protocol

    Physical Layer(PHY)

    • 蓝牙通信系统的物理层,是免费ISM频段,整个频带分成40份,每份带宽2MHz;此外还定义了RF收发相关的特性,如发射功率、调制解调方式等

    Link Layer(LL)

    • 解决在有限物理信道上传输远多实际信道数量的数据,即信道共享,然后为通信实体创建看似独享的逻辑信道,以及解决传输过程中的校验、重传等问题

    • LL中的信道设计:BLE系统基于通信场景,在40个物理信道中选取三个作为广播信道,处理数据量小、发送不频繁、时延不敏感的场景,存在的问题就是不可靠、效率低、不安全;另外的场景则在剩下的37个信道中选取一个为双方建立单独信道,并且为了抗干扰采用跳频技术

    • 为此,LL为通信双方实体定义了以下状态及切换条件

    BLE-state

    - Standby:初始状态,不收发数据,接受上层协议命令与其他状态切换
    - Advertising:通过广播发送数据的状态,建立连接后可进入Connection
    - Scanning:接收广播的数据的状态
    - Initiating:特殊的接收状态,类似Scanning,接收Advertiser广播的连接数据,建立连接后进入Connection
    - Connection:建立连接后拥有单独的通道
    
    • 这里会使用空中接口协议(Air Interface Protocol,AIP)来负责实体之间的数据交换和状态切换

    Host Controller Interface(HCI)

    • 定义Host和Contorller之间的通信协议,如两个芯片之间的串口

    L2CAP

    • 逻辑控制和适配协议的工作就是实现逻辑信道的多路复用(multiplexing),对上层数据进行分割和重组,以及后续的流控、错误控制和重传等
    • 多路复用思想:将要发送的数据分割成一个个数据包(Packet Data Unit,PDU),添加包含特定ID的头部,接收方解析头部ID进行重组
    • 多路复用实现
      • 基于连接:L2CAP会为每个逻辑信道分配一个编号(Channel ID,CID),有些CID会有固定用途
      • 基于协议(略)

    Attribute Protocol(ATT)

    • 属性协议主要是针对物联网场景,核心思想就是将采集的信息或控制的命令以属性的形式抽象出来,提供接口供远端设备读写
    • 采用C/S形式,信息提供方为ATT Server,如传感器,访问方为ATT Client
    • 为每个Attribute定义了三个属性
      • Type,即Attribute的类型,使用UUID区分
      • Handle,服务端用来唯一标识Attribute的16-bit数值
      • Value,Attribute的值
    • 为每个Attribute定义了一系列权限,方便服务端控制客户端的行为,包括访问/加密/认证/授权
    • 对于不同的Attribute,客户端对服务端的访问方式也不一样,包括Find/Read/Write
    • 传输过程是在L2CAP的基础上,使用基于通道的多路复用,CID为0x0004

    Generic Attribute Profile(GATT)

    • 通用属性配置文件,Attribute只是将信息(或者说通信数据)做一下抽象,但是真正对抽象的信息做分类管理则是GATT来完成,形成profile的概念(解决了很多无线协议的兼容问题),profile可以理解成应用场景或者使用方式

    • GATT提供了这样一种通用的、信息存储与共享的profile framework,实现BLE双向通信

    • GATT的层次结构

    GATT_profile_hierarchy

    • Profile位于最顶层,不是真正存在的配置文件,而是一个或多个场景相关的service的抽象集合

    • Service(服务)是一种行为的抽象,具有唯一标识UUID,每个service包含一个或多个Characteristic,也可以通过include的方式包含其他service

    • Characteristic(特征)可以理解成一个属性,是真正与设备通信相关的,数据发送和接收的最基本单位,通过对特征的读写实现蓝牙双向通信,它由一个Propertities(定义Value的使用规范和Descriptor的访问规范)、一个Value(特征的实际取值)和一个或多个Descriptor(Value相关的描述信息)组成,每个特征也具有自己的唯一标识,但是有三种形式:

      • 16-bit是官方认证,收费,Bluetooth_Base_UUID 为 00000000-0000-1000-8000-00805F9B34FB

      • 16-bit转128-bit,格式为 0000xxxx-0000-1000-8000-00805F9B34FB

      • 32-bit转128-bit,格式为 xxxxxxxx-0000-1000-8000-00805F9B34FB

    • 事实上,目前几乎所有的BLE应用都基于GATT实现通信

    • GATT通信基于C/S模型,外围设备作为Server端,维护ATT结构及产出数据,中心设备作为client端,请求连接获取数据

    • GATT连接对外围设备是独占的,即一个外围设备同时与一个中心设备建立连接,一个中心设备可同时与多个外围设备建立连接

    Security Manager(SM)

    • 安全管理协议主要负责BLE通信过程中安全相关的内容,包括认证、加密这些过程

    Generic Access Profile(GAP)

    • 通用访问配置文件,定义了蓝牙设备的通用的访问功能,与GATT的数据通信过程对应,处理无连接连接建立过程的通信,也就是为广播、扫描、发起连接这些过程定义统一规范
    • 定义了用户接口的基本参数,包括蓝牙地址、名称、pincode、class等概念
    • 定义了设备的角色:
      • Broadcaster Role:正在发送advertising events的设备
      • Observer Role:正在接收advertising events的设备
      • Peripheral Role:接受Link Layer连接的设备(对应Link Layer的slave角色)
      • Central Role,发起Link Layer连接的设备(对应Link Layer的master角色)
    • 定义了通信的过程和操作模式:
      • Broadcast mode and observation procedure:实现单向的、无连接的通信
      • Discovery modes and procedures:实现蓝牙设备的发现操作
      • Connection modes and procedures:实现蓝牙设备的连接操作
      • Bonding modes and procedures:实现蓝牙设备的配对操作

    0x06 BLE的广播

    使用场景

    1. 单向、无连接的数据通信,发送者使用广播信道发送数据,接受者扫描接收数据
    2. 连接建立阶段

    协议层次

    • GAP:以应用程序角度进行功能封装,提供一套统一的、通用的广播规范
    • HCI:将LL提供的功能抽象成Command/Events的形式,供上层使用
    • LL:负责广播通信相关功能的定义和实现,包括信道选择、链路状态定义、PDU定义、设备过滤机制等

    LL

    • 信道选择。BLE将蓝牙频段分成了40个物理信道,综合考虑(抗干扰等)后将其中三个作为广播信道,频段为0/12/39,编号是37-39

    • 链路状态。参与广播的BLE设备,总是处于这三种状态之一

      • Advertising:广播状态,周期性地广播,数据发送方
      • Scanning:扫描状态,扫描并接受广播数据,数据接收方
      • Initiating:初始化状态,扫描到可连接的广播时,发起连接请求,连接发起方
    • PDU(Packet Data Unit)格式

    pdu

    • Type是指PDU的类型,如不同的状态下也有不同的消息类型,TxAdd和RxAdd都是地址类型flag,针对不同的type有不同的含义,RFU都是保留字段,Length标明payload的长度

    • Payload内容

      StateTypeDescriptionsPayloadlengthDescriptions
      AdvertisingADV_IND常规广播,可连接可扫描AdvA6address of broadcaster
      【后续建立点对点连接,监听CONNECT_REQ请求】AdvData0~31Broadcast data
      ADV_NONCONN_IND同ADV_IND,不可连接不可扫描AdvA6address of broadcaster
      【用于定时传输简单数据】AdvData0~31Broadcast data
      ADV_SCAN_IND同ADV_IND,不可连接可扫描AdvA6address of broadcaster
      【用于传输额外数据,监听SCAN_REQ请求】AdvData0~31Broadcast data
      ADV_DIRECT_IND点对点连接,已知双方蓝牙地址,无广播数据,可被指定设备连接不可扫描AdvA6address of broadcaster
      【快速建立连接,不关心广播数据,监听CONNECT_REQ请求】InitA6address of receiver/initiater
      ScanningSCAN_REQ接收ADV_IND/ADV_SCAN_IND后,请求更多信息ScanA6address of scanne r
      【接收广播数据后请求更多信息】AdvA6address of broadcaster
      SCAN_RSPSCAN_REQ的响应,返回更多信息AdvA6address of broadcaster
      ScanRspData0~31response data
      InitiatingCONNECT_REQ接收ADV_IND/ADV_DIRECT_IND后,请求建立连接InitA6address of receiver/initiater
      【请求建立连接】AdvA6address of broadcaster
      LLData22parameters of connection
    • BLE设备地址类型

      • Public Device Address:IEEE分配,24-bit的company_id+24-bit的company_assigned,类似MAC
      • Random Device Address:随机生成,解决费用和维护、设备身份绑定的问题
        • Static Device Address:上电生成,46-bit的random+11,断电后可变
        • Private Device Address:进一步提供定时更新和地址加密提高可靠行和安全性
          • Non-resolvable Private Address:按周期定时更新,46-bit的random+00
          • Resolvable Private Address:通过随机数和IRK(Identity Resolving Key)生成,24-bit的hash+22-bit的random+10

    HCI

    • 将Link Layer提供的功能封装成Command/Event组

    • Command格式

    command

    OCF(Opcode Command Field)表示特定的HCI命令,OGF(Opcode Group Field)表示该HCI命令所属组别,他们共同组成16位操作码;Parameter Total Length表示所有参数总长度

    所有BLE相关的HCI Command的OGF都是0x08

    • Event格式

    event

    • 这些Command/Event包括广播、扫描、连接建立的相关操作,这些都可以通过hcitool命令进行测试

    GAP

    • 会从应用程序角度对各种状态和操作再一次进行封装,包括设备角色,通信的模式和操作的定义

    • 与GAP广播通信相关的是广播和发现模式

      • Broadcast mode and observation procedure,广播模式及对应的解析过程,对应状态下的角色双方就是Broadcaster和Observer
      • Discovery modes and procedures,发现模式及对应的发现过程,对应的角色就是Peripheral和Central
    • 广播数据格式

    adv_data

    • 广播/扫描应答数据,包含有意义部分和无意义部分(补齐为0),有意义部分是由一个个广播块(AD Structure)组成,每个广播块包含1字节长度(指示数据部分长度)和剩下的数据部分,数据部分又分为数据类型和数据内容,数据类型会指示真实Data部分的内容,例如0x01表示Data内容是描述设备物理连接状态,再例如0x08表示Data内容是设备名称,更多可以参考generic-access-profile

    • 举个广播数据的例子

      02 01 06 03 03 aa fe 17 16 aa fe 00 -10 00 01 02 03 04 05 06 07 08 09 0a 0b 0e 0f 00 00 00 00
      

      02 01 06是一个AD Structure,数据部分长度为2字节,类型是0x01,描述设备物理连接状态,数据部分0x06,1字节8bit,每bit都是一个标志位([预留]|[预留]|[预留]|[同时支持BLE和BR/EDR(Host)]|[同时支持BLE和BR/EDR(Controller)]|[不支持BR/EDR]|[普通发现模式]|[有限发现模式]),那么这个广播就是普通发现模式,不支持BR/EDR

      03 03 aa fe是第二个AD Structure,数据部分长度为3字节,类型是0x03,表示16-bits的Service UUID

      17 16 aa fe 00 -10 00 01 02 03 04 05 06 07 08 09 0a 0b 0e 0f 00 00 00 00是最后一个AD Structure,数据部分长度为0x17即23字节,类型是0x16,表示服务数据

    AD TypeDescriptionAD Data
    0x01设备物理连接状态1字节8bit,每个bit都是一个标志位 [预留]|[预留]|[预留]|[同时支持BLE和BR/EDR(Host)]|[同时支持BLE和BR/EDR(Controller)]|[不支持BR/EDR]|[普通发现模式]|[有限发现模式]
    0x02UUID非完整的16-bit UUID
    0x03UUID完整的16-bit UUID
    0x04UUID非完整的32-bit UUID
    0x05UUID完整的32-bit UUID
    0x06UUID非完整的128-bit UUID
    0x07UUID完整的128-bit UUID
    0x08设备名称缩写设备名称
    0x09设备名称完整设备名称
    0x0aTX Power LevelTX Power Level
    0xff厂商数据[厂商ID]|[厂商自定义数据]

    0x07 BLE的连接

    经典蓝牙中保持连接非常耗费资源,但是每次连接建立效率又非常低,为了优化体验,BLE简化了连接过程(毫秒级),极大的降低了面向连接通信的代价

    蓝牙通信系统中,对于连接的定义是:在约定的时间段内,双方都到一个指定的物理Channel上通信。

    LL

    • 角色定义。BLE为处于连接状态的两个设备定义了两个角色,Master和Slave。Master作为连接发起方,定义和连接相关的参数,Slave是连接的接收方,请求连接参数

    • PDU(Packet Data Unit)格式

    DC_PDU

    面向连接的通信使用特定的PDU,称为Data channel PDU

    LLID指示Data Channel传输的PDU类型,传输数据是LL Data PDU,传输控制信息是LL Control PDU,NESN(Next Expected Sequence Number)和SN(Sequence Number)用于数据传输过程中的应答和流控,MD(More Data)用于关闭连接,RFU是预留位,Length指示有效数据长度,包括Payload和MIC

    LLIDtypeDescription
    01bLL Data PDU空包或未传输完成的消息(被拆包)
    10bLL Data PDU(不需拆包)完整消息或第一个包
    11bLL Control PDU用于控制、管理LL连接的数据包,此时Payload为1字节Opcode和剩余的控制数据
    • 建立连接
      1. 可连接状态的设备(Advertiser)按照一定周期广播可连接数据包
      2. 主动连接的设备(Initiator)收到广播包后回应一个连接请求(约定时间点、物理信道等)
      3. Initiator发送完毕后进入连接状态,成为Master
      4. Advertiser接收到连接请求后也进入连接状态,成为Slave
      5. 双方按照参数约定,定时切换到某一物理信道,开始依次收发数据,直至连接断开

    HCI

    • 封装Link Layer的功能,主要包括连接的建立、关闭、参数设置和管理,以及数据封装和转发

    GAP

    • 定义设备具有的能力和操作

    0x08 BLE安全机制

    White List

    白名单就是一组蓝牙地址列表,通过设置白名单可以允许扫描、连接特定的蓝牙设备,以及被扫描、连接

    LL Privacy

    在白名单的基础上将设备地址进行加密,转变成Resolvable Private addresses

    • 本地Resolving List需要保存每一对BLE设备的key/address信息,格式为:Local IRK|Peer IRK|Peer Device Identity Address|Address Type
    • LL Privacy机制在Controller中完成,即加解密操作对HCI上层是透明的

    LL Encryption

    数据发送和接收过程进行加解密

    • 加解密操作在Link Layer完成
    • Host会保存至少1280bit的LTK(根密钥),启动加密传输时,LL会首先协商出一个128-bit的随机数SDK(Session Key Diversifier)和64-bit的iv,经过Encryption Engine和LTK生成此次通信的会话密钥SessionKey

    SecurityManager

    为BLE设备提供加密连接相关的key,包含以下规范:

    • 定义了配对(Pairing)的相关概念及过程
    • 定义了密码工具箱,包含配对、加密所需的各种算法
    • 定义了安全管理协议(Security Manager Protocol,SMP),实现配对、密码传输等操作

    SMP规范中,配对的定义是,Master和Slave通过协商确定用于加密通信的key的过程,包含三个阶段:

    • 阶段一、Pairing Feature Exchange,交换双方配对相关的设置,如配对方法、鉴权方式等
      • 鉴权方式可以采用交换额外的信息(Out of band,OOB),或者弹窗引入人来判定,称为MITM鉴权,还有输入配对码进行对比(Passkey Entry/Numeric Comparison),或者不鉴权(Just Work)
    • 阶段二、通过SMP协议进行配对操作,有两种配对方案,LE Legacy Pairing和LE Secure Connections
    • 阶段三、协商好密钥key,建立加密连接,传输密钥信息(可选)

    0x09 Android中的BLE应用

    具体可以参考开发的蓝牙测试工具:BLETool

    BLE,蓝牙低功耗(极低的运行和待机功耗)

    Android 4.3(API 18) 开始引入 BLE ,即蓝牙4.0

    Android 4.3 的 BLE 只支持 Central Role(中心设备,扫描并连接外围设备)

    Android 5.0 开始同时支持 Central Role 和 Peripheral Role(外围设备,向外广播发送数据)

    1、权限

    <!--蓝牙权限-->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <!--蓝牙相关操作设置权限-->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <!--位置权限,扫描时需要,Android 9-需要模糊定位,Android 10开始需要精确定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <!--声明使用BLE硬件特性,仅系统支持时可安装-->
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
    

    2、开启/关闭蓝牙

    // 判断支持蓝牙功能
    if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        // 获取蓝牙管理服务
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        // 获取蓝牙适配器
        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
        if (bluetoothAdapter != null) {
            // 判断蓝牙是否开启
            if (bluetoothAdapter.isEnabled()) {
                // 关闭蓝牙
                bluetoothAdapter.disable();
            } else {
                // 1、静默开启蓝牙
                bluetoothAdapter.enable();
                // 2、显式请求开启蓝牙
                Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(intent, REQUEST_BLUETOOTH_ENABLE);
            }
        }
    }
    

    3、扫描与监听

    if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        // 获取蓝牙管理服务
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        // 获取蓝牙适配器
        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
        if (bluetoothAdapter != null) {
            // 判断蓝牙是否开启
            if (bluetoothAdapter.isEnabled()) {
              	// 获取扫描器实例
                BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
                boolean isScanning = false;
                if (bluetoothLeScanner != null) {
                    if (isScanning) {
                        // 停止扫描
                        isScanning = false;
                        bluetoothLeScanner.stopScan(scanCallback);
                    } else {
                      	// 开始扫描
                        isScanning = true;
                        bluetoothLeScanner.startScan(scanCallback);
                    }
                }
            }
        }
    }
    

    Android 8 开始提供一个后台持续扫描的API,应用杀死后也可以继续扫描,直到关闭蓝牙【待验证】

    public int startScan (List<ScanFilter> filters, ScanSettings settings, PendingIntent callbackIntent);
    
    // 设置拦截器和扫描选项
    bluetoothLeScanner.startScan(scanFilters, scanSettings, scanCallback);
    

    初始化扫描过滤器

    scanFilters = new ArrayList<>();
    ScanFilter scanFilter = new ScanFilter.Builder()
      .setDeviceName("lalala")
      .setServiceUuid(new ParcelUuid(UUID.randomUUID()))
      .build();
    scanFilters.add(scanFilter);
    

    初始化扫描设置

    scanSettings = new ScanSettings.Builder()
      // 设置扫描模式
      .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
      // 设置回调类型  
      .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
      // 设置配对模式
      .setMatchMode(ScanSettings.MATCH_MODE_STICKY)
      // 设置报告延迟
      .setReportDelay(0)
      .build();
    

    两个类都是通过 Builder 构造,提供系列函数用于参数设置,如 setDeviceName()setScanMode()setMatchMode()

    4、扫描回调

    scanCallback = new ScanCallback {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
        }
    
        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
        }
    
        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
        }
    }
    

    其中 onBatchScanResults() 是批量返回扫描结果。可通过下面的接口判断蓝牙芯片是否支持批处理

    Bluetoothadapter.isOffloadedScanBatchingSupported();
    

    注意 onScanResult()onBatchScanResults() 是互斥的,ScanSettingssetReportDelay() 设置为0(默认)则通过 onScanResult() 返回扫描结果,否则开启批处理扫描模式,并触发 onBatchScanResults() 回调。

    5、广播数据解析

    扫描成功会返回 ScanResult 广播数据类,然后进一步解析

    // 返回远程设备类
    BluetoothDevice device = scanResult.getDevice();
    // 返回扫描记录,包含广播和扫描响应
    ScanRecord scanRecord = scanResult.getScanRecord();
    // 返回信号强度,[-127, 126]
    int rssi = scanResult.getRssi()
    

    BluetoothDevice 是设备信息类,常用的方法有

    // 获取硬件地址
    String address = device.getAddress();
    // 获取蓝牙名称
    String name = device.getName();
    // 获取设备类型,如DEVICE_TYPE_CLASSIC、DEVICE_TYPE_LE、DEVICE_TYPE_DUAL、DEVICE_TYPE_UNKNOWN
    int type = device.getType();
    // 获取绑定状态,如BOND_NONE、BOND_BONDING、BOND_BONDED
    int state = device.getBondState();
    

    6、连接设备

    扫描返回的广播消息中可以获取到远程设备的MAC地址,可用于设备的连接

    if (bluetoothAdapter.isEnabled()) {
      // 获取远程设备对象
      BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
      if (bluetoothDevice != null) {
        handler.post(new Runnable() {
          @Override
          public void run() {
            BluetoothGatt bluetoothGatt;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
              // 连接远程设备
              bluetoothGatt = bluetoothDevice.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);
            } else {
              bluetoothGatt = bluetoothDevice.connectGatt(context, false, bluetoothGattCallback);
            }
          }
        });
      }
    }
    

    bluetoothGatt 是蓝牙通用属性协议的封装,定义了BLE通信的一些基本规则和连接通信操作

    7、连接回调

    bluetoothGattCallback 则是 bluetoothGatt 连接的回调类,通知客户端连接状态和结果

    bluetoothGattCallback = new BluetoothGattCallback {
      @Override
      public void onConnectionStateChange(BluetoothGatt gatt, final int status, final int newState) {
        super.onConnectionStateChange(gatt, status, newState);
      }
    
      @Override
      public void onServicesDiscovered(BluetoothGatt gatt, final int status) {
        super.onServicesDiscovered(gatt, status);
      }
    
      @Override
      public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
      }
    
      @Override
      public void onCharacteristicRead(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
        super.onCharacteristicRead(gatt, characteristic, status);
      }
    
      @Override
      public void onCharacteristicWrite(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
      }
    
      @Override
      public void onDescriptorRead(BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
        super.onDescriptorRead(gatt, descriptor, status);
      }
    
      @Override
      public void onDescriptorWrite(BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
        super.onDescriptorWrite(gatt, descriptor, status);
      }
    }
    

    连接成功及其他连接状态改变都会调用 onConnectionStateChange() 方法。status 表示这个操作的状态,是 BluetoothGatt.GATT_SUCCESS 或者读写受限、超过范围等其他错误状态。newState 则表示当前设备的连接状态,连接成功为 BluetoothProfile.STATE_CONNECTED,连接失败是BluetoothProfile.STATE_DISCONNECTED

    8、发现服务

    连接成功后就可以开始通信,从请求服务开始(Profile只是一系列具有共同业务需求的服务的抽象集合,服务才是实体)

    bluetoothGatt.discoverServices();
    

    发现服务后会触发 onServicesDiscovered() 回调,然后继续获取服务

    // 获取所有服务
    List<BluetoothGattService> bleServiceList = bluetoothGatt.getServices();
    // 通过uuid获取特定的服务
    BluetoothGattService bleService = bluetoothGatt.getService(serviceUuid);
    

    BluetoothGattService 是蓝牙服务类,是与某个场景相关的一系列行为的抽象,具有一个唯一的UUID,然后服务类型,如SERVICE_TYPE_PRIMARY、SERVICE_TYPE_SECONDARY(主要服务可以包含二级服务),包含的特征列表

    9、获取特征

    // 获取所有特征
    List<BluetoothGattCharacteristic> bleCharacteristicList = bleService.getCharacteristics();
    // 通过uuid获取特定的特征
    BluetoothGattCharacteristic bleCharacteristic = bleService.getCharacteristic(characteristicUuid);
    

    BluetoothGattCharacteristic 是蓝牙特征类,是通信的基本数据单位,包含标志特征的唯一的UUID,描述特征访问权限的特性,如PROPERTY_BROADCAST、PROPERTY_READ、PROPERTY_WRITE等,特征的实际取值,以及特征的描述

    10、读写特征

    // 读取特征
    bluetoothGatt.readCharacteristic(bleCharacteristic);
    // 设置并写入特征
    bleCharacteristic.setValue("XXX");
    bluetoothGatt.writeCharacteristic(bleCharacteristic);
    

    这里的读写特征函数都是返回布尔类型表示是否操作成功,如果成功真正的值会在 onCharacteristicRead/onCharacteristicWrite 回调中读取/写入

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
      switch (status) {
        case GATT_SUCCESS:
          String valueStr = BLEUtils.byte2HexString(characteristic.getValue());
          break;
        case GATT_READ_NOT_PERMITTED:
          ToastUtils.showShort(context, "GATT_READ_NOT_PERMITTED");
          break;
        default:
          ToastUtils.showShort(context, "CHARACTERISTIC_READ_FAILED");
          break;
      }
    }
    
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
      switch (status) {
        case GATT_SUCCESS:
          String valueStr = BLEUtils.byte2HexString(characteristic.getValue());
          break;
        default:
          ToastUtils.showShort(context, "CHARACTERISTIC_WRITE_FAILED");
          break;
      }
    }
    

    11、监听特征

    真正要实现通信除了单方面读写,还需要对数据变化进行监听,这样就可以进行数据交换

    // 设置特征监听为true,且要求特征具有NOTIFY属性
    bluetoothGatt.setCharacteristicNotification(characteristic, true);
    

    这样,自己或对方特征改变时就会回调函数从而获取改变后的特征值

    @Override
    public void onCharacteristicChanged(BluetoothGattCharacteristic characteristic) {
      Log.d("bledemo", "uuid = " + characteristic.getUuid().toString());
      Log.d("bledemo", "value = 0x" + BLEUtils.byte2HexString(characteristic.getValue()));
    }
    

    12、获取描述

    // 获取所有描述
    List<BluetoothGattDescriptor> bleDescriptorList = bleCharacteristic.getDescriptors();
    // 通过uuid获取特定的描述
    BluetoothGattDescriptor bleDescriptor = bleCharacteristic.getDescriptor(descriptorUuid);
    

    BluetoothGattDescriptor 是蓝牙特征描述类,包含对特征的一些额外描述信息

    13、读写描述

    // 读取描述
    bluetoothGatt.readDescriptor(bleDescriptor);
    // 设置并写入描述
    bleDescriptor.setValue("XXX");
    bluetoothGatt.writeDescriptor(bleDescriptor);
    

    同样读写成功会触发onDescriptorRead/onDescriptorWrite 回调

    @Override
    public void onDescriptorRead(BluetoothGattDescriptor descriptor, int status) {
      switch (status) {
        case GATT_SUCCESS:
          String valueStr = BLEUtils.byte2HexString(descriptor.getValue());
          break;
        case GATT_READ_NOT_PERMITTED:
          ToastUtils.showShort(context, "GATT_READ_NOT_PERMITTED");
          break;
        default:
          ToastUtils.showShort(context, "DESCRIPTOR_READ_FAILED");
          break;
      }
    }
    
    @Override
    public void onDescriptorWrite(BluetoothGattDescriptor descriptor, int status) {
      switch (status) {
        case GATT_SUCCESS:
          String valueStr = BLEUtils.byte2HexString(descriptor.getValue());
          break;
        default:
          ToastUtils.showShort(context, "DESCRIPTOR_WRITE_FAILED");
          break;
      }
    }
    

    14、断开连接

    // 断开连接,会触发onConnectionStateChange()回调
    bluetoothGatt.disconnect();
    // 关闭连接,不会触发回调
    bluetoothGatt.close();
    

    15、开启/关闭广播

    if (bluetoothAdapter.isEnabled()) {
      // 设置广播设备的名称,方便搜索
      bluetoothAdapter.setName("XXX");
      // 获取广播类
      BluetoothLeAdvertiser bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
      if (bluetoothLeAdvertiser != null) {
        if (isAdvertising) {
          // 关闭广播
          bluetoothLeAdvertiser.stopAdvertising(advertiseCallback);
        } else {
          // 开始广播
          bluetoothLeAdvertiser.startAdvertising(advertiseSetting, advertiseData, advertiseCallback);
        }
      }
    }
    

    还可以发送带响应报文的广播包

    bluetoothLeAdvertiser.startAdvertising(advertiseSetting, advertiseData, advertiseResData, advertiseCallback);
    

    其中 advertiseSetting 为广播设置类对象

    advertiseSetting = new AdvertiseSettings.Builder()
      // 广播模式,控制广播功率和延迟
      .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
      // 广播发射功率级别
      .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
      // 广播超时时间,最大值为 3*60*1000 毫秒,为 0 时禁用超时,默认无限广播
      .setTimeout(advertiseTimeout)
      // 广播连接类型
      .setConnectable(true)
      .build();
    

    advertiseData、advertiseResData 为广播包

    advertiseData = new AdvertiseData.Builder()
      // 广播是否包含设备名称
      .setIncludeDeviceName(true)
      // 广播是否包含发射功率
      .setIncludeTxPowerLevel(true)
      // 添加服务uuid
      .addServiceUuid(new ParcelUuid(UUID.randomUUID()))
      .build();
    
    advertiseResData = new AdvertiseData.Builder()
      // 添加自定义服务数据
      .addServiceData(new ParcelUuid(UUID.randomUUID()), new byte[]{1,2,3,4})
      // 添加自定义厂商数据
      .addManufacturerData(0x06, new byte[]{5,6,7,8})
      .build();
    

    16、广播回调

    advertiseCallback 是广播回调

    advertiseCallback = new AdvertiseCallback {
      @Override
      public void onStartSuccess(AdvertiseSettings settingsInEffect) {
        super.onStartSuccess(settingsInEffect);
      }
    
      @Override
      public void onStartFailure(int errorCode) {
        super.onStartFailure(errorCode);
      }
    }
    

    17、启动GATT服务

    只有广播仍然不够,作为外围角色的设备还需要启动GATT服务,等待中心设备与之建立连接之后就可以通过服务通信

    // 启动 Gatt 服务
    bluetoothGattServer = bluetoothManager.openGattServer(context, bluetoothGattServerCallback);
    

    接下来可以向启动的GATT服务中添加Service

    // 构造服务
    BluetoothGattService bluetoothGattService = new BluetoothGattService(UUID.randomUUID(), BluetoothGattService.SERVICE_TYPE_PRIMARY);
    
    // 构造特征
    BluetoothGattCharacteristic bluetoothGattCharacteristic = new BluetoothGattCharacteristic(UUID.randomUUID(), BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ);
    bluetoothGattCharacteristic.setValue("character_test_value");
    
    // 构造描述
    BluetoothGattDescriptor bluetoothGattDescriptor = new BluetoothGattDescriptor(UUID.randomUUID(), BluetoothGattDescriptor.PERMISSION_READ |BluetoothGattDescriptor.PERMISSION_WRITE);
    bluetoothGattDescriptor.setValue("descriptor_test_value".getBytes());
    
    // 添加描述到特征中
    bluetoothGattCharacteristic.addDescriptor(bluetoothGattDescriptor);
    // 添加特征到服务中
    bluetoothGattService.addCharacteristic(bluetoothGattCharacteristic);
    // 添加服务
    bluetoothGattServer.addService(bluetoothGattService);
    

    18、GATT服务回调

    bluetoothGattServerCallback 是GATT服务的回调,当设备被连接、通信(读写特征)时都会触发响应的回调函数

    bluetoothGattServerCallback = new BluetoothGattServerCallback {
      @Override
      public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
        super.onConnectionStateChange(device, status, newState);
      }
    
      @Override
      public void onServiceAdded(int status, BluetoothGattService service) {
        super.onServiceAdded(status, service);
      }
      
      @Override
      public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
                                              BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
      }
    
      @Override
      public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
                                               BluetoothGattCharacteristic characteristic,
                                               boolean preparedWrite, boolean responseNeeded,
                                               int offset, byte[] value) {
        super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite,
                                           responseNeeded, offset, value);
      }
    
      @Override
      public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
                                          int offset, BluetoothGattDescriptor descriptor) {
        super.onDescriptorReadRequest(device, requestId, offset, descriptor);
      }
    
      @Override
      public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
                                           BluetoothGattDescriptor descriptor,
                                           boolean preparedWrite, boolean responseNeeded,
                                           int offset, byte[] value) {
        super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded,
                                       offset, value);
      }
    
    
      @Override
      public void onNotificationSent(BluetoothDevice device, int status) {
        super.onNotificationSent(device, status);
      }
    

    0x10 参考

    1、蓝牙技术发展史

    2、蜗窝科技蓝牙系列文章

    3、深入浅出讲解低功耗蓝牙(BLE)协议栈

    展开全文
  • 蓝牙相关协议解析

    千次阅读 2021-07-21 18:14:13
    1、ARM平台蓝牙协议栈移植详解: https://blog.csdn.net/gatieme/article/details/48751743 2、蓝牙协议栈各层功能简介: http://blog.chinaunix.net/uid-21411227-id-2780269.html 3、蓝牙广播通信相关技术分析...

    目录

    【参考链接如下】

    1 蓝牙广播通信解析                      -------具体参考链接3

    2  HIC                                  --------具体参数参考链接4

    2.1  HIC command格式                  —-----具体参数参考链接5

    2.2  HIC event                               —-----具体参数参考链接5

    3 .L2CAP(逻辑链路控制和适配协议)        ------具体参数参考链接6

    3.1 信道工作模式

    3.2 信道分类

    3.1.1 面向连接的信道

    3.1.2 无连接信道

    3.1.3 信令信道

    4. RFCOMM (串口仿真协议)

    5. SDP (服务发现协议)  

    6.  GAP(Generic Access Profile通用访问协议)

    7. ATT (属性协议)

    8. GATT (Generic Attribute Protocol 通用属性协议)


    【参考链接如下】

    1、ARM平台蓝牙协议栈移植详解:

    https://blog.csdn.net/gatieme/article/details/48751743

    2、蓝牙协议栈各层功能简介:

    http://blog.chinaunix.net/uid-21411227-id-2780269.html

    3、蓝牙广播通信相关技术分析:PDU数据包的构成及分析、channel分析、三种广播状态(7种广播类型)、command参数

    https://blog.csdn.net/huangshuyi529/article/details/80435010

    4蓝牙HCI层采用不同串口分析:HCI层描述了Host和Controller之间可以通过串口、usb口进行连接的不同参数和不同的处理方式

    https://blog.csdn.net/dahailinan/article/details/109337222?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-0&spm=1001.2101.3001.4242

    5、HCI层数据包参数详解:OCF 、OGF、及其组合参数解析(详),供应商特定操作码解析,HCI数据传输过程的文字解析

    https://blog.csdn.net/weixin_30823833/article/details/98105913?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.control

    6、I2CAP协议:信道工作模式,信道分类、各类信道在不同工作模式下的帧

    https://blog.csdn.net/xsophiax/article/details/104052416

    7、RFCOMM协议(详):https://blog.csdn.net/madannasf/article/details/102738074

    8、SDP协议:https://blog.csdn.net/jobbofhe/article/details/78477407

    9、GAP协议:https://blog.csdn.net/liwei16611/article/details/80958842

    10、ATT协议(详):https://blog.csdn.net/zw515370851/article/details/88959205

    10-1:GAP、ATT、GATT协议简析

    https://blog.csdn.net/stivor/article/details/107507162

    11、GATT协议:https://www.pianshen.com/article/2563508308/

    1 蓝牙广播通信解析                      -------具体参考链接3

    1.1 广播类型及其编码

    报头的内容取决于该报文是广播报文还是数据报文。广播报文的报头如下图

    广播报文的报头包含4bit广播报文类型、2bit保留位、1bit发送地址类型和1bit接收地址类型。 

    广播类型可分为三类,Advertising Event Type1-4), Scanning状态(5-6),Initiating状态(7),详细介绍如下所示:

    1. 可连接的非定向广播(Connectable Undirected Event Type):

            这是一种用途最广的广播类型,包括广播数据和扫描响应数据,它表示当前设备可以接受其他任何设备的连接请求。进行通用广播的设备能够被扫描设备扫描到,或者在接收到连接请求时作为“从设备”进入一个连接。通用广播可以在没有连接的情况下发出,换句话说,没有主从设备之分。

    2. 可连接的定向广播(Connectable Directed Event Type):

            定向广播类型是为了尽可能快的建立连接。这种报文包含两个地址:广播者的地址和发起者的地址。发起者收到发给自己的定向广播报文之后,可以立即发送连接请求作为回应。 定向广播类型有特殊的时序要求。完整的广播事件必须每3.75ms重复一次。这一要求使得扫描设备只需扫描3.75ms便可以收到定向广播设备的消息。 

    3. 可扫描的非定向广播(Scannable Undirected Event Type):

            又称可发现广播,这种广播不能用于发起连接,但允许其他设备扫描该广播设备。这意味着该设备可以被发现,既可以发送广播数据,也可以响应扫描发送扫描回应数据,但不能建立连接。这是一种适用于广播数据的广播形式,动态数据可以包含于广播数据之中,而静态数据可以包含于扫描响应数据之中。

    4. 不可连接的非定向广播(Non-connectable Undirected Event Type):

            仅仅发送广播数据,而不想被扫描或者连接。这也是唯一可用于只有发射机而没有接收机设备的广播类型。不可连接广播设备不会进入连接态,因此,它只能根据主机的要求在广播态和就绪态之间切换。

    5. 扫描请求(SCAN_REQ):

            蓝牙一直会不间断的发送扫描请求,主动寻找正在广播的设备,以建立连接

    6. 扫描响应(SCAN_RSP):

            蓝牙进行文件传送时,传送几个文件,这里就会响应几次,接收数据

    7. 连接请求(CONNECT_REQ):

            它不关心广播数据,只关心ADV_DIRECT_IND和ADV_IND两类消息,并在符合条件的时候,发出CONNECT_REQ,请求建立连接。

            LE定义了物理层、链路层、L2CAP、安全管理器、属性协议和通用属性配置文件。GAP定义了四个特定角色:Broadcaster(广播), Observer(观察)、从机和主机

    2  HIC                                  --------具体参数参考链接4

    BLE协议在硬件上分为上下两部件:主机(Host,PC、单片机、Linux板)、控制器(蓝牙模块), Host和Controller之间,通过HCI(Host Controller Interface)相连,如下图所示:

     https://img-blog.csdnimg.cn/img_convert/1deb8185bef22421fa13ac5f200426e8.png

    Host和Controller之间的数据有命令(Command)、事件(Event)、ACL数据和SOC数据(传输层)。

    HCI可分为三个部分,前两个 用于沟通Host和Control的接口,具体如下:
             位于Control中的HCI Firmware
             位于Host的HCI Driver
             位于Host 和Control的HCI 传输层

    HCI层描述了Host和Controller之间通过什么接口来连接,可以通过串口、usb口等进行连接。

             当通过串口进行传输数据时,可以在数据的前面加上一个字节的头部,用来分辨这个数据是command、event还是acl data,头部格式如下图所示:
            对于usb口,在usb硬件里面有多个endpoint,command可以发送给某个端点,event可以从某个端点发给Host,不同的数据使用不同的端点。在硬件上传输这些数据时,就不需要加上头部,只需发送数据本身就可以了。

     

    send_packet函数原型为:

    int    (*send_packet)(uint8_t packet_type, uint8_t *packet, int size);

    其中的packet_type有4种取值,代表4种类型的数据(BLE中只有3种,不支持SCO),这些值在头文件btstack-master\src\bluetooth.h中定义:

    https://img-blog.csdnimg.cn/img_convert/eb23f37c3cad01189785aeccb11ea58d.png

    2.1  HIC command格式                  —-----具体参数参考链接5

    OGF(组域)=OpCode Group Field        OCF(命令域)=OpCode Command Field       OpCode:用以区分不同的命令, OGF(最高有效位6比特) OCF(最低有效位10比特)),具体OCF OGF及其组合参数解析参考链接5的第2

    Parameter_Total_length:参数的长度(以字节为单位,一般为1字节)

    Parameter 0~N        :参数列表

    Command分为六种类型(case OGF)

            ~0x01 链路控制命令(Link Control Commands)

            ~0x02 链路政策命令(Link Policy Commands)

            ~0x03 控制和基带命令(Control & Baseband Commands)

            ~0x04 信息命令(Informational Parameters)

            ~0x05 状态命令(Status Parameters)

            ~0x06 测试命令(Testing Commands)

            ~0x08 仅限LE指令( LE Only Commands)----Low Power

            ~0x3F 厂商调试命令(Reserved)

    tip: 所有BLE相关的HCI Command的OGF都是0x08。

    Host发出的大多数Command都会触发Control产生相应的Event作为响应

    广播通信相关的HCI Command介绍:         —-----具体参数参考链接3

    用于设置广播参数(HCI_LE_Set_Advertising_Parameters);

    广播数据(HCI_LE_Set_Advertising_DataOCF为0x0008);

    建立连接(HCI_LE_Create_Connection);

    取消连接(HCI_LE_Create_Connection_Cancel)等                            

    2.2  HIC event                               —-----具体参数参考链接5

    Event Code                     用以区分不同的事件(0x00~0xFF)

    Parameter_Total_length    参数的长度(以字节为单位)
    Event Parameter 0~N       参数列表

    HCI事件使用8位事件代码,所有LE事件只有一个事件代码(0x3E)。

    所有事件代码对于BT和BLE都是唯一的。

    仅供应商特定事件保留事件代码255。

    第一个事件参数用作子事件代码以区分LE事件类型,LE事件及对应的子事件代码如下图所示:

     其他事件对应的代码如下所示:

    3 .L2CAP(逻辑链路控制和适配协议)        ------具体参数参考链接6

            L2CAP位于基带之上,将基带的数据分组转换为便于高层应用的数据分组格式,并提供协议复用和服务质量交换等功能。L2CAP只支持ACL数据传输,不支持SCO数据。

            L2CAP中文为逻辑链路适配层,主要提供信息数据的分割/重组等传输方式。在bluedroid中,很多的上层会向l2cap注册相关服务,比如rfcomm(虚拟串口,最多可虚拟64路),sdp,gatt等。

            1、L2CA_Register (SDP_PSM, &sdp_cb.reg_info)

            2、L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info)

    3.1 信道工作模式

    逻辑信道可以工作在5种不同的模式下(可以理解为5种不同的使用场景),最后一种是LE设备特有的:

            1、Basic L2CAP Mode 默认模式,在未选择其他模式的情况下,用此模式。

            2、Flow Control Mode 此模式下不会进行重传,但是丢失的数据能够被检测到,并报告丢失。

            3、Retransmission Mode 此模式确保数据包都能成功的传输给对端设备。

            4、Enhanced Retransmission Mode 此模式和重传模式类似,加入了Poll-bit等提高恢复效率。

            5、Streaming Mode 此模式是为了真实的实时传输,数据包被编号但是不需要ACK确认。设定一个超时定时器,一旦定时器超时就将超时数据冲掉。

            6、LE Credit Based Flow Control Mode 被用于LE设备通讯。

    3.2 信道分类

    L2CAP信道有三种类型:

            A、面向连接信道CO:Connection-Oriented,用于两个设备之间的数据通信。

            B、无连接信道CL:Connection-Less,用来向一组设备广播方式传输数据。CID(channel ID)为固定值:0x0002

            C、信令信道:Signaling,用于创建CO通道,可以通过协商改变CO信道的特性。若当前蓝牙处于普通蓝牙模式下,CID = 0X0001;  若当前蓝牙处于低功耗模式下,CID = 0X0005

    3.1.1 面向连接的信道

            用于基础L2CAP模式下的面向连接信道。B格式如下:

            其中的LengthInformation payload的长度,不包括包头长度,Information payload的长度范围是0~65535ChannelID为接收方的CID

    举例如下:

    3.1.2 无连接信道

            1) 用于基础L2CAP模式下面向无连接的信道。G用于固定的无连接信道0x0002,G帧格式如下:

            PSM为(协议/服务复用器Protocol/Service Multiplexer)用于指定上层的传输类型,一般为SDP、RFCOMM、TCS等中介协议复用。小于0x1000的值,0x0001对应SDP,0x0003对应RFCOMM、0x0005对应TCS。CID为固定值0x0002

            抓包举例如下:

     

    2)     I/S用于重传、流控或者流模式下面向无连接的信道。I帧(Information frame)被用于L2CAP实体之间的信息传递;S帧被用于I帧的确认和请求重传。I/S帧格式如下:

    Length为除了Basic L2CAP header外的数据长度。

    需要指出的是:只有在服务数据包SDU需要分段,并且是第一个L2CAP包的时候才需要L2CAP SDU Length段。

    Control字段与L2CAP模式有关,具体每种模式对应的control字段处理方式有a b c三种,如下所示:

    3)  LE,Channel I

    D为接收方的CID。格式如下:(暂定为无连接信道,不确定)

    3.1.3 信令信道

    1) 控制帧(Control frame)在信令信道(传统蓝牙0x0001BLE0x0005)上传输。

            在信令信道0x0001上可以多个控制命令同时包含于一个C帧中,但是0x0005信道上一个C帧只能够包含一个控制命令。C帧格式如下所示:

            Code表示控制命令的固定编号,例如连接请求为0x02;

            Identifier为请求方设置此标志,回应方回复请求帧的时候需要和请求帧的Identifier一致。

            Length表示data的长度。

            Data依据不同的命令而定的。

    L2CAP信令指令码:

    具体可参考以下例子进行分析:

     L2CAP:

             Role:Master

             Address:11

             PDULength: 6  //指令的长度,值为06 00

             ChannelID: 0x0001  (Signaling)//L2CAP的信令通道,值为01 00

             Code:Information request   //信息请求,值为0a----对应信令指令码

             Identifier:1//标识符,值为01

             CommandLength: 2//命令长度,值为02 00

             InfoType:Extended features supported//02 00

    4. RFCOMM (串口仿真协议)

            RFCOMM协议基于L2CAP协议的串行(9针RS-232)仿真。最新规范是V12,支持在两个蓝牙设备间高达60路的通信连接。

            RFCOMM支持两种设备类型的存在:一是设备本身就是通信终端(如计算机,打印机) ,而是作为通信节点使用。

    • Address

    • Control字段

    • Length 由最低位决定长度占位是1字节还是2字节,最低位为1时,长度为7bits(0~127),最低位为0时,长度为 5bits(0~32767)
    • RFCOMM帧类型如下:

    SABM

    异步平衡模式设置指令

    UA

    未加编号的确认响应

    DM

    断开连接模式响应

    DISC

    断开连接指令

    UIH

    带头校验的未编号信息命令和响应

    • FCS校验

            对于SABM,DISC,UA和DM帧,FCS计算Address,Control and Length字段用于接收方校验接收数据是否正确,校验原理采用循环冗余校验CRC-8

            对于UIH帧,FCS计算Address and Control字段

            具体帧的分析实例参考链接7---RFCOMM协议数据分析

    5. SDP (服务发现协议)  

    SDP两种服务发现模式:
    1)服务搜索:查询具有特定服务属性的服务;
    2)服务浏览:简单的浏览全部可用服务。
    PDU 格式:(协议数据单元)

    PDU ID1byte

    Transaction ID2byte

    参数长度(2byte

    参数1

    ……

    参数N

    Header

    不同PDU ID实现SDP的不同功能,概述如下表格:

    Value

    Parameter Descirption

    0x00

    Reserved 

    保留

    0x01

    SDP_ErrorResponse

    错误响应

    0x02

    SDP_ServiceSearchRequest

    服务搜索请求

    0x03

    SDP_ServiceSearchResponse

    服务搜索响应

    0x04

    SDP_ServiceAttributeRequest

    服务属性请求

    0x05

    SDP_ServiceAttributeResponse

    服务属性响应

    0x06

    SDP_ServiceSearchAttributeRequest

    服务搜索属性请求

    0x07

    SDP_ServiceSearchAttributeResponse

    服务搜索属性响应

    0x08-0xff

    Reserved

    保留

    SDP的服务记录表对每一个服务进行描述,每条记录包含服务句柄(Handle)、一组服务属性(Attributes)

    6.  GAP(Generic Access Profile通用访问协议)

            GAP 给设备定义了若干角色,其中主要的两个是:外围设备(Peripheral - 从机 - 服务端)和中心设备(Central - 主机 - 客户端)。

            外围设备 - 从机:这一般就是非常小或者简单的低功耗设备,用来提供数据,并连接到一个更加相对强大的中心设备,例如小米手环;

            中心设备 - 主机:中心设备相对比较强大,用来连接其他外围设备。例如手机等;

            GAP 中外围设备通过两种方式向外广播数据:Advertising Data Payload(广播数据)和 Scan Response Data Payload(扫描回复):

            每种数据最长可以包含 31 byte,广播数据是必需的,因为外设必需不停的向外广播,让中心设备知道它的存在;

            扫描回复是可选的,中心设备可以向外设请求扫描回复,这里包含一些设备额外的信息,例如:设备的名字。

            大部分情况下外设通过广播自己来让中心设备发现自己,并建立 GATT 连接,从而进行更多的数据交换;

            也有些情况是不需要连接的,只要外设广播自己的数据即可,用这种方式主要目的是让外围设备,把自己的信息发送给多个中心设备。

    1)定义GAP层的蓝牙设备角色(role)

            和Link Layer的role类似,只不过GAP层的role更接近用户(可以等同于从用户的角度看到的蓝牙设备的role),包括:

            Broadcaster Role,设备正在发送advertising events;

            Observer Role,设备正在接收advertising events;

            Peripheral Role,设备接受Link Layer连接(对应Link Layer的slave角色);

            Central Role,设备发起Link Layer连接(对应Link Layer的master角色)。

    2)定义GAP层的、用于实现各种通信的操作模式(Operational Mode)和过程(Procedures),包括:

            Broadcast mode and observation procedure,实现单向的、无连接的通信方式;

            Discovery modes and procedures,实现蓝牙设备的发现操作;

            Connection modes and procedures,实现蓝牙设备的连接操作;

            Bonding modes and procedures,实现蓝牙设备的配对操作。

    3)定义User Interface有关的蓝牙参数,包括:

            蓝牙地址(Bluetooth Device Address);

            蓝牙名称(Bluetooth Device Name);

            蓝牙的pincode(Bluetooth Passkey);

    7. ATT (属性协议)

            服务项包含一个或多个特征值,特征值包含一个或多个描述符,多个服务项组织在一起,构成属性规范ATT

    ATT协议将“信息”以“Attribute(属性)”的形式抽象出来,并允许client和server通过Attribute的形式共享信息,提供一些方法,供远端设备(remote device)读取、修改这些属性的值(Attribute value)。

    Attribute Protocol的主要思路包括:

            1)基于L2CAP,使用固定的Channel ID(0x0004

            2)采用client-server的形式。提供信息(以后都称作Attribute)的一方称作ATT server(一般是那些传感器节点),访问信息的一方称作ATT client。

            3)一个AttributeAttribute TypeAttribute HandleAttribute Value组成

            Attribute Type用于标示Attribute的类型,类似于我们常说的“温度”、“湿度”等,不同的是,Attribute Type使用UUID(Universally Unique IDentifier,16-bit、32-bit或者128-bit的数值)区分。

    Attribute4个字段表示类型,句柄,权限,值

            属性类型:由一个128bits的UUID表示               --------》用来搜索属性

            句柄:唯一的无符号数(16bits)                      ---------》用来识别属性

            权限:决定客户端是否可以读取和修改资源

            属性值:可以是定长也可以是变长

    方法有6种:对应6Protocol Data UnitsPDU 协议数据单元)       ---具体参考链接9

            Commands:由客户端发给服务端,并不作响应

            Requests :由客户端发给服务端,并作响应

            Responses:收到Requests(请求)后,服务的将响应发给客户端

            Notifications :服务器主动发送通知给客户端,没响应

            Indications :服务器发送指示给客户端,有响应

            Confirmations :客户端发送给服务器以作为对指示(Indications)的确认

            (客户端:一般指手机。服务端:指存储各种数据的设备)

            ATT协议本身没有定义任何UUID。这部分工作留给了GATT和上层协议。

            和属性相关的还有读写权限。读写权限存在属性值里,由高层协议确定。ATT本身不会关心,也不会试图解释属性值来确定权限。这部分工作也留给了GATT和上层协议。

            ATT有一些良好的特征,比如通过UUID来搜索属性,通过handle区间范围来获取所有区间内的属性,因此client不需要提前获得handle的值,也不需要高层协议硬编码这些值。

    8. GATT (Generic Attribute Protocol 通用属性协议)

            用于提供通用的、信息的存储和共享等功能,基于 GATT 连接的方式的,只能是一个外设连接一个中心设备。

            服务:服务可以由一个或多个特征,服务使用UUID与其他服务区别开来,对于通用的服务使用16bits的UUID,对于自定义服务则使用128bits的服务。

    特征每个特征包含特征属性,特征值,描述符

    特征属性(上图中的properties)由以下属性组成

            属性类型为:“特征“

            属性值由3个位域组成:特征UUID(2/16字节),特征属性(1字节),特征句柄(2字节)

            属性权限必须是可读的,并且不需要身份验证或授权

            特征属性位域显示了如何使用特征值或其描述符可以访问。它可以是广播,读取,无响应写入,写入,通知,指示,已认证签名写入或扩展属性

    特征值(上图中的value

            属性类型与特性声明中的UUID相同。

            属性值是特征值。

            属性权限是特定于实现的

    描述符:特征描述符是可选的,用于提供有关特征的附加信息

            GATT service的基础是UUID值为0x2800的属性。所有跟在这个属性后面的属性都属于这个属性定义的服务,直到另一个0x2800属性出现。

            每个属性定义事实上包含了两个UUID,0x2800或者0x2801作为属性UUID,另外一个属性值里面存储的UUID。后面这个UUID是服务ID。这是GATT/ATT分层方式导致的后果。 UUID0x2800被GATT用来寻找服务定义边界。一旦找到了边界,属性值,也就是第二个UUID用来指定服务。这样client能够找到所有的服务而不需要知道服务的具体定义。

            GATT中所有的服务细节通过ATT来描述,所以不需要像BR/EDR那样设置专门的服务发现协议。

    展开全文
  • 蓝牙RFCOMM协议

    2021-01-14 19:15:02
    零. 概述 本文章主要讲下蓝牙RFCOMM协议(bluetooth rfcomm)的帧格式,包括Address,Control,Length Indicator...第二篇:Transport层介绍,主要介绍蓝牙协议栈跟蓝牙芯片之前的硬件传输协议,比如基于UART的H4,H5,BCSP,
  • 大牛在蓝牙BLE领域干了十来年的总结,总结得很到位。都准备出书了。非常好。在这里共享给大家!版权所有273、扫描态.46274、发起态275、软件设计广播状态流程图.….….:::::::::::..:·::.::::::4728、连接状态...
  • 深挖蓝牙BLE配对过程系列文章其一:配对特性交换。记录笔者查阅大量文章,努力翻译Core_v4.2以上版本标准的学习成果...介绍低功耗蓝牙BLE协议栈配对连接过程系列文章,本文仅为其中一小部分,带自己深入探讨蓝牙协议
  • 蓝牙协议栈(四、协议)

    千次阅读 2019-09-11 17:43:22
    BTstack是一种模块化双模蓝牙堆栈,支持蓝牙基本速率/增强日期速率(BR / EDR)以及蓝牙低功耗(LE)。BR / EDR技术也称为经典蓝牙,可在专为高数据速率设计的设备之间提供强大的无线连接。相比之下,LE技术具有更低...
  • 蓝牙篇之蓝牙核心规范(V5.2)深入详解汇总 ...安全管理协议为低功耗系统独有的,在经典蓝牙系统,安全管理协议包含在控制器的链路管理器模块。在低功耗系统,安全管理协议被移至主机...
  • 蓝牙低功耗(Bluetooth Low Energy,或称Bluetooth LE、BLE,旧商标Bluetooth Smart)也称蓝牙低能耗、低功耗蓝牙,是蓝牙技术联盟设计和销售的一种个人局域网技术,旨在用于医疗保健、运动健身、信标、安防、家庭...
  • UART协议就应该这么理解

    千次阅读 2022-04-08 15:37:16
    UART协议的概念介绍:包括串行/并行概念,单工/半双工/全双工,数据格式,数据速率,流控,最后再介绍下基于UART标准的RS232,RS485接口
  • 蓝牙篇之蓝牙核心规范(V5.2)深入详解汇总 目录 3 配对方法 3.1 安全属性 3.2 IO能力 3.3 OOB认证数据 3.4 加密密钥大小 3.5配对算法 3.5.1 选择密钥生成方法 3.5.2 LE传统配对-Just Works 3.5.3 LE传统...
  • 蓝牙协议栈(三、如何配置Btstack)

    千次阅读 2019-09-11 17:41:32
    BTstack实现了一组蓝牙协议和配置文件。要连接其他蓝牙设备或提供蓝牙服务,必须正确配置BTstack。 BTstack的配置既可以在编译时完成,也可以在运行时完成: 编译时配置: adjustbtstack_config.h- 此文件...
  • 蓝牙Mesh协议三 设备配网

    千次阅读 2021-01-21 13:48:20
    蓝牙Mesh配网就是通过配网器配置未配网设备,将未配网设备加入网络,使其成为蓝牙mesh网络的节点;配网数据包括分发网络密钥(network key)、元素单播地址(unicast address)和IV Index 为了提高配网效率,厂家会...
  • 蓝牙篇之蓝牙核心规范(V5.2)深入详解汇总 1.GATT定义 通用属性协议(GATT)使用属性协议定义了一个服务框架。该框架定义了服务的程序和格式及其特征。所定义的过程包括发现、读、写、通知和指示特征,以及配置...
  • 蓝牙基础知识总结

    千次阅读 2021-05-12 09:37:53
    蓝牙基础知识总结 蓝牙版本概述 蓝牙各个版本发布时间: 版本 规范发布时间 增强描述 0.7 1998-10-19 Baseband,LMP 0.8 1999-1...
  • 蓝牙协议中HCI层的研究与开发

    千次阅读 2015-10-19 17:43:06
    从图可以看出,HCI是位于蓝牙系统的L2CAP(逻辑链路控制与适配协议)层和LMP(链路管理协议)层之间的一层协议。HCI为上层协议提供了进入LM的统一接口和进入基带的统一方式。在HCI的主机(Host)和HCI主机控制器...
  • 蓝牙安全与攻击案例分析

    千次阅读 2021-07-11 12:46:43
    本文是 2020 年旬对于蓝牙技术栈安全研究的笔记,主要针对传统蓝牙和低功耗蓝牙协议层和软件安全性上攻击面分析,并介绍了一些影响较大的蓝牙漏洞原理,比如协议层的 KNOB、BIAS 漏洞,软件实现上的 BlueBorne、...
  • 蓝牙协议

    2014-01-07 10:02:12
    什么是蓝牙  一、蓝牙名字的由来  蓝牙的名字来源于10世纪丹麦国王Harald Blatand-英译为Harold Bluetooth。在行业协会筹备阶段,需要一个极具有表现力的名字来命名这项高新技术。行业组织人员,在经过一夜关于...
  • 蓝牙协议简述 && Linux下Bluez

    千次阅读 2017-02-21 13:55:57
    121蓝牙协议栈体系结构122蓝牙协议栈低层模块123软件模块 13蓝牙的一些Profile 2Bluez和D-Bus 21Bluez和D-Bus体系结构22D-Bus介绍23Bluez的安全接口24Bluez适配器接口25Bluez配对26Bluez绑定 3Bluez编程实现
  • 蓝牙LE Audio的关键-LC3技术

    千次阅读 2020-11-07 11:09:09
    在过去的二十年,自成立以来,蓝牙技术已成为去到解决方案对于绝大多数的无线音频流应用。如果您曾经通过头戴式耳机或汽车的信息娱乐系统无线听音乐,那么您很可能已经使用了蓝牙技术。 蓝牙经典(BR / EDR)已...
  • 蓝牙 - Bluetooth SIG

    千次阅读 2022-03-02 07:53:44
    它拥有蓝牙的商标,负责认证制造厂商,授权他们使用蓝牙技术与蓝牙标志,但是它本身不负责蓝牙装置的设计、生产及贩售。 Bluetooth SIG成立于1998年9月,是一个由成员组织组成的网络,是蓝牙技术的守护者和创新者...
  • IP协议解析与实战

    2022-05-15 16:34:02
    1.IP协议概述 1.1 什么是IP协议?...通过之前对ARP协议的分析,可以发现它是通过MAC地址发送数据的,但是其有一个很大的问题:ARP协议是子网广播协议(在子网的所有的设备都会收到该ARP协议数据包)。
  • 1. 前言大家都知道,相比传统蓝牙蓝牙低功耗(BLE)最大的突破就是加大了对广播通信(Advertising)的支持和...本文将依此为基础,从技术的角度,分析和理解BLE协议中有关广播通信的定义和实现。注1:之前的蓝牙协...
  • 蓝牙版本发展

    2021-03-08 17:21:06
    蓝牙这个名称来自于第十世纪的一丹麦国王哈拉尔蓝牙王,哈拉尔蓝牙王Blatand 在英文里的意思可以被解释为 Bluetooth( 蓝牙 )因为国王喜欢吃蓝莓,牙龈每天都是蓝色的所以叫蓝牙。 在行业协会筹备阶段,需要一个极...
  • 在应用层这里,最最重要的事情,就是 “设计并实现一个应用层协议” 这是一个非常简单,同时也是在工作经常要做的事情 举个栗子: 你们公司在开发一个项目,点外卖的软件 当前要开发一个功能,叫做获取用户的订单...
  • 蓝牙协议中HCI层的研究与开发蓝牙协议中HCI层的研究与开发刘向阳,沈连丰(东南大学移动通信国家重点实验室, 南京 210096)一、HCI在蓝牙软件协议模型位置的分析蓝牙系统的协议模型如图1所示。从图可以看出,HCI...
  • 带你解锁蓝牙skill(三)

    千次阅读 2017-06-21 11:38:10
    蓝牙这块儿算是系统的一个大块儿,刚开始分析确实很容易没有头绪,所以在进入庞大的源码之前先确定一个分析顺序,也好避免越学越乱。 对于源码的分析不外乎whw(what—how—why)对于蓝牙协议的功能以及如何...
  • 低功耗蓝牙(BLE)基本概念讲解三、Android BLE API 简介1.Android 蓝牙开发示例第一步:声明所需要的权限第二步:连接蓝牙前的初始化工作第三步:扫描蓝牙设备第四步:连接蓝牙设备第五步:发现服务最后一步:断开...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,537
精华内容 1,014
关键字:

蓝牙协议中的计算标志位

友情链接: weixinMenu.rar