本文作者twowinter,轉載自:http://blog.csdn.net/iotisan/
前言
這是《LoRaWAN102》的譯文,即LoRaWAN協定規範 V1.0.2 版本(2016年7月定稿)。
我正在陸續對協定的各個章節進行翻譯,具體其他章節的譯文,以及譯文之外的代碼解析,可點此檢視文章LoRa學習筆記_彙總。
本文作者twowinter,轉載請注明作者:http://blog.csdn.net/iotisan/
翻譯開始
第4章 MAC幀格式
LoRa所有上下行鍊路消息都會攜帶PHY載荷,PHY載荷以1位元組MAC頭(MHDR)開始,緊接着MAC載荷(MACPayload),最後是4位元組的MAC校驗碼(MIC)。
射頻PHY層:
Preamble | PHDR | PHDR_CRC | PHYPayload | CRC |
圖5.射頻PHY結構(注意 CRC隻有上行鍊路消息中存在)
PHY載荷:
MHDR | MACPayload | MIC |
或者
MHDR | Join-Request | MIC |
或者
MHDR | Join-Response | MIC |
圖6.PHY載荷結構
MAC載荷:
FHDR | FPort | FRMPayload |
圖7.MAC載荷結構
FHDR:
DevAddr | FCtrl | FCnt | FOpts |
圖8.幀頭結構
圖9.LoRa幀格式元素(即圖5~8)
4.1 MAC層(PHYPayload)
Size (bytes) | 1 | 1..M | 4 |
PHYPayload | MHDR | MACPayload | MIC |
MACPayload字段的最大長度M,在第6章有詳細說明。
4.2 MAC頭(MHDR字段)
Bit# | 7..5 | 4..2 | 1..0 |
MHDR bits | MType | RFU | Major |
MAC頭中指定了消息類型(MType)和幀編碼所遵循的LoRaWAN規範的主版本号(Major)。
4.2.1 消息類型(MType位字段)
LoRaWAN定義了六個不同的MAC消息類型:join request, join accept, unconfirmed data up/down, 以及 confirmed data up/down 。
MType | 描述 |
000 | Join Request |
001 | Join Accept |
010 | Unconfirmed Data Up |
011 | Unconfirmed Data Down |
100 | Confirmed Data Up |
101 | Confirmed Data Down |
110 | RFU |
111 | Proprietary |
表1.MAC消息類型
- 4.2.1.1 Join-request and join-accept 消息
join-request和join-accept都是用在空中激活流程中,具體見章節6.2
- 4.2.1.2 Data messages
Data messages 用來傳輸MAC指令和應用資料,這兩種指令也可以放在單個消息中發送。
Confirmed-data message 接收者需要應答。
Unconfirmed-data message 接收者則不需要應答。
Proprietary messages 用來處理非标準的消息格式,不能和标準消息互通,隻能用來和具有相同拓展格式的消息進行通信。
不同消息類型用不同的方法保證消息一緻性,下面會介紹每種消息類型的具體情況。
4.2.2 資料消息的主版本(Major位字段)
Major位字段 | 描述 |
00 | LoRaWAN R1 |
01..11 | RFU |
表2.Major清單
注意:Major定義了激活過程中(join procedure)使用的消息格式(見章節6.2)和MAC Payload的前4位元組(見第4章)。終端要根據不同的主版本号實作不同最小版本的消息格式。終端使用的最小版本應當提前通知網絡伺服器。
4.3 MAC載荷(MACPayload)
MAC載荷,也就是所謂的“資料幀”,包含:幀頭(FHDR)、端口(FPort)以及幀載荷(FRMPayload),其中端口和幀載荷是可選的。
4.3.1 幀頭(FHDR)
FHDR是由終端短位址(DevAddr)、1位元組幀控制位元組(FCtrl)、2位元組幀計數器(FCnt)和用來傳輸MAC指令的幀選項(FOpts,最多15個位元組)組成。
Size(bytes) | 4 | 1 | 2 | 0..15 |
FHDR | DevAddr | FCtrl | FCnt | FOpts |
FCtrl在上下行消息中有所不同,下行消息如下:
Bit# | 7 | 6 | 5 | 4 | [3..0] |
FCtrl bits | ADR | ADRACKReq | ACK | FPending | FOptsLen |
上行消息如下:
Bit# | 7 | 6 | 5 | 4 | [3..0] |
FCtrl bits | ADR | ADRACKReq | ACK | RFU | FOptsLen |
- 4.3.1.1 幀頭中 自适應資料速率 的控制(ADR, ADRACKReq in FCtrl)
LoRa網絡允許終端采用任何可能的資料速率。LoRaWAN協定利用該特性來優化固定終端的資料速率。這就是自适應資料速率(Adaptive Data Rate (ADR))。當這個使能時,網絡會優化使得盡可能使用最快的資料速率。
移動的終端由于射頻環境的快速變化,資料速率管理就不再适用了,應當使用固定的資料速率。
如果ADR的位字段有置位,網絡就會通過相應的MAC指令來控制終端裝置的資料速率。如果ADR位沒設定,網絡則無視終端的接收信号強度,不再控制終端裝置的資料速率。ADR位可以根據需要通過終端及網絡來設定或取消。不管怎樣,ADR機制都應該盡可能使能,幫助終端延長電池壽命和擴大網絡容量。
注意:即使是移動的終端,可能在大部分時間也是處于非移動狀态。是以根據它的移動狀态,終端也可以請求網絡使用ADR來幫助優化資料速率。
如果終端被網絡優化過的資料速率高于自己預設的資料速率,它需要定期檢查下網絡仍能收到上行的資料。每次上行幀計數都會累加(是針對于每個新的上行包,重傳包就不再增加計數),終端增加 ADR_ACK_CNT 計數。如果直到ADR_ACK_LIMIT次上行(ADR_ACK_CNT >= ADR_ACK_LIMIT)都沒有收到下行回複,它就得置高ADR應答請求位(ADRACKReq)。 網絡必須在規定時間内回複一個下行幀,這個時間是通過ADR_ACK_DELAY來設定,上行之後收到任何下行幀就要把ADR_ACK_CNT的計數重置。當終端在接收時隙中的任何回複下行幀的ACK位字段不需要設定,表示網關仍在接收這個裝置的上行幀。如果在下一個ADR_ACK_DELAY上行時間内都沒收到回複(例如,在總時間ADR_ACK_LIMIT+ADR_ACK_DELAY之後),終端必須切換到下一個更低速率,使得能夠獲得更遠傳輸距離來重連網絡。終端如果在每次ADR_ACK_LIMIT到了之後依舊連接配接不上,就需要每次逐漸降低資料速率。如果終端用它的預設資料速率,那就不需要置位ADRACKReq,因為無法幫助提高鍊路距離。
注意:不要ADRACKReq立刻回複,這樣給網絡預留一些餘量,讓它做出最好的下行排程處理。
注意:上行傳輸時,如果 ADR_ACK_CNT >= ADR_ACK_LIMIT 并且目前資料速率比裝置的最小資料速率高,就要設定 ADRACKReq,其它情況下不需要。
- 4.3.1.2 消息應答位及應答流程(ACK in FCtrl)
收到confirmed類型的消息時,接收端要回複一條應答消息(應答位ACK要進行置位)。如果發送者是終端,網絡就利用終端發送操作後打開的兩個接收視窗之一進行回複。如果發送者是網關,終端就自行決定是否發送應答。
應答消息隻會在收到消息後回複發送,并且不重發。
注意:為了讓終端盡可能簡單,盡可能減少狀态,在收到confirmation類型需要确認的資料幀,需要立即發送一個嚴格的應答資料幀。或者,終端會延遲發送應答,在它下一個資料幀中再攜帶。
- 4.3.1.3 重傳流程
當需要應答卻沒收到應答時就會進行重發,重發的個數由終端自己定,可能每個終端都不一樣,這個參數也可以由網絡伺服器來設定調整。
注意:一些應答機制的示例時序圖在第18章中有提供。
注意:如果終端裝置重發次數到達了最大值,它可以降低資料速率來重連。至于後面是否再重發還是說丢棄不管,都取決于終端自己。
注意:如果網絡伺服器重發次數到達了最大值,它就認為該終端掉線了,直到它再收到終端的消息。一旦和終端裝置的連接配接出現問題時,要不要重發都取決于網絡伺服器自己。
注意:在重傳期間的資料速率回退的建議政策在章節18.4中有描述。
- 4.3.1.4 幀挂起位(FPending in FCtrl 隻在下行有效)
幀挂起位(FPending)隻在下行互動中使用,表示網關還有挂起資料等待下發,需要終端盡快發送上行消息來再打開一個接收視窗。
FPending的詳細用法在章節18.3。
- 4.3.1.5 幀計數器(FCnt)
每個終端有兩個計數器跟蹤資料幀的個數,一個是上行鍊路計數器(FCntUp),由終端在每次上行資料給網絡伺服器時累加;另一個是下行鍊路計數器(FCntDown),由伺服器在每次下行資料給終端時累計。 網絡伺服器為每個終端跟蹤上行幀計數及産生下行幀計數。 終端入網成功後,終端和服務端的上下行幀計數同時置0。 每次發送消息後,發送端與之對應的 FCntUp 或 FCntDown 就會加1。 接收方會同步儲存接收資料的幀計數,對比收到的計數值和目前儲存的值,如果兩者相差小于 MAX_FCNT_GAP (要考慮計數器滾動),接收方就按接收的幀計數更新對應值。如果兩者相差大于 MAX_FCNY_GAP 就說明中間丢失了很多資料,這條以及後面的資料就被丢掉。
LoRaWAN的幀計數器可以用16位和32位兩種,節點上具體執行哪種計數,需要在帶外通知網絡側,告知計數器的位數。
如果采用16位幀計數,FCnt字段的值可以使用幀計數器的值,此時有需要的話通過在前面填充0(值為0)位元組來補足;如果采用32位幀計數,
FCnt就對應計數器32位的16個低有效位(上行資料使用上行FCnt,下行資料使用下行FCnt)。
終端在相同應用和網絡密鑰下,不能重複用相同的FCntUp數值,除非是重傳。
-
4.3.1.6 幀可選項(FOptsLen in FCtrl, FOpts)
FCtrl 位元組中的FOptsLen位字段描述了整個幀可選項(FOpts)的字段長度。
FOpts字段存放MAC指令,最長15位元組,詳細的MAC指令見章節4.4。
如果FOptsLen為0,則FOpts為空。在FOptsLen非0時,則反之。如果MAC指令在FOpts字段中展現,port0不能用(FPort要麼不展現,要麼非0)。
MAC指令不能同時出現在FRMPayload和FOpts中,如果出現了,裝置丢掉該組資料。
4.3.2 端口字段(FPort)
如果幀載荷字段不為空,端口字段必須展現出來。端口字段有展現時,若FPort的值為0表示FRMPayload隻包含了MAC指令;具體見章節4.4中的MAC指令。 FPort的數值從1到223(0x01..0xDF)都是由應用層使用。 FPort的值從224到255(0xE0..0xFF)是保留用做未來的标準應用拓展。
Size(bytes) | 7..23 | 0..1 | 0..N |
MACPayload | FHDR | FPort | FRMPayload |
N是應用程式載荷的位元組個數。N的有效範圍具體在第7章有定義。
N應該小于等于:
N <= M - 1 - (FHDR長度)
M是MAC載荷的最大長度。
4.3.3 MAC幀載荷加密(FRMPayload)
如果資料幀攜帶了載荷,FRMPayload必須要在MIC計算前進行加密。
加密機制是采用IEEE802.15.4/2006的AES128算法。
預設的,加密和加密由LoRaWAN層來給所有的FPort來執行。如果加密/解密由應用層來做更友善的話,也可以在LoRaWAN層之上給特定FPorts來執行,除了端口0。具體哪個節點的哪個FPort在LoRaWAN層之外要做加解密,必須要和伺服器通過out-of-band信道來互動(見第19章)。
- 4.3.3.1 LoRaWAN的加密
密鑰K根據不同的FPort來使用:
FPort | K |
NwkSKey | |
1..255 | AppSKey |
表3: FPort清單
具體加密是這樣:
pld = FRMPayload
對于每個資料幀,算法定義了一個塊序列Ai,i從1到k,k = ceil(len(pld) / 16):
Size(bytes) | 1 | 4 | 1 | 4 | 4 | 1 | 1 |
Ai | 0x01 | 4 x 0x00 | Dir | DevAddr | FCntUp or FCntDown | 0x00 | i |
方向字段(Dir)在上行幀時為0,在下行幀時為1.
塊Ai通過加密,得到一個由塊Si組成的序列S。
Si = aes128_encrypt(K, Ai) for i = 1..k
S = S1 | S2 | .. | Sk
通過異或計算對payload進行加解密:
-
4.3.3.2 LoRaWAN層之上的加密
如果LoRaWAN之上的層級在已選的端口上(但不能是端口0,這是給MAC指令保留的)提供了預加密的FRMPayload給LoRaWAN,LoRaWAN則不再對FRMPayload進行修改,直接将FRMPayload從MACPayload傳到應用層,以及從應用層傳到MACPayload。
4.4 消息校驗碼(MIC)
消息檢驗碼要計算消息中所有字段。
msg = MHDR | FHDR | FPort | FRMPayload
MIC是按照[RFC4493]來計算:
cmac = aes128_cmac(NwkSKey, B0 | msg)
MIC = cmac[0..3]
塊B0的定義如下:
Size(bytes) | 1 | 4 | 1 | 4 | 4 | 1 | 1 |
B0 | 0x49 | 4 x 0x00 | Dir | DevAddr | FCntUp or FCntDown | 0x00 | len(msg) |
方向字段(Dir)在上行幀時為0,在下行幀時為1.