四、Physical Message Formats

LoRa数据包结构

LoRaTM调制解调器采用隐式和显式两种数据包格式。其中,显式数据包的报头较短,主要

包含字节数、编码率及是否在数据包中使用循环冗余校验(CRC)等信息。

LoRaTM数据包包含以下三个组成部分:

前导码 可选报头 数据有效负载

前导码Preamble

  • [x] Preamble寄存器及其设置
reg_name reg_addr bits 默认值 description
RegPreambleMsb 0x20 7-0 0x00(wr) 前导码长度最高有效位
RegPreambleLsb 0x21 7-0 0x08(wr) 前导码长度最低有效位
// preamble for lora networks (nibbles swapped)
#define LORA_MAC_PREAMBLE 0x34
#define LORARegPreambleMsb 0x20
#define LORARegPreambleLsb 0x21
// 寄存器设置方法;由于LoraWAN1.0中默认为8字节的Preamble,所以不用操作该寄存器
writeReg(RegPreambleMsb, 0x00);
writeReg(RegPreambleLsb, 0x08);

由此,++Preamble值设定8字节,每个字节的值约定为0x34。++

可选报头

根据所选择的操作模式,可以选用隐式、显式两种报头。在RegModemConfig1寄存器上,通过设定ImplicitHeaderModeOn(RegModemConfig1的最低位)位选择报头类型。

显式报头:显式报头模式是默认的操作模式。在这种模式下,报头包含有效负载的相关信息,包括:

  • 以字节数表示的有效负载长度;
  • 前向纠错码率;
  • 是否打开可选的16位负载CRC。

    报头按照最大纠错码(4/8)发送。另外,报头还包含自己的CRC,使接收机可以丢弃无效的报头。

隐式报头:在特定情况下,如果有效负载长度、编码率及CRC为固定或已知,则比较有效的做法是通过调用隐式报头模式来缩短发送时间。这种情况下,需要手动设置无线链路两端的有效负载长度、错误编码率及CRC。

注意:如果将扩频因子SF设定为6,则只能使用隐式报头模式。

  • [x] PHDR寄存器及其设置
reg_name reg_addr bits description
LORARegPayloadLength 0x22 7-0 负载字节长度
LORARegPayloadMaxLength 0x23 7-0 负载长度最大值
RegModemConfig1 0x1D 7-0 RegModemConfig1

LORARegPayloadLength:负载字节长度。隐式报头模式下需要设置寄存器,以达到预期的数据包长度。不允许将寄存器值设置为 0。

LORARegPayloadMaxLength:负载长度最大值;如果报头负载长度超过该最大值,则会产生报头CRC错误。允许对长度不正确的数据包进行过滤。

#define LORARegModemConfig1                        0x1D
#define LORARegPayloadLength 0x22
#define LORARegPayloadMaxLength 0x23
// 设置可选报头为隐式
#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
  • [x] LMIC数据结构中LMIC.rps的值
  • 包括SF值、BW值、CR值、IH报头模式值、NOCRC值,LMIC数据结构参见《LoraWAN——(2)LMIC library 编程模型及API》

// Radio parameter set (encodes SF/BW/CR/IH/NOCRC)
typedef u2_t rps_t;
inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc) {
return sf | (bw<<3) | (cr<<5) | (nocrc?(1<<7):0) | ((ih&0xFF)<<8);
}

根据LMIC.rps设置的值,填写可选报头寄存器。

// configure LoRa modem (cfg1, cfg2)
if (getIh(LMIC.rps)) {
mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;
writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
}
// set ModemConfig1
writeReg(LORARegModemConfig1, mc1);

低数据速率优化

由于扩频因子较高时数据包的发送时间可能较长,因此可以选择在数据包发送和接收期间提高传输对频率变化的鲁棒性。

有效数据速率较低时,可通过LowDataRateOptimize位提高LoRa链路的鲁棒性。当单个符号传输时间超过16毫秒时,必须使用LowDataRateOptimize位。

注意: 发射机和接收机的LowDataRateOptimize位设置必须一致。

有效负载PayLoad

数据包有效负载是一个长度不固定的字段,而实际长度和纠错编码率CR则由显式模式下的报头指定或者由隐式模式下在寄存器的设置来决定。另外,还可以选择在有效负载中包含CRC码。

Uplink Messages:上行数据包结构组成

Preamble PHDR PHDR_CRC PHYPayload CRC

上行链路消息是从终端发送到的网络服务端,由一个或多个网关中继;LORA物理报头(PHDR)加上首部CRC(PHDR_CRC)都包括在LORA无线分组的显式模式中,有效载荷(PHYPayload)的完整性受CRC保护。PHDR、PHDR_CRC和PHYPayload的CRC字段由无线收发器自动插入。由此处可知,PDHR(可选报头)是收发器自动插入的,只要注意显示、隐式相关寄存器的设置即可。

Downlink Messages:下行数据包结构组成

Preamble PHDR PHDR_CRC PHYPayload

每个下行链路消息由网络服务器只发送给一个终端设备和由单个网关中继。下行链路消息使用其中LORA物理报头(PHDR)和一个首部CRC(PHDR_CRC),无线分组显式模式。

数据包组成

  • [x] PHYPayLoad组成
MHDR MACPayLoad MIC
    1. MHDRd组成
Bit 7..5 4..2 1..0
MHDR bits MType RFU Major
  • Major 协议主要版本,00为LoRaWAN R1,其他为预留。
  • MType :Message type 消息类型
MType	    Description
000 Join Request Join请求帧
001 Join Accept Join接受帧
010 Unconfirmed Data Up 上行非确认帧
011 Unconfirmed Data Down 下行非确认帧
100 Confirmed Data Up 上行确认帧
101 Confirmed Data Down 下行确认帧
110 Rejoin Request Rejoin请求帧
111 Proprietary (自定义专有帧)

数据消息既用于MAC命令也用于应用数据,他们可以被组合在一起在单个消息中传送。确认帧会被接收并答复确认,非确认帧将不答复。Proprietary(专有消息)可以用于实现与标准报文不互操作的非标准消息格式,但这些设备间必须在专有扩展上达成共识。

    1. MACPayLoad
  • [x] MACPayLoad组成
FHDR FPort(可选) FRMPayload(可选)
  • 2.1) FHDR组成
Size (bytes) 4 1 2 0..15
FHDR DevAddr FCtrl FCnt FOpts

FHDR包含终端(DevAddr)的短设备地址,一字节帧控制(FCtrl),2字节帧计数器(FCNT)和高达15字节用于传输的MAC命令的框架选项

  • DevAddr 短设备地址
  • FCnt 帧计数器

    在join accept(连接接受)之后,终端帧计数器与网络服务器为该终端上的帧计数器都被重置为0。接着FCntUp和FCntDown将以每次发送数据帧递增1次的方式在各自的方向上递增。
  • FOpts

    FOpts字段最大15个字节,用来传输MAC命令。

  • 下行链路FCtrl帧的帧头内容:
Bit 7 6 5 4 [3...0]
FCtrl bits ADR RFU ACK FPending FOptsLen
  • 上行链路FCtrl帧的帧头内容:
Bit 7 6 5 4 [3...0]
FCtrl bits ADR ADRACKReq ACK RFU FOptsLen
  • ADR 自适应数据速率

    LoRaWAN利用自适应数据速率(ADR)功能特性适应和优化的静态终端设备的数据速率。

    如果ADR位被置位时,网络将通过适当的MAC命令控制终端的数据速率。一般移动终端不推荐使用ADR功能。
  • ACK 确认位

    当接收到一个确认数据信息,接收器应响应设定了确认位(ACK)的数据帧。如果发送者是终端,网络将在完成终端发送操作之后选择一个由终端打开的接收窗口发送确认信息。如果发件人是网关,终端自己的判断发送确认。
  • FPending 帧挂起位

    待发送帧标志位(FPending)仅用于下行链路通信,表明该网关具有更多的数据等待发送,因此,要求终端尽可能通过发送另一个上行链路消息打开另一个接收窗口。
  • FOptsLen

    FCtrl字段中的FOptsLen表示FOpts字段的实际字节长度。数据帧中的FOpts字段最大15个字节,用来传输MAC命令。

FOptsLen、FOpts、Fopts端口

  1. FOptsLen=0时,Fopts字段不存在;
  2. FOptsLen != 0时,Fopts字段存在,Fopts过程不加密;如果存在FOpts字段,端口0不能使用(FPort必须是不存在或不等于0)。
  3. 如果Fport = 0时,表示FRMPayload中只有MAC command;
  4. MAC的命令不能同时出现在有效载荷字段(FRMPayload)和帧选项域(FOpts)。
  • 2.2) FPort(可选)
  1. 如果FPort为0值指示该FRMPayload只包含MAC命令;
  2. FPort值1..223(0x01..0xDF)为特定的应用程序;
  3. FPort值224..255(0xE0..0xFF)保留为将来标准化 应用程序扩展。
  • 2.3) FRMPayload(可选)

    N是应用Payload(有效载荷)的字节数;M值MAC payload 的最大长度。

    N必须等于或小于:

    N ≤ M - 1 - (length of FHDR in octets)

捎带在FOpts中的MAC Commands

在网络管理中,一套MAC命令可以只在网络服务器和终端MAC层之间进行数据交换。 MAC层命令对于应用程序、应用服务器以及终端上的应用程序来说都是不可见的。

单个数据帧可以包含任何序列的MAC命令,此时夹带在FOpts字段中;或者在FRMPayload字段中作为单独的数据帧中发送,但是此时FPort端口字段必须设置为0。捎带在FOpts中的MAC命令通常不加密发送且数据长度不得超过15个字节;放在FRMPayload 中的MAC命令始终加密发送,并且必须不超过FRMPayload的最大长度。

  • [x] Link Check commands (LinkCheckReq, LinkCheckAns)

  • [x] Link ADR commands (LinkADRReq, LinkADRAns)

  • [x] End-Device Transmit Duty Cycle (DutyCycleReq, DutyCycleAns)

  • [x] Receive Windows Parameters (RXParamSetupReq, RXParamSetupAns)

  • [x] End-Device Status (DevStatusReq, DevStatusAns)

  • [x] Creation / Modification of a Channel (NewChannelReq, NewChannelAns)

  • [x] Setting delay between TX and RX (RXTimingSetupReq, RXTimingSetupAns)

  • [x] 黄色区域解析

(4)LoraWAN:Physical Message Formats的更多相关文章

  1. (5)LoraWAN:Join procedure、Receive Windows

    网络在建立之初,终端设备启动后需要向服务端发起Jion请求(接入请求),只有在接入请求得到成功答复,并根据答复配置相关参数后,终端才算成功加入网络.Jion成功后才能进行数据的上行.下行通信. Jio ...

  2. (3)LoraWAN:链路控制、SF BW CR

    三.Introduction on LoRaWAN options 本文件描述了一种用于可为移动的或固定在一个固定位置的电池供电的终端设备而优化的LoRaWAN™网络协议.LORA™是一个由Semte ...

  3. (2)LoraWAN:Lora LMIC library 编程模型及API

    二.LMIC library 编程模型及API LMiC库可以通过一组API函数(API functions),运行时函数(run-time functions),回调函数(callback func ...

  4. Django(九)下:Ajax操作、图片验证码、KindEditor使用

    三.Ajax操作 ajax操作基于浏览器的xmlHttpRequest对象,IE低版本是另外一个对象,jQuery 1 版本对那两个对象做了封装,兼容性最好,2 .3版本不再支持IE低版本了. Aja ...

  5. 架构设计:系统间通信(20)——MQ:消息协议(下)

    (接上文<架构设计:系统间通信(19)--MQ:消息协议(上)>) 上篇文章中我们重点讨论了"协议"的重要性.并为各位读者介绍了Stomp协议和XMPP协议. 这两种协 ...

  6. GUI编程笔记(java)03:GUI的组件继承图

    1.组件继承图: 2.分析上面的组件继承图 (1)Component:public abstract class Component extends Object implements ImageOb ...

  7. kafka原理和实践(一)原理:10分钟入门

    系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...

  8. 实验四 (1):定义一个形状类(Shape)方法:计算周长,计算面积

    (1)定义一个形状类(Shape)方法:计算周长,计算面积子类:矩形类(Rectangle) :额外的方法:differ() 计算长宽差圆形类(Circle)三角形类(Triangle)正方形类(Sq ...

  9. Python(一)—— 控制流:if & for & while

    基操 编程语言类 编译型 程序在执行之前需要一个专门的编译过程,把程序编译成 为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了.程序执行效率高,依赖编译器,跨平台性差些.缺点:编译之后 ...

随机推荐

  1. jmh 微基准测试

    选择依据:对某段代码的性能测试. 1.运行方法 mvn clean install java -jar target/benchmarks.jar JMHSample_02 -f 1 2.maven ...

  2. springboot2.x整合redis

    pom文件 <!--springboot中的redis依赖--> <dependency> <groupId>org.springframework.boot< ...

  3. 19 JavaScript数组 &数组增删&最值&排序&迭代

    关联数组(散列) 关联数组又叫做散列,即使用命名索引. JavaScript数组只支持数字索引. JavaScript对象使用命名索引,而数组使用数字索引,JavaScript数组是特殊类型的对象. ...

  4. java里自定义分页查询的尝试

    public String list(){ try { LoginUser loginUser = getLoginUser();//获取当前登录用户 if(curpage<=0){ curpa ...

  5. inline-block,真的懂吗

    曾几何时,display:inline-block 已经深入「大街小巷」,随处可见 「display:inline-block; *display:inline; *zoom:1; 」这样的代码.如今 ...

  6. codeforces- Shortest path of the king

    The king is left alone on the chessboard. In spite of this loneliness, he doesn't lose heart, becaus ...

  7. Update(Stage5):Kudu_javaApi使用_Spark整合

    Table of Contents: 2.3. 安装 Zookeeper 2.4. 安装 Hadoop 2.4. 安装 MySQL 2.5. 安装 Hive 2.6. 安装 Kudu 2.7. 安装 ...

  8. C++11常用特性介绍——左值引用、右值引用

    一.左值.右值 1)左值:可以放在赋值号左侧.可以被赋值的值:左值必须要在内存中有实体. 2)右值:必须放在赋值号右侧.取出值赋值给其它变量:右值可以在内存中也可以在CPU寄存器中. 二.引用 引用是 ...

  9. python2.7 一个莫名其妙的错误

    先看看错误: Traceback (most recent call last): File "/home/darkchii/文档/PycharmProjects/ml/model.py&q ...

  10. subprocess.Popen()

    def run(): str_shell='ipconfig' sub=subprocess.Popen(args=str_shell,shell=True,stdin=subprocess.PIPE ...