From f67722feb8f99ff5bea9bd1cc6e9b22abe84733e Mon Sep 17 00:00:00 2001 From: Michael Coracin Date: Thu, 7 May 2015 15:13:14 +0200 Subject: [PATCH] v2.0.0 - Changed: Several configuration parameters are now set dynamically from the JSON configuration file: RSSI offset, concentrator clock source, radio type, TX gain table, network type. The HAL does not need to be recompiled any more to update those parameters. An example for IoT Starter Kit platform is provided in global_conf.json for basic, gps and beacon packet_forwarder. - Removed: Band frequency JSON configuration file has been removed. An example for EU 868MHz is provided in global_conf.json for basic, gps and beacon packet_forwarder. - Changed: Updated makefiles to allow cross compilation from environment variable (ARCH, CROSS_COMPILE). ** WARNING: ** ** Update your JSON configuration file with new dynamic parameters. ** --- .gitignore | 3 + Makefile | 7 +- VERSION | 2 +- basic_pkt_fwd/Makefile | 29 +- basic_pkt_fwd/cfg/global_conf.cn470.json | 63 ---- basic_pkt_fwd/cfg/global_conf.empty.json | 86 ----- basic_pkt_fwd/cfg/global_conf.eu433.json | 35 -- basic_pkt_fwd/cfg/global_conf.eu868.json | 79 ----- basic_pkt_fwd/cfg/global_conf.us915.json | 58 --- basic_pkt_fwd/global_conf.json | 212 +++++++++++ basic_pkt_fwd/src/basic_pkt_fwd.c | 106 +++++- beacon_pkt_fwd/Makefile | 29 +- beacon_pkt_fwd/cfg/global_conf.cn470.json | 65 ---- beacon_pkt_fwd/cfg/global_conf.empty.json | 94 ----- beacon_pkt_fwd/cfg/global_conf.eu433.json | 35 -- beacon_pkt_fwd/cfg/global_conf.eu868.json | 81 ----- beacon_pkt_fwd/cfg/global_conf.us915.json | 60 ---- beacon_pkt_fwd/global_conf.json | 214 +++++++++++ beacon_pkt_fwd/src/beacon_pkt_fwd.c | 106 +++++- gps_pkt_fwd/Makefile | 29 +- gps_pkt_fwd/cfg/global_conf.cn470.json | 65 ---- gps_pkt_fwd/cfg/global_conf.empty.json | 91 ----- gps_pkt_fwd/cfg/global_conf.eu433.json | 35 -- gps_pkt_fwd/cfg/global_conf.eu868.json | 81 ----- gps_pkt_fwd/cfg/global_conf.us915.json | 60 ---- gps_pkt_fwd/global_conf.json | 215 ++++++++++++ gps_pkt_fwd/src/gps_pkt_fwd.c | 410 ++++++++++++++-------- readme.md | 11 +- 28 files changed, 1135 insertions(+), 1226 deletions(-) create mode 100644 .gitignore delete mode 100644 basic_pkt_fwd/cfg/global_conf.cn470.json delete mode 100644 basic_pkt_fwd/cfg/global_conf.empty.json delete mode 100644 basic_pkt_fwd/cfg/global_conf.eu433.json delete mode 100644 basic_pkt_fwd/cfg/global_conf.eu868.json delete mode 100644 basic_pkt_fwd/cfg/global_conf.us915.json create mode 100644 basic_pkt_fwd/global_conf.json delete mode 100644 beacon_pkt_fwd/cfg/global_conf.cn470.json delete mode 100644 beacon_pkt_fwd/cfg/global_conf.empty.json delete mode 100644 beacon_pkt_fwd/cfg/global_conf.eu433.json delete mode 100644 beacon_pkt_fwd/cfg/global_conf.eu868.json delete mode 100644 beacon_pkt_fwd/cfg/global_conf.us915.json create mode 100644 beacon_pkt_fwd/global_conf.json delete mode 100644 gps_pkt_fwd/cfg/global_conf.cn470.json delete mode 100644 gps_pkt_fwd/cfg/global_conf.empty.json delete mode 100644 gps_pkt_fwd/cfg/global_conf.eu433.json delete mode 100644 gps_pkt_fwd/cfg/global_conf.eu868.json delete mode 100644 gps_pkt_fwd/cfg/global_conf.us915.json create mode 100644 gps_pkt_fwd/global_conf.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ea0baf24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.swp +*.bak diff --git a/Makefile b/Makefile index efd3708f..976a6072 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ ### Environment constants -LGW_PATH := ../../lora_gateway/libloragw -CROSS_COMPILE := +LGW_PATH ?= ../../lora_gateway/libloragw +ARCH ?= +CROSS_COMPILE ?= export ### general build targets @@ -22,4 +23,4 @@ clean: $(MAKE) clean -e -C util_sink $(MAKE) clean -e -C util_tx_test -### EOF \ No newline at end of file +### EOF diff --git a/VERSION b/VERSION index 13175fdc..227cea21 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.1 \ No newline at end of file +2.0.0 diff --git a/basic_pkt_fwd/Makefile b/basic_pkt_fwd/Makefile index 25a44993..5c0596a6 100644 --- a/basic_pkt_fwd/Makefile +++ b/basic_pkt_fwd/Makefile @@ -4,8 +4,9 @@ APP_NAME := basic_pkt_fwd ### Environment constants -LGW_PATH := ../../lora_gateway/libloragw -CROSS_COMPILE := +LGW_PATH ?= ../../lora_gateway/libloragw +ARCH ?= +CROSS_COMPILE ?= ### External constant definitions # must get library build option to know if mpsse must be linked or not @@ -50,12 +51,11 @@ endif ### General build targets -all: $(APP_NAME) global_conf.json +all: $(APP_NAME) clean: rm -f obj/*.o rm -f $(APP_NAME) - find . -name global_conf.json -exec rm -i {} \; ### Sub-modules compilation @@ -65,25 +65,6 @@ obj/base64.o: src/base64.c inc/base64.h obj/parson.o: src/parson.c inc/parson.h $(CC) -c $(CFLAGS) $< -o $@ -### Select the proper configuration JSON for the program - -ifeq ($(CFG_BAND),eu868) -global_conf.json: cfg/global_conf.eu868.json - cp $< $@ -else ifeq ($(CFG_BAND),us915) -global_conf.json: cfg/global_conf.us915.json - cp $< $@ -else ifeq ($(CFG_BAND),cn470) -global_conf.json: cfg/global_conf.cn470.json - cp $< $@ -else ifeq ($(CFG_BAND),eu433) -global_conf.json: cfg/global_conf.eu433.json - cp $< $@ -else -global_conf.json: cfg/global_conf.empty.json - cp $< $@ -endif - ### Main program compilation and assembly obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h @@ -92,4 +73,4 @@ obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h $(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a obj/parson.o obj/base64.o $(CC) -L$(LGW_PATH) $< obj/parson.o obj/base64.o -o $@ $(LIBS) -### EOF \ No newline at end of file +### EOF diff --git a/basic_pkt_fwd/cfg/global_conf.cn470.json b/basic_pkt_fwd/cfg/global_conf.cn470.json deleted file mode 100644 index 1f4d58b4..00000000 --- a/basic_pkt_fwd/cfg/global_conf.cn470.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 471500000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 471.1 MHz */ - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 471.3 MHz */ - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 471.5 MHz */ - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - /* Lora MAC channel, 125kHz, all SF, 471.7 MHz */ - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 125kHz, SF7, 471.9 MHz */ - "enable": true, - "radio": 0, - "if": 400000, - "bandwidth": 125000, - "spread_factor": 7 - }, - "chan_FSK": { - /* FSK 64kbps channel, 471.9 MHz */ - "enable": true, - "radio": 0, - "if": 400000, - "bandwidth": 200000, - "datarate": 64000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false - } -} diff --git a/basic_pkt_fwd/cfg/global_conf.empty.json b/basic_pkt_fwd/cfg/global_conf.empty.json deleted file mode 100644 index 3a4ef087..00000000 --- a/basic_pkt_fwd/cfg/global_conf.empty.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "SX1301_conf": { - /* depending on board configuration, you may have 1 or 2 radios, with 1 or 2 antenna ports */ - "radio_0": { - "enable": false, - "freq": 0 - }, - "radio_1": { - "enable": false, - "freq": 0 - }, - - /* 'multi' Lora channels car receive Lora packets with a BW of 125 kHz, and any SF is automatically recognized and demodulated */ - /* Note: chan_multiSF_3 to 7 are not available on the FPGA version */ - "chan_multiSF_0": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_1": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_2": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_4": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_5": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_6": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_7": { - "enable": false, - "radio": 0, - "if": 0 - }, - - /* the 'stand-alone' Lora modem can receive emissions with BW 125, 250 or 500 kHz, on a specific SF */ - "chan_Lora_std": { - "enable": false, - "radio": 0, - "if": 0, - "bandwidth": 250000, - "spread_factor": 7 - }, - - /* 'high speed' FSK channel, use for radio backhaul, or for maintenance, remote update, etc */ - "chan_FSK": { - "enable": false, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "datarate": 100000 - } - }, - "gateway_conf": { - // "gateway_ID": "AA555A0000000000", // default ID (hexadecimal string) - // "server_address": "127.0.0.1", // Lora network server hostname or IPv4 address - // "serv_port_up": 1780, // default server port for 'upstream' traffic - // "serv_port_down": 1782, // default server port for 'downstream' traffic - // "keepalive_interval": 12, // every X seconds, a PULL_REQ is sent to keep downstream route alive - // "stat_interval": 20, // every X seconds, a status report is displayed on screen - // "push_timeout_ms": 120, // time in ms the program will wait for an ACK on upstream traffic - // "forward_crc_valid": true, // configure if certain types of packets are forwarded or ignored - // "forward_crc_error": false, // configure if certain types of packets are forwarded or ignored - // "forward_crc_disabled": false // configure if certain types of packets are forwarded or ignored - } -} diff --git a/basic_pkt_fwd/cfg/global_conf.eu433.json b/basic_pkt_fwd/cfg/global_conf.eu433.json deleted file mode 100644 index 9988809c..00000000 --- a/basic_pkt_fwd/cfg/global_conf.eu433.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 433500000 - }, - "chan_multiSF_0": { - /* LoRa MAC channel, 125kHz, all SF, 433.2 MHz */ - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_1": { - /* LoRa MAC channel, 125kHz, all SF, 433.4 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_2": { - /* LoRa MAC channel, 125kHz, all SF, 433.6 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_3": { - /* LoRa MAC channel, 125kHz, all SF, 433.8 MHz */ - "enable": true, - "radio": 0, - "if": 300000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000" - } -} diff --git a/basic_pkt_fwd/cfg/global_conf.eu868.json b/basic_pkt_fwd/cfg/global_conf.eu868.json deleted file mode 100644 index 1e62886c..00000000 --- a/basic_pkt_fwd/cfg/global_conf.eu868.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 868200000 - }, - "radio_1": { - "enable": true, - "freq": 869200000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ - "enable": true, - "radio": 0, - "if": 300000 - }, - "chan_multiSF_3": { - /* Lora MAC channel, 125kHz, all SF, 868.85 MHz */ - "enable": true, - "radio": 1, - "if": -350000 - }, - "chan_multiSF_4": { - /* Lora MAC channel, 125kHz, all SF, 869.05 MHz */ - "enable": true, - "radio": 1, - "if": -150000 - }, - "chan_multiSF_5": { - /* Lora MAC channel, 125kHz, all SF, 869.525 MHz */ - "enable": true, - "radio": 1, - "if": 325000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "spread_factor": 7 - }, - "chan_FSK": { - /* FSK 50kbps channel, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "datarate": 50000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false - } -} diff --git a/basic_pkt_fwd/cfg/global_conf.us915.json b/basic_pkt_fwd/cfg/global_conf.us915.json deleted file mode 100644 index c5cdfae7..00000000 --- a/basic_pkt_fwd/cfg/global_conf.us915.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 927000000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 926.7 MHz */ - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 926.9 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 927.1 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 250kHz, SF7, 927.3 MHz */ - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 250000, - "spread_factor": 7 - }, - - "chan_FSK": { - /* FSK 100kbps channel, 927.3 MHz */ - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 250000, - "datarate": 100000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false - } -} diff --git a/basic_pkt_fwd/global_conf.json b/basic_pkt_fwd/global_conf.json new file mode 100644 index 00000000..ef5189a0 --- /dev/null +++ b/basic_pkt_fwd/global_conf.json @@ -0,0 +1,212 @@ +{ + "SX1301_conf": { + "lorawan_public": true, + "clksrc": 1, /* radio_1 provides clock to concentrator */ + "radio_0": { + "enable": true, + "type": "SX1257", + "freq": 867500000, + "rssi_offset": -166.0, + "tx_enable": true + }, + "radio_1": { + "enable": true, + "type": "SX1257", + "freq": 868500000, + "rssi_offset": -166.0, + "tx_enable": false + }, + "chan_multiSF_0": { + /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */ + "enable": true, + "radio": 1, + "if": -400000 + }, + "chan_multiSF_1": { + /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ + "enable": true, + "radio": 1, + "if": -200000 + }, + "chan_multiSF_2": { + /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ + "enable": true, + "radio": 1, + "if": 0 + }, + "chan_multiSF_3": { + /* Lora MAC channel, 125kHz, all SF, 867.1 MHz */ + "enable": true, + "radio": 0, + "if": -400000 + }, + "chan_multiSF_4": { + /* Lora MAC channel, 125kHz, all SF, 867.3 MHz */ + "enable": true, + "radio": 0, + "if": -200000 + }, + "chan_multiSF_5": { + /* Lora MAC channel, 125kHz, all SF, 867.5 MHz */ + "enable": true, + "radio": 0, + "if": 0 + }, + "chan_multiSF_6": { + /* Lora MAC channel, 125kHz, all SF, 867.7 MHz */ + "enable": true, + "radio": 0, + "if": 200000 + }, + "chan_multiSF_7": { + /* Lora MAC channel, 125kHz, all SF, 867.9 MHz */ + "enable": true, + "radio": 0, + "if": 400000 + }, + "chan_Lora_std": { + /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ + "enable": true, + "radio": 1, + "if": -200000, + "bandwidth": 250000, + "spread_factor": 7 + }, + "chan_FSK": { + /* FSK 50kbps channel, 868.8 MHz */ + "enable": true, + "radio": 1, + "if": 300000, + "bandwidth": 125000, + "datarate": 50000 + }, + "tx_lut_0": { + /* TX gain table, index 0 */ + "pa_gain": 0, + "mix_gain": 8, + "rf_power": -6, + "dig_gain": 0 + }, + "tx_lut_1": { + /* TX gain table, index 1 */ + "pa_gain": 0, + "mix_gain": 10, + "rf_power": -3, + "dig_gain": 0 + }, + "tx_lut_2": { + /* TX gain table, index 2 */ + "pa_gain": 0, + "mix_gain": 12, + "rf_power": 0, + "dig_gain": 0 + }, + "tx_lut_3": { + /* TX gain table, index 3 */ + "pa_gain": 1, + "mix_gain": 8, + "rf_power": 3, + "dig_gain": 0 + }, + "tx_lut_4": { + /* TX gain table, index 4 */ + "pa_gain": 1, + "mix_gain": 10, + "rf_power": 6, + "dig_gain": 0 + }, + "tx_lut_5": { + /* TX gain table, index 5 */ + "pa_gain": 1, + "mix_gain": 12, + "rf_power": 10, + "dig_gain": 0 + }, + "tx_lut_6": { + /* TX gain table, index 6 */ + "pa_gain": 1, + "mix_gain": 13, + "rf_power": 11, + "dig_gain": 0 + }, + "tx_lut_7": { + /* TX gain table, index 7 */ + "pa_gain": 2, + "mix_gain": 9, + "rf_power": 12, + "dig_gain": 0 + }, + "tx_lut_8": { + /* TX gain table, index 8 */ + "pa_gain": 1, + "mix_gain": 15, + "rf_power": 13, + "dig_gain": 0 + }, + "tx_lut_9": { + /* TX gain table, index 9 */ + "pa_gain": 2, + "mix_gain": 10, + "rf_power": 14, + "dig_gain": 0 + }, + "tx_lut_10": { + /* TX gain table, index 10 */ + "pa_gain": 2, + "mix_gain": 11, + "rf_power": 16, + "dig_gain": 0 + }, + "tx_lut_11": { + /* TX gain table, index 11 */ + "pa_gain": 3, + "mix_gain": 9, + "rf_power": 20, + "dig_gain": 0 + }, + "tx_lut_12": { + /* TX gain table, index 12 */ + "pa_gain": 3, + "mix_gain": 10, + "rf_power": 23, + "dig_gain": 0 + }, + "tx_lut_13": { + /* TX gain table, index 13 */ + "pa_gain": 3, + "mix_gain": 11, + "rf_power": 25, + "dig_gain": 0 + }, + "tx_lut_14": { + /* TX gain table, index 14 */ + "pa_gain": 3, + "mix_gain": 12, + "rf_power": 26, + "dig_gain": 0 + }, + "tx_lut_15": { + /* TX gain table, index 15 */ + "pa_gain": 3, + "mix_gain": 14, + "rf_power": 27, + "dig_gain": 0 + } + }, + + "gateway_conf": { + "gateway_ID": "AA555A0000000000", + /* change with default server address/ports, or overwrite in local_conf.json */ + "server_address": "iot.semtech.com", + "serv_port_up": 1680, + "serv_port_down": 1680, + /* adjust the following parameters for your network */ + "keepalive_interval": 10, + "stat_interval": 30, + "push_timeout_ms": 100, + /* forward only valid packets */ + "forward_crc_valid": true, + "forward_crc_error": false, + "forward_crc_disabled": false + } +} diff --git a/basic_pkt_fwd/src/basic_pkt_fwd.c b/basic_pkt_fwd/src/basic_pkt_fwd.c index e20dfc1e..4c3c7d5a 100644 --- a/basic_pkt_fwd/src/basic_pkt_fwd.c +++ b/basic_pkt_fwd/src/basic_pkt_fwd.c @@ -181,14 +181,17 @@ static void sig_handler(int sigio) { 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_Value *val = NULL; + struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; struct lgw_conf_rxif_s ifconf; uint32_t sf, bw, fdev; - + struct lgw_tx_gain_lut_s txlut; + /* try to parse JSON */ root_val = json_parse_file_with_comments(conf_file); if (root_val == NULL) { @@ -204,7 +207,86 @@ static int parse_SX1301_configuration(const char * conf_file) { } 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("WARNING: Failed to configure board\n"); + } + + /* 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 */ + MSG("INFO: Configuring TX LUT with %u indexes\n", txlut.size); + if (lgw_txgain_setconf(&txlut) != LGW_HAL_SUCCESS) { + MSG("WARNING: Failed to configure concentrator TX Gain LUT\n"); + } + /* set configuration for RF chains */ for (i = 0; i < LGW_RF_CHAIN_NB; ++i) { memset(&rfconf, 0, sizeof rfconf); /* initialize configuration structure */ @@ -227,7 +309,25 @@ static int parse_SX1301_configuration(const char * conf_file) { } 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); - MSG("INFO: radio %i enabled, center frequency %u\n", i, rfconf.freq_hz); + 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); + } else { + rfconf.tx_enable = false; + } + MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable); } /* all parameters parsed, submitting configuration to the HAL */ if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) { diff --git a/beacon_pkt_fwd/Makefile b/beacon_pkt_fwd/Makefile index f65258bc..5af5adad 100644 --- a/beacon_pkt_fwd/Makefile +++ b/beacon_pkt_fwd/Makefile @@ -4,8 +4,9 @@ APP_NAME := beacon_pkt_fwd ### Environment constants -LGW_PATH := ../../lora_gateway/libloragw -CROSS_COMPILE := +LGW_PATH ?= ../../lora_gateway/libloragw +ARCH ?= +CROSS_COMPILE ?= ### External constant definitions # must get library build option to know if mpsse must be linked or not @@ -51,12 +52,11 @@ endif ### General build targets -all: $(APP_NAME) global_conf.json +all: $(APP_NAME) clean: rm -f obj/*.o rm -f $(APP_NAME) - find . -name global_conf.json -exec rm -i {} \; ### Sub-modules compilation @@ -66,25 +66,6 @@ obj/base64.o: src/base64.c inc/base64.h obj/parson.o: src/parson.c inc/parson.h $(CC) -c $(CFLAGS) $< -o $@ -### Select the proper configuration JSON for the program - -ifeq ($(CFG_BAND),eu868) -global_conf.json: cfg/global_conf.eu868.json - cp $< $@ -else ifeq ($(CFG_BAND),us915) -global_conf.json: cfg/global_conf.us915.json - cp $< $@ -else ifeq ($(CFG_BAND),cn470) -global_conf.json: cfg/global_conf.cn470.json - cp $< $@ -else ifeq ($(CFG_BAND),eu433) -global_conf.json: cfg/global_conf.eu433.json - cp $< $@ -else -global_conf.json: cfg/global_conf.empty.json - cp $< $@ -endif - ### Main program compilation and assembly obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h @@ -93,4 +74,4 @@ obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h $(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a obj/parson.o obj/base64.o $(CC) -L$(LGW_PATH) $< obj/parson.o obj/base64.o -o $@ $(LIBS) -### EOF \ No newline at end of file +### EOF diff --git a/beacon_pkt_fwd/cfg/global_conf.cn470.json b/beacon_pkt_fwd/cfg/global_conf.cn470.json deleted file mode 100644 index 7cb5a599..00000000 --- a/beacon_pkt_fwd/cfg/global_conf.cn470.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 471500000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 471.1 MHz */ - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 471.3 MHz */ - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 471.5 MHz */ - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - /* Lora MAC channel, 125kHz, all SF, 471.7 MHz */ - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 125kHz, SF7, 471.9 MHz */ - "enable": true, - "radio": 0, - "if": 400000, - "bandwidth": 125000, - "spread_factor": 7 - }, - "chan_FSK": { - /* FSK 64kbps channel, 471.9 MHz */ - "enable": true, - "radio": 0, - "if": 400000, - "bandwidth": 200000, - "datarate": 64000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false, - /* GPS configuration */ - "gps_tty_path": "/dev/ttyACM0" - } -} diff --git a/beacon_pkt_fwd/cfg/global_conf.empty.json b/beacon_pkt_fwd/cfg/global_conf.empty.json deleted file mode 100644 index 6f28527b..00000000 --- a/beacon_pkt_fwd/cfg/global_conf.empty.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "SX1301_conf": { - /* depending on board configuration, you may have 1 or 2 radios, with 1 or 2 antenna ports */ - "radio_0": { - "enable": false, - "freq": 0 - }, - "radio_1": { - "enable": false, - "freq": 0 - }, - - /* 'multi' Lora channels car receive Lora packets with a BW of 125 kHz, and any SF is automatically recognized and demodulated */ - /* Note: chan_multiSF_3 to 7 are not available on the FPGA version */ - "chan_multiSF_0": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_1": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_2": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_4": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_5": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_6": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_7": { - "enable": false, - "radio": 0, - "if": 0 - }, - - /* the 'stand-alone' Lora modem can receive emissions with BW 125, 250 or 500 kHz, on a specific SF */ - "chan_Lora_std": { - "enable": false, - "radio": 0, - "if": 0, - "bandwidth": 250000, - "spread_factor": 7 - }, - - /* 'high speed' FSK channel, use for radio backhaul, or for maintenance, remote update, etc */ - "chan_FSK": { - "enable": false, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "datarate": 100000 - } - }, - "gateway_conf": { - // "gateway_ID": "AA555A0000000000", // default ID (hexadecimal string) - // "server_address": "127.0.0.1", // Lora network server hostname or IPv4 address - // "serv_port_up": 1780, // default server port for 'upstream' traffic - // "serv_port_down": 1782, // default server port for 'downstream' traffic - // "keepalive_interval": 12, // every X seconds, a PULL_REQ is sent to keep downstream route alive - // "stat_interval": 20, // every X seconds, a status report is displayed on screen - // "push_timeout_ms": 120, // time in ms the program will wait for an ACK on upstream traffic - // "forward_crc_valid": true, // configure if certain types of packets are forwarded or ignored - // "forward_crc_error": false, // configure if certain types of packets are forwarded or ignored - // "forward_crc_disabled": false, // configure if certain types of packets are forwarded or ignored - // "gps_tty_path": "/dev/ttyACM0", // path to TTY devices configured to receive GPS NMEA frames - // "ref_latitude": 47.00638, // reference latitude in degrees (brodcasted in beacons), N is + - // "ref_longitude": 6.96655, // reference longitude in degrees (brodcasted in beacons), E is + - // "ref_altitude": 440, // reference altitude in meters - // "fake_gps": false, // report ref coordinates instead of GPS coordinates in the status report - // "beacon_period": 128, // period in seconds of beacon signal - // "beacon_offset": 17, // offset in seconds on the signal in the period - // "beacon_freq_hz": 700000000 // frequency in Hz the beacon is sent on - } -} diff --git a/beacon_pkt_fwd/cfg/global_conf.eu433.json b/beacon_pkt_fwd/cfg/global_conf.eu433.json deleted file mode 100644 index 9988809c..00000000 --- a/beacon_pkt_fwd/cfg/global_conf.eu433.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 433500000 - }, - "chan_multiSF_0": { - /* LoRa MAC channel, 125kHz, all SF, 433.2 MHz */ - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_1": { - /* LoRa MAC channel, 125kHz, all SF, 433.4 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_2": { - /* LoRa MAC channel, 125kHz, all SF, 433.6 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_3": { - /* LoRa MAC channel, 125kHz, all SF, 433.8 MHz */ - "enable": true, - "radio": 0, - "if": 300000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000" - } -} diff --git a/beacon_pkt_fwd/cfg/global_conf.eu868.json b/beacon_pkt_fwd/cfg/global_conf.eu868.json deleted file mode 100644 index 5c3e412a..00000000 --- a/beacon_pkt_fwd/cfg/global_conf.eu868.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 868200000 - }, - "radio_1": { - "enable": true, - "freq": 869200000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ - "enable": true, - "radio": 0, - "if": 300000 - }, - "chan_multiSF_3": { - /* Lora MAC channel, 125kHz, all SF, 868.85 MHz */ - "enable": true, - "radio": 1, - "if": -350000 - }, - "chan_multiSF_4": { - /* Lora MAC channel, 125kHz, all SF, 869.05 MHz */ - "enable": true, - "radio": 1, - "if": -150000 - }, - "chan_multiSF_5": { - /* Lora MAC channel, 125kHz, all SF, 869.525 MHz */ - "enable": true, - "radio": 1, - "if": 325000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "spread_factor": 7 - }, - "chan_FSK": { - /* FSK 50kbps channel, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "datarate": 50000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false, - /* GPS configuration */ - "gps_tty_path": "/dev/ttyACM0" - } -} diff --git a/beacon_pkt_fwd/cfg/global_conf.us915.json b/beacon_pkt_fwd/cfg/global_conf.us915.json deleted file mode 100644 index 690ed9c2..00000000 --- a/beacon_pkt_fwd/cfg/global_conf.us915.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 927000000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 926.7 MHz */ - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 926.9 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 927.1 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 250kHz, SF7, 927.3 MHz */ - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 250000, - "spread_factor": 7 - }, - - "chan_FSK": { - /* FSK 100kbps channel, 927.3 MHz */ - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 250000, - "datarate": 100000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false, - /* GPS configuration */ - "gps_tty_path": "/dev/ttyACM0" - } -} diff --git a/beacon_pkt_fwd/global_conf.json b/beacon_pkt_fwd/global_conf.json new file mode 100644 index 00000000..7c53b778 --- /dev/null +++ b/beacon_pkt_fwd/global_conf.json @@ -0,0 +1,214 @@ +{ + "SX1301_conf": { + "lorawan_public": true, + "clksrc": 1, /* radio_1 provides clock to concentrator */ + "radio_0": { + "enable": true, + "type": "SX1257", + "freq": 867500000, + "rssi_offset": -166.0, + "tx_enable": true + }, + "radio_1": { + "enable": true, + "type": "SX1257", + "freq": 868500000, + "rssi_offset": -166.0, + "tx_enable": false + }, + "chan_multiSF_0": { + /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */ + "enable": true, + "radio": 1, + "if": -400000 + }, + "chan_multiSF_1": { + /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ + "enable": true, + "radio": 1, + "if": -200000 + }, + "chan_multiSF_2": { + /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ + "enable": true, + "radio": 1, + "if": 0 + }, + "chan_multiSF_3": { + /* Lora MAC channel, 125kHz, all SF, 867.1 MHz */ + "enable": true, + "radio": 0, + "if": -400000 + }, + "chan_multiSF_4": { + /* Lora MAC channel, 125kHz, all SF, 867.3 MHz */ + "enable": true, + "radio": 0, + "if": -200000 + }, + "chan_multiSF_5": { + /* Lora MAC channel, 125kHz, all SF, 867.5 MHz */ + "enable": true, + "radio": 0, + "if": 0 + }, + "chan_multiSF_6": { + /* Lora MAC channel, 125kHz, all SF, 867.7 MHz */ + "enable": true, + "radio": 0, + "if": 200000 + }, + "chan_multiSF_7": { + /* Lora MAC channel, 125kHz, all SF, 867.9 MHz */ + "enable": true, + "radio": 0, + "if": 400000 + }, + "chan_Lora_std": { + /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ + "enable": true, + "radio": 1, + "if": -200000, + "bandwidth": 250000, + "spread_factor": 7 + }, + "chan_FSK": { + /* FSK 50kbps channel, 868.8 MHz */ + "enable": true, + "radio": 1, + "if": 300000, + "bandwidth": 125000, + "datarate": 50000 + }, + "tx_lut_0": { + /* TX gain table, index 0 */ + "pa_gain": 0, + "mix_gain": 8, + "rf_power": -6, + "dig_gain": 0 + }, + "tx_lut_1": { + /* TX gain table, index 1 */ + "pa_gain": 0, + "mix_gain": 10, + "rf_power": -3, + "dig_gain": 0 + }, + "tx_lut_2": { + /* TX gain table, index 2 */ + "pa_gain": 0, + "mix_gain": 12, + "rf_power": 0, + "dig_gain": 0 + }, + "tx_lut_3": { + /* TX gain table, index 3 */ + "pa_gain": 1, + "mix_gain": 8, + "rf_power": 3, + "dig_gain": 0 + }, + "tx_lut_4": { + /* TX gain table, index 4 */ + "pa_gain": 1, + "mix_gain": 10, + "rf_power": 6, + "dig_gain": 0 + }, + "tx_lut_5": { + /* TX gain table, index 5 */ + "pa_gain": 1, + "mix_gain": 12, + "rf_power": 10, + "dig_gain": 0 + }, + "tx_lut_6": { + /* TX gain table, index 6 */ + "pa_gain": 1, + "mix_gain": 13, + "rf_power": 11, + "dig_gain": 0 + }, + "tx_lut_7": { + /* TX gain table, index 7 */ + "pa_gain": 2, + "mix_gain": 9, + "rf_power": 12, + "dig_gain": 0 + }, + "tx_lut_8": { + /* TX gain table, index 8 */ + "pa_gain": 1, + "mix_gain": 15, + "rf_power": 13, + "dig_gain": 0 + }, + "tx_lut_9": { + /* TX gain table, index 9 */ + "pa_gain": 2, + "mix_gain": 10, + "rf_power": 14, + "dig_gain": 0 + }, + "tx_lut_10": { + /* TX gain table, index 10 */ + "pa_gain": 2, + "mix_gain": 11, + "rf_power": 16, + "dig_gain": 0 + }, + "tx_lut_11": { + /* TX gain table, index 11 */ + "pa_gain": 3, + "mix_gain": 9, + "rf_power": 20, + "dig_gain": 0 + }, + "tx_lut_12": { + /* TX gain table, index 12 */ + "pa_gain": 3, + "mix_gain": 10, + "rf_power": 23, + "dig_gain": 0 + }, + "tx_lut_13": { + /* TX gain table, index 13 */ + "pa_gain": 3, + "mix_gain": 11, + "rf_power": 25, + "dig_gain": 0 + }, + "tx_lut_14": { + /* TX gain table, index 14 */ + "pa_gain": 3, + "mix_gain": 12, + "rf_power": 26, + "dig_gain": 0 + }, + "tx_lut_15": { + /* TX gain table, index 15 */ + "pa_gain": 3, + "mix_gain": 14, + "rf_power": 27, + "dig_gain": 0 + } + }, + + "gateway_conf": { + "gateway_ID": "AA555A0000000000", + /* change with default server address/ports, or overwrite in local_conf.json */ + "server_address": "iot.semtech.com", + "serv_port_up": 1680, + "serv_port_down": 1680, + /* adjust the following parameters for your network */ + "keepalive_interval": 10, + "stat_interval": 30, + "push_timeout_ms": 100, + /* forward only valid packets */ + "forward_crc_valid": true, + "forward_crc_error": false, + "forward_crc_disabled": false, + /* GPS configuration */ + "gps_tty_path": "/dev/ttyACM0" + } +} diff --git a/beacon_pkt_fwd/src/beacon_pkt_fwd.c b/beacon_pkt_fwd/src/beacon_pkt_fwd.c index 47b1c1f8..35b6e171 100644 --- a/beacon_pkt_fwd/src/beacon_pkt_fwd.c +++ b/beacon_pkt_fwd/src/beacon_pkt_fwd.c @@ -231,14 +231,17 @@ static void sig_handler(int sigio) { 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_Value *val = NULL; + struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; struct lgw_conf_rxif_s ifconf; uint32_t sf, bw, fdev; - + struct lgw_tx_gain_lut_s txlut; + /* try to parse JSON */ root_val = json_parse_file_with_comments(conf_file); if (root_val == NULL) { @@ -254,7 +257,86 @@ static int parse_SX1301_configuration(const char * conf_file) { } 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("WARNING: Failed to configure board\n"); + } + + /* 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 */ + MSG("INFO: Configuring TX LUT with %u indexes\n", txlut.size); + if (lgw_txgain_setconf(&txlut) != LGW_HAL_SUCCESS) { + MSG("WARNING: Failed to configure concentrator TX Gain LUT\n"); + } + /* set configuration for RF chains */ for (i = 0; i < LGW_RF_CHAIN_NB; ++i) { memset(&rfconf, 0, sizeof rfconf); /* initialize configuration structure */ @@ -277,7 +359,25 @@ static int parse_SX1301_configuration(const char * conf_file) { } 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); - MSG("INFO: radio %i enabled, center frequency %u\n", i, rfconf.freq_hz); + 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); + } else { + rfconf.tx_enable = false; + } + MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable); } /* all parameters parsed, submitting configuration to the HAL */ if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) { diff --git a/gps_pkt_fwd/Makefile b/gps_pkt_fwd/Makefile index 43af2ec8..89f10001 100644 --- a/gps_pkt_fwd/Makefile +++ b/gps_pkt_fwd/Makefile @@ -4,8 +4,9 @@ APP_NAME := gps_pkt_fwd ### Environment constants -LGW_PATH := ../../lora_gateway/libloragw -CROSS_COMPILE := +LGW_PATH ?= ../../lora_gateway/libloragw +ARCH ?= +CROSS_COMPILE ?= ### External constant definitions # must get library build option to know if mpsse must be linked or not @@ -51,12 +52,11 @@ endif ### General build targets -all: $(APP_NAME) global_conf.json +all: $(APP_NAME) clean: rm -f obj/*.o rm -f $(APP_NAME) - find . -name global_conf.json -exec rm -i {} \; ### Sub-modules compilation @@ -66,25 +66,6 @@ obj/base64.o: src/base64.c inc/base64.h obj/parson.o: src/parson.c inc/parson.h $(CC) -c $(CFLAGS) $< -o $@ -### Select the proper configuration JSON for the program - -ifeq ($(CFG_BAND),eu868) -global_conf.json: cfg/global_conf.eu868.json - cp $< $@ -else ifeq ($(CFG_BAND),us915) -global_conf.json: cfg/global_conf.us915.json - cp $< $@ -else ifeq ($(CFG_BAND),cn470) -global_conf.json: cfg/global_conf.cn470.json - cp $< $@ -else ifeq ($(CFG_BAND),eu433) -global_conf.json: cfg/global_conf.eu433.json - cp $< $@ -else -global_conf.json: cfg/global_conf.empty.json - cp $< $@ -endif - ### Main program compilation and assembly obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h @@ -93,4 +74,4 @@ obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h inc/base64.h $(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a obj/parson.o obj/base64.o $(CC) -L$(LGW_PATH) $< obj/parson.o obj/base64.o -o $@ $(LIBS) -### EOF \ No newline at end of file +### EOF diff --git a/gps_pkt_fwd/cfg/global_conf.cn470.json b/gps_pkt_fwd/cfg/global_conf.cn470.json deleted file mode 100644 index 7cb5a599..00000000 --- a/gps_pkt_fwd/cfg/global_conf.cn470.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 471500000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 471.1 MHz */ - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 471.3 MHz */ - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 471.5 MHz */ - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - /* Lora MAC channel, 125kHz, all SF, 471.7 MHz */ - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 125kHz, SF7, 471.9 MHz */ - "enable": true, - "radio": 0, - "if": 400000, - "bandwidth": 125000, - "spread_factor": 7 - }, - "chan_FSK": { - /* FSK 64kbps channel, 471.9 MHz */ - "enable": true, - "radio": 0, - "if": 400000, - "bandwidth": 200000, - "datarate": 64000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false, - /* GPS configuration */ - "gps_tty_path": "/dev/ttyACM0" - } -} diff --git a/gps_pkt_fwd/cfg/global_conf.empty.json b/gps_pkt_fwd/cfg/global_conf.empty.json deleted file mode 100644 index a1e1556f..00000000 --- a/gps_pkt_fwd/cfg/global_conf.empty.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "SX1301_conf": { - /* depending on board configuration, you may have 1 or 2 radios, with 1 or 2 antenna ports */ - "radio_0": { - "enable": false, - "freq": 0 - }, - "radio_1": { - "enable": false, - "freq": 0 - }, - - /* 'multi' Lora channels car receive Lora packets with a BW of 125 kHz, and any SF is automatically recognized and demodulated */ - /* Note: chan_multiSF_3 to 7 are not available on the FPGA version */ - "chan_multiSF_0": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_1": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_2": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_4": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_5": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_6": { - "enable": false, - "radio": 0, - "if": 0 - }, - "chan_multiSF_7": { - "enable": false, - "radio": 0, - "if": 0 - }, - - /* the 'stand-alone' Lora modem can receive emissions with BW 125, 250 or 500 kHz, on a specific SF */ - "chan_Lora_std": { - "enable": false, - "radio": 0, - "if": 0, - "bandwidth": 250000, - "spread_factor": 7 - }, - - /* 'high speed' FSK channel, use for radio backhaul, or for maintenance, remote update, etc */ - "chan_FSK": { - "enable": false, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "datarate": 100000 - } - }, - "gateway_conf": { - // "gateway_ID": "AA555A0000000000", // default ID (hexadecimal string) - // "server_address": "127.0.0.1", // Lora network server hostname or IPv4 address - // "serv_port_up": 1780, // default server port for 'upstream' traffic - // "serv_port_down": 1782, // default server port for 'downstream' traffic - // "keepalive_interval": 12, // every X seconds, a PULL_REQ is sent to keep downstream route alive - // "stat_interval": 20, // every X seconds, a status report is displayed on screen - // "push_timeout_ms": 120, // time in ms the program will wait for an ACK on upstream traffic - // "forward_crc_valid": true, // configure if certain types of packets are forwarded or ignored - // "forward_crc_error": false, // configure if certain types of packets are forwarded or ignored - // "forward_crc_disabled": false, // configure if certain types of packets are forwarded or ignored - // "gps_tty_path": "/dev/ttyACM0", // path to TTY devices configured to receive GPS NMEA frames - // "ref_latitude": 47.00638, // reference latitude in degrees (brodcasted in beacons), N is + - // "ref_longitude": 6.96655, // reference longitude in degrees (brodcasted in beacons), E is + - // "ref_altitude": 440, // reference altitude in meters - // "fake_gps": false // report ref coordinates instead of GPS coordinates in the status report - } -} diff --git a/gps_pkt_fwd/cfg/global_conf.eu433.json b/gps_pkt_fwd/cfg/global_conf.eu433.json deleted file mode 100644 index 9988809c..00000000 --- a/gps_pkt_fwd/cfg/global_conf.eu433.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 433500000 - }, - "chan_multiSF_0": { - /* LoRa MAC channel, 125kHz, all SF, 433.2 MHz */ - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_1": { - /* LoRa MAC channel, 125kHz, all SF, 433.4 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_2": { - /* LoRa MAC channel, 125kHz, all SF, 433.6 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_3": { - /* LoRa MAC channel, 125kHz, all SF, 433.8 MHz */ - "enable": true, - "radio": 0, - "if": 300000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000" - } -} diff --git a/gps_pkt_fwd/cfg/global_conf.eu868.json b/gps_pkt_fwd/cfg/global_conf.eu868.json deleted file mode 100644 index 5c3e412a..00000000 --- a/gps_pkt_fwd/cfg/global_conf.eu868.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 868200000 - }, - "radio_1": { - "enable": true, - "freq": 869200000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ - "enable": true, - "radio": 0, - "if": 300000 - }, - "chan_multiSF_3": { - /* Lora MAC channel, 125kHz, all SF, 868.85 MHz */ - "enable": true, - "radio": 1, - "if": -350000 - }, - "chan_multiSF_4": { - /* Lora MAC channel, 125kHz, all SF, 869.05 MHz */ - "enable": true, - "radio": 1, - "if": -150000 - }, - "chan_multiSF_5": { - /* Lora MAC channel, 125kHz, all SF, 869.525 MHz */ - "enable": true, - "radio": 1, - "if": 325000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "spread_factor": 7 - }, - "chan_FSK": { - /* FSK 50kbps channel, 868.3 MHz */ - "enable": true, - "radio": 0, - "if": 100000, - "bandwidth": 250000, - "datarate": 50000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false, - /* GPS configuration */ - "gps_tty_path": "/dev/ttyACM0" - } -} diff --git a/gps_pkt_fwd/cfg/global_conf.us915.json b/gps_pkt_fwd/cfg/global_conf.us915.json deleted file mode 100644 index 690ed9c2..00000000 --- a/gps_pkt_fwd/cfg/global_conf.us915.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "SX1301_conf": { - "radio_0": { - "enable": true, - "freq": 927000000 - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 926.7 MHz */ - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 926.9 MHz */ - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 927.1 MHz */ - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 250kHz, SF7, 927.3 MHz */ - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 250000, - "spread_factor": 7 - }, - - "chan_FSK": { - /* FSK 100kbps channel, 927.3 MHz */ - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 250000, - "datarate": 100000 - } - }, - "gateway_conf": { - "gateway_ID": "AA555A0000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "iot.semtech.com", - "serv_port_up": 1780, - "serv_port_down": 1782, - /* adjust the following parameters for your network */ - "keepalive_interval": 10, - "stat_interval": 30, - "push_timeout_ms": 100, - /* forward only valid packets */ - "forward_crc_valid": true, - "forward_crc_error": false, - "forward_crc_disabled": false, - /* GPS configuration */ - "gps_tty_path": "/dev/ttyACM0" - } -} diff --git a/gps_pkt_fwd/global_conf.json b/gps_pkt_fwd/global_conf.json new file mode 100644 index 00000000..5f43c6c0 --- /dev/null +++ b/gps_pkt_fwd/global_conf.json @@ -0,0 +1,215 @@ +{ + "SX1301_conf": { + "lorawan_public": true, + "clksrc": 1, /* radio_1 provides clock to concentrator */ + "radio_0": { + "enable": true, + "type": "SX1257", + "freq": 867500000, + "rssi_offset": -166.0, + "tx_enable": true + }, + "radio_1": { + "enable": true, + "type": "SX1257", + "freq": 868500000, + "rssi_offset": -166.0, + "tx_enable": false + }, + "chan_multiSF_0": { + /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */ + "enable": true, + "radio": 1, + "if": -400000 + }, + "chan_multiSF_1": { + /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ + "enable": true, + "radio": 1, + "if": -200000 + }, + "chan_multiSF_2": { + /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ + "enable": true, + "radio": 1, + "if": 0 + }, + "chan_multiSF_3": { + /* Lora MAC channel, 125kHz, all SF, 867.1 MHz */ + "enable": true, + "radio": 0, + "if": -400000 + }, + "chan_multiSF_4": { + /* Lora MAC channel, 125kHz, all SF, 867.3 MHz */ + "enable": true, + "radio": 0, + "if": -200000 + }, + "chan_multiSF_5": { + /* Lora MAC channel, 125kHz, all SF, 867.5 MHz */ + "enable": true, + "radio": 0, + "if": 0 + }, + "chan_multiSF_6": { + /* Lora MAC channel, 125kHz, all SF, 867.7 MHz */ + "enable": true, + "radio": 0, + "if": 200000 + }, + "chan_multiSF_7": { + /* Lora MAC channel, 125kHz, all SF, 867.9 MHz */ + "enable": true, + "radio": 0, + "if": 400000 + }, + "chan_Lora_std": { + /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ + "enable": true, + "radio": 1, + "if": -200000, + "bandwidth": 250000, + "spread_factor": 7 + }, + "chan_FSK": { + /* FSK 50kbps channel, 868.8 MHz */ + "enable": true, + "radio": 1, + "if": 300000, + "bandwidth": 125000, + "datarate": 50000 + }, + "tx_lut_0": { + /* TX gain table, index 0 */ + "pa_gain": 0, + "mix_gain": 8, + "rf_power": -6, + "dig_gain": 0 + }, + "tx_lut_1": { + /* TX gain table, index 1 */ + "pa_gain": 0, + "mix_gain": 10, + "rf_power": -3, + "dig_gain": 0 + }, + "tx_lut_2": { + /* TX gain table, index 2 */ + "pa_gain": 0, + "mix_gain": 12, + "rf_power": 0, + "dig_gain": 0 + }, + "tx_lut_3": { + /* TX gain table, index 3 */ + "pa_gain": 1, + "mix_gain": 8, + "rf_power": 3, + "dig_gain": 0 + }, + "tx_lut_4": { + /* TX gain table, index 4 */ + "pa_gain": 1, + "mix_gain": 10, + "rf_power": 6, + "dig_gain": 0 + }, + "tx_lut_5": { + /* TX gain table, index 5 */ + "pa_gain": 1, + "mix_gain": 12, + "rf_power": 10, + "dig_gain": 0 + }, + "tx_lut_6": { + /* TX gain table, index 6 */ + "pa_gain": 1, + "mix_gain": 13, + "rf_power": 11, + "dig_gain": 0 + }, + "tx_lut_7": { + /* TX gain table, index 7 */ + "pa_gain": 2, + "mix_gain": 9, + "rf_power": 12, + "dig_gain": 0 + }, + "tx_lut_8": { + /* TX gain table, index 8 */ + "pa_gain": 1, + "mix_gain": 15, + "rf_power": 13, + "dig_gain": 0 + }, + "tx_lut_9": { + /* TX gain table, index 9 */ + "pa_gain": 2, + "mix_gain": 10, + "rf_power": 14, + "dig_gain": 0 + }, + "tx_lut_10": { + /* TX gain table, index 10 */ + "pa_gain": 2, + "mix_gain": 11, + "rf_power": 16, + "dig_gain": 0 + }, + "tx_lut_11": { + /* TX gain table, index 11 */ + "pa_gain": 3, + "mix_gain": 9, + "rf_power": 20, + "dig_gain": 0 + }, + "tx_lut_12": { + /* TX gain table, index 12 */ + "pa_gain": 3, + "mix_gain": 10, + "rf_power": 23, + "dig_gain": 0 + }, + "tx_lut_13": { + /* TX gain table, index 13 */ + "pa_gain": 3, + "mix_gain": 11, + "rf_power": 25, + "dig_gain": 0 + }, + "tx_lut_14": { + /* TX gain table, index 14 */ + "pa_gain": 3, + "mix_gain": 12, + "rf_power": 26, + "dig_gain": 0 + }, + "tx_lut_15": { + /* TX gain table, index 15 */ + "pa_gain": 3, + "mix_gain": 14, + "rf_power": 27, + "dig_gain": 0 + } + }, + + "gateway_conf": { + "gateway_ID": "AA555A0000000000", + /* change with default server address/ports, or overwrite in local_conf.json */ + "server_address": "iot.semtech.com", + "serv_port_up": 1680, + "serv_port_down": 1680, + /* adjust the following parameters for your network */ + "keepalive_interval": 10, + "stat_interval": 30, + "push_timeout_ms": 100, + /* forward only valid packets */ + "forward_crc_valid": true, + "forward_crc_error": false, + "forward_crc_disabled": false, + /* GPS configuration */ + "gps_tty_path": "/dev/ttyACM0" + } +} + diff --git a/gps_pkt_fwd/src/gps_pkt_fwd.c b/gps_pkt_fwd/src/gps_pkt_fwd.c index 79f75845..57ffc7bf 100644 --- a/gps_pkt_fwd/src/gps_pkt_fwd.c +++ b/gps_pkt_fwd/src/gps_pkt_fwd.c @@ -213,21 +213,24 @@ static void sig_handler(int sigio) { 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_Value *val = NULL; + struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; struct lgw_conf_rxif_s ifconf; uint32_t sf, bw, fdev; - + struct lgw_tx_gain_lut_s txlut; + /* 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) { @@ -236,7 +239,86 @@ static int parse_SX1301_configuration(const char * conf_file) { } 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("WARNING: Failed to configure board\n"); + } + + /* 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 */ + MSG("INFO: Configuring TX LUT with %u indexes\n", txlut.size); + if (lgw_txgain_setconf(&txlut) != LGW_HAL_SUCCESS) { + MSG("WARNING: Failed to configure concentrator TX Gain LUT\n"); + } + /* set configuration for RF chains */ for (i = 0; i < LGW_RF_CHAIN_NB; ++i) { memset(&rfconf, 0, sizeof rfconf); /* initialize configuration structure */ @@ -259,14 +341,32 @@ static int parse_SX1301_configuration(const char * conf_file) { } 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); - MSG("INFO: radio %i enabled, center frequency %u\n", i, rfconf.freq_hz); + 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); + } else { + rfconf.tx_enable = false; + } + MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable); } /* all parameters parsed, submitting configuration to the HAL */ if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) { MSG("WARNING: invalid configuration for radio %i\n", i); } } - + /* 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 */ @@ -299,7 +399,7 @@ static int parse_SX1301_configuration(const char * conf_file) { MSG("WARNING: invalid configuration for Lora multi-SF channel %i\n", i); } } - + /* 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) */ @@ -340,7 +440,7 @@ static int parse_SX1301_configuration(const char * conf_file) { MSG("WARNING: invalid configuration for Lora standard channel\n"); } } - + /* 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) */ @@ -361,7 +461,7 @@ static int parse_SX1301_configuration(const char * conf_file) { 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; @@ -375,7 +475,7 @@ static int parse_SX1301_configuration(const char * conf_file) { 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) { @@ -393,14 +493,14 @@ static int parse_gateway_configuration(const char * conf_file) { 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) { @@ -409,7 +509,7 @@ static int parse_gateway_configuration(const char * conf_file) { } 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) { @@ -417,14 +517,14 @@ static int parse_gateway_configuration(const char * conf_file) { 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) { @@ -436,28 +536,28 @@ static int parse_gateway_configuration(const char * conf_file) { 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) { @@ -474,14 +574,14 @@ static int parse_gateway_configuration(const char * conf_file) { 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) { @@ -498,7 +598,7 @@ static int parse_gateway_configuration(const char * conf_file) { 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) { @@ -509,14 +609,14 @@ static int parse_gateway_configuration(const char * conf_file) { MSG("INFO: fake GPS is disabled\n"); } } - + /* 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; @@ -524,10 +624,10 @@ static int parse_gateway_configuration(const char * conf_file) { static double difftimespec(struct timespec end, struct timespec beginning) { double x; - + x = 1E-9 * (double)(end.tv_nsec - beginning.tv_nsec); x += (double)(end.tv_sec - beginning.tv_sec); - + return x; } @@ -538,25 +638,25 @@ int main(void) { struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ int i; /* loop variable and temporary variable for return value */ - + /* configuration file related */ char *global_cfg_path= "global_conf.json"; /* contain global (typ. network-wide) configuration */ char *local_cfg_path = "local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */ char *debug_cfg_path = "debug_conf.json"; /* if present, all other configuration files are ignored */ - + /* threads */ pthread_t thrid_up; pthread_t thrid_down; pthread_t thrid_gps; pthread_t thrid_valid; - + /* network socket creation */ struct addrinfo hints; struct addrinfo *result; /* store result of getaddrinfo */ struct addrinfo *q; /* pointer to move into *result data */ char host_name[64]; char port_name[64]; - + /* variables to get local copies of measurements */ uint32_t cp_nb_rx_rcv; uint32_t cp_nb_rx_ok; @@ -574,12 +674,12 @@ int main(void) uint32_t cp_dw_payload_byte; uint32_t cp_nb_tx_ok; uint32_t cp_nb_tx_fail; - + /* GPS coordinates variables */ bool coord_ok = false; struct coord_s cp_gps_coord = {0.0, 0.0, 0}; //struct coord_s cp_gps_err; - + /* statistics variable */ time_t t; char stat_timestamp[24]; @@ -588,11 +688,11 @@ int main(void) float rx_nocrc_ratio; float up_ack_ratio; float dw_ack_ratio; - + /* display version informations */ MSG("*** GPS Packet Forwarder for Lora Gateway ***\nVersion: " VERSION_STRING "\n"); MSG("*** Lora concentrator HAL library version info ***\n%s\n***\n", lgw_version_info()); - + /* display host endianness */ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ MSG("INFO: Little endian host\n"); @@ -601,7 +701,7 @@ int main(void) #else MSG("INFO: Host endianness unknown\n"); #endif - + /* 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); @@ -626,7 +726,7 @@ int main(void) 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); } - + /* Start GPS a.s.a.p., to allow it to lock */ i = lgw_gps_enable(gps_tty_path, NULL, 0, &gps_tty_fd); if (i != LGW_GPS_SUCCESS) { @@ -638,29 +738,29 @@ int main(void) gps_enabled = true; gps_ref_valid = false; } - + /* get timezone info */ tzset(); - + /* sanity check on configuration variables */ // TODO - + /* process some of the configuration variables */ net_mac_h = htonl((uint32_t)(0xFFFFFFFF & (lgwm>>32))); net_mac_l = htonl((uint32_t)(0xFFFFFFFF & lgwm )); - + /* prepare hints to open network sockets */ memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; /* should handle IP v4 or v6 automatically */ hints.ai_socktype = SOCK_DGRAM; - + /* look for server address w/ upstream port */ i = getaddrinfo(serv_addr, serv_port_up, &hints, &result); if (i != 0) { MSG("ERROR: [up] getaddrinfo on address %s (PORT %s) returned %s\n", serv_addr, serv_port_up, gai_strerror(i)); exit(EXIT_FAILURE); } - + /* try to open socket for upstream traffic */ for (q=result; q!=NULL; q=q->ai_next) { sock_up = socket(q->ai_family, q->ai_socktype,q->ai_protocol); @@ -677,7 +777,7 @@ int main(void) } exit(EXIT_FAILURE); } - + /* connect so we can send/receive packet with the server only */ i = connect(sock_up, q->ai_addr, q->ai_addrlen); if (i != 0) { @@ -692,7 +792,7 @@ int main(void) MSG("ERROR: [down] getaddrinfo on address %s (port %s) returned %s\n", serv_addr, serv_port_up, gai_strerror(i)); exit(EXIT_FAILURE); } - + /* try to open socket for downstream traffic */ for (q=result; q!=NULL; q=q->ai_next) { sock_down = socket(q->ai_family, q->ai_socktype,q->ai_protocol); @@ -709,7 +809,7 @@ int main(void) } exit(EXIT_FAILURE); } - + /* connect so we can send/receive packet with the server only */ i = connect(sock_down, q->ai_addr, q->ai_addrlen); if (i != 0) { @@ -717,7 +817,7 @@ int main(void) exit(EXIT_FAILURE); } freeaddrinfo(result); - + /* starting the concentrator */ i = lgw_start(); if (i == LGW_HAL_SUCCESS) { @@ -726,7 +826,7 @@ int main(void) MSG("ERROR: [main] failed to start the concentrator\n"); exit(EXIT_FAILURE); } - + /* spawn threads to manage upstream and downstream */ i = pthread_create( &thrid_up, NULL, (void * (*)(void *))thread_up, NULL); if (i != 0) { @@ -738,7 +838,7 @@ int main(void) MSG("ERROR: [main] impossible to create downstream thread\n"); exit(EXIT_FAILURE); } - + /* spawn thread to manage GPS */ if (gps_enabled == true) { i = pthread_create( &thrid_gps, NULL, (void * (*)(void *))thread_gps, NULL); @@ -752,7 +852,7 @@ int main(void) exit(EXIT_FAILURE); } } - + /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; @@ -760,16 +860,16 @@ int main(void) sigaction(SIGQUIT, &sigact, NULL); /* Ctrl-\ */ sigaction(SIGINT, &sigact, NULL); /* Ctrl-C */ sigaction(SIGTERM, &sigact, NULL); /* default "kill" command */ - + /* main loop task : statistics collection */ while (!exit_sig && !quit_sig) { /* wait for next reporting interval */ wait_ms(1000 * stat_interval); - + /* get timestamp for statistics */ t = time(NULL); strftime(stat_timestamp, sizeof stat_timestamp, "%F %T %Z", gmtime(&t)); - + /* access upstream statistics, copy and reset them */ pthread_mutex_lock(&mx_meas_up); cp_nb_rx_rcv = meas_nb_rx_rcv; @@ -805,7 +905,7 @@ int main(void) } else { up_ack_ratio = 0.0; } - + /* access downstream statistics, copy and reset them */ pthread_mutex_lock(&mx_meas_dw); cp_dw_pull_sent = meas_dw_pull_sent; @@ -828,7 +928,7 @@ int main(void) } else { dw_ack_ratio = 0.0; } - + /* access GPS statistics, copy them */ if (gps_enabled == true) { pthread_mutex_lock(&mx_meas_gps); @@ -837,14 +937,14 @@ int main(void) //cp_gps_err = meas_gps_err; pthread_mutex_unlock(&mx_meas_gps); } - + /* overwrite with reference coordinates if function is enabled */ if (gps_fake_enable == true) { gps_enabled = true; coord_ok = true; cp_gps_coord = reference_coord; } - + /* display a report */ printf("\n##### %s #####\n", stat_timestamp); printf("### [UPSTREAM] ###\n"); @@ -877,7 +977,7 @@ int main(void) printf("# GPS sync is disabled\n"); } printf("##### END #####\n"); - + /* generate a JSON report (will be sent to server by upstream thread) */ pthread_mutex_lock(&mx_stat_rep); if ((gps_enabled == true) && (coord_ok == true)) { @@ -888,13 +988,13 @@ int main(void) report_ready = true; pthread_mutex_unlock(&mx_stat_rep); } - + /* wait for upstream thread to finish (1 fetch cycle max) */ pthread_join(thrid_up, NULL); pthread_cancel(thrid_down); /* don't wait for downstream thread */ pthread_cancel(thrid_gps); /* don't wait for GPS thread */ pthread_cancel(thrid_valid); /* don't wait for validation thread */ - + /* if an exit signal was received, try to quit properly */ if (exit_sig) { /* shut down network sockets */ @@ -908,7 +1008,7 @@ int main(void) MSG("WARNING: failed to stop concentrator successfully\n"); } } - + MSG("INFO: Exiting packet forwarder program\n"); exit(EXIT_SUCCESS); } @@ -919,51 +1019,51 @@ int main(void) void thread_up(void) { int i, j; /* loop variables */ unsigned pkt_in_dgram; /* nb on Lora packet in the current datagram */ - + /* allocate memory for packet fetching and processing */ struct lgw_pkt_rx_s rxpkt[NB_PKT_MAX]; /* array containing inbound packets + metadata */ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ int nb_pkt; - + /* local copy of GPS time reference */ bool ref_ok = false; /* determine if GPS time reference must be used or not */ struct tref local_ref; /* time reference used for UTC <-> timestamp conversion */ - + /* data buffers */ uint8_t buff_up[TX_BUFF_SIZE]; /* buffer to compose the upstream packet */ int buff_index; uint8_t buff_ack[32]; /* buffer to receive acknowledges */ - + /* protocol variables */ uint8_t token_h; /* random token for acknowledgement matching */ uint8_t token_l; /* random token for acknowledgement matching */ - + /* ping measurement variables */ struct timespec send_time; struct timespec recv_time; - + /* GPS synchronization variables */ struct timespec pkt_utc_time; struct tm * x; /* broken-up UTC time */ - + /* report management variable */ bool send_report = false; - + /* set upstream socket RX timeout */ i = setsockopt(sock_up, SOL_SOCKET, SO_RCVTIMEO, (void *)&push_timeout_half, sizeof push_timeout_half); if (i != 0) { MSG("ERROR: [up] setsockopt returned %s\n", strerror(errno)); exit(EXIT_FAILURE); } - + /* pre-fill the data buffer with fixed fields */ buff_up[0] = PROTOCOL_VERSION; buff_up[3] = PKT_PUSH_DATA; *(uint32_t *)(buff_up + 4) = net_mac_h; *(uint32_t *)(buff_up + 8) = net_mac_l; - + while (!exit_sig && !quit_sig) { - + /* fetch packets */ pthread_mutex_lock(&mx_concent); nb_pkt = lgw_receive(NB_PKT_MAX, rxpkt); @@ -971,18 +1071,18 @@ void thread_up(void) { if (nb_pkt == LGW_HAL_ERROR) { MSG("ERROR: [up] failed packet fetch, exiting\n"); exit(EXIT_FAILURE); - } - + } + /* check if there are status report to send */ send_report = report_ready; /* copy the variable so it doesn't change mid-function */ /* no mutex, we're only reading */ - + /* wait a short time if no packets, nor status report */ if ((nb_pkt == 0) && (send_report == false)) { wait_ms(FETCH_SLEEP_MS); continue; } - + /* get a copy of GPS time reference (avoid 1 mutex per packet) */ if ((nb_pkt > 0) && (gps_enabled == true)) { pthread_mutex_lock(&mx_timeref); @@ -992,23 +1092,23 @@ void thread_up(void) { } else { ref_ok = false; } - + /* start composing datagram with the header */ token_h = (uint8_t)rand(); /* random token */ token_l = (uint8_t)rand(); /* random token */ buff_up[1] = token_h; buff_up[2] = token_l; buff_index = 12; /* 12-byte header */ - + /* start of JSON structure */ memcpy((void *)(buff_up + buff_index), (void *)"{\"rxpk\":[", 9); buff_index += 9; - + /* serialize Lora packets metadata and payload */ pkt_in_dgram = 0; for (i=0; i < nb_pkt; ++i) { p = &rxpkt[i]; - + /* basic packet filtering */ pthread_mutex_lock(&mx_meas_up); meas_nb_rx_rcv += 1; @@ -1043,7 +1143,7 @@ void thread_up(void) { meas_up_pkt_fwd += 1; meas_up_payload_byte += p->size; pthread_mutex_unlock(&mx_meas_up); - + /* Start of packet, add inter-packet separator if necessary */ if (pkt_in_dgram == 0) { buff_up[buff_index] = '{'; @@ -1053,7 +1153,7 @@ void thread_up(void) { buff_up[buff_index+1] = '{'; buff_index += 2; } - + /* RAW timestamp, 8-17 useful chars */ j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "\"tmst\":%u", p->count_us); if (j > 0) { @@ -1062,7 +1162,7 @@ void thread_up(void) { MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); exit(EXIT_FAILURE); } - + /* Packet RX time (GPS based), 37 useful chars */ if (ref_ok == true) { /* convert packet timestamp to UTC absolute time */ @@ -1079,7 +1179,7 @@ void thread_up(void) { } } } - + /* Packet concentrator channel, RF chain & RX frequency, 34-36 useful chars */ j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"chan\":%1u,\"rfch\":%1u,\"freq\":%.6lf", p->if_chain, p->rf_chain, ((double)p->freq_hz / 1e6)); if (j > 0) { @@ -1088,7 +1188,7 @@ void thread_up(void) { MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); exit(EXIT_FAILURE); } - + /* Packet status, 9-10 useful chars */ switch (p->status) { case STAT_CRC_OK: @@ -1109,12 +1209,12 @@ void thread_up(void) { buff_index += 9; exit(EXIT_FAILURE); } - + /* Packet modulation, 13-14 useful chars */ if (p->modulation == MOD_LORA) { memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"LORA\"", 14); buff_index += 14; - + /* Lora datarate & bandwidth, 16-19 useful chars */ switch (p->datarate) { case DR_LORA_SF7: @@ -1166,7 +1266,7 @@ void thread_up(void) { buff_index += 4; exit(EXIT_FAILURE); } - + /* Packet ECC coding rate, 11-13 useful chars */ switch (p->coderate) { case CR_LORA_4_5: @@ -1195,7 +1295,7 @@ void thread_up(void) { buff_index += 11; exit(EXIT_FAILURE); } - + /* Lora SNR, 11-13 useful chars */ j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"lsnr\":%.1f", p->snr); if (j > 0) { @@ -1207,7 +1307,7 @@ void thread_up(void) { } else if (p->modulation == MOD_FSK) { memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"FSK\"", 13); buff_index += 13; - + /* FSK datarate, 11-14 useful chars */ j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"datr\":%u", p->datarate); if (j > 0) { @@ -1220,7 +1320,7 @@ void thread_up(void) { MSG("ERROR: [up] received packet with unknown modulation\n"); exit(EXIT_FAILURE); } - + /* Packet RSSI, payload size, 18-23 useful chars */ j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"rssi\":%.0f,\"size\":%u", p->rssi, p->size); if (j > 0) { @@ -1229,7 +1329,7 @@ void thread_up(void) { MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); exit(EXIT_FAILURE); } - + /* Packet base64-encoded payload, 14-350 useful chars */ memcpy((void *)(buff_up + buff_index), (void *)",\"data\":\"", 9); buff_index += 9; @@ -1242,13 +1342,13 @@ void thread_up(void) { } buff_up[buff_index] = '"'; ++buff_index; - + /* End of packet serialization */ buff_up[buff_index] = '}'; ++buff_index; ++pkt_in_dgram; } - + /* restart fetch sequence without sending empty JSON if all packets have been filtered out */ if (pkt_in_dgram == 0) { if (send_report == true) { @@ -1268,7 +1368,7 @@ void thread_up(void) { ++buff_index; } } - + /* add status report if a new one is available */ if (send_report == true) { pthread_mutex_lock(&mx_stat_rep); @@ -1282,21 +1382,21 @@ void thread_up(void) { exit(EXIT_FAILURE); } } - + /* end of JSON datagram payload */ buff_up[buff_index] = '}'; ++buff_index; buff_up[buff_index] = 0; /* add string terminator, for safety */ - + // printf("\nJSON up: %s\n", (char *)(buff_up + 12)); /* DEBUG: display JSON payload */ - + /* send datagram to server */ send(sock_up, (void *)buff_up, buff_index, 0); clock_gettime(CLOCK_MONOTONIC, &send_time); pthread_mutex_lock(&mx_meas_up); meas_up_dgram_sent += 1; meas_up_network_byte += buff_index; - + /* wait for acknowledge (in 2 times, to catch extra packets) */ for (i=0; i<2; ++i) { j = recv(sock_up, (void *)buff_ack, sizeof buff_ack, 0); @@ -1329,25 +1429,25 @@ void thread_up(void) { void thread_down(void) { int i; /* loop variables */ - + /* configuration and metadata for an outbound packet */ struct lgw_pkt_tx_s txpkt; bool sent_immediate = false; /* option to sent the packet immediately */ - + /* local timekeeping variables */ struct timespec send_time; /* time of the pull request */ struct timespec recv_time; /* time of return from recv socket call */ - + /* data buffers */ uint8_t buff_down[1000]; /* buffer to receive downstream packets */ uint8_t buff_req[12]; /* buffer to compose pull requests */ int msg_len; - + /* protocol variables */ uint8_t token_h; /* random token for acknowledgement matching */ uint8_t token_l; /* random token for acknowledgement matching */ bool req_ack = false; /* keep track of whether PULL_DATA was acknowledged or not */ - + /* JSON parsing variables */ JSON_Value *root_val = NULL; JSON_Object *txpk_obj = NULL; @@ -1356,43 +1456,43 @@ void thread_down(void) { short x0, x1; short x2, x3, x4; double x5, x6; - + /* variables to send on UTC timestamp */ struct tref local_ref; /* time reference used for UTC <-> timestamp conversion */ struct tm utc_vector; /* for collecting the elements of the UTC time */ struct timespec utc_tx; /* UTC time that needs to be converted to timestamp */ - + /* auto-quit variable */ uint32_t autoquit_cnt = 0; /* count the number of PULL_DATA sent since the latest PULL_ACK */ - + /* set downstream socket RX timeout */ i = setsockopt(sock_down, SOL_SOCKET, SO_RCVTIMEO, (void *)&pull_timeout, sizeof pull_timeout); if (i != 0) { MSG("ERROR: [down] setsockopt returned %s\n", strerror(errno)); exit(EXIT_FAILURE); } - + /* pre-fill the pull request buffer with fixed fields */ buff_req[0] = PROTOCOL_VERSION; buff_req[3] = PKT_PULL_DATA; *(uint32_t *)(buff_req + 4) = net_mac_h; *(uint32_t *)(buff_req + 8) = net_mac_l; - + while (!exit_sig && !quit_sig) { - + /* auto-quit if the threshold is crossed */ if ((autoquit_threshold > 0) && (autoquit_cnt >= autoquit_threshold)) { exit_sig = true; MSG("INFO: [down] the last %u PULL_DATA were not ACKed, exiting application\n", autoquit_threshold); break; } - + /* generate random token for request */ token_h = (uint8_t)rand(); /* random token */ token_l = (uint8_t)rand(); /* random token */ buff_req[1] = token_h; buff_req[2] = token_l; - + /* send PULL request and record time */ send(sock_down, (void *)buff_req, sizeof buff_req, 0); clock_gettime(CLOCK_MONOTONIC, &send_time); @@ -1401,27 +1501,27 @@ void thread_down(void) { pthread_mutex_unlock(&mx_meas_dw); req_ack = false; autoquit_cnt++; - + /* listen to packets and process them until a new PULL request must be sent */ recv_time = send_time; while ((int)difftimespec(recv_time, send_time) < keepalive_time) { - + /* try to receive a datagram */ msg_len = recv(sock_down, (void *)buff_down, (sizeof buff_down)-1, 0); clock_gettime(CLOCK_MONOTONIC, &recv_time); - + /* if no network message was received, got back to listening sock_down socket */ if (msg_len == -1) { //MSG("WARNING: [down] recv returned %s\n", strerror(errno)); /* too verbose */ continue; } - + /* if the datagram does not respect protocol, just ignore it */ if ((msg_len < 4) || (buff_down[0] != PROTOCOL_VERSION) || ((buff_down[3] != PKT_PULL_RESP) && (buff_down[3] != PKT_PULL_ACK))) { MSG("WARNING: [down] ignoring invalid packet\n"); continue; } - + /* if the datagram is an ACK, check token */ if (buff_down[3] == PKT_PULL_ACK) { if ((buff_down[1] == token_h) && (buff_down[2] == token_l)) { @@ -1440,12 +1540,12 @@ void thread_down(void) { } continue; } - + /* the datagram is a PULL_RESP */ buff_down[msg_len] = 0; /* add string terminator, just to be safe */ MSG("INFO: [down] PULL_RESP received :)\n"); /* very verbose */ // printf("\nJSON down: %s\n", (char *)(buff_down + 4)); /* DEBUG: display JSON payload */ - + /* initialize TX struct and try to parse JSON */ memset(&txpkt, 0, sizeof txpkt); root_val = json_parse_string_with_comments((const char *)(buff_down + 4)); /* JSON offset */ @@ -1453,7 +1553,7 @@ void thread_down(void) { MSG("WARNING: [down] invalid JSON, TX aborted\n"); continue; } - + /* look for JSON sub-object 'txpk' */ txpk_obj = json_object_get_object(json_value_get_object(root_val), "txpk"); if (txpk_obj == NULL) { @@ -1461,7 +1561,7 @@ void thread_down(void) { json_value_free(root_val); continue; } - + /* Parse "immediate" tag, or target timestamp, or UTC time to be converted by GPS (mandatory) */ i = json_object_get_boolean(txpk_obj,"imme"); /* can be 1 if true, 0 if false, or -1 if not a JSON boolean */ if (i == 1) { @@ -1499,7 +1599,7 @@ void thread_down(void) { json_value_free(root_val); continue; } - + i = sscanf (str, "%4hd-%2hd-%2hdT%2hd:%2hd:%9lf", &x0, &x1, &x2, &x3, &x4, &x5); if (i != 6 ) { MSG("WARNING: [down] \"txpk.time\" must follow ISO 8601 format, TX aborted\n"); @@ -1515,7 +1615,7 @@ void thread_down(void) { utc_vector.tm_sec = (int)x6; utc_tx.tv_sec = mktime(&utc_vector) - timezone; utc_tx.tv_nsec = (long)(1e9 * x5); - + /* transform UTC time to timestamp */ i = lgw_utc2cnt(local_ref, utc_tx, &(txpkt.count_us)); if (i != LGW_GPS_SUCCESS) { @@ -1527,13 +1627,13 @@ void thread_down(void) { } } } - + /* Parse "No CRC" flag (optional field) */ val = json_object_get_value(txpk_obj,"ncrc"); if (val != NULL) { txpkt.no_crc = (bool)json_value_get_boolean(val); } - + /* parse target frequency (mandatory) */ val = json_object_get_value(txpk_obj,"freq"); if (val == NULL) { @@ -1542,7 +1642,7 @@ void thread_down(void) { continue; } txpkt.freq_hz = (uint32_t)((double)(1.0e6) * json_value_get_number(val)); - + /* parse RF chain used for TX (mandatory) */ val = json_object_get_value(txpk_obj,"rfch"); if (val == NULL) { @@ -1551,13 +1651,13 @@ void thread_down(void) { continue; } txpkt.rf_chain = (uint8_t)json_value_get_number(val); - + /* parse TX power (optional field) */ val = json_object_get_value(txpk_obj,"powe"); if (val != NULL) { txpkt.rf_power = (int8_t)json_value_get_number(val); } - + /* Parse modulation (mandatory) */ str = json_object_get_string(txpk_obj, "modu"); if (str == NULL) { @@ -1568,7 +1668,7 @@ void thread_down(void) { if (strcmp(str, "LORA") == 0) { /* Lora modulation */ txpkt.modulation = MOD_LORA; - + /* Parse Lora spreading-factor and modulation bandwidth (mandatory) */ str = json_object_get_string(txpk_obj, "datr"); if (str == NULL) { @@ -1603,7 +1703,7 @@ void thread_down(void) { json_value_free(root_val); continue; } - + /* Parse ECC coding rate (optional field) */ str = json_object_get_string(txpk_obj, "codr"); if (str == NULL) { @@ -1622,13 +1722,13 @@ void thread_down(void) { json_value_free(root_val); continue; } - + /* Parse signal polarity switch (optional field) */ val = json_object_get_value(txpk_obj,"ipol"); if (val != NULL) { txpkt.invert_pol = (bool)json_value_get_boolean(val); } - + /* parse Lora preamble length (optional field, optimum min value enforced) */ val = json_object_get_value(txpk_obj,"prea"); if (val != NULL) { @@ -1641,11 +1741,11 @@ void thread_down(void) { } else { txpkt.preamble = (uint16_t)STD_LORA_PREAMB; } - + } else if (strcmp(str, "FSK") == 0) { /* FSK modulation */ txpkt.modulation = MOD_FSK; - + /* parse FSK bitrate (mandatory) */ val = json_object_get_value(txpk_obj,"datr"); if (val == NULL) { @@ -1654,7 +1754,7 @@ void thread_down(void) { continue; } txpkt.datarate = (uint32_t)(json_value_get_number(val)); - + /* parse frequency deviation (mandatory) */ val = json_object_get_value(txpk_obj,"fdev"); if (val == NULL) { @@ -1663,7 +1763,7 @@ void thread_down(void) { continue; } txpkt.f_dev = (uint8_t)(json_value_get_number(val) / 1000.0); /* JSON value in Hz, txpkt.f_dev in kHz */ - + /* parse FSK preamble length (optional field, optimum min value enforced) */ val = json_object_get_value(txpk_obj,"prea"); if (val != NULL) { @@ -1676,13 +1776,13 @@ void thread_down(void) { } else { txpkt.preamble = (uint16_t)STD_FSK_PREAMB; } - + } else { MSG("WARNING: [down] invalid modulation in \"txpk.modu\", TX aborted\n"); json_value_free(root_val); continue; } - + /* Parse payload length (mandatory) */ val = json_object_get_value(txpk_obj,"size"); if (val == NULL) { @@ -1691,7 +1791,7 @@ void thread_down(void) { continue; } txpkt.size = (uint16_t)json_value_get_number(val); - + /* Parse payload data (mandatory) */ str = json_object_get_string(txpk_obj, "data"); if (str == NULL) { @@ -1703,23 +1803,23 @@ void thread_down(void) { if (i != txpkt.size) { MSG("WARNING: [down] mismatch between .size and .data size once converter to binary\n"); } - + /* free the JSON parse tree from memory */ json_value_free(root_val); - + /* select TX mode */ if (sent_immediate) { txpkt.tx_mode = IMMEDIATE; } else { txpkt.tx_mode = TIMESTAMPED; } - + /* record measurement data */ pthread_mutex_lock(&mx_meas_dw); meas_dw_dgram_rcv += 1; /* count only datagrams with no JSON errors */ meas_dw_network_byte += msg_len; /* meas_dw_network_byte */ meas_dw_payload_byte += txpkt.size; - + /* transfer data and metadata to the concentrator, and schedule TX */ pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish */ i = lgw_send(txpkt); @@ -1743,7 +1843,7 @@ void thread_down(void) { void thread_gps(void) { int i; - + /* serial variables */ char serial_buff[128]; /* buffer to receive GPS data */ ssize_t nb_char; @@ -1752,14 +1852,14 @@ void thread_gps(void) { enum gps_msg latest_msg; /* keep track of latest NMEA message parsed */ struct timespec utc_time; /* UTC time associated with PPS pulse */ uint32_t trig_tstamp; /* concentrator timestamp associated with PPM pulse */ - + /* position variable */ struct coord_s coord; struct coord_s gpserr; - + /* initialize some variables before loop */ memset(serial_buff, 0, sizeof serial_buff); - + while (!exit_sig && !quit_sig) { /* blocking canonical read on serial port */ nb_char = read(gps_tty_fd, serial_buff, sizeof(serial_buff)-1); @@ -1769,19 +1869,19 @@ void thread_gps(void) { } else { serial_buff[nb_char] = 0; /* add null terminator, just to be sure */ } - + /* parse the received NMEA */ latest_msg = lgw_parse_nmea(serial_buff, sizeof(serial_buff)); - + if (latest_msg == NMEA_RMC) { /* trigger sync only on RMC frames */ - + /* get UTC time for synchronization */ i = lgw_gps_get(&utc_time, NULL, NULL); if (i != LGW_GPS_SUCCESS) { MSG("WARNING: [gps] could not get UTC time from GPS\n"); continue; } - + /* get timestamp captured on PPM pulse */ pthread_mutex_lock(&mx_concent); i = lgw_get_trigcnt(&trig_tstamp); @@ -1790,7 +1890,7 @@ void thread_gps(void) { MSG("WARNING: [gps] failed to read concentrator timestamp\n"); continue; } - + /* try to update time reference with the new UTC & timestamp */ pthread_mutex_lock(&mx_timeref); i = lgw_gps_sync(&time_reference_gps, trig_tstamp, utc_time); @@ -1799,7 +1899,7 @@ void thread_gps(void) { MSG("WARNING: [gps] GPS out of sync, keeping previous time reference\n"); continue; } - + /* update gateway coordinates */ i = lgw_gps_get(NULL, &coord, &gpserr); pthread_mutex_lock(&mx_meas_gps); @@ -1821,14 +1921,14 @@ void thread_gps(void) { /* --- THREAD 4: CHECK TIME REFERENCE AND CALCULATE XTAL CORRECTION --------- */ void thread_valid(void) { - + /* GPS reference validation variables */ long gps_ref_age = 0; - + /* main loop task */ while (!exit_sig && !quit_sig) { wait_ms(1000); - + /* calculate when the time reference was last updated */ pthread_mutex_lock(&mx_timeref); gps_ref_age = (long)difftime(time(NULL), time_reference_gps.systime); @@ -1840,7 +1940,7 @@ void thread_valid(void) { gps_ref_valid = false; } pthread_mutex_unlock(&mx_timeref); - + } MSG("\nINFO: End of validation thread\n"); } diff --git a/readme.md b/readme.md index 5a1aec16..9a04d2f6 100644 --- a/readme.md +++ b/readme.md @@ -75,6 +75,15 @@ through the gateway-to-server downlink route. 4. Changelog ------------- +### v2.0.0 - 2015-04-30 ### + +* Changed: Several configuration parameters are now set dynamically from the JSON configuration file: RSSI offset, concentrator clock source, radio type, TX gain table, network type. The HAL does not need to be recompiled any more to update those parameters. An example for IoT Starter Kit platform is provided in global_conf.json for basic, gps and beacon packet_forwarder. +* Removed: Band frequency JSON configuration file has been removed. An example for EU 868MHz is provided in global_conf.json for basic, gps and beacon packet_forwarder. +* Changed: Updated makefiles to allow cross compilation from environment variable (ARCH, CROSS_COMPILE). + +** WARNING: ** +** Update your JSON configuration file with new dynamic parameters. ** + ### v1.4.1 - 2015-01-23 ### * Bugfix: fixed LP-116, fdev parameter parsed incorrectly, making FSK TX fail. @@ -151,4 +160,4 @@ application, the customer shall indemnify and hold Semtech and its officers, employees, subsidiaries, affiliates, and distributors harmless against all claims, costs damages and attorney fees which could arise. -*EOF* \ No newline at end of file +*EOF*