
RIOT OS GNRC LoRaWAN 示例应用实战OTAA/ABP 入网、数据收发与 Link Check 完整指南【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT本篇技术指南以 RIOT OS 仓库中的 examples/networking/gnrc/lorawan/README.md 为骨架结合 gnrc_lorawan 协议栈源码与 gnrc_netif_lorawan 网络接口实现完整讲解如何使用 GNRC LoRaWAN 协议栈完成 OTAA/ABP 两种入网方式、通过 shell 命令收发数据、调整数据速率、执行 Link Check 链路检查以及接收下行数据。读完本文你将掌握在任意 RIOT 支持的 LoRa 板卡默认示例为 b-l072z-lrwan1上从编译配置到运行验证 LoRaWAN Class A 节点的完整流程。示例应用概览这个 demo 能做什么该应用是 GNRC LoRaWAN 协议栈的演示与测试程序目标是让开发者能够通过OTAAOver-The-Air Activation或ABPActivation By Personalization加入 LoRaWAN 网络发送与接收 LoRaWAN 数据包执行基础 LoRaWAN 命令如Link Check链路检查。从 Makefile 可以看到应用由以下模块组成USEMODULE netdev_default # 板卡默认网络设备 USEMODULE auto_init_gnrc_netif # GNRC 接口自动初始化 USEMODULE gnrc_lorawan # GNRC LoRaWAN MAC 协议栈 USEMODULE gnrc_pktdump # 打印下行数据的 pktdump 线程 USEMODULE shell # shell 交互 USEMODULE shell_cmds_default # 默认 shell 命令含 ifconfig/txtsnd USEMODULE gnrc_txtsnd # 从 shell 以文本方式发送 LoRaWAN 帧其中shell_cmds_default提供ifconfig命令用于配置网络接口gnrc_txtsnd提供txtsnd命令用于发送数据。若板卡默认不携带 LoRa 射频芯片可在 Makefile 中取消注释USEMODULE sx1272或USEMODULE sx1276来启用对应驱动。应用主程序 main.c 的逻辑非常简洁先把gnrc_pktdump线程注册为GNRC_NETTYPE_UNDEF类型包的接收者GNRC_NETREG_DEMUX_CTX_ALL表示接收所有上下文使任何进入协议栈的下行数据都被自动打印出来随后启动 shellgnrc_netreg_entry_t dump GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL, gnrc_pktdump_pid); gnrc_netreg_register(GNRC_NETTYPE_UNDEF, dump); shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);当前支持范围与限制文档明确说明截至该 README 版本MAC 层尚未实现占空比duty cycle限制机制但已遵循 LoRaWAN 重传流程仅支持 Class A且仅支持EU868与IN865两个区域协议栈整体仍处于实验阶段尚未完全符合 LoRaWAN 规范部分 FOps 缺失。从 gnrc_lorawan_region.c 源码可以看到当前区域相关实现由CONFIG_LORAMAC_REGION_EU_868/CONFIG_LORAMAC_REGION_IN_865两个编译期配置选择其他区域如 US915尚未实现。编译与运行构建配置与区域设置应用默认板卡为b-l072z-lrwan1ST 的 LoRa 开发板板载 SX1276 射频。编译前需要在 Makefile 中确认/设置区域。示例默认通过 CFLAGS 选择 EU868CFLAGS -DCONFIG_LORAMAC_REGION_EU_868也可以改为 IN865CFLAGS -DCONFIG_LORAMAC_REGION_IN_865编译烧录的通用流程make BOARDb-l072z-lrwan1 flash termflash会烧录固件term会打开串口终端进入 shell。启动后可以看到Initialization successful - starting the shell now提示。注意该应用没有 IP 层支持因此示例把 GNRC 包缓冲区从默认大小缩减为 512 字节以降低 RAM 占用Makefile 中CONFIG_GNRC_PKTBUF_SIZE512。Makefile.ci 中列出了因内存不足而不支持该示例的板卡如 arduino-uno、atmega328p 等可作为板卡选型的参考。所有密钥、地址和 EUI 均使用网络字节序大端序。OTAA 入网默认的接入方式应用默认采用 OTAA 方式入网Makefile 中CONFIG_LORAMAC_DEFAULT_JOIN_PROCEDURE_OTAA。只需通过ifconfig设置三项参数即可假设接口 pid 为 3ifconfig 3 set deveui AAAAAAAAAAAAAAAA ifconfig 3 set appeui BBBBBBBBBBBBBBBB ifconfig 3 set appkey CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC ifconfig 3 up各参数含义与长度deveui设备 EUIDevEUI8 字节16 个十六进制字符appeui应用 EUIAppEUI/JoinEUI8 字节若使用 ChirpStackAppEUI 会被忽略appkey应用密钥AppKey16 字节32 个十六进制字符用于 Join 流程派生会话密钥。在 shell 命令实现 gnrc_netif.c 中这些参数分别映射到NETOPT_ADDRESS_LONGdeveui、NETOPT_LORAWAN_APPEUIappeui和NETOPT_LORAWAN_APPKEYappkey。ifconfig 3 up会触发 gnrc_netif_lorawan.c 中的NETOPT_LINK处理逻辑当netif-lorawan.otaa为真时构造MLME_JOIN请求并调用gnrc_lorawan_mlme_request()发送 Join Request。等待 56 秒后输入ifconfig若入网成功链接状态应显示为upIface 3 HWaddr: 26:01:27:2F Frequency: 868500000Hz BW: 125kHz SF: 7 CR: 4/5 Link: up TX-Power: 14dBm State: SLEEP Demod margin.: 0 Num gateways.: 0 IQ_INVERT RX_SINGLE OTAA从 gnrc_netif_lorawan.c 的gnrc_lorawan_mlme_confirm()回调可以看到Join 成功confirm-status 0时网络接口会设置GNRC_NETIF_FLAGS_HAS_L2ADDR标志并向上层派发NETDEV_EVENT_LINK_UP事件这正是Link: up状态位的来源。ABP 入网通过 ifconfig 切换到个人化激活ABP 方式无需 Join 流程节点直接使用预共享的会话密钥。先关闭 OTAA再设置 AppSKey、NwkSKey 与 DevAddrifconfig 3 -otaa ifconfig 3 set appskey DDDDDDDDDDDDDDDD ifconfig 3 set nwkskey EEEEEEEEEEEEEEEE ifconfig 3 set addr FFFFFFFF ifconfig 3 upappskey应用会话密钥AppSKey16 字节用于加密应用负载nwkskey网络会话密钥NwkSKey16 字节用于网络层完整性校验与加密addr设备短地址DevAddr4 字节8 个十六进制字符。ifconfig 3 up时由于otaa标志已被清除gnrc_netif_lorawan.c 会走MLME_SET分支直接把激活方式设置为MLME_ACTIVATION_ABP因此ABP 入网立即生效无需等待网络响应。编译期静态配置密钥用 CFLAGS 固化参数如果不想每次上电都通过 shell 手工输入密钥可以把全部参数通过 CFLAGS 编译进固件。这样运行时只需选择入网方式并执行ifconfig if_pid up即可。在应用 Makefile 中对应examples/networking/gnrc/lorawan/Makefile中的配置方式CFLAGS -DCONFIG_LORAMAC_DEV_EUI_DEFAULT\AAAAAAAAAAAAAAAA\ CFLAGS -DCONFIG_LORAMAC_APP_EUI_DEFAULT\BBBBBBBBBBBBBBBB\ CFLAGS -DCONFIG_LORAMAC_APP_KEY_DEFAULT\CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\ CFLAGS -DCONFIG_LORAMAC_APP_SKEY_DEFAULT\DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\ CFLAGS -DCONFIG_LORAMAC_NWK_SKEY_DEFAULT\EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\ CFLAGS -DCONFIG_LORAMAC_DEV_ADDR_DEFAULT\FFFFFFFF\在_init()中gnrc_netif_lorawan.c 会用fmt_hex_bytes()把上述十六进制字符串解析为字节数组并分别存入deveui注意 EUI 通过memcpy_reversed做字节序反转以匹配内部表示、joineui、nwkkey、fnwksintkey等字段再构造gnrc_lorawan_key_ctx_t上下文交给gnrc_lorawan_init()。选择入网方式示例 Makefile 中通过USE_ABP变量控制# OTAA默认 CFLAGS -DCONFIG_LORAMAC_DEFAULT_JOIN_PROCEDURE_OTAA # 或 ABP CFLAGS -DCONFIG_LORAMAC_DEFAULT_JOIN_PROCEDURE_ABP示例 Makefile 中还有两个常用编译选项值得注意CONFIG_LORAMAC_DEFAULT_RX2_DR_3使用 TTN 网络时EU868 区域需将 RX2 数据速率设为 DR3CONFIG_LORAMAC_DEFAULT_DR_5FIT-IoT Lab 环境下网关较近可使用最高数据速率 DR5默认是 DR0。发送数据txtsnd 命令入网成功后使用txtsnd命令发送数据语法为txtsnd if hex_port data参数说明if是接口 pid如 3hex_port是十六进制的 LoRaWAN 端口号1223data是待发送的字符串。例如通过接口 3 向 LoRaWAN 端口 123十六进制 0x7B发送 Hello RIOT!txtsnd 3 7B Hello RIOT!从发送路径看txtsnd构造的网络层数据包经过 gnrc_netif_lorawan.c 的_send()它从 netif 头中取出目的地址即端口号port dst[0]剥掉 netif 头后根据ack_req标志构造MCPS_CONFIRMED确认帧或MCPS_UNCONFIRMED非确认帧请求连同端口、数据速率一起交给gnrc_lorawan_mcps_request()。调整数据速率ifconfig set dr默认数据速率为 DR0EU868 下对应 SF12可通过ifconfig动态修改。例如把 DR 设为 2ifconfig 3 set dr 2从 gnrc_lorawan_region.c 可以看到 GNRC LoRaWAN 目前支持 6 档数据速率EU868 与 IN865 相同对应关系如下DR扩频因子 SF带宽 BW0SF12125 kHz1SF11125 kHz2SF10125 kHz3SF9125 kHz4SF8125 kHz5SF7125 kHzgnrc_lorawan_set_dr()会先把NETOPT_BANDWIDTH和NETOPT_SPREADING_FACTOR下发给射频驱动再通过gnrc_lorawan_validate_dr()校验数据速率是否合法越界返回-EINVAL。DR 越低SF 越大灵敏度越高但速率越慢、空中时间越长。执行 Link Check链路质量检查Link Check 是 LoRaWAN 的 MAC 命令用于查询当前链路的解调余量demodulation margin与网关数量。请求会在下一次发送数据时随上行帧带给网络服务器。先请求 Link Checkifconfig 3 link_check然后发送一帧数据此时带上 Link Check 请求txtsnd 3 01 Join the RIOT!再用ifconfig查看结果此时Demod margin与Num gateways应已更新为真实值Iface 3 HWaddr: 26:01:2C:EA Frequency: 867500000Hz BW: 125kHz SF: 7 CR: 4/5 Link: up TX-Power: 14dBm State: SLEEP Demod margin.: 14 Num gateways.: 2 IQ_INVERT RX_SINGLE OTAA实现细节ifconfig 3 link_check对应NETOPT_LINK_CHECK在 gnrc_netif_lorawan.c 中会置位GNRC_NETIF_LORAWAN_FLAGS_LINK_CHECK标志下一次_send()时检测到该标志就先发起MLME_LINK_CHECK请求。当服务器返回 Link Check 应答后gnrc_lorawan_mlme_confirm()会清除该标志并把结果存入demod_margin与num_gateways字段——这就是ifconfig输出中Demod margin和Num gateways的数据来源。确认帧与非确认帧ack_req 开关LoRaWAN 支持两种上行消息类型确认帧Confirmable要求网络服务器回 ACK非确认帧Unconfirmable不需要 ACK。用ifconfig的ack_req标志控制。开启后发送的就是确认帧ifconfig 3 ack_req txtsnd 3 01 My confirmable message关闭后发送的是非确认帧ifconfig 3 -ack_req txtsnd 3 01 My unconfirmable message对应关系在源码中非常清晰shell 命令表gnrc_netif.c 中{ ack_req, NETOPT_ACK_REQ }把ack_req/-ack_req映射到NETOPT_ACK_REQgnrc_netif_lorawan.c 的_set()将其写入netif-lorawan.ack_req_send()据此选择MCPS_CONFIRMED或MCPS_UNCONFIRMED。示例 Makefile 默认通过CONFIG_LORAMAC_DEFAULT_TX_MODE_UNCNF把所有消息设为非确认帧。发送确认帧时若未收到 ACKMAC 层会按 LoRaWAN 规范执行重传。接收下行数据pktdump 输出解析在网络服务器Application Server侧为节点调度一条下行数据即可测试接收。若使用 TTN可在Applications APP Devices DEV Overview的Downlink区域操作。节点每次发送上行数据后LoRaWAN 网络服务器会在 RX1/RX2 接收窗口内回送下行数据。为简化演示本应用将下行数据直接交给 GNRC pktdump 打印例如PKTDUMP: data received: ~~ SNIP 0 - size: 2 byte, type: NETTYPE_UNDEF (0) 00000000 AA AA ~~ SNIP 1 - size: 9 byte, type: NETTYPE_NETIF (-1) if_pid: 3 rssi: -32768 lqi: 0 flags: 0x0 src_l2addr: (nil) dst_l2addr: 01 ~~ PKT - 2 snips, total size: 11 byte解读dst_l2addr: 01表示这条下行数据被发送到了端口 1if_pid: 3说明数据来自接口 3。这正是 main.c 中把 pktdump 注册到GNRC_NETTYPE_UNDEF的效果——所有未识别类型的包都会被转交到gnrc_pktdump_pid打印。下行接收在底层由 gnrc_lorawan.c 的接收回调驱动收到MTYPE_JOIN_ACCEPT走 Join 处理收到MTYPE_CNF_DOWNLINK/MTYPE_UNCNF_DOWNLINK走gnrc_lorawan_mcps_process_downlink()最终通过gnrc_lorawan_mcps_indication()把负载与端口信息封装成 netif 头并派发到上层注册的接收者即 pktdump。源码级原理解析MAC 状态机与接收窗口为帮助理解上述行为这里补充 GNRC LoRaWAN 协议栈的若干底层机制实现见 gnrc_lorawan.c 与 gnrc_lorawan_internal.hMAC 状态机LORAWAN_STATE_IDLE空闲、LORAWAN_STATE_RX_1RX1 窗口、LORAWAN_STATE_RX_2RX2 窗口、LORAWAN_STATE_TX发送中、LORAWAN_STATE_JOIN入网中。发送完成回调把状态切到RX_1并根据是否已激活决定使用CONFIG_LORAMAC_DEFAULT_JOIN_DELAY1还是rx_delay来定时打开 RX1 窗口RX1 超时后自动切换到 RX2 窗口CONFIG_LORAMAC_DEFAULT_RX2_FREQ频率、CONFIG_LORAMAC_DEFAULT_RX2_DR数据速率RX2 也超时则回到 IDLE。这解释了文档中State: SLEEP与 56 秒入网等待时间的行为来源。Class A 时序Class A 设备只在发送后的 RX1/RX2 窗口接收下行窗口关闭后进入睡眠这正是State: SLEEP的含义。频道管理gnrc_lorawan_channels_init()初始化默认信道gnrc_lorawan_pick_channel()从信道掩码中随机挑选发送信道EU868 默认 868.1/868.3/868.5 MHz 三个默认信道收到 Join Accept 中的 CFList 后由gnrc_lorawan_process_cflist()扩展信道列表。占空比如前所述MAC 层尚未实现完整的 duty cycle 限制但已保留重传机制backoff预算相关宏在 gnrc_lorawan_internal.h 中有定义。当前状态与后续规划README 明确指出当前 GNRC LoRaWAN 协议栈仍处于实验阶段尚未完全符合 LoRaWAN 规范——缺少占空比限制与部分 FOpsMAC 命令。规划中的下一步工作包括增加更多区域支持US915 等实现自适应数据速率ADR实现占空比限制增加 RTC 支持用于持久化的帧计数与时间管理。从 gnrc_lorawan_1_1 相关源码MODULE_GNRC_LORAWAN_1_1可以看出LoRaWAN 1.1 的密钥体系AppKey/NwkKey/FNwkSIntKey/SNwkSIntKey/NwkSEncKey 分离与 DevNonce 持久化写入 flashpage已在代码层面初步支持可通过在 Makefile 中取消注释USEMODULE gnrc_lorawan_1_1来启用。常见问题与排查建议Link: down持续不变化确认 deveui/appeui/appkey 与网络服务器ChirpStack、TTN 等中注册的设备一致确认区域配置EU868/IN865与网关一致OTAA 入网通常需要数秒等待后再查ifconfig。确认帧无响应确认ack_req已开启且网络服务器支持 ACK 回复Class A 的 ACK 只在下一次下行时捎带不一定立即可见。下行数据收不到确认下行端口与上行发送端口一致检查 pktdump 输出中的dst_l2addr字段并确认应用服务器在下行队列中有待发送数据。内存不足若编译失败提示 RAM 不足可参考 Makefile.ci 中的板卡列表换用内存更大的板卡。若需要进一步深入可阅读协议栈头文件 net/gnrc/lorawan.h 与 MAC 层公共头文件 net/loramac.h其中包含CONFIG_LORAMAC_DEFAULT_DR、CONFIG_LORAMAC_DEFAULT_DEVICE_CLASS等全部默认值定义以及 region 相关接口 net/gnrc/lorawan/region.h。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考