協議棧解析

  • 對開發者來説,很簡單,他只需要調用send(0x53)
  • GATT層定義數據的類型和分組,方便起見,我們用0x0013表示電量這種數據類型,這樣GATT層把數據打包成130053(小端模式!)
  • ATT層用來選擇具體的通信命令,比如讀/寫/notify/indicate等,這裏選擇notify命令0x1B,這樣數據包變成了:1B130053
  • L2CAP用來指定connection interval(連接間隔),比如每10ms同步一次(CI不體現在數據包中),同時指定邏輯通道編號0004(表示ATT命令),最後把ATT數據長度0x0004加在包頭,這樣數據就變為:040004001B130053
  • LL層要做的工作很多,首先LL層需要指定用哪個物理信道進行傳輸(物理信道不體現在數據包中),然後再給此連接分配一個Access address(0x50655DAB)以標識此連接只為設備A和設備B直連服務,然後加上LL header和payload length字段,LL header標識此packet為數據packet,而不是control packet等,payload length為整個L2CAP字段的長度,最後加上CRC24字段,以保證整個packet的數據完整性,所以數據包最後變成:
  • AAAB5D65501E08040004001B130053D550F6
  • AA – 前導幀(preamble)
  • 0x50655DAB – 訪問地址(access address)
  • 1E – LL幀頭字段(LL header)
  • 08 – 有效數據包長度(payload length)
  • 04000400 – ATT數據長度,以及L2CAP通道編號
  • 1B – notify command
  • 0x0013 – 電量數據handle
  • 0x53 – 真正要發送的電量數據
  • 0xF650D5 – CRC24值
  • 雖然開發者只調用了 send(0x53),但由於低功耗藍牙協議棧層層打包,最後空中實際傳輸的數據將變成下圖所示的模樣,這就既滿足了低功耗藍牙通信的需求,又讓用户API變得簡單,可謂一箭雙鵰!

ble 可以同時是write和write no response嗎_數據

 

常用ATT命令

        藍牙的request/response

        Client和Server之間是通過ATT PDU來通信的,ATT PDU主要包括4類:讀,寫,notify和indicate。如果一個命令需要response,那麼會在相應命令後面加上request;如果一個命令只需要ACK而不需要response,那麼它的後面就不會帶request。這裏要特別強調一點,BLE所有命令都是“必達”的,也就是説每個命令發出去之後,會立馬等ACK信息,如果收到了ACK包,發起方認為命令完成;否則發起方會一直重傳該命令直到超時導致BLE連接斷開。換句話説,只要你的BLE沒有斷開,那麼你之前發送的數據包,不管它是用什麼ATT PDU來發送的,它肯定被對方收到了。我估計很多人對此會產生疑問,因為他們經常碰到丟包的情況,其實大家經常碰到的“丟包”,不是空中把包丟了或者包在空中被幹擾了,而是大家發送的代碼寫得有問題,導致你要發送的包沒有被安全送達到協議棧射頻FIFO中,所以以後大家碰到丟包情況,請先檢查你的代碼,保證你的數據包正確完整安全地送達到協議棧射頻FIFO中,只要數據包放到了協議棧射頻FIFO中,藍牙協議棧就能保證該數據包“必達”對方。既然每個ATT命令都必達對方,那麼還需要request做什麼?如果一個命令帶有request後綴,那麼發起方就可以收到命令的response包,這個response包在應用層是有回調事件的,而前述的ACK包在應用層是沒有回調事件的。所以採用request/response方式,應用層可以按順序地發送一些數據包,這個在很多應用場合是非常有用的。相反,如果你對應用層數據包的順序沒有要求,那麼就可以不使用request/response形式。另外Request/response有一個副作用:大大降低通信的吞吐率,因為request/response必須在不同的連接間隔中出現,也就是説,你在間隔1中發送了一個request命令,那麼response包必須在間隔2或者稍後間隔中回覆,而不能在間隔1中回覆,這就導致兩個連接間隔最多隻能發一個數據包,而不帶request後綴的ATT命令就沒有這個問題,在同一個連接間隔中,你可以同時發多個數據包,這樣將大大提高數據的吞吐率。大家可以參考下圖來理解request和非request命令的區別:

 

ble 可以同時是write和write no response嗎_數據_02

ble 可以同時是write和write no response嗎_協議棧_03

常用的帶request的命令:所有read命令,write request,indication等,而常用的不帶request的命令有write command,notification等,完整的ATT命令列表如下所示:

ble 可以同時是write和write no response嗎_數據_04

ble 可以同時是write和write no response嗎_應用層_05

 

NRF_SDH_BLE_OBSERVER用來為本地文件(此處為main.c)註冊一個BLE回調函數(此處為ble_evt_handler),NRF_SDH_BLE_OBSERVER這個宏執行成功後,所有的BLE事件都會被ble_evt_handler捕獲。進入ble_evt_handler,你會發現BLE有上百個回調事件,你不需要每個都處理,你只需要處理你關心的事件即可,比如連接成功事件BLE_GAP_EVT_CONNECTED或者連接斷開事件BLE_GAP_EVT_DISCONNECTED

NRF_SDH_BLE_OBSERVER有一個很大的好處:某個模塊如果需要捕獲BLE事件,那麼它自己調用NRF_SDH_BLE_OBSERVER這個宏註冊相應回調函數即可,而不再需要在其它文件中去註冊這個回調函數,將模塊的耦合性降到最低,符合模塊化編程思想。(即response包在應用層的回調函數)