1. LoRaWAN 终端节点入网参数规划与频段选择
任务目标
搭建一个基于SX1301/1308芯片的单通道LoRaWAN网关,使其能够接收来自LoRa节点的上行数据包,并通过UDP协议将数据转发至LoRaWAN网络服务器(如ChirpStack)。本案例聚焦于网关核心转发逻辑的最小可复现实现。
环境与依赖
- 硬件:Raspberry Pi(或任意Linux主机)+ SX1301/1308 LoRa concentrator板卡
- 系统依赖:
libmpsse、spi-dev(内核已启用SPI) - 软件依赖:
lora_gateway(Semtech HAL库)、packet_forwarder(Semtech UDP转发程序) - 网络服务器:ChirpStack(本地或远程,默认端口1700/UDP)
核心实现
以下代码为单通道网关的最小转发实现,基于Semtech HAL库的lgw_receive与lgw_send接口,将接收到的LoRa数据包封装为JSON格式并通过UDP发送至服务器:
// single_chan_gw.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "loragw_hal.h"
#include "loragw_gps.h"
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 1700
#define RADIO_FREQ 868100000 // 868.1 MHz
static int udp_sock;
static struct sockaddr_in server_addr;
// 构造ChirpStack兼容的JSON上行数据
static void build_pull_resp_json(struct lgw_pkt_rx *pkt, char *buf, size_t size) {
snprintf(buf, size,
"{\"rxpk\":[{\"time\":\"%s\",\"tmst\":%u,\"freq\":%lu,"
"\"chan\":0,\"rfch\":0,\"stat\":1,\"modu\":\"LORA\","
"\"datr\":\"SF%dBW125\",\"codr\":\"4/5\",\"lsnr\":%.1f,"
"\"rssi\":%d,\"size\":%u,\"data\":\"",
pkt->utc_time, pkt->count_us, pkt->freq_hz,
pkt->datarate, pkt->snr, pkt->rssi, pkt->size);
// Base64编码payload
static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (int i = 0; i < pkt->size; i += 3) {
uint32_t n = pkt->payload[i] << 16;
if (i+1 < pkt->size) n |= pkt->payload[i+1] << 8;
if (i+2 < pkt->size) n |= pkt->payload[i+2];
char tmp[4] = {b64[(n>>18)&63], b64[(n>>12)&63],
(i+1<pkt->size)?b64[(n>>6)&63]:'=',
(i+2<pkt->size)?b64[n&63]:'='};
strncat(buf, tmp, size - strlen(buf) - 1);
}
strncat(buf, "\"}]}", size - strlen(buf) - 1);
}
int main(void) {
// 初始化网关硬件
if (lgw_board_setconf(BOARD_SX1301) != LGW_HAL_SUCCESS) {
fprintf(stderr, "Board config failed\n");
return -1;
}
lgw_radio_setconf(RADIO_TYPE_SX1257, 0, RADIO_FREQ);
lgw_radio_setconf(RADIO_TYPE_SX1257, 1, RADIO_FREQ);
lgw_channel_setconf(0, 0, RADIO_FREQ, 0, 125000);
lgw_rxrf_setconf(0, 0, RADIO_FREQ, 125000, 0);
lgw_rxif_setconf(0, 0, 0, 125000, 0, 0);
if (lgw_start() != LGW_HAL_SUCCESS) {
fprintf(stderr, "Gateway start failed\n");
return -1;
}
// 创建UDP socket
udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
printf("Single-channel gateway running on %lu Hz...\n", RADIO_FREQ);
// 主接收循环
struct lgw_pkt_rx pkt;
char json_buf[512];
while (1) {
memset(&pkt, 0, sizeof(pkt));
if (lgw_receive(1, &pkt) == LGW_HAL_SUCCESS && pkt.size > 0) {
build_pull_resp_json(&pkt, json_buf, sizeof(json_buf));
sendto(udp_sock, json_buf, strlen(json_buf), 0,
(struct sockaddr*)&server_addr, sizeof(server_addr));
printf("Forwarded packet: %u bytes\n", pkt.size);
}
usleep(1000); // 1ms轮询间隔
}
lgw_stop();
close(udp_sock);
return 0;
}
编译与运行
# 编译(需链接Semtech HAL库)
gcc -o single_chan_gw single_chan_gw.c -I/opt/lora_gateway/libloragw \
-L/opt/lora_gateway/libloragw -lloragw -lpthread -lm
# 运行(需root权限访问SPI)
sudo ./single_chan_gw
验证方法
- 硬件检查:运行
dmesg | grep spi确认SPI设备已识别;执行cat /proc/spidev查看spidev设备节点。 - 服务器监听:在ChirpStack服务器端执行
tcpdump -i any udp port 1700,观察是否有来自网关的UDP数据包。 - 端到端测试:使用LoRa节点(如SX1276)发送一个上行数据包,网关控制台应打印
Forwarded packet: N bytes,同时服务器端tcpdump应捕获到包含rxpk字段的JSON数据。 - 通过条件:服务器成功解析出上行数据且RSSI/SNR值在合理范围(RSSI通常在-30~-120 dBm之间),即判定网关搭建成功。
常见问题
- SPI通信失败:确认
/boot/config.txt中已启用dtparam=spi=on,且板卡接线正确。 - 收不到数据:检查频率设置是否与节点一致(本案例默认868.1MHz),并确认天线已连接。
- UDP发送失败:确认服务器IP/端口可达,且防火墙未屏蔽1700端口。