低功耗蓝牙_低功耗蓝牙芯片 - CSDN
精华内容
参与话题
  • 低功耗蓝牙学习

    千次阅读 2016-07-15 11:21:51
    一、低功耗蓝牙  1、简介 低功耗蓝牙是当前功耗最低的无线技术,有别于传统的标准蓝牙。 1.0版蓝牙最大 的物理层数据速率为1Mbps,2.0版本为3Mbps,3.0引入了交替射频技术速率高达百兆。低功耗蓝牙并非只是增加速率...

    一、低功耗蓝牙

       1、简介

    低功耗蓝牙是当前功耗最低的无线技术,有别于传统的标准蓝牙。

    1.0版蓝牙最大 的物理层数据速率为1Mbps,2.0版本为3Mbps,3.0引入了交替射频技术速率高达百兆。低功耗蓝牙并非只是增加速率,尽可能的降低功耗。

    低功耗设备分为两类:单模设备、双模设备。双模设备支持经典蓝牙又支持低功耗蓝牙,单模设备只支持低功耗蓝牙。第三种类型,只支持经典蓝牙。单模设备只能与单模设备或者双模设备不能与经典蓝牙通信,单模设备不支持头戴式耳机、立体声音乐和较高的文件传输速率,无法再大部分领域使用。

    跳频:两个节点之间通信,使用多个频率,某一时刻只使用一个频率,各频率按照确定的顺序依次使用。

    自适应跳频:使用某个频率子集的技术,使设备可以避免其他非自适应技术使用的频率。

    层:系统中一个具体功能部分。每一次都是根据上层或者下层抽象而来。

      1.2、时间即能力

    鲁棒的设备发现至少两个模块:一个模块寻找其他设备,一个模块处于可发现状态。低功耗蓝牙中,一个设备如果想被发现就必须每个几秒发送三次短消息;如果想与发现它的设备通信,在广播短消息之后立即进入监听。寻找其他设备时,设备打开它的接收器并帧听其他设备的广播。三次传输利用三个不同的频率,防止某一个频率被阻塞。

      1.3 无连接模型

    低功耗蓝牙大约3ms可快速的建立连接,这意味着发送完成后可断开连接节约能量,下次发送数据时重新建立连接。

    低功耗蓝牙架构:客户端—服务器(客户端发送请求,服务器响应),面向服务。

    二、蓝牙的体系结构

      2.1、低功耗蓝牙结构分为三个部分:控制器、主机、应用程序。控制器通常是无力设备,能够发送和接收无线信号,并能将无线信号解码成数据包。主机通常是软件栈,管理多个设备间通信。应用程序则使用软件栈使控制器实现


    协议栈包括两个部分:主机和控制器。任何的规范和应用都以协议栈的GAP(通用访问规范)、GATT(通用的属性规范)为基础。

    物理层:1Mbps的GFSK,2.4G ISM频段。

    数据链路层(LL):控制射频的状态,设备的5中状态:待机(就绪)、扫描、广播、发起、链接。没有连接的设备广播数据,扫描中的设备如果接收到广播数据如果想连接广播设备,那么给广播设备发送发连接请求,如果广播设备接收连接请求了,那这两个设备就会进入连接状态。广播设备是从机,扫描设备是主机。

    HCI层为主机和控制器进行数据交互提供了标准的接口。这个层可以通过软件API或者硬件接口比如UART,SPI,USB实现。

    L2CAP层:为上一层提供数据封装服务,允许合理的端对端的数据交互。

    SM层:安全管理层定义校验和密匙分发的方法,为协议栈其他层的安全连接和交换数据提供方法。

    GAP层:面向应用或者规范,解决设备发现,为设备连接相关设备。GAP层掌握安全特征的发起。

    ATT协议:允许一个设备明文发送确定的数据片到另一个设备。也就是“属性”

    用户实例。

    控制器包含物理层和链路层还有和协议栈的接口HCI。协议栈包含三个协议:逻辑链路控制和适配协议(L2CAP)、属性协议(Attribute Protocol)、安全管理协议(Security Manager Protocol),还包括通用属性规范(GATT )、通用访问规范(GAP)、模式(mode).

    物理层采用2.4G无线电,完成传送和接收数据。无线电波可以在给定的某一个频段给改变幅值、频率、相位来携带信息。低功耗蓝牙采用高斯频移键控GFSK。从中心频率发出超过185khz的正向偏移代表1,超过185k的负向偏移表示0。2.4G频段被划分为40个RF信道,每个宽度2M。

      2.2、链路层

    链路层负责广播、扫描、建立和维护链接,以及确保数据包按照正确的方式组织、校验和加密。与链路相关概念:信道、报文、过程。

    链路层信道分为两种:广播信道、数据信道。未建立链接的设备使用广播信道发送设备,广播信道有三个,设备利用广播信道通知其他设备自己是可发现或可链接的。建立连接后,用数据通道通信,数据信道有37个,由自适应跳频引擎控制。

    任意信道上的数据(广播信道和数据信道)均为小数据包,且格式相同。数据链路层数据格式:


    介入地址在广播信道中是固定的,在数据信道中是随机的私有值。

    2.3 协议栈和控制器接口HCI

    HCI为协议栈提供了一个与控制器通信的标准接口。它允许协议栈和控制器相互发送数据和命令。HCI由逻辑接口和物理接口组成。逻辑接口定义了命令和事件相关的行为;物理接口包括USB、SDIO和两个uart的变种。

      2.4、主机

    主机包括复用层、协议和实现许多功能。

    逻辑链路控制和适配协议(L2CAP)是一个复用层。复用层定义两个基本概念:L2CAP信道和LCAP信令。L2CAP信道是一个双向的数据通道。每个通道都是独立的,可以由自己的流量控制和配置信息。经典蓝牙使用了大部分功能包括动态信道标示符,协议服务多路复用器、增强的重传、流模式等,低功耗蓝牙使用了少部分功能。

    低功耗蓝牙只使用固定信道:一个用于信令信道,一个用于安全管理,还有一个属性协议。低功耗蓝牙只用一种侦格式,B侦,包含两个字节长度字段和两个字节的信道识别符。

      2.4安全管理协议

    安全管理器定义了一个简单的配对协议和密匙分发协议。配对是一个获取对方设备信任的过程,采取认证方式实现。配对之后接着是链路加密和密匙分发过程。密匙分发通常是从设备发给主设备。两个设备在未来某个时候进行重连时,可以使用先前分发的共享密匙进行加密,迅速完成认证。安全管理器提供一个工具箱,生产数据哈希值、确认值以及配对过程使用的短期密匙。

      2.5、属性协议

    属性协议定义了对端设备的数据规则,数据存储在属性服务器的“属性”里,供属性客户端执行读写操作。客户端将请求发送至服务器,服务器回复响应消息。客户端可以使用这些请求在服务器上找到所有的属性并进行读写属性。属性协议的六种信息:客户端发到服务器的信息、服务器回复给客户端的请求信息、客户端到服务器的无需响应的命令、服务器到客户端的无需确认的通知、服务器到客户端的指示、客户端给服务器回复指示确认。

      2.6、通用访问规范

    通用访问规范定义了设备如何发现、连接以及为用户提供信息。它还定义了如果建立长久的连接。

      2.7、应用层

    应用层定义了三种类型:特性(characteristic)、服务(service)、规范(profile).


    四、新的使用模型

    新的模型都是基于广播模式,包括存在检测、数据广播、无连接模型等。

      4.1、存在检测

    “存在”是指当前发生的或某处出现的状态和事实。使用广播模型,设备在后台被动扫描那些正在广播的设备。广播设备仅仅通告地址,也有少量数据。

    广播是数据链路层的模式。有了它,设备周期性的发送身份信息和少量数据。

    扫描模式分为两类:主动扫描、被动扫描。主动扫描,扫描者从广播者请求更多的信息以获取额外的静态数据;被动扫描,扫描者仅仅帧听广播数据,并不发送请求。链路层收到广播数据包后交给主机(协议栈)。

    数据广播:广播模式下发送少量数据。

       4.2、无连接模型

    无连接是低功耗蓝牙与经典蓝牙比较大的区别。无连接,设备无线为数据交换始终保持连接,每次在发送数据时重新建立连接。

    无连接定义的是设备的状态而不是连接到 状态。经典蓝牙定义了简单的状态机和配置系统用于建立连接,明确定义了所有 的链接状态,并对状态进行了完整描述。


    五、物理层

    两个蓝牙设备通过无线电波收发信息。无线电从最简单的火花隙式发射机开始到幅度调制、频率调制、到相移键控以及其他调制方案。

    火花隙式调制信道利用率低。

      5.1、调制

    低功耗蓝牙采用高斯频移键控,高斯滤波器通过增加一个值到另一个值的频率转换时间,过滤噪声。低功耗蓝牙物理层比特率为1Mbps。负频偏代表比特0,正频偏代表1,最小频偏约为180khz。如果中心频率选取2402M,比特0位2401.820Mhz,比特1 位2402.180Mhz。

      

      5.2、射频信道

    经典蓝牙用跳频来实现,经典蓝牙在79个窄带信道间切换进行信息传输。低功耗蓝牙使用40个信道,每个信道的中心频率为f=2402+2K Mhz。

    2.4G ISM频段最大发射功率+10dbm即10mw,最小不低于-20dbm功率为10uw。

      5.3 容限

    中心频率可以偏离 的最大限制。比如无线电设计为2402MHz发射,实际的工作频率可能是2401.850Mhz或者2402.150Mhz,报文中心频率的容限是±150KHz。中心频率偏移的原因可能是外部晶振的偏差或者芯片发热。

    报文发送过程中中心频率的偏移,发送过程中心频率的偏移不超过50KHz。如果发送报文时中心频率是2402MHz,发送过程中中心频率在2401.950Mhz—2402.050Mhz。

      5.4、接收灵敏度

    低功耗蓝牙灵敏度高于-70dbm即接收机收到0.000 000 1mW的电磁能量时要正常工作。


    六、链路层

    链路层 定义了两个设备如何利用无线电传输信息。包含了报文、广播、信道的详细信息、发现其他设备到流程、广播的数据、连接建立、连接管理以及连接中的数据传输。

      6.1、链路层的状态机

    链路层的5种状态:就绪态、广播态、扫描态、发起态、连接态。扫描有两个状态:被动扫描和主动扫描。连接太有两个子状态:主、从。

    就绪态:上电后链路层进入就绪态,直到接到主机命令从就绪态进入广播、扫描或者发起态。


    广播态可以发送广播报文也可以发送扫描响应用于回复主动扫描的设备。可被发现和可被连接的设备处于广播状态,广播数据也需要处于广播状态。广播态的设备停止广播后进入就绪态,收到发起者的链接请求后进入连接态。

    扫描状态的设备能够接收广播信道的报文,帧听哪些设备正在广播。被动扫描仅接收广播报文,主动扫描则发送扫描请求给广播态设备,并获取扫描响应的设备。主动扫描中,链路层一旦发现新的广播设备,都会发送扫描请求。

            发起态,为了发起连接链路层需要处于发起状态,发起态的发起者,其接收机用于帧听自己试图连接的设备。如果收到了该设备的广播报文,链路层向目标设备发送连接请求并进入连接态。如果发起者不再试图连接,可以进入就绪态。

            连接态,从广播态和发起态都可以进入连接态。两种情况都是发起者向广播者发送连接请求报文。连接态的两个子状态:主和从。连接态中两个设备相互传送数据报文,唯一一个用到数据通道的状态,其他各状态均使用广播信道。主连接状态只能从发起态进入,它必须向端设备发起连接。主设备定期向从设备发送报文,从设备只能通过回复这些报文发送自己的数据。从连接只能从广播态进入。

           设备不能成为主从设备。成为主设备后,不能发送可用于连接的广播报文,不过还可发送不可连接的广播报文或者是可发现的广播报文。从设备也不能发起连接,因为这会导致其成为主设备。一个设备也不能同时成为两个设备的从设备。经典蓝牙支持。

      6.2、报文

    报文是链路层的基石。报文很简单,带有标签的数据,一个设备发送,一个或多个设备接收。标签指明了数据由谁发出,要哪个设备接收。报文的基本结构:


     低功耗蓝牙报文有两类:广播报文和数据报文。广播报文用于发现、连接其他设备,一旦建立连接后,开始使用数据报文(用于连接建立后的设备)。是广播报文还是数据报文由信道决定。低功耗蓝牙规定了3个广播信道和37个数据信道。数据信道中的是数据报文,广播信道中的是广播报文。

      6.3、 白化

    频移键控(FSK)接收机连续接收相同比特的能力很差,为避免这一情况,低功耗蓝牙使用了“白化器”来随机化数据。对于给定的报文,“0”、“1”的顺序是确定的。


    前导:报文最开始的8个比特是01010101或者是10101010.

    接入地址:接入地址的第一个比特决定了前导是01010101还是10101010,如果接入地址的第一个比特是0,则使用01010101如果是1则使用10101010,保证报文的前9个比特都是交替的。

    32位的接入地址有两种类型:广播接入地址、数据接入地址。广播接入地址在广播数据或者是扫描、发起连接时使用。数据接入地址在两个设备建立连接后发送数据时使用。

    当控制器试图接收一个报文是,它要事先知道接收报文的接入地址。对于广播信道,接入地址是固定值0x8E89BED6,这意味着广播报文的前导是01010101.对于数据信道,接入地址是一个随机值,但是要符合规则,符合规则的数据通道接入地址大概有231个。

    报头的内容取决于是广播报文还是数据报文,广播报文有7种报头类型:

    ADV_IND 通用广播指示

    ADV_DIRECT_IND   定向连接指示

    ADV_NONCONN_IND  不可连接指示

    ADV_SCAN_IND可连接指示

    SCAN_REQ主动扫描请求

    SCAN_RSP主动扫描响应

    CONNECT_REQ连接请求


    信道:广播信道37/38/39,0-36是数据信道。低功耗蓝牙信道间隔2M,经典蓝牙信道间隔是1M。

                      


      6.4、跳频

    跳频算法用于数据连接中,数据信道共有37个是一个质数,因此调频算法很简单f(n+1)=(f(n)+hop)mod37;

    hop范围5~16.也可以先加hop如果大于36则减去37.

    自适应调频能够将一个已知的坏的信道映射到一个好的信道。

      6.5 设备发现

    一个设备广播,另一个设备扫描。共有四种不同类型的广播:通用的、定向的、不可连接的及可发现的。每次广播都会同时在三个信道上发送相同报文。除了定向广播,其他广播事件都会选择20ms-10.28s的间隔。扫描用于接收广播事件。

           通用广播能被扫描设备扫描到或者接收到连接请求时成为从设备,通用广播的设备可以在没有链接的情况下发出。也就是还没有主从之分。

    定向广播:为了快速的建立连接,报文包含两个地址:广播者的地址和发起者的地址。发起设备收到发给自己的定向报文后,可以立即发送连接请求作为响应。

    数据接入地址由主设备提供。


      6.6、逻辑链路标示符

    逻辑链路标示符来判断数据报文属于哪种类型:

    链路层控制报文(11) — 用于管理连接

    高层报文开始(10) — 也可用于一个完整报文

    高层报文延续(01)

    如果数据包为链路层控制报文,那么逻辑链路标示符为11,并被直接交给链路层控制实体。所有其他的数据包都要经过主机——要么来自主机,要么发给主机。主机可以发送大于27个字节的数据,但是无法放入单个链路层的数据包,因此必须支持分段;具体做法是给数据包贴上"高层报文开始"、"高层报文延续"LLID



    七、逻辑链路控制和适配协议(logic link control and adaptation protocol )

    L2CAP是个复用层,可以让低功耗蓝牙复用三条不同的通道,它也支持数据的分割和重组功能。经典蓝牙L2CAP层更复杂。

    低功耗蓝牙的基本概念在于无连接模式,用户只有在需要发送数据时才建立链接。L2CAP只支持固定的信道,信道是指一个数据包序列连接两个设备上的一对服务,两个设备可以同时开启多个信道。


    低功耗L2CAP层使用了三条信道:信道标识符0x0004用于属性协议,0x0005用于低功耗蓝牙信令信道,0x0006用于安全管理。0x0007~0x003E为保留,0x0040~0xffff 用于面向连接。



    数据包的操作码如下:命令拒绝(command reject)、连接参数更新请求(connetciton parameter updata request)、连接参数更新响应(connection paramerter updata reponse).

    标识符用于匹配请求和响应,如果请求的标识符为0x35,则响应该请求的数据包标识符也必须使用0x35.每个请求有不同的标识符,多个请求便能同时发送。


    八、属性

       低功耗蓝牙的三种协议:逻辑链路控制与适配协议(L2CAP)、安全管理协议(SM)、属性协议(AP).属性就是带标签的数据。





    展开全文
  • 低功耗蓝牙(学习笔记)

    千次阅读 2016-12-11 00:41:28
    最近在搞低功耗蓝牙,对所学知识的一个整理
    清单文件写入蓝牙低功耗蓝牙权限:
    <uses-feature
            android:name="android.hardware.bluetooth_le"
            android:required="true" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     
    ***************************************************************************************************************************
     
     获取蓝牙实例:
     BluetoothManager mBluetoothManager= (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);  //开启使用蓝牙服务
     BluetoothAdapter mBluetoothAdapter= mBluetoothManager.getAdapter();   //获取蓝牙适配器
     
     
    ***************************************************************************************************************************
     
     扫描连接蓝牙需要通过蓝牙适配器
     
     扫描蓝牙:
     mBluetoothAdapter.startLeScan(mLeScanCallback); // 开启扫描开关
     mBluetoothAdapter.stopLeScan(mLeScanCallback);   //关闭
     
     当开启扫描后,需等待一段时间扫描附近设备,此时扫描到了则调用扫描回调方法:
     /* 扫描回调5.0以前 */
        private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {     //返回device中存储name和mac
                runOnUiThread(new Runnable() {
                    public void run() {
                            mBLEDeviceList = device;      //将扫描到的设备信息传出方法,mBLEDeviceList和device同一类型
                    }
                });
            }
        };
        

    ***************************************************************************************************************************
        
    连接蓝牙:
    mBluetoothAdapter.stopLeScan(mLeScanCallback);   //关闭蓝牙扫描
    mBLE.connect(mBLEDeviceList.getAddress());    //传入蓝牙mac以连接到蓝牙


    ***************************************************************************************************************************

    此时需要了解客户端和硬件数据交互规则:
    客户端发送有效指令----->设备接收处理指令
    设备根据指令反馈数据----->客户端接收数据转码

    ***************************************************************************************************************************

    此时需要了解操作低功耗蓝牙的规则:
    GATT服务,全称BluetoothGattService(蓝牙Gatt协定服务),当通过mac连接到ble后还不能与硬件数据交互,由GATT服务管理着硬件数据交互
    特征值,全程BluetoothGattCharacteristic(蓝牙Gatt协定的特点),特征值就是蓝牙提供给外设进行数据交互的接口.通过写特征值,
    就可以把数据传给对方,通过读特征值就能读到对方的数据

    gatt下可有多个特征值

    获取GATT服务和特征值需通过调用方法传入UUID获取,UUID即通用唯一识别码,用于确保唯一性
    UUID_SERVICE = "0000fff0-0000-1000-8000-00805f9b34fb";  //gatt服务
    UUID_CHAR6 = "0000fff6-0000-1000-8000-00805f9b34fb";    //数据描述符
    获取gatt:BluetoothGattService gatt.getService(UUID.fromString(UUID_SERVICE));
    获取数据描述符:BluetoothGattCharacteristic gattCharacteristic_char6 = mService.getCharacteristic(UUID.fromString(UUID_CHAR6));

    ***************************************************************************************************************************
    发送数据:
    向设备发送数据前需要打开蓝牙设备可写入开关(操控获得的数据描述符)

    此方法当识别到连接蓝牙后立即回调
    需提前在oncreate中加载:
    BluetoothLeClass mBLE = new BluetoothLeClass(this);
    mBLE.setOnServiceDiscoverListener(mOnServiceDiscover);

    private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new OnServiceDiscoverListener() {
            public void onServiceDiscover(BluetoothGatt gatt) {
                mService = gatt.getService(UUID.fromString(UUID_SERVICE));
                gattCharacteristic_char6 = mService.getCharacteristic(UUID.fromString(UUID_CHAR6));
                mBLE.setCharacteristicNotification(gattCharacteristic_char6, true);     //传入数据描述符以打开设备可写
            }
        };
        
    ***************************************************************************************************************************
        
    此时设置设备可通知后可向硬件写入数据:
    gattCharacteristic_char6.setValue(HexStrConvertUtil.hexStringToByte(writeStr));
    mBLE.getmBluetoothGatt().writeCharacteristic(gattCharacteristic_char6); // 写入给硬件

    ***************************************************************************************************************************

    设备反馈:
    设备接收到写入指令后

    /* Ble硬件可以数据交互,则调用此回调 */ // 有个前提得检测到蓝牙
        private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new OnDataAvailableListener() {
            /**
             * BLE终端数据被读的事件,硬件读取数据
             */
            public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            }
            
            /* 收到BLE终端写入数据回调,硬件传回数据 */
            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                if (characteristic.getUuid().toString().equals(UUID_CHAR6)) { // characteristic.getUUID()来判断是谁发送值给你
                }
                
            byte[] readBuff = characteristic.getValue(); // 取得硬件传回的值
            
            };
            
    ***************************************************************************************************************************
    附:创建gatt中央类  BluetoothLeClass mBLE

    public class BluetoothLeClass {
        public static final String TAG = MainActivity.TAG;// BluetoothLeClass.class.getSimpleName();
        /*引用的是主布局文件的java代码*/

        public static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID
                .fromString("00002902-0000-1000-8000-00805f9b34fb");  //通用识别码,硬件唯一
        private BluetoothManager mBluetoothManager;   //蓝牙服务
        private BluetoothAdapter mBluetoothAdapter;   //蓝牙实例
        private String mBluetoothDeviceAddress;      //mac
        private BluetoothGatt mBluetoothGatt;      //蓝牙连接协议实例

        public interface OnConnectListener {     //当连接时
            public void onConnect(BluetoothGatt gatt);
        }

        public interface OnDisconnectListener {     //当断开连接时
            public void onDisconnect(BluetoothGatt gatt);
        }

        public interface OnServiceDiscoverListener {   //发现gatt服务
            public void onServiceDiscover(BluetoothGatt gatt);
        }

        public interface OnDataAvailableListener {   //数据监听器   
            public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status);   //读

            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic);   //写
        }

        private OnConnectListener mOnConnectListener;
        private OnDisconnectListener mOnDisconnectListener;
        private OnServiceDiscoverListener mOnServiceDiscoverListener;
        private OnDataAvailableListener mOnDataAvailableListener;
        private Context mContext;

        public void setOnConnectListener(OnConnectListener l) {
            mOnConnectListener = l;
        }

        public void setOnDisconnectListener(OnDisconnectListener l) {
            mOnDisconnectListener = l;
        }

        public void setOnServiceDiscoverListener(OnServiceDiscoverListener l) {
            mOnServiceDiscoverListener = l;
        }

        public void setOnDataAvailableListener(OnDataAvailableListener l) {
            mOnDataAvailableListener = l;
        }

        public BluetoothLeClass(Context c) {
            mContext = c;
        }

        /**
         * 实现回调方法,因为程序需要用到的GATT事件 例如,连接更改和发现服务等会触发到的方法
         *
         * Implements callback methods for GATT events that the app cares about. For
         * example,connection change and services discovered.
         */
        private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
            /**
             * 当调用了连接函数 mBluetoothGatt = bluetoothDevice.connectGatt(this.context,
             * false, gattCallback);或者connect()之后, 如果连接成功就会 走到 连接状态回调
             */
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    if (mOnConnectListener != null)
                        mOnConnectListener.onConnect(gatt);
                    Log.i(TAG, "Connected to GATT server.");
                    // Attempts to discover services after successful connection.
                    Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());

                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    if (mOnDisconnectListener != null)
                        mOnDisconnectListener.onDisconnect(gatt);
                    Log.i(TAG, "Disconnected from GATT server.");
                }
            }
            /*个人心得:只要开始连接,就会进入这个回调*/

            /**
             * 当判断到连接成功之后,会去寻找服务, 这个过程是异步的,会耗点时间。 当discoverServices()寻找到服务之后,会走到回调:
             */
            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                if (status == BluetoothGatt.GATT_SUCCESS && mOnServiceDiscoverListener != null) {
                    mOnServiceDiscoverListener.onServiceDiscover(gatt);
                } else {
                    Log.i(TAG, "onServicesDiscovered received: " + status);
                }
            }
            /*个人心得:当连接成功,开始寻找服务,就会进入这个回调*/

            /**
             *
             * 如果mBluetoothGatt.readCharacteristic() 读取数据(或者读取其他值)成功之后 ,会来到 回调:
             *
             */
            @Override
            public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                if (mOnDataAvailableListener != null)
                    mOnDataAvailableListener.onCharacteristicRead(gatt, characteristic, status);
            }

            /**
             * Notify(通知) notify 就是让设备 可以发送通知给你,也可以说上报值给你(发送命令给你)
             * 一旦设备那边notify数据给你,你会在回调里收到:
             */
            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                if (mOnDataAvailableListener != null)
                    mOnDataAvailableListener.onCharacteristicWrite(gatt, characteristic);
            }
        };

        /**
         * 初始化一个参考本地蓝牙适配器 Initializes a reference to the local Bluetooth adapter.
         *
         * 如果初始化成功,返回true
         */
        public boolean initialize() {
            // Use this check to determine whether BLE is supported on the device.
            // Then you can
            // selectively disable BLE-related features.
            if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
                Log.i(TAG, "Unable to initialize Bluetooth,do not has BLE system");
                return false;
            } else {
                Log.i(TAG, "initialize Bluetooth, has BLE system");
            }
            // For API level 18 and above, get a reference to BluetoothAdapter
            // through
            // BluetoothManager.
            if (mBluetoothManager == null) {
                mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
                if (mBluetoothManager == null) {
                    Log.i(TAG, "Unable to initialize BluetoothManager.");
                    return false;
                }
            }

            mBluetoothAdapter = mBluetoothManager.getAdapter();
            if (mBluetoothAdapter == null) {
                Log.i(TAG, "Unable to obtain a BluetoothAdapter.");
                return false;
            }

            // 直接启动蓝牙
            boolean isEnableBTA = mBluetoothAdapter.enable();
            if (isEnableBTA) {
                Log.i(TAG, "mBluetoothAdapter.enable");
            } else {
                Log.i(TAG, "mBluetoothAdapter.disable");
            }

            return isEnableBTA;
        }

        /**
         * 连接托管在蓝牙LE设备的GATT服务 Connects to the GATT server hosted on the Bluetooth LE
         * device.
         *
         * @param address
         *            目标设备地址 The device address of the destination device.
         *
         * @return 若已连接过的会调用connect(),若未连接过的会调用connectGatt(),如果连接成功,则返回真。
         *         连接结果会异步通过回调{ @代码bluetoothgattcallback #
         */
        public boolean connect(final String address) {   
            if (mBluetoothAdapter == null || address == null) {
                Log.i(TAG, "BluetoothAdapter not initialized or unspecified address.");
                return false;
            }

            // Previously connected device. Try to reconnect.
            if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
                Log.i(TAG, "Trying to use an existing mBluetoothGatt for connection.");
                if (mBluetoothGatt.connect()) {
                    return true;
                } else {
                    return false;
                }
            }

            final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
            if (device == null) {
                Log.i(TAG, "Device not found.  Unable to connect.");
                return false;
            }
            // We want to directly connect to the device, so we are setting the
            // autoConnect
            // parameter to false.
            mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
            Log.i(TAG, "Trying to create a new connection.");
            mBluetoothDeviceAddress = address;
            return true;
        }

        /**
         * 断开现有连接或取消挂起的连接。 这个断开的结果会异步通过报告回调 { @代码bluetoothgattcallback #
         */
        public void disconnect() {
            if (mBluetoothAdapter == null || mBluetoothGatt == null) {
                Log.i(TAG, "BluetoothAdapter not initialized");
                return;
            }
            mBluetoothGatt.disconnect();
        }

        /**
         * 使用一个给定的BLE设备后,应用程序必须调用这个方法来确定资源释放。
         */
        public void close() {
            if (mBluetoothGatt == null) {
                return;
            }
            mBluetoothGatt.close();
            mBluetoothGatt = null;
        }

        /**
         * 要求在一个读给定的{ @代码bluetoothgattcharacteristic}。 读结果是通过异步报告回调
         * { @代码bluetoothgattcallback # oncharacteristicread
         */
        public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
            if (mBluetoothAdapter == null || mBluetoothGatt == null) {
                Log.i(TAG, "BluetoothAdapter not initialized");
                return;
            }
            mBluetoothGatt.readCharacteristic(characteristic);
        }

        /**
         * 打开或关闭设备的通知功能: 参数 enable 就是打开还是关闭,
         * characteristic就是你想设置BluetoothGattCharacteristic里的Descriptor,
         * 让characteristic具有通知功能。
         */
        public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
            if (mBluetoothAdapter == null || mBluetoothGatt == null) {
                Log.i(TAG, "BluetoothAdapter not initialized");
                return;
            }
            if (enabled == true) {
                Log.i(TAG, "Enable Notification");
                mBluetoothGatt.setCharacteristicNotification(characteristic, true);   //启用通知
                BluetoothGattDescriptor descriptor = characteristic
                        .getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mBluetoothGatt.writeDescriptor(descriptor);
            } else {
                Log.i(TAG, "Disable Notification");
                mBluetoothGatt.setCharacteristicNotification(characteristic, false);
                BluetoothGattDescriptor descriptor = characteristic
                        .getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
                descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
                mBluetoothGatt.writeDescriptor(descriptor);
            }
        }

        public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
            mBluetoothGatt.writeCharacteristic(characteristic);
        }

        /**
         * 获得在该已连接的设备的GATT服务列表 这些服务都是在调用{@code BluetoothGatt#discoverServices()}
         * 后成功的发现的服务。
         */
        public List<BluetoothGattService> getSupportedGattServices() {
            if (mBluetoothGatt == null)
                return null;

            return mBluetoothGatt.getServices();
        }

        public BluetoothAdapter getmBluetoothAdapter() {
            return mBluetoothAdapter;
        }

        public void setmBluetoothAdapter(BluetoothAdapter mBluetoothAdapter) {
            this.mBluetoothAdapter = mBluetoothAdapter;
        }

        public BluetoothGatt getmBluetoothGatt() {
            return mBluetoothGatt;
        }

        public void setmBluetoothGatt(BluetoothGatt mBluetoothGatt) {
            this.mBluetoothGatt = mBluetoothGatt;
        }
        
    }
    展开全文
  • 蓝牙组织规定了一些标准的profile,例如 HID OVER GATT ,防丢器 ,心率计等。 每个profile中会包含多个service,每个service代表从机的一种能力。 2、service service可以理解为一个服务,在ble从机中,通过有多...

    1、profile
    profile可以理解为一种规范,一个标准的通信协议,它存在于从机中。
    蓝牙组织规定了一些标准的profile,例如 HID OVER GATT ,防丢器 ,心率计等。
    每个profile中会包含多个service,每个service代表从机的一种能力。


    2、service
    service可以理解为一个服务,在ble从机中,通过有多个服务,
    例如电量信息服务、系统信息服务等,每个service中又包含多个characteristic特征值。
    每个具体的characteristic特征值才是ble通信的主题。比如当前的电量是80%,
    所以会通过电量的characteristic特征值存在从机的profile里,
    这样主机就可以通过这个characteristic来读取80%这个数据。

    3、characteristic
    characteristic特征值,ble主从机的通信均是通过characteristic来实现,
    可以理解为一个标签,通过这个标签可以获取或者写入想要的内容。

    4、UUID
    UUID,统一识别码,我们刚才提到的service和characteristic,都需要一个唯一的uuid来标识


    现在低功耗蓝牙(BLE)连接都是建立在 GATT (Generic Attribute Profile) 协议之上。
    GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,
    这些很短的数据段被称为属性(Attribute)。

    在BLE协议中,广播通信主要有两类使用场景:
    1)单一方向的、无连接的数据通信,数据发送者在广播信道上广播数据,数据接收者扫描、接收数据。
    2)连接的建立。

    Advertising,数据发送方,周期性的发送广播数据;
    Scanning,数据接收方,扫描、接收广播数据;
    Initiating,连接发起方,扫描带有“可连接”标志的广播数据,一旦发现,则发起连接请求(都是由Link Layer自动完成,不需要Host软件参与)。

    对BLE广播通信来说,Advertising的周期是一个比较重要的参数,因为它关系到系统的功耗和通信的效率,因此需要根据使用场景,小心设定。

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


    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的顺序,收发数据,直至连接断开。


    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。

    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不同是,这是一个协商的过程,不是一定能够成功。

    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。

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

    所谓的白名单,就是一组蓝牙地址;
    通过白名单,可以只允许特定的蓝牙设备(白名单中列出的)扫描(Scan)、连接(connect)我们,也可以只扫描、连接特定的蓝牙设备(白名单中列出的)。

    总结来说,LL Privacy机制是白名单(white list)机制的进阶和加强,它在白名单的基础上,将设备地址转变成Private addresses[2]地址,以降低“小人E“窃得设备地址进而进行伪装的概率。

    通过Resolvable Private Addresses,将在空中传输的设备地址加密,让“小人E”无法窃得,从而增加其伪装的难度。

    从字面理解,Encryption是一个名词,意思是“加密术”,因此LE Encryption就是“BLE所使用的加密技术”的意思。
    数据发送方在需要发送数据的时候,按照一定的加密算法,将数据加密;
    数据接收方在接收到数据的时候,按照等同的解密算法,将数据解密。

    展开全文
  • [BLE]低功耗蓝牙介绍

    万次阅读 2016-11-12 22:53:05
    一、BLE的协议栈框架  BLE协议栈包括两个部分,主机(Host)和控制器(Controller)。二者通过HCI(Host Controller Interface)标准接口相互通信。常用的单芯片单模BLE芯片有TI的CC254X、CC26xx,nordic的NRF51288,...

    一、BLE的协议栈框架

            BLE协议栈包括两个部分,主机(Host)和控制器(Controller)。二者通过HCI(Host Controller Interface)标准接口相互通信。常用的单芯片单模BLE芯片有TI的CC254X、CC26xx,nordic的NRF51288,dailog的DA14580等等,双芯片的双模BT有TI的CC2564。


          NRF52832吊炸天啊~~~~~  

          协议栈整体结构图如下:


            主机是一个逻辑实体,定义包括应用层以下,HCI以上的配置文件(Profile)、通用访问协议(GAP)、通用属性协议(GATT)、属性协议(ATT)、安全管理协议(SMP)、逻辑链路控制适配层(L2CAP)、HCI驱动各层。控制器也是一个逻辑实体,定义HCI层以下的HCI固件、链路层(LL),物理层(PHY)各层。


    三、协议栈各层介绍

    1、物理层规范(PHY)

            射频方面,BLE工作在免费的2.4GHz ISM(Industrial Scientific Medical)频段,其频带是2400 -2483.5MHz,BLE的调制方式是高斯频移键控(GFSK),BT=0.5,而标准蓝牙技术是0.35,0.5的指数接近高斯最小频移键控(GMSK)方案,可以降低无线设备的功耗要求(这方面的原因比较复杂)。更低调制指数还有两个好处,即提高覆盖范围和增强鲁棒性;二进制“1”和“0”分表表示正频偏和负频偏,在使用频谱仪(N9020A)测试频偏时需要提前知道其背离频率;发射功率范围在-20dBm~+10dBm之间(天线增益为0dBi情况下);误比特率为0.1%的情况下,接收灵敏度小于-70dBm;通信距离可到达100m;传输速率为1Mbps;数据包间对中心频率的偏移应当小于±150kHz,其中包括了初始的频率补偿和频率漂移;在一个数据包内,频率偏移应当小于150kHz,最大的频率偏移率不能超过400Hz/us,一般要求在±20PPM以内即可。

            相对于传统蓝牙而言,传统蓝牙可以增强数据率,可支持2或3Mb/s的总空气比特率。这些模式分别被称为基本速率(BR)和增强数据率(EDR)。定义了两种调制模式。强制模式被称为基本速率,使用一个成型的二进制FM调制从而将收发器的复杂程度降至最低。可选模式被称为增强数据率,使用PSK调制并存在两个变量:π/4-DQPSK和8DPSK。所有调制程序的符号率是1 Ms/s。就总空中传输数据率而言,基本速率为1 Mbps,使用π/4-DQPSK的增强数据率为2 Mbps,而使用8DPSK的增强数据率为3 Mbps。

            信道结构方面,BLE系统采用跳频收发机提供多个跳频序列载波,抵抗干扰和衰减。BLE信道分为广播信道与数据信道,数量分别为3和37。系统提供两种复用方案:频分多址和时分多址。在频分复用方案中,40个信道间的频率间隔为2MHz,中心频率分别为2402+k*2MHZ,其中k是0—39之间的任意整数,k等于0,12,39时信道为广播信道,其他值时为数据信道;在时分复用方案中,两个正在通信的设备,通过轮训的方式在预定好的时间单元中收发数据。数据传输是采样自适应跳频的方式在37个数据传输信道中传输有效数据包,该技术主要是为了防止单一信道堵塞而导致的问题。

        1)为什么选择3个信道作为广播信道?(2.402GHZ、2.426GHZ、2.480GHZ

        在BLE进行广播时,三次传输分别利用了三个不同的频率进行,以提高鲁棒性。选择数字3其实就是为了鲁棒性和低功耗之间求得平衡。在BLE中,如果频率的数量只有一个,那么像其他技术那样只有该频率被阻塞,整个系统将无法工作;如果频率太多,比如16个,该设备将花费大量的时间进行广播数据的传输,将不再是“LE”设备。并且在BLE协议栈实现的代码中,广播数据包的大小也有严格的要求,最大包长度不能超过31,这就是为了减小在单次传输过程中实现LE的结果,所以广播数据包尽量短小。

        2)蓝牙设备寻址

        蓝牙设备获分配一个独一无二的48位蓝牙设备地址(BD_ADDR),这个地址来自IEEE Registration Authority。

        3)待补充

        。。。。。

    2、链路层规范(LL)

        1)链路层的功能

            链路层使用链路协议来控制网络中设备的状态,并且提供管理下层的服务。低功耗蓝牙设备有五个工作状态,分别是:待机状态、广播状态、扫描状态、初始化状态、和连接状态。链路层控制器一个时刻内只允许设备处于上述5个状态之一。

            待机状态:默认状态,不能发送接收任何数据包,任何其他状态都可以直接进入待机状态。

            广播状态:广播状态可由待机状态切换进入,设备在3个广播信道发送广播数据包,同时在当前信道监听和回复扫描者可能发送的扫描数据包。处于广播状态下的设备称为广播者。

            扫描状态:扫描状态可由待机状态切换进入,设备在3个广播信道监听远程设备发出的广播数据包,同时发送扫描数据包,等待广播者的扫描回复信号。处于扫描状态下的设备称为扫描者。

            初始化状态:初始化状态可由待机状态切换进入,设备在广播信道监听回复远程设备的广播数据包,从而发起设备之间的连接。处于初始化状态下的设备称为发起者。

            连接状态:连接状态可以从初始化状态和广播状态进入,此时发起者作为主设备,确定传输时隙,广播者作为从设备,双方在数据信道以跳频的方式进行数据传输。

    2)链路层数据包结构

            无论是广播信道或者数据信道,链路层仅仅只有一种数据包结构,格式如下所示。

    前导码             

    (1字节)   [LSB]

    接入地址

    (4 字节)

    协议数据单元

    (2~39 字节)

    循环冗余码校验

    (3 字节)

            数据包由前导码,接入地址,协议数据单元和循环冗余码校验四部分组成。由于低功耗蓝牙采用短包技术,数据包的长度范围为80位~376位,可以较大程度降低功耗。下面将对各部分进行详细说明。

            前导码:前导码共有1个字节,用于接收机执行频率同步、符号定时判断和自动增益控制。广播信道数据包的前导码固定为10101010b;数据信道数据包根据接入地址首位的不同而不同,若接入地址首位为1,则前导码为01010101b,反之为10101010b。

            接入地址:所有广播信道数据包的接入地址都为0x8E89BED6;数据信道中接入地址是在初始化状态下产生,来自连接请求数据包接收到的24位随机数,这个随机数应该确保满足以下条件:

    1)       不能超过连续6个1或者0;

    2)       不能和广播信道数据包的接入地址一样;

    3)       必须2位及以上不同于广播信道数据包接入地址;

    4)       不能有相同的4字节;

    5)       不能超过24个转折点;

    6)       在6位最高位中,至少要有2个转折点。

            协议数据单元:大小为2字节~39字节,根据不同数据包类型而不同。

    3)广播信道协议数据单元:由包头和有效荷载2部分组成。具体格式如下表所示。

    包头(16位)

    有效荷载 

    PDU类型

    RFU

    TxAdd

    RxAdd

    Length

    RFU

    (由包头中的长度位标志)

        其中PDU类型如下表所示。

    PDU 类型

    数据包名称

    0000

    ADV_IND

    0001

    ADV_DIRECT_IND

    0010

    ADV_NONCONN_IND

    0011

    SCAN_REQ

    0100

    SCAN_RSP

    0101

    CONNECT_REQ

    0110

    ADV_SCAN_IND

    0111-1111

    Reserved

    4)数据信道协议数据单元:由包头、有效荷载和可选的信息完整性检查(MIC)组成,格式如表2‑5所示。信息完整性检查在没有加密的链路连接,或者加密了但数据协议数据单元长度为0的情况下使用。LL DataPDU 是用来发送L2CAP数据,而LL Control PDU是用来控制连接链路的。

            数据信道协议数据单元格式如下表所示

    包头(16位)

    有效荷载 

    信息

    完整性检

    (32 位)

    LLID

    NESN

    SN

    MD

    RFU

    Length

    RFU

    LL DATA PDU

    LL Control PDU

            CRC:3字节的CRC是根据PDU计算的。如果PDU已加密,则CRC根据加密后的PDU计算。CRC多项式的形式自行百度。对于任一个广播信道PDU,移位寄存器应该预设为0x555555;对于每一个数据信道PDU,移位寄存器的预设值在连接状态时,从连接请求PDU中得出。

    3、HCI规范

            HCI是连接主机和控制器的桥梁,提供主机访问下层协议、硬件和控制寄存器的统一接口。HCI实际为三部分:HCI 固件、HCI驱动和实际物理接口。

            HCI固件:HCI固件位于蓝牙控制器中,固件主要内容有:中断向量表、堆栈设计、初始化程序和蓝牙处理程序。HCI固件通过访问控制硬件状态寄存器、控制寄存器、事件寄存器、基带命令和链路管理命令执行HCI命令。蓝牙系统的MCU在蓝牙处理程序控制下,会读取来自上层协议栈的命令,然后根据命令配置基带层的相应寄存器。反之基带层接收到信息后反馈给MCU,MCU通过HCI物理接口递交这些信息至上层协议栈,上层协议栈根据这些信息,再产生新的命令进行处理。

            HCI驱动:HCI驱动位于蓝牙主机中,也就是协议结构中HCI软件驱动部分。当某个事件触发时,控制器通过事件方式通知主机,主机则接收该事件的异步通知。当主机发现有事件发生时,它将分析收到的事件包并判断事件类型,做出相应的处理。

            实际物理接口:作为HCI接口的实际物理实体,位于HCI固件和HCI驱动的中间层,提供可靠的数据传输。蓝牙控制器与主机可以使用不同的数据传输方式进行通信。不同通信方式的数据格式在实际硬件接口均具有特定的封装格式,但是经过HCI层的封装统一,不同类别的通信方式并不会造成主机接收到的HCI事件异步通知无法相互识别的情况。常用的物理接口有USB、UART和RS232三种。下图表示UART作为HCI接口时,主机与控制器的连接图。


    4、其他上层协议规范

    1)逻辑链路控制适配层(L2CAP)规范

            逻辑链路控制适配层位于主机中,采用了协议复用和数据包分段重组技术,负责向高层协议栈提供面向连接的数据服务。它允许高层协议收发数据长度为64K字节。

            协议复用技术:因为基带不能够识别全部高层协议的类型标志,所以位于基带上层的逻辑链路控制适配层必须支持识别不同的高层协议。

            分段和重组:由于基带定义的空中数据包大小被限定在一定的范围,所以来自上层的较大数据到达逻辑链路控制适配层后,必须进行重新封包成多个小型基带数据包,以适应空中传输规则。相反的,当基带接收到空中包传输到逻辑链路控制适配层后,需要将数据包重组成一个较大的逻辑链路控制适配层数据包,再传输到上层协议。

    2)通用访问协议(GAP)规范

            通用访问协议规范表示蓝牙设备基本功能,包括工作模式和访问过程。低功耗蓝牙的工作模式有四种,广播、扫描、周边外设和中心主设备。在指定时间,设备只能处于四种模式之一。访问模式包括设备发现、连接模式、认证、服务发现等。

    3)属性协议(ATT)规范

            属性协议规范将连接中的设备区分成两种角色,即客户机和服务器。客户机与服务器通过固定逻辑链路控制适配层信道通信。客户机发送指令,请求和确认信息至服务器;服务器发送回复,通知和指示至主机。

    4)安全管理协议(SMP)规范

            安全管理协议产生加密密钥和识别密钥,同时也管理密钥的存储,负责产生随机的地址并通过地址识别设备。在数据加密和配对的过程中,安全管理协议将密钥发送至控制器。

    5)通用属性协议(GATT)规范

            通用属性协议用于建立数据传输时常用操作和框架。通用属性协议同属性协议一样分为客户机与服务器两个角色。服务器存储属性协议上传输的数据,并且接收来自属性协议上传的请求、指令和确认信息,处理好请求配置好后,则发送指令和通知至客户机。同时,通用属性协议定义了包含在服务器中的数据,即各式服务、关键词。

    四、总结

            在BLE协议栈的应用开发过程中,整个协议栈一般有各个半导体公司自己开发好,并封装成特定的demo以后供用户使用。整个代码架构遵循二八原则,协议栈抽象成应用底层框架(Framework),半导体公司完成应用开发的80%,剩下的20%则以回调(callback)和接口的方式供应用开发人员调用以实现具体的功能。

            BLE的出现是为了实现连接后的数据通信和控制,其初衷是为了完成较少量的数据通信,侧重于通信控制。所以我们可以理解BLE的协议栈包括两大组成部分:一个是BLE连接;另一个是BLE数据传输。前者即对应GAP(General Access Profile),后者对应GATT(General Attribute Profile)。Profile在蓝牙术语里面对应于特定的应用协议规范(可以自己安装标准规范编写实现特定功能的Profile)。

            Framework应该完成应用开发的80%工作,剩下20%则是由各个具体应用的具体场景需求来决定的。例如,蓝牙底层连接时怎么握手,应用开发人员不需要关心吧;GATT的characteristics value值的通信过程,不要关心吧。当蓝牙外设有新的数据要传输给主设备时,只需要调用notify或者indicate接口就可以了,至于底层怎么实现,那是协议栈开发人员的工作!

            上述仅仅是做一个简要的概括,关于BLE协议栈实现过程中的很多细节问题都没有涉及到,很多东西都需要研究具体的协议栈代码,关于PDU、MTU、payload以及数据传输耗时、连接间隔、从机延时、IOS端的限制等等会单独写一篇博客。

    参考:1)蓝牙技术联盟官网

                2)Bluetooth开发者门户


    展开全文
  • 低功耗蓝牙设计的一点总结

    千次阅读 2020-07-04 11:41:17
    参考: 1.说说低功耗的那些事儿
  • 初识低功耗蓝牙

    2018-11-29 13:51:20
    初识低功耗蓝牙 Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)的核心功能并提供了相应的 API, 应用程序通过这些 API 扫描蓝牙设备、查询 services、读写设备的 characteristics...
  • 作者:feasycom ...蓝牙作为一种近距离通信技术,目前已大量应用于各种移动终端,物联网,健康医疗,智能家居等行业,而蓝牙模块由于集成了蓝牙协议栈,射频部分和天线,因此也受到广大设备厂家青睐,...
  • 经典蓝牙与低功耗蓝牙的区别

    万次阅读 2018-08-31 10:55:14
    Android中的蓝牙开发 要说到蓝牙,小伙伴们听到的可能有蓝牙1.0、蓝牙2.0...这里提到的低功耗蓝牙也会有很多人会误解为就是蓝牙4.0,但是完整的蓝牙4.0规范中实际上包括有经典蓝牙和低功耗蓝牙这两个部分,小伙伴们...
  • 什么是低功耗蓝牙技术

    千次阅读 2020-02-11 19:10:16
    什么是低功耗蓝牙技术 低功耗蓝牙是一种全新的技术,是当前可以用来设计和使用的功耗最低的无线技术。 经典蓝牙的设计目的在于统一全球各地的计算和通信设备,让手机与笔记本电脑相互连接。不过事实证明,蓝牙最为...
  • 4.0低功耗蓝牙解决方案

    万次阅读 2012-08-22 14:09:04
    4.0低功耗蓝牙解决方案  1.物品防丢  2.健康监测  3.家居测控  4.人机交互  5.工业数据交换  6.家电遥控  7.玩具遥控 蓝牙模块应用: 4.0低功耗蓝牙解决方案 蓝牙汽车DVD模块 蓝牙车载免提模块 蓝牙...
  • 蓝牙低功耗BLE】引言

    千次阅读 2014-10-23 21:06:09
    1、【蓝牙低功耗BLE】控制GPIO来点亮LED 2、【蓝牙低功耗BLE】按键的使用 3、【蓝牙低功耗BLE】GPIO外部中断 4、【蓝牙低功耗BLE】定时器T1之查询方式 5、【蓝牙低功耗BLE】定时器T3之中断方式 6、【蓝牙低功耗BLE】...
  • 最近在做蓝牙开发,刚接触时傻傻的分不清经典蓝牙和低功耗蓝牙的区别,一直用开发低功耗蓝牙的方法去连接经典蓝牙设备,最后当然是一直连接不上了。在此记录下经典蓝牙和低功耗蓝牙的区别和联系。 Android中的蓝牙 ...
  • 关于经典蓝牙和低功耗蓝牙的区别

    万次阅读 2017-08-10 09:22:04
    刚开发蓝牙的小伙伴在开发的时候,或许会看到经典蓝牙和低功耗蓝牙这两种,不知道它们之间的区别与联系,今天给大家介绍一下经典蓝牙和低功耗蓝牙(BLE)的区别。 文章转载自: ...
  • 最开始不知道,看的是传统蓝牙的连接与传输,几天过后,发现与低功耗蓝牙不一样啊,又针对低功耗蓝牙开始找资料。低功耗蓝牙支持的api最低是18。基本思路:低功耗蓝牙连接分两种,一种是作为周边设备,一种是作为...
  • 实现蓝牙4.0低功耗的几点方法

    千次阅读 2015-05-09 20:26:15
    对于蓝牙低功耗,一般的做法都是通过配置进入睡眠模式去减低功耗,很少考虑在工作时如何降低功耗; 其实低功耗主要体现在连接方面,建立连接时间越长,功耗越高。蓝牙4.0在3ms就可以建立一次连接,而传统蓝牙却要几...
  • 一般将蓝牙3.0之前的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的LE蓝牙称为低功耗蓝牙。 蓝牙4.0标准包括传统蓝牙模块部分和低功耗蓝牙模块部分,是一个双模标准。低功耗蓝牙也是建立在传统蓝牙基础之上发展...
  • 低功耗板子测试功耗的方法

    千次阅读 2016-09-06 15:56:46
    蓝牙、wifi、ZigBee等低功耗组网通信和智能电子设备开发过程中,功耗的调试是至关重要的一部分, 怎样简易的测试功耗以方便我们对功耗的调试呢,介绍一种万用表测试整体功耗的方法。 如图: 万用表...
  • 低功耗蓝牙技术连接的那点事

    千次阅读 2016-05-12 16:00:41
    低功耗蓝牙技术(Bluetooth® low energytechnology)是蓝牙经典标准的演进,专注于为设备间提供可靠、高效且低功耗的链路连接。它具有超低的功耗,满足超长的续航能力。2014年年底,蓝牙技术核心规范4.2版本正式...
  • 今天来普及下Ble低功耗蓝牙和蓝牙mesh网络之间的关系! 一、低功耗蓝牙和蓝牙mesh的关系: 蓝牙mesh并非无线通信技术,而是一种网络技术。蓝牙mesh网络依赖于低功耗蓝牙低功耗蓝牙技术是蓝牙m...
  • 蓝牙 4.0 标准包括传统蓝牙部分和低功耗蓝牙模块部分。 1、蓝牙模块 蓝牙模块(Bluetooth module)是指集成蓝牙功能的芯片基本电路集合,用于短距离 2.4G 的无线通讯模块。 对于终端用户来说,蓝牙模块是半成品,...
1 2 3 4 5 ... 20
收藏数 12,824
精华内容 5,129
关键字:

低功耗蓝牙