蓝牙LMP概述
LMP 全称是Link Manager Protocol,我们还是要一张图,说明LMP 在哪里?

他是在HCI 以下,baseband 以上,实现在蓝牙控制器中。
按照协议规范,我们分几个部分来分别介绍LMP
- introduction
- general rules
- device features
- procedure rules
下面我们先来看看 整体的介绍部分:
Introduction
LMP是用来控制和协商两个设备连接行为的协议,涉及的方面包括逻辑传输连接的建立和控制,以及对于物理链路的控制等等,它是两个设备的LMP模块之前的交流,其消息是传输在ACL-C 的逻辑链路上,对于这一点,我们在baseband的概述中已经提过:

这里需要注意的一点是,LMP 是实现在控制器里面,其消息并不会经过HCI 接口传输到HOST 端,其架构如下图:

我们可以看到其是 两个设备的LMP 模块之前的通信。
General rules
2.1 Message Transport
这里描述的就是三个点:
- LMP的消息的交互是传输在ACL-C 逻辑链路上的,他和ACL-U的区别是通过LLID 来区分的。
- ACL-C有更高的优先级,一般控制信号都会有较高的优先级
- LMP消息本身没有携带额外的数据错误检测的信息
2.2 Synchronization
LMP 传输在ACL-C的逻辑链路上面,但这并不能保证传输的时间的以及对方ack的及时性。

2.3Packet Format
LMP 的数据包的格式有两种,一种是7bit的opcode,另外一种是15bit的opcode

我们发现除了opcode,在最低位还有一个TID,他是transtransaction ID,当它是0 的时候,说明这个LMP message是 master 发起的,当它是1的是时候说明是slave 发起的。

上图中是 header的最低位是0,代表是Transaction ID Initiated by master。
2.4Transactions
transaction 就是一次完整的打成某种目的的传输。所有属于同一个transaction 的单次传输的transaction ID 都是想同的。
比如下面:

LMP version exchange 的Transaction ID 都是 Initiated by slave
另外LMP_setup_complete 是一个 独立PDU,它自己形成一个transaction,


上面两个OpCode LMP_setup_complete 的transaction ID 是不同的,他们是独立的PDU
LMP response的timeout 时间是30s
2.5ERROR HANDLING
关于出错处理,每一个错误都分配了一个错误码,常见的错误如下:
- Unknown opcode(0x19)
- Invalid parameters(0x1E)
- PDU is not allowed(0x24)
- PDU not supported(0x1A)
- Transaction Collision / LL Procedure Collision(0x23)
- Different Transaction Collision(0x2A)
2.6GENERAL RESPONSE MESSAGES
general response 在很多的procedure中,被用来对于各种流程的应答消息,如果opcode是7bit,那么应该使用前两种 PDU,如果opcode 是15bit,那么应答的PDU 应该使用后两种。

DEVICE FEATURES
device feature,顾名思义,这里面定义了很多的设备的特性,并且这些特定是可以用特定的LMP message 来获取的。那么这些feature 是如何传输的呢?其实就是定义了一些bit 位来代表相应的feature,当这些位被设置为1的时候,就说明支持该feature,这个我们在程序代码实现中经常见到这样的技巧。
这些feature 定义在两个page 上面,page1 里面使用8个字节,64bit 定义了64个feature,page2用2个字节定义了12个feature,其中包括2个reserved 位。
这里简单列举几个feature:

PROCEDURE RULES
这里包含了很多的基本流程,主要有如下的项目:
Connection control
- Information Requests
- Role Switch
- Modes of Operation
- Logical Transports
我们下面分别看看这几个流程:
4.1Connection control
这里每一个流程都有很多的子流程,这里只简单介绍下Connection establishment和Detach的流程:
下面先看一下Connection establishment的流程图
在经过了page的流程之后,可能的行为是请求时钟的偏移量,LMP的版本,对端支持的feature请求,对端的name请求,以及可能的deteach行为。
之后如果要建立连接的话,paging的设备就会发送LMP_host_connection_req,对端如果同意建立连接就会回复LMP_accepted 否则就是LMP_not_accepted
后续可能走得关于认证和加密的流程,最后是LMP_setup_complete,下面我们来看一个例子:

下面的建立连接的PDU:
下面我们看看detach 的流程:

我们发现关于detach 是没有LMP response 的消息的过来的,从实际的air log 中,也的确没有detach response 回复,对端设置只会简单的ack 该 消息:

下面我们看看 从设备的host 端 去断开对端设备的 LMP 与HCI 的message 流向:

我们发现是 A设备再收到了对端的ACK 之后就会向host 端上传断开完成事件。
关于 验证和加密的部分,会在分析配对的文章中专门讲述。
下面我们我们看看
4.2Information Requests
这一类的message 交互都是 信息请求类型的,具体的有如下几种:
Timing accuracy
- Clock offset
- LMP version
- Supported features
- Name request
这几个流程也是非常的类型,我们也是挑选其中一个来 看一下:
我们看看lmp version 的流程:
其交互流程很简单,发起端发起一个LMP_version_req,对端回应一个LMP_version_res

涉及到的PDU的包如下:

这里我们发现,发起这个LMP version请求的时候,还会携带本端的LMP version,Company ID 以及Sub Version Number,这个Sub Version Number 应该是公司内部的编号了,那这样一来,一个request,一个response,就完成了LMP 相关版本信息的交互。我们看看air log 关于这交互的消息:

response 如下:

这里需要提一点就是LMP 数据包的payload header 里面也是有流控相关的,但是这个流控对于LMP 是不起作用的。其应该是主要针对ACL-U的数据。
这里再简单名字的获取的流程,当没有建立物理link的时候,获取名字和已经建立了link的获取的名字的流程有点区别。我们先下有link的时候 流程:

有link的时候,很简单,直接是在LMP 层进行LMP_name_req的交互,收到对方的应答之后,通过HCI接口上报的到host端,如果是没有link的话,那么是要先建立一个临时的link,其流程见下图:

我们可以看到两个设备经过page 之后,会先进行LMP feature exchange以及extend feature exchange,然后上报到host 端,接下来才进行LMP_name_req 的交互,最后是detach 这个临时的link,
我们看看 air log 中实际的交互情况:

实际情况和上面的流程也是非常的吻合,最后会把这个 临时建立起来的获取名字的link断开。
下面我们看看role switch 相关的
4.3Role switch
关于role switch ,因为我们平常在debug 中会遇到,值得仔细讲一下:
role switch的执行需要符合几个条件:
- 设备要处于active mode
- 加密的流程被终止或者已经关闭
- 在当前的link上面,没有sco数据在传输
- 需要停掉当前link所有的ACL-U 数据流
role switch 从字面含义上来看,非常的简单,就是交互角色,我们知道两个设备连接之后,一开始发起配对的那个设备在建立连接之后就是master,这样一种默认模式不能总是符合应用场景,所以经常在两个设备之后需要交互角色。
role switch 是master 和slave 都可以发起的,我们先看一下,master 发起的角色交换的流程:

LMP 层面的交互很简单,就三个指令。下面我们详细讲一下LMP_switch_req和LMP_slot_offset的 作用。

我们看出 LMP_slot_offset 携带两个关键的信息,一个slot offset,另外一个 蓝牙设备地址。这个地址是当前 slave 地址,也是role switch 之后master的地址。这个slot offset 是干嘛的呢?
这个在specification中原话是“The slot offset shall be the time in microseconds between the start of a master transmission in the current piconet to the start of the next following master transmission in the piconet where the BD_ADDR device (normally the slave) is master at the time that the request is interpreted by the BD_ADDR device.”
其含义就是,当前网络的master的开始传输的时机(时钟上升沿)到交换后的网络master 进行传输的时机(时钟上升沿)的时间间隔,次时间是用ms 来描述的。

从这里,我们能够觉悟出,slot offset 应该都是由当前网络的slave(role switch 之后的master) 来发送,而不管是 哪一端的设备先发起的,下面我们看看slave 端发起的role switch的交互流程:

我们发现,slot offset,的确是由slave端送出,之后才送出 LMP_switch_req,现在我们看看一下LMP_switch_req这个命令:
我们可以设想一下,蓝牙设备之间的交互是要保持时钟同步的,否则就会“失去联系”,那么我们在进行role swtich 之后还是要保持时钟同步才能继续通信,那在什么样的时机进行role switch呢?
我们先看下LMP_switch_req的参数:

我们发现其有一个参数是 switch instant ,这就是 描述 具体在哪一个时间点进行TDD switch。
这个instant 应该是一个未来的时间,如果是过去的时间,那么当接受者受到这个instant的时候,并不会接受这样的参数,会回复 LMP_not_accepted PDU with the error code Instant Passed (0x28)。
当role switch 完成的时候,两个设备都要向各自的host 上报HCI_Role_Change event,如下图:

Modes of Operation
hold mode 很少遇到,这里主要讲一下 sniff mode ,
sniff mode 就是呼吸模式,主要是为了省电而应用的,比如一些蓝牙设备,比如键盘鼠标,当他们在active mode的时候,每一个master to slave slot,设备都要去监听master是否有数据发过来。而当他们不使用的时候,如果还是一直处于active mode 的话,那么这段时间的消耗的电量就浪费了,而进入到sniff mode 可以使得设备进入了类似睡眠的状态,只是定期去监听master 的封包,这样可以节省电量。
我们先看看 进入sniff mode 的流程图:

我们这里主要着眼于LMP层面,当host端有进入sniff mode的命令下来,那么控制器 将向对方发出LMP_sniff_req的请求,对方如果同意,那么回复LMP_accepted。因为这是一个协商的过程,上图只显示了一次协商的过程,其实可能存在有发多次的LMP_sniff_req的情况。现在我们看看 LMP_sniff_req的参数:

Dsniff = Clock_Value (bits 26-1) mod Tsniff
Tsniff 是 sniff interval,就是每次起来监听的时间间隔

Tsniff 就是 相邻的两个sniff anchor point的时间间隔。
sniff attempt 是 每次起来之后 尝试去监听的次数,如果监听了sniff attempt 次数之后发现master 没有发数据过来,那么再次进入到睡眠的状态。
sniff timeout 是 在slave 去监听master 的封包的时候,如果有封包发过来,那么就要继续监听额外的sniff timeout 个master to slave slot。
我们这里说一下Sniff 第一个锚点的计算方法:Dsniff = Clock_Value (bits 26-1) mod Tsniff
这里Dsniff 和Tsniff 是参数已经给出的,那么就是根据上面的公式去反推第一个锚点的clk的值。我们这里举一个例子来说明:

其当前的clk值是Clock[27-0] 0x04301E02 这里的Dsniff 的值是0,
bit27 = 0,我们先看看当前的clk是0x04301E02,那么下一个锚点一定是 大于当前值而小于(0x04301E02+800*2)
我们先看看当前的Clock_Value (bits 26-1) mod Tsniff = (0x04301E02>>1)mod(800) = 737
那么下一个锚点的clk = ((800-737)+ (0x04301E02>>1))*2 = 0x4301E80

那么关于LMP 的概述就先介绍到这里。
蓝牙LMP概述的更多相关文章
- 蓝牙核心技术概述(五):蓝牙协议规范(irOBEX、BNEP、AVDTP、AVCTP)
关键词:蓝牙核心技术协议 irDA BNEP AVDTP AVCTP 作者:xubin341719(欢迎转载,请注明作者,请尊重版权,谢谢! )欢迎指正错误,共同学习.共同进步!! 下载链接:Bl ...
- 蓝牙(CoreBluetooth)-概述
蓝牙(CoreBluetooth)-概述 通过此框架可以让你的Mac和iOS应用程序与外部蓝牙设备通信 外部设备: 就是需要通过iOS App控制器的其他设备: 例如:心率检测仪.数字温控器 蓝牙通讯 ...
- 蓝牙核心技术概述(四):蓝牙协议规范(HCI、L2CAP、SDP、RFOCMM)(转载)
一.主机控制接口协议 HCI 蓝牙主机-主机控模型 蓝牙软件协议栈堆的数据传输过程: 1.蓝牙控制器接口数据分组:指令分组.事件分组.数据分组(1).指令分组 如:Accpet Connection ...
- 蓝牙baseband概述
从蓝牙specispecification中看,基带协议主要分为8个部分来介绍的,分别是概述.物理信道.物理连接.逻辑传输.逻辑连接.封包.比特流的处理.组网行为.这里面会涉及到很多的概念,主要是在概 ...
- Qt 蓝牙部分翻译
这是我第一次尝试翻译技术文档,自己英语太烂,一直不敢尝试,感谢生活,让我勇敢迈出这第一步. 大部分都是直译,如有不妥,还请制导. Qt Bluetooth The Bluetooth API prov ...
- 【Bluetooth|蓝牙开发】二、蓝牙开发入门
个人主页:董哥聊技术 我是董哥,嵌入式领域新星创作者 创作理念:专注分享高质量嵌入式文章,让大家读有所得! [所有文章汇总] 1.蓝牙基础概念 蓝牙,是一种利用低功率无线电,支持设备短距离通信的无线电 ...
- 一、Stream,sink,source,transform
1. 蓝牙核心概述 2.Stream,sink,source,transform 在ADK的blueCore里面,Stream作为一个逻辑结构用来描述一个数据终点(data Endpoint).通常, ...
- 《深入浅出Windows 10通用应用开发》
<深入浅出Windows 10通用应用开发>采用Windows 10的SDK进行重新改版,整合了<深入浅出Windows Phone 8.1应用开发>和<深入解析 ...
- 《深入浅出Windows Phone 8.1 应用开发》基于Runtime框架全新升级版
<深入浅出Windows Phone 8.1 应用开发>使用WP8.1 Runtime框架最新的API重写了上一本<深入浅出Windows Phone 8应用开发>大部分的的内 ...
随机推荐
- 初见jQuery EasyUI
本文通过一个简单的小例子,简述jQuery EasyUI的使用方法,仅供学习分享使用,如有不足之处,还请指正. 什么是jQuery EasyUI ? 引用官网的一句话:jQuery EasyUI fr ...
- (网页)java数组去重总结(转)
转自CSDN: 1.背景 根据不同的业务逻辑,经常会遇到数组中存在多个重复元素的场合,总结了下数组的排序,留个记录. 2.实现方法 总结了四种方法,接下来进行展示 1.方法一 //数组去重方法一 ...
- 关于最新笔记本机型预装win8如何更换为win7的解决办法
关于最新笔记本机型预装win8如何更换为win7的解决办法 目前新出的很多机型出厂自带的都是win8系统,可能有些人用不习惯,想更换为win7系统,但是由于这些机型主板都采用UEFI这种接口(硬盘分区 ...
- JAVA设计模式——代理(静态代理)
定义 为其它的对象提供一种代理,以控制这个对象的访问 使用场景 当不想直接访问某个对象的时候,就可以通过代理 1.不想买午餐,同事帮忙带 2.买车不用去厂里,去4s店 3.去代理点买火车票,不用去车站 ...
- 使用VSTS的Git进行版本控制(四)——在Visual Studio中管理分支
使用VSTS的Git进行版本控制(四)--在Visual Studio中管理分支 可以从web版Team Services Git repo 的Branches视图中管理工作.定制视图来跟踪最关注的分 ...
- 2018-05-11-机器学习环境安装-I7-GTX960M-UBUNTU1804-CUDA90-CUDNN712-TF180-KERAS-GYM-ATARI-BOX2D
layout: post title: 2018-05-11-机器学习环境安装-I7-GTX960M-UBUNTU1804-CUDA90-CUDNN712-TF180-KERAS-GYM-ATARI- ...
- ubuntu16.04如何安装多个版本的CUDA
我的机器是CUDA16.04的,之前装过CUDA10.0,因为一些原因,现在需要安转CUDA9.0. 1.首先https://developer.nvidia.com/cuda-90-download ...
- gcc5.4报错对‘std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()’未定义的引用
我在编译ligra是遇到了这个问题,网上搜了一遍,发现是了原因https://gcc.gnu.org/onlinedocs/libstdc%2B%2B/manual/using_dual_abi.ht ...
- java操作elasticsearch实现query String
1.CommonTersQuery: 指定字段进行模糊查询 //commonTermsQuery @Test public void test35() throws UnknownHostExcept ...
- own address as source address
1222.762730] br0: received packet on nbif0 with own address as source address[ 1222.769697] br0: rec ...