From 17a9aface7bf1aa744ec59faa81890b68bb6e07b Mon Sep 17 00:00:00 2001 From: Van <330406357@qq.com> Date: Mon, 8 Mar 2021 11:23:56 +0800 Subject: [PATCH] Only upgraded for RAK2287, added EU433 and CN470 for RAK2287. --- README.md | 4 + chirpstack/chirpstack-application-server.toml | 31 +- lora/rak2287_spi/Makefile | 126 -- .../global_conf.as_920_923.json | 11 +- .../global_conf.as_923_925.json | 11 +- .../global_conf.au_915_928.json | 11 +- .../global_conf.cn_470_510.json | 103 ++ .../global_conf_i2c/global_conf.eu_433.json | 103 ++ .../global_conf.eu_863_870.json | 11 +- .../global_conf.in_865_867.json | 11 +- .../global_conf.kr_920_923.json | 11 +- .../global_conf.ru_864_870.json | 11 +- .../global_conf.us_902_928.json | 11 +- .../global_conf.as_920_923.json | 11 +- .../global_conf.as_923_925.json | 12 +- .../global_conf.au_915_928.json | 11 +- .../global_conf.cn_470_510.json | 103 ++ .../global_conf_uart/global_conf.eu_433.json | 103 ++ .../global_conf.eu_863_870.json | 11 +- .../global_conf.in_865_867.json | 12 +- .../global_conf.kr_920_923.json | 11 +- .../global_conf.ru_864_870.json | 12 +- .../global_conf.us_902_928.json | 12 +- lora/rak2287_spi/install.sh | 18 +- lora/rak2287_spi/lora_pkt_fwd.c | 570 ++++++++- lora/rak2287_spi/loragw_gps.c | 2 +- lora/rak2287_spi/loragw_hal.c | 1076 ----------------- lora/rak2287_spi/loragw_stts751.c | 185 +++ lora/rak2287_spi/test_loragw_gps_i2c.c | 63 +- lora/rak2287_spi/test_loragw_gps_uart.c | 63 +- rak/gateway-config | 4 +- rak/install.sh | 1 + rak/rak/rak_gw_model.json | 2 +- rak/test_rak | Bin 0 -> 29319 bytes 34 files changed, 1306 insertions(+), 1431 deletions(-) mode change 100644 => 100755 chirpstack/chirpstack-application-server.toml delete mode 100755 lora/rak2287_spi/Makefile create mode 100755 lora/rak2287_spi/global_conf_i2c/global_conf.cn_470_510.json create mode 100755 lora/rak2287_spi/global_conf_i2c/global_conf.eu_433.json create mode 100755 lora/rak2287_spi/global_conf_uart/global_conf.cn_470_510.json create mode 100755 lora/rak2287_spi/global_conf_uart/global_conf.eu_433.json mode change 100644 => 100755 lora/rak2287_spi/lora_pkt_fwd.c delete mode 100644 lora/rak2287_spi/loragw_hal.c create mode 100644 lora/rak2287_spi/loragw_stts751.c create mode 100755 rak/test_rak diff --git a/README.md b/README.md index dca9786..3a4ea69 100755 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ This project currently provides support for the below platforms. * RAK2285 ## Changelog +2021-01-21 V4.2.7 + +* 1.Only upgraded for RAK2287, added EU433 and CN470 for RAK2287. + 2020-11-25 V4.2.6 * 1.Added support for RAK7248C. diff --git a/chirpstack/chirpstack-application-server.toml b/chirpstack/chirpstack-application-server.toml old mode 100644 new mode 100755 index d751889..bee5db7 --- a/chirpstack/chirpstack-application-server.toml +++ b/chirpstack/chirpstack-application-server.toml @@ -60,29 +60,24 @@ url="redis://localhost:6379" # besides the extra integrations that can be added on a per-application # basis. [application_server.integration] + # Payload marshaler. + # + # This defines how the MQTT payloads are encoded. Valid options are: + # * protobuf: Protobuf encoding + # * json: JSON encoding (easier for debugging, but less compact than 'protobuf') + # * json_v3: v3 JSON (will be removed in the next major release) + marshaler="json" + # Enabled integrations. enabled=["mqtt"] # MQTT integration backend. [application_server.integration.mqtt] - # MQTT topic templates for the different MQTT topics. - # - # The meaning of these topics are documented at: - # https://www.chirpstack.io/application-server/integrate/data/ - # - # The following substitutions can be used: - # * "{{ .ApplicationID }}" for the application id. - # * "{{ .DevEUI }}" for the DevEUI of the device. - # - # Note: the downlink_topic_template must contain both the application id and - # DevEUI substitution! - uplink_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/rx" - downlink_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/tx" - join_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/join" - ack_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/ack" - error_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/error" - status_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/status" - location_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/location" + # Event topic template. + event_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/event/{{ .EventType }}" + + # Command topic template. + command_topic_template="application/{{ .ApplicationID }}/device/{{ .DevEUI }}/command/{{ .CommandType }}" # MQTT server (e.g. scheme://host:port where scheme is tcp, ssl or ws) server="tcp://localhost:1883" diff --git a/lora/rak2287_spi/Makefile b/lora/rak2287_spi/Makefile deleted file mode 100755 index 78481b3..0000000 --- a/lora/rak2287_spi/Makefile +++ /dev/null @@ -1,126 +0,0 @@ -### get external defined data - -LIBLORAGW_VERSION := `cat ../VERSION` -include library.cfg -include ../target.cfg - -### constant symbols - -ARCH ?= -CROSS_COMPILE ?= -CC := $(CROSS_COMPILE)gcc -AR := $(CROSS_COMPILE)ar - -CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -I../libtools/inc - -OBJDIR = obj -INCLUDES = $(wildcard inc/*.h) $(wildcard ../libtools/inc/*.h) - -### linking options - -LIBS := -lloragw -ltinymt32 -lrt -lm - -### general build targets - -all: libloragw.a test_loragw_spi test_loragw_i2c test_loragw_reg test_loragw_hal_tx test_loragw_hal_rx test_loragw_cal test_loragw_capture_ram test_loragw_spi_sx1250 test_loragw_counter test_loragw_gps test_loragw_gps_i2c - -clean: - rm -f libloragw.a - rm -f test_loragw_* - rm -f $(OBJDIR)/*.o - rm -f inc/config.h - -install: -ifneq ($(strip $(TARGET_IP)),) - ifneq ($(strip $(TARGET_DIR)),) - ifneq ($(strip $(TARGET_USR)),) - @echo "---- Copying libloragw files to $(TARGET_IP):$(TARGET_DIR)" - @ssh $(TARGET_USR)@$(TARGET_IP) "mkdir -p $(TARGET_DIR)" - @scp test_loragw_* $(TARGET_USR)@$(TARGET_IP):$(TARGET_DIR) - @scp ../tools/reset_lgw.sh $(TARGET_USR)@$(TARGET_IP):$(TARGET_DIR) - else - @echo "ERROR: TARGET_USR is not configured in target.cfg" - endif - else - @echo "ERROR: TARGET_DIR is not configured in target.cfg" - endif -else - @echo "ERROR: TARGET_IP is not configured in target.cfg" -endif - -### transpose library.cfg into a C header file : config.h - -inc/config.h: ../VERSION library.cfg - @echo "*** Checking libloragw library configuration ***" - @rm -f $@ - #File initialization - @echo "#ifndef _LORAGW_CONFIGURATION_H" >> $@ - @echo "#define _LORAGW_CONFIGURATION_H" >> $@ - # Release version - @echo "Release version : $(LIBLORAGW_VERSION)" - @echo " #define LIBLORAGW_VERSION "\"$(LIBLORAGW_VERSION)\""" >> $@ - # Debug options - @echo " #define DEBUG_AUX $(DEBUG_AUX)" >> $@ - @echo " #define DEBUG_SPI $(DEBUG_SPI)" >> $@ - @echo " #define DEBUG_I2C $(DEBUG_I2C)" >> $@ - @echo " #define DEBUG_REG $(DEBUG_REG)" >> $@ - @echo " #define DEBUG_HAL $(DEBUG_HAL)" >> $@ - @echo " #define DEBUG_GPS $(DEBUG_GPS)" >> $@ - @echo " #define DEBUG_GPIO $(DEBUG_GPIO)" >> $@ - @echo " #define DEBUG_LBT $(DEBUG_LBT)" >> $@ - @echo " #define DEBUG_RAD $(DEBUG_RAD)" >> $@ - @echo " #define DEBUG_CAL $(DEBUG_CAL)" >> $@ - @echo " #define DEBUG_SX1302 $(DEBUG_SX1302)" >> $@ - # end of file - @echo "#endif" >> $@ - @echo "*** Configuration seems ok ***" - -### library module target - -$(OBJDIR): - mkdir -p $(OBJDIR) - -$(OBJDIR)/%.o: src/%.c $(INCLUDES) inc/config.h | $(OBJDIR) - $(CC) -c $(CFLAGS) $< -o $@ - -### static library - -libloragw.a: $(OBJDIR)/loragw_spi.o $(OBJDIR)/loragw_i2c.o $(OBJDIR)/loragw_aux.o $(OBJDIR)/loragw_reg.o $(OBJDIR)/loragw_sx1250.o $(OBJDIR)/loragw_sx125x.o $(OBJDIR)/loragw_sx1302.o $(OBJDIR)/loragw_cal.o $(OBJDIR)/loragw_debug.o $(OBJDIR)/loragw_hal.o $(OBJDIR)/loragw_gps.o $(OBJDIR)/loragw_sx1302_timestamp.o $(OBJDIR)/loragw_sx1302_rx.o - $(AR) rcs $@ $^ - -### test programs - -test_loragw_spi: tst/test_loragw_spi.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_i2c: tst/test_loragw_i2c.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_reg: tst/test_loragw_reg.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_hal_tx: tst/test_loragw_hal_tx.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_hal_rx: tst/test_loragw_hal_rx.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_capture_ram: tst/test_loragw_capture_ram.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_cal: tst/test_loragw_cal.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_spi_sx1250: tst/test_loragw_spi_sx1250.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_counter: tst/test_loragw_counter.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_gps: tst/test_loragw_gps.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -test_loragw_gps_i2c: tst/test_loragw_gps_i2c.c libloragw.a - $(CC) $(CFLAGS) -L. -L../libtools $< -o $@ $(LIBS) - -### EOF diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.as_920_923.json b/lora/rak2287_spi/global_conf_i2c/global_conf.as_920_923.json index 16ed944..7bfcb3c 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.as_920_923.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.as_920_923.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": 200000}, /* Freq : 922.6 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": 400000}, /* Freq : 922.8 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 1, "if": 200000}, /* Freq : 923.0 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923400000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.as_923_925.json b/lora/rak2287_spi/global_conf_i2c/global_conf.as_923_925.json index 0fec6ad..41597bb 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.as_923_925.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.as_923_925.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 923.2 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 923.4 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 923.6 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923400000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.au_915_928.json b/lora/rak2287_spi/global_conf_i2c/global_conf.au_915_928.json index 247eb9a..6ce13bd 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.au_915_928.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.au_915_928.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 916.8 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 917.0 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 917.2 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923300000, "beacon_freq_nb": 8, "beacon_freq_step": 600000, diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.cn_470_510.json b/lora/rak2287_spi/global_conf_i2c/global_conf.cn_470_510.json new file mode 100755 index 0000000..7ff4219 --- /dev/null +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.cn_470_510.json @@ -0,0 +1,103 @@ +{ + "SX130x_conf": { + "com_type": "SPI", + "com_path": "/dev/spidev0.0", + "lorawan_public": true, + "clksrc": 0, + "antenna_gain": 0, /* antenna gain, in dBi */ + "full_duplex": false, + "fine_timestamp": { + "enable": false, + "mode": "all_sf" /* high_capacity or all_sf */ + }, + "radio_0": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 486600000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": true, + "tx_freq_min": 470000000, + "tx_freq_max": 510000000, + "tx_gain_lut":[ + {"rf_power": -6, "pa_gain": 0, "pwr_idx": 0}, + {"rf_power": -3, "pa_gain": 0, "pwr_idx": 1}, + {"rf_power": 0, "pa_gain": 0, "pwr_idx": 2}, + {"rf_power": 3, "pa_gain": 1, "pwr_idx": 3}, + {"rf_power": 6, "pa_gain": 1, "pwr_idx": 4}, + {"rf_power": 10, "pa_gain": 1, "pwr_idx": 5}, + {"rf_power": 11, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 12}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 13}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 14}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 15} + ] + }, + "radio_1": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 487400000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": false + }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, + "chan_multiSF_0": {"enable": true, "radio": 1, "if": -300000}, + "chan_multiSF_1": {"enable": true, "radio": 1, "if": -100000}, + "chan_multiSF_2": {"enable": true, "radio": 1, "if": 100000}, + "chan_multiSF_3": {"enable": true, "radio": 1, "if": 300000}, + "chan_multiSF_4": {"enable": true, "radio": 0, "if": -300000}, + "chan_multiSF_5": {"enable": true, "radio": 0, "if": -100000}, + "chan_multiSF_6": {"enable": true, "radio": 0, "if": 100000}, + "chan_multiSF_7": {"enable": true, "radio": 0, "if": 300000}, + "chan_Lora_std": {"enable": false, "radio": 1, "if": -200000, "bandwidth": 250000, "spread_factor": 7, + "implicit_hdr": false, "implicit_payload_length": 17, "implicit_crc_en": false, "implicit_coderate": 1}, + "chan_FSK": {"enable": false, "radio": 1, "if": 300000, "bandwidth": 125000, "datarate": 50000} + }, + + "gateway_conf": { + "gateway_ID": "0000000000000000", + /* change with default server address/ports */ + "server_address": "router.cn.thethings.network", + "serv_port_up": 1700, + "serv_port_down": 1700, + /* 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/i2c-1", + /* GPS reference coordinates */ + "ref_latitude": 0.0, + "ref_longitude": 0.0, + "ref_altitude": 0, + "autoquit_threshold": 20, + /* Beaconing parameters */ + "beacon_period": 0, /* disable class B beacon */ + "beacon_freq_hz": 508300000, + "beacon_freq_nb": 8, + "beacon_freq_step": 200000, + "beacon_datarate": 10, + "beacon_bw_hz": 125000, + "beacon_power": 27 + }, + + "debug_conf": { + "ref_payload":[ + {"id": "0xCAFE1234"}, + {"id": "0xCAFE2345"} + ], + "log_file": "loragw_hal.log" + } +} diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.eu_433.json b/lora/rak2287_spi/global_conf_i2c/global_conf.eu_433.json new file mode 100755 index 0000000..6d36fcb --- /dev/null +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.eu_433.json @@ -0,0 +1,103 @@ +{ + "SX130x_conf": { + "com_type": "SPI", + "com_path": "/dev/spidev0.0", + "lorawan_public": true, + "clksrc": 0, + "antenna_gain": 0, /* antenna gain, in dBi */ + "full_duplex": false, + "fine_timestamp": { + "enable": false, + "mode": "all_sf" /* high_capacity or all_sf */ + }, + "radio_0": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 434375000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": true, + "tx_freq_min": 433050000, + "tx_freq_max": 434900000, + "tx_gain_lut":[ + {"rf_power": -6, "pa_gain": 0, "pwr_idx": 0}, + {"rf_power": -3, "pa_gain": 0, "pwr_idx": 1}, + {"rf_power": 0, "pa_gain": 0, "pwr_idx": 2}, + {"rf_power": 3, "pa_gain": 1, "pwr_idx": 3}, + {"rf_power": 6, "pa_gain": 1, "pwr_idx": 4}, + {"rf_power": 10, "pa_gain": 1, "pwr_idx": 5}, + {"rf_power": 11, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 12}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 13}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 14}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 15} + ] + }, + "radio_1": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 433575000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": false + }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, + "chan_multiSF_0": {"enable": true, "radio": 1, "if": -400000}, + "chan_multiSF_1": {"enable": true, "radio": 1, "if": -200000}, + "chan_multiSF_2": {"enable": true, "radio": 1, "if": 0}, + "chan_multiSF_3": {"enable": true, "radio": 1, "if": 200000}, + "chan_multiSF_4": {"enable": true, "radio": 0, "if": -400000}, + "chan_multiSF_5": {"enable": true, "radio": 0, "if": -200000}, + "chan_multiSF_6": {"enable": true, "radio": 0, "if": 0}, + "chan_multiSF_7": {"enable": true, "radio": 0, "if": 200000}, + "chan_Lora_std": {"enable": true, "radio": 1, "if": -200000, "bandwidth": 250000, "spread_factor": 7, + "implicit_hdr": false, "implicit_payload_length": 17, "implicit_crc_en": false, "implicit_coderate": 1}, + "chan_FSK": {"enable": true, "radio": 1, "if": 300000, "bandwidth": 125000, "datarate": 50000} + }, + + "gateway_conf": { + "gateway_ID": "0000000000000000", + /* change with default server address/ports */ + "server_address": "router.cn.thethings.network", + "serv_port_up": 1700, + "serv_port_down": 1700, + /* 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/i2c-1", + /* GPS reference coordinates */ + "ref_latitude": 0.0, + "ref_longitude": 0.0, + "ref_altitude": 0, + "autoquit_threshold": 20, + /* Beaconing parameters */ + "beacon_period": 0, /* disable class B beacon */ + "beacon_freq_hz": 434665000, + "beacon_freq_nb": 1, + "beacon_freq_step": 0, + "beacon_datarate": 9, + "beacon_bw_hz": 125000, + "beacon_power": 27 + }, + + "debug_conf": { + "ref_payload":[ + {"id": "0xCAFE1234"}, + {"id": "0xCAFE2345"} + ], + "log_file": "loragw_hal.log" + } +} diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.eu_863_870.json b/lora/rak2287_spi/global_conf_i2c/global_conf.eu_863_870.json index b0464e7..8897fb7 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.eu_863_870.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.eu_863_870.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 1, "if": -400000}, "chan_multiSF_1": {"enable": true, "radio": 1, "if": -200000}, "chan_multiSF_2": {"enable": true, "radio": 1, "if": 0}, @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 869525000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.in_865_867.json b/lora/rak2287_spi/global_conf_i2c/global_conf.in_865_867.json index 464a0c0..21ae177 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.in_865_867.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.in_865_867.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -137500}, /* Freq : 865.0625 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": 202500}, /* Freq : 865.4025 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 1, "if": -400000}, /* Freq : 865.9850 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 866500000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.kr_920_923.json b/lora/rak2287_spi/global_conf_i2c/global_conf.kr_920_923.json index bd74a47..b7236a5 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.kr_920_923.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.kr_920_923.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -300000}, /* Freq : 922.1 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -100000}, /* Freq : 922.3 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 100000}, /* Freq : 922.5 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923100000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.ru_864_870.json b/lora/rak2287_spi/global_conf_i2c/global_conf.ru_864_870.json index 78299d2..434ceee 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.ru_864_870.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.ru_864_870.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 864.1 MHz */ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 864.3 MHz */ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 864.5 MHz */ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 869100000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.us_902_928.json b/lora/rak2287_spi/global_conf_i2c/global_conf.us_902_928.json index 7435fda..1773d25 100755 --- a/lora/rak2287_spi/global_conf_i2c/global_conf.us_902_928.json +++ b/lora/rak2287_spi/global_conf_i2c/global_conf.us_902_928.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 903.9 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 904.1 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 904.3 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923300000, "beacon_freq_nb": 8, "beacon_freq_step": 600000, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.as_920_923.json b/lora/rak2287_spi/global_conf_uart/global_conf.as_920_923.json index 4b90f05..927158c 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.as_920_923.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.as_920_923.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": 200000}, /* Freq : 922.6 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": 400000}, /* Freq : 922.8 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 1, "if": 200000}, /* Freq : 923.0 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923400000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.as_923_925.json b/lora/rak2287_spi/global_conf_uart/global_conf.as_923_925.json index 4cfa336..69afe05 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.as_923_925.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.as_923_925.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, + "radio_0": { "enable": true, "type": "SX1250", @@ -46,6 +47,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 923.2 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 923.4 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 923.6 MHz*/ @@ -80,7 +82,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923400000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.au_915_928.json b/lora/rak2287_spi/global_conf_uart/global_conf.au_915_928.json index ec9e248..aa28f2c 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.au_915_928.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.au_915_928.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 916.8 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 917.0 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 917.2 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923300000, "beacon_freq_nb": 8, "beacon_freq_step": 600000, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.cn_470_510.json b/lora/rak2287_spi/global_conf_uart/global_conf.cn_470_510.json new file mode 100755 index 0000000..578a272 --- /dev/null +++ b/lora/rak2287_spi/global_conf_uart/global_conf.cn_470_510.json @@ -0,0 +1,103 @@ +{ + "SX130x_conf": { + "com_type": "SPI", + "com_path": "/dev/spidev0.0", + "lorawan_public": true, + "clksrc": 0, + "antenna_gain": 0, /* antenna gain, in dBi */ + "full_duplex": false, + "fine_timestamp": { + "enable": false, + "mode": "all_sf" /* high_capacity or all_sf */ + }, + "radio_0": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 486600000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": true, + "tx_freq_min": 470000000, + "tx_freq_max": 510000000, + "tx_gain_lut":[ + {"rf_power": -6, "pa_gain": 0, "pwr_idx": 0}, + {"rf_power": -3, "pa_gain": 0, "pwr_idx": 1}, + {"rf_power": 0, "pa_gain": 0, "pwr_idx": 2}, + {"rf_power": 3, "pa_gain": 1, "pwr_idx": 3}, + {"rf_power": 6, "pa_gain": 1, "pwr_idx": 4}, + {"rf_power": 10, "pa_gain": 1, "pwr_idx": 5}, + {"rf_power": 11, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 12}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 13}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 14}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 15} + ] + }, + "radio_1": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 487400000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": false + }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, + "chan_multiSF_0": {"enable": true, "radio": 1, "if": -300000}, + "chan_multiSF_1": {"enable": true, "radio": 1, "if": -100000}, + "chan_multiSF_2": {"enable": true, "radio": 1, "if": 100000}, + "chan_multiSF_3": {"enable": true, "radio": 1, "if": 300000}, + "chan_multiSF_4": {"enable": true, "radio": 0, "if": -300000}, + "chan_multiSF_5": {"enable": true, "radio": 0, "if": -100000}, + "chan_multiSF_6": {"enable": true, "radio": 0, "if": 100000}, + "chan_multiSF_7": {"enable": true, "radio": 0, "if": 300000}, + "chan_Lora_std": {"enable": false, "radio": 1, "if": -200000, "bandwidth": 250000, "spread_factor": 7, + "implicit_hdr": false, "implicit_payload_length": 17, "implicit_crc_en": false, "implicit_coderate": 1}, + "chan_FSK": {"enable": false, "radio": 1, "if": 300000, "bandwidth": 125000, "datarate": 50000} + }, + + "gateway_conf": { + "gateway_ID": "0000000000000000", + /* change with default server address/ports */ + "server_address": "router.cn.thethings.network", + "serv_port_up": 1700, + "serv_port_down": 1700, + /* 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/ttyAMA0", + /* GPS reference coordinates */ + "ref_latitude": 0.0, + "ref_longitude": 0.0, + "ref_altitude": 0, + "autoquit_threshold": 20, + /* Beaconing parameters */ + "beacon_period": 0, /* disable class B beacon */ + "beacon_freq_hz": 508300000, + "beacon_freq_nb": 8, + "beacon_freq_step": 200000, + "beacon_datarate": 10, + "beacon_bw_hz": 125000, + "beacon_power": 27 + }, + + "debug_conf": { + "ref_payload":[ + {"id": "0xCAFE1234"}, + {"id": "0xCAFE2345"} + ], + "log_file": "loragw_hal.log" + } +} diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.eu_433.json b/lora/rak2287_spi/global_conf_uart/global_conf.eu_433.json new file mode 100755 index 0000000..6ce79ca --- /dev/null +++ b/lora/rak2287_spi/global_conf_uart/global_conf.eu_433.json @@ -0,0 +1,103 @@ +{ + "SX130x_conf": { + "com_type": "SPI", + "com_path": "/dev/spidev0.0", + "lorawan_public": true, + "clksrc": 0, + "antenna_gain": 0, /* antenna gain, in dBi */ + "full_duplex": false, + "fine_timestamp": { + "enable": false, + "mode": "all_sf" /* high_capacity or all_sf */ + }, + "radio_0": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 434375000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": true, + "tx_freq_min": 433050000, + "tx_freq_max": 434900000, + "tx_gain_lut":[ + {"rf_power": -6, "pa_gain": 0, "pwr_idx": 0}, + {"rf_power": -3, "pa_gain": 0, "pwr_idx": 1}, + {"rf_power": 0, "pa_gain": 0, "pwr_idx": 2}, + {"rf_power": 3, "pa_gain": 1, "pwr_idx": 3}, + {"rf_power": 6, "pa_gain": 1, "pwr_idx": 4}, + {"rf_power": 10, "pa_gain": 1, "pwr_idx": 5}, + {"rf_power": 11, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 12}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 13}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 14}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 15} + ] + }, + "radio_1": { + "enable": true, + "type": "SX1250", + "single_input_mode": true, + "freq": 433575000, + "rssi_offset": -207.0, + "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, + "tx_enable": false + }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, + "chan_multiSF_0": {"enable": true, "radio": 1, "if": -400000}, + "chan_multiSF_1": {"enable": true, "radio": 1, "if": -200000}, + "chan_multiSF_2": {"enable": true, "radio": 1, "if": 0}, + "chan_multiSF_3": {"enable": true, "radio": 1, "if": 200000}, + "chan_multiSF_4": {"enable": true, "radio": 0, "if": -400000}, + "chan_multiSF_5": {"enable": true, "radio": 0, "if": -200000}, + "chan_multiSF_6": {"enable": true, "radio": 0, "if": 0}, + "chan_multiSF_7": {"enable": true, "radio": 0, "if": 200000}, + "chan_Lora_std": {"enable": true, "radio": 1, "if": -200000, "bandwidth": 250000, "spread_factor": 7, + "implicit_hdr": false, "implicit_payload_length": 17, "implicit_crc_en": false, "implicit_coderate": 1}, + "chan_FSK": {"enable": true, "radio": 1, "if": 300000, "bandwidth": 125000, "datarate": 50000} + }, + + "gateway_conf": { + "gateway_ID": "0000000000000000", + /* change with default server address/ports */ + "server_address": "router.cn.thethings.network", + "serv_port_up": 1700, + "serv_port_down": 1700, + /* 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/ttyAMA0", + /* GPS reference coordinates */ + "ref_latitude": 0.0, + "ref_longitude": 0.0, + "ref_altitude": 0, + "autoquit_threshold": 20, + /* Beaconing parameters */ + "beacon_period": 0, /* disable class B beacon */ + "beacon_freq_hz": 434665000, + "beacon_freq_nb": 1, + "beacon_freq_step": 0, + "beacon_datarate": 9, + "beacon_bw_hz": 125000, + "beacon_power": 27 + }, + + "debug_conf": { + "ref_payload":[ + {"id": "0xCAFE1234"}, + {"id": "0xCAFE2345"} + ], + "log_file": "loragw_hal.log" + } +} diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.eu_863_870.json b/lora/rak2287_spi/global_conf_uart/global_conf.eu_863_870.json index aab53ec..9114513 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.eu_863_870.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.eu_863_870.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 1, "if": -400000}, "chan_multiSF_1": {"enable": true, "radio": 1, "if": -200000}, "chan_multiSF_2": {"enable": true, "radio": 1, "if": 0}, @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 869525000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.in_865_867.json b/lora/rak2287_spi/global_conf_uart/global_conf.in_865_867.json index 304d1ad..38c59f0 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.in_865_867.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.in_865_867.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, + "radio_0": { "enable": true, "type": "SX1250", @@ -46,6 +47,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -137500}, /* Freq : 865.0625 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": 202500}, /* Freq : 865.4025 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 1, "if": -400000}, /* Freq : 865.9850 MHz*/ @@ -80,7 +82,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 866500000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.kr_920_923.json b/lora/rak2287_spi/global_conf_uart/global_conf.kr_920_923.json index 0c4d329..7264f4c 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.kr_920_923.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.kr_920_923.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, "radio_0": { "enable": true, @@ -46,6 +46,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -300000}, /* Freq : 922.1 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -100000}, /* Freq : 922.3 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 100000}, /* Freq : 922.5 MHz*/ @@ -80,7 +81,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923100000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.ru_864_870.json b/lora/rak2287_spi/global_conf_uart/global_conf.ru_864_870.json index 51f7426..2bbdd5e 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.ru_864_870.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.ru_864_870.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, + "radio_0": { "enable": true, "type": "SX1250", @@ -46,6 +47,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 864.1 MHz */ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 864.3 MHz */ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 864.5 MHz */ @@ -80,7 +82,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 869100000, "beacon_freq_nb": 1, "beacon_freq_step": 0, diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.us_902_928.json b/lora/rak2287_spi/global_conf_uart/global_conf.us_902_928.json index 9ec9bde..ca8eea5 100755 --- a/lora/rak2287_spi/global_conf_uart/global_conf.us_902_928.json +++ b/lora/rak2287_spi/global_conf_uart/global_conf.us_902_928.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "SPI", + "com_path": "/dev/spidev0.0", "lorawan_public": true, "clksrc": 0, "antenna_gain": 0, /* antenna gain, in dBi */ "full_duplex": false, - "precision_timestamp": { + "fine_timestamp": { "enable": false, - "max_ts_metrics": 255, - "nb_symbols": 1 + "mode": "all_sf" /* high_capacity or all_sf */ }, + "radio_0": { "enable": true, "type": "SX1250", @@ -46,6 +47,7 @@ "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0}, "tx_enable": false }, + "chan_multiSF_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]}, "chan_multiSF_0": {"enable": true, "radio": 0, "if": -400000}, /* Freq : 903.9 MHz*/ "chan_multiSF_1": {"enable": true, "radio": 0, "if": -200000}, /* Freq : 904.1 MHz*/ "chan_multiSF_2": {"enable": true, "radio": 0, "if": 0}, /* Freq : 904.3 MHz*/ @@ -80,7 +82,7 @@ "ref_longitude": 0.0, "ref_altitude": 0, /* Beaconing parameters */ - "beacon_period": 0, /* disable class B beacon */ + "beacon_period": 0, /* disable class B beacon, set to 128 enable beacon */ "beacon_freq_hz": 923300000, "beacon_freq_nb": 8, "beacon_freq_step": 600000, diff --git a/lora/rak2287_spi/install.sh b/lora/rak2287_spi/install.sh index d63eb89..a07a17a 100755 --- a/lora/rak2287_spi/install.sh +++ b/lora/rak2287_spi/install.sh @@ -22,21 +22,21 @@ pushd $INSTALL_DIR # Build LoRa gateway app -wget https://github.com/Lora-net/sx1302_hal/archive/V1.0.5.tar.gz -O ./rak2287.tar.gz +wget https://github.com/Lora-net/sx1302_hal/archive/V2.0.1.tar.gz -O ./rak2287.tar.gz tar -zxvf ./rak2287.tar.gz -#mv sx1302_hal-1.0.5 lora_gateway -pushd sx1302_hal-1.0.5 + +sleep 1 +mv sx1302_hal-2.0.1 sx1302_hal +pushd sx1302_hal make clean -rm libloragw/inc/loragw_stts751.h -f -rm libloragw/src/loragw_stts751.c -f -cp ../loragw_hal.c libloragw/src/loragw_hal.c -f +cp ../loragw_stts751.c libloragw/src/loragw_stts751.c -f cp ../test_loragw_gps_uart.c libloragw/tst/test_loragw_gps.c -f cp ../test_loragw_gps_i2c.c libloragw/tst/test_loragw_gps_i2c.c -f #mkdir -p packet_forwarder/lora_pkt_fwd/ #cp ../reset_lgw.sh packet_forwarder/lora_pkt_fwd/reset_lgw.sh -f -cp ../Makefile libloragw/Makefile -f + cp ../lora_pkt_fwd.c packet_forwarder/src/lora_pkt_fwd.c make rm packet_forwarder/lora_pkt_fwd/obj/* -f @@ -45,8 +45,8 @@ popd if [ -d $INSTALL_DIR/packet_forwarder ]; then rm -rf $INSTALL_DIR/packet_forwarder/ fi -cp $INSTALL_DIR/sx1302_hal-1.0.5/packet_forwarder $INSTALL_DIR/ -rf -cp $INSTALL_DIR/sx1302_hal-1.0.5/libloragw $INSTALL_DIR/lora_gateway -rf +cp $INSTALL_DIR/sx1302_hal/packet_forwarder $INSTALL_DIR/ -rf +cp $INSTALL_DIR/sx1302_hal/libloragw $INSTALL_DIR/lora_gateway -rf if [ -f $SCRIPT_DIR/../../lte/lte_test ]; then cp $SCRIPT_DIR/../../lte/lte_test $INSTALL_DIR/lora_gateway/ cp $SCRIPT_DIR/reset_lgw.sh $INSTALL_DIR/lora_gateway/ diff --git a/lora/rak2287_spi/lora_pkt_fwd.c b/lora/rak2287_spi/lora_pkt_fwd.c old mode 100644 new mode 100755 index bd2cc13..501f0c0 --- a/lora/rak2287_spi/lora_pkt_fwd.c +++ b/lora/rak2287_spi/lora_pkt_fwd.c @@ -62,6 +62,8 @@ License: Revised BSD License, see LICENSE.TXT file include in the project #define STRINGIFY(x) #x #define STR(x) STRINGIFY(x) +#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min) + /* -------------------------------------------------------------------------- */ /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ @@ -83,10 +85,10 @@ License: Revised BSD License, see LICENSE.TXT file include in the project #define FETCH_SLEEP_MS 10 /* nb of ms waited when a fetch return no packets */ #define BEACON_POLL_MS 50 /* time in ms between polling of beacon TX status */ -#define PROTOCOL_VERSION 2 /* v1.3 */ +#define PROTOCOL_VERSION 2 /* v1.6 */ #define PROTOCOL_JSON_RXPK_FRAME_FORMAT 1 -#define XERR_INIT_AVG 128 /* nb of measurements the XTAL correction is averaged on as initial value */ +#define XERR_INIT_AVG 16 /* nb of measurements the XTAL correction is averaged on as initial value */ #define XERR_FILT_COEF 256 /* coefficient for low-pass XTAL error tracking */ #define PKT_PUSH_DATA 0 @@ -118,6 +120,18 @@ License: Revised BSD License, see LICENSE.TXT file include in the project #define DEFAULT_BEACON_POWER 14 #define DEFAULT_BEACON_INFODESC 0 +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE TYPES -------------------------------------------------------- */ + +/* spectral scan */ +typedef struct spectral_scan_s { + bool enable; /* enable spectral scan thread */ + uint32_t freq_hz_start; /* first channel frequency, in Hz */ + uint8_t nb_chan; /* number of channels to scan (200kHz between each channel) */ + uint16_t nb_scan; /* number of scan points for each frequency scan */ + uint32_t pace_s; /* number of seconds between 2 scans in the thread */ +} spectral_scan_t; + /* -------------------------------------------------------------------------- */ /* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ @@ -235,6 +249,7 @@ static int8_t antenna_gain = 0; static struct lgw_tx_gain_lut_s txlut[LGW_RF_CHAIN_NB]; /* TX gain table */ static uint32_t tx_freq_min[LGW_RF_CHAIN_NB]; /* lowest frequency supported by TX chain */ static uint32_t tx_freq_max[LGW_RF_CHAIN_NB]; /* highest frequency supported by TX chain */ +static bool tx_enable[LGW_RF_CHAIN_NB] = {false}; /* Is TX enabled for a given RF chain ? */ static uint32_t nb_pkt_log[LGW_IF_CHAIN_NB][8]; /* [CH][SF] */ static uint32_t nb_pkt_received_lora = 0; @@ -243,6 +258,18 @@ static uint32_t nb_pkt_received_fsk = 0; static struct lgw_conf_debug_s debugconf; static uint32_t nb_pkt_received_ref[16]; +/* Interface type */ +static lgw_com_type_t com_type = LGW_COM_SPI; + +/* Spectral Scan */ +static spectral_scan_t spectral_scan_params = { + .enable = false, + .freq_hz_start = 0, + .nb_chan = 0, + .nb_scan = 0, + .pace_s = 10 +}; + /* -------------------------------------------------------------------------- */ /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ @@ -272,6 +299,7 @@ void thread_down(void); void thread_jit(void); void thread_gps(void); void thread_valid(void); +void thread_spectral_scan(void); /* -------------------------------------------------------------------------- */ /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ @@ -296,7 +324,7 @@ static void sig_handler(int sigio) { } static int parse_SX130x_configuration(const char * conf_file) { - int i, j; + int i, j, number; 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[] = "SX130x_conf"; @@ -305,14 +333,23 @@ static int parse_SX130x_configuration(const char * conf_file) { JSON_Object *conf_obj = NULL; JSON_Object *conf_txgain_obj; JSON_Object *conf_ts_obj; - JSON_Array *conf_txlut_array; + JSON_Object *conf_sx1261_obj = NULL; + JSON_Object *conf_scan_obj = NULL; + JSON_Object *conf_lbt_obj = NULL; + JSON_Object *conf_lbtchan_obj = NULL; + JSON_Array *conf_txlut_array = NULL; + JSON_Array *conf_lbtchan_array = NULL; + JSON_Array *conf_demod_array = NULL; struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; struct lgw_conf_rxif_s ifconf; - struct lgw_conf_timestamp_s tsconf; + struct lgw_conf_demod_s demodconf; + struct lgw_conf_ftime_s tsconf; + struct lgw_conf_sx1261_s sx1261conf; uint32_t sf, bw, fdev; bool sx1250_tx_lut; + size_t size; /* try to parse JSON */ root_val = json_parse_file_with_comments(conf_file); @@ -332,15 +369,27 @@ static int parse_SX130x_configuration(const char * conf_file) { /* set board configuration */ memset(&boardconf, 0, sizeof boardconf); /* initialize configuration structure */ - str = json_object_get_string(conf_obj, "spidev_path"); + str = json_object_get_string(conf_obj, "com_type"); + if (str == NULL) { + MSG("ERROR: com_type must be configured in %s\n", conf_file); + return -1; + } else if (!strncmp(str, "SPI", 3) || !strncmp(str, "spi", 3)) { + boardconf.com_type = LGW_COM_SPI; + } else if (!strncmp(str, "USB", 3) || !strncmp(str, "usb", 3)) { + boardconf.com_type = LGW_COM_USB; + } else { + MSG("ERROR: invalid com type: %s (should be SPI or USB)\n", str); + return -1; + } + com_type = boardconf.com_type; + str = json_object_get_string(conf_obj, "com_path"); if (str != NULL) { - strncpy(boardconf.spidev_path, str, sizeof(boardconf.spidev_path) - 1); - boardconf.spidev_path[sizeof boardconf.spidev_path - 1] = '\0'; /* ensure string termination */ + strncpy(boardconf.com_path, str, sizeof boardconf.com_path); + boardconf.com_path[sizeof boardconf.com_path - 1] = '\0'; /* ensure string termination */ } else { - MSG("ERROR: spidev path must be configured in %s\n", conf_file); + MSG("ERROR: com_path must be configured in %s\n", conf_file); return -1; } - 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); @@ -362,7 +411,7 @@ static int parse_SX130x_configuration(const char * conf_file) { MSG("WARNING: Data type for full_duplex seems wrong, please check\n"); boardconf.full_duplex = false; } - MSG("INFO: spidev_path %s, lorawan_public %d, clksrc %d, full_duplex %d\n", boardconf.spidev_path, boardconf.lorawan_public, boardconf.clksrc, boardconf.full_duplex); + MSG("INFO: com_type %s, com_path %s, lorawan_public %d, clksrc %d, full_duplex %d\n", (boardconf.com_type == LGW_COM_SPI) ? "SPI" : "USB", boardconf.com_path, boardconf.lorawan_public, boardconf.clksrc, boardconf.full_duplex); /* all parameters parsed, submitting configuration to the HAL */ if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) { MSG("ERROR: Failed to configure board\n"); @@ -382,37 +431,35 @@ static int parse_SX130x_configuration(const char * conf_file) { MSG("INFO: antenna_gain %d dBi\n", antenna_gain); /* set timestamp configuration */ - conf_ts_obj = json_object_get_object(conf_obj, "precision_timestamp"); + conf_ts_obj = json_object_get_object(conf_obj, "fine_timestamp"); if (conf_ts_obj == NULL) { - MSG("INFO: %s does not contain a JSON object for precision timestamp\n", conf_file); + MSG("INFO: %s does not contain a JSON object for fine timestamp\n", conf_file); } else { val = json_object_get_value(conf_ts_obj, "enable"); /* fetch value (if possible) */ if (json_value_get_type(val) == JSONBoolean) { - tsconf.enable_precision_ts = (bool)json_value_get_boolean(val); + tsconf.enable = (bool)json_value_get_boolean(val); } else { - MSG("WARNING: Data type for precision_timestamp.enable seems wrong, please check\n"); - tsconf.enable_precision_ts = false; + MSG("WARNING: Data type for fine_timestamp.enable seems wrong, please check\n"); + tsconf.enable = false; } - if (tsconf.enable_precision_ts == true) { - val = json_object_get_value(conf_ts_obj, "max_ts_metrics"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - tsconf.max_ts_metrics = (uint8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for precision_timestamp.max_ts_metrics seems wrong, please check\n"); - tsconf.max_ts_metrics = 0xFF; - } - val = json_object_get_value(conf_ts_obj, "nb_symbols"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - tsconf.nb_symbols = (uint8_t)json_value_get_number(val); + if (tsconf.enable == true) { + str = json_object_get_string(conf_ts_obj, "mode"); + if (str == NULL) { + MSG("ERROR: fine_timestamp.mode must be configured in %s\n", conf_file); + return -1; + } else if (!strncmp(str, "high_capacity", 13) || !strncmp(str, "HIGH_CAPACITY", 13)) { + tsconf.mode = LGW_FTIME_MODE_HIGH_CAPACITY; + } else if (!strncmp(str, "all_sf", 6) || !strncmp(str, "ALL_SF", 6)) { + tsconf.mode = LGW_FTIME_MODE_ALL_SF; } else { - MSG("WARNING: Data type for precision_timestamp.nb_symbols seems wrong, please check\n"); - tsconf.nb_symbols = 1; + MSG("ERROR: invalid fine timestamp mode: %s (should be high_capacity or all_sf)\n", str); + return -1; } - MSG("INFO: Configuring precision timestamp: max_ts_metrics:%u, nb_symbols:%u\n", tsconf.max_ts_metrics, tsconf.nb_symbols); + MSG("INFO: Configuring precision timestamp with %s mode\n", str); /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_timestamp_setconf(&tsconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure precision timestamp\n"); + if (lgw_ftime_setconf(&tsconf) != LGW_HAL_SUCCESS) { + MSG("ERROR: Failed to configure fine timestamp\n"); return -1; } } else { @@ -420,6 +467,190 @@ static int parse_SX130x_configuration(const char * conf_file) { } } + /* set SX1261 configuration */ + memset(&sx1261conf, 0, sizeof sx1261conf); /* initialize configuration structure */ + conf_sx1261_obj = json_object_get_object(conf_obj, "sx1261_conf"); /* fetch value (if possible) */ + if (conf_sx1261_obj == NULL) { + MSG("INFO: no configuration for SX1261\n"); + } else { + /* Global SX1261 configuration */ + str = json_object_get_string(conf_sx1261_obj, "spi_path"); + if (str != NULL) { + strncpy(sx1261conf.spi_path, str, sizeof sx1261conf.spi_path); + sx1261conf.spi_path[sizeof sx1261conf.spi_path - 1] = '\0'; /* ensure string termination */ + } else { + MSG("INFO: SX1261 spi_path is not configured in %s\n", conf_file); + } + val = json_object_get_value(conf_sx1261_obj, "rssi_offset"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONNumber) { + sx1261conf.rssi_offset = (int8_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for sx1261_conf.rssi_offset seems wrong, please check\n"); + sx1261conf.rssi_offset = 0; + } + + /* Spectral Scan configuration */ + conf_scan_obj = json_object_get_object(conf_sx1261_obj, "spectral_scan"); /* fetch value (if possible) */ + if (conf_scan_obj == NULL) { + MSG("INFO: no configuration for Spectral Scan\n"); + } else { + val = json_object_get_value(conf_scan_obj, "enable"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONBoolean) { + /* Enable background spectral scan thread in packet forwarder */ + spectral_scan_params.enable = (bool)json_value_get_boolean(val); + } else { + MSG("WARNING: Data type for spectral_scan.enable seems wrong, please check\n"); + } + if (spectral_scan_params.enable == true) { + /* Enable the sx1261 radio hardware configuration to allow spectral scan */ + sx1261conf.enable = true; + MSG("INFO: Spectral Scan with SX1261 is enabled\n"); + + /* Get Spectral Scan Parameters */ + val = json_object_get_value(conf_scan_obj, "freq_start"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONNumber) { + spectral_scan_params.freq_hz_start = (uint32_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for spectral_scan.freq_start seems wrong, please check\n"); + } + val = json_object_get_value(conf_scan_obj, "nb_chan"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONNumber) { + spectral_scan_params.nb_chan = (uint8_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for spectral_scan.nb_chan seems wrong, please check\n"); + } + val = json_object_get_value(conf_scan_obj, "nb_scan"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONNumber) { + spectral_scan_params.nb_scan = (uint16_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for spectral_scan.nb_scan seems wrong, please check\n"); + } + val = json_object_get_value(conf_scan_obj, "pace_s"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONNumber) { + spectral_scan_params.pace_s = (uint32_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for spectral_scan.pace_s seems wrong, please check\n"); + } + } + } + + /* LBT configuration */ + conf_lbt_obj = json_object_get_object(conf_sx1261_obj, "lbt"); /* fetch value (if possible) */ + if (conf_lbt_obj == NULL) { + MSG("INFO: no configuration for LBT\n"); + } else { + val = json_object_get_value(conf_lbt_obj, "enable"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONBoolean) { + sx1261conf.lbt_conf.enable = (bool)json_value_get_boolean(val); + } else { + MSG("WARNING: Data type for lbt.enable seems wrong, please check\n"); + } + if (sx1261conf.lbt_conf.enable == true) { + /* Enable the sx1261 radio hardware configuration to allow spectral scan */ + sx1261conf.enable = true; + MSG("INFO: Listen-Before-Talk with SX1261 is enabled\n"); + + val = json_object_get_value(conf_lbt_obj, "rssi_target"); /* fetch value (if possible) */ + if (json_value_get_type(val) == JSONNumber) { + sx1261conf.lbt_conf.rssi_target = (int8_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for lbt.rssi_target seems wrong, please check\n"); + sx1261conf.lbt_conf.rssi_target = 0; + } + /* set LBT channels configuration */ + conf_lbtchan_array = json_object_get_array(conf_lbt_obj, "channels"); + if (conf_lbtchan_array != NULL) { + sx1261conf.lbt_conf.nb_channel = json_array_get_count(conf_lbtchan_array); + MSG("INFO: %u LBT channels configured\n", sx1261conf.lbt_conf.nb_channel); + } + for (i = 0; i < (int)sx1261conf.lbt_conf.nb_channel; i++) { + /* Sanity check */ + if (i >= LGW_LBT_CHANNEL_NB_MAX) { + MSG("ERROR: LBT channel %d not supported, skip it\n", i); + break; + } + /* Get LBT channel configuration object from array */ + conf_lbtchan_obj = json_array_get_object(conf_lbtchan_array, i); + + /* Channel frequency */ + val = json_object_dotget_value(conf_lbtchan_obj, "freq_hz"); /* fetch value (if possible) */ + if (val != NULL) { + if (json_value_get_type(val) == JSONNumber) { + sx1261conf.lbt_conf.channels[i].freq_hz = (uint32_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for lbt.channels[%d].freq_hz seems wrong, please check\n", i); + sx1261conf.lbt_conf.channels[i].freq_hz = 0; + } + } else { + MSG("ERROR: no frequency defined for LBT channel %d\n", i); + return -1; + } + + /* Channel bandiwdth */ + val = json_object_dotget_value(conf_lbtchan_obj, "bandwidth"); /* fetch value (if possible) */ + if (val != NULL) { + if (json_value_get_type(val) == JSONNumber) { + bw = (uint32_t)json_value_get_number(val); + switch(bw) { + case 500000: sx1261conf.lbt_conf.channels[i].bandwidth = BW_500KHZ; break; + case 250000: sx1261conf.lbt_conf.channels[i].bandwidth = BW_250KHZ; break; + case 125000: sx1261conf.lbt_conf.channels[i].bandwidth = BW_125KHZ; break; + default: sx1261conf.lbt_conf.channels[i].bandwidth = BW_UNDEFINED; + } + } else { + MSG("WARNING: Data type for lbt.channels[%d].freq_hz seems wrong, please check\n", i); + sx1261conf.lbt_conf.channels[i].bandwidth = BW_UNDEFINED; + } + } else { + MSG("ERROR: no bandiwdth defined for LBT channel %d\n", i); + return -1; + } + + /* Channel scan time */ + val = json_object_dotget_value(conf_lbtchan_obj, "scan_time_us"); /* fetch value (if possible) */ + if (val != NULL) { + if (json_value_get_type(val) == JSONNumber) { + if ((uint16_t)json_value_get_number(val) == 128) { + sx1261conf.lbt_conf.channels[i].scan_time_us = LGW_LBT_SCAN_TIME_128_US; + } else if ((uint16_t)json_value_get_number(val) == 5000) { + sx1261conf.lbt_conf.channels[i].scan_time_us = LGW_LBT_SCAN_TIME_5000_US; + } else { + MSG("ERROR: scan time not supported for LBT channel %d, must be 128 or 5000\n", i); + return -1; + } + } else { + MSG("WARNING: Data type for lbt.channels[%d].scan_time_us seems wrong, please check\n", i); + sx1261conf.lbt_conf.channels[i].scan_time_us = 0; + } + } else { + MSG("ERROR: no scan_time_us defined for LBT channel %d\n", i); + return -1; + } + + /* Channel transmit time */ + val = json_object_dotget_value(conf_lbtchan_obj, "transmit_time_ms"); /* fetch value (if possible) */ + if (val != NULL) { + if (json_value_get_type(val) == JSONNumber) { + sx1261conf.lbt_conf.channels[i].transmit_time_ms = (uint16_t)json_value_get_number(val); + } else { + MSG("WARNING: Data type for lbt.channels[%d].transmit_time_ms seems wrong, please check\n", i); + sx1261conf.lbt_conf.channels[i].transmit_time_ms = 0; + } + } else { + MSG("ERROR: no transmit_time_ms defined for LBT channel %d\n", i); + return -1; + } + } + } + } + + /* all parameters parsed, submitting configuration to the HAL */ + if (lgw_sx1261_setconf(&sx1261conf) != LGW_HAL_SUCCESS) { + MSG("ERROR: Failed to configure the SX1261 radio\n"); + return -1; + } + } + /* set configuration for RF chains */ for (i = 0; i < LGW_RF_CHAIN_NB; ++i) { memset(&rfconf, 0, sizeof rfconf); /* initialize configuration structure */ @@ -477,6 +708,7 @@ static int parse_SX130x_configuration(const char * conf_file) { 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); + tx_enable[i] = rfconf.tx_enable; /* update global context for later check */ if (rfconf.tx_enable == true) { /* tx is enabled on this rf chain, we need its frequency range */ snprintf(param_name, sizeof param_name, "radio_%i.tx_freq_min", i); @@ -592,6 +824,36 @@ static int parse_SX130x_configuration(const char * conf_file) { } } + /* set configuration for demodulators */ + memset(&demodconf, 0, sizeof demodconf); /* initialize configuration structure */ + val = json_object_get_value(conf_obj, "chan_multiSF_All"); /* fetch value (if possible) */ + if (json_value_get_type(val) != JSONObject) { + MSG("INFO: no configuration for LoRa multi-SF spreading factors enabling\n"); + } else { + conf_demod_array = json_object_dotget_array(conf_obj, "chan_multiSF_All.spreading_factor_enable"); + if ((conf_demod_array != NULL) && ((size = json_array_get_count(conf_demod_array)) <= LGW_MULTI_NB)) { + for (i = 0; i < (int)size; i++) { + number = json_array_get_number(conf_demod_array, i); + if (number < 5 || number > 12) { + MSG("WARNING: failed to parse chan_multiSF_All.spreading_factor_enable (wrong value at idx %d)\n", i); + demodconf.multisf_datarate = 0xFF; /* enable all SFs */ + break; + } else { + /* set corresponding bit in the bitmask SF5 is LSB -> SF12 is MSB */ + demodconf.multisf_datarate |= (1 << (number - 5)); + } + } + } else { + MSG("WARNING: failed to parse chan_multiSF_All.spreading_factor_enable\n"); + demodconf.multisf_datarate = 0xFF; /* enable all SFs */ + } + /* all parameters parsed, submitting configuration to the HAL */ + if (lgw_demod_setconf(&demodconf) != LGW_HAL_SUCCESS) { + MSG("ERROR: invalid configuration for demodulation parameters\n"); + return -1; + } + } + /* set configuration for Lora multi-SF channels (bandwidth cannot be set) */ for (i = 0; i < LGW_MULTI_NB; ++i) { memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */ @@ -784,7 +1046,7 @@ static int parse_gateway_configuration(const char * conf_file) { /* 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) - 1); + strncpy(serv_addr, str, sizeof serv_addr); serv_addr[sizeof serv_addr - 1] = '\0'; /* ensure string termination */ MSG("INFO: server hostname or IP address is configured to \"%s\"\n", serv_addr); } @@ -842,7 +1104,7 @@ static int parse_gateway_configuration(const char * conf_file) { /* 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) - 1); + strncpy(gps_tty_path, str, sizeof gps_tty_path); gps_tty_path[sizeof gps_tty_path - 1] = '\0'; /* ensure string termination */ MSG("INFO: GPS serial port path is configured to \"%s\"\n", gps_tty_path); } @@ -1000,7 +1262,7 @@ static int parse_debug_configuration(const char * conf_file) { /* Get log file configuration */ str = json_object_get_string(conf_obj, "log_file"); if (str != NULL) { - strncpy(debugconf.log_file_name, str, sizeof(debugconf.log_file_name) - 1); + strncpy(debugconf.log_file_name, str, sizeof debugconf.log_file_name); debugconf.log_file_name[sizeof debugconf.log_file_name - 1] = '\0'; /* ensure string termination */ MSG("INFO: setting debug log file name to %s\n", debugconf.log_file_name); } @@ -1179,6 +1441,7 @@ int main(int argc, char ** argv) pthread_t thrid_gps; pthread_t thrid_valid; pthread_t thrid_jit; + pthread_t thrid_ss; /* network socket creation */ struct addrinfo hints; @@ -1221,7 +1484,7 @@ int main(int argc, char ** argv) uint32_t trig_tstamp; uint32_t inst_tstamp; uint64_t eui; -// float temperature; + float temperature; /* statistics variable */ time_t t; @@ -1361,7 +1624,7 @@ int main(int argc, char ** argv) /* look for server address w/ downstream port */ i = getaddrinfo(serv_addr, serv_port_down, &hints, &result); if (i != 0) { - MSG("ERROR: [down] getaddrinfo on address %s (port %s) returned %s\n", serv_addr, serv_port_up, gai_strerror(i)); + MSG("ERROR: [down] getaddrinfo on address %s (port %s) returned %s\n", serv_addr, serv_port_down, gai_strerror(i)); exit(EXIT_FAILURE); } @@ -1372,7 +1635,7 @@ int main(int argc, char ** argv) else break; /* success, get out of loop */ } if (q == NULL) { - MSG("ERROR: [down] failed to open socket to any of server %s addresses (port %s)\n", serv_addr, serv_port_up); + MSG("ERROR: [down] failed to open socket to any of server %s addresses (port %s)\n", serv_addr, serv_port_down); i = 1; for (q=result; q!=NULL; q=q->ai_next) { getnameinfo(q->ai_addr, q->ai_addrlen, host_name, sizeof host_name, port_name, sizeof port_name, NI_NUMERICHOST); @@ -1390,10 +1653,12 @@ int main(int argc, char ** argv) } freeaddrinfo(result); - /* Board reset */ - if (system("./reset_lgw.sh start") != 0) { - printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); - exit(EXIT_FAILURE); + if (com_type == LGW_COM_SPI) { + /* Board reset */ + if (system("./reset_lgw.sh start") != 0) { + printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); + exit(EXIT_FAILURE); + } } for (l = 0; l < LGW_IF_CHAIN_NB; l++) { @@ -1420,30 +1685,39 @@ int main(int argc, char ** argv) } /* spawn threads to manage upstream and downstream */ - i = pthread_create( &thrid_up, NULL, (void * (*)(void *))thread_up, NULL); + i = pthread_create(&thrid_up, NULL, (void * (*)(void *))thread_up, NULL); if (i != 0) { MSG("ERROR: [main] impossible to create upstream thread\n"); exit(EXIT_FAILURE); } - i = pthread_create( &thrid_down, NULL, (void * (*)(void *))thread_down, NULL); + i = pthread_create(&thrid_down, NULL, (void * (*)(void *))thread_down, NULL); if (i != 0) { MSG("ERROR: [main] impossible to create downstream thread\n"); exit(EXIT_FAILURE); } - i = pthread_create( &thrid_jit, NULL, (void * (*)(void *))thread_jit, NULL); + i = pthread_create(&thrid_jit, NULL, (void * (*)(void *))thread_jit, NULL); if (i != 0) { MSG("ERROR: [main] impossible to create JIT thread\n"); exit(EXIT_FAILURE); } + /* spawn thread for background spectral scan */ + if (spectral_scan_params.enable == true) { + i = pthread_create(&thrid_ss, NULL, (void * (*)(void *))thread_spectral_scan, NULL); + if (i != 0) { + MSG("ERROR: [main] impossible to create Spectral Scan 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); + i = pthread_create(&thrid_gps, NULL, (void * (*)(void *))thread_gps, NULL); if (i != 0) { MSG("ERROR: [main] impossible to create GPS thread\n"); exit(EXIT_FAILURE); } - i = pthread_create( &thrid_valid, NULL, (void * (*)(void *))thread_valid, NULL); + i = pthread_create(&thrid_valid, NULL, (void * (*)(void *))thread_valid, NULL); if (i != 0) { MSG("ERROR: [main] impossible to create validation thread\n"); exit(EXIT_FAILURE); @@ -1611,34 +1885,49 @@ int main(int argc, char ** argv) } else { printf("# GPS sync is disabled\n"); } - /* + pthread_mutex_lock(&mx_concent); i = lgw_get_temperature(&temperature); + pthread_mutex_unlock(&mx_concent); if (i != LGW_HAL_SUCCESS) { - printf("### Concentrator temperature unknown ###\n"); +// printf("### Concentrator temperature unknown ###\n"); } else { - printf("### Concentrator temperature: %.0f C ###\n", temperature); +// printf("### Concentrator temperature: %.0f C ###\n", temperature); } - */ 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)) || (gps_fake_enable == true)) { - snprintf(status_report, STATUS_SIZE, "\"stat\":{\"time\":\"%s\",\"lati\":%.5f,\"long\":%.5f,\"alti\":%i,\"rxnb\":%u,\"rxok\":%u,\"rxfw\":%u,\"ackr\":%.1f,\"dwnb\":%u,\"txnb\":%u}", stat_timestamp, cp_gps_coord.lat, cp_gps_coord.lon, cp_gps_coord.alt, cp_nb_rx_rcv, cp_nb_rx_ok, cp_up_pkt_fwd, 100.0 * up_ack_ratio, cp_dw_dgram_rcv, cp_nb_tx_ok); + snprintf(status_report, STATUS_SIZE, "\"stat\":{\"time\":\"%s\",\"lati\":%.5f,\"long\":%.5f,\"alti\":%i,\"rxnb\":%u,\"rxok\":%u,\"rxfw\":%u,\"ackr\":%.1f,\"dwnb\":%u,\"txnb\":%u,\"temp\":%.1f}", stat_timestamp, cp_gps_coord.lat, cp_gps_coord.lon, cp_gps_coord.alt, cp_nb_rx_rcv, cp_nb_rx_ok, cp_up_pkt_fwd, 100.0 * up_ack_ratio, cp_dw_dgram_rcv, cp_nb_tx_ok, temperature); } else { - snprintf(status_report, STATUS_SIZE, "\"stat\":{\"time\":\"%s\",\"rxnb\":%u,\"rxok\":%u,\"rxfw\":%u,\"ackr\":%.1f,\"dwnb\":%u,\"txnb\":%u}", stat_timestamp, cp_nb_rx_rcv, cp_nb_rx_ok, cp_up_pkt_fwd, 100.0 * up_ack_ratio, cp_dw_dgram_rcv, cp_nb_tx_ok); + snprintf(status_report, STATUS_SIZE, "\"stat\":{\"time\":\"%s\",\"rxnb\":%u,\"rxok\":%u,\"rxfw\":%u,\"ackr\":%.1f,\"dwnb\":%u,\"txnb\":%u,\"temp\":%.1f}", stat_timestamp, cp_nb_rx_rcv, cp_nb_rx_ok, cp_up_pkt_fwd, 100.0 * up_ack_ratio, cp_dw_dgram_rcv, cp_nb_tx_ok, temperature); } 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_jit); /* don't wait for jit thread */ + /* wait for all threads with a COM with the concentrator board to finish (1 fetch cycle max) */ + i = pthread_join(thrid_up, NULL); + if (i != 0) { + printf("ERROR: failed to join upstream thread with %d - %s\n", i, strerror(errno)); + } + i = pthread_join(thrid_down, NULL); + if (i != 0) { + printf("ERROR: failed to join downstream thread with %d - %s\n", i, strerror(errno)); + } + i = pthread_join(thrid_jit, NULL); + if (i != 0) { + printf("ERROR: failed to join JIT thread with %d - %s\n", i, strerror(errno)); + } + if (spectral_scan_params.enable == true) { + i = pthread_join(thrid_ss, NULL); + if (i != 0) { + printf("ERROR: failed to join Spectral Scan thread with %d - %s\n", i, strerror(errno)); + } + } if (gps_enabled == true) { - pthread_cancel(thrid_gps); /* don't wait for GPS thread */ - pthread_cancel(thrid_valid); /* don't wait for validation thread */ + pthread_cancel(thrid_gps); /* don't wait for GPS thread, no access to concentrator board */ + pthread_cancel(thrid_valid); /* don't wait for validation thread, no access to concentrator board */ i = lgw_gps_disable(gps_tty_fd); if (i == LGW_HAL_SUCCESS) { @@ -1662,10 +1951,12 @@ int main(int argc, char ** argv) } } - /* Board reset */ - if (system("./reset_lgw.sh stop") != 0) { - printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); - exit(EXIT_FAILURE); + if (com_type == LGW_COM_SPI) { + /* Board reset */ + if (system("./reset_lgw.sh stop") != 0) { + printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); + exit(EXIT_FAILURE); + } } MSG("INFO: Exiting packet forwarder program\n"); @@ -1889,6 +2180,17 @@ void thread_up(void) { } } + /* Fine timestamp */ + if (p->ftime_received == true) { + j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"ftime\":%u", p->ftime); + if (j > 0) { + buff_index += j; + } else { + MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); + exit(EXIT_FAILURE); + } + } + /* 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,\"mid\":%2u", p->if_chain, p->rf_chain, ((double)p->freq_hz / 1e6), p->modem_id); if (j > 0) { @@ -2442,7 +2744,7 @@ void thread_down(void) { /* 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) { + while (((int)difftimespec(recv_time, send_time) < keepalive_time) && !exit_sig && !quit_sig) { /* try to receive a datagram */ msg_len = recv(sock_down, (void *)buff_down, (sizeof buff_down)-1, 0); @@ -2682,6 +2984,12 @@ void thread_down(void) { txpkt.no_crc = (bool)json_value_get_boolean(val); } + /* Parse "No header" flag (optional field) */ + val = json_object_get_value(txpk_obj,"nhdr"); + if (val != NULL) { + txpkt.no_header = (bool)json_value_get_boolean(val); + } + /* parse target frequency (mandatory) */ val = json_object_get_value(txpk_obj,"freq"); if (val == NULL) { @@ -2699,6 +3007,11 @@ void thread_down(void) { continue; } txpkt.rf_chain = (uint8_t)json_value_get_number(val); + if (tx_enable[txpkt.rf_chain] == false) { + MSG("WARNING: [down] TX is not enabled on RF chain %u, TX aborted\n", txpkt.rf_chain); + json_value_free(root_val); + continue; + } /* parse TX power (optional field) */ val = json_object_get_value(txpk_obj,"powe"); @@ -3000,9 +3313,15 @@ void thread_jit(void) { /* send packet to concentrator */ pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish */ + if (spectral_scan_params.enable == true) { + result = lgw_spectral_scan_abort(); + if (result != LGW_HAL_SUCCESS) { + MSG("WARNING: [jit%d] lgw_spectral_scan_abort failed\n", i); + } + } result = lgw_send(&pkt); pthread_mutex_unlock(&mx_concent); /* free concentrator ASAP */ - if (result == LGW_HAL_ERROR) { + if (result != LGW_HAL_SUCCESS) { pthread_mutex_lock(&mx_meas_dw); meas_nb_tx_fail += 1; pthread_mutex_unlock(&mx_meas_dw); @@ -3025,6 +3344,8 @@ void thread_jit(void) { } } } + + MSG("\nINFO: End of JIT thread\n"); } static void modify_os_time(const uint32_t ppm_tstamp) @@ -3300,9 +3621,126 @@ void thread_valid(void) { // fprintf(log_file,"%.18lf,\"track\"\n", xtal_correct); // DEBUG } } - // printf("Time ref: %s, XTAL correct: %s (%.15lf)\n", ref_valid_local?"valid":"invalid", xtal_correct_ok?"valid":"invalid", xtal_correct); // DEBUG + + //printf("Time ref: %s, XTAL correct: %s (%.15lf)\n", ref_valid_local?"valid":"invalid", xtal_correct_ok?"valid":"invalid", xtal_correct); // DEBUG } MSG("\nINFO: End of validation thread\n"); } +/* -------------------------------------------------------------------------- */ +/* --- THREAD 6: BACKGROUND SPECTRAL SCAN --------- */ + +void thread_spectral_scan(void) { + int i, x; + uint32_t freq_hz = spectral_scan_params.freq_hz_start; + uint32_t freq_hz_stop = spectral_scan_params.freq_hz_start + spectral_scan_params.nb_chan * 200E3; + int16_t levels[LGW_SPECTRAL_SCAN_RESULT_SIZE]; + uint16_t results[LGW_SPECTRAL_SCAN_RESULT_SIZE]; + struct timeval tm_start; + lgw_spectral_scan_status_t status; + uint8_t tx_status = TX_FREE; + bool spectral_scan_started; + bool exit_thread = false; + + /* main loop task */ + while (!exit_sig && !quit_sig) { + /* Pace the scan thread (1 sec min), and avoid waiting several seconds when exit */ + for (i = 0; i < (int)(spectral_scan_params.pace_s ? spectral_scan_params.pace_s : 1); i++) { + if (exit_sig || quit_sig) { + exit_thread = true; + break; + } + wait_ms(1000); + } + if (exit_thread == true) { + break; + } + + spectral_scan_started = false; + + /* Start spectral scan (if no downlink programmed) */ + pthread_mutex_lock(&mx_concent); + /* -- Check if there is a downlink programmed */ + for (i = 0; i < LGW_RF_CHAIN_NB; i++) { + if (tx_enable[i] == true) { + x = lgw_status((uint8_t)i, TX_STATUS, &tx_status); + if (x != LGW_HAL_SUCCESS) { + printf("ERROR: failed to get TX status on chain %d\n", i); + } else { + if (tx_status == TX_SCHEDULED || tx_status == TX_EMITTING) { + printf("INFO: skip spectral scan (downlink programmed on RF chain %d)\n", i); + break; /* exit for loop */ + } + } + } + } + if (tx_status != TX_SCHEDULED && tx_status != TX_EMITTING) { + x = lgw_spectral_scan_start(freq_hz, spectral_scan_params.nb_scan); + if (x != 0) { + printf("ERROR: spectral scan start failed\n"); + pthread_mutex_unlock(&mx_concent); + continue; /* main while loop */ + } + spectral_scan_started = true; + } + pthread_mutex_unlock(&mx_concent); + + if (spectral_scan_started == true) { + /* Wait for scan to be completed */ + status = LGW_SPECTRAL_SCAN_STATUS_UNKNOWN; + timeout_start(&tm_start); + do { + /* handle timeout */ + if (timeout_check(tm_start, 2000) != 0) { + printf("ERROR: %s: TIMEOUT on Spectral Scan\n", __FUNCTION__); + break; /* do while */ + } + + /* get spectral scan status */ + pthread_mutex_lock(&mx_concent); + x = lgw_spectral_scan_get_status(&status); + pthread_mutex_unlock(&mx_concent); + if (x != 0) { + printf("ERROR: spectral scan status failed\n"); + break; /* do while */ + } + + /* wait a bit before checking status again */ + wait_ms(10); + } while (status != LGW_SPECTRAL_SCAN_STATUS_COMPLETED && status != LGW_SPECTRAL_SCAN_STATUS_ABORTED); + + if (status == LGW_SPECTRAL_SCAN_STATUS_COMPLETED) { + /* Get spectral scan results */ + memset(levels, 0, sizeof levels); + memset(results, 0, sizeof results); + pthread_mutex_lock(&mx_concent); + x = lgw_spectral_scan_get_results(levels, results); + pthread_mutex_unlock(&mx_concent); + if (x != 0) { + printf("ERROR: spectral scan get results failed\n"); + continue; /* main while loop */ + } + + /* print results */ + printf("SPECTRAL SCAN - %u Hz: ", freq_hz); + for (i = 0; i < LGW_SPECTRAL_SCAN_RESULT_SIZE; i++) { + printf("%u ", results[i]); + } + printf("\n"); + + /* Next frequency to scan */ + freq_hz += 200000; /* 200kHz channels */ + if (freq_hz >= freq_hz_stop) { + freq_hz = spectral_scan_params.freq_hz_start; + } + } else if (status == LGW_SPECTRAL_SCAN_STATUS_ABORTED) { + printf("INFO: %s: spectral scan has been aborted\n", __FUNCTION__); + } else { + printf("ERROR: %s: spectral scan status us unexpected 0x%02X\n", __FUNCTION__, status); + } + } + } + printf("\nINFO: End of Spectral Scan thread\n"); +} + /* --- EOF ------------------------------------------------------------------ */ diff --git a/lora/rak2287_spi/loragw_gps.c b/lora/rak2287_spi/loragw_gps.c index 210b599..f7f6d11 100755 --- a/lora/rak2287_spi/loragw_gps.c +++ b/lora/rak2287_spi/loragw_gps.c @@ -23,7 +23,7 @@ License: Revised BSD License, see LICENSE.TXT file include in the project #include /* bool type */ #include /* printf fprintf */ #include /* memcpy */ -#include +#include /* strerrno */ #include /* struct timespec */ #include /* open */ diff --git a/lora/rak2287_spi/loragw_hal.c b/lora/rak2287_spi/loragw_hal.c deleted file mode 100644 index 3f36fe6..0000000 --- a/lora/rak2287_spi/loragw_hal.c +++ /dev/null @@ -1,1076 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2019 Semtech - -Description: - LoRa concentrator Hardware Abstraction Layer - -License: Revised BSD License, see LICENSE.TXT file include in the project -*/ - - -/* -------------------------------------------------------------------------- */ -/* --- DEPENDANCIES --------------------------------------------------------- */ - -/* fix an issue between POSIX and C99 */ -#if __STDC_VERSION__ >= 199901L - #define _XOPEN_SOURCE 600 -#else - #define _XOPEN_SOURCE 500 -#endif - -#include /* C99 types */ -#include /* bool type */ -#include /* printf fprintf */ -#include /* memcpy */ -#include /* pow, cell */ -#include -#include /* symlink, unlink */ -#include -#include - -#include "loragw_reg.h" -#include "loragw_hal.h" -#include "loragw_aux.h" -#include "loragw_spi.h" -#include "loragw_i2c.h" -#include "loragw_sx1250.h" -#include "loragw_sx125x.h" -#include "loragw_sx1302.h" - -#include "loragw_debug.h" - -/* -------------------------------------------------------------------------- */ -/* --- DEBUG CONSTANTS ------------------------------------------------------ */ - -#define HAL_DEBUG_FILE_LOG 0 - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE MACROS ------------------------------------------------------- */ - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#if DEBUG_HAL == 1 - #define DEBUG_MSG(str) fprintf(stderr, str) - #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) - #define DEBUG_ARRAY(a,b,c) for(a=0;alorawan_public; - CONTEXT_BOARD.clksrc = conf->clksrc; - CONTEXT_BOARD.full_duplex = conf->full_duplex; - strncpy(CONTEXT_SPI, conf->spidev_path, sizeof CONTEXT_SPI); - CONTEXT_SPI[sizeof CONTEXT_SPI - 1] = '\0'; /* ensure string termination */ - - DEBUG_PRINTF("Note: board configuration: spidev_path: %s, lorawan_public:%d, clksrc:%d, full_duplex:%d\n", CONTEXT_SPI, - CONTEXT_LWAN_PUBLIC, - CONTEXT_BOARD.clksrc, - CONTEXT_BOARD.full_duplex); - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s * conf) { - CHECK_NULL(conf); - - /* check if the concentrator is running */ - if (CONTEXT_STARTED == true) { - DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); - return LGW_HAL_ERROR; - } - - if (conf->enable == false) { - /* nothing to do */ - DEBUG_PRINTF("Note: rf_chain %d disabled\n", rf_chain); - return LGW_HAL_SUCCESS; - } - - /* check input range (segfault prevention) */ - if (rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: NOT A VALID RF_CHAIN NUMBER\n"); - return LGW_HAL_ERROR; - } - - /* check if radio type is supported */ - if ((conf->type != LGW_RADIO_TYPE_SX1255) && (conf->type != LGW_RADIO_TYPE_SX1257) && (conf->type != LGW_RADIO_TYPE_SX1250)) { - DEBUG_PRINTF("ERROR: NOT A VALID RADIO TYPE (%d)\n", conf->type); - return LGW_HAL_ERROR; - } - - /* check if the radio central frequency is valid */ - if ((conf->freq_hz < LGW_RF_RX_FREQ_MIN) || (conf->freq_hz > LGW_RF_RX_FREQ_MAX)) { - DEBUG_PRINTF("ERROR: NOT A VALID RADIO CENTER FREQUENCY, PLEASE CHECK IF IT HAS BEEN GIVEN IN HZ (%u)\n", conf->freq_hz); - return LGW_HAL_ERROR; - } - - /* set internal config according to parameters */ - CONTEXT_RF_CHAIN[rf_chain].enable = conf->enable; - CONTEXT_RF_CHAIN[rf_chain].freq_hz = conf->freq_hz; - CONTEXT_RF_CHAIN[rf_chain].rssi_offset = conf->rssi_offset; - CONTEXT_RF_CHAIN[rf_chain].rssi_tcomp.coeff_a = conf->rssi_tcomp.coeff_a; - CONTEXT_RF_CHAIN[rf_chain].rssi_tcomp.coeff_b = conf->rssi_tcomp.coeff_b; - CONTEXT_RF_CHAIN[rf_chain].rssi_tcomp.coeff_c = conf->rssi_tcomp.coeff_c; - CONTEXT_RF_CHAIN[rf_chain].rssi_tcomp.coeff_d = conf->rssi_tcomp.coeff_d; - CONTEXT_RF_CHAIN[rf_chain].rssi_tcomp.coeff_e = conf->rssi_tcomp.coeff_e; - CONTEXT_RF_CHAIN[rf_chain].type = conf->type; - CONTEXT_RF_CHAIN[rf_chain].tx_enable = conf->tx_enable; - CONTEXT_RF_CHAIN[rf_chain].single_input_mode = conf->single_input_mode; - - DEBUG_PRINTF("Note: rf_chain %d configuration; en:%d freq:%d rssi_offset:%f radio_type:%d tx_enable:%d single_input_mode:%d\n", rf_chain, - CONTEXT_RF_CHAIN[rf_chain].enable, - CONTEXT_RF_CHAIN[rf_chain].freq_hz, - CONTEXT_RF_CHAIN[rf_chain].rssi_offset, - CONTEXT_RF_CHAIN[rf_chain].type, - CONTEXT_RF_CHAIN[rf_chain].tx_enable, - CONTEXT_RF_CHAIN[rf_chain].single_input_mode); - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s * conf) { - int32_t bw_hz; - uint32_t rf_rx_bandwidth; - - CHECK_NULL(conf); - - /* check if the concentrator is running */ - if (CONTEXT_STARTED == true) { - DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); - return LGW_HAL_ERROR; - } - - /* check input range (segfault prevention) */ - if (if_chain >= LGW_IF_CHAIN_NB) { - DEBUG_PRINTF("ERROR: %d NOT A VALID IF_CHAIN NUMBER\n", if_chain); - return LGW_HAL_ERROR; - } - - /* if chain is disabled, don't care about most parameters */ - if (conf->enable == false) { - CONTEXT_IF_CHAIN[if_chain].enable = false; - CONTEXT_IF_CHAIN[if_chain].freq_hz = 0; - DEBUG_PRINTF("Note: if_chain %d disabled\n", if_chain); - return LGW_HAL_SUCCESS; - } - - /* check 'general' parameters */ - if (sx1302_get_ifmod_config(if_chain) == IF_UNDEFINED) { - DEBUG_PRINTF("ERROR: IF CHAIN %d NOT CONFIGURABLE\n", if_chain); - } - if (conf->rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n"); - return LGW_HAL_ERROR; - } - /* check if IF frequency is optimal based on channel and radio bandwidths */ - switch (conf->bandwidth) { - case BW_250KHZ: - rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_250KHZ; /* radio bandwidth */ - break; - case BW_500KHZ: - rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_500KHZ; /* radio bandwidth */ - break; - default: - /* For 125KHz and below */ - rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_125KHZ; /* radio bandwidth */ - break; - } - bw_hz = lgw_bw_getval(conf->bandwidth); /* channel bandwidth */ - if ((conf->freq_hz + ((bw_hz==-1)?LGW_REF_BW:bw_hz)/2) > ((int32_t)rf_rx_bandwidth/2)) { - DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO HIGH\n", conf->freq_hz); - return LGW_HAL_ERROR; - } else if ((conf->freq_hz - ((bw_hz==-1)?LGW_REF_BW:bw_hz)/2) < -((int32_t)rf_rx_bandwidth/2)) { - DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf->freq_hz); - return LGW_HAL_ERROR; - } - - /* check parameters according to the type of IF chain + modem, - fill default if necessary, and commit configuration if everything is OK */ - switch (sx1302_get_ifmod_config(if_chain)) { - case IF_LORA_STD: - /* fill default parameters if needed */ - if (conf->bandwidth == BW_UNDEFINED) { - conf->bandwidth = BW_250KHZ; - } - if (conf->datarate == DR_UNDEFINED) { - conf->datarate = DR_LORA_SF7; - } - /* check BW & DR */ - if (!IS_LORA_BW(conf->bandwidth)) { - DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_STD IF CHAIN\n"); - return LGW_HAL_ERROR; - } - if (!IS_LORA_DR(conf->datarate)) { - DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA_STD IF CHAIN\n"); - return LGW_HAL_ERROR; - } - /* set internal configuration */ - CONTEXT_IF_CHAIN[if_chain].enable = conf->enable; - CONTEXT_IF_CHAIN[if_chain].rf_chain = conf->rf_chain; - CONTEXT_IF_CHAIN[if_chain].freq_hz = conf->freq_hz; - CONTEXT_LORA_SERVICE.bandwidth = conf->bandwidth; - CONTEXT_LORA_SERVICE.datarate = conf->datarate; - CONTEXT_LORA_SERVICE.implicit_hdr = conf->implicit_hdr; - CONTEXT_LORA_SERVICE.implicit_payload_length = conf->implicit_payload_length; - CONTEXT_LORA_SERVICE.implicit_crc_en = conf->implicit_crc_en; - CONTEXT_LORA_SERVICE.implicit_coderate = conf->implicit_coderate; - - DEBUG_PRINTF("Note: LoRa 'std' if_chain %d configuration; en:%d freq:%d bw:%d dr:%d\n", if_chain, - CONTEXT_IF_CHAIN[if_chain].enable, - CONTEXT_IF_CHAIN[if_chain].freq_hz, - CONTEXT_LORA_SERVICE.bandwidth, - CONTEXT_LORA_SERVICE.datarate); - break; - - case IF_LORA_MULTI: - /* fill default parameters if needed */ - if (conf->bandwidth == BW_UNDEFINED) { - conf->bandwidth = BW_125KHZ; - } - if (conf->datarate == DR_UNDEFINED) { - conf->datarate = DR_LORA_SF7; - } - /* check BW & DR */ - if (conf->bandwidth != BW_125KHZ) { - DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_MULTI IF CHAIN\n"); - return LGW_HAL_ERROR; - } - if (!IS_LORA_DR(conf->datarate)) { - DEBUG_MSG("ERROR: DATARATE(S) NOT SUPPORTED BY LORA_MULTI IF CHAIN\n"); - return LGW_HAL_ERROR; - } - /* set internal configuration */ - CONTEXT_IF_CHAIN[if_chain].enable = conf->enable; - CONTEXT_IF_CHAIN[if_chain].rf_chain = conf->rf_chain; - CONTEXT_IF_CHAIN[if_chain].freq_hz = conf->freq_hz; - - DEBUG_PRINTF("Note: LoRa 'multi' if_chain %d configuration; en:%d freq:%d\n", if_chain, - CONTEXT_IF_CHAIN[if_chain].enable, - CONTEXT_IF_CHAIN[if_chain].freq_hz); - break; - - case IF_FSK_STD: - /* fill default parameters if needed */ - if (conf->bandwidth == BW_UNDEFINED) { - conf->bandwidth = BW_250KHZ; - } - if (conf->datarate == DR_UNDEFINED) { - conf->datarate = 64000; /* default datarate */ - } - /* check BW & DR */ - if(!IS_FSK_BW(conf->bandwidth)) { - DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY FSK IF CHAIN\n"); - return LGW_HAL_ERROR; - } - if(!IS_FSK_DR(conf->datarate)) { - DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY FSK IF CHAIN\n"); - return LGW_HAL_ERROR; - } - /* set internal configuration */ - CONTEXT_IF_CHAIN[if_chain].enable = conf->enable; - CONTEXT_IF_CHAIN[if_chain].rf_chain = conf->rf_chain; - CONTEXT_IF_CHAIN[if_chain].freq_hz = conf->freq_hz; - CONTEXT_FSK.bandwidth = conf->bandwidth; - CONTEXT_FSK.datarate = conf->datarate; - if (conf->sync_word > 0) { - CONTEXT_FSK.sync_word_size = conf->sync_word_size; - CONTEXT_FSK.sync_word = conf->sync_word; - } - DEBUG_PRINTF("Note: FSK if_chain %d configuration; en:%d freq:%d bw:%d dr:%d (%d real dr) sync:0x%0*" PRIu64 "\n", if_chain, - CONTEXT_IF_CHAIN[if_chain].enable, - CONTEXT_IF_CHAIN[if_chain].freq_hz, - CONTEXT_FSK.bandwidth, - CONTEXT_FSK.datarate, - LGW_XTAL_FREQU/(LGW_XTAL_FREQU/CONTEXT_FSK.datarate), - 2*CONTEXT_FSK.sync_word_size, - CONTEXT_FSK.sync_word); - break; - - default: - DEBUG_PRINTF("ERROR: IF CHAIN %d TYPE NOT SUPPORTED\n", if_chain); - return LGW_HAL_ERROR; - } - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_txgain_setconf(uint8_t rf_chain, struct lgw_tx_gain_lut_s * conf) { - int i; - - CHECK_NULL(conf); - - /* Check LUT size */ - if ((conf->size < 1) || (conf->size > TX_GAIN_LUT_SIZE_MAX)) { - DEBUG_PRINTF("ERROR: TX gain LUT must have at least one entry and maximum %d entries\n", TX_GAIN_LUT_SIZE_MAX); - return LGW_HAL_ERROR; - } - - CONTEXT_TX_GAIN_LUT[rf_chain].size = conf->size; - - for (i = 0; i < CONTEXT_TX_GAIN_LUT[rf_chain].size; i++) { - /* Check gain range */ - if (conf->lut[i].dig_gain > 3) { - DEBUG_MSG("ERROR: TX gain LUT: SX1302 digital gain must be between 0 and 3\n"); - return LGW_HAL_ERROR; - } - if (conf->lut[i].dac_gain > 3) { - DEBUG_MSG("ERROR: TX gain LUT: SX1257 DAC gains must not exceed 3\n"); - return LGW_HAL_ERROR; - } - if ((conf->lut[i].mix_gain < 5) || (conf->lut[i].mix_gain > 15)) { - DEBUG_MSG("ERROR: TX gain LUT: SX1257 mixer gain must be betwen [5..15]\n"); - return LGW_HAL_ERROR; - } - if (conf->lut[i].pa_gain > 3) { - DEBUG_MSG("ERROR: TX gain LUT: External PA gain must not exceed 3\n"); - return LGW_HAL_ERROR; - } - if (conf->lut[i].pwr_idx > 22) { - DEBUG_MSG("ERROR: TX gain LUT: SX1250 power iundex must not exceed 22\n"); - return LGW_HAL_ERROR; - } - - /* Set internal LUT */ - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].rf_power = conf->lut[i].rf_power; - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].dig_gain = conf->lut[i].dig_gain; - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].pa_gain = conf->lut[i].pa_gain; - /* sx125x */ - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].dac_gain = conf->lut[i].dac_gain; - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].mix_gain = conf->lut[i].mix_gain; - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].offset_i = 0; /* To be calibrated */ - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].offset_q = 0; /* To be calibrated */ - - /* sx1250 */ - CONTEXT_TX_GAIN_LUT[rf_chain].lut[i].pwr_idx = conf->lut[i].pwr_idx; - } - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_timestamp_setconf(struct lgw_conf_timestamp_s * conf) { - CHECK_NULL(conf); - - CONTEXT_TIMESTAMP.enable_precision_ts = conf->enable_precision_ts; - CONTEXT_TIMESTAMP.max_ts_metrics = conf->max_ts_metrics; - CONTEXT_TIMESTAMP.nb_symbols = conf->nb_symbols; - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_debug_setconf(struct lgw_conf_debug_s * conf) { - int i; - - CHECK_NULL(conf); - - CONTEXT_DEBUG.nb_ref_payload = conf->nb_ref_payload; - for (i = 0; i < CONTEXT_DEBUG.nb_ref_payload; i++) { - /* Get user configuration */ - CONTEXT_DEBUG.ref_payload[i].id = conf->ref_payload[i].id; - - /* Initialize global context */ - CONTEXT_DEBUG.ref_payload[i].prev_cnt = 0; - CONTEXT_DEBUG.ref_payload[i].payload[0] = (uint8_t)(CONTEXT_DEBUG.ref_payload[i].id >> 24); - CONTEXT_DEBUG.ref_payload[i].payload[1] = (uint8_t)(CONTEXT_DEBUG.ref_payload[i].id >> 16); - CONTEXT_DEBUG.ref_payload[i].payload[2] = (uint8_t)(CONTEXT_DEBUG.ref_payload[i].id >> 8); - CONTEXT_DEBUG.ref_payload[i].payload[3] = (uint8_t)(CONTEXT_DEBUG.ref_payload[i].id >> 0); - } - - if (conf->log_file_name != NULL) { - strncpy(CONTEXT_DEBUG.log_file_name, conf->log_file_name, sizeof CONTEXT_DEBUG.log_file_name); - CONTEXT_DEBUG.log_file_name[sizeof CONTEXT_DEBUG.log_file_name - 1] = '\0'; /* ensure string termination */ - } - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_start(void) { - int i, err; - int reg_stat; - - if (CONTEXT_STARTED == true) { - DEBUG_MSG("Note: LoRa concentrator already started, restarting it now\n"); - } - - reg_stat = lgw_connect(CONTEXT_SPI); - if (reg_stat == LGW_REG_ERROR) { - DEBUG_MSG("ERROR: FAIL TO CONNECT BOARD\n"); - return LGW_HAL_ERROR; - } - - /* Calibrate radios */ - err = sx1302_radio_calibrate(&CONTEXT_RF_CHAIN[0], CONTEXT_BOARD.clksrc, &CONTEXT_TX_GAIN_LUT[0]); - if (err != LGW_REG_SUCCESS) { - printf("ERROR: radio calibration failed\n"); - return LGW_HAL_ERROR; - } - - /* Setup radios for RX */ - for (i = 0; i < LGW_RF_CHAIN_NB; i++) { - if (CONTEXT_RF_CHAIN[i].enable == true) { - sx1302_radio_reset(i, CONTEXT_RF_CHAIN[i].type); - switch (CONTEXT_RF_CHAIN[i].type) { - case LGW_RADIO_TYPE_SX1250: - sx1250_setup(i, CONTEXT_RF_CHAIN[i].freq_hz, CONTEXT_RF_CHAIN[i].single_input_mode); - break; - case LGW_RADIO_TYPE_SX1255: - case LGW_RADIO_TYPE_SX1257: - sx125x_setup(i, CONTEXT_BOARD.clksrc, true, CONTEXT_RF_CHAIN[i].type, CONTEXT_RF_CHAIN[i].freq_hz); - break; - default: - DEBUG_PRINTF("ERROR: RADIO TYPE NOT SUPPORTED (RF_CHAIN %d)\n", i); - return LGW_HAL_ERROR; - } - sx1302_radio_set_mode(i, CONTEXT_RF_CHAIN[i].type); - } - } - - /* Select the radio which provides the clock to the sx1302 */ - sx1302_radio_clock_select(CONTEXT_BOARD.clksrc); - - /* Release host control on radio (will be controlled by AGC) */ - sx1302_radio_host_ctrl(false); - - /* Basic initialization of the sx1302 */ - sx1302_init(&CONTEXT_TIMESTAMP); - - /* Configure PA/LNA LUTs */ - sx1302_pa_lna_lut_configure(); - - /* Configure Radio FE */ - sx1302_radio_fe_configure(); - - /* Configure the Channelizer */ - sx1302_channelizer_configure(CONTEXT_IF_CHAIN, false); - - /* configure LoRa 'multi' demodulators */ - sx1302_lora_correlator_configure(); - sx1302_lora_modem_configure(CONTEXT_RF_CHAIN[0].freq_hz); /* TODO: freq_hz used to confiogure freq to time drift, based on RF0 center freq only */ - - /* configure LoRa 'stand-alone' modem */ - if (CONTEXT_IF_CHAIN[8].enable == true) { - sx1302_lora_service_correlator_configure(&(CONTEXT_LORA_SERVICE)); - sx1302_lora_service_modem_configure(&(CONTEXT_LORA_SERVICE), CONTEXT_RF_CHAIN[0].freq_hz); /* TODO: freq_hz used to confiogure freq to time drift, based on RF0 center freq only */ - } - - /* configure FSK modem */ - if (CONTEXT_IF_CHAIN[9].enable == true) { - sx1302_fsk_configure(&(CONTEXT_FSK)); - } - - /* configure syncword */ - sx1302_lora_syncword(CONTEXT_LWAN_PUBLIC, CONTEXT_LORA_SERVICE.datarate); - - /* enable demodulators - to be done before starting AGC/ARB */ - sx1302_modem_enable(); - - /* Load firmware */ - switch (CONTEXT_RF_CHAIN[CONTEXT_BOARD.clksrc].type) { - case LGW_RADIO_TYPE_SX1250: - DEBUG_MSG("Loading AGC fw for sx1250\n"); - if (sx1302_agc_load_firmware(agc_firmware_sx1250) != LGW_HAL_SUCCESS) { - return LGW_HAL_ERROR; - } - break; - case LGW_RADIO_TYPE_SX1257: - DEBUG_MSG("Loading AGC fw for sx125x\n"); - if (sx1302_agc_load_firmware(agc_firmware_sx125x) != LGW_HAL_SUCCESS) { - return LGW_HAL_ERROR; - } - break; - default: - break; - } - if (sx1302_agc_start(FW_VERSION_AGC, CONTEXT_RF_CHAIN[CONTEXT_BOARD.clksrc].type, SX1302_AGC_RADIO_GAIN_AUTO, SX1302_AGC_RADIO_GAIN_AUTO, (CONTEXT_BOARD.full_duplex == true) ? 1 : 0) != LGW_HAL_SUCCESS) { - return LGW_HAL_ERROR; - } - DEBUG_MSG("Loading ARB fw\n"); - if (sx1302_arb_load_firmware(arb_firmware) != LGW_HAL_SUCCESS) { - return LGW_HAL_ERROR; - } - if (sx1302_arb_start(FW_VERSION_ARB) != LGW_HAL_SUCCESS) { - return LGW_HAL_ERROR; - } - - /* static TX configuration */ - sx1302_tx_configure(CONTEXT_RF_CHAIN[CONTEXT_BOARD.clksrc].type); - - /* enable GPS */ - sx1302_gps_enable(true); - - /* For debug logging */ -#if HAL_DEBUG_FILE_LOG - char timestamp_str[40]; - struct tm *timenow; - - /* Append current time to log file name */ - time_t now = time(NULL); - timenow = gmtime(&now); - strftime(timestamp_str, sizeof(timestamp_str), ".%Y-%m-%d_%H%M%S", timenow); - strncat(CONTEXT_DEBUG.log_file_name, timestamp_str, sizeof CONTEXT_DEBUG.log_file_name); - - /* Open the file for writting */ - log_file = fopen(CONTEXT_DEBUG.log_file_name, "w+"); /* create log file, overwrite if file already exist */ - if (log_file == NULL) { - printf("ERROR: impossible to create log file %s\n", CONTEXT_DEBUG.log_file_name); - return LGW_HAL_ERROR; - } else { - printf("INFO: %s file opened for debug log\n", CONTEXT_DEBUG.log_file_name); - - /* Create "pktlog.csv" symlink to simplify user life */ - unlink("loragw_hal.log"); - i = symlink(CONTEXT_DEBUG.log_file_name, "loragw_hal.log"); - if (i < 0) { - printf("ERROR: impossible to create symlink to log file %s\n", CONTEXT_DEBUG.log_file_name); - } - } -#endif - - /* Configure the pseudo-random generator (For Debug) */ - dbg_init_random(); - -#if 0 - /* Configure a GPIO to be toggled for debug purpose */ - dbg_init_gpio(); -#endif - - /* Try to configure temperature sensor STTS751-0DP3F */ -/* - ts_addr = I2C_PORT_TEMP_SENSOR_0; - i2c_linuxdev_open(I2C_DEVICE, ts_addr, &ts_fd); - err = stts751_configure(ts_fd, ts_addr); - if (err != LGW_I2C_SUCCESS) { - i2c_linuxdev_close(ts_fd); - ts_fd = -1; - // * Not found, try to configure temperature sensor STTS751-1DP3F - ts_addr = I2C_PORT_TEMP_SENSOR_1; - i2c_linuxdev_open(I2C_DEVICE, ts_addr, &ts_fd); - err = stts751_configure(ts_fd, ts_addr); - if (err != LGW_I2C_SUCCESS) { - printf("ERROR: failed to configure the temperature sensor\n"); - return LGW_HAL_ERROR; - } - } -*/ - /* set hal state */ - CONTEXT_STARTED = true; - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_stop(void) { - int i, err; - - DEBUG_MSG("INFO: aborting TX\n"); - for (i = 0; i < LGW_RF_CHAIN_NB; i++) { - lgw_abort_tx(i); - } - - /* Close log file */ - if (log_file != NULL) { - fclose(log_file); - log_file = NULL; - } - - DEBUG_MSG("INFO: Disconnecting\n"); - lgw_disconnect(); - - DEBUG_MSG("INFO: Closing I2C\n"); - //err = i2c_linuxdev_close(ts_fd); - //if (err != 0) { - // printf("ERROR: failed to close I2C device (err=%i)\n", err); - //} - - CONTEXT_STARTED = false; - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { - int res; - uint8_t nb_pkt_fetched = 0; - uint16_t nb_pkt_found = 0; - uint16_t nb_pkt_left = 0; - //float current_temperature, rssi_temperature_offset; - float current_temperature = 30.0; - float rssi_temperature_offset; - - /* Check that AGC/ARB firmwares are not corrupted, and update internal counter */ - /* WARNING: this needs to be called regularly by the upper layer */ - res = sx1302_update(); - if (res != LGW_REG_SUCCESS) { - return LGW_HAL_ERROR; - } - - /* Get packets from SX1302, if any */ - res = sx1302_fetch(&nb_pkt_fetched); - if (res != LGW_REG_SUCCESS) { - printf("ERROR: failed to fetch packets from SX1302\n"); - return LGW_HAL_ERROR; - } - if (nb_pkt_fetched == 0) { - return 0; - } - if (nb_pkt_fetched > max_pkt) { - nb_pkt_left = nb_pkt_fetched - max_pkt; - printf("WARNING: not enough space allocated, fetched %d packet(s), %d will be left in RX buffer\n", nb_pkt_fetched, nb_pkt_left); - } - - /* Apply RSSI temperature compensation */ - //res = stts751_get_temperature(ts_fd, ts_addr, ¤t_temperature); - //if (res != LGW_I2C_SUCCESS) { - // printf("ERROR: failed to get current temperature\n"); - // return LGW_HAL_ERROR; - //} - - /* Iterate on the RX buffer to get parsed packets */ - for (nb_pkt_found = 0; nb_pkt_found < ((nb_pkt_fetched <= max_pkt) ? nb_pkt_fetched : max_pkt); nb_pkt_found++) { - /* Get packet and move to next one */ - res = sx1302_parse(&lgw_context, &pkt_data[nb_pkt_found]); - if (res != LGW_REG_SUCCESS) { - printf("ERROR: failed to parse fetched packet %d, aborting...\n", nb_pkt_found); - return LGW_HAL_ERROR; - } - - /* Appli RSSI offset calibrated for the board */ - pkt_data[nb_pkt_found].rssic += CONTEXT_RF_CHAIN[pkt_data[nb_pkt_found].rf_chain].rssi_offset; - pkt_data[nb_pkt_found].rssis += CONTEXT_RF_CHAIN[pkt_data[nb_pkt_found].rf_chain].rssi_offset; - - rssi_temperature_offset = sx1302_rssi_get_temperature_offset(&CONTEXT_RF_CHAIN[pkt_data[nb_pkt_found].rf_chain].rssi_tcomp, current_temperature); - pkt_data[nb_pkt_found].rssic += rssi_temperature_offset; - pkt_data[nb_pkt_found].rssis += rssi_temperature_offset; - DEBUG_PRINTF("INFO: RSSI temperature offset applied: %.3f dB (current temperature %.1f C)\n", rssi_temperature_offset, current_temperature); - } - - DEBUG_PRINTF("INFO: nb pkt found:%u left:%u\n", nb_pkt_found, nb_pkt_left); - - return nb_pkt_found; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_send(struct lgw_pkt_tx_s * pkt_data) { - /* check if the concentrator is running */ - if (CONTEXT_STARTED == false) { - DEBUG_MSG("ERROR: CONCENTRATOR IS NOT RUNNING, START IT BEFORE SENDING\n"); - return LGW_HAL_ERROR; - } - - CHECK_NULL(pkt_data); - - /* check input range (segfault prevention) */ - if (pkt_data->rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN TO SEND PACKETS\n"); - return LGW_HAL_ERROR; - } - - /* check input variables */ - if (CONTEXT_RF_CHAIN[pkt_data->rf_chain].tx_enable == false) { - DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED FOR TX ON SELECTED BOARD\n"); - return LGW_HAL_ERROR; - } - if (CONTEXT_RF_CHAIN[pkt_data->rf_chain].enable == false) { - DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED\n"); - return LGW_HAL_ERROR; - } - if (!IS_TX_MODE(pkt_data->tx_mode)) { - DEBUG_MSG("ERROR: TX_MODE NOT SUPPORTED\n"); - return LGW_HAL_ERROR; - } - if (pkt_data->modulation == MOD_LORA) { - if (!IS_LORA_BW(pkt_data->bandwidth)) { - DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA TX\n"); - return LGW_HAL_ERROR; - } - if (!IS_LORA_DR(pkt_data->datarate)) { - DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA TX\n"); - return LGW_HAL_ERROR; - } - if (!IS_LORA_CR(pkt_data->coderate)) { - DEBUG_MSG("ERROR: CODERATE NOT SUPPORTED BY LORA TX\n"); - return LGW_HAL_ERROR; - } - if (pkt_data->size > 255) { - DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR LORA TX\n"); - return LGW_HAL_ERROR; - } - } else if (pkt_data->modulation == MOD_FSK) { - if((pkt_data->f_dev < 1) || (pkt_data->f_dev > 200)) { - DEBUG_MSG("ERROR: TX FREQUENCY DEVIATION OUT OF ACCEPTABLE RANGE\n"); - return LGW_HAL_ERROR; - } - if(!IS_FSK_DR(pkt_data->datarate)) { - DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY FSK IF CHAIN\n"); - return LGW_HAL_ERROR; - } - if (pkt_data->size > 255) { - DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR FSK TX\n"); - return LGW_HAL_ERROR; - } - } else if (pkt_data->modulation == MOD_CW) { - /* do nothing */ - } else { - DEBUG_MSG("ERROR: INVALID TX MODULATION\n"); - return LGW_HAL_ERROR; - } - - return sx1302_send(CONTEXT_RF_CHAIN[pkt_data->rf_chain].type, &CONTEXT_TX_GAIN_LUT[pkt_data->rf_chain], CONTEXT_LWAN_PUBLIC, &CONTEXT_FSK, pkt_data); -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_status(uint8_t rf_chain, uint8_t select, uint8_t *code) { - /* check input variables */ - CHECK_NULL(code); - if (rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: NOT A VALID RF_CHAIN NUMBER\n"); - return LGW_HAL_ERROR; - } - - /* Get status */ - if (select == TX_STATUS) { - if (CONTEXT_STARTED == false) { - *code = TX_OFF; - } else { - *code = sx1302_tx_status(rf_chain); - } - } else if (select == RX_STATUS) { - if (CONTEXT_STARTED == false) { - *code = RX_OFF; - } else { - *code = sx1302_rx_status(rf_chain); - } - } else { - DEBUG_MSG("ERROR: SELECTION INVALID, NO STATUS TO RETURN\n"); - return LGW_HAL_ERROR; - } - - //DEBUG_PRINTF("INFO: STATUS %u\n", *code); - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_abort_tx(uint8_t rf_chain) { - /* check input variables */ - if (rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: NOT A VALID RF_CHAIN NUMBER\n"); - return LGW_HAL_ERROR; - } - - /* Abort current TX */ - return sx1302_tx_abort(rf_chain); -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_get_trigcnt(uint32_t* trig_cnt_us) { - CHECK_NULL(trig_cnt_us); - - *trig_cnt_us = sx1302_timestamp_counter(true); - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_get_instcnt(uint32_t* inst_cnt_us) { - CHECK_NULL(inst_cnt_us); - - *inst_cnt_us = sx1302_timestamp_counter(false); - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_get_eui(uint64_t* eui) { - CHECK_NULL(eui); - - if (sx1302_get_eui(eui) != LGW_REG_SUCCESS) { - return LGW_HAL_ERROR; - } - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -int lgw_get_temperature(float* temperature) { - CHECK_NULL(temperature); - *temperature = 30.0; - //if (stts751_get_temperature(ts_fd, ts_addr, temperature) != LGW_I2C_SUCCESS) { - // return LGW_HAL_ERROR; - //} - - return LGW_HAL_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -const char* lgw_version_info() { - return lgw_version_string; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -uint32_t lgw_time_on_air(struct lgw_pkt_tx_s *packet) { - int32_t val; - uint8_t SF, H, DE; - uint16_t BW; - uint32_t payloadSymbNb, Tpacket; - double Tsym, Tpreamble, Tpayload, Tfsk; - - if (packet == NULL) { - DEBUG_MSG("ERROR: Failed to compute time on air, wrong parameter\n"); - return 0; - } - - if (packet->modulation == MOD_LORA) { - /* Get bandwidth */ - val = lgw_bw_getval(packet->bandwidth); - if (val != -1) { - BW = (uint16_t)(val / 1E3); - } else { - DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported bandwidth (0x%02X)\n", packet->bandwidth); - return 0; - } - - /* Get datarate */ - val = lgw_sf_getval(packet->datarate); - if (val != -1) { - SF = (uint8_t)val; - /* TODO: update formula for SF5/SF6 */ - if (SF < 7) { - DEBUG_MSG("WARNING: clipping time on air computing to SF7 for SF5/SF6\n"); - SF = 7; - } - } else { - DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported datarate (0x%02X)\n", packet->datarate); - return 0; - } - - /* Duration of 1 symbol */ - Tsym = pow(2, SF) / BW; - - /* Duration of preamble */ - Tpreamble = ((double)(packet->preamble) + 4.25) * Tsym; - - /* Duration of payload */ - H = (packet->no_header==false) ? 0 : 1; /* header is always enabled, except for beacons */ - DE = (SF >= 11) ? 1 : 0; /* Low datarate optimization enabled for SF11 and SF12 */ - - payloadSymbNb = 8 + (ceil((double)(8*packet->size - 4*SF + 28 + 16 - 20*H) / (double)(4*(SF - 2*DE))) * (packet->coderate + 4)); /* Explicitely cast to double to keep precision of the division */ - - Tpayload = payloadSymbNb * Tsym; - - /* Duration of packet */ - Tpacket = Tpreamble + Tpayload; - } else if (packet->modulation == MOD_FSK) { - /* PREAMBLE + SYNC_WORD + PKT_LEN + PKT_PAYLOAD + CRC - PREAMBLE: default 5 bytes - SYNC_WORD: default 3 bytes - PKT_LEN: 1 byte (variable length mode) - PKT_PAYLOAD: x bytes - CRC: 0 or 2 bytes - */ - Tfsk = (8 * (double)(packet->preamble + CONTEXT_FSK.sync_word_size + 1 + packet->size + ((packet->no_crc == true) ? 0 : 2)) / (double)packet->datarate) * 1E3; - - /* Duration of packet */ - Tpacket = (uint32_t)Tfsk + 1; /* add margin for rounding */ - } else { - Tpacket = 0; - DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported modulation (0x%02X)\n", packet->modulation); - } - - return Tpacket; -} - -/* --- EOF ------------------------------------------------------------------ */ diff --git a/lora/rak2287_spi/loragw_stts751.c b/lora/rak2287_spi/loragw_stts751.c new file mode 100644 index 0000000..dea8616 --- /dev/null +++ b/lora/rak2287_spi/loragw_stts751.c @@ -0,0 +1,185 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2019 Semtech + +Description: + Basic driver for ST ts751 temperature sensor + +License: Revised BSD License, see LICENSE.TXT file include in the project +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +#include /* C99 types */ +#include /* bool type */ +#include /* printf fprintf */ + +#include "loragw_i2c.h" +#include "loragw_stts751.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#if DEBUG_I2C == 1 + #define DEBUG_MSG(str) fprintf(stdout, str) + #define DEBUG_PRINTF(fmt, args...) fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) + #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;} +#else + #define DEBUG_MSG(str) + #define DEBUG_PRINTF(fmt, args...) + #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;} +#endif + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +#define STTS751_REG_TEMP_H 0x00 +#define STTS751_REG_STATUS 0x01 +#define STTS751_STATUS_TRIPT BIT(0) +#define STTS751_STATUS_TRIPL BIT(5) +#define STTS751_STATUS_TRIPH BIT(6) +#define STTS751_REG_TEMP_L 0x02 +#define STTS751_REG_CONF 0x03 +#define STTS751_CONF_RES_MASK 0x0C +#define STTS751_CONF_RES_SHIFT 2 +#define STTS751_CONF_EVENT_DIS BIT(7) +#define STTS751_CONF_STOP BIT(6) +#define STTS751_REG_RATE 0x04 +#define STTS751_REG_HLIM_H 0x05 +#define STTS751_REG_HLIM_L 0x06 +#define STTS751_REG_LLIM_H 0x07 +#define STTS751_REG_LLIM_L 0x08 +#define STTS751_REG_TLIM 0x20 +#define STTS751_REG_HYST 0x21 +#define STTS751_REG_SMBUS_TO 0x22 + +#define STTS751_REG_PROD_ID 0xFD +#define STTS751_REG_MAN_ID 0xFE +#define STTS751_REG_REV_ID 0xFF + +#define STTS751_0_PROD_ID 0x00 +#define STTS751_1_PROD_ID 0x01 +#define ST_MAN_ID 0x53 + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES ---------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ + +int stts751_configure(int i2c_fd, uint8_t i2c_addr) { +#if 0 + int err; + uint8_t val; + + /* Check Input Params */ + if (i2c_fd <= 0) { + printf("ERROR: invalid I2C file descriptor\n"); + return LGW_I2C_ERROR; + } + + DEBUG_PRINTF("INFO: configuring STTS751 temperature sensor on 0x%02X...\n", i2c_addr); + + /* Get product ID and test which sensor is mounted */ + err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_PROD_ID, &val); + if (err != 0) { + DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); + return LGW_I2C_ERROR; + } + switch (val) { + case STTS751_0_PROD_ID: + DEBUG_MSG("INFO: Product ID: STTS751-0\n"); + break; + case STTS751_1_PROD_ID: + DEBUG_MSG("INFO: Product ID: STTS751-1\n"); + break; + default: + printf("ERROR: Product ID: UNKNOWN\n"); + return LGW_I2C_ERROR; + } + + /* Get Manufacturer ID */ + err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_MAN_ID, &val); + if (err != 0) { + DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); + return LGW_I2C_ERROR; + } + if (val != ST_MAN_ID) { + printf("ERROR: Manufacturer ID: UNKNOWN\n"); + return LGW_I2C_ERROR; + } else { + DEBUG_PRINTF("INFO: Manufacturer ID: 0x%02X\n", val); + } + + /* Get revision number */ + err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_REV_ID, &val); + if (err != 0) { + DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); + return LGW_I2C_ERROR; + } + DEBUG_PRINTF("INFO: Revision number: 0x%02X\n", val); + + /* Set conversion resolution to 12 bits */ + err = i2c_linuxdev_write(i2c_fd, i2c_addr, STTS751_REG_CONF, 0x8C); /* TODO: do not hardcode the whole byte */ + if (err != 0) { + DEBUG_PRINTF("ERROR: failed to write I2C device 0x%02X (err=%i)\n", i2c_addr, err); + return LGW_I2C_ERROR; + } + + /* Set conversion rate to 1 / second */ + err = i2c_linuxdev_write(i2c_fd, i2c_addr, STTS751_REG_RATE, 0x04); + if (err != 0) { + DEBUG_PRINTF("ERROR: failed to write I2C device 0x%02X (err=%i)\n", i2c_addr, err); + return LGW_I2C_ERROR; + } +#endif + return LGW_I2C_SUCCESS; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +int stts751_get_temperature(int i2c_fd, uint8_t i2c_addr, float * temperature) { +#if 0 + int err; + uint8_t high_byte, low_byte; + int8_t h; + + /* Check Input Params */ + if (i2c_fd <= 0) { + printf("ERROR: invalid I2C file descriptor\n"); + return LGW_I2C_ERROR; + } + + /* Read Temperature LSB */ + err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_TEMP_L, &low_byte); + if (err != 0) { + printf("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); + return LGW_I2C_ERROR; + } + + /* Read Temperature MSB */ + err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_TEMP_H, &high_byte); + if (err != 0) { + printf("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); + return LGW_I2C_ERROR; + } + + h = (int8_t)high_byte; + *temperature = ((h << 8) | low_byte) / 256.0; + + DEBUG_PRINTF("Temperature: %f C (h:0x%02X l:0x%02X)\n", *temperature, high_byte, low_byte); +#endif + return LGW_I2C_SUCCESS; +} + +/* --- EOF ------------------------------------------------------------------ */ diff --git a/lora/rak2287_spi/test_loragw_gps_i2c.c b/lora/rak2287_spi/test_loragw_gps_i2c.c index 6c08c06..95385b9 100755 --- a/lora/rak2287_spi/test_loragw_gps_i2c.c +++ b/lora/rak2287_spi/test_loragw_gps_i2c.c @@ -43,7 +43,8 @@ License: Revised BSD License, see LICENSE.TXT file include in the project /* -------------------------------------------------------------------------- */ /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ -#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0" +#define COM_TYPE_DEFAULT LGW_COM_SPI +#define COM_PATH_DEFAULT "/dev/spidev0.0" /* -------------------------------------------------------------------------- */ /* --- PRIVATE VARIABLES ---------------------------------------------------- */ @@ -65,10 +66,13 @@ static void gps_process_coords(void); void usage(void) { //printf("Library version information: %s\n", lgw_version_info()); - printf( "Available options:\n"); - printf( " -h print this help\n"); - printf( " -k Concentrator clock source (Radio A or Radio B) [0..1]\n"); - printf( " -r Radio type (1255, 1257, 1250)\n"); + printf("Available options:\n"); + printf(" -h print this help\n"); + printf(" -u set COM type as USB (default is SPI)\n"); + printf(" -d COM path to be used to connect the concentrator\n"); + printf(" => default path (SPI): " COM_PATH_DEFAULT "\n"); + printf(" -k Concentrator clock source (Radio A or Radio B) [0..1]\n"); + printf(" -r Radio type (1255, 1257, 1250)\n"); } static void sig_handler(int sigio) { @@ -170,8 +174,9 @@ static void gps_process_coords(void) { int main(int argc, char **argv) { /* SPI interfaces */ - const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT; - const char * spidev_path = spidev_path_default; + const char com_path_default[] = COM_PATH_DEFAULT; + const char * com_path = com_path_default; + lgw_com_type_t com_type = COM_TYPE_DEFAULT; struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ @@ -180,7 +185,7 @@ int main(int argc, char **argv) /* concentrator variables */ uint8_t clocksource = 0; - lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE; + lgw_radio_type_t radio_type = LGW_RADIO_TYPE_SX1250; struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; @@ -193,12 +198,20 @@ int main(int argc, char **argv) enum gps_msg latest_msg; /* keep track of latest NMEA/UBX message parsed */ /* parse command line options */ - while ((i = getopt (argc, argv, "hk:r:")) != -1) { + while ((i = getopt (argc, argv, "hk:r:d:u")) != -1) { switch (i) { case 'h': usage(); return -1; break; + case 'd': + if (optarg != NULL) { + com_path = optarg; + } + break; + case 'u': + com_type = LGW_COM_USB; + break; case 'r': /* Radio type */ i = sscanf(optarg, "%u", &arg_u); if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) { @@ -234,13 +247,6 @@ int main(int argc, char **argv) } } - /* Check arguments */ - if (radio_type == LGW_RADIO_TYPE_NONE) { - printf("ERROR: radio type must be specified\n"); - usage(); - exit(EXIT_FAILURE); - } - /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; @@ -253,10 +259,12 @@ int main(int argc, char **argv) printf("Beginning of test for loragw_gps.c\n"); printf("*** Library version information ***\n%s\n***\n", lgw_version_info()); - /* Board reset */ - if (system("./reset_lgw.sh start") != 0) { - printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); - exit(EXIT_FAILURE); + if (com_type == LGW_COM_SPI) { + /* Board reset */ + if (system("./reset_lgw.sh start") != 0) { + printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); + exit(EXIT_FAILURE); + } } /* Open and configure GPS */ @@ -272,8 +280,9 @@ int main(int argc, char **argv) boardconf.lorawan_public = true; boardconf.clksrc = clocksource; boardconf.full_duplex = false; - strncpy(boardconf.spidev_path, spidev_path, sizeof boardconf.spidev_path); - boardconf.spidev_path[sizeof boardconf.spidev_path - 1] = '\0'; /* ensure string termination */ + boardconf.com_type = com_type; + strncpy(boardconf.com_path, com_path, sizeof boardconf.com_path); + boardconf.com_path[sizeof boardconf.com_path - 1] = '\0'; /* ensure string termination */ if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) { printf("ERROR: failed to configure board\n"); return EXIT_FAILURE; @@ -405,10 +414,12 @@ int main(int argc, char **argv) lgw_stop(); } - /* Board reset */ - if (system("./reset_lgw.sh stop") != 0) { - printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); - exit(EXIT_FAILURE); + if (com_type == LGW_COM_SPI) { + /* Board reset */ + if (system("./reset_lgw.sh stop") != 0) { + printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); + exit(EXIT_FAILURE); + } } printf("\nEnd of test for loragw_gps.c\n"); diff --git a/lora/rak2287_spi/test_loragw_gps_uart.c b/lora/rak2287_spi/test_loragw_gps_uart.c index df9627b..b686cd0 100755 --- a/lora/rak2287_spi/test_loragw_gps_uart.c +++ b/lora/rak2287_spi/test_loragw_gps_uart.c @@ -43,7 +43,8 @@ License: Revised BSD License, see LICENSE.TXT file include in the project /* -------------------------------------------------------------------------- */ /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ -#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0" +#define COM_TYPE_DEFAULT LGW_COM_SPI +#define COM_PATH_DEFAULT "/dev/spidev0.0" /* -------------------------------------------------------------------------- */ /* --- PRIVATE VARIABLES ---------------------------------------------------- */ @@ -65,10 +66,13 @@ static void gps_process_coords(void); void usage(void) { //printf("Library version information: %s\n", lgw_version_info()); - printf( "Available options:\n"); - printf( " -h print this help\n"); - printf( " -k Concentrator clock source (Radio A or Radio B) [0..1]\n"); - printf( " -r Radio type (1255, 1257, 1250)\n"); + printf("Available options:\n"); + printf(" -h print this help\n"); + printf(" -u set COM type as USB (default is SPI)\n"); + printf(" -d COM path to be used to connect the concentrator\n"); + printf(" => default path (SPI): " COM_PATH_DEFAULT "\n"); + printf(" -k Concentrator clock source (Radio A or Radio B) [0..1]\n"); + printf(" -r Radio type (1255, 1257, 1250)\n"); } static void sig_handler(int sigio) { @@ -170,8 +174,9 @@ static void gps_process_coords(void) { int main(int argc, char **argv) { /* SPI interfaces */ - const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT; - const char * spidev_path = spidev_path_default; + const char com_path_default[] = COM_PATH_DEFAULT; + const char * com_path = com_path_default; + lgw_com_type_t com_type = COM_TYPE_DEFAULT; struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ @@ -180,7 +185,7 @@ int main(int argc, char **argv) /* concentrator variables */ uint8_t clocksource = 0; - lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE; + lgw_radio_type_t radio_type = LGW_RADIO_TYPE_SX1250; struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; @@ -193,12 +198,20 @@ int main(int argc, char **argv) enum gps_msg latest_msg; /* keep track of latest NMEA/UBX message parsed */ /* parse command line options */ - while ((i = getopt (argc, argv, "hk:r:")) != -1) { + while ((i = getopt (argc, argv, "hk:r:d:u")) != -1) { switch (i) { case 'h': usage(); return -1; break; + case 'd': + if (optarg != NULL) { + com_path = optarg; + } + break; + case 'u': + com_type = LGW_COM_USB; + break; case 'r': /* Radio type */ i = sscanf(optarg, "%u", &arg_u); if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) { @@ -234,13 +247,6 @@ int main(int argc, char **argv) } } - /* Check arguments */ - if (radio_type == LGW_RADIO_TYPE_NONE) { - printf("ERROR: radio type must be specified\n"); - usage(); - exit(EXIT_FAILURE); - } - /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; @@ -253,10 +259,12 @@ int main(int argc, char **argv) printf("Beginning of test for loragw_gps.c\n"); printf("*** Library version information ***\n%s\n***\n", lgw_version_info()); - /* Board reset */ - if (system("./reset_lgw.sh start") != 0) { - printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); - exit(EXIT_FAILURE); + if (com_type == LGW_COM_SPI) { + /* Board reset */ + if (system("./reset_lgw.sh start") != 0) { + printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); + exit(EXIT_FAILURE); + } } /* Open and configure GPS */ @@ -272,8 +280,9 @@ int main(int argc, char **argv) boardconf.lorawan_public = true; boardconf.clksrc = clocksource; boardconf.full_duplex = false; - strncpy(boardconf.spidev_path, spidev_path, sizeof boardconf.spidev_path); - boardconf.spidev_path[sizeof boardconf.spidev_path - 1] = '\0'; /* ensure string termination */ + boardconf.com_type = com_type; + strncpy(boardconf.com_path, com_path, sizeof boardconf.com_path); + boardconf.com_path[sizeof boardconf.com_path - 1] = '\0'; /* ensure string termination */ if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) { printf("ERROR: failed to configure board\n"); return EXIT_FAILURE; @@ -405,10 +414,12 @@ int main(int argc, char **argv) lgw_stop(); } - /* Board reset */ - if (system("./reset_lgw.sh stop") != 0) { - printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); - exit(EXIT_FAILURE); + if (com_type == LGW_COM_SPI) { + /* Board reset */ + if (system("./reset_lgw.sh stop") != 0) { + printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n"); + exit(EXIT_FAILURE); + } } printf("\nEnd of test for loragw_gps.c\n"); diff --git a/rak/gateway-config b/rak/gateway-config index b4619c5..c541808 100755 --- a/rak/gateway-config +++ b/rak/gateway-config @@ -101,7 +101,7 @@ do_copy_global_conf() { do_setup_ttn_channel_plan() { default_item=1 - if [ "${GW_MODEL}" = "RAK2287" ] || [ "${GW_MODEL}" = "RAK2285" ]; then + if [ "${GW_MODEL}" = "RAK2285" ]; then FUN=$(dialog --title "TTN Channel-plan configuration" --default-item $default_item --menu "Select the Channel-plan:" 18 60 12 \ 1 "AS_923(920_923)" \ 2 "AS_923(923_925)" \ @@ -188,7 +188,7 @@ do_set_lora_server_ip() do_setup_LoRaServer_channel_plan() { default_item=1 - if [ "${GW_MODEL}" = "RAK2287" ] || [ "${GW_MODEL}" = "RAK2285" ]; then + if [ "${GW_MODEL}" = "RAK2285" ]; then FUN=$(dialog --title "TTN Channel-plan configuration" --default-item $default_item --menu "Select the Channel-plan:" 18 60 12 \ 1 "AS_923(920_923)" \ 2 "AS_923(923_925)" \ diff --git a/rak/install.sh b/rak/install.sh index d609170..e2217e4 100755 --- a/rak/install.sh +++ b/rak/install.sh @@ -20,6 +20,7 @@ apt install git ppp dialog jq minicom monit i2c-tools -y cp gateway-config /usr/bin/ cp gateway-version /usr/bin/ cp rak_test /usr/bin/ +cp test_rak /usr/bin/ cp rak /usr/local/ -rf if [ "$1" = "create_img" ]; then diff --git a/rak/rak/rak_gw_model.json b/rak/rak/rak_gw_model.json index 3fbc1a5..280c26a 100755 --- a/rak/rak/rak_gw_model.json +++ b/rak/rak/rak_gw_model.json @@ -1,5 +1,5 @@ { "gw_model": "RAK7243", - "gw_version": "4.2.6R", + "gw_version": "4.2.7R", "spi": 0 } diff --git a/rak/test_rak b/rak/test_rak new file mode 100755 index 0000000000000000000000000000000000000000..c4c782f1a34cdbd0bf6577509442dccc5cc24aa8 GIT binary patch literal 29319 zcmeIu0Sy2E0K%a6Pi+o2h(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* u1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5a4;}(hX4Tp literal 0 HcmV?d00001