轉自:http://www.05935.com/bc/294540/
連接事件
在一個連接當中,主設備會在每個連接事件里向從設備發送數據包。一個連接事件是指主設備和從設備之間相互發送數據包的過程。連接事件的進行始終位於一個頻率,每個數據包會在上個數據包發完之后等待150μs再發送。
連接間隔決定了主設備與從設備的交互間隔;它是指兩個連續的連接事件開始處的時間距離,可以是7.5ms ~ 4s內的任意值,但必須為1.25ms的整數倍。要確定從設備與主設備的實際交互間隔,需要用到從設備延遲這一參數,代表從設備在必須偵聽之前可以忽略多少個連接事件。
如下圖所示,連接事件被一個個的連接間隔分開。從主設備發送數據包開始,每個連接事件可以持續進行,直至主設備或從設備停止響應。在連接事件之外,主從設備之間不發送任何數據包。
舉個例子,如果連接間隔為100ms,從設備延遲是9,那么從設備可以忽略9個鏈接事件,但不得不偵聽第10個連接事件。換言之,從設備必須每秒偵聽一次,而此時監控超時的最小值應為1010ms。反過來,另一個極端的例子是,如果監控超時使用了32s的最大值,對於間隔為100ms的鏈路,從設備延時必須小於等於319。
雖然如此,如果將從設備延遲設為可行的最大值,在監控超時發生前從設備只能獲得唯一一次偵聽主設備的機會,這可不是一個好主意。因此,建議至少給從設備留出6次偵聽的機會。在前面的例子中,如果連接間隔為100ms,從設備延遲為9,那么監控超時應該至少為6s,這樣一來,鏈路在最終斷開前從設備至少會有6次偵聽的機會。
連接參數介紹
主設備和從設備建立連接之后,所有的數據通信都是在連接事件(ConnectionEvents)中進行的。
尖刺的波就是連接事件(Connectionevents),剩下的Sleeping是睡眠時間,設備在建立連接之后的大多數時間都是處於Sleeping,這種情況下耗電量比較低,而在連接事件(Connectionevents)中,耗電量就相對高很多,這也是BLE為什么省電的原因之一。
每個連接事件(Connectionevents)中,都需要由Master發起包,再由Slave回復。
Master即主機,簡稱M;Slave即從機,簡稱S。抓包過程中看到的M->S或者S->M即主機到從機或者從機到主機。
連接參數 (ConnectionParameters):
通過修改下面三個參數,就可以設置BLE連接過程中的傳輸速度和功耗。
1.ConnectionInterval(連接間隔)
ConnectionInterval(GAPROLE_MIN_CONN_INTERVAL&&GAPROLE_MAX_CONN_INTERVAL)連接間隔,在BLE的兩個設備的連接中使用跳頻機制。兩個設備使用特定的信道發送和接收數據,然后過一段時間后再使用新的信道(BLE協議棧的鏈路層處理信道的切換)。兩個設備在切換信道后發送和接收數據稱為一個連接事件。盡管沒有應用數據被發送和接收,兩個設備仍舊會交換鏈路層數據(空包 EmptyPDU)來維持連接。
這個連接間隔就是指在一個連接事件(Connectionevents)的開始到下一個連接事件(Connectionevents)的開始的時間間隔。連接間隔以1.25ms為單元,連接間隔的范圍是6~3200既7.5ms~4s之間。
2.SlaveLatency(從設備延遲或者從設備時延)
允許Slave(從設備)在沒有數據要發的情況下,跳過一定數目的連接事件(Connectionevents),在這些連接事件(Connectionevents)中不必回復Master(主設備)的包,這樣就能更加省電。
范圍可以是0 ~ 499
更詳細的使用解析如下:
SlaveLatency=OFF也就是SlaveLatency為0時,Master發包,Slave必須回復,如果不回復,Master就會認為Slave那邊接收不正常。
SlaveLatency=ON也就是SlaveLatency不為0的時候,圖中SlaveLatency為3。Master發包,Slave沒有數據要回復的時候,就會忽略3個連接事件,在第4個連接事件接收到Master發送的數據之后,回復Master。如果Slave有數據要發送就會喚醒,也就是說即使SlaveLatency為3,但是在Master發第二包的時候Slave有數據要回復,這個時候就會立即回復Master而不是等到3個連接事件之后的第4個連接事件去回復。
3.SupervisionTimeout(超時時間或者監控超時)
這個參數設定了一個超時時間,如果BLE在這個時間內沒有發生通信的話,就會自動斷開。
單位是10ms,該變量的范圍是10 ~ 3200,折算成時間范圍是100ms ~ 32s。
連接間隔、從機時延以及超時時間這三者必須滿足如下公式:
SupervisionTimeout >(1+slaveLatency)*(connectionInterval)
上述公式必須滿足,否則連接就會不正常斷開。
這三個連接參數不同情況下對通信速率和功耗的影響:
1.ConnectionInterval縮短,Master和Slave通信更加頻繁,提高數據吞吐速度,縮短了數據發送的時間,當然也增加了功耗。
2.ConnectionInterval增長,通信頻率降低,數據吞吐速度降低,增加了數據發送的時間,當然,這種設置降低了功耗。
3.SlaveLatency減少或者設置為0,每次ConnectionEvents中都需要回復Master的包,功耗會上升,數據發送速度會提高。
4.SlaveLatency加長,功耗下降,數據發送速度降低。
連接參數更新規程
連接建立時,主設備通過鏈接請求數據包發送連接參數。當連接活躍了一段時間,連接參數也許不再適用於當前使用的服務。出於提高效率的目的,連接參數需要進行更新。較之首先斷開連接、接着更換新參數重新連接,還有一種在鏈路中更新參數更為簡單的途徑,如下圖所示:
為此,主設備向從設備發送連接更新請求,即LL_CONNECTION_UPDATE_REQ,當中攜帶了新的參數。這些參數不必進行協商,從設備或者接受和使用它們,或者斷開鏈路。連接更新請求中包含了早先創建連接時用過的一部分參數,還有一個稱為瞬時(instant)的新參數:
1.傳輸窗口大小
2.傳輸窗口偏移量
3.連接間隔
4.從設備延遲
5.監控超時
6.瞬時
瞬時參數決定了連接更新的開始時刻。發送消息時,主設備為連接更新選定一個未來的時間點,並且放在消息中。接到消息后,從設備會記住這個未來的時刻,屆時再切換至新的連接參數。這有助於解決無線系統里的一個最大問題----報文重傳。只要數據包的重傳次數足夠,並最終在瞬時之前傳輸成功,上述過程執行起來就不會有問題。但是,如果該數據包屆時沒能完成傳輸,鏈路就有可能丟失。
由於低功耗藍牙沒有時鍾,要決定瞬時時刻只有依靠計算連接事件的個數。因此,每一個連接事件都會被計數,鏈路上的第一個連接事件,也就是在連接請求之后的位於首個傳輸窗口里的連接事件記為0。因此,瞬時實際上是一個連接事件的計數器,相應的連接事件到來時就使用新的參數。為了讓從設備收到數據包,主設備必須為其提供足夠的機會。不過從設備延遲是多少,都應該至少保證 6 次數據發送機會。也就是說,如果從設備延遲為500ms,那么瞬時通常被設定在3s之后的某個未來時刻。
瞬時到來時,從設備開始偵聽發送窗口,就好像連接建立的過程那樣。主設備能夠調整從設備的計時,總體而言不超過1.25ms。不過,由於主設備可能還是一個經典藍牙設備,上述調整使其得以協調低功耗藍牙從設備,從而更好地完成調度。一旦該過程結束,新的連接間隔、監控超時、從設備延遲值將投入使用。
連接參數的修改
“連接參數更新請求”命令可以讓從設備更新鏈路層的連接參數,如下圖所示。這些參數包括連接間隔(從設備希望主設備允許從設備發送數據包的頻率)、從設備延遲(從設備能夠忽略主設備的連接事件的最大值)以及監控超時。
在連接中,如果從設備希望修改當前的連接參數則可以使用該命令。比方說,如果連接事件的間隔有可能太快了,導致過多的電量浪費。這在從設備時延很大時沒有問題,但如果不是這樣,從設備將會頻繁的偵聽鏈路。這在一些情況下是必要的,例如設備間首次綁定、互發多個數據包、探索服務和設備特性等。但在很多其他情況下,盡可能地減少從設備必須偵聽連接事件的數量對提高電池壽命至關重要。
連接參數更新請求命令僅用於從設備向主設備發送,這是由於主設備隨時都能啟動鏈路層連接參數更新控制(ConnectionParameterUpdateControl)規程。如果該命令由主設備發送,從設備會將其視為一個錯誤,並返回帶有“命令不理解”原因代碼的“命令拒絕”命令。
從設備可以在任何時候發送該命令;收到該信息的主設備如果可以修改連接參數,則將返回“連接參數更新響應”(ConnectionParameterUpdateResponse),其中的結果代碼設為“接受(accepted)”。隨后,主設備將會啟動鏈路層連接參數更新控制規程。
當然,如果主設備不同意從設備的請求參數,它可以發送結果代碼為“拒絕(rejected)”的連接參數更新響應命令以拒絕請求。此時從設備有兩個選擇:要么接受主設備希望的正在使用的連接參數,要么終止連接。終止連接的做法咋看起來可能讓人覺得很激進,但是,假如使用當前的參數從設備將會在一周內耗盡電量,而使用請求的參數則可以持續數年,很明顯,合理的選擇只有一個。
修改連接參數時,如果要減少主設備拒絕從設備請求的可能性,可以在請求里設置一個可接受的參數范圍。經過精心設計的從設備會樂意接受很寬的參數范圍。由於主設備可能正忙於實時會話音頻連接或者高質量語音連接等任務,它可以接受一定范圍內的連接間隔參數。設備可接受的間隔參數會根據當前任務的不同而不同,可能有別於上一次設備連接時的參數。
要提高主設備接受連接參數的機率,還有個方法是從設備提供一個合理的從設備延遲。主設備可以選擇最合適的連接事件間隔,從設備則使用最佳功耗的從設備延遲參數。
舉個例子,如果從設備想每600ms同步一次,它可以請求范圍100ms ~ 750ms的連接間隔參數,並帶上從設備延遲5。如果主設備選擇100ms,則從設備每6個連接事件同步一次;如果主設備選擇200ms,則從設備每3個連接事件同步一次,實現其所期望的600ms間隔;如果主設備選擇300ms,則從設備忽略每隔一個連接事件同步一次;如果主設備選擇400ms,則從設備每400ms同步一次。
下面介紹一下在TI的CC2540和CC2541中,連接參數修改的API。
1.修改單個連接參數的方法
修改最小連接間隔
uint16 desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;GAPRole_SetParameter( GAPROLE_MIN_CONN_INTERVAL, sizeof( uint16 ), &desired_min_interval );
修改最大連接間隔
uint16 desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;GAPRole_SetParameter( GAPROLE_MAX_CONN_INTERVAL, sizeof( uint16 ), &desired_max_interval );
修改從設備延遲
uint16 desired_slave_latency = DEFAULT_DESIRED_SLAVE_LATENCY;GAPRole_SetParameter( GAPROLE_SLAVE_LATENCY, sizeof( uint16 ), &desired_slave_latency );
修改超時時間
uint16 desired_conn_timeout = DEFAULT_DESIRED_CONN_TIMEOUT;GAPRole_SetParameter( GAPROLE_TIMEOUT_MULTIPLIER, sizeof( uint16 ), &desired_conn_timeout );
2.所有連接參數一起修改的方法
uint16 minConnInterval;uint16 maxConnInterval;uint16 slaveLatency;uint16 timeoutMultiplier;// Update connection parametersGAPRole_SendUpdateParam( minConnInterval, maxConnInterval, slaveLatency, timeoutMultiplier, GAPROLE_TERMINATE_LINK);
GAPRole_SendUpdateParam傳入的前四個參數在之前都已經介紹過了,下面介紹下最后一個參數,最后一個參數設置的是連接參數更新失敗后的操作,可取值定義在peripheral.h文件中,如下:
/** * Possible actions the peripheral device may take if an unsuccessful parameter * update is received. * * Parameters for GAPRole_SendUpdateParam() only */#define GAPROLE_NO_ACTION 0 // Take no action upon unsuccessful parameter updates#define GAPROLE_RESEND_PARAM_UPDATE 1 // Continue to resend request until successful update#define GAPROLE_TERMINATE_LINK 2 // Terminate link upon unsuccessful parameter updates
GAPROLE_NO_ACTION:沒有任何動作
GAPROLE_RESEND_PARAM_UPDATE:重新發送參數更新請求
GAPROLE_TERMINATE_LINK:斷開連接
對於上述介紹的兩種修改連接參數的方法,個人建議還是采用第二種方法,因為第一種方法在修改某一個參數的時候,可能會導致其他參數的變化,比如我們只修改了連接間隔,但從機延時可能會隨之改變,這樣我們就無法根據自己的需求控制連接參數的更新。
第二種方法在使用的時候有可能碰到一種情況,就是我們只想修改某一個或者某兩個連接參數,剩下的參數想保持原有的,這樣的話,我們需要在修改連接參數之前先去讀取連接參數,然后將需要修改的參數進行重新設置即可,讀取連接參數的代碼如下:
uint16 interval;uint16 latency;uint16 timeout;GAPRole_GetParameter(GAPROLE_CONN_INTERVAL, &interval); GAPRole_GetParameter(GAPROLE_CONN_LATENCY, &latency); GAPRole_GetParameter(GAPROLE_CONN_TIMEOUT, &timeout);
下面我們通過一個實例來具體了解下連接參數修改的方法,需求是將連接間隔修改為25,從機延遲修改為8,超時時間不修改,更新失敗后重新發送參數更新請求,本實例中主設備是安卓設備,從設備是CC2541。代碼實現如下:
uint16 interval;uint16 latency;uint16 timeout;GAPRole_GetParameter(GAPROLE_CONN_INTERVAL, &interval); GAPRole_GetParameter(GAPROLE_CONN_LATENCY, &latency); GAPRole_GetParameter(GAPROLE_CONN_TIMEOUT, &timeout); GAPRole_SendUpdateParam( 25, 25, 8, timeout, GAPROLE_RESEND_PARAM_UPDATE);
該過程抓包顯示如下:
從抓到的包中我們看到首先是S->M,即從設備發送連接參數更新請求,請求中帶有申請的連接參數,然后M->S,即主設備返回連接參數更新響應,Result為0,表示同意修改更新。最后M->S發送Datatype為Control的鏈路層連接參數更新控制規程,攜帶同意的連接參數,這樣,新的連接參數就會投入使用。
注意修改連接參數的時候要滿足一定的要求:
1.安卓設備作主設備時,連接參數滿足的要求見本篇博文第二節“連接參數介紹”中提到的內容。另外實際開發過程中發現安卓設備作主設備時存在一個問題,就是部分安卓設備連接BLE設備之后,只能進行一次連接參數的修改。
2. 蘋果系統設備作主設備時,連接參數更新的要求比較苛刻,如下:
IntervalMax*(SlaveLatency+1)≤2seconds
IntervalMin≥20ms
IntervalMin+20ms≤IntervalMax
SlaveLatency≤4
connSupervisionTimeout≤6seconds
IntervalMax*(SlaveLatency+1)*3<connsupervisiontimeout< p="">
即:
最大連接間隔時間 *(從機延遲+1)≤2s
最小連接間隔時間 ≥20ms
最小連接間隔時間 +20ms≤最大連接間隔時間
從機延遲≤4
超時時間≤6s
最大連接間隔時間 *(從機延遲+1)*3<超時時間
所以如果你的BLE從設備需要被IOS主設備連接,那你的BLE從設備的默認申請的連接參數一定要滿足上述要求,並且連接過程中修改連接參數的時候也要滿足上述要求。