本文档描述了LoRaWAN网络协议,是针对电池供电的终端设备(不管移动还是固定位置)进行优化的一套网络协议。
LoRaWAN网络通常采用星型拓扑结构,由拓扑中的网关来转发终端与后台网络服务器间的消息。网关通过标准IP连接来接入网络服务器,而终端则通过单跳的 LoRa 或者 FSK 来和一个或多个网关通讯。虽然主要传输方式是终端上行传输给网络服务器,但所有的传输通常都是双向的。
终端和网关间的通讯被分散到不同的信道频点和数据速率上。数据速率的选择需要权衡距离和消息时长两个因素,使用不同数据速率的设备互不影响。LoRa的数据速率范围可以从 到 50kbps。为了最大程度地延长终端的电池寿命和扩大网络容量,LoRa网络使用速率自适应(ADR)机制来管理每个终端的速率和RF输出。
虽然每个设备可以在任意信道,任意时间,发送任意数据,但需要注意遵守如下规定:
•
终端的每次传输都使用伪随机方式来改变信道。频率的多变使得系统具有更强的抗干扰能力。
终端要遵守相应频段和本地区的无线电规定中的发射占空比要求。 终端要遵守相应频段和本地区的无线电规定中的发射时长要求。
• •
twowinter注:发射占空比,意思是发射时长占总时长的比例。按照无线电规定,每个设备不能疯狂发射霸占信道,总得给别人一点机会。
这份文档主要讲述协议细节,一些基于各地区规定的操作参数,例如发射占空比和发射时长等,在另一份文档[LoRaWAN地区参数]中做具体描述。将这份文档分开,是为了加入新地区参数时不影响基础的协议规范。
LoRaWAN Classes
所有的LoRaWAN设备都必须至少实现本文档描述的 Class A 功能。另外也可以实现本文档中描述的 Class B 和 Class C 及后续将定义的可选功能。不管怎么样,设备都必须兼容 Class A。
文档约定
MAC命令的格式写作LinkCheckReq(粗斜体),位和位域的格式写作
FRMPayload(粗体),常量的格式写作 RECEIVE_DELAY1,变量的格式写作 N。 在本文档中,
• • •
所有多字节字段的字节序均采用小端模式 EUI 是8字节字段,采用小端模式传输 默认所有RFU保留位都设为0
第2章 LoRaWAN Classes 类型介绍
LoRa 是由Semtech面向长距离、低功耗、低速率应用而开发的无线调制技术。本文档中,将 Class A 基础上实现了更多功能的设备称为“更高 class 终端”。
LoRaWAN Classes
LoRa网络包含基础LoRaWAN(称之为Class A)和可选功能(Class B,Class C):
? 图 Classes
•
双向传输终端(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?
更加耗电,但同时从服务器下发给终端的时延也是最短的。
•
文档范围
这份LoRaWAN协议还描述了与 Class A 不同的其他 Class 的额外功能。更高 Class 的终端必须满足 Class A 定义的所有功能。
注意:物理层帧格式,MAC帧格式,以及协议中更高 class 和 Class A 相同的内容都写在了 Class A 部分,避免内容重复。 第3章 PHY 帧格式
LoRa 有上行消息和下行消息。
上行消息
上行消息是由终端发出,经过一个或多个网关转发给网络服务器。
上行消息使用 LoRa 射频帧的严格模式,消息中含有 PHDR 和 PHDR_CRC 。载荷有CRC校验来保证完整性。
PHDR,PHDR_CRC 及载荷 CRC 域都通过射频收发器加入。
上行 PHY:
Preamble 图2.上行PHY帧格式
PHDR PHDR_CRC PHYPayload CRC 下行消息
下行消息是由网络服务器发出,经过单个网关转发给单个终端。 下行消息使用射频帧的严格模式,消息中包含 PHDR 和 PHDR_CRC。
下行 PHY:
Preamble 图3.下行PHY帧格式
PHDR PHDR_CRC PHYPayload 接收窗口
每个上行传输后终端都要开两个短的接收窗口。接收窗口开始时间的规定,是以传输结束时间为参考。
?
图4.终端接收时隙的时序图
第一接收窗口的信道,数据速率和启动。
第一接收窗口 RX1 使用的频率和上行频率有关,使用的速率和上行速率有关。RX1 是在上行调制结束后的 RECEIVE_DELAY1 秒打开。上行和 RX1 时隙下行速率的关系是按区域规定,详细描述在[LoRaWAN地区参数]文件中。默认第一窗口的速率是和最后一次上行的速率相同。
第二接收窗口的信道,数据速率和启动。
第二接收窗口 RX2 使用一个固定可配置的频率和数据速率,在上行调制结束后的 RECEIVE_DELAY2 秒打开。频率和数据速率可以通过 MAC 命令(见 第5章)。默认的频率和速率是按区域规定,详细描述在[LoRaWAN地区参数]文件中。 接收窗口的持续时间
接收窗口的长度至少要让终端射频收发器有足够的时间来检测到下行的前导码。 接收方在接收窗口期间的处理
如果在任何一个接收窗口中检测到前导码,射频收发器需要继续激活,直到整个下行帧都解调完毕。如果在第一接收窗口检测到数据帧,且这个数据帧的地址和MIC校验通过确认是给这个终端,那终端就不必开启第二个接收窗口。 网络发送消息给终端
如果网络想要发一个下行消息给终端,它会精确地在两个接收窗口的起始点发起传输。
接收窗口的重要事项
终端在第一或第二接收窗口收到下行消息后,或者在第二接收窗口阶段,不能再发起另一个上行消息。 其他协议的收发处理
节点在LoRaWAN收发窗口阶段可以收发其他协议,只要终端能满足当地要求以及兼容LoRaWAN协议。
2 梳理解析
LoRaWAN第3章,主要是讲了接收窗口这回事,只要记住张图就行。
目前RX1一般是在上行后1秒开始,RX2是在上行后2秒开始。
3 源码分析
源码流程
在梳理这章节的对应代码时,自己手动做了张思维导图。有时是这样,代码再有层次感,也不及一个图。好,请收下。
发送完成就开始RX1和RX2延时
static void OnRadioTxDone( void ) { ... . }
接收窗口的射频处理
从上面一步,我们已经清晰的知道,对应的处理肯定是在
OnRxWindow1TimerEvent和OnRxWindow2TimerEvent中。?
这两个接收窗口的处理,会对速率和信道进行设置,按照中对各地区的要求分别进行处理。
比如这个470的处理,对上行信道对48取余得到下行信道。
RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 48 ) * LORAMAC_STEPWIDTH_
第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 图载荷结构 MAC载荷:
Join-Response MIC FHDR 图载荷结构 FHDR:
FPort FRMPayload DevAddr 图8.帧头结构
FCtrl FCnt FOpts 图帧格式元素(即图5~8)
MAC层(PHYPayload)
Size (bytes) 1 1..M 4 PHYPayload MHDR MACPayload MIC MACPayload字段的最大长度M,在第6章有详细说明。
MAC头(MHDR字段)
Bit# 7..5 4..2 1..0 MHDR bits MType RFU Major MAC头中指定了消息类型(MType)和帧编码所遵循的LoRaWAN规范的主版本号(Major)。
消息类型(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 消息
join-request和join-accept都是用在空中激活流程中,具体见章节
•
Data messages 用来传输MAC命令和应用数据,这两种命令也可以放在单个消息中发送。?
Confirmed-data message 接收者需要应答。?
Unconfirmed-data message 接收者则不需要应答。?
Proprietary messages 用来处理非标准的消息格式,不能和标准消息互通,只能用来和具有相同拓展格式的消息进行通信。
不同消息类型用不同的方法保证消息一致性,下面会介绍每种消息类型的具体情况。
数据消息的主版本(Major位字段)
描述 Major位字段 00 LoRaWAN R1 01..11 表列表
RFU 注意:Major定义了激活过程中(join procedure)使用的消息格式(见章节)和MAC Payload的前4字节(见第4章)。终端要根据不同的主版本号实现不同最小版本的消息格式。终端使用的最小版本应当提前通知网络服务器。
MAC载荷(MACPayload)
MAC载荷,也就是所谓的“数据帧”,包含:帧头(FHDR)、端口(FPort)以及帧载荷(FRMPayload),其中端口和帧载荷是可选的。
帧头(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 •
帧头中 自适应数据速率 的控制(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,其它情况下不需要。
•
消息应答位及应答流程(ACK in FCtrl)
收到confirmed类型的消息时,接收端要回复一条应答消息(应答位ACK要进行置位)。如果发送者是终端,网络就利用终端发送操作后打开的两个接收窗口之一进行回复。如果发送者是网关,终端就自行决定是否发送应答。? 应答消息只会在收到消息后回复发送,并且不重发。
注意:为了让终端尽可能简单,尽可能减少状态,在收到confirmation类型需要确认的数据帧,需要立即发送一个严格的应答数据帧。或者,终端会延迟发送应答,在它下一个数据帧中再携带。
•
重传流程
当需要应答却没收到应答时就会进行重发,重发的个数由终端自己定,可能每个终端都不一样,这个参数也可以由网络服务器来设置调整。 注意:一些应答机制的示例时序图在第18章中有提供。
注意:如果终端设备重发次数到达了最大值,它可以降低数据速率来重连。至于后面是否再重发还是说丢弃不管,都取决于终端自己。
注意:如果网络服务器重发次数到达了最大值,它就认为该终端掉线了,直到它再收到终端的消息。一旦和终端设备的连接出现问题时,要不要重发都取决于网络服务器自己。
注意:在重传期间的数据速率回退的建议策略在章节中有描述。
•
帧挂起位(FPending in FCtrl 只在下行有效)
帧挂起位(FPending)只在下行交互中使用,表示网关还有挂起数据等待下发,需要终端尽快发送上行消息来再打开一个接收窗口。 FPending的详细用法在章节。
•
帧计数器(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数值,除非是重传。
• •
帧可选项(FOptsLen in FCtrl, FOpts)?
FCtrl 字节中的FOptsLen位字段描述了整个帧可选项(FOpts)的字段长度。
FOpts字段存放MAC命令,最长15字节,详细的MAC命令见章节。
如果FOptsLen为0,则FOpts为空。在FOptsLen非0时,则反之。如果MAC命令在FOpts字段中体现,port0不能用(FPort要么不体现,要么非0)。
MAC命令不能同时出现在FRMPayload和FOpts中,如果出现了,设备丢掉该组数据。
端口字段(FPort)
如果帧载荷字段不为空,端口字段必须体现出来。端口字段有体现时,若FPort的值为0表示FRMPayload只包含了MAC命令;具体见章节中的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载荷的最大长度。
MAC帧载荷加密(FRMPayload)
如果数据帧携带了载荷,FRMPayload必须要在MIC计算前进行加密。?
加密机制是采用的AES128。
默认的,加密和加密由LoRaWAN层来给所有的FPort来执行。如果加密/解密由应用层来做更方便的话,也可以在LoRaWAN层之上给特定FPorts来执行,除了端口0。具体哪个节点的哪个FPort在LoRaWAN层之外要做加解密,必须要和服务器通过out-of-band信道来交互(见第19章)。
•
的加密
密钥K根据不同的FPort来使用:
FPort K 0 NwkSKey 1..255 表3: FPort列表
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 Dir DevAddr FCntUp FCntDown or 0x00 i 0x00 方向字段(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。
• •
消息校验码(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 Dir 0x00 DevAddr FCntUp or 0x00 len(msg) FCntDown 方向字段(Dir)在上行帧时为0,在下行帧时为1.
LoRaWAN第4章,主要讲述了MAC帧格式,对所有涉及的字段都做了解释。
千言万语汇成一句话,哦不,汇成一个表。 数据帧头 DevAddr FCtrl FCnt FOpts 数据帧 PreaPHPHDRMHDR FHDR FPort FRMPMCmble DR _CRC ayload IC RC MAC层 PHY层 PreaPHPHDRMHDR MACPayload MCmble DR _CRC IC RC PreaPHPHDRPHYPayload CRC mble DR _CRC 好了,帧格式是大家随手都能看到的东西,本尊作为IoT小能手,如果不能提出一些稍有深度的信息增量,就对不起这个称号了。所以,有些协议设计层面的心得要分享下:
1. 特别酷的ADR(速率自适应)机制?
2. 这个章节中最亮眼的莫过于速率自适应机制,简直是为LoRa网络量身定做
的:一旦使能了FCtrl中的ADR位,距离近信号好的节点用高速率,距离
远信号弱的节点用低速率,不小心被调高了速率,则自动降下来。这样,尽可能地提高了传输速率,也有效提高了网络容量。我已经见过不少厂家,拿这个协议的公知特点当产品卖点了。 3. 可同时携带数据和命令的MAC帧?
4. 一般来说,应用除了数据,出于管理需要,肯定还会涉及命令。比如基站
要查询节点状态,或者节点要请求变更信道等。所以LoRaWAN协议设计上利用FOpts把数据和命令揉在一个MAC帧里,这样可以提高交互效率,有效地降低功耗。这在寸土寸金,哦不,寸库仑(电量单位)寸金的物联网应用中,是一个很有必要的设计。
3 源码解析
这章的处理基本都在 \\src\\mac\\ 中,下面按照MAC帧格式的字段逐个解析下。
MAC层MHDR
在LoRaWAN的数据API中处理了MHDR,这个字段内容比较少,就按需选择了消息类型是confirm还是unconfirm。?
另外在管理API中的Join-Req的消息类型。
具体可见 LoRaMacMcpsRequest() 和 LoRaMacMlmeRequest() 这两个函数。
MACPayload
MACPayload 的组帧都在 PrepareFrame() 这个函数中处理,将macHdr和macPayload的fCtrl、FPort、FRMPayload都传递进去,完成整个MAC层的数据组帧。
LoRaMacBuffer就存放了MACPayload的数据,这个变量的组帧和协议字段定义是一一对应。MACPayload的组帧处理,在大流程上是对join和数据两种类型的帧分别处理,用两个case分开。
为了方便阅览,我把函数代码框架提炼了出来。
LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ) {
switch( macHdr-> ) {
case FRAME_TYPE_JOIN_REQ: ....
fCtrl-> = AdrNextDr( fCtrl->, true, & ); ...
if( SrvAckRequested == true ) {
SrvAckRequested = false; fCtrl-> = 1; }
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value; LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF; .
Omit the fPort. ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr ); } }
MAC命令的发送及回复
MAC命令的发送及回复处理都在这个函数中,AddMacCommand()。
协议栈对MAC命令发送的处理还是比较简单的,都是放在Fopts中来传输,都在这个15字节的MacCommandsBuffer中。
LinkADR是LoRaWAN网络管理中相当重要的一个MAC命令,其解析占用了183行。索性专门写篇源码解析,记录下。
阅读此文前,最好再把第五章的这个命令好好翻一翻,代码和协议才能对应上。 我正在陆续对协议的各个章节进行翻译,具体其他章节的译文,以及译文之外的代码解析,可点此查看帖子。?
本文作者twowinter,转载请注明作者:
LinkADRReq 的源码解析
按照代码思路走一遍。
1.解析 DataRate_TXPower 字段
datarate = payload[macIndex++]; txPower = datarate & 0x0F;
datarate = ( datarate >> 4 ) & 0x0F; if( ( AdrCtrlOn == false ) &&
( ( != datarate ) || ( != txPower ) ) )
{
析 ChMask 字段
chMask = ( uint16_t )payload[macIndex++]; chMask |= ( uint16_t )payload[macIndex++] << 8;
3.解析 Redundancy 字段
nbRep = payload[macIndex++]; chMaskCntl = ( nbRep >> 4 ) & 0x07; nbRep &= 0x0F; if( nbRep == 0 )
{
nbRep = 1; }
把字段中的 chMaskCntl 和 nbRep 都给解析了出来。
4.按地区规定处理 chMaskCntl ,及判断 ChMask 有效性
#elif defined( USE_BAND_470 ) if( chMaskCntl == 6 ) {
requency != 0 ) {
channelsMask[k] |= 1 << j; } } } }
else if( chMaskCntl == 7 ) {
status &= 0xFE; requency == 0 ) ) {
断速率有效性
if( ValidateDatarate( datarate, channelsMask ) == false ) {
status &= 0xFD;
断发射功率有效性
if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
{
status &= 0xFB;
部判断通过后更新参数
if( ( status & 0x07 ) == 0x07 ) {
= datarate; = txPower;
memcpy1( ( uint8_t* ), ( uint8_t* )channelsMask, sizeof( ) ); = nbRep; }
8.回复MAC命令 LinkADRAns
AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
突然发现 AddMacCommand 的形参只有CID加2字节的回复,我是太无聊,把终端所有MAC命令都翻了一遍,确认所有payload确实是小于2字节。再次赞扬LoRaWAN协议的精简作风。
第6章 终端激活
为了加入LoRaWAN网络,每个终端需要初始化及激活。
终端的激活有两种方式,一种是空中激活 Over-The-Air Activation (OTAA),当设备部署和重置时使用; 另一种是激活 Activation By Personalization (ABP),此时初始化和激活这两步就在一个步骤内完成。
twowinter 备注: ABP 这个词不太好翻译,通常会翻成个性化激活,也就是通过配置参数的方式激活。但总感觉少点味道,与空中激活摆在一起,感觉
激活这个词在语义上更有并列感。当然这是我的主观感觉,建议大家和同行交流时,还是说 ABP激活 吧。
终端激活后的数据存储
激活后,终端会存储如下信息:设备地址(DevAddr),应用ID(AppEUI),网络会话密钥(NwkSKey),应用会话密钥(AppSKey)。
•
终端地址(DevAddr)
终端地址(DevAddr)由可标识当前网络设备的32位ID所组成,具体格式如下:
Bit# [31..25] [24..0] DevAddr bits NwkID NwkAddr 它的高7位是NwkId,用来区别同一区域内的不同网络,另外也保证防止节点窜到别的网络去。它的低25位是NwkAddr,是终端的网络地址,可以由网络管理者来分配。
•
应用ID(AppEUI)?
•
AppEUI是一个类似IEEE EUI的全球唯一ID,标识终端的应用提供者。?
•
APPEUI在激活流程开始前就存储在终端中。
•
网络会话密钥(NwkSKey)
NwkSKey被终端和网络服务器用来计算和校验所有消息的MIC,以保证数据完整性。也用来对单独MAC的数据消息载荷进行加解密。
•
应用会话密钥(AppSKey)
AppSKey被终端和网络服务器用来对应用层消息进行加解密。当应用层消息载荷有MIC时,也可以用来计算和校验该应用层MIC。
空中激活 OTAA
针对空中激活,终端必须按照加网流程来和网络服务器进行数据交互。如果终端丢失会话消息,则每次必须重新进行一次加网流程。?
加网流程需要终端准备好如下这三个参数:DevEUI,AppEUI,AppKey。
APPEUI在上面的已经做了描述。
注意:对于空中激活,终端不会初始化任何网络密钥。只有当终端加入网络后,才会被分配一个网络会话密钥,用来加密和校验网络层的传输。通过这样,使得终端在不同网络间的漫游处理变得方便。同时使用网络和应用会话密钥,使得网络服务器中的应用数据,不会被网络提供者读取或者篡改。
•
终端 ID (DevEUI)?
•
DevEUI 是一个类似IEEE EUI的全球唯一ID,标识唯一的终端设备。
•
应用密钥(AppKey)?
•
AppKey 是由应用程序拥有者分配给终端,很可能是由应用程序指定的根密钥来衍生的,并且受提供者控制。当终端通过空中激活方式加入网络,AppKey用来产生会话密钥NwkSKey和AppSKey,会话密钥分别用来加密和校验网络层和应用层数据。
•
加网流程?
从终端角度看,加网流程是由和服务器的两个MAC命令交互组成的,分别是 join request 和 join accept。
•
•
Join-request 消息?
•
加网流程总是由终端发送 join-request 来发起。
Size (bytes) 8 8 2 Join Request AppEUI DevEUI DevNonce join-request 消息包含了AppEUI 和 DevEUI ,后面还跟了2个字节的声明 DevNonce。
DevNonce 是一个随机值。网络服务器为每个终端记录过去的 DevNonce 数值,如果相同设备发出相同的 DevNonce 的join request就会忽略。
join-request 消息的MIC数值(见第4章 MAC帧格式)按照如下公式计算:
cmac = aes128_cmac(AppKey, MHDR | AppEUI | DevEUI | DevNonce)? MIC = cmac[0..3]
join-request 消息不用加密。
• •
Join-accept 消息? 待补充。
激活 ABP
在某些情况下,终端可以激活。激活是让终端绕过 join request - join accept的加网流程,直接加入到指定网络中。
激活终端,意味着 DevAddr 和两个会话密钥 NwkSKey 和 AppSKey 直接存储在终端中,而不是DevEUI,AppEUI,AppKey。终端在一开始就配置好了入网必要的信息。
每个终端必须要有唯一的 NwkSKey 和 AppSKey。这样,一个设备的密钥被破解也不会造成其他设备的安全性危险。创建那些密钥的过程中,密钥不允许通过公开可用信息获得(例如节点地址)。
2 梳理解析
LoRaWAN第6章,主要对节点加网做了描述,它有两种方式。如果要用一句话来总结的话,那就是这一句了,请看:
如果是空中激活,则需要准备 DevEUI,AppEUI,AppKey 这三个参数,即设备自身MAC地址和要使用的应用(应用ID和密钥)。?
如果是ABP激活,则直接配置 DevAddr,NwkSKey,AppSKey 这三个LoRaWAN最终通讯的参数,不再需要join流程。在这种情况下,这个设备是可以直接发应用数据的。
这里插个题外话,商用的LoRaWAN网络一般都是走OTAA流程,这样安全性才得以保证。
(twowinter,你数数,这是一句话)?
(如果是空中激活,则需要准备 DevEUI,AppEUI,AppKey来join。如果是ABP激活,则直接配置 DevAddr,NwkSKey,AppSKey。)
3 代码位置
激活处理
协议的第6章,相关的核心代码是这么几行,位于 \\src\\mac\\。?
整个代码结构非常清晰,用一个宏(OVER_THE_AIR_ACTIVATION)分开两段,分别对应两种激活方式。
case DEVICE_STATE_JOIN: {
#if( OVER_THE_AIR_ACTIVATION != 0 ) MlmeReq_t mlmeReq;
•
Some of the many improvements include: - India: added support for the country’s 865 MHz band, which enabled the recent deployment
announced by Tata Communications that includes managing data from 200,000 sensors and
gateways using Hewlett Packard Enterprise’s Universal IoT platform. - Australia: the LoRa Alliance demonstrated its responsiveness to the constantly changing
technical landscape by rapidly adding support for Australia’s recent regulatory change to its
ISM band. These changes greatly extend the maximum range and payloads of LoRaWAN
networks, using even the lowest data rates. - Korea: expanded Korean band capabilities.
- Global: added more consistent support for regions where the maximum allowed transmit
power is expressed as equivalent isotropic radiated power (EIRP). This EIRP support makes it
much easier for network operators to manage heterogeneous devices while ensuring
regulatory compliance.
简单梳理下:
印度新增865MHz频段,这为塔塔通讯近期宣布的 20 万传感器和基站节点建设计划进行了规范铺路。更新提及塔塔通讯将使用 HPE 的 IoT平台,HPE是惠普2015年分出来的技术公司,主攻云平台这块,这个知识点大家伙做个简单备忘。
另外一个大的更新应该是澳大利亚地区,澳大利亚最近更新了ISM频段的监管要求,这使得LoRaWAN可以极大地提高了载荷容量,特别是低速率情况下的数据量,你知道吗以前澳大利亚在最低速率只能发11字节。
在公告中,官方还发布了最新的网络覆盖图,可以明显看到大洋洲这块转为了公开部署网络的国家。
前言
在中已经为中国规划了470频段,因此国内开发者对此需求很强烈。
在最新(2017-02-27)的版本协议栈上已经新增了中国470频段。这篇文章从源码角度解析下其实现方式。
目前国内的LoRaWAN基站产品都和标准有一些不同,比如CLAA等,所以搞清楚整个代码实现还是很有必要的。只要熟悉了整个流程,对接任何一个基站都不是难事。
我正在陆续对协议的各个章节进行翻译,具体其他章节的译文,以及译文之外的代码解析,可点此查看帖子。?
本文作者twowinter,转载请注明作者:
源码解析
1.前导码格式的源码实现
同步字的处理在SX1276的驱动中:
void SX1276SetPublicNetwork( bool enable ) {
SX1276SetModem( MODEM_LORA ); if( enable == true ) {
道频率的源码实现
先说上行信道的处理。
第一步,初始化时把所有信道6*16=96个上行信道都使能了。
[0] = 0xFFFF; [1] = 0xFFFF; [2] = 0xFFFF; [3] = 0xFFFF; [4] = 0xFFFF; [5] = 0xFFFF;
第二步,紧接着把96个信道的频点赋值一遍。
for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ ) {
Channels[i].Frequency = + i * 200e3; Channels[i]. = ( DR_5 << 4 ) | DR_0; Channels[i].Band = 0; }
第三步,发送时在SetNextChannel中选择合适的频点,默认是96个信道中随机选择。
Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
这上面是上行信道处理三部曲,下行信道处理则轻松多了。主要是配合接收窗口处理,由这个宏定义了下行的起始频点。具体可以看下面第7点。
#define LORAMAC_FIRST_RX1_CHANNEL ( (uint32_t) )
3.数据速率和节点发射功率编码
速率编码如下:
const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7 };
发射功率编码如下:
const int8_t TxPowers[] = { 17, 16, 14, 12, 10, 7, 5, 2 };
速率范围如下:
/*!
* Minimal datarate that can be used by the node */
#define LORAMAC_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node */
#define LORAMAC_TX_MAX_DATARATE DR_5 /*!
* Minimal datarate that can be used by the node */
#define LORAMAC_RX_MIN_DATARATE DR_0 /*!
* Maximal datarate that can be used by the node */
#define LORAMAC_RX_MAX_DATARATE DR_5 /*!
* Default datarate used by the node */
#define LORAMAC_DEFAULT_DATARATE DR_0
发射功率范围如下:
/*!
* Minimal Tx output power that can be used by the node */
#define LORAMAC_MIN_TX_POWER TX_POWER_2_DBM /*!
* Maximal Tx output power that can be used by the node */
#define LORAMAC_MAX_TX_POWER TX_POWER_17_DBM /*!
* Default Tx output power used by the node */
#define LORAMAC_DEFAULT_TX_POWER TX_POWER_14_DBM
中国没有。具体见OnRadioRxDone中的FRAME_TYPE_JOIN_ACCEPT分支。
命令
对于 ChMaskCntl 的处理都在 ProcessMacCommands() 的 SRV_MAC_LINK_ADR_REQ 分支中。
小彩蛋一个:你发现没,注释里写着Channel mask KO。不知是djaeckle (loramac-node的作者之一)调皮,还是语言习惯如此。
if( chMaskCntl == 6 ) {
requency != 0 ) {
channelsMask[k] |= 1 << j; } } } }
else if( chMaskCntl == 7 ) {
status &= 0xFE; requency == 0 ) ) {/*!
大载荷长度
* Maximum payload with respect to the datarate index. Cannot operate with repeater. */
const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 222, 222 }; /*!
* Maximum payload with respect to the datarate index. Can operate with repeater. */
const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222 };
这在RxWindowSetup()进行处理,调用了最终的驱动函数。
if( RepeaterSupport == true ) {
( modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); } else {
( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); }
7.接收窗口处理。
RX1的处理在OnRxWindow1TimerEvent()中,满足协议要求。
RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 48 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, datarate, bandwidth, symbTimeout, false );
RX2的默认参数见如下宏:
#define RX_WND_2_CHANNEL , DR_0 }
RX2的处理在OnRxWindow2TimerEvent()中:
if( {
RxSlot = 1; }
速率偏移处理如下:
datarate = - ; if( datarate < 0 ) {
datarate = DR_0; }
8.默认设置
目前基本各地区的参数都一样,因此协议栈也是直接共用如下参数:
/*!
* Class A&B receive delay 1 in ms */
#define RECEIVE_DELAY1 1000 /*!
* Class A&B receive delay 2 in ms */
#define RECEIVE_DELAY2 2000 /*!
* Join accept receive delay 1 in ms */
#define JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept receive delay 2 in ms */
#define JOIN_ACCEPT_DELAY2 6000 /*!
* Class A&B maximum receive window delay in ms */
#define MAX_RX_WINDOW 3000 /*!
* Maximum allowed gap for the FCNT field */
#define MAX_FCNT_GAP 16384
第8章 Class B 介绍
这章描述了LoRaWAN Class B层,这是为电池节点优化设计的,不管它是移动还是固定在某个位置。
Class B 的终端必须执行如下操作,为了获得服务端发起的下行消息,终端必须按要求开启一个固定间隔的接收窗口。
LoRaWAN Class B 可以选择在终端上增加一个异步接收窗口。
LoRaWAN Class A 的之一就是终端发送数据使用的Aloha;这使得客户应用程序或者服务端不能在确定时间内定位终端。Class B 的目的就是在Class A 终端随机上行后的接收窗口之外,让终端也能在可预见的时间内开启接收。Class B 是让网关周期发送信标来同步网络中的所有终端,为此终端需要在周期时隙的确定时间点打开一个短的接收窗口(叫做“ping slot”)。
注意:是否要从Class A 切换到 Class B,这个要在终端的应用层进行处理。如果打算从网络端将Class A 切换到 Class B,客户程序只能利用终端 Class A的上行包来反馈一个下行包给节点,需要应用层上处理来识别这个请求 - 这个处理不在LoRaWAN层面。 第17章 持续接收的终端
具备Class C 能力的终端,通常应用于供电充足的场景,因此不必精简接收时间。
Class C 的终端不能执行 Class B 。
Class C 终端会尽可能地使用 RX2 窗口来监听。按照 Class A 的规定,终端是在 RX1 无数据收发才进行 RX2 接收。为了满足这个规定,终端会在上行发送结束和 RX1 接收窗口开启之间,打开一个短暂的 RX2 窗口,一旦 RX1 接收窗口关闭,终端会立即切换到 RX2 接收状态; RX2 接收窗口会程序打开,除非终端需要发送其他消息。
注意:没有规定节点必须要告诉服务端它是 Class C 节点。这完全取决于服务端的应用程序,它们可以在 join 流程通过协议交互来获知是否是 Class C 节点。
Class C 的第二接收窗口持续时间
Class C 设备执行和 Class A 一样的两个接收窗口,但它们没有关闭 RX2 ,除非他们需要再次发送数据。因此它们几乎可以在任意时间用 RX2 来接收下行消息,包括MAC命令和ACK传输的下行消息。另外在发送结束和 RX1 开启之间还打开了一个短暂的RX2窗口。
图 C 终端的接收时隙时序图
Class C 对多播下行的处理
和 Class B 类似,Class C 设备也可以接收多播下行帧。多播地址和相关的 NWKSKEY 及 APPSKEY 都需要从应用层获取。Class C 多播下行帧也有相同的:
•
不允许携带MAC命令,既不能放在FOpts域中,也不能放在 port 0 的 payload 中,因为多播下行无法像单播帧那样具备相同的鲁棒性。
•
ACK 和 ADRACKReq 位必须要为0。MType 域需要为 Unconfirmed Data Down 类型的数值。
•
FPending 位表明有更多的多播数据要发送。考虑到 Classs C 设备在大部分时间处于接收状态,FPending位不触发终端的任何特殊行为。
这个目录包含了编译一个多通道基站库所需的源码。编译之后就会生成固定链接的。
lora_gateway\\libloragw\st? 目录下还有不同子模块的程序。
HAL介绍
这部分也就是LoRa集中器的HAL层(LoRa concentrator Hardware
Abstraction Layer),它是个C库,让大家使用少量的C函数就可以对LoRa集中器芯片进行配置硬件,以及收发数据包。
LoRa集中器是数字化的多信道多数据包标准的射频芯片,使用LoRa或者FSK模式进行收发数据。
HAL的组成
这个库是由6(8)个模块组成:
•
loragw_hal
主模块,包含高等级函数来配置和使用集中器
•
loragw_reg
这个模块用来操作集中器的寄存器
•
loragw_spi
通过SPI接口来操作集中器的寄存器
•
loragw_aux
包含一个主机需要的wait_ms函数,用于指定ms的延时
•
loragw_gps
通过基准时基来同步集中器内部计数,例如例程中的GPS授时。
•
loragw_radio
配置 SX125x 和 SX127x。
•
loragw_fpga (only for SX1301AP2 ref design)
SX1301AP2参考设计才需要,用于操作FPGA的寄存器,以及配置FPGA功能。
•
loragw_lbt (only for SX1301AP2 ref design)
SX1301AP2参考设计才需要,用于配置和使用LBT功能。
软件编译
软件细节
这个库按照ANSI C99进行编写。loragw_aux模块中的ms精确延时含有POSIX格式函数,平台可以用硬件定时器进行重写。 编译选项
中 DEBUG_xxx 如果置为1,则会用 fprintf 输出对应的调试信息。 编译流程
对于交叉编译,需要设置 Makefile 中的 ARCH 和 CROSS_COMPILE 变量,或者在 shell 环境中,使用正确的工具链名字和路径。例如:
export PATH=/home/foo/rpi-toolchain/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x/bin:$PATH export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabihf-
libloragw目录下的Makefile会解析 文件,产生一个的C头文件,包含 #define 选项。那些选项会使能或禁用 文件和 *.c 原文件中的代码。 也用来直接选择动态链接库。 导出
如果想在其他系统使用编译后的库,你需要导出这些文件:
• • • • •
libloragw/ -> 根配置文件 libloragw/ -> 静态库 libloragw/ -> license要求
libloragw/inc/ -> 从 衍生出的C配置标志
libloragw/inc/loragw_*.h -> 你需要用到的头文件 (例如. _hal and _gps)
在这个库链接到你的应用之后,只有 license 文件要求在程序文件中拷贝和保留。
硬件条件
硬件版本
loragw_reg 和 loragw_hal 是针对Semtech硬件编写的特殊版本:
• •
Semtech SX1301 芯片
Semtech SX1257 or SX1255 收发器
如果硬件版本和库版本不匹配的话,这个库将无法使用。你可以用 test_loragw_reg 来测试软硬件是否匹配。
SPI通信
loragw_spi 的SPI函数适合平台相关的,如果你用别的SPI接口可能需要重写这个函数:
• • •
SPI master matched to the Linux SPI device driver (provided) SPI over USB using FTDI components (not provided) native SPI using a microcontroller peripheral (not provided)
你可以用 test_loragw_spi 来测试SPI通信。
GPS接收
为了使用库中的GPS模块,主机必须要通过串口连接GPS接收器,串口连接必须以“tty”设备出现在 /dev/ 目录,启用这个程序的用户必须用读写这个设备的权限。使用 chmod a+rw 来允许所有用户能操作指定的tty设备,或者使用sudo来运行你的程序(例如. sudo ./test_loragw_gps)。
当前版本,库只从串口读取数据,在GPS接收器上电后会收到他们发出NMEA帧 以及 u-blox 模块私有的 UBX 消息。
GPS接收器必须在发出PPS脉冲后发出UBX消息,让内部集中器的时间戳可以用GPS时基校准。如果GPS接收器发出了GGA NMEA语句,gateway则可以进行3D定位。
使用
设置软件环境
对一个典型应用,你需要这么做:
• • •
源码中包含
编译时链接 静态库文件
由于 loragw_aux 的依赖关系,需要链接 librt 库
如果应用需要直接访问集中器配置寄存器的话(例如做些高级配置),你还需要这样做:
•
源码中包含
使用软件API
要在你的应用中使用 HAL,需要遵守如下规则:
• • •
在射频启动之前需要配置好 radios path 和 IF+modem path 只有在调用了 start 函数之后,配置才会传送给硬件
只有在 radio 使能,同时IF+modem 使能,以及集中器启动后,才能接收数据包。
• •
只有在 radio 使能,以及集中器启动后,才能发送数据包。 改变配置之前,必须停止集中器。
一个对HAL的典型应用流程图如下:
/!\\ 注意,lgw_send 在LoRa集中器仍然发包时,或者即使在准备开始发包时,是非阻塞立即返回。当有数据包在发送时,将无法收到任何数据。 你的应用需要考虑发包的时长,或者在尝试发包前检查下状态(使用 lgw_status)。 当前一包未完成时立即发一包,会导致前一包无法发送,或者发送部分(会导致接收端出现CRC错误)。 调试模式 为了调试程序,可以激活调试信息后( 在 中设置 DEBUG_HAL=1 ),编译 loragw_hal 函数。这样就会输出很多细节信息,包括stderr的错误细节信息。 2.帮助程序 工程中的这些程序提供了一些示例,应该如何使用HAL库。帮助系统构建者单独测试不同部分。 . util_pkt_logger This software is used to set up a LoRa concentrator using a JSON configuration file and then record all the packets received in a log file, indefinitely, until the user stops the application. 这个软件用来让LoRa集中器使用JSON配置文件,以及记录所有的包于一个log文件,除非用户停止这个应用。 . util_spi_stress This software is used to check the reliability of the link between the host platform (on which the program is run) and the LoRa concentrator register file that is the interface through which all interaction with the LoRa concentrator happens. 这个软件用来检测主CPU与LoRa协调器寄存器文件的连接的稳定性。 . util_tx_test This software is used to send test packets with a LoRa concentrator. The packets contain little information, on no protocol (ie. MAC address) information but can be used to assess the functionality of a gateway downlink using other gateways as receivers. 这个软件用来做发包测试。包里没有协议信息,但可以用来检测基站下行功能,使用另一台基站来做接收。 . util_tx_continuous This software is used to set LoRa concentrator in Tx continuous mode, for spectral measurement. 这个软件用来设置LoRa集中器为持续TX模式,用于频谱测试。 . util_spectral_scan This software is used to scan the spectral band in background, where the LoRa 这个软件用来扫描基站工作环境的频段。 . util_lbt_test This software is used to test \"Listen-Before-Talk\" channels timestamps. 这个软件用来测试“Listen-Before-Talk”的信道时间戳。 3. 帮助脚本 . This script must be launched on IoT Start Kit platform to reset concentrator chip through GPIO, before starting any application using the concentrator. 这个脚本仅在 IoT Start Kit 平台上运行,用于在启动任何应用前,通过GPIO复位集中器芯片。 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- awee.cn 版权所有 湘ICP备2023022495号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务