LoRa Protocol

LoRa Protocol

十一月 24, 2017

一 Introduction

本文档描述了LoRaWAN网络协议,是针对电池供电的终端设备(不管移动还是固定位置)进行优化的一套网络协议。

LoRaWAN网络通常采用星型拓扑结构,由拓扑中的网关来转发终端与后台网络服务器间的消息。网关通过标准IP连接来接入网络服务器,而终端则通过单跳的 LoRa 或者 FSK 来和一个或多个网关通讯。虽然主要传输方式是终端上行传输给网络服务器,但所有的传输通常都是双向的。

终端和网关间的通讯被分散到不同的信道频点和数据速率上。数据速率的选择需要权衡距离和消息时长两个因素,使用不同数据速率的设备互不影响。LoRa的数据速率范围可以从 0.3kbps 到 50kbps。为了最大程度地延长终端的电池寿命和扩大网络容量,LoRa网络使用速率自适应(ADR)机制来独立管理每个终端的速率和RF输出。

虽然每个设备可以在任意信道,任意时间,发送任意数据,但需要注意遵守如下规定:

  • 终端的每次传输都使用伪随机方式来改变信道。频率的多变使得系统具有更强的抗干扰能力。
  • 终端要遵守相应频段和本地区的无线电规定中的发射占空比要求。
  • 终端要遵守相应频段和本地区的无线电规定中的发射时长要求。

注:发射占空比,意思是发射时长占总时长的比例。按照无线电规定,每个设备不能疯狂发射霸占信道,总给别人一点机会。

这份文档主要讲述协议细节,一些基于各地区规定的操作参数,例如发射占空比和发射时长等,在另一份文档[LoRaWAN地区参数]中做具体描述。将这份文档分开,是为了加入新地区参数时不影响基础的协议规范。

1.1 LoRaWan Classes

所有的LoRaWAN设备都必须至少实现本文档描述的 Class A 功能。另外也可以实现本文档中描述的 Class B 和 Class C 及后续将定义的可选功能。不管怎么样,设备都必须兼容 Class A。

1.2 文档规定

MAC命令的格式写作 LinkCheckReq (粗斜体),位和位域的格式写作 FRMPayload (粗体),常量的格式写作RECEIVE_DELAY1变量的格式写作N

在本文档中,

  • 所有多字节字段的字节序均采用小端模式。
  • EUI是8字节字段,采用小端模式传输。
  • 默认所有RFU保留位都设为0。

二 LoRaWAN Classes类型介绍

LoRa是由Semtech面向长距离、低功耗、低速率应用而开发的无线调制技术。本文档中,将 Class A 基础上实现了更多功能的设备称为“更高 class 终端”。

2.1 LoRaWAN Classes

LoRa网络包含基础LoRaWAN(称之为Class A)和可选功能(Class B,Class C):

  • 双向传输终端(Class A)

    Class A的终端在每次上行后都会紧跟两个短暂的下行接收窗口,以此实现双向传输。传输时隙是由终端在有传输需要时安排,附加一定的随机延时(即ALOHA协议)。这种Class A 操作是最省电的,要求应用在终端上行传输后的很短时间内进行服务器的下行传输。服务器在其他任何时间进行的下行传输都得等终端的下一次上行。

  • 划定接收时隙的双向传输终端(Class B)

    Class B 的终端会有更多的接收时隙。除了Class A 的随机接收窗口,Class B 设备还会在指定时间打开别的接收窗口。为了让终端可以在指定时间打开接收窗口,终端需要从网关接收时间同步的信标 Beacon。这使得服务器可以知道终端正在监听。

  • 最大化接收时隙的双向传输终端(Class C)

    Class C 的终端基本是一直打开着接收窗口,只在发送时短暂关闭。Class C 的终端会比 Class A 和 Class B更加耗电,但同时从服务器下发给终端的时延也是最短的。

2.2 文档范围

这份LoRaWAN协议还描述了与 Class A 不同的其他 Class 的额外功能。更高 Class 的终端必须满足 Class A 定义的所有功能。

注意:物理层帧格式,MAC帧格式,以及协议中更高 class 和 Class A 相同的内容都写在了 Class A 部分,避免内容重复。

Class A - All end-devices

三 PHY帧格式

LoRa是有上行消息和下行消息的。

3.1 上行消息

  • 上行消息是由终端发出,经过一个或多个网关转发给网络服务器。
  • 上行消息使用 LoRa 射频帧的严格模式,消息中含有 PHDR 和 PHDR_CRC 。载荷有CRC校验来保证完整性。
  • PHDR,PHDR_CRC 及载荷 CRC 域都通过射频收发器加入。

上行PHY:(如下图)

3.2 下行消息

  • 下行消息是由网络服务器发出,经过单个网关转发给单个终端。
  • 下行消息使用射频帧的严格模式,消息中包含 PHDR和 PHDR_CRC。

下行PHY:(如下图)

3.3 接收窗口

每个上行传输后终端都要开两个短的接收窗口。接收窗口开始时间的规定,是以传输结束时间为参考。

3.3.1 第一接收窗口的信道,数据速率和启动

第一接收窗口 RX1 使用的频率和上行频率有关,使用的速率和上行速率有关。RX1 是在上行调制结束后的 RECEIVE_DELAY1 秒打开。上行和 RX1 时隙下行速率的关系是按区域规定,详细描述在[LoRaWAN地区参数]文件中。默认第一窗口的速率是和最后一次上行的速率相同。

3.3.2 第二接收窗口的信道,数据速率和启动

第二接收窗口 RX2 使用一个固定可配置的频率和数据速率,在上行调制结束后的 RECEIVE_DELAY2 秒打开。频率和数据速率可以通过 MAC 命令(见第五章。默认的频率和速率是按区域规定,详细描述在[LoRaWAN地区参数]文件中。

3.3.3 接收窗口的持续时间

接收窗口的长度至少要让终端射频收发器有足够的时间来检测到下行的前导码

3.3.4 接收方在接收窗口期间的处理

如果在任何一个接收窗口中检测到前导码,射频收发器需要继续激活,直到整个下行帧都解调完毕。如果在第一接收窗口检测到数据帧,且这个数据帧的地址和MIC(信息完整性检测码)校验通过确认是给这个终端,那终端就不必开启第二个接收窗口。

3.3.5 网络发送消息给终端

如果网络想要发一个下行消息给终端,它会精确地在两个接收窗口的起始点发起传输。

3.3.6 接收窗口的重要事项

终端在第一或第二接收窗口收到下行消息后,或者在第二接收窗口阶段,不能再发起另一个上行消息。

3.3.7 其他协议的收发处理

终端节点在LoRaWAN收发窗口阶段可以收发其他协议,只要终端能满足当地要求以及兼容LoRaWAN协议。

附加

本章节的对应代码梳理思维导图,如下:

发送完成就开始RX1和RX2延时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void OnRadioTxDone( void )
{
...
// Setup timers
if( IsRxWindowsEnabled == true )
{
TimerSetValue( &RxWindowTimer1, RxWindow1Delay );
TimerStart( &RxWindowTimer1 );
if( LoRaMacDeviceClass != CLASS_C )
{
TimerSetValue( &RxWindowTimer2, RxWindow2Delay );
TimerStart( &RxWindowTimer2 );
}
if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) )
{
TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + ACK_TIMEOUT +
randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
TimerStart( &AckTimeoutTimer );
}
}
...
}

接收窗口的射频处理

从源码了解,对应的处理是在OnRxWindow1TimerEventOnRxWindow2TimerEvent 中。 这两个接收窗口的处理,会对速率和信道进行设置,按照LoRaWAN协议中文版_配套文件 地区参数(物理层) 中对各地区的要求分别进行处理。

比如这个470的处理,对上行信道对48取余得到下行信道。

1
RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 48 ) * LORAMAC_STEPWIDTH_

四 MAC帧格式

LoRa所有上下行链路消息都会携带PHY载荷,PHY载荷以1字节MAC头(MHDR)开始,紧接着MAC载荷(MACPayload),最后是4字节的MAC校验码(MIC)。

① Radio PHY layer (射频PHY层) :

注:在射频PHY结构中的CRC只有上行链路消息中存在

② PHYPayload (PHY有效载荷结构) :

或者

或者

③ MACPayload (MAC载荷结构) :

其中FHDR具体可以分为:

4.1 MAC层(PHYPayload)

Size (bytes) 1 1..M 4
PHYPayload MHDR MACPayload MIC

MACPayload字段的最大长度M,在第六章有详细说明。

4.2 MAC头(MHDR字段)

Bit# 7..5 4..2 1..0
MHDR MType RFU Mayjor

MAC头中指定了消息类型(MType)和帧编码所遵循的LoRaWAN规范的主版本号(Major)。

4.2.1 消息类型(MType位字段)

LoRaWAN定义了6个不同的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
4.2.1.1 Join-request 和 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列表 :

Major位字段 描述
00 LoRaWAN R1
01..11 RFU

注意: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的详细用法在(参考LORAWAN英文手册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数值,除非是重传。

注意: 由于FCnt字段只包含32位帧计数器中最不重要的16位,因此服务器必须从对数据流的观察中推断出16个最重要的帧计数器。

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专用于LoRaWAN Mac层测试协议。

注意

  • Fport值224的目的是提供一个专用的Fport,以在设备的最终版本上运行Mac的兼容性测试场景,而不需要依赖于实际方面的设备的特定测试版本。测试不应该同时与现场操作同时进行,但是设备的Mac层实现应该与普通应用程序完全相同。测试协议通常使用AppSKey加密。这确保了网络在不涉及设备所有者的情况下不能启用设备的测试模式。如果测试运行在一个动态网络连接设备上,那么网络上的测试应用程序就会知道AppSkey是在LoRaWAN规范的范围之外的。如果测试在一个专用的测试台上使用OTAA(而不是一个实时网络),那么Appkey与测试工作台通信的方式,对于安全的连接过程,也超出了规范的范围。

  • 在应用层上运行的测试协议是在LoRaWAN规范之外定义的,因为它是一个应用层协议。

FPort的值从225到255(0xE1..0xFF)是保留用做未来的标准应用拓展。

Size(bytes) 7..22 0..1 0..N
MACPayload FHDR FPort FRMPayload
  • 应用程序载荷的字节个数。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信道来交互(见英文版LORAWAN规范19章)。

  • 密钥K根据不同的FPort来使用:
FPort Key
0 NwkSKey
1..255 AppSKey
  • 具体加密是这样: 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进行的。

:如果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.

附加

关于MAC帧格式,可参考下表

1. ADR(速率自适应)机制

这个章节中最亮眼的莫过于速率自适应机制,简直是为LoRa网络量身定做的:一旦使能了FCtrl中的ADR位,距离近信号好的节点用高速率,距离远信号弱的节点用低速率,不小心被调高了速率,则自动降下来。这样,尽可能地提高了传输速率,也有效提高了网络容量。

2. 可同时携带数据和命令的MAC帧

一般来说,应用除了数据,出于管理需要,肯定还会涉及命令。比如基站要查询节点状态,或者节点要请求变更信道等。所以LoRaWAN协议设计上利用FOpts把数据和命令揉在一个MAC帧里,这样可以提高交互效率,有效地降低功耗。

相关源码解析

在源码的\src\mac\LoRaMac.C文件中

1. MAC层MHDR
  • 在LoRaWAN的数据API中处理了MHDR,这个字段内容比较少,就按需选择了消息类型是confirm还是unconfirm。 另外在管理API中的Join-Req的消息类型。
  • 具体可见 LoRaMacMcpsRequest()LoRaMacMlmeRequest() 这两个函数。
2. MACPayload
  • MACPayload的组帧都在PrepareFrame() 这个函数中处理,将macHdr和macPayload的fCtrl、FPort、FRMPayload都传递进去,完成整个MAC层的数据组帧。
  • LoRaMacBuffer就存放了MACPayload的数据,这个变量的组帧和协议字段定义是一一对应。MACPayload的组帧处理,在大流程上是对join和数据两种类型的帧分别处理,用两个case分开。

Join-request的组帧处理对应协议第6章 6.2.4) Join-request message。

数据帧的组帧处理则稍微复杂些,尤其是FHDR,下面逐个字段讲解下FHDR。

3. MACPayload中的FHDR
3.1 FHDR中的DevAddr
1
2
3
4
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF; 
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) &
3.2 FHDR中的FCtrl

首先 ADR 位段 是在传入 PrepareFrame() 之前,就做了处理。

1
fCtrl.Bits.Adr = AdrCtrlOn;

接着 AdrAckReq 位段,在长期失联情况下会发送AdrAckReq确认链路。

1
fCtrl->Bits.AdrAckReq=AdrNextDr( fCtrl->Bits.Adr,true,&LoRaMacParams.ChannelsDatarate );

最后 F0ptsLen 位段,会在下面计算完FOpts之后更新。

3.3 FHDR中的FCnt
1
2
LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF; 
LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF;
  • 这个 UpLinkCounter 会在物理层发送完成后会按照协议进行累加。可以看到这是个32位计数器,按照协议规定,“如果采用32位帧计数,FCnt就对应计数器32位的16个低有效位”。
  • 这是上行的,另外下行的也类似。
3.4 FHDR中的FOpts

把MAC命令放入F0pts中,并且更新F0ptsLen。MAC命令,要么使用非零的FPort来和数据一起传输,要么使用FPort0来单独传输。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Copy the MAC commands which must be re-send into the MAC command buffer
memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex );
MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex;

if( ( payload != NULL ) && ( payloadSize > 0 ) )
{
if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) )
{
fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;

// Update FCtrl field with new value of OptionsLength
LoRaMacBuffer[0x05] = fCtrl->Value;
for( i = 0; i < MacCommandsBufferIndex; i++ )
{
LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
}
}
}
else
{
if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) )
{
payloadSize = MacCommandsBufferIndex;
payload = MacCommandsBuffer;
framePort = 0;
}
}
4. MACPayload中的FPort
  • 这个是在应用层一直传递进去的,协议栈默认是用了端口2。这个是后期大家在应用时要调整的,类似于IP端口,不同的端口对应不同的服务。
5. MIC解析
  • 在函数 PrepareFrame()的最后是调用LoRaMacComputeMic() 计算出整个MAC层的校验码。应用层这边基本不用改这边就暂时不细究了。

    五 MAC命令

  • 对网络管理者而言,有一套专门的MAC命令用来在服务器和终端MAC层之间交互。这套MAC命令对应用程序(不管是服务器端还是终端设备的应用程序)是不可见的。

  • 单个数据帧中可以携带MAC命令,要么在FOpts字段中捎带,要么在独立帧中将FPort设成0后放在FRMPayload里。如果采用FOpts捎带的方式,MAC命令是不加密并且不长度超过15字节。如果采用独立帧放在FRMPayload的方式,那就必须采用加密方式,并且不超过FRMPayload的最大长度。

    注意: 如果MAC命令不想被窃听,那就必须以独立帧形式放在FRMPayload中。

    每个MAC命令是由 1字节CID 跟着一段可能为空的字节序列组成的。

CID Command 终端作为发送端 网关作为发送端 描述
0x02 LinkCheckReq x 终端利用这个命令来判断网络连接质量
0x02 LinkCheckAns x LinkCheckReq的回复。包含接收信号强度,告知终端接收质量
0x03 LinkADRReq x 向终端请求改变数据速率,发射功率,重传率以及信道
0x03 LinkADRAns x LinkADRReq的回复。
0x04 DutyCycleReq x 向终端设置发送的最大占空比。
0x04 DutyCycleAns x DutyCycleReq的回复。
0x05 RXParamSetupReq x 向终端设置接收时隙参数。
0x05 RXParamSetupAns x RXParamSetupReq的回复。
0x06 DevStatusReq x 向终端查询其状态。
0x06 DevStatusAns x 返回终端设备的状态,即电池余量和链路解调预算。
0x07 NewChannelReq x 创建或修改 1个射频信道定义。
0x07 NewChannelAns x NewChannelReq的回复。
0x08 RXTimingSetupReq x 设置接收时隙的时间。
0x08 RXTimingSetupAns x RXTimingSetupReq的回复。
0x09 TxParamSetupReq x 网络服务器用它来设置终端设备停留时间的最大值和最大EIRP(等效全向辐射功率),与地域相关
0x09 TxParamSetuoAns x TxParamSetupReq的回复
0x0A DIChannelReq x 通过将下行频率与上行频率进行偏移,来修改下行RX1的无线信道(即:创建非对称信道)
0x0A DIChannelAns x DIChannelReq的回复
0x80~0xFF 私有 x x 给私有网络命令拓展做预留。
  • 注意: MAC命令的长度虽然没有明确给出,但是MAC执行层必须要知道。因此未知的MAC命令无法被忽略,且前面未知的MAC命令会终止MAC命令的进程。所以建议按照LoRaWAN协议介绍的MAC命令来处理MAC命令。所有当前版本LoRaWAN规范中实现的MAC命令都可以被更高版本的规范兼容处理。
  • 注意 :终端设备所有被网络服务器调整过的内容(例如:RX2,新创建或调整过的信道)仅在下次入网前有效。因此,终端设备每次重新入网之后都会使用默认参数配置,而网络服务器则根据需要对这些值重新调整。

5.1 链路检查 (LinkCheckReq和LinkCheckAns)

终端使用LinkCheckReq命令检查与网络的连通性,该命令不含荷载(payload)。网络服务器收到(一个或多个)网关转发过来的LinkCheckReq后回复一条 LinkCheckAns命令

大小(字节) 1 1
LinkCheckAns Payload Margin GwCnt
  • Margin (解调幅度)是最近一条被成功收到的LinkCheckReq 命令的链路预算(单位dB),是一个8位(bits)无符号整型,范围[0,254]。值为0 表示在解调(信号强度)的下限(0dB或者没有余量)上收到了数据,值20表示网关在比解调下限高出 20 dB 的信号强度上收到了数据。255是保留值
  • GwCnt 是最近一次成功收到 LinkCheckReq 的网关的数量。

5.2 速率自适应LinkADRReq和LinkADRAns

服务器通过发送 LinkADRReq 命令让终端设备进行速率自适应。

大小(字节) 1 2 1
LinkADRReq Payload DataRate_TXPow ChMask Redundancy 9
大小位 (bits) [7:4] [3:0]
DataRate_TXPower DataRate TXPower

数据速率(DataRate)和 TX输出功率(TXPower),两者和地理区域相关,编码参考第7章

信道掩码(ChMask)通过对相应的最低有效位填0来对上行信道进行编码,

信道列表如下:

Bit# 可用信道
0 Channel 1
1 Channel 2
.. ..
15 Channel 16

ChMask中某位是1,表示启用该位对应的上行信道(用来进行上行传输的信道),只有终端设备当前使用的数据速率可以在该信道上使用时,该信道才可以使用,如果是0,则表示对应的上行信道不可用。终端设备当前使用的信道要设为1

Bit# 7 [6:4] [3:0]
Redundancy bits 保留(RFU) ChMaskCntl NbTran
  • 冗余(Redundancy)位中,NbTrans表示每条上行消息重复发送的次数,仅用于 unconfirmed 类型的上行消息。默认值为1,表示每帧只上传一次。有效范围 [1:15]。终端设备收到NbTrans == 0时仍然使用默认值。服务器通过控制节点的上行冗余来保证给定的服务质量。终端设备在重传期间照常跳频,每次重传后也会等待接收数据,直到接收窗口过期。在RX1短暂窗口期间的任一时刻接收到下行消息都会停止该消息的重传。对于A类来说,RX2情况与RX1相同。
  • 信道掩码控制(ChMaskCntl)字段负责控制ChMask的掩码位。当网络上信道的实现超过16个,该字段必须是一个非0值。用它来控制ChMask使用哪16个信道,还可以用它来全局性的打开或关闭指定调制方式的所有信道。该字段的具体使用和地域相关,具体见第7章
  • 网络服务器可能会在一条下行消息中包含多个LinkAdrReq命令。终端设备为了配置信道掩码,会按照命令在下行消息中的出现的顺序处理所有LinkAdrReq消息。对于命令中的这些ChMaskCntl,终端设备要么全部接受要么全部拒绝,同时为它们的 LinkAdrAns 设置相同的 Channel Mask ACK 。对于 DataRate、TXPowerNbTrans ,因为它们是全局性设置(后面的值会覆盖前面的值),所以终端设备只按照命令中的最后一条LinkADRReq执行。同样,对于这些,终端设备也会为它们在 LinkAdrAns 中各自设置相同的 ACK,来指明它们最终被接受了还是被拒绝了。
  • 信道频率与地域有关,具体见第6章

终端收到LinkADRReq后回复LinkADRAns命令。

大小(字节) 1
LinkADRAns Payload Status
大小(位) [7:3] 2 1 0
Status bits RFU Power ACK Data rate ACK Channel mask ACK

LinkADRAns Status释义如下:

表:LinkADRAns状态位定义

BIT=0 BIT=1
Channel mask ACK 要使用的信道未定义,或信道掩码想关闭所有信道。忽略该命令,终端状态不改变 设置成功
Data rate ACK 终端未定义或者不支持该速率(可用信道不支持该速率),命令被忽略,终端状态不改变 设置成功
Power ACK 终端未定义该功率等级。命令被忽略,终端状态不改变 设置成功

以上三个字段任意一个是0,命令就会执行失败,而节点也保持之前的状态不变。

5.3 终端的发射占空比(DutyCycleReq和DutyCycleAns)

  • DutyCycleReq,网络协调员使用该命令来限制终端设备的总发射占空比的最大值。总发射占空比指所有子频带的发射占空比。
大小(字节) 1
DutyCycleReq Payload DutyCyclePL
Bits 7:4 3:0
DutyCyclePL RFU MaxDCyle

终端允许的发射占空比的最大值:
$$
总发射占空比=\frac{1}{2^{MaxDCycle}}
$$
MaxDutyCycle有效范围[0:15]。在没有区域调节设置占空比限制的情况下,使用 0 表示“占空比没有限制”。

注意,下面这条在LoRaWAN1.0.2中被删除:

值为 255 时要求终端设备立刻转为静默状态,等价于远程关闭终端。

终端收到DutyCycleReq后回复DutyCycleAnsDutyCycleAns不包含任何payload。

5.4 接收窗口相关参数(RXParamSetupReq,RXParamSetupAns)

通过下发RXParamSetupReq命令,可以修改第二个接收窗口(RX2)使用的频率和数据速率。该命令还可以修改下行RX1数据速率,使下行RX1的速率相对上行进行偏移。

大小(字节) 1 3
RX2SetupReq Payload DLsettings Frequency
Bits 7 6:4 3:0
DLsettings RFU RX1DRoffset RX2DataRate
  • RX1DRoffset 用来设置终端设备上行和下行第一个接收窗口(RX1)数据速率之间的偏移,默认值是0。基站在某些地域有最大功率密度限制,所以使用偏移,并且还可以用来均衡上行和下行的无线链路预算。
  • RX2DataRate 定义第二个接收窗口使用的数据速率,用法和 LinkADRReq 一样(例如,0 表示 DR0/125kHz)。Frequency 是第二个接收窗口使用的信道频率,其频率编码规则的定义见NewChannelReq 命令。
  • 终端设备回复 RXParamSetupAns。终端设备在没有收到基于A类的下行数据前,会在所有上行数据的 FOpt 中携带 RXParamSetupAns,直到收到一次基于A类的下行数据。这样可以保证及时上行链路存在丢包的情况,网络也总能知道终端设备使用的下行链路参数。

payload只有一个字节:

大小(字节) 1
RX2SetupAns Payload Status

Status位结构如下:

Bits 7:3 2 1 0
Status bits RFU RX1DRoffset ACK RX2 Data rate ACK Channel ACK

表 : RX2SetupAns 的 status bits 含义

字段 Bits=0 Bits=1
Channel ACK (对于终端)频率不可用 RX2信道设置成功
RX2 Data rate ACK (对于终端)未知的数据速率 RX2数据速率设置成功
RX1DRoffset ACK RX1上行/下行数据速率的偏移不在可用范围 设置成功

5.5 终端状态(DevStatusReq,DevStatusAns)

服务器通过发送 DevStatusReq 获取一个终端设备的状态,该命令没有payload。终端收到 DevStatusReq 之后回复DevStatusAns

大小(字节) 1 1
DevStatusAns payload Battery Margin

电池电量(Battery)上报的数据编码如下:

电量 说明
0 终端在使用外接电源
1..254 电池电量,1是最小值,254是最大值
255 终端设备无法获取电池电量

余量(Margin)是最近一次接收成功 DevStatusReq 命令的解调信噪比,其值(四舍五入)取整,单位dB。余量值是一个有符号整型,长度6个比特位,最小值 -32,最大值31。

占位 ( bits ) 7 : 6 5 : 0
Status RFU Margin

5.6 创建或修改信道(NewChannelReq, NewChannelAns)

NewChannelReq命令要么用来修改已有信道的参数,要么创建一个新的信道。该命令设置新信道的中心频率,以及在该信道上行传输的数据速率范围。

大小(字节) 1 3 1
NewChannelReq payload ChIndex Freq DrRange
  • 信道索引(ChIndex)是新信道或者待修改信道的索引值。LoRaWAN规范中已经为不同的地域和频段内置了默认信道,这些信道存在所有的设备上,而且不能通过NewChannelReq(见第6章)进行修改。如果默认的信道数量是N,那默认的信道就是 0~ N-1,而 ChIndex 可用范围就是 N~15。终端设备至少要能处理 16 个不同的信道。在某些地域终端允许存储超过16个信道。

  • 频率(Freq)是一个 24bits 无符号整型,实际信道频率是 100 × Freq Hz

    (笔记:按这个说法,433.1MHz 服务器发送的数据是 4331000)

  • 其中100MHz以下的值留待未来使用。通过这种方法可以以 100 Hz为步长,使用 100MHz~1.67GHz 之间任意的信道频率。 Freq == 0表示不使用该信道。终端设备必须对频率进行检查,保证它的射频硬件支持将要使用的频率,否则返回错误。

数据速率范围(DrRange)指明此信道的数据速率范围。该字由两个4位长的索引组成:

大小(bits) 7:4 3:0
DrRange MaxDR MinDR

根据章节5.2的定义,最小数据速率(MinDR)字段指定此信道最低数据速率,例如:0 表示指定 DR0/125 kHz。与之类似,最大数据速率指定最高数据速率。例如:DrRange = 0x77表示信道只能使用 50kbps GFSK,DrRange = 0x50表示数据速率范围是DR0 / 125 kHz 到 DR5 / 125 kHz。

  • 创建或修改的信道一旦设置成功,可以马上用来通信。RX1的下行频率与其上行频率相同。

终端回复NewChannelAns命令,其payload如下:

大小(字节) 1
NewChannelAns Payload Status

状态(Status)每位的含义如下:

大小(bits) 7:2 1 0
Status RFU Data rate range ok Channel frequency ok
Bit = 0 Bit = 1
Data rate range ok 数据速率范围超出终端当前所允许的范围 终端兼容该数据速率范围
Channel frequency ok 终端无法使用该频率 可以使用

注意:两者之中有一个是0,就表示命令执行失败,不会创建信道。

DlChannelReq允许服务器将一个不同的下行频率和RX1关联起来。所有支持 NewChannelReq 的地域也适用于 DlChannelReq (比如欧洲、中国,但美国和澳大利亚不可以,具体见第七章

该命令会设置下行RX1的中心频率:

大小(字节) 1 3
DlChannelReq Payload ChIndex Freq
  • 频率(Freq)是一个 24bits 无符号整型,实际信道频率是 100 × Freq Hz,其中100MHz以下的值留待未来使用。通过这种方法可以以 100 Hz为步长,使用 100MHz~1.67GHz 之间任意的信道频率。 Freq== 0表示不使用该信道。终端设备必须对频率进行检查,保证它的射频硬件支持将要使用的频率,否则返回错误。
  • 终端设备回复DlChannelAns。终端设备在没有收到下行数据前,会在所有上行数据的 FOpt 中携带 DlChannelAns,直到收到一次下行数据。这样可以保证及时上行链路存在丢包的情况,网络也总能知道终端设备使用的下行频率。

Payload包含以下信息:

大小(字节) 1
DlChannelAns Payload Status

Status含义如下:

Bits 7:2 1 0
Status RFU Uplink frequency exists Channel frequency ok
bit=0 bit=1
Channel frequency ok 设备无法使用该频率 设备可以使用该频率
Uplink frequency exists 该信道的上行频率未定义,下行频率只能给有效上行频率的信道设置 该信道的上行频率值有效

5.7 Rx和Tx之间的延迟(RXTimingSetupReq,RXTimingSetupAns)

RXTimingSetupReq用来配置上行传输结束(一帧数据发送完成的时刻)到打开第一个接收窗口之间的时间间隔。第二个接收窗口比第一个晚1秒打开。

大小(字节) 1
RXTimingSetupReq Payload Settings

延迟(Delay)字段指定时间间隔,由两个4位的索引组成:

大小(bits) 7:4 3:0
Settings RFU Del

延迟单位是秒(s),Del=0 表示1秒:

Del 延迟(秒)
0 1
1 1
2 2
3 3
15 15

终端设备回复RXTimingSetupAns,并且不携带payload。

终端设备在没有收到下行数据前,会在所有上行数据的 FOpt 中携带 RXTimingSetupAns,直到收到一次下行数据。这样可以保证及时上行链路存在丢包的情况,网络也总能知道终端设备使用的下行参数。

5.8 终端发射参数(TxParamSetupReq,TxParamSetupAns)

该MAC命令只在需要监管的区域执行,参考第七章

TxParamSetupReq命令可以用来通知终端设备其允许的最大驻留时间,比如:一个数据包在空中持续传输的最大时间,以及所允许的设备最大的EIRP(有效全向辐射功率)。

大小(字节) 1
TxParamSetup payload EIRP_DwellTime

EIRP_DwellTime 字段的结构如下:

Bits 7:6 5 4 3:0
MaxDwellTime RFU DownlinkDwellTime UplinkDwellTime MaxEIRP

TxParamSetupReq的 [0:3] bits用来编码 Max EIRP值,见下表:

编码值 0 1 2 3 4 5
Max EIRP(dBm) 8 10 12 13 14 16
6 7 8 9 10 11 12 13 14 15
18 20 21 24 26 27 29 30 33 36

设备无线传输的最大功率即为EIRP的最大值。设备不必使用该功率进行传输,可也不能超过该EIRP。第4、第5位定义上、下行链路最大的驻留时间 ,编码如下:

编码值 驻留时间
0 无限制
1 400 ms

该命令执行后,终端设备回复TxParamSetupAnsTxParamSetupAns不携带任何负载数据。如果在一个对此没有要求的地域使用该命令,设备不执行,并且不回复。

附加

1. 解析

  • 从LoRaWAN第4章的帧格式可以得到如下信息:MAC命令,要么使用FPort0来单独传输,要么使用非零的FPort来和数据一起传输。
  • LoRaWAN第5章,LoRaWAN出于网络管理需要,提出了9条MAC命令,这个章节是对9条命令进行具体的描述。

2. MAC命令枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*!
* LoRaMAC mote MAC commands
*
* LoRaWAN Specification V1.0.1, chapter 5, table 4
*/
typedef enum eLoRaMacMoteCmd
{
/*!
* LinkCheckReq
*/
MOTE_MAC_LINK_CHECK_REQ = 0x02,
/*!
* LinkADRAns
*/
MOTE_MAC_LINK_ADR_ANS = 0x03,
/*!
* DutyCycleAns
*/
MOTE_MAC_DUTY_CYCLE_ANS = 0x04,
/*!
* RXParamSetupAns
*/
MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05,
/*!
* DevStatusAns
*/
MOTE_MAC_DEV_STATUS_ANS = 0x06,
/*!
* NewChannelAns
*/
MOTE_MAC_NEW_CHANNEL_ANS = 0x07,
/*!
* RXTimingSetupAns
*/
MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08,
}LoRaMacMoteCmd_t;



/*!
* LoRaMAC server MAC commands
*
* LoRaWAN Specification V1.0.1 chapter 5, table 4
*/
typedef enum eLoRaMacSrvCmd
{
/*!
* LinkCheckAns
*/
SRV_MAC_LINK_CHECK_ANS = 0x02,
/*!
* LinkADRReq
*/
SRV_MAC_LINK_ADR_REQ = 0x03,
/*!
* DutyCycleReq
*/
SRV_MAC_DUTY_CYCLE_REQ = 0x04,
/*!
* RXParamSetupReq
*/
SRV_MAC_RX_PARAM_SETUP_REQ = 0x05,
/*!
* DevStatusReq
*/
SRV_MAC_DEV_STATUS_REQ = 0x06,
/*!
* NewChannelReq
*/
SRV_MAC_NEW_CHANNEL_REQ = 0x07,
/*!
* RXTimingSetupReq
*/
SRV_MAC_RX_TIMING_SETUP_REQ = 0x08,
}LoRaMacSrvCmd_t;

3. MAC命令接收处理

  • OnRadioRxDone() 携带着MAC帧进来,经过层层筛选,最终到达ProcessMacCommands() 来处理MAC命令。 这里代码中涉及的两种处理方式,可以跟协议对应起来:port = 0时,MAC命令放在FRMPayload中,需要先解密再处理;port非零时,MAC命令放在fopts中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if( port == 0 )
{
if( fCtrl.Bits.FOptsLen == 0 )
{
LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
frameLen,
nwkSKey,
address,
DOWN_LINK,
downLinkCounter,
LoRaMacRxPayload );

// Decode frame payload MAC commands
ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr );
}
} else {
if( fCtrl.Bits.FOptsLen > 0 )
{
// Decode Options field MAC commands. Omit the fPort.
ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr );
}
}

4. MAC命令的发送及回复

  • MAC命令的发送及回复处理都在这个函数中AddMacCommand()
  • 协议栈对MAC命令发送的处理还是比较简单的,都是放在Fopts中来传输,都在这个15字节的MacCommandsBuffer中。
  • LinkADR是LoRaWAN网络管理中相当重要的一个MAC命令,其解析占用了183行(把第五章的这个命令好好翻一翻,代码和协议才能对应上)
LinkADRReq的源码解析
1. 解析 DataRate_TXPower 字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

datarate = payload[macIndex++];
txPower = datarate & 0x0F;
datarate = ( datarate >> 4 ) & 0x0F;

if( ( AdrCtrlOn == false ) &&( ( LoRaMacParams.ChannelsDatarate != datarate ) || (LoRaMacParams.ChannelsTxPower != txPower ) ) )
{
#if 0
ADR disabled don't handle ADR requests if server tries to change datarate or txpower
Answer the server with fail status
Power ACK = 0
Data rate ACK = 0
Channel mask = 0
#endif
AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
macIndex += 3; // Skip over the remaining bytes of the request
break;
}

如果终端ADR没开,那么就立即丢弃本命令处理。这里的macIndex += 3是对应LinkADRReq的剩余命令长度3而言的。

2.解析 ChMask 字段
1
2
chMask = ( uint16_t )payload[macIndex++];
chMask |= ( uint16_t )payload[macIndex++] << 8;
3.解析 Redundancy 字段
1
2
3
4
5
6
7
nbRep = payload[macIndex++];
chMaskCntl = ( nbRep >> 4 ) & 0x07;
nbRep &= 0x0F;
if( nbRep == 0 )
{
nbRep = 1;
}

把字段中的 chMaskCntl 和 nbRep 都给解析了出来。

4.按地区规定处理chMaskCntl ,及判断 ChMask 有效性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#elif defined( USE_BAND_470 )
if( chMaskCntl == 6 )
{
// Enable all 125 kHz channels
for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
{
for( uint8_t j = 0; j < 16; j++ )
{
if( Channels[i + j].Frequency != 0 )
{
channelsMask[k] |= 1 << j;
}
}
}
}
else if( chMaskCntl == 7 )
{
status &= 0xFE; // Channel mask KO
}
else
{
for( uint8_t i = 0; i < 16; i++ )
{
if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
( Channels[chMaskCntl * 16 + i].Frequency == 0 ) )
{// Trying to enable an undefined channel
status &= 0xFE; // Channel mask KO
}
}
channelsMask[chMaskCntl] = chMask;
}
  • 如果 chMaskCntl 为6,则所有信道都使能。如果 chMaskCntl 为7,则由于未定义返回失败。
  • 其他有效 chMaskCntl 情况下,先检查是否有未定义的频点,如果没问题则更新对应的channelsMask。
5.判断速率有效性
1
2
3
4
if( ValidateDatarate( datarate, channelsMask ) == false )
{
status &= 0xFD; // Datarate KO
}
6.判断发射功率有效性
1
2
3
4
if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
{
status &= 0xFB; // TxPower KO
}
7.全部判断通过后更新参数
1
2
3
4
5
6
7
8
9
10
11
12
if( ( status & 0x07 ) == 0x07 )
{
LoRaMacParams.ChannelsDatarate = datarate;
LoRaMacParams.ChannelsTxPower = txPower;
LoRaMacParams.ChannelsMask[0] = channelsMask[0];
LoRaMacParams.ChannelsMask[1] = channelsMask[1];
LoRaMacParams.ChannelsMask[2] = channelsMask[2];
LoRaMacParams.ChannelsMask[3] = channelsMask[3];
LoRaMacParams.ChannelsMask[4] = channelsMask[4];
LoRaMacParams.ChannelsMask[5] = channelsMask[5];
LoRaMacParams.ChannelsNbRep = nbRep;
}
8.回复MAC命令 LinkADRAns
1
AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );

AddMacCommand 的形参只有CID加2字节的回复

六 终端激活

  • 为了加入LoRaWAN网络,每个终端需要初始化及激活。
  • 终端的激活有两种方式,一种是空中激活Over-The-Air Activation (OTAA),当设备部署和重置时使用;另一种是独立激活Activation By Personalization (ABP),此时初始化和激活这两步就在一个步骤内完成。

6.1 终端激活后的数据存储

激活后,终端会存储如下信息:设备地址(DevAddr),应用ID(AppEUI),网络会话密钥(NwkSKey),应用会话密钥(AppSKey)

6.1.1 终端地址(DevAddr)

终端地址(DevAddr)由可标识当前网络设备的32位ID所组成,具体格式如下:

Bit# [31..25] [24..0]
DevAddr bits NwkID NwkAddr

它的高7位是NwkId,用来区别同一区域内的不同网络,另外也保证防止节点窜到别的网络去。它的低25位是NwkAddr,是终端的网络地址,可以由网络管理者来分配

6.1.2 应用ID(AppEUI)

  • AppEUI是一个类似IEEE EUI64的全球唯一ID,标识终端的应用提供者。
  • APPEUI在激活流程开始前就存储在终端中
  • 就是说AppEUI是出厂时烧录进去的

6.1.3 网络会话密钥(NwkSKey)

  • NwkSKey是分配给终端设备的网络会话密钥。网络服务器设备用它来计算和校验所有消息的MIC(消息一致码),来保证收发的数据一致。也可以用来对MAC负载(MAC命令放在Payload里面)的消息进行加/解密

6.1.4 应用会话密钥(AppSKey)

  • AppSKey是分配给终端设备的应用会话密钥。网络服务器和设备用来对应用指定的 Payload字段进行加解密。也可以用来计算和校验应用层MIC(可能存放在应用指定消息的Payload中)。

6.2 空中激活(OTAA)

  • 针对空中激活,终端必须按照加网流程来和网络服务器进行数据交互。如果终端丢失会话消息,则每次必须重新进行一次加网流程
  • 加网流程需要终端准备好如下这三个参数:全局唯一设备ID(DevEUI)、应用ID(AppEUI)、AES-128密钥(AppKey)

APPEUI在上面的6.1.2)已经做了描述。

注意:无线激活时,网络密钥不会像初始化那样写死到终端,而是在终端加入网络时由网络层衍生并分发,该密钥用来对传输数据进行加密和校验。这样,终端设备能很方便的在不同的网络服务器和应用提供商之间切换。使用网络会话密钥和应用会话密钥可以避免应用数据被网络供应商(网络服务器拥有者)解析或篡改,从而接入大量的网络服务器。

6.2.1 终端 ID (DevEUI)

  • DevEUI是一个类似IEEE EUI64的全球唯一ID,标识唯一的终端设备

6.2.2 应用密钥 (AppKey)

  • AppKey是AES-128的应用密钥,由应用拥有者通过应用指定根密钥衍生并分配给终端设备,根密钥只有应用供应商知晓和掌握。终端设备通过无线激活入网时,通过AppKey衍生会话密钥 NwkSKeyAppSKey,并分发相应的终端设备,用来加密和校验网络通讯和应用数据。

6.2.3 入网流程

从终端角度看,加网流程是由和服务器的两个MAC命令交互组成的,分别是 join request 和 join accept

6.2.4 入网申请(Join-request )

  • 入网流程总是由终端发送 join-request 来发起,消息格式如下:
Size (bytes) 8 8 2
Join Request AppEUI DevEUI DevNonce
  • join-request消息包含了AppEUI和DevEUI ,后面还跟了2个字节的随机数(DevNonce)
  • DevNonce是一个随机值。终端设备最近使用的一些(数量自定义)DevNonce会保存在网络服务器 (NS)。如果终端发送的入网请求中的DevNonce在NS中可以查到,该请求就会被忽略。

注意:该机制的目的是防止重放攻击(replay attacks),避免其它人通过发送之前的入网请求来断开终端设备和网络的连接。

入网请求的消息一致性校验码(MIC)(见第4章MAC消息部分)通过下述算法计算:

① cmac = aes128_cmac(AppKey, MHDR | AppEUI | DevEUI | DevNonce)

② MIC = cmac[0..3]

  • 入网请求(join-request) 消息不用加密,即明文发送。

6.2.5 接受入网消息(Join-accept)

服务器同意终端入网后网络服务器(NS)会回复 接受入网 消息。接受入网使用 JOIN_ACCEPT_DELAY1JOIN_ACCEPT_DELAY2(而不是RECEIVE_DELAY1 和RECEIVE_DELAY2),和普通消息一样发送。这两种接收窗口使用的信道频率和数据率与 RX1和RX2的接收窗口(见章节“物理层”之”接收窗口”)相同。

  • 注意:入网请求被拒绝则服务器不发送任何数据。

    接受入网消息包含以下字段:应用层随机数(AppNonce),3字节;网络ID(NetID);终端地址(DevAddr);介于 TX 和 RX(RxDelay) 之间的延迟;信道频率的一系列配置(CFList)。CFList相关内容见第7章

大小 ( 字节 ) 3 3 4 1 1 变长 ( 16 )
接受入网 AppNonce NetID DevAddr DLSeting RxDelay CFList

AppNonce是由网络服务器产生的一个随机数或唯一ID,终端设备用它来衍生两个会话密钥:NwkSKeyAppSKey。衍生算法如下:

NwkSKey = aes128_encrypt(AppKey, 0x01 | AppNonce | NetID | DevNonce | pad16)
AppSKey = aes128_encrypt(AppKey, 0x02 | AppNonce | NetID | DevNonce | pad16)

接受入网的MIC计算方式如下:

1
2
cmac = aes128_cmac(AppKey,MHDR|AppNonce|NetID|DevAddr|DLSeting|RxDelay|CFList)
MIC = cmac[0..3]

消息本身采用 AppKey 加密,加密方式如下:

1
aes128_decrypt(AppKey, AppNonce|NetID|DevAddr|DLSeting|RxDelay|CFList|MIC)

注意:网络服务器加密接收入网消息使用的是 AEC ECB模式的解密算法。这样终端就不必再实现AES解密算法,只用AES加密即可。

DLsetting字段含有下行配置:

位(Bits) 7 6 : 4 3 : 0
DLsettings RFU RX1DRoffset RX2 Data rate

RX1DRoffset设置上下行数据速率之间的偏移(偏差),和终端设备交互的首个接收时隙(RX1)。offset默认为0。下行数据速率不能比上行的大。考虑到一些地区基站的最大功率密度限制,offset用来平衡上行和下行的无线链路余量。

上行和下行链路数据速率之间的确切关系见章节 “物理层(Physical Layer)

延时RxDelay规则和RXTimingSetupReq命令中的Delay字段相同。

6.3 ABP激活

  • 在某些情况下,终端可以独立激活。独立激活是让终端绕过 join request - join accept的加网流程,直接加入到指定网络中。
  • 独立激活终端,意味着 DevAddr 和两个会话密钥 NwkSKey 和 AppSKey 直接存储在终端中,而不是DevEUI,AppEUI,AppKey。终端在一开始就配置好了入网必要的信息。
  • 手动激活需要把 DevAddrNwkSKey以及AppSKey直接存放到终端设备,而不再需要(无线激活 (或空中激活、OTA激活、OTAA) 中的)DevEUIAppEUI以及AppKey。终端设备启动时就已经具备了加入指定LoRa网络所需要的信息。

注意: 每个终端必须要有唯一的 NwkSKey 和 AppSKey。这些协商的设备密钥不能影响其它设备的通信安全。生成密钥的流程应当保证这些密钥不能通过公开的信息以任何方式推导出来。(比如:节点地址)。

附加

本章主要对节点加网做了描述,具体有如下两种加网方式:

  • 空中激活:需要准备 DevEUI,AppEUI,AppKey 这三个参数,即设备自身MAC地址和要使用的应用(应用ID和密钥)。
  • ABP激活:直接配置 DevAddr,NwkSKey,AppSKey 这三个LoRaWAN最终通讯的参数,不再需要join流程。在这种情况下,这个设备是可以直接发应用数据的。

1. 入网激活处理源码

通过宏定义OVER_THE_AIR_ACTIVATION进行区分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
case DEVICE_STATE_JOIN:
{
#if( OVER_THE_AIR_ACTIVATION != 0 )
MlmeReq_t mlmeReq;

// Initialize LoRaMac device unique ID
BoardGetUniqueId( DevEui );

mlmeReq.Type = MLME_JOIN;

mlmeReq.Req.Join.DevEui = DevEui;
mlmeReq.Req.Join.AppEui = AppEui;
mlmeReq.Req.Join.AppKey = AppKey;

if( NextTx == true )
{
LoRaMacMlmeRequest( &mlmeReq );
}
DeviceState = DEVICE_STATE_SLEEP;
#else
// Choose a random device address if not already defined in Comissioning.h
if( DevAddr == 0 )
{
// Random seed initialization
srand1( BoardGetRandomSeed( ) );

// Choose a random device address
DevAddr = randr( 0, 0x01FFFFFF );
}

mibReq.Type = MIB_NET_ID;
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
LoRaMacMibSetRequestConfirm( &mibReq );

mibReq.Type = MIB_DEV_ADDR;
mibReq.Param.DevAddr = DevAddr;
LoRaMacMibSetRequestConfirm( &mibReq );

mibReq.Type = MIB_NWK_SKEY;
mibReq.Param.NwkSKey = NwkSKey;
LoRaMacMibSetRequestConfirm( &mibReq );

mibReq.Type = MIB_APP_SKEY;
mibReq.Param.AppSKey = AppSKey;
LoRaMacMibSetRequestConfirm( &mibReq );

mibReq.Type = MIB_NETWORK_JOINED;
mibReq.Param.IsNetworkJoined = true;
LoRaMacMibSetRequestConfirm( &mibReq );

DeviceState = DEVICE_STATE_SEND;
#endif
break;
}

2. 参数配置

主要在Comissioning.h 中,请参考源码

七 Physical Layer(物理层)

7.1 欧洲ISM频段 863-870MHz

7.1.1 欧洲 863-870 前导码

同步字见下表:

调制方式 同步字 前导码长度
LoRa 0x34 8 symbols
GFSK 0xC194C 5 byte

symbols参考资料:比特速率、码片速率和符号速率等区分

7.1.2 欧洲863-870 ISM频段信道频率

欧洲的无线电频谱的ISM频段由ETSI[EN300.220]分配。

网络运营商可以自己定义网络通道,但任何 EU868MHz 终端设备都必须实现下面三个默认信道。这些信道是所有网络网关都必须一直终监听的最小集合。

调制方式 带宽( kH ) 信道频率 ( MHz ) FSK 比特率 或 LoRa 数据率或比特率 Nb信道 占空比
LoRa 125 868.10 868.30 868.50 DR0 至 DR5\ 0.3-5kbps 3 <1%
  • 为了访问物理层,ETSI强制规定了一些限制,发射机可以在线的最大时间或者发射机每小时内可以发送的最大时间。ETSI允许使用占空比限制或者使用所谓的Listen Before Talk Adaptive Frequency Agility (LBT AFA) 传输管理。为了遵守ETSI规定,现在的LoRaWAN规范仅使用占空比对传输做限制。

  • LoRaWAN强制规定每个子带的占空比限制。给定子带上每一帧数据的发射时间和空中传输时间都会被记录下来。子带在接下来 Toff 秒之内不能再次使用,其中:

    $$ Toff_subband = \frac{TimeOnAir} {DutyCycle_subband} - TimeOnAir $$

  • 在指定子带不可用期间,设备可以通过其它子带发送数据,如果所有的子带都不可用,设备就只能等待下一次传输。设备根据可用子带调整其信道调频顺序。

  • 例如:A设备在默认信道上只传输帧数据消耗了0.5s,该信道子带的占空比 1%,那么A在接下来 49.5s 内不能再次使用整个子带(868-868.6)。

    $$49.5 = \frac{0.5} {1%} - 0.5 = {0.5}\times{100} - 0.5$$

    EU868MHz ISM 频段的终端设备的默认参数如下:

    • 默认无线传输的发送功率:14 dBm
    • EU868Mhz 频段的终端设备应能够在 863~870 MHz 频段范围内运行,并且应有至少能存储16个信道参数的信道数据的结构体。一个信道数据结构对应一个频率以及一组改频率下可用的数据速率。
    • 前三个信道是 868.1,868.3 和 868.5MHz/ DR0 至 DR5,这些参数必须在所有(EU868MHz下使用的)终端设备实现。这些默认信道不能通过 NewChannelReq 命令进行修改,以保证终端设备和网关之间存在最小的信道集合。

下表给出了终端设备用来发送入网激活请求的频率列表,入网请求传输占空比绝对不能超过 0.1%

表:EU863-870 JoinReq Channel list

解调模式 带宽[kHz] 信道频率[MHz] FSK比特率或\n\rLoRa数据速率/比特率 Nb信道 占空比
LoRa 125 864.10 864.30 864.50 868.10 868.30 868.50 DR0-DR5/0.3-5kbps 6 <0.1%

7.1.3 EU863-870 数据速率以及 节点输出功率的编码

下表是数据速率(DR)和 节点输出功率(TXPower)在 EU863-870上的编码:

表: 数据速率和TX功率

数据速率 配置 对应物理比特速率[bit/s]
0 LoRa: SF12 / 125 kHz 250
1 LoRa: SF11 / 125 kHz 440
2 LoRa: SF10 / 125 kHz 980
3 LoRa: SF9 / 125 kHz 1760
4 LoRa: SF8 / 125 kHz 3125
5 LoRa: SF7 / 125 kHz 5470
6 LoRa: SF7 / 250 kHz 11000
7 FSK: 50 kbps 50000
8..15 RFU
TXPower 配置
0 20 dBm (if supported)
1 14 dBm
2 11 dBm
3 8 dBm
4 5 dBm
5 2 dBm
6..15 RFU

7.1.4 EU863-870 JoinAccept CFList

欧洲 863-870 ISM频段的LoRaWAN在JoinAccept消息中实现了一个16字节的可选信道配置列表(CFlist)。

CFList由第4至第8这5个信道组成,每个信道都是3字节的无符号整型数字,不使用的信道填充0。所有列表里面的信道都可以使用LoRa模式的 DR0~DR5。列表最后有一个填充字节用来凑足16字节,该字节暂时无意义(保留字节)。

字节 3 3 3 3 3 1
CFList Freq Ch4 Freq Ch5 Freq Ch6 Freq CN7 Freq Ch8 RFU

7.1.5 EU863-870的LinkAdrReq命令

EU863-870的LoRaWAN支持最多16个信道,此时 ChMaskCntl 字段值是0,ChMask字段挨个 打开/关闭这16个信道。

表:ChMaskCntl 值列表

ChMaskCntl ChMask 控制的信道
0 信道 1 ~ 16
1 RFU
RFU
4 RFU
5 RFU
6 开启所有信道。设备打开所有已经定义的独立于ChMask字段的信道
7 RFU

7.1.6 EU863-870 payload最大字节数

MACPayload最大长度(单位:字节)见下表。该长度受PHY层限制,考虑到可能会有中继封装层 PHY层依赖于有效调制速率。下表同样给出了在没有FOpt的情况下,应用负载最大长度的参考值,如果FOpt字段费空,N的值可能会更小:

表 : EU863-870 payload最大长度

DataRate M(MACPayload长度) N(FRMPayload长度)
0 59 51
1 59 51
2 59 51
3 123 115
4 230 222
5 230 222
6 230 222
7 230 222
8:15 未定义 未定义

7.1.7 EU863-870 接收窗口

第一个接收窗口RX1使用和上行(使RX1开启的上行消息)相同的信道,数据速率是上行数据速率的一个函数,RX1DROffset 见下表。RX1DROffset的范围是[0:5],[6:7]是保留值。

RX1DROffset上传数据速率 (列) \ 下发数据速率RX1 slot (行) 0 1 2 3 4 5
DR0 DR0 DR0 DR0 DR0 DR0 DR0
DR1 DR1 DR0 DR0 DR0 DR0 DR0
DR2 DR2 DR1 DR0 DR0 DR0 DR0
DR3 DR3 DR2 DR1 DR0 DR0 DR0
DR4 DR4 DR3 DR2 DR1 DR0 DR0
DR5 DR5 DR4 DR3 DR2 DR1 DR0
DR6 DR6 DR5 DR4 DR3 DR2 DR1
DR7 DR7 DR6 DR5 DR4 DR3 DR2

接收窗口 RX2 使用修改后的频率和数据速率。默认参数是 869.525 MHz/DR0(SF12,125 kHz)

7.1.8 EU863-870 默认设置

下面是 EU863-870Mhz 频段相应参数的推荐值

参数 推荐值
RECEIVE_DELAY1 1 s
RECEIVE_DELAY2 2 s ( 必须是 RECEIVE_DELAY1 + 1s )
JOIN_ACCEPT_DELAY1 5 s
JOIN_ACCEPT_DELAY2 6 s
MAX_FCNT_GAP 16384
ADR_ACK_LIMIT 64
ADR_ACK_DELAY 32
ACK_TIMEOUT 2 +/- 1 s ( 1 ~ 3 的随机值 )

如果终端中实现的实际值和这些默认值不一样(比如,RECEIVE_DELAY1和RECEIVE_DELAY2延迟时间更长),这些参数的值一定要通过外带信道(out-of-band channel)通知给网络服务器。网络服务器可能会不接受与默认值不一致的参数。

其他频段相似

章节10~13详细讲解B类相关的知识,当然下面几章也是

除了帧头中FCtrl字段的保留(RFU)位,B类和A类的上行数据帧一样。B类使用A类中没有使用的RFU位:

第几位 7 6 5 4 3…0
FCtrl ADR ADRACKReq ACK ClassB FOptsLen

上行数据中的 ClassB 位设为1,来告诉网络服务器:设备已经转换为B类模式,已经准备在照预定时间接收下行ping。

下行数据的 FPending 位意义不变,仍然表示服务器上有等待发送给设备的消息。如果下行数据使用该标记,设备应当按照A类的规范来接收数据。

11 下行Ping帧格式(B类)

11.1 物理层帧格式

和A类下行帧格式一致,不过可能要按照不同的信道频率规划。

11.2 单播和组播MAC消息

消息可以是单播,也可以是组播。给一个终端设备单独发送消息使用单播,给多个终端设备发送使用组播。组播时属于同一组的设备必须使用相同的组播地址和加密密钥。LoRaWAN B类规范并没有指定这些,这就是说要远程设置组播的组,或者安全地分发组播需要的密钥相关的信息。这些信息必须要设置,要么在节点手动激活的时候一起配置,要么通过应用层配置(远程)。

  • 11.2.1单播的MAC消息格式

    单播时的,下行Ping的MAC负载(MAC payload)遵循A类规范,终端设备处理数据的方式完全相同。同时也使用相同的帧计数器,无论下行数据使用B类的 ping slot 还是使用A类的 “piggy-back” slot,计数器都会增加。

  • 11.2.2组播的MAC消息格式

    组播帧和单播帧的格式只有一些微小差别:

    • 禁止携带MAC命令,不论在FOpt还是在payload(port=0):因为组播和单播的验证稳健性不同。
    • ACKADRACKReq 必须为0,MType必须使用不需要回复的类型(Unconfirmed Data Down)。
    • 此处的FPending表示还有组播数据需要发送。一旦使用,下一次组播的接收时隙会发送一个数据帧;如果不使用,下一个组播可以带数据也可以不带数据。当接收时隙冲突时,终端可以用它来评估优先级。

12 信标捕获和追踪

终端设备由A类切换到B类之前要先接收一次网络的信标,来校正它的内部时序。终端设备进入B类模式以后,为了关闭和网络时间不一致(时基发生漂移)的内部时钟,要定期搜寻、接收网络信标。使用B类的终端有时可能会接收不到信标(超出网关连接范围、有干扰等等), 这种情况下终端设备就必须逐步扩大其信标的范围,而且 ping slots 的接收窗口也要考虑到内部时钟漂移的情况。

注: 例如,一个设备,其内部时钟精度 10ppm ,那么每个信标周期就可能会漂移 +/-1.3ms。10ppm——每秒误差百万分之十秒,表示一天会有 10×24×60×60=0.864s的误差。

12.1 最小无信标操作时间

设备在没有信标的情况下,会维持B类模式2小时(距最后一次收到信标120分钟),这种临时的没有信标的B类操作称作“无信标”操作,这些操作都依赖终端设备自身的时钟计时。

在无信标期间,为了适应终端可能出现的时钟漂移,单播、组播和信标的接收时隙必须要逐步扩大。

12.2 建立在接收上的无信标操作扩展

在120分钟“无信标”期间,终端接收到任何信标,都会重置“无信标”时间(重新从0计算)。终端设备会通过接收到的信标来修正时间漂移,并重置接收时隙的时间长度。

12.3 时间漂移最小化

终端设备可以使用信标(如果可以的话)的精度周期性的校准它们的内部时钟,并降低内部时钟频率的误差。由于定时振荡器的时间偏移与温度相关,并且可以计算出来,因此可以通过使用温度传感器进一步降低时间漂移。

13 B类下行时隙时间

13.1 定义

为保证B类终端设备操作成功,必须要在精确的时间点开启接收时隙,该时间点与基础信标有关。本节会详细介绍这些时间。

两个信标起点之间的时间间隔称作信标周期。信标以 BEACON_RESERVED 的起点作为数据传输的起始时刻。每个信标的前面都有一段守护时间,守护时间内部不会有任何 ping slot。守护时间的时间长度和所允许的最长帧在空中的传输时间一致,以此来保证守护时间之前任何时刻开始的下行数据都能被接收完,并且不会和接收信标发生冲突。ping slot的可用时间范围:从信标预留时间的结束时刻开始,到下一个信标守护时间的起始时刻结束。

表:信标时间

名称 时间长度
Beacon_period 128 s
Beacon_reserved 2.120 s
Beacon_guard 3.000 s
Beacon_window 122.880 s

信标在空中传输的时间远远小于信标为网络管理广播帧预留的时间。
信标窗口时间间隔分成 $ 2^{ 12} = 4096 $个时长为 30ms 的ping slots(ping时隙),这些时隙从第0个开始,至4095个结束。

终端设备一旦使用第 N 个时隙,就必须精确的在信标起始之后的第 Ton 秒打开接收窗口,其中Ton计算方法如下:

N是时隙索引(第N个时隙),单位ms。

最后一个ping slot在上次信标开始之后的第 beacon_reserved+4095×30ms=124970 ms 或者 下次信标开始之前的第 3030ms 打开。

13.2 随机时隙

为了避免系统冲突和 over-hearing (不确定是窃听还是过载,不过根据LoRWAN的功能推断这里应该是过载),使用随机的时隙索引,并且每个信标期间都要变化。

参数如下:

DevAddr 设备单播或组播网络地址,32位
pingNb 每个信标周期内的ping slot数量。必须是2的指数倍: 2k 其中 1≤k≤7
pingPeriod Period of the device receiver wake-up expressed in number of slots:212pingNb
pingOffset offset是个随机值,每次信标周期开始时通过计算获得。范围: 0~(pingPeriod - 1)
beaconTime 该时间在BCNPayload中,Time of the immediately preceding beacon frame
slotLen 一个ping slot的时长:30ms

为了校准(对齐)接收时隙,每个信标周期终端设备和服务器都会重新计算一个伪随机偏移。随机数生成使用AES加密算法,密钥全部由0组成:

1
2
3
Key = 16 x 0x00
Rand = aes128_encrypt(Key, beaconTime | DevAddr | pad16
pingOffset = (Rand[0] + Rand[1]x 256) modulo pingPeriod

本信标周期内使用的缝隙:

1
pingOffset + N x pingPeriod 其中 N=[0:pingNb-1]

节点在以下时间点打开接收缝隙:

缝隙 开启时刻
缝隙 1 Beacon_reserved + pingOffset x slotLen
缝隙 2 Beacon_reserved + ( pingOffset + pingPeriod ) x slotLen
缝隙 3 Beacon_reserved + ( pingOffset + 2 x pingPeriod ) x slotLen
缝隙 n Beacon_reserved + ( pingOffset + ( n-1) x pingPeriod ) x slotLen

如果终端设备同时提供一个单播以及一个或多个组播缝隙,那么在一个新的信标周期开始时,要进行多次这种计算。为单播地址计(节点网络地址:DevAddr)算一次,为每个组播地址计算一次。

单播和组播的 缝隙冲突时,终端设备的接收器优先处理组播。如果多个组播接收缝隙冲突,上次FPending标记位非0的优先处理。

使用随机化方案来避免单播时隙和组播时隙之间系统级别的冲突。如果在某个信标周期出现冲突,下一个信标周期几乎没有发生冲突的可能性。