LoRaWAN网关源码分析(集中器篇)

目录

一、前言

二、主函数逻辑

三、lgw_start函数

四、lgw_connect函数

五、lgw_soft_reset函数


一、前言

        对于lora_pkt_fwd.c主函数实现功能的流程不熟悉的话,可以看上一篇文章。本篇文章就集中器开始进行整理。

二、主函数逻辑

    i = lgw_start();
    if (i == LGW_HAL_SUCCESS) 
    {
        MSG("INFO: [main] concentrator started, packet can now be received\n");
    }
    else 
    {
        MSG("ERROR: [main] failed to start the concentrator\n");
        exit(EXIT_FAILURE);
    }    

        首先,调用 lgw_start() 函数启动集中器,并将返回值赋给变量 i。然后检查 lgw_start() 的返回值,以确定集中器是否成功启动:

成功---调用 MSG 宏输出信息:“INFO: [main] concentrator started, packet can now be received”,通知用户集中器已经成功启动,并且可以接收数据包。

失败---调用 MSG 宏输出错误信息:“ERROR: [main] failed to start the concentrator”,通知用户启动集中器失败。然后调用 exit(EXIT_FAILURE) 退出程序,表示程序因错误退出。

三、lgw_start函数

        该函数用于初始化和启动一个 LoRa 集中器设备。接下来我们来看看该函数是如何实现功能的吧!

1、检查设备是否已经启动

if (lgw_is_started == true) 
{
    DEBUG_MSG("Note: LoRa concentrator already started, restarting it now\n");
}

2、连接到设备(lgw_connect函数下面已经整理了)

reg_stat = lgw_connect(false, rf_tx_notch_freq[rf_tx_enable[1]?1:0]);
if (reg_stat == LGW_REG_ERROR) 
{
    DEBUG_MSG("ERROR: FAIL TO CONNECT BOARD\n");
    return LGW_HAL_ERROR;
}

3、重置寄存器(lgw_soft_reset函数下面已经整理了)

lgw_soft_reset();
lgw_reg_w(LGW_GLOBAL_EN, 0);
lgw_reg_w(LGW_CLK32M_EN, 0);

4、启动和重置射频电台

lgw_reg_w(LGW_RADIO_A_EN,1);
lgw_reg_w(LGW_RADIO_B_EN,1);
wait_ms(500);
lgw_reg_w(LGW_RADIO_RST,1);
wait_ms(5);
lgw_reg_w(LGW_RADIO_RST,0);

5、配置射频电台

err = lgw_setup_sx125x(0, rf_clkout, rf_enable[0], rf_radio_type[0], rf_rx_freq[0]);
if (err != 0) 
{
    DEBUG_MSG("ERROR: Failed to setup sx125x radio for RF chain 0\n");
    return LGW_HAL_ERROR;
}
err = lgw_setup_sx125x(1, rf_clkout, rf_enable[1], rf_radio_type[1], rf_rx_freq[1]);
if (err != 0) 
{
    DEBUG_MSG("ERROR: Failed to setup sx125x radio for RF chain 0\n");
    return LGW_HAL_ERROR;
}

6、配置外部数字滤波器

lgw_reg_w(LGW_GPIO_MODE,31);
lgw_reg_w(LGW_GPIO_SELECT_OUTPUT,2);

7、配置LBT(Listen Before Talk)功能

if (lbt_is_enabled() == true) 
{
    lgw_reg_w(LGW_CLK32M_EN, 1);
    i = lbt_setup();
    if (i != LGW_LBT_SUCCESS) 
    {
        DEBUG_MSG("ERROR: lbt_setup() did not return SUCCESS\n");
        return LGW_HAL_ERROR;
    }
    lgw_reg_w(LGW_CLK32M_EN, 0);
    i = lbt_start();
    if (i != LGW_LBT_SUCCESS) 
    {
        DEBUG_MSG("ERROR: lbt_start() did not return SUCCESS\n");
        return LGW_HAL_ERROR;
    }
}

8、启用时钟

lgw_reg_w(LGW_GLOBAL_EN, 1);
lgw_reg_w(LGW_CLK32M_EN, 1);

9、选择和发送校准命令

cal_cmd = 0;
cal_cmd |= rf_enable[0] ? 0x01 : 0x00;
cal_cmd |= rf_enable[1] ? 0x02 : 0x00;
cal_cmd |= (rf_enable[0] && rf_tx_enable[0]) ? 0x04 : 0x00;
cal_cmd |= (rf_enable[1] && rf_tx_enable[1]) ? 0x08 : 0x00;
cal_cmd |= 0x10;

switch (rf_radio_type[0]) {
    case LGW_RADIO_TYPE_SX1255:
        cal_cmd |= 0x20;
        break;
    case LGW_RADIO_TYPE_SX1257:
        cal_cmd |= 0x00;
        break;
    default:
        DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type[0]);
        break;
}

cal_time = 2300;

10、加载校准固件并启动MCU

load_firmware(MCU_AGC, cal_firmware, MCU_AGC_FW_BYTE);
lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL, 0);
lgw_reg_w(LGW_RADIO_SELECT, cal_cmd);
lgw_reg_w(LGW_MCU_RST_1, 0);

11、检查固件版本

lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, FW_VERSION_ADDR);
lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
fw_version = (uint8_t)read_val;
if (fw_version != FW_VERSION_CAL) 
{
    printf("ERROR: Version of calibration firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_CAL);
    return -1;
}

12、启动校准并检查校准状态

lgw_reg_w(LGW_PAGE_REG, 3);
lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 0);
DEBUG_PRINTF("Note: calibration started (time: %u ms)\n", cal_time);
wait_ms(cal_time);
lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 1);

lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
cal_status = (uint8_t)read_val;
if ((cal_status & 0x81) != 0x81) 
{
    DEBUG_PRINTF("ERROR: CALIBRATION FAILURE (STATUS = %u)\n", cal_status);
    return LGW_HAL_ERROR;
}

13、获取和检查校准偏移值

for(i=0; i<=7; ++i) 
{
    lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA0+i);
    lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
    cal_offset_a_i[i] = (int8_t)read_val;
    lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA8+i);
    lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
    cal_offset_a_q[i] = (int8_t)read_val;
    lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB0+i);
    lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
    cal_offset_b_i[i] = (int8_t)read_val;
    lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB8+i);
    lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
    cal_offset_b_q[i] = (int8_t)read_val;
}

14、调整常数并配置频率漂移

lgw_constant_adjust();
x = 4096000000 / (rf_rx_freq[0] >> 1);
x = ( x > 63 ) ? 63 : x;
lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT, x);

x = 4096000000 / (rf_rx_freq[0] >> 3);
x = ( x > 63 ) ? 63 : x;
lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT, x);

15、配置LoRa多通道解调器

radio_select = 0;
for(i=0; i<LGW_MULTI_NB; ++i) 
{
    radio_select += (if_rf_chain[i] == 1 ? 1 << i : 0);
}

16、配置LoRa单独解调器

lgw_reg_w(LGW_IF_FREQ_8, IF_HZ_TO_REG(if_freq[8]));
if (if_enable[8] == true) {
    lgw_reg_w(LGW_MBWSSF_RADIO_SELECT, if_rf_chain[8]);
    switch(lora_rx_bw) {
        case BW_125KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 0); break;
        case BW_250KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 1); break;
        case BW_500KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 2); break;
        default:
            DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_bw);
            return LGW_HAL_ERROR;
    }
    switch(lora_rx_sf) {
        case DR_LORA_SF7: lgw_reg_w(LGW_MBWSSF_RATE_SF, 7); break;
        case DR_LORA_SF8: lgw_reg_w(LGW_MBWSSF_RATE_SF, 8); break;
        case DR_LORA_SF9: lgw_reg_w(LGW_MBWSSF_RATE_SF, 9); break;

四、lgw_connect函数

        这段代码主要用于连接 LoRa 集中器,并且在连接成功后进行一些初始化操作。以下是代码的详细解释:

代码主干部分

int lgw_connect(bool spi_only, uint32_t tx_notch_freq) 
{
    int spi_stat = LGW_SPI_SUCCESS;
    uint8_t u = 0;
    int x;

    /* check SPI link status */
    if (lgw_spi_target != NULL) 
    {
        DEBUG_MSG("WARNING: concentrator was already connected\n");
        lgw_spi_close(lgw_spi_target);
    }

    /* open the SPI link */
    spi_stat = lgw_spi_open(&lgw_spi_target);
    if (spi_stat != LGW_SPI_SUCCESS) 
    {
        DEBUG_MSG("ERROR CONNECTING CONCENTRATOR\n");
        return LGW_REG_ERROR;
    }
  • lgw_connect 函数接受两个参数:spi_only 表示是否仅使用 SPI,tx_notch_freq 是传输时的不可用频率。
  • 首先,代码检查当前的 SPI 链接状态,如果已经连接了集中器,则关闭当前连接。
  • 然后,尝试打开 SPI 链接,如果打开失败,则输出错误信息并返回错误代码 LGW_REG_ERROR
    if (spi_only == false ) {
        /* Detect if the gateway has an FPGA with SPI mux header support */
        /* First, we assume there is an FPGA, and try to read its version */
        spi_stat = lgw_spi_r(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, loregs[LGW_VERSION].addr, &u);
        if (spi_stat != LGW_SPI_SUCCESS) {
            DEBUG_MSG("ERROR READING VERSION REGISTER\n");
            return LGW_REG_ERROR;
        }
        if (check_fpga_version(u) != true) {
            /* We failed to read expected FPGA version, so let's assume there is no FPGA */
            DEBUG_PRINTF("INFO: no FPGA detected or version not supported (v%u)\n", u);
            lgw_spi_mux_mode = LGW_SPI_MUX_MODE0;
        } else {
            DEBUG_PRINTF("INFO: detected FPGA with SPI mux header (v%u)\n", u);
            lgw_spi_mux_mode = LGW_SPI_MUX_MODE1;
            /* FPGA Soft Reset */
            lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 1);
            lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 0);
            /* FPGA configure */
            x = lgw_fpga_configure(tx_notch_freq);
            if (x != LGW_REG_SUCCESS) {
                DEBUG_MSG("ERROR CONFIGURING FPGA\n");
                return LGW_REG_ERROR;
            }
        }

        /* check SX1301 version */
        spi_stat = lgw_spi_r(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, loregs[LGW_VERSION].addr, &u);
        if (spi_stat != LGW_SPI_SUCCESS) {
            DEBUG_MSG("ERROR READING CHIP VERSION REGISTER\n");
            return LGW_REG_ERROR;
        }
        if (u != loregs[LGW_VERSION].dflt) {
            DEBUG_PRINTF("ERROR: NOT EXPECTED CHIP VERSION (v%u)\n", u);
            return LGW_REG_ERROR;
        }

        /* write 0 to the page/reset register */
        spi_stat = lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, loregs[LGW_PAGE_REG].addr, 0);
        if (spi_stat != LGW_SPI_SUCCESS) {
            DEBUG_MSG("ERROR WRITING PAGE REGISTER\n");
            return LGW_REG_ERROR;
        } else {
            lgw_regpage = 0;
        }
    }

 如果 spi_only 参数为 false,则执行以下操作:

  • 检测网关是否具有带有 SPI 复用器头的 FPGA 支持。
  • 尝试读取 FPGA 版本,如果成功读取到版本号则进行 FPGA 的软复位和配置。
  • 检查 SX1301 芯片的版本号,并且确保版本号与期望的版本号相符。
  • 将值 0 写入页/复位寄存器,以重置寄存器页为默认页。
    DEBUG_MSG("Note: success connecting the concentrator\n");
    return LGW_REG_SUCCESS;
}

        最后,在成功连接集中器后输出成功信息,并返回 LGW_REG_SUCCESS 表示连接成功。

五、lgw_soft_reset函数

        这个函数实现了软重置功能,用于重置集中器模块。

1、检查SPI连接

if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) 
{
    DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
    return LGW_REG_ERROR;
}

        这里首先检查了是否已经初始化了 SPI 连接,并且检查了是否已经设置了正确的寄存器页(lgw_regpage)。如果 SPI 连接未初始化或者寄存器页设置不正确,就会打印错误消息并返回 LGW_REG_ERROR

2、发送软重置命令

lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0, 0x80); /* 1 -> SOFT_RESET bit */

这行代码向 SX1301 芯片的指定目标(LGW_SPI_MUX_TARGET_SX1301)发送一个特定的命令字节,其中第 7 位被设置为 1,表示软重置(SOFT_RESET)。这个命令将触发 SX1301 芯片执行软重置操作。

3、重置寄存器页

lgw_regpage = 0; /* reset the paging static variable */

4、返回执行结果

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力学代码的小信

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值