BLE通信由兩種設(shè)備類型構(gòu)成—— Client和Server。
Server提供數(shù)據(jù)服務(wù),所以一般來說設(shè)備是Server,手機(jī)是Client。Server和Client通過ATT PDU進(jìn)行交互,Server通過characteristic對數(shù)據(jù)進(jìn)行封裝。多個characteristic組成一個Service,一個Service是一個獨(dú)立的服務(wù)單元,或者說service是一個基本的BLE應(yīng)用。如果某個service是一個藍(lán)牙聯(lián)盟定義的標(biāo)準(zhǔn)服務(wù),也可以稱其為profile,比如HID/心率計/體溫計/血糖儀等,都是標(biāo)準(zhǔn)藍(lán)牙服務(wù),因此都有相應(yīng)的profile規(guī)格書。
一. characteristic
一個characteristic包含三種條目:characteristic聲明,characteristic的值以及characteristic的描述符(可以有多個描述符):
1.1 Characteristic declaration
就是每個characteristic的分界符。解析時一旦遇到characteristicdeclaration,就可以認(rèn)為接下來又是一個新的characteristic了,同時characteristic declaration還將包含value的讀寫屬性等。
1.2 Characteristic value
就是數(shù)據(jù)的值了,這個比較好理解就不再說了。
1.3 Characteristic descriptor
就是數(shù)據(jù)的額外信息。比如溫度的單位是什么,數(shù)據(jù)是用小數(shù)表示還是百分比表示等之類的數(shù)據(jù)描述信息。CCCD是一種特殊的characteristicdescriptor,當(dāng)characteristic具有notify或者indicate操作功能時,那么必須為其添加相應(yīng)CCCD,以方便client來使能或者禁止notify或者indicate功能。
不管是characteristic declaration,characteristic value還是characteristic descriptor,實(shí)現(xiàn)的時候,我們都是用attribute來表達(dá)的,也就是說,他們每一個都是一個attribute,attribute可以用下圖來表示:
二. Attribute
2.1 Attribute handle
Attribute句柄。Client要訪問Server的Attribute,都是通過這個句柄來訪問的,也就是說ATT PDU一般都包含handle的值。用戶在軟件代碼添加characteristic的時候,系統(tǒng)會自動按順序地為相關(guān)attribute生成句柄。
2.2 Attribute type
Attribute類型。在BLE中我們使用UUID來定義數(shù)據(jù)的類型,UUID是128 bit的,所以我們有足夠的UUID來表達(dá)萬事萬物。其中有一個UUID非常特殊,它被藍(lán)牙聯(lián)盟采用為官方UUID,這個UUID如下所示:0000xxxx-0000-1000-8000-00805F9B34FB, 由于這個UUID眾所周知,藍(lán)牙聯(lián)盟將自己定義的attribute或者數(shù)據(jù)只用16bit UUID來表示,比如0x1234,其實(shí)它也是128bit,完整表示為:
00001234-0000-1000-8000-00805F9B34FB = 16 bit UUID 0x1234
Attribute type一般是由service和characteristic規(guī)格來定義,站在藍(lán)牙協(xié)議棧角度來看,ATT層定義了一個通信的基本框架,數(shù)據(jù)的基本結(jié)構(gòu),以及通信的指令,而GATT層就是前文所述的service和characteristic,GATT層用來賦予每個數(shù)據(jù)一個具體的內(nèi)涵,讓數(shù)據(jù)變得有結(jié)構(gòu)和意義。換句話說,沒有GATT層,低功耗藍(lán)牙也可以通信起來,但會產(chǎn)生兼容性問題以及通信的低效率。
2.3 Attribute value
就是數(shù)據(jù)真正的值,0到512字節(jié)長。
2.4 Attribute permissions
Attribute的權(quán)限屬性,權(quán)限屬性不會直接在空中包中體現(xiàn),而是隱含在ATT命令的操作結(jié)果中。目前主要有如下四種權(quán)限屬性:
●Open,直接可以讀或者寫
●No Access,禁止讀或者寫
●Authentication,需要配對才能讀或者寫,由于配對有多種類型,因此authentication又衍生多種子類型,比如帶不帶MITM,有沒有LESC
●Authorization,跟open一樣,不過server返回attribute的值之前需要應(yīng)用先授權(quán),也就是說應(yīng)用可以在回調(diào)函數(shù)里面去修改讀或者寫的原始值。
●Signed,簽名后才能讀或者寫,這個用得比較少。
Client和Server之間是通過ATT PDU來通信的,ATT PDU主要包括4類:讀,寫,notify和indicate。如果一個命令需要response,那么會在相應(yīng)命令后面加上request;如果一個命令只需要ACK而不需要response,那么它的后面就不會帶request。這里要特別強(qiáng)調(diào)一點(diǎn),BLE所有命令都是“必達(dá)”的,也就是說每個命令發(fā)出去之后,會立馬等ACK信息,如果收到了ACK包,發(fā)起方認(rèn)為命令完成;否則發(fā)起方會一直重傳該命令直到超時導(dǎo)致BLE連接斷開。換句話說,只要你的BLE沒有斷開,那么你之前發(fā)送的數(shù)據(jù)包,不管它是用什么ATT PDU來發(fā)送的,它肯定被對方收到了。我估計很多人對此會產(chǎn)生疑問,因?yàn)樗麄兘?jīng)常碰到丟包的情況,其實(shí)大家經(jīng)常碰到的“丟包”,不是空中把包丟了或者包在空中被干擾了,而是大家發(fā)送的代碼寫得有問題,導(dǎo)致你要發(fā)送的包沒有被安全送達(dá)到協(xié)議棧射頻FIFO中,所以以后大家碰到丟包情況,請先檢查你的代碼,保證你的數(shù)據(jù)包正確完整安全地送達(dá)到協(xié)議棧射頻FIFO中,只要數(shù)據(jù)包放到了協(xié)議棧射頻FIFO中,藍(lán)牙協(xié)議棧就能保證該數(shù)據(jù)包“必達(dá)”對方。既然每個ATT命令都必達(dá)對方,那么還需要request做什么?如果一個命令帶有request后綴,那么發(fā)起方就可以收到命令的response包,這個response包在應(yīng)用層是有回調(diào)事件的,而前述的ACK包在應(yīng)用層是沒有回調(diào)事件的。所以采用request/response方式,應(yīng)用層可以按順序地發(fā)送一些數(shù)據(jù)包,這個在很多應(yīng)用場合是非常有用的。相反,如果你對應(yīng)用層數(shù)據(jù)包的順序沒有要求,那么就可以不使用request/response形式。另外Request/response有一個副作用:大大降低通信的吞吐率,因?yàn)閞equest/response必須在不同的連接間隔中出現(xiàn),也就是說,你在間隔1中發(fā)送了一個request命令,那么response包必須在間隔2或者稍后間隔中回復(fù),而不能在間隔1中回復(fù),這就導(dǎo)致兩個連接間隔最多只能發(fā)一個數(shù)據(jù)包,而不帶request后綴的ATT命令就沒有這個問題,在同一個連接間隔中,你可以同時發(fā)多個數(shù)據(jù)包,這樣將大大提高數(shù)據(jù)的吞吐率。
常用的帶request的命令:所有read命令,writerequest,indication等,而常用的不帶request的命令有write command,notification等。