当前位置: 首页> 汽车> 时评 > LoRaWAN网关源码分析(配置篇)

LoRaWAN网关源码分析(配置篇)

时间:2025/7/11 7:46:42来源:https://blog.csdn.net/m0_65292176/article/details/139899856 浏览次数: 0次

目录

一、前言

二、主函数逻辑

三、parse_SX1301_configuration函数

四、parse_gateway_configuration函数

五、local_conf.json配置文件

六、global_conf.json配置文件


一、前言

        对主函数的功能不了解的同学,可以看我上一篇文章。本篇文章我主要整理了如何通过实现读取配置,以及配置文件的内容。

二、主函数逻辑

        主函数关于读取配置文件的代码如下:

/* load configuration files */
if (access(debug_cfg_path, R_OK) == 0) 
{ /* if there is a debug conf, parse only the debug conf */MSG("INFO: found debug configuration file %s, parsing it\n", debug_cfg_path);MSG("INFO: other configuration files will be ignored\n");x = parse_SX1301_configuration(debug_cfg_path);if (x != 0) {exit(EXIT_FAILURE);}x = parse_gateway_configuration(debug_cfg_path);if (x != 0){exit(EXIT_FAILURE);}
} 
else if (access(global_cfg_path, R_OK) == 0) 
{ /* if there is a global conf, parse it and then try to parse local conf  */MSG("INFO: found global configuration file %s, parsing it\n", global_cfg_path);x = parse_SX1301_configuration(global_cfg_path);if (x != 0) {exit(EXIT_FAILURE);}x = parse_gateway_configuration(global_cfg_path);if (x != 0) {exit(EXIT_FAILURE);}if (access(local_cfg_path, R_OK) == 0) {MSG("INFO: found local configuration file %s, parsing it\n", local_cfg_path);MSG("INFO: redefined parameters will overwrite global parameters\n");parse_SX1301_configuration(local_cfg_path);parse_gateway_configuration(local_cfg_path);}
} 
else if (access(local_cfg_path, R_OK) == 0) 
{ /* if there is only a local conf, parse it and that's all */MSG("INFO: found local configuration file %s, parsing it\n", local_cfg_path);x = parse_SX1301_configuration(local_cfg_path);if (x != 0) {exit(EXIT_FAILURE);}x = parse_gateway_configuration(local_cfg_path);if (x != 0) {exit(EXIT_FAILURE);}
} 
else 
{MSG("ERROR: [main] failed to find any configuration file named %s, %s OR %s\n", global_cfg_path, local_cfg_path, debug_cfg_path);exit(EXIT_FAILURE);
}

        这段代码是用来加载配置文件的,具体来说是按照一定的优先级顺序去解析和加载调试配置、全局配置和本地配置。具体的逻辑如下:

  • 检查调试配置文件 (debug_cfg_path) 是否存在并可读:

(1)如果存在并且可读,程序会打印一条信息消息,然后解析这个调试配置文件,并忽略其他配置文件。

(2)调用 parse_SX1301_configuration(debug_cfg_path) 函数解析 SX1301 配置。

(3)如果解析失败(返回值不为 0),程序会退出。

(3)调用 parse_gateway_configuration(debug_cfg_path) 函数解析网关配置。

(4)如果解析失败(返回值不为 0),程序会退出。

  • 如果调试配置文件不存在或不可读,检查全局配置文件 (global_cfg_path) 是否存在并可读:

(1)如果全局配置文件存在并且可读,程序会打印一条信息消息,然后解析这个全局配置文件。

(2)调用 parse_SX1301_configuration(global_cfg_path) 函数解析 SX1301 配置。

(3)如果解析失败(返回值不为 0),程序会退出。

(4)调用 parse_gateway_configuration(global_cfg_path) 函数解析网关配置。

(5)如果解析失败(返回值不为 0),程序会退出。

(6)检查本地配置文件 (local_cfg_path) 是否存在并可读。

        (6.1)如果本地配置文件存在并且可读。

        (6.1.1)程序会打印一条信息消息,然后解析这个本地配置文件。

        (6.1.2) 本地配置文件中的重新定义的参数将覆盖全局配置文件中的参数。

        (6.1.3)调用 parse_SX1301_configuration(local_cfg_path) 函数解析 SX1301 配置。

        (6.1.4)调用 parse_gateway_configuration(local_cfg_path) 函数解析网关配置。

  • 如果全局配置文件不存在或不可读,检查本地配置文件 (local_cfg_path) 是否存在并可读:

(1)如果本地配置文件存在并且可读,程序会打印一条信息消息,然后解析这个本地配置文件。

(2)调用 parse_SX1301_configuration(local_cfg_path) 函数解析 SX1301 配置。

(3)如果解析失败(返回值不为 0),程序会退出。

(4)调用 parse_gateway_configuration(local_cfg_path) 函数解析网关配置。

(5)如果解析失败(返回值不为 0),程序会退出。

  • 如果没有找到任何一个配置文件:

        程序会打印一条错误消息,指出没有找到任何配置文件,并退出。

三、parse_SX1301_configuration函数

         这个函数主要是通过解析 JSON 文件,提取相关的配置参数,然后调用相应的库函数将这些配置参数设置到硬件上,使得 SX1301 LoRa 集中器板可以按照配置文件中的参数正常工作。

         源码对于该函数的定义如下:

static int parse_SX1301_configuration(const char * conf_file) 
{int i;char param_name[32]; /* used to generate variable parameter names */const char *str; /* used to store string value from JSON object */const char conf_obj_name[] = "SX1301_conf";JSON_Value *root_val = NULL;JSON_Object *conf_obj = NULL;JSON_Object *conf_lbt_obj = NULL;JSON_Object *conf_lbtchan_obj = NULL;JSON_Value *val = NULL;JSON_Array *conf_array = NULL;struct lgw_conf_board_s boardconf;struct lgw_conf_lbt_s lbtconf;struct lgw_conf_rxrf_s rfconf;struct lgw_conf_rxif_s ifconf;uint32_t sf, bw, fdev;/* try to parse JSON */root_val = json_parse_file_with_comments(conf_file);if (root_val == NULL) {MSG("ERROR: %s is not a valid JSON file\n", conf_file);exit(EXIT_FAILURE);}/* point to the gateway configuration object */conf_obj = json_object_get_object(json_value_get_object(root_val), conf_obj_name);if (conf_obj == NULL) {MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj_name);return -1;} else {MSG("INFO: %s does contain a JSON object named %s, parsing SX1301 parameters\n", conf_file, conf_obj_name);}/* set board configuration */memset(&boardconf, 0, sizeof boardconf); /* initialize configuration structure */val = json_object_get_value(conf_obj, "lorawan_public"); /* fetch value (if possible) */if (json_value_get_type(val) == JSONBoolean) {boardconf.lorawan_public = (bool)json_value_get_boolean(val);} else {MSG("WARNING: Data type for lorawan_public seems wrong, please check\n");boardconf.lorawan_public = false;}val = json_object_get_value(conf_obj, "clksrc"); /* fetch value (if possible) */if (json_value_get_type(val) == JSONNumber) {boardconf.clksrc = (uint8_t)json_value_get_number(val);} else {MSG("WARNING: Data type for clksrc seems wrong, please check\n");boardconf.clksrc = 0;}MSG("INFO: lorawan_public %d, clksrc %d\n", boardconf.lorawan_public, boardconf.clksrc);/* all parameters parsed, submitting configuration to the HAL */if (lgw_board_setconf(boardconf) != LGW_HAL_SUCCESS) {MSG("ERROR: Failed to configure board\n");return -1;}/* set LBT configuration */memset(&lbtconf, 0, sizeof lbtconf); /* initialize configuration structure */conf_lbt_obj = json_object_get_object(conf_obj, "lbt_cfg"); /* fetch value (if possible) */if (conf_lbt_obj == NULL) {MSG("INFO: no configuration for LBT\n");} else {val = json_object_get_value(conf_lbt_obj, "enable"); /* fetch value (if possible) */if (json_value_get_type(val) == JSONBoolean) {lbtconf.enable = (bool)json_value_get_boolean(val);} else {MSG("WARNING: Data type for lbt_cfg.enable seems wrong, please check\n");lbtconf.enable = false;}if (lbtconf.enable == true) {val = json_object_get_value(conf_lbt_obj, "rssi_target"); /* fetch value (if possible) */if (json_value_get_type(val) == JSONNumber){lbtconf.rssi_target = (int8_t)json_value_get_number(val);} else {MSG("WARNING: Data type for lbt_cfg.rssi_target seems wrong, please check\n");lbtconf.rssi_target = 0;}val = json_object_get_value(conf_lbt_obj, "sx127x_rssi_offset"); /* fetch value (if possible) */if (json_value_get_type(val) == JSONNumber) {lbtconf.rssi_offset = (int8_t)json_value_get_number(val);} else {MSG("WARNING: Data type for lbt_cfg.sx127x_rssi_offset seems wrong, please check\n");lbtconf.rssi_offset = 0;}/* set LBT channels configuration */conf_array = json_object_get_array(conf_lbt_obj, "chan_cfg");if (conf_array != NULL) {lbtconf.nb_channel = json_array_get_count( conf_array );MSG("INFO: %u LBT channels configured\n", lbtconf.nb_channel);}for (i = 0; i < (int)lbtconf.nb_channel; i++) {/* Sanity check */if (i >= LBT_CHANNEL_FREQ_NB){MSG("ERROR: LBT channel %d not supported, skip it\n", i );break;}/* Get LBT channel configuration object from array */conf_lbtchan_obj = json_array_get_object(conf_array, i);/* Channel frequency */val = json_object_dotget_value(conf_lbtchan_obj, "freq_hz"); /* fetch value (if possible) */if (json_value_get_type(val) == JSONNumber) {lbtconf.channels[i].freq_hz = (uint32_t)json_value_get_number(val);}else {MSG("WARNING: Data type for lbt_cfg.channels[%d].freq_hz seems wrong, please check\n", i);lbtconf.channels[i].freq_hz = 0;}/* Channel scan time */val = json_object_dotget_value(conf_lbtchan_obj, "scan_time_us"); /* fetch value (if possible) */if (json_value_get_type(val) == JSONNumber) {lbtconf.channels[i].scan_time_us = (uint16_t)json_value_get_number(val);}else {MSG("WARNING: Data type for lbt_cfg.channels[%d].scan_time_us seems wrong, please check\n", i);lbtconf.channels[i].scan_time_us = 0;}}/* all parameters parsed, submitting configuration to the HAL */if (lgw_lbt_setconf(lbtconf) != LGW_HAL_SUCCESS) {MSG("ERROR: Failed to configure LBT\n");return -1;}} else {MSG("INFO: LBT is disabled\n");}}/* set antenna gain configuration */val = json_object_get_value(conf_obj, "antenna_gain"); /* fetch value (if possible) */if (val != NULL) {if (json_value_get_type(val) == JSONNumber) {antenna_gain = (int8_t)json_value_get_number(val);}else {MSG("WARNING: Data type for antenna_gain seems wrong, please check\n");antenna_gain = 0;}}MSG("INFO: antenna_gain %d dBi\n", antenna_gain);/* set configuration for tx gains */memset(&txlut, 0, sizeof txlut); /* initialize configuration structure */for (i = 0; i < TX_GAIN_LUT_SIZE_MAX; i++) {snprintf(param_name, sizeof param_name, "tx_lut_%i", i); /* compose parameter path inside JSON structure */val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */if (json_value_get_type(val) != JSONObject) 
{MSG("INFO: no configuration for tx gain lut %i\n", i);continue;}txlut.size++; /* update TX LUT size based on JSON object found in configuration file *//* there is an object to configure that TX gain index, let's parse it */snprintf(param_name, sizeof param_name, "tx_lut_%i.pa_gain", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONNumber) {txlut.lut[i].pa_gain = (uint8_t)json_value_get_number(val);} else {MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i);txlut.lut[i].pa_gain = 0;}snprintf(param_name, sizeof param_name, "tx_lut_%i.dac_gain", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONNumber) {txlut.lut[i].dac_gain = (uint8_t)json_value_get_number(val);} else {txlut.lut[i].dac_gain = 3; /* This is the only dac_gain supported for now */}snprintf(param_name, sizeof param_name, "tx_lut_%i.dig_gain", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONNumber) {txlut.lut[i].dig_gain = (uint8_t)json_value_get_number(val);} else {MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i);txlut.lut[i].dig_gain = 0;}snprintf(param_name, sizeof param_name, "tx_lut_%i.mix_gain", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONNumber) {txlut.lut[i].mix_gain = (uint8_t)json_value_get_number(val);} else {MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i);txlut.lut[i].mix_gain = 0;}snprintf(param_name, sizeof param_name, "tx_lut_%i.rf_power", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONNumber) {txlut.lut[i].rf_power = (int8_t)json_value_get_number(val);} else {MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i);txlut.lut[i].rf_power = 0;}}/* all parameters parsed, submitting configuration to the HAL */if (txlut.size > 0) {MSG("INFO: Configuring TX LUT with %u indexes\n", txlut.size);if (lgw_txgain_setconf(&txlut) != LGW_HAL_SUCCESS) {MSG("ERROR: Failed to configure concentrator TX Gain LUT\n");return -1;}} else {MSG("WARNING: No TX gain LUT defined\n");}/* set configuration for RF chains */for (i = 0; i < LGW_RF_CHAIN_NB; ++i) {memset(&rfconf, 0, sizeof rfconf); /* initialize configuration structure */snprintf(param_name, sizeof param_name, "radio_%i", i); /* compose parameter path inside JSON structure */val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */if (json_value_get_type(val) != JSONObject) {MSG("INFO: no configuration for radio %i\n", i);continue;}/* there is an object to configure that radio, let's parse it */snprintf(param_name, sizeof param_name, "radio_%i.enable", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONBoolean) {rfconf.enable = (bool)json_value_get_boolean(val);} else {rfconf.enable = false;}if (rfconf.enable == false) { /* radio disabled, nothing else to parse */MSG("INFO: radio %i disabled\n", i);} else  { /* radio enabled, will parse the other parameters */snprintf(param_name, sizeof param_name, "radio_%i.freq", i);rfconf.freq_hz = (uint32_t)json_object_dotget_number(conf_obj, param_name);snprintf(param_name, sizeof param_name, "radio_%i.rssi_offset", i);rfconf.rssi_offset = (float)json_object_dotget_number(conf_obj, param_name);snprintf(param_name, sizeof param_name, "radio_%i.type", i);str = json_object_dotget_string(conf_obj, param_name);if (!strncmp(str, "SX1255", 6)) {rfconf.type = LGW_RADIO_TYPE_SX1255;} else if (!strncmp(str, "SX1257", 6)) {rfconf.type = LGW_RADIO_TYPE_SX1257;} else {MSG("WARNING: invalid radio type: %s (should be SX1255 or SX1257)\n", str);}snprintf(param_name, sizeof param_name, "radio_%i.tx_enable", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONBoolean) {rfconf.tx_enable = (bool)json_value_get_boolean(val);if (rfconf.tx_enable == true) {/* tx is enabled on this rf chain, we need its frequency range */snprintf(param_name, sizeof param_name, "radio_%i.tx_freq_min", i);tx_freq_min[i] = (uint32_t)json_object_dotget_number(conf_obj, param_name);snprintf(param_name, sizeof param_name, "radio_%i.tx_freq_max", i);tx_freq_max[i] = (uint32_t)json_object_dotget_number(conf_obj, param_name);if ((tx_freq_min[i] == 0) || (tx_freq_max[i] == 0)) {MSG("WARNING: no frequency range specified for TX rf chain %d\n", i);}/* ... and the notch filter frequency to be set */snprintf(param_name, sizeof param_name, "radio_%i.tx_notch_freq", i);rfconf.tx_notch_freq = (uint32_t)json_object_dotget_number(conf_obj, param_name);}} else {rfconf.tx_enable = false;}MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d, tx_notch_freq %u\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable, rfconf.tx_notch_freq);}/* all parameters parsed, submitting configuration to the HAL */if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) {MSG("ERROR: invalid configuration for radio %i\n", i);return -1;}}/* set configuration for Lora multi-SF channels (bandwidth cannot be set) */for (i = 0; i < LGW_MULTI_NB; ++i) {memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */snprintf(param_name, sizeof param_name, "chan_multiSF_%i", i); /* compose parameter path inside JSON structure */val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */if (json_value_get_type(val) != JSONObject) {MSG("INFO: no configuration for Lora multi-SF channel %i\n", i);continue;}/* there is an object to configure that Lora multi-SF channel, let's parse it */snprintf(param_name, sizeof param_name, "chan_multiSF_%i.enable", i);val = json_object_dotget_value(conf_obj, param_name);if (json_value_get_type(val) == JSONBoolean) {ifconf.enable = (bool)json_value_get_boolean(val);} else {ifconf.enable = false;}if (ifconf.enable == false) { /* Lora multi-SF channel disabled, nothing else to parse */MSG("INFO: Lora multi-SF channel %i disabled\n", i);} else  { /* Lora multi-SF channel enabled, will parse the other parameters */snprintf(param_name, sizeof param_name, "chan_multiSF_%i.radio", i);ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, param_name);snprintf(param_name, sizeof param_name, "chan_multiSF_%i.if", i);ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, param_name);// TODO: handle individual SF enabling and disabling (spread_factor)MSG("INFO: Lora multi-SF channel %i>  radio %i, IF %i Hz, 125 kHz bw, SF 7 to 12\n", i, ifconf.rf_chain, ifconf.freq_hz);}/* all parameters parsed, submitting configuration to the HAL */if (lgw_rxif_setconf(i, ifconf) != LGW_HAL_SUCCESS) {MSG("ERROR: invalid configuration for Lora multi-SF channel %i\n", i);return -1;}}/* set configuration for Lora standard channel */memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */val = json_object_get_value(conf_obj, "chan_Lora_std"); /* fetch value (if possible) */if (json_value_get_type(val) != JSONObject) {MSG("INFO: no configuration for Lora standard channel\n");} else {val = json_object_dotget_value(conf_obj, "chan_Lora_std.enable");if (json_value_get_type(val) == JSONBoolean) {ifconf.enable = (bool)json_value_get_boolean(val);} else {ifconf.enable = false;}if (ifconf.enable == false) {MSG("INFO: Lora standard channel %i disabled\n", i);} else  {ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.radio");ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.if");bw = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.bandwidth");switch(bw) {case 500000: ifconf.bandwidth = BW_500KHZ; break;case 250000: ifconf.bandwidth = BW_250KHZ; break;case 125000: ifconf.bandwidth = BW_125KHZ; break;default: ifconf.bandwidth = BW_UNDEFINED;}sf = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.spread_factor");switch(sf) {case  7: ifconf.datarate = DR_LORA_SF7;  break;case  8: ifconf.datarate = DR_LORA_SF8;  break;case  9: ifconf.datarate = DR_LORA_SF9;  break;case 10: ifconf.datarate = DR_LORA_SF10; break;case 11: ifconf.datarate = DR_LORA_SF11; break;case 12: ifconf.datarate = DR_LORA_SF12; break;default: ifconf.datarate = DR_UNDEFINED;}MSG("INFO: Lora std channel> radio %i, IF %i Hz, %u Hz bw, SF %u\n", ifconf.rf_chain, ifconf.freq_hz, bw, sf);}if (lgw_rxif_setconf(8, ifconf) != LGW_HAL_SUCCESS) {MSG("ERROR: invalid configuration for Lora standard channel\n");return -1;}}/* set configuration for FSK channel */memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */val = json_object_get_value(conf_obj, "chan_FSK"); /* fetch value (if possible) */if (json_value_get_type(val) != JSONObject) {MSG("INFO: no configuration for FSK channel\n");} else {val = json_object_dotget_value(conf_obj, "chan_FSK.enable");if (json_value_get_type(val) == JSONBoolean) {ifconf.enable = (bool)json_value_get_boolean(val);} else {ifconf.enable = false;}if (ifconf.enable == false) {MSG("INFO: FSK channel %i disabled\n", i);} else  {ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.radio");ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, "chan_FSK.if");bw = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.bandwidth");fdev = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.freq_deviation");ifconf.datarate = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.datarate");/* if chan_FSK.bandwidth is set, it has priority over chan_FSK.freq_deviation */if ((bw == 0) && (fdev != 0)) {bw = 2 * fdev + ifconf.datarate;}if      (bw == 0)      ifconf.bandwidth = BW_UNDEFINED;else if (bw <= 7800)   ifconf.bandwidth = BW_7K8HZ;else if (bw <= 15600)  ifconf.bandwidth = BW_15K6HZ;else if (bw <= 31200)  ifconf.bandwidth = BW_31K2HZ;else if (bw <= 62500)  ifconf.bandwidth = BW_62K5HZ;else if (bw <= 125000) ifconf.bandwidth = BW_125KHZ;else if (bw <= 250000) ifconf.bandwidth = BW_250KHZ;else if (bw <= 500000) ifconf.bandwidth = BW_500KHZ;else ifconf.bandwidth = BW_UNDEFINED;MSG("INFO: FSK channel> radio %i, IF %i Hz, %u Hz bw, %u bps datarate\n", ifconf.rf_chain, ifconf.freq_hz, bw, ifconf.datarate);}if (lgw_rxif_setconf(9, ifconf) != LGW_HAL_SUCCESS) {MSG("ERROR: invalid configuration for FSK channel\n");return -1;}}json_value_free(root_val);return 0;
}

 1、变量声明

        声明了一些变量和结构体,用于存储配置参数。例如 lgw_conf_board_s 用于板配置,lgw_conf_lbt_s 用于LBT配置,lgw_conf_rxrf_s 用于RF链配置,lgw_conf_rxif_s 用于多SF(多速率)和标准Lora信道配置。

2、解析JSON文件

root_val = json_parse_file_with_comments(conf_file);
if (root_val == NULL) 
{MSG("ERROR: %s is not a valid JSON file\n", conf_file);exit(EXIT_FAILURE);
}

3、定位到JSON

        找到名为 SX1301_conf 的 JSON 对象,它包含了所有配置参数。如果找不到这个对象,会输出错误信息并返回。

4、设置板配置

        初始化 boardconf 结构体。从 JSON 中提取 lorawan_publicclksrc 参数,并设置到 boardconf 结构体中。调用 lgw_board_setconf 函数提交板配置到硬件。

5、设置 LBT(Listen Before Talk)配置

        初始化 lbtconf 结构体。提取并设置 lbt_cfg 参数,包括是否启用 LBT、RSSI 目标值、RSSI 偏移量等。提取并配置 LBT 信道参数,包括频率和扫描时间。调用 lgw_lbt_setconf 提交 LBT 配置。

6、设置天线增益配置

        从 JSON 中提取 antenna_gain 参数,并设置天线增益。

7、设置发射增益配置

        初始化 txlut 结构体。提取并配置 tx_lut 参数,包括各种增益值和发射功率。调用 lgw_txgain_setconf 提交 TX 增益配置。

8、设置 RF 链配置   

        循环配置每个 RF 链。从 JSON 中提取 radio 参数,并设置各个 RF 链的频率、RSSI 偏移量、类型(SX1255 或 SX1257)、发射启用和发射频率范围。调用 lgw_rxrf_setconf 提交 RF 链配置。

9、设置多 SF 信道配置

        循环配置每个多 SF 信道。从 JSON 中提取 chan_multiSF 参数,并设置各个信道的 RF 链、频率等。调用 lgw_rxif_setconf 提交多 SF 信道配置。

10、设置标准 LoRa 信道配置

        初始化 ifconf 结构体。从 JSON 中提取 chan_Lora_std 参数,并设置信道的 RF 链、频率、带宽和扩频因子。调用 lgw_rxif_setconf 提交标准 LoRa 信道配置。

11、设置 FSK 信道配置

        初始化 ifconf 结构体。从 JSON 中提取 chan_FSK 参数,并设置信道的 RF 链、频率、带宽、频偏和数据率。调用 lgw_rxif_setconf 提交 FSK 信道配置。

12、释放 JSON 解析的内存

json_value_free(root_val);

13、返回结果

        如果配置成功,返回 0;如果有错误发生,则返回 -1。

四、parse_gateway_configuration函数

        这个函数的作用是读取并解析用于配置网关的 JSON 配置文件,并根据配置文件中的参数设置网关的配置。

        源码中对于该函数的定义如下:

static int parse_gateway_configuration(const char * conf_file) {const char conf_obj_name[] = "gateway_conf";JSON_Value *root_val;JSON_Object *conf_obj = NULL;JSON_Value *val = NULL; /* needed to detect the absence of some fields */const char *str; /* pointer to sub-strings in the JSON data */unsigned long long ull = 0;/* try to parse JSON */root_val = json_parse_file_with_comments(conf_file);if (root_val == NULL) {MSG("ERROR: %s is not a valid JSON file\n", conf_file);exit(EXIT_FAILURE);}/* point to the gateway configuration object */conf_obj = json_object_get_object(json_value_get_object(root_val), conf_obj_name);if (conf_obj == NULL) {MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj_name);return -1;} else {MSG("INFO: %s does contain a JSON object named %s, parsing gateway parameters\n", conf_file, conf_obj_name);}/* gateway unique identifier (aka MAC address) (optional) */str = json_object_get_string(conf_obj, "gateway_ID");if (str != NULL) {sscanf(str, "%llx", &ull);lgwm = ull;MSG("INFO: gateway MAC address is configured to %016llX\n", ull);}/* server hostname or IP address (optional) */str = json_object_get_string(conf_obj, "server_address");if (str != NULL) {strncpy(serv_addr, str, sizeof serv_addr);MSG("INFO: server hostname or IP address is configured to \"%s\"\n", serv_addr);}/* get up and down ports (optional) */val = json_object_get_value(conf_obj, "serv_port_up");if (val != NULL) {snprintf(serv_port_up, sizeof serv_port_up, "%u", (uint16_t)json_value_get_number(val));MSG("INFO: upstream port is configured to \"%s\"\n", serv_port_up);}val = json_object_get_value(conf_obj, "serv_port_down");if (val != NULL) {snprintf(serv_port_down, sizeof serv_port_down, "%u", (uint16_t)json_value_get_number(val));MSG("INFO: downstream port is configured to \"%s\"\n", serv_port_down);}/* get keep-alive interval (in seconds) for downstream (optional) */val = json_object_get_value(conf_obj, "keepalive_interval");if (val != NULL) {keepalive_time = (int)json_value_get_number(val);MSG("INFO: downstream keep-alive interval is configured to %u seconds\n", keepalive_time);}/* get interval (in seconds) for statistics display (optional) */val = json_object_get_value(conf_obj, "stat_interval");if (val != NULL) {stat_interval = (unsigned)json_value_get_number(val);MSG("INFO: statistics display interval is configured to %u seconds\n", stat_interval);}/* get time-out value (in ms) for upstream datagrams (optional) */val = json_object_get_value(conf_obj, "push_timeout_ms");if (val != NULL) {push_timeout_half.tv_usec = 500 * (long int)json_value_get_number(val);MSG("INFO: upstream PUSH_DATA time-out is configured to %u ms\n", (unsigned)(push_timeout_half.tv_usec / 500));}/* packet filtering parameters */val = json_object_get_value(conf_obj, "forward_crc_valid");if (json_value_get_type(val) == JSONBoolean) {fwd_valid_pkt = (bool)json_value_get_boolean(val);}MSG("INFO: packets received with a valid CRC will%s be forwarded\n", (fwd_valid_pkt ? "" : " NOT"));val = json_object_get_value(conf_obj, "forward_crc_error");if (json_value_get_type(val) == JSONBoolean) {fwd_error_pkt = (bool)json_value_get_boolean(val);}MSG("INFO: packets received with a CRC error will%s be forwarded\n", (fwd_error_pkt ? "" : " NOT"));val = json_object_get_value(conf_obj, "forward_crc_disabled");if (json_value_get_type(val) == JSONBoolean) {fwd_nocrc_pkt = (bool)json_value_get_boolean(val);}MSG("INFO: packets received with no CRC will%s be forwarded\n", (fwd_nocrc_pkt ? "" : " NOT"));/* GPS module TTY path (optional) */str = json_object_get_string(conf_obj, "gps_tty_path");if (str != NULL) {strncpy(gps_tty_path, str, sizeof gps_tty_path);MSG("INFO: GPS serial port path is configured to \"%s\"\n", gps_tty_path);}/* get reference coordinates */val = json_object_get_value(conf_obj, "ref_latitude");if (val != NULL) {reference_coord.lat = (double)json_value_get_number(val);MSG("INFO: Reference latitude is configured to %f deg\n", reference_coord.lat);}val = json_object_get_value(conf_obj, "ref_longitude");if (val != NULL) {reference_coord.lon = (double)json_value_get_number(val);MSG("INFO: Reference longitude is configured to %f deg\n", reference_coord.lon);}val = json_object_get_value(conf_obj, "ref_altitude");if (val != NULL) {reference_coord.alt = (short)json_value_get_number(val);MSG("INFO: Reference altitude is configured to %i meters\n", reference_coord.alt);}/* Gateway GPS coordinates hardcoding (aka. faking) option */val = json_object_get_value(conf_obj, "fake_gps");if (json_value_get_type(val) == JSONBoolean) {gps_fake_enable = (bool)json_value_get_boolean(val);if (gps_fake_enable == true) {MSG("INFO: fake GPS is enabled\n");} else {MSG("INFO: fake GPS is disabled\n");}}/* Beacon signal period (optional) */val = json_object_get_value(conf_obj, "beacon_period");if (val != NULL) {beacon_period = (uint32_t)json_value_get_number(val);if ((beacon_period > 0) && (beacon_period < 6)) {MSG("ERROR: invalid configuration for Beacon period, must be >= 6s\n");return -1;} else {MSG("INFO: Beaconing period is configured to %u seconds\n", beacon_period);}}/* Beacon TX frequency (optional) */val = json_object_get_value(conf_obj, "beacon_freq_hz");if (val != NULL) {beacon_freq_hz = (uint32_t)json_value_get_number(val);MSG("INFO: Beaconing signal will be emitted at %u Hz\n", beacon_freq_hz);}/* Number of beacon channels (optional) */val = json_object_get_value(conf_obj, "beacon_freq_nb");if (val != NULL) {beacon_freq_nb = (uint8_t)json_value_get_number(val);MSG("INFO: Beaconing channel number is set to %u\n", beacon_freq_nb);}/* Frequency step between beacon channels (optional) */val = json_object_get_value(conf_obj, "beacon_freq_step");if (val != NULL) {beacon_freq_step = (uint32_t)json_value_get_number(val);MSG("INFO: Beaconing channel frequency step is set to %uHz\n", beacon_freq_step);}/* Beacon datarate (optional) */val = json_object_get_value(conf_obj, "beacon_datarate");if (val != NULL) {beacon_datarate = (uint8_t)json_value_get_number(val);MSG("INFO: Beaconing datarate is set to SF%d\n", beacon_datarate);}/* Beacon modulation bandwidth (optional) */val = json_object_get_value(conf_obj, "beacon_bw_hz");if (val != NULL) {beacon_bw_hz = (uint32_t)json_value_get_number(val);MSG("INFO: Beaconing modulation bandwidth is set to %dHz\n", beacon_bw_hz);}/* Beacon TX power (optional) */val = json_object_get_value(conf_obj, "beacon_power");if (val != NULL) {beacon_power = (int8_t)json_value_get_number(val);MSG("INFO: Beaconing TX power is set to %ddBm\n", beacon_power);}/* Beacon information descriptor (optional) */val = json_object_get_value(conf_obj, "beacon_infodesc");if (val != NULL) {beacon_infodesc = (uint8_t)json_value_get_number(val);MSG("INFO: Beaconing information descriptor is set to %u\n", beacon_infodesc);}/* Auto-quit threshold (optional) */val = json_object_get_value(conf_obj, "autoquit_threshold");if (val != NULL) {autoquit_threshold = (uint32_t)json_value_get_number(val);MSG("INFO: Auto-quit after %u non-acknowledged PULL_DATA\n", autoquit_threshold);}/* free JSON parsing data structure */json_value_free(root_val);return 0;
}

1、变量声明

(1)conf_obj_name 定义了 JSON 对象的名称 "gateway_conf"。

(2)root_val 是 JSON 文件的根值。

(3)conf_obj 指向解析的 JSON 对象。

(4)val 用于检测某些字段是否存在。

(5)str 用于指向 JSON 数据中的子字符串。

(6)ull 用于存储解析后的网关唯一标识符(MAC 地址)。

2、解析 JSON 文件

root_val = json_parse_file_with_comments(conf_file);
if (root_val == NULL) 
{MSG("ERROR: %s is not a valid JSON file\n", conf_file);exit(EXIT_FAILURE);
}

 3、定位到 JSON 对象

        找到名为 gateway_conf 的 JSON 对象。如果找不到这个对象,会输出错误信息并返回 -1。

4、解析并设置网关唯一标识符(MAC 地址)

str = json_object_get_string(conf_obj, "gateway_ID");
if (str != NULL) 
{sscanf(str, "%llx", &ull);lgwm = ull;MSG("INFO: gateway MAC address is configured to %016llX\n", ull);
}

5、解析并设置服务器地址

str = json_object_get_string(conf_obj, "server_address");
if (str != NULL) 
{strncpy(serv_addr, str, sizeof serv_addr);MSG("INFO: server hostname or IP address is configured to \"%s\"\n", serv_addr);
}

6、解析并设置上行和下行端口

val = json_object_get_value(conf_obj, "serv_port_up");
if (val != NULL) 
{snprintf(serv_port_up, sizeof serv_port_up, "%u", (uint16_t)json_value_get_number(val));MSG("INFO: upstream port is configured to \"%s\"\n", serv_port_up);
}
val = json_object_get_value(conf_obj, "serv_port_down");
if (val != NULL) 
{snprintf(serv_port_down, sizeof serv_port_down, "%u", (uint16_t)json_value_get_number(val));MSG("INFO: downstream port is configured to \"%s\"\n", serv_port_down);
}

7、解析并设置下行保持连接的间隔时间

8、解析并设置统计信息显示的间隔时间

9、解析并设置上行数据包的超时时间

10、解析并设置数据包过滤参数

11、解析并设置 GPS 模块的 TTY 路径

12、解析并设置参考坐标

13、解析并设置假 GPS 选项

14、解析并设置信标参数        

        信标周期、信标频率、信标信道数量、信道频率步长、信标数据速率、信标带宽、信标发射功率。

五、local_conf.json配置文件

        这个配置文件比较简单,下载后的源代码如下:

{
/* Put there parameters that are different for each gateway (eg. pointing one gateway to a test server while the others     
stay in production) */
/* Settings defined in global_conf will be overwritten by those in local_conf */"gateway_conf": {"gateway_ID": "AA555A0000000101" /* you must pick a unique 64b number for each gateway (represented by an hex    
string) */}   
}

        gateway_conf是这个对象包含特定于网关的配置。gateway_ID是这是网关的唯一标识符。每个网关必须有一个唯一的64位十六进制字符串。

        但是要注意,global_conf中定义的设置会被local_conf中的设置覆盖。

六、global_conf.json配置文件

        这是一个用于配置LoRa网关的完整配置文件,其中包含了SX1301和网关的详细设置。对于移植该源代码来说,是很重要的。

        配置文件分为两个主要部分:SX1301_confgateway_confSX1301_conf 部分主要是关于 LoRa 网关的 SX1301 基带芯片的配置。gateway_conf 部分则是关于网关本身的一些设置。接下来我进行逐一整理。

SX1301_conf

"SX1301_conf": {"lorawan_public": true,"clksrc": 1, /* radio_1 提供集中器的时钟 */
  • lorawan_public: 设置为 true 表示使用公共的 LoRaWAN 网络。如果是私有网络,可以设置为 false
  • clksrc: 设置时钟源为 1,表示使用 radio_1 作为时钟源。
    "lbt_cfg": {"enable": false,"rssi_target": -80, /* dBm */"chan_cfg": [ /* 最多8个频道 */{ "freq_hz": 867100000, "scan_time_us": 128 },{ "freq_hz": 867300000, "scan_time_us": 5000 },{ "freq_hz": 867500000, "scan_time_us": 128 },{ "freq_hz": 869525000, "scan_time_us": 128 }],"sx127x_rssi_offset": -4 /* dB */},

lbt_cfg: 侦听前发送(LBT)配置。

  • enable: 设置为 false 表示禁用 LBT。
  • rssi_target: 目标 RSSI 值,为 -80 dBm。
  • chan_cfg: 配置各个频道的频率和扫描时间,最多可配置8个频道。
  • sx127x_rssi_offset: 设置 RSSI 的偏移量为 -4 dB。
    "antenna_gain": 0, /* 天线增益,以dBi表示 */

antenna_gain: 天线增益,单位是 dBi。这里设置为 0。

    "radio_0": {"enable": true,"type": "SX1257","freq": 867500000,"rssi_offset": -166.0,"tx_enable": true,"tx_notch_freq": 129000, /* [126..250] KHz */"tx_freq_min": 863000000,"tx_freq_max": 870000000},"radio_1": {"enable": true,"type": "SX1257","freq": 868500000,"rssi_offset": -166.0,"tx_enable": false},

radio_0radio_1: 配置两个无线电模块。

  • enable: 设置为 true 表示启用该无线电模块。
  • type: 无线电模块的类型,这里是 SX1257
  • freq: 无线电模块的频率。
  • rssi_offset: RSSI 偏移量。
  • tx_enable: 是否启用传输(true 表示启用)。
  • tx_notch_freq: 传输的凹陷频率。
  • tx_freq_mintx_freq_max: 传输频率的最小值和最大值(仅在 radio_0 中配置)。
    "chan_multiSF_0": {/* Lora MAC 频道,125kHz,所有SF,868.1 MHz */"enable": true,"radio": 1,"if": -400000},...

 chan_multiSF_0chan_multiSF_7: 配置多个 LoRa MAC 频道。

  • enable: 设置为 true 表示启用该频道。
  • radio: 使用的无线电模块(0 或 1)。
  • if: 中频偏移。
    "chan_Lora_std": {/* Lora MAC 频道,250kHz,SF7,868.3 MHz */"enable": true,"radio": 1,"if": -200000,"bandwidth": 250000,"spread_factor": 7},

chan_Lora_std: 配置标准 LoRa 频道。

  • enable: 启用该频道。
  • radio: 使用的无线电模块。
  • if: 中频偏移。
  • bandwidth: 带宽。
  • spread_factor: 扩频因子。
    "chan_FSK": {/* FSK 50kbps 频道,868.8 MHz */"enable": true,"radio": 1,"if": 300000,"bandwidth": 125000,"datarate": 50000},

chan_FSK: 配置 FSK 频道。

  • enable: 启用该频道。
  • radio: 使用的无线电模块。
  • if: 中频偏移。
  • bandwidth: 带宽。
  • datarate: 数据速率。
    "tx_lut_0": {/* TX 增益表,索引0 */"pa_gain": 0,"mix_gain": 8,"rf_power": -6,"dig_gain": 0},...

tx_lut_0tx_lut_15: 配置传输增益表。

  • pa_gain: 功率放大器增益。
  • mix_gain: 混合增益。
  • rf_power: 射频功率。
  • dig_gain: 数字增益。

gateway_conf

"gateway_conf": {"gateway_ID": "AA555A0000000000",/* 更改默认服务器地址/端口,或在local_conf.json中覆盖 */"server_address": "localhost","serv_port_up": 1680,"serv_port_down": 1680,
  • gateway_ID: 网关的唯一标识符,这里是 AA555A0000000000
  • server_address: 服务器地址,这里设置为 localhost
  • serv_port_upserv_port_down: 上行和下行数据的服务器端口,默认是 1680
    /* 根据您的网络调整以下参数 */"keepalive_interval": 10,"stat_interval": 30,"push_timeout_ms": 100,
  • keepalive_interval: 保持连接的时间间隔,单位是秒,这里设置为 10 秒。
  • stat_interval: 统计信息的时间间隔,单位是秒,这里设置为 30 秒。
  • push_timeout_ms: 推送超时时间,单位是毫秒,这里设置为 100 毫秒。
    /* 仅转发有效的数据包 */"forward_crc_valid": true,"forward_crc_error": false,"forward_crc_disabled": false
}
  • forward_crc_valid: 仅转发CRC校验有效的数据包,这里设置为 true
  • forward_crc_error: 是否转发CRC校验错误的数据包,这里设置为 false
  • forward_crc_disabled: 是否转发未进行CRC校验的数据包,这里设置为 false
关键字:LoRaWAN网关源码分析(配置篇)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: