LoRaWAN GW NS代码
2018-09-27 本文已影响36人
小鱼儿他老汉
花了两天时间,根据 Semtech 公司的报文转发网关文档,我基于Twisted完成了相关原型开发,主要是用于之后的设备模拟,设备交叉测试和服务器压力测试,同时绘制了一下相关有限状态机。
FSM
Packet ID | Enum | Direction | Header | MAC | Token | Payload |
---|---|---|---|---|---|---|
PUSH_DATA | 0 | G>>S | 12 | Yes | G(X) | stat/rxpk[] |
PUSH_ACK | 1 | G<<S | 4 | N/A | S(X) | N/A |
PULL_DATA | 2 | G>>S | 12 | Yes | G(Y) | N/A |
PULL_ACK | 4 | G<<S | 4 | N/A | S(Y) | N/A |
PULL_RESP | 3 | G<<S | 4 | N/A | S(Z) | txpk |
TX_ACK | 5 | G>>S | 4 | N/A | G(Z) | N/A |
表1: LoRaWAN 协议有限状态机
RF->>GW: New Packet Received
GW->>NS: PUSH_DATA
NS->>GW: PUSH_ACK
NS->>DB: Packet Stored
GW->>NS: PULL_DATA
NS->>GW: PULL_ACK
DB->>NS: Packet Loaded
NS->>GW: PULL_RESP
GW->>NS: TX_ACK
GW->>RF: Packet Transmitted
图1: LoRaWAN流程
文档分析
在这个网络模型中,有两个角色:
- GW即网关;
- NS即网关服务器。
NS基本上可以投入实用,对接数据库和缓存即可。而目前的GW仅仅够做压测,另外一个MicroPython移植版本还在开发中。
相比NS,GW的开发需要增加多线程编程。在原始的MicroPython设计中,有以下线程:
- UDP push data / pull data 的定时器线程,需要反复执行,其中push data对于服务器是异步事件,而pull data需要网关定时打开接受通道接受服务器下发;
- RX/TX/Timeout 事件的ISR 回调函数,来自D0/D1和对应超时定时器;
- LoRa Downlink 定时器线程,用于下发窗口空口通讯。
在多通道网关设计中,需要对多线程设计仔细规划,尤其在使用Python/Node.js这种多线程设计有缺陷的语言。相比之下,C++/Java/Lua之类的更加成熟。有必要拆解成为双通道网关,而每个双通道守护程序需要作为单独线程存在。
要淡化定制协议的存在
即便是IBM这种高大上的IT专业公司,和Semtech开发出来的这个协议,依然让我失望。这种协议的缺陷在于:
- 二进制和ASCII JSON混合在一起;
- 缺乏传输层安全,确切说安全是在应用层实现的;
- 收发状态机有限,扩展困难;
- 报文下发比较困难,尤其是GW在NAT之后时,需要GW定时发送Pull_data请求打开UDP接收端口。
虽说LoRaWANPktFwd协议在NS一侧设计比较简单,现在越来越多的LoRaWAN设计开始直接使用MQTT/TLS(也是IBM十年期的设计,但是通用性较强),并直接使用JSON作为序列化标准。即便是ESP8266这种SoC中也有足够资源来支持这些标准。一收一发,简单有效,扩展容易。
所以,在TTN接入协议中,LoRaWANPktFwd是作为Legacy(历史遗留)协议接入的。