轉自Wowo大神的http://www.wowotech.net/bluetooth/ble_connection.html
1. 前言
了解藍牙的人都知道,在經典藍牙中,保持連接配接(Connection)是一個相當消耗資源(power和帶寬)的過程。特别是當沒有資料傳輸的時候,所消耗的資源完全被浪費了。因而,對很多藍牙裝置來說(特别是功耗敏感的裝置),希望在無數可傳的時候,能夠斷開連接配接。但是,由于跳頻(hopping)以及實體通道(Physical Channel)劃分的緣故,經典藍牙連接配接建立的速度實在難以忍受(要好幾秒)。對那些突發的資料傳輸來說,幾秒鐘的連接配接延遲,簡直是災難。
是以,藍牙SIG制訂BLE規範的時候,充分考慮了這方面的需求,極大的簡化了連接配接的建立過程,使連接配接速度可以達到毫秒級(最快3.75ms就可以搞定)。與此同時,為了節省功耗,也調整了跳頻的政策。至此,相比廣播通信而言,BLE面向連接配接的通信,幾乎沒有額外的代價。
在“藍牙解析(part5)”中,我們對BLE的廣播通信有了比較全面的了解,本文将接着分析和面向連接配接的通信有關的技術,包括連接配接的建立和斷開、BLE跳頻(Hopping)技術、Link Layer的應答、重傳、流控、等等。
2. 怎樣才算是建立了連接配接?
開始之前,我們先回答一個問題,對通信的雙方而言,怎樣才算建立了連接配接呢?
從字面上了解,建立了連接配接,就是指:
二者之間,建立了一條專用的通道,它們可以随時随地的通信。
當然,在藍牙這種資源有限的通信系統中,通道無法獨占,退而求其次,分時也Okay。是以,在BLE中建立了連接配接,是這樣定義的:
在約定的時間段内,雙方都到一個指定的實體Channel上通信。
其中,“約定好的時間段”,是時分的概念。而“到指定的實體Channel上”,是跳頻的概念。後面的分析,将會圍繞這兩個概念進行。
另外,和“藍牙解析(part5)”類似,我們也将從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=01b時,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:
圖檔1 BLE連接配接時序---Master視角
圖檔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)
圖檔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]。